318 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2 3#include <linux/delay.h>4#include <linux/pci.h>5 6#include <drm/drm_atomic.h>7#include <drm/drm_atomic_helper.h>8#include <drm/drm_drv.h>9#include <drm/drm_gem_atomic_helper.h>10#include <drm/drm_probe_helper.h>11 12#include "mgag200_drv.h"13 14static void mgag200_g200ev_init_registers(struct mga_device *mdev)15{16 static const u8 dacvalue[] = {17 MGAG200_DAC_DEFAULT(0x00,18 MGA1064_PIX_CLK_CTL_SEL_PLL,19 MGA1064_MISC_CTL_VGA8 | MGA1064_MISC_CTL_DAC_RAM_CS,20 0x00, 0x00, 0x00)21 };22 23 size_t i;24 25 for (i = 0; i < ARRAY_SIZE(dacvalue); i++) {26 if ((i <= 0x17) ||27 (i == 0x1b) ||28 (i == 0x1c) ||29 ((i >= 0x1f) && (i <= 0x29)) ||30 ((i >= 0x30) && (i <= 0x37)) ||31 ((i >= 0x44) && (i <= 0x4e)))32 continue;33 WREG_DAC(i, dacvalue[i]);34 }35 36 mgag200_init_registers(mdev);37}38 39static void mgag200_g200ev_set_hiprilvl(struct mga_device *mdev)40{41 WREG_ECRT(0x06, 0x00);42}43 44/*45 * PIXPLLC46 */47 48static int mgag200_g200ev_pixpllc_atomic_check(struct drm_crtc *crtc,49 struct drm_atomic_state *new_state)50{51 static const unsigned int vcomax = 550000;52 static const unsigned int vcomin = 150000;53 static const unsigned int pllreffreq = 50000;54 55 struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);56 struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);57 long clock = new_crtc_state->mode.clock;58 struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc;59 unsigned int delta, tmpdelta;60 unsigned int testp, testm, testn;61 unsigned int p, m, n, s;62 unsigned int computed;63 64 m = n = p = s = 0;65 delta = 0xffffffff;66 67 for (testp = 16; testp > 0; testp--) {68 if (clock * testp > vcomax)69 continue;70 if (clock * testp < vcomin)71 continue;72 73 for (testn = 1; testn < 257; testn++) {74 for (testm = 1; testm < 17; testm++) {75 computed = (pllreffreq * testn) /76 (testm * testp);77 if (computed > clock)78 tmpdelta = computed - clock;79 else80 tmpdelta = clock - computed;81 if (tmpdelta < delta) {82 delta = tmpdelta;83 n = testn;84 m = testm;85 p = testp;86 }87 }88 }89 }90 91 pixpllc->m = m;92 pixpllc->n = n;93 pixpllc->p = p;94 pixpllc->s = s;95 96 return 0;97}98 99static void mgag200_g200ev_pixpllc_atomic_update(struct drm_crtc *crtc,100 struct drm_atomic_state *old_state)101{102 struct drm_device *dev = crtc->dev;103 struct mga_device *mdev = to_mga_device(dev);104 struct drm_crtc_state *crtc_state = crtc->state;105 struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);106 struct mgag200_pll_values *pixpllc = &mgag200_crtc_state->pixpllc;107 unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;108 u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp;109 110 pixpllcm = pixpllc->m - 1;111 pixpllcn = pixpllc->n - 1;112 pixpllcp = pixpllc->p - 1;113 pixpllcs = pixpllc->s;114 115 xpixpllcm = pixpllcm;116 xpixpllcn = pixpllcn;117 xpixpllcp = (pixpllcs << 3) | pixpllcp;118 119 WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);120 121 WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);122 tmp = RREG8(DAC_DATA);123 tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS;124 WREG8(DAC_DATA, tmp);125 126 tmp = RREG8(MGAREG_MEM_MISC_READ);127 tmp |= 0x3 << 2;128 WREG8(MGAREG_MEM_MISC_WRITE, tmp);129 130 WREG8(DAC_INDEX, MGA1064_PIX_PLL_STAT);131 tmp = RREG8(DAC_DATA);132 WREG8(DAC_DATA, tmp & ~0x40);133 134 WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);135 tmp = RREG8(DAC_DATA);136 tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;137 WREG8(DAC_DATA, tmp);138 139 WREG_DAC(MGA1064_EV_PIX_PLLC_M, xpixpllcm);140 WREG_DAC(MGA1064_EV_PIX_PLLC_N, xpixpllcn);141 WREG_DAC(MGA1064_EV_PIX_PLLC_P, xpixpllcp);142 143 udelay(50);144 145 WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);146 tmp = RREG8(DAC_DATA);147 tmp &= ~MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;148 WREG8(DAC_DATA, tmp);149 150 udelay(500);151 152 WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);153 tmp = RREG8(DAC_DATA);154 tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK;155 tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL;156 WREG8(DAC_DATA, tmp);157 158 WREG8(DAC_INDEX, MGA1064_PIX_PLL_STAT);159 tmp = RREG8(DAC_DATA);160 WREG8(DAC_DATA, tmp | 0x40);161 162 tmp = RREG8(MGAREG_MEM_MISC_READ);163 tmp |= (0x3 << 2);164 WREG8(MGAREG_MEM_MISC_WRITE, tmp);165 166 WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);167 tmp = RREG8(DAC_DATA);168 tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS;169 WREG8(DAC_DATA, tmp);170}171 172/*173 * Mode-setting pipeline174 */175 176static const struct drm_plane_helper_funcs mgag200_g200ev_primary_plane_helper_funcs = {177 MGAG200_PRIMARY_PLANE_HELPER_FUNCS,178};179 180static const struct drm_plane_funcs mgag200_g200ev_primary_plane_funcs = {181 MGAG200_PRIMARY_PLANE_FUNCS,182};183 184static void mgag200_g200ev_crtc_helper_atomic_enable(struct drm_crtc *crtc,185 struct drm_atomic_state *old_state)186{187 struct drm_device *dev = crtc->dev;188 struct mga_device *mdev = to_mga_device(dev);189 const struct mgag200_device_funcs *funcs = mdev->funcs;190 struct drm_crtc_state *crtc_state = crtc->state;191 struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;192 struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);193 const struct drm_format_info *format = mgag200_crtc_state->format;194 195 mgag200_set_format_regs(mdev, format);196 mgag200_set_mode_regs(mdev, adjusted_mode, mgag200_crtc_state->set_vidrst);197 198 if (funcs->pixpllc_atomic_update)199 funcs->pixpllc_atomic_update(crtc, old_state);200 201 mgag200_g200ev_set_hiprilvl(mdev);202 203 if (crtc_state->gamma_lut)204 mgag200_crtc_set_gamma(mdev, format, crtc_state->gamma_lut->data);205 else206 mgag200_crtc_set_gamma_linear(mdev, format);207 208 mgag200_enable_display(mdev);209}210 211static const struct drm_crtc_helper_funcs mgag200_g200ev_crtc_helper_funcs = {212 .mode_valid = mgag200_crtc_helper_mode_valid,213 .atomic_check = mgag200_crtc_helper_atomic_check,214 .atomic_flush = mgag200_crtc_helper_atomic_flush,215 .atomic_enable = mgag200_g200ev_crtc_helper_atomic_enable,216 .atomic_disable = mgag200_crtc_helper_atomic_disable217};218 219static const struct drm_crtc_funcs mgag200_g200ev_crtc_funcs = {220 MGAG200_CRTC_FUNCS,221};222 223static int mgag200_g200ev_pipeline_init(struct mga_device *mdev)224{225 struct drm_device *dev = &mdev->base;226 struct drm_plane *primary_plane = &mdev->primary_plane;227 struct drm_crtc *crtc = &mdev->crtc;228 int ret;229 230 ret = drm_universal_plane_init(dev, primary_plane, 0,231 &mgag200_g200ev_primary_plane_funcs,232 mgag200_primary_plane_formats,233 mgag200_primary_plane_formats_size,234 mgag200_primary_plane_fmtmods,235 DRM_PLANE_TYPE_PRIMARY, NULL);236 if (ret) {237 drm_err(dev, "drm_universal_plane_init() failed: %d\n", ret);238 return ret;239 }240 drm_plane_helper_add(primary_plane, &mgag200_g200ev_primary_plane_helper_funcs);241 drm_plane_enable_fb_damage_clips(primary_plane);242 243 ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL,244 &mgag200_g200ev_crtc_funcs, NULL);245 if (ret) {246 drm_err(dev, "drm_crtc_init_with_planes() failed: %d\n", ret);247 return ret;248 }249 drm_crtc_helper_add(crtc, &mgag200_g200ev_crtc_helper_funcs);250 251 /* FIXME: legacy gamma tables, but atomic gamma doesn't work without */252 drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE);253 drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE);254 255 ret = mgag200_vga_bmc_output_init(mdev);256 if (ret)257 return ret;258 259 return 0;260}261 262/*263 * DRM device264 */265 266static const struct mgag200_device_info mgag200_g200ev_device_info =267 MGAG200_DEVICE_INFO_INIT(2048, 2048, 32700, false, 0, 1, false);268 269static const struct mgag200_device_funcs mgag200_g200ev_device_funcs = {270 .pixpllc_atomic_check = mgag200_g200ev_pixpllc_atomic_check,271 .pixpllc_atomic_update = mgag200_g200ev_pixpllc_atomic_update,272};273 274struct mga_device *mgag200_g200ev_device_create(struct pci_dev *pdev, const struct drm_driver *drv)275{276 struct mga_device *mdev;277 struct drm_device *dev;278 resource_size_t vram_available;279 int ret;280 281 mdev = devm_drm_dev_alloc(&pdev->dev, drv, struct mga_device, base);282 if (IS_ERR(mdev))283 return mdev;284 dev = &mdev->base;285 286 pci_set_drvdata(pdev, dev);287 288 ret = mgag200_init_pci_options(pdev, 0x00000120, 0x0000b000);289 if (ret)290 return ERR_PTR(ret);291 292 ret = mgag200_device_preinit(mdev);293 if (ret)294 return ERR_PTR(ret);295 296 ret = mgag200_device_init(mdev, &mgag200_g200ev_device_info,297 &mgag200_g200ev_device_funcs);298 if (ret)299 return ERR_PTR(ret);300 301 mgag200_g200ev_init_registers(mdev);302 303 vram_available = mgag200_device_probe_vram(mdev);304 305 ret = mgag200_mode_config_init(mdev, vram_available);306 if (ret)307 return ERR_PTR(ret);308 309 ret = mgag200_g200ev_pipeline_init(mdev);310 if (ret)311 return ERR_PTR(ret);312 313 drm_mode_config_reset(dev);314 drm_kms_helper_poll_init(dev);315 316 return mdev;317}318