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