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