185397f6bSThomas Zimmermann // SPDX-License-Identifier: GPL-2.0-only 285397f6bSThomas Zimmermann 385397f6bSThomas Zimmermann #include <linux/pci.h> 485397f6bSThomas Zimmermann 5877507bbSThomas Zimmermann #include <drm/drm_atomic.h> 6bc835040SThomas Zimmermann #include <drm/drm_atomic_helper.h> 785397f6bSThomas Zimmermann #include <drm/drm_drv.h> 8bc835040SThomas Zimmermann #include <drm/drm_gem_atomic_helper.h> 9bc835040SThomas Zimmermann #include <drm/drm_probe_helper.h> 1089c6ea20SThomas Zimmermann #include <drm/drm_vblank.h> 1185397f6bSThomas Zimmermann 1285397f6bSThomas Zimmermann #include "mgag200_drv.h" 1385397f6bSThomas Zimmermann 149382ec27SThomas Zimmermann static void mgag200_g200ew3_init_registers(struct mga_device *mdev) 159382ec27SThomas Zimmermann { 169382ec27SThomas Zimmermann mgag200_g200wb_init_registers(mdev); // same as G200WB 179382ec27SThomas Zimmermann 189382ec27SThomas Zimmermann WREG_ECRT(0x34, 0x5); // G200EW3 specific 199382ec27SThomas Zimmermann } 209382ec27SThomas Zimmermann 2185397f6bSThomas Zimmermann /* 22877507bbSThomas Zimmermann * PIXPLLC 23877507bbSThomas Zimmermann */ 24877507bbSThomas Zimmermann 25877507bbSThomas Zimmermann static int mgag200_g200ew3_pixpllc_atomic_check(struct drm_crtc *crtc, 26877507bbSThomas Zimmermann struct drm_atomic_state *new_state) 27877507bbSThomas Zimmermann { 28877507bbSThomas Zimmermann static const unsigned int vcomax = 800000; 29877507bbSThomas Zimmermann static const unsigned int vcomin = 400000; 30877507bbSThomas Zimmermann static const unsigned int pllreffreq = 25000; 31877507bbSThomas Zimmermann 32877507bbSThomas Zimmermann struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc); 33877507bbSThomas Zimmermann struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state); 34877507bbSThomas Zimmermann long clock = new_crtc_state->mode.clock; 35877507bbSThomas Zimmermann struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc; 36877507bbSThomas Zimmermann unsigned int delta, tmpdelta; 37877507bbSThomas Zimmermann unsigned int testp, testm, testn, testp2; 38877507bbSThomas Zimmermann unsigned int p, m, n, s; 39877507bbSThomas Zimmermann unsigned int computed; 40877507bbSThomas Zimmermann 41877507bbSThomas Zimmermann m = n = p = s = 0; 42877507bbSThomas Zimmermann delta = 0xffffffff; 43877507bbSThomas Zimmermann 44877507bbSThomas Zimmermann for (testp = 1; testp < 8; testp++) { 45877507bbSThomas Zimmermann for (testp2 = 1; testp2 < 8; testp2++) { 46877507bbSThomas Zimmermann if (testp < testp2) 47877507bbSThomas Zimmermann continue; 48877507bbSThomas Zimmermann if ((clock * testp * testp2) > vcomax) 49877507bbSThomas Zimmermann continue; 50877507bbSThomas Zimmermann if ((clock * testp * testp2) < vcomin) 51877507bbSThomas Zimmermann continue; 52877507bbSThomas Zimmermann for (testm = 1; testm < 26; testm++) { 53877507bbSThomas Zimmermann for (testn = 32; testn < 2048 ; testn++) { 54877507bbSThomas Zimmermann computed = (pllreffreq * testn) / (testm * testp * testp2); 55877507bbSThomas Zimmermann if (computed > clock) 56877507bbSThomas Zimmermann tmpdelta = computed - clock; 57877507bbSThomas Zimmermann else 58877507bbSThomas Zimmermann tmpdelta = clock - computed; 59877507bbSThomas Zimmermann if (tmpdelta < delta) { 60877507bbSThomas Zimmermann delta = tmpdelta; 61877507bbSThomas Zimmermann m = testm + 1; 62877507bbSThomas Zimmermann n = testn + 1; 63877507bbSThomas Zimmermann p = testp + 1; 64877507bbSThomas Zimmermann s = testp2; 65877507bbSThomas Zimmermann } 66877507bbSThomas Zimmermann } 67877507bbSThomas Zimmermann } 68877507bbSThomas Zimmermann } 69877507bbSThomas Zimmermann } 70877507bbSThomas Zimmermann 71877507bbSThomas Zimmermann pixpllc->m = m; 72877507bbSThomas Zimmermann pixpllc->n = n; 73877507bbSThomas Zimmermann pixpllc->p = p; 74877507bbSThomas Zimmermann pixpllc->s = s; 75877507bbSThomas Zimmermann 76877507bbSThomas Zimmermann return 0; 77877507bbSThomas Zimmermann } 78877507bbSThomas Zimmermann 79877507bbSThomas Zimmermann /* 80bc835040SThomas Zimmermann * Mode-setting pipeline 81bc835040SThomas Zimmermann */ 82bc835040SThomas Zimmermann 83bc835040SThomas Zimmermann static const struct drm_plane_helper_funcs mgag200_g200ew3_primary_plane_helper_funcs = { 84bc835040SThomas Zimmermann MGAG200_PRIMARY_PLANE_HELPER_FUNCS, 85bc835040SThomas Zimmermann }; 86bc835040SThomas Zimmermann 87bc835040SThomas Zimmermann static const struct drm_plane_funcs mgag200_g200ew3_primary_plane_funcs = { 88bc835040SThomas Zimmermann MGAG200_PRIMARY_PLANE_FUNCS, 89bc835040SThomas Zimmermann }; 90bc835040SThomas Zimmermann 91bc835040SThomas Zimmermann static const struct drm_crtc_helper_funcs mgag200_g200ew3_crtc_helper_funcs = { 92bc835040SThomas Zimmermann MGAG200_CRTC_HELPER_FUNCS, 93bc835040SThomas Zimmermann }; 94bc835040SThomas Zimmermann 95bc835040SThomas Zimmermann static const struct drm_crtc_funcs mgag200_g200ew3_crtc_funcs = { 96bc835040SThomas Zimmermann MGAG200_CRTC_FUNCS, 97bc835040SThomas Zimmermann }; 98bc835040SThomas Zimmermann 99bc835040SThomas Zimmermann static int mgag200_g200ew3_pipeline_init(struct mga_device *mdev) 100bc835040SThomas Zimmermann { 101bc835040SThomas Zimmermann struct drm_device *dev = &mdev->base; 102bc835040SThomas Zimmermann struct drm_plane *primary_plane = &mdev->primary_plane; 103bc835040SThomas Zimmermann struct drm_crtc *crtc = &mdev->crtc; 104bc835040SThomas Zimmermann int ret; 105bc835040SThomas Zimmermann 106bc835040SThomas Zimmermann ret = drm_universal_plane_init(dev, primary_plane, 0, 107bc835040SThomas Zimmermann &mgag200_g200ew3_primary_plane_funcs, 108bc835040SThomas Zimmermann mgag200_primary_plane_formats, 109bc835040SThomas Zimmermann mgag200_primary_plane_formats_size, 110bc835040SThomas Zimmermann mgag200_primary_plane_fmtmods, 111bc835040SThomas Zimmermann DRM_PLANE_TYPE_PRIMARY, NULL); 112bc835040SThomas Zimmermann if (ret) { 113bc835040SThomas Zimmermann drm_err(dev, "drm_universal_plane_init() failed: %d\n", ret); 114bc835040SThomas Zimmermann return ret; 115bc835040SThomas Zimmermann } 116bc835040SThomas Zimmermann drm_plane_helper_add(primary_plane, &mgag200_g200ew3_primary_plane_helper_funcs); 117bc835040SThomas Zimmermann drm_plane_enable_fb_damage_clips(primary_plane); 118bc835040SThomas Zimmermann 119bc835040SThomas Zimmermann ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL, 120bc835040SThomas Zimmermann &mgag200_g200ew3_crtc_funcs, NULL); 121bc835040SThomas Zimmermann if (ret) { 122bc835040SThomas Zimmermann drm_err(dev, "drm_crtc_init_with_planes() failed: %d\n", ret); 123bc835040SThomas Zimmermann return ret; 124bc835040SThomas Zimmermann } 125bc835040SThomas Zimmermann drm_crtc_helper_add(crtc, &mgag200_g200ew3_crtc_helper_funcs); 126bc835040SThomas Zimmermann 127bc835040SThomas Zimmermann /* FIXME: legacy gamma tables, but atomic gamma doesn't work without */ 128bc835040SThomas Zimmermann drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE); 129bc835040SThomas Zimmermann drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE); 130bc835040SThomas Zimmermann 131*f5510726SThomas Zimmermann ret = mgag200_vga_bmc_output_init(mdev); 132579d4783SThomas Zimmermann if (ret) 133bc835040SThomas Zimmermann return ret; 134bc835040SThomas Zimmermann 135bc835040SThomas Zimmermann return 0; 136bc835040SThomas Zimmermann } 137bc835040SThomas Zimmermann 138bc835040SThomas Zimmermann /* 13985397f6bSThomas Zimmermann * DRM device 14085397f6bSThomas Zimmermann */ 14185397f6bSThomas Zimmermann 142b9a577a4SThomas Zimmermann static const struct mgag200_device_info mgag200_g200ew3_device_info = 143da1efdb2SThomas Zimmermann MGAG200_DEVICE_INFO_INIT(2048, 2048, 0, true, 0, 1, false); 144b9a577a4SThomas Zimmermann 145f639f74aSThomas Zimmermann static const struct mgag200_device_funcs mgag200_g200ew3_device_funcs = { 146877507bbSThomas Zimmermann .pixpllc_atomic_check = mgag200_g200ew3_pixpllc_atomic_check, 147877507bbSThomas Zimmermann .pixpllc_atomic_update = mgag200_g200wb_pixpllc_atomic_update, // same as G200WB 148f639f74aSThomas Zimmermann }; 149f639f74aSThomas Zimmermann 150d45e32c9SThomas Zimmermann static resource_size_t mgag200_g200ew3_device_probe_vram(struct mga_device *mdev) 151d45e32c9SThomas Zimmermann { 152b62d943eSThomas Zimmermann resource_size_t vram_size = resource_size(mdev->vram_res); 153d45e32c9SThomas Zimmermann 154d45e32c9SThomas Zimmermann if (vram_size >= 0x1000000) 155d45e32c9SThomas Zimmermann vram_size = vram_size - 0x400000; 156d45e32c9SThomas Zimmermann return mgag200_probe_vram(mdev->vram, vram_size); 157d45e32c9SThomas Zimmermann } 158d45e32c9SThomas Zimmermann 15985397f6bSThomas Zimmermann struct mga_device *mgag200_g200ew3_device_create(struct pci_dev *pdev, 160d4a3e50fSThomas Zimmermann const struct drm_driver *drv) 16185397f6bSThomas Zimmermann { 16285397f6bSThomas Zimmermann struct mga_device *mdev; 16385397f6bSThomas Zimmermann struct drm_device *dev; 164d45e32c9SThomas Zimmermann resource_size_t vram_available; 16585397f6bSThomas Zimmermann int ret; 16685397f6bSThomas Zimmermann 16785397f6bSThomas Zimmermann mdev = devm_drm_dev_alloc(&pdev->dev, drv, struct mga_device, base); 16885397f6bSThomas Zimmermann if (IS_ERR(mdev)) 16985397f6bSThomas Zimmermann return mdev; 17085397f6bSThomas Zimmermann dev = &mdev->base; 17185397f6bSThomas Zimmermann 17285397f6bSThomas Zimmermann pci_set_drvdata(pdev, dev); 17385397f6bSThomas Zimmermann 174ce19021fSThomas Zimmermann ret = mgag200_init_pci_options(pdev, 0x41049120, 0x0000b000); 175ce19021fSThomas Zimmermann if (ret) 176ce19021fSThomas Zimmermann return ERR_PTR(ret); 177ce19021fSThomas Zimmermann 178b62d943eSThomas Zimmermann ret = mgag200_device_preinit(mdev); 17985397f6bSThomas Zimmermann if (ret) 18085397f6bSThomas Zimmermann return ERR_PTR(ret); 18185397f6bSThomas Zimmermann 182d4a3e50fSThomas Zimmermann ret = mgag200_device_init(mdev, &mgag200_g200ew3_device_info, 183f639f74aSThomas Zimmermann &mgag200_g200ew3_device_funcs); 18485397f6bSThomas Zimmermann if (ret) 18585397f6bSThomas Zimmermann return ERR_PTR(ret); 18685397f6bSThomas Zimmermann 1879382ec27SThomas Zimmermann mgag200_g200ew3_init_registers(mdev); 1881ee181feSThomas Zimmermann 189d45e32c9SThomas Zimmermann vram_available = mgag200_g200ew3_device_probe_vram(mdev); 190d45e32c9SThomas Zimmermann 191bc835040SThomas Zimmermann ret = mgag200_mode_config_init(mdev, vram_available); 19285397f6bSThomas Zimmermann if (ret) 19385397f6bSThomas Zimmermann return ERR_PTR(ret); 19485397f6bSThomas Zimmermann 195bc835040SThomas Zimmermann ret = mgag200_g200ew3_pipeline_init(mdev); 196bc835040SThomas Zimmermann if (ret) 197bc835040SThomas Zimmermann return ERR_PTR(ret); 198bc835040SThomas Zimmermann 199bc835040SThomas Zimmermann drm_mode_config_reset(dev); 2002bae076fSThomas Zimmermann drm_kms_helper_poll_init(dev); 201bc835040SThomas Zimmermann 20289c6ea20SThomas Zimmermann ret = drm_vblank_init(dev, 1); 20389c6ea20SThomas Zimmermann if (ret) 20489c6ea20SThomas Zimmermann return ERR_PTR(ret); 20589c6ea20SThomas Zimmermann 20685397f6bSThomas Zimmermann return mdev; 20785397f6bSThomas Zimmermann } 208