v4l: exynos/tv: Add TV/HDMI/Mixer driver
authorShirish S <s.shirish@samsung.com>
Wed, 20 Jun 2012 09:41:57 +0000 (02:41 -0700)
committerPrathyush K <prathyush.k@samsung.com>
Wed, 20 Jun 2012 12:46:48 +0000 (18:16 +0530)
This patch adds non-mainlined Exynos5 HDMI driver.

Change-Id: Ieb0c0b29fa2b9ba61249ae9d83feeda9025ffd48
Signed-off-by: Shirish S <s.shirish@samsung.com>
29 files changed:
drivers/media/video/exynos/Kconfig [new file with mode: 0644]
drivers/media/video/exynos/Makefile [new file with mode: 0644]
drivers/media/video/exynos/tv/Kconfig [new file with mode: 0644]
drivers/media/video/exynos/tv/Makefile [new file with mode: 0644]
drivers/media/video/exynos/tv/cec.h [new file with mode: 0644]
drivers/media/video/exynos/tv/hdcp_drv.c [new file with mode: 0644]
drivers/media/video/exynos/tv/hdmi.h [new file with mode: 0644]
drivers/media/video/exynos/tv/hdmi_cec.c [new file with mode: 0644]
drivers/media/video/exynos/tv/hdmi_cec_ctrl.c [new file with mode: 0644]
drivers/media/video/exynos/tv/hdmi_drv.c [new file with mode: 0644]
drivers/media/video/exynos/tv/hdmi_reg_4210.c [new file with mode: 0644]
drivers/media/video/exynos/tv/hdmi_reg_5250.c [new file with mode: 0644]
drivers/media/video/exynos/tv/hdmiphy_conf_4210.c [new file with mode: 0644]
drivers/media/video/exynos/tv/hdmiphy_conf_5250.c [new file with mode: 0644]
drivers/media/video/exynos/tv/hdmiphy_drv.c [new file with mode: 0644]
drivers/media/video/exynos/tv/mixer.h [new file with mode: 0644]
drivers/media/video/exynos/tv/mixer_drv.c [new file with mode: 0644]
drivers/media/video/exynos/tv/mixer_grp_layer.c [new file with mode: 0644]
drivers/media/video/exynos/tv/mixer_reg.c [new file with mode: 0644]
drivers/media/video/exynos/tv/mixer_vb2.c [new file with mode: 0644]
drivers/media/video/exynos/tv/mixer_video.c [new file with mode: 0644]
drivers/media/video/exynos/tv/mixer_video_layer.c [new file with mode: 0644]
drivers/media/video/exynos/tv/mixer_vp_layer.c [new file with mode: 0644]
drivers/media/video/exynos/tv/regs-hdmi-4210.h [new file with mode: 0644]
drivers/media/video/exynos/tv/regs-hdmi-5250.h [new file with mode: 0644]
drivers/media/video/exynos/tv/regs-mixer.h [new file with mode: 0644]
drivers/media/video/exynos/tv/regs-sdo.h [new file with mode: 0644]
drivers/media/video/exynos/tv/regs-vp.h [new file with mode: 0644]
drivers/media/video/exynos/tv/sdo_drv.c [new file with mode: 0644]

diff --git a/drivers/media/video/exynos/Kconfig b/drivers/media/video/exynos/Kconfig
new file mode 100644 (file)
index 0000000..f5ea172
--- /dev/null
@@ -0,0 +1,17 @@
+config VIDEO_EXYNOS
+       bool "Exynos Multimedia Devices"
+       depends on ARCH_EXYNOS5
+       default n
+       select VIDEO_FIXED_MINOR_RANGES
+       select VIDEOBUF2_DMA_CONTIG
+       help
+         This is a representative exynos multimedia device.
+
+if VIDEO_EXYNOS
+       source "drivers/media/video/exynos/tv/Kconfig"
+endif
+
+config MEDIA_EXYNOS
+       bool
+       help
+         Compile mdev to use exynos5 media device driver.
diff --git a/drivers/media/video/exynos/Makefile b/drivers/media/video/exynos/Makefile
new file mode 100644 (file)
index 0000000..c586fd3
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_VIDEO_EXYNOS_TV)           += tv/
diff --git a/drivers/media/video/exynos/tv/Kconfig b/drivers/media/video/exynos/tv/Kconfig
new file mode 100644 (file)
index 0000000..ca9c191
--- /dev/null
@@ -0,0 +1,122 @@
+# drivers/media/video/s5p-tv/Kconfig
+#
+# Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+#      http://www.samsung.com/
+# Tomasz Stanislawski <t.stanislaws@samsung.com>
+#
+# Licensed under GPL
+
+comment "Exynos TV support"
+
+config VIDEO_EXYNOS_TV
+       bool "Samsung TV driver for S5P platform (experimental)"
+       depends on PLAT_S5P
+       depends on EXPERIMENTAL
+       select MEDIA_EXYNOS
+       select VIDEO_EXYNOS_HDMI
+       select VIDEO_EXYNOS_MIXER
+       default n
+       ---help---
+         Say Y here to enable selecting the TV output devices for
+         Samsung S5P platform.
+
+if VIDEO_EXYNOS_TV
+
+config VIDEO_EXYNOS_HDMI
+       tristate "Samsung HDMI Driver"
+       depends on VIDEO_V4L2
+       depends on VIDEO_EXYNOS_TV
+       select VIDEO_EXYNOS_HDMIPHY
+       help
+         Say Y here if you want support for the HDMI output
+         interface in S5P Samsung SoC. The driver can be compiled
+         as module. It is an auxiliary driver, that exposes a V4L2
+         subdev for use by other drivers. This driver requires
+         hdmiphy driver to work correctly.
+
+config VIDEO_EXYNOS_HDMI_AUDIO_I2S
+       bool "Enable HDMI audio using I2S path"
+       depends on VIDEO_EXYNOS_HDMI
+       depends on SND_SOC_SAMSUNG_SMDK_WM8994
+       default y
+       help
+         Enables HDMI audio through I2S path.
+
+config VIDEO_EXYNOS_HDMI_AUDIO_SPDIF
+       bool "Enable HDMI audio using SPDIF path"
+       depends on VIDEO_EXYNOS_HDMI
+       depends on SND_SOC_SAMSUNG_SMDK_SPDIF
+       default n
+       help
+         Enables HDMI audio through SPDIF path.
+
+config VIDEO_EXYNOS_HDCP
+       bool "Enable HDCP"
+       depends on VIDEO_EXYNOS_HDMI
+       depends on I2C
+       default n
+       help
+         Enables HDCP feature. However if you want to use HDCP,
+         device private key must be e-fused in SoC.
+
+config VIDEO_EXYNOS_HDMI_DEBUG
+       bool "Enable debug for HDMI Driver"
+       depends on VIDEO_EXYNOS_HDMI
+       default n
+       help
+         Enables debugging for HDMI driver.
+
+config VIDEO_EXYNOS_HDMIPHY
+       tristate "Samsung HDMIPHY Driver"
+       depends on VIDEO_DEV && VIDEO_V4L2 && I2C
+       depends on VIDEO_EXYNOS_TV
+       help
+         Say Y here if you want support for the physical HDMI
+         interface in S5P Samsung SoC. The driver can be compiled
+         as module. It is an I2C driver, that exposes a V4L2
+         subdev for use by other drivers.
+
+config VIDEO_EXYNOS_SDO
+       tristate "Samsung Analog TV Driver"
+       depends on VIDEO_DEV && VIDEO_V4L2
+       depends on VIDEO_EXYNOS_TV
+       depends on CPU_EXYNOS4210
+       help
+         Say Y here if you want support for the analog TV output
+         interface in S5P Samsung SoC. The driver can be compiled
+         as module. It is an auxiliary driver, that exposes a V4L2
+         subdev for use by other drivers. This driver requires
+         hdmiphy driver to work correctly.
+
+config VIDEO_EXYNOS_MIXER
+       tristate "Samsung Mixer and Video Processor Driver"
+       depends on VIDEO_DEV && VIDEO_V4L2
+       depends on VIDEO_EXYNOS_TV
+       #select VIDEOBUF2_DMA_CONTIG
+       select VIDEOBUF2_FB
+       help
+         Say Y here if you want support for the Mixer in Samsung S5P SoCs.
+         This device produce image data to one of output interfaces.
+
+config VIDEO_EXYNOS_HDMI_CEC
+       tristate "Samsung HDMI CEC Driver"
+       depends on VIDEO_DEV && VIDEO_V4L2 && I2C
+       depends on VIDEO_EXYNOS_TV
+       help
+         Say Y here if you want support for the HDMI CEC
+         interface in S5P Samsung SoC. The driver can be compiled
+         as module.
+
+config VIDEO_SAMSUNG_MEMSIZE_TV
+       int "Memory size in kbytes for TV"
+       depends on VIDEO_EXYNOS_MIXER && VIDEOBUF2_CMA_PHYS
+       default "16200"
+
+config VIDEO_EXYNOS_MIXER_DEBUG
+       bool "Enable debug for Mixer Driver"
+       depends on VIDEO_EXYNOS_MIXER
+       default n
+       help
+         Enables debugging for Mixer driver.
+
+endif # VIDEO_EXYNOS_TV
diff --git a/drivers/media/video/exynos/tv/Makefile b/drivers/media/video/exynos/tv/Makefile
new file mode 100644 (file)
index 0000000..29cef3f
--- /dev/null
@@ -0,0 +1,31 @@
+# drivers/media/video/samsung/tvout/Makefile
+#
+# Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+#      http://www.samsung.com/
+# Tomasz Stanislawski <t.stanislaws@samsung.com>
+#
+# Licensed under GPL
+obj-$(CONFIG_VIDEO_EXYNOS_HDMIPHY) += s5p-hdmiphy.o
+s5p-hdmiphy-y += hdmiphy_drv.o
+obj-$(CONFIG_VIDEO_EXYNOS_HDMI) += s5p-hdmi.o
+s5p-hdmi-y += hdcp_drv.o hdmi_drv.o
+obj-$(CONFIG_VIDEO_EXYNOS_SDO) += s5p-sdo.o
+s5p-sdo-y += sdo_drv.o
+obj-$(CONFIG_VIDEO_EXYNOS_MIXER) += s5p-mixer.o
+s5p-mixer-y += mixer_vb2.o mixer_drv.o mixer_video.o mixer_reg.o mixer_grp_layer.o
+obj-$(CONFIG_VIDEO_EXYNOS_HDMI_CEC) += s5p-hdmi_cec.o
+s5p-hdmi_cec-y += hdmi_cec.o hdmi_cec_ctrl.o
+
+ifeq ($(CONFIG_ARCH_EXYNOS4), y)
+       s5p-mixer-y += mixer_vp_layer.o
+else
+       s5p-mixer-y += mixer_video_layer.o
+endif
+
+ifeq ($(CONFIG_VIDEO_EXYNOS_HDMI),y)
+       ifeq ($(CONFIG_CPU_EXYNOS4210), y)
+               s5p-hdmi-y += hdmi_reg_4210.o hdmiphy_conf_4210.o
+       else
+               s5p-hdmi-y += hdmi_reg_5250.o hdmiphy_conf_5250.o
+       endif
+endif
diff --git a/drivers/media/video/exynos/tv/cec.h b/drivers/media/video/exynos/tv/cec.h
new file mode 100644 (file)
index 0000000..ba54bd7
--- /dev/null
@@ -0,0 +1,84 @@
+/* linux/drivers/media/video/samsung/tvout/hw_if/hw_if.h
+ *
+ * Copyright (c) 2010 Samsung Electronics
+ *             http://www.samsung.com/
+ *
+ * Header file for interface of Samsung TVOUT-related hardware
+ *
+ * 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.
+ */
+
+#ifndef _SAMSUNG_TVOUT_CEC_H_
+#define _SAMSUNG_TVOUT_CEC_H_ __FILE__
+
+/*****************************************************************************
+ * This file includes declarations for external functions of
+ * Samsung TVOUT-related hardware. So only external functions
+ * to be used by higher layer must exist in this file.
+ *
+ * Higher layer must use only the declarations included in this file.
+ ****************************************************************************/
+
+#define to_tvout_plat(d) (to_platform_device(d)->dev.platform_data)
+
+#ifndef tvout_dbg
+#ifdef CONFIG_TV_DEBUG
+#define tvout_dbg(fmt, ...)                                    \
+               printk(KERN_INFO "[%s] %s(): " fmt,             \
+                       DRV_NAME, __func__, ##__VA_ARGS__)
+#else
+#define tvout_dbg(fmt, ...)
+#endif
+#endif
+
+enum s5p_tvout_endian {
+       TVOUT_LITTLE_ENDIAN = 0,
+       TVOUT_BIG_ENDIAN = 1
+};
+
+enum cec_state {
+       STATE_RX,
+       STATE_TX,
+       STATE_DONE,
+       STATE_ERROR
+};
+
+struct cec_rx_struct {
+       spinlock_t lock;
+       wait_queue_head_t waitq;
+       atomic_t state;
+       u8 *buffer;
+       unsigned int size;
+};
+
+struct cec_tx_struct {
+       wait_queue_head_t waitq;
+       atomic_t state;
+};
+
+extern struct cec_rx_struct cec_rx_struct;
+extern struct cec_tx_struct cec_tx_struct;
+
+void s5p_cec_set_divider(void);
+void s5p_cec_enable_rx(void);
+void s5p_cec_mask_rx_interrupts(void);
+void s5p_cec_unmask_rx_interrupts(void);
+void s5p_cec_mask_tx_interrupts(void);
+void s5p_cec_unmask_tx_interrupts(void);
+void s5p_cec_reset(void);
+void s5p_cec_tx_reset(void);
+void s5p_cec_rx_reset(void);
+void s5p_cec_threshold(void);
+void s5p_cec_set_tx_state(enum cec_state state);
+void s5p_cec_set_rx_state(enum cec_state state);
+void s5p_cec_copy_packet(char *data, size_t count);
+void s5p_cec_set_addr(u32 addr);
+u32 s5p_cec_get_status(void);
+void s5p_clr_pending_tx(void);
+void s5p_clr_pending_rx(void);
+void s5p_cec_get_rx_buf(u32 size, u8 *buffer);
+void __init s5p_cec_mem_probe(struct platform_device *pdev);
+
+#endif /* _SAMSUNG_TVOUT_CEC_H_ */
diff --git a/drivers/media/video/exynos/tv/hdcp_drv.c b/drivers/media/video/exynos/tv/hdcp_drv.c
new file mode 100644 (file)
index 0000000..d37cd41
--- /dev/null
@@ -0,0 +1,996 @@
+/* linux/drivers/media/video/exynos/tv/hdcp_drv.c
+ *
+ * Copyright (c) 2011 Samsung Electronics
+ *             http://www.samsung.com/
+ *
+ * HDCP function for Samsung TV driver
+ *
+ * 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/i2c.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/workqueue.h>
+#include <linux/export.h>
+#include <linux/module.h>
+
+#include "hdmi.h"
+#include "regs-hdmi-5250.h"
+
+#define AN_SIZE                        8
+#define AKSV_SIZE              5
+#define BKSV_SIZE              5
+#define MAX_KEY_SIZE           16
+
+#define BKSV_RETRY_CNT         14
+#define BKSV_DELAY             100
+
+#define DDC_RETRY_CNT          400000
+#define DDC_DELAY              25
+
+#define KEY_LOAD_RETRY_CNT     1000
+#define ENCRYPT_CHECK_CNT      10
+
+#define KSV_FIFO_RETRY_CNT     50
+#define KSV_FIFO_CHK_DELAY     100 /* ms */
+#define KSV_LIST_RETRY_CNT     10000
+
+#define BCAPS_SIZE             1
+#define BSTATUS_SIZE           2
+#define SHA_1_HASH_SIZE                20
+#define HDCP_MAX_DEVS          128
+#define HDCP_KSV_SIZE          5
+
+/* offset of HDCP port */
+#define HDCP_BKSV              0x00
+#define HDCP_RI                        0x08
+#define HDCP_AKSV              0x10
+#define HDCP_AN                        0x18
+#define HDCP_SHA1              0x20
+#define HDCP_BCAPS             0x40
+#define HDCP_BSTATUS           0x41
+#define HDCP_KSVFIFO           0x43
+
+#define KSV_FIFO_READY                 (0x1 << 5)
+
+#define MAX_CASCADE_EXCEEDED_ERROR     (-2)
+#define MAX_DEVS_EXCEEDED_ERROR                (-3)
+#define REPEATER_ILLEGAL_DEVICE_ERROR  (-4)
+#define REPEATER_TIMEOUT_ERROR         (-5)
+
+#define MAX_CASCADE_EXCEEDED           (0x1 << 3)
+#define MAX_DEVS_EXCEEDED              (0x1 << 7)
+
+struct i2c_client *hdcp_client;
+
+int hdcp_i2c_read(struct hdmi_device *hdev, u8 offset, int bytes, u8 *buf)
+{
+       struct device *dev = hdev->dev;
+       struct i2c_client *i2c = hdcp_client;
+       int ret, cnt = 0;
+
+       struct i2c_msg msg[] = {
+               [0] = {
+                       .addr = i2c->addr,
+                       .flags = 0,
+                       .len = 1,
+                       .buf = &offset
+               },
+               [1] = {
+                       .addr = i2c->addr,
+                       .flags = I2C_M_RD,
+                       .len = bytes,
+                       .buf = buf
+               }
+       };
+
+       do {
+               if (!is_hdmi_streaming(hdev))
+                       goto ddc_read_err;
+
+               ret = i2c_transfer(i2c->adapter, msg, 2);
+
+               if (ret < 0 || ret != 2)
+                       dev_dbg(dev, "%s: can't read data, retry %d\n",
+                                       __func__, cnt);
+               else
+                       break;
+
+               if (hdev->hdcp_info.auth_status == FIRST_AUTHENTICATION_DONE
+                               || hdev->hdcp_info.auth_status
+                                       == SECOND_AUTHENTICATION_DONE)
+                       goto ddc_read_err;
+
+               msleep(DDC_DELAY);
+               cnt++;
+       } while (cnt < DDC_RETRY_CNT);
+
+       if (cnt == DDC_RETRY_CNT)
+               goto ddc_read_err;
+
+       dev_dbg(dev, "%s: read data ok\n", __func__);
+
+       return 0;
+
+ddc_read_err:
+       dev_err(dev, "%s: can't read data, timeout\n", __func__);
+       return -ETIME;
+}
+
+int hdcp_i2c_write(struct hdmi_device *hdev, u8 offset, int bytes, u8 *buf)
+{
+       struct device *dev = hdev->dev;
+       struct i2c_client *i2c = hdcp_client;
+       u8 msg[bytes + 1];
+       int ret, cnt = 0;
+
+       msg[0] = offset;
+       memcpy(&msg[1], buf, bytes);
+
+       do {
+               if (!is_hdmi_streaming(hdev))
+                       goto ddc_write_err;
+
+               ret = i2c_master_send(i2c, msg, bytes + 1);
+
+               if (ret < 0 || ret < bytes + 1)
+                       dev_dbg(dev, "%s: can't write data, retry %d\n",
+                                       __func__, cnt);
+               else
+                       break;
+
+               msleep(DDC_DELAY);
+               cnt++;
+       } while (cnt < DDC_RETRY_CNT);
+
+       if (cnt == DDC_RETRY_CNT)
+               goto ddc_write_err;
+
+       dev_dbg(dev, "%s: write data ok\n", __func__);
+       return 0;
+
+ddc_write_err:
+       dev_err(dev, "%s: can't write data, timeout\n", __func__);
+       return -ETIME;
+}
+
+static int __devinit hdcp_probe(struct i2c_client *client,
+                       const struct i2c_device_id *dev_id)
+{
+       int ret = 0;
+
+       hdcp_client = client;
+
+       dev_info(&client->adapter->dev, "attached exynos hdcp "
+               "into i2c adapter successfully\n");
+
+       return ret;
+}
+
+static int hdcp_remove(struct i2c_client *client)
+{
+       dev_info(&client->adapter->dev, "detached exynos hdcp "
+               "from i2c adapter successfully\n");
+
+       return 0;
+}
+
+static int hdcp_suspend(struct i2c_client *cl, pm_message_t mesg)
+{
+       return 0;
+};
+
+static int hdcp_resume(struct i2c_client *cl)
+{
+       return 0;
+};
+
+static struct i2c_device_id hdcp_idtable[] = {
+       {"exynos_hdcp", 0},
+};
+MODULE_DEVICE_TABLE(i2c, hdcp_idtable);
+
+static struct i2c_driver hdcp_driver = {
+       .driver = {
+               .name = "exynos_hdcp",
+               .owner = THIS_MODULE,
+       },
+       .id_table       = hdcp_idtable,
+       .probe          = hdcp_probe,
+       .remove         = __devexit_p(hdcp_remove),
+       .suspend        = hdcp_suspend,
+       .resume         = hdcp_resume,
+};
+
+static int __init hdcp_init(void)
+{
+       return i2c_add_driver(&hdcp_driver);
+}
+
+static void __exit hdcp_exit(void)
+{
+       i2c_del_driver(&hdcp_driver);
+}
+
+module_init(hdcp_init);
+module_exit(hdcp_exit);
+
+/* internal functions of HDCP */
+static void hdcp_encryption(struct hdmi_device *hdev, bool on)
+{
+       if (on)
+               hdmi_write_mask(hdev, HDMI_ENC_EN, ~0, HDMI_HDCP_ENC_ENABLE);
+       else
+               hdmi_write_mask(hdev, HDMI_ENC_EN, 0, HDMI_HDCP_ENC_ENABLE);
+
+       hdmi_reg_mute(hdev, !on);
+}
+
+static int hdcp_write_key(struct hdmi_device *hdev, int size,
+               int reg, int offset)
+{
+       struct device *dev = hdev->dev;
+       u8 buf[MAX_KEY_SIZE];
+       int cnt, zero = 0;
+       int i;
+
+       memset(buf, 0, sizeof(buf));
+       hdmi_read_bytes(hdev, reg, buf, size);
+
+       for (cnt = 0; cnt < size; cnt++)
+               if (buf[cnt] == 0)
+                       zero++;
+
+       if (zero == size) {
+               dev_dbg(dev, "%s: %s is null\n", __func__,
+                               offset == HDCP_AN ? "An" : "Aksv");
+               goto write_key_err;
+       }
+
+       if (hdcp_i2c_write(hdev, offset, size, buf) < 0)
+               goto write_key_err;
+
+       for (i = 1; i < size + 1; i++)
+               dev_dbg(dev, "%s: %s[%d] : 0x%02x\n", __func__,
+                               offset == HDCP_AN ? "An" : "Aksv", i, buf[i]);
+
+       return 0;
+
+write_key_err:
+       dev_dbg(dev, "%s: write %s is failed\n", __func__,
+                       offset == HDCP_AN ? "An" : "Aksv");
+       return -1;
+}
+
+static int hdcp_read_bcaps(struct hdmi_device *hdev)
+{
+       struct device *dev = hdev->dev;
+       u8 bcaps = 0;
+
+       if (hdcp_i2c_read(hdev, HDCP_BCAPS, BCAPS_SIZE, &bcaps) < 0)
+               goto bcaps_read_err;
+
+       if (!is_hdmi_streaming(hdev))
+               goto bcaps_read_err;
+
+       hdmi_writeb(hdev, HDMI_HDCP_BCAPS, bcaps);
+
+       if (bcaps & HDMI_HDCP_BCAPS_REPEATER)
+               hdev->hdcp_info.is_repeater = 1;
+       else
+               hdev->hdcp_info.is_repeater = 0;
+
+       dev_dbg(dev, "%s: device is %s\n", __func__,
+                       hdev->hdcp_info.is_repeater ? "REPEAT" : "SINK");
+       dev_dbg(dev, "%s: [i2c] bcaps : 0x%02x\n", __func__, bcaps);
+
+       return 0;
+
+bcaps_read_err:
+       dev_err(dev, "can't read bcaps : timeout\n");
+       return -ETIME;
+}
+
+static int hdcp_read_bksv(struct hdmi_device *hdev)
+{
+       struct device *dev = hdev->dev;
+       u8 bksv[BKSV_SIZE];
+       int i, j;
+       u32 one = 0, zero = 0, result = 0;
+       u32 cnt = 0;
+
+       memset(bksv, 0, sizeof(bksv));
+
+       do {
+               if (hdcp_i2c_read(hdev, HDCP_BKSV, BKSV_SIZE, bksv) < 0)
+                       goto bksv_read_err;
+
+               for (i = 0; i < BKSV_SIZE; i++)
+                       dev_dbg(dev, "%s: i2c read : bksv[%d]: 0x%x\n",
+                                       __func__, i, bksv[i]);
+
+               for (i = 0; i < BKSV_SIZE; i++) {
+
+                       for (j = 0; j < 8; j++) {
+                               result = bksv[i] & (0x1 << j);
+
+                               if (result == 0)
+                                       zero++;
+                               else
+                                       one++;
+                       }
+
+               }
+
+               if (!is_hdmi_streaming(hdev))
+                       goto bksv_read_err;
+
+               if ((zero == 20) && (one == 20)) {
+                       hdmi_write_bytes(hdev, HDMI_HDCP_BKSV_(0),
+                                       bksv, BKSV_SIZE);
+                       break;
+               }
+               dev_dbg(dev, "%s: invalid bksv, retry : %d\n", __func__, cnt);
+
+               msleep(BKSV_DELAY);
+               cnt++;
+       } while (cnt < BKSV_RETRY_CNT);
+
+       if (cnt == BKSV_RETRY_CNT)
+               goto bksv_read_err;
+
+       dev_dbg(dev, "%s: bksv read OK, retry : %d\n", __func__, cnt);
+       return 0;
+
+bksv_read_err:
+       dev_err(dev, "%s: can't read bksv : timeout\n", __func__);
+       return -ETIME;
+}
+
+static int hdcp_read_ri(struct hdmi_device *hdev)
+{
+       struct device *dev = hdev->dev;
+       u8 ri[2] = {0, 0};
+       u8 rj[2] = {0, 0};
+
+
+       ri[0] = hdmi_readb(hdev, HDMI_HDCP_RI_0);
+       ri[1] = hdmi_readb(hdev, HDMI_HDCP_RI_1);
+
+       if (hdcp_i2c_read(hdev, HDCP_RI, 2, rj) < 0)
+               goto compare_err;
+
+       dev_dbg(dev, "%s: Rx -> rj[0]: 0x%02x, rj[1]: 0x%02x\n", __func__,
+                       rj[0], rj[1]);
+       dev_dbg(dev, "%s: Tx -> ri[0]: 0x%02x, ri[1]: 0x%02x\n", __func__,
+                       ri[0], ri[1]);
+
+       if ((ri[0] == rj[0]) && (ri[1] == rj[1]) && (ri[0] | ri[1]))
+               hdmi_writeb(hdev, HDMI_HDCP_CHECK_RESULT,
+                               HDMI_HDCP_RI_MATCH_RESULT_Y);
+       else {
+               hdmi_writeb(hdev, HDMI_HDCP_CHECK_RESULT,
+                               HDMI_HDCP_RI_MATCH_RESULT_N);
+               goto compare_err;
+       }
+
+       memset(ri, 0, sizeof(ri));
+       memset(rj, 0, sizeof(rj));
+
+       dev_dbg(dev, "%s: ri and ri' are matched\n", __func__);
+
+       return 0;
+
+compare_err:
+       hdev->hdcp_info.event = HDCP_EVENT_STOP;
+       hdev->hdcp_info.auth_status = NOT_AUTHENTICATED;
+       dev_err(dev, "%s: ri and ri' are mismatched\n", __func__);
+       msleep(10);
+       return -1;
+}
+
+static void hdcp_sw_reset(struct hdmi_device *hdev)
+{
+       u8 val;
+
+       val = hdmi_get_int_mask(hdev);
+
+       hdmi_set_int_mask(hdev, HDMI_INTC_EN_HPD_PLUG, 0);
+       hdmi_set_int_mask(hdev, HDMI_INTC_EN_HPD_UNPLUG, 0);
+
+       hdmi_sw_hpd_enable(hdev, 1);
+       hdmi_sw_hpd_plug(hdev, 0);
+       hdmi_sw_hpd_plug(hdev, 1);
+       hdmi_sw_hpd_enable(hdev, 0);
+
+       if (val & HDMI_INTC_EN_HPD_PLUG)
+               hdmi_set_int_mask(hdev, HDMI_INTC_EN_HPD_PLUG, 1);
+       if (val & HDMI_INTC_EN_HPD_UNPLUG)
+               hdmi_set_int_mask(hdev, HDMI_INTC_EN_HPD_UNPLUG, 1);
+}
+
+static int hdcp_reset_auth(struct hdmi_device *hdev)
+{
+       struct device *dev = hdev->dev;
+       u8 val;
+       unsigned long spin_flags;
+
+       if (!is_hdmi_streaming(hdev))
+               return -ENODEV;
+
+       spin_lock_irqsave(&hdev->hdcp_info.reset_lock, spin_flags);
+
+       hdev->hdcp_info.event           = HDCP_EVENT_STOP;
+       hdev->hdcp_info.auth_status     = NOT_AUTHENTICATED;
+
+       hdmi_write(hdev, HDMI_HDCP_CTRL1, 0x0);
+       hdmi_write(hdev, HDMI_HDCP_CTRL2, 0x0);
+       hdmi_reg_mute(hdev, 1);
+
+       hdcp_encryption(hdev, 0);
+
+       dev_dbg(dev, "%s: reset authentication\n", __func__);
+
+       val = HDMI_UPDATE_RI_INT_EN | HDMI_WRITE_INT_EN |
+               HDMI_WATCHDOG_INT_EN | HDMI_WTFORACTIVERX_INT_EN;
+       hdmi_write_mask(hdev, HDMI_STATUS_EN, 0, val);
+
+       hdmi_writeb(hdev, HDMI_HDCP_CHECK_RESULT, HDMI_HDCP_CLR_ALL_RESULTS);
+
+       /* need some delay (at least 1 frame) */
+       mdelay(16);
+
+       hdcp_sw_reset(hdev);
+
+       val = HDMI_UPDATE_RI_INT_EN | HDMI_WRITE_INT_EN |
+               HDMI_WATCHDOG_INT_EN | HDMI_WTFORACTIVERX_INT_EN;
+       hdmi_write_mask(hdev, HDMI_STATUS_EN, ~0, val);
+       hdmi_write_mask(hdev, HDMI_HDCP_CTRL1, ~0, HDMI_HDCP_CP_DESIRED_EN);
+       spin_unlock_irqrestore(&hdev->hdcp_info.reset_lock, spin_flags);
+
+       return 0;
+}
+
+static int hdcp_loadkey(struct hdmi_device *hdev)
+{
+       struct device *dev = hdev->dev;
+       u8 val;
+       int cnt = 0;
+
+       hdmi_write_mask(hdev, HDMI_EFUSE_CTRL, ~0,
+                       HDMI_EFUSE_CTRL_HDCP_KEY_READ);
+
+       do {
+               val = hdmi_readb(hdev, HDMI_EFUSE_STATUS);
+               if (val & HDMI_EFUSE_ECC_DONE)
+                       break;
+               cnt++;
+               mdelay(1);
+       } while (cnt < KEY_LOAD_RETRY_CNT);
+
+       if (cnt == KEY_LOAD_RETRY_CNT)
+               goto key_load_err;
+
+       val = hdmi_readb(hdev, HDMI_EFUSE_STATUS);
+
+       if (val & HDMI_EFUSE_ECC_FAIL)
+               goto key_load_err;
+
+       dev_dbg(dev, "%s: load key is ok\n", __func__);
+       return 0;
+
+key_load_err:
+       dev_err(dev, "%s: can't load key\n", __func__);
+       return -1;
+}
+
+static int hdmi_start_encryption(struct hdmi_device *hdev)
+{
+       struct device *dev = hdev->dev;
+       u8 val;
+       u32 cnt = 0;
+
+       do {
+               val = hdmi_readb(hdev, HDMI_STATUS);
+
+               if (val & HDMI_AUTHEN_ACK_AUTH) {
+                       hdcp_encryption(hdev, 1);
+                       break;
+               }
+
+               mdelay(1);
+
+               cnt++;
+       } while (cnt < ENCRYPT_CHECK_CNT);
+
+       if (cnt == ENCRYPT_CHECK_CNT)
+               goto encrypt_err;
+
+
+       dev_dbg(dev, "%s: encryption is start\n", __func__);
+       return 0;
+
+encrypt_err:
+       hdcp_encryption(hdev, 0);
+       dev_err(dev, "%s: encryption is failed\n", __func__);
+       return -1;
+}
+
+static int hdmi_check_repeater(struct hdmi_device *hdev)
+{
+       struct device *dev = hdev->dev;
+       int val, i;
+       int cnt = 0, cnt2 = 0;
+
+       u8 bcaps = 0;
+       u8 status[BSTATUS_SIZE];
+       u8 rx_v[SHA_1_HASH_SIZE];
+       u8 ksv_list[HDCP_MAX_DEVS * HDCP_KSV_SIZE];
+
+       u32 dev_cnt;
+
+       memset(status, 0, sizeof(status));
+       memset(rx_v, 0, sizeof(rx_v));
+       memset(ksv_list, 0, sizeof(ksv_list));
+
+       do {
+               if (hdcp_read_bcaps(hdev) < 0)
+                       goto check_repeater_err;
+
+               bcaps = hdmi_readb(hdev, HDMI_HDCP_BCAPS);
+
+               if (bcaps & KSV_FIFO_READY) {
+                       dev_dbg(dev, "%s: repeater : ksv fifo not ready\n",
+                                       __func__);
+                       dev_dbg(dev, "%s: retries = %d\n", __func__, cnt);
+                       break;
+               }
+
+               msleep(KSV_FIFO_CHK_DELAY);
+
+               cnt++;
+       } while (cnt < KSV_FIFO_RETRY_CNT);
+
+       if (cnt == KSV_FIFO_RETRY_CNT)
+               return REPEATER_TIMEOUT_ERROR;
+
+       dev_dbg(dev, "%s: repeater : ksv fifo ready\n", __func__);
+
+       if (hdcp_i2c_read(hdev, HDCP_BSTATUS, BSTATUS_SIZE, status) < 0)
+               goto check_repeater_err;
+
+       if (status[1] & MAX_CASCADE_EXCEEDED)
+               return MAX_CASCADE_EXCEEDED_ERROR;
+       else if (status[0] & MAX_DEVS_EXCEEDED)
+               return MAX_DEVS_EXCEEDED_ERROR;
+
+       hdmi_writeb(hdev, HDMI_HDCP_BSTATUS_0, status[0]);
+       hdmi_writeb(hdev, HDMI_HDCP_BSTATUS_1, status[1]);
+
+       dev_dbg(dev, "%s: status[0] :0x%02x\n", __func__, status[0]);
+       dev_dbg(dev, "%s: status[1] :0x%02x\n", __func__, status[1]);
+
+       dev_cnt = status[0] & 0x7f;
+
+       dev_dbg(dev, "%s: repeater : dev cnt = %d\n", __func__, dev_cnt);
+
+       if (dev_cnt) {
+
+               if (hdcp_i2c_read(hdev, HDCP_KSVFIFO, dev_cnt * HDCP_KSV_SIZE,
+                               ksv_list) < 0)
+                       goto check_repeater_err;
+
+               cnt = 0;
+
+               do {
+                       hdmi_write_bytes(hdev, HDMI_HDCP_KSV_LIST_(0),
+                                       &ksv_list[cnt * 5], HDCP_KSV_SIZE);
+
+                       val = HDMI_HDCP_KSV_WRITE_DONE;
+
+                       if (cnt == dev_cnt - 1)
+                               val |= HDMI_HDCP_KSV_END;
+
+                       hdmi_write(hdev, HDMI_HDCP_KSV_LIST_CON, val);
+
+                       if (cnt < dev_cnt - 1) {
+                               cnt2 = 0;
+                               do {
+                                       val = hdmi_readb(hdev,
+                                               HDMI_HDCP_KSV_LIST_CON);
+                                       if (val & HDMI_HDCP_KSV_READ)
+                                               break;
+                                       cnt2++;
+                               } while (cnt2 < KSV_LIST_RETRY_CNT);
+
+                               if (cnt2 == KSV_LIST_RETRY_CNT)
+                                       dev_dbg(dev, "%s: ksv list not readed\n",
+                                                       __func__);
+                       }
+                       cnt++;
+               } while (cnt < dev_cnt);
+       } else
+               hdmi_writeb(hdev, HDMI_HDCP_KSV_LIST_CON,
+                               HDMI_HDCP_KSV_LIST_EMPTY);
+
+       if (hdcp_i2c_read(hdev, HDCP_SHA1, SHA_1_HASH_SIZE, rx_v) < 0)
+               goto check_repeater_err;
+
+       for (i = 0; i < SHA_1_HASH_SIZE; i++)
+               dev_dbg(dev, "%s: [i2c] SHA-1 rx :: %02x\n", __func__, rx_v[i]);
+
+       hdmi_write_bytes(hdev, HDMI_HDCP_SHA1_(0), rx_v, SHA_1_HASH_SIZE);
+
+       val = hdmi_readb(hdev, HDMI_HDCP_SHA_RESULT);
+       if (val & HDMI_HDCP_SHA_VALID_RD) {
+               if (val & HDMI_HDCP_SHA_VALID) {
+                       dev_dbg(dev, "%s: SHA-1 result is ok\n", __func__);
+                       hdmi_writeb(hdev, HDMI_HDCP_SHA_RESULT, 0x0);
+               } else {
+                       dev_dbg(dev, "%s: SHA-1 result is not vaild\n",
+                                       __func__);
+                       hdmi_writeb(hdev, HDMI_HDCP_SHA_RESULT, 0x0);
+                       goto check_repeater_err;
+               }
+       } else {
+               dev_dbg(dev, "%s: SHA-1 result is not ready\n", __func__);
+               hdmi_writeb(hdev, HDMI_HDCP_SHA_RESULT, 0x0);
+               goto check_repeater_err;
+       }
+
+       dev_dbg(dev, "%s: check repeater is ok\n", __func__);
+       return 0;
+
+check_repeater_err:
+       dev_err(dev, "%s: check repeater is failed\n", __func__);
+       return -1;
+}
+
+static int hdcp_bksv(struct hdmi_device *hdev)
+{
+       struct device *dev = hdev->dev;
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       hdev->hdcp_info.auth_status = RECEIVER_READ_READY;
+
+       if (hdcp_read_bcaps(hdev) < 0)
+               goto bksv_start_err;
+
+       hdev->hdcp_info.auth_status = BCAPS_READ_DONE;
+
+       if (hdcp_read_bksv(hdev) < 0)
+               goto bksv_start_err;
+
+       hdev->hdcp_info.auth_status = BKSV_READ_DONE;
+
+       dev_dbg(dev, "%s: bksv start is ok\n", __func__);
+
+       return 0;
+
+bksv_start_err:
+       dev_err(dev, "%s: failed to start bksv\n", __func__);
+       msleep(100);
+       return -1;
+}
+
+static int hdcp_second_auth(struct hdmi_device *hdev)
+{
+       struct device *dev = hdev->dev;
+       int ret = 0;
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       if (!hdev->hdcp_info.hdcp_start)
+               goto second_auth_err;
+
+       if (!is_hdmi_streaming(hdev))
+               goto second_auth_err;
+
+       ret = hdmi_check_repeater(hdev);
+
+       if (!ret) {
+               hdev->hdcp_info.auth_status = SECOND_AUTHENTICATION_DONE;
+               hdmi_start_encryption(hdev);
+       } else {
+               switch (ret) {
+
+               case REPEATER_ILLEGAL_DEVICE_ERROR:
+                       hdmi_writeb(hdev, HDMI_HDCP_CTRL2, 0x1);
+                       mdelay(1);
+                       hdmi_writeb(hdev, HDMI_HDCP_CTRL2, 0x0);
+
+                       dev_dbg(dev, "%s: repeater : illegal device\n",
+                                       __func__);
+                       break;
+               case REPEATER_TIMEOUT_ERROR:
+                       hdmi_write_mask(hdev, HDMI_HDCP_CTRL1, ~0,
+                                       HDMI_HDCP_SET_REPEATER_TIMEOUT);
+                       hdmi_write_mask(hdev, HDMI_HDCP_CTRL1, 0,
+                                       HDMI_HDCP_SET_REPEATER_TIMEOUT);
+
+                       dev_dbg(dev, "%s: repeater : timeout\n", __func__);
+                       break;
+               case MAX_CASCADE_EXCEEDED_ERROR:
+
+                       dev_dbg(dev, "%s: repeater : exceeded MAX_CASCADE\n",
+                                       __func__);
+                       break;
+               case MAX_DEVS_EXCEEDED_ERROR:
+
+                       dev_dbg(dev, "%s: repeater : exceeded MAX_DEVS\n",
+                                       __func__);
+                       break;
+               default:
+                       break;
+               }
+
+               hdev->hdcp_info.auth_status = NOT_AUTHENTICATED;
+
+               goto second_auth_err;
+       }
+
+       dev_dbg(dev, "%s: second authentication is OK\n", __func__);
+       return 0;
+
+second_auth_err:
+       dev_dbg(dev, "%s: second authentication is failed\n", __func__);
+       return -1;
+}
+
+static int hdcp_write_aksv(struct hdmi_device *hdev)
+{
+       struct device *dev = hdev->dev;
+       dev_dbg(dev, "%s\n", __func__);
+
+       if (hdev->hdcp_info.auth_status != BKSV_READ_DONE) {
+               dev_err(dev, "%s: bksv is not ready\n", __func__);
+               goto aksv_write_err;
+       }
+       if (!is_hdmi_streaming(hdev))
+               goto aksv_write_err;
+
+       if (hdcp_write_key(hdev, AN_SIZE, HDMI_HDCP_AN_(0), HDCP_AN) < 0)
+               goto aksv_write_err;
+
+       hdev->hdcp_info.auth_status = AN_WRITE_DONE;
+
+       dev_dbg(dev, "%s: write An is done\n", __func__);
+
+       if (hdcp_write_key(hdev, AKSV_SIZE, HDMI_HDCP_AKSV_(0), HDCP_AKSV) < 0)
+               goto aksv_write_err;
+
+       msleep(100);
+
+       hdev->hdcp_info.auth_status = AKSV_WRITE_DONE;
+
+       dev_dbg(dev, "%s: write aksv is done\n", __func__);
+       dev_dbg(dev, "%s: aksv start is OK\n", __func__);
+       return 0;
+
+aksv_write_err:
+       dev_err(dev, "%s: aksv start is failed\n", __func__);
+       return -1;
+}
+
+static int hdcp_check_ri(struct hdmi_device *hdev)
+{
+       struct device *dev = hdev->dev;
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       if (hdev->hdcp_info.auth_status < AKSV_WRITE_DONE) {
+               dev_dbg(dev, "%s: ri check is not ready\n", __func__);
+               goto check_ri_err;
+       }
+
+       if (!is_hdmi_streaming(hdev))
+               goto check_ri_err;
+
+       if (hdcp_read_ri(hdev) < 0)
+               goto check_ri_err;
+
+       if (hdev->hdcp_info.is_repeater)
+               hdev->hdcp_info.auth_status
+                       = SECOND_AUTHENTICATION_RDY;
+       else {
+               hdev->hdcp_info.auth_status
+                       = FIRST_AUTHENTICATION_DONE;
+               hdmi_start_encryption(hdev);
+       }
+
+       dev_dbg(dev, "%s: ri check is OK\n", __func__);
+       return 0;
+
+check_ri_err:
+       dev_err(dev, "%s: ri check is failed\n", __func__);
+       return -1;
+}
+
+static void hdcp_work(struct work_struct *work)
+{
+       struct hdmi_device *hdev = container_of(work, struct hdmi_device, work);
+
+       if (!hdev->hdcp_info.hdcp_start)
+               return;
+
+       if (!is_hdmi_streaming(hdev))
+               return;
+
+       if (hdev->hdcp_info.event & HDCP_EVENT_READ_BKSV_START) {
+               if (hdcp_bksv(hdev) < 0)
+                       goto work_err;
+               else
+                       hdev->hdcp_info.event &= ~HDCP_EVENT_READ_BKSV_START;
+       }
+
+       if (hdev->hdcp_info.event & HDCP_EVENT_SECOND_AUTH_START) {
+               if (hdcp_second_auth(hdev) < 0)
+                       goto work_err;
+               else
+                       hdev->hdcp_info.event &= ~HDCP_EVENT_SECOND_AUTH_START;
+       }
+
+       if (hdev->hdcp_info.event & HDCP_EVENT_WRITE_AKSV_START) {
+               if (hdcp_write_aksv(hdev) < 0)
+                       goto work_err;
+               else
+                       hdev->hdcp_info.event  &= ~HDCP_EVENT_WRITE_AKSV_START;
+       }
+
+       if (hdev->hdcp_info.event & HDCP_EVENT_CHECK_RI_START) {
+               if (hdcp_check_ri(hdev) < 0)
+                       goto work_err;
+               else
+                       hdev->hdcp_info.event &= ~HDCP_EVENT_CHECK_RI_START;
+       }
+       return;
+work_err:
+       if (!hdev->hdcp_info.hdcp_start)
+               return;
+       if (!is_hdmi_streaming(hdev))
+               return;
+
+       hdcp_reset_auth(hdev);
+}
+
+/* HDCP APIs for hdmi driver */
+irqreturn_t hdcp_irq_handler(struct hdmi_device *hdev)
+{
+       struct device *dev = hdev->dev;
+       u32 event = 0;
+       u8 flag;
+       event = 0;
+
+       if (!hdev->streaming) {
+               hdev->hdcp_info.event           = HDCP_EVENT_STOP;
+               hdev->hdcp_info.auth_status     = NOT_AUTHENTICATED;
+               return IRQ_HANDLED;
+       }
+
+       flag = hdmi_readb(hdev, HDMI_STATUS);
+
+       if (flag & HDMI_WTFORACTIVERX_INT_OCC) {
+               event |= HDCP_EVENT_READ_BKSV_START;
+               hdmi_write_mask(hdev, HDMI_STATUS, ~0,
+                               HDMI_WTFORACTIVERX_INT_OCC);
+               hdmi_write(hdev, HDMI_HDCP_I2C_INT, 0x0);
+       }
+
+       if (flag & HDMI_WRITE_INT_OCC) {
+               event |= HDCP_EVENT_WRITE_AKSV_START;
+               hdmi_write_mask(hdev, HDMI_STATUS, ~0, HDMI_WRITE_INT_OCC);
+               hdmi_write(hdev, HDMI_HDCP_AN_INT, 0x0);
+       }
+
+       if (flag & HDMI_UPDATE_RI_INT_OCC) {
+               event |= HDCP_EVENT_CHECK_RI_START;
+               hdmi_write_mask(hdev, HDMI_STATUS, ~0, HDMI_UPDATE_RI_INT_OCC);
+               hdmi_write(hdev, HDMI_HDCP_RI_INT, 0x0);
+       }
+
+       if (flag & HDMI_WATCHDOG_INT_OCC) {
+               event |= HDCP_EVENT_SECOND_AUTH_START;
+               hdmi_write_mask(hdev, HDMI_STATUS, ~0, HDMI_WATCHDOG_INT_OCC);
+               hdmi_write(hdev, HDMI_HDCP_WDT_INT, 0x0);
+       }
+
+       if (!event) {
+               dev_dbg(dev, "%s: unknown irq\n", __func__);
+               return IRQ_HANDLED;
+       }
+
+       if (is_hdmi_streaming(hdev)) {
+               hdev->hdcp_info.event |= event;
+               queue_work(hdev->hdcp_wq, &hdev->work);
+       } else {
+               hdev->hdcp_info.event           = HDCP_EVENT_STOP;
+               hdev->hdcp_info.auth_status     = NOT_AUTHENTICATED;
+       }
+
+       return IRQ_HANDLED;
+}
+
+int hdcp_prepare(struct hdmi_device *hdev)
+{
+       hdev->hdcp_wq = create_workqueue("khdcpd");
+       if (hdev->hdcp_wq == NULL)
+               return -ENOMEM;
+
+       INIT_WORK(&hdev->work, hdcp_work);
+
+       spin_lock_init(&hdev->hdcp_info.reset_lock);
+
+#if defined(CONFIG_VIDEO_EXYNOS_HDCP)
+       hdev->hdcp_info.hdcp_enable = 1;
+#else
+       hdev->hdcp_info.hdcp_enable = 0;
+#endif
+       return 0;
+}
+
+int hdcp_start(struct hdmi_device *hdev)
+{
+       struct device *dev = hdev->dev;
+
+       hdev->hdcp_info.event = HDCP_EVENT_STOP;
+       hdev->hdcp_info.auth_status = NOT_AUTHENTICATED;
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       hdcp_sw_reset(hdev);
+
+       dev_dbg(dev, "%s: stop encryption\n", __func__);
+
+       hdcp_encryption(hdev, 0);
+
+       msleep(120);
+       if (hdcp_loadkey(hdev) < 0)
+               return -1;
+
+       hdmi_write(hdev, HDMI_GCP_CON, HDMI_GCP_CON_NO_TRAN);
+       hdmi_write(hdev, HDMI_STATUS_EN, HDMI_INT_EN_ALL);
+
+       hdmi_write(hdev, HDMI_HDCP_CTRL1, HDMI_HDCP_CP_DESIRED_EN);
+
+       hdmi_set_int_mask(hdev, HDMI_INTC_EN_HDCP, 1);
+
+       hdev->hdcp_info.hdcp_start = 1;
+
+       return 0;
+}
+
+int hdcp_stop(struct hdmi_device *hdev)
+{
+       struct device *dev = hdev->dev;
+       u8 val;
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       hdmi_set_int_mask(hdev, HDMI_INTC_EN_HDCP, 0);
+
+       hdev->hdcp_info.event           = HDCP_EVENT_STOP;
+       hdev->hdcp_info.auth_status     = NOT_AUTHENTICATED;
+       hdev->hdcp_info.hdcp_start      = false;
+
+       hdmi_writeb(hdev, HDMI_HDCP_CTRL1, 0x0);
+
+       hdmi_sw_hpd_enable(hdev, 0);
+
+       val = HDMI_UPDATE_RI_INT_EN | HDMI_WRITE_INT_EN |
+               HDMI_WATCHDOG_INT_EN | HDMI_WTFORACTIVERX_INT_EN;
+       hdmi_write_mask(hdev, HDMI_STATUS_EN, 0, val);
+       hdmi_write_mask(hdev, HDMI_STATUS_EN, ~0, val);
+
+       hdmi_write_mask(hdev, HDMI_STATUS, ~0, HDMI_INT_EN_ALL);
+
+       dev_dbg(dev, "%s: stop encryption\n", __func__);
+       hdcp_encryption(hdev, 0);
+
+       hdmi_writeb(hdev, HDMI_HDCP_CHECK_RESULT, HDMI_HDCP_CLR_ALL_RESULTS);
+
+       return 0;
+}
diff --git a/drivers/media/video/exynos/tv/hdmi.h b/drivers/media/video/exynos/tv/hdmi.h
new file mode 100644 (file)
index 0000000..55b08aa
--- /dev/null
@@ -0,0 +1,403 @@
+/*
+ * Samsung HDMI interface driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Jiun Yu, <jiun.yu@samsung.com>
+ *
+ * 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 Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#ifndef SAMSUMG_HDMI_H
+#define SAMSUNG_HDMI_H
+
+#ifdef CONFIG_VIDEO_EXYNOS_HDMI_DEBUG
+#define DEBUG
+#endif
+
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/regulator/consumer.h>
+
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-device.h>
+
+#define INFOFRAME_CNT          2
+
+#define HDMI_VSI_VERSION       0x01;
+#define HDMI_AVI_VERSION       0x02;
+#define HDMI_VSI_LENGTH                0x05;
+#define HDMI_AVI_LENGTH                0x0d;
+
+/* HDMI audio configuration value */
+#define DEFAULT_SAMPLE_RATE    44100
+#define DEFAULT_BITS_PER_SAMPLE        16
+
+/* HDMI pad definitions */
+#define HDMI_PAD_SINK          0
+#define HDMI_PADS_NUM          1
+
+/* HPD state definitions */
+#define HPD_LOW                0
+#define HPD_HIGH       1
+
+enum HDMI_VIDEO_FORMAT {
+       HDMI_VIDEO_FORMAT_2D = 0x0,
+       /** refer to Table 8-12 HDMI_Video_Format in HDMI specification v1.4a */
+       HDMI_VIDEO_FORMAT_3D = 0x2
+};
+
+enum HDMI_3D_FORMAT {
+       /** refer to Table 8-13 3D_Structure in HDMI specification v1.4a */
+
+       /** Frame Packing */
+       HDMI_3D_FORMAT_FP = 0x0,
+       /** Top-and-Bottom */
+       HDMI_3D_FORMAT_TB = 0x6,
+       /** Side-by-Side Half */
+       HDMI_3D_FORMAT_SB_HALF = 0x8
+};
+
+enum HDMI_3D_EXT_DATA {
+       /* refer to Table H-3 3D_Ext_Data - Additional video format
+        * information for Side-by-side(half) 3D structure */
+
+       /** Horizontal sub-sampleing */
+       HDMI_H_SUB_SAMPLE = 0x1
+};
+
+enum HDMI_OUTPUT_FMT {
+       HDMI_OUTPUT_RGB888 = 0x0,
+       HDMI_OUTPUT_YUV444 = 0x2
+};
+
+enum HDMI_PACKET_TYPE {
+       /** refer to Table 5-8 Packet Type in HDMI specification v1.4a */
+
+       /** InfoFrame packet type */
+       HDMI_PACKET_TYPE_INFOFRAME = 0X80,
+       /** Vendor-Specific InfoFrame */
+       HDMI_PACKET_TYPE_VSI = HDMI_PACKET_TYPE_INFOFRAME + 1,
+       /** Auxiliary Video information InfoFrame */
+       HDMI_PACKET_TYPE_AVI = HDMI_PACKET_TYPE_INFOFRAME + 2
+};
+
+enum HDMI_AUDIO_CODEC {
+       HDMI_AUDIO_PCM,
+       HDMI_AUDIO_AC3,
+       HDMI_AUDIO_MP3
+};
+
+enum HDCP_EVENT {
+       HDCP_EVENT_STOP                 = 1 << 0,
+       HDCP_EVENT_START                = 1 << 1,
+       HDCP_EVENT_READ_BKSV_START      = 1 << 2,
+       HDCP_EVENT_WRITE_AKSV_START     = 1 << 4,
+       HDCP_EVENT_CHECK_RI_START       = 1 << 8,
+       HDCP_EVENT_SECOND_AUTH_START    = 1 << 16
+};
+
+enum HDCP_STATE {
+       NOT_AUTHENTICATED,
+       RECEIVER_READ_READY,
+       BCAPS_READ_DONE,
+       BKSV_READ_DONE,
+       AN_WRITE_DONE,
+       AKSV_WRITE_DONE,
+       FIRST_AUTHENTICATION_DONE,
+       SECOND_AUTHENTICATION_RDY,
+       SECOND_AUTHENTICATION_DONE,
+};
+
+#define DEFAULT_AUDIO_CODEC    HDMI_AUDIO_PCM
+
+struct hdmi_resources {
+       struct clk *hdmi;
+       struct clk *sclk_hdmi;
+       struct clk *sclk_pixel;
+       struct clk *sclk_hdmiphy;
+       struct clk *hdmiphy;
+       struct regulator_bulk_data *regul_bulk;
+       int regul_count;
+};
+
+struct hdmi_tg_regs {
+       u8 cmd;
+       u8 h_fsz_l;
+       u8 h_fsz_h;
+       u8 hact_st_l;
+       u8 hact_st_h;
+       u8 hact_sz_l;
+       u8 hact_sz_h;
+       u8 v_fsz_l;
+       u8 v_fsz_h;
+       u8 vsync_l;
+       u8 vsync_h;
+       u8 vsync2_l;
+       u8 vsync2_h;
+       u8 vact_st_l;
+       u8 vact_st_h;
+       u8 vact_sz_l;
+       u8 vact_sz_h;
+       u8 field_chg_l;
+       u8 field_chg_h;
+       u8 vact_st2_l;
+       u8 vact_st2_h;
+#ifndef CONFIG_CPU_EXYNOS4210
+       u8 vact_st3_l;
+       u8 vact_st3_h;
+       u8 vact_st4_l;
+       u8 vact_st4_h;
+#endif
+       u8 vsync_top_hdmi_l;
+       u8 vsync_top_hdmi_h;
+       u8 vsync_bot_hdmi_l;
+       u8 vsync_bot_hdmi_h;
+       u8 field_top_hdmi_l;
+       u8 field_top_hdmi_h;
+       u8 field_bot_hdmi_l;
+       u8 field_bot_hdmi_h;
+#ifndef CONFIG_CPU_EXYNOS4210
+       u8 tg_3d;
+#endif
+};
+
+struct hdmi_core_regs {
+#ifndef CONFIG_CPU_EXYNOS4210
+       u8 h_blank[2];
+       u8 v2_blank[2];
+       u8 v1_blank[2];
+       u8 v_line[2];
+       u8 h_line[2];
+       u8 hsync_pol[1];
+       u8 vsync_pol[1];
+       u8 int_pro_mode[1];
+       u8 v_blank_f0[2];
+       u8 v_blank_f1[2];
+       u8 h_sync_start[2];
+       u8 h_sync_end[2];
+       u8 v_sync_line_bef_2[2];
+       u8 v_sync_line_bef_1[2];
+       u8 v_sync_line_aft_2[2];
+       u8 v_sync_line_aft_1[2];
+       u8 v_sync_line_aft_pxl_2[2];
+       u8 v_sync_line_aft_pxl_1[2];
+       u8 v_blank_f2[2]; /* for 3D mode */
+       u8 v_blank_f3[2]; /* for 3D mode */
+       u8 v_blank_f4[2]; /* for 3D mode */
+       u8 v_blank_f5[2]; /* for 3D mode */
+       u8 v_sync_line_aft_3[2];
+       u8 v_sync_line_aft_4[2];
+       u8 v_sync_line_aft_5[2];
+       u8 v_sync_line_aft_6[2];
+       u8 v_sync_line_aft_pxl_3[2];
+       u8 v_sync_line_aft_pxl_4[2];
+       u8 v_sync_line_aft_pxl_5[2];
+       u8 v_sync_line_aft_pxl_6[2];
+       u8 vact_space_1[2];
+       u8 vact_space_2[2];
+       u8 vact_space_3[2];
+       u8 vact_space_4[2];
+       u8 vact_space_5[2];
+       u8 vact_space_6[2];
+#else
+       u8 h_blank[2];
+       u8 v_blank[3];
+       u8 h_v_line[3];
+       u8 vsync_pol[1];
+       u8 int_pro_mode[1];
+       u8 v_blank_f[3];
+       u8 h_sync_gen[3];
+       u8 v_sync_gen1[3];
+       u8 v_sync_gen2[3];
+       u8 v_sync_gen3[3];
+#endif
+};
+
+struct hdmi_3d_info {
+       enum HDMI_VIDEO_FORMAT is_3d;
+       enum HDMI_3D_FORMAT fmt_3d;
+};
+
+struct hdmi_preset_conf {
+       struct hdmi_core_regs core;
+       struct hdmi_tg_regs tg;
+       struct v4l2_mbus_framefmt mbus_fmt;
+};
+
+struct hdmi_driver_data {
+       int hdmiphy_bus;
+};
+
+struct hdmi_infoframe {
+       enum HDMI_PACKET_TYPE type;
+       u8 ver;
+       u8 len;
+};
+
+struct hdcp_info {
+       u8 is_repeater;
+       u32 hdcp_start;
+       int hdcp_enable;
+       spinlock_t reset_lock;
+
+       enum HDCP_EVENT event;
+       enum HDCP_STATE auth_status;
+};
+
+struct hdmi_device {
+       /** base address of HDMI registers */
+       void __iomem *regs;
+
+       /** HDMI interrupt */
+       unsigned int int_irq;
+       unsigned int ext_irq;
+       unsigned int curr_irq;
+
+       /** pointer to device parent */
+       struct device *dev;
+       /** subdev generated by HDMI device */
+       struct v4l2_subdev sd;
+       /** sink pad connected to mixer */
+       struct media_pad pad;
+       /** V4L2 device structure */
+       struct v4l2_device v4l2_dev;
+       /** subdev of HDMIPHY interface */
+       struct v4l2_subdev *phy_sd;
+       /** configuration of current graphic mode */
+       const struct hdmi_preset_conf *cur_conf;
+       /** current preset */
+       u32 cur_preset;
+       /** other resources */
+       struct hdmi_resources res;
+       /** HDMI is streaming or not */
+       int streaming;
+       /** supported HDMI InfoFrame */
+       struct hdmi_infoframe infoframe[INFOFRAME_CNT];
+       /** audio on/off control flag */
+       int audio_enable;
+       /** audio sample rate */
+       int sample_rate;
+       /** audio bits per sample */
+       int bits_per_sample;
+       /** current audio codec type */
+       enum HDMI_AUDIO_CODEC audio_codec;
+       /** HDMI output format */
+       enum HDMI_OUTPUT_FMT output_fmt;
+
+       /** HDCP information */
+       struct hdcp_info hdcp_info;
+       struct work_struct work;
+       struct work_struct hpd_work;
+       struct workqueue_struct *hdcp_wq;
+       struct workqueue_struct *hpd_wq;
+
+       /* HPD releated */
+       bool hpd_user_checked;
+       atomic_t hpd_state;
+       spinlock_t hpd_lock;
+};
+
+struct hdmi_conf {
+       u32 preset;
+       const struct hdmi_preset_conf *conf;
+       const struct hdmi_3d_info *info;
+};
+extern const struct hdmi_conf hdmi_conf[];
+
+struct hdmiphy_conf {
+       u32 preset;
+       const u8 *data;
+};
+extern const struct hdmiphy_conf hdmiphy_conf[];
+extern const int hdmi_pre_cnt;
+extern const int hdmiphy_conf_cnt;
+
+const struct hdmi_3d_info *hdmi_preset2info(u32 preset);
+
+irqreturn_t hdmi_irq_handler(int irq, void *dev_data);
+int hdmi_conf_apply(struct hdmi_device *hdmi_dev);
+int is_hdmiphy_ready(struct hdmi_device *hdev);
+void hdmi_enable(struct hdmi_device *hdev, int on);
+void hdmi_hpd_enable(struct hdmi_device *hdev, int on);
+void hdmi_tg_enable(struct hdmi_device *hdev, int on);
+void hdmi_reg_stop_vsi(struct hdmi_device *hdev);
+void hdmi_reg_infoframe(struct hdmi_device *hdev,
+               struct hdmi_infoframe *infoframe);
+void hdmi_reg_set_acr(struct hdmi_device *hdev);
+void hdmi_reg_spdif_audio_init(struct hdmi_device *hdev);
+void hdmi_reg_i2s_audio_init(struct hdmi_device *hdev);
+void hdmi_audio_enable(struct hdmi_device *hdev, int on);
+void hdmi_bluescreen_enable(struct hdmi_device *hdev, int on);
+void hdmi_reg_mute(struct hdmi_device *hdev, int on);
+int hdmi_hpd_status(struct hdmi_device *hdev);
+int is_hdmi_streaming(struct hdmi_device *hdev);
+u8 hdmi_get_int_mask(struct hdmi_device *hdev);
+void hdmi_set_int_mask(struct hdmi_device *hdev, u8 mask, int en);
+void hdmi_sw_hpd_enable(struct hdmi_device *hdev, int en);
+void hdmi_sw_hpd_plug(struct hdmi_device *hdev, int en);
+void hdmi_phy_sw_reset(struct hdmi_device *hdev);
+void hdmi_dumpregs(struct hdmi_device *hdev, char *prefix);
+void hdmi_set_3d_info(struct hdmi_device *hdev);
+
+/** HDCP functions */
+irqreturn_t hdcp_irq_handler(struct hdmi_device *hdev);
+int hdcp_stop(struct hdmi_device *hdev);
+int hdcp_start(struct hdmi_device *hdev);
+int hdcp_prepare(struct hdmi_device *hdev);
+int hdcp_i2c_read(struct hdmi_device *hdev, u8 offset, int bytes, u8 *buf);
+int hdcp_i2c_write(struct hdmi_device *hdev, u8 offset, int bytes, u8 *buf);
+
+static inline
+void hdmi_write(struct hdmi_device *hdev, u32 reg_id, u32 value)
+{
+       writel(value, hdev->regs + reg_id);
+}
+
+static inline
+void hdmi_write_mask(struct hdmi_device *hdev, u32 reg_id, u32 value, u32 mask)
+{
+       u32 old = readl(hdev->regs + reg_id);
+       value = (value & mask) | (old & ~mask);
+       writel(value, hdev->regs + reg_id);
+}
+
+static inline
+void hdmi_writeb(struct hdmi_device *hdev, u32 reg_id, u8 value)
+{
+       writeb(value, hdev->regs + reg_id);
+}
+
+static inline void hdmi_write_bytes(struct hdmi_device *hdev, u32 reg_id,
+               u8 *buf, int bytes)
+{
+       int i;
+
+       for (i = 0; i < bytes; ++i)
+               writeb(buf[i], hdev->regs + reg_id + i * 4);
+}
+
+static inline u32 hdmi_read(struct hdmi_device *hdev, u32 reg_id)
+{
+       return readl(hdev->regs + reg_id);
+}
+
+static inline u8 hdmi_readb(struct hdmi_device *hdev, u32 reg_id)
+{
+       return readb(hdev->regs + reg_id);
+}
+
+static inline void hdmi_read_bytes(struct hdmi_device *hdev, u32 reg_id,
+               u8 *buf, int bytes)
+{
+       int i;
+
+       for (i = 0; i < bytes; ++i)
+               buf[i] = readb(hdev->regs + reg_id + i * 4);
+}
+
+#endif /* SAMSUNG_HDMI_H */
diff --git a/drivers/media/video/exynos/tv/hdmi_cec.c b/drivers/media/video/exynos/tv/hdmi_cec.c
new file mode 100644 (file)
index 0000000..d561c84
--- /dev/null
@@ -0,0 +1,436 @@
+/* linux/drivers/media/video/samsung/tvout/s5p_cec_ctrl.c
+ *
+ * Copyright (c) 2009 Samsung Electronics
+ *             http://www.samsung.com/
+ *
+ * cec interface file for Samsung TVOut driver
+ *
+ * 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/slab.h>
+#include <linux/uaccess.h>
+#include <linux/poll.h>
+#include <linux/miscdevice.h>
+#include <linux/clk.h>
+#include <linux/sched.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/export.h>
+#include <linux/module.h>
+#include <plat/devs.h>
+#include <plat/tv-core.h>
+
+#include "cec.h"
+
+MODULE_AUTHOR("SangPil Moon");
+MODULE_DESCRIPTION("S5P CEC driver");
+MODULE_LICENSE("GPL");
+
+#define CEC_IOC_MAGIC        'c'
+#define CEC_IOC_SETLADDR     _IOW(CEC_IOC_MAGIC, 0, unsigned int)
+
+#define VERSION   "1.0" /* Driver version number */
+#define CEC_MINOR 243  /* Major 10, Minor 242, /dev/cec */
+
+
+#define CEC_STATUS_TX_RUNNING       (1<<0)
+#define CEC_STATUS_TX_TRANSFERRING  (1<<1)
+#define CEC_STATUS_TX_DONE          (1<<2)
+#define CEC_STATUS_TX_ERROR         (1<<3)
+#define CEC_STATUS_TX_BYTES         (0xFF<<8)
+#define CEC_STATUS_RX_RUNNING       (1<<16)
+#define CEC_STATUS_RX_RECEIVING     (1<<17)
+#define CEC_STATUS_RX_DONE          (1<<18)
+#define CEC_STATUS_RX_ERROR         (1<<19)
+#define CEC_STATUS_RX_BCAST         (1<<20)
+#define CEC_STATUS_RX_BYTES         (0xFF<<24)
+
+
+/* CEC Rx buffer size */
+#define CEC_RX_BUFF_SIZE            16
+/* CEC Tx buffer size */
+#define CEC_TX_BUFF_SIZE            16
+
+#define TV_CLK_GET_WITH_ERR_CHECK(clk, pdev, clk_name)                 \
+               do {                                                    \
+                       clk = clk_get(&pdev->dev, clk_name);            \
+                       if (IS_ERR(clk)) {                              \
+                               printk(KERN_ERR                         \
+                               "failed to find clock %s\n", clk_name); \
+                               return -ENOENT;                         \
+                       }                                               \
+               } while (0);
+
+static atomic_t hdmi_on = ATOMIC_INIT(0);
+static DEFINE_MUTEX(cec_lock);
+struct clk *hdmi_cec_clk;
+
+static int s5p_cec_open(struct inode *inode, struct file *file)
+{
+       int ret = 0;
+
+       mutex_lock(&cec_lock);
+       clk_enable(hdmi_cec_clk);
+
+       if (atomic_read(&hdmi_on)) {
+               tvout_dbg("do not allow multiple open for tvout cec\n");
+               ret = -EBUSY;
+               goto err_multi_open;
+       } else
+               atomic_inc(&hdmi_on);
+
+       s5p_cec_reset();
+
+       s5p_cec_set_divider();
+
+       s5p_cec_threshold();
+
+       s5p_cec_unmask_tx_interrupts();
+
+       s5p_cec_set_rx_state(STATE_RX);
+       s5p_cec_unmask_rx_interrupts();
+       s5p_cec_enable_rx();
+
+err_multi_open:
+       mutex_unlock(&cec_lock);
+
+       return ret;
+}
+
+static int s5p_cec_release(struct inode *inode, struct file *file)
+{
+       atomic_dec(&hdmi_on);
+
+       s5p_cec_mask_tx_interrupts();
+       s5p_cec_mask_rx_interrupts();
+
+       clk_disable(hdmi_cec_clk);
+       clk_put(hdmi_cec_clk);
+
+       return 0;
+}
+
+static ssize_t s5p_cec_read(struct file *file, char __user *buffer,
+                       size_t count, loff_t *ppos)
+{
+       ssize_t retval;
+       unsigned long spin_flags;
+
+       if (wait_event_interruptible(cec_rx_struct.waitq,
+                       atomic_read(&cec_rx_struct.state) == STATE_DONE)) {
+               return -ERESTARTSYS;
+       }
+       spin_lock_irqsave(&cec_rx_struct.lock, spin_flags);
+
+       if (cec_rx_struct.size > count) {
+               spin_unlock_irqrestore(&cec_rx_struct.lock, spin_flags);
+
+               return -1;
+       }
+
+       if (copy_to_user(buffer, cec_rx_struct.buffer, cec_rx_struct.size)) {
+               spin_unlock_irqrestore(&cec_rx_struct.lock, spin_flags);
+               printk(KERN_ERR " copy_to_user() failed!\n");
+
+               return -EFAULT;
+       }
+
+       retval = cec_rx_struct.size;
+
+       s5p_cec_set_rx_state(STATE_RX);
+       spin_unlock_irqrestore(&cec_rx_struct.lock, spin_flags);
+
+       return retval;
+}
+
+static ssize_t s5p_cec_write(struct file *file, const char __user *buffer,
+                       size_t count, loff_t *ppos)
+{
+       char *data;
+
+       /* check data size */
+
+       if (count > CEC_TX_BUFF_SIZE || count == 0)
+               return -1;
+
+       data = kmalloc(count, GFP_KERNEL);
+
+       if (!data) {
+               printk(KERN_ERR " kmalloc() failed!\n");
+
+               return -1;
+       }
+
+       if (copy_from_user(data, buffer, count)) {
+               printk(KERN_ERR " copy_from_user() failed!\n");
+               kfree(data);
+
+               return -EFAULT;
+       }
+
+       s5p_cec_copy_packet(data, count);
+
+       kfree(data);
+
+       /* wait for interrupt */
+       if (wait_event_interruptible(cec_tx_struct.waitq,
+               atomic_read(&cec_tx_struct.state)
+               != STATE_TX)) {
+
+               return -ERESTARTSYS;
+       }
+
+       if (atomic_read(&cec_tx_struct.state) == STATE_ERROR)
+               return -1;
+
+       return count;
+}
+
+#if 0
+static int s5p_cec_ioctl(struct inode *inode, struct file *file, u32 cmd,
+                       unsigned long arg)
+#else
+static long s5p_cec_ioctl(struct file *file, unsigned int cmd,
+                                               unsigned long arg)
+#endif
+{
+       u32 laddr;
+
+       switch (cmd) {
+       case CEC_IOC_SETLADDR:
+               if (get_user(laddr, (u32 __user *) arg))
+                       return -EFAULT;
+
+               tvout_dbg("logical address = 0x%02x\n", laddr);
+
+               s5p_cec_set_addr(laddr);
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static u32 s5p_cec_poll(struct file *file, poll_table *wait)
+{
+       poll_wait(file, &cec_rx_struct.waitq, wait);
+
+       if (atomic_read(&cec_rx_struct.state) == STATE_DONE)
+               return POLLIN | POLLRDNORM;
+
+       return 0;
+}
+
+static const struct file_operations cec_fops = {
+       .owner   = THIS_MODULE,
+       .open    = s5p_cec_open,
+       .release = s5p_cec_release,
+       .read    = s5p_cec_read,
+       .write   = s5p_cec_write,
+#if 1
+       .unlocked_ioctl = s5p_cec_ioctl,
+#else
+       .ioctl   = s5p_cec_ioctl,
+#endif
+       .poll    = s5p_cec_poll,
+};
+
+static struct miscdevice cec_misc_device = {
+       .minor = CEC_MINOR,
+       .name  = "CEC",
+       .fops  = &cec_fops,
+};
+
+static irqreturn_t s5p_cec_irq_handler(int irq, void *dev_id)
+{
+
+       u32 status = 0;
+
+       status = s5p_cec_get_status();
+
+       if (status & CEC_STATUS_TX_DONE) {
+               if (status & CEC_STATUS_TX_ERROR) {
+                       tvout_dbg(" CEC_STATUS_TX_ERROR!\n");
+                       s5p_cec_set_tx_state(STATE_ERROR);
+               } else {
+                       tvout_dbg(" CEC_STATUS_TX_DONE!\n");
+                       s5p_cec_set_tx_state(STATE_DONE);
+               }
+
+               s5p_clr_pending_tx();
+
+               wake_up_interruptible(&cec_tx_struct.waitq);
+       }
+
+       if (status & CEC_STATUS_RX_DONE) {
+               if (status & CEC_STATUS_RX_ERROR) {
+                       tvout_dbg(" CEC_STATUS_RX_ERROR!\n");
+                       s5p_cec_rx_reset();
+
+               } else {
+                       u32 size;
+
+                       tvout_dbg(" CEC_STATUS_RX_DONE!\n");
+
+                       /* copy data from internal buffer */
+                       size = status >> 24;
+
+                       spin_lock(&cec_rx_struct.lock);
+
+                       s5p_cec_get_rx_buf(size, cec_rx_struct.buffer);
+
+                       cec_rx_struct.size = size;
+
+                       s5p_cec_set_rx_state(STATE_DONE);
+
+                       spin_unlock(&cec_rx_struct.lock);
+
+                       s5p_cec_enable_rx();
+               }
+
+               /* clear interrupt pending bit */
+               s5p_clr_pending_rx();
+
+               wake_up_interruptible(&cec_rx_struct.waitq);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static int __devinit s5p_cec_probe(struct platform_device *pdev)
+{
+       struct s5p_platform_cec *pdata;
+       u8 *buffer;
+       int ret;
+       struct resource *res;
+
+       pdata = to_tvout_plat(&pdev->dev);
+
+       if (pdata->cfg_gpio)
+               pdata->cfg_gpio(pdev);
+
+
+       s5p_cec_mem_probe(pdev);
+
+       if (misc_register(&cec_misc_device)) {
+               printk(KERN_WARNING " Couldn't register device 10, %d.\n",
+                       CEC_MINOR);
+
+               return -EBUSY;
+       }
+
+#if 0
+       irq_num = platform_get_irq(pdev, 0);
+
+       if (irq_num < 0) {
+               printk(KERN_ERR  "failed to get %s irq resource\n", "cec");
+               ret = -ENOENT;
+
+               return ret;
+       }
+#endif
+
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (res == NULL) {
+               dev_err(&pdev->dev, "failed to get irq resource.\n");
+               ret = -ENOENT;
+               return ret;
+       }
+
+       ret = request_irq(res->start, s5p_cec_irq_handler, IRQF_DISABLED,
+               pdev->name, &pdev->id);
+
+       if (ret != 0) {
+               printk(KERN_ERR  "failed to install %s irq (%d)\n", "cec", ret);
+
+               return ret;
+       }
+
+       init_waitqueue_head(&cec_rx_struct.waitq);
+       spin_lock_init(&cec_rx_struct.lock);
+       init_waitqueue_head(&cec_tx_struct.waitq);
+
+       buffer = kmalloc(CEC_TX_BUFF_SIZE, GFP_KERNEL);
+
+       if (!buffer) {
+               printk(KERN_ERR " kmalloc() failed!\n");
+               misc_deregister(&cec_misc_device);
+
+               return -EIO;
+       }
+
+       cec_rx_struct.buffer = buffer;
+
+       cec_rx_struct.size   = 0;
+       TV_CLK_GET_WITH_ERR_CHECK(hdmi_cec_clk, pdev, "sclk_cec");
+
+       dev_info(&pdev->dev, "probe successful\n");
+
+       return 0;
+}
+
+static int __devexit s5p_cec_remove(struct platform_device *pdev)
+{
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int s5p_cec_suspend(struct platform_device *dev, pm_message_t state)
+{
+       return 0;
+}
+
+static int s5p_cec_resume(struct platform_device *dev)
+{
+       return 0;
+}
+#else
+#define s5p_cec_suspend NULL
+#define s5p_cec_resume NULL
+#endif
+
+static struct platform_driver s5p_cec_driver = {
+       .probe          = s5p_cec_probe,
+       .remove         = __devexit_p(s5p_cec_remove),
+       .suspend        = s5p_cec_suspend,
+       .resume         = s5p_cec_resume,
+       .driver         = {
+               .name   = "s5p-tvout-cec",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static char banner[] __initdata =
+       "S5P CEC for Exynos4 Driver, (c) 2009 Samsung Electronics\n";
+
+static int __init s5p_cec_init(void)
+{
+       int ret;
+
+       printk(banner);
+
+       ret = platform_driver_register(&s5p_cec_driver);
+
+       if (ret) {
+               printk(KERN_ERR "Platform Device Register Failed %d\n", ret);
+
+               return -1;
+       }
+
+       return 0;
+}
+
+static void __exit s5p_cec_exit(void)
+{
+       kfree(cec_rx_struct.buffer);
+
+       platform_driver_unregister(&s5p_cec_driver);
+}
+
+module_init(s5p_cec_init);
+module_exit(s5p_cec_exit);
diff --git a/drivers/media/video/exynos/tv/hdmi_cec_ctrl.c b/drivers/media/video/exynos/tv/hdmi_cec_ctrl.c
new file mode 100644 (file)
index 0000000..228f260
--- /dev/null
@@ -0,0 +1,264 @@
+/* linux/drivers/media/video/samsung/tvout/hw_if/cec.c
+ *
+ * Copyright (c) 2009 Samsung Electronics
+ *             http://www.samsung.com/
+ *
+ * cec ftn file for Samsung TVOUT driver
+ *
+ * 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/io.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_media.h>
+#include <linux/irqreturn.h>
+#include <linux/stddef.h>
+
+#include <mach/regs-clock.h>
+#include <mach/regs-clock.h>
+#include <mach/regs-cec.h>
+
+#include "cec.h"
+
+#undef tvout_dbg
+
+#ifdef CONFIG_CEC_DEBUG
+#define tvout_dbg(fmt, ...)                                    \
+               printk(KERN_INFO "\t\t[CEC] %s(): " fmt,        \
+                       __func__, ##__VA_ARGS__)
+#else
+#define tvout_dbg(fmt, ...)
+#endif
+
+#define S5P_HDMI_FIN                   24000000
+#define CEC_DIV_RATIO                  320000
+
+#define CEC_MESSAGE_BROADCAST_MASK     0x0F
+#define CEC_MESSAGE_BROADCAST          0x0F
+#define CEC_FILTER_THRESHOLD           0x15
+
+static struct resource *cec_mem;
+void __iomem           *cec_base;
+
+struct cec_rx_struct cec_rx_struct;
+struct cec_tx_struct cec_tx_struct;
+
+void s5p_cec_set_divider(void)
+{
+       u32 div_ratio, reg, div_val;
+
+       div_ratio  = S5P_HDMI_FIN / CEC_DIV_RATIO - 1;
+
+       reg = readl(EXYNOS_HDMI_PHY_CONTROL);
+       reg = (reg & ~(0x3FF << 16)) | (div_ratio << 16);
+
+       writel(reg, EXYNOS_HDMI_PHY_CONTROL);
+
+       div_val = CEC_DIV_RATIO * 0.00005 - 1;
+
+       writeb(0x0, cec_base + S5P_CES_DIVISOR_3);
+       writeb(0x0, cec_base + S5P_CES_DIVISOR_2);
+       writeb(0x0, cec_base + S5P_CES_DIVISOR_1);
+       writeb(div_val, cec_base + S5P_CES_DIVISOR_0);
+}
+
+void s5p_cec_enable_rx(void)
+{
+       u8 reg;
+
+       reg = readb(cec_base + S5P_CES_RX_CTRL);
+       reg |= S5P_CES_RX_CTRL_ENABLE;
+       writeb(reg, cec_base + S5P_CES_RX_CTRL);
+}
+
+void s5p_cec_mask_rx_interrupts(void)
+{
+       u8 reg;
+
+       reg = readb(cec_base + S5P_CES_IRQ_MASK);
+       reg |= S5P_CES_IRQ_RX_DONE;
+       reg |= S5P_CES_IRQ_RX_ERROR;
+       writeb(reg, cec_base + S5P_CES_IRQ_MASK);
+}
+
+void s5p_cec_unmask_rx_interrupts(void)
+{
+       u8 reg;
+
+       reg = readb(cec_base + S5P_CES_IRQ_MASK);
+       reg &= ~S5P_CES_IRQ_RX_DONE;
+       reg &= ~S5P_CES_IRQ_RX_ERROR;
+       writeb(reg, cec_base + S5P_CES_IRQ_MASK);
+}
+
+void s5p_cec_mask_tx_interrupts(void)
+{
+       u8 reg;
+       reg = readb(cec_base + S5P_CES_IRQ_MASK);
+       reg |= S5P_CES_IRQ_TX_DONE;
+       reg |= S5P_CES_IRQ_TX_ERROR;
+       writeb(reg, cec_base + S5P_CES_IRQ_MASK);
+
+}
+
+void s5p_cec_unmask_tx_interrupts(void)
+{
+       u8 reg;
+
+       reg = readb(cec_base + S5P_CES_IRQ_MASK);
+       reg &= ~S5P_CES_IRQ_TX_DONE;
+       reg &= ~S5P_CES_IRQ_TX_ERROR;
+       writeb(reg, cec_base + S5P_CES_IRQ_MASK);
+}
+
+void s5p_cec_reset(void)
+{
+       writeb(S5P_CES_RX_CTRL_RESET, cec_base + S5P_CES_RX_CTRL);
+       writeb(S5P_CES_TX_CTRL_RESET, cec_base + S5P_CES_TX_CTRL);
+}
+
+void s5p_cec_tx_reset(void)
+{
+       writeb(S5P_CES_TX_CTRL_RESET, cec_base + S5P_CES_TX_CTRL);
+}
+
+void s5p_cec_rx_reset(void)
+{
+       writeb(S5P_CES_RX_CTRL_RESET, cec_base + S5P_CES_RX_CTRL);
+}
+
+void s5p_cec_threshold(void)
+{
+       writeb(CEC_FILTER_THRESHOLD, cec_base + S5P_CES_RX_FILTER_TH);
+       writeb(0, cec_base + S5P_CES_RX_FILTER_CTRL);
+}
+
+void s5p_cec_set_tx_state(enum cec_state state)
+{
+       atomic_set(&cec_tx_struct.state, state);
+}
+
+void s5p_cec_set_rx_state(enum cec_state state)
+{
+       atomic_set(&cec_rx_struct.state, state);
+}
+
+void s5p_cec_copy_packet(char *data, size_t count)
+{
+       int i = 0;
+       u8 reg;
+
+       while (i < count) {
+               writeb(data[i], cec_base + (S5P_CES_TX_BUFF0 + (i * 4)));
+               i++;
+       }
+
+       writeb(count, cec_base + S5P_CES_TX_BYTES);
+       s5p_cec_set_tx_state(STATE_TX);
+       reg = readb(cec_base + S5P_CES_TX_CTRL);
+       reg |= S5P_CES_TX_CTRL_START;
+
+       if ((data[0] & CEC_MESSAGE_BROADCAST_MASK) == CEC_MESSAGE_BROADCAST)
+               reg |= S5P_CES_TX_CTRL_BCAST;
+       else
+               reg &= ~S5P_CES_TX_CTRL_BCAST;
+
+       reg |= 0x50;
+       writeb(reg, cec_base + S5P_CES_TX_CTRL);
+}
+
+void s5p_cec_set_addr(u32 addr)
+{
+       writeb(addr & 0x0F, cec_base + S5P_CES_LOGIC_ADDR);
+}
+
+u32 s5p_cec_get_status(void)
+{
+       u32 status = 0;
+
+       status = readb(cec_base + S5P_CES_STATUS_0);
+       status |= readb(cec_base + S5P_CES_STATUS_1) << 8;
+       status |= readb(cec_base + S5P_CES_STATUS_2) << 16;
+       status |= readb(cec_base + S5P_CES_STATUS_3) << 24;
+
+       tvout_dbg("status = 0x%x!\n", status);
+
+       return status;
+}
+
+void s5p_clr_pending_tx(void)
+{
+       writeb(S5P_CES_IRQ_TX_DONE | S5P_CES_IRQ_TX_ERROR,
+                                       cec_base + S5P_CES_IRQ_CLEAR);
+}
+
+void s5p_clr_pending_rx(void)
+{
+       writeb(S5P_CES_IRQ_RX_DONE | S5P_CES_IRQ_RX_ERROR,
+                                       cec_base + S5P_CES_IRQ_CLEAR);
+}
+
+void s5p_cec_get_rx_buf(u32 size, u8 *buffer)
+{
+       u32 i = 0;
+
+       while (i < size) {
+               buffer[i] = readb(cec_base + S5P_CES_RX_BUFF0 + (i * 4));
+               i++;
+       }
+}
+
+void s5p_cec_mem_probe(struct platform_device *pdev)
+{
+       struct resource *res;
+       size_t  size;
+       int     ret;
+
+       dev_dbg(&pdev->dev, "%s\n", __func__);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+       if (res == NULL) {
+               dev_err(&pdev->dev,
+                       "failed to get memory region resource for cec\n");
+               ret = -ENOENT;
+       }
+
+       size = (res->end - res->start) + 1;
+       cec_mem = request_mem_region(res->start, size, pdev->name);
+
+       if (cec_mem == NULL) {
+               dev_err(&pdev->dev,
+                       "failed to get memory region for cec\n");
+               ret = -ENOENT;
+       }
+
+       cec_base = ioremap(res->start, size);
+
+       if (cec_base == NULL) {
+               dev_err(&pdev->dev,
+                       "failed to ioremap address region for cec\n");
+               ret = -ENOENT;
+       }
+}
+
+int __init s5p_cec_mem_release(struct platform_device *pdev)
+{
+       iounmap(cec_base);
+
+       if (cec_mem != NULL) {
+               if (release_resource(cec_mem))
+                       dev_err(&pdev->dev,
+                               "Can't remove tvout drv !!\n");
+
+               kfree(cec_mem);
+
+               cec_mem = NULL;
+       }
+
+       return 0;
+}
diff --git a/drivers/media/video/exynos/tv/hdmi_drv.c b/drivers/media/video/exynos/tv/hdmi_drv.c
new file mode 100644 (file)
index 0000000..4932d6f
--- /dev/null
@@ -0,0 +1,912 @@
+/*
+ * Samsung HDMI interface driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.com>
+ *
+ * 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 Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+#include "hdmi.h"
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <media/v4l2-subdev.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/bug.h>
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/sched.h>
+#include <linux/of_i2c.h>
+#include <plat/devs.h>
+#include <plat/tv-core.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <media/exynos_mc.h>
+
+MODULE_AUTHOR("Tomasz Stanislawski, <t.stanislaws@samsung.com>");
+MODULE_DESCRIPTION("Samsung HDMI");
+MODULE_LICENSE("GPL");
+
+/* default preset configured on probe */
+#define HDMI_DEFAULT_PRESET V4L2_DV_1080P60
+
+/* I2C module and id for HDMIPHY */
+static struct i2c_board_info hdmiphy_info = {
+       I2C_BOARD_INFO("hdmiphy", 0x38),
+};
+
+static struct hdmi_driver_data hdmi_driver_data[] = {
+       { .hdmiphy_bus = 3 },
+       { .hdmiphy_bus = 8 },
+       { .hdmiphy_bus = 5 },
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id exynos_hdmi_match[] = {
+       {
+               .compatible = "samsung,exynos5-hdmi",
+               .data = (unsigned long)&hdmi_driver_data[2],
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, exynos_hdmi_match);
+#endif
+
+static inline struct hdmi_driver_data *get_drvdata(struct platform_device *pdev)
+{
+       if (pdev->dev.of_node) {
+               const struct of_device_id *match;
+               match = of_match_node(of_match_ptr(exynos_hdmi_match), pdev->dev.of_node);
+               return (struct hdmi_driver_data *) match->data;
+       }
+       return (struct hdmi_driver_data *)platform_get_device_id(pdev)->driver_data;
+}
+
+static struct platform_device_id hdmi_driver_types[] = {
+       {
+               .name           = "s5pv210-hdmi",
+               .driver_data    = (unsigned long)&hdmi_driver_data[0],
+       }, {
+               .name           = "exynos4-hdmi",
+               .driver_data    = (unsigned long)&hdmi_driver_data[1],
+       }, {
+               .name           = "exynos5-hdmi",
+               .driver_data    = (unsigned long)&hdmi_driver_data[2],
+       }, {
+               /* end node */
+       }
+};
+
+static const struct v4l2_subdev_ops hdmi_sd_ops;
+
+static struct hdmi_device *sd_to_hdmi_dev(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct hdmi_device, sd);
+}
+
+static int set_external_hpd_int(struct hdmi_device *hdev)
+{
+       int ret = 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&hdev->hpd_lock, flags);
+
+       s5p_v4l2_int_src_ext_hpd();
+       /* irq change by TV power status */
+       if (hdev->curr_irq != hdev->ext_irq) {
+               disable_irq(hdev->curr_irq);
+               free_irq(hdev->curr_irq, hdev);
+       } else {
+               spin_unlock_irqrestore(&hdev->hpd_lock, flags);
+               return ret;
+       }
+
+       hdev->curr_irq = hdev->ext_irq;
+       ret = request_irq(hdev->curr_irq, hdmi_irq_handler,
+                       IRQ_TYPE_EDGE_BOTH, "hdmi", hdev);
+
+       if (ret)
+               dev_err(hdev->dev, "request change failed.\n");
+
+       dev_info(hdev->dev, "HDMI interrupt source is changed : external\n");
+
+       spin_unlock_irqrestore(&hdev->hpd_lock, flags);
+       return ret;
+}
+
+static int set_internal_hpd_int(struct hdmi_device *hdev)
+{
+       int ret = 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&hdev->hpd_lock, flags);
+
+       s5p_v4l2_int_src_hdmi_hpd();
+       /* irq change by TV power status */
+       if (hdev->curr_irq != hdev->int_irq) {
+               disable_irq(hdev->curr_irq);
+               free_irq(hdev->curr_irq, hdev);
+       } else {
+               spin_unlock_irqrestore(&hdev->hpd_lock, flags);
+               return ret;
+       }
+
+       hdev->curr_irq = hdev->int_irq;
+       ret = request_irq(hdev->curr_irq, hdmi_irq_handler,
+                       0, "hdmi", hdev);
+       if (ret)
+               dev_err(hdev->dev, "request change failed.\n");
+
+       dev_info(hdev->dev, "HDMI interrupt source is changed : internal\n");
+       spin_unlock_irqrestore(&hdev->hpd_lock, flags);
+
+       return ret;
+}
+
+static const struct hdmi_preset_conf *hdmi_preset2conf(u32 preset)
+{
+       int i;
+
+       for (i = 0; i < hdmi_pre_cnt; ++i)
+               if (hdmi_conf[i].preset == preset)
+                       return  hdmi_conf[i].conf;
+       return NULL;
+}
+
+const struct hdmi_3d_info *hdmi_preset2info(u32 preset)
+{
+       int i;
+
+       for (i = 0; i < hdmi_pre_cnt; ++i)
+               if (hdmi_conf[i].preset == preset)
+                       return  hdmi_conf[i].info;
+       return NULL;
+}
+
+static int hdmi_set_infoframe(struct hdmi_device *hdev)
+{
+       struct hdmi_infoframe infoframe;
+       const struct hdmi_3d_info *info;
+
+       info = hdmi_preset2info(hdev->cur_preset);
+
+       if (info->is_3d == HDMI_VIDEO_FORMAT_3D) {
+               infoframe.type = HDMI_PACKET_TYPE_VSI;
+               infoframe.ver = HDMI_VSI_VERSION;
+               infoframe.len = HDMI_VSI_LENGTH;
+               hdmi_reg_infoframe(hdev, &infoframe);
+       } else
+               hdmi_reg_stop_vsi(hdev);
+
+       infoframe.type = HDMI_PACKET_TYPE_AVI;
+       infoframe.ver = HDMI_AVI_VERSION;
+       infoframe.len = HDMI_AVI_LENGTH;
+       hdmi_reg_infoframe(hdev, &infoframe);
+
+       return 0;
+}
+
+static int hdmi_set_packets(struct hdmi_device *hdev)
+{
+       hdmi_reg_set_acr(hdev);
+       return 0;
+}
+
+static int hdmi_streamon(struct hdmi_device *hdev)
+{
+       struct device *dev = hdev->dev;
+       struct hdmi_resources *res = &hdev->res;
+       int ret, tries;
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       hdev->streaming = 1;
+       ret = v4l2_subdev_call(hdev->phy_sd, video, s_stream, 1);
+       if (ret)
+               return ret;
+
+       /* waiting for HDMIPHY's PLL to get to steady state */
+       for (tries = 100; tries; --tries) {
+               if (is_hdmiphy_ready(hdev))
+                       break;
+
+               mdelay(1);
+       }
+       /* steady state not achieved */
+       if (tries == 0) {
+               dev_err(dev, "hdmiphy's pll could not reach steady state.\n");
+               v4l2_subdev_call(hdev->phy_sd, video, s_stream, 0);
+               hdmi_dumpregs(hdev, "s_stream");
+               return -EIO;
+       }
+
+       /* hdmiphy clock is used for HDMI in streaming mode */
+       clk_disable(res->sclk_hdmi);
+       clk_set_parent(res->sclk_hdmi, res->sclk_hdmiphy);
+       clk_enable(res->sclk_hdmi);
+
+       /* 3D test */
+       hdmi_set_infoframe(hdev);
+
+       /* set packets for audio */
+       hdmi_set_packets(hdev);
+
+       /* init audio */
+#if defined(CONFIG_VIDEO_EXYNOS_HDMI_AUDIO_I2S)
+       hdmi_reg_i2s_audio_init(hdev);
+#elif defined(CONFIG_VIDEO_EXYNOS_HDMI_AUDIO_SPDIF)
+       hdmi_reg_spdif_audio_init(hdev);
+#endif
+       /* enbale HDMI audio */
+       if (hdev->audio_enable)
+               hdmi_audio_enable(hdev, 1);
+
+       /* enable HDMI and timing generator */
+       hdmi_enable(hdev, 1);
+       hdmi_tg_enable(hdev, 1);
+
+       /* start HDCP if enabled */
+       if (hdev->hdcp_info.hdcp_enable) {
+               ret = hdcp_start(hdev);
+               if (ret)
+                       return ret;
+       }
+
+       hdmi_dumpregs(hdev, "streamon");
+       return 0;
+}
+
+static int hdmi_streamoff(struct hdmi_device *hdev)
+{
+       struct device *dev = hdev->dev;
+       struct hdmi_resources *res = &hdev->res;
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       if (hdev->hdcp_info.hdcp_enable)
+               hdcp_stop(hdev);
+
+       hdmi_audio_enable(hdev, 0);
+       hdmi_enable(hdev, 0);
+       hdmi_tg_enable(hdev, 0);
+
+       /* pixel(vpll) clock is used for HDMI in config mode */
+       clk_disable(res->sclk_hdmi);
+       clk_set_parent(res->sclk_hdmi, res->sclk_pixel);
+       clk_enable(res->sclk_hdmi);
+
+       v4l2_subdev_call(hdev->phy_sd, video, s_stream, 0);
+
+       hdev->streaming = 0;
+       hdmi_dumpregs(hdev, "streamoff");
+       return 0;
+}
+
+static int hdmi_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+       struct device *dev = hdev->dev;
+
+       dev_dbg(dev, "%s(%d)\n", __func__, enable);
+       if (enable)
+               return hdmi_streamon(hdev);
+       return hdmi_streamoff(hdev);
+}
+
+static void hdmi_resource_poweron(struct hdmi_resources *res)
+{
+       /* power-on hdmi physical interface */
+       clk_enable(res->hdmiphy);
+       /* use VPP as parent clock; HDMIPHY is not working yet */
+       clk_set_parent(res->sclk_hdmi, res->sclk_pixel);
+       /* turn clocks on */
+       clk_enable(res->sclk_hdmi);
+}
+
+static int hdmi_runtime_resume(struct device *dev);
+static int hdmi_runtime_suspend(struct device *dev);
+
+static int hdmi_s_power(struct v4l2_subdev *sd, int on)
+{
+       struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+
+       /* If runtime PM is not implemented, hdmi_runtime_resume
+        * and hdmi_runtime_suspend functions are directly called.
+        */
+#ifdef CONFIG_PM_RUNTIME
+       int ret;
+
+       if (on) {
+               clk_enable(hdev->res.hdmi);
+               hdmi_hpd_enable(hdev, 1);
+               ret = pm_runtime_get_sync(hdev->dev);
+               set_internal_hpd_int(hdev);
+       } else {
+               hdmi_hpd_enable(hdev, 0);
+               set_external_hpd_int(hdev);
+               ret = pm_runtime_put_sync(hdev->dev);
+               clk_disable(hdev->res.hdmi);
+       }
+       /* only values < 0 indicate errors */
+       return IS_ERR_VALUE(ret) ? ret : 0;
+#else
+       if (on)
+               hdmi_runtime_resume(hdev->dev);
+       else
+               hdmi_runtime_suspend(hdev->dev);
+       return 0;
+#endif
+}
+
+int hdmi_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+       struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+       struct device *dev = hdev->dev;
+
+       dev_info(dev, "S_CTRL is not applied yet.\n");
+
+       return 0;
+}
+
+int hdmi_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+       struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+       struct device *dev = hdev->dev;
+
+       if (!pm_runtime_suspended(hdev->dev) && !hdev->hpd_user_checked)
+               ctrl->value = hdmi_hpd_status(hdev);
+       else
+               ctrl->value = atomic_read(&hdev->hpd_state);
+
+       dev_dbg(dev, "HDMI cable is %s\n", ctrl->value ?
+                       "connected" : "disconnected");
+
+       return 0;
+}
+
+static int hdmi_s_dv_preset(struct v4l2_subdev *sd,
+       struct v4l2_dv_preset *preset)
+{
+       struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+       struct device *dev = hdev->dev;
+       const struct hdmi_preset_conf *conf;
+
+       conf = hdmi_preset2conf(preset->preset);
+       if (conf == NULL) {
+               dev_err(dev, "preset (%u) not supported\n", preset->preset);
+               return -EINVAL;
+       }
+       hdev->cur_conf = conf;
+       hdev->cur_preset = preset->preset;
+       return 0;
+}
+
+static int hdmi_g_dv_preset(struct v4l2_subdev *sd,
+       struct v4l2_dv_preset *preset)
+{
+       memset(preset, 0, sizeof(*preset));
+       preset->preset = sd_to_hdmi_dev(sd)->cur_preset;
+       return 0;
+}
+
+static int hdmi_g_mbus_fmt(struct v4l2_subdev *sd,
+         struct v4l2_mbus_framefmt *fmt)
+{
+       struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+       struct device *dev = hdev->dev;
+
+       dev_dbg(dev, "%s\n", __func__);
+       if (!hdev->cur_conf)
+               return -EINVAL;
+       *fmt = hdev->cur_conf->mbus_fmt;
+       return 0;
+}
+
+static int hdmi_s_mbus_fmt(struct v4l2_subdev *sd,
+         struct v4l2_mbus_framefmt *fmt)
+{
+       struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+       struct device *dev = hdev->dev;
+
+       dev_dbg(dev, "%s\n", __func__);
+       if (fmt->code == V4L2_MBUS_FMT_YUV8_1X24)
+               hdev->output_fmt = HDMI_OUTPUT_YUV444;
+       else
+               hdev->output_fmt = HDMI_OUTPUT_RGB888;
+
+       return 0;
+}
+
+static int hdmi_enum_dv_presets(struct v4l2_subdev *sd,
+       struct v4l2_dv_enum_preset *preset)
+{
+       if (preset->index >= hdmi_pre_cnt)
+               return -EINVAL;
+       return v4l_fill_dv_preset_info(hdmi_conf[preset->index].preset, preset);
+}
+
+static const struct v4l2_subdev_core_ops hdmi_sd_core_ops = {
+       .s_power = hdmi_s_power,
+       .s_ctrl = hdmi_s_ctrl,
+       .g_ctrl = hdmi_g_ctrl,
+};
+
+static const struct v4l2_subdev_video_ops hdmi_sd_video_ops = {
+       .s_dv_preset = hdmi_s_dv_preset,
+       .g_dv_preset = hdmi_g_dv_preset,
+       .enum_dv_presets = hdmi_enum_dv_presets,
+       .g_mbus_fmt = hdmi_g_mbus_fmt,
+       .s_mbus_fmt = hdmi_s_mbus_fmt,
+       .s_stream = hdmi_s_stream,
+};
+
+static const struct v4l2_subdev_ops hdmi_sd_ops = {
+       .core = &hdmi_sd_core_ops,
+       .video = &hdmi_sd_video_ops,
+};
+
+static int hdmi_runtime_suspend(struct device *dev)
+{
+       struct v4l2_subdev *sd = dev_get_drvdata(dev);
+       struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+       struct hdmi_resources *res = &hdev->res;
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       /* HDMI PHY off sequence
+        * LINK off -> PHY off -> HDMI_PHY_CONTROL disable */
+
+       /* turn clocks off */
+       clk_disable(res->sclk_hdmi);
+
+       v4l2_subdev_call(hdev->phy_sd, core, s_power, 0);
+
+       /* power-off hdmiphy */
+       clk_disable(res->hdmiphy);
+
+       return 0;
+}
+
+static int hdmi_runtime_resume(struct device *dev)
+{
+       struct v4l2_subdev *sd = dev_get_drvdata(dev);
+       struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+       struct hdmi_resources *res = &hdev->res;
+       int ret = 0;
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       hdmi_resource_poweron(&hdev->res);
+
+       hdmi_phy_sw_reset(hdev);
+       ret = v4l2_subdev_call(hdev->phy_sd, core, s_power, 1);
+       if (ret) {
+               dev_err(dev, "failed to turn on hdmiphy\n");
+               goto fail;
+       }
+
+       ret = hdmi_conf_apply(hdev);
+       if (ret)
+               goto fail;
+
+       dev_dbg(dev, "poweron succeed\n");
+
+       return 0;
+
+fail:
+       clk_disable(res->sclk_hdmi);
+       v4l2_subdev_call(hdev->phy_sd, core, s_power, 0);
+       clk_disable(res->hdmiphy);
+       dev_err(dev, "poweron failed\n");
+
+       return ret;
+}
+
+static const struct dev_pm_ops hdmi_pm_ops = {
+       .runtime_suspend = hdmi_runtime_suspend,
+       .runtime_resume  = hdmi_runtime_resume,
+};
+
+static void hdmi_resources_cleanup(struct hdmi_device *hdev)
+{
+       struct hdmi_resources *res = &hdev->res;
+
+       dev_dbg(hdev->dev, "HDMI resource cleanup\n");
+       /* put clocks */
+       if (!IS_ERR_OR_NULL(res->hdmiphy))
+               clk_put(res->hdmiphy);
+       if (!IS_ERR_OR_NULL(res->sclk_hdmiphy))
+               clk_put(res->sclk_hdmiphy);
+       if (!IS_ERR_OR_NULL(res->sclk_pixel))
+               clk_put(res->sclk_pixel);
+       if (!IS_ERR_OR_NULL(res->sclk_hdmi))
+               clk_put(res->sclk_hdmi);
+       if (!IS_ERR_OR_NULL(res->hdmi))
+               clk_put(res->hdmi);
+       memset(res, 0, sizeof *res);
+}
+
+static int hdmi_resources_init(struct hdmi_device *hdev)
+{
+       struct device *dev = hdev->dev;
+       struct hdmi_resources *res = &hdev->res;
+
+       dev_dbg(dev, "HDMI resource init\n");
+
+       memset(res, 0, sizeof *res);
+       /* get clocks, power */
+
+       res->hdmi = clk_get(dev, "hdmi");
+       if (IS_ERR_OR_NULL(res->hdmi)) {
+               dev_err(dev, "failed to get clock 'hdmi'\n");
+               goto fail;
+       }
+       res->sclk_hdmi = clk_get(dev, "sclk_hdmi");
+       if (IS_ERR_OR_NULL(res->sclk_hdmi)) {
+               dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
+               goto fail;
+       }
+       res->sclk_pixel = clk_get(dev, "sclk_pixel");
+       if (IS_ERR_OR_NULL(res->sclk_pixel)) {
+               dev_err(dev, "failed to get clock 'sclk_pixel'\n");
+               goto fail;
+       }
+       res->sclk_hdmiphy = clk_get(dev, "sclk_hdmiphy");
+       if (IS_ERR_OR_NULL(res->sclk_hdmiphy)) {
+               dev_err(dev, "failed to get clock 'sclk_hdmiphy'\n");
+               goto fail;
+       }
+       res->hdmiphy = clk_get(dev, "hdmiphy");
+       if (IS_ERR_OR_NULL(res->hdmiphy)) {
+               dev_err(dev, "failed to get clock 'hdmiphy'\n");
+               goto fail;
+       }
+
+       return 0;
+fail:
+       dev_err(dev, "HDMI resource init - failed\n");
+       hdmi_resources_cleanup(hdev);
+       return -ENODEV;
+}
+
+static int hdmi_link_setup(struct media_entity *entity,
+                             const struct media_pad *local,
+                             const struct media_pad *remote, u32 flags)
+{
+       return 0;
+}
+
+/* hdmi entity operations */
+static const struct media_entity_operations hdmi_entity_ops = {
+       .link_setup = hdmi_link_setup,
+};
+
+static int hdmi_register_entity(struct hdmi_device *hdev)
+{
+       struct v4l2_subdev *sd = &hdev->sd;
+       struct v4l2_device *v4l2_dev;
+       struct media_pad *pads = &hdev->pad;
+       struct media_entity *me = &sd->entity;
+       struct device *dev = hdev->dev;
+       struct exynos_md *md;
+       int ret;
+
+       dev_dbg(dev, "HDMI entity init\n");
+
+       /* init hdmi subdev */
+       v4l2_subdev_init(sd, &hdmi_sd_ops);
+       sd->owner = THIS_MODULE;
+       strlcpy(sd->name, "exynos5-hdmi", sizeof(sd->name));
+
+       dev_set_drvdata(dev, sd);
+
+       /* init hdmi sub-device as entity */
+       pads[HDMI_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+       me->ops = &hdmi_entity_ops;
+       ret = media_entity_init(me, HDMI_PADS_NUM, pads, 0);
+       if (ret) {
+               dev_err(dev, "failed to initialize media entity\n");
+               return ret;
+       }
+
+       /* get output media ptr for registering hdmi's sd */
+       md = (struct exynos_md *)module_name_to_driver_data(MDEV_MODULE_NAME);
+       if (!md) {
+               dev_err(dev, "failed to get output media device\n");
+               return -ENODEV;
+       }
+
+       v4l2_dev = &md->v4l2_dev;
+
+       /* regiser HDMI subdev as entity to v4l2_dev pointer of
+        * output media device
+        */
+       ret = v4l2_device_register_subdev(v4l2_dev, sd);
+       if (ret) {
+               dev_err(dev, "failed to register HDMI subdev\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static void hdmi_entity_info_print(struct hdmi_device *hdev)
+{
+       struct v4l2_subdev *sd = &hdev->sd;
+       struct media_entity *me = &sd->entity;
+
+       dev_dbg(hdev->dev, "\n************* HDMI entity info **************\n");
+       dev_dbg(hdev->dev, "[SUB DEVICE INFO]\n");
+       entity_info_print(me, hdev->dev);
+       dev_dbg(hdev->dev, "*********************************************\n\n");
+}
+
+static void s5p_hpd_kobject_uevent(struct work_struct *work)
+{
+       struct hdmi_device *hdev = container_of(work, struct hdmi_device,
+                                               hpd_work);
+       char *disconnected[2] = { "HDMI_STATE=offline", NULL };
+       char *connected[2]    = { "HDMI_STATE=online", NULL };
+       char **envp = NULL;
+       int state = atomic_read(&hdev->hpd_state);
+
+       /* irq setting by TV power on/off status */
+       if (!pm_runtime_suspended(hdev->dev))
+               set_internal_hpd_int(hdev);
+       else
+               set_external_hpd_int(hdev);
+
+       if (state)
+               envp = connected;
+       else
+               envp = disconnected;
+
+       hdev->hpd_user_checked = true;
+
+       kobject_uevent_env(&hdev->dev->kobj, KOBJ_CHANGE, envp);
+       pr_info("%s: sent uevent %s\n", __func__, envp[0]);
+}
+
+static int __devinit hdmi_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct resource *res;
+       struct i2c_adapter *phy_adapter;
+       struct hdmi_device *hdmi_dev = NULL;
+       struct hdmi_driver_data *drv_data;
+       int ret;
+       unsigned int irq_type;
+
+       dev_dbg(dev, "probe start\n");
+
+       hdmi_dev = kzalloc(sizeof(*hdmi_dev), GFP_KERNEL);
+       if (!hdmi_dev) {
+               dev_err(dev, "out of memory\n");
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       hdmi_dev->dev = dev;
+       ret = hdmi_resources_init(hdmi_dev);
+       if (ret)
+               goto fail_hdev;
+
+       /* mapping HDMI registers */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               dev_err(dev, "get memory resource failed.\n");
+               ret = -ENXIO;
+               goto fail_init;
+       }
+
+       hdmi_dev->regs = ioremap(res->start, resource_size(res));
+       if (hdmi_dev->regs == NULL) {
+               dev_err(dev, "register mapping failed.\n");
+               ret = -ENXIO;
+               goto fail_hdev;
+       }
+
+       /* External hpd */
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (res == NULL) {
+               dev_err(dev, "get external interrupt resource failed.\n");
+               ret = -ENXIO;
+               goto fail_regs;
+       }
+       hdmi_dev->ext_irq = res->start;
+
+       /* Internal hpd */
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
+       if (res == NULL) {
+               dev_err(dev, "get internal interrupt resource failed.\n");
+               ret = -ENXIO;
+               goto fail_regs;
+       }
+       hdmi_dev->int_irq = res->start;
+
+       /* workqueue for HPD */
+       hdmi_dev->hpd_wq = create_workqueue("hdmi-hpd");
+       if (hdmi_dev->hpd_wq == NULL)
+               ret = -ENXIO;
+       INIT_WORK(&hdmi_dev->hpd_work, s5p_hpd_kobject_uevent);
+
+       /* setting v4l2 name to prevent WARN_ON in v4l2_device_register */
+       strlcpy(hdmi_dev->v4l2_dev.name, dev_name(dev),
+               sizeof(hdmi_dev->v4l2_dev.name));
+       /* passing NULL owner prevents driver from erasing drvdata */
+       ret = v4l2_device_register(NULL, &hdmi_dev->v4l2_dev);
+       if (ret) {
+               dev_err(dev, "could not register v4l2 device.\n");
+               goto fail_regs;
+       }
+
+       drv_data = (struct hdmi_driver_data *)get_drvdata(pdev);
+       dev_info(dev, "hdmiphy i2c bus number = %d\n", drv_data->hdmiphy_bus);
+
+       phy_adapter = i2c_get_adapter(drv_data->hdmiphy_bus);
+       if (phy_adapter == NULL) {
+               dev_err(dev, "adapter request failed\n");
+               ret = -ENXIO;
+               goto fail_vdev;
+       }
+
+       hdmi_dev->phy_sd = v4l2_i2c_new_subdev_board(&hdmi_dev->v4l2_dev,
+               phy_adapter, &hdmiphy_info, NULL);
+       /* on failure or not adapter is no longer useful */
+       i2c_put_adapter(phy_adapter);
+       if (hdmi_dev->phy_sd == NULL) {
+               dev_err(dev, "missing subdev for hdmiphy\n");
+               ret = -ENODEV;
+               goto fail_vdev;
+       }
+
+       /* HDMI PHY power off
+        * HDMI PHY is on as default configuration
+        * So, HDMI PHY must be turned off if it's not used */
+       clk_enable(hdmi_dev->res.hdmiphy);
+       v4l2_subdev_call(hdmi_dev->phy_sd, core, s_power, 0);
+       clk_disable(hdmi_dev->res.hdmiphy);
+
+       pm_runtime_enable(dev);
+
+       /* irq setting by TV power on/off status */
+       if (!pm_runtime_suspended(hdmi_dev->dev)) {
+               hdmi_dev->curr_irq = hdmi_dev->int_irq;
+               irq_type = 0;
+               s5p_v4l2_int_src_hdmi_hpd();
+       } else {
+               if (s5p_v4l2_hpd_read_gpio())
+                       atomic_set(&hdmi_dev->hpd_state, HPD_HIGH);
+               else
+                       atomic_set(&hdmi_dev->hpd_state, HPD_LOW);
+               hdmi_dev->curr_irq = hdmi_dev->ext_irq;
+               irq_type = IRQ_TYPE_EDGE_BOTH;
+               s5p_v4l2_int_src_ext_hpd();
+       }
+
+       hdmi_dev->hpd_user_checked = false;
+
+       ret = request_irq(hdmi_dev->curr_irq, hdmi_irq_handler,
+                       irq_type, "hdmi", hdmi_dev);
+
+       if (ret) {
+               dev_err(dev, "request interrupt failed.\n");
+               goto fail_vdev;
+       }
+
+       hdmi_dev->cur_preset = HDMI_DEFAULT_PRESET;
+       /* FIXME: missing fail preset is not supported */
+       hdmi_dev->cur_conf = hdmi_preset2conf(hdmi_dev->cur_preset);
+
+       /* default audio configuration : enable audio */
+       hdmi_dev->audio_enable = 1;
+       hdmi_dev->sample_rate = DEFAULT_SAMPLE_RATE;
+       hdmi_dev->bits_per_sample = DEFAULT_BITS_PER_SAMPLE;
+       hdmi_dev->audio_codec = DEFAULT_AUDIO_CODEC;
+
+       /* register hdmi subdev as entity */
+       ret = hdmi_register_entity(hdmi_dev);
+       if (ret)
+               goto fail_irq;
+
+       hdmi_entity_info_print(hdmi_dev);
+
+       /* initialize hdcp resource */
+       ret = hdcp_prepare(hdmi_dev);
+       if (ret)
+               goto fail_irq;
+
+       dev_info(dev, "probe sucessful\n");
+
+       return 0;
+
+fail_irq:
+       free_irq(hdmi_dev->curr_irq, hdmi_dev);
+
+fail_vdev:
+       v4l2_device_unregister(&hdmi_dev->v4l2_dev);
+
+fail_regs:
+       iounmap(hdmi_dev->regs);
+
+fail_init:
+       hdmi_resources_cleanup(hdmi_dev);
+
+fail_hdev:
+       kfree(hdmi_dev);
+
+fail:
+       dev_err(dev, "probe failed\n");
+       return ret;
+}
+
+static int __devexit hdmi_remove(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct v4l2_subdev *sd = dev_get_drvdata(dev);
+       struct hdmi_device *hdmi_dev = sd_to_hdmi_dev(sd);
+
+       pm_runtime_disable(dev);
+       clk_disable(hdmi_dev->res.hdmi);
+       v4l2_device_unregister(&hdmi_dev->v4l2_dev);
+       disable_irq(hdmi_dev->curr_irq);
+       free_irq(hdmi_dev->curr_irq, hdmi_dev);
+       iounmap(hdmi_dev->regs);
+       hdmi_resources_cleanup(hdmi_dev);
+       flush_workqueue(hdmi_dev->hdcp_wq);
+       destroy_workqueue(hdmi_dev->hdcp_wq);
+       kfree(hdmi_dev);
+       dev_info(dev, "remove sucessful\n");
+
+       return 0;
+}
+
+static struct platform_driver hdmi_driver __refdata = {
+       .probe = hdmi_probe,
+       .remove = __devexit_p(hdmi_remove),
+       .id_table = hdmi_driver_types,
+       .driver = {
+               .name = "exynos5-hdmi",
+               .owner = THIS_MODULE,
+               .pm = &hdmi_pm_ops,
+               .of_match_table = of_match_ptr(exynos_hdmi_match),
+       }
+};
+
+/* D R I V E R   I N I T I A L I Z A T I O N */
+
+static int __init hdmi_init(void)
+{
+       int ret;
+       static const char banner[] __initdata = KERN_INFO \
+               "Samsung HDMI output driver, "
+               "(c) 2010-2011 Samsung Electronics Co., Ltd.\n";
+       printk(banner);
+
+       ret = platform_driver_register(&hdmi_driver);
+       if (ret)
+               printk(KERN_ERR "HDMI platform driver register failed\n");
+
+       return ret;
+}
+module_init(hdmi_init);
+/*late_initcall(hdmi_init);*/
+
+static void __exit hdmi_exit(void)
+{
+       platform_driver_unregister(&hdmi_driver);
+}
+module_exit(hdmi_exit);
diff --git a/drivers/media/video/exynos/tv/hdmi_reg_4210.c b/drivers/media/video/exynos/tv/hdmi_reg_4210.c
new file mode 100644 (file)
index 0000000..51a37c8
--- /dev/null
@@ -0,0 +1,450 @@
+/*
+ * Samsung HDMI driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Jiun Yu <jiun.yu@samsung.com>
+ *
+ * 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 Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#include <linux/delay.h>
+
+#include "hdmi.h"
+#include "regs-hdmi-4210.h"
+
+static const struct hdmi_preset_conf hdmi_conf_480p = {
+       .core = {
+               .h_blank = {0x8a, 0x00},
+               .v_blank = {0x0d, 0x6a, 0x01},
+               .h_v_line = {0x0d, 0xa2, 0x35},
+               .vsync_pol = {0x01},
+               .int_pro_mode = {0x00},
+               .v_blank_f = {0x00, 0x00, 0x00},
+               .h_sync_gen = {0x0e, 0x30, 0x11},
+               .v_sync_gen1 = {0x0f, 0x90, 0x00},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0x5a, 0x03, /* h_fsz */
+               0x8a, 0x00, 0xd0, 0x02, /* hact */
+               0x0d, 0x02, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x2d, 0x00, 0xe0, 0x01, /* vact */
+               0x33, 0x02, /* field_chg */
+               0x49, 0x02, /* vact_st2 */
+               0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+       },
+       .mbus_fmt = {
+               .width = 720,
+               .height = 480,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_720p60 = {
+       .core = {
+               .h_blank = {0x72, 0x01},
+               .v_blank = {0xee, 0xf2, 0x00},
+               .h_v_line = {0xee, 0x22, 0x67},
+               .vsync_pol = {0x00},
+               .int_pro_mode = {0x00},
+               .v_blank_f = {0x00, 0x00, 0x00}, /* don't care */
+               .h_sync_gen = {0x6c, 0x50, 0x02},
+               .v_sync_gen1 = {0x0a, 0x50, 0x00},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0x72, 0x06, /* h_fsz */
+               0x72, 0x01, 0x00, 0x05, /* hact */
+               0xee, 0x02, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x1e, 0x00, 0xd0, 0x02, /* vact */
+               0x33, 0x02, /* field_chg */
+               0x49, 0x02, /* vact_st2 */
+               0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+       },
+       .mbus_fmt = {
+               .width = 1280,
+               .height = 720,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p50 = {
+       .core = {
+               .h_blank = {0xd0, 0x02},
+               .v_blank = {0x65, 0x6c, 0x01},
+               .h_v_line = {0x65, 0x04, 0xa5},
+               .vsync_pol = {0x00},
+               .int_pro_mode = {0x00},
+               .v_blank_f = {0x00, 0x00, 0x00}, /* don't care */
+               .h_sync_gen = {0x0e, 0xea, 0x08},
+               .v_sync_gen1 = {0x09, 0x40, 0x00},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0x98, 0x08, /* h_fsz */
+               0x18, 0x01, 0x80, 0x07, /* hact */
+               0x65, 0x04, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x2d, 0x00, 0x38, 0x04, /* vact */
+               0x33, 0x02, /* field_chg */
+               0x49, 0x02, /* vact_st2 */
+               0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+       },
+       .mbus_fmt = {
+               .width = 1920,
+               .height = 1080,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p60 = {
+       .core = {
+               .h_blank = {0x18, 0x01},
+               .v_blank = {0x65, 0x6c, 0x01},
+               .h_v_line = {0x65, 0x84, 0x89},
+               .vsync_pol = {0x00},
+               .int_pro_mode = {0x00},
+               .v_blank_f = {0x00, 0x00, 0x00}, /* don't care */
+               .h_sync_gen = {0x56, 0x08, 0x02},
+               .v_sync_gen1 = {0x09, 0x40, 0x00},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0x98, 0x08, /* h_fsz */
+               0x18, 0x01, 0x80, 0x07, /* hact */
+               0x65, 0x04, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x2d, 0x00, 0x38, 0x04, /* vact */
+               0x33, 0x02, /* field_chg */
+               0x48, 0x02, /* vact_st2 */
+               0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+       },
+       .mbus_fmt = {
+               .width = 1920,
+               .height = 1080,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080i60 = {
+       .core = {
+               .h_blank = {0x18, 0x01},
+               .v_blank = {0x32, 0xb2, 0x00},
+               .h_v_line = {0x65, 0x84, 0x89},
+               .vsync_pol = {0x00},
+               .int_pro_mode = {0x01},
+               .v_blank_f = {0x49, 0x2a, 0x23},
+               .h_sync_gen = {0x56, 0x08, 0x02},
+               .v_sync_gen1 = {0x07, 0x20, 0x00},
+               .v_sync_gen2 = {0x39, 0x42, 0x23},
+               .v_sync_gen3 = {0xa4, 0x44, 0x4a},
+       },
+       .tg = {
+               0x00, /* cmd */
+               0x98, 0x08, /* h_fsz */
+               0x17, 0x01, 0x81, 0x07, /* hact */
+               0x65, 0x04, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x16, 0x00, 0x1c, 0x02, /* vact */
+               0x33, 0x02, /* field_chg */
+               0x49, 0x02, /* vact_st2 */
+               0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+       },
+       .mbus_fmt = {
+               .width = 1920,
+               .height = 1080,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_INTERLACED,
+       },
+};
+
+const struct hdmi_conf hdmi_conf[] = {
+       { V4L2_DV_480P59_94, &hdmi_conf_480p },
+       { V4L2_DV_720P59_94, &hdmi_conf_720p60 },
+       { V4L2_DV_1080P50, &hdmi_conf_1080p50 },
+       { V4L2_DV_1080P30, &hdmi_conf_1080p60 },
+       { V4L2_DV_1080P60, &hdmi_conf_1080p60 },
+       { V4L2_DV_1080I60, &hdmi_conf_1080i60 },
+};
+
+const int hdmi_pre_cnt = ARRAY_SIZE(hdmi_conf);
+
+irqreturn_t hdmi_irq_handler(int irq, void *dev_data)
+{
+       struct hdmi_device *hdev = dev_data;
+       u32 intc_flag;
+
+       (void)irq;
+       intc_flag = hdmi_read(hdev, HDMI_INTC_FLAG);
+       /* clearing flags for HPD plug/unplug */
+       if (intc_flag & HDMI_INTC_FLAG_HPD_UNPLUG) {
+               printk(KERN_INFO "unplugged\n");
+               hdmi_write_mask(hdev, HDMI_INTC_FLAG, ~0,
+                       HDMI_INTC_FLAG_HPD_UNPLUG);
+       }
+       if (intc_flag & HDMI_INTC_FLAG_HPD_PLUG) {
+               printk(KERN_INFO "plugged\n");
+               hdmi_write_mask(hdev, HDMI_INTC_FLAG, ~0,
+                       HDMI_INTC_FLAG_HPD_PLUG);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static void hdmi_reg_init(struct hdmi_device *hdev)
+{
+       /* enable HPD interrupts */
+       hdmi_write_mask(hdev, HDMI_INTC_CON, ~0, HDMI_INTC_EN_GLOBAL |
+               HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
+       /* choose HDMI mode */
+       hdmi_write_mask(hdev, HDMI_MODE_SEL,
+               HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
+       /* disable bluescreen */
+       hdmi_write_mask(hdev, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
+       /* choose bluescreen (fecal) color */
+       hdmi_writeb(hdev, HDMI_BLUE_SCREEN_0, 0x12);
+       hdmi_writeb(hdev, HDMI_BLUE_SCREEN_1, 0x34);
+       hdmi_writeb(hdev, HDMI_BLUE_SCREEN_2, 0x56);
+       /* enable AVI packet every vsync, fixes purple line problem */
+       hdmi_writeb(hdev, HDMI_AVI_CON, 0x02);
+       /* force YUV444, look to CEA-861-D, table 7 for more detail */
+       hdmi_writeb(hdev, HDMI_AVI_BYTE(0), 2 << 5);
+       hdmi_write_mask(hdev, HDMI_CON_1, 2, 3 << 5);
+}
+
+static void hdmi_timing_apply(struct hdmi_device *hdev,
+       const struct hdmi_preset_conf *conf)
+{
+       const struct hdmi_core_regs *core = &conf->core;
+       const struct hdmi_tg_regs *tg = &conf->tg;
+
+       /* setting core registers */
+       hdmi_writeb(hdev, HDMI_H_BLANK_0, core->h_blank[0]);
+       hdmi_writeb(hdev, HDMI_H_BLANK_1, core->h_blank[1]);
+       hdmi_writeb(hdev, HDMI_V_BLANK_0, core->v_blank[0]);
+       hdmi_writeb(hdev, HDMI_V_BLANK_1, core->v_blank[1]);
+       hdmi_writeb(hdev, HDMI_V_BLANK_2, core->v_blank[2]);
+       hdmi_writeb(hdev, HDMI_H_V_LINE_0, core->h_v_line[0]);
+       hdmi_writeb(hdev, HDMI_H_V_LINE_1, core->h_v_line[1]);
+       hdmi_writeb(hdev, HDMI_H_V_LINE_2, core->h_v_line[2]);
+       hdmi_writeb(hdev, HDMI_VSYNC_POL, core->vsync_pol[0]);
+       hdmi_writeb(hdev, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
+       hdmi_writeb(hdev, HDMI_V_BLANK_F_0, core->v_blank_f[0]);
+       hdmi_writeb(hdev, HDMI_V_BLANK_F_1, core->v_blank_f[1]);
+       hdmi_writeb(hdev, HDMI_V_BLANK_F_2, core->v_blank_f[2]);
+       hdmi_writeb(hdev, HDMI_H_SYNC_GEN_0, core->h_sync_gen[0]);
+       hdmi_writeb(hdev, HDMI_H_SYNC_GEN_1, core->h_sync_gen[1]);
+       hdmi_writeb(hdev, HDMI_H_SYNC_GEN_2, core->h_sync_gen[2]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_GEN_1_0, core->v_sync_gen1[0]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_GEN_1_1, core->v_sync_gen1[1]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_GEN_1_2, core->v_sync_gen1[2]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_GEN_2_0, core->v_sync_gen2[0]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_GEN_2_1, core->v_sync_gen2[1]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_GEN_2_2, core->v_sync_gen2[2]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_GEN_3_0, core->v_sync_gen3[0]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_GEN_3_1, core->v_sync_gen3[1]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_GEN_3_2, core->v_sync_gen3[2]);
+       /* Timing generator registers */
+       hdmi_writeb(hdev, HDMI_TG_H_FSZ_L, tg->h_fsz_l);
+       hdmi_writeb(hdev, HDMI_TG_H_FSZ_H, tg->h_fsz_h);
+       hdmi_writeb(hdev, HDMI_TG_HACT_ST_L, tg->hact_st_l);
+       hdmi_writeb(hdev, HDMI_TG_HACT_ST_H, tg->hact_st_h);
+       hdmi_writeb(hdev, HDMI_TG_HACT_SZ_L, tg->hact_sz_l);
+       hdmi_writeb(hdev, HDMI_TG_HACT_SZ_H, tg->hact_sz_h);
+       hdmi_writeb(hdev, HDMI_TG_V_FSZ_L, tg->v_fsz_l);
+       hdmi_writeb(hdev, HDMI_TG_V_FSZ_H, tg->v_fsz_h);
+       hdmi_writeb(hdev, HDMI_TG_VSYNC_L, tg->vsync_l);
+       hdmi_writeb(hdev, HDMI_TG_VSYNC_H, tg->vsync_h);
+       hdmi_writeb(hdev, HDMI_TG_VSYNC2_L, tg->vsync2_l);
+       hdmi_writeb(hdev, HDMI_TG_VSYNC2_H, tg->vsync2_h);
+       hdmi_writeb(hdev, HDMI_TG_VACT_ST_L, tg->vact_st_l);
+       hdmi_writeb(hdev, HDMI_TG_VACT_ST_H, tg->vact_st_h);
+       hdmi_writeb(hdev, HDMI_TG_VACT_SZ_L, tg->vact_sz_l);
+       hdmi_writeb(hdev, HDMI_TG_VACT_SZ_H, tg->vact_sz_h);
+       hdmi_writeb(hdev, HDMI_TG_FIELD_CHG_L, tg->field_chg_l);
+       hdmi_writeb(hdev, HDMI_TG_FIELD_CHG_H, tg->field_chg_h);
+       hdmi_writeb(hdev, HDMI_TG_VACT_ST2_L, tg->vact_st2_l);
+       hdmi_writeb(hdev, HDMI_TG_VACT_ST2_H, tg->vact_st2_h);
+       hdmi_writeb(hdev, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi_l);
+       hdmi_writeb(hdev, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi_h);
+       hdmi_writeb(hdev, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi_l);
+       hdmi_writeb(hdev, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi_h);
+       hdmi_writeb(hdev, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi_l);
+       hdmi_writeb(hdev, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi_h);
+       hdmi_writeb(hdev, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi_l);
+       hdmi_writeb(hdev, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi_h);
+}
+
+int hdmi_conf_apply(struct hdmi_device *hdmi_dev)
+{
+       struct device *dev = hdmi_dev->dev;
+       const struct hdmi_preset_conf *conf = hdmi_dev->cur_conf;
+       struct v4l2_dv_preset preset;
+       int ret;
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       /* reset hdmiphy */
+       hdmi_write_mask(hdmi_dev, HDMI_PHY_RSTOUT, ~0, HDMI_PHY_SW_RSTOUT);
+       mdelay(10);
+       hdmi_write_mask(hdmi_dev, HDMI_PHY_RSTOUT,  0, HDMI_PHY_SW_RSTOUT);
+       mdelay(10);
+
+       /* configure presets */
+       preset.preset = hdmi_dev->cur_preset;
+       ret = v4l2_subdev_call(hdmi_dev->phy_sd, video, s_dv_preset, &preset);
+       if (ret) {
+               dev_err(dev, "failed to set preset (%u)\n", preset.preset);
+               return ret;
+       }
+
+       /* resetting HDMI core */
+       hdmi_write_mask(hdmi_dev, HDMI_CORE_RSTOUT,  0, HDMI_CORE_SW_RSTOUT);
+       mdelay(10);
+       hdmi_write_mask(hdmi_dev, HDMI_CORE_RSTOUT, ~0, HDMI_CORE_SW_RSTOUT);
+       mdelay(10);
+
+       hdmi_reg_init(hdmi_dev);
+
+       /* setting core registers */
+       hdmi_timing_apply(hdmi_dev, conf);
+
+       return 0;
+}
+
+int is_hdmiphy_ready(struct hdmi_device *hdev)
+{
+       u32 val = hdmi_read(hdev, HDMI_PHY_STATUS);
+       if (val & HDMI_PHY_STATUS_READY)
+               return 1;
+
+       return 0;
+}
+
+void hdmi_enable(struct hdmi_device *hdev, int on)
+{
+       if (on)
+               hdmi_write_mask(hdev, HDMI_CON_0, ~0, HDMI_EN);
+       else
+               hdmi_write_mask(hdev, HDMI_CON_0, 0, HDMI_EN);
+}
+
+void hdmi_tg_enable(struct hdmi_device *hdev, int on)
+{
+       u32 mask;
+
+       mask = (hdev->cur_conf->mbus_fmt.field == V4L2_FIELD_INTERLACED) ?
+                       HDMI_TG_EN | HDMI_FIELD_EN : HDMI_TG_EN;
+
+       if (on)
+               hdmi_write_mask(hdev, HDMI_TG_CMD, ~0, mask);
+       else
+               hdmi_write_mask(hdev, HDMI_TG_CMD, 0, mask);
+}
+
+void hdmi_dumpregs(struct hdmi_device *hdev, char *prefix)
+{
+#define DUMPREG(reg_id) \
+       dev_dbg(hdev->dev, "%s:" #reg_id " = %08x\n", prefix, \
+               readl(hdev->regs + reg_id))
+
+       dev_dbg(hdev->dev, "%s: ---- CONTROL REGISTERS ----\n", prefix);
+       DUMPREG(HDMI_INTC_FLAG);
+       DUMPREG(HDMI_INTC_CON);
+       DUMPREG(HDMI_HPD_STATUS);
+       DUMPREG(HDMI_PHY_RSTOUT);
+       DUMPREG(HDMI_PHY_VPLL);
+       DUMPREG(HDMI_PHY_CMU);
+       DUMPREG(HDMI_CORE_RSTOUT);
+
+       dev_dbg(hdev->dev, "%s: ---- CORE REGISTERS ----\n", prefix);
+       DUMPREG(HDMI_CON_0);
+       DUMPREG(HDMI_CON_1);
+       DUMPREG(HDMI_CON_2);
+       DUMPREG(HDMI_SYS_STATUS);
+       DUMPREG(HDMI_PHY_STATUS);
+       DUMPREG(HDMI_STATUS_EN);
+       DUMPREG(HDMI_HPD);
+       DUMPREG(HDMI_MODE_SEL);
+       DUMPREG(HDMI_HPD_GEN);
+       DUMPREG(HDMI_DC_CONTROL);
+       DUMPREG(HDMI_VIDEO_PATTERN_GEN);
+
+       dev_dbg(hdev->dev, "%s: ---- CORE SYNC REGISTERS ----\n", prefix);
+       DUMPREG(HDMI_H_BLANK_0);
+       DUMPREG(HDMI_H_BLANK_1);
+       DUMPREG(HDMI_V_BLANK_0);
+       DUMPREG(HDMI_V_BLANK_1);
+       DUMPREG(HDMI_V_BLANK_2);
+       DUMPREG(HDMI_H_V_LINE_0);
+       DUMPREG(HDMI_H_V_LINE_1);
+       DUMPREG(HDMI_H_V_LINE_2);
+       DUMPREG(HDMI_VSYNC_POL);
+       DUMPREG(HDMI_INT_PRO_MODE);
+       DUMPREG(HDMI_V_BLANK_F_0);
+       DUMPREG(HDMI_V_BLANK_F_1);
+       DUMPREG(HDMI_V_BLANK_F_2);
+       DUMPREG(HDMI_H_SYNC_GEN_0);
+       DUMPREG(HDMI_H_SYNC_GEN_1);
+       DUMPREG(HDMI_H_SYNC_GEN_2);
+       DUMPREG(HDMI_V_SYNC_GEN_1_0);
+       DUMPREG(HDMI_V_SYNC_GEN_1_1);
+       DUMPREG(HDMI_V_SYNC_GEN_1_2);
+       DUMPREG(HDMI_V_SYNC_GEN_2_0);
+       DUMPREG(HDMI_V_SYNC_GEN_2_1);
+       DUMPREG(HDMI_V_SYNC_GEN_2_2);
+       DUMPREG(HDMI_V_SYNC_GEN_3_0);
+       DUMPREG(HDMI_V_SYNC_GEN_3_1);
+       DUMPREG(HDMI_V_SYNC_GEN_3_2);
+
+       dev_dbg(hdev->dev, "%s: ---- TG REGISTERS ----\n", prefix);
+       DUMPREG(HDMI_TG_CMD);
+       DUMPREG(HDMI_TG_H_FSZ_L);
+       DUMPREG(HDMI_TG_H_FSZ_H);
+       DUMPREG(HDMI_TG_HACT_ST_L);
+       DUMPREG(HDMI_TG_HACT_ST_H);
+       DUMPREG(HDMI_TG_HACT_SZ_L);
+       DUMPREG(HDMI_TG_HACT_SZ_H);
+       DUMPREG(HDMI_TG_V_FSZ_L);
+       DUMPREG(HDMI_TG_V_FSZ_H);
+       DUMPREG(HDMI_TG_VSYNC_L);
+       DUMPREG(HDMI_TG_VSYNC_H);
+       DUMPREG(HDMI_TG_VSYNC2_L);
+       DUMPREG(HDMI_TG_VSYNC2_H);
+       DUMPREG(HDMI_TG_VACT_ST_L);
+       DUMPREG(HDMI_TG_VACT_ST_H);
+       DUMPREG(HDMI_TG_VACT_SZ_L);
+       DUMPREG(HDMI_TG_VACT_SZ_H);
+       DUMPREG(HDMI_TG_FIELD_CHG_L);
+       DUMPREG(HDMI_TG_FIELD_CHG_H);
+       DUMPREG(HDMI_TG_VACT_ST2_L);
+       DUMPREG(HDMI_TG_VACT_ST2_H);
+       DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
+       DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
+       DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
+       DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
+       DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
+       DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
+       DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
+       DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
+#undef DUMPREG
+}
diff --git a/drivers/media/video/exynos/tv/hdmi_reg_5250.c b/drivers/media/video/exynos/tv/hdmi_reg_5250.c
new file mode 100644 (file)
index 0000000..1384966
--- /dev/null
@@ -0,0 +1,2931 @@
+/*
+ * Samsung HDMI driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Jiun Yu <jiun.yu@samsung.com>
+ *
+ * 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 Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+#include <plat/devs.h>
+#include <plat/tv-core.h>
+
+#include "hdmi.h"
+#include "regs-hdmi-5250.h"
+
+static const struct hdmi_preset_conf hdmi_conf_480p60 = {
+       .core = {
+               .h_blank = {0x8a, 0x00},
+               .v2_blank = {0x0d, 0x02},
+               .v1_blank = {0x2d, 0x00},
+               .v_line = {0x0d, 0x02},
+               .h_line = {0x5a, 0x03},
+               .hsync_pol = {0x01},
+               .vsync_pol = {0x01},
+               .int_pro_mode = {0x00},
+               .v_blank_f0 = {0xff, 0xff},
+               .v_blank_f1 = {0xff, 0xff},
+               .h_sync_start = {0x0e, 0x00},
+               .h_sync_end = {0x4c, 0x00},
+               .v_sync_line_bef_2 = {0x0f, 0x00},
+               .v_sync_line_bef_1 = {0x09, 0x00},
+               .v_sync_line_aft_2 = {0xff, 0xff},
+               .v_sync_line_aft_1 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+               .v_blank_f2 = {0xff, 0xff},
+               .v_blank_f3 = {0xff, 0xff},
+               .v_blank_f4 = {0xff, 0xff},
+               .v_blank_f5 = {0xff, 0xff},
+               .v_sync_line_aft_3 = {0xff, 0xff},
+               .v_sync_line_aft_4 = {0xff, 0xff},
+               .v_sync_line_aft_5 = {0xff, 0xff},
+               .v_sync_line_aft_6 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+               .vact_space_1 = {0xff, 0xff},
+               .vact_space_2 = {0xff, 0xff},
+               .vact_space_3 = {0xff, 0xff},
+               .vact_space_4 = {0xff, 0xff},
+               .vact_space_5 = {0xff, 0xff},
+               .vact_space_6 = {0xff, 0xff},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0x5a, 0x03, /* h_fsz */
+               0x8a, 0x00, 0xd0, 0x02, /* hact */
+               0x0d, 0x02, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x2d, 0x00, 0xe0, 0x01, /* vact */
+               0x33, 0x02, /* field_chg */
+               0x48, 0x02, /* vact_st2 */
+               0x00, 0x00, /* vact_st3 */
+               0x00, 0x00, /* vact_st4 */
+               0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+               0x00, /* 3d FP */
+       },
+       .mbus_fmt = {
+               .width = 720,
+               .height = 480,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_720p60 = {
+       .core = {
+               .h_blank = {0x72, 0x01},
+               .v2_blank = {0xee, 0x02},
+               .v1_blank = {0x1e, 0x00},
+               .v_line = {0xee, 0x02},
+               .h_line = {0x72, 0x06},
+               .hsync_pol = {0x00},
+               .vsync_pol = {0x00},
+               .int_pro_mode = {0x00},
+               .v_blank_f0 = {0xff, 0xff},
+               .v_blank_f1 = {0xff, 0xff},
+               .h_sync_start = {0x6c, 0x00},
+               .h_sync_end = {0x94, 0x00},
+               .v_sync_line_bef_2 = {0x0a, 0x00},
+               .v_sync_line_bef_1 = {0x05, 0x00},
+               .v_sync_line_aft_2 = {0xff, 0xff},
+               .v_sync_line_aft_1 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+               .v_blank_f2 = {0xff, 0xff},
+               .v_blank_f3 = {0xff, 0xff},
+               .v_blank_f4 = {0xff, 0xff},
+               .v_blank_f5 = {0xff, 0xff},
+               .v_sync_line_aft_3 = {0xff, 0xff},
+               .v_sync_line_aft_4 = {0xff, 0xff},
+               .v_sync_line_aft_5 = {0xff, 0xff},
+               .v_sync_line_aft_6 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+               .vact_space_1 = {0xff, 0xff},
+               .vact_space_2 = {0xff, 0xff},
+               .vact_space_3 = {0xff, 0xff},
+               .vact_space_4 = {0xff, 0xff},
+               .vact_space_5 = {0xff, 0xff},
+               .vact_space_6 = {0xff, 0xff},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0x72, 0x06, /* h_fsz */
+               0x72, 0x01, 0x00, 0x05, /* hact */
+               0xee, 0x02, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x1e, 0x00, 0xd0, 0x02, /* vact */
+               0x33, 0x02, /* field_chg */
+               0x48, 0x02, /* vact_st2 */
+               0x00, 0x00, /* vact_st3 */
+               0x00, 0x00, /* vact_st4 */
+               0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+               0x00, /* 3d FP */
+       },
+       .mbus_fmt = {
+               .width = 1280,
+               .height = 720,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080i60 = {
+       .core = {
+               .h_blank = {0x18, 0x01},
+               .v2_blank = {0x32, 0x02},
+               .v1_blank = {0x16, 0x00},
+               .v_line = {0x65, 0x04},
+               .h_line = {0x98, 0x08},
+               .hsync_pol = {0x00},
+               .vsync_pol = {0x00},
+               .int_pro_mode = {0x01},
+               .v_blank_f0 = {0x49, 0x02},
+               .v_blank_f1 = {0x65, 0x04},
+               .h_sync_start = {0x56, 0x00},
+               .h_sync_end = {0x82, 0x00},
+               .v_sync_line_bef_2 = {0x07, 0x00},
+               .v_sync_line_bef_1 = {0x02, 0x00},
+               .v_sync_line_aft_2 = {0x39, 0x02},
+               .v_sync_line_aft_1 = {0x34, 0x02},
+               .v_sync_line_aft_pxl_2 = {0xa4, 0x04},
+               .v_sync_line_aft_pxl_1 = {0xa4, 0x04},
+               .v_blank_f2 = {0xff, 0xff},
+               .v_blank_f3 = {0xff, 0xff},
+               .v_blank_f4 = {0xff, 0xff},
+               .v_blank_f5 = {0xff, 0xff},
+               .v_sync_line_aft_3 = {0xff, 0xff},
+               .v_sync_line_aft_4 = {0xff, 0xff},
+               .v_sync_line_aft_5 = {0xff, 0xff},
+               .v_sync_line_aft_6 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+               .vact_space_1 = {0xff, 0xff},
+               .vact_space_2 = {0xff, 0xff},
+               .vact_space_3 = {0xff, 0xff},
+               .vact_space_4 = {0xff, 0xff},
+               .vact_space_5 = {0xff, 0xff},
+               .vact_space_6 = {0xff, 0xff},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0x98, 0x08, /* h_fsz */
+               0x18, 0x01, 0x80, 0x07, /* hact */
+               0x65, 0x04, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x16, 0x00, 0x1c, 0x02, /* vact */
+               0x33, 0x02, /* field_chg */
+               0x49, 0x02, /* vact_st2 */
+               0x00, 0x00, /* vact_st3 */
+               0x00, 0x00, /* vact_st4 */
+               0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+               0x00, /* 3d FP */
+       },
+       .mbus_fmt = {
+               .width = 1920,
+               .height = 1080,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p60 = {
+       .core = {
+               .h_blank = {0x18, 0x01},
+               .v2_blank = {0x65, 0x04},
+               .v1_blank = {0x2d, 0x00},
+               .v_line = {0x65, 0x04},
+               .h_line = {0x98, 0x08},
+               .hsync_pol = {0x00},
+               .vsync_pol = {0x00},
+               .int_pro_mode = {0x00},
+               .v_blank_f0 = {0xff, 0xff},
+               .v_blank_f1 = {0xff, 0xff},
+               .h_sync_start = {0x56, 0x00},
+               .h_sync_end = {0x82, 0x00},
+               .v_sync_line_bef_2 = {0x09, 0x00},
+               .v_sync_line_bef_1 = {0x04, 0x00},
+               .v_sync_line_aft_2 = {0xff, 0xff},
+               .v_sync_line_aft_1 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+               .v_blank_f2 = {0xff, 0xff},
+               .v_blank_f3 = {0xff, 0xff},
+               .v_blank_f4 = {0xff, 0xff},
+               .v_blank_f5 = {0xff, 0xff},
+               .v_sync_line_aft_3 = {0xff, 0xff},
+               .v_sync_line_aft_4 = {0xff, 0xff},
+               .v_sync_line_aft_5 = {0xff, 0xff},
+               .v_sync_line_aft_6 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0x98, 0x08, /* h_fsz */
+               0x18, 0x01, 0x80, 0x07, /* hact */
+               0x65, 0x04, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x2d, 0x00, 0x38, 0x04, /* vact */
+               0x33, 0x02, /* field_chg */
+               0x48, 0x02, /* vact_st2 */
+               0x00, 0x00, /* vact_st3 */
+               0x00, 0x00, /* vact_st4 */
+               0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+               0x00, /* 3d FP */
+       },
+       .mbus_fmt = {
+               .width = 1920,
+               .height = 1080,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_576p50 = {
+       .core = {
+               .h_blank = {0x90, 0x00},
+               .v2_blank = {0x71, 0x02},
+               .v1_blank = {0x31, 0x00},
+               .v_line = {0x71, 0x02},
+               .h_line = {0x60, 0x03},
+               .hsync_pol = {0x01},
+               .vsync_pol = {0x01},
+               .int_pro_mode = {0x00},
+               .v_blank_f0 = {0xff, 0xff},
+               .v_blank_f1 = {0xff, 0xff},
+               .h_sync_start = {0x0a, 0x00},
+               .h_sync_end = {0x4a, 0x00},
+               .v_sync_line_bef_2 = {0x0a, 0x00},
+               .v_sync_line_bef_1 = {0x05, 0x00},
+               .v_sync_line_aft_2 = {0xff, 0xff},
+               .v_sync_line_aft_1 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+               .v_blank_f2 = {0xff, 0xff},
+               .v_blank_f3 = {0xff, 0xff},
+               .v_blank_f4 = {0xff, 0xff},
+               .v_blank_f5 = {0xff, 0xff},
+               .v_sync_line_aft_3 = {0xff, 0xff},
+               .v_sync_line_aft_4 = {0xff, 0xff},
+               .v_sync_line_aft_5 = {0xff, 0xff},
+               .v_sync_line_aft_6 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0x60, 0x03, /* h_fsz */
+               0x90, 0x00, 0xd0, 0x02, /* hact */
+               0x71, 0x02, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x31, 0x00, 0x40, 0x02, /* vact */
+               0x33, 0x02, /* field_chg */
+               0x48, 0x02, /* vact_st2 */
+               0x00, 0x00, /* vact_st3 */
+               0x00, 0x00, /* vact_st4 */
+               0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+               0x00, /* 3d FP */
+       },
+       .mbus_fmt = {
+               .width = 720,
+               .height = 576,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_720p50 = {
+       .core = {
+               .h_blank = {0xbc, 0x02},
+               .v2_blank = {0xee, 0x02},
+               .v1_blank = {0x1e, 0x00},
+               .v_line = {0xee, 0x02},
+               .h_line = {0xbc, 0x07},
+               .hsync_pol = {0x00},
+               .vsync_pol = {0x00},
+               .int_pro_mode = {0x00},
+               .v_blank_f0 = {0xff, 0xff},
+               .v_blank_f1 = {0xff, 0xff},
+               .h_sync_start = {0xb6, 0x01},
+               .h_sync_end = {0xde, 0x01},
+               .v_sync_line_bef_2 = {0x0a, 0x00},
+               .v_sync_line_bef_1 = {0x05, 0x00},
+               .v_sync_line_aft_2 = {0xff, 0xff},
+               .v_sync_line_aft_1 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+               .v_blank_f2 = {0xff, 0xff},
+               .v_blank_f3 = {0xff, 0xff},
+               .v_blank_f4 = {0xff, 0xff},
+               .v_blank_f5 = {0xff, 0xff},
+               .v_sync_line_aft_3 = {0xff, 0xff},
+               .v_sync_line_aft_4 = {0xff, 0xff},
+               .v_sync_line_aft_5 = {0xff, 0xff},
+               .v_sync_line_aft_6 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+               .vact_space_1 = {0xff, 0xff},
+               .vact_space_2 = {0xff, 0xff},
+               .vact_space_3 = {0xff, 0xff},
+               .vact_space_4 = {0xff, 0xff},
+               .vact_space_5 = {0xff, 0xff},
+               .vact_space_6 = {0xff, 0xff},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0xbc, 0x07, /* h_fsz */
+               0xbc, 0x02, 0x00, 0x05, /* hact */
+               0xee, 0x02, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x1e, 0x00, 0xd0, 0x02, /* vact */
+               0x33, 0x02, /* field_chg */
+               0x48, 0x02, /* vact_st2 */
+               0x00, 0x00, /* vact_st3 */
+               0x00, 0x00, /* vact_st4 */
+               0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+               0x00, /* 3d FP */
+       },
+       .mbus_fmt = {
+               .width = 1280,
+               .height = 720,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080i50 = {
+       .core = {
+               .h_blank = {0xd0, 0x02},
+               .v2_blank = {0x32, 0x02},
+               .v1_blank = {0x16, 0x00},
+               .v_line = {0x65, 0x04},
+               .h_line = {0x50, 0x0a},
+               .hsync_pol = {0x00},
+               .vsync_pol = {0x00},
+               .int_pro_mode = {0x01},
+               .v_blank_f0 = {0x49, 0x02},
+               .v_blank_f1 = {0x65, 0x04},
+               .h_sync_start = {0x0e, 0x02},
+               .h_sync_end = {0x3a, 0x02},
+               .v_sync_line_bef_2 = {0x07, 0x00},
+               .v_sync_line_bef_1 = {0x02, 0x00},
+               .v_sync_line_aft_2 = {0x39, 0x02},
+               .v_sync_line_aft_1 = {0x34, 0x02},
+               .v_sync_line_aft_pxl_2 = {0x38, 0x07},
+               .v_sync_line_aft_pxl_1 = {0x38, 0x07},
+               .v_blank_f2 = {0xff, 0xff},
+               .v_blank_f3 = {0xff, 0xff},
+               .v_blank_f4 = {0xff, 0xff},
+               .v_blank_f5 = {0xff, 0xff},
+               .v_sync_line_aft_3 = {0xff, 0xff},
+               .v_sync_line_aft_4 = {0xff, 0xff},
+               .v_sync_line_aft_5 = {0xff, 0xff},
+               .v_sync_line_aft_6 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+               .vact_space_1 = {0xff, 0xff},
+               .vact_space_2 = {0xff, 0xff},
+               .vact_space_3 = {0xff, 0xff},
+               .vact_space_4 = {0xff, 0xff},
+               .vact_space_5 = {0xff, 0xff},
+               .vact_space_6 = {0xff, 0xff},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0x50, 0x0a, /* h_fsz */
+               0xd0, 0x02, 0x80, 0x07, /* hact */
+               0x65, 0x04, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x16, 0x00, 0x1c, 0x02, /* vact */
+               0x33, 0x02, /* field_chg */
+               0x49, 0x02, /* vact_st2 */
+               0x00, 0x00, /* vact_st3 */
+               0x00, 0x00, /* vact_st4 */
+               0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+               0x00, /* 3d FP */
+       },
+       .mbus_fmt = {
+               .width = 1920,
+               .height = 1080,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p50 = {
+       .core = {
+               .h_blank = {0xd0, 0x02},
+               .v2_blank = {0x65, 0x04},
+               .v1_blank = {0x2d, 0x00},
+               .v_line = {0x65, 0x04},
+               .h_line = {0x50, 0x0a},
+               .hsync_pol = {0x00},
+               .vsync_pol = {0x00},
+               .int_pro_mode = {0x00},
+               .v_blank_f0 = {0xff, 0xff},
+               .v_blank_f1 = {0xff, 0xff},
+               .h_sync_start = {0x0e, 0x02},
+               .h_sync_end = {0x3a, 0x02},
+               .v_sync_line_bef_2 = {0x09, 0x00},
+               .v_sync_line_bef_1 = {0x04, 0x00},
+               .v_sync_line_aft_2 = {0xff, 0xff},
+               .v_sync_line_aft_1 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+               .v_blank_f2 = {0xff, 0xff},
+               .v_blank_f3 = {0xff, 0xff},
+               .v_blank_f4 = {0xff, 0xff},
+               .v_blank_f5 = {0xff, 0xff},
+               .v_sync_line_aft_3 = {0xff, 0xff},
+               .v_sync_line_aft_4 = {0xff, 0xff},
+               .v_sync_line_aft_5 = {0xff, 0xff},
+               .v_sync_line_aft_6 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+               .vact_space_1 = {0xff, 0xff},
+               .vact_space_2 = {0xff, 0xff},
+               .vact_space_3 = {0xff, 0xff},
+               .vact_space_4 = {0xff, 0xff},
+               .vact_space_5 = {0xff, 0xff},
+               .vact_space_6 = {0xff, 0xff},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0x50, 0x0a, /* h_fsz */
+               0xd0, 0x02, 0x80, 0x07, /* hact */
+               0x65, 0x04, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x2d, 0x00, 0x38, 0x04, /* vact */
+               0x33, 0x02, /* field_chg */
+               0x48, 0x02, /* vact_st2 */
+               0x00, 0x00, /* vact_st3 */
+               0x00, 0x00, /* vact_st4 */
+               0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+               0x00, /* 3d FP */
+       },
+       .mbus_fmt = {
+               .width = 1920,
+               .height = 1080,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p30 = {
+       .core = {
+               .h_blank = {0x18, 0x01},
+               .v2_blank = {0x65, 0x04},
+               .v1_blank = {0x2d, 0x00},
+               .v_line = {0x65, 0x04},
+               .h_line = {0x98, 0x08},
+               .hsync_pol = {0x00},
+               .vsync_pol = {0x00},
+               .int_pro_mode = {0x00},
+               .v_blank_f0 = {0xff, 0xff},
+               .v_blank_f1 = {0xff, 0xff},
+               .h_sync_start = {0x56, 0x00},
+               .h_sync_end = {0x82, 0x00},
+               .v_sync_line_bef_2 = {0x09, 0x00},
+               .v_sync_line_bef_1 = {0x04, 0x00},
+               .v_sync_line_aft_2 = {0xff, 0xff},
+               .v_sync_line_aft_1 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+               .v_blank_f2 = {0xff, 0xff},
+               .v_blank_f3 = {0xff, 0xff},
+               .v_blank_f4 = {0xff, 0xff},
+               .v_blank_f5 = {0xff, 0xff},
+               .v_sync_line_aft_3 = {0xff, 0xff},
+               .v_sync_line_aft_4 = {0xff, 0xff},
+               .v_sync_line_aft_5 = {0xff, 0xff},
+               .v_sync_line_aft_6 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+               .vact_space_1 = {0xff, 0xff},
+               .vact_space_2 = {0xff, 0xff},
+               .vact_space_3 = {0xff, 0xff},
+               .vact_space_4 = {0xff, 0xff},
+               .vact_space_5 = {0xff, 0xff},
+               .vact_space_6 = {0xff, 0xff},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0x98, 0x08, /* h_fsz */
+               0x18, 0x01, 0x80, 0x07, /* hact */
+               0x65, 0x04, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x2d, 0x00, 0x38, 0x04, /* vact */
+               0x33, 0x02, /* field_chg */
+               0x48, 0x02, /* vact_st2 */
+               0x00, 0x00, /* vact_st3 */
+               0x00, 0x00, /* vact_st4 */
+               0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+               0x00, /* 3d FP */
+       },
+       .mbus_fmt = {
+               .width = 1920,
+               .height = 1080,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p24 = {
+       .core = {
+               .h_blank = {0x3e, 0x03},
+               .v2_blank = {0x65, 0x04},
+               .v1_blank = {0x2d, 0x00},
+               .v_line = {0x65, 0x04},
+               .h_line = {0xbe, 0x0a},
+               .hsync_pol = {0x00},
+               .vsync_pol = {0x00},
+               .int_pro_mode = {0x00},
+               .v_blank_f0 = {0xff, 0xff},
+               .v_blank_f1 = {0xff, 0xff},
+               .h_sync_start = {0x7c, 0x02},
+               .h_sync_end = {0xa8, 0x02},
+               .v_sync_line_bef_2 = {0x09, 0x00},
+               .v_sync_line_bef_1 = {0x04, 0x00},
+               .v_sync_line_aft_2 = {0xff, 0xff},
+               .v_sync_line_aft_1 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+               .v_blank_f2 = {0xff, 0xff},
+               .v_blank_f3 = {0xff, 0xff},
+               .v_blank_f4 = {0xff, 0xff},
+               .v_blank_f5 = {0xff, 0xff},
+               .v_sync_line_aft_3 = {0xff, 0xff},
+               .v_sync_line_aft_4 = {0xff, 0xff},
+               .v_sync_line_aft_5 = {0xff, 0xff},
+               .v_sync_line_aft_6 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+               .vact_space_1 = {0xff, 0xff},
+               .vact_space_2 = {0xff, 0xff},
+               .vact_space_3 = {0xff, 0xff},
+               .vact_space_4 = {0xff, 0xff},
+               .vact_space_5 = {0xff, 0xff},
+               .vact_space_6 = {0xff, 0xff},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0xbe, 0x0a, /* h_fsz */
+               0x3e, 0x03, 0x80, 0x07, /* hact */
+               0x65, 0x04, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x2d, 0x00, 0x38, 0x04, /* vact */
+               0x33, 0x02, /* field_chg */
+               0x48, 0x02, /* vact_st2 */
+               0x00, 0x00, /* vact_st3 */
+               0x00, 0x00, /* vact_st4 */
+               0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+               0x00, /* 3d FP */
+       },
+       .mbus_fmt = {
+               .width = 1920,
+               .height = 1080,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p25 = {
+       .core = {
+               .h_blank = {0xd0, 0x02},
+               .v2_blank = {0x65, 0x04},
+               .v1_blank = {0x2d, 0x00},
+               .v_line = {0x65, 0x04},
+               .h_line = {0x50, 0x0a},
+               .hsync_pol = {0x00},
+               .vsync_pol = {0x00},
+               .int_pro_mode = {0x00},
+               .v_blank_f0 = {0xff, 0xff},
+               .v_blank_f1 = {0xff, 0xff},
+               .h_sync_start = {0x0e, 0x02},
+               .h_sync_end = {0x3a, 0x02},
+               .v_sync_line_bef_2 = {0x09, 0x00},
+               .v_sync_line_bef_1 = {0x04, 0x00},
+               .v_sync_line_aft_2 = {0xff, 0xff},
+               .v_sync_line_aft_1 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+               .v_blank_f2 = {0xff, 0xff},
+               .v_blank_f3 = {0xff, 0xff},
+               .v_blank_f4 = {0xff, 0xff},
+               .v_blank_f5 = {0xff, 0xff},
+               .v_sync_line_aft_3 = {0xff, 0xff},
+               .v_sync_line_aft_4 = {0xff, 0xff},
+               .v_sync_line_aft_5 = {0xff, 0xff},
+               .v_sync_line_aft_6 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+               .vact_space_1 = {0xff, 0xff},
+               .vact_space_2 = {0xff, 0xff},
+               .vact_space_3 = {0xff, 0xff},
+               .vact_space_4 = {0xff, 0xff},
+               .vact_space_5 = {0xff, 0xff},
+               .vact_space_6 = {0xff, 0xff},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0x50, 0x0a, /* h_fsz */
+               0xd0, 0x02, 0x80, 0x07, /* hact */
+               0x65, 0x04, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x2d, 0x00, 0x38, 0x04, /* vact */
+               0x33, 0x02, /* field_chg */
+               0x48, 0x02, /* vact_st2 */
+               0x00, 0x00, /* vact_st3 */
+               0x00, 0x00, /* vact_st4 */
+               0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+               0x00, /* 3d FP */
+       },
+       .mbus_fmt = {
+               .width = 1920,
+               .height = 1080,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_480p59_94 = {
+       .core = {
+               .h_blank = {0x8a, 0x00},
+               .v2_blank = {0x0d, 0x02},
+               .v1_blank = {0x2d, 0x00},
+               .v_line = {0x0d, 0x02},
+               .h_line = {0x5a, 0x03},
+               .hsync_pol = {0x01},
+               .vsync_pol = {0x01},
+               .int_pro_mode = {0x00},
+               .v_blank_f0 = {0xff, 0xff},
+               .v_blank_f1 = {0xff, 0xff},
+               .h_sync_start = {0x0e, 0x00},
+               .h_sync_end = {0x4c, 0x00},
+               .v_sync_line_bef_2 = {0x0f, 0x00},
+               .v_sync_line_bef_1 = {0x09, 0x00},
+               .v_sync_line_aft_2 = {0xff, 0xff},
+               .v_sync_line_aft_1 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+               .v_blank_f2 = {0xff, 0xff},
+               .v_blank_f3 = {0xff, 0xff},
+               .v_blank_f4 = {0xff, 0xff},
+               .v_blank_f5 = {0xff, 0xff},
+               .v_sync_line_aft_3 = {0xff, 0xff},
+               .v_sync_line_aft_4 = {0xff, 0xff},
+               .v_sync_line_aft_5 = {0xff, 0xff},
+               .v_sync_line_aft_6 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+               .vact_space_1 = {0xff, 0xff},
+               .vact_space_2 = {0xff, 0xff},
+               .vact_space_3 = {0xff, 0xff},
+               .vact_space_4 = {0xff, 0xff},
+               .vact_space_5 = {0xff, 0xff},
+               .vact_space_6 = {0xff, 0xff},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0x5a, 0x03, /* h_fsz */
+               0x8a, 0x00, 0xd0, 0x02, /* hact */
+               0x0d, 0x02, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x2d, 0x00, 0xe0, 0x01, /* vact */
+               0x33, 0x02, /* field_chg */
+               0x48, 0x02, /* vact_st2 */
+               0x00, 0x00, /* vact_st3 */
+               0x00, 0x00, /* vact_st4 */
+               0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+               0x00, /* 3d FP */
+       },
+       .mbus_fmt = {
+               .width = 720,
+               .height = 480,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_720p59_94 = {
+       .core = {
+               .h_blank = {0x72, 0x01},
+               .v2_blank = {0xee, 0x02},
+               .v1_blank = {0x1e, 0x00},
+               .v_line = {0xee, 0x02},
+               .h_line = {0x72, 0x06},
+               .hsync_pol = {0x00},
+               .vsync_pol = {0x00},
+               .int_pro_mode = {0x00},
+               .v_blank_f0 = {0xff, 0xff},
+               .v_blank_f1 = {0xff, 0xff},
+               .h_sync_start = {0x6c, 0x00},
+               .h_sync_end = {0x94, 0x00},
+               .v_sync_line_bef_2 = {0x0a, 0x00},
+               .v_sync_line_bef_1 = {0x05, 0x00},
+               .v_sync_line_aft_2 = {0xff, 0xff},
+               .v_sync_line_aft_1 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+               .v_blank_f2 = {0xff, 0xff},
+               .v_blank_f3 = {0xff, 0xff},
+               .v_blank_f4 = {0xff, 0xff},
+               .v_blank_f5 = {0xff, 0xff},
+               .v_sync_line_aft_3 = {0xff, 0xff},
+               .v_sync_line_aft_4 = {0xff, 0xff},
+               .v_sync_line_aft_5 = {0xff, 0xff},
+               .v_sync_line_aft_6 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+               .vact_space_1 = {0xff, 0xff},
+               .vact_space_2 = {0xff, 0xff},
+               .vact_space_3 = {0xff, 0xff},
+               .vact_space_4 = {0xff, 0xff},
+               .vact_space_5 = {0xff, 0xff},
+               .vact_space_6 = {0xff, 0xff},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0x72, 0x06, /* h_fsz */
+               0x72, 0x01, 0x00, 0x05, /* hact */
+               0xee, 0x02, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x1e, 0x00, 0xd0, 0x02, /* vact */
+               0x33, 0x02, /* field_chg */
+               0x48, 0x02, /* vact_st2 */
+               0x00, 0x00, /* vact_st3 */
+               0x00, 0x00, /* vact_st4 */
+               0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+               0x00, /* 3d FP */
+       },
+       .mbus_fmt = {
+               .width = 1280,
+               .height = 720,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080i59_94 = {
+       .core = {
+               .h_blank = {0x18, 0x01},
+               .v2_blank = {0x32, 0x02},
+               .v1_blank = {0x16, 0x00},
+               .v_line = {0x65, 0x04},
+               .h_line = {0x98, 0x08},
+               .hsync_pol = {0x00},
+               .vsync_pol = {0x00},
+               .int_pro_mode = {0x01},
+               .v_blank_f0 = {0x49, 0x02},
+               .v_blank_f1 = {0x65, 0x04},
+               .h_sync_start = {0x56, 0x00},
+               .h_sync_end = {0x82, 0x00},
+               .v_sync_line_bef_2 = {0x07, 0x00},
+               .v_sync_line_bef_1 = {0x02, 0x00},
+               .v_sync_line_aft_2 = {0x39, 0x02},
+               .v_sync_line_aft_1 = {0x34, 0x02},
+               .v_sync_line_aft_pxl_2 = {0xa4, 0x04},
+               .v_sync_line_aft_pxl_1 = {0xa4, 0x04},
+               .v_blank_f2 = {0xff, 0xff},
+               .v_blank_f3 = {0xff, 0xff},
+               .v_blank_f4 = {0xff, 0xff},
+               .v_blank_f5 = {0xff, 0xff},
+               .v_sync_line_aft_3 = {0xff, 0xff},
+               .v_sync_line_aft_4 = {0xff, 0xff},
+               .v_sync_line_aft_5 = {0xff, 0xff},
+               .v_sync_line_aft_6 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+               .vact_space_1 = {0xff, 0xff},
+               .vact_space_2 = {0xff, 0xff},
+               .vact_space_3 = {0xff, 0xff},
+               .vact_space_4 = {0xff, 0xff},
+               .vact_space_5 = {0xff, 0xff},
+               .vact_space_6 = {0xff, 0xff},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0x98, 0x08, /* h_fsz */
+               0x18, 0x01, 0x80, 0x07, /* hact */
+               0x65, 0x04, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x16, 0x00, 0x1c, 0x02, /* vact */
+               0x33, 0x02, /* field_chg */
+               0x49, 0x02, /* vact_st2 */
+               0x00, 0x00, /* vact_st3 */
+               0x00, 0x00, /* vact_st4 */
+               0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+               0x00, /* 3d FP */
+       },
+       .mbus_fmt = {
+               .width = 1920,
+               .height = 1080,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p59_94 = {
+       .core = {
+               .h_blank = {0x18, 0x01},
+               .v2_blank = {0x65, 0x04},
+               .v1_blank = {0x2d, 0x00},
+               .v_line = {0x65, 0x04},
+               .h_line = {0x98, 0x08},
+               .hsync_pol = {0x00},
+               .vsync_pol = {0x00},
+               .int_pro_mode = {0x00},
+               .v_blank_f0 = {0xff, 0xff},
+               .v_blank_f1 = {0xff, 0xff},
+               .h_sync_start = {0x56, 0x00},
+               .h_sync_end = {0x82, 0x00},
+               .v_sync_line_bef_2 = {0x09, 0x00},
+               .v_sync_line_bef_1 = {0x04, 0x00},
+               .v_sync_line_aft_2 = {0xff, 0xff},
+               .v_sync_line_aft_1 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+               .v_blank_f2 = {0xff, 0xff},
+               .v_blank_f3 = {0xff, 0xff},
+               .v_blank_f4 = {0xff, 0xff},
+               .v_blank_f5 = {0xff, 0xff},
+               .v_sync_line_aft_3 = {0xff, 0xff},
+               .v_sync_line_aft_4 = {0xff, 0xff},
+               .v_sync_line_aft_5 = {0xff, 0xff},
+               .v_sync_line_aft_6 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+               .vact_space_1 = {0xff, 0xff},
+               .vact_space_2 = {0xff, 0xff},
+               .vact_space_3 = {0xff, 0xff},
+               .vact_space_4 = {0xff, 0xff},
+               .vact_space_5 = {0xff, 0xff},
+               .vact_space_6 = {0xff, 0xff},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0x98, 0x08, /* h_fsz */
+               0x18, 0x01, 0x80, 0x07, /* hact */
+               0x65, 0x04, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x2d, 0x00, 0x38, 0x04, /* vact */
+               0x33, 0x02, /* field_chg */
+               0x48, 0x02, /* vact_st2 */
+               0x00, 0x00, /* vact_st3 */
+               0x00, 0x00, /* vact_st4 */
+               0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+               0x00, /* 3d FP */
+       },
+       .mbus_fmt = {
+               .width = 1920,
+               .height = 1080,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_720p60_sb_half = {
+       .core = {
+               .h_blank = {0x72, 0x01},
+               .v2_blank = {0xee, 0x02},
+               .v1_blank = {0x1e, 0x00},
+               .v_line = {0xee, 0x02},
+               .h_line = {0x72, 0x06},
+               .hsync_pol = {0x00},
+               .vsync_pol = {0x00},
+               .int_pro_mode = {0x00},
+               .v_blank_f0 = {0xff, 0xff},
+               .v_blank_f1 = {0xff, 0xff},
+               .h_sync_start = {0x6c, 0x00},
+               .h_sync_end = {0x94, 0x00},
+               .v_sync_line_bef_2 = {0x0a, 0x00},
+               .v_sync_line_bef_1 = {0x05, 0x00},
+               .v_sync_line_aft_2 = {0xff, 0xff},
+               .v_sync_line_aft_1 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+               .v_blank_f2 = {0xff, 0xff},
+               .v_blank_f3 = {0xff, 0xff},
+               .v_blank_f4 = {0xff, 0xff},
+               .v_blank_f5 = {0xff, 0xff},
+               .v_sync_line_aft_3 = {0xff, 0xff},
+               .v_sync_line_aft_4 = {0xff, 0xff},
+               .v_sync_line_aft_5 = {0xff, 0xff},
+               .v_sync_line_aft_6 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+               .vact_space_1 = {0xff, 0xff},
+               .vact_space_2 = {0xff, 0xff},
+               .vact_space_3 = {0xff, 0xff},
+               .vact_space_4 = {0xff, 0xff},
+               .vact_space_5 = {0xff, 0xff},
+               .vact_space_6 = {0xff, 0xff},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0x72, 0x06, /* h_fsz */
+               0x72, 0x01, 0x00, 0x05, /* hact */
+               0xee, 0x02, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x1e, 0x00, 0xd0, 0x02, /* vact */
+               0x33, 0x02, /* field_chg */
+               0x0c, 0x03, /* vact_st2 */
+               0x00, 0x00, /* vact_st3 */
+               0x00, 0x00, /* vact_st4 */
+               0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+               0x00, /* 3d FP */
+       },
+       .mbus_fmt = {
+               .width = 1280,
+               .height = 720,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_720p60_tb = {
+       .core = {
+               .h_blank = {0x72, 0x01},
+               .v2_blank = {0xee, 0x02},
+               .v1_blank = {0x1e, 0x00},
+               .v_line = {0xee, 0x02},
+               .h_line = {0x72, 0x06},
+               .hsync_pol = {0x00},
+               .vsync_pol = {0x00},
+               .int_pro_mode = {0x00},
+               .v_blank_f0 = {0xff, 0xff},
+               .v_blank_f1 = {0xff, 0xff},
+               .h_sync_start = {0x6c, 0x00},
+               .h_sync_end = {0x94, 0x00},
+               .v_sync_line_bef_2 = {0x0a, 0x00},
+               .v_sync_line_bef_1 = {0x05, 0x00},
+               .v_sync_line_aft_2 = {0xff, 0xff},
+               .v_sync_line_aft_1 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+               .v_blank_f2 = {0xff, 0xff},
+               .v_blank_f3 = {0xff, 0xff},
+               .v_blank_f4 = {0xff, 0xff},
+               .v_blank_f5 = {0xff, 0xff},
+               .v_sync_line_aft_3 = {0xff, 0xff},
+               .v_sync_line_aft_4 = {0xff, 0xff},
+               .v_sync_line_aft_5 = {0xff, 0xff},
+               .v_sync_line_aft_6 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+               .vact_space_1 = {0xff, 0xff},
+               .vact_space_2 = {0xff, 0xff},
+               .vact_space_3 = {0xff, 0xff},
+               .vact_space_4 = {0xff, 0xff},
+               .vact_space_5 = {0xff, 0xff},
+               .vact_space_6 = {0xff, 0xff},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0x72, 0x06, /* h_fsz */
+               0x72, 0x01, 0x00, 0x05, /* hact */
+               0xee, 0x02, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x1e, 0x00, 0xd0, 0x02, /* vact */
+               0x33, 0x02, /* field_chg */
+               0x0c, 0x03, /* vact_st2 */
+               0x00, 0x00, /* vact_st3 */
+               0x00, 0x00, /* vact_st4 */
+               0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+               0x00, /* 3d FP */
+       },
+       .mbus_fmt = {
+               .width = 1280,
+               .height = 720,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_720p59_94_sb_half = {
+       .core = {
+               .h_blank = {0x72, 0x01},
+               .v2_blank = {0xee, 0x02},
+               .v1_blank = {0x1e, 0x00},
+               .v_line = {0xee, 0x02},
+               .h_line = {0x72, 0x06},
+               .hsync_pol = {0x00},
+               .vsync_pol = {0x00},
+               .int_pro_mode = {0x00},
+               .v_blank_f0 = {0xff, 0xff},
+               .v_blank_f1 = {0xff, 0xff},
+               .h_sync_start = {0x6c, 0x00},
+               .h_sync_end = {0x94, 0x00},
+               .v_sync_line_bef_2 = {0x0a, 0x00},
+               .v_sync_line_bef_1 = {0x05, 0x00},
+               .v_sync_line_aft_2 = {0xff, 0xff},
+               .v_sync_line_aft_1 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+               .v_blank_f2 = {0xff, 0xff},
+               .v_blank_f3 = {0xff, 0xff},
+               .v_blank_f4 = {0xff, 0xff},
+               .v_blank_f5 = {0xff, 0xff},
+               .v_sync_line_aft_3 = {0xff, 0xff},
+               .v_sync_line_aft_4 = {0xff, 0xff},
+               .v_sync_line_aft_5 = {0xff, 0xff},
+               .v_sync_line_aft_6 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+               .vact_space_1 = {0xff, 0xff},
+               .vact_space_2 = {0xff, 0xff},
+               .vact_space_3 = {0xff, 0xff},
+               .vact_space_4 = {0xff, 0xff},
+               .vact_space_5 = {0xff, 0xff},
+               .vact_space_6 = {0xff, 0xff},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0x72, 0x06, /* h_fsz */
+               0x72, 0x01, 0x00, 0x05, /* hact */
+               0xee, 0x02, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x1e, 0x00, 0xd0, 0x02, /* vact */
+               0x00, 0x00, /* field_chg */
+               0x0c, 0x03, /* vact_st2 */
+               0x00, 0x00, /* vact_st3 */
+               0x00, 0x00, /* vact_st4 */
+               0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+               0x00, /* 3d FP */
+       },
+       .mbus_fmt = {
+               .width = 1280,
+               .height = 720,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_720p59_94_tb = {
+       .core = {
+               .h_blank = {0x72, 0x01},
+               .v2_blank = {0xee, 0x02},
+               .v1_blank = {0x1e, 0x00},
+               .v_line = {0xee, 0x02},
+               .h_line = {0x72, 0x06},
+               .hsync_pol = {0x00},
+               .vsync_pol = {0x00},
+               .int_pro_mode = {0x00},
+               .v_blank_f0 = {0xff, 0xff},
+               .v_blank_f1 = {0xff, 0xff},
+               .h_sync_start = {0x6c, 0x00},
+               .h_sync_end = {0x94, 0x00},
+               .v_sync_line_bef_2 = {0x0a, 0x00},
+               .v_sync_line_bef_1 = {0x05, 0x00},
+               .v_sync_line_aft_2 = {0xff, 0xff},
+               .v_sync_line_aft_1 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+               .v_blank_f2 = {0xff, 0xff},
+               .v_blank_f3 = {0xff, 0xff},
+               .v_blank_f4 = {0xff, 0xff},
+               .v_blank_f5 = {0xff, 0xff},
+               .v_sync_line_aft_3 = {0xff, 0xff},
+               .v_sync_line_aft_4 = {0xff, 0xff},
+               .v_sync_line_aft_5 = {0xff, 0xff},
+               .v_sync_line_aft_6 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+               .vact_space_1 = {0xff, 0xff},
+               .vact_space_2 = {0xff, 0xff},
+               .vact_space_3 = {0xff, 0xff},
+               .vact_space_4 = {0xff, 0xff},
+               .vact_space_5 = {0xff, 0xff},
+               .vact_space_6 = {0xff, 0xff},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0x72, 0x06, /* h_fsz */
+               0x72, 0x01, 0x00, 0x05, /* hact */
+               0xee, 0x02, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x1e, 0x00, 0xd0, 0x02, /* vact */
+               0x00, 0x00, /* field_chg */
+               0x0c, 0x03, /* vact_st2 */
+               0x00, 0x00, /* vact_st3 */
+               0x00, 0x00, /* vact_st4 */
+               0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+               0x00, /* 3d FP */
+       },
+       .mbus_fmt = {
+               .width = 1280,
+               .height = 720,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_720p50_sb_half = {
+       .core = {
+               .h_blank = {0xbc, 0x02},
+               .v2_blank = {0xdc, 0x05},
+               .v1_blank = {0x1e, 0x00},
+               .v_line = {0xdc, 0x05},
+               .h_line = {0xbc, 0x07},
+               .hsync_pol = {0x00},
+               .vsync_pol = {0x00},
+               .int_pro_mode = {0x00},
+               .v_blank_f0 = {0xff, 0xff},
+               .v_blank_f1 = {0xff, 0xff},
+               .h_sync_start = {0xb6, 0x01},
+               .h_sync_end = {0xde, 0x01},
+               .v_sync_line_bef_2 = {0x0a, 0x00},
+               .v_sync_line_bef_1 = {0x05, 0x00},
+               .v_sync_line_aft_2 = {0xff, 0xff},
+               .v_sync_line_aft_1 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+               .v_blank_f2 = {0xff, 0xff},
+               .v_blank_f3 = {0xff, 0xff},
+               .v_blank_f4 = {0xff, 0xff},
+               .v_blank_f5 = {0xff, 0xff},
+               .v_sync_line_aft_3 = {0xff, 0xff},
+               .v_sync_line_aft_4 = {0xff, 0xff},
+               .v_sync_line_aft_5 = {0xff, 0xff},
+               .v_sync_line_aft_6 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+               .vact_space_1 = {0xee, 0x02},
+               .vact_space_2 = {0x0c, 0x03},
+               .vact_space_3 = {0xff, 0xff},
+               .vact_space_4 = {0xff, 0xff},
+               .vact_space_5 = {0xff, 0xff},
+               .vact_space_6 = {0xff, 0xff},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0xbc, 0x07, /* h_fsz */
+               0xbc, 0x02, 0x00, 0x05, /* hact */
+               0xee, 0x02, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x1e, 0x00, 0xd0, 0x02, /* vact */
+               0x00, 0x00, /* field_chg */
+               0x0c, 0x03, /* vact_st2 */
+               0x00, 0x00, /* vact_st3 */
+               0x00, 0x00, /* vact_st4 */
+               0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+               0x00, /* 3d FP */
+       },
+       .mbus_fmt = {
+               .width = 1280,
+               .height = 720,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_720p50_tb = {
+       .core = {
+               .h_blank = {0xbc, 0x02},
+               .v2_blank = {0xdc, 0x05},
+               .v1_blank = {0x1e, 0x00},
+               .v_line = {0xdc, 0x05},
+               .h_line = {0xbc, 0x07},
+               .hsync_pol = {0x00},
+               .vsync_pol = {0x00},
+               .int_pro_mode = {0x00},
+               .v_blank_f0 = {0xff, 0xff},
+               .v_blank_f1 = {0xff, 0xff},
+               .h_sync_start = {0xb6, 0x01},
+               .h_sync_end = {0xde, 0x01},
+               .v_sync_line_bef_2 = {0x0a, 0x00},
+               .v_sync_line_bef_1 = {0x05, 0x00},
+               .v_sync_line_aft_2 = {0xff, 0xff},
+               .v_sync_line_aft_1 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+               .v_blank_f2 = {0xff, 0xff},
+               .v_blank_f3 = {0xff, 0xff},
+               .v_blank_f4 = {0xff, 0xff},
+               .v_blank_f5 = {0xff, 0xff},
+               .v_sync_line_aft_3 = {0xff, 0xff},
+               .v_sync_line_aft_4 = {0xff, 0xff},
+               .v_sync_line_aft_5 = {0xff, 0xff},
+               .v_sync_line_aft_6 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+               .vact_space_1 = {0xee, 0x02},
+               .vact_space_2 = {0x0c, 0x03},
+               .vact_space_3 = {0xff, 0xff},
+               .vact_space_4 = {0xff, 0xff},
+               .vact_space_5 = {0xff, 0xff},
+               .vact_space_6 = {0xff, 0xff},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0xbc, 0x07, /* h_fsz */
+               0xbc, 0x02, 0x00, 0x05, /* hact */
+               0xee, 0x02, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x1e, 0x00, 0xd0, 0x02, /* vact */
+               0x00, 0x00, /* field_chg */
+               0x0c, 0x03, /* vact_st2 */
+               0x00, 0x00, /* vact_st3 */
+               0x00, 0x00, /* vact_st4 */
+               0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+               0x00, /* 3d FP */
+       },
+       .mbus_fmt = {
+               .width = 1280,
+               .height = 720,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p24_fp = {
+       .core = {
+               .h_blank = {0x3e, 0x03},
+               .v2_blank = {0xca, 0x08},
+               .v1_blank = {0x2d, 0x00},
+               .v_line = {0xca, 0x08},
+               .h_line = {0xbe, 0x0a},
+               .hsync_pol = {0x00},
+               .vsync_pol = {0x00},
+               .int_pro_mode = {0x00},
+               .v_blank_f0 = {0xff, 0xff},
+               .v_blank_f1 = {0xff, 0xff},
+               .h_sync_start = {0x7c, 0x02},
+               .h_sync_end = {0xa8, 0x02},
+               .v_sync_line_bef_2 = {0x09, 0x00},
+               .v_sync_line_bef_1 = {0x04, 0x00},
+               .v_sync_line_aft_2 = {0xff, 0xff},
+               .v_sync_line_aft_1 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+               .v_blank_f2 = {0xff, 0xff},
+               .v_blank_f3 = {0xff, 0xff},
+               .v_blank_f4 = {0xff, 0xff},
+               .v_blank_f5 = {0xff, 0xff},
+               .v_sync_line_aft_3 = {0xff, 0xff},
+               .v_sync_line_aft_4 = {0xff, 0xff},
+               .v_sync_line_aft_5 = {0xff, 0xff},
+               .v_sync_line_aft_6 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+               .vact_space_1 = {0x65, 0x04},
+               .vact_space_2 = {0x92, 0x04},
+               .vact_space_3 = {0xff, 0xff},
+               .vact_space_4 = {0xff, 0xff},
+               .vact_space_5 = {0xff, 0xff},
+               .vact_space_6 = {0xff, 0xff},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0xbe, 0x0a, /* h_fsz */
+               0x3e, 0x03, 0x80, 0x07, /* hact */
+               0xca, 0x08, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x2d, 0x00, 0x38, 0x04, /* vact */
+               0x33, 0x02, /* field_chg */
+               0x92, 0x04, /* vact_st2 */
+               0x00, 0x00, /* vact_st3 */
+               0x00, 0x00, /* vact_st4 */
+               0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+               0x01, /* 3d FP */
+       },
+       .mbus_fmt = {
+               .width = 1920,
+               .height = 1080,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p24_sb_half = {
+       .core = {
+               .h_blank = {0x3e, 0x03},
+               .v2_blank = {0x65, 0x04},
+               .v1_blank = {0x2d, 0x00},
+               .v_line = {0x65, 0x04},
+               .h_line = {0xbe, 0x0a},
+               .hsync_pol = {0x00},
+               .vsync_pol = {0x00},
+               .int_pro_mode = {0x00},
+               .v_blank_f0 = {0xff, 0xff},
+               .v_blank_f1 = {0xff, 0xff},
+               .h_sync_start = {0x7c, 0x02},
+               .h_sync_end = {0xa8, 0x02},
+               .v_sync_line_bef_2 = {0x09, 0x00},
+               .v_sync_line_bef_1 = {0x04, 0x00},
+               .v_sync_line_aft_2 = {0xff, 0xff},
+               .v_sync_line_aft_1 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+               .v_blank_f2 = {0xff, 0xff},
+               .v_blank_f3 = {0xff, 0xff},
+               .v_blank_f4 = {0xff, 0xff},
+               .v_blank_f5 = {0xff, 0xff},
+               .v_sync_line_aft_3 = {0xff, 0xff},
+               .v_sync_line_aft_4 = {0xff, 0xff},
+               .v_sync_line_aft_5 = {0xff, 0xff},
+               .v_sync_line_aft_6 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+               .vact_space_1 = {0xff, 0xff},
+               .vact_space_2 = {0xff, 0xff},
+               .vact_space_3 = {0xff, 0xff},
+               .vact_space_4 = {0xff, 0xff},
+               .vact_space_5 = {0xff, 0xff},
+               .vact_space_6 = {0xff, 0xff},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0xbe, 0x0a, /* h_fsz */
+               0x3e, 0x03, 0x80, 0x07, /* hact */
+               0x65, 0x04, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x2d, 0x00, 0x38, 0x04, /* vact */
+               0x33, 0x02, /* field_chg */
+               0x48, 0x02, /* vact_st2 */
+               0x00, 0x00, /* vact_st3 */
+               0x00, 0x00, /* vact_st4 */
+               0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+               0x00, /* 3d FP */
+       },
+       .mbus_fmt = {
+               .width = 1920,
+               .height = 1080,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p24_tb = {
+       .core = {
+               .h_blank = {0x3e, 0x03},
+               .v2_blank = {0x65, 0x04},
+               .v1_blank = {0x2d, 0x00},
+               .v_line = {0x65, 0x04},
+               .h_line = {0xbe, 0x0a},
+               .hsync_pol = {0x00},
+               .vsync_pol = {0x00},
+               .int_pro_mode = {0x00},
+               .v_blank_f0 = {0xff, 0xff},
+               .v_blank_f1 = {0xff, 0xff},
+               .h_sync_start = {0x7c, 0x02},
+               .h_sync_end = {0xa8, 0x02},
+               .v_sync_line_bef_2 = {0x09, 0x00},
+               .v_sync_line_bef_1 = {0x04, 0x00},
+               .v_sync_line_aft_2 = {0xff, 0xff},
+               .v_sync_line_aft_1 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+               .v_blank_f2 = {0xff, 0xff},
+               .v_blank_f3 = {0xff, 0xff},
+               .v_blank_f4 = {0xff, 0xff},
+               .v_blank_f5 = {0xff, 0xff},
+               .v_sync_line_aft_3 = {0xff, 0xff},
+               .v_sync_line_aft_4 = {0xff, 0xff},
+               .v_sync_line_aft_5 = {0xff, 0xff},
+               .v_sync_line_aft_6 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+               .vact_space_1 = {0xff, 0xff},
+               .vact_space_2 = {0xff, 0xff},
+               .vact_space_3 = {0xff, 0xff},
+               .vact_space_4 = {0xff, 0xff},
+               .vact_space_5 = {0xff, 0xff},
+               .vact_space_6 = {0xff, 0xff},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0xbe, 0x0a, /* h_fsz */
+               0x3e, 0x03, 0x80, 0x07, /* hact */
+               0x65, 0x04, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x2d, 0x00, 0x38, 0x04, /* vact */
+               0x33, 0x02, /* field_chg */
+               0x48, 0x02, /* vact_st2 */
+               0x00, 0x00, /* vact_st3 */
+               0x00, 0x00, /* vact_st4 */
+               0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+               0x00, /* 3d FP */
+       },
+       .mbus_fmt = {
+               .width = 1920,
+               .height = 1080,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p23_98_fp = {
+       .core = {
+               .h_blank = {0x3e, 0x03},
+               .v2_blank = {0xca, 0x08},
+               .v1_blank = {0x2d, 0x00},
+               .v_line = {0xca, 0x08},
+               .h_line = {0xbe, 0x0a},
+               .hsync_pol = {0x00},
+               .vsync_pol = {0x00},
+               .int_pro_mode = {0x00},
+               .v_blank_f0 = {0xff, 0xff},
+               .v_blank_f1 = {0xff, 0xff},
+               .h_sync_start = {0x7c, 0x02},
+               .h_sync_end = {0xa8, 0x02},
+               .v_sync_line_bef_2 = {0x09, 0x00},
+               .v_sync_line_bef_1 = {0x04, 0x00},
+               .v_sync_line_aft_2 = {0xff, 0xff},
+               .v_sync_line_aft_1 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+               .v_blank_f2 = {0xff, 0xff},
+               .v_blank_f3 = {0xff, 0xff},
+               .v_blank_f4 = {0xff, 0xff},
+               .v_blank_f5 = {0xff, 0xff},
+               .v_sync_line_aft_3 = {0xff, 0xff},
+               .v_sync_line_aft_4 = {0xff, 0xff},
+               .v_sync_line_aft_5 = {0xff, 0xff},
+               .v_sync_line_aft_6 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+               .vact_space_1 = {0x65, 0x04},
+               .vact_space_2 = {0x92, 0x04},
+               .vact_space_3 = {0xff, 0xff},
+               .vact_space_4 = {0xff, 0xff},
+               .vact_space_5 = {0xff, 0xff},
+               .vact_space_6 = {0xff, 0xff},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0xbe, 0x0a, /* h_fsz */
+               0x3e, 0x03, 0x80, 0x07, /* hact */
+               0xca, 0x08, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x2d, 0x00, 0x38, 0x04, /* vact */
+               0x33, 0x02, /* field_chg */
+               0x92, 0x04, /* vact_st2 */
+               0x00, 0x00, /* vact_st3 */
+               0x00, 0x00, /* vact_st4 */
+               0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+               0x01, /* 3d FP */
+       },
+       .mbus_fmt = {
+               .width = 1920,
+               .height = 1080,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p23_98_sb_half = {
+       .core = {
+               .h_blank = {0x3e, 0x03},
+               .v2_blank = {0x65, 0x04},
+               .v1_blank = {0x2d, 0x00},
+               .v_line = {0x65, 0x04},
+               .h_line = {0xbe, 0x0a},
+               .hsync_pol = {0x00},
+               .vsync_pol = {0x00},
+               .int_pro_mode = {0x00},
+               .v_blank_f0 = {0xff, 0xff},
+               .v_blank_f1 = {0xff, 0xff},
+               .h_sync_start = {0x7c, 0x02},
+               .h_sync_end = {0xa8, 0x02},
+               .v_sync_line_bef_2 = {0x09, 0x00},
+               .v_sync_line_bef_1 = {0x04, 0x00},
+               .v_sync_line_aft_2 = {0xff, 0xff},
+               .v_sync_line_aft_1 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+               .v_blank_f2 = {0xff, 0xff},
+               .v_blank_f3 = {0xff, 0xff},
+               .v_blank_f4 = {0xff, 0xff},
+               .v_blank_f5 = {0xff, 0xff},
+               .v_sync_line_aft_3 = {0xff, 0xff},
+               .v_sync_line_aft_4 = {0xff, 0xff},
+               .v_sync_line_aft_5 = {0xff, 0xff},
+               .v_sync_line_aft_6 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+               .vact_space_1 = {0xff, 0xff},
+               .vact_space_2 = {0xff, 0xff},
+               .vact_space_3 = {0xff, 0xff},
+               .vact_space_4 = {0xff, 0xff},
+               .vact_space_5 = {0xff, 0xff},
+               .vact_space_6 = {0xff, 0xff},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0xbe, 0x0a, /* h_fsz */
+               0x3e, 0x03, 0x80, 0x07, /* hact */
+               0x65, 0x04, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x2d, 0x00, 0x38, 0x04, /* vact */
+               0x33, 0x02, /* field_chg */
+               0x48, 0x02, /* vact_st2 */
+               0x00, 0x00, /* vact_st3 */
+               0x00, 0x00, /* vact_st4 */
+               0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+               0x00, /* 3d FP */
+       },
+       .mbus_fmt = {
+               .width = 1920,
+               .height = 1080,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p23_98_tb = {
+       .core = {
+               .h_blank = {0x3e, 0x03},
+               .v2_blank = {0x65, 0x04},
+               .v1_blank = {0x2d, 0x00},
+               .v_line = {0x65, 0x04},
+               .h_line = {0xbe, 0x0a},
+               .hsync_pol = {0x00},
+               .vsync_pol = {0x00},
+               .int_pro_mode = {0x00},
+               .v_blank_f0 = {0xff, 0xff},
+               .v_blank_f1 = {0xff, 0xff},
+               .h_sync_start = {0x7c, 0x02},
+               .h_sync_end = {0xa8, 0x02},
+               .v_sync_line_bef_2 = {0x09, 0x00},
+               .v_sync_line_bef_1 = {0x04, 0x00},
+               .v_sync_line_aft_2 = {0xff, 0xff},
+               .v_sync_line_aft_1 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+               .v_blank_f2 = {0xff, 0xff},
+               .v_blank_f3 = {0xff, 0xff},
+               .v_blank_f4 = {0xff, 0xff},
+               .v_blank_f5 = {0xff, 0xff},
+               .v_sync_line_aft_3 = {0xff, 0xff},
+               .v_sync_line_aft_4 = {0xff, 0xff},
+               .v_sync_line_aft_5 = {0xff, 0xff},
+               .v_sync_line_aft_6 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+               .vact_space_1 = {0xff, 0xff},
+               .vact_space_2 = {0xff, 0xff},
+               .vact_space_3 = {0xff, 0xff},
+               .vact_space_4 = {0xff, 0xff},
+               .vact_space_5 = {0xff, 0xff},
+               .vact_space_6 = {0xff, 0xff},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0xbe, 0x0a, /* h_fsz */
+               0x3e, 0x03, 0x80, 0x07, /* hact */
+               0x65, 0x04, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x2d, 0x00, 0x38, 0x04, /* vact */
+               0x33, 0x02, /* field_chg */
+               0x48, 0x02, /* vact_st2 */
+               0x00, 0x00, /* vact_st3 */
+               0x00, 0x00, /* vact_st4 */
+               0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+               0x00, /* 3d FP */
+       },
+       .mbus_fmt = {
+               .width = 1920,
+               .height = 1080,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080i60_sb_half = {
+       .core = {
+               .h_blank = {0x18, 0x01},
+               .v2_blank = {0x32, 0x02},
+               .v1_blank = {0x16, 0x00},
+               .v_line = {0x65, 0x04},
+               .h_line = {0x98, 0x08},
+               .hsync_pol = {0x00},
+               .vsync_pol = {0x00},
+               .int_pro_mode = {0x01},
+               .v_blank_f0 = {0x49, 0x02},
+               .v_blank_f1 = {0x65, 0x04},
+               .h_sync_start = {0x56, 0x00},
+               .h_sync_end = {0x82, 0x00},
+               .v_sync_line_bef_2 = {0x07, 0x00},
+               .v_sync_line_bef_1 = {0x02, 0x00},
+               .v_sync_line_aft_2 = {0x39, 0x02},
+               .v_sync_line_aft_1 = {0x34, 0x02},
+               .v_sync_line_aft_pxl_2 = {0xa4, 0x04},
+               .v_sync_line_aft_pxl_1 = {0xa4, 0x04},
+               .v_blank_f2 = {0xff, 0xff},
+               .v_blank_f3 = {0xff, 0xff},
+               .v_blank_f4 = {0xff, 0xff},
+               .v_blank_f5 = {0xff, 0xff},
+               .v_sync_line_aft_3 = {0xff, 0xff},
+               .v_sync_line_aft_4 = {0xff, 0xff},
+               .v_sync_line_aft_5 = {0xff, 0xff},
+               .v_sync_line_aft_6 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+               .vact_space_1 = {0xff, 0xff},
+               .vact_space_2 = {0xff, 0xff},
+               .vact_space_3 = {0xff, 0xff},
+               .vact_space_4 = {0xff, 0xff},
+               .vact_space_5 = {0xff, 0xff},
+               .vact_space_6 = {0xff, 0xff},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0x98, 0x08, /* h_fsz */
+               0x18, 0x01, 0x80, 0x07, /* hact */
+               0x64, 0x04, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x16, 0x00, 0x1c, 0x02, /* vact */
+               0x65, 0x04, /* field_chg */
+               0x49, 0x02, /* vact_st2 */
+               0x7b, 0x04, /* vact_st3 */
+               0xae, 0x06, /* vact_st4 */
+               0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+               0x00, /* 3d FP */
+       },
+       .mbus_fmt = {
+               .width = 1920,
+               .height = 1080,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080i59_94_sb_half = {
+       .core = {
+               .h_blank = {0x18, 0x01},
+               .v2_blank = {0x32, 0x02},
+               .v1_blank = {0x16, 0x00},
+               .v_line = {0x65, 0x04},
+               .h_line = {0x98, 0x08},
+               .hsync_pol = {0x00},
+               .vsync_pol = {0x00},
+               .int_pro_mode = {0x01},
+               .v_blank_f0 = {0x49, 0x02},
+               .v_blank_f1 = {0x65, 0x04},
+               .h_sync_start = {0x56, 0x00},
+               .h_sync_end = {0x82, 0x00},
+               .v_sync_line_bef_2 = {0x07, 0x00},
+               .v_sync_line_bef_1 = {0x02, 0x00},
+               .v_sync_line_aft_2 = {0x39, 0x02},
+               .v_sync_line_aft_1 = {0x34, 0x02},
+               .v_sync_line_aft_pxl_2 = {0xa4, 0x04},
+               .v_sync_line_aft_pxl_1 = {0xa4, 0x04},
+               .v_blank_f2 = {0xff, 0xff},
+               .v_blank_f3 = {0xff, 0xff},
+               .v_blank_f4 = {0xff, 0xff},
+               .v_blank_f5 = {0xff, 0xff},
+               .v_sync_line_aft_3 = {0xff, 0xff},
+               .v_sync_line_aft_4 = {0xff, 0xff},
+               .v_sync_line_aft_5 = {0xff, 0xff},
+               .v_sync_line_aft_6 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+               .vact_space_1 = {0xff, 0xff},
+               .vact_space_2 = {0xff, 0xff},
+               .vact_space_3 = {0xff, 0xff},
+               .vact_space_4 = {0xff, 0xff},
+               .vact_space_5 = {0xff, 0xff},
+               .vact_space_6 = {0xff, 0xff},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0x98, 0x08, /* h_fsz */
+               0x18, 0x01, 0x80, 0x07, /* hact */
+               0x64, 0x04, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x16, 0x00, 0x1c, 0x02, /* vact */
+               0x65, 0x04, /* field_chg */
+               0x49, 0x02, /* vact_st2 */
+               0x7b, 0x04, /* vact_st3 */
+               0xae, 0x06, /* vact_st4 */
+               0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+               0x00, /* 3d FP */
+       },
+       .mbus_fmt = {
+               .width = 1920,
+               .height = 1080,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080i50_sb_half = {
+       .core = {
+               .h_blank = {0xd0, 0x02},
+               .v2_blank = {0x32, 0x02},
+               .v1_blank = {0x16, 0x00},
+               .v_line = {0x65, 0x04},
+               .h_line = {0x50, 0x0a},
+               .hsync_pol = {0x00},
+               .vsync_pol = {0x00},
+               .int_pro_mode = {0x01},
+               .v_blank_f0 = {0x49, 0x02},
+               .v_blank_f1 = {0x65, 0x04},
+               .h_sync_start = {0x0e, 0x02},
+               .h_sync_end = {0x3a, 0x02},
+               .v_sync_line_bef_2 = {0x07, 0x00},
+               .v_sync_line_bef_1 = {0x02, 0x00},
+               .v_sync_line_aft_2 = {0x39, 0x02},
+               .v_sync_line_aft_1 = {0x34, 0x02},
+               .v_sync_line_aft_pxl_2 = {0x38, 0x07},
+               .v_sync_line_aft_pxl_1 = {0x38, 0x07},
+               .v_blank_f2 = {0xff, 0xff},
+               .v_blank_f3 = {0xff, 0xff},
+               .v_blank_f4 = {0xff, 0xff},
+               .v_blank_f5 = {0xff, 0xff},
+               .v_sync_line_aft_3 = {0xff, 0xff},
+               .v_sync_line_aft_4 = {0xff, 0xff},
+               .v_sync_line_aft_5 = {0xff, 0xff},
+               .v_sync_line_aft_6 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+               .vact_space_1 = {0xff, 0xff},
+               .vact_space_2 = {0xff, 0xff},
+               .vact_space_3 = {0xff, 0xff},
+               .vact_space_4 = {0xff, 0xff},
+               .vact_space_5 = {0xff, 0xff},
+               .vact_space_6 = {0xff, 0xff},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0x50, 0x0a, /* h_fsz */
+               0xd0, 0x02, 0x80, 0x07, /* hact */
+               0x64, 0x04, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x16, 0x00, 0x1c, 0x02, /* vact */
+               0x65, 0x04, /* field_chg */
+               0x49, 0x02, /* vact_st2 */
+               0x7b, 0x04, /* vact_st3 */
+               0xae, 0x06, /* vact_st4 */
+               0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+               0x00, /* 3d FP */
+       },
+       .mbus_fmt = {
+               .width = 1920,
+               .height = 1080,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p60_sb_half = {
+       .core = {
+               .h_blank = {0x18, 0x01},
+               .v2_blank = {0x65, 0x04},
+               .v1_blank = {0x2d, 0x00},
+               .v_line = {0x65, 0x04},
+               .h_line = {0x98, 0x08},
+               .hsync_pol = {0x00},
+               .vsync_pol = {0x00},
+               .int_pro_mode = {0x00},
+               .v_blank_f0 = {0xff, 0xff},
+               .v_blank_f1 = {0xff, 0xff},
+               .h_sync_start = {0x56, 0x00},
+               .h_sync_end = {0x82, 0x00},
+               .v_sync_line_bef_2 = {0x09, 0x00},
+               .v_sync_line_bef_1 = {0x04, 0x00},
+               .v_sync_line_aft_2 = {0xff, 0xff},
+               .v_sync_line_aft_1 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+               .v_blank_f2 = {0xff, 0xff},
+               .v_blank_f3 = {0xff, 0xff},
+               .v_blank_f4 = {0xff, 0xff},
+               .v_blank_f5 = {0xff, 0xff},
+               .v_sync_line_aft_3 = {0xff, 0xff},
+               .v_sync_line_aft_4 = {0xff, 0xff},
+               .v_sync_line_aft_5 = {0xff, 0xff},
+               .v_sync_line_aft_6 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+               .vact_space_1 = {0xff, 0xff},
+               .vact_space_2 = {0xff, 0xff},
+               .vact_space_3 = {0xff, 0xff},
+               .vact_space_4 = {0xff, 0xff},
+               .vact_space_5 = {0xff, 0xff},
+               .vact_space_6 = {0xff, 0xff},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0x98, 0x08, /* h_fsz */
+               0x18, 0x01, 0x80, 0x07, /* hact */
+               0x65, 0x04, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x2d, 0x00, 0x38, 0x04, /* vact */
+               0x33, 0x02, /* field_chg */
+               0x48, 0x02, /* vact_st2 */
+               0x00, 0x00, /* vact_st3 */
+               0x00, 0x00, /* vact_st4 */
+               0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+               0x00, /* 3d FP */
+       },
+       .mbus_fmt = {
+               .width = 1920,
+               .height = 1080,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p60_tb = {
+       .core = {
+               .h_blank = {0x18, 0x01},
+               .v2_blank = {0x65, 0x04},
+               .v1_blank = {0x2d, 0x00},
+               .v_line = {0x65, 0x04},
+               .h_line = {0x98, 0x08},
+               .hsync_pol = {0x00},
+               .vsync_pol = {0x00},
+               .int_pro_mode = {0x00},
+               .v_blank_f0 = {0xff, 0xff},
+               .v_blank_f1 = {0xff, 0xff},
+               .h_sync_start = {0x56, 0x00},
+               .h_sync_end = {0x82, 0x00},
+               .v_sync_line_bef_2 = {0x09, 0x00},
+               .v_sync_line_bef_1 = {0x04, 0x00},
+               .v_sync_line_aft_2 = {0xff, 0xff},
+               .v_sync_line_aft_1 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+               .v_blank_f2 = {0xff, 0xff},
+               .v_blank_f3 = {0xff, 0xff},
+               .v_blank_f4 = {0xff, 0xff},
+               .v_blank_f5 = {0xff, 0xff},
+               .v_sync_line_aft_3 = {0xff, 0xff},
+               .v_sync_line_aft_4 = {0xff, 0xff},
+               .v_sync_line_aft_5 = {0xff, 0xff},
+               .v_sync_line_aft_6 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+               .vact_space_1 = {0xff, 0xff},
+               .vact_space_2 = {0xff, 0xff},
+               .vact_space_3 = {0xff, 0xff},
+               .vact_space_4 = {0xff, 0xff},
+               .vact_space_5 = {0xff, 0xff},
+               .vact_space_6 = {0xff, 0xff},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0x98, 0x08, /* h_fsz */
+               0x18, 0x01, 0x80, 0x07, /* hact */
+               0x65, 0x04, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x2d, 0x00, 0x38, 0x04, /* vact */
+               0x33, 0x02, /* field_chg */
+               0x48, 0x02, /* vact_st2 */
+               0x00, 0x00, /* vact_st3 */
+               0x00, 0x00, /* vact_st4 */
+               0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+               0x00, /* 3d FP */
+       },
+       .mbus_fmt = {
+               .width = 1920,
+               .height = 1080,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p30_sb_half = {
+       .core = {
+               .h_blank = {0x18, 0x01},
+               .v2_blank = {0x65, 0x04},
+               .v1_blank = {0x2d, 0x00},
+               .v_line = {0x65, 0x04},
+               .h_line = {0x98, 0x08},
+               .hsync_pol = {0x00},
+               .vsync_pol = {0x00},
+               .int_pro_mode = {0x00},
+               .v_blank_f0 = {0xff, 0xff},
+               .v_blank_f1 = {0xff, 0xff},
+               .h_sync_start = {0x56, 0x00},
+               .h_sync_end = {0x82, 0x00},
+               .v_sync_line_bef_2 = {0x09, 0x00},
+               .v_sync_line_bef_1 = {0x04, 0x00},
+               .v_sync_line_aft_2 = {0xff, 0xff},
+               .v_sync_line_aft_1 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+               .v_blank_f2 = {0xff, 0xff},
+               .v_blank_f3 = {0xff, 0xff},
+               .v_blank_f4 = {0xff, 0xff},
+               .v_blank_f5 = {0xff, 0xff},
+               .v_sync_line_aft_3 = {0xff, 0xff},
+               .v_sync_line_aft_4 = {0xff, 0xff},
+               .v_sync_line_aft_5 = {0xff, 0xff},
+               .v_sync_line_aft_6 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+               .vact_space_1 = {0xff, 0xff},
+               .vact_space_2 = {0xff, 0xff},
+               .vact_space_3 = {0xff, 0xff},
+               .vact_space_4 = {0xff, 0xff},
+               .vact_space_5 = {0xff, 0xff},
+               .vact_space_6 = {0xff, 0xff},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0x98, 0x08, /* h_fsz */
+               0x18, 0x01, 0x80, 0x07, /* hact */
+               0x65, 0x04, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x2d, 0x00, 0x38, 0x04, /* vact */
+               0x33, 0x02, /* field_chg */
+               0x48, 0x02, /* vact_st2 */
+               0x00, 0x00, /* vact_st3 */
+               0x00, 0x00, /* vact_st4 */
+               0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+               0x00, /* 3d FP */
+       },
+       .mbus_fmt = {
+               .width = 1920,
+               .height = 1080,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p30_tb = {
+       .core = {
+               .h_blank = {0x18, 0x01},
+               .v2_blank = {0x65, 0x04},
+               .v1_blank = {0x2d, 0x00},
+               .v_line = {0x65, 0x04},
+               .h_line = {0x98, 0x08},
+               .hsync_pol = {0x00},
+               .vsync_pol = {0x00},
+               .int_pro_mode = {0x00},
+               .v_blank_f0 = {0xff, 0xff},
+               .v_blank_f1 = {0xff, 0xff},
+               .h_sync_start = {0x56, 0x00},
+               .h_sync_end = {0x82, 0x00},
+               .v_sync_line_bef_2 = {0x09, 0x00},
+               .v_sync_line_bef_1 = {0x04, 0x00},
+               .v_sync_line_aft_2 = {0xff, 0xff},
+               .v_sync_line_aft_1 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+               .v_blank_f2 = {0xff, 0xff},
+               .v_blank_f3 = {0xff, 0xff},
+               .v_blank_f4 = {0xff, 0xff},
+               .v_blank_f5 = {0xff, 0xff},
+               .v_sync_line_aft_3 = {0xff, 0xff},
+               .v_sync_line_aft_4 = {0xff, 0xff},
+               .v_sync_line_aft_5 = {0xff, 0xff},
+               .v_sync_line_aft_6 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+               .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+               .vact_space_1 = {0xff, 0xff},
+               .vact_space_2 = {0xff, 0xff},
+               .vact_space_3 = {0xff, 0xff},
+               .vact_space_4 = {0xff, 0xff},
+               .vact_space_5 = {0xff, 0xff},
+               .vact_space_6 = {0xff, 0xff},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0x98, 0x08, /* h_fsz */
+               0x18, 0x01, 0x80, 0x07, /* hact */
+               0x65, 0x04, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x2d, 0x00, 0x38, 0x04, /* vact */
+               0x33, 0x02, /* field_chg */
+               0x48, 0x02, /* vact_st2 */
+               0x00, 0x00, /* vact_st3 */
+               0x00, 0x00, /* vact_st4 */
+               0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+               0x00, /* 3d FP */
+       },
+       .mbus_fmt = {
+               .width = 1920,
+               .height = 1080,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct hdmi_3d_info info_2d = {
+       .is_3d = HDMI_VIDEO_FORMAT_2D,
+};
+
+static const struct hdmi_3d_info info_3d_sb_h = {
+       .is_3d = HDMI_VIDEO_FORMAT_3D,
+       .fmt_3d = HDMI_3D_FORMAT_SB_HALF,
+};
+
+static const struct hdmi_3d_info info_3d_tb = {
+       .is_3d = HDMI_VIDEO_FORMAT_3D,
+       .fmt_3d = HDMI_3D_FORMAT_TB,
+};
+
+static const struct hdmi_3d_info info_3d_fp = {
+       .is_3d = HDMI_VIDEO_FORMAT_3D,
+       .fmt_3d = HDMI_3D_FORMAT_FP,
+};
+
+const struct hdmi_conf hdmi_conf[] = {
+       { V4L2_DV_480P59_94,       &hdmi_conf_480p59_94,        &info_2d },
+       { V4L2_DV_480P60,          &hdmi_conf_480p60,           &info_2d },
+       { V4L2_DV_576P50,          &hdmi_conf_576p50,           &info_2d },
+       { V4L2_DV_720P50,          &hdmi_conf_720p50,           &info_2d },
+       { V4L2_DV_720P59_94,       &hdmi_conf_720p59_94,        &info_2d },
+       { V4L2_DV_720P60,          &hdmi_conf_720p60,           &info_2d },
+       { V4L2_DV_1080I50,         &hdmi_conf_1080i50,          &info_2d },
+       { V4L2_DV_1080I59_94,      &hdmi_conf_1080i59_94,       &info_2d },
+       { V4L2_DV_1080I60,         &hdmi_conf_1080i60,          &info_2d },
+       { V4L2_DV_1080P24,         &hdmi_conf_1080p24,          &info_2d },
+       { V4L2_DV_1080P25,         &hdmi_conf_1080p25,          &info_2d },
+       { V4L2_DV_1080P30,         &hdmi_conf_1080p30,          &info_2d },
+       { V4L2_DV_1080P50,         &hdmi_conf_1080p50,          &info_2d },
+       { V4L2_DV_1080P59_94,      &hdmi_conf_1080p59_94,       &info_2d },
+       { V4L2_DV_1080P60,         &hdmi_conf_1080p60,          &info_2d },
+       { V4L2_DV_720P60_SB_HALF,  &hdmi_conf_720p60_sb_half,   &info_3d_sb_h },
+       { V4L2_DV_720P60_TB,       &hdmi_conf_720p60_tb,        &info_3d_tb },
+       { V4L2_DV_720P59_94_SB_HALF, &hdmi_conf_720p59_94_sb_half,
+               &info_3d_sb_h },
+       { V4L2_DV_720P59_94_TB,    &hdmi_conf_720p59_94_tb,     &info_3d_tb },
+       { V4L2_DV_720P50_SB_HALF,  &hdmi_conf_720p50_sb_half,   &info_3d_sb_h },
+       { V4L2_DV_720P50_TB,       &hdmi_conf_720p50_tb,        &info_3d_tb },
+       { V4L2_DV_1080P24_FP,      &hdmi_conf_1080p24_fp,       &info_3d_fp },
+       { V4L2_DV_1080P24_SB_HALF, &hdmi_conf_1080p24_sb_half,  &info_3d_sb_h },
+       { V4L2_DV_1080P24_TB,      &hdmi_conf_1080p24_tb,       &info_3d_tb },
+       { V4L2_DV_1080P23_98_FP,   &hdmi_conf_1080p23_98_fp,    &info_3d_fp },
+       { V4L2_DV_1080P23_98_SB_HALF, &hdmi_conf_1080p23_98_sb_half,
+               &info_3d_sb_h },
+       { V4L2_DV_1080P23_98_TB,   &hdmi_conf_1080p23_98_tb,    &info_3d_tb },
+       { V4L2_DV_1080I60_SB_HALF, &hdmi_conf_1080i60_sb_half,  &info_3d_sb_h },
+       { V4L2_DV_1080I59_94_SB_HALF, &hdmi_conf_1080i59_94_sb_half,
+               &info_3d_sb_h },
+       { V4L2_DV_1080I50_SB_HALF, &hdmi_conf_1080i50_sb_half, &info_3d_sb_h },
+       { V4L2_DV_1080P60_SB_HALF, &hdmi_conf_1080p60_sb_half, &info_3d_sb_h },
+       { V4L2_DV_1080P60_TB, &hdmi_conf_1080p60_tb, &info_3d_tb },
+       { V4L2_DV_1080P30_SB_HALF, &hdmi_conf_1080p30_sb_half, &info_3d_sb_h },
+       { V4L2_DV_1080P30_TB, &hdmi_conf_1080p30_tb, &info_3d_tb },
+};
+
+const int hdmi_pre_cnt = ARRAY_SIZE(hdmi_conf);
+
+irqreturn_t hdmi_irq_handler(int irq, void *dev_data)
+{
+       struct hdmi_device *hdev = dev_data;
+       u32 intc_flag;
+
+       if (!pm_runtime_suspended(hdev->dev)) {
+               intc_flag = hdmi_read(hdev, HDMI_INTC_FLAG_0);
+               /* clearing flags for HPD plug/unplug */
+               if (intc_flag & HDMI_INTC_FLAG_HPD_UNPLUG) {
+                       printk(KERN_INFO "unplugged\n");
+                       if (hdev->hdcp_info.hdcp_enable)
+                               hdcp_stop(hdev);
+                       hdmi_write_mask(hdev, HDMI_INTC_FLAG_0, ~0,
+                                       HDMI_INTC_FLAG_HPD_UNPLUG);
+                       atomic_set(&hdev->hpd_state, HPD_LOW);
+               }
+               if (intc_flag & HDMI_INTC_FLAG_HPD_PLUG) {
+                       printk(KERN_INFO "plugged\n");
+                       hdmi_write_mask(hdev, HDMI_INTC_FLAG_0, ~0,
+                                       HDMI_INTC_FLAG_HPD_PLUG);
+                       atomic_set(&hdev->hpd_state, HPD_HIGH);
+               }
+               if (intc_flag & HDMI_INTC_FLAG_HDCP) {
+                       printk(KERN_INFO "hdcp interrupt occur\n");
+                       hdcp_irq_handler(hdev);
+                       hdmi_write_mask(hdev, HDMI_INTC_FLAG_0, ~0,
+                                       HDMI_INTC_FLAG_HDCP);
+               }
+       } else{
+               if (s5p_v4l2_hpd_read_gpio())
+                       atomic_set(&hdev->hpd_state, HPD_HIGH);
+               else
+                       atomic_set(&hdev->hpd_state, HPD_LOW);
+       }
+
+       queue_work(hdev->hpd_wq, &hdev->hpd_work);
+
+       return IRQ_HANDLED;
+}
+
+void hdmi_reg_init(struct hdmi_device *hdev)
+{
+       /* enable HPD interrupts */
+       hdmi_write_mask(hdev, HDMI_INTC_CON_0, ~0, HDMI_INTC_EN_GLOBAL |
+               HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
+       /* choose HDMI mode */
+       hdmi_write_mask(hdev, HDMI_MODE_SEL,
+               HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
+       /* disable bluescreen */
+       hdmi_write_mask(hdev, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
+       /* enable AVI packet every vsync, fixes purple line problem */
+       hdmi_writeb(hdev, HDMI_AVI_CON, 0x02);
+       /* RGB888 is default output format of HDMI,
+        * look to CEA-861-D, table 7 for more detail */
+       hdmi_writeb(hdev, HDMI_AVI_BYTE(1), 0 << 5);
+       hdmi_write_mask(hdev, HDMI_CON_1, 2, 3 << 5);
+}
+
+void hdmi_timing_apply(struct hdmi_device *hdev,
+       const struct hdmi_preset_conf *conf)
+{
+       const struct hdmi_core_regs *core = &conf->core;
+       const struct hdmi_tg_regs *tg = &conf->tg;
+
+       /* setting core registers */
+       hdmi_writeb(hdev, HDMI_H_BLANK_0, core->h_blank[0]);
+       hdmi_writeb(hdev, HDMI_H_BLANK_1, core->h_blank[1]);
+       hdmi_writeb(hdev, HDMI_V2_BLANK_0, core->v2_blank[0]);
+       hdmi_writeb(hdev, HDMI_V2_BLANK_1, core->v2_blank[1]);
+       hdmi_writeb(hdev, HDMI_V1_BLANK_0, core->v1_blank[0]);
+       hdmi_writeb(hdev, HDMI_V1_BLANK_1, core->v1_blank[1]);
+       hdmi_writeb(hdev, HDMI_V_LINE_0, core->v_line[0]);
+       hdmi_writeb(hdev, HDMI_V_LINE_1, core->v_line[1]);
+       hdmi_writeb(hdev, HDMI_H_LINE_0, core->h_line[0]);
+       hdmi_writeb(hdev, HDMI_H_LINE_1, core->h_line[1]);
+       hdmi_writeb(hdev, HDMI_HSYNC_POL, core->hsync_pol[0]);
+       hdmi_writeb(hdev, HDMI_VSYNC_POL, core->vsync_pol[0]);
+       hdmi_writeb(hdev, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
+       hdmi_writeb(hdev, HDMI_V_BLANK_F0_0, core->v_blank_f0[0]);
+       hdmi_writeb(hdev, HDMI_V_BLANK_F0_1, core->v_blank_f0[1]);
+       hdmi_writeb(hdev, HDMI_V_BLANK_F1_0, core->v_blank_f1[0]);
+       hdmi_writeb(hdev, HDMI_V_BLANK_F1_1, core->v_blank_f1[1]);
+       hdmi_writeb(hdev, HDMI_H_SYNC_START_0, core->h_sync_start[0]);
+       hdmi_writeb(hdev, HDMI_H_SYNC_START_1, core->h_sync_start[1]);
+       hdmi_writeb(hdev, HDMI_H_SYNC_END_0, core->h_sync_end[0]);
+       hdmi_writeb(hdev, HDMI_H_SYNC_END_1, core->h_sync_end[1]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_LINE_BEF_2_0, core->v_sync_line_bef_2[0]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_LINE_BEF_2_1, core->v_sync_line_bef_2[1]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_LINE_BEF_1_0, core->v_sync_line_bef_1[0]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_LINE_BEF_1_1, core->v_sync_line_bef_1[1]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_2_0, core->v_sync_line_aft_2[0]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_2_1, core->v_sync_line_aft_2[1]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_1_0, core->v_sync_line_aft_1[0]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_1_1, core->v_sync_line_aft_1[1]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_PXL_2_0,
+                       core->v_sync_line_aft_pxl_2[0]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_PXL_2_1,
+                       core->v_sync_line_aft_pxl_2[1]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_PXL_1_0,
+                       core->v_sync_line_aft_pxl_1[0]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_PXL_1_1,
+                       core->v_sync_line_aft_pxl_1[1]);
+       hdmi_writeb(hdev, HDMI_V_BLANK_F2_0, core->v_blank_f2[0]);
+       hdmi_writeb(hdev, HDMI_V_BLANK_F2_1, core->v_blank_f2[1]);
+       hdmi_writeb(hdev, HDMI_V_BLANK_F3_0, core->v_blank_f3[0]);
+       hdmi_writeb(hdev, HDMI_V_BLANK_F3_1, core->v_blank_f3[1]);
+       hdmi_writeb(hdev, HDMI_V_BLANK_F4_0, core->v_blank_f4[0]);
+       hdmi_writeb(hdev, HDMI_V_BLANK_F4_1, core->v_blank_f4[1]);
+       hdmi_writeb(hdev, HDMI_V_BLANK_F5_0, core->v_blank_f5[0]);
+       hdmi_writeb(hdev, HDMI_V_BLANK_F5_1, core->v_blank_f5[1]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_3_0, core->v_sync_line_aft_3[0]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_3_1, core->v_sync_line_aft_3[1]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_4_0, core->v_sync_line_aft_4[0]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_4_1, core->v_sync_line_aft_4[1]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_5_0, core->v_sync_line_aft_5[0]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_5_1, core->v_sync_line_aft_5[1]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_6_0, core->v_sync_line_aft_6[0]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_6_1, core->v_sync_line_aft_6[1]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_PXL_3_0,
+                       core->v_sync_line_aft_pxl_3[0]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_PXL_3_1,
+                       core->v_sync_line_aft_pxl_3[1]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_PXL_4_0,
+                       core->v_sync_line_aft_pxl_4[0]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_PXL_4_1,
+                       core->v_sync_line_aft_pxl_4[1]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_PXL_5_0,
+                       core->v_sync_line_aft_pxl_5[0]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_PXL_5_1,
+                       core->v_sync_line_aft_pxl_5[1]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_PXL_6_0,
+                       core->v_sync_line_aft_pxl_6[0]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_PXL_6_1,
+                       core->v_sync_line_aft_pxl_6[1]);
+       hdmi_writeb(hdev, HDMI_VACT_SPACE_1_0, core->vact_space_1[0]);
+       hdmi_writeb(hdev, HDMI_VACT_SPACE_1_1, core->vact_space_1[1]);
+       hdmi_writeb(hdev, HDMI_VACT_SPACE_2_0, core->vact_space_2[0]);
+       hdmi_writeb(hdev, HDMI_VACT_SPACE_2_1, core->vact_space_2[1]);
+       hdmi_writeb(hdev, HDMI_VACT_SPACE_3_0, core->vact_space_3[0]);
+       hdmi_writeb(hdev, HDMI_VACT_SPACE_3_1, core->vact_space_3[1]);
+       hdmi_writeb(hdev, HDMI_VACT_SPACE_4_0, core->vact_space_4[0]);
+       hdmi_writeb(hdev, HDMI_VACT_SPACE_4_1, core->vact_space_4[1]);
+       hdmi_writeb(hdev, HDMI_VACT_SPACE_5_0, core->vact_space_5[0]);
+       hdmi_writeb(hdev, HDMI_VACT_SPACE_5_1, core->vact_space_5[1]);
+       hdmi_writeb(hdev, HDMI_VACT_SPACE_6_0, core->vact_space_6[0]);
+       hdmi_writeb(hdev, HDMI_VACT_SPACE_6_1, core->vact_space_6[1]);
+
+       /* Timing generator registers */
+       hdmi_writeb(hdev, HDMI_TG_H_FSZ_L, tg->h_fsz_l);
+       hdmi_writeb(hdev, HDMI_TG_H_FSZ_H, tg->h_fsz_h);
+       hdmi_writeb(hdev, HDMI_TG_HACT_ST_L, tg->hact_st_l);
+       hdmi_writeb(hdev, HDMI_TG_HACT_ST_H, tg->hact_st_h);
+       hdmi_writeb(hdev, HDMI_TG_HACT_SZ_L, tg->hact_sz_l);
+       hdmi_writeb(hdev, HDMI_TG_HACT_SZ_H, tg->hact_sz_h);
+       hdmi_writeb(hdev, HDMI_TG_V_FSZ_L, tg->v_fsz_l);
+       hdmi_writeb(hdev, HDMI_TG_V_FSZ_H, tg->v_fsz_h);
+       hdmi_writeb(hdev, HDMI_TG_VSYNC_L, tg->vsync_l);
+       hdmi_writeb(hdev, HDMI_TG_VSYNC_H, tg->vsync_h);
+       hdmi_writeb(hdev, HDMI_TG_VSYNC2_L, tg->vsync2_l);
+       hdmi_writeb(hdev, HDMI_TG_VSYNC2_H, tg->vsync2_h);
+       hdmi_writeb(hdev, HDMI_TG_VACT_ST_L, tg->vact_st_l);
+       hdmi_writeb(hdev, HDMI_TG_VACT_ST_H, tg->vact_st_h);
+       hdmi_writeb(hdev, HDMI_TG_VACT_SZ_L, tg->vact_sz_l);
+       hdmi_writeb(hdev, HDMI_TG_VACT_SZ_H, tg->vact_sz_h);
+       hdmi_writeb(hdev, HDMI_TG_FIELD_CHG_L, tg->field_chg_l);
+       hdmi_writeb(hdev, HDMI_TG_FIELD_CHG_H, tg->field_chg_h);
+       hdmi_writeb(hdev, HDMI_TG_VACT_ST2_L, tg->vact_st2_l);
+       hdmi_writeb(hdev, HDMI_TG_VACT_ST2_H, tg->vact_st2_h);
+       hdmi_writeb(hdev, HDMI_TG_VACT_ST3_L, tg->vact_st3_l);
+       hdmi_writeb(hdev, HDMI_TG_VACT_ST3_H, tg->vact_st3_h);
+       hdmi_writeb(hdev, HDMI_TG_VACT_ST4_L, tg->vact_st4_l);
+       hdmi_writeb(hdev, HDMI_TG_VACT_ST4_H, tg->vact_st4_h);
+       hdmi_writeb(hdev, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi_l);
+       hdmi_writeb(hdev, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi_h);
+       hdmi_writeb(hdev, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi_l);
+       hdmi_writeb(hdev, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi_h);
+       hdmi_writeb(hdev, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi_l);
+       hdmi_writeb(hdev, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi_h);
+       hdmi_writeb(hdev, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi_l);
+       hdmi_writeb(hdev, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi_h);
+       hdmi_writeb(hdev, HDMI_TG_3D, tg->tg_3d);
+}
+
+int hdmi_conf_apply(struct hdmi_device *hdmi_dev)
+{
+       struct device *dev = hdmi_dev->dev;
+       const struct hdmi_preset_conf *conf = hdmi_dev->cur_conf;
+       struct v4l2_dv_preset preset;
+       int ret;
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       /* configure presets */
+       preset.preset = hdmi_dev->cur_preset;
+       ret = v4l2_subdev_call(hdmi_dev->phy_sd, video, s_dv_preset, &preset);
+       if (ret) {
+               dev_err(dev, "failed to set preset (%u)\n", preset.preset);
+               return ret;
+       }
+
+       hdmi_reg_init(hdmi_dev);
+
+       /* setting core registers */
+       hdmi_timing_apply(hdmi_dev, conf);
+
+       return 0;
+}
+
+int is_hdmiphy_ready(struct hdmi_device *hdev)
+{
+       u32 val = hdmi_read(hdev, HDMI_PHY_STATUS);
+       if (val & HDMI_PHY_STATUS_READY)
+               return 1;
+
+       return 0;
+}
+
+void hdmi_enable(struct hdmi_device *hdev, int on)
+{
+       if (on)
+               hdmi_write_mask(hdev, HDMI_CON_0, ~0, HDMI_EN);
+       else
+               hdmi_write_mask(hdev, HDMI_CON_0, 0, HDMI_EN);
+}
+
+void hdmi_hpd_enable(struct hdmi_device *hdev, int on)
+{
+       /* enable HPD interrupts */
+       hdmi_write_mask(hdev, HDMI_INTC_CON_0, ~0, HDMI_INTC_EN_GLOBAL |
+                       HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
+}
+
+void hdmi_tg_enable(struct hdmi_device *hdev, int on)
+{
+       u32 mask;
+
+       mask = (hdev->cur_conf->mbus_fmt.field == V4L2_FIELD_INTERLACED) ?
+                       HDMI_TG_EN | HDMI_FIELD_EN : HDMI_TG_EN;
+
+       if (on)
+               hdmi_write_mask(hdev, HDMI_TG_CMD, ~0, mask);
+       else
+               hdmi_write_mask(hdev, HDMI_TG_CMD, 0, mask);
+}
+
+static u8 hdmi_chksum(struct hdmi_device *hdev, u32 start, u8 len, u32 hdr_sum)
+{
+       int i;
+
+       /* hdr_sum : header0 + header1 + header2
+        * start : start address of packet byte1
+        * len : packet bytes - 1 */
+       for (i = 0; i < len; ++i)
+               hdr_sum += hdmi_read(hdev, start + i * 4);
+
+       return (u8)(0x100 - (hdr_sum & 0xff));
+}
+
+void hdmi_reg_stop_vsi(struct hdmi_device *hdev)
+{
+       hdmi_writeb(hdev, HDMI_VSI_CON, HDMI_VSI_CON_DO_NOT_TRANSMIT);
+}
+
+void hdmi_reg_infoframe(struct hdmi_device *hdev,
+               struct hdmi_infoframe *infoframe)
+{
+       struct device *dev = hdev->dev;
+       const struct hdmi_3d_info *info = hdmi_preset2info(hdev->cur_preset);
+       u32 hdr_sum;
+       u8 chksum;
+       dev_dbg(dev, "%s: InfoFrame type = 0x%x\n", __func__, infoframe->type);
+
+       switch (infoframe->type) {
+       case HDMI_PACKET_TYPE_VSI:
+               hdmi_writeb(hdev, HDMI_VSI_CON, HDMI_VSI_CON_EVERY_VSYNC);
+               hdmi_writeb(hdev, HDMI_VSI_HEADER0, infoframe->type);
+               hdmi_writeb(hdev, HDMI_VSI_HEADER1, infoframe->ver);
+               /* 0x000C03 : 24-bit IEEE Registration Identifier */
+               hdmi_writeb(hdev, HDMI_VSI_DATA(1), 0x03);
+               hdmi_writeb(hdev, HDMI_VSI_DATA(2), 0x0c);
+               hdmi_writeb(hdev, HDMI_VSI_DATA(3), 0x00);
+               hdmi_writeb(hdev, HDMI_VSI_DATA(4),
+                       HDMI_VSI_DATA04_VIDEO_FORMAT(info->is_3d));
+               hdmi_writeb(hdev, HDMI_VSI_DATA(5),
+                       HDMI_VSI_DATA05_3D_STRUCTURE(info->fmt_3d));
+               if (info->fmt_3d == HDMI_3D_FORMAT_SB_HALF) {
+                       infoframe->len += 1;
+                       hdmi_writeb(hdev, HDMI_VSI_DATA(6),
+                       (u8)HDMI_VSI_DATA06_3D_EXT_DATA(HDMI_H_SUB_SAMPLE));
+               }
+               hdmi_writeb(hdev, HDMI_VSI_HEADER2, infoframe->len);
+               hdr_sum = infoframe->type + infoframe->ver + infoframe->len;
+               chksum = hdmi_chksum(hdev, HDMI_VSI_DATA(1), infoframe->len, hdr_sum);
+               dev_dbg(dev, "VSI checksum = 0x%x\n", chksum);
+               hdmi_writeb(hdev, HDMI_VSI_DATA(0), chksum);
+               break;
+       case HDMI_PACKET_TYPE_AVI:
+               hdmi_writeb(hdev, HDMI_AVI_CON, HDMI_AVI_CON_EVERY_VSYNC);
+               hdmi_writeb(hdev, HDMI_AVI_HEADER0, infoframe->type);
+               hdmi_writeb(hdev, HDMI_AVI_HEADER1, infoframe->ver);
+               hdmi_writeb(hdev, HDMI_AVI_HEADER2, infoframe->len);
+               hdmi_writeb(hdev, HDMI_AVI_BYTE(1), hdev->output_fmt << 5);
+               hdr_sum = infoframe->type + infoframe->ver + infoframe->len;
+               chksum = hdmi_chksum(hdev, HDMI_AVI_BYTE(1), infoframe->len, hdr_sum);
+               dev_dbg(dev, "AVI checksum = 0x%x\n", chksum);
+               hdmi_writeb(hdev, HDMI_AVI_CHECK_SUM, chksum);
+               break;
+       default:
+               break;
+       }
+}
+
+void hdmi_reg_set_acr(struct hdmi_device *hdev)
+{
+       u32 n, cts;
+       int sample_rate = hdev->sample_rate;
+
+       if (sample_rate == 32000) {
+               n = 4096;
+               cts = 27000;
+       } else if (sample_rate == 44100) {
+               n = 6272;
+               cts = 30000;
+       } else if (sample_rate == 48000) {
+               n = 6144;
+               cts = 27000;
+       } else if (sample_rate == 88200) {
+               n = 12544;
+               cts = 30000;
+       } else if (sample_rate == 96000) {
+               n = 12288;
+               cts = 27000;
+       } else if (sample_rate == 176400) {
+               n = 25088;
+               cts = 30000;
+       } else if (sample_rate == 192000) {
+               n = 24576;
+               cts = 27000;
+       } else {
+               n = 0;
+               cts = 0;
+       }
+
+       hdmi_write(hdev, HDMI_ACR_N0, HDMI_ACR_N0_VAL(n));
+       hdmi_write(hdev, HDMI_ACR_N1, HDMI_ACR_N1_VAL(n));
+       hdmi_write(hdev, HDMI_ACR_N2, HDMI_ACR_N2_VAL(n));
+
+       /* transfer ACR packet */
+       hdmi_write(hdev, HDMI_ACR_CON, HDMI_ACR_CON_TX_MODE_MESURED_CTS);
+}
+
+void hdmi_reg_spdif_audio_init(struct hdmi_device *hdev)
+{
+       u32 val;
+       int bps, rep_time;
+
+       hdmi_write(hdev, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_ENABLE);
+
+       val = HDMI_SPDIFIN_CFG_NOISE_FILTER_2_SAMPLE |
+               HDMI_SPDIFIN_CFG_PCPD_MANUAL |
+               HDMI_SPDIFIN_CFG_WORD_LENGTH_MANUAL |
+               HDMI_SPDIFIN_CFG_UVCP_REPORT |
+               HDMI_SPDIFIN_CFG_HDMI_2_BURST |
+               HDMI_SPDIFIN_CFG_DATA_ALIGN_32;
+       hdmi_write(hdev, HDMI_SPDIFIN_CONFIG_1, val);
+       hdmi_write(hdev, HDMI_SPDIFIN_CONFIG_2, 0);
+
+       bps = hdev->audio_codec == HDMI_AUDIO_PCM ? hdev->bits_per_sample : 16;
+       rep_time = hdev->audio_codec == HDMI_AUDIO_AC3 ? 1536 * 2 - 1 : 0;
+       val = HDMI_SPDIFIN_USER_VAL_REPETITION_TIME_LOW(rep_time) |
+               HDMI_SPDIFIN_USER_VAL_WORD_LENGTH_24;
+       hdmi_write(hdev, HDMI_SPDIFIN_USER_VALUE_1, val);
+       val = HDMI_SPDIFIN_USER_VAL_REPETITION_TIME_HIGH(rep_time);
+       hdmi_write(hdev, HDMI_SPDIFIN_USER_VALUE_2, val);
+       hdmi_write(hdev, HDMI_SPDIFIN_USER_VALUE_3, 0);
+       hdmi_write(hdev, HDMI_SPDIFIN_USER_VALUE_4, 0);
+
+       val = HDMI_I2S_IN_ENABLE | HDMI_I2S_AUD_SPDIF | HDMI_I2S_MUX_ENABLE;
+       hdmi_write(hdev, HDMI_I2S_IN_MUX_CON, val);
+
+       hdmi_write(hdev, HDMI_I2S_MUX_CH, HDMI_I2S_CH_ALL_EN);
+       hdmi_write(hdev, HDMI_I2S_MUX_CUV, HDMI_I2S_CUV_RL_EN);
+
+       hdmi_write_mask(hdev, HDMI_SPDIFIN_CLK_CTRL, 0, HDMI_SPDIFIN_CLK_ON);
+       hdmi_write_mask(hdev, HDMI_SPDIFIN_CLK_CTRL, ~0, HDMI_SPDIFIN_CLK_ON);
+
+       hdmi_write(hdev, HDMI_SPDIFIN_OP_CTRL, HDMI_SPDIFIN_STATUS_CHECK_MODE);
+       hdmi_write(hdev, HDMI_SPDIFIN_OP_CTRL,
+                       HDMI_SPDIFIN_STATUS_CHECK_MODE_HDMI);
+}
+
+void hdmi_reg_i2s_audio_init(struct hdmi_device *hdev)
+{
+       u32 data_num, bit_ch, sample_frq, val;
+       int sample_rate = hdev->sample_rate;
+       int bits_per_sample = hdev->bits_per_sample;
+
+       if (bits_per_sample == 16) {
+               data_num = 1;
+               bit_ch = 0;
+       } else if (bits_per_sample == 20) {
+               data_num = 2;
+               bit_ch  = 1;
+       } else if (bits_per_sample == 24) {
+               data_num = 3;
+               bit_ch  = 1;
+       } else if (bits_per_sample == 32) {
+               data_num = 1;
+               bit_ch  = 2;
+       } else {
+               data_num = 1;
+               bit_ch = 0;
+       }
+
+       /* reset I2S */
+       hdmi_write(hdev, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_DISABLE);
+       hdmi_write(hdev, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_ENABLE);
+
+       hdmi_write_mask(hdev, HDMI_I2S_DSD_CON, 0, HDMI_I2S_DSD_ENABLE);
+
+       /* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */
+       val = HDMI_I2S_SEL_SCLK(5) | HDMI_I2S_SEL_LRCK(6);
+       hdmi_write(hdev, HDMI_I2S_PIN_SEL_0, val);
+       val = HDMI_I2S_SEL_SDATA1(3) | HDMI_I2S_SEL_SDATA0(4);
+       hdmi_write(hdev, HDMI_I2S_PIN_SEL_1, val);
+       val = HDMI_I2S_SEL_SDATA3(1) | HDMI_I2S_SEL_SDATA2(2);
+       hdmi_write(hdev, HDMI_I2S_PIN_SEL_2, val);
+       hdmi_write(hdev, HDMI_I2S_PIN_SEL_3, HDMI_I2S_SEL_DSD(0));
+
+       /* I2S_CON_1 & 2 */
+       val = HDMI_I2S_SCLK_FALLING_EDGE | HDMI_I2S_L_CH_LOW_POL;
+       hdmi_write(hdev, HDMI_I2S_CON_1, val);
+       val = HDMI_I2S_MSB_FIRST_MODE | HDMI_I2S_SET_BIT_CH(bit_ch) |
+               HDMI_I2S_SET_SDATA_BIT(data_num) | HDMI_I2S_BASIC_FORMAT;
+       hdmi_write(hdev, HDMI_I2S_CON_2, val);
+
+       if (sample_rate == 32000)
+               sample_frq = 0x3;
+       else if (sample_rate == 44100)
+               sample_frq = 0x0;
+       else if (sample_rate == 48000)
+               sample_frq = 0x2;
+       else if (sample_rate == 96000)
+               sample_frq = 0xa;
+       else
+               sample_frq = 0;
+
+       /* Configure register related to CUV information */
+       val = HDMI_I2S_CH_STATUS_MODE_0 | HDMI_I2S_2AUD_CH_WITHOUT_PREEMPH |
+               HDMI_I2S_COPYRIGHT | HDMI_I2S_LINEAR_PCM |
+               HDMI_I2S_CONSUMER_FORMAT;
+       hdmi_write(hdev, HDMI_I2S_CH_ST_0, val);
+       hdmi_write(hdev, HDMI_I2S_CH_ST_1, HDMI_I2S_CD_PLAYER);
+       hdmi_write(hdev, HDMI_I2S_CH_ST_2, HDMI_I2S_SET_SOURCE_NUM(0));
+       val = HDMI_I2S_CLK_ACCUR_LEVEL_1 |
+               HDMI_I2S_SET_SAMPLING_FREQ(sample_frq);
+       hdmi_write(hdev, HDMI_I2S_CH_ST_3, val);
+       val = HDMI_I2S_ORG_SAMPLING_FREQ_44_1 |
+               HDMI_I2S_WORD_LENGTH_MAX24_20BITS |
+               HDMI_I2S_WORD_LENGTH_MAX_20BITS;
+       hdmi_write(hdev, HDMI_I2S_CH_ST_4, val);
+
+       hdmi_write(hdev, HDMI_I2S_CH_ST_CON, HDMI_I2S_CH_STATUS_RELOAD);
+
+       val = HDMI_I2S_IN_ENABLE | HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE
+               | HDMI_I2S_MUX_ENABLE;
+       hdmi_write(hdev, HDMI_I2S_IN_MUX_CON, val);
+
+       val = HDMI_I2S_CH0_L_EN | HDMI_I2S_CH0_R_EN | HDMI_I2S_CH1_L_EN |
+               HDMI_I2S_CH1_R_EN | HDMI_I2S_CH2_L_EN | HDMI_I2S_CH2_R_EN |
+               HDMI_I2S_CH3_L_EN | HDMI_I2S_CH3_R_EN;
+       hdmi_write(hdev, HDMI_I2S_MUX_CH, val);
+
+       val = HDMI_I2S_CUV_L_EN | HDMI_I2S_CUV_R_EN;
+       hdmi_write(hdev, HDMI_I2S_MUX_CUV, val);
+}
+
+void hdmi_audio_enable(struct hdmi_device *hdev, int on)
+{
+       if (on) {
+               hdmi_write(hdev, HDMI_AUI_CON, HDMI_AUI_CON_TRANS_EVERY_VSYNC);
+               hdmi_write_mask(hdev, HDMI_CON_0, ~0, HDMI_ASP_ENABLE);
+       } else {
+               hdmi_write(hdev, HDMI_AUI_CON, HDMI_AUI_CON_NO_TRAN);
+               hdmi_write_mask(hdev, HDMI_CON_0, 0, HDMI_ASP_ENABLE);
+       }
+}
+
+void hdmi_bluescreen_enable(struct hdmi_device *hdev, int on)
+{
+       if (on)
+               hdmi_write_mask(hdev, HDMI_CON_0, ~0, HDMI_BLUE_SCR_EN);
+       else
+               hdmi_write_mask(hdev, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
+}
+
+void hdmi_reg_mute(struct hdmi_device *hdev, int on)
+{
+       hdmi_bluescreen_enable(hdev, on);
+       hdmi_audio_enable(hdev, !on);
+}
+
+int hdmi_hpd_status(struct hdmi_device *hdev)
+{
+       return hdmi_read(hdev, HDMI_HPD_STATUS);
+}
+
+int is_hdmi_streaming(struct hdmi_device *hdev)
+{
+       if (hdmi_hpd_status(hdev) && hdev->streaming)
+               return 1;
+       return 0;
+}
+
+u8 hdmi_get_int_mask(struct hdmi_device *hdev)
+{
+       return hdmi_readb(hdev, HDMI_INTC_CON_0);
+}
+
+void hdmi_set_int_mask(struct hdmi_device *hdev, u8 mask, int en)
+{
+       if (en) {
+               mask |= HDMI_INTC_EN_GLOBAL;
+               hdmi_write_mask(hdev, HDMI_INTC_CON_0, ~0, mask);
+       } else
+               hdmi_write_mask(hdev, HDMI_INTC_CON_0, 0,
+                               HDMI_INTC_EN_GLOBAL);
+}
+
+void hdmi_sw_hpd_enable(struct hdmi_device *hdev, int en)
+{
+       if (en)
+               hdmi_write_mask(hdev, HDMI_HPD, ~0, HDMI_HPD_SEL_I_HPD);
+       else
+               hdmi_write_mask(hdev, HDMI_HPD, 0, HDMI_HPD_SEL_I_HPD);
+}
+
+void hdmi_sw_hpd_plug(struct hdmi_device *hdev, int en)
+{
+       if (en)
+               hdmi_write_mask(hdev, HDMI_HPD, ~0, HDMI_SW_HPD_PLUGGED);
+       else
+               hdmi_write_mask(hdev, HDMI_HPD, 0, HDMI_SW_HPD_PLUGGED);
+}
+
+void hdmi_phy_sw_reset(struct hdmi_device *hdev)
+{
+       hdmi_write_mask(hdev, HDMI_PHY_RSTOUT, ~0, HDMI_PHY_SW_RSTOUT);
+       mdelay(10);
+       hdmi_write_mask(hdev, HDMI_PHY_RSTOUT,  0, HDMI_PHY_SW_RSTOUT);
+}
+
+void hdmi_dumpregs(struct hdmi_device *hdev, char *prefix)
+{
+#define DUMPREG(reg_id) \
+       dev_dbg(hdev->dev, "%s:" #reg_id " = %08x\n", prefix, \
+               readl(hdev->regs + reg_id))
+
+       int i;
+
+       dev_dbg(hdev->dev, "%s: ---- CONTROL REGISTERS ----\n", prefix);
+       DUMPREG(HDMI_INTC_CON_0);
+       DUMPREG(HDMI_INTC_FLAG_0);
+       DUMPREG(HDMI_HPD_STATUS);
+       DUMPREG(HDMI_INTC_CON_1);
+       DUMPREG(HDMI_INTC_FLAG_1);
+       DUMPREG(HDMI_PHY_STATUS_0);
+       DUMPREG(HDMI_PHY_STATUS_PLL);
+       DUMPREG(HDMI_PHY_CON_0);
+       DUMPREG(HDMI_PHY_RSTOUT);
+       DUMPREG(HDMI_PHY_VPLL);
+       DUMPREG(HDMI_PHY_CMU);
+       DUMPREG(HDMI_CORE_RSTOUT);
+
+       dev_dbg(hdev->dev, "%s: ---- CORE REGISTERS ----\n", prefix);
+       DUMPREG(HDMI_CON_0);
+       DUMPREG(HDMI_CON_1);
+       DUMPREG(HDMI_CON_2);
+       DUMPREG(HDMI_STATUS);
+       DUMPREG(HDMI_PHY_STATUS);
+       DUMPREG(HDMI_STATUS_EN);
+       DUMPREG(HDMI_HPD);
+       DUMPREG(HDMI_MODE_SEL);
+       DUMPREG(HDMI_ENC_EN);
+       DUMPREG(HDMI_DC_CONTROL);
+       DUMPREG(HDMI_VIDEO_PATTERN_GEN);
+
+       dev_dbg(hdev->dev, "%s: ---- CORE SYNC REGISTERS ----\n", prefix);
+       DUMPREG(HDMI_H_BLANK_0);
+       DUMPREG(HDMI_H_BLANK_1);
+       DUMPREG(HDMI_V2_BLANK_0);
+       DUMPREG(HDMI_V2_BLANK_1);
+       DUMPREG(HDMI_V1_BLANK_0);
+       DUMPREG(HDMI_V1_BLANK_1);
+       DUMPREG(HDMI_V_LINE_0);
+       DUMPREG(HDMI_V_LINE_1);
+       DUMPREG(HDMI_H_LINE_0);
+       DUMPREG(HDMI_H_LINE_1);
+       DUMPREG(HDMI_HSYNC_POL);
+
+       DUMPREG(HDMI_VSYNC_POL);
+       DUMPREG(HDMI_INT_PRO_MODE);
+       DUMPREG(HDMI_V_BLANK_F0_0);
+       DUMPREG(HDMI_V_BLANK_F0_1);
+       DUMPREG(HDMI_V_BLANK_F1_0);
+       DUMPREG(HDMI_V_BLANK_F1_1);
+
+       DUMPREG(HDMI_H_SYNC_START_0);
+       DUMPREG(HDMI_H_SYNC_START_1);
+       DUMPREG(HDMI_H_SYNC_END_0);
+       DUMPREG(HDMI_H_SYNC_END_1);
+
+       DUMPREG(HDMI_V_SYNC_LINE_BEF_2_0);
+       DUMPREG(HDMI_V_SYNC_LINE_BEF_2_1);
+       DUMPREG(HDMI_V_SYNC_LINE_BEF_1_0);
+       DUMPREG(HDMI_V_SYNC_LINE_BEF_1_1);
+
+       DUMPREG(HDMI_V_SYNC_LINE_AFT_2_0);
+       DUMPREG(HDMI_V_SYNC_LINE_AFT_2_1);
+       DUMPREG(HDMI_V_SYNC_LINE_AFT_1_0);
+       DUMPREG(HDMI_V_SYNC_LINE_AFT_1_1);
+
+       DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_0);
+       DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_1);
+       DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_0);
+       DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_1);
+
+       DUMPREG(HDMI_V_BLANK_F2_0);
+       DUMPREG(HDMI_V_BLANK_F2_1);
+       DUMPREG(HDMI_V_BLANK_F3_0);
+       DUMPREG(HDMI_V_BLANK_F3_1);
+       DUMPREG(HDMI_V_BLANK_F4_0);
+       DUMPREG(HDMI_V_BLANK_F4_1);
+       DUMPREG(HDMI_V_BLANK_F5_0);
+       DUMPREG(HDMI_V_BLANK_F5_1);
+
+       DUMPREG(HDMI_V_SYNC_LINE_AFT_3_0);
+       DUMPREG(HDMI_V_SYNC_LINE_AFT_3_1);
+       DUMPREG(HDMI_V_SYNC_LINE_AFT_4_0);
+       DUMPREG(HDMI_V_SYNC_LINE_AFT_4_1);
+       DUMPREG(HDMI_V_SYNC_LINE_AFT_5_0);
+       DUMPREG(HDMI_V_SYNC_LINE_AFT_5_1);
+       DUMPREG(HDMI_V_SYNC_LINE_AFT_6_0);
+       DUMPREG(HDMI_V_SYNC_LINE_AFT_6_1);
+
+       DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_0);
+       DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_1);
+       DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_0);
+       DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_1);
+       DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_0);
+       DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_1);
+       DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_0);
+       DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_1);
+
+       DUMPREG(HDMI_VACT_SPACE_1_0);
+       DUMPREG(HDMI_VACT_SPACE_1_1);
+       DUMPREG(HDMI_VACT_SPACE_2_0);
+       DUMPREG(HDMI_VACT_SPACE_2_1);
+       DUMPREG(HDMI_VACT_SPACE_3_0);
+       DUMPREG(HDMI_VACT_SPACE_3_1);
+       DUMPREG(HDMI_VACT_SPACE_4_0);
+       DUMPREG(HDMI_VACT_SPACE_4_1);
+       DUMPREG(HDMI_VACT_SPACE_5_0);
+       DUMPREG(HDMI_VACT_SPACE_5_1);
+       DUMPREG(HDMI_VACT_SPACE_6_0);
+       DUMPREG(HDMI_VACT_SPACE_6_1);
+
+       dev_dbg(hdev->dev, "%s: ---- TG REGISTERS ----\n", prefix);
+       DUMPREG(HDMI_TG_CMD);
+       DUMPREG(HDMI_TG_H_FSZ_L);
+       DUMPREG(HDMI_TG_H_FSZ_H);
+       DUMPREG(HDMI_TG_HACT_ST_L);
+       DUMPREG(HDMI_TG_HACT_ST_H);
+       DUMPREG(HDMI_TG_HACT_SZ_L);
+       DUMPREG(HDMI_TG_HACT_SZ_H);
+       DUMPREG(HDMI_TG_V_FSZ_L);
+       DUMPREG(HDMI_TG_V_FSZ_H);
+       DUMPREG(HDMI_TG_VSYNC_L);
+       DUMPREG(HDMI_TG_VSYNC_H);
+       DUMPREG(HDMI_TG_VSYNC2_L);
+       DUMPREG(HDMI_TG_VSYNC2_H);
+       DUMPREG(HDMI_TG_VACT_ST_L);
+       DUMPREG(HDMI_TG_VACT_ST_H);
+       DUMPREG(HDMI_TG_VACT_SZ_L);
+       DUMPREG(HDMI_TG_VACT_SZ_H);
+       DUMPREG(HDMI_TG_FIELD_CHG_L);
+       DUMPREG(HDMI_TG_FIELD_CHG_H);
+       DUMPREG(HDMI_TG_VACT_ST2_L);
+       DUMPREG(HDMI_TG_VACT_ST2_H);
+       DUMPREG(HDMI_TG_VACT_ST3_L);
+       DUMPREG(HDMI_TG_VACT_ST3_H);
+       DUMPREG(HDMI_TG_VACT_ST4_L);
+       DUMPREG(HDMI_TG_VACT_ST4_H);
+       DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
+       DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
+       DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
+       DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
+       DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
+       DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
+       DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
+       DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
+       DUMPREG(HDMI_TG_3D);
+
+       dev_dbg(hdev->dev, "%s: ---- PACKET REGISTERS ----\n", prefix);
+       DUMPREG(HDMI_AVI_CON);
+       DUMPREG(HDMI_AVI_HEADER0);
+       DUMPREG(HDMI_AVI_HEADER1);
+       DUMPREG(HDMI_AVI_HEADER2);
+       DUMPREG(HDMI_AVI_CHECK_SUM);
+       DUMPREG(HDMI_AVI_BYTE(1));
+       DUMPREG(HDMI_VSI_CON);
+       DUMPREG(HDMI_VSI_HEADER0);
+       DUMPREG(HDMI_VSI_HEADER1);
+       DUMPREG(HDMI_VSI_HEADER2);
+       for (i = 0; i < 7; ++i)
+               DUMPREG(HDMI_VSI_DATA(i));
+
+#undef DUMPREG
+}
diff --git a/drivers/media/video/exynos/tv/hdmiphy_conf_4210.c b/drivers/media/video/exynos/tv/hdmiphy_conf_4210.c
new file mode 100644 (file)
index 0000000..67033c5
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Samsung HDMI Physical interface driver
+ *
+ * Copyright (C) 2010-2011 Samsung Electronics Co.Ltd
+ * Author: Jiun Yu <jiun.yu@samsung.com>
+ *
+ * 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.
+ */
+
+#include "hdmi.h"
+
+static const u8 hdmiphy_conf27[32] = {
+       0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
+       0x6B, 0x10, 0x02, 0x51, 0xDf, 0xF2, 0x54, 0x87,
+       0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
+       0x22, 0x40, 0xe3, 0x26, 0x00, 0x00, 0x00, 0x80,
+};
+
+static const u8 hdmiphy_conf74_175[32] = {
+       0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
+       0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
+       0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
+       0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x80,
+};
+
+static const u8 hdmiphy_conf74_25[32] = {
+       0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
+       0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
+       0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xe0,
+       0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x80,
+};
+
+static const u8 hdmiphy_conf148_5[32] = {
+       0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
+       0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
+       0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
+       0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x80,
+};
+
+const struct hdmiphy_conf hdmiphy_conf[] = {
+       { V4L2_DV_480P59_94, hdmiphy_conf27 },
+       { V4L2_DV_1080P30, hdmiphy_conf74_175 },
+       { V4L2_DV_720P59_94, hdmiphy_conf74_175 },
+       { V4L2_DV_720P60, hdmiphy_conf74_25 },
+       { V4L2_DV_1080P50, hdmiphy_conf148_5 },
+       { V4L2_DV_1080P60, hdmiphy_conf148_5 },
+       { V4L2_DV_1080I60, hdmiphy_conf74_25 },
+};
+
+const int hdmiphy_conf_cnt = ARRAY_SIZE(hdmiphy_conf);
diff --git a/drivers/media/video/exynos/tv/hdmiphy_conf_5250.c b/drivers/media/video/exynos/tv/hdmiphy_conf_5250.c
new file mode 100644 (file)
index 0000000..5cc0643
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Samsung HDMI Physical interface driver
+ *
+ * Copyright (C) 2010-2011 Samsung Electronics Co.Ltd
+ * Author: Jiun Yu <jiun.yu@samsung.com>
+ *
+ * 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.
+ */
+
+#include "hdmi.h"
+
+static const u8 hdmiphy_conf27[32] = {
+       0x01, 0x51, 0x2d, 0x75, 0x40, 0x01, 0x00, 0x08,
+       0x82, 0xa0, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
+       0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
+       0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00,
+};
+
+static const u8 hdmiphy_conf27_027[32] = {
+       0x01, 0xd1, 0x2d, 0x72, 0x40, 0x64, 0x12, 0x08,
+       0x43, 0xa0, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
+       0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
+       0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00,
+};
+
+static const u8 hdmiphy_conf74_175[32] = {
+       0x01, 0xd1, 0x1f, 0x10, 0x40, 0x5b, 0xef, 0x08,
+       0x81, 0xa0, 0xb9, 0xd8, 0x45, 0xa0, 0xac, 0x80,
+       0x5a, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
+       0x54, 0xa6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00,
+};
+
+static const u8 hdmiphy_conf74_25[32] = {
+       0x01, 0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0x08,
+       0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
+       0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
+       0x54, 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00,
+};
+
+static const u8 hdmiphy_conf148_352[32] = {
+       0x01, 0xd2, 0x3e, 0x00, 0x40, 0x5b, 0xef, 0x08,
+       0x81, 0xa0, 0xb9, 0xd8, 0x45, 0xa0, 0xac, 0x80,
+       0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
+       0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x00,
+};
+
+static const u8 hdmiphy_conf148_5[32] = {
+       0x01, 0xd1, 0x1f, 0x00, 0x40, 0x40, 0xf8, 0x08,
+       0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
+       0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
+       0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x00,
+};
+
+const struct hdmiphy_conf hdmiphy_conf[] = {
+       { V4L2_DV_480P59_94, hdmiphy_conf27 },
+       { V4L2_DV_480P60, hdmiphy_conf27_027 },
+       { V4L2_DV_576P50, hdmiphy_conf27 },
+       { V4L2_DV_720P50, hdmiphy_conf74_25 },
+       { V4L2_DV_720P59_94, hdmiphy_conf74_175 },
+       { V4L2_DV_720P60, hdmiphy_conf74_25 },
+       { V4L2_DV_1080I50, hdmiphy_conf74_25 },
+       { V4L2_DV_1080I59_94, hdmiphy_conf74_175 },
+       { V4L2_DV_1080I60, hdmiphy_conf74_25 },
+       { V4L2_DV_1080P24, hdmiphy_conf74_25 },
+       { V4L2_DV_1080P25, hdmiphy_conf74_25 },
+       { V4L2_DV_1080P30, hdmiphy_conf74_175 },
+       { V4L2_DV_1080P50, hdmiphy_conf148_5 },
+       { V4L2_DV_1080P59_94, hdmiphy_conf148_352 },
+       { V4L2_DV_1080P60, hdmiphy_conf148_5 },
+       { V4L2_DV_720P60_SB_HALF, hdmiphy_conf74_25 },
+       { V4L2_DV_720P60_TB, hdmiphy_conf74_25 },
+       { V4L2_DV_720P59_94_SB_HALF, hdmiphy_conf74_25 },
+       { V4L2_DV_720P59_94_TB, hdmiphy_conf74_25 },
+       { V4L2_DV_720P50_SB_HALF, hdmiphy_conf74_25 },
+       { V4L2_DV_720P50_TB, hdmiphy_conf74_25 },
+       { V4L2_DV_1080P24_FP, hdmiphy_conf148_5 },
+       { V4L2_DV_1080P24_SB_HALF, hdmiphy_conf74_25 },
+       { V4L2_DV_1080P24_TB, hdmiphy_conf74_25 },
+       { V4L2_DV_1080P23_98_FP, hdmiphy_conf148_5 },
+       { V4L2_DV_1080P23_98_SB_HALF, hdmiphy_conf74_25 },
+       { V4L2_DV_1080P23_98_TB, hdmiphy_conf74_25 },
+       { V4L2_DV_1080I60_SB_HALF, hdmiphy_conf74_25 },
+       { V4L2_DV_1080I59_94_SB_HALF, hdmiphy_conf74_25 },
+       { V4L2_DV_1080I50_SB_HALF, hdmiphy_conf74_25 },
+       { V4L2_DV_1080P60_SB_HALF, hdmiphy_conf148_5 },
+       { V4L2_DV_1080P60_TB, hdmiphy_conf148_5 },
+       { V4L2_DV_1080P30_SB_HALF, hdmiphy_conf74_25 },
+       { V4L2_DV_1080P30_TB, hdmiphy_conf74_25 },
+};
+
+const int hdmiphy_conf_cnt = ARRAY_SIZE(hdmiphy_conf);
diff --git a/drivers/media/video/exynos/tv/hdmiphy_drv.c b/drivers/media/video/exynos/tv/hdmiphy_drv.c
new file mode 100644 (file)
index 0000000..01d28da
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ * Samsung HDMI Physical interface driver
+ *
+ * Copyright (C) 2010-2011 Samsung Electronics Co.Ltd
+ * Author: Tomasz Stanislawski <t.stanislaws@samsung.com>
+ *
+ * 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.
+ */
+#include "hdmi.h"
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/err.h>
+
+#include <media/v4l2-subdev.h>
+
+MODULE_AUTHOR("Tomasz Stanislawski <t.stanislaws@samsung.com>");
+MODULE_DESCRIPTION("Samsung HDMI Physical interface driver");
+MODULE_LICENSE("GPL");
+
+#ifdef DEBUG
+static void hdmiphy_print_reg(u8 *recv_buffer)
+{
+       int i;
+
+       for (i = 1; i <= 32; i++) {
+               printk("[%2x]", recv_buffer[i - 1]);
+               if (!(i % 8) && i)
+                       printk("\n");
+       }
+       printk("\n");
+}
+#endif
+
+const u8 *hdmiphy_preset2conf(u32 preset)
+{
+       int i;
+       for (i = 0; i < hdmiphy_conf_cnt; ++i)
+               if (hdmiphy_conf[i].preset == preset)
+                       return hdmiphy_conf[i].data;
+       return NULL;
+}
+
+static int hdmiphy_ctrl(struct i2c_client *client, u8 reg, u8 bit,
+               u8 *recv_buffer, int en)
+{
+       int ret;
+       u8 buffer[2];
+       struct device *dev = &client->dev;
+
+       buffer[0] = reg;
+       buffer[1] = en ? (recv_buffer[reg] & (~(1 << bit))) :
+                       (recv_buffer[reg] | (1 << bit));
+       recv_buffer[reg] = buffer[1];
+
+       ret = i2c_master_send(client, buffer, 2);
+       if (ret != 2) {
+               dev_err(dev, "failed to turn %s HDMIPHY via I2C\n",
+                               en ? "on" : "off");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int hdmiphy_enable_oscpad(struct i2c_client *client, int on,
+               u8 *recv_buffer)
+{
+       int ret;
+       u8 buffer[2];
+       struct device *dev = &client->dev;
+
+       buffer[0] = 0x0b;
+       if (on)
+               buffer[1] = 0xd8;
+       else
+               buffer[1] = 0x18;
+       recv_buffer[0x0b] = buffer[1];
+
+       ret = i2c_master_send(client, buffer, 2);
+       if (ret != 2) {
+               dev_err(dev, "failed to %s osc pad\n",
+                               on ? "enable" : "disable");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int hdmiphy_s_power(struct v4l2_subdev *sd, int on)
+{
+       u8 recv_buffer[32];
+       u8 buffer[2];
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct device *dev = &client->dev;
+
+       memset(recv_buffer, 0, sizeof(recv_buffer));
+
+       dev_dbg(dev, "%s: hdmiphy is %s\n", __func__, on ? "on" : "off");
+
+       buffer[0] = 0x1;
+       i2c_master_send(client, buffer, 1);
+       i2c_master_recv(client, recv_buffer, 32);
+
+#ifdef DEBUG
+       hdmiphy_print_reg(recv_buffer);
+#endif
+
+       if (!on)
+               hdmiphy_enable_oscpad(client, 0, recv_buffer);
+
+       hdmiphy_ctrl(client, 0x1d, 0x7, recv_buffer, on);
+       hdmiphy_ctrl(client, 0x1d, 0x0, recv_buffer, on);
+       hdmiphy_ctrl(client, 0x1d, 0x1, recv_buffer, on);
+       hdmiphy_ctrl(client, 0x1d, 0x2, recv_buffer, on);
+       hdmiphy_ctrl(client, 0x1d, 0x4, recv_buffer, on);
+       hdmiphy_ctrl(client, 0x1d, 0x5, recv_buffer, on);
+       hdmiphy_ctrl(client, 0x1d, 0x6, recv_buffer, on);
+
+       if (!on)
+               hdmiphy_ctrl(client, 0x4, 0x3, recv_buffer, 0);
+
+#ifdef DEBUG
+       buffer[0] = 0x1;
+       i2c_master_send(client, buffer, 1);
+       i2c_master_recv(client, recv_buffer, 32);
+
+       hdmiphy_print_reg(recv_buffer);
+#endif
+       return 0;
+}
+
+static int hdmiphy_s_dv_preset(struct v4l2_subdev *sd,
+       struct v4l2_dv_preset *preset)
+{
+       const u8 *data;
+       u8 buffer[32];
+       u8 recv_buffer[32];
+       int ret;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct device *dev = &client->dev;
+
+       dev_dbg(dev, "s_dv_preset(preset = %d)\n", preset->preset);
+       data = hdmiphy_preset2conf(preset->preset);
+       if (!data) {
+               dev_err(dev, "format not supported\n");
+               return -EINVAL;
+       }
+
+       memset(recv_buffer, 0, 32);
+
+#ifdef DEBUG
+       i2c_master_recv(client, recv_buffer, 32);
+       hdmiphy_print_reg(recv_buffer);
+#endif
+
+       /* storing configuration to the device */
+       memcpy(buffer, data, 32);
+       ret = i2c_master_send(client, buffer, 32);
+       if (ret != 32) {
+               dev_err(dev, "failed to configure HDMIPHY via I2C\n");
+               return -EIO;
+       }
+
+#ifdef DEBUG
+       i2c_master_recv(client, recv_buffer, 32);
+       hdmiphy_print_reg(recv_buffer);
+#endif
+
+       return 0;
+}
+
+static int hdmiphy_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct device *dev = &client->dev;
+       u8 buffer[2];
+       int ret;
+
+       dev_dbg(dev, "s_stream(%d)\n", enable);
+       /* going to/from configuration from/to operation mode */
+       buffer[0] = 0x1f;
+       buffer[1] = enable ? 0x80 : 0x00;
+
+       ret = i2c_master_send(client, buffer, 2);
+       if (ret != 2) {
+               dev_err(dev, "stream (%d) failed\n", enable);
+               return -EIO;
+       }
+       return 0;
+}
+
+static const struct v4l2_subdev_core_ops hdmiphy_core_ops = {
+       .s_power =  hdmiphy_s_power,
+};
+
+static const struct v4l2_subdev_video_ops hdmiphy_video_ops = {
+       .s_dv_preset = hdmiphy_s_dv_preset,
+       .s_stream =  hdmiphy_s_stream,
+};
+
+static const struct v4l2_subdev_ops hdmiphy_ops = {
+       .core = &hdmiphy_core_ops,
+       .video = &hdmiphy_video_ops,
+};
+
+static int __devinit hdmiphy_probe(struct i2c_client *client,
+       const struct i2c_device_id *id)
+{
+       static struct v4l2_subdev sd;
+
+       dev_info(&client->dev, "hdmiphy_probe start\n");
+
+       v4l2_i2c_subdev_init(&sd, client, &hdmiphy_ops);
+       dev_info(&client->dev, "probe successful\n");
+       return 0;
+}
+
+static int __devexit hdmiphy_remove(struct i2c_client *client)
+{
+       dev_info(&client->dev, "remove successful\n");
+       return 0;
+}
+
+static const struct i2c_device_id hdmiphy_id[] = {
+       { "hdmiphy", 0 },
+       { },
+};
+MODULE_DEVICE_TABLE(i2c, hdmiphy_id);
+
+static struct i2c_driver hdmiphy_driver = {
+       .driver = {
+               .name   = "s5p-hdmiphy",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = hdmiphy_probe,
+       .remove         = __devexit_p(hdmiphy_remove),
+       .id_table = hdmiphy_id,
+};
+
+static int __init hdmiphy_init(void)
+{
+       return i2c_add_driver(&hdmiphy_driver);
+}
+module_init(hdmiphy_init);
+
+static void __exit hdmiphy_exit(void)
+{
+       i2c_del_driver(&hdmiphy_driver);
+}
+module_exit(hdmiphy_exit);
diff --git a/drivers/media/video/exynos/tv/mixer.h b/drivers/media/video/exynos/tv/mixer.h
new file mode 100644 (file)
index 0000000..c9bdef9
--- /dev/null
@@ -0,0 +1,557 @@
+/*
+ * Samsung TV Mixer driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.com>
+ *
+ * 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 Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#ifndef SAMSUNG_MIXER_H
+#define SAMSUNG_MIXER_H
+
+#ifdef CONFIG_VIDEO_EXYNOS_MIXER_DEBUG
+       #define DEBUG
+#endif
+
+#include <linux/fb.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <media/v4l2-device.h>
+#include <media/videobuf2-core.h>
+#include <media/exynos_mc.h>
+
+#include "regs-mixer.h"
+
+/** maximum number of output interfaces */
+#define MXR_MAX_OUTPUTS 2
+
+/** There are 2 mixers after EXYNOS5250 */
+#define MXR_SUB_MIXER0         0
+#define MXR_SUB_MIXER1         1
+/** maximum number of sub-mixers */
+#if defined(CONFIG_ARCH_EXYNOS4)
+#define MXR_MAX_SUB_MIXERS     1
+#else
+#define MXR_MAX_SUB_MIXERS     2
+#endif
+
+/** each sub-mixer supports 1 video layer and 2 graphic layers */
+#define MXR_LAYER_VIDEO                0
+#define MXR_LAYER_GRP0         1
+#define MXR_LAYER_GRP1         2
+
+#define EXYNOS_VIDEONODE_MXR_GRP(x)    (16 + x)
+#define EXYNOS_VIDEONODE_MXR_VIDEO     20
+
+/** maximum number of input interfaces (layers) */
+#define MXR_MAX_LAYERS 3
+#define MXR_DRIVER_NAME "s5p-mixer"
+/** maximal number of planes for every layer */
+#define MXR_MAX_PLANES 2
+
+#define MXR_ENABLE 1
+#define MXR_DISABLE 0
+
+/* mixer pad definitions */
+#define MXR_PAD_SINK_GSCALER   0
+#define MXR_PAD_SINK_GRP0      1
+#define MXR_PAD_SINK_GRP1      2
+#define MXR_PAD_SOURCE_GSCALER 3
+#define MXR_PAD_SOURCE_GRP0    4
+#define MXR_PAD_SOURCE_GRP1    5
+#define MXR_PADS_NUM           6
+/** description of a macroblock for packed formats */
+struct mxr_block {
+       /** vertical number of pixels in macroblock */
+       unsigned int width;
+       /** horizontal number of pixels in macroblock */
+       unsigned int height;
+       /** size of block in bytes */
+       unsigned int size;
+};
+
+/** description of supported format */
+struct mxr_format {
+       /** format name/mnemonic */
+       const char *name;
+       /** fourcc identifier */
+       u32 fourcc;
+       /** colorspace identifier */
+       enum v4l2_colorspace colorspace;
+       /** number of planes in image data */
+       int num_planes;
+       /** description of block for each plane */
+       struct mxr_block plane[MXR_MAX_PLANES];
+       /** number of subframes in image data */
+       int num_subframes;
+       /** specifies to which subframe belong given plane */
+       int plane2subframe[MXR_MAX_PLANES];
+       /** internal code, driver dependant */
+       unsigned long cookie;
+};
+
+/** description of crop configuration for image */
+struct mxr_crop {
+       /** width of layer in pixels */
+       unsigned int full_width;
+       /** height of layer in pixels */
+       unsigned int full_height;
+       /** horizontal offset of first pixel to be displayed */
+       unsigned int x_offset;
+       /** vertical offset of first pixel to be displayed */
+       unsigned int y_offset;
+       /** width of displayed data in pixels */
+       unsigned int width;
+       /** height of displayed data in pixels */
+       unsigned int height;
+       /** indicate which fields are present in buffer */
+       unsigned int field;
+};
+
+/** stages of geometry operations */
+enum mxr_geometry_stage {
+       MXR_GEOMETRY_SINK,
+       MXR_GEOMETRY_COMPOSE,
+       MXR_GEOMETRY_CROP,
+       MXR_GEOMETRY_SOURCE,
+};
+
+/** description of transformation from source to destination image */
+struct mxr_geometry {
+       /** cropping for source image */
+       struct mxr_crop src;
+       /** cropping for destination image */
+       struct mxr_crop dst;
+       /** layer-dependant description of horizontal scaling */
+       unsigned int x_ratio;
+       /** layer-dependant description of vertical scaling */
+       unsigned int y_ratio;
+};
+
+/** instance of a buffer */
+struct mxr_buffer {
+       /** common v4l buffer stuff -- must be first */
+       struct vb2_buffer       vb;
+       /** node for layer's lists */
+       struct list_head        list;
+};
+
+/** TV graphic layer pipeline state */
+enum tv_graph_pipeline_state {
+       /** graphic layer is not shown */
+       TV_GRAPH_PIPELINE_IDLE = 0,
+       /** state between STREAMON and hardware start */
+       TV_GRAPH_PIPELINE_STREAMING_START,
+       /** graphic layer is shown */
+       TV_GRAPH_PIPELINE_STREAMING,
+       /** state before STREAMOFF is finished */
+       TV_GRAPH_PIPELINE_STREAMING_FINISH,
+};
+
+/** TV graphic layer pipeline structure for streaming media data */
+struct tv_graph_pipeline {
+       struct media_pipeline pipe;
+       enum tv_graph_pipeline_state state;
+
+       /** starting point on pipeline */
+       struct mxr_layer *layer;
+};
+
+/** forward declarations */
+struct mxr_device;
+struct mxr_layer;
+
+/** callback for layers operation */
+struct mxr_layer_ops {
+       /* TODO: try to port it to subdev API */
+       /** handler for resource release function */
+       void (*release)(struct mxr_layer *);
+       /** setting buffer to HW */
+       void (*buffer_set)(struct mxr_layer *, struct mxr_buffer *);
+       /** setting format and geometry in HW */
+       void (*format_set)(struct mxr_layer *);
+       /** streaming stop/start */
+       void (*stream_set)(struct mxr_layer *, int);
+       /** adjusting geometry */
+       void (*fix_geometry)(struct mxr_layer *);
+};
+
+enum mxr_layer_type {
+       MXR_LAYER_TYPE_VIDEO = 0,
+       MXR_LAYER_TYPE_GRP = 1,
+};
+
+struct mxr_layer_en {
+       int graph0;
+       int graph1;
+       int graph2;
+       int graph3;
+};
+/** layer instance, a single window and content displayed on output */
+struct mxr_layer {
+       /** parent mixer device */
+       struct mxr_device *mdev;
+       /** layer index (unique identifier) */
+       int idx;
+       /** layer type */
+       enum mxr_layer_type type;
+       /** minor number of mixer layer as video device */
+       int minor;
+       /** callbacks for layer methods */
+       struct mxr_layer_ops ops;
+       /** format array */
+       const struct mxr_format **fmt_array;
+       /** size of format array */
+       unsigned long fmt_array_size;
+       /** frame buffer emulator */
+       void *fb;
+
+       /** lock for protection of list and state fields */
+       spinlock_t enq_slock;
+       /** list for enqueued buffers */
+       struct list_head enq_list;
+       /** buffer currently owned by hardware in temporary registers */
+       struct mxr_buffer *update_buf;
+       /** buffer currently owned by hardware in shadow registers */
+       struct mxr_buffer *shadow_buf;
+
+       /** mutex for protection of fields below */
+       struct mutex mutex;
+       /** handler for video node */
+       struct video_device vfd;
+       /** queue for output buffers */
+       struct vb2_queue vb_queue;
+       /** current image format */
+       const struct mxr_format *fmt;
+       /** current geometry of image */
+       struct mxr_geometry geo;
+
+       /** index of current mixer path : MXR_SUB_MIXERx*/
+       int cur_mxr;
+       /** source pad of mixer input */
+       struct media_pad pad;
+       /** pipeline structure for streaming TV graphic layer */
+       struct tv_graph_pipeline pipe;
+
+       /** enable per layer blending for each layer */
+       int layer_blend_en;
+       /** alpha value for per layer blending */
+       u32 layer_alpha;
+       /** enable per pixel blending */
+       int pixel_blend_en;
+       /** enable chromakey */
+       int chroma_en;
+       /** value for chromakey */
+       u32 chroma_val;
+};
+
+/** description of mixers output interface */
+struct mxr_output {
+       /** name of output */
+       char name[32];
+       /** output subdev */
+       struct v4l2_subdev *sd;
+       /** cookie used for configuration of registers */
+       int cookie;
+};
+
+/** specify source of output subdevs */
+struct mxr_output_conf {
+       /** name of output (connector) */
+       char *output_name;
+       /** name of module that generates output subdev */
+       char *module_name;
+       /** cookie need for mixer HW */
+       int cookie;
+};
+
+struct clk;
+struct regulator;
+
+/** auxiliary resources used my mixer */
+struct mxr_resources {
+       /** interrupt index */
+       int irq;
+       /** pointer to Mixer registers */
+       void __iomem *mxr_regs;
+#if defined(CONFIG_ARCH_EXYNOS4)
+       /** pointer to Video Processor registers */
+       void __iomem *vp_regs;
+       /** other resources, should used under mxr_device.mutex */
+       struct clk *vp;
+#endif
+#if defined(CONFIG_CPU_EXYNOS4210)
+       struct clk *sclk_dac;
+#endif
+       struct clk *sclk_mixer;
+       struct clk *mixer;
+       struct clk *sclk_hdmi;
+};
+
+/* event flags used  */
+enum mxr_devide_flags {
+       MXR_EVENT_VSYNC = 0,
+};
+
+/** videobuf2 context of mixer */
+struct mxr_vb2 {
+       const struct vb2_mem_ops *ops;
+       void *(*init)(struct mxr_device *mdev);
+       void (*cleanup)(void *alloc_ctx);
+
+       dma_addr_t (*plane_addr)(struct vb2_buffer *vb, u32 plane_no);
+
+       int (*resume)(void *alloc_ctx);
+       void (*suspend)(void *alloc_ctx);
+
+       int (*cache_flush)(struct vb2_buffer *vb, u32 num_planes);
+       void (*set_cacheable)(void *alloc_ctx, bool cacheable);
+       void            *(*attach_dmabuf)(void *alloc_ctx, struct dma_buf *dbuf,
+                               unsigned long size, int write);
+       void            (*detach_dmabuf)(void *buf_priv);
+       int             (*map_dmabuf)(void *buf_priv);
+       void            (*unmap_dmabuf)(void *buf_priv);
+};
+
+/** sub-mixer 0,1 drivers instance */
+struct sub_mxr_device {
+       /** state of each layer */
+       struct mxr_layer *layer[MXR_MAX_LAYERS];
+
+       /** use of each sub mixer */
+       int use;
+       /** use of local path gscaler to mixer */
+       int local;
+       /** for mixer as sub-device */
+       struct v4l2_subdev sd;
+       /** mixer's pads : 3 sink pad, 3 source pad */
+       struct media_pad pads[MXR_PADS_NUM];
+       /** format info of mixer's pads */
+       struct v4l2_mbus_framefmt mbus_fmt[MXR_PADS_NUM];
+       /** crop info of mixer's pads */
+       struct v4l2_rect crop[MXR_PADS_NUM];
+};
+
+/** drivers instance */
+struct mxr_device {
+       /** master device */
+       struct device *dev;
+       /** state of each output */
+       struct mxr_output *output[MXR_MAX_OUTPUTS];
+       /** number of registered outputs */
+       int output_cnt;
+
+       /* video resources */
+
+       /** videbuf2 context */
+       const struct mxr_vb2 *vb2;
+       /** context of allocator */
+       void *alloc_ctx;
+       /** event wait queue */
+       wait_queue_head_t event_queue;
+       /** state flags */
+       unsigned long event_flags;
+
+       /** spinlock for protection of registers */
+       spinlock_t reg_slock;
+
+       /** mutex for protection of fields below */
+       struct mutex mutex;
+       /** mutex for protection of streamer */
+       struct mutex s_mutex;
+
+       /** number of entities depndant on output configuration */
+       int n_output;
+       /** number of users that do streaming */
+       int n_streamer;
+       /** index of current output */
+       int current_output;
+       /** auxiliary resources used my mixer */
+       struct mxr_resources res;
+
+       /** number of G-Scaler linked to mixer0 */
+       int mxr0_gsc;
+       /** number of G-Scaler linked to mixer1 */
+       int mxr1_gsc;
+       /** media entity link setup flags */
+       unsigned long flags;
+
+       /** entity info which transfers media data to mixer subdev */
+       enum mxr_data_from mxr_data_from;
+
+       /** count of sub-mixers */
+       struct sub_mxr_device sub_mxr[MXR_MAX_SUB_MIXERS];
+
+       /** enabled layer number **/
+       struct mxr_layer_en layer_en;
+       /** frame packing flag **/
+       int frame_packing;
+};
+
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+extern const struct mxr_vb2 mxr_vb2_cma;
+#elif defined(CONFIG_VIDEOBUF2_DMA_CONTIG)
+extern const struct mxr_vb2 mxr_vb2_dma_contig;
+#endif
+
+extern struct mxr_device *my_gbl_mdev;
+/** transform device structure into mixer device */
+static inline struct mxr_device *to_mdev(struct device *dev)
+{
+       return dev_get_drvdata(dev);
+}
+
+/** transform subdev structure into mixer device */
+static inline struct mxr_device *sd_to_mdev(struct v4l2_subdev *sd)
+{
+       struct sub_mxr_device *sub_mxr =
+               container_of(sd, struct sub_mxr_device, sd);
+       return sub_mxr->layer[MXR_LAYER_GRP0]->mdev;
+}
+
+/** transform subdev structure into sub mixer device */
+static inline struct sub_mxr_device *sd_to_sub_mxr(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct sub_mxr_device, sd);
+}
+
+/** transform entity structure into sub mixer device */
+static inline struct sub_mxr_device *entity_to_sub_mxr(struct media_entity *me)
+{
+       struct v4l2_subdev *sd;
+
+       sd = container_of(me, struct v4l2_subdev, entity);
+       return container_of(sd, struct sub_mxr_device, sd);
+}
+
+/** transform entity structure into sub mixer device */
+static inline struct mxr_device *sub_mxr_to_mdev(struct sub_mxr_device *sub_mxr)
+{
+       int idx;
+
+       if (!strcmp(sub_mxr->sd.name, "s5p-mixer0"))
+               idx = MXR_SUB_MIXER0;
+       else
+               idx = MXR_SUB_MIXER1;
+
+       return container_of(sub_mxr, struct mxr_device, sub_mxr[idx]);
+}
+
+/** get current output data, should be called under mdev's mutex */
+static inline struct mxr_output *to_output(struct mxr_device *mdev)
+{
+       return mdev->output[mdev->current_output];
+}
+
+/** get current output subdev, should be called under mdev's mutex */
+static inline struct v4l2_subdev *to_outsd(struct mxr_device *mdev)
+{
+       struct mxr_output *out = to_output(mdev);
+       return out ? out->sd : NULL;
+}
+
+/** forward declaration for mixer platform data */
+struct mxr_platform_data;
+
+/** acquiring common video resources */
+int __devinit mxr_acquire_video(struct mxr_device *mdev,
+       struct mxr_output_conf *output_cont, int output_count);
+
+/** releasing common video resources */
+void __devexit mxr_release_video(struct mxr_device *mdev);
+
+struct mxr_layer *mxr_graph_layer_create(struct mxr_device *mdev, int cur_mxr,
+       int idx, int nr);
+struct mxr_layer *mxr_vp_layer_create(struct mxr_device *mdev, int cur_mxr,
+       int idx, int nr);
+struct mxr_layer *mxr_video_layer_create(struct mxr_device *mdev, int cur_mxr,
+       int idx);
+struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev,
+       int idx, char *name, struct mxr_layer_ops *ops);
+
+const struct mxr_format *find_format_by_fourcc(
+       struct mxr_layer *layer, unsigned long fourcc);
+
+void mxr_base_layer_release(struct mxr_layer *layer);
+void mxr_layer_release(struct mxr_layer *layer);
+void mxr_layer_geo_fix(struct mxr_layer *layer);
+void mxr_layer_default_geo(struct mxr_layer *layer);
+
+int mxr_base_layer_register(struct mxr_layer *layer);
+void mxr_base_layer_unregister(struct mxr_layer *layer);
+
+unsigned long mxr_get_plane_size(const struct mxr_block *blk,
+       unsigned int width, unsigned int height);
+
+/** adds new consumer for mixer's power */
+int __must_check mxr_power_get(struct mxr_device *mdev);
+/** removes consumer for mixer's power */
+void mxr_power_put(struct mxr_device *mdev);
+/** add new client for output configuration */
+void mxr_output_get(struct mxr_device *mdev);
+/** removes new client for output configuration */
+void mxr_output_put(struct mxr_device *mdev);
+/** returns format of data delivared to current output */
+void mxr_get_mbus_fmt(struct mxr_device *mdev,
+       struct v4l2_mbus_framefmt *mbus_fmt);
+
+/* Debug */
+
+#define mxr_err(mdev, fmt, ...)  dev_err(mdev->dev, fmt, ##__VA_ARGS__)
+#define mxr_warn(mdev, fmt, ...) dev_warn(mdev->dev, fmt, ##__VA_ARGS__)
+#define mxr_info(mdev, fmt, ...) dev_info(mdev->dev, fmt, ##__VA_ARGS__)
+
+#ifdef CONFIG_VIDEO_EXYNOS_MIXER_DEBUG
+       #define mxr_dbg(mdev, fmt, ...)  dev_dbg(mdev->dev, fmt, ##__VA_ARGS__)
+#else
+       #define mxr_dbg(mdev, fmt, ...)  do { (void) mdev; } while (0)
+#endif
+
+/* accessing Mixer's and Video Processor's registers */
+
+void mxr_layer_sync(struct mxr_device *mdev, int en);
+void mxr_vsync_set_update(struct mxr_device *mdev, int en);
+void mxr_reg_reset(struct mxr_device *mdev);
+void mxr_reg_set_layer_blend(struct mxr_device *mdev, int sub_mxr, int num,
+               int en);
+void mxr_reg_layer_alpha(struct mxr_device *mdev, int sub_mxr, int num, u32 a);
+void mxr_reg_set_pixel_blend(struct mxr_device *mdev, int sub_mxr, int num,
+               int en);
+void mxr_reg_set_colorkey(struct mxr_device *mdev, int sub_mxr,
+               int num, int en);
+void mxr_reg_colorkey_val(struct mxr_device *mdev, int sub_mxr, int num, u32 v);
+irqreturn_t mxr_irq_handler(int irq, void *dev_data);
+void mxr_reg_s_output(struct mxr_device *mdev, int cookie);
+void mxr_reg_streamon(struct mxr_device *mdev);
+void mxr_reg_streamoff(struct mxr_device *mdev);
+int mxr_reg_wait4vsync(struct mxr_device *mdev);
+void mxr_reg_set_mbus_fmt(struct mxr_device *mdev,
+       struct v4l2_mbus_framefmt *fmt);
+void mxr_reg_local_path_clear(struct mxr_device *mdev);
+void mxr_reg_local_path_set(struct mxr_device *mdev, int mxr0_gsc, int mxr1_gsc,
+               u32 flags);
+void mxr_reg_graph_layer_stream(struct mxr_device *mdev, int idx, int en);
+void mxr_reg_graph_buffer(struct mxr_device *mdev, int idx, dma_addr_t addr);
+void mxr_reg_graph_format(struct mxr_device *mdev, int idx,
+       const struct mxr_format *fmt, const struct mxr_geometry *geo);
+
+void mxr_reg_video_layer_stream(struct mxr_device *mdev, int idx, int en);
+void mxr_reg_video_geo(struct mxr_device *mdev, int cur_mxr, int idx,
+               const struct mxr_geometry *geo);
+
+#if defined(CONFIG_ARCH_EXYNOS4)
+void mxr_reg_vp_layer_stream(struct mxr_device *mdev, int en);
+void mxr_reg_vp_buffer(struct mxr_device *mdev,
+       dma_addr_t luma_addr[2], dma_addr_t chroma_addr[2]);
+void mxr_reg_vp_format(struct mxr_device *mdev,
+       const struct mxr_format *fmt, const struct mxr_geometry *geo);
+#endif
+void mxr_reg_dump(struct mxr_device *mdev);
+
+#endif /* SAMSUNG_MIXER_H */
diff --git a/drivers/media/video/exynos/tv/mixer_drv.c b/drivers/media/video/exynos/tv/mixer_drv.c
new file mode 100644 (file)
index 0000000..3e7557b
--- /dev/null
@@ -0,0 +1,1476 @@
+/*
+ * Samsung TV Mixer driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.com>
+ *
+ * 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 Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+#include "mixer.h"
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
+#include <linux/kernel.h>
+
+#if defined(CONFIG_VIDEOBUF2_DMA_CONTIG)
+#include <media/videobuf2-dma-contig.h>
+#endif
+#include <media/exynos_mc.h>
+
+struct mxr_device *my_gbl_mdev;
+MODULE_AUTHOR("Tomasz Stanislawski, <t.stanislaws@samsung.com>");
+MODULE_DESCRIPTION("Samsung MIXER");
+MODULE_LICENSE("GPL");
+
+/* --------- DRIVER PARAMETERS ---------- */
+
+static struct mxr_output_conf mxr_output_conf[] = {
+       {
+               .output_name = "S5P HDMI connector",
+               .module_name = "exynos5-hdmi",
+               .cookie = 1,
+       },
+       {
+               .output_name = "S5P SDO connector",
+               .module_name = "s5p-sdo",
+               .cookie = 0,
+       },
+};
+
+void mxr_get_mbus_fmt(struct mxr_device *mdev,
+       struct v4l2_mbus_framefmt *mbus_fmt)
+{
+       struct v4l2_subdev *sd;
+       int ret;
+
+       mutex_lock(&mdev->mutex);
+       sd = to_outsd(mdev);
+       ret = v4l2_subdev_call(sd, video, g_mbus_fmt, mbus_fmt);
+       WARN(ret, "failed to get mbus_fmt for output %s\n", sd->name);
+       mutex_unlock(&mdev->mutex);
+}
+
+static void mxr_set_alpha_blend(struct mxr_device *mdev)
+{
+       int i, j;
+       int layer_en, pixel_en, chroma_en;
+       u32 a, v;
+
+       for (i = 0; i < MXR_MAX_SUB_MIXERS; ++i) {
+               for (j = 0; j < MXR_MAX_LAYERS; ++j) {
+                       layer_en = mdev->sub_mxr[i].layer[j]->layer_blend_en;
+                       a = mdev->sub_mxr[i].layer[j]->layer_alpha;
+                       pixel_en = mdev->sub_mxr[i].layer[j]->pixel_blend_en;
+                       chroma_en = mdev->sub_mxr[i].layer[j]->chroma_en;
+                       v = mdev->sub_mxr[i].layer[j]->chroma_val;
+
+                       mxr_dbg(mdev, "mixer%d: layer%d\n", i, j);
+                       mxr_dbg(mdev, "layer blend is %s, alpha = %d\n",
+                                       layer_en ? "enabled" : "disabled", a);
+                       mxr_dbg(mdev, "pixel blend is %s\n",
+                                       pixel_en ? "enabled" : "disabled");
+                       mxr_dbg(mdev, "chromakey is %s, value = %d\n",
+                                       chroma_en ? "enabled" : "disabled", v);
+
+                       mxr_reg_set_layer_blend(mdev, i, j, layer_en);
+                       mxr_reg_layer_alpha(mdev, i, j, a);
+                       mxr_reg_set_pixel_blend(mdev, i, j, pixel_en);
+                       mxr_reg_set_colorkey(mdev, i, j, chroma_en);
+                       mxr_reg_colorkey_val(mdev, i, j, v);
+               }
+       }
+}
+
+static int mxr_streamer_get(struct mxr_device *mdev, struct v4l2_subdev *sd)
+{
+       int i, ret;
+       int local = 1;
+       struct sub_mxr_device *sub_mxr;
+       struct mxr_layer *layer;
+       struct media_pad *pad;
+       struct v4l2_mbus_framefmt mbus_fmt;
+#if defined(CONFIG_CPU_EXYNOS4210)
+       struct mxr_resources *res = &mdev->res;
+#endif
+
+       mutex_lock(&mdev->s_mutex);
+       ++mdev->n_streamer;
+       mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_streamer);
+       /* If pipeline is started from Gscaler input video device,
+        * TV basic configuration must be set before running mixer */
+       if (mdev->mxr_data_from == FROM_GSC_SD) {
+               mxr_dbg(mdev, "%s: from gscaler\n", __func__);
+               local = 0;
+               /* enable mixer clock */
+               ret = mxr_power_get(mdev);
+               if (ret) {
+                       mxr_err(mdev, "power on failed\n");
+                       return -ENODEV;
+               }
+               /* turn on connected output device through link
+                * with mixer */
+               mxr_output_get(mdev);
+
+               for (i = 0; i < MXR_MAX_SUB_MIXERS; ++i) {
+                       sub_mxr = &mdev->sub_mxr[i];
+                       if (sub_mxr->local) {
+                               layer = sub_mxr->layer[MXR_LAYER_VIDEO];
+                               layer->pipe.state = TV_GRAPH_PIPELINE_STREAMING;
+                               mxr_layer_geo_fix(layer);
+                               layer->ops.format_set(layer);
+                               layer->ops.stream_set(layer, 1);
+                               local += sub_mxr->local;
+                       }
+               }
+               if (local == 2)
+                       mxr_layer_sync(mdev, MXR_ENABLE);
+               /* Set the TVOUT register about gsc-mixer local path */
+               mxr_reg_local_path_set(mdev, mdev->mxr0_gsc, mdev->mxr1_gsc,
+                               mdev->flags);
+       }
+
+       /* Alpha blending configuration always can be changed
+        * whenever streaming */
+       mxr_set_alpha_blend(mdev);
+
+       if ((mdev->n_streamer == 1 && local == 1) ||
+           (mdev->n_streamer == 2 && local == 2)) {
+               for (i = MXR_PAD_SOURCE_GSCALER; i < MXR_PADS_NUM; ++i) {
+                       pad = &sd->entity.pads[i];
+
+                       /* find sink pad of output via enabled link*/
+                       pad = media_entity_remote_source(pad);
+                       if (pad)
+                               if (media_entity_type(pad->entity)
+                                               == MEDIA_ENT_T_V4L2_SUBDEV)
+                                       break;
+
+                       if (i == MXR_PAD_SOURCE_GRP1)
+                               return -ENODEV;
+               }
+
+               sd = media_entity_to_v4l2_subdev(pad->entity);
+
+               mxr_dbg(mdev, "cookie of current output = (%d)\n",
+                       to_output(mdev)->cookie);
+
+#if defined(CONFIG_CPU_EXYNOS4210)
+               if (to_output(mdev)->cookie == 0)
+                       clk_set_parent(res->sclk_mixer, res->sclk_dac);
+               else
+                       clk_set_parent(res->sclk_mixer, res->sclk_hdmi);
+#endif
+               mxr_reg_s_output(mdev, to_output(mdev)->cookie);
+
+               ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mbus_fmt);
+               if (ret) {
+                       mxr_err(mdev, "failed to get mbus_fmt for output %s\n",
+                                       sd->name);
+                       return ret;
+               }
+
+               mxr_reg_set_mbus_fmt(mdev, &mbus_fmt);
+               ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mbus_fmt);
+               if (ret) {
+                       mxr_err(mdev, "failed to set mbus_fmt for output %s\n",
+                                       sd->name);
+                       return ret;
+               }
+               mxr_reg_streamon(mdev);
+
+               ret = v4l2_subdev_call(sd, video, s_stream, 1);
+               if (ret) {
+                       mxr_err(mdev, "starting stream failed for output %s\n",
+                                       sd->name);
+                       return ret;
+               }
+
+               ret = mxr_reg_wait4vsync(mdev);
+               if (ret) {
+                       mxr_err(mdev, "failed to get vsync (%d) from output\n",
+                                       ret);
+                       return ret;
+               }
+       }
+
+       mutex_unlock(&mdev->s_mutex);
+       mxr_reg_dump(mdev);
+
+       return 0;
+}
+
+static int mxr_streamer_put(struct mxr_device *mdev, struct v4l2_subdev *sd)
+{
+       int ret, i;
+       int local = 1;
+       struct media_pad *pad;
+       struct sub_mxr_device *sub_mxr;
+       struct mxr_layer *layer;
+       struct v4l2_subdev *hdmi_sd;
+       struct v4l2_subdev *gsc_sd;
+       struct exynos_entity_data *md_data;
+
+       mutex_lock(&mdev->s_mutex);
+       --mdev->n_streamer;
+       mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_streamer);
+
+       /* distinction number of local path */
+       if (mdev->mxr_data_from == FROM_GSC_SD) {
+               local = 0;
+               for (i = 0; i < MXR_MAX_SUB_MIXERS; ++i) {
+                       sub_mxr = &mdev->sub_mxr[i];
+                       if (sub_mxr->local)
+                               local += sub_mxr->local;
+               }
+               if (local == 2)
+                       mxr_layer_sync(mdev, MXR_DISABLE);
+       }
+
+       if ((mdev->n_streamer == 0 && local == 1) ||
+           (mdev->n_streamer == 1 && local == 2)) {
+               for (i = MXR_PAD_SOURCE_GSCALER; i < MXR_PADS_NUM; ++i) {
+                       pad = &sd->entity.pads[i];
+
+                       /* find sink pad of output via enabled link*/
+                       pad = media_entity_remote_source(pad);
+                       if (pad)
+                               if (media_entity_type(pad->entity)
+                                               == MEDIA_ENT_T_V4L2_SUBDEV)
+                                       break;
+
+                       if (i == MXR_PAD_SOURCE_GRP1)
+                               return -ENODEV;
+               }
+
+               hdmi_sd = media_entity_to_v4l2_subdev(pad->entity);
+
+               mxr_reg_streamoff(mdev);
+               /* vsync applies Mixer setup */
+               ret = mxr_reg_wait4vsync(mdev);
+               if (ret) {
+                       mxr_err(mdev, "failed to get vsync (%d) from output\n",
+                                       ret);
+                       return ret;
+               }
+       }
+       /* When using local path between gscaler and mixer, below stop sequence
+        * must be processed */
+       if (mdev->mxr_data_from == FROM_GSC_SD) {
+               pad = &sd->entity.pads[MXR_PAD_SINK_GSCALER];
+               pad = media_entity_remote_source(pad);
+               if (pad) {
+                       gsc_sd = media_entity_to_v4l2_subdev(
+                                       pad->entity);
+                       mxr_dbg(mdev, "stop from %s\n", gsc_sd->name);
+                       md_data = (struct exynos_entity_data *)
+                               gsc_sd->dev_priv;
+                       md_data->media_ops->power_off(gsc_sd);
+               }
+       }
+
+       if ((mdev->n_streamer == 0 && local == 1) ||
+           (mdev->n_streamer == 1 && local == 2)) {
+               ret = v4l2_subdev_call(hdmi_sd, video, s_stream, 0);
+               if (ret) {
+                       mxr_err(mdev, "stopping stream failed for output %s\n",
+                                       hdmi_sd->name);
+                       return ret;
+               }
+       }
+       /* turn off connected output device through link
+        * with mixer */
+       if (mdev->mxr_data_from == FROM_GSC_SD) {
+               for (i = 0; i < MXR_MAX_SUB_MIXERS; ++i) {
+                       sub_mxr = &mdev->sub_mxr[i];
+                       if (sub_mxr->local) {
+                               layer = sub_mxr->layer[MXR_LAYER_VIDEO];
+                               layer->ops.stream_set(layer, 0);
+                               layer->pipe.state = TV_GRAPH_PIPELINE_IDLE ;
+                       }
+               }
+               mxr_reg_local_path_clear(mdev);
+               mxr_output_put(mdev);
+
+               /* disable mixer clock */
+               mxr_power_put(mdev);
+       }
+       WARN(mdev->n_streamer < 0, "negative number of streamers (%d)\n",
+               mdev->n_streamer);
+       mutex_unlock(&mdev->s_mutex);
+       mxr_reg_dump(mdev);
+
+       return 0;
+}
+
+void mxr_output_get(struct mxr_device *mdev)
+{
+       mutex_lock(&mdev->mutex);
+       ++mdev->n_output;
+       mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_output);
+       /* turn on auxiliary driver */
+       if (mdev->n_output == 1)
+               v4l2_subdev_call(to_outsd(mdev), core, s_power, 1);
+       mutex_unlock(&mdev->mutex);
+}
+
+void mxr_output_put(struct mxr_device *mdev)
+{
+       mutex_lock(&mdev->mutex);
+       --mdev->n_output;
+       mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_output);
+       /* turn on auxiliary driver */
+       if (mdev->n_output == 0)
+               v4l2_subdev_call(to_outsd(mdev), core, s_power, 0);
+       WARN(mdev->n_output < 0, "negative number of output users (%d)\n",
+               mdev->n_output);
+       mutex_unlock(&mdev->mutex);
+}
+
+static int mxr_runtime_resume(struct device *dev);
+static int mxr_runtime_suspend(struct device *dev);
+
+int mxr_power_get(struct mxr_device *mdev)
+{
+       /* If runtime PM is not implemented, mxr_runtime_resume
+        * function is directly called.
+        */
+#ifdef CONFIG_PM_RUNTIME
+       int ret = pm_runtime_get_sync(mdev->dev);
+       /* returning 1 means that power is already enabled,
+        * so zero success be returned */
+       if (IS_ERR_VALUE(ret))
+               return ret;
+       return 0;
+#else
+       mxr_runtime_resume(mdev->dev);
+       return 0;
+#endif
+}
+
+void mxr_power_put(struct mxr_device *mdev)
+{
+       /* If runtime PM is not implemented, mxr_runtime_suspend
+        * function is directly called.
+        */
+#ifdef CONFIG_PM_RUNTIME
+       pm_runtime_put_sync(mdev->dev);
+#else
+       mxr_runtime_suspend(mdev->dev);
+#endif
+}
+
+/*--------- RESOURCE MANAGEMENT -------------*/
+
+static int __devinit mxr_acquire_plat_resources(struct mxr_device *mdev,
+       struct platform_device *pdev)
+{
+       struct resource *res;
+       int ret;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               mxr_err(mdev, "get memory resource failed.\n");
+               ret = -ENXIO;
+               goto fail;
+       }
+
+       mdev->res.mxr_regs = ioremap(res->start, resource_size(res));
+       if (mdev->res.mxr_regs == NULL) {
+               mxr_err(mdev, "register mapping failed.\n");
+               ret = -ENXIO;
+               goto fail;
+       }
+
+#if defined(CONFIG_ARCH_EXYNOS4)
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vp");
+       if (res == NULL) {
+               mxr_err(mdev, "get memory resource failed.\n");
+               ret = -ENXIO;
+               goto fail_mxr_regs;
+       }
+
+       mdev->res.vp_regs = ioremap(res->start, resource_size(res));
+       if (mdev->res.vp_regs == NULL) {
+               mxr_err(mdev, "register mapping failed.\n");
+               ret = -ENXIO;
+               goto fail_mxr_regs;
+       }
+#endif
+
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (res == NULL) {
+               mxr_err(mdev, "get interrupt resource failed.\n");
+               ret = -ENXIO;
+               goto fail_vp_regs;
+       }
+
+       ret = request_irq(res->start, mxr_irq_handler, 0, "s5p-mixer", mdev);
+       if (ret) {
+               mxr_err(mdev, "request interrupt failed.\n");
+               goto fail_vp_regs;
+       }
+       mdev->res.irq = res->start;
+
+       return 0;
+
+fail_vp_regs:
+#if defined(CONFIG_ARCH_EXYNOS4)
+       iounmap(mdev->res.vp_regs);
+
+fail_mxr_regs:
+#endif
+       iounmap(mdev->res.mxr_regs);
+
+fail:
+       return ret;
+}
+
+static void mxr_release_plat_resources(struct mxr_device *mdev)
+{
+       free_irq(mdev->res.irq, mdev);
+#if defined(CONFIG_ARCH_EXYNOS4)
+       iounmap(mdev->res.vp_regs);
+#endif
+       iounmap(mdev->res.mxr_regs);
+}
+
+static void mxr_release_clocks(struct mxr_device *mdev)
+{
+       struct mxr_resources *res = &mdev->res;
+
+#if defined(CONFIG_ARCH_EXYNOS4)
+       if (!IS_ERR_OR_NULL(res->vp))
+               clk_put(res->vp);
+#endif
+#if defined(CONFIG_CPU_EXYNOS4210)
+       if (!IS_ERR_OR_NULL(res->sclk_mixer))
+               clk_put(res->sclk_mixer);
+       if (!IS_ERR_OR_NULL(res->sclk_dac))
+               clk_put(res->sclk_dac);
+#endif
+       if (!IS_ERR_OR_NULL(res->mixer))
+               clk_put(res->mixer);
+       if (!IS_ERR_OR_NULL(res->sclk_hdmi))
+               clk_put(res->sclk_hdmi);
+}
+
+static int mxr_acquire_clocks(struct mxr_device *mdev)
+{
+       struct mxr_resources *res = &mdev->res;
+       struct device *dev = mdev->dev;
+
+#if defined(CONFIG_ARCH_EXYNOS4)
+       res->vp = clk_get(dev, "vp");
+       if (IS_ERR_OR_NULL(res->vp)) {
+               mxr_err(mdev, "failed to get clock 'vp'\n");
+               goto fail;
+       }
+       res->sclk_mixer = clk_get(dev, "sclk_mixer");
+       if (IS_ERR_OR_NULL(res->sclk_mixer)) {
+               mxr_err(mdev, "failed to get clock 'sclk_mixer'\n");
+               goto fail;
+       }
+#endif
+#if defined(CONFIG_CPU_EXYNOS4210)
+
+       res->sclk_dac = clk_get(dev, "sclk_dac");
+       if (IS_ERR_OR_NULL(res->sclk_dac)) {
+               mxr_err(mdev, "failed to get clock 'sclk_dac'\n");
+               goto fail;
+       }
+#endif
+       res->mixer = clk_get(dev, "mixer");
+       if (IS_ERR_OR_NULL(res->mixer)) {
+               mxr_err(mdev, "failed to get clock 'mixer'\n");
+               goto fail;
+       }
+       res->sclk_hdmi = clk_get(dev, "sclk_hdmi");
+       if (IS_ERR_OR_NULL(res->sclk_hdmi)) {
+               mxr_err(mdev, "failed to get clock 'sclk_hdmi'\n");
+               goto fail;
+       }
+
+       return 0;
+fail:
+       mxr_release_clocks(mdev);
+       return -ENODEV;
+}
+
+static int __devinit mxr_acquire_resources(struct mxr_device *mdev,
+       struct platform_device *pdev)
+{
+       int ret;
+       ret = mxr_acquire_plat_resources(mdev, pdev);
+
+       if (ret)
+               goto fail;
+
+       ret = mxr_acquire_clocks(mdev);
+       if (ret)
+               goto fail_plat;
+
+       mxr_info(mdev, "resources acquired\n");
+       return 0;
+
+fail_plat:
+       mxr_release_plat_resources(mdev);
+fail:
+       mxr_err(mdev, "resources acquire failed\n");
+       return ret;
+}
+
+static void mxr_release_resources(struct mxr_device *mdev)
+{
+       mxr_release_clocks(mdev);
+       mxr_release_plat_resources(mdev);
+       memset(&mdev->res, 0, sizeof mdev->res);
+}
+
+static void mxr_release_layers(struct mxr_device *mdev)
+{
+       int i, j;
+
+       for (i = 0; i < MXR_MAX_SUB_MIXERS; ++i) {
+               for (j = 0; j < MXR_MAX_LAYERS; ++j)
+                       if (mdev->sub_mxr[i].layer[j])
+                               mxr_layer_release(mdev->sub_mxr[i].layer[j]);
+       }
+}
+
+static int __devinit mxr_acquire_layers(struct mxr_device *mdev,
+       struct mxr_platform_data *pdata)
+{
+       struct sub_mxr_device *sub_mxr;
+
+       sub_mxr = &mdev->sub_mxr[MXR_SUB_MIXER0];
+#if defined(CONFIG_ARCH_EXYNOS4)
+       sub_mxr->layer[MXR_LAYER_VIDEO] = mxr_vp_layer_create(mdev,
+                       MXR_SUB_MIXER0, 0, EXYNOS_VIDEONODE_MXR_VIDEO);
+#else
+       sub_mxr->layer[MXR_LAYER_VIDEO] =
+               mxr_video_layer_create(mdev, MXR_SUB_MIXER0, 0);
+#endif
+       sub_mxr->layer[MXR_LAYER_GRP0] = mxr_graph_layer_create(mdev,
+                       MXR_SUB_MIXER0, 0, EXYNOS_VIDEONODE_MXR_GRP(0));
+       sub_mxr->layer[MXR_LAYER_GRP1] = mxr_graph_layer_create(mdev,
+                       MXR_SUB_MIXER0, 1, EXYNOS_VIDEONODE_MXR_GRP(1));
+       if (!sub_mxr->layer[MXR_LAYER_VIDEO] || !sub_mxr->layer[MXR_LAYER_GRP0]
+                       || !sub_mxr->layer[MXR_LAYER_GRP1]) {
+               mxr_err(mdev, "failed to acquire layers\n");
+               goto fail;
+       }
+
+       /* Exynos5250 supports 2 sub-mixers */
+       if (MXR_MAX_SUB_MIXERS == 2) {
+               sub_mxr = &mdev->sub_mxr[MXR_SUB_MIXER1];
+               sub_mxr->layer[MXR_LAYER_VIDEO] =
+                       mxr_video_layer_create(mdev, MXR_SUB_MIXER1, 1);
+               sub_mxr->layer[MXR_LAYER_GRP0] = mxr_graph_layer_create(mdev,
+                               MXR_SUB_MIXER1, 2, EXYNOS_VIDEONODE_MXR_GRP(2));
+               sub_mxr->layer[MXR_LAYER_GRP1] = mxr_graph_layer_create(mdev,
+                               MXR_SUB_MIXER1, 3, EXYNOS_VIDEONODE_MXR_GRP(3));
+               if (!sub_mxr->layer[MXR_LAYER_VIDEO] ||
+                               !sub_mxr->layer[MXR_LAYER_GRP0] ||
+                               !sub_mxr->layer[MXR_LAYER_GRP1]) {
+                       mxr_err(mdev, "failed to acquire layers\n");
+                       goto fail;
+               }
+       }
+
+       return 0;
+
+fail:
+       mxr_release_layers(mdev);
+       return -ENODEV;
+}
+
+/* ---------- POWER MANAGEMENT ----------- */
+
+static int mxr_runtime_resume(struct device *dev)
+{
+       struct mxr_device *mdev = to_mdev(dev);
+       struct mxr_resources *res = &mdev->res;
+
+       mxr_dbg(mdev, "resume - start\n");
+       mutex_lock(&mdev->mutex);
+       /* turn clocks on */
+       clk_enable(res->mixer);
+#if defined(CONFIG_ARCH_EXYNOS4)
+       clk_enable(res->vp);
+#endif
+#if defined(CONFIG_CPU_EXYNOS4210)
+       clk_enable(res->sclk_mixer);
+#endif
+       /* enable system mmu for tv. It must be enabled after enabling
+        * mixer's clock. Because of system mmu limitation. */
+       /*mdev->vb2->resume(mdev->alloc_ctx);*/
+       /* apply default configuration */
+       mxr_reg_reset(mdev);
+       mxr_dbg(mdev, "resume - finished\n");
+
+       mutex_unlock(&mdev->mutex);
+       return 0;
+}
+
+static int mxr_runtime_suspend(struct device *dev)
+{
+       struct mxr_device *mdev = to_mdev(dev);
+       struct mxr_resources *res = &mdev->res;
+       mxr_dbg(mdev, "suspend - start\n");
+       mutex_lock(&mdev->mutex);
+       /* disable system mmu for tv. It must be disabled before disabling
+        * mixer's clock. Because of system mmu limitation. */
+       /*mdev->vb2->suspend(mdev->alloc_ctx);*/
+       /* turn clocks off */
+#if defined(CONFIG_CPU_EXYNOS4210)
+       clk_disable(res->sclk_mixer);
+#endif
+#if defined(CONFIG_ARCH_EXYNOS4)
+       clk_disable(res->vp);
+#endif
+       clk_disable(res->mixer);
+       mutex_unlock(&mdev->mutex);
+       mxr_dbg(mdev, "suspend - finished\n");
+       return 0;
+}
+
+/* ---------- SUB-DEVICE CALLBACKS ----------- */
+
+static const struct dev_pm_ops mxr_pm_ops = {
+       .runtime_suspend = mxr_runtime_suspend,
+       .runtime_resume  = mxr_runtime_resume,
+};
+
+static int mxr_s_power(struct v4l2_subdev *sd, int on)
+{
+       return 0;
+}
+
+/* When mixer is connected to gscaler through local path, only gscaler's
+ * video device can command alpha blending functionality for mixer */
+static int mxr_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+       struct mxr_device *mdev = sd_to_mdev(sd);
+       int v = ctrl->value;
+       int num = 0;
+
+       mxr_dbg(mdev, "%s start\n", __func__);
+       mxr_dbg(mdev, "id = %d, value = %d\n", ctrl->id, ctrl->value);
+
+       if (!strcmp(sd->name, "s5p-mixer0"))
+               num = MXR_SUB_MIXER0;
+       else if (!strcmp(sd->name, "s5p-mixer1"))
+               num = MXR_SUB_MIXER1;
+
+       switch (ctrl->id) {
+       case V4L2_CID_TV_LAYER_BLEND_ENABLE:
+               mdev->sub_mxr[num].layer[MXR_LAYER_VIDEO]->layer_blend_en = v;
+               break;
+       case V4L2_CID_TV_LAYER_BLEND_ALPHA:
+               mdev->sub_mxr[num].layer[MXR_LAYER_VIDEO]->layer_alpha = (u32)v;
+               break;
+       case V4L2_CID_TV_PIXEL_BLEND_ENABLE:
+               mdev->sub_mxr[num].layer[MXR_LAYER_VIDEO]->pixel_blend_en = v;
+               break;
+       case V4L2_CID_TV_CHROMA_ENABLE:
+               mdev->sub_mxr[num].layer[MXR_LAYER_VIDEO]->chroma_en = v;
+               break;
+       case V4L2_CID_TV_CHROMA_VALUE:
+               mdev->sub_mxr[num].layer[MXR_LAYER_VIDEO]->chroma_val = (u32)v;
+               break;
+       default:
+               mxr_err(mdev, "invalid control id\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int mxr_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct mxr_device *mdev = sd_to_mdev(sd);
+       struct exynos_entity_data *md_data;
+       int ret;
+
+       /* It can be known which entity calls this function */
+       md_data = v4l2_get_subdevdata(sd);
+       mdev->mxr_data_from = md_data->mxr_data_from;
+
+       if (enable)
+               ret = mxr_streamer_get(mdev, sd);
+       else
+               ret = mxr_streamer_put(mdev, sd);
+
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static struct v4l2_mbus_framefmt *
+__mxr_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+               unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+       struct sub_mxr_device *sub_mxr = sd_to_sub_mxr(sd);
+
+       if (which == V4L2_SUBDEV_FORMAT_TRY)
+               return v4l2_subdev_get_try_format(fh, pad);
+       else
+               return &sub_mxr->mbus_fmt[pad];
+}
+
+static struct v4l2_rect *
+__mxr_get_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+               unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+       struct sub_mxr_device *sub_mxr = sd_to_sub_mxr(sd);
+
+       if (which == V4L2_SUBDEV_FORMAT_TRY)
+               return v4l2_subdev_get_try_crop(fh, pad);
+       else
+               return &sub_mxr->crop[pad];
+}
+
+static unsigned int mxr_adjust_graph_format(unsigned int code)
+{
+       switch (code) {
+       case V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE:
+       case V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE:
+       case V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE:
+       case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE:
+       case V4L2_MBUS_FMT_RGB565_2X8_BE:
+       case V4L2_MBUS_FMT_RGB565_2X8_LE:
+       case V4L2_MBUS_FMT_XRGB8888_4X8_LE:
+               return code;
+       default:
+               return V4L2_MBUS_FMT_XRGB8888_4X8_LE; /* default format */
+       }
+}
+
+/* This can be moved to graphic layer's callback function */
+static void mxr_set_layer_src_fmt(struct sub_mxr_device *sub_mxr, u32 pad)
+{
+       /* sink pad number and array index of layer are same */
+       struct mxr_layer *layer = sub_mxr->layer[pad];
+       struct v4l2_mbus_framefmt *fmt = &sub_mxr->mbus_fmt[pad];
+       u32 fourcc;
+
+       switch (fmt->code) {
+       case V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE:
+       case V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE:
+               fourcc = V4L2_PIX_FMT_RGB444;
+               break;
+       case V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE:
+       case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE:
+               fourcc = V4L2_PIX_FMT_RGB555;
+               break;
+       case V4L2_MBUS_FMT_RGB565_2X8_BE:
+       case V4L2_MBUS_FMT_RGB565_2X8_LE:
+               fourcc = V4L2_PIX_FMT_RGB565;
+               break;
+       case V4L2_MBUS_FMT_XRGB8888_4X8_LE:
+               fourcc = V4L2_PIX_FMT_BGR32;
+               break;
+       }
+       /* This will be applied to hardware right after streamon */
+       layer->fmt = find_format_by_fourcc(layer, fourcc);
+}
+
+static int mxr_try_format(struct mxr_device *mdev,
+               struct v4l2_subdev_fh *fh, u32 pad,
+               struct v4l2_mbus_framefmt *fmt,
+               enum v4l2_subdev_format_whence which)
+{
+       struct v4l2_mbus_framefmt mbus_fmt;
+
+       fmt->width = clamp_val(fmt->width, 1, 32767);
+       fmt->height = clamp_val(fmt->height, 1, 2047);
+
+       switch (pad) {
+       case MXR_PAD_SINK_GSCALER:
+               fmt->code = V4L2_MBUS_FMT_YUV8_1X24;
+               break;
+       case MXR_PAD_SINK_GRP0:
+       case MXR_PAD_SINK_GRP1:
+               fmt->code = mxr_adjust_graph_format(fmt->code);
+               break;
+       case MXR_PAD_SOURCE_GSCALER:
+       case MXR_PAD_SOURCE_GRP0:
+       case MXR_PAD_SOURCE_GRP1:
+               mxr_get_mbus_fmt(mdev, &mbus_fmt);
+               fmt->code = (fmt->code == V4L2_MBUS_FMT_YUV8_1X24) ?
+                       V4L2_MBUS_FMT_YUV8_1X24 : V4L2_MBUS_FMT_XRGB8888_4X8_LE;
+               fmt->width = mbus_fmt.width;
+               fmt->height = mbus_fmt.height;
+               break;
+       }
+
+       return 0;
+}
+
+static void mxr_apply_format(struct v4l2_subdev *sd,
+               struct v4l2_subdev_fh *fh, u32 pad,
+               struct v4l2_mbus_framefmt *fmt,
+               enum v4l2_subdev_format_whence which)
+{
+       struct sub_mxr_device *sub_mxr;
+       struct mxr_device *mdev;
+       int i, j;
+       sub_mxr = sd_to_sub_mxr(sd);
+       mdev = sd_to_mdev(sd);
+
+       if (which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+               if (pad == MXR_PAD_SINK_GRP0 || pad == MXR_PAD_SINK_GRP1) {
+                       struct mxr_layer *layer = sub_mxr->layer[pad];
+
+                       mxr_set_layer_src_fmt(sub_mxr, pad);
+                       layer->geo.src.full_width = fmt->width;
+                       layer->geo.src.full_height = fmt->height;
+                       layer->ops.fix_geometry(layer);
+               } else if (pad == MXR_PAD_SOURCE_GSCALER
+                               || pad == MXR_PAD_SOURCE_GRP0
+                               || pad == MXR_PAD_SOURCE_GRP1) {
+                       for (i = 0; i < MXR_MAX_LAYERS; ++i) {
+                               struct mxr_layer *layer = sub_mxr->layer[i];
+                               layer->geo.dst.full_width = fmt->width;
+                               layer->geo.dst.full_height = fmt->height;
+                               layer->ops.fix_geometry(layer);
+                       }
+                       for (i = 0; i < MXR_MAX_SUB_MIXERS; ++i) {
+                               sub_mxr = &mdev->sub_mxr[i];
+                               for (j = MXR_PAD_SOURCE_GSCALER;
+                                               j < MXR_PADS_NUM; ++j)
+                                       sub_mxr->mbus_fmt[j].code = fmt->code;
+                       }
+               }
+       }
+}
+
+static int mxr_try_crop(struct v4l2_subdev *sd,
+               struct v4l2_subdev_fh *fh, unsigned int pad,
+               struct v4l2_rect *r, enum v4l2_subdev_format_whence which)
+{
+       struct v4l2_mbus_framefmt *fmt;
+
+       fmt = __mxr_get_fmt(sd, fh, pad, which);
+       if (fmt == NULL)
+               return -EINVAL;
+
+       r->left = clamp_val(r->left, 0, fmt->width);
+       r->top = clamp_val(r->top, 0, fmt->height);
+       r->width = clamp_val(r->width, 1, fmt->width - r->left);
+       r->height = clamp_val(r->height, 1, fmt->height - r->top);
+
+       /* need to align size with G-Scaler */
+       if (pad == MXR_PAD_SINK_GSCALER || pad == MXR_PAD_SOURCE_GSCALER)
+               if (r->width % 2)
+                       r->width -= 1;
+
+       return 0;
+}
+
+static void mxr_apply_crop(struct v4l2_subdev *sd,
+               struct v4l2_subdev_fh *fh, unsigned int pad,
+               struct v4l2_rect *r, enum v4l2_subdev_format_whence which)
+{
+       struct sub_mxr_device *sub_mxr = sd_to_sub_mxr(sd);
+       struct mxr_layer *layer;
+
+       if (which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+               if (pad == MXR_PAD_SINK_GRP0 || pad == MXR_PAD_SINK_GRP1) {
+                       layer = sub_mxr->layer[pad];
+
+                       layer->geo.src.width = r->width;
+                       layer->geo.src.height = r->height;
+                       layer->geo.src.x_offset = r->left;
+                       layer->geo.src.y_offset = r->top;
+                       layer->ops.fix_geometry(layer);
+               } else if (pad == MXR_PAD_SOURCE_GSCALER
+                               || pad == MXR_PAD_SOURCE_GRP0
+                               || pad == MXR_PAD_SOURCE_GRP1) {
+                       layer = sub_mxr->layer[pad - (MXR_PADS_NUM >> 1)];
+
+                       layer->geo.dst.width = r->width;
+                       layer->geo.dst.height = r->height;
+                       layer->geo.dst.x_offset = r->left;
+                       layer->geo.dst.y_offset = r->top;
+                       layer->ops.fix_geometry(layer);
+               }
+       }
+}
+
+static int mxr_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+                      struct v4l2_subdev_format *format)
+{
+       struct v4l2_mbus_framefmt *fmt;
+
+       fmt = __mxr_get_fmt(sd, fh, format->pad, format->which);
+       if (fmt == NULL)
+               return -EINVAL;
+
+       format->format = *fmt;
+
+       return 0;
+}
+
+static int mxr_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+                      struct v4l2_subdev_format *format)
+{
+       struct mxr_device *mdev = sd_to_mdev(sd);
+       struct v4l2_mbus_framefmt *fmt;
+       int ret;
+       u32 pad;
+
+       fmt = __mxr_get_fmt(sd, fh, format->pad, format->which);
+       if (fmt == NULL)
+               return -EINVAL;
+
+       ret = mxr_try_format(mdev, fh, format->pad, &format->format,
+                       format->which);
+       if (ret)
+               return ret;
+
+       *fmt = format->format;
+
+       mxr_apply_format(sd, fh, format->pad, &format->format, format->which);
+
+       if (format->pad == MXR_PAD_SINK_GSCALER ||
+                       format->pad == MXR_PAD_SINK_GRP0 ||
+                       format->pad == MXR_PAD_SINK_GRP1) {
+               pad = format->pad + (MXR_PADS_NUM >> 1);
+               fmt = __mxr_get_fmt(sd, fh, pad, format->which);
+               if (fmt == NULL)
+                       return -EINVAL;
+
+               *fmt = format->format;
+
+               ret = mxr_try_format(mdev, fh, pad, fmt, format->which);
+               if (ret)
+                       return ret;
+
+               mxr_apply_format(sd, fh, pad, fmt, format->which);
+       }
+
+       return 0;
+}
+
+static int mxr_set_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+                      struct v4l2_subdev_crop *crop)
+{
+       struct v4l2_rect *r;
+       int ret;
+       u32 pad;
+
+       r = __mxr_get_crop(sd, fh, crop->pad, crop->which);
+       if (r == NULL)
+               return -EINVAL;
+
+       ret = mxr_try_crop(sd, fh, crop->pad, &crop->rect, crop->which);
+       if (ret)
+               return ret;
+
+       /* transfer adjusted crop information to user space */
+       *r = crop->rect;
+
+       /* reserved[0] is used for sink pad number temporally */
+       mxr_apply_crop(sd, fh, crop->pad, r, crop->which);
+
+       /* In case of sink pad, crop info will be propagated to source pad */
+       if (crop->pad == MXR_PAD_SINK_GSCALER ||
+                       crop->pad == MXR_PAD_SINK_GRP0 ||
+                       crop->pad == MXR_PAD_SINK_GRP1) {
+               pad = crop->pad + (MXR_PADS_NUM >> 1);
+               r = __mxr_get_crop(sd, fh, pad, crop->which);
+               if (r == NULL)
+                       return -EINVAL;
+               /* store propagated crop info to source pad */
+               *r = crop->rect;
+
+               ret = mxr_try_crop(sd, fh, pad, r, crop->which);
+               if (ret)
+                       return ret;
+
+               mxr_apply_crop(sd, fh, pad, r, crop->which);
+       }
+
+       return 0;
+}
+
+static int mxr_get_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+                      struct v4l2_subdev_crop *crop)
+{
+       struct v4l2_rect *r;
+
+       r = __mxr_get_crop(sd, fh, crop->pad, crop->which);
+       if (r == NULL)
+               return -EINVAL;
+
+       crop->rect = *r;
+
+       return 0;
+}
+
+static const struct v4l2_subdev_core_ops mxr_sd_core_ops = {
+       .s_power = mxr_s_power,
+       .s_ctrl = mxr_s_ctrl,
+};
+
+static const struct v4l2_subdev_video_ops mxr_sd_video_ops = {
+       .s_stream = mxr_s_stream,
+};
+
+static const struct v4l2_subdev_pad_ops        mxr_sd_pad_ops = {
+       .get_fmt = mxr_get_fmt,
+       .set_fmt = mxr_set_fmt,
+       .get_crop = mxr_get_crop,
+       .set_crop = mxr_set_crop
+};
+
+static const struct v4l2_subdev_ops mxr_sd_ops = {
+       .core = &mxr_sd_core_ops,
+       .video = &mxr_sd_video_ops,
+       .pad = &mxr_sd_pad_ops,
+};
+
+static int mxr_link_setup(struct media_entity *entity,
+                             const struct media_pad *local,
+                             const struct media_pad *remote, u32 flags)
+{
+       struct media_pad *pad;
+       struct sub_mxr_device *sub_mxr = entity_to_sub_mxr(entity);
+       struct mxr_device *mdev = sub_mxr_to_mdev(sub_mxr);
+       int i;
+       int gsc_num = 0;
+
+       /* difficult to get dev ptr */
+       printk(KERN_DEBUG "%s start\n", __func__);
+
+       if (flags & MEDIA_LNK_FL_ENABLED) {
+               sub_mxr->use = 1;
+               if (local->index == MXR_PAD_SINK_GSCALER)
+                       sub_mxr->local = 1;
+               /* find a remote pad by interating over all links
+                * until enabled link is found.
+                * This will be remove. because Exynos5250 only supports
+                * HDMI output */
+               pad = media_entity_remote_source((struct media_pad *)local);
+               if (pad) {
+                       printk(KERN_ERR "%s is already connected to %s\n",
+                                       entity->name, pad->entity->name);
+                       return -EBUSY;
+               }
+       } else {
+               if (local->index == MXR_PAD_SINK_GSCALER)
+                       sub_mxr->local = 0;
+               sub_mxr->use = 0;
+               for (i = 0; i < entity->num_links; ++i)
+                       if (entity->links[i].flags & MEDIA_LNK_FL_ENABLED)
+                               sub_mxr->use = 1;
+       }
+
+       if (!strcmp(remote->entity->name, "exynos-gsc-sd.0"))
+               gsc_num = 0;
+       else if (!strcmp(remote->entity->name, "exynos-gsc-sd.1"))
+               gsc_num = 1;
+       else if (!strcmp(remote->entity->name, "exynos-gsc-sd.2"))
+               gsc_num = 2;
+       else if (!strcmp(remote->entity->name, "exynos-gsc-sd.3"))
+               gsc_num = 3;
+
+       if (!strcmp(local->entity->name, "s5p-mixer0"))
+               mdev->mxr0_gsc = gsc_num;
+       else if (!strcmp(local->entity->name, "s5p-mixer1"))
+               mdev->mxr1_gsc = gsc_num;
+
+       /* deliver those variables to mxr_streamer_get() */
+       mdev->flags = flags;
+       return 0;
+}
+
+/* mixer entity operations */
+static const struct media_entity_operations mxr_entity_ops = {
+       .link_setup = mxr_link_setup,
+};
+
+/* ---------- MEDIA CONTROLLER MANAGEMENT ----------- */
+
+static int mxr_register_entity(struct mxr_device *mdev, int mxr_num)
+{
+       struct v4l2_subdev *sd = &mdev->sub_mxr[mxr_num].sd;
+       struct media_pad *pads = mdev->sub_mxr[mxr_num].pads;
+       struct media_entity *me = &sd->entity;
+       struct exynos_md *md;
+       int ret;
+
+       mxr_dbg(mdev, "mixer%d entity init\n", mxr_num);
+
+       /* init mixer sub-device */
+       v4l2_subdev_init(sd, &mxr_sd_ops);
+       sd->owner = THIS_MODULE;
+       sprintf(sd->name, "s5p-mixer%d", mxr_num);
+
+       /* mixer sub-device can be opened in user space */
+       sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+       /* init mixer sub-device as entity */
+       pads[MXR_PAD_SINK_GSCALER].flags = MEDIA_PAD_FL_SINK;
+       pads[MXR_PAD_SINK_GRP0].flags = MEDIA_PAD_FL_SINK;
+       pads[MXR_PAD_SINK_GRP1].flags = MEDIA_PAD_FL_SINK;
+       pads[MXR_PAD_SOURCE_GSCALER].flags = MEDIA_PAD_FL_SOURCE;
+       pads[MXR_PAD_SOURCE_GRP0].flags = MEDIA_PAD_FL_SOURCE;
+       pads[MXR_PAD_SOURCE_GRP1].flags = MEDIA_PAD_FL_SOURCE;
+       me->ops = &mxr_entity_ops;
+       ret = media_entity_init(me, MXR_PADS_NUM, pads, 0);
+       if (ret) {
+               mxr_err(mdev, "failed to initialize media entity\n");
+               return ret;
+       }
+
+       md = (struct exynos_md *)module_name_to_driver_data(MDEV_MODULE_NAME);
+       if (!md) {
+               mxr_err(mdev, "failed to get output media device\n");
+               return -ENODEV;
+       }
+
+       ret = v4l2_device_register_subdev(&md->v4l2_dev, sd);
+       if (ret) {
+               mxr_err(mdev, "failed to register mixer subdev\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int mxr_register_entities(struct mxr_device *mdev)
+{
+       int ret, i;
+
+       for (i = 0; i < MXR_MAX_SUB_MIXERS; ++i) {
+               ret = mxr_register_entity(mdev, i);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static void mxr_unregister_entity(struct mxr_device *mdev, int mxr_num)
+{
+       v4l2_device_unregister_subdev(&mdev->sub_mxr[mxr_num].sd);
+}
+
+static void mxr_unregister_entities(struct mxr_device *mdev)
+{
+       int i;
+
+       for (i = 0; i < MXR_MAX_SUB_MIXERS; ++i)
+               mxr_unregister_entity(mdev, i);
+}
+
+static void mxr_entities_info_print(struct mxr_device *mdev)
+{
+       struct v4l2_subdev *sd;
+       struct media_entity *sd_me;
+       struct media_entity *vd_me;
+       int num_layers;
+       int i, j;
+
+#if defined(CONFIG_ARCH_EXYNOS4)
+       num_layers = 3;
+#else
+       num_layers = 2;
+#endif
+       mxr_dbg(mdev, "\n************ MIXER entities info ***********\n");
+
+       for (i = 0; i < MXR_MAX_SUB_MIXERS; ++i) {
+               mxr_dbg(mdev, "[SUB DEVICE INFO]\n");
+               sd = &mdev->sub_mxr[i].sd;
+               sd_me = &sd->entity;
+               entity_info_print(sd_me, mdev->dev);
+
+               for (j = 0; j < num_layers; ++j) {
+                       vd_me = &mdev->sub_mxr[i].layer[j]->vfd.entity;
+
+                       mxr_dbg(mdev, "\n[VIDEO DEVICE %d INFO]\n", j);
+                       entity_info_print(vd_me, mdev->dev);
+               }
+       }
+
+       mxr_dbg(mdev, "**************************************************\n\n");
+}
+
+static int mxr_create_links_sub_mxr(struct mxr_device *mdev, int mxr_num,
+               int flags)
+{
+       struct exynos_md *md;
+       struct mxr_layer *layer;
+       int ret;
+       int i, j;
+       char err[80];
+
+       mxr_info(mdev, "mixer%d create links\n", mxr_num);
+
+       memset(err, 0, sizeof(err));
+
+       /* link creation : gscaler0~3[1] -> mixer[0] */
+       md = (struct exynos_md *)module_name_to_driver_data(MDEV_MODULE_NAME);
+       for (i = 0; i < MAX_GSC_SUBDEV; ++i) {
+               if (md->gsc_sd[i] != NULL) {
+                       ret = media_entity_create_link(&md->gsc_sd[i]->entity,
+                               GSC_OUT_PAD_SOURCE,
+                               &mdev->sub_mxr[mxr_num].sd.entity,
+                               MXR_PAD_SINK_GSCALER, 0);
+                       if (ret) {
+                               sprintf(err, "%s --> %s",
+                                       md->gsc_sd[i]->entity.name,
+                                       mdev->sub_mxr[mxr_num].sd.entity.name);
+                               goto fail;
+                       }
+               }
+       }
+
+       /* link creation : mixer input0[0] -> mixer[1] */
+       layer = mdev->sub_mxr[mxr_num].layer[MXR_LAYER_GRP0];
+       ret = media_entity_create_link(&layer->vfd.entity, 0,
+               &mdev->sub_mxr[mxr_num].sd.entity, MXR_PAD_SINK_GRP0, flags);
+       if (ret) {
+               sprintf(err, "%s --> %s", layer->vfd.entity.name,
+                               mdev->sub_mxr[mxr_num].sd.entity.name);
+               goto fail;
+       }
+
+       /* link creation : mixer input1[0] -> mixer[2] */
+       layer = mdev->sub_mxr[mxr_num].layer[MXR_LAYER_GRP1];
+       ret = media_entity_create_link(&layer->vfd.entity, 0,
+               &mdev->sub_mxr[mxr_num].sd.entity, MXR_PAD_SINK_GRP1, flags);
+       if (ret) {
+               sprintf(err, "%s --> %s", layer->vfd.entity.name,
+                               mdev->sub_mxr[mxr_num].sd.entity.name);
+               goto fail;
+       }
+
+       /* link creation : mixer[3,4,5] -> output device(hdmi or sdo)[0] */
+       mxr_dbg(mdev, "output device count = %d\n", mdev->output_cnt);
+       for (i = 0; i < mdev->output_cnt; ++i) { /* sink pad of hdmi/sdo is 0 */
+               flags = 0;
+               /* default output device link is HDMI */
+               if (!strcmp(mdev->output[i]->sd->name, "exynos5-hdmi"))
+                       flags = MEDIA_LNK_FL_ENABLED;
+
+               for (j = MXR_PAD_SOURCE_GSCALER; j < MXR_PADS_NUM; ++j) {
+                       ret = media_entity_create_link(
+                                       &mdev->sub_mxr[mxr_num].sd.entity,
+                                       j, &mdev->output[i]->sd->entity,
+                                       0, flags);
+                       if (ret) {
+                               sprintf(err, "%s --> %s",
+                                       mdev->sub_mxr[mxr_num].sd.entity.name,
+                                       mdev->output[i]->sd->entity.name);
+                               goto fail;
+                       }
+               }
+       }
+
+       return 0;
+
+fail:
+       mxr_err(mdev, "failed to create link : %s\n", err);
+       return ret;
+}
+
+static int mxr_create_links(struct mxr_device *mdev)
+{
+       int ret, i;
+       int flags;
+
+#if defined(CONFIG_ARCH_EXYNOS4)
+       struct mxr_layer *layer;
+       struct media_entity *source, *sink;
+
+       layer = mdev->sub_mxr[MXR_SUB_MIXER0].layer[MXR_LAYER_VIDEO];
+       source = &layer->vfd.entity;
+       sink = &mdev->sub_mxr[MXR_SUB_MIXER0].sd.entity;
+       ret = media_entity_create_link(source, 0, sink, MXR_PAD_SINK_GSCALER,
+                       MEDIA_LNK_FL_ENABLED);
+#endif
+       for (i = 0; i < MXR_MAX_SUB_MIXERS; ++i) {
+               if (mdev->sub_mxr[i].use)
+                       flags = MEDIA_LNK_FL_ENABLED;
+               else
+                       flags = 0;
+
+               ret = mxr_create_links_sub_mxr(mdev, i, flags);
+               if (ret)
+                       return ret;
+       }
+
+       mxr_info(mdev, "mixer links are created successfully\n");
+
+       return 0;
+}
+
+/* --------- DRIVER INITIALIZATION ---------- */
+
+static int __devinit mxr_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct mxr_platform_data *pdata = dev->platform_data;
+       struct mxr_device *mdev;
+       int ret;
+
+       /* mdev does not exist yet so no mxr_dbg is used */
+       dev_info(dev, "probe start\n");
+
+       mdev = kzalloc(sizeof *mdev, GFP_KERNEL);
+       if (!mdev) {
+               mxr_err(mdev, "not enough memory.\n");
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       /* setup pointer to master device */
+       mdev->dev = dev;
+       /* use only sub mixer0 as default */
+       mdev->sub_mxr[MXR_SUB_MIXER0].use = 1;
+
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+       mdev->vb2 = &mxr_vb2_cma;
+#elif defined(CONFIG_VIDEOBUF2_DMA_CONTIG)
+       mdev->vb2 = &mxr_vb2_dma_contig;
+#endif
+
+       mutex_init(&mdev->mutex);
+       mutex_init(&mdev->s_mutex);
+       spin_lock_init(&mdev->reg_slock);
+       init_waitqueue_head(&mdev->event_queue);
+
+       /* acquire resources: regs, irqs, clocks, regulators */
+       ret = mxr_acquire_resources(mdev, pdev);
+       if (ret)
+               goto fail_mem;
+
+       /* configure resources for video output */
+       ret = mxr_acquire_video(mdev, mxr_output_conf,
+               ARRAY_SIZE(mxr_output_conf));
+       if (ret)
+               goto fail_resources;
+
+       /* register mixer subdev as entity */
+       ret = mxr_register_entities(mdev);
+       if (ret)
+               goto fail_video;
+
+       /* configure layers */
+       ret = mxr_acquire_layers(mdev, pdata);
+       if (ret)
+               goto fail_entity;
+
+       /* create links connected to gscaler, mixer inputs and hdmi */
+       ret = mxr_create_links(mdev);
+       if (ret)
+               goto fail_entity;
+
+       dev_set_drvdata(dev, mdev);
+
+       pm_runtime_enable(dev);
+
+       mxr_entities_info_print(mdev);
+
+       mxr_info(mdev, "probe successful\n");
+       my_gbl_mdev = mdev;
+       memcpy(my_gbl_mdev, mdev, sizeof(mdev));
+       printk(KERN_CRIT"PROBE END");
+       return 0;
+
+fail_entity:
+       mxr_unregister_entities(mdev);
+
+fail_video:
+       mxr_release_video(mdev);
+
+fail_resources:
+       mxr_release_resources(mdev);
+
+fail_mem:
+       kfree(mdev);
+
+fail:
+       dev_info(dev, "probe failed\n");
+       return ret;
+}
+
+static int __devexit mxr_remove(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct mxr_device *mdev = to_mdev(dev);
+
+       pm_runtime_disable(dev);
+
+       mxr_release_layers(mdev);
+       mxr_release_video(mdev);
+       mxr_release_resources(mdev);
+
+       kfree(mdev);
+
+       dev_info(dev, "remove sucessful\n");
+       return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id exynos_mixer_match[] = {
+       { .compatible = "samsung,s5p-mixer" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, exynos_mixer_match);
+#endif
+
+static struct platform_driver mxr_driver __refdata = {
+       .probe = mxr_probe,
+       .remove = __devexit_p(mxr_remove),
+       .driver = {
+               .name = MXR_DRIVER_NAME,
+               .owner = THIS_MODULE,
+               .pm = &mxr_pm_ops,
+               .of_match_table = of_match_ptr(exynos_mixer_match),
+       }
+};
+
+static int __init mxr_init(void)
+{
+       int i, ret;
+       static const char banner[] __initdata = KERN_INFO
+               "Samsung TV Mixer driver, "
+               "(c) 2010-2011 Samsung Electronics Co., Ltd.\n";
+       printk(banner);
+
+       /* Loading auxiliary modules */
+       for (i = 0; i < ARRAY_SIZE(mxr_output_conf); ++i)
+               request_module(mxr_output_conf[i].module_name);
+
+       ret = platform_driver_register(&mxr_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "registration of MIXER driver failed\n");
+               return -ENXIO;
+       }
+
+       return 0;
+}
+module_init(mxr_init);
+/*late_initcall(mxr_init);*/
+
+static void __exit mxr_exit(void)
+{
+       platform_driver_unregister(&mxr_driver);
+}
+module_exit(mxr_exit);
diff --git a/drivers/media/video/exynos/tv/mixer_grp_layer.c b/drivers/media/video/exynos/tv/mixer_grp_layer.c
new file mode 100644 (file)
index 0000000..3309c21
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * Samsung TV Mixer driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.com>
+ *
+ * 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 Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#include "mixer.h"
+
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+#include <media/videobuf2-cma-phys.h>
+#elif defined(CONFIG_VIDEOBUF2_ION)
+#include <media/videobuf2-ion.h>
+#endif
+
+/* FORMAT DEFINITIONS */
+
+static const struct mxr_format mxr_fb_fmt_rgb565 = {
+       .name = "RGB565",
+       .fourcc = V4L2_PIX_FMT_RGB565,
+       .colorspace = V4L2_COLORSPACE_SRGB,
+       .num_planes = 1,
+       .plane = {
+               { .width = 1, .height = 1, .size = 2 },
+       },
+       .num_subframes = 1,
+       .cookie = 4,
+};
+
+static const struct mxr_format mxr_fb_fmt_argb1555 = {
+       .name = "ARGB1555",
+       .num_planes = 1,
+       .fourcc = V4L2_PIX_FMT_RGB555,
+       .colorspace = V4L2_COLORSPACE_SRGB,
+       .plane = {
+               { .width = 1, .height = 1, .size = 2 },
+       },
+       .num_subframes = 1,
+       .cookie = 5,
+};
+
+static const struct mxr_format mxr_fb_fmt_argb4444 = {
+       .name = "ARGB4444",
+       .num_planes = 1,
+       .fourcc = V4L2_PIX_FMT_RGB444,
+       .colorspace = V4L2_COLORSPACE_SRGB,
+       .plane = {
+               { .width = 1, .height = 1, .size = 2 },
+       },
+       .num_subframes = 1,
+       .cookie = 6,
+};
+
+static const struct mxr_format mxr_fb_fmt_argb8888 = {
+       .name = "ARGB8888",
+       .fourcc = V4L2_PIX_FMT_BGR32,
+       .colorspace = V4L2_COLORSPACE_SRGB,
+       .num_planes = 1,
+       .plane = {
+               { .width = 1, .height = 1, .size = 4 },
+       },
+       .num_subframes = 1,
+       .cookie = 7,
+};
+
+static const struct mxr_format *mxr_graph_format[] = {
+       &mxr_fb_fmt_rgb565,
+       &mxr_fb_fmt_argb1555,
+       &mxr_fb_fmt_argb4444,
+       &mxr_fb_fmt_argb8888,
+};
+
+/* AUXILIARY CALLBACKS */
+
+static void mxr_graph_layer_release(struct mxr_layer *layer)
+{
+       mxr_base_layer_unregister(layer);
+       mxr_base_layer_release(layer);
+}
+
+static void mxr_graph_buffer_set(struct mxr_layer *layer,
+       struct mxr_buffer *buf)
+{
+       struct mxr_device *mdev = layer->mdev;
+       dma_addr_t addr = 0;
+
+       if (buf)
+               addr = mdev->vb2->plane_addr(&buf->vb, 0);
+       mxr_reg_graph_buffer(layer->mdev, layer->idx, addr);
+}
+
+static void mxr_graph_stream_set(struct mxr_layer *layer, int en)
+{
+       mxr_reg_graph_layer_stream(layer->mdev, layer->idx, en);
+}
+
+static void mxr_graph_format_set(struct mxr_layer *layer)
+{
+       mxr_reg_graph_format(layer->mdev, layer->idx,
+                       layer->fmt, &layer->geo);
+}
+
+static void mxr_graph_fix_geometry(struct mxr_layer *layer)
+{
+       struct mxr_geometry *geo = &layer->geo;
+
+       mxr_dbg(layer->mdev, "%s start\n", __func__);
+       /* limit to boundary size */
+       geo->src.full_width = clamp_val(geo->src.full_width, 1, 32767);
+       geo->src.full_height = clamp_val(geo->src.full_height, 1, 2047);
+
+       /* limit to coordinate of source x, y */
+       geo->src.x_offset = clamp_val(geo->src.x_offset, 0,
+                       geo->src.full_width - 1);
+       geo->src.y_offset = clamp_val(geo->src.y_offset, 0,
+                       geo->src.full_height - 1);
+
+       /* limit to boundary size of crop width, height */
+       geo->src.width = clamp_val(geo->src.width, 1,
+                       geo->src.full_width - geo->src.x_offset);
+       geo->src.height = clamp_val(geo->src.height, 1,
+                       geo->src.full_height - geo->src.y_offset);
+
+       /* dst full resolution and TV display size are same */
+
+       geo->dst.x_offset = clamp_val(geo->dst.x_offset, 0,
+                       geo->dst.full_width - 1);
+       geo->dst.y_offset = clamp_val(geo->dst.y_offset, 0,
+                       geo->dst.full_height - 1);
+
+       /* mixer scale-up is unuseful. so no use it */
+       geo->dst.width = clamp_val(geo->src.width, 1,
+                       geo->dst.full_width - geo->dst.x_offset);
+       geo->dst.height = clamp_val(geo->src.height, 1,
+                       geo->dst.full_height - geo->dst.y_offset);
+}
+
+/* PUBLIC API */
+
+struct mxr_layer *mxr_graph_layer_create(struct mxr_device *mdev, int cur_mxr,
+               int idx, int nr)
+{
+       struct mxr_layer *layer;
+       int ret;
+       struct mxr_layer_ops ops = {
+               .release = mxr_graph_layer_release,
+               .buffer_set = mxr_graph_buffer_set,
+               .stream_set = mxr_graph_stream_set,
+               .format_set = mxr_graph_format_set,
+               .fix_geometry = mxr_graph_fix_geometry,
+       };
+       char name[32];
+
+       sprintf(name, "mxr%d_graph%d", cur_mxr, idx);
+
+       layer = mxr_base_layer_create(mdev, idx, name, &ops);
+       if (layer == NULL) {
+               mxr_err(mdev, "failed to initialize layer(%d) base\n", idx);
+               goto fail;
+       }
+
+       layer->fmt_array = mxr_graph_format;
+       layer->fmt_array_size = ARRAY_SIZE(mxr_graph_format);
+       layer->minor = nr;
+       layer->type = MXR_LAYER_TYPE_GRP;
+
+       ret = mxr_base_layer_register(layer);
+       if (ret)
+               goto fail_layer;
+
+       layer->cur_mxr = cur_mxr;
+       return layer;
+
+fail_layer:
+       mxr_base_layer_release(layer);
+
+fail:
+       return NULL;
+}
diff --git a/drivers/media/video/exynos/tv/mixer_reg.c b/drivers/media/video/exynos/tv/mixer_reg.c
new file mode 100644 (file)
index 0000000..c905b90
--- /dev/null
@@ -0,0 +1,928 @@
+/*
+ * Samsung TV Mixer driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.com>
+ *
+ * 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 Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#include "mixer.h"
+#include "regs-mixer.h"
+#include "regs-vp.h"
+
+#include <linux/delay.h>
+
+/* Register access subroutines */
+static inline u32 vp_read(struct mxr_device *mdev, u32 reg_id)
+{
+#if defined(CONFIG_ARCH_EXYNOS4)
+       return readl(mdev->res.vp_regs + reg_id);
+#else
+       return 0;
+#endif
+}
+
+static inline void vp_write(struct mxr_device *mdev, u32 reg_id, u32 val)
+{
+#if defined(CONFIG_ARCH_EXYNOS4)
+       writel(val, mdev->res.vp_regs + reg_id);
+#endif
+}
+
+static inline void vp_write_mask(struct mxr_device *mdev, u32 reg_id,
+       u32 val, u32 mask)
+{
+#if defined(CONFIG_ARCH_EXYNOS4)
+       u32 old = vp_read(mdev, reg_id);
+
+       val = (val & mask) | (old & ~mask);
+       writel(val, mdev->res.vp_regs + reg_id);
+#endif
+}
+
+static inline u32 mxr_read(struct mxr_device *mdev, u32 reg_id)
+{
+       return readl(mdev->res.mxr_regs + reg_id);
+}
+
+static inline void mxr_write(struct mxr_device *mdev, u32 reg_id, u32 val)
+{
+       writel(val, mdev->res.mxr_regs + reg_id);
+}
+
+static inline void mxr_write_mask(struct mxr_device *mdev, u32 reg_id,
+       u32 val, u32 mask)
+{
+       u32 old = mxr_read(mdev, reg_id);
+
+       val = (val & mask) | (old & ~mask);
+       writel(val, mdev->res.mxr_regs + reg_id);
+}
+
+void mxr_layer_sync(struct mxr_device *mdev, int en)
+{
+       mxr_write_mask(mdev, MXR_STATUS, en ? MXR_STATUS_LAYER_SYNC : 0,
+               MXR_STATUS_LAYER_SYNC);
+}
+void mxr_vsync_set_update(struct mxr_device *mdev, int en)
+{
+       /* block update on vsync */
+       mxr_write_mask(mdev, MXR_STATUS, en ? MXR_STATUS_SYNC_ENABLE : 0,
+               MXR_STATUS_SYNC_ENABLE);
+#if defined(CONFIG_ARCH_EXYNOS4)
+       vp_write(mdev, VP_SHADOW_UPDATE, en ? VP_SHADOW_UPDATE_ENABLE : 0);
+#endif
+}
+
+static void __mxr_reg_vp_reset(struct mxr_device *mdev)
+{
+#if defined(CONFIG_ARCH_EXYNOS4)
+       int tries = 100;
+
+       vp_write(mdev, VP_SRESET, VP_SRESET_PROCESSING);
+       for (tries = 100; tries; --tries) {
+               /* waiting until VP_SRESET_PROCESSING is 0 */
+               if (~vp_read(mdev, VP_SRESET) & VP_SRESET_PROCESSING)
+                       break;
+               mdelay(10);
+       }
+       WARN(tries == 0, "failed to reset Video Processor\n");
+#endif
+}
+
+static void mxr_reg_sub_mxr_reset(struct mxr_device *mdev, int mxr_num)
+{
+       u32 val; /* value stored to register */
+
+       if (mxr_num == MXR_SUB_MIXER0) {
+               /* setting default layer priority: layer1 > layer0 > video
+                * because typical usage scenario would be
+                * layer0,1 - UI overlay
+                * video - video playback
+                */
+               val  = MXR_LAYER_CFG_GRP1_VAL(3);
+               val |= MXR_LAYER_CFG_GRP0_VAL(2);
+               val |= MXR_LAYER_CFG_VP_VAL(1);
+               mxr_write(mdev, MXR_LAYER_CFG, val);
+
+               /* use dark gray background color */
+               mxr_write(mdev, MXR_BG_COLOR0, 0x008080);
+               mxr_write(mdev, MXR_BG_COLOR1, 0x008080);
+               mxr_write(mdev, MXR_BG_COLOR2, 0x008080);
+
+               /* setting graphical layers */
+
+               val  = MXR_GRP_CFG_BLANK_KEY_OFF; /* no blank key */
+               val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
+
+               /* the same configuration for both layers */
+               mxr_write(mdev, MXR_GRAPHIC_CFG(0), val);
+               mxr_write(mdev, MXR_GRAPHIC_CFG(1), val);
+       } else if (mxr_num == MXR_SUB_MIXER1) {
+               val  = MXR_LAYER_CFG_GRP1_VAL(3);
+               val |= MXR_LAYER_CFG_GRP0_VAL(2);
+               val |= MXR_LAYER_CFG_VP_VAL(1);
+               mxr_write(mdev, MXR1_LAYER_CFG, val);
+
+               /* use dark gray background color */
+               mxr_write(mdev, MXR1_BG_COLOR0, 0x008080);
+               mxr_write(mdev, MXR1_BG_COLOR1, 0x008080);
+               mxr_write(mdev, MXR1_BG_COLOR2, 0x008080);
+
+               /* setting graphical layers */
+
+               val  = MXR_GRP_CFG_BLANK_KEY_OFF; /* no blank key */
+               val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
+
+               /* the same configuration for both layers */
+               mxr_write(mdev, MXR1_GRAPHIC_CFG(0), val);
+               mxr_write(mdev, MXR1_GRAPHIC_CFG(1), val);
+       }
+}
+
+static void mxr_reg_vp_default_filter(struct mxr_device *mdev);
+
+void mxr_reg_reset(struct mxr_device *mdev)
+{
+       int i;
+       unsigned long flags;
+
+       spin_lock_irqsave(&mdev->reg_slock, flags);
+
+       mxr_write_mask(mdev, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET);
+       mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+       /* set output in RGB888 mode */
+       mxr_write(mdev, MXR_CFG, MXR_CFG_OUT_RGB888);
+
+       /* 16 beat burst in DMA */
+       mxr_write_mask(mdev, MXR_STATUS, MXR_STATUS_16_BURST,
+               MXR_STATUS_BURST_MASK);
+
+       for (i = 0; i < MXR_MAX_SUB_MIXERS; ++i)
+               mxr_reg_sub_mxr_reset(mdev, i);
+
+       /* configuration of Video Processor Registers */
+       __mxr_reg_vp_reset(mdev);
+       mxr_reg_vp_default_filter(mdev);
+
+       /* enable all interrupts */
+       mxr_write_mask(mdev, MXR_INT_EN, ~0, MXR_INT_EN_ALL);
+
+       mxr_vsync_set_update(mdev, MXR_ENABLE);
+       spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+void mxr_reg_graph_format(struct mxr_device *mdev, int idx,
+       const struct mxr_format *fmt, const struct mxr_geometry *geo)
+{
+       u32 wh, sxy, dxy;
+       unsigned long flags;
+
+       spin_lock_irqsave(&mdev->reg_slock, flags);
+       mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+       /* Mostly, src width, height and dst width, height are same.
+        * However, in case of doing src and dst cropping, those are different.
+        * So you have to write dst width and height to MXR_GRAPHIC_WH register.
+        */
+       wh  = MXR_GRP_WH_WIDTH(geo->dst.width);
+       wh |= MXR_GRP_WH_HEIGHT(geo->dst.height);
+       wh |= MXR_GRP_WH_H_SCALE(geo->x_ratio);
+       wh |= MXR_GRP_WH_V_SCALE(geo->y_ratio);
+
+       /* setup offsets in source image */
+       sxy  = MXR_GRP_SXY_SX(geo->src.x_offset);
+       sxy |= MXR_GRP_SXY_SY(geo->src.y_offset);
+
+       /* setup offsets in display image */
+       dxy  = MXR_GRP_DXY_DX(geo->dst.x_offset);
+       dxy |= MXR_GRP_DXY_DY(geo->dst.y_offset);
+
+       if (idx == 0) {
+               mxr_write_mask(mdev, MXR_GRAPHIC_CFG(0),
+                               MXR_GRP_CFG_FORMAT_VAL(fmt->cookie),
+                               MXR_GRP_CFG_FORMAT_MASK);
+               mxr_write(mdev, MXR_GRAPHIC_SPAN(0), geo->src.full_width);
+               mxr_write(mdev, MXR_GRAPHIC_WH(0), wh);
+               mxr_write(mdev, MXR_GRAPHIC_SXY(0), sxy);
+               mxr_write(mdev, MXR_GRAPHIC_DXY(0), dxy);
+       } else if (idx == 1) {
+               mxr_write_mask(mdev, MXR_GRAPHIC_CFG(1),
+                               MXR_GRP_CFG_FORMAT_VAL(fmt->cookie),
+                               MXR_GRP_CFG_FORMAT_MASK);
+               mxr_write(mdev, MXR_GRAPHIC_SPAN(1), geo->src.full_width);
+               mxr_write(mdev, MXR_GRAPHIC_WH(1), wh);
+               mxr_write(mdev, MXR_GRAPHIC_SXY(1), sxy);
+               mxr_write(mdev, MXR_GRAPHIC_DXY(1), dxy);
+       } else if (idx == 2) {
+               mxr_write_mask(mdev, MXR1_GRAPHIC_CFG(0),
+                               MXR_GRP_CFG_FORMAT_VAL(fmt->cookie),
+                               MXR_GRP_CFG_FORMAT_MASK);
+               mxr_write(mdev, MXR1_GRAPHIC_SPAN(0), geo->src.full_width);
+               mxr_write(mdev, MXR1_GRAPHIC_WH(0), wh);
+               mxr_write(mdev, MXR1_GRAPHIC_SXY(0), sxy);
+               mxr_write(mdev, MXR1_GRAPHIC_DXY(0), dxy);
+       } else if (idx == 3) {
+               mxr_write_mask(mdev, MXR1_GRAPHIC_CFG(1),
+                               MXR_GRP_CFG_FORMAT_VAL(fmt->cookie),
+                               MXR_GRP_CFG_FORMAT_MASK);
+               mxr_write(mdev, MXR1_GRAPHIC_SPAN(1), geo->src.full_width);
+               mxr_write(mdev, MXR1_GRAPHIC_WH(1), wh);
+               mxr_write(mdev, MXR1_GRAPHIC_SXY(1), sxy);
+               mxr_write(mdev, MXR1_GRAPHIC_DXY(1), dxy);
+       }
+
+       mxr_vsync_set_update(mdev, MXR_ENABLE);
+       spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+void mxr_reg_video_geo(struct mxr_device *mdev, int cur_mxr, int idx,
+               const struct mxr_geometry *geo)
+{
+       u32 lt, rb;
+       unsigned long flags;
+
+       mxr_dbg(mdev, "%s\n", __func__);
+
+       spin_lock_irqsave(&mdev->reg_slock, flags);
+       mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+       lt  = MXR_VIDEO_LT_LEFT_VAL(geo->dst.x_offset);
+       lt |= MXR_VIDEO_LT_TOP_VAL(geo->dst.y_offset);
+       rb  = MXR_VIDEO_RB_RIGHT_VAL(geo->dst.x_offset + geo->dst.width - 1);
+       rb |= MXR_VIDEO_RB_BOTTOM_VAL(geo->dst.y_offset + geo->dst.height - 1);
+
+       if (cur_mxr == MXR_SUB_MIXER0) {
+               mxr_write(mdev, MXR_VIDEO_LT, lt);
+               mxr_write(mdev, MXR_VIDEO_RB, rb);
+       } else if (cur_mxr == MXR_SUB_MIXER1) {
+               mxr_write(mdev, MXR1_VIDEO_LT, lt);
+               mxr_write(mdev, MXR1_VIDEO_RB, rb);
+       }
+
+       mxr_vsync_set_update(mdev, MXR_ENABLE);
+       spin_unlock_irqrestore(&mdev->reg_slock, flags);
+
+       mxr_dbg(mdev, "destination x = %d, y = %d, width = %d, height = %d\n",
+                       geo->dst.x_offset, geo->dst.y_offset,
+                       geo->dst.width, geo->dst.height);
+}
+
+void mxr_reg_vp_format(struct mxr_device *mdev,
+       const struct mxr_format *fmt, const struct mxr_geometry *geo)
+{
+#if defined(CONFIG_ARCH_EXYNOS4)
+       unsigned long flags;
+
+       spin_lock_irqsave(&mdev->reg_slock, flags);
+       mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+       vp_write_mask(mdev, VP_MODE, fmt->cookie, VP_MODE_FMT_MASK);
+
+       /* setting size of input image */
+       vp_write(mdev, VP_IMG_SIZE_Y, VP_IMG_HSIZE(geo->src.full_width) |
+               VP_IMG_VSIZE(geo->src.full_height));
+       /* chroma height has to reduced by 2 to avoid chroma distorions */
+       vp_write(mdev, VP_IMG_SIZE_C, VP_IMG_HSIZE(geo->src.full_width) |
+               VP_IMG_VSIZE(geo->src.full_height / 2));
+
+       vp_write(mdev, VP_SRC_WIDTH, geo->src.width);
+       vp_write(mdev, VP_SRC_HEIGHT, geo->src.height);
+       vp_write(mdev, VP_SRC_H_POSITION,
+               VP_SRC_H_POSITION_VAL(geo->src.x_offset));
+       vp_write(mdev, VP_SRC_V_POSITION, geo->src.y_offset);
+
+       vp_write(mdev, VP_DST_WIDTH, geo->dst.width);
+       vp_write(mdev, VP_DST_H_POSITION, geo->dst.x_offset);
+       if (geo->dst.field == V4L2_FIELD_INTERLACED) {
+               vp_write(mdev, VP_DST_HEIGHT, geo->dst.height / 2);
+               vp_write(mdev, VP_DST_V_POSITION, geo->dst.y_offset / 2);
+       } else {
+               vp_write(mdev, VP_DST_HEIGHT, geo->dst.height);
+               vp_write(mdev, VP_DST_V_POSITION, geo->dst.y_offset);
+       }
+
+       vp_write(mdev, VP_H_RATIO, geo->x_ratio);
+       vp_write(mdev, VP_V_RATIO, geo->y_ratio);
+
+       vp_write(mdev, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
+
+       mxr_vsync_set_update(mdev, MXR_ENABLE);
+       spin_unlock_irqrestore(&mdev->reg_slock, flags);
+#endif
+}
+
+void mxr_reg_graph_buffer(struct mxr_device *mdev, int idx, dma_addr_t addr)
+{
+       u32 val = addr ? ~0 : 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&mdev->reg_slock, flags);
+       mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+       if (idx == 0) {
+               mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_GRP0_ENABLE);
+               mxr_write(mdev, MXR_GRAPHIC_BASE(0), addr);
+       } else if (idx == 1) {
+               mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_GRP1_ENABLE);
+               mxr_write(mdev, MXR_GRAPHIC_BASE(1), addr);
+       } else if (idx == 2) {
+               mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_MX1_GRP0_ENABLE);
+               mxr_write(mdev, MXR1_GRAPHIC_BASE(0), addr);
+       } else if (idx == 3) {
+               mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_MX1_GRP1_ENABLE);
+               mxr_write(mdev, MXR1_GRAPHIC_BASE(1), addr);
+       }
+
+       mxr_vsync_set_update(mdev, MXR_ENABLE);
+       spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+void mxr_reg_vp_buffer(struct mxr_device *mdev,
+       dma_addr_t luma_addr[2], dma_addr_t chroma_addr[2])
+{
+#if defined(CONFIG_ARCH_EXYNOS4)
+       u32 val = luma_addr[0] ? ~0 : 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&mdev->reg_slock, flags);
+       mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+       mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_VIDEO_ENABLE);
+       vp_write_mask(mdev, VP_ENABLE, val, VP_ENABLE_ON);
+       /* TODO: fix tiled mode */
+       vp_write(mdev, VP_TOP_Y_PTR, luma_addr[0]);
+       vp_write(mdev, VP_TOP_C_PTR, chroma_addr[0]);
+       vp_write(mdev, VP_BOT_Y_PTR, luma_addr[1]);
+       vp_write(mdev, VP_BOT_C_PTR, chroma_addr[1]);
+
+       mxr_vsync_set_update(mdev, MXR_ENABLE);
+       spin_unlock_irqrestore(&mdev->reg_slock, flags);
+#endif
+}
+
+void mxr_reg_set_layer_blend(struct mxr_device *mdev, int sub_mxr, int num,
+               int en)
+{
+       u32 val = en ? ~0 : 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&mdev->reg_slock, flags);
+       mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+       if (sub_mxr == MXR_SUB_MIXER0 && num == MXR_LAYER_VIDEO)
+               mxr_write_mask(mdev, MXR_VIDEO_CFG, val,
+                               MXR_VIDEO_CFG_BLEND_EN);
+       else if (sub_mxr == MXR_SUB_MIXER0 && num == MXR_LAYER_GRP0)
+               mxr_write_mask(mdev, MXR_GRAPHIC_CFG(0), val,
+                               MXR_GRP_CFG_LAYER_BLEND_EN);
+       else if (sub_mxr == MXR_SUB_MIXER0 && num == MXR_LAYER_GRP1)
+               mxr_write_mask(mdev, MXR_GRAPHIC_CFG(1), val,
+                               MXR_GRP_CFG_LAYER_BLEND_EN);
+#if defined(CONFIG_ARCH_EXYNOS5)
+       else if (sub_mxr == MXR_SUB_MIXER1 && num == MXR_LAYER_VIDEO)
+               mxr_write_mask(mdev, MXR1_VIDEO_CFG, val,
+                               MXR_VIDEO_CFG_BLEND_EN);
+       else if (sub_mxr == MXR_SUB_MIXER1 && num == MXR_LAYER_GRP0)
+               mxr_write_mask(mdev, MXR1_GRAPHIC_CFG(0), val,
+                               MXR_GRP_CFG_LAYER_BLEND_EN);
+       else if (sub_mxr == MXR_SUB_MIXER1 && num == MXR_LAYER_GRP1)
+               mxr_write_mask(mdev, MXR1_GRAPHIC_CFG(1), val,
+                               MXR_GRP_CFG_LAYER_BLEND_EN);
+#endif
+
+       mxr_vsync_set_update(mdev, MXR_ENABLE);
+       spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+void mxr_reg_layer_alpha(struct mxr_device *mdev, int sub_mxr, int num, u32 a)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&mdev->reg_slock, flags);
+       mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+       if (sub_mxr == MXR_SUB_MIXER0 && num == MXR_LAYER_VIDEO)
+               mxr_write_mask(mdev, MXR_VIDEO_CFG, MXR_VIDEO_CFG_ALPHA(a),
+                               0xff);
+       else if (sub_mxr == MXR_SUB_MIXER0 && num == MXR_LAYER_GRP0)
+               mxr_write_mask(mdev, MXR_GRAPHIC_CFG(0), MXR_GRP_CFG_ALPHA_VAL(a),
+                               0xff);
+       else if (sub_mxr == MXR_SUB_MIXER0 && num == MXR_LAYER_GRP1)
+               mxr_write_mask(mdev, MXR_GRAPHIC_CFG(1), MXR_GRP_CFG_ALPHA_VAL(a),
+                               0xff);
+#if defined(CONFIG_ARCH_EXYNOS5)
+       else if (sub_mxr == MXR_SUB_MIXER1 && num == MXR_LAYER_VIDEO)
+               mxr_write_mask(mdev, MXR1_VIDEO_CFG, MXR_VIDEO_CFG_ALPHA(a),
+                               0xff);
+       else if (sub_mxr == MXR_SUB_MIXER1 && num == MXR_LAYER_GRP0)
+               mxr_write_mask(mdev, MXR1_GRAPHIC_CFG(0), MXR_GRP_CFG_ALPHA_VAL(a),
+                               0xff);
+       else if (sub_mxr == MXR_SUB_MIXER1 && num == MXR_LAYER_GRP1)
+               mxr_write_mask(mdev, MXR1_GRAPHIC_CFG(1), MXR_GRP_CFG_ALPHA_VAL(a),
+                               0xff);
+#endif
+
+       mxr_vsync_set_update(mdev, MXR_ENABLE);
+       spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+void mxr_reg_set_pixel_blend(struct mxr_device *mdev, int sub_mxr, int num,
+               int en)
+{
+       u32 val = en ? ~0 : 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&mdev->reg_slock, flags);
+       mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+       if (sub_mxr == MXR_SUB_MIXER0 && num == MXR_LAYER_GRP0)
+               mxr_write_mask(mdev, MXR_GRAPHIC_CFG(0), val,
+                               MXR_GRP_CFG_PIXEL_BLEND_EN);
+       else if (sub_mxr == MXR_SUB_MIXER0 && num == MXR_LAYER_GRP1)
+               mxr_write_mask(mdev, MXR_GRAPHIC_CFG(1), val,
+                               MXR_GRP_CFG_PIXEL_BLEND_EN);
+#if defined(CONFIG_ARCH_EXYNOS5)
+       else if (sub_mxr == MXR_SUB_MIXER1 && num == MXR_LAYER_GRP0)
+               mxr_write_mask(mdev, MXR1_GRAPHIC_CFG(0), val,
+                               MXR_GRP_CFG_PIXEL_BLEND_EN);
+       else if (sub_mxr == MXR_SUB_MIXER1 && num == MXR_LAYER_GRP1)
+               mxr_write_mask(mdev, MXR1_GRAPHIC_CFG(1), val,
+                               MXR_GRP_CFG_PIXEL_BLEND_EN);
+#endif
+
+       mxr_vsync_set_update(mdev, MXR_ENABLE);
+       spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+void mxr_reg_set_colorkey(struct mxr_device *mdev, int sub_mxr, int num, int en)
+{
+       u32 val = en ? ~0 : 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&mdev->reg_slock, flags);
+       mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+       if (sub_mxr == MXR_SUB_MIXER0 && num == MXR_LAYER_GRP0)
+               mxr_write_mask(mdev, MXR_GRAPHIC_CFG(0), val,
+                               MXR_GRP_CFG_BLANK_KEY_OFF);
+       else if (sub_mxr == MXR_SUB_MIXER0 && num == MXR_LAYER_GRP1)
+               mxr_write_mask(mdev, MXR_GRAPHIC_CFG(1), val,
+                               MXR_GRP_CFG_BLANK_KEY_OFF);
+#if defined(CONFIG_ARCH_EXYNOS5)
+       else if (sub_mxr == MXR_SUB_MIXER1 && num == MXR_LAYER_GRP0)
+               mxr_write_mask(mdev, MXR1_GRAPHIC_CFG(0), val,
+                               MXR_GRP_CFG_BLANK_KEY_OFF);
+       else if (sub_mxr == MXR_SUB_MIXER1 && num == MXR_LAYER_GRP1)
+               mxr_write_mask(mdev, MXR1_GRAPHIC_CFG(1), val,
+                               MXR_GRP_CFG_BLANK_KEY_OFF);
+#endif
+
+       mxr_vsync_set_update(mdev, MXR_ENABLE);
+       spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+void mxr_reg_colorkey_val(struct mxr_device *mdev, int sub_mxr, int num, u32 v)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&mdev->reg_slock, flags);
+       mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+       if (sub_mxr == MXR_SUB_MIXER0 && num == MXR_LAYER_GRP0)
+               mxr_write(mdev, MXR_GRAPHIC_BLANK(0), v);
+       else if (sub_mxr == MXR_SUB_MIXER0 && num == MXR_LAYER_GRP1)
+               mxr_write(mdev, MXR_GRAPHIC_BLANK(1), v);
+#if defined(CONFIG_ARCH_EXYNOS5)
+       else if (sub_mxr == MXR_SUB_MIXER1 && num == MXR_LAYER_GRP0)
+               mxr_write(mdev, MXR1_GRAPHIC_BLANK(0), v);
+       else if (sub_mxr == MXR_SUB_MIXER1 && num == MXR_LAYER_GRP1)
+               mxr_write(mdev, MXR1_GRAPHIC_BLANK(1), v);
+#endif
+
+       mxr_vsync_set_update(mdev, MXR_ENABLE);
+       spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+static void mxr_irq_layer_handle(struct mxr_layer *layer)
+{
+       struct list_head *head = &layer->enq_list;
+       struct tv_graph_pipeline *pipe = &layer->pipe;
+       struct mxr_buffer *done;
+
+       /* skip non-existing layer */
+       if (layer == NULL)
+               return;
+
+       spin_lock(&layer->enq_slock);
+       if (pipe->state == TV_GRAPH_PIPELINE_IDLE)
+               goto done;
+
+       done = layer->shadow_buf;
+       layer->shadow_buf = layer->update_buf;
+
+       if (list_empty(head)) {
+               if (pipe->state != TV_GRAPH_PIPELINE_STREAMING)
+                       layer->update_buf = NULL;
+       } else {
+               struct mxr_buffer *next;
+               next = list_first_entry(head, struct mxr_buffer, list);
+               list_del(&next->list);
+               layer->update_buf = next;
+       }
+
+       layer->ops.buffer_set(layer, layer->update_buf);
+
+       if (done && done != layer->shadow_buf)
+               vb2_buffer_done(&done->vb, VB2_BUF_STATE_DONE);
+
+done:
+       spin_unlock(&layer->enq_slock);
+}
+
+u32 mxr_irq_underrun_handle(struct mxr_device *mdev, u32 val)
+{
+       if (val & MXR_INT_STATUS_MX0_VIDEO) {
+               mxr_warn(mdev, "mixer0 video layer underrun occur\n");
+               val |= MXR_INT_STATUS_MX0_VIDEO;
+       } else if (val & MXR_INT_STATUS_MX0_GRP0) {
+               mxr_warn(mdev, "mixer0 graphic0 layer underrun occur\n");
+               val |= MXR_INT_STATUS_MX0_GRP0;
+       } else if (val & MXR_INT_STATUS_MX0_GRP1) {
+               mxr_warn(mdev, "mixer0 graphic1 layer underrun occur\n");
+               val |= MXR_INT_STATUS_MX0_GRP1;
+       } else if (val & MXR_INT_STATUS_MX1_VIDEO) {
+               mxr_warn(mdev, "mixer1 video layer underrun occur\n");
+               val |= MXR_INT_STATUS_MX1_VIDEO;
+       } else if (val & MXR_INT_STATUS_MX1_GRP0) {
+               mxr_warn(mdev, "mixer1 graphic0 layer underrun occur\n");
+               val |= MXR_INT_STATUS_MX1_GRP0;
+       } else if (val & MXR_INT_STATUS_MX1_GRP1) {
+               mxr_warn(mdev, "mixer1 graphic1 layer underrun occur\n");
+               val |= MXR_INT_STATUS_MX1_GRP1;
+       }
+
+       return val;
+}
+
+irqreturn_t mxr_irq_handler(int irq, void *dev_data)
+{
+       struct mxr_device *mdev = dev_data;
+       u32 i, val;
+
+       spin_lock(&mdev->reg_slock);
+       val = mxr_read(mdev, MXR_INT_STATUS);
+
+       /* wake up process waiting for VSYNC */
+       if (val & MXR_INT_STATUS_VSYNC) {
+               set_bit(MXR_EVENT_VSYNC, &mdev->event_flags);
+               wake_up(&mdev->event_queue);
+       }
+
+       /* clear interrupts.
+          vsync is updated after write MXR_CFG_LAYER_UPDATE bit */
+       if (val & MXR_INT_CLEAR_VSYNC)
+               mxr_write_mask(mdev, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
+
+       val = mxr_irq_underrun_handle(mdev, val);
+       mxr_write(mdev, MXR_INT_STATUS, val);
+
+       spin_unlock(&mdev->reg_slock);
+       /* leave on non-vsync event */
+       if (~val & MXR_INT_CLEAR_VSYNC)
+               return IRQ_HANDLED;
+
+       for (i = 0; i < MXR_MAX_SUB_MIXERS; ++i) {
+#if defined(CONFIG_ARCH_EXYNOS4)
+               mxr_irq_layer_handle(mdev->sub_mxr[i].layer[MXR_LAYER_VIDEO]);
+#endif
+               mxr_irq_layer_handle(mdev->sub_mxr[i].layer[MXR_LAYER_GRP0]);
+               mxr_irq_layer_handle(mdev->sub_mxr[i].layer[MXR_LAYER_GRP1]);
+       }
+
+       if (test_bit(MXR_EVENT_VSYNC, &mdev->event_flags)) {
+               spin_lock(&mdev->reg_slock);
+               mxr_write_mask(mdev, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
+               spin_unlock(&mdev->reg_slock);
+       }
+
+       return IRQ_HANDLED;
+}
+
+void mxr_reg_s_output(struct mxr_device *mdev, int cookie)
+{
+       u32 val;
+
+       val = cookie == 0 ? MXR_CFG_DST_SDO : MXR_CFG_DST_HDMI;
+       mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_DST_MASK);
+}
+
+void mxr_reg_streamon(struct mxr_device *mdev)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&mdev->reg_slock, flags);
+       /* single write -> no need to block vsync update */
+
+       /* start MIXER */
+       mxr_write_mask(mdev, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
+
+       spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+void mxr_reg_streamoff(struct mxr_device *mdev)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&mdev->reg_slock, flags);
+       /* single write -> no need to block vsync update */
+
+       /* stop MIXER */
+       mxr_write_mask(mdev, MXR_STATUS, 0, MXR_STATUS_REG_RUN);
+
+       spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+int mxr_reg_wait4vsync(struct mxr_device *mdev)
+{
+       int ret;
+
+       clear_bit(MXR_EVENT_VSYNC, &mdev->event_flags);
+       /* TODO: consider adding interruptible */
+       ret = wait_event_timeout(mdev->event_queue,
+               test_bit(MXR_EVENT_VSYNC, &mdev->event_flags),
+               msecs_to_jiffies(1000));
+       if (ret > 0)
+               return 0;
+       if (ret < 0)
+               return ret;
+       mxr_warn(mdev, "no vsync detected - timeout\n");
+       return -ETIME;
+}
+
+void mxr_reg_set_mbus_fmt(struct mxr_device *mdev,
+       struct v4l2_mbus_framefmt *fmt)
+{
+       u32 val = 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&mdev->reg_slock, flags);
+       mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+       /* choosing between YUV444 and RGB888 as mixer output type */
+       if (mdev->sub_mxr[MXR_SUB_MIXER0].mbus_fmt[MXR_PAD_SOURCE_GRP0].code ==
+               V4L2_MBUS_FMT_YUV8_1X24) {
+               val = MXR_CFG_OUT_YUV444;
+               fmt->code = V4L2_MBUS_FMT_YUV8_1X24;
+       } else {
+               val = MXR_CFG_OUT_RGB888;
+               fmt->code = V4L2_MBUS_FMT_XRGB8888_4X8_LE;
+       }
+
+       /* choosing between interlace and progressive mode */
+       if (fmt->field == V4L2_FIELD_INTERLACED)
+               val |= MXR_CFG_SCAN_INTERLACE;
+       else
+               val |= MXR_CFG_SCAN_PROGRASSIVE;
+
+       /* choosing between porper HD and SD mode */
+       if (fmt->height == 480)
+               val |= MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD;
+       else if (fmt->height == 576)
+               val |= MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD;
+       else if (fmt->height == 720)
+               val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
+       else if (fmt->height == 1080)
+               val |= MXR_CFG_SCAN_HD_1080 | MXR_CFG_SCAN_HD;
+       else
+               WARN(1, "unrecognized mbus height %u!\n", fmt->height);
+
+       mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_SCAN_MASK |
+                       MXR_CFG_OUT_MASK);
+
+       val = (fmt->field == V4L2_FIELD_INTERLACED) ? ~0 : 0;
+       vp_write_mask(mdev, VP_MODE, val,
+               VP_MODE_LINE_SKIP | VP_MODE_FIELD_ID_AUTO_TOGGLING);
+
+       mxr_vsync_set_update(mdev, MXR_ENABLE);
+       spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+void mxr_reg_local_path_clear(struct mxr_device *mdev)
+{
+       u32 val;
+
+       val = readl(SYSREG_DISP1BLK_CFG);
+       val &= ~(DISP1BLK_CFG_MIXER0_VALID | DISP1BLK_CFG_MIXER1_VALID);
+       writel(val, SYSREG_DISP1BLK_CFG);
+       mxr_dbg(mdev, "SYSREG_DISP1BLK_CFG = 0x%x\n", readl(SYSREG_DISP1BLK_CFG));
+}
+
+void mxr_reg_local_path_set(struct mxr_device *mdev, int mxr0_gsc, int mxr1_gsc,
+               u32 flags)
+{
+       u32 val = 0;
+       int mxr0_local = mdev->sub_mxr[MXR_SUB_MIXER0].local;
+       int mxr1_local = mdev->sub_mxr[MXR_SUB_MIXER1].local;
+
+       if (mxr0_local && !mxr1_local) { /* 1-path : sub-mixer0 */
+               val  = MXR_TVOUT_CFG_ONE_PATH;
+               val |= MXR_TVOUT_CFG_PATH_MIXER0;
+       } else if (!mxr0_local && mxr1_local) { /* 1-path : sub-mixer1 */
+               val  = MXR_TVOUT_CFG_ONE_PATH;
+               val |= MXR_TVOUT_CFG_PATH_MIXER1;
+       } else if (mxr0_local && mxr1_local) { /* 2-path */
+               val  = MXR_TVOUT_CFG_TWO_PATH;
+               val |= MXR_TVOUT_CFG_STEREO_SCOPIC;
+       }
+
+       mxr_write(mdev, MXR_TVOUT_CFG, val);
+
+       /* set local path gscaler to mixer */
+       val = readl(SYSREG_DISP1BLK_CFG);
+       val |= DISP1BLK_CFG_FIFORST_DISP1;
+       val &= ~DISP1BLK_CFG_MIXER_MASK;
+       if (flags & MEDIA_LNK_FL_ENABLED) {
+               if (mxr0_local) {
+                       val |= DISP1BLK_CFG_MIXER0_VALID;
+                       val |= DISP1BLK_CFG_MIXER0_SRC_GSC(mxr0_gsc);
+               }
+               if (mxr1_local) {
+                       val |= DISP1BLK_CFG_MIXER1_VALID;
+                       val |= DISP1BLK_CFG_MIXER1_SRC_GSC(mxr1_gsc);
+               }
+       }
+       mxr_dbg(mdev, "%s: SYSREG value = 0x%x\n", __func__, val);
+       writel(val, SYSREG_DISP1BLK_CFG);
+}
+
+void mxr_reg_graph_layer_stream(struct mxr_device *mdev, int idx, int en)
+{
+       u32 val = 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&mdev->reg_slock, flags);
+       mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+       if (mdev->frame_packing) {
+               val  = MXR_TVOUT_CFG_TWO_PATH;
+               val |= MXR_TVOUT_CFG_STEREO_SCOPIC;
+       } else {
+               val  = MXR_TVOUT_CFG_ONE_PATH;
+               val |= MXR_TVOUT_CFG_PATH_MIXER0;
+       }
+
+       mxr_write(mdev, MXR_TVOUT_CFG, val);
+
+       mxr_vsync_set_update(mdev, MXR_ENABLE);
+       spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+void mxr_reg_vp_layer_stream(struct mxr_device *mdev, int en)
+{
+       /* no extra actions need to be done */
+}
+
+void mxr_reg_video_layer_stream(struct mxr_device *mdev, int idx, int en)
+{
+       u32 val = en ? ~0 : 0;
+
+       if (idx == 0)
+               mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_VIDEO_ENABLE);
+       else if (idx == 1)
+               mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_MX1_VIDEO_ENABLE);
+}
+
+static const u8 filter_y_horiz_tap8[] = {
+       0,      -1,     -1,     -1,     -1,     -1,     -1,     -1,
+       -1,     -1,     -1,     -1,     -1,     0,      0,      0,
+       0,      2,      4,      5,      6,      6,      6,      6,
+       6,      5,      5,      4,      3,      2,      1,      1,
+       0,      -6,     -12,    -16,    -18,    -20,    -21,    -20,
+       -20,    -18,    -16,    -13,    -10,    -8,     -5,     -2,
+       127,    126,    125,    121,    114,    107,    99,     89,
+       79,     68,     57,     46,     35,     25,     16,     8,
+};
+
+static const u8 filter_y_vert_tap4[] = {
+       0,      -3,     -6,     -8,     -8,     -8,     -8,     -7,
+       -6,     -5,     -4,     -3,     -2,     -1,     -1,     0,
+       127,    126,    124,    118,    111,    102,    92,     81,
+       70,     59,     48,     37,     27,     19,     11,     5,
+       0,      5,      11,     19,     27,     37,     48,     59,
+       70,     81,     92,     102,    111,    118,    124,    126,
+       0,      0,      -1,     -1,     -2,     -3,     -4,     -5,
+       -6,     -7,     -8,     -8,     -8,     -8,     -6,     -3,
+};
+
+static const u8 filter_cr_horiz_tap4[] = {
+       0,      -3,     -6,     -8,     -8,     -8,     -8,     -7,
+       -6,     -5,     -4,     -3,     -2,     -1,     -1,     0,
+       127,    126,    124,    118,    111,    102,    92,     81,
+       70,     59,     48,     37,     27,     19,     11,     5,
+};
+
+static inline void mxr_reg_vp_filter_set(struct mxr_device *mdev,
+       int reg_id, const u8 *data, unsigned int size)
+{
+       /* assure 4-byte align */
+       BUG_ON(size & 3);
+       for (; size; size -= 4, reg_id += 4, data += 4) {
+               u32 val = (data[0] << 24) |  (data[1] << 16) |
+                       (data[2] << 8) | data[3];
+               vp_write(mdev, reg_id, val);
+       }
+}
+
+static void mxr_reg_vp_default_filter(struct mxr_device *mdev)
+{
+#if defined(CONFIG_ARCH_EXYNOS4)
+       mxr_reg_vp_filter_set(mdev, VP_POLY8_Y0_LL,
+               filter_y_horiz_tap8, sizeof filter_y_horiz_tap8);
+       mxr_reg_vp_filter_set(mdev, VP_POLY4_Y0_LL,
+               filter_y_vert_tap4, sizeof filter_y_vert_tap4);
+       mxr_reg_vp_filter_set(mdev, VP_POLY4_C0_LL,
+               filter_cr_horiz_tap4, sizeof filter_cr_horiz_tap4);
+#endif
+}
+
+static void mxr_reg_mxr_dump(struct mxr_device *mdev)
+{
+#define DUMPREG(reg_id) \
+do { \
+       mxr_dbg(mdev, #reg_id " = %08x\n", \
+               (u32)readl(mdev->res.mxr_regs + reg_id)); \
+} while (0)
+
+       DUMPREG(MXR_STATUS);
+       DUMPREG(MXR_CFG);
+       DUMPREG(MXR_INT_EN);
+       DUMPREG(MXR_INT_STATUS);
+
+       DUMPREG(MXR_LAYER_CFG);
+       DUMPREG(MXR_VIDEO_CFG);
+
+       DUMPREG(MXR_GRAPHIC0_CFG);
+       DUMPREG(MXR_GRAPHIC0_BASE);
+       DUMPREG(MXR_GRAPHIC0_SPAN);
+       DUMPREG(MXR_GRAPHIC0_WH);
+       DUMPREG(MXR_GRAPHIC0_SXY);
+       DUMPREG(MXR_GRAPHIC0_DXY);
+
+       DUMPREG(MXR_GRAPHIC1_CFG);
+       DUMPREG(MXR_GRAPHIC1_BASE);
+       DUMPREG(MXR_GRAPHIC1_SPAN);
+       DUMPREG(MXR_GRAPHIC1_WH);
+       DUMPREG(MXR_GRAPHIC1_SXY);
+       DUMPREG(MXR_GRAPHIC1_DXY);
+#undef DUMPREG
+}
+
+static void mxr_reg_vp_dump(struct mxr_device *mdev)
+{
+#define DUMPREG(reg_id) \
+do { \
+       mxr_dbg(mdev, #reg_id " = %08x\n", \
+               (u32) readl(mdev->res.vp_regs + reg_id)); \
+} while (0)
+
+#if defined(CONFIG_ARCH_EXYNOS4)
+       DUMPREG(VP_ENABLE);
+       DUMPREG(VP_SRESET);
+       DUMPREG(VP_SHADOW_UPDATE);
+       DUMPREG(VP_FIELD_ID);
+       DUMPREG(VP_MODE);
+       DUMPREG(VP_IMG_SIZE_Y);
+       DUMPREG(VP_IMG_SIZE_C);
+       DUMPREG(VP_PER_RATE_CTRL);
+       DUMPREG(VP_TOP_Y_PTR);
+       DUMPREG(VP_BOT_Y_PTR);
+       DUMPREG(VP_TOP_C_PTR);
+       DUMPREG(VP_BOT_C_PTR);
+       DUMPREG(VP_ENDIAN_MODE);
+       DUMPREG(VP_SRC_H_POSITION);
+       DUMPREG(VP_SRC_V_POSITION);
+       DUMPREG(VP_SRC_WIDTH);
+       DUMPREG(VP_SRC_HEIGHT);
+       DUMPREG(VP_DST_H_POSITION);
+       DUMPREG(VP_DST_V_POSITION);
+       DUMPREG(VP_DST_WIDTH);
+       DUMPREG(VP_DST_HEIGHT);
+       DUMPREG(VP_H_RATIO);
+       DUMPREG(VP_V_RATIO);
+#endif
+
+#undef DUMPREG
+}
+
+void mxr_reg_dump(struct mxr_device *mdev)
+{
+       mxr_reg_mxr_dump(mdev);
+       mxr_reg_vp_dump(mdev);
+}
diff --git a/drivers/media/video/exynos/tv/mixer_vb2.c b/drivers/media/video/exynos/tv/mixer_vb2.c
new file mode 100644 (file)
index 0000000..757b7da
--- /dev/null
@@ -0,0 +1,58 @@
+/* linux/drivers/media/video/exynos/tv/mixer_vb2.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * Videobuf2 allocator operations file
+ *
+ * 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/platform_device.h>
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+#include <media/videobuf2-cma-phys.h>
+#elif defined(CONFIG_VIDEOBUF2_DMA_CONTIG)
+#include <media/videobuf2-dma-contig.h>
+#endif
+
+#include "mixer.h"
+
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+void *mxr_cma_init(struct mxr_device *mdev)
+{
+       return vb2_cma_phys_init(mdev->dev, NULL, 0, false);
+}
+
+int mxr_cma_resume(void *alloc_ctx) {}
+void mxr_cma_suspend(void *alloc_ctx) {}
+void mxr_cma_set_cacheable(void *alloc_ctx, bool cacheable) {}
+
+int mxr_cma_cache_flush(struct vb2_buffer *vb, u32 plane_no)
+{
+       return 0;
+}
+
+const struct mxr_vb2 mxr_vb2_cma = {
+       .ops            = &vb2_cma_phys_memops,
+       .init           = mxr_cma_init,
+       .cleanup        = vb2_cma_phys_cleanup,
+       .plane_addr     = vb2_cma_phys_plane_paddr,
+       .resume         = mxr_cma_resume,
+       .suspend        = mxr_cma_suspend,
+       .cache_flush    = mxr_cma_cache_flush,
+       .set_cacheable  = mxr_cma_set_cacheable,
+};
+#elif defined(CONFIG_VIDEOBUF2_DMA_CONTIG)
+void *mxr_dma_contig_init(struct mxr_device *mdev)
+{
+       return vb2_dma_contig_init_ctx(mdev->dev);
+}
+
+const struct mxr_vb2 mxr_vb2_dma_contig = {
+       .ops            = &vb2_dma_contig_memops,
+       .init           = mxr_dma_contig_init,
+       .cleanup        = vb2_dma_contig_cleanup_ctx,
+       .plane_addr     = vb2_dma_contig_plane_dma_addr,
+};
+#endif
diff --git a/drivers/media/video/exynos/tv/mixer_video.c b/drivers/media/video/exynos/tv/mixer_video.c
new file mode 100644 (file)
index 0000000..dab58e0
--- /dev/null
@@ -0,0 +1,1237 @@
+/*
+ * Samsung TV Mixer driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.com>
+ *
+ * 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
+ */
+#include "mixer.h"
+
+#include <linux/videodev2.h>
+#include <linux/mm.h>
+#include <linux/version.h>
+#include <linux/timer.h>
+#include <linux/export.h>
+
+#include <media/exynos_mc.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-fb.h>
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+#include <media/videobuf2-cma-phys.h>
+#elif defined(CONFIG_VIDEOBUF2_ION)
+#include <media/videobuf2-ion.h>
+#else
+#include <media/videobuf2-dma-contig.h>
+#endif
+
+
+int __devinit mxr_acquire_video(struct mxr_device *mdev,
+       struct mxr_output_conf *output_conf, int output_count)
+{
+       int i;
+       int ret = 0;
+       struct v4l2_subdev *sd;
+
+       mdev->alloc_ctx = mdev->vb2->init(mdev);
+       if (IS_ERR_OR_NULL(mdev->alloc_ctx)) {
+               mxr_err(mdev, "could not acquire vb2 allocator\n");
+               ret = PTR_ERR(mdev->alloc_ctx);
+               goto fail;
+       }
+
+       /* registering outputs */
+       mdev->output_cnt = 0;
+       for (i = 0; i < output_count; ++i) {
+               struct mxr_output_conf *conf = &output_conf[i];
+               struct mxr_output *out;
+
+               /* find subdev of output devices */
+               sd = (struct v4l2_subdev *)
+                       module_name_to_driver_data(conf->module_name);
+               /* trying to register next output */
+               if (sd == NULL)
+                       continue;
+               out = kzalloc(sizeof *out, GFP_KERNEL);
+               if (out == NULL) {
+                       mxr_err(mdev, "no memory for '%s'\n",
+                               conf->output_name);
+                       ret = -ENOMEM;
+                       /* registered subdevs are removed in fail_v4l2_dev */
+                       goto fail_output;
+               }
+               strlcpy(out->name, conf->output_name, sizeof(out->name));
+               out->sd = sd;
+               out->cookie = conf->cookie;
+               mdev->output[mdev->output_cnt++] = out;
+               mxr_info(mdev, "added output '%s' from module '%s'\n",
+                       conf->output_name, conf->module_name);
+               /* checking if maximal number of outputs is reached */
+               if (mdev->output_cnt >= MXR_MAX_OUTPUTS)
+                       break;
+       }
+
+       if (mdev->output_cnt == 0) {
+               mxr_err(mdev, "failed to register any output\n");
+               ret = -ENODEV;
+               /* skipping fail_output because there is nothing to free */
+               goto fail_vb2_allocator;
+       }
+
+       return 0;
+
+fail_output:
+       /* kfree is NULL-safe */
+       for (i = 0; i < mdev->output_cnt; ++i)
+               kfree(mdev->output[i]);
+       memset(mdev->output, 0, sizeof mdev->output);
+
+fail_vb2_allocator:
+       /* freeing allocator context */
+       mdev->vb2->cleanup(mdev->alloc_ctx);
+
+fail:
+       return ret;
+}
+
+void __devexit mxr_release_video(struct mxr_device *mdev)
+{
+       int i;
+
+       /* kfree is NULL-safe */
+       for (i = 0; i < mdev->output_cnt; ++i)
+               kfree(mdev->output[i]);
+
+       mdev->vb2->cleanup(mdev->alloc_ctx);
+}
+
+static void tv_graph_pipeline_stream(struct tv_graph_pipeline *pipe, int on)
+{
+       struct mxr_device *mdev = pipe->layer->mdev;
+       struct media_entity *me = &pipe->layer->vfd.entity;
+       /* source pad of graphic layer entity */
+       struct media_pad *pad = &me->pads[0];
+       struct v4l2_subdev *sd;
+       struct exynos_entity_data md_data;
+
+       mxr_dbg(mdev, "%s TV graphic layer pipeline\n", on ? "start" : "stop");
+
+       /* find remote pad through enabled link */
+       pad = media_entity_remote_source(pad);
+       if (media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV
+                       || pad == NULL)
+               mxr_warn(mdev, "cannot find remote pad\n");
+
+       sd = media_entity_to_v4l2_subdev(pad->entity);
+       mxr_dbg(mdev, "s_stream of %s sub-device is called\n", sd->name);
+
+       md_data.mxr_data_from = FROM_MXR_VD;
+       v4l2_set_subdevdata(sd, &md_data);
+       v4l2_subdev_call(sd, video, s_stream, on);
+}
+
+static int mxr_querycap(struct file *file, void *priv,
+       struct v4l2_capability *cap)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+
+       mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+
+       strlcpy(cap->driver, MXR_DRIVER_NAME, sizeof cap->driver);
+       strlcpy(cap->card, layer->vfd.name, sizeof cap->card);
+       sprintf(cap->bus_info, "%d", layer->idx);
+       cap->version = KERNEL_VERSION(0, 1, 0);
+       cap->capabilities = V4L2_CAP_STREAMING |
+               V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_MPLANE;
+
+       return 0;
+}
+
+/* Geometry handling */
+void mxr_layer_geo_fix(struct mxr_layer *layer)
+{
+       struct mxr_device *mdev = layer->mdev;
+       struct v4l2_mbus_framefmt mbus_fmt;
+
+       /* TODO: add some dirty flag to avoid unnecessary adjustments */
+       mxr_get_mbus_fmt(mdev, &mbus_fmt);
+       layer->geo.dst.full_width = mbus_fmt.width;
+       layer->geo.dst.full_height = mbus_fmt.height;
+       layer->geo.dst.field = mbus_fmt.field;
+       layer->ops.fix_geometry(layer);
+}
+
+void mxr_layer_default_geo(struct mxr_layer *layer)
+{
+       struct mxr_device *mdev = layer->mdev;
+       struct v4l2_mbus_framefmt mbus_fmt;
+
+       mxr_dbg(layer->mdev, "%s start\n", __func__);
+       memset(&layer->geo, 0, sizeof layer->geo);
+
+       mxr_get_mbus_fmt(mdev, &mbus_fmt);
+
+       layer->geo.dst.full_width = mbus_fmt.width;
+       layer->geo.dst.full_height = mbus_fmt.height;
+       layer->geo.dst.width = layer->geo.dst.full_width;
+       layer->geo.dst.height = layer->geo.dst.full_height;
+       layer->geo.dst.field = mbus_fmt.field;
+
+       layer->geo.src.full_width = mbus_fmt.width;
+       layer->geo.src.full_height = mbus_fmt.height;
+       layer->geo.src.width = layer->geo.src.full_width;
+       layer->geo.src.height = layer->geo.src.full_height;
+
+       layer->ops.fix_geometry(layer);
+}
+
+static void mxr_geometry_dump(struct mxr_device *mdev, struct mxr_geometry *geo)
+{
+       mxr_dbg(mdev, "src.full_size = (%u, %u)\n",
+               geo->src.full_width, geo->src.full_height);
+       mxr_dbg(mdev, "src.size = (%u, %u)\n",
+               geo->src.width, geo->src.height);
+       mxr_dbg(mdev, "src.offset = (%u, %u)\n",
+               geo->src.x_offset, geo->src.y_offset);
+       mxr_dbg(mdev, "dst.full_size = (%u, %u)\n",
+               geo->dst.full_width, geo->dst.full_height);
+       mxr_dbg(mdev, "dst.size = (%u, %u)\n",
+               geo->dst.width, geo->dst.height);
+       mxr_dbg(mdev, "dst.offset = (%u, %u)\n",
+               geo->dst.x_offset, geo->dst.y_offset);
+       mxr_dbg(mdev, "ratio = (%u, %u)\n",
+               geo->x_ratio, geo->y_ratio);
+}
+
+static const struct mxr_format *find_format_by_index(
+       struct mxr_layer *layer, unsigned long index);
+
+static int mxr_enum_fmt(struct file *file, void  *priv,
+       struct v4l2_fmtdesc *f)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       struct mxr_device *mdev = layer->mdev;
+       const struct mxr_format *fmt;
+
+       mxr_dbg(mdev, "%s\n", __func__);
+       fmt = find_format_by_index(layer, f->index);
+       if (fmt == NULL)
+               return -EINVAL;
+
+       strlcpy(f->description, fmt->name, sizeof(f->description));
+       f->pixelformat = fmt->fourcc;
+
+       return 0;
+}
+
+static int mxr_s_fmt(struct file *file, void *priv,
+       struct v4l2_format *f)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       const struct mxr_format *fmt;
+       struct v4l2_pix_format_mplane *pix;
+       struct mxr_device *mdev = layer->mdev;
+       struct mxr_geometry *geo = &layer->geo;
+
+       mxr_dbg(mdev, "%s:%d\n", __func__, __LINE__);
+
+       pix = &f->fmt.pix_mp;
+       fmt = find_format_by_fourcc(layer, pix->pixelformat);
+       if (fmt == NULL) {
+               mxr_warn(mdev, "not recognized fourcc: %08x\n",
+                       pix->pixelformat);
+               return -EINVAL;
+       }
+       layer->fmt = fmt;
+       geo->src.full_width = pix->width;
+       geo->src.width = pix->width;
+       geo->src.full_height = pix->height;
+       geo->src.height = pix->height;
+       /* assure consistency of geometry */
+       mxr_layer_geo_fix(layer);
+       mxr_dbg(mdev, "width=%u height=%u span=%u\n",
+               geo->src.width, geo->src.height, geo->src.full_width);
+
+       return 0;
+}
+
+static unsigned int divup(unsigned int divident, unsigned int divisor)
+{
+       return (divident + divisor - 1) / divisor;
+}
+
+unsigned long mxr_get_plane_size(const struct mxr_block *blk,
+       unsigned int width, unsigned int height)
+{
+       unsigned int bl_width = divup(width, blk->width);
+       unsigned int bl_height = divup(height, blk->height);
+
+       return bl_width * bl_height * blk->size;
+}
+
+static void mxr_mplane_fill(struct v4l2_plane_pix_format *planes,
+       const struct mxr_format *fmt, u32 width, u32 height)
+{
+       int i;
+
+       memset(planes, 0, sizeof(*planes) * fmt->num_subframes);
+       for (i = 0; i < fmt->num_planes; ++i) {
+               struct v4l2_plane_pix_format *plane = planes
+                       + fmt->plane2subframe[i];
+               const struct mxr_block *blk = &fmt->plane[i];
+               u32 bl_width = divup(width, blk->width);
+               u32 bl_height = divup(height, blk->height);
+               u32 sizeimage = bl_width * bl_height * blk->size;
+               u16 bytesperline = bl_width * blk->size / blk->height;
+
+               plane->sizeimage += sizeimage;
+               plane->bytesperline = max(plane->bytesperline, bytesperline);
+       }
+}
+
+static int mxr_g_fmt(struct file *file, void *priv,
+                            struct v4l2_format *f)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
+
+       mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+
+       pix->width = layer->geo.src.full_width;
+       pix->height = layer->geo.src.full_height;
+       pix->field = V4L2_FIELD_NONE;
+       pix->pixelformat = layer->fmt->fourcc;
+       pix->colorspace = layer->fmt->colorspace;
+       mxr_mplane_fill(pix->plane_fmt, layer->fmt, pix->width, pix->height);
+
+       return 0;
+}
+
+static inline struct mxr_crop *choose_crop_by_type(struct mxr_geometry *geo,
+       enum v4l2_buf_type type)
+{
+       switch (type) {
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+               return &geo->dst;
+       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+               return &geo->src;
+       default:
+               return NULL;
+       }
+}
+
+static int mxr_g_crop(struct file *file, void *fh, struct v4l2_crop *a)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       struct mxr_crop *crop;
+
+       mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+       crop = choose_crop_by_type(&layer->geo, a->type);
+       if (crop == NULL)
+               return -EINVAL;
+       mxr_layer_geo_fix(layer);
+       a->c.left = crop->x_offset;
+       a->c.top = crop->y_offset;
+       a->c.width = crop->width;
+       a->c.height = crop->height;
+       return 0;
+}
+
+static int mxr_s_crop(struct file *file, void *fh, struct v4l2_crop *a)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       struct mxr_crop *crop;
+
+       mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+       crop = choose_crop_by_type(&layer->geo, a->type);
+       if (crop == NULL)
+               return -EINVAL;
+       crop->x_offset = a->c.left;
+       crop->y_offset = a->c.top;
+       crop->width = a->c.width;
+       crop->height = a->c.height;
+       mxr_layer_geo_fix(layer);
+       return 0;
+}
+
+static int mxr_cropcap(struct file *file, void *fh, struct v4l2_cropcap *a)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       struct mxr_crop *crop;
+
+       mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+       crop = choose_crop_by_type(&layer->geo, a->type);
+       if (crop == NULL)
+               return -EINVAL;
+       mxr_layer_geo_fix(layer);
+       a->bounds.left = 0;
+       a->bounds.top = 0;
+       a->bounds.width = crop->full_width;
+       a->bounds.top = crop->full_height;
+       a->defrect = a->bounds;
+       /* setting pixel aspect to 1/1 */
+       a->pixelaspect.numerator = 1;
+       a->pixelaspect.denominator = 1;
+       return 0;
+}
+
+static int mxr_check_ctrl_val(struct v4l2_control *ctrl)
+{
+       int ret = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_TV_LAYER_BLEND_ALPHA:
+       case V4L2_CID_TV_CHROMA_VALUE:
+               if (ctrl->value < 0 || ctrl->value > 256)
+                       ret = -ERANGE;
+               break;
+       }
+
+       return ret;
+}
+
+static int mxr_s_ctrl(struct file *file, void *fh, struct v4l2_control *ctrl)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       struct mxr_device *mdev = layer->mdev;
+       int cur_mxr = layer->cur_mxr;
+       int v = ctrl->value;
+       int num = 0;
+       int ret;
+
+       mxr_dbg(mdev, "%s start\n", __func__);
+
+       if (layer->type == MXR_LAYER_TYPE_VIDEO)
+               num = 0;
+       else if (layer->type == MXR_LAYER_TYPE_GRP && layer->idx == 0)
+               num = 1;
+       else if (layer->type == MXR_LAYER_TYPE_GRP && layer->idx == 1)
+               num = 2;
+
+       ret = mxr_check_ctrl_val(ctrl);
+       if (ret) {
+               mxr_err(mdev, "alpha value is out of range\n");
+               return ret;
+       }
+
+       switch (ctrl->id) {
+       case V4L2_CID_TV_LAYER_BLEND_ENABLE:
+               mdev->sub_mxr[cur_mxr].layer[num]->layer_blend_en = v;
+               break;
+       case V4L2_CID_TV_LAYER_BLEND_ALPHA:
+               mdev->sub_mxr[cur_mxr].layer[num]->layer_alpha = (u32)v;
+               break;
+       case V4L2_CID_TV_PIXEL_BLEND_ENABLE:
+               mdev->sub_mxr[cur_mxr].layer[num]->pixel_blend_en = v;
+               break;
+       case V4L2_CID_TV_CHROMA_ENABLE:
+               mdev->sub_mxr[cur_mxr].layer[num]->chroma_en = v;
+               break;
+       case V4L2_CID_TV_CHROMA_VALUE:
+               mdev->sub_mxr[cur_mxr].layer[num]->chroma_val = (u32)v;
+               break;
+       case V4L2_CID_TV_HPD_STATUS:
+               v4l2_subdev_call(to_outsd(mdev), core, s_ctrl, ctrl);
+               break;
+       default:
+               mxr_err(mdev, "invalid control id\n");
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+static int mxr_g_ctrl(struct file *file, void *fh, struct v4l2_control *ctrl)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       struct mxr_device *mdev = layer->mdev;
+       int num = 0;
+       int ret = 0;
+
+       mxr_dbg(mdev, "%s start\n", __func__);
+
+       if (layer->type == MXR_LAYER_TYPE_VIDEO)
+               num = 0;
+       else if (layer->type == MXR_LAYER_TYPE_GRP && layer->idx == 0)
+               num = 1;
+       else if (layer->type == MXR_LAYER_TYPE_GRP && layer->idx == 1)
+               num = 2;
+
+       ret = mxr_check_ctrl_val(ctrl);
+
+       switch (ctrl->id) {
+       case V4L2_CID_TV_HPD_STATUS:
+               v4l2_subdev_call(to_outsd(mdev), core, g_ctrl, ctrl);
+               break;
+       default:
+               mxr_err(mdev, "invalid control id\n");
+               ret = -EINVAL;
+               break;
+       }
+       return ret;
+}
+
+static int mxr_enum_dv_presets(struct file *file, void *fh,
+       struct v4l2_dv_enum_preset *preset)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       struct mxr_device *mdev = layer->mdev;
+       int ret;
+
+       /* lock protects from changing sd_out */
+       mutex_lock(&mdev->mutex);
+       ret = v4l2_subdev_call(to_outsd(mdev), video, enum_dv_presets, preset);
+       mutex_unlock(&mdev->mutex);
+
+       return ret ? -EINVAL : 0;
+}
+
+static int mxr_s_dv_preset(struct file *file, void *fh,
+       struct v4l2_dv_preset *preset)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       struct mxr_device *mdev = layer->mdev;
+       int ret;
+
+       /* lock protects from changing sd_out */
+       mutex_lock(&mdev->mutex);
+
+       /* preset change cannot be done while there is an entity
+        * dependant on output configuration
+        */
+       if (mdev->n_output > 0) {
+               mutex_unlock(&mdev->mutex);
+               return -EBUSY;
+       }
+
+       ret = v4l2_subdev_call(to_outsd(mdev), video, s_dv_preset, preset);
+
+       mutex_unlock(&mdev->mutex);
+
+       /* any failure should return EINVAL according to V4L2 doc */
+       return ret ? -EINVAL : 0;
+}
+
+static int mxr_g_dv_preset(struct file *file, void *fh,
+       struct v4l2_dv_preset *preset)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       struct mxr_device *mdev = layer->mdev;
+       int ret;
+
+       /* lock protects from changing sd_out */
+       mutex_lock(&mdev->mutex);
+       ret = v4l2_subdev_call(to_outsd(mdev), video, g_dv_preset, preset);
+       mutex_unlock(&mdev->mutex);
+
+       return ret ? -EINVAL : 0;
+}
+
+static int mxr_s_std(struct file *file, void *fh, v4l2_std_id *norm)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       struct mxr_device *mdev = layer->mdev;
+       int ret;
+
+       /* lock protects from changing sd_out */
+       mutex_lock(&mdev->mutex);
+
+       /* standard change cannot be done while there is an entity
+        * dependant on output configuration
+        */
+       if (mdev->n_output > 0) {
+               mutex_unlock(&mdev->mutex);
+               return -EBUSY;
+       }
+
+       ret = v4l2_subdev_call(to_outsd(mdev), video, s_std_output, *norm);
+
+       mutex_unlock(&mdev->mutex);
+
+       return ret ? -EINVAL : 0;
+}
+
+static int mxr_g_std(struct file *file, void *fh, v4l2_std_id *norm)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       struct mxr_device *mdev = layer->mdev;
+       int ret;
+
+       /* lock protects from changing sd_out */
+       mutex_lock(&mdev->mutex);
+       ret = v4l2_subdev_call(to_outsd(mdev), video, g_std_output, norm);
+       mutex_unlock(&mdev->mutex);
+
+       return ret ? -EINVAL : 0;
+}
+
+static int mxr_enum_output(struct file *file, void *fh, struct v4l2_output *a)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       struct mxr_device *mdev = layer->mdev;
+       struct mxr_output *out;
+       struct v4l2_subdev *sd;
+
+       if (a->index >= mdev->output_cnt)
+               return -EINVAL;
+       out = mdev->output[a->index];
+       BUG_ON(out == NULL);
+       sd = out->sd;
+       strlcpy(a->name, out->name, sizeof(a->name));
+
+       /* try to obtain supported tv norms */
+       v4l2_subdev_call(sd, video, g_tvnorms_output, &a->std);
+       a->capabilities = 0;
+       if (sd->ops->video && sd->ops->video->s_dv_preset)
+               a->capabilities |= V4L2_OUT_CAP_PRESETS;
+       if (sd->ops->video && sd->ops->video->s_std_output)
+               a->capabilities |= V4L2_OUT_CAP_STD;
+       a->type = V4L2_OUTPUT_TYPE_ANALOG;
+
+       return 0;
+}
+
+static int mxr_s_output(struct file *file, void *fh, unsigned int i)
+{
+       struct video_device *vfd = video_devdata(file);
+       struct mxr_layer *layer = video_drvdata(file);
+       struct mxr_device *mdev = layer->mdev;
+       int ret = 0;
+
+       if (i >= mdev->output_cnt || mdev->output[i] == NULL)
+               return -EINVAL;
+
+       mutex_lock(&mdev->mutex);
+       if (mdev->n_output > 0) {
+               ret = -EBUSY;
+               goto done;
+       }
+       mdev->current_output = i;
+       vfd->tvnorms = 0;
+       v4l2_subdev_call(to_outsd(mdev), video, g_tvnorms_output,
+               &vfd->tvnorms);
+       mxr_dbg(mdev, "tvnorms = %08llx\n", vfd->tvnorms);
+
+done:
+       mutex_unlock(&mdev->mutex);
+       return ret;
+}
+
+static int mxr_g_output(struct file *file, void *fh, unsigned int *p)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       struct mxr_device *mdev = layer->mdev;
+
+       mutex_lock(&mdev->mutex);
+       *p = mdev->current_output;
+       mutex_unlock(&mdev->mutex);
+
+       return 0;
+}
+
+static int mxr_reqbufs(struct file *file, void *priv,
+                         struct v4l2_requestbuffers *p)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+
+       mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+       return vb2_reqbufs(&layer->vb_queue, p);
+}
+
+static int mxr_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+
+       mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+       return vb2_querybuf(&layer->vb_queue, p);
+}
+
+static int mxr_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+
+       mxr_dbg(layer->mdev, "%s:%d(%d)\n", __func__, __LINE__, p->index);
+       return vb2_qbuf(&layer->vb_queue, p);
+}
+
+static int mxr_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+
+       mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+       return vb2_dqbuf(&layer->vb_queue, p, file->f_flags & O_NONBLOCK);
+}
+
+static int mxr_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       struct mxr_device *mdev = layer->mdev;
+
+       switch (layer->idx) {
+       case 0:
+               mdev->layer_en.graph0 = 1;
+               break;
+       case 1:
+               mdev->layer_en.graph1 = 1;
+               break;
+       case 2:
+               mdev->layer_en.graph2 = 1;
+               break;
+       case 3:
+               mdev->layer_en.graph3 = 1;
+               break;
+       default:
+               mxr_err(mdev, "invalid layer number\n");
+               return -EINVAL;
+       }
+
+       if ((mdev->layer_en.graph0 && mdev->layer_en.graph2) ||
+           (mdev->layer_en.graph1 && mdev->layer_en.graph3)) {
+               mdev->frame_packing = 1;
+               mxr_dbg(mdev, "frame packing mode\n");
+       }
+
+       layer->ops.stream_set(layer, MXR_ENABLE);
+       mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+       return vb2_streamon(&layer->vb_queue, i);
+}
+
+static int mxr_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       struct mxr_device *mdev = layer->mdev;
+
+       switch (layer->idx) {
+       case 0:
+               mdev->layer_en.graph0 = 0;
+               break;
+       case 1:
+               mdev->layer_en.graph1 = 0;
+               break;
+       case 2:
+               mdev->layer_en.graph2 = 0;
+               break;
+       case 3:
+               mdev->layer_en.graph3 = 0;
+               break;
+       default:
+               mxr_err(mdev, "invalid layer number\n");
+               return -EINVAL;
+       }
+
+       mdev->frame_packing = 0;
+       if ((mdev->layer_en.graph0 && mdev->layer_en.graph2) ||
+           (mdev->layer_en.graph1 && mdev->layer_en.graph3)) {
+               mdev->frame_packing = 1;
+               mxr_dbg(mdev, "frame packing mode\n");
+       }
+
+       mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+       return vb2_streamoff(&layer->vb_queue, i);
+}
+
+static const struct v4l2_ioctl_ops mxr_ioctl_ops = {
+       .vidioc_querycap = mxr_querycap,
+       /* format handling */
+       .vidioc_enum_fmt_vid_out = mxr_enum_fmt,
+       .vidioc_s_fmt_vid_out_mplane = mxr_s_fmt,
+       .vidioc_g_fmt_vid_out_mplane = mxr_g_fmt,
+       /* buffer control */
+       .vidioc_reqbufs = mxr_reqbufs,
+       .vidioc_querybuf = mxr_querybuf,
+       .vidioc_qbuf = mxr_qbuf,
+       .vidioc_dqbuf = mxr_dqbuf,
+       /* Streaming control */
+       .vidioc_streamon = mxr_streamon,
+       .vidioc_streamoff = mxr_streamoff,
+       /* Preset functions */
+       .vidioc_enum_dv_presets = mxr_enum_dv_presets,
+       .vidioc_s_dv_preset = mxr_s_dv_preset,
+       .vidioc_g_dv_preset = mxr_g_dv_preset,
+       /* analog TV standard functions */
+       .vidioc_s_std = mxr_s_std,
+       .vidioc_g_std = mxr_g_std,
+       /* Output handling */
+       .vidioc_enum_output = mxr_enum_output,
+       .vidioc_s_output = mxr_s_output,
+       .vidioc_g_output = mxr_g_output,
+       /* Crop ioctls */
+       .vidioc_g_crop = mxr_g_crop,
+       .vidioc_s_crop = mxr_s_crop,
+       .vidioc_cropcap = mxr_cropcap,
+       /* Alpha blending functions */
+       .vidioc_s_ctrl = mxr_s_ctrl,
+       .vidioc_g_ctrl = mxr_g_ctrl,
+};
+
+static int mxr_video_open(struct file *file)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       struct mxr_device *mdev = layer->mdev;
+       int ret = 0;
+
+       mxr_dbg(mdev, "%s:%d\n", __func__, __LINE__);
+       /* assure device probe is finished */
+       wait_for_device_probe();
+       /* creating context for file descriptor */
+       ret = v4l2_fh_open(file);
+       if (ret) {
+               mxr_err(mdev, "v4l2_fh_open failed\n");
+               return ret;
+       }
+
+       /* leaving if layer is already initialized */
+       if (!v4l2_fh_is_singular_file(file))
+               return 0;
+
+       ret = vb2_queue_init(&layer->vb_queue);
+       if (ret != 0) {
+               mxr_err(mdev, "failed to initialize vb2 queue\n");
+               goto fail_fh_open;
+       }
+       /* set default format, first on the list */
+       layer->fmt = layer->fmt_array[0];
+       /* setup default geometry */
+       mxr_layer_default_geo(layer);
+
+       return 0;
+
+fail_fh_open:
+       v4l2_fh_release(file);
+
+       return ret;
+}
+
+static unsigned int
+mxr_video_poll(struct file *file, struct poll_table_struct *wait)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+
+       mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+
+       return vb2_poll(&layer->vb_queue, file, wait);
+}
+
+static int mxr_video_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+
+       mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+
+       return vb2_mmap(&layer->vb_queue, vma);
+}
+
+static int mxr_video_release(struct file *file)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+
+       mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+
+       /* initialize alpha blending variables */
+       layer->layer_blend_en = 0;
+       layer->layer_alpha = 0;
+       layer->pixel_blend_en = 0;
+       layer->chroma_en = 0;
+       layer->chroma_val = 0;
+
+       if (v4l2_fh_is_singular_file(file))
+               vb2_queue_release(&layer->vb_queue);
+
+       v4l2_fh_release(file);
+       return 0;
+}
+
+static const struct v4l2_file_operations mxr_fops = {
+       .owner = THIS_MODULE,
+       .open = mxr_video_open,
+       .poll = mxr_video_poll,
+       .mmap = mxr_video_mmap,
+       .release = mxr_video_release,
+       .unlocked_ioctl = video_ioctl2,
+};
+
+static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *pfmt,
+               unsigned int *nbuffers, unsigned int *nplanes,
+               unsigned int sizes[], void *alloc_ctxs[])
+{
+       struct mxr_layer *layer = vb2_get_drv_priv(vq);
+       const struct mxr_format *fmt = layer->fmt;
+       int i;
+       struct mxr_device *mdev = layer->mdev;
+       struct v4l2_plane_pix_format planes[3];
+
+       mxr_dbg(mdev, "%s fmt->num_planes=%d\n", __func__,fmt->num_planes);
+       /* checking if format was configured */
+       if (fmt == NULL)
+               return -EINVAL;
+       mxr_dbg(mdev, "fmt = %s\n", fmt->name);
+       mxr_mplane_fill(planes, fmt, layer->geo.src.full_width,
+               layer->geo.src.full_height);
+
+       *nplanes = fmt->num_subframes;
+       for (i = 0; i < fmt->num_subframes; ++i) {
+               alloc_ctxs[i] = layer->mdev->alloc_ctx;
+               sizes[i] = PAGE_ALIGN(planes[i].sizeimage);
+               mxr_dbg(mdev, "size[%d] = %08x\n", i, sizes[i]);
+       }
+
+       if (*nbuffers == 0)
+               *nbuffers = 1;
+
+       return 0;
+}
+
+static void buf_queue(struct vb2_buffer *vb)
+{
+       struct mxr_buffer *buffer = container_of(vb, struct mxr_buffer, vb);
+       struct mxr_layer *layer = vb2_get_drv_priv(vb->vb2_queue);
+       struct mxr_device *mdev = layer->mdev;
+       struct tv_graph_pipeline *pipe = &layer->pipe;
+       unsigned long flags;
+
+       spin_lock_irqsave(&layer->enq_slock, flags);
+       list_add_tail(&buffer->list, &layer->enq_list);
+       spin_unlock_irqrestore(&layer->enq_slock, flags);
+
+       spin_lock_irqsave(&layer->enq_slock, flags);
+       if (pipe->state == TV_GRAPH_PIPELINE_STREAMING_START)
+               pipe->state = TV_GRAPH_PIPELINE_STREAMING;
+
+       spin_unlock_irqrestore(&layer->enq_slock, flags);
+
+       mxr_dbg(mdev, "queuing buffer\n");
+}
+
+static void wait_lock(struct vb2_queue *vq)
+{
+       struct mxr_layer *layer = vb2_get_drv_priv(vq);
+
+       mxr_dbg(layer->mdev, "%s\n", __func__);
+       mutex_lock(&layer->mutex);
+}
+
+static void wait_unlock(struct vb2_queue *vq)
+{
+       struct mxr_layer *layer = vb2_get_drv_priv(vq);
+
+       mxr_dbg(layer->mdev, "%s\n", __func__);
+       mutex_unlock(&layer->mutex);
+}
+
+static int buf_prepare(struct vb2_buffer *vb)
+{
+       struct mxr_layer *layer = vb2_get_drv_priv(vb->vb2_queue);
+       struct mxr_device *mdev = layer->mdev;
+       struct v4l2_subdev *sd;
+       struct media_pad *pad;
+       int i, j;
+       int enable = 0;
+       mxr_dbg(layer->mdev, "%s\n", __func__);
+
+       for (i = 0; i < MXR_MAX_SUB_MIXERS; ++i) {
+               sd = &mdev->sub_mxr[i].sd;
+
+               for (j = MXR_PAD_SOURCE_GSCALER; j < MXR_PADS_NUM; ++j) {
+                       pad = &sd->entity.pads[j];
+
+                       /* find sink pad of hdmi or sdo through enabled link*/
+                       pad = media_entity_remote_source(pad);
+                       if (media_entity_type(pad->entity)
+                                       == MEDIA_ENT_T_V4L2_SUBDEV) {
+                               enable = 1;
+                               break;
+                       }
+               }
+               if (enable)
+                       break;
+       }
+       if (!enable)
+               return -ENODEV;
+
+       sd = media_entity_to_v4l2_subdev(pad->entity);
+
+       /* current output device must be matched terminal entity
+        * which represents HDMI or SDO sub-device
+        */
+       if (strcmp(sd->name, to_output(mdev)->sd->name)) {
+               mxr_err(mdev, "subdev name : %s, output device name : %s\n",
+                               sd->name, to_output(mdev)->sd->name);
+               mxr_err(mdev, "output device is not mached\n");
+               return -ERANGE;
+       }
+
+       return 0;
+}
+
+static int start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+       struct mxr_layer *layer = vb2_get_drv_priv(vq);
+       struct mxr_device *mdev = layer->mdev;
+       struct tv_graph_pipeline *pipe = &layer->pipe;
+       unsigned long flags;
+       int ret;
+
+       mxr_dbg(mdev, "%s\n", __func__);
+
+       if (count == 0) {
+               mxr_dbg(mdev, "no output buffers queued\n");
+               return -EINVAL;
+       }
+
+       /* enable mixer clock */
+       ret = mxr_power_get(mdev);
+       if (ret)
+               mxr_err(mdev, "power on failed\n");
+
+       /* block any changes in output configuration */
+       mxr_output_get(mdev);
+
+       /* update layers geometry */
+       mxr_layer_geo_fix(layer);
+       mxr_geometry_dump(mdev, &layer->geo);
+
+       layer->ops.format_set(layer);
+
+       spin_lock_irqsave(&layer->enq_slock, flags);
+       pipe->state = TV_GRAPH_PIPELINE_STREAMING_START;
+       spin_unlock_irqrestore(&layer->enq_slock, flags);
+
+       /* enabling layer in hardware */
+       layer->ops.stream_set(layer, MXR_ENABLE);
+       /* store starting entity ptr on the tv graphic pipeline */
+       pipe->layer = layer;
+       /* start streaming all entities on the tv graphic pipeline */
+       tv_graph_pipeline_stream(pipe, 1);
+
+       return 0;
+}
+
+static void mxr_watchdog(unsigned long arg)
+{
+       struct mxr_layer *layer = (struct mxr_layer *) arg;
+       struct mxr_device *mdev = layer->mdev;
+       unsigned long flags;
+
+       mxr_err(mdev, "watchdog fired for layer %s\n", layer->vfd.name);
+
+       spin_lock_irqsave(&layer->enq_slock, flags);
+
+       if (layer->update_buf == layer->shadow_buf)
+               layer->update_buf = NULL;
+       if (layer->update_buf) {
+               vb2_buffer_done(&layer->update_buf->vb, VB2_BUF_STATE_ERROR);
+               layer->update_buf = NULL;
+       }
+       if (layer->shadow_buf) {
+               vb2_buffer_done(&layer->shadow_buf->vb, VB2_BUF_STATE_ERROR);
+               layer->shadow_buf = NULL;
+       }
+       spin_unlock_irqrestore(&layer->enq_slock, flags);
+}
+
+static int stop_streaming(struct vb2_queue *vq)
+{
+       struct mxr_layer *layer = vb2_get_drv_priv(vq);
+       struct mxr_device *mdev = layer->mdev;
+       unsigned long flags;
+       struct timer_list watchdog;
+       struct mxr_buffer *buf, *buf_tmp;
+       struct tv_graph_pipeline *pipe = &layer->pipe;
+
+       mxr_dbg(mdev, "%s\n", __func__);
+
+       spin_lock_irqsave(&layer->enq_slock, flags);
+
+       /* reset list */
+       pipe->state = TV_GRAPH_PIPELINE_STREAMING_FINISH;
+
+       /* set all buffer to be done */
+       list_for_each_entry_safe(buf, buf_tmp, &layer->enq_list, list) {
+               list_del(&buf->list);
+               vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+       }
+
+       spin_unlock_irqrestore(&layer->enq_slock, flags);
+
+       /* give 1 seconds to complete to complete last buffers */
+       setup_timer_on_stack(&watchdog, mxr_watchdog,
+               (unsigned long)layer);
+       mod_timer(&watchdog, jiffies + msecs_to_jiffies(1000));
+
+       /* wait until all buffers are goes to done state */
+       vb2_wait_for_all_buffers(vq);
+
+       /* stop timer if all synchronization is done */
+       del_timer_sync(&watchdog);
+       destroy_timer_on_stack(&watchdog);
+
+       /* stopping hardware */
+       spin_lock_irqsave(&layer->enq_slock, flags);
+
+       pipe->state = TV_GRAPH_PIPELINE_IDLE;
+       spin_unlock_irqrestore(&layer->enq_slock, flags);
+
+       /* disabling layer in hardware */
+       layer->ops.stream_set(layer, MXR_DISABLE);
+
+       /* starting entity on the pipeline */
+       pipe->layer = layer;
+       /* stop streaming all entities on the pipeline */
+       tv_graph_pipeline_stream(pipe, 0);
+
+       /* allow changes in output configuration */
+       mxr_output_put(mdev);
+
+       /* disable mixer clock */
+       mxr_power_put(mdev);
+
+       return 0;
+}
+
+static struct vb2_ops mxr_video_qops = {
+       .queue_setup = queue_setup,
+       .buf_queue = buf_queue,
+       .wait_prepare = wait_unlock,
+       .wait_finish = wait_lock,
+       .buf_prepare = buf_prepare,
+       .start_streaming = start_streaming,
+       .stop_streaming = stop_streaming,
+};
+
+/* FIXME: try to put this functions to mxr_base_layer_create */
+int mxr_base_layer_register(struct mxr_layer *layer)
+{
+       struct mxr_device *mdev = layer->mdev;
+       struct exynos_md *md;
+       int ret;
+
+       md = (struct exynos_md *)module_name_to_driver_data(MDEV_MODULE_NAME);
+       if (!md) {
+               mxr_err(mdev, "failed to get output media device\n");
+               return -ENODEV;
+       }
+
+       layer->vfd.v4l2_dev = &md->v4l2_dev;
+       ret = video_register_device(&layer->vfd, VFL_TYPE_GRABBER,
+                       layer->minor);
+       if (ret)
+               mxr_err(mdev, "failed to register video device\n");
+       else
+               mxr_info(mdev, "registered layer %s as /dev/video%d\n",
+                       layer->vfd.name, layer->vfd.num);
+
+       layer->fb = vb2_fb_register(&layer->vb_queue, &layer->vfd);
+       if (PTR_ERR(layer->fb))
+               layer->fb = NULL;
+
+       return ret;
+}
+
+void mxr_base_layer_unregister(struct mxr_layer *layer)
+{
+       if (layer->fb)
+               vb2_fb_unregister(layer->fb);
+       video_unregister_device(&layer->vfd);
+}
+
+void mxr_layer_release(struct mxr_layer *layer)
+{
+       if (layer->ops.release)
+               layer->ops.release(layer);
+}
+
+void mxr_base_layer_release(struct mxr_layer *layer)
+{
+       kfree(layer);
+}
+
+static void mxr_vfd_release(struct video_device *vdev)
+{
+       printk(KERN_INFO "video device release\n");
+}
+
+struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev,
+       int idx, char *name, struct mxr_layer_ops *ops)
+{
+       struct mxr_layer *layer;
+       int ret;
+
+       layer = kzalloc(sizeof *layer, GFP_KERNEL);
+       if (layer == NULL) {
+               mxr_err(mdev, "not enough memory for layer.\n");
+               goto fail;
+       }
+
+       layer->mdev = mdev;
+       layer->idx = idx;
+       layer->ops = *ops;
+
+       spin_lock_init(&layer->enq_slock);
+       INIT_LIST_HEAD(&layer->enq_list);
+       mutex_init(&layer->mutex);
+
+       layer->vfd = (struct video_device) {
+               .minor = -1,
+               .release = mxr_vfd_release,
+               .fops = &mxr_fops,
+               .ioctl_ops = &mxr_ioctl_ops,
+       };
+
+       /* media_entity_init must be called after initializing layer->vfd
+        * for preventing to overwrite
+        */
+       ret = media_entity_init(&layer->vfd.entity, 1, &layer->pad, 0);
+       if (ret) {
+               mxr_err(mdev, "media entity init failed\n");
+               goto fail_alloc;
+       }
+
+       strlcpy(layer->vfd.name, name, sizeof(layer->vfd.name));
+       layer->vfd.entity.name = layer->vfd.name;
+       /* let framework control PRIORITY */
+       set_bit(V4L2_FL_USE_FH_PRIO, &layer->vfd.flags);
+
+       video_set_drvdata(&layer->vfd, layer);
+       layer->vfd.lock = &layer->mutex;
+
+       layer->vb_queue = (struct vb2_queue) {
+               .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+               .io_modes = VB2_MMAP | VB2_USERPTR| VB2_DMABUF,
+               .drv_priv = layer,
+               .buf_struct_size = sizeof(struct mxr_buffer),
+               .ops = &mxr_video_qops,
+               .mem_ops = &vb2_dma_contig_memops,
+       };
+       return layer;
+
+fail_alloc:
+       kfree(layer);
+
+fail:
+       return NULL;
+}
+
+const struct mxr_format *find_format_by_fourcc(
+       struct mxr_layer *layer, unsigned long fourcc)
+{
+       int i;
+
+       for (i = 0; i < layer->fmt_array_size; ++i)
+               if (layer->fmt_array[i]->fourcc == fourcc)
+                       return layer->fmt_array[i];
+       return NULL;
+}
+
+static const struct mxr_format *find_format_by_index(
+       struct mxr_layer *layer, unsigned long index)
+{
+       if (index >= layer->fmt_array_size)
+               return NULL;
+       return layer->fmt_array[index];
+}
diff --git a/drivers/media/video/exynos/tv/mixer_video_layer.c b/drivers/media/video/exynos/tv/mixer_video_layer.c
new file mode 100644 (file)
index 0000000..225fc38
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Samsung TV Mixer driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.com>
+ *
+ * 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 Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#include "mixer.h"
+
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+#include <media/videobuf2-cma-phys.h>
+#elif defined(CONFIG_VIDEOBUF2_ION)
+#include <media/videobuf2-ion.h>
+#endif
+
+/* AUXILIARY CALLBACKS */
+
+static void mxr_video_layer_release(struct mxr_layer *layer)
+{
+       mxr_base_layer_release(layer);
+}
+
+static void mxr_video_stream_set(struct mxr_layer *layer, int en)
+{
+       mxr_reg_video_layer_stream(layer->mdev, layer->idx, en);
+}
+
+static void mxr_video_format_set(struct mxr_layer *layer)
+{
+       mxr_reg_video_geo(layer->mdev, layer->cur_mxr, layer->idx, &layer->geo);
+}
+
+static void mxr_video_fix_geometry(struct mxr_layer *layer)
+{
+       struct mxr_geometry *geo = &layer->geo;
+
+       mxr_dbg(layer->mdev, "%s start\n", __func__);
+       geo->dst.x_offset = clamp_val(geo->dst.x_offset, 0,
+                       geo->dst.full_width - 1);
+       geo->dst.y_offset = clamp_val(geo->dst.y_offset, 0,
+                       geo->dst.full_height - 1);
+
+       /* mixer scale-up is unuseful. so no use it */
+       geo->dst.width = clamp_val(geo->dst.width, 1,
+                       geo->dst.full_width - geo->dst.x_offset);
+       geo->dst.height = clamp_val(geo->dst.height, 1,
+                       geo->dst.full_height - geo->dst.y_offset);
+}
+
+/* PUBLIC API */
+
+struct mxr_layer *mxr_video_layer_create(struct mxr_device *mdev, int cur_mxr,
+               int idx)
+{
+       struct mxr_layer *layer;
+       struct mxr_layer_ops ops = {
+               .release = mxr_video_layer_release,
+               .stream_set = mxr_video_stream_set,
+               .format_set = mxr_video_format_set,
+               .fix_geometry = mxr_video_fix_geometry,
+       };
+
+       layer = kzalloc(sizeof *layer, GFP_KERNEL);
+       if (layer == NULL) {
+               mxr_err(mdev, "not enough memory for layer.\n");
+               goto fail;
+       }
+
+       layer->mdev = mdev;
+       layer->idx = idx;
+       layer->type = MXR_LAYER_TYPE_VIDEO;
+       layer->ops = ops;
+
+       layer->cur_mxr = cur_mxr;
+
+       mxr_layer_default_geo(layer);
+
+       return layer;
+
+fail:
+       return NULL;
+}
diff --git a/drivers/media/video/exynos/tv/mixer_vp_layer.c b/drivers/media/video/exynos/tv/mixer_vp_layer.c
new file mode 100644 (file)
index 0000000..65bdbbe
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * Samsung TV Mixer driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.com>
+ *
+ * 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 Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#include "mixer.h"
+
+#include "regs-vp.h"
+
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+#include <media/videobuf2-cma-phys.h>
+#elif defined(CONFIG_VIDEOBUF2_ION)
+#include <media/videobuf2-ion.h>
+#endif
+
+/* FORMAT DEFINITIONS */
+static const struct mxr_format mxr_fmt_nv12 = {
+       .name = "NV12",
+       .fourcc = V4L2_PIX_FMT_NV12,
+       .colorspace = V4L2_COLORSPACE_JPEG,
+       .num_planes = 2,
+       .plane = {
+               { .width = 1, .height = 1, .size = 1 },
+               { .width = 2, .height = 2, .size = 2 },
+       },
+       .num_subframes = 1,
+       .cookie = VP_MODE_NV12 | VP_MODE_MEM_LINEAR,
+};
+
+static const struct mxr_format mxr_fmt_nv21 = {
+       .name = "NV21",
+       .fourcc = V4L2_PIX_FMT_NV21,
+       .colorspace = V4L2_COLORSPACE_JPEG,
+       .num_planes = 2,
+       .plane = {
+               { .width = 1, .height = 1, .size = 1 },
+               { .width = 2, .height = 2, .size = 2 },
+       },
+       .num_subframes = 1,
+       .cookie = VP_MODE_NV21 | VP_MODE_MEM_LINEAR,
+};
+
+static const struct mxr_format mxr_fmt_nv12m = {
+       .name = "NV12 (mplane)",
+       .fourcc = V4L2_PIX_FMT_NV12M,
+       .colorspace = V4L2_COLORSPACE_JPEG,
+       .num_planes = 2,
+       .plane = {
+               { .width = 1, .height = 1, .size = 1 },
+               { .width = 2, .height = 2, .size = 2 },
+       },
+       .num_subframes = 2,
+       .plane2subframe = {0, 1},
+       .cookie = VP_MODE_NV12 | VP_MODE_MEM_LINEAR,
+};
+
+static const struct mxr_format mxr_fmt_nv12mt = {
+       .name = "NV12 tiled (mplane)",
+       .fourcc = V4L2_PIX_FMT_NV12MT,
+       .colorspace = V4L2_COLORSPACE_JPEG,
+       .num_planes = 2,
+       .plane = {
+               { .width = 128, .height = 32, .size = 4096 },
+               { .width = 128, .height = 32, .size = 2048 },
+       },
+       .num_subframes = 2,
+       .plane2subframe = {0, 1},
+       .cookie = VP_MODE_NV12 | VP_MODE_MEM_TILED,
+};
+
+static const struct mxr_format *mxr_video_format[] = {
+       &mxr_fmt_nv12,
+       &mxr_fmt_nv21,
+       &mxr_fmt_nv12m,
+       &mxr_fmt_nv12mt,
+};
+
+/* AUXILIARY CALLBACKS */
+
+static void mxr_vp_layer_release(struct mxr_layer *layer)
+{
+       mxr_base_layer_unregister(layer);
+       mxr_base_layer_release(layer);
+}
+
+static void mxr_vp_buffer_set(struct mxr_layer *layer,
+       struct mxr_buffer *buf)
+{
+       struct mxr_device *mdev = layer->mdev;
+       dma_addr_t luma_addr[2] = {0, 0};
+       dma_addr_t chroma_addr[2] = {0, 0};
+
+       if (buf == NULL) {
+               mxr_reg_vp_buffer(mdev, luma_addr, chroma_addr);
+               return;
+       }
+
+       luma_addr[0] = mdev->vb2->plane_addr(&buf->vb, 0);
+       if (layer->fmt->num_subframes == 2) {
+               chroma_addr[0] = mdev->vb2->plane_addr(&buf->vb, 1);
+       } else {
+               /* FIXME: mxr_get_plane_size compute integer division,
+                * which is slow and should not be performed in interrupt */
+               chroma_addr[0] = luma_addr[0] + mxr_get_plane_size(
+                       &layer->fmt->plane[0], layer->geo.src.full_width,
+                       layer->geo.src.full_height);
+       }
+       if (layer->fmt->cookie & VP_MODE_MEM_TILED) {
+               luma_addr[1] = luma_addr[0] + 0x40;
+               chroma_addr[1] = chroma_addr[0] + 0x40;
+       } else {
+               luma_addr[1] = luma_addr[0] + layer->geo.src.full_width;
+               chroma_addr[1] = chroma_addr[0];
+       }
+       mxr_reg_vp_buffer(layer->mdev, luma_addr, chroma_addr);
+}
+
+static void mxr_vp_stream_set(struct mxr_layer *layer, int en)
+{
+       mxr_reg_vp_layer_stream(layer->mdev, en);
+}
+
+static void mxr_vp_format_set(struct mxr_layer *layer)
+{
+       mxr_reg_vp_format(layer->mdev, layer->fmt, &layer->geo);
+}
+
+static void mxr_vp_fix_geometry(struct mxr_layer *layer)
+{
+       struct mxr_geometry *geo = &layer->geo;
+
+       mxr_dbg(layer->mdev, "%s start\n", __func__);
+       /* align horizontal size to 8 pixels */
+       geo->src.full_width = ALIGN(geo->src.full_width, 8);
+       /* limit to boundary size */
+       geo->src.full_width = clamp_val(geo->src.full_width, 8, 8192);
+       geo->src.full_height = clamp_val(geo->src.full_height, 1, 8192);
+       geo->src.width = clamp_val(geo->src.width, 32, geo->src.full_width);
+       geo->src.width = min(geo->src.width, 2047U);
+       geo->src.height = clamp_val(geo->src.height, 4, geo->src.full_height);
+       geo->src.height = min(geo->src.height, 2047U);
+
+       /* setting size of output window */
+       geo->dst.width = clamp_val(geo->dst.width, 8, geo->dst.full_width);
+       geo->dst.height = clamp_val(geo->dst.height, 1, geo->dst.full_height);
+
+       /* ensure that scaling is in range 1/4x to 16x */
+       if (geo->src.width >= 4 * geo->dst.width)
+               geo->src.width = 4 * geo->dst.width;
+       if (geo->dst.width >= 16 * geo->src.width)
+               geo->dst.width = 16 * geo->src.width;
+       if (geo->src.height >= 4 * geo->dst.height)
+               geo->src.height = 4 * geo->dst.height;
+       if (geo->dst.height >= 16 * geo->src.height)
+               geo->dst.height = 16 * geo->src.height;
+
+       /* setting scaling ratio */
+       geo->x_ratio = (geo->src.width << 16) / geo->dst.width;
+       geo->y_ratio = (geo->src.height << 16) / geo->dst.height;
+
+       /* adjust offsets */
+       geo->src.x_offset = min(geo->src.x_offset,
+               geo->src.full_width - geo->src.width);
+       geo->src.y_offset = min(geo->src.y_offset,
+               geo->src.full_height - geo->src.height);
+       geo->dst.x_offset = min(geo->dst.x_offset,
+               geo->dst.full_width - geo->dst.width);
+       geo->dst.y_offset = min(geo->dst.y_offset,
+               geo->dst.full_height - geo->dst.height);
+}
+
+/* PUBLIC API */
+
+struct mxr_layer *mxr_vp_layer_create(struct mxr_device *mdev, int cur_mxr,
+               int idx, int nr)
+{
+       struct mxr_layer *layer;
+       int ret;
+       struct mxr_layer_ops ops = {
+               .release = mxr_vp_layer_release,
+               .buffer_set = mxr_vp_buffer_set,
+               .stream_set = mxr_vp_stream_set,
+               .format_set = mxr_vp_format_set,
+               .fix_geometry = mxr_vp_fix_geometry,
+       };
+       char name[32];
+
+       sprintf(name, "mxr%d_video%d", cur_mxr, idx);
+
+       layer = mxr_base_layer_create(mdev, idx, name, &ops);
+       if (layer == NULL) {
+               mxr_err(mdev, "failed to initialize layer(%d) base\n", idx);
+               goto fail;
+       }
+
+       layer->fmt_array = mxr_video_format;
+       layer->fmt_array_size = ARRAY_SIZE(mxr_video_format);
+       layer->minor = nr;
+       layer->type = MXR_LAYER_TYPE_VIDEO;
+
+       ret = mxr_base_layer_register(layer);
+       if (ret)
+               goto fail_layer;
+
+       layer->cur_mxr = cur_mxr;
+       return layer;
+
+fail_layer:
+       mxr_base_layer_release(layer);
+
+fail:
+       return NULL;
+}
diff --git a/drivers/media/video/exynos/tv/regs-hdmi-4210.h b/drivers/media/video/exynos/tv/regs-hdmi-4210.h
new file mode 100644 (file)
index 0000000..74c36d7
--- /dev/null
@@ -0,0 +1,142 @@
+/* linux/arch/arm/mach-exynos4/include/mach/regs-hdmi.h
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * HDMI register header file for Samsung TVOUT driver
+ *
+ * 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.
+*/
+
+#ifndef SAMSUNG_REGS_HDMI_H
+#define SAMSUNG_REGS_HDMI_H
+
+/*
+ * Register part
+*/
+
+#define HDMI_CTRL_BASE(x)              ((x) + 0x00000000)
+#define HDMI_CORE_BASE(x)              ((x) + 0x00010000)
+#define HDMI_TG_BASE(x)                        ((x) + 0x00050000)
+
+/* Control registers */
+#define HDMI_INTC_CON                  HDMI_CTRL_BASE(0x0000)
+#define HDMI_INTC_FLAG                 HDMI_CTRL_BASE(0x0004)
+#define HDMI_HPD_STATUS                        HDMI_CTRL_BASE(0x000C)
+#define HDMI_PHY_RSTOUT                        HDMI_CTRL_BASE(0x0014)
+#define HDMI_PHY_VPLL                  HDMI_CTRL_BASE(0x0018)
+#define HDMI_PHY_CMU                   HDMI_CTRL_BASE(0x001C)
+#define HDMI_CORE_RSTOUT               HDMI_CTRL_BASE(0x0020)
+
+/* Core registers */
+#define HDMI_CON_0                     HDMI_CORE_BASE(0x0000)
+#define HDMI_CON_1                     HDMI_CORE_BASE(0x0004)
+#define HDMI_CON_2                     HDMI_CORE_BASE(0x0008)
+#define HDMI_SYS_STATUS                        HDMI_CORE_BASE(0x0010)
+#define HDMI_PHY_STATUS                        HDMI_CORE_BASE(0x0014)
+#define HDMI_STATUS_EN                 HDMI_CORE_BASE(0x0020)
+#define HDMI_HPD                       HDMI_CORE_BASE(0x0030)
+#define HDMI_MODE_SEL                  HDMI_CORE_BASE(0x0040)
+#define HDMI_BLUE_SCREEN_0             HDMI_CORE_BASE(0x0050)
+#define HDMI_BLUE_SCREEN_1             HDMI_CORE_BASE(0x0054)
+#define HDMI_BLUE_SCREEN_2             HDMI_CORE_BASE(0x0058)
+#define HDMI_H_BLANK_0                 HDMI_CORE_BASE(0x00A0)
+#define HDMI_H_BLANK_1                 HDMI_CORE_BASE(0x00A4)
+#define HDMI_V_BLANK_0                 HDMI_CORE_BASE(0x00B0)
+#define HDMI_V_BLANK_1                 HDMI_CORE_BASE(0x00B4)
+#define HDMI_V_BLANK_2                 HDMI_CORE_BASE(0x00B8)
+#define HDMI_H_V_LINE_0                        HDMI_CORE_BASE(0x00C0)
+#define HDMI_H_V_LINE_1                        HDMI_CORE_BASE(0x00C4)
+#define HDMI_H_V_LINE_2                        HDMI_CORE_BASE(0x00C8)
+#define HDMI_VSYNC_POL                 HDMI_CORE_BASE(0x00E4)
+#define HDMI_INT_PRO_MODE              HDMI_CORE_BASE(0x00E8)
+#define HDMI_V_BLANK_F_0               HDMI_CORE_BASE(0x0110)
+#define HDMI_V_BLANK_F_1               HDMI_CORE_BASE(0x0114)
+#define HDMI_V_BLANK_F_2               HDMI_CORE_BASE(0x0118)
+#define HDMI_H_SYNC_GEN_0              HDMI_CORE_BASE(0x0120)
+#define HDMI_H_SYNC_GEN_1              HDMI_CORE_BASE(0x0124)
+#define HDMI_H_SYNC_GEN_2              HDMI_CORE_BASE(0x0128)
+#define HDMI_V_SYNC_GEN_1_0            HDMI_CORE_BASE(0x0130)
+#define HDMI_V_SYNC_GEN_1_1            HDMI_CORE_BASE(0x0134)
+#define HDMI_V_SYNC_GEN_1_2            HDMI_CORE_BASE(0x0138)
+#define HDMI_V_SYNC_GEN_2_0            HDMI_CORE_BASE(0x0140)
+#define HDMI_V_SYNC_GEN_2_1            HDMI_CORE_BASE(0x0144)
+#define HDMI_V_SYNC_GEN_2_2            HDMI_CORE_BASE(0x0148)
+#define HDMI_V_SYNC_GEN_3_0            HDMI_CORE_BASE(0x0150)
+#define HDMI_V_SYNC_GEN_3_1            HDMI_CORE_BASE(0x0154)
+#define HDMI_V_SYNC_GEN_3_2            HDMI_CORE_BASE(0x0158)
+#define HDMI_AVI_CON                   HDMI_CORE_BASE(0x0300)
+#define HDMI_AVI_BYTE(n)               HDMI_CORE_BASE(0x0320 + 4 * (n))
+#define        HDMI_DC_CONTROL                 HDMI_CORE_BASE(0x05C0)
+#define HDMI_VIDEO_PATTERN_GEN         HDMI_CORE_BASE(0x05C4)
+#define HDMI_HPD_GEN                   HDMI_CORE_BASE(0x05C8)
+
+/* Timing generator registers */
+#define HDMI_TG_CMD                    HDMI_TG_BASE(0x0000)
+#define HDMI_TG_H_FSZ_L                        HDMI_TG_BASE(0x0018)
+#define HDMI_TG_H_FSZ_H                        HDMI_TG_BASE(0x001C)
+#define HDMI_TG_HACT_ST_L              HDMI_TG_BASE(0x0020)
+#define HDMI_TG_HACT_ST_H              HDMI_TG_BASE(0x0024)
+#define HDMI_TG_HACT_SZ_L              HDMI_TG_BASE(0x0028)
+#define HDMI_TG_HACT_SZ_H              HDMI_TG_BASE(0x002C)
+#define HDMI_TG_V_FSZ_L                        HDMI_TG_BASE(0x0030)
+#define HDMI_TG_V_FSZ_H                        HDMI_TG_BASE(0x0034)
+#define HDMI_TG_VSYNC_L                        HDMI_TG_BASE(0x0038)
+#define HDMI_TG_VSYNC_H                        HDMI_TG_BASE(0x003C)
+#define HDMI_TG_VSYNC2_L               HDMI_TG_BASE(0x0040)
+#define HDMI_TG_VSYNC2_H               HDMI_TG_BASE(0x0044)
+#define HDMI_TG_VACT_ST_L              HDMI_TG_BASE(0x0048)
+#define HDMI_TG_VACT_ST_H              HDMI_TG_BASE(0x004C)
+#define HDMI_TG_VACT_SZ_L              HDMI_TG_BASE(0x0050)
+#define HDMI_TG_VACT_SZ_H              HDMI_TG_BASE(0x0054)
+#define HDMI_TG_FIELD_CHG_L            HDMI_TG_BASE(0x0058)
+#define HDMI_TG_FIELD_CHG_H            HDMI_TG_BASE(0x005C)
+#define HDMI_TG_VACT_ST2_L             HDMI_TG_BASE(0x0060)
+#define HDMI_TG_VACT_ST2_H             HDMI_TG_BASE(0x0064)
+#define HDMI_TG_VSYNC_TOP_HDMI_L       HDMI_TG_BASE(0x0078)
+#define HDMI_TG_VSYNC_TOP_HDMI_H       HDMI_TG_BASE(0x007C)
+#define HDMI_TG_VSYNC_BOT_HDMI_L       HDMI_TG_BASE(0x0080)
+#define HDMI_TG_VSYNC_BOT_HDMI_H       HDMI_TG_BASE(0x0084)
+#define HDMI_TG_FIELD_TOP_HDMI_L       HDMI_TG_BASE(0x0088)
+#define HDMI_TG_FIELD_TOP_HDMI_H       HDMI_TG_BASE(0x008C)
+#define HDMI_TG_FIELD_BOT_HDMI_L       HDMI_TG_BASE(0x0090)
+#define HDMI_TG_FIELD_BOT_HDMI_H       HDMI_TG_BASE(0x0094)
+
+/*
+ * Bit definition part
+ */
+
+/* HDMI_INTC_CON */
+#define HDMI_INTC_EN_GLOBAL            (1 << 6)
+#define HDMI_INTC_EN_HPD_PLUG          (1 << 3)
+#define HDMI_INTC_EN_HPD_UNPLUG                (1 << 2)
+
+/* HDMI_INTC_FLAG */
+#define HDMI_INTC_FLAG_HPD_PLUG                (1 << 3)
+#define HDMI_INTC_FLAG_HPD_UNPLUG      (1 << 2)
+
+/* HDMI_PHY_RSTOUT */
+#define HDMI_PHY_SW_RSTOUT             (1 << 0)
+
+/* HDMI_CORE_RSTOUT */
+#define HDMI_CORE_SW_RSTOUT            (1 << 0)
+
+/* HDMI_CON_0 */
+#define HDMI_BLUE_SCR_EN               (1 << 5)
+#define HDMI_EN                                (1 << 0)
+
+/* HDMI_PHY_STATUS */
+#define HDMI_PHY_STATUS_READY          (1 << 0)
+
+/* HDMI_MODE_SEL */
+#define HDMI_MODE_HDMI_EN              (1 << 1)
+#define HDMI_MODE_DVI_EN               (1 << 0)
+#define HDMI_MODE_MASK                 (3 << 0)
+
+/* HDMI_TG_CMD */
+#define HDMI_FIELD_EN                  (1 << 1)
+#define HDMI_TG_EN                     (1 << 0)
+
+#endif /* SAMSUNG_REGS_HDMI_H */
diff --git a/drivers/media/video/exynos/tv/regs-hdmi-5250.h b/drivers/media/video/exynos/tv/regs-hdmi-5250.h
new file mode 100644 (file)
index 0000000..be9ac4f
--- /dev/null
@@ -0,0 +1,1275 @@
+/* linux/arch/arm/mach-exynos4/include/mach/regs-hdmi_14.h
+ *
+ * Copyright (c) 2010 Samsung Electronics
+ *             http://www.samsung.com/
+ *
+ * HDMI register header file for Samsung TVOUT driver
+ *
+ * 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.
+*/
+
+#ifndef __ARCH_ARM_REGS_HDMI_H
+#define __ARCH_ARM_REGS_HDMI_H
+
+/*
+ * Register part
+*/
+
+#define S5P_HDMI_I2C_PHY_BASE(x)       (x)
+
+#define HDMI_I2C_CON                   S5P_HDMI_I2C_PHY_BASE(0x0000)
+#define HDMI_I2C_STAT                  S5P_HDMI_I2C_PHY_BASE(0x0004)
+#define HDMI_I2C_ADD                   S5P_HDMI_I2C_PHY_BASE(0x0008)
+#define HDMI_I2C_DS                    S5P_HDMI_I2C_PHY_BASE(0x000c)
+#define HDMI_I2C_LC                    S5P_HDMI_I2C_PHY_BASE(0x0010)
+
+#define HDMI_CTRL_BASE(x)              ((x) + 0x00000000)
+#define HDMI_CORE_BASE(x)              ((x) + 0x00010000)
+#define HDMI_SPDIF_BASE(x)             ((x) + 0x00030000)
+#define HDMI_I2S_BASE(x)               ((x) + 0x00040000)
+#define HDMI_TG_BASE(x)                        ((x) + 0x00050000)
+#define HDMI_EFUSE_BASE(x)             ((x) + 0x00060000)
+
+/* Control registers */
+#define HDMI_INTC_CON_0                        HDMI_CTRL_BASE(0x0000)
+#define HDMI_INTC_FLAG_0               HDMI_CTRL_BASE(0x0004)
+#define HDMI_HDCP_KEY_LOAD             HDMI_CTRL_BASE(0x0008)
+#define HDMI_HPD_STATUS                        HDMI_CTRL_BASE(0x000C)
+
+#define HDMI_INTC_CON_1                        HDMI_CTRL_BASE(0x0010)
+#define HDMI_INTC_FLAG_1               HDMI_CTRL_BASE(0x0014)
+#define HDMI_PHY_STATUS_0              HDMI_CTRL_BASE(0x0020)
+#define HDMI_PHY_STATUS_PLL            HDMI_CTRL_BASE(0x0028)
+#define HDMI_PHY_CON_0                 HDMI_CTRL_BASE(0x0030)
+
+#define HDMI_HPD_CTRL                  HDMI_CTRL_BASE(0x0040)
+#define HDMI_HPD_TH_(n)                        HDMI_CTRL_BASE(0x0050 + 4 * (n))
+
+#define HDMI_AUDIO_CLKSEL              HDMI_CTRL_BASE(0x0070)
+#define HDMI_PHY_RSTOUT                        HDMI_CTRL_BASE(0x0074)
+#define HDMI_PHY_VPLL                  HDMI_CTRL_BASE(0x0078)
+#define HDMI_PHY_CMU                   HDMI_CTRL_BASE(0x007C)
+#define HDMI_CORE_RSTOUT               HDMI_CTRL_BASE(0x080)
+
+/* HDMI core registers */
+#define HDMI_CON_0                     HDMI_CORE_BASE(0x000)
+#define HDMI_CON_1                     HDMI_CORE_BASE(0x004)
+#define HDMI_CON_2                     HDMI_CORE_BASE(0x008)
+#define HDMI_SIM_MODE                  HDMI_CORE_BASE(0x00C)
+#define HDMI_STATUS                    HDMI_CORE_BASE(0x010)
+#define HDMI_PHY_STATUS                        HDMI_CORE_BASE(0x014)
+#define HDMI_STATUS_EN                 HDMI_CORE_BASE(0x020)
+#define HDMI_HPD                       HDMI_CORE_BASE(0x030)
+#define HDMI_MODE_SEL                  HDMI_CORE_BASE(0x040)
+#define HDMI_ENC_EN                    HDMI_CORE_BASE(0x044)
+
+/* Video related registers */
+#define HDMI_YMAX                      HDMI_CORE_BASE(0x060)
+#define HDMI_YMIN                      HDMI_CORE_BASE(0x064)
+#define HDMI_CMAX                      HDMI_CORE_BASE(0x068)
+#define HDMI_CMIN                      HDMI_CORE_BASE(0x06c)
+
+#define HDMI_DI_PREFIX                 HDMI_CORE_BASE(0x078)
+#define HDMI_VBI_ST_MG                 HDMI_CORE_BASE(0x080)
+#define HDMI_END_MG                    HDMI_CORE_BASE(0x084)
+
+#define HDMI_AUTH_ST_MG0               HDMI_CORE_BASE(0x090)
+#define HDMI_AUTH_ST_MG1               HDMI_CORE_BASE(0x094)
+#define HDMI_AUTH_END_MG0              HDMI_CORE_BASE(0x098)
+#define HDMI_AUTH_END_MG1              HDMI_CORE_BASE(0x09C)
+
+#define HDMI_H_BLANK_0                 HDMI_CORE_BASE(0x0a0)
+#define HDMI_H_BLANK_1                 HDMI_CORE_BASE(0x0a4)
+
+#define HDMI_V2_BLANK_0                        HDMI_CORE_BASE(0x0b0)
+#define HDMI_V2_BLANK_1                        HDMI_CORE_BASE(0x0b4)
+#define HDMI_V1_BLANK_0                        HDMI_CORE_BASE(0x0b8)
+#define HDMI_V1_BLANK_1                        HDMI_CORE_BASE(0x0bC)
+
+#define HDMI_V_LINE_0                  HDMI_CORE_BASE(0x0c0)
+#define HDMI_V_LINE_1                  HDMI_CORE_BASE(0x0c4)
+#define HDMI_H_LINE_0                  HDMI_CORE_BASE(0x0c8)
+#define HDMI_H_LINE_1                  HDMI_CORE_BASE(0x0cC)
+#define HDMI_HSYNC_POL                 HDMI_CORE_BASE(0x0E0)
+
+#define HDMI_VSYNC_POL                 HDMI_CORE_BASE(0x0e4)
+#define HDMI_INT_PRO_MODE              HDMI_CORE_BASE(0x0e8)
+
+#define HDMI_V_BLANK_F0_0              HDMI_CORE_BASE(0x110)
+#define HDMI_V_BLANK_F0_1              HDMI_CORE_BASE(0x114)
+#define HDMI_V_BLANK_F1_0              HDMI_CORE_BASE(0x118)
+#define HDMI_V_BLANK_F1_1              HDMI_CORE_BASE(0x11C)
+
+#define HDMI_H_SYNC_START_0            HDMI_CORE_BASE(0x120)
+#define HDMI_H_SYNC_START_1            HDMI_CORE_BASE(0x124)
+#define HDMI_H_SYNC_END_0              HDMI_CORE_BASE(0x128)
+#define HDMI_H_SYNC_END_1              HDMI_CORE_BASE(0x12C)
+
+#define HDMI_V_SYNC_LINE_BEF_2_0       HDMI_CORE_BASE(0x130)
+#define HDMI_V_SYNC_LINE_BEF_2_1       HDMI_CORE_BASE(0x134)
+#define HDMI_V_SYNC_LINE_BEF_1_0       HDMI_CORE_BASE(0x138)
+#define HDMI_V_SYNC_LINE_BEF_1_1       HDMI_CORE_BASE(0x13C)
+
+#define HDMI_V_SYNC_LINE_AFT_2_0       HDMI_CORE_BASE(0x140)
+#define HDMI_V_SYNC_LINE_AFT_2_1       HDMI_CORE_BASE(0x144)
+#define HDMI_V_SYNC_LINE_AFT_1_0       HDMI_CORE_BASE(0x148)
+#define HDMI_V_SYNC_LINE_AFT_1_1       HDMI_CORE_BASE(0x14C)
+
+#define HDMI_V_SYNC_LINE_AFT_PXL_2_0   HDMI_CORE_BASE(0x150)
+#define HDMI_V_SYNC_LINE_AFT_PXL_2_1   HDMI_CORE_BASE(0x154)
+#define HDMI_V_SYNC_LINE_AFT_PXL_1_0   HDMI_CORE_BASE(0x158)
+#define HDMI_V_SYNC_LINE_AFT_PXL_1_1   HDMI_CORE_BASE(0x15C)
+
+#define HDMI_V_BLANK_F2_0              HDMI_CORE_BASE(0x160)
+#define HDMI_V_BLANK_F2_1              HDMI_CORE_BASE(0x164)
+#define HDMI_V_BLANK_F3_0              HDMI_CORE_BASE(0x168)
+#define HDMI_V_BLANK_F3_1              HDMI_CORE_BASE(0x16C)
+#define HDMI_V_BLANK_F4_0              HDMI_CORE_BASE(0x170)
+#define HDMI_V_BLANK_F4_1              HDMI_CORE_BASE(0x174)
+#define HDMI_V_BLANK_F5_0              HDMI_CORE_BASE(0x178)
+#define HDMI_V_BLANK_F5_1              HDMI_CORE_BASE(0x17C)
+
+#define HDMI_V_SYNC_LINE_AFT_3_0       HDMI_CORE_BASE(0x180)
+#define HDMI_V_SYNC_LINE_AFT_3_1       HDMI_CORE_BASE(0x184)
+#define HDMI_V_SYNC_LINE_AFT_4_0       HDMI_CORE_BASE(0x188)
+#define HDMI_V_SYNC_LINE_AFT_4_1       HDMI_CORE_BASE(0x18C)
+#define HDMI_V_SYNC_LINE_AFT_5_0       HDMI_CORE_BASE(0x190)
+#define HDMI_V_SYNC_LINE_AFT_5_1       HDMI_CORE_BASE(0x194)
+#define HDMI_V_SYNC_LINE_AFT_6_0       HDMI_CORE_BASE(0x198)
+#define HDMI_V_SYNC_LINE_AFT_6_1       HDMI_CORE_BASE(0x19C)
+
+#define HDMI_V_SYNC_LINE_AFT_PXL_3_0   HDMI_CORE_BASE(0x1A0)
+#define HDMI_V_SYNC_LINE_AFT_PXL_3_1   HDMI_CORE_BASE(0x1A4)
+#define HDMI_V_SYNC_LINE_AFT_PXL_4_0   HDMI_CORE_BASE(0x1A8)
+#define HDMI_V_SYNC_LINE_AFT_PXL_4_1   HDMI_CORE_BASE(0x1AC)
+#define HDMI_V_SYNC_LINE_AFT_PXL_5_0   HDMI_CORE_BASE(0x1B0)
+#define HDMI_V_SYNC_LINE_AFT_PXL_5_1   HDMI_CORE_BASE(0x1B4)
+#define HDMI_V_SYNC_LINE_AFT_PXL_6_0   HDMI_CORE_BASE(0x1B8)
+#define HDMI_V_SYNC_LINE_AFT_PXL_6_1   HDMI_CORE_BASE(0x1BC)
+
+#define HDMI_VACT_SPACE_1_0            HDMI_CORE_BASE(0x1C0)
+#define HDMI_VACT_SPACE_1_1            HDMI_CORE_BASE(0x1C4)
+#define HDMI_VACT_SPACE_2_0            HDMI_CORE_BASE(0x1C8)
+#define HDMI_VACT_SPACE_2_1            HDMI_CORE_BASE(0x1CC)
+#define HDMI_VACT_SPACE_3_0            HDMI_CORE_BASE(0x1D0)
+#define HDMI_VACT_SPACE_3_1            HDMI_CORE_BASE(0x1D4)
+#define HDMI_VACT_SPACE_4_0            HDMI_CORE_BASE(0x1D8)
+#define HDMI_VACT_SPACE_4_1            HDMI_CORE_BASE(0x1DC)
+#define HDMI_VACT_SPACE_5_0            HDMI_CORE_BASE(0x1E0)
+#define HDMI_VACT_SPACE_5_1            HDMI_CORE_BASE(0x1E4)
+#define HDMI_VACT_SPACE_6_0            HDMI_CORE_BASE(0x1E8)
+#define HDMI_VACT_SPACE_6_1            HDMI_CORE_BASE(0x1EC)
+#define HDMI_CSC_MUX                   HDMI_CORE_BASE(0x1F0)
+#define HDMI_SYNC_GEN_MUX              HDMI_CORE_BASE(0x1F4)
+
+#define HDMI_GCP_CON                   HDMI_CORE_BASE(0x200)
+#define HDMI_GCP_CON_EX                        HDMI_CORE_BASE(0x204)
+#define HDMI_GCP_BYTE1                 HDMI_CORE_BASE(0x210)
+#define HDMI_GCP_BYTE2                 HDMI_CORE_BASE(0x214)
+#define HDMI_GCP_BYTE3                 HDMI_CORE_BASE(0x218)
+
+/* Audio related registers */
+#define HDMI_ASP_CON                   HDMI_CORE_BASE(0x300)
+#define HDMI_ASP_SP_FLAT               HDMI_CORE_BASE(0x304)
+#define HDMI_ASP_CHCFG0                        HDMI_CORE_BASE(0x310)
+#define HDMI_ASP_CHCFG1                        HDMI_CORE_BASE(0x314)
+#define HDMI_ASP_CHCFG2                        HDMI_CORE_BASE(0x318)
+#define HDMI_ASP_CHCFG3                        HDMI_CORE_BASE(0x31c)
+
+#define HDMI_ACR_CON                   HDMI_CORE_BASE(0x400)
+#define HDMI_ACR_MCTS0                 HDMI_CORE_BASE(0x410)
+#define HDMI_ACR_MCTS1                 HDMI_CORE_BASE(0x414)
+#define HDMI_ACR_MCTS2                 HDMI_CORE_BASE(0x418)
+#define HDMI_ACR_CTS0                  HDMI_CORE_BASE(0x420)
+#define HDMI_ACR_CTS1                  HDMI_CORE_BASE(0x424)
+#define HDMI_ACR_CTS2                  HDMI_CORE_BASE(0x428)
+#define HDMI_ACR_N0                    HDMI_CORE_BASE(0x430)
+#define HDMI_ACR_N1                    HDMI_CORE_BASE(0x434)
+#define HDMI_ACR_N2                    HDMI_CORE_BASE(0x438)
+#define HDMI_ACR_LSB2                  HDMI_CORE_BASE(0x440)
+#define HDMI_ACR_TXCNT                 HDMI_CORE_BASE(0x444)
+#define HDMI_ACR_TXINTERNAL            HDMI_CORE_BASE(0x448)
+#define HDMI_ACR_CTS_OFFSET            HDMI_CORE_BASE(0x44c)
+
+#define HDMI_ACP_CON                   HDMI_CORE_BASE(0x500)
+#define HDMI_ACP_TYPE                  HDMI_CORE_BASE(0x514)
+/* offset of HDMI_ACP_DATA00 ~ 16 : 0x0520 ~ 0x0560 */
+#define HDMI_ACP_DATA(n)               HDMI_CORE_BASE(0x520 + 4 * (n))
+
+#define HDMI_ISRC_CON                  HDMI_CORE_BASE(0x600)
+#define HDMI_ISRC1_HEADER1             HDMI_CORE_BASE(0x614)
+/* offset of HDMI_ISRC1_DATA00 ~ 15 : 0x0620 ~ 0x065C */
+#define HDMI_ISRC1_DATA(n)             HDMI_CORE_BASE(0x620 + 4 * (n))
+/* offset of HDMI_ISRC2_DATA00 ~ 15 : 0x06A0 ~ 0x06DC */
+#define HDMI_ISRC2_DATA(n)             HDMI_CORE_BASE(0x6A0 + 4 * (n))
+
+#define HDMI_AVI_CON                   HDMI_CORE_BASE(0x700)
+#define HDMI_AVI_HEADER0               HDMI_CORE_BASE(0x710)
+#define HDMI_AVI_HEADER1               HDMI_CORE_BASE(0x714)
+#define HDMI_AVI_HEADER2               HDMI_CORE_BASE(0x718)
+#define HDMI_AVI_CHECK_SUM             HDMI_CORE_BASE(0x71C)
+/* offset of HDMI_AVI_BYTE1 ~ 13 : 0x0720 ~ 0x0750 */
+#define HDMI_AVI_BYTE(n)               HDMI_CORE_BASE(0x720 + 4 * (n - 1))
+
+#define HDMI_AUI_CON                   HDMI_CORE_BASE(0x800)
+#define HDMI_AUI_HEADER0               HDMI_CORE_BASE(0x810)
+#define HDMI_AUI_HEADER1               HDMI_CORE_BASE(0x814)
+#define HDMI_AUI_HEADER2               HDMI_CORE_BASE(0x818)
+#define HDMI_AUI_CHECK_SUM             HDMI_CORE_BASE(0x81C)
+/* offset of HDMI_AUI_BYTE1 ~ 12 : 0x0820 ~ 0x084C */
+#define HDMI_AUI_BYTE(n)               HDMI_CORE_BASE(0x820 + 4 * (n - 1))
+
+#define HDMI_MPG_CON                   HDMI_CORE_BASE(0x900)
+#define HDMI_MPG_CHECK_SUM             HDMI_CORE_BASE(0x91C)
+/* offset of HDMI_MPG_BYTE1 ~ 6 : 0x0920 ~ 0x0934 */
+#define HDMI_MPG_BYTE(n)               HDMI_CORE_BASE(0x920 + 4 * (n - 1))
+
+#define HDMI_SPD_CON                   HDMI_CORE_BASE(0xA00)
+#define HDMI_SPD_HEADER0               HDMI_CORE_BASE(0xA10)
+#define HDMI_SPD_HEADER1               HDMI_CORE_BASE(0xA14)
+#define HDMI_SPD_HEADER2               HDMI_CORE_BASE(0xA18)
+/* offset of HDMI_SPD_DATA00 ~ 27 : 0x0A20 ~ 0x0A8C */
+#define HDMI_SPD_DATA0(n)              HDMI_CORE_BASE(0xA20 + 4 * (n))
+
+#define HDMI_GAMUT_CON                 HDMI_CORE_BASE(0xB00)
+#define HDMI_GAMUT_HEADER0             HDMI_CORE_BASE(0xB10)
+#define HDMI_GAMUT_HEADER1             HDMI_CORE_BASE(0xB14)
+#define HDMI_GAMUT_HEADER2             HDMI_CORE_BASE(0xB18)
+/* offset of HDMI_GAMUT_METADATA00 ~ 27 : 0x0B20 ~ 0x0B8C */
+#define HDMI_GAMUT_METADATA(n)         HDMI_CORE_BASE(0xB20 + 4 * (n))
+
+#define HDMI_VSI_CON                   HDMI_CORE_BASE(0xC00)
+#define HDMI_VSI_HEADER0               HDMI_CORE_BASE(0xC10)
+#define HDMI_VSI_HEADER1               HDMI_CORE_BASE(0xC14)
+#define HDMI_VSI_HEADER2               HDMI_CORE_BASE(0xC18)
+/* offset of HDMI_VSI_DATA00 ~ 27 : 0x0C20 ~ 0x0C8C */
+#define HDMI_VSI_DATA(n)               HDMI_CORE_BASE(0xC20 + 4 * (n))
+
+#define HDMI_DC_CONTROL                        HDMI_CORE_BASE(0xD00)
+#define HDMI_VIDEO_PATTERN_GEN         HDMI_CORE_BASE(0xD04)
+#define HDMI_HPD_GEN0                  HDMI_CORE_BASE(0xD08)
+#define HDMI_HPD_GEN1                  HDMI_CORE_BASE(0xD0C)
+#define HDMI_HPD_GEN2                  HDMI_CORE_BASE(0xD10)
+#define HDMI_HPD_GEN3                  HDMI_CORE_BASE(0xD14)
+
+#define HDMI_DIM_CON                   HDMI_CORE_BASE(0xD30)
+
+/* HDCP related registers */
+/* offset of HDMI_HDCP_SHA1_00 ~ 19 : 0x7000 ~ 0x704C */
+#define HDMI_HDCP_SHA1_(n)             HDMI_CORE_BASE(0x7000 + 4 * (n))
+
+/* offset of HDMI_HDCP_KSV_LIST_0 ~ 4 : 0x7050 ~ 0x7060 */
+#define HDMI_HDCP_KSV_LIST_(n)         HDMI_CORE_BASE(0x7050 + 4 * (n))
+
+#define HDMI_HDCP_KSV_LIST_CON         HDMI_CORE_BASE(0x7064)
+#define HDMI_HDCP_SHA_RESULT           HDMI_CORE_BASE(0x7070)
+#define HDMI_HDCP_CTRL1                        HDMI_CORE_BASE(0x7080)
+#define HDMI_HDCP_CTRL2                        HDMI_CORE_BASE(0x7084)
+#define HDMI_HDCP_CHECK_RESULT         HDMI_CORE_BASE(0x7090)
+
+/* offset of HDMI_HDCP_BKSV_0 ~ 4 : 0x70A0 ~ 0x70B0 */
+#define HDMI_HDCP_BKSV_(n)             HDMI_CORE_BASE(0x70A0 + 4 * (n))
+/* offset of HDMI_HDCP_AKSV_0 ~ 4 : 0x70C0 ~ 0x70D0 */
+#define HDMI_HDCP_AKSV_(n)             HDMI_CORE_BASE(0x70C0 + 4 * (n))
+
+/* offset of HDMI_HDCP_AN_0 ~ 7 : 0x70E0 ~ 0x70FC */
+#define HDMI_HDCP_AN_(n)               HDMI_CORE_BASE(0x70E0 + 4 * (n))
+
+#define HDMI_HDCP_BCAPS                        HDMI_CORE_BASE(0x7100)
+#define HDMI_HDCP_BSTATUS_0            HDMI_CORE_BASE(0x7110)
+#define HDMI_HDCP_BSTATUS_1            HDMI_CORE_BASE(0x7114)
+#define HDMI_HDCP_RI_0                 HDMI_CORE_BASE(0x7140)
+#define HDMI_HDCP_RI_1                 HDMI_CORE_BASE(0x7144)
+#define HDMI_HDCP_I2C_INT              HDMI_CORE_BASE(0x7180)
+#define HDMI_HDCP_AN_INT               HDMI_CORE_BASE(0x7190)
+#define HDMI_HDCP_WDT_INT              HDMI_CORE_BASE(0x71a0)
+#define HDMI_HDCP_RI_INT               HDMI_CORE_BASE(0x71b0)
+
+#define HDMI_HDCP_RI_COMPARE_0         HDMI_CORE_BASE(0x71d0)
+#define HDMI_HDCP_RI_COMPARE_1         HDMI_CORE_BASE(0x71d4)
+#define HDMI_HDCP_FRAME_COUNT          HDMI_CORE_BASE(0x71e0)
+
+#define HDMI_RGB_ROUND_EN              HDMI_CORE_BASE(0xD500)
+
+#define HDMI_VACT_SPACE_R_0            HDMI_CORE_BASE(0xD504)
+#define HDMI_VACT_SPACE_R_1            HDMI_CORE_BASE(0xD508)
+
+#define HDMI_VACT_SPACE_G_0            HDMI_CORE_BASE(0xD50C)
+#define HDMI_VACT_SPACE_G_1            HDMI_CORE_BASE(0xD510)
+
+#define HDMI_VACT_SPACE_B_0            HDMI_CORE_BASE(0xD514)
+#define HDMI_VACT_SPACE_B_1            HDMI_CORE_BASE(0xD518)
+
+#define HDMI_BLUE_SCREEN_B_0           HDMI_CORE_BASE(0xD520)
+#define HDMI_BLUE_SCREEN_B_1           HDMI_CORE_BASE(0xD524)
+#define HDMI_BLUE_SCREEN_G_0           HDMI_CORE_BASE(0xD528)
+#define HDMI_BLUE_SCREEN_G_1           HDMI_CORE_BASE(0xD52C)
+#define HDMI_BLUE_SCREEN_R_0           HDMI_CORE_BASE(0xD530)
+#define HDMI_BLUE_SCREEN_R_1           HDMI_CORE_BASE(0xD534)
+
+/* SPDIF registers */
+#define HDMI_SPDIFIN_CLK_CTRL          HDMI_SPDIF_BASE(0x000)
+#define HDMI_SPDIFIN_OP_CTRL           HDMI_SPDIF_BASE(0x004)
+#define HDMI_SPDIFIN_IRQ_MASK          HDMI_SPDIF_BASE(0x008)
+#define HDMI_SPDIFIN_IRQ_STATUS                HDMI_SPDIF_BASE(0x00c)
+#define HDMI_SPDIFIN_CONFIG_1          HDMI_SPDIF_BASE(0x010)
+#define HDMI_SPDIFIN_CONFIG_2          HDMI_SPDIF_BASE(0x014)
+#define HDMI_SPDIFIN_USER_VALUE_1      HDMI_SPDIF_BASE(0x020)
+#define HDMI_SPDIFIN_USER_VALUE_2      HDMI_SPDIF_BASE(0x024)
+#define HDMI_SPDIFIN_USER_VALUE_3      HDMI_SPDIF_BASE(0x028)
+#define HDMI_SPDIFIN_USER_VALUE_4      HDMI_SPDIF_BASE(0x02c)
+#define HDMI_SPDIFIN_CH_STATUS_0_1     HDMI_SPDIF_BASE(0x030)
+#define HDMI_SPDIFIN_CH_STATUS_0_2     HDMI_SPDIF_BASE(0x034)
+#define HDMI_SPDIFIN_CH_STATUS_0_3     HDMI_SPDIF_BASE(0x038)
+#define HDMI_SPDIFIN_CH_STATUS_0_4     HDMI_SPDIF_BASE(0x03c)
+#define HDMI_SPDIFIN_CH_STATUS_1       HDMI_SPDIF_BASE(0x040)
+#define HDMI_SPDIFIN_FRAME_PERIOD_1    HDMI_SPDIF_BASE(0x048)
+#define HDMI_SPDIFIN_FRAME_PERIOD_2    HDMI_SPDIF_BASE(0x04c)
+#define HDMI_SPDIFIN_PC_INFO_1         HDMI_SPDIF_BASE(0x050)
+#define HDMI_SPDIFIN_PC_INFO_2         HDMI_SPDIF_BASE(0x054)
+#define HDMI_SPDIFIN_PD_INFO_1         HDMI_SPDIF_BASE(0x058)
+#define HDMI_SPDIFIN_PD_INFO_2         HDMI_SPDIF_BASE(0x05c)
+#define HDMI_SPDIFIN_DATA_BUF_0_1      HDMI_SPDIF_BASE(0x060)
+#define HDMI_SPDIFIN_DATA_BUF_0_2      HDMI_SPDIF_BASE(0x064)
+#define HDMI_SPDIFIN_DATA_BUF_0_3      HDMI_SPDIF_BASE(0x068)
+#define HDMI_SPDIFIN_USER_BUF_0                HDMI_SPDIF_BASE(0x06c)
+#define HDMI_SPDIFIN_DATA_BUF_1_1      HDMI_SPDIF_BASE(0x070)
+#define HDMI_SPDIFIN_DATA_BUF_1_2      HDMI_SPDIF_BASE(0x074)
+#define HDMI_SPDIFIN_DATA_BUF_1_3      HDMI_SPDIF_BASE(0x078)
+#define HDMI_SPDIFIN_USER_BUF_1                HDMI_SPDIF_BASE(0x07c)
+
+/* I2S registers */
+#define HDMI_I2S_CLK_CON               HDMI_I2S_BASE(0x000)
+#define HDMI_I2S_CON_1                 HDMI_I2S_BASE(0x004)
+#define HDMI_I2S_CON_2                 HDMI_I2S_BASE(0x008)
+#define HDMI_I2S_PIN_SEL_0             HDMI_I2S_BASE(0x00c)
+#define HDMI_I2S_PIN_SEL_1             HDMI_I2S_BASE(0x010)
+#define HDMI_I2S_PIN_SEL_2             HDMI_I2S_BASE(0x014)
+#define HDMI_I2S_PIN_SEL_3             HDMI_I2S_BASE(0x018)
+#define HDMI_I2S_DSD_CON               HDMI_I2S_BASE(0x01c)
+#define HDMI_I2S_IN_MUX_CON            HDMI_I2S_BASE(0x020)
+#define HDMI_I2S_CH_ST_CON             HDMI_I2S_BASE(0x024)
+#define HDMI_I2S_CH_ST_0               HDMI_I2S_BASE(0x028)
+#define HDMI_I2S_CH_ST_1               HDMI_I2S_BASE(0x02c)
+#define HDMI_I2S_CH_ST_2               HDMI_I2S_BASE(0x030)
+#define HDMI_I2S_CH_ST_3               HDMI_I2S_BASE(0x034)
+#define HDMI_I2S_CH_ST_4               HDMI_I2S_BASE(0x038)
+#define HDMI_I2S_CH_ST_SH_0            HDMI_I2S_BASE(0x03c)
+#define HDMI_I2S_CH_ST_SH_1            HDMI_I2S_BASE(0x040)
+#define HDMI_I2S_CH_ST_SH_2            HDMI_I2S_BASE(0x044)
+#define HDMI_I2S_CH_ST_SH_3            HDMI_I2S_BASE(0x048)
+#define HDMI_I2S_CH_ST_SH_4            HDMI_I2S_BASE(0x04c)
+#define HDMI_I2S_VD_DATA               HDMI_I2S_BASE(0x050)
+#define HDMI_I2S_MUX_CH                        HDMI_I2S_BASE(0x054)
+#define HDMI_I2S_MUX_CUV               HDMI_I2S_BASE(0x058)
+#define HDMI_I2S_IRQ_MASK              HDMI_I2S_BASE(0x05c)
+#define HDMI_I2S_IRQ_STATUS            HDMI_I2S_BASE(0x060)
+
+#define HDMI_I2S_CH0_L_0               HDMI_I2S_BASE(0x0064)
+#define HDMI_I2S_CH0_L_1               HDMI_I2S_BASE(0x0068)
+#define HDMI_I2S_CH0_L_2               HDMI_I2S_BASE(0x006C)
+#define HDMI_I2S_CH0_L_3               HDMI_I2S_BASE(0x0070)
+#define HDMI_I2S_CH0_R_0               HDMI_I2S_BASE(0x0074)
+#define HDMI_I2S_CH0_R_1               HDMI_I2S_BASE(0x0078)
+#define HDMI_I2S_CH0_R_2               HDMI_I2S_BASE(0x007C)
+#define HDMI_I2S_CH0_R_3               HDMI_I2S_BASE(0x0080)
+#define HDMI_I2S_CH1_L_0               HDMI_I2S_BASE(0x0084)
+#define HDMI_I2S_CH1_L_1               HDMI_I2S_BASE(0x0088)
+#define HDMI_I2S_CH1_L_2               HDMI_I2S_BASE(0x008C)
+#define HDMI_I2S_CH1_L_3               HDMI_I2S_BASE(0x0090)
+#define HDMI_I2S_CH1_R_0               HDMI_I2S_BASE(0x0094)
+#define HDMI_I2S_CH1_R_1               HDMI_I2S_BASE(0x0098)
+#define HDMI_I2S_CH1_R_2               HDMI_I2S_BASE(0x009C)
+#define HDMI_I2S_CH1_R_3               HDMI_I2S_BASE(0x00A0)
+#define HDMI_I2S_CH2_L_0               HDMI_I2S_BASE(0x00A4)
+#define HDMI_I2S_CH2_L_1               HDMI_I2S_BASE(0x00A8)
+#define HDMI_I2S_CH2_L_2               HDMI_I2S_BASE(0x00AC)
+#define HDMI_I2S_CH2_L_3               HDMI_I2S_BASE(0x00B0)
+#define HDMI_I2S_CH2_R_0               HDMI_I2S_BASE(0x00B4)
+#define HDMI_I2S_CH2_R_1               HDMI_I2S_BASE(0x00B8)
+#define HDMI_I2S_CH2_R_2               HDMI_I2S_BASE(0x00BC)
+#define HDMI_I2S_Ch2_R_3               HDMI_I2S_BASE(0x00C0)
+#define HDMI_I2S_CH3_L_0               HDMI_I2S_BASE(0x00C4)
+#define HDMI_I2S_CH3_L_1               HDMI_I2S_BASE(0x00C8)
+#define HDMI_I2S_CH3_L_2               HDMI_I2S_BASE(0x00CC)
+#define HDMI_I2S_CH3_R_0               HDMI_I2S_BASE(0x00D0)
+#define HDMI_I2S_CH3_R_1               HDMI_I2S_BASE(0x00D4)
+#define HDMI_I2S_CH3_R_2               HDMI_I2S_BASE(0x00D8)
+#define HDMI_I2S_CUV_L_R               HDMI_I2S_BASE(0x00DC)
+
+/* Timing Generator registers */
+#define HDMI_TG_CMD                    HDMI_TG_BASE(0x000)
+#define HDMI_TG_CFG                    HDMI_TG_BASE(0x004)
+#define HDMI_TG_CB_SZ                  HDMI_TG_BASE(0x008)
+#define HDMI_TG_INDELAY_L              HDMI_TG_BASE(0x00c)
+#define HDMI_TG_INDELAY_H              HDMI_TG_BASE(0x010)
+#define HDMI_TG_POL_CTRL               HDMI_TG_BASE(0x014)
+#define HDMI_TG_H_FSZ_L                        HDMI_TG_BASE(0x018)
+#define HDMI_TG_H_FSZ_H                        HDMI_TG_BASE(0x01c)
+#define HDMI_TG_HACT_ST_L              HDMI_TG_BASE(0x020)
+#define HDMI_TG_HACT_ST_H              HDMI_TG_BASE(0x024)
+#define HDMI_TG_HACT_SZ_L              HDMI_TG_BASE(0x028)
+#define HDMI_TG_HACT_SZ_H              HDMI_TG_BASE(0x02c)
+#define HDMI_TG_V_FSZ_L                        HDMI_TG_BASE(0x030)
+#define HDMI_TG_V_FSZ_H                        HDMI_TG_BASE(0x034)
+#define HDMI_TG_VSYNC_L                        HDMI_TG_BASE(0x038)
+#define HDMI_TG_VSYNC_H                        HDMI_TG_BASE(0x03c)
+#define HDMI_TG_VSYNC2_L               HDMI_TG_BASE(0x040)
+#define HDMI_TG_VSYNC2_H               HDMI_TG_BASE(0x044)
+#define HDMI_TG_VACT_ST_L              HDMI_TG_BASE(0x048)
+#define HDMI_TG_VACT_ST_H              HDMI_TG_BASE(0x04c)
+#define HDMI_TG_VACT_SZ_L              HDMI_TG_BASE(0x050)
+#define HDMI_TG_VACT_SZ_H              HDMI_TG_BASE(0x054)
+#define HDMI_TG_FIELD_CHG_L            HDMI_TG_BASE(0x058)
+#define HDMI_TG_FIELD_CHG_H            HDMI_TG_BASE(0x05c)
+#define HDMI_TG_VACT_ST2_L             HDMI_TG_BASE(0x060)
+#define HDMI_TG_VACT_ST2_H             HDMI_TG_BASE(0x064)
+#define HDMI_TG_VACT_ST3_L             HDMI_TG_BASE(0x068)
+#define HDMI_TG_VACT_ST3_H             HDMI_TG_BASE(0x06c)
+#define HDMI_TG_VACT_ST4_L             HDMI_TG_BASE(0x070)
+#define HDMI_TG_VACT_ST4_H             HDMI_TG_BASE(0x074)
+
+#define HDMI_TG_VSYNC_TOP_HDMI_L       HDMI_TG_BASE(0x078)
+#define HDMI_TG_VSYNC_TOP_HDMI_H       HDMI_TG_BASE(0x07c)
+#define HDMI_TG_VSYNC_BOT_HDMI_L       HDMI_TG_BASE(0x080)
+#define HDMI_TG_VSYNC_BOT_HDMI_H       HDMI_TG_BASE(0x084)
+#define HDMI_TG_FIELD_TOP_HDMI_L       HDMI_TG_BASE(0x088)
+#define HDMI_TG_FIELD_TOP_HDMI_H       HDMI_TG_BASE(0x08c)
+#define HDMI_TG_FIELD_BOT_HDMI_L       HDMI_TG_BASE(0x090)
+#define HDMI_TG_FIELD_BOT_HDMI_H       HDMI_TG_BASE(0x094)
+
+#define HDMI_TG_3D                     HDMI_TG_BASE(0x0F0)
+
+#define HDMI_MHL_HSYNC_WIDTH           HDMI_TG_BASE(0x17C)
+#define HDMI_MHL_VSYNC_WIDTH           HDMI_TG_BASE(0x180)
+#define HDMI_MHL_CLK_INV               HDMI_TG_BASE(0x184)
+
+/* HDMI eFUSE registers */
+#define HDMI_EFUSE_CTRL                        HDMI_EFUSE_BASE(0x000)
+#define HDMI_EFUSE_STATUS              HDMI_EFUSE_BASE(0x004)
+#define HDMI_EFUSE_ADDR_WIDTH          HDMI_EFUSE_BASE(0x008)
+#define HDMI_EFUSE_SIGDEV_ASSERT       HDMI_EFUSE_BASE(0x00c)
+#define HDMI_EFUSE_SIGDEV_DE_ASSERT    HDMI_EFUSE_BASE(0x010)
+#define HDMI_EFUSE_PRCHG_ASSERT                HDMI_EFUSE_BASE(0x014)
+#define HDMI_EFUSE_PRCHG_DE_ASSERT     HDMI_EFUSE_BASE(0x018)
+#define HDMI_EFUSE_FSET_ASSERT         HDMI_EFUSE_BASE(0x01c)
+#define HDMI_EFUSE_FSET_DE_ASSERT      HDMI_EFUSE_BASE(0x020)
+#define HDMI_EFUSE_SENSING             HDMI_EFUSE_BASE(0x024)
+#define HDMI_EFUSE_SCK_ASSERT          HDMI_EFUSE_BASE(0x028)
+#define HDMI_EFUSE_SCK_DE_ASSERT       HDMI_EFUSE_BASE(0x02c)
+#define HDMI_EFUSE_SDOUT_OFFSET                HDMI_EFUSE_BASE(0x030)
+#define HDMI_EFUSE_READ_OFFSET         HDMI_EFUSE_BASE(0x034)
+
+/*
+ * Bit definition part
+ */
+
+/* Control Register */
+
+/* HDMI_INTC_CON_0 */
+#define HDMI_INTC_POL                          (1 << 7)
+#define HDMI_INTC_EN_GLOBAL                    (1 << 6)
+#define HDMI_INTC_EN_I2S                       (1 << 5)
+#define HDMI_INTC_EN_CEC                       (1 << 4)
+#define HDMI_INTC_EN_HPD_PLUG                  (1 << 3)
+#define HDMI_INTC_EN_HPD_UNPLUG                        (1 << 2)
+#define HDMI_INTC_EN_SPDIF                     (1 << 1)
+#define HDMI_INTC_EN_HDCP                      (1 << 0)
+
+/* HDMI_INTC_FLAG_0 */
+#define HDMI_INTC_FLAG_I2S                     (1 << 5)
+#define HDMI_INTC_FLAG_CEC                     (1 << 4)
+#define HDMI_INTC_FLAG_HPD_PLUG                        (1 << 3)
+#define HDMI_INTC_FLAG_HPD_UNPLUG              (1 << 2)
+#define HDMI_INTC_FLAG_SPDIF                   (1 << 1)
+#define HDMI_INTC_FLAG_HDCP                    (1 << 0)
+
+/* HDMI_HDCP_KEY_LOAD */
+#define HDMI_HDCP_KEY_LOAD_DONE                        (1 << 0)
+
+/* HDMI_HPD_STATUS */
+#define HDMI_HPD_VALUE                         (1 << 0)
+
+/* AUDIO_CLKSEL */
+#define HDMI_AUDIO_SPDIF_CLK                   (1 << 0)
+#define HDMI_AUDIO_PCLK                                (0 << 0)
+
+/* HDMI_PHY_RSTOUT */
+#define HDMI_PHY_SW_RSTOUT                     (1 << 0)
+
+/* HDMI_PHY_VPLL */
+#define HDMI_PHY_VPLL_LOCK                     (1 << 7)
+#define HDMI_PHY_VPLL_CODE_MASK                        (0x7 << 0)
+
+/* HDMI_PHY_CMU */
+#define HDMI_PHY_CMU_LOCK                      (1 << 7)
+#define HDMI_PHY_CMU_CODE_MASK                 (0x7 << 0)
+
+/* HDMI_CORE_RSTOUT */
+#define HDMI_CORE_SW_RSTOUT                    (1 << 0)
+
+/* Core Register */
+
+/* HDMI_CON_0 */
+#define HDMI_BLUE_SCR_EN                       (1 << 5)
+#define HDMI_BLUE_SCR_DIS                      (0 << 5)
+#define HDMI_ENC_OPTION                                (1 << 4)
+#define HDMI_ASP_ENABLE                                (1 << 2)
+#define HDMI_ASP_DISABLE                       (0 << 2)
+#define HDMI_PWDN_ENB_NORMAL                   (1 << 1)
+#define HDMI_PWDN_ENB_PD                       (0 << 1)
+#define HDMI_EN                                        (1 << 0)
+#define HDMI_DIS                               (~(1 << 0))
+
+/* HDMI_CON_1 */
+#define HDMI_PX_LMT_CTRL_BYPASS                        (0 << 5)
+#define HDMI_PX_LMT_CTRL_RGB                   (1 << 5)
+#define HDMI_PX_LMT_CTRL_YPBPR                 (2 << 5)
+#define HDMI_PX_LMT_CTRL_RESERVED              (3 << 5)
+#define HDMI_CON_PXL_REP_RATIO_MASK            (1 << 1 | 1 << 0)
+#define HDMI_DOUBLE_PIXEL_REPETITION           (0x01)
+
+/* HDMI_CON_2 */
+#define HDMI_VID_PREAMBLE_EN                   (0 << 5)
+#define HDMI_VID_PREAMBLE_DIS                  (1 << 5)
+#define HDMI_GUARD_BAND_EN                     (0 << 1)
+#define HDMI_GUARD_BAND_DIS                    (1 << 1)
+
+/* STATUS */
+#define HDMI_AUTHEN_ACK_AUTH                   (1 << 7)
+#define HDMI_AUTHEN_ACK_NOT                    (0 << 7)
+#define HDMI_AUD_FIFO_OVF_FULL                 (1 << 6)
+#define HDMI_AUD_FIFO_OVF_NOT                  (0 << 6)
+#define HDMI_UPDATE_RI_INT_OCC                 (1 << 4)
+#define HDMI_UPDATE_RI_INT_NOT                 (0 << 4)
+#define HDMI_UPDATE_RI_INT_CLEAR               (1 << 4)
+#define HDMI_UPDATE_PJ_INT_OCC                 (1 << 3)
+#define HDMI_UPDATE_PJ_INT_NOT                 (0 << 3)
+#define HDMI_UPDATE_PJ_INT_CLEAR               (1 << 3)
+#define HDMI_WRITE_INT_OCC                     (1 << 2)
+#define HDMI_WRITE_INT_NOT                     (0 << 2)
+#define HDMI_WRITE_INT_CLEAR                   (1 << 2)
+#define HDMI_WATCHDOG_INT_OCC                  (1 << 1)
+#define HDMI_WATCHDOG_INT_NOT                  (0 << 1)
+#define HDMI_WATCHDOG_INT_CLEAR                        (1 << 1)
+#define HDMI_WTFORACTIVERX_INT_OCC             (1)
+#define HDMI_WTFORACTIVERX_INT_NOT             (0)
+#define HDMI_WTFORACTIVERX_INT_CLEAR           (1)
+
+/* PHY_STATUS */
+#define HDMI_PHY_STATUS_READY                  (1)
+
+/* HDMI_MODE_SEL */
+#define HDMI_MODE_HDMI_EN              (1 << 1)
+#define HDMI_MODE_DVI_EN               (1 << 0)
+#define HDMI_MODE_MASK                 (3 << 0)
+
+/* STATUS_EN */
+#define HDMI_AUD_FIFO_OVF_EN                   (1 << 6)
+#define HDMI_AUD_FIFO_OVF_DIS                  (0 << 6)
+#define HDMI_UPDATE_RI_INT_EN                  (1 << 4)
+#define HDMI_UPDATE_RI_INT_DIS                 (0 << 4)
+#define HDMI_UPDATE_PJ_INT_EN                  (1 << 3)
+#define HDMI_UPDATE_PJ_INT_DIS                 (0 << 3)
+#define HDMI_WRITE_INT_EN                      (1 << 2)
+#define HDMI_WRITE_INT_DIS                     (0 << 2)
+#define HDMI_WATCHDOG_INT_EN                   (1 << 1)
+#define HDMI_WATCHDOG_INT_DIS                  (0 << 1)
+#define HDMI_WTFORACTIVERX_INT_EN              (1)
+#define HDMI_WTFORACTIVERX_INT_DIS             (0)
+#define HDMI_INT_EN_ALL                                (HDMI_UPDATE_RI_INT_EN|\
+                                               HDMI_UPDATE_PJ_INT_DIS|\
+                                               HDMI_WRITE_INT_EN|\
+                                               HDMI_WATCHDOG_INT_EN|\
+                                               HDMI_WTFORACTIVERX_INT_EN)
+#define HDMI_INT_DIS_ALL                       (~0x1F)
+
+/* HPD */
+#define HDMI_SW_HPD_PLUGGED                    (1 << 1)
+#define HDMI_SW_HPD_UNPLUGGED                  (0 << 1)
+#define HDMI_HPD_SEL_I_HPD                     (1)
+#define HDMI_HPD_SEL_SW_HPD                    (0)
+
+/* MODE_SEL */
+#define HDMI_MODE_EN                           (1 << 1)
+#define HDMI_MODE_DIS                          (0 << 1)
+#define HDMI_DVI_MODE_EN                       (1)
+#define HDMI_DVI_MODE_DIS                      (0)
+
+/* ENC_EN */
+#define HDMI_HDCP_ENC_ENABLE                   (1)
+#define HDMI_HDCP_ENC_DISABLE                  (0)
+
+/* Video Related Register */
+
+/* BLUESCREEN_0/1/2 */
+
+/* HDMI_YMAX/YMIN/CMAX/CMIN */
+
+/* H_BLANK_0/1 */
+
+/* V_BLANK_0/1/2 */
+
+/* H_V_LINE_0/1/2 */
+
+/* VSYNC_POL */
+#define HDMI_V_SYNC_POL_ACT_LOW                        (1)
+#define HDMI_V_SYNC_POL_ACT_HIGH               (0)
+
+/* INT_PRO_MODE */
+#define HDMI_INTERLACE_MODE                    (1)
+#define HDMI_PROGRESSIVE_MODE                  (0)
+
+/* V_BLANK_F_0/1/2 */
+
+/* H_SYNC_GEN_0/1/2 */
+
+/* V_SYNC_GEN1_0/1/2 */
+
+/* V_SYNC_GEN2_0/1/2 */
+
+/* V_SYNC_GEN3_0/1/2 */
+
+/* Audio Related Packet Register */
+
+/* ASP_CON */
+#define HDMI_AUD_DST_DOUBLE                    (1 << 7)
+#define HDMI_AUD_NO_DST_DOUBLE                 (0 << 7)
+#define HDMI_AUD_TYPE_SAMPLE                   (0 << 5)
+#define HDMI_AUD_TYPE_ONE_BIT                  (1 << 5)
+#define HDMI_AUD_TYPE_HBR                      (2 << 5)
+#define HDMI_AUD_TYPE_DST                      (3 << 5)
+#define HDMI_AUD_MODE_TWO_CH                   (0 << 4)
+#define HDMI_AUD_MODE_MULTI_CH                 (1 << 4)
+#define HDMI_AUD_SP_AUD3_EN                    (1 << 3)
+#define HDMI_AUD_SP_AUD2_EN                    (1 << 2)
+#define HDMI_AUD_SP_AUD1_EN                    (1 << 1)
+#define HDMI_AUD_SP_AUD0_EN                    (1 << 0)
+#define HDMI_AUD_SP_ALL_DIS                    (0 << 0)
+
+#define HDMI_AUD_SET_SP_PRE(x)                 ((x) & 0xF)
+
+/* ASP_SP_FLAT */
+#define HDMI_ASP_SP_FLAT_AUD_SAMPLE            (0)
+
+/* ASP_CHCFG0/1/2/3 */
+#define HDMI_SPK3R_SEL_I_PCM0L                 (0 << 27)
+#define HDMI_SPK3R_SEL_I_PCM0R                 (1 << 27)
+#define HDMI_SPK3R_SEL_I_PCM1L                 (2 << 27)
+#define HDMI_SPK3R_SEL_I_PCM1R                 (3 << 27)
+#define HDMI_SPK3R_SEL_I_PCM2L                 (4 << 27)
+#define HDMI_SPK3R_SEL_I_PCM2R                 (5 << 27)
+#define HDMI_SPK3R_SEL_I_PCM3L                 (6 << 27)
+#define HDMI_SPK3R_SEL_I_PCM3R                 (7 << 27)
+#define HDMI_SPK3L_SEL_I_PCM0L                 (0 << 24)
+#define HDMI_SPK3L_SEL_I_PCM0R                 (1 << 24)
+#define HDMI_SPK3L_SEL_I_PCM1L                 (2 << 24)
+#define HDMI_SPK3L_SEL_I_PCM1R                 (3 << 24)
+#define HDMI_SPK3L_SEL_I_PCM2L                 (4 << 24)
+#define HDMI_SPK3L_SEL_I_PCM2R                 (5 << 24)
+#define HDMI_SPK3L_SEL_I_PCM3L                 (6 << 24)
+#define HDMI_SPK3L_SEL_I_PCM3R                 (7 << 24)
+#define HDMI_SPK2R_SEL_I_PCM0L                 (0 << 19)
+#define HDMI_SPK2R_SEL_I_PCM0R                 (1 << 19)
+#define HDMI_SPK2R_SEL_I_PCM1L                 (2 << 19)
+#define HDMI_SPK2R_SEL_I_PCM1R                 (3 << 19)
+#define HDMI_SPK2R_SEL_I_PCM2L                 (4 << 19)
+#define HDMI_SPK2R_SEL_I_PCM2R                 (5 << 19)
+#define HDMI_SPK2R_SEL_I_PCM3L                 (6 << 19)
+#define HDMI_SPK2R_SEL_I_PCM3R                 (7 << 19)
+#define HDMI_SPK2L_SEL_I_PCM0L                 (0 << 16)
+#define HDMI_SPK2L_SEL_I_PCM0R                 (1 << 16)
+#define HDMI_SPK2L_SEL_I_PCM1L                 (2 << 16)
+#define HDMI_SPK2L_SEL_I_PCM1R                 (3 << 16)
+#define HDMI_SPK2L_SEL_I_PCM2L                 (4 << 16)
+#define HDMI_SPK2L_SEL_I_PCM2R                 (5 << 16)
+#define HDMI_SPK2L_SEL_I_PCM3L                 (6 << 16)
+#define HDMI_SPK2L_SEL_I_PCM3R                 (7 << 16)
+#define HDMI_SPK1R_SEL_I_PCM0L                 (0 << 11)
+#define HDMI_SPK1R_SEL_I_PCM0R                 (1 << 11)
+#define HDMI_SPK1R_SEL_I_PCM1L                 (2 << 11)
+#define HDMI_SPK1R_SEL_I_PCM1R                 (3 << 11)
+#define HDMI_SPK1R_SEL_I_PCM2L                 (4 << 11)
+#define HDMI_SPK1R_SEL_I_PCM2R                 (5 << 11)
+#define HDMI_SPK1R_SEL_I_PCM3L                 (6 << 11)
+#define HDMI_SPK1R_SEL_I_PCM3R                 (7 << 11)
+#define HDMI_SPK1L_SEL_I_PCM0L                 (0 << 8)
+#define HDMI_SPK1L_SEL_I_PCM0R                 (1 << 8)
+#define HDMI_SPK1L_SEL_I_PCM1L                 (2 << 8)
+#define HDMI_SPK1L_SEL_I_PCM1R                 (3 << 8)
+#define HDMI_SPK1L_SEL_I_PCM2L                 (4 << 8)
+#define HDMI_SPK1L_SEL_I_PCM2R                 (5 << 8)
+#define HDMI_SPK1L_SEL_I_PCM3L                 (6 << 8)
+#define HDMI_SPK1L_SEL_I_PCM3R                 (7 << 8)
+#define HDMI_SPK0R_SEL_I_PCM0L                 (0 << 3)
+#define HDMI_SPK0R_SEL_I_PCM0R                 (1 << 3)
+#define HDMI_SPK0R_SEL_I_PCM1L                 (2 << 3)
+#define HDMI_SPK0R_SEL_I_PCM1R                 (3 << 3)
+#define HDMI_SPK0R_SEL_I_PCM2L                 (4 << 3)
+#define HDMI_SPK0R_SEL_I_PCM2R                 (5 << 3)
+#define HDMI_SPK0R_SEL_I_PCM3L                 (6 << 3)
+#define HDMI_SPK0R_SEL_I_PCM3R                 (7 << 3)
+#define HDMI_SPK0L_SEL_I_PCM0L                 (0)
+#define HDMI_SPK0L_SEL_I_PCM0R                 (1)
+#define HDMI_SPK0L_SEL_I_PCM1L                 (2)
+#define HDMI_SPK0L_SEL_I_PCM1R                 (3)
+#define HDMI_SPK0L_SEL_I_PCM2L                 (4)
+#define HDMI_SPK0L_SEL_I_PCM2R                 (5)
+#define HDMI_SPK0L_SEL_I_PCM3L                 (6)
+#define HDMI_SPK0L_SEL_I_PCM3R                 (7)
+
+/* ACR_CON */
+#define HDMI_ACR_CON_TX_MODE_NO_TX             (0 << 0)
+#define HDMI_ACR_CON_TX_MODE_MESURED_CTS       (4 << 0)
+
+/* ACR_MCTS0/1/2 */
+
+/* ACR_CTS0/1/2 */
+
+/* ACR_N0/1/2 */
+#define HDMI_ACR_N0_VAL(x)                     (x & 0xff)
+#define HDMI_ACR_N1_VAL(x)                     ((x >> 8) & 0xff)
+#define HDMI_ACR_N2_VAL(x)                     ((x >> 16) & 0xff)
+
+/* ACR_LSB2 */
+#define HDMI_ACR_LSB2_MASK                     (0xFF)
+
+/* ACR_TXCNT */
+#define HDMI_ACR_TXCNT_MASK                    (0x1F)
+
+/* ACR_TXINTERNAL */
+#define HDMI_ACR_TX_INTERNAL_MASK              (0xFF)
+
+/* ACR_CTS_OFFSET */
+#define HDMI_ACR_CTS_OFFSET_MASK               (0xFF)
+
+/* GCP_CON */
+#define HDMI_GCP_CON_EN_1ST_VSYNC              (1 << 3)
+#define HDMI_GCP_CON_EN_2ST_VSYNC              (1 << 2)
+#define HDMI_GCP_CON_TRANS_EVERY_VSYNC         (2)
+#define HDMI_GCP_CON_NO_TRAN                   (0)
+#define HDMI_GCP_CON_TRANS_ONCE                        (1)
+#define HDMI_GCP_CON_TRANS_EVERY_VSYNC         (2)
+
+/* GCP_BYTE1 */
+#define HDMI_GCP_BYTE1_MASK                    (0xFF)
+
+/* GCP_BYTE2 */
+#define HDMI_GCP_BYTE2_PP_MASK                 (0xF << 4)
+#define HDMI_GCP_24BPP                         (1 << 2)
+#define HDMI_GCP_30BPP                         (1 << 0 | 1 << 2)
+#define HDMI_GCP_36BPP                         (1 << 1 | 1 << 2)
+#define HDMI_GCP_48BPP                         (1 << 0 | 1 << 1 | 1 << 2)
+
+/* GCP_BYTE3 */
+#define HDMI_GCP_BYTE3_MASK                    (0xFF)
+
+/* ACP Packet Register */
+
+/* ACP_CON */
+#define HDMI_ACP_FR_RATE_MASK                  (0x1F << 3)
+#define HDMI_ACP_CON_NO_TRAN                   (0)
+#define HDMI_ACP_CON_TRANS_ONCE                        (1)
+#define HDMI_ACP_CON_TRANS_EVERY_VSYNC         (2)
+
+/* ACP_TYPE */
+#define HDMI_ACP_TYPE_MASK                     (0xFF)
+
+/* ACP_DATA00~16 */
+#define HDMI_ACP_DATA_MASK                     (0xFF)
+
+/* ISRC1/2 Packet Register */
+
+/* ISRC_CON */
+#define HDMI_ISRC_FR_RATE_MASK                 (0x1F << 3)
+#define HDMI_ISRC_EN                           (1 << 2)
+#define HDMI_ISRC_DIS                          (0 << 2)
+
+/* ISRC1_HEADER1 */
+#define HDMI_ISRC1_HEADER_MASK                 (0xFF)
+
+/* ISRC1_DATA 00~15 */
+#define HDMI_ISRC1_DATA_MASK                   (0xFF)
+
+/* ISRC2_DATA 00~15 */
+#define HDMI_ISRC2_DATA_MASK                   (0xFF)
+
+/* AVI InfoFrame Register */
+
+/* AVI_CON */
+#define HDMI_AVI_CON_EVERY_VSYNC               (1 << 1)
+
+/* AVI_CHECK_SUM */
+
+/* AVI_DATA01~13 */
+#define HDMI_AVI_PIXEL_REPETITION_DOUBLE       (1<<0)
+#define HDMI_AVI_PICTURE_ASPECT_4_3            (1<<4)
+#define HDMI_AVI_PICTURE_ASPECT_16_9           (1<<5)
+
+/* Audio InfoFrame Register */
+
+/* AUI_CON */
+#define HDMI_AUI_CON_NO_TRAN                   (0 << 0)
+#define HDMI_AUI_CON_TRANS_ONCE                        (1 << 0)
+#define HDMI_AUI_CON_TRANS_EVERY_VSYNC         (2 << 0)
+
+/* AUI_CHECK_SUM */
+
+/* AUI_DATA1~5 */
+
+/* MPEG Source InfoFrame registers */
+
+/* MPG_CON */
+
+/* HDMI_MPG_CHECK_SUM */
+
+/* MPG_DATA1~5 */
+
+/* Source Product Descriptor Infoframe registers */
+
+/* SPD_CON */
+
+/* SPD_HEADER0/1/2 */
+
+/* SPD_DATA0~27 */
+
+/* VSI_CON */
+#define HDMI_VSI_CON_DO_NOT_TRANSMIT           (0 << 0)
+#define HDMI_VSI_CON_EVERY_VSYNC               (1 << 1)
+
+/* VSI_DATA00 ~ 27 */
+#define HDMI_VSI_DATA04_VIDEO_FORMAT(x)                (x << 5)
+#define HDMI_VSI_DATA05_3D_STRUCTURE(x)                (x << 4)
+#define HDMI_VSI_DATA06_3D_EXT_DATA(x)         (x << 4)
+
+/* HDCP Register */
+
+/* HDCP_SHA1_00~19 */
+
+/* HDCP_KSV_LIST_0~4 */
+
+/* HDCP_KSV_LIST_CON */
+#define HDMI_HDCP_KSV_WRITE_DONE               (0x1 << 3)
+#define HDMI_HDCP_KSV_LIST_EMPTY               (0x1 << 2)
+#define HDMI_HDCP_KSV_END                      (0x1 << 1)
+#define HDMI_HDCP_KSV_READ                     (0x1 << 0)
+
+/* HDCP_CTRL1 */
+#define HDMI_HDCP_EN_PJ_EN                     (1 << 4)
+#define HDMI_HDCP_EN_PJ_DIS                    (~(1 << 4))
+#define HDMI_HDCP_SET_REPEATER_TIMEOUT         (1 << 2)
+#define HDMI_HDCP_CLEAR_REPEATER_TIMEOUT       (~(1 << 2))
+#define HDMI_HDCP_CP_DESIRED_EN                        (1 << 1)
+#define HDMI_HDCP_CP_DESIRED_DIS               (~(1 << 1))
+#define HDMI_HDCP_ENABLE_1_1_FEATURE_EN                (1)
+#define HDMI_HDCP_ENABLE_1_1_FEATURE_DIS       (~(1))
+
+/* HDCP_CHECK_RESULT */
+#define HDMI_HDCP_PI_MATCH_RESULT_Y            ((0x1 << 3) | (0x1 << 2))
+#define HDMI_HDCP_PI_MATCH_RESULT_N            ((0x1 << 3) | (0x0 << 2))
+#define HDMI_HDCP_RI_MATCH_RESULT_Y            ((0x1 << 1) | (0x1 << 0))
+#define HDMI_HDCP_RI_MATCH_RESULT_N            ((0x1 << 1) | (0x0 << 0))
+#define HDMI_HDCP_CLR_ALL_RESULTS              (0)
+
+/* HDCP_BKSV0~4 */
+/* HDCP_AKSV0~4 */
+
+/* HDCP_BCAPS */
+#define HDMI_HDCP_BCAPS_REPEATER               (1 << 6)
+#define HDMI_HDCP_BCAPS_READY                  (1 << 5)
+#define HDMI_HDCP_BCAPS_FAST                   (1 << 4)
+#define HDMI_HDCP_BCAPS_1_1_FEATURES           (1 << 1)
+#define HDMI_HDCP_BCAPS_FAST_REAUTH            (1)
+
+/* HDCP_BSTATUS_0/1 */
+/* HDCP_Ri_0/1 */
+/* HDCP_I2C_INT */
+/* HDCP_AN_INT */
+/* HDCP_WATCHDOG_INT */
+/* HDCP_RI_INT/1 */
+/* HDCP_Ri_Compare_0 */
+/* HDCP_Ri_Compare_1 */
+/* HDCP_Frame_Count */
+
+/* Gamut Metadata Packet Register */
+
+/* GAMUT_CON */
+/* GAMUT_HEADER0 */
+/* GAMUT_HEADER1 */
+/* GAMUT_HEADER2 */
+/* GAMUT_METADATA0~27 */
+
+/* Video Mode Register */
+
+/* VIDEO_PATTERN_GEN */
+/* HPD_GEN */
+/* HDCP_Ri_Compare_0 */
+/* HDCP_Ri_Compare_0 */
+/* HDCP_Ri_Compare_0 */
+/* HDCP_Ri_Compare_0 */
+/* HDCP_Ri_Compare_0 */
+/* HDCP_Ri_Compare_0 */
+/* HDCP_Ri_Compare_0 */
+/* HDCP_Ri_Compare_0 */
+/* HDCP_Ri_Compare_0 */
+/* HDCP_Ri_Compare_0 */
+
+/* SPDIF Register */
+
+/* SPDIFIN_CLK_CTRL */
+#define HDMI_SPDIFIN_READY_CLK_DOWN            (1 << 1)
+#define HDMI_SPDIFIN_CLK_ON                    (1 << 0)
+
+/* SPDIFIN_OP_CTRL */
+#define HDMI_SPDIFIN_SW_RESET                  (0 << 0)
+#define HDMI_SPDIFIN_STATUS_CHECK_MODE         (1 << 0)
+#define HDMI_SPDIFIN_STATUS_CHECK_MODE_HDMI    (3 << 0)
+
+/* SPDIFIN_IRQ_MASK */
+
+/* SPDIFIN_IRQ_STATUS */
+#define HDMI_SPDIFIN_IRQ_OVERFLOW_EN                           (1 << 7)
+#define HDMI_SPDIFIN_IRQ_ABNORMAL_PD_EN                                (1 << 6)
+#define HDMI_SPDIFIN_IRQ_SH_NOT_DETECTED_RIGHTTIME_EN          (1 << 5)
+#define HDMI_SPDIFIN_IRQ_SH_DETECTED_EN                                (1 << 4)
+#define HDMI_SPDIFIN_IRQ_SH_NOT_DETECTED_EN                    (1 << 3)
+#define HDMI_SPDIFIN_IRQ_WRONG_PREAMBLE_EN                     (1 << 2)
+#define HDMI_SPDIFIN_IRQ_CH_STATUS_RECOVERED_EN                        (1 << 1)
+#define HDMI_SPDIFIN_IRQ_WRONG_SIG_EN                          (1 << 0)
+
+/* SPDIFIN_CONFIG_1 */
+#define HDMI_SPDIFIN_CFG_NOISE_FILTER_2_SAMPLE                 (1 << 6)
+#define HDMI_SPDIFIN_CFG_PCPD_MANUAL                           (1 << 4)
+#define HDMI_SPDIFIN_CFG_WORD_LENGTH_MANUAL                    (1 << 3)
+#define HDMI_SPDIFIN_CFG_UVCP_REPORT                           (1 << 2)
+#define HDMI_SPDIFIN_CFG_HDMI_2_BURST                          (1 << 1)
+#define HDMI_SPDIFIN_CFG_DATA_ALIGN_32                         (1 << 0)
+
+/* SPDIFIN_CONFIG_2 */
+#define HDMI_SPDIFIN_CFG2_NO_CLK_DIV                           (0)
+
+/* SPDIFIN_USER_VALUE_1 */
+#define HDMI_SPDIFIN_USER_VAL_REPETITION_TIME_LOW(x)   ((x & 0xf) << 4)
+#define HDMI_SPDIFIN_USER_VAL_WORD_LENGTH_24           (0xb << 0)
+#define HDMI_SPDIFIN_USER_VAL_REPETITION_TIME_HIGH(x)  ((x >> 4) & 0xff)
+/* SPDIFIN_USER_VALUE_2 */
+/* SPDIFIN_USER_VALUE_3 */
+/* SPDIFIN_USER_VALUE_4 */
+/* SPDIFIN_CH_STATUS_0_1 */
+/* SPDIFIN_CH_STATUS_0_2 */
+/* SPDIFIN_CH_STATUS_0_3 */
+/* SPDIFIN_CH_STATUS_0_4 */
+/* SPDIFIN_CH_STATUS_1 */
+/* SPDIFIN_FRAME_PERIOD_1 */
+/* SPDIFIN_FRAME_PERIOD_2 */
+/* SPDIFIN_PC_INFO_1 */
+/* SPDIFIN_PC_INFO_2 */
+/* SPDIFIN_PD_INFO_1 */
+/* SPDIFIN_PD_INFO_2 */
+/* SPDIFIN_DATA_BUF_0_1 */
+/* SPDIFIN_DATA_BUF_0_2 */
+/* SPDIFIN_DATA_BUF_0_3 */
+/* SPDIFIN_USER_BUF_0 */
+/* SPDIFIN_USER_BUF_1_1 */
+/* SPDIFIN_USER_BUF_1_2 */
+/* SPDIFIN_USER_BUF_1_3 */
+/* SPDIFIN_USER_BUF_1 */
+
+/* I2S Register */
+
+/* I2S_CLK_CON */
+#define HDMI_I2S_CLK_DISABLE                   (0)
+#define HDMI_I2S_CLK_ENABLE                    (1)
+
+/* I2S_CON_1 */
+#define HDMI_I2S_SCLK_FALLING_EDGE             (0 << 1)
+#define HDMI_I2S_SCLK_RISING_EDGE              (1 << 1)
+#define HDMI_I2S_L_CH_LOW_POL                  (0)
+#define HDMI_I2S_L_CH_HIGH_POL                 (1)
+
+/* I2S_CON_2 */
+#define HDMI_I2S_MSB_FIRST_MODE                        (0 << 6)
+#define HDMI_I2S_LSB_FIRST_MODE                        (1 << 6)
+#define HDMI_I2S_BIT_CH_32FS                   (0 << 4)
+#define HDMI_I2S_BIT_CH_48FS                   (1 << 4)
+#define HDMI_I2S_BIT_CH_RESERVED               (2 << 4)
+#define HDMI_I2S_SDATA_16BIT                   (1 << 2)
+#define HDMI_I2S_SDATA_20BIT                   (2 << 2)
+#define HDMI_I2S_SDATA_24BIT                   (3 << 2)
+#define HDMI_I2S_BASIC_FORMAT                  (0)
+#define HDMI_I2S_L_JUST_FORMAT                 (2)
+#define HDMI_I2S_R_JUST_FORMAT                 (3)
+#define HDMI_I2S_CON_2_CLR                     (~(0xFF))
+#define HDMI_I2S_SET_BIT_CH(x)                 (((x) & 0x7) << 4)
+#define HDMI_I2S_SET_SDATA_BIT(x)              (((x) & 0x7) << 2)
+
+/* I2S_PIN_SEL_0 */
+#define HDMI_I2S_SEL_SCLK(x)                   (((x) & 0x7) << 4)
+#define HDMI_I2S_SEL_LRCK(x)                   ((x) & 0x7)
+
+/* I2S_PIN_SEL_1 */
+#define HDMI_I2S_SEL_SDATA1(x)                 (((x) & 0x7) << 4)
+#define HDMI_I2S_SEL_SDATA0(x)                 ((x) & 0x7)
+
+/* I2S_PIN_SEL_2 */
+#define HDMI_I2S_SEL_SDATA3(x)                 (((x) & 0x7) << 4)
+#define HDMI_I2S_SEL_SDATA2(x)                 ((x) & 0x7)
+
+/* I2S_PIN_SEL_3 */
+#define HDMI_I2S_SEL_DSD(x)                    ((x) & 0x7)
+
+/* I2S_DSD_CON */
+#define HDMI_I2S_DSD_CLK_RI_EDGE               (1 << 1)
+#define HDMI_I2S_DSD_CLK_FA_EDGE               (0 << 1)
+#define HDMI_I2S_DSD_ENABLE                    (1 << 0)
+#define HDMI_I2S_DSD_DISABLE                   (0 << 0)
+
+/* I2S_MUX_CON */
+#define HDMI_I2S_NOISE_FILTER_ZERO             (0 << 5)
+#define HDMI_I2S_NOISE_FILTER_2_STAGE          (1 << 5)
+#define HDMI_I2S_NOISE_FILTER_3_STAGE          (2 << 5)
+#define HDMI_I2S_NOISE_FILTER_4_STAGE          (3 << 5)
+#define HDMI_I2S_NOISE_FILTER_5_STAGE          (4 << 5)
+#define HDMI_I2S_IN_ENABLE                     (1 << 4)
+#define HDMI_I2S_IN_DISABLE                    (0 << 4)
+#define HDMI_I2S_AUD_SPDIF                     (0 << 2)
+#define HDMI_I2S_AUD_I2S                       (1 << 2)
+#define HDMI_I2S_AUD_DSD                       (2 << 2)
+#define HDMI_I2S_CUV_SPDIF_ENABLE              (0 << 1)
+#define HDMI_I2S_CUV_I2S_ENABLE                        (1 << 1)
+#define HDMI_I2S_MUX_DISABLE                   (0 << 0)
+#define HDMI_I2S_MUX_ENABLE                    (1 << 0)
+
+/* I2S_CH_ST_CON */
+#define HDMI_I2S_CH_STATUS_RELOAD              (1 << 0)
+#define HDMI_I2S_CH_ST_CON_CLR                 (~(1))
+
+/* I2S_CH_ST_0 / I2S_CH_ST_SH_0 */
+#define HDMI_I2S_CH_STATUS_MODE_0              (0 << 6)
+#define HDMI_I2S_2AUD_CH_WITHOUT_PREEMPH       (0 << 3)
+#define HDMI_I2S_2AUD_CH_WITH_PREEMPH          (1 << 3)
+#define HDMI_I2S_DEFAULT_EMPHASIS              (0 << 3)
+#define HDMI_I2S_COPYRIGHT                     (0 << 2)
+#define HDMI_I2S_NO_COPYRIGHT                  (1 << 2)
+#define HDMI_I2S_LINEAR_PCM                    (0 << 1)
+#define HDMI_I2S_NO_LINEAR_PCM                 (1 << 1)
+#define HDMI_I2S_CONSUMER_FORMAT               (0)
+#define HDMI_I2S_PROF_FORMAT                   (1)
+#define HDMI_I2S_CH_ST_0_CLR                   (~(0xFF))
+
+/* I2S_CH_ST_1 / I2S_CH_ST_SH_1 */
+#define HDMI_I2S_CD_PLAYER                     (0x00)
+#define HDMI_I2S_DAT_PLAYER                    (0x03)
+#define HDMI_I2S_DCC_PLAYER                    (0x43)
+#define HDMI_I2S_MINI_DISC_PLAYER              (0x49)
+
+/* I2S_CH_ST_2 / I2S_CH_ST_SH_2 */
+#define HDMI_I2S_CHANNEL_NUM_MASK              (0xF << 4)
+#define HDMI_I2S_SOURCE_NUM_MASK               (0xF)
+#define HDMI_I2S_SET_CHANNEL_NUM(x)            ((x) & (0xF) << 4)
+#define HDMI_I2S_SET_SOURCE_NUM(x)             ((x) & (0xF))
+
+/* I2S_CH_ST_3 / I2S_CH_ST_SH_3 */
+#define HDMI_I2S_CLK_ACCUR_LEVEL_1             (1 << 4)
+#define HDMI_I2S_CLK_ACCUR_LEVEL_2             (0 << 4)
+#define HDMI_I2S_CLK_ACCUR_LEVEL_3             (2 << 4)
+#define HDMI_I2S_SAMPLING_FREQ_44_1            (0x0)
+#define HDMI_I2S_SAMPLING_FREQ_48              (0x2)
+#define HDMI_I2S_SAMPLING_FREQ_32              (0x3)
+#define HDMI_I2S_SAMPLING_FREQ_96              (0xA)
+#define HDMI_I2S_SET_SAMPLING_FREQ(x)          ((x) & (0xF))
+
+/* I2S_CH_ST_4 / I2S_CH_ST_SH_4 */
+#define HDMI_I2S_ORG_SAMPLING_FREQ_44_1                (0xF << 4)
+#define HDMI_I2S_ORG_SAMPLING_FREQ_88_2                (0x7 << 4)
+#define HDMI_I2S_ORG_SAMPLING_FREQ_22_05       (0xB << 4)
+#define HDMI_I2S_ORG_SAMPLING_FREQ_176_4       (0x3 << 4)
+#define HDMI_I2S_WORD_LENGTH_NOT_DEFINE                (0x0 << 1)
+#define HDMI_I2S_WORD_LENGTH_MAX24_20BITS      (0x1 << 1)
+#define HDMI_I2S_WORD_LENGTH_MAX24_22BITS      (0x2 << 1)
+#define HDMI_I2S_WORD_LENGTH_MAX24_23BITS      (0x4 << 1)
+#define HDMI_I2S_WORD_LENGTH_MAX24_24BITS      (0x5 << 1)
+#define HDMI_I2S_WORD_LENGTH_MAX24_21BITS      (0x6 << 1)
+#define HDMI_I2S_WORD_LENGTH_MAX20_16BITS      (0x1 << 1)
+#define HDMI_I2S_WORD_LENGTH_MAX20_18BITS      (0x2 << 1)
+#define HDMI_I2S_WORD_LENGTH_MAX20_19BITS      (0x4 << 1)
+#define HDMI_I2S_WORD_LENGTH_MAX20_20BITS      (0x5 << 1)
+#define HDMI_I2S_WORD_LENGTH_MAX20_17BITS      (0x6 << 1)
+#define HDMI_I2S_WORD_LENGTH_MAX_24BITS                (1)
+#define HDMI_I2S_WORD_LENGTH_MAX_20BITS                (0)
+
+/* I2S_VD_DATA */
+#define HDMI_I2S_VD_AUD_SAMPLE_RELIABLE                (0)
+#define HDMI_I2S_VD_AUD_SAMPLE_UNRELIABLE      (1)
+
+/* I2S_MUX_CH */
+#define HDMI_I2S_CH3_R_EN                      (1 << 7)
+#define HDMI_I2S_CH3_L_EN                      (1 << 6)
+#define HDMI_I2S_CH2_R_EN                      (1 << 5)
+#define HDMI_I2S_CH2_L_EN                      (1 << 4)
+#define HDMI_I2S_CH1_R_EN                      (1 << 3)
+#define HDMI_I2S_CH1_L_EN                      (1 << 2)
+#define HDMI_I2S_CH0_R_EN                      (1 << 1)
+#define HDMI_I2S_CH0_L_EN                      (1)
+#define HDMI_I2S_CH_ALL_EN                     (0xFF)
+#define HDMI_I2S_MUX_CH_CLR                    (~HDMI_I2S_CH_ALL_EN)
+
+/* I2S_MUX_CUV */
+#define HDMI_I2S_CUV_R_EN                      (1 << 1)
+#define HDMI_I2S_CUV_L_EN                      (1 << 0)
+#define HDMI_I2S_CUV_RL_EN                     (0x03)
+
+/* I2S_IRQ_MASK */
+#define HDMI_I2S_INT2_DIS                      (0 << 1)
+#define HDMI_I2S_INT2_EN                       (1 << 1)
+
+/* I2S_IRQ_STATUS */
+#define HDMI_I2S_INT2_STATUS                   (1 << 1)
+
+/* I2S_CH0_L_0 */
+/* I2S_CH0_L_1 */
+/* I2S_CH0_L_2 */
+/* I2S_CH0_L_3 */
+/* I2S_CH0_R_0 */
+/* I2S_CH0_R_1 */
+/* I2S_CH0_R_2 */
+/* I2S_CH0_R_3 */
+/* I2S_CH1_L_0 */
+/* I2S_CH1_L_1 */
+/* I2S_CH1_L_2 */
+/* I2S_CH1_L_3 */
+/* I2S_CH1_R_0 */
+/* I2S_CH1_R_1 */
+/* I2S_CH1_R_2 */
+/* I2S_CH1_R_3 */
+/* I2S_CH2_L_0 */
+/* I2S_CH2_L_1 */
+/* I2S_CH2_L_2 */
+/* I2S_CH2_L_3 */
+/* I2S_CH2_R_0 */
+/* I2S_CH2_R_1 */
+/* I2S_CH2_R_2 */
+/* I2S_Ch2_R_3 */
+/* I2S_CH3_L_0 */
+/* I2S_CH3_L_1 */
+/* I2S_CH3_L_2 */
+/* I2S_CH3_R_0 */
+/* I2S_CH3_R_1 */
+/* I2S_CH3_R_2 */
+
+/* I2S_CUV_L_R */
+#define HDMI_I2S_CUV_R_DATA_MASK               (0x7 << 4)
+#define HDMI_I2S_CUV_L_DATA_MASK               (0x7)
+
+/* Timing Generator Register */
+/* TG_CMD */
+#define HDMI_GETSYNC_TYPE                      (1 << 4)
+#define HDMI_GETSYNC                           (1 << 3)
+
+/* HDMI_TG_CMD */
+#define HDMI_FIELD_EN                          (1 << 1)
+#define HDMI_TG_EN                             (1 << 0)
+
+/* TG_CFG */
+/* TG_CB_SZ */
+/* TG_INDELAY_L */
+/* TG_INDELAY_H */
+/* TG_POL_CTRL */
+
+/* TG_H_FSZ_L */
+/* TG_H_FSZ_H */
+/* TG_HACT_ST_L */
+/* TG_HACT_ST_H */
+/* TG_HACT_SZ_L */
+/* TG_HACT_SZ_H */
+/* TG_V_FSZ_L */
+/* TG_V_FSZ_H */
+/* TG_VSYNC_L */
+/* TG_VSYNC_H */
+/* TG_VSYNC2_L */
+/* TG_VSYNC2_H */
+/* TG_VACT_ST_L */
+/* TG_VACT_ST_H */
+/* TG_VACT_SZ_L */
+/* TG_VACT_SZ_H */
+/* TG_FIELD_CHG_L */
+/* TG_FIELD_CHG_H */
+/* TG_VACT_ST2_L */
+/* TG_VACT_ST2_H */
+/* TG_VACT_SC_ST_L */
+/* TG_VACT_SC_ST_H */
+/* TG_VACT_SC_SZ_L */
+/* TG_VACT_SC_SZ_H */
+
+/* TG_VSYNC_TOP_HDMI_L */
+/* TG_VSYNC_TOP_HDMI_H */
+/* TG_VSYNC_BOT_HDMI_L */
+/* TG_VSYNC_BOT_HDMI_H */
+/* TG_FIELD_TOP_HDMI_L */
+/* TG_FIELD_TOP_HDMI_H */
+/* TG_FIELD_BOT_HDMI_L */
+/* TG_FIELD_BOT_HDMI_H */
+/* TG_HSYNC_HDOUT_ST_L */
+/* TG_HSYNC_HDOUT_ST_H */
+/* TG_HSYNC_HDOUT_END_L */
+/* TG_HSYNC_HDOUT_END_H */
+/* TG_VSYNC_HDOUT_ST_L */
+/* TG_VSYNC_HDOUT_ST_H */
+/* TG_VSYNC_HDOUT_END_L */
+/* TG_VSYNC_HDOUT_END_H */
+/* TG_VSYNC_HDOUT_DLY_L */
+/* TG_VSYNC_HDOUT_DLY_H */
+/* TG_BT_ERR_RANGE */
+/* TG_BT_ERR_RESULT */
+/* TG_COR_THR */
+/* TG_COR_NUM */
+/* TG_BT_CON */
+/* TG_BT_H_FSZ_L */
+/* TG_BT_H_FSZ_H */
+/* TG_BT_HSYNC_ST */
+/* TG_BT_HSYNC_SZ */
+/* TG_BT_FSZ_L */
+/* TG_BT_FSZ_H */
+/* TG_BT_VACT_T_ST_L */
+/* TG_BT_VACT_T_ST_H */
+/* TG_BT_VACT_B_ST_L */
+/* TG_BT_VACT_B_ST_H */
+/* TG_BT_VACT_SZ_L */
+/* TG_BT_VACT_SZ_H */
+/* TG_BT_VSYNC_SZ */
+
+/* HDCP E-FUSE Control Register */
+/* HDCP_E_FUSE_CTRL */
+#define HDMI_EFUSE_CTRL_HDCP_KEY_READ          (1 << 0)
+
+/* HDCP_E_FUSE_STATUS */
+#define HDMI_EFUSE_ECC_FAIL                    (1 << 2)
+#define HDMI_EFUSE_ECC_BUSY                    (1 << 1)
+#define HDMI_EFUSE_ECC_DONE                    (1)
+
+/* EFUSE_ADDR_WIDTH */
+/* EFUSE_SIGDEV_ASSERT */
+/* EFUSE_SIGDEV_DE-ASSERT */
+/* EFUSE_PRCHG_ASSERT */
+/* EFUSE_PRCHG_DE-ASSERT */
+/* EFUSE_FSET_ASSERT */
+/* EFUSE_FSET_DE-ASSERT */
+/* EFUSE_SENSING */
+/* EFUSE_SCK_ASSERT */
+/* EFUSE_SCK_DEASSERT */
+/* EFUSE_SDOUT_OFFSET */
+/* EFUSE_READ_OFFSET */
+
+/* HDCP_SHA_RESULT */
+#define HDMI_HDCP_SHA_VALID_NO_RD              (0 << 1)
+#define HDMI_HDCP_SHA_VALID_RD                 (1 << 1)
+#define HDMI_HDCP_SHA_VALID                    (1)
+#define HDMI_HDCP_SHA_NO_VALID                 (0)
+
+/* DC_CONTRAL */
+#define HDMI_DC_CTL_12                         (1 << 1)
+#define HDMI_DC_CTL_8                          (0)
+#define HDMI_DC_CTL_10                         (1)
+#endif /* __ARCH_ARM_REGS_HDMI_H */
diff --git a/drivers/media/video/exynos/tv/regs-mixer.h b/drivers/media/video/exynos/tv/regs-mixer.h
new file mode 100644 (file)
index 0000000..15ad119
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Mixer register header file for Samsung Mixer driver
+ *
+ * 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.
+*/
+#ifndef SAMSUNG_REGS_MIXER_H
+#define SAMSUNG_REGS_MIXER_H
+
+#include <plat/map-base.h>
+
+/* SYSREG for local path between Gscaler and Mixer */
+#define SYSREG_DISP1BLK_CFG            (S3C_VA_SYS + 0x0214)
+
+#define DISP1BLK_CFG_FIFORST_DISP1     (1 << 23)
+#define DISP1BLK_CFG_MIXER_MASK                (0x3F << 2)
+#define DISP1BLK_CFG_MIXER0_VALID      (1 << 7)
+#define DISP1BLK_CFG_MIXER0_SRC_GSC(x) (x << 5)
+#define DISP1BLK_CFG_MIXER1_VALID      (1 << 4)
+#define DISP1BLK_CFG_MIXER1_SRC_GSC(x) (x << 2)
+
+/*
+ * Register part
+ */
+#define MXR_STATUS                     0x0000
+#define MXR_CFG                                0x0004
+#define MXR_INT_EN                     0x0008
+#define MXR_INT_STATUS                 0x000C
+#define MXR_LAYER_CFG                  0x0010
+#define MXR_VIDEO_CFG                  0x0014
+#define MXR_GRAPHIC0_CFG               0x0020
+#define MXR_GRAPHIC0_BASE              0x0024
+#define MXR_GRAPHIC0_SPAN              0x0028
+#define MXR_GRAPHIC0_SXY               0x002C
+#define MXR_GRAPHIC0_WH                        0x0030
+#define MXR_GRAPHIC0_DXY               0x0034
+#define MXR_GRAPHIC0_BLANK             0x0038
+#define MXR_GRAPHIC1_CFG               0x0040
+#define MXR_GRAPHIC1_BASE              0x0044
+#define MXR_GRAPHIC1_SPAN              0x0048
+#define MXR_GRAPHIC1_SXY               0x004C
+#define MXR_GRAPHIC1_WH                        0x0050
+#define MXR_GRAPHIC1_DXY               0x0054
+#define MXR_GRAPHIC1_BLANK             0x0058
+#define MXR_BG_CFG                     0x0060
+#define MXR_BG_COLOR0                  0x0064
+#define MXR_BG_COLOR1                  0x0068
+#define MXR_BG_COLOR2                  0x006C
+#define MXR_CM_COEFF_Y                 0x0080
+#define MXR_CM_COEFF_CB                        0x0084
+#define MXR_CM_COEFF_CR                        0x0088
+/* after EXYNOS5250 for video layer transfered from Gscaler */
+#define MXR_VIDEO_LT                   0x0090
+#define MXR_VIDEO_RB                   0x0094
+
+/* after EXYNOS4212 for setting 3D */
+#define MXR_TVOUT_CFG                  0x0100
+#define MXR_3D_ACTIVE_VIDEO            0x0104
+#define MXR_3D_ACTIVE_SPACE            0x0108
+
+/* after EXYNOS5250, support 2 sub-mixers */
+#define MXR1_LAYER_CFG                 0x0110
+#define MXR1_VIDEO_CFG                 0x0114
+#define MXR1_GRAPHIC0_CFG              0x0120
+#define MXR1_GRAPHIC0_BASE             0x0124
+#define MXR1_GRAPHIC0_SPAN             0x0128
+#define MXR1_GRAPHIC0_SXY              0x012C
+#define MXR1_GRAPHIC0_WH               0x0130
+#define MXR1_GRAPHIC0_DXY              0x0134
+#define MXR1_GRAPHIC0_BLANK            0x0138
+#define MXR1_GRAPHIC1_CFG              0x0140
+#define MXR1_GRAPHIC1_BASE             0x0144
+#define MXR1_GRAPHIC1_SPAN             0x0148
+#define MXR1_GRAPHIC1_SXY              0x014C
+#define MXR1_GRAPHIC1_WH               0x0150
+#define MXR1_GRAPHIC1_DXY              0x0154
+#define MXR1_GRAPHIC1_BLANK            0x0158
+#define MXR1_BG_CFG                    0x0160
+#define MXR1_BG_COLOR0                 0x0164
+#define MXR1_BG_COLOR1                 0x0168
+#define MXR1_BG_COLOR2                 0x016C
+#define MXR1_CM_COEFF_Y                        0x0180
+#define MXR1_CM_COEFF_CB               0x0184
+#define MXR1_CM_COEFF_CR               0x0188
+/* after EXYNOS5250 for video layer transfered from Gscaler */
+#define MXR1_VIDEO_LT                  0x0190
+#define MXR1_VIDEO_RB                  0x0194
+
+/* for parametrized access to layer registers */
+#define MXR_GRAPHIC_CFG(i)             (0x0020 + (i) * 0x20)
+#define MXR_GRAPHIC_BASE(i)            (0x0024 + (i) * 0x20)
+#define MXR_GRAPHIC_SPAN(i)            (0x0028 + (i) * 0x20)
+#define MXR_GRAPHIC_SXY(i)             (0x002C + (i) * 0x20)
+#define MXR_GRAPHIC_WH(i)              (0x0030 + (i) * 0x20)
+#define MXR_GRAPHIC_DXY(i)             (0x0034 + (i) * 0x20)
+#define MXR_GRAPHIC_BLANK(i)           (0x0038 + (i) * 0x20)
+
+/* after EXYNOS5250, support 2 sub-mixers */
+#define MXR1_GRAPHIC_CFG(i)            (0x0120 + (i) * 0x20)
+#define MXR1_GRAPHIC_BASE(i)           (0x0124 + (i) * 0x20)
+#define MXR1_GRAPHIC_SPAN(i)           (0x0128 + (i) * 0x20)
+#define MXR1_GRAPHIC_SXY(i)            (0x012C + (i) * 0x20)
+#define MXR1_GRAPHIC_WH(i)             (0x0130 + (i) * 0x20)
+#define MXR1_GRAPHIC_DXY(i)            (0x0134 + (i) * 0x20)
+#define MXR1_GRAPHIC_BLANK(i)          (0x0138 + (i) * 0x20)
+
+/*
+ * Bit definition part
+ */
+
+/* generates mask for range of bits */
+#define MXR_MASK(high_bit, low_bit) \
+       (((2 << ((high_bit) - (low_bit))) - 1) << (low_bit))
+
+#define MXR_MASK_VAL(val, high_bit, low_bit) \
+       (((val) << (low_bit)) & MXR_MASK(high_bit, low_bit))
+
+/* bits for MXR_STATUS */
+#define MXR_STATUS_SOFT_RESET          (1 << 8)
+#define MXR_STATUS_16_BURST            (1 << 7)
+#define MXR_STATUS_BURST_MASK          (1 << 7)
+#define MXR_STATUS_LAYER_SYNC          (1 << 6)
+#define MXR_STATUS_SYNC_ENABLE         (1 << 2)
+#define MXR_STATUS_REG_RUN             (1 << 0)
+
+/* bits for MXR_CFG */
+#define MXR_CFG_LAYER_UPDATE            (1 << 31)
+#define MXR_CFG_LAYER_UPDATE_COUNTER    (3 << 29)
+#define MXR_CFG_MX1_GRP1_ENABLE                (1 << 15)
+#define MXR_CFG_MX1_GRP0_ENABLE                (1 << 14)
+#define MXR_CFG_MX1_VIDEO_ENABLE       (1 << 13)
+#define MXR_CFG_OUT_YUV444             (0 << 8)
+#define MXR_CFG_OUT_RGB888             (1 << 8)
+#define MXR_CFG_OUT_MASK               (1 << 8)
+#define MXR_CFG_DST_SDO                        (0 << 7)
+#define MXR_CFG_DST_HDMI               (1 << 7)
+#define MXR_CFG_DST_MASK               (1 << 7)
+#define MXR_CFG_SCAN_HD_720            (0 << 6)
+#define MXR_CFG_SCAN_HD_1080           (1 << 6)
+#define MXR_CFG_GRP1_ENABLE            (1 << 5)
+#define MXR_CFG_GRP0_ENABLE            (1 << 4)
+#define MXR_CFG_VIDEO_ENABLE           (1 << 3)
+#define MXR_CFG_SCAN_INTERLACE         (0 << 2)
+#define MXR_CFG_SCAN_PROGRASSIVE       (1 << 2)
+#define MXR_CFG_SCAN_NTSC              (0 << 1)
+#define MXR_CFG_SCAN_PAL               (1 << 1)
+#define MXR_CFG_SCAN_SD                        (0 << 0)
+#define MXR_CFG_SCAN_HD                        (1 << 0)
+#define MXR_CFG_SCAN_MASK              0x47
+
+/* bits for MXR_GRAPHICn_CFG */
+#define MXR_GRP_CFG_BLANK_KEY_OFF      (1 << 21)
+#define MXR_GRP_CFG_LAYER_BLEND_EN     (1 << 17)
+#define MXR_GRP_CFG_PIXEL_BLEND_EN     (1 << 16)
+#define MXR_GRP_CFG_FORMAT_VAL(x)      MXR_MASK_VAL(x, 11, 8)
+#define MXR_GRP_CFG_FORMAT_MASK                MXR_GRP_CFG_FORMAT_VAL(~0)
+#define MXR_GRP_CFG_ALPHA_VAL(x)       MXR_MASK_VAL(x, 7, 0)
+
+/* bits for MXR_GRAPHICn_WH */
+#define MXR_GRP_WH_H_SCALE(x)          MXR_MASK_VAL(x, 28, 28)
+#define MXR_GRP_WH_V_SCALE(x)          MXR_MASK_VAL(x, 12, 12)
+#define MXR_GRP_WH_WIDTH(x)            MXR_MASK_VAL(x, 26, 16)
+#define MXR_GRP_WH_HEIGHT(x)           MXR_MASK_VAL(x, 10, 0)
+
+/* bits for MXR_GRAPHICn_SXY */
+#define MXR_GRP_SXY_SX(x)              MXR_MASK_VAL(x, 26, 16)
+#define MXR_GRP_SXY_SY(x)              MXR_MASK_VAL(x, 10, 0)
+
+/* bits for MXR_GRAPHICn_DXY */
+#define MXR_GRP_DXY_DX(x)              MXR_MASK_VAL(x, 26, 16)
+#define MXR_GRP_DXY_DY(x)              MXR_MASK_VAL(x, 10, 0)
+
+/* bits for MXR_INT_EN */
+#define MXR_INT_EN_VSYNC               (1 << 11)
+#define MXR_INT_EN_ALL                 (0x38b80)
+
+/* bit for MXR_INT_STATUS */
+#define MXR_INT_STATUS_MX1_GRP1                (1 << 17)
+#define MXR_INT_STATUS_MX1_GRP0                (1 << 16)
+#define MXR_INT_STATUS_MX1_VIDEO       (1 << 15)
+#define MXR_INT_CLEAR_VSYNC            (1 << 11)
+#define MXR_INT_STATUS_MX0_GRP1                (1 << 9)
+#define MXR_INT_STATUS_MX0_GRP0                (1 << 8)
+#define MXR_INT_STATUS_MX0_VIDEO       (1 << 7)
+#define MXR_INT_STATUS_VSYNC           (1 << 0)
+
+/* bit for MXR_LAYER_CFG */
+#define MXR_LAYER_CFG_GRP1_VAL(x)      MXR_MASK_VAL(x, 11, 8)
+#define MXR_LAYER_CFG_GRP0_VAL(x)      MXR_MASK_VAL(x, 7, 4)
+#define MXR_LAYER_CFG_VP_VAL(x)                MXR_MASK_VAL(x, 3, 0)
+
+/* bit for MXR_VIDEO_CFG */
+#define MXR_VIDEO_CFG_BLEND_EN         (1 << 16)
+#define MXR_VIDEO_CFG_ALPHA(x)         MXR_MASK_VAL(x, 7, 0)
+
+/* bit for MXR_VIDEO_LT */
+#define MXR_VIDEO_LT_LEFT_VAL(x)       MXR_MASK_VAL(x, 31, 16)
+#define MXR_VIDEO_LT_TOP_VAL(x)                MXR_MASK_VAL(x, 15, 0)
+
+/* bit for MXR_VIDEO_RB */
+#define MXR_VIDEO_RB_RIGHT_VAL(x)      MXR_MASK_VAL(x, 31, 16)
+#define MXR_VIDEO_RB_BOTTOM_VAL(x)     MXR_MASK_VAL(x, 15, 0)
+
+/* bit for MXR_TVOUT_CFG */
+#define MXR_TVOUT_CFG_3D_FROMAT_VAL(x) MXR_MASK_VAL(x, 5, 4)
+#define MXR_TVOUT_CFG_PATH_MIXER0      (0 << 3)
+#define MXR_TVOUT_CFG_PATH_MIXER1      (1 << 3)
+#define MXR_TVOUT_CFG_ONE_PATH         (1 << 2)
+#define MXR_TVOUT_CFG_TWO_PATH         (0 << 2)
+#define MXR_TVOUT_CFG_PATH_MASK                (3 << 2)
+#define MXR_TVOUT_CFG_STEREO_SCOPIC    (1 << 0)
+
+#endif /* SAMSUNG_REGS_MIXER_H */
diff --git a/drivers/media/video/exynos/tv/regs-sdo.h b/drivers/media/video/exynos/tv/regs-sdo.h
new file mode 100644 (file)
index 0000000..7f7c2b8
--- /dev/null
@@ -0,0 +1,63 @@
+/* drivers/media/video/s5p-tv/regs-sdo.h
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * SDO register description file
+ *
+ * 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.
+ */
+
+#ifndef SAMSUNG_REGS_SDO_H
+#define SAMSUNG_REGS_SDO_H
+
+/*
+ * Register part
+ */
+
+#define SDO_CLKCON                     0x0000
+#define SDO_CONFIG                     0x0008
+#define SDO_VBI                                0x0014
+#define SDO_DAC                                0x003C
+#define SDO_CCCON                      0x0180
+#define SDO_IRQ                                0x0280
+#define SDO_IRQMASK                    0x0284
+#define SDO_VERSION                    0x03D8
+
+/*
+ * Bit definition part
+ */
+
+/* SDO Clock Control Register (SDO_CLKCON) */
+#define SDO_TVOUT_SW_RESET             (1 << 4)
+#define SDO_TVOUT_CLOCK_READY          (1 << 1)
+#define SDO_TVOUT_CLOCK_ON             (1 << 0)
+
+/* SDO Video Standard Configuration Register (SDO_CONFIG) */
+#define SDO_PROGRESSIVE                        (1 << 4)
+#define SDO_NTSC_M                     0
+#define SDO_PAL_M                      1
+#define SDO_PAL_BGHID                  2
+#define SDO_PAL_N                      3
+#define SDO_PAL_NC                     4
+#define SDO_NTSC_443                   8
+#define SDO_PAL_60                     9
+#define SDO_STANDARD_MASK              0xf
+
+/* SDO VBI Configuration Register (SDO_VBI) */
+#define SDO_CVBS_WSS_INS               (1 << 14)
+#define SDO_CVBS_CLOSED_CAPTION_MASK   (3 << 12)
+
+/* SDO DAC Configuration Register (SDO_DAC) */
+#define SDO_POWER_ON_DAC               (1 << 0)
+
+/* SDO Color Compensation On/Off Control (SDO_CCCON) */
+#define SDO_COMPENSATION_BHS_ADJ_OFF   (1 << 4)
+#define SDO_COMPENSATION_CVBS_COMP_OFF (1 << 0)
+
+/* SDO Interrupt Request Register (SDO_IRQ) */
+#define SDO_VSYNC_IRQ_PEND             (1 << 0)
+
+#endif /* SAMSUNG_REGS_SDO_H */
diff --git a/drivers/media/video/exynos/tv/regs-vp.h b/drivers/media/video/exynos/tv/regs-vp.h
new file mode 100644 (file)
index 0000000..6c63984
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * Video processor register header file for Samsung Mixer driver
+ *
+ * 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.
+ */
+
+#ifndef SAMSUNG_REGS_VP_H
+#define SAMSUNG_REGS_VP_H
+
+/*
+ * Register part
+ */
+
+#define VP_ENABLE                      0x0000
+#define VP_SRESET                      0x0004
+#define VP_SHADOW_UPDATE               0x0008
+#define VP_FIELD_ID                    0x000C
+#define VP_MODE                                0x0010
+#define VP_IMG_SIZE_Y                  0x0014
+#define VP_IMG_SIZE_C                  0x0018
+#define VP_PER_RATE_CTRL               0x001C
+#define VP_TOP_Y_PTR                   0x0028
+#define VP_BOT_Y_PTR                   0x002C
+#define VP_TOP_C_PTR                   0x0030
+#define VP_BOT_C_PTR                   0x0034
+#define VP_ENDIAN_MODE                 0x03CC
+#define VP_SRC_H_POSITION              0x0044
+#define VP_SRC_V_POSITION              0x0048
+#define VP_SRC_WIDTH                   0x004C
+#define VP_SRC_HEIGHT                  0x0050
+#define VP_DST_H_POSITION              0x0054
+#define VP_DST_V_POSITION              0x0058
+#define VP_DST_WIDTH                   0x005C
+#define VP_DST_HEIGHT                  0x0060
+#define VP_H_RATIO                     0x0064
+#define VP_V_RATIO                     0x0068
+#define VP_POLY8_Y0_LL                 0x006C
+#define VP_POLY4_Y0_LL                 0x00EC
+#define VP_POLY4_C0_LL                 0x012C
+
+/*
+ * Bit definition part
+ */
+
+/* generates mask for range of bits */
+
+#define VP_MASK(high_bit, low_bit) \
+       (((2 << ((high_bit) - (low_bit))) - 1) << (low_bit))
+
+#define VP_MASK_VAL(val, high_bit, low_bit) \
+       (((val) << (low_bit)) & VP_MASK(high_bit, low_bit))
+
+ /* VP_ENABLE */
+#define VP_ENABLE_ON                   (1 << 0)
+
+/* VP_SRESET */
+#define VP_SRESET_PROCESSING           (1 << 0)
+
+/* VP_SHADOW_UPDATE */
+#define VP_SHADOW_UPDATE_ENABLE                (1 << 0)
+
+/* VP_MODE */
+#define VP_MODE_NV12                   (0 << 6)
+#define VP_MODE_NV21                   (1 << 6)
+#define VP_MODE_LINE_SKIP              (1 << 5)
+#define VP_MODE_MEM_LINEAR             (0 << 4)
+#define VP_MODE_MEM_TILED              (1 << 4)
+#define VP_MODE_FMT_MASK               (5 << 4)
+#define VP_MODE_FIELD_ID_AUTO_TOGGLING (1 << 2)
+#define VP_MODE_2D_IPC                 (1 << 1)
+
+/* VP_IMG_SIZE_Y */
+/* VP_IMG_SIZE_C */
+#define VP_IMG_HSIZE(x)                        VP_MASK_VAL(x, 29, 16)
+#define VP_IMG_VSIZE(x)                        VP_MASK_VAL(x, 13, 0)
+
+/* VP_SRC_H_POSITION */
+#define VP_SRC_H_POSITION_VAL(x)       VP_MASK_VAL(x, 14, 4)
+
+/* VP_ENDIAN_MODE */
+#define VP_ENDIAN_MODE_LITTLE          (1 << 0)
+
+#endif /* SAMSUNG_REGS_VP_H */
diff --git a/drivers/media/video/exynos/tv/sdo_drv.c b/drivers/media/video/exynos/tv/sdo_drv.c
new file mode 100644 (file)
index 0000000..c2975db
--- /dev/null
@@ -0,0 +1,540 @@
+/*
+ * Samsung Standard Definition Output (SDO) driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.com>
+ *
+ * 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 Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+#include <media/v4l2-subdev.h>
+#include <media/exynos_mc.h>
+
+#include "regs-sdo.h"
+
+MODULE_AUTHOR("Tomasz Stanislawski, <t.stanislaws@samsung.com>");
+MODULE_DESCRIPTION("Samsung Standard Definition Output (SDO)");
+MODULE_LICENSE("GPL");
+
+/* SDO pad definitions */
+#define SDO_PAD_SINK           0
+#define SDO_PADS_NUM           1
+
+#define SDO_DEFAULT_STD        V4L2_STD_PAL
+
+struct sdo_format {
+       v4l2_std_id id;
+       /* all modes are 720 pixels wide */
+       unsigned int height;
+       unsigned int cookie;
+};
+
+struct sdo_device {
+       /** pointer to device parent */
+       struct device *dev;
+       /** base address of SDO registers */
+       void __iomem *regs;
+       /** SDO interrupt */
+       unsigned int irq;
+       /** DAC source clock */
+       struct clk *sclk_dac;
+       /** DAC clock */
+       struct clk *dac;
+       /** DAC physical interface */
+       struct clk *dacphy;
+       /** clock for control of VPLL */
+       struct clk *fout_vpll;
+       /** regulator for SDO IP power */
+       struct regulator *vdac;
+       /** regulator for SDO plug detection */
+       struct regulator *vdet;
+       /** subdev used as device interface */
+       struct v4l2_subdev sd;
+       /** sink pad connected to mixer */
+       struct media_pad pad;
+       /** current format */
+       const struct sdo_format *fmt;
+};
+
+static inline struct sdo_device *sd_to_sdev(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct sdo_device, sd);
+}
+
+static inline
+void sdo_write_mask(struct sdo_device *sdev, u32 reg_id, u32 value, u32 mask)
+{
+       u32 old = readl(sdev->regs + reg_id);
+       value = (value & mask) | (old & ~mask);
+       writel(value, sdev->regs + reg_id);
+}
+
+static inline
+void sdo_write(struct sdo_device *sdev, u32 reg_id, u32 value)
+{
+       writel(value, sdev->regs + reg_id);
+}
+
+static inline
+u32 sdo_read(struct sdo_device *sdev, u32 reg_id)
+{
+       return readl(sdev->regs + reg_id);
+}
+
+static irqreturn_t sdo_irq_handler(int irq, void *dev_data)
+{
+       struct sdo_device *sdev = dev_data;
+
+       /* clear interrupt */
+       sdo_write_mask(sdev, SDO_IRQ, ~0, SDO_VSYNC_IRQ_PEND);
+       return IRQ_HANDLED;
+}
+
+static void sdo_reg_debug(struct sdo_device *sdev)
+{
+#define DBGREG(reg_id) \
+       dev_info(sdev->dev, #reg_id " = %08x\n", \
+               sdo_read(sdev, reg_id))
+
+       DBGREG(SDO_CLKCON);
+       DBGREG(SDO_CONFIG);
+       DBGREG(SDO_VBI);
+       DBGREG(SDO_DAC);
+       DBGREG(SDO_IRQ);
+       DBGREG(SDO_IRQMASK);
+       DBGREG(SDO_VERSION);
+}
+
+static const struct sdo_format sdo_format[] = {
+       { V4L2_STD_PAL_N,       .height = 576, .cookie = SDO_PAL_N },
+       { V4L2_STD_PAL_Nc,      .height = 576, .cookie = SDO_PAL_NC },
+       { V4L2_STD_PAL_M,       .height = 480, .cookie = SDO_PAL_M },
+       { V4L2_STD_PAL_60,      .height = 480, .cookie = SDO_PAL_60 },
+       { V4L2_STD_NTSC_443,    .height = 480, .cookie = SDO_NTSC_443 },
+       { V4L2_STD_PAL,         .height = 576, .cookie = SDO_PAL_BGHID },
+       { V4L2_STD_NTSC_M,      .height = 480, .cookie = SDO_NTSC_M },
+};
+
+static const struct sdo_format *sdo_find_format(v4l2_std_id id)
+{
+       int i;
+       for (i = 0; i < ARRAY_SIZE(sdo_format); ++i)
+               if (sdo_format[i].id & id)
+                       return &sdo_format[i];
+       return NULL;
+}
+
+static int sdo_g_tvnorms_output(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+       *std = V4L2_STD_NTSC_M | V4L2_STD_PAL_M | V4L2_STD_PAL |
+               V4L2_STD_PAL_N | V4L2_STD_PAL_Nc |
+               V4L2_STD_NTSC_443 | V4L2_STD_PAL_60;
+       return 0;
+}
+
+static int sdo_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+       struct sdo_device *sdev = sd_to_sdev(sd);
+       const struct sdo_format *fmt;
+       fmt = sdo_find_format(std);
+       if (fmt == NULL)
+               return -EINVAL;
+       sdev->fmt = fmt;
+       return 0;
+}
+
+static int sdo_g_std_output(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+       *std = sd_to_sdev(sd)->fmt->id;
+       return 0;
+}
+
+static int sdo_g_mbus_fmt(struct v4l2_subdev *sd,
+       struct v4l2_mbus_framefmt *fmt)
+{
+       struct sdo_device *sdev = sd_to_sdev(sd);
+
+       if (!sdev->fmt)
+               return -ENXIO;
+       /* all modes are 720 pixels wide */
+       fmt->width = 720;
+       fmt->height = sdev->fmt->height;
+       fmt->code = V4L2_MBUS_FMT_FIXED;
+       fmt->field = V4L2_FIELD_INTERLACED;
+       return 0;
+}
+
+static int sdo_s_power(struct v4l2_subdev *sd, int on)
+{
+       struct sdo_device *sdev = sd_to_sdev(sd);
+       struct device *dev = sdev->dev;
+       int ret;
+
+       dev_info(dev, "sdo_s_power(%d)\n", on);
+
+       if (on)
+               ret = pm_runtime_get_sync(dev);
+       else
+               ret = pm_runtime_put_sync(dev);
+
+       /* only values < 0 indicate errors */
+       return IS_ERR_VALUE(ret) ? ret : 0;
+}
+
+static int sdo_streamon(struct sdo_device *sdev)
+{
+       /* set proper clock for Timing Generator */
+       clk_set_rate(sdev->fout_vpll, 54000000);
+       dev_info(sdev->dev, "fout_vpll.rate = %lu\n",
+       clk_get_rate(sdev->fout_vpll));
+       /* enable clock in SDO */
+       sdo_write_mask(sdev, SDO_CLKCON, ~0, SDO_TVOUT_CLOCK_ON);
+       clk_enable(sdev->dacphy);
+       /* enable DAC */
+       sdo_write_mask(sdev, SDO_DAC, ~0, SDO_POWER_ON_DAC);
+       sdo_reg_debug(sdev);
+       return 0;
+}
+
+static int sdo_streamoff(struct sdo_device *sdev)
+{
+       int tries;
+
+       sdo_write_mask(sdev, SDO_DAC, 0, SDO_POWER_ON_DAC);
+       clk_disable(sdev->dacphy);
+       sdo_write_mask(sdev, SDO_CLKCON, 0, SDO_TVOUT_CLOCK_ON);
+       for (tries = 100; tries; --tries) {
+               if (sdo_read(sdev, SDO_CLKCON) & SDO_TVOUT_CLOCK_READY)
+                       break;
+               mdelay(1);
+       }
+       if (tries == 0)
+               dev_err(sdev->dev, "failed to stop streaming\n");
+       return tries ? 0 : -EIO;
+}
+
+static int sdo_s_stream(struct v4l2_subdev *sd, int on)
+{
+       struct sdo_device *sdev = sd_to_sdev(sd);
+       return on ? sdo_streamon(sdev) : sdo_streamoff(sdev);
+}
+
+static const struct v4l2_subdev_core_ops sdo_sd_core_ops = {
+       .s_power = sdo_s_power,
+};
+
+static const struct v4l2_subdev_video_ops sdo_sd_video_ops = {
+       .s_std_output = sdo_s_std_output,
+       .g_std_output = sdo_g_std_output,
+       .g_tvnorms_output = sdo_g_tvnorms_output,
+       .g_mbus_fmt = sdo_g_mbus_fmt,
+       .s_stream = sdo_s_stream,
+};
+
+static const struct v4l2_subdev_ops sdo_sd_ops = {
+       .core = &sdo_sd_core_ops,
+       .video = &sdo_sd_video_ops,
+};
+
+static int sdo_runtime_suspend(struct device *dev)
+{
+       struct v4l2_subdev *sd = dev_get_drvdata(dev);
+       struct sdo_device *sdev = sd_to_sdev(sd);
+
+       dev_info(dev, "suspend\n");
+       regulator_disable(sdev->vdet);
+       regulator_disable(sdev->vdac);
+       clk_disable(sdev->sclk_dac);
+       return 0;
+}
+
+static int sdo_runtime_resume(struct device *dev)
+{
+       struct v4l2_subdev *sd = dev_get_drvdata(dev);
+       struct sdo_device *sdev = sd_to_sdev(sd);
+
+       dev_info(dev, "resume\n");
+       clk_enable(sdev->sclk_dac);
+       regulator_enable(sdev->vdac);
+       regulator_enable(sdev->vdet);
+
+       /* software reset */
+       sdo_write_mask(sdev, SDO_CLKCON, ~0, SDO_TVOUT_SW_RESET);
+       mdelay(10);
+       sdo_write_mask(sdev, SDO_CLKCON, 0, SDO_TVOUT_SW_RESET);
+
+       /* setting TV mode */
+       sdo_write_mask(sdev, SDO_CONFIG, sdev->fmt->cookie, SDO_STANDARD_MASK);
+       /* XXX: forcing interlaced mode using undocumented bit */
+       sdo_write_mask(sdev, SDO_CONFIG, 0, SDO_PROGRESSIVE);
+       /* turn all VBI off */
+       sdo_write_mask(sdev, SDO_VBI, 0, SDO_CVBS_WSS_INS |
+               SDO_CVBS_CLOSED_CAPTION_MASK);
+       /* turn all post processing off */
+       sdo_write_mask(sdev, SDO_CCCON, ~0, SDO_COMPENSATION_BHS_ADJ_OFF |
+               SDO_COMPENSATION_CVBS_COMP_OFF);
+       sdo_reg_debug(sdev);
+       return 0;
+}
+
+static const struct dev_pm_ops sdo_pm_ops = {
+       .runtime_suspend = sdo_runtime_suspend,
+       .runtime_resume  = sdo_runtime_resume,
+};
+
+static int sdo_link_setup(struct media_entity *entity,
+                             const struct media_pad *local,
+                             const struct media_pad *remote, u32 flags)
+{
+       return 0;
+}
+
+/* sdo entity operations */
+static const struct media_entity_operations sdo_entity_ops = {
+       .link_setup = sdo_link_setup,
+};
+
+static int sdo_register_entity(struct sdo_device *sdev)
+{
+       struct v4l2_subdev *sd = &sdev->sd;
+       struct v4l2_device *v4l2_dev;
+       struct media_pad *pads = &sdev->pad;
+       struct media_entity *me = &sd->entity;
+       struct device *dev = sdev->dev;
+       struct exynos_md *md;
+       int ret;
+
+       dev_dbg(dev, "SDO entity init\n");
+
+       /* init sdo subdev */
+       v4l2_subdev_init(sd, &sdo_sd_ops);
+       sd->owner = THIS_MODULE;
+       strlcpy(sd->name, "s5p-sdo", sizeof(sd->name));
+
+       dev_set_drvdata(dev, sd);
+
+       /* init sdo sub-device as entity */
+       pads[SDO_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+       me->ops = &sdo_entity_ops;
+       ret = media_entity_init(me, SDO_PADS_NUM, pads, 0);
+       if (ret) {
+               dev_err(dev, "failed to initialize media entity\n");
+               return ret;
+       }
+
+       /* get output media ptr for registering sdo's sd */
+       md = (struct exynos_md *)module_name_to_driver_data(MDEV_MODULE_NAME);
+       if (!md) {
+               dev_err(dev, "failed to get output media device\n");
+               return -ENODEV;
+       }
+
+       v4l2_dev = &md->v4l2_dev;
+
+       /* regiser SDO subdev as entity to v4l2_dev pointer of
+        * output media device
+        */
+       ret = v4l2_device_register_subdev(v4l2_dev, sd);
+       if (ret) {
+               dev_err(dev, "failed to register SDO subdev\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static void sdo_entity_info_print(struct sdo_device *sdev)
+{
+       struct v4l2_subdev *sd = &sdev->sd;
+       struct media_entity *me = &sd->entity;
+
+       dev_dbg(sdev->dev, "\n************** SDO entity info **************\n");
+       dev_dbg(sdev->dev, "[SUB DEVICE INFO]\n");
+       entity_info_print(me, sdev->dev);
+       dev_dbg(sdev->dev, "*********************************************\n\n");
+}
+
+static int __devinit sdo_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct sdo_device *sdev;
+       struct resource *res;
+       int ret = 0;
+       struct clk *sclk_vpll;
+
+       dev_info(dev, "probe start\n");
+       sdev = kzalloc(sizeof *sdev, GFP_KERNEL);
+       if (!sdev) {
+               dev_err(dev, "not enough memory.\n");
+               ret = -ENOMEM;
+               goto fail;
+       }
+       sdev->dev = dev;
+
+       /* mapping registers */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               dev_err(dev, "get memory resource failed.\n");
+               ret = -ENXIO;
+               goto fail_sdev;
+       }
+
+       sdev->regs = ioremap(res->start, resource_size(res));
+       if (sdev->regs == NULL) {
+               dev_err(dev, "register mapping failed.\n");
+               ret = -ENXIO;
+               goto fail_sdev;
+       }
+
+       /* acquiring interrupt */
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (res == NULL) {
+               dev_err(dev, "get interrupt resource failed.\n");
+               ret = -ENXIO;
+               goto fail_regs;
+       }
+       ret = request_irq(res->start, sdo_irq_handler, 0, "s5p-sdo", sdev);
+       if (ret) {
+               dev_err(dev, "request interrupt failed.\n");
+               goto fail_regs;
+       }
+       sdev->irq = res->start;
+
+       /* acquire clocks */
+       sdev->sclk_dac = clk_get(dev, "sclk_dac");
+       if (IS_ERR_OR_NULL(sdev->sclk_dac)) {
+               dev_err(dev, "failed to get clock 'sclk_dac'\n");
+               ret = -ENXIO;
+               goto fail_irq;
+       }
+       sdev->dac = clk_get(dev, "dac");
+       if (IS_ERR_OR_NULL(sdev->dac)) {
+               dev_err(dev, "failed to get clock 'dac'\n");
+               ret = -ENXIO;
+               goto fail_sclk_dac;
+       }
+       sdev->dacphy = clk_get(dev, "dacphy");
+       if (IS_ERR_OR_NULL(sdev->dacphy)) {
+               dev_err(dev, "failed to get clock 'dacphy'\n");
+               ret = -ENXIO;
+               goto fail_dac;
+       }
+       sclk_vpll = clk_get(dev, "sclk_vpll");
+       if (IS_ERR_OR_NULL(sclk_vpll)) {
+               dev_err(dev, "failed to get clock 'sclk_vpll'\n");
+               ret = -ENXIO;
+               goto fail_dacphy;
+       }
+       clk_set_parent(sdev->sclk_dac, sclk_vpll);
+       clk_put(sclk_vpll);
+       sdev->fout_vpll = clk_get(dev, "fout_vpll");
+       if (IS_ERR_OR_NULL(sdev->fout_vpll)) {
+               dev_err(dev, "failed to get clock 'fout_vpll'\n");
+               goto fail_dacphy;
+       }
+       dev_info(dev, "fout_vpll.rate = %lu\n", clk_get_rate(sclk_vpll));
+
+       /* enable gate for dac clock, because mixer uses it */
+       clk_enable(sdev->dac);
+
+       /* configure power management */
+       pm_runtime_enable(dev);
+
+       /* set default format */
+       sdev->fmt = sdo_find_format(SDO_DEFAULT_STD);
+       BUG_ON(sdev->fmt == NULL);
+
+       ret = sdo_register_entity(sdev);
+       if (ret)
+               goto fail_dacphy;
+
+       sdo_entity_info_print(sdev);
+
+       dev_info(dev, "probe succeeded\n");
+       return 0;
+
+fail_dacphy:
+       clk_put(sdev->dacphy);
+fail_dac:
+       clk_put(sdev->dac);
+fail_sclk_dac:
+       clk_put(sdev->sclk_dac);
+fail_irq:
+       free_irq(sdev->irq, sdev);
+fail_regs:
+       iounmap(sdev->regs);
+fail_sdev:
+       kfree(sdev);
+fail:
+       dev_info(dev, "probe failed\n");
+       return ret;
+}
+
+static int __devexit sdo_remove(struct platform_device *pdev)
+{
+       struct v4l2_subdev *sd = dev_get_drvdata(&pdev->dev);
+       struct sdo_device *sdev = sd_to_sdev(sd);
+
+       pm_runtime_disable(&pdev->dev);
+       clk_disable(sdev->dac);
+       regulator_put(sdev->vdet);
+       regulator_put(sdev->vdac);
+       clk_put(sdev->fout_vpll);
+       clk_put(sdev->dacphy);
+       clk_put(sdev->dac);
+       clk_put(sdev->sclk_dac);
+       free_irq(sdev->irq, sdev);
+       iounmap(sdev->regs);
+       kfree(sdev);
+
+       dev_info(&pdev->dev, "remove successful\n");
+       return 0;
+}
+
+static struct platform_driver sdo_driver __refdata = {
+       .probe = sdo_probe,
+       .remove = __devexit_p(sdo_remove),
+       .driver = {
+               .name = "s5p-sdo",
+               .owner = THIS_MODULE,
+               .pm = &sdo_pm_ops,
+       }
+};
+
+static int __init sdo_init(void)
+{
+       int ret;
+       static const char banner[] __initdata = KERN_INFO \
+               "Samsung Standard Definition Output (SDO) driver, "
+               "(c) 2010-2011 Samsung Electronics Co., Ltd.\n";
+       printk(banner);
+
+       ret = platform_driver_register(&sdo_driver);
+       if (ret)
+               printk(KERN_ERR "SDO platform driver register failed\n");
+
+       return ret;
+}
+module_init(sdo_init);
+
+static void __exit sdo_exit(void)
+{
+       platform_driver_unregister(&sdo_driver);
+}
+module_exit(sdo_exit);