nva3_pm.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. /*
  2. * Copyright 2010 Red Hat 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: Ben Skeggs
  23. */
  24. #include "drmP.h"
  25. #include "nouveau_drv.h"
  26. #include "nouveau_bios.h"
  27. #include "nouveau_pm.h"
  28. /* This is actually a lot more complex than it appears here, but hopefully
  29. * this should be able to deal with what the VBIOS leaves for us..
  30. *
  31. * If not, well, I'll jump off that bridge when I come to it.
  32. */
  33. struct nva3_pm_state {
  34. enum pll_types type;
  35. u32 src0;
  36. u32 src1;
  37. u32 ctrl;
  38. u32 coef;
  39. u32 old_pnm;
  40. u32 new_pnm;
  41. u32 new_div;
  42. };
  43. static int
  44. nva3_pm_pll_offset(u32 id)
  45. {
  46. static const u32 pll_map[] = {
  47. 0x00, PLL_CORE,
  48. 0x01, PLL_SHADER,
  49. 0x02, PLL_MEMORY,
  50. 0x00, 0x00
  51. };
  52. const u32 *map = pll_map;
  53. while (map[1]) {
  54. if (id == map[1])
  55. return map[0];
  56. map += 2;
  57. }
  58. return -ENOENT;
  59. }
  60. int
  61. nva3_pm_clock_get(struct drm_device *dev, u32 id)
  62. {
  63. u32 src0, src1, ctrl, coef;
  64. struct pll_lims pll;
  65. int ret, off;
  66. int P, N, M;
  67. ret = get_pll_limits(dev, id, &pll);
  68. if (ret)
  69. return ret;
  70. off = nva3_pm_pll_offset(id);
  71. if (off < 0)
  72. return off;
  73. src0 = nv_rd32(dev, 0x4120 + (off * 4));
  74. src1 = nv_rd32(dev, 0x4160 + (off * 4));
  75. ctrl = nv_rd32(dev, pll.reg + 0);
  76. coef = nv_rd32(dev, pll.reg + 4);
  77. NV_DEBUG(dev, "PLL %02x: 0x%08x 0x%08x 0x%08x 0x%08x\n",
  78. id, src0, src1, ctrl, coef);
  79. if (ctrl & 0x00000008) {
  80. u32 div = ((src1 & 0x003c0000) >> 18) + 1;
  81. return (pll.refclk * 2) / div;
  82. }
  83. P = (coef & 0x003f0000) >> 16;
  84. N = (coef & 0x0000ff00) >> 8;
  85. M = (coef & 0x000000ff);
  86. return pll.refclk * N / M / P;
  87. }
  88. void *
  89. nva3_pm_clock_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl,
  90. u32 id, int khz)
  91. {
  92. struct nva3_pm_state *pll;
  93. struct pll_lims limits;
  94. int N, M, P, diff;
  95. int ret, off;
  96. ret = get_pll_limits(dev, id, &limits);
  97. if (ret < 0)
  98. return (ret == -ENOENT) ? NULL : ERR_PTR(ret);
  99. off = nva3_pm_pll_offset(id);
  100. if (id < 0)
  101. return ERR_PTR(-EINVAL);
  102. pll = kzalloc(sizeof(*pll), GFP_KERNEL);
  103. if (!pll)
  104. return ERR_PTR(-ENOMEM);
  105. pll->type = id;
  106. pll->src0 = 0x004120 + (off * 4);
  107. pll->src1 = 0x004160 + (off * 4);
  108. pll->ctrl = limits.reg + 0;
  109. pll->coef = limits.reg + 4;
  110. /* If target clock is within [-2, 3) MHz of a divisor, we'll
  111. * use that instead of calculating MNP values
  112. */
  113. pll->new_div = min((limits.refclk * 2) / (khz - 2999), 16);
  114. if (pll->new_div) {
  115. diff = khz - ((limits.refclk * 2) / pll->new_div);
  116. if (diff < -2000 || diff >= 3000)
  117. pll->new_div = 0;
  118. }
  119. if (!pll->new_div) {
  120. ret = nva3_calc_pll(dev, &limits, khz, &N, NULL, &M, &P);
  121. if (ret < 0)
  122. return ERR_PTR(ret);
  123. pll->new_pnm = (P << 16) | (N << 8) | M;
  124. pll->new_div = 2 - 1;
  125. } else {
  126. pll->new_pnm = 0;
  127. pll->new_div--;
  128. }
  129. if ((nv_rd32(dev, pll->src1) & 0x00000101) != 0x00000101)
  130. pll->old_pnm = nv_rd32(dev, pll->coef);
  131. return pll;
  132. }
  133. void
  134. nva3_pm_clock_set(struct drm_device *dev, void *pre_state)
  135. {
  136. struct nva3_pm_state *pll = pre_state;
  137. u32 ctrl = 0;
  138. /* For the memory clock, NVIDIA will build a "script" describing
  139. * the reclocking process and ask PDAEMON to execute it.
  140. */
  141. if (pll->type == PLL_MEMORY) {
  142. nv_wr32(dev, 0x100210, 0);
  143. nv_wr32(dev, 0x1002dc, 1);
  144. nv_wr32(dev, 0x004018, 0x00001000);
  145. ctrl = 0x18000100;
  146. }
  147. if (pll->old_pnm || !pll->new_pnm) {
  148. nv_mask(dev, pll->src1, 0x003c0101, 0x00000101 |
  149. (pll->new_div << 18));
  150. nv_wr32(dev, pll->ctrl, 0x0001001d | ctrl);
  151. nv_mask(dev, pll->ctrl, 0x00000001, 0x00000000);
  152. }
  153. if (pll->new_pnm) {
  154. nv_mask(dev, pll->src0, 0x00000101, 0x00000101);
  155. nv_wr32(dev, pll->coef, pll->new_pnm);
  156. nv_wr32(dev, pll->ctrl, 0x0001001d | ctrl);
  157. nv_mask(dev, pll->ctrl, 0x00000010, 0x00000000);
  158. nv_mask(dev, pll->ctrl, 0x00020010, 0x00020010);
  159. nv_wr32(dev, pll->ctrl, 0x00010015 | ctrl);
  160. nv_mask(dev, pll->src1, 0x00000100, 0x00000000);
  161. nv_mask(dev, pll->src1, 0x00000001, 0x00000000);
  162. if (pll->type == PLL_MEMORY)
  163. nv_wr32(dev, 0x4018, 0x10005000);
  164. } else {
  165. nv_mask(dev, pll->ctrl, 0x00000001, 0x00000000);
  166. nv_mask(dev, pll->src0, 0x00000100, 0x00000000);
  167. nv_mask(dev, pll->src0, 0x00000001, 0x00000000);
  168. if (pll->type == PLL_MEMORY)
  169. nv_wr32(dev, 0x4018, 0x1000d000);
  170. }
  171. if (pll->type == PLL_MEMORY) {
  172. nv_wr32(dev, 0x1002dc, 0);
  173. nv_wr32(dev, 0x100210, 0x80000000);
  174. }
  175. kfree(pll);
  176. }