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