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