From 749fe7836d2f4d8484466656371c0b5664f90002 Mon Sep 17 00:00:00 2001 From: Chen Shunqing Date: Tue, 7 Nov 2023 01:53:24 +0000 Subject: [PATCH] media: i2c: rk628: bt1120: compatible with rk628f Change-Id: Ia7064e107a326d79bb40381cba3b1dfed31a72c1 Signed-off-by: Chen Shunqing --- drivers/media/i2c/rk628/rk628_bt1120_v4l2.c | 132 ++++++++++++++------ 1 file changed, 94 insertions(+), 38 deletions(-) diff --git a/drivers/media/i2c/rk628/rk628_bt1120_v4l2.c b/drivers/media/i2c/rk628/rk628_bt1120_v4l2.c index 96cc08fa66d8..854129ded2c7 100644 --- a/drivers/media/i2c/rk628/rk628_bt1120_v4l2.c +++ b/drivers/media/i2c/rk628/rk628_bt1120_v4l2.c @@ -44,7 +44,7 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "debug level (0-3)"); -#define DRIVER_VERSION KERNEL_VERSION(0, 0x0, 0x1) +#define DRIVER_VERSION KERNEL_VERSION(0, 0x1, 0x0) #define RK628_BT1120_NAME "rk628-bt1120" #define EDID_NUM_BLOCKS_MAX 2 @@ -246,8 +246,8 @@ static int rk628_bt1120_s_dv_timings(struct v4l2_subdev *sd, struct v4l2_dv_timings *timings); static int rk628_bt1120_s_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid); -static int rk628_hdmirx_phy_power_on(struct v4l2_subdev *sd); -static int rk628_hdmirx_phy_power_off(struct v4l2_subdev *sd); +static int rk628_hdmirx_inno_phy_power_on(struct v4l2_subdev *sd); +static int rk628_hdmirx_inno_phy_power_off(struct v4l2_subdev *sd); static int rk628_hdmirx_phy_setup(struct v4l2_subdev *sd); static void rk628_bt1120_format_change(struct v4l2_subdev *sd); static void enable_stream(struct v4l2_subdev *sd, bool enable); @@ -339,6 +339,7 @@ static int rk628_bt1120_get_detected_timings(struct v4l2_subdev *sd, u32 hofs_pix, hbp, hfp, vbp, vfp; u32 tmds_clk, tmdsclk_cnt; u64 tmp_data; + u8 video_fmt; int retry = 0; __retry: @@ -364,21 +365,25 @@ __retry: rk628_i2c_read(bt1120->rk628, HDMI_RX_MD_VOL, &val); vbp = (val & 0xffff) + 1; - rk628_i2c_read(bt1120->rk628, HDMI_RX_HDMI_CKM_RESULT, &val); - tmdsclk_cnt = val & 0xffff; + tmdsclk_cnt = rk628_hdmirx_get_tmdsclk_cnt(bt1120->rk628); tmp_data = tmdsclk_cnt; tmp_data = ((tmp_data * MODETCLK_HZ) + MODETCLK_CNT_NUM / 2); do_div(tmp_data, MODETCLK_CNT_NUM); tmds_clk = tmp_data; - if (!htotal || !vtotal) { + if (!htotal || !vtotal || bt->interlaced || vtotal > 3000) { v4l2_err(&bt1120->sd, "timing err, htotal:%d, vtotal:%d\n", htotal, vtotal); - if (retry++ < 5) + if (retry++ < 5) { + msleep(20); goto __retry; + } goto TIMING_ERR; } - fps = (tmds_clk + (htotal * vtotal) / 2) / (htotal * vtotal); + if (bt1120->rk628->version >= RK628F_VERSION) + fps = tmds_clk / (htotal * vtotal); + else + fps = (tmds_clk + (htotal * vtotal) / 2) / (htotal * vtotal); rk628_i2c_read(bt1120->rk628, HDMI_RX_MD_HT0, &val); modetclk_cnt_hs = val & 0xffff; @@ -392,15 +397,28 @@ __retry: vs = (vs + htotal / 2) / htotal; if ((hofs_pix < hs) || (htotal < (hact + hofs_pix)) || - (vtotal < (vact + vs + vbp))) { + (vtotal < (vact + vs + vbp)) || !vs) { v4l2_err(sd, "timing err, total:%dx%d, act:%dx%d, hofs:%d, hs:%d, vs:%d, vbp:%d\n", htotal, vtotal, hact, vact, hofs_pix, hs, vs, vbp); + if (retry++ < 5) { + msleep(20); + goto __retry; + } goto TIMING_ERR; } hbp = hofs_pix - hs; hfp = htotal - hact - hofs_pix; vfp = vtotal - vact - vs - vbp; + video_fmt = rk628_hdmirx_get_format(bt1120->rk628); + if (video_fmt == BUS_FMT_YUV420) { + htotal *= 2; + hact *= 2; + hfp *= 2; + hbp *= 2; + hs *= 2; + } + v4l2_dbg(2, debug, sd, "cnt_num:%d, tmds_cnt:%d, hs_cnt:%d, vs_cnt:%d, hofs:%d\n", MODETCLK_CNT_NUM, tmdsclk_cnt, modetclk_cnt_hs, modetclk_cnt_vs, hofs_pix); @@ -412,13 +430,18 @@ __retry: bt->vfrontporch = vfp; bt->vsync = vs; bt->vbackporch = vbp; - bt->pixelclock = htotal * vtotal * fps; + if (bt1120->rk628->version >= RK628F_VERSION) + bt->pixelclock = tmds_clk; + else + bt->pixelclock = htotal * vtotal * fps; if (bt->interlaced == V4L2_DV_INTERLACED) { bt->height *= 2; bt->il_vsync = bt->vsync + 1; bt->pixelclock /= 2; } + if (video_fmt == BUS_FMT_YUV420) + bt->pixelclock *= 2; v4l2_dbg(1, debug, sd, "SCDC_REGS1:%#x, act:%dx%d, total:%dx%d, fps:%d, pixclk:%llu\n", status, hact, vact, htotal, vtotal, fps, bt->pixelclock); @@ -509,8 +532,9 @@ static void rk628_bt1120_delayed_work_enable_hotplug(struct work_struct *work) cancel_delayed_work(&bt1120->delayed_work_res_change); rk628_hdmirx_audio_cancel_work_audio(bt1120->audio_info, true); rk628_hdmirx_hpd_ctrl(sd, false); - rk628_hdmirx_phy_power_off(sd); - rk628_hdmirx_controller_reset(sd); + rk628_hdmirx_inno_phy_power_off(sd); + if (bt1120->rk628->version < RK628F_VERSION) + rk628_hdmirx_controller_reset(sd); bt1120->nosignal = true; rk628_set_io_func_to_gpio(bt1120->rk628); } @@ -525,6 +549,9 @@ static int rk628_check_resulotion_change(struct v4l2_subdev *sd) u32 old_htotal, old_vtotal; struct v4l2_bt_timings *bt = &bt1120->src_timings.bt; + if (bt1120->rk628->version >= RK628F_VERSION) + return 1; + rk628_i2c_read(bt1120->rk628, HDMI_RX_MD_HT1, &val); htotal = (val >> 16) & 0xffff; rk628_i2c_read(bt1120->rk628, HDMI_RX_MD_VTL, &val); @@ -563,8 +590,9 @@ static void rk628_delayed_work_res_change(struct work_struct *work) cancel_delayed_work(&bt1120->delayed_work_res_change); rk628_hdmirx_audio_cancel_work_audio(bt1120->audio_info, true); rk628_hdmirx_hpd_ctrl(sd, false); - rk628_hdmirx_phy_power_off(sd); - rk628_hdmirx_controller_reset(sd); + rk628_hdmirx_inno_phy_power_off(sd); + if (bt1120->rk628->version < RK628F_VERSION) + rk628_hdmirx_controller_reset(sd); bt1120->nosignal = true; rk628_hdmirx_reset_regfile(sd); } else { @@ -724,7 +752,7 @@ static void rk628_post_process_setup(struct v4l2_subdev *sd) dst_bt->pixelclock = dst_pclk; } -static int rk628_hdmirx_phy_power_on(struct v4l2_subdev *sd) +static int rk628_hdmirx_inno_phy_power_on(struct v4l2_subdev *sd) { struct rk628_bt1120 *bt1120 = to_bt1120(sd); int ret, f; @@ -765,10 +793,13 @@ static int rk628_hdmirx_phy_power_on(struct v4l2_subdev *sd) return ret; } -static int rk628_hdmirx_phy_power_off(struct v4l2_subdev *sd) +static int rk628_hdmirx_inno_phy_power_off(struct v4l2_subdev *sd) { struct rk628_bt1120 *bt1120 = to_bt1120(sd); + if (bt1120->rk628->version >= RK628F_VERSION) + return 0; + if (bt1120->rxphy_pwron) { v4l2_dbg(1, debug, sd, "rxphy power off!\n"); rk628_rxphy_power_off(bt1120->rk628); @@ -815,6 +846,10 @@ static bool rk628_rcv_supported_res(struct v4l2_subdev *sd, u32 width, u32 height) { u32 i; + struct rk628_bt1120 *bt1120 = to_bt1120(sd); + + if (bt1120->rk628->version >= RK628F_VERSION) + return true; for (i = 0; i < ARRAY_SIZE(supported_modes); i++) { if ((supported_modes[i].width == width) && @@ -836,10 +871,13 @@ static int rk628_hdmirx_phy_setup(struct v4l2_subdev *sd) u32 i, cnt, val; u32 width, height, frame_width, frame_height, status; struct rk628_bt1120 *bt1120 = to_bt1120(sd); - int ret; + int ret = 0; for (i = 0; i < RXPHY_CFG_MAX_TIMES; i++) { - ret = rk628_hdmirx_phy_power_on(sd); + if (bt1120->rk628->version < RK628F_VERSION) + ret = rk628_hdmirx_inno_phy_power_on(sd); + else + rk628_hdmirx_verisyno_phy_power_on(bt1120->rk628); if (ret < 0) { msleep(50); continue; @@ -847,6 +885,7 @@ static int rk628_hdmirx_phy_setup(struct v4l2_subdev *sd) cnt = 0; do { + msleep(20); cnt++; rk628_i2c_read(bt1120->rk628, HDMI_RX_MD_HACT_PX, &val); width = val & 0xffff; @@ -862,7 +901,7 @@ static int rk628_hdmirx_phy_setup(struct v4l2_subdev *sd) __func__, width, height, frame_width, frame_height, status, cnt); rk628_i2c_read(bt1120->rk628, HDMI_RX_PDEC_STS, &val); - if (val & DVI_DET) + if (bt1120->rk628->version < RK628F_VERSION && (val & DVI_DET)) dev_info(bt1120->dev, "DVI mode detected\n"); if (!tx_5v_power_present(sd)) { @@ -881,6 +920,8 @@ static int rk628_hdmirx_phy_setup(struct v4l2_subdev *sd) __func__, i); continue; } else { + if (bt1120->rk628->version >= RK628F_VERSION) + rk628_hdmirx_phy_prepclk_cfg(bt1120->rk628); break; } } @@ -906,7 +947,10 @@ static void rk628_bt1120_initial_setup(struct v4l2_subdev *sd) /* I2SM0D0 */ rk628_i2c_write(bt1120->rk628, GRF_GPIO0AB_SEL_CON, HIWORD_UPDATE(0x1, 5, 4)); /* hdmirx int en */ - rk628_i2c_write(bt1120->rk628, GRF_INTR0_EN, 0x01000100); + if (bt1120->rk628->version >= RK628F_VERSION) + rk628_i2c_write(bt1120->rk628, GRF_INTR0_EN, 0x02000200); + else + rk628_i2c_write(bt1120->rk628, GRF_INTR0_EN, 0x01000100); udelay(10); rk628_control_assert(bt1120->rk628, RGU_HDMIRX); @@ -940,7 +984,7 @@ static void rk628_bt1120_initial_setup(struct v4l2_subdev *sd) rk628_hdmirx_set_hdcp(bt1120->rk628, &bt1120->hdcp, false); if (tx_5v_power_present(sd)) - schedule_delayed_work(&bt1120->delayed_work_enable_hotplug, 1000); + schedule_delayed_work(&bt1120->delayed_work_enable_hotplug, 4000); } static void rk628_bt1120_format_change(struct v4l2_subdev *sd) @@ -1005,31 +1049,37 @@ static int rk628_bt1120_isr(struct v4l2_subdev *sd, u32 status, bool *handled) v4l2_err(sd, "handled NULL, err return!\n"); return -EINVAL; } - rk628_i2c_read(bt1120->rk628, HDMI_RX_PDEC_ISTS, &pdec_ints); - if (rk628_audio_ctsnints_enabled(audio_info)) { - if (pdec_ints & (ACR_N_CHG_ICLR | ACR_CTS_CHG_ICLR)) { - rk628_csi_isr_ctsn(audio_info, pdec_ints); - pdec_ints &= ~(ACR_CTS_CHG_ICLR | ACR_CTS_CHG_ICLR); - *handled = true; - } + plugin = tx_5v_power_present(sd); + if (!plugin) { + rk628_bt1120_enable_interrupts(sd, false); + goto __clear_int; } - if (rk628_audio_fifoints_enabled(audio_info)) { - rk628_i2c_read(bt1120->rk628, HDMI_RX_AUD_FIFO_ISTS, &fifo_ints); - if (fifo_ints & 0x18) { - rk628_csi_isr_fifoints(audio_info, fifo_ints); - *handled = true; + + rk628_i2c_read(bt1120->rk628, HDMI_RX_PDEC_ISTS, &pdec_ints); + if (bt1120->rk628->version < RK628F_VERSION) { + if (rk628_audio_ctsnints_enabled(audio_info)) { + if (pdec_ints & (ACR_N_CHG_ICLR | ACR_CTS_CHG_ICLR)) { + rk628_csi_isr_ctsn(audio_info, pdec_ints); + pdec_ints &= ~(ACR_CTS_CHG_ICLR | ACR_CTS_CHG_ICLR); + *handled = true; + } + } + if (rk628_audio_fifoints_enabled(audio_info)) { + rk628_i2c_read(bt1120->rk628, HDMI_RX_AUD_FIFO_ISTS, &fifo_ints); + if (fifo_ints & 0x18) { + rk628_csi_isr_fifoints(audio_info, fifo_ints); + *handled = true; + } } } if (bt1120->vid_ints_en) { rk628_i2c_read(bt1120->rk628, HDMI_RX_MD_ISTS, &md_ints); - plugin = tx_5v_power_present(sd); v4l2_dbg(1, debug, sd, "%s: md_ints: %#x, pdec_ints:%#x, plugin: %d\n", __func__, md_ints, pdec_ints, plugin); if ((md_ints & (VACT_LIN_ISTS | HACT_PIX_ISTS | HS_CLK_ISTS | DE_ACTIVITY_ISTS | - VS_ACT_ISTS | HS_ACT_ISTS)) - && plugin) { + VS_ACT_ISTS | HS_ACT_ISTS))) { rk628_i2c_read(bt1120->rk628, HDMI_RX_MD_HACT_PX, &hact); rk628_i2c_read(bt1120->rk628, HDMI_RX_MD_VAL, &vact); @@ -1058,10 +1108,14 @@ static int rk628_bt1120_isr(struct v4l2_subdev *sd, u32 status, bool *handled) if (*handled != true) v4l2_dbg(1, debug, sd, "%s: unhandled interrupt!\n", __func__); +__clear_int: /* clear interrupts */ rk628_i2c_write(bt1120->rk628, HDMI_RX_MD_ICLR, 0xffffffff); rk628_i2c_write(bt1120->rk628, HDMI_RX_PDEC_ICLR, 0xffffffff); - rk628_i2c_write(bt1120->rk628, GRF_INTR0_CLR_EN, 0x01000100); + if (bt1120->rk628->version >= RK628F_VERSION) + rk628_i2c_write(bt1120->rk628, GRF_INTR0_CLR_EN, 0x02000200); + else + rk628_i2c_write(bt1120->rk628, GRF_INTR0_CLR_EN, 0x01000100); return 0; } @@ -1483,7 +1537,7 @@ static int rk628_bt1120_s_edid(struct v4l2_subdev *sd, bt1120->edid_blocks_written = edid->blocks; udelay(100); - if (tx_5v_power_present(sd)) + if (tx_5v_power_present(sd) && bt1120->rk628->version < RK628F_VERSION) rk628_hdmirx_hpd_ctrl(sd, true); return 0; @@ -1857,6 +1911,8 @@ static int rk628_bt1120_probe(struct i2c_client *client, rk628_cru_initialize(rk628); + rk628_version_parse(rk628); + #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API v4l2_i2c_subdev_init(sd, client, &rk628_bt1120_ops); sd->internal_ops = &bt1120_subdev_internal_ops;