1 /* 2 * Copyright © 2009 Intel Corporation 3 * 4 * This program is free software; you can redistribute it and/or modify it 5 * under the terms and conditions of the GNU General Public License, 6 * version 2, as published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope it will be useful, but WITHOUT 9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 * more details. 12 * 13 * You should have received a copy of the GNU General Public License along with 14 * this program; if not, write to the Free Software Foundation, Inc., 15 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 16 */ 17 18 #include <linux/i2c.h> 19 #include <linux/pm_runtime.h> 20 21 #include <drm/drmP.h> 22 #include "framebuffer.h" 23 #include "psb_drv.h" 24 #include "psb_intel_drv.h" 25 #include "psb_intel_reg.h" 26 #include "gma_display.h" 27 #include "power.h" 28 29 #define MRST_LIMIT_LVDS_100L 0 30 #define MRST_LIMIT_LVDS_83 1 31 #define MRST_LIMIT_LVDS_100 2 32 #define MRST_LIMIT_SDVO 3 33 34 #define MRST_DOT_MIN 19750 35 #define MRST_DOT_MAX 120000 36 #define MRST_M_MIN_100L 20 37 #define MRST_M_MIN_100 10 38 #define MRST_M_MIN_83 12 39 #define MRST_M_MAX_100L 34 40 #define MRST_M_MAX_100 17 41 #define MRST_M_MAX_83 20 42 #define MRST_P1_MIN 2 43 #define MRST_P1_MAX_0 7 44 #define MRST_P1_MAX_1 8 45 46 static bool mrst_lvds_find_best_pll(const struct gma_limit_t *limit, 47 struct drm_crtc *crtc, int target, 48 int refclk, struct gma_clock_t *best_clock); 49 50 static bool mrst_sdvo_find_best_pll(const struct gma_limit_t *limit, 51 struct drm_crtc *crtc, int target, 52 int refclk, struct gma_clock_t *best_clock); 53 54 static const struct gma_limit_t mrst_limits[] = { 55 { /* MRST_LIMIT_LVDS_100L */ 56 .dot = {.min = MRST_DOT_MIN, .max = MRST_DOT_MAX}, 57 .m = {.min = MRST_M_MIN_100L, .max = MRST_M_MAX_100L}, 58 .p1 = {.min = MRST_P1_MIN, .max = MRST_P1_MAX_1}, 59 .find_pll = mrst_lvds_find_best_pll, 60 }, 61 { /* MRST_LIMIT_LVDS_83L */ 62 .dot = {.min = MRST_DOT_MIN, .max = MRST_DOT_MAX}, 63 .m = {.min = MRST_M_MIN_83, .max = MRST_M_MAX_83}, 64 .p1 = {.min = MRST_P1_MIN, .max = MRST_P1_MAX_0}, 65 .find_pll = mrst_lvds_find_best_pll, 66 }, 67 { /* MRST_LIMIT_LVDS_100 */ 68 .dot = {.min = MRST_DOT_MIN, .max = MRST_DOT_MAX}, 69 .m = {.min = MRST_M_MIN_100, .max = MRST_M_MAX_100}, 70 .p1 = {.min = MRST_P1_MIN, .max = MRST_P1_MAX_1}, 71 .find_pll = mrst_lvds_find_best_pll, 72 }, 73 { /* MRST_LIMIT_SDVO */ 74 .vco = {.min = 1400000, .max = 2800000}, 75 .n = {.min = 3, .max = 7}, 76 .m = {.min = 80, .max = 137}, 77 .p1 = {.min = 1, .max = 2}, 78 .p2 = {.dot_limit = 200000, .p2_slow = 10, .p2_fast = 10}, 79 .find_pll = mrst_sdvo_find_best_pll, 80 }, 81 }; 82 83 #define MRST_M_MIN 10 84 static const u32 oaktrail_m_converts[] = { 85 0x2B, 0x15, 0x2A, 0x35, 0x1A, 0x0D, 0x26, 0x33, 0x19, 0x2C, 86 0x36, 0x3B, 0x1D, 0x2E, 0x37, 0x1B, 0x2D, 0x16, 0x0B, 0x25, 87 0x12, 0x09, 0x24, 0x32, 0x39, 0x1c, 88 }; 89 90 static const struct gma_limit_t *mrst_limit(struct drm_crtc *crtc, 91 int refclk) 92 { 93 const struct gma_limit_t *limit = NULL; 94 struct drm_device *dev = crtc->dev; 95 struct drm_psb_private *dev_priv = dev->dev_private; 96 97 if (gma_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) 98 || gma_pipe_has_type(crtc, INTEL_OUTPUT_MIPI)) { 99 switch (dev_priv->core_freq) { 100 case 100: 101 limit = &mrst_limits[MRST_LIMIT_LVDS_100L]; 102 break; 103 case 166: 104 limit = &mrst_limits[MRST_LIMIT_LVDS_83]; 105 break; 106 case 200: 107 limit = &mrst_limits[MRST_LIMIT_LVDS_100]; 108 break; 109 } 110 } else if (gma_pipe_has_type(crtc, INTEL_OUTPUT_SDVO)) { 111 limit = &mrst_limits[MRST_LIMIT_SDVO]; 112 } else { 113 limit = NULL; 114 dev_err(dev->dev, "mrst_limit Wrong display type.\n"); 115 } 116 117 return limit; 118 } 119 120 /** Derive the pixel clock for the given refclk and divisors for 8xx chips. */ 121 static void mrst_lvds_clock(int refclk, struct gma_clock_t *clock) 122 { 123 clock->dot = (refclk * clock->m) / (14 * clock->p1); 124 } 125 126 static void mrst_print_pll(struct gma_clock_t *clock) 127 { 128 DRM_DEBUG_DRIVER("dotclock=%d, m=%d, m1=%d, m2=%d, n=%d, p1=%d, p2=%d\n", 129 clock->dot, clock->m, clock->m1, clock->m2, clock->n, 130 clock->p1, clock->p2); 131 } 132 133 static bool mrst_sdvo_find_best_pll(const struct gma_limit_t *limit, 134 struct drm_crtc *crtc, int target, 135 int refclk, struct gma_clock_t *best_clock) 136 { 137 struct gma_clock_t clock; 138 u32 target_vco, actual_freq; 139 s32 freq_error, min_error = 100000; 140 141 memset(best_clock, 0, sizeof(*best_clock)); 142 143 for (clock.m = limit->m.min; clock.m <= limit->m.max; clock.m++) { 144 for (clock.n = limit->n.min; clock.n <= limit->n.max; 145 clock.n++) { 146 for (clock.p1 = limit->p1.min; 147 clock.p1 <= limit->p1.max; clock.p1++) { 148 /* p2 value always stored in p2_slow on SDVO */ 149 clock.p = clock.p1 * limit->p2.p2_slow; 150 target_vco = target * clock.p; 151 152 /* VCO will increase at this point so break */ 153 if (target_vco > limit->vco.max) 154 break; 155 156 if (target_vco < limit->vco.min) 157 continue; 158 159 actual_freq = (refclk * clock.m) / 160 (clock.n * clock.p); 161 freq_error = 10000 - 162 ((target * 10000) / actual_freq); 163 164 if (freq_error < -min_error) { 165 /* freq_error will start to decrease at 166 this point so break */ 167 break; 168 } 169 170 if (freq_error < 0) 171 freq_error = -freq_error; 172 173 if (freq_error < min_error) { 174 min_error = freq_error; 175 *best_clock = clock; 176 } 177 } 178 } 179 if (min_error == 0) 180 break; 181 } 182 183 return min_error == 0; 184 } 185 186 /** 187 * Returns a set of divisors for the desired target clock with the given refclk, 188 * or FALSE. Divisor values are the actual divisors for 189 */ 190 static bool mrst_lvds_find_best_pll(const struct gma_limit_t *limit, 191 struct drm_crtc *crtc, int target, 192 int refclk, struct gma_clock_t *best_clock) 193 { 194 struct gma_clock_t clock; 195 int err = target; 196 197 memset(best_clock, 0, sizeof(*best_clock)); 198 199 for (clock.m = limit->m.min; clock.m <= limit->m.max; clock.m++) { 200 for (clock.p1 = limit->p1.min; clock.p1 <= limit->p1.max; 201 clock.p1++) { 202 int this_err; 203 204 mrst_lvds_clock(refclk, &clock); 205 206 this_err = abs(clock.dot - target); 207 if (this_err < err) { 208 *best_clock = clock; 209 err = this_err; 210 } 211 } 212 } 213 return err != target; 214 } 215 216 /** 217 * Sets the power management mode of the pipe and plane. 218 * 219 * This code should probably grow support for turning the cursor off and back 220 * on appropriately at the same time as we're turning the pipe off/on. 221 */ 222 static void oaktrail_crtc_dpms(struct drm_crtc *crtc, int mode) 223 { 224 struct drm_device *dev = crtc->dev; 225 struct drm_psb_private *dev_priv = dev->dev_private; 226 struct gma_crtc *gma_crtc = to_gma_crtc(crtc); 227 int pipe = gma_crtc->pipe; 228 const struct psb_offset *map = &dev_priv->regmap[pipe]; 229 u32 temp; 230 int i; 231 int need_aux = gma_pipe_has_type(crtc, INTEL_OUTPUT_SDVO) ? 1 : 0; 232 233 if (gma_pipe_has_type(crtc, INTEL_OUTPUT_HDMI)) { 234 oaktrail_crtc_hdmi_dpms(crtc, mode); 235 return; 236 } 237 238 if (!gma_power_begin(dev, true)) 239 return; 240 241 /* XXX: When our outputs are all unaware of DPMS modes other than off 242 * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC. 243 */ 244 switch (mode) { 245 case DRM_MODE_DPMS_ON: 246 case DRM_MODE_DPMS_STANDBY: 247 case DRM_MODE_DPMS_SUSPEND: 248 for (i = 0; i <= need_aux; i++) { 249 /* Enable the DPLL */ 250 temp = REG_READ_WITH_AUX(map->dpll, i); 251 if ((temp & DPLL_VCO_ENABLE) == 0) { 252 REG_WRITE_WITH_AUX(map->dpll, temp, i); 253 REG_READ_WITH_AUX(map->dpll, i); 254 /* Wait for the clocks to stabilize. */ 255 udelay(150); 256 REG_WRITE_WITH_AUX(map->dpll, 257 temp | DPLL_VCO_ENABLE, i); 258 REG_READ_WITH_AUX(map->dpll, i); 259 /* Wait for the clocks to stabilize. */ 260 udelay(150); 261 REG_WRITE_WITH_AUX(map->dpll, 262 temp | DPLL_VCO_ENABLE, i); 263 REG_READ_WITH_AUX(map->dpll, i); 264 /* Wait for the clocks to stabilize. */ 265 udelay(150); 266 } 267 268 /* Enable the pipe */ 269 temp = REG_READ_WITH_AUX(map->conf, i); 270 if ((temp & PIPEACONF_ENABLE) == 0) { 271 REG_WRITE_WITH_AUX(map->conf, 272 temp | PIPEACONF_ENABLE, i); 273 } 274 275 /* Enable the plane */ 276 temp = REG_READ_WITH_AUX(map->cntr, i); 277 if ((temp & DISPLAY_PLANE_ENABLE) == 0) { 278 REG_WRITE_WITH_AUX(map->cntr, 279 temp | DISPLAY_PLANE_ENABLE, 280 i); 281 /* Flush the plane changes */ 282 REG_WRITE_WITH_AUX(map->base, 283 REG_READ_WITH_AUX(map->base, i), i); 284 } 285 286 } 287 gma_crtc_load_lut(crtc); 288 289 /* Give the overlay scaler a chance to enable 290 if it's on this pipe */ 291 /* psb_intel_crtc_dpms_video(crtc, true); TODO */ 292 break; 293 case DRM_MODE_DPMS_OFF: 294 /* Give the overlay scaler a chance to disable 295 * if it's on this pipe */ 296 /* psb_intel_crtc_dpms_video(crtc, FALSE); TODO */ 297 298 for (i = 0; i <= need_aux; i++) { 299 /* Disable the VGA plane that we never use */ 300 REG_WRITE_WITH_AUX(VGACNTRL, VGA_DISP_DISABLE, i); 301 /* Disable display plane */ 302 temp = REG_READ_WITH_AUX(map->cntr, i); 303 if ((temp & DISPLAY_PLANE_ENABLE) != 0) { 304 REG_WRITE_WITH_AUX(map->cntr, 305 temp & ~DISPLAY_PLANE_ENABLE, i); 306 /* Flush the plane changes */ 307 REG_WRITE_WITH_AUX(map->base, 308 REG_READ(map->base), i); 309 REG_READ_WITH_AUX(map->base, i); 310 } 311 312 /* Next, disable display pipes */ 313 temp = REG_READ_WITH_AUX(map->conf, i); 314 if ((temp & PIPEACONF_ENABLE) != 0) { 315 REG_WRITE_WITH_AUX(map->conf, 316 temp & ~PIPEACONF_ENABLE, i); 317 REG_READ_WITH_AUX(map->conf, i); 318 } 319 /* Wait for for the pipe disable to take effect. */ 320 gma_wait_for_vblank(dev); 321 322 temp = REG_READ_WITH_AUX(map->dpll, i); 323 if ((temp & DPLL_VCO_ENABLE) != 0) { 324 REG_WRITE_WITH_AUX(map->dpll, 325 temp & ~DPLL_VCO_ENABLE, i); 326 REG_READ_WITH_AUX(map->dpll, i); 327 } 328 329 /* Wait for the clocks to turn off. */ 330 udelay(150); 331 } 332 break; 333 } 334 335 /* Set FIFO Watermarks (values taken from EMGD) */ 336 REG_WRITE(DSPARB, 0x3f80); 337 REG_WRITE(DSPFW1, 0x3f8f0404); 338 REG_WRITE(DSPFW2, 0x04040f04); 339 REG_WRITE(DSPFW3, 0x0); 340 REG_WRITE(DSPFW4, 0x04040404); 341 REG_WRITE(DSPFW5, 0x04040404); 342 REG_WRITE(DSPFW6, 0x78); 343 REG_WRITE(DSPCHICKENBIT, REG_READ(DSPCHICKENBIT) | 0xc040); 344 345 gma_power_end(dev); 346 } 347 348 /** 349 * Return the pipe currently connected to the panel fitter, 350 * or -1 if the panel fitter is not present or not in use 351 */ 352 static int oaktrail_panel_fitter_pipe(struct drm_device *dev) 353 { 354 u32 pfit_control; 355 356 pfit_control = REG_READ(PFIT_CONTROL); 357 358 /* See if the panel fitter is in use */ 359 if ((pfit_control & PFIT_ENABLE) == 0) 360 return -1; 361 return (pfit_control >> 29) & 3; 362 } 363 364 static int oaktrail_crtc_mode_set(struct drm_crtc *crtc, 365 struct drm_display_mode *mode, 366 struct drm_display_mode *adjusted_mode, 367 int x, int y, 368 struct drm_framebuffer *old_fb) 369 { 370 struct drm_device *dev = crtc->dev; 371 struct gma_crtc *gma_crtc = to_gma_crtc(crtc); 372 struct drm_psb_private *dev_priv = dev->dev_private; 373 int pipe = gma_crtc->pipe; 374 const struct psb_offset *map = &dev_priv->regmap[pipe]; 375 int refclk = 0; 376 struct gma_clock_t clock; 377 const struct gma_limit_t *limit; 378 u32 dpll = 0, fp = 0, dspcntr, pipeconf; 379 bool ok, is_sdvo = false; 380 bool is_lvds = false; 381 bool is_mipi = false; 382 struct drm_mode_config *mode_config = &dev->mode_config; 383 struct gma_encoder *gma_encoder = NULL; 384 uint64_t scalingType = DRM_MODE_SCALE_FULLSCREEN; 385 struct drm_connector *connector; 386 int i; 387 int need_aux = gma_pipe_has_type(crtc, INTEL_OUTPUT_SDVO) ? 1 : 0; 388 389 if (gma_pipe_has_type(crtc, INTEL_OUTPUT_HDMI)) 390 return oaktrail_crtc_hdmi_mode_set(crtc, mode, adjusted_mode, x, y, old_fb); 391 392 if (!gma_power_begin(dev, true)) 393 return 0; 394 395 memcpy(&gma_crtc->saved_mode, 396 mode, 397 sizeof(struct drm_display_mode)); 398 memcpy(&gma_crtc->saved_adjusted_mode, 399 adjusted_mode, 400 sizeof(struct drm_display_mode)); 401 402 list_for_each_entry(connector, &mode_config->connector_list, head) { 403 if (!connector->encoder || connector->encoder->crtc != crtc) 404 continue; 405 406 gma_encoder = gma_attached_encoder(connector); 407 408 switch (gma_encoder->type) { 409 case INTEL_OUTPUT_LVDS: 410 is_lvds = true; 411 break; 412 case INTEL_OUTPUT_SDVO: 413 is_sdvo = true; 414 break; 415 case INTEL_OUTPUT_MIPI: 416 is_mipi = true; 417 break; 418 } 419 } 420 421 /* Disable the VGA plane that we never use */ 422 for (i = 0; i <= need_aux; i++) 423 REG_WRITE_WITH_AUX(VGACNTRL, VGA_DISP_DISABLE, i); 424 425 /* Disable the panel fitter if it was on our pipe */ 426 if (oaktrail_panel_fitter_pipe(dev) == pipe) 427 REG_WRITE(PFIT_CONTROL, 0); 428 429 for (i = 0; i <= need_aux; i++) { 430 REG_WRITE_WITH_AUX(map->src, ((mode->crtc_hdisplay - 1) << 16) | 431 (mode->crtc_vdisplay - 1), i); 432 } 433 434 if (gma_encoder) 435 drm_object_property_get_value(&connector->base, 436 dev->mode_config.scaling_mode_property, &scalingType); 437 438 if (scalingType == DRM_MODE_SCALE_NO_SCALE) { 439 /* Moorestown doesn't have register support for centering so 440 * we need to mess with the h/vblank and h/vsync start and 441 * ends to get centering */ 442 int offsetX = 0, offsetY = 0; 443 444 offsetX = (adjusted_mode->crtc_hdisplay - 445 mode->crtc_hdisplay) / 2; 446 offsetY = (adjusted_mode->crtc_vdisplay - 447 mode->crtc_vdisplay) / 2; 448 449 for (i = 0; i <= need_aux; i++) { 450 REG_WRITE_WITH_AUX(map->htotal, (mode->crtc_hdisplay - 1) | 451 ((adjusted_mode->crtc_htotal - 1) << 16), i); 452 REG_WRITE_WITH_AUX(map->vtotal, (mode->crtc_vdisplay - 1) | 453 ((adjusted_mode->crtc_vtotal - 1) << 16), i); 454 REG_WRITE_WITH_AUX(map->hblank, 455 (adjusted_mode->crtc_hblank_start - offsetX - 1) | 456 ((adjusted_mode->crtc_hblank_end - offsetX - 1) << 16), i); 457 REG_WRITE_WITH_AUX(map->hsync, 458 (adjusted_mode->crtc_hsync_start - offsetX - 1) | 459 ((adjusted_mode->crtc_hsync_end - offsetX - 1) << 16), i); 460 REG_WRITE_WITH_AUX(map->vblank, 461 (adjusted_mode->crtc_vblank_start - offsetY - 1) | 462 ((adjusted_mode->crtc_vblank_end - offsetY - 1) << 16), i); 463 REG_WRITE_WITH_AUX(map->vsync, 464 (adjusted_mode->crtc_vsync_start - offsetY - 1) | 465 ((adjusted_mode->crtc_vsync_end - offsetY - 1) << 16), i); 466 } 467 } else { 468 for (i = 0; i <= need_aux; i++) { 469 REG_WRITE_WITH_AUX(map->htotal, (adjusted_mode->crtc_hdisplay - 1) | 470 ((adjusted_mode->crtc_htotal - 1) << 16), i); 471 REG_WRITE_WITH_AUX(map->vtotal, (adjusted_mode->crtc_vdisplay - 1) | 472 ((adjusted_mode->crtc_vtotal - 1) << 16), i); 473 REG_WRITE_WITH_AUX(map->hblank, (adjusted_mode->crtc_hblank_start - 1) | 474 ((adjusted_mode->crtc_hblank_end - 1) << 16), i); 475 REG_WRITE_WITH_AUX(map->hsync, (adjusted_mode->crtc_hsync_start - 1) | 476 ((adjusted_mode->crtc_hsync_end - 1) << 16), i); 477 REG_WRITE_WITH_AUX(map->vblank, (adjusted_mode->crtc_vblank_start - 1) | 478 ((adjusted_mode->crtc_vblank_end - 1) << 16), i); 479 REG_WRITE_WITH_AUX(map->vsync, (adjusted_mode->crtc_vsync_start - 1) | 480 ((adjusted_mode->crtc_vsync_end - 1) << 16), i); 481 } 482 } 483 484 /* Flush the plane changes */ 485 { 486 const struct drm_crtc_helper_funcs *crtc_funcs = 487 crtc->helper_private; 488 crtc_funcs->mode_set_base(crtc, x, y, old_fb); 489 } 490 491 /* setup pipeconf */ 492 pipeconf = REG_READ(map->conf); 493 494 /* Set up the display plane register */ 495 dspcntr = REG_READ(map->cntr); 496 dspcntr |= DISPPLANE_GAMMA_ENABLE; 497 498 if (pipe == 0) 499 dspcntr |= DISPPLANE_SEL_PIPE_A; 500 else 501 dspcntr |= DISPPLANE_SEL_PIPE_B; 502 503 if (is_mipi) 504 goto oaktrail_crtc_mode_set_exit; 505 506 507 dpll = 0; /*BIT16 = 0 for 100MHz reference */ 508 509 refclk = is_sdvo ? 96000 : dev_priv->core_freq * 1000; 510 limit = mrst_limit(crtc, refclk); 511 ok = limit->find_pll(limit, crtc, adjusted_mode->clock, 512 refclk, &clock); 513 514 if (is_sdvo) { 515 /* Convert calculated values to register values */ 516 clock.p1 = (1L << (clock.p1 - 1)); 517 clock.m -= 2; 518 clock.n = (1L << (clock.n - 1)); 519 } 520 521 if (!ok) 522 DRM_ERROR("Failed to find proper PLL settings"); 523 524 mrst_print_pll(&clock); 525 526 if (is_sdvo) 527 fp = clock.n << 16 | clock.m; 528 else 529 fp = oaktrail_m_converts[(clock.m - MRST_M_MIN)] << 8; 530 531 dpll |= DPLL_VGA_MODE_DIS; 532 533 534 dpll |= DPLL_VCO_ENABLE; 535 536 if (is_lvds) 537 dpll |= DPLLA_MODE_LVDS; 538 else 539 dpll |= DPLLB_MODE_DAC_SERIAL; 540 541 if (is_sdvo) { 542 int sdvo_pixel_multiply = 543 adjusted_mode->clock / mode->clock; 544 545 dpll |= DPLL_DVO_HIGH_SPEED; 546 dpll |= 547 (sdvo_pixel_multiply - 548 1) << SDVO_MULTIPLIER_SHIFT_HIRES; 549 } 550 551 552 /* compute bitmask from p1 value */ 553 if (is_sdvo) 554 dpll |= clock.p1 << 16; // dpll |= (1 << (clock.p1 - 1)) << 16; 555 else 556 dpll |= (1 << (clock.p1 - 2)) << 17; 557 558 dpll |= DPLL_VCO_ENABLE; 559 560 if (dpll & DPLL_VCO_ENABLE) { 561 for (i = 0; i <= need_aux; i++) { 562 REG_WRITE_WITH_AUX(map->fp0, fp, i); 563 REG_WRITE_WITH_AUX(map->dpll, dpll & ~DPLL_VCO_ENABLE, i); 564 REG_READ_WITH_AUX(map->dpll, i); 565 /* Check the DPLLA lock bit PIPEACONF[29] */ 566 udelay(150); 567 } 568 } 569 570 for (i = 0; i <= need_aux; i++) { 571 REG_WRITE_WITH_AUX(map->fp0, fp, i); 572 REG_WRITE_WITH_AUX(map->dpll, dpll, i); 573 REG_READ_WITH_AUX(map->dpll, i); 574 /* Wait for the clocks to stabilize. */ 575 udelay(150); 576 577 /* write it again -- the BIOS does, after all */ 578 REG_WRITE_WITH_AUX(map->dpll, dpll, i); 579 REG_READ_WITH_AUX(map->dpll, i); 580 /* Wait for the clocks to stabilize. */ 581 udelay(150); 582 583 REG_WRITE_WITH_AUX(map->conf, pipeconf, i); 584 REG_READ_WITH_AUX(map->conf, i); 585 gma_wait_for_vblank(dev); 586 587 REG_WRITE_WITH_AUX(map->cntr, dspcntr, i); 588 gma_wait_for_vblank(dev); 589 } 590 591 oaktrail_crtc_mode_set_exit: 592 gma_power_end(dev); 593 return 0; 594 } 595 596 static int oaktrail_pipe_set_base(struct drm_crtc *crtc, 597 int x, int y, struct drm_framebuffer *old_fb) 598 { 599 struct drm_device *dev = crtc->dev; 600 struct drm_psb_private *dev_priv = dev->dev_private; 601 struct gma_crtc *gma_crtc = to_gma_crtc(crtc); 602 struct drm_framebuffer *fb = crtc->primary->fb; 603 struct psb_framebuffer *psbfb = to_psb_fb(fb); 604 int pipe = gma_crtc->pipe; 605 const struct psb_offset *map = &dev_priv->regmap[pipe]; 606 unsigned long start, offset; 607 608 u32 dspcntr; 609 int ret = 0; 610 611 /* no fb bound */ 612 if (!fb) { 613 dev_dbg(dev->dev, "No FB bound\n"); 614 return 0; 615 } 616 617 if (!gma_power_begin(dev, true)) 618 return 0; 619 620 start = psbfb->gtt->offset; 621 offset = y * fb->pitches[0] + x * fb->format->cpp[0]; 622 623 REG_WRITE(map->stride, fb->pitches[0]); 624 625 dspcntr = REG_READ(map->cntr); 626 dspcntr &= ~DISPPLANE_PIXFORMAT_MASK; 627 628 switch (fb->format->cpp[0] * 8) { 629 case 8: 630 dspcntr |= DISPPLANE_8BPP; 631 break; 632 case 16: 633 if (fb->format->depth == 15) 634 dspcntr |= DISPPLANE_15_16BPP; 635 else 636 dspcntr |= DISPPLANE_16BPP; 637 break; 638 case 24: 639 case 32: 640 dspcntr |= DISPPLANE_32BPP_NO_ALPHA; 641 break; 642 default: 643 dev_err(dev->dev, "Unknown color depth\n"); 644 ret = -EINVAL; 645 goto pipe_set_base_exit; 646 } 647 REG_WRITE(map->cntr, dspcntr); 648 649 REG_WRITE(map->base, offset); 650 REG_READ(map->base); 651 REG_WRITE(map->surf, start); 652 REG_READ(map->surf); 653 654 pipe_set_base_exit: 655 gma_power_end(dev); 656 return ret; 657 } 658 659 const struct drm_crtc_helper_funcs oaktrail_helper_funcs = { 660 .dpms = oaktrail_crtc_dpms, 661 .mode_set = oaktrail_crtc_mode_set, 662 .mode_set_base = oaktrail_pipe_set_base, 663 .prepare = gma_crtc_prepare, 664 .commit = gma_crtc_commit, 665 }; 666 667 /* Not used yet */ 668 const struct gma_clock_funcs mrst_clock_funcs = { 669 .clock = mrst_lvds_clock, 670 .limit = mrst_limit, 671 .pll_is_valid = gma_pll_is_valid, 672 }; 673