518 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 int mgag200_g200se_init_pci_options(struct pci_dev *pdev)15{16 struct device *dev = &pdev->dev;17 bool has_sgram;18 u32 option;19 int err;20 21 err = pci_read_config_dword(pdev, PCI_MGA_OPTION, &option);22 if (err != PCIBIOS_SUCCESSFUL) {23 dev_err(dev, "pci_read_config_dword(PCI_MGA_OPTION) failed: %d\n", err);24 return pcibios_err_to_errno(err);25 }26 27 has_sgram = !!(option & PCI_MGA_OPTION_HARDPWMSK);28 29 option = 0x40049120;30 if (has_sgram)31 option |= PCI_MGA_OPTION_HARDPWMSK;32 33 return mgag200_init_pci_options(pdev, option, 0x00008000);34}35 36static void mgag200_g200se_init_registers(struct mgag200_g200se_device *g200se)37{38 static const u8 dacvalue[] = {39 MGAG200_DAC_DEFAULT(0x03,40 MGA1064_PIX_CLK_CTL_SEL_PLL,41 MGA1064_MISC_CTL_DAC_EN |42 MGA1064_MISC_CTL_VGA8 |43 MGA1064_MISC_CTL_DAC_RAM_CS,44 0x00, 0x00, 0x00)45 };46 47 struct mga_device *mdev = &g200se->base;48 size_t i;49 50 for (i = 0; i < ARRAY_SIZE(dacvalue); i++) {51 if ((i <= 0x17) ||52 (i == 0x1b) ||53 (i == 0x1c) ||54 ((i >= 0x1f) && (i <= 0x29)) ||55 ((i == 0x2c) || (i == 0x2d) || (i == 0x2e)) ||56 ((i >= 0x30) && (i <= 0x37)))57 continue;58 WREG_DAC(i, dacvalue[i]);59 }60 61 mgag200_init_registers(mdev);62}63 64static void mgag200_g200se_set_hiprilvl(struct mga_device *mdev,65 const struct drm_display_mode *mode,66 const struct drm_format_info *format)67{68 struct mgag200_g200se_device *g200se = to_mgag200_g200se_device(&mdev->base);69 unsigned int hiprilvl;70 u8 crtcext6;71 72 if (g200se->unique_rev_id >= 0x04) {73 hiprilvl = 0;74 } else if (g200se->unique_rev_id >= 0x02) {75 unsigned int bpp;76 unsigned long mb;77 78 if (format->cpp[0] * 8 > 16)79 bpp = 32;80 else if (format->cpp[0] * 8 > 8)81 bpp = 16;82 else83 bpp = 8;84 85 mb = (mode->clock * bpp) / 1000;86 if (mb > 3100)87 hiprilvl = 0;88 else if (mb > 2600)89 hiprilvl = 1;90 else if (mb > 1900)91 hiprilvl = 2;92 else if (mb > 1160)93 hiprilvl = 3;94 else if (mb > 440)95 hiprilvl = 4;96 else97 hiprilvl = 5;98 99 } else if (g200se->unique_rev_id >= 0x01) {100 hiprilvl = 3;101 } else {102 hiprilvl = 4;103 }104 105 crtcext6 = hiprilvl; /* implicitly sets maxhipri to 0 */106 107 WREG_ECRT(0x06, crtcext6);108}109 110/*111 * PIXPLLC112 */113 114static int mgag200_g200se_00_pixpllc_atomic_check(struct drm_crtc *crtc,115 struct drm_atomic_state *new_state)116{117 static const unsigned int vcomax = 320000;118 static const unsigned int vcomin = 160000;119 static const unsigned int pllreffreq = 25000;120 121 struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);122 struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);123 long clock = new_crtc_state->mode.clock;124 struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc;125 unsigned int delta, tmpdelta, permitteddelta;126 unsigned int testp, testm, testn;127 unsigned int p, m, n, s;128 unsigned int computed;129 130 m = n = p = s = 0;131 delta = 0xffffffff;132 permitteddelta = clock * 5 / 1000;133 134 for (testp = 8; testp > 0; testp /= 2) {135 if (clock * testp > vcomax)136 continue;137 if (clock * testp < vcomin)138 continue;139 140 for (testn = 17; testn < 256; testn++) {141 for (testm = 1; testm < 32; testm++) {142 computed = (pllreffreq * testn) / (testm * testp);143 if (computed > clock)144 tmpdelta = computed - clock;145 else146 tmpdelta = clock - computed;147 if (tmpdelta < delta) {148 delta = tmpdelta;149 m = testm;150 n = testn;151 p = testp;152 }153 }154 }155 }156 157 if (delta > permitteddelta) {158 pr_warn("PLL delta too large\n");159 return -EINVAL;160 }161 162 pixpllc->m = m;163 pixpllc->n = n;164 pixpllc->p = p;165 pixpllc->s = s;166 167 return 0;168}169 170static void mgag200_g200se_00_pixpllc_atomic_update(struct drm_crtc *crtc,171 struct drm_atomic_state *old_state)172{173 struct drm_device *dev = crtc->dev;174 struct mga_device *mdev = to_mga_device(dev);175 struct drm_crtc_state *crtc_state = crtc->state;176 struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);177 struct mgag200_pll_values *pixpllc = &mgag200_crtc_state->pixpllc;178 unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;179 u8 xpixpllcm, xpixpllcn, xpixpllcp;180 181 pixpllcm = pixpllc->m - 1;182 pixpllcn = pixpllc->n - 1;183 pixpllcp = pixpllc->p - 1;184 pixpllcs = pixpllc->s;185 186 xpixpllcm = pixpllcm | ((pixpllcn & BIT(8)) >> 1);187 xpixpllcn = pixpllcn;188 xpixpllcp = (pixpllcs << 3) | pixpllcp;189 190 WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);191 192 WREG_DAC(MGA1064_PIX_PLLC_M, xpixpllcm);193 WREG_DAC(MGA1064_PIX_PLLC_N, xpixpllcn);194 WREG_DAC(MGA1064_PIX_PLLC_P, xpixpllcp);195}196 197static int mgag200_g200se_04_pixpllc_atomic_check(struct drm_crtc *crtc,198 struct drm_atomic_state *new_state)199{200 static const unsigned int vcomax = 1600000;201 static const unsigned int vcomin = 800000;202 static const unsigned int pllreffreq = 25000;203 static const unsigned int pvalues_e4[] = {16, 14, 12, 10, 8, 6, 4, 2, 1};204 205 struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);206 struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);207 long clock = new_crtc_state->mode.clock;208 struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc;209 unsigned int delta, tmpdelta, permitteddelta;210 unsigned int testp, testm, testn;211 unsigned int p, m, n, s;212 unsigned int computed;213 unsigned int fvv;214 unsigned int i;215 216 m = n = p = s = 0;217 delta = 0xffffffff;218 219 if (clock < 25000)220 clock = 25000;221 clock = clock * 2;222 223 /* Permited delta is 0.5% as VESA Specification */224 permitteddelta = clock * 5 / 1000;225 226 for (i = 0 ; i < ARRAY_SIZE(pvalues_e4); i++) {227 testp = pvalues_e4[i];228 229 if ((clock * testp) > vcomax)230 continue;231 if ((clock * testp) < vcomin)232 continue;233 234 for (testn = 50; testn <= 256; testn++) {235 for (testm = 1; testm <= 32; testm++) {236 computed = (pllreffreq * testn) / (testm * testp);237 if (computed > clock)238 tmpdelta = computed - clock;239 else240 tmpdelta = clock - computed;241 242 if (tmpdelta < delta) {243 delta = tmpdelta;244 m = testm;245 n = testn;246 p = testp;247 }248 }249 }250 }251 252 fvv = pllreffreq * n / m;253 fvv = (fvv - 800000) / 50000;254 if (fvv > 15)255 fvv = 15;256 s = fvv << 1;257 258 if (delta > permitteddelta) {259 pr_warn("PLL delta too large\n");260 return -EINVAL;261 }262 263 pixpllc->m = m;264 pixpllc->n = n;265 pixpllc->p = p;266 pixpllc->s = s;267 268 return 0;269}270 271static void mgag200_g200se_04_pixpllc_atomic_update(struct drm_crtc *crtc,272 struct drm_atomic_state *old_state)273{274 struct drm_device *dev = crtc->dev;275 struct mga_device *mdev = to_mga_device(dev);276 struct drm_crtc_state *crtc_state = crtc->state;277 struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);278 struct mgag200_pll_values *pixpllc = &mgag200_crtc_state->pixpllc;279 unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;280 u8 xpixpllcm, xpixpllcn, xpixpllcp;281 282 pixpllcm = pixpllc->m - 1;283 pixpllcn = pixpllc->n - 1;284 pixpllcp = pixpllc->p - 1;285 pixpllcs = pixpllc->s;286 287 // For G200SE A, BIT(7) should be set unconditionally.288 xpixpllcm = BIT(7) | pixpllcm;289 xpixpllcn = pixpllcn;290 xpixpllcp = (pixpllcs << 3) | pixpllcp;291 292 WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);293 294 WREG_DAC(MGA1064_PIX_PLLC_M, xpixpllcm);295 WREG_DAC(MGA1064_PIX_PLLC_N, xpixpllcn);296 WREG_DAC(MGA1064_PIX_PLLC_P, xpixpllcp);297 298 WREG_DAC(0x1a, 0x09);299 msleep(20);300 WREG_DAC(0x1a, 0x01);301}302 303/*304 * Mode-setting pipeline305 */306 307static const struct drm_plane_helper_funcs mgag200_g200se_primary_plane_helper_funcs = {308 MGAG200_PRIMARY_PLANE_HELPER_FUNCS,309};310 311static const struct drm_plane_funcs mgag200_g200se_primary_plane_funcs = {312 MGAG200_PRIMARY_PLANE_FUNCS,313};314 315static void mgag200_g200se_crtc_helper_atomic_enable(struct drm_crtc *crtc,316 struct drm_atomic_state *old_state)317{318 struct drm_device *dev = crtc->dev;319 struct mga_device *mdev = to_mga_device(dev);320 const struct mgag200_device_funcs *funcs = mdev->funcs;321 struct drm_crtc_state *crtc_state = crtc->state;322 struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;323 struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);324 const struct drm_format_info *format = mgag200_crtc_state->format;325 326 mgag200_set_format_regs(mdev, format);327 mgag200_set_mode_regs(mdev, adjusted_mode, mgag200_crtc_state->set_vidrst);328 329 if (funcs->pixpllc_atomic_update)330 funcs->pixpllc_atomic_update(crtc, old_state);331 332 mgag200_g200se_set_hiprilvl(mdev, adjusted_mode, format);333 334 if (crtc_state->gamma_lut)335 mgag200_crtc_set_gamma(mdev, format, crtc_state->gamma_lut->data);336 else337 mgag200_crtc_set_gamma_linear(mdev, format);338 339 mgag200_enable_display(mdev);340}341 342static const struct drm_crtc_helper_funcs mgag200_g200se_crtc_helper_funcs = {343 .mode_valid = mgag200_crtc_helper_mode_valid,344 .atomic_check = mgag200_crtc_helper_atomic_check,345 .atomic_flush = mgag200_crtc_helper_atomic_flush,346 .atomic_enable = mgag200_g200se_crtc_helper_atomic_enable,347 .atomic_disable = mgag200_crtc_helper_atomic_disable348};349 350static const struct drm_crtc_funcs mgag200_g200se_crtc_funcs = {351 MGAG200_CRTC_FUNCS,352};353 354static int mgag200_g200se_pipeline_init(struct mga_device *mdev)355{356 struct drm_device *dev = &mdev->base;357 struct drm_plane *primary_plane = &mdev->primary_plane;358 struct drm_crtc *crtc = &mdev->crtc;359 int ret;360 361 ret = drm_universal_plane_init(dev, primary_plane, 0,362 &mgag200_g200se_primary_plane_funcs,363 mgag200_primary_plane_formats,364 mgag200_primary_plane_formats_size,365 mgag200_primary_plane_fmtmods,366 DRM_PLANE_TYPE_PRIMARY, NULL);367 if (ret) {368 drm_err(dev, "drm_universal_plane_init() failed: %d\n", ret);369 return ret;370 }371 drm_plane_helper_add(primary_plane, &mgag200_g200se_primary_plane_helper_funcs);372 drm_plane_enable_fb_damage_clips(primary_plane);373 374 ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL,375 &mgag200_g200se_crtc_funcs, NULL);376 if (ret) {377 drm_err(dev, "drm_crtc_init_with_planes() failed: %d\n", ret);378 return ret;379 }380 drm_crtc_helper_add(crtc, &mgag200_g200se_crtc_helper_funcs);381 382 /* FIXME: legacy gamma tables, but atomic gamma doesn't work without */383 drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE);384 drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE);385 386 ret = mgag200_vga_bmc_output_init(mdev);387 if (ret)388 return ret;389 390 return 0;391}392 393/*394 * DRM device395 */396 397static const struct mgag200_device_info mgag200_g200se_a_01_device_info =398 MGAG200_DEVICE_INFO_INIT(1600, 1200, 24400, false, 0, 1, true);399 400static const struct mgag200_device_info mgag200_g200se_a_02_device_info =401 MGAG200_DEVICE_INFO_INIT(1920, 1200, 30100, false, 0, 1, true);402 403static const struct mgag200_device_info mgag200_g200se_a_03_device_info =404 MGAG200_DEVICE_INFO_INIT(2048, 2048, 55000, false, 0, 1, false);405 406static const struct mgag200_device_info mgag200_g200se_b_01_device_info =407 MGAG200_DEVICE_INFO_INIT(1600, 1200, 24400, false, 0, 1, false);408 409static const struct mgag200_device_info mgag200_g200se_b_02_device_info =410 MGAG200_DEVICE_INFO_INIT(1920, 1200, 30100, false, 0, 1, false);411 412static const struct mgag200_device_info mgag200_g200se_b_03_device_info =413 MGAG200_DEVICE_INFO_INIT(2048, 2048, 55000, false, 0, 1, false);414 415static int mgag200_g200se_init_unique_rev_id(struct mgag200_g200se_device *g200se)416{417 struct mga_device *mdev = &g200se->base;418 struct drm_device *dev = &mdev->base;419 420 /* stash G200 SE model number for later use */421 g200se->unique_rev_id = RREG32(0x1e24);422 if (!g200se->unique_rev_id)423 return -ENODEV;424 425 drm_dbg(dev, "G200 SE unique revision id is 0x%x\n", g200se->unique_rev_id);426 427 return 0;428}429 430static const struct mgag200_device_funcs mgag200_g200se_00_device_funcs = {431 .pixpllc_atomic_check = mgag200_g200se_00_pixpllc_atomic_check,432 .pixpllc_atomic_update = mgag200_g200se_00_pixpllc_atomic_update,433};434 435static const struct mgag200_device_funcs mgag200_g200se_04_device_funcs = {436 .pixpllc_atomic_check = mgag200_g200se_04_pixpllc_atomic_check,437 .pixpllc_atomic_update = mgag200_g200se_04_pixpllc_atomic_update,438};439 440struct mga_device *mgag200_g200se_device_create(struct pci_dev *pdev, const struct drm_driver *drv,441 enum mga_type type)442{443 struct mgag200_g200se_device *g200se;444 const struct mgag200_device_info *info;445 const struct mgag200_device_funcs *funcs;446 struct mga_device *mdev;447 struct drm_device *dev;448 resource_size_t vram_available;449 int ret;450 451 g200se = devm_drm_dev_alloc(&pdev->dev, drv, struct mgag200_g200se_device, base.base);452 if (IS_ERR(g200se))453 return ERR_CAST(g200se);454 mdev = &g200se->base;455 dev = &mdev->base;456 457 pci_set_drvdata(pdev, dev);458 459 ret = mgag200_g200se_init_pci_options(pdev);460 if (ret)461 return ERR_PTR(ret);462 463 ret = mgag200_device_preinit(mdev);464 if (ret)465 return ERR_PTR(ret);466 467 ret = mgag200_g200se_init_unique_rev_id(g200se);468 if (ret)469 return ERR_PTR(ret);470 471 switch (type) {472 case G200_SE_A:473 if (g200se->unique_rev_id >= 0x03)474 info = &mgag200_g200se_a_03_device_info;475 else if (g200se->unique_rev_id >= 0x02)476 info = &mgag200_g200se_a_02_device_info;477 else478 info = &mgag200_g200se_a_01_device_info;479 break;480 case G200_SE_B:481 if (g200se->unique_rev_id >= 0x03)482 info = &mgag200_g200se_b_03_device_info;483 else if (g200se->unique_rev_id >= 0x02)484 info = &mgag200_g200se_b_02_device_info;485 else486 info = &mgag200_g200se_b_01_device_info;487 break;488 default:489 return ERR_PTR(-EINVAL);490 }491 492 if (g200se->unique_rev_id >= 0x04)493 funcs = &mgag200_g200se_04_device_funcs;494 else495 funcs = &mgag200_g200se_00_device_funcs;496 497 ret = mgag200_device_init(mdev, info, funcs);498 if (ret)499 return ERR_PTR(ret);500 501 mgag200_g200se_init_registers(g200se);502 503 vram_available = mgag200_device_probe_vram(mdev);504 505 ret = mgag200_mode_config_init(mdev, vram_available);506 if (ret)507 return ERR_PTR(ret);508 509 ret = mgag200_g200se_pipeline_init(mdev);510 if (ret)511 return ERR_PTR(ret);512 513 drm_mode_config_reset(dev);514 drm_kms_helper_poll_init(dev);515 516 return mdev;517}518