diff options
author | Srikant Patnaik | 2015-01-11 12:28:04 +0530 |
---|---|---|
committer | Srikant Patnaik | 2015-01-11 12:28:04 +0530 |
commit | 871480933a1c28f8a9fed4c4d34d06c439a7a422 (patch) | |
tree | 8718f573808810c2a1e8cb8fb6ac469093ca2784 /drivers/video/wmt/hdmi.c | |
parent | 9d40ac5867b9aefe0722bc1f110b965ff294d30d (diff) | |
download | FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.tar.gz FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.tar.bz2 FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.zip |
Moved, renamed, and deleted files
The original directory structure was scattered and unorganized.
Changes are basically to make it look like kernel structure.
Diffstat (limited to 'drivers/video/wmt/hdmi.c')
-rwxr-xr-x | drivers/video/wmt/hdmi.c | 1457 |
1 files changed, 1457 insertions, 0 deletions
diff --git a/drivers/video/wmt/hdmi.c b/drivers/video/wmt/hdmi.c new file mode 100755 index 00000000..c181d757 --- /dev/null +++ b/drivers/video/wmt/hdmi.c @@ -0,0 +1,1457 @@ +/*++ + * linux/drivers/video/wmt/hdmi.c + * WonderMedia video post processor (VPP) driver + * + * Copyright c 2014 WonderMedia Technologies, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * WonderMedia Technologies, Inc. + * 4F, 533, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C +--*/ + +#define HDMI_C +#undef DEBUG +/* #define DEBUG */ +/*----------------------- DEPENDENCE -----------------------------------------*/ +#include "hdmi.h" +#include "vout.h" +#ifdef __KERNEL__ +#include <asm/div64.h> +#endif + +/*----------------------- PRIVATE MACRO --------------------------------------*/ + +/*----------------------- PRIVATE CONSTANTS ----------------------------------*/ +/* #define HDMI_XXXX 1 *//*Example*/ +/* #define CONFIG_HDMI_INFOFRAME_DISABLE */ +/* #define CONFIG_HDMI_EDID_DISABLE */ + +#define HDMI_I2C_FREQ 80000 +/*----------------------- PRIVATE TYPE --------------------------------------*/ +/* typedef xxxx hdmi_xxx_t; *//*Example*/ +enum hdmi_fifo_slot_t { + HDMI_FIFO_SLOT_AVI = 0, + HDMI_FIFO_SLOT_VENDOR = 1, + HDMI_FIFO_SLOT_AUDIO = 2, + HDMI_FIFO_SLOT_CONTROL = 3, + HDMI_FIFO_SLOT_MAX = 15 +}; + +/*----------EXPORTED PRIVATE VARIABLES are defined in hdmi.h -------------*/ +/*----------------------- INTERNAL PRIVATE VARIABLES - -----------------------*/ +/* int hdmi_xxx; *//*Example*/ + +HW_REG struct hdmi_base1_regs *hdmi_regs1 = (void *) (HDMI_BASE_ADDR + 0x100); +HW_REG struct hdmi_base2_regs *hdmi_regs2 = (void *) HDMI_BASE2_ADDR; + +/*--------------------- INTERNAL PRIVATE FUNCTIONS ---------------------------*/ +/* void hdmi_xxx(void); *//*Example*/ + +/*----------------------- Function Body --------------------------------------*/ +/*---------------------------- HDMI COMMON API -------------------------------*/ +unsigned char hdmi_ecc(unsigned char *buf, int bit_cnt) +{ + #define HDMI_CRC_LEN 9 + + int crc[HDMI_CRC_LEN], crc_o[HDMI_CRC_LEN]; + int i, j; + int input, result, result_rev = 0; + + for (i = 0; i < HDMI_CRC_LEN; i++) + crc[i] = 0; + + for (i = 0; i < bit_cnt; i++) { + for (j = 0; j < HDMI_CRC_LEN; j++) + crc_o[j] = crc[j]; + input = (buf[i/8] & (1<<(i%8))) ? 1 : 0; + crc[0] = crc_o[7] ^ input; + crc[1] = crc_o[0]; + crc[2] = crc_o[1]; + crc[3] = crc_o[2]; + crc[4] = crc_o[3]; + crc[5] = crc_o[4]; + crc[6] = crc_o[5] ^ crc_o[7] ^ input; + crc[7] = crc_o[6] ^ crc_o[7] ^ input; + crc[8] = crc_o[7]; + + result = 0; + result_rev = 0; + for (j = 0; j < HDMI_CRC_LEN - 1; j++) { + result += (crc[j] << j); + result_rev += (crc[j] << (HDMI_CRC_LEN - 2 - j)); + } + } + +/* DPRINT("[HDMI] crc 0x%x, %x %x %x %x %x %x %x\n",result_rev, + buf[0],buf[1],buf[2],buf[3],buf[4],buf[5],buf[6]); */ + return result_rev; +} + +unsigned char hdmi_checksum(unsigned char *header, + unsigned char *buf, int cnt) +{ + unsigned char sum; + int i; + + for (i = 0, sum = 0; i < cnt; i++) + sum += buf[i]; + for (i = 0; i < 3; i++) + sum += header[i]; + return 0 - sum; +} + +#ifdef WMT_FTBLK_HDMI +/*---------------------------- HDMI HAL --------------------------------------*/ +void hdmi_set_power_down(int pwrdn) +{ + DBG_DETAIL("(%d)\n", pwrdn); + + if ((hdmi_regs2->test.b.pd == 0) && (pwrdn == 0)) + return; /* avoid HDMI reset */ + + hdmi_regs2->status.b.internal_ldo = (pwrdn) ? 0 : 1; + hdmi_regs2->test.b.pd = pwrdn; + if (!pwrdn) { + hdmi_regs2->dftset2.b.reset_pll = 1; + mdelay(1); + hdmi_regs2->dftset2.b.reset_pll = 0; + } + mdelay(1); + hdmi_regs2->test2.b.pd_l2ha = pwrdn; +} + +int hdmi_get_power_down(void) +{ + return hdmi_regs2->test.b.pd; +} + +void hdmi_set_enable(vpp_flag_t enable) +{ + hdmi_regs1->general_ctrl.b.enable = enable; + hdmi_regs1->general_ctrl.b.vsync_enable = 1; /* for write only */ + hdmi_regs2->test2.b.mode = (enable) ? 0 : 1; +} + +void hdmi_set_avmute(vpp_flag_t mute) +{ + hdmi_regs1->aud_insert_ctrl.b.avmute_set_enable = mute; +} + +void hdmi_set_dvi_enable(vpp_flag_t enable) +{ + hdmi_regs1->general_ctrl.b.dvi_mode_enable = enable; + hdmi_regs1->general_ctrl.b.vsync_enable = 1; /* for write only */ +} + +void hdmi_set_sync_low_active(vpp_flag_t hsync, vpp_flag_t vsync) +{ + hdmi_regs1->general_ctrl.b.hsync_low_active = hsync; + hdmi_regs1->general_ctrl.b.vsync_low_active = vsync; + hdmi_regs1->general_ctrl.b.vsync_enable = 1; /* for write only */ +} + +void hdmi_get_sync_polar(int *hsync_hi, int *vsync_hi) +{ + *hsync_hi = (hdmi_regs1->general_ctrl.b.hsync_low_active) ? 0 : 1; + *vsync_hi = (hdmi_regs1->general_ctrl.b.vsync_low_active) ? 0 : 1; +} + +void hdmi_set_output_colfmt(vdo_color_fmt colfmt) +{ + unsigned int val; + + switch (colfmt) { + default: + case VDO_COL_FMT_ARGB: + val = 0; + break; + case VDO_COL_FMT_YUV444: + val = 1; + break; + case VDO_COL_FMT_YUV422H: + case VDO_COL_FMT_YUV422V: + val = 2; + break; + } + hdmi_regs1->general_ctrl.b.convert_yuv422 = (val == 2) ? 1 : 0; + hdmi_regs1->general_ctrl.b.output_format = val; + hdmi_regs1->general_ctrl.b.vsync_enable = 1; /* for write only */ +} + +vdo_color_fmt hdmi_get_output_colfmt(void) +{ + unsigned int val; + + val = hdmi_regs1->general_ctrl.b.output_format; + switch (val) { + default: + case 0: + return VDO_COL_FMT_ARGB; + case 1: + return VDO_COL_FMT_YUV444; + case 2: + return VDO_COL_FMT_YUV422H; + } + return VDO_COL_FMT_ARGB; +} + +int hdmi_get_plugin(void) +{ + int plugin; + + if (hdmi_regs1->hotplug_detect.b.in_enable) { + plugin = hdmi_regs1->hotplug_detect.b.sts; + } else { + int tre_en; + + tre_en = hdmi_regs2->test.b.tre_en; + hdmi_regs2->test.b.tre_en = 0; + plugin = hdmi_regs2->detect.b.rsen; + hdmi_regs2->test.b.tre_en = tre_en; + } + return plugin; +} + +int hdmi_get_plug_status(void) +{ + int reg; + + reg = hdmi_regs1->hotplug_detect.val; + return reg & 0x3000000; +} + +void hdmi_clear_plug_status(void) +{ + hdmi_regs1->hotplug_detect.b.in_sts = 1; + hdmi_regs1->hotplug_detect.b.out_sts = 1; +} + +void hdmi_enable_plugin(int enable) +{ + hdmi_regs1->hotplug_detect.b.out_enable = enable; + hdmi_regs1->hotplug_detect.b.in_enable = enable; +} + +void hdmi_write_fifo(enum hdmi_fifo_slot_t no, unsigned int *buf, int cnt) +{ + int i; + + if (no > HDMI_FIFO_SLOT_MAX) + return; +#ifdef DEBUG +{ + char *ptr; + + DPRINT("[HDMI] wr fifo %d,cnt %d", no, cnt); + ptr = (char *) buf; + for (i = 0; i < cnt; i++) { + if ((i % 4) == 0) + DPRINT("\n %02d :", i); + DPRINT(" 0x%02x", ptr[i]); + } + DPRINT("\n[HDMI] AVI info package end\n"); +} +#endif + hdmi_regs1->fifo_ctrl.val = (no << 8); + cnt = (cnt + 3) / 4; + for (i = 0; i < cnt; i++) + hdmi_regs1->wr_fifo_addr[i] = buf[i]; + hdmi_regs1->fifo_ctrl.b.wr_strobe = 1; +} + +void hdmi_read_fifo(enum hdmi_fifo_slot_t no, unsigned int *buf, int cnt) +{ + int i; + int rdy; + + if (no > HDMI_FIFO_SLOT_MAX) + return; + + rdy = hdmi_regs1->infoframe_ctrl.b.fifo1_rdy; + hdmi_regs1->infoframe_ctrl.b.fifo1_rdy = 0; + + no = no - 1; + hdmi_regs1->fifo_ctrl.val = (no << 8); + hdmi_regs1->fifo_ctrl.b.rd_strobe = 1; + cnt = (cnt + 3) / 4; + for (i = 0; i < cnt; i++) + buf[i] = hdmi_regs1->rd_fifo_addr[i]; + hdmi_regs1->infoframe_ctrl.b.fifo1_rdy = rdy; +#ifdef DEBUG +{ + char *ptr; + + cnt *= 4; + DPRINT("[HDMI] rd fifo %d,cnt %d", no, cnt); + ptr = (char *) buf; + for (i = 0; i < cnt; i++) { + if ((i % 4) == 0) + DPRINT("\n %02d :", i); + DPRINT(" 0x%02x", ptr[i]); + } + DPRINT("\n[HDMI] AVI info package end\n"); +} +#endif +} + +#if 1 +int hdmi_ddc_delay_us = 5; +int hdmi_ddc_ctrl_delay_us = 5; + +#define HDMI_DDC_OUT +#define HDMI_DDC_DELAY hdmi_ddc_delay_us +#define HDMI_DDC_CHK_DELAY 1 +#define HDMI_DDC_CTRL_DELAY hdmi_ddc_ctrl_delay_us +#else +#define HDMI_DDC_OUT +#define HDMI_DDC_DELAY 1 +#define HDMI_DDC_CHK_DELAY 1 +#define HDMI_DDC_CTRL_DELAY 1 +#endif + +#define HDMI_STATUS_START BIT16 +#define HDMI_STATUS_STOP BIT17 +#define HDMI_STATUS_WR_AVAIL BIT18 +#define HDMI_STATUS_CP_USE BIT19 +#define HDMI_STATUS_SW_READ BIT25 +int hdmi_DDC_check_status(unsigned int checkbits, int condition) +{ + int status = 1; + unsigned int i = 0, maxloop; + + maxloop = 500 / HDMI_DDC_CHK_DELAY; + udelay(HDMI_DDC_DELAY); + + if (condition) { /* wait 1 --> 0 */ + while ((hdmi_regs1->i2c_ctrl2.val & checkbits) + && (i < maxloop)) { + udelay(HDMI_DDC_CHK_DELAY); + if (++i == maxloop) + status = 0; + } + } else { /* wait 0 --> 1 */ + while (!(hdmi_regs1->i2c_ctrl2.val & checkbits) + && (i < maxloop)) { + udelay(HDMI_DDC_CHK_DELAY); + if (++i == maxloop) + status = 0; + } + } + + if ((status == 0) && (checkbits != HDMI_STATUS_SW_READ)) { + unsigned int reg; + + reg = hdmi_regs1->i2c_ctrl2.val; + DBG_DETAIL("[HDMI] status timeout check 0x%x,wait to %s\n", + checkbits, (condition) ? "0" : "1"); + DBG_DETAIL("[HDMI] 0x%x,sta %d,stop %d,wr %d,rd %d,cp %d\n", + reg, (reg & HDMI_STATUS_START) ? 1 : 0, + (reg & HDMI_STATUS_STOP) ? 1 : 0, + (reg & HDMI_STATUS_WR_AVAIL) ? 1 : 0, + (reg & HDMI_STATUS_SW_READ) ? 1 : 0, + (reg & HDMI_STATUS_CP_USE) ? 1 : 0); + } + return status; +} + +void hdmi_DDC_set_freq(unsigned int hz) +{ + unsigned int clock; + unsigned int div; + + clock = 25000000*15/100; /* RTC clock source */ + div = clock / hz; + + hdmi_regs1->i2c_ctrl.b.i2c_clk_divider = div; + DBG_DETAIL("[HDMI] set freq(%d,clk %d,div %d)\n", hz, clock, div); +} + +void hdmi_DDC_reset(void) +{ + hdmi_regs1->i2c_ctrl.b.i2c_sw_reset = 1; + udelay(1); + hdmi_regs1->i2c_ctrl.b.i2c_sw_reset = 0; +} + +int hdmi_DDC_read_func(char addr, int index, char *buf, int length) +{ + int status = 1; + unsigned int i = 0; + int err_cnt = 0; + + DBG_DETAIL("[HDMI] read DDC(index 0x%x,len %d),reg 0x%x\n", + index, length, hdmi_regs1->i2c_ctrl2.val); + +#ifdef CONFIG_HDMI_EDID_DISABLE + return status; +#endif + + hdmi_DDC_set_freq(g_vpp.hdmi_i2c_freq); + /* enhanced DDC read */ + if (index >= 256) { + /* sw start, write data avail */ + vppif_reg32_write((unsigned int) &hdmi_regs1->i2c_ctrl2, + BIT18 + BIT16, 16, 0x5); + udelay(HDMI_DDC_CTRL_DELAY); + /* wait start & wr data avail */ + status = hdmi_DDC_check_status(HDMI_STATUS_START + + HDMI_STATUS_WR_AVAIL, 1); + if (status == 0) { + DBGMSG("[HDMI] *E* start\n"); + err_cnt++; + goto ddc_read_fail; + } + + /* Slave address */ + hdmi_regs1->i2c_ctrl2.b.wr_data = 0x60; + hdmi_regs1->i2c_ctrl2.b.wr_data_avail = 1; + udelay(HDMI_DDC_CTRL_DELAY); + /* wait wr data avail */ + status = hdmi_DDC_check_status(HDMI_STATUS_WR_AVAIL, 1); + if (status == 0) { + DBGMSG("[HDMI] *E* slave addr 0x%x\n", addr); + err_cnt++; + goto ddc_read_fail; + } + + /* Offset */ + hdmi_regs1->i2c_ctrl2.b.wr_data = 0x1; + hdmi_regs1->i2c_ctrl2.b.wr_data_avail = 1; + udelay(HDMI_DDC_CTRL_DELAY); + /* wait wr data avail */ + status = hdmi_DDC_check_status(HDMI_STATUS_WR_AVAIL, 1); + if (status == 0) { + DBGMSG("[HDMI] *E* index 0x%x\n", index); + err_cnt++; + goto ddc_read_fail; + } + index -= 256; + } + + /* START */ + hdmi_regs1->i2c_ctrl2.val = 0x50000; /* start & data avail */ + udelay(HDMI_DDC_CTRL_DELAY); + /* wait start & wr data avail */ + status = hdmi_DDC_check_status(HDMI_STATUS_START + + HDMI_STATUS_WR_AVAIL, 1); + if (status == 0) { + DBGMSG("[HDMI] *E* start\n"); + err_cnt++; + goto ddc_read_fail; + } + + /* Slave address */ + hdmi_regs1->i2c_ctrl2.val = 0x400A0; /* addr & data avail */ + udelay(HDMI_DDC_CTRL_DELAY); + /* wait wr data avail */ + status = hdmi_DDC_check_status(HDMI_STATUS_WR_AVAIL, 1); + if (status == 0) { + DBGMSG("[HDMI] *E* slave addr 0x%x\n", addr); + err_cnt++; + goto ddc_read_fail; + } + + /* Offset */ + hdmi_regs1->i2c_ctrl2.val = (0x40000 + index); /* index & data avail */ + udelay(HDMI_DDC_CTRL_DELAY); + /* wait wr data avail */ + status = hdmi_DDC_check_status(HDMI_STATUS_WR_AVAIL, 1); + if (status == 0) { + DBGMSG("[HDMI] *E* index 0x%x\n", index); + err_cnt++; + goto ddc_read_fail; + } + + /* START */ + hdmi_regs1->i2c_ctrl2.val = 0x50000; /* start & data avail */ + udelay(HDMI_DDC_CTRL_DELAY); + /* wait start & wr data avail */ + status = hdmi_DDC_check_status(HDMI_STATUS_START + + HDMI_STATUS_WR_AVAIL, 1); + if (status == 0) { + DBGMSG("[HDMI] *E* restart\n"); + err_cnt++; + goto ddc_read_fail; + } + + /* Slave Address + 1 */ + hdmi_regs1->i2c_ctrl2.val = 0x400A1; /* addr(rd) & data avail */ + udelay(HDMI_DDC_CTRL_DELAY); + /* wait wr data avail */ + status = hdmi_DDC_check_status(HDMI_STATUS_WR_AVAIL, 1); + if (status == 0) { + DBGMSG("[HDMI] *E* slave addr 0x%x\n", addr + 1); + err_cnt++; + goto ddc_read_fail; + } + + /* Read Data */ + for (i = 0; i < length; i++) { + hdmi_regs1->i2c_ctrl2.val = 0x40000; /* data avail */ + udelay(HDMI_DDC_CTRL_DELAY); + /* wait wr data avail */ + status = hdmi_DDC_check_status(HDMI_STATUS_WR_AVAIL, 1); + if (status == 0) { + DBGMSG("[HDMI] *E* wr ACK(%d)\n", i); + err_cnt++; + goto ddc_read_fail; + /* break; */ + } + + /* wait sw read not set */ + status = hdmi_DDC_check_status(HDMI_STATUS_SW_READ, 0); + if (status == 0) { + DBGMSG("[HDMI] *E* read avail(%d)\n", i); + if (i == 0) { + err_cnt++; + /* goto ddc_read_fail; */ + } else { + /* g_vpp.dbg_hdmi_ddc_read_err++; */ + } + goto ddc_read_fail; + /* break; */ + } + + *buf++ = hdmi_regs1->i2c_ctrl2.b.rd_data; + udelay(HDMI_DDC_DELAY); + hdmi_regs1->i2c_ctrl2.val = 0x2000000; /* clr sw read */ + udelay(HDMI_DDC_DELAY); + } + + /* STOP */ + /* sw stop, write data avail */ + vppif_reg32_write((unsigned int) &hdmi_regs1->i2c_ctrl2.val, + BIT18 + BIT17, 17, 3); + udelay(HDMI_DDC_CTRL_DELAY); + /* wait start & wr data avail */ + status = hdmi_DDC_check_status(HDMI_STATUS_STOP + + HDMI_STATUS_WR_AVAIL + HDMI_STATUS_CP_USE, 1); + if (status == 0) { + DBGMSG("[HDMI] *E* stop\n"); + err_cnt++; + goto ddc_read_fail; + } + udelay(HDMI_DDC_DELAY); + +ddc_read_fail: + if (err_cnt) + DBGMSG("[HDMI] *E* read DDC %d\n", err_cnt); + return (err_cnt) ? 1 : 0; +} + +int hdmi_DDC_read(char addr, int index, char *buf, int length) +{ + int retry = 3; + int ret; + + DBG_MSG("(0x%x,0x%x,%d)\n", addr, index, length); + + do { + ret = hdmi_DDC_read_func(addr, index, buf, length); + if (ret == 0) + break; + hdmi_DDC_reset(); + DPRINT("[HDMI] *W* DDC reset %d\n", ret); + retry--; + } while (retry); + + return (retry == 0) ? 1 : 0; +} + +void hdmi_audio_enable(vpp_flag_t enable) +{ + if (hdmi_regs1->aud_enable != enable) { + if (!enable) { +#ifdef CONFIG_KERNEL + msleep(5); +#endif + if (g_vpp.hdmi_ch_change) + REG32_VAL(I2S_BASE_ADDR + 0x188) = 0; + } + hdmi_regs1->aud_enable = (enable) ? 1 : 0; + } +} + +void hdmi_audio_mute(vpp_flag_t enable) +{ + hdmi_regs1->aud_ratio.b.mute = enable; +} + +/*----------------------- HDMI API --------------------------------------*/ +void hdmi_write_packet(unsigned int header, unsigned char *packet, + int cnt) +{ + unsigned char buf[36]; + int i; + enum hdmi_fifo_slot_t no; + +#ifdef CONFIG_HDMI_INFOFRAME_DISABLE + return; +#endif + memcpy(&buf[0], &header, 3); + buf[3] = hdmi_ecc((unsigned char *)&header, 24); + for (i = 0; i < cnt / 7; i++) { + memcpy(&buf[4+8*i], &packet[7*i], 7); + buf[11+8*i] = hdmi_ecc(&packet[7*i], 56); + } + + switch (header & 0xFF) { + case HDMI_PACKET_INFOFRAME_AVI: + no = HDMI_FIFO_SLOT_AVI; + break; + case HDMI_PACKET_INFOFRAME_AUDIO: + no = HDMI_FIFO_SLOT_AUDIO; + break; + case HDMI_PACKET_INFOFRAME_VENDOR: + no = HDMI_FIFO_SLOT_VENDOR; + break; + default: + no = HDMI_FIFO_SLOT_CONTROL; + break; + } + hdmi_write_fifo(no, (unsigned int *)buf, (4 + 8 * (cnt / 7))); +} + +void hdmi_tx_null_packet(void) +{ + hdmi_write_packet(HDMI_PACKET_NULL, 0, 0); +} + +void hdmi_tx_general_control_packet(int mute) +{ + unsigned char buf[7]; + memset(buf, 0x0, 7); + buf[0] = (mute) ? 0x01 : 0x10; + buf[1] = HDMI_COLOR_DEPTH_24 | (HDMI_PHASE_4 << 4); + hdmi_write_packet(HDMI_PACKET_GENERAL_CTRL, buf, 7); +} + +int hdmi_get_pic_aspect(enum hdmi_video_code_t vic) +{ + switch (vic) { + case HDMI_640x480p60_4x3: + case HDMI_720x480p60_4x3: + case HDMI_1440x480i60_4x3: + case HDMI_1440x240p60_4x3: + case HDMI_2880x480i60_4x3: + case HDMI_2880x240p60_4x3: + case HDMI_1440x480p60_4x3: + case HDMI_720x576p50_4x3: + case HDMI_1440x576i50_4x3: + case HDMI_1440x288p50_4x3: + case HDMI_2880x576i50_4x3: + case HDMI_2880x288p50_4x3: + case HDMI_1440x576p50_4x3: + return HDMI_PIC_ASPECT_4_3; + default: + break; + } + return HDMI_PIC_ASPECT_16_9; +} + +int hdmi_get_vic(int resx, int resy, int fps, int interlace) +{ + struct hdmi_vic_t info; + int i; + + info.resx = resx; + info.resy = resy; + info.freq = fps; + info.option = (interlace) ? HDMI_VIC_INTERLACE : HDMI_VIC_PROGRESS; + info.option |= (vout_check_ratio_16_9(resx, resy)) ? + HDMI_VIC_16x9 : HDMI_VIC_4x3; + for (i = 0; i < HDMI_VIDEO_CODE_MAX; i++) { + if (memcmp(&hdmi_vic_info[i], &info, + sizeof(struct hdmi_vic_t)) == 0) + return i; + } + return HDMI_UNKNOW; +} + +void hdmi_tx_avi_infoframe_packet(vdo_color_fmt colfmt, + enum hdmi_video_code_t vic) +{ + unsigned int header; + unsigned char buf[28]; + unsigned char temp; + + memset(buf, 0x0, 28); + header = HDMI_PACKET_INFOFRAME_AVI + (0x2 << 8) + (0x0d << 16); + buf[1] = HDMI_SI_NO_DATA + (HDMI_BI_V_H_VALID << 2) + + (HDMI_AF_INFO_NO_DATA << 4); + switch (colfmt) { + case VDO_COL_FMT_YUV422H: + case VDO_COL_FMT_YUV422V: + temp = HDMI_OUTPUT_YUV422; + break; + case VDO_COL_FMT_YUV444: + temp = HDMI_OUTPUT_YUV444; + break; + case VDO_COL_FMT_ARGB: + default: + temp = HDMI_OUTPUT_RGB; + break; + } + buf[1] += (temp << 5); + buf[2] = HDMI_ASPECT_RATIO_PIC + (hdmi_get_pic_aspect(vic) << 4) + + (HDMI_COLORIMETRY_ITU709 << 6); + buf[3] = 0x84; + buf[4] = vic; + switch (vic) { + case HDMI_1440x480i60_16x9: + case HDMI_1440x576i50_16x9: + buf[5] = HDMI_PIXEL_REP_2; + break; + default: + buf[5] = HDMI_PIXEL_REP_NO; + break; + } + buf[0] = hdmi_checksum((unsigned char *)&header, buf, 28); + hdmi_write_packet(header, buf, 28); +} + +void hdmi_tx_audio_infoframe_packet(int channel, int freq) +{ + unsigned int header; + unsigned char buf[28]; + + memset(buf, 0x0, 28); + header = HDMI_PACKET_INFOFRAME_AUDIO + (0x1 << 8) + (0x0a << 16); + buf[1] = (channel - 1) + (HDMI_AUD_TYPE_REF_STM << 4); + buf[2] = 0x0; /* HDMI_AUD_SAMPLE_24 + (freq << 2); */ + buf[3] = 0x00; + /* 0x13: RRC RLC RR RL FC LFE FR FL + 0x1F: FRC FLC RR RL FC LFE FR FL */ + buf[4] = (channel == 8) ? 0x13 : 0; + buf[5] = 0x0; /* 0 db */ + buf[0] = hdmi_checksum((unsigned char *)&header, buf, 28); + hdmi_write_packet(header, buf, 28); +} + +void hdmi_tx_vendor_specific_infoframe_packet(void) +{ + unsigned int header; + unsigned char buf[28]; + unsigned char structure_3d, meta_present; + unsigned char hdmi_video_format; + + /* 0-No,1-1 byte param,2-3D format */ + hdmi_video_format = (g_vpp.hdmi_3d_type) ? 2 : 0; + /* HDMI_3D_STRUCTURE_XXX; */ + structure_3d = (g_vpp.hdmi_3d_type == 1) ? 0 : g_vpp.hdmi_3d_type; + meta_present = 0; + + memset(buf, 0x0, 28); + header = HDMI_PACKET_INFOFRAME_VENDOR + (0x1 << 8) + (0xa << 16); + buf[1] = 0x3; + buf[2] = 0xC; + buf[3] = 0x0; + buf[4] = (hdmi_video_format << 5); + buf[5] = (structure_3d << 4) + ((meta_present) ? 0x8 : 0x0); + buf[6] = 0x0; /* 3D_Ext_Data */ +#if 0 /* metadata present */ + buf[7] = 0x0; /* 3D_Metadata_type,3D_Metadata_Length(N) */ + buf[8] = 0x0; /* 3D Metadata 1_N */ +#endif + buf[0] = hdmi_checksum((unsigned char *)&header, buf, 28); + hdmi_write_packet(header, buf, 28); +} + +#define HDMI_N_CTS_USE_TABLE +#ifdef HDMI_N_CTS_USE_TABLE +struct hdmi_n_cts_s { + unsigned int n; + unsigned int cts; +}; + +struct hdmi_n_cts_s hdmi_n_cts_table[7][11] = { + /* 32kHz */ + {{ 9152, 84375 }, {4096, 37800}, {4096, 40500}, {8192, 81081}, + { 4096, 81000 }, {4096, 81081}, {11648, 316406}, {4096, 111375}, + { 11648, 632812}, {4096, 222750}, {4096, 0}}, + /* 44.1kHz */ + {{7007, 46875}, {6272, 42000}, {6272, 45000}, {6272, 45045}, + {6272, 90000}, {6272, 90090}, {17836, 351562}, {6272, 123750}, + {17836, 703125}, {6272, 247500}, {6272, 0}}, + /* 88.2kHz */ + {{14014, 46875}, {12544, 42000}, {12544, 45000}, {12544, 45045}, + {12544, 90000}, {12544, 90090}, {35672, 351562}, {12544, 123750}, + {35672, 703125}, {12544, 247500}, {12544, 0}}, + /* 176.4kHz */ + {{28028, 46875}, {25088, 42000}, {25088, 45000}, {25088, 45045}, + {25088, 90000}, {25088, 90090}, {71344, 351562}, {25088, 123750}, + {71344, 703125}, {25088, 247500}, {25088, 0}}, + /* 48kHz */ + {{9152, 56250}, {6144, 37800}, {6144, 40500}, {8192, 54054}, + {6144, 81000}, {6144, 81081}, {11648, 210937}, {6144, 111375}, + {11648, 421875}, {6144, 222750}, {6144, 0}}, + /* 96kHz */ + {{18304, 56250}, {12288, 37800}, {12288, 40500}, {16384, 54054}, + {12288, 81000}, {12288,81081}, {23296, 210937}, {12288, 111375}, + {23296, 421875}, {12288, 222750}, {12288, 0}}, + /* 192kHz */ + {{36608, 56250}, {24576, 37800}, {24576, 40500}, {32768, 54054}, + {24576, 81000}, {24576, 81081}, {46592, 210937}, {24576, 111375}, + {46592, 421875}, {24576, 222750}, {24576, 0}} +}; + +struct hdmi_n_cts_s *hdmi_get_n_cts(unsigned int tmds_clk, + unsigned int freq) +{ + int i, j; + + switch (freq) { + case 32000: + i = 0; + break; + case 44100: + i = 1; + break; + case 88200: + i = 2; + break; + case 176400: + i = 3; + break; + case 48000: + i = 4; + break; + case 96000: + i = 5; + break; + case 192000: + i = 6; + break; + default: + return 0; + } + + switch (tmds_clk) { + case 25174825: + j = 0; + break; + case 25200000: + j = 1; + break; + case 27000000: + j = 2; + break; + case 27027000: + j = 3; + break; + case 54000000: + j = 4; + break; + case 54054000: + j = 5; + break; + case 74175824: + j = 6; + break; + case 74250000: + j = 7; + break; + case 148351648: + j = 8; + break; + case 148500000: + j = 9; + break; + default: + j = 10; + break; + } + return &hdmi_n_cts_table[i][j]; +} +#endif + +void hdmi_set_audio_n_cts(unsigned int freq) +{ + unsigned int n = 0, cts = 0; + +#ifdef HDMI_N_CTS_USE_TABLE + struct hdmi_n_cts_s *p; + + p = hdmi_get_n_cts(g_vpp.hdmi_pixel_clock, freq); + if (p) { + n = p->n; + cts = p->cts; + MSG("[HDMI] use table n %d, cts %d\n", n, cts); + } +#endif + + if (n == 0) + n = 128 * freq / 1000; + + if (cts == 0) { +#ifdef __KERNEL__ + unsigned int tmp; + unsigned int pll_clk; + + pll_clk = auto_pll_divisor(DEV_I2S, GET_FREQ, 0, 0); + tmp = (inl(AUDREGF_BASE_ADDR + 0x70) & 0xF); + + switch (tmp) { + case 0 ... 4: + tmp = 0x01 << tmp; + break; + case 9 ... 12: + tmp = 3 * (0x1 << (tmp-9)); + break; + default: + tmp = 1; + break; + } + { + unsigned long long tmp2; + unsigned long long div2; + unsigned long mod; + + tmp2 = g_vpp.hdmi_pixel_clock; + tmp2 = tmp2 * n * tmp; + div2 = pll_clk; + mod = do_div(tmp2, div2); + cts = tmp2; + } + DBGMSG("[HDMI] i2s %d,cts %d,reg 0x%x\n", pll_clk, cts, + vppif_reg32_in(AUDREGF_BASE_ADDR + 0x70)); +#else + cts = (g_vpp.hdmi_pixel_clock / 1000) - 1; +#endif + } + hdmi_regs1->aud_sample_rate1.b.n_20bits = n; + hdmi_regs1->aud_ratio.b.acr_ratio = cts - 1; + hdmi_regs1->aud_sample_rate2.b.cts_select = 0; + cts = 0; + hdmi_regs1->aud_sample_rate1.b.cts_low_12bits = cts & 0xFFF; + hdmi_regs1->aud_sample_rate2.b.cts_hi_8bits = (cts & 0xFF000) >> 12; + DBGMSG("[HDMI] set audio freq %d,n %d,cts %d,tmds %d\n", + freq, n, cts, g_vpp.hdmi_pixel_clock); +} + +void hdmi_config_audio(struct vout_audio_t *info) +{ + unsigned int freq; + + g_vpp.hdmi_audio_channel = info->channel; + g_vpp.hdmi_audio_freq = info->sample_rate; + + /* enable ARF & ARFP clock */ + REG32_VAL(PM_CTRL_BASE_ADDR + 0x254) |= (BIT4 | BIT3); + hdmi_tx_audio_infoframe_packet(info->channel, info->sample_rate); + hdmi_audio_enable(VPP_FLAG_DISABLE); + hdmi_regs1->aud_mode.b.layout = (info->channel > 2) ? 1 : 0; + hdmi_regs1->aud_mode.b._2ch_eco = (info->channel > 2) ? 0 : 1; + switch (info->sample_rate) { + case 32000: + freq = 0x3; + break; + case 44100: + freq = 0x0; + break; + case 88200: + freq = 0x8; + break; + case 176400: + freq = 0xC; + break; + default: + case 48000: + freq = 0x2; + break; + case 96000: + freq = 0xA; + break; + case 192000: + freq = 0xE; + break; + case 768000: + freq = 0x9; + break; + } + hdmi_regs1->aud_chan_status0 = (freq << 24) + 0x4; + hdmi_regs1->aud_chan_status1 = 0x0; + hdmi_regs1->aud_chan_status2 = 0xb; + hdmi_regs1->aud_chan_status3 = 0x0; + hdmi_regs1->aud_chan_status4 = 0x0; + hdmi_regs1->aud_chan_status5 = 0x0; + + hdmi_set_audio_n_cts(info->sample_rate); + hdmi_regs1->aud_ratio.b.acr_enable = 1; + hdmi_regs1->aud_sample_rate2.b.aipclk_rate = 0; + hdmi_audio_enable(VPP_FLAG_ENABLE); +} + +void hdmi_config_video(struct hdmi_info_t *info) +{ + hdmi_set_output_colfmt(info->outfmt); + hdmi_tx_avi_infoframe_packet(info->outfmt, info->vic); + hdmi_tx_vendor_specific_infoframe_packet(); +} + +void hdmi_set_option(unsigned int option) +{ + vdo_color_fmt colfmt; + int temp; + + hdmi_set_dvi_enable((option & EDID_OPT_HDMI) ? + VPP_FLAG_DISABLE : VPP_FLAG_ENABLE); + hdmi_audio_enable((option & EDID_OPT_AUDIO) ? + VPP_FLAG_ENABLE : VPP_FLAG_DISABLE); + + colfmt = hdmi_get_output_colfmt(); + switch (colfmt) { + case VDO_COL_FMT_YUV422H: + temp = option & EDID_OPT_YUV422; + break; + case VDO_COL_FMT_YUV444: + temp = option & EDID_OPT_YUV444; + break; + default: + temp = 1; + break; + } + if (temp == 0) { + hdmi_set_output_colfmt(VDO_COL_FMT_ARGB); + DBG_MSG("[HDMI] TV not support %s,use default RGB\n", + vpp_colfmt_str[colfmt]); + } + DBG_MSG("[HDMI] set option(8-HDMI,6-AUDIO) 0x%x\n", option); +} + +void hdmi_config(struct hdmi_info_t *info) +{ + struct vout_audio_t audio_info; + int h_porch; + int delay_cfg; + vpp_clock_t clock; + + hdmi_regs1->ctrl.b.hden = 0; + hdmi_regs1->infoframe_ctrl.b.select = 0; + hdmi_regs1->infoframe_ctrl.b.fifo1_rdy = 0; + hdmi_config_video(info); + + govrh_get_tg(p_govrh, &clock); + h_porch = clock.total_pixel_of_line - clock.end_pixel_of_active; /*fp*/ + delay_cfg = 47 - h_porch; + if (delay_cfg <= 0) + delay_cfg = 1; + h_porch = clock.begin_pixel_of_active; /* bp */ + h_porch = (h_porch - (delay_cfg + 1) - 26) / 32; + if (h_porch <= 0) + h_porch = 1; + if (h_porch >= 8) + h_porch = 0; + + hdmi_regs1->general_ctrl.b.cp_delay = delay_cfg; + hdmi_regs1->general_ctrl.b.vsync_enable = 1; /* for write only */ + hdmi_regs1->infoframe_ctrl.b.horiz_blank_max_pck = h_porch; + DBGMSG("[HDMI] H blank max pck %d,delay %d\n", h_porch, delay_cfg); + + audio_info.fmt = 16; + audio_info.channel = info->channel; + audio_info.sample_rate = info->freq; + hdmi_config_audio(&audio_info); + + hdmi_regs1->infoframe_ctrl.b.fifo1_addr = 0; + hdmi_regs1->infoframe_ctrl.b.fifo1_len = 2; + hdmi_regs1->infoframe_ctrl.b.fifo1_rdy = 1; + hdmi_set_option(info->option); + hdmi_regs2->test.b.tre_en = + (g_vpp.hdmi_pixel_clock < 40000000) ? 3 : 2; +} + +/*----------------------- Module API --------------------------------------*/ +void hdmi_set_cp_enable(vpp_flag_t enable) +{ + if (!g_vpp.hdmi_cp_enable) + enable = 0; + + if (hdmi_cp) + hdmi_cp->enable(enable); + +#ifdef __KERNEL__ + if (hdmi_cp && hdmi_cp->poll) { + vpp_irqproc_del_work(VPP_INT_GOVRH_VBIS, (void *)hdmi_cp->poll); + if (enable) + vpp_irqproc_work(VPP_INT_GOVRH_VBIS, + (void *)hdmi_cp->poll, 0, 0, 0); + } +#endif +} + +int hdmi_check_cp_int(void) +{ + int ret = 0; + + if (hdmi_cp) + ret = hdmi_cp->interrupt(); + return ret; +} + +void hdmi_get_bksv(unsigned int *bksv) +{ + if (hdmi_cp) + hdmi_cp->get_bksv(bksv); +} + +#ifdef __KERNEL__ +void hdmi_hotplug_notify(int plug_status) +{ + if (g_vpp.hdmi_disable) + return; + vpp_netlink_notify_plug(VPP_VOUT_NUM_HDMI, plug_status); +} +#else +#define hdmi_hotplug_notify +#endif + +int hdmi_check_plugin(int hotplug) +{ + static int last_plugin = -1; + int plugin; + int flag; + + if (g_vpp.hdmi_disable) + return 0; + + plugin = hdmi_get_plugin(); + hdmi_clear_plug_status(); +#ifdef __KERNEL__ + /* disable HDMI before change clock */ + if (plugin == 0) { + hdmi_set_enable(0); + hdmi_set_power_down(1); + } + vpp_set_clock_enable(DEV_HDMII2C, plugin, 1); + vpp_set_clock_enable(DEV_HDCE, plugin, 1); + + /* slow down clock for plugout */ + flag = (auto_pll_divisor(DEV_HDMILVDS, GET_FREQ, 0, 0) + == 8000000) ? 0 : 1; + if ((plugin != flag) && !g_vpp.virtual_display) { + int pixclk; + + pixclk = (plugin) ? g_vpp.hdmi_pixel_clock : 8000000; + auto_pll_divisor(DEV_HDMILVDS, SET_PLLDIV, 0, pixclk); + } +#endif + if (last_plugin != plugin) { + DPRINT("[HDMI] HDMI plug%s,hotplug %d\n", (plugin) ? + "in" : "out", hotplug); + last_plugin = plugin; + } +#if 0 /* Denzel test */ + if (plugin == 0) + hdmi_set_dvi_enable(VPP_FLAG_ENABLE); +#endif + return plugin; +} + +void hdmi_reg_dump(void) +{ + DPRINT("========== HDMI register dump ==========\n"); + vpp_reg_dump(REG_HDMI_BEGIN, REG_HDMI_END - REG_HDMI_BEGIN); + vpp_reg_dump(REG_HDMI2_BEGIN, REG_HDMI2_END - REG_HDMI2_BEGIN); + + DPRINT("---------- HDMI common ----------\n"); + DPRINT("enable %d,hden %d,reset %d,dvi %d\n", + hdmi_regs1->general_ctrl.b.enable, + hdmi_regs1->ctrl.b.hden, + hdmi_regs1->general_ctrl.b.reset, + hdmi_regs1->general_ctrl.b.dvi_mode_enable); + DPRINT("colfmt %d,conv 422 %d,hsync low %d,vsync low %d\n", + hdmi_regs1->general_ctrl.b.output_format, + hdmi_regs1->general_ctrl.b.convert_yuv422, + hdmi_regs1->general_ctrl.b.hsync_low_active, + hdmi_regs1->general_ctrl.b.vsync_low_active); + DPRINT("dbg bus sel %d,state mach %d\n", + hdmi_regs1->general_ctrl.b.dbg_bus_select, + hdmi_regs1->general_ctrl.b.state_machine_status); + DPRINT("eep reset %d,encode %d,eess %d\n", + hdmi_regs1->ctrl.b.eeprom_reset, + hdmi_regs1->ctrl.b.encode_enable, + hdmi_regs1->ctrl.b.eess_enable); + DPRINT("verify pj %d,auth test %d,cipher %d\n", + hdmi_regs1->ctrl.b.verify_pj_enable, + hdmi_regs1->ctrl.b.auth_test_key, + hdmi_regs1->ctrl.b.cipher_1_1); + DPRINT("preamble %d\n", hdmi_regs1->ctrl.b.preamble); + + DPRINT("---------- HDMI hotplug ----------\n"); + DPRINT("plug %s\n", (hdmi_regs1->hotplug_detect.b.sts) ? "in" : "out"); + DPRINT("plug in enable %d, status %d\n", + hdmi_regs1->hotplug_detect.b.in_enable, + hdmi_regs1->hotplug_detect.b.in_sts); + DPRINT("plug out enable %d, status %d\n", + hdmi_regs1->hotplug_detect.b.out_enable, + hdmi_regs1->hotplug_detect.b.out_sts); + DPRINT("debounce detect %d,sample %d\n", + hdmi_regs1->hotplug_debounce.b.detect, + hdmi_regs1->hotplug_debounce.b.sample); + + DPRINT("---------- I2C ----------\n"); + DPRINT("enable %d,exit FSM %d,key read %d\n", + hdmi_regs1->ctrl.b.i2c_enable, + hdmi_regs1->i2c_ctrl.b.force_exit_fsm, + hdmi_regs1->i2c_ctrl.b.key_read_word); + DPRINT("clk divid %d,rd data 0x%x,wr data 0x%x\n", + hdmi_regs1->i2c_ctrl.b.i2c_clk_divider, + hdmi_regs1->i2c_ctrl2.b.rd_data, + hdmi_regs1->i2c_ctrl2.b.wr_data); + DPRINT("start %d,stop %d,wr avail %d\n", + hdmi_regs1->i2c_ctrl2.b.sw_start_req, + hdmi_regs1->i2c_ctrl2.b.sw_stop_req, + hdmi_regs1->i2c_ctrl2.b.wr_data_avail); + DPRINT("status %d,sw read %d,sw i2c req %d\n", + hdmi_regs1->i2c_ctrl2.b.i2c_status, + hdmi_regs1->i2c_ctrl2.b.sw_read, + hdmi_regs1->i2c_ctrl2.b.sw_i2c_req); + + DPRINT("---------- AUDIO ----------\n"); + DPRINT("enable %d,sub pck %d,spflat %d\n", + hdmi_regs1->aud_enable, + hdmi_regs1->aud_mode.b.sub_packet, + hdmi_regs1->aud_mode.b.spflat); + DPRINT("aud pck insert reset %d,enable %d,delay %d\n", + hdmi_regs1->aud_insert_ctrl.b.pck_insert_reset, + hdmi_regs1->aud_insert_ctrl.b.pck_insert_enable, + hdmi_regs1->aud_insert_ctrl.b.insert_delay); + DPRINT("avmute set %d,clr %d,pixel repete %d\n", + hdmi_regs1->aud_insert_ctrl.b.avmute_set_enable, + hdmi_regs1->aud_insert_ctrl.b.avmute_clr_enable, + hdmi_regs1->aud_insert_ctrl.b.pixel_repetition); + DPRINT("acr ratio %d,acr enable %d,mute %d\n", + hdmi_regs1->aud_ratio.b.acr_ratio, + hdmi_regs1->aud_ratio.b.acr_enable, + hdmi_regs1->aud_ratio.b.mute); + DPRINT("layout %d,pwr save %d,n 20bits %d\n", + hdmi_regs1->aud_mode.b.layout, + hdmi_regs1->aud_mode.b.pwr_saving, + hdmi_regs1->aud_sample_rate1.b.n_20bits); + DPRINT("cts low 12 %d,hi 8 %d,cts sel %d\n", + hdmi_regs1->aud_sample_rate1.b.cts_low_12bits, + hdmi_regs1->aud_sample_rate2.b.cts_hi_8bits, + hdmi_regs1->aud_sample_rate2.b.cts_select); + DPRINT("aipclk rate %d\n", hdmi_regs1->aud_sample_rate2.b.aipclk_rate); + + DPRINT("---------- INFOFRAME ----------\n"); + DPRINT("sel %d,hor blank pck %d\n", + hdmi_regs1->infoframe_ctrl.b.select, + hdmi_regs1->infoframe_ctrl.b.horiz_blank_max_pck); + DPRINT("fifo1 ready %d,addr 0x%x,len %d\n", + hdmi_regs1->infoframe_ctrl.b.fifo1_rdy, + hdmi_regs1->infoframe_ctrl.b.fifo1_addr, + hdmi_regs1->infoframe_ctrl.b.fifo1_len); + DPRINT("fifo2 ready %d,addr 0x%x,len %d\n", + hdmi_regs1->infoframe_ctrl.b.fifo2_rdy, + hdmi_regs1->infoframe_ctrl.b.fifo2_addr, + hdmi_regs1->infoframe_ctrl.b.fifo2_len); + DPRINT("wr strobe %d,rd strobe %d,fifo addr %d\n", + hdmi_regs1->fifo_ctrl.b.wr_strobe, + hdmi_regs1->fifo_ctrl.b.rd_strobe, + hdmi_regs1->fifo_ctrl.b.addr); + + { + int i; + unsigned int buf[32]; + + for (i = 0; i <= hdmi_regs1->infoframe_ctrl.b.fifo1_len; i++) { + DPRINT("----- infoframe %d -----\n", i); + hdmi_read_fifo(i, buf, 32); + vpp_reg_dump((unsigned int) buf, 32); + } + } + + DPRINT("---------- HDMI test ----------\n"); + DPRINT("ch0 enable %d, data 0x%x\n", + hdmi_regs1->channel_test.b.ch0_enable, + hdmi_regs1->channel_test.b.ch0_data); + DPRINT("ch1 enable %d, data 0x%x\n", + hdmi_regs1->channel_test.b.ch1_enable, + hdmi_regs1->channel_test.b.ch1_data); + DPRINT("ch2 enable %d, data 0x%x\n", + hdmi_regs1->hotplug_detect.b.ch2_enable, + hdmi_regs1->hotplug_detect.b.ch2_data); + if (hdmi_cp) + hdmi_cp->dump(); +} + +#ifdef CONFIG_PM +static unsigned int *hdmi_pm_bk; +static unsigned int *hdmi_pm_bk2; +static unsigned int hdmi_pm_enable; +static unsigned int hdmi_pm_enable2; +static int hdmi_plug_enable = 0xFF; +static int hdmi_resume_plug_cnt; +#define HDMI_RESUME_PLUG_MS 50 +#define HDMI_RESUME_PLUG_CNT 20 +static void hdmi_do_resume_plug(struct work_struct *ptr) +{ + struct vout_t *vo; + int plugin; + struct delayed_work *dwork = to_delayed_work(ptr); + + plugin = hdmi_check_plugin(0); + vo = vout_get_entry(VPP_VOUT_NUM_HDMI); + vout_change_status(vo, VPP_VOUT_STS_PLUGIN, plugin); + if (plugin) + hdmi_hotplug_notify(1); + hdmi_resume_plug_cnt--; + if (hdmi_resume_plug_cnt && (vpp_sdev.state == 0)) + schedule_delayed_work(dwork, + msecs_to_jiffies(HDMI_RESUME_PLUG_MS)); +} + +DECLARE_DELAYED_WORK(hdmi_resume_work, hdmi_do_resume_plug); + +void hdmi_suspend(int sts) +{ + vo_hdmi_set_clock(1); + switch (sts) { + case 0: /* disable module */ + cancel_delayed_work_sync(&hdmi_resume_work); + hdmi_pm_enable = hdmi_regs1->general_ctrl.b.enable; + hdmi_regs1->general_ctrl.b.enable = 0; + hdmi_regs1->general_ctrl.b.vsync_enable = 1; /* for wr only */ + hdmi_pm_enable2 = hdmi_regs1->ctrl.b.hden; + hdmi_regs1->ctrl.b.hden = 0; + if (hdmi_plug_enable == 0xFF) + hdmi_plug_enable = + hdmi_regs1->hotplug_detect.b.out_enable; + hdmi_enable_plugin(0); + break; + case 1: /* disable tg */ + break; + case 2: /* backup register */ + hdmi_pm_bk = vpp_backup_reg(REG_HDMI_BEGIN, + (REG_HDMI_END - REG_HDMI_BEGIN)); + hdmi_pm_bk2 = vpp_backup_reg(REG_HDMI2_BEGIN, + (REG_HDMI2_END - REG_HDMI2_BEGIN)); + hdmi_resume_plug_cnt = 20; + break; + default: + break; + } + vo_hdmi_set_clock(0); +} + +void hdmi_resume(int sts) +{ + vo_hdmi_set_clock(1); + switch (sts) { + case 0: /* restore register */ + switch_set_state(&vpp_sdev, 0); + vpp_restore_reg(REG_HDMI_BEGIN, + (REG_HDMI_END - REG_HDMI_BEGIN), hdmi_pm_bk); + vpp_restore_reg(REG_HDMI2_BEGIN, + (REG_HDMI2_END - REG_HDMI2_BEGIN), hdmi_pm_bk2); + hdmi_pm_bk = 0; + hdmi_pm_bk2 = 0; + hdmi_config(&hdmi_info); /* re-config HDMI info frame */ + if (g_vpp.hdmi_cp_p && hdmi_cp) + hdmi_cp->init(); + break; + case 1: /* enable module */ + hdmi_regs1->general_ctrl.b.enable = hdmi_pm_enable; + hdmi_regs1->general_ctrl.b.vsync_enable = 1; /* for wr only */ + hdmi_regs1->ctrl.b.hden = hdmi_pm_enable2; + break; + case 2: /* enable tg */ + hdmi_check_plugin(0); + hdmi_clear_plug_status(); + hdmi_enable_plugin(hdmi_plug_enable); + hdmi_plug_enable = 0xFF; + if (vpp_sdev.state == 0) { + hdmi_resume_plug_cnt = HDMI_RESUME_PLUG_CNT; + schedule_delayed_work(&hdmi_resume_work, + msecs_to_jiffies(HDMI_RESUME_PLUG_MS)); + } + break; + default: + break; + } + vo_hdmi_set_clock(0); +} +#else +#define hdmi_suspend NULL +#define hdmi_resume NULL +#endif + +void hdmi_init(void) +{ + struct fb_videomode vmode; + + g_vpp.hdmi_pixel_clock = vpp_get_base_clock(VPP_MOD_GOVRH); + g_vpp.hdmi_i2c_freq = HDMI_I2C_FREQ; + g_vpp.hdmi_i2c_udelay = 0; + g_vpp.hdmi_ctrl = 0x1000000; + g_vpp.hdmi_audio_pb4 = 0x0; + g_vpp.hdmi_audio_pb1 = 0x0; + + hdmi_info.outfmt = hdmi_get_output_colfmt(); + govrh_get_videomode(p_govrh, &vmode); + hdmi_info.vic = hdmi_get_vic(vmode.xres, vmode.yres, vmode.refresh, + (vmode.vmode & FB_VMODE_INTERLACED) ? 1 : 0); + hdmi_info.channel = 2; + hdmi_info.freq = 48000; + hdmi_info.option = EDID_OPT_AUDIO + EDID_OPT_HDMI; + + hdmi_enable_plugin(0); + + if (g_vpp.govrh_preinit) { + DBGMSG("[HDMI] hdmi_init for uboot logo\n"); + } else { + /* bit8-HDMI SDA,bit9-HDMI SCL,bit10-Hotplug,bit26-CEC */ + /* GPIO disable GPIO function */ + vppif_reg32_write(GPIO_BASE_ADDR+0x54, 0x4000700, 0, 0); + /* GPIO4 disable GPIO out */ + vppif_reg32_write(GPIO_BASE_ADDR+0x494, 0x4000700, 0, 0); +#if 0 + /* Suspend GPIO output enable */ + vppif_reg32_write(GPIO_BASE_ADDR+0x80, BIT23, 23, 1); + /* Suspend GPIO output high */ + vppif_reg32_write(GPIO_BASE_ADDR+0xC0, BIT23, 23, 1); + /* Wake3 disable pull ctrl */ + vppif_reg32_write(GPIO_BASE_ADDR+0x480, BIT19, 19, 0); +#endif + hdmi_regs2->level.b.level = 1; + hdmi_regs2->level.b.update = 1; + hdmi_regs2->igs.b.ldi_shift_left = 1; + hdmi_regs2->status.val = 0x0008c000; + hdmi_regs2->test.val = 0x00450409; + hdmi_regs2->test2.val = 0x00005022; + hdmi_regs2->test3 = (g_vpp.hdmi_sp_mode) ? + 0x00010100 : 0x00000100; + hdmi_set_enable(VPP_FLAG_DISABLE); + hdmi_set_dvi_enable(VPP_FLAG_DISABLE); + hdmi_regs1->ctrl.b.cipher_1_1 = 0; + + hdmi_regs1->tmds_ctrl.b.infoframe_sram_enable = 1; + hdmi_regs1->infoframe_ctrl.b.select = 0; + hdmi_regs1->infoframe_ctrl.b.fifo1_rdy = 0; + + hdmi_regs1->hotplug_detect.val = 0x0; + hdmi_regs1->channel_test.val = 0x1; + + hdmi_DDC_reset(); + hdmi_DDC_set_freq(g_vpp.hdmi_i2c_freq); + hdmi_regs1->ctrl.b.i2c_enable = 1; + } + g_vpp.hdmi_init = 1; + if (hdmi_cp) + hdmi_cp->init(); +} +#endif /* WMT_FTBLK_HDMI */ |