nv50_calc.c 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  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_hw.h"
  27. int
  28. nv50_calc_pll(struct drm_device *dev, struct pll_lims *pll, int clk,
  29. int *N1, int *M1, int *N2, int *M2, int *P)
  30. {
  31. struct nouveau_pll_vals pll_vals;
  32. int ret;
  33. ret = nouveau_calc_pll_mnp(dev, pll, clk, &pll_vals);
  34. if (ret <= 0)
  35. return ret;
  36. *N1 = pll_vals.N1;
  37. *M1 = pll_vals.M1;
  38. *N2 = pll_vals.N2;
  39. *M2 = pll_vals.M2;
  40. *P = pll_vals.log2P;
  41. return ret;
  42. }
  43. int
  44. nva3_calc_pll(struct drm_device *dev, struct pll_lims *pll, int clk,
  45. int *pN, int *pfN, int *pM, int *P)
  46. {
  47. u32 best_err = ~0, err;
  48. int M, lM, hM, N, fN;
  49. *P = pll->vco1.maxfreq / clk;
  50. if (*P > pll->max_p)
  51. *P = pll->max_p;
  52. if (*P < pll->min_p)
  53. *P = pll->min_p;
  54. lM = (pll->refclk + pll->vco1.max_inputfreq) / pll->vco1.max_inputfreq;
  55. lM = max(lM, (int)pll->vco1.min_m);
  56. hM = (pll->refclk + pll->vco1.min_inputfreq) / pll->vco1.min_inputfreq;
  57. hM = min(hM, (int)pll->vco1.max_m);
  58. for (M = lM; M <= hM; M++) {
  59. u32 tmp = clk * *P * M;
  60. N = tmp / pll->refclk;
  61. fN = tmp % pll->refclk;
  62. if (!pfN && fN >= pll->refclk / 2)
  63. N++;
  64. if (N < pll->vco1.min_n)
  65. continue;
  66. if (N > pll->vco1.max_n)
  67. break;
  68. err = abs(clk - (pll->refclk * N / M / *P));
  69. if (err < best_err) {
  70. best_err = err;
  71. *pN = N;
  72. *pM = M;
  73. }
  74. if (pfN) {
  75. *pfN = (((fN << 13) / pll->refclk) - 4096) & 0xffff;
  76. return clk;
  77. }
  78. }
  79. if (unlikely(best_err == ~0)) {
  80. NV_ERROR(dev, "unable to find matching pll values\n");
  81. return -EINVAL;
  82. }
  83. return pll->refclk * *pN / *pM / *P;
  84. }