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> 1249a3f51dSThomas Zimmermann #include <linux/dma-buf-map.h> 13414c4531SDave Airlie 1488fabb75SThomas Zimmermann #include <drm/drm_atomic_helper.h> 1588fabb75SThomas Zimmermann #include <drm/drm_atomic_state_helper.h> 16760285e7SDavid Howells #include <drm/drm_crtc_helper.h> 17913ec479SThomas Zimmermann #include <drm/drm_damage_helper.h> 18913ec479SThomas Zimmermann #include <drm/drm_format_helper.h> 199f397801SSam Ravnborg #include <drm/drm_fourcc.h> 204862ffaeSThomas Zimmermann #include <drm/drm_gem_atomic_helper.h> 215635b7cfSThomas Zimmermann #include <drm/drm_gem_framebuffer_helper.h> 223cb9ae4fSDaniel Vetter #include <drm/drm_plane_helper.h> 2388fabb75SThomas Zimmermann #include <drm/drm_print.h> 24fcd70cd3SDaniel Vetter #include <drm/drm_probe_helper.h> 2503e44ad1SThomas Zimmermann #include <drm/drm_simple_kms_helper.h> 26414c4531SDave Airlie 27414c4531SDave Airlie #include "mgag200_drv.h" 28414c4531SDave Airlie 29414c4531SDave Airlie #define MGAG200_LUT_SIZE 256 30414c4531SDave Airlie 31414c4531SDave Airlie /* 32414c4531SDave Airlie * This file contains setup code for the CRTC. 33414c4531SDave Airlie */ 34414c4531SDave Airlie 35414c4531SDave Airlie static void mga_crtc_load_lut(struct drm_crtc *crtc) 36414c4531SDave Airlie { 37414c4531SDave Airlie struct drm_device *dev = crtc->dev; 388d8ff2a9SThomas Zimmermann struct mga_device *mdev = to_mga_device(dev); 3988fabb75SThomas Zimmermann struct drm_framebuffer *fb; 409ed85e14SPeter Rosin u16 *r_ptr, *g_ptr, *b_ptr; 41414c4531SDave Airlie int i; 42414c4531SDave Airlie 43414c4531SDave Airlie if (!crtc->enabled) 44414c4531SDave Airlie return; 45414c4531SDave Airlie 4688fabb75SThomas Zimmermann if (!mdev->display_pipe.plane.state) 4788fabb75SThomas Zimmermann return; 4888fabb75SThomas Zimmermann 4988fabb75SThomas Zimmermann fb = mdev->display_pipe.plane.state->fb; 5088fabb75SThomas Zimmermann 519ed85e14SPeter Rosin r_ptr = crtc->gamma_store; 529ed85e14SPeter Rosin g_ptr = r_ptr + crtc->gamma_size; 539ed85e14SPeter Rosin b_ptr = g_ptr + crtc->gamma_size; 549ed85e14SPeter Rosin 55414c4531SDave Airlie WREG8(DAC_INDEX + MGA1064_INDEX, 0); 56414c4531SDave Airlie 57272725c7SVille Syrjälä if (fb && fb->format->cpp[0] * 8 == 16) { 58b00c600eSVille Syrjälä int inc = (fb->format->depth == 15) ? 8 : 4; 59de7500eaSEgbert Eich u8 r, b; 60de7500eaSEgbert Eich for (i = 0; i < MGAG200_LUT_SIZE; i += inc) { 61b00c600eSVille Syrjälä if (fb->format->depth == 16) { 62de7500eaSEgbert Eich if (i > (MGAG200_LUT_SIZE >> 1)) { 63de7500eaSEgbert Eich r = b = 0; 64de7500eaSEgbert Eich } else { 659ed85e14SPeter Rosin r = *r_ptr++ >> 8; 669ed85e14SPeter Rosin b = *b_ptr++ >> 8; 679ed85e14SPeter Rosin r_ptr++; 689ed85e14SPeter Rosin b_ptr++; 69de7500eaSEgbert Eich } 70de7500eaSEgbert Eich } else { 719ed85e14SPeter Rosin r = *r_ptr++ >> 8; 729ed85e14SPeter Rosin b = *b_ptr++ >> 8; 73de7500eaSEgbert Eich } 74de7500eaSEgbert Eich /* VGA registers */ 75de7500eaSEgbert Eich WREG8(DAC_INDEX + MGA1064_COL_PAL, r); 769ed85e14SPeter Rosin WREG8(DAC_INDEX + MGA1064_COL_PAL, *g_ptr++ >> 8); 77de7500eaSEgbert Eich WREG8(DAC_INDEX + MGA1064_COL_PAL, b); 78de7500eaSEgbert Eich } 79de7500eaSEgbert Eich return; 80de7500eaSEgbert Eich } 81414c4531SDave Airlie for (i = 0; i < MGAG200_LUT_SIZE; i++) { 82414c4531SDave Airlie /* VGA registers */ 839ed85e14SPeter Rosin WREG8(DAC_INDEX + MGA1064_COL_PAL, *r_ptr++ >> 8); 849ed85e14SPeter Rosin WREG8(DAC_INDEX + MGA1064_COL_PAL, *g_ptr++ >> 8); 859ed85e14SPeter Rosin WREG8(DAC_INDEX + MGA1064_COL_PAL, *b_ptr++ >> 8); 86414c4531SDave Airlie } 87414c4531SDave Airlie } 88414c4531SDave Airlie 89414c4531SDave Airlie static inline void mga_wait_vsync(struct mga_device *mdev) 90414c4531SDave Airlie { 913cdc0e8dSChristopher Harvey unsigned long timeout = jiffies + HZ/10; 92414c4531SDave Airlie unsigned int status = 0; 93414c4531SDave Airlie 94414c4531SDave Airlie do { 95414c4531SDave Airlie status = RREG32(MGAREG_Status); 963cdc0e8dSChristopher Harvey } while ((status & 0x08) && time_before(jiffies, timeout)); 973cdc0e8dSChristopher Harvey timeout = jiffies + HZ/10; 98414c4531SDave Airlie status = 0; 99414c4531SDave Airlie do { 100414c4531SDave Airlie status = RREG32(MGAREG_Status); 1013cdc0e8dSChristopher Harvey } while (!(status & 0x08) && time_before(jiffies, timeout)); 102414c4531SDave Airlie } 103414c4531SDave Airlie 104414c4531SDave Airlie static inline void mga_wait_busy(struct mga_device *mdev) 105414c4531SDave Airlie { 1063cdc0e8dSChristopher Harvey unsigned long timeout = jiffies + HZ; 107414c4531SDave Airlie unsigned int status = 0; 108414c4531SDave Airlie do { 109414c4531SDave Airlie status = RREG8(MGAREG_Status + 2); 1103cdc0e8dSChristopher Harvey } while ((status & 0x01) && time_before(jiffies, timeout)); 111414c4531SDave Airlie } 112414c4531SDave Airlie 113e20dfd27SThomas Zimmermann /* 114e20dfd27SThomas Zimmermann * PLL setup 115e20dfd27SThomas Zimmermann */ 116e20dfd27SThomas Zimmermann 117e20dfd27SThomas Zimmermann static int mgag200_g200_set_plls(struct mga_device *mdev, long clock) 118e20dfd27SThomas Zimmermann { 119e20dfd27SThomas Zimmermann struct drm_device *dev = &mdev->base; 120e20dfd27SThomas Zimmermann const int post_div_max = 7; 121e20dfd27SThomas Zimmermann const int in_div_min = 1; 122e20dfd27SThomas Zimmermann const int in_div_max = 6; 123e20dfd27SThomas Zimmermann const int feed_div_min = 7; 124e20dfd27SThomas Zimmermann const int feed_div_max = 127; 125e20dfd27SThomas Zimmermann u8 testm, testn; 126e20dfd27SThomas Zimmermann u8 n = 0, m = 0, p, s; 127e20dfd27SThomas Zimmermann long f_vco; 128e20dfd27SThomas Zimmermann long computed; 129e20dfd27SThomas Zimmermann long delta, tmp_delta; 130e20dfd27SThomas Zimmermann long ref_clk = mdev->model.g200.ref_clk; 131e20dfd27SThomas Zimmermann long p_clk_min = mdev->model.g200.pclk_min; 132e20dfd27SThomas Zimmermann long p_clk_max = mdev->model.g200.pclk_max; 133e20dfd27SThomas Zimmermann 134e20dfd27SThomas Zimmermann if (clock > p_clk_max) { 135e20dfd27SThomas Zimmermann drm_err(dev, "Pixel Clock %ld too high\n", clock); 136e20dfd27SThomas Zimmermann return 1; 137e20dfd27SThomas Zimmermann } 138e20dfd27SThomas Zimmermann 139e20dfd27SThomas Zimmermann if (clock < p_clk_min >> 3) 140e20dfd27SThomas Zimmermann clock = p_clk_min >> 3; 141e20dfd27SThomas Zimmermann 142e20dfd27SThomas Zimmermann f_vco = clock; 143e20dfd27SThomas Zimmermann for (p = 0; 144e20dfd27SThomas Zimmermann p <= post_div_max && f_vco < p_clk_min; 145e20dfd27SThomas Zimmermann p = (p << 1) + 1, f_vco <<= 1) 146e20dfd27SThomas Zimmermann ; 147e20dfd27SThomas Zimmermann 148e20dfd27SThomas Zimmermann delta = clock; 149e20dfd27SThomas Zimmermann 150e20dfd27SThomas Zimmermann for (testm = in_div_min; testm <= in_div_max; testm++) { 151e20dfd27SThomas Zimmermann for (testn = feed_div_min; testn <= feed_div_max; testn++) { 152e20dfd27SThomas Zimmermann computed = ref_clk * (testn + 1) / (testm + 1); 153e20dfd27SThomas Zimmermann if (computed < f_vco) 154e20dfd27SThomas Zimmermann tmp_delta = f_vco - computed; 155e20dfd27SThomas Zimmermann else 156e20dfd27SThomas Zimmermann tmp_delta = computed - f_vco; 157e20dfd27SThomas Zimmermann if (tmp_delta < delta) { 158e20dfd27SThomas Zimmermann delta = tmp_delta; 159e20dfd27SThomas Zimmermann m = testm; 160e20dfd27SThomas Zimmermann n = testn; 161e20dfd27SThomas Zimmermann } 162e20dfd27SThomas Zimmermann } 163e20dfd27SThomas Zimmermann } 164e20dfd27SThomas Zimmermann f_vco = ref_clk * (n + 1) / (m + 1); 165e20dfd27SThomas Zimmermann if (f_vco < 100000) 166e20dfd27SThomas Zimmermann s = 0; 167e20dfd27SThomas Zimmermann else if (f_vco < 140000) 168e20dfd27SThomas Zimmermann s = 1; 169e20dfd27SThomas Zimmermann else if (f_vco < 180000) 170e20dfd27SThomas Zimmermann s = 2; 171e20dfd27SThomas Zimmermann else 172e20dfd27SThomas Zimmermann s = 3; 173e20dfd27SThomas Zimmermann 174e20dfd27SThomas Zimmermann drm_dbg_kms(dev, "clock: %ld vco: %ld m: %d n: %d p: %d s: %d\n", 175e20dfd27SThomas Zimmermann clock, f_vco, m, n, p, s); 176e20dfd27SThomas Zimmermann 177e20dfd27SThomas Zimmermann WREG_DAC(MGA1064_PIX_PLLC_M, m); 178e20dfd27SThomas Zimmermann WREG_DAC(MGA1064_PIX_PLLC_N, n); 179e20dfd27SThomas Zimmermann WREG_DAC(MGA1064_PIX_PLLC_P, (p | (s << 3))); 180e20dfd27SThomas Zimmermann 181e20dfd27SThomas Zimmermann return 0; 182e20dfd27SThomas Zimmermann } 183e20dfd27SThomas Zimmermann 184e829d7efSMathieu Larouche #define P_ARRAY_SIZE 9 185e829d7efSMathieu Larouche 186414c4531SDave Airlie static int mga_g200se_set_plls(struct mga_device *mdev, long clock) 187414c4531SDave Airlie { 188fb18825fSThomas Zimmermann u32 unique_rev_id = mdev->model.g200se.unique_rev_id; 189414c4531SDave Airlie unsigned int vcomax, vcomin, pllreffreq; 190414c4531SDave Airlie unsigned int delta, tmpdelta, permitteddelta; 191414c4531SDave Airlie unsigned int testp, testm, testn; 192414c4531SDave Airlie unsigned int p, m, n; 193414c4531SDave Airlie unsigned int computed; 194e829d7efSMathieu Larouche unsigned int pvalues_e4[P_ARRAY_SIZE] = {16, 14, 12, 10, 8, 6, 4, 2, 1}; 195e829d7efSMathieu Larouche unsigned int fvv; 196e829d7efSMathieu Larouche unsigned int i; 197e829d7efSMathieu Larouche 198fb18825fSThomas Zimmermann if (unique_rev_id <= 0x03) { 199414c4531SDave Airlie 200414c4531SDave Airlie m = n = p = 0; 201414c4531SDave Airlie vcomax = 320000; 202414c4531SDave Airlie vcomin = 160000; 203414c4531SDave Airlie pllreffreq = 25000; 204414c4531SDave Airlie 205414c4531SDave Airlie delta = 0xffffffff; 206414c4531SDave Airlie permitteddelta = clock * 5 / 1000; 207414c4531SDave Airlie 208414c4531SDave Airlie for (testp = 8; testp > 0; testp /= 2) { 209414c4531SDave Airlie if (clock * testp > vcomax) 210414c4531SDave Airlie continue; 211414c4531SDave Airlie if (clock * testp < vcomin) 212414c4531SDave Airlie continue; 213414c4531SDave Airlie 214414c4531SDave Airlie for (testn = 17; testn < 256; testn++) { 215414c4531SDave Airlie for (testm = 1; testm < 32; testm++) { 216414c4531SDave Airlie computed = (pllreffreq * testn) / 217414c4531SDave Airlie (testm * testp); 218414c4531SDave Airlie if (computed > clock) 219414c4531SDave Airlie tmpdelta = computed - clock; 220414c4531SDave Airlie else 221414c4531SDave Airlie tmpdelta = clock - computed; 222414c4531SDave Airlie if (tmpdelta < delta) { 223414c4531SDave Airlie delta = tmpdelta; 224414c4531SDave Airlie m = testm - 1; 225414c4531SDave Airlie n = testn - 1; 226414c4531SDave Airlie p = testp - 1; 227414c4531SDave Airlie } 228414c4531SDave Airlie } 229414c4531SDave Airlie } 230414c4531SDave Airlie } 231e829d7efSMathieu Larouche } else { 232e829d7efSMathieu Larouche 233e829d7efSMathieu Larouche 234e829d7efSMathieu Larouche m = n = p = 0; 235e829d7efSMathieu Larouche vcomax = 1600000; 236e829d7efSMathieu Larouche vcomin = 800000; 237e829d7efSMathieu Larouche pllreffreq = 25000; 238e829d7efSMathieu Larouche 239e829d7efSMathieu Larouche if (clock < 25000) 240e829d7efSMathieu Larouche clock = 25000; 241e829d7efSMathieu Larouche 242e829d7efSMathieu Larouche clock = clock * 2; 243e829d7efSMathieu Larouche 244e829d7efSMathieu Larouche delta = 0xFFFFFFFF; 245e829d7efSMathieu Larouche /* Permited delta is 0.5% as VESA Specification */ 246e829d7efSMathieu Larouche permitteddelta = clock * 5 / 1000; 247e829d7efSMathieu Larouche 248e829d7efSMathieu Larouche for (i = 0 ; i < P_ARRAY_SIZE ; i++) { 249e829d7efSMathieu Larouche testp = pvalues_e4[i]; 250e829d7efSMathieu Larouche 251e829d7efSMathieu Larouche if ((clock * testp) > vcomax) 252e829d7efSMathieu Larouche continue; 253e829d7efSMathieu Larouche if ((clock * testp) < vcomin) 254e829d7efSMathieu Larouche continue; 255e829d7efSMathieu Larouche 256e829d7efSMathieu Larouche for (testn = 50; testn <= 256; testn++) { 257e829d7efSMathieu Larouche for (testm = 1; testm <= 32; testm++) { 258e829d7efSMathieu Larouche computed = (pllreffreq * testn) / 259e829d7efSMathieu Larouche (testm * testp); 260e829d7efSMathieu Larouche if (computed > clock) 261e829d7efSMathieu Larouche tmpdelta = computed - clock; 262e829d7efSMathieu Larouche else 263e829d7efSMathieu Larouche tmpdelta = clock - computed; 264e829d7efSMathieu Larouche 265e829d7efSMathieu Larouche if (tmpdelta < delta) { 266e829d7efSMathieu Larouche delta = tmpdelta; 267e829d7efSMathieu Larouche m = testm - 1; 268e829d7efSMathieu Larouche n = testn - 1; 269e829d7efSMathieu Larouche p = testp - 1; 270e829d7efSMathieu Larouche } 271e829d7efSMathieu Larouche } 272e829d7efSMathieu Larouche } 273e829d7efSMathieu Larouche } 274e829d7efSMathieu Larouche 275d3922b69SMathieu Larouche fvv = pllreffreq * (n + 1) / (m + 1); 276e829d7efSMathieu Larouche fvv = (fvv - 800000) / 50000; 277e829d7efSMathieu Larouche 278e829d7efSMathieu Larouche if (fvv > 15) 279e829d7efSMathieu Larouche fvv = 15; 280e829d7efSMathieu Larouche 281e829d7efSMathieu Larouche p |= (fvv << 4); 282e829d7efSMathieu Larouche m |= 0x80; 283e829d7efSMathieu Larouche 284e829d7efSMathieu Larouche clock = clock / 2; 285e829d7efSMathieu Larouche } 286414c4531SDave Airlie 287414c4531SDave Airlie if (delta > permitteddelta) { 2888dfe162aSJoe Perches pr_warn("PLL delta too large\n"); 289414c4531SDave Airlie return 1; 290414c4531SDave Airlie } 291414c4531SDave Airlie 292414c4531SDave Airlie WREG_DAC(MGA1064_PIX_PLLC_M, m); 293414c4531SDave Airlie WREG_DAC(MGA1064_PIX_PLLC_N, n); 294414c4531SDave Airlie WREG_DAC(MGA1064_PIX_PLLC_P, p); 295d3922b69SMathieu Larouche 296fb18825fSThomas Zimmermann if (unique_rev_id >= 0x04) { 297d3922b69SMathieu Larouche WREG_DAC(0x1a, 0x09); 298d3922b69SMathieu Larouche msleep(20); 299d3922b69SMathieu Larouche WREG_DAC(0x1a, 0x01); 300d3922b69SMathieu Larouche 301d3922b69SMathieu Larouche } 302d3922b69SMathieu Larouche 303414c4531SDave Airlie return 0; 304414c4531SDave Airlie } 305414c4531SDave Airlie 306414c4531SDave Airlie static int mga_g200wb_set_plls(struct mga_device *mdev, long clock) 307414c4531SDave Airlie { 308414c4531SDave Airlie unsigned int vcomax, vcomin, pllreffreq; 309546aee51SSudip Mukherjee unsigned int delta, tmpdelta; 3106d857c18SMathieu Larouche unsigned int testp, testm, testn, testp2; 311414c4531SDave Airlie unsigned int p, m, n; 312414c4531SDave Airlie unsigned int computed; 313414c4531SDave Airlie int i, j, tmpcount, vcount; 314414c4531SDave Airlie bool pll_locked = false; 315414c4531SDave Airlie u8 tmp; 316414c4531SDave Airlie 317414c4531SDave Airlie m = n = p = 0; 3186d857c18SMathieu Larouche 3196d857c18SMathieu Larouche delta = 0xffffffff; 3206d857c18SMathieu Larouche 3216d857c18SMathieu Larouche if (mdev->type == G200_EW3) { 3226d857c18SMathieu Larouche 3236d857c18SMathieu Larouche vcomax = 800000; 3246d857c18SMathieu Larouche vcomin = 400000; 3256d857c18SMathieu Larouche pllreffreq = 25000; 3266d857c18SMathieu Larouche 3276d857c18SMathieu Larouche for (testp = 1; testp < 8; testp++) { 3286d857c18SMathieu Larouche for (testp2 = 1; testp2 < 8; testp2++) { 3296d857c18SMathieu Larouche if (testp < testp2) 3306d857c18SMathieu Larouche continue; 3316d857c18SMathieu Larouche if ((clock * testp * testp2) > vcomax) 3326d857c18SMathieu Larouche continue; 3336d857c18SMathieu Larouche if ((clock * testp * testp2) < vcomin) 3346d857c18SMathieu Larouche continue; 3356d857c18SMathieu Larouche for (testm = 1; testm < 26; testm++) { 3366d857c18SMathieu Larouche for (testn = 32; testn < 2048 ; testn++) { 3376d857c18SMathieu Larouche computed = (pllreffreq * testn) / 3386d857c18SMathieu Larouche (testm * testp * testp2); 3396d857c18SMathieu Larouche if (computed > clock) 3406d857c18SMathieu Larouche tmpdelta = computed - clock; 3416d857c18SMathieu Larouche else 3426d857c18SMathieu Larouche tmpdelta = clock - computed; 3436d857c18SMathieu Larouche if (tmpdelta < delta) { 3446d857c18SMathieu Larouche delta = tmpdelta; 3456d857c18SMathieu Larouche m = ((testn & 0x100) >> 1) | 3466d857c18SMathieu Larouche (testm); 3476d857c18SMathieu Larouche n = (testn & 0xFF); 3486d857c18SMathieu Larouche p = ((testn & 0x600) >> 3) | 3496d857c18SMathieu Larouche (testp2 << 3) | 3506d857c18SMathieu Larouche (testp); 3516d857c18SMathieu Larouche } 3526d857c18SMathieu Larouche } 3536d857c18SMathieu Larouche } 3546d857c18SMathieu Larouche } 3556d857c18SMathieu Larouche } 3566d857c18SMathieu Larouche } else { 3576d857c18SMathieu Larouche 358414c4531SDave Airlie vcomax = 550000; 359414c4531SDave Airlie vcomin = 150000; 360414c4531SDave Airlie pllreffreq = 48000; 361414c4531SDave Airlie 362414c4531SDave Airlie for (testp = 1; testp < 9; testp++) { 363414c4531SDave Airlie if (clock * testp > vcomax) 364414c4531SDave Airlie continue; 365414c4531SDave Airlie if (clock * testp < vcomin) 366414c4531SDave Airlie continue; 367414c4531SDave Airlie 368414c4531SDave Airlie for (testm = 1; testm < 17; testm++) { 369414c4531SDave Airlie for (testn = 1; testn < 151; testn++) { 370414c4531SDave Airlie computed = (pllreffreq * testn) / 371414c4531SDave Airlie (testm * testp); 372414c4531SDave Airlie if (computed > clock) 373414c4531SDave Airlie tmpdelta = computed - clock; 374414c4531SDave Airlie else 375414c4531SDave Airlie tmpdelta = clock - computed; 376414c4531SDave Airlie if (tmpdelta < delta) { 377414c4531SDave Airlie delta = tmpdelta; 378414c4531SDave Airlie n = testn - 1; 3796d857c18SMathieu Larouche m = (testm - 1) | 3806d857c18SMathieu Larouche ((n >> 1) & 0x80); 381414c4531SDave Airlie p = testp - 1; 382414c4531SDave Airlie } 383414c4531SDave Airlie } 384414c4531SDave Airlie } 385414c4531SDave Airlie } 3866d857c18SMathieu Larouche } 387414c4531SDave Airlie 388414c4531SDave Airlie for (i = 0; i <= 32 && pll_locked == false; i++) { 389414c4531SDave Airlie if (i > 0) { 390414c4531SDave Airlie WREG8(MGAREG_CRTC_INDEX, 0x1e); 391414c4531SDave Airlie tmp = RREG8(MGAREG_CRTC_DATA); 392414c4531SDave Airlie if (tmp < 0xff) 393414c4531SDave Airlie WREG8(MGAREG_CRTC_DATA, tmp+1); 394414c4531SDave Airlie } 395414c4531SDave Airlie 396414c4531SDave Airlie /* set pixclkdis to 1 */ 397414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 398414c4531SDave Airlie tmp = RREG8(DAC_DATA); 399414c4531SDave Airlie tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS; 400fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 401414c4531SDave Airlie 402414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_REMHEADCTL); 403414c4531SDave Airlie tmp = RREG8(DAC_DATA); 404414c4531SDave Airlie tmp |= MGA1064_REMHEADCTL_CLKDIS; 405fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 406414c4531SDave Airlie 407414c4531SDave Airlie /* select PLL Set C */ 408414c4531SDave Airlie tmp = RREG8(MGAREG_MEM_MISC_READ); 409414c4531SDave Airlie tmp |= 0x3 << 2; 410414c4531SDave Airlie WREG8(MGAREG_MEM_MISC_WRITE, tmp); 411414c4531SDave Airlie 412414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 413414c4531SDave Airlie tmp = RREG8(DAC_DATA); 414414c4531SDave Airlie tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN | 0x80; 415fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 416414c4531SDave Airlie 417414c4531SDave Airlie udelay(500); 418414c4531SDave Airlie 419414c4531SDave Airlie /* reset the PLL */ 420414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_VREF_CTL); 421414c4531SDave Airlie tmp = RREG8(DAC_DATA); 422414c4531SDave Airlie tmp &= ~0x04; 423fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 424414c4531SDave Airlie 425414c4531SDave Airlie udelay(50); 426414c4531SDave Airlie 427414c4531SDave Airlie /* program pixel pll register */ 428414c4531SDave Airlie WREG_DAC(MGA1064_WB_PIX_PLLC_N, n); 429414c4531SDave Airlie WREG_DAC(MGA1064_WB_PIX_PLLC_M, m); 430414c4531SDave Airlie WREG_DAC(MGA1064_WB_PIX_PLLC_P, p); 431414c4531SDave Airlie 432414c4531SDave Airlie udelay(50); 433414c4531SDave Airlie 434414c4531SDave Airlie /* turn pll on */ 435414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_VREF_CTL); 436414c4531SDave Airlie tmp = RREG8(DAC_DATA); 437414c4531SDave Airlie tmp |= 0x04; 438414c4531SDave Airlie WREG_DAC(MGA1064_VREF_CTL, tmp); 439414c4531SDave Airlie 440414c4531SDave Airlie udelay(500); 441414c4531SDave Airlie 442414c4531SDave Airlie /* select the pixel pll */ 443414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 444414c4531SDave Airlie tmp = RREG8(DAC_DATA); 445414c4531SDave Airlie tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK; 446414c4531SDave Airlie tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL; 447fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 448414c4531SDave Airlie 449414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_REMHEADCTL); 450414c4531SDave Airlie tmp = RREG8(DAC_DATA); 451414c4531SDave Airlie tmp &= ~MGA1064_REMHEADCTL_CLKSL_MSK; 452414c4531SDave Airlie tmp |= MGA1064_REMHEADCTL_CLKSL_PLL; 453fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 454414c4531SDave Airlie 455414c4531SDave Airlie /* reset dotclock rate bit */ 456414c4531SDave Airlie WREG8(MGAREG_SEQ_INDEX, 1); 457414c4531SDave Airlie tmp = RREG8(MGAREG_SEQ_DATA); 458414c4531SDave Airlie tmp &= ~0x8; 459414c4531SDave Airlie WREG8(MGAREG_SEQ_DATA, tmp); 460414c4531SDave Airlie 461414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 462414c4531SDave Airlie tmp = RREG8(DAC_DATA); 463414c4531SDave Airlie tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS; 464fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 465414c4531SDave Airlie 466414c4531SDave Airlie vcount = RREG8(MGAREG_VCOUNT); 467414c4531SDave Airlie 468414c4531SDave Airlie for (j = 0; j < 30 && pll_locked == false; j++) { 469414c4531SDave Airlie tmpcount = RREG8(MGAREG_VCOUNT); 470414c4531SDave Airlie if (tmpcount < vcount) 471414c4531SDave Airlie vcount = 0; 472414c4531SDave Airlie if ((tmpcount - vcount) > 2) 473414c4531SDave Airlie pll_locked = true; 474414c4531SDave Airlie else 475414c4531SDave Airlie udelay(5); 476414c4531SDave Airlie } 477414c4531SDave Airlie } 478414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_REMHEADCTL); 479414c4531SDave Airlie tmp = RREG8(DAC_DATA); 480414c4531SDave Airlie tmp &= ~MGA1064_REMHEADCTL_CLKDIS; 481414c4531SDave Airlie WREG_DAC(MGA1064_REMHEADCTL, tmp); 482414c4531SDave Airlie return 0; 483414c4531SDave Airlie } 484414c4531SDave Airlie 485414c4531SDave Airlie static int mga_g200ev_set_plls(struct mga_device *mdev, long clock) 486414c4531SDave Airlie { 487414c4531SDave Airlie unsigned int vcomax, vcomin, pllreffreq; 488546aee51SSudip Mukherjee unsigned int delta, tmpdelta; 489414c4531SDave Airlie unsigned int testp, testm, testn; 490414c4531SDave Airlie unsigned int p, m, n; 491414c4531SDave Airlie unsigned int computed; 492414c4531SDave Airlie u8 tmp; 493414c4531SDave Airlie 494414c4531SDave Airlie m = n = p = 0; 495414c4531SDave Airlie vcomax = 550000; 496414c4531SDave Airlie vcomin = 150000; 497414c4531SDave Airlie pllreffreq = 50000; 498414c4531SDave Airlie 499414c4531SDave Airlie delta = 0xffffffff; 500414c4531SDave Airlie 501414c4531SDave Airlie for (testp = 16; testp > 0; testp--) { 502414c4531SDave Airlie if (clock * testp > vcomax) 503414c4531SDave Airlie continue; 504414c4531SDave Airlie if (clock * testp < vcomin) 505414c4531SDave Airlie continue; 506414c4531SDave Airlie 507414c4531SDave Airlie for (testn = 1; testn < 257; testn++) { 508414c4531SDave Airlie for (testm = 1; testm < 17; testm++) { 509414c4531SDave Airlie computed = (pllreffreq * testn) / 510414c4531SDave Airlie (testm * testp); 511414c4531SDave Airlie if (computed > clock) 512414c4531SDave Airlie tmpdelta = computed - clock; 513414c4531SDave Airlie else 514414c4531SDave Airlie tmpdelta = clock - computed; 515414c4531SDave Airlie if (tmpdelta < delta) { 516414c4531SDave Airlie delta = tmpdelta; 517414c4531SDave Airlie n = testn - 1; 518414c4531SDave Airlie m = testm - 1; 519414c4531SDave Airlie p = testp - 1; 520414c4531SDave Airlie } 521414c4531SDave Airlie } 522414c4531SDave Airlie } 523414c4531SDave Airlie } 524414c4531SDave Airlie 525414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 526414c4531SDave Airlie tmp = RREG8(DAC_DATA); 527414c4531SDave Airlie tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS; 528fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 529414c4531SDave Airlie 530414c4531SDave Airlie tmp = RREG8(MGAREG_MEM_MISC_READ); 531414c4531SDave Airlie tmp |= 0x3 << 2; 532414c4531SDave Airlie WREG8(MGAREG_MEM_MISC_WRITE, tmp); 533414c4531SDave Airlie 534414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_PLL_STAT); 535414c4531SDave Airlie tmp = RREG8(DAC_DATA); 536fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp & ~0x40); 537414c4531SDave Airlie 538414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 539414c4531SDave Airlie tmp = RREG8(DAC_DATA); 540414c4531SDave Airlie tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; 541fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 542414c4531SDave Airlie 543414c4531SDave Airlie WREG_DAC(MGA1064_EV_PIX_PLLC_M, m); 544414c4531SDave Airlie WREG_DAC(MGA1064_EV_PIX_PLLC_N, n); 545414c4531SDave Airlie WREG_DAC(MGA1064_EV_PIX_PLLC_P, p); 546414c4531SDave Airlie 547414c4531SDave Airlie udelay(50); 548414c4531SDave Airlie 549414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 550414c4531SDave Airlie tmp = RREG8(DAC_DATA); 551414c4531SDave Airlie tmp &= ~MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; 552fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 553414c4531SDave Airlie 554414c4531SDave Airlie udelay(500); 555414c4531SDave Airlie 556414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 557414c4531SDave Airlie tmp = RREG8(DAC_DATA); 558414c4531SDave Airlie tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK; 559414c4531SDave Airlie tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL; 560fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 561414c4531SDave Airlie 562414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_PLL_STAT); 563414c4531SDave Airlie tmp = RREG8(DAC_DATA); 564fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp | 0x40); 565414c4531SDave Airlie 566414c4531SDave Airlie tmp = RREG8(MGAREG_MEM_MISC_READ); 567414c4531SDave Airlie tmp |= (0x3 << 2); 568414c4531SDave Airlie WREG8(MGAREG_MEM_MISC_WRITE, tmp); 569414c4531SDave Airlie 570414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 571414c4531SDave Airlie tmp = RREG8(DAC_DATA); 572414c4531SDave Airlie tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS; 573fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 574414c4531SDave Airlie 575414c4531SDave Airlie return 0; 576414c4531SDave Airlie } 577414c4531SDave Airlie 578414c4531SDave Airlie static int mga_g200eh_set_plls(struct mga_device *mdev, long clock) 579414c4531SDave Airlie { 580414c4531SDave Airlie unsigned int vcomax, vcomin, pllreffreq; 581546aee51SSudip Mukherjee unsigned int delta, tmpdelta; 582414c4531SDave Airlie unsigned int testp, testm, testn; 583414c4531SDave Airlie unsigned int p, m, n; 584414c4531SDave Airlie unsigned int computed; 585414c4531SDave Airlie int i, j, tmpcount, vcount; 586414c4531SDave Airlie u8 tmp; 587414c4531SDave Airlie bool pll_locked = false; 588414c4531SDave Airlie 589414c4531SDave Airlie m = n = p = 0; 590f0493e65SMathieu Larouche 591f0493e65SMathieu Larouche if (mdev->type == G200_EH3) { 592f0493e65SMathieu Larouche vcomax = 3000000; 593f0493e65SMathieu Larouche vcomin = 1500000; 594f0493e65SMathieu Larouche pllreffreq = 25000; 595f0493e65SMathieu Larouche 596f0493e65SMathieu Larouche delta = 0xffffffff; 597f0493e65SMathieu Larouche 598f0493e65SMathieu Larouche testp = 0; 599f0493e65SMathieu Larouche 600f0493e65SMathieu Larouche for (testm = 150; testm >= 6; testm--) { 601f0493e65SMathieu Larouche if (clock * testm > vcomax) 602f0493e65SMathieu Larouche continue; 603f0493e65SMathieu Larouche if (clock * testm < vcomin) 604f0493e65SMathieu Larouche continue; 605f0493e65SMathieu Larouche for (testn = 120; testn >= 60; testn--) { 606f0493e65SMathieu Larouche computed = (pllreffreq * testn) / testm; 607f0493e65SMathieu Larouche if (computed > clock) 608f0493e65SMathieu Larouche tmpdelta = computed - clock; 609f0493e65SMathieu Larouche else 610f0493e65SMathieu Larouche tmpdelta = clock - computed; 611f0493e65SMathieu Larouche if (tmpdelta < delta) { 612f0493e65SMathieu Larouche delta = tmpdelta; 613f0493e65SMathieu Larouche n = testn; 614f0493e65SMathieu Larouche m = testm; 615f0493e65SMathieu Larouche p = testp; 616f0493e65SMathieu Larouche } 617f0493e65SMathieu Larouche if (delta == 0) 618f0493e65SMathieu Larouche break; 619f0493e65SMathieu Larouche } 620f0493e65SMathieu Larouche if (delta == 0) 621f0493e65SMathieu Larouche break; 622f0493e65SMathieu Larouche } 623f0493e65SMathieu Larouche } else { 624f0493e65SMathieu Larouche 625414c4531SDave Airlie vcomax = 800000; 626414c4531SDave Airlie vcomin = 400000; 627260b3f12SJulia Lemire pllreffreq = 33333; 628414c4531SDave Airlie 629414c4531SDave Airlie delta = 0xffffffff; 630414c4531SDave Airlie 631260b3f12SJulia Lemire for (testp = 16; testp > 0; testp >>= 1) { 632414c4531SDave Airlie if (clock * testp > vcomax) 633414c4531SDave Airlie continue; 634414c4531SDave Airlie if (clock * testp < vcomin) 635414c4531SDave Airlie continue; 636414c4531SDave Airlie 637414c4531SDave Airlie for (testm = 1; testm < 33; testm++) { 638260b3f12SJulia Lemire for (testn = 17; testn < 257; testn++) { 639414c4531SDave Airlie computed = (pllreffreq * testn) / 640414c4531SDave Airlie (testm * testp); 641414c4531SDave Airlie if (computed > clock) 642414c4531SDave Airlie tmpdelta = computed - clock; 643414c4531SDave Airlie else 644414c4531SDave Airlie tmpdelta = clock - computed; 645414c4531SDave Airlie if (tmpdelta < delta) { 646414c4531SDave Airlie delta = tmpdelta; 647414c4531SDave Airlie n = testn - 1; 648260b3f12SJulia Lemire m = (testm - 1); 649414c4531SDave Airlie p = testp - 1; 650414c4531SDave Airlie } 651414c4531SDave Airlie if ((clock * testp) >= 600000) 652260b3f12SJulia Lemire p |= 0x80; 653414c4531SDave Airlie } 654414c4531SDave Airlie } 655414c4531SDave Airlie } 656f0493e65SMathieu Larouche } 657414c4531SDave Airlie for (i = 0; i <= 32 && pll_locked == false; i++) { 658414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 659414c4531SDave Airlie tmp = RREG8(DAC_DATA); 660414c4531SDave Airlie tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS; 661fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 662414c4531SDave Airlie 663414c4531SDave Airlie tmp = RREG8(MGAREG_MEM_MISC_READ); 664414c4531SDave Airlie tmp |= 0x3 << 2; 665414c4531SDave Airlie WREG8(MGAREG_MEM_MISC_WRITE, tmp); 666414c4531SDave Airlie 667414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 668414c4531SDave Airlie tmp = RREG8(DAC_DATA); 669414c4531SDave Airlie tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; 670fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 671414c4531SDave Airlie 672414c4531SDave Airlie udelay(500); 673414c4531SDave Airlie 674414c4531SDave Airlie WREG_DAC(MGA1064_EH_PIX_PLLC_M, m); 675414c4531SDave Airlie WREG_DAC(MGA1064_EH_PIX_PLLC_N, n); 676414c4531SDave Airlie WREG_DAC(MGA1064_EH_PIX_PLLC_P, p); 677414c4531SDave Airlie 678414c4531SDave Airlie udelay(500); 679414c4531SDave Airlie 680414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 681414c4531SDave Airlie tmp = RREG8(DAC_DATA); 682414c4531SDave Airlie tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK; 683414c4531SDave Airlie tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL; 684fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 685414c4531SDave Airlie 686414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 687414c4531SDave Airlie tmp = RREG8(DAC_DATA); 688414c4531SDave Airlie tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS; 689414c4531SDave Airlie tmp &= ~MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; 690fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 691414c4531SDave Airlie 692414c4531SDave Airlie vcount = RREG8(MGAREG_VCOUNT); 693414c4531SDave Airlie 694414c4531SDave Airlie for (j = 0; j < 30 && pll_locked == false; j++) { 695414c4531SDave Airlie tmpcount = RREG8(MGAREG_VCOUNT); 696414c4531SDave Airlie if (tmpcount < vcount) 697414c4531SDave Airlie vcount = 0; 698414c4531SDave Airlie if ((tmpcount - vcount) > 2) 699414c4531SDave Airlie pll_locked = true; 700414c4531SDave Airlie else 701414c4531SDave Airlie udelay(5); 702414c4531SDave Airlie } 703414c4531SDave Airlie } 704414c4531SDave Airlie 705414c4531SDave Airlie return 0; 706414c4531SDave Airlie } 707414c4531SDave Airlie 708414c4531SDave Airlie static int mga_g200er_set_plls(struct mga_device *mdev, long clock) 709414c4531SDave Airlie { 7100c9d59c3SColin Ian King static const unsigned int m_div_val[] = { 1, 2, 4, 8 }; 711414c4531SDave Airlie unsigned int vcomax, vcomin, pllreffreq; 712414c4531SDave Airlie unsigned int delta, tmpdelta; 7139830605dSDave Airlie int testr, testn, testm, testo; 714414c4531SDave Airlie unsigned int p, m, n; 7159830605dSDave Airlie unsigned int computed, vco; 716414c4531SDave Airlie int tmp; 717414c4531SDave Airlie 718414c4531SDave Airlie m = n = p = 0; 719414c4531SDave Airlie vcomax = 1488000; 720414c4531SDave Airlie vcomin = 1056000; 721414c4531SDave Airlie pllreffreq = 48000; 722414c4531SDave Airlie 723414c4531SDave Airlie delta = 0xffffffff; 724414c4531SDave Airlie 725414c4531SDave Airlie for (testr = 0; testr < 4; testr++) { 726414c4531SDave Airlie if (delta == 0) 727414c4531SDave Airlie break; 728414c4531SDave Airlie for (testn = 5; testn < 129; testn++) { 729414c4531SDave Airlie if (delta == 0) 730414c4531SDave Airlie break; 731414c4531SDave Airlie for (testm = 3; testm >= 0; testm--) { 732414c4531SDave Airlie if (delta == 0) 733414c4531SDave Airlie break; 734414c4531SDave Airlie for (testo = 5; testo < 33; testo++) { 7359830605dSDave Airlie vco = pllreffreq * (testn + 1) / 736414c4531SDave Airlie (testr + 1); 7379830605dSDave Airlie if (vco < vcomin) 738414c4531SDave Airlie continue; 7399830605dSDave Airlie if (vco > vcomax) 740414c4531SDave Airlie continue; 7419830605dSDave Airlie computed = vco / (m_div_val[testm] * (testo + 1)); 742414c4531SDave Airlie if (computed > clock) 743414c4531SDave Airlie tmpdelta = computed - clock; 744414c4531SDave Airlie else 745414c4531SDave Airlie tmpdelta = clock - computed; 746414c4531SDave Airlie if (tmpdelta < delta) { 747414c4531SDave Airlie delta = tmpdelta; 748414c4531SDave Airlie m = testm | (testo << 3); 749414c4531SDave Airlie n = testn; 750414c4531SDave Airlie p = testr | (testr << 3); 751414c4531SDave Airlie } 752414c4531SDave Airlie } 753414c4531SDave Airlie } 754414c4531SDave Airlie } 755414c4531SDave Airlie } 756414c4531SDave Airlie 757414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 758414c4531SDave Airlie tmp = RREG8(DAC_DATA); 759414c4531SDave Airlie tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS; 760fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 761414c4531SDave Airlie 762414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_REMHEADCTL); 763414c4531SDave Airlie tmp = RREG8(DAC_DATA); 764414c4531SDave Airlie tmp |= MGA1064_REMHEADCTL_CLKDIS; 765fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 766414c4531SDave Airlie 767414c4531SDave Airlie tmp = RREG8(MGAREG_MEM_MISC_READ); 768414c4531SDave Airlie tmp |= (0x3<<2) | 0xc0; 769414c4531SDave Airlie WREG8(MGAREG_MEM_MISC_WRITE, tmp); 770414c4531SDave Airlie 771414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); 772414c4531SDave Airlie tmp = RREG8(DAC_DATA); 773414c4531SDave Airlie tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS; 774414c4531SDave Airlie tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; 775fb70a669SChristopher Harvey WREG8(DAC_DATA, tmp); 776414c4531SDave Airlie 777414c4531SDave Airlie udelay(500); 778414c4531SDave Airlie 779414c4531SDave Airlie WREG_DAC(MGA1064_ER_PIX_PLLC_N, n); 780414c4531SDave Airlie WREG_DAC(MGA1064_ER_PIX_PLLC_M, m); 781414c4531SDave Airlie WREG_DAC(MGA1064_ER_PIX_PLLC_P, p); 782414c4531SDave Airlie 783414c4531SDave Airlie udelay(50); 784414c4531SDave Airlie 785414c4531SDave Airlie return 0; 786414c4531SDave Airlie } 787414c4531SDave Airlie 788fc42e89fSThomas Zimmermann static int mgag200_crtc_set_plls(struct mga_device *mdev, long clock) 789414c4531SDave Airlie { 790db05f8d3SThomas Zimmermann u8 misc; 791db05f8d3SThomas Zimmermann 792414c4531SDave Airlie switch(mdev->type) { 793e20dfd27SThomas Zimmermann case G200_PCI: 794e20dfd27SThomas Zimmermann case G200_AGP: 795e20dfd27SThomas Zimmermann return mgag200_g200_set_plls(mdev, clock); 796414c4531SDave Airlie case G200_SE_A: 797414c4531SDave Airlie case G200_SE_B: 798414c4531SDave Airlie return mga_g200se_set_plls(mdev, clock); 799414c4531SDave Airlie case G200_WB: 8006d857c18SMathieu Larouche case G200_EW3: 801414c4531SDave Airlie return mga_g200wb_set_plls(mdev, clock); 802414c4531SDave Airlie case G200_EV: 803414c4531SDave Airlie return mga_g200ev_set_plls(mdev, clock); 804414c4531SDave Airlie case G200_EH: 805f0493e65SMathieu Larouche case G200_EH3: 806414c4531SDave Airlie return mga_g200eh_set_plls(mdev, clock); 807414c4531SDave Airlie case G200_ER: 808414c4531SDave Airlie return mga_g200er_set_plls(mdev, clock); 809414c4531SDave Airlie } 810db05f8d3SThomas Zimmermann 811db05f8d3SThomas Zimmermann misc = RREG8(MGA_MISC_IN); 812db05f8d3SThomas Zimmermann misc &= ~MGAREG_MISC_CLK_SEL_MASK; 813db05f8d3SThomas Zimmermann misc |= MGAREG_MISC_CLK_SEL_MGA_MSK; 814db05f8d3SThomas Zimmermann WREG8(MGA_MISC_OUT, misc); 815db05f8d3SThomas Zimmermann 816414c4531SDave Airlie return 0; 817414c4531SDave Airlie } 818414c4531SDave Airlie 819904347fbSThomas Zimmermann static void mgag200_g200wb_hold_bmc(struct mga_device *mdev) 820414c4531SDave Airlie { 821414c4531SDave Airlie u8 tmp; 822414c4531SDave Airlie int iter_max; 823414c4531SDave Airlie 824414c4531SDave Airlie /* 1- The first step is to warn the BMC of an upcoming mode change. 825414c4531SDave Airlie * We are putting the misc<0> to output.*/ 826414c4531SDave Airlie 827414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_GEN_IO_CTL); 828414c4531SDave Airlie tmp = RREG8(DAC_DATA); 829414c4531SDave Airlie tmp |= 0x10; 830414c4531SDave Airlie WREG_DAC(MGA1064_GEN_IO_CTL, tmp); 831414c4531SDave Airlie 832414c4531SDave Airlie /* we are putting a 1 on the misc<0> line */ 833414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_GEN_IO_DATA); 834414c4531SDave Airlie tmp = RREG8(DAC_DATA); 835414c4531SDave Airlie tmp |= 0x10; 836414c4531SDave Airlie WREG_DAC(MGA1064_GEN_IO_DATA, tmp); 837414c4531SDave Airlie 838414c4531SDave Airlie /* 2- Second step to mask and further scan request 839414c4531SDave Airlie * This will be done by asserting the remfreqmsk bit (XSPAREREG<7>) 840414c4531SDave Airlie */ 841414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_SPAREREG); 842414c4531SDave Airlie tmp = RREG8(DAC_DATA); 843414c4531SDave Airlie tmp |= 0x80; 844414c4531SDave Airlie WREG_DAC(MGA1064_SPAREREG, tmp); 845414c4531SDave Airlie 846414c4531SDave Airlie /* 3a- the third step is to verifu if there is an active scan 847414c4531SDave Airlie * We are searching for a 0 on remhsyncsts <XSPAREREG<0>) 848414c4531SDave Airlie */ 849414c4531SDave Airlie iter_max = 300; 850414c4531SDave Airlie while (!(tmp & 0x1) && iter_max) { 851414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_SPAREREG); 852414c4531SDave Airlie tmp = RREG8(DAC_DATA); 853414c4531SDave Airlie udelay(1000); 854414c4531SDave Airlie iter_max--; 855414c4531SDave Airlie } 856414c4531SDave Airlie 857414c4531SDave Airlie /* 3b- this step occurs only if the remove is actually scanning 858414c4531SDave Airlie * we are waiting for the end of the frame which is a 1 on 859414c4531SDave Airlie * remvsyncsts (XSPAREREG<1>) 860414c4531SDave Airlie */ 861414c4531SDave Airlie if (iter_max) { 862414c4531SDave Airlie iter_max = 300; 863414c4531SDave Airlie while ((tmp & 0x2) && iter_max) { 864414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_SPAREREG); 865414c4531SDave Airlie tmp = RREG8(DAC_DATA); 866414c4531SDave Airlie udelay(1000); 867414c4531SDave Airlie iter_max--; 868414c4531SDave Airlie } 869414c4531SDave Airlie } 870414c4531SDave Airlie } 871414c4531SDave Airlie 872904347fbSThomas Zimmermann static void mgag200_g200wb_release_bmc(struct mga_device *mdev) 873414c4531SDave Airlie { 874414c4531SDave Airlie u8 tmp; 875414c4531SDave Airlie 876414c4531SDave Airlie /* 1- The first step is to ensure that the vrsten and hrsten are set */ 877414c4531SDave Airlie WREG8(MGAREG_CRTCEXT_INDEX, 1); 878414c4531SDave Airlie tmp = RREG8(MGAREG_CRTCEXT_DATA); 879414c4531SDave Airlie WREG8(MGAREG_CRTCEXT_DATA, tmp | 0x88); 880414c4531SDave Airlie 881414c4531SDave Airlie /* 2- second step is to assert the rstlvl2 */ 882414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_REMHEADCTL2); 883414c4531SDave Airlie tmp = RREG8(DAC_DATA); 884414c4531SDave Airlie tmp |= 0x8; 885414c4531SDave Airlie WREG8(DAC_DATA, tmp); 886414c4531SDave Airlie 887414c4531SDave Airlie /* wait 10 us */ 888414c4531SDave Airlie udelay(10); 889414c4531SDave Airlie 890414c4531SDave Airlie /* 3- deassert rstlvl2 */ 891414c4531SDave Airlie tmp &= ~0x08; 892414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_REMHEADCTL2); 893414c4531SDave Airlie WREG8(DAC_DATA, tmp); 894414c4531SDave Airlie 895414c4531SDave Airlie /* 4- remove mask of scan request */ 896414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_SPAREREG); 897414c4531SDave Airlie tmp = RREG8(DAC_DATA); 898414c4531SDave Airlie tmp &= ~0x80; 899414c4531SDave Airlie WREG8(DAC_DATA, tmp); 900414c4531SDave Airlie 901414c4531SDave Airlie /* 5- put back a 0 on the misc<0> line */ 902414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_GEN_IO_DATA); 903414c4531SDave Airlie tmp = RREG8(DAC_DATA); 904414c4531SDave Airlie tmp &= ~0x10; 905414c4531SDave Airlie WREG_DAC(MGA1064_GEN_IO_DATA, tmp); 906414c4531SDave Airlie } 907414c4531SDave Airlie 9089f1d0366SChristopher Harvey /* 909d6237687SThomas Zimmermann * This is how the framebuffer base address is stored in g200 cards: 910d6237687SThomas Zimmermann * * Assume @offset is the gpu_addr variable of the framebuffer object 911d6237687SThomas Zimmermann * * Then addr is the number of _pixels_ (not bytes) from the start of 912d6237687SThomas Zimmermann * VRAM to the first pixel we want to display. (divided by 2 for 32bit 913d6237687SThomas Zimmermann * framebuffers) 914d6237687SThomas Zimmermann * * addr is stored in the CRTCEXT0, CRTCC and CRTCD registers 915d6237687SThomas Zimmermann * addr<20> -> CRTCEXT0<6> 916d6237687SThomas Zimmermann * addr<19-16> -> CRTCEXT0<3-0> 917d6237687SThomas Zimmermann * addr<15-8> -> CRTCC<7-0> 918d6237687SThomas Zimmermann * addr<7-0> -> CRTCD<7-0> 919d6237687SThomas Zimmermann * 920d6237687SThomas Zimmermann * CRTCEXT0 has to be programmed last to trigger an update and make the 921d6237687SThomas Zimmermann * new addr variable take effect. 9229f1d0366SChristopher Harvey */ 923d6237687SThomas Zimmermann static void mgag200_set_startadd(struct mga_device *mdev, 924d6237687SThomas Zimmermann unsigned long offset) 925414c4531SDave Airlie { 926832eddf5SThomas Zimmermann struct drm_device *dev = &mdev->base; 927d6237687SThomas Zimmermann u32 startadd; 928d6237687SThomas Zimmermann u8 crtcc, crtcd, crtcext0; 929414c4531SDave Airlie 930d6237687SThomas Zimmermann startadd = offset / 8; 931414c4531SDave Airlie 932d6237687SThomas Zimmermann /* 933d6237687SThomas Zimmermann * Can't store addresses any higher than that, but we also 934d6237687SThomas Zimmermann * don't have more than 16 MiB of memory, so it should be fine. 935d6237687SThomas Zimmermann */ 936d6237687SThomas Zimmermann drm_WARN_ON(dev, startadd > 0x1fffff); 937414c4531SDave Airlie 938d6237687SThomas Zimmermann RREG_ECRT(0x00, crtcext0); 939d6237687SThomas Zimmermann 940d6237687SThomas Zimmermann crtcc = (startadd >> 8) & 0xff; 941d6237687SThomas Zimmermann crtcd = startadd & 0xff; 942d6237687SThomas Zimmermann crtcext0 &= 0xb0; 943d6237687SThomas Zimmermann crtcext0 |= ((startadd >> 14) & BIT(6)) | 944d6237687SThomas Zimmermann ((startadd >> 16) & 0x0f); 945d6237687SThomas Zimmermann 946d6237687SThomas Zimmermann WREG_CRT(0x0c, crtcc); 947d6237687SThomas Zimmermann WREG_CRT(0x0d, crtcd); 948d6237687SThomas Zimmermann WREG_ECRT(0x00, crtcext0); 949414c4531SDave Airlie } 950414c4531SDave Airlie 9514f710d7cSThomas Zimmermann static void mgag200_set_dac_regs(struct mga_device *mdev) 9524f710d7cSThomas Zimmermann { 9534f710d7cSThomas Zimmermann size_t i; 9544f710d7cSThomas Zimmermann u8 dacvalue[] = { 9554f710d7cSThomas Zimmermann /* 0x00: */ 0, 0, 0, 0, 0, 0, 0x00, 0, 9564f710d7cSThomas Zimmermann /* 0x08: */ 0, 0, 0, 0, 0, 0, 0, 0, 9574f710d7cSThomas Zimmermann /* 0x10: */ 0, 0, 0, 0, 0, 0, 0, 0, 9584f710d7cSThomas Zimmermann /* 0x18: */ 0x00, 0, 0xC9, 0xFF, 0xBF, 0x20, 0x1F, 0x20, 9594f710d7cSThomas Zimmermann /* 0x20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 9604f710d7cSThomas Zimmermann /* 0x28: */ 0x00, 0x00, 0x00, 0x00, 0, 0, 0, 0x40, 9614f710d7cSThomas Zimmermann /* 0x30: */ 0x00, 0xB0, 0x00, 0xC2, 0x34, 0x14, 0x02, 0x83, 9624f710d7cSThomas Zimmermann /* 0x38: */ 0x00, 0x93, 0x00, 0x77, 0x00, 0x00, 0x00, 0x3A, 9634f710d7cSThomas Zimmermann /* 0x40: */ 0, 0, 0, 0, 0, 0, 0, 0, 9644f710d7cSThomas Zimmermann /* 0x48: */ 0, 0, 0, 0, 0, 0, 0, 0 9654f710d7cSThomas Zimmermann }; 9664f710d7cSThomas Zimmermann 9674f710d7cSThomas Zimmermann switch (mdev->type) { 968e20dfd27SThomas Zimmermann case G200_PCI: 969e20dfd27SThomas Zimmermann case G200_AGP: 970e20dfd27SThomas Zimmermann dacvalue[MGA1064_SYS_PLL_M] = 0x04; 971e20dfd27SThomas Zimmermann dacvalue[MGA1064_SYS_PLL_N] = 0x2D; 972e20dfd27SThomas Zimmermann dacvalue[MGA1064_SYS_PLL_P] = 0x19; 973e20dfd27SThomas Zimmermann break; 9744f710d7cSThomas Zimmermann case G200_SE_A: 9754f710d7cSThomas Zimmermann case G200_SE_B: 9764f710d7cSThomas Zimmermann dacvalue[MGA1064_VREF_CTL] = 0x03; 9774f710d7cSThomas Zimmermann dacvalue[MGA1064_PIX_CLK_CTL] = MGA1064_PIX_CLK_CTL_SEL_PLL; 9784f710d7cSThomas Zimmermann dacvalue[MGA1064_MISC_CTL] = MGA1064_MISC_CTL_DAC_EN | 9794f710d7cSThomas Zimmermann MGA1064_MISC_CTL_VGA8 | 9804f710d7cSThomas Zimmermann MGA1064_MISC_CTL_DAC_RAM_CS; 9814f710d7cSThomas Zimmermann break; 9824f710d7cSThomas Zimmermann case G200_WB: 9834f710d7cSThomas Zimmermann case G200_EW3: 9844f710d7cSThomas Zimmermann dacvalue[MGA1064_VREF_CTL] = 0x07; 9854f710d7cSThomas Zimmermann break; 9864f710d7cSThomas Zimmermann case G200_EV: 9874f710d7cSThomas Zimmermann dacvalue[MGA1064_PIX_CLK_CTL] = MGA1064_PIX_CLK_CTL_SEL_PLL; 9884f710d7cSThomas Zimmermann dacvalue[MGA1064_MISC_CTL] = MGA1064_MISC_CTL_VGA8 | 9894f710d7cSThomas Zimmermann MGA1064_MISC_CTL_DAC_RAM_CS; 9904f710d7cSThomas Zimmermann break; 9914f710d7cSThomas Zimmermann case G200_EH: 9924f710d7cSThomas Zimmermann case G200_EH3: 9934f710d7cSThomas Zimmermann dacvalue[MGA1064_MISC_CTL] = MGA1064_MISC_CTL_VGA8 | 9944f710d7cSThomas Zimmermann MGA1064_MISC_CTL_DAC_RAM_CS; 9954f710d7cSThomas Zimmermann break; 9964f710d7cSThomas Zimmermann case G200_ER: 9974f710d7cSThomas Zimmermann break; 9984f710d7cSThomas Zimmermann } 9994f710d7cSThomas Zimmermann 10004f710d7cSThomas Zimmermann for (i = 0; i < ARRAY_SIZE(dacvalue); i++) { 10014f710d7cSThomas Zimmermann if ((i <= 0x17) || 10024f710d7cSThomas Zimmermann (i == 0x1b) || 10034f710d7cSThomas Zimmermann (i == 0x1c) || 10044f710d7cSThomas Zimmermann ((i >= 0x1f) && (i <= 0x29)) || 10054f710d7cSThomas Zimmermann ((i >= 0x30) && (i <= 0x37))) 10064f710d7cSThomas Zimmermann continue; 10074f710d7cSThomas Zimmermann if (IS_G200_SE(mdev) && 10084f710d7cSThomas Zimmermann ((i == 0x2c) || (i == 0x2d) || (i == 0x2e))) 10094f710d7cSThomas Zimmermann continue; 10104f710d7cSThomas Zimmermann if ((mdev->type == G200_EV || 10114f710d7cSThomas Zimmermann mdev->type == G200_WB || 10124f710d7cSThomas Zimmermann mdev->type == G200_EH || 10134f710d7cSThomas Zimmermann mdev->type == G200_EW3 || 10144f710d7cSThomas Zimmermann mdev->type == G200_EH3) && 10154f710d7cSThomas Zimmermann (i >= 0x44) && (i <= 0x4e)) 10164f710d7cSThomas Zimmermann continue; 10174f710d7cSThomas Zimmermann 10184f710d7cSThomas Zimmermann WREG_DAC(i, dacvalue[i]); 10194f710d7cSThomas Zimmermann } 10204f710d7cSThomas Zimmermann 10214f710d7cSThomas Zimmermann if (mdev->type == G200_ER) 10224f710d7cSThomas Zimmermann WREG_DAC(0x90, 0); 10234f710d7cSThomas Zimmermann } 10244f710d7cSThomas Zimmermann 10254f710d7cSThomas Zimmermann static void mgag200_init_regs(struct mga_device *mdev) 10264f710d7cSThomas Zimmermann { 10279053cad2SThomas Zimmermann u8 crtc11, misc; 10284f710d7cSThomas Zimmermann 10294f710d7cSThomas Zimmermann mgag200_set_dac_regs(mdev); 10304f710d7cSThomas Zimmermann 10314f710d7cSThomas Zimmermann WREG_SEQ(2, 0x0f); 10324f710d7cSThomas Zimmermann WREG_SEQ(3, 0x00); 10334f710d7cSThomas Zimmermann WREG_SEQ(4, 0x0e); 10344f710d7cSThomas Zimmermann 10354f710d7cSThomas Zimmermann WREG_CRT(10, 0); 10364f710d7cSThomas Zimmermann WREG_CRT(11, 0); 10374f710d7cSThomas Zimmermann WREG_CRT(12, 0); 10384f710d7cSThomas Zimmermann WREG_CRT(13, 0); 10394f710d7cSThomas Zimmermann WREG_CRT(14, 0); 10404f710d7cSThomas Zimmermann WREG_CRT(15, 0); 10414f710d7cSThomas Zimmermann 1042da568d5eSThomas Zimmermann RREG_CRT(0x11, crtc11); 1043da568d5eSThomas Zimmermann crtc11 &= ~(MGAREG_CRTC11_CRTCPROTECT | 1044da568d5eSThomas Zimmermann MGAREG_CRTC11_VINTEN | 1045da568d5eSThomas Zimmermann MGAREG_CRTC11_VINTCLR); 1046da568d5eSThomas Zimmermann WREG_CRT(0x11, crtc11); 1047da568d5eSThomas Zimmermann 10484f710d7cSThomas Zimmermann if (mdev->type == G200_ER) 10494f710d7cSThomas Zimmermann WREG_ECRT(0x24, 0x5); 10504f710d7cSThomas Zimmermann 10514f710d7cSThomas Zimmermann if (mdev->type == G200_EW3) 10524f710d7cSThomas Zimmermann WREG_ECRT(0x34, 0x5); 10534f710d7cSThomas Zimmermann 10544f710d7cSThomas Zimmermann misc = RREG8(MGA_MISC_IN); 1055b9fa77ecSThomas Zimmermann misc |= MGAREG_MISC_IOADSEL; 10564f710d7cSThomas Zimmermann WREG8(MGA_MISC_OUT, misc); 10574f710d7cSThomas Zimmermann } 10584f710d7cSThomas Zimmermann 1059a6edae07SThomas Zimmermann static void mgag200_set_mode_regs(struct mga_device *mdev, 1060a6edae07SThomas Zimmermann const struct drm_display_mode *mode) 1061a6edae07SThomas Zimmermann { 1062a6edae07SThomas Zimmermann unsigned int hdisplay, hsyncstart, hsyncend, htotal; 1063a6edae07SThomas Zimmermann unsigned int vdisplay, vsyncstart, vsyncend, vtotal; 1064db05f8d3SThomas Zimmermann u8 misc, crtcext1, crtcext2, crtcext5; 1065a6edae07SThomas Zimmermann 1066a6edae07SThomas Zimmermann hdisplay = mode->hdisplay / 8 - 1; 1067a6edae07SThomas Zimmermann hsyncstart = mode->hsync_start / 8 - 1; 1068a6edae07SThomas Zimmermann hsyncend = mode->hsync_end / 8 - 1; 1069a6edae07SThomas Zimmermann htotal = mode->htotal / 8 - 1; 1070a6edae07SThomas Zimmermann 1071a6edae07SThomas Zimmermann /* Work around hardware quirk */ 1072a6edae07SThomas Zimmermann if ((htotal & 0x07) == 0x06 || (htotal & 0x07) == 0x04) 1073a6edae07SThomas Zimmermann htotal++; 1074a6edae07SThomas Zimmermann 1075a6edae07SThomas Zimmermann vdisplay = mode->vdisplay - 1; 1076a6edae07SThomas Zimmermann vsyncstart = mode->vsync_start - 1; 1077a6edae07SThomas Zimmermann vsyncend = mode->vsync_end - 1; 1078a6edae07SThomas Zimmermann vtotal = mode->vtotal - 2; 1079a6edae07SThomas Zimmermann 1080db05f8d3SThomas Zimmermann misc = RREG8(MGA_MISC_IN); 1081db05f8d3SThomas Zimmermann 1082a6edae07SThomas Zimmermann if (mode->flags & DRM_MODE_FLAG_NHSYNC) 1083db05f8d3SThomas Zimmermann misc |= MGAREG_MISC_HSYNCPOL; 1084db05f8d3SThomas Zimmermann else 1085db05f8d3SThomas Zimmermann misc &= ~MGAREG_MISC_HSYNCPOL; 1086db05f8d3SThomas Zimmermann 1087a6edae07SThomas Zimmermann if (mode->flags & DRM_MODE_FLAG_NVSYNC) 1088db05f8d3SThomas Zimmermann misc |= MGAREG_MISC_VSYNCPOL; 1089db05f8d3SThomas Zimmermann else 1090db05f8d3SThomas Zimmermann misc &= ~MGAREG_MISC_VSYNCPOL; 1091a6edae07SThomas Zimmermann 1092a6edae07SThomas Zimmermann crtcext1 = (((htotal - 4) & 0x100) >> 8) | 1093a6edae07SThomas Zimmermann ((hdisplay & 0x100) >> 7) | 1094a6edae07SThomas Zimmermann ((hsyncstart & 0x100) >> 6) | 1095a6edae07SThomas Zimmermann (htotal & 0x40); 1096a6edae07SThomas Zimmermann if (mdev->type == G200_WB || mdev->type == G200_EW3) 1097a6edae07SThomas Zimmermann crtcext1 |= BIT(7) | /* vrsten */ 1098a6edae07SThomas Zimmermann BIT(3); /* hrsten */ 1099a6edae07SThomas Zimmermann 1100a6edae07SThomas Zimmermann crtcext2 = ((vtotal & 0xc00) >> 10) | 1101a6edae07SThomas Zimmermann ((vdisplay & 0x400) >> 8) | 1102a6edae07SThomas Zimmermann ((vdisplay & 0xc00) >> 7) | 1103a6edae07SThomas Zimmermann ((vsyncstart & 0xc00) >> 5) | 1104a6edae07SThomas Zimmermann ((vdisplay & 0x400) >> 3); 1105a6edae07SThomas Zimmermann crtcext5 = 0x00; 1106a6edae07SThomas Zimmermann 1107a6edae07SThomas Zimmermann WREG_CRT(0, htotal - 4); 1108a6edae07SThomas Zimmermann WREG_CRT(1, hdisplay); 1109a6edae07SThomas Zimmermann WREG_CRT(2, hdisplay); 1110a6edae07SThomas Zimmermann WREG_CRT(3, (htotal & 0x1F) | 0x80); 1111a6edae07SThomas Zimmermann WREG_CRT(4, hsyncstart); 1112a6edae07SThomas Zimmermann WREG_CRT(5, ((htotal & 0x20) << 2) | (hsyncend & 0x1F)); 1113a6edae07SThomas Zimmermann WREG_CRT(6, vtotal & 0xFF); 1114a6edae07SThomas Zimmermann WREG_CRT(7, ((vtotal & 0x100) >> 8) | 1115a6edae07SThomas Zimmermann ((vdisplay & 0x100) >> 7) | 1116a6edae07SThomas Zimmermann ((vsyncstart & 0x100) >> 6) | 1117a6edae07SThomas Zimmermann ((vdisplay & 0x100) >> 5) | 1118a6edae07SThomas Zimmermann ((vdisplay & 0x100) >> 4) | /* linecomp */ 1119a6edae07SThomas Zimmermann ((vtotal & 0x200) >> 4) | 1120a6edae07SThomas Zimmermann ((vdisplay & 0x200) >> 3) | 1121a6edae07SThomas Zimmermann ((vsyncstart & 0x200) >> 2)); 1122a6edae07SThomas Zimmermann WREG_CRT(9, ((vdisplay & 0x200) >> 4) | 1123a6edae07SThomas Zimmermann ((vdisplay & 0x200) >> 3)); 1124a6edae07SThomas Zimmermann WREG_CRT(16, vsyncstart & 0xFF); 1125a6edae07SThomas Zimmermann WREG_CRT(17, (vsyncend & 0x0F) | 0x20); 1126a6edae07SThomas Zimmermann WREG_CRT(18, vdisplay & 0xFF); 1127a6edae07SThomas Zimmermann WREG_CRT(20, 0); 1128a6edae07SThomas Zimmermann WREG_CRT(21, vdisplay & 0xFF); 1129a6edae07SThomas Zimmermann WREG_CRT(22, (vtotal + 1) & 0xFF); 1130a6edae07SThomas Zimmermann WREG_CRT(23, 0xc3); 1131a6edae07SThomas Zimmermann WREG_CRT(24, vdisplay & 0xFF); 1132a6edae07SThomas Zimmermann 1133a6edae07SThomas Zimmermann WREG_ECRT(0x01, crtcext1); 1134a6edae07SThomas Zimmermann WREG_ECRT(0x02, crtcext2); 1135a6edae07SThomas Zimmermann WREG_ECRT(0x05, crtcext5); 1136db05f8d3SThomas Zimmermann 1137db05f8d3SThomas Zimmermann WREG8(MGA_MISC_OUT, misc); 1138a6edae07SThomas Zimmermann } 1139a6edae07SThomas Zimmermann 114072a03a35SThomas Zimmermann static u8 mgag200_get_bpp_shift(struct mga_device *mdev, 114172a03a35SThomas Zimmermann const struct drm_format_info *format) 114272a03a35SThomas Zimmermann { 114372a03a35SThomas Zimmermann return mdev->bpp_shifts[format->cpp[0] - 1]; 114472a03a35SThomas Zimmermann } 114572a03a35SThomas Zimmermann 114672a03a35SThomas Zimmermann /* 114772a03a35SThomas Zimmermann * Calculates the HW offset value from the framebuffer's pitch. The 114872a03a35SThomas Zimmermann * offset is a multiple of the pixel size and depends on the display 114972a03a35SThomas Zimmermann * format. 115072a03a35SThomas Zimmermann */ 115172a03a35SThomas Zimmermann static u32 mgag200_calculate_offset(struct mga_device *mdev, 115272a03a35SThomas Zimmermann const struct drm_framebuffer *fb) 115372a03a35SThomas Zimmermann { 115472a03a35SThomas Zimmermann u32 offset = fb->pitches[0] / fb->format->cpp[0]; 115572a03a35SThomas Zimmermann u8 bppshift = mgag200_get_bpp_shift(mdev, fb->format); 115672a03a35SThomas Zimmermann 115772a03a35SThomas Zimmermann if (fb->format->cpp[0] * 8 == 24) 115872a03a35SThomas Zimmermann offset = (offset * 3) >> (4 - bppshift); 115972a03a35SThomas Zimmermann else 116072a03a35SThomas Zimmermann offset = offset >> (4 - bppshift); 116172a03a35SThomas Zimmermann 116272a03a35SThomas Zimmermann return offset; 116372a03a35SThomas Zimmermann } 116472a03a35SThomas Zimmermann 116572a03a35SThomas Zimmermann static void mgag200_set_offset(struct mga_device *mdev, 116672a03a35SThomas Zimmermann const struct drm_framebuffer *fb) 116772a03a35SThomas Zimmermann { 116872a03a35SThomas Zimmermann u8 crtc13, crtcext0; 116972a03a35SThomas Zimmermann u32 offset = mgag200_calculate_offset(mdev, fb); 117072a03a35SThomas Zimmermann 117172a03a35SThomas Zimmermann RREG_ECRT(0, crtcext0); 117272a03a35SThomas Zimmermann 117372a03a35SThomas Zimmermann crtc13 = offset & 0xff; 117472a03a35SThomas Zimmermann 117572a03a35SThomas Zimmermann crtcext0 &= ~MGAREG_CRTCEXT0_OFFSET_MASK; 117672a03a35SThomas Zimmermann crtcext0 |= (offset >> 4) & MGAREG_CRTCEXT0_OFFSET_MASK; 117772a03a35SThomas Zimmermann 117872a03a35SThomas Zimmermann WREG_CRT(0x13, crtc13); 117972a03a35SThomas Zimmermann WREG_ECRT(0x00, crtcext0); 118072a03a35SThomas Zimmermann } 118172a03a35SThomas Zimmermann 1182836d5368SThomas Zimmermann static void mgag200_set_format_regs(struct mga_device *mdev, 1183836d5368SThomas Zimmermann const struct drm_framebuffer *fb) 1184836d5368SThomas Zimmermann { 1185832eddf5SThomas Zimmermann struct drm_device *dev = &mdev->base; 1186836d5368SThomas Zimmermann const struct drm_format_info *format = fb->format; 1187836d5368SThomas Zimmermann unsigned int bpp, bppshift, scale; 1188836d5368SThomas Zimmermann u8 crtcext3, xmulctrl; 1189836d5368SThomas Zimmermann 1190836d5368SThomas Zimmermann bpp = format->cpp[0] * 8; 1191836d5368SThomas Zimmermann 1192836d5368SThomas Zimmermann bppshift = mgag200_get_bpp_shift(mdev, format); 1193836d5368SThomas Zimmermann switch (bpp) { 1194836d5368SThomas Zimmermann case 24: 1195836d5368SThomas Zimmermann scale = ((1 << bppshift) * 3) - 1; 1196836d5368SThomas Zimmermann break; 1197836d5368SThomas Zimmermann default: 1198836d5368SThomas Zimmermann scale = (1 << bppshift) - 1; 1199836d5368SThomas Zimmermann break; 1200836d5368SThomas Zimmermann } 1201836d5368SThomas Zimmermann 1202836d5368SThomas Zimmermann RREG_ECRT(3, crtcext3); 1203836d5368SThomas Zimmermann 1204836d5368SThomas Zimmermann switch (bpp) { 1205836d5368SThomas Zimmermann case 8: 1206836d5368SThomas Zimmermann xmulctrl = MGA1064_MUL_CTL_8bits; 1207836d5368SThomas Zimmermann break; 1208836d5368SThomas Zimmermann case 16: 1209836d5368SThomas Zimmermann if (format->depth == 15) 1210836d5368SThomas Zimmermann xmulctrl = MGA1064_MUL_CTL_15bits; 1211836d5368SThomas Zimmermann else 1212836d5368SThomas Zimmermann xmulctrl = MGA1064_MUL_CTL_16bits; 1213836d5368SThomas Zimmermann break; 1214836d5368SThomas Zimmermann case 24: 1215836d5368SThomas Zimmermann xmulctrl = MGA1064_MUL_CTL_24bits; 1216836d5368SThomas Zimmermann break; 1217836d5368SThomas Zimmermann case 32: 1218836d5368SThomas Zimmermann xmulctrl = MGA1064_MUL_CTL_32_24bits; 1219836d5368SThomas Zimmermann break; 1220836d5368SThomas Zimmermann default: 1221836d5368SThomas Zimmermann /* BUG: We should have caught this problem already. */ 1222836d5368SThomas Zimmermann drm_WARN_ON(dev, "invalid format depth\n"); 1223836d5368SThomas Zimmermann return; 1224836d5368SThomas Zimmermann } 1225836d5368SThomas Zimmermann 1226836d5368SThomas Zimmermann crtcext3 &= ~GENMASK(2, 0); 1227836d5368SThomas Zimmermann crtcext3 |= scale; 1228836d5368SThomas Zimmermann 1229836d5368SThomas Zimmermann WREG_DAC(MGA1064_MUL_CTL, xmulctrl); 1230836d5368SThomas Zimmermann 1231836d5368SThomas Zimmermann WREG_GFX(0, 0x00); 1232836d5368SThomas Zimmermann WREG_GFX(1, 0x00); 1233836d5368SThomas Zimmermann WREG_GFX(2, 0x00); 1234836d5368SThomas Zimmermann WREG_GFX(3, 0x00); 1235836d5368SThomas Zimmermann WREG_GFX(4, 0x00); 1236836d5368SThomas Zimmermann WREG_GFX(5, 0x40); 1237836d5368SThomas Zimmermann WREG_GFX(6, 0x05); 1238836d5368SThomas Zimmermann WREG_GFX(7, 0x0f); 1239836d5368SThomas Zimmermann WREG_GFX(8, 0x0f); 1240836d5368SThomas Zimmermann 1241836d5368SThomas Zimmermann WREG_ECRT(3, crtcext3); 1242836d5368SThomas Zimmermann } 1243836d5368SThomas Zimmermann 12442e5ccbbaSThomas Zimmermann static void mgag200_g200er_reset_tagfifo(struct mga_device *mdev) 12452e5ccbbaSThomas Zimmermann { 12462e5ccbbaSThomas Zimmermann static uint32_t RESET_FLAG = 0x00200000; /* undocumented magic value */ 12472e5ccbbaSThomas Zimmermann u32 memctl; 12482e5ccbbaSThomas Zimmermann 12492e5ccbbaSThomas Zimmermann memctl = RREG32(MGAREG_MEMCTL); 12502e5ccbbaSThomas Zimmermann 12512e5ccbbaSThomas Zimmermann memctl |= RESET_FLAG; 12522e5ccbbaSThomas Zimmermann WREG32(MGAREG_MEMCTL, memctl); 12532e5ccbbaSThomas Zimmermann 12542e5ccbbaSThomas Zimmermann udelay(1000); 12552e5ccbbaSThomas Zimmermann 12562e5ccbbaSThomas Zimmermann memctl &= ~RESET_FLAG; 12572e5ccbbaSThomas Zimmermann WREG32(MGAREG_MEMCTL, memctl); 12582e5ccbbaSThomas Zimmermann } 12592e5ccbbaSThomas Zimmermann 12607fc1ae56SThomas Zimmermann static void mgag200_g200se_set_hiprilvl(struct mga_device *mdev, 12617fc1ae56SThomas Zimmermann const struct drm_display_mode *mode, 12627fc1ae56SThomas Zimmermann const struct drm_framebuffer *fb) 12637fc1ae56SThomas Zimmermann { 1264fb18825fSThomas Zimmermann u32 unique_rev_id = mdev->model.g200se.unique_rev_id; 12657fc1ae56SThomas Zimmermann unsigned int hiprilvl; 12667fc1ae56SThomas Zimmermann u8 crtcext6; 12677fc1ae56SThomas Zimmermann 1268fb18825fSThomas Zimmermann if (unique_rev_id >= 0x04) { 12697fc1ae56SThomas Zimmermann hiprilvl = 0; 1270fb18825fSThomas Zimmermann } else if (unique_rev_id >= 0x02) { 12717fc1ae56SThomas Zimmermann unsigned int bpp; 12727fc1ae56SThomas Zimmermann unsigned long mb; 12737fc1ae56SThomas Zimmermann 12747fc1ae56SThomas Zimmermann if (fb->format->cpp[0] * 8 > 16) 12757fc1ae56SThomas Zimmermann bpp = 32; 12767fc1ae56SThomas Zimmermann else if (fb->format->cpp[0] * 8 > 8) 12777fc1ae56SThomas Zimmermann bpp = 16; 12787fc1ae56SThomas Zimmermann else 12797fc1ae56SThomas Zimmermann bpp = 8; 12807fc1ae56SThomas Zimmermann 12817fc1ae56SThomas Zimmermann mb = (mode->clock * bpp) / 1000; 12827fc1ae56SThomas Zimmermann if (mb > 3100) 12837fc1ae56SThomas Zimmermann hiprilvl = 0; 12847fc1ae56SThomas Zimmermann else if (mb > 2600) 12857fc1ae56SThomas Zimmermann hiprilvl = 1; 12867fc1ae56SThomas Zimmermann else if (mb > 1900) 12877fc1ae56SThomas Zimmermann hiprilvl = 2; 12887fc1ae56SThomas Zimmermann else if (mb > 1160) 12897fc1ae56SThomas Zimmermann hiprilvl = 3; 12907fc1ae56SThomas Zimmermann else if (mb > 440) 12917fc1ae56SThomas Zimmermann hiprilvl = 4; 12927fc1ae56SThomas Zimmermann else 12937fc1ae56SThomas Zimmermann hiprilvl = 5; 12947fc1ae56SThomas Zimmermann 1295fb18825fSThomas Zimmermann } else if (unique_rev_id >= 0x01) { 12967fc1ae56SThomas Zimmermann hiprilvl = 3; 12977fc1ae56SThomas Zimmermann } else { 12987fc1ae56SThomas Zimmermann hiprilvl = 4; 12997fc1ae56SThomas Zimmermann } 13007fc1ae56SThomas Zimmermann 13017fc1ae56SThomas Zimmermann crtcext6 = hiprilvl; /* implicitly sets maxhipri to 0 */ 13027fc1ae56SThomas Zimmermann 13037fc1ae56SThomas Zimmermann WREG_ECRT(0x06, crtcext6); 13047fc1ae56SThomas Zimmermann } 13057fc1ae56SThomas Zimmermann 13067fc1ae56SThomas Zimmermann static void mgag200_g200ev_set_hiprilvl(struct mga_device *mdev) 13077fc1ae56SThomas Zimmermann { 13087fc1ae56SThomas Zimmermann WREG_ECRT(0x06, 0x00); 13097fc1ae56SThomas Zimmermann } 13107fc1ae56SThomas Zimmermann 1311153fef41SThomas Zimmermann static void mgag200_enable_display(struct mga_device *mdev) 1312414c4531SDave Airlie { 131370c3881eSThomas Zimmermann u8 seq0, seq1, crtcext1; 131470c3881eSThomas Zimmermann 131570c3881eSThomas Zimmermann RREG_SEQ(0x00, seq0); 131670c3881eSThomas Zimmermann seq0 |= MGAREG_SEQ0_SYNCRST | 131770c3881eSThomas Zimmermann MGAREG_SEQ0_ASYNCRST; 131870c3881eSThomas Zimmermann WREG_SEQ(0x00, seq0); 1319414c4531SDave Airlie 1320153fef41SThomas Zimmermann /* 1321153fef41SThomas Zimmermann * TODO: replace busy waiting with vblank IRQ; put 1322153fef41SThomas Zimmermann * msleep(50) before changing SCROFF 1323153fef41SThomas Zimmermann */ 1324414c4531SDave Airlie mga_wait_vsync(mdev); 1325414c4531SDave Airlie mga_wait_busy(mdev); 1326153fef41SThomas Zimmermann 1327153fef41SThomas Zimmermann RREG_SEQ(0x01, seq1); 1328153fef41SThomas Zimmermann seq1 &= ~MGAREG_SEQ1_SCROFF; 1329153fef41SThomas Zimmermann WREG_SEQ(0x01, seq1); 1330153fef41SThomas Zimmermann 1331414c4531SDave Airlie msleep(20); 1332153fef41SThomas Zimmermann 1333153fef41SThomas Zimmermann RREG_ECRT(0x01, crtcext1); 1334153fef41SThomas Zimmermann crtcext1 &= ~MGAREG_CRTCEXT1_VSYNCOFF; 1335153fef41SThomas Zimmermann crtcext1 &= ~MGAREG_CRTCEXT1_HSYNCOFF; 1336153fef41SThomas Zimmermann WREG_ECRT(0x01, crtcext1); 1337153fef41SThomas Zimmermann } 1338153fef41SThomas Zimmermann 1339153fef41SThomas Zimmermann static void mgag200_disable_display(struct mga_device *mdev) 1340153fef41SThomas Zimmermann { 134170c3881eSThomas Zimmermann u8 seq0, seq1, crtcext1; 134270c3881eSThomas Zimmermann 134370c3881eSThomas Zimmermann RREG_SEQ(0x00, seq0); 134470c3881eSThomas Zimmermann seq0 &= ~MGAREG_SEQ0_SYNCRST; 134570c3881eSThomas Zimmermann WREG_SEQ(0x00, seq0); 1346153fef41SThomas Zimmermann 1347153fef41SThomas Zimmermann /* 1348153fef41SThomas Zimmermann * TODO: replace busy waiting with vblank IRQ; put 1349153fef41SThomas Zimmermann * msleep(50) before changing SCROFF 1350153fef41SThomas Zimmermann */ 1351153fef41SThomas Zimmermann mga_wait_vsync(mdev); 1352153fef41SThomas Zimmermann mga_wait_busy(mdev); 1353153fef41SThomas Zimmermann 1354153fef41SThomas Zimmermann RREG_SEQ(0x01, seq1); 1355153fef41SThomas Zimmermann seq1 |= MGAREG_SEQ1_SCROFF; 1356153fef41SThomas Zimmermann WREG_SEQ(0x01, seq1); 1357153fef41SThomas Zimmermann 1358153fef41SThomas Zimmermann msleep(20); 1359153fef41SThomas Zimmermann 1360153fef41SThomas Zimmermann RREG_ECRT(0x01, crtcext1); 1361153fef41SThomas Zimmermann crtcext1 |= MGAREG_CRTCEXT1_VSYNCOFF | 1362153fef41SThomas Zimmermann MGAREG_CRTCEXT1_HSYNCOFF; 1363153fef41SThomas Zimmermann WREG_ECRT(0x01, crtcext1); 1364414c4531SDave Airlie } 1365414c4531SDave Airlie 1366414c4531SDave Airlie /* 136781a15b9aSThomas Zimmermann * Connector 136881a15b9aSThomas Zimmermann */ 136981a15b9aSThomas Zimmermann 1370414c4531SDave Airlie static int mga_vga_get_modes(struct drm_connector *connector) 1371414c4531SDave Airlie { 1372414c4531SDave Airlie struct mga_connector *mga_connector = to_mga_connector(connector); 1373414c4531SDave Airlie struct edid *edid; 1374414c4531SDave Airlie int ret = 0; 1375414c4531SDave Airlie 1376414c4531SDave Airlie edid = drm_get_edid(connector, &mga_connector->i2c->adapter); 1377414c4531SDave Airlie if (edid) { 1378c555f023SDaniel Vetter drm_connector_update_edid_property(connector, edid); 1379414c4531SDave Airlie ret = drm_add_edid_modes(connector, edid); 1380414c4531SDave Airlie kfree(edid); 1381414c4531SDave Airlie } 1382414c4531SDave Airlie return ret; 1383414c4531SDave Airlie } 1384414c4531SDave Airlie 1385abbee623SJulia Lemire static uint32_t mga_vga_calculate_mode_bandwidth(struct drm_display_mode *mode, 1386abbee623SJulia Lemire int bits_per_pixel) 1387abbee623SJulia Lemire { 1388abbee623SJulia Lemire uint32_t total_area, divisor; 1389c24ca5beSNicolas Pitre uint64_t active_area, pixels_per_second, bandwidth; 1390abbee623SJulia Lemire uint64_t bytes_per_pixel = (bits_per_pixel + 7) / 8; 1391abbee623SJulia Lemire 1392abbee623SJulia Lemire divisor = 1024; 1393abbee623SJulia Lemire 1394abbee623SJulia Lemire if (!mode->htotal || !mode->vtotal || !mode->clock) 1395abbee623SJulia Lemire return 0; 1396abbee623SJulia Lemire 1397abbee623SJulia Lemire active_area = mode->hdisplay * mode->vdisplay; 1398abbee623SJulia Lemire total_area = mode->htotal * mode->vtotal; 1399abbee623SJulia Lemire 1400abbee623SJulia Lemire pixels_per_second = active_area * mode->clock * 1000; 1401abbee623SJulia Lemire do_div(pixels_per_second, total_area); 1402abbee623SJulia Lemire 1403abbee623SJulia Lemire bandwidth = pixels_per_second * bytes_per_pixel * 100; 1404abbee623SJulia Lemire do_div(bandwidth, divisor); 1405abbee623SJulia Lemire 1406abbee623SJulia Lemire return (uint32_t)(bandwidth); 1407abbee623SJulia Lemire } 1408abbee623SJulia Lemire 1409abbee623SJulia Lemire #define MODE_BANDWIDTH MODE_BAD 1410abbee623SJulia Lemire 1411c69e52deSLuc Van Oostenryck static enum drm_mode_status mga_vga_mode_valid(struct drm_connector *connector, 1412414c4531SDave Airlie struct drm_display_mode *mode) 1413414c4531SDave Airlie { 14140ba53171SChristopher Harvey struct drm_device *dev = connector->dev; 14158d8ff2a9SThomas Zimmermann struct mga_device *mdev = to_mga_device(dev); 14160ba53171SChristopher Harvey int bpp = 32; 14170ba53171SChristopher Harvey 1418abbee623SJulia Lemire if (IS_G200_SE(mdev)) { 1419fb18825fSThomas Zimmermann u32 unique_rev_id = mdev->model.g200se.unique_rev_id; 1420fb18825fSThomas Zimmermann 1421fb18825fSThomas Zimmermann if (unique_rev_id == 0x01) { 1422abbee623SJulia Lemire if (mode->hdisplay > 1600) 1423abbee623SJulia Lemire return MODE_VIRTUAL_X; 1424abbee623SJulia Lemire if (mode->vdisplay > 1200) 1425abbee623SJulia Lemire return MODE_VIRTUAL_Y; 1426abbee623SJulia Lemire if (mga_vga_calculate_mode_bandwidth(mode, bpp) 1427abbee623SJulia Lemire > (24400 * 1024)) 1428abbee623SJulia Lemire return MODE_BANDWIDTH; 1429fb18825fSThomas Zimmermann } else if (unique_rev_id == 0x02) { 1430abbee623SJulia Lemire if (mode->hdisplay > 1920) 1431abbee623SJulia Lemire return MODE_VIRTUAL_X; 1432abbee623SJulia Lemire if (mode->vdisplay > 1200) 1433abbee623SJulia Lemire return MODE_VIRTUAL_Y; 1434abbee623SJulia Lemire if (mga_vga_calculate_mode_bandwidth(mode, bpp) 1435abbee623SJulia Lemire > (30100 * 1024)) 1436abbee623SJulia Lemire return MODE_BANDWIDTH; 14370cbb7381SMathieu Larouche } else { 14380cbb7381SMathieu Larouche if (mga_vga_calculate_mode_bandwidth(mode, bpp) 14390cbb7381SMathieu Larouche > (55000 * 1024)) 14400cbb7381SMathieu Larouche return MODE_BANDWIDTH; 1441abbee623SJulia Lemire } 1442abbee623SJulia Lemire } else if (mdev->type == G200_WB) { 1443abbee623SJulia Lemire if (mode->hdisplay > 1280) 1444abbee623SJulia Lemire return MODE_VIRTUAL_X; 1445abbee623SJulia Lemire if (mode->vdisplay > 1024) 1446abbee623SJulia Lemire return MODE_VIRTUAL_Y; 14479eb8d7a9SDan Carpenter if (mga_vga_calculate_mode_bandwidth(mode, bpp) > 14489eb8d7a9SDan Carpenter (31877 * 1024)) 1449abbee623SJulia Lemire return MODE_BANDWIDTH; 1450abbee623SJulia Lemire } else if (mdev->type == G200_EV && 1451abbee623SJulia Lemire (mga_vga_calculate_mode_bandwidth(mode, bpp) 1452abbee623SJulia Lemire > (32700 * 1024))) { 1453abbee623SJulia Lemire return MODE_BANDWIDTH; 1454ec22b4aaSDave Airlie } else if (mdev->type == G200_EH && 1455abbee623SJulia Lemire (mga_vga_calculate_mode_bandwidth(mode, bpp) 1456abbee623SJulia Lemire > (37500 * 1024))) { 1457abbee623SJulia Lemire return MODE_BANDWIDTH; 1458ec22b4aaSDave Airlie } else if (mdev->type == G200_ER && 1459abbee623SJulia Lemire (mga_vga_calculate_mode_bandwidth(mode, 1460abbee623SJulia Lemire bpp) > (55000 * 1024))) { 1461abbee623SJulia Lemire return MODE_BANDWIDTH; 1462abbee623SJulia Lemire } 1463414c4531SDave Airlie 146425161084SAdam Jackson if ((mode->hdisplay % 8) != 0 || (mode->hsync_start % 8) != 0 || 146525161084SAdam Jackson (mode->hsync_end % 8) != 0 || (mode->htotal % 8) != 0) { 146625161084SAdam Jackson return MODE_H_ILLEGAL; 146725161084SAdam Jackson } 146825161084SAdam Jackson 1469414c4531SDave Airlie if (mode->crtc_hdisplay > 2048 || mode->crtc_hsync_start > 4096 || 1470414c4531SDave Airlie mode->crtc_hsync_end > 4096 || mode->crtc_htotal > 4096 || 1471414c4531SDave Airlie mode->crtc_vdisplay > 2048 || mode->crtc_vsync_start > 4096 || 1472414c4531SDave Airlie mode->crtc_vsync_end > 4096 || mode->crtc_vtotal > 4096) { 1473414c4531SDave Airlie return MODE_BAD; 1474414c4531SDave Airlie } 1475414c4531SDave Airlie 14760ba53171SChristopher Harvey /* Validate the mode input by the user */ 1477eaf99c74SChris Wilson if (connector->cmdline_mode.specified) { 1478eaf99c74SChris Wilson if (connector->cmdline_mode.bpp_specified) 1479eaf99c74SChris Wilson bpp = connector->cmdline_mode.bpp; 14800ba53171SChristopher Harvey } 14810ba53171SChristopher Harvey 14822c51a660SThomas Zimmermann if ((mode->hdisplay * mode->vdisplay * (bpp/8)) > mdev->vram_fb_available) { 1483eaf99c74SChris Wilson if (connector->cmdline_mode.specified) 1484eaf99c74SChris Wilson connector->cmdline_mode.specified = false; 14850ba53171SChristopher Harvey return MODE_BAD; 14860ba53171SChristopher Harvey } 14870ba53171SChristopher Harvey 1488414c4531SDave Airlie return MODE_OK; 1489414c4531SDave Airlie } 1490414c4531SDave Airlie 1491414c4531SDave Airlie static void mga_connector_destroy(struct drm_connector *connector) 1492414c4531SDave Airlie { 1493414c4531SDave Airlie struct mga_connector *mga_connector = to_mga_connector(connector); 1494414c4531SDave Airlie mgag200_i2c_destroy(mga_connector->i2c); 1495414c4531SDave Airlie drm_connector_cleanup(connector); 1496414c4531SDave Airlie } 1497414c4531SDave Airlie 149871cb7495SVille Syrjälä static const struct drm_connector_helper_funcs mga_vga_connector_helper_funcs = { 1499414c4531SDave Airlie .get_modes = mga_vga_get_modes, 1500414c4531SDave Airlie .mode_valid = mga_vga_mode_valid, 1501414c4531SDave Airlie }; 1502414c4531SDave Airlie 150371cb7495SVille Syrjälä static const struct drm_connector_funcs mga_vga_connector_funcs = { 150488fabb75SThomas Zimmermann .reset = drm_atomic_helper_connector_reset, 1505414c4531SDave Airlie .fill_modes = drm_helper_probe_single_connector_modes, 1506414c4531SDave Airlie .destroy = mga_connector_destroy, 150788fabb75SThomas Zimmermann .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, 150888fabb75SThomas Zimmermann .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, 1509414c4531SDave Airlie }; 1510414c4531SDave Airlie 151181a15b9aSThomas Zimmermann static int mgag200_vga_connector_init(struct mga_device *mdev) 1512414c4531SDave Airlie { 1513832eddf5SThomas Zimmermann struct drm_device *dev = &mdev->base; 151481a15b9aSThomas Zimmermann struct mga_connector *mconnector = &mdev->connector; 151581a15b9aSThomas Zimmermann struct drm_connector *connector = &mconnector->base; 151681a15b9aSThomas Zimmermann struct mga_i2c_chan *i2c; 151781a15b9aSThomas Zimmermann int ret; 1518414c4531SDave Airlie 151981a15b9aSThomas Zimmermann i2c = mgag200_i2c_create(dev); 152081a15b9aSThomas Zimmermann if (!i2c) 152181a15b9aSThomas Zimmermann drm_warn(dev, "failed to add DDC bus\n"); 1522414c4531SDave Airlie 152381a15b9aSThomas Zimmermann ret = drm_connector_init_with_ddc(dev, connector, 15249572ae17SAndrzej Pietrasiewicz &mga_vga_connector_funcs, 15259572ae17SAndrzej Pietrasiewicz DRM_MODE_CONNECTOR_VGA, 152681a15b9aSThomas Zimmermann &i2c->adapter); 152781a15b9aSThomas Zimmermann if (ret) 152881a15b9aSThomas Zimmermann goto err_mgag200_i2c_destroy; 1529414c4531SDave Airlie drm_connector_helper_add(connector, &mga_vga_connector_helper_funcs); 1530414c4531SDave Airlie 153181a15b9aSThomas Zimmermann mconnector->i2c = i2c; 15323d5a1c5eSEgbert Eich 153381a15b9aSThomas Zimmermann return 0; 153481a15b9aSThomas Zimmermann 153581a15b9aSThomas Zimmermann err_mgag200_i2c_destroy: 153681a15b9aSThomas Zimmermann mgag200_i2c_destroy(i2c); 153781a15b9aSThomas Zimmermann return ret; 1538414c4531SDave Airlie } 1539414c4531SDave Airlie 154088fabb75SThomas Zimmermann /* 154188fabb75SThomas Zimmermann * Simple Display Pipe 154288fabb75SThomas Zimmermann */ 154388fabb75SThomas Zimmermann 154488fabb75SThomas Zimmermann static enum drm_mode_status 154588fabb75SThomas Zimmermann mgag200_simple_display_pipe_mode_valid(struct drm_simple_display_pipe *pipe, 154688fabb75SThomas Zimmermann const struct drm_display_mode *mode) 154788fabb75SThomas Zimmermann { 154888fabb75SThomas Zimmermann return MODE_OK; 154988fabb75SThomas Zimmermann } 155088fabb75SThomas Zimmermann 155188fabb75SThomas Zimmermann static void 1552913ec479SThomas Zimmermann mgag200_handle_damage(struct mga_device *mdev, struct drm_framebuffer *fb, 15534862ffaeSThomas Zimmermann struct drm_rect *clip, const struct dma_buf_map *map) 1554913ec479SThomas Zimmermann { 15554862ffaeSThomas Zimmermann void *vmap = map->vaddr; /* TODO: Use mapping abstraction properly */ 1556913ec479SThomas Zimmermann 1557*5ab7af71SThomas Zimmermann drm_fb_memcpy_dstclip(mdev->vram, fb->pitches[0], vmap, fb, clip); 1558913ec479SThomas Zimmermann 1559913ec479SThomas Zimmermann /* Always scanout image at VRAM offset 0 */ 1560913ec479SThomas Zimmermann mgag200_set_startadd(mdev, (u32)0); 1561913ec479SThomas Zimmermann mgag200_set_offset(mdev, fb); 1562913ec479SThomas Zimmermann } 1563913ec479SThomas Zimmermann 1564913ec479SThomas Zimmermann static void 156588fabb75SThomas Zimmermann mgag200_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe, 156688fabb75SThomas Zimmermann struct drm_crtc_state *crtc_state, 156788fabb75SThomas Zimmermann struct drm_plane_state *plane_state) 156888fabb75SThomas Zimmermann { 156988fabb75SThomas Zimmermann struct drm_crtc *crtc = &pipe->crtc; 157088fabb75SThomas Zimmermann struct drm_device *dev = crtc->dev; 157188fabb75SThomas Zimmermann struct mga_device *mdev = to_mga_device(dev); 157288fabb75SThomas Zimmermann struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode; 157388fabb75SThomas Zimmermann struct drm_framebuffer *fb = plane_state->fb; 15744862ffaeSThomas Zimmermann struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); 1575913ec479SThomas Zimmermann struct drm_rect fullscreen = { 1576913ec479SThomas Zimmermann .x1 = 0, 1577913ec479SThomas Zimmermann .x2 = fb->width, 1578913ec479SThomas Zimmermann .y1 = 0, 1579913ec479SThomas Zimmermann .y2 = fb->height, 1580913ec479SThomas Zimmermann }; 158188fabb75SThomas Zimmermann 1582895a4790SThomas Zimmermann if (mdev->type == G200_WB || mdev->type == G200_EW3) 1583895a4790SThomas Zimmermann mgag200_g200wb_hold_bmc(mdev); 158488fabb75SThomas Zimmermann 158588fabb75SThomas Zimmermann mgag200_set_format_regs(mdev, fb); 158688fabb75SThomas Zimmermann mgag200_set_mode_regs(mdev, adjusted_mode); 1587fc42e89fSThomas Zimmermann mgag200_crtc_set_plls(mdev, adjusted_mode->clock); 158888fabb75SThomas Zimmermann 158988fabb75SThomas Zimmermann if (mdev->type == G200_ER) 159088fabb75SThomas Zimmermann mgag200_g200er_reset_tagfifo(mdev); 159188fabb75SThomas Zimmermann 159288fabb75SThomas Zimmermann if (IS_G200_SE(mdev)) 159388fabb75SThomas Zimmermann mgag200_g200se_set_hiprilvl(mdev, adjusted_mode, fb); 159488fabb75SThomas Zimmermann else if (mdev->type == G200_EV) 159588fabb75SThomas Zimmermann mgag200_g200ev_set_hiprilvl(mdev); 159688fabb75SThomas Zimmermann 1597895a4790SThomas Zimmermann if (mdev->type == G200_WB || mdev->type == G200_EW3) 1598895a4790SThomas Zimmermann mgag200_g200wb_release_bmc(mdev); 1599895a4790SThomas Zimmermann 1600895a4790SThomas Zimmermann mga_crtc_load_lut(crtc); 1601895a4790SThomas Zimmermann mgag200_enable_display(mdev); 1602913ec479SThomas Zimmermann 16034862ffaeSThomas Zimmermann mgag200_handle_damage(mdev, fb, &fullscreen, &shadow_plane_state->map[0]); 160488fabb75SThomas Zimmermann } 160588fabb75SThomas Zimmermann 160688fabb75SThomas Zimmermann static void 160788fabb75SThomas Zimmermann mgag200_simple_display_pipe_disable(struct drm_simple_display_pipe *pipe) 160888fabb75SThomas Zimmermann { 160988fabb75SThomas Zimmermann struct drm_crtc *crtc = &pipe->crtc; 1610153fef41SThomas Zimmermann struct mga_device *mdev = to_mga_device(crtc->dev); 161188fabb75SThomas Zimmermann 1612153fef41SThomas Zimmermann mgag200_disable_display(mdev); 161388fabb75SThomas Zimmermann } 161488fabb75SThomas Zimmermann 161588fabb75SThomas Zimmermann static int 161688fabb75SThomas Zimmermann mgag200_simple_display_pipe_check(struct drm_simple_display_pipe *pipe, 161788fabb75SThomas Zimmermann struct drm_plane_state *plane_state, 161888fabb75SThomas Zimmermann struct drm_crtc_state *crtc_state) 161988fabb75SThomas Zimmermann { 162088fabb75SThomas Zimmermann struct drm_plane *plane = plane_state->plane; 162188fabb75SThomas Zimmermann struct drm_framebuffer *new_fb = plane_state->fb; 162288fabb75SThomas Zimmermann struct drm_framebuffer *fb = NULL; 162388fabb75SThomas Zimmermann 162488fabb75SThomas Zimmermann if (!new_fb) 162588fabb75SThomas Zimmermann return 0; 162688fabb75SThomas Zimmermann 162788fabb75SThomas Zimmermann if (plane->state) 162888fabb75SThomas Zimmermann fb = plane->state->fb; 162988fabb75SThomas Zimmermann 163088fabb75SThomas Zimmermann if (!fb || (fb->format != new_fb->format)) 163188fabb75SThomas Zimmermann crtc_state->mode_changed = true; /* update PLL settings */ 163288fabb75SThomas Zimmermann 163388fabb75SThomas Zimmermann return 0; 163488fabb75SThomas Zimmermann } 163588fabb75SThomas Zimmermann 163688fabb75SThomas Zimmermann static void 163788fabb75SThomas Zimmermann mgag200_simple_display_pipe_update(struct drm_simple_display_pipe *pipe, 163888fabb75SThomas Zimmermann struct drm_plane_state *old_state) 163988fabb75SThomas Zimmermann { 164088fabb75SThomas Zimmermann struct drm_plane *plane = &pipe->plane; 164188fabb75SThomas Zimmermann struct drm_device *dev = plane->dev; 164288fabb75SThomas Zimmermann struct mga_device *mdev = to_mga_device(dev); 164388fabb75SThomas Zimmermann struct drm_plane_state *state = plane->state; 16444862ffaeSThomas Zimmermann struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(state); 164588fabb75SThomas Zimmermann struct drm_framebuffer *fb = state->fb; 1646913ec479SThomas Zimmermann struct drm_rect damage; 164788fabb75SThomas Zimmermann 164888fabb75SThomas Zimmermann if (!fb) 164988fabb75SThomas Zimmermann return; 165088fabb75SThomas Zimmermann 1651913ec479SThomas Zimmermann if (drm_atomic_helper_damage_merged(old_state, state, &damage)) 16524862ffaeSThomas Zimmermann mgag200_handle_damage(mdev, fb, &damage, &shadow_plane_state->map[0]); 165388fabb75SThomas Zimmermann } 165488fabb75SThomas Zimmermann 165588fabb75SThomas Zimmermann static const struct drm_simple_display_pipe_funcs 165688fabb75SThomas Zimmermann mgag200_simple_display_pipe_funcs = { 165788fabb75SThomas Zimmermann .mode_valid = mgag200_simple_display_pipe_mode_valid, 165888fabb75SThomas Zimmermann .enable = mgag200_simple_display_pipe_enable, 165988fabb75SThomas Zimmermann .disable = mgag200_simple_display_pipe_disable, 166088fabb75SThomas Zimmermann .check = mgag200_simple_display_pipe_check, 166188fabb75SThomas Zimmermann .update = mgag200_simple_display_pipe_update, 16624862ffaeSThomas Zimmermann DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS, 166388fabb75SThomas Zimmermann }; 166488fabb75SThomas Zimmermann 166588fabb75SThomas Zimmermann static const uint32_t mgag200_simple_display_pipe_formats[] = { 166688fabb75SThomas Zimmermann DRM_FORMAT_XRGB8888, 166788fabb75SThomas Zimmermann DRM_FORMAT_RGB565, 166888fabb75SThomas Zimmermann DRM_FORMAT_RGB888, 166988fabb75SThomas Zimmermann }; 167088fabb75SThomas Zimmermann 167188fabb75SThomas Zimmermann static const uint64_t mgag200_simple_display_pipe_fmtmods[] = { 167288fabb75SThomas Zimmermann DRM_FORMAT_MOD_LINEAR, 167388fabb75SThomas Zimmermann DRM_FORMAT_MOD_INVALID 167488fabb75SThomas Zimmermann }; 167588fabb75SThomas Zimmermann 167688fabb75SThomas Zimmermann /* 167788fabb75SThomas Zimmermann * Mode config 167888fabb75SThomas Zimmermann */ 167988fabb75SThomas Zimmermann 16805635b7cfSThomas Zimmermann static const struct drm_mode_config_funcs mgag200_mode_config_funcs = { 1681913ec479SThomas Zimmermann .fb_create = drm_gem_fb_create_with_dirty, 168288fabb75SThomas Zimmermann .atomic_check = drm_atomic_helper_check, 168388fabb75SThomas Zimmermann .atomic_commit = drm_atomic_helper_commit, 16845635b7cfSThomas Zimmermann }; 16855635b7cfSThomas Zimmermann 16865635b7cfSThomas Zimmermann static unsigned int mgag200_preferred_depth(struct mga_device *mdev) 16875635b7cfSThomas Zimmermann { 16885635b7cfSThomas Zimmermann if (IS_G200_SE(mdev) && mdev->vram_fb_available < (2048*1024)) 16895635b7cfSThomas Zimmermann return 16; 16905635b7cfSThomas Zimmermann else 16915635b7cfSThomas Zimmermann return 32; 16925635b7cfSThomas Zimmermann } 1693414c4531SDave Airlie 1694414c4531SDave Airlie int mgag200_modeset_init(struct mga_device *mdev) 1695414c4531SDave Airlie { 1696832eddf5SThomas Zimmermann struct drm_device *dev = &mdev->base; 169781a15b9aSThomas Zimmermann struct drm_connector *connector = &mdev->connector.base; 169888fabb75SThomas Zimmermann struct drm_simple_display_pipe *pipe = &mdev->display_pipe; 169988fabb75SThomas Zimmermann size_t format_count = ARRAY_SIZE(mgag200_simple_display_pipe_formats); 170003e44ad1SThomas Zimmermann int ret; 1701414c4531SDave Airlie 17025635b7cfSThomas Zimmermann mdev->bpp_shifts[0] = 0; 17035635b7cfSThomas Zimmermann mdev->bpp_shifts[1] = 1; 17045635b7cfSThomas Zimmermann mdev->bpp_shifts[2] = 0; 17055635b7cfSThomas Zimmermann mdev->bpp_shifts[3] = 2; 17065635b7cfSThomas Zimmermann 170788fabb75SThomas Zimmermann mgag200_init_regs(mdev); 170888fabb75SThomas Zimmermann 17095635b7cfSThomas Zimmermann ret = drmm_mode_config_init(dev); 17105635b7cfSThomas Zimmermann if (ret) { 17115635b7cfSThomas Zimmermann drm_err(dev, "drmm_mode_config_init() failed, error %d\n", 17125635b7cfSThomas Zimmermann ret); 17135635b7cfSThomas Zimmermann return ret; 17145635b7cfSThomas Zimmermann } 17155635b7cfSThomas Zimmermann 1716ed5877b6SThomas Zimmermann dev->mode_config.max_width = MGAG200_MAX_FB_WIDTH; 1717ed5877b6SThomas Zimmermann dev->mode_config.max_height = MGAG200_MAX_FB_HEIGHT; 1718414c4531SDave Airlie 17195635b7cfSThomas Zimmermann dev->mode_config.preferred_depth = mgag200_preferred_depth(mdev); 17205635b7cfSThomas Zimmermann 1721ed5877b6SThomas Zimmermann dev->mode_config.fb_base = mdev->mc.vram_base; 1722414c4531SDave Airlie 17235635b7cfSThomas Zimmermann dev->mode_config.funcs = &mgag200_mode_config_funcs; 17245635b7cfSThomas Zimmermann 172581a15b9aSThomas Zimmermann ret = mgag200_vga_connector_init(mdev); 172681a15b9aSThomas Zimmermann if (ret) { 172781a15b9aSThomas Zimmermann drm_err(dev, 172881a15b9aSThomas Zimmermann "mgag200_vga_connector_init() failed, error %d\n", 172981a15b9aSThomas Zimmermann ret); 173081a15b9aSThomas Zimmermann return ret; 1731414c4531SDave Airlie } 1732414c4531SDave Airlie 173388fabb75SThomas Zimmermann ret = drm_simple_display_pipe_init(dev, pipe, 173488fabb75SThomas Zimmermann &mgag200_simple_display_pipe_funcs, 173588fabb75SThomas Zimmermann mgag200_simple_display_pipe_formats, 173688fabb75SThomas Zimmermann format_count, 173788fabb75SThomas Zimmermann mgag200_simple_display_pipe_fmtmods, 173888fabb75SThomas Zimmermann connector); 173988fabb75SThomas Zimmermann if (ret) { 174088fabb75SThomas Zimmermann drm_err(dev, 174188fabb75SThomas Zimmermann "drm_simple_display_pipe_init() failed, error %d\n", 174288fabb75SThomas Zimmermann ret); 174388fabb75SThomas Zimmermann return ret; 174488fabb75SThomas Zimmermann } 174588fabb75SThomas Zimmermann 174688fabb75SThomas Zimmermann /* FIXME: legacy gamma tables; convert to CRTC state */ 174788fabb75SThomas Zimmermann drm_mode_crtc_set_gamma_size(&pipe->crtc, MGAG200_LUT_SIZE); 174888fabb75SThomas Zimmermann 174988fabb75SThomas Zimmermann drm_mode_config_reset(dev); 1750414c4531SDave Airlie 1751414c4531SDave Airlie return 0; 1752414c4531SDave Airlie } 1753