rkisp1: Add i.MX8MP support

-----BEGIN PGP SIGNATURE-----
 
 iJgEABYKAEAWIQTAnvhxs4J7QT+XHKnMPy2AAyfeZAUCZdiOeyIcbGF1cmVudC5w
 aW5jaGFydEBpZGVhc29uYm9hcmQuY29tAAoJEMw/LYADJ95kLSEBAPKGOtKxuEwK
 CVpWvxStpfm0Xs3aAdSG6UO99b81rrwtAQCVOv71Dh/c7JRnbEHeOK5OaOgDJLEf
 MAMQLBJno+EkAA==
 =gshp
 -----END PGP SIGNATURE-----

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/
This commit is contained in:
Hans Verkuil 2024-02-23 15:17:10 +01:00
commit cecce089b9
8 changed files with 501 additions and 94 deletions

View File

@ -16,6 +16,7 @@ description: |
properties:
compatible:
enum:
- fsl,imx8mp-isp
- rockchip,px30-cif-isp
- rockchip,rk3399-cif-isp
@ -36,9 +37,9 @@ properties:
minItems: 3
items:
# isp0 and isp1
- description: ISP clock
- description: ISP AXI clock
- description: ISP AHB clock
- description: ISP clock (for imx8mp, clk)
- description: ISP AXI clock (for imx8mp, m_hclk)
- description: ISP AHB clock (for imx8mp, hclk)
# only for isp1
- description: ISP Pixel clock
@ -52,6 +53,13 @@ properties:
# only for isp1
- const: pclk
fsl,blk-ctrl:
$ref: /schemas/types.yaml#/definitions/phandle-array
maxItems: 1
description:
A phandle to the media block control for the ISP, followed by a cell
containing the index of the gasket.
iommus:
maxItems: 1
@ -113,9 +121,6 @@ required:
- interrupts
- clocks
- clock-names
- iommus
- phys
- phy-names
- power-domains
- ports
@ -143,6 +148,26 @@ allOf:
required:
- interrupt-names
- if:
properties:
compatible:
contains:
const: fsl,imx8mp-isp
then:
properties:
iommus: false
phys: false
phy-names: false
required:
- fsl,blk-ctrl
else:
properties:
fsl,blk-ctrl: false
required:
- iommus
- phys
- phy-names
additionalProperties: false
examples:

View File

@ -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,
},
};
@ -229,6 +275,13 @@ static const struct rkisp1_capture_fmt_cfg rkisp1_sp_fmts[] = {
.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_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,
@ -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);

View File

@ -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;
@ -524,6 +540,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.
*

View File

@ -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);

View File

@ -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) {

View File

@ -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)

View File

@ -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;

View File

@ -175,16 +175,21 @@
/**
* enum rkisp1_cif_isp_version - ISP variants
*
* @RKISP1_V10: used at least in rk3288 and rk3399
* @RKISP1_V11: declared in the original vendor code, but not used
* @RKISP1_V12: used at least in rk3326 and px30
* @RKISP1_V13: used at least in rk1808
* @RKISP1_V10: Used at least in RK3288 and RK3399.
* @RKISP1_V11: Declared in the original vendor code, but not used. Same number
* of entries in grids and histogram as v10.
* @RKISP1_V12: Used at least in RK3326 and PX30.
* @RKISP1_V13: Used at least in RK1808. Same number of entries in grids and
* histogram as v12.
* @RKISP1_V_IMX8MP: Used in at least i.MX8MP. Same number of entries in grids
* and histogram as v10.
*/
enum rkisp1_cif_isp_version {
RKISP1_V10 = 10,
RKISP1_V11,
RKISP1_V12,
RKISP1_V13,
RKISP1_V_IMX8MP,
};
enum rkisp1_cif_isp_histogram_mode {
@ -584,10 +589,9 @@ enum rkisp1_cif_isp_goc_mode {
* as is reported by the hw_revision field of the struct media_device_info
* that is returned by ioctl MEDIA_IOC_DEVICE_INFO.
*
* Versions <= V11 have RKISP1_CIF_ISP_GAMMA_OUT_MAX_SAMPLES_V10
* entries, versions >= V12 have RKISP1_CIF_ISP_GAMMA_OUT_MAX_SAMPLES_V12
* entries. RKISP1_CIF_ISP_GAMMA_OUT_MAX_SAMPLES is equal to the maximum
* of the two.
* V10 has RKISP1_CIF_ISP_GAMMA_OUT_MAX_SAMPLES_V10 entries, V12 has
* RKISP1_CIF_ISP_GAMMA_OUT_MAX_SAMPLES_V12 entries.
* RKISP1_CIF_ISP_GAMMA_OUT_MAX_SAMPLES is equal to the maximum of the two.
*/
struct rkisp1_cif_isp_goc_config {
__u32 mode;
@ -607,10 +611,10 @@ struct rkisp1_cif_isp_goc_config {
* as is reported by the hw_revision field of the struct media_device_info
* that is returned by ioctl MEDIA_IOC_DEVICE_INFO.
*
* Versions <= V11 have RKISP1_CIF_ISP_HISTOGRAM_WEIGHT_GRIDS_SIZE_V10
* entries, versions >= V12 have RKISP1_CIF_ISP_HISTOGRAM_WEIGHT_GRIDS_SIZE_V12
* entries. RKISP1_CIF_ISP_HISTOGRAM_WEIGHT_GRIDS_SIZE is equal to the maximum
* of the two.
* V10 has RKISP1_CIF_ISP_HISTOGRAM_WEIGHT_GRIDS_SIZE_V10 entries, V12 has
* RKISP1_CIF_ISP_HISTOGRAM_WEIGHT_GRIDS_SIZE_V12 entries.
* RKISP1_CIF_ISP_HISTOGRAM_WEIGHT_GRIDS_SIZE is equal to the maximum of the
* two.
*/
struct rkisp1_cif_isp_hst_config {
__u32 mode;
@ -902,9 +906,9 @@ struct rkisp1_cif_isp_bls_meas_val {
* as is reported by the hw_revision field of the struct media_device_info
* that is returned by ioctl MEDIA_IOC_DEVICE_INFO.
*
* Versions <= V11 have RKISP1_CIF_ISP_AE_MEAN_MAX_V10 entries,
* versions >= V12 have RKISP1_CIF_ISP_AE_MEAN_MAX_V12 entries.
* RKISP1_CIF_ISP_AE_MEAN_MAX is equal to the maximum of the two.
* V10 has RKISP1_CIF_ISP_AE_MEAN_MAX_V10 entries, V12 has
* RKISP1_CIF_ISP_AE_MEAN_MAX_V12 entries. RKISP1_CIF_ISP_AE_MEAN_MAX is equal
* to the maximum of the two.
*
* Image is divided into 5x5 blocks on V10 and 9x9 blocks on V12.
*/
@ -944,21 +948,21 @@ struct rkisp1_cif_isp_af_stat {
* integer part.
*
* The window of the measurements area is divided to 5x5 sub-windows for
* V10/V11 and to 9x9 sub-windows for V12. The histogram is then computed for
* each sub-window independently and the final result is a weighted average of
* the histogram measurements on all sub-windows. The window of the
* measurements area and the weight of each sub-window are configurable using
* V10 and to 9x9 sub-windows for V12. The histogram is then computed for each
* sub-window independently and the final result is a weighted average of the
* histogram measurements on all sub-windows. The window of the measurements
* area and the weight of each sub-window are configurable using
* struct @rkisp1_cif_isp_hst_config.
*
* The histogram contains 16 bins in V10/V11 and 32 bins in V12/V13.
* The histogram contains 16 bins in V10 and 32 bins in V12.
*
* The number of entries of @hist_bins depends on the hardware revision
* as is reported by the hw_revision field of the struct media_device_info
* that is returned by ioctl MEDIA_IOC_DEVICE_INFO.
*
* Versions <= V11 have RKISP1_CIF_ISP_HIST_BIN_N_MAX_V10 entries,
* versions >= V12 have RKISP1_CIF_ISP_HIST_BIN_N_MAX_V12 entries.
* RKISP1_CIF_ISP_HIST_BIN_N_MAX is equal to the maximum of the two.
* V10 has RKISP1_CIF_ISP_HIST_BIN_N_MAX_V10 entries, V12 has
* RKISP1_CIF_ISP_HIST_BIN_N_MAX_V12 entries. RKISP1_CIF_ISP_HIST_BIN_N_MAX is
* equal to the maximum of the two.
*/
struct rkisp1_cif_isp_hist_stat {
__u32 hist_bins[RKISP1_CIF_ISP_HIST_BIN_N_MAX];