rv740_dpm.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  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. #include "radeon.h"
  25. #include "rv740d.h"
  26. #include "r600_dpm.h"
  27. #include "rv770.h"
  28. #include "rv770_dpm.h"
  29. #include "atom.h"
  30. u32 rv740_get_decoded_reference_divider(u32 encoded_ref)
  31. {
  32. u32 ref = 0;
  33. switch (encoded_ref) {
  34. case 0:
  35. ref = 1;
  36. break;
  37. case 16:
  38. ref = 2;
  39. break;
  40. case 17:
  41. ref = 3;
  42. break;
  43. case 18:
  44. ref = 2;
  45. break;
  46. case 19:
  47. ref = 3;
  48. break;
  49. case 20:
  50. ref = 4;
  51. break;
  52. case 21:
  53. ref = 5;
  54. break;
  55. default:
  56. DRM_ERROR("Invalid encoded Reference Divider\n");
  57. ref = 0;
  58. break;
  59. }
  60. return ref;
  61. }
  62. struct dll_speed_setting {
  63. u16 min;
  64. u16 max;
  65. u32 dll_speed;
  66. };
  67. static struct dll_speed_setting dll_speed_table[16] =
  68. {
  69. { 270, 320, 0x0f },
  70. { 240, 270, 0x0e },
  71. { 200, 240, 0x0d },
  72. { 180, 200, 0x0c },
  73. { 160, 180, 0x0b },
  74. { 140, 160, 0x0a },
  75. { 120, 140, 0x09 },
  76. { 110, 120, 0x08 },
  77. { 95, 110, 0x07 },
  78. { 85, 95, 0x06 },
  79. { 78, 85, 0x05 },
  80. { 70, 78, 0x04 },
  81. { 65, 70, 0x03 },
  82. { 60, 65, 0x02 },
  83. { 42, 60, 0x01 },
  84. { 00, 42, 0x00 }
  85. };
  86. u32 rv740_get_dll_speed(bool is_gddr5, u32 memory_clock)
  87. {
  88. int i;
  89. u32 factor;
  90. u16 data_rate;
  91. if (is_gddr5)
  92. factor = 4;
  93. else
  94. factor = 2;
  95. data_rate = (u16)(memory_clock * factor / 1000);
  96. if (data_rate < dll_speed_table[0].max) {
  97. for (i = 0; i < 16; i++) {
  98. if (data_rate > dll_speed_table[i].min &&
  99. data_rate <= dll_speed_table[i].max)
  100. return dll_speed_table[i].dll_speed;
  101. }
  102. }
  103. DRM_DEBUG_KMS("Target MCLK greater than largest MCLK in DLL speed table\n");
  104. return 0x0f;
  105. }
  106. int rv740_populate_sclk_value(struct radeon_device *rdev, u32 engine_clock,
  107. RV770_SMC_SCLK_VALUE *sclk)
  108. {
  109. struct rv7xx_power_info *pi = rv770_get_pi(rdev);
  110. struct atom_clock_dividers dividers;
  111. u32 spll_func_cntl = pi->clk_regs.rv770.cg_spll_func_cntl;
  112. u32 spll_func_cntl_2 = pi->clk_regs.rv770.cg_spll_func_cntl_2;
  113. u32 spll_func_cntl_3 = pi->clk_regs.rv770.cg_spll_func_cntl_3;
  114. u32 cg_spll_spread_spectrum = pi->clk_regs.rv770.cg_spll_spread_spectrum;
  115. u32 cg_spll_spread_spectrum_2 = pi->clk_regs.rv770.cg_spll_spread_spectrum_2;
  116. u64 tmp;
  117. u32 reference_clock = rdev->clock.spll.reference_freq;
  118. u32 reference_divider;
  119. u32 fbdiv;
  120. int ret;
  121. ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
  122. engine_clock, false, &dividers);
  123. if (ret)
  124. return ret;
  125. reference_divider = 1 + dividers.ref_div;
  126. tmp = (u64) engine_clock * reference_divider * dividers.post_div * 16384;
  127. do_div(tmp, reference_clock);
  128. fbdiv = (u32) tmp;
  129. spll_func_cntl &= ~(SPLL_PDIV_A_MASK | SPLL_REF_DIV_MASK);
  130. spll_func_cntl |= SPLL_REF_DIV(dividers.ref_div);
  131. spll_func_cntl |= SPLL_PDIV_A(dividers.post_div);
  132. spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK;
  133. spll_func_cntl_2 |= SCLK_MUX_SEL(2);
  134. spll_func_cntl_3 &= ~SPLL_FB_DIV_MASK;
  135. spll_func_cntl_3 |= SPLL_FB_DIV(fbdiv);
  136. spll_func_cntl_3 |= SPLL_DITHEN;
  137. if (pi->sclk_ss) {
  138. struct radeon_atom_ss ss;
  139. u32 vco_freq = engine_clock * dividers.post_div;
  140. if (radeon_atombios_get_asic_ss_info(rdev, &ss,
  141. ASIC_INTERNAL_ENGINE_SS, vco_freq)) {
  142. u32 clk_s = reference_clock * 5 / (reference_divider * ss.rate);
  143. u32 clk_v = 4 * ss.percentage * fbdiv / (clk_s * 10000);
  144. cg_spll_spread_spectrum &= ~CLK_S_MASK;
  145. cg_spll_spread_spectrum |= CLK_S(clk_s);
  146. cg_spll_spread_spectrum |= SSEN;
  147. cg_spll_spread_spectrum_2 &= ~CLK_V_MASK;
  148. cg_spll_spread_spectrum_2 |= CLK_V(clk_v);
  149. }
  150. }
  151. sclk->sclk_value = cpu_to_be32(engine_clock);
  152. sclk->vCG_SPLL_FUNC_CNTL = cpu_to_be32(spll_func_cntl);
  153. sclk->vCG_SPLL_FUNC_CNTL_2 = cpu_to_be32(spll_func_cntl_2);
  154. sclk->vCG_SPLL_FUNC_CNTL_3 = cpu_to_be32(spll_func_cntl_3);
  155. sclk->vCG_SPLL_SPREAD_SPECTRUM = cpu_to_be32(cg_spll_spread_spectrum);
  156. sclk->vCG_SPLL_SPREAD_SPECTRUM_2 = cpu_to_be32(cg_spll_spread_spectrum_2);
  157. return 0;
  158. }
  159. int rv740_populate_mclk_value(struct radeon_device *rdev,
  160. u32 engine_clock, u32 memory_clock,
  161. RV7XX_SMC_MCLK_VALUE *mclk)
  162. {
  163. struct rv7xx_power_info *pi = rv770_get_pi(rdev);
  164. u32 mpll_ad_func_cntl = pi->clk_regs.rv770.mpll_ad_func_cntl;
  165. u32 mpll_ad_func_cntl_2 = pi->clk_regs.rv770.mpll_ad_func_cntl_2;
  166. u32 mpll_dq_func_cntl = pi->clk_regs.rv770.mpll_dq_func_cntl;
  167. u32 mpll_dq_func_cntl_2 = pi->clk_regs.rv770.mpll_dq_func_cntl_2;
  168. u32 mclk_pwrmgt_cntl = pi->clk_regs.rv770.mclk_pwrmgt_cntl;
  169. u32 dll_cntl = pi->clk_regs.rv770.dll_cntl;
  170. u32 mpll_ss1 = pi->clk_regs.rv770.mpll_ss1;
  171. u32 mpll_ss2 = pi->clk_regs.rv770.mpll_ss2;
  172. struct atom_clock_dividers dividers;
  173. u32 ibias;
  174. u32 dll_speed;
  175. int ret;
  176. ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_MEMORY_PLL_PARAM,
  177. memory_clock, false, &dividers);
  178. if (ret)
  179. return ret;
  180. ibias = rv770_map_clkf_to_ibias(rdev, dividers.whole_fb_div);
  181. mpll_ad_func_cntl &= ~(CLKR_MASK |
  182. YCLK_POST_DIV_MASK |
  183. CLKF_MASK |
  184. CLKFRAC_MASK |
  185. IBIAS_MASK);
  186. mpll_ad_func_cntl |= CLKR(dividers.ref_div);
  187. mpll_ad_func_cntl |= YCLK_POST_DIV(dividers.post_div);
  188. mpll_ad_func_cntl |= CLKF(dividers.whole_fb_div);
  189. mpll_ad_func_cntl |= CLKFRAC(dividers.frac_fb_div);
  190. mpll_ad_func_cntl |= IBIAS(ibias);
  191. if (dividers.vco_mode)
  192. mpll_ad_func_cntl_2 |= VCO_MODE;
  193. else
  194. mpll_ad_func_cntl_2 &= ~VCO_MODE;
  195. if (pi->mem_gddr5) {
  196. mpll_dq_func_cntl &= ~(CLKR_MASK |
  197. YCLK_POST_DIV_MASK |
  198. CLKF_MASK |
  199. CLKFRAC_MASK |
  200. IBIAS_MASK);
  201. mpll_dq_func_cntl |= CLKR(dividers.ref_div);
  202. mpll_dq_func_cntl |= YCLK_POST_DIV(dividers.post_div);
  203. mpll_dq_func_cntl |= CLKF(dividers.whole_fb_div);
  204. mpll_dq_func_cntl |= CLKFRAC(dividers.frac_fb_div);
  205. mpll_dq_func_cntl |= IBIAS(ibias);
  206. if (dividers.vco_mode)
  207. mpll_dq_func_cntl_2 |= VCO_MODE;
  208. else
  209. mpll_dq_func_cntl_2 &= ~VCO_MODE;
  210. }
  211. if (pi->mclk_ss) {
  212. struct radeon_atom_ss ss;
  213. u32 vco_freq = memory_clock * dividers.post_div;
  214. if (radeon_atombios_get_asic_ss_info(rdev, &ss,
  215. ASIC_INTERNAL_MEMORY_SS, vco_freq)) {
  216. u32 reference_clock = rdev->clock.mpll.reference_freq;
  217. u32 decoded_ref = rv740_get_decoded_reference_divider(dividers.ref_div);
  218. u32 clk_s, clk_v;
  219. if (!decoded_ref)
  220. return -EINVAL;
  221. clk_s = reference_clock * 5 / (decoded_ref * ss.rate);
  222. clk_v = 0x40000 * ss.percentage *
  223. (dividers.whole_fb_div + (dividers.frac_fb_div / 8)) / (clk_s * 10000);
  224. mpll_ss1 &= ~CLKV_MASK;
  225. mpll_ss1 |= CLKV(clk_v);
  226. mpll_ss2 &= ~CLKS_MASK;
  227. mpll_ss2 |= CLKS(clk_s);
  228. }
  229. }
  230. dll_speed = rv740_get_dll_speed(pi->mem_gddr5,
  231. memory_clock);
  232. mclk_pwrmgt_cntl &= ~DLL_SPEED_MASK;
  233. mclk_pwrmgt_cntl |= DLL_SPEED(dll_speed);
  234. mclk->mclk770.mclk_value = cpu_to_be32(memory_clock);
  235. mclk->mclk770.vMPLL_AD_FUNC_CNTL = cpu_to_be32(mpll_ad_func_cntl);
  236. mclk->mclk770.vMPLL_AD_FUNC_CNTL_2 = cpu_to_be32(mpll_ad_func_cntl_2);
  237. mclk->mclk770.vMPLL_DQ_FUNC_CNTL = cpu_to_be32(mpll_dq_func_cntl);
  238. mclk->mclk770.vMPLL_DQ_FUNC_CNTL_2 = cpu_to_be32(mpll_dq_func_cntl_2);
  239. mclk->mclk770.vMCLK_PWRMGT_CNTL = cpu_to_be32(mclk_pwrmgt_cntl);
  240. mclk->mclk770.vDLL_CNTL = cpu_to_be32(dll_cntl);
  241. mclk->mclk770.vMPLL_SS = cpu_to_be32(mpll_ss1);
  242. mclk->mclk770.vMPLL_SS2 = cpu_to_be32(mpll_ss2);
  243. return 0;
  244. }
  245. void rv740_read_clock_registers(struct radeon_device *rdev)
  246. {
  247. struct rv7xx_power_info *pi = rv770_get_pi(rdev);
  248. pi->clk_regs.rv770.cg_spll_func_cntl =
  249. RREG32(CG_SPLL_FUNC_CNTL);
  250. pi->clk_regs.rv770.cg_spll_func_cntl_2 =
  251. RREG32(CG_SPLL_FUNC_CNTL_2);
  252. pi->clk_regs.rv770.cg_spll_func_cntl_3 =
  253. RREG32(CG_SPLL_FUNC_CNTL_3);
  254. pi->clk_regs.rv770.cg_spll_spread_spectrum =
  255. RREG32(CG_SPLL_SPREAD_SPECTRUM);
  256. pi->clk_regs.rv770.cg_spll_spread_spectrum_2 =
  257. RREG32(CG_SPLL_SPREAD_SPECTRUM_2);
  258. pi->clk_regs.rv770.mpll_ad_func_cntl =
  259. RREG32(MPLL_AD_FUNC_CNTL);
  260. pi->clk_regs.rv770.mpll_ad_func_cntl_2 =
  261. RREG32(MPLL_AD_FUNC_CNTL_2);
  262. pi->clk_regs.rv770.mpll_dq_func_cntl =
  263. RREG32(MPLL_DQ_FUNC_CNTL);
  264. pi->clk_regs.rv770.mpll_dq_func_cntl_2 =
  265. RREG32(MPLL_DQ_FUNC_CNTL_2);
  266. pi->clk_regs.rv770.mclk_pwrmgt_cntl =
  267. RREG32(MCLK_PWRMGT_CNTL);
  268. pi->clk_regs.rv770.dll_cntl = RREG32(DLL_CNTL);
  269. pi->clk_regs.rv770.mpll_ss1 = RREG32(MPLL_SS1);
  270. pi->clk_regs.rv770.mpll_ss2 = RREG32(MPLL_SS2);
  271. }
  272. int rv740_populate_smc_acpi_state(struct radeon_device *rdev,
  273. RV770_SMC_STATETABLE *table)
  274. {
  275. struct rv7xx_power_info *pi = rv770_get_pi(rdev);
  276. u32 mpll_ad_func_cntl = pi->clk_regs.rv770.mpll_ad_func_cntl;
  277. u32 mpll_ad_func_cntl_2 = pi->clk_regs.rv770.mpll_ad_func_cntl_2;
  278. u32 mpll_dq_func_cntl = pi->clk_regs.rv770.mpll_dq_func_cntl;
  279. u32 mpll_dq_func_cntl_2 = pi->clk_regs.rv770.mpll_dq_func_cntl_2;
  280. u32 spll_func_cntl = pi->clk_regs.rv770.cg_spll_func_cntl;
  281. u32 spll_func_cntl_2 = pi->clk_regs.rv770.cg_spll_func_cntl_2;
  282. u32 spll_func_cntl_3 = pi->clk_regs.rv770.cg_spll_func_cntl_3;
  283. u32 mclk_pwrmgt_cntl = pi->clk_regs.rv770.mclk_pwrmgt_cntl;
  284. u32 dll_cntl = pi->clk_regs.rv770.dll_cntl;
  285. table->ACPIState = table->initialState;
  286. table->ACPIState.flags &= ~PPSMC_SWSTATE_FLAG_DC;
  287. if (pi->acpi_vddc) {
  288. rv770_populate_vddc_value(rdev, pi->acpi_vddc,
  289. &table->ACPIState.levels[0].vddc);
  290. table->ACPIState.levels[0].gen2PCIE =
  291. pi->pcie_gen2 ?
  292. pi->acpi_pcie_gen2 : 0;
  293. table->ACPIState.levels[0].gen2XSP =
  294. pi->acpi_pcie_gen2;
  295. } else {
  296. rv770_populate_vddc_value(rdev, pi->min_vddc_in_table,
  297. &table->ACPIState.levels[0].vddc);
  298. table->ACPIState.levels[0].gen2PCIE = 0;
  299. }
  300. mpll_ad_func_cntl_2 |= BIAS_GEN_PDNB | RESET_EN;
  301. mpll_dq_func_cntl_2 |= BYPASS | BIAS_GEN_PDNB | RESET_EN;
  302. mclk_pwrmgt_cntl |= (MRDCKA0_RESET |
  303. MRDCKA1_RESET |
  304. MRDCKB0_RESET |
  305. MRDCKB1_RESET |
  306. MRDCKC0_RESET |
  307. MRDCKC1_RESET |
  308. MRDCKD0_RESET |
  309. MRDCKD1_RESET);
  310. dll_cntl |= (MRDCKA0_BYPASS |
  311. MRDCKA1_BYPASS |
  312. MRDCKB0_BYPASS |
  313. MRDCKB1_BYPASS |
  314. MRDCKC0_BYPASS |
  315. MRDCKC1_BYPASS |
  316. MRDCKD0_BYPASS |
  317. MRDCKD1_BYPASS);
  318. spll_func_cntl |= SPLL_RESET | SPLL_SLEEP | SPLL_BYPASS_EN;
  319. spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK;
  320. spll_func_cntl_2 |= SCLK_MUX_SEL(4);
  321. table->ACPIState.levels[0].mclk.mclk770.vMPLL_AD_FUNC_CNTL = cpu_to_be32(mpll_ad_func_cntl);
  322. table->ACPIState.levels[0].mclk.mclk770.vMPLL_AD_FUNC_CNTL_2 = cpu_to_be32(mpll_ad_func_cntl_2);
  323. table->ACPIState.levels[0].mclk.mclk770.vMPLL_DQ_FUNC_CNTL = cpu_to_be32(mpll_dq_func_cntl);
  324. table->ACPIState.levels[0].mclk.mclk770.vMPLL_DQ_FUNC_CNTL_2 = cpu_to_be32(mpll_dq_func_cntl_2);
  325. table->ACPIState.levels[0].mclk.mclk770.vMCLK_PWRMGT_CNTL = cpu_to_be32(mclk_pwrmgt_cntl);
  326. table->ACPIState.levels[0].mclk.mclk770.vDLL_CNTL = cpu_to_be32(dll_cntl);
  327. table->ACPIState.levels[0].mclk.mclk770.mclk_value = 0;
  328. table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL = cpu_to_be32(spll_func_cntl);
  329. table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 = cpu_to_be32(spll_func_cntl_2);
  330. table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 = cpu_to_be32(spll_func_cntl_3);
  331. table->ACPIState.levels[0].sclk.sclk_value = 0;
  332. table->ACPIState.levels[1] = table->ACPIState.levels[0];
  333. table->ACPIState.levels[2] = table->ACPIState.levels[0];
  334. rv770_populate_mvdd_value(rdev, 0, &table->ACPIState.levels[0].mvdd);
  335. return 0;
  336. }
  337. void rv740_enable_mclk_spread_spectrum(struct radeon_device *rdev,
  338. bool enable)
  339. {
  340. if (enable)
  341. WREG32_P(MPLL_CNTL_MODE, SS_SSEN, ~SS_SSEN);
  342. else
  343. WREG32_P(MPLL_CNTL_MODE, 0, ~SS_SSEN);
  344. }
  345. u8 rv740_get_mclk_frequency_ratio(u32 memory_clock)
  346. {
  347. u8 mc_para_index;
  348. if ((memory_clock < 10000) || (memory_clock > 47500))
  349. mc_para_index = 0x00;
  350. else
  351. mc_para_index = (u8)((memory_clock - 10000) / 2500);
  352. return mc_para_index;
  353. }