1c51669eaSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2414c4531SDave Airlie /* 3414c4531SDave Airlie * Copyright 2010 Matt Turner. 4414c4531SDave Airlie * Copyright 2012 Red Hat 5414c4531SDave Airlie * 6414c4531SDave Airlie * Authors: Matthew Garrett 7414c4531SDave Airlie * Matt Turner 8414c4531SDave Airlie * Dave Airlie 9414c4531SDave Airlie */ 10414c4531SDave Airlie 11414c4531SDave Airlie #include <linux/delay.h> 1209daa2e7SThomas Zimmermann #include <linux/pci.h> 13414c4531SDave Airlie 14760285e7SDavid Howells #include <drm/drm_crtc_helper.h> 159f397801SSam Ravnborg #include <drm/drm_fourcc.h> 165635b7cfSThomas Zimmermann #include <drm/drm_gem_framebuffer_helper.h> 173cb9ae4fSDaniel Vetter #include <drm/drm_plane_helper.h> 18fcd70cd3SDaniel Vetter #include <drm/drm_probe_helper.h> 1903e44ad1SThomas Zimmermann #include <drm/drm_simple_kms_helper.h> 20414c4531SDave Airlie 21414c4531SDave Airlie #include "mgag200_drv.h" 22414c4531SDave Airlie 23414c4531SDave Airlie #define MGAG200_LUT_SIZE 256 24414c4531SDave Airlie 25414c4531SDave Airlie /* 26414c4531SDave Airlie * This file contains setup code for the CRTC. 27414c4531SDave Airlie */ 28414c4531SDave Airlie 29414c4531SDave Airlie static void mga_crtc_load_lut(struct drm_crtc *crtc) 30414c4531SDave Airlie { 31414c4531SDave Airlie struct drm_device *dev = crtc->dev; 328d8ff2a9SThomas Zimmermann struct mga_device *mdev = to_mga_device(dev); 33f4510a27SMatt Roper struct drm_framebuffer *fb = crtc->primary->fb; 349ed85e14SPeter Rosin u16 *r_ptr, *g_ptr, *b_ptr; 35414c4531SDave Airlie int i; 36414c4531SDave Airlie 37414c4531SDave Airlie if (!crtc->enabled) 38414c4531SDave Airlie return; 39414c4531SDave Airlie 409ed85e14SPeter Rosin r_ptr = crtc->gamma_store; 419ed85e14SPeter Rosin g_ptr = r_ptr + crtc->gamma_size; 429ed85e14SPeter Rosin b_ptr = g_ptr + crtc->gamma_size; 439ed85e14SPeter Rosin 44414c4531SDave Airlie WREG8(DAC_INDEX + MGA1064_INDEX, 0); 45414c4531SDave Airlie 46272725c7SVille Syrjälä if (fb && fb->format->cpp[0] * 8 == 16) { 47b00c600eSVille Syrjälä int inc = (fb->format->depth == 15) ? 8 : 4; 48de7500eaSEgbert Eich u8 r, b; 49de7500eaSEgbert Eich for (i = 0; i < MGAG200_LUT_SIZE; i += inc) { 50b00c600eSVille Syrjälä if (fb->format->depth == 16) { 51de7500eaSEgbert Eich if (i > (MGAG200_LUT_SIZE >> 1)) { 52de7500eaSEgbert Eich r = b = 0; 53de7500eaSEgbert Eich } else { 549ed85e14SPeter Rosin r = *r_ptr++ >> 8; 559ed85e14SPeter Rosin b = *b_ptr++ >> 8; 569ed85e14SPeter Rosin r_ptr++; 579ed85e14SPeter Rosin b_ptr++; 58de7500eaSEgbert Eich } 59de7500eaSEgbert Eich } else { 609ed85e14SPeter Rosin r = *r_ptr++ >> 8; 619ed85e14SPeter Rosin b = *b_ptr++ >> 8; 62de7500eaSEgbert Eich } 63de7500eaSEgbert Eich /* VGA registers */ 64de7500eaSEgbert Eich WREG8(DAC_INDEX + MGA1064_COL_PAL, r); 659ed85e14SPeter Rosin WREG8(DAC_INDEX + MGA1064_COL_PAL, *g_ptr++ >> 8); 66de7500eaSEgbert Eich WREG8(DAC_INDEX + MGA1064_COL_PAL, b); 67de7500eaSEgbert Eich } 68de7500eaSEgbert Eich return; 69de7500eaSEgbert Eich } 70414c4531SDave Airlie for (i = 0; i < MGAG200_LUT_SIZE; i++) { 71414c4531SDave Airlie /* VGA registers */ 729ed85e14SPeter Rosin WREG8(DAC_INDEX + MGA1064_COL_PAL, *r_ptr++ >> 8); 739ed85e14SPeter Rosin WREG8(DAC_INDEX + MGA1064_COL_PAL, *g_ptr++ >> 8); 749ed85e14SPeter Rosin WREG8(DAC_INDEX + MGA1064_COL_PAL, *b_ptr++ >> 8); 75414c4531SDave Airlie } 76414c4531SDave Airlie } 77414c4531SDave Airlie 78414c4531SDave Airlie static inline void mga_wait_vsync(struct mga_device *mdev) 79414c4531SDave Airlie { 803cdc0e8dSChristopher Harvey unsigned long timeout = jiffies + HZ/10; 81414c4531SDave Airlie unsigned int status = 0; 82414c4531SDave Airlie 83414c4531SDave Airlie do { 84414c4531SDave Airlie status = RREG32(MGAREG_Status); 853cdc0e8dSChristopher Harvey } while ((status & 0x08) && time_before(jiffies, timeout)); 863cdc0e8dSChristopher Harvey timeout = jiffies + HZ/10; 87414c4531SDave Airlie status = 0; 88414c4531SDave Airlie do { 89414c4531SDave Airlie status = RREG32(MGAREG_Status); 903cdc0e8dSChristopher Harvey } while (!(status & 0x08) && time_before(jiffies, timeout)); 91414c4531SDave Airlie } 92414c4531SDave Airlie 93414c4531SDave Airlie static inline void mga_wait_busy(struct mga_device *mdev) 94414c4531SDave Airlie { 953cdc0e8dSChristopher Harvey unsigned long timeout = jiffies + HZ; 96414c4531SDave Airlie unsigned int status = 0; 97414c4531SDave Airlie do { 98414c4531SDave Airlie status = RREG8(MGAREG_Status + 2); 993cdc0e8dSChristopher Harvey } while ((status & 0x01) && time_before(jiffies, timeout)); 100414c4531SDave Airlie } 101414c4531SDave Airlie 102e829d7efSMathieu Larouche #define P_ARRAY_SIZE 9 103e829d7efSMathieu Larouche 104414c4531SDave Airlie static int mga_g200se_set_plls(struct mga_device *mdev, long clock) 105414c4531SDave Airlie { 106414c4531SDave Airlie unsigned int vcomax, vcomin, pllreffreq; 107414c4531SDave Airlie unsigned int delta, tmpdelta, permitteddelta; 108414c4531SDave Airlie unsigned int testp, testm, testn; 109414c4531SDave Airlie unsigned int p, m, n; 110414c4531SDave Airlie unsigned int computed; 111e829d7efSMathieu Larouche unsigned int pvalues_e4[P_ARRAY_SIZE] = {16, 14, 12, 10, 8, 6, 4, 2, 1}; 112e829d7efSMathieu Larouche unsigned int fvv; 113e829d7efSMathieu Larouche unsigned int i; 114e829d7efSMathieu Larouche 115e829d7efSMathieu Larouche if (mdev->unique_rev_id <= 0x03) { 116414c4531SDave Airlie 117414c4531SDave Airlie m = n = p = 0; 118414c4531SDave Airlie vcomax = 320000; 119414c4531SDave Airlie vcomin = 160000; 120414c4531SDave Airlie pllreffreq = 25000; 121414c4531SDave Airlie 122414c4531SDave Airlie delta = 0xffffffff; 123414c4531SDave Airlie permitteddelta = clock * 5 / 1000; 124414c4531SDave Airlie 125414c4531SDave Airlie for (testp = 8; testp > 0; testp /= 2) { 126414c4531SDave Airlie if (clock * testp > vcomax) 127414c4531SDave Airlie continue; 128414c4531SDave Airlie if (clock * testp < vcomin) 129414c4531SDave Airlie continue; 130414c4531SDave Airlie 131414c4531SDave Airlie for (testn = 17; testn < 256; testn++) { 132414c4531SDave Airlie for (testm = 1; testm < 32; testm++) { 133414c4531SDave Airlie computed = (pllreffreq * testn) / 134414c4531SDave Airlie (testm * testp); 135414c4531SDave Airlie if (computed > clock) 136414c4531SDave Airlie tmpdelta = computed - clock; 137414c4531SDave Airlie else 138414c4531SDave Airlie tmpdelta = clock - computed; 139414c4531SDave Airlie if (tmpdelta < delta) { 140414c4531SDave Airlie delta = tmpdelta; 141414c4531SDave Airlie m = testm - 1; 142414c4531SDave Airlie n = testn - 1; 143414c4531SDave Airlie p = testp - 1; 144414c4531SDave Airlie } 145414c4531SDave Airlie } 146414c4531SDave Airlie } 147414c4531SDave Airlie } 148e829d7efSMathieu Larouche } else { 149e829d7efSMathieu Larouche 150e829d7efSMathieu Larouche 151e829d7efSMathieu Larouche m = n = p = 0; 152e829d7efSMathieu Larouche vcomax = 1600000; 153e829d7efSMathieu Larouche vcomin = 800000; 154e829d7efSMathieu Larouche pllreffreq = 25000; 155e829d7efSMathieu Larouche 156e829d7efSMathieu Larouche if (clock < 25000) 157e829d7efSMathieu Larouche clock = 25000; 158e829d7efSMathieu Larouche 159e829d7efSMathieu Larouche clock = clock * 2; 160e829d7efSMathieu Larouche 161e829d7efSMathieu Larouche delta = 0xFFFFFFFF; 162e829d7efSMathieu Larouche /* Permited delta is 0.5% as VESA Specification */ 163e829d7efSMathieu Larouche permitteddelta = clock * 5 / 1000; 164e829d7efSMathieu Larouche 165e829d7efSMathieu Larouche for (i = 0 ; i < P_ARRAY_SIZE ; i++) { 166e829d7efSMathieu Larouche testp = pvalues_e4[i]; 167e829d7efSMathieu Larouche 168e829d7efSMathieu Larouche if ((clock * testp) > vcomax) 169e829d7efSMathieu Larouche continue; 170e829d7efSMathieu Larouche if ((clock * testp) < vcomin) 171e829d7efSMathieu Larouche continue; 172e829d7efSMathieu Larouche 173e829d7efSMathieu Larouche for (testn = 50; testn <= 256; testn++) { 174e829d7efSMathieu Larouche for (testm = 1; testm <= 32; testm++) { 175e829d7efSMathieu Larouche computed = (pllreffreq * testn) / 176e829d7efSMathieu Larouche (testm * testp); 177e829d7efSMathieu Larouche if (computed > clock) 178e829d7efSMathieu Larouche tmpdelta = computed - clock; 179e829d7efSMathieu Larouche else 180e829d7efSMathieu Larouche tmpdelta = clock - computed; 181e829d7efSMathieu Larouche 182e829d7efSMathieu Larouche if (tmpdelta < delta) { 183e829d7efSMathieu Larouche delta = tmpdelta; 184e829d7efSMathieu Larouche m = testm - 1; 185e829d7efSMathieu Larouche n = testn - 1; 186e829d7efSMathieu Larouche p = testp - 1; 187e829d7efSMathieu Larouche } 188e829d7efSMathieu Larouche } 189e829d7efSMathieu Larouche } 190e829d7efSMathieu Larouche } 191e829d7efSMathieu Larouche 192d3922b69SMathieu Larouche fvv = pllreffreq * (n + 1) / (m + 1); 193e829d7efSMathieu Larouche fvv = (fvv - 800000) / 50000; 194e829d7efSMathieu Larouche 195e829d7efSMathieu Larouche if (fvv > 15) 196e829d7efSMathieu Larouche fvv = 15; 197e829d7efSMathieu Larouche 198e829d7efSMathieu Larouche p |= (fvv << 4); 199e829d7efSMathieu Larouche m |= 0x80; 200e829d7efSMathieu Larouche 201e829d7efSMathieu Larouche clock = clock / 2; 202e829d7efSMathieu Larouche } 203414c4531SDave Airlie 204414c4531SDave Airlie if (delta > permitteddelta) { 2058dfe162aSJoe Perches pr_warn("PLL delta too large\n"); 206414c4531SDave Airlie return 1; 207414c4531SDave Airlie } 208414c4531SDave Airlie 209414c4531SDave Airlie WREG_DAC(MGA1064_PIX_PLLC_M, m); 210414c4531SDave Airlie WREG_DAC(MGA1064_PIX_PLLC_N, n); 211414c4531SDave Airlie WREG_DAC(MGA1064_PIX_PLLC_P, p); 212d3922b69SMathieu Larouche 213d3922b69SMathieu Larouche if (mdev->unique_rev_id >= 0x04) { 214d3922b69SMathieu Larouche WREG_DAC(0x1a, 0x09); 215d3922b69SMathieu Larouche msleep(20); 216d3922b69SMathieu Larouche WREG_DAC(0x1a, 0x01); 217d3922b69SMathieu Larouche 218d3922b69SMathieu Larouche } 219d3922b69SMathieu Larouche 220414c4531SDave Airlie return 0; 221414c4531SDave Airlie } 222414c4531SDave Airlie 223414c4531SDave Airlie static int mga_g200wb_set_plls(struct mga_device *mdev, long clock) 224414c4531SDave Airlie { 225414c4531SDave Airlie unsigned int vcomax, vcomin, pllreffreq; 226546aee51SSudip Mukherjee unsigned int delta, tmpdelta; 2276d857c18SMathieu Larouche unsigned int testp, testm, testn, testp2; 228414c4531SDave Airlie unsigned int p, m, n; 229414c4531SDave Airlie unsigned int computed; 230414c4531SDave Airlie int i, j, tmpcount, vcount; 231414c4531SDave Airlie bool pll_locked = false; 232414c4531SDave Airlie u8 tmp; 233414c4531SDave Airlie 234414c4531SDave Airlie m = n = p = 0; 2356d857c18SMathieu Larouche 2366d857c18SMathieu Larouche delta = 0xffffffff; 2376d857c18SMathieu Larouche 2386d857c18SMathieu Larouche if (mdev->type == G200_EW3) { 2396d857c18SMathieu Larouche 2406d857c18SMathieu Larouche vcomax = 800000; 2416d857c18SMathieu Larouche vcomin = 400000; 2426d857c18SMathieu Larouche pllreffreq = 25000; 2436d857c18SMathieu Larouche 2446d857c18SMathieu Larouche for (testp = 1; testp < 8; testp++) { 2456d857c18SMathieu Larouche for (testp2 = 1; testp2 < 8; testp2++) { 2466d857c18SMathieu Larouche if (testp < testp2) 2476d857c18SMathieu Larouche continue; 2486d857c18SMathieu Larouche if ((clock * testp * testp2) > vcomax) 2496d857c18SMathieu Larouche continue; 2506d857c18SMathieu Larouche if ((clock * testp * testp2) < vcomin) 2516d857c18SMathieu Larouche continue; 2526d857c18SMathieu Larouche for (testm = 1; testm < 26; testm++) { 2536d857c18SMathieu Larouche for (testn = 32; testn < 2048 ; testn++) { 2546d857c18SMathieu Larouche computed = (pllreffreq * testn) / 2556d857c18SMathieu Larouche (testm * testp * testp2); 2566d857c18SMathieu Larouche if (computed > clock) 2576d857c18SMathieu Larouche tmpdelta = computed - clock; 2586d857c18SMathieu Larouche else 2596d857c18SMathieu Larouche tmpdelta = clock - computed; 2606d857c18SMathieu Larouche if (tmpdelta < delta) { 2616d857c18SMathieu Larouche delta = tmpdelta; 2626d857c18SMathieu Larouche m = ((testn & 0x100) >> 1) | 2636d857c18SMathieu Larouche (testm); 2646d857c18SMathieu Larouche n = (testn & 0xFF); 2656d857c18SMathieu Larouche p = ((testn & 0x600) >> 3) | 2666d857c18SMathieu Larouche (testp2 << 3) | 2676d857c18SMathieu Larouche (testp); 2686d857c18SMathieu Larouche } 2696d857c18SMathieu Larouche } 2706d857c18SMathieu Larouche } 2716d857c18SMathieu Larouche } 2726d857c18SMathieu Larouche } 2736d857c18SMathieu Larouche } else { 2746d857c18SMathieu Larouche 275414c4531SDave Airlie vcomax = 550000; 276414c4531SDave Airlie vcomin = 150000; 277414c4531SDave Airlie pllreffreq = 48000; 278414c4531SDave Airlie 279414c4531SDave Airlie for (testp = 1; testp < 9; testp++) { 280414c4531SDave Airlie if (clock * testp > vcomax) 281414c4531SDave Airlie continue; 282414c4531SDave Airlie if (clock * testp < vcomin) 283414c4531SDave Airlie continue; 284414c4531SDave Airlie 285414c4531SDave Airlie for (testm = 1; testm < 17; testm++) { 286414c4531SDave Airlie for (testn = 1; testn < 151; testn++) { 287414c4531SDave Airlie computed = (pllreffreq * testn) / 288414c4531SDave Airlie (testm * testp); 289414c4531SDave Airlie if (computed > clock) 290414c4531SDave Airlie tmpdelta = computed - clock; 291414c4531SDave Airlie else 292414c4531SDave Airlie tmpdelta = clock - computed; 293414c4531SDave Airlie if (tmpdelta < delta) { 294414c4531SDave Airlie delta = tmpdelta; 295414c4531SDave Airlie n = testn - 1; 2966d857c18SMathieu Larouche m = (testm - 1) | 2976d857c18SMathieu Larouche ((n >> 1) & 0x80); 298414c4531SDave Airlie p = testp - 1; 299414c4531SDave Airlie } 300414c4531SDave Airlie } 301414c4531SDave Airlie } 302414c4531SDave Airlie } 3036d857c18SMathieu Larouche } 304414c4531SDave Airlie 305414c4531SDave Airlie for (i = 0; i <= 32 && pll_locked == false; i++) { 306414c4531SDave Airlie if (i > 0) { 307414c4531SDave Airlie WREG8(MGAREG_CRTC_INDEX, 0x1e); 308414c4531SDave Airlie tmp = RREG8(MGAREG_CRTC_DATA); 309414c4531SDave Airlie if (tmp < 0xff) 310414c4531SDave Airlie WREG8(MGAREG_CRTC_DATA, tmp+1); 311414c4531SDave Airlie } 312414c4531SDave Airlie 313414c4531SDave Airlie /* set pixclkdis to 1 */ 314414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 315414c4531SDave Airlie tmp = RREG8(DAC_DATA); 316414c4531SDave Airlie tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS; 317fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 318414c4531SDave Airlie 319414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_REMHEADCTL); 320414c4531SDave Airlie tmp = RREG8(DAC_DATA); 321414c4531SDave Airlie tmp |= MGA1064_REMHEADCTL_CLKDIS; 322fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 323414c4531SDave Airlie 324414c4531SDave Airlie /* select PLL Set C */ 325414c4531SDave Airlie tmp = RREG8(MGAREG_MEM_MISC_READ); 326414c4531SDave Airlie tmp |= 0x3 << 2; 327414c4531SDave Airlie WREG8(MGAREG_MEM_MISC_WRITE, tmp); 328414c4531SDave Airlie 329414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 330414c4531SDave Airlie tmp = RREG8(DAC_DATA); 331414c4531SDave Airlie tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN | 0x80; 332fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 333414c4531SDave Airlie 334414c4531SDave Airlie udelay(500); 335414c4531SDave Airlie 336414c4531SDave Airlie /* reset the PLL */ 337414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_VREF_CTL); 338414c4531SDave Airlie tmp = RREG8(DAC_DATA); 339414c4531SDave Airlie tmp &= ~0x04; 340fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 341414c4531SDave Airlie 342414c4531SDave Airlie udelay(50); 343414c4531SDave Airlie 344414c4531SDave Airlie /* program pixel pll register */ 345414c4531SDave Airlie WREG_DAC(MGA1064_WB_PIX_PLLC_N, n); 346414c4531SDave Airlie WREG_DAC(MGA1064_WB_PIX_PLLC_M, m); 347414c4531SDave Airlie WREG_DAC(MGA1064_WB_PIX_PLLC_P, p); 348414c4531SDave Airlie 349414c4531SDave Airlie udelay(50); 350414c4531SDave Airlie 351414c4531SDave Airlie /* turn pll on */ 352414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_VREF_CTL); 353414c4531SDave Airlie tmp = RREG8(DAC_DATA); 354414c4531SDave Airlie tmp |= 0x04; 355414c4531SDave Airlie WREG_DAC(MGA1064_VREF_CTL, tmp); 356414c4531SDave Airlie 357414c4531SDave Airlie udelay(500); 358414c4531SDave Airlie 359414c4531SDave Airlie /* select the pixel pll */ 360414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 361414c4531SDave Airlie tmp = RREG8(DAC_DATA); 362414c4531SDave Airlie tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK; 363414c4531SDave Airlie tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL; 364fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 365414c4531SDave Airlie 366414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_REMHEADCTL); 367414c4531SDave Airlie tmp = RREG8(DAC_DATA); 368414c4531SDave Airlie tmp &= ~MGA1064_REMHEADCTL_CLKSL_MSK; 369414c4531SDave Airlie tmp |= MGA1064_REMHEADCTL_CLKSL_PLL; 370fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 371414c4531SDave Airlie 372414c4531SDave Airlie /* reset dotclock rate bit */ 373414c4531SDave Airlie WREG8(MGAREG_SEQ_INDEX, 1); 374414c4531SDave Airlie tmp = RREG8(MGAREG_SEQ_DATA); 375414c4531SDave Airlie tmp &= ~0x8; 376414c4531SDave Airlie WREG8(MGAREG_SEQ_DATA, tmp); 377414c4531SDave Airlie 378414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 379414c4531SDave Airlie tmp = RREG8(DAC_DATA); 380414c4531SDave Airlie tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS; 381fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 382414c4531SDave Airlie 383414c4531SDave Airlie vcount = RREG8(MGAREG_VCOUNT); 384414c4531SDave Airlie 385414c4531SDave Airlie for (j = 0; j < 30 && pll_locked == false; j++) { 386414c4531SDave Airlie tmpcount = RREG8(MGAREG_VCOUNT); 387414c4531SDave Airlie if (tmpcount < vcount) 388414c4531SDave Airlie vcount = 0; 389414c4531SDave Airlie if ((tmpcount - vcount) > 2) 390414c4531SDave Airlie pll_locked = true; 391414c4531SDave Airlie else 392414c4531SDave Airlie udelay(5); 393414c4531SDave Airlie } 394414c4531SDave Airlie } 395414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_REMHEADCTL); 396414c4531SDave Airlie tmp = RREG8(DAC_DATA); 397414c4531SDave Airlie tmp &= ~MGA1064_REMHEADCTL_CLKDIS; 398414c4531SDave Airlie WREG_DAC(MGA1064_REMHEADCTL, tmp); 399414c4531SDave Airlie return 0; 400414c4531SDave Airlie } 401414c4531SDave Airlie 402414c4531SDave Airlie static int mga_g200ev_set_plls(struct mga_device *mdev, long clock) 403414c4531SDave Airlie { 404414c4531SDave Airlie unsigned int vcomax, vcomin, pllreffreq; 405546aee51SSudip Mukherjee unsigned int delta, tmpdelta; 406414c4531SDave Airlie unsigned int testp, testm, testn; 407414c4531SDave Airlie unsigned int p, m, n; 408414c4531SDave Airlie unsigned int computed; 409414c4531SDave Airlie u8 tmp; 410414c4531SDave Airlie 411414c4531SDave Airlie m = n = p = 0; 412414c4531SDave Airlie vcomax = 550000; 413414c4531SDave Airlie vcomin = 150000; 414414c4531SDave Airlie pllreffreq = 50000; 415414c4531SDave Airlie 416414c4531SDave Airlie delta = 0xffffffff; 417414c4531SDave Airlie 418414c4531SDave Airlie for (testp = 16; testp > 0; testp--) { 419414c4531SDave Airlie if (clock * testp > vcomax) 420414c4531SDave Airlie continue; 421414c4531SDave Airlie if (clock * testp < vcomin) 422414c4531SDave Airlie continue; 423414c4531SDave Airlie 424414c4531SDave Airlie for (testn = 1; testn < 257; testn++) { 425414c4531SDave Airlie for (testm = 1; testm < 17; testm++) { 426414c4531SDave Airlie computed = (pllreffreq * testn) / 427414c4531SDave Airlie (testm * testp); 428414c4531SDave Airlie if (computed > clock) 429414c4531SDave Airlie tmpdelta = computed - clock; 430414c4531SDave Airlie else 431414c4531SDave Airlie tmpdelta = clock - computed; 432414c4531SDave Airlie if (tmpdelta < delta) { 433414c4531SDave Airlie delta = tmpdelta; 434414c4531SDave Airlie n = testn - 1; 435414c4531SDave Airlie m = testm - 1; 436414c4531SDave Airlie p = testp - 1; 437414c4531SDave Airlie } 438414c4531SDave Airlie } 439414c4531SDave Airlie } 440414c4531SDave Airlie } 441414c4531SDave Airlie 442414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 443414c4531SDave Airlie tmp = RREG8(DAC_DATA); 444414c4531SDave Airlie tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS; 445fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 446414c4531SDave Airlie 447414c4531SDave Airlie tmp = RREG8(MGAREG_MEM_MISC_READ); 448414c4531SDave Airlie tmp |= 0x3 << 2; 449414c4531SDave Airlie WREG8(MGAREG_MEM_MISC_WRITE, tmp); 450414c4531SDave Airlie 451414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_PLL_STAT); 452414c4531SDave Airlie tmp = RREG8(DAC_DATA); 453fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp & ~0x40); 454414c4531SDave Airlie 455414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 456414c4531SDave Airlie tmp = RREG8(DAC_DATA); 457414c4531SDave Airlie tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; 458fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 459414c4531SDave Airlie 460414c4531SDave Airlie WREG_DAC(MGA1064_EV_PIX_PLLC_M, m); 461414c4531SDave Airlie WREG_DAC(MGA1064_EV_PIX_PLLC_N, n); 462414c4531SDave Airlie WREG_DAC(MGA1064_EV_PIX_PLLC_P, p); 463414c4531SDave Airlie 464414c4531SDave Airlie udelay(50); 465414c4531SDave Airlie 466414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 467414c4531SDave Airlie tmp = RREG8(DAC_DATA); 468414c4531SDave Airlie tmp &= ~MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; 469fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 470414c4531SDave Airlie 471414c4531SDave Airlie udelay(500); 472414c4531SDave Airlie 473414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 474414c4531SDave Airlie tmp = RREG8(DAC_DATA); 475414c4531SDave Airlie tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK; 476414c4531SDave Airlie tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL; 477fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 478414c4531SDave Airlie 479414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_PLL_STAT); 480414c4531SDave Airlie tmp = RREG8(DAC_DATA); 481fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp | 0x40); 482414c4531SDave Airlie 483414c4531SDave Airlie tmp = RREG8(MGAREG_MEM_MISC_READ); 484414c4531SDave Airlie tmp |= (0x3 << 2); 485414c4531SDave Airlie WREG8(MGAREG_MEM_MISC_WRITE, tmp); 486414c4531SDave Airlie 487414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 488414c4531SDave Airlie tmp = RREG8(DAC_DATA); 489414c4531SDave Airlie tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS; 490fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 491414c4531SDave Airlie 492414c4531SDave Airlie return 0; 493414c4531SDave Airlie } 494414c4531SDave Airlie 495414c4531SDave Airlie static int mga_g200eh_set_plls(struct mga_device *mdev, long clock) 496414c4531SDave Airlie { 497414c4531SDave Airlie unsigned int vcomax, vcomin, pllreffreq; 498546aee51SSudip Mukherjee unsigned int delta, tmpdelta; 499414c4531SDave Airlie unsigned int testp, testm, testn; 500414c4531SDave Airlie unsigned int p, m, n; 501414c4531SDave Airlie unsigned int computed; 502414c4531SDave Airlie int i, j, tmpcount, vcount; 503414c4531SDave Airlie u8 tmp; 504414c4531SDave Airlie bool pll_locked = false; 505414c4531SDave Airlie 506414c4531SDave Airlie m = n = p = 0; 507f0493e65SMathieu Larouche 508f0493e65SMathieu Larouche if (mdev->type == G200_EH3) { 509f0493e65SMathieu Larouche vcomax = 3000000; 510f0493e65SMathieu Larouche vcomin = 1500000; 511f0493e65SMathieu Larouche pllreffreq = 25000; 512f0493e65SMathieu Larouche 513f0493e65SMathieu Larouche delta = 0xffffffff; 514f0493e65SMathieu Larouche 515f0493e65SMathieu Larouche testp = 0; 516f0493e65SMathieu Larouche 517f0493e65SMathieu Larouche for (testm = 150; testm >= 6; testm--) { 518f0493e65SMathieu Larouche if (clock * testm > vcomax) 519f0493e65SMathieu Larouche continue; 520f0493e65SMathieu Larouche if (clock * testm < vcomin) 521f0493e65SMathieu Larouche continue; 522f0493e65SMathieu Larouche for (testn = 120; testn >= 60; testn--) { 523f0493e65SMathieu Larouche computed = (pllreffreq * testn) / testm; 524f0493e65SMathieu Larouche if (computed > clock) 525f0493e65SMathieu Larouche tmpdelta = computed - clock; 526f0493e65SMathieu Larouche else 527f0493e65SMathieu Larouche tmpdelta = clock - computed; 528f0493e65SMathieu Larouche if (tmpdelta < delta) { 529f0493e65SMathieu Larouche delta = tmpdelta; 530f0493e65SMathieu Larouche n = testn; 531f0493e65SMathieu Larouche m = testm; 532f0493e65SMathieu Larouche p = testp; 533f0493e65SMathieu Larouche } 534f0493e65SMathieu Larouche if (delta == 0) 535f0493e65SMathieu Larouche break; 536f0493e65SMathieu Larouche } 537f0493e65SMathieu Larouche if (delta == 0) 538f0493e65SMathieu Larouche break; 539f0493e65SMathieu Larouche } 540f0493e65SMathieu Larouche } else { 541f0493e65SMathieu Larouche 542414c4531SDave Airlie vcomax = 800000; 543414c4531SDave Airlie vcomin = 400000; 544260b3f12SJulia Lemire pllreffreq = 33333; 545414c4531SDave Airlie 546414c4531SDave Airlie delta = 0xffffffff; 547414c4531SDave Airlie 548260b3f12SJulia Lemire for (testp = 16; testp > 0; testp >>= 1) { 549414c4531SDave Airlie if (clock * testp > vcomax) 550414c4531SDave Airlie continue; 551414c4531SDave Airlie if (clock * testp < vcomin) 552414c4531SDave Airlie continue; 553414c4531SDave Airlie 554414c4531SDave Airlie for (testm = 1; testm < 33; testm++) { 555260b3f12SJulia Lemire for (testn = 17; testn < 257; testn++) { 556414c4531SDave Airlie computed = (pllreffreq * testn) / 557414c4531SDave Airlie (testm * testp); 558414c4531SDave Airlie if (computed > clock) 559414c4531SDave Airlie tmpdelta = computed - clock; 560414c4531SDave Airlie else 561414c4531SDave Airlie tmpdelta = clock - computed; 562414c4531SDave Airlie if (tmpdelta < delta) { 563414c4531SDave Airlie delta = tmpdelta; 564414c4531SDave Airlie n = testn - 1; 565260b3f12SJulia Lemire m = (testm - 1); 566414c4531SDave Airlie p = testp - 1; 567414c4531SDave Airlie } 568414c4531SDave Airlie if ((clock * testp) >= 600000) 569260b3f12SJulia Lemire p |= 0x80; 570414c4531SDave Airlie } 571414c4531SDave Airlie } 572414c4531SDave Airlie } 573f0493e65SMathieu Larouche } 574414c4531SDave Airlie for (i = 0; i <= 32 && pll_locked == false; i++) { 575414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 576414c4531SDave Airlie tmp = RREG8(DAC_DATA); 577414c4531SDave Airlie tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS; 578fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 579414c4531SDave Airlie 580414c4531SDave Airlie tmp = RREG8(MGAREG_MEM_MISC_READ); 581414c4531SDave Airlie tmp |= 0x3 << 2; 582414c4531SDave Airlie WREG8(MGAREG_MEM_MISC_WRITE, tmp); 583414c4531SDave Airlie 584414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 585414c4531SDave Airlie tmp = RREG8(DAC_DATA); 586414c4531SDave Airlie tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; 587fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 588414c4531SDave Airlie 589414c4531SDave Airlie udelay(500); 590414c4531SDave Airlie 591414c4531SDave Airlie WREG_DAC(MGA1064_EH_PIX_PLLC_M, m); 592414c4531SDave Airlie WREG_DAC(MGA1064_EH_PIX_PLLC_N, n); 593414c4531SDave Airlie WREG_DAC(MGA1064_EH_PIX_PLLC_P, p); 594414c4531SDave Airlie 595414c4531SDave Airlie udelay(500); 596414c4531SDave Airlie 597414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 598414c4531SDave Airlie tmp = RREG8(DAC_DATA); 599414c4531SDave Airlie tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK; 600414c4531SDave Airlie tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL; 601fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 602414c4531SDave Airlie 603414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 604414c4531SDave Airlie tmp = RREG8(DAC_DATA); 605414c4531SDave Airlie tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS; 606414c4531SDave Airlie tmp &= ~MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; 607fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 608414c4531SDave Airlie 609414c4531SDave Airlie vcount = RREG8(MGAREG_VCOUNT); 610414c4531SDave Airlie 611414c4531SDave Airlie for (j = 0; j < 30 && pll_locked == false; j++) { 612414c4531SDave Airlie tmpcount = RREG8(MGAREG_VCOUNT); 613414c4531SDave Airlie if (tmpcount < vcount) 614414c4531SDave Airlie vcount = 0; 615414c4531SDave Airlie if ((tmpcount - vcount) > 2) 616414c4531SDave Airlie pll_locked = true; 617414c4531SDave Airlie else 618414c4531SDave Airlie udelay(5); 619414c4531SDave Airlie } 620414c4531SDave Airlie } 621414c4531SDave Airlie 622414c4531SDave Airlie return 0; 623414c4531SDave Airlie } 624414c4531SDave Airlie 625414c4531SDave Airlie static int mga_g200er_set_plls(struct mga_device *mdev, long clock) 626414c4531SDave Airlie { 627414c4531SDave Airlie unsigned int vcomax, vcomin, pllreffreq; 628414c4531SDave Airlie unsigned int delta, tmpdelta; 6299830605dSDave Airlie int testr, testn, testm, testo; 630414c4531SDave Airlie unsigned int p, m, n; 6319830605dSDave Airlie unsigned int computed, vco; 632414c4531SDave Airlie int tmp; 6339830605dSDave Airlie const unsigned int m_div_val[] = { 1, 2, 4, 8 }; 634414c4531SDave Airlie 635414c4531SDave Airlie m = n = p = 0; 636414c4531SDave Airlie vcomax = 1488000; 637414c4531SDave Airlie vcomin = 1056000; 638414c4531SDave Airlie pllreffreq = 48000; 639414c4531SDave Airlie 640414c4531SDave Airlie delta = 0xffffffff; 641414c4531SDave Airlie 642414c4531SDave Airlie for (testr = 0; testr < 4; testr++) { 643414c4531SDave Airlie if (delta == 0) 644414c4531SDave Airlie break; 645414c4531SDave Airlie for (testn = 5; testn < 129; testn++) { 646414c4531SDave Airlie if (delta == 0) 647414c4531SDave Airlie break; 648414c4531SDave Airlie for (testm = 3; testm >= 0; testm--) { 649414c4531SDave Airlie if (delta == 0) 650414c4531SDave Airlie break; 651414c4531SDave Airlie for (testo = 5; testo < 33; testo++) { 6529830605dSDave Airlie vco = pllreffreq * (testn + 1) / 653414c4531SDave Airlie (testr + 1); 6549830605dSDave Airlie if (vco < vcomin) 655414c4531SDave Airlie continue; 6569830605dSDave Airlie if (vco > vcomax) 657414c4531SDave Airlie continue; 6589830605dSDave Airlie computed = vco / (m_div_val[testm] * (testo + 1)); 659414c4531SDave Airlie if (computed > clock) 660414c4531SDave Airlie tmpdelta = computed - clock; 661414c4531SDave Airlie else 662414c4531SDave Airlie tmpdelta = clock - computed; 663414c4531SDave Airlie if (tmpdelta < delta) { 664414c4531SDave Airlie delta = tmpdelta; 665414c4531SDave Airlie m = testm | (testo << 3); 666414c4531SDave Airlie n = testn; 667414c4531SDave Airlie p = testr | (testr << 3); 668414c4531SDave Airlie } 669414c4531SDave Airlie } 670414c4531SDave Airlie } 671414c4531SDave Airlie } 672414c4531SDave Airlie } 673414c4531SDave Airlie 674414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 675414c4531SDave Airlie tmp = RREG8(DAC_DATA); 676414c4531SDave Airlie tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS; 677fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 678414c4531SDave Airlie 679414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_REMHEADCTL); 680414c4531SDave Airlie tmp = RREG8(DAC_DATA); 681414c4531SDave Airlie tmp |= MGA1064_REMHEADCTL_CLKDIS; 682fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 683414c4531SDave Airlie 684414c4531SDave Airlie tmp = RREG8(MGAREG_MEM_MISC_READ); 685414c4531SDave Airlie tmp |= (0x3<<2) | 0xc0; 686414c4531SDave Airlie WREG8(MGAREG_MEM_MISC_WRITE, tmp); 687414c4531SDave Airlie 688414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 689414c4531SDave Airlie tmp = RREG8(DAC_DATA); 690414c4531SDave Airlie tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS; 691414c4531SDave Airlie tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; 692fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 693414c4531SDave Airlie 694414c4531SDave Airlie udelay(500); 695414c4531SDave Airlie 696414c4531SDave Airlie WREG_DAC(MGA1064_ER_PIX_PLLC_N, n); 697414c4531SDave Airlie WREG_DAC(MGA1064_ER_PIX_PLLC_M, m); 698414c4531SDave Airlie WREG_DAC(MGA1064_ER_PIX_PLLC_P, p); 699414c4531SDave Airlie 700414c4531SDave Airlie udelay(50); 701414c4531SDave Airlie 702414c4531SDave Airlie return 0; 703414c4531SDave Airlie } 704414c4531SDave Airlie 705414c4531SDave Airlie static int mga_crtc_set_plls(struct mga_device *mdev, long clock) 706414c4531SDave Airlie { 707*db05f8d3SThomas Zimmermann u8 misc; 708*db05f8d3SThomas Zimmermann 709414c4531SDave Airlie switch(mdev->type) { 710414c4531SDave Airlie case G200_SE_A: 711414c4531SDave Airlie case G200_SE_B: 712414c4531SDave Airlie return mga_g200se_set_plls(mdev, clock); 713414c4531SDave Airlie break; 714414c4531SDave Airlie case G200_WB: 7156d857c18SMathieu Larouche case G200_EW3: 716414c4531SDave Airlie return mga_g200wb_set_plls(mdev, clock); 717414c4531SDave Airlie break; 718414c4531SDave Airlie case G200_EV: 719414c4531SDave Airlie return mga_g200ev_set_plls(mdev, clock); 720414c4531SDave Airlie break; 721414c4531SDave Airlie case G200_EH: 722f0493e65SMathieu Larouche case G200_EH3: 723414c4531SDave Airlie return mga_g200eh_set_plls(mdev, clock); 724414c4531SDave Airlie break; 725414c4531SDave Airlie case G200_ER: 726414c4531SDave Airlie return mga_g200er_set_plls(mdev, clock); 727414c4531SDave Airlie break; 728414c4531SDave Airlie } 729*db05f8d3SThomas Zimmermann 730*db05f8d3SThomas Zimmermann misc = RREG8(MGA_MISC_IN); 731*db05f8d3SThomas Zimmermann misc &= ~MGAREG_MISC_CLK_SEL_MASK; 732*db05f8d3SThomas Zimmermann misc |= MGAREG_MISC_CLK_SEL_MGA_MSK; 733*db05f8d3SThomas Zimmermann WREG8(MGA_MISC_OUT, misc); 734*db05f8d3SThomas Zimmermann 735414c4531SDave Airlie return 0; 736414c4531SDave Airlie } 737414c4531SDave Airlie 738414c4531SDave Airlie static void mga_g200wb_prepare(struct drm_crtc *crtc) 739414c4531SDave Airlie { 7408d8ff2a9SThomas Zimmermann struct mga_device *mdev = to_mga_device(crtc->dev); 741414c4531SDave Airlie u8 tmp; 742414c4531SDave Airlie int iter_max; 743414c4531SDave Airlie 744414c4531SDave Airlie /* 1- The first step is to warn the BMC of an upcoming mode change. 745414c4531SDave Airlie * We are putting the misc<0> to output.*/ 746414c4531SDave Airlie 747414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_GEN_IO_CTL); 748414c4531SDave Airlie tmp = RREG8(DAC_DATA); 749414c4531SDave Airlie tmp |= 0x10; 750414c4531SDave Airlie WREG_DAC(MGA1064_GEN_IO_CTL, tmp); 751414c4531SDave Airlie 752414c4531SDave Airlie /* we are putting a 1 on the misc<0> line */ 753414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_GEN_IO_DATA); 754414c4531SDave Airlie tmp = RREG8(DAC_DATA); 755414c4531SDave Airlie tmp |= 0x10; 756414c4531SDave Airlie WREG_DAC(MGA1064_GEN_IO_DATA, tmp); 757414c4531SDave Airlie 758414c4531SDave Airlie /* 2- Second step to mask and further scan request 759414c4531SDave Airlie * This will be done by asserting the remfreqmsk bit (XSPAREREG<7>) 760414c4531SDave Airlie */ 761414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_SPAREREG); 762414c4531SDave Airlie tmp = RREG8(DAC_DATA); 763414c4531SDave Airlie tmp |= 0x80; 764414c4531SDave Airlie WREG_DAC(MGA1064_SPAREREG, tmp); 765414c4531SDave Airlie 766414c4531SDave Airlie /* 3a- the third step is to verifu if there is an active scan 767414c4531SDave Airlie * We are searching for a 0 on remhsyncsts <XSPAREREG<0>) 768414c4531SDave Airlie */ 769414c4531SDave Airlie iter_max = 300; 770414c4531SDave Airlie while (!(tmp & 0x1) && iter_max) { 771414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_SPAREREG); 772414c4531SDave Airlie tmp = RREG8(DAC_DATA); 773414c4531SDave Airlie udelay(1000); 774414c4531SDave Airlie iter_max--; 775414c4531SDave Airlie } 776414c4531SDave Airlie 777414c4531SDave Airlie /* 3b- this step occurs only if the remove is actually scanning 778414c4531SDave Airlie * we are waiting for the end of the frame which is a 1 on 779414c4531SDave Airlie * remvsyncsts (XSPAREREG<1>) 780414c4531SDave Airlie */ 781414c4531SDave Airlie if (iter_max) { 782414c4531SDave Airlie iter_max = 300; 783414c4531SDave Airlie while ((tmp & 0x2) && iter_max) { 784414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_SPAREREG); 785414c4531SDave Airlie tmp = RREG8(DAC_DATA); 786414c4531SDave Airlie udelay(1000); 787414c4531SDave Airlie iter_max--; 788414c4531SDave Airlie } 789414c4531SDave Airlie } 790414c4531SDave Airlie } 791414c4531SDave Airlie 792414c4531SDave Airlie static void mga_g200wb_commit(struct drm_crtc *crtc) 793414c4531SDave Airlie { 794414c4531SDave Airlie u8 tmp; 7958d8ff2a9SThomas Zimmermann struct mga_device *mdev = to_mga_device(crtc->dev); 796414c4531SDave Airlie 797414c4531SDave Airlie /* 1- The first step is to ensure that the vrsten and hrsten are set */ 798414c4531SDave Airlie WREG8(MGAREG_CRTCEXT_INDEX, 1); 799414c4531SDave Airlie tmp = RREG8(MGAREG_CRTCEXT_DATA); 800414c4531SDave Airlie WREG8(MGAREG_CRTCEXT_DATA, tmp | 0x88); 801414c4531SDave Airlie 802414c4531SDave Airlie /* 2- second step is to assert the rstlvl2 */ 803414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_REMHEADCTL2); 804414c4531SDave Airlie tmp = RREG8(DAC_DATA); 805414c4531SDave Airlie tmp |= 0x8; 806414c4531SDave Airlie WREG8(DAC_DATA, tmp); 807414c4531SDave Airlie 808414c4531SDave Airlie /* wait 10 us */ 809414c4531SDave Airlie udelay(10); 810414c4531SDave Airlie 811414c4531SDave Airlie /* 3- deassert rstlvl2 */ 812414c4531SDave Airlie tmp &= ~0x08; 813414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_REMHEADCTL2); 814414c4531SDave Airlie WREG8(DAC_DATA, tmp); 815414c4531SDave Airlie 816414c4531SDave Airlie /* 4- remove mask of scan request */ 817414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_SPAREREG); 818414c4531SDave Airlie tmp = RREG8(DAC_DATA); 819414c4531SDave Airlie tmp &= ~0x80; 820414c4531SDave Airlie WREG8(DAC_DATA, tmp); 821414c4531SDave Airlie 822414c4531SDave Airlie /* 5- put back a 0 on the misc<0> line */ 823414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_GEN_IO_DATA); 824414c4531SDave Airlie tmp = RREG8(DAC_DATA); 825414c4531SDave Airlie tmp &= ~0x10; 826414c4531SDave Airlie WREG_DAC(MGA1064_GEN_IO_DATA, tmp); 827414c4531SDave Airlie } 828414c4531SDave Airlie 8299f1d0366SChristopher Harvey /* 830d6237687SThomas Zimmermann * This is how the framebuffer base address is stored in g200 cards: 831d6237687SThomas Zimmermann * * Assume @offset is the gpu_addr variable of the framebuffer object 832d6237687SThomas Zimmermann * * Then addr is the number of _pixels_ (not bytes) from the start of 833d6237687SThomas Zimmermann * VRAM to the first pixel we want to display. (divided by 2 for 32bit 834d6237687SThomas Zimmermann * framebuffers) 835d6237687SThomas Zimmermann * * addr is stored in the CRTCEXT0, CRTCC and CRTCD registers 836d6237687SThomas Zimmermann * addr<20> -> CRTCEXT0<6> 837d6237687SThomas Zimmermann * addr<19-16> -> CRTCEXT0<3-0> 838d6237687SThomas Zimmermann * addr<15-8> -> CRTCC<7-0> 839d6237687SThomas Zimmermann * addr<7-0> -> CRTCD<7-0> 840d6237687SThomas Zimmermann * 841d6237687SThomas Zimmermann * CRTCEXT0 has to be programmed last to trigger an update and make the 842d6237687SThomas Zimmermann * new addr variable take effect. 8439f1d0366SChristopher Harvey */ 844d6237687SThomas Zimmermann static void mgag200_set_startadd(struct mga_device *mdev, 845d6237687SThomas Zimmermann unsigned long offset) 846414c4531SDave Airlie { 847d6237687SThomas Zimmermann struct drm_device *dev = mdev->dev; 848d6237687SThomas Zimmermann u32 startadd; 849d6237687SThomas Zimmermann u8 crtcc, crtcd, crtcext0; 850414c4531SDave Airlie 851d6237687SThomas Zimmermann startadd = offset / 8; 852414c4531SDave Airlie 853d6237687SThomas Zimmermann /* 854d6237687SThomas Zimmermann * Can't store addresses any higher than that, but we also 855d6237687SThomas Zimmermann * don't have more than 16 MiB of memory, so it should be fine. 856d6237687SThomas Zimmermann */ 857d6237687SThomas Zimmermann drm_WARN_ON(dev, startadd > 0x1fffff); 858414c4531SDave Airlie 859d6237687SThomas Zimmermann RREG_ECRT(0x00, crtcext0); 860d6237687SThomas Zimmermann 861d6237687SThomas Zimmermann crtcc = (startadd >> 8) & 0xff; 862d6237687SThomas Zimmermann crtcd = startadd & 0xff; 863d6237687SThomas Zimmermann crtcext0 &= 0xb0; 864d6237687SThomas Zimmermann crtcext0 |= ((startadd >> 14) & BIT(6)) | 865d6237687SThomas Zimmermann ((startadd >> 16) & 0x0f); 866d6237687SThomas Zimmermann 867d6237687SThomas Zimmermann WREG_CRT(0x0c, crtcc); 868d6237687SThomas Zimmermann WREG_CRT(0x0d, crtcd); 869d6237687SThomas Zimmermann WREG_ECRT(0x00, crtcext0); 870414c4531SDave Airlie } 871414c4531SDave Airlie 872fb724f1eSThomas Zimmermann static int mga_crtc_do_set_base(struct mga_device *mdev, 873fb724f1eSThomas Zimmermann const struct drm_framebuffer *fb, 874fb724f1eSThomas Zimmermann const struct drm_framebuffer *old_fb) 875414c4531SDave Airlie { 876ebb04eb3SThomas Zimmermann struct drm_gem_vram_object *gbo; 877414c4531SDave Airlie int ret; 878ebb04eb3SThomas Zimmermann s64 gpu_addr; 879414c4531SDave Airlie 880fb724f1eSThomas Zimmermann if (old_fb) { 881fb724f1eSThomas Zimmermann gbo = drm_gem_vram_of_gem(old_fb->obj[0]); 88281da87f6SThomas Zimmermann drm_gem_vram_unpin(gbo); 883414c4531SDave Airlie } 884414c4531SDave Airlie 885fb724f1eSThomas Zimmermann gbo = drm_gem_vram_of_gem(fb->obj[0]); 886414c4531SDave Airlie 887ebb04eb3SThomas Zimmermann ret = drm_gem_vram_pin(gbo, DRM_GEM_VRAM_PL_FLAG_VRAM); 888ebb04eb3SThomas Zimmermann if (ret) 8895b24f715SThomas Zimmermann return ret; 890ebb04eb3SThomas Zimmermann gpu_addr = drm_gem_vram_offset(gbo); 891ebb04eb3SThomas Zimmermann if (gpu_addr < 0) { 892ebb04eb3SThomas Zimmermann ret = (int)gpu_addr; 893ebb04eb3SThomas Zimmermann goto err_drm_gem_vram_unpin; 894414c4531SDave Airlie } 895414c4531SDave Airlie 896d6237687SThomas Zimmermann mgag200_set_startadd(mdev, (unsigned long)gpu_addr); 897414c4531SDave Airlie 898414c4531SDave Airlie return 0; 899ebb04eb3SThomas Zimmermann 900ebb04eb3SThomas Zimmermann err_drm_gem_vram_unpin: 901ebb04eb3SThomas Zimmermann drm_gem_vram_unpin(gbo); 902ebb04eb3SThomas Zimmermann return ret; 903414c4531SDave Airlie } 904414c4531SDave Airlie 905414c4531SDave Airlie static int mga_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, 906414c4531SDave Airlie struct drm_framebuffer *old_fb) 907414c4531SDave Airlie { 908d6237687SThomas Zimmermann struct drm_device *dev = crtc->dev; 909d6237687SThomas Zimmermann struct mga_device *mdev = dev->dev_private; 910fb724f1eSThomas Zimmermann struct drm_framebuffer *fb = crtc->primary->fb; 911d6237687SThomas Zimmermann unsigned int count; 912d6237687SThomas Zimmermann 913d6237687SThomas Zimmermann do { } while (RREG8(0x1fda) & 0x08); 914d6237687SThomas Zimmermann do { } while (!(RREG8(0x1fda) & 0x08)); 915d6237687SThomas Zimmermann 916d6237687SThomas Zimmermann count = RREG8(MGAREG_VCOUNT) + 2; 917d6237687SThomas Zimmermann do { } while (RREG8(MGAREG_VCOUNT) < count); 918d6237687SThomas Zimmermann 919fb724f1eSThomas Zimmermann return mga_crtc_do_set_base(mdev, fb, old_fb); 920414c4531SDave Airlie } 921414c4531SDave Airlie 922a6edae07SThomas Zimmermann static void mgag200_set_mode_regs(struct mga_device *mdev, 923a6edae07SThomas Zimmermann const struct drm_display_mode *mode) 924a6edae07SThomas Zimmermann { 925a6edae07SThomas Zimmermann unsigned int hdisplay, hsyncstart, hsyncend, htotal; 926a6edae07SThomas Zimmermann unsigned int vdisplay, vsyncstart, vsyncend, vtotal; 927*db05f8d3SThomas Zimmermann u8 misc, crtcext1, crtcext2, crtcext5; 928a6edae07SThomas Zimmermann 929a6edae07SThomas Zimmermann hdisplay = mode->hdisplay / 8 - 1; 930a6edae07SThomas Zimmermann hsyncstart = mode->hsync_start / 8 - 1; 931a6edae07SThomas Zimmermann hsyncend = mode->hsync_end / 8 - 1; 932a6edae07SThomas Zimmermann htotal = mode->htotal / 8 - 1; 933a6edae07SThomas Zimmermann 934a6edae07SThomas Zimmermann /* Work around hardware quirk */ 935a6edae07SThomas Zimmermann if ((htotal & 0x07) == 0x06 || (htotal & 0x07) == 0x04) 936a6edae07SThomas Zimmermann htotal++; 937a6edae07SThomas Zimmermann 938a6edae07SThomas Zimmermann vdisplay = mode->vdisplay - 1; 939a6edae07SThomas Zimmermann vsyncstart = mode->vsync_start - 1; 940a6edae07SThomas Zimmermann vsyncend = mode->vsync_end - 1; 941a6edae07SThomas Zimmermann vtotal = mode->vtotal - 2; 942a6edae07SThomas Zimmermann 943*db05f8d3SThomas Zimmermann misc = RREG8(MGA_MISC_IN); 944*db05f8d3SThomas Zimmermann 945a6edae07SThomas Zimmermann if (mode->flags & DRM_MODE_FLAG_NHSYNC) 946*db05f8d3SThomas Zimmermann misc |= MGAREG_MISC_HSYNCPOL; 947*db05f8d3SThomas Zimmermann else 948*db05f8d3SThomas Zimmermann misc &= ~MGAREG_MISC_HSYNCPOL; 949*db05f8d3SThomas Zimmermann 950a6edae07SThomas Zimmermann if (mode->flags & DRM_MODE_FLAG_NVSYNC) 951*db05f8d3SThomas Zimmermann misc |= MGAREG_MISC_VSYNCPOL; 952*db05f8d3SThomas Zimmermann else 953*db05f8d3SThomas Zimmermann misc &= ~MGAREG_MISC_VSYNCPOL; 954a6edae07SThomas Zimmermann 955a6edae07SThomas Zimmermann crtcext1 = (((htotal - 4) & 0x100) >> 8) | 956a6edae07SThomas Zimmermann ((hdisplay & 0x100) >> 7) | 957a6edae07SThomas Zimmermann ((hsyncstart & 0x100) >> 6) | 958a6edae07SThomas Zimmermann (htotal & 0x40); 959a6edae07SThomas Zimmermann if (mdev->type == G200_WB || mdev->type == G200_EW3) 960a6edae07SThomas Zimmermann crtcext1 |= BIT(7) | /* vrsten */ 961a6edae07SThomas Zimmermann BIT(3); /* hrsten */ 962a6edae07SThomas Zimmermann 963a6edae07SThomas Zimmermann crtcext2 = ((vtotal & 0xc00) >> 10) | 964a6edae07SThomas Zimmermann ((vdisplay & 0x400) >> 8) | 965a6edae07SThomas Zimmermann ((vdisplay & 0xc00) >> 7) | 966a6edae07SThomas Zimmermann ((vsyncstart & 0xc00) >> 5) | 967a6edae07SThomas Zimmermann ((vdisplay & 0x400) >> 3); 968a6edae07SThomas Zimmermann crtcext5 = 0x00; 969a6edae07SThomas Zimmermann 970a6edae07SThomas Zimmermann WREG_CRT(0, htotal - 4); 971a6edae07SThomas Zimmermann WREG_CRT(1, hdisplay); 972a6edae07SThomas Zimmermann WREG_CRT(2, hdisplay); 973a6edae07SThomas Zimmermann WREG_CRT(3, (htotal & 0x1F) | 0x80); 974a6edae07SThomas Zimmermann WREG_CRT(4, hsyncstart); 975a6edae07SThomas Zimmermann WREG_CRT(5, ((htotal & 0x20) << 2) | (hsyncend & 0x1F)); 976a6edae07SThomas Zimmermann WREG_CRT(6, vtotal & 0xFF); 977a6edae07SThomas Zimmermann WREG_CRT(7, ((vtotal & 0x100) >> 8) | 978a6edae07SThomas Zimmermann ((vdisplay & 0x100) >> 7) | 979a6edae07SThomas Zimmermann ((vsyncstart & 0x100) >> 6) | 980a6edae07SThomas Zimmermann ((vdisplay & 0x100) >> 5) | 981a6edae07SThomas Zimmermann ((vdisplay & 0x100) >> 4) | /* linecomp */ 982a6edae07SThomas Zimmermann ((vtotal & 0x200) >> 4) | 983a6edae07SThomas Zimmermann ((vdisplay & 0x200) >> 3) | 984a6edae07SThomas Zimmermann ((vsyncstart & 0x200) >> 2)); 985a6edae07SThomas Zimmermann WREG_CRT(9, ((vdisplay & 0x200) >> 4) | 986a6edae07SThomas Zimmermann ((vdisplay & 0x200) >> 3)); 987a6edae07SThomas Zimmermann WREG_CRT(16, vsyncstart & 0xFF); 988a6edae07SThomas Zimmermann WREG_CRT(17, (vsyncend & 0x0F) | 0x20); 989a6edae07SThomas Zimmermann WREG_CRT(18, vdisplay & 0xFF); 990a6edae07SThomas Zimmermann WREG_CRT(20, 0); 991a6edae07SThomas Zimmermann WREG_CRT(21, vdisplay & 0xFF); 992a6edae07SThomas Zimmermann WREG_CRT(22, (vtotal + 1) & 0xFF); 993a6edae07SThomas Zimmermann WREG_CRT(23, 0xc3); 994a6edae07SThomas Zimmermann WREG_CRT(24, vdisplay & 0xFF); 995a6edae07SThomas Zimmermann 996a6edae07SThomas Zimmermann WREG_ECRT(0x01, crtcext1); 997a6edae07SThomas Zimmermann WREG_ECRT(0x02, crtcext2); 998a6edae07SThomas Zimmermann WREG_ECRT(0x05, crtcext5); 999*db05f8d3SThomas Zimmermann 1000*db05f8d3SThomas Zimmermann WREG8(MGA_MISC_OUT, misc); 1001*db05f8d3SThomas Zimmermann 1002*db05f8d3SThomas Zimmermann mga_crtc_set_plls(mdev, mode->clock); 1003a6edae07SThomas Zimmermann } 1004a6edae07SThomas Zimmermann 1005414c4531SDave Airlie static int mga_crtc_mode_set(struct drm_crtc *crtc, 1006414c4531SDave Airlie struct drm_display_mode *mode, 1007414c4531SDave Airlie struct drm_display_mode *adjusted_mode, 1008414c4531SDave Airlie int x, int y, struct drm_framebuffer *old_fb) 1009414c4531SDave Airlie { 1010414c4531SDave Airlie struct drm_device *dev = crtc->dev; 10118d8ff2a9SThomas Zimmermann struct mga_device *mdev = to_mga_device(dev); 101272952757SVille Syrjälä const struct drm_framebuffer *fb = crtc->primary->fb; 1013414c4531SDave Airlie int pitch; 1014414c4531SDave Airlie int option = 0, option2 = 0; 1015414c4531SDave Airlie int i; 1016414c4531SDave Airlie unsigned char misc = 0; 1017414c4531SDave Airlie unsigned char ext_vga[6]; 1018414c4531SDave Airlie u8 bppshift; 1019414c4531SDave Airlie 1020414c4531SDave Airlie static unsigned char dacvalue[] = { 1021414c4531SDave Airlie /* 0x00: */ 0, 0, 0, 0, 0, 0, 0x00, 0, 1022414c4531SDave Airlie /* 0x08: */ 0, 0, 0, 0, 0, 0, 0, 0, 1023414c4531SDave Airlie /* 0x10: */ 0, 0, 0, 0, 0, 0, 0, 0, 1024414c4531SDave Airlie /* 0x18: */ 0x00, 0, 0xC9, 0xFF, 0xBF, 0x20, 0x1F, 0x20, 1025414c4531SDave Airlie /* 0x20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1026414c4531SDave Airlie /* 0x28: */ 0x00, 0x00, 0x00, 0x00, 0, 0, 0, 0x40, 1027414c4531SDave Airlie /* 0x30: */ 0x00, 0xB0, 0x00, 0xC2, 0x34, 0x14, 0x02, 0x83, 1028414c4531SDave Airlie /* 0x38: */ 0x00, 0x93, 0x00, 0x77, 0x00, 0x00, 0x00, 0x3A, 1029414c4531SDave Airlie /* 0x40: */ 0, 0, 0, 0, 0, 0, 0, 0, 1030414c4531SDave Airlie /* 0x48: */ 0, 0, 0, 0, 0, 0, 0, 0 1031414c4531SDave Airlie }; 1032414c4531SDave Airlie 1033272725c7SVille Syrjälä bppshift = mdev->bpp_shifts[fb->format->cpp[0] - 1]; 1034414c4531SDave Airlie 1035414c4531SDave Airlie switch (mdev->type) { 1036414c4531SDave Airlie case G200_SE_A: 1037414c4531SDave Airlie case G200_SE_B: 1038414c4531SDave Airlie dacvalue[MGA1064_VREF_CTL] = 0x03; 1039414c4531SDave Airlie dacvalue[MGA1064_PIX_CLK_CTL] = MGA1064_PIX_CLK_CTL_SEL_PLL; 1040414c4531SDave Airlie dacvalue[MGA1064_MISC_CTL] = MGA1064_MISC_CTL_DAC_EN | 1041414c4531SDave Airlie MGA1064_MISC_CTL_VGA8 | 1042414c4531SDave Airlie MGA1064_MISC_CTL_DAC_RAM_CS; 1043414c4531SDave Airlie if (mdev->has_sdram) 1044414c4531SDave Airlie option = 0x40049120; 1045414c4531SDave Airlie else 1046414c4531SDave Airlie option = 0x4004d120; 1047414c4531SDave Airlie option2 = 0x00008000; 1048414c4531SDave Airlie break; 1049414c4531SDave Airlie case G200_WB: 10506d857c18SMathieu Larouche case G200_EW3: 1051414c4531SDave Airlie dacvalue[MGA1064_VREF_CTL] = 0x07; 1052414c4531SDave Airlie option = 0x41049120; 1053414c4531SDave Airlie option2 = 0x0000b000; 1054414c4531SDave Airlie break; 1055414c4531SDave Airlie case G200_EV: 1056414c4531SDave Airlie dacvalue[MGA1064_PIX_CLK_CTL] = MGA1064_PIX_CLK_CTL_SEL_PLL; 1057414c4531SDave Airlie dacvalue[MGA1064_MISC_CTL] = MGA1064_MISC_CTL_VGA8 | 1058414c4531SDave Airlie MGA1064_MISC_CTL_DAC_RAM_CS; 1059414c4531SDave Airlie option = 0x00000120; 1060414c4531SDave Airlie option2 = 0x0000b000; 1061414c4531SDave Airlie break; 1062414c4531SDave Airlie case G200_EH: 1063f0493e65SMathieu Larouche case G200_EH3: 1064414c4531SDave Airlie dacvalue[MGA1064_MISC_CTL] = MGA1064_MISC_CTL_VGA8 | 1065414c4531SDave Airlie MGA1064_MISC_CTL_DAC_RAM_CS; 1066414c4531SDave Airlie option = 0x00000120; 1067414c4531SDave Airlie option2 = 0x0000b000; 1068414c4531SDave Airlie break; 1069414c4531SDave Airlie case G200_ER: 1070414c4531SDave Airlie break; 1071414c4531SDave Airlie } 1072414c4531SDave Airlie 1073272725c7SVille Syrjälä switch (fb->format->cpp[0] * 8) { 1074414c4531SDave Airlie case 8: 1075414c4531SDave Airlie dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_8bits; 1076414c4531SDave Airlie break; 1077414c4531SDave Airlie case 16: 1078b00c600eSVille Syrjälä if (fb->format->depth == 15) 1079414c4531SDave Airlie dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_15bits; 1080414c4531SDave Airlie else 1081414c4531SDave Airlie dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_16bits; 1082414c4531SDave Airlie break; 1083414c4531SDave Airlie case 24: 1084414c4531SDave Airlie dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_24bits; 1085414c4531SDave Airlie break; 1086414c4531SDave Airlie case 32: 1087414c4531SDave Airlie dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_32_24bits; 1088414c4531SDave Airlie break; 1089414c4531SDave Airlie } 1090414c4531SDave Airlie 1091414c4531SDave Airlie for (i = 0; i < sizeof(dacvalue); i++) { 10929d8aa55fSChristopher Harvey if ((i <= 0x17) || 1093414c4531SDave Airlie (i == 0x1b) || 1094414c4531SDave Airlie (i == 0x1c) || 1095414c4531SDave Airlie ((i >= 0x1f) && (i <= 0x29)) || 1096414c4531SDave Airlie ((i >= 0x30) && (i <= 0x37))) 1097414c4531SDave Airlie continue; 1098414c4531SDave Airlie if (IS_G200_SE(mdev) && 1099414c4531SDave Airlie ((i == 0x2c) || (i == 0x2d) || (i == 0x2e))) 1100414c4531SDave Airlie continue; 11016d857c18SMathieu Larouche if ((mdev->type == G200_EV || 11026d857c18SMathieu Larouche mdev->type == G200_WB || 11036d857c18SMathieu Larouche mdev->type == G200_EH || 1104f0493e65SMathieu Larouche mdev->type == G200_EW3 || 1105f0493e65SMathieu Larouche mdev->type == G200_EH3) && 1106414c4531SDave Airlie (i >= 0x44) && (i <= 0x4e)) 1107414c4531SDave Airlie continue; 1108414c4531SDave Airlie 1109414c4531SDave Airlie WREG_DAC(i, dacvalue[i]); 1110414c4531SDave Airlie } 1111414c4531SDave Airlie 11121812a3dbSChristopher Harvey if (mdev->type == G200_ER) 11131812a3dbSChristopher Harvey WREG_DAC(0x90, 0); 1114414c4531SDave Airlie 1115414c4531SDave Airlie if (option) 1116414c4531SDave Airlie pci_write_config_dword(dev->pdev, PCI_MGA_OPTION, option); 1117414c4531SDave Airlie if (option2) 1118414c4531SDave Airlie pci_write_config_dword(dev->pdev, PCI_MGA_OPTION2, option2); 1119414c4531SDave Airlie 1120414c4531SDave Airlie WREG_SEQ(2, 0xf); 1121414c4531SDave Airlie WREG_SEQ(3, 0); 1122414c4531SDave Airlie WREG_SEQ(4, 0xe); 1123414c4531SDave Airlie 1124272725c7SVille Syrjälä pitch = fb->pitches[0] / fb->format->cpp[0]; 1125272725c7SVille Syrjälä if (fb->format->cpp[0] * 8 == 24) 1126da558398STakashi Iwai pitch = (pitch * 3) >> (4 - bppshift); 1127414c4531SDave Airlie else 1128414c4531SDave Airlie pitch = pitch >> (4 - bppshift); 1129414c4531SDave Airlie 1130414c4531SDave Airlie WREG_GFX(0, 0); 1131414c4531SDave Airlie WREG_GFX(1, 0); 1132414c4531SDave Airlie WREG_GFX(2, 0); 1133414c4531SDave Airlie WREG_GFX(3, 0); 1134414c4531SDave Airlie WREG_GFX(4, 0); 1135414c4531SDave Airlie WREG_GFX(5, 0x40); 1136414c4531SDave Airlie WREG_GFX(6, 0x5); 1137414c4531SDave Airlie WREG_GFX(7, 0xf); 1138414c4531SDave Airlie WREG_GFX(8, 0xf); 1139414c4531SDave Airlie 1140414c4531SDave Airlie WREG_CRT(10, 0); 1141414c4531SDave Airlie WREG_CRT(11, 0); 1142414c4531SDave Airlie WREG_CRT(12, 0); 1143414c4531SDave Airlie WREG_CRT(13, 0); 1144414c4531SDave Airlie WREG_CRT(14, 0); 1145414c4531SDave Airlie WREG_CRT(15, 0); 1146414c4531SDave Airlie WREG_CRT(19, pitch & 0xFF); 1147a6edae07SThomas Zimmermann 1148a6edae07SThomas Zimmermann mgag200_set_mode_regs(mdev, mode); 1149414c4531SDave Airlie 1150414c4531SDave Airlie ext_vga[0] = 0; 1151414c4531SDave Airlie 1152414c4531SDave Airlie /* TODO interlace */ 1153414c4531SDave Airlie 1154414c4531SDave Airlie ext_vga[0] |= (pitch & 0x300) >> 4; 1155272725c7SVille Syrjälä if (fb->format->cpp[0] * 8 == 24) 1156414c4531SDave Airlie ext_vga[3] = (((1 << bppshift) * 3) - 1) | 0x80; 1157414c4531SDave Airlie else 1158414c4531SDave Airlie ext_vga[3] = ((1 << bppshift) - 1) | 0x80; 1159414c4531SDave Airlie ext_vga[4] = 0; 1160414c4531SDave Airlie 1161a6edae07SThomas Zimmermann WREG_ECRT(0, ext_vga[0]); 1162a6edae07SThomas Zimmermann WREG_ECRT(3, ext_vga[3]); 1163a6edae07SThomas Zimmermann WREG_ECRT(4, ext_vga[4]); 1164414c4531SDave Airlie 1165414c4531SDave Airlie if (mdev->type == G200_ER) 11661812a3dbSChristopher Harvey WREG_ECRT(0x24, 0x5); 1167414c4531SDave Airlie 11686d857c18SMathieu Larouche if (mdev->type == G200_EW3) 11696d857c18SMathieu Larouche WREG_ECRT(0x34, 0x5); 11706d857c18SMathieu Larouche 1171414c4531SDave Airlie if (mdev->type == G200_EV) { 1172414c4531SDave Airlie WREG_ECRT(6, 0); 1173414c4531SDave Airlie } 1174414c4531SDave Airlie 1175414c4531SDave Airlie WREG_ECRT(0, ext_vga[0]); 1176414c4531SDave Airlie 1177*db05f8d3SThomas Zimmermann misc = RREG8(MGA_MISC_IN); 1178*db05f8d3SThomas Zimmermann misc |= MGAREG_MISC_IOADSEL | 1179*db05f8d3SThomas Zimmermann MGAREG_MISC_RAMMAPEN | 1180*db05f8d3SThomas Zimmermann MGAREG_MISC_HIGH_PG_SEL; 1181414c4531SDave Airlie WREG8(MGA_MISC_OUT, misc); 1182414c4531SDave Airlie 1183fb724f1eSThomas Zimmermann mga_crtc_do_set_base(mdev, fb, old_fb); 1184414c4531SDave Airlie 1185414c4531SDave Airlie /* reset tagfifo */ 1186414c4531SDave Airlie if (mdev->type == G200_ER) { 1187414c4531SDave Airlie u32 mem_ctl = RREG32(MGAREG_MEMCTL); 1188414c4531SDave Airlie u8 seq1; 1189414c4531SDave Airlie 1190414c4531SDave Airlie /* screen off */ 1191414c4531SDave Airlie WREG8(MGAREG_SEQ_INDEX, 0x01); 1192414c4531SDave Airlie seq1 = RREG8(MGAREG_SEQ_DATA) | 0x20; 1193414c4531SDave Airlie WREG8(MGAREG_SEQ_DATA, seq1); 1194414c4531SDave Airlie 1195414c4531SDave Airlie WREG32(MGAREG_MEMCTL, mem_ctl | 0x00200000); 1196414c4531SDave Airlie udelay(1000); 1197414c4531SDave Airlie WREG32(MGAREG_MEMCTL, mem_ctl & ~0x00200000); 1198414c4531SDave Airlie 1199414c4531SDave Airlie WREG8(MGAREG_SEQ_DATA, seq1 & ~0x20); 1200414c4531SDave Airlie } 1201414c4531SDave Airlie 1202414c4531SDave Airlie 1203414c4531SDave Airlie if (IS_G200_SE(mdev)) { 12040cbb7381SMathieu Larouche if (mdev->unique_rev_id >= 0x04) { 12050cbb7381SMathieu Larouche WREG8(MGAREG_CRTCEXT_INDEX, 0x06); 12060cbb7381SMathieu Larouche WREG8(MGAREG_CRTCEXT_DATA, 0); 12070cbb7381SMathieu Larouche } else if (mdev->unique_rev_id >= 0x02) { 1208414c4531SDave Airlie u8 hi_pri_lvl; 1209414c4531SDave Airlie u32 bpp; 1210414c4531SDave Airlie u32 mb; 1211414c4531SDave Airlie 1212272725c7SVille Syrjälä if (fb->format->cpp[0] * 8 > 16) 1213414c4531SDave Airlie bpp = 32; 1214272725c7SVille Syrjälä else if (fb->format->cpp[0] * 8 > 8) 1215414c4531SDave Airlie bpp = 16; 1216414c4531SDave Airlie else 1217414c4531SDave Airlie bpp = 8; 1218414c4531SDave Airlie 1219414c4531SDave Airlie mb = (mode->clock * bpp) / 1000; 1220414c4531SDave Airlie if (mb > 3100) 1221414c4531SDave Airlie hi_pri_lvl = 0; 1222414c4531SDave Airlie else if (mb > 2600) 1223414c4531SDave Airlie hi_pri_lvl = 1; 1224414c4531SDave Airlie else if (mb > 1900) 1225414c4531SDave Airlie hi_pri_lvl = 2; 1226414c4531SDave Airlie else if (mb > 1160) 1227414c4531SDave Airlie hi_pri_lvl = 3; 1228414c4531SDave Airlie else if (mb > 440) 1229414c4531SDave Airlie hi_pri_lvl = 4; 1230414c4531SDave Airlie else 1231414c4531SDave Airlie hi_pri_lvl = 5; 1232414c4531SDave Airlie 123391f8f105SChristopher Harvey WREG8(MGAREG_CRTCEXT_INDEX, 0x06); 123491f8f105SChristopher Harvey WREG8(MGAREG_CRTCEXT_DATA, hi_pri_lvl); 1235414c4531SDave Airlie } else { 123691f8f105SChristopher Harvey WREG8(MGAREG_CRTCEXT_INDEX, 0x06); 1237abbee623SJulia Lemire if (mdev->unique_rev_id >= 0x01) 123891f8f105SChristopher Harvey WREG8(MGAREG_CRTCEXT_DATA, 0x03); 1239414c4531SDave Airlie else 124091f8f105SChristopher Harvey WREG8(MGAREG_CRTCEXT_DATA, 0x04); 1241414c4531SDave Airlie } 1242414c4531SDave Airlie } 1243414c4531SDave Airlie return 0; 1244414c4531SDave Airlie } 1245414c4531SDave Airlie 1246414c4531SDave Airlie #if 0 /* code from mjg to attempt D3 on crtc dpms off - revisit later */ 1247414c4531SDave Airlie static int mga_suspend(struct drm_crtc *crtc) 1248414c4531SDave Airlie { 1249414c4531SDave Airlie struct mga_crtc *mga_crtc = to_mga_crtc(crtc); 1250414c4531SDave Airlie struct drm_device *dev = crtc->dev; 1251414c4531SDave Airlie struct mga_device *mdev = dev->dev_private; 1252414c4531SDave Airlie struct pci_dev *pdev = dev->pdev; 1253414c4531SDave Airlie int option; 1254414c4531SDave Airlie 1255414c4531SDave Airlie if (mdev->suspended) 1256414c4531SDave Airlie return 0; 1257414c4531SDave Airlie 1258414c4531SDave Airlie WREG_SEQ(1, 0x20); 1259414c4531SDave Airlie WREG_ECRT(1, 0x30); 1260414c4531SDave Airlie /* Disable the pixel clock */ 1261414c4531SDave Airlie WREG_DAC(0x1a, 0x05); 1262414c4531SDave Airlie /* Power down the DAC */ 1263414c4531SDave Airlie WREG_DAC(0x1e, 0x18); 1264414c4531SDave Airlie /* Power down the pixel PLL */ 1265414c4531SDave Airlie WREG_DAC(0x1a, 0x0d); 1266414c4531SDave Airlie 1267414c4531SDave Airlie /* Disable PLLs and clocks */ 1268414c4531SDave Airlie pci_read_config_dword(pdev, PCI_MGA_OPTION, &option); 1269414c4531SDave Airlie option &= ~(0x1F8024); 1270414c4531SDave Airlie pci_write_config_dword(pdev, PCI_MGA_OPTION, option); 1271414c4531SDave Airlie pci_set_power_state(pdev, PCI_D3hot); 1272414c4531SDave Airlie pci_disable_device(pdev); 1273414c4531SDave Airlie 1274414c4531SDave Airlie mdev->suspended = true; 1275414c4531SDave Airlie 1276414c4531SDave Airlie return 0; 1277414c4531SDave Airlie } 1278414c4531SDave Airlie 1279414c4531SDave Airlie static int mga_resume(struct drm_crtc *crtc) 1280414c4531SDave Airlie { 1281414c4531SDave Airlie struct mga_crtc *mga_crtc = to_mga_crtc(crtc); 1282414c4531SDave Airlie struct drm_device *dev = crtc->dev; 1283414c4531SDave Airlie struct mga_device *mdev = dev->dev_private; 1284414c4531SDave Airlie struct pci_dev *pdev = dev->pdev; 1285414c4531SDave Airlie int option; 1286414c4531SDave Airlie 1287414c4531SDave Airlie if (!mdev->suspended) 1288414c4531SDave Airlie return 0; 1289414c4531SDave Airlie 1290414c4531SDave Airlie pci_set_power_state(pdev, PCI_D0); 1291414c4531SDave Airlie pci_enable_device(pdev); 1292414c4531SDave Airlie 1293414c4531SDave Airlie /* Disable sysclk */ 1294414c4531SDave Airlie pci_read_config_dword(pdev, PCI_MGA_OPTION, &option); 1295414c4531SDave Airlie option &= ~(0x4); 1296414c4531SDave Airlie pci_write_config_dword(pdev, PCI_MGA_OPTION, option); 1297414c4531SDave Airlie 1298414c4531SDave Airlie mdev->suspended = false; 1299414c4531SDave Airlie 1300414c4531SDave Airlie return 0; 1301414c4531SDave Airlie } 1302414c4531SDave Airlie 1303414c4531SDave Airlie #endif 1304414c4531SDave Airlie 1305414c4531SDave Airlie static void mga_crtc_dpms(struct drm_crtc *crtc, int mode) 1306414c4531SDave Airlie { 1307414c4531SDave Airlie struct drm_device *dev = crtc->dev; 13088d8ff2a9SThomas Zimmermann struct mga_device *mdev = to_mga_device(dev); 1309414c4531SDave Airlie u8 seq1 = 0, crtcext1 = 0; 1310414c4531SDave Airlie 1311414c4531SDave Airlie switch (mode) { 1312414c4531SDave Airlie case DRM_MODE_DPMS_ON: 1313414c4531SDave Airlie seq1 = 0; 1314414c4531SDave Airlie crtcext1 = 0; 1315414c4531SDave Airlie mga_crtc_load_lut(crtc); 1316414c4531SDave Airlie break; 1317414c4531SDave Airlie case DRM_MODE_DPMS_STANDBY: 1318414c4531SDave Airlie seq1 = 0x20; 1319414c4531SDave Airlie crtcext1 = 0x10; 1320414c4531SDave Airlie break; 1321414c4531SDave Airlie case DRM_MODE_DPMS_SUSPEND: 1322414c4531SDave Airlie seq1 = 0x20; 1323414c4531SDave Airlie crtcext1 = 0x20; 1324414c4531SDave Airlie break; 1325414c4531SDave Airlie case DRM_MODE_DPMS_OFF: 1326414c4531SDave Airlie seq1 = 0x20; 1327414c4531SDave Airlie crtcext1 = 0x30; 1328414c4531SDave Airlie break; 1329414c4531SDave Airlie } 1330414c4531SDave Airlie 1331414c4531SDave Airlie #if 0 1332414c4531SDave Airlie if (mode == DRM_MODE_DPMS_OFF) { 1333414c4531SDave Airlie mga_suspend(crtc); 1334414c4531SDave Airlie } 1335414c4531SDave Airlie #endif 1336414c4531SDave Airlie WREG8(MGAREG_SEQ_INDEX, 0x01); 1337414c4531SDave Airlie seq1 |= RREG8(MGAREG_SEQ_DATA) & ~0x20; 1338414c4531SDave Airlie mga_wait_vsync(mdev); 1339414c4531SDave Airlie mga_wait_busy(mdev); 1340414c4531SDave Airlie WREG8(MGAREG_SEQ_DATA, seq1); 1341414c4531SDave Airlie msleep(20); 1342414c4531SDave Airlie WREG8(MGAREG_CRTCEXT_INDEX, 0x01); 1343414c4531SDave Airlie crtcext1 |= RREG8(MGAREG_CRTCEXT_DATA) & ~0x30; 1344414c4531SDave Airlie WREG8(MGAREG_CRTCEXT_DATA, crtcext1); 1345414c4531SDave Airlie 1346414c4531SDave Airlie #if 0 1347414c4531SDave Airlie if (mode == DRM_MODE_DPMS_ON && mdev->suspended == true) { 1348414c4531SDave Airlie mga_resume(crtc); 1349414c4531SDave Airlie drm_helper_resume_force_mode(dev); 1350414c4531SDave Airlie } 1351414c4531SDave Airlie #endif 1352414c4531SDave Airlie } 1353414c4531SDave Airlie 1354414c4531SDave Airlie /* 1355414c4531SDave Airlie * This is called before a mode is programmed. A typical use might be to 1356414c4531SDave Airlie * enable DPMS during the programming to avoid seeing intermediate stages, 1357414c4531SDave Airlie * but that's not relevant to us 1358414c4531SDave Airlie */ 1359414c4531SDave Airlie static void mga_crtc_prepare(struct drm_crtc *crtc) 1360414c4531SDave Airlie { 1361414c4531SDave Airlie struct drm_device *dev = crtc->dev; 13628d8ff2a9SThomas Zimmermann struct mga_device *mdev = to_mga_device(dev); 1363414c4531SDave Airlie u8 tmp; 1364414c4531SDave Airlie 1365414c4531SDave Airlie /* mga_resume(crtc);*/ 1366414c4531SDave Airlie 1367414c4531SDave Airlie WREG8(MGAREG_CRTC_INDEX, 0x11); 1368414c4531SDave Airlie tmp = RREG8(MGAREG_CRTC_DATA); 1369414c4531SDave Airlie WREG_CRT(0x11, tmp | 0x80); 1370414c4531SDave Airlie 1371414c4531SDave Airlie if (mdev->type == G200_SE_A || mdev->type == G200_SE_B) { 1372414c4531SDave Airlie WREG_SEQ(0, 1); 1373414c4531SDave Airlie msleep(50); 1374414c4531SDave Airlie WREG_SEQ(1, 0x20); 1375414c4531SDave Airlie msleep(20); 1376414c4531SDave Airlie } else { 1377414c4531SDave Airlie WREG8(MGAREG_SEQ_INDEX, 0x1); 1378414c4531SDave Airlie tmp = RREG8(MGAREG_SEQ_DATA); 1379414c4531SDave Airlie 1380414c4531SDave Airlie /* start sync reset */ 1381414c4531SDave Airlie WREG_SEQ(0, 1); 1382414c4531SDave Airlie WREG_SEQ(1, tmp | 0x20); 1383414c4531SDave Airlie } 1384414c4531SDave Airlie 13856d857c18SMathieu Larouche if (mdev->type == G200_WB || mdev->type == G200_EW3) 1386414c4531SDave Airlie mga_g200wb_prepare(crtc); 1387414c4531SDave Airlie 1388414c4531SDave Airlie WREG_CRT(17, 0); 1389414c4531SDave Airlie } 1390414c4531SDave Airlie 1391414c4531SDave Airlie /* 1392414c4531SDave Airlie * This is called after a mode is programmed. It should reverse anything done 1393414c4531SDave Airlie * by the prepare function 1394414c4531SDave Airlie */ 1395414c4531SDave Airlie static void mga_crtc_commit(struct drm_crtc *crtc) 1396414c4531SDave Airlie { 1397414c4531SDave Airlie struct drm_device *dev = crtc->dev; 13988d8ff2a9SThomas Zimmermann struct mga_device *mdev = to_mga_device(dev); 1399d584ff82SJani Nikula const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; 1400414c4531SDave Airlie u8 tmp; 1401414c4531SDave Airlie 14026d857c18SMathieu Larouche if (mdev->type == G200_WB || mdev->type == G200_EW3) 1403414c4531SDave Airlie mga_g200wb_commit(crtc); 1404414c4531SDave Airlie 1405414c4531SDave Airlie if (mdev->type == G200_SE_A || mdev->type == G200_SE_B) { 1406414c4531SDave Airlie msleep(50); 1407414c4531SDave Airlie WREG_SEQ(1, 0x0); 1408414c4531SDave Airlie msleep(20); 1409414c4531SDave Airlie WREG_SEQ(0, 0x3); 1410414c4531SDave Airlie } else { 1411414c4531SDave Airlie WREG8(MGAREG_SEQ_INDEX, 0x1); 1412414c4531SDave Airlie tmp = RREG8(MGAREG_SEQ_DATA); 1413414c4531SDave Airlie 1414414c4531SDave Airlie tmp &= ~0x20; 1415414c4531SDave Airlie WREG_SEQ(0x1, tmp); 1416414c4531SDave Airlie WREG_SEQ(0, 3); 1417414c4531SDave Airlie } 1418414c4531SDave Airlie crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); 1419414c4531SDave Airlie } 1420414c4531SDave Airlie 1421414c4531SDave Airlie /* 1422414c4531SDave Airlie * The core can pass us a set of gamma values to program. We actually only 1423414c4531SDave Airlie * use this for 8-bit mode so can't perform smooth fades on deeper modes, 1424414c4531SDave Airlie * but it's a requirement that we provide the function 1425414c4531SDave Airlie */ 14267ea77283SMaarten Lankhorst static int mga_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, 14276d124ff8SDaniel Vetter u16 *blue, uint32_t size, 14286d124ff8SDaniel Vetter struct drm_modeset_acquire_ctx *ctx) 1429414c4531SDave Airlie { 1430414c4531SDave Airlie mga_crtc_load_lut(crtc); 14317ea77283SMaarten Lankhorst 14327ea77283SMaarten Lankhorst return 0; 1433414c4531SDave Airlie } 1434414c4531SDave Airlie 1435414c4531SDave Airlie /* Simple cleanup function */ 1436414c4531SDave Airlie static void mga_crtc_destroy(struct drm_crtc *crtc) 1437414c4531SDave Airlie { 1438414c4531SDave Airlie struct mga_crtc *mga_crtc = to_mga_crtc(crtc); 1439414c4531SDave Airlie 1440414c4531SDave Airlie drm_crtc_cleanup(crtc); 1441414c4531SDave Airlie kfree(mga_crtc); 1442414c4531SDave Airlie } 1443414c4531SDave Airlie 144464c29076SEgbert Eich static void mga_crtc_disable(struct drm_crtc *crtc) 144564c29076SEgbert Eich { 144664c29076SEgbert Eich DRM_DEBUG_KMS("\n"); 144764c29076SEgbert Eich mga_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); 1448f4510a27SMatt Roper if (crtc->primary->fb) { 14495d177189SThomas Zimmermann struct drm_framebuffer *fb = crtc->primary->fb; 14505d177189SThomas Zimmermann struct drm_gem_vram_object *gbo = 14515d177189SThomas Zimmermann drm_gem_vram_of_gem(fb->obj[0]); 145281da87f6SThomas Zimmermann drm_gem_vram_unpin(gbo); 145364c29076SEgbert Eich } 1454f4510a27SMatt Roper crtc->primary->fb = NULL; 145564c29076SEgbert Eich } 145664c29076SEgbert Eich 1457414c4531SDave Airlie /* These provide the minimum set of functions required to handle a CRTC */ 1458414c4531SDave Airlie static const struct drm_crtc_funcs mga_crtc_funcs = { 1459414c4531SDave Airlie .gamma_set = mga_crtc_gamma_set, 1460414c4531SDave Airlie .set_config = drm_crtc_helper_set_config, 1461414c4531SDave Airlie .destroy = mga_crtc_destroy, 1462414c4531SDave Airlie }; 1463414c4531SDave Airlie 1464414c4531SDave Airlie static const struct drm_crtc_helper_funcs mga_helper_funcs = { 146564c29076SEgbert Eich .disable = mga_crtc_disable, 1466414c4531SDave Airlie .dpms = mga_crtc_dpms, 1467414c4531SDave Airlie .mode_set = mga_crtc_mode_set, 1468414c4531SDave Airlie .mode_set_base = mga_crtc_mode_set_base, 1469414c4531SDave Airlie .prepare = mga_crtc_prepare, 1470414c4531SDave Airlie .commit = mga_crtc_commit, 1471414c4531SDave Airlie }; 1472414c4531SDave Airlie 1473414c4531SDave Airlie /* CRTC setup */ 1474f1998fe2SChristopher Harvey static void mga_crtc_init(struct mga_device *mdev) 1475414c4531SDave Airlie { 1476ed5877b6SThomas Zimmermann struct drm_device *dev = mdev->dev; 1477414c4531SDave Airlie struct mga_crtc *mga_crtc; 1478414c4531SDave Airlie 1479414c4531SDave Airlie mga_crtc = kzalloc(sizeof(struct mga_crtc) + 1480414c4531SDave Airlie (MGAG200FB_CONN_LIMIT * sizeof(struct drm_connector *)), 1481414c4531SDave Airlie GFP_KERNEL); 1482414c4531SDave Airlie 1483414c4531SDave Airlie if (mga_crtc == NULL) 1484414c4531SDave Airlie return; 1485414c4531SDave Airlie 1486ed5877b6SThomas Zimmermann drm_crtc_init(dev, &mga_crtc->base, &mga_crtc_funcs); 1487414c4531SDave Airlie 1488414c4531SDave Airlie drm_mode_crtc_set_gamma_size(&mga_crtc->base, MGAG200_LUT_SIZE); 1489414c4531SDave Airlie 1490414c4531SDave Airlie drm_crtc_helper_add(&mga_crtc->base, &mga_helper_funcs); 1491414c4531SDave Airlie } 1492414c4531SDave Airlie 149381a15b9aSThomas Zimmermann /* 149481a15b9aSThomas Zimmermann * Connector 149581a15b9aSThomas Zimmermann */ 149681a15b9aSThomas Zimmermann 1497414c4531SDave Airlie static int mga_vga_get_modes(struct drm_connector *connector) 1498414c4531SDave Airlie { 1499414c4531SDave Airlie struct mga_connector *mga_connector = to_mga_connector(connector); 1500414c4531SDave Airlie struct edid *edid; 1501414c4531SDave Airlie int ret = 0; 1502414c4531SDave Airlie 1503414c4531SDave Airlie edid = drm_get_edid(connector, &mga_connector->i2c->adapter); 1504414c4531SDave Airlie if (edid) { 1505c555f023SDaniel Vetter drm_connector_update_edid_property(connector, edid); 1506414c4531SDave Airlie ret = drm_add_edid_modes(connector, edid); 1507414c4531SDave Airlie kfree(edid); 1508414c4531SDave Airlie } 1509414c4531SDave Airlie return ret; 1510414c4531SDave Airlie } 1511414c4531SDave Airlie 1512abbee623SJulia Lemire static uint32_t mga_vga_calculate_mode_bandwidth(struct drm_display_mode *mode, 1513abbee623SJulia Lemire int bits_per_pixel) 1514abbee623SJulia Lemire { 1515abbee623SJulia Lemire uint32_t total_area, divisor; 1516c24ca5beSNicolas Pitre uint64_t active_area, pixels_per_second, bandwidth; 1517abbee623SJulia Lemire uint64_t bytes_per_pixel = (bits_per_pixel + 7) / 8; 1518abbee623SJulia Lemire 1519abbee623SJulia Lemire divisor = 1024; 1520abbee623SJulia Lemire 1521abbee623SJulia Lemire if (!mode->htotal || !mode->vtotal || !mode->clock) 1522abbee623SJulia Lemire return 0; 1523abbee623SJulia Lemire 1524abbee623SJulia Lemire active_area = mode->hdisplay * mode->vdisplay; 1525abbee623SJulia Lemire total_area = mode->htotal * mode->vtotal; 1526abbee623SJulia Lemire 1527abbee623SJulia Lemire pixels_per_second = active_area * mode->clock * 1000; 1528abbee623SJulia Lemire do_div(pixels_per_second, total_area); 1529abbee623SJulia Lemire 1530abbee623SJulia Lemire bandwidth = pixels_per_second * bytes_per_pixel * 100; 1531abbee623SJulia Lemire do_div(bandwidth, divisor); 1532abbee623SJulia Lemire 1533abbee623SJulia Lemire return (uint32_t)(bandwidth); 1534abbee623SJulia Lemire } 1535abbee623SJulia Lemire 1536abbee623SJulia Lemire #define MODE_BANDWIDTH MODE_BAD 1537abbee623SJulia Lemire 1538c69e52deSLuc Van Oostenryck static enum drm_mode_status mga_vga_mode_valid(struct drm_connector *connector, 1539414c4531SDave Airlie struct drm_display_mode *mode) 1540414c4531SDave Airlie { 15410ba53171SChristopher Harvey struct drm_device *dev = connector->dev; 15428d8ff2a9SThomas Zimmermann struct mga_device *mdev = to_mga_device(dev); 15430ba53171SChristopher Harvey int bpp = 32; 15440ba53171SChristopher Harvey 1545abbee623SJulia Lemire if (IS_G200_SE(mdev)) { 1546abbee623SJulia Lemire if (mdev->unique_rev_id == 0x01) { 1547abbee623SJulia Lemire if (mode->hdisplay > 1600) 1548abbee623SJulia Lemire return MODE_VIRTUAL_X; 1549abbee623SJulia Lemire if (mode->vdisplay > 1200) 1550abbee623SJulia Lemire return MODE_VIRTUAL_Y; 1551abbee623SJulia Lemire if (mga_vga_calculate_mode_bandwidth(mode, bpp) 1552abbee623SJulia Lemire > (24400 * 1024)) 1553abbee623SJulia Lemire return MODE_BANDWIDTH; 1554e829d7efSMathieu Larouche } else if (mdev->unique_rev_id == 0x02) { 1555abbee623SJulia Lemire if (mode->hdisplay > 1920) 1556abbee623SJulia Lemire return MODE_VIRTUAL_X; 1557abbee623SJulia Lemire if (mode->vdisplay > 1200) 1558abbee623SJulia Lemire return MODE_VIRTUAL_Y; 1559abbee623SJulia Lemire if (mga_vga_calculate_mode_bandwidth(mode, bpp) 1560abbee623SJulia Lemire > (30100 * 1024)) 1561abbee623SJulia Lemire return MODE_BANDWIDTH; 15620cbb7381SMathieu Larouche } else { 15630cbb7381SMathieu Larouche if (mga_vga_calculate_mode_bandwidth(mode, bpp) 15640cbb7381SMathieu Larouche > (55000 * 1024)) 15650cbb7381SMathieu Larouche return MODE_BANDWIDTH; 1566abbee623SJulia Lemire } 1567abbee623SJulia Lemire } else if (mdev->type == G200_WB) { 1568abbee623SJulia Lemire if (mode->hdisplay > 1280) 1569abbee623SJulia Lemire return MODE_VIRTUAL_X; 1570abbee623SJulia Lemire if (mode->vdisplay > 1024) 1571abbee623SJulia Lemire return MODE_VIRTUAL_Y; 15729eb8d7a9SDan Carpenter if (mga_vga_calculate_mode_bandwidth(mode, bpp) > 15739eb8d7a9SDan Carpenter (31877 * 1024)) 1574abbee623SJulia Lemire return MODE_BANDWIDTH; 1575abbee623SJulia Lemire } else if (mdev->type == G200_EV && 1576abbee623SJulia Lemire (mga_vga_calculate_mode_bandwidth(mode, bpp) 1577abbee623SJulia Lemire > (32700 * 1024))) { 1578abbee623SJulia Lemire return MODE_BANDWIDTH; 1579ec22b4aaSDave Airlie } else if (mdev->type == G200_EH && 1580abbee623SJulia Lemire (mga_vga_calculate_mode_bandwidth(mode, bpp) 1581abbee623SJulia Lemire > (37500 * 1024))) { 1582abbee623SJulia Lemire return MODE_BANDWIDTH; 1583ec22b4aaSDave Airlie } else if (mdev->type == G200_ER && 1584abbee623SJulia Lemire (mga_vga_calculate_mode_bandwidth(mode, 1585abbee623SJulia Lemire bpp) > (55000 * 1024))) { 1586abbee623SJulia Lemire return MODE_BANDWIDTH; 1587abbee623SJulia Lemire } 1588414c4531SDave Airlie 158925161084SAdam Jackson if ((mode->hdisplay % 8) != 0 || (mode->hsync_start % 8) != 0 || 159025161084SAdam Jackson (mode->hsync_end % 8) != 0 || (mode->htotal % 8) != 0) { 159125161084SAdam Jackson return MODE_H_ILLEGAL; 159225161084SAdam Jackson } 159325161084SAdam Jackson 1594414c4531SDave Airlie if (mode->crtc_hdisplay > 2048 || mode->crtc_hsync_start > 4096 || 1595414c4531SDave Airlie mode->crtc_hsync_end > 4096 || mode->crtc_htotal > 4096 || 1596414c4531SDave Airlie mode->crtc_vdisplay > 2048 || mode->crtc_vsync_start > 4096 || 1597414c4531SDave Airlie mode->crtc_vsync_end > 4096 || mode->crtc_vtotal > 4096) { 1598414c4531SDave Airlie return MODE_BAD; 1599414c4531SDave Airlie } 1600414c4531SDave Airlie 16010ba53171SChristopher Harvey /* Validate the mode input by the user */ 1602eaf99c74SChris Wilson if (connector->cmdline_mode.specified) { 1603eaf99c74SChris Wilson if (connector->cmdline_mode.bpp_specified) 1604eaf99c74SChris Wilson bpp = connector->cmdline_mode.bpp; 16050ba53171SChristopher Harvey } 16060ba53171SChristopher Harvey 16072c51a660SThomas Zimmermann if ((mode->hdisplay * mode->vdisplay * (bpp/8)) > mdev->vram_fb_available) { 1608eaf99c74SChris Wilson if (connector->cmdline_mode.specified) 1609eaf99c74SChris Wilson connector->cmdline_mode.specified = false; 16100ba53171SChristopher Harvey return MODE_BAD; 16110ba53171SChristopher Harvey } 16120ba53171SChristopher Harvey 1613414c4531SDave Airlie return MODE_OK; 1614414c4531SDave Airlie } 1615414c4531SDave Airlie 1616414c4531SDave Airlie static void mga_connector_destroy(struct drm_connector *connector) 1617414c4531SDave Airlie { 1618414c4531SDave Airlie struct mga_connector *mga_connector = to_mga_connector(connector); 1619414c4531SDave Airlie mgag200_i2c_destroy(mga_connector->i2c); 1620414c4531SDave Airlie drm_connector_cleanup(connector); 1621414c4531SDave Airlie } 1622414c4531SDave Airlie 162371cb7495SVille Syrjälä static const struct drm_connector_helper_funcs mga_vga_connector_helper_funcs = { 1624414c4531SDave Airlie .get_modes = mga_vga_get_modes, 1625414c4531SDave Airlie .mode_valid = mga_vga_mode_valid, 1626414c4531SDave Airlie }; 1627414c4531SDave Airlie 162871cb7495SVille Syrjälä static const struct drm_connector_funcs mga_vga_connector_funcs = { 1629414c4531SDave Airlie .dpms = drm_helper_connector_dpms, 1630414c4531SDave Airlie .fill_modes = drm_helper_probe_single_connector_modes, 1631414c4531SDave Airlie .destroy = mga_connector_destroy, 1632414c4531SDave Airlie }; 1633414c4531SDave Airlie 163481a15b9aSThomas Zimmermann static int mgag200_vga_connector_init(struct mga_device *mdev) 1635414c4531SDave Airlie { 163681a15b9aSThomas Zimmermann struct drm_device *dev = mdev->dev; 163781a15b9aSThomas Zimmermann struct mga_connector *mconnector = &mdev->connector; 163881a15b9aSThomas Zimmermann struct drm_connector *connector = &mconnector->base; 163981a15b9aSThomas Zimmermann struct mga_i2c_chan *i2c; 164081a15b9aSThomas Zimmermann int ret; 1641414c4531SDave Airlie 164281a15b9aSThomas Zimmermann i2c = mgag200_i2c_create(dev); 164381a15b9aSThomas Zimmermann if (!i2c) 164481a15b9aSThomas Zimmermann drm_warn(dev, "failed to add DDC bus\n"); 1645414c4531SDave Airlie 164681a15b9aSThomas Zimmermann ret = drm_connector_init_with_ddc(dev, connector, 16479572ae17SAndrzej Pietrasiewicz &mga_vga_connector_funcs, 16489572ae17SAndrzej Pietrasiewicz DRM_MODE_CONNECTOR_VGA, 164981a15b9aSThomas Zimmermann &i2c->adapter); 165081a15b9aSThomas Zimmermann if (ret) 165181a15b9aSThomas Zimmermann goto err_mgag200_i2c_destroy; 1652414c4531SDave Airlie drm_connector_helper_add(connector, &mga_vga_connector_helper_funcs); 1653414c4531SDave Airlie 165481a15b9aSThomas Zimmermann mconnector->i2c = i2c; 16553d5a1c5eSEgbert Eich 165681a15b9aSThomas Zimmermann return 0; 165781a15b9aSThomas Zimmermann 165881a15b9aSThomas Zimmermann err_mgag200_i2c_destroy: 165981a15b9aSThomas Zimmermann mgag200_i2c_destroy(i2c); 166081a15b9aSThomas Zimmermann return ret; 1661414c4531SDave Airlie } 1662414c4531SDave Airlie 16635635b7cfSThomas Zimmermann static const struct drm_mode_config_funcs mgag200_mode_config_funcs = { 16645635b7cfSThomas Zimmermann .fb_create = drm_gem_fb_create 16655635b7cfSThomas Zimmermann }; 16665635b7cfSThomas Zimmermann 16675635b7cfSThomas Zimmermann static unsigned int mgag200_preferred_depth(struct mga_device *mdev) 16685635b7cfSThomas Zimmermann { 16695635b7cfSThomas Zimmermann if (IS_G200_SE(mdev) && mdev->vram_fb_available < (2048*1024)) 16705635b7cfSThomas Zimmermann return 16; 16715635b7cfSThomas Zimmermann else 16725635b7cfSThomas Zimmermann return 32; 16735635b7cfSThomas Zimmermann } 1674414c4531SDave Airlie 1675414c4531SDave Airlie int mgag200_modeset_init(struct mga_device *mdev) 1676414c4531SDave Airlie { 1677ed5877b6SThomas Zimmermann struct drm_device *dev = mdev->dev; 167803e44ad1SThomas Zimmermann struct drm_encoder *encoder = &mdev->encoder; 167981a15b9aSThomas Zimmermann struct drm_connector *connector = &mdev->connector.base; 168003e44ad1SThomas Zimmermann int ret; 1681414c4531SDave Airlie 16825635b7cfSThomas Zimmermann mdev->bpp_shifts[0] = 0; 16835635b7cfSThomas Zimmermann mdev->bpp_shifts[1] = 1; 16845635b7cfSThomas Zimmermann mdev->bpp_shifts[2] = 0; 16855635b7cfSThomas Zimmermann mdev->bpp_shifts[3] = 2; 16865635b7cfSThomas Zimmermann 16875635b7cfSThomas Zimmermann ret = drmm_mode_config_init(dev); 16885635b7cfSThomas Zimmermann if (ret) { 16895635b7cfSThomas Zimmermann drm_err(dev, "drmm_mode_config_init() failed, error %d\n", 16905635b7cfSThomas Zimmermann ret); 16915635b7cfSThomas Zimmermann return ret; 16925635b7cfSThomas Zimmermann } 16935635b7cfSThomas Zimmermann 1694ed5877b6SThomas Zimmermann dev->mode_config.max_width = MGAG200_MAX_FB_WIDTH; 1695ed5877b6SThomas Zimmermann dev->mode_config.max_height = MGAG200_MAX_FB_HEIGHT; 1696414c4531SDave Airlie 16975635b7cfSThomas Zimmermann dev->mode_config.preferred_depth = mgag200_preferred_depth(mdev); 16985635b7cfSThomas Zimmermann dev->mode_config.prefer_shadow = 1; 16995635b7cfSThomas Zimmermann 1700ed5877b6SThomas Zimmermann dev->mode_config.fb_base = mdev->mc.vram_base; 1701414c4531SDave Airlie 17025635b7cfSThomas Zimmermann dev->mode_config.funcs = &mgag200_mode_config_funcs; 17035635b7cfSThomas Zimmermann 1704f1998fe2SChristopher Harvey mga_crtc_init(mdev); 1705414c4531SDave Airlie 1706ed5877b6SThomas Zimmermann ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_DAC); 170703e44ad1SThomas Zimmermann if (ret) { 1708ed5877b6SThomas Zimmermann drm_err(dev, 170903e44ad1SThomas Zimmermann "drm_simple_encoder_init() failed, error %d\n", 171003e44ad1SThomas Zimmermann ret); 171103e44ad1SThomas Zimmermann return ret; 1712414c4531SDave Airlie } 171303e44ad1SThomas Zimmermann encoder->possible_crtcs = 0x1; 1714414c4531SDave Airlie 171581a15b9aSThomas Zimmermann ret = mgag200_vga_connector_init(mdev); 171681a15b9aSThomas Zimmermann if (ret) { 171781a15b9aSThomas Zimmermann drm_err(dev, 171881a15b9aSThomas Zimmermann "mgag200_vga_connector_init() failed, error %d\n", 171981a15b9aSThomas Zimmermann ret); 172081a15b9aSThomas Zimmermann return ret; 1721414c4531SDave Airlie } 1722414c4531SDave Airlie 1723cde4c44dSDaniel Vetter drm_connector_attach_encoder(connector, encoder); 1724414c4531SDave Airlie 1725414c4531SDave Airlie return 0; 1726414c4531SDave Airlie } 1727