185397f6bSThomas Zimmermann // SPDX-License-Identifier: GPL-2.0-only 285397f6bSThomas Zimmermann 3*877507bbSThomas Zimmermann #include <linux/delay.h> 485397f6bSThomas Zimmermann #include <linux/pci.h> 585397f6bSThomas Zimmermann 6*877507bbSThomas Zimmermann #include <drm/drm_atomic.h> 785397f6bSThomas Zimmermann #include <drm/drm_drv.h> 885397f6bSThomas Zimmermann 985397f6bSThomas Zimmermann #include "mgag200_drv.h" 1085397f6bSThomas Zimmermann 111ee181feSThomas Zimmermann void mgag200_g200eh_init_registers(struct mga_device *mdev) 121ee181feSThomas Zimmermann { 131ee181feSThomas Zimmermann static const u8 dacvalue[] = { 141ee181feSThomas Zimmermann MGAG200_DAC_DEFAULT(0x00, 0xc9, 151ee181feSThomas Zimmermann MGA1064_MISC_CTL_VGA8 | MGA1064_MISC_CTL_DAC_RAM_CS, 161ee181feSThomas Zimmermann 0x00, 0x00, 0x00) 171ee181feSThomas Zimmermann }; 181ee181feSThomas Zimmermann 191ee181feSThomas Zimmermann size_t i; 201ee181feSThomas Zimmermann 211ee181feSThomas Zimmermann for (i = 0; i < ARRAY_SIZE(dacvalue); i++) { 221ee181feSThomas Zimmermann if ((i <= 0x17) || 231ee181feSThomas Zimmermann (i == 0x1b) || 241ee181feSThomas Zimmermann (i == 0x1c) || 251ee181feSThomas Zimmermann ((i >= 0x1f) && (i <= 0x29)) || 261ee181feSThomas Zimmermann ((i >= 0x30) && (i <= 0x37)) || 271ee181feSThomas Zimmermann ((i >= 0x44) && (i <= 0x4e))) 281ee181feSThomas Zimmermann continue; 291ee181feSThomas Zimmermann WREG_DAC(i, dacvalue[i]); 301ee181feSThomas Zimmermann } 311ee181feSThomas Zimmermann 321ee181feSThomas Zimmermann mgag200_init_registers(mdev); 331ee181feSThomas Zimmermann } 341ee181feSThomas Zimmermann 3585397f6bSThomas Zimmermann /* 36*877507bbSThomas Zimmermann * PIXPLLC 37*877507bbSThomas Zimmermann */ 38*877507bbSThomas Zimmermann 39*877507bbSThomas Zimmermann static int mgag200_g200eh_pixpllc_atomic_check(struct drm_crtc *crtc, 40*877507bbSThomas Zimmermann struct drm_atomic_state *new_state) 41*877507bbSThomas Zimmermann { 42*877507bbSThomas Zimmermann static const unsigned int vcomax = 800000; 43*877507bbSThomas Zimmermann static const unsigned int vcomin = 400000; 44*877507bbSThomas Zimmermann static const unsigned int pllreffreq = 33333; 45*877507bbSThomas Zimmermann 46*877507bbSThomas Zimmermann struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc); 47*877507bbSThomas Zimmermann struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state); 48*877507bbSThomas Zimmermann long clock = new_crtc_state->mode.clock; 49*877507bbSThomas Zimmermann struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc; 50*877507bbSThomas Zimmermann unsigned int delta, tmpdelta; 51*877507bbSThomas Zimmermann unsigned int testp, testm, testn; 52*877507bbSThomas Zimmermann unsigned int p, m, n, s; 53*877507bbSThomas Zimmermann unsigned int computed; 54*877507bbSThomas Zimmermann 55*877507bbSThomas Zimmermann m = n = p = s = 0; 56*877507bbSThomas Zimmermann delta = 0xffffffff; 57*877507bbSThomas Zimmermann 58*877507bbSThomas Zimmermann for (testp = 16; testp > 0; testp >>= 1) { 59*877507bbSThomas Zimmermann if (clock * testp > vcomax) 60*877507bbSThomas Zimmermann continue; 61*877507bbSThomas Zimmermann if (clock * testp < vcomin) 62*877507bbSThomas Zimmermann continue; 63*877507bbSThomas Zimmermann 64*877507bbSThomas Zimmermann for (testm = 1; testm < 33; testm++) { 65*877507bbSThomas Zimmermann for (testn = 17; testn < 257; testn++) { 66*877507bbSThomas Zimmermann computed = (pllreffreq * testn) / (testm * testp); 67*877507bbSThomas Zimmermann if (computed > clock) 68*877507bbSThomas Zimmermann tmpdelta = computed - clock; 69*877507bbSThomas Zimmermann else 70*877507bbSThomas Zimmermann tmpdelta = clock - computed; 71*877507bbSThomas Zimmermann if (tmpdelta < delta) { 72*877507bbSThomas Zimmermann delta = tmpdelta; 73*877507bbSThomas Zimmermann n = testn; 74*877507bbSThomas Zimmermann m = testm; 75*877507bbSThomas Zimmermann p = testp; 76*877507bbSThomas Zimmermann } 77*877507bbSThomas Zimmermann } 78*877507bbSThomas Zimmermann } 79*877507bbSThomas Zimmermann } 80*877507bbSThomas Zimmermann 81*877507bbSThomas Zimmermann pixpllc->m = m; 82*877507bbSThomas Zimmermann pixpllc->n = n; 83*877507bbSThomas Zimmermann pixpllc->p = p; 84*877507bbSThomas Zimmermann pixpllc->s = s; 85*877507bbSThomas Zimmermann 86*877507bbSThomas Zimmermann return 0; 87*877507bbSThomas Zimmermann } 88*877507bbSThomas Zimmermann 89*877507bbSThomas Zimmermann void mgag200_g200eh_pixpllc_atomic_update(struct drm_crtc *crtc, 90*877507bbSThomas Zimmermann struct drm_atomic_state *old_state) 91*877507bbSThomas Zimmermann { 92*877507bbSThomas Zimmermann struct drm_device *dev = crtc->dev; 93*877507bbSThomas Zimmermann struct mga_device *mdev = to_mga_device(dev); 94*877507bbSThomas Zimmermann struct drm_crtc_state *crtc_state = crtc->state; 95*877507bbSThomas Zimmermann struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state); 96*877507bbSThomas Zimmermann struct mgag200_pll_values *pixpllc = &mgag200_crtc_state->pixpllc; 97*877507bbSThomas Zimmermann unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs; 98*877507bbSThomas Zimmermann u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp; 99*877507bbSThomas Zimmermann int i, j, tmpcount, vcount; 100*877507bbSThomas Zimmermann bool pll_locked = false; 101*877507bbSThomas Zimmermann 102*877507bbSThomas Zimmermann pixpllcm = pixpllc->m - 1; 103*877507bbSThomas Zimmermann pixpllcn = pixpllc->n - 1; 104*877507bbSThomas Zimmermann pixpllcp = pixpllc->p - 1; 105*877507bbSThomas Zimmermann pixpllcs = pixpllc->s; 106*877507bbSThomas Zimmermann 107*877507bbSThomas Zimmermann xpixpllcm = ((pixpllcn & BIT(8)) >> 1) | pixpllcm; 108*877507bbSThomas Zimmermann xpixpllcn = pixpllcn; 109*877507bbSThomas Zimmermann xpixpllcp = (pixpllcs << 3) | pixpllcp; 110*877507bbSThomas Zimmermann 111*877507bbSThomas Zimmermann WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK); 112*877507bbSThomas Zimmermann 113*877507bbSThomas Zimmermann for (i = 0; i <= 32 && pll_locked == false; i++) { 114*877507bbSThomas Zimmermann WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 115*877507bbSThomas Zimmermann tmp = RREG8(DAC_DATA); 116*877507bbSThomas Zimmermann tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS; 117*877507bbSThomas Zimmermann WREG8(DAC_DATA, tmp); 118*877507bbSThomas Zimmermann 119*877507bbSThomas Zimmermann tmp = RREG8(MGAREG_MEM_MISC_READ); 120*877507bbSThomas Zimmermann tmp |= 0x3 << 2; 121*877507bbSThomas Zimmermann WREG8(MGAREG_MEM_MISC_WRITE, tmp); 122*877507bbSThomas Zimmermann 123*877507bbSThomas Zimmermann WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 124*877507bbSThomas Zimmermann tmp = RREG8(DAC_DATA); 125*877507bbSThomas Zimmermann tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; 126*877507bbSThomas Zimmermann WREG8(DAC_DATA, tmp); 127*877507bbSThomas Zimmermann 128*877507bbSThomas Zimmermann udelay(500); 129*877507bbSThomas Zimmermann 130*877507bbSThomas Zimmermann WREG_DAC(MGA1064_EH_PIX_PLLC_M, xpixpllcm); 131*877507bbSThomas Zimmermann WREG_DAC(MGA1064_EH_PIX_PLLC_N, xpixpllcn); 132*877507bbSThomas Zimmermann WREG_DAC(MGA1064_EH_PIX_PLLC_P, xpixpllcp); 133*877507bbSThomas Zimmermann 134*877507bbSThomas Zimmermann udelay(500); 135*877507bbSThomas Zimmermann 136*877507bbSThomas Zimmermann WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 137*877507bbSThomas Zimmermann tmp = RREG8(DAC_DATA); 138*877507bbSThomas Zimmermann tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK; 139*877507bbSThomas Zimmermann tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL; 140*877507bbSThomas Zimmermann WREG8(DAC_DATA, tmp); 141*877507bbSThomas Zimmermann 142*877507bbSThomas Zimmermann WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 143*877507bbSThomas Zimmermann tmp = RREG8(DAC_DATA); 144*877507bbSThomas Zimmermann tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS; 145*877507bbSThomas Zimmermann tmp &= ~MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; 146*877507bbSThomas Zimmermann WREG8(DAC_DATA, tmp); 147*877507bbSThomas Zimmermann 148*877507bbSThomas Zimmermann vcount = RREG8(MGAREG_VCOUNT); 149*877507bbSThomas Zimmermann 150*877507bbSThomas Zimmermann for (j = 0; j < 30 && pll_locked == false; j++) { 151*877507bbSThomas Zimmermann tmpcount = RREG8(MGAREG_VCOUNT); 152*877507bbSThomas Zimmermann if (tmpcount < vcount) 153*877507bbSThomas Zimmermann vcount = 0; 154*877507bbSThomas Zimmermann if ((tmpcount - vcount) > 2) 155*877507bbSThomas Zimmermann pll_locked = true; 156*877507bbSThomas Zimmermann else 157*877507bbSThomas Zimmermann udelay(5); 158*877507bbSThomas Zimmermann } 159*877507bbSThomas Zimmermann } 160*877507bbSThomas Zimmermann } 161*877507bbSThomas Zimmermann 162*877507bbSThomas Zimmermann /* 16385397f6bSThomas Zimmermann * DRM device 16485397f6bSThomas Zimmermann */ 16585397f6bSThomas Zimmermann 166b9a577a4SThomas Zimmermann static const struct mgag200_device_info mgag200_g200eh_device_info = 167da1efdb2SThomas Zimmermann MGAG200_DEVICE_INFO_INIT(2048, 2048, 37500, false, 1, 0, false); 168b9a577a4SThomas Zimmermann 169f639f74aSThomas Zimmermann static const struct mgag200_device_funcs mgag200_g200eh_device_funcs = { 170*877507bbSThomas Zimmermann .pixpllc_atomic_check = mgag200_g200eh_pixpllc_atomic_check, 171*877507bbSThomas Zimmermann .pixpllc_atomic_update = mgag200_g200eh_pixpllc_atomic_update, 172f639f74aSThomas Zimmermann }; 173f639f74aSThomas Zimmermann 17485397f6bSThomas Zimmermann struct mga_device *mgag200_g200eh_device_create(struct pci_dev *pdev, const struct drm_driver *drv, 17521e74bf9SThomas Zimmermann enum mga_type type) 17685397f6bSThomas Zimmermann { 17785397f6bSThomas Zimmermann struct mga_device *mdev; 17885397f6bSThomas Zimmermann struct drm_device *dev; 179d45e32c9SThomas Zimmermann resource_size_t vram_available; 18085397f6bSThomas Zimmermann int ret; 18185397f6bSThomas Zimmermann 18285397f6bSThomas Zimmermann mdev = devm_drm_dev_alloc(&pdev->dev, drv, struct mga_device, base); 18385397f6bSThomas Zimmermann if (IS_ERR(mdev)) 18485397f6bSThomas Zimmermann return mdev; 18585397f6bSThomas Zimmermann dev = &mdev->base; 18685397f6bSThomas Zimmermann 18785397f6bSThomas Zimmermann pci_set_drvdata(pdev, dev); 18885397f6bSThomas Zimmermann 189ce19021fSThomas Zimmermann ret = mgag200_init_pci_options(pdev, 0x00000120, 0x0000b000); 190ce19021fSThomas Zimmermann if (ret) 191ce19021fSThomas Zimmermann return ERR_PTR(ret); 192ce19021fSThomas Zimmermann 193b62d943eSThomas Zimmermann ret = mgag200_device_preinit(mdev); 19485397f6bSThomas Zimmermann if (ret) 19585397f6bSThomas Zimmermann return ERR_PTR(ret); 19685397f6bSThomas Zimmermann 197f639f74aSThomas Zimmermann ret = mgag200_device_init(mdev, type, &mgag200_g200eh_device_info, 198f639f74aSThomas Zimmermann &mgag200_g200eh_device_funcs); 19985397f6bSThomas Zimmermann if (ret) 20085397f6bSThomas Zimmermann return ERR_PTR(ret); 20185397f6bSThomas Zimmermann 2021ee181feSThomas Zimmermann mgag200_g200eh_init_registers(mdev); 2031ee181feSThomas Zimmermann 204d45e32c9SThomas Zimmermann vram_available = mgag200_device_probe_vram(mdev); 205d45e32c9SThomas Zimmermann 206d45e32c9SThomas Zimmermann ret = mgag200_modeset_init(mdev, vram_available); 20785397f6bSThomas Zimmermann if (ret) 20885397f6bSThomas Zimmermann return ERR_PTR(ret); 20985397f6bSThomas Zimmermann 21085397f6bSThomas Zimmermann return mdev; 21185397f6bSThomas Zimmermann } 212