cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

oaktrail_crtc.c (18534B)


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