18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/**************************************************************************
38c2ecf20Sopenharmony_ci * Copyright (c) 2011, Intel Corporation.
48c2ecf20Sopenharmony_ci * All Rights Reserved.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci **************************************************************************/
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/delay.h>
98c2ecf20Sopenharmony_ci#include <linux/gpio/machine.h>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <asm/intel_scu_ipc.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include "mdfld_dsi_output.h"
148c2ecf20Sopenharmony_ci#include "mdfld_output.h"
158c2ecf20Sopenharmony_ci#include "mid_bios.h"
168c2ecf20Sopenharmony_ci#include "psb_drv.h"
178c2ecf20Sopenharmony_ci#include "tc35876x-dsi-lvds.h"
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#define MRST_BLC_MAX_PWM_REG_FREQ	    0xFFFF
228c2ecf20Sopenharmony_ci#define BLC_PWM_PRECISION_FACTOR 100	/* 10000000 */
238c2ecf20Sopenharmony_ci#define BLC_PWM_FREQ_CALC_CONSTANT 32
248c2ecf20Sopenharmony_ci#define MHz 1000000
258c2ecf20Sopenharmony_ci#define BRIGHTNESS_MIN_LEVEL 1
268c2ecf20Sopenharmony_ci#define BRIGHTNESS_MAX_LEVEL 100
278c2ecf20Sopenharmony_ci#define BRIGHTNESS_MASK	0xFF
288c2ecf20Sopenharmony_ci#define BLC_POLARITY_NORMAL 0
298c2ecf20Sopenharmony_ci#define BLC_POLARITY_INVERSE 1
308c2ecf20Sopenharmony_ci#define BLC_ADJUSTMENT_MAX 100
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#define MDFLD_BLC_PWM_PRECISION_FACTOR    10
338c2ecf20Sopenharmony_ci#define MDFLD_BLC_MAX_PWM_REG_FREQ        0xFFFE
348c2ecf20Sopenharmony_ci#define MDFLD_BLC_MIN_PWM_REG_FREQ        0x2
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci#define MDFLD_BACKLIGHT_PWM_POLARITY_BIT_CLEAR (0xFFFE)
378c2ecf20Sopenharmony_ci#define MDFLD_BACKLIGHT_PWM_CTL_SHIFT	(16)
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistatic struct backlight_device *mdfld_backlight_device;
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ciint mdfld_set_brightness(struct backlight_device *bd)
428c2ecf20Sopenharmony_ci{
438c2ecf20Sopenharmony_ci	struct drm_device *dev =
448c2ecf20Sopenharmony_ci		(struct drm_device *)bl_get_data(mdfld_backlight_device);
458c2ecf20Sopenharmony_ci	struct drm_psb_private *dev_priv = dev->dev_private;
468c2ecf20Sopenharmony_ci	int level = bd->props.brightness;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	DRM_DEBUG_DRIVER("backlight level set to %d\n", level);
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	/* Perform value bounds checking */
518c2ecf20Sopenharmony_ci	if (level < BRIGHTNESS_MIN_LEVEL)
528c2ecf20Sopenharmony_ci		level = BRIGHTNESS_MIN_LEVEL;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	if (gma_power_begin(dev, false)) {
558c2ecf20Sopenharmony_ci		u32 adjusted_level = 0;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci		/*
588c2ecf20Sopenharmony_ci		 * Adjust the backlight level with the percent in
598c2ecf20Sopenharmony_ci		 * dev_priv->blc_adj2
608c2ecf20Sopenharmony_ci		 */
618c2ecf20Sopenharmony_ci		adjusted_level = level * dev_priv->blc_adj2;
628c2ecf20Sopenharmony_ci		adjusted_level = adjusted_level / BLC_ADJUSTMENT_MAX;
638c2ecf20Sopenharmony_ci		dev_priv->brightness_adjusted = adjusted_level;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci		if (mdfld_get_panel_type(dev, 0) == TC35876X) {
668c2ecf20Sopenharmony_ci			if (dev_priv->dpi_panel_on[0] ||
678c2ecf20Sopenharmony_ci					dev_priv->dpi_panel_on[2])
688c2ecf20Sopenharmony_ci				tc35876x_brightness_control(dev,
698c2ecf20Sopenharmony_ci						dev_priv->brightness_adjusted);
708c2ecf20Sopenharmony_ci		} else {
718c2ecf20Sopenharmony_ci			if (dev_priv->dpi_panel_on[0])
728c2ecf20Sopenharmony_ci				mdfld_dsi_brightness_control(dev, 0,
738c2ecf20Sopenharmony_ci						dev_priv->brightness_adjusted);
748c2ecf20Sopenharmony_ci		}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci		if (dev_priv->dpi_panel_on[2])
778c2ecf20Sopenharmony_ci			mdfld_dsi_brightness_control(dev, 2,
788c2ecf20Sopenharmony_ci					dev_priv->brightness_adjusted);
798c2ecf20Sopenharmony_ci		gma_power_end(dev);
808c2ecf20Sopenharmony_ci	}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	/* cache the brightness for later use */
838c2ecf20Sopenharmony_ci	dev_priv->brightness = level;
848c2ecf20Sopenharmony_ci	return 0;
858c2ecf20Sopenharmony_ci}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_cistatic int mdfld_get_brightness(struct backlight_device *bd)
888c2ecf20Sopenharmony_ci{
898c2ecf20Sopenharmony_ci	struct drm_device *dev =
908c2ecf20Sopenharmony_ci		(struct drm_device *)bl_get_data(mdfld_backlight_device);
918c2ecf20Sopenharmony_ci	struct drm_psb_private *dev_priv = dev->dev_private;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	DRM_DEBUG_DRIVER("brightness = 0x%x \n", dev_priv->brightness);
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	/* return locally cached var instead of HW read (due to DPST etc.) */
968c2ecf20Sopenharmony_ci	return dev_priv->brightness;
978c2ecf20Sopenharmony_ci}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_cistatic const struct backlight_ops mdfld_ops = {
1008c2ecf20Sopenharmony_ci	.get_brightness = mdfld_get_brightness,
1018c2ecf20Sopenharmony_ci	.update_status  = mdfld_set_brightness,
1028c2ecf20Sopenharmony_ci};
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_cistatic int device_backlight_init(struct drm_device *dev)
1058c2ecf20Sopenharmony_ci{
1068c2ecf20Sopenharmony_ci	struct drm_psb_private *dev_priv = (struct drm_psb_private *)
1078c2ecf20Sopenharmony_ci		dev->dev_private;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	dev_priv->blc_adj1 = BLC_ADJUSTMENT_MAX;
1108c2ecf20Sopenharmony_ci	dev_priv->blc_adj2 = BLC_ADJUSTMENT_MAX;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	return 0;
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_cistatic int mdfld_backlight_init(struct drm_device *dev)
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci	struct backlight_properties props;
1188c2ecf20Sopenharmony_ci	int ret = 0;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	memset(&props, 0, sizeof(struct backlight_properties));
1218c2ecf20Sopenharmony_ci	props.max_brightness = BRIGHTNESS_MAX_LEVEL;
1228c2ecf20Sopenharmony_ci	props.type = BACKLIGHT_PLATFORM;
1238c2ecf20Sopenharmony_ci	mdfld_backlight_device = backlight_device_register("mdfld-bl",
1248c2ecf20Sopenharmony_ci				NULL, (void *)dev, &mdfld_ops, &props);
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	if (IS_ERR(mdfld_backlight_device))
1278c2ecf20Sopenharmony_ci		return PTR_ERR(mdfld_backlight_device);
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	ret = device_backlight_init(dev);
1308c2ecf20Sopenharmony_ci	if (ret)
1318c2ecf20Sopenharmony_ci		return ret;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	mdfld_backlight_device->props.brightness = BRIGHTNESS_MAX_LEVEL;
1348c2ecf20Sopenharmony_ci	mdfld_backlight_device->props.max_brightness = BRIGHTNESS_MAX_LEVEL;
1358c2ecf20Sopenharmony_ci	backlight_update_status(mdfld_backlight_device);
1368c2ecf20Sopenharmony_ci	return 0;
1378c2ecf20Sopenharmony_ci}
1388c2ecf20Sopenharmony_ci#endif
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_cistruct backlight_device *mdfld_get_backlight_device(void)
1418c2ecf20Sopenharmony_ci{
1428c2ecf20Sopenharmony_ci#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
1438c2ecf20Sopenharmony_ci	return mdfld_backlight_device;
1448c2ecf20Sopenharmony_ci#else
1458c2ecf20Sopenharmony_ci	return NULL;
1468c2ecf20Sopenharmony_ci#endif
1478c2ecf20Sopenharmony_ci}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci/*
1508c2ecf20Sopenharmony_ci * mdfld_save_display_registers
1518c2ecf20Sopenharmony_ci *
1528c2ecf20Sopenharmony_ci * Description: We are going to suspend so save current display
1538c2ecf20Sopenharmony_ci * register state.
1548c2ecf20Sopenharmony_ci *
1558c2ecf20Sopenharmony_ci * Notes: FIXME_JLIU7 need to add the support for DPI MIPI & HDMI audio
1568c2ecf20Sopenharmony_ci */
1578c2ecf20Sopenharmony_cistatic int mdfld_save_display_registers(struct drm_device *dev, int pipenum)
1588c2ecf20Sopenharmony_ci{
1598c2ecf20Sopenharmony_ci	struct drm_psb_private *dev_priv = dev->dev_private;
1608c2ecf20Sopenharmony_ci	struct medfield_state *regs = &dev_priv->regs.mdfld;
1618c2ecf20Sopenharmony_ci	struct psb_pipe *pipe = &dev_priv->regs.pipe[pipenum];
1628c2ecf20Sopenharmony_ci	const struct psb_offset *map = &dev_priv->regmap[pipenum];
1638c2ecf20Sopenharmony_ci	int i;
1648c2ecf20Sopenharmony_ci	u32 *mipi_val;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	/* register */
1678c2ecf20Sopenharmony_ci	u32 mipi_reg = MIPI;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	switch (pipenum) {
1708c2ecf20Sopenharmony_ci	case 0:
1718c2ecf20Sopenharmony_ci		mipi_val = &regs->saveMIPI;
1728c2ecf20Sopenharmony_ci		break;
1738c2ecf20Sopenharmony_ci	case 1:
1748c2ecf20Sopenharmony_ci		mipi_val = &regs->saveMIPI;
1758c2ecf20Sopenharmony_ci		break;
1768c2ecf20Sopenharmony_ci	case 2:
1778c2ecf20Sopenharmony_ci		/* register */
1788c2ecf20Sopenharmony_ci		mipi_reg = MIPI_C;
1798c2ecf20Sopenharmony_ci		/* pointer to values */
1808c2ecf20Sopenharmony_ci		mipi_val = &regs->saveMIPI_C;
1818c2ecf20Sopenharmony_ci		break;
1828c2ecf20Sopenharmony_ci	default:
1838c2ecf20Sopenharmony_ci		DRM_ERROR("%s, invalid pipe number.\n", __func__);
1848c2ecf20Sopenharmony_ci		return -EINVAL;
1858c2ecf20Sopenharmony_ci	}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	/* Pipe & plane A info */
1888c2ecf20Sopenharmony_ci	pipe->dpll = PSB_RVDC32(map->dpll);
1898c2ecf20Sopenharmony_ci	pipe->fp0 = PSB_RVDC32(map->fp0);
1908c2ecf20Sopenharmony_ci	pipe->conf = PSB_RVDC32(map->conf);
1918c2ecf20Sopenharmony_ci	pipe->htotal = PSB_RVDC32(map->htotal);
1928c2ecf20Sopenharmony_ci	pipe->hblank = PSB_RVDC32(map->hblank);
1938c2ecf20Sopenharmony_ci	pipe->hsync = PSB_RVDC32(map->hsync);
1948c2ecf20Sopenharmony_ci	pipe->vtotal = PSB_RVDC32(map->vtotal);
1958c2ecf20Sopenharmony_ci	pipe->vblank = PSB_RVDC32(map->vblank);
1968c2ecf20Sopenharmony_ci	pipe->vsync = PSB_RVDC32(map->vsync);
1978c2ecf20Sopenharmony_ci	pipe->src = PSB_RVDC32(map->src);
1988c2ecf20Sopenharmony_ci	pipe->stride = PSB_RVDC32(map->stride);
1998c2ecf20Sopenharmony_ci	pipe->linoff = PSB_RVDC32(map->linoff);
2008c2ecf20Sopenharmony_ci	pipe->tileoff = PSB_RVDC32(map->tileoff);
2018c2ecf20Sopenharmony_ci	pipe->size = PSB_RVDC32(map->size);
2028c2ecf20Sopenharmony_ci	pipe->pos = PSB_RVDC32(map->pos);
2038c2ecf20Sopenharmony_ci	pipe->surf = PSB_RVDC32(map->surf);
2048c2ecf20Sopenharmony_ci	pipe->cntr = PSB_RVDC32(map->cntr);
2058c2ecf20Sopenharmony_ci	pipe->status = PSB_RVDC32(map->status);
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	/*save palette (gamma) */
2088c2ecf20Sopenharmony_ci	for (i = 0; i < 256; i++)
2098c2ecf20Sopenharmony_ci		pipe->palette[i] = PSB_RVDC32(map->palette + (i << 2));
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	if (pipenum == 1) {
2128c2ecf20Sopenharmony_ci		regs->savePFIT_CONTROL = PSB_RVDC32(PFIT_CONTROL);
2138c2ecf20Sopenharmony_ci		regs->savePFIT_PGM_RATIOS = PSB_RVDC32(PFIT_PGM_RATIOS);
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci		regs->saveHDMIPHYMISCCTL = PSB_RVDC32(HDMIPHYMISCCTL);
2168c2ecf20Sopenharmony_ci		regs->saveHDMIB_CONTROL = PSB_RVDC32(HDMIB_CONTROL);
2178c2ecf20Sopenharmony_ci		return 0;
2188c2ecf20Sopenharmony_ci	}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	*mipi_val = PSB_RVDC32(mipi_reg);
2218c2ecf20Sopenharmony_ci	return 0;
2228c2ecf20Sopenharmony_ci}
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci/*
2258c2ecf20Sopenharmony_ci * mdfld_restore_display_registers
2268c2ecf20Sopenharmony_ci *
2278c2ecf20Sopenharmony_ci * Description: We are going to resume so restore display register state.
2288c2ecf20Sopenharmony_ci *
2298c2ecf20Sopenharmony_ci * Notes: FIXME_JLIU7 need to add the support for DPI MIPI & HDMI audio
2308c2ecf20Sopenharmony_ci */
2318c2ecf20Sopenharmony_cistatic int mdfld_restore_display_registers(struct drm_device *dev, int pipenum)
2328c2ecf20Sopenharmony_ci{
2338c2ecf20Sopenharmony_ci	/* To get  panel out of ULPS mode. */
2348c2ecf20Sopenharmony_ci	u32 temp = 0;
2358c2ecf20Sopenharmony_ci	u32 device_ready_reg = DEVICE_READY_REG;
2368c2ecf20Sopenharmony_ci	struct drm_psb_private *dev_priv = dev->dev_private;
2378c2ecf20Sopenharmony_ci	struct mdfld_dsi_config *dsi_config = NULL;
2388c2ecf20Sopenharmony_ci	struct medfield_state *regs = &dev_priv->regs.mdfld;
2398c2ecf20Sopenharmony_ci	struct psb_pipe *pipe = &dev_priv->regs.pipe[pipenum];
2408c2ecf20Sopenharmony_ci	const struct psb_offset *map = &dev_priv->regmap[pipenum];
2418c2ecf20Sopenharmony_ci	u32 i;
2428c2ecf20Sopenharmony_ci	u32 dpll;
2438c2ecf20Sopenharmony_ci	u32 timeout = 0;
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	/* register */
2468c2ecf20Sopenharmony_ci	u32 mipi_reg = MIPI;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	/* values */
2498c2ecf20Sopenharmony_ci	u32 dpll_val = pipe->dpll;
2508c2ecf20Sopenharmony_ci	u32 mipi_val = regs->saveMIPI;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	switch (pipenum) {
2538c2ecf20Sopenharmony_ci	case 0:
2548c2ecf20Sopenharmony_ci		dpll_val &= ~DPLL_VCO_ENABLE;
2558c2ecf20Sopenharmony_ci		dsi_config = dev_priv->dsi_configs[0];
2568c2ecf20Sopenharmony_ci		break;
2578c2ecf20Sopenharmony_ci	case 1:
2588c2ecf20Sopenharmony_ci		dpll_val &= ~DPLL_VCO_ENABLE;
2598c2ecf20Sopenharmony_ci		break;
2608c2ecf20Sopenharmony_ci	case 2:
2618c2ecf20Sopenharmony_ci		mipi_reg = MIPI_C;
2628c2ecf20Sopenharmony_ci		mipi_val = regs->saveMIPI_C;
2638c2ecf20Sopenharmony_ci		dsi_config = dev_priv->dsi_configs[1];
2648c2ecf20Sopenharmony_ci		break;
2658c2ecf20Sopenharmony_ci	default:
2668c2ecf20Sopenharmony_ci		DRM_ERROR("%s, invalid pipe number.\n", __func__);
2678c2ecf20Sopenharmony_ci		return -EINVAL;
2688c2ecf20Sopenharmony_ci	}
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	/*make sure VGA plane is off. it initializes to on after reset!*/
2718c2ecf20Sopenharmony_ci	PSB_WVDC32(0x80000000, VGACNTRL);
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	if (pipenum == 1) {
2748c2ecf20Sopenharmony_ci		PSB_WVDC32(dpll_val & ~DPLL_VCO_ENABLE, map->dpll);
2758c2ecf20Sopenharmony_ci		PSB_RVDC32(map->dpll);
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci		PSB_WVDC32(pipe->fp0, map->fp0);
2788c2ecf20Sopenharmony_ci	} else {
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci		dpll = PSB_RVDC32(map->dpll);
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci		if (!(dpll & DPLL_VCO_ENABLE)) {
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci			/* When ungating power of DPLL, needs to wait 0.5us
2858c2ecf20Sopenharmony_ci			   before enable the VCO */
2868c2ecf20Sopenharmony_ci			if (dpll & MDFLD_PWR_GATE_EN) {
2878c2ecf20Sopenharmony_ci				dpll &= ~MDFLD_PWR_GATE_EN;
2888c2ecf20Sopenharmony_ci				PSB_WVDC32(dpll, map->dpll);
2898c2ecf20Sopenharmony_ci				/* FIXME_MDFLD PO - change 500 to 1 after PO */
2908c2ecf20Sopenharmony_ci				udelay(500);
2918c2ecf20Sopenharmony_ci			}
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci			PSB_WVDC32(pipe->fp0, map->fp0);
2948c2ecf20Sopenharmony_ci			PSB_WVDC32(dpll_val, map->dpll);
2958c2ecf20Sopenharmony_ci			/* FIXME_MDFLD PO - change 500 to 1 after PO */
2968c2ecf20Sopenharmony_ci			udelay(500);
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci			dpll_val |= DPLL_VCO_ENABLE;
2998c2ecf20Sopenharmony_ci			PSB_WVDC32(dpll_val, map->dpll);
3008c2ecf20Sopenharmony_ci			PSB_RVDC32(map->dpll);
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci			/* wait for DSI PLL to lock */
3038c2ecf20Sopenharmony_ci			while (timeout < 20000 &&
3048c2ecf20Sopenharmony_ci			  !(PSB_RVDC32(map->conf) & PIPECONF_DSIPLL_LOCK)) {
3058c2ecf20Sopenharmony_ci				udelay(150);
3068c2ecf20Sopenharmony_ci				timeout++;
3078c2ecf20Sopenharmony_ci			}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci			if (timeout == 20000) {
3108c2ecf20Sopenharmony_ci				DRM_ERROR("%s, can't lock DSIPLL.\n",
3118c2ecf20Sopenharmony_ci								__func__);
3128c2ecf20Sopenharmony_ci				return -EINVAL;
3138c2ecf20Sopenharmony_ci			}
3148c2ecf20Sopenharmony_ci		}
3158c2ecf20Sopenharmony_ci	}
3168c2ecf20Sopenharmony_ci	/* Restore mode */
3178c2ecf20Sopenharmony_ci	PSB_WVDC32(pipe->htotal, map->htotal);
3188c2ecf20Sopenharmony_ci	PSB_WVDC32(pipe->hblank, map->hblank);
3198c2ecf20Sopenharmony_ci	PSB_WVDC32(pipe->hsync, map->hsync);
3208c2ecf20Sopenharmony_ci	PSB_WVDC32(pipe->vtotal, map->vtotal);
3218c2ecf20Sopenharmony_ci	PSB_WVDC32(pipe->vblank, map->vblank);
3228c2ecf20Sopenharmony_ci	PSB_WVDC32(pipe->vsync, map->vsync);
3238c2ecf20Sopenharmony_ci	PSB_WVDC32(pipe->src, map->src);
3248c2ecf20Sopenharmony_ci	PSB_WVDC32(pipe->status, map->status);
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	/*set up the plane*/
3278c2ecf20Sopenharmony_ci	PSB_WVDC32(pipe->stride, map->stride);
3288c2ecf20Sopenharmony_ci	PSB_WVDC32(pipe->linoff, map->linoff);
3298c2ecf20Sopenharmony_ci	PSB_WVDC32(pipe->tileoff, map->tileoff);
3308c2ecf20Sopenharmony_ci	PSB_WVDC32(pipe->size, map->size);
3318c2ecf20Sopenharmony_ci	PSB_WVDC32(pipe->pos, map->pos);
3328c2ecf20Sopenharmony_ci	PSB_WVDC32(pipe->surf, map->surf);
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	if (pipenum == 1) {
3358c2ecf20Sopenharmony_ci		/* restore palette (gamma) */
3368c2ecf20Sopenharmony_ci		/* udelay(50000); */
3378c2ecf20Sopenharmony_ci		for (i = 0; i < 256; i++)
3388c2ecf20Sopenharmony_ci			PSB_WVDC32(pipe->palette[i], map->palette + (i << 2));
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci		PSB_WVDC32(regs->savePFIT_CONTROL, PFIT_CONTROL);
3418c2ecf20Sopenharmony_ci		PSB_WVDC32(regs->savePFIT_PGM_RATIOS, PFIT_PGM_RATIOS);
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci		/*TODO: resume HDMI port */
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci		/*TODO: resume pipe*/
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci		/*enable the plane*/
3488c2ecf20Sopenharmony_ci		PSB_WVDC32(pipe->cntr & ~DISPLAY_PLANE_ENABLE, map->cntr);
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci		return 0;
3518c2ecf20Sopenharmony_ci	}
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	/*set up pipe related registers*/
3548c2ecf20Sopenharmony_ci	PSB_WVDC32(mipi_val, mipi_reg);
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	/*setup MIPI adapter + MIPI IP registers*/
3578c2ecf20Sopenharmony_ci	if (dsi_config)
3588c2ecf20Sopenharmony_ci		mdfld_dsi_controller_init(dsi_config, pipenum);
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	if (in_atomic() || in_interrupt())
3618c2ecf20Sopenharmony_ci		mdelay(20);
3628c2ecf20Sopenharmony_ci	else
3638c2ecf20Sopenharmony_ci		msleep(20);
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	/*enable the plane*/
3668c2ecf20Sopenharmony_ci	PSB_WVDC32(pipe->cntr, map->cntr);
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	if (in_atomic() || in_interrupt())
3698c2ecf20Sopenharmony_ci		mdelay(20);
3708c2ecf20Sopenharmony_ci	else
3718c2ecf20Sopenharmony_ci		msleep(20);
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	/* LP Hold Release */
3748c2ecf20Sopenharmony_ci	temp = REG_READ(mipi_reg);
3758c2ecf20Sopenharmony_ci	temp |= LP_OUTPUT_HOLD_RELEASE;
3768c2ecf20Sopenharmony_ci	REG_WRITE(mipi_reg, temp);
3778c2ecf20Sopenharmony_ci	mdelay(1);
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	/* Set DSI host to exit from Utra Low Power State */
3818c2ecf20Sopenharmony_ci	temp = REG_READ(device_ready_reg);
3828c2ecf20Sopenharmony_ci	temp &= ~ULPS_MASK;
3838c2ecf20Sopenharmony_ci	temp |= 0x3;
3848c2ecf20Sopenharmony_ci	temp |= EXIT_ULPS_DEV_READY;
3858c2ecf20Sopenharmony_ci	REG_WRITE(device_ready_reg, temp);
3868c2ecf20Sopenharmony_ci	mdelay(1);
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	temp = REG_READ(device_ready_reg);
3898c2ecf20Sopenharmony_ci	temp &= ~ULPS_MASK;
3908c2ecf20Sopenharmony_ci	temp |= EXITING_ULPS;
3918c2ecf20Sopenharmony_ci	REG_WRITE(device_ready_reg, temp);
3928c2ecf20Sopenharmony_ci	mdelay(1);
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	/*enable the pipe*/
3958c2ecf20Sopenharmony_ci	PSB_WVDC32(pipe->conf, map->conf);
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	/* restore palette (gamma) */
3988c2ecf20Sopenharmony_ci	/* udelay(50000); */
3998c2ecf20Sopenharmony_ci	for (i = 0; i < 256; i++)
4008c2ecf20Sopenharmony_ci		PSB_WVDC32(pipe->palette[i], map->palette + (i << 2));
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	return 0;
4038c2ecf20Sopenharmony_ci}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_cistatic int mdfld_save_registers(struct drm_device *dev)
4068c2ecf20Sopenharmony_ci{
4078c2ecf20Sopenharmony_ci	/* mdfld_save_cursor_overlay_registers(dev); */
4088c2ecf20Sopenharmony_ci	mdfld_save_display_registers(dev, 0);
4098c2ecf20Sopenharmony_ci	mdfld_save_display_registers(dev, 2);
4108c2ecf20Sopenharmony_ci	mdfld_disable_crtc(dev, 0);
4118c2ecf20Sopenharmony_ci	mdfld_disable_crtc(dev, 2);
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	return 0;
4148c2ecf20Sopenharmony_ci}
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_cistatic int mdfld_restore_registers(struct drm_device *dev)
4178c2ecf20Sopenharmony_ci{
4188c2ecf20Sopenharmony_ci	mdfld_restore_display_registers(dev, 2);
4198c2ecf20Sopenharmony_ci	mdfld_restore_display_registers(dev, 0);
4208c2ecf20Sopenharmony_ci	/* mdfld_restore_cursor_overlay_registers(dev); */
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	return 0;
4238c2ecf20Sopenharmony_ci}
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_cistatic int mdfld_power_down(struct drm_device *dev)
4268c2ecf20Sopenharmony_ci{
4278c2ecf20Sopenharmony_ci	/* FIXME */
4288c2ecf20Sopenharmony_ci	return 0;
4298c2ecf20Sopenharmony_ci}
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_cistatic int mdfld_power_up(struct drm_device *dev)
4328c2ecf20Sopenharmony_ci{
4338c2ecf20Sopenharmony_ci	/* FIXME */
4348c2ecf20Sopenharmony_ci	return 0;
4358c2ecf20Sopenharmony_ci}
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci/* Medfield  */
4388c2ecf20Sopenharmony_cistatic const struct psb_offset mdfld_regmap[3] = {
4398c2ecf20Sopenharmony_ci	{
4408c2ecf20Sopenharmony_ci		.fp0 = MRST_FPA0,
4418c2ecf20Sopenharmony_ci		.fp1 = MRST_FPA1,
4428c2ecf20Sopenharmony_ci		.cntr = DSPACNTR,
4438c2ecf20Sopenharmony_ci		.conf = PIPEACONF,
4448c2ecf20Sopenharmony_ci		.src = PIPEASRC,
4458c2ecf20Sopenharmony_ci		.dpll = MRST_DPLL_A,
4468c2ecf20Sopenharmony_ci		.htotal = HTOTAL_A,
4478c2ecf20Sopenharmony_ci		.hblank = HBLANK_A,
4488c2ecf20Sopenharmony_ci		.hsync = HSYNC_A,
4498c2ecf20Sopenharmony_ci		.vtotal = VTOTAL_A,
4508c2ecf20Sopenharmony_ci		.vblank = VBLANK_A,
4518c2ecf20Sopenharmony_ci		.vsync = VSYNC_A,
4528c2ecf20Sopenharmony_ci		.stride = DSPASTRIDE,
4538c2ecf20Sopenharmony_ci		.size = DSPASIZE,
4548c2ecf20Sopenharmony_ci		.pos = DSPAPOS,
4558c2ecf20Sopenharmony_ci		.surf = DSPASURF,
4568c2ecf20Sopenharmony_ci		.addr = MRST_DSPABASE,
4578c2ecf20Sopenharmony_ci		.status = PIPEASTAT,
4588c2ecf20Sopenharmony_ci		.linoff = DSPALINOFF,
4598c2ecf20Sopenharmony_ci		.tileoff = DSPATILEOFF,
4608c2ecf20Sopenharmony_ci		.palette = PALETTE_A,
4618c2ecf20Sopenharmony_ci	},
4628c2ecf20Sopenharmony_ci	{
4638c2ecf20Sopenharmony_ci		.fp0 = MDFLD_DPLL_DIV0,
4648c2ecf20Sopenharmony_ci		.cntr = DSPBCNTR,
4658c2ecf20Sopenharmony_ci		.conf = PIPEBCONF,
4668c2ecf20Sopenharmony_ci		.src = PIPEBSRC,
4678c2ecf20Sopenharmony_ci		.dpll = MDFLD_DPLL_B,
4688c2ecf20Sopenharmony_ci		.htotal = HTOTAL_B,
4698c2ecf20Sopenharmony_ci		.hblank = HBLANK_B,
4708c2ecf20Sopenharmony_ci		.hsync = HSYNC_B,
4718c2ecf20Sopenharmony_ci		.vtotal = VTOTAL_B,
4728c2ecf20Sopenharmony_ci		.vblank = VBLANK_B,
4738c2ecf20Sopenharmony_ci		.vsync = VSYNC_B,
4748c2ecf20Sopenharmony_ci		.stride = DSPBSTRIDE,
4758c2ecf20Sopenharmony_ci		.size = DSPBSIZE,
4768c2ecf20Sopenharmony_ci		.pos = DSPBPOS,
4778c2ecf20Sopenharmony_ci		.surf = DSPBSURF,
4788c2ecf20Sopenharmony_ci		.addr = MRST_DSPBBASE,
4798c2ecf20Sopenharmony_ci		.status = PIPEBSTAT,
4808c2ecf20Sopenharmony_ci		.linoff = DSPBLINOFF,
4818c2ecf20Sopenharmony_ci		.tileoff = DSPBTILEOFF,
4828c2ecf20Sopenharmony_ci		.palette = PALETTE_B,
4838c2ecf20Sopenharmony_ci	},
4848c2ecf20Sopenharmony_ci	{
4858c2ecf20Sopenharmony_ci		.fp0 = MRST_FPA0,	/* This is what the old code did ?? */
4868c2ecf20Sopenharmony_ci		.cntr = DSPCCNTR,
4878c2ecf20Sopenharmony_ci		.conf = PIPECCONF,
4888c2ecf20Sopenharmony_ci		.src = PIPECSRC,
4898c2ecf20Sopenharmony_ci		/* No DPLL_C */
4908c2ecf20Sopenharmony_ci		.dpll = MRST_DPLL_A,
4918c2ecf20Sopenharmony_ci		.htotal = HTOTAL_C,
4928c2ecf20Sopenharmony_ci		.hblank = HBLANK_C,
4938c2ecf20Sopenharmony_ci		.hsync = HSYNC_C,
4948c2ecf20Sopenharmony_ci		.vtotal = VTOTAL_C,
4958c2ecf20Sopenharmony_ci		.vblank = VBLANK_C,
4968c2ecf20Sopenharmony_ci		.vsync = VSYNC_C,
4978c2ecf20Sopenharmony_ci		.stride = DSPCSTRIDE,
4988c2ecf20Sopenharmony_ci		.size = DSPBSIZE,
4998c2ecf20Sopenharmony_ci		.pos = DSPCPOS,
5008c2ecf20Sopenharmony_ci		.surf = DSPCSURF,
5018c2ecf20Sopenharmony_ci		.addr = MDFLD_DSPCBASE,
5028c2ecf20Sopenharmony_ci		.status = PIPECSTAT,
5038c2ecf20Sopenharmony_ci		.linoff = DSPCLINOFF,
5048c2ecf20Sopenharmony_ci		.tileoff = DSPCTILEOFF,
5058c2ecf20Sopenharmony_ci		.palette = PALETTE_C,
5068c2ecf20Sopenharmony_ci	},
5078c2ecf20Sopenharmony_ci};
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci/*
5108c2ecf20Sopenharmony_ci * The GPIO lines for resetting DSI pipe 0 and 2 are available in the
5118c2ecf20Sopenharmony_ci * PCI device 0000:00:0c.0 on the Medfield.
5128c2ecf20Sopenharmony_ci */
5138c2ecf20Sopenharmony_cistatic struct gpiod_lookup_table mdfld_dsi_pipe_gpio_table = {
5148c2ecf20Sopenharmony_ci	.table  = {
5158c2ecf20Sopenharmony_ci		GPIO_LOOKUP("0000:00:0c.0", 128, "dsi-pipe0-reset",
5168c2ecf20Sopenharmony_ci			    GPIO_ACTIVE_HIGH),
5178c2ecf20Sopenharmony_ci		GPIO_LOOKUP("0000:00:0c.0", 34, "dsi-pipe2-reset",
5188c2ecf20Sopenharmony_ci			    GPIO_ACTIVE_HIGH),
5198c2ecf20Sopenharmony_ci		{ },
5208c2ecf20Sopenharmony_ci	},
5218c2ecf20Sopenharmony_ci};
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_cistatic int mdfld_chip_setup(struct drm_device *dev)
5248c2ecf20Sopenharmony_ci{
5258c2ecf20Sopenharmony_ci	struct drm_psb_private *dev_priv = dev->dev_private;
5268c2ecf20Sopenharmony_ci	if (pci_enable_msi(dev->pdev))
5278c2ecf20Sopenharmony_ci		dev_warn(dev->dev, "Enabling MSI failed!\n");
5288c2ecf20Sopenharmony_ci	dev_priv->regmap = mdfld_regmap;
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci	/* Associate the GPIO lines with the DRM device */
5318c2ecf20Sopenharmony_ci	mdfld_dsi_pipe_gpio_table.dev_id = dev_name(dev->dev);
5328c2ecf20Sopenharmony_ci	gpiod_add_lookup_table(&mdfld_dsi_pipe_gpio_table);
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	return mid_chip_setup(dev);
5358c2ecf20Sopenharmony_ci}
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ciconst struct psb_ops mdfld_chip_ops = {
5388c2ecf20Sopenharmony_ci	.name = "mdfld",
5398c2ecf20Sopenharmony_ci	.accel_2d = 0,
5408c2ecf20Sopenharmony_ci	.pipes = 3,
5418c2ecf20Sopenharmony_ci	.crtcs = 3,
5428c2ecf20Sopenharmony_ci	.lvds_mask = (1 << 1),
5438c2ecf20Sopenharmony_ci	.hdmi_mask = (1 << 1),
5448c2ecf20Sopenharmony_ci	.cursor_needs_phys = 0,
5458c2ecf20Sopenharmony_ci	.sgx_offset = MRST_SGX_OFFSET,
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	.chip_setup = mdfld_chip_setup,
5488c2ecf20Sopenharmony_ci	.crtc_helper = &mdfld_helper_funcs,
5498c2ecf20Sopenharmony_ci	.crtc_funcs = &psb_intel_crtc_funcs,
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci	.output_init = mdfld_output_init,
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
5548c2ecf20Sopenharmony_ci	.backlight_init = mdfld_backlight_init,
5558c2ecf20Sopenharmony_ci#endif
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	.save_regs = mdfld_save_registers,
5588c2ecf20Sopenharmony_ci	.restore_regs = mdfld_restore_registers,
5598c2ecf20Sopenharmony_ci	.save_crtc = gma_crtc_save,
5608c2ecf20Sopenharmony_ci	.restore_crtc = gma_crtc_restore,
5618c2ecf20Sopenharmony_ci	.power_down = mdfld_power_down,
5628c2ecf20Sopenharmony_ci	.power_up = mdfld_power_up,
5638c2ecf20Sopenharmony_ci};
564