/*++ * 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 . * * 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 #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 */