root/drivers/gpu/drm/gma500/oaktrail_crtc.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mrst_limit
  2. mrst_lvds_clock
  3. mrst_print_pll
  4. mrst_sdvo_find_best_pll
  5. mrst_lvds_find_best_pll
  6. oaktrail_crtc_dpms
  7. oaktrail_panel_fitter_pipe
  8. oaktrail_crtc_mode_set
  9. oaktrail_pipe_set_base

   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 
  36 static 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 
  40 static 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 
  44 static 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
  74 static 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 
  80 static 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. */
 111 static void mrst_lvds_clock(int refclk, struct gma_clock_t *clock)
 112 {
 113         clock->dot = (refclk * clock->m) / (14 * clock->p1);
 114 }
 115 
 116 static 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 
 123 static 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  */
 181 static 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  */
 214 static 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  */
 344 static 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 
 356 static 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 
 583 oaktrail_crtc_mode_set_exit:
 584         gma_power_end(dev);
 585         return 0;
 586 }
 587 
 588 static 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 
 645 pipe_set_base_exit:
 646         gma_power_end(dev);
 647         return ret;
 648 }
 649 
 650 const 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 */
 659 const 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 };

/* [<][>][^][v][top][bottom][index][help] */