summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorDanny Nold <dannynold@freescale.com>2011-07-25 22:01:15 -0500
committerDanny Nold <dannynold@freescale.com>2011-07-26 21:14:10 -0500
commitfac969581b4829fbab56d15ed1876f9216f2a6ae (patch)
tree6e599dfea1f345f0afaff9f1df4a3ed5eedefa2c /drivers
parentd8a533a9be698c3abfb8f7fd0b2850afb85a3264 (diff)
ENGR00153670-4 - MXC HDMI: Add support for basic HDMI operation
- Add MXC HDMI to kconfig and makefile - Add initial mxc_hdmi.c file to provide basic HDMI functionality: - Basic HDMI output functional - Support for reading EDID via I2C and registering video modes with IPU - Support for output from IPU1 DI0 - These features not yet added: - Hotplug support - Dual display with LVDS - Power management - Support for FB notifications - Changes to IPU to allow HDMI to use source clocks that it needs Signed-off-by: Danny Nold <dannynold@freescale.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mxc/ipu3/ipu_disp.c7
-rw-r--r--drivers/video/Kconfig7
-rw-r--r--drivers/video/Makefile3
-rw-r--r--drivers/video/mxc_hdmi.c2690
4 files changed, 2704 insertions, 3 deletions
diff --git a/drivers/mxc/ipu3/ipu_disp.c b/drivers/mxc/ipu3/ipu_disp.c
index 38884c6705a4..fc28b3700a7f 100644
--- a/drivers/mxc/ipu3/ipu_disp.c
+++ b/drivers/mxc/ipu3/ipu_disp.c
@@ -18,6 +18,7 @@
*
* @ingroup IPU
*/
+
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/delay.h>
@@ -1042,7 +1043,7 @@ int32_t ipu_init_sync_panel(struct ipu_soc *ipu, int disp, uint32_t pixel_clk,
uint32_t field1_offset;
uint32_t reg;
uint32_t di_gen, vsync_cnt;
- uint32_t div, rounded_pixel_clk;
+ uint32_t div, rounded_pixel_clk, rounded_parent_clk;
uint32_t h_total, v_total;
int map;
struct clk *di_parent;
@@ -1084,7 +1085,9 @@ int32_t ipu_init_sync_panel(struct ipu_soc *ipu, int disp, uint32_t pixel_clk,
"ext di clk already in use, go back to internal clk\n");
else {
rounded_pixel_clk = pixel_clk * 2;
- while (rounded_pixel_clk < 150000000)
+ rounded_parent_clk = clk_round_rate(di_parent,
+ rounded_pixel_clk);
+ while (rounded_pixel_clk < rounded_parent_clk)
rounded_pixel_clk += pixel_clk * 2;
clk_set_rate(di_parent, rounded_pixel_clk);
rounded_pixel_clk =
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 7f2f9388135e..18321f0e3326 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2384,6 +2384,13 @@ if ARCH_MXC
source "drivers/video/mxc/Kconfig"
endif
+config FB_MXC_HDMI
+ depends on FB_MXC_SYNC_PANEL
+ tristate "MXC HDMI driver support"
+ help
+ Driver for the on-chip MXC HDMI controller.
+
+
if VT
source "drivers/video/console/Kconfig"
endif
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 4688dedf42a1..c10e82568655 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -47,7 +47,8 @@ obj-$(CONFIG_FB_VIA) += via/
obj-$(CONFIG_FB_KYRO) += kyro/
obj-$(CONFIG_FB_SAVAGE) += savage/
obj-$(CONFIG_FB_GEODE) += geode/
-obj-$(CONFIG_FB_MBX) += mbx/
+obj-$(CONFIG_FB_MBX) += mbx/
+obj-$(CONFIG_FB_MXC_HDMI) += mxc_hdmi.o
obj-$(CONFIG_FB_MXC) += mxc/
obj-$(CONFIG_FB_NEOMAGIC) += neofb.o
obj-$(CONFIG_FB_3DFX) += tdfxfb.o
diff --git a/drivers/video/mxc_hdmi.c b/drivers/video/mxc_hdmi.c
new file mode 100644
index 000000000000..35dec91c30e1
--- /dev/null
+++ b/drivers/video/mxc_hdmi.c
@@ -0,0 +1,2690 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+/*
+ * SH-Mobile High-Definition Multimedia Interface (HDMI) driver
+ * for SLISHDMI13T and SLIPHDMIT IP cores
+ *
+ * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/uaccess.h>
+#include <linux/cpufreq.h>
+#include <linux/firmware.h>
+#include <linux/kthread.h>
+#include <linux/regulator/driver.h>
+#include <linux/fsl_devices.h>
+#include <linux/ipu.h>
+
+#include <linux/console.h>
+#include <linux/types.h>
+
+#include <mach/mxc_edid.h>
+#include "mxc/mxc_dispdrv.h"
+
+#include <mach/mxc_hdmi.h>
+
+#define DISPDRV_HDMI "hdmi"
+#define HDMI_EDID_LEN 512
+
+#define TRUE 1
+#define FALSE 0
+
+#define NUM_CEA_VIDEO_MODES 64
+#define DEFAULT_VIDEO_MODE 16 /* 1080P */
+
+/* VIC = Video ID Code */
+static struct fb_videomode hdmi_cea_video_modes[NUM_CEA_VIDEO_MODES] = {
+ { /* 1 */
+ .xres = 640,
+ .yres = 480,
+ .refresh = 60,
+ },
+ {
+ .xres = 720,
+ .yres = 480,
+ .refresh = 60,
+ },
+ {
+ .xres = 720,
+ .yres = 480,
+ .refresh = 60,
+ },
+ {
+ .xres = 1280,
+ .yres = 720,
+ .refresh = 60,
+ },
+ {
+ .xres = 1920,
+ .yres = 1080,
+ .refresh = 60,
+ .flag = FB_VMODE_INTERLACED,
+ },
+ {
+ .xres = 720,
+ .yres = 480,
+ .refresh = 60,
+ .flag = FB_VMODE_INTERLACED,
+ },
+ {
+ .xres = 720,
+ .yres = 480,
+ .refresh = 60,
+ .flag = FB_VMODE_INTERLACED,
+ },
+ {
+ .xres = 720,
+ .yres = 240,
+ .refresh = 60,
+ },
+ {
+ .xres = 720,
+ .yres = 240,
+ .refresh = 60,
+ },
+ { /* 10 */
+ .xres = 2880,
+ .yres = 480,
+ .refresh = 60,
+ .flag = FB_VMODE_INTERLACED,
+ },
+ {
+ .xres = 2880,
+ .yres = 480,
+ .refresh = 60,
+ .flag = FB_VMODE_INTERLACED,
+ },
+ {
+ .xres = 2880,
+ .yres = 240,
+ .refresh = 60,
+ },
+ {
+ .xres = 2880,
+ .yres = 240,
+ .refresh = 60,
+ },
+ {
+ .xres = 1440,
+ .yres = 480,
+ .refresh = 60,
+ },
+ {
+ .xres = 1440,
+ .yres = 480,
+ .refresh = 60,
+ },
+ {
+ .xres = 1920,
+ .yres = 1080,
+ .refresh = 60,
+ },
+ {
+ .xres = 720,
+ .yres = 576,
+ .refresh = 50,
+ },
+ {
+ .xres = 720,
+ .yres = 576,
+ .refresh = 50,
+ },
+ {
+ .xres = 1280,
+ .yres = 720,
+ .refresh = 50,
+ },
+ { /* 20 */
+ .xres = 1920,
+ .yres = 1080,
+ .refresh = 50,
+ .flag = FB_VMODE_INTERLACED,
+ },
+ {
+ .xres = 720,
+ .yres = 576,
+ .refresh = 50,
+ .flag = FB_VMODE_INTERLACED,
+ },
+ {
+ .xres = 720,
+ .yres = 576,
+ .refresh = 50,
+ .flag = FB_VMODE_INTERLACED,
+ },
+ {
+ .xres = 720,
+ .yres = 288,
+ .refresh = 50,
+ },
+ {
+ .xres = 720,
+ .yres = 288,
+ .refresh = 50,
+ },
+ {
+ .xres = 2880,
+ .yres = 576,
+ .refresh = 50,
+ .flag = FB_VMODE_INTERLACED,
+ },
+ {
+ .xres = 2880,
+ .yres = 576,
+ .refresh = 50,
+ .flag = FB_VMODE_INTERLACED,
+ },
+ {
+ .xres = 2880,
+ .yres = 288,
+ .refresh = 50,
+ },
+ {
+ .xres = 2880,
+ .yres = 288,
+ .refresh = 50,
+ },
+ {
+ .xres = 1440,
+ .yres = 576,
+ .refresh = 50,
+ .flag = FB_VMODE_INTERLACED,
+ },
+ { /* 30 */
+ .xres = 1440,
+ .yres = 576,
+ .refresh = 50,
+ .flag = FB_VMODE_INTERLACED,
+ },
+ {
+ .xres = 1920,
+ .yres = 1080,
+ .refresh = 50,
+ },
+ {
+ .xres = 1920,
+ .yres = 1080,
+ .refresh = 24,
+ },
+ {
+ .xres = 1920,
+ .yres = 1080,
+ .refresh = 25,
+ },
+ {
+ .xres = 1920,
+ .yres = 1080,
+ .refresh = 30,
+ },
+ {
+ .xres = 2880,
+ .yres = 480,
+ .refresh = 60,
+ },
+ {
+ .xres = 2880,
+ .yres = 480,
+ .refresh = 60,
+ },
+ {
+ .xres = 2880,
+ .yres = 576,
+ .refresh = 50,
+ },
+ {
+ .xres = 2880,
+ .yres = 576,
+ .refresh = 50,
+ },
+ {
+ .xres = 1920,
+ .yres = 1080,
+ .refresh = 50,
+ .flag = FB_VMODE_INTERLACED,
+ },
+ { /* 40 */
+ .xres = 1920,
+ .yres = 1080,
+ .refresh = 100,
+ .flag = FB_VMODE_INTERLACED,
+ },
+ {
+ .xres = 1280,
+ .yres = 720,
+ .refresh = 100,
+ },
+ {
+ .xres = 720,
+ .yres = 576,
+ .refresh = 100,
+ },
+ {
+ .xres = 720,
+ .yres = 576,
+ .refresh = 100,
+ },
+ {
+ .xres = 720,
+ .yres = 576,
+ .refresh = 100,
+ .flag = FB_VMODE_INTERLACED,
+ },
+ {
+ .xres = 720,
+ .yres = 576,
+ .refresh = 100,
+ .flag = FB_VMODE_INTERLACED,
+ },
+ {
+ .xres = 1920,
+ .yres = 1080,
+ .refresh = 120,
+ .flag = FB_VMODE_INTERLACED,
+ },
+ {
+ .xres = 1280,
+ .yres = 720,
+ .refresh = 120,
+ },
+ {
+ .xres = 720,
+ .yres = 480,
+ .refresh = 120,
+ },
+ {
+ .xres = 720,
+ .yres = 480,
+ .refresh = 120,
+ },
+ { /* 50 */
+ .xres = 720,
+ .yres = 480,
+ .refresh = 120,
+ .flag = FB_VMODE_INTERLACED,
+ },
+ {
+ .xres = 720,
+ .yres = 480,
+ .refresh = 120,
+ .flag = FB_VMODE_INTERLACED,
+ },
+ {
+ .xres = 720,
+ .yres = 576,
+ .refresh = 200,
+ },
+ {
+ .xres = 720,
+ .yres = 576,
+ .refresh = 200,
+ },
+ {
+ .xres = 720,
+ .yres = 576,
+ .refresh = 200,
+ .flag = FB_VMODE_INTERLACED,
+ },
+ {
+ .xres = 720,
+ .yres = 576,
+ .refresh = 200,
+ .flag = FB_VMODE_INTERLACED,
+ },
+ {
+ .xres = 720,
+ .yres = 480,
+ .refresh = 240,
+ },
+ {
+ .xres = 720,
+ .yres = 480,
+ .refresh = 240,
+ },
+ {
+ .xres = 720,
+ .yres = 480,
+ .refresh = 240,
+ .flag = FB_VMODE_INTERLACED,
+ },
+ {
+ .xres = 720,
+ .yres = 480,
+ .refresh = 240,
+ .flag = FB_VMODE_INTERLACED,
+ },
+ { /* 60 */
+ .xres = 1280,
+ .yres = 720,
+ .refresh = 24,
+ },
+ {
+ .xres = 1280,
+ .yres = 720,
+ .refresh = 25,
+ },
+ {
+ .xres = 1280,
+ .yres = 720,
+ .refresh = 30,
+ },
+ {
+ .xres = 1920,
+ .yres = 1080,
+ .refresh = 120,
+ },
+ {
+ .xres = 1920,
+ .yres = 1080,
+ .refresh = 100,
+ },
+};
+
+enum hdmi_datamap {
+ RGB444_8B = 0x01,
+ RGB444_10B = 0x03,
+ RGB444_12B = 0x05,
+ RGB444_16B = 0x07,
+ YCbCr444_8B = 0x09,
+ YCbCr444_10B = 0x0B,
+ YCbCr444_12B = 0x0D,
+ YCbCr444_16B = 0x0F,
+ YCbCr422_8B = 0x16,
+ YCbCr422_10B = 0x14,
+ YCbCr422_12B = 0x12,
+};
+
+enum hdmi_csc_enc_format {
+ eRGB = 0x0,
+ eYCC444 = 0x01,
+ eYCC422 = 0x2,
+ eExtended = 0x3,
+};
+
+enum hdmi_colorimetry {
+ eITU601,
+ eITU709,
+};
+
+struct hdmi_vmode {
+ unsigned int mCode;
+ unsigned int mHdmiDviSel;
+ unsigned int mRVBlankInOSC;
+ unsigned int mRefreshRate;
+ unsigned int mHImageSize;
+ unsigned int mVImageSize;
+ unsigned int mHActive;
+ unsigned int mVActive;
+ unsigned int mHBlanking;
+ unsigned int mVBlanking;
+ unsigned int mHSyncOffset;
+ unsigned int mVSyncOffset;
+ unsigned int mHSyncPulseWidth;
+ unsigned int mVSyncPulseWidth;
+ unsigned int mHSyncPolarity;
+ unsigned int mVSyncPolarity;
+ unsigned int mDataEnablePolarity;
+ unsigned int mInterlaced;
+ unsigned int mPixelClock;
+ unsigned int mHBorder;
+ unsigned int mVBorder;
+ unsigned int mPixelRepetitionInput;
+};
+
+struct hdmi_data_info {
+ unsigned int enc_in_format;
+ unsigned int enc_out_format;
+ unsigned int enc_color_depth;
+ unsigned int colorimetry;
+ unsigned int pix_repet_factor;
+ unsigned int hdcp_enable;
+ struct hdmi_vmode video_mode;
+};
+
+enum hotplug_state {
+ HDMI_HOTPLUG_DISCONNECTED,
+ HDMI_HOTPLUG_CONNECTED,
+ HDMI_HOTPLUG_EDID_DONE,
+};
+
+struct mxc_hdmi {
+ void __iomem *base;
+ enum hotplug_state hp_state; /* hot-plug status */
+
+ struct regulator *io_reg;
+ struct regulator *analog_reg;
+ struct mxc_dispdrv_entry *disp_mxc_hdmi;
+ struct hdmi_data_info hdmi_data;
+ struct clk *hdmi_clk;
+
+ struct mxc_edid_cfg edid_cfg;
+ u8 edid[HDMI_EDID_LEN];
+
+ struct platform_device *pdev;
+ struct fb_info *fbi;
+ struct mutex mutex; /* Protect the info pointer */
+ struct delayed_work edid_work;
+ struct fb_var_screeninfo var;
+ struct fb_monspecs monspec;
+ struct notifier_block nb;
+};
+
+struct i2c_client *hdmi_i2c;
+
+static irqreturn_t mxc_hdmi_hotplug(int irq, void *dev_id)
+{
+}
+
+/*!
+ * this submodule is responsible for the video/audio data composition.
+ */
+void hdmi_set_video_mode(struct hdmi_vmode *vmode)
+{
+ vmode->mHBorder = 0;
+ vmode->mVBorder = 0;
+ vmode->mPixelRepetitionInput = 0;
+ vmode->mHImageSize = 16;
+ vmode->mVImageSize = 9;
+
+ switch (vmode->mCode) {
+ case 1: /* 640x480p @ 59.94/60Hz 4:3 */
+ vmode->mHImageSize = 4;
+ vmode->mVImageSize = 3;
+ vmode->mHActive = 640;
+ vmode->mVActive = 480;
+ vmode->mHBlanking = 160;
+ vmode->mVBlanking = 45;
+ vmode->mHSyncOffset = 16;
+ vmode->mVSyncOffset = 10;
+ vmode->mHSyncPulseWidth = 96;
+ vmode->mVSyncPulseWidth = 2;
+ vmode->mHSyncPolarity = vmode->mVSyncPolarity = FALSE;
+ vmode->mInterlaced = FALSE; /* not(progressive_nI) */
+ vmode->mPixelClock =
+ (vmode->mRefreshRate == 59940) ? 2517 : 2520;
+ break;
+ case 2: /* 720x480p @ 59.94/60Hz 4:3 */
+ vmode->mHImageSize = 4;
+ vmode->mVImageSize = 3;
+ case 3: /* 720x480p @ 59.94/60Hz 16:9 */
+ vmode->mHActive = 720;
+ vmode->mVActive = 480;
+ vmode->mHBlanking = 138;
+ vmode->mVBlanking = 45;
+ vmode->mHSyncOffset = 16;
+ vmode->mVSyncOffset = 9;
+ vmode->mHSyncPulseWidth = 62;
+ vmode->mVSyncPulseWidth = 6;
+ vmode->mHSyncPolarity = vmode->mVSyncPolarity = FALSE;
+ vmode->mInterlaced = FALSE;
+ vmode->mPixelClock =
+ (vmode->mRefreshRate == 59940) ? 2700 : 2702;
+ break;
+ case 4: /* 1280x720p @ 59.94/60Hz 16:9 */
+ vmode->mHActive = 1280;
+ vmode->mVActive = 720;
+ vmode->mHBlanking = 370;
+ vmode->mVBlanking = 30;
+ vmode->mHSyncOffset = 110;
+ vmode->mVSyncOffset = 5;
+ vmode->mHSyncPulseWidth = 40;
+ vmode->mVSyncPulseWidth = 5;
+ vmode->mHSyncPolarity = vmode->mVSyncPolarity = TRUE;
+ vmode->mInterlaced = FALSE;
+ vmode->mPixelClock =
+ (vmode->mRefreshRate == 59940) ? 7417 : 7425;
+ break;
+ case 5: /* 1920x1080i @ 59.94/60Hz 16:9 */
+ vmode->mHActive = 1920;
+ vmode->mVActive = 540;
+ vmode->mHBlanking = 280;
+ vmode->mVBlanking = 22;
+ vmode->mHSyncOffset = 88;
+ vmode->mVSyncOffset = 2;
+ vmode->mHSyncPulseWidth = 44;
+ vmode->mVSyncPulseWidth = 5;
+ vmode->mHSyncPolarity = vmode->mVSyncPolarity = TRUE;
+ vmode->mInterlaced = TRUE;
+ vmode->mPixelClock =
+ (vmode->mRefreshRate == 59940) ? 7417 : 7425;
+ break;
+ case 6: /* 720(1440)x480i @ 59.94/60Hz 4:3 */
+ vmode->mHImageSize = 4;
+ vmode->mVImageSize = 3;
+ case 7: /* 720(1440)x480i @ 59.94/60Hz 16:9 */
+ vmode->mHActive = 1440;
+ vmode->mVActive = 240;
+ vmode->mHBlanking = 276;
+ vmode->mVBlanking = 22;
+ vmode->mHSyncOffset = 38;
+ vmode->mVSyncOffset = 4;
+ vmode->mHSyncPulseWidth = 124;
+ vmode->mVSyncPulseWidth = 3;
+ vmode->mHSyncPolarity = vmode->mVSyncPolarity = FALSE;
+ vmode->mInterlaced = TRUE;
+ vmode->mPixelClock =
+ (vmode->mRefreshRate == 59940) ? 2700 : 2702;
+ vmode->mPixelRepetitionInput = 1;
+ break;
+ case 8: /* 720(1440)x240p @ 59.826/60.054/59.886/60.115Hz 4:3 */
+ vmode->mHImageSize = 4;
+ vmode->mVImageSize = 3;
+ case 9: /* 720(1440)x240p @ 59.826/60.054/59.886/60.115Hz 16:9 */
+ vmode->mHActive = 1440;
+ vmode->mVActive = 240;
+ vmode->mHBlanking = 276;
+ vmode->mVBlanking = (vmode->mRefreshRate > 60000) ? 22 : 23;
+ vmode->mHSyncOffset = 38;
+ vmode->mVSyncOffset = (vmode->mRefreshRate > 60000) ? 4 : 5;
+ vmode->mHSyncPulseWidth = 124;
+ vmode->mVSyncPulseWidth = 3;
+ vmode->mHSyncPolarity = vmode->mVSyncPolarity = FALSE;
+ vmode->mInterlaced = FALSE;
+ vmode->mPixelClock =
+ ((vmode->mRefreshRate == 60054) ||
+ vmode->mRefreshRate == 59826)
+ ? 2700 : 2702; /* else 60.115/59.886 Hz */
+ vmode->mPixelRepetitionInput = 1;
+ break;
+ case 10: /* 2880x480i @ 59.94/60Hz 4:3 */
+ vmode->mHImageSize = 4;
+ vmode->mVImageSize = 3;
+ case 11: /* 2880x480i @ 59.94/60Hz 16:9 */
+ vmode->mHActive = 2880;
+ vmode->mVActive = 240;
+ vmode->mHBlanking = 552;
+ vmode->mVBlanking = 22;
+ vmode->mHSyncOffset = 76;
+ vmode->mVSyncOffset = 4;
+ vmode->mHSyncPulseWidth = 248;
+ vmode->mVSyncPulseWidth = 3;
+ vmode->mHSyncPolarity = vmode->mVSyncPolarity = FALSE;
+ vmode->mInterlaced = TRUE;
+ vmode->mPixelClock =
+ (vmode->mRefreshRate == 59940) ? 5400 : 5405;
+ break;
+ case 12: /* 2880x240p @ 59.826/60.054/59.886/60.115Hz 4:3 */
+ vmode->mHImageSize = 4;
+ vmode->mVImageSize = 3;
+ case 13: /* 2880x240p @ 59.826/60.054/59.886/60.115Hz 16:9 */
+ vmode->mHActive = 2880;
+ vmode->mVActive = 240;
+ vmode->mHBlanking = 552;
+ vmode->mVBlanking = (vmode->mRefreshRate > 60000) ? 22 : 23;
+ vmode->mHSyncOffset = 76;
+ vmode->mVSyncOffset = (vmode->mRefreshRate > 60000) ? 4 : 5;
+ vmode->mHSyncPulseWidth = 248;
+ vmode->mVSyncPulseWidth = 3;
+ vmode->mHSyncPolarity = vmode->mVSyncPolarity = FALSE;
+ vmode->mInterlaced = FALSE;
+ vmode->mPixelClock =
+ ((vmode->mRefreshRate == 60054) ||
+ vmode->mRefreshRate == 59826)
+ ? 5400 : 5405; /* else 60.115/59.886 Hz */
+ break;
+ case 14: /* 1440x480p @ 59.94/60Hz 4:3 */
+ vmode->mHImageSize = 4;
+ vmode->mVImageSize = 3;
+ case 15: /* 1440x480p @ 59.94/60Hz 16:9 */
+ vmode->mHActive = 1440;
+ vmode->mVActive = 480;
+ vmode->mHBlanking = 276;
+ vmode->mVBlanking = 45;
+ vmode->mHSyncOffset = 32;
+ vmode->mVSyncOffset = 9;
+ vmode->mHSyncPulseWidth = 124;
+ vmode->mVSyncPulseWidth = 6;
+ vmode->mHSyncPolarity = vmode->mVSyncPolarity = FALSE;
+ vmode->mInterlaced = FALSE;
+ vmode->mPixelClock =
+ (vmode->mRefreshRate == 59940) ? 5400 : 5405;
+ break;
+ case 16: /* 1920x1080p @ 59.94/60Hz 16:9 */
+ vmode->mHActive = 1920;
+ vmode->mVActive = 1080;
+ vmode->mHBlanking = 280;
+ vmode->mVBlanking = 45;
+ vmode->mHSyncOffset = 88;
+ vmode->mVSyncOffset = 4;
+ vmode->mHSyncPulseWidth = 44;
+ vmode->mVSyncPulseWidth = 5;
+ vmode->mHSyncPolarity = vmode->mVSyncPolarity = TRUE;
+ vmode->mInterlaced = FALSE;
+ vmode->mPixelClock =
+ (vmode->mRefreshRate == 59940) ? 14835 : 14850;
+ break;
+ case 17: /* 720x576p @ 50Hz 4:3 */
+ vmode->mHImageSize = 4;
+ vmode->mVImageSize = 3;
+ case 18: /* 720x576p @ 50Hz 16:9 */
+ vmode->mHActive = 720;
+ vmode->mVActive = 576;
+ vmode->mHBlanking = 144;
+ vmode->mVBlanking = 49;
+ vmode->mHSyncOffset = 12;
+ vmode->mVSyncOffset = 5;
+ vmode->mHSyncPulseWidth = 64;
+ vmode->mVSyncPulseWidth = 5;
+ vmode->mHSyncPolarity = vmode->mVSyncPolarity = FALSE;
+ vmode->mInterlaced = FALSE;
+ vmode->mPixelClock = 2700;
+ break;
+ case 19: /* 1280x720p @ 50Hz 16:9 */
+ vmode->mHActive = 1280;
+ vmode->mVActive = 720;
+ vmode->mHBlanking = 700;
+ vmode->mVBlanking = 30;
+ vmode->mHSyncOffset = 440;
+ vmode->mVSyncOffset = 5;
+ vmode->mHSyncPulseWidth = 40;
+ vmode->mVSyncPulseWidth = 5;
+ vmode->mHSyncPolarity = vmode->mVSyncPolarity = TRUE;
+ vmode->mInterlaced = FALSE;
+ vmode->mPixelClock = 7425;
+ break;
+ case 20: /* 1920x1080i @ 50Hz 16:9 */
+ vmode->mHActive = 1920;
+ vmode->mVActive = 540;
+ vmode->mHBlanking = 720;
+ vmode->mVBlanking = 22;
+ vmode->mHSyncOffset = 528;
+ vmode->mVSyncOffset = 2;
+ vmode->mHSyncPulseWidth = 44;
+ vmode->mVSyncPulseWidth = 5;
+ vmode->mHSyncPolarity = vmode->mVSyncPolarity = TRUE;
+ vmode->mInterlaced = TRUE;
+ vmode->mPixelClock = 7425;
+ break;
+ case 21: /* 720(1440)x576i @ 50Hz 4:3 */
+ vmode->mHImageSize = 4;
+ vmode->mVImageSize = 3;
+ case 22: /* 720(1440)x576i @ 50Hz 16:9 */
+ vmode->mHActive = 1440;
+ vmode->mVActive = 288;
+ vmode->mHBlanking = 288;
+ vmode->mVBlanking = 24;
+ vmode->mHSyncOffset = 24;
+ vmode->mVSyncOffset = 2;
+ vmode->mHSyncPulseWidth = 126;
+ vmode->mVSyncPulseWidth = 3;
+ vmode->mHSyncPolarity = vmode->mVSyncPolarity = FALSE;
+ vmode->mInterlaced = TRUE;
+ vmode->mPixelClock = 2700;
+ vmode->mPixelRepetitionInput = 1;
+ break;
+ case 23: /* 720(1440)x288p @ 50Hz 4:3 */
+ vmode->mHImageSize = 4;
+ vmode->mVImageSize = 3;
+ case 24: /* 720(1440)x288p @ 50Hz 16:9 */
+ vmode->mHActive = 1440;
+ vmode->mVActive = 288;
+ vmode->mHBlanking = 288;
+ vmode->mVBlanking =
+ (vmode->mRefreshRate == 50080) ?
+ 24 : ((vmode->mRefreshRate == 49920) ? 25 : 26);
+ vmode->mHSyncOffset = 24;
+ vmode->mVSyncOffset =
+ (vmode->mRefreshRate == 50080) ?
+ 2 : ((vmode->mRefreshRate == 49920) ? 3 : 4);
+ vmode->mHSyncPulseWidth = 126;
+ vmode->mVSyncPulseWidth = 3;
+ vmode->mHSyncPolarity = vmode->mVSyncPolarity = FALSE;
+ vmode->mInterlaced = FALSE;
+ vmode->mPixelClock = 2700;
+ vmode->mPixelRepetitionInput = 1;
+ break;
+ case 25: /* 2880x576i @ 50Hz 4:3 */
+ vmode->mHImageSize = 4;
+ vmode->mVImageSize = 3;
+ case 26: /* 2880x576i @ 50Hz 16:9 */
+ vmode->mHActive = 2880;
+ vmode->mVActive = 288;
+ vmode->mHBlanking = 576;
+ vmode->mVBlanking = 24;
+ vmode->mHSyncOffset = 48;
+ vmode->mVSyncOffset = 2;
+ vmode->mHSyncPulseWidth = 252;
+ vmode->mVSyncPulseWidth = 3;
+ vmode->mHSyncPolarity = vmode->mVSyncPolarity = FALSE;
+ vmode->mInterlaced = TRUE;
+ vmode->mPixelClock = 5400;
+ break;
+ case 27: /* 2880x288p @ 50Hz 4:3 */
+ vmode->mHImageSize = 4;
+ vmode->mVImageSize = 3;
+ case 28: /* 2880x288p @ 50Hz 16:9 */
+ vmode->mHActive = 2880;
+ vmode->mVActive = 288;
+ vmode->mHBlanking = 576;
+ vmode->mVBlanking =
+ (vmode->mRefreshRate == 50080) ?
+ 24 : ((vmode->mRefreshRate == 49920) ? 25 : 26);
+ vmode->mHSyncOffset = 48;
+ vmode->mVSyncOffset =
+ (vmode->mRefreshRate == 50080) ?
+ 2 : ((vmode->mRefreshRate == 49920) ? 3 : 4);
+ vmode->mHSyncPulseWidth = 252;
+ vmode->mVSyncPulseWidth = 3;
+ vmode->mHSyncPolarity = vmode->mVSyncPolarity = FALSE;
+ vmode->mInterlaced = FALSE;
+ vmode->mPixelClock = 5400;
+ break;
+ case 29: /* 1440x576p @ 50Hz 4:3 */
+ vmode->mHImageSize = 4;
+ vmode->mVImageSize = 3;
+ case 30: /* 1440x576p @ 50Hz 16:9 */
+ vmode->mHActive = 1440;
+ vmode->mVActive = 576;
+ vmode->mHBlanking = 288;
+ vmode->mVBlanking = 49;
+ vmode->mHSyncOffset = 24;
+ vmode->mVSyncOffset = 5;
+ vmode->mHSyncPulseWidth = 128;
+ vmode->mVSyncPulseWidth = 5;
+ vmode->mHSyncPolarity = vmode->mVSyncPolarity = FALSE;
+ vmode->mInterlaced = FALSE;
+ vmode->mPixelClock = 5400;
+ break;
+ case 31: /* 1920x1080p @ 50Hz 16:9 */
+ vmode->mHActive = 1920;
+ vmode->mVActive = 1080;
+ vmode->mHBlanking = 720;
+ vmode->mVBlanking = 45;
+ vmode->mHSyncOffset = 528;
+ vmode->mVSyncOffset = 4;
+ vmode->mHSyncPulseWidth = 44;
+ vmode->mVSyncPulseWidth = 5;
+ vmode->mHSyncPolarity = vmode->mVSyncPolarity = TRUE;
+ vmode->mInterlaced = FALSE;
+ vmode->mPixelClock = 14850;
+ break;
+ case 32: /* 1920x1080p @ 23.976/24Hz 16:9 */
+ vmode->mHActive = 1920;
+ vmode->mVActive = 1080;
+ vmode->mHBlanking = 830;
+ vmode->mVBlanking = 45;
+ vmode->mHSyncOffset = 638;
+ vmode->mVSyncOffset = 4;
+ vmode->mHSyncPulseWidth = 44;
+ vmode->mVSyncPulseWidth = 5;
+ vmode->mHSyncPolarity = vmode->mVSyncPolarity = TRUE;
+ vmode->mInterlaced = FALSE;
+ vmode->mPixelClock =
+ (vmode->mRefreshRate == 23976) ? 7417 : 7425;
+ break;
+ case 33: /* 1920x1080p @ 25Hz 16:9 */
+ vmode->mHActive = 1920;
+ vmode->mVActive = 1080;
+ vmode->mHBlanking = 720;
+ vmode->mVBlanking = 45;
+ vmode->mHSyncOffset = 528;
+ vmode->mVSyncOffset = 4;
+ vmode->mHSyncPulseWidth = 44;
+ vmode->mVSyncPulseWidth = 5;
+ vmode->mHSyncPolarity = vmode->mVSyncPolarity = TRUE;
+ vmode->mInterlaced = FALSE;
+ vmode->mPixelClock = 7425;
+ break;
+ case 34: /* 1920x1080p @ 29.97/30Hz 16:9 */
+ vmode->mHActive = 1920;
+ vmode->mVActive = 1080;
+ vmode->mHBlanking = 280;
+ vmode->mVBlanking = 45;
+ vmode->mHSyncOffset = 88;
+ vmode->mVSyncOffset = 4;
+ vmode->mHSyncPulseWidth = 44;
+ vmode->mVSyncPulseWidth = 5;
+ vmode->mHSyncPolarity = vmode->mVSyncPolarity = TRUE;
+ vmode->mInterlaced = FALSE;
+ vmode->mPixelClock =
+ (vmode->mRefreshRate == 29970) ? 7417 : 7425;
+ break;
+ case 35: /* 2880x480p @ 60Hz 4:3 */
+ vmode->mHImageSize = 4;
+ vmode->mVImageSize = 3;
+ case 36: /* 2880x480p @ 60Hz 16:9 */
+ vmode->mHActive = 2880;
+ vmode->mVActive = 480;
+ vmode->mHBlanking = 552;
+ vmode->mVBlanking = 45;
+ vmode->mHSyncOffset = 64;
+ vmode->mVSyncOffset = 9;
+ vmode->mHSyncPulseWidth = 248;
+ vmode->mVSyncPulseWidth = 6;
+ vmode->mHSyncPolarity = vmode->mVSyncPolarity = FALSE;
+ vmode->mInterlaced = FALSE;
+ vmode->mPixelClock =
+ (vmode->mRefreshRate == 59940) ? 10800 : 10810;
+ break;
+ case 37: /* 2880x576p @ 50Hz 4:3 */
+ vmode->mHImageSize = 4;
+ vmode->mVImageSize = 3;
+ case 38: /* 2880x576p @ 50Hz 16:9 */
+ vmode->mHActive = 2880;
+ vmode->mVActive = 576;
+ vmode->mHBlanking = 576;
+ vmode->mVBlanking = 49;
+ vmode->mHSyncOffset = 48;
+ vmode->mVSyncOffset = 5;
+ vmode->mHSyncPulseWidth = 256;
+ vmode->mVSyncPulseWidth = 5;
+ vmode->mHSyncPolarity = vmode->mVSyncPolarity = FALSE;
+ vmode->mInterlaced = FALSE;
+ vmode->mPixelClock = 10800;
+ break;
+ case 39: /* 1920x1080i (1250 total) @ 50Hz 16:9 */
+ vmode->mHActive = 1920;
+ vmode->mVActive = 540;
+ vmode->mHBlanking = 384;
+ vmode->mVBlanking = 85;
+ vmode->mHSyncOffset = 32;
+ vmode->mVSyncOffset = 23;
+ vmode->mHSyncPulseWidth = 168;
+ vmode->mVSyncPulseWidth = 5;
+ vmode->mHSyncPolarity = vmode->mVSyncPolarity = TRUE;
+ vmode->mInterlaced = TRUE;
+ vmode->mPixelClock = 7200;
+ break;
+ case 40: /* 1920x1080i @ 100Hz 16:9 */
+ vmode->mHActive = 1920;
+ vmode->mVActive = 540;
+ vmode->mHBlanking = 720;
+ vmode->mVBlanking = 22;
+ vmode->mHSyncOffset = 528;
+ vmode->mVSyncOffset = 2;
+ vmode->mHSyncPulseWidth = 44;
+ vmode->mVSyncPulseWidth = 5;
+ vmode->mHSyncPolarity = vmode->mVSyncPolarity = TRUE;
+ vmode->mInterlaced = TRUE;
+ vmode->mPixelClock = 14850;
+ break;
+ case 41: /* 1280x720p @ 100Hz 16:9 */
+ vmode->mHActive = 1280;
+ vmode->mVActive = 720;
+ vmode->mHBlanking = 700;
+ vmode->mVBlanking = 30;
+ vmode->mHSyncOffset = 440;
+ vmode->mVSyncOffset = 5;
+ vmode->mHSyncPulseWidth = 40;
+ vmode->mVSyncPulseWidth = 5;
+ vmode->mHSyncPolarity = vmode->mVSyncPolarity = TRUE;
+ vmode->mInterlaced = FALSE;
+ vmode->mPixelClock = 14850;
+ break;
+ case 42: /* 720x576p @ 100Hz 4:3 */
+ vmode->mHImageSize = 4;
+ vmode->mVImageSize = 3;
+ case 43: /* 720x576p @ 100Hz 16:9 */
+ vmode->mHActive = 720;
+ vmode->mVActive = 576;
+ vmode->mHBlanking = 144;
+ vmode->mVBlanking = 49;
+ vmode->mHSyncOffset = 12;
+ vmode->mVSyncOffset = 5;
+ vmode->mHSyncPulseWidth = 64;
+ vmode->mVSyncPulseWidth = 5;
+ vmode->mHSyncPolarity = vmode->mVSyncPolarity = FALSE;
+ vmode->mInterlaced = FALSE;
+ vmode->mPixelClock = 5400;
+ break;
+ case 44: /* 720(1440)x576i @ 100Hz 4:3 */
+ vmode->mHImageSize = 4;
+ vmode->mVImageSize = 3;
+ case 45: /* 720(1440)x576i @ 100Hz 16:9 */
+ vmode->mHActive = 1440;
+ vmode->mVActive = 288;
+ vmode->mHBlanking = 288;
+ vmode->mVBlanking = 24;
+ vmode->mHSyncOffset = 24;
+ vmode->mVSyncOffset = 2;
+ vmode->mHSyncPulseWidth = 126;
+ vmode->mVSyncPulseWidth = 3;
+ vmode->mHSyncPolarity = vmode->mVSyncPolarity = FALSE;
+ vmode->mInterlaced = TRUE;
+ vmode->mPixelClock = 5400;
+ vmode->mPixelRepetitionInput = 1;
+ break;
+ case 46: /* 1920x1080i @ 119.88/120Hz 16:9 */
+ vmode->mHActive = 1920;
+ vmode->mVActive = 540;
+ vmode->mHBlanking = 288;
+ vmode->mVBlanking = 22;
+ vmode->mHSyncOffset = 88;
+ vmode->mVSyncOffset = 2;
+ vmode->mHSyncPulseWidth = 44;
+ vmode->mVSyncPulseWidth = 5;
+ vmode->mHSyncPolarity = vmode->mVSyncPolarity = TRUE;
+ vmode->mInterlaced = TRUE;
+ vmode->mPixelClock =
+ (vmode->mRefreshRate == 119880) ? 14835 : 14850;
+ break;
+ case 47: /* 1280x720p @ 119.88/120Hz 16:9 */
+ vmode->mHActive = 1280;
+ vmode->mVActive = 720;
+ vmode->mHBlanking = 370;
+ vmode->mVBlanking = 30;
+ vmode->mHSyncOffset = 110;
+ vmode->mVSyncOffset = 5;
+ vmode->mHSyncPulseWidth = 40;
+ vmode->mVSyncPulseWidth = 5;
+ vmode->mHSyncPolarity = vmode->mVSyncPolarity = TRUE;
+ vmode->mInterlaced = FALSE;
+ vmode->mPixelClock =
+ (vmode->mRefreshRate == 119880) ? 14835 : 14850;
+ break;
+ case 48: /* 720x480p @ 119.88/120Hz 4:3 */
+ vmode->mHImageSize = 4;
+ vmode->mVImageSize = 3;
+ case 49: /* 720x480p @ 119.88/120Hz 16:9 */
+ vmode->mHActive = 720;
+ vmode->mVActive = 480;
+ vmode->mHBlanking = 138;
+ vmode->mVBlanking = 45;
+ vmode->mHSyncOffset = 16;
+ vmode->mVSyncOffset = 9;
+ vmode->mHSyncPulseWidth = 62;
+ vmode->mVSyncPulseWidth = 6;
+ vmode->mHSyncPolarity = vmode->mVSyncPolarity = FALSE;
+ vmode->mInterlaced = FALSE;
+ vmode->mPixelClock =
+ (vmode->mRefreshRate == 119880) ? 5400 : 5405;
+ break;
+ case 50: /* 720(1440)x480i @ 119.88/120Hz 4:3 */
+ vmode->mHImageSize = 4;
+ vmode->mVImageSize = 3;
+ case 51: /* 720(1440)x480i @ 119.88/120Hz 16:9 */
+ vmode->mHActive = 1440;
+ vmode->mVActive = 240;
+ vmode->mHBlanking = 276;
+ vmode->mVBlanking = 22;
+ vmode->mHSyncOffset = 38;
+ vmode->mVSyncOffset = 4;
+ vmode->mHSyncPulseWidth = 124;
+ vmode->mVSyncPulseWidth = 3;
+ vmode->mHSyncPolarity = vmode->mVSyncPolarity = FALSE;
+ vmode->mInterlaced = TRUE;
+ vmode->mPixelClock =
+ (vmode->mRefreshRate == 119880) ? 5400 : 5405;
+ vmode->mPixelRepetitionInput = 1;
+ break;
+ case 52: /* 720X576p @ 200Hz 4:3 */
+ vmode->mHImageSize = 4;
+ vmode->mVImageSize = 3;
+ case 53: /* 720X576p @ 200Hz 16:9 */
+ vmode->mHActive = 720;
+ vmode->mVActive = 576;
+ vmode->mHBlanking = 144;
+ vmode->mVBlanking = 49;
+ vmode->mHSyncOffset = 12;
+ vmode->mVSyncOffset = 5;
+ vmode->mHSyncPulseWidth = 64;
+ vmode->mVSyncPulseWidth = 5;
+ vmode->mHSyncPolarity = vmode->mVSyncPolarity = FALSE;
+ vmode->mInterlaced = FALSE;
+ vmode->mPixelClock = 10800;
+ break;
+ case 54: /* 720(1440)x576i @ 200Hz 4:3 */
+ vmode->mHImageSize = 4;
+ vmode->mVImageSize = 3;
+ case 55: /* 720(1440)x576i @ 200Hz 16:9 */
+ vmode->mHActive = 1440;
+ vmode->mVActive = 288;
+ vmode->mHBlanking = 288;
+ vmode->mVBlanking = 24;
+ vmode->mHSyncOffset = 24;
+ vmode->mVSyncOffset = 2;
+ vmode->mHSyncPulseWidth = 126;
+ vmode->mVSyncPulseWidth = 3;
+ vmode->mHSyncPolarity = vmode->mVSyncPolarity = FALSE;
+ vmode->mInterlaced = TRUE;
+ vmode->mPixelClock = 10800;
+ vmode->mPixelRepetitionInput = 1;
+ break;
+ case 56: /* 720x480p @ 239.76/240Hz 4:3 */
+ vmode->mHImageSize = 4;
+ vmode->mVImageSize = 3;
+ case 57: /* 720x480p @ 239.76/240Hz 16:9 */
+ vmode->mHActive = 720;
+ vmode->mVActive = 480;
+ vmode->mHBlanking = 138;
+ vmode->mVBlanking = 45;
+ vmode->mHSyncOffset = 16;
+ vmode->mVSyncOffset = 9;
+ vmode->mHSyncPulseWidth = 62;
+ vmode->mVSyncPulseWidth = 6;
+ vmode->mHSyncPolarity = vmode->mVSyncPolarity = FALSE;
+ vmode->mInterlaced = FALSE;
+ vmode->mPixelClock =
+ (vmode->mRefreshRate == 239760) ? 10800 : 10810;
+ break;
+ case 58: /* 720(1440)x480i @ 239.76/240Hz 4:3 */
+ vmode->mHImageSize = 4;
+ vmode->mVImageSize = 3;
+ case 59: /* 720(1440)x480i @ 239.76/240Hz 16:9 */
+ vmode->mHActive = 1440;
+ vmode->mVActive = 240;
+ vmode->mHBlanking = 276;
+ vmode->mVBlanking = 22;
+ vmode->mHSyncOffset = 38;
+ vmode->mVSyncOffset = 4;
+ vmode->mHSyncPulseWidth = 124;
+ vmode->mVSyncPulseWidth = 3;
+ vmode->mHSyncPolarity = vmode->mVSyncPolarity = FALSE;
+ vmode->mInterlaced = TRUE;
+ vmode->mPixelClock =
+ (vmode->mRefreshRate == 239760) ? 10800 : 10810;
+ vmode->mPixelRepetitionInput = 1;
+ break;
+ default:
+ vmode->mCode = -1;
+ return;
+ }
+ return;
+}
+
+/*!
+ * this submodule is responsible for the video data synchronization.
+ * for example, for RGB 4:4:4 input, the data map is defined as
+ * pin{47~40} <==> R[7:0]
+ * pin{31~24} <==> G[7:0]
+ * pin{15~8} <==> B[7:0]
+ */
+void hdmi_video_sample(struct mxc_hdmi *hdmi)
+{
+ int color_format = 0;
+ u8 val;
+
+ if (hdmi->hdmi_data.enc_in_format == eRGB) {
+ if (hdmi->hdmi_data.enc_color_depth == 8)
+ color_format = 0x01;
+ else if (hdmi->hdmi_data.enc_color_depth == 10)
+ color_format = 0x03;
+ else if (hdmi->hdmi_data.enc_color_depth == 12)
+ color_format = 0x05;
+ else if (hdmi->hdmi_data.enc_color_depth == 16)
+ color_format = 0x07;
+ else
+ return;
+ } else if (hdmi->hdmi_data.enc_in_format == eYCC444) {
+ if (hdmi->hdmi_data.enc_color_depth == 8)
+ color_format = 0x09;
+ else if (hdmi->hdmi_data.enc_color_depth == 10)
+ color_format = 0x0B;
+ else if (hdmi->hdmi_data.enc_color_depth == 12)
+ color_format = 0x0D;
+ else if (hdmi->hdmi_data.enc_color_depth == 16)
+ color_format = 0x0F;
+ else
+ return;
+ } else if (hdmi->hdmi_data.enc_in_format == eYCC422) {
+ if (hdmi->hdmi_data.enc_color_depth == 8)
+ color_format = 0x16;
+ else if (hdmi->hdmi_data.enc_color_depth == 10)
+ color_format = 0x14;
+ else if (hdmi->hdmi_data.enc_color_depth == 12)
+ color_format = 0x12;
+ else
+ return;
+ }
+
+ val = HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_DISABLE |
+ ((color_format << HDMI_TX_INVID0_VIDEO_MAPPING_OFFSET) &
+ HDMI_TX_INVID0_VIDEO_MAPPING_MASK);
+ writeb(val, hdmi->base + HDMI_TX_INVID0);
+
+ /* Enable TX stuffing: When DE is inactive, fix the output data to 0 */
+ val = HDMI_TX_INSTUFFING_BDBDATA_STUFFING_ENABLE |
+ HDMI_TX_INSTUFFING_RCRDATA_STUFFING_ENABLE |
+ HDMI_TX_INSTUFFING_GYDATA_STUFFING_ENABLE;
+ writeb(val, hdmi->base + HDMI_TX_INSTUFFING);
+ writeb(0x0, hdmi->base + HDMI_TX_GYDATA0);
+ writeb(0x0, hdmi->base + HDMI_TX_GYDATA1);
+ writeb(0x0, hdmi->base + HDMI_TX_RCRDATA0);
+ writeb(0x0, hdmi->base + HDMI_TX_RCRDATA1);
+ writeb(0x0, hdmi->base + HDMI_TX_BCBDATA0);
+ writeb(0x0, hdmi->base + HDMI_TX_BCBDATA1);
+}
+
+static int isColorSpaceConversion(struct mxc_hdmi *hdmi)
+{
+ return (hdmi->hdmi_data.enc_in_format !=
+ hdmi->hdmi_data.enc_out_format) ? TRUE : FALSE;
+}
+
+static int isColorSpaceDecimation(struct mxc_hdmi *hdmi)
+{
+ return (hdmi->hdmi_data.enc_in_format !=
+ hdmi->hdmi_data.enc_out_format) ? TRUE : FALSE;
+}
+
+static int isColorSpaceInterpolation(struct mxc_hdmi *hdmi)
+{
+ return ((hdmi->hdmi_data.enc_in_format == eYCC422) &&
+ (hdmi->hdmi_data.enc_out_format == eRGB
+ || hdmi->hdmi_data.enc_out_format == eYCC444)) ?
+ TRUE : FALSE;
+}
+
+/*!
+ * update the color space conversion coefficients.
+ */
+void update_csc_coeffs(struct mxc_hdmi *hdmi)
+{
+ unsigned short csc_coeff[3][4];
+ unsigned int csc_scale = 1;
+ u8 val;
+
+ if (isColorSpaceConversion(hdmi) == TRUE) { /* csc needed */
+ if (hdmi->hdmi_data.enc_out_format == eRGB) {
+ if (hdmi->hdmi_data.colorimetry == eITU601) {
+ csc_coeff[0][0] = 0x2000;
+ csc_coeff[0][1] = 0x6926;
+ csc_coeff[0][2] = 0x74fd;
+ csc_coeff[0][3] = 0x010e;
+
+ csc_coeff[1][0] = 0x2000;
+ csc_coeff[1][1] = 0x2cdd;
+ csc_coeff[1][2] = 0x0000;
+ csc_coeff[1][3] = 0x7e9a;
+
+ csc_coeff[2][0] = 0x2000;
+ csc_coeff[2][1] = 0x0000;
+ csc_coeff[2][2] = 0x38b4;
+ csc_coeff[2][3] = 0x7e3b;
+
+ csc_scale = 1;
+ } else if (hdmi->hdmi_data.colorimetry == eITU709) {
+ csc_coeff[0][0] = 0x2000;
+ csc_coeff[0][1] = 0x7106;
+ csc_coeff[0][2] = 0x7a02;
+ csc_coeff[0][3] = 0x00a7;
+
+ csc_coeff[1][0] = 0x2000;
+ csc_coeff[1][1] = 0x3264;
+ csc_coeff[1][2] = 0x0000;
+ csc_coeff[1][3] = 0x7e6d;
+
+ csc_coeff[2][0] = 0x2000;
+ csc_coeff[2][1] = 0x0000;
+ csc_coeff[2][2] = 0x3b61;
+ csc_coeff[2][3] = 0x7e25;
+
+ csc_scale = 1;
+ }
+ } else if (hdmi->hdmi_data.enc_in_format == eRGB) {
+ if (hdmi->hdmi_data.colorimetry == eITU601) {
+ csc_coeff[0][0] = 0x2591;
+ csc_coeff[0][1] = 0x1322;
+ csc_coeff[0][2] = 0x074b;
+ csc_coeff[0][3] = 0x0000;
+
+ csc_coeff[1][0] = 0x6535;
+ csc_coeff[1][1] = 0x2000;
+ csc_coeff[1][2] = 0x7acc;
+ csc_coeff[1][3] = 0x0200;
+
+ csc_coeff[1][0] = 0x6acd;
+ csc_coeff[1][1] = 0x7534;
+ csc_coeff[1][2] = 0x2000;
+ csc_coeff[1][3] = 0x0200;
+
+ csc_scale = 1;
+ } else if (hdmi->hdmi_data.colorimetry == eITU709) {
+ csc_coeff[0][0] = 0x2dc5;
+ csc_coeff[0][1] = 0x0d9b;
+ csc_coeff[0][2] = 0x049e;
+ csc_coeff[0][3] = 0x0000;
+
+ csc_coeff[1][0] = 0x63f0;
+ csc_coeff[1][1] = 0x2000;
+ csc_coeff[1][2] = 0x7d11;
+ csc_coeff[1][3] = 0x0200;
+
+ csc_coeff[2][0] = 0x6756;
+ csc_coeff[2][1] = 0x78ab;
+ csc_coeff[2][2] = 0x2000;
+ csc_coeff[2][3] = 0x0200;
+
+ csc_scale = 1;
+ }
+ }
+ } else {
+ csc_coeff[0][0] = 0x2000;
+ csc_coeff[0][1] = 0x0000;
+ csc_coeff[0][2] = 0x0000;
+ csc_coeff[0][3] = 0x0000;
+
+ csc_coeff[1][0] = 0x0000;
+ csc_coeff[1][1] = 0x2000;
+ csc_coeff[1][2] = 0x0000;
+ csc_coeff[1][3] = 0x0000;
+
+ csc_coeff[2][0] = 0x0000;
+ csc_coeff[2][1] = 0x0000;
+ csc_coeff[2][2] = 0x2000;
+ csc_coeff[2][3] = 0x0000;
+
+ csc_scale = 1;
+ }
+
+ /* Update CSC parameters in HDMI CSC registers */
+ writeb((unsigned char)(csc_coeff[0][0] & 0xFF),
+ hdmi->base + HDMI_CSC_COEF_A1_LSB);
+ writeb((unsigned char)(csc_coeff[0][0] >> 8),
+ hdmi->base + HDMI_CSC_COEF_A1_MSB);
+ writeb((unsigned char)(csc_coeff[0][1] & 0xFF),
+ hdmi->base + HDMI_CSC_COEF_A2_LSB);
+ writeb((unsigned char)(csc_coeff[0][1] >> 8),
+ hdmi->base + HDMI_CSC_COEF_A2_MSB);
+ writeb((unsigned char)(csc_coeff[0][2] & 0xFF),
+ hdmi->base + HDMI_CSC_COEF_A3_LSB);
+ writeb((unsigned char)(csc_coeff[0][2] >> 8),
+ hdmi->base + HDMI_CSC_COEF_A3_MSB);
+ writeb((unsigned char)(csc_coeff[0][3] & 0xFF),
+ hdmi->base + HDMI_CSC_COEF_A4_LSB);
+ writeb((unsigned char)(csc_coeff[0][3] >> 8),
+ hdmi->base + HDMI_CSC_COEF_A4_MSB);
+
+ writeb((unsigned char)(csc_coeff[1][0] & 0xFF),
+ hdmi->base + HDMI_CSC_COEF_B1_LSB);
+ writeb((unsigned char)(csc_coeff[1][0] >> 8),
+ hdmi->base + HDMI_CSC_COEF_B1_MSB);
+ writeb((unsigned char)(csc_coeff[1][1] & 0xFF),
+ hdmi->base + HDMI_CSC_COEF_B2_LSB);
+ writeb((unsigned char)(csc_coeff[1][1] >> 8),
+ hdmi->base + HDMI_CSC_COEF_B2_MSB);
+ writeb((unsigned char)(csc_coeff[1][2] & 0xFF),
+ hdmi->base + HDMI_CSC_COEF_B3_LSB);
+ writeb((unsigned char)(csc_coeff[1][2] >> 8),
+ hdmi->base + HDMI_CSC_COEF_B3_MSB);
+ writeb((unsigned char)(csc_coeff[1][3] & 0xFF),
+ hdmi->base + HDMI_CSC_COEF_B4_LSB);
+ writeb((unsigned char)(csc_coeff[1][3] >> 8),
+ hdmi->base + HDMI_CSC_COEF_B4_MSB);
+
+ writeb((unsigned char)(csc_coeff[2][0] & 0xFF),
+ hdmi->base + HDMI_CSC_COEF_C1_LSB);
+ writeb((unsigned char)(csc_coeff[2][0] >> 8),
+ hdmi->base + HDMI_CSC_COEF_C1_MSB);
+ writeb((unsigned char)(csc_coeff[2][1] & 0xFF),
+ hdmi->base + HDMI_CSC_COEF_C2_LSB);
+ writeb((unsigned char)(csc_coeff[2][1] >> 8),
+ hdmi->base + HDMI_CSC_COEF_C2_MSB);
+ writeb((unsigned char)(csc_coeff[2][2] & 0xFF),
+ hdmi->base + HDMI_CSC_COEF_C3_LSB);
+ writeb((unsigned char)(csc_coeff[2][2] >> 8),
+ hdmi->base + HDMI_CSC_COEF_C3_MSB);
+ writeb((unsigned char)(csc_coeff[2][3] & 0xFF),
+ hdmi->base + HDMI_CSC_COEF_C4_LSB);
+ writeb((unsigned char)(csc_coeff[2][3] >> 8),
+ hdmi->base + HDMI_CSC_COEF_C4_MSB);
+
+ readb(hdmi->base + HDMI_CSC_SCALE);
+ val &= ~HDMI_CSC_SCALE_CSCSCALE_MASK;
+ val |= csc_scale & HDMI_CSC_SCALE_CSCSCALE_MASK;
+ writeb(val, hdmi->base + HDMI_CSC_SCALE);
+}
+
+void hdmi_video_csc(struct mxc_hdmi *hdmi)
+{
+ int color_depth = 0;
+ int interpolation = HDMI_CSC_CFG_INTMODE_DISABLE;
+ int decimation = 0;
+ u8 val;
+
+ /* YCC422 interpolation to 444 mode */
+ if (isColorSpaceInterpolation(hdmi))
+ interpolation = HDMI_CSC_CFG_INTMODE_CHROMA_INT_FORMULA1;
+ else if (isColorSpaceDecimation(hdmi))
+ decimation = HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA1;
+
+ if (hdmi->hdmi_data.enc_color_depth == 8)
+ color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_24BPP;
+ else if (hdmi->hdmi_data.enc_color_depth == 10)
+ color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_30BPP;
+ else if (hdmi->hdmi_data.enc_color_depth == 12)
+ color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_36BPP;
+ else if (hdmi->hdmi_data.enc_color_depth == 16)
+ color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_48BPP;
+ else
+ return;
+
+ /*configure the CSC registers */
+ writeb(interpolation | decimation, hdmi->base + HDMI_CSC_CFG);
+ val = readb(hdmi->base + HDMI_CSC_SCALE);
+ val &= ~HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK;
+ val |= color_depth;
+ writeb(val, hdmi->base + HDMI_CSC_SCALE);
+
+ update_csc_coeffs(hdmi);
+}
+
+/*!
+ * HDMI video packetizer is used to packetize the data.
+ * for example, if input is YCC422 mode or repeater is used,
+ * data should be repacked this module can be bypassed.
+ */
+void hdmi_video_packetize(struct mxc_hdmi *hdmi)
+{
+ unsigned int color_depth = 0;
+ unsigned int remap_size = HDMI_VP_REMAP_YCC422_16bit;
+ unsigned int output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_PP;
+ struct hdmi_data_info *hdmi_data = &hdmi->hdmi_data;
+ u8 val;
+
+ if (hdmi_data->enc_out_format == eRGB
+ || hdmi_data->enc_out_format == eYCC444) {
+ if (hdmi_data->enc_color_depth == 0)
+ output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
+ else if (hdmi_data->enc_color_depth == 8) {
+ color_depth = 4;
+ output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
+ } else if (hdmi_data->enc_color_depth == 10)
+ color_depth = 5;
+ else if (hdmi_data->enc_color_depth == 12)
+ color_depth = 6;
+ else if (hdmi_data->enc_color_depth == 16)
+ color_depth = 7;
+ else
+ return;
+ } else if (hdmi_data->enc_out_format == eYCC422) {
+ if (hdmi_data->enc_color_depth == 0 ||
+ hdmi_data->enc_color_depth == 8)
+ remap_size = HDMI_VP_REMAP_YCC422_16bit;
+ else if (hdmi_data->enc_color_depth == 10)
+ remap_size = HDMI_VP_REMAP_YCC422_20bit;
+ else if (hdmi_data->enc_color_depth == 12)
+ remap_size = HDMI_VP_REMAP_YCC422_24bit;
+ else
+ return;
+ output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422;
+ } else
+ return;
+
+ /* set the packetizer registers */
+ val = ((color_depth << HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET) &
+ HDMI_VP_PR_CD_COLOR_DEPTH_MASK) |
+ ((hdmi_data->pix_repet_factor <<
+ HDMI_VP_PR_CD_DESIRED_PR_FACTOR_OFFSET) &
+ HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK);
+ writeb(val, hdmi->base + HDMI_VP_PR_CD);
+
+ val = readb(hdmi->base + HDMI_VP_STUFF);
+ val &= ~HDMI_VP_STUFF_PR_STUFFING_MASK;
+ val |= HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE;
+ writeb(val, hdmi->base + HDMI_VP_STUFF);
+
+ /* Data from pixel repeater block */
+ if (hdmi_data->pix_repet_factor > 1) {
+ val = readb(hdmi->base + HDMI_VP_CONF);
+ val &= ~(HDMI_VP_CONF_PR_EN_MASK |
+ HDMI_VP_CONF_BYPASS_SELECT_MASK);
+ val |= HDMI_VP_CONF_PR_EN_ENABLE |
+ HDMI_VP_CONF_BYPASS_SELECT_PIX_REPEATER;
+ writeb(val, hdmi->base + HDMI_VP_CONF);
+ } else { /* data from packetizer block */
+ val = readb(hdmi->base + HDMI_VP_CONF);
+ val &= ~(HDMI_VP_CONF_PR_EN_MASK |
+ HDMI_VP_CONF_BYPASS_SELECT_MASK);
+ val |= HDMI_VP_CONF_PR_EN_DISABLE |
+ HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER;
+ writeb(val, hdmi->base + HDMI_VP_CONF);
+ }
+
+ val = readb(hdmi->base + HDMI_VP_STUFF);
+ val &= ~HDMI_VP_STUFF_IDEFAULT_PHASE_MASK;
+ val |= 1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET;
+ writeb(val, hdmi->base + HDMI_VP_STUFF);
+
+ writeb(remap_size, hdmi->base + HDMI_VP_REMAP);
+
+ if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_PP) {
+ val = readb(hdmi->base + HDMI_VP_CONF);
+ val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK |
+ HDMI_VP_CONF_PP_EN_ENMASK |
+ HDMI_VP_CONF_YCC422_EN_MASK);
+ val |= HDMI_VP_CONF_BYPASS_EN_DISABLE |
+ HDMI_VP_CONF_PP_EN_ENABLE |
+ HDMI_VP_CONF_YCC422_EN_DISABLE;
+ writeb(val, hdmi->base + HDMI_VP_CONF);
+ } else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422) {
+ val = readb(hdmi->base + HDMI_VP_CONF);
+ val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK |
+ HDMI_VP_CONF_PP_EN_ENMASK |
+ HDMI_VP_CONF_YCC422_EN_MASK);
+ val |= HDMI_VP_CONF_BYPASS_EN_DISABLE |
+ HDMI_VP_CONF_PP_EN_DISABLE |
+ HDMI_VP_CONF_YCC422_EN_ENABLE;
+ writeb(val, hdmi->base + HDMI_VP_CONF);
+ } else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS) {
+ val = readb(hdmi->base + HDMI_VP_CONF);
+ val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK |
+ HDMI_VP_CONF_PP_EN_ENMASK |
+ HDMI_VP_CONF_YCC422_EN_MASK);
+ val |= HDMI_VP_CONF_BYPASS_EN_ENABLE |
+ HDMI_VP_CONF_PP_EN_DISABLE |
+ HDMI_VP_CONF_YCC422_EN_DISABLE;
+ writeb(val, hdmi->base + HDMI_VP_CONF);
+ } else {
+ return;
+ }
+
+ val = readb(hdmi->base + HDMI_VP_STUFF);
+ val &= ~(HDMI_VP_STUFF_PP_STUFFING_MASK |
+ HDMI_VP_STUFF_YCC422_STUFFING_MASK);
+ val |= HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE |
+ HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE;
+ writeb(val, hdmi->base + HDMI_VP_STUFF);
+
+ val = readb(hdmi->base + HDMI_VP_CONF);
+ val &= ~HDMI_VP_CONF_OUTPUT_SELECTOR_MASK;
+ val |= output_select;
+ writeb(val, hdmi->base + HDMI_VP_CONF);
+}
+
+void hdmi_video_force_output(struct mxc_hdmi *hdmi, unsigned char force)
+{
+ u8 val;
+
+ if (force == TRUE) {
+ writeb(0x00, hdmi->base + HDMI_FC_DBGTMDS2); /* R */
+ writeb(0x00, hdmi->base + HDMI_FC_DBGTMDS1); /* G */
+ writeb(0xFF, hdmi->base + HDMI_FC_DBGTMDS0); /* B */
+ val = readb(hdmi->base + HDMI_FC_DBGFORCE);
+ val |= HDMI_FC_DBGFORCE_FORCEVIDEO;
+ writeb(val, hdmi->base + HDMI_FC_DBGFORCE);
+ } else {
+ val = readb(hdmi->base + HDMI_FC_DBGFORCE);
+ val &= ~HDMI_FC_DBGFORCE_FORCEVIDEO;
+ writeb(val, hdmi->base + HDMI_FC_DBGFORCE);
+ writeb(0x00, hdmi->base + HDMI_FC_DBGTMDS2); /* R */
+ writeb(0x00, hdmi->base + HDMI_FC_DBGTMDS1); /* G */
+ writeb(0x00, hdmi->base + HDMI_FC_DBGTMDS0); /* B */
+ }
+}
+
+static inline void hdmi_phy_test_clear(struct mxc_hdmi *hdmi,
+ unsigned char bit)
+{
+ u8 val = readb(hdmi->base + HDMI_PHY_TST0);
+ val &= ~HDMI_PHY_TST0_TSTCLR_MASK;
+ val |= (bit << HDMI_PHY_TST0_TSTCLR_OFFSET) &
+ HDMI_PHY_TST0_TSTCLR_MASK;
+ writeb(val, hdmi->base + HDMI_PHY_TST0);
+}
+
+static inline void hdmi_phy_test_enable(struct mxc_hdmi *hdmi,
+ unsigned char bit)
+{
+ u8 val = readb(hdmi->base + HDMI_PHY_TST0);
+ val &= ~HDMI_PHY_TST0_TSTEN_MASK;
+ val |= (bit << HDMI_PHY_TST0_TSTEN_OFFSET) &
+ HDMI_PHY_TST0_TSTEN_MASK;
+ writeb(val, hdmi->base + HDMI_PHY_TST0);
+}
+
+static inline void hdmi_phy_test_clock(struct mxc_hdmi *hdmi,
+ unsigned char bit)
+{
+ u8 val = readb(hdmi->base + HDMI_PHY_TST0);
+ val &= ~HDMI_PHY_TST0_TSTCLK_MASK;
+ val |= (bit << HDMI_PHY_TST0_TSTCLK_OFFSET) &
+ HDMI_PHY_TST0_TSTCLK_MASK;
+ writeb(val, hdmi->base + HDMI_PHY_TST0);
+}
+
+static inline void hdmi_phy_test_din(struct mxc_hdmi *hdmi,
+ unsigned char bit)
+{
+ writeb(bit, hdmi->base + HDMI_PHY_TST1);
+}
+
+static inline void hdmi_phy_test_dout(struct mxc_hdmi *hdmi,
+ unsigned char bit)
+{
+ writeb(bit, hdmi->base + HDMI_PHY_TST2);
+}
+
+static int hdmi_phy_test_control(struct mxc_hdmi *hdmi, unsigned char value)
+{
+ hdmi_phy_test_din(hdmi, value);
+ hdmi_phy_test_enable(hdmi, 1);
+ hdmi_phy_test_clock(hdmi, 1);
+ hdmi_phy_test_clock(hdmi, 0);
+ hdmi_phy_test_enable(hdmi, 0);
+
+ return TRUE;
+}
+
+static int hdmi_phy_test_data(struct mxc_hdmi *hdmi, unsigned char value)
+{
+ hdmi_phy_test_din(hdmi, value);
+ hdmi_phy_test_enable(hdmi, 0);
+ hdmi_phy_test_clock(hdmi, 1);
+ hdmi_phy_test_clock(hdmi, 0);
+
+ return TRUE;
+}
+
+int hdmi_phy_wait_i2c_done(struct mxc_hdmi *hdmi, int msec)
+{
+ unsigned char val = 0;
+ val = readb(hdmi->base + HDMI_IH_I2CMPHY_STAT0) & 0x3;
+ while (val == 0) {
+ udelay(1000);
+ if (msec-- == 0)
+ return FALSE;
+ val = readb(hdmi->base + HDMI_IH_I2CMPHY_STAT0) & 0x3;
+ }
+ return TRUE;
+}
+
+int hdmi_phy_i2c_write(struct mxc_hdmi *hdmi, unsigned short data,
+ unsigned char addr)
+{
+ writeb(0xFF, hdmi->base + HDMI_IH_I2CMPHY_STAT0);
+ writeb(addr, hdmi->base + HDMI_PHY_I2CM_ADDRESS_ADDR);
+ writeb((unsigned char)(data >> 8),
+ hdmi->base + HDMI_PHY_I2CM_DATAO_1_ADDR);
+ writeb((unsigned char)(data >> 0),
+ hdmi->base + HDMI_PHY_I2CM_DATAO_0_ADDR);
+ writeb(HDMI_PHY_I2CM_OPERATION_ADDR_WRITE,
+ hdmi->base + HDMI_PHY_I2CM_OPERATION_ADDR);
+ hdmi_phy_wait_i2c_done(hdmi, 1000);
+ return TRUE;
+}
+
+unsigned short hdmi_phy_i2c_read(struct mxc_hdmi *hdmi, unsigned char addr)
+{
+ unsigned short data;
+ unsigned char msb = 0, lsb = 0;
+ writeb(0xFF, hdmi->base + HDMI_IH_I2CMPHY_STAT0);
+ writeb(addr, hdmi->base + HDMI_PHY_I2CM_ADDRESS_ADDR);
+ writeb(HDMI_PHY_I2CM_OPERATION_ADDR_READ,
+ hdmi->base + HDMI_PHY_I2CM_OPERATION_ADDR);
+ hdmi_phy_wait_i2c_done(hdmi, 1000);
+ msb = readb(hdmi->base + HDMI_PHY_I2CM_DATAI_1_ADDR);
+ lsb = readb(hdmi->base + HDMI_PHY_I2CM_DATAI_0_ADDR);
+ data = (msb << 8) | lsb;
+ return data;
+}
+
+int hdmi_phy_i2c_write_verify(struct mxc_hdmi *hdmi, unsigned short data,
+ unsigned char addr)
+{
+ unsigned short val = 0;
+ hdmi_phy_i2c_write(hdmi, data, addr);
+ val = hdmi_phy_i2c_read(hdmi, addr);
+ if (val != data)
+ return FALSE;
+ return TRUE;
+}
+
+int hdmi_phy_configure(struct mxc_hdmi *hdmi, unsigned char pRep,
+ unsigned char cRes, int cscOn, int audioOn,
+ int cecOn, int hdcpOn)
+{
+ unsigned short clk = 0, rep = 0;
+ u8 val;
+
+ /* color resolution 0 is 8 bit colour depth */
+ if (cRes == 0)
+ cRes = 8;
+
+ if (pRep != 0)
+ return FALSE;
+ else if (cRes != 8 && cRes != 12)
+ return FALSE;
+
+ switch (hdmi->hdmi_data.video_mode.mPixelClock) {
+ case 2520:
+ clk = 0x93C1;
+ rep = (cRes == 8) ? 0x6A4A : 0x6653;
+ break;
+ case 2700:
+ clk = 0x96C1;
+ rep = (cRes == 8) ? 0x6A4A : 0x6653;
+ break;
+ case 5400:
+ clk = 0x8CC3;
+ rep = (cRes == 8) ? 0x6A4A : 0x6653;
+ break;
+ case 7200:
+ clk = 0x90C4;
+ rep = (cRes == 8) ? 0x6A4A : 0x6654;
+ break;
+ case 7425:
+ clk = 0x95C8;
+ rep = (cRes == 8) ? 0x6A4A : 0x6654;
+ break;
+ case 10800:
+ clk = 0x98C6;
+ rep = (cRes == 8) ? 0x6A4A : 0x6653;
+ break;
+ case 14850:
+ clk = 0x89C9;
+ rep = (cRes == 8) ? 0x6A4A : 0x6654;
+ break;
+ default:
+ return FALSE;
+ }
+
+ if (cscOn)
+ val = HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_IN_PATH;
+ else
+ val = HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS;
+ writeb(val, hdmi->base + HDMI_MC_FLOWCTRL);
+
+#if 0
+ /* clock gate == 0 => turn on modules */
+ val = hdcpOn ? HDMI_MC_CLKDIS_PIXELCLK_DISABLE_ENABLE :
+ HDMI_MC_CLKDIS_PIXELCLK_DISABLE_DISABLE;
+ val |= HDMI_MC_CLKDIS_PIXELCLK_DISABLE_ENABLE;
+ val |= HDMI_MC_CLKDIS_TMDSCLK_DISABLE_ENABLE;
+ val |= (pRep > 0) ? HDMI_MC_CLKDIS_PREPCLK_DISABLE_ENABLE :
+ HDMI_MC_CLKDIS_PREPCLK_DISABLE_DISABLE;
+ val |= cecOn ? HDMI_MC_CLKDIS_CECCLK_DISABLE_ENABLE :
+ HDMI_MC_CLKDIS_CECCLK_DISABLE_DISABLE;
+ val |= cscOn ? HDMI_MC_CLKDIS_CSCCLK_DISABLE_ENABLE :
+ HDMI_MC_CLKDIS_CSCCLK_DISABLE_DISABLE;
+ val |= audioOn ? HDMI_MC_CLKDIS_AUDCLK_DISABLE_ENABLE :
+ HDMI_MC_CLKDIS_AUDCLK_DISABLE_DISABLE;
+#else
+ /* clock gate == 0 => turn on modules */
+ val = hdcpOn ? HDMI_MC_CLKDIS_PIXELCLK_DISABLE_DISABLE :
+ HDMI_MC_CLKDIS_PIXELCLK_DISABLE_ENABLE;
+ val |= HDMI_MC_CLKDIS_PIXELCLK_DISABLE_ENABLE;
+ val |= HDMI_MC_CLKDIS_TMDSCLK_DISABLE_ENABLE;
+ val |= (pRep > 0) ? HDMI_MC_CLKDIS_PREPCLK_DISABLE_DISABLE :
+ HDMI_MC_CLKDIS_PREPCLK_DISABLE_ENABLE;
+ val |= cecOn ? HDMI_MC_CLKDIS_CECCLK_DISABLE_DISABLE :
+ HDMI_MC_CLKDIS_CECCLK_DISABLE_ENABLE;
+ val |= cscOn ? HDMI_MC_CLKDIS_CSCCLK_DISABLE_DISABLE :
+ HDMI_MC_CLKDIS_CSCCLK_DISABLE_ENABLE;
+ val |= audioOn ? HDMI_MC_CLKDIS_AUDCLK_DISABLE_DISABLE :
+ HDMI_MC_CLKDIS_AUDCLK_DISABLE_ENABLE;
+#endif
+ writeb(val, hdmi->base + HDMI_MC_CLKDIS);
+
+ /* gen2 tx power off */
+ val = readb(hdmi->base + HDMI_PHY_CONF0);
+ val &= ~HDMI_PHY_CONF0_GEN2_TXPWRON_MASK;
+ val |= HDMI_PHY_CONF0_GEN2_TXPWRON_POWER_OFF;
+ writeb(val, hdmi->base + HDMI_PHY_CONF0);
+
+ /* gen2 pddq */
+ val = readb(hdmi->base + HDMI_PHY_CONF0);
+ val &= ~HDMI_PHY_CONF0_GEN2_PDDQ_MASK;
+ val |= HDMI_PHY_CONF0_GEN2_PDDQ_ENABLE;
+ writeb(val, hdmi->base + HDMI_PHY_CONF0);
+
+ /* PHY reset */
+#if 0
+ writeb(HDMI_MC_PHYRSTZ_ASSERT, hdmi->base + HDMI_MC_PHYRSTZ);
+ writeb(HDMI_MC_PHYRSTZ_DEASSERT, hdmi->base + HDMI_MC_PHYRSTZ);
+#else
+ writeb(HDMI_MC_PHYRSTZ_DEASSERT, hdmi->base + HDMI_MC_PHYRSTZ);
+ writeb(HDMI_MC_PHYRSTZ_ASSERT, hdmi->base + HDMI_MC_PHYRSTZ);
+#endif
+
+ writeb(HDMI_MC_HEACPHY_RST_ASSERT,
+ hdmi->base + HDMI_MC_HEACPHY_RST);
+
+ hdmi_phy_test_clear(hdmi, 1);
+ writeb(HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2,
+ hdmi->base + HDMI_PHY_I2CM_SLAVE_ADDR);
+ hdmi_phy_test_clear(hdmi, 0);
+
+ switch (hdmi->hdmi_data.video_mode.mPixelClock) {
+ case 2520:
+ switch (cRes) {
+ case 8:
+ /* PLL/MPLL Cfg */
+ hdmi_phy_i2c_write(hdmi, 0x01e0, 0x06);
+ hdmi_phy_i2c_write(hdmi, 0x091c, 0x10); /* CURRCTRL */
+ hdmi_phy_i2c_write(hdmi, 0x0000, 0x15); /* GMPCTRL */
+ hdmi_phy_i2c_write(hdmi, 0x0000, 0x13); /* PLLPHBYCTRL */
+ hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
+ /* RESISTANCE TERM 133Ohm Cfg */
+ hdmi_phy_i2c_write(hdmi, 0x0005, 0x19); /* TXTERM */
+ /* PREEMP Cgf 0.00 */
+ hdmi_phy_i2c_write(hdmi, 0x8009, 0x09); /* CKSYMTXCTRL */
+ /* TX/CK LVL 10 */
+ hdmi_phy_i2c_write(hdmi, 0x0210, 0x0E); /* VLEVCTRL */
+ /* REMOVE CLK TERM */
+ hdmi_phy_i2c_write(hdmi, 0x8000, 0x05); /* CKCALCTRL */
+ break;
+ case 10:
+ hdmi_phy_i2c_write(hdmi, 0x21e1, 0x06);
+ hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
+ hdmi_phy_i2c_write(hdmi, 0x0000, 0x15);
+ hdmi_phy_i2c_write(hdmi, 0x0000, 0x13);
+ hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
+ hdmi_phy_i2c_write(hdmi, 0x0005, 0x19);
+ hdmi_phy_i2c_write(hdmi, 0x8009, 0x09);
+ hdmi_phy_i2c_write(hdmi, 0x0210, 0x0E);
+ hdmi_phy_i2c_write(hdmi, 0x8000, 0x05);
+ break;
+ case 12:
+ hdmi_phy_i2c_write(hdmi, 0x41e2, 0x06);
+ hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
+ hdmi_phy_i2c_write(hdmi, 0x0000, 0x15);
+ hdmi_phy_i2c_write(hdmi, 0x0000, 0x13);
+ hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
+ hdmi_phy_i2c_write(hdmi, 0x0005, 0x19);
+ hdmi_phy_i2c_write(hdmi, 0x8009, 0x09);
+ hdmi_phy_i2c_write(hdmi, 0x0210, 0x0E);
+ hdmi_phy_i2c_write(hdmi, 0x8000, 0x05);
+ break;
+ default:
+ return FALSE;
+ }
+ break;
+ case 2700:
+ switch (cRes) {
+ case 8:
+ hdmi_phy_i2c_write(hdmi, 0x01e0, 0x06);
+ hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
+ hdmi_phy_i2c_write(hdmi, 0x0000, 0x15);
+ hdmi_phy_i2c_write(hdmi, 0x0000, 0x13);
+ hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
+ hdmi_phy_i2c_write(hdmi, 0x0005, 0x19);
+ hdmi_phy_i2c_write(hdmi, 0x8009, 0x09);
+ hdmi_phy_i2c_write(hdmi, 0x0210, 0x0E);
+ hdmi_phy_i2c_write(hdmi, 0x8000, 0x05);
+ break;
+ case 10:
+ hdmi_phy_i2c_write(hdmi, 0x21e1, 0x06);
+ hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
+ hdmi_phy_i2c_write(hdmi, 0x0000, 0x15);
+ hdmi_phy_i2c_write(hdmi, 0x0000, 0x13);
+ hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
+ hdmi_phy_i2c_write(hdmi, 0x0005, 0x19);
+ hdmi_phy_i2c_write(hdmi, 0x8009, 0x09);
+ hdmi_phy_i2c_write(hdmi, 0x0210, 0x0E);
+ hdmi_phy_i2c_write(hdmi, 0x8000, 0x05);
+ break;
+ case 12:
+ hdmi_phy_i2c_write(hdmi, 0x41e2, 0x06);
+ hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
+ hdmi_phy_i2c_write(hdmi, 0x0000, 0x15);
+ hdmi_phy_i2c_write(hdmi, 0x0000, 0x13);
+ hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
+ hdmi_phy_i2c_write(hdmi, 0x0005, 0x19);
+ hdmi_phy_i2c_write(hdmi, 0x8009, 0x09);
+ hdmi_phy_i2c_write(hdmi, 0x0210, 0x0E);
+ hdmi_phy_i2c_write(hdmi, 0x8000, 0x05);
+ break;
+ default:
+ return FALSE;
+ }
+ break;
+ case 5400:
+ switch (cRes) {
+ case 8:
+ hdmi_phy_i2c_write(hdmi, 0x0140, 0x06);
+ hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
+ hdmi_phy_i2c_write(hdmi, 0x0005, 0x15);
+ hdmi_phy_i2c_write(hdmi, 0x0000, 0x13);
+ hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
+ hdmi_phy_i2c_write(hdmi, 0x0005, 0x19);
+ hdmi_phy_i2c_write(hdmi, 0x8009, 0x09);
+ hdmi_phy_i2c_write(hdmi, 0x0210, 0x0E);
+ hdmi_phy_i2c_write(hdmi, 0x8000, 0x05);
+ break;
+ case 10:
+ hdmi_phy_i2c_write(hdmi, 0x2141, 0x06);
+ hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
+ hdmi_phy_i2c_write(hdmi, 0x0005, 0x15);
+ hdmi_phy_i2c_write(hdmi, 0x0000, 0x13);
+ hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
+ hdmi_phy_i2c_write(hdmi, 0x0005, 0x19);
+ hdmi_phy_i2c_write(hdmi, 0x8009, 0x09);
+ hdmi_phy_i2c_write(hdmi, 0x0210, 0x0E);
+ hdmi_phy_i2c_write(hdmi, 0x8000, 0x05);
+ break;
+ case 12:
+ hdmi_phy_i2c_write(hdmi, 0x4142, 0x06);
+ hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
+ hdmi_phy_i2c_write(hdmi, 0x0005, 0x15);
+ hdmi_phy_i2c_write(hdmi, 0x0000, 0x13);
+ hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
+ hdmi_phy_i2c_write(hdmi, 0x0005, 0x19);
+ hdmi_phy_i2c_write(hdmi, 0x8009, 0x09);
+ hdmi_phy_i2c_write(hdmi, 0x0210, 0x0E);
+ hdmi_phy_i2c_write(hdmi, 0x8000, 0x05);
+ break;
+ default:
+ return FALSE;
+ }
+ break;
+ case 7200:
+ switch (cRes) {
+ case 8:
+ hdmi_phy_i2c_write(hdmi, 0x0140, 0x06);
+ hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
+ hdmi_phy_i2c_write(hdmi, 0x0005, 0x15);
+ hdmi_phy_i2c_write(hdmi, 0x0000, 0x13);
+ hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
+ hdmi_phy_i2c_write(hdmi, 0x0005, 0x19);
+ hdmi_phy_i2c_write(hdmi, 0x8009, 0x09);
+ hdmi_phy_i2c_write(hdmi, 0x0210, 0x0E);
+ hdmi_phy_i2c_write(hdmi, 0x8000, 0x05);
+ break;
+ case 10:
+ hdmi_phy_i2c_write(hdmi, 0x2141, 0x06);
+ hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
+ hdmi_phy_i2c_write(hdmi, 0x0005, 0x15);
+ hdmi_phy_i2c_write(hdmi, 0x0000, 0x13);
+ hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
+ hdmi_phy_i2c_write(hdmi, 0x0005, 0x19);
+ hdmi_phy_i2c_write(hdmi, 0x8009, 0x09);
+ hdmi_phy_i2c_write(hdmi, 0x0210, 0x0E);
+ hdmi_phy_i2c_write(hdmi, 0x8000, 0x05);
+ break;
+ case 12:
+ hdmi_phy_i2c_write(hdmi, 0x40a2, 0x06);
+ hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
+ hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
+ hdmi_phy_i2c_write(hdmi, 0x0000, 0x13);
+ hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
+ hdmi_phy_i2c_write(hdmi, 0x0005, 0x19);
+ hdmi_phy_i2c_write(hdmi, 0x8009, 0x09);
+ hdmi_phy_i2c_write(hdmi, 0x0210, 0x0E);
+ hdmi_phy_i2c_write(hdmi, 0x8000, 0x05);
+ break;
+ default:
+ return FALSE;
+ }
+ break;
+ case 7425:
+ switch (cRes) {
+ case 8:
+ hdmi_phy_i2c_write(hdmi, 0x0140, 0x06);
+ hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
+ hdmi_phy_i2c_write(hdmi, 0x0005, 0x15);
+ hdmi_phy_i2c_write(hdmi, 0x0000, 0x13);
+ hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
+ hdmi_phy_i2c_write(hdmi, 0x0005, 0x19);
+ hdmi_phy_i2c_write(hdmi, 0x8009, 0x09);
+ hdmi_phy_i2c_write(hdmi, 0x0210, 0x0E);
+ hdmi_phy_i2c_write(hdmi, 0x8000, 0x05);
+ break;
+ case 10:
+ hdmi_phy_i2c_write(hdmi, 0x20a1, 0x06);
+ hdmi_phy_i2c_write(hdmi, 0x0b5c, 0x10);
+ hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
+ hdmi_phy_i2c_write(hdmi, 0x0000, 0x13);
+ hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
+ hdmi_phy_i2c_write(hdmi, 0x0005, 0x19);
+ hdmi_phy_i2c_write(hdmi, 0x8009, 0x09);
+ hdmi_phy_i2c_write(hdmi, 0x0210, 0x0E);
+ hdmi_phy_i2c_write(hdmi, 0x8000, 0x05);
+ break;
+ case 12:
+ hdmi_phy_i2c_write(hdmi, 0x40a2, 0x06);
+ hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
+ hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
+ hdmi_phy_i2c_write(hdmi, 0x0000, 0x13);
+ hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
+ hdmi_phy_i2c_write(hdmi, 0x0005, 0x19);
+ hdmi_phy_i2c_write(hdmi, 0x8009, 0x09);
+ hdmi_phy_i2c_write(hdmi, 0x0210, 0x0E);
+ hdmi_phy_i2c_write(hdmi, 0x8000, 0x05);
+ break;
+ default:
+ return FALSE;
+ }
+ break;
+ case 10800:
+ switch (cRes) {
+ case 8:
+ hdmi_phy_i2c_write(hdmi, 0x00a0, 0x06);
+ hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
+ hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
+ hdmi_phy_i2c_write(hdmi, 0x0000, 0x13);
+ hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
+ hdmi_phy_i2c_write(hdmi, 0x0005, 0x19);
+ hdmi_phy_i2c_write(hdmi, 0x8009, 0x09);
+ hdmi_phy_i2c_write(hdmi, 0x0210, 0x0E);
+ hdmi_phy_i2c_write(hdmi, 0x8000, 0x05);
+ break;
+ case 10:
+ hdmi_phy_i2c_write(hdmi, 0x20a1, 0x06);
+ hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
+ hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
+ hdmi_phy_i2c_write(hdmi, 0x0000, 0x13);
+ hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
+ hdmi_phy_i2c_write(hdmi, 0x0005, 0x19);
+ hdmi_phy_i2c_write(hdmi, 0x8009, 0x09);
+ hdmi_phy_i2c_write(hdmi, 0x0210, 0x0E);
+ hdmi_phy_i2c_write(hdmi, 0x8000, 0x05);
+ break;
+ case 12:
+ hdmi_phy_i2c_write(hdmi, 0x40a2, 0x06);
+ hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
+ hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
+ hdmi_phy_i2c_write(hdmi, 0x0000, 0x13);
+ hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
+ hdmi_phy_i2c_write(hdmi, 0x0005, 0x19);
+ hdmi_phy_i2c_write(hdmi, 0x8009, 0x09);
+ hdmi_phy_i2c_write(hdmi, 0x0210, 0x0E);
+ hdmi_phy_i2c_write(hdmi, 0x8000, 0x05);
+ break;
+ default:
+ return FALSE;
+ }
+ break;
+ case 14850:
+ switch (cRes) {
+ case 8:
+ hdmi_phy_i2c_write(hdmi, 0x00a0, 0x06);
+ hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
+ hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
+ hdmi_phy_i2c_write(hdmi, 0x0000, 0x13);
+ hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
+ hdmi_phy_i2c_write(hdmi, 0x0005, 0x19);
+ hdmi_phy_i2c_write(hdmi, 0x8009, 0x09);
+ hdmi_phy_i2c_write(hdmi, 0x0210, 0x0E);
+ hdmi_phy_i2c_write(hdmi, 0x8000, 0x05);
+ break;
+ case 10:
+ hdmi_phy_i2c_write(hdmi, 0x2001, 0x06);
+ hdmi_phy_i2c_write(hdmi, 0x0b5c, 0x10);
+ hdmi_phy_i2c_write(hdmi, 0x000f, 0x15);
+ hdmi_phy_i2c_write(hdmi, 0x0000, 0x13);
+ hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
+ hdmi_phy_i2c_write(hdmi, 0x0005, 0x19);
+ hdmi_phy_i2c_write(hdmi, 0x8009, 0x09);
+ hdmi_phy_i2c_write(hdmi, 0x0210, 0x0E);
+ hdmi_phy_i2c_write(hdmi, 0x8000, 0x05);
+ break;
+ case 12:
+ hdmi_phy_i2c_write(hdmi, 0x4002, 0x06);
+ hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
+ hdmi_phy_i2c_write(hdmi, 0x000f, 0x15);
+ hdmi_phy_i2c_write(hdmi, 0x0000, 0x13);
+ hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
+ hdmi_phy_i2c_write(hdmi, 0x0005, 0x19);
+ hdmi_phy_i2c_write(hdmi, 0x800b, 0x09);
+ hdmi_phy_i2c_write(hdmi, 0x0129, 0x0E);
+ hdmi_phy_i2c_write(hdmi, 0x8000, 0x05);
+ break;
+ default:
+ return FALSE;
+ }
+ break;
+ default:
+ return FALSE;
+ }
+
+ /* gen2 tx power on */
+ val = readb(hdmi->base + HDMI_PHY_CONF0);
+ val &= ~HDMI_PHY_CONF0_GEN2_TXPWRON_MASK;
+ val |= HDMI_PHY_CONF0_GEN2_TXPWRON_POWER_ON;
+ writeb(val, hdmi->base + HDMI_PHY_CONF0);
+
+ val = readb(hdmi->base + HDMI_PHY_CONF0);
+ val &= ~HDMI_PHY_CONF0_GEN2_PDDQ_MASK;
+ val |= HDMI_PHY_CONF0_GEN2_PDDQ_DISABLE;
+ writeb(val, hdmi->base + HDMI_PHY_CONF0);
+
+ udelay(1000);
+
+ if ((readb(hdmi->base + HDMI_PHY_STAT0) & 0x01) == 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+void hdmi_phy_init(struct mxc_hdmi *hdmi, unsigned char de)
+{
+ u8 val;
+
+ /* configure the interrupt mask of source PHY. */
+ writeb(0xFF, hdmi->base + HDMI_PHY_MASK0);
+
+ val = readb(hdmi->base + HDMI_PHY_CONF0);
+ /* set the DE polarity */
+ val |= (de << HDMI_PHY_CONF0_SELDATAENPOL_OFFSET) &
+ HDMI_PHY_CONF0_SELDATAENPOL_MASK;
+ /* set the interface control to 0 */
+ val |= (0 << HDMI_PHY_CONF0_SELDIPIF_OFFSET) &
+ HDMI_PHY_CONF0_SELDIPIF_MASK;
+ /* enable TMDS output */
+ val |= (1 << HDMI_PHY_CONF0_ENTMDS_OFFSET) &
+ HDMI_PHY_CONF0_ENTMDS_MASK;
+ writeb(val, hdmi->base + HDMI_PHY_CONF0);
+
+ /* PHY power down disable (i.e., enable PHY) */
+ val = readb(hdmi->base + HDMI_PHY_CONF0);
+ val |= (1 << HDMI_PHY_CONF0_PDZ_OFFSET) &
+ HDMI_PHY_CONF0_PDZ_MASK;
+ writeb(val, hdmi->base + HDMI_PHY_CONF0);
+
+ hdmi_phy_configure(hdmi, 0, 8, FALSE, FALSE, FALSE, FALSE);
+}
+
+void hdmi_tx_tmds_clock(unsigned short tmdsclk, int i2cfsmode)
+{
+}
+
+void hdmi_tx_hdcp_config(struct mxc_hdmi *hdmi)
+{
+ u8 de, val;
+
+ if (hdmi->hdmi_data.video_mode.mDataEnablePolarity)
+ de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_HIGH;
+ else
+ de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_LOW;
+
+ /* disable rx detect */
+ val = readb(hdmi->base + HDMI_A_HDCPCFG0);
+ val &= HDMI_A_HDCPCFG0_RXDETECT_MASK;
+ val |= HDMI_A_HDCPCFG0_RXDETECT_DISABLE;
+ writeb(val, hdmi->base + HDMI_A_HDCPCFG0);
+
+ val = readb(hdmi->base + HDMI_A_VIDPOLCFG);
+ val &= HDMI_A_VIDPOLCFG_DATAENPOL_MASK;
+ val |= de;
+ writeb(val, hdmi->base + HDMI_A_VIDPOLCFG);
+
+ val = readb(hdmi->base + HDMI_A_HDCPCFG1);
+ val &= HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK;
+ val |= HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE;
+ writeb(val, hdmi->base + HDMI_A_HDCPCFG1);
+
+ hdmi_tx_tmds_clock(0, 0);
+}
+
+void hdmi_audio_mute(struct mxc_hdmi *hdmi, int en)
+{
+ u8 val;
+ val = readb(hdmi->base + HDMI_FC_AUDSCONF);
+ val &= HDMI_FC_AUDSCONF_AUD_PACKET_SAMPFIT_MASK;
+ val |= ((en == TRUE) ? 0xF : 0) <<
+ HDMI_FC_AUDSCONF_AUD_PACKET_SAMPFIT_OFFSET;
+ writeb(val, hdmi->base + HDMI_FC_AUDSCONF);
+}
+
+void preamble_filter_set(struct mxc_hdmi *hdmi, unsigned char value,
+ unsigned char channel)
+{
+ if (channel == 0)
+ writeb(value, hdmi->base + HDMI_FC_CH0PREAM);
+ else if (channel == 1)
+ writeb(value, hdmi->base + HDMI_FC_CH1PREAM);
+ else if (channel == 2)
+ writeb(value, hdmi->base + HDMI_FC_CH2PREAM);
+ else
+
+ return;
+}
+
+/*!
+ * this submodule is responsible for the video/audio data composition.
+ */
+void hdmi_av_composer(struct mxc_hdmi *hdmi)
+{
+ unsigned char i = 0;
+ u8 val;
+
+ hdmi_set_video_mode(&hdmi->hdmi_data.video_mode);
+
+ /* Set up HDMI_FC_INVIDCONF */
+ val = ((hdmi->hdmi_data.hdcp_enable == TRUE) ?
+ HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE :
+ HDMI_FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE);
+ val |= ((hdmi->hdmi_data.video_mode.mVSyncPolarity == TRUE) ?
+ HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_HIGH :
+ HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_LOW);
+ val |= ((hdmi->hdmi_data.video_mode.mHSyncPolarity == TRUE) ?
+ HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_HIGH :
+ HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_LOW);
+ val |= ((hdmi->hdmi_data.video_mode.mDataEnablePolarity == TRUE) ?
+ HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_HIGH :
+ HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_LOW);
+ val |= ((hdmi->hdmi_data.video_mode.mHdmiDviSel == TRUE) ?
+ HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE :
+ HDMI_FC_INVIDCONF_DVI_MODEZ_DVI_MODE);
+ if (hdmi->hdmi_data.video_mode.mCode == 39)
+ val |= HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_HIGH;
+ else
+ val |= ((hdmi->hdmi_data.video_mode.mInterlaced == TRUE) ?
+ HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_HIGH :
+ HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_LOW);
+ val |= ((hdmi->hdmi_data.video_mode.mInterlaced == TRUE) ?
+ HDMI_FC_INVIDCONF_IN_I_P_INTERLACED :
+ HDMI_FC_INVIDCONF_IN_I_P_PROGRESSIVE);
+ writeb(val, hdmi->base + HDMI_FC_INVIDCONF);
+
+ /* Set up horizontal active pixel region width */
+ writeb(hdmi->hdmi_data.video_mode.mHActive,
+ hdmi->base + HDMI_FC_INHACTV0);
+ writeb(hdmi->hdmi_data.video_mode.mHActive >> 8,
+ hdmi->base + HDMI_FC_INHACTV1);
+
+ /* Set up horizontal blanking pixel region width */
+ writeb(hdmi->hdmi_data.video_mode.mHBlanking,
+ hdmi->base + HDMI_FC_INHBLANK0);
+ writeb(hdmi->hdmi_data.video_mode.mHBlanking >> 8,
+ hdmi->base + HDMI_FC_INHBLANK1);
+
+ /* Set up vertical blanking pixel region width */
+ writeb(hdmi->hdmi_data.video_mode.mVActive,
+ hdmi->base + HDMI_FC_INVACTV0);
+ writeb(hdmi->hdmi_data.video_mode.mVActive >> 8,
+ hdmi->base + HDMI_FC_INVACTV1);
+
+ /* Set up vertical blanking pixel region width */
+ writeb(hdmi->hdmi_data.video_mode.mVBlanking,
+ hdmi->base + HDMI_FC_INVBLANK);
+
+ /* Set up HSYNC active edge delay width (in pixel clks) */
+ writeb(hdmi->hdmi_data.video_mode.mHSyncOffset,
+ hdmi->base + HDMI_FC_HSYNCINDELAY0);
+ writeb(hdmi->hdmi_data.video_mode.mHSyncOffset >> 8,
+ hdmi->base + HDMI_FC_HSYNCINDELAY1);
+
+ /* Set up HSYNC active pulse width (in pixel clks) */
+ writeb(hdmi->hdmi_data.video_mode.mHSyncPulseWidth,
+ hdmi->base + HDMI_FC_HSYNCINWIDTH0);
+ writeb(hdmi->hdmi_data.video_mode.mHSyncPulseWidth >> 8,
+ hdmi->base + HDMI_FC_HSYNCINWIDTH1);
+
+ /* Set up vertical blanking pixel region width */
+ writeb(hdmi->hdmi_data.video_mode.mVBlanking,
+ hdmi->base + HDMI_FC_INVBLANK);
+
+ /* Set up VSYNC active edge delay (in pixel clks) */
+ writeb(hdmi->hdmi_data.video_mode.mVSyncOffset,
+ hdmi->base + HDMI_FC_VSYNCINDELAY);
+
+ /* Set up VSYNC active edge delay (in pixel clks) */
+ writeb(hdmi->hdmi_data.video_mode.mVSyncPulseWidth,
+ hdmi->base + HDMI_FC_VSYNCINWIDTH);
+
+ /* control period minimum duration */
+ writeb(12, hdmi->base + HDMI_FC_CTRLDUR);
+ writeb(32, hdmi->base + HDMI_FC_EXCTRLDUR);
+ writeb(1, hdmi->base + HDMI_FC_EXCTRLSPAC);
+
+ for (i = 0; i < 3; i++)
+ preamble_filter_set(hdmi, (i + 1) * 11, i);
+
+ /* Set up input and output pixel repetition */
+ val = (((hdmi->hdmi_data.video_mode.mPixelRepetitionInput + 1) <<
+ HDMI_FC_PRCONF_INCOMING_PR_FACTOR_OFFSET) &
+ HDMI_FC_PRCONF_INCOMING_PR_FACTOR_MASK) |
+ ((0 << HDMI_FC_PRCONF_INCOMING_PR_FACTOR_OFFSET) &
+ HDMI_FC_PRCONF_INCOMING_PR_FACTOR_MASK);
+ writeb(val, hdmi->base + HDMI_FC_PRCONF);
+
+ /* AVI - underscan , IT601 */
+ writeb(0x20, hdmi->base + HDMI_FC_AVICONF0);
+ writeb(0x40, hdmi->base + HDMI_FC_AVICONF1);
+}
+
+static void mxc_hdmi_poweron(struct mxc_hdmi *hdmi)
+{
+ struct fsl_mxc_lcd_platform_data *plat = hdmi->pdev->dev.platform_data;
+
+ dev_dbg(&hdmi->pdev->dev, "power on\n");
+
+ /* Enable pins to HDMI */
+ if (plat->enable_pins)
+ plat->enable_pins();
+}
+static int mxc_hdmi_read_edid(struct mxc_hdmi *hdmi,
+ struct fb_info *fbi)
+{
+ int ret;
+ u8 edid_old[HDMI_EDID_LEN];
+
+ /* save old edid */
+ memcpy(edid_old, hdmi->edid, HDMI_EDID_LEN);
+
+ /* edid reading */
+ ret = mxc_edid_read(hdmi_i2c->adapter, hdmi_i2c->addr,
+ hdmi->edid, &hdmi->edid_cfg, fbi);
+
+ if (!memcmp(edid_old, hdmi->edid, HDMI_EDID_LEN))
+ ret = -2;
+ return ret;
+}
+
+static void mxc_hdmi_poweroff(struct mxc_hdmi *hdmi)
+{
+ struct fsl_mxc_lcd_platform_data *plat = hdmi->pdev->dev.platform_data;
+
+ dev_dbg(&hdmi->pdev->dev, "power off\n");
+
+ /* Disable pins to HDMI */
+ if (plat->disable_pins)
+ plat->disable_pins();
+}
+
+static int mxc_hdmi_fb_event(struct notifier_block *nb,
+ unsigned long val, void *v)
+{
+ struct fb_event *event = v;
+ struct fb_info *fbi = event->info;
+ struct mxc_hdmi *hdmi = container_of(nb, struct mxc_hdmi, nb);
+
+ if (strcmp(event->info->fix.id, hdmi->fbi->fix.id))
+ return 0;
+
+ switch (val) {
+ case FB_EVENT_MODE_CHANGE:
+ break;
+ case FB_EVENT_BLANK:
+ if (*((int *)event->data) == FB_BLANK_UNBLANK)
+ mxc_hdmi_poweron(hdmi);
+ else
+ mxc_hdmi_poweroff(hdmi);
+ break;
+ }
+ return 0;
+}
+
+static bool hdmi_is_mode_equal(struct fb_videomode *mode1,
+ struct fb_videomode *mode2)
+{
+ if ((mode1->xres == mode2->xres) &&
+ (mode1->yres == mode2->yres) &&
+ ((mode1->refresh >= mode2->refresh - 1) &&
+ (mode1->refresh <= mode2->refresh + 1)) &&
+ ((mode1->flag & mode2->flag) == mode2->flag))
+ return true;
+ else
+ return false;
+}
+
+static int mxc_hdmi_get_vmode(struct fb_info *fbi)
+{
+ int i;
+ int vci_code = 0;
+ struct fb_videomode m;
+
+ fb_var_to_videomode(&m, &fbi->var);
+
+ for (i = 1; i < NUM_CEA_VIDEO_MODES; i++)
+ if (hdmi_is_mode_equal(&m, &hdmi_cea_video_modes[i-1])) {
+ vci_code = i;
+ break;
+ }
+
+ return vci_code;
+}
+
+
+static int mxc_hdmi_disp_init(struct mxc_dispdrv_entry *disp)
+{
+ int ret = 0;
+ struct mxc_hdmi *hdmi = mxc_dispdrv_getdata(disp);
+ struct mxc_dispdrv_setting *setting = mxc_dispdrv_getsetting(disp);
+ struct fsl_mxc_lcd_platform_data *plat = hdmi->pdev->dev.platform_data;
+ struct resource *res =
+ platform_get_resource(hdmi->pdev, IORESOURCE_MEM, 0);
+ int irq = platform_get_irq(hdmi->pdev, 0);
+ bool found = false;
+ int i;
+ int mCode;
+
+ if (!res || !plat || irq < 0)
+ return -ENODEV;
+
+ setting->dev_id = plat->ipu_id;
+ setting->disp_id = plat->disp_id;
+ setting->if_fmt = IPU_PIX_FMT_RGB24;
+
+ hdmi->fbi = setting->fbi;
+
+ if (plat->io_reg) {
+ hdmi->io_reg = regulator_get(&hdmi->pdev->dev, plat->io_reg);
+ if (!IS_ERR(hdmi->io_reg)) {
+ regulator_set_voltage(hdmi->io_reg, 3300000, 3300000);
+ regulator_enable(hdmi->io_reg);
+ }
+ }
+ if (plat->analog_reg) {
+ hdmi->analog_reg =
+ regulator_get(&hdmi->pdev->dev, plat->analog_reg);
+ if (!IS_ERR(hdmi->analog_reg)) {
+ regulator_set_voltage(hdmi->analog_reg,
+ 1300000, 1300000);
+ regulator_enable(hdmi->analog_reg);
+ }
+ }
+
+ /* Claim HDMI pins */
+ if (plat->get_pins)
+ if (!plat->get_pins()) {
+ ret = -EACCES;
+ goto egetpins;
+ }
+
+ hdmi->hdmi_clk = clk_get(&hdmi->pdev->dev, "hdmi_isfr_clk");
+ if (IS_ERR(hdmi->hdmi_clk)) {
+ ret = PTR_ERR(hdmi->hdmi_clk);
+ dev_err(&hdmi->pdev->dev,
+ "Unable to get HDMI clk: %d\n", ret);
+ goto egetclk;
+ }
+
+ ret = clk_enable(hdmi->hdmi_clk);
+ if (ret < 0) {
+ dev_err(&hdmi->pdev->dev,
+ "Cannot enable HDMI clock: %d\n", ret);
+ goto erate;
+ }
+ dev_dbg(&hdmi->pdev->dev, "Enabled HDMI clocks\n");
+
+ if (!request_mem_region(res->start, resource_size(res),
+ dev_name(&hdmi->pdev->dev))) {
+ dev_err(&hdmi->pdev->dev,
+ "HDMI register region already claimed\n");
+ ret = -EBUSY;
+ goto ereqreg;
+ }
+
+ hdmi->base = ioremap(res->start, resource_size(res));
+ if (!hdmi->base) {
+ dev_err(&hdmi->pdev->dev,
+ "HDMI register iomap failed\n");
+ ret = -ENOMEM;
+ goto emap;
+ }
+
+ /* Product and revision IDs */
+ dev_info(&hdmi->pdev->dev,
+ "Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n",
+ readb(hdmi->base + HDMI_DESIGN_ID),
+ readb(hdmi->base + HDMI_REVISION_ID),
+ readb(hdmi->base + HDMI_PRODUCT_ID0),
+ readb(hdmi->base + HDMI_PRODUCT_ID1));
+
+ ret = request_irq(irq, mxc_hdmi_hotplug, 0,
+ dev_name(&hdmi->pdev->dev), hdmi);
+ if (ret < 0) {
+ dev_err(&hdmi->pdev->dev, "Unable to request irq: %d\n", ret);
+ goto ereqirq;
+ }
+
+ /* try to read edid */
+ ret = mxc_hdmi_read_edid(hdmi, hdmi->fbi);
+ if (ret < 0)
+ dev_warn(&hdmi->pdev->dev, "Can not read edid\n");
+ else {
+ INIT_LIST_HEAD(&hdmi->fbi->modelist);
+ if (hdmi->fbi->monspecs.modedb_len > 0) {
+ int i;
+ const struct fb_videomode *mode;
+ struct fb_videomode m;
+
+ for (i = 0; i < hdmi->fbi->monspecs.modedb_len; i++) {
+ /*FIXME now we do not support interlaced mode */
+ if (!(hdmi->fbi->monspecs.modedb[i].vmode
+ & FB_VMODE_INTERLACED)) {
+ fb_add_videomode(
+ &hdmi->fbi->monspecs.modedb[i],
+ &hdmi->fbi->modelist);
+ }
+ }
+
+ fb_find_mode(&hdmi->fbi->var, hdmi->fbi,
+ setting->dft_mode_str, NULL, 0, NULL,
+ setting->default_bpp);
+
+ fb_var_to_videomode(&m, &hdmi->fbi->var);
+ mode = fb_find_nearest_mode(&m,
+ &hdmi->fbi->modelist);
+ fb_videomode_to_var(&hdmi->fbi->var, mode);
+ found = 1;
+ }
+ }
+
+ if (!found) {
+ ret = fb_find_mode(&hdmi->fbi->var, hdmi->fbi,
+ setting->dft_mode_str, NULL, 0, NULL,
+ setting->default_bpp);
+ if (!ret) {
+ ret = -EINVAL;
+ goto efindmode;
+ }
+ }
+
+ hdmi->nb.notifier_call = mxc_hdmi_fb_event;
+ ret = fb_register_client(&hdmi->nb);
+ if (ret < 0)
+ goto efbclient;
+
+ mCode = mxc_hdmi_get_vmode(hdmi->fbi);
+ if (mCode == 0)
+ mCode = DEFAULT_VIDEO_MODE;
+
+ memset(&hdmi->hdmi_data, 0, sizeof(struct hdmi_data_info));
+
+ hdmi->hdmi_data.enc_in_format = eRGB;
+ hdmi->hdmi_data.enc_out_format = eRGB;
+ hdmi->hdmi_data.enc_color_depth = 8;
+ hdmi->hdmi_data.colorimetry = eITU601;
+ hdmi->hdmi_data.pix_repet_factor = 0;
+ hdmi->hdmi_data.hdcp_enable = 0;
+ hdmi->hdmi_data.video_mode.mCode = mCode;
+ hdmi->hdmi_data.video_mode.mHdmiDviSel = TRUE;
+ hdmi->hdmi_data.video_mode.mRVBlankInOSC = FALSE;
+ hdmi->hdmi_data.video_mode.mRefreshRate = 60000;
+ hdmi->hdmi_data.video_mode.mDataEnablePolarity = TRUE;
+
+ hdmi_video_force_output(hdmi, TRUE);
+ hdmi_av_composer(hdmi);
+ hdmi_video_packetize(hdmi);
+ hdmi_video_csc(hdmi);
+ hdmi_video_sample(hdmi);
+ hdmi_audio_mute(hdmi, TRUE);
+ hdmi_tx_hdcp_config(hdmi);
+ hdmi_phy_init(hdmi, TRUE);
+ hdmi_video_force_output(hdmi, FALSE);
+
+ return ret;
+
+efbclient:
+ free_irq(irq, hdmi);
+efindmode:
+ereqirq:
+ iounmap(hdmi->base);
+emap:
+ release_mem_region(res->start, resource_size(res));
+ereqreg:
+ clk_disable(hdmi->hdmi_clk);
+erate:
+ clk_put(hdmi->hdmi_clk);
+egetclk:
+egetpins:
+ return ret;
+}
+
+static void mxc_hdmi_disp_deinit(struct mxc_dispdrv_entry *disp)
+{
+ struct mxc_hdmi *hdmi = mxc_dispdrv_getdata(disp);
+ struct fsl_mxc_lcd_platform_data *plat = hdmi->pdev->dev.platform_data;
+
+ fb_unregister_client(&hdmi->nb);
+
+ mxc_hdmi_poweroff(hdmi);
+
+ /* Release HDMI pins */
+ if (plat->put_pins)
+ plat->put_pins();
+
+ platform_device_unregister(hdmi->pdev);
+
+ kfree(hdmi);
+}
+
+static struct mxc_dispdrv_driver mxc_hdmi_drv = {
+ .name = DISPDRV_HDMI,
+ .init = mxc_hdmi_disp_init,
+ .deinit = mxc_hdmi_disp_deinit,
+};
+
+static int __init mxc_hdmi_probe(struct platform_device *pdev)
+{
+ struct mxc_hdmi *hdmi;
+ int ret = 0;
+
+ /* Check that I2C driver is loaded and available */
+ if (!hdmi_i2c)
+ return -ENODEV;
+
+ hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL);
+ if (!hdmi) {
+ dev_err(&pdev->dev, "Cannot allocate device data\n");
+ ret = -ENOMEM;
+ goto ealloc;
+ }
+
+ hdmi->pdev = pdev;
+
+ hdmi->disp_mxc_hdmi = mxc_dispdrv_register(&mxc_hdmi_drv);
+ if (IS_ERR(hdmi->disp_mxc_hdmi)) {
+ dev_err(&pdev->dev, "Failed to register dispdrv - 0x%x\n",
+ (int)hdmi->disp_mxc_hdmi);
+ ret = (int)hdmi->disp_mxc_hdmi;
+ goto edispdrv;
+ }
+ mxc_dispdrv_setdata(hdmi->disp_mxc_hdmi, hdmi);
+
+ platform_set_drvdata(pdev, hdmi);
+
+ return 0;
+edispdrv:
+ kfree(hdmi);
+ealloc:
+ return ret;
+}
+
+static int __exit mxc_hdmi_remove(struct platform_device *pdev)
+{
+ struct fsl_mxc_lcd_platform_data *pdata = pdev->dev.platform_data;
+ struct mxc_hdmi *hdmi = platform_get_drvdata(pdev);
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ int irq = platform_get_irq(pdev, 0);
+
+ fb_unregister_client(&hdmi->nb);
+
+ /* No new work will be scheduled, wait for running ISR */
+ free_irq(irq, hdmi);
+ clk_disable(hdmi->hdmi_clk);
+ clk_put(hdmi->hdmi_clk);
+ iounmap(hdmi->base);
+ release_mem_region(res->start, resource_size(res));
+ kfree(hdmi);
+
+ return 0;
+}
+
+static struct platform_driver mxc_hdmi_driver = {
+ .probe = mxc_hdmi_probe,
+ .remove = mxc_hdmi_remove,
+ .driver = {
+ .name = "mxc_hdmi",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init mxc_hdmi_init(void)
+{
+ return platform_driver_register(&mxc_hdmi_driver);
+}
+module_init(mxc_hdmi_init);
+
+static void __exit mxc_hdmi_exit(void)
+{
+ platform_driver_unregister(&mxc_hdmi_driver);
+}
+module_exit(mxc_hdmi_exit);
+
+
+static int __devinit mxc_hdmi_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_BYTE | I2C_FUNC_I2C))
+ return -ENODEV;
+
+ hdmi_i2c = client;
+
+ return 0;
+}
+
+static int __devexit mxc_hdmi_i2c_remove(struct i2c_client *client)
+{
+ hdmi_i2c = NULL;
+ return 0;
+}
+
+static const struct i2c_device_id mxc_hdmi_i2c_id[] = {
+ { "mxc_hdmi_i2c", 0 },
+ {},
+};
+MODULE_DEVICE_TABLE(i2c, mxc_hdmi_i2c_id);
+
+static struct i2c_driver mxc_hdmi_i2c_driver = {
+ .driver = {
+ .name = "mxc_hdmi_i2c",
+ },
+ .probe = mxc_hdmi_i2c_probe,
+ .remove = mxc_hdmi_i2c_remove,
+ .id_table = mxc_hdmi_i2c_id,
+};
+
+static int __init mxc_hdmi_i2c_init(void)
+{
+ return i2c_add_driver(&mxc_hdmi_i2c_driver);
+}
+
+static void __exit mxc_hdmi_i2c_exit(void)
+{
+ i2c_del_driver(&mxc_hdmi_i2c_driver);
+}
+
+module_init(mxc_hdmi_i2c_init);
+module_exit(mxc_hdmi_i2c_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");