mgag200_g200eh5.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. #include <linux/limits.h>
  3. #include <linux/pci.h>
  4. #include <linux/units.h>
  5. #include <drm/drm_atomic.h>
  6. #include <drm/drm_atomic_helper.h>
  7. #include <drm/drm_drv.h>
  8. #include <drm/drm_gem_atomic_helper.h>
  9. #include <drm/drm_print.h>
  10. #include <drm/drm_probe_helper.h>
  11. #include "mgag200_drv.h"
  12. /*
  13. * PIXPLLC
  14. */
  15. static int mgag200_g200eh5_pixpllc_atomic_check(struct drm_crtc *crtc,
  16. struct drm_atomic_state *new_state)
  17. {
  18. const unsigned long long VCO_MAX = 10 * GIGA; // Hz
  19. const unsigned long long VCO_MIN = 2500 * MEGA; // Hz
  20. const unsigned long long PLL_FREQ_REF = 25 * MEGA; // Hz
  21. struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
  22. struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);
  23. long clock = new_crtc_state->mode.clock;
  24. struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc;
  25. unsigned long long fdelta = ULLONG_MAX;
  26. u16 mult_max = (u16)(VCO_MAX / PLL_FREQ_REF); // 400 (0x190)
  27. u16 mult_min = (u16)(VCO_MIN / PLL_FREQ_REF); // 100 (0x64)
  28. u64 ftmp_delta;
  29. u64 computed_fo;
  30. u16 test_m;
  31. u8 test_div_a;
  32. u8 test_div_b;
  33. u64 fo_hz;
  34. u8 uc_m = 0;
  35. u8 uc_n = 0;
  36. u8 uc_p = 0;
  37. fo_hz = (u64)clock * HZ_PER_KHZ;
  38. for (test_m = mult_min; test_m <= mult_max; test_m++) { // This gives 100 <= M <= 400
  39. for (test_div_a = 8; test_div_a > 0; test_div_a--) { // This gives 1 <= A <= 8
  40. for (test_div_b = 1; test_div_b <= test_div_a; test_div_b++) {
  41. // This gives 1 <= B <= A
  42. computed_fo = (PLL_FREQ_REF * test_m) /
  43. (4 * test_div_a * test_div_b);
  44. if (computed_fo > fo_hz)
  45. ftmp_delta = computed_fo - fo_hz;
  46. else
  47. ftmp_delta = fo_hz - computed_fo;
  48. if (ftmp_delta < fdelta) {
  49. fdelta = ftmp_delta;
  50. uc_m = (u8)(0xFF & test_m);
  51. uc_n = (u8)((0x7 & (test_div_a - 1))
  52. | (0x70 & (0x7 & (test_div_b - 1)) << 4));
  53. uc_p = (u8)(1 & (test_m >> 8));
  54. }
  55. if (fdelta == 0)
  56. break;
  57. }
  58. if (fdelta == 0)
  59. break;
  60. }
  61. if (fdelta == 0)
  62. break;
  63. }
  64. pixpllc->m = uc_m + 1;
  65. pixpllc->n = uc_n + 1;
  66. pixpllc->p = uc_p + 1;
  67. pixpllc->s = 0;
  68. return 0;
  69. }
  70. /*
  71. * Mode-setting pipeline
  72. */
  73. static const struct drm_plane_helper_funcs mgag200_g200eh5_primary_plane_helper_funcs = {
  74. MGAG200_PRIMARY_PLANE_HELPER_FUNCS,
  75. };
  76. static const struct drm_plane_funcs mgag200_g200eh5_primary_plane_funcs = {
  77. MGAG200_PRIMARY_PLANE_FUNCS,
  78. };
  79. static const struct drm_crtc_helper_funcs mgag200_g200eh5_crtc_helper_funcs = {
  80. MGAG200_CRTC_HELPER_FUNCS,
  81. };
  82. static const struct drm_crtc_funcs mgag200_g200eh5_crtc_funcs = {
  83. MGAG200_CRTC_FUNCS,
  84. };
  85. static int mgag200_g200eh5_pipeline_init(struct mga_device *mdev)
  86. {
  87. struct drm_device *dev = &mdev->base;
  88. struct drm_plane *primary_plane = &mdev->primary_plane;
  89. struct drm_crtc *crtc = &mdev->crtc;
  90. int ret;
  91. ret = drm_universal_plane_init(dev, primary_plane, 0,
  92. &mgag200_g200eh5_primary_plane_funcs,
  93. mgag200_primary_plane_formats,
  94. mgag200_primary_plane_formats_size,
  95. mgag200_primary_plane_fmtmods,
  96. DRM_PLANE_TYPE_PRIMARY, NULL);
  97. if (ret) {
  98. drm_err(dev, "drm_universal_plane_init() failed: %d\n", ret);
  99. return ret;
  100. }
  101. drm_plane_helper_add(primary_plane, &mgag200_g200eh5_primary_plane_helper_funcs);
  102. drm_plane_enable_fb_damage_clips(primary_plane);
  103. ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL,
  104. &mgag200_g200eh5_crtc_funcs, NULL);
  105. if (ret) {
  106. drm_err(dev, "drm_crtc_init_with_planes() failed: %d\n", ret);
  107. return ret;
  108. }
  109. drm_crtc_helper_add(crtc, &mgag200_g200eh5_crtc_helper_funcs);
  110. /* FIXME: legacy gamma tables, but atomic gamma doesn't work without */
  111. drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE);
  112. drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE);
  113. ret = mgag200_vga_bmc_output_init(mdev);
  114. if (ret)
  115. return ret;
  116. return 0;
  117. }
  118. /*
  119. * DRM device
  120. */
  121. static const struct mgag200_device_info mgag200_g200eh5_device_info =
  122. MGAG200_DEVICE_INFO_INIT(2048, 2048, 0, false, 1, 0, false);
  123. static const struct mgag200_device_funcs mgag200_g200eh5_device_funcs = {
  124. .pixpllc_atomic_check = mgag200_g200eh5_pixpllc_atomic_check,
  125. .pixpllc_atomic_update = mgag200_g200eh_pixpllc_atomic_update, // same as G200EH
  126. };
  127. struct mga_device *mgag200_g200eh5_device_create(struct pci_dev *pdev,
  128. const struct drm_driver *drv)
  129. {
  130. struct mga_device *mdev;
  131. struct drm_device *dev;
  132. resource_size_t vram_available;
  133. int ret;
  134. mdev = devm_drm_dev_alloc(&pdev->dev, drv, struct mga_device, base);
  135. if (IS_ERR(mdev))
  136. return mdev;
  137. dev = &mdev->base;
  138. pci_set_drvdata(pdev, dev);
  139. ret = mgag200_init_pci_options(pdev, 0x00000120, 0x0000b000);
  140. if (ret)
  141. return ERR_PTR(ret);
  142. ret = mgag200_device_preinit(mdev);
  143. if (ret)
  144. return ERR_PTR(ret);
  145. ret = mgag200_device_init(mdev, &mgag200_g200eh5_device_info,
  146. &mgag200_g200eh5_device_funcs);
  147. if (ret)
  148. return ERR_PTR(ret);
  149. mgag200_g200eh_init_registers(mdev); // same as G200EH
  150. vram_available = mgag200_device_probe_vram(mdev);
  151. ret = mgag200_mode_config_init(mdev, vram_available);
  152. if (ret)
  153. return ERR_PTR(ret);
  154. ret = mgag200_g200eh5_pipeline_init(mdev);
  155. if (ret)
  156. return ERR_PTR(ret);
  157. drm_mode_config_reset(dev);
  158. drm_kms_helper_poll_init(dev);
  159. return mdev;
  160. }