20,20 → 20,18 |
* Authors: Rafał Miłecki <zajec5@gmail.com> |
* Alex Deucher <alexdeucher@gmail.com> |
*/ |
#include "drmP.h" |
#include <drm/drmP.h> |
#include "radeon.h" |
#include "avivod.h" |
#include "atom.h" |
|
#define DRM_DEBUG_DRIVER(fmt, args...) |
|
#define RADEON_IDLE_LOOP_MS 100 |
#define RADEON_RECLOCK_DELAY_MS 200 |
#define RADEON_WAIT_VBLANK_TIMEOUT 200 |
#define RADEON_WAIT_IDLE_TIMEOUT 200 |
|
static const char *radeon_pm_state_type_name[5] = { |
"Default", |
"", |
"Powersave", |
"Battery", |
"Balanced", |
47,24 → 45,26 |
static void radeon_pm_update_profile(struct radeon_device *rdev); |
static void radeon_pm_set_clocks(struct radeon_device *rdev); |
|
static inline int power_supply_is_system_supplied(void) { return -ENOSYS; } |
int radeon_pm_get_type_index(struct radeon_device *rdev, |
enum radeon_pm_state_type ps_type, |
int instance) |
{ |
int i; |
int found_instance = -1; |
|
#define ACPI_AC_CLASS "ac_adapter" |
for (i = 0; i < rdev->pm.num_power_states; i++) { |
if (rdev->pm.power_state[i].type == ps_type) { |
found_instance++; |
if (found_instance == instance) |
return i; |
} |
} |
/* return default if no match */ |
return rdev->pm.default_power_state_index; |
} |
|
#ifdef CONFIG_ACPI |
static int radeon_acpi_event(struct notifier_block *nb, |
unsigned long val, |
void *data) |
void radeon_pm_acpi_event_handler(struct radeon_device *rdev) |
{ |
struct radeon_device *rdev = container_of(nb, struct radeon_device, acpi_nb); |
struct acpi_bus_event *entry = (struct acpi_bus_event *)data; |
|
if (strcmp(entry->device_class, ACPI_AC_CLASS) == 0) { |
if (power_supply_is_system_supplied() > 0) |
DRM_DEBUG_DRIVER("pm: AC\n"); |
else |
DRM_DEBUG_DRIVER("pm: DC\n"); |
|
if (rdev->pm.pm_method == PM_METHOD_PROFILE) { |
if (rdev->pm.profile == PM_PROFILE_AUTO) { |
mutex_lock(&rdev->pm.mutex); |
75,10 → 75,6 |
} |
} |
|
return NOTIFY_OK; |
} |
#endif |
|
static void radeon_pm_update_profile(struct radeon_device *rdev) |
{ |
switch (rdev->pm.profile) { |
140,6 → 136,15 |
|
} |
|
static void radeon_sync_with_vblank(struct radeon_device *rdev) |
{ |
if (rdev->pm.active_crtcs) { |
rdev->pm.vblank_sync = false; |
// wait_event_timeout( |
// rdev->irq.vblank_queue, rdev->pm.vblank_sync, |
// msecs_to_jiffies(RADEON_WAIT_VBLANK_TIMEOUT)); |
} |
} |
|
static void radeon_set_power_state(struct radeon_device *rdev) |
{ |
156,8 → 161,21 |
if (sclk > rdev->pm.default_sclk) |
sclk = rdev->pm.default_sclk; |
|
/* starting with BTC, there is one state that is used for both |
* MH and SH. Difference is that we always use the high clock index for |
* mclk. |
*/ |
if ((rdev->pm.pm_method == PM_METHOD_PROFILE) && |
(rdev->family >= CHIP_BARTS) && |
rdev->pm.active_crtc_count && |
((rdev->pm.profile_index == PM_PROFILE_MID_MH_IDX) || |
(rdev->pm.profile_index == PM_PROFILE_LOW_MH_IDX))) |
mclk = rdev->pm.power_state[rdev->pm.requested_power_state_index]. |
clock_info[rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx].mclk; |
else |
mclk = rdev->pm.power_state[rdev->pm.requested_power_state_index]. |
clock_info[rdev->pm.requested_clock_mode_index].mclk; |
|
if (mclk > rdev->pm.default_mclk) |
mclk = rdev->pm.default_mclk; |
|
165,7 → 183,7 |
if (sclk < rdev->pm.current_sclk) |
misc_after = true; |
|
// radeon_sync_with_vblank(rdev); |
radeon_sync_with_vblank(rdev); |
|
if (rdev->pm.pm_method == PM_METHOD_DYNPM) { |
if (!radeon_pm_in_vbl(rdev)) |
188,7 → 206,7 |
} |
|
/* set memory clock */ |
if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { |
if (rdev->asic->pm.set_memory_clock && (mclk != rdev->pm.current_mclk)) { |
radeon_pm_debug_check_in_vbl(rdev, false); |
radeon_set_memory_clock(rdev, mclk); |
radeon_pm_debug_check_in_vbl(rdev, true); |
218,27 → 236,16 |
return; |
|
mutex_lock(&rdev->ddev->struct_mutex); |
mutex_lock(&rdev->vram_mutex); |
mutex_lock(&rdev->cp.mutex); |
// down_write(&rdev->pm.mclk_lock); |
mutex_lock(&rdev->ring_lock); |
|
/* gui idle int has issues on older chips it seems */ |
if (rdev->family >= CHIP_R600) { |
if (rdev->irq.installed) { |
/* wait for GPU idle */ |
rdev->pm.gui_idle = false; |
rdev->irq.gui_idle = true; |
/* wait for the rings to drain */ |
for (i = 0; i < RADEON_NUM_RINGS; i++) { |
struct radeon_ring *ring = &rdev->ring[i]; |
if (ring->ready) |
radeon_fence_wait_empty_locked(rdev, i); |
} |
} else { |
if (rdev->cp.ready) { |
// struct radeon_fence *fence; |
// radeon_ring_alloc(rdev, 64); |
// radeon_fence_create(rdev, &fence); |
// radeon_fence_emit(rdev, fence); |
// radeon_ring_commit(rdev); |
// radeon_fence_wait(fence, false); |
// radeon_fence_unref(&fence); |
} |
} |
|
radeon_unmap_vram_bos(rdev); |
|
if (rdev->irq.installed) { |
268,8 → 275,8 |
|
rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE; |
|
mutex_unlock(&rdev->cp.mutex); |
mutex_unlock(&rdev->vram_mutex); |
mutex_unlock(&rdev->ring_lock); |
// up_write(&rdev->pm.mclk_lock); |
mutex_unlock(&rdev->ddev->struct_mutex); |
} |
|
294,17 → 301,15 |
for (j = 0; j < power_state->num_clock_modes; j++) { |
clock_info = &(power_state->clock_info[j]); |
if (rdev->flags & RADEON_IS_IGP) |
DRM_DEBUG_DRIVER("\t\t%d e: %d%s\n", |
DRM_DEBUG_DRIVER("\t\t%d e: %d\n", |
j, |
clock_info->sclk * 10, |
clock_info->flags & RADEON_PM_MODE_NO_DISPLAY ? "\tNo display only" : ""); |
clock_info->sclk * 10); |
else |
DRM_DEBUG_DRIVER("\t\t%d e: %d\tm: %d\tv: %d%s\n", |
DRM_DEBUG_DRIVER("\t\t%d e: %d\tm: %d\tv: %d\n", |
j, |
clock_info->sclk * 10, |
clock_info->mclk * 10, |
clock_info->voltage.voltage, |
clock_info->flags & RADEON_PM_MODE_NO_DISPLAY ? "\tNo display only" : ""); |
clock_info->voltage.voltage); |
} |
} |
} |
313,8 → 318,15 |
struct device_attribute *attr, |
char *buf) |
{ |
struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev)); |
struct radeon_device *rdev = ddev->dev_private; |
int cp = rdev->pm.profile; |
|
return snprintf(buf, PAGE_SIZE, "%s\n", "default"); |
return snprintf(buf, PAGE_SIZE, "%s\n", |
(cp == PM_PROFILE_AUTO) ? "auto" : |
(cp == PM_PROFILE_LOW) ? "low" : |
(cp == PM_PROFILE_MID) ? "mid" : |
(cp == PM_PROFILE_HIGH) ? "high" : "default"); |
} |
|
static ssize_t radeon_set_pm_profile(struct device *dev, |
326,11 → 338,26 |
struct radeon_device *rdev = ddev->dev_private; |
|
mutex_lock(&rdev->pm.mutex); |
|
if (rdev->pm.pm_method == PM_METHOD_PROFILE) { |
if (strncmp("default", buf, strlen("default")) == 0) |
rdev->pm.profile = PM_PROFILE_DEFAULT; |
|
else if (strncmp("auto", buf, strlen("auto")) == 0) |
rdev->pm.profile = PM_PROFILE_AUTO; |
else if (strncmp("low", buf, strlen("low")) == 0) |
rdev->pm.profile = PM_PROFILE_LOW; |
else if (strncmp("mid", buf, strlen("mid")) == 0) |
rdev->pm.profile = PM_PROFILE_MID; |
else if (strncmp("high", buf, strlen("high")) == 0) |
rdev->pm.profile = PM_PROFILE_HIGH; |
else { |
count = -EINVAL; |
goto fail; |
} |
radeon_pm_update_profile(rdev); |
radeon_pm_set_clocks(rdev); |
} else |
count = -EINVAL; |
|
fail: |
mutex_unlock(&rdev->pm.mutex); |
|
373,7 → 400,7 |
mutex_unlock(&rdev->pm.mutex); |
// cancel_delayed_work_sync(&rdev->pm.dynpm_idle_work); |
} else { |
DRM_ERROR("invalid power method!\n"); |
count = -EINVAL; |
goto fail; |
} |
radeon_pm_compute_clocks(rdev); |
381,6 → 408,9 |
return count; |
} |
|
//static DEVICE_ATTR(power_profile, S_IRUGO | S_IWUSR, radeon_get_pm_profile, radeon_set_pm_profile); |
//static DEVICE_ATTR(power_method, S_IRUGO | S_IWUSR, radeon_get_pm_method, radeon_set_pm_method); |
|
static ssize_t radeon_hwmon_show_temp(struct device *dev, |
struct device_attribute *attr, |
char *buf) |
387,7 → 417,7 |
{ |
struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev)); |
struct radeon_device *rdev = ddev->dev_private; |
u32 temp; |
int temp; |
|
switch (rdev->pm.int_thermal_type) { |
case THERMAL_TYPE_RV6XX: |
400,6 → 430,12 |
case THERMAL_TYPE_NI: |
temp = evergreen_get_temp(rdev); |
break; |
case THERMAL_TYPE_SUMO: |
temp = sumo_get_temp(rdev); |
break; |
case THERMAL_TYPE_SI: |
temp = si_get_temp(rdev); |
break; |
default: |
temp = 0; |
break; |