From c913e23a145ae07b6f9f88aae8cd5ad06b5729ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 22 Dec 2009 23:02:16 +0100 Subject: drm/radeon/kms: add dynamic engine reclocking (V9) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit V2: reorganize functions, fix modesetting calls V3: rebase patch, use radeon's workqueue V4: enable on tested chipsets only, request VBLANK IRQs V5: enable PM on older hardware (IRQs, mode_fixup, dpms) V6: use separate dynpm module parameter V7: drop RADEON_ prefix, set minimum mode for dpms off V8: update legacy encoder call, fix order in rs600 IRQ V9: update compute_clocks call in legacy, not only DPMS_OFF Signed-off-by: Rafał Miłecki Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_pm.c | 241 ++++++++++++++++++++++++++++++++++++- 1 file changed, 239 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/radeon/radeon_pm.c') diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 8bce64cdc320..a9c61f435c06 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -22,17 +22,253 @@ #include "drmP.h" #include "radeon.h" -int radeon_debugfs_pm_init(struct radeon_device *rdev); +#define RADEON_IDLE_LOOP_MS 100 +#define RADEON_RECLOCK_DELAY_MS 200 + +static void radeon_pm_check_limits(struct radeon_device *rdev); +static void radeon_pm_set_clocks_locked(struct radeon_device *rdev); +static void radeon_pm_set_clocks(struct radeon_device *rdev); +static void radeon_pm_reclock_work_handler(struct work_struct *work); +static void radeon_pm_idle_work_handler(struct work_struct *work); +static int radeon_debugfs_pm_init(struct radeon_device *rdev); + +static const char *pm_state_names[4] = { + "PM_STATE_DISABLED", + "PM_STATE_MINIMUM", + "PM_STATE_PAUSED", + "PM_STATE_ACTIVE" +}; int radeon_pm_init(struct radeon_device *rdev) { + rdev->pm.state = PM_STATE_DISABLED; + rdev->pm.planned_action = PM_ACTION_NONE; + rdev->pm.downclocked = false; + rdev->pm.vblank_callback = false; + + radeon_pm_check_limits(rdev); + if (radeon_debugfs_pm_init(rdev)) { DRM_ERROR("Failed to register debugfs file for PM!\n"); } + INIT_WORK(&rdev->pm.reclock_work, radeon_pm_reclock_work_handler); + INIT_DELAYED_WORK(&rdev->pm.idle_work, radeon_pm_idle_work_handler); + + if (radeon_dynpm != -1 && radeon_dynpm) { + rdev->pm.state = PM_STATE_PAUSED; + DRM_INFO("radeon: dynamic power management enabled\n"); + } + + DRM_INFO("radeon: power management initialized\n"); + return 0; } +static void radeon_pm_check_limits(struct radeon_device *rdev) +{ + rdev->pm.min_gpu_engine_clock = rdev->clock.default_sclk - 5000; + rdev->pm.min_gpu_memory_clock = rdev->clock.default_mclk - 5000; +} + +void radeon_pm_compute_clocks(struct radeon_device *rdev) +{ + struct drm_device *ddev = rdev->ddev; + struct drm_connector *connector; + struct radeon_crtc *radeon_crtc; + int count = 0; + + if (rdev->pm.state == PM_STATE_DISABLED) + return; + + mutex_lock(&rdev->pm.mutex); + + rdev->pm.active_crtcs = 0; + list_for_each_entry(connector, + &ddev->mode_config.connector_list, head) { + if (connector->encoder && + connector->dpms != DRM_MODE_DPMS_OFF) { + radeon_crtc = to_radeon_crtc(connector->encoder->crtc); + rdev->pm.active_crtcs |= (1 << radeon_crtc->crtc_id); + ++count; + } + } + + if (count > 1) { + if (rdev->pm.state == PM_STATE_ACTIVE) { + wait_queue_head_t wait; + init_waitqueue_head(&wait); + + cancel_delayed_work(&rdev->pm.idle_work); + + rdev->pm.state = PM_STATE_PAUSED; + rdev->pm.planned_action = PM_ACTION_UPCLOCK; + rdev->pm.vblank_callback = true; + + mutex_unlock(&rdev->pm.mutex); + + wait_event_timeout(wait, !rdev->pm.downclocked, + msecs_to_jiffies(300)); + if (!rdev->pm.downclocked) + radeon_pm_set_clocks(rdev); + + DRM_DEBUG("radeon: dynamic power management deactivated\n"); + } else { + mutex_unlock(&rdev->pm.mutex); + } + } else if (count == 1) { + rdev->pm.min_mode_engine_clock = rdev->pm.min_gpu_engine_clock; + rdev->pm.min_mode_memory_clock = rdev->pm.min_gpu_memory_clock; + /* TODO: Increase clocks if needed for current mode */ + + if (rdev->pm.state == PM_STATE_MINIMUM) { + rdev->pm.state = PM_STATE_ACTIVE; + rdev->pm.planned_action = PM_ACTION_UPCLOCK; + radeon_pm_set_clocks_locked(rdev); + + queue_delayed_work(rdev->wq, &rdev->pm.idle_work, + msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); + } + else if (rdev->pm.state == PM_STATE_PAUSED) { + rdev->pm.state = PM_STATE_ACTIVE; + queue_delayed_work(rdev->wq, &rdev->pm.idle_work, + msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); + DRM_DEBUG("radeon: dynamic power management activated\n"); + } + + mutex_unlock(&rdev->pm.mutex); + } + else { /* count == 0 */ + if (rdev->pm.state != PM_STATE_MINIMUM) { + cancel_delayed_work(&rdev->pm.idle_work); + + rdev->pm.state = PM_STATE_MINIMUM; + rdev->pm.planned_action = PM_ACTION_MINIMUM; + radeon_pm_set_clocks_locked(rdev); + } + + mutex_unlock(&rdev->pm.mutex); + } +} + +static void radeon_pm_set_clocks_locked(struct radeon_device *rdev) +{ + /*radeon_fence_wait_last(rdev);*/ + switch (rdev->pm.planned_action) { + case PM_ACTION_UPCLOCK: + radeon_set_engine_clock(rdev, rdev->clock.default_sclk); + rdev->pm.downclocked = false; + break; + case PM_ACTION_DOWNCLOCK: + radeon_set_engine_clock(rdev, + rdev->pm.min_mode_engine_clock); + rdev->pm.downclocked = true; + break; + case PM_ACTION_MINIMUM: + radeon_set_engine_clock(rdev, + rdev->pm.min_gpu_engine_clock); + break; + case PM_ACTION_NONE: + DRM_ERROR("%s: PM_ACTION_NONE\n", __func__); + break; + } + + rdev->pm.planned_action = PM_ACTION_NONE; +} + +static void radeon_pm_set_clocks(struct radeon_device *rdev) +{ + mutex_lock(&rdev->pm.mutex); + /* new VBLANK irq may come before handling previous one */ + if (rdev->pm.vblank_callback) { + mutex_lock(&rdev->cp.mutex); + if (rdev->pm.req_vblank & (1 << 0)) { + rdev->pm.req_vblank &= ~(1 << 0); + drm_vblank_put(rdev->ddev, 0); + } + if (rdev->pm.req_vblank & (1 << 1)) { + rdev->pm.req_vblank &= ~(1 << 1); + drm_vblank_put(rdev->ddev, 1); + } + rdev->pm.vblank_callback = false; + radeon_pm_set_clocks_locked(rdev); + mutex_unlock(&rdev->cp.mutex); + } + mutex_unlock(&rdev->pm.mutex); +} + +static void radeon_pm_reclock_work_handler(struct work_struct *work) +{ + struct radeon_device *rdev; + rdev = container_of(work, struct radeon_device, + pm.reclock_work); + radeon_pm_set_clocks(rdev); +} + +static void radeon_pm_idle_work_handler(struct work_struct *work) +{ + struct radeon_device *rdev; + rdev = container_of(work, struct radeon_device, + pm.idle_work.work); + + mutex_lock(&rdev->pm.mutex); + if (rdev->pm.state == PM_STATE_ACTIVE && + !rdev->pm.vblank_callback) { + unsigned long irq_flags; + int not_processed = 0; + + read_lock_irqsave(&rdev->fence_drv.lock, irq_flags); + if (!list_empty(&rdev->fence_drv.emited)) { + struct list_head *ptr; + list_for_each(ptr, &rdev->fence_drv.emited) { + /* count up to 3, that's enought info */ + if (++not_processed >= 3) + break; + } + } + read_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags); + + if (not_processed >= 3) { /* should upclock */ + if (rdev->pm.planned_action == PM_ACTION_DOWNCLOCK) { + rdev->pm.planned_action = PM_ACTION_NONE; + } else if (rdev->pm.planned_action == PM_ACTION_NONE && + rdev->pm.downclocked) { + rdev->pm.planned_action = + PM_ACTION_UPCLOCK; + rdev->pm.action_timeout = jiffies + + msecs_to_jiffies(RADEON_RECLOCK_DELAY_MS); + } + } else if (not_processed == 0) { /* should downclock */ + if (rdev->pm.planned_action == PM_ACTION_UPCLOCK) { + rdev->pm.planned_action = PM_ACTION_NONE; + } else if (rdev->pm.planned_action == PM_ACTION_NONE && + !rdev->pm.downclocked) { + rdev->pm.planned_action = + PM_ACTION_DOWNCLOCK; + rdev->pm.action_timeout = jiffies + + msecs_to_jiffies(RADEON_RECLOCK_DELAY_MS); + } + } + + if (rdev->pm.planned_action != PM_ACTION_NONE && + jiffies > rdev->pm.action_timeout) { + if (rdev->pm.active_crtcs & (1 << 0)) { + rdev->pm.req_vblank |= (1 << 0); + drm_vblank_get(rdev->ddev, 0); + } + if (rdev->pm.active_crtcs & (1 << 1)) { + rdev->pm.req_vblank |= (1 << 1); + drm_vblank_get(rdev->ddev, 1); + } + rdev->pm.vblank_callback = true; + } + } + mutex_unlock(&rdev->pm.mutex); + + queue_delayed_work(rdev->wq, &rdev->pm.idle_work, + msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); +} + /* * Debugfs info */ @@ -44,6 +280,7 @@ static int radeon_debugfs_pm_info(struct seq_file *m, void *data) struct drm_device *dev = node->minor->dev; struct radeon_device *rdev = dev->dev_private; + seq_printf(m, "state: %s\n", pm_state_names[rdev->pm.state]); seq_printf(m, "default engine clock: %u0 kHz\n", rdev->clock.default_sclk); seq_printf(m, "current engine clock: %u0 kHz\n", radeon_get_engine_clock(rdev)); seq_printf(m, "default memory clock: %u0 kHz\n", rdev->clock.default_mclk); @@ -58,7 +295,7 @@ static struct drm_info_list radeon_pm_info_list[] = { }; #endif -int radeon_debugfs_pm_init(struct radeon_device *rdev) +static int radeon_debugfs_pm_init(struct radeon_device *rdev) { #if defined(CONFIG_DEBUG_FS) return radeon_debugfs_add_files(rdev, radeon_pm_info_list, ARRAY_SIZE(radeon_pm_info_list)); -- cgit v1.2.1 From 56278a8edacee9ae9e3bc9d8c8e2d37e9969f3eb Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 28 Dec 2009 13:58:44 -0500 Subject: drm/radeon/kms: pull power mode info from bios tables (v3) The general idea is to validate the current hw state against the set of power states and select a power state based on that. This patch just pulls the power states from the bios and prints the information. It is not currently hooked up in the actual power management code. Hooking it up will require reworking the the current power state selection code and will be handled in a future patch. Additionally, we'd need to decide on some default lower power states for cards without power tables. v2 - increment state_index after checking for default state v3 - fix typo in pm init on pre-atom cards, handle pre-atom cards without x86 bioses Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_pm.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'drivers/gpu/drm/radeon/radeon_pm.c') diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index a9c61f435c06..6eb0e0b3264b 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -18,6 +18,7 @@ * OTHER DEALINGS IN THE SOFTWARE. * * Authors: Rafał Miłecki + * Alex Deucher */ #include "drmP.h" #include "radeon.h" @@ -39,6 +40,35 @@ static const char *pm_state_names[4] = { "PM_STATE_ACTIVE" }; +static void radeon_print_power_mode_info(struct radeon_device *rdev) +{ + int i, j; + bool is_default; + + DRM_INFO("%d Power State(s)\n", rdev->pm.num_power_states); + for (i = 0; i < rdev->pm.num_power_states; i++) { + if (rdev->pm.default_power_state == &rdev->pm.power_state[i]) + is_default = true; + else + is_default = false; + DRM_INFO("State %d %s\n", i, is_default ? "(default)" : ""); + if ((rdev->flags & RADEON_IS_PCIE) && !(rdev->flags & RADEON_IS_IGP)) + DRM_INFO("\t%d PCIE Lanes\n", rdev->pm.power_state[i].non_clock_info.pcie_lanes); + DRM_INFO("\t%d Clock Mode(s)\n", rdev->pm.power_state[i].num_clock_modes); + for (j = 0; j < rdev->pm.power_state[i].num_clock_modes; j++) { + if (rdev->flags & RADEON_IS_IGP) + DRM_INFO("\t\t%d engine: %d\n", + j, + rdev->pm.power_state[i].clock_info[j].sclk * 10); + else + DRM_INFO("\t\t%d engine/memory: %d/%d\n", + j, + rdev->pm.power_state[i].clock_info[j].sclk * 10, + rdev->pm.power_state[i].clock_info[j].mclk * 10); + } + } +} + int radeon_pm_init(struct radeon_device *rdev) { rdev->pm.state = PM_STATE_DISABLED; @@ -46,6 +76,14 @@ int radeon_pm_init(struct radeon_device *rdev) rdev->pm.downclocked = false; rdev->pm.vblank_callback = false; + if (rdev->bios) { + if (rdev->is_atom_bios) + radeon_atombios_get_power_modes(rdev); + else + radeon_combios_get_power_modes(rdev); + radeon_print_power_mode_info(rdev); + } + radeon_pm_check_limits(rdev); if (radeon_debugfs_pm_init(rdev)) { -- cgit v1.2.1 From 0ec0e74f784ca08eab0354ab1dada46924c39b73 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 23 Dec 2009 13:21:58 -0500 Subject: drm/radeon/kms: add a power state type based on power state flags The idea is to flag a power state with a certain type and use that type to decide on what state to select. On r6xx+, we select a state and then transition between clock modes in that state. On pre-r6xx, we transition between states directly. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_pm.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/radeon/radeon_pm.c') diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 6eb0e0b3264b..93ba0fb27e9d 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -40,6 +40,14 @@ static const char *pm_state_names[4] = { "PM_STATE_ACTIVE" }; +static const char *pm_state_types[5] = { + "Default", + "Powersave", + "Battery", + "Balanced", + "Performance", +}; + static void radeon_print_power_mode_info(struct radeon_device *rdev) { int i, j; @@ -51,7 +59,9 @@ static void radeon_print_power_mode_info(struct radeon_device *rdev) is_default = true; else is_default = false; - DRM_INFO("State %d %s\n", i, is_default ? "(default)" : ""); + DRM_INFO("State %d %s %s\n", i, + pm_state_types[rdev->pm.power_state[i].type], + is_default ? "(default)" : ""); if ((rdev->flags & RADEON_IS_PCIE) && !(rdev->flags & RADEON_IS_IGP)) DRM_INFO("\t%d PCIE Lanes\n", rdev->pm.power_state[i].non_clock_info.pcie_lanes); DRM_INFO("\t%d Clock Mode(s)\n", rdev->pm.power_state[i].num_clock_modes); -- cgit v1.2.1 From 516d0e46c80d2d20391f4145c2c5e3915253b8bf Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 23 Dec 2009 14:28:05 -0500 Subject: drm/radeon/kms: add code to select power state not hooked up yet. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_pm.c | 122 +++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) (limited to 'drivers/gpu/drm/radeon/radeon_pm.c') diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 93ba0fb27e9d..87d2776624bb 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -79,6 +79,128 @@ static void radeon_print_power_mode_info(struct radeon_device *rdev) } } +static struct radeon_power_state * radeon_pick_power_state(struct radeon_device *rdev, + enum radeon_pm_state_type type) +{ + int i; + struct radeon_power_state *power_state = NULL; + + switch (type) { + case POWER_STATE_TYPE_DEFAULT: + default: + return rdev->pm.default_power_state; + case POWER_STATE_TYPE_POWERSAVE: + for (i = 0; i < rdev->pm.num_power_states; i++) { + if (rdev->pm.power_state[i].type == POWER_STATE_TYPE_POWERSAVE) { + power_state = &rdev->pm.power_state[i]; + break; + } + } + if (power_state == NULL) { + for (i = 0; i < rdev->pm.num_power_states; i++) { + if (rdev->pm.power_state[i].type == POWER_STATE_TYPE_BATTERY) { + power_state = &rdev->pm.power_state[i]; + break; + } + } + } + break; + case POWER_STATE_TYPE_BATTERY: + for (i = 0; i < rdev->pm.num_power_states; i++) { + if (rdev->pm.power_state[i].type == POWER_STATE_TYPE_BATTERY) { + power_state = &rdev->pm.power_state[i]; + break; + } + } + if (power_state == NULL) { + for (i = 0; i < rdev->pm.num_power_states; i++) { + if (rdev->pm.power_state[i].type == POWER_STATE_TYPE_POWERSAVE) { + power_state = &rdev->pm.power_state[i]; + break; + } + } + } + break; + case POWER_STATE_TYPE_BALANCED: + case POWER_STATE_TYPE_PERFORMANCE: + for (i = 0; i < rdev->pm.num_power_states; i++) { + if (rdev->pm.power_state[i].type == type) { + power_state = &rdev->pm.power_state[i]; + break; + } + } + break; + } + + if (power_state == NULL) + return rdev->pm.default_power_state; + + return power_state; +} + +static struct radeon_pm_clock_info * radeon_pick_clock_mode(struct radeon_device *rdev, + struct radeon_power_state *power_state, + enum radeon_pm_clock_mode_type type) +{ + switch (type) { + case POWER_MODE_TYPE_DEFAULT: + default: + return power_state->default_clock_mode; + case POWER_MODE_TYPE_LOW: + return &power_state->clock_info[0]; + case POWER_MODE_TYPE_MID: + if (power_state->num_clock_modes > 2) + return &power_state->clock_info[1]; + else + return &power_state->clock_info[0]; + break; + case POWER_MODE_TYPE_HIGH: + return &power_state->clock_info[power_state->num_clock_modes - 1]; + } + +} + +static void radeon_get_power_state(struct radeon_device *rdev, + enum radeon_pm_action action) +{ + switch (action) { + case PM_ACTION_NONE: + default: + rdev->pm.requested_power_state = rdev->pm.current_power_state; + rdev->pm.requested_power_state->requested_clock_mode = + rdev->pm.requested_power_state->current_clock_mode; + break; + case PM_ACTION_MINIMUM: + rdev->pm.requested_power_state = radeon_pick_power_state(rdev, POWER_STATE_TYPE_BATTERY); + rdev->pm.requested_power_state->requested_clock_mode = + radeon_pick_clock_mode(rdev, rdev->pm.requested_power_state, POWER_MODE_TYPE_LOW); + break; + case PM_ACTION_DOWNCLOCK: + rdev->pm.requested_power_state = radeon_pick_power_state(rdev, POWER_STATE_TYPE_POWERSAVE); + rdev->pm.requested_power_state->requested_clock_mode = + radeon_pick_clock_mode(rdev, rdev->pm.requested_power_state, POWER_MODE_TYPE_MID); + break; + case PM_ACTION_UPCLOCK: + rdev->pm.requested_power_state = radeon_pick_power_state(rdev, POWER_STATE_TYPE_DEFAULT); + rdev->pm.requested_power_state->requested_clock_mode = + radeon_pick_clock_mode(rdev, rdev->pm.requested_power_state, POWER_MODE_TYPE_HIGH); + break; + } +} + +static void radeon_set_power_state(struct radeon_device *rdev) +{ + if (rdev->pm.requested_power_state == rdev->pm.current_power_state) + return; + /* set pcie lanes */ + /* set voltage */ + /* set engine clock */ + radeon_set_engine_clock(rdev, rdev->pm.requested_power_state->requested_clock_mode->sclk); + /* set memory clock */ + + rdev->pm.current_power_state = rdev->pm.requested_power_state; +} + int radeon_pm_init(struct radeon_device *rdev) { rdev->pm.state = PM_STATE_DISABLED; -- cgit v1.2.1 From 530079a8f3f35828a80ba4981c1be902982363e7 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 23 Dec 2009 14:39:36 -0500 Subject: drm/radeon/kms: use power states for dynamic reclocking Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_pm.c | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) (limited to 'drivers/gpu/drm/radeon/radeon_pm.c') diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 87d2776624bb..f500c8d200e7 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -26,7 +26,6 @@ #define RADEON_IDLE_LOOP_MS 100 #define RADEON_RECLOCK_DELAY_MS 200 -static void radeon_pm_check_limits(struct radeon_device *rdev); static void radeon_pm_set_clocks_locked(struct radeon_device *rdev); static void radeon_pm_set_clocks(struct radeon_device *rdev); static void radeon_pm_reclock_work_handler(struct work_struct *work); @@ -186,12 +185,21 @@ static void radeon_get_power_state(struct radeon_device *rdev, radeon_pick_clock_mode(rdev, rdev->pm.requested_power_state, POWER_MODE_TYPE_HIGH); break; } + DRM_INFO("Requested: e: %d m: %d p: %d\n", + rdev->pm.requested_power_state->requested_clock_mode->sclk, + rdev->pm.requested_power_state->requested_clock_mode->mclk, + rdev->pm.requested_power_state->non_clock_info.pcie_lanes); } static void radeon_set_power_state(struct radeon_device *rdev) { if (rdev->pm.requested_power_state == rdev->pm.current_power_state) return; + + DRM_INFO("Setting: e: %d m: %d p: %d\n", + rdev->pm.requested_power_state->requested_clock_mode->sclk, + rdev->pm.requested_power_state->requested_clock_mode->mclk, + rdev->pm.requested_power_state->non_clock_info.pcie_lanes); /* set pcie lanes */ /* set voltage */ /* set engine clock */ @@ -216,8 +224,6 @@ int radeon_pm_init(struct radeon_device *rdev) radeon_print_power_mode_info(rdev); } - radeon_pm_check_limits(rdev); - if (radeon_debugfs_pm_init(rdev)) { DRM_ERROR("Failed to register debugfs file for PM!\n"); } @@ -235,12 +241,6 @@ int radeon_pm_init(struct radeon_device *rdev) return 0; } -static void radeon_pm_check_limits(struct radeon_device *rdev) -{ - rdev->pm.min_gpu_engine_clock = rdev->clock.default_sclk - 5000; - rdev->pm.min_gpu_memory_clock = rdev->clock.default_mclk - 5000; -} - void radeon_pm_compute_clocks(struct radeon_device *rdev) { struct drm_device *ddev = rdev->ddev; @@ -287,8 +287,6 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev) mutex_unlock(&rdev->pm.mutex); } } else if (count == 1) { - rdev->pm.min_mode_engine_clock = rdev->pm.min_gpu_engine_clock; - rdev->pm.min_mode_memory_clock = rdev->pm.min_gpu_memory_clock; /* TODO: Increase clocks if needed for current mode */ if (rdev->pm.state == PM_STATE_MINIMUM) { @@ -326,23 +324,22 @@ static void radeon_pm_set_clocks_locked(struct radeon_device *rdev) /*radeon_fence_wait_last(rdev);*/ switch (rdev->pm.planned_action) { case PM_ACTION_UPCLOCK: - radeon_set_engine_clock(rdev, rdev->clock.default_sclk); + radeon_get_power_state(rdev, PM_ACTION_UPCLOCK); rdev->pm.downclocked = false; break; case PM_ACTION_DOWNCLOCK: - radeon_set_engine_clock(rdev, - rdev->pm.min_mode_engine_clock); + radeon_get_power_state(rdev, PM_ACTION_DOWNCLOCK); rdev->pm.downclocked = true; break; case PM_ACTION_MINIMUM: - radeon_set_engine_clock(rdev, - rdev->pm.min_gpu_engine_clock); + radeon_get_power_state(rdev, PM_ACTION_MINIMUM); break; case PM_ACTION_NONE: + radeon_get_power_state(rdev, PM_ACTION_NONE); DRM_ERROR("%s: PM_ACTION_NONE\n", __func__); break; } - + radeon_set_power_state(rdev); rdev->pm.planned_action = PM_ACTION_NONE; } -- cgit v1.2.1 From a0eb38eb8637a81bb7770d34036e498d2ba63a26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 24 Dec 2009 03:28:33 +0100 Subject: drm/radeon/kms: get_power_state early, not when processing IRQ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_pm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/radeon/radeon_pm.c') diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index f500c8d200e7..1cecd7346ab9 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -273,6 +273,7 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev) rdev->pm.state = PM_STATE_PAUSED; rdev->pm.planned_action = PM_ACTION_UPCLOCK; + radeon_get_power_state(rdev, rdev->pm.planned_action); rdev->pm.vblank_callback = true; mutex_unlock(&rdev->pm.mutex); @@ -292,6 +293,7 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev) if (rdev->pm.state == PM_STATE_MINIMUM) { rdev->pm.state = PM_STATE_ACTIVE; rdev->pm.planned_action = PM_ACTION_UPCLOCK; + radeon_get_power_state(rdev, rdev->pm.planned_action); radeon_pm_set_clocks_locked(rdev); queue_delayed_work(rdev->wq, &rdev->pm.idle_work, @@ -312,6 +314,7 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev) rdev->pm.state = PM_STATE_MINIMUM; rdev->pm.planned_action = PM_ACTION_MINIMUM; + radeon_get_power_state(rdev, rdev->pm.planned_action); radeon_pm_set_clocks_locked(rdev); } @@ -324,18 +327,14 @@ static void radeon_pm_set_clocks_locked(struct radeon_device *rdev) /*radeon_fence_wait_last(rdev);*/ switch (rdev->pm.planned_action) { case PM_ACTION_UPCLOCK: - radeon_get_power_state(rdev, PM_ACTION_UPCLOCK); rdev->pm.downclocked = false; break; case PM_ACTION_DOWNCLOCK: - radeon_get_power_state(rdev, PM_ACTION_DOWNCLOCK); rdev->pm.downclocked = true; break; case PM_ACTION_MINIMUM: - radeon_get_power_state(rdev, PM_ACTION_MINIMUM); break; case PM_ACTION_NONE: - radeon_get_power_state(rdev, PM_ACTION_NONE); DRM_ERROR("%s: PM_ACTION_NONE\n", __func__); break; } @@ -427,6 +426,7 @@ static void radeon_pm_idle_work_handler(struct work_struct *work) rdev->pm.req_vblank |= (1 << 1); drm_vblank_get(rdev->ddev, 1); } + radeon_get_power_state(rdev, rdev->pm.planned_action); rdev->pm.vblank_callback = true; } } -- cgit v1.2.1 From 73a6d3fc104827db574e4bd206a025299fef0bb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 8 Jan 2010 00:22:47 +0100 Subject: drm/radeon/kms: use wait queue (events) for VBLANK sync MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This already simplifies code significally and makes it maintaible in case of adding memory reclocking plus voltage changing in future. Signed-off-by: Rafał Miłecki Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_pm.c | 93 ++++++++++++++------------------------ 1 file changed, 33 insertions(+), 60 deletions(-) (limited to 'drivers/gpu/drm/radeon/radeon_pm.c') diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 1cecd7346ab9..a8e151ec1351 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -25,10 +25,10 @@ #define RADEON_IDLE_LOOP_MS 100 #define RADEON_RECLOCK_DELAY_MS 200 +#define RADEON_WAIT_VBLANK_TIMEOUT 200 static void radeon_pm_set_clocks_locked(struct radeon_device *rdev); static void radeon_pm_set_clocks(struct radeon_device *rdev); -static void radeon_pm_reclock_work_handler(struct work_struct *work); static void radeon_pm_idle_work_handler(struct work_struct *work); static int radeon_debugfs_pm_init(struct radeon_device *rdev); @@ -214,7 +214,6 @@ int radeon_pm_init(struct radeon_device *rdev) rdev->pm.state = PM_STATE_DISABLED; rdev->pm.planned_action = PM_ACTION_NONE; rdev->pm.downclocked = false; - rdev->pm.vblank_callback = false; if (rdev->bios) { if (rdev->is_atom_bios) @@ -228,7 +227,6 @@ int radeon_pm_init(struct radeon_device *rdev) DRM_ERROR("Failed to register debugfs file for PM!\n"); } - INIT_WORK(&rdev->pm.reclock_work, radeon_pm_reclock_work_handler); INIT_DELAYED_WORK(&rdev->pm.idle_work, radeon_pm_idle_work_handler); if (radeon_dynpm != -1 && radeon_dynpm) { @@ -266,26 +264,14 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev) if (count > 1) { if (rdev->pm.state == PM_STATE_ACTIVE) { - wait_queue_head_t wait; - init_waitqueue_head(&wait); - cancel_delayed_work(&rdev->pm.idle_work); rdev->pm.state = PM_STATE_PAUSED; rdev->pm.planned_action = PM_ACTION_UPCLOCK; - radeon_get_power_state(rdev, rdev->pm.planned_action); - rdev->pm.vblank_callback = true; - - mutex_unlock(&rdev->pm.mutex); - - wait_event_timeout(wait, !rdev->pm.downclocked, - msecs_to_jiffies(300)); - if (!rdev->pm.downclocked) + if (rdev->pm.downclocked) radeon_pm_set_clocks(rdev); DRM_DEBUG("radeon: dynamic power management deactivated\n"); - } else { - mutex_unlock(&rdev->pm.mutex); } } else if (count == 1) { /* TODO: Increase clocks if needed for current mode */ @@ -293,8 +279,7 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev) if (rdev->pm.state == PM_STATE_MINIMUM) { rdev->pm.state = PM_STATE_ACTIVE; rdev->pm.planned_action = PM_ACTION_UPCLOCK; - radeon_get_power_state(rdev, rdev->pm.planned_action); - radeon_pm_set_clocks_locked(rdev); + radeon_pm_set_clocks(rdev); queue_delayed_work(rdev->wq, &rdev->pm.idle_work, msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); @@ -305,8 +290,6 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev) msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); DRM_DEBUG("radeon: dynamic power management activated\n"); } - - mutex_unlock(&rdev->pm.mutex); } else { /* count == 0 */ if (rdev->pm.state != PM_STATE_MINIMUM) { @@ -314,12 +297,11 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev) rdev->pm.state = PM_STATE_MINIMUM; rdev->pm.planned_action = PM_ACTION_MINIMUM; - radeon_get_power_state(rdev, rdev->pm.planned_action); - radeon_pm_set_clocks_locked(rdev); + radeon_pm_set_clocks(rdev); } - - mutex_unlock(&rdev->pm.mutex); } + + mutex_unlock(&rdev->pm.mutex); } static void radeon_pm_set_clocks_locked(struct radeon_device *rdev) @@ -344,31 +326,32 @@ static void radeon_pm_set_clocks_locked(struct radeon_device *rdev) static void radeon_pm_set_clocks(struct radeon_device *rdev) { - mutex_lock(&rdev->pm.mutex); - /* new VBLANK irq may come before handling previous one */ - if (rdev->pm.vblank_callback) { - mutex_lock(&rdev->cp.mutex); - if (rdev->pm.req_vblank & (1 << 0)) { - rdev->pm.req_vblank &= ~(1 << 0); - drm_vblank_put(rdev->ddev, 0); - } - if (rdev->pm.req_vblank & (1 << 1)) { - rdev->pm.req_vblank &= ~(1 << 1); - drm_vblank_put(rdev->ddev, 1); - } - rdev->pm.vblank_callback = false; - radeon_pm_set_clocks_locked(rdev); - mutex_unlock(&rdev->cp.mutex); + radeon_get_power_state(rdev, rdev->pm.planned_action); + mutex_lock(&rdev->cp.mutex); + + if (rdev->pm.active_crtcs & (1 << 0)) { + rdev->pm.req_vblank |= (1 << 0); + drm_vblank_get(rdev->ddev, 0); + } + if (rdev->pm.active_crtcs & (1 << 1)) { + rdev->pm.req_vblank |= (1 << 1); + drm_vblank_get(rdev->ddev, 1); + } + if (rdev->pm.active_crtcs) + wait_event_interruptible_timeout( + rdev->irq.vblank_queue, 0, + msecs_to_jiffies(RADEON_WAIT_VBLANK_TIMEOUT)); + if (rdev->pm.req_vblank & (1 << 0)) { + rdev->pm.req_vblank &= ~(1 << 0); + drm_vblank_put(rdev->ddev, 0); + } + if (rdev->pm.req_vblank & (1 << 1)) { + rdev->pm.req_vblank &= ~(1 << 1); + drm_vblank_put(rdev->ddev, 1); } - mutex_unlock(&rdev->pm.mutex); -} -static void radeon_pm_reclock_work_handler(struct work_struct *work) -{ - struct radeon_device *rdev; - rdev = container_of(work, struct radeon_device, - pm.reclock_work); - radeon_pm_set_clocks(rdev); + radeon_pm_set_clocks_locked(rdev); + mutex_unlock(&rdev->cp.mutex); } static void radeon_pm_idle_work_handler(struct work_struct *work) @@ -378,8 +361,7 @@ static void radeon_pm_idle_work_handler(struct work_struct *work) pm.idle_work.work); mutex_lock(&rdev->pm.mutex); - if (rdev->pm.state == PM_STATE_ACTIVE && - !rdev->pm.vblank_callback) { + if (rdev->pm.state == PM_STATE_ACTIVE) { unsigned long irq_flags; int not_processed = 0; @@ -417,17 +399,8 @@ static void radeon_pm_idle_work_handler(struct work_struct *work) } if (rdev->pm.planned_action != PM_ACTION_NONE && - jiffies > rdev->pm.action_timeout) { - if (rdev->pm.active_crtcs & (1 << 0)) { - rdev->pm.req_vblank |= (1 << 0); - drm_vblank_get(rdev->ddev, 0); - } - if (rdev->pm.active_crtcs & (1 << 1)) { - rdev->pm.req_vblank |= (1 << 1); - drm_vblank_get(rdev->ddev, 1); - } - radeon_get_power_state(rdev, rdev->pm.planned_action); - rdev->pm.vblank_callback = true; + jiffies > rdev->pm.action_timeout) { + radeon_pm_set_clocks(rdev); } } mutex_unlock(&rdev->pm.mutex); -- cgit v1.2.1 From bc4624cad9b53b3fd3248fe3086b432471fc0fe0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 11 Feb 2010 21:50:06 +0000 Subject: drm/radeon/kms: simplify picking power state Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_pm.c | 57 ++++++++++++-------------------------- 1 file changed, 18 insertions(+), 39 deletions(-) (limited to 'drivers/gpu/drm/radeon/radeon_pm.c') diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index a8e151ec1351..f0234351fd57 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -81,60 +81,39 @@ static void radeon_print_power_mode_info(struct radeon_device *rdev) static struct radeon_power_state * radeon_pick_power_state(struct radeon_device *rdev, enum radeon_pm_state_type type) { - int i; - struct radeon_power_state *power_state = NULL; + int i, j; + enum radeon_pm_state_type wanted_types[2]; + int wanted_count; switch (type) { case POWER_STATE_TYPE_DEFAULT: default: return rdev->pm.default_power_state; case POWER_STATE_TYPE_POWERSAVE: - for (i = 0; i < rdev->pm.num_power_states; i++) { - if (rdev->pm.power_state[i].type == POWER_STATE_TYPE_POWERSAVE) { - power_state = &rdev->pm.power_state[i]; - break; - } - } - if (power_state == NULL) { - for (i = 0; i < rdev->pm.num_power_states; i++) { - if (rdev->pm.power_state[i].type == POWER_STATE_TYPE_BATTERY) { - power_state = &rdev->pm.power_state[i]; - break; - } - } - } + wanted_types[0] = POWER_STATE_TYPE_POWERSAVE; + wanted_types[1] = POWER_STATE_TYPE_BATTERY; + wanted_count = 2; break; case POWER_STATE_TYPE_BATTERY: - for (i = 0; i < rdev->pm.num_power_states; i++) { - if (rdev->pm.power_state[i].type == POWER_STATE_TYPE_BATTERY) { - power_state = &rdev->pm.power_state[i]; - break; - } - } - if (power_state == NULL) { - for (i = 0; i < rdev->pm.num_power_states; i++) { - if (rdev->pm.power_state[i].type == POWER_STATE_TYPE_POWERSAVE) { - power_state = &rdev->pm.power_state[i]; - break; - } - } - } + wanted_types[0] = POWER_STATE_TYPE_BATTERY; + wanted_types[1] = POWER_STATE_TYPE_POWERSAVE; + wanted_count = 2; break; case POWER_STATE_TYPE_BALANCED: case POWER_STATE_TYPE_PERFORMANCE: - for (i = 0; i < rdev->pm.num_power_states; i++) { - if (rdev->pm.power_state[i].type == type) { - power_state = &rdev->pm.power_state[i]; - break; - } - } + wanted_types[0] = type; + wanted_count = 1; break; } - if (power_state == NULL) - return rdev->pm.default_power_state; + for (i = 0; i < wanted_count; i++) { + for (j = 0; j < rdev->pm.num_power_states; j++) { + if (rdev->pm.power_state[j].type == wanted_types[i]) + return &rdev->pm.power_state[j]; + } + } - return power_state; + return rdev->pm.default_power_state; } static struct radeon_pm_clock_info * radeon_pick_clock_mode(struct radeon_device *rdev, -- cgit v1.2.1 From f735261baab3a275a273533c391d2d1b86a9e66a Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 18 Feb 2010 15:58:36 +1000 Subject: [rfc] drm/radeon/kms: pm debugging check for vbl. This patch adds a check on avivo chips to see if we are in the VBL region for the active crtcs when we trigger the engine change. I appear to have glitches locally on pm transistion (not sure all fixes are in yet) and this at least seems to be correct here, maybe others can test on systems with no glitches. --- drivers/gpu/drm/radeon/radeon_pm.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'drivers/gpu/drm/radeon/radeon_pm.c') diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index f0234351fd57..6dbfdf48a5f5 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -22,6 +22,7 @@ */ #include "drmP.h" #include "radeon.h" +#include "avivod.h" #define RADEON_IDLE_LOOP_MS 100 #define RADEON_RECLOCK_DELAY_MS 200 @@ -283,6 +284,28 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev) mutex_unlock(&rdev->pm.mutex); } +static bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish) +{ + u32 stat_crtc1 = 0, stat_crtc2 = 0; + bool in_vbl = true; + + if (ASIC_IS_AVIVO(rdev)) { + if (rdev->pm.active_crtcs & (1 << 0)) { + stat_crtc1 = RREG32(D1CRTC_STATUS); + if (!(stat_crtc1 & 1)) + in_vbl = false; + } + if (rdev->pm.active_crtcs & (1 << 1)) { + stat_crtc2 = RREG32(D2CRTC_STATUS); + if (!(stat_crtc2 & 1)) + in_vbl = false; + } + } + if (in_vbl == false) + DRM_INFO("not in vbl for pm change %08x %08x at %s\n", stat_crtc1, + stat_crtc2, finish ? "exit" : "entry"); + return in_vbl; +} static void radeon_pm_set_clocks_locked(struct radeon_device *rdev) { /*radeon_fence_wait_last(rdev);*/ @@ -299,7 +322,11 @@ static void radeon_pm_set_clocks_locked(struct radeon_device *rdev) DRM_ERROR("%s: PM_ACTION_NONE\n", __func__); break; } + + /* check if we are in vblank */ + radeon_pm_debug_check_in_vbl(rdev, false); radeon_set_power_state(rdev); + radeon_pm_debug_check_in_vbl(rdev, true); rdev->pm.planned_action = PM_ACTION_NONE; } -- cgit v1.2.1 From 9038dfdf699a3227004f1f6da32a3ef4ef3ba5a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sat, 20 Feb 2010 23:15:04 +0000 Subject: drm/radeon/kms: simplify storing current and requested PM mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We kept pointers to requested and current clock modes in every power state. That was useless, more /global/ pointers in power struct are enough. Signed-off-by: Rafał Miłecki Reviewed-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_pm.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers/gpu/drm/radeon/radeon_pm.c') diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 6dbfdf48a5f5..8960acf14155 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -143,50 +143,50 @@ static void radeon_get_power_state(struct radeon_device *rdev, enum radeon_pm_action action) { switch (action) { - case PM_ACTION_NONE: - default: - rdev->pm.requested_power_state = rdev->pm.current_power_state; - rdev->pm.requested_power_state->requested_clock_mode = - rdev->pm.requested_power_state->current_clock_mode; - break; case PM_ACTION_MINIMUM: rdev->pm.requested_power_state = radeon_pick_power_state(rdev, POWER_STATE_TYPE_BATTERY); - rdev->pm.requested_power_state->requested_clock_mode = + rdev->pm.requested_clock_mode = radeon_pick_clock_mode(rdev, rdev->pm.requested_power_state, POWER_MODE_TYPE_LOW); break; case PM_ACTION_DOWNCLOCK: rdev->pm.requested_power_state = radeon_pick_power_state(rdev, POWER_STATE_TYPE_POWERSAVE); - rdev->pm.requested_power_state->requested_clock_mode = + rdev->pm.requested_clock_mode = radeon_pick_clock_mode(rdev, rdev->pm.requested_power_state, POWER_MODE_TYPE_MID); break; case PM_ACTION_UPCLOCK: rdev->pm.requested_power_state = radeon_pick_power_state(rdev, POWER_STATE_TYPE_DEFAULT); - rdev->pm.requested_power_state->requested_clock_mode = + rdev->pm.requested_clock_mode = radeon_pick_clock_mode(rdev, rdev->pm.requested_power_state, POWER_MODE_TYPE_HIGH); break; + case PM_ACTION_NONE: + default: + DRM_ERROR("Requested mode for not defined action\n"); + return; } DRM_INFO("Requested: e: %d m: %d p: %d\n", - rdev->pm.requested_power_state->requested_clock_mode->sclk, - rdev->pm.requested_power_state->requested_clock_mode->mclk, + rdev->pm.requested_clock_mode->sclk, + rdev->pm.requested_clock_mode->mclk, rdev->pm.requested_power_state->non_clock_info.pcie_lanes); } static void radeon_set_power_state(struct radeon_device *rdev) { - if (rdev->pm.requested_power_state == rdev->pm.current_power_state) + /* if *_clock_mode are the same, *_power_state are as well */ + if (rdev->pm.requested_clock_mode == rdev->pm.current_clock_mode) return; DRM_INFO("Setting: e: %d m: %d p: %d\n", - rdev->pm.requested_power_state->requested_clock_mode->sclk, - rdev->pm.requested_power_state->requested_clock_mode->mclk, + rdev->pm.requested_clock_mode->sclk, + rdev->pm.requested_clock_mode->mclk, rdev->pm.requested_power_state->non_clock_info.pcie_lanes); /* set pcie lanes */ /* set voltage */ /* set engine clock */ - radeon_set_engine_clock(rdev, rdev->pm.requested_power_state->requested_clock_mode->sclk); + radeon_set_engine_clock(rdev, rdev->pm.requested_clock_mode->sclk); /* set memory clock */ rdev->pm.current_power_state = rdev->pm.requested_power_state; + rdev->pm.current_clock_mode = rdev->pm.requested_clock_mode; } int radeon_pm_init(struct radeon_device *rdev) -- cgit v1.2.1 From 08ff2a7a7a13c562e81a406722193f43cbb4e4ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sun, 21 Feb 2010 22:46:30 +0000 Subject: drm/radeon/kms: for downclocking non-mobility check PERFORMANCE state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AtomBIOS tables on non-mobility GPU do not contain POWERSAVE/BATTERY. Signed-off-by: Rafał Miłecki Reviewed-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_pm.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm/radeon/radeon_pm.c') diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 8960acf14155..d174d93c9386 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -91,14 +91,24 @@ static struct radeon_power_state * radeon_pick_power_state(struct radeon_device default: return rdev->pm.default_power_state; case POWER_STATE_TYPE_POWERSAVE: - wanted_types[0] = POWER_STATE_TYPE_POWERSAVE; - wanted_types[1] = POWER_STATE_TYPE_BATTERY; - wanted_count = 2; + if (rdev->flags & RADEON_IS_MOBILITY) { + wanted_types[0] = POWER_STATE_TYPE_POWERSAVE; + wanted_types[1] = POWER_STATE_TYPE_BATTERY; + wanted_count = 2; + } else { + wanted_types[0] = POWER_STATE_TYPE_PERFORMANCE; + wanted_count = 1; + } break; case POWER_STATE_TYPE_BATTERY: - wanted_types[0] = POWER_STATE_TYPE_BATTERY; - wanted_types[1] = POWER_STATE_TYPE_POWERSAVE; - wanted_count = 2; + if (rdev->flags & RADEON_IS_MOBILITY) { + wanted_types[0] = POWER_STATE_TYPE_BATTERY; + wanted_types[1] = POWER_STATE_TYPE_POWERSAVE; + wanted_count = 2; + } else { + wanted_types[0] = POWER_STATE_TYPE_PERFORMANCE; + wanted_count = 1; + } break; case POWER_STATE_TYPE_BALANCED: case POWER_STATE_TYPE_PERFORMANCE: -- cgit v1.2.1 From aa5120d2ef228042416d3023fb7eda9ee487dcf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 18 Feb 2010 20:24:28 +0000 Subject: drm/radeon/kms: implement reading active PCIE lanes on R600+ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_pm.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/gpu/drm/radeon/radeon_pm.c') diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index d174d93c9386..d4d1c39a0e99 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -442,6 +442,8 @@ static int radeon_debugfs_pm_info(struct seq_file *m, void *data) seq_printf(m, "default memory clock: %u0 kHz\n", rdev->clock.default_mclk); if (rdev->asic->get_memory_clock) seq_printf(m, "current memory clock: %u0 kHz\n", radeon_get_memory_clock(rdev)); + if (rdev->asic->get_pcie_lanes) + seq_printf(m, "PCIE lanes: %d\n", radeon_get_pcie_lanes(rdev)); return 0; } -- cgit v1.2.1