18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright © 2006-2007 Intel Corporation
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Authors:
68c2ecf20Sopenharmony_ci *	Eric Anholt <eric@anholt.net>
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/delay.h>
108c2ecf20Sopenharmony_ci#include <linux/i2c.h>
118c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <drm/drm_crtc.h>
148c2ecf20Sopenharmony_ci#include <drm/drm_fourcc.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include "framebuffer.h"
178c2ecf20Sopenharmony_ci#include "gma_display.h"
188c2ecf20Sopenharmony_ci#include "mdfld_dsi_output.h"
198c2ecf20Sopenharmony_ci#include "mdfld_output.h"
208c2ecf20Sopenharmony_ci#include "psb_intel_reg.h"
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci/* Hardcoded currently */
238c2ecf20Sopenharmony_cistatic int ksel = KSEL_CRYSTAL_19;
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistruct psb_intel_range_t {
268c2ecf20Sopenharmony_ci	int min, max;
278c2ecf20Sopenharmony_ci};
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistruct mrst_limit_t {
308c2ecf20Sopenharmony_ci	struct psb_intel_range_t dot, m, p1;
318c2ecf20Sopenharmony_ci};
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cistruct mrst_clock_t {
348c2ecf20Sopenharmony_ci	/* derived values */
358c2ecf20Sopenharmony_ci	int dot;
368c2ecf20Sopenharmony_ci	int m;
378c2ecf20Sopenharmony_ci	int p1;
388c2ecf20Sopenharmony_ci};
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci#define COUNT_MAX 0x10000000
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_civoid mdfldWaitForPipeDisable(struct drm_device *dev, int pipe)
438c2ecf20Sopenharmony_ci{
448c2ecf20Sopenharmony_ci	struct drm_psb_private *dev_priv = dev->dev_private;
458c2ecf20Sopenharmony_ci	const struct psb_offset *map = &dev_priv->regmap[pipe];
468c2ecf20Sopenharmony_ci	int count, temp;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	switch (pipe) {
498c2ecf20Sopenharmony_ci	case 0:
508c2ecf20Sopenharmony_ci	case 1:
518c2ecf20Sopenharmony_ci	case 2:
528c2ecf20Sopenharmony_ci		break;
538c2ecf20Sopenharmony_ci	default:
548c2ecf20Sopenharmony_ci		DRM_ERROR("Illegal Pipe Number.\n");
558c2ecf20Sopenharmony_ci		return;
568c2ecf20Sopenharmony_ci	}
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	/* FIXME JLIU7_PO */
598c2ecf20Sopenharmony_ci	gma_wait_for_vblank(dev);
608c2ecf20Sopenharmony_ci	return;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	/* Wait for for the pipe disable to take effect. */
638c2ecf20Sopenharmony_ci	for (count = 0; count < COUNT_MAX; count++) {
648c2ecf20Sopenharmony_ci		temp = REG_READ(map->conf);
658c2ecf20Sopenharmony_ci		if ((temp & PIPEACONF_PIPE_STATE) == 0)
668c2ecf20Sopenharmony_ci			break;
678c2ecf20Sopenharmony_ci	}
688c2ecf20Sopenharmony_ci}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_civoid mdfldWaitForPipeEnable(struct drm_device *dev, int pipe)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	struct drm_psb_private *dev_priv = dev->dev_private;
738c2ecf20Sopenharmony_ci	const struct psb_offset *map = &dev_priv->regmap[pipe];
748c2ecf20Sopenharmony_ci	int count, temp;
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	switch (pipe) {
778c2ecf20Sopenharmony_ci	case 0:
788c2ecf20Sopenharmony_ci	case 1:
798c2ecf20Sopenharmony_ci	case 2:
808c2ecf20Sopenharmony_ci		break;
818c2ecf20Sopenharmony_ci	default:
828c2ecf20Sopenharmony_ci		DRM_ERROR("Illegal Pipe Number.\n");
838c2ecf20Sopenharmony_ci		return;
848c2ecf20Sopenharmony_ci	}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	/* FIXME JLIU7_PO */
878c2ecf20Sopenharmony_ci	gma_wait_for_vblank(dev);
888c2ecf20Sopenharmony_ci	return;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	/* Wait for for the pipe enable to take effect. */
918c2ecf20Sopenharmony_ci	for (count = 0; count < COUNT_MAX; count++) {
928c2ecf20Sopenharmony_ci		temp = REG_READ(map->conf);
938c2ecf20Sopenharmony_ci		if (temp & PIPEACONF_PIPE_STATE)
948c2ecf20Sopenharmony_ci			break;
958c2ecf20Sopenharmony_ci	}
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci/**
998c2ecf20Sopenharmony_ci * Return the pipe currently connected to the panel fitter,
1008c2ecf20Sopenharmony_ci * or -1 if the panel fitter is not present or not in use
1018c2ecf20Sopenharmony_ci */
1028c2ecf20Sopenharmony_cistatic int psb_intel_panel_fitter_pipe(struct drm_device *dev)
1038c2ecf20Sopenharmony_ci{
1048c2ecf20Sopenharmony_ci	u32 pfit_control;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	pfit_control = REG_READ(PFIT_CONTROL);
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	/* See if the panel fitter is in use */
1098c2ecf20Sopenharmony_ci	if ((pfit_control & PFIT_ENABLE) == 0)
1108c2ecf20Sopenharmony_ci		return -1;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	/* 965 can place panel fitter on either pipe */
1138c2ecf20Sopenharmony_ci	return (pfit_control >> 29) & 0x3;
1148c2ecf20Sopenharmony_ci}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_cistatic int check_fb(struct drm_framebuffer *fb)
1178c2ecf20Sopenharmony_ci{
1188c2ecf20Sopenharmony_ci	if (!fb)
1198c2ecf20Sopenharmony_ci		return 0;
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	switch (fb->format->cpp[0] * 8) {
1228c2ecf20Sopenharmony_ci	case 8:
1238c2ecf20Sopenharmony_ci	case 16:
1248c2ecf20Sopenharmony_ci	case 24:
1258c2ecf20Sopenharmony_ci	case 32:
1268c2ecf20Sopenharmony_ci		return 0;
1278c2ecf20Sopenharmony_ci	default:
1288c2ecf20Sopenharmony_ci		DRM_ERROR("Unknown color depth\n");
1298c2ecf20Sopenharmony_ci		return -EINVAL;
1308c2ecf20Sopenharmony_ci	}
1318c2ecf20Sopenharmony_ci}
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_cistatic int mdfld__intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
1348c2ecf20Sopenharmony_ci				struct drm_framebuffer *old_fb)
1358c2ecf20Sopenharmony_ci{
1368c2ecf20Sopenharmony_ci	struct drm_device *dev = crtc->dev;
1378c2ecf20Sopenharmony_ci	struct drm_psb_private *dev_priv = dev->dev_private;
1388c2ecf20Sopenharmony_ci	struct drm_framebuffer *fb = crtc->primary->fb;
1398c2ecf20Sopenharmony_ci	struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
1408c2ecf20Sopenharmony_ci	int pipe = gma_crtc->pipe;
1418c2ecf20Sopenharmony_ci	const struct psb_offset *map = &dev_priv->regmap[pipe];
1428c2ecf20Sopenharmony_ci	unsigned long start, offset;
1438c2ecf20Sopenharmony_ci	u32 dspcntr;
1448c2ecf20Sopenharmony_ci	int ret;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	dev_dbg(dev->dev, "pipe = 0x%x.\n", pipe);
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	/* no fb bound */
1498c2ecf20Sopenharmony_ci	if (!fb) {
1508c2ecf20Sopenharmony_ci		dev_dbg(dev->dev, "No FB bound\n");
1518c2ecf20Sopenharmony_ci		return 0;
1528c2ecf20Sopenharmony_ci	}
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	ret = check_fb(fb);
1558c2ecf20Sopenharmony_ci	if (ret)
1568c2ecf20Sopenharmony_ci		return ret;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	if (pipe > 2) {
1598c2ecf20Sopenharmony_ci		DRM_ERROR("Illegal Pipe Number.\n");
1608c2ecf20Sopenharmony_ci		return -EINVAL;
1618c2ecf20Sopenharmony_ci	}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	if (!gma_power_begin(dev, true))
1648c2ecf20Sopenharmony_ci		return 0;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	start = to_gtt_range(fb->obj[0])->offset;
1678c2ecf20Sopenharmony_ci	offset = y * fb->pitches[0] + x * fb->format->cpp[0];
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	REG_WRITE(map->stride, fb->pitches[0]);
1708c2ecf20Sopenharmony_ci	dspcntr = REG_READ(map->cntr);
1718c2ecf20Sopenharmony_ci	dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	switch (fb->format->cpp[0] * 8) {
1748c2ecf20Sopenharmony_ci	case 8:
1758c2ecf20Sopenharmony_ci		dspcntr |= DISPPLANE_8BPP;
1768c2ecf20Sopenharmony_ci		break;
1778c2ecf20Sopenharmony_ci	case 16:
1788c2ecf20Sopenharmony_ci		if (fb->format->depth == 15)
1798c2ecf20Sopenharmony_ci			dspcntr |= DISPPLANE_15_16BPP;
1808c2ecf20Sopenharmony_ci		else
1818c2ecf20Sopenharmony_ci			dspcntr |= DISPPLANE_16BPP;
1828c2ecf20Sopenharmony_ci		break;
1838c2ecf20Sopenharmony_ci	case 24:
1848c2ecf20Sopenharmony_ci	case 32:
1858c2ecf20Sopenharmony_ci		dspcntr |= DISPPLANE_32BPP_NO_ALPHA;
1868c2ecf20Sopenharmony_ci		break;
1878c2ecf20Sopenharmony_ci	}
1888c2ecf20Sopenharmony_ci	REG_WRITE(map->cntr, dspcntr);
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	dev_dbg(dev->dev, "Writing base %08lX %08lX %d %d\n",
1918c2ecf20Sopenharmony_ci						start, offset, x, y);
1928c2ecf20Sopenharmony_ci	REG_WRITE(map->linoff, offset);
1938c2ecf20Sopenharmony_ci	REG_READ(map->linoff);
1948c2ecf20Sopenharmony_ci	REG_WRITE(map->surf, start);
1958c2ecf20Sopenharmony_ci	REG_READ(map->surf);
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	gma_power_end(dev);
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	return 0;
2008c2ecf20Sopenharmony_ci}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci/*
2038c2ecf20Sopenharmony_ci * Disable the pipe, plane and pll.
2048c2ecf20Sopenharmony_ci *
2058c2ecf20Sopenharmony_ci */
2068c2ecf20Sopenharmony_civoid mdfld_disable_crtc(struct drm_device *dev, int pipe)
2078c2ecf20Sopenharmony_ci{
2088c2ecf20Sopenharmony_ci	struct drm_psb_private *dev_priv = dev->dev_private;
2098c2ecf20Sopenharmony_ci	const struct psb_offset *map = &dev_priv->regmap[pipe];
2108c2ecf20Sopenharmony_ci	u32 temp;
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	dev_dbg(dev->dev, "pipe = %d\n", pipe);
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	if (pipe != 1)
2168c2ecf20Sopenharmony_ci		mdfld_dsi_gen_fifo_ready(dev, MIPI_GEN_FIFO_STAT_REG(pipe),
2178c2ecf20Sopenharmony_ci				HS_CTRL_FIFO_EMPTY | HS_DATA_FIFO_EMPTY);
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	/* Disable display plane */
2208c2ecf20Sopenharmony_ci	temp = REG_READ(map->cntr);
2218c2ecf20Sopenharmony_ci	if ((temp & DISPLAY_PLANE_ENABLE) != 0) {
2228c2ecf20Sopenharmony_ci		REG_WRITE(map->cntr,
2238c2ecf20Sopenharmony_ci			  temp & ~DISPLAY_PLANE_ENABLE);
2248c2ecf20Sopenharmony_ci		/* Flush the plane changes */
2258c2ecf20Sopenharmony_ci		REG_WRITE(map->base, REG_READ(map->base));
2268c2ecf20Sopenharmony_ci		REG_READ(map->base);
2278c2ecf20Sopenharmony_ci	}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	/* FIXME_JLIU7 MDFLD_PO revisit */
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	/* Next, disable display pipes */
2328c2ecf20Sopenharmony_ci	temp = REG_READ(map->conf);
2338c2ecf20Sopenharmony_ci	if ((temp & PIPEACONF_ENABLE) != 0) {
2348c2ecf20Sopenharmony_ci		temp &= ~PIPEACONF_ENABLE;
2358c2ecf20Sopenharmony_ci		temp |= PIPECONF_PLANE_OFF | PIPECONF_CURSOR_OFF;
2368c2ecf20Sopenharmony_ci		REG_WRITE(map->conf, temp);
2378c2ecf20Sopenharmony_ci		REG_READ(map->conf);
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci		/* Wait for for the pipe disable to take effect. */
2408c2ecf20Sopenharmony_ci		mdfldWaitForPipeDisable(dev, pipe);
2418c2ecf20Sopenharmony_ci	}
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	temp = REG_READ(map->dpll);
2448c2ecf20Sopenharmony_ci	if (temp & DPLL_VCO_ENABLE) {
2458c2ecf20Sopenharmony_ci		if ((pipe != 1 &&
2468c2ecf20Sopenharmony_ci			!((REG_READ(PIPEACONF) | REG_READ(PIPECCONF))
2478c2ecf20Sopenharmony_ci				& PIPEACONF_ENABLE)) || pipe == 1) {
2488c2ecf20Sopenharmony_ci			temp &= ~(DPLL_VCO_ENABLE);
2498c2ecf20Sopenharmony_ci			REG_WRITE(map->dpll, temp);
2508c2ecf20Sopenharmony_ci			REG_READ(map->dpll);
2518c2ecf20Sopenharmony_ci			/* Wait for the clocks to turn off. */
2528c2ecf20Sopenharmony_ci			/* FIXME_MDFLD PO may need more delay */
2538c2ecf20Sopenharmony_ci			udelay(500);
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci			if (!(temp & MDFLD_PWR_GATE_EN)) {
2568c2ecf20Sopenharmony_ci				/* gating power of DPLL */
2578c2ecf20Sopenharmony_ci				REG_WRITE(map->dpll, temp | MDFLD_PWR_GATE_EN);
2588c2ecf20Sopenharmony_ci				/* FIXME_MDFLD PO - change 500 to 1 after PO */
2598c2ecf20Sopenharmony_ci				udelay(5000);
2608c2ecf20Sopenharmony_ci			}
2618c2ecf20Sopenharmony_ci		}
2628c2ecf20Sopenharmony_ci	}
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci}
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci/**
2678c2ecf20Sopenharmony_ci * Sets the power management mode of the pipe and plane.
2688c2ecf20Sopenharmony_ci *
2698c2ecf20Sopenharmony_ci * This code should probably grow support for turning the cursor off and back
2708c2ecf20Sopenharmony_ci * on appropriately at the same time as we're turning the pipe off/on.
2718c2ecf20Sopenharmony_ci */
2728c2ecf20Sopenharmony_cistatic void mdfld_crtc_dpms(struct drm_crtc *crtc, int mode)
2738c2ecf20Sopenharmony_ci{
2748c2ecf20Sopenharmony_ci	struct drm_device *dev = crtc->dev;
2758c2ecf20Sopenharmony_ci	struct drm_psb_private *dev_priv = dev->dev_private;
2768c2ecf20Sopenharmony_ci	struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
2778c2ecf20Sopenharmony_ci	int pipe = gma_crtc->pipe;
2788c2ecf20Sopenharmony_ci	const struct psb_offset *map = &dev_priv->regmap[pipe];
2798c2ecf20Sopenharmony_ci	u32 pipeconf = dev_priv->pipeconf[pipe];
2808c2ecf20Sopenharmony_ci	u32 temp;
2818c2ecf20Sopenharmony_ci	int timeout = 0;
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	dev_dbg(dev->dev, "mode = %d, pipe = %d\n", mode, pipe);
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	/* Note: Old code uses pipe a stat for pipe b but that appears
2868c2ecf20Sopenharmony_ci	   to be a bug */
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	if (!gma_power_begin(dev, true))
2898c2ecf20Sopenharmony_ci		return;
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	/* XXX: When our outputs are all unaware of DPMS modes other than off
2928c2ecf20Sopenharmony_ci	 * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC.
2938c2ecf20Sopenharmony_ci	 */
2948c2ecf20Sopenharmony_ci	switch (mode) {
2958c2ecf20Sopenharmony_ci	case DRM_MODE_DPMS_ON:
2968c2ecf20Sopenharmony_ci	case DRM_MODE_DPMS_STANDBY:
2978c2ecf20Sopenharmony_ci	case DRM_MODE_DPMS_SUSPEND:
2988c2ecf20Sopenharmony_ci		/* Enable the DPLL */
2998c2ecf20Sopenharmony_ci		temp = REG_READ(map->dpll);
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci		if ((temp & DPLL_VCO_ENABLE) == 0) {
3028c2ecf20Sopenharmony_ci			/* When ungating power of DPLL, needs to wait 0.5us
3038c2ecf20Sopenharmony_ci			   before enable the VCO */
3048c2ecf20Sopenharmony_ci			if (temp & MDFLD_PWR_GATE_EN) {
3058c2ecf20Sopenharmony_ci				temp &= ~MDFLD_PWR_GATE_EN;
3068c2ecf20Sopenharmony_ci				REG_WRITE(map->dpll, temp);
3078c2ecf20Sopenharmony_ci				/* FIXME_MDFLD PO - change 500 to 1 after PO */
3088c2ecf20Sopenharmony_ci				udelay(500);
3098c2ecf20Sopenharmony_ci			}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci			REG_WRITE(map->dpll, temp);
3128c2ecf20Sopenharmony_ci			REG_READ(map->dpll);
3138c2ecf20Sopenharmony_ci			/* FIXME_MDFLD PO - change 500 to 1 after PO */
3148c2ecf20Sopenharmony_ci			udelay(500);
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci			REG_WRITE(map->dpll, temp | DPLL_VCO_ENABLE);
3178c2ecf20Sopenharmony_ci			REG_READ(map->dpll);
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci			/**
3208c2ecf20Sopenharmony_ci			 * wait for DSI PLL to lock
3218c2ecf20Sopenharmony_ci			 * NOTE: only need to poll status of pipe 0 and pipe 1,
3228c2ecf20Sopenharmony_ci			 * since both MIPI pipes share the same PLL.
3238c2ecf20Sopenharmony_ci			 */
3248c2ecf20Sopenharmony_ci			while ((pipe != 2) && (timeout < 20000) &&
3258c2ecf20Sopenharmony_ci			  !(REG_READ(map->conf) & PIPECONF_DSIPLL_LOCK)) {
3268c2ecf20Sopenharmony_ci				udelay(150);
3278c2ecf20Sopenharmony_ci				timeout++;
3288c2ecf20Sopenharmony_ci			}
3298c2ecf20Sopenharmony_ci		}
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci		/* Enable the plane */
3328c2ecf20Sopenharmony_ci		temp = REG_READ(map->cntr);
3338c2ecf20Sopenharmony_ci		if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
3348c2ecf20Sopenharmony_ci			REG_WRITE(map->cntr,
3358c2ecf20Sopenharmony_ci				temp | DISPLAY_PLANE_ENABLE);
3368c2ecf20Sopenharmony_ci			/* Flush the plane changes */
3378c2ecf20Sopenharmony_ci			REG_WRITE(map->base, REG_READ(map->base));
3388c2ecf20Sopenharmony_ci		}
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci		/* Enable the pipe */
3418c2ecf20Sopenharmony_ci		temp = REG_READ(map->conf);
3428c2ecf20Sopenharmony_ci		if ((temp & PIPEACONF_ENABLE) == 0) {
3438c2ecf20Sopenharmony_ci			REG_WRITE(map->conf, pipeconf);
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci			/* Wait for for the pipe enable to take effect. */
3468c2ecf20Sopenharmony_ci			mdfldWaitForPipeEnable(dev, pipe);
3478c2ecf20Sopenharmony_ci		}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci		/*workaround for sighting 3741701 Random X blank display*/
3508c2ecf20Sopenharmony_ci		/*perform w/a in video mode only on pipe A or C*/
3518c2ecf20Sopenharmony_ci		if (pipe == 0 || pipe == 2) {
3528c2ecf20Sopenharmony_ci			REG_WRITE(map->status, REG_READ(map->status));
3538c2ecf20Sopenharmony_ci			msleep(100);
3548c2ecf20Sopenharmony_ci			if (PIPE_VBLANK_STATUS & REG_READ(map->status))
3558c2ecf20Sopenharmony_ci				dev_dbg(dev->dev, "OK");
3568c2ecf20Sopenharmony_ci			else {
3578c2ecf20Sopenharmony_ci				dev_dbg(dev->dev, "STUCK!!!!");
3588c2ecf20Sopenharmony_ci				/*shutdown controller*/
3598c2ecf20Sopenharmony_ci				temp = REG_READ(map->cntr);
3608c2ecf20Sopenharmony_ci				REG_WRITE(map->cntr,
3618c2ecf20Sopenharmony_ci						temp & ~DISPLAY_PLANE_ENABLE);
3628c2ecf20Sopenharmony_ci				REG_WRITE(map->base, REG_READ(map->base));
3638c2ecf20Sopenharmony_ci				/*mdfld_dsi_dpi_shut_down(dev, pipe);*/
3648c2ecf20Sopenharmony_ci				REG_WRITE(0xb048, 1);
3658c2ecf20Sopenharmony_ci				msleep(100);
3668c2ecf20Sopenharmony_ci				temp = REG_READ(map->conf);
3678c2ecf20Sopenharmony_ci				temp &= ~PIPEACONF_ENABLE;
3688c2ecf20Sopenharmony_ci				REG_WRITE(map->conf, temp);
3698c2ecf20Sopenharmony_ci				msleep(100); /*wait for pipe disable*/
3708c2ecf20Sopenharmony_ci				REG_WRITE(MIPI_DEVICE_READY_REG(pipe), 0);
3718c2ecf20Sopenharmony_ci				msleep(100);
3728c2ecf20Sopenharmony_ci				REG_WRITE(0xb004, REG_READ(0xb004));
3738c2ecf20Sopenharmony_ci				/* try to bring the controller back up again*/
3748c2ecf20Sopenharmony_ci				REG_WRITE(MIPI_DEVICE_READY_REG(pipe), 1);
3758c2ecf20Sopenharmony_ci				temp = REG_READ(map->cntr);
3768c2ecf20Sopenharmony_ci				REG_WRITE(map->cntr,
3778c2ecf20Sopenharmony_ci						temp | DISPLAY_PLANE_ENABLE);
3788c2ecf20Sopenharmony_ci				REG_WRITE(map->base, REG_READ(map->base));
3798c2ecf20Sopenharmony_ci				/*mdfld_dsi_dpi_turn_on(dev, pipe);*/
3808c2ecf20Sopenharmony_ci				REG_WRITE(0xb048, 2);
3818c2ecf20Sopenharmony_ci				msleep(100);
3828c2ecf20Sopenharmony_ci				temp = REG_READ(map->conf);
3838c2ecf20Sopenharmony_ci				temp |= PIPEACONF_ENABLE;
3848c2ecf20Sopenharmony_ci				REG_WRITE(map->conf, temp);
3858c2ecf20Sopenharmony_ci			}
3868c2ecf20Sopenharmony_ci		}
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci		gma_crtc_load_lut(crtc);
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci		/* Give the overlay scaler a chance to enable
3918c2ecf20Sopenharmony_ci		   if it's on this pipe */
3928c2ecf20Sopenharmony_ci		/* psb_intel_crtc_dpms_video(crtc, true); TODO */
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci		break;
3958c2ecf20Sopenharmony_ci	case DRM_MODE_DPMS_OFF:
3968c2ecf20Sopenharmony_ci		/* Give the overlay scaler a chance to disable
3978c2ecf20Sopenharmony_ci		 * if it's on this pipe */
3988c2ecf20Sopenharmony_ci		/* psb_intel_crtc_dpms_video(crtc, FALSE); TODO */
3998c2ecf20Sopenharmony_ci		if (pipe != 1)
4008c2ecf20Sopenharmony_ci			mdfld_dsi_gen_fifo_ready(dev,
4018c2ecf20Sopenharmony_ci				MIPI_GEN_FIFO_STAT_REG(pipe),
4028c2ecf20Sopenharmony_ci				HS_CTRL_FIFO_EMPTY | HS_DATA_FIFO_EMPTY);
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci		/* Disable the VGA plane that we never use */
4058c2ecf20Sopenharmony_ci		REG_WRITE(VGACNTRL, VGA_DISP_DISABLE);
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci		/* Disable display plane */
4088c2ecf20Sopenharmony_ci		temp = REG_READ(map->cntr);
4098c2ecf20Sopenharmony_ci		if ((temp & DISPLAY_PLANE_ENABLE) != 0) {
4108c2ecf20Sopenharmony_ci			REG_WRITE(map->cntr,
4118c2ecf20Sopenharmony_ci				  temp & ~DISPLAY_PLANE_ENABLE);
4128c2ecf20Sopenharmony_ci			/* Flush the plane changes */
4138c2ecf20Sopenharmony_ci			REG_WRITE(map->base, REG_READ(map->base));
4148c2ecf20Sopenharmony_ci			REG_READ(map->base);
4158c2ecf20Sopenharmony_ci		}
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci		/* Next, disable display pipes */
4188c2ecf20Sopenharmony_ci		temp = REG_READ(map->conf);
4198c2ecf20Sopenharmony_ci		if ((temp & PIPEACONF_ENABLE) != 0) {
4208c2ecf20Sopenharmony_ci			temp &= ~PIPEACONF_ENABLE;
4218c2ecf20Sopenharmony_ci			temp |= PIPECONF_PLANE_OFF | PIPECONF_CURSOR_OFF;
4228c2ecf20Sopenharmony_ci			REG_WRITE(map->conf, temp);
4238c2ecf20Sopenharmony_ci			REG_READ(map->conf);
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci			/* Wait for for the pipe disable to take effect. */
4268c2ecf20Sopenharmony_ci			mdfldWaitForPipeDisable(dev, pipe);
4278c2ecf20Sopenharmony_ci		}
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci		temp = REG_READ(map->dpll);
4308c2ecf20Sopenharmony_ci		if (temp & DPLL_VCO_ENABLE) {
4318c2ecf20Sopenharmony_ci			if ((pipe != 1 && !((REG_READ(PIPEACONF)
4328c2ecf20Sopenharmony_ci				| REG_READ(PIPECCONF)) & PIPEACONF_ENABLE))
4338c2ecf20Sopenharmony_ci					|| pipe == 1) {
4348c2ecf20Sopenharmony_ci				temp &= ~(DPLL_VCO_ENABLE);
4358c2ecf20Sopenharmony_ci				REG_WRITE(map->dpll, temp);
4368c2ecf20Sopenharmony_ci				REG_READ(map->dpll);
4378c2ecf20Sopenharmony_ci				/* Wait for the clocks to turn off. */
4388c2ecf20Sopenharmony_ci				/* FIXME_MDFLD PO may need more delay */
4398c2ecf20Sopenharmony_ci				udelay(500);
4408c2ecf20Sopenharmony_ci			}
4418c2ecf20Sopenharmony_ci		}
4428c2ecf20Sopenharmony_ci		break;
4438c2ecf20Sopenharmony_ci	}
4448c2ecf20Sopenharmony_ci	gma_power_end(dev);
4458c2ecf20Sopenharmony_ci}
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci#define MDFLD_LIMT_DPLL_19	    0
4498c2ecf20Sopenharmony_ci#define MDFLD_LIMT_DPLL_25	    1
4508c2ecf20Sopenharmony_ci#define MDFLD_LIMT_DPLL_83	    2
4518c2ecf20Sopenharmony_ci#define MDFLD_LIMT_DPLL_100	    3
4528c2ecf20Sopenharmony_ci#define MDFLD_LIMT_DSIPLL_19	    4
4538c2ecf20Sopenharmony_ci#define MDFLD_LIMT_DSIPLL_25	    5
4548c2ecf20Sopenharmony_ci#define MDFLD_LIMT_DSIPLL_83	    6
4558c2ecf20Sopenharmony_ci#define MDFLD_LIMT_DSIPLL_100	    7
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci#define MDFLD_DOT_MIN		  19750
4588c2ecf20Sopenharmony_ci#define MDFLD_DOT_MAX		  120000
4598c2ecf20Sopenharmony_ci#define MDFLD_DPLL_M_MIN_19	    113
4608c2ecf20Sopenharmony_ci#define MDFLD_DPLL_M_MAX_19	    155
4618c2ecf20Sopenharmony_ci#define MDFLD_DPLL_P1_MIN_19	    2
4628c2ecf20Sopenharmony_ci#define MDFLD_DPLL_P1_MAX_19	    10
4638c2ecf20Sopenharmony_ci#define MDFLD_DPLL_M_MIN_25	    101
4648c2ecf20Sopenharmony_ci#define MDFLD_DPLL_M_MAX_25	    130
4658c2ecf20Sopenharmony_ci#define MDFLD_DPLL_P1_MIN_25	    2
4668c2ecf20Sopenharmony_ci#define MDFLD_DPLL_P1_MAX_25	    10
4678c2ecf20Sopenharmony_ci#define MDFLD_DPLL_M_MIN_83	    64
4688c2ecf20Sopenharmony_ci#define MDFLD_DPLL_M_MAX_83	    64
4698c2ecf20Sopenharmony_ci#define MDFLD_DPLL_P1_MIN_83	    2
4708c2ecf20Sopenharmony_ci#define MDFLD_DPLL_P1_MAX_83	    2
4718c2ecf20Sopenharmony_ci#define MDFLD_DPLL_M_MIN_100	    64
4728c2ecf20Sopenharmony_ci#define MDFLD_DPLL_M_MAX_100	    64
4738c2ecf20Sopenharmony_ci#define MDFLD_DPLL_P1_MIN_100	    2
4748c2ecf20Sopenharmony_ci#define MDFLD_DPLL_P1_MAX_100	    2
4758c2ecf20Sopenharmony_ci#define MDFLD_DSIPLL_M_MIN_19	    131
4768c2ecf20Sopenharmony_ci#define MDFLD_DSIPLL_M_MAX_19	    175
4778c2ecf20Sopenharmony_ci#define MDFLD_DSIPLL_P1_MIN_19	    3
4788c2ecf20Sopenharmony_ci#define MDFLD_DSIPLL_P1_MAX_19	    8
4798c2ecf20Sopenharmony_ci#define MDFLD_DSIPLL_M_MIN_25	    97
4808c2ecf20Sopenharmony_ci#define MDFLD_DSIPLL_M_MAX_25	    140
4818c2ecf20Sopenharmony_ci#define MDFLD_DSIPLL_P1_MIN_25	    3
4828c2ecf20Sopenharmony_ci#define MDFLD_DSIPLL_P1_MAX_25	    9
4838c2ecf20Sopenharmony_ci#define MDFLD_DSIPLL_M_MIN_83	    33
4848c2ecf20Sopenharmony_ci#define MDFLD_DSIPLL_M_MAX_83	    92
4858c2ecf20Sopenharmony_ci#define MDFLD_DSIPLL_P1_MIN_83	    2
4868c2ecf20Sopenharmony_ci#define MDFLD_DSIPLL_P1_MAX_83	    3
4878c2ecf20Sopenharmony_ci#define MDFLD_DSIPLL_M_MIN_100	    97
4888c2ecf20Sopenharmony_ci#define MDFLD_DSIPLL_M_MAX_100	    140
4898c2ecf20Sopenharmony_ci#define MDFLD_DSIPLL_P1_MIN_100	    3
4908c2ecf20Sopenharmony_ci#define MDFLD_DSIPLL_P1_MAX_100	    9
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_cistatic const struct mrst_limit_t mdfld_limits[] = {
4938c2ecf20Sopenharmony_ci	{			/* MDFLD_LIMT_DPLL_19 */
4948c2ecf20Sopenharmony_ci	 .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX},
4958c2ecf20Sopenharmony_ci	 .m = {.min = MDFLD_DPLL_M_MIN_19, .max = MDFLD_DPLL_M_MAX_19},
4968c2ecf20Sopenharmony_ci	 .p1 = {.min = MDFLD_DPLL_P1_MIN_19, .max = MDFLD_DPLL_P1_MAX_19},
4978c2ecf20Sopenharmony_ci	 },
4988c2ecf20Sopenharmony_ci	{			/* MDFLD_LIMT_DPLL_25 */
4998c2ecf20Sopenharmony_ci	 .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX},
5008c2ecf20Sopenharmony_ci	 .m = {.min = MDFLD_DPLL_M_MIN_25, .max = MDFLD_DPLL_M_MAX_25},
5018c2ecf20Sopenharmony_ci	 .p1 = {.min = MDFLD_DPLL_P1_MIN_25, .max = MDFLD_DPLL_P1_MAX_25},
5028c2ecf20Sopenharmony_ci	 },
5038c2ecf20Sopenharmony_ci	{			/* MDFLD_LIMT_DPLL_83 */
5048c2ecf20Sopenharmony_ci	 .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX},
5058c2ecf20Sopenharmony_ci	 .m = {.min = MDFLD_DPLL_M_MIN_83, .max = MDFLD_DPLL_M_MAX_83},
5068c2ecf20Sopenharmony_ci	 .p1 = {.min = MDFLD_DPLL_P1_MIN_83, .max = MDFLD_DPLL_P1_MAX_83},
5078c2ecf20Sopenharmony_ci	 },
5088c2ecf20Sopenharmony_ci	{			/* MDFLD_LIMT_DPLL_100 */
5098c2ecf20Sopenharmony_ci	 .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX},
5108c2ecf20Sopenharmony_ci	 .m = {.min = MDFLD_DPLL_M_MIN_100, .max = MDFLD_DPLL_M_MAX_100},
5118c2ecf20Sopenharmony_ci	 .p1 = {.min = MDFLD_DPLL_P1_MIN_100, .max = MDFLD_DPLL_P1_MAX_100},
5128c2ecf20Sopenharmony_ci	 },
5138c2ecf20Sopenharmony_ci	{			/* MDFLD_LIMT_DSIPLL_19 */
5148c2ecf20Sopenharmony_ci	 .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX},
5158c2ecf20Sopenharmony_ci	 .m = {.min = MDFLD_DSIPLL_M_MIN_19, .max = MDFLD_DSIPLL_M_MAX_19},
5168c2ecf20Sopenharmony_ci	 .p1 = {.min = MDFLD_DSIPLL_P1_MIN_19, .max = MDFLD_DSIPLL_P1_MAX_19},
5178c2ecf20Sopenharmony_ci	 },
5188c2ecf20Sopenharmony_ci	{			/* MDFLD_LIMT_DSIPLL_25 */
5198c2ecf20Sopenharmony_ci	 .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX},
5208c2ecf20Sopenharmony_ci	 .m = {.min = MDFLD_DSIPLL_M_MIN_25, .max = MDFLD_DSIPLL_M_MAX_25},
5218c2ecf20Sopenharmony_ci	 .p1 = {.min = MDFLD_DSIPLL_P1_MIN_25, .max = MDFLD_DSIPLL_P1_MAX_25},
5228c2ecf20Sopenharmony_ci	 },
5238c2ecf20Sopenharmony_ci	{			/* MDFLD_LIMT_DSIPLL_83 */
5248c2ecf20Sopenharmony_ci	 .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX},
5258c2ecf20Sopenharmony_ci	 .m = {.min = MDFLD_DSIPLL_M_MIN_83, .max = MDFLD_DSIPLL_M_MAX_83},
5268c2ecf20Sopenharmony_ci	 .p1 = {.min = MDFLD_DSIPLL_P1_MIN_83, .max = MDFLD_DSIPLL_P1_MAX_83},
5278c2ecf20Sopenharmony_ci	 },
5288c2ecf20Sopenharmony_ci	{			/* MDFLD_LIMT_DSIPLL_100 */
5298c2ecf20Sopenharmony_ci	 .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX},
5308c2ecf20Sopenharmony_ci	 .m = {.min = MDFLD_DSIPLL_M_MIN_100, .max = MDFLD_DSIPLL_M_MAX_100},
5318c2ecf20Sopenharmony_ci	 .p1 = {.min = MDFLD_DSIPLL_P1_MIN_100, .max = MDFLD_DSIPLL_P1_MAX_100},
5328c2ecf20Sopenharmony_ci	 },
5338c2ecf20Sopenharmony_ci};
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci#define MDFLD_M_MIN	    21
5368c2ecf20Sopenharmony_ci#define MDFLD_M_MAX	    180
5378c2ecf20Sopenharmony_cistatic const u32 mdfld_m_converts[] = {
5388c2ecf20Sopenharmony_ci/* M configuration table from 9-bit LFSR table */
5398c2ecf20Sopenharmony_ci	224, 368, 440, 220, 366, 439, 219, 365, 182, 347, /* 21 - 30 */
5408c2ecf20Sopenharmony_ci	173, 342, 171, 85, 298, 149, 74, 37, 18, 265,   /* 31 - 40 */
5418c2ecf20Sopenharmony_ci	388, 194, 353, 432, 216, 108, 310, 155, 333, 166, /* 41 - 50 */
5428c2ecf20Sopenharmony_ci	83, 41, 276, 138, 325, 162, 337, 168, 340, 170, /* 51 - 60 */
5438c2ecf20Sopenharmony_ci	341, 426, 469, 234, 373, 442, 221, 110, 311, 411, /* 61 - 70 */
5448c2ecf20Sopenharmony_ci	461, 486, 243, 377, 188, 350, 175, 343, 427, 213, /* 71 - 80 */
5458c2ecf20Sopenharmony_ci	106, 53, 282, 397, 354, 227, 113, 56, 284, 142, /* 81 - 90 */
5468c2ecf20Sopenharmony_ci	71, 35, 273, 136, 324, 418, 465, 488, 500, 506, /* 91 - 100 */
5478c2ecf20Sopenharmony_ci	253, 126, 63, 287, 399, 455, 483, 241, 376, 444, /* 101 - 110 */
5488c2ecf20Sopenharmony_ci	478, 495, 503, 251, 381, 446, 479, 239, 375, 443, /* 111 - 120 */
5498c2ecf20Sopenharmony_ci	477, 238, 119, 315, 157, 78, 295, 147, 329, 420, /* 121 - 130 */
5508c2ecf20Sopenharmony_ci	210, 105, 308, 154, 77, 38, 275, 137, 68, 290, /* 131 - 140 */
5518c2ecf20Sopenharmony_ci	145, 328, 164, 82, 297, 404, 458, 485, 498, 249, /* 141 - 150 */
5528c2ecf20Sopenharmony_ci	380, 190, 351, 431, 471, 235, 117, 314, 413, 206, /* 151 - 160 */
5538c2ecf20Sopenharmony_ci	103, 51, 25, 12, 262, 387, 193, 96, 48, 280, /* 161 - 170 */
5548c2ecf20Sopenharmony_ci	396, 198, 99, 305, 152, 76, 294, 403, 457, 228, /* 171 - 180 */
5558c2ecf20Sopenharmony_ci};
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_cistatic const struct mrst_limit_t *mdfld_limit(struct drm_crtc *crtc)
5588c2ecf20Sopenharmony_ci{
5598c2ecf20Sopenharmony_ci	const struct mrst_limit_t *limit = NULL;
5608c2ecf20Sopenharmony_ci	struct drm_device *dev = crtc->dev;
5618c2ecf20Sopenharmony_ci	struct drm_psb_private *dev_priv = dev->dev_private;
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci	if (gma_pipe_has_type(crtc, INTEL_OUTPUT_MIPI)
5648c2ecf20Sopenharmony_ci	    || gma_pipe_has_type(crtc, INTEL_OUTPUT_MIPI2)) {
5658c2ecf20Sopenharmony_ci		if ((ksel == KSEL_CRYSTAL_19) || (ksel == KSEL_BYPASS_19))
5668c2ecf20Sopenharmony_ci			limit = &mdfld_limits[MDFLD_LIMT_DSIPLL_19];
5678c2ecf20Sopenharmony_ci		else if (ksel == KSEL_BYPASS_25)
5688c2ecf20Sopenharmony_ci			limit = &mdfld_limits[MDFLD_LIMT_DSIPLL_25];
5698c2ecf20Sopenharmony_ci		else if ((ksel == KSEL_BYPASS_83_100) &&
5708c2ecf20Sopenharmony_ci				(dev_priv->core_freq == 166))
5718c2ecf20Sopenharmony_ci			limit = &mdfld_limits[MDFLD_LIMT_DSIPLL_83];
5728c2ecf20Sopenharmony_ci		else if ((ksel == KSEL_BYPASS_83_100) &&
5738c2ecf20Sopenharmony_ci			 (dev_priv->core_freq == 100 ||
5748c2ecf20Sopenharmony_ci				dev_priv->core_freq == 200))
5758c2ecf20Sopenharmony_ci			limit = &mdfld_limits[MDFLD_LIMT_DSIPLL_100];
5768c2ecf20Sopenharmony_ci	} else if (gma_pipe_has_type(crtc, INTEL_OUTPUT_HDMI)) {
5778c2ecf20Sopenharmony_ci		if ((ksel == KSEL_CRYSTAL_19) || (ksel == KSEL_BYPASS_19))
5788c2ecf20Sopenharmony_ci			limit = &mdfld_limits[MDFLD_LIMT_DPLL_19];
5798c2ecf20Sopenharmony_ci		else if (ksel == KSEL_BYPASS_25)
5808c2ecf20Sopenharmony_ci			limit = &mdfld_limits[MDFLD_LIMT_DPLL_25];
5818c2ecf20Sopenharmony_ci		else if ((ksel == KSEL_BYPASS_83_100) &&
5828c2ecf20Sopenharmony_ci				(dev_priv->core_freq == 166))
5838c2ecf20Sopenharmony_ci			limit = &mdfld_limits[MDFLD_LIMT_DPLL_83];
5848c2ecf20Sopenharmony_ci		else if ((ksel == KSEL_BYPASS_83_100) &&
5858c2ecf20Sopenharmony_ci				 (dev_priv->core_freq == 100 ||
5868c2ecf20Sopenharmony_ci				 dev_priv->core_freq == 200))
5878c2ecf20Sopenharmony_ci			limit = &mdfld_limits[MDFLD_LIMT_DPLL_100];
5888c2ecf20Sopenharmony_ci	} else {
5898c2ecf20Sopenharmony_ci		limit = NULL;
5908c2ecf20Sopenharmony_ci		dev_dbg(dev->dev, "mdfld_limit Wrong display type.\n");
5918c2ecf20Sopenharmony_ci	}
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci	return limit;
5948c2ecf20Sopenharmony_ci}
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci/** Derive the pixel clock for the given refclk and divisors for 8xx chips. */
5978c2ecf20Sopenharmony_cistatic void mdfld_clock(int refclk, struct mrst_clock_t *clock)
5988c2ecf20Sopenharmony_ci{
5998c2ecf20Sopenharmony_ci	clock->dot = (refclk * clock->m) / clock->p1;
6008c2ecf20Sopenharmony_ci}
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci/**
6038c2ecf20Sopenharmony_ci * Returns a set of divisors for the desired target clock with the given refclk,
6048c2ecf20Sopenharmony_ci * or FALSE.  Divisor values are the actual divisors for
6058c2ecf20Sopenharmony_ci */
6068c2ecf20Sopenharmony_cistatic bool
6078c2ecf20Sopenharmony_cimdfldFindBestPLL(struct drm_crtc *crtc, int target, int refclk,
6088c2ecf20Sopenharmony_ci		struct mrst_clock_t *best_clock)
6098c2ecf20Sopenharmony_ci{
6108c2ecf20Sopenharmony_ci	struct mrst_clock_t clock;
6118c2ecf20Sopenharmony_ci	const struct mrst_limit_t *limit = mdfld_limit(crtc);
6128c2ecf20Sopenharmony_ci	int err = target;
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	memset(best_clock, 0, sizeof(*best_clock));
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci	for (clock.m = limit->m.min; clock.m <= limit->m.max; clock.m++) {
6178c2ecf20Sopenharmony_ci		for (clock.p1 = limit->p1.min; clock.p1 <= limit->p1.max;
6188c2ecf20Sopenharmony_ci		     clock.p1++) {
6198c2ecf20Sopenharmony_ci			int this_err;
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci			mdfld_clock(refclk, &clock);
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci			this_err = abs(clock.dot - target);
6248c2ecf20Sopenharmony_ci			if (this_err < err) {
6258c2ecf20Sopenharmony_ci				*best_clock = clock;
6268c2ecf20Sopenharmony_ci				err = this_err;
6278c2ecf20Sopenharmony_ci			}
6288c2ecf20Sopenharmony_ci		}
6298c2ecf20Sopenharmony_ci	}
6308c2ecf20Sopenharmony_ci	return err != target;
6318c2ecf20Sopenharmony_ci}
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_cistatic int mdfld_crtc_mode_set(struct drm_crtc *crtc,
6348c2ecf20Sopenharmony_ci			      struct drm_display_mode *mode,
6358c2ecf20Sopenharmony_ci			      struct drm_display_mode *adjusted_mode,
6368c2ecf20Sopenharmony_ci			      int x, int y,
6378c2ecf20Sopenharmony_ci			      struct drm_framebuffer *old_fb)
6388c2ecf20Sopenharmony_ci{
6398c2ecf20Sopenharmony_ci	struct drm_device *dev = crtc->dev;
6408c2ecf20Sopenharmony_ci	struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
6418c2ecf20Sopenharmony_ci	struct drm_psb_private *dev_priv = dev->dev_private;
6428c2ecf20Sopenharmony_ci	int pipe = gma_crtc->pipe;
6438c2ecf20Sopenharmony_ci	const struct psb_offset *map = &dev_priv->regmap[pipe];
6448c2ecf20Sopenharmony_ci	int refclk = 0;
6458c2ecf20Sopenharmony_ci	int clk_n = 0, clk_p2 = 0, clk_byte = 1, clk = 0, m_conv = 0,
6468c2ecf20Sopenharmony_ci								clk_tmp = 0;
6478c2ecf20Sopenharmony_ci	struct mrst_clock_t clock;
6488c2ecf20Sopenharmony_ci	bool ok;
6498c2ecf20Sopenharmony_ci	u32 dpll = 0, fp = 0;
6508c2ecf20Sopenharmony_ci	bool is_mipi = false, is_mipi2 = false, is_hdmi = false;
6518c2ecf20Sopenharmony_ci	struct drm_mode_config *mode_config = &dev->mode_config;
6528c2ecf20Sopenharmony_ci	struct gma_encoder *gma_encoder = NULL;
6538c2ecf20Sopenharmony_ci	uint64_t scalingType = DRM_MODE_SCALE_FULLSCREEN;
6548c2ecf20Sopenharmony_ci	struct drm_encoder *encoder;
6558c2ecf20Sopenharmony_ci	struct drm_connector *connector;
6568c2ecf20Sopenharmony_ci	int timeout = 0;
6578c2ecf20Sopenharmony_ci	int ret;
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci	dev_dbg(dev->dev, "pipe = 0x%x\n", pipe);
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_ci	ret = check_fb(crtc->primary->fb);
6628c2ecf20Sopenharmony_ci	if (ret)
6638c2ecf20Sopenharmony_ci		return ret;
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci	dev_dbg(dev->dev, "adjusted_hdisplay = %d\n",
6668c2ecf20Sopenharmony_ci		 adjusted_mode->hdisplay);
6678c2ecf20Sopenharmony_ci	dev_dbg(dev->dev, "adjusted_vdisplay = %d\n",
6688c2ecf20Sopenharmony_ci		 adjusted_mode->vdisplay);
6698c2ecf20Sopenharmony_ci	dev_dbg(dev->dev, "adjusted_hsync_start = %d\n",
6708c2ecf20Sopenharmony_ci		 adjusted_mode->hsync_start);
6718c2ecf20Sopenharmony_ci	dev_dbg(dev->dev, "adjusted_hsync_end = %d\n",
6728c2ecf20Sopenharmony_ci		 adjusted_mode->hsync_end);
6738c2ecf20Sopenharmony_ci	dev_dbg(dev->dev, "adjusted_htotal = %d\n",
6748c2ecf20Sopenharmony_ci		 adjusted_mode->htotal);
6758c2ecf20Sopenharmony_ci	dev_dbg(dev->dev, "adjusted_vsync_start = %d\n",
6768c2ecf20Sopenharmony_ci		 adjusted_mode->vsync_start);
6778c2ecf20Sopenharmony_ci	dev_dbg(dev->dev, "adjusted_vsync_end = %d\n",
6788c2ecf20Sopenharmony_ci		 adjusted_mode->vsync_end);
6798c2ecf20Sopenharmony_ci	dev_dbg(dev->dev, "adjusted_vtotal = %d\n",
6808c2ecf20Sopenharmony_ci		 adjusted_mode->vtotal);
6818c2ecf20Sopenharmony_ci	dev_dbg(dev->dev, "adjusted_clock = %d\n",
6828c2ecf20Sopenharmony_ci		 adjusted_mode->clock);
6838c2ecf20Sopenharmony_ci	dev_dbg(dev->dev, "hdisplay = %d\n",
6848c2ecf20Sopenharmony_ci		 mode->hdisplay);
6858c2ecf20Sopenharmony_ci	dev_dbg(dev->dev, "vdisplay = %d\n",
6868c2ecf20Sopenharmony_ci		 mode->vdisplay);
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	if (!gma_power_begin(dev, true))
6898c2ecf20Sopenharmony_ci		return 0;
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	memcpy(&gma_crtc->saved_mode, mode,
6928c2ecf20Sopenharmony_ci					sizeof(struct drm_display_mode));
6938c2ecf20Sopenharmony_ci	memcpy(&gma_crtc->saved_adjusted_mode, adjusted_mode,
6948c2ecf20Sopenharmony_ci					sizeof(struct drm_display_mode));
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	list_for_each_entry(connector, &mode_config->connector_list, head) {
6978c2ecf20Sopenharmony_ci		encoder = connector->encoder;
6988c2ecf20Sopenharmony_ci		if (!encoder)
6998c2ecf20Sopenharmony_ci			continue;
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci		if (encoder->crtc != crtc)
7028c2ecf20Sopenharmony_ci			continue;
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci		gma_encoder = gma_attached_encoder(connector);
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci		switch (gma_encoder->type) {
7078c2ecf20Sopenharmony_ci		case INTEL_OUTPUT_MIPI:
7088c2ecf20Sopenharmony_ci			is_mipi = true;
7098c2ecf20Sopenharmony_ci			break;
7108c2ecf20Sopenharmony_ci		case INTEL_OUTPUT_MIPI2:
7118c2ecf20Sopenharmony_ci			is_mipi2 = true;
7128c2ecf20Sopenharmony_ci			break;
7138c2ecf20Sopenharmony_ci		case INTEL_OUTPUT_HDMI:
7148c2ecf20Sopenharmony_ci			is_hdmi = true;
7158c2ecf20Sopenharmony_ci			break;
7168c2ecf20Sopenharmony_ci		}
7178c2ecf20Sopenharmony_ci	}
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci	/* Disable the VGA plane that we never use */
7208c2ecf20Sopenharmony_ci	REG_WRITE(VGACNTRL, VGA_DISP_DISABLE);
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci	/* Disable the panel fitter if it was on our pipe */
7238c2ecf20Sopenharmony_ci	if (psb_intel_panel_fitter_pipe(dev) == pipe)
7248c2ecf20Sopenharmony_ci		REG_WRITE(PFIT_CONTROL, 0);
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci	/* pipesrc and dspsize control the size that is scaled from,
7278c2ecf20Sopenharmony_ci	 * which should always be the user's requested size.
7288c2ecf20Sopenharmony_ci	 */
7298c2ecf20Sopenharmony_ci	if (pipe == 1) {
7308c2ecf20Sopenharmony_ci		/* FIXME: To make HDMI display with 864x480 (TPO), 480x864
7318c2ecf20Sopenharmony_ci		 * (PYR) or 480x854 (TMD), set the sprite width/height and
7328c2ecf20Sopenharmony_ci		 * souce image size registers with the adjusted mode for
7338c2ecf20Sopenharmony_ci		 * pipe B.
7348c2ecf20Sopenharmony_ci		 */
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci		/*
7378c2ecf20Sopenharmony_ci		 * The defined sprite rectangle must always be completely
7388c2ecf20Sopenharmony_ci		 * contained within the displayable area of the screen image
7398c2ecf20Sopenharmony_ci		 * (frame buffer).
7408c2ecf20Sopenharmony_ci		 */
7418c2ecf20Sopenharmony_ci		REG_WRITE(map->size, ((min(mode->crtc_vdisplay, adjusted_mode->crtc_vdisplay) - 1) << 16)
7428c2ecf20Sopenharmony_ci				| (min(mode->crtc_hdisplay, adjusted_mode->crtc_hdisplay) - 1));
7438c2ecf20Sopenharmony_ci		/* Set the CRTC with encoder mode. */
7448c2ecf20Sopenharmony_ci		REG_WRITE(map->src, ((mode->crtc_hdisplay - 1) << 16)
7458c2ecf20Sopenharmony_ci				 | (mode->crtc_vdisplay - 1));
7468c2ecf20Sopenharmony_ci	} else {
7478c2ecf20Sopenharmony_ci		REG_WRITE(map->size,
7488c2ecf20Sopenharmony_ci				((mode->crtc_vdisplay - 1) << 16) |
7498c2ecf20Sopenharmony_ci						(mode->crtc_hdisplay - 1));
7508c2ecf20Sopenharmony_ci		REG_WRITE(map->src,
7518c2ecf20Sopenharmony_ci				((mode->crtc_hdisplay - 1) << 16) |
7528c2ecf20Sopenharmony_ci						(mode->crtc_vdisplay - 1));
7538c2ecf20Sopenharmony_ci	}
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci	REG_WRITE(map->pos, 0);
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci	if (gma_encoder)
7588c2ecf20Sopenharmony_ci		drm_object_property_get_value(&connector->base,
7598c2ecf20Sopenharmony_ci			dev->mode_config.scaling_mode_property, &scalingType);
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	if (scalingType == DRM_MODE_SCALE_NO_SCALE) {
7628c2ecf20Sopenharmony_ci		/* Medfield doesn't have register support for centering so we
7638c2ecf20Sopenharmony_ci		 * need to mess with the h/vblank and h/vsync start and ends
7648c2ecf20Sopenharmony_ci		 * to get centering
7658c2ecf20Sopenharmony_ci		 */
7668c2ecf20Sopenharmony_ci		int offsetX = 0, offsetY = 0;
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci		offsetX = (adjusted_mode->crtc_hdisplay -
7698c2ecf20Sopenharmony_ci					mode->crtc_hdisplay) / 2;
7708c2ecf20Sopenharmony_ci		offsetY = (adjusted_mode->crtc_vdisplay -
7718c2ecf20Sopenharmony_ci					mode->crtc_vdisplay) / 2;
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_ci		REG_WRITE(map->htotal, (mode->crtc_hdisplay - 1) |
7748c2ecf20Sopenharmony_ci			((adjusted_mode->crtc_htotal - 1) << 16));
7758c2ecf20Sopenharmony_ci		REG_WRITE(map->vtotal, (mode->crtc_vdisplay - 1) |
7768c2ecf20Sopenharmony_ci			((adjusted_mode->crtc_vtotal - 1) << 16));
7778c2ecf20Sopenharmony_ci		REG_WRITE(map->hblank, (adjusted_mode->crtc_hblank_start -
7788c2ecf20Sopenharmony_ci								offsetX - 1) |
7798c2ecf20Sopenharmony_ci			((adjusted_mode->crtc_hblank_end - offsetX - 1) << 16));
7808c2ecf20Sopenharmony_ci		REG_WRITE(map->hsync, (adjusted_mode->crtc_hsync_start -
7818c2ecf20Sopenharmony_ci								offsetX - 1) |
7828c2ecf20Sopenharmony_ci			((adjusted_mode->crtc_hsync_end - offsetX - 1) << 16));
7838c2ecf20Sopenharmony_ci		REG_WRITE(map->vblank, (adjusted_mode->crtc_vblank_start -
7848c2ecf20Sopenharmony_ci								offsetY - 1) |
7858c2ecf20Sopenharmony_ci			((adjusted_mode->crtc_vblank_end - offsetY - 1) << 16));
7868c2ecf20Sopenharmony_ci		REG_WRITE(map->vsync, (adjusted_mode->crtc_vsync_start -
7878c2ecf20Sopenharmony_ci								offsetY - 1) |
7888c2ecf20Sopenharmony_ci			((adjusted_mode->crtc_vsync_end - offsetY - 1) << 16));
7898c2ecf20Sopenharmony_ci	} else {
7908c2ecf20Sopenharmony_ci		REG_WRITE(map->htotal, (adjusted_mode->crtc_hdisplay - 1) |
7918c2ecf20Sopenharmony_ci			((adjusted_mode->crtc_htotal - 1) << 16));
7928c2ecf20Sopenharmony_ci		REG_WRITE(map->vtotal, (adjusted_mode->crtc_vdisplay - 1) |
7938c2ecf20Sopenharmony_ci			((adjusted_mode->crtc_vtotal - 1) << 16));
7948c2ecf20Sopenharmony_ci		REG_WRITE(map->hblank, (adjusted_mode->crtc_hblank_start - 1) |
7958c2ecf20Sopenharmony_ci			((adjusted_mode->crtc_hblank_end - 1) << 16));
7968c2ecf20Sopenharmony_ci		REG_WRITE(map->hsync, (adjusted_mode->crtc_hsync_start - 1) |
7978c2ecf20Sopenharmony_ci			((adjusted_mode->crtc_hsync_end - 1) << 16));
7988c2ecf20Sopenharmony_ci		REG_WRITE(map->vblank, (adjusted_mode->crtc_vblank_start - 1) |
7998c2ecf20Sopenharmony_ci			((adjusted_mode->crtc_vblank_end - 1) << 16));
8008c2ecf20Sopenharmony_ci		REG_WRITE(map->vsync, (adjusted_mode->crtc_vsync_start - 1) |
8018c2ecf20Sopenharmony_ci			((adjusted_mode->crtc_vsync_end - 1) << 16));
8028c2ecf20Sopenharmony_ci	}
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_ci	/* Flush the plane changes */
8058c2ecf20Sopenharmony_ci	{
8068c2ecf20Sopenharmony_ci		const struct drm_crtc_helper_funcs *crtc_funcs =
8078c2ecf20Sopenharmony_ci		    crtc->helper_private;
8088c2ecf20Sopenharmony_ci		crtc_funcs->mode_set_base(crtc, x, y, old_fb);
8098c2ecf20Sopenharmony_ci	}
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci	/* setup pipeconf */
8128c2ecf20Sopenharmony_ci	dev_priv->pipeconf[pipe] = PIPEACONF_ENABLE; /* FIXME_JLIU7 REG_READ(pipeconf_reg); */
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	/* Set up the display plane register */
8158c2ecf20Sopenharmony_ci	dev_priv->dspcntr[pipe] = REG_READ(map->cntr);
8168c2ecf20Sopenharmony_ci	dev_priv->dspcntr[pipe] |= pipe << DISPPLANE_SEL_PIPE_POS;
8178c2ecf20Sopenharmony_ci	dev_priv->dspcntr[pipe] |= DISPLAY_PLANE_ENABLE;
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_ci	if (is_mipi2)
8208c2ecf20Sopenharmony_ci		goto mrst_crtc_mode_set_exit;
8218c2ecf20Sopenharmony_ci	clk = adjusted_mode->clock;
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci	if (is_hdmi) {
8248c2ecf20Sopenharmony_ci		if ((ksel == KSEL_CRYSTAL_19) || (ksel == KSEL_BYPASS_19)) {
8258c2ecf20Sopenharmony_ci			refclk = 19200;
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci			if (is_mipi || is_mipi2)
8288c2ecf20Sopenharmony_ci				clk_n = 1, clk_p2 = 8;
8298c2ecf20Sopenharmony_ci			else if (is_hdmi)
8308c2ecf20Sopenharmony_ci				clk_n = 1, clk_p2 = 10;
8318c2ecf20Sopenharmony_ci		} else if (ksel == KSEL_BYPASS_25) {
8328c2ecf20Sopenharmony_ci			refclk = 25000;
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci			if (is_mipi || is_mipi2)
8358c2ecf20Sopenharmony_ci				clk_n = 1, clk_p2 = 8;
8368c2ecf20Sopenharmony_ci			else if (is_hdmi)
8378c2ecf20Sopenharmony_ci				clk_n = 1, clk_p2 = 10;
8388c2ecf20Sopenharmony_ci		} else if ((ksel == KSEL_BYPASS_83_100) &&
8398c2ecf20Sopenharmony_ci					dev_priv->core_freq == 166) {
8408c2ecf20Sopenharmony_ci			refclk = 83000;
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci			if (is_mipi || is_mipi2)
8438c2ecf20Sopenharmony_ci				clk_n = 4, clk_p2 = 8;
8448c2ecf20Sopenharmony_ci			else if (is_hdmi)
8458c2ecf20Sopenharmony_ci				clk_n = 4, clk_p2 = 10;
8468c2ecf20Sopenharmony_ci		} else if ((ksel == KSEL_BYPASS_83_100) &&
8478c2ecf20Sopenharmony_ci					(dev_priv->core_freq == 100 ||
8488c2ecf20Sopenharmony_ci					dev_priv->core_freq == 200)) {
8498c2ecf20Sopenharmony_ci			refclk = 100000;
8508c2ecf20Sopenharmony_ci			if (is_mipi || is_mipi2)
8518c2ecf20Sopenharmony_ci				clk_n = 4, clk_p2 = 8;
8528c2ecf20Sopenharmony_ci			else if (is_hdmi)
8538c2ecf20Sopenharmony_ci				clk_n = 4, clk_p2 = 10;
8548c2ecf20Sopenharmony_ci		}
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ci		if (is_mipi)
8578c2ecf20Sopenharmony_ci			clk_byte = dev_priv->bpp / 8;
8588c2ecf20Sopenharmony_ci		else if (is_mipi2)
8598c2ecf20Sopenharmony_ci			clk_byte = dev_priv->bpp2 / 8;
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci		clk_tmp = clk * clk_n * clk_p2 * clk_byte;
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci		dev_dbg(dev->dev, "clk = %d, clk_n = %d, clk_p2 = %d.\n",
8648c2ecf20Sopenharmony_ci					clk, clk_n, clk_p2);
8658c2ecf20Sopenharmony_ci		dev_dbg(dev->dev, "adjusted_mode->clock = %d, clk_tmp = %d.\n",
8668c2ecf20Sopenharmony_ci					adjusted_mode->clock, clk_tmp);
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci		ok = mdfldFindBestPLL(crtc, clk_tmp, refclk, &clock);
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci		if (!ok) {
8718c2ecf20Sopenharmony_ci			DRM_ERROR
8728c2ecf20Sopenharmony_ci			    ("mdfldFindBestPLL fail in mdfld_crtc_mode_set.\n");
8738c2ecf20Sopenharmony_ci		} else {
8748c2ecf20Sopenharmony_ci			m_conv = mdfld_m_converts[(clock.m - MDFLD_M_MIN)];
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_ci			dev_dbg(dev->dev, "dot clock = %d,"
8778c2ecf20Sopenharmony_ci				 "m = %d, p1 = %d, m_conv = %d.\n",
8788c2ecf20Sopenharmony_ci					clock.dot, clock.m,
8798c2ecf20Sopenharmony_ci					clock.p1, m_conv);
8808c2ecf20Sopenharmony_ci		}
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci		dpll = REG_READ(map->dpll);
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci		if (dpll & DPLL_VCO_ENABLE) {
8858c2ecf20Sopenharmony_ci			dpll &= ~DPLL_VCO_ENABLE;
8868c2ecf20Sopenharmony_ci			REG_WRITE(map->dpll, dpll);
8878c2ecf20Sopenharmony_ci			REG_READ(map->dpll);
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci			/* FIXME jliu7 check the DPLL lock bit PIPEACONF[29] */
8908c2ecf20Sopenharmony_ci			/* FIXME_MDFLD PO - change 500 to 1 after PO */
8918c2ecf20Sopenharmony_ci			udelay(500);
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci			/* reset M1, N1 & P1 */
8948c2ecf20Sopenharmony_ci			REG_WRITE(map->fp0, 0);
8958c2ecf20Sopenharmony_ci			dpll &= ~MDFLD_P1_MASK;
8968c2ecf20Sopenharmony_ci			REG_WRITE(map->dpll, dpll);
8978c2ecf20Sopenharmony_ci			/* FIXME_MDFLD PO - change 500 to 1 after PO */
8988c2ecf20Sopenharmony_ci			udelay(500);
8998c2ecf20Sopenharmony_ci		}
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_ci		/* When ungating power of DPLL, needs to wait 0.5us before
9028c2ecf20Sopenharmony_ci		 * enable the VCO */
9038c2ecf20Sopenharmony_ci		if (dpll & MDFLD_PWR_GATE_EN) {
9048c2ecf20Sopenharmony_ci			dpll &= ~MDFLD_PWR_GATE_EN;
9058c2ecf20Sopenharmony_ci			REG_WRITE(map->dpll, dpll);
9068c2ecf20Sopenharmony_ci			/* FIXME_MDFLD PO - change 500 to 1 after PO */
9078c2ecf20Sopenharmony_ci			udelay(500);
9088c2ecf20Sopenharmony_ci		}
9098c2ecf20Sopenharmony_ci		dpll = 0;
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ci		if (is_hdmi)
9128c2ecf20Sopenharmony_ci			dpll |= MDFLD_VCO_SEL;
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci		fp = (clk_n / 2) << 16;
9158c2ecf20Sopenharmony_ci		fp |= m_conv;
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_ci		/* compute bitmask from p1 value */
9188c2ecf20Sopenharmony_ci		dpll |= (1 << (clock.p1 - 2)) << 17;
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ci	} else {
9218c2ecf20Sopenharmony_ci		dpll = 0x00800000;
9228c2ecf20Sopenharmony_ci		fp = 0x000000c1;
9238c2ecf20Sopenharmony_ci	}
9248c2ecf20Sopenharmony_ci
9258c2ecf20Sopenharmony_ci	REG_WRITE(map->fp0, fp);
9268c2ecf20Sopenharmony_ci	REG_WRITE(map->dpll, dpll);
9278c2ecf20Sopenharmony_ci	/* FIXME_MDFLD PO - change 500 to 1 after PO */
9288c2ecf20Sopenharmony_ci	udelay(500);
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci	dpll |= DPLL_VCO_ENABLE;
9318c2ecf20Sopenharmony_ci	REG_WRITE(map->dpll, dpll);
9328c2ecf20Sopenharmony_ci	REG_READ(map->dpll);
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ci	/* wait for DSI PLL to lock */
9358c2ecf20Sopenharmony_ci	while (timeout < 20000 &&
9368c2ecf20Sopenharmony_ci			!(REG_READ(map->conf) & PIPECONF_DSIPLL_LOCK)) {
9378c2ecf20Sopenharmony_ci		udelay(150);
9388c2ecf20Sopenharmony_ci		timeout++;
9398c2ecf20Sopenharmony_ci	}
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_ci	if (is_mipi)
9428c2ecf20Sopenharmony_ci		goto mrst_crtc_mode_set_exit;
9438c2ecf20Sopenharmony_ci
9448c2ecf20Sopenharmony_ci	dev_dbg(dev->dev, "is_mipi = 0x%x\n", is_mipi);
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_ci	REG_WRITE(map->conf, dev_priv->pipeconf[pipe]);
9478c2ecf20Sopenharmony_ci	REG_READ(map->conf);
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_ci	/* Wait for for the pipe enable to take effect. */
9508c2ecf20Sopenharmony_ci	REG_WRITE(map->cntr, dev_priv->dspcntr[pipe]);
9518c2ecf20Sopenharmony_ci	gma_wait_for_vblank(dev);
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_cimrst_crtc_mode_set_exit:
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_ci	gma_power_end(dev);
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ci	return 0;
9588c2ecf20Sopenharmony_ci}
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_ciconst struct drm_crtc_helper_funcs mdfld_helper_funcs = {
9618c2ecf20Sopenharmony_ci	.dpms = mdfld_crtc_dpms,
9628c2ecf20Sopenharmony_ci	.mode_set = mdfld_crtc_mode_set,
9638c2ecf20Sopenharmony_ci	.mode_set_base = mdfld__intel_pipe_set_base,
9648c2ecf20Sopenharmony_ci	.prepare = gma_crtc_prepare,
9658c2ecf20Sopenharmony_ci	.commit = gma_crtc_commit,
9668c2ecf20Sopenharmony_ci};
967