Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5)

Unified Diff: drivers/media/video/samsung/tv20/hdmi_s5pv210.c

Issue 2036011: V4L/DVB : Add S5PV210 TV out driver support (Closed) Base URL: swsolcc@12.23.106.100:kernel-samsung.git
Patch Set: Created 10 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « drivers/media/video/samsung/tv20/hdmi_param.h ('k') | drivers/media/video/samsung/tv20/hpd.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: drivers/media/video/samsung/tv20/hdmi_s5pv210.c
diff --git a/drivers/media/video/samsung/tv20/hdmi_s5pv210.c b/drivers/media/video/samsung/tv20/hdmi_s5pv210.c
new file mode 100644
index 0000000000000000000000000000000000000000..42efb72fc28236fdacc2068bfa5b55268d4a416f
--- /dev/null
+++ b/drivers/media/video/samsung/tv20/hdmi_s5pv210.c
@@ -0,0 +1,1994 @@
+/* linux/drivers/media/video/samsung/tv20/hdmi_s5pv210.c
+*
+* Copyright (c) 2010 Samsung Electronics Co., Ltd.
+* http://www.samsung.com/
+*
+* S5PV210 - hdmi raw 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/module.h>
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+
+#include <plat/clock.h>
+#include <linux/io.h>
+
+#include "tv_out_s5pv210.h"
+
+#include <mach/regs-hdmi.h>
+
+#include <mach/regs-clock.h>
+
+#include "hdmi_param.h"
+
+#ifdef CONFIG_TVOUT_RAW_DBG
+#define S5P_HDMI_DEBUG 1
+#endif
+
+#ifdef S5P_HDMI_DEBUG
+#define HDMIPRINTK(fmt, args...) \
+ printk(KERN_INFO "\t\t[HDMI] %s: " fmt, __func__ , ## args)
+#else
+#define HDMIPRINTK(fmt, args...)
+#endif
+
+static struct resource *hdmi_mem;
+void __iomem *hdmi_base;
+
+static struct resource *i2c_hdmi_phy_mem;
+void __iomem *i2c_hdmi_phy_base;
+
+
+spinlock_t lock_hdmi;
+
+/*
+ * i2c_hdmi_phy related
+ */
+
+#define PHY_I2C_ADDRESS 0x70
+
+#define I2C_ACK (1<<7)
+#define I2C_INT (1<<5)
+#define I2C_PEND (1<<4)
+
+#define I2C_INT_CLEAR (0<<4)
+
+#define I2C_CLK (0x41)
+#define I2C_CLK_PEND_INT (I2C_CLK|I2C_INT_CLEAR|I2C_INT)
+
+#define I2C_ENABLE (1<<4)
+#define I2C_START (1<<5)
+
+#define I2C_MODE_MTX 0xC0
+#define I2C_MODE_MRX 0x80
+
+#define I2C_IDLE 0
+
+static struct {
+ s32 state;
+ u8 *buffer;
+ s32 bytes;
+} i2c_hdmi_phy_context;
+
+enum i2c_hdmi_phy_state {
+ STATE_IDLE,
+ STATE_TX_EDDC_SEGADDR,
+ STATE_TX_EDDC_SEGNUM,
+ STATE_TX_DDC_ADDR,
+ STATE_TX_DDC_OFFSET,
+ STATE_RX_DDC_ADDR,
+ STATE_RX_DDC_DATA,
+ STATE_RX_ADDR,
+ STATE_RX_DATA,
+ STATE_TX_ADDR,
+ STATE_TX_DATA,
+ STATE_TX_STOP,
+ STATE_RX_STOP
+};
+
+static s32 i2c_hdmi_phy_interruptwait(void)
+{
+ u8 status, reg;
+ s32 retval = 0;
+
+ do {
+ status = readb(i2c_hdmi_phy_base + I2C_HDMI_CON);
+
+ if (status & I2C_PEND) {
+ /* check status flags */
+ reg = readb(i2c_hdmi_phy_base + I2C_HDMI_STAT);
+ break;
+ }
+
+ } while (1);
+
+ return retval;
+}
+
+s32 i2c_hdmi_phy_read(u8 addr, u8 nbytes, u8 *buffer)
+{
+ u8 reg;
+ s32 ret = 0;
+ u32 i, proc = true;
+
+ i2c_hdmi_phy_context.state = STATE_RX_ADDR;
+
+ i2c_hdmi_phy_context.buffer = buffer;
+ i2c_hdmi_phy_context.bytes = nbytes;
+
+ writeb(I2C_CLK | I2C_INT | I2C_ACK,
+ i2c_hdmi_phy_base + I2C_HDMI_CON);
+ writeb(I2C_ENABLE | I2C_MODE_MRX,
+ i2c_hdmi_phy_base + I2C_HDMI_STAT);
+ writeb(addr & 0xFE,
+ i2c_hdmi_phy_base + I2C_HDMI_DS);
+
+ writeb(I2C_ENABLE | I2C_START | I2C_MODE_MRX,
+ i2c_hdmi_phy_base + I2C_HDMI_STAT);
+
+ while (proc) {
+
+ if (i2c_hdmi_phy_context.state != STATE_RX_STOP) {
+ if (i2c_hdmi_phy_interruptwait() != 0) {
+ HDMIPRINTK("interrupt wait failed!!!\n");
+ ret = EINVAL;
+ break;
+ }
+
+ }
+
+ switch (i2c_hdmi_phy_context.state) {
+
+ case STATE_RX_DATA:
+
+ reg = readb(i2c_hdmi_phy_base + I2C_HDMI_DS);
+ *(i2c_hdmi_phy_context.buffer) = reg;
+
+ i2c_hdmi_phy_context.buffer++;
+ --(i2c_hdmi_phy_context.bytes);
+
+ if (i2c_hdmi_phy_context.bytes == 1) {
+ i2c_hdmi_phy_context.state = STATE_RX_STOP;
+ writeb(I2C_CLK_PEND_INT,
+ i2c_hdmi_phy_base + I2C_HDMI_CON);
+ } else {
+ writeb(I2C_CLK_PEND_INT | I2C_ACK,
+ i2c_hdmi_phy_base + I2C_HDMI_CON);
+
+ }
+ break;
+
+ case STATE_RX_ADDR:
+ i2c_hdmi_phy_context.state = STATE_RX_DATA;
+
+ if (i2c_hdmi_phy_context.bytes == 1) {
+ i2c_hdmi_phy_context.state = STATE_RX_STOP;
+ writeb(I2C_CLK_PEND_INT,
+ i2c_hdmi_phy_base + I2C_HDMI_CON);
+ } else {
+ writeb(I2C_CLK_PEND_INT | I2C_ACK,
+ i2c_hdmi_phy_base + I2C_HDMI_CON);
+ }
+
+ break;
+
+ case STATE_RX_STOP:
+
+ i2c_hdmi_phy_context.state = STATE_IDLE;
+
+ for (i = 0 ; i < 10000 ; i++)
+ ;
+ reg = readb(i2c_hdmi_phy_base + I2C_HDMI_DS);
+
+ *(i2c_hdmi_phy_context.buffer) = reg;
+
+ writeb(I2C_MODE_MRX|I2C_ENABLE,
+ i2c_hdmi_phy_base + I2C_HDMI_STAT);
+
+ writeb(I2C_CLK_PEND_INT,
+ i2c_hdmi_phy_base + I2C_HDMI_CON);
+
+ writeb(I2C_MODE_MRX, i2c_hdmi_phy_base + I2C_HDMI_STAT);
+
+ while (readb(i2c_hdmi_phy_base + I2C_HDMI_STAT) &
+ (1<<5))
+ ;
+ proc = false;
+
+ break;
+
+ case STATE_IDLE:
+
+ default:
+ HDMIPRINTK("error state!!!\n");
+
+ ret = EINVAL;
+
+ proc = false;
+
+ break;
+ }
+ }
+
+ return ret;
+}
+
+s32 i2c_hdmi_phy_write(u8 addr, u8 nbytes, u8 *buffer)
+{
+ u8 reg;
+ s32 ret = 0;
+ u32 proc = true;
+
+ i2c_hdmi_phy_context.state = STATE_TX_ADDR;
+
+ i2c_hdmi_phy_context.buffer = buffer;
+ i2c_hdmi_phy_context.bytes = nbytes;
+
+ writeb(I2C_CLK | I2C_INT | I2C_ACK,
+ i2c_hdmi_phy_base + I2C_HDMI_CON);
+ writeb(I2C_ENABLE | I2C_MODE_MTX,
+ i2c_hdmi_phy_base + I2C_HDMI_STAT);
+ writeb(addr & 0xFE,
+ i2c_hdmi_phy_base + I2C_HDMI_DS);
+ writeb(I2C_ENABLE | I2C_START | I2C_MODE_MTX,
+ i2c_hdmi_phy_base + I2C_HDMI_STAT);
+
+ while (proc) {
+
+ if (i2c_hdmi_phy_interruptwait() != 0) {
+ HDMIPRINTK("interrupt wait failed!!!\n");
+ ret = EINVAL;
+ break;
+ }
+
+
+ switch (i2c_hdmi_phy_context.state) {
+
+ case STATE_TX_ADDR:
+ case STATE_TX_DATA:
+ i2c_hdmi_phy_context.state = STATE_TX_DATA;
+
+ reg = *(i2c_hdmi_phy_context.buffer);
+
+ writeb(reg, i2c_hdmi_phy_base + I2C_HDMI_DS);
+
+ i2c_hdmi_phy_context.buffer++;
+ --(i2c_hdmi_phy_context.bytes);
+
+ if (i2c_hdmi_phy_context.bytes == 0) {
+ i2c_hdmi_phy_context.state = STATE_TX_STOP;
+ writeb(I2C_CLK_PEND_INT,
+ i2c_hdmi_phy_base + I2C_HDMI_CON);
+ } else
+ writeb(I2C_CLK_PEND_INT | I2C_ACK,
+ i2c_hdmi_phy_base + I2C_HDMI_CON);
+ break;
+
+ case STATE_TX_STOP:
+ i2c_hdmi_phy_context.state = STATE_IDLE;
+
+ writeb(I2C_MODE_MTX | I2C_ENABLE,
+ i2c_hdmi_phy_base + I2C_HDMI_STAT);
+
+ writeb(I2C_CLK_PEND_INT,
+ i2c_hdmi_phy_base + I2C_HDMI_CON);
+
+ writeb(I2C_MODE_MTX, i2c_hdmi_phy_base + I2C_HDMI_STAT);
+
+ while (readb(i2c_hdmi_phy_base +
+ I2C_HDMI_STAT) & (1<<5))
+ ;
+
+ proc = false;
+
+ break;
+
+ case STATE_IDLE:
+ default:
+ HDMIPRINTK("error state!!!\n");
+
+ ret = EINVAL;
+
+ proc = false;
+
+ break;
+ }
+ }
+
+ return ret;
+}
+
+int hdmi_phy_down(bool on, u8 addr, u8 offset, u8 *read_buffer)
+{
+ u8 buff[2] = {0};
+
+ buff[0] = addr;
+ buff[1] = (on) ? (read_buffer[addr] & (~(1<<offset))) :
+ (read_buffer[addr] | (1<<offset));
+
+ if (i2c_hdmi_phy_write(PHY_I2C_ADDRESS, 2, buff) != 0)
+ return EINVAL;
+
+ return 0;
+}
+
+
+int tv_hdmi_phy_power(bool on)
+{
+ u32 size;
+ u8 *buffer;
+ u8 read_buffer[0x40] = {0, };
+
+ size = sizeof(phy_config[0][0])
+ / sizeof(phy_config[0][0][0]);
+
+ buffer = (u8 *) phy_config[0][0];
+
+ /* write offset */
+ if (i2c_hdmi_phy_write(PHY_I2C_ADDRESS, 1, buffer) != 0)
+ return EINVAL;
+
+ /* read data */
+ if (i2c_hdmi_phy_read(PHY_I2C_ADDRESS, size, read_buffer) != 0) {
+ HDMIPRINTK("i2c_hdmi_phy_read failed.\n");
+ return EINVAL;
+ }
+
+ /* i can't get the information about phy setting */
+ if (on) {
+ /* on */
+ /* biaspd */
+ hdmi_phy_down(true, 0x1, 0x5, read_buffer);
+ /* clockgenpd */
+ hdmi_phy_down(true, 0x1, 0x7, read_buffer);
+ /* pllpd */
+ hdmi_phy_down(true, 0x5, 0x5, read_buffer);
+ /* pcgpd */
+ hdmi_phy_down(true, 0x17, 0x0, read_buffer);
+ /* txpd */
+ hdmi_phy_down(true, 0x17, 0x1, read_buffer);
+ } else {
+ /* off */
+ /* biaspd */
+ hdmi_phy_down(false, 0x1, 0x5, read_buffer);
+ /* clockgenpd */
+ hdmi_phy_down(false, 0x1, 0x7, read_buffer);
+ /* pllpd */
+ hdmi_phy_down(false, 0x5, 0x5, read_buffer);
+ /* pcgpd */
+ hdmi_phy_down(false, 0x17, 0x0, read_buffer);
+ /* txpd */
+ hdmi_phy_down(false, 0x17, 0x1, read_buffer);
+ }
+
+ return 0;
+}
+
+s32 hdmi_corereset(void)
+{
+ u32 i;
+
+ writeb(0x0, hdmi_base + S5P_HDMI_CTRL_CORE_RSTOUT);
+
+ for (i = 0 ; i < 1000 ; i++)
+ ;
+
+ writeb(0x1, hdmi_base + S5P_HDMI_CTRL_CORE_RSTOUT);
+
+ return 0;
+}
+
+s32 hdmi_phy_config(enum phy_freq freq, enum s5p_hdmi_color_depth cd)
+{
+ s32 index;
+ s32 size;
+ u8 buffer[32] = {0, };
+ u8 reg;
+
+ switch (cd) {
+
+ case HDMI_CD_24:
+ index = 0;
+ break;
+
+ case HDMI_CD_30:
+ index = 1;
+ break;
+
+ case HDMI_CD_36:
+ index = 2;
+ break;
+
+ default:
+ return false;
+ }
+
+
+ /* i2c_hdmi init - set i2c filtering */
+ buffer[0] = PHY_REG_MODE_SET_DONE;
+ buffer[1] = 0x00;
+
+ if (i2c_hdmi_phy_write(PHY_I2C_ADDRESS, 2, buffer) != 0) {
+ HDMIPRINTK("i2c_hdmi_phy_write failed.\n");
+ return EINVAL;
+ }
+
+ writeb(0x5, i2c_hdmi_phy_base + I2C_HDMI_LC);
+
+ size = sizeof(phy_config[freq][index])
+ / sizeof(phy_config[freq][index][0]);
+
+ memcpy(buffer, phy_config[freq][index], sizeof(buffer));
+
+ if (i2c_hdmi_phy_write(PHY_I2C_ADDRESS, size, buffer) != 0)
+ return EINVAL;
+
+ /* write offset */
+ buffer[0] = 0x01;
+
+ if (i2c_hdmi_phy_write(PHY_I2C_ADDRESS, 1, buffer) != 0) {
+ HDMIPRINTK("i2c_hdmi_phy_write failed.\n");
+ return EINVAL;
+ }
+
+#ifdef S5P_HDMI_DEBUG
+{
+ int i = 0;
+ u8 read_buffer[0x40] = {0, };
+
+ /* read data */
+ if (i2c_hdmi_phy_read(PHY_I2C_ADDRESS, size, read_buffer) != 0) {
+ HDMIPRINTK("i2c_hdmi_phy_read failed.\n");
+ return EINVAL;
+ }
+
+ HDMIPRINTK("read buffer :\n\t\t");
+
+ for (i = 1; i < size; i++) {
+
+
+ printk("0x%02x", read_buffer[i]);
+
+ if (i % 8)
+ printk(" ");
+ else
+ printk("\n\t\t");
+ }
+ printk("\n");
+}
+#endif
+ hdmi_corereset();
+
+ do {
+ reg = readb(hdmi_base + HDMI_PHY_STATUS);
+ } while (!(reg & HDMI_PHY_READY));
+
+ writeb(I2C_CLK_PEND_INT, i2c_hdmi_phy_base + I2C_HDMI_CON);
+ /* disable */
+ writeb(I2C_IDLE, i2c_hdmi_phy_base + I2C_HDMI_STAT);
+
+ return 0;
+}
+
+s32 hdmi_set_tg(enum s5p_hdmi_v_fmt mode)
+{
+ u16 temp_reg;
+ u8 tc_cmd;
+
+ temp_reg = hdmi_tg_param[mode].h_fsz;
+ writeb((u8)(temp_reg&0xff), hdmi_base + S5P_TG_H_FSZ_L);
+ writeb((u8)(temp_reg >> 8), hdmi_base + S5P_TG_H_FSZ_H);
+
+ /* set Horizontal Active Start Position */
+ temp_reg = hdmi_tg_param[mode].hact_st ;
+ writeb((u8)(temp_reg&0xff), hdmi_base + S5P_TG_HACT_ST_L);
+ writeb((u8)(temp_reg >> 8), hdmi_base + S5P_TG_HACT_ST_H);
+
+ /* set Horizontal Active Size */
+ temp_reg = hdmi_tg_param[mode].hact_sz ;
+ writeb((u8)(temp_reg&0xff), hdmi_base + S5P_TG_HACT_SZ_L);
+ writeb((u8)(temp_reg >> 8), hdmi_base + S5P_TG_HACT_SZ_H);
+
+ /* set Vertical Full Size */
+ temp_reg = hdmi_tg_param[mode].v_fsz ;
+ writeb((u8)(temp_reg&0xff), hdmi_base + S5P_TG_V_FSZ_L);
+ writeb((u8)(temp_reg >> 8), hdmi_base + S5P_TG_V_FSZ_H);
+
+ /* set VSYNC Position */
+ temp_reg = hdmi_tg_param[mode].vsync ;
+ writeb((u8)(temp_reg&0xff), hdmi_base + S5P_TG_VSYNC_L);
+ writeb((u8)(temp_reg >> 8), hdmi_base + S5P_TG_VSYNC_H);
+
+ /* set Bottom Field VSYNC Position */
+ temp_reg = hdmi_tg_param[mode].vsync2;
+ writeb((u8)(temp_reg&0xff), hdmi_base + S5P_TG_VSYNC2_L);
+ writeb((u8)(temp_reg >> 8), hdmi_base + S5P_TG_VSYNC2_H);
+
+ /* set Vertical Active Start Position */
+ temp_reg = hdmi_tg_param[mode].vact_st ;
+ writeb((u8)(temp_reg&0xff), hdmi_base + S5P_TG_VACT_ST_L);
+ writeb((u8)(temp_reg >> 8), hdmi_base + S5P_TG_VACT_ST_H);
+
+ /* set Vertical Active Size */
+ temp_reg = hdmi_tg_param[mode].vact_sz ;
+ writeb((u8)(temp_reg&0xff), hdmi_base + S5P_TG_VACT_SZ_L);
+ writeb((u8)(temp_reg >> 8), hdmi_base + S5P_TG_VACT_SZ_H);
+
+ /* set Field Change Position */
+ temp_reg = hdmi_tg_param[mode].field_chg ;
+ writeb((u8)(temp_reg&0xff), hdmi_base + S5P_TG_FIELD_CHG_L);
+ writeb((u8)(temp_reg >> 8), hdmi_base + S5P_TG_FIELD_CHG_H);
+
+ /* set Bottom Field Vertical Active Start Position */
+ temp_reg = hdmi_tg_param[mode].vact_st2;
+ writeb((u8)(temp_reg&0xff), hdmi_base + S5P_TG_VACT_ST2_L);
+ writeb((u8)(temp_reg >> 8), hdmi_base + S5P_TG_VACT_ST2_H);
+
+ /* set VSYNC Position for HDMI */
+ temp_reg = hdmi_tg_param[mode].vsync_top_hdmi;
+ writeb((u8)(temp_reg&0xff), hdmi_base + S5P_TG_VSYNC_TOP_HDMI_L);
+ writeb((u8)(temp_reg >> 8), hdmi_base + S5P_TG_VSYNC_TOP_HDMI_H);
+
+ /* set Bottom Field VSYNC Position */
+ temp_reg = hdmi_tg_param[mode].vsync_bot_hdmi;
+ writeb((u8)(temp_reg&0xff), hdmi_base + S5P_TG_VSYNC_BOT_HDMI_L);
+ writeb((u8)(temp_reg >> 8), hdmi_base + S5P_TG_VSYNC_BOT_HDMI_H);
+
+ /* set Top Field Change Position for HDMI */
+ temp_reg = hdmi_tg_param[mode].field_top_hdmi ;
+ writeb((u8)(temp_reg&0xff), hdmi_base + S5P_TG_FIELD_TOP_HDMI_L);
+ writeb((u8)(temp_reg >> 8), hdmi_base + S5P_TG_FIELD_TOP_HDMI_H);
+
+ /* set Bottom Field Change Position for HDMI */
+ temp_reg = hdmi_tg_param[mode].field_bot_hdmi;
+ writeb((u8)(temp_reg&0xff), hdmi_base + S5P_TG_FIELD_BOT_HDMI_L);
+ writeb((u8)(temp_reg >> 8), hdmi_base + S5P_TG_FIELD_BOT_HDMI_H);
+
+ tc_cmd = readb(hdmi_base + S5P_TG_CMD);
+
+ if (video_params[mode].interlaced == 1)
+ /* Field Mode enable(interlace mode) */
+ tc_cmd |= (1<<1);
+ else
+ /* Field Mode disable */
+ tc_cmd &= ~(1<<1);
+
+ writeb(tc_cmd, hdmi_base + S5P_TG_CMD);
+
+ return 0;
+}
+
+/**
+ * Set registers related to color depth.
+ */
+static s32 hdmi_set_clr_depth(enum s5p_hdmi_color_depth cd)
+{
+ /* if color depth is supported by RX, set GCP packet */
+ switch (cd) {
+
+ case HDMI_CD_48:
+ writeb(GCP_CD_48BPP, hdmi_base + S5P_GCP_BYTE2);
+ break;
+
+ case HDMI_CD_36:
+ writeb(GCP_CD_36BPP, hdmi_base + S5P_GCP_BYTE2);
+ /* set DC register */
+ writeb(HDMI_DC_CTL_12, hdmi_base + S5P_HDMI_DC_CONTROL);
+ break;
+
+ case HDMI_CD_30:
+ writeb(GCP_CD_30BPP, hdmi_base + S5P_GCP_BYTE2);
+ /* set DC register */
+ writeb(HDMI_DC_CTL_10, hdmi_base + S5P_HDMI_DC_CONTROL);
+ break;
+
+ case HDMI_CD_24:
+ writeb(GCP_CD_24BPP, hdmi_base + S5P_GCP_BYTE2);
+ /* set DC register */
+ writeb(HDMI_DC_CTL_8, hdmi_base + S5P_HDMI_DC_CONTROL);
+ /* disable GCP */
+ writeb(DO_NOT_TRANSMIT, hdmi_base + S5P_GCP_CON);
+ break;
+
+ default:
+ HDMIPRINTK(
+ "HDMI core does not support requested Deep Color mode\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+s32 hdmi_set_video_mode(enum s5p_hdmi_v_fmt mode, enum s5p_hdmi_color_depth cd,
+ enum s5p_tv_hdmi_pxl_aspect pxl_ratio)
+{
+ u8 temp_reg8;
+ u16 temp_reg16;
+ u32 temp_reg32, temp_sync2, temp_sync3;
+
+ /* check if HDMI code support that mode */
+ if (mode > (sizeof(video_params)/sizeof(struct hdmi_v_params)) ||
+ (s32)mode < 0) {
+ HDMIPRINTK("This video mode is not Supported\n");
+ return -EINVAL;
+ }
+
+ hdmi_set_tg(mode);
+
+ /* set HBlank */
+ temp_reg16 = video_params[mode].h_blank;
+ writeb((u8)(temp_reg16&0xff), hdmi_base + S5P_H_BLANK_0);
+ writeb((u8)(temp_reg16 >> 8), hdmi_base + S5P_H_BLANK_1);
+
+ /* set VBlank */
+ temp_reg32 = video_params[mode].v_blank;
+ writeb((u8)(temp_reg32&0xff), hdmi_base + S5P_V_BLANK_0);
+ writeb((u8)(temp_reg32 >> 8), hdmi_base + S5P_V_BLANK_1);
+ writeb((u8)(temp_reg32 >> 16), hdmi_base + S5P_V_BLANK_2);
+
+ /* set HVLine */
+ temp_reg32 = video_params[mode].hvline;
+ writeb((u8)(temp_reg32&0xff), hdmi_base + S5P_H_V_LINE_0);
+ writeb((u8)(temp_reg32 >> 8), hdmi_base + S5P_H_V_LINE_1);
+ writeb((u8)(temp_reg32 >> 16), hdmi_base + S5P_H_V_LINE_2);
+
+ /* set VSYNC polarity */
+ writeb(video_params[mode].polarity, hdmi_base + S5P_SYNC_MODE);
+
+ /* set HSyncGen */
+ temp_reg32 = video_params[mode].h_sync_gen;
+ writeb((u8)(temp_reg32&0xff), hdmi_base + S5P_H_SYNC_GEN_0);
+ writeb((u8)(temp_reg32 >> 8), hdmi_base + S5P_H_SYNC_GEN_1);
+ writeb((u8)(temp_reg32 >> 16), hdmi_base + S5P_H_SYNC_GEN_2);
+
+ /* set VSyncGen1 */
+ temp_reg32 = video_params[mode].v_sync_gen;
+ writeb((u8)(temp_reg32&0xff), hdmi_base + S5P_V_SYNC_GEN_1_0);
+ writeb((u8)(temp_reg32 >> 8), hdmi_base + S5P_V_SYNC_GEN_1_1);
+ writeb((u8)(temp_reg32 >> 16), hdmi_base + S5P_V_SYNC_GEN_1_2);
+
+ if (video_params[mode].interlaced) {
+ /* set up v_blank_f, v_sync_gen2, v_sync_gen3 */
+ temp_reg32 = video_params[mode].v_blank_f;
+ temp_sync2 = video_params[mode].v_sync_gen2;
+ temp_sync3 = video_params[mode].v_sync_gen3;
+
+ writeb((u8)(temp_reg32 & 0xff), hdmi_base + S5P_V_BLANK_F_0);
+ writeb((u8)(temp_reg32 >> 8), hdmi_base + S5P_V_BLANK_F_1);
+ writeb((u8)(temp_reg32 >> 16), hdmi_base + S5P_V_BLANK_F_2);
+
+ writeb((u8)(temp_sync2 & 0xff), hdmi_base + S5P_V_SYNC_GEN_2_0);
+ writeb((u8)(temp_sync2 >> 8), hdmi_base + S5P_V_SYNC_GEN_2_1);
+ writeb((u8)(temp_sync2 >> 16), hdmi_base + S5P_V_SYNC_GEN_2_2);
+
+ writeb((u8)(temp_sync3 & 0xff), hdmi_base + S5P_V_SYNC_GEN_3_0);
+ writeb((u8)(temp_sync3 >> 8), hdmi_base + S5P_V_SYNC_GEN_3_1);
+ writeb((u8)(temp_sync3 >> 16), hdmi_base + S5P_V_SYNC_GEN_3_2);
+ } else {
+ /* progressive mode */
+ writeb(0x00, hdmi_base + S5P_V_BLANK_F_0);
+ writeb(0x00, hdmi_base + S5P_V_BLANK_F_1);
+ writeb(0x00, hdmi_base + S5P_V_BLANK_F_2);
+
+ writeb(0x01, hdmi_base + S5P_V_SYNC_GEN_2_0);
+ writeb(0x10, hdmi_base + S5P_V_SYNC_GEN_2_1);
+ writeb(0x00, hdmi_base + S5P_V_SYNC_GEN_2_2);
+
+ writeb(0x01, hdmi_base + S5P_V_SYNC_GEN_3_0);
+ writeb(0x10, hdmi_base + S5P_V_SYNC_GEN_3_1);
+ writeb(0x00, hdmi_base + S5P_V_SYNC_GEN_3_2);
+ }
+
+ /* set interlaced mode */
+ writeb(video_params[mode].interlaced, hdmi_base + S5P_INT_PRO_MODE);
+
+ /* pixel repetition */
+ temp_reg8 = readb(hdmi_base + S5P_HDMI_CON_1);
+
+ /* clear */
+ temp_reg8 &= ~HDMI_CON_PXL_REP_RATIO_MASK;
+
+ if (video_params[mode].repetition) {
+ /* set pixel repetition */
+ temp_reg8 |= HDMI_DOUBLE_PIXEL_REPETITION;
+ /* AVI Packet */
+ writeb(AVI_PIXEL_REPETITION_DOUBLE, hdmi_base + S5P_AVI_BYTE5);
+ } else/* clear pixel repetition */
+ writeb(0x00, hdmi_base + S5P_AVI_BYTE5); /* AVI Packet */
+
+ /* set pixel repetition */
+ writeb(temp_reg8, hdmi_base + S5P_HDMI_CON_1);
+
+ /* set AVI packet VIC */
+ if (pxl_ratio == HDMI_PIXEL_RATIO_16_9)
+ writeb(video_params[mode].avi_vic_16_9,
+ hdmi_base + S5P_AVI_BYTE4);
+ else
+ writeb(video_params[mode].avi_vic,
+ hdmi_base + S5P_AVI_BYTE4);
+
+ /* clear */
+ temp_reg8 = readb(hdmi_base + S5P_AVI_BYTE2) &
+ ~(AVI_PICTURE_ASPECT_4_3 | AVI_PICTURE_ASPECT_16_9);
+
+ if (pxl_ratio == HDMI_PIXEL_RATIO_16_9)
+ temp_reg8 |= AVI_PICTURE_ASPECT_16_9;
+ else
+ temp_reg8 |= AVI_PICTURE_ASPECT_4_3;
+
+ /* set AVI packet MM */
+ writeb(temp_reg8, hdmi_base + S5P_AVI_BYTE2);
+
+ /* set color depth */
+ if (hdmi_set_clr_depth(cd) != 0) {
+ HDMIPRINTK("[ERR] Can't set hdmi clr. depth.\n");
+ return -EINVAL;
+ }
+
+ if (video_params[mode].interlaced == 1) {
+ u32 gcp_con;
+
+ gcp_con = readb(hdmi_base + S5P_GCP_CON);
+ gcp_con |= (3<<2);
+
+ writeb(gcp_con, hdmi_base + S5P_GCP_CON);
+ } else {
+ u32 gcp_con;
+
+ gcp_con = readb(hdmi_base + S5P_GCP_CON);
+ gcp_con &= (~(3<<2));
+
+ writeb(gcp_con, hdmi_base + S5P_GCP_CON);
+ }
+
+ return 0;
+}
+
+
+void tv_hdmi_set_hpd_onoff(bool on_off)
+{
+ HDMIPRINTK("hpd is %s\n\r", on_off ? "on" : "off");
+
+ if (on_off)
+ writel(SW_HPD_PLUGGED, hdmi_base + S5P_HPD);
+ else
+ writel(SW_HPD_UNPLUGGED, hdmi_base + S5P_HPD);
+
+ HDMIPRINTK("0x%08x\n\r", readl(hdmi_base + S5P_HPD));
+}
+
+
+void tv_hdmi_audio_set_config(enum s5p_tv_audio_codec_type audio_codec)
+{
+
+ u32 data_type = (audio_codec == PCM) ? CONFIG_LINEAR_PCM_TYPE :
+ (audio_codec == AC3) ?
+ CONFIG_NON_LINEAR_PCM_TYPE : 0xff;
+
+ HDMIPRINTK("audio codec type = %s\n\r",
+ (audio_codec&PCM) ? "PCM" :
+ (audio_codec&AC3) ? "AC3" :
+ (audio_codec&MP3) ? "MP3" :
+ (audio_codec&WMA) ? "WMA" : "Unknown");
+
+ /* open SPDIF path on HDMI_I2S */
+ writel(0x01, hdmi_base + S5P_HDMI_I2S_CLK_CON);
+ writel(readl(hdmi_base + S5P_HDMI_I2S_MUX_CON) | 0x11,
+ hdmi_base + S5P_HDMI_I2S_MUX_CON);
+ writel(0xFF, hdmi_base + S5P_HDMI_I2S_MUX_CH);
+ writel(0x03, hdmi_base + S5P_HDMI_I2S_MUX_CUV);
+
+ writel(CONFIG_FILTER_2_SAMPLE | data_type
+ | CONFIG_PCPD_MANUAL_SET | CONFIG_WORD_LENGTH_MANUAL_SET
+ | CONFIG_U_V_C_P_REPORT | CONFIG_BURST_SIZE_2
+ | CONFIG_DATA_ALIGN_32BIT
+ , hdmi_base + S5P_SPDIFIN_CONFIG_1);
+ writel(0, hdmi_base + S5P_SPDIFIN_CONFIG_2);
+}
+
+void tv_hdmi_audio_set_acr(u32 sample_rate)
+{
+ u32 value_n = (sample_rate == 32000) ? 4096 :
+ (sample_rate == 44100) ? 6272 :
+ (sample_rate == 88200) ? 12544 :
+ (sample_rate == 176400) ? 25088 :
+ (sample_rate == 48000) ? 6144 :
+ (sample_rate == 96000) ? 12288 :
+ (sample_rate == 192000) ? 24576 : 0;
+
+ u32 cts = (sample_rate == 32000) ? 27000 :
+ (sample_rate == 44100) ? 30000 :
+ (sample_rate == 88200) ? 30000 :
+ (sample_rate == 176400) ? 30000 :
+ (sample_rate == 48000) ? 27000 :
+ (sample_rate == 96000) ? 27000 :
+ (sample_rate == 192000) ? 27000 : 0;
+
+ HDMIPRINTK("sample rate = %d\n\r", sample_rate);
+ HDMIPRINTK("cts = %d\n\r", cts);
+
+ writel(value_n & 0xff, hdmi_base + S5P_ACR_N0);
+ writel((value_n >> 8) & 0xff, hdmi_base + S5P_ACR_N1);
+ writel((value_n >> 16) & 0xff, hdmi_base + S5P_ACR_N2);
+
+ writel(cts & 0xff, hdmi_base + S5P_ACR_MCTS0);
+ writel((cts >> 8) & 0xff, hdmi_base + S5P_ACR_MCTS1);
+ writel((cts >> 16) & 0xff, hdmi_base + S5P_ACR_MCTS2);
+
+ writel(cts & 0xff, hdmi_base + S5P_ACR_CTS0);
+ writel((cts >> 8) & 0xff, hdmi_base + S5P_ACR_CTS1);
+ writel((cts >> 16) & 0xff, hdmi_base + S5P_ACR_CTS2);
+
+ writel(4, hdmi_base + S5P_ACR_CON); /* TO-DO : what it is? */
+}
+
+void tv_hdmi_audio_set_asp(void)
+{
+ writel(0x0, hdmi_base + S5P_ASP_CON);
+ /* All Subpackets contain audio samples */
+ writel(0x0, hdmi_base + S5P_ASP_SP_FLAT);
+
+ writel(1 << 3 | 0, hdmi_base + S5P_ASP_CHCFG0);
+ writel(1 << 3 | 0, hdmi_base + S5P_ASP_CHCFG1);
+ writel(1 << 3 | 0, hdmi_base + S5P_ASP_CHCFG2);
+ writel(1 << 3 | 0, hdmi_base + S5P_ASP_CHCFG3);
+}
+
+void tv_hdmi_audio_clock_enable(void)
+{
+ writel(0x1, hdmi_base + S5P_SPDIFIN_CLK_CTRL);
+ /* HDMI operation mode */
+ writel(0x3, hdmi_base + S5P_SPDIFIN_OP_CTRL);
+}
+
+
+void tv_hdmi_audio_set_repetition_time(enum s5p_tv_audio_codec_type audio_codec,
+ u32 bits, u32 frame_size_code)
+{
+ /* Only 4'b1011 24bit */
+ u32 wl = 5 << 1 | 1;
+ u32 rpt_cnt = (audio_codec == AC3) ? 1536 * 2 - 1 : 0;
+
+ HDMIPRINTK("repetition count = %d\n\r", rpt_cnt);
+
+ /* 24bit and manual mode */
+ writel(((rpt_cnt&0xf) << 4) | wl, hdmi_base + S5P_SPDIFIN_USER_VALUE_1);
+ /* if PCM this value is 0 */
+ writel((rpt_cnt >> 4)&0xff, hdmi_base + S5P_SPDIFIN_USER_VALUE_2);
+ /* if PCM this value is 0 */
+ writel(frame_size_code&0xff, hdmi_base + S5P_SPDIFIN_USER_VALUE_3);
+ /* if PCM this value is 0 */
+ writel((frame_size_code >> 8)&0xff,
+ hdmi_base + S5P_SPDIFIN_USER_VALUE_4);
+}
+
+void tv_hdmi_audio_irq_enable(u32 irq_en)
+{
+ writel(irq_en, hdmi_base + S5P_SPDIFIN_IRQ_MASK);
+}
+
+
+void tv_hdmi_audio_set_aui(enum s5p_tv_audio_codec_type audio_codec,
+ u32 sample_rate,
+ u32 bits)
+{
+ u8 sum_of_bits, bytes1, bytes2, bytes3, check_sum;
+ u32 bit_rate;
+ /* Ac3 16bit only */
+ u32 bps = (audio_codec == PCM) ? bits : 16;
+
+ /* AUI Packet set. */
+ u32 type = (audio_codec == PCM) ? 1 : /* PCM */
+ (audio_codec == AC3) ? 2 : 0;
+ /* AC3 or Refer stream header */
+ u32 ch = (audio_codec == PCM) ? 1 : 0;
+ /* 2ch or refer to stream header */
+
+ u32 sample = (sample_rate == 32000) ? 1 :
+ (sample_rate == 44100) ? 2 :
+ (sample_rate == 48000) ? 3 :
+ (sample_rate == 88200) ? 4 :
+ (sample_rate == 96000) ? 5 :
+ (sample_rate == 176400) ? 6 :
+ (sample_rate == 192000) ? 7 : 0;
+
+ u32 bpsType = (bps == 16) ? 1 :
+ (bps == 20) ? 2 :
+ (bps == 24) ? 3 : 0;
+
+
+ bpsType = (audio_codec == PCM) ? bpsType : 0;
+
+ sum_of_bits = (0x84 + 0x1 + 10); /* header */
+
+ bytes1 = (u8)((type << 4) | ch);
+
+ bytes2 = (u8)((sample << 2) | bpsType);
+
+ bit_rate = 256; /* AC3 Test */
+
+ bytes3 = (audio_codec == PCM) ? (u8)0 : (u8)(bit_rate / 8) ;
+
+
+ sum_of_bits += (bytes1 + bytes2 + bytes3);
+ check_sum = 256 - sum_of_bits;
+
+ /* AUI Packet set. */
+ writel(check_sum , hdmi_base + S5P_AUI_CHECK_SUM);
+ writel(bytes1 , hdmi_base + S5P_AUI_BYTE1);
+ writel(bytes2 , hdmi_base + S5P_AUI_BYTE2);
+ writel(bytes3 , hdmi_base + S5P_AUI_BYTE3); /* Pcm or stream */
+ writel(0x00 , hdmi_base + S5P_AUI_BYTE4); /* 2ch pcm or Stream */
+ writel(0x00 , hdmi_base + S5P_AUI_BYTE5); /* 2ch pcm or Stream */
+
+
+ writel(2 , hdmi_base + S5P_ACP_CON);
+ writel(1 , hdmi_base + S5P_ACP_TYPE);
+
+ writel(0x10 , hdmi_base + S5P_GCP_BYTE1);
+
+}
+
+void tv_hdmi_video_set_bluescreen(bool en,
+ u8 cb_b,
+ u8 y_g,
+ u8 cr_r)
+{
+ HDMIPRINTK("%d,%d,%d,%d\n\r", en, cb_b, y_g, cr_r);
+
+ if (en) {
+ writel(SET_BLUESCREEN_0(cb_b), hdmi_base + S5P_BLUE_SCREEN_0);
+ writel(SET_BLUESCREEN_1(y_g), hdmi_base + S5P_BLUE_SCREEN_1);
+ writel(SET_BLUESCREEN_2(cr_r), hdmi_base + S5P_BLUE_SCREEN_2);
+ writel(readl(hdmi_base + S5P_HDMI_CON_0) | BLUE_SCR_EN,
+ hdmi_base + S5P_HDMI_CON_0);
+
+ HDMIPRINTK("HDMI_BLUE_SCREEN0 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_BLUE_SCREEN_0));
+ HDMIPRINTK("HDMI_BLUE_SCREEN1 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_BLUE_SCREEN_1));
+ HDMIPRINTK("HDMI_BLUE_SCREEN2 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_BLUE_SCREEN_2));
+ } else {
+ writel(readl(hdmi_base + S5P_HDMI_CON_0)&~BLUE_SCR_EN,
+ hdmi_base + S5P_HDMI_CON_0);
+ }
+
+ HDMIPRINTK("HDMI_CON0 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_HDMI_CON_0));
+}
+
+
+enum s5p_tv_hdmi_err tv_hdmi_init_spd_infoframe(
+ enum s5p_hdmi_transmit trans_type,
+ u8 *spd_header,
+ u8 *spd_data)
+{
+ HDMIPRINTK("%d,%d,%d\n\r", (u32)trans_type,
+ (u32)spd_header,
+ (u32)spd_data);
+
+ switch (trans_type) {
+
+ case HDMI_DO_NOT_TANS:
+ writel(SPD_TX_CON_NO_TRANS, hdmi_base + S5P_SPD_CON);
+ break;
+
+ case HDMI_TRANS_ONCE:
+ writel(SPD_TX_CON_TRANS_ONCE, hdmi_base + S5P_SPD_CON);
+ break;
+
+ case HDMI_TRANS_EVERY_SYNC:
+ writel(SPD_TX_CON_TRANS_EVERY_VSYNC, hdmi_base + S5P_SPD_CON);
+ break;
+
+ default:
+ HDMIPRINTK(" invalid out_mode parameter(%d)\n\r", trans_type);
+ return S5P_TV_HDMI_ERR_INVALID_PARAM;
+ }
+
+ writel(SET_SPD_HEADER(*(spd_header)), hdmi_base + S5P_SPD_HEADER0);
+
+ writel(SET_SPD_HEADER(*(spd_header + 1)) , hdmi_base + S5P_SPD_HEADER1);
+ writel(SET_SPD_HEADER(*(spd_header + 2)) , hdmi_base + S5P_SPD_HEADER2);
+
+ writel(SET_SPD_DATA(*(spd_data)), hdmi_base + S5P_SPD_DATA0);
+ writel(SET_SPD_DATA(*(spd_data + 1)) , hdmi_base + S5P_SPD_DATA1);
+ writel(SET_SPD_DATA(*(spd_data + 2)) , hdmi_base + S5P_SPD_DATA2);
+ writel(SET_SPD_DATA(*(spd_data + 3)) , hdmi_base + S5P_SPD_DATA3);
+ writel(SET_SPD_DATA(*(spd_data + 4)) , hdmi_base + S5P_SPD_DATA4);
+ writel(SET_SPD_DATA(*(spd_data + 5)) , hdmi_base + S5P_SPD_DATA5);
+ writel(SET_SPD_DATA(*(spd_data + 6)) , hdmi_base + S5P_SPD_DATA6);
+ writel(SET_SPD_DATA(*(spd_data + 7)) , hdmi_base + S5P_SPD_DATA7);
+ writel(SET_SPD_DATA(*(spd_data + 8)) , hdmi_base + S5P_SPD_DATA8);
+ writel(SET_SPD_DATA(*(spd_data + 9)) , hdmi_base + S5P_SPD_DATA9);
+ writel(SET_SPD_DATA(*(spd_data + 10)) , hdmi_base + S5P_SPD_DATA10);
+ writel(SET_SPD_DATA(*(spd_data + 11)) , hdmi_base + S5P_SPD_DATA11);
+ writel(SET_SPD_DATA(*(spd_data + 12)) , hdmi_base + S5P_SPD_DATA12);
+ writel(SET_SPD_DATA(*(spd_data + 13)) , hdmi_base + S5P_SPD_DATA13);
+ writel(SET_SPD_DATA(*(spd_data + 14)) , hdmi_base + S5P_SPD_DATA14);
+ writel(SET_SPD_DATA(*(spd_data + 15)) , hdmi_base + S5P_SPD_DATA15);
+ writel(SET_SPD_DATA(*(spd_data + 16)) , hdmi_base + S5P_SPD_DATA16);
+ writel(SET_SPD_DATA(*(spd_data + 17)) , hdmi_base + S5P_SPD_DATA17);
+ writel(SET_SPD_DATA(*(spd_data + 18)) , hdmi_base + S5P_SPD_DATA18);
+ writel(SET_SPD_DATA(*(spd_data + 19)) , hdmi_base + S5P_SPD_DATA19);
+ writel(SET_SPD_DATA(*(spd_data + 20)) , hdmi_base + S5P_SPD_DATA20);
+ writel(SET_SPD_DATA(*(spd_data + 21)) , hdmi_base + S5P_SPD_DATA21);
+ writel(SET_SPD_DATA(*(spd_data + 22)) , hdmi_base + S5P_SPD_DATA22);
+ writel(SET_SPD_DATA(*(spd_data + 23)) , hdmi_base + S5P_SPD_DATA23);
+ writel(SET_SPD_DATA(*(spd_data + 24)) , hdmi_base + S5P_SPD_DATA24);
+ writel(SET_SPD_DATA(*(spd_data + 25)) , hdmi_base + S5P_SPD_DATA25);
+ writel(SET_SPD_DATA(*(spd_data + 26)) , hdmi_base + S5P_SPD_DATA26);
+ writel(SET_SPD_DATA(*(spd_data + 27)) , hdmi_base + S5P_SPD_DATA27);
+
+ HDMIPRINTK("SPD_CON = 0x%08x \n\r",
+ readl(hdmi_base + S5P_SPD_CON));
+ HDMIPRINTK("SPD_HEADER0 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_SPD_HEADER0));
+ HDMIPRINTK("SPD_HEADER1 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_SPD_HEADER1));
+ HDMIPRINTK("SPD_HEADER2 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_SPD_HEADER2));
+ HDMIPRINTK("SPD_DATA0 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_SPD_DATA0));
+ HDMIPRINTK("SPD_DATA1 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_SPD_DATA1));
+ HDMIPRINTK("SPD_DATA2 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_SPD_DATA2));
+ HDMIPRINTK("SPD_DATA3 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_SPD_DATA3));
+ HDMIPRINTK("SPD_DATA4 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_SPD_DATA4));
+ HDMIPRINTK("SPD_DATA5 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_SPD_DATA5));
+ HDMIPRINTK("SPD_DATA6 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_SPD_DATA6));
+ HDMIPRINTK("SPD_DATA7 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_SPD_DATA7));
+ HDMIPRINTK("SPD_DATA8 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_SPD_DATA8));
+ HDMIPRINTK("SPD_DATA9 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_SPD_DATA9));
+ HDMIPRINTK("SPD_DATA10 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_SPD_DATA10));
+ HDMIPRINTK("SPD_DATA11 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_SPD_DATA11));
+ HDMIPRINTK("SPD_DATA12 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_SPD_DATA12));
+ HDMIPRINTK("SPD_DATA13 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_SPD_DATA13));
+ HDMIPRINTK("SPD_DATA14 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_SPD_DATA14));
+ HDMIPRINTK("SPD_DATA15 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_SPD_DATA15));
+ HDMIPRINTK("SPD_DATA16 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_SPD_DATA16));
+ HDMIPRINTK("SPD_DATA17 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_SPD_DATA17));
+ HDMIPRINTK("SPD_DATA18 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_SPD_DATA18));
+ HDMIPRINTK("SPD_DATA19 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_SPD_DATA19));
+ HDMIPRINTK("SPD_DATA20 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_SPD_DATA20));
+ HDMIPRINTK("SPD_DATA21 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_SPD_DATA21));
+ HDMIPRINTK("SPD_DATA22 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_SPD_DATA22));
+ HDMIPRINTK("SPD_DATA23 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_SPD_DATA23));
+ HDMIPRINTK("SPD_DATA24 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_SPD_DATA24));
+ HDMIPRINTK("SPD_DATA25 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_SPD_DATA25));
+ HDMIPRINTK("SPD_DATA26 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_SPD_DATA26));
+ HDMIPRINTK("SPD_DATA27 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_SPD_DATA27));
+
+ return HDMI_NO_ERROR;
+}
+
+void tv_hdmi_init_hpd_onoff(bool on_off)
+{
+ HDMIPRINTK("%d\n\r", on_off);
+ tv_hdmi_set_hpd_onoff(on_off);
+ HDMIPRINTK("0x%08x\n\r", readl(hdmi_base + S5P_HPD));
+}
+
+#ifndef CONFIG_SND_S5P_SPDIF
+static void tv_hdmi_audio_i2s_config(
+ enum s5p_tv_audio_codec_type audio_codec,
+ u32 sample_rate,
+ u32 bits_per_sample,
+ u32 frame_size_code)
+{
+ u32 data_num, bit_ch, sample_frq;
+
+ if (bits_per_sample == 20) {
+ data_num = 2;
+ bit_ch = 1;
+ } else if (bits_per_sample == 24) {
+ data_num = 3;
+ bit_ch = 1;
+ } else { /* bits_per_sample == 16 or default */
+ data_num = 1;
+ bit_ch = 0;
+ }
+
+ sample_frq = (sample_rate == 44100) ? 0 :
+ (sample_rate == 48000) ? 2 :
+ (sample_rate == 32000) ? 3 :
+ (sample_rate == 96000) ? 0xa : 0x0;
+
+ /* readl(hdmi_base + S5P_HDMI_YMAX) */
+ writel(0x00, hdmi_base + S5P_HDMI_I2S_CLK_CON);
+ writel(0x01, hdmi_base + S5P_HDMI_I2S_CLK_CON);
+
+ writel(readl(hdmi_base + S5P_HDMI_I2S_DSD_CON) | 0x01,
+ hdmi_base + S5P_HDMI_I2S_DSD_CON);
+
+ /* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */
+ writel((readl(hdmi_base + S5P_HDMI_I2S_PIN_SEL_0) &
+ ~(7<<4 | 7<<0)) | (5<<4|6<<0),
+ hdmi_base + S5P_HDMI_I2S_PIN_SEL_0);
+ writel((readl(hdmi_base + S5P_HDMI_I2S_PIN_SEL_1) &
+ ~(7<<4 | 7<<0)) | (1<<4|4<<0),
+ hdmi_base + S5P_HDMI_I2S_PIN_SEL_1);
+ writel((readl(hdmi_base + S5P_HDMI_I2S_PIN_SEL_2) &
+ ~(7<<4 | 7<<0)) | (1<<4|2<<0),
+ hdmi_base + S5P_HDMI_I2S_PIN_SEL_2);
+ writel((readl(hdmi_base + S5P_HDMI_I2S_PIN_SEL_3) &
+ ~(7<<0)) | (0<<0),
+ hdmi_base + S5P_HDMI_I2S_PIN_SEL_3);
+
+ /* I2S_CON_1 & 2 */
+ writel((readl(hdmi_base + S5P_HDMI_I2S_CON_1) &
+ ~(1<<1 | 1<<0)) | (1<<1|0<<0),
+ hdmi_base + S5P_HDMI_I2S_CON_1);
+ writel((readl(hdmi_base + S5P_HDMI_I2S_CON_2) &
+ ~(1<<6 | 3<<4 | 3<<2 | 3<<0))
+ | (0<<6 | bit_ch<<4 | data_num<<2 | 0<<0),
+ hdmi_base + S5P_HDMI_I2S_CON_2);
+
+ /* Configure register related to CUV information */
+ writel((readl(hdmi_base + S5P_HDMI_I2S_CH_ST_0) &
+ ~(3<<6 | 7<<3 | 1<<2 | 1<<1 | 1<<0))
+ | (0<<6 | 0<<3 | 0<<2 | 0<<1 | 1<<0),
+ hdmi_base + S5P_HDMI_I2S_CH_ST_0);
+ writel((readl(hdmi_base + S5P_HDMI_I2S_CH_ST_1) &
+ ~(0xff<<0)) | (0<<0),
+ hdmi_base + S5P_HDMI_I2S_CH_ST_1);
+ writel((readl(hdmi_base + S5P_HDMI_I2S_CH_ST_2) &
+ ~(0xff<<0)) | (0<<0),
+ hdmi_base + S5P_HDMI_I2S_CH_ST_2);
+ writel((readl(hdmi_base + S5P_HDMI_I2S_CH_ST_3) &
+ ~(3<<4 | 0xf<<0))
+ | (1<<4 | sample_frq<<0),
+ hdmi_base + S5P_HDMI_I2S_CH_ST_3);
+ writel((readl(hdmi_base + S5P_HDMI_I2S_CH_ST_4) &
+ ~(0xf<<4 | 7<<1 | 1<<0))
+ | (0xf<<4 | 5<<1 | 1<<0),
+ hdmi_base + S5P_HDMI_I2S_CH_ST_4);
+
+ writel(0x00, hdmi_base + S5P_HDMI_I2S_CH_ST_SH_0);
+ writel(0x00, hdmi_base + S5P_HDMI_I2S_CH_ST_SH_1);
+ writel(0x00, hdmi_base + S5P_HDMI_I2S_CH_ST_SH_2);
+ writel(0x02, hdmi_base + S5P_HDMI_I2S_CH_ST_SH_3);
+ writel(0x00, hdmi_base + S5P_HDMI_I2S_CH_ST_SH_4);
+
+ writel((readl(hdmi_base + S5P_HDMI_I2S_CH_ST_CON) &
+ ~(1<<0)) | (1<<0),
+ hdmi_base + S5P_HDMI_I2S_CH_ST_CON);
+
+ writel((readl(hdmi_base + S5P_HDMI_I2S_MUX_CON) &
+ ~(1<<4 | 3<<2 | 1<<1 | 1<<0))
+ | (1<<4 | 1<<2 | 1<<1 | 1<<0),
+ hdmi_base + S5P_HDMI_I2S_MUX_CON);
+
+ writel((readl(hdmi_base + S5P_HDMI_I2S_MUX_CH) &
+ ~(0xff<<0)) | (0x3f<<0),
+ hdmi_base + S5P_HDMI_I2S_MUX_CH);
+
+ writel((readl(hdmi_base + S5P_HDMI_I2S_MUX_CUV) &
+ ~(0x3<<0)) | (0x3<<0),
+ hdmi_base + S5P_HDMI_I2S_MUX_CUV);
+}
+#endif
+
+enum s5p_tv_hdmi_err tv_hdmi_audio_init(
+ enum s5p_tv_audio_codec_type audio_codec,
+ u32 sample_rate, u32 bits,
+ u32 frame_size_code)
+{
+#ifdef CONFIG_SND_S5P_SPDIF
+ tv_hdmi_audio_set_config(audio_codec);
+ tv_hdmi_audio_set_repetition_time(audio_codec, bits,
+ frame_size_code);
+ tv_hdmi_audio_irq_enable(IRQ_BUFFER_OVERFLOW_ENABLE);
+ tv_hdmi_audio_clock_enable();
+#else
+ tv_hdmi_audio_i2s_config(audio_codec, sample_rate,
+ bits, frame_size_code);
+#endif
+ tv_hdmi_audio_set_asp();
+ tv_hdmi_audio_set_acr(sample_rate);
+
+ tv_hdmi_audio_set_aui(audio_codec, sample_rate, bits);
+
+ return HDMI_NO_ERROR;
+}
+
+enum s5p_tv_hdmi_err tv_hdmi_video_init_display_mode(
+ enum s5p_tv_disp_mode disp_mode,
+ enum s5p_tv_o_mode out_mode)
+{
+ enum s5p_hdmi_v_fmt hdmi_v_fmt;
+
+ HDMIPRINTK("disp mode %d, output mode%d\n\r", disp_mode, out_mode);
+
+ switch (disp_mode) {
+ /* 480p */
+ case TVOUT_480P_60_16_9:
+ case TVOUT_480P_60_4_3:
+ hdmi_v_fmt = v720x480p_60Hz;
+ break;
+ case TVOUT_480P_59:
+ hdmi_v_fmt = v720x480p_59Hz;
+ break;
+
+ /* 576p */
+ case TVOUT_576P_50_16_9:
+ case TVOUT_576P_50_4_3:
+ hdmi_v_fmt = v720x576p_50Hz;
+ break;
+
+ /* 720p */
+ case TVOUT_720P_60:
+ hdmi_v_fmt = v1280x720p_60Hz;
+ break;
+
+ case TVOUT_720P_59:
+ hdmi_v_fmt = v1280x720p_59Hz;
+ break;
+
+ case TVOUT_720P_50:
+ hdmi_v_fmt = v1280x720p_50Hz;
+ break;
+
+ /* 1080p */
+ case TVOUT_1080P_30:
+ hdmi_v_fmt = v1920x1080p_30Hz;
+ break;
+
+ case TVOUT_1080P_60:
+ hdmi_v_fmt = v1920x1080p_60Hz;
+ break;
+
+ case TVOUT_1080P_59:
+ hdmi_v_fmt = v1920x1080p_59Hz;
+ break;
+
+ case TVOUT_1080P_50:
+ hdmi_v_fmt = v1920x1080p_50Hz;
+ break;
+
+ /* 1080i */
+ case TVOUT_1080I_60:
+ hdmi_v_fmt = v1920x1080i_60Hz;
+ break;
+
+ case TVOUT_1080I_59:
+ hdmi_v_fmt = v1920x1080i_59Hz;
+ break;
+
+ case TVOUT_1080I_50:
+ hdmi_v_fmt = v1920x1080i_50Hz;
+ break;
+
+ default:
+ HDMIPRINTK(" invalid disp_mode parameter(%d)\n\r", disp_mode);
+ return S5P_TV_HDMI_ERR_INVALID_PARAM;
+ }
+
+ if (hdmi_phy_config(video_params[hdmi_v_fmt].pixel_clock,
+ HDMI_CD_24) == EINVAL) {
+ HDMIPRINTK("[ERR] hdmi_phy_config() failed.\n");
+ return EINVAL;
+ }
+
+ switch (out_mode) {
+ case TVOUT_OUTPUT_HDMI_RGB:
+ writel(PX_LMT_CTRL_RGB, hdmi_base + S5P_HDMI_CON_1);
+ writel(VID_PREAMBLE_EN | GUARD_BAND_EN,
+ hdmi_base + S5P_HDMI_CON_2);
+ writel(HDMI_MODE_EN | DVI_MODE_DIS, hdmi_base + S5P_MODE_SEL);
+
+ /* there's no ACP packet api */
+ writel(HDMI_DO_NOT_TANS , hdmi_base + S5P_ACP_CON);
+ writel(HDMI_TRANS_EVERY_SYNC , hdmi_base + S5P_AUI_CON);
+ break;
+
+ case TVOUT_OUTPUT_HDMI:
+ writel(PX_LMT_CTRL_BYPASS, hdmi_base + S5P_HDMI_CON_1);
+ writel(VID_PREAMBLE_EN | GUARD_BAND_EN,
+ hdmi_base + S5P_HDMI_CON_2);
+ writel(HDMI_MODE_EN | DVI_MODE_DIS, hdmi_base + S5P_MODE_SEL);
+
+ /* there's no ACP packet api */
+ writel(HDMI_DO_NOT_TANS , hdmi_base + S5P_ACP_CON);
+ writel(HDMI_TRANS_EVERY_SYNC , hdmi_base + S5P_AUI_CON);
+ break;
+
+ case TVOUT_OUTPUT_DVI:
+ writel(PX_LMT_CTRL_RGB, hdmi_base + S5P_HDMI_CON_1);
+ writel(VID_PREAMBLE_DIS | GUARD_BAND_DIS,
+ hdmi_base + S5P_HDMI_CON_2);
+ writel(HDMI_MODE_DIS | DVI_MODE_EN,
+ hdmi_base + S5P_MODE_SEL);
+
+ /* disable ACP & Audio Info.frame packet */
+ writel(HDMI_DO_NOT_TANS , hdmi_base + S5P_ACP_CON);
+ writel(HDMI_DO_NOT_TANS , hdmi_base + S5P_AUI_CON);
+ break;
+
+ default:
+ HDMIPRINTK("invalid out_mode parameter(%d)\n\r", out_mode);
+ return S5P_TV_HDMI_ERR_INVALID_PARAM;
+ }
+
+ hdmi_set_video_mode(hdmi_v_fmt, HDMI_CD_24, HDMI_PIXEL_RATIO_16_9);
+
+ return HDMI_NO_ERROR;
+}
+
+void tv_hdmi_video_init_bluescreen(bool en,
+ u8 cb_b,
+ u8 y_g,
+ u8 cr_r)
+{
+ tv_hdmi_video_set_bluescreen(en, cb_b, y_g, cr_r);
+
+}
+
+void tv_hdmi_video_init_color_range(u8 y_min,
+ u8 y_max,
+ u8 c_min,
+ u8 c_max)
+{
+ HDMIPRINTK("%d,%d,%d,%d\n\r", y_max, y_min, c_max, c_min);
+
+ writel(y_max, hdmi_base + S5P_HDMI_YMAX);
+ writel(y_min, hdmi_base + S5P_HDMI_YMIN);
+ writel(c_max, hdmi_base + S5P_HDMI_CMAX);
+ writel(c_min, hdmi_base + S5P_HDMI_CMIN);
+
+ HDMIPRINTK("HDMI_YMAX = 0x%08x \n\r",
+ readl(hdmi_base + S5P_HDMI_YMAX));
+ HDMIPRINTK("HDMI_YMIN = 0x%08x \n\r",
+ readl(hdmi_base + S5P_HDMI_YMIN));
+ HDMIPRINTK("HDMI_CMAX = 0x%08x \n\r",
+ readl(hdmi_base + S5P_HDMI_CMAX));
+ HDMIPRINTK("HDMI_CMIN = 0x%08x \n\r",
+ readl(hdmi_base + S5P_HDMI_CMIN));
+}
+
+enum s5p_tv_hdmi_err tv_hdmi_video_init_csc(enum s5p_tv_hdmi_csc_type csc_type)
+{
+ unsigned short us_csc_coeff[10];
+
+ HDMIPRINTK("%d)\n\r", csc_type);
+
+ switch (csc_type) {
+
+ case HDMI_CSC_YUV601_TO_RGB_LR:
+ us_csc_coeff[0] = 0x23;
+ us_csc_coeff[1] = 256;
+ us_csc_coeff[2] = 938;
+ us_csc_coeff[3] = 846;
+ us_csc_coeff[4] = 256;
+ us_csc_coeff[5] = 443;
+ us_csc_coeff[6] = 0;
+ us_csc_coeff[7] = 256;
+ us_csc_coeff[8] = 0;
+ us_csc_coeff[9] = 350;
+ break;
+
+ case HDMI_CSC_YUV601_TO_RGB_FR:
+ us_csc_coeff[0] = 0x03;
+ us_csc_coeff[1] = 298;
+ us_csc_coeff[2] = 924;
+ us_csc_coeff[3] = 816;
+ us_csc_coeff[4] = 298;
+ us_csc_coeff[5] = 516;
+ us_csc_coeff[6] = 0;
+ us_csc_coeff[7] = 298;
+ us_csc_coeff[8] = 0;
+ us_csc_coeff[9] = 408;
+ break;
+
+ case HDMI_CSC_YUV709_TO_RGB_LR:
+ us_csc_coeff[0] = 0x23;
+ us_csc_coeff[1] = 256;
+ us_csc_coeff[2] = 978;
+ us_csc_coeff[3] = 907;
+ us_csc_coeff[4] = 256;
+ us_csc_coeff[5] = 464;
+ us_csc_coeff[6] = 0;
+ us_csc_coeff[7] = 256;
+ us_csc_coeff[8] = 0;
+ us_csc_coeff[9] = 394;
+ break;
+
+ case HDMI_CSC_YUV709_TO_RGB_FR:
+ us_csc_coeff[0] = 0x03;
+ us_csc_coeff[1] = 298;
+ us_csc_coeff[2] = 970;
+ us_csc_coeff[3] = 888;
+ us_csc_coeff[4] = 298;
+ us_csc_coeff[5] = 540;
+ us_csc_coeff[6] = 0;
+ us_csc_coeff[7] = 298;
+ us_csc_coeff[8] = 0;
+ us_csc_coeff[9] = 458;
+ break;
+
+ case HDMI_CSC_YUV601_TO_YUV709:
+ us_csc_coeff[0] = 0x33;
+ us_csc_coeff[1] = 256;
+ us_csc_coeff[2] = 995;
+ us_csc_coeff[3] = 971;
+ us_csc_coeff[4] = 0;
+ us_csc_coeff[5] = 260;
+ us_csc_coeff[6] = 29;
+ us_csc_coeff[7] = 0;
+ us_csc_coeff[8] = 19;
+ us_csc_coeff[9] = 262;
+ break;
+
+ case HDMI_CSC_RGB_FR_TO_RGB_LR:
+ us_csc_coeff[0] = 0x20;
+ us_csc_coeff[1] = 220;
+ us_csc_coeff[2] = 0;
+ us_csc_coeff[3] = 0;
+ us_csc_coeff[4] = 0;
+ us_csc_coeff[5] = 220;
+ us_csc_coeff[6] = 0;
+ us_csc_coeff[7] = 0;
+ us_csc_coeff[8] = 0;
+ us_csc_coeff[9] = 220;
+ break;
+
+ case HDMI_CSC_RGB_FR_TO_YUV601:
+ us_csc_coeff[0] = 0x30;
+ us_csc_coeff[1] = 129;
+ us_csc_coeff[2] = 25;
+ us_csc_coeff[3] = 65;
+ us_csc_coeff[4] = 950; /* -74 */
+ us_csc_coeff[5] = 112;
+ us_csc_coeff[6] = 986; /* -38 */
+ us_csc_coeff[7] = 930; /* -94 */
+ us_csc_coeff[8] = 1006; /* -18 */
+ us_csc_coeff[9] = 112;
+ break;
+
+ case HDMI_CSC_RGB_FR_TO_YUV709:
+ us_csc_coeff[0] = 0x30;
+ us_csc_coeff[1] = 157;
+ us_csc_coeff[2] = 16;
+ us_csc_coeff[3] = 47;
+ us_csc_coeff[4] = 937; /* -87 */
+ us_csc_coeff[5] = 112;
+ us_csc_coeff[6] = 999; /* -25 */
+ us_csc_coeff[7] = 922; /* -102 */
+ us_csc_coeff[8] = 1014; /* -10 */
+ us_csc_coeff[9] = 112;
+ break;
+
+ case HDMI_BYPASS:
+ us_csc_coeff[0] = 0x33;
+ us_csc_coeff[1] = 256;
+ us_csc_coeff[2] = 0;
+ us_csc_coeff[3] = 0;
+ us_csc_coeff[4] = 0;
+ us_csc_coeff[5] = 256;
+ us_csc_coeff[6] = 0;
+ us_csc_coeff[7] = 0;
+ us_csc_coeff[8] = 0;
+ us_csc_coeff[9] = 256;
+ break;
+
+ default:
+ HDMIPRINTK("invalid out_mode parameter(%d)\n\r", csc_type);
+ return S5P_TV_HDMI_ERR_INVALID_PARAM;
+ }
+
+ return HDMI_NO_ERROR;
+}
+
+enum s5p_tv_hdmi_err tv_hdmi_video_init_avi_infoframe(
+ enum s5p_hdmi_transmit trans_type,
+ u8 check_sum,
+ u8 *avi_data)
+{
+ HDMIPRINTK("%d,%d,%d\n\r",
+ (u32)trans_type, (u32)check_sum, (u32)avi_data);
+
+ switch (trans_type) {
+
+ case HDMI_DO_NOT_TANS:
+ writel(AVI_TX_CON_NO_TRANS, hdmi_base + S5P_AVI_CON);
+ break;
+
+ case HDMI_TRANS_ONCE:
+ writel(AVI_TX_CON_TRANS_ONCE, hdmi_base + S5P_AVI_CON);
+ break;
+
+ case HDMI_TRANS_EVERY_SYNC:
+ writel(AVI_TX_CON_TRANS_EVERY_VSYNC, hdmi_base + S5P_AVI_CON);
+ break;
+
+ default:
+ HDMIPRINTK(" invalid out_mode parameter(%d)\n\r", trans_type);
+ return S5P_TV_HDMI_ERR_INVALID_PARAM;
+ }
+
+ writel(SET_AVI_CHECK_SUM(check_sum), hdmi_base + S5P_AVI_CHECK_SUM);
+
+ writel(SET_AVI_BYTE(*(avi_data)), hdmi_base + S5P_AVI_BYTE1);
+ writel(SET_AVI_BYTE(*(avi_data + 1)), hdmi_base + S5P_AVI_BYTE2);
+ writel(SET_AVI_BYTE(*(avi_data + 2)), hdmi_base + S5P_AVI_BYTE3);
+ writel(SET_AVI_BYTE(*(avi_data + 3)), hdmi_base + S5P_AVI_BYTE4);
+ writel(SET_AVI_BYTE(*(avi_data + 4)), hdmi_base + S5P_AVI_BYTE5);
+ writel(SET_AVI_BYTE(*(avi_data + 5)), hdmi_base + S5P_AVI_BYTE6);
+ writel(SET_AVI_BYTE(*(avi_data + 6)), hdmi_base + S5P_AVI_BYTE7);
+ writel(SET_AVI_BYTE(*(avi_data + 7)), hdmi_base + S5P_AVI_BYTE8);
+ writel(SET_AVI_BYTE(*(avi_data + 8)), hdmi_base + S5P_AVI_BYTE9);
+ writel(SET_AVI_BYTE(*(avi_data + 9)), hdmi_base + S5P_AVI_BYTE10);
+ writel(SET_AVI_BYTE(*(avi_data + 10)), hdmi_base + S5P_AVI_BYTE11);
+ writel(SET_AVI_BYTE(*(avi_data + 11)), hdmi_base + S5P_AVI_BYTE12);
+ writel(SET_AVI_BYTE(*(avi_data + 12)), hdmi_base + S5P_AVI_BYTE13);
+
+ HDMIPRINTK("AVI_CON = 0x%08x \n\r", readl(hdmi_base + S5P_AVI_CON));
+ HDMIPRINTK("AVI_CHECK_SUM = 0x%08x \n\r",
+ readl(hdmi_base + S5P_AVI_CHECK_SUM));
+ HDMIPRINTK("AVI_BYTE1 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_AVI_BYTE1));
+ HDMIPRINTK("AVI_BYTE2 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_AVI_BYTE2));
+ HDMIPRINTK("AVI_BYTE3 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_AVI_BYTE3));
+ HDMIPRINTK("AVI_BYTE4 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_AVI_BYTE4));
+ HDMIPRINTK("AVI_BYTE5 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_AVI_BYTE5));
+ HDMIPRINTK("AVI_BYTE6 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_AVI_BYTE6));
+ HDMIPRINTK("AVI_BYTE7 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_AVI_BYTE7));
+ HDMIPRINTK("AVI_BYTE8 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_AVI_BYTE8));
+ HDMIPRINTK("AVI_BYTE9 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_AVI_BYTE9));
+ HDMIPRINTK("AVI_BYTE10 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_AVI_BYTE10));
+ HDMIPRINTK("AVI_BYTE11 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_AVI_BYTE11));
+ HDMIPRINTK("AVI_BYTE12 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_AVI_BYTE12));
+ HDMIPRINTK("AVI_BYTE13 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_AVI_BYTE13));
+
+ return HDMI_NO_ERROR;
+}
+
+enum s5p_tv_hdmi_err tv_hdmi_video_init_mpg_infoframe(
+ enum s5p_hdmi_transmit trans_type,
+ u8 check_sum,
+ u8 *mpg_data)
+{
+ HDMIPRINTK("trans_type : %d,%d,%d\n\r", (u32)trans_type,
+ (u32)check_sum, (u32)mpg_data);
+
+ switch (trans_type) {
+
+ case HDMI_DO_NOT_TANS:
+ writel(MPG_TX_CON_NO_TRANS,
+ hdmi_base + S5P_MPG_CON);
+ break;
+
+ case HDMI_TRANS_ONCE:
+ writel(MPG_TX_CON_TRANS_ONCE,
+ hdmi_base + S5P_MPG_CON);
+ break;
+
+ case HDMI_TRANS_EVERY_SYNC:
+ writel(MPG_TX_CON_TRANS_EVERY_VSYNC,
+ hdmi_base + S5P_MPG_CON);
+ break;
+
+ default:
+ HDMIPRINTK("invalid out_mode parameter(%d)\n\r",
+ trans_type);
+ return S5P_TV_HDMI_ERR_INVALID_PARAM;
+ }
+
+ writel(SET_MPG_CHECK_SUM(check_sum),
+
+ hdmi_base + S5P_MPG_CHECK_SUM);
+
+ writel(SET_MPG_BYTE(*(mpg_data)),
+ hdmi_base + S5P_MPEG_BYTE1);
+ writel(SET_MPG_BYTE(*(mpg_data + 1)),
+ hdmi_base + S5P_MPEG_BYTE2);
+ writel(SET_MPG_BYTE(*(mpg_data + 2)),
+ hdmi_base + S5P_MPEG_BYTE3);
+ writel(SET_MPG_BYTE(*(mpg_data + 3)),
+ hdmi_base + S5P_MPEG_BYTE4);
+ writel(SET_MPG_BYTE(*(mpg_data + 4)),
+ hdmi_base + S5P_MPEG_BYTE5);
+
+ HDMIPRINTK("MPG_CON = 0x%08x \n\r",
+ readl(hdmi_base + S5P_MPG_CON));
+ HDMIPRINTK("MPG_CHECK_SUM = 0x%08x \n\r",
+ readl(hdmi_base + S5P_MPG_CHECK_SUM));
+ HDMIPRINTK("MPEG_BYTE1 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_MPEG_BYTE1));
+ HDMIPRINTK("MPEG_BYTE2 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_MPEG_BYTE2));
+ HDMIPRINTK("MPEG_BYTE3 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_MPEG_BYTE3));
+ HDMIPRINTK("MPEG_BYTE4 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_MPEG_BYTE4));
+ HDMIPRINTK("MPEG_BYTE5 = 0x%08x \n\r",
+ readl(hdmi_base + S5P_MPEG_BYTE5));
+
+ return HDMI_NO_ERROR;
+}
+
+void tv_hdmi_video_init_tg_cmd(bool time_c_e,
+ bool bt656_sync_en,
+ bool tg_en)
+{
+ u32 temp_reg = 0;
+
+ temp_reg = readl(hdmi_base + S5P_TG_CMD);
+
+ if (time_c_e)
+ temp_reg |= GETSYNC_TYPE_EN;
+ else
+ temp_reg &= GETSYNC_TYPE_DIS;
+
+ if (bt656_sync_en)
+ temp_reg |= GETSYNC_EN;
+ else
+ temp_reg &= GETSYNC_DIS;
+
+ if (tg_en)
+ temp_reg |= TG_EN;
+ else
+ temp_reg &= TG_DIS;
+
+ writel(temp_reg, hdmi_base + S5P_TG_CMD);
+
+ HDMIPRINTK("TG_CMD = 0x%08x \n\r", readl(hdmi_base + S5P_TG_CMD));
+}
+
+
+bool tv_hdmi_start(enum s5p_hdmi_audio_type hdmi_audio_type,
+ bool hdcp_en,
+ struct i2c_client *ddc_port)
+{
+ u32 temp_reg = HDMI_EN;
+
+ HDMIPRINTK("aud type : %d, hdcp enable : %d\n\r",
+ hdmi_audio_type, hdcp_en);
+
+ switch (hdmi_audio_type) {
+
+ case HDMI_AUDIO_PCM:
+ temp_reg |= ASP_EN;
+ break;
+
+ case HDMI_AUDIO_NO:
+ break;
+
+ default:
+ HDMIPRINTK(" invalid hdmi_audio_type(%d)\n\r",
+ hdmi_audio_type);
+ return false;
+ }
+
+ writel(readl(hdmi_base + S5P_HDMI_CON_0) | temp_reg,
+ hdmi_base + S5P_HDMI_CON_0);
+
+ if (hdcp_en) {
+ if (!tv_start_hdcp())
+ HDMIPRINTK("HDCP start failed\n");
+ }
+
+ HDMIPRINTK("HPD : 0x%08x, HDMI_CON_0 : 0x%08x\n\r",
+ readl(hdmi_base + S5P_HPD),
+ readl(hdmi_base + S5P_HDMI_CON_0));
+
+ return true;
+}
+
+
+
+/*
+* stop - stop functions are only called under running HDMI
+*/
+void tv_hdmi_stop(void)
+{
+ u32 temp = 0, result = 0;
+ HDMIPRINTK("\n\r");
+
+ tv_stop_hdcp();
+
+ /*
+ * Before stopping hdmi, stop the hdcp first. However,
+ * if there's no delay between hdcp stop & hdmi stop,
+ * re-opening would be failed.
+ */
+ mdelay(100);
+
+ temp = readl(hdmi_base + S5P_HDMI_CON_0);
+ result = temp & HDMI_EN;
+
+ if (result)
+ writel(temp & ~(HDMI_EN | ASP_EN),
+ hdmi_base + S5P_HDMI_CON_0);
+
+ do {
+ temp = readl(hdmi_base + S5P_HDMI_CON_0);
+ } while (temp & HDMI_EN);
+
+ HDMIPRINTK("HPD 0x%08x,HDMI_CON_0 0x%08x\n\r",
+ readl(hdmi_base + S5P_HPD),
+ readl(hdmi_base + S5P_HDMI_CON_0));
+}
+
+int __init tv_hdmi_probe(struct platform_device *pdev,
+ u32 res_num, u32 res_num2)
+{
+ struct resource *res;
+ size_t size;
+ u32 reg;
+
+ spin_lock_init(&lock_hdmi);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, res_num);
+
+ if (res == NULL) {
+ dev_err(&pdev->dev,
+ "failed to get memory region resource\n");
+ goto error;
+ }
+
+ size = (res->end - res->start) + 1;
+
+ hdmi_mem = request_mem_region(res->start, size, pdev->name);
+
+ if (hdmi_mem == NULL) {
+ dev_err(&pdev->dev,
+ "failed to get memory region\n");
+ goto error;
+ }
+
+ hdmi_base = ioremap(res->start, size);
+
+ if (hdmi_base == NULL) {
+ dev_err(&pdev->dev,
+ "failed to ioremap address region\n");
+ goto error;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, res_num2);
+
+ if (res == NULL) {
+ dev_err(&pdev->dev,
+ "failed to get memory region resource\n");
+ goto error;
+ }
+
+ size = (res->end - res->start) + 1;
+
+ i2c_hdmi_phy_mem = request_mem_region(res->start, size, pdev->name);
+
+ if (i2c_hdmi_phy_mem == NULL) {
+ dev_err(&pdev->dev,
+ "failed to get memory region\n");
+ goto error;
+ }
+
+ i2c_hdmi_phy_base = ioremap(res->start, size);
+
+ if (i2c_hdmi_phy_base == NULL) {
+ dev_err(&pdev->dev,
+ "failed to ioremap address region\n");
+ goto error;
+ }
+
+ /* PMU Block : HDMI PHY Enable */
+ reg = readl(S3C_VA_SYS+0xE804);
+ reg |= (1<<0);
+ writel(reg, S3C_VA_SYS+0xE804);
+
+ /* i2c_hdmi init - set i2c filtering */
+ writeb(0x5, i2c_hdmi_phy_base + I2C_HDMI_LC);
+
+ /* temp for test - hdmi intr. global enable */
+ reg = readb(hdmi_base+S5P_HDMI_CTRL_INTC_CON);
+ writeb(reg | (1<<HDMI_IRQ_GLOBAL), hdmi_base+S5P_HDMI_CTRL_INTC_CON);
+
+ return 0;
+error:
+ return -ENOENT;
+
+}
+
+int __init tv_hdmi_release(struct platform_device *pdev)
+{
+ iounmap(hdmi_base);
+
+ /* remove memory region */
+ if (hdmi_mem != NULL) {
+ if (release_resource(hdmi_mem))
+ dev_err(&pdev->dev,
+ "Can't remove tvout drv !!\n");
+
+ kfree(hdmi_mem);
+
+ hdmi_mem = NULL;
+ }
+
+ return 0;
+}
+
+/*
+ * HDCP ISR.
+ * If HDCP IRQ occurs, set hdcp_event and wake up the waitqueue.
+ */
+
+#define HDMI_IRQ_TOTAL_NUM 6
+
+hdmi_isr hdmi_isr_ftn[HDMI_IRQ_TOTAL_NUM];
+
+int s5p_hdmi_register_isr(hdmi_isr isr, u8 irq_num)
+{
+ HDMIPRINTK("Try to register ISR for IRQ number (%d)\n", irq_num);
+
+ if (isr == NULL) {
+ HDMIPRINTK("Invaild ISR\n");
+ return -EINVAL;
+ }
+
+ /* check IRQ number */
+ if (irq_num > HDMI_IRQ_TOTAL_NUM) {
+ HDMIPRINTK("irq_num exceeds allowed IRQ number(%d)\n",
+ HDMI_IRQ_TOTAL_NUM);
+ return -EINVAL;
+ }
+
+ /* check if is the number already registered? */
+ if (hdmi_isr_ftn[irq_num]) {
+ HDMIPRINTK("the %d th ISR is already registered\n",
+ irq_num);
+ }
+
+ hdmi_isr_ftn[irq_num] = isr;
+
+ HDMIPRINTK("Success to register ISR for IRQ number (%d)\n",
+ irq_num);
+
+ return 0;
+}
+
+irqreturn_t tv_hdmi_irq(int irq, void *dev_id)
+{
+ u8 irq_state, irq_num;
+
+ spin_lock_irq(&lock_hdmi);
+
+ irq_state = readb(hdmi_base+S5P_HDMI_CTRL_INTC_FLAG);
+
+ HDMIPRINTK("S5P_HDMI_CTRL_INTC_FLAG = 0x%02x\n", irq_state);
+
+ /* Check interrupt happened */
+ /* Priority of Interrupt HDCP> I2C > Audio > CEC ( Not implemented) */
+
+ if (irq_state) {
+ /* HDCP IRQ*/
+ irq_num = 0;
+ /* check if ISR is null or not */
+ while (irq_num < HDMI_IRQ_TOTAL_NUM) {
+ if (irq_state & (1<<irq_num)) {
+ if (hdmi_isr_ftn[irq_num] != NULL) {
+ (hdmi_isr_ftn[irq_num])(irq_num);
+ } else {
+ HDMIPRINTK(
+ "No registered ISR for IRQ[%d]\n",
+ irq_num);
+ }
+ }
+ ++irq_num;
+ }
+
+ } else {
+ HDMIPRINTK("Undefined IRQ happened[%x]\n", irq_state);
+ }
+
+ spin_unlock_irq(&lock_hdmi);
+
+ /* Because of HW Problem,
+ after processing INT we should INT enable again.
+ HdmiOutp8(
+ S5P_HDMI_INTC_CON, 1 << HDMI_IRQ_HDCP | 1 << HDMI_IRQ_GLOBAL );
+ INTC_ClearVectAddr(); */
+
+ return IRQ_HANDLED;
+}
+
+void s5p_hdmi_enable_interrupts(enum s5p_tv_hdmi_interrrupt intr)
+{
+ u8 reg;
+ reg = readb(hdmi_base+S5P_HDMI_CTRL_INTC_CON);
+ writeb(reg | (1<<intr) | (1<<HDMI_IRQ_GLOBAL),
+ hdmi_base+S5P_HDMI_CTRL_INTC_CON);
+}
+
+void s5p_hdmi_disable_interrupts(enum s5p_tv_hdmi_interrrupt intr)
+{
+ u8 reg;
+ reg = readb(hdmi_base+S5P_HDMI_CTRL_INTC_CON);
+ writeb(reg & ~(1<<intr), hdmi_base+S5P_HDMI_CTRL_INTC_CON);
+}
+
+void s5p_hdmi_clear_pending(enum s5p_tv_hdmi_interrrupt intr)
+{
+ u8 reg;
+ reg = readb(hdmi_base+S5P_HDMI_CTRL_INTC_FLAG);
+ writeb(reg | (1<<intr), hdmi_base+S5P_HDMI_CTRL_INTC_FLAG);
+}
+
+u8 s5p_hdmi_get_interrupts(void)
+{
+ u8 reg;
+ reg = readb(hdmi_base+S5P_HDMI_CTRL_INTC_FLAG);
+ return reg;
+}
+
+u8 s5p_hdmi_get_swhpd_status(void)
+{
+ u8 reg;
+ reg = readb(hdmi_base+S5P_HPD) & HPD_SW_ENABLE;
+ return reg;
+}
+
+u8 s5p_hdmi_get_hpd_status(void)
+{
+ u8 reg;
+ reg = readb(hdmi_base+S5P_HDMI_CTRL_HPD);
+ return reg;
+}
+
+void s5p_hdmi_swhpd_disable(void)
+{
+ u8 reg;
+ reg = writeb(HPD_SW_DISABLE, hdmi_base+S5P_HPD);
+}
+
+void s5p_hdmi_hpd_gen(void)
+{
+ writeb(0xFF, hdmi_base+S5P_HDMI_HPD_GEN);
+}
+
« no previous file with comments | « drivers/media/video/samsung/tv20/hdmi_param.h ('k') | drivers/media/video/samsung/tv20/hpd.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698