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