media: i2c: rk628: optimized get resolution probability abnormal

Change-Id: I99433dc24d993a6ceae8fbc1472cb39d43a72ad1
Signed-off-by: Chen Shunqing <csq@rock-chips.com>
This commit is contained in:
Chen Shunqing
2023-11-28 08:39:40 +00:00
committed by Tao Huang
parent 2ef107a7a5
commit 08be2e3816
4 changed files with 192 additions and 234 deletions

View File

@@ -58,8 +58,6 @@ MODULE_PARM_DESC(debug, "debug level (0-3)");
#define MIPI_DATARATE_MBPS_HIGH 1250
#define POLL_INTERVAL_MS 1000
#define MODETCLK_CNT_NUM 1000
#define MODETCLK_HZ 49500000
#define RXPHY_CFG_MAX_TIMES 15
#define CSITX_ERR_RETRY_TIMES 3
@@ -333,118 +331,12 @@ static int rk628_bt1120_get_detected_timings(struct v4l2_subdev *sd,
{
struct rk628_bt1120 *bt1120 = to_bt1120(sd);
struct v4l2_bt_timings *bt = &timings->bt;
u32 hact, vact, htotal, vtotal, fps, status;
u32 val;
u32 modetclk_cnt_hs, modetclk_cnt_vs, hs, vs;
u32 hofs_pix, hbp, hfp, vbp, vfp;
u32 tmds_clk, tmdsclk_cnt;
u64 tmp_data;
u8 video_fmt;
int retry = 0;
int ret;
__retry:
memset(timings, 0, sizeof(struct v4l2_dv_timings));
timings->type = V4L2_DV_BT_656_1120;
rk628_i2c_read(bt1120->rk628, HDMI_RX_SCDC_REGS1, &val);
status = val;
ret = rk628_hdmirx_get_timings(bt1120->rk628, timings);
if (ret)
return ret;
rk628_i2c_read(bt1120->rk628, HDMI_RX_MD_STS, &val);
bt->interlaced = val & ILACE_STS ?
V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE;
rk628_i2c_read(bt1120->rk628, HDMI_RX_MD_HACT_PX, &val);
hact = val & 0xffff;
rk628_i2c_read(bt1120->rk628, HDMI_RX_MD_VAL, &val);
vact = val & 0xffff;
rk628_i2c_read(bt1120->rk628, HDMI_RX_MD_HT1, &val);
htotal = (val >> 16) & 0xffff;
rk628_i2c_read(bt1120->rk628, HDMI_RX_MD_VTL, &val);
vtotal = val & 0xffff;
rk628_i2c_read(bt1120->rk628, HDMI_RX_MD_HT1, &val);
hofs_pix = val & 0xffff;
rk628_i2c_read(bt1120->rk628, HDMI_RX_MD_VOL, &val);
vbp = (val & 0xffff) + 1;
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 || bt->interlaced || vtotal > 3000) {
v4l2_err(&bt1120->sd, "timing err, htotal:%d, vtotal:%d\n",
htotal, vtotal);
if (retry++ < 5) {
msleep(20);
goto __retry;
}
goto TIMING_ERR;
}
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;
hs = (tmdsclk_cnt * modetclk_cnt_hs + MODETCLK_CNT_NUM / 2) /
MODETCLK_CNT_NUM;
rk628_i2c_read(bt1120->rk628, HDMI_RX_MD_VSC, &val);
modetclk_cnt_vs = val & 0xffff;
vs = (tmdsclk_cnt * modetclk_cnt_vs + MODETCLK_CNT_NUM / 2) /
MODETCLK_CNT_NUM;
vs = (vs + htotal / 2) / htotal;
if ((hofs_pix < hs) || (htotal < (hact + hofs_pix)) ||
(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);
bt->width = hact;
bt->height = vact;
bt->hfrontporch = hfp;
bt->hsync = hs;
bt->hbackporch = hbp;
bt->vfrontporch = vfp;
bt->vsync = vs;
bt->vbackporch = vbp;
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);
v4l2_dbg(1, debug, sd, "hfp:%d, hs:%d, hbp:%d, vfp:%d, vs:%d, vbp:%d, interlace:%d\n",
bt->hfrontporch, bt->hsync, bt->hbackporch, bt->vfrontporch,
bt->vsync, bt->vbackporch, bt->interlaced);
@@ -453,10 +345,7 @@ __retry:
if (bt1120->scaler_en)
*timings = bt1120->timings;
return 0;
TIMING_ERR:
return -ENOLCK;
return ret;
}
static void rk628_hdmirx_config_all(struct v4l2_subdev *sd)

View File

@@ -62,8 +62,6 @@ MODULE_PARM_DESC(debug, "debug level (0-3)");
#define MIPI_DATARATE_MBPS_HIGH 1250
#define POLL_INTERVAL_MS 1000
#define MODETCLK_CNT_NUM 1000
#define MODETCLK_HZ 49500000
#define RXPHY_CFG_MAX_TIMES 15
#define CSITX_ERR_RETRY_TIMES 3
@@ -412,121 +410,12 @@ static int rk628_csi_get_detected_timings(struct v4l2_subdev *sd,
{
struct rk628_csi *csi = to_csi(sd);
struct v4l2_bt_timings *bt = &timings->bt;
u32 hact, vact, htotal, vtotal, fps, status;
u32 val;
u32 modetclk_cnt_hs, modetclk_cnt_vs, hs, vs;
u32 hofs_pix, hbp, hfp, vbp, vfp;
u32 tmds_clk, tmdsclk_cnt;
u64 tmp_data;
u8 video_fmt;
int retry = 0;
int ret;
__retry:
memset(timings, 0, sizeof(struct v4l2_dv_timings));
timings->type = V4L2_DV_BT_656_1120;
rk628_i2c_read(csi->rk628, HDMI_RX_SCDC_REGS1, &val);
status = val;
ret = rk628_hdmirx_get_timings(csi->rk628, timings);
if (ret)
return ret;
rk628_i2c_read(csi->rk628, HDMI_RX_MD_STS, &val);
bt->interlaced = val & ILACE_STS ?
V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE;
rk628_i2c_read(csi->rk628, HDMI_RX_MD_HACT_PX, &val);
hact = val & 0xffff;
rk628_i2c_read(csi->rk628, HDMI_RX_MD_VAL, &val);
vact = val & 0xffff;
rk628_i2c_read(csi->rk628, HDMI_RX_MD_HT1, &val);
htotal = (val >> 16) & 0xffff;
rk628_i2c_read(csi->rk628, HDMI_RX_MD_VTL, &val);
vtotal = val & 0xffff;
rk628_i2c_read(csi->rk628, HDMI_RX_MD_HT1, &val);
hofs_pix = val & 0xffff;
rk628_i2c_read(csi->rk628, HDMI_RX_MD_VOL, &val);
vbp = (val & 0xffff) + 1;
tmdsclk_cnt = rk628_hdmirx_get_tmdsclk_cnt(csi->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 || bt->interlaced || vtotal > 3000) {
v4l2_err(&csi->sd, "timing err, htotal:%d, vtotal:%d\n",
htotal, vtotal);
if (retry++ < 5) {
msleep(20);
goto __retry;
}
goto TIMING_ERR;
}
if (csi->rk628->version >= RK628F_VERSION)
fps = tmds_clk / (htotal * vtotal);
else
fps = (tmds_clk + (htotal * vtotal) / 2) / (htotal * vtotal);
rk628_i2c_read(csi->rk628, HDMI_RX_MD_HT0, &val);
modetclk_cnt_hs = val & 0xffff;
hs = (tmdsclk_cnt * modetclk_cnt_hs + MODETCLK_CNT_NUM / 2) /
MODETCLK_CNT_NUM;
rk628_i2c_read(csi->rk628, HDMI_RX_MD_VSC, &val);
modetclk_cnt_vs = val & 0xffff;
vs = (tmdsclk_cnt * modetclk_cnt_vs + MODETCLK_CNT_NUM / 2) /
MODETCLK_CNT_NUM;
vs = (vs + htotal / 2) / htotal;
if ((hofs_pix < hs) || (htotal < (hact + hofs_pix)) ||
(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(csi->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);
bt->width = hact;
bt->height = vact;
bt->hfrontporch = hfp;
bt->hsync = hs;
bt->hbackporch = hbp;
bt->vfrontporch = vfp;
bt->vsync = vs;
bt->vbackporch = vbp;
if (csi->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;
if (vact == 1080 && vtotal > 1500)
goto __retry;
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);
v4l2_dbg(1, debug, sd, "hfp:%d, hs:%d, hbp:%d, vfp:%d, vs:%d, vbp:%d, interlace:%d\n",
bt->hfrontporch, bt->hsync, bt->hbackporch, bt->vfrontporch, bt->vsync,
bt->vbackporch, bt->interlaced);
@@ -535,10 +424,8 @@ __retry:
if (csi->scaler_en)
*timings = csi->timings;
return 0;
return ret;
TIMING_ERR:
return -ENOLCK;
}
static void rk628_hdmirx_config_all(struct v4l2_subdev *sd)

View File

@@ -833,3 +833,178 @@ u32 rk628_hdmirx_get_tmdsclk_cnt(struct rk628 *rk628)
return tmdsclk_cnt;
}
EXPORT_SYMBOL(rk628_hdmirx_get_tmdsclk_cnt);
static int rk628_hdmirx_read_timing(struct rk628 *rk628,
struct v4l2_dv_timings *timings)
{
struct v4l2_bt_timings *bt = &timings->bt;
u32 hact, vact, htotal, vtotal, fps, status;
u32 val;
u32 modetclk_cnt_hs, modetclk_cnt_vs, hs, vs;
u32 hofs_pix, hbp, hfp, vbp, vfp;
u32 tmds_clk, tmdsclk_cnt;
u64 tmp_data;
u8 video_fmt;
memset(timings, 0, sizeof(struct v4l2_dv_timings));
timings->type = V4L2_DV_BT_656_1120;
rk628_i2c_read(rk628, HDMI_RX_SCDC_REGS1, &val);
status = val;
rk628_i2c_read(rk628, HDMI_RX_MD_STS, &val);
bt->interlaced = val & ILACE_STS ?
V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE;
rk628_i2c_read(rk628, HDMI_RX_MD_HACT_PX, &val);
hact = val & 0xffff;
rk628_i2c_read(rk628, HDMI_RX_MD_VAL, &val);
vact = val & 0xffff;
rk628_i2c_read(rk628, HDMI_RX_MD_HT1, &val);
htotal = (val >> 16) & 0xffff;
rk628_i2c_read(rk628, HDMI_RX_MD_VTL, &val);
vtotal = val & 0xffff;
rk628_i2c_read(rk628, HDMI_RX_MD_HT1, &val);
hofs_pix = val & 0xffff;
rk628_i2c_read(rk628, HDMI_RX_MD_VOL, &val);
vbp = (val & 0xffff) + 1;
tmdsclk_cnt = rk628_hdmirx_get_tmdsclk_cnt(rk628);
tmp_data = tmdsclk_cnt;
tmp_data = ((tmp_data * HDMIRX_MODETCLK_HZ) + HDMIRX_MODETCLK_CNT_NUM / 2);
do_div(tmp_data, HDMIRX_MODETCLK_CNT_NUM);
tmds_clk = tmp_data;
if (!htotal || !vtotal || bt->interlaced || vtotal > 3000) {
dev_err(rk628->dev, "timing err, %s htotal:%d, vtotal:%d\n",
bt->interlaced ? "interlaced is not supported," : "",
htotal, vtotal);
goto TIMING_ERR;
}
if (rk628->version >= RK628F_VERSION)
fps = tmds_clk / (htotal * vtotal);
else
fps = (tmds_clk + (htotal * vtotal) / 2) / (htotal * vtotal);
rk628_i2c_read(rk628, HDMI_RX_MD_HT0, &val);
modetclk_cnt_hs = val & 0xffff;
hs = (tmdsclk_cnt * modetclk_cnt_hs + HDMIRX_MODETCLK_CNT_NUM / 2) /
HDMIRX_MODETCLK_CNT_NUM;
rk628_i2c_read(rk628, HDMI_RX_MD_VSC, &val);
modetclk_cnt_vs = val & 0xffff;
vs = (tmdsclk_cnt * modetclk_cnt_vs + HDMIRX_MODETCLK_CNT_NUM / 2) /
HDMIRX_MODETCLK_CNT_NUM;
vs = (vs + htotal / 2) / htotal;
if ((hofs_pix < hs) || (htotal < (hact + hofs_pix)) ||
(vtotal < (vact + vs + vbp)) || !vs) {
dev_err(rk628->dev, "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);
goto TIMING_ERR;
}
hbp = hofs_pix - hs;
hfp = htotal - hact - hofs_pix;
vfp = vtotal - vact - vs - vbp;
video_fmt = rk628_hdmirx_get_format(rk628);
if (video_fmt == BUS_FMT_YUV420) {
htotal *= 2;
hact *= 2;
hfp *= 2;
hbp *= 2;
hs *= 2;
}
dev_info(rk628->dev, "cnt_num:%d, tmds_cnt:%d, hs_cnt:%d, vs_cnt:%d, hofs:%d\n",
HDMIRX_MODETCLK_CNT_NUM, tmdsclk_cnt, modetclk_cnt_hs, modetclk_cnt_vs, hofs_pix);
bt->width = hact;
bt->height = vact;
bt->hfrontporch = hfp;
bt->hsync = hs;
bt->hbackporch = hbp;
bt->vfrontporch = vfp;
bt->vsync = vs;
bt->vbackporch = vbp;
if (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;
if (vact == 1080 && vtotal > 1500)
goto TIMING_ERR;
dev_info(rk628->dev, "SCDC_REGS1:%#x, act:%dx%d, total:%dx%d, fps:%d, pixclk:%llu\n",
status, hact, vact, htotal, vtotal, fps, bt->pixelclock);
return 0;
TIMING_ERR:
return -ENOLCK;
}
static int rk628_hdmirx_try_to_get_timing(struct rk628 *rk628,
struct v4l2_dv_timings *timings)
{
int ret, i;
for (i = 0; i < 5; i++) {
ret = rk628_hdmirx_read_timing(rk628, timings);
if (!ret)
return ret;
msleep(20);
}
return ret;
}
int rk628_hdmirx_get_timings(struct rk628 *rk628,
struct v4l2_dv_timings *timings)
{
int i, cnt = 0, ret = 0;
u32 last_w, last_h;
u8 last_fmt;
struct v4l2_bt_timings *bt = &timings->bt;
last_w = 0;
last_h = 0;
last_fmt = BUS_FMT_RGB;
for (i = 0; i < HDMIRX_GET_TIMING_CNT; i++) {
ret = rk628_hdmirx_try_to_get_timing(rk628, timings);
if ((last_w == 0) && (last_h == 0)) {
last_w = bt->width;
last_h = bt->height;
last_fmt = rk628_hdmirx_get_format(rk628);
}
if (ret || (last_w != bt->width) || (last_h != bt->height)
|| (last_fmt != rk628_hdmirx_get_format(rk628)))
cnt = 0;
else
cnt++;
if (cnt >= 8)
break;
last_w = bt->width;
last_h = bt->height;
last_fmt = rk628_hdmirx_get_format(rk628);
usleep_range(10*1000, 10*1100);
}
if (cnt < 8) {
dev_info(rk628->dev, "%s: res not stable!\n", __func__);
ret = -EINVAL;
}
return ret;
}
EXPORT_SYMBOL(rk628_hdmirx_get_timings);

View File

@@ -8,6 +8,7 @@
#ifndef __RK628_HDMIRX_H
#define __RK628_HDMIRX_H
#include <media/v4l2-dv-timings.h>
#include "rk628.h"
/* --------- EDID and HDCP KEY ------- */
@@ -373,6 +374,10 @@
#define HDMIRX_HDCP1X_ID 13
#define HDMIRX_GET_TIMING_CNT 20
#define HDMIRX_MODETCLK_CNT_NUM 1000
#define HDMIRX_MODETCLK_HZ 49500000
enum bus_format {
BUS_FMT_RGB = 0,
BUS_FMT_YUV422 = 1,
@@ -420,5 +425,7 @@ int rk628_hdmirx_verisyno_phy_init(struct rk628 *rk628);
u8 rk628_hdmirx_get_format(struct rk628 *rk628);
void rk628_set_bg_enable(struct rk628 *rk628, bool en);
u32 rk628_hdmirx_get_tmdsclk_cnt(struct rk628 *rk628);
int rk628_hdmirx_get_timings(struct rk628 *rk628,
struct v4l2_dv_timings *timings);
#endif