From 279c0de8338979722e7000ad36079016866a90f3 Mon Sep 17 00:00:00 2001 From: Erik Gilling Date: Mon, 23 Aug 2010 21:36:56 -0700 Subject: [PATCH] video: tegra: add hdmi output support Signed-off-by: Erik Gilling --- arch/arm/mach-tegra/include/mach/dc.h | 1 + drivers/video/tegra/dc/Makefile | 4 +- drivers/video/tegra/dc/dc.c | 23 +- drivers/video/tegra/dc/edid.c | 109 ++++ drivers/video/tegra/dc/edid.h | 37 ++ drivers/video/tegra/dc/hdmi.c | 723 ++++++++++++++++++++++++++ drivers/video/tegra/dc/hdmi_reg.h | 378 ++++++++++++++ 7 files changed, 1273 insertions(+), 2 deletions(-) create mode 100644 drivers/video/tegra/dc/edid.c create mode 100644 drivers/video/tegra/dc/edid.h create mode 100644 drivers/video/tegra/dc/hdmi.c create mode 100644 drivers/video/tegra/dc/hdmi_reg.h diff --git a/arch/arm/mach-tegra/include/mach/dc.h b/arch/arm/mach-tegra/include/mach/dc.h index fc1911dfba13..7e2e230aad13 100644 --- a/arch/arm/mach-tegra/include/mach/dc.h +++ b/arch/arm/mach-tegra/include/mach/dc.h @@ -53,6 +53,7 @@ struct tegra_dc_mode { enum { TEGRA_DC_OUT_RGB, + TEGRA_DC_OUT_HDMI, }; struct tegra_dc_out { diff --git a/drivers/video/tegra/dc/Makefile b/drivers/video/tegra/dc/Makefile index 3ecb63c59e77..eb39d5d28e92 100644 --- a/drivers/video/tegra/dc/Makefile +++ b/drivers/video/tegra/dc/Makefile @@ -1,2 +1,4 @@ obj-y += dc.o -obj-y += rgb.o \ No newline at end of file +obj-y += rgb.o +obj-y += hdmi.o +obj-y += edid.o \ No newline at end of file diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c index 397ade7f11d9..6331b30be38d 100644 --- a/drivers/video/tegra/dc/dc.c +++ b/drivers/video/tegra/dc/dc.c @@ -487,7 +487,24 @@ EXPORT_SYMBOL(tegra_dc_set_blending); void tegra_dc_setup_clk(struct tegra_dc *dc, struct clk *clk) { - /* clock setup for DSI/HDMI to go here */ + if (dc->out->type == TEGRA_DC_OUT_HDMI) { + unsigned long rate; + struct clk *pll_d_out0_clk = + clk_get_sys(NULL, "pll_d_out0"); + struct clk *pll_d_clk = + clk_get_sys(NULL, "pll_d"); + + if (dc->mode.pclk > 70000) + rate = 594000000; + else + rate = 216000000; + + if (rate != clk_get_rate(pll_d_clk)) + clk_set_rate(pll_d_clk, rate); + + if (clk_get_parent(clk) != pll_d_out0_clk) + clk_set_parent(clk, pll_d_out0_clk); + } } static int tegra_dc_program_mode(struct tegra_dc *dc, struct tegra_dc_mode *mode) @@ -570,6 +587,10 @@ static void tegra_dc_set_out(struct tegra_dc *dc, struct tegra_dc_out *out) dc->out_ops = &tegra_dc_rgb_ops; break; + case TEGRA_DC_OUT_HDMI: + dc->out_ops = &tegra_dc_hdmi_ops; + break; + default: dc->out_ops = NULL; break; diff --git a/drivers/video/tegra/dc/edid.c b/drivers/video/tegra/dc/edid.c new file mode 100644 index 000000000000..0b0b1a760a4e --- /dev/null +++ b/drivers/video/tegra/dc/edid.c @@ -0,0 +1,109 @@ +/* + * drivers/video/tegra/dc/edid.c + * + * Copyright (C) 2010 Google, Inc. + * Author: Erik Gilling + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include + +#include "edid.h" + +int tegra_edid_get_monspecs(struct tegra_edid *edid, struct fb_monspecs *specs) +{ + u8 data[256]; + int i; + int ret; + + for (i = 0; i < 256; i++) { + ret = i2c_smbus_read_byte_data(edid->client, i); + if (ret < 0) + break; + + data[i] = ret; + } + + if (i != 128 && i != 256) + return ret; + + fb_edid_to_monspecs(data, specs); + if (i == 256) + fb_edid_add_monspecs(data + 128, specs); + + return 0; +} + +struct tegra_edid *tegra_edid_create(int bus) +{ + struct tegra_edid *edid; + struct i2c_adapter *adapter; + + edid = kzalloc(sizeof(struct tegra_edid), GFP_KERNEL); + if (!edid) + return ERR_PTR(-ENOMEM); + + strlcpy(edid->info.type, "tegra_edid", sizeof(edid->info.type)); + edid->info.addr = 0x50; + edid->info.platform_data = edid; + init_waitqueue_head(&edid->wq); + + adapter = i2c_get_adapter(bus); + if (!adapter) { + pr_err("can't get adpater for bus %d\n", bus); + return NULL; + } + edid->client = i2c_new_device(adapter, &edid->info); + + i2c_put_adapter(adapter); + + if (!edid->client) { + pr_err("can't create new device\n"); + return NULL; + } + + return edid; +} + +void tegra_edid_destroy(struct tegra_edid *edid) +{ + i2c_release_client(edid->client); + kfree(edid); +} + +static const struct i2c_device_id tegra_edid_id[] = { + { "tegra_edid", 0 }, + { } +}; + +MODULE_DEVICE_TABLE(i2c, tegra_edid_id); + +static struct i2c_driver tegra_edid_driver = { + .id_table = tegra_edid_id, + .driver = { + .name = "tegra_edid", + }, +}; + +static int __init tegra_edid_init(void) +{ + return i2c_add_driver(&tegra_edid_driver); +} + +static void __exit tegra_edid_exit(void) +{ + i2c_del_driver(&tegra_edid_driver); +} + +module_init(tegra_edid_init); +module_exit(tegra_edid_exit); diff --git a/drivers/video/tegra/dc/edid.h b/drivers/video/tegra/dc/edid.h new file mode 100644 index 000000000000..eb78abb7e7d8 --- /dev/null +++ b/drivers/video/tegra/dc/edid.h @@ -0,0 +1,37 @@ +/* + * drivers/video/tegra/dc/edid.h + * + * Copyright (C) 2010 Google, Inc. + * Author: Erik Gilling + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __DRIVERS_VIDEO_TEGRA_DC_EDID_H +#define __DRIVERS_VIDEO_TEGRA_DC_EDID_H + +#include +#include + +struct tegra_edid { + struct i2c_client *client; + struct i2c_board_info info; + + int probed; + wait_queue_head_t wq; +}; + +struct tegra_edid *tegra_edid_create(int bus); +void tegra_edid_destroy(struct tegra_edid *edid); + +int tegra_edid_get_monspecs(struct tegra_edid *edid, struct fb_monspecs *specs); + +#endif diff --git a/drivers/video/tegra/dc/hdmi.c b/drivers/video/tegra/dc/hdmi.c new file mode 100644 index 000000000000..b2a3b72172ee --- /dev/null +++ b/drivers/video/tegra/dc/hdmi.c @@ -0,0 +1,723 @@ +/* + * drivers/video/tegra/dc/hdmi.c + * + * Copyright (C) 2010 Google, Inc. + * Author: Erik Gilling + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "dc_reg.h" +#include "dc_priv.h" +#include "hdmi_reg.h" +#include "edid.h" + +struct tegra_dc_hdmi_data { + struct tegra_dc *dc; + struct tegra_edid *edid; + struct delayed_work work; + + struct resource *base_res; + void __iomem *base; + struct clk *clk; +}; + +const struct fb_videomode tegra_dc_hdmi_supported_modes[] = { + /* 1280x720p 60hz: EIA/CEA-861-B Format 4 */ + { + .xres = 1280, + .yres = 720, + .pixclock = KHZ2PICOS(74250), + .hsync_len = 40, /* h_sync_width */ + .vsync_len = 5, /* v_sync_width */ + .left_margin = 220, /* h_back_porch */ + .upper_margin = 20, /* v_back_porch */ + .right_margin = 110, /* h_front_porch */ + .lower_margin = 5, /* v_front_porch */ + .vmode = FB_VMODE_NONINTERLACED, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + }, + + /* 720x480p 59.94hz: EIA/CEA-861-B Formats 2 & 3 */ + { + .xres = 720, + .yres = 480, + .pixclock = KHZ2PICOS(27000), + .hsync_len = 62, /* h_sync_width */ + .vsync_len = 6, /* v_sync_width */ + .left_margin = 60, /* h_back_porch */ + .upper_margin = 30, /* v_back_porch */ + .right_margin = 16, /* h_front_porch */ + .lower_margin = 9, /* v_front_porch */ + .vmode = FB_VMODE_NONINTERLACED, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + }, + + /* 640x480p 60hz: EIA/CEA-861-B Format 1 */ + { + .xres = 640, + .yres = 480, + .pixclock = KHZ2PICOS(25200), + .hsync_len = 96, /* h_sync_width */ + .vsync_len = 2, /* v_sync_width */ + .left_margin = 48, /* h_back_porch */ + .upper_margin = 33, /* v_back_porch */ + .right_margin = 16, /* h_front_porch */ + .lower_margin = 10, /* v_front_porch */ + .vmode = FB_VMODE_NONINTERLACED, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + }, + + /* 720x576p 50hz EIA/CEA-861-B Formats 17 & 18 */ + { + .xres = 720, + .yres = 576, + .pixclock = KHZ2PICOS(27000), + .hsync_len = 64, /* h_sync_width */ + .vsync_len = 5, /* v_sync_width */ + .left_margin = 68, /* h_back_porch */ + .upper_margin = 39, /* v_back_porch */ + .right_margin = 12, /* h_front_porch */ + .lower_margin = 5, /* v_front_porch */ + .vmode = FB_VMODE_NONINTERLACED, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + }, + + /* 1920x1080p 59.94/60hz EIA/CEA-861-B Format 16 */ + { + .xres = 1920, + .yres = 1080, + .pixclock = KHZ2PICOS(148500), + .hsync_len = 44, /* h_sync_width */ + .vsync_len = 5, /* v_sync_width */ + .left_margin = 148, /* h_back_porch */ + .upper_margin = 36, /* v_back_porch */ + .right_margin = 88, /* h_front_porch */ + .lower_margin = 4, /* v_front_porch */ + .vmode = FB_VMODE_NONINTERLACED, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + }, +}; + +static inline unsigned long tegra_hdmi_readl(struct tegra_dc_hdmi_data *hdmi, + unsigned long reg) +{ + return readl(hdmi->base + reg * 4); +} + +static inline void tegra_hdmi_writel(struct tegra_dc_hdmi_data *hdmi, + unsigned long val, unsigned long reg) +{ + writel(val, hdmi->base + reg * 4); +} + +static inline void tegra_hdmi_clrsetbits(struct tegra_dc_hdmi_data *hdmi, + unsigned long reg, unsigned long clr, + unsigned long set) +{ + unsigned long val = tegra_hdmi_readl(hdmi, reg); + val &= ~clr; + val |= set; + tegra_hdmi_writel(hdmi, val, reg); +} + +#define DUMP_REG(a) do { \ + printk("HDMI %-32s\t%03x\t%08lx\n", \ + #a, a, tegra_hdmi_readl(hdmi, a)); \ + } while (0) + +#ifdef DEBUG +static void hdmi_dumpregs(struct tegra_dc_hdmi_data *hdmi) +{ + DUMP_REG(HDMI_CTXSW); + DUMP_REG(HDMI_NV_PDISP_SOR_STATE0); + DUMP_REG(HDMI_NV_PDISP_SOR_STATE1); + DUMP_REG(HDMI_NV_PDISP_SOR_STATE2); + DUMP_REG(HDMI_NV_PDISP_RG_HDCP_AN_MSB); + DUMP_REG(HDMI_NV_PDISP_RG_HDCP_AN_LSB); + DUMP_REG(HDMI_NV_PDISP_RG_HDCP_CN_MSB); + DUMP_REG(HDMI_NV_PDISP_RG_HDCP_CN_LSB); + DUMP_REG(HDMI_NV_PDISP_RG_HDCP_AKSV_MSB); + DUMP_REG(HDMI_NV_PDISP_RG_HDCP_AKSV_LSB); + DUMP_REG(HDMI_NV_PDISP_RG_HDCP_BKSV_MSB); + DUMP_REG(HDMI_NV_PDISP_RG_HDCP_BKSV_LSB); + DUMP_REG(HDMI_NV_PDISP_RG_HDCP_CKSV_MSB); + DUMP_REG(HDMI_NV_PDISP_RG_HDCP_CKSV_LSB); + DUMP_REG(HDMI_NV_PDISP_RG_HDCP_DKSV_MSB); + DUMP_REG(HDMI_NV_PDISP_RG_HDCP_DKSV_LSB); + DUMP_REG(HDMI_NV_PDISP_RG_HDCP_CTRL); + DUMP_REG(HDMI_NV_PDISP_RG_HDCP_CMODE); + DUMP_REG(HDMI_NV_PDISP_RG_HDCP_MPRIME_MSB); + DUMP_REG(HDMI_NV_PDISP_RG_HDCP_MPRIME_LSB); + DUMP_REG(HDMI_NV_PDISP_RG_HDCP_SPRIME_MSB); + DUMP_REG(HDMI_NV_PDISP_RG_HDCP_SPRIME_LSB2); + DUMP_REG(HDMI_NV_PDISP_RG_HDCP_SPRIME_LSB1); + DUMP_REG(HDMI_NV_PDISP_RG_HDCP_RI); + DUMP_REG(HDMI_NV_PDISP_RG_HDCP_CS_MSB); + DUMP_REG(HDMI_NV_PDISP_RG_HDCP_CS_LSB); + DUMP_REG(HDMI_NV_PDISP_HDMI_AUDIO_EMU0); + DUMP_REG(HDMI_NV_PDISP_HDMI_AUDIO_EMU_RDATA0); + DUMP_REG(HDMI_NV_PDISP_HDMI_AUDIO_EMU1); + DUMP_REG(HDMI_NV_PDISP_HDMI_AUDIO_EMU2); + DUMP_REG(HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_CTRL); + DUMP_REG(HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_STATUS); + DUMP_REG(HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_HEADER); + DUMP_REG(HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_SUBPACK0_LOW); + DUMP_REG(HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_SUBPACK0_HIGH); + DUMP_REG(HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_CTRL); + DUMP_REG(HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_STATUS); + DUMP_REG(HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_HEADER); + DUMP_REG(HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK0_LOW); + DUMP_REG(HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK0_HIGH); + DUMP_REG(HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK1_LOW); + DUMP_REG(HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK1_HIGH); + DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_CTRL); + DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_STATUS); + DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_HEADER); + DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK0_LOW); + DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK0_HIGH); + DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK1_LOW); + DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK1_HIGH); + DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK2_LOW); + DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK2_HIGH); + DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK3_LOW); + DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK3_HIGH); + DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_CTRL); + DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0320_SUBPACK_LOW); + DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0320_SUBPACK_HIGH); + DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0441_SUBPACK_LOW); + DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0441_SUBPACK_HIGH); + DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0882_SUBPACK_LOW); + DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0882_SUBPACK_HIGH); + DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_1764_SUBPACK_LOW); + DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_1764_SUBPACK_HIGH); + DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0480_SUBPACK_LOW); + DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0480_SUBPACK_HIGH); + DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0960_SUBPACK_LOW); + DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0960_SUBPACK_HIGH); + DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_1920_SUBPACK_LOW); + DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_1920_SUBPACK_HIGH); + DUMP_REG(HDMI_NV_PDISP_HDMI_CTRL); + DUMP_REG(HDMI_NV_PDISP_HDMI_VSYNC_KEEPOUT); + DUMP_REG(HDMI_NV_PDISP_HDMI_VSYNC_WINDOW); + DUMP_REG(HDMI_NV_PDISP_HDMI_GCP_CTRL); + DUMP_REG(HDMI_NV_PDISP_HDMI_GCP_STATUS); + DUMP_REG(HDMI_NV_PDISP_HDMI_GCP_SUBPACK); + DUMP_REG(HDMI_NV_PDISP_HDMI_CHANNEL_STATUS1); + DUMP_REG(HDMI_NV_PDISP_HDMI_CHANNEL_STATUS2); + DUMP_REG(HDMI_NV_PDISP_HDMI_EMU0); + DUMP_REG(HDMI_NV_PDISP_HDMI_EMU1); + DUMP_REG(HDMI_NV_PDISP_HDMI_EMU1_RDATA); + DUMP_REG(HDMI_NV_PDISP_HDMI_SPARE); + DUMP_REG(HDMI_NV_PDISP_HDMI_SPDIF_CHN_STATUS1); + DUMP_REG(HDMI_NV_PDISP_HDMI_SPDIF_CHN_STATUS2); + DUMP_REG(HDMI_NV_PDISP_HDCPRIF_ROM_CTRL); + DUMP_REG(HDMI_NV_PDISP_SOR_CAP); + DUMP_REG(HDMI_NV_PDISP_SOR_PWR); + DUMP_REG(HDMI_NV_PDISP_SOR_TEST); + DUMP_REG(HDMI_NV_PDISP_SOR_PLL0); + DUMP_REG(HDMI_NV_PDISP_SOR_PLL1); + DUMP_REG(HDMI_NV_PDISP_SOR_PLL2); + DUMP_REG(HDMI_NV_PDISP_SOR_CSTM); + DUMP_REG(HDMI_NV_PDISP_SOR_LVDS); + DUMP_REG(HDMI_NV_PDISP_SOR_CRCA); + DUMP_REG(HDMI_NV_PDISP_SOR_CRCB); + DUMP_REG(HDMI_NV_PDISP_SOR_BLANK); + DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_CTL); + DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST0); + DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST1); + DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST2); + DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST3); + DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST4); + DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST5); + DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST6); + DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST7); + DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST8); + DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST9); + DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INSTA); + DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INSTB); + DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INSTC); + DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INSTD); + DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INSTE); + DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INSTF); + DUMP_REG(HDMI_NV_PDISP_SOR_VCRCA0); + DUMP_REG(HDMI_NV_PDISP_SOR_VCRCA1); + DUMP_REG(HDMI_NV_PDISP_SOR_CCRCA0); + DUMP_REG(HDMI_NV_PDISP_SOR_CCRCA1); + DUMP_REG(HDMI_NV_PDISP_SOR_EDATAA0); + DUMP_REG(HDMI_NV_PDISP_SOR_EDATAA1); + DUMP_REG(HDMI_NV_PDISP_SOR_COUNTA0); + DUMP_REG(HDMI_NV_PDISP_SOR_COUNTA1); + DUMP_REG(HDMI_NV_PDISP_SOR_DEBUGA0); + DUMP_REG(HDMI_NV_PDISP_SOR_DEBUGA1); + DUMP_REG(HDMI_NV_PDISP_SOR_TRIG); + DUMP_REG(HDMI_NV_PDISP_SOR_MSCHECK); + DUMP_REG(HDMI_NV_PDISP_SOR_LANE_DRIVE_CURRENT); + DUMP_REG(HDMI_NV_PDISP_AUDIO_DEBUG0); + DUMP_REG(HDMI_NV_PDISP_AUDIO_DEBUG1); + DUMP_REG(HDMI_NV_PDISP_AUDIO_DEBUG2); + DUMP_REG(HDMI_NV_PDISP_AUDIO_FS1); + DUMP_REG(HDMI_NV_PDISP_AUDIO_FS2); + DUMP_REG(HDMI_NV_PDISP_AUDIO_FS3); + DUMP_REG(HDMI_NV_PDISP_AUDIO_FS4); + DUMP_REG(HDMI_NV_PDISP_AUDIO_FS5); + DUMP_REG(HDMI_NV_PDISP_AUDIO_FS6); + DUMP_REG(HDMI_NV_PDISP_AUDIO_FS7); + DUMP_REG(HDMI_NV_PDISP_AUDIO_PULSE_WIDTH); + DUMP_REG(HDMI_NV_PDISP_AUDIO_THRESHOLD); + DUMP_REG(HDMI_NV_PDISP_AUDIO_CNTRL0); + DUMP_REG(HDMI_NV_PDISP_AUDIO_N); + DUMP_REG(HDMI_NV_PDISP_HDCPRIF_ROM_TIMING); + DUMP_REG(HDMI_NV_PDISP_SOR_REFCLK); + DUMP_REG(HDMI_NV_PDISP_CRC_CONTROL); + DUMP_REG(HDMI_NV_PDISP_INPUT_CONTROL); + DUMP_REG(HDMI_NV_PDISP_SCRATCH); + DUMP_REG(HDMI_NV_PDISP_PE_CURRENT); + DUMP_REG(HDMI_NV_PDISP_KEY_CTRL); + DUMP_REG(HDMI_NV_PDISP_KEY_DEBUG0); + DUMP_REG(HDMI_NV_PDISP_KEY_DEBUG1); + DUMP_REG(HDMI_NV_PDISP_KEY_DEBUG2); + DUMP_REG(HDMI_NV_PDISP_KEY_HDCP_KEY_0); + DUMP_REG(HDMI_NV_PDISP_KEY_HDCP_KEY_1); + DUMP_REG(HDMI_NV_PDISP_KEY_HDCP_KEY_2); + DUMP_REG(HDMI_NV_PDISP_KEY_HDCP_KEY_3); + DUMP_REG(HDMI_NV_PDISP_KEY_HDCP_KEY_TRIG); + DUMP_REG(HDMI_NV_PDISP_KEY_SKEY_INDEX); +} +#endif + +#define PIXCLOCK_TOLERANCE 200 + +static bool tegra_dc_hdmi_mode_equal(const struct fb_videomode *mode1, + const struct fb_videomode *mode2) +{ + int diff = (s64)mode1->pixclock - (s64)mode2->pixclock; + + return mode1->xres == mode2->xres && + mode1->yres == mode2->yres && + diff < PIXCLOCK_TOLERANCE && + diff > -PIXCLOCK_TOLERANCE && + mode1->vmode == mode2->vmode; +} + +static bool tegra_dc_hdmi_mode_filter(struct fb_videomode *mode) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(tegra_dc_hdmi_supported_modes); i++) { + if (tegra_dc_hdmi_mode_equal(&tegra_dc_hdmi_supported_modes[i], + mode)) + return true; + } + + return false; +} + + +static bool tegra_dc_hdmi_hpd(struct tegra_dc *dc) +{ + int sense; + int level; + + level = gpio_get_value(dc->out->hotplug_gpio); + + sense = dc->out->flags & TEGRA_DC_OUT_HOTPLUG_MASK; + + return (sense == TEGRA_DC_OUT_HOTPLUG_HIGH && level) || + (sense == TEGRA_DC_OUT_HOTPLUG_LOW && !level); +} + +static bool tegra_dc_hdmi_detect(struct tegra_dc *dc) +{ + struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc); + struct fb_monspecs specs; + int err; + + if (!tegra_dc_hdmi_hpd(dc)) + return false; + + err = tegra_edid_get_monspecs(hdmi->edid, &specs); + if (err < 0) { + dev_err(&dc->ndev->dev, "error reading edid\n"); + return false; + } + + tegra_fb_update_monspecs(dc->fb, &specs, tegra_dc_hdmi_mode_filter); + dev_info(&dc->ndev->dev, "display detected\n"); + return true; +} + + +static void tegra_dc_hdmi_detect_worker(struct work_struct *work) +{ + struct tegra_dc_hdmi_data *hdmi = + container_of(to_delayed_work(work), struct tegra_dc_hdmi_data, work); + struct tegra_dc *dc = hdmi->dc; + + if (tegra_dc_hdmi_hpd(dc)) + tegra_dc_hdmi_detect(dc); +} + +static irqreturn_t tegra_dc_hdmi_irq(int irq, void *ptr) +{ + struct tegra_dc *dc = ptr; + struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc); + + if (tegra_dc_hdmi_hpd(dc)) + schedule_delayed_work(&hdmi->work, msecs_to_jiffies(2000)); + + return IRQ_HANDLED; +} + +static int tegra_dc_hdmi_init(struct tegra_dc *dc) +{ + struct tegra_dc_hdmi_data *hdmi; + struct resource *res; + struct resource *base_res; + void __iomem *base; + struct clk *clk; + int err; + + hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL); + if (!hdmi) + return -ENOMEM; + + res = nvhost_get_resource_byname(dc->ndev, IORESOURCE_MEM, "hdmi_regs"); + if (!res) { + dev_err(&dc->ndev->dev, "hdmi: no mem resource\n"); + err = -ENOENT; + goto err_free_hdmi; + } + + base_res = request_mem_region(res->start, resource_size(res), dc->ndev->name); + if (!base_res) { + dev_err(&dc->ndev->dev, "hdmi: request_mem_region failed\n"); + err = -EBUSY; + goto err_free_hdmi; + } + + base = ioremap(res->start, resource_size(res)); + if (!base) { + dev_err(&dc->ndev->dev, "hdmi: registers can't be mapped\n"); + err = -EBUSY; + goto err_release_resource_reg; + } + + clk = clk_get(&dc->ndev->dev, "hdmi"); + if (IS_ERR_OR_NULL(clk)) { + dev_err(&dc->ndev->dev, "hdmi: can't get clock\n"); + err = -ENOENT; + goto err_iounmap_reg; + } + + /* TODO: support non-hotplug */ + if (request_irq(gpio_to_irq(dc->out->hotplug_gpio), tegra_dc_hdmi_irq, + IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + dev_name(&dc->ndev->dev), dc)) { + dev_err(&dc->ndev->dev, "hdmi: request_irq %d failed\n", + gpio_to_irq(dc->out->hotplug_gpio)); + err = -EBUSY; + goto err_put_clock; + } + + hdmi->edid = tegra_edid_create(dc->out->dcc_bus); + if (IS_ERR_OR_NULL(hdmi->edid)) { + dev_err(&dc->ndev->dev, "hdmi: can't create edid\n"); + err = PTR_ERR(hdmi->edid); + goto err_free_irq; + } + + INIT_DELAYED_WORK(&hdmi->work, tegra_dc_hdmi_detect_worker); + + hdmi->dc = dc; + hdmi->base = base; + hdmi->base_res = base_res; + hdmi->clk = clk; + + tegra_dc_set_outdata(dc, hdmi); + + return 0; + +err_free_irq: + free_irq(gpio_to_irq(dc->out->hotplug_gpio), dc); +err_put_clock: + clk_put(clk); +err_iounmap_reg: + iounmap(base); +err_release_resource_reg: + release_resource(base_res); +err_free_hdmi: + kfree(hdmi); + return err; +} + +static void tegra_dc_hdmi_destroy(struct tegra_dc *dc) +{ + struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc); + + free_irq(gpio_to_irq(dc->out->hotplug_gpio), dc); + cancel_delayed_work_sync(&hdmi->work); + iounmap(hdmi->base); + release_resource(hdmi->base_res); + clk_put(hdmi->clk); + tegra_edid_destroy(hdmi->edid); + + kfree(hdmi); + +} + +static void tegra_dc_hdmi_enable(struct tegra_dc *dc) +{ + struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc); + int pulse_start; + int dispclk_div_8_2; + int pll0; + int pll1; + int ds; + int retries; + unsigned long val; + + /* enbale power, clocks, resets, etc. */ + tegra_dc_setup_clk(dc, hdmi->clk); + clk_set_rate(hdmi->clk, dc->mode.pclk); + + clk_enable(hdmi->clk); + tegra_periph_reset_assert(hdmi->clk); + mdelay(1); + tegra_periph_reset_deassert(hdmi->clk); + + /* TODO: copy HDCP keys from KFUSE to HDMI */ + + /* Program display timing registers: handled by dc */ + + /* program HDMI registers and SOR sequencer */ + + tegra_dc_writel(dc, VSYNC_H_POSITION(1), DC_DISP_DISP_TIMING_OPTIONS); + tegra_dc_writel(dc, DITHER_CONTROL_DISABLE | BASE_COLOR_SIZE888, + DC_DISP_DISP_COLOR_CONTROL); + + /* video_preamble uses h_pulse2 */ + pulse_start = dc->mode.h_ref_to_sync + dc->mode.h_sync_width + + dc->mode.h_back_porch - 10; + tegra_dc_writel(dc, H_PULSE_2_ENABLE, DC_DISP_DISP_SIGNAL_OPTIONS0); + tegra_dc_writel(dc, + PULSE_MODE_NORMAL | + PULSE_POLARITY_HIGH | + PULSE_QUAL_VACTIVE | + PULSE_LAST_END_A, + DC_DISP_H_PULSE2_CONTROL); + tegra_dc_writel(dc, PULSE_START(pulse_start) | PULSE_END(pulse_start + 8), + DC_DISP_H_PULSE2_POSITION_A); + + tegra_hdmi_writel(hdmi, + VSYNC_WINDOW_END(0x210) | + VSYNC_WINDOW_START(0x200) | + VSYNC_WINDOW_ENABLE, + HDMI_NV_PDISP_HDMI_VSYNC_WINDOW); + + /* TODO: scale output to 16-235 */ + + tegra_hdmi_writel(hdmi, + (dc->ndev->id ? HDMI_SRC_DISPLAYB : HDMI_SRC_DISPLAYA) | + ARM_VIDEO_RANGE_LIMITED, + HDMI_NV_PDISP_INPUT_CONTROL); + + dispclk_div_8_2 = clk_get_rate(hdmi->clk) / 1000000 * 4; + tegra_hdmi_writel(hdmi, + SOR_REFCLK_DIV_INT(dispclk_div_8_2 >> 2) | + SOR_REFCLK_DIV_FRAC(dispclk_div_8_2), + HDMI_NV_PDISP_SOR_REFCLK); + + /* TODO: setup audio */ + + /* values from harmony board. Will be replaced when + * audio and avi are supported */ + tegra_hdmi_writel(hdmi, 0x00000001, 0x1e); + tegra_hdmi_writel(hdmi, 0x00000000, 0x20); + tegra_hdmi_writel(hdmi, 0x000000aa, 0x21); + tegra_hdmi_writel(hdmi, 0x00000001, 0x23); + tegra_hdmi_writel(hdmi, 0x00000001, 0x24); + tegra_hdmi_writel(hdmi, 0x00000000, 0x25); + tegra_hdmi_writel(hdmi, 0x000445eb, 0x26); + tegra_hdmi_writel(hdmi, 0x00000004, 0x27); + tegra_hdmi_writel(hdmi, 0x00002710, 0x2a); + tegra_hdmi_writel(hdmi, 0x00000000, 0x35); + tegra_hdmi_writel(hdmi, 0x0015bc10, 0x38); + tegra_hdmi_writel(hdmi, 0x04c4bb58, 0x39); + tegra_hdmi_writel(hdmi, 0x0263b9b6, 0x44); + tegra_hdmi_writel(hdmi, 0x00002713, 0x4f); + tegra_hdmi_writel(hdmi, 0x01e85426, 0x57); + tegra_hdmi_writel(hdmi, 0x001136c2, 0x89); + tegra_hdmi_writel(hdmi, 0x00000730, 0x8a); + tegra_hdmi_writel(hdmi, 0x0001875b, 0x8c); + tegra_hdmi_writel(hdmi, 0x00000000, 0x9d); + + tegra_hdmi_writel(hdmi, 0x40090038, HDMI_NV_PDISP_HDMI_CTRL); + tegra_hdmi_writel(hdmi, 0x0, HDMI_NV_PDISP_HDMI_GENERIC_CTRL); + + /* TMDS CONFIG */ + pll0 = 0x200033f; + pll1 = 0; + + pll0 &= ~SOR_PLL_PWR & ~SOR_PLL_VCOPD & ~SOR_PLL_PDBG & ~SOR_PLL_PDPORT & ~SOR_PLL_PULLDOWN & + ~SOR_PLL_VCOCAP(~0) & ~SOR_PLL_ICHPMP(~0); + pll0 |= SOR_PLL_RESISTORSEL; + + if (dc->mode.pclk <= 27000000) + pll0 |= SOR_PLL_VCOCAP(0); + else if (dc->mode.pclk <= 74250000) + pll0 |= SOR_PLL_VCOCAP(1); + else + pll0 |= SOR_PLL_VCOCAP(3); + + if (dc->mode.h_active == 1080) { + pll0 |= SOR_PLL_ICHPMP(1) | SOR_PLL_TX_REG_LOAD(3) | + SOR_PLL_TX_REG_LOAD(3) | SOR_PLL_BG_V17_S(3); + pll1 |= SOR_PLL_TMDS_TERM_ENABLE | SOR_PLL_PE_EN; + } else { + pll0 |= SOR_PLL_ICHPMP(2); + } + + tegra_hdmi_writel(hdmi, pll0, HDMI_NV_PDISP_SOR_PLL0); + tegra_hdmi_writel(hdmi, pll1, HDMI_NV_PDISP_SOR_PLL1); + + if (pll1 & SOR_PLL_PE_EN) { + tegra_hdmi_writel(hdmi, + PE_CURRENT0(0xf) | + PE_CURRENT1(0xf) | + PE_CURRENT2(0xf) | + PE_CURRENT3(0xf), + HDMI_NV_PDISP_PE_CURRENT); + } + + /* enable SOR */ + if (dc->mode.h_active == 1080) + ds = DRIVE_CURRENT_13_500_mA; + else + ds = DRIVE_CURRENT_5_250_mA; + + tegra_hdmi_writel(hdmi, + DRIVE_CURRENT_LANE0(ds) | + DRIVE_CURRENT_LANE1(ds) | + DRIVE_CURRENT_LANE2(ds) | + DRIVE_CURRENT_LANE3(ds) | + DRIVE_CURRENT_FUSE_OVERRIDE, + HDMI_NV_PDISP_SOR_LANE_DRIVE_CURRENT); + + tegra_hdmi_writel(hdmi, + SOR_SEQ_CTL_PU_PC(0) | + SOR_SEQ_PU_PC_ALT(0) | + SOR_SEQ_PD_PC(8) | + SOR_SEQ_PD_PC_ALT(8), + HDMI_NV_PDISP_SOR_SEQ_CTL); + + val = SOR_SEQ_INST_WAIT_TIME(1) | + SOR_SEQ_INST_WAIT_UNITS_VSYNC | + SOR_SEQ_INST_HALT | + SOR_SEQ_INST_PIN_A_LOW | + SOR_SEQ_INST_PIN_B_LOW | + SOR_SEQ_INST_DRIVE_PWM_OUT_LO; + + tegra_hdmi_writel(hdmi, val, HDMI_NV_PDISP_SOR_SEQ_INST0); + tegra_hdmi_writel(hdmi, val, HDMI_NV_PDISP_SOR_SEQ_INST8); + + val = 0x1c800; + val &= ~SOR_CSTM_ROTCLK(~0); + val |= SOR_CSTM_ROTCLK(2); + tegra_hdmi_writel(hdmi, val, HDMI_NV_PDISP_SOR_CSTM); + + + tegra_dc_writel(dc, DISP_CTRL_MODE_STOP, DC_CMD_DISPLAY_COMMAND); + tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL); + tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); + + + /* start SOR */ + tegra_hdmi_writel(hdmi, + SOR_PWR_NORMAL_STATE_PU | + SOR_PWR_NORMAL_START_NORMAL | + SOR_PWR_SAFE_STATE_PD | + SOR_PWR_SETTING_NEW_TRIGGER, + HDMI_NV_PDISP_SOR_PWR); + tegra_hdmi_writel(hdmi, + SOR_PWR_NORMAL_STATE_PU | + SOR_PWR_NORMAL_START_NORMAL | + SOR_PWR_SAFE_STATE_PD | + SOR_PWR_SETTING_NEW_DONE, + HDMI_NV_PDISP_SOR_PWR); + + retries = 1000; + do { + BUG_ON(--retries < 0); + val = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_SOR_PWR); + } while (val & SOR_PWR_SETTING_NEW_PENDING); + + tegra_hdmi_writel(hdmi, + SOR_STATE_ASY_CRCMODE_COMPLETE | + SOR_STATE_ASY_OWNER_HEAD0 | + SOR_STATE_ASY_SUBOWNER_BOTH | + SOR_STATE_ASY_PROTOCOL_SINGLE_TMDS_A | + /* TODO: to look at hsync polarity */ + SOR_STATE_ASY_HSYNCPOL_POS | + SOR_STATE_ASY_VSYNCPOL_POS | + SOR_STATE_ASY_DEPOL_POS, + HDMI_NV_PDISP_SOR_STATE2); + + val = SOR_STATE_ASY_HEAD_OPMODE_AWAKE | SOR_STATE_ASY_ORMODE_NORMAL; + tegra_hdmi_writel(hdmi, val, HDMI_NV_PDISP_SOR_STATE1); + + tegra_hdmi_writel(hdmi, 0, HDMI_NV_PDISP_SOR_STATE0); + tegra_hdmi_writel(hdmi, SOR_STATE_UPDATE, HDMI_NV_PDISP_SOR_STATE0); + tegra_hdmi_writel(hdmi, val | SOR_STATE_ATTACHED, + HDMI_NV_PDISP_SOR_STATE1); + tegra_hdmi_writel(hdmi, 0, HDMI_NV_PDISP_SOR_STATE0); + + tegra_dc_writel(dc, HDMI_ENABLE, DC_DISP_DISP_WIN_OPTIONS); + + tegra_dc_writel(dc, PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE | + PW4_ENABLE | PM0_ENABLE | PM1_ENABLE, + DC_CMD_DISPLAY_POWER_CONTROL); + + tegra_dc_writel(dc, DISP_CTRL_MODE_C_DISPLAY, DC_CMD_DISPLAY_COMMAND); + tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL); + tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); +} + +static void tegra_dc_hdmi_disable(struct tegra_dc *dc) +{ + struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc); + + tegra_periph_reset_assert(hdmi->clk); + clk_disable(hdmi->clk); +} +struct tegra_dc_out_ops tegra_dc_hdmi_ops = { + .init = tegra_dc_hdmi_init, + .destroy = tegra_dc_hdmi_destroy, + .enable = tegra_dc_hdmi_enable, + .disable = tegra_dc_hdmi_disable, + .detect = tegra_dc_hdmi_detect, +}; + diff --git a/drivers/video/tegra/dc/hdmi_reg.h b/drivers/video/tegra/dc/hdmi_reg.h new file mode 100644 index 000000000000..862f8d626467 --- /dev/null +++ b/drivers/video/tegra/dc/hdmi_reg.h @@ -0,0 +1,378 @@ +/* + * drivers/video/tegra/dc/hdmi_reg.h + * + * Copyright (C) 2010 Google, Inc. + * Author: Erik Gilling + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __DRIVERS_VIDEO_TEGRA_DC_HDMI_REG_H +#define __DRIVERS_VIDEO_TEGRA_DC_HDMI_REG_H + +#define HDMI_CTXSW 0x00 +#define HDMI_NV_PDISP_SOR_STATE0 0x01 +#define SOR_STATE_UPDATE (1 << 0) + +#define HDMI_NV_PDISP_SOR_STATE1 0x02 +#define SOR_STATE_ASY_HEAD_OPMODE_SLEEP (0 << 0) +#define SOR_STATE_ASY_HEAD_OPMODE_SNOOSE (1 << 0) +#define SOR_STATE_ASY_HEAD_OPMODE_AWAKE (2 << 0) +#define SOR_STATE_ASY_ORMODE_SAFE (0 << 2) +#define SOR_STATE_ASY_ORMODE_NORMAL (1 << 2) +#define SOR_STATE_ATTACHED (1 << 3) +#define SOR_STATE_ARM_SHOW_VGA (1 << 4) + +#define HDMI_NV_PDISP_SOR_STATE2 0x03 +#define SOR_STATE_ASY_OWNER_NONE (0 << 0) +#define SOR_STATE_ASY_OWNER_HEAD0 (1 << 0) +#define SOR_STATE_ASY_SUBOWNER_NONE (0 << 4) +#define SOR_STATE_ASY_SUBOWNER_SUBHEAD0 (1 << 4) +#define SOR_STATE_ASY_SUBOWNER_SUBHEAD1 (2 << 4) +#define SOR_STATE_ASY_SUBOWNER_BOTH (3 << 4) +#define SOR_STATE_ASY_CRCMODE_ACTIVE (0 << 6) +#define SOR_STATE_ASY_CRCMODE_COMPLETE (1 << 6) +#define SOR_STATE_ASY_CRCMODE_NON_ACTIVE (2 << 6) +#define SOR_STATE_ASY_PROTOCOL_SINGLE_TMDS_A (1 << 8) +#define SOR_STATE_ASY_PROTOCOL_CUSTOM (15 << 8) +#define SOR_STATE_ASY_HSYNCPOL_POS (0 << 12) +#define SOR_STATE_ASY_HSYNCPOL_NEG (1 << 12) +#define SOR_STATE_ASY_VSYNCPOL_POS (0 << 13) +#define SOR_STATE_ASY_VSYNCPOL_NEG (1 << 13) +#define SOR_STATE_ASY_DEPOL_POS (0 << 14) +#define SOR_STATE_ASY_DEPOL_NEG (1 << 14) + +#define HDMI_NV_PDISP_RG_HDCP_AN_MSB 0x04 +#define HDMI_NV_PDISP_RG_HDCP_AN_LSB 0x05 +#define HDMI_NV_PDISP_RG_HDCP_CN_MSB 0x06 +#define HDMI_NV_PDISP_RG_HDCP_CN_LSB 0x07 +#define HDMI_NV_PDISP_RG_HDCP_AKSV_MSB 0x08 +#define HDMI_NV_PDISP_RG_HDCP_AKSV_LSB 0x09 +#define HDMI_NV_PDISP_RG_HDCP_BKSV_MSB 0x0a +#define HDMI_NV_PDISP_RG_HDCP_BKSV_LSB 0x0b +#define HDMI_NV_PDISP_RG_HDCP_CKSV_MSB 0x0c +#define HDMI_NV_PDISP_RG_HDCP_CKSV_LSB 0x0d +#define HDMI_NV_PDISP_RG_HDCP_DKSV_MSB 0x0e +#define HDMI_NV_PDISP_RG_HDCP_DKSV_LSB 0x0f +#define HDMI_NV_PDISP_RG_HDCP_CTRL 0x10 +#define HDMI_NV_PDISP_RG_HDCP_CMODE 0x11 +#define HDMI_NV_PDISP_RG_HDCP_MPRIME_MSB 0x12 +#define HDMI_NV_PDISP_RG_HDCP_MPRIME_LSB 0x13 +#define HDMI_NV_PDISP_RG_HDCP_SPRIME_MSB 0x14 +#define HDMI_NV_PDISP_RG_HDCP_SPRIME_LSB2 0x15 +#define HDMI_NV_PDISP_RG_HDCP_SPRIME_LSB1 0x16 +#define HDMI_NV_PDISP_RG_HDCP_RI 0x17 +#define HDMI_NV_PDISP_RG_HDCP_CS_MSB 0x18 +#define HDMI_NV_PDISP_RG_HDCP_CS_LSB 0x19 +#define HDMI_NV_PDISP_HDMI_AUDIO_EMU0 0x1a +#define HDMI_NV_PDISP_HDMI_AUDIO_EMU_RDATA0 0x1b +#define HDMI_NV_PDISP_HDMI_AUDIO_EMU1 0x1c +#define HDMI_NV_PDISP_HDMI_AUDIO_EMU2 0x1d +#define HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_CTRL 0x1e +#define HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_STATUS 0x1f +#define HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_HEADER 0x20 +#define HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_SUBPACK0_LOW 0x21 +#define HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_SUBPACK0_HIGH 0x22 +#define HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_CTRL 0x23 +#define HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_STATUS 0x24 +#define HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_HEADER 0x25 +#define HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK0_LOW 0x26 +#define HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK0_HIGH 0x27 +#define HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK1_LOW 0x28 +#define HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK1_HIGH 0x29 +#define HDMI_NV_PDISP_HDMI_GENERIC_CTRL 0x2a +#define HDMI_NV_PDISP_HDMI_GENERIC_STATUS 0x2b +#define HDMI_NV_PDISP_HDMI_GENERIC_HEADER 0x2c +#define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK0_LOW 0x2d +#define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK0_HIGH 0x2e +#define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK1_LOW 0x2f +#define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK1_HIGH 0x30 +#define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK2_LOW 0x31 +#define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK2_HIGH 0x32 +#define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK3_LOW 0x33 +#define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK3_HIGH 0x34 +#define HDMI_NV_PDISP_HDMI_ACR_CTRL 0x35 +#define HDMI_NV_PDISP_HDMI_ACR_0320_SUBPACK_LOW 0x36 +#define HDMI_NV_PDISP_HDMI_ACR_0320_SUBPACK_HIGH 0x37 +#define HDMI_NV_PDISP_HDMI_ACR_0441_SUBPACK_LOW 0x38 +#define HDMI_NV_PDISP_HDMI_ACR_0441_SUBPACK_HIGH 0x39 +#define HDMI_NV_PDISP_HDMI_ACR_0882_SUBPACK_LOW 0x3a +#define HDMI_NV_PDISP_HDMI_ACR_0882_SUBPACK_HIGH 0x3b +#define HDMI_NV_PDISP_HDMI_ACR_1764_SUBPACK_LOW 0x3c +#define HDMI_NV_PDISP_HDMI_ACR_1764_SUBPACK_HIGH 0x3d +#define HDMI_NV_PDISP_HDMI_ACR_0480_SUBPACK_LOW 0x3e +#define HDMI_NV_PDISP_HDMI_ACR_0480_SUBPACK_HIGH 0x3f +#define HDMI_NV_PDISP_HDMI_ACR_0960_SUBPACK_LOW 0x40 +#define HDMI_NV_PDISP_HDMI_ACR_0960_SUBPACK_HIGH 0x41 +#define HDMI_NV_PDISP_HDMI_ACR_1920_SUBPACK_LOW 0x42 +#define HDMI_NV_PDISP_HDMI_ACR_1920_SUBPACK_HIGH 0x43 +#define HDMI_NV_PDISP_HDMI_CTRL 0x44 +#define HDMI_CTRL_REKEY(x) (((x) & 0x7f) << 0) +#define HDMI_CTRL_AUDIO_LAYOUT (1 << 8) +#define HDMI_CTRL_SAMPLE_FLAT (1 << 12) +#define HDMI_CTRL_MAX_AC_PACKET(x) (((x) & 0x1f) << 16) +#define HDMI_CTRL_ENABLE (1 << 30) + +#define HDMI_NV_PDISP_HDMI_VSYNC_KEEPOUT 0x45 +#define HDMI_NV_PDISP_HDMI_VSYNC_WINDOW 0x46 +#define VSYNC_WINDOW_END(x) (((x) & 0x3ff) << 0) +#define VSYNC_WINDOW_START(x) (((x) & 0x3ff) << 16) +#define VSYNC_WINDOW_ENABLE (1 << 31) + +#define HDMI_NV_PDISP_HDMI_GCP_CTRL 0x47 +#define HDMI_NV_PDISP_HDMI_GCP_STATUS 0x48 +#define HDMI_NV_PDISP_HDMI_GCP_SUBPACK 0x49 +#define HDMI_NV_PDISP_HDMI_CHANNEL_STATUS1 0x4a +#define HDMI_NV_PDISP_HDMI_CHANNEL_STATUS2 0x4b +#define HDMI_NV_PDISP_HDMI_EMU0 0x4c +#define HDMI_NV_PDISP_HDMI_EMU1 0x4d +#define HDMI_NV_PDISP_HDMI_EMU1_RDATA 0x4e +#define HDMI_NV_PDISP_HDMI_SPARE 0x4f +#define HDMI_NV_PDISP_HDMI_SPDIF_CHN_STATUS1 0x50 +#define HDMI_NV_PDISP_HDMI_SPDIF_CHN_STATUS2 0x51 +#define HDMI_NV_PDISP_HDCPRIF_ROM_CTRL 0x53 +#define HDMI_NV_PDISP_SOR_CAP 0x54 +#define HDMI_NV_PDISP_SOR_PWR 0x55 +#define SOR_PWR_NORMAL_STATE_PD (0 << 0) +#define SOR_PWR_NORMAL_STATE_PU (1 << 0) +#define SOR_PWR_NORMAL_START_NORMAL (0 << 1) +#define SOR_PWR_NORMAL_START_ALT (1 << 1) +#define SOR_PWR_SAFE_STATE_PD (0 << 16) +#define SOR_PWR_SAFE_STATE_PU (1 << 16) +#define SOR_PWR_SAFE_START_NORMAL (0 << 17) +#define SOR_PWR_SAFE_START_ALT (1 << 17) +#define SOR_PWR_HALT_DELAY (1 << 24) +#define SOR_PWR_MODE (1 << 28) +#define SOR_PWR_SETTING_NEW_DONE (0 << 31) +#define SOR_PWR_SETTING_NEW_PENDING (1 << 31) +#define SOR_PWR_SETTING_NEW_TRIGGER (1 << 31) + +#define HDMI_NV_PDISP_SOR_TEST 0x56 +#define HDMI_NV_PDISP_SOR_PLL0 0x57 +#define SOR_PLL_PWR (1 << 0) +#define SOR_PLL_PDBG (1 << 1) +#define SOR_PLL_VCOPD (1 << 2) +#define SOR_PLL_PDPORT (1 << 3) +#define SOR_PLL_RESISTORSEL (1 << 4) +#define SOR_PLL_PULLDOWN (1 << 5) +#define SOR_PLL_VCOCAP(x) (((x) & 0xf) << 8) +#define SOR_PLL_BG_V17_S(x) (((x) & 0xf) << 12) +#define SOR_PLL_FILTER(x) (((x) & 0xf) << 16) +#define SOR_PLL_ICHPMP(x) (((x) & 0xf) << 24) +#define SOR_PLL_TX_REG_LOAD(x) (((x) & 0x3) << 28) + +#define HDMI_NV_PDISP_SOR_PLL1 0x58 +#define SOR_PLL_TMDS_TERM_ENABLE (1 << 8) +#define SOR_PLL_TMDS_TERMADJ(x) (((x) & 0xf) << 9) +#define SOR_PLL_LOADADJ(x) (((x) & 0xf) << 20) +#define SOR_PLL_PE_EN (1 << 28) +#define SOR_PLL_HALF_FULL_PE (1 << 29) +#define SOR_PLL_S_D_PIN_PE (1 << 30) + +#define HDMI_NV_PDISP_SOR_PLL2 0x59 +#define HDMI_NV_PDISP_SOR_CSTM 0x5a +#define SOR_CSTM_PD_TXDA_0 (1 << 0) +#define SOR_CSTM_PD_TXDA_1 (1 << 1) +#define SOR_CSTM_PD_TXDA_2 (1 << 2) +#define SOR_CSTM_PD_TXDA_3 (1 << 3) +#define SOR_CSTM_PD_TXDB_0 (1 << 4) +#define SOR_CSTM_PD_TXDB_1 (1 << 5) +#define SOR_CSTM_PD_TXDB_2 (1 << 6) +#define SOR_CSTM_PD_TXDB_3 (1 << 7) +#define SOR_CSTM_PD_TXCA (1 << 8) +#define SOR_CSTM_PD_TXCB (1 << 9) +#define SOR_CSTM_UPPER (1 << 11) +#define SOR_CSTM_MODE(x) (((x) & 0x3) << 12) +#define SOR_CSTM_LINKACTA (1 << 14) +#define SOR_CSTM_LINKACTB (1 << 15) +#define SOR_CSTM_LVDS_EN (1 << 16) +#define SOR_CSTM_DUP_SYNC (1 << 17) +#define SOR_CSTM_NEW_MODE (1 << 18) +#define SOR_CSTM_BALANCED (1 << 19) +#define SOR_CSTM_PLLDIV (1 << 21) +#define SOR_CSTM_ROTCLK(x) (((x) & 0xf) << 24) +#define SOR_CSTM_ROTDAT(x) (((x) & 0x7) << 28) + +#define HDMI_NV_PDISP_SOR_LVDS 0x5b +#define HDMI_NV_PDISP_SOR_CRCA 0x5c +#define HDMI_NV_PDISP_SOR_CRCB 0x5d +#define HDMI_NV_PDISP_SOR_BLANK 0x5e +#define HDMI_NV_PDISP_SOR_SEQ_CTL 0x5f +#define SOR_SEQ_CTL_PU_PC(x) (((x) & 0xf) << 0) +#define SOR_SEQ_PU_PC_ALT(x) (((x) & 0xf) << 4) +#define SOR_SEQ_PD_PC(x) (((x) & 0xf) << 8) +#define SOR_SEQ_PD_PC_ALT(x) (((x) & 0xf) << 12) +#define SOR_SEQ_PC(x) (((x) & 0xf) << 16) +#define SOR_SEQ_STATUS (1 << 28) +#define SOR_SEQ_SWITCH (1 << 30) + +#define HDMI_NV_PDISP_SOR_SEQ_INST0 0x60 +#define HDMI_NV_PDISP_SOR_SEQ_INST1 0x61 +#define HDMI_NV_PDISP_SOR_SEQ_INST2 0x62 +#define HDMI_NV_PDISP_SOR_SEQ_INST3 0x63 +#define HDMI_NV_PDISP_SOR_SEQ_INST4 0x64 +#define HDMI_NV_PDISP_SOR_SEQ_INST5 0x65 +#define HDMI_NV_PDISP_SOR_SEQ_INST6 0x66 +#define HDMI_NV_PDISP_SOR_SEQ_INST7 0x67 +#define HDMI_NV_PDISP_SOR_SEQ_INST8 0x68 +#define HDMI_NV_PDISP_SOR_SEQ_INST9 0x69 +#define HDMI_NV_PDISP_SOR_SEQ_INSTA 0x6a +#define HDMI_NV_PDISP_SOR_SEQ_INSTB 0x6b +#define HDMI_NV_PDISP_SOR_SEQ_INSTC 0x6c +#define HDMI_NV_PDISP_SOR_SEQ_INSTD 0x6d +#define HDMI_NV_PDISP_SOR_SEQ_INSTE 0x6e +#define HDMI_NV_PDISP_SOR_SEQ_INSTF 0x6f +#define SOR_SEQ_INST_WAIT_TIME(x) (((x) & 0x3ff) << 0) +#define SOR_SEQ_INST_WAIT_UNITS_US (0 << 12) +#define SOR_SEQ_INST_WAIT_UNITS_MS (1 << 12) +#define SOR_SEQ_INST_WAIT_UNITS_VSYNC (2 << 12) +#define SOR_SEQ_INST_HALT (1 << 15) +#define SOR_SEQ_INST_PIN_A_LOW (0 << 21) +#define SOR_SEQ_INST_PIN_A_HIGH (1 << 21) +#define SOR_SEQ_INST_PIN_B_LOW (0 << 22) +#define SOR_SEQ_INST_PIN_B_HIGH (1 << 22) +#define SOR_SEQ_INST_DRIVE_PWM_OUT_LO (1 << 23) +#define SOR_SEQ_INST_TRISTATE_IOS (1 << 24) +#define SOR_SEQ_INST_SOR_SEQ_INST_BLACK_DATA (1 << 25) +#define SOR_SEQ_INST_BLANK_DE (1 << 26) +#define SOR_SEQ_INST_BLANK_H (1 << 27) +#define SOR_SEQ_INST_BLANK_V (1 << 28) +#define SOR_SEQ_INST_ASSERT_PLL_RESETV (1 << 29) +#define SOR_SEQ_INST_POWERDOWN_MACRO (1 << 30) +#define SOR_SEQ_INST_PLL_PULLDOWN (1 << 31) + +#define HDMI_NV_PDISP_SOR_VCRCA0 0x72 +#define HDMI_NV_PDISP_SOR_VCRCA1 0x73 +#define HDMI_NV_PDISP_SOR_CCRCA0 0x74 +#define HDMI_NV_PDISP_SOR_CCRCA1 0x75 +#define HDMI_NV_PDISP_SOR_EDATAA0 0x76 +#define HDMI_NV_PDISP_SOR_EDATAA1 0x77 +#define HDMI_NV_PDISP_SOR_COUNTA0 0x78 +#define HDMI_NV_PDISP_SOR_COUNTA1 0x79 +#define HDMI_NV_PDISP_SOR_DEBUGA0 0x7a +#define HDMI_NV_PDISP_SOR_DEBUGA1 0x7b +#define HDMI_NV_PDISP_SOR_TRIG 0x7c +#define HDMI_NV_PDISP_SOR_MSCHECK 0x7d +#define HDMI_NV_PDISP_SOR_LANE_DRIVE_CURRENT 0x7e +#define DRIVE_CURRENT_LANE0(x) (((x) & 0x3f) << 0) +#define DRIVE_CURRENT_LANE1(x) (((x) & 0x3f) << 8) +#define DRIVE_CURRENT_LANE2(x) (((x) & 0x3f) << 16) +#define DRIVE_CURRENT_LANE3(x) (((x) & 0x3f) << 24) +#define DRIVE_CURRENT_FUSE_OVERRIDE (1 << 31) +#define DRIVE_CURRENT_1_500_mA 0x00 +#define DRIVE_CURRENT_1_875_mA 0x01 +#define DRIVE_CURRENT_2_250_mA 0x02 +#define DRIVE_CURRENT_2_625_mA 0x03 +#define DRIVE_CURRENT_3_000_mA 0x04 +#define DRIVE_CURRENT_3_375_mA 0x05 +#define DRIVE_CURRENT_3_750_mA 0x06 +#define DRIVE_CURRENT_4_125_mA 0x07 +#define DRIVE_CURRENT_4_500_mA 0x08 +#define DRIVE_CURRENT_4_875_mA 0x09 +#define DRIVE_CURRENT_5_250_mA 0x0a +#define DRIVE_CURRENT_5_625_mA 0x0b +#define DRIVE_CURRENT_6_000_mA 0x0c +#define DRIVE_CURRENT_6_375_mA 0x0d +#define DRIVE_CURRENT_6_750_mA 0x0e +#define DRIVE_CURRENT_7_125_mA 0x0f +#define DRIVE_CURRENT_7_500_mA 0x10 +#define DRIVE_CURRENT_7_875_mA 0x11 +#define DRIVE_CURRENT_8_250_mA 0x12 +#define DRIVE_CURRENT_8_625_mA 0x13 +#define DRIVE_CURRENT_9_000_mA 0x14 +#define DRIVE_CURRENT_9_375_mA 0x15 +#define DRIVE_CURRENT_9_750_mA 0x16 +#define DRIVE_CURRENT_10_125_mA 0x17 +#define DRIVE_CURRENT_10_500_mA 0x18 +#define DRIVE_CURRENT_10_875_mA 0x19 +#define DRIVE_CURRENT_11_250_mA 0x1a +#define DRIVE_CURRENT_11_625_mA 0x1b +#define DRIVE_CURRENT_12_000_mA 0x1c +#define DRIVE_CURRENT_12_375_mA 0x1d +#define DRIVE_CURRENT_12_750_mA 0x1e +#define DRIVE_CURRENT_13_125_mA 0x1f +#define DRIVE_CURRENT_13_500_mA 0x20 +#define DRIVE_CURRENT_13_875_mA 0x21 +#define DRIVE_CURRENT_14_250_mA 0x22 +#define DRIVE_CURRENT_14_625_mA 0x23 +#define DRIVE_CURRENT_15_000_mA 0x24 +#define DRIVE_CURRENT_15_375_mA 0x25 +#define DRIVE_CURRENT_15_750_mA 0x26 +#define DRIVE_CURRENT_16_125_mA 0x27 +#define DRIVE_CURRENT_16_500_mA 0x28 +#define DRIVE_CURRENT_16_875_mA 0x29 +#define DRIVE_CURRENT_17_250_mA 0x2a +#define DRIVE_CURRENT_17_625_mA 0x2b +#define DRIVE_CURRENT_18_000_mA 0x2c +#define DRIVE_CURRENT_18_375_mA 0x2d +#define DRIVE_CURRENT_18_750_mA 0x2e +#define DRIVE_CURRENT_19_125_mA 0x2f +#define DRIVE_CURRENT_19_500_mA 0x30 +#define DRIVE_CURRENT_19_875_mA 0x31 +#define DRIVE_CURRENT_20_250_mA 0x32 +#define DRIVE_CURRENT_20_625_mA 0x33 +#define DRIVE_CURRENT_21_000_mA 0x34 +#define DRIVE_CURRENT_21_375_mA 0x35 +#define DRIVE_CURRENT_21_750_mA 0x36 +#define DRIVE_CURRENT_22_125_mA 0x37 +#define DRIVE_CURRENT_22_500_mA 0x38 +#define DRIVE_CURRENT_22_875_mA 0x39 +#define DRIVE_CURRENT_23_250_mA 0x3a +#define DRIVE_CURRENT_23_625_mA 0x3b +#define DRIVE_CURRENT_24_000_mA 0x3c +#define DRIVE_CURRENT_24_375_mA 0x3d +#define DRIVE_CURRENT_24_750_mA 0x3e + +#define HDMI_NV_PDISP_AUDIO_DEBUG0 0x7f +#define HDMI_NV_PDISP_AUDIO_DEBUG1 0x80 +#define HDMI_NV_PDISP_AUDIO_DEBUG2 0x81 +#define HDMI_NV_PDISP_AUDIO_FS1 0x82 +#define HDMI_NV_PDISP_AUDIO_FS2 0x83 +#define HDMI_NV_PDISP_AUDIO_FS3 0x84 +#define HDMI_NV_PDISP_AUDIO_FS4 0x85 +#define HDMI_NV_PDISP_AUDIO_FS5 0x86 +#define HDMI_NV_PDISP_AUDIO_FS6 0x87 +#define HDMI_NV_PDISP_AUDIO_FS7 0x88 +#define HDMI_NV_PDISP_AUDIO_PULSE_WIDTH 0x89 +#define HDMI_NV_PDISP_AUDIO_THRESHOLD 0x8a +#define HDMI_NV_PDISP_AUDIO_CNTRL0 0x8b +#define HDMI_NV_PDISP_AUDIO_N 0x8c +#define HDMI_NV_PDISP_HDCPRIF_ROM_TIMING 0x94 +#define HDMI_NV_PDISP_SOR_REFCLK 0x95 +#define SOR_REFCLK_DIV_INT(x) (((x) & 0xff) << 8) +#define SOR_REFCLK_DIV_FRAC(x) (((x) & 0x3) << 6) + +#define HDMI_NV_PDISP_CRC_CONTROL 0x96 +#define HDMI_NV_PDISP_INPUT_CONTROL 0x97 +#define HDMI_SRC_DISPLAYA (0 << 0) +#define HDMI_SRC_DISPLAYB (1 << 0) +#define ARM_VIDEO_RANGE_FULL (0 << 1) +#define ARM_VIDEO_RANGE_LIMITED (1 << 1) + +#define HDMI_NV_PDISP_SCRATCH 0x98 +#define HDMI_NV_PDISP_PE_CURRENT 0x99 +#define PE_CURRENT0(x) (((x) & 0xf) << 0) +#define PE_CURRENT1(x) (((x) & 0xf) << 8) +#define PE_CURRENT2(x) (((x) & 0xf) << 16) +#define PE_CURRENT3(x) (((x) & 0xf) << 24) + +#define HDMI_NV_PDISP_KEY_CTRL 0x9a +#define HDMI_NV_PDISP_KEY_DEBUG0 0x9b +#define HDMI_NV_PDISP_KEY_DEBUG1 0x9c +#define HDMI_NV_PDISP_KEY_DEBUG2 0x9d +#define HDMI_NV_PDISP_KEY_HDCP_KEY_0 0x9e +#define HDMI_NV_PDISP_KEY_HDCP_KEY_1 0x9f +#define HDMI_NV_PDISP_KEY_HDCP_KEY_2 0xa0 +#define HDMI_NV_PDISP_KEY_HDCP_KEY_3 0xa1 +#define HDMI_NV_PDISP_KEY_HDCP_KEY_TRIG 0xa2 +#define HDMI_NV_PDISP_KEY_SKEY_INDEX 0xa3 + +#endif -- 2.34.1