diff options
-rw-r--r-- | drivers/gpu/drm/radeon/Makefile | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/r600.c | 27 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/r600_dpm.c | 45 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/r600_dpm.h | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/r600d.h | 13 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon.h | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_asic.c | 12 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_asic.h | 12 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_atombios.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_irq_kms.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_mode.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_pm.c | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/rs780_dpm.c | 12 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/rv6xx_dpm.c | 1991 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/rv6xx_dpm.h | 95 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/rv6xxd.h | 246 |
16 files changed, 2477 insertions, 3 deletions
diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile index e44b046d8752..3aa20dc686fc 100644 --- a/drivers/gpu/drm/radeon/Makefile +++ b/drivers/gpu/drm/radeon/Makefile | |||
@@ -77,7 +77,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \ | |||
77 | evergreen_hdmi.o radeon_trace_points.o ni.o cayman_blit_shaders.o \ | 77 | evergreen_hdmi.o radeon_trace_points.o ni.o cayman_blit_shaders.o \ |
78 | atombios_encoders.o radeon_semaphore.o radeon_sa.o atombios_i2c.o si.o \ | 78 | atombios_encoders.o radeon_semaphore.o radeon_sa.o atombios_i2c.o si.o \ |
79 | si_blit_shaders.o radeon_prime.o radeon_uvd.o cik.o cik_blit_shaders.o \ | 79 | si_blit_shaders.o radeon_prime.o radeon_uvd.o cik.o cik_blit_shaders.o \ |
80 | r600_dpm.o rs780_dpm.o | 80 | r600_dpm.o rs780_dpm.o rv6xx_dpm.o |
81 | 81 | ||
82 | radeon-$(CONFIG_COMPAT) += radeon_ioc32.o | 82 | radeon-$(CONFIG_COMPAT) += radeon_ioc32.o |
83 | radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o | 83 | radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o |
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 4678ed102af6..ce5aa1febb80 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c | |||
@@ -3998,6 +3998,7 @@ int r600_irq_set(struct radeon_device *rdev) | |||
3998 | u32 hdmi0, hdmi1; | 3998 | u32 hdmi0, hdmi1; |
3999 | u32 d1grph = 0, d2grph = 0; | 3999 | u32 d1grph = 0, d2grph = 0; |
4000 | u32 dma_cntl; | 4000 | u32 dma_cntl; |
4001 | u32 thermal_int = 0; | ||
4001 | 4002 | ||
4002 | if (!rdev->irq.installed) { | 4003 | if (!rdev->irq.installed) { |
4003 | WARN(1, "Can't enable IRQ/MSI because no handler is installed\n"); | 4004 | WARN(1, "Can't enable IRQ/MSI because no handler is installed\n"); |
@@ -4032,8 +4033,18 @@ int r600_irq_set(struct radeon_device *rdev) | |||
4032 | hdmi0 = RREG32(HDMI0_AUDIO_PACKET_CONTROL) & ~HDMI0_AZ_FORMAT_WTRIG_MASK; | 4033 | hdmi0 = RREG32(HDMI0_AUDIO_PACKET_CONTROL) & ~HDMI0_AZ_FORMAT_WTRIG_MASK; |
4033 | hdmi1 = RREG32(HDMI1_AUDIO_PACKET_CONTROL) & ~HDMI0_AZ_FORMAT_WTRIG_MASK; | 4034 | hdmi1 = RREG32(HDMI1_AUDIO_PACKET_CONTROL) & ~HDMI0_AZ_FORMAT_WTRIG_MASK; |
4034 | } | 4035 | } |
4036 | |||
4035 | dma_cntl = RREG32(DMA_CNTL) & ~TRAP_ENABLE; | 4037 | dma_cntl = RREG32(DMA_CNTL) & ~TRAP_ENABLE; |
4036 | 4038 | ||
4039 | if ((rdev->family > CHIP_R600) && (rdev->family < CHIP_RV770)) { | ||
4040 | thermal_int = RREG32(CG_THERMAL_INT) & | ||
4041 | ~(THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW); | ||
4042 | if (rdev->irq.dpm_thermal) { | ||
4043 | DRM_DEBUG("dpm thermal\n"); | ||
4044 | thermal_int |= THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW; | ||
4045 | } | ||
4046 | } | ||
4047 | |||
4037 | if (atomic_read(&rdev->irq.ring_int[RADEON_RING_TYPE_GFX_INDEX])) { | 4048 | if (atomic_read(&rdev->irq.ring_int[RADEON_RING_TYPE_GFX_INDEX])) { |
4038 | DRM_DEBUG("r600_irq_set: sw int\n"); | 4049 | DRM_DEBUG("r600_irq_set: sw int\n"); |
4039 | cp_int_cntl |= RB_INT_ENABLE; | 4050 | cp_int_cntl |= RB_INT_ENABLE; |
@@ -4115,6 +4126,9 @@ int r600_irq_set(struct radeon_device *rdev) | |||
4115 | WREG32(HDMI0_AUDIO_PACKET_CONTROL, hdmi0); | 4126 | WREG32(HDMI0_AUDIO_PACKET_CONTROL, hdmi0); |
4116 | WREG32(HDMI1_AUDIO_PACKET_CONTROL, hdmi1); | 4127 | WREG32(HDMI1_AUDIO_PACKET_CONTROL, hdmi1); |
4117 | } | 4128 | } |
4129 | if ((rdev->family > CHIP_R600) && (rdev->family < CHIP_RV770)) { | ||
4130 | WREG32(CG_THERMAL_INT, thermal_int); | ||
4131 | } | ||
4118 | 4132 | ||
4119 | return 0; | 4133 | return 0; |
4120 | } | 4134 | } |
@@ -4306,6 +4320,7 @@ int r600_irq_process(struct radeon_device *rdev) | |||
4306 | u32 ring_index; | 4320 | u32 ring_index; |
4307 | bool queue_hotplug = false; | 4321 | bool queue_hotplug = false; |
4308 | bool queue_hdmi = false; | 4322 | bool queue_hdmi = false; |
4323 | bool queue_thermal = false; | ||
4309 | 4324 | ||
4310 | if (!rdev->ih.enabled || rdev->shutdown) | 4325 | if (!rdev->ih.enabled || rdev->shutdown) |
4311 | return IRQ_NONE; | 4326 | return IRQ_NONE; |
@@ -4473,6 +4488,16 @@ restart_ih: | |||
4473 | DRM_DEBUG("IH: DMA trap\n"); | 4488 | DRM_DEBUG("IH: DMA trap\n"); |
4474 | radeon_fence_process(rdev, R600_RING_TYPE_DMA_INDEX); | 4489 | radeon_fence_process(rdev, R600_RING_TYPE_DMA_INDEX); |
4475 | break; | 4490 | break; |
4491 | case 230: /* thermal low to high */ | ||
4492 | DRM_DEBUG("IH: thermal low to high\n"); | ||
4493 | rdev->pm.dpm.thermal.high_to_low = false; | ||
4494 | queue_thermal = true; | ||
4495 | break; | ||
4496 | case 231: /* thermal high to low */ | ||
4497 | DRM_DEBUG("IH: thermal high to low\n"); | ||
4498 | rdev->pm.dpm.thermal.high_to_low = true; | ||
4499 | queue_thermal = true; | ||
4500 | break; | ||
4476 | case 233: /* GUI IDLE */ | 4501 | case 233: /* GUI IDLE */ |
4477 | DRM_DEBUG("IH: GUI idle\n"); | 4502 | DRM_DEBUG("IH: GUI idle\n"); |
4478 | break; | 4503 | break; |
@@ -4489,6 +4514,8 @@ restart_ih: | |||
4489 | schedule_work(&rdev->hotplug_work); | 4514 | schedule_work(&rdev->hotplug_work); |
4490 | if (queue_hdmi) | 4515 | if (queue_hdmi) |
4491 | schedule_work(&rdev->audio_work); | 4516 | schedule_work(&rdev->audio_work); |
4517 | if (queue_thermal && rdev->pm.dpm_enabled) | ||
4518 | schedule_work(&rdev->pm.dpm.thermal.work); | ||
4492 | rdev->ih.rptr = rptr; | 4519 | rdev->ih.rptr = rptr; |
4493 | WREG32(IH_RB_RPTR, rdev->ih.rptr); | 4520 | WREG32(IH_RB_RPTR, rdev->ih.rptr); |
4494 | atomic_set(&rdev->ih.lock, 0); | 4521 | atomic_set(&rdev->ih.lock, 0); |
diff --git a/drivers/gpu/drm/radeon/r600_dpm.c b/drivers/gpu/drm/radeon/r600_dpm.c index 91bc5ab5b1e6..bf396a0f6a50 100644 --- a/drivers/gpu/drm/radeon/r600_dpm.c +++ b/drivers/gpu/drm/radeon/r600_dpm.c | |||
@@ -676,3 +676,48 @@ bool r600_is_uvd_state(u32 class, u32 class2) | |||
676 | return true; | 676 | return true; |
677 | return false; | 677 | return false; |
678 | } | 678 | } |
679 | |||
680 | int r600_set_thermal_temperature_range(struct radeon_device *rdev, | ||
681 | int min_temp, int max_temp) | ||
682 | { | ||
683 | int low_temp = 0 * 1000; | ||
684 | int high_temp = 255 * 1000; | ||
685 | |||
686 | if (low_temp < min_temp) | ||
687 | low_temp = min_temp; | ||
688 | if (high_temp > max_temp) | ||
689 | high_temp = max_temp; | ||
690 | if (high_temp < low_temp) { | ||
691 | DRM_ERROR("invalid thermal range: %d - %d\n", low_temp, high_temp); | ||
692 | return -EINVAL; | ||
693 | } | ||
694 | |||
695 | WREG32_P(CG_THERMAL_INT, DIG_THERM_INTH(high_temp / 1000), ~DIG_THERM_INTH_MASK); | ||
696 | WREG32_P(CG_THERMAL_INT, DIG_THERM_INTL(low_temp / 1000), ~DIG_THERM_INTL_MASK); | ||
697 | WREG32_P(CG_THERMAL_CTRL, DIG_THERM_DPM(high_temp / 1000), ~DIG_THERM_DPM_MASK); | ||
698 | |||
699 | rdev->pm.dpm.thermal.min_temp = low_temp; | ||
700 | rdev->pm.dpm.thermal.max_temp = high_temp; | ||
701 | |||
702 | return 0; | ||
703 | } | ||
704 | |||
705 | bool r600_is_internal_thermal_sensor(enum radeon_int_thermal_type sensor) | ||
706 | { | ||
707 | switch (sensor) { | ||
708 | case THERMAL_TYPE_RV6XX: | ||
709 | case THERMAL_TYPE_RV770: | ||
710 | case THERMAL_TYPE_EVERGREEN: | ||
711 | case THERMAL_TYPE_SUMO: | ||
712 | case THERMAL_TYPE_NI: | ||
713 | return true; | ||
714 | case THERMAL_TYPE_ADT7473_WITH_INTERNAL: | ||
715 | case THERMAL_TYPE_EMC2103_WITH_INTERNAL: | ||
716 | return false; /* need special handling */ | ||
717 | case THERMAL_TYPE_NONE: | ||
718 | case THERMAL_TYPE_EXTERNAL: | ||
719 | case THERMAL_TYPE_EXTERNAL_GPIO: | ||
720 | default: | ||
721 | return false; | ||
722 | } | ||
723 | } | ||
diff --git a/drivers/gpu/drm/radeon/r600_dpm.h b/drivers/gpu/drm/radeon/r600_dpm.h index 240a7ed325cc..bd33aa1df036 100644 --- a/drivers/gpu/drm/radeon/r600_dpm.h +++ b/drivers/gpu/drm/radeon/r600_dpm.h | |||
@@ -92,6 +92,10 @@ | |||
92 | #define R600_PM_NUMBER_OF_VOLTAGE_LEVELS 4 | 92 | #define R600_PM_NUMBER_OF_VOLTAGE_LEVELS 4 |
93 | #define R600_PM_NUMBER_OF_ACTIVITY_LEVELS 3 | 93 | #define R600_PM_NUMBER_OF_ACTIVITY_LEVELS 3 |
94 | 94 | ||
95 | /* XXX are these ok? */ | ||
96 | #define R600_TEMP_RANGE_MIN (90 * 1000) | ||
97 | #define R600_TEMP_RANGE_MAX (120 * 1000) | ||
98 | |||
95 | enum r600_power_level { | 99 | enum r600_power_level { |
96 | R600_POWER_LEVEL_LOW = 0, | 100 | R600_POWER_LEVEL_LOW = 0, |
97 | R600_POWER_LEVEL_MEDIUM = 1, | 101 | R600_POWER_LEVEL_MEDIUM = 1, |
@@ -207,4 +211,8 @@ void r600_wait_for_power_level(struct radeon_device *rdev, | |||
207 | void r600_start_dpm(struct radeon_device *rdev); | 211 | void r600_start_dpm(struct radeon_device *rdev); |
208 | void r600_stop_dpm(struct radeon_device *rdev); | 212 | void r600_stop_dpm(struct radeon_device *rdev); |
209 | 213 | ||
214 | int r600_set_thermal_temperature_range(struct radeon_device *rdev, | ||
215 | int min_temp, int max_temp); | ||
216 | bool r600_is_internal_thermal_sensor(enum radeon_int_thermal_type sensor); | ||
217 | |||
210 | #endif | 218 | #endif |
diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h index d6d385a95eb3..3bca4db4c46f 100644 --- a/drivers/gpu/drm/radeon/r600d.h +++ b/drivers/gpu/drm/radeon/r600d.h | |||
@@ -302,10 +302,23 @@ | |||
302 | #define GRBM_SOFT_RESET 0x8020 | 302 | #define GRBM_SOFT_RESET 0x8020 |
303 | #define SOFT_RESET_CP (1<<0) | 303 | #define SOFT_RESET_CP (1<<0) |
304 | 304 | ||
305 | #define CG_THERMAL_CTRL 0x7F0 | ||
306 | #define DIG_THERM_DPM(x) ((x) << 12) | ||
307 | #define DIG_THERM_DPM_MASK 0x000FF000 | ||
308 | #define DIG_THERM_DPM_SHIFT 12 | ||
305 | #define CG_THERMAL_STATUS 0x7F4 | 309 | #define CG_THERMAL_STATUS 0x7F4 |
306 | #define ASIC_T(x) ((x) << 0) | 310 | #define ASIC_T(x) ((x) << 0) |
307 | #define ASIC_T_MASK 0x1FF | 311 | #define ASIC_T_MASK 0x1FF |
308 | #define ASIC_T_SHIFT 0 | 312 | #define ASIC_T_SHIFT 0 |
313 | #define CG_THERMAL_INT 0x7F8 | ||
314 | #define DIG_THERM_INTH(x) ((x) << 8) | ||
315 | #define DIG_THERM_INTH_MASK 0x0000FF00 | ||
316 | #define DIG_THERM_INTH_SHIFT 8 | ||
317 | #define DIG_THERM_INTL(x) ((x) << 16) | ||
318 | #define DIG_THERM_INTL_MASK 0x00FF0000 | ||
319 | #define DIG_THERM_INTL_SHIFT 16 | ||
320 | #define THERM_INT_MASK_HIGH (1 << 24) | ||
321 | #define THERM_INT_MASK_LOW (1 << 25) | ||
309 | 322 | ||
310 | #define HDP_HOST_PATH_CNTL 0x2C00 | 323 | #define HDP_HOST_PATH_CNTL 0x2C00 |
311 | #define HDP_NONSURFACE_BASE 0x2C04 | 324 | #define HDP_NONSURFACE_BASE 0x2C04 |
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 0e077d4eaffd..f9069055b069 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h | |||
@@ -227,6 +227,8 @@ void radeon_atom_set_engine_dram_timings(struct radeon_device *rdev, | |||
227 | u32 eng_clock, u32 mem_clock); | 227 | u32 eng_clock, u32 mem_clock); |
228 | int radeon_atom_get_voltage_step(struct radeon_device *rdev, | 228 | int radeon_atom_get_voltage_step(struct radeon_device *rdev, |
229 | u8 voltage_type, u16 *voltage_step); | 229 | u8 voltage_type, u16 *voltage_step); |
230 | int radeon_atom_get_max_vddc(struct radeon_device *rdev, u8 voltage_type, | ||
231 | u16 voltage_id, u16 *voltage); | ||
230 | int radeon_atom_round_to_true_voltage(struct radeon_device *rdev, | 232 | int radeon_atom_round_to_true_voltage(struct radeon_device *rdev, |
231 | u8 voltage_type, | 233 | u8 voltage_type, |
232 | u16 nominal_voltage, | 234 | u16 nominal_voltage, |
@@ -681,6 +683,7 @@ struct radeon_irq { | |||
681 | bool hpd[RADEON_MAX_HPD_PINS]; | 683 | bool hpd[RADEON_MAX_HPD_PINS]; |
682 | bool afmt[RADEON_MAX_AFMT_BLOCKS]; | 684 | bool afmt[RADEON_MAX_AFMT_BLOCKS]; |
683 | union radeon_irq_stat_regs stat_regs; | 685 | union radeon_irq_stat_regs stat_regs; |
686 | bool dpm_thermal; | ||
684 | }; | 687 | }; |
685 | 688 | ||
686 | int radeon_irq_kms_init(struct radeon_device *rdev); | 689 | int radeon_irq_kms_init(struct radeon_device *rdev); |
diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 1448270e5b06..45fb196c2cb9 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c | |||
@@ -1147,6 +1147,18 @@ static struct radeon_asic rv6xx_asic = { | |||
1147 | .set_clock_gating = NULL, | 1147 | .set_clock_gating = NULL, |
1148 | .get_temperature = &rv6xx_get_temp, | 1148 | .get_temperature = &rv6xx_get_temp, |
1149 | }, | 1149 | }, |
1150 | .dpm = { | ||
1151 | .init = &rv6xx_dpm_init, | ||
1152 | .setup_asic = &rv6xx_setup_asic, | ||
1153 | .enable = &rv6xx_dpm_enable, | ||
1154 | .disable = &rv6xx_dpm_disable, | ||
1155 | .set_power_state = &rv6xx_dpm_set_power_state, | ||
1156 | .display_configuration_changed = &rv6xx_dpm_display_configuration_changed, | ||
1157 | .fini = &rv6xx_dpm_fini, | ||
1158 | .get_sclk = &rv6xx_dpm_get_sclk, | ||
1159 | .get_mclk = &rv6xx_dpm_get_mclk, | ||
1160 | .print_power_state = &rv6xx_dpm_print_power_state, | ||
1161 | }, | ||
1150 | .pflip = { | 1162 | .pflip = { |
1151 | .pre_page_flip = &rs600_pre_page_flip, | 1163 | .pre_page_flip = &rs600_pre_page_flip, |
1152 | .page_flip = &rs600_page_flip, | 1164 | .page_flip = &rs600_page_flip, |
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index a2faabd81c01..36f66faa1d15 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h | |||
@@ -402,6 +402,18 @@ int r600_mc_wait_for_idle(struct radeon_device *rdev); | |||
402 | u32 r600_get_xclk(struct radeon_device *rdev); | 402 | u32 r600_get_xclk(struct radeon_device *rdev); |
403 | uint64_t r600_get_gpu_clock_counter(struct radeon_device *rdev); | 403 | uint64_t r600_get_gpu_clock_counter(struct radeon_device *rdev); |
404 | int rv6xx_get_temp(struct radeon_device *rdev); | 404 | int rv6xx_get_temp(struct radeon_device *rdev); |
405 | /* rv6xx dpm */ | ||
406 | int rv6xx_dpm_init(struct radeon_device *rdev); | ||
407 | int rv6xx_dpm_enable(struct radeon_device *rdev); | ||
408 | void rv6xx_dpm_disable(struct radeon_device *rdev); | ||
409 | int rv6xx_dpm_set_power_state(struct radeon_device *rdev); | ||
410 | void rv6xx_setup_asic(struct radeon_device *rdev); | ||
411 | void rv6xx_dpm_display_configuration_changed(struct radeon_device *rdev); | ||
412 | void rv6xx_dpm_fini(struct radeon_device *rdev); | ||
413 | u32 rv6xx_dpm_get_sclk(struct radeon_device *rdev, bool low); | ||
414 | u32 rv6xx_dpm_get_mclk(struct radeon_device *rdev, bool low); | ||
415 | void rv6xx_dpm_print_power_state(struct radeon_device *rdev, | ||
416 | struct radeon_ps *ps); | ||
405 | /* rs780 dpm */ | 417 | /* rs780 dpm */ |
406 | int rs780_dpm_init(struct radeon_device *rdev); | 418 | int rs780_dpm_init(struct radeon_device *rdev); |
407 | int rs780_dpm_enable(struct radeon_device *rdev); | 419 | int rs780_dpm_enable(struct radeon_device *rdev); |
diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 90401fdc937c..612d9bc1ccb0 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c | |||
@@ -2268,8 +2268,8 @@ static void radeon_atombios_add_pplib_thermal_controller(struct radeon_device *r | |||
2268 | } | 2268 | } |
2269 | } | 2269 | } |
2270 | 2270 | ||
2271 | static void radeon_atombios_get_default_voltages(struct radeon_device *rdev, | 2271 | void radeon_atombios_get_default_voltages(struct radeon_device *rdev, |
2272 | u16 *vddc, u16 *vddci) | 2272 | u16 *vddc, u16 *vddci) |
2273 | { | 2273 | { |
2274 | struct radeon_mode_info *mode_info = &rdev->mode_info; | 2274 | struct radeon_mode_info *mode_info = &rdev->mode_info; |
2275 | int index = GetIndexIntoMasterTable(DATA, FirmwareInfo); | 2275 | int index = GetIndexIntoMasterTable(DATA, FirmwareInfo); |
diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index dbffecad5a4c..bcdefd1dcd43 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c | |||
@@ -116,6 +116,7 @@ void radeon_driver_irq_preinstall_kms(struct drm_device *dev) | |||
116 | /* Disable *all* interrupts */ | 116 | /* Disable *all* interrupts */ |
117 | for (i = 0; i < RADEON_NUM_RINGS; i++) | 117 | for (i = 0; i < RADEON_NUM_RINGS; i++) |
118 | atomic_set(&rdev->irq.ring_int[i], 0); | 118 | atomic_set(&rdev->irq.ring_int[i], 0); |
119 | rdev->irq.dpm_thermal = false; | ||
119 | for (i = 0; i < RADEON_MAX_HPD_PINS; i++) | 120 | for (i = 0; i < RADEON_MAX_HPD_PINS; i++) |
120 | rdev->irq.hpd[i] = false; | 121 | rdev->irq.hpd[i] = false; |
121 | for (i = 0; i < RADEON_MAX_CRTCS; i++) { | 122 | for (i = 0; i < RADEON_MAX_CRTCS; i++) { |
@@ -163,6 +164,7 @@ void radeon_driver_irq_uninstall_kms(struct drm_device *dev) | |||
163 | /* Disable *all* interrupts */ | 164 | /* Disable *all* interrupts */ |
164 | for (i = 0; i < RADEON_NUM_RINGS; i++) | 165 | for (i = 0; i < RADEON_NUM_RINGS; i++) |
165 | atomic_set(&rdev->irq.ring_int[i], 0); | 166 | atomic_set(&rdev->irq.ring_int[i], 0); |
167 | rdev->irq.dpm_thermal = false; | ||
166 | for (i = 0; i < RADEON_MAX_HPD_PINS; i++) | 168 | for (i = 0; i < RADEON_MAX_HPD_PINS; i++) |
167 | rdev->irq.hpd[i] = false; | 169 | rdev->irq.hpd[i] = false; |
168 | for (i = 0; i < RADEON_MAX_CRTCS; i++) { | 170 | for (i = 0; i < RADEON_MAX_CRTCS; i++) { |
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 5a1c69ec6a41..02bf4a755f34 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h | |||
@@ -580,6 +580,8 @@ extern enum radeon_tv_std | |||
580 | radeon_combios_get_tv_info(struct radeon_device *rdev); | 580 | radeon_combios_get_tv_info(struct radeon_device *rdev); |
581 | extern enum radeon_tv_std | 581 | extern enum radeon_tv_std |
582 | radeon_atombios_get_tv_info(struct radeon_device *rdev); | 582 | radeon_atombios_get_tv_info(struct radeon_device *rdev); |
583 | extern void radeon_atombios_get_default_voltages(struct radeon_device *rdev, | ||
584 | u16 *vddc, u16 *vddci); | ||
583 | 585 | ||
584 | extern struct drm_connector * | 586 | extern struct drm_connector * |
585 | radeon_get_connector_for_encoder(struct drm_encoder *encoder); | 587 | radeon_get_connector_for_encoder(struct drm_encoder *encoder); |
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 853a8a2e141b..17f28974745e 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c | |||
@@ -1030,6 +1030,11 @@ int radeon_pm_init(struct radeon_device *rdev) | |||
1030 | { | 1030 | { |
1031 | /* enable dpm on rv6xx+ */ | 1031 | /* enable dpm on rv6xx+ */ |
1032 | switch (rdev->family) { | 1032 | switch (rdev->family) { |
1033 | case CHIP_RV610: | ||
1034 | case CHIP_RV630: | ||
1035 | case CHIP_RV620: | ||
1036 | case CHIP_RV635: | ||
1037 | case CHIP_RV670: | ||
1033 | case CHIP_RS780: | 1038 | case CHIP_RS780: |
1034 | case CHIP_RS880: | 1039 | case CHIP_RS880: |
1035 | if (radeon_dpm == 1) | 1040 | if (radeon_dpm == 1) |
@@ -1114,6 +1119,7 @@ static void radeon_pm_compute_clocks_old(struct radeon_device *rdev) | |||
1114 | if (rdev->pm.num_power_states < 2) | 1119 | if (rdev->pm.num_power_states < 2) |
1115 | return; | 1120 | return; |
1116 | 1121 | ||
1122 | INIT_WORK(&rdev->pm.dpm.thermal.work, radeon_dpm_thermal_work_handler); | ||
1117 | mutex_lock(&rdev->pm.mutex); | 1123 | mutex_lock(&rdev->pm.mutex); |
1118 | 1124 | ||
1119 | rdev->pm.active_crtcs = 0; | 1125 | rdev->pm.active_crtcs = 0; |
diff --git a/drivers/gpu/drm/radeon/rs780_dpm.c b/drivers/gpu/drm/radeon/rs780_dpm.c index f594900160a0..a1497a6315d6 100644 --- a/drivers/gpu/drm/radeon/rs780_dpm.c +++ b/drivers/gpu/drm/radeon/rs780_dpm.c | |||
@@ -560,6 +560,12 @@ int rs780_dpm_enable(struct radeon_device *rdev) | |||
560 | if (pi->gfx_clock_gating) | 560 | if (pi->gfx_clock_gating) |
561 | r600_gfx_clockgating_enable(rdev, true); | 561 | r600_gfx_clockgating_enable(rdev, true); |
562 | 562 | ||
563 | if (rdev->irq.installed && (rdev->pm.int_thermal_type == THERMAL_TYPE_RV6XX)) { | ||
564 | r600_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX); | ||
565 | rdev->irq.dpm_thermal = true; | ||
566 | radeon_irq_set(rdev); | ||
567 | } | ||
568 | |||
563 | return 0; | 569 | return 0; |
564 | } | 570 | } |
565 | 571 | ||
@@ -574,6 +580,12 @@ void rs780_dpm_disable(struct radeon_device *rdev) | |||
574 | 580 | ||
575 | if (pi->gfx_clock_gating) | 581 | if (pi->gfx_clock_gating) |
576 | r600_gfx_clockgating_enable(rdev, false); | 582 | r600_gfx_clockgating_enable(rdev, false); |
583 | |||
584 | if (rdev->irq.installed && | ||
585 | (rdev->pm.int_thermal_type == THERMAL_TYPE_RV6XX)) { | ||
586 | rdev->irq.dpm_thermal = false; | ||
587 | radeon_irq_set(rdev); | ||
588 | } | ||
577 | } | 589 | } |
578 | 590 | ||
579 | int rs780_dpm_set_power_state(struct radeon_device *rdev) | 591 | int rs780_dpm_set_power_state(struct radeon_device *rdev) |
diff --git a/drivers/gpu/drm/radeon/rv6xx_dpm.c b/drivers/gpu/drm/radeon/rv6xx_dpm.c new file mode 100644 index 000000000000..fa4beb2398cb --- /dev/null +++ b/drivers/gpu/drm/radeon/rv6xx_dpm.c | |||
@@ -0,0 +1,1991 @@ | |||
1 | /* | ||
2 | * Copyright 2011 Advanced Micro Devices, Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | * Authors: Alex Deucher | ||
23 | */ | ||
24 | |||
25 | #include "drmP.h" | ||
26 | #include "radeon.h" | ||
27 | #include "rv6xxd.h" | ||
28 | #include "r600_dpm.h" | ||
29 | #include "rv6xx_dpm.h" | ||
30 | #include "atom.h" | ||
31 | |||
32 | static u32 rv6xx_scale_count_given_unit(struct radeon_device *rdev, | ||
33 | u32 unscaled_count, u32 unit); | ||
34 | |||
35 | static struct rv6xx_ps *rv6xx_get_ps(struct radeon_ps *rps) | ||
36 | { | ||
37 | struct rv6xx_ps *ps = rps->ps_priv; | ||
38 | |||
39 | return ps; | ||
40 | } | ||
41 | |||
42 | static struct rv6xx_power_info *rv6xx_get_pi(struct radeon_device *rdev) | ||
43 | { | ||
44 | struct rv6xx_power_info *pi = rdev->pm.dpm.priv; | ||
45 | |||
46 | return pi; | ||
47 | } | ||
48 | |||
49 | static void rv6xx_force_pcie_gen1(struct radeon_device *rdev) | ||
50 | { | ||
51 | u32 tmp; | ||
52 | int i; | ||
53 | |||
54 | tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL); | ||
55 | tmp &= LC_GEN2_EN; | ||
56 | WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp); | ||
57 | |||
58 | tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL); | ||
59 | tmp |= LC_INITIATE_LINK_SPEED_CHANGE; | ||
60 | WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp); | ||
61 | |||
62 | for (i = 0; i < rdev->usec_timeout; i++) { | ||
63 | if (!(RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL) & LC_CURRENT_DATA_RATE)) | ||
64 | break; | ||
65 | udelay(1); | ||
66 | } | ||
67 | |||
68 | tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL); | ||
69 | tmp &= ~LC_INITIATE_LINK_SPEED_CHANGE; | ||
70 | WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp); | ||
71 | } | ||
72 | |||
73 | static void rv6xx_enable_pcie_gen2_support(struct radeon_device *rdev) | ||
74 | { | ||
75 | u32 tmp; | ||
76 | |||
77 | tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL); | ||
78 | |||
79 | if ((tmp & LC_OTHER_SIDE_EVER_SENT_GEN2) && | ||
80 | (tmp & LC_OTHER_SIDE_SUPPORTS_GEN2)) { | ||
81 | tmp |= LC_GEN2_EN; | ||
82 | WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp); | ||
83 | } | ||
84 | } | ||
85 | |||
86 | static void rv6xx_enable_bif_dynamic_pcie_gen2(struct radeon_device *rdev, | ||
87 | bool enable) | ||
88 | { | ||
89 | u32 tmp; | ||
90 | |||
91 | tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL) & ~LC_HW_VOLTAGE_IF_CONTROL_MASK; | ||
92 | if (enable) | ||
93 | tmp |= LC_HW_VOLTAGE_IF_CONTROL(1); | ||
94 | else | ||
95 | tmp |= LC_HW_VOLTAGE_IF_CONTROL(0); | ||
96 | WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp); | ||
97 | } | ||
98 | |||
99 | static void rv6xx_enable_l0s(struct radeon_device *rdev) | ||
100 | { | ||
101 | u32 tmp; | ||
102 | |||
103 | tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL) & ~LC_L0S_INACTIVITY_MASK; | ||
104 | tmp |= LC_L0S_INACTIVITY(3); | ||
105 | WREG32_PCIE_PORT(PCIE_LC_CNTL, tmp); | ||
106 | } | ||
107 | |||
108 | static void rv6xx_enable_l1(struct radeon_device *rdev) | ||
109 | { | ||
110 | u32 tmp; | ||
111 | |||
112 | tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL); | ||
113 | tmp &= ~LC_L1_INACTIVITY_MASK; | ||
114 | tmp |= LC_L1_INACTIVITY(4); | ||
115 | tmp &= ~LC_PMI_TO_L1_DIS; | ||
116 | tmp &= ~LC_ASPM_TO_L1_DIS; | ||
117 | WREG32_PCIE_PORT(PCIE_LC_CNTL, tmp); | ||
118 | } | ||
119 | |||
120 | static void rv6xx_enable_pll_sleep_in_l1(struct radeon_device *rdev) | ||
121 | { | ||
122 | u32 tmp; | ||
123 | |||
124 | tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL) & ~LC_L1_INACTIVITY_MASK; | ||
125 | tmp |= LC_L1_INACTIVITY(8); | ||
126 | WREG32_PCIE_PORT(PCIE_LC_CNTL, tmp); | ||
127 | |||
128 | /* NOTE, this is a PCIE indirect reg, not PCIE PORT */ | ||
129 | tmp = RREG32_PCIE(PCIE_P_CNTL); | ||
130 | tmp |= P_PLL_PWRDN_IN_L1L23; | ||
131 | tmp &= ~P_PLL_BUF_PDNB; | ||
132 | tmp &= ~P_PLL_PDNB; | ||
133 | tmp |= P_ALLOW_PRX_FRONTEND_SHUTOFF; | ||
134 | WREG32_PCIE(PCIE_P_CNTL, tmp); | ||
135 | } | ||
136 | |||
137 | static int rv6xx_convert_clock_to_stepping(struct radeon_device *rdev, | ||
138 | u32 clock, struct rv6xx_sclk_stepping *step) | ||
139 | { | ||
140 | int ret; | ||
141 | struct atom_clock_dividers dividers; | ||
142 | |||
143 | ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, | ||
144 | clock, false, ÷rs); | ||
145 | if (ret) | ||
146 | return ret; | ||
147 | |||
148 | if (dividers.enable_post_div) | ||
149 | step->post_divider = 2 + (dividers.post_div & 0xF) + (dividers.post_div >> 4); | ||
150 | else | ||
151 | step->post_divider = 1; | ||
152 | |||
153 | step->vco_frequency = clock * step->post_divider; | ||
154 | |||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | static void rv6xx_output_stepping(struct radeon_device *rdev, | ||
159 | u32 step_index, struct rv6xx_sclk_stepping *step) | ||
160 | { | ||
161 | struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); | ||
162 | u32 ref_clk = rdev->clock.spll.reference_freq; | ||
163 | u32 fb_divider; | ||
164 | u32 spll_step_count = rv6xx_scale_count_given_unit(rdev, | ||
165 | R600_SPLLSTEPTIME_DFLT * | ||
166 | pi->spll_ref_div, | ||
167 | R600_SPLLSTEPUNIT_DFLT); | ||
168 | |||
169 | r600_engine_clock_entry_enable(rdev, step_index, true); | ||
170 | r600_engine_clock_entry_enable_pulse_skipping(rdev, step_index, false); | ||
171 | |||
172 | if (step->post_divider == 1) | ||
173 | r600_engine_clock_entry_enable_post_divider(rdev, step_index, false); | ||
174 | else { | ||
175 | u32 lo_len = (step->post_divider - 2) / 2; | ||
176 | u32 hi_len = step->post_divider - 2 - lo_len; | ||
177 | |||
178 | r600_engine_clock_entry_enable_post_divider(rdev, step_index, true); | ||
179 | r600_engine_clock_entry_set_post_divider(rdev, step_index, (hi_len << 4) | lo_len); | ||
180 | } | ||
181 | |||
182 | fb_divider = ((step->vco_frequency * pi->spll_ref_div) / ref_clk) >> | ||
183 | pi->fb_div_scale; | ||
184 | |||
185 | r600_engine_clock_entry_set_reference_divider(rdev, step_index, | ||
186 | pi->spll_ref_div - 1); | ||
187 | r600_engine_clock_entry_set_feedback_divider(rdev, step_index, fb_divider); | ||
188 | r600_engine_clock_entry_set_step_time(rdev, step_index, spll_step_count); | ||
189 | |||
190 | } | ||
191 | |||
192 | static struct rv6xx_sclk_stepping rv6xx_next_vco_step(struct radeon_device *rdev, | ||
193 | struct rv6xx_sclk_stepping *cur, | ||
194 | bool increasing_vco, u32 step_size) | ||
195 | { | ||
196 | struct rv6xx_sclk_stepping next; | ||
197 | |||
198 | next.post_divider = cur->post_divider; | ||
199 | |||
200 | if (increasing_vco) | ||
201 | next.vco_frequency = (cur->vco_frequency * (100 + step_size)) / 100; | ||
202 | else | ||
203 | next.vco_frequency = (cur->vco_frequency * 100 + 99 + step_size) / (100 + step_size); | ||
204 | |||
205 | return next; | ||
206 | } | ||
207 | |||
208 | static bool rv6xx_can_step_post_div(struct radeon_device *rdev, | ||
209 | struct rv6xx_sclk_stepping *cur, | ||
210 | struct rv6xx_sclk_stepping *target) | ||
211 | { | ||
212 | return (cur->post_divider > target->post_divider) && | ||
213 | ((cur->vco_frequency * target->post_divider) <= | ||
214 | (target->vco_frequency * (cur->post_divider - 1))); | ||
215 | } | ||
216 | |||
217 | static struct rv6xx_sclk_stepping rv6xx_next_post_div_step(struct radeon_device *rdev, | ||
218 | struct rv6xx_sclk_stepping *cur, | ||
219 | struct rv6xx_sclk_stepping *target) | ||
220 | { | ||
221 | struct rv6xx_sclk_stepping next = *cur; | ||
222 | |||
223 | while (rv6xx_can_step_post_div(rdev, &next, target)) | ||
224 | next.post_divider--; | ||
225 | |||
226 | return next; | ||
227 | } | ||
228 | |||
229 | static bool rv6xx_reached_stepping_target(struct radeon_device *rdev, | ||
230 | struct rv6xx_sclk_stepping *cur, | ||
231 | struct rv6xx_sclk_stepping *target, | ||
232 | bool increasing_vco) | ||
233 | { | ||
234 | return (increasing_vco && (cur->vco_frequency >= target->vco_frequency)) || | ||
235 | (!increasing_vco && (cur->vco_frequency <= target->vco_frequency)); | ||
236 | } | ||
237 | |||
238 | static void rv6xx_generate_steps(struct radeon_device *rdev, | ||
239 | u32 low, u32 high, | ||
240 | u32 start_index, u8 *end_index) | ||
241 | { | ||
242 | struct rv6xx_sclk_stepping cur; | ||
243 | struct rv6xx_sclk_stepping target; | ||
244 | bool increasing_vco; | ||
245 | u32 step_index = start_index; | ||
246 | |||
247 | rv6xx_convert_clock_to_stepping(rdev, low, &cur); | ||
248 | rv6xx_convert_clock_to_stepping(rdev, high, &target); | ||
249 | |||
250 | rv6xx_output_stepping(rdev, step_index++, &cur); | ||
251 | |||
252 | increasing_vco = (target.vco_frequency >= cur.vco_frequency); | ||
253 | |||
254 | if (target.post_divider > cur.post_divider) | ||
255 | cur.post_divider = target.post_divider; | ||
256 | |||
257 | while (1) { | ||
258 | struct rv6xx_sclk_stepping next; | ||
259 | |||
260 | if (rv6xx_can_step_post_div(rdev, &cur, &target)) | ||
261 | next = rv6xx_next_post_div_step(rdev, &cur, &target); | ||
262 | else | ||
263 | next = rv6xx_next_vco_step(rdev, &cur, increasing_vco, R600_VCOSTEPPCT_DFLT); | ||
264 | |||
265 | if (rv6xx_reached_stepping_target(rdev, &next, &target, increasing_vco)) { | ||
266 | struct rv6xx_sclk_stepping tiny = | ||
267 | rv6xx_next_vco_step(rdev, &target, !increasing_vco, R600_ENDINGVCOSTEPPCT_DFLT); | ||
268 | tiny.post_divider = next.post_divider; | ||
269 | |||
270 | if (!rv6xx_reached_stepping_target(rdev, &tiny, &cur, !increasing_vco)) | ||
271 | rv6xx_output_stepping(rdev, step_index++, &tiny); | ||
272 | |||
273 | if ((next.post_divider != target.post_divider) && | ||
274 | (next.vco_frequency != target.vco_frequency)) { | ||
275 | struct rv6xx_sclk_stepping final_vco; | ||
276 | |||
277 | final_vco.vco_frequency = target.vco_frequency; | ||
278 | final_vco.post_divider = next.post_divider; | ||
279 | |||
280 | rv6xx_output_stepping(rdev, step_index++, &final_vco); | ||
281 | } | ||
282 | |||
283 | rv6xx_output_stepping(rdev, step_index++, &target); | ||
284 | break; | ||
285 | } else | ||
286 | rv6xx_output_stepping(rdev, step_index++, &next); | ||
287 | |||
288 | cur = next; | ||
289 | } | ||
290 | |||
291 | *end_index = (u8)step_index - 1; | ||
292 | |||
293 | } | ||
294 | |||
295 | static void rv6xx_generate_single_step(struct radeon_device *rdev, | ||
296 | u32 clock, u32 index) | ||
297 | { | ||
298 | struct rv6xx_sclk_stepping step; | ||
299 | |||
300 | rv6xx_convert_clock_to_stepping(rdev, clock, &step); | ||
301 | rv6xx_output_stepping(rdev, index, &step); | ||
302 | } | ||
303 | |||
304 | static void rv6xx_invalidate_intermediate_steps_range(struct radeon_device *rdev, | ||
305 | u32 start_index, u32 end_index) | ||
306 | { | ||
307 | u32 step_index; | ||
308 | |||
309 | for (step_index = start_index + 1; step_index < end_index; step_index++) | ||
310 | r600_engine_clock_entry_enable(rdev, step_index, false); | ||
311 | } | ||
312 | |||
313 | static void rv6xx_set_engine_spread_spectrum_clk_s(struct radeon_device *rdev, | ||
314 | u32 index, u32 clk_s) | ||
315 | { | ||
316 | WREG32_P(CG_SPLL_SPREAD_SPECTRUM_LOW + (index * 4), | ||
317 | CLKS(clk_s), ~CLKS_MASK); | ||
318 | } | ||
319 | |||
320 | static void rv6xx_set_engine_spread_spectrum_clk_v(struct radeon_device *rdev, | ||
321 | u32 index, u32 clk_v) | ||
322 | { | ||
323 | WREG32_P(CG_SPLL_SPREAD_SPECTRUM_LOW + (index * 4), | ||
324 | CLKV(clk_v), ~CLKV_MASK); | ||
325 | } | ||
326 | |||
327 | static void rv6xx_enable_engine_spread_spectrum(struct radeon_device *rdev, | ||
328 | u32 index, bool enable) | ||
329 | { | ||
330 | if (enable) | ||
331 | WREG32_P(CG_SPLL_SPREAD_SPECTRUM_LOW + (index * 4), | ||
332 | SSEN, ~SSEN); | ||
333 | else | ||
334 | WREG32_P(CG_SPLL_SPREAD_SPECTRUM_LOW + (index * 4), | ||
335 | 0, ~SSEN); | ||
336 | } | ||
337 | |||
338 | static void rv6xx_set_memory_spread_spectrum_clk_s(struct radeon_device *rdev, | ||
339 | u32 clk_s) | ||
340 | { | ||
341 | WREG32_P(CG_MPLL_SPREAD_SPECTRUM, CLKS(clk_s), ~CLKS_MASK); | ||
342 | } | ||
343 | |||
344 | static void rv6xx_set_memory_spread_spectrum_clk_v(struct radeon_device *rdev, | ||
345 | u32 clk_v) | ||
346 | { | ||
347 | WREG32_P(CG_MPLL_SPREAD_SPECTRUM, CLKV(clk_v), ~CLKV_MASK); | ||
348 | } | ||
349 | |||
350 | static void rv6xx_enable_memory_spread_spectrum(struct radeon_device *rdev, | ||
351 | bool enable) | ||
352 | { | ||
353 | if (enable) | ||
354 | WREG32_P(CG_MPLL_SPREAD_SPECTRUM, SSEN, ~SSEN); | ||
355 | else | ||
356 | WREG32_P(CG_MPLL_SPREAD_SPECTRUM, 0, ~SSEN); | ||
357 | } | ||
358 | |||
359 | static void rv6xx_enable_dynamic_spread_spectrum(struct radeon_device *rdev, | ||
360 | bool enable) | ||
361 | { | ||
362 | if (enable) | ||
363 | WREG32_P(GENERAL_PWRMGT, DYN_SPREAD_SPECTRUM_EN, ~DYN_SPREAD_SPECTRUM_EN); | ||
364 | else | ||
365 | WREG32_P(GENERAL_PWRMGT, 0, ~DYN_SPREAD_SPECTRUM_EN); | ||
366 | } | ||
367 | |||
368 | static void rv6xx_memory_clock_entry_enable_post_divider(struct radeon_device *rdev, | ||
369 | u32 index, bool enable) | ||
370 | { | ||
371 | if (enable) | ||
372 | WREG32_P(MPLL_FREQ_LEVEL_0 + (index * 4), | ||
373 | LEVEL0_MPLL_DIV_EN, ~LEVEL0_MPLL_DIV_EN); | ||
374 | else | ||
375 | WREG32_P(MPLL_FREQ_LEVEL_0 + (index * 4), 0, ~LEVEL0_MPLL_DIV_EN); | ||
376 | } | ||
377 | |||
378 | static void rv6xx_memory_clock_entry_set_post_divider(struct radeon_device *rdev, | ||
379 | u32 index, u32 divider) | ||
380 | { | ||
381 | WREG32_P(MPLL_FREQ_LEVEL_0 + (index * 4), | ||
382 | LEVEL0_MPLL_POST_DIV(divider), ~LEVEL0_MPLL_POST_DIV_MASK); | ||
383 | } | ||
384 | |||
385 | static void rv6xx_memory_clock_entry_set_feedback_divider(struct radeon_device *rdev, | ||
386 | u32 index, u32 divider) | ||
387 | { | ||
388 | WREG32_P(MPLL_FREQ_LEVEL_0 + (index * 4), LEVEL0_MPLL_FB_DIV(divider), | ||
389 | ~LEVEL0_MPLL_FB_DIV_MASK); | ||
390 | } | ||
391 | |||
392 | static void rv6xx_memory_clock_entry_set_reference_divider(struct radeon_device *rdev, | ||
393 | u32 index, u32 divider) | ||
394 | { | ||
395 | WREG32_P(MPLL_FREQ_LEVEL_0 + (index * 4), | ||
396 | LEVEL0_MPLL_REF_DIV(divider), ~LEVEL0_MPLL_REF_DIV_MASK); | ||
397 | } | ||
398 | |||
399 | static void rv6xx_vid_response_set_brt(struct radeon_device *rdev, u32 rt) | ||
400 | { | ||
401 | WREG32_P(VID_RT, BRT(rt), ~BRT_MASK); | ||
402 | } | ||
403 | |||
404 | static void rv6xx_enable_engine_feedback_and_reference_sync(struct radeon_device *rdev) | ||
405 | { | ||
406 | WREG32_P(SPLL_CNTL_MODE, SPLL_DIV_SYNC, ~SPLL_DIV_SYNC); | ||
407 | } | ||
408 | |||
409 | static u64 rv6xx_clocks_per_unit(u32 unit) | ||
410 | { | ||
411 | u64 tmp = 1 << (2 * unit); | ||
412 | |||
413 | return tmp; | ||
414 | } | ||
415 | |||
416 | static u32 rv6xx_scale_count_given_unit(struct radeon_device *rdev, | ||
417 | u32 unscaled_count, u32 unit) | ||
418 | { | ||
419 | u32 count_per_unit = (u32)rv6xx_clocks_per_unit(unit); | ||
420 | |||
421 | return (unscaled_count + count_per_unit - 1) / count_per_unit; | ||
422 | } | ||
423 | |||
424 | static u32 rv6xx_compute_count_for_delay(struct radeon_device *rdev, | ||
425 | u32 delay_us, u32 unit) | ||
426 | { | ||
427 | u32 ref_clk = rdev->clock.spll.reference_freq; | ||
428 | |||
429 | return rv6xx_scale_count_given_unit(rdev, delay_us * (ref_clk / 100), unit); | ||
430 | } | ||
431 | |||
432 | static void rv6xx_calculate_engine_speed_stepping_parameters(struct radeon_device *rdev, | ||
433 | struct rv6xx_ps *state) | ||
434 | { | ||
435 | struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); | ||
436 | |||
437 | pi->hw.sclks[R600_POWER_LEVEL_LOW] = | ||
438 | state->low.sclk; | ||
439 | pi->hw.sclks[R600_POWER_LEVEL_MEDIUM] = | ||
440 | state->medium.sclk; | ||
441 | pi->hw.sclks[R600_POWER_LEVEL_HIGH] = | ||
442 | state->high.sclk; | ||
443 | |||
444 | pi->hw.low_sclk_index = R600_POWER_LEVEL_LOW; | ||
445 | pi->hw.medium_sclk_index = R600_POWER_LEVEL_MEDIUM; | ||
446 | pi->hw.high_sclk_index = R600_POWER_LEVEL_HIGH; | ||
447 | } | ||
448 | |||
449 | static void rv6xx_calculate_memory_clock_stepping_parameters(struct radeon_device *rdev, | ||
450 | struct rv6xx_ps *state) | ||
451 | { | ||
452 | struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); | ||
453 | |||
454 | pi->hw.mclks[R600_POWER_LEVEL_CTXSW] = | ||
455 | state->high.mclk; | ||
456 | pi->hw.mclks[R600_POWER_LEVEL_HIGH] = | ||
457 | state->high.mclk; | ||
458 | pi->hw.mclks[R600_POWER_LEVEL_MEDIUM] = | ||
459 | state->medium.mclk; | ||
460 | pi->hw.mclks[R600_POWER_LEVEL_LOW] = | ||
461 | state->low.mclk; | ||
462 | |||
463 | pi->hw.high_mclk_index = R600_POWER_LEVEL_HIGH; | ||
464 | |||
465 | if (state->high.mclk == state->medium.mclk) | ||
466 | pi->hw.medium_mclk_index = | ||
467 | pi->hw.high_mclk_index; | ||
468 | else | ||
469 | pi->hw.medium_mclk_index = R600_POWER_LEVEL_MEDIUM; | ||
470 | |||
471 | |||
472 | if (state->medium.mclk == state->low.mclk) | ||
473 | pi->hw.low_mclk_index = | ||
474 | pi->hw.medium_mclk_index; | ||
475 | else | ||
476 | pi->hw.low_mclk_index = R600_POWER_LEVEL_LOW; | ||
477 | } | ||
478 | |||
479 | static void rv6xx_calculate_voltage_stepping_parameters(struct radeon_device *rdev, | ||
480 | struct rv6xx_ps *state) | ||
481 | { | ||
482 | struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); | ||
483 | |||
484 | pi->hw.vddc[R600_POWER_LEVEL_CTXSW] = state->high.vddc; | ||
485 | pi->hw.vddc[R600_POWER_LEVEL_HIGH] = state->high.vddc; | ||
486 | pi->hw.vddc[R600_POWER_LEVEL_MEDIUM] = state->medium.vddc; | ||
487 | pi->hw.vddc[R600_POWER_LEVEL_LOW] = state->low.vddc; | ||
488 | |||
489 | pi->hw.backbias[R600_POWER_LEVEL_CTXSW] = | ||
490 | (state->high.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) ? true : false; | ||
491 | pi->hw.backbias[R600_POWER_LEVEL_HIGH] = | ||
492 | (state->high.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) ? true : false; | ||
493 | pi->hw.backbias[R600_POWER_LEVEL_MEDIUM] = | ||
494 | (state->medium.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) ? true : false; | ||
495 | pi->hw.backbias[R600_POWER_LEVEL_LOW] = | ||
496 | (state->low.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) ? true : false; | ||
497 | |||
498 | pi->hw.pcie_gen2[R600_POWER_LEVEL_HIGH] = | ||
499 | (state->high.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) ? true : false; | ||
500 | pi->hw.pcie_gen2[R600_POWER_LEVEL_MEDIUM] = | ||
501 | (state->medium.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) ? true : false; | ||
502 | pi->hw.pcie_gen2[R600_POWER_LEVEL_LOW] = | ||
503 | (state->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) ? true : false; | ||
504 | |||
505 | pi->hw.high_vddc_index = R600_POWER_LEVEL_HIGH; | ||
506 | |||
507 | if ((state->high.vddc == state->medium.vddc) && | ||
508 | ((state->high.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) == | ||
509 | (state->medium.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE))) | ||
510 | pi->hw.medium_vddc_index = | ||
511 | pi->hw.high_vddc_index; | ||
512 | else | ||
513 | pi->hw.medium_vddc_index = R600_POWER_LEVEL_MEDIUM; | ||
514 | |||
515 | if ((state->medium.vddc == state->low.vddc) && | ||
516 | ((state->medium.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) == | ||
517 | (state->low.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE))) | ||
518 | pi->hw.low_vddc_index = | ||
519 | pi->hw.medium_vddc_index; | ||
520 | else | ||
521 | pi->hw.medium_vddc_index = R600_POWER_LEVEL_LOW; | ||
522 | } | ||
523 | |||
524 | static inline u32 rv6xx_calculate_vco_frequency(u32 ref_clock, | ||
525 | struct atom_clock_dividers *dividers, | ||
526 | u32 fb_divider_scale) | ||
527 | { | ||
528 | return ref_clock * ((dividers->fb_div & ~1) << fb_divider_scale) / | ||
529 | (dividers->ref_div + 1); | ||
530 | } | ||
531 | |||
532 | static inline u32 rv6xx_calculate_spread_spectrum_clk_v(u32 vco_freq, u32 ref_freq, | ||
533 | u32 ss_rate, u32 ss_percent, | ||
534 | u32 fb_divider_scale) | ||
535 | { | ||
536 | u32 fb_divider = vco_freq / ref_freq; | ||
537 | |||
538 | return (ss_percent * ss_rate * 4 * (fb_divider * fb_divider) / | ||
539 | (5375 * ((vco_freq * 10) / (4096 >> fb_divider_scale)))); | ||
540 | } | ||
541 | |||
542 | static inline u32 rv6xx_calculate_spread_spectrum_clk_s(u32 ss_rate, u32 ref_freq) | ||
543 | { | ||
544 | return (((ref_freq * 10) / (ss_rate * 2)) - 1) / 4; | ||
545 | } | ||
546 | |||
547 | static void rv6xx_program_engine_spread_spectrum(struct radeon_device *rdev, | ||
548 | u32 clock, enum r600_power_level level) | ||
549 | { | ||
550 | u32 ref_clk = rdev->clock.spll.reference_freq; | ||
551 | struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); | ||
552 | struct atom_clock_dividers dividers; | ||
553 | struct radeon_atom_ss ss; | ||
554 | u32 vco_freq, clk_v, clk_s; | ||
555 | |||
556 | rv6xx_enable_engine_spread_spectrum(rdev, level, false); | ||
557 | |||
558 | if (clock && pi->sclk_ss) { | ||
559 | if (radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, clock, false, ÷rs) == 0) { | ||
560 | vco_freq = rv6xx_calculate_vco_frequency(ref_clk, ÷rs, | ||
561 | pi->fb_div_scale); | ||
562 | |||
563 | if (radeon_atombios_get_asic_ss_info(rdev, &ss, | ||
564 | ASIC_INTERNAL_ENGINE_SS, vco_freq)) { | ||
565 | clk_v = rv6xx_calculate_spread_spectrum_clk_v(vco_freq, | ||
566 | (ref_clk / (dividers.ref_div + 1)), | ||
567 | ss.rate, | ||
568 | ss.percentage, | ||
569 | pi->fb_div_scale); | ||
570 | |||
571 | clk_s = rv6xx_calculate_spread_spectrum_clk_s(ss.rate, | ||
572 | (ref_clk / (dividers.ref_div + 1))); | ||
573 | |||
574 | rv6xx_set_engine_spread_spectrum_clk_v(rdev, level, clk_v); | ||
575 | rv6xx_set_engine_spread_spectrum_clk_s(rdev, level, clk_s); | ||
576 | rv6xx_enable_engine_spread_spectrum(rdev, level, true); | ||
577 | } | ||
578 | } | ||
579 | } | ||
580 | } | ||
581 | |||
582 | static void rv6xx_program_sclk_spread_spectrum_parameters_except_lowest_entry(struct radeon_device *rdev) | ||
583 | { | ||
584 | struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); | ||
585 | |||
586 | rv6xx_program_engine_spread_spectrum(rdev, | ||
587 | pi->hw.sclks[R600_POWER_LEVEL_HIGH], | ||
588 | R600_POWER_LEVEL_HIGH); | ||
589 | |||
590 | rv6xx_program_engine_spread_spectrum(rdev, | ||
591 | pi->hw.sclks[R600_POWER_LEVEL_MEDIUM], | ||
592 | R600_POWER_LEVEL_MEDIUM); | ||
593 | |||
594 | } | ||
595 | |||
596 | static int rv6xx_program_mclk_stepping_entry(struct radeon_device *rdev, | ||
597 | u32 entry, u32 clock) | ||
598 | { | ||
599 | struct atom_clock_dividers dividers; | ||
600 | |||
601 | if (radeon_atom_get_clock_dividers(rdev, COMPUTE_MEMORY_PLL_PARAM, clock, false, ÷rs)) | ||
602 | return -EINVAL; | ||
603 | |||
604 | |||
605 | rv6xx_memory_clock_entry_set_reference_divider(rdev, entry, dividers.ref_div); | ||
606 | rv6xx_memory_clock_entry_set_feedback_divider(rdev, entry, dividers.fb_div); | ||
607 | rv6xx_memory_clock_entry_set_post_divider(rdev, entry, dividers.post_div); | ||
608 | |||
609 | if (dividers.enable_post_div) | ||
610 | rv6xx_memory_clock_entry_enable_post_divider(rdev, entry, true); | ||
611 | else | ||
612 | rv6xx_memory_clock_entry_enable_post_divider(rdev, entry, false); | ||
613 | |||
614 | return 0; | ||
615 | } | ||
616 | |||
617 | static void rv6xx_program_mclk_stepping_parameters_except_lowest_entry(struct radeon_device *rdev) | ||
618 | { | ||
619 | struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); | ||
620 | int i; | ||
621 | |||
622 | for (i = 1; i < R600_PM_NUMBER_OF_MCLKS; i++) { | ||
623 | if (pi->hw.mclks[i]) | ||
624 | rv6xx_program_mclk_stepping_entry(rdev, i, | ||
625 | pi->hw.mclks[i]); | ||
626 | } | ||
627 | } | ||
628 | |||
629 | static void rv6xx_find_memory_clock_with_highest_vco(struct radeon_device *rdev, | ||
630 | u32 requested_memory_clock, | ||
631 | u32 ref_clk, | ||
632 | struct atom_clock_dividers *dividers, | ||
633 | u32 *vco_freq) | ||
634 | { | ||
635 | struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); | ||
636 | struct atom_clock_dividers req_dividers; | ||
637 | u32 vco_freq_temp; | ||
638 | |||
639 | if (radeon_atom_get_clock_dividers(rdev, COMPUTE_MEMORY_PLL_PARAM, | ||
640 | requested_memory_clock, false, &req_dividers) == 0) { | ||
641 | vco_freq_temp = rv6xx_calculate_vco_frequency(ref_clk, &req_dividers, | ||
642 | pi->fb_div_scale); | ||
643 | |||
644 | if (vco_freq_temp > *vco_freq) { | ||
645 | *dividers = req_dividers; | ||
646 | *vco_freq = vco_freq_temp; | ||
647 | } | ||
648 | } | ||
649 | } | ||
650 | |||
651 | static void rv6xx_program_mclk_spread_spectrum_parameters(struct radeon_device *rdev) | ||
652 | { | ||
653 | struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); | ||
654 | u32 ref_clk = rdev->clock.mpll.reference_freq; | ||
655 | struct atom_clock_dividers dividers; | ||
656 | struct radeon_atom_ss ss; | ||
657 | u32 vco_freq = 0, clk_v, clk_s; | ||
658 | |||
659 | rv6xx_enable_memory_spread_spectrum(rdev, false); | ||
660 | |||
661 | if (pi->mclk_ss) { | ||
662 | rv6xx_find_memory_clock_with_highest_vco(rdev, | ||
663 | pi->hw.mclks[pi->hw.high_mclk_index], | ||
664 | ref_clk, | ||
665 | ÷rs, | ||
666 | &vco_freq); | ||
667 | |||
668 | rv6xx_find_memory_clock_with_highest_vco(rdev, | ||
669 | pi->hw.mclks[pi->hw.medium_mclk_index], | ||
670 | ref_clk, | ||
671 | ÷rs, | ||
672 | &vco_freq); | ||
673 | |||
674 | rv6xx_find_memory_clock_with_highest_vco(rdev, | ||
675 | pi->hw.mclks[pi->hw.low_mclk_index], | ||
676 | ref_clk, | ||
677 | ÷rs, | ||
678 | &vco_freq); | ||
679 | |||
680 | if (vco_freq) { | ||
681 | if (radeon_atombios_get_asic_ss_info(rdev, &ss, | ||
682 | ASIC_INTERNAL_MEMORY_SS, vco_freq)) { | ||
683 | clk_v = rv6xx_calculate_spread_spectrum_clk_v(vco_freq, | ||
684 | (ref_clk / (dividers.ref_div + 1)), | ||
685 | ss.rate, | ||
686 | ss.percentage, | ||
687 | pi->fb_div_scale); | ||
688 | |||
689 | clk_s = rv6xx_calculate_spread_spectrum_clk_s(ss.rate, | ||
690 | (ref_clk / (dividers.ref_div + 1))); | ||
691 | |||
692 | rv6xx_set_memory_spread_spectrum_clk_v(rdev, clk_v); | ||
693 | rv6xx_set_memory_spread_spectrum_clk_s(rdev, clk_s); | ||
694 | rv6xx_enable_memory_spread_spectrum(rdev, true); | ||
695 | } | ||
696 | } | ||
697 | } | ||
698 | } | ||
699 | |||
700 | static int rv6xx_program_voltage_stepping_entry(struct radeon_device *rdev, | ||
701 | u32 entry, u16 voltage) | ||
702 | { | ||
703 | u32 mask, set_pins; | ||
704 | int ret; | ||
705 | |||
706 | ret = radeon_atom_get_voltage_gpio_settings(rdev, voltage, | ||
707 | SET_VOLTAGE_TYPE_ASIC_VDDC, | ||
708 | &set_pins, &mask); | ||
709 | if (ret) | ||
710 | return ret; | ||
711 | |||
712 | r600_voltage_control_program_voltages(rdev, entry, set_pins); | ||
713 | |||
714 | return 0; | ||
715 | } | ||
716 | |||
717 | static void rv6xx_program_voltage_stepping_parameters_except_lowest_entry(struct radeon_device *rdev) | ||
718 | { | ||
719 | struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); | ||
720 | int i; | ||
721 | |||
722 | for (i = 1; i < R600_PM_NUMBER_OF_VOLTAGE_LEVELS; i++) | ||
723 | rv6xx_program_voltage_stepping_entry(rdev, i, | ||
724 | pi->hw.vddc[i]); | ||
725 | |||
726 | } | ||
727 | |||
728 | static void rv6xx_program_backbias_stepping_parameters_except_lowest_entry(struct radeon_device *rdev) | ||
729 | { | ||
730 | struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); | ||
731 | |||
732 | if (pi->hw.backbias[1]) | ||
733 | WREG32_P(VID_UPPER_GPIO_CNTL, MEDIUM_BACKBIAS_VALUE, ~MEDIUM_BACKBIAS_VALUE); | ||
734 | else | ||
735 | WREG32_P(VID_UPPER_GPIO_CNTL, 0, ~MEDIUM_BACKBIAS_VALUE); | ||
736 | |||
737 | if (pi->hw.backbias[2]) | ||
738 | WREG32_P(VID_UPPER_GPIO_CNTL, HIGH_BACKBIAS_VALUE, ~HIGH_BACKBIAS_VALUE); | ||
739 | else | ||
740 | WREG32_P(VID_UPPER_GPIO_CNTL, 0, ~HIGH_BACKBIAS_VALUE); | ||
741 | } | ||
742 | |||
743 | static void rv6xx_program_sclk_spread_spectrum_parameters_lowest_entry(struct radeon_device *rdev) | ||
744 | { | ||
745 | struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); | ||
746 | |||
747 | rv6xx_program_engine_spread_spectrum(rdev, | ||
748 | pi->hw.sclks[R600_POWER_LEVEL_LOW], | ||
749 | R600_POWER_LEVEL_LOW); | ||
750 | } | ||
751 | |||
752 | static void rv6xx_program_mclk_stepping_parameters_lowest_entry(struct radeon_device *rdev) | ||
753 | { | ||
754 | struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); | ||
755 | |||
756 | if (pi->hw.mclks[0]) | ||
757 | rv6xx_program_mclk_stepping_entry(rdev, 0, | ||
758 | pi->hw.mclks[0]); | ||
759 | } | ||
760 | |||
761 | static void rv6xx_program_voltage_stepping_parameters_lowest_entry(struct radeon_device *rdev) | ||
762 | { | ||
763 | struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); | ||
764 | |||
765 | rv6xx_program_voltage_stepping_entry(rdev, 0, | ||
766 | pi->hw.vddc[0]); | ||
767 | |||
768 | } | ||
769 | |||
770 | static void rv6xx_program_backbias_stepping_parameters_lowest_entry(struct radeon_device *rdev) | ||
771 | { | ||
772 | struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); | ||
773 | |||
774 | if (pi->hw.backbias[0]) | ||
775 | WREG32_P(VID_UPPER_GPIO_CNTL, LOW_BACKBIAS_VALUE, ~LOW_BACKBIAS_VALUE); | ||
776 | else | ||
777 | WREG32_P(VID_UPPER_GPIO_CNTL, 0, ~LOW_BACKBIAS_VALUE); | ||
778 | } | ||
779 | |||
780 | static u32 calculate_memory_refresh_rate(struct radeon_device *rdev, | ||
781 | u32 engine_clock) | ||
782 | { | ||
783 | u32 dram_rows, dram_refresh_rate; | ||
784 | u32 tmp; | ||
785 | |||
786 | tmp = (RREG32(RAMCFG) & NOOFROWS_MASK) >> NOOFROWS_SHIFT; | ||
787 | dram_rows = 1 << (tmp + 10); | ||
788 | dram_refresh_rate = 1 << ((RREG32(MC_SEQ_RESERVE_M) & 0x3) + 3); | ||
789 | |||
790 | return ((engine_clock * 10) * dram_refresh_rate / dram_rows - 32) / 64; | ||
791 | } | ||
792 | |||
793 | static void rv6xx_program_memory_timing_parameters(struct radeon_device *rdev) | ||
794 | { | ||
795 | struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); | ||
796 | u32 sqm_ratio; | ||
797 | u32 arb_refresh_rate; | ||
798 | u32 high_clock; | ||
799 | |||
800 | if (pi->hw.sclks[R600_POWER_LEVEL_HIGH] < | ||
801 | (pi->hw.sclks[R600_POWER_LEVEL_LOW] * 0xFF / 0x40)) | ||
802 | high_clock = pi->hw.sclks[R600_POWER_LEVEL_HIGH]; | ||
803 | else | ||
804 | high_clock = | ||
805 | pi->hw.sclks[R600_POWER_LEVEL_LOW] * 0xFF / 0x40; | ||
806 | |||
807 | radeon_atom_set_engine_dram_timings(rdev, high_clock, 0); | ||
808 | |||
809 | sqm_ratio = (STATE0(64 * high_clock / pi->hw.sclks[R600_POWER_LEVEL_LOW]) | | ||
810 | STATE1(64 * high_clock / pi->hw.sclks[R600_POWER_LEVEL_MEDIUM]) | | ||
811 | STATE2(64 * high_clock / pi->hw.sclks[R600_POWER_LEVEL_HIGH]) | | ||
812 | STATE3(64 * high_clock / pi->hw.sclks[R600_POWER_LEVEL_HIGH])); | ||
813 | WREG32(SQM_RATIO, sqm_ratio); | ||
814 | |||
815 | arb_refresh_rate = | ||
816 | (POWERMODE0(calculate_memory_refresh_rate(rdev, | ||
817 | pi->hw.sclks[R600_POWER_LEVEL_LOW])) | | ||
818 | POWERMODE1(calculate_memory_refresh_rate(rdev, | ||
819 | pi->hw.sclks[R600_POWER_LEVEL_MEDIUM])) | | ||
820 | POWERMODE2(calculate_memory_refresh_rate(rdev, | ||
821 | pi->hw.sclks[R600_POWER_LEVEL_MEDIUM])) | | ||
822 | POWERMODE3(calculate_memory_refresh_rate(rdev, | ||
823 | pi->hw.sclks[R600_POWER_LEVEL_HIGH]))); | ||
824 | WREG32(ARB_RFSH_RATE, arb_refresh_rate); | ||
825 | } | ||
826 | |||
827 | static void rv6xx_program_mpll_timing_parameters(struct radeon_device *rdev) | ||
828 | { | ||
829 | struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); | ||
830 | |||
831 | r600_set_mpll_lock_time(rdev, R600_MPLLLOCKTIME_DFLT * | ||
832 | pi->mpll_ref_div); | ||
833 | r600_set_mpll_reset_time(rdev, R600_MPLLRESETTIME_DFLT); | ||
834 | } | ||
835 | |||
836 | static void rv6xx_program_bsp(struct radeon_device *rdev) | ||
837 | { | ||
838 | struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); | ||
839 | u32 ref_clk = rdev->clock.spll.reference_freq; | ||
840 | |||
841 | r600_calculate_u_and_p(R600_ASI_DFLT, | ||
842 | ref_clk, 16, | ||
843 | &pi->bsp, | ||
844 | &pi->bsu); | ||
845 | |||
846 | r600_set_bsp(rdev, pi->bsu, pi->bsp); | ||
847 | } | ||
848 | |||
849 | static void rv6xx_program_at(struct radeon_device *rdev) | ||
850 | { | ||
851 | struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); | ||
852 | |||
853 | r600_set_at(rdev, | ||
854 | (pi->hw.rp[0] * pi->bsp) / 200, | ||
855 | (pi->hw.rp[1] * pi->bsp) / 200, | ||
856 | (pi->hw.lp[2] * pi->bsp) / 200, | ||
857 | (pi->hw.lp[1] * pi->bsp) / 200); | ||
858 | } | ||
859 | |||
860 | static void rv6xx_program_git(struct radeon_device *rdev) | ||
861 | { | ||
862 | r600_set_git(rdev, R600_GICST_DFLT); | ||
863 | } | ||
864 | |||
865 | static void rv6xx_program_tp(struct radeon_device *rdev) | ||
866 | { | ||
867 | int i; | ||
868 | |||
869 | for (i = 0; i < R600_PM_NUMBER_OF_TC; i++) | ||
870 | r600_set_tc(rdev, i, r600_utc[i], r600_dtc[i]); | ||
871 | |||
872 | r600_select_td(rdev, R600_TD_DFLT); | ||
873 | } | ||
874 | |||
875 | static void rv6xx_program_vc(struct radeon_device *rdev) | ||
876 | { | ||
877 | r600_set_vrc(rdev, R600_VRC_DFLT); | ||
878 | } | ||
879 | |||
880 | static void rv6xx_clear_vc(struct radeon_device *rdev) | ||
881 | { | ||
882 | r600_set_vrc(rdev, 0); | ||
883 | } | ||
884 | |||
885 | static void rv6xx_program_tpp(struct radeon_device *rdev) | ||
886 | { | ||
887 | r600_set_tpu(rdev, R600_TPU_DFLT); | ||
888 | r600_set_tpc(rdev, R600_TPC_DFLT); | ||
889 | } | ||
890 | |||
891 | static void rv6xx_program_sstp(struct radeon_device *rdev) | ||
892 | { | ||
893 | r600_set_sstu(rdev, R600_SSTU_DFLT); | ||
894 | r600_set_sst(rdev, R600_SST_DFLT); | ||
895 | } | ||
896 | |||
897 | static void rv6xx_program_fcp(struct radeon_device *rdev) | ||
898 | { | ||
899 | r600_set_fctu(rdev, R600_FCTU_DFLT); | ||
900 | r600_set_fct(rdev, R600_FCT_DFLT); | ||
901 | } | ||
902 | |||
903 | static void rv6xx_program_vddc3d_parameters(struct radeon_device *rdev) | ||
904 | { | ||
905 | r600_set_vddc3d_oorsu(rdev, R600_VDDC3DOORSU_DFLT); | ||
906 | r600_set_vddc3d_oorphc(rdev, R600_VDDC3DOORPHC_DFLT); | ||
907 | r600_set_vddc3d_oorsdc(rdev, R600_VDDC3DOORSDC_DFLT); | ||
908 | r600_set_ctxcgtt3d_rphc(rdev, R600_CTXCGTT3DRPHC_DFLT); | ||
909 | r600_set_ctxcgtt3d_rsdc(rdev, R600_CTXCGTT3DRSDC_DFLT); | ||
910 | } | ||
911 | |||
912 | static void rv6xx_program_voltage_timing_parameters(struct radeon_device *rdev) | ||
913 | { | ||
914 | u32 rt; | ||
915 | |||
916 | r600_vid_rt_set_vru(rdev, R600_VRU_DFLT); | ||
917 | |||
918 | r600_vid_rt_set_vrt(rdev, | ||
919 | rv6xx_compute_count_for_delay(rdev, | ||
920 | rdev->pm.dpm.voltage_response_time, | ||
921 | R600_VRU_DFLT)); | ||
922 | |||
923 | rt = rv6xx_compute_count_for_delay(rdev, | ||
924 | rdev->pm.dpm.backbias_response_time, | ||
925 | R600_VRU_DFLT); | ||
926 | |||
927 | rv6xx_vid_response_set_brt(rdev, (rt + 0x1F) >> 5); | ||
928 | } | ||
929 | |||
930 | static void rv6xx_program_engine_speed_parameters(struct radeon_device *rdev) | ||
931 | { | ||
932 | r600_vid_rt_set_ssu(rdev, R600_SPLLSTEPUNIT_DFLT); | ||
933 | rv6xx_enable_engine_feedback_and_reference_sync(rdev); | ||
934 | } | ||
935 | |||
936 | static u64 rv6xx_get_master_voltage_mask(struct radeon_device *rdev) | ||
937 | { | ||
938 | struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); | ||
939 | u64 master_mask = 0; | ||
940 | int i; | ||
941 | |||
942 | for (i = 0; i < R600_PM_NUMBER_OF_VOLTAGE_LEVELS; i++) { | ||
943 | u32 tmp_mask, tmp_set_pins; | ||
944 | int ret; | ||
945 | |||
946 | ret = radeon_atom_get_voltage_gpio_settings(rdev, | ||
947 | pi->hw.vddc[i], | ||
948 | SET_VOLTAGE_TYPE_ASIC_VDDC, | ||
949 | &tmp_set_pins, &tmp_mask); | ||
950 | |||
951 | if (ret == 0) | ||
952 | master_mask |= tmp_mask; | ||
953 | } | ||
954 | |||
955 | return master_mask; | ||
956 | } | ||
957 | |||
958 | static void rv6xx_program_voltage_gpio_pins(struct radeon_device *rdev) | ||
959 | { | ||
960 | r600_voltage_control_enable_pins(rdev, | ||
961 | rv6xx_get_master_voltage_mask(rdev)); | ||
962 | } | ||
963 | |||
964 | static void rv6xx_enable_static_voltage_control(struct radeon_device *rdev, bool enable) | ||
965 | { | ||
966 | struct rv6xx_ps *new_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps); | ||
967 | |||
968 | if (enable) | ||
969 | radeon_atom_set_voltage(rdev, | ||
970 | new_state->low.vddc, | ||
971 | SET_VOLTAGE_TYPE_ASIC_VDDC); | ||
972 | else | ||
973 | r600_voltage_control_deactivate_static_control(rdev, | ||
974 | rv6xx_get_master_voltage_mask(rdev)); | ||
975 | } | ||
976 | |||
977 | static void rv6xx_enable_display_gap(struct radeon_device *rdev, bool enable) | ||
978 | { | ||
979 | if (enable) { | ||
980 | u32 tmp = (DISP1_GAP(R600_PM_DISPLAY_GAP_VBLANK_OR_WM) | | ||
981 | DISP2_GAP(R600_PM_DISPLAY_GAP_VBLANK_OR_WM) | | ||
982 | DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE) | | ||
983 | DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE) | | ||
984 | VBI_TIMER_COUNT(0x3FFF) | | ||
985 | VBI_TIMER_UNIT(7)); | ||
986 | WREG32(CG_DISPLAY_GAP_CNTL, tmp); | ||
987 | |||
988 | WREG32_P(MCLK_PWRMGT_CNTL, USE_DISPLAY_GAP, ~USE_DISPLAY_GAP); | ||
989 | } else | ||
990 | WREG32_P(MCLK_PWRMGT_CNTL, 0, ~USE_DISPLAY_GAP); | ||
991 | } | ||
992 | |||
993 | static void rv6xx_program_power_level_enter_state(struct radeon_device *rdev) | ||
994 | { | ||
995 | r600_power_level_set_enter_index(rdev, R600_POWER_LEVEL_MEDIUM); | ||
996 | } | ||
997 | |||
998 | static void rv6xx_calculate_t(u32 l_f, u32 h_f, int h, | ||
999 | int d_l, int d_r, u8 *l, u8 *r) | ||
1000 | { | ||
1001 | int a_n, a_d, h_r, l_r; | ||
1002 | |||
1003 | h_r = d_l; | ||
1004 | l_r = 100 - d_r; | ||
1005 | |||
1006 | a_n = (int)h_f * d_l + (int)l_f * (h - d_r); | ||
1007 | a_d = (int)l_f * l_r + (int)h_f * h_r; | ||
1008 | |||
1009 | if (a_d != 0) { | ||
1010 | *l = d_l - h_r * a_n / a_d; | ||
1011 | *r = d_r + l_r * a_n / a_d; | ||
1012 | } | ||
1013 | } | ||
1014 | |||
1015 | static void rv6xx_calculate_ap(struct radeon_device *rdev, | ||
1016 | struct rv6xx_ps *state) | ||
1017 | { | ||
1018 | struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); | ||
1019 | |||
1020 | pi->hw.lp[0] = 0; | ||
1021 | pi->hw.rp[R600_PM_NUMBER_OF_ACTIVITY_LEVELS - 1] | ||
1022 | = 100; | ||
1023 | |||
1024 | rv6xx_calculate_t(state->low.sclk, | ||
1025 | state->medium.sclk, | ||
1026 | R600_AH_DFLT, | ||
1027 | R600_LMP_DFLT, | ||
1028 | R600_RLP_DFLT, | ||
1029 | &pi->hw.lp[1], | ||
1030 | &pi->hw.rp[0]); | ||
1031 | |||
1032 | rv6xx_calculate_t(state->medium.sclk, | ||
1033 | state->high.sclk, | ||
1034 | R600_AH_DFLT, | ||
1035 | R600_LHP_DFLT, | ||
1036 | R600_RMP_DFLT, | ||
1037 | &pi->hw.lp[2], | ||
1038 | &pi->hw.rp[1]); | ||
1039 | |||
1040 | } | ||
1041 | |||
1042 | static void rv6xx_calculate_stepping_parameters(struct radeon_device *rdev) | ||
1043 | { | ||
1044 | struct rv6xx_ps *new_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps); | ||
1045 | |||
1046 | rv6xx_calculate_engine_speed_stepping_parameters(rdev, new_state); | ||
1047 | rv6xx_calculate_memory_clock_stepping_parameters(rdev, new_state); | ||
1048 | rv6xx_calculate_voltage_stepping_parameters(rdev, new_state); | ||
1049 | rv6xx_calculate_ap(rdev, new_state); | ||
1050 | } | ||
1051 | |||
1052 | static void rv6xx_program_stepping_parameters_except_lowest_entry(struct radeon_device *rdev) | ||
1053 | { | ||
1054 | struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); | ||
1055 | |||
1056 | rv6xx_program_mclk_stepping_parameters_except_lowest_entry(rdev); | ||
1057 | if (pi->voltage_control) | ||
1058 | rv6xx_program_voltage_stepping_parameters_except_lowest_entry(rdev); | ||
1059 | rv6xx_program_backbias_stepping_parameters_except_lowest_entry(rdev); | ||
1060 | rv6xx_program_sclk_spread_spectrum_parameters_except_lowest_entry(rdev); | ||
1061 | rv6xx_program_mclk_spread_spectrum_parameters(rdev); | ||
1062 | rv6xx_program_memory_timing_parameters(rdev); | ||
1063 | } | ||
1064 | |||
1065 | static void rv6xx_program_stepping_parameters_lowest_entry(struct radeon_device *rdev) | ||
1066 | { | ||
1067 | struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); | ||
1068 | |||
1069 | rv6xx_program_mclk_stepping_parameters_lowest_entry(rdev); | ||
1070 | if (pi->voltage_control) | ||
1071 | rv6xx_program_voltage_stepping_parameters_lowest_entry(rdev); | ||
1072 | rv6xx_program_backbias_stepping_parameters_lowest_entry(rdev); | ||
1073 | rv6xx_program_sclk_spread_spectrum_parameters_lowest_entry(rdev); | ||
1074 | } | ||
1075 | |||
1076 | static void rv6xx_program_power_level_low(struct radeon_device *rdev) | ||
1077 | { | ||
1078 | struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); | ||
1079 | |||
1080 | r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_LOW, | ||
1081 | pi->hw.low_vddc_index); | ||
1082 | r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_LOW, | ||
1083 | pi->hw.low_mclk_index); | ||
1084 | r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_LOW, | ||
1085 | pi->hw.low_sclk_index); | ||
1086 | r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_LOW, | ||
1087 | R600_DISPLAY_WATERMARK_LOW); | ||
1088 | r600_power_level_set_pcie_gen2(rdev, R600_POWER_LEVEL_LOW, | ||
1089 | pi->hw.pcie_gen2[R600_POWER_LEVEL_LOW]); | ||
1090 | } | ||
1091 | |||
1092 | static void rv6xx_program_power_level_low_to_lowest_state(struct radeon_device *rdev) | ||
1093 | { | ||
1094 | struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); | ||
1095 | |||
1096 | r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_LOW, 0); | ||
1097 | r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_LOW, 0); | ||
1098 | r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_LOW, 0); | ||
1099 | |||
1100 | r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_LOW, | ||
1101 | R600_DISPLAY_WATERMARK_LOW); | ||
1102 | |||
1103 | r600_power_level_set_pcie_gen2(rdev, R600_POWER_LEVEL_LOW, | ||
1104 | pi->hw.pcie_gen2[R600_POWER_LEVEL_LOW]); | ||
1105 | |||
1106 | } | ||
1107 | |||
1108 | static void rv6xx_program_power_level_medium(struct radeon_device *rdev) | ||
1109 | { | ||
1110 | struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); | ||
1111 | |||
1112 | r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_MEDIUM, | ||
1113 | pi->hw.medium_vddc_index); | ||
1114 | r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_MEDIUM, | ||
1115 | pi->hw.medium_mclk_index); | ||
1116 | r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_MEDIUM, | ||
1117 | pi->hw.medium_sclk_index); | ||
1118 | r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_MEDIUM, | ||
1119 | R600_DISPLAY_WATERMARK_LOW); | ||
1120 | r600_power_level_set_pcie_gen2(rdev, R600_POWER_LEVEL_MEDIUM, | ||
1121 | pi->hw.pcie_gen2[R600_POWER_LEVEL_MEDIUM]); | ||
1122 | } | ||
1123 | |||
1124 | static void rv6xx_program_power_level_medium_for_transition(struct radeon_device *rdev) | ||
1125 | { | ||
1126 | struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); | ||
1127 | |||
1128 | rv6xx_program_mclk_stepping_entry(rdev, | ||
1129 | R600_POWER_LEVEL_CTXSW, | ||
1130 | pi->hw.mclks[pi->hw.low_mclk_index]); | ||
1131 | |||
1132 | r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_MEDIUM, 1); | ||
1133 | |||
1134 | r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_MEDIUM, | ||
1135 | R600_POWER_LEVEL_CTXSW); | ||
1136 | r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_MEDIUM, | ||
1137 | pi->hw.medium_sclk_index); | ||
1138 | |||
1139 | r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_MEDIUM, | ||
1140 | R600_DISPLAY_WATERMARK_LOW); | ||
1141 | |||
1142 | rv6xx_enable_engine_spread_spectrum(rdev, R600_POWER_LEVEL_MEDIUM, false); | ||
1143 | |||
1144 | r600_power_level_set_pcie_gen2(rdev, R600_POWER_LEVEL_MEDIUM, | ||
1145 | pi->hw.pcie_gen2[R600_POWER_LEVEL_LOW]); | ||
1146 | } | ||
1147 | |||
1148 | static void rv6xx_program_power_level_high(struct radeon_device *rdev) | ||
1149 | { | ||
1150 | struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); | ||
1151 | |||
1152 | r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_HIGH, | ||
1153 | pi->hw.high_vddc_index); | ||
1154 | r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_HIGH, | ||
1155 | pi->hw.high_mclk_index); | ||
1156 | r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_HIGH, | ||
1157 | pi->hw.high_sclk_index); | ||
1158 | |||
1159 | r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_HIGH, | ||
1160 | R600_DISPLAY_WATERMARK_HIGH); | ||
1161 | |||
1162 | r600_power_level_set_pcie_gen2(rdev, R600_POWER_LEVEL_HIGH, | ||
1163 | pi->hw.pcie_gen2[R600_POWER_LEVEL_HIGH]); | ||
1164 | } | ||
1165 | |||
1166 | static void rv6xx_enable_backbias(struct radeon_device *rdev, bool enable) | ||
1167 | { | ||
1168 | if (enable) | ||
1169 | WREG32_P(GENERAL_PWRMGT, BACKBIAS_PAD_EN | BACKBIAS_DPM_CNTL, | ||
1170 | ~(BACKBIAS_PAD_EN | BACKBIAS_DPM_CNTL)); | ||
1171 | else | ||
1172 | WREG32_P(GENERAL_PWRMGT, 0, | ||
1173 | ~(BACKBIAS_VALUE | BACKBIAS_PAD_EN | BACKBIAS_DPM_CNTL)); | ||
1174 | } | ||
1175 | |||
1176 | static void rv6xx_program_display_gap(struct radeon_device *rdev) | ||
1177 | { | ||
1178 | u32 tmp = RREG32(CG_DISPLAY_GAP_CNTL); | ||
1179 | |||
1180 | tmp &= ~(DISP1_GAP_MCHG_MASK | DISP2_GAP_MCHG_MASK); | ||
1181 | if (RREG32(AVIVO_D1CRTC_CONTROL) & AVIVO_CRTC_EN) { | ||
1182 | tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK); | ||
1183 | tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE); | ||
1184 | } else if (RREG32(AVIVO_D2CRTC_CONTROL) & AVIVO_CRTC_EN) { | ||
1185 | tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE); | ||
1186 | tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK); | ||
1187 | } else { | ||
1188 | tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE); | ||
1189 | tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE); | ||
1190 | } | ||
1191 | WREG32(CG_DISPLAY_GAP_CNTL, tmp); | ||
1192 | } | ||
1193 | |||
1194 | static void rv6xx_set_sw_voltage_to_safe(struct radeon_device *rdev) | ||
1195 | { | ||
1196 | struct rv6xx_ps *new_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps); | ||
1197 | struct rv6xx_ps *old_state = rv6xx_get_ps(rdev->pm.dpm.current_ps); | ||
1198 | u16 safe_voltage; | ||
1199 | |||
1200 | safe_voltage = (new_state->low.vddc >= old_state->low.vddc) ? | ||
1201 | new_state->low.vddc : old_state->low.vddc; | ||
1202 | |||
1203 | rv6xx_program_voltage_stepping_entry(rdev, R600_POWER_LEVEL_CTXSW, | ||
1204 | safe_voltage); | ||
1205 | |||
1206 | WREG32_P(GENERAL_PWRMGT, SW_GPIO_INDEX(R600_POWER_LEVEL_CTXSW), | ||
1207 | ~SW_GPIO_INDEX_MASK); | ||
1208 | } | ||
1209 | |||
1210 | static void rv6xx_set_sw_voltage_to_low(struct radeon_device *rdev) | ||
1211 | { | ||
1212 | struct rv6xx_ps *old_state = rv6xx_get_ps(rdev->pm.dpm.current_ps); | ||
1213 | |||
1214 | rv6xx_program_voltage_stepping_entry(rdev, R600_POWER_LEVEL_CTXSW, | ||
1215 | old_state->low.vddc); | ||
1216 | |||
1217 | WREG32_P(GENERAL_PWRMGT, SW_GPIO_INDEX(R600_POWER_LEVEL_CTXSW), | ||
1218 | ~SW_GPIO_INDEX_MASK); | ||
1219 | } | ||
1220 | |||
1221 | static void rv6xx_set_safe_backbias(struct radeon_device *rdev) | ||
1222 | { | ||
1223 | struct rv6xx_ps *new_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps); | ||
1224 | struct rv6xx_ps *old_state = rv6xx_get_ps(rdev->pm.dpm.current_ps); | ||
1225 | |||
1226 | if ((new_state->low.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) && | ||
1227 | (old_state->low.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE)) | ||
1228 | WREG32_P(GENERAL_PWRMGT, BACKBIAS_VALUE, ~BACKBIAS_VALUE); | ||
1229 | else | ||
1230 | WREG32_P(GENERAL_PWRMGT, 0, ~BACKBIAS_VALUE); | ||
1231 | } | ||
1232 | |||
1233 | static void rv6xx_set_safe_pcie_gen2(struct radeon_device *rdev) | ||
1234 | { | ||
1235 | struct rv6xx_ps *new_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps); | ||
1236 | struct rv6xx_ps *old_state = rv6xx_get_ps(rdev->pm.dpm.current_ps); | ||
1237 | |||
1238 | if ((new_state->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) != | ||
1239 | (old_state->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2)) | ||
1240 | rv6xx_force_pcie_gen1(rdev); | ||
1241 | } | ||
1242 | |||
1243 | static void rv6xx_enable_dynamic_voltage_control(struct radeon_device *rdev, | ||
1244 | bool enable) | ||
1245 | { | ||
1246 | if (enable) | ||
1247 | WREG32_P(GENERAL_PWRMGT, VOLT_PWRMGT_EN, ~VOLT_PWRMGT_EN); | ||
1248 | else | ||
1249 | WREG32_P(GENERAL_PWRMGT, 0, ~VOLT_PWRMGT_EN); | ||
1250 | } | ||
1251 | |||
1252 | static void rv6xx_enable_dynamic_backbias_control(struct radeon_device *rdev, | ||
1253 | bool enable) | ||
1254 | { | ||
1255 | if (enable) | ||
1256 | WREG32_P(GENERAL_PWRMGT, BACKBIAS_DPM_CNTL, ~BACKBIAS_DPM_CNTL); | ||
1257 | else | ||
1258 | WREG32_P(GENERAL_PWRMGT, 0, ~BACKBIAS_DPM_CNTL); | ||
1259 | } | ||
1260 | |||
1261 | static int rv6xx_step_sw_voltage(struct radeon_device *rdev, | ||
1262 | u16 initial_voltage, | ||
1263 | u16 target_voltage) | ||
1264 | { | ||
1265 | u16 current_voltage; | ||
1266 | u16 true_target_voltage; | ||
1267 | u16 voltage_step; | ||
1268 | int signed_voltage_step; | ||
1269 | |||
1270 | if ((radeon_atom_get_voltage_step(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, | ||
1271 | &voltage_step)) || | ||
1272 | (radeon_atom_round_to_true_voltage(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, | ||
1273 | initial_voltage, ¤t_voltage)) || | ||
1274 | (radeon_atom_round_to_true_voltage(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, | ||
1275 | target_voltage, &true_target_voltage))) | ||
1276 | return -EINVAL; | ||
1277 | |||
1278 | if (true_target_voltage < current_voltage) | ||
1279 | signed_voltage_step = -(int)voltage_step; | ||
1280 | else | ||
1281 | signed_voltage_step = voltage_step; | ||
1282 | |||
1283 | while (current_voltage != true_target_voltage) { | ||
1284 | current_voltage += signed_voltage_step; | ||
1285 | rv6xx_program_voltage_stepping_entry(rdev, R600_POWER_LEVEL_CTXSW, | ||
1286 | current_voltage); | ||
1287 | msleep((rdev->pm.dpm.voltage_response_time + 999) / 1000); | ||
1288 | } | ||
1289 | |||
1290 | return 0; | ||
1291 | } | ||
1292 | |||
1293 | static int rv6xx_step_voltage_if_increasing(struct radeon_device *rdev) | ||
1294 | { | ||
1295 | struct rv6xx_ps *new_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps); | ||
1296 | struct rv6xx_ps *old_state = rv6xx_get_ps(rdev->pm.dpm.current_ps); | ||
1297 | |||
1298 | if (new_state->low.vddc > old_state->low.vddc) | ||
1299 | return rv6xx_step_sw_voltage(rdev, | ||
1300 | old_state->low.vddc, | ||
1301 | new_state->low.vddc); | ||
1302 | |||
1303 | return 0; | ||
1304 | } | ||
1305 | |||
1306 | static int rv6xx_step_voltage_if_decreasing(struct radeon_device *rdev) | ||
1307 | { | ||
1308 | struct rv6xx_ps *new_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps); | ||
1309 | struct rv6xx_ps *old_state = rv6xx_get_ps(rdev->pm.dpm.current_ps); | ||
1310 | |||
1311 | if (new_state->low.vddc < old_state->low.vddc) | ||
1312 | return rv6xx_step_sw_voltage(rdev, | ||
1313 | old_state->low.vddc, | ||
1314 | new_state->low.vddc); | ||
1315 | else | ||
1316 | return 0; | ||
1317 | } | ||
1318 | |||
1319 | static void rv6xx_enable_high(struct radeon_device *rdev) | ||
1320 | { | ||
1321 | struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); | ||
1322 | |||
1323 | if ((pi->restricted_levels < 1) || | ||
1324 | (pi->restricted_levels == 3)) | ||
1325 | r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, true); | ||
1326 | } | ||
1327 | |||
1328 | static void rv6xx_enable_medium(struct radeon_device *rdev) | ||
1329 | { | ||
1330 | struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); | ||
1331 | |||
1332 | if (pi->restricted_levels < 2) | ||
1333 | r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, true); | ||
1334 | } | ||
1335 | |||
1336 | static void rv6xx_set_dpm_event_sources(struct radeon_device *rdev, u32 sources) | ||
1337 | { | ||
1338 | struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); | ||
1339 | bool want_thermal_protection; | ||
1340 | enum radeon_dpm_event_src dpm_event_src; | ||
1341 | |||
1342 | switch (sources) { | ||
1343 | case 0: | ||
1344 | default: | ||
1345 | want_thermal_protection = false; | ||
1346 | break; | ||
1347 | case (1 << RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL): | ||
1348 | want_thermal_protection = true; | ||
1349 | dpm_event_src = RADEON_DPM_EVENT_SRC_DIGITAL; | ||
1350 | break; | ||
1351 | |||
1352 | case (1 << RADEON_DPM_AUTO_THROTTLE_SRC_EXTERNAL): | ||
1353 | want_thermal_protection = true; | ||
1354 | dpm_event_src = RADEON_DPM_EVENT_SRC_EXTERNAL; | ||
1355 | break; | ||
1356 | |||
1357 | case ((1 << RADEON_DPM_AUTO_THROTTLE_SRC_EXTERNAL) | | ||
1358 | (1 << RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL)): | ||
1359 | want_thermal_protection = true; | ||
1360 | dpm_event_src = RADEON_DPM_EVENT_SRC_DIGIAL_OR_EXTERNAL; | ||
1361 | break; | ||
1362 | } | ||
1363 | |||
1364 | if (want_thermal_protection) { | ||
1365 | WREG32_P(CG_THERMAL_CTRL, DPM_EVENT_SRC(dpm_event_src), ~DPM_EVENT_SRC_MASK); | ||
1366 | if (pi->thermal_protection) | ||
1367 | WREG32_P(GENERAL_PWRMGT, 0, ~THERMAL_PROTECTION_DIS); | ||
1368 | } else { | ||
1369 | WREG32_P(GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, ~THERMAL_PROTECTION_DIS); | ||
1370 | } | ||
1371 | } | ||
1372 | |||
1373 | static void rv6xx_enable_auto_throttle_source(struct radeon_device *rdev, | ||
1374 | enum radeon_dpm_auto_throttle_src source, | ||
1375 | bool enable) | ||
1376 | { | ||
1377 | struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); | ||
1378 | |||
1379 | if (enable) { | ||
1380 | if (!(pi->active_auto_throttle_sources & (1 << source))) { | ||
1381 | pi->active_auto_throttle_sources |= 1 << source; | ||
1382 | rv6xx_set_dpm_event_sources(rdev, pi->active_auto_throttle_sources); | ||
1383 | } | ||
1384 | } else { | ||
1385 | if (pi->active_auto_throttle_sources & (1 << source)) { | ||
1386 | pi->active_auto_throttle_sources &= ~(1 << source); | ||
1387 | rv6xx_set_dpm_event_sources(rdev, pi->active_auto_throttle_sources); | ||
1388 | } | ||
1389 | } | ||
1390 | } | ||
1391 | |||
1392 | |||
1393 | static void rv6xx_enable_thermal_protection(struct radeon_device *rdev, | ||
1394 | bool enable) | ||
1395 | { | ||
1396 | struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); | ||
1397 | |||
1398 | if (pi->active_auto_throttle_sources) | ||
1399 | r600_enable_thermal_protection(rdev, enable); | ||
1400 | } | ||
1401 | |||
1402 | static void rv6xx_generate_transition_stepping(struct radeon_device *rdev) | ||
1403 | { | ||
1404 | struct rv6xx_ps *new_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps); | ||
1405 | struct rv6xx_ps *old_state = rv6xx_get_ps(rdev->pm.dpm.current_ps); | ||
1406 | struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); | ||
1407 | |||
1408 | rv6xx_generate_steps(rdev, | ||
1409 | old_state->low.sclk, | ||
1410 | new_state->low.sclk, | ||
1411 | 0, &pi->hw.medium_sclk_index); | ||
1412 | } | ||
1413 | |||
1414 | static void rv6xx_generate_low_step(struct radeon_device *rdev) | ||
1415 | { | ||
1416 | struct rv6xx_ps *new_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps); | ||
1417 | struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); | ||
1418 | |||
1419 | pi->hw.low_sclk_index = 0; | ||
1420 | rv6xx_generate_single_step(rdev, | ||
1421 | new_state->low.sclk, | ||
1422 | 0); | ||
1423 | } | ||
1424 | |||
1425 | static void rv6xx_invalidate_intermediate_steps(struct radeon_device *rdev) | ||
1426 | { | ||
1427 | struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); | ||
1428 | |||
1429 | rv6xx_invalidate_intermediate_steps_range(rdev, 0, | ||
1430 | pi->hw.medium_sclk_index); | ||
1431 | } | ||
1432 | |||
1433 | static void rv6xx_generate_stepping_table(struct radeon_device *rdev) | ||
1434 | { | ||
1435 | struct rv6xx_ps *new_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps); | ||
1436 | struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); | ||
1437 | |||
1438 | pi->hw.low_sclk_index = 0; | ||
1439 | |||
1440 | rv6xx_generate_steps(rdev, | ||
1441 | new_state->low.sclk, | ||
1442 | new_state->medium.sclk, | ||
1443 | 0, | ||
1444 | &pi->hw.medium_sclk_index); | ||
1445 | rv6xx_generate_steps(rdev, | ||
1446 | new_state->medium.sclk, | ||
1447 | new_state->high.sclk, | ||
1448 | pi->hw.medium_sclk_index, | ||
1449 | &pi->hw.high_sclk_index); | ||
1450 | } | ||
1451 | |||
1452 | static void rv6xx_enable_spread_spectrum(struct radeon_device *rdev, | ||
1453 | bool enable) | ||
1454 | { | ||
1455 | if (enable) | ||
1456 | rv6xx_enable_dynamic_spread_spectrum(rdev, true); | ||
1457 | else { | ||
1458 | rv6xx_enable_engine_spread_spectrum(rdev, R600_POWER_LEVEL_LOW, false); | ||
1459 | rv6xx_enable_engine_spread_spectrum(rdev, R600_POWER_LEVEL_MEDIUM, false); | ||
1460 | rv6xx_enable_engine_spread_spectrum(rdev, R600_POWER_LEVEL_HIGH, false); | ||
1461 | rv6xx_enable_dynamic_spread_spectrum(rdev, false); | ||
1462 | rv6xx_enable_memory_spread_spectrum(rdev, false); | ||
1463 | } | ||
1464 | } | ||
1465 | |||
1466 | static void rv6xx_reset_lvtm_data_sync(struct radeon_device *rdev) | ||
1467 | { | ||
1468 | if (ASIC_IS_DCE3(rdev)) | ||
1469 | WREG32_P(DCE3_LVTMA_DATA_SYNCHRONIZATION, LVTMA_PFREQCHG, ~LVTMA_PFREQCHG); | ||
1470 | else | ||
1471 | WREG32_P(LVTMA_DATA_SYNCHRONIZATION, LVTMA_PFREQCHG, ~LVTMA_PFREQCHG); | ||
1472 | } | ||
1473 | |||
1474 | static void rv6xx_enable_dynamic_pcie_gen2(struct radeon_device *rdev, | ||
1475 | bool enable) | ||
1476 | { | ||
1477 | struct rv6xx_ps *new_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps); | ||
1478 | |||
1479 | if (enable) { | ||
1480 | rv6xx_enable_bif_dynamic_pcie_gen2(rdev, true); | ||
1481 | rv6xx_enable_pcie_gen2_support(rdev); | ||
1482 | r600_enable_dynamic_pcie_gen2(rdev, true); | ||
1483 | } else { | ||
1484 | if (!(new_state->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2)) | ||
1485 | rv6xx_force_pcie_gen1(rdev); | ||
1486 | rv6xx_enable_bif_dynamic_pcie_gen2(rdev, false); | ||
1487 | r600_enable_dynamic_pcie_gen2(rdev, false); | ||
1488 | } | ||
1489 | } | ||
1490 | |||
1491 | int rv6xx_dpm_enable(struct radeon_device *rdev) | ||
1492 | { | ||
1493 | struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); | ||
1494 | |||
1495 | if (r600_dynamicpm_enabled(rdev)) | ||
1496 | return -EINVAL; | ||
1497 | |||
1498 | if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS) | ||
1499 | rv6xx_enable_backbias(rdev, true); | ||
1500 | |||
1501 | if (pi->dynamic_ss) | ||
1502 | rv6xx_enable_spread_spectrum(rdev, true); | ||
1503 | |||
1504 | rv6xx_program_mpll_timing_parameters(rdev); | ||
1505 | rv6xx_program_bsp(rdev); | ||
1506 | rv6xx_program_git(rdev); | ||
1507 | rv6xx_program_tp(rdev); | ||
1508 | rv6xx_program_tpp(rdev); | ||
1509 | rv6xx_program_sstp(rdev); | ||
1510 | rv6xx_program_fcp(rdev); | ||
1511 | rv6xx_program_vddc3d_parameters(rdev); | ||
1512 | rv6xx_program_voltage_timing_parameters(rdev); | ||
1513 | rv6xx_program_engine_speed_parameters(rdev); | ||
1514 | |||
1515 | rv6xx_enable_display_gap(rdev, true); | ||
1516 | if (pi->display_gap == false) | ||
1517 | rv6xx_enable_display_gap(rdev, false); | ||
1518 | |||
1519 | rv6xx_program_power_level_enter_state(rdev); | ||
1520 | |||
1521 | rv6xx_calculate_stepping_parameters(rdev); | ||
1522 | |||
1523 | if (pi->voltage_control) | ||
1524 | rv6xx_program_voltage_gpio_pins(rdev); | ||
1525 | |||
1526 | rv6xx_generate_stepping_table(rdev); | ||
1527 | |||
1528 | rv6xx_program_stepping_parameters_except_lowest_entry(rdev); | ||
1529 | rv6xx_program_stepping_parameters_lowest_entry(rdev); | ||
1530 | |||
1531 | rv6xx_program_power_level_low(rdev); | ||
1532 | rv6xx_program_power_level_medium(rdev); | ||
1533 | rv6xx_program_power_level_high(rdev); | ||
1534 | rv6xx_program_vc(rdev); | ||
1535 | rv6xx_program_at(rdev); | ||
1536 | |||
1537 | r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true); | ||
1538 | r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, true); | ||
1539 | r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, true); | ||
1540 | |||
1541 | if (rdev->irq.installed && | ||
1542 | r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) { | ||
1543 | r600_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX); | ||
1544 | rdev->irq.dpm_thermal = true; | ||
1545 | radeon_irq_set(rdev); | ||
1546 | } | ||
1547 | |||
1548 | rv6xx_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true); | ||
1549 | |||
1550 | r600_start_dpm(rdev); | ||
1551 | |||
1552 | if (pi->voltage_control) | ||
1553 | rv6xx_enable_static_voltage_control(rdev, false); | ||
1554 | |||
1555 | if (pi->dynamic_pcie_gen2) | ||
1556 | rv6xx_enable_dynamic_pcie_gen2(rdev, true); | ||
1557 | |||
1558 | if (pi->gfx_clock_gating) | ||
1559 | r600_gfx_clockgating_enable(rdev, true); | ||
1560 | |||
1561 | return 0; | ||
1562 | } | ||
1563 | |||
1564 | void rv6xx_dpm_disable(struct radeon_device *rdev) | ||
1565 | { | ||
1566 | struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); | ||
1567 | |||
1568 | if (!r600_dynamicpm_enabled(rdev)) | ||
1569 | return; | ||
1570 | |||
1571 | r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true); | ||
1572 | r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, true); | ||
1573 | rv6xx_enable_display_gap(rdev, false); | ||
1574 | rv6xx_clear_vc(rdev); | ||
1575 | r600_set_at(rdev, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF); | ||
1576 | |||
1577 | if (pi->thermal_protection) | ||
1578 | r600_enable_thermal_protection(rdev, false); | ||
1579 | |||
1580 | r600_wait_for_power_level(rdev, R600_POWER_LEVEL_LOW); | ||
1581 | r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, false); | ||
1582 | r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, false); | ||
1583 | |||
1584 | if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS) | ||
1585 | rv6xx_enable_backbias(rdev, false); | ||
1586 | |||
1587 | rv6xx_enable_spread_spectrum(rdev, false); | ||
1588 | |||
1589 | if (pi->voltage_control) | ||
1590 | rv6xx_enable_static_voltage_control(rdev, true); | ||
1591 | |||
1592 | if (pi->dynamic_pcie_gen2) | ||
1593 | rv6xx_enable_dynamic_pcie_gen2(rdev, false); | ||
1594 | |||
1595 | if (rdev->irq.installed && | ||
1596 | r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) { | ||
1597 | rdev->irq.dpm_thermal = false; | ||
1598 | radeon_irq_set(rdev); | ||
1599 | } | ||
1600 | |||
1601 | if (pi->gfx_clock_gating) | ||
1602 | r600_gfx_clockgating_enable(rdev, false); | ||
1603 | |||
1604 | r600_stop_dpm(rdev); | ||
1605 | } | ||
1606 | |||
1607 | int rv6xx_dpm_set_power_state(struct radeon_device *rdev) | ||
1608 | { | ||
1609 | struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); | ||
1610 | |||
1611 | rv6xx_clear_vc(rdev); | ||
1612 | r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true); | ||
1613 | r600_set_at(rdev, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF); | ||
1614 | |||
1615 | if (pi->thermal_protection) | ||
1616 | r600_enable_thermal_protection(rdev, false); | ||
1617 | |||
1618 | r600_wait_for_power_level(rdev, R600_POWER_LEVEL_LOW); | ||
1619 | r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, false); | ||
1620 | r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, false); | ||
1621 | |||
1622 | rv6xx_generate_transition_stepping(rdev); | ||
1623 | rv6xx_program_power_level_medium_for_transition(rdev); | ||
1624 | |||
1625 | if (pi->voltage_control) { | ||
1626 | rv6xx_set_sw_voltage_to_safe(rdev); | ||
1627 | if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC) | ||
1628 | rv6xx_set_sw_voltage_to_low(rdev); | ||
1629 | } | ||
1630 | |||
1631 | if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS) | ||
1632 | rv6xx_set_safe_backbias(rdev); | ||
1633 | |||
1634 | if (pi->dynamic_pcie_gen2) | ||
1635 | rv6xx_set_safe_pcie_gen2(rdev); | ||
1636 | |||
1637 | if (pi->voltage_control) | ||
1638 | rv6xx_enable_dynamic_voltage_control(rdev, false); | ||
1639 | |||
1640 | if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS) | ||
1641 | rv6xx_enable_dynamic_backbias_control(rdev, false); | ||
1642 | |||
1643 | if (pi->voltage_control) { | ||
1644 | if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC) | ||
1645 | rv6xx_step_voltage_if_increasing(rdev); | ||
1646 | msleep((rdev->pm.dpm.voltage_response_time + 999) / 1000); | ||
1647 | } | ||
1648 | |||
1649 | r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, true); | ||
1650 | r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, false); | ||
1651 | r600_wait_for_power_level_unequal(rdev, R600_POWER_LEVEL_LOW); | ||
1652 | |||
1653 | rv6xx_generate_low_step(rdev); | ||
1654 | rv6xx_invalidate_intermediate_steps(rdev); | ||
1655 | rv6xx_calculate_stepping_parameters(rdev); | ||
1656 | rv6xx_program_stepping_parameters_lowest_entry(rdev); | ||
1657 | rv6xx_program_power_level_low_to_lowest_state(rdev); | ||
1658 | |||
1659 | r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true); | ||
1660 | r600_wait_for_power_level(rdev, R600_POWER_LEVEL_LOW); | ||
1661 | r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, false); | ||
1662 | |||
1663 | if (pi->voltage_control) { | ||
1664 | if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC) | ||
1665 | rv6xx_step_voltage_if_decreasing(rdev); | ||
1666 | rv6xx_enable_dynamic_voltage_control(rdev, true); | ||
1667 | } | ||
1668 | |||
1669 | if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS) | ||
1670 | rv6xx_enable_dynamic_backbias_control(rdev, true); | ||
1671 | |||
1672 | if (pi->dynamic_pcie_gen2) | ||
1673 | rv6xx_enable_dynamic_pcie_gen2(rdev, true); | ||
1674 | |||
1675 | rv6xx_reset_lvtm_data_sync(rdev); | ||
1676 | |||
1677 | rv6xx_generate_stepping_table(rdev); | ||
1678 | rv6xx_program_stepping_parameters_except_lowest_entry(rdev); | ||
1679 | rv6xx_program_power_level_low(rdev); | ||
1680 | rv6xx_program_power_level_medium(rdev); | ||
1681 | rv6xx_program_power_level_high(rdev); | ||
1682 | rv6xx_enable_medium(rdev); | ||
1683 | rv6xx_enable_high(rdev); | ||
1684 | |||
1685 | if (pi->thermal_protection) | ||
1686 | rv6xx_enable_thermal_protection(rdev, true); | ||
1687 | rv6xx_program_vc(rdev); | ||
1688 | rv6xx_program_at(rdev); | ||
1689 | |||
1690 | return 0; | ||
1691 | } | ||
1692 | |||
1693 | void rv6xx_setup_asic(struct radeon_device *rdev) | ||
1694 | { | ||
1695 | r600_enable_acpi_pm(rdev); | ||
1696 | |||
1697 | if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L0s) | ||
1698 | rv6xx_enable_l0s(rdev); | ||
1699 | if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L1) | ||
1700 | rv6xx_enable_l1(rdev); | ||
1701 | if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1) | ||
1702 | rv6xx_enable_pll_sleep_in_l1(rdev); | ||
1703 | } | ||
1704 | |||
1705 | void rv6xx_dpm_display_configuration_changed(struct radeon_device *rdev) | ||
1706 | { | ||
1707 | rv6xx_program_display_gap(rdev); | ||
1708 | } | ||
1709 | |||
1710 | union power_info { | ||
1711 | struct _ATOM_POWERPLAY_INFO info; | ||
1712 | struct _ATOM_POWERPLAY_INFO_V2 info_2; | ||
1713 | struct _ATOM_POWERPLAY_INFO_V3 info_3; | ||
1714 | struct _ATOM_PPLIB_POWERPLAYTABLE pplib; | ||
1715 | struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2; | ||
1716 | struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3; | ||
1717 | }; | ||
1718 | |||
1719 | union pplib_clock_info { | ||
1720 | struct _ATOM_PPLIB_R600_CLOCK_INFO r600; | ||
1721 | struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780; | ||
1722 | struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen; | ||
1723 | struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo; | ||
1724 | }; | ||
1725 | |||
1726 | union pplib_power_state { | ||
1727 | struct _ATOM_PPLIB_STATE v1; | ||
1728 | struct _ATOM_PPLIB_STATE_V2 v2; | ||
1729 | }; | ||
1730 | |||
1731 | static void rv6xx_parse_pplib_non_clock_info(struct radeon_device *rdev, | ||
1732 | struct radeon_ps *rps, | ||
1733 | struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info) | ||
1734 | { | ||
1735 | rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings); | ||
1736 | rps->class = le16_to_cpu(non_clock_info->usClassification); | ||
1737 | rps->class2 = le16_to_cpu(non_clock_info->usClassification2); | ||
1738 | |||
1739 | if (r600_is_uvd_state(rps->class, rps->class2)) { | ||
1740 | rps->vclk = RV6XX_DEFAULT_VCLK_FREQ; | ||
1741 | rps->dclk = RV6XX_DEFAULT_DCLK_FREQ; | ||
1742 | } else { | ||
1743 | rps->vclk = 0; | ||
1744 | rps->dclk = 0; | ||
1745 | } | ||
1746 | |||
1747 | if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) | ||
1748 | rdev->pm.dpm.boot_ps = rps; | ||
1749 | if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE) | ||
1750 | rdev->pm.dpm.uvd_ps = rps; | ||
1751 | } | ||
1752 | |||
1753 | static void rv6xx_parse_pplib_clock_info(struct radeon_device *rdev, | ||
1754 | struct radeon_ps *rps, int index, | ||
1755 | union pplib_clock_info *clock_info) | ||
1756 | { | ||
1757 | struct rv6xx_ps *ps = rv6xx_get_ps(rps); | ||
1758 | u32 sclk, mclk; | ||
1759 | u16 vddc; | ||
1760 | struct rv6xx_pl *pl; | ||
1761 | |||
1762 | switch (index) { | ||
1763 | case 0: | ||
1764 | pl = &ps->low; | ||
1765 | break; | ||
1766 | case 1: | ||
1767 | pl = &ps->medium; | ||
1768 | break; | ||
1769 | case 2: | ||
1770 | default: | ||
1771 | pl = &ps->high; | ||
1772 | break; | ||
1773 | } | ||
1774 | |||
1775 | sclk = le16_to_cpu(clock_info->r600.usEngineClockLow); | ||
1776 | sclk |= clock_info->r600.ucEngineClockHigh << 16; | ||
1777 | mclk = le16_to_cpu(clock_info->r600.usMemoryClockLow); | ||
1778 | mclk |= clock_info->r600.ucMemoryClockHigh << 16; | ||
1779 | |||
1780 | pl->mclk = mclk; | ||
1781 | pl->sclk = sclk; | ||
1782 | pl->vddc = le16_to_cpu(clock_info->r600.usVDDC); | ||
1783 | pl->flags = le32_to_cpu(clock_info->r600.ulFlags); | ||
1784 | |||
1785 | /* patch up vddc if necessary */ | ||
1786 | if (pl->vddc == 0xff01) { | ||
1787 | if (radeon_atom_get_max_vddc(rdev, 0, 0, &vddc) == 0) | ||
1788 | pl->vddc = vddc; | ||
1789 | } | ||
1790 | |||
1791 | /* fix up pcie gen2 */ | ||
1792 | if (pl->flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) { | ||
1793 | if ((rdev->family == CHIP_RV610) || (rdev->family == CHIP_RV630)) { | ||
1794 | if (pl->vddc < 1100) | ||
1795 | pl->flags &= ~ATOM_PPLIB_R600_FLAGS_PCIEGEN2; | ||
1796 | } | ||
1797 | } | ||
1798 | |||
1799 | /* patch up boot state */ | ||
1800 | if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) { | ||
1801 | u16 vddc, vddci; | ||
1802 | radeon_atombios_get_default_voltages(rdev, &vddc, &vddci); | ||
1803 | pl->mclk = rdev->clock.default_mclk; | ||
1804 | pl->sclk = rdev->clock.default_sclk; | ||
1805 | pl->vddc = vddc; | ||
1806 | } | ||
1807 | } | ||
1808 | |||
1809 | static int rv6xx_parse_power_table(struct radeon_device *rdev) | ||
1810 | { | ||
1811 | struct radeon_mode_info *mode_info = &rdev->mode_info; | ||
1812 | struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info; | ||
1813 | union pplib_power_state *power_state; | ||
1814 | int i, j; | ||
1815 | union pplib_clock_info *clock_info; | ||
1816 | union power_info *power_info; | ||
1817 | int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); | ||
1818 | u16 data_offset; | ||
1819 | u8 frev, crev; | ||
1820 | struct rv6xx_ps *ps; | ||
1821 | |||
1822 | if (!atom_parse_data_header(mode_info->atom_context, index, NULL, | ||
1823 | &frev, &crev, &data_offset)) | ||
1824 | return -EINVAL; | ||
1825 | power_info = (union power_info *)(mode_info->atom_context->bios + data_offset); | ||
1826 | |||
1827 | rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) * | ||
1828 | power_info->pplib.ucNumStates, GFP_KERNEL); | ||
1829 | if (!rdev->pm.dpm.ps) | ||
1830 | return -ENOMEM; | ||
1831 | rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps); | ||
1832 | rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime); | ||
1833 | rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime); | ||
1834 | |||
1835 | for (i = 0; i < power_info->pplib.ucNumStates; i++) { | ||
1836 | power_state = (union pplib_power_state *) | ||
1837 | (mode_info->atom_context->bios + data_offset + | ||
1838 | le16_to_cpu(power_info->pplib.usStateArrayOffset) + | ||
1839 | i * power_info->pplib.ucStateEntrySize); | ||
1840 | non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) | ||
1841 | (mode_info->atom_context->bios + data_offset + | ||
1842 | le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) + | ||
1843 | (power_state->v1.ucNonClockStateIndex * | ||
1844 | power_info->pplib.ucNonClockSize)); | ||
1845 | if (power_info->pplib.ucStateEntrySize - 1) { | ||
1846 | ps = kzalloc(sizeof(struct rv6xx_ps), GFP_KERNEL); | ||
1847 | if (ps == NULL) { | ||
1848 | kfree(rdev->pm.dpm.ps); | ||
1849 | return -ENOMEM; | ||
1850 | } | ||
1851 | rdev->pm.dpm.ps[i].ps_priv = ps; | ||
1852 | rv6xx_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i], | ||
1853 | non_clock_info); | ||
1854 | for (j = 0; j < (power_info->pplib.ucStateEntrySize - 1); j++) { | ||
1855 | clock_info = (union pplib_clock_info *) | ||
1856 | (mode_info->atom_context->bios + data_offset + | ||
1857 | le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) + | ||
1858 | (power_state->v1.ucClockStateIndices[j] * | ||
1859 | power_info->pplib.ucClockInfoSize)); | ||
1860 | rv6xx_parse_pplib_clock_info(rdev, | ||
1861 | &rdev->pm.dpm.ps[i], j, | ||
1862 | clock_info); | ||
1863 | } | ||
1864 | } | ||
1865 | } | ||
1866 | rdev->pm.dpm.num_ps = power_info->pplib.ucNumStates; | ||
1867 | return 0; | ||
1868 | } | ||
1869 | |||
1870 | int rv6xx_dpm_init(struct radeon_device *rdev) | ||
1871 | { | ||
1872 | int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info); | ||
1873 | uint16_t data_offset, size; | ||
1874 | uint8_t frev, crev; | ||
1875 | struct atom_clock_dividers dividers; | ||
1876 | struct rv6xx_power_info *pi; | ||
1877 | int ret; | ||
1878 | |||
1879 | pi = kzalloc(sizeof(struct rv6xx_power_info), GFP_KERNEL); | ||
1880 | if (pi == NULL) | ||
1881 | return -ENOMEM; | ||
1882 | rdev->pm.dpm.priv = pi; | ||
1883 | |||
1884 | ret = rv6xx_parse_power_table(rdev); | ||
1885 | if (ret) | ||
1886 | return ret; | ||
1887 | |||
1888 | if (rdev->pm.dpm.voltage_response_time == 0) | ||
1889 | rdev->pm.dpm.voltage_response_time = R600_VOLTAGERESPONSETIME_DFLT; | ||
1890 | if (rdev->pm.dpm.backbias_response_time == 0) | ||
1891 | rdev->pm.dpm.backbias_response_time = R600_BACKBIASRESPONSETIME_DFLT; | ||
1892 | |||
1893 | ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, | ||
1894 | 0, false, ÷rs); | ||
1895 | if (ret) | ||
1896 | pi->spll_ref_div = dividers.ref_div + 1; | ||
1897 | else | ||
1898 | pi->spll_ref_div = R600_REFERENCEDIVIDER_DFLT; | ||
1899 | |||
1900 | ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_MEMORY_PLL_PARAM, | ||
1901 | 0, false, ÷rs); | ||
1902 | if (ret) | ||
1903 | pi->mpll_ref_div = dividers.ref_div + 1; | ||
1904 | else | ||
1905 | pi->mpll_ref_div = R600_REFERENCEDIVIDER_DFLT; | ||
1906 | |||
1907 | if (rdev->family >= CHIP_RV670) | ||
1908 | pi->fb_div_scale = 1; | ||
1909 | else | ||
1910 | pi->fb_div_scale = 0; | ||
1911 | |||
1912 | pi->voltage_control = | ||
1913 | radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC); | ||
1914 | |||
1915 | pi->gfx_clock_gating = true; | ||
1916 | |||
1917 | if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size, | ||
1918 | &frev, &crev, &data_offset)) { | ||
1919 | pi->sclk_ss = true; | ||
1920 | pi->mclk_ss = true; | ||
1921 | pi->dynamic_ss = true; | ||
1922 | } else { | ||
1923 | pi->sclk_ss = false; | ||
1924 | pi->mclk_ss = false; | ||
1925 | pi->dynamic_ss = false; | ||
1926 | } | ||
1927 | |||
1928 | pi->dynamic_pcie_gen2 = true; | ||
1929 | |||
1930 | if (pi->gfx_clock_gating && | ||
1931 | (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE)) | ||
1932 | pi->thermal_protection = true; | ||
1933 | else | ||
1934 | pi->thermal_protection = false; | ||
1935 | |||
1936 | pi->display_gap = true; | ||
1937 | |||
1938 | return 0; | ||
1939 | } | ||
1940 | |||
1941 | void rv6xx_dpm_print_power_state(struct radeon_device *rdev, | ||
1942 | struct radeon_ps *rps) | ||
1943 | { | ||
1944 | struct rv6xx_ps *ps = rv6xx_get_ps(rps); | ||
1945 | struct rv6xx_pl *pl; | ||
1946 | |||
1947 | r600_dpm_print_class_info(rps->class, rps->class2); | ||
1948 | r600_dpm_print_cap_info(rps->caps); | ||
1949 | printk("\tuvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk); | ||
1950 | pl = &ps->low; | ||
1951 | printk("\t\tpower level 0 sclk: %u mclk: %u vddc: %u\n", | ||
1952 | pl->sclk, pl->mclk, pl->vddc); | ||
1953 | pl = &ps->medium; | ||
1954 | printk("\t\tpower level 1 sclk: %u mclk: %u vddc: %u\n", | ||
1955 | pl->sclk, pl->mclk, pl->vddc); | ||
1956 | pl = &ps->high; | ||
1957 | printk("\t\tpower level 2 sclk: %u mclk: %u vddc: %u\n", | ||
1958 | pl->sclk, pl->mclk, pl->vddc); | ||
1959 | r600_dpm_print_ps_status(rdev, rps); | ||
1960 | } | ||
1961 | |||
1962 | void rv6xx_dpm_fini(struct radeon_device *rdev) | ||
1963 | { | ||
1964 | int i; | ||
1965 | |||
1966 | for (i = 0; i < rdev->pm.dpm.num_ps; i++) { | ||
1967 | kfree(rdev->pm.dpm.ps[i].ps_priv); | ||
1968 | } | ||
1969 | kfree(rdev->pm.dpm.ps); | ||
1970 | kfree(rdev->pm.dpm.priv); | ||
1971 | } | ||
1972 | |||
1973 | u32 rv6xx_dpm_get_sclk(struct radeon_device *rdev, bool low) | ||
1974 | { | ||
1975 | struct rv6xx_ps *requested_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps); | ||
1976 | |||
1977 | if (low) | ||
1978 | return requested_state->low.sclk; | ||
1979 | else | ||
1980 | return requested_state->high.sclk; | ||
1981 | } | ||
1982 | |||
1983 | u32 rv6xx_dpm_get_mclk(struct radeon_device *rdev, bool low) | ||
1984 | { | ||
1985 | struct rv6xx_ps *requested_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps); | ||
1986 | |||
1987 | if (low) | ||
1988 | return requested_state->low.mclk; | ||
1989 | else | ||
1990 | return requested_state->high.mclk; | ||
1991 | } | ||
diff --git a/drivers/gpu/drm/radeon/rv6xx_dpm.h b/drivers/gpu/drm/radeon/rv6xx_dpm.h new file mode 100644 index 000000000000..8035d53ebea6 --- /dev/null +++ b/drivers/gpu/drm/radeon/rv6xx_dpm.h | |||
@@ -0,0 +1,95 @@ | |||
1 | /* | ||
2 | * Copyright 2011 Advanced Micro Devices, Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | * Authors: Alex Deucher | ||
23 | */ | ||
24 | |||
25 | #ifndef __RV6XX_DPM_H__ | ||
26 | #define __RV6XX_DPM_H__ | ||
27 | |||
28 | #include "r600_dpm.h" | ||
29 | |||
30 | /* Represents a single SCLK step. */ | ||
31 | struct rv6xx_sclk_stepping | ||
32 | { | ||
33 | u32 vco_frequency; | ||
34 | u32 post_divider; | ||
35 | }; | ||
36 | |||
37 | struct rv6xx_pm_hw_state { | ||
38 | u32 sclks[R600_PM_NUMBER_OF_ACTIVITY_LEVELS]; | ||
39 | u32 mclks[R600_PM_NUMBER_OF_MCLKS]; | ||
40 | u16 vddc[R600_PM_NUMBER_OF_VOLTAGE_LEVELS]; | ||
41 | bool backbias[R600_PM_NUMBER_OF_VOLTAGE_LEVELS]; | ||
42 | bool pcie_gen2[R600_PM_NUMBER_OF_ACTIVITY_LEVELS]; | ||
43 | u8 high_sclk_index; | ||
44 | u8 medium_sclk_index; | ||
45 | u8 low_sclk_index; | ||
46 | u8 high_mclk_index; | ||
47 | u8 medium_mclk_index; | ||
48 | u8 low_mclk_index; | ||
49 | u8 high_vddc_index; | ||
50 | u8 medium_vddc_index; | ||
51 | u8 low_vddc_index; | ||
52 | u8 rp[R600_PM_NUMBER_OF_ACTIVITY_LEVELS]; | ||
53 | u8 lp[R600_PM_NUMBER_OF_ACTIVITY_LEVELS]; | ||
54 | }; | ||
55 | |||
56 | struct rv6xx_power_info { | ||
57 | /* flags */ | ||
58 | bool voltage_control; | ||
59 | bool sclk_ss; | ||
60 | bool mclk_ss; | ||
61 | bool dynamic_ss; | ||
62 | bool dynamic_pcie_gen2; | ||
63 | bool thermal_protection; | ||
64 | bool display_gap; | ||
65 | bool gfx_clock_gating; | ||
66 | /* clk values */ | ||
67 | u32 fb_div_scale; | ||
68 | u32 spll_ref_div; | ||
69 | u32 mpll_ref_div; | ||
70 | u32 bsu; | ||
71 | u32 bsp; | ||
72 | /* */ | ||
73 | u32 active_auto_throttle_sources; | ||
74 | /* current power state */ | ||
75 | u32 restricted_levels; | ||
76 | struct rv6xx_pm_hw_state hw; | ||
77 | }; | ||
78 | |||
79 | struct rv6xx_pl { | ||
80 | u32 sclk; | ||
81 | u32 mclk; | ||
82 | u16 vddc; | ||
83 | u32 flags; | ||
84 | }; | ||
85 | |||
86 | struct rv6xx_ps { | ||
87 | struct rv6xx_pl high; | ||
88 | struct rv6xx_pl medium; | ||
89 | struct rv6xx_pl low; | ||
90 | }; | ||
91 | |||
92 | #define RV6XX_DEFAULT_VCLK_FREQ 40000 /* 10 khz */ | ||
93 | #define RV6XX_DEFAULT_DCLK_FREQ 30000 /* 10 khz */ | ||
94 | |||
95 | #endif | ||
diff --git a/drivers/gpu/drm/radeon/rv6xxd.h b/drivers/gpu/drm/radeon/rv6xxd.h new file mode 100644 index 000000000000..34e86f90b431 --- /dev/null +++ b/drivers/gpu/drm/radeon/rv6xxd.h | |||
@@ -0,0 +1,246 @@ | |||
1 | /* | ||
2 | * Copyright 2011 Advanced Micro Devices, Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | */ | ||
23 | #ifndef RV6XXD_H | ||
24 | #define RV6XXD_H | ||
25 | |||
26 | /* RV6xx power management */ | ||
27 | #define SPLL_CNTL_MODE 0x60c | ||
28 | # define SPLL_DIV_SYNC (1 << 5) | ||
29 | |||
30 | #define GENERAL_PWRMGT 0x618 | ||
31 | # define GLOBAL_PWRMGT_EN (1 << 0) | ||
32 | # define STATIC_PM_EN (1 << 1) | ||
33 | # define MOBILE_SU (1 << 2) | ||
34 | # define THERMAL_PROTECTION_DIS (1 << 3) | ||
35 | # define THERMAL_PROTECTION_TYPE (1 << 4) | ||
36 | # define ENABLE_GEN2PCIE (1 << 5) | ||
37 | # define SW_GPIO_INDEX(x) ((x) << 6) | ||
38 | # define SW_GPIO_INDEX_MASK (3 << 6) | ||
39 | # define LOW_VOLT_D2_ACPI (1 << 8) | ||
40 | # define LOW_VOLT_D3_ACPI (1 << 9) | ||
41 | # define VOLT_PWRMGT_EN (1 << 10) | ||
42 | # define BACKBIAS_PAD_EN (1 << 16) | ||
43 | # define BACKBIAS_VALUE (1 << 17) | ||
44 | # define BACKBIAS_DPM_CNTL (1 << 18) | ||
45 | # define DYN_SPREAD_SPECTRUM_EN (1 << 21) | ||
46 | |||
47 | #define MCLK_PWRMGT_CNTL 0x624 | ||
48 | # define MPLL_PWRMGT_OFF (1 << 0) | ||
49 | # define YCLK_TURNOFF (1 << 1) | ||
50 | # define MPLL_TURNOFF (1 << 2) | ||
51 | # define SU_MCLK_USE_BCLK (1 << 3) | ||
52 | # define DLL_READY (1 << 4) | ||
53 | # define MC_BUSY (1 << 5) | ||
54 | # define MC_INT_CNTL (1 << 7) | ||
55 | # define MRDCKA_SLEEP (1 << 8) | ||
56 | # define MRDCKB_SLEEP (1 << 9) | ||
57 | # define MRDCKC_SLEEP (1 << 10) | ||
58 | # define MRDCKD_SLEEP (1 << 11) | ||
59 | # define MRDCKE_SLEEP (1 << 12) | ||
60 | # define MRDCKF_SLEEP (1 << 13) | ||
61 | # define MRDCKG_SLEEP (1 << 14) | ||
62 | # define MRDCKH_SLEEP (1 << 15) | ||
63 | # define MRDCKA_RESET (1 << 16) | ||
64 | # define MRDCKB_RESET (1 << 17) | ||
65 | # define MRDCKC_RESET (1 << 18) | ||
66 | # define MRDCKD_RESET (1 << 19) | ||
67 | # define MRDCKE_RESET (1 << 20) | ||
68 | # define MRDCKF_RESET (1 << 21) | ||
69 | # define MRDCKG_RESET (1 << 22) | ||
70 | # define MRDCKH_RESET (1 << 23) | ||
71 | # define DLL_READY_READ (1 << 24) | ||
72 | # define USE_DISPLAY_GAP (1 << 25) | ||
73 | # define USE_DISPLAY_URGENT_NORMAL (1 << 26) | ||
74 | # define USE_DISPLAY_GAP_CTXSW (1 << 27) | ||
75 | # define MPLL_TURNOFF_D2 (1 << 28) | ||
76 | # define USE_DISPLAY_URGENT_CTXSW (1 << 29) | ||
77 | |||
78 | #define MPLL_FREQ_LEVEL_0 0x6e8 | ||
79 | # define LEVEL0_MPLL_POST_DIV(x) ((x) << 0) | ||
80 | # define LEVEL0_MPLL_POST_DIV_MASK (0xff << 0) | ||
81 | # define LEVEL0_MPLL_FB_DIV(x) ((x) << 8) | ||
82 | # define LEVEL0_MPLL_FB_DIV_MASK (0xfff << 8) | ||
83 | # define LEVEL0_MPLL_REF_DIV(x) ((x) << 20) | ||
84 | # define LEVEL0_MPLL_REF_DIV_MASK (0x3f << 20) | ||
85 | # define LEVEL0_MPLL_DIV_EN (1 << 28) | ||
86 | # define LEVEL0_DLL_BYPASS (1 << 29) | ||
87 | # define LEVEL0_DLL_RESET (1 << 30) | ||
88 | |||
89 | #define VID_RT 0x6f8 | ||
90 | # define VID_CRT(x) ((x) << 0) | ||
91 | # define VID_CRT_MASK (0x1fff << 0) | ||
92 | # define VID_CRTU(x) ((x) << 13) | ||
93 | # define VID_CRTU_MASK (7 << 13) | ||
94 | # define SSTU(x) ((x) << 16) | ||
95 | # define SSTU_MASK (7 << 16) | ||
96 | # define VID_SWT(x) ((x) << 19) | ||
97 | # define VID_SWT_MASK (0x1f << 19) | ||
98 | # define BRT(x) ((x) << 24) | ||
99 | # define BRT_MASK (0xff << 24) | ||
100 | |||
101 | #define TARGET_AND_CURRENT_PROFILE_INDEX 0x70c | ||
102 | # define TARGET_PROFILE_INDEX_MASK (3 << 0) | ||
103 | # define TARGET_PROFILE_INDEX_SHIFT 0 | ||
104 | # define CURRENT_PROFILE_INDEX_MASK (3 << 2) | ||
105 | # define CURRENT_PROFILE_INDEX_SHIFT 2 | ||
106 | # define DYN_PWR_ENTER_INDEX(x) ((x) << 4) | ||
107 | # define DYN_PWR_ENTER_INDEX_MASK (3 << 4) | ||
108 | # define DYN_PWR_ENTER_INDEX_SHIFT 4 | ||
109 | # define CURR_MCLK_INDEX_MASK (3 << 6) | ||
110 | # define CURR_MCLK_INDEX_SHIFT 6 | ||
111 | # define CURR_SCLK_INDEX_MASK (0x1f << 8) | ||
112 | # define CURR_SCLK_INDEX_SHIFT 8 | ||
113 | # define CURR_VID_INDEX_MASK (3 << 13) | ||
114 | # define CURR_VID_INDEX_SHIFT 13 | ||
115 | |||
116 | #define VID_UPPER_GPIO_CNTL 0x740 | ||
117 | # define CTXSW_UPPER_GPIO_VALUES(x) ((x) << 0) | ||
118 | # define CTXSW_UPPER_GPIO_VALUES_MASK (7 << 0) | ||
119 | # define HIGH_UPPER_GPIO_VALUES(x) ((x) << 3) | ||
120 | # define HIGH_UPPER_GPIO_VALUES_MASK (7 << 3) | ||
121 | # define MEDIUM_UPPER_GPIO_VALUES(x) ((x) << 6) | ||
122 | # define MEDIUM_UPPER_GPIO_VALUES_MASK (7 << 6) | ||
123 | # define LOW_UPPER_GPIO_VALUES(x) ((x) << 9) | ||
124 | # define LOW_UPPER_GPIO_VALUES_MASK (7 << 9) | ||
125 | # define CTXSW_BACKBIAS_VALUE (1 << 12) | ||
126 | # define HIGH_BACKBIAS_VALUE (1 << 13) | ||
127 | # define MEDIUM_BACKBIAS_VALUE (1 << 14) | ||
128 | # define LOW_BACKBIAS_VALUE (1 << 15) | ||
129 | |||
130 | #define CG_DISPLAY_GAP_CNTL 0x7dc | ||
131 | # define DISP1_GAP(x) ((x) << 0) | ||
132 | # define DISP1_GAP_MASK (3 << 0) | ||
133 | # define DISP2_GAP(x) ((x) << 2) | ||
134 | # define DISP2_GAP_MASK (3 << 2) | ||
135 | # define VBI_TIMER_COUNT(x) ((x) << 4) | ||
136 | # define VBI_TIMER_COUNT_MASK (0x3fff << 4) | ||
137 | # define VBI_TIMER_UNIT(x) ((x) << 20) | ||
138 | # define VBI_TIMER_UNIT_MASK (7 << 20) | ||
139 | # define DISP1_GAP_MCHG(x) ((x) << 24) | ||
140 | # define DISP1_GAP_MCHG_MASK (3 << 24) | ||
141 | # define DISP2_GAP_MCHG(x) ((x) << 26) | ||
142 | # define DISP2_GAP_MCHG_MASK (3 << 26) | ||
143 | |||
144 | #define CG_THERMAL_CTRL 0x7f0 | ||
145 | # define DPM_EVENT_SRC(x) ((x) << 0) | ||
146 | # define DPM_EVENT_SRC_MASK (7 << 0) | ||
147 | # define THERM_INC_CLK (1 << 3) | ||
148 | # define TOFFSET(x) ((x) << 4) | ||
149 | # define TOFFSET_MASK (0xff << 4) | ||
150 | # define DIG_THERM_DPM(x) ((x) << 12) | ||
151 | # define DIG_THERM_DPM_MASK (0xff << 12) | ||
152 | # define CTF_SEL(x) ((x) << 20) | ||
153 | # define CTF_SEL_MASK (7 << 20) | ||
154 | # define CTF_PAD_POLARITY (1 << 23) | ||
155 | # define CTF_PAD_EN (1 << 24) | ||
156 | |||
157 | #define CG_SPLL_SPREAD_SPECTRUM_LOW 0x820 | ||
158 | # define SSEN (1 << 0) | ||
159 | # define CLKS(x) ((x) << 3) | ||
160 | # define CLKS_MASK (0xff << 3) | ||
161 | # define CLKS_SHIFT 3 | ||
162 | # define CLKV(x) ((x) << 11) | ||
163 | # define CLKV_MASK (0x7ff << 11) | ||
164 | # define CLKV_SHIFT 11 | ||
165 | #define CG_MPLL_SPREAD_SPECTRUM 0x830 | ||
166 | |||
167 | #define CITF_CNTL 0x200c | ||
168 | # define BLACKOUT_RD (1 << 0) | ||
169 | # define BLACKOUT_WR (1 << 1) | ||
170 | |||
171 | #define RAMCFG 0x2408 | ||
172 | #define NOOFBANK_SHIFT 0 | ||
173 | #define NOOFBANK_MASK 0x00000001 | ||
174 | #define NOOFRANK_SHIFT 1 | ||
175 | #define NOOFRANK_MASK 0x00000002 | ||
176 | #define NOOFROWS_SHIFT 2 | ||
177 | #define NOOFROWS_MASK 0x0000001C | ||
178 | #define NOOFCOLS_SHIFT 5 | ||
179 | #define NOOFCOLS_MASK 0x00000060 | ||
180 | #define CHANSIZE_SHIFT 7 | ||
181 | #define CHANSIZE_MASK 0x00000080 | ||
182 | #define BURSTLENGTH_SHIFT 8 | ||
183 | #define BURSTLENGTH_MASK 0x00000100 | ||
184 | #define CHANSIZE_OVERRIDE (1 << 10) | ||
185 | |||
186 | #define SQM_RATIO 0x2424 | ||
187 | # define STATE0(x) ((x) << 0) | ||
188 | # define STATE0_MASK (0xff << 0) | ||
189 | # define STATE1(x) ((x) << 8) | ||
190 | # define STATE1_MASK (0xff << 8) | ||
191 | # define STATE2(x) ((x) << 16) | ||
192 | # define STATE2_MASK (0xff << 16) | ||
193 | # define STATE3(x) ((x) << 24) | ||
194 | # define STATE3_MASK (0xff << 24) | ||
195 | |||
196 | #define ARB_RFSH_CNTL 0x2460 | ||
197 | # define ENABLE (1 << 0) | ||
198 | #define ARB_RFSH_RATE 0x2464 | ||
199 | # define POWERMODE0(x) ((x) << 0) | ||
200 | # define POWERMODE0_MASK (0xff << 0) | ||
201 | # define POWERMODE1(x) ((x) << 8) | ||
202 | # define POWERMODE1_MASK (0xff << 8) | ||
203 | # define POWERMODE2(x) ((x) << 16) | ||
204 | # define POWERMODE2_MASK (0xff << 16) | ||
205 | # define POWERMODE3(x) ((x) << 24) | ||
206 | # define POWERMODE3_MASK (0xff << 24) | ||
207 | |||
208 | #define MC_SEQ_DRAM 0x2608 | ||
209 | # define CKE_DYN (1 << 12) | ||
210 | |||
211 | #define MC_SEQ_CMD 0x26c4 | ||
212 | |||
213 | #define MC_SEQ_RESERVE_S 0x2890 | ||
214 | #define MC_SEQ_RESERVE_M 0x2894 | ||
215 | |||
216 | #define LVTMA_DATA_SYNCHRONIZATION 0x7adc | ||
217 | # define LVTMA_PFREQCHG (1 << 8) | ||
218 | #define DCE3_LVTMA_DATA_SYNCHRONIZATION 0x7f98 | ||
219 | |||
220 | /* PCIE indirect regs */ | ||
221 | #define PCIE_P_CNTL 0x40 | ||
222 | # define P_PLL_PWRDN_IN_L1L23 (1 << 3) | ||
223 | # define P_PLL_BUF_PDNB (1 << 4) | ||
224 | # define P_PLL_PDNB (1 << 9) | ||
225 | # define P_ALLOW_PRX_FRONTEND_SHUTOFF (1 << 12) | ||
226 | /* PCIE PORT indirect regs */ | ||
227 | #define PCIE_LC_CNTL 0xa0 | ||
228 | # define LC_L0S_INACTIVITY(x) ((x) << 8) | ||
229 | # define LC_L0S_INACTIVITY_MASK (0xf << 8) | ||
230 | # define LC_L0S_INACTIVITY_SHIFT 8 | ||
231 | # define LC_L1_INACTIVITY(x) ((x) << 12) | ||
232 | # define LC_L1_INACTIVITY_MASK (0xf << 12) | ||
233 | # define LC_L1_INACTIVITY_SHIFT 12 | ||
234 | # define LC_PMI_TO_L1_DIS (1 << 16) | ||
235 | # define LC_ASPM_TO_L1_DIS (1 << 24) | ||
236 | #define PCIE_LC_SPEED_CNTL 0xa4 | ||
237 | # define LC_GEN2_EN (1 << 0) | ||
238 | # define LC_INITIATE_LINK_SPEED_CHANGE (1 << 7) | ||
239 | # define LC_CURRENT_DATA_RATE (1 << 11) | ||
240 | # define LC_HW_VOLTAGE_IF_CONTROL(x) ((x) << 12) | ||
241 | # define LC_HW_VOLTAGE_IF_CONTROL_MASK (3 << 12) | ||
242 | # define LC_HW_VOLTAGE_IF_CONTROL_SHIFT 12 | ||
243 | # define LC_OTHER_SIDE_EVER_SENT_GEN2 (1 << 23) | ||
244 | # define LC_OTHER_SIDE_SUPPORTS_GEN2 (1 << 24) | ||
245 | |||
246 | #endif | ||