diff --git a/arch/arm/configs/rv1126b-rk628.config b/arch/arm/configs/rv1126b-rk628.config new file mode 100644 index 000000000000..c7da1a8470be --- /dev/null +++ b/arch/arm/configs/rv1126b-rk628.config @@ -0,0 +1,5 @@ +CONFIG_VIDEO_RK628_CSI=y +CONFIG_VIDEO_ROCKCHIP_HDMIRX_CLASS=y +CONFIG_CEC_CORE=y +CONFIG_HDMI=y +CONFIG_VIDEO_RK628=y diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile index c0bcb890132e..b8205753db22 100644 --- a/arch/arm64/boot/dts/rockchip/Makefile +++ b/arch/arm64/boot/dts/rockchip/Makefile @@ -386,6 +386,8 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-evb1-v10-fastboot-spi-nand.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-evb1-v10-fastboot-spi-nor.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-evb1-v10-spi-nor.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-evb1-v11.dtb +dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-evb1-v11-dual-cam-csi0.dtb +dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-evb1-v11-dual-cam-csi1.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-evb1-v11-dual-4k.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-evb1-v11-fastboot-emmc.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-evb1-v11-fastboot-emmc-projector.dtb diff --git a/arch/arm64/boot/dts/rockchip/rv1126b-evb1-v11-dual-cam-csi0.dts b/arch/arm64/boot/dts/rockchip/rv1126b-evb1-v11-dual-cam-csi0.dts new file mode 100644 index 000000000000..5428339c81a3 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rv1126b-evb1-v11-dual-cam-csi0.dts @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2025 Rockchip Electronics Co., Ltd. + */ + +/dts-v1/; +#include "rv1126b.dtsi" +#include "rv1126b-evb.dtsi" +#include "rv1126b-evb-dual-cam-csi0.dtsi" +#include "rv1126b-evb1-v11.dtsi" + +/ { + model = "Rockchip RV1126B EVB1 V11 DUAL CAM Board"; + compatible = "rockchip,rv1126b-evb1-v11-dual-cam-csi0", "rockchip,rv1126b"; +}; diff --git a/arch/arm64/boot/dts/rockchip/rv1126b-evb1-v11-dual-cam-csi1.dts b/arch/arm64/boot/dts/rockchip/rv1126b-evb1-v11-dual-cam-csi1.dts new file mode 100644 index 000000000000..089968b6d016 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rv1126b-evb1-v11-dual-cam-csi1.dts @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2025 Rockchip Electronics Co., Ltd. + */ + +/dts-v1/; +#include "rv1126b.dtsi" +#include "rv1126b-evb.dtsi" +#include "rv1126b-evb-dual-cam-csi1.dtsi" +#include "rv1126b-evb1-v11.dtsi" + +/ { + model = "Rockchip RV1126B EVB1 V11 DUAL CAM Board"; + compatible = "rockchip,rv1126b-evb1-v11-dual-cam-csi1", "rockchip,rv1126b"; +}; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index caa054ae2569..3ef5c987c779 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -3945,7 +3945,9 @@ static void vop2_wb_irqs_enable(struct vop2 *vop2) const struct vop_intr *intr = &vop2_data->axi_intr[0]; uint32_t irqs = WB_UV_FIFO_FULL_INTR | WB_YRGB_FIFO_FULL_INTR; - VOP_INTR_SET_TYPE(vop2, intr, clear, irqs, 1); + if (is_vop3(vop2)) + irqs |= WB_COMPLETE_INTR; + VOP_INTR_SET_TYPE(vop2, intr, enable, irqs, 1); } @@ -3953,7 +3955,7 @@ static uint32_t vop2_read_and_clear_wb_irqs(struct vop2 *vop2) { const struct vop2_data *vop2_data = vop2->data; const struct vop_intr *intr = &vop2_data->axi_intr[0]; - uint32_t irqs = WB_UV_FIFO_FULL_INTR | WB_YRGB_FIFO_FULL_INTR; + uint32_t irqs = WB_UV_FIFO_FULL_INTR | WB_YRGB_FIFO_FULL_INTR | WB_COMPLETE_INTR; uint32_t val; val = VOP_INTR_GET_TYPE(vop2, intr, status, irqs); @@ -3993,14 +3995,20 @@ static void vop2_wb_commit(struct drm_crtc *crtc) fb->pitches[0], &wb_state->yrgb_addr); drm_writeback_queue_job(wb_conn, conn_state); - conn_state->writeback_job = NULL; + if (!vp->enabled_win_mask) { + drm_warn(vop2->drm_dev, "Writeback can not work when all plane are disabled!"); + drm_writeback_signal_completion(&vop2->wb.conn, 0); + return; + } - spin_lock_irqsave(&wb->job_lock, flags); - wb->jobs[wb->job_index].pending = true; - wb->job_index++; - if (wb->job_index >= VOP2_WB_JOB_MAX) - wb->job_index = 0; - spin_unlock_irqrestore(&wb->job_lock, flags); + if (vop2->version < VOP_VERSION_RK3576) { + spin_lock_irqsave(&wb->job_lock, flags); + wb->jobs[wb->job_index].pending = true; + wb->job_index++; + if (wb->job_index >= VOP2_WB_JOB_MAX) + wb->job_index = 0; + spin_unlock_irqrestore(&wb->job_lock, flags); + } fifo_throd = fb->pitches[0] >> 4; if (fifo_throd >= vop2->data->wb->fifo_depth) @@ -14371,6 +14379,28 @@ out: return ret; } +static void vop3_writeback_complete(struct vop2 *vop2) +{ + struct vop2_wb *wb = &vop2->wb; + struct vop2_video_port *vp; + uint8_t wb_vp_id; + bool wb_oneframe_mode; + bool wb_en; + + wb_en = VOP_MODULE_GET(vop2, wb, enable); + wb_oneframe_mode = VOP_MODULE_GET(vop2, wb, one_frame_mode); + /* + * The write back should work in one shot mode, + * stop when write back complete in next vsync. + */ + if (wb_en && !wb_oneframe_mode) { + wb_vp_id = VOP_MODULE_GET(vop2, wb, vp_id); + vp = &vop2->vps[wb_vp_id]; + vop2_wb_disable(vp); + } + drm_writeback_signal_completion(&vop2->wb.conn, 0); +} + static irqreturn_t vop3_sys_isr(int irq, void *data) { struct vop2 *vop2 = data; @@ -14423,7 +14453,13 @@ static irqreturn_t vop3_sys_isr(int irq, void *data) active_irqs = wb_irqs; SYS_ERROR_HANDLER(WB_UV_FIFO_FULL); SYS_ERROR_HANDLER(WB_YRGB_FIFO_FULL); - SYS_ERROR_HANDLER(WB_COMPLETE); + if (active_irqs & WB_COMPLETE_INTR) { + active_irqs &= ~WB_COMPLETE_INTR; + vop3_writeback_complete(vop2); + } + /* Unhandled irqs are spurious. */ + if (active_irqs) + DRM_ERROR("Unknown writeback IRQs: %02x\n", active_irqs); } for (i = 0; i < axi_max; i++) { @@ -14496,7 +14532,6 @@ static irqreturn_t vop3_vp_isr(int irq, void *data) if (active_irqs & FS_FIELD_INTR) { rockchip_drm_dbg(vop2->dev, VOP_DEBUG_VSYNC, "vsync_vp%d", vp->id); - vop2_wb_handler(vp); drm_crtc_handle_vblank(crtc); vop2_handle_vblank(vop2, crtc); active_irqs &= ~FS_FIELD_INTR; diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c index b684cefbb2ae..eab21f2750b4 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c @@ -611,7 +611,6 @@ static const int rk3568_vop_axi_intrs[] = { 0, WB_UV_FIFO_FULL_INTR, WB_YRGB_FIFO_FULL_INTR, - WB_COMPLETE_INTR, }; diff --git a/drivers/media/i2c/rk628/rk628.c b/drivers/media/i2c/rk628/rk628.c index fe43f2ca3c11..ab354f8d015e 100644 --- a/drivers/media/i2c/rk628/rk628.c +++ b/drivers/media/i2c/rk628/rk628.c @@ -512,9 +512,10 @@ void rk628_debugfs_create(struct rk628 *rk628) struct dentry *debugfs, *debugfs_tmp = debugfs_lookup("rk628", NULL); debugfs = debugfs_tmp; - if (!debugfs) + if (IS_ERR_OR_NULL(debugfs)) debugfs = debugfs_create_dir("rk628", NULL); - dput(debugfs_tmp); + if (!IS_ERR_OR_NULL(debugfs_tmp)) + dput(debugfs_tmp); rk628->debug_dir = debugfs_create_dir(dev_name(rk628->dev), debugfs); if (IS_ERR(rk628->debug_dir)) return; diff --git a/drivers/media/platform/rockchip/isp/isp_stats_v35.c b/drivers/media/platform/rockchip/isp/isp_stats_v35.c index 86e0888cc000..900d16b7ca63 100644 --- a/drivers/media/platform/rockchip/isp/isp_stats_v35.c +++ b/drivers/media/platform/rockchip/isp/isp_stats_v35.c @@ -407,7 +407,7 @@ rkisp_stats_info2ddr(struct rkisp_isp_stats_vdev *stats_vdev, } static void -rkisp_stats_send_meas_fe(struct rkisp_isp_stats_vdev *stats_vdev) +rkisp_stats_send_meas_fe(struct rkisp_isp_stats_vdev *stats_vdev, u32 w3a_ris) { struct rkisp_isp_params_vdev *params_vdev = &stats_vdev->dev->params_vdev; struct rkisp_isp_params_val_v35 *priv = params_vdev->priv_val; @@ -537,14 +537,14 @@ rkisp_stats_send_meas_fe(struct rkisp_isp_stats_vdev *stats_vdev) vb2_buffer_done(&cur_buf->vb.vb2_buf, VB2_BUF_STATE_DONE); } v4l2_dbg(4, rkisp_debug, &stats_vdev->dev->v4l2_dev, - "%s seq:%d params_id:%d ris:0x%x buf:0x%x meas_type:0x%x\n", - __func__, cur_frame_id, params_vdev->cur_fe_frame_id, ris, + "%s seq:%d params_id:%d ris:0x%x w3a:0x%x buf:0x%x meas_type:0x%x\n", + __func__, cur_frame_id, params_vdev->cur_fe_frame_id, ris, w3a_ris, !cur_buf ? -1 : cur_buf->buff_addr[0], !stat_buf ? 0 : stat_buf->meas_type); } static void -rkisp_stats_send_meas(struct rkisp_isp_stats_vdev *stats_vdev) +rkisp_stats_send_meas(struct rkisp_isp_stats_vdev *stats_vdev, u32 w3a_ris) { struct rkisp_isp_params_vdev *params_vdev = &stats_vdev->dev->params_vdev; struct rkisp_isp_params_val_v35 *priv = params_vdev->priv_val; @@ -745,8 +745,8 @@ rkisp_stats_send_meas(struct rkisp_isp_stats_vdev *stats_vdev) vb2_buffer_done(&cur_buf->vb.vb2_buf, VB2_BUF_STATE_DONE); } v4l2_dbg(4, rkisp_debug, &stats_vdev->dev->v4l2_dev, - "%s seq:%d params_id:%d ris:0x%x buf:0x%x meas_type:0x%x\n", - __func__, cur_frame_id, params_vdev->cur_frame_id, ris, + "%s seq:%d params_id:%d ris:0x%x w3a:0x%x buf:0x%x meas_type:0x%x\n", + __func__, cur_frame_id, params_vdev->cur_frame_id, ris, w3a_ris, !cur_buf ? -1 : cur_buf->buff_addr[0], !cur_stat_buf ? 0 : cur_stat_buf->meas_type); } @@ -760,15 +760,16 @@ rkisp_stats_isr_v35(struct rkisp_isp_stats_vdev *stats_vdev, rkisp_pdaf_isr(stats_vdev->dev); w3a_ris = rkisp_read(stats_vdev->dev, ISP39_W3A_INT_STAT, true); - if (w3a_ris & ISP39_W3A_INT_ERR_MASK) { - v4l2_err(&stats_vdev->dev->v4l2_dev, "w3a error 0x%x\n", w3a_ris); + if (w3a_ris) { rkisp_write(stats_vdev->dev, ISP39_W3A_INT_STAT, w3a_ris, true); + if (w3a_ris & ISP39_W3A_INT_ERR_MASK) + v4l2_err(&stats_vdev->dev->v4l2_dev, "w3a error 0x%x\n", w3a_ris); } if (isp_ris & ISP3X_BAY3D_FRM_END) - rkisp_stats_send_meas_fe(stats_vdev); + rkisp_stats_send_meas_fe(stats_vdev, w3a_ris); if (isp_ris & ISP3X_FRAME) - rkisp_stats_send_meas(stats_vdev); + rkisp_stats_send_meas(stats_vdev, w3a_ris); } static void diff --git a/drivers/media/platform/rockchip/isp/rkisp.c b/drivers/media/platform/rockchip/isp/rkisp.c index d2cdd96358b6..25f32da33b6f 100644 --- a/drivers/media/platform/rockchip/isp/rkisp.c +++ b/drivers/media/platform/rockchip/isp/rkisp.c @@ -2569,6 +2569,9 @@ static int rkisp_isp_start(struct rkisp_device *dev) rkisp_unite_write(dev, CIF_ISP_CTRL, val, is_direct); rkisp_clear_reg_cache_bits(dev, CIF_ISP_CTRL, upd); + val = CIF_MI_CTRL_INIT_BASE_EN | CIF_MI_CTRL_INIT_OFFSET_EN; + rkisp_unite_set_bits(dev, CIF_MI_CTRL, 0, val, false); + dev->isp_err_cnt = 0; dev->isp_isr_cnt = 0; dev->irq_ends_mask |= ISP_FRAME_END; diff --git a/include/uapi/linux/rk-camera-module.h b/include/uapi/linux/rk-camera-module.h index 79e5e0526eb9..74dd3529e118 100644 --- a/include/uapi/linux/rk-camera-module.h +++ b/include/uapi/linux/rk-camera-module.h @@ -250,6 +250,12 @@ #define RKMODULE_GET_HDR_COMPR_SINGLE_FRAME_INFO \ _IOR('V', BASE_VIDIOC_PRIVATE + 62, struct rkmodule_hdr_compr_single_frame_info) +#define RKMODULE_SET_CHANNEL_POWER \ + _IOW('V', BASE_VIDIOC_PRIVATE + 63, struct rkmodule_channel_power) + +#define RKMODULE_SET_CHANNEL_STREAM \ + _IOW('x', 0, struct rkmodule_channel_stream) + #define RKMODULE_REG_LIST_MAX (16) struct rkmodule_reg_struct { __u32 reg_addr; @@ -1086,4 +1092,14 @@ struct rkmodule_hdr_compr_single_frame_info { __u32 reserved[8]; }; +struct rkmodule_channel_power { + __u32 channel; + __u32 enable; +}; + +struct rkmodule_channel_stream { + __u32 channel; + __u32 enable; +}; + #endif /* _UAPI_RKMODULE_CAMERA_H */