diff --git a/arch/arm64/boot/dts/amlogic/t3x_t968d4_bc302.dts b/arch/arm64/boot/dts/amlogic/t3x_t968d4_bc302.dts index 6ad06960e..09dcb9886 100644 --- a/arch/arm64/boot/dts/amlogic/t3x_t968d4_bc302.dts +++ b/arch/arm64/boot/dts/amlogic/t3x_t968d4_bc302.dts @@ -628,7 +628,7 @@ 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xfe390000 0x0 0x20000 - 0x0 0xfe000000 0x0 0x1fff + 0x0 0xfe000000 0x0 0x15000 0x0 0xfe008000 0x280 0x334>; }; diff --git a/drivers/media/vin/tvin/hdmirx/hdmi_rx_drv.h b/drivers/media/vin/tvin/hdmirx/hdmi_rx_drv.h index 40cf93397..d37d9fb03 100644 --- a/drivers/media/vin/tvin/hdmirx/hdmi_rx_drv.h +++ b/drivers/media/vin/tvin/hdmirx/hdmi_rx_drv.h @@ -770,6 +770,11 @@ struct emp_info_s { u8 data_ver; }; +struct i2c_info_s { + phys_addr_t phy_addr; + struct page *pg_addr; +}; + struct spkts_rcvd_sts { u32 pkt_vsi_rcvd:1; u32 pkt_drm_rcvd:1; @@ -840,6 +845,7 @@ struct rx_info_s { struct rx_aml_phy aml_phy_21; struct emp_info_s emp_buff_a; //for vid0 struct emp_info_s emp_buff_b; //for vid1 + struct i2c_info_s i2c_buff; struct edid_capacity edid_cap; bool suspend_flag; }; diff --git a/drivers/media/vin/tvin/hdmirx/hdmi_rx_hw.c b/drivers/media/vin/tvin/hdmirx/hdmi_rx_hw.c index 4b70a2b50..76aeee781 100644 --- a/drivers/media/vin/tvin/hdmirx/hdmi_rx_hw.c +++ b/drivers/media/vin/tvin/hdmirx/hdmi_rx_hw.c @@ -6026,6 +6026,9 @@ int rx_debug_wr_reg(const char *buf, char *tmpbuf, int i, u8 port) } else if (buf[2] == 'A') { hdmirx_wr_amlphy_t3x(adr, value, port); rx_pr("write %x to port%d [%x]\n", value, port, adr); + } else if (buf[2] == 'c') { + wr_reg_clk_ctl(adr, value); + rx_pr("write %x to [%x]\n", value, adr); } } return 0; @@ -6072,6 +6075,9 @@ int rx_debug_rd_reg(const char *buf, char *tmpbuf, u8 port) } else if (buf[2] == 'A') { value = hdmirx_rd_amlphy_t3x(adr, port); rx_pr("port%d, amlphy [%x]=%x\n", port, adr, value); + } else if (buf[2] == 'c') { + value = rd_reg_clk_ctl(adr); + rx_pr("amlphy [%x]=%x\n", adr, value); } } return 0; diff --git a/drivers/media/vin/tvin/hdmirx/hdmi_rx_hw.h b/drivers/media/vin/tvin/hdmirx/hdmi_rx_hw.h index f9c2cb1fd..e6e4664e1 100644 --- a/drivers/media/vin/tvin/hdmirx/hdmi_rx_hw.h +++ b/drivers/media/vin/tvin/hdmirx/hdmi_rx_hw.h @@ -3430,6 +3430,7 @@ unsigned int hdmirx_rd_amlphy(unsigned int addr); unsigned int hdmirx_rd_amlphy_t3x(unsigned int addr, u8 port); void hdmirx_irq_hdcp_enable(bool enable, u8 port); u8 rx_get_avmute_sts(u8 port); +void wr_reg_ana_ctl(u32 offset, u32 val); u8 hdmirx_rd_cor(u32 addr, u8 port); void hdmirx_wr_cor(u32 addr, u8 data, u8 port); bool hdmirx_poll_cor(u32 addr, u8 exp_data, u8 mask, u32 max_try, u8 port); diff --git a/drivers/media/vin/tvin/hdmirx/hdmi_rx_hw_t3x.c b/drivers/media/vin/tvin/hdmirx/hdmi_rx_hw_t3x.c index 319bbdae1..ab3a6b7f2 100644 --- a/drivers/media/vin/tvin/hdmirx/hdmi_rx_hw_t3x.c +++ b/drivers/media/vin/tvin/hdmirx/hdmi_rx_hw_t3x.c @@ -60,7 +60,8 @@ int vga_tuning_min = 0x21; int vga_tuning_max = 0x26; int cal_phy_time; enum frl_train_sts_e frl_train_sts = E_FRL_TRAIN_START; - +/* i2c monitor */ +#define I2C_BUFF_SIZE 0x1000 /* for T3X 2.0 */ static const u32 phy_misc_t3x_20[][2] = { /* 0x18 0x1c */ @@ -4825,6 +4826,208 @@ bool is_frl_train_finished(void) return ret; } +void rx_i2c_dbg_monitor(void) +{ + u32 data32; + + if (rx_info.chip_id != CHIP_ID_T3X) + return; + data32 = rd_reg_clk_ctl(T3X_I2C_MONITOR_INTR_STATUS); + + if (data32 > 3) { //ignore start abnormal + wr_reg_clk_ctl(T3X_I2C_MONITOR_SMP_START, 0x0); + rx_i2c_dump(); + wr_reg_clk_ctl(T3X_I2C_MONITOR_INTR_STATUS, data32); + } +} + +static void rx_parse_i2c_data(u8 *buf, int size) +{ + static const char * const ack_print[] = {"ACK", "NAK"}; + static const char * const wr_print[] = {"Write", "Read"}; + u8 type, data, ack, wr; + int i; + + if (!buf || size < 4) + return; + for (i = 0; i < size; i += 4) { + /* + * |31..29|28.......9|8..1| 0| + * |type |delta time|data|ack| + */ + if (!buf[i] && !buf[i + 1] && !buf[i + 2] && !buf[i + 3]) + break; + type = (buf[i + 3] & MSK(3, 5)) >> 5; + data = (buf[i] & MSK(7, 1)) >> 1 | (buf[i + 1] & 0x1) << 7; + ack = buf[i] & 0x1; + wr = data & 0x1; + + switch (type) { + case E_DATA: + rx_pr("0x%x + %s\n", data, ack_print[ack]); + break; + case E_START_DATA: + rx_pr("%s to [0x%x] + %s\n", wr_print[wr], data, ack_print[ack]); + break; + case E_STOP_DATA: + rx_pr("0x%x + %s + Stop\n", data, ack_print[ack]); + break; + case E_START_DATA_STOP: + rx_pr("%s to [0x%x] + %s + Stop\n", wr_print[wr], data, ack_print[ack]); + break; + case E_STOP_ABNORMAL: + rx_pr("!!STOP Abnormal(incomplete data)\n"); + break; + case E_START_ABNORMAL: + if (ack) { + rx_pr("!!Start Abnormal: %s to [0x%x] + %s\n", + wr_print[wr], data, ack_print[ack]); + } else { + rx_pr("!!Start Abnormal(incomplete data)\n"); + } + break; + case E_TIME_OUT: + if (ack) + rx_pr("!!time out(no data)\n"); + else + rx_pr("!!time out + 0x%x\n", data); + break; + default: + if ((data >> 5) == 0) { + if (ack) + rx_pr("HPD rise\n"); + else + rx_pr("HPD fall\n"); + } else { + rx_pr("!!other type:0x%x\n", data); + } + break; + } + } + rx_pr("i:0x%x\n", i); +} + +void rx_i2c_monitor(u8 sel, u8 smp_mod, u8 trig_mod, u8 dump_mod) +{ + u8 *src = NULL; + u32 data32; + + data32 = 0; + data32 |= (smp_mod == 3 ? 1 : 0) << 31; //[31] bist_mode exist bug, can't use + data32 |= (dump_mod & 0x1f) << 16; //[20-16]dump mode + data32 |= 0x0 << 4; //[4] clk_free + data32 |= (smp_mod & 0x3) << 2; //[3:2] smp_mode + data32 |= 0x1 << 1; //[1] hpd_en + data32 |= (trig_mod & 0x1) << 0; //[0] trig_mode + wr_reg_clk_ctl(T3X_I2C_MONITOR_SMP_CNTL, data32); + + data32 = 0; + data32 |= (sel >= 6 ? 1 << (sel - 6) : 0) << 24; //[31:24] sel input hpd to monitor + data32 |= (1 << sel) << 0; //[23:0] sel input scl to monitor + wr_reg_clk_ctl(T3X_I2C_MONITOR_SMP_SEL, data32); + + data32 = 0; + data32 |= 0x2008 << 16; //[31:16] scl filter control + data32 |= 0x2008 << 0; //[15: 0] sda filter control + wr_reg_clk_ctl(T3X_I2C_MONITOR_SMP_FLT, data32); + + data32 = 0; + data32 |= 0x7 << 0; //[15: 0] sda filter control + wr_reg_clk_ctl(T3X_I2C_MONITOR_SMP_FLT_HPD, data32); + + data32 = 0; + data32 |= 0xa << 16; //[31:16] time tick in smp_clk + data32 |= 0x1 << 8; //[ 8] smp_clk enable + data32 |= 0x5 << 0; //[ 7: 0] smp_clk div, cec sample:0x48 + wr_reg_clk_ctl(T3X_I2C_MONITOR_SMP_CLK, data32); + + data32 = 0; + data32 |= 0x3ff << 0; //[10:0] + wr_reg_clk_ctl(T3X_I2C_MONITOR_INTR_MASK, data32); + + rx_info.i2c_buff.pg_addr = alloc_pages(GFP_KERNEL, 0); + src = (u8 *)kmap_atomic(rx_info.i2c_buff.pg_addr); + memset(src, 0x0, I2C_BUFF_SIZE); + kunmap_atomic(src); + rx_info.i2c_buff.phy_addr = page_to_phys(rx_info.i2c_buff.pg_addr); + + if (rx_info.i2c_buff.phy_addr) { + wr_reg_clk_ctl(T3X_I2C_MONITOR_DDR_START_ADDR, + rx_info.i2c_buff.phy_addr >> 4); + wr_reg_clk_ctl(T3X_I2C_MONITOR_DDR_END_ADDR, + (rx_info.i2c_buff.phy_addr + I2C_BUFF_SIZE) >> 4); + } + + data32 = 0; + data32 |= 0x1 << 4; //[ 4] endian in 32 bit + data32 |= 0x0 << 0; //[3:0] burst length + wr_reg_clk_ctl(T3X_I2C_MONITOR_DDR_CNTL, data32); + + //smp start,config this bit after all the other reg has been ready + wr_reg_clk_ctl(T3X_I2C_MONITOR_SMP_START, 0x1); +} + +static void rx_i2c_reg_dump(void) +{ + rx_pr("T3X_I2C_MONITOR_SMP_CNTL: 0x%x-0x%x\n", T3X_I2C_MONITOR_SMP_CNTL, + rd_reg_clk_ctl(T3X_I2C_MONITOR_SMP_CNTL)); + rx_pr("T3X_I2C_MONITOR_SMP_SEL: 0x%x-0x%x\n", T3X_I2C_MONITOR_SMP_SEL, + rd_reg_clk_ctl(T3X_I2C_MONITOR_SMP_SEL)); + rx_pr("T3X_I2C_MONITOR_SMP_FLT: 0x%x-0x%x\n", T3X_I2C_MONITOR_SMP_FLT, + rd_reg_clk_ctl(T3X_I2C_MONITOR_SMP_FLT)); + rx_pr("T3X_I2C_MONITOR_SMP_FLT_HPD: 0x%x-0x%x\n", T3X_I2C_MONITOR_SMP_FLT_HPD, + rd_reg_clk_ctl(T3X_I2C_MONITOR_SMP_FLT_HPD)); + rx_pr("T3X_I2C_MONITOR_SMP_CLK: 0x%x-0x%x\n", T3X_I2C_MONITOR_SMP_CLK, + rd_reg_clk_ctl(T3X_I2C_MONITOR_SMP_CLK)); + rx_pr("T3X_I2C_MONITOR_INTR_MASK: 0x%x-0x%x\n", T3X_I2C_MONITOR_INTR_MASK, + rd_reg_clk_ctl(T3X_I2C_MONITOR_INTR_MASK)); + rx_pr("T3X_I2C_MONITOR_DDR_START_ADDR: 0x%x-0x%x\n", T3X_I2C_MONITOR_DDR_START_ADDR, + rd_reg_clk_ctl(T3X_I2C_MONITOR_DDR_START_ADDR)); + rx_pr("T3X_I2C_MONITOR_DDR_END_ADDR: 0x%x-0x%x\n", T3X_I2C_MONITOR_DDR_END_ADDR, + rd_reg_clk_ctl(T3X_I2C_MONITOR_DDR_END_ADDR)); + rx_pr("T3X_I2C_MONITOR_DDR_CNTL: 0x%x-0x%x\n", T3X_I2C_MONITOR_DDR_CNTL, + rd_reg_clk_ctl(T3X_I2C_MONITOR_DDR_CNTL)); +} + +void rx_i2c_dump(void) +{ + //int i, j; + u8 *i2c_buff = NULL; + u8 *src_buf = NULL; + int buf_cnt; + + if (log_level & REG_LOG) + rx_i2c_reg_dump(); + + i2c_buff = kmalloc(I2C_BUFF_SIZE, GFP_KERNEL); + if (!i2c_buff) + return; + memset(i2c_buff, 0, I2C_BUFF_SIZE); + src_buf = (u8 *)kmap_atomic(rx_info.i2c_buff.pg_addr); + if (!src_buf) { + kfree(i2c_buff); + return; + } + memcpy(i2c_buff, src_buf, I2C_BUFF_SIZE); + /* + *for (i = 0; i < 128; i++) { + * for (j = 0; j < 32; j++) + * pr_cont("%02X ", i2c_buff[i * 32 + j]); + * rx_pr("\n"); + *} + */ + kunmap_atomic(src_buf); + + buf_cnt = (rd_reg_clk_ctl(T3X_I2C_MONITOR_DDR_WPTR) - + rd_reg_clk_ctl(T3X_I2C_MONITOR_DDR_START_ADDR)) << 4; + rx_pr("buf_cnt:wptr:0x%x-start:0x%x=0x%x\n", + rd_reg_clk_ctl(T3X_I2C_MONITOR_DDR_WPTR) << 4, + rd_reg_clk_ctl(T3X_I2C_MONITOR_DDR_START_ADDR) << 4, + buf_cnt); + rx_parse_i2c_data(i2c_buff, I2C_BUFF_SIZE); + kfree(i2c_buff); +} + void rx_frl_train_handler(struct work_struct *work) { hdmi_tx_rx_frl_training_main(E_PORT2); diff --git a/drivers/media/vin/tvin/hdmirx/hdmi_rx_hw_t3x.h b/drivers/media/vin/tvin/hdmirx/hdmi_rx_hw_t3x.h index 8e2fbc9e4..fefec6dc1 100644 --- a/drivers/media/vin/tvin/hdmirx/hdmi_rx_hw_t3x.h +++ b/drivers/media/vin/tvin/hdmirx/hdmi_rx_hw_t3x.h @@ -134,6 +134,59 @@ #define T3X_CLKCTRL_AUD21_PLL_CTRL3 (0x02ed << 2) #define T3X_CLKCTRL_AUD21_PLL_STS (0x02ee << 2) +/* i2c monitor reg */ +#define T3X_I2C_MONITOR_BASE 0xfe014000 +#define T3X_I2C_MONITOR_SMP_START (0x14000 + (0x000 << 2)) +#define T3X_I2C_MONITOR_SMP_SEL (0x14000 + (0x001 << 2)) +#define T3X_I2C_MONITOR_SMP_CNTL (0x14000 + (0x002 << 2)) +#define T3X_I2C_MONITOR_SMP_FLT (0x14000 + (0x003 << 2)) +#define T3X_I2C_MONITOR_SMP_FLT_HPD (0x14000 + (0x004 << 2)) +#define T3X_I2C_MONITOR_SMP_I2C_TIMEOUT_TH (0x14000 + (0x005 << 2)) +#define T3X_I2C_MONITOR_SMP_CLK (0x14000 + (0x006 << 2)) +#define T3X_I2C_MONITOR_DDR_START_ADDR (0x14000 + (0x007 << 2)) +#define T3X_I2C_MONITOR_DDR_END_ADDR (0x14000 + (0x008 << 2)) +#define T3X_I2C_MONITOR_DDR_CNTL (0x14000 + (0x009 << 2)) +#define T3X_I2C_MONITOR_INTR_MASK (0x14000 + (0x00a << 2)) +#define T3X_I2C_MONITOR_DDR_WPTR (0x14000 + (0x00b << 2)) +#define T3X_I2C_MONITOR_DDR_BOUND_CNT (0x14000 + (0x00c << 2)) +#define T3X_I2C_MONITOR_AXI_CMD_PENDING (0x14000 + (0x00d << 2)) +#define T3X_I2C_MONITOR_SMP_STATUS (0x14000 + (0x00e << 2)) +#define T3X_I2C_MONITOR_SMP_I2C_BUSY_CNT (0x14000 + (0x00f << 2)) +#define T3X_I2C_MONITOR_AXI_STATUS (0x14000 + (0x010 << 2)) +#define T3X_I2C_MONITOR_INTR_STATUS (0x14000 + (0x011 << 2)) +#define T3X_I2C_MONITOR_AXI_CMD_CNT (0x14000 + (0x012 << 2)) + +enum i2c_sample_mode_e { + E_FUNC_SAMPLE, + E_I2C_WAVE_SAMPLE, + E_CEC_WAVE_SAMPLE, + E_BIST_MODE +}; + +enum i2c_trigger_mode_e { + E_HW_TRIGGER, + E_SW_TRIGGER +}; + +enum i2c_dump_mode_e { + E_ABNORMAL_START0 = 0x1, + E_ABNORMAL_START1 = 0x2, + E_ABNORMAL_STOP = 0x4, + E_I2C_TIMEOUT = 0x8, + E_HPD_CHANGE = 0x10, + E_DUMP_ALL = 0x1f +}; + +enum i2c_data_type_e { + E_DATA, + E_START_DATA, + E_STOP_DATA, + E_START_DATA_STOP, + E_STOP_ABNORMAL, + E_START_ABNORMAL, + E_TIME_OUT +}; + enum frl_train_sts_e { E_FRL_TRAIN_START, E_FRL_TRAIN_FINISH, @@ -230,6 +283,9 @@ bool is_fsm_ready_t3x(void); bool rx_get_clkready_sts(u8 port); bool rx_get_valid_m_sts(u8 port); +void rx_i2c_dbg_monitor(void); +void rx_i2c_monitor(u8 sel, u8 smp_mod, u8 trig_mod, u8 dump_mod); +void rx_i2c_dump(void); //void reset_pcs(void); /*function declare end*/ diff --git a/drivers/media/vin/tvin/hdmirx/hdmi_rx_wrapper.c b/drivers/media/vin/tvin/hdmirx/hdmi_rx_wrapper.c index 455ae4dab..8b8a08c16 100644 --- a/drivers/media/vin/tvin/hdmirx/hdmi_rx_wrapper.c +++ b/drivers/media/vin/tvin/hdmirx/hdmi_rx_wrapper.c @@ -8413,6 +8413,12 @@ int hdmirx_debug(const char *buf, int size) rx_pr("phy_addr = 0x%x, size = 0x%x, maped:%px\n", rx_reg_maps[i].phy_addr, size, rx_reg_maps[i].p); } + } else if (strncmp(tmpbuf, "i2c_monitor", 10) == 0) { + rx_i2c_monitor(6 + port, E_FUNC_SAMPLE, E_SW_TRIGGER, E_DUMP_ALL); + rx_pr("i2c_monitor start\n"); + } else if (strncmp(tmpbuf, "i2c_dump", 7) == 0) { + rx_pr("i2c_dump\n"); + rx_i2c_dump(); } return 0; } @@ -8699,6 +8705,7 @@ void hdmirx_timer_handler(struct timer_list *t) rx_clkmsr_monitor(); rx_hpd_monitor(); rx_edid_monitor(); + rx_i2c_dbg_monitor(); if (rx_info.chip_id == CHIP_ID_T3X) hdmirx_timer_t3x(); else