summaryrefslogtreecommitdiff
path: root/drivers/media
diff options
context:
space:
mode:
authorHans Verkuil <hverkuil-cisco@xs4all.nl>2024-02-23 15:17:10 +0100
committerHans Verkuil <hverkuil-cisco@xs4all.nl>2024-02-23 15:17:10 +0100
commitcecce089b92f52888160b0d9bc53fc191c0d08d3 (patch)
tree1b6366ff3cb41d8948c7e623255132326ccc6f79 /drivers/media
parent6fc62efa266b0918c7b226f45c2eccfcf99a6d8e (diff)
parent9f9cd26aec8406bbae42d7d2afe23a5d368b7b9a (diff)
Merge tag 'tags/media-next-rkisp1-20240223' of git://git.kernel.org/pub/scm/linux/kernel/git/pinchartl/linux.git into media_stage
This adds i.MX8MP support to the rkisp1 driver. Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl> From: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Link: https://patchwork.linuxtv.org/project/linux-media/patch/20240223123556.GA26004@pendragon.ideasonboard.com/
Diffstat (limited to 'drivers/media')
-rw-r--r--drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c216
-rw-r--r--drivers/media/platform/rockchip/rkisp1/rkisp1-common.h35
-rw-r--r--drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c71
-rw-r--r--drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c131
-rw-r--r--drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h36
-rw-r--r--drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c19
6 files changed, 443 insertions, 65 deletions
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c
index aebd3c12020b..9e0e69052096 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c
@@ -47,13 +47,18 @@ enum rkisp1_plane {
* @fourcc: pixel format
* @fmt_type: helper filed for pixel format
* @uv_swap: if cb cr swapped, for yuv
+ * @yc_swap: if y and cb/cr swapped, for yuv
+ * @byte_swap: if byte pairs are swapped, for raw
* @write_format: defines how YCbCr self picture data is written to memory
- * @output_format: defines sp output format
+ * @output_format: defines the output format (RKISP1_CIF_MI_INIT_MP_OUTPUT_* for
+ * the main path and RKISP1_MI_CTRL_SP_OUTPUT_* for the self path)
* @mbus: the mbus code on the src resizer pad that matches the pixel format
*/
struct rkisp1_capture_fmt_cfg {
u32 fourcc;
- u8 uv_swap;
+ u32 uv_swap : 1;
+ u32 yc_swap : 1;
+ u32 byte_swap : 1;
u32 write_format;
u32 output_format;
u32 mbus;
@@ -94,36 +99,50 @@ static const struct rkisp1_capture_fmt_cfg rkisp1_mp_fmts[] = {
.fourcc = V4L2_PIX_FMT_YUYV,
.uv_swap = 0,
.write_format = RKISP1_MI_CTRL_MP_WRITE_YUVINT,
+ .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV422,
+ .mbus = MEDIA_BUS_FMT_YUYV8_2X8,
+ }, {
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .uv_swap = 0,
+ .yc_swap = 1,
+ .write_format = RKISP1_MI_CTRL_MP_WRITE_YUVINT,
+ .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV422,
.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
}, {
.fourcc = V4L2_PIX_FMT_YUV422P,
.uv_swap = 0,
.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8,
+ .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV422,
.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
}, {
.fourcc = V4L2_PIX_FMT_NV16,
.uv_swap = 0,
.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA,
+ .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV422,
.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
}, {
.fourcc = V4L2_PIX_FMT_NV61,
.uv_swap = 1,
.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA,
+ .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV422,
.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
}, {
.fourcc = V4L2_PIX_FMT_NV16M,
.uv_swap = 0,
.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA,
+ .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV422,
.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
}, {
.fourcc = V4L2_PIX_FMT_NV61M,
.uv_swap = 1,
.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA,
+ .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV422,
.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
}, {
.fourcc = V4L2_PIX_FMT_YVU422M,
.uv_swap = 1,
.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8,
+ .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV422,
.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
},
/* yuv400 */
@@ -131,6 +150,7 @@ static const struct rkisp1_capture_fmt_cfg rkisp1_mp_fmts[] = {
.fourcc = V4L2_PIX_FMT_GREY,
.uv_swap = 0,
.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8,
+ .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV400,
.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
},
/* yuv420 */
@@ -138,81 +158,107 @@ static const struct rkisp1_capture_fmt_cfg rkisp1_mp_fmts[] = {
.fourcc = V4L2_PIX_FMT_NV21,
.uv_swap = 1,
.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA,
+ .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV420,
.mbus = MEDIA_BUS_FMT_YUYV8_1_5X8,
}, {
.fourcc = V4L2_PIX_FMT_NV12,
.uv_swap = 0,
.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA,
+ .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV420,
.mbus = MEDIA_BUS_FMT_YUYV8_1_5X8,
}, {
.fourcc = V4L2_PIX_FMT_NV21M,
.uv_swap = 1,
.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA,
+ .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV420,
.mbus = MEDIA_BUS_FMT_YUYV8_1_5X8,
}, {
.fourcc = V4L2_PIX_FMT_NV12M,
.uv_swap = 0,
.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA,
+ .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV420,
.mbus = MEDIA_BUS_FMT_YUYV8_1_5X8,
}, {
.fourcc = V4L2_PIX_FMT_YUV420,
.uv_swap = 0,
.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8,
+ .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV420,
.mbus = MEDIA_BUS_FMT_YUYV8_1_5X8,
}, {
.fourcc = V4L2_PIX_FMT_YVU420,
.uv_swap = 1,
.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8,
+ .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV420,
.mbus = MEDIA_BUS_FMT_YUYV8_1_5X8,
},
/* raw */
{
.fourcc = V4L2_PIX_FMT_SRGGB8,
.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8,
+ .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_RAW8,
.mbus = MEDIA_BUS_FMT_SRGGB8_1X8,
}, {
.fourcc = V4L2_PIX_FMT_SGRBG8,
.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8,
+ .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_RAW8,
.mbus = MEDIA_BUS_FMT_SGRBG8_1X8,
}, {
.fourcc = V4L2_PIX_FMT_SGBRG8,
.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8,
+ .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_RAW8,
.mbus = MEDIA_BUS_FMT_SGBRG8_1X8,
}, {
.fourcc = V4L2_PIX_FMT_SBGGR8,
.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8,
+ .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_RAW8,
.mbus = MEDIA_BUS_FMT_SBGGR8_1X8,
}, {
.fourcc = V4L2_PIX_FMT_SRGGB10,
+ .byte_swap = 1,
.write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12,
+ .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_RAW10,
.mbus = MEDIA_BUS_FMT_SRGGB10_1X10,
}, {
.fourcc = V4L2_PIX_FMT_SGRBG10,
+ .byte_swap = 1,
.write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12,
+ .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_RAW10,
.mbus = MEDIA_BUS_FMT_SGRBG10_1X10,
}, {
.fourcc = V4L2_PIX_FMT_SGBRG10,
+ .byte_swap = 1,
.write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12,
+ .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_RAW10,
.mbus = MEDIA_BUS_FMT_SGBRG10_1X10,
}, {
.fourcc = V4L2_PIX_FMT_SBGGR10,
+ .byte_swap = 1,
.write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12,
+ .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_RAW10,
.mbus = MEDIA_BUS_FMT_SBGGR10_1X10,
}, {
.fourcc = V4L2_PIX_FMT_SRGGB12,
+ .byte_swap = 1,
.write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12,
+ .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_RAW12,
.mbus = MEDIA_BUS_FMT_SRGGB12_1X12,
}, {
.fourcc = V4L2_PIX_FMT_SGRBG12,
+ .byte_swap = 1,
.write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12,
+ .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_RAW12,
.mbus = MEDIA_BUS_FMT_SGRBG12_1X12,
}, {
.fourcc = V4L2_PIX_FMT_SGBRG12,
+ .byte_swap = 1,
.write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12,
+ .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_RAW12,
.mbus = MEDIA_BUS_FMT_SGBRG12_1X12,
}, {
.fourcc = V4L2_PIX_FMT_SBGGR12,
+ .byte_swap = 1,
.write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12,
+ .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_RAW12,
.mbus = MEDIA_BUS_FMT_SBGGR12_1X12,
},
};
@@ -230,6 +276,13 @@ static const struct rkisp1_capture_fmt_cfg rkisp1_sp_fmts[] = {
.output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV422,
.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
}, {
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .uv_swap = 0,
+ .yc_swap = 1,
+ .write_format = RKISP1_MI_CTRL_SP_WRITE_INT,
+ .output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV422,
+ .mbus = MEDIA_BUS_FMT_YUYV8_2X8,
+ }, {
.fourcc = V4L2_PIX_FMT_YUV422P,
.uv_swap = 0,
.write_format = RKISP1_MI_CTRL_SP_WRITE_PLA,
@@ -442,6 +495,14 @@ static void rkisp1_mp_config(struct rkisp1_capture *cap)
rkisp1_write(rkisp1, cap->config->mi.cr_size_init,
rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CR));
+ if (rkisp1_has_feature(rkisp1, MAIN_STRIDE)) {
+ rkisp1_write(rkisp1, RKISP1_CIF_MI_MP_Y_LLENGTH, cap->stride);
+ rkisp1_write(rkisp1, RKISP1_CIF_MI_MP_Y_PIC_WIDTH, pixm->width);
+ rkisp1_write(rkisp1, RKISP1_CIF_MI_MP_Y_PIC_HEIGHT, pixm->height);
+ rkisp1_write(rkisp1, RKISP1_CIF_MI_MP_Y_PIC_SIZE,
+ cap->stride * pixm->height);
+ }
+
rkisp1_irq_frame_end_enable(cap);
/* set uv swapping for semiplanar formats */
@@ -454,6 +515,25 @@ static void rkisp1_mp_config(struct rkisp1_capture *cap)
rkisp1_write(rkisp1, RKISP1_CIF_MI_XTD_FORMAT_CTRL, reg);
}
+ /*
+ * U/V swapping with the MI_XTD_FORMAT_CTRL register only works for
+ * NV12/NV21 and NV16/NV61, so instead use byte swap to support UYVY.
+ * YVYU and VYUY cannot be supported with this method.
+ */
+ if (rkisp1_has_feature(rkisp1, MAIN_STRIDE)) {
+ reg = rkisp1_read(rkisp1, RKISP1_CIF_MI_OUTPUT_ALIGN_FORMAT);
+ if (cap->pix.cfg->yc_swap || cap->pix.cfg->byte_swap)
+ reg |= RKISP1_CIF_OUTPUT_ALIGN_FORMAT_MP_BYTE_SWAP_BYTES;
+ else
+ reg &= ~RKISP1_CIF_OUTPUT_ALIGN_FORMAT_MP_BYTE_SWAP_BYTES;
+
+ reg |= RKISP1_CIF_OUTPUT_ALIGN_FORMAT_MP_LSB_ALIGNMENT;
+ rkisp1_write(rkisp1, RKISP1_CIF_MI_OUTPUT_ALIGN_FORMAT, reg);
+
+ rkisp1_write(rkisp1, RKISP1_CIF_MI_INIT,
+ cap->pix.cfg->output_format);
+ }
+
rkisp1_mi_config_ctrl(cap);
reg = rkisp1_read(rkisp1, RKISP1_CIF_MI_CTRL);
@@ -479,11 +559,11 @@ static void rkisp1_sp_config(struct rkisp1_capture *cap)
rkisp1_write(rkisp1, cap->config->mi.cr_size_init,
rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CR));
- rkisp1_write(rkisp1, RKISP1_CIF_MI_SP_Y_LLENGTH, cap->sp_y_stride);
+ rkisp1_write(rkisp1, RKISP1_CIF_MI_SP_Y_LLENGTH, cap->stride);
rkisp1_write(rkisp1, RKISP1_CIF_MI_SP_Y_PIC_WIDTH, pixm->width);
rkisp1_write(rkisp1, RKISP1_CIF_MI_SP_Y_PIC_HEIGHT, pixm->height);
rkisp1_write(rkisp1, RKISP1_CIF_MI_SP_Y_PIC_SIZE,
- cap->sp_y_stride * pixm->height);
+ cap->stride * pixm->height);
rkisp1_irq_frame_end_enable(cap);
@@ -497,6 +577,20 @@ static void rkisp1_sp_config(struct rkisp1_capture *cap)
rkisp1_write(rkisp1, RKISP1_CIF_MI_XTD_FORMAT_CTRL, reg);
}
+ /*
+ * U/V swapping with the MI_XTD_FORMAT_CTRL register only works for
+ * NV12/NV21 and NV16/NV61, so instead use byte swap to support UYVY.
+ * YVYU and VYUY cannot be supported with this method.
+ */
+ if (rkisp1_has_feature(rkisp1, MAIN_STRIDE)) {
+ reg = rkisp1_read(rkisp1, RKISP1_CIF_MI_OUTPUT_ALIGN_FORMAT);
+ if (cap->pix.cfg->yc_swap)
+ reg |= RKISP1_CIF_OUTPUT_ALIGN_FORMAT_SP_BYTE_SWAP_BYTES;
+ else
+ reg &= ~RKISP1_CIF_OUTPUT_ALIGN_FORMAT_SP_BYTE_SWAP_BYTES;
+ rkisp1_write(rkisp1, RKISP1_CIF_MI_OUTPUT_ALIGN_FORMAT, reg);
+ }
+
rkisp1_mi_config_ctrl(cap);
mi_ctrl = rkisp1_read(rkisp1, RKISP1_CIF_MI_CTRL);
@@ -640,11 +734,13 @@ static void rkisp1_dummy_buf_destroy(struct rkisp1_capture *cap)
static void rkisp1_set_next_buf(struct rkisp1_capture *cap)
{
+ u8 shift = rkisp1_has_feature(cap->rkisp1, DMA_34BIT) ? 2 : 0;
+
cap->buf.curr = cap->buf.next;
cap->buf.next = NULL;
if (!list_empty(&cap->buf.queue)) {
- u32 *buff_addr;
+ dma_addr_t *buff_addr;
cap->buf.next = list_first_entry(&cap->buf.queue, struct rkisp1_buffer, queue);
list_del(&cap->buf.next->queue);
@@ -652,7 +748,7 @@ static void rkisp1_set_next_buf(struct rkisp1_capture *cap)
buff_addr = cap->buf.next->buff_addr;
rkisp1_write(cap->rkisp1, cap->config->mi.y_base_ad_init,
- buff_addr[RKISP1_PLANE_Y]);
+ buff_addr[RKISP1_PLANE_Y] >> shift);
/*
* In order to support grey format we capture
* YUV422 planar format from the camera and
@@ -661,17 +757,17 @@ static void rkisp1_set_next_buf(struct rkisp1_capture *cap)
if (cap->pix.cfg->fourcc == V4L2_PIX_FMT_GREY) {
rkisp1_write(cap->rkisp1,
cap->config->mi.cb_base_ad_init,
- cap->buf.dummy.dma_addr);
+ cap->buf.dummy.dma_addr >> shift);
rkisp1_write(cap->rkisp1,
cap->config->mi.cr_base_ad_init,
- cap->buf.dummy.dma_addr);
+ cap->buf.dummy.dma_addr >> shift);
} else {
rkisp1_write(cap->rkisp1,
cap->config->mi.cb_base_ad_init,
- buff_addr[RKISP1_PLANE_CB]);
+ buff_addr[RKISP1_PLANE_CB] >> shift);
rkisp1_write(cap->rkisp1,
cap->config->mi.cr_base_ad_init,
- buff_addr[RKISP1_PLANE_CR]);
+ buff_addr[RKISP1_PLANE_CR] >> shift);
}
} else {
/*
@@ -679,11 +775,11 @@ static void rkisp1_set_next_buf(struct rkisp1_capture *cap)
* throw data if there is no available buffer.
*/
rkisp1_write(cap->rkisp1, cap->config->mi.y_base_ad_init,
- cap->buf.dummy.dma_addr);
+ cap->buf.dummy.dma_addr >> shift);
rkisp1_write(cap->rkisp1, cap->config->mi.cb_base_ad_init,
- cap->buf.dummy.dma_addr);
+ cap->buf.dummy.dma_addr >> shift);
rkisp1_write(cap->rkisp1, cap->config->mi.cr_base_ad_init,
- cap->buf.dummy.dma_addr);
+ cap->buf.dummy.dma_addr >> shift);
}
/* Set plane offsets */
@@ -722,6 +818,7 @@ irqreturn_t rkisp1_capture_isr(int irq, void *ctx)
{
struct device *dev = ctx;
struct rkisp1_device *rkisp1 = dev_get_drvdata(dev);
+ unsigned int dev_count = rkisp1_path_count(rkisp1);
unsigned int i;
u32 status;
@@ -731,7 +828,7 @@ irqreturn_t rkisp1_capture_isr(int irq, void *ctx)
rkisp1_write(rkisp1, RKISP1_CIF_MI_ICR, status);
- for (i = 0; i < ARRAY_SIZE(rkisp1->capture_devs); ++i) {
+ for (i = 0; i < dev_count; ++i) {
struct rkisp1_capture *cap = &rkisp1->capture_devs[i];
if (!(status & RKISP1_CIF_MI_FRAME(cap)))
@@ -888,6 +985,7 @@ static void rkisp1_cap_stream_enable(struct rkisp1_capture *cap)
{
struct rkisp1_device *rkisp1 = cap->rkisp1;
struct rkisp1_capture *other = &rkisp1->capture_devs[cap->id ^ 1];
+ bool has_self_path = rkisp1_has_feature(rkisp1, SELF_PATH);
cap->ops->set_data_path(cap);
cap->ops->config(cap);
@@ -896,19 +994,40 @@ static void rkisp1_cap_stream_enable(struct rkisp1_capture *cap)
spin_lock_irq(&cap->buf.lock);
rkisp1_set_next_buf(cap);
cap->ops->enable(cap);
- /* It's safe to configure ACTIVE and SHADOW registers for the
- * first stream. While when the second is starting, do NOT
- * force update because it also updates the first one.
+
+ /*
+ * It's safe to configure ACTIVE and SHADOW registers for the first
+ * stream. While when the second is starting, do NOT force update
+ * because it also updates the first one.
*
- * The latter case would drop one more buffer(that is 2) since
- * there's no buffer in a shadow register when the second FE received.
- * This's also required because the second FE maybe corrupt
- * especially when run at 120fps.
+ * The latter case would drop one more buffer(that is 2) since there's
+ * no buffer in a shadow register when the second FE received. This's
+ * also required because the second FE maybe corrupt especially when
+ * run at 120fps.
*/
- if (!other->is_streaming) {
- /* force cfg update */
- rkisp1_write(rkisp1, RKISP1_CIF_MI_INIT,
- RKISP1_CIF_MI_INIT_SOFT_UPD);
+ if (!has_self_path || !other->is_streaming) {
+ u32 reg;
+
+ /*
+ * Force cfg update.
+ *
+ * The ISP8000 (implementing the MAIN_STRIDE feature) as a
+ * mp_output_format field in the CIF_MI_INIT register that must
+ * be preserved. It can be read back, but it is not clear what
+ * other register bits will return. Mask them out.
+ *
+ * On Rockchip platforms, the CIF_MI_INIT register is marked as
+ * write-only and reads as zeros. We can skip reading it.
+ */
+ if (rkisp1_has_feature(rkisp1, MAIN_STRIDE))
+ reg = rkisp1_read(rkisp1, RKISP1_CIF_MI_INIT)
+ & RKISP1_CIF_MI_INIT_MP_OUTPUT_MASK;
+ else
+ reg = 0;
+
+ reg |= RKISP1_CIF_MI_INIT_SOFT_UPD;
+ rkisp1_write(rkisp1, RKISP1_CIF_MI_INIT, reg);
+
rkisp1_set_next_buf(cap);
}
spin_unlock_irq(&cap->buf.lock);
@@ -1092,8 +1211,8 @@ static const struct vb2_ops rkisp1_vb2_ops = {
*/
static const struct v4l2_format_info *
-rkisp1_fill_pixfmt(struct v4l2_pix_format_mplane *pixm,
- enum rkisp1_stream_id id)
+rkisp1_fill_pixfmt(const struct rkisp1_capture *cap,
+ struct v4l2_pix_format_mplane *pixm)
{
struct v4l2_plane_pix_format *plane_y = &pixm->plane_fmt[0];
const struct v4l2_format_info *info;
@@ -1106,10 +1225,13 @@ rkisp1_fill_pixfmt(struct v4l2_pix_format_mplane *pixm,
/*
* The SP supports custom strides, expressed as a number of pixels for
- * the Y plane. Clamp the stride to a reasonable value to avoid integer
- * overflows when calculating the bytesperline and sizeimage values.
+ * the Y plane, and so does the MP in ISP versions that have the
+ * MAIN_STRIDE feature. Clamp the stride to a reasonable value to avoid
+ * integer overflows when calculating the bytesperline and sizeimage
+ * values.
*/
- if (id == RKISP1_SELFPATH)
+ if (cap->id == RKISP1_SELFPATH ||
+ rkisp1_has_feature(cap->rkisp1, MAIN_STRIDE))
stride = clamp(DIV_ROUND_UP(plane_y->bytesperline, info->bpp[0]),
pixm->width, 65536U);
else
@@ -1144,10 +1266,14 @@ rkisp1_fill_pixfmt(struct v4l2_pix_format_mplane *pixm,
static const struct rkisp1_capture_fmt_cfg *
rkisp1_find_fmt_cfg(const struct rkisp1_capture *cap, const u32 pixelfmt)
{
+ bool yc_swap_support = rkisp1_has_feature(cap->rkisp1, MAIN_STRIDE);
unsigned int i;
for (i = 0; i < cap->config->fmt_size; i++) {
- if (cap->config->fmts[i].fourcc == pixelfmt)
+ const struct rkisp1_capture_fmt_cfg *fmt = &cap->config->fmts[i];
+
+ if (fmt->fourcc == pixelfmt &&
+ (!fmt->yc_swap || yc_swap_support))
return &cap->config->fmts[i];
}
return NULL;
@@ -1184,7 +1310,7 @@ static void rkisp1_try_fmt(const struct rkisp1_capture *cap,
pixm->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
pixm->quantization = V4L2_QUANTIZATION_DEFAULT;
- info = rkisp1_fill_pixfmt(pixm, cap->id);
+ info = rkisp1_fill_pixfmt(cap, pixm);
if (fmt_cfg)
*fmt_cfg = fmt;
@@ -1196,12 +1322,9 @@ static void rkisp1_set_fmt(struct rkisp1_capture *cap,
struct v4l2_pix_format_mplane *pixm)
{
rkisp1_try_fmt(cap, pixm, &cap->pix.cfg, &cap->pix.info);
- cap->pix.fmt = *pixm;
- /* SP supports custom stride in number of pixels of the Y plane */
- if (cap->id == RKISP1_SELFPATH)
- cap->sp_y_stride = pixm->plane_fmt[0].bytesperline /
- cap->pix.info->bpp[0];
+ cap->pix.fmt = *pixm;
+ cap->stride = pixm->plane_fmt[0].bytesperline / cap->pix.info->bpp[0];
}
static int rkisp1_try_fmt_vid_cap_mplane(struct file *file, void *fh,
@@ -1219,23 +1342,29 @@ static int rkisp1_enum_fmt_vid_cap_mplane(struct file *file, void *priv,
{
struct rkisp1_capture *cap = video_drvdata(file);
const struct rkisp1_capture_fmt_cfg *fmt = NULL;
+ bool yc_swap_support = rkisp1_has_feature(cap->rkisp1, MAIN_STRIDE);
unsigned int i, n = 0;
- if (!f->mbus_code) {
- if (f->index >= cap->config->fmt_size)
- return -EINVAL;
+ if (f->index >= cap->config->fmt_size)
+ return -EINVAL;
+ if (!f->mbus_code && yc_swap_support) {
fmt = &cap->config->fmts[f->index];
f->pixelformat = fmt->fourcc;
return 0;
}
for (i = 0; i < cap->config->fmt_size; i++) {
- if (cap->config->fmts[i].mbus != f->mbus_code)
+ fmt = &cap->config->fmts[i];
+
+ if (f->mbus_code && fmt->mbus != f->mbus_code)
+ continue;
+
+ if (!yc_swap_support && fmt->yc_swap)
continue;
if (n++ == f->index) {
- f->pixelformat = cap->config->fmts[i].fourcc;
+ f->pixelformat = fmt->fourcc;
return 0;
}
}
@@ -1498,10 +1627,11 @@ rkisp1_capture_init(struct rkisp1_device *rkisp1, enum rkisp1_stream_id id)
int rkisp1_capture_devs_register(struct rkisp1_device *rkisp1)
{
+ unsigned int dev_count = rkisp1_path_count(rkisp1);
unsigned int i;
int ret;
- for (i = 0; i < ARRAY_SIZE(rkisp1->capture_devs); i++) {
+ for (i = 0; i < dev_count; i++) {
struct rkisp1_capture *cap = &rkisp1->capture_devs[i];
rkisp1_capture_init(rkisp1, i);
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h
index 4b6b28c05b89..0afee50b97b9 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h
@@ -24,6 +24,7 @@
#include "rkisp1-regs.h"
struct dentry;
+struct regmap;
/*
* flags on the 'direction' field in struct rkisp1_mbus_info' that indicate
@@ -110,6 +111,10 @@ enum rkisp1_isp_pad {
* enum rkisp1_feature - ISP features
*
* @RKISP1_FEATURE_MIPI_CSI2: The ISP has an internal MIPI CSI-2 receiver
+ * @RKISP1_FEATURE_MAIN_STRIDE: The ISP supports configurable stride on the main path
+ * @RKISP1_FEATURE_SELF_PATH: The ISP has a self path
+ * @RKISP1_FEATURE_DUAL_CROP: The ISP has the dual crop block at the resizer input
+ * @RKISP1_FEATURE_DMA_34BIT: The ISP uses 34-bit DMA addresses
*
* The ISP features are stored in a bitmask in &rkisp1_info.features and allow
* the driver to implement support for features present in some ISP versions
@@ -117,8 +122,15 @@ enum rkisp1_isp_pad {
*/
enum rkisp1_feature {
RKISP1_FEATURE_MIPI_CSI2 = BIT(0),
+ RKISP1_FEATURE_MAIN_STRIDE = BIT(1),
+ RKISP1_FEATURE_SELF_PATH = BIT(2),
+ RKISP1_FEATURE_DUAL_CROP = BIT(3),
+ RKISP1_FEATURE_DMA_34BIT = BIT(4),
};
+#define rkisp1_has_feature(rkisp1, feature) \
+ ((rkisp1)->info->features & RKISP1_FEATURE_##feature)
+
/*
* struct rkisp1_info - Model-specific ISP Information
*
@@ -229,7 +241,7 @@ struct rkisp1_vdev_node {
struct rkisp1_buffer {
struct vb2_v4l2_buffer vb;
struct list_head queue;
- u32 buff_addr[VIDEO_MAX_PLANES];
+ dma_addr_t buff_addr[VIDEO_MAX_PLANES];
};
/*
@@ -263,7 +275,7 @@ struct rkisp1_device;
* handler to stop the streaming by waiting on the 'done' wait queue.
* If the irq handler is not called, the stream is stopped by the callback
* after timeout.
- * @sp_y_stride: the selfpath allows to configure a y stride that is longer than the image width.
+ * @stride: the line stride for the first plane, in pixel units
* @buf.lock: lock to protect buf.queue
* @buf.queue: queued buffer list
* @buf.dummy: dummy space to store dropped data
@@ -284,7 +296,7 @@ struct rkisp1_capture {
bool is_streaming;
bool is_stopping;
wait_queue_head_t done;
- unsigned int sp_y_stride;
+ unsigned int stride;
struct {
/* protects queue, curr and next */
spinlock_t lock;
@@ -435,6 +447,8 @@ struct rkisp1_debug {
* @dev: a pointer to the struct device
* @clk_size: number of clocks
* @clks: array of clocks
+ * @gasket: the gasket - i.MX8MP only
+ * @gasket_id: the gasket ID (0 or 1) - i.MX8MP only
* @v4l2_dev: v4l2_device variable
* @media_dev: media_device variable
* @notifier: a notifier to register on the v4l2-async API to be notified on the sensor
@@ -456,6 +470,8 @@ struct rkisp1_device {
struct device *dev;
unsigned int clk_size;
struct clk_bulk_data clks[RKISP1_MAX_BUS_CLK];
+ struct regmap *gasket;
+ unsigned int gasket_id;
struct v4l2_device v4l2_dev;
struct media_device media_dev;
struct v4l2_async_notifier notifier;
@@ -525,6 +541,19 @@ int rkisp1_cap_enum_mbus_codes(struct rkisp1_capture *cap,
const struct rkisp1_mbus_info *rkisp1_mbus_info_get_by_index(unsigned int index);
/*
+ * rkisp1_path_count - Return the number of paths supported by the device
+ *
+ * Some devices only have a main path, while other device have both a main path
+ * and a self path. This function returns the number of paths that this device
+ * has, based on the feature flags. It should be used insted of checking
+ * ARRAY_SIZE of capture_devs/resizer_devs.
+ */
+static inline unsigned int rkisp1_path_count(struct rkisp1_device *rkisp1)
+{
+ return rkisp1_has_feature(rkisp1, SELF_PATH) ? 2 : 1;
+}
+
+/*
* rkisp1_sd_adjust_crop_rect - adjust a rectangle to fit into another rectangle.
*
* @crop: rectangle to adjust.
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
index f96f821a7b50..e6cd4b8604bc 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
@@ -10,6 +10,7 @@
#include <linux/clk.h>
#include <linux/interrupt.h>
+#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_graph.h>
@@ -207,7 +208,7 @@ static int rkisp1_subdev_notifier_register(struct rkisp1_device *rkisp1)
switch (reg) {
case 0:
/* MIPI CSI-2 port */
- if (!(rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2)) {
+ if (!rkisp1_has_feature(rkisp1, MIPI_CSI2)) {
dev_err(rkisp1->dev,
"internal CSI must be available for port 0\n");
ret = -EINVAL;
@@ -336,10 +337,11 @@ static const struct dev_pm_ops rkisp1_pm_ops = {
static int rkisp1_create_links(struct rkisp1_device *rkisp1)
{
+ unsigned int dev_count = rkisp1_path_count(rkisp1);
unsigned int i;
int ret;
- if (rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2) {
+ if (rkisp1_has_feature(rkisp1, MIPI_CSI2)) {
/* Link the CSI receiver to the ISP. */
ret = media_create_pad_link(&rkisp1->csi.sd.entity,
RKISP1_CSI_PAD_SRC,
@@ -351,7 +353,7 @@ static int rkisp1_create_links(struct rkisp1_device *rkisp1)
}
/* create ISP->RSZ->CAP links */
- for (i = 0; i < 2; i++) {
+ for (i = 0; i < dev_count; i++) {
struct media_entity *resizer =
&rkisp1->resizer_devs[i].sd.entity;
struct media_entity *capture =
@@ -391,7 +393,7 @@ static int rkisp1_create_links(struct rkisp1_device *rkisp1)
static void rkisp1_entities_unregister(struct rkisp1_device *rkisp1)
{
- if (rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2)
+ if (rkisp1_has_feature(rkisp1, MIPI_CSI2))
rkisp1_csi_unregister(rkisp1);
rkisp1_params_unregister(rkisp1);
rkisp1_stats_unregister(rkisp1);
@@ -424,7 +426,7 @@ static int rkisp1_entities_register(struct rkisp1_device *rkisp1)
if (ret)
goto error;
- if (rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2) {
+ if (rkisp1_has_feature(rkisp1, MIPI_CSI2)) {
ret = rkisp1_csi_register(rkisp1);
if (ret)
goto error;
@@ -483,7 +485,9 @@ static const struct rkisp1_info px30_isp_info = {
.isrs = px30_isp_isrs,
.isr_size = ARRAY_SIZE(px30_isp_isrs),
.isp_ver = RKISP1_V12,
- .features = RKISP1_FEATURE_MIPI_CSI2,
+ .features = RKISP1_FEATURE_MIPI_CSI2
+ | RKISP1_FEATURE_SELF_PATH
+ | RKISP1_FEATURE_DUAL_CROP,
};
static const char * const rk3399_isp_clks[] = {
@@ -502,7 +506,29 @@ static const struct rkisp1_info rk3399_isp_info = {
.isrs = rk3399_isp_isrs,
.isr_size = ARRAY_SIZE(rk3399_isp_isrs),
.isp_ver = RKISP1_V10,
- .features = RKISP1_FEATURE_MIPI_CSI2,
+ .features = RKISP1_FEATURE_MIPI_CSI2
+ | RKISP1_FEATURE_SELF_PATH
+ | RKISP1_FEATURE_DUAL_CROP,
+};
+
+static const char * const imx8mp_isp_clks[] = {
+ "isp",
+ "hclk",
+ "aclk",
+};
+
+static const struct rkisp1_isr_data imx8mp_isp_isrs[] = {
+ { NULL, rkisp1_isr, BIT(RKISP1_IRQ_ISP) | BIT(RKISP1_IRQ_MI) },
+};
+
+static const struct rkisp1_info imx8mp_isp_info = {
+ .clks = imx8mp_isp_clks,
+ .clk_size = ARRAY_SIZE(imx8mp_isp_clks),
+ .isrs = imx8mp_isp_isrs,
+ .isr_size = ARRAY_SIZE(imx8mp_isp_isrs),
+ .isp_ver = RKISP1_V_IMX8MP,
+ .features = RKISP1_FEATURE_MAIN_STRIDE
+ | RKISP1_FEATURE_DMA_34BIT,
};
static const struct of_device_id rkisp1_of_match[] = {
@@ -514,6 +540,10 @@ static const struct of_device_id rkisp1_of_match[] = {
.compatible = "rockchip,rk3399-cif-isp",
.data = &rk3399_isp_info,
},
+ {
+ .compatible = "fsl,imx8mp-isp",
+ .data = &imx8mp_isp_info,
+ },
{},
};
MODULE_DEVICE_TABLE(of, rkisp1_of_match);
@@ -525,6 +555,7 @@ static int rkisp1_probe(struct platform_device *pdev)
struct rkisp1_device *rkisp1;
struct v4l2_device *v4l2_dev;
unsigned int i;
+ u64 dma_mask;
int ret, irq;
u32 cif_id;
@@ -538,6 +569,13 @@ static int rkisp1_probe(struct platform_device *pdev)
dev_set_drvdata(dev, rkisp1);
rkisp1->dev = dev;
+ dma_mask = rkisp1_has_feature(rkisp1, DMA_34BIT) ? DMA_BIT_MASK(34) :
+ DMA_BIT_MASK(32);
+
+ ret = dma_set_mask_and_coherent(dev, dma_mask);
+ if (ret)
+ return ret;
+
mutex_init(&rkisp1->stream_lock);
rkisp1->base_addr = devm_platform_ioremap_resource(pdev, 0);
@@ -574,6 +612,21 @@ static int rkisp1_probe(struct platform_device *pdev)
return ret;
rkisp1->clk_size = info->clk_size;
+ if (info->isp_ver == RKISP1_V_IMX8MP) {
+ unsigned int id;
+
+ rkisp1->gasket = syscon_regmap_lookup_by_phandle_args(dev->of_node,
+ "fsl,blk-ctrl",
+ 1, &id);
+ if (IS_ERR(rkisp1->gasket)) {
+ ret = PTR_ERR(rkisp1->gasket);
+ dev_err(dev, "failed to get gasket: %d\n", ret);
+ return ret;
+ }
+
+ rkisp1->gasket_id = id;
+ }
+
pm_runtime_enable(&pdev->dev);
ret = pm_runtime_resume_and_get(&pdev->dev);
@@ -628,7 +681,7 @@ static int rkisp1_probe(struct platform_device *pdev)
err_unreg_entities:
rkisp1_entities_unregister(rkisp1);
err_cleanup_csi:
- if (rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2)
+ if (rkisp1_has_feature(rkisp1, MIPI_CSI2))
rkisp1_csi_cleanup(rkisp1);
err_unreg_media_dev:
media_device_unregister(&rkisp1->media_dev);
@@ -649,7 +702,7 @@ static void rkisp1_remove(struct platform_device *pdev)
v4l2_async_nf_cleanup(&rkisp1->notifier);
rkisp1_entities_unregister(rkisp1);
- if (rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2)
+ if (rkisp1_has_feature(rkisp1, MIPI_CSI2))
rkisp1_csi_cleanup(rkisp1);
rkisp1_debug_cleanup(rkisp1);
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
index f00873d31c42..f3552e1a88dd 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
@@ -10,6 +10,7 @@
#include <linux/iopoll.h>
#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
#include <linux/videodev2.h>
#include <linux/vmalloc.h>
@@ -53,6 +54,115 @@
* +---------------------------------------------------------+
*/
+/* -----------------------------------------------------------------------------
+ * Media block control (i.MX8MP only)
+ */
+
+#define ISP_DEWARP_CONTROL 0x0138
+
+#define ISP_DEWARP_CONTROL_MIPI_CSI2_HS_POLARITY BIT(22)
+#define ISP_DEWARP_CONTROL_MIPI_CSI2_VS_SEL_RISING (0 << 20)
+#define ISP_DEWARP_CONTROL_MIPI_CSI2_VS_SEL_NEGATIVE (1 << 20)
+#define ISP_DEWARP_CONTROL_MIPI_CSI2_VS_SEL_POSITIVE (2 << 20)
+#define ISP_DEWARP_CONTROL_MIPI_CSI2_VS_SEL_FALLING (3 << 20)
+#define ISP_DEWARP_CONTROL_MIPI_CSI2_VS_SEL_MASK GENMASK(21, 20)
+#define ISP_DEWARP_CONTROL_MIPI_ISP2_LEFT_JUST_MODE BIT(19)
+#define ISP_DEWARP_CONTROL_MIPI_ISP2_DATA_TYPE(dt) ((dt) << 13)
+#define ISP_DEWARP_CONTROL_MIPI_ISP2_DATA_TYPE_MASK GENMASK(18, 13)
+
+#define ISP_DEWARP_CONTROL_MIPI_CSI1_HS_POLARITY BIT(12)
+#define ISP_DEWARP_CONTROL_MIPI_CSI1_VS_SEL_RISING (0 << 10)
+#define ISP_DEWARP_CONTROL_MIPI_CSI1_VS_SEL_NEGATIVE (1 << 10)
+#define ISP_DEWARP_CONTROL_MIPI_CSI1_VS_SEL_POSITIVE (2 << 10)
+#define ISP_DEWARP_CONTROL_MIPI_CSI1_VS_SEL_FALLING (3 << 10)
+#define ISP_DEWARP_CONTROL_MIPI_CSI1_VS_SEL_MASK GENMASK(11, 10)
+#define ISP_DEWARP_CONTROL_MIPI_ISP1_LEFT_JUST_MODE BIT(9)
+#define ISP_DEWARP_CONTROL_MIPI_ISP1_DATA_TYPE(dt) ((dt) << 3)
+#define ISP_DEWARP_CONTROL_MIPI_ISP1_DATA_TYPE_MASK GENMASK(8, 3)
+
+#define ISP_DEWARP_CONTROL_GPR_ISP_1_DISABLE BIT(1)
+#define ISP_DEWARP_CONTROL_GPR_ISP_0_DISABLE BIT(0)
+
+static int rkisp1_gasket_enable(struct rkisp1_device *rkisp1,
+ struct media_pad *source)
+{
+ struct v4l2_subdev *source_sd;
+ struct v4l2_mbus_frame_desc fd;
+ unsigned int dt;
+ u32 mask;
+ u32 val;
+ int ret;
+
+ /*
+ * Configure and enable the gasket with the CSI-2 data type. Set the
+ * vsync polarity as active high, as that is what the ISP is configured
+ * to expect in ISP_ACQ_PROP. Enable left justification, as the i.MX8MP
+ * ISP has a 16-bit wide input and expects data to be left-aligned.
+ */
+
+ source_sd = media_entity_to_v4l2_subdev(source->entity);
+ ret = v4l2_subdev_call(source_sd, pad, get_frame_desc,
+ source->index, &fd);
+ if (ret) {
+ dev_err(rkisp1->dev,
+ "failed to get frame descriptor from '%s':%u: %d\n",
+ source_sd->name, 0, ret);
+ return ret;
+ }
+
+ if (fd.num_entries != 1) {
+ dev_err(rkisp1->dev, "invalid frame descriptor for '%s':%u\n",
+ source_sd->name, 0);
+ return -EINVAL;
+ }
+
+ dt = fd.entry[0].bus.csi2.dt;
+
+ if (rkisp1->gasket_id == 0) {
+ mask = ISP_DEWARP_CONTROL_MIPI_CSI1_HS_POLARITY
+ | ISP_DEWARP_CONTROL_MIPI_CSI1_VS_SEL_MASK
+ | ISP_DEWARP_CONTROL_MIPI_ISP1_LEFT_JUST_MODE
+ | ISP_DEWARP_CONTROL_MIPI_ISP1_DATA_TYPE_MASK
+ | ISP_DEWARP_CONTROL_GPR_ISP_0_DISABLE;
+ val = ISP_DEWARP_CONTROL_MIPI_CSI1_VS_SEL_POSITIVE
+ | ISP_DEWARP_CONTROL_MIPI_ISP1_LEFT_JUST_MODE
+ | ISP_DEWARP_CONTROL_MIPI_ISP1_DATA_TYPE(dt);
+ } else {
+ mask = ISP_DEWARP_CONTROL_MIPI_CSI2_HS_POLARITY
+ | ISP_DEWARP_CONTROL_MIPI_CSI2_VS_SEL_MASK
+ | ISP_DEWARP_CONTROL_MIPI_ISP2_LEFT_JUST_MODE
+ | ISP_DEWARP_CONTROL_MIPI_ISP2_DATA_TYPE_MASK
+ | ISP_DEWARP_CONTROL_GPR_ISP_1_DISABLE;
+ val = ISP_DEWARP_CONTROL_MIPI_CSI2_VS_SEL_POSITIVE
+ | ISP_DEWARP_CONTROL_MIPI_ISP2_LEFT_JUST_MODE
+ | ISP_DEWARP_CONTROL_MIPI_ISP2_DATA_TYPE(dt);
+ }
+
+ regmap_update_bits(rkisp1->gasket, ISP_DEWARP_CONTROL, mask, val);
+
+ return 0;
+}
+
+static void rkisp1_gasket_disable(struct rkisp1_device *rkisp1)
+{
+ u32 mask;
+ u32 val;
+
+ if (rkisp1->gasket_id == 1) {
+ mask = ISP_DEWARP_CONTROL_MIPI_ISP2_LEFT_JUST_MODE
+ | ISP_DEWARP_CONTROL_MIPI_ISP2_DATA_TYPE_MASK
+ | ISP_DEWARP_CONTROL_GPR_ISP_1_DISABLE;
+ val = ISP_DEWARP_CONTROL_GPR_ISP_1_DISABLE;
+ } else {
+ mask = ISP_DEWARP_CONTROL_MIPI_ISP1_LEFT_JUST_MODE
+ | ISP_DEWARP_CONTROL_MIPI_ISP1_DATA_TYPE_MASK
+ | ISP_DEWARP_CONTROL_GPR_ISP_0_DISABLE;
+ val = ISP_DEWARP_CONTROL_GPR_ISP_0_DISABLE;
+ }
+
+ regmap_update_bits(rkisp1->gasket, ISP_DEWARP_CONTROL, mask, val);
+}
+
/* ----------------------------------------------------------------------------
* Camera Interface registers configurations
*/
@@ -291,6 +401,9 @@ static void rkisp1_isp_stop(struct rkisp1_isp *isp)
RKISP1_CIF_VI_IRCL_MIPI_SW_RST |
RKISP1_CIF_VI_IRCL_ISP_SW_RST);
rkisp1_write(rkisp1, RKISP1_CIF_VI_IRCL, 0x0);
+
+ if (rkisp1->info->isp_ver == RKISP1_V_IMX8MP)
+ rkisp1_gasket_disable(rkisp1);
}
static void rkisp1_config_clk(struct rkisp1_isp *isp)
@@ -315,16 +428,24 @@ static void rkisp1_config_clk(struct rkisp1_isp *isp)
}
}
-static void rkisp1_isp_start(struct rkisp1_isp *isp,
- struct v4l2_subdev_state *sd_state)
+static int rkisp1_isp_start(struct rkisp1_isp *isp,
+ struct v4l2_subdev_state *sd_state,
+ struct media_pad *source)
{
struct rkisp1_device *rkisp1 = isp->rkisp1;
const struct v4l2_mbus_framefmt *src_fmt;
const struct rkisp1_mbus_info *src_info;
u32 val;
+ int ret;
rkisp1_config_clk(isp);
+ if (rkisp1->info->isp_ver == RKISP1_V_IMX8MP) {
+ ret = rkisp1_gasket_enable(rkisp1, source);
+ if (ret)
+ return ret;
+ }
+
/* Activate ISP */
val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_CTRL);
val |= RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD |
@@ -338,6 +459,8 @@ static void rkisp1_isp_start(struct rkisp1_isp *isp,
if (src_info->pixel_enc != V4L2_PIXEL_ENC_BAYER)
rkisp1_params_post_configure(&rkisp1->params);
+
+ return 0;
}
/* ----------------------------------------------------------------------------
@@ -848,7 +971,9 @@ static int rkisp1_isp_s_stream(struct v4l2_subdev *sd, int enable)
if (ret)
goto out_unlock;
- rkisp1_isp_start(isp, sd_state);
+ ret = rkisp1_isp_start(isp, sd_state, source_pad);
+ if (ret)
+ goto out_unlock;
ret = v4l2_subdev_call(rkisp1->source, video, s_stream, true);
if (ret) {
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h
index bea69a0d766a..fccf4c17ee8d 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h
@@ -144,6 +144,15 @@
/* MI_INIT */
#define RKISP1_CIF_MI_INIT_SKIP BIT(2)
#define RKISP1_CIF_MI_INIT_SOFT_UPD BIT(4)
+#define RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV400 (0 << 5)
+#define RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV420 (1 << 5)
+#define RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV422 (2 << 5)
+#define RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV444 (3 << 5)
+#define RKISP1_CIF_MI_INIT_MP_OUTPUT_RAW12 (4 << 5)
+#define RKISP1_CIF_MI_INIT_MP_OUTPUT_RAW8 (5 << 5)
+#define RKISP1_CIF_MI_INIT_MP_OUTPUT_JPEG (6 << 5)
+#define RKISP1_CIF_MI_INIT_MP_OUTPUT_RAW10 (7 << 5)
+#define RKISP1_CIF_MI_INIT_MP_OUTPUT_MASK (15 << 5)
/* MI_CTRL_SHD */
#define RKISP1_CIF_MI_CTRL_SHD_MP_IN_ENABLED BIT(0)
@@ -207,6 +216,24 @@
#define RKISP1_CIF_MI_XTD_FMT_CTRL_SP_CB_CR_SWAP BIT(1)
#define RKISP1_CIF_MI_XTD_FMT_CTRL_DMA_CB_CR_SWAP BIT(2)
+/* MI_OUTPUT_ALIGN_FORMAT */
+#define RKISP1_CIF_OUTPUT_ALIGN_FORMAT_MP_LSB_ALIGNMENT BIT(0)
+#define RKISP1_CIF_OUTPUT_ALIGN_FORMAT_MP_BYTE_SWAP_BYTES BIT(1)
+#define RKISP1_CIF_OUTPUT_ALIGN_FORMAT_MP_BYTE_SWAP_WORDS BIT(2)
+#define RKISP1_CIF_OUTPUT_ALIGN_FORMAT_MP_BYTE_SWAP_DWORDS BIT(3)
+#define RKISP1_CIF_OUTPUT_ALIGN_FORMAT_SP_BYTE_SWAP_BYTES BIT(4)
+#define RKISP1_CIF_OUTPUT_ALIGN_FORMAT_SP_BYTE_SWAP_WORDS BIT(5)
+#define RKISP1_CIF_OUTPUT_ALIGN_FORMAT_SP_BYTE_SWAP_DWORDS BIT(6)
+#define RKISP1_CIF_OUTPUT_ALIGN_FORMAT_DMA_BYTE_SWAP_BYTES BIT(7)
+#define RKISP1_CIF_OUTPUT_ALIGN_FORMAT_DMA_BYTE_SWAP_WORDS BIT(8)
+#define RKISP1_CIF_OUTPUT_ALIGN_FORMAT_DMA_BYTE_SWAP_DWORDS BIT(9)
+
+/* MI_MP_OUTPUT_FIFO_SIZE */
+#define RKISP1_CIF_MI_MP_OUTPUT_FIFO_SIZE_OUTPUT_FIFO_DEPTH_FULL (0 << 0)
+#define RKISP1_CIF_MI_MP_OUTPUT_FIFO_SIZE_OUTPUT_FIFO_DEPTH_HALF (1 << 0)
+#define RKISP1_CIF_MI_MP_OUTPUT_FIFO_SIZE_OUTPUT_FIFO_DEPTH_QUARTER (2 << 0)
+#define RKISP1_CIF_MI_MP_OUTPUT_FIFO_SIZE_OUTPUT_FIFO_DEPTH_EIGHT (3 << 0)
+
/* VI_CCL */
#define RKISP1_CIF_CCL_CIF_CLK_DIS BIT(2)
/* VI_ISP_CLK_CTRL */
@@ -1000,6 +1027,15 @@
#define RKISP1_CIF_MI_SP_CB_BASE_AD_INIT2 (RKISP1_CIF_MI_BASE + 0x00000140)
#define RKISP1_CIF_MI_SP_CR_BASE_AD_INIT2 (RKISP1_CIF_MI_BASE + 0x00000144)
#define RKISP1_CIF_MI_XTD_FORMAT_CTRL (RKISP1_CIF_MI_BASE + 0x00000148)
+#define RKISP1_CIF_MI_MP_HANDSHAKE_0 (RKISP1_CIF_MI_BASE + 0x0000014C)
+#define RKISP1_CIF_MI_MP_Y_LLENGTH (RKISP1_CIF_MI_BASE + 0x00000150)
+#define RKISP1_CIF_MI_MP_Y_SLICE_OFFSET (RKISP1_CIF_MI_BASE + 0x00000154)
+#define RKISP1_CIF_MI_MP_C_SLICE_OFFSET (RKISP1_CIF_MI_BASE + 0x00000158)
+#define RKISP1_CIF_MI_OUTPUT_ALIGN_FORMAT (RKISP1_CIF_MI_BASE + 0x0000015C)
+#define RKISP1_CIF_MI_MP_OUTPUT_FIFO_SIZE (RKISP1_CIF_MI_BASE + 0x00000160)
+#define RKISP1_CIF_MI_MP_Y_PIC_WIDTH (RKISP1_CIF_MI_BASE + 0x00000164)
+#define RKISP1_CIF_MI_MP_Y_PIC_HEIGHT (RKISP1_CIF_MI_BASE + 0x00000168)
+#define RKISP1_CIF_MI_MP_Y_PIC_SIZE (RKISP1_CIF_MI_BASE + 0x0000016C)
#define RKISP1_CIF_SMIA_BASE 0x00001a00
#define RKISP1_CIF_SMIA_CTRL (RKISP1_CIF_SMIA_BASE + 0x00000000)
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c
index a8e377701302..6f3931ca5b51 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c
@@ -444,11 +444,12 @@ static void rkisp1_rsz_set_sink_crop(struct rkisp1_resizer *rsz,
sink_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_RSZ_PAD_SINK);
sink_crop = v4l2_subdev_state_get_crop(sd_state, RKISP1_RSZ_PAD_SINK);
- /* Not crop for MP bayer raw data */
+ /* Not crop for MP bayer raw data, or for devices lacking dual crop. */
mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code);
- if (rsz->id == RKISP1_MAINPATH &&
- mbus_info->pixel_enc == V4L2_PIXEL_ENC_BAYER) {
+ if ((rsz->id == RKISP1_MAINPATH &&
+ mbus_info->pixel_enc == V4L2_PIXEL_ENC_BAYER) ||
+ !rkisp1_has_feature(rsz->rkisp1, DUAL_CROP)) {
sink_crop->left = 0;
sink_crop->top = 0;
sink_crop->width = sink_fmt->width;
@@ -631,21 +632,24 @@ static int rkisp1_rsz_s_stream(struct v4l2_subdev *sd, int enable)
struct rkisp1_device *rkisp1 = rsz->rkisp1;
struct rkisp1_capture *other = &rkisp1->capture_devs[rsz->id ^ 1];
enum rkisp1_shadow_regs_when when = RKISP1_SHADOW_REGS_SYNC;
+ bool has_self_path = rkisp1_has_feature(rkisp1, SELF_PATH);
struct v4l2_subdev_state *sd_state;
if (!enable) {
- rkisp1_dcrop_disable(rsz, RKISP1_SHADOW_REGS_ASYNC);
+ if (rkisp1_has_feature(rkisp1, DUAL_CROP))
+ rkisp1_dcrop_disable(rsz, RKISP1_SHADOW_REGS_ASYNC);
rkisp1_rsz_disable(rsz, RKISP1_SHADOW_REGS_ASYNC);
return 0;
}
- if (other->is_streaming)
+ if (has_self_path && other->is_streaming)
when = RKISP1_SHADOW_REGS_ASYNC;
sd_state = v4l2_subdev_lock_and_get_active_state(sd);
rkisp1_rsz_config(rsz, sd_state, when);
- rkisp1_dcrop_config(rsz, sd_state);
+ if (rkisp1_has_feature(rkisp1, DUAL_CROP))
+ rkisp1_dcrop_config(rsz, sd_state);
v4l2_subdev_unlock_state(sd_state);
@@ -731,10 +735,11 @@ err_entity_cleanup:
int rkisp1_resizer_devs_register(struct rkisp1_device *rkisp1)
{
+ unsigned int dev_count = rkisp1_path_count(rkisp1);
unsigned int i;
int ret;
- for (i = 0; i < ARRAY_SIZE(rkisp1->resizer_devs); i++) {
+ for (i = 0; i < dev_count; i++) {
struct rkisp1_resizer *rsz = &rkisp1->resizer_devs[i];
rsz->rkisp1 = rkisp1;