media: i2c: rk628: fix mipi dphy timing set

Signed-off-by: Jianwei Fan <jianwei.fan@rock-chips.com>
Change-Id: I58c77f0f7418651ecf817b225d7dac3e649567db
This commit is contained in:
Jianwei Fan
2025-08-16 11:33:20 +08:00
committed by Tao Huang
parent 7007e186ca
commit f2f204f06b
4 changed files with 101 additions and 124 deletions

View File

@@ -257,23 +257,6 @@ static const unsigned int rk628_csi_extcon_cable[] = {
EXTCON_NONE,
};
static const struct mipi_timing rk628d_csi_mipi = {
0x0b, 0x53, 0x10, 0x5b, 0x0b, 0x43, 0x2c, 0x50, 0x0f
};
static const struct mipi_timing rk628f_csi0_mipi = {
0x0b, 0x53, 0x10, 0x5b, 0x0b, 0x43, 0x2c, 0x50, 0x0f
};
static const struct mipi_timing rk628f_csi1_mipi = {
//data_lp, data-pre, data-zero, data-trail, clk_lp, clk-pre, clk-zero, clk-trail, clk-post
0x0b, 0x53, 0x10, 0x5b, 0x0b, 0x43, 0x2c, 0x50, 0x0f
};
static const struct mipi_timing rk628f_dsi0_mipi = {
0x10, 0x70, 0x1c, 0x7f, 0x10, 0x70, 0x3f, 0x7f, 0x1f
};
static struct rkmodule_csi_dphy_param rk3588_dcphy_param = {
.vendor = PHY_VENDOR_SAMSUNG,
.lp_vol_ref = 0,
@@ -1488,17 +1471,6 @@ static void rk628_csi_initial_setup(struct v4l2_subdev *sd)
struct rk628_csi *csi = to_csi(sd);
rk628_csi_initial(sd);
if (csi->rk628->version >= RK628F_VERSION) {
csi->rk628->mipi_timing[0] = rk628f_csi0_mipi;
csi->rk628->mipi_timing[1] = rk628f_csi1_mipi;
} else {
csi->rk628->mipi_timing[0] = rk628d_csi_mipi;
}
if (csi->plat_data->tx_mode == DSI_MODE) {
csi->rk628->mipi_timing[0] = rk628f_dsi0_mipi;
csi->rk628->mipi_timing[1] = rk628f_dsi0_mipi;
}
csi->rk628->dphy_lane_en = 0x1f;
csi->txphy_pwron = true;
@@ -2156,11 +2128,37 @@ static int rk628_csi_enum_frame_interval(struct v4l2_subdev *sd,
return 0;
}
static u32 rk628_csi_get_lane_rate_mbps(struct rk628_csi *csi)
{
u32 lane_rate;
u32 max_lane_rate = 1300;
u8 bpp, lanes;
u64 pixelclock = csi->timings.bt.pixelclock;
bpp = 16;
lanes = csi->csi_lanes_in_use;
pixelclock = div_u64(pixelclock, 1000 * 1000);
lane_rate = pixelclock * bpp;
lane_rate = div_u64(lane_rate, lanes);
if (csi->rk628->dual_mipi)
lane_rate /= 2;
if (lane_rate > 1300)
lane_rate = max_lane_rate;
else if (lane_rate > 700 && lane_rate <= 1300)
lane_rate = 1300;
else
lane_rate = 700;
return lane_rate;
}
static int rk628_csi_get_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct rk628_csi *csi = to_csi(sd);
u32 rate;
if (!tx_5v_power_present(sd) || csi->nosignal) {
v4l2_info(sd, "%s hdmirx no signal\n", __func__);
@@ -2178,47 +2176,24 @@ static int rk628_csi_get_fmt(struct v4l2_subdev *sd,
V4L2_FIELD_INTERLACED : V4L2_FIELD_NONE;
if (csi->plat_data->tx_mode == CSI_MODE) {
if (csi->timings.bt.pixelclock > 150000000 || csi->csi_lanes_in_use <= 2) {
v4l2_dbg(1, debug, sd,
"%s res wxh:%dx%d, link freq:%llu, pixrate:%u\n",
__func__, csi->timings.bt.width, csi->timings.bt.height,
link_freq_menu_items[1], RK628_CSI_PIXEL_RATE_HIGH);
__v4l2_ctrl_s_ctrl(csi->link_freq, 1);
__v4l2_ctrl_s_ctrl_int64(csi->pixel_rate,
RK628_CSI_PIXEL_RATE_HIGH);
} else {
v4l2_dbg(1, debug, sd,
"%s res wxh:%dx%d, link freq:%llu, pixrate:%u\n",
__func__, csi->timings.bt.width, csi->timings.bt.height,
link_freq_menu_items[0], RK628_CSI_PIXEL_RATE_LOW);
__v4l2_ctrl_s_ctrl(csi->link_freq, 0);
__v4l2_ctrl_s_ctrl_int64(csi->pixel_rate,
RK628_CSI_PIXEL_RATE_LOW);
}
rate = rk628_csi_get_lane_rate_mbps(csi);
} else {
u32 rate;
csi->dsi.rk628 = csi->rk628;
csi->dsi.timings = csi->timings;
rate = rk628_dsi_get_lane_rate_mbps(&csi->dsi);
v4l2_dbg(1, debug, sd, "%s mipi bitrate:%u mbps\n", __func__, rate);
if (rate > 1300) {
csi->rk628->mipi_timing[0] = rk628f_dsi0_mipi;
csi->rk628->mipi_timing[1] = rk628f_dsi0_mipi;
__v4l2_ctrl_s_ctrl(csi->link_freq, 2);
} else if (rate <= 1300 && rate > 700) {
csi->rk628->mipi_timing[0] = rk628f_csi0_mipi;
csi->rk628->mipi_timing[1] = rk628f_csi0_mipi;
__v4l2_ctrl_s_ctrl(csi->link_freq, 1);
} else {
csi->rk628->mipi_timing[0] = rk628f_csi0_mipi;
csi->rk628->mipi_timing[1] = rk628f_csi0_mipi;
__v4l2_ctrl_s_ctrl(csi->link_freq, 0);
}
__v4l2_ctrl_s_ctrl_int64(csi->pixel_rate, RK628_CSI_PIXEL_RATE_HIGH);
}
v4l2_dbg(1, debug, sd, "%s mipi bitrate:%u mbps\n", __func__, rate);
if (rate > 1300)
__v4l2_ctrl_s_ctrl(csi->link_freq, 2);
else if (rate <= 1300 && rate > 700)
__v4l2_ctrl_s_ctrl(csi->link_freq, 1);
else
__v4l2_ctrl_s_ctrl(csi->link_freq, 0);
__v4l2_ctrl_s_ctrl_int64(csi->pixel_rate, RK628_CSI_PIXEL_RATE_HIGH);
mutex_unlock(&csi->confctl_mutex);
v4l2_dbg(1, debug, sd, "%s: fmt code:%d, w:%d, h:%d, field code:%d\n",
__func__, format->format.code, format->format.width,
@@ -2649,19 +2624,13 @@ static int mipi_dphy_power_on(struct rk628_csi *csi)
struct v4l2_subdev *sd = &csi->sd;
int ret;
if (csi->timings.bt.pixelclock > 150000000 || csi->csi_lanes_in_use <= 2) {
csi->lane_mbps = MIPI_DATARATE_MBPS_HIGH;
} else {
csi->lane_mbps = MIPI_DATARATE_MBPS_LOW;
}
if (csi->rk628->dual_mipi)
csi->lane_mbps = MIPI_DATARATE_MBPS_HIGH;
csi->lane_mbps = rk628_csi_get_lane_rate_mbps(csi);
bus_width = csi->lane_mbps << 8;
bus_width |= COMBTXPHY_MODULEA_EN;
if (csi->rk628->version >= RK628F_VERSION)
bus_width |= COMBTXPHY_MODULEB_EN;
v4l2_dbg(1, debug, sd, "%s mipi bitrate:%llu mbps\n", __func__,
csi->lane_mbps);
v4l2_info(sd, "%s mipi bitrate:%llu mbps\n", __func__, csi->lane_mbps);
rk628_mipi_dphy_reset_assert(csi->rk628);
rk628_mipi_dphy_reset_deassert(csi->rk628);
@@ -2672,18 +2641,6 @@ static int mipi_dphy_power_on(struct rk628_csi *csi)
if (csi->rk628->version >= RK628F_VERSION)
rk628_mipi_dphy_init_hsfreqrange(csi->rk628, csi->lane_mbps, 1);
if (csi->rk628->dual_mipi) {
rk628_mipi_dphy_init_hsmanual(csi->rk628, true, 0);
rk628_mipi_dphy_init_hsmanual(csi->rk628, true, 1);
} else if (csi->lane_mbps == MIPI_DATARATE_MBPS_HIGH && !csi->rk628->dual_mipi) {
rk628_mipi_dphy_init_hsmanual(csi->rk628, true, 0);
if (csi->rk628->version >= RK628F_VERSION)
rk628_mipi_dphy_init_hsmanual(csi->rk628, false, 1);
} else {
rk628_mipi_dphy_init_hsmanual(csi->rk628, false, 0);
if (csi->rk628->version >= RK628F_VERSION)
rk628_mipi_dphy_init_hsmanual(csi->rk628, false, 1);
}
rk628_txphy_power_on(csi->rk628);
usleep_range(1500, 2000);

View File

@@ -88,11 +88,6 @@ static void mipi_dphy_power_on_dsi(struct rk628_dsi *dsi, uint8_t mipi_id)
rk628_testif_testclr_deassert(dsi->rk628, mipi_id);
rk628_mipi_dphy_init_hsfreqrange(dsi->rk628, dsi->lane_mbps, mipi_id);
if (dsi->lane_mbps > 1100)
rk628_mipi_dphy_init_hsmanual(dsi->rk628, true, mipi_id);
else
rk628_mipi_dphy_init_hsmanual(dsi->rk628, false, mipi_id);
dsi_update_bits(rk628, mipi_id, DSI_PHY_RSTZ,
PHY_ENABLECLK, PHY_ENABLECLK);
dsi_update_bits(rk628, mipi_id, DSI_PHY_RSTZ,

View File

@@ -104,6 +104,15 @@ u8 rk628_testif_write(struct rk628 *rk628, u8 test_code, u8 test_data, uint8_t m
}
EXPORT_SYMBOL(rk628_testif_write);
static void rk628_testif_set_timing(struct rk628 *rk628, u8 addr,
u8 max, u8 val, uint8_t mipi_id)
{
if (val > max)
return;
rk628_testif_write(rk628, addr, (max + 1) | val, mipi_id);
}
u8 rk628_testif_read(struct rk628 *rk628, u8 test_code, uint8_t mipi_id)
{
u8 test_data;
@@ -170,6 +179,56 @@ static inline void mipi_dphy_rstz_deassert(struct rk628 *rk628)
udelay(1);
}
static void rk628_mipi_dphy_set_timing(struct rk628 *rk628, int lane_mbps, uint8_t mipi_id)
{
const struct {
unsigned int min_lane_mbps;
unsigned int max_lane_mbps;
u8 clk_lp;
u8 clk_hs_prepare;
u8 clk_hs_zero;
u8 clk_hs_trail;
u8 clk_post;
u8 data_lp;
u8 data_hs_prepare;
u8 data_hs_zero;
u8 data_hs_trail;
} timing_table[] = {
{800, 899, 0x07, 0x30, 0x25, 0x3c, 0x0f, 0x07, 0x40, 0x09, 0x40},
{1100, 1249, 0x0a, 0x43, 0x2c, 0x50, 0x0f, 0x0a, 0x43, 0x10, 0x55},
{1250, 1349, 0x0b, 0x43, 0x2c, 0x50, 0x0f, 0x0b, 0x53, 0x10, 0x5b},
{1350, 1449, 0x0c, 0x43, 0x36, 0x60, 0x0f, 0x0c, 0x53, 0x10, 0x65},
{1450, 1500, 0x0f, 0x60, 0x31, 0x60, 0x0f, 0x0e, 0x60, 0x11, 0x6a},
{1750, 2050, 0x10, 0x70, 0x3f, 0x7f, 0x1f, 0x10, 0x70, 0x1c, 0x7f},
};
unsigned int index;
// These ranges use the controller's internal automatically calculated timing.
if (lane_mbps < 800 || (lane_mbps >= 900 && lane_mbps < 1100))
return;
if (lane_mbps < timing_table[0].min_lane_mbps)
return;
for (index = 0; index < ARRAY_SIZE(timing_table); index++)
if (lane_mbps >= timing_table[index].min_lane_mbps &&
lane_mbps < timing_table[index].max_lane_mbps)
break;
if (index == ARRAY_SIZE(timing_table))
--index;
rk628_testif_set_timing(rk628, 0x60, 0x3f, timing_table[index].clk_lp, mipi_id);
rk628_testif_set_timing(rk628, 0x61, 0x7f, timing_table[index].clk_hs_prepare, mipi_id);
rk628_testif_set_timing(rk628, 0x62, 0x3f, timing_table[index].clk_hs_zero, mipi_id);
rk628_testif_set_timing(rk628, 0x63, 0x7f, timing_table[index].clk_hs_trail, mipi_id);
rk628_testif_set_timing(rk628, 0x65, 0x0f, timing_table[index].clk_post, mipi_id);
rk628_testif_set_timing(rk628, 0x70, 0x3f, timing_table[index].data_lp, mipi_id);
rk628_testif_set_timing(rk628, 0x71, 0x7f, timing_table[index].data_hs_prepare, mipi_id);
rk628_testif_set_timing(rk628, 0x72, 0x3f, timing_table[index].data_hs_zero, mipi_id);
rk628_testif_set_timing(rk628, 0x73, 0x7f, timing_table[index].data_hs_trail, mipi_id);
}
void rk628_mipi_dphy_init_hsfreqrange(struct rk628 *rk628, int lane_mbps, uint8_t mipi_id)
{
const struct {
@@ -199,43 +258,10 @@ void rk628_mipi_dphy_init_hsfreqrange(struct rk628 *rk628, int lane_mbps, uint8_
hsfreqrange = hsfreqrange_table[index].hsfreqrange;
rk628_testif_write(rk628, 0x44, HSFREQRANGE(hsfreqrange), mipi_id);
rk628_mipi_dphy_set_timing(rk628, lane_mbps, mipi_id);
}
EXPORT_SYMBOL(rk628_mipi_dphy_init_hsfreqrange);
void rk628_mipi_dphy_init_hsmanual(struct rk628 *rk628, bool manual, uint8_t mipi_id)
{
dev_info(rk628->dev,
"mipi dphy%d hs config, manual: %s\n", mipi_id, manual ? "true" : "false");
//config mipi timing when mipi freq is 1250Mbps
rk628_testif_write(rk628, 0x70,
manual ? (HSZERO(rk628->mipi_timing[mipi_id].data_lp) | BIT(6)) : 0, mipi_id);
usleep_range(1500, 2000);
rk628_testif_write(rk628, 0x71,
manual ? (HSTX(rk628->mipi_timing[mipi_id].data_prepare) | BIT(7)) : 0, mipi_id);
usleep_range(1500, 2000);
rk628_testif_write(rk628, 0x72,
manual ? (HSZERO(rk628->mipi_timing[mipi_id].data_zero) | BIT(6)) : 0, mipi_id);
usleep_range(1500, 2000);
rk628_testif_write(rk628, 0x73,
manual ? (HSTX(rk628->mipi_timing[mipi_id].data_trail) | BIT(7)) : 0, mipi_id);
usleep_range(1500, 2000);
rk628_testif_write(rk628, 0x60,
manual ? (HSZERO(rk628->mipi_timing[mipi_id].clk_lp) | BIT(6)) : 0, mipi_id);
usleep_range(1500, 2000);
rk628_testif_write(rk628, 0x61,
manual ? (HSTX(rk628->mipi_timing[mipi_id].clk_prepare) | BIT(7)) : 0, mipi_id);
usleep_range(1500, 2000);
rk628_testif_write(rk628, 0x62,
manual ? (HSZERO(rk628->mipi_timing[mipi_id].clk_zero) | BIT(6)) : 0, mipi_id);
usleep_range(1500, 2000);
rk628_testif_write(rk628, 0x63,
manual ? (HSTX(rk628->mipi_timing[mipi_id].clk_trail) | BIT(7)) : 0, mipi_id);
usleep_range(1500, 2000);
rk628_testif_write(rk628, 0x65,
manual ? (HSPOST(rk628->mipi_timing[mipi_id].clk_post) | BIT(4)) : 0, mipi_id);
}
EXPORT_SYMBOL(rk628_mipi_dphy_init_hsmanual);
int rk628_mipi_dphy_reset_assert(struct rk628 *rk628)
{
rk628_i2c_write(rk628, CSITX_SYS_CTRL0_IMD, 0x1);

View File

@@ -22,7 +22,6 @@ void rk628_testif_testclr_assert(struct rk628 *rk628, uint8_t mipi_id);
u8 rk628_testif_write(struct rk628 *rk628, u8 test_code, u8 test_data, uint8_t mipi_id);
u8 rk628_testif_read(struct rk628 *rk628, u8 test_code, uint8_t mipi_id);
void rk628_mipi_dphy_init_hsfreqrange(struct rk628 *rk628, int lane_mbps, uint8_t mipi_id);
void rk628_mipi_dphy_init_hsmanual(struct rk628 *rk628, bool manual, uint8_t mipi_id);
int rk628_mipi_dphy_reset_assert(struct rk628 *rk628);
int rk628_mipi_dphy_reset_deassert(struct rk628 *rk628);