diff options
Diffstat (limited to 'drivers/gpu/drm/mgag200/mgag200_g200eh3.c')
-rw-r--r-- | drivers/gpu/drm/mgag200/mgag200_g200eh3.c | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/drivers/gpu/drm/mgag200/mgag200_g200eh3.c b/drivers/gpu/drm/mgag200/mgag200_g200eh3.c index 99e00aa848e1..b47b100d219d 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200eh3.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200eh3.c @@ -2,11 +2,68 @@ #include <linux/pci.h> +#include <drm/drm_atomic.h> #include <drm/drm_drv.h> #include "mgag200_drv.h" /* + * PIXPLLC + */ + +static int mgag200_g200eh3_pixpllc_atomic_check(struct drm_crtc *crtc, + struct drm_atomic_state *new_state) +{ + static const unsigned int vcomax = 3000000; + static const unsigned int vcomin = 1500000; + static const unsigned int pllreffreq = 25000; + + struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc); + struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state); + long clock = new_crtc_state->mode.clock; + struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc; + unsigned int delta, tmpdelta; + unsigned int testp, testm, testn; + unsigned int p, m, n, s; + unsigned int computed; + + m = n = p = s = 0; + delta = 0xffffffff; + testp = 0; + + for (testm = 150; testm >= 6; testm--) { + if (clock * testm > vcomax) + continue; + if (clock * testm < vcomin) + continue; + for (testn = 120; testn >= 60; testn--) { + computed = (pllreffreq * testn) / testm; + if (computed > clock) + tmpdelta = computed - clock; + else + tmpdelta = clock - computed; + if (tmpdelta < delta) { + delta = tmpdelta; + n = testn + 1; + m = testm + 1; + p = testp + 1; + } + if (delta == 0) + break; + } + if (delta == 0) + break; + } + + pixpllc->m = m; + pixpllc->n = n; + pixpllc->p = p; + pixpllc->s = s; + + return 0; +} + +/* * DRM device */ @@ -14,6 +71,8 @@ static const struct mgag200_device_info mgag200_g200eh3_device_info = MGAG200_DEVICE_INFO_INIT(2048, 2048, 0, false, 1, 0, false); static const struct mgag200_device_funcs mgag200_g200eh3_device_funcs = { + .pixpllc_atomic_check = mgag200_g200eh3_pixpllc_atomic_check, + .pixpllc_atomic_update = mgag200_g200eh_pixpllc_atomic_update, // same as G200EH }; struct mga_device *mgag200_g200eh3_device_create(struct pci_dev *pdev, |