1 // SPDX-License-Identifier: GPL-2.0-only 2 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_print.h> 11 #include <drm/drm_probe_helper.h> 12 13 #include "mgag200_drv.h" 14 15 static void mgag200_g200er_init_registers(struct mga_device *mdev) 16 { 17 static const u8 dacvalue[] = { 18 MGAG200_DAC_DEFAULT(0x00, 0xc9, 0x1f, 0x00, 0x00, 0x00) 19 }; 20 21 size_t i; 22 23 for (i = 0; i < ARRAY_SIZE(dacvalue); i++) { 24 if ((i <= 0x17) || 25 (i == 0x1b) || 26 (i == 0x1c) || 27 ((i >= 0x1f) && (i <= 0x29)) || 28 ((i >= 0x30) && (i <= 0x37))) 29 continue; 30 WREG_DAC(i, dacvalue[i]); 31 } 32 33 WREG_DAC(0x90, 0); /* G200ER specific */ 34 35 mgag200_init_registers(mdev); 36 37 WREG_ECRT(0x24, 0x5); /* G200ER specific */ 38 } 39 40 static void mgag200_g200er_reset_tagfifo(struct mga_device *mdev) 41 { 42 static const uint32_t RESET_FLAG = 0x00200000; /* undocumented magic value */ 43 u32 memctl; 44 45 memctl = RREG32(MGAREG_MEMCTL); 46 47 memctl |= RESET_FLAG; 48 WREG32(MGAREG_MEMCTL, memctl); 49 50 udelay(1000); 51 52 memctl &= ~RESET_FLAG; 53 WREG32(MGAREG_MEMCTL, memctl); 54 } 55 56 /* 57 * PIXPLLC 58 */ 59 60 static int mgag200_g200er_pixpllc_atomic_check(struct drm_crtc *crtc, 61 struct drm_atomic_state *new_state) 62 { 63 static const unsigned int vcomax = 1488000; 64 static const unsigned int vcomin = 1056000; 65 static const unsigned int pllreffreq = 48000; 66 static const unsigned int m_div_val[] = { 1, 2, 4, 8 }; 67 68 struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc); 69 struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state); 70 long clock = new_crtc_state->mode.clock; 71 struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc; 72 unsigned int delta, tmpdelta; 73 int testr, testn, testm, testo; 74 unsigned int p, m, n, s; 75 unsigned int computed, vco; 76 77 m = n = p = s = 0; 78 delta = 0xffffffff; 79 80 for (testr = 0; testr < 4; testr++) { 81 if (delta == 0) 82 break; 83 for (testn = 5; testn < 129; testn++) { 84 if (delta == 0) 85 break; 86 for (testm = 3; testm >= 0; testm--) { 87 if (delta == 0) 88 break; 89 for (testo = 5; testo < 33; testo++) { 90 vco = pllreffreq * (testn + 1) / 91 (testr + 1); 92 if (vco < vcomin) 93 continue; 94 if (vco > vcomax) 95 continue; 96 computed = vco / (m_div_val[testm] * (testo + 1)); 97 if (computed > clock) 98 tmpdelta = computed - clock; 99 else 100 tmpdelta = clock - computed; 101 if (tmpdelta < delta) { 102 delta = tmpdelta; 103 m = (testm | (testo << 3)) + 1; 104 n = testn + 1; 105 p = testr + 1; 106 s = testr; 107 } 108 } 109 } 110 } 111 } 112 113 pixpllc->m = m; 114 pixpllc->n = n; 115 pixpllc->p = p; 116 pixpllc->s = s; 117 118 return 0; 119 } 120 121 static void mgag200_g200er_pixpllc_atomic_update(struct drm_crtc *crtc, 122 struct drm_atomic_state *old_state) 123 { 124 struct drm_device *dev = crtc->dev; 125 struct mga_device *mdev = to_mga_device(dev); 126 struct drm_crtc_state *crtc_state = crtc->state; 127 struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state); 128 struct mgag200_pll_values *pixpllc = &mgag200_crtc_state->pixpllc; 129 unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs; 130 u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp; 131 132 pixpllcm = pixpllc->m - 1; 133 pixpllcn = pixpllc->n - 1; 134 pixpllcp = pixpllc->p - 1; 135 pixpllcs = pixpllc->s; 136 137 xpixpllcm = pixpllcm; 138 xpixpllcn = pixpllcn; 139 xpixpllcp = (pixpllcs << 3) | pixpllcp; 140 141 WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK); 142 143 WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 144 tmp = RREG8(DAC_DATA); 145 tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS; 146 WREG8(DAC_DATA, tmp); 147 148 WREG8(DAC_INDEX, MGA1064_REMHEADCTL); 149 tmp = RREG8(DAC_DATA); 150 tmp |= MGA1064_REMHEADCTL_CLKDIS; 151 WREG8(DAC_DATA, tmp); 152 153 tmp = RREG8(MGAREG_MEM_MISC_READ); 154 tmp |= (0x3<<2) | 0xc0; 155 WREG8(MGAREG_MEM_MISC_WRITE, tmp); 156 157 WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 158 tmp = RREG8(DAC_DATA); 159 tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS; 160 tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; 161 WREG8(DAC_DATA, tmp); 162 163 udelay(500); 164 165 WREG_DAC(MGA1064_ER_PIX_PLLC_N, xpixpllcn); 166 WREG_DAC(MGA1064_ER_PIX_PLLC_M, xpixpllcm); 167 WREG_DAC(MGA1064_ER_PIX_PLLC_P, xpixpllcp); 168 169 udelay(50); 170 } 171 172 /* 173 * Mode-setting pipeline 174 */ 175 176 static const struct drm_plane_helper_funcs mgag200_g200er_primary_plane_helper_funcs = { 177 MGAG200_PRIMARY_PLANE_HELPER_FUNCS, 178 }; 179 180 static const struct drm_plane_funcs mgag200_g200er_primary_plane_funcs = { 181 MGAG200_PRIMARY_PLANE_FUNCS, 182 }; 183 184 static void mgag200_g200er_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_g200er_reset_tagfifo(mdev); 202 203 if (crtc_state->gamma_lut) 204 mgag200_crtc_load_gamma(mdev, format, crtc_state->gamma_lut->data); 205 else 206 mgag200_crtc_fill_gamma(mdev, format); 207 208 mgag200_enable_display(mdev); 209 } 210 211 static const struct drm_crtc_helper_funcs mgag200_g200er_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_g200er_crtc_helper_atomic_enable, 216 .atomic_disable = mgag200_crtc_helper_atomic_disable 217 }; 218 219 static const struct drm_crtc_funcs mgag200_g200er_crtc_funcs = { 220 MGAG200_CRTC_FUNCS, 221 }; 222 223 static int mgag200_g200er_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_g200er_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_g200er_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_g200er_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_g200er_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 device 264 */ 265 266 static const struct mgag200_device_info mgag200_g200er_device_info = 267 MGAG200_DEVICE_INFO_INIT(2048, 2048, 55000, false, 1, 0, false); 268 269 static const struct mgag200_device_funcs mgag200_g200er_device_funcs = { 270 .pixpllc_atomic_check = mgag200_g200er_pixpllc_atomic_check, 271 .pixpllc_atomic_update = mgag200_g200er_pixpllc_atomic_update, 272 }; 273 274 struct mga_device *mgag200_g200er_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_device_preinit(mdev); 289 if (ret) 290 return ERR_PTR(ret); 291 292 ret = mgag200_device_init(mdev, &mgag200_g200er_device_info, 293 &mgag200_g200er_device_funcs); 294 if (ret) 295 return ERR_PTR(ret); 296 297 mgag200_g200er_init_registers(mdev); 298 299 vram_available = mgag200_device_probe_vram(mdev); 300 301 ret = mgag200_mode_config_init(mdev, vram_available); 302 if (ret) 303 return ERR_PTR(ret); 304 305 ret = mgag200_g200er_pipeline_init(mdev); 306 if (ret) 307 return ERR_PTR(ret); 308 309 drm_mode_config_reset(dev); 310 drm_kms_helper_poll_init(dev); 311 312 return mdev; 313 } 314