11b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox/*
21b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox * Copyright © 2010 Intel Corporation
31b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox *
41b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox * Permission is hereby granted, free of charge, to any person obtaining a
51b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox * copy of this software and associated documentation files (the "Software"),
61b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox * to deal in the Software without restriction, including without limitation
71b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox * the rights to use, copy, modify, merge, publish, distribute, sublicense,
81b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox * and/or sell copies of the Software, and to permit persons to whom the
91b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox * Software is furnished to do so, subject to the following conditions:
101b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox *
111b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox * The above copyright notice and this permission notice (including the next
121b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox * paragraph) shall be included in all copies or substantial portions of the
131b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox * Software.
141b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox *
151b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
161b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
171b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
181b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
191b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
201b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
211b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox * DEALINGS IN THE SOFTWARE.
221b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox *
231b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox * Authors:
241b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox *	Li Peng <peng.li@intel.com>
251b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox */
261b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
271b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#include <drm/drmP.h>
281b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#include <drm/drm.h>
291b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#include "psb_intel_drv.h"
301b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#include "psb_intel_reg.h"
311b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#include "psb_drv.h"
321b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
331b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define HDMI_READ(reg)		readl(hdmi_dev->regs + (reg))
341b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define HDMI_WRITE(reg, val)	writel(val, hdmi_dev->regs + (reg))
351b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
361b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define HDMI_HCR	0x1000
371b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define HCR_ENABLE_HDCP		(1 << 5)
381b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define HCR_ENABLE_AUDIO	(1 << 2)
391b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define HCR_ENABLE_PIXEL	(1 << 1)
401b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define HCR_ENABLE_TMDS		(1 << 0)
411b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
421b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define HDMI_HICR	0x1004
431b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define HDMI_HSR	0x1008
441b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define HDMI_HISR	0x100C
451b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define HDMI_DETECT_HDP		(1 << 0)
461b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
471b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define HDMI_VIDEO_REG	0x3000
481b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define HDMI_UNIT_EN		(1 << 7)
491b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define HDMI_MODE_OUTPUT	(1 << 0)
501b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define HDMI_HBLANK_A	0x3100
511b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
521b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define HDMI_AUDIO_CTRL	0x4000
531b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define HDMI_ENABLE_AUDIO	(1 << 0)
541b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
551b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define PCH_HTOTAL_B	0x3100
561b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define PCH_HBLANK_B	0x3104
571b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define PCH_HSYNC_B	0x3108
581b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define PCH_VTOTAL_B	0x310C
591b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define PCH_VBLANK_B	0x3110
601b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define PCH_VSYNC_B	0x3114
611b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define PCH_PIPEBSRC	0x311C
621b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
631b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define PCH_PIPEB_DSL	0x3800
641b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define PCH_PIPEB_SLC	0x3804
651b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define PCH_PIPEBCONF	0x3808
661b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define PCH_PIPEBSTAT	0x3824
671b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
681b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define CDVO_DFT	0x5000
691b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define CDVO_SLEWRATE	0x5004
701b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define CDVO_STRENGTH	0x5008
711b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define CDVO_RCOMP	0x500C
721b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
731b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define DPLL_CTRL       0x6000
741b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define DPLL_PDIV_SHIFT		16
751b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define DPLL_PDIV_MASK		(0xf << 16)
761b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define DPLL_PWRDN		(1 << 4)
771b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define DPLL_RESET		(1 << 3)
781b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define DPLL_FASTEN		(1 << 2)
791b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define DPLL_ENSTAT		(1 << 1)
801b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define DPLL_DITHEN		(1 << 0)
811b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
821b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define DPLL_DIV_CTRL   0x6004
831b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define DPLL_CLKF_MASK		0xffffffc0
841b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define DPLL_CLKR_MASK		(0x3f)
851b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
861b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define DPLL_CLK_ENABLE 0x6008
871b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define DPLL_EN_DISP		(1 << 31)
881b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define DPLL_SEL_HDMI		(1 << 8)
891b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define DPLL_EN_HDMI		(1 << 1)
901b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define DPLL_EN_VGA		(1 << 0)
911b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
921b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define DPLL_ADJUST     0x600C
931b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define DPLL_STATUS     0x6010
941b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define DPLL_UPDATE     0x6014
951b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define DPLL_DFT        0x6020
961b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
971b082ccf5901108d3acd860a73d8c0442556c0bbAlan Coxstruct intel_range {
981b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	int	min, max;
991b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox};
1001b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
1011b082ccf5901108d3acd860a73d8c0442556c0bbAlan Coxstruct oaktrail_hdmi_limit {
1021b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	struct intel_range vco, np, nr, nf;
1031b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox};
1041b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
1051b082ccf5901108d3acd860a73d8c0442556c0bbAlan Coxstruct oaktrail_hdmi_clock {
1061b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	int np;
1071b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	int nr;
1081b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	int nf;
1091b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	int dot;
1101b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox};
1111b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
1121b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define VCO_MIN		320000
1131b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define VCO_MAX		1650000
1141b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define	NP_MIN		1
1151b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define	NP_MAX		15
1161b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define	NR_MIN		1
1171b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define	NR_MAX		64
1181b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define NF_MIN		2
1191b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox#define NF_MAX		4095
1201b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
1211b082ccf5901108d3acd860a73d8c0442556c0bbAlan Coxstatic const struct oaktrail_hdmi_limit oaktrail_hdmi_limit = {
1221b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	.vco = { .min = VCO_MIN,		.max = VCO_MAX },
1231b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	.np  = { .min = NP_MIN,			.max = NP_MAX  },
1241b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	.nr  = { .min = NR_MIN,			.max = NR_MAX  },
1251b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	.nf  = { .min = NF_MIN,			.max = NF_MAX  },
1261b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox};
1271b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
1281b082ccf5901108d3acd860a73d8c0442556c0bbAlan Coxstatic void oaktrail_hdmi_audio_enable(struct drm_device *dev)
1291b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox{
1301b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	struct drm_psb_private *dev_priv = dev->dev_private;
1311b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	struct oaktrail_hdmi_dev *hdmi_dev = dev_priv->hdmi_priv;
1321b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
1331b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	HDMI_WRITE(HDMI_HCR, 0x67);
1341b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	HDMI_READ(HDMI_HCR);
1351b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
1361b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	HDMI_WRITE(0x51a8, 0x10);
1371b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	HDMI_READ(0x51a8);
1381b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
1391b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	HDMI_WRITE(HDMI_AUDIO_CTRL, 0x1);
1401b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	HDMI_READ(HDMI_AUDIO_CTRL);
1411b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox}
1421b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
1431b082ccf5901108d3acd860a73d8c0442556c0bbAlan Coxstatic void oaktrail_hdmi_audio_disable(struct drm_device *dev)
1441b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox{
1451b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	struct drm_psb_private *dev_priv = dev->dev_private;
1461b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	struct oaktrail_hdmi_dev *hdmi_dev = dev_priv->hdmi_priv;
1471b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
1481b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	HDMI_WRITE(0x51a8, 0x0);
1491b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	HDMI_READ(0x51a8);
1501b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
1511b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	HDMI_WRITE(HDMI_AUDIO_CTRL, 0x0);
1521b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	HDMI_READ(HDMI_AUDIO_CTRL);
1531b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
1541b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	HDMI_WRITE(HDMI_HCR, 0x47);
1551b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	HDMI_READ(HDMI_HCR);
1561b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox}
1571b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
1581b082ccf5901108d3acd860a73d8c0442556c0bbAlan Coxstatic void oaktrail_hdmi_dpms(struct drm_encoder *encoder, int mode)
1591b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox{
1601b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	static int dpms_mode = -1;
1611b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
1621b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	struct drm_device *dev = encoder->dev;
1631b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	struct drm_psb_private *dev_priv = dev->dev_private;
1641b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	struct oaktrail_hdmi_dev *hdmi_dev = dev_priv->hdmi_priv;
1651b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	u32 temp;
1661b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
1671b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	if (dpms_mode == mode)
1681b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox		return;
1691b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
1701b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	if (mode != DRM_MODE_DPMS_ON)
1711b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox		temp = 0x0;
1721b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	else
1731b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox		temp = 0x99;
1741b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
1751b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	dpms_mode = mode;
1761b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	HDMI_WRITE(HDMI_VIDEO_REG, temp);
1771b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox}
1781b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
1791b082ccf5901108d3acd860a73d8c0442556c0bbAlan Coxstatic int oaktrail_hdmi_mode_valid(struct drm_connector *connector,
1801b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox				struct drm_display_mode *mode)
1811b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox{
1829f821c675a389cf4aab7f1dc8ee0860fba4f3204Alan Cox	struct drm_psb_private *dev_priv = connector->dev->dev_private;
1831b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	if (mode->clock > 165000)
1841b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox		return MODE_CLOCK_HIGH;
1851b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	if (mode->clock < 20000)
1861b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox		return MODE_CLOCK_LOW;
1871b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
1881b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
1891b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox		return MODE_NO_DBLESCAN;
1901b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
1919f821c675a389cf4aab7f1dc8ee0860fba4f3204Alan Cox	/* We assume worst case scenario of 32 bpp here, since we don't know */
1929f821c675a389cf4aab7f1dc8ee0860fba4f3204Alan Cox	if ((ALIGN(mode->hdisplay * 4, 64) * mode->vdisplay) >
1939f821c675a389cf4aab7f1dc8ee0860fba4f3204Alan Cox	    dev_priv->vram_stolen_size)
1949f821c675a389cf4aab7f1dc8ee0860fba4f3204Alan Cox		return MODE_MEM;
1959f821c675a389cf4aab7f1dc8ee0860fba4f3204Alan Cox
1961b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	return MODE_OK;
1971b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox}
1981b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
1991b082ccf5901108d3acd860a73d8c0442556c0bbAlan Coxstatic bool oaktrail_hdmi_mode_fixup(struct drm_encoder *encoder,
2001b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox				 struct drm_display_mode *mode,
2011b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox				 struct drm_display_mode *adjusted_mode)
2021b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox{
2031b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	return true;
2041b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox}
2051b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
2061b082ccf5901108d3acd860a73d8c0442556c0bbAlan Coxstatic enum drm_connector_status
2071b082ccf5901108d3acd860a73d8c0442556c0bbAlan Coxoaktrail_hdmi_detect(struct drm_connector *connector, bool force)
2081b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox{
2091b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	enum drm_connector_status status;
2101b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	struct drm_device *dev = connector->dev;
2111b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	struct drm_psb_private *dev_priv = dev->dev_private;
2121b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	struct oaktrail_hdmi_dev *hdmi_dev = dev_priv->hdmi_priv;
2131b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	u32 temp;
2141b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
2151b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	temp = HDMI_READ(HDMI_HSR);
2161b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	DRM_DEBUG_KMS("HDMI_HSR %x\n", temp);
2171b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
2181b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	if ((temp & HDMI_DETECT_HDP) != 0)
2191b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox		status = connector_status_connected;
2201b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	else
2211b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox		status = connector_status_disconnected;
2221b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
2231b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	return status;
2241b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox}
2251b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
2261b082ccf5901108d3acd860a73d8c0442556c0bbAlan Coxstatic const unsigned char raw_edid[] = {
2271b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x10, 0xac, 0x2f, 0xa0,
2281b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	0x53, 0x55, 0x33, 0x30, 0x16, 0x13, 0x01, 0x03, 0x0e, 0x3a, 0x24, 0x78,
2291b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	0xea, 0xe9, 0xf5, 0xac, 0x51, 0x30, 0xb4, 0x25, 0x11, 0x50, 0x54, 0xa5,
2301b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	0x4b, 0x00, 0x81, 0x80, 0xa9, 0x40, 0x71, 0x4f, 0xb3, 0x00, 0x01, 0x01,
2311b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x28, 0x3c, 0x80, 0xa0, 0x70, 0xb0,
2321b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	0x23, 0x40, 0x30, 0x20, 0x36, 0x00, 0x46, 0x6c, 0x21, 0x00, 0x00, 0x1a,
2331b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	0x00, 0x00, 0x00, 0xff, 0x00, 0x47, 0x4e, 0x37, 0x32, 0x31, 0x39, 0x35,
2341b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	0x52, 0x30, 0x33, 0x55, 0x53, 0x0a, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x44,
2351b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	0x45, 0x4c, 0x4c, 0x20, 0x32, 0x37, 0x30, 0x39, 0x57, 0x0a, 0x20, 0x20,
2361b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	0x00, 0x00, 0x00, 0xfd, 0x00, 0x38, 0x4c, 0x1e, 0x53, 0x11, 0x00, 0x0a,
2371b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x8d
2381b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox};
2391b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
2401b082ccf5901108d3acd860a73d8c0442556c0bbAlan Coxstatic int oaktrail_hdmi_get_modes(struct drm_connector *connector)
2411b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox{
2421b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	struct drm_device *dev = connector->dev;
2431b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	struct drm_psb_private *dev_priv = dev->dev_private;
2441b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	struct i2c_adapter *i2c_adap;
2451b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	struct edid *edid;
2461b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	struct drm_display_mode *mode, *t;
2471b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	int i = 0, ret = 0;
2481b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
2491b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	i2c_adap = i2c_get_adapter(3);
2501b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	if (i2c_adap == NULL) {
2511b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox		DRM_ERROR("No ddc adapter available!\n");
2521b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox		edid = (struct edid *)raw_edid;
2531b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	} else {
2541b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox		edid = (struct edid *)raw_edid;
2551b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox		/* FIXME ? edid = drm_get_edid(connector, i2c_adap); */
2561b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	}
2571b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
2581b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	if (edid) {
2591b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox		drm_mode_connector_update_edid_property(connector, edid);
2601b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox		ret = drm_add_edid_modes(connector, edid);
2611b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox		connector->display_info.raw_edid = NULL;
2621b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	}
2631b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
2641b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	/*
2651b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	 * prune modes that require frame buffer bigger than stolen mem
2661b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	 */
2671b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	list_for_each_entry_safe(mode, t, &connector->probed_modes, head) {
2681b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox		if ((mode->hdisplay * mode->vdisplay * 4) >= dev_priv->vram_stolen_size) {
2691b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox			i++;
2701b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox			drm_mode_remove(connector, mode);
2711b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox		}
2721b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	}
2731b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	return ret - i;
2741b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox}
2751b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
2761b082ccf5901108d3acd860a73d8c0442556c0bbAlan Coxstatic void oaktrail_hdmi_mode_set(struct drm_encoder *encoder,
2771b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox			       struct drm_display_mode *mode,
2781b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox			       struct drm_display_mode *adjusted_mode)
2791b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox{
2801b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	struct drm_device *dev = encoder->dev;
2811b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
2821b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	oaktrail_hdmi_audio_enable(dev);
2831b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	return;
2841b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox}
2851b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
2861b082ccf5901108d3acd860a73d8c0442556c0bbAlan Coxstatic void oaktrail_hdmi_destroy(struct drm_connector *connector)
2871b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox{
2881b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	return;
2891b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox}
2901b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
2911b082ccf5901108d3acd860a73d8c0442556c0bbAlan Coxstatic const struct drm_encoder_helper_funcs oaktrail_hdmi_helper_funcs = {
2921b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	.dpms = oaktrail_hdmi_dpms,
2931b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	.mode_fixup = oaktrail_hdmi_mode_fixup,
2941b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	.prepare = psb_intel_encoder_prepare,
2951b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	.mode_set = oaktrail_hdmi_mode_set,
2961b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	.commit = psb_intel_encoder_commit,
2971b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox};
2981b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
2991b082ccf5901108d3acd860a73d8c0442556c0bbAlan Coxstatic const struct drm_connector_helper_funcs
3001b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox					oaktrail_hdmi_connector_helper_funcs = {
3011b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	.get_modes = oaktrail_hdmi_get_modes,
3021b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	.mode_valid = oaktrail_hdmi_mode_valid,
3031b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	.best_encoder = psb_intel_best_encoder,
3041b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox};
3051b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
3061b082ccf5901108d3acd860a73d8c0442556c0bbAlan Coxstatic const struct drm_connector_funcs oaktrail_hdmi_connector_funcs = {
3071b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	.dpms = drm_helper_connector_dpms,
3081b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	.detect = oaktrail_hdmi_detect,
3091b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	.fill_modes = drm_helper_probe_single_connector_modes,
3101b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	.destroy = oaktrail_hdmi_destroy,
3111b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox};
3121b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
3131b082ccf5901108d3acd860a73d8c0442556c0bbAlan Coxstatic void oaktrail_hdmi_enc_destroy(struct drm_encoder *encoder)
3141b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox{
3151b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	drm_encoder_cleanup(encoder);
3161b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox}
3171b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
3181b082ccf5901108d3acd860a73d8c0442556c0bbAlan Coxstatic const struct drm_encoder_funcs oaktrail_hdmi_enc_funcs = {
3191b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	.destroy = oaktrail_hdmi_enc_destroy,
3201b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox};
3211b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
3221b082ccf5901108d3acd860a73d8c0442556c0bbAlan Coxvoid oaktrail_hdmi_init(struct drm_device *dev,
3231b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox					struct psb_intel_mode_device *mode_dev)
3241b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox{
3259bd81acdb648509dbbc32d4da0477c9fae0d6a73Patrik Jakobsson	struct psb_intel_encoder *psb_intel_encoder;
3269bd81acdb648509dbbc32d4da0477c9fae0d6a73Patrik Jakobsson	struct psb_intel_connector *psb_intel_connector;
3271b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	struct drm_connector *connector;
3281b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	struct drm_encoder *encoder;
3291b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
3309bd81acdb648509dbbc32d4da0477c9fae0d6a73Patrik Jakobsson	psb_intel_encoder = kzalloc(sizeof(struct psb_intel_encoder), GFP_KERNEL);
3319bd81acdb648509dbbc32d4da0477c9fae0d6a73Patrik Jakobsson	if (!psb_intel_encoder)
3321b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox		return;
3331b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
3349bd81acdb648509dbbc32d4da0477c9fae0d6a73Patrik Jakobsson	psb_intel_connector = kzalloc(sizeof(struct psb_intel_connector), GFP_KERNEL);
3359bd81acdb648509dbbc32d4da0477c9fae0d6a73Patrik Jakobsson	if (!psb_intel_connector)
3369bd81acdb648509dbbc32d4da0477c9fae0d6a73Patrik Jakobsson		goto failed_connector;
3379bd81acdb648509dbbc32d4da0477c9fae0d6a73Patrik Jakobsson
3389bd81acdb648509dbbc32d4da0477c9fae0d6a73Patrik Jakobsson	connector = &psb_intel_connector->base;
3399bd81acdb648509dbbc32d4da0477c9fae0d6a73Patrik Jakobsson	encoder = &psb_intel_encoder->base;
3409bd81acdb648509dbbc32d4da0477c9fae0d6a73Patrik Jakobsson	drm_connector_init(dev, connector,
3411b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox			   &oaktrail_hdmi_connector_funcs,
3421b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox			   DRM_MODE_CONNECTOR_DVID);
3431b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
3449bd81acdb648509dbbc32d4da0477c9fae0d6a73Patrik Jakobsson	drm_encoder_init(dev, encoder,
3451b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox			 &oaktrail_hdmi_enc_funcs,
3461b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox			 DRM_MODE_ENCODER_TMDS);
3471b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
3489bd81acdb648509dbbc32d4da0477c9fae0d6a73Patrik Jakobsson	psb_intel_connector_attach_encoder(psb_intel_connector,
3499bd81acdb648509dbbc32d4da0477c9fae0d6a73Patrik Jakobsson					   psb_intel_encoder);
3501b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
3519bd81acdb648509dbbc32d4da0477c9fae0d6a73Patrik Jakobsson	psb_intel_encoder->type = INTEL_OUTPUT_HDMI;
3521b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	drm_encoder_helper_add(encoder, &oaktrail_hdmi_helper_funcs);
3531b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	drm_connector_helper_add(connector, &oaktrail_hdmi_connector_helper_funcs);
3541b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
3551b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	connector->display_info.subpixel_order = SubPixelHorizontalRGB;
3561b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	connector->interlace_allowed = false;
3571b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	connector->doublescan_allowed = false;
3581b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	drm_sysfs_connector_add(connector);
3591b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
3601b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	return;
3619bd81acdb648509dbbc32d4da0477c9fae0d6a73Patrik Jakobsson
3629bd81acdb648509dbbc32d4da0477c9fae0d6a73Patrik Jakobssonfailed_connector:
3639bd81acdb648509dbbc32d4da0477c9fae0d6a73Patrik Jakobsson	kfree(psb_intel_encoder);
3641b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox}
3651b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
3661b082ccf5901108d3acd860a73d8c0442556c0bbAlan Coxstatic DEFINE_PCI_DEVICE_TABLE(hdmi_ids) = {
3671b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080d) },
3686e7f45736e46f14e0f30ff94883fbc665d100d61Kirill A. Shutemov	{ 0 }
3691b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox};
3701b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
3711b082ccf5901108d3acd860a73d8c0442556c0bbAlan Coxvoid oaktrail_hdmi_setup(struct drm_device *dev)
3721b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox{
3731b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	struct drm_psb_private *dev_priv = dev->dev_private;
3741b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	struct pci_dev *pdev;
3751b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	struct oaktrail_hdmi_dev *hdmi_dev;
3761b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	int ret;
3771b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
3781b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x080d, NULL);
3791b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	if (!pdev)
3801b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox		return;
3811b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
3821b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	hdmi_dev = kzalloc(sizeof(struct oaktrail_hdmi_dev), GFP_KERNEL);
3831b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	if (!hdmi_dev) {
3841b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox		dev_err(dev->dev, "failed to allocate memory\n");
3851b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox		goto out;
3861b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	}
3871b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
3881b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
3891b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	ret = pci_enable_device(pdev);
3901b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	if (ret) {
3911b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox		dev_err(dev->dev, "failed to enable hdmi controller\n");
3921b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox		goto free;
3931b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	}
3941b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
3951b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	hdmi_dev->mmio = pci_resource_start(pdev, 0);
3961b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	hdmi_dev->mmio_len = pci_resource_len(pdev, 0);
3971b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	hdmi_dev->regs = ioremap(hdmi_dev->mmio, hdmi_dev->mmio_len);
3981b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	if (!hdmi_dev->regs) {
3991b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox		dev_err(dev->dev, "failed to map hdmi mmio\n");
4001b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox		goto free;
4011b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	}
4021b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
4031b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	hdmi_dev->dev = pdev;
4041b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	pci_set_drvdata(pdev, hdmi_dev);
4051b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
4061b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	/* Initialize i2c controller */
4071b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	ret = oaktrail_hdmi_i2c_init(hdmi_dev->dev);
4081b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	if (ret)
4091b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox		dev_err(dev->dev, "HDMI I2C initialization failed\n");
4101b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
4111b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	dev_priv->hdmi_priv = hdmi_dev;
4121b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	oaktrail_hdmi_audio_disable(dev);
4131b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	return;
4141b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
4151b082ccf5901108d3acd860a73d8c0442556c0bbAlan Coxfree:
4161b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	kfree(hdmi_dev);
4171b082ccf5901108d3acd860a73d8c0442556c0bbAlan Coxout:
4181b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	return;
4191b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox}
4201b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
4211b082ccf5901108d3acd860a73d8c0442556c0bbAlan Coxvoid oaktrail_hdmi_teardown(struct drm_device *dev)
4221b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox{
4231b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	struct drm_psb_private *dev_priv = dev->dev_private;
4241b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	struct oaktrail_hdmi_dev *hdmi_dev = dev_priv->hdmi_priv;
4251b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	struct pci_dev *pdev;
4261b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
4271b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	if (hdmi_dev) {
4281b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox		pdev = hdmi_dev->dev;
4291b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox		pci_set_drvdata(pdev, NULL);
4301b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox		oaktrail_hdmi_i2c_exit(pdev);
4311b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox		iounmap(hdmi_dev->regs);
4321b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox		kfree(hdmi_dev);
4331b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox		pci_dev_put(pdev);
4341b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	}
4351b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox}
4361b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
4371b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox/* save HDMI register state */
4381b082ccf5901108d3acd860a73d8c0442556c0bbAlan Coxvoid oaktrail_hdmi_save(struct drm_device *dev)
4391b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox{
4401b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	struct drm_psb_private *dev_priv = dev->dev_private;
4411b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	struct oaktrail_hdmi_dev *hdmi_dev = dev_priv->hdmi_priv;
442c6265ff593467d472814aa9f16f89f6c1dc90a5dAlan Cox	struct psb_state *regs = &dev_priv->regs.psb;
4431b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	int i;
4441b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
4451b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	/* dpll */
4461b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	hdmi_dev->saveDPLL_CTRL = PSB_RVDC32(DPLL_CTRL);
4471b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	hdmi_dev->saveDPLL_DIV_CTRL = PSB_RVDC32(DPLL_DIV_CTRL);
4481b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	hdmi_dev->saveDPLL_ADJUST = PSB_RVDC32(DPLL_ADJUST);
4491b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	hdmi_dev->saveDPLL_UPDATE = PSB_RVDC32(DPLL_UPDATE);
4501b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	hdmi_dev->saveDPLL_CLK_ENABLE = PSB_RVDC32(DPLL_CLK_ENABLE);
4511b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
4521b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	/* pipe B */
453648a8e342c5a754bdc62f003d3af90507c1abfdeAlan Cox	regs->savePIPEBCONF = PSB_RVDC32(PIPEBCONF);
454648a8e342c5a754bdc62f003d3af90507c1abfdeAlan Cox	regs->savePIPEBSRC  = PSB_RVDC32(PIPEBSRC);
455648a8e342c5a754bdc62f003d3af90507c1abfdeAlan Cox	regs->saveHTOTAL_B  = PSB_RVDC32(HTOTAL_B);
456648a8e342c5a754bdc62f003d3af90507c1abfdeAlan Cox	regs->saveHBLANK_B  = PSB_RVDC32(HBLANK_B);
457648a8e342c5a754bdc62f003d3af90507c1abfdeAlan Cox	regs->saveHSYNC_B   = PSB_RVDC32(HSYNC_B);
458648a8e342c5a754bdc62f003d3af90507c1abfdeAlan Cox	regs->saveVTOTAL_B  = PSB_RVDC32(VTOTAL_B);
459648a8e342c5a754bdc62f003d3af90507c1abfdeAlan Cox	regs->saveVBLANK_B  = PSB_RVDC32(VBLANK_B);
460648a8e342c5a754bdc62f003d3af90507c1abfdeAlan Cox	regs->saveVSYNC_B   = PSB_RVDC32(VSYNC_B);
4611b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
4621b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	hdmi_dev->savePCH_PIPEBCONF = PSB_RVDC32(PCH_PIPEBCONF);
4631b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	hdmi_dev->savePCH_PIPEBSRC = PSB_RVDC32(PCH_PIPEBSRC);
4641b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	hdmi_dev->savePCH_HTOTAL_B = PSB_RVDC32(PCH_HTOTAL_B);
4651b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	hdmi_dev->savePCH_HBLANK_B = PSB_RVDC32(PCH_HBLANK_B);
4661b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	hdmi_dev->savePCH_HSYNC_B  = PSB_RVDC32(PCH_HSYNC_B);
4671b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	hdmi_dev->savePCH_VTOTAL_B = PSB_RVDC32(PCH_VTOTAL_B);
4681b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	hdmi_dev->savePCH_VBLANK_B = PSB_RVDC32(PCH_VBLANK_B);
4691b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	hdmi_dev->savePCH_VSYNC_B  = PSB_RVDC32(PCH_VSYNC_B);
4701b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
4711b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	/* plane */
472648a8e342c5a754bdc62f003d3af90507c1abfdeAlan Cox	regs->saveDSPBCNTR = PSB_RVDC32(DSPBCNTR);
473648a8e342c5a754bdc62f003d3af90507c1abfdeAlan Cox	regs->saveDSPBSTRIDE = PSB_RVDC32(DSPBSTRIDE);
474648a8e342c5a754bdc62f003d3af90507c1abfdeAlan Cox	regs->saveDSPBADDR = PSB_RVDC32(DSPBBASE);
475648a8e342c5a754bdc62f003d3af90507c1abfdeAlan Cox	regs->saveDSPBSURF = PSB_RVDC32(DSPBSURF);
476648a8e342c5a754bdc62f003d3af90507c1abfdeAlan Cox	regs->saveDSPBLINOFF = PSB_RVDC32(DSPBLINOFF);
477648a8e342c5a754bdc62f003d3af90507c1abfdeAlan Cox	regs->saveDSPBTILEOFF = PSB_RVDC32(DSPBTILEOFF);
4781b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
4791b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	/* cursor B */
480648a8e342c5a754bdc62f003d3af90507c1abfdeAlan Cox	regs->saveDSPBCURSOR_CTRL = PSB_RVDC32(CURBCNTR);
481648a8e342c5a754bdc62f003d3af90507c1abfdeAlan Cox	regs->saveDSPBCURSOR_BASE = PSB_RVDC32(CURBBASE);
482648a8e342c5a754bdc62f003d3af90507c1abfdeAlan Cox	regs->saveDSPBCURSOR_POS = PSB_RVDC32(CURBPOS);
4831b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
4841b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	/* save palette */
4851b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	for (i = 0; i < 256; i++)
486648a8e342c5a754bdc62f003d3af90507c1abfdeAlan Cox		regs->save_palette_b[i] = PSB_RVDC32(PALETTE_B + (i << 2));
4871b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox}
4881b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
4891b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox/* restore HDMI register state */
4901b082ccf5901108d3acd860a73d8c0442556c0bbAlan Coxvoid oaktrail_hdmi_restore(struct drm_device *dev)
4911b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox{
4921b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	struct drm_psb_private *dev_priv = dev->dev_private;
4931b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	struct oaktrail_hdmi_dev *hdmi_dev = dev_priv->hdmi_priv;
494c6265ff593467d472814aa9f16f89f6c1dc90a5dAlan Cox	struct psb_state *regs = &dev_priv->regs.psb;
4951b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	int i;
4961b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
4971b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	/* dpll */
4981b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	PSB_WVDC32(hdmi_dev->saveDPLL_CTRL, DPLL_CTRL);
4991b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	PSB_WVDC32(hdmi_dev->saveDPLL_DIV_CTRL, DPLL_DIV_CTRL);
5001b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	PSB_WVDC32(hdmi_dev->saveDPLL_ADJUST, DPLL_ADJUST);
5011b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	PSB_WVDC32(hdmi_dev->saveDPLL_UPDATE, DPLL_UPDATE);
5021b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	PSB_WVDC32(hdmi_dev->saveDPLL_CLK_ENABLE, DPLL_CLK_ENABLE);
5031b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	DRM_UDELAY(150);
5041b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
5051b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	/* pipe */
506648a8e342c5a754bdc62f003d3af90507c1abfdeAlan Cox	PSB_WVDC32(regs->savePIPEBSRC, PIPEBSRC);
507648a8e342c5a754bdc62f003d3af90507c1abfdeAlan Cox	PSB_WVDC32(regs->saveHTOTAL_B, HTOTAL_B);
508648a8e342c5a754bdc62f003d3af90507c1abfdeAlan Cox	PSB_WVDC32(regs->saveHBLANK_B, HBLANK_B);
509648a8e342c5a754bdc62f003d3af90507c1abfdeAlan Cox	PSB_WVDC32(regs->saveHSYNC_B,  HSYNC_B);
510648a8e342c5a754bdc62f003d3af90507c1abfdeAlan Cox	PSB_WVDC32(regs->saveVTOTAL_B, VTOTAL_B);
511648a8e342c5a754bdc62f003d3af90507c1abfdeAlan Cox	PSB_WVDC32(regs->saveVBLANK_B, VBLANK_B);
512648a8e342c5a754bdc62f003d3af90507c1abfdeAlan Cox	PSB_WVDC32(regs->saveVSYNC_B,  VSYNC_B);
5131b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
5141b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	PSB_WVDC32(hdmi_dev->savePCH_PIPEBSRC, PCH_PIPEBSRC);
5151b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	PSB_WVDC32(hdmi_dev->savePCH_HTOTAL_B, PCH_HTOTAL_B);
5161b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	PSB_WVDC32(hdmi_dev->savePCH_HBLANK_B, PCH_HBLANK_B);
5171b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	PSB_WVDC32(hdmi_dev->savePCH_HSYNC_B,  PCH_HSYNC_B);
5181b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	PSB_WVDC32(hdmi_dev->savePCH_VTOTAL_B, PCH_VTOTAL_B);
5191b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	PSB_WVDC32(hdmi_dev->savePCH_VBLANK_B, PCH_VBLANK_B);
5201b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	PSB_WVDC32(hdmi_dev->savePCH_VSYNC_B,  PCH_VSYNC_B);
5211b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
522648a8e342c5a754bdc62f003d3af90507c1abfdeAlan Cox	PSB_WVDC32(regs->savePIPEBCONF, PIPEBCONF);
5231b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	PSB_WVDC32(hdmi_dev->savePCH_PIPEBCONF, PCH_PIPEBCONF);
5241b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
5251b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	/* plane */
526648a8e342c5a754bdc62f003d3af90507c1abfdeAlan Cox	PSB_WVDC32(regs->saveDSPBLINOFF, DSPBLINOFF);
527648a8e342c5a754bdc62f003d3af90507c1abfdeAlan Cox	PSB_WVDC32(regs->saveDSPBSTRIDE, DSPBSTRIDE);
528648a8e342c5a754bdc62f003d3af90507c1abfdeAlan Cox	PSB_WVDC32(regs->saveDSPBTILEOFF, DSPBTILEOFF);
529648a8e342c5a754bdc62f003d3af90507c1abfdeAlan Cox	PSB_WVDC32(regs->saveDSPBCNTR, DSPBCNTR);
530648a8e342c5a754bdc62f003d3af90507c1abfdeAlan Cox	PSB_WVDC32(regs->saveDSPBSURF, DSPBSURF);
5311b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
5321b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	/* cursor B */
533648a8e342c5a754bdc62f003d3af90507c1abfdeAlan Cox	PSB_WVDC32(regs->saveDSPBCURSOR_CTRL, CURBCNTR);
534648a8e342c5a754bdc62f003d3af90507c1abfdeAlan Cox	PSB_WVDC32(regs->saveDSPBCURSOR_POS, CURBPOS);
535648a8e342c5a754bdc62f003d3af90507c1abfdeAlan Cox	PSB_WVDC32(regs->saveDSPBCURSOR_BASE, CURBBASE);
5361b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox
5371b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	/* restore palette */
5381b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox	for (i = 0; i < 256; i++)
539648a8e342c5a754bdc62f003d3af90507c1abfdeAlan Cox		PSB_WVDC32(regs->save_palette_b[i], PALETTE_B + (i << 2));
5401b082ccf5901108d3acd860a73d8c0442556c0bbAlan Cox}
541