1414c4531SDave Airlie /* 2414c4531SDave Airlie * Copyright 2010 Matt Turner. 3414c4531SDave Airlie * Copyright 2012 Red Hat 4414c4531SDave Airlie * 5414c4531SDave Airlie * This file is subject to the terms and conditions of the GNU General 6414c4531SDave Airlie * Public License version 2. See the file COPYING in the main 7414c4531SDave Airlie * directory of this archive for more details. 8414c4531SDave Airlie * 9414c4531SDave Airlie * Authors: Matthew Garrett 10414c4531SDave Airlie * Matt Turner 11414c4531SDave Airlie * Dave Airlie 12414c4531SDave Airlie */ 13414c4531SDave Airlie 14414c4531SDave Airlie #include <linux/delay.h> 15414c4531SDave Airlie 16760285e7SDavid Howells #include <drm/drmP.h> 17760285e7SDavid Howells #include <drm/drm_crtc_helper.h> 183cb9ae4fSDaniel Vetter #include <drm/drm_plane_helper.h> 19414c4531SDave Airlie 20414c4531SDave Airlie #include "mgag200_drv.h" 21414c4531SDave Airlie 22414c4531SDave Airlie #define MGAG200_LUT_SIZE 256 23414c4531SDave Airlie 24414c4531SDave Airlie /* 25414c4531SDave Airlie * This file contains setup code for the CRTC. 26414c4531SDave Airlie */ 27414c4531SDave Airlie 28414c4531SDave Airlie static void mga_crtc_load_lut(struct drm_crtc *crtc) 29414c4531SDave Airlie { 30414c4531SDave Airlie struct drm_device *dev = crtc->dev; 31414c4531SDave Airlie struct mga_device *mdev = dev->dev_private; 32f4510a27SMatt Roper struct drm_framebuffer *fb = crtc->primary->fb; 339ed85e14SPeter Rosin u16 *r_ptr, *g_ptr, *b_ptr; 34414c4531SDave Airlie int i; 35414c4531SDave Airlie 36414c4531SDave Airlie if (!crtc->enabled) 37414c4531SDave Airlie return; 38414c4531SDave Airlie 399ed85e14SPeter Rosin r_ptr = crtc->gamma_store; 409ed85e14SPeter Rosin g_ptr = r_ptr + crtc->gamma_size; 419ed85e14SPeter Rosin b_ptr = g_ptr + crtc->gamma_size; 429ed85e14SPeter Rosin 43414c4531SDave Airlie WREG8(DAC_INDEX + MGA1064_INDEX, 0); 44414c4531SDave Airlie 45272725c7SVille Syrjälä if (fb && fb->format->cpp[0] * 8 == 16) { 46b00c600eSVille Syrjälä int inc = (fb->format->depth == 15) ? 8 : 4; 47de7500eaSEgbert Eich u8 r, b; 48de7500eaSEgbert Eich for (i = 0; i < MGAG200_LUT_SIZE; i += inc) { 49b00c600eSVille Syrjälä if (fb->format->depth == 16) { 50de7500eaSEgbert Eich if (i > (MGAG200_LUT_SIZE >> 1)) { 51de7500eaSEgbert Eich r = b = 0; 52de7500eaSEgbert Eich } else { 539ed85e14SPeter Rosin r = *r_ptr++ >> 8; 549ed85e14SPeter Rosin b = *b_ptr++ >> 8; 559ed85e14SPeter Rosin r_ptr++; 569ed85e14SPeter Rosin b_ptr++; 57de7500eaSEgbert Eich } 58de7500eaSEgbert Eich } else { 599ed85e14SPeter Rosin r = *r_ptr++ >> 8; 609ed85e14SPeter Rosin b = *b_ptr++ >> 8; 61de7500eaSEgbert Eich } 62de7500eaSEgbert Eich /* VGA registers */ 63de7500eaSEgbert Eich WREG8(DAC_INDEX + MGA1064_COL_PAL, r); 649ed85e14SPeter Rosin WREG8(DAC_INDEX + MGA1064_COL_PAL, *g_ptr++ >> 8); 65de7500eaSEgbert Eich WREG8(DAC_INDEX + MGA1064_COL_PAL, b); 66de7500eaSEgbert Eich } 67de7500eaSEgbert Eich return; 68de7500eaSEgbert Eich } 69414c4531SDave Airlie for (i = 0; i < MGAG200_LUT_SIZE; i++) { 70414c4531SDave Airlie /* VGA registers */ 719ed85e14SPeter Rosin WREG8(DAC_INDEX + MGA1064_COL_PAL, *r_ptr++ >> 8); 729ed85e14SPeter Rosin WREG8(DAC_INDEX + MGA1064_COL_PAL, *g_ptr++ >> 8); 739ed85e14SPeter Rosin WREG8(DAC_INDEX + MGA1064_COL_PAL, *b_ptr++ >> 8); 74414c4531SDave Airlie } 75414c4531SDave Airlie } 76414c4531SDave Airlie 77414c4531SDave Airlie static inline void mga_wait_vsync(struct mga_device *mdev) 78414c4531SDave Airlie { 793cdc0e8dSChristopher Harvey unsigned long timeout = jiffies + HZ/10; 80414c4531SDave Airlie unsigned int status = 0; 81414c4531SDave Airlie 82414c4531SDave Airlie do { 83414c4531SDave Airlie status = RREG32(MGAREG_Status); 843cdc0e8dSChristopher Harvey } while ((status & 0x08) && time_before(jiffies, timeout)); 853cdc0e8dSChristopher Harvey timeout = jiffies + HZ/10; 86414c4531SDave Airlie status = 0; 87414c4531SDave Airlie do { 88414c4531SDave Airlie status = RREG32(MGAREG_Status); 893cdc0e8dSChristopher Harvey } while (!(status & 0x08) && time_before(jiffies, timeout)); 90414c4531SDave Airlie } 91414c4531SDave Airlie 92414c4531SDave Airlie static inline void mga_wait_busy(struct mga_device *mdev) 93414c4531SDave Airlie { 943cdc0e8dSChristopher Harvey unsigned long timeout = jiffies + HZ; 95414c4531SDave Airlie unsigned int status = 0; 96414c4531SDave Airlie do { 97414c4531SDave Airlie status = RREG8(MGAREG_Status + 2); 983cdc0e8dSChristopher Harvey } while ((status & 0x01) && time_before(jiffies, timeout)); 99414c4531SDave Airlie } 100414c4531SDave Airlie 101e829d7efSMathieu Larouche #define P_ARRAY_SIZE 9 102e829d7efSMathieu Larouche 103414c4531SDave Airlie static int mga_g200se_set_plls(struct mga_device *mdev, long clock) 104414c4531SDave Airlie { 105414c4531SDave Airlie unsigned int vcomax, vcomin, pllreffreq; 106414c4531SDave Airlie unsigned int delta, tmpdelta, permitteddelta; 107414c4531SDave Airlie unsigned int testp, testm, testn; 108414c4531SDave Airlie unsigned int p, m, n; 109414c4531SDave Airlie unsigned int computed; 110e829d7efSMathieu Larouche unsigned int pvalues_e4[P_ARRAY_SIZE] = {16, 14, 12, 10, 8, 6, 4, 2, 1}; 111e829d7efSMathieu Larouche unsigned int fvv; 112e829d7efSMathieu Larouche unsigned int i; 113e829d7efSMathieu Larouche 114e829d7efSMathieu Larouche if (mdev->unique_rev_id <= 0x03) { 115414c4531SDave Airlie 116414c4531SDave Airlie m = n = p = 0; 117414c4531SDave Airlie vcomax = 320000; 118414c4531SDave Airlie vcomin = 160000; 119414c4531SDave Airlie pllreffreq = 25000; 120414c4531SDave Airlie 121414c4531SDave Airlie delta = 0xffffffff; 122414c4531SDave Airlie permitteddelta = clock * 5 / 1000; 123414c4531SDave Airlie 124414c4531SDave Airlie for (testp = 8; testp > 0; testp /= 2) { 125414c4531SDave Airlie if (clock * testp > vcomax) 126414c4531SDave Airlie continue; 127414c4531SDave Airlie if (clock * testp < vcomin) 128414c4531SDave Airlie continue; 129414c4531SDave Airlie 130414c4531SDave Airlie for (testn = 17; testn < 256; testn++) { 131414c4531SDave Airlie for (testm = 1; testm < 32; testm++) { 132414c4531SDave Airlie computed = (pllreffreq * testn) / 133414c4531SDave Airlie (testm * testp); 134414c4531SDave Airlie if (computed > clock) 135414c4531SDave Airlie tmpdelta = computed - clock; 136414c4531SDave Airlie else 137414c4531SDave Airlie tmpdelta = clock - computed; 138414c4531SDave Airlie if (tmpdelta < delta) { 139414c4531SDave Airlie delta = tmpdelta; 140414c4531SDave Airlie m = testm - 1; 141414c4531SDave Airlie n = testn - 1; 142414c4531SDave Airlie p = testp - 1; 143414c4531SDave Airlie } 144414c4531SDave Airlie } 145414c4531SDave Airlie } 146414c4531SDave Airlie } 147e829d7efSMathieu Larouche } else { 148e829d7efSMathieu Larouche 149e829d7efSMathieu Larouche 150e829d7efSMathieu Larouche m = n = p = 0; 151e829d7efSMathieu Larouche vcomax = 1600000; 152e829d7efSMathieu Larouche vcomin = 800000; 153e829d7efSMathieu Larouche pllreffreq = 25000; 154e829d7efSMathieu Larouche 155e829d7efSMathieu Larouche if (clock < 25000) 156e829d7efSMathieu Larouche clock = 25000; 157e829d7efSMathieu Larouche 158e829d7efSMathieu Larouche clock = clock * 2; 159e829d7efSMathieu Larouche 160e829d7efSMathieu Larouche delta = 0xFFFFFFFF; 161e829d7efSMathieu Larouche /* Permited delta is 0.5% as VESA Specification */ 162e829d7efSMathieu Larouche permitteddelta = clock * 5 / 1000; 163e829d7efSMathieu Larouche 164e829d7efSMathieu Larouche for (i = 0 ; i < P_ARRAY_SIZE ; i++) { 165e829d7efSMathieu Larouche testp = pvalues_e4[i]; 166e829d7efSMathieu Larouche 167e829d7efSMathieu Larouche if ((clock * testp) > vcomax) 168e829d7efSMathieu Larouche continue; 169e829d7efSMathieu Larouche if ((clock * testp) < vcomin) 170e829d7efSMathieu Larouche continue; 171e829d7efSMathieu Larouche 172e829d7efSMathieu Larouche for (testn = 50; testn <= 256; testn++) { 173e829d7efSMathieu Larouche for (testm = 1; testm <= 32; testm++) { 174e829d7efSMathieu Larouche computed = (pllreffreq * testn) / 175e829d7efSMathieu Larouche (testm * testp); 176e829d7efSMathieu Larouche if (computed > clock) 177e829d7efSMathieu Larouche tmpdelta = computed - clock; 178e829d7efSMathieu Larouche else 179e829d7efSMathieu Larouche tmpdelta = clock - computed; 180e829d7efSMathieu Larouche 181e829d7efSMathieu Larouche if (tmpdelta < delta) { 182e829d7efSMathieu Larouche delta = tmpdelta; 183e829d7efSMathieu Larouche m = testm - 1; 184e829d7efSMathieu Larouche n = testn - 1; 185e829d7efSMathieu Larouche p = testp - 1; 186e829d7efSMathieu Larouche } 187e829d7efSMathieu Larouche } 188e829d7efSMathieu Larouche } 189e829d7efSMathieu Larouche } 190e829d7efSMathieu Larouche 191d3922b69SMathieu Larouche fvv = pllreffreq * (n + 1) / (m + 1); 192e829d7efSMathieu Larouche fvv = (fvv - 800000) / 50000; 193e829d7efSMathieu Larouche 194e829d7efSMathieu Larouche if (fvv > 15) 195e829d7efSMathieu Larouche fvv = 15; 196e829d7efSMathieu Larouche 197e829d7efSMathieu Larouche p |= (fvv << 4); 198e829d7efSMathieu Larouche m |= 0x80; 199e829d7efSMathieu Larouche 200e829d7efSMathieu Larouche clock = clock / 2; 201e829d7efSMathieu Larouche } 202414c4531SDave Airlie 203414c4531SDave Airlie if (delta > permitteddelta) { 2048dfe162aSJoe Perches pr_warn("PLL delta too large\n"); 205414c4531SDave Airlie return 1; 206414c4531SDave Airlie } 207414c4531SDave Airlie 208414c4531SDave Airlie WREG_DAC(MGA1064_PIX_PLLC_M, m); 209414c4531SDave Airlie WREG_DAC(MGA1064_PIX_PLLC_N, n); 210414c4531SDave Airlie WREG_DAC(MGA1064_PIX_PLLC_P, p); 211d3922b69SMathieu Larouche 212d3922b69SMathieu Larouche if (mdev->unique_rev_id >= 0x04) { 213d3922b69SMathieu Larouche WREG_DAC(0x1a, 0x09); 214d3922b69SMathieu Larouche msleep(20); 215d3922b69SMathieu Larouche WREG_DAC(0x1a, 0x01); 216d3922b69SMathieu Larouche 217d3922b69SMathieu Larouche } 218d3922b69SMathieu Larouche 219414c4531SDave Airlie return 0; 220414c4531SDave Airlie } 221414c4531SDave Airlie 222414c4531SDave Airlie static int mga_g200wb_set_plls(struct mga_device *mdev, long clock) 223414c4531SDave Airlie { 224414c4531SDave Airlie unsigned int vcomax, vcomin, pllreffreq; 225546aee51SSudip Mukherjee unsigned int delta, tmpdelta; 2266d857c18SMathieu Larouche unsigned int testp, testm, testn, testp2; 227414c4531SDave Airlie unsigned int p, m, n; 228414c4531SDave Airlie unsigned int computed; 229414c4531SDave Airlie int i, j, tmpcount, vcount; 230414c4531SDave Airlie bool pll_locked = false; 231414c4531SDave Airlie u8 tmp; 232414c4531SDave Airlie 233414c4531SDave Airlie m = n = p = 0; 2346d857c18SMathieu Larouche 2356d857c18SMathieu Larouche delta = 0xffffffff; 2366d857c18SMathieu Larouche 2376d857c18SMathieu Larouche if (mdev->type == G200_EW3) { 2386d857c18SMathieu Larouche 2396d857c18SMathieu Larouche vcomax = 800000; 2406d857c18SMathieu Larouche vcomin = 400000; 2416d857c18SMathieu Larouche pllreffreq = 25000; 2426d857c18SMathieu Larouche 2436d857c18SMathieu Larouche for (testp = 1; testp < 8; testp++) { 2446d857c18SMathieu Larouche for (testp2 = 1; testp2 < 8; testp2++) { 2456d857c18SMathieu Larouche if (testp < testp2) 2466d857c18SMathieu Larouche continue; 2476d857c18SMathieu Larouche if ((clock * testp * testp2) > vcomax) 2486d857c18SMathieu Larouche continue; 2496d857c18SMathieu Larouche if ((clock * testp * testp2) < vcomin) 2506d857c18SMathieu Larouche continue; 2516d857c18SMathieu Larouche for (testm = 1; testm < 26; testm++) { 2526d857c18SMathieu Larouche for (testn = 32; testn < 2048 ; testn++) { 2536d857c18SMathieu Larouche computed = (pllreffreq * testn) / 2546d857c18SMathieu Larouche (testm * testp * testp2); 2556d857c18SMathieu Larouche if (computed > clock) 2566d857c18SMathieu Larouche tmpdelta = computed - clock; 2576d857c18SMathieu Larouche else 2586d857c18SMathieu Larouche tmpdelta = clock - computed; 2596d857c18SMathieu Larouche if (tmpdelta < delta) { 2606d857c18SMathieu Larouche delta = tmpdelta; 2616d857c18SMathieu Larouche m = ((testn & 0x100) >> 1) | 2626d857c18SMathieu Larouche (testm); 2636d857c18SMathieu Larouche n = (testn & 0xFF); 2646d857c18SMathieu Larouche p = ((testn & 0x600) >> 3) | 2656d857c18SMathieu Larouche (testp2 << 3) | 2666d857c18SMathieu Larouche (testp); 2676d857c18SMathieu Larouche } 2686d857c18SMathieu Larouche } 2696d857c18SMathieu Larouche } 2706d857c18SMathieu Larouche } 2716d857c18SMathieu Larouche } 2726d857c18SMathieu Larouche } else { 2736d857c18SMathieu Larouche 274414c4531SDave Airlie vcomax = 550000; 275414c4531SDave Airlie vcomin = 150000; 276414c4531SDave Airlie pllreffreq = 48000; 277414c4531SDave Airlie 278414c4531SDave Airlie for (testp = 1; testp < 9; testp++) { 279414c4531SDave Airlie if (clock * testp > vcomax) 280414c4531SDave Airlie continue; 281414c4531SDave Airlie if (clock * testp < vcomin) 282414c4531SDave Airlie continue; 283414c4531SDave Airlie 284414c4531SDave Airlie for (testm = 1; testm < 17; testm++) { 285414c4531SDave Airlie for (testn = 1; testn < 151; testn++) { 286414c4531SDave Airlie computed = (pllreffreq * testn) / 287414c4531SDave Airlie (testm * testp); 288414c4531SDave Airlie if (computed > clock) 289414c4531SDave Airlie tmpdelta = computed - clock; 290414c4531SDave Airlie else 291414c4531SDave Airlie tmpdelta = clock - computed; 292414c4531SDave Airlie if (tmpdelta < delta) { 293414c4531SDave Airlie delta = tmpdelta; 294414c4531SDave Airlie n = testn - 1; 2956d857c18SMathieu Larouche m = (testm - 1) | 2966d857c18SMathieu Larouche ((n >> 1) & 0x80); 297414c4531SDave Airlie p = testp - 1; 298414c4531SDave Airlie } 299414c4531SDave Airlie } 300414c4531SDave Airlie } 301414c4531SDave Airlie } 3026d857c18SMathieu Larouche } 303414c4531SDave Airlie 304414c4531SDave Airlie for (i = 0; i <= 32 && pll_locked == false; i++) { 305414c4531SDave Airlie if (i > 0) { 306414c4531SDave Airlie WREG8(MGAREG_CRTC_INDEX, 0x1e); 307414c4531SDave Airlie tmp = RREG8(MGAREG_CRTC_DATA); 308414c4531SDave Airlie if (tmp < 0xff) 309414c4531SDave Airlie WREG8(MGAREG_CRTC_DATA, tmp+1); 310414c4531SDave Airlie } 311414c4531SDave Airlie 312414c4531SDave Airlie /* set pixclkdis to 1 */ 313414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 314414c4531SDave Airlie tmp = RREG8(DAC_DATA); 315414c4531SDave Airlie tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS; 316fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 317414c4531SDave Airlie 318414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_REMHEADCTL); 319414c4531SDave Airlie tmp = RREG8(DAC_DATA); 320414c4531SDave Airlie tmp |= MGA1064_REMHEADCTL_CLKDIS; 321fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 322414c4531SDave Airlie 323414c4531SDave Airlie /* select PLL Set C */ 324414c4531SDave Airlie tmp = RREG8(MGAREG_MEM_MISC_READ); 325414c4531SDave Airlie tmp |= 0x3 << 2; 326414c4531SDave Airlie WREG8(MGAREG_MEM_MISC_WRITE, tmp); 327414c4531SDave Airlie 328414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 329414c4531SDave Airlie tmp = RREG8(DAC_DATA); 330414c4531SDave Airlie tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN | 0x80; 331fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 332414c4531SDave Airlie 333414c4531SDave Airlie udelay(500); 334414c4531SDave Airlie 335414c4531SDave Airlie /* reset the PLL */ 336414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_VREF_CTL); 337414c4531SDave Airlie tmp = RREG8(DAC_DATA); 338414c4531SDave Airlie tmp &= ~0x04; 339fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 340414c4531SDave Airlie 341414c4531SDave Airlie udelay(50); 342414c4531SDave Airlie 343414c4531SDave Airlie /* program pixel pll register */ 344414c4531SDave Airlie WREG_DAC(MGA1064_WB_PIX_PLLC_N, n); 345414c4531SDave Airlie WREG_DAC(MGA1064_WB_PIX_PLLC_M, m); 346414c4531SDave Airlie WREG_DAC(MGA1064_WB_PIX_PLLC_P, p); 347414c4531SDave Airlie 348414c4531SDave Airlie udelay(50); 349414c4531SDave Airlie 350414c4531SDave Airlie /* turn pll on */ 351414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_VREF_CTL); 352414c4531SDave Airlie tmp = RREG8(DAC_DATA); 353414c4531SDave Airlie tmp |= 0x04; 354414c4531SDave Airlie WREG_DAC(MGA1064_VREF_CTL, tmp); 355414c4531SDave Airlie 356414c4531SDave Airlie udelay(500); 357414c4531SDave Airlie 358414c4531SDave Airlie /* select the pixel pll */ 359414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 360414c4531SDave Airlie tmp = RREG8(DAC_DATA); 361414c4531SDave Airlie tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK; 362414c4531SDave Airlie tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL; 363fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 364414c4531SDave Airlie 365414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_REMHEADCTL); 366414c4531SDave Airlie tmp = RREG8(DAC_DATA); 367414c4531SDave Airlie tmp &= ~MGA1064_REMHEADCTL_CLKSL_MSK; 368414c4531SDave Airlie tmp |= MGA1064_REMHEADCTL_CLKSL_PLL; 369fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 370414c4531SDave Airlie 371414c4531SDave Airlie /* reset dotclock rate bit */ 372414c4531SDave Airlie WREG8(MGAREG_SEQ_INDEX, 1); 373414c4531SDave Airlie tmp = RREG8(MGAREG_SEQ_DATA); 374414c4531SDave Airlie tmp &= ~0x8; 375414c4531SDave Airlie WREG8(MGAREG_SEQ_DATA, tmp); 376414c4531SDave Airlie 377414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 378414c4531SDave Airlie tmp = RREG8(DAC_DATA); 379414c4531SDave Airlie tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS; 380fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 381414c4531SDave Airlie 382414c4531SDave Airlie vcount = RREG8(MGAREG_VCOUNT); 383414c4531SDave Airlie 384414c4531SDave Airlie for (j = 0; j < 30 && pll_locked == false; j++) { 385414c4531SDave Airlie tmpcount = RREG8(MGAREG_VCOUNT); 386414c4531SDave Airlie if (tmpcount < vcount) 387414c4531SDave Airlie vcount = 0; 388414c4531SDave Airlie if ((tmpcount - vcount) > 2) 389414c4531SDave Airlie pll_locked = true; 390414c4531SDave Airlie else 391414c4531SDave Airlie udelay(5); 392414c4531SDave Airlie } 393414c4531SDave Airlie } 394414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_REMHEADCTL); 395414c4531SDave Airlie tmp = RREG8(DAC_DATA); 396414c4531SDave Airlie tmp &= ~MGA1064_REMHEADCTL_CLKDIS; 397414c4531SDave Airlie WREG_DAC(MGA1064_REMHEADCTL, tmp); 398414c4531SDave Airlie return 0; 399414c4531SDave Airlie } 400414c4531SDave Airlie 401414c4531SDave Airlie static int mga_g200ev_set_plls(struct mga_device *mdev, long clock) 402414c4531SDave Airlie { 403414c4531SDave Airlie unsigned int vcomax, vcomin, pllreffreq; 404546aee51SSudip Mukherjee unsigned int delta, tmpdelta; 405414c4531SDave Airlie unsigned int testp, testm, testn; 406414c4531SDave Airlie unsigned int p, m, n; 407414c4531SDave Airlie unsigned int computed; 408414c4531SDave Airlie u8 tmp; 409414c4531SDave Airlie 410414c4531SDave Airlie m = n = p = 0; 411414c4531SDave Airlie vcomax = 550000; 412414c4531SDave Airlie vcomin = 150000; 413414c4531SDave Airlie pllreffreq = 50000; 414414c4531SDave Airlie 415414c4531SDave Airlie delta = 0xffffffff; 416414c4531SDave Airlie 417414c4531SDave Airlie for (testp = 16; testp > 0; testp--) { 418414c4531SDave Airlie if (clock * testp > vcomax) 419414c4531SDave Airlie continue; 420414c4531SDave Airlie if (clock * testp < vcomin) 421414c4531SDave Airlie continue; 422414c4531SDave Airlie 423414c4531SDave Airlie for (testn = 1; testn < 257; testn++) { 424414c4531SDave Airlie for (testm = 1; testm < 17; testm++) { 425414c4531SDave Airlie computed = (pllreffreq * testn) / 426414c4531SDave Airlie (testm * testp); 427414c4531SDave Airlie if (computed > clock) 428414c4531SDave Airlie tmpdelta = computed - clock; 429414c4531SDave Airlie else 430414c4531SDave Airlie tmpdelta = clock - computed; 431414c4531SDave Airlie if (tmpdelta < delta) { 432414c4531SDave Airlie delta = tmpdelta; 433414c4531SDave Airlie n = testn - 1; 434414c4531SDave Airlie m = testm - 1; 435414c4531SDave Airlie p = testp - 1; 436414c4531SDave Airlie } 437414c4531SDave Airlie } 438414c4531SDave Airlie } 439414c4531SDave Airlie } 440414c4531SDave Airlie 441414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 442414c4531SDave Airlie tmp = RREG8(DAC_DATA); 443414c4531SDave Airlie tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS; 444fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 445414c4531SDave Airlie 446414c4531SDave Airlie tmp = RREG8(MGAREG_MEM_MISC_READ); 447414c4531SDave Airlie tmp |= 0x3 << 2; 448414c4531SDave Airlie WREG8(MGAREG_MEM_MISC_WRITE, tmp); 449414c4531SDave Airlie 450414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_PLL_STAT); 451414c4531SDave Airlie tmp = RREG8(DAC_DATA); 452fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp & ~0x40); 453414c4531SDave Airlie 454414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 455414c4531SDave Airlie tmp = RREG8(DAC_DATA); 456414c4531SDave Airlie tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; 457fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 458414c4531SDave Airlie 459414c4531SDave Airlie WREG_DAC(MGA1064_EV_PIX_PLLC_M, m); 460414c4531SDave Airlie WREG_DAC(MGA1064_EV_PIX_PLLC_N, n); 461414c4531SDave Airlie WREG_DAC(MGA1064_EV_PIX_PLLC_P, p); 462414c4531SDave Airlie 463414c4531SDave Airlie udelay(50); 464414c4531SDave Airlie 465414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 466414c4531SDave Airlie tmp = RREG8(DAC_DATA); 467414c4531SDave Airlie tmp &= ~MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; 468fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 469414c4531SDave Airlie 470414c4531SDave Airlie udelay(500); 471414c4531SDave Airlie 472414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 473414c4531SDave Airlie tmp = RREG8(DAC_DATA); 474414c4531SDave Airlie tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK; 475414c4531SDave Airlie tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL; 476fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 477414c4531SDave Airlie 478414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_PLL_STAT); 479414c4531SDave Airlie tmp = RREG8(DAC_DATA); 480fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp | 0x40); 481414c4531SDave Airlie 482414c4531SDave Airlie tmp = RREG8(MGAREG_MEM_MISC_READ); 483414c4531SDave Airlie tmp |= (0x3 << 2); 484414c4531SDave Airlie WREG8(MGAREG_MEM_MISC_WRITE, tmp); 485414c4531SDave Airlie 486414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 487414c4531SDave Airlie tmp = RREG8(DAC_DATA); 488414c4531SDave Airlie tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS; 489fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 490414c4531SDave Airlie 491414c4531SDave Airlie return 0; 492414c4531SDave Airlie } 493414c4531SDave Airlie 494414c4531SDave Airlie static int mga_g200eh_set_plls(struct mga_device *mdev, long clock) 495414c4531SDave Airlie { 496414c4531SDave Airlie unsigned int vcomax, vcomin, pllreffreq; 497546aee51SSudip Mukherjee unsigned int delta, tmpdelta; 498414c4531SDave Airlie unsigned int testp, testm, testn; 499414c4531SDave Airlie unsigned int p, m, n; 500414c4531SDave Airlie unsigned int computed; 501414c4531SDave Airlie int i, j, tmpcount, vcount; 502414c4531SDave Airlie u8 tmp; 503414c4531SDave Airlie bool pll_locked = false; 504414c4531SDave Airlie 505414c4531SDave Airlie m = n = p = 0; 506f0493e65SMathieu Larouche 507f0493e65SMathieu Larouche if (mdev->type == G200_EH3) { 508f0493e65SMathieu Larouche vcomax = 3000000; 509f0493e65SMathieu Larouche vcomin = 1500000; 510f0493e65SMathieu Larouche pllreffreq = 25000; 511f0493e65SMathieu Larouche 512f0493e65SMathieu Larouche delta = 0xffffffff; 513f0493e65SMathieu Larouche 514f0493e65SMathieu Larouche testp = 0; 515f0493e65SMathieu Larouche 516f0493e65SMathieu Larouche for (testm = 150; testm >= 6; testm--) { 517f0493e65SMathieu Larouche if (clock * testm > vcomax) 518f0493e65SMathieu Larouche continue; 519f0493e65SMathieu Larouche if (clock * testm < vcomin) 520f0493e65SMathieu Larouche continue; 521f0493e65SMathieu Larouche for (testn = 120; testn >= 60; testn--) { 522f0493e65SMathieu Larouche computed = (pllreffreq * testn) / testm; 523f0493e65SMathieu Larouche if (computed > clock) 524f0493e65SMathieu Larouche tmpdelta = computed - clock; 525f0493e65SMathieu Larouche else 526f0493e65SMathieu Larouche tmpdelta = clock - computed; 527f0493e65SMathieu Larouche if (tmpdelta < delta) { 528f0493e65SMathieu Larouche delta = tmpdelta; 529f0493e65SMathieu Larouche n = testn; 530f0493e65SMathieu Larouche m = testm; 531f0493e65SMathieu Larouche p = testp; 532f0493e65SMathieu Larouche } 533f0493e65SMathieu Larouche if (delta == 0) 534f0493e65SMathieu Larouche break; 535f0493e65SMathieu Larouche } 536f0493e65SMathieu Larouche if (delta == 0) 537f0493e65SMathieu Larouche break; 538f0493e65SMathieu Larouche } 539f0493e65SMathieu Larouche } else { 540f0493e65SMathieu Larouche 541414c4531SDave Airlie vcomax = 800000; 542414c4531SDave Airlie vcomin = 400000; 543260b3f12SJulia Lemire pllreffreq = 33333; 544414c4531SDave Airlie 545414c4531SDave Airlie delta = 0xffffffff; 546414c4531SDave Airlie 547260b3f12SJulia Lemire for (testp = 16; testp > 0; testp >>= 1) { 548414c4531SDave Airlie if (clock * testp > vcomax) 549414c4531SDave Airlie continue; 550414c4531SDave Airlie if (clock * testp < vcomin) 551414c4531SDave Airlie continue; 552414c4531SDave Airlie 553414c4531SDave Airlie for (testm = 1; testm < 33; testm++) { 554260b3f12SJulia Lemire for (testn = 17; testn < 257; testn++) { 555414c4531SDave Airlie computed = (pllreffreq * testn) / 556414c4531SDave Airlie (testm * testp); 557414c4531SDave Airlie if (computed > clock) 558414c4531SDave Airlie tmpdelta = computed - clock; 559414c4531SDave Airlie else 560414c4531SDave Airlie tmpdelta = clock - computed; 561414c4531SDave Airlie if (tmpdelta < delta) { 562414c4531SDave Airlie delta = tmpdelta; 563414c4531SDave Airlie n = testn - 1; 564260b3f12SJulia Lemire m = (testm - 1); 565414c4531SDave Airlie p = testp - 1; 566414c4531SDave Airlie } 567414c4531SDave Airlie if ((clock * testp) >= 600000) 568260b3f12SJulia Lemire p |= 0x80; 569414c4531SDave Airlie } 570414c4531SDave Airlie } 571414c4531SDave Airlie } 572f0493e65SMathieu Larouche } 573414c4531SDave Airlie for (i = 0; i <= 32 && pll_locked == false; i++) { 574414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 575414c4531SDave Airlie tmp = RREG8(DAC_DATA); 576414c4531SDave Airlie tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS; 577fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 578414c4531SDave Airlie 579414c4531SDave Airlie tmp = RREG8(MGAREG_MEM_MISC_READ); 580414c4531SDave Airlie tmp |= 0x3 << 2; 581414c4531SDave Airlie WREG8(MGAREG_MEM_MISC_WRITE, tmp); 582414c4531SDave Airlie 583414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 584414c4531SDave Airlie tmp = RREG8(DAC_DATA); 585414c4531SDave Airlie tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; 586fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 587414c4531SDave Airlie 588414c4531SDave Airlie udelay(500); 589414c4531SDave Airlie 590414c4531SDave Airlie WREG_DAC(MGA1064_EH_PIX_PLLC_M, m); 591414c4531SDave Airlie WREG_DAC(MGA1064_EH_PIX_PLLC_N, n); 592414c4531SDave Airlie WREG_DAC(MGA1064_EH_PIX_PLLC_P, p); 593414c4531SDave Airlie 594414c4531SDave Airlie udelay(500); 595414c4531SDave Airlie 596414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 597414c4531SDave Airlie tmp = RREG8(DAC_DATA); 598414c4531SDave Airlie tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK; 599414c4531SDave Airlie tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL; 600fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 601414c4531SDave Airlie 602414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 603414c4531SDave Airlie tmp = RREG8(DAC_DATA); 604414c4531SDave Airlie tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS; 605414c4531SDave Airlie tmp &= ~MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; 606fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 607414c4531SDave Airlie 608414c4531SDave Airlie vcount = RREG8(MGAREG_VCOUNT); 609414c4531SDave Airlie 610414c4531SDave Airlie for (j = 0; j < 30 && pll_locked == false; j++) { 611414c4531SDave Airlie tmpcount = RREG8(MGAREG_VCOUNT); 612414c4531SDave Airlie if (tmpcount < vcount) 613414c4531SDave Airlie vcount = 0; 614414c4531SDave Airlie if ((tmpcount - vcount) > 2) 615414c4531SDave Airlie pll_locked = true; 616414c4531SDave Airlie else 617414c4531SDave Airlie udelay(5); 618414c4531SDave Airlie } 619414c4531SDave Airlie } 620414c4531SDave Airlie 621414c4531SDave Airlie return 0; 622414c4531SDave Airlie } 623414c4531SDave Airlie 624414c4531SDave Airlie static int mga_g200er_set_plls(struct mga_device *mdev, long clock) 625414c4531SDave Airlie { 626414c4531SDave Airlie unsigned int vcomax, vcomin, pllreffreq; 627414c4531SDave Airlie unsigned int delta, tmpdelta; 6289830605dSDave Airlie int testr, testn, testm, testo; 629414c4531SDave Airlie unsigned int p, m, n; 6309830605dSDave Airlie unsigned int computed, vco; 631414c4531SDave Airlie int tmp; 6329830605dSDave Airlie const unsigned int m_div_val[] = { 1, 2, 4, 8 }; 633414c4531SDave Airlie 634414c4531SDave Airlie m = n = p = 0; 635414c4531SDave Airlie vcomax = 1488000; 636414c4531SDave Airlie vcomin = 1056000; 637414c4531SDave Airlie pllreffreq = 48000; 638414c4531SDave Airlie 639414c4531SDave Airlie delta = 0xffffffff; 640414c4531SDave Airlie 641414c4531SDave Airlie for (testr = 0; testr < 4; testr++) { 642414c4531SDave Airlie if (delta == 0) 643414c4531SDave Airlie break; 644414c4531SDave Airlie for (testn = 5; testn < 129; testn++) { 645414c4531SDave Airlie if (delta == 0) 646414c4531SDave Airlie break; 647414c4531SDave Airlie for (testm = 3; testm >= 0; testm--) { 648414c4531SDave Airlie if (delta == 0) 649414c4531SDave Airlie break; 650414c4531SDave Airlie for (testo = 5; testo < 33; testo++) { 6519830605dSDave Airlie vco = pllreffreq * (testn + 1) / 652414c4531SDave Airlie (testr + 1); 6539830605dSDave Airlie if (vco < vcomin) 654414c4531SDave Airlie continue; 6559830605dSDave Airlie if (vco > vcomax) 656414c4531SDave Airlie continue; 6579830605dSDave Airlie computed = vco / (m_div_val[testm] * (testo + 1)); 658414c4531SDave Airlie if (computed > clock) 659414c4531SDave Airlie tmpdelta = computed - clock; 660414c4531SDave Airlie else 661414c4531SDave Airlie tmpdelta = clock - computed; 662414c4531SDave Airlie if (tmpdelta < delta) { 663414c4531SDave Airlie delta = tmpdelta; 664414c4531SDave Airlie m = testm | (testo << 3); 665414c4531SDave Airlie n = testn; 666414c4531SDave Airlie p = testr | (testr << 3); 667414c4531SDave Airlie } 668414c4531SDave Airlie } 669414c4531SDave Airlie } 670414c4531SDave Airlie } 671414c4531SDave Airlie } 672414c4531SDave Airlie 673414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 674414c4531SDave Airlie tmp = RREG8(DAC_DATA); 675414c4531SDave Airlie tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS; 676fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 677414c4531SDave Airlie 678414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_REMHEADCTL); 679414c4531SDave Airlie tmp = RREG8(DAC_DATA); 680414c4531SDave Airlie tmp |= MGA1064_REMHEADCTL_CLKDIS; 681fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 682414c4531SDave Airlie 683414c4531SDave Airlie tmp = RREG8(MGAREG_MEM_MISC_READ); 684414c4531SDave Airlie tmp |= (0x3<<2) | 0xc0; 685414c4531SDave Airlie WREG8(MGAREG_MEM_MISC_WRITE, tmp); 686414c4531SDave Airlie 687414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 688414c4531SDave Airlie tmp = RREG8(DAC_DATA); 689414c4531SDave Airlie tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS; 690414c4531SDave Airlie tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; 691fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 692414c4531SDave Airlie 693414c4531SDave Airlie udelay(500); 694414c4531SDave Airlie 695414c4531SDave Airlie WREG_DAC(MGA1064_ER_PIX_PLLC_N, n); 696414c4531SDave Airlie WREG_DAC(MGA1064_ER_PIX_PLLC_M, m); 697414c4531SDave Airlie WREG_DAC(MGA1064_ER_PIX_PLLC_P, p); 698414c4531SDave Airlie 699414c4531SDave Airlie udelay(50); 700414c4531SDave Airlie 701414c4531SDave Airlie return 0; 702414c4531SDave Airlie } 703414c4531SDave Airlie 704414c4531SDave Airlie static int mga_crtc_set_plls(struct mga_device *mdev, long clock) 705414c4531SDave Airlie { 706414c4531SDave Airlie switch(mdev->type) { 707414c4531SDave Airlie case G200_SE_A: 708414c4531SDave Airlie case G200_SE_B: 709414c4531SDave Airlie return mga_g200se_set_plls(mdev, clock); 710414c4531SDave Airlie break; 711414c4531SDave Airlie case G200_WB: 7126d857c18SMathieu Larouche case G200_EW3: 713414c4531SDave Airlie return mga_g200wb_set_plls(mdev, clock); 714414c4531SDave Airlie break; 715414c4531SDave Airlie case G200_EV: 716414c4531SDave Airlie return mga_g200ev_set_plls(mdev, clock); 717414c4531SDave Airlie break; 718414c4531SDave Airlie case G200_EH: 719f0493e65SMathieu Larouche case G200_EH3: 720414c4531SDave Airlie return mga_g200eh_set_plls(mdev, clock); 721414c4531SDave Airlie break; 722414c4531SDave Airlie case G200_ER: 723414c4531SDave Airlie return mga_g200er_set_plls(mdev, clock); 724414c4531SDave Airlie break; 725414c4531SDave Airlie } 726414c4531SDave Airlie return 0; 727414c4531SDave Airlie } 728414c4531SDave Airlie 729414c4531SDave Airlie static void mga_g200wb_prepare(struct drm_crtc *crtc) 730414c4531SDave Airlie { 731414c4531SDave Airlie struct mga_device *mdev = crtc->dev->dev_private; 732414c4531SDave Airlie u8 tmp; 733414c4531SDave Airlie int iter_max; 734414c4531SDave Airlie 735414c4531SDave Airlie /* 1- The first step is to warn the BMC of an upcoming mode change. 736414c4531SDave Airlie * We are putting the misc<0> to output.*/ 737414c4531SDave Airlie 738414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_GEN_IO_CTL); 739414c4531SDave Airlie tmp = RREG8(DAC_DATA); 740414c4531SDave Airlie tmp |= 0x10; 741414c4531SDave Airlie WREG_DAC(MGA1064_GEN_IO_CTL, tmp); 742414c4531SDave Airlie 743414c4531SDave Airlie /* we are putting a 1 on the misc<0> line */ 744414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_GEN_IO_DATA); 745414c4531SDave Airlie tmp = RREG8(DAC_DATA); 746414c4531SDave Airlie tmp |= 0x10; 747414c4531SDave Airlie WREG_DAC(MGA1064_GEN_IO_DATA, tmp); 748414c4531SDave Airlie 749414c4531SDave Airlie /* 2- Second step to mask and further scan request 750414c4531SDave Airlie * This will be done by asserting the remfreqmsk bit (XSPAREREG<7>) 751414c4531SDave Airlie */ 752414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_SPAREREG); 753414c4531SDave Airlie tmp = RREG8(DAC_DATA); 754414c4531SDave Airlie tmp |= 0x80; 755414c4531SDave Airlie WREG_DAC(MGA1064_SPAREREG, tmp); 756414c4531SDave Airlie 757414c4531SDave Airlie /* 3a- the third step is to verifu if there is an active scan 758414c4531SDave Airlie * We are searching for a 0 on remhsyncsts <XSPAREREG<0>) 759414c4531SDave Airlie */ 760414c4531SDave Airlie iter_max = 300; 761414c4531SDave Airlie while (!(tmp & 0x1) && iter_max) { 762414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_SPAREREG); 763414c4531SDave Airlie tmp = RREG8(DAC_DATA); 764414c4531SDave Airlie udelay(1000); 765414c4531SDave Airlie iter_max--; 766414c4531SDave Airlie } 767414c4531SDave Airlie 768414c4531SDave Airlie /* 3b- this step occurs only if the remove is actually scanning 769414c4531SDave Airlie * we are waiting for the end of the frame which is a 1 on 770414c4531SDave Airlie * remvsyncsts (XSPAREREG<1>) 771414c4531SDave Airlie */ 772414c4531SDave Airlie if (iter_max) { 773414c4531SDave Airlie iter_max = 300; 774414c4531SDave Airlie while ((tmp & 0x2) && iter_max) { 775414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_SPAREREG); 776414c4531SDave Airlie tmp = RREG8(DAC_DATA); 777414c4531SDave Airlie udelay(1000); 778414c4531SDave Airlie iter_max--; 779414c4531SDave Airlie } 780414c4531SDave Airlie } 781414c4531SDave Airlie } 782414c4531SDave Airlie 783414c4531SDave Airlie static void mga_g200wb_commit(struct drm_crtc *crtc) 784414c4531SDave Airlie { 785414c4531SDave Airlie u8 tmp; 786414c4531SDave Airlie struct mga_device *mdev = crtc->dev->dev_private; 787414c4531SDave Airlie 788414c4531SDave Airlie /* 1- The first step is to ensure that the vrsten and hrsten are set */ 789414c4531SDave Airlie WREG8(MGAREG_CRTCEXT_INDEX, 1); 790414c4531SDave Airlie tmp = RREG8(MGAREG_CRTCEXT_DATA); 791414c4531SDave Airlie WREG8(MGAREG_CRTCEXT_DATA, tmp | 0x88); 792414c4531SDave Airlie 793414c4531SDave Airlie /* 2- second step is to assert the rstlvl2 */ 794414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_REMHEADCTL2); 795414c4531SDave Airlie tmp = RREG8(DAC_DATA); 796414c4531SDave Airlie tmp |= 0x8; 797414c4531SDave Airlie WREG8(DAC_DATA, tmp); 798414c4531SDave Airlie 799414c4531SDave Airlie /* wait 10 us */ 800414c4531SDave Airlie udelay(10); 801414c4531SDave Airlie 802414c4531SDave Airlie /* 3- deassert rstlvl2 */ 803414c4531SDave Airlie tmp &= ~0x08; 804414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_REMHEADCTL2); 805414c4531SDave Airlie WREG8(DAC_DATA, tmp); 806414c4531SDave Airlie 807414c4531SDave Airlie /* 4- remove mask of scan request */ 808414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_SPAREREG); 809414c4531SDave Airlie tmp = RREG8(DAC_DATA); 810414c4531SDave Airlie tmp &= ~0x80; 811414c4531SDave Airlie WREG8(DAC_DATA, tmp); 812414c4531SDave Airlie 813414c4531SDave Airlie /* 5- put back a 0 on the misc<0> line */ 814414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_GEN_IO_DATA); 815414c4531SDave Airlie tmp = RREG8(DAC_DATA); 816414c4531SDave Airlie tmp &= ~0x10; 817414c4531SDave Airlie WREG_DAC(MGA1064_GEN_IO_DATA, tmp); 818414c4531SDave Airlie } 819414c4531SDave Airlie 8209f1d0366SChristopher Harvey /* 8219f1d0366SChristopher Harvey This is how the framebuffer base address is stored in g200 cards: 8229f1d0366SChristopher Harvey * Assume @offset is the gpu_addr variable of the framebuffer object 8239f1d0366SChristopher Harvey * Then addr is the number of _pixels_ (not bytes) from the start of 8249f1d0366SChristopher Harvey VRAM to the first pixel we want to display. (divided by 2 for 32bit 8259f1d0366SChristopher Harvey framebuffers) 8269f1d0366SChristopher Harvey * addr is stored in the CRTCEXT0, CRTCC and CRTCD registers 8279f1d0366SChristopher Harvey addr<20> -> CRTCEXT0<6> 8289f1d0366SChristopher Harvey addr<19-16> -> CRTCEXT0<3-0> 8299f1d0366SChristopher Harvey addr<15-8> -> CRTCC<7-0> 8309f1d0366SChristopher Harvey addr<7-0> -> CRTCD<7-0> 8319f1d0366SChristopher Harvey CRTCEXT0 has to be programmed last to trigger an update and make the 8329f1d0366SChristopher Harvey new addr variable take effect. 8339f1d0366SChristopher Harvey */ 834080fd6b5SRashika static void mga_set_start_address(struct drm_crtc *crtc, unsigned offset) 835414c4531SDave Airlie { 836414c4531SDave Airlie struct mga_device *mdev = crtc->dev->dev_private; 837414c4531SDave Airlie u32 addr; 838414c4531SDave Airlie int count; 8399f1d0366SChristopher Harvey u8 crtcext0; 840414c4531SDave Airlie 841414c4531SDave Airlie while (RREG8(0x1fda) & 0x08); 842414c4531SDave Airlie while (!(RREG8(0x1fda) & 0x08)); 843414c4531SDave Airlie 844414c4531SDave Airlie count = RREG8(MGAREG_VCOUNT) + 2; 845414c4531SDave Airlie while (RREG8(MGAREG_VCOUNT) < count); 846414c4531SDave Airlie 8479f1d0366SChristopher Harvey WREG8(MGAREG_CRTCEXT_INDEX, 0); 8489f1d0366SChristopher Harvey crtcext0 = RREG8(MGAREG_CRTCEXT_DATA); 8499f1d0366SChristopher Harvey crtcext0 &= 0xB0; 8509f1d0366SChristopher Harvey addr = offset / 8; 8519f1d0366SChristopher Harvey /* Can't store addresses any higher than that... 8529f1d0366SChristopher Harvey but we also don't have more than 16MB of memory, so it should be fine. */ 8539f1d0366SChristopher Harvey WARN_ON(addr > 0x1fffff); 8549f1d0366SChristopher Harvey crtcext0 |= (!!(addr & (1<<20)))<<6; 855414c4531SDave Airlie WREG_CRT(0x0d, (u8)(addr & 0xff)); 856414c4531SDave Airlie WREG_CRT(0x0c, (u8)(addr >> 8) & 0xff); 8579f1d0366SChristopher Harvey WREG_ECRT(0x0, ((u8)(addr >> 16) & 0xf) | crtcext0); 858414c4531SDave Airlie } 859414c4531SDave Airlie 860414c4531SDave Airlie 861414c4531SDave Airlie /* ast is different - we will force move buffers out of VRAM */ 862414c4531SDave Airlie static int mga_crtc_do_set_base(struct drm_crtc *crtc, 863414c4531SDave Airlie struct drm_framebuffer *fb, 864414c4531SDave Airlie int x, int y, int atomic) 865414c4531SDave Airlie { 866414c4531SDave Airlie struct mga_device *mdev = crtc->dev->dev_private; 867414c4531SDave Airlie struct drm_gem_object *obj; 868414c4531SDave Airlie struct mga_framebuffer *mga_fb; 869414c4531SDave Airlie struct mgag200_bo *bo; 870414c4531SDave Airlie int ret; 871414c4531SDave Airlie u64 gpu_addr; 872414c4531SDave Airlie 873414c4531SDave Airlie /* push the previous fb to system ram */ 874414c4531SDave Airlie if (!atomic && fb) { 875414c4531SDave Airlie mga_fb = to_mga_framebuffer(fb); 876414c4531SDave Airlie obj = mga_fb->obj; 877414c4531SDave Airlie bo = gem_to_mga_bo(obj); 878414c4531SDave Airlie ret = mgag200_bo_reserve(bo, false); 879414c4531SDave Airlie if (ret) 880414c4531SDave Airlie return ret; 881414c4531SDave Airlie mgag200_bo_push_sysram(bo); 882414c4531SDave Airlie mgag200_bo_unreserve(bo); 883414c4531SDave Airlie } 884414c4531SDave Airlie 885f4510a27SMatt Roper mga_fb = to_mga_framebuffer(crtc->primary->fb); 886414c4531SDave Airlie obj = mga_fb->obj; 887414c4531SDave Airlie bo = gem_to_mga_bo(obj); 888414c4531SDave Airlie 889414c4531SDave Airlie ret = mgag200_bo_reserve(bo, false); 890414c4531SDave Airlie if (ret) 891414c4531SDave Airlie return ret; 892414c4531SDave Airlie 893414c4531SDave Airlie ret = mgag200_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr); 894414c4531SDave Airlie if (ret) { 895414c4531SDave Airlie mgag200_bo_unreserve(bo); 896414c4531SDave Airlie return ret; 897414c4531SDave Airlie } 898414c4531SDave Airlie 899414c4531SDave Airlie if (&mdev->mfbdev->mfb == mga_fb) { 900414c4531SDave Airlie /* if pushing console in kmap it */ 901414c4531SDave Airlie ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap); 902414c4531SDave Airlie if (ret) 903414c4531SDave Airlie DRM_ERROR("failed to kmap fbcon\n"); 904414c4531SDave Airlie 905414c4531SDave Airlie } 906414c4531SDave Airlie mgag200_bo_unreserve(bo); 907414c4531SDave Airlie 908414c4531SDave Airlie mga_set_start_address(crtc, (u32)gpu_addr); 909414c4531SDave Airlie 910414c4531SDave Airlie return 0; 911414c4531SDave Airlie } 912414c4531SDave Airlie 913414c4531SDave Airlie static int mga_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, 914414c4531SDave Airlie struct drm_framebuffer *old_fb) 915414c4531SDave Airlie { 916414c4531SDave Airlie return mga_crtc_do_set_base(crtc, old_fb, x, y, 0); 917414c4531SDave Airlie } 918414c4531SDave Airlie 919414c4531SDave Airlie static int mga_crtc_mode_set(struct drm_crtc *crtc, 920414c4531SDave Airlie struct drm_display_mode *mode, 921414c4531SDave Airlie struct drm_display_mode *adjusted_mode, 922414c4531SDave Airlie int x, int y, struct drm_framebuffer *old_fb) 923414c4531SDave Airlie { 924414c4531SDave Airlie struct drm_device *dev = crtc->dev; 925414c4531SDave Airlie struct mga_device *mdev = dev->dev_private; 92672952757SVille Syrjälä const struct drm_framebuffer *fb = crtc->primary->fb; 927414c4531SDave Airlie int hdisplay, hsyncstart, hsyncend, htotal; 928414c4531SDave Airlie int vdisplay, vsyncstart, vsyncend, vtotal; 929414c4531SDave Airlie int pitch; 930414c4531SDave Airlie int option = 0, option2 = 0; 931414c4531SDave Airlie int i; 932414c4531SDave Airlie unsigned char misc = 0; 933414c4531SDave Airlie unsigned char ext_vga[6]; 934414c4531SDave Airlie u8 bppshift; 935414c4531SDave Airlie 936414c4531SDave Airlie static unsigned char dacvalue[] = { 937414c4531SDave Airlie /* 0x00: */ 0, 0, 0, 0, 0, 0, 0x00, 0, 938414c4531SDave Airlie /* 0x08: */ 0, 0, 0, 0, 0, 0, 0, 0, 939414c4531SDave Airlie /* 0x10: */ 0, 0, 0, 0, 0, 0, 0, 0, 940414c4531SDave Airlie /* 0x18: */ 0x00, 0, 0xC9, 0xFF, 0xBF, 0x20, 0x1F, 0x20, 941414c4531SDave Airlie /* 0x20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 942414c4531SDave Airlie /* 0x28: */ 0x00, 0x00, 0x00, 0x00, 0, 0, 0, 0x40, 943414c4531SDave Airlie /* 0x30: */ 0x00, 0xB0, 0x00, 0xC2, 0x34, 0x14, 0x02, 0x83, 944414c4531SDave Airlie /* 0x38: */ 0x00, 0x93, 0x00, 0x77, 0x00, 0x00, 0x00, 0x3A, 945414c4531SDave Airlie /* 0x40: */ 0, 0, 0, 0, 0, 0, 0, 0, 946414c4531SDave Airlie /* 0x48: */ 0, 0, 0, 0, 0, 0, 0, 0 947414c4531SDave Airlie }; 948414c4531SDave Airlie 949272725c7SVille Syrjälä bppshift = mdev->bpp_shifts[fb->format->cpp[0] - 1]; 950414c4531SDave Airlie 951414c4531SDave Airlie switch (mdev->type) { 952414c4531SDave Airlie case G200_SE_A: 953414c4531SDave Airlie case G200_SE_B: 954414c4531SDave Airlie dacvalue[MGA1064_VREF_CTL] = 0x03; 955414c4531SDave Airlie dacvalue[MGA1064_PIX_CLK_CTL] = MGA1064_PIX_CLK_CTL_SEL_PLL; 956414c4531SDave Airlie dacvalue[MGA1064_MISC_CTL] = MGA1064_MISC_CTL_DAC_EN | 957414c4531SDave Airlie MGA1064_MISC_CTL_VGA8 | 958414c4531SDave Airlie MGA1064_MISC_CTL_DAC_RAM_CS; 959414c4531SDave Airlie if (mdev->has_sdram) 960414c4531SDave Airlie option = 0x40049120; 961414c4531SDave Airlie else 962414c4531SDave Airlie option = 0x4004d120; 963414c4531SDave Airlie option2 = 0x00008000; 964414c4531SDave Airlie break; 965414c4531SDave Airlie case G200_WB: 9666d857c18SMathieu Larouche case G200_EW3: 967414c4531SDave Airlie dacvalue[MGA1064_VREF_CTL] = 0x07; 968414c4531SDave Airlie option = 0x41049120; 969414c4531SDave Airlie option2 = 0x0000b000; 970414c4531SDave Airlie break; 971414c4531SDave Airlie case G200_EV: 972414c4531SDave Airlie dacvalue[MGA1064_PIX_CLK_CTL] = MGA1064_PIX_CLK_CTL_SEL_PLL; 973414c4531SDave Airlie dacvalue[MGA1064_MISC_CTL] = MGA1064_MISC_CTL_VGA8 | 974414c4531SDave Airlie MGA1064_MISC_CTL_DAC_RAM_CS; 975414c4531SDave Airlie option = 0x00000120; 976414c4531SDave Airlie option2 = 0x0000b000; 977414c4531SDave Airlie break; 978414c4531SDave Airlie case G200_EH: 979f0493e65SMathieu Larouche case G200_EH3: 980414c4531SDave Airlie dacvalue[MGA1064_MISC_CTL] = MGA1064_MISC_CTL_VGA8 | 981414c4531SDave Airlie MGA1064_MISC_CTL_DAC_RAM_CS; 982414c4531SDave Airlie option = 0x00000120; 983414c4531SDave Airlie option2 = 0x0000b000; 984414c4531SDave Airlie break; 985414c4531SDave Airlie case G200_ER: 986414c4531SDave Airlie break; 987414c4531SDave Airlie } 988414c4531SDave Airlie 989272725c7SVille Syrjälä switch (fb->format->cpp[0] * 8) { 990414c4531SDave Airlie case 8: 991414c4531SDave Airlie dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_8bits; 992414c4531SDave Airlie break; 993414c4531SDave Airlie case 16: 994b00c600eSVille Syrjälä if (fb->format->depth == 15) 995414c4531SDave Airlie dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_15bits; 996414c4531SDave Airlie else 997414c4531SDave Airlie dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_16bits; 998414c4531SDave Airlie break; 999414c4531SDave Airlie case 24: 1000414c4531SDave Airlie dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_24bits; 1001414c4531SDave Airlie break; 1002414c4531SDave Airlie case 32: 1003414c4531SDave Airlie dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_32_24bits; 1004414c4531SDave Airlie break; 1005414c4531SDave Airlie } 1006414c4531SDave Airlie 1007414c4531SDave Airlie if (mode->flags & DRM_MODE_FLAG_NHSYNC) 1008414c4531SDave Airlie misc |= 0x40; 1009414c4531SDave Airlie if (mode->flags & DRM_MODE_FLAG_NVSYNC) 1010414c4531SDave Airlie misc |= 0x80; 1011414c4531SDave Airlie 1012414c4531SDave Airlie 1013414c4531SDave Airlie for (i = 0; i < sizeof(dacvalue); i++) { 10149d8aa55fSChristopher Harvey if ((i <= 0x17) || 1015414c4531SDave Airlie (i == 0x1b) || 1016414c4531SDave Airlie (i == 0x1c) || 1017414c4531SDave Airlie ((i >= 0x1f) && (i <= 0x29)) || 1018414c4531SDave Airlie ((i >= 0x30) && (i <= 0x37))) 1019414c4531SDave Airlie continue; 1020414c4531SDave Airlie if (IS_G200_SE(mdev) && 1021414c4531SDave Airlie ((i == 0x2c) || (i == 0x2d) || (i == 0x2e))) 1022414c4531SDave Airlie continue; 10236d857c18SMathieu Larouche if ((mdev->type == G200_EV || 10246d857c18SMathieu Larouche mdev->type == G200_WB || 10256d857c18SMathieu Larouche mdev->type == G200_EH || 1026f0493e65SMathieu Larouche mdev->type == G200_EW3 || 1027f0493e65SMathieu Larouche mdev->type == G200_EH3) && 1028414c4531SDave Airlie (i >= 0x44) && (i <= 0x4e)) 1029414c4531SDave Airlie continue; 1030414c4531SDave Airlie 1031414c4531SDave Airlie WREG_DAC(i, dacvalue[i]); 1032414c4531SDave Airlie } 1033414c4531SDave Airlie 10341812a3dbSChristopher Harvey if (mdev->type == G200_ER) 10351812a3dbSChristopher Harvey WREG_DAC(0x90, 0); 1036414c4531SDave Airlie 1037414c4531SDave Airlie if (option) 1038414c4531SDave Airlie pci_write_config_dword(dev->pdev, PCI_MGA_OPTION, option); 1039414c4531SDave Airlie if (option2) 1040414c4531SDave Airlie pci_write_config_dword(dev->pdev, PCI_MGA_OPTION2, option2); 1041414c4531SDave Airlie 1042414c4531SDave Airlie WREG_SEQ(2, 0xf); 1043414c4531SDave Airlie WREG_SEQ(3, 0); 1044414c4531SDave Airlie WREG_SEQ(4, 0xe); 1045414c4531SDave Airlie 1046272725c7SVille Syrjälä pitch = fb->pitches[0] / fb->format->cpp[0]; 1047272725c7SVille Syrjälä if (fb->format->cpp[0] * 8 == 24) 1048da558398STakashi Iwai pitch = (pitch * 3) >> (4 - bppshift); 1049414c4531SDave Airlie else 1050414c4531SDave Airlie pitch = pitch >> (4 - bppshift); 1051414c4531SDave Airlie 1052414c4531SDave Airlie hdisplay = mode->hdisplay / 8 - 1; 1053414c4531SDave Airlie hsyncstart = mode->hsync_start / 8 - 1; 1054414c4531SDave Airlie hsyncend = mode->hsync_end / 8 - 1; 1055414c4531SDave Airlie htotal = mode->htotal / 8 - 1; 1056414c4531SDave Airlie 1057414c4531SDave Airlie /* Work around hardware quirk */ 1058414c4531SDave Airlie if ((htotal & 0x07) == 0x06 || (htotal & 0x07) == 0x04) 1059414c4531SDave Airlie htotal++; 1060414c4531SDave Airlie 1061414c4531SDave Airlie vdisplay = mode->vdisplay - 1; 1062414c4531SDave Airlie vsyncstart = mode->vsync_start - 1; 1063414c4531SDave Airlie vsyncend = mode->vsync_end - 1; 1064414c4531SDave Airlie vtotal = mode->vtotal - 2; 1065414c4531SDave Airlie 1066414c4531SDave Airlie WREG_GFX(0, 0); 1067414c4531SDave Airlie WREG_GFX(1, 0); 1068414c4531SDave Airlie WREG_GFX(2, 0); 1069414c4531SDave Airlie WREG_GFX(3, 0); 1070414c4531SDave Airlie WREG_GFX(4, 0); 1071414c4531SDave Airlie WREG_GFX(5, 0x40); 1072414c4531SDave Airlie WREG_GFX(6, 0x5); 1073414c4531SDave Airlie WREG_GFX(7, 0xf); 1074414c4531SDave Airlie WREG_GFX(8, 0xf); 1075414c4531SDave Airlie 1076414c4531SDave Airlie WREG_CRT(0, htotal - 4); 1077414c4531SDave Airlie WREG_CRT(1, hdisplay); 1078414c4531SDave Airlie WREG_CRT(2, hdisplay); 1079414c4531SDave Airlie WREG_CRT(3, (htotal & 0x1F) | 0x80); 1080414c4531SDave Airlie WREG_CRT(4, hsyncstart); 1081414c4531SDave Airlie WREG_CRT(5, ((htotal & 0x20) << 2) | (hsyncend & 0x1F)); 1082414c4531SDave Airlie WREG_CRT(6, vtotal & 0xFF); 1083414c4531SDave Airlie WREG_CRT(7, ((vtotal & 0x100) >> 8) | 1084414c4531SDave Airlie ((vdisplay & 0x100) >> 7) | 1085414c4531SDave Airlie ((vsyncstart & 0x100) >> 6) | 1086414c4531SDave Airlie ((vdisplay & 0x100) >> 5) | 1087414c4531SDave Airlie ((vdisplay & 0x100) >> 4) | /* linecomp */ 1088414c4531SDave Airlie ((vtotal & 0x200) >> 4)| 1089414c4531SDave Airlie ((vdisplay & 0x200) >> 3) | 1090414c4531SDave Airlie ((vsyncstart & 0x200) >> 2)); 1091414c4531SDave Airlie WREG_CRT(9, ((vdisplay & 0x200) >> 4) | 1092414c4531SDave Airlie ((vdisplay & 0x200) >> 3)); 1093414c4531SDave Airlie WREG_CRT(10, 0); 1094414c4531SDave Airlie WREG_CRT(11, 0); 1095414c4531SDave Airlie WREG_CRT(12, 0); 1096414c4531SDave Airlie WREG_CRT(13, 0); 1097414c4531SDave Airlie WREG_CRT(14, 0); 1098414c4531SDave Airlie WREG_CRT(15, 0); 1099414c4531SDave Airlie WREG_CRT(16, vsyncstart & 0xFF); 1100414c4531SDave Airlie WREG_CRT(17, (vsyncend & 0x0F) | 0x20); 1101414c4531SDave Airlie WREG_CRT(18, vdisplay & 0xFF); 1102414c4531SDave Airlie WREG_CRT(19, pitch & 0xFF); 1103414c4531SDave Airlie WREG_CRT(20, 0); 1104414c4531SDave Airlie WREG_CRT(21, vdisplay & 0xFF); 1105414c4531SDave Airlie WREG_CRT(22, (vtotal + 1) & 0xFF); 1106414c4531SDave Airlie WREG_CRT(23, 0xc3); 1107414c4531SDave Airlie WREG_CRT(24, vdisplay & 0xFF); 1108414c4531SDave Airlie 1109414c4531SDave Airlie ext_vga[0] = 0; 1110414c4531SDave Airlie ext_vga[5] = 0; 1111414c4531SDave Airlie 1112414c4531SDave Airlie /* TODO interlace */ 1113414c4531SDave Airlie 1114414c4531SDave Airlie ext_vga[0] |= (pitch & 0x300) >> 4; 1115414c4531SDave Airlie ext_vga[1] = (((htotal - 4) & 0x100) >> 8) | 1116414c4531SDave Airlie ((hdisplay & 0x100) >> 7) | 1117414c4531SDave Airlie ((hsyncstart & 0x100) >> 6) | 1118414c4531SDave Airlie (htotal & 0x40); 1119414c4531SDave Airlie ext_vga[2] = ((vtotal & 0xc00) >> 10) | 1120414c4531SDave Airlie ((vdisplay & 0x400) >> 8) | 1121414c4531SDave Airlie ((vdisplay & 0xc00) >> 7) | 1122414c4531SDave Airlie ((vsyncstart & 0xc00) >> 5) | 1123414c4531SDave Airlie ((vdisplay & 0x400) >> 3); 1124272725c7SVille Syrjälä if (fb->format->cpp[0] * 8 == 24) 1125414c4531SDave Airlie ext_vga[3] = (((1 << bppshift) * 3) - 1) | 0x80; 1126414c4531SDave Airlie else 1127414c4531SDave Airlie ext_vga[3] = ((1 << bppshift) - 1) | 0x80; 1128414c4531SDave Airlie ext_vga[4] = 0; 11296d857c18SMathieu Larouche if (mdev->type == G200_WB || mdev->type == G200_EW3) 1130414c4531SDave Airlie ext_vga[1] |= 0x88; 1131414c4531SDave Airlie 1132414c4531SDave Airlie /* Set pixel clocks */ 1133414c4531SDave Airlie misc = 0x2d; 1134414c4531SDave Airlie WREG8(MGA_MISC_OUT, misc); 1135414c4531SDave Airlie 1136414c4531SDave Airlie mga_crtc_set_plls(mdev, mode->clock); 1137414c4531SDave Airlie 1138414c4531SDave Airlie for (i = 0; i < 6; i++) { 1139414c4531SDave Airlie WREG_ECRT(i, ext_vga[i]); 1140414c4531SDave Airlie } 1141414c4531SDave Airlie 1142414c4531SDave Airlie if (mdev->type == G200_ER) 11431812a3dbSChristopher Harvey WREG_ECRT(0x24, 0x5); 1144414c4531SDave Airlie 11456d857c18SMathieu Larouche if (mdev->type == G200_EW3) 11466d857c18SMathieu Larouche WREG_ECRT(0x34, 0x5); 11476d857c18SMathieu Larouche 1148414c4531SDave Airlie if (mdev->type == G200_EV) { 1149414c4531SDave Airlie WREG_ECRT(6, 0); 1150414c4531SDave Airlie } 1151414c4531SDave Airlie 1152414c4531SDave Airlie WREG_ECRT(0, ext_vga[0]); 1153414c4531SDave Airlie /* Enable mga pixel clock */ 1154414c4531SDave Airlie misc = 0x2d; 1155414c4531SDave Airlie 1156414c4531SDave Airlie WREG8(MGA_MISC_OUT, misc); 1157414c4531SDave Airlie 1158414c4531SDave Airlie if (adjusted_mode) 1159414c4531SDave Airlie memcpy(&mdev->mode, mode, sizeof(struct drm_display_mode)); 1160414c4531SDave Airlie 1161414c4531SDave Airlie mga_crtc_do_set_base(crtc, old_fb, x, y, 0); 1162414c4531SDave Airlie 1163414c4531SDave Airlie /* reset tagfifo */ 1164414c4531SDave Airlie if (mdev->type == G200_ER) { 1165414c4531SDave Airlie u32 mem_ctl = RREG32(MGAREG_MEMCTL); 1166414c4531SDave Airlie u8 seq1; 1167414c4531SDave Airlie 1168414c4531SDave Airlie /* screen off */ 1169414c4531SDave Airlie WREG8(MGAREG_SEQ_INDEX, 0x01); 1170414c4531SDave Airlie seq1 = RREG8(MGAREG_SEQ_DATA) | 0x20; 1171414c4531SDave Airlie WREG8(MGAREG_SEQ_DATA, seq1); 1172414c4531SDave Airlie 1173414c4531SDave Airlie WREG32(MGAREG_MEMCTL, mem_ctl | 0x00200000); 1174414c4531SDave Airlie udelay(1000); 1175414c4531SDave Airlie WREG32(MGAREG_MEMCTL, mem_ctl & ~0x00200000); 1176414c4531SDave Airlie 1177414c4531SDave Airlie WREG8(MGAREG_SEQ_DATA, seq1 & ~0x20); 1178414c4531SDave Airlie } 1179414c4531SDave Airlie 1180414c4531SDave Airlie 1181414c4531SDave Airlie if (IS_G200_SE(mdev)) { 11820cbb7381SMathieu Larouche if (mdev->unique_rev_id >= 0x04) { 11830cbb7381SMathieu Larouche WREG8(MGAREG_CRTCEXT_INDEX, 0x06); 11840cbb7381SMathieu Larouche WREG8(MGAREG_CRTCEXT_DATA, 0); 11850cbb7381SMathieu Larouche } else if (mdev->unique_rev_id >= 0x02) { 1186414c4531SDave Airlie u8 hi_pri_lvl; 1187414c4531SDave Airlie u32 bpp; 1188414c4531SDave Airlie u32 mb; 1189414c4531SDave Airlie 1190272725c7SVille Syrjälä if (fb->format->cpp[0] * 8 > 16) 1191414c4531SDave Airlie bpp = 32; 1192272725c7SVille Syrjälä else if (fb->format->cpp[0] * 8 > 8) 1193414c4531SDave Airlie bpp = 16; 1194414c4531SDave Airlie else 1195414c4531SDave Airlie bpp = 8; 1196414c4531SDave Airlie 1197414c4531SDave Airlie mb = (mode->clock * bpp) / 1000; 1198414c4531SDave Airlie if (mb > 3100) 1199414c4531SDave Airlie hi_pri_lvl = 0; 1200414c4531SDave Airlie else if (mb > 2600) 1201414c4531SDave Airlie hi_pri_lvl = 1; 1202414c4531SDave Airlie else if (mb > 1900) 1203414c4531SDave Airlie hi_pri_lvl = 2; 1204414c4531SDave Airlie else if (mb > 1160) 1205414c4531SDave Airlie hi_pri_lvl = 3; 1206414c4531SDave Airlie else if (mb > 440) 1207414c4531SDave Airlie hi_pri_lvl = 4; 1208414c4531SDave Airlie else 1209414c4531SDave Airlie hi_pri_lvl = 5; 1210414c4531SDave Airlie 121191f8f105SChristopher Harvey WREG8(MGAREG_CRTCEXT_INDEX, 0x06); 121291f8f105SChristopher Harvey WREG8(MGAREG_CRTCEXT_DATA, hi_pri_lvl); 1213414c4531SDave Airlie } else { 121491f8f105SChristopher Harvey WREG8(MGAREG_CRTCEXT_INDEX, 0x06); 1215abbee623SJulia Lemire if (mdev->unique_rev_id >= 0x01) 121691f8f105SChristopher Harvey WREG8(MGAREG_CRTCEXT_DATA, 0x03); 1217414c4531SDave Airlie else 121891f8f105SChristopher Harvey WREG8(MGAREG_CRTCEXT_DATA, 0x04); 1219414c4531SDave Airlie } 1220414c4531SDave Airlie } 1221414c4531SDave Airlie return 0; 1222414c4531SDave Airlie } 1223414c4531SDave Airlie 1224414c4531SDave Airlie #if 0 /* code from mjg to attempt D3 on crtc dpms off - revisit later */ 1225414c4531SDave Airlie static int mga_suspend(struct drm_crtc *crtc) 1226414c4531SDave Airlie { 1227414c4531SDave Airlie struct mga_crtc *mga_crtc = to_mga_crtc(crtc); 1228414c4531SDave Airlie struct drm_device *dev = crtc->dev; 1229414c4531SDave Airlie struct mga_device *mdev = dev->dev_private; 1230414c4531SDave Airlie struct pci_dev *pdev = dev->pdev; 1231414c4531SDave Airlie int option; 1232414c4531SDave Airlie 1233414c4531SDave Airlie if (mdev->suspended) 1234414c4531SDave Airlie return 0; 1235414c4531SDave Airlie 1236414c4531SDave Airlie WREG_SEQ(1, 0x20); 1237414c4531SDave Airlie WREG_ECRT(1, 0x30); 1238414c4531SDave Airlie /* Disable the pixel clock */ 1239414c4531SDave Airlie WREG_DAC(0x1a, 0x05); 1240414c4531SDave Airlie /* Power down the DAC */ 1241414c4531SDave Airlie WREG_DAC(0x1e, 0x18); 1242414c4531SDave Airlie /* Power down the pixel PLL */ 1243414c4531SDave Airlie WREG_DAC(0x1a, 0x0d); 1244414c4531SDave Airlie 1245414c4531SDave Airlie /* Disable PLLs and clocks */ 1246414c4531SDave Airlie pci_read_config_dword(pdev, PCI_MGA_OPTION, &option); 1247414c4531SDave Airlie option &= ~(0x1F8024); 1248414c4531SDave Airlie pci_write_config_dword(pdev, PCI_MGA_OPTION, option); 1249414c4531SDave Airlie pci_set_power_state(pdev, PCI_D3hot); 1250414c4531SDave Airlie pci_disable_device(pdev); 1251414c4531SDave Airlie 1252414c4531SDave Airlie mdev->suspended = true; 1253414c4531SDave Airlie 1254414c4531SDave Airlie return 0; 1255414c4531SDave Airlie } 1256414c4531SDave Airlie 1257414c4531SDave Airlie static int mga_resume(struct drm_crtc *crtc) 1258414c4531SDave Airlie { 1259414c4531SDave Airlie struct mga_crtc *mga_crtc = to_mga_crtc(crtc); 1260414c4531SDave Airlie struct drm_device *dev = crtc->dev; 1261414c4531SDave Airlie struct mga_device *mdev = dev->dev_private; 1262414c4531SDave Airlie struct pci_dev *pdev = dev->pdev; 1263414c4531SDave Airlie int option; 1264414c4531SDave Airlie 1265414c4531SDave Airlie if (!mdev->suspended) 1266414c4531SDave Airlie return 0; 1267414c4531SDave Airlie 1268414c4531SDave Airlie pci_set_power_state(pdev, PCI_D0); 1269414c4531SDave Airlie pci_enable_device(pdev); 1270414c4531SDave Airlie 1271414c4531SDave Airlie /* Disable sysclk */ 1272414c4531SDave Airlie pci_read_config_dword(pdev, PCI_MGA_OPTION, &option); 1273414c4531SDave Airlie option &= ~(0x4); 1274414c4531SDave Airlie pci_write_config_dword(pdev, PCI_MGA_OPTION, option); 1275414c4531SDave Airlie 1276414c4531SDave Airlie mdev->suspended = false; 1277414c4531SDave Airlie 1278414c4531SDave Airlie return 0; 1279414c4531SDave Airlie } 1280414c4531SDave Airlie 1281414c4531SDave Airlie #endif 1282414c4531SDave Airlie 1283414c4531SDave Airlie static void mga_crtc_dpms(struct drm_crtc *crtc, int mode) 1284414c4531SDave Airlie { 1285414c4531SDave Airlie struct drm_device *dev = crtc->dev; 1286414c4531SDave Airlie struct mga_device *mdev = dev->dev_private; 1287414c4531SDave Airlie u8 seq1 = 0, crtcext1 = 0; 1288414c4531SDave Airlie 1289414c4531SDave Airlie switch (mode) { 1290414c4531SDave Airlie case DRM_MODE_DPMS_ON: 1291414c4531SDave Airlie seq1 = 0; 1292414c4531SDave Airlie crtcext1 = 0; 1293414c4531SDave Airlie mga_crtc_load_lut(crtc); 1294414c4531SDave Airlie break; 1295414c4531SDave Airlie case DRM_MODE_DPMS_STANDBY: 1296414c4531SDave Airlie seq1 = 0x20; 1297414c4531SDave Airlie crtcext1 = 0x10; 1298414c4531SDave Airlie break; 1299414c4531SDave Airlie case DRM_MODE_DPMS_SUSPEND: 1300414c4531SDave Airlie seq1 = 0x20; 1301414c4531SDave Airlie crtcext1 = 0x20; 1302414c4531SDave Airlie break; 1303414c4531SDave Airlie case DRM_MODE_DPMS_OFF: 1304414c4531SDave Airlie seq1 = 0x20; 1305414c4531SDave Airlie crtcext1 = 0x30; 1306414c4531SDave Airlie break; 1307414c4531SDave Airlie } 1308414c4531SDave Airlie 1309414c4531SDave Airlie #if 0 1310414c4531SDave Airlie if (mode == DRM_MODE_DPMS_OFF) { 1311414c4531SDave Airlie mga_suspend(crtc); 1312414c4531SDave Airlie } 1313414c4531SDave Airlie #endif 1314414c4531SDave Airlie WREG8(MGAREG_SEQ_INDEX, 0x01); 1315414c4531SDave Airlie seq1 |= RREG8(MGAREG_SEQ_DATA) & ~0x20; 1316414c4531SDave Airlie mga_wait_vsync(mdev); 1317414c4531SDave Airlie mga_wait_busy(mdev); 1318414c4531SDave Airlie WREG8(MGAREG_SEQ_DATA, seq1); 1319414c4531SDave Airlie msleep(20); 1320414c4531SDave Airlie WREG8(MGAREG_CRTCEXT_INDEX, 0x01); 1321414c4531SDave Airlie crtcext1 |= RREG8(MGAREG_CRTCEXT_DATA) & ~0x30; 1322414c4531SDave Airlie WREG8(MGAREG_CRTCEXT_DATA, crtcext1); 1323414c4531SDave Airlie 1324414c4531SDave Airlie #if 0 1325414c4531SDave Airlie if (mode == DRM_MODE_DPMS_ON && mdev->suspended == true) { 1326414c4531SDave Airlie mga_resume(crtc); 1327414c4531SDave Airlie drm_helper_resume_force_mode(dev); 1328414c4531SDave Airlie } 1329414c4531SDave Airlie #endif 1330414c4531SDave Airlie } 1331414c4531SDave Airlie 1332414c4531SDave Airlie /* 1333414c4531SDave Airlie * This is called before a mode is programmed. A typical use might be to 1334414c4531SDave Airlie * enable DPMS during the programming to avoid seeing intermediate stages, 1335414c4531SDave Airlie * but that's not relevant to us 1336414c4531SDave Airlie */ 1337414c4531SDave Airlie static void mga_crtc_prepare(struct drm_crtc *crtc) 1338414c4531SDave Airlie { 1339414c4531SDave Airlie struct drm_device *dev = crtc->dev; 1340414c4531SDave Airlie struct mga_device *mdev = dev->dev_private; 1341414c4531SDave Airlie u8 tmp; 1342414c4531SDave Airlie 1343414c4531SDave Airlie /* mga_resume(crtc);*/ 1344414c4531SDave Airlie 1345414c4531SDave Airlie WREG8(MGAREG_CRTC_INDEX, 0x11); 1346414c4531SDave Airlie tmp = RREG8(MGAREG_CRTC_DATA); 1347414c4531SDave Airlie WREG_CRT(0x11, tmp | 0x80); 1348414c4531SDave Airlie 1349414c4531SDave Airlie if (mdev->type == G200_SE_A || mdev->type == G200_SE_B) { 1350414c4531SDave Airlie WREG_SEQ(0, 1); 1351414c4531SDave Airlie msleep(50); 1352414c4531SDave Airlie WREG_SEQ(1, 0x20); 1353414c4531SDave Airlie msleep(20); 1354414c4531SDave Airlie } else { 1355414c4531SDave Airlie WREG8(MGAREG_SEQ_INDEX, 0x1); 1356414c4531SDave Airlie tmp = RREG8(MGAREG_SEQ_DATA); 1357414c4531SDave Airlie 1358414c4531SDave Airlie /* start sync reset */ 1359414c4531SDave Airlie WREG_SEQ(0, 1); 1360414c4531SDave Airlie WREG_SEQ(1, tmp | 0x20); 1361414c4531SDave Airlie } 1362414c4531SDave Airlie 13636d857c18SMathieu Larouche if (mdev->type == G200_WB || mdev->type == G200_EW3) 1364414c4531SDave Airlie mga_g200wb_prepare(crtc); 1365414c4531SDave Airlie 1366414c4531SDave Airlie WREG_CRT(17, 0); 1367414c4531SDave Airlie } 1368414c4531SDave Airlie 1369414c4531SDave Airlie /* 1370414c4531SDave Airlie * This is called after a mode is programmed. It should reverse anything done 1371414c4531SDave Airlie * by the prepare function 1372414c4531SDave Airlie */ 1373414c4531SDave Airlie static void mga_crtc_commit(struct drm_crtc *crtc) 1374414c4531SDave Airlie { 1375414c4531SDave Airlie struct drm_device *dev = crtc->dev; 1376414c4531SDave Airlie struct mga_device *mdev = dev->dev_private; 1377d584ff82SJani Nikula const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; 1378414c4531SDave Airlie u8 tmp; 1379414c4531SDave Airlie 13806d857c18SMathieu Larouche if (mdev->type == G200_WB || mdev->type == G200_EW3) 1381414c4531SDave Airlie mga_g200wb_commit(crtc); 1382414c4531SDave Airlie 1383414c4531SDave Airlie if (mdev->type == G200_SE_A || mdev->type == G200_SE_B) { 1384414c4531SDave Airlie msleep(50); 1385414c4531SDave Airlie WREG_SEQ(1, 0x0); 1386414c4531SDave Airlie msleep(20); 1387414c4531SDave Airlie WREG_SEQ(0, 0x3); 1388414c4531SDave Airlie } else { 1389414c4531SDave Airlie WREG8(MGAREG_SEQ_INDEX, 0x1); 1390414c4531SDave Airlie tmp = RREG8(MGAREG_SEQ_DATA); 1391414c4531SDave Airlie 1392414c4531SDave Airlie tmp &= ~0x20; 1393414c4531SDave Airlie WREG_SEQ(0x1, tmp); 1394414c4531SDave Airlie WREG_SEQ(0, 3); 1395414c4531SDave Airlie } 1396414c4531SDave Airlie crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); 1397414c4531SDave Airlie } 1398414c4531SDave Airlie 1399414c4531SDave Airlie /* 1400414c4531SDave Airlie * The core can pass us a set of gamma values to program. We actually only 1401414c4531SDave Airlie * use this for 8-bit mode so can't perform smooth fades on deeper modes, 1402414c4531SDave Airlie * but it's a requirement that we provide the function 1403414c4531SDave Airlie */ 14047ea77283SMaarten Lankhorst static int mga_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, 14056d124ff8SDaniel Vetter u16 *blue, uint32_t size, 14066d124ff8SDaniel Vetter struct drm_modeset_acquire_ctx *ctx) 1407414c4531SDave Airlie { 1408414c4531SDave Airlie mga_crtc_load_lut(crtc); 14097ea77283SMaarten Lankhorst 14107ea77283SMaarten Lankhorst return 0; 1411414c4531SDave Airlie } 1412414c4531SDave Airlie 1413414c4531SDave Airlie /* Simple cleanup function */ 1414414c4531SDave Airlie static void mga_crtc_destroy(struct drm_crtc *crtc) 1415414c4531SDave Airlie { 1416414c4531SDave Airlie struct mga_crtc *mga_crtc = to_mga_crtc(crtc); 1417414c4531SDave Airlie 1418414c4531SDave Airlie drm_crtc_cleanup(crtc); 1419414c4531SDave Airlie kfree(mga_crtc); 1420414c4531SDave Airlie } 1421414c4531SDave Airlie 142264c29076SEgbert Eich static void mga_crtc_disable(struct drm_crtc *crtc) 142364c29076SEgbert Eich { 142464c29076SEgbert Eich int ret; 142564c29076SEgbert Eich DRM_DEBUG_KMS("\n"); 142664c29076SEgbert Eich mga_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); 1427f4510a27SMatt Roper if (crtc->primary->fb) { 1428f4510a27SMatt Roper struct mga_framebuffer *mga_fb = to_mga_framebuffer(crtc->primary->fb); 142964c29076SEgbert Eich struct drm_gem_object *obj = mga_fb->obj; 143064c29076SEgbert Eich struct mgag200_bo *bo = gem_to_mga_bo(obj); 143164c29076SEgbert Eich ret = mgag200_bo_reserve(bo, false); 143264c29076SEgbert Eich if (ret) 143364c29076SEgbert Eich return; 143464c29076SEgbert Eich mgag200_bo_push_sysram(bo); 143564c29076SEgbert Eich mgag200_bo_unreserve(bo); 143664c29076SEgbert Eich } 1437f4510a27SMatt Roper crtc->primary->fb = NULL; 143864c29076SEgbert Eich } 143964c29076SEgbert Eich 1440414c4531SDave Airlie /* These provide the minimum set of functions required to handle a CRTC */ 1441414c4531SDave Airlie static const struct drm_crtc_funcs mga_crtc_funcs = { 1442a080db9fSChristopher Harvey .cursor_set = mga_crtc_cursor_set, 1443a080db9fSChristopher Harvey .cursor_move = mga_crtc_cursor_move, 1444414c4531SDave Airlie .gamma_set = mga_crtc_gamma_set, 1445414c4531SDave Airlie .set_config = drm_crtc_helper_set_config, 1446414c4531SDave Airlie .destroy = mga_crtc_destroy, 1447414c4531SDave Airlie }; 1448414c4531SDave Airlie 1449414c4531SDave Airlie static const struct drm_crtc_helper_funcs mga_helper_funcs = { 145064c29076SEgbert Eich .disable = mga_crtc_disable, 1451414c4531SDave Airlie .dpms = mga_crtc_dpms, 1452414c4531SDave Airlie .mode_set = mga_crtc_mode_set, 1453414c4531SDave Airlie .mode_set_base = mga_crtc_mode_set_base, 1454414c4531SDave Airlie .prepare = mga_crtc_prepare, 1455414c4531SDave Airlie .commit = mga_crtc_commit, 1456414c4531SDave Airlie }; 1457414c4531SDave Airlie 1458414c4531SDave Airlie /* CRTC setup */ 1459f1998fe2SChristopher Harvey static void mga_crtc_init(struct mga_device *mdev) 1460414c4531SDave Airlie { 1461414c4531SDave Airlie struct mga_crtc *mga_crtc; 1462414c4531SDave Airlie 1463414c4531SDave Airlie mga_crtc = kzalloc(sizeof(struct mga_crtc) + 1464414c4531SDave Airlie (MGAG200FB_CONN_LIMIT * sizeof(struct drm_connector *)), 1465414c4531SDave Airlie GFP_KERNEL); 1466414c4531SDave Airlie 1467414c4531SDave Airlie if (mga_crtc == NULL) 1468414c4531SDave Airlie return; 1469414c4531SDave Airlie 1470f1998fe2SChristopher Harvey drm_crtc_init(mdev->dev, &mga_crtc->base, &mga_crtc_funcs); 1471414c4531SDave Airlie 1472414c4531SDave Airlie drm_mode_crtc_set_gamma_size(&mga_crtc->base, MGAG200_LUT_SIZE); 1473414c4531SDave Airlie mdev->mode_info.crtc = mga_crtc; 1474414c4531SDave Airlie 1475414c4531SDave Airlie drm_crtc_helper_add(&mga_crtc->base, &mga_helper_funcs); 1476414c4531SDave Airlie } 1477414c4531SDave Airlie 1478414c4531SDave Airlie /* 1479414c4531SDave Airlie * The encoder comes after the CRTC in the output pipeline, but before 1480414c4531SDave Airlie * the connector. It's responsible for ensuring that the digital 1481414c4531SDave Airlie * stream is appropriately converted into the output format. Setup is 1482414c4531SDave Airlie * very simple in this case - all we have to do is inform qemu of the 1483414c4531SDave Airlie * colour depth in order to ensure that it displays appropriately 1484414c4531SDave Airlie */ 1485414c4531SDave Airlie 1486414c4531SDave Airlie /* 1487414c4531SDave Airlie * These functions are analagous to those in the CRTC code, but are intended 1488414c4531SDave Airlie * to handle any encoder-specific limitations 1489414c4531SDave Airlie */ 1490414c4531SDave Airlie static void mga_encoder_mode_set(struct drm_encoder *encoder, 1491414c4531SDave Airlie struct drm_display_mode *mode, 1492414c4531SDave Airlie struct drm_display_mode *adjusted_mode) 1493414c4531SDave Airlie { 1494414c4531SDave Airlie 1495414c4531SDave Airlie } 1496414c4531SDave Airlie 1497414c4531SDave Airlie static void mga_encoder_dpms(struct drm_encoder *encoder, int state) 1498414c4531SDave Airlie { 1499414c4531SDave Airlie return; 1500414c4531SDave Airlie } 1501414c4531SDave Airlie 1502414c4531SDave Airlie static void mga_encoder_prepare(struct drm_encoder *encoder) 1503414c4531SDave Airlie { 1504414c4531SDave Airlie } 1505414c4531SDave Airlie 1506414c4531SDave Airlie static void mga_encoder_commit(struct drm_encoder *encoder) 1507414c4531SDave Airlie { 1508414c4531SDave Airlie } 1509414c4531SDave Airlie 1510080fd6b5SRashika static void mga_encoder_destroy(struct drm_encoder *encoder) 1511414c4531SDave Airlie { 1512414c4531SDave Airlie struct mga_encoder *mga_encoder = to_mga_encoder(encoder); 1513414c4531SDave Airlie drm_encoder_cleanup(encoder); 1514414c4531SDave Airlie kfree(mga_encoder); 1515414c4531SDave Airlie } 1516414c4531SDave Airlie 1517414c4531SDave Airlie static const struct drm_encoder_helper_funcs mga_encoder_helper_funcs = { 1518414c4531SDave Airlie .dpms = mga_encoder_dpms, 1519414c4531SDave Airlie .mode_set = mga_encoder_mode_set, 1520414c4531SDave Airlie .prepare = mga_encoder_prepare, 1521414c4531SDave Airlie .commit = mga_encoder_commit, 1522414c4531SDave Airlie }; 1523414c4531SDave Airlie 1524414c4531SDave Airlie static const struct drm_encoder_funcs mga_encoder_encoder_funcs = { 1525414c4531SDave Airlie .destroy = mga_encoder_destroy, 1526414c4531SDave Airlie }; 1527414c4531SDave Airlie 1528414c4531SDave Airlie static struct drm_encoder *mga_encoder_init(struct drm_device *dev) 1529414c4531SDave Airlie { 1530414c4531SDave Airlie struct drm_encoder *encoder; 1531414c4531SDave Airlie struct mga_encoder *mga_encoder; 1532414c4531SDave Airlie 1533414c4531SDave Airlie mga_encoder = kzalloc(sizeof(struct mga_encoder), GFP_KERNEL); 1534414c4531SDave Airlie if (!mga_encoder) 1535414c4531SDave Airlie return NULL; 1536414c4531SDave Airlie 1537414c4531SDave Airlie encoder = &mga_encoder->base; 1538414c4531SDave Airlie encoder->possible_crtcs = 0x1; 1539414c4531SDave Airlie 1540414c4531SDave Airlie drm_encoder_init(dev, encoder, &mga_encoder_encoder_funcs, 154113a3d91fSVille Syrjälä DRM_MODE_ENCODER_DAC, NULL); 1542414c4531SDave Airlie drm_encoder_helper_add(encoder, &mga_encoder_helper_funcs); 1543414c4531SDave Airlie 1544414c4531SDave Airlie return encoder; 1545414c4531SDave Airlie } 1546414c4531SDave Airlie 1547414c4531SDave Airlie 1548414c4531SDave Airlie static int mga_vga_get_modes(struct drm_connector *connector) 1549414c4531SDave Airlie { 1550414c4531SDave Airlie struct mga_connector *mga_connector = to_mga_connector(connector); 1551414c4531SDave Airlie struct edid *edid; 1552414c4531SDave Airlie int ret = 0; 1553414c4531SDave Airlie 1554414c4531SDave Airlie edid = drm_get_edid(connector, &mga_connector->i2c->adapter); 1555414c4531SDave Airlie if (edid) { 1556414c4531SDave Airlie drm_mode_connector_update_edid_property(connector, edid); 1557414c4531SDave Airlie ret = drm_add_edid_modes(connector, edid); 1558414c4531SDave Airlie kfree(edid); 1559414c4531SDave Airlie } 1560414c4531SDave Airlie return ret; 1561414c4531SDave Airlie } 1562414c4531SDave Airlie 1563abbee623SJulia Lemire static uint32_t mga_vga_calculate_mode_bandwidth(struct drm_display_mode *mode, 1564abbee623SJulia Lemire int bits_per_pixel) 1565abbee623SJulia Lemire { 1566abbee623SJulia Lemire uint32_t total_area, divisor; 1567c24ca5beSNicolas Pitre uint64_t active_area, pixels_per_second, bandwidth; 1568abbee623SJulia Lemire uint64_t bytes_per_pixel = (bits_per_pixel + 7) / 8; 1569abbee623SJulia Lemire 1570abbee623SJulia Lemire divisor = 1024; 1571abbee623SJulia Lemire 1572abbee623SJulia Lemire if (!mode->htotal || !mode->vtotal || !mode->clock) 1573abbee623SJulia Lemire return 0; 1574abbee623SJulia Lemire 1575abbee623SJulia Lemire active_area = mode->hdisplay * mode->vdisplay; 1576abbee623SJulia Lemire total_area = mode->htotal * mode->vtotal; 1577abbee623SJulia Lemire 1578abbee623SJulia Lemire pixels_per_second = active_area * mode->clock * 1000; 1579abbee623SJulia Lemire do_div(pixels_per_second, total_area); 1580abbee623SJulia Lemire 1581abbee623SJulia Lemire bandwidth = pixels_per_second * bytes_per_pixel * 100; 1582abbee623SJulia Lemire do_div(bandwidth, divisor); 1583abbee623SJulia Lemire 1584abbee623SJulia Lemire return (uint32_t)(bandwidth); 1585abbee623SJulia Lemire } 1586abbee623SJulia Lemire 1587abbee623SJulia Lemire #define MODE_BANDWIDTH MODE_BAD 1588abbee623SJulia Lemire 1589414c4531SDave Airlie static int mga_vga_mode_valid(struct drm_connector *connector, 1590414c4531SDave Airlie struct drm_display_mode *mode) 1591414c4531SDave Airlie { 15920ba53171SChristopher Harvey struct drm_device *dev = connector->dev; 15930ba53171SChristopher Harvey struct mga_device *mdev = (struct mga_device*)dev->dev_private; 15940ba53171SChristopher Harvey int bpp = 32; 15950ba53171SChristopher Harvey 1596abbee623SJulia Lemire if (IS_G200_SE(mdev)) { 1597abbee623SJulia Lemire if (mdev->unique_rev_id == 0x01) { 1598abbee623SJulia Lemire if (mode->hdisplay > 1600) 1599abbee623SJulia Lemire return MODE_VIRTUAL_X; 1600abbee623SJulia Lemire if (mode->vdisplay > 1200) 1601abbee623SJulia Lemire return MODE_VIRTUAL_Y; 1602abbee623SJulia Lemire if (mga_vga_calculate_mode_bandwidth(mode, bpp) 1603abbee623SJulia Lemire > (24400 * 1024)) 1604abbee623SJulia Lemire return MODE_BANDWIDTH; 1605e829d7efSMathieu Larouche } else if (mdev->unique_rev_id == 0x02) { 1606abbee623SJulia Lemire if (mode->hdisplay > 1920) 1607abbee623SJulia Lemire return MODE_VIRTUAL_X; 1608abbee623SJulia Lemire if (mode->vdisplay > 1200) 1609abbee623SJulia Lemire return MODE_VIRTUAL_Y; 1610abbee623SJulia Lemire if (mga_vga_calculate_mode_bandwidth(mode, bpp) 1611abbee623SJulia Lemire > (30100 * 1024)) 1612abbee623SJulia Lemire return MODE_BANDWIDTH; 16130cbb7381SMathieu Larouche } else { 16140cbb7381SMathieu Larouche if (mga_vga_calculate_mode_bandwidth(mode, bpp) 16150cbb7381SMathieu Larouche > (55000 * 1024)) 16160cbb7381SMathieu Larouche return MODE_BANDWIDTH; 1617abbee623SJulia Lemire } 1618abbee623SJulia Lemire } else if (mdev->type == G200_WB) { 1619abbee623SJulia Lemire if (mode->hdisplay > 1280) 1620abbee623SJulia Lemire return MODE_VIRTUAL_X; 1621abbee623SJulia Lemire if (mode->vdisplay > 1024) 1622abbee623SJulia Lemire return MODE_VIRTUAL_Y; 1623*9eb8d7a9SDan Carpenter if (mga_vga_calculate_mode_bandwidth(mode, bpp) > 1624*9eb8d7a9SDan Carpenter (31877 * 1024)) 1625abbee623SJulia Lemire return MODE_BANDWIDTH; 1626abbee623SJulia Lemire } else if (mdev->type == G200_EV && 1627abbee623SJulia Lemire (mga_vga_calculate_mode_bandwidth(mode, bpp) 1628abbee623SJulia Lemire > (32700 * 1024))) { 1629abbee623SJulia Lemire return MODE_BANDWIDTH; 1630ec22b4aaSDave Airlie } else if (mdev->type == G200_EH && 1631abbee623SJulia Lemire (mga_vga_calculate_mode_bandwidth(mode, bpp) 1632abbee623SJulia Lemire > (37500 * 1024))) { 1633abbee623SJulia Lemire return MODE_BANDWIDTH; 1634ec22b4aaSDave Airlie } else if (mdev->type == G200_ER && 1635abbee623SJulia Lemire (mga_vga_calculate_mode_bandwidth(mode, 1636abbee623SJulia Lemire bpp) > (55000 * 1024))) { 1637abbee623SJulia Lemire return MODE_BANDWIDTH; 1638abbee623SJulia Lemire } 1639414c4531SDave Airlie 164025161084SAdam Jackson if ((mode->hdisplay % 8) != 0 || (mode->hsync_start % 8) != 0 || 164125161084SAdam Jackson (mode->hsync_end % 8) != 0 || (mode->htotal % 8) != 0) { 164225161084SAdam Jackson return MODE_H_ILLEGAL; 164325161084SAdam Jackson } 164425161084SAdam Jackson 1645414c4531SDave Airlie if (mode->crtc_hdisplay > 2048 || mode->crtc_hsync_start > 4096 || 1646414c4531SDave Airlie mode->crtc_hsync_end > 4096 || mode->crtc_htotal > 4096 || 1647414c4531SDave Airlie mode->crtc_vdisplay > 2048 || mode->crtc_vsync_start > 4096 || 1648414c4531SDave Airlie mode->crtc_vsync_end > 4096 || mode->crtc_vtotal > 4096) { 1649414c4531SDave Airlie return MODE_BAD; 1650414c4531SDave Airlie } 1651414c4531SDave Airlie 16520ba53171SChristopher Harvey /* Validate the mode input by the user */ 1653eaf99c74SChris Wilson if (connector->cmdline_mode.specified) { 1654eaf99c74SChris Wilson if (connector->cmdline_mode.bpp_specified) 1655eaf99c74SChris Wilson bpp = connector->cmdline_mode.bpp; 16560ba53171SChristopher Harvey } 16570ba53171SChristopher Harvey 16580ba53171SChristopher Harvey if ((mode->hdisplay * mode->vdisplay * (bpp/8)) > mdev->mc.vram_size) { 1659eaf99c74SChris Wilson if (connector->cmdline_mode.specified) 1660eaf99c74SChris Wilson connector->cmdline_mode.specified = false; 16610ba53171SChristopher Harvey return MODE_BAD; 16620ba53171SChristopher Harvey } 16630ba53171SChristopher Harvey 1664414c4531SDave Airlie return MODE_OK; 1665414c4531SDave Airlie } 1666414c4531SDave Airlie 1667080fd6b5SRashika static struct drm_encoder *mga_connector_best_encoder(struct drm_connector 1668414c4531SDave Airlie *connector) 1669414c4531SDave Airlie { 1670414c4531SDave Airlie int enc_id = connector->encoder_ids[0]; 1671414c4531SDave Airlie /* pick the encoder ids */ 1672c7e95114SRob Clark if (enc_id) 1673418da172SKeith Packard return drm_encoder_find(connector->dev, NULL, enc_id); 1674414c4531SDave Airlie return NULL; 1675414c4531SDave Airlie } 1676414c4531SDave Airlie 1677414c4531SDave Airlie static void mga_connector_destroy(struct drm_connector *connector) 1678414c4531SDave Airlie { 1679414c4531SDave Airlie struct mga_connector *mga_connector = to_mga_connector(connector); 1680414c4531SDave Airlie mgag200_i2c_destroy(mga_connector->i2c); 1681414c4531SDave Airlie drm_connector_cleanup(connector); 1682414c4531SDave Airlie kfree(connector); 1683414c4531SDave Airlie } 1684414c4531SDave Airlie 168571cb7495SVille Syrjälä static const struct drm_connector_helper_funcs mga_vga_connector_helper_funcs = { 1686414c4531SDave Airlie .get_modes = mga_vga_get_modes, 1687414c4531SDave Airlie .mode_valid = mga_vga_mode_valid, 1688414c4531SDave Airlie .best_encoder = mga_connector_best_encoder, 1689414c4531SDave Airlie }; 1690414c4531SDave Airlie 169171cb7495SVille Syrjälä static const struct drm_connector_funcs mga_vga_connector_funcs = { 1692414c4531SDave Airlie .dpms = drm_helper_connector_dpms, 1693414c4531SDave Airlie .fill_modes = drm_helper_probe_single_connector_modes, 1694414c4531SDave Airlie .destroy = mga_connector_destroy, 1695414c4531SDave Airlie }; 1696414c4531SDave Airlie 1697414c4531SDave Airlie static struct drm_connector *mga_vga_init(struct drm_device *dev) 1698414c4531SDave Airlie { 1699414c4531SDave Airlie struct drm_connector *connector; 1700414c4531SDave Airlie struct mga_connector *mga_connector; 1701414c4531SDave Airlie 1702414c4531SDave Airlie mga_connector = kzalloc(sizeof(struct mga_connector), GFP_KERNEL); 1703414c4531SDave Airlie if (!mga_connector) 1704414c4531SDave Airlie return NULL; 1705414c4531SDave Airlie 1706414c4531SDave Airlie connector = &mga_connector->base; 1707414c4531SDave Airlie 1708414c4531SDave Airlie drm_connector_init(dev, connector, 1709414c4531SDave Airlie &mga_vga_connector_funcs, DRM_MODE_CONNECTOR_VGA); 1710414c4531SDave Airlie 1711414c4531SDave Airlie drm_connector_helper_add(connector, &mga_vga_connector_helper_funcs); 1712414c4531SDave Airlie 171334ea3d38SThomas Wood drm_connector_register(connector); 17143d5a1c5eSEgbert Eich 1715414c4531SDave Airlie mga_connector->i2c = mgag200_i2c_create(dev); 1716414c4531SDave Airlie if (!mga_connector->i2c) 1717414c4531SDave Airlie DRM_ERROR("failed to add ddc bus\n"); 1718414c4531SDave Airlie 1719414c4531SDave Airlie return connector; 1720414c4531SDave Airlie } 1721414c4531SDave Airlie 1722414c4531SDave Airlie 1723414c4531SDave Airlie int mgag200_modeset_init(struct mga_device *mdev) 1724414c4531SDave Airlie { 1725414c4531SDave Airlie struct drm_encoder *encoder; 1726414c4531SDave Airlie struct drm_connector *connector; 1727414c4531SDave Airlie int ret; 1728414c4531SDave Airlie 1729414c4531SDave Airlie mdev->mode_info.mode_config_initialized = true; 1730414c4531SDave Airlie 1731414c4531SDave Airlie mdev->dev->mode_config.max_width = MGAG200_MAX_FB_WIDTH; 1732414c4531SDave Airlie mdev->dev->mode_config.max_height = MGAG200_MAX_FB_HEIGHT; 1733414c4531SDave Airlie 1734414c4531SDave Airlie mdev->dev->mode_config.fb_base = mdev->mc.vram_base; 1735414c4531SDave Airlie 1736f1998fe2SChristopher Harvey mga_crtc_init(mdev); 1737414c4531SDave Airlie 1738414c4531SDave Airlie encoder = mga_encoder_init(mdev->dev); 1739414c4531SDave Airlie if (!encoder) { 1740414c4531SDave Airlie DRM_ERROR("mga_encoder_init failed\n"); 1741414c4531SDave Airlie return -1; 1742414c4531SDave Airlie } 1743414c4531SDave Airlie 1744414c4531SDave Airlie connector = mga_vga_init(mdev->dev); 1745414c4531SDave Airlie if (!connector) { 1746414c4531SDave Airlie DRM_ERROR("mga_vga_init failed\n"); 1747414c4531SDave Airlie return -1; 1748414c4531SDave Airlie } 1749414c4531SDave Airlie 1750414c4531SDave Airlie drm_mode_connector_attach_encoder(connector, encoder); 1751414c4531SDave Airlie 1752414c4531SDave Airlie ret = mgag200_fbdev_init(mdev); 1753414c4531SDave Airlie if (ret) { 1754414c4531SDave Airlie DRM_ERROR("mga_fbdev_init failed\n"); 1755414c4531SDave Airlie return ret; 1756414c4531SDave Airlie } 1757414c4531SDave Airlie 1758414c4531SDave Airlie return 0; 1759414c4531SDave Airlie } 1760414c4531SDave Airlie 1761414c4531SDave Airlie void mgag200_modeset_fini(struct mga_device *mdev) 1762414c4531SDave Airlie { 1763414c4531SDave Airlie 1764414c4531SDave Airlie } 1765