185397f6bSThomas Zimmermann // SPDX-License-Identifier: GPL-2.0-only 285397f6bSThomas Zimmermann 3877507bbSThomas Zimmermann #include <linux/delay.h> 485397f6bSThomas Zimmermann #include <linux/pci.h> 585397f6bSThomas Zimmermann 6877507bbSThomas Zimmermann #include <drm/drm_atomic.h> 7*bc835040SThomas Zimmermann #include <drm/drm_atomic_helper.h> 885397f6bSThomas Zimmermann #include <drm/drm_drv.h> 9*bc835040SThomas Zimmermann #include <drm/drm_gem_atomic_helper.h> 10*bc835040SThomas Zimmermann #include <drm/drm_probe_helper.h> 1185397f6bSThomas Zimmermann 1285397f6bSThomas Zimmermann #include "mgag200_drv.h" 1385397f6bSThomas Zimmermann 141ee181feSThomas Zimmermann void mgag200_g200eh_init_registers(struct mga_device *mdev) 151ee181feSThomas Zimmermann { 161ee181feSThomas Zimmermann static const u8 dacvalue[] = { 171ee181feSThomas Zimmermann MGAG200_DAC_DEFAULT(0x00, 0xc9, 181ee181feSThomas Zimmermann MGA1064_MISC_CTL_VGA8 | MGA1064_MISC_CTL_DAC_RAM_CS, 191ee181feSThomas Zimmermann 0x00, 0x00, 0x00) 201ee181feSThomas Zimmermann }; 211ee181feSThomas Zimmermann 221ee181feSThomas Zimmermann size_t i; 231ee181feSThomas Zimmermann 241ee181feSThomas Zimmermann for (i = 0; i < ARRAY_SIZE(dacvalue); i++) { 251ee181feSThomas Zimmermann if ((i <= 0x17) || 261ee181feSThomas Zimmermann (i == 0x1b) || 271ee181feSThomas Zimmermann (i == 0x1c) || 281ee181feSThomas Zimmermann ((i >= 0x1f) && (i <= 0x29)) || 291ee181feSThomas Zimmermann ((i >= 0x30) && (i <= 0x37)) || 301ee181feSThomas Zimmermann ((i >= 0x44) && (i <= 0x4e))) 311ee181feSThomas Zimmermann continue; 321ee181feSThomas Zimmermann WREG_DAC(i, dacvalue[i]); 331ee181feSThomas Zimmermann } 341ee181feSThomas Zimmermann 351ee181feSThomas Zimmermann mgag200_init_registers(mdev); 361ee181feSThomas Zimmermann } 371ee181feSThomas Zimmermann 3885397f6bSThomas Zimmermann /* 39877507bbSThomas Zimmermann * PIXPLLC 40877507bbSThomas Zimmermann */ 41877507bbSThomas Zimmermann 42877507bbSThomas Zimmermann static int mgag200_g200eh_pixpllc_atomic_check(struct drm_crtc *crtc, 43877507bbSThomas Zimmermann struct drm_atomic_state *new_state) 44877507bbSThomas Zimmermann { 45877507bbSThomas Zimmermann static const unsigned int vcomax = 800000; 46877507bbSThomas Zimmermann static const unsigned int vcomin = 400000; 47877507bbSThomas Zimmermann static const unsigned int pllreffreq = 33333; 48877507bbSThomas Zimmermann 49877507bbSThomas Zimmermann struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc); 50877507bbSThomas Zimmermann struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state); 51877507bbSThomas Zimmermann long clock = new_crtc_state->mode.clock; 52877507bbSThomas Zimmermann struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc; 53877507bbSThomas Zimmermann unsigned int delta, tmpdelta; 54877507bbSThomas Zimmermann unsigned int testp, testm, testn; 55877507bbSThomas Zimmermann unsigned int p, m, n, s; 56877507bbSThomas Zimmermann unsigned int computed; 57877507bbSThomas Zimmermann 58877507bbSThomas Zimmermann m = n = p = s = 0; 59877507bbSThomas Zimmermann delta = 0xffffffff; 60877507bbSThomas Zimmermann 61877507bbSThomas Zimmermann for (testp = 16; testp > 0; testp >>= 1) { 62877507bbSThomas Zimmermann if (clock * testp > vcomax) 63877507bbSThomas Zimmermann continue; 64877507bbSThomas Zimmermann if (clock * testp < vcomin) 65877507bbSThomas Zimmermann continue; 66877507bbSThomas Zimmermann 67877507bbSThomas Zimmermann for (testm = 1; testm < 33; testm++) { 68877507bbSThomas Zimmermann for (testn = 17; testn < 257; testn++) { 69877507bbSThomas Zimmermann computed = (pllreffreq * testn) / (testm * testp); 70877507bbSThomas Zimmermann if (computed > clock) 71877507bbSThomas Zimmermann tmpdelta = computed - clock; 72877507bbSThomas Zimmermann else 73877507bbSThomas Zimmermann tmpdelta = clock - computed; 74877507bbSThomas Zimmermann if (tmpdelta < delta) { 75877507bbSThomas Zimmermann delta = tmpdelta; 76877507bbSThomas Zimmermann n = testn; 77877507bbSThomas Zimmermann m = testm; 78877507bbSThomas Zimmermann p = testp; 79877507bbSThomas Zimmermann } 80877507bbSThomas Zimmermann } 81877507bbSThomas Zimmermann } 82877507bbSThomas Zimmermann } 83877507bbSThomas Zimmermann 84877507bbSThomas Zimmermann pixpllc->m = m; 85877507bbSThomas Zimmermann pixpllc->n = n; 86877507bbSThomas Zimmermann pixpllc->p = p; 87877507bbSThomas Zimmermann pixpllc->s = s; 88877507bbSThomas Zimmermann 89877507bbSThomas Zimmermann return 0; 90877507bbSThomas Zimmermann } 91877507bbSThomas Zimmermann 92877507bbSThomas Zimmermann void mgag200_g200eh_pixpllc_atomic_update(struct drm_crtc *crtc, 93877507bbSThomas Zimmermann struct drm_atomic_state *old_state) 94877507bbSThomas Zimmermann { 95877507bbSThomas Zimmermann struct drm_device *dev = crtc->dev; 96877507bbSThomas Zimmermann struct mga_device *mdev = to_mga_device(dev); 97877507bbSThomas Zimmermann struct drm_crtc_state *crtc_state = crtc->state; 98877507bbSThomas Zimmermann struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state); 99877507bbSThomas Zimmermann struct mgag200_pll_values *pixpllc = &mgag200_crtc_state->pixpllc; 100877507bbSThomas Zimmermann unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs; 101877507bbSThomas Zimmermann u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp; 102877507bbSThomas Zimmermann int i, j, tmpcount, vcount; 103877507bbSThomas Zimmermann bool pll_locked = false; 104877507bbSThomas Zimmermann 105877507bbSThomas Zimmermann pixpllcm = pixpllc->m - 1; 106877507bbSThomas Zimmermann pixpllcn = pixpllc->n - 1; 107877507bbSThomas Zimmermann pixpllcp = pixpllc->p - 1; 108877507bbSThomas Zimmermann pixpllcs = pixpllc->s; 109877507bbSThomas Zimmermann 110877507bbSThomas Zimmermann xpixpllcm = ((pixpllcn & BIT(8)) >> 1) | pixpllcm; 111877507bbSThomas Zimmermann xpixpllcn = pixpllcn; 112877507bbSThomas Zimmermann xpixpllcp = (pixpllcs << 3) | pixpllcp; 113877507bbSThomas Zimmermann 114877507bbSThomas Zimmermann WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK); 115877507bbSThomas Zimmermann 116877507bbSThomas Zimmermann for (i = 0; i <= 32 && pll_locked == false; i++) { 117877507bbSThomas Zimmermann WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 118877507bbSThomas Zimmermann tmp = RREG8(DAC_DATA); 119877507bbSThomas Zimmermann tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS; 120877507bbSThomas Zimmermann WREG8(DAC_DATA, tmp); 121877507bbSThomas Zimmermann 122877507bbSThomas Zimmermann tmp = RREG8(MGAREG_MEM_MISC_READ); 123877507bbSThomas Zimmermann tmp |= 0x3 << 2; 124877507bbSThomas Zimmermann WREG8(MGAREG_MEM_MISC_WRITE, tmp); 125877507bbSThomas Zimmermann 126877507bbSThomas Zimmermann WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 127877507bbSThomas Zimmermann tmp = RREG8(DAC_DATA); 128877507bbSThomas Zimmermann tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; 129877507bbSThomas Zimmermann WREG8(DAC_DATA, tmp); 130877507bbSThomas Zimmermann 131877507bbSThomas Zimmermann udelay(500); 132877507bbSThomas Zimmermann 133877507bbSThomas Zimmermann WREG_DAC(MGA1064_EH_PIX_PLLC_M, xpixpllcm); 134877507bbSThomas Zimmermann WREG_DAC(MGA1064_EH_PIX_PLLC_N, xpixpllcn); 135877507bbSThomas Zimmermann WREG_DAC(MGA1064_EH_PIX_PLLC_P, xpixpllcp); 136877507bbSThomas Zimmermann 137877507bbSThomas Zimmermann udelay(500); 138877507bbSThomas Zimmermann 139877507bbSThomas Zimmermann WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 140877507bbSThomas Zimmermann tmp = RREG8(DAC_DATA); 141877507bbSThomas Zimmermann tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK; 142877507bbSThomas Zimmermann tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL; 143877507bbSThomas Zimmermann WREG8(DAC_DATA, tmp); 144877507bbSThomas Zimmermann 145877507bbSThomas Zimmermann WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 146877507bbSThomas Zimmermann tmp = RREG8(DAC_DATA); 147877507bbSThomas Zimmermann tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS; 148877507bbSThomas Zimmermann tmp &= ~MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; 149877507bbSThomas Zimmermann WREG8(DAC_DATA, tmp); 150877507bbSThomas Zimmermann 151877507bbSThomas Zimmermann vcount = RREG8(MGAREG_VCOUNT); 152877507bbSThomas Zimmermann 153877507bbSThomas Zimmermann for (j = 0; j < 30 && pll_locked == false; j++) { 154877507bbSThomas Zimmermann tmpcount = RREG8(MGAREG_VCOUNT); 155877507bbSThomas Zimmermann if (tmpcount < vcount) 156877507bbSThomas Zimmermann vcount = 0; 157877507bbSThomas Zimmermann if ((tmpcount - vcount) > 2) 158877507bbSThomas Zimmermann pll_locked = true; 159877507bbSThomas Zimmermann else 160877507bbSThomas Zimmermann udelay(5); 161877507bbSThomas Zimmermann } 162877507bbSThomas Zimmermann } 163877507bbSThomas Zimmermann } 164877507bbSThomas Zimmermann 165877507bbSThomas Zimmermann /* 166*bc835040SThomas Zimmermann * Mode-setting pipeline 167*bc835040SThomas Zimmermann */ 168*bc835040SThomas Zimmermann 169*bc835040SThomas Zimmermann static const struct drm_plane_helper_funcs mgag200_g200eh_primary_plane_helper_funcs = { 170*bc835040SThomas Zimmermann MGAG200_PRIMARY_PLANE_HELPER_FUNCS, 171*bc835040SThomas Zimmermann }; 172*bc835040SThomas Zimmermann 173*bc835040SThomas Zimmermann static const struct drm_plane_funcs mgag200_g200eh_primary_plane_funcs = { 174*bc835040SThomas Zimmermann MGAG200_PRIMARY_PLANE_FUNCS, 175*bc835040SThomas Zimmermann }; 176*bc835040SThomas Zimmermann 177*bc835040SThomas Zimmermann static const struct drm_crtc_helper_funcs mgag200_g200eh_crtc_helper_funcs = { 178*bc835040SThomas Zimmermann MGAG200_CRTC_HELPER_FUNCS, 179*bc835040SThomas Zimmermann }; 180*bc835040SThomas Zimmermann 181*bc835040SThomas Zimmermann static const struct drm_crtc_funcs mgag200_g200eh_crtc_funcs = { 182*bc835040SThomas Zimmermann MGAG200_CRTC_FUNCS, 183*bc835040SThomas Zimmermann }; 184*bc835040SThomas Zimmermann 185*bc835040SThomas Zimmermann static const struct drm_encoder_funcs mgag200_g200eh_dac_encoder_funcs = { 186*bc835040SThomas Zimmermann MGAG200_DAC_ENCODER_FUNCS, 187*bc835040SThomas Zimmermann }; 188*bc835040SThomas Zimmermann 189*bc835040SThomas Zimmermann static const struct drm_connector_helper_funcs mgag200_g200eh_vga_connector_helper_funcs = { 190*bc835040SThomas Zimmermann MGAG200_VGA_CONNECTOR_HELPER_FUNCS, 191*bc835040SThomas Zimmermann }; 192*bc835040SThomas Zimmermann 193*bc835040SThomas Zimmermann static const struct drm_connector_funcs mgag200_g200eh_vga_connector_funcs = { 194*bc835040SThomas Zimmermann MGAG200_VGA_CONNECTOR_FUNCS, 195*bc835040SThomas Zimmermann }; 196*bc835040SThomas Zimmermann 197*bc835040SThomas Zimmermann static int mgag200_g200eh_pipeline_init(struct mga_device *mdev) 198*bc835040SThomas Zimmermann { 199*bc835040SThomas Zimmermann struct drm_device *dev = &mdev->base; 200*bc835040SThomas Zimmermann struct drm_plane *primary_plane = &mdev->primary_plane; 201*bc835040SThomas Zimmermann struct drm_crtc *crtc = &mdev->crtc; 202*bc835040SThomas Zimmermann struct drm_encoder *encoder = &mdev->encoder; 203*bc835040SThomas Zimmermann struct mga_i2c_chan *i2c = &mdev->i2c; 204*bc835040SThomas Zimmermann struct drm_connector *connector = &mdev->connector; 205*bc835040SThomas Zimmermann int ret; 206*bc835040SThomas Zimmermann 207*bc835040SThomas Zimmermann ret = drm_universal_plane_init(dev, primary_plane, 0, 208*bc835040SThomas Zimmermann &mgag200_g200eh_primary_plane_funcs, 209*bc835040SThomas Zimmermann mgag200_primary_plane_formats, 210*bc835040SThomas Zimmermann mgag200_primary_plane_formats_size, 211*bc835040SThomas Zimmermann mgag200_primary_plane_fmtmods, 212*bc835040SThomas Zimmermann DRM_PLANE_TYPE_PRIMARY, NULL); 213*bc835040SThomas Zimmermann if (ret) { 214*bc835040SThomas Zimmermann drm_err(dev, "drm_universal_plane_init() failed: %d\n", ret); 215*bc835040SThomas Zimmermann return ret; 216*bc835040SThomas Zimmermann } 217*bc835040SThomas Zimmermann drm_plane_helper_add(primary_plane, &mgag200_g200eh_primary_plane_helper_funcs); 218*bc835040SThomas Zimmermann drm_plane_enable_fb_damage_clips(primary_plane); 219*bc835040SThomas Zimmermann 220*bc835040SThomas Zimmermann ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL, 221*bc835040SThomas Zimmermann &mgag200_g200eh_crtc_funcs, NULL); 222*bc835040SThomas Zimmermann if (ret) { 223*bc835040SThomas Zimmermann drm_err(dev, "drm_crtc_init_with_planes() failed: %d\n", ret); 224*bc835040SThomas Zimmermann return ret; 225*bc835040SThomas Zimmermann } 226*bc835040SThomas Zimmermann drm_crtc_helper_add(crtc, &mgag200_g200eh_crtc_helper_funcs); 227*bc835040SThomas Zimmermann 228*bc835040SThomas Zimmermann /* FIXME: legacy gamma tables, but atomic gamma doesn't work without */ 229*bc835040SThomas Zimmermann drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE); 230*bc835040SThomas Zimmermann drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE); 231*bc835040SThomas Zimmermann 232*bc835040SThomas Zimmermann encoder->possible_crtcs = drm_crtc_mask(crtc); 233*bc835040SThomas Zimmermann ret = drm_encoder_init(dev, encoder, &mgag200_g200eh_dac_encoder_funcs, 234*bc835040SThomas Zimmermann DRM_MODE_ENCODER_DAC, NULL); 235*bc835040SThomas Zimmermann if (ret) { 236*bc835040SThomas Zimmermann drm_err(dev, "drm_encoder_init() failed: %d\n", ret); 237*bc835040SThomas Zimmermann return ret; 238*bc835040SThomas Zimmermann } 239*bc835040SThomas Zimmermann 240*bc835040SThomas Zimmermann ret = mgag200_i2c_init(mdev, i2c); 241*bc835040SThomas Zimmermann if (ret) { 242*bc835040SThomas Zimmermann drm_err(dev, "failed to add DDC bus: %d\n", ret); 243*bc835040SThomas Zimmermann return ret; 244*bc835040SThomas Zimmermann } 245*bc835040SThomas Zimmermann 246*bc835040SThomas Zimmermann ret = drm_connector_init_with_ddc(dev, connector, 247*bc835040SThomas Zimmermann &mgag200_g200eh_vga_connector_funcs, 248*bc835040SThomas Zimmermann DRM_MODE_CONNECTOR_VGA, 249*bc835040SThomas Zimmermann &i2c->adapter); 250*bc835040SThomas Zimmermann if (ret) { 251*bc835040SThomas Zimmermann drm_err(dev, "drm_connector_init_with_ddc() failed: %d\n", ret); 252*bc835040SThomas Zimmermann return ret; 253*bc835040SThomas Zimmermann } 254*bc835040SThomas Zimmermann drm_connector_helper_add(connector, &mgag200_g200eh_vga_connector_helper_funcs); 255*bc835040SThomas Zimmermann 256*bc835040SThomas Zimmermann ret = drm_connector_attach_encoder(connector, encoder); 257*bc835040SThomas Zimmermann if (ret) { 258*bc835040SThomas Zimmermann drm_err(dev, "drm_connector_attach_encoder() failed: %d\n", ret); 259*bc835040SThomas Zimmermann return ret; 260*bc835040SThomas Zimmermann } 261*bc835040SThomas Zimmermann 262*bc835040SThomas Zimmermann return 0; 263*bc835040SThomas Zimmermann } 264*bc835040SThomas Zimmermann 265*bc835040SThomas Zimmermann /* 26685397f6bSThomas Zimmermann * DRM device 26785397f6bSThomas Zimmermann */ 26885397f6bSThomas Zimmermann 269b9a577a4SThomas Zimmermann static const struct mgag200_device_info mgag200_g200eh_device_info = 270da1efdb2SThomas Zimmermann MGAG200_DEVICE_INFO_INIT(2048, 2048, 37500, false, 1, 0, false); 271b9a577a4SThomas Zimmermann 272f639f74aSThomas Zimmermann static const struct mgag200_device_funcs mgag200_g200eh_device_funcs = { 273877507bbSThomas Zimmermann .pixpllc_atomic_check = mgag200_g200eh_pixpllc_atomic_check, 274877507bbSThomas Zimmermann .pixpllc_atomic_update = mgag200_g200eh_pixpllc_atomic_update, 275f639f74aSThomas Zimmermann }; 276f639f74aSThomas Zimmermann 27785397f6bSThomas Zimmermann struct mga_device *mgag200_g200eh_device_create(struct pci_dev *pdev, const struct drm_driver *drv, 27821e74bf9SThomas Zimmermann enum mga_type type) 27985397f6bSThomas Zimmermann { 28085397f6bSThomas Zimmermann struct mga_device *mdev; 28185397f6bSThomas Zimmermann struct drm_device *dev; 282d45e32c9SThomas Zimmermann resource_size_t vram_available; 28385397f6bSThomas Zimmermann int ret; 28485397f6bSThomas Zimmermann 28585397f6bSThomas Zimmermann mdev = devm_drm_dev_alloc(&pdev->dev, drv, struct mga_device, base); 28685397f6bSThomas Zimmermann if (IS_ERR(mdev)) 28785397f6bSThomas Zimmermann return mdev; 28885397f6bSThomas Zimmermann dev = &mdev->base; 28985397f6bSThomas Zimmermann 29085397f6bSThomas Zimmermann pci_set_drvdata(pdev, dev); 29185397f6bSThomas Zimmermann 292ce19021fSThomas Zimmermann ret = mgag200_init_pci_options(pdev, 0x00000120, 0x0000b000); 293ce19021fSThomas Zimmermann if (ret) 294ce19021fSThomas Zimmermann return ERR_PTR(ret); 295ce19021fSThomas Zimmermann 296b62d943eSThomas Zimmermann ret = mgag200_device_preinit(mdev); 29785397f6bSThomas Zimmermann if (ret) 29885397f6bSThomas Zimmermann return ERR_PTR(ret); 29985397f6bSThomas Zimmermann 300f639f74aSThomas Zimmermann ret = mgag200_device_init(mdev, type, &mgag200_g200eh_device_info, 301f639f74aSThomas Zimmermann &mgag200_g200eh_device_funcs); 30285397f6bSThomas Zimmermann if (ret) 30385397f6bSThomas Zimmermann return ERR_PTR(ret); 30485397f6bSThomas Zimmermann 3051ee181feSThomas Zimmermann mgag200_g200eh_init_registers(mdev); 3061ee181feSThomas Zimmermann 307d45e32c9SThomas Zimmermann vram_available = mgag200_device_probe_vram(mdev); 308d45e32c9SThomas Zimmermann 309*bc835040SThomas Zimmermann ret = mgag200_mode_config_init(mdev, vram_available); 31085397f6bSThomas Zimmermann if (ret) 31185397f6bSThomas Zimmermann return ERR_PTR(ret); 31285397f6bSThomas Zimmermann 313*bc835040SThomas Zimmermann ret = mgag200_g200eh_pipeline_init(mdev); 314*bc835040SThomas Zimmermann if (ret) 315*bc835040SThomas Zimmermann return ERR_PTR(ret); 316*bc835040SThomas Zimmermann 317*bc835040SThomas Zimmermann drm_mode_config_reset(dev); 318*bc835040SThomas Zimmermann 31985397f6bSThomas Zimmermann return mdev; 32085397f6bSThomas Zimmermann } 321