313 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_g200er_init_registers(struct mga_device *mdev)15{16 static const u8 dacvalue[] = {17 MGAG200_DAC_DEFAULT(0x00, 0xc9, 0x1f, 0x00, 0x00, 0x00)18 };19 20 size_t i;21 22 for (i = 0; i < ARRAY_SIZE(dacvalue); i++) {23 if ((i <= 0x17) ||24 (i == 0x1b) ||25 (i == 0x1c) ||26 ((i >= 0x1f) && (i <= 0x29)) ||27 ((i >= 0x30) && (i <= 0x37)))28 continue;29 WREG_DAC(i, dacvalue[i]);30 }31 32 WREG_DAC(0x90, 0); /* G200ER specific */33 34 mgag200_init_registers(mdev);35 36 WREG_ECRT(0x24, 0x5); /* G200ER specific */37}38 39static void mgag200_g200er_reset_tagfifo(struct mga_device *mdev)40{41 static const uint32_t RESET_FLAG = 0x00200000; /* undocumented magic value */42 u32 memctl;43 44 memctl = RREG32(MGAREG_MEMCTL);45 46 memctl |= RESET_FLAG;47 WREG32(MGAREG_MEMCTL, memctl);48 49 udelay(1000);50 51 memctl &= ~RESET_FLAG;52 WREG32(MGAREG_MEMCTL, memctl);53}54 55/*56 * PIXPLLC57 */58 59static int mgag200_g200er_pixpllc_atomic_check(struct drm_crtc *crtc,60 struct drm_atomic_state *new_state)61{62 static const unsigned int vcomax = 1488000;63 static const unsigned int vcomin = 1056000;64 static const unsigned int pllreffreq = 48000;65 static const unsigned int m_div_val[] = { 1, 2, 4, 8 };66 67 struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);68 struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);69 long clock = new_crtc_state->mode.clock;70 struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc;71 unsigned int delta, tmpdelta;72 int testr, testn, testm, testo;73 unsigned int p, m, n, s;74 unsigned int computed, vco;75 76 m = n = p = s = 0;77 delta = 0xffffffff;78 79 for (testr = 0; testr < 4; testr++) {80 if (delta == 0)81 break;82 for (testn = 5; testn < 129; testn++) {83 if (delta == 0)84 break;85 for (testm = 3; testm >= 0; testm--) {86 if (delta == 0)87 break;88 for (testo = 5; testo < 33; testo++) {89 vco = pllreffreq * (testn + 1) /90 (testr + 1);91 if (vco < vcomin)92 continue;93 if (vco > vcomax)94 continue;95 computed = vco / (m_div_val[testm] * (testo + 1));96 if (computed > clock)97 tmpdelta = computed - clock;98 else99 tmpdelta = clock - computed;100 if (tmpdelta < delta) {101 delta = tmpdelta;102 m = (testm | (testo << 3)) + 1;103 n = testn + 1;104 p = testr + 1;105 s = testr;106 }107 }108 }109 }110 }111 112 pixpllc->m = m;113 pixpllc->n = n;114 pixpllc->p = p;115 pixpllc->s = s;116 117 return 0;118}119 120static void mgag200_g200er_pixpllc_atomic_update(struct drm_crtc *crtc,121 struct drm_atomic_state *old_state)122{123 struct drm_device *dev = crtc->dev;124 struct mga_device *mdev = to_mga_device(dev);125 struct drm_crtc_state *crtc_state = crtc->state;126 struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);127 struct mgag200_pll_values *pixpllc = &mgag200_crtc_state->pixpllc;128 unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;129 u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp;130 131 pixpllcm = pixpllc->m - 1;132 pixpllcn = pixpllc->n - 1;133 pixpllcp = pixpllc->p - 1;134 pixpllcs = pixpllc->s;135 136 xpixpllcm = pixpllcm;137 xpixpllcn = pixpllcn;138 xpixpllcp = (pixpllcs << 3) | pixpllcp;139 140 WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);141 142 WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);143 tmp = RREG8(DAC_DATA);144 tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS;145 WREG8(DAC_DATA, tmp);146 147 WREG8(DAC_INDEX, MGA1064_REMHEADCTL);148 tmp = RREG8(DAC_DATA);149 tmp |= MGA1064_REMHEADCTL_CLKDIS;150 WREG8(DAC_DATA, tmp);151 152 tmp = RREG8(MGAREG_MEM_MISC_READ);153 tmp |= (0x3<<2) | 0xc0;154 WREG8(MGAREG_MEM_MISC_WRITE, tmp);155 156 WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);157 tmp = RREG8(DAC_DATA);158 tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS;159 tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;160 WREG8(DAC_DATA, tmp);161 162 udelay(500);163 164 WREG_DAC(MGA1064_ER_PIX_PLLC_N, xpixpllcn);165 WREG_DAC(MGA1064_ER_PIX_PLLC_M, xpixpllcm);166 WREG_DAC(MGA1064_ER_PIX_PLLC_P, xpixpllcp);167 168 udelay(50);169}170 171/*172 * Mode-setting pipeline173 */174 175static const struct drm_plane_helper_funcs mgag200_g200er_primary_plane_helper_funcs = {176 MGAG200_PRIMARY_PLANE_HELPER_FUNCS,177};178 179static const struct drm_plane_funcs mgag200_g200er_primary_plane_funcs = {180 MGAG200_PRIMARY_PLANE_FUNCS,181};182 183static void mgag200_g200er_crtc_helper_atomic_enable(struct drm_crtc *crtc,184 struct drm_atomic_state *old_state)185{186 struct drm_device *dev = crtc->dev;187 struct mga_device *mdev = to_mga_device(dev);188 const struct mgag200_device_funcs *funcs = mdev->funcs;189 struct drm_crtc_state *crtc_state = crtc->state;190 struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;191 struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);192 const struct drm_format_info *format = mgag200_crtc_state->format;193 194 mgag200_set_format_regs(mdev, format);195 mgag200_set_mode_regs(mdev, adjusted_mode, mgag200_crtc_state->set_vidrst);196 197 if (funcs->pixpllc_atomic_update)198 funcs->pixpllc_atomic_update(crtc, old_state);199 200 mgag200_g200er_reset_tagfifo(mdev);201 202 if (crtc_state->gamma_lut)203 mgag200_crtc_set_gamma(mdev, format, crtc_state->gamma_lut->data);204 else205 mgag200_crtc_set_gamma_linear(mdev, format);206 207 mgag200_enable_display(mdev);208}209 210static const struct drm_crtc_helper_funcs mgag200_g200er_crtc_helper_funcs = {211 .mode_valid = mgag200_crtc_helper_mode_valid,212 .atomic_check = mgag200_crtc_helper_atomic_check,213 .atomic_flush = mgag200_crtc_helper_atomic_flush,214 .atomic_enable = mgag200_g200er_crtc_helper_atomic_enable,215 .atomic_disable = mgag200_crtc_helper_atomic_disable216};217 218static const struct drm_crtc_funcs mgag200_g200er_crtc_funcs = {219 MGAG200_CRTC_FUNCS,220};221 222static int mgag200_g200er_pipeline_init(struct mga_device *mdev)223{224 struct drm_device *dev = &mdev->base;225 struct drm_plane *primary_plane = &mdev->primary_plane;226 struct drm_crtc *crtc = &mdev->crtc;227 int ret;228 229 ret = drm_universal_plane_init(dev, primary_plane, 0,230 &mgag200_g200er_primary_plane_funcs,231 mgag200_primary_plane_formats,232 mgag200_primary_plane_formats_size,233 mgag200_primary_plane_fmtmods,234 DRM_PLANE_TYPE_PRIMARY, NULL);235 if (ret) {236 drm_err(dev, "drm_universal_plane_init() failed: %d\n", ret);237 return ret;238 }239 drm_plane_helper_add(primary_plane, &mgag200_g200er_primary_plane_helper_funcs);240 drm_plane_enable_fb_damage_clips(primary_plane);241 242 ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL,243 &mgag200_g200er_crtc_funcs, NULL);244 if (ret) {245 drm_err(dev, "drm_crtc_init_with_planes() failed: %d\n", ret);246 return ret;247 }248 drm_crtc_helper_add(crtc, &mgag200_g200er_crtc_helper_funcs);249 250 /* FIXME: legacy gamma tables, but atomic gamma doesn't work without */251 drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE);252 drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE);253 254 ret = mgag200_vga_bmc_output_init(mdev);255 if (ret)256 return ret;257 258 return 0;259}260 261/*262 * DRM device263 */264 265static const struct mgag200_device_info mgag200_g200er_device_info =266 MGAG200_DEVICE_INFO_INIT(2048, 2048, 55000, false, 1, 0, false);267 268static const struct mgag200_device_funcs mgag200_g200er_device_funcs = {269 .pixpllc_atomic_check = mgag200_g200er_pixpllc_atomic_check,270 .pixpllc_atomic_update = mgag200_g200er_pixpllc_atomic_update,271};272 273struct mga_device *mgag200_g200er_device_create(struct pci_dev *pdev, const struct drm_driver *drv)274{275 struct mga_device *mdev;276 struct drm_device *dev;277 resource_size_t vram_available;278 int ret;279 280 mdev = devm_drm_dev_alloc(&pdev->dev, drv, struct mga_device, base);281 if (IS_ERR(mdev))282 return mdev;283 dev = &mdev->base;284 285 pci_set_drvdata(pdev, dev);286 287 ret = mgag200_device_preinit(mdev);288 if (ret)289 return ERR_PTR(ret);290 291 ret = mgag200_device_init(mdev, &mgag200_g200er_device_info,292 &mgag200_g200er_device_funcs);293 if (ret)294 return ERR_PTR(ret);295 296 mgag200_g200er_init_registers(mdev);297 298 vram_available = mgag200_device_probe_vram(mdev);299 300 ret = mgag200_mode_config_init(mdev, vram_available);301 if (ret)302 return ERR_PTR(ret);303 304 ret = mgag200_g200er_pipeline_init(mdev);305 if (ret)306 return ERR_PTR(ret);307 308 drm_mode_config_reset(dev);309 drm_kms_helper_poll_init(dev);310 311 return mdev;312}313