From e2b8f25af6192b97d6e66d338b0dd10083ad8058 Mon Sep 17 00:00:00 2001 From: Zefa Chen Date: Wed, 17 Sep 2025 09:59:01 +0800 Subject: [PATCH 01/13] media: rockchip: vicap force update buf when it's return and update very close to fe Change-Id: I019779287b2f2aa7885e4154c4ad0c0907d88e1a Signed-off-by: Zefa Chen --- drivers/media/platform/rockchip/cif/capture.c | 43 ++++++++++++++++++- drivers/media/platform/rockchip/cif/dev.h | 2 + 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/rockchip/cif/capture.c b/drivers/media/platform/rockchip/cif/capture.c index bdebc322f0a1..a062accac7d4 100644 --- a/drivers/media/platform/rockchip/cif/capture.c +++ b/drivers/media/platform/rockchip/cif/capture.c @@ -2568,6 +2568,23 @@ out_get_buf: rkcif_write_register(dev, frm_addr_y, buff_addr_y); } } + if (buf_stream->is_force_update) { + if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || + mbus_cfg->type == V4L2_MBUS_CSI2_CPHY) { + if (dev->chip_id < CHIP_RK3562_CIF) + rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_CTRL, 0x00010000); + else + rkcif_write_register_or(dev, get_reg_index_of_frm0_y_vlw(stream->id), BIT(31)); + } else { + if (dev->chip_id < CHIP_RK3562_CIF) + rkcif_write_register_or(dev, CIF_REG_DVP_CTRL, 0x00010000); + else if (dev->chip_id < CHIP_RK3576_CIF) + rkcif_write_register_or(dev, CIF_REG_DVP_VIR_LINE_WIDTH, BIT(28) << stream->id); + else + rkcif_write_register_or(dev, CIF_REG_DVP_VIR_LINE_WIDTH, BIT(31)); + } + buf_stream->is_force_update = false; + } spin_unlock_irqrestore(&buf_stream->vbq_lock, flags); return 0; } @@ -2584,6 +2601,19 @@ static int rkcif_assign_new_buffer_pingpong_toisp(struct rkcif_stream *stream, return ret; } +static void rkcif_check_force_update_buf(struct rkcif_stream *stream) +{ + u64 cur_time = 0; + u64 offset = 0; + + offset = stream->cifdev->readout_ns - 2000000; + cur_time = rkcif_time_get_ns(stream->cifdev); + if (stream->dma_en && + (cur_time - stream->readout.fs_timestamp) > offset && + !stream->is_in_vblank) + stream->is_force_update = true; +} + void rkcif_assign_check_buffer_update_toisp(struct rkcif_stream *stream) { struct rkcif_device *dev = stream->cifdev; @@ -2634,6 +2664,11 @@ void rkcif_assign_check_buffer_update_toisp(struct rkcif_stream *stream) buf_stream->toisp_buf_state.check_cnt == 0) is_dual_update = true; + if ((buf_stream->toisp_buf_state.state == RKCIF_TOISP_BUF_LOSS || + buf_stream->toisp_buf_state.state == RKCIF_TOISP_BUF_THESAME) && + buf_stream->toisp_buf_state.check_cnt == 0) + rkcif_check_force_update_buf(buf_stream); + if ((dev->rdbk_debug > 2 && stream->frame_idx < 15) || rkcif_debug > 4) @@ -6982,6 +7017,7 @@ void rkcif_do_stop_stream(struct rkcif_stream *stream, stream->crop_mask = 0; stream->frame_loss = 0; stream->is_fb_first_frame = true; + stream->is_force_update = false; } if (mode == RKCIF_STREAM_MODE_CAPTURE) { tasklet_disable(&stream->vb_done_tasklet); @@ -8601,6 +8637,8 @@ int rkcif_do_start_stream(struct rkcif_stream *stream, enum rkcif_stream_mode mo tasklet_enable(&stream->vb_done_tasklet); if (stream->cur_stream_mode == RKCIF_STREAM_MODE_NONE) { + dev->sensor_linetime = rkcif_get_linetime(stream); + dev->readout_ns = dev->terminal_sensor.raw_rect.height * dev->sensor_linetime; ret = dev->pipe.open(&dev->pipe, &node->vdev.entity, true); if (ret < 0) { v4l2_err(v4l2_dev, "open cif pipeline failed %d\n", @@ -9095,6 +9133,7 @@ void rkcif_stream_init(struct rkcif_device *dev, u32 id) memset(&stream->sensor_exp_info, 0, sizeof(stream->sensor_exp_info)); stream->frame_loss = 0; stream->is_pause_stream = false; + stream->is_force_update = false; } int rkcif_sensor_set_power(struct rkcif_stream *stream, int on) @@ -13179,8 +13218,10 @@ void rkcif_enable_dma_capture(struct rkcif_stream *stream, bool is_only_enable) } else { if (cif_dev->chip_id < CHIP_RK3562_CIF) rkcif_write_register_or(cif_dev, CIF_REG_DVP_CTRL, 0x00010000); - else + else if (cif_dev->chip_id < CHIP_RK3576_CIF) rkcif_write_register_or(cif_dev, CIF_REG_DVP_VIR_LINE_WIDTH, BIT(28) << stream->id); + else + rkcif_write_register_or(cif_dev, CIF_REG_DVP_VIR_LINE_WIDTH, BIT(31)); } if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || mbus_cfg->type == V4L2_MBUS_CSI2_CPHY) { diff --git a/drivers/media/platform/rockchip/cif/dev.h b/drivers/media/platform/rockchip/cif/dev.h index c3dbe068391e..1a54a894203b 100644 --- a/drivers/media/platform/rockchip/cif/dev.h +++ b/drivers/media/platform/rockchip/cif/dev.h @@ -680,6 +680,7 @@ struct rkcif_stream { bool is_m_online_fb_res; bool is_fb_first_frame; bool is_pause_stream; + bool is_force_update; }; struct rkcif_lvds_subdev { @@ -1057,6 +1058,7 @@ struct rkcif_device { u32 early_line; int isp_runtime_max; int sensor_linetime; + u64 readout_ns; u32 err_state; struct rkcif_err_state_work err_state_work; struct rkcif_sensor_work sensor_work; From 53cf10734177c0e2d36389188a38857b1dab96a8 Mon Sep 17 00:00:00 2001 From: Damon Ding Date: Mon, 8 Sep 2025 17:43:47 +0800 Subject: [PATCH 02/13] drm/rockchip: analogix_dp: Initialize the PSR helper only for the left device in split mode In split mode, since only the left device will create the DRM encoder, there will be an unexpected crash because the right device does not have &rockchip_encoder.encoder->dev, which used to check PSR initialization in rockchip_dp_drm_self_refresh_helper_init(). Fixes: 3b97d716d55e ("drm/rockchip: Move the init/cleanup of self refresh helper from VOP/VOP2 to eDP/RGB drivers") Change-Id: I282c646b4ea44b34403328693af27724ac543f4f Signed-off-by: Damon Ding --- drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index bc9652a02024..eac34da215f2 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -684,14 +684,14 @@ static int rockchip_dp_bind(struct device *dev, struct device *master, } dp->plat_data.encoder = &dp->encoder.encoder; + + rockchip_dp_drm_self_refresh_helper_init(dp); } ret = analogix_dp_bind(dp->adp, drm_dev); if (ret) goto err_unregister_audio_pdev; - rockchip_dp_drm_self_refresh_helper_init(dp); - return 0; err_unregister_audio_pdev: @@ -707,7 +707,8 @@ static void rockchip_dp_unbind(struct device *dev, struct device *master, if (dp->audio_pdev) platform_device_unregister(dp->audio_pdev); - rockchip_dp_drm_self_refresh_helper_cleanup(dp); + if (!dp->plat_data.left) + rockchip_dp_drm_self_refresh_helper_cleanup(dp); analogix_dp_unbind(dp->adp); dp->encoder.encoder.funcs->destroy(&dp->encoder.encoder); } From 4a1668a9ba9796e835dcf25e6032553697368603 Mon Sep 17 00:00:00 2001 From: Haoran Han Date: Wed, 27 Aug 2025 18:33:42 +0800 Subject: [PATCH 03/13] media: i2c: max96756: Add writing of 1080p & 720p & 480p EDID tables during streaming Change-Id: Ie9a86aeebc9f5aed3cad3cf4daa2ad967a180f9b Signed-off-by: Haoran Han --- drivers/media/i2c/max96756.c | 180 ++++++++++++++++++++++++++++++++++- 1 file changed, 176 insertions(+), 4 deletions(-) diff --git a/drivers/media/i2c/max96756.c b/drivers/media/i2c/max96756.c index 42b18c9aaee6..ff642a7a50a1 100644 --- a/drivers/media/i2c/max96756.c +++ b/drivers/media/i2c/max96756.c @@ -11,6 +11,9 @@ * * V0.0X01.0X02 * - Compatible with kernel-6.1 version + * + * V0.0X01.0X03 + * - Add writing EDID tables */ #define DEBUG @@ -40,7 +43,7 @@ #include #include "max96756.h" -#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x02) +#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x03) static int debug; module_param(debug, int, 0644); @@ -64,12 +67,14 @@ MODULE_PARM_DESC(debug, "debug level (0-3)"); #define OF_CAMERA_PINCTRL_STATE_DEFAULT "rockchip,camera_default" #define OF_CAMERA_PINCTRL_STATE_SLEEP "rockchip,camera_sleep" +#define MAX96756_WRITEEDID_ENABLE "rockchip,max96756-writeedid-enable" #define MAX96756_REG_VALUE_08BIT 1 #define MAX96756_REG_VALUE_16BIT 2 #define MAX96756_NAME "max96756" #define MAX96756_MEDIA_BUS_FMT MEDIA_BUS_FMT_BGR888_1X24 +#define MAX96745_I2CADDR 0x40 static const char *const max96756_supply_names[] = { "vcc1v2", /* Analog power */ @@ -77,6 +82,27 @@ static const char *const max96756_supply_names[] = { }; #define MAX96756_NUM_SUPPLIES ARRAY_SIZE(max96756_supply_names) +#define MAX96756_EDID_COUNT 256 + +static const u8 edid_1080p60_720p_480p_rgb888[MAX96756_EDID_COUNT] = { +0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x34, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x01, 0x00, 0x01, 0x04, 0xA5, 0xF0, 0x90, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, +0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x3A, 0x80, 0x18, 0x71, 0x38, 0x2D, 0x40, 0x58, 0x2C, +0x45, 0x00, 0x40, 0x44, 0x21, 0x00, 0x00, 0x18, 0x01, 0x1D, 0x00, 0x72, 0x51, 0xD0, 0x1E, 0x20, +0x6E, 0x28, 0x55, 0x00, 0x40, 0x44, 0x21, 0x00, 0x00, 0x18, 0x8C, 0x0A, 0xD0, 0x8A, 0x20, 0xE0, +0x2D, 0x10, 0x10, 0x3E, 0x96, 0x00, 0x40, 0x44, 0x21, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x10, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x7F, +0x02, 0x03, 0x09, 0xF3, 0x40, 0x23, 0x09, 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x85 +}; + static struct rkmodule_csi_dphy_param rk3588_dcphy_param = { .vendor = PHY_VENDOR_SAMSUNG, .lp_vol_ref = 3, @@ -95,6 +121,11 @@ struct regval { u16 delay; }; +struct edid_msg { + u32 max_width; + const u8 *edid_list; +}; + struct max96756_mode { u32 width; u32 height; @@ -156,6 +187,9 @@ struct max96756 { const char *module_facing; const char *module_name; const char *len_name; + + bool writeedid_enable; + const struct edid_msg *cur_edid_msg; }; #define to_max96756(sd) container_of(sd, struct max96756, subdev) @@ -238,6 +272,29 @@ static const struct regval max96756_mipi_1080p_60fps[] = { { 0x48, REG_NULL, 0x00, 0x00 }, }; +static const struct regval max96745_reconfig_begin[] = { + + { 0x40, 0x7000, 0x00, 0x00 }, // Disable LINK_ENABLE + { 0x40, 0x6422, 0x05, 0x00 }, + { 0x40, REG_NULL, 0x00, 0x00 }, +}; + +static const struct regval max96745_reconfig_end[] = { + + { 0x40, 0x6422, 0x73, 0x00 }, + { 0x40, 0x7054, 0x03, 0x32 }, // video input and link reset + { 0x40, 0x7000, 0x01, 0x00 }, // Enable LINK_ENABLE + { 0x48, 0x0010, 0x25, 0x32 }, // max96756 reset one shot + { 0x48, REG_NULL, 0x00, 0x00 }, +}; + +static const struct edid_msg edid_msgs[] = { + { + .max_width = 1920, + .edid_list = edid_1080p60_720p_480p_rgb888, + }, +}; + static const struct max96756_mode supported_modes[] = { { .width = 1920, @@ -249,6 +306,26 @@ static const struct max96756_mode supported_modes[] = { .reg_list = max96756_mipi_1080p_60fps, .link_freq_idx = 0, }, + { + .width = 1280, + .height = 720, + .max_fps = { + .numerator = 10000, + .denominator = 600000, + }, + .reg_list = max96756_mipi_1080p_60fps, + .link_freq_idx = 0, + }, + { + .width = 720, + .height = 480, + .max_fps = { + .numerator = 10000, + .denominator = 600000, + }, + .reg_list = max96756_mipi_1080p_60fps, + .link_freq_idx = 0, + }, }; static const struct max96756_mode supported_modes_dcphy[] = { @@ -352,6 +429,40 @@ static int max96756_read_reg(struct i2c_client *client, u16 reg, return 0; } +static int max96756_write_reg_burst(struct i2c_client *client, u16 reg, + const u8 *val) +{ + struct i2c_msg msgs[1]; + int ret; + int total_len = 2 + MAX96756_EDID_COUNT; + u8 *buf; + + buf = kzalloc(total_len, GFP_KERNEL); + if (buf == NULL) { + dev_err(&client->dev, "Failed to allocate bytes\n"); + return -ENOMEM; + } + + buf[0] = (reg >> 8) & 0xff; + buf[1] = reg & 0xff; + memcpy(&buf[2], val, MAX96756_EDID_COUNT); + + /* Fill msg struct */ + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = total_len; + msgs[0].buf = buf; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret != ARRAY_SIZE(msgs)) { + kfree(buf); + return -EIO; + } + + kfree(buf); + return 0; +} + static int max96756_get_reso_dist(const struct max96756_mode *mode, struct v4l2_mbus_framefmt *framefmt) { @@ -727,6 +838,59 @@ static int max96756_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, } } +static int max96745_reconfig_edid(struct max96756 *max96756) +{ + int ret = -1; + u32 val = 0, i, flag = 0; + unsigned short temp_addr = 0; + + temp_addr = max96756->client->addr; + + //wait for link lock + for (i = 0; i < 10; i++) { // Maximum waiting time 100ms + max96756_read_reg(max96756->client, 0x0013, + MAX96756_REG_VALUE_08BIT, &val); + if (val & (1 << 3)) { + dev_dbg(&max96756->client->dev, "serdes reg locked 0x%x\n", val); + flag = 1; + break; + } + usleep_range(10000, 10100); + } + + if (flag != 1) { + dev_err(&max96756->client->dev, "%s: serdes reg still not locked ", __func__); + return ret; + } + + //common begin + ret = max96756_write_array(max96756->client, + max96745_reconfig_begin); + if (ret) { + dev_err(&max96756->client->dev, "max96745_reconfig_begin err\n"); + max96756->client->addr = temp_addr; + return ret; + } + + //write edid table + max96756->client->addr = MAX96745_I2CADDR; + ret = max96756_write_reg_burst(max96756->client, 0x6500, max96756->cur_edid_msg->edid_list); + if (ret) { + dev_err(&max96756->client->dev, "edid_table err\n"); + max96756->client->addr = temp_addr; + return ret; + } + + //common end + ret = max96756_write_array(max96756->client, + max96745_reconfig_end); + if (ret) + dev_err(&max96756->client->dev, "max96745_reconfig_end err\n"); + + max96756->client->addr = temp_addr; + return ret; +} + static int __max96756_start_stream(struct max96756 *max96756) { int ret; @@ -739,10 +903,16 @@ static int __max96756_start_stream(struct max96756 *max96756) return ret; } + if (max96756->writeedid_enable) { + ret = max96745_reconfig_edid(max96756); + if (ret) { + dev_err(&max96756->client->dev, "Failed to write edid\n"); + return ret; + } + } + /* In case these controls are set before streaming */ - mutex_unlock(&max96756->mutex); - ret = v4l2_ctrl_handler_setup(&max96756->ctrl_handler); - mutex_lock(&max96756->mutex); + ret = __v4l2_ctrl_handler_setup(&max96756->ctrl_handler); if (ret) { dev_warn(&max96756->client->dev, "Failed to setup ctrl\n"); return ret; @@ -1329,6 +1499,8 @@ static int max96756_probe(struct i2c_client *client) max96756->client = client; max96756->cur_mode = &supported_modes[0]; + max96756->writeedid_enable = of_property_read_bool(node, MAX96756_WRITEEDID_ENABLE); + max96756->cur_edid_msg = &edid_msgs[0]; max96756->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_OUT_LOW); if (IS_ERR(max96756->pwdn_gpio)) From d5e575bdf73249e82315db0ea25abcb0188048c2 Mon Sep 17 00:00:00 2001 From: Zefa Chen Date: Wed, 27 Aug 2025 15:55:24 +0800 Subject: [PATCH 04/13] phy: rockchip: csi2-dphy: fixes lvds bit-width error for rv1126b Change-Id: I56007548f832c3c89c6e2be324c30ca5445945a2 Signed-off-by: Zefa Chen --- .../phy/rockchip/phy-rockchip-csi2-dphy-hw.c | 44 ++++++++++++++++++- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/drivers/phy/rockchip/phy-rockchip-csi2-dphy-hw.c b/drivers/phy/rockchip/phy-rockchip-csi2-dphy-hw.c index 4e96b19ac333..2816abd07a00 100644 --- a/drivers/phy/rockchip/phy-rockchip-csi2-dphy-hw.c +++ b/drivers/phy/rockchip/phy-rockchip-csi2-dphy-hw.c @@ -650,6 +650,40 @@ static unsigned char get_lvds_data_width(u32 pixelformat) } } +static unsigned char get_lvds_data_width_rv1126b(u32 pixelformat) +{ + switch (pixelformat) { + /* csi raw8 */ + case MEDIA_BUS_FMT_SBGGR8_1X8: + case MEDIA_BUS_FMT_SGBRG8_1X8: + case MEDIA_BUS_FMT_SGRBG8_1X8: + case MEDIA_BUS_FMT_SRGGB8_1X8: + return 0x1; + /* csi raw10 */ + case MEDIA_BUS_FMT_SBGGR10_1X10: + case MEDIA_BUS_FMT_SGBRG10_1X10: + case MEDIA_BUS_FMT_SGRBG10_1X10: + case MEDIA_BUS_FMT_SRGGB10_1X10: + return 0x2; + /* csi raw12 */ + case MEDIA_BUS_FMT_SBGGR12_1X12: + case MEDIA_BUS_FMT_SGBRG12_1X12: + case MEDIA_BUS_FMT_SGRBG12_1X12: + case MEDIA_BUS_FMT_SRGGB12_1X12: + return 0x3; + /* csi uyvy 422 */ + case MEDIA_BUS_FMT_UYVY8_2X8: + case MEDIA_BUS_FMT_VYUY8_2X8: + case MEDIA_BUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_YVYU8_2X8: + case MEDIA_BUS_FMT_RGB888_1X24: + return 0x1; + + default: + return 0x2; + } +} + static void csi2_dphy_hw_do_reset(struct csi2_dphy_hw *hw) { if (hw->rsts_bulk) @@ -991,7 +1025,10 @@ static int csi2_dphy_hw_stream_on(struct csi2_dphy *dphy, write_csi2_dphy_reg(hw, CSI2PHY_PATH0_MODEL, 0x2); } else { write_csi2_dphy_reg(hw, CSI2PHY_PATH0_MODEL, 0x4); - lvds_width = get_lvds_data_width(sensor->format.code); + if (hw->drv_data->chip_id == CHIP_ID_RV1126B) + lvds_width = get_lvds_data_width_rv1126b(sensor->format.code); + else + lvds_width = get_lvds_data_width(sensor->format.code); write_csi2_dphy_reg(hw, CSI2PHY_PATH0_LVDS_MODEL, (lvds_width << 4) | 0X0f); } } else { @@ -999,7 +1036,10 @@ static int csi2_dphy_hw_stream_on(struct csi2_dphy *dphy, write_csi2_dphy_reg(hw, CSI2PHY_PATH1_MODEL, 0x2); } else { write_csi2_dphy_reg(hw, CSI2PHY_PATH1_MODEL, 0x4); - lvds_width = get_lvds_data_width(sensor->format.code); + if (hw->drv_data->chip_id == CHIP_ID_RV1126B) + lvds_width = get_lvds_data_width_rv1126b(sensor->format.code); + else + lvds_width = get_lvds_data_width(sensor->format.code); write_csi2_dphy_reg(hw, CSI2PHY_PATH1_LVDS_MODEL, (lvds_width << 4) | 0X0f); } } From 0caa02b632592f56dd61ba75f7de9f0fd0f9a0d8 Mon Sep 17 00:00:00 2001 From: Zefa Chen Date: Mon, 8 Sep 2025 17:51:50 +0800 Subject: [PATCH 05/13] phy: rockchip: csi2_dphy: add hw_idx to distinguish dev Change-Id: I072cedcba316cf5d26335cbead272457bee2f61c Signed-off-by: Zefa Chen --- drivers/phy/rockchip/phy-rockchip-csi2-dphy-common.h | 1 + drivers/phy/rockchip/phy-rockchip-csi2-dphy-hw.c | 2 +- drivers/phy/rockchip/phy-rockchip-csi2-dphy.c | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/phy/rockchip/phy-rockchip-csi2-dphy-common.h b/drivers/phy/rockchip/phy-rockchip-csi2-dphy-common.h index 295974d9bc89..43c595b70e52 100644 --- a/drivers/phy/rockchip/phy-rockchip-csi2-dphy-common.h +++ b/drivers/phy/rockchip/phy-rockchip-csi2-dphy-common.h @@ -128,6 +128,7 @@ struct csi2_dphy_hw { int dphy_dev_num; enum csi2_dphy_lane_mode lane_mode; struct resource *res; + int hw_idx; int (*stream_on)(struct csi2_dphy *dphy, struct v4l2_subdev *sd); int (*stream_off)(struct csi2_dphy *dphy, struct v4l2_subdev *sd); diff --git a/drivers/phy/rockchip/phy-rockchip-csi2-dphy-hw.c b/drivers/phy/rockchip/phy-rockchip-csi2-dphy-hw.c index 2816abd07a00..47ac3ce72124 100644 --- a/drivers/phy/rockchip/phy-rockchip-csi2-dphy-hw.c +++ b/drivers/phy/rockchip/phy-rockchip-csi2-dphy-hw.c @@ -712,7 +712,7 @@ static void csi2_dphy_config_dual_mode(struct csi2_dphy *dphy, if (hw->lane_mode == LANE_MODE_FULL) { val = !GRF_CSI2PHY_LANE_SEL_SPLIT; - if (dphy->phy_index < 3) { + if (hw->hw_idx == 0) { write_grf_reg(hw, GRF_DPHY_CSI2PHY_DATALANE_EN, GENMASK(sensor->lanes - 1, 0)); write_grf_reg(hw, GRF_DPHY_CSI2PHY_CLKLANE_EN, 0x1); diff --git a/drivers/phy/rockchip/phy-rockchip-csi2-dphy.c b/drivers/phy/rockchip/phy-rockchip-csi2-dphy.c index 9bbf7f5d1a3b..418405ed4bc0 100644 --- a/drivers/phy/rockchip/phy-rockchip-csi2-dphy.c +++ b/drivers/phy/rockchip/phy-rockchip-csi2-dphy.c @@ -1161,6 +1161,7 @@ static int rockchip_csi2_dphy_get_inno_phy_hw(struct csi2_dphy *dphy) dphy->phy_index); return -EINVAL; } + dphy_hw->hw_idx = i; dphy->dphy_hw_group[i] = dphy_hw; } return 0; From 552ee9dedd4a8c825961d1333f8d944baccf8791 Mon Sep 17 00:00:00 2001 From: Zefa Chen Date: Mon, 8 Sep 2025 10:15:12 +0800 Subject: [PATCH 06/13] media: rockchip: vicap fixes multi combine mode error for rv1126b Change-Id: I3d3faf319b5f03b1ded1e5b1eb6fd704939ddf71 Signed-off-by: Zefa Chen --- drivers/media/platform/rockchip/cif/capture.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/rockchip/cif/capture.c b/drivers/media/platform/rockchip/cif/capture.c index a062accac7d4..29f72a391c33 100644 --- a/drivers/media/platform/rockchip/cif/capture.c +++ b/drivers/media/platform/rockchip/cif/capture.c @@ -5429,19 +5429,24 @@ static int rkcif_csi_stream_start(struct rkcif_stream *stream, unsigned int mode } if (stream->cifdev->chip_id < CHIP_RK3588_CIF) { rkcif_csi_channel_set(stream, channel, mbus_type); - } else if (stream->cifdev->chip_id < CHIP_RV1126B_CIF) { + } else { if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { for (i = 0; i < channel->capture_info.multi_dev.dev_num; i++) { dev->csi_host_idx = channel->capture_info.multi_dev.dev_idx[i]; - rkcif_csi_channel_set_v1(stream, channel, mbus_type, mode, i); + if (stream->cifdev->chip_id < CHIP_RV1126B_CIF) + rkcif_csi_channel_set_v1(stream, channel, mbus_type, mode, i); + else + rkcif_csi_channel_set_rv1126b(stream, channel, mbus_type, mode, i); } } else { if (!dev->switch_info.is_use_switch || - atomic_inc_return(&dev->hw_dev->switch_stream_cnt[dev->switch_info.host_idx]) == 1) - rkcif_csi_channel_set_v1(stream, channel, mbus_type, mode, 0); + atomic_inc_return(&dev->hw_dev->switch_stream_cnt[dev->switch_info.host_idx]) == 1) { + if (stream->cifdev->chip_id < CHIP_RV1126B_CIF) + rkcif_csi_channel_set_v1(stream, channel, mbus_type, mode, 0); + else + rkcif_csi_channel_set_rv1126b(stream, channel, mbus_type, mode, 0); + } } - } else { - rkcif_csi_channel_set_rv1126b(stream, channel, mbus_type, mode, 0); } } else { if (stream->cifdev->chip_id >= CHIP_RK3588_CIF) { From 02aea86b5729cd24893b9f33d4e32065ffd1fcec Mon Sep 17 00:00:00 2001 From: Zefa Chen Date: Fri, 21 Mar 2025 17:30:28 +0800 Subject: [PATCH 07/13] media: rockchip: vicap add support RAW14 Change-Id: I80024552bddcf0452e96c2621a0f4fb7ae4c4b76 Signed-off-by: Zefa Chen --- drivers/media/platform/rockchip/cif/capture.c | 199 ++++++++++++++---- drivers/media/platform/rockchip/cif/regs.h | 1 + .../media/platform/rockchip/cif/subdev-itf.c | 21 ++ 3 files changed, 182 insertions(+), 39 deletions(-) diff --git a/drivers/media/platform/rockchip/cif/capture.c b/drivers/media/platform/rockchip/cif/capture.c index 29f72a391c33..4693ab164847 100644 --- a/drivers/media/platform/rockchip/cif/capture.c +++ b/drivers/media/platform/rockchip/cif/capture.c @@ -273,45 +273,13 @@ static const struct cif_output_fmt out_fmts[] = { .raw_bpp = 12, .csi_fmt_val = CSI_WRDDR_TYPE_RAW12, .fmt_type = CIF_FMT_TYPE_RAW, - }, { - .fourcc = V4L2_PIX_FMT_SBGGR16, - .cplanes = 1, - .mplanes = 1, - .bpp = { 16 }, - .raw_bpp = 16, - .csi_fmt_val = CSI_WRDDR_TYPE_RAW8, - .fmt_type = CIF_FMT_TYPE_RAW, - }, { - .fourcc = V4L2_PIX_FMT_SGBRG16, - .cplanes = 1, - .mplanes = 1, - .bpp = { 16 }, - .raw_bpp = 16, - .csi_fmt_val = CSI_WRDDR_TYPE_RAW8, - .fmt_type = CIF_FMT_TYPE_RAW, - }, { - .fourcc = V4L2_PIX_FMT_SGRBG16, - .cplanes = 1, - .mplanes = 1, - .bpp = { 16 }, - .raw_bpp = 16, - .csi_fmt_val = CSI_WRDDR_TYPE_RAW8, - .fmt_type = CIF_FMT_TYPE_RAW, - }, { - .fourcc = V4L2_PIX_FMT_SRGGB16, - .cplanes = 1, - .mplanes = 1, - .bpp = { 16 }, - .raw_bpp = 16, - .csi_fmt_val = CSI_WRDDR_TYPE_RAW8, - .fmt_type = CIF_FMT_TYPE_RAW, }, { .fourcc = V4L2_PIX_FMT_Y16, .cplanes = 1, .mplanes = 1, .bpp = { 16 }, .raw_bpp = 16, - .csi_fmt_val = CSI_WRDDR_TYPE_RAW8, + .csi_fmt_val = CSI_WRDDR_TYPE_RAW16, .fmt_type = CIF_FMT_TYPE_RAW, }, { .fourcc = V4L2_PIX_FMT_GREY, @@ -345,6 +313,13 @@ static const struct cif_output_fmt out_fmts[] = { .raw_bpp = 12, .csi_fmt_val = CSI_WRDDR_TYPE_RAW12, .fmt_type = CIF_FMT_TYPE_RAW, + }, { + .fourcc = V4L2_PIX_FMT_Y14, + .cplanes = 1, + .mplanes = 1, + .bpp = { 16 }, + .raw_bpp = 14, + .csi_fmt_val = CSI_WRDDR_TYPE_RAW14_RK3588, }, { .fourcc = V4L2_PIX_FMT_Y10, .cplanes = 1, @@ -385,7 +360,39 @@ static const struct cif_output_fmt out_fmts[] = { .raw_bpp = 16, .csi_fmt_val = CSI_WRDDR_TYPE_RAW16, .fmt_type = CIF_FMT_TYPE_RAW, - } + }, { + .fourcc = V4L2_PIX_FMT_SBGGR14, + .cplanes = 1, + .mplanes = 1, + .bpp = { 16 }, + .raw_bpp = 14, + .csi_fmt_val = CSI_WRDDR_TYPE_RAW14_RK3588, + .fmt_type = CIF_FMT_TYPE_RAW, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG14, + .cplanes = 1, + .mplanes = 1, + .bpp = { 16 }, + .raw_bpp = 14, + .csi_fmt_val = CSI_WRDDR_TYPE_RAW14_RK3588, + .fmt_type = CIF_FMT_TYPE_RAW, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG14, + .cplanes = 1, + .mplanes = 1, + .bpp = { 16 }, + .raw_bpp = 14, + .csi_fmt_val = CSI_WRDDR_TYPE_RAW14_RK3588, + .fmt_type = CIF_FMT_TYPE_RAW, + }, { + .fourcc = V4L2_PIX_FMT_SRGGB14, + .cplanes = 1, + .mplanes = 1, + .bpp = { 16 }, + .raw_bpp = 14, + .csi_fmt_val = CSI_WRDDR_TYPE_RAW14_RK3588, + .fmt_type = CIF_FMT_TYPE_RAW, + }, /* TODO: We can support NV12M/NV21M/NV16M/NV61M too */ }; @@ -572,6 +579,12 @@ static const struct cif_input_fmt in_fmts[] = { .csi_fmt_val = CSI_WRDDR_TYPE_RAW12, .fmt_type = CIF_FMT_TYPE_RAW, .field = V4L2_FIELD_NONE, + }, { + .mbus_code = MEDIA_BUS_FMT_Y14_1X14, + .dvp_fmt_val = INPUT_MODE_RAW | RAW_DATA_WIDTH_14, + .csi_fmt_val = CSI_WRDDR_TYPE_RAW14_RK3588, + .fmt_type = CIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, }, { .mbus_code = MEDIA_BUS_FMT_EBD_1X8, .dvp_fmt_val = INPUT_MODE_RAW | RAW_DATA_WIDTH_8, @@ -614,6 +627,26 @@ static const struct cif_input_fmt in_fmts[] = { .csi_fmt_val = CSI_WRDDR_TYPE_RAW16, .fmt_type = CIF_FMT_TYPE_RAW, .field = V4L2_FIELD_NONE, + }, { + .mbus_code = MEDIA_BUS_FMT_SBGGR14_1X14, + .csi_fmt_val = CSI_WRDDR_TYPE_RAW14_RK3588, + .fmt_type = CIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, { + .mbus_code = MEDIA_BUS_FMT_SGBRG14_1X14, + .csi_fmt_val = CSI_WRDDR_TYPE_RAW14_RK3588, + .fmt_type = CIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, { + .mbus_code = MEDIA_BUS_FMT_SGRBG14_1X14, + .csi_fmt_val = CSI_WRDDR_TYPE_RAW14_RK3588, + .fmt_type = CIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, { + .mbus_code = MEDIA_BUS_FMT_SRGGB14_1X14, + .csi_fmt_val = CSI_WRDDR_TYPE_RAW14_RK3588, + .fmt_type = CIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, }, }; @@ -789,6 +822,18 @@ static int rkcif_output_fmt_check(struct rkcif_stream *stream, if (output_fmt->fourcc == V4L2_PIX_FMT_NV12) ret = 0; break; + case MEDIA_BUS_FMT_SBGGR14_1X14: + case MEDIA_BUS_FMT_SGBRG14_1X14: + case MEDIA_BUS_FMT_SGRBG14_1X14: + case MEDIA_BUS_FMT_SRGGB14_1X14: + case MEDIA_BUS_FMT_Y14_1X14: + if (output_fmt->fourcc == V4L2_PIX_FMT_SRGGB14 || + output_fmt->fourcc == V4L2_PIX_FMT_SGRBG14 || + output_fmt->fourcc == V4L2_PIX_FMT_SGBRG14 || + output_fmt->fourcc == V4L2_PIX_FMT_SBGGR14 || + output_fmt->fourcc == V4L2_PIX_FMT_Y14) + ret = 0; + break; default: break; } @@ -915,6 +960,13 @@ static unsigned char get_data_type(u32 pixelformat, u8 cmd_mode_en, u8 dsi_input case MEDIA_BUS_FMT_SRGGB12_1X12: case MEDIA_BUS_FMT_Y12_1X12: return 0x2c; + /* csi raw14 */ + case MEDIA_BUS_FMT_SBGGR14_1X14: + case MEDIA_BUS_FMT_SGBRG14_1X14: + case MEDIA_BUS_FMT_SGRBG14_1X14: + case MEDIA_BUS_FMT_SRGGB14_1X14: + case MEDIA_BUS_FMT_Y14_1X14: + return 0x2d; /* csi raw16 */ case MEDIA_BUS_FMT_SBGGR16_1X16: case MEDIA_BUS_FMT_SGBRG16_1X16: @@ -4031,6 +4083,7 @@ static int rkcif_csi_channel_init(struct rkcif_stream *stream, const struct cif_output_fmt *fmt; u32 fourcc; int vc = dev->channels[stream->id].vc; + u32 raw_bpp = 0; channel->enable = 1; channel->width = stream->pixm.width; @@ -4096,11 +4149,20 @@ static int rkcif_csi_channel_init(struct rkcif_stream *stream, if (fmt->fmt_type == CIF_FMT_TYPE_RAW && stream->is_compact && fmt->csi_fmt_val != CSI_WRDDR_TYPE_RGB888 && fmt->csi_fmt_val != CSI_WRDDR_TYPE_RGB565) { + if (dev->chip_id < CHIP_RV1126B_CIF && + (fmt->fourcc == V4L2_PIX_FMT_Y14 || + fmt->fourcc == V4L2_PIX_FMT_SBGGR14 || + fmt->fourcc == V4L2_PIX_FMT_SGBRG14 || + fmt->fourcc == V4L2_PIX_FMT_SGRBG14 || + fmt->fourcc == V4L2_PIX_FMT_SRGGB14)) + raw_bpp = 12; + else + raw_bpp = fmt->raw_bpp; if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { - channel->virtual_width = ALIGN(channel->width * 2 * fmt->raw_bpp / 8, 256); - channel->left_virtual_width = channel->width * fmt->raw_bpp / 8; + channel->virtual_width = ALIGN(channel->width * 2 * raw_bpp / 8, 256); + channel->left_virtual_width = channel->width * raw_bpp / 8; } else { - channel->virtual_width = ALIGN(channel->width * fmt->raw_bpp / 8, 256); + channel->virtual_width = ALIGN(channel->width * raw_bpp / 8, 256); } } else { if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { @@ -4453,9 +4515,14 @@ static int rkcif_csi_get_output_type_mask(struct rkcif_stream *stream) case V4L2_PIX_FMT_SGRBG12: case V4L2_PIX_FMT_SGBRG12: case V4L2_PIX_FMT_SBGGR12: + case V4L2_PIX_FMT_SRGGB14: + case V4L2_PIX_FMT_SGRBG14: + case V4L2_PIX_FMT_SGBRG14: + case V4L2_PIX_FMT_SBGGR14: case V4L2_PIX_FMT_GREY: case V4L2_PIX_FMT_Y10: case V4L2_PIX_FMT_Y12: + case V4L2_PIX_FMT_Y14: if (stream->is_compact) mask = CSI_WRDDR_TYPE_RAW_COMPACT; else @@ -4523,9 +4590,14 @@ static int rkcif_csi_get_output_type_mask_rk3576(struct rkcif_stream *stream) case V4L2_PIX_FMT_SGRBG12: case V4L2_PIX_FMT_SGBRG12: case V4L2_PIX_FMT_SBGGR12: + case V4L2_PIX_FMT_SRGGB14: + case V4L2_PIX_FMT_SGRBG14: + case V4L2_PIX_FMT_SGBRG14: + case V4L2_PIX_FMT_SBGGR14: case V4L2_PIX_FMT_GREY: case V4L2_PIX_FMT_Y10: case V4L2_PIX_FMT_Y12: + case V4L2_PIX_FMT_Y14: if (stream->is_compact) mask = CSI_WRDDR_TYPE_RAW_COMPACT << 3; else @@ -7357,6 +7429,11 @@ static u32 rkcif_align_bits_per_pixel(struct rkcif_stream *stream, case V4l2_PIX_FMT_EBD8: case V4L2_PIX_FMT_Y10: case V4L2_PIX_FMT_Y12: + case V4L2_PIX_FMT_Y14: + case V4L2_PIX_FMT_SRGGB14: + case V4L2_PIX_FMT_SGRBG14: + case V4L2_PIX_FMT_SGBRG14: + case V4L2_PIX_FMT_SBGGR14: if (stream->cifdev->chip_id < CHIP_RV1126_CIF) { bpp = max(fmt->bpp[plane_index], (u8)CIF_RAW_STORED_BIT_WIDTH); cal = CIF_RAW_STORED_BIT_WIDTH; @@ -7661,9 +7738,14 @@ static int rkcif_dvp_get_output_type_mask(struct rkcif_stream *stream) case V4L2_PIX_FMT_SGRBG12: case V4L2_PIX_FMT_SGBRG12: case V4L2_PIX_FMT_SBGGR12: + case V4L2_PIX_FMT_SRGGB14: + case V4L2_PIX_FMT_SGRBG14: + case V4L2_PIX_FMT_SGBRG14: + case V4L2_PIX_FMT_SBGGR14: case V4L2_PIX_FMT_GREY: case V4L2_PIX_FMT_Y10: case V4L2_PIX_FMT_Y12: + case V4L2_PIX_FMT_Y14: if (stream->is_compact) mask = CSI_WRDDR_TYPE_RAW_COMPACT << 11; else @@ -7742,6 +7824,11 @@ static int rkcif_dvp_get_output_type_mask_rk3576(struct rkcif_stream *stream) case V4L2_PIX_FMT_GREY: case V4L2_PIX_FMT_Y10: case V4L2_PIX_FMT_Y12: + case V4L2_PIX_FMT_Y14: + case V4L2_PIX_FMT_SRGGB14: + case V4L2_PIX_FMT_SGRBG14: + case V4L2_PIX_FMT_SGBRG14: + case V4L2_PIX_FMT_SBGGR14: if (stream->is_compact) mask = CSI_WRDDR_TYPE_RAW_COMPACT << 15; else @@ -8866,6 +8953,7 @@ int rkcif_set_fmt(struct rkcif_stream *stream, struct rkcif_extend_info *extend_line = &stream->extend_line; struct csi_channel_info *channel_info = &dev->channels[stream->id]; int ret; + u32 raw_bpp = 0; for (i = 0; i < RKCIF_MAX_PLANE; i++) memset(&pixm->plane_fmt[i], 0, sizeof(struct v4l2_plane_pix_format)); @@ -8981,13 +9069,31 @@ int rkcif_set_fmt(struct rkcif_stream *stream, dev->active_sensor->mbus.type == V4L2_MBUS_CCP2) && fmt->csi_fmt_val != CSI_WRDDR_TYPE_RGB888 && fmt->csi_fmt_val != CSI_WRDDR_TYPE_RGB565) { - bpl = ALIGN(width * fmt->raw_bpp / 8, 256); + if (dev->chip_id < CHIP_RV1126B_CIF && + (fmt->fourcc == V4L2_PIX_FMT_Y14 || + fmt->fourcc == V4L2_PIX_FMT_SBGGR14 || + fmt->fourcc == V4L2_PIX_FMT_SGBRG14 || + fmt->fourcc == V4L2_PIX_FMT_SGRBG14 || + fmt->fourcc == V4L2_PIX_FMT_SRGGB14)) + raw_bpp = 12; + else + raw_bpp = fmt->raw_bpp; + bpl = ALIGN(width * raw_bpp / 8, 256); } else { if (fmt->fmt_type == CIF_FMT_TYPE_RAW && stream->is_compact && fmt->csi_fmt_val != CSI_WRDDR_TYPE_RGB888 && fmt->csi_fmt_val != CSI_WRDDR_TYPE_RGB565 && dev->chip_id >= CHIP_RK3588_CIF) { - bpl = ALIGN(width * fmt->raw_bpp / 8, 256); + if (dev->chip_id < CHIP_RV1126B_CIF && + (fmt->fourcc == V4L2_PIX_FMT_Y14 || + fmt->fourcc == V4L2_PIX_FMT_SBGGR14 || + fmt->fourcc == V4L2_PIX_FMT_SGBRG14 || + fmt->fourcc == V4L2_PIX_FMT_SGRBG14 || + fmt->fourcc == V4L2_PIX_FMT_SRGGB14)) + raw_bpp = 12; + else + raw_bpp = fmt->raw_bpp; + bpl = ALIGN(width * raw_bpp / 8, 256); } else { bpp = rkcif_align_bits_per_pixel(stream, fmt, i); bpl = ALIGN(width * bpp / CIF_YUV_STORED_BIT_WIDTH, 8); @@ -13132,6 +13238,21 @@ u32 rkcif_mbus_pixelcode_to_v4l2(u32 pixelcode) case MEDIA_BUS_FMT_SRGGB16_1X16: pixelformat = V4L2_PIX_FMT_SRGGB16; break; + case MEDIA_BUS_FMT_Y14_1X14: + pixelformat = V4L2_PIX_FMT_Y14; + break; + case MEDIA_BUS_FMT_SBGGR14_1X14: + pixelformat = V4L2_PIX_FMT_SBGGR14; + break; + case MEDIA_BUS_FMT_SGBRG14_1X14: + pixelformat = V4L2_PIX_FMT_SGBRG14; + break; + case MEDIA_BUS_FMT_SGRBG14_1X14: + pixelformat = V4L2_PIX_FMT_SGRBG14; + break; + case MEDIA_BUS_FMT_SRGGB14_1X14: + pixelformat = V4L2_PIX_FMT_SRGGB14; + break; default: pixelformat = V4L2_PIX_FMT_SRGGB10; } diff --git a/drivers/media/platform/rockchip/cif/regs.h b/drivers/media/platform/rockchip/cif/regs.h index eea73b3ced40..755898a5f7de 100644 --- a/drivers/media/platform/rockchip/cif/regs.h +++ b/drivers/media/platform/rockchip/cif/regs.h @@ -874,6 +874,7 @@ enum cif_reg_index { #define RAW_DATA_WIDTH_8 (0x00 << 11) #define RAW_DATA_WIDTH_10 (0x01 << 11) #define RAW_DATA_WIDTH_12 (0x02 << 11) +#define RAW_DATA_WIDTH_14 (0x03 << 11) #define MIPI_MODE_32BITS_BYPASS (0x00 << 13) #define MIPI_MODE_RGB (0x01 << 13) #define MIPI_MODE_YUV (0x02 << 13) diff --git a/drivers/media/platform/rockchip/cif/subdev-itf.c b/drivers/media/platform/rockchip/cif/subdev-itf.c index cad599f5831e..ff16cc6452f8 100644 --- a/drivers/media/platform/rockchip/cif/subdev-itf.c +++ b/drivers/media/platform/rockchip/cif/subdev-itf.c @@ -208,6 +208,27 @@ static int sditf_get_set_fmt(struct v4l2_subdev *sd, priv->cap_info.offset_x = 0; priv->cap_info .offset_y = 0; } + if (cif_dev->chip_id < CHIP_RV1126B_CIF) { + switch (fmt->format.code) { + case MEDIA_BUS_FMT_Y14_1X14: + fmt->format.code = MEDIA_BUS_FMT_Y12_1X12; + break; + case MEDIA_BUS_FMT_SBGGR14_1X14: + fmt->format.code = MEDIA_BUS_FMT_SBGGR12_1X12; + break; + case MEDIA_BUS_FMT_SGBRG14_1X14: + fmt->format.code = MEDIA_BUS_FMT_SGBRG12_1X12; + break; + case MEDIA_BUS_FMT_SGRBG14_1X14: + fmt->format.code = MEDIA_BUS_FMT_SGRBG12_1X12; + break; + case MEDIA_BUS_FMT_SRGGB14_1X14: + fmt->format.code = MEDIA_BUS_FMT_SRGGB12_1X12; + break; + default: + break; + } + } priv->cap_info.width = fmt->format.width; priv->cap_info.height = fmt->format.height; pixm.pixelformat = rkcif_mbus_pixelcode_to_v4l2(fmt->format.code); From f97148ab5991baead2bc1459e5004fda01ef991d Mon Sep 17 00:00:00 2001 From: Shengfei Xu Date: Wed, 24 Sep 2025 10:37:00 +0800 Subject: [PATCH 08/13] regulator: rk806: Resolving rk806m abnormal power-off during DVS Mode If the RK806M DVS mode does not follow the configured timing sequence, it may cause abnormal power-off. The settings must be configured in the following order: entering voltage adjustment: first configure SLPn_FUN, then configure XXX_SLP_CTR_SEL at addresses 0x64~0x6e. exiting voltage adjustment: first clear XXX_SLP_CTR_SEL at addresses 0x64~0x6e to 0, then modify SLPn_FUN. Change-Id: I265d916b99160fddf467f7c12149490a95f75ca8 Signed-off-by: Shengfei Xu --- drivers/regulator/rk806-regulator.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/drivers/regulator/rk806-regulator.c b/drivers/regulator/rk806-regulator.c index 2672bf91dd77..3eba9d6e7957 100644 --- a/drivers/regulator/rk806-regulator.c +++ b/drivers/regulator/rk806-regulator.c @@ -1195,6 +1195,20 @@ static int __maybe_unused rk806_suspend(struct device *dev) for (i = RK806_ID_DCDC1; i < RK806_ID_END; i++) rk806_field_write(rk806, BUCK1_VSEL_CTR_SEL + i, CTR_BY_PWRCTRL1); } else { + for (i = RK806_ID_DCDC1; i < RK806_ID_END; i++) { + if (pdata->dvs_control_suspend[i] == CTR_BY_PWRCTRL1) { + chip_ver = rk806_field_read(rk806, CHIP_VER); + if (chip_ver & 0x08) + rk806_field_write(rk806, PWRCTRL1_FUN, PWRCTRL_SLP_FUN); + else + rk806_field_write(rk806, PWRCTRL1_FUN, PWRCTRL_DVS_FUN); + } + if (pdata->dvs_control_suspend[i] == CTR_BY_PWRCTRL2) + rk806_field_write(rk806, PWRCTRL2_FUN, PWRCTRL_DVS_FUN); + if (pdata->dvs_control_suspend[i] == CTR_BY_PWRCTRL3) + rk806_field_write(rk806, PWRCTRL3_FUN, PWRCTRL_DVS_FUN); + } + for (i = 0; i <= RK806_ID_PLDO6 - RK806_ID_PLDO1; i++) { value = rk806_field_read(rk806, PLDO1_ON_VSEL + i); rk806_field_write(rk806, PLDO1_SLP_VSEL + i, value); @@ -1209,18 +1223,6 @@ static int __maybe_unused rk806_suspend(struct device *dev) rk806_field_write(rk806, PLDO4_VSEL_CTR_SEL, pdata->dvs_control_suspend[RK806_ID_PLDO3]); rk806_field_write(rk806, PLDO5_VSEL_CTR_SEL, pdata->dvs_control_suspend[RK806_ID_PLDO4]); rk806_field_write(rk806, PLDO6_VSEL_CTR_SEL, pdata->dvs_control_suspend[RK806_ID_PLDO5]); - - for (i = RK806_ID_DCDC1; i < RK806_ID_END; i++) { - if (pdata->dvs_control_suspend[i] == CTR_BY_PWRCTRL2) - rk806_field_write(rk806, PWRCTRL2_FUN, PWRCTRL_DVS_FUN); - if (pdata->dvs_control_suspend[i] == CTR_BY_PWRCTRL3) - rk806_field_write(rk806, PWRCTRL3_FUN, PWRCTRL_DVS_FUN); - } - chip_ver = rk806_field_read(rk806, CHIP_VER); - if (chip_ver & 0x08) - rk806_field_write(rk806, PWRCTRL1_FUN, PWRCTRL_SLP_FUN); - else - rk806_field_write(rk806, PWRCTRL1_FUN, PWRCTRL_DVS_FUN); } return 0; From 6a5a34e3609497942e083aa65105d9da266a6823 Mon Sep 17 00:00:00 2001 From: Cai YiWei Date: Tue, 26 Aug 2025 15:35:01 +0800 Subject: [PATCH 09/13] media: rockchip: isp: support raw14 format Change-Id: I46569179161e2fc136654ab8ecbdff74ad228c4d Signed-off-by: Cai YiWei --- drivers/media/platform/rockchip/isp/csi.c | 2 + drivers/media/platform/rockchip/isp/dmarx.c | 52 ++++++++++++++++++ drivers/media/platform/rockchip/isp/regs.h | 1 + drivers/media/platform/rockchip/isp/rkisp.c | 60 +++++++++++++++++++-- 4 files changed, 112 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/rockchip/isp/csi.c b/drivers/media/platform/rockchip/isp/csi.c index 8a7cc961485a..74d1ba06e44e 100644 --- a/drivers/media/platform/rockchip/isp/csi.c +++ b/drivers/media/platform/rockchip/isp/csi.c @@ -644,6 +644,8 @@ int rkisp_csi_config_patch(struct rkisp_device *dev, bool is_pre_cfg) } else { rkisp_unite_write(dev, CSI2RX_CTRL0, SW_IBUF_OP_MODE(dev->hdr.op_mode), false); + rkisp_unite_write(dev, CSI2RX_DATA_IDS_1, + dev->isp_sdev.in_fmt.mipi_dt, false); } /* hdr merge */ switch (dev->hdr.op_mode) { diff --git a/drivers/media/platform/rockchip/isp/dmarx.c b/drivers/media/platform/rockchip/isp/dmarx.c index 40df35dda320..8e489f4a5ff5 100644 --- a/drivers/media/platform/rockchip/isp/dmarx.c +++ b/drivers/media/platform/rockchip/isp/dmarx.c @@ -196,6 +196,26 @@ static const struct capture_fmt rawrd_fmts[] = { .fmt_type = FMT_YUV, .bpp = { 16 }, .mplanes = 1, + }, { + .fourcc = V4L2_PIX_FMT_SRGGB14, + .fmt_type = FMT_BAYER, + .bpp = { 14 }, + .mplanes = 1, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG14, + .fmt_type = FMT_BAYER, + .bpp = { 14 }, + .mplanes = 1, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG14, + .fmt_type = FMT_BAYER, + .bpp = { 14 }, + .mplanes = 1, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR14, + .fmt_type = FMT_BAYER, + .bpp = { 14 }, + .mplanes = 1, }, { .fourcc = V4L2_PIX_FMT_SRGGB16, .fmt_type = FMT_BAYER, @@ -216,6 +236,11 @@ static const struct capture_fmt rawrd_fmts[] = { .fmt_type = FMT_BAYER, .bpp = { 16 }, .mplanes = 1, + }, { + .fourcc = V4L2_PIX_FMT_Y14, + .fmt_type = FMT_BAYER, + .bpp = { 14 }, + .mplanes = 1, }, { .fourcc = V4L2_PIX_FMT_Y16, .fmt_type = FMT_BAYER, @@ -367,6 +392,13 @@ static int rawrd_config_mi(struct rkisp_stream *stream) case V4L2_PIX_FMT_VYUY: val |= CIF_CSI2_DT_YUV422_8b; break; + case V4L2_PIX_FMT_SRGGB14: + case V4L2_PIX_FMT_SBGGR14: + case V4L2_PIX_FMT_SGRBG14: + case V4L2_PIX_FMT_SGBRG14: + case V4L2_PIX_FMT_Y14: + val |= CIF_CSI2_DT_RAW14; + break; case V4L2_PIX_FMT_SRGGB16: case V4L2_PIX_FMT_SBGGR16: case V4L2_PIX_FMT_SGRBG16: @@ -816,6 +848,26 @@ static int rkisp_set_fmt(struct rkisp_stream *stream, u32 xsubs = 1, ysubs = 1; unsigned int i; + if (stream->ispdev->isp_ver < ISP_V35 && + (pixm->pixelformat == V4L2_PIX_FMT_SBGGR14 || + pixm->pixelformat == V4L2_PIX_FMT_SGBRG14 || + pixm->pixelformat == V4L2_PIX_FMT_SGRBG14 || + pixm->pixelformat == V4L2_PIX_FMT_SRGGB14 || + pixm->pixelformat == V4L2_PIX_FMT_Y14)) { + if (pixm->pixelformat == V4L2_PIX_FMT_SBGGR14) + pixm->pixelformat = V4L2_PIX_FMT_SBGGR12; + else if (pixm->pixelformat == V4L2_PIX_FMT_SGBRG14) + pixm->pixelformat = V4L2_PIX_FMT_SGBRG12; + else if (pixm->pixelformat == V4L2_PIX_FMT_SGRBG14) + pixm->pixelformat = V4L2_PIX_FMT_SGRBG12; + else if (pixm->pixelformat == V4L2_PIX_FMT_SRGGB14) + pixm->pixelformat = V4L2_PIX_FMT_SRGGB12; + else + pixm->pixelformat = V4L2_PIX_FMT_Y12; + v4l2_warn(&stream->ispdev->v4l2_dev, + "no support raw14, rawrd format force to raw12\n"); + } + fmt = find_fmt(stream, pixm->pixelformat); if (!fmt) { v4l2_err(&stream->ispdev->v4l2_dev, diff --git a/drivers/media/platform/rockchip/isp/regs.h b/drivers/media/platform/rockchip/isp/regs.h index 79b6e89b9b23..6a378152535b 100644 --- a/drivers/media/platform/rockchip/isp/regs.h +++ b/drivers/media/platform/rockchip/isp/regs.h @@ -406,6 +406,7 @@ #define CIF_CSI2_DT_RAW8 0x2A #define CIF_CSI2_DT_RAW10 0x2B #define CIF_CSI2_DT_RAW12 0x2C +#define CIF_CSI2_DT_RAW14 0x2D #define CIF_CSI2_DT_RAW16 0x2e #define CIF_CSI2_DT_SPD 0x2F diff --git a/drivers/media/platform/rockchip/isp/rkisp.c b/drivers/media/platform/rockchip/isp/rkisp.c index 25f32da33b6f..9ed7eb162de7 100644 --- a/drivers/media/platform/rockchip/isp/rkisp.c +++ b/drivers/media/platform/rockchip/isp/rkisp.c @@ -2787,6 +2787,41 @@ static const struct ispsd_in_fmt rkisp_isp_input_formats[] = { .mipi_dt = CIF_CSI2_DT_RAW12, .yuv_seq = CIF_ISP_ACQ_PROP_YCBYCR, .bus_width = 12, + }, { + .name = "Y14_1X14", + .mbus_code = MEDIA_BUS_FMT_Y14_1X14, + .fmt_type = FMT_BAYER, + .mipi_dt = CIF_CSI2_DT_RAW14, + .yuv_seq = CIF_ISP_ACQ_PROP_YCBYCR, + .bus_width = 14, + }, { + .name = "SRGGB14_1X14", + .mbus_code = MEDIA_BUS_FMT_SRGGB14_1X14, + .fmt_type = FMT_BAYER, + .mipi_dt = CIF_CSI2_DT_RAW14, + .bayer_pat = RAW_RGGB, + .bus_width = 14, + }, { + .name = "SBGGR14_1X14", + .mbus_code = MEDIA_BUS_FMT_SBGGR14_1X14, + .fmt_type = FMT_BAYER, + .mipi_dt = CIF_CSI2_DT_RAW14, + .bayer_pat = RAW_BGGR, + .bus_width = 14, + }, { + .name = "SGBRG14_1X14", + .mbus_code = MEDIA_BUS_FMT_SGBRG14_1X14, + .fmt_type = FMT_BAYER, + .mipi_dt = CIF_CSI2_DT_RAW14, + .bayer_pat = RAW_GBRG, + .bus_width = 14, + }, { + .name = "SGRBG14_1X14", + .mbus_code = MEDIA_BUS_FMT_SGRBG14_1X14, + .fmt_type = FMT_BAYER, + .mipi_dt = CIF_CSI2_DT_RAW14, + .bayer_pat = RAW_GRBG, + .bus_width = 14, }, { .name = "SRGGB16_1X16", .mbus_code = MEDIA_BUS_FMT_SRGGB16_1X16, @@ -2795,21 +2830,21 @@ static const struct ispsd_in_fmt rkisp_isp_input_formats[] = { .bayer_pat = RAW_RGGB, .bus_width = 16, }, { - .name = "SBGGR12_1X16", + .name = "SBGGR16_1X16", .mbus_code = MEDIA_BUS_FMT_SBGGR16_1X16, .fmt_type = FMT_BAYER, .mipi_dt = CIF_CSI2_DT_RAW16, .bayer_pat = RAW_BGGR, .bus_width = 16, }, { - .name = "SGBRG12_1X16", + .name = "SGBRG16_1X16", .mbus_code = MEDIA_BUS_FMT_SGBRG16_1X16, .fmt_type = FMT_BAYER, .mipi_dt = CIF_CSI2_DT_RAW16, .bayer_pat = RAW_GBRG, .bus_width = 16, }, { - .name = "SGRBG12_1X16", + .name = "SGRBG16_1X16", .mbus_code = MEDIA_BUS_FMT_SGRBG16_1X16, .fmt_type = FMT_BAYER, .mipi_dt = CIF_CSI2_DT_RAW16, @@ -2974,6 +3009,25 @@ static int rkisp_isp_sd_set_fmt(struct v4l2_subdev *sd, struct v4l2_pix_format_mplane pixm = { 0 }; const struct ispsd_in_fmt *in_fmt; + if (isp_dev->isp_ver < ISP_V35 && + (mf->code == MEDIA_BUS_FMT_SGRBG14_1X14 || + mf->code == MEDIA_BUS_FMT_SGBRG14_1X14 || + mf->code == MEDIA_BUS_FMT_SBGGR14_1X14 || + mf->code == MEDIA_BUS_FMT_SRGGB14_1X14 || + mf->code == MEDIA_BUS_FMT_Y14_1X14)) { + if (mf->code == MEDIA_BUS_FMT_SGRBG14_1X14) + mf->code = MEDIA_BUS_FMT_SGRBG12_1X12; + else if (mf->code == MEDIA_BUS_FMT_SGBRG14_1X14) + mf->code = MEDIA_BUS_FMT_SGBRG12_1X12; + else if (mf->code == MEDIA_BUS_FMT_SBGGR12_1X12) + mf->code = MEDIA_BUS_FMT_SBGGR12_1X12; + else if (mf->code == MEDIA_BUS_FMT_SRGGB14_1X14) + mf->code = MEDIA_BUS_FMT_SRGGB12_1X12; + else + mf->code = MEDIA_BUS_FMT_Y12_1X12; + v4l2_warn(&isp_dev->v4l2_dev, + "no support raw14, isp format force to raw12\n"); + } in_fmt = find_in_fmt(mf->code); if (!in_fmt || mf->width < CIF_ISP_INPUT_W_MIN || From 7007e186ca9924ba2f6212cf177e1be660e4443d Mon Sep 17 00:00:00 2001 From: Finley Xiao Date: Tue, 23 Sep 2025 11:44:04 +0800 Subject: [PATCH 10/13] thermal: rockchip: Add support to save and restore tsadc offset for rv1126b Change-Id: Ie21cd1854b4421036a7eafc210ef2b2e378b2967 Signed-off-by: Finley Xiao --- drivers/thermal/rockchip_thermal.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c index 373eee1e6dc3..a53b5c21c5aa 100644 --- a/drivers/thermal/rockchip_thermal.c +++ b/drivers/thermal/rockchip_thermal.c @@ -70,6 +70,7 @@ enum adc_sort_mode { struct phy_config { unsigned int bias; + unsigned int offset; }; /** @@ -337,6 +338,7 @@ struct rockchip_thermal_data { #define RV1126B_GRF_TSADC_CON0 0x50 #define RV1126B_GRF_TSADC_CON1 0x54 +#define RV1126B_GRF_TSADC_CON4 0x60 #define RV1126B_GRF_TSADC_CON6 0x68 #define RV1126B_GRF_TSADC_ST1 0x114 #define RV1126B_UNLOCK_VALUE 0xa5 @@ -345,6 +347,8 @@ struct rockchip_thermal_data { #define RV1126B_UNLOCK_TRIGGER_MASK (BIT(8) << 16) #define RV1126B_MAX_BIAS 0x7f #define RV1126B_BIAS_MASK (0x7f << 16) +#define RV1126B_MAX_OFFSET 0xffff +#define RV1126B_OFFSET_MASK (0xffff << 16) #define RV1126B_CTRL_MASK (0x8078 << 16) #define GRF_SARADC_TESTBIT_ON (0x10001 << 2) @@ -1719,8 +1723,16 @@ static void rv1126b_tsadc_phy_init(struct device *dev, struct regmap *grf, regmap_write(grf, RV1126B_GRF_TSADC_CON6, phy_cfg->bias | RV1126B_BIAS_MASK); } + if (!phy_cfg->offset) { + regmap_read(grf, RV1126B_GRF_TSADC_CON4, &val); + phy_cfg->offset = val & RV1126B_MAX_OFFSET; + } else { + regmap_write(grf, RV1126B_GRF_TSADC_CON4, + phy_cfg->offset | RV1126B_OFFSET_MASK); + } regmap_read(grf, RV1126B_GRF_TSADC_ST1, &val); - dev_info(dev, "width=0x%x, bias=0x%x\n", val, phy_cfg->bias); + dev_info(dev, "width=0x%x, bias=0x%x, offset=0x%x\n", val, phy_cfg->bias, + phy_cfg->offset); regmap_write(grf, RV1126B_GRF_TSADC_CON0, RV1126B_CTRL_MASK); regmap_write(grf, RV1126B_GRF_TSADC_CON1, RV1126B_UNLOCK_VALUE | RV1126B_UNLOCK_VALUE_MASK); From f2f204f06bcaeaf1267d7ff9696d18cd1b849f16 Mon Sep 17 00:00:00 2001 From: Jianwei Fan Date: Sat, 16 Aug 2025 11:33:20 +0800 Subject: [PATCH 11/13] media: i2c: rk628: fix mipi dphy timing set Signed-off-by: Jianwei Fan Change-Id: I58c77f0f7418651ecf817b225d7dac3e649567db --- drivers/media/i2c/rk628/rk628_csi_v4l2.c | 125 +++++++--------------- drivers/media/i2c/rk628/rk628_dsi.c | 5 - drivers/media/i2c/rk628/rk628_mipi_dphy.c | 94 ++++++++++------ drivers/media/i2c/rk628/rk628_mipi_dphy.h | 1 - 4 files changed, 101 insertions(+), 124 deletions(-) diff --git a/drivers/media/i2c/rk628/rk628_csi_v4l2.c b/drivers/media/i2c/rk628/rk628_csi_v4l2.c index c320465737b0..8428504b4d42 100644 --- a/drivers/media/i2c/rk628/rk628_csi_v4l2.c +++ b/drivers/media/i2c/rk628/rk628_csi_v4l2.c @@ -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); diff --git a/drivers/media/i2c/rk628/rk628_dsi.c b/drivers/media/i2c/rk628/rk628_dsi.c index af2ab7e5b50a..4255c57c536a 100644 --- a/drivers/media/i2c/rk628/rk628_dsi.c +++ b/drivers/media/i2c/rk628/rk628_dsi.c @@ -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, diff --git a/drivers/media/i2c/rk628/rk628_mipi_dphy.c b/drivers/media/i2c/rk628/rk628_mipi_dphy.c index 22e4d2984610..38809ef50f13 100644 --- a/drivers/media/i2c/rk628/rk628_mipi_dphy.c +++ b/drivers/media/i2c/rk628/rk628_mipi_dphy.c @@ -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); diff --git a/drivers/media/i2c/rk628/rk628_mipi_dphy.h b/drivers/media/i2c/rk628/rk628_mipi_dphy.h index 8410f4d9d7df..72759eb1cea5 100644 --- a/drivers/media/i2c/rk628/rk628_mipi_dphy.h +++ b/drivers/media/i2c/rk628/rk628_mipi_dphy.h @@ -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); From 215d3c5bf9aa24c769ef5dbfaa937c75a4b5c59e Mon Sep 17 00:00:00 2001 From: Jianwei Fan Date: Wed, 30 Apr 2025 15:45:16 +0800 Subject: [PATCH 12/13] media: i2c: rk628: fix vsync/vfp/vbp calculate when scaler en Signed-off-by: Jianwei Fan Change-Id: I4472e8ceff09e326107c203ae6d65eaf907e90ac --- drivers/media/i2c/rk628/rk628_csi_v4l2.c | 26 ++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/drivers/media/i2c/rk628/rk628_csi_v4l2.c b/drivers/media/i2c/rk628/rk628_csi_v4l2.c index 8428504b4d42..f699966f89cb 100644 --- a/drivers/media/i2c/rk628/rk628_csi_v4l2.c +++ b/drivers/media/i2c/rk628/rk628_csi_v4l2.c @@ -449,6 +449,14 @@ static int rk628_csi_get_detected_timings(struct v4l2_subdev *sd, if (ret) return ret; + 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); + + csi->src_timings = *timings; + if (csi->scaler_en) + *timings = csi->timings; + if ((bt->pixelclock > 300000000 && csi->rk628->version >= RK628F_VERSION) || (bt->width > 2048 && csi->plat_data->tx_mode == DSI_MODE)) { v4l2_info(sd, "rk628f detect pixclk more than 300M, use dual mipi mode\n"); @@ -458,14 +466,6 @@ static int rk628_csi_get_detected_timings(struct v4l2_subdev *sd, csi->rk628->dual_mipi = false; } - 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); - - csi->src_timings = *timings; - if (csi->scaler_en) - *timings = csi->timings; - return ret; } @@ -1001,6 +1001,16 @@ static void rk628_post_process_setup(struct v4l2_subdev *sd) dst.vback_porch = dst_bt->vbackporch; dst.pixelclock = dst_bt->pixelclock; + if (csi->scaler_en) { + dst.vfront_porch = DIV_ROUND_UP(src.vfront_porch * dst_bt->height, src.vactive); + dst.vsync_len = DIV_ROUND_UP(src.vsync_len * dst_bt->height, src.vactive); + dst.vback_porch = DIV_ROUND_UP(src.vback_porch * dst_bt->height, src.vactive); + v4l2_info(sd, "%s: src timing: vfp: %d, vs: %d, vbp: %d\n", + __func__, src.vfront_porch, src.vsync_len, src.vback_porch); + v4l2_info(sd, "%s: dst timing: vfp: %d, vs: %d, vbp: %d\n", + __func__, dst.vfront_porch, dst.vsync_len, dst.vback_porch); + } + rk628_post_process_en(csi->rk628, &src, &dst, &dst_pclk); dst_bt->pixelclock = dst_pclk; } From e1f3f2c568280a7dd490ad87fce7608a93ae001e Mon Sep 17 00:00:00 2001 From: Jianwei Fan Date: Fri, 22 Aug 2025 16:47:34 +0800 Subject: [PATCH 13/13] media: i2c: rk628: post process fix output space for BT2020 Signed-off-by: Jianwei Fan Change-Id: If3795a08ce7be84ece2d0f0a4d5f091655be4baa --- drivers/media/i2c/rk628/rk628_post_process.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/rk628/rk628_post_process.c b/drivers/media/i2c/rk628/rk628_post_process.c index 66bf979fa568..05db9ee6f6fc 100644 --- a/drivers/media/i2c/rk628/rk628_post_process.c +++ b/drivers/media/i2c/rk628/rk628_post_process.c @@ -1638,7 +1638,7 @@ static u8 rk628_get_output_color_space(struct rk628 *rk628, u8 input_color_space return rk628->tx_mode ? OPTM_CS_E_RGB : OPTM_CS_E_XV_YCC_709; case OPTM_CS_E_XV_YCC_2020: case OPTM_CS_E_RGB_2020: - return rk628->tx_mode ? OPTM_CS_E_RGB_2020 : OPTM_CS_E_XV_YCC_709; + return rk628->tx_mode ? OPTM_CS_E_RGB_2020 : OPTM_CS_E_XV_YCC_2020; case OPTM_CS_E_RGB_ADOBE: case OPTM_CS_E_YUV_ADOBE: return rk628->tx_mode ? OPTM_CS_E_RGB_ADOBE : OPTM_CS_E_XV_YCC_709;