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