diff options
Diffstat (limited to 'drivers/media/platform/nxp')
-rw-r--r-- | drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c | 47 | ||||
-rw-r--r-- | drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h | 1 | ||||
-rw-r--r-- | drivers/media/platform/nxp/imx-mipi-csis.c | 68 | ||||
-rw-r--r-- | drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c | 135 | ||||
-rw-r--r-- | drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h | 6 | ||||
-rw-r--r-- | drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c | 18 | ||||
-rw-r--r-- | drivers/media/platform/nxp/imx8mq-mipi-csi2.c | 169 |
7 files changed, 294 insertions, 150 deletions
diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c index 5c17bc58181e..8681dd193033 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c @@ -598,6 +598,27 @@ static void _bswap16(u16 *a) *a = ((*a & 0x00FF) << 8) | ((*a & 0xFF00) >> 8); } +static dma_addr_t mxc_jpeg_get_plane_dma_addr(struct vb2_buffer *buf, unsigned int plane_no) +{ + if (plane_no >= buf->num_planes) + return 0; + return vb2_dma_contig_plane_dma_addr(buf, plane_no) + buf->planes[plane_no].data_offset; +} + +static void *mxc_jpeg_get_plane_vaddr(struct vb2_buffer *buf, unsigned int plane_no) +{ + if (plane_no >= buf->num_planes) + return NULL; + return vb2_plane_vaddr(buf, plane_no) + buf->planes[plane_no].data_offset; +} + +static unsigned long mxc_jpeg_get_plane_payload(struct vb2_buffer *buf, unsigned int plane_no) +{ + if (plane_no >= buf->num_planes) + return 0; + return vb2_get_plane_payload(buf, plane_no) - buf->planes[plane_no].data_offset; +} + static void print_mxc_buf(struct mxc_jpeg_dev *jpeg, struct vb2_buffer *buf, unsigned long len) { @@ -610,11 +631,11 @@ static void print_mxc_buf(struct mxc_jpeg_dev *jpeg, struct vb2_buffer *buf, return; for (plane_no = 0; plane_no < buf->num_planes; plane_no++) { - payload = vb2_get_plane_payload(buf, plane_no); + payload = mxc_jpeg_get_plane_payload(buf, plane_no); if (len == 0) len = payload; - dma_addr = vb2_dma_contig_plane_dma_addr(buf, plane_no); - vaddr = vb2_plane_vaddr(buf, plane_no); + dma_addr = mxc_jpeg_get_plane_dma_addr(buf, plane_no); + vaddr = mxc_jpeg_get_plane_vaddr(buf, plane_no); v4l2_dbg(3, debug, &jpeg->v4l2_dev, "plane %d (vaddr=%p dma_addr=%x payload=%ld):", plane_no, vaddr, dma_addr, payload); @@ -712,16 +733,15 @@ static void mxc_jpeg_addrs(struct mxc_jpeg_desc *desc, struct mxc_jpeg_q_data *q_data; q_data = mxc_jpeg_get_q_data(ctx, raw_buf->type); - desc->buf_base0 = vb2_dma_contig_plane_dma_addr(raw_buf, 0); + desc->buf_base0 = mxc_jpeg_get_plane_dma_addr(raw_buf, 0); desc->buf_base1 = 0; if (img_fmt == STM_CTRL_IMAGE_FORMAT(MXC_JPEG_YUV420)) { if (raw_buf->num_planes == 2) - desc->buf_base1 = vb2_dma_contig_plane_dma_addr(raw_buf, 1); + desc->buf_base1 = mxc_jpeg_get_plane_dma_addr(raw_buf, 1); else desc->buf_base1 = desc->buf_base0 + q_data->sizeimage[0]; } - desc->stm_bufbase = vb2_dma_contig_plane_dma_addr(jpeg_buf, 0) + - offset; + desc->stm_bufbase = mxc_jpeg_get_plane_dma_addr(jpeg_buf, 0) + offset; } static bool mxc_jpeg_is_extended_sequential(const struct mxc_jpeg_fmt *fmt) @@ -1029,8 +1049,8 @@ static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv) vb2_set_plane_payload(&dst_buf->vb2_buf, 1, payload); } dev_dbg(dev, "Decoding finished, payload size: %ld + %ld\n", - vb2_get_plane_payload(&dst_buf->vb2_buf, 0), - vb2_get_plane_payload(&dst_buf->vb2_buf, 1)); + mxc_jpeg_get_plane_payload(&dst_buf->vb2_buf, 0), + mxc_jpeg_get_plane_payload(&dst_buf->vb2_buf, 1)); } /* short preview of the results */ @@ -1889,8 +1909,8 @@ static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx, struct vb2_buffer *vb) struct mxc_jpeg_sof *psof = NULL; struct mxc_jpeg_sos *psos = NULL; struct mxc_jpeg_src_buf *jpeg_src_buf = vb2_to_mxc_buf(vb); - u8 *src_addr = (u8 *)vb2_plane_vaddr(vb, 0); - u32 size = vb2_get_plane_payload(vb, 0); + u8 *src_addr = (u8 *)mxc_jpeg_get_plane_vaddr(vb, 0); + u32 size = mxc_jpeg_get_plane_payload(vb, 0); int ret; memset(&header, 0, sizeof(header)); @@ -2027,6 +2047,11 @@ static int mxc_jpeg_buf_prepare(struct vb2_buffer *vb) i, vb2_plane_size(vb, i), sizeimage); return -EINVAL; } + if (!IS_ALIGNED(mxc_jpeg_get_plane_dma_addr(vb, i), MXC_JPEG_ADDR_ALIGNMENT)) { + dev_err(dev, "planes[%d] address is not %d aligned\n", + i, MXC_JPEG_ADDR_ALIGNMENT); + return -EINVAL; + } } if (V4L2_TYPE_IS_CAPTURE(vb->vb2_queue->type)) { vb2_set_plane_payload(vb, 0, 0); diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h index fdde45f7e163..44e46face6d1 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h @@ -30,6 +30,7 @@ #define MXC_JPEG_MAX_PLANES 2 #define MXC_JPEG_PATTERN_WIDTH 128 #define MXC_JPEG_PATTERN_HEIGHT 64 +#define MXC_JPEG_ADDR_ALIGNMENT 16 enum mxc_jpeg_enc_state { MXC_JPEG_ENCODING = 0, /* jpeg encode phase */ diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c index d060eadebc7a..2beb5f43c2c0 100644 --- a/drivers/media/platform/nxp/imx-mipi-csis.c +++ b/drivers/media/platform/nxp/imx-mipi-csis.c @@ -28,6 +28,7 @@ #include <linux/reset.h> #include <linux/spinlock.h> +#include <media/mipi-csi2.h> #include <media/v4l2-common.h> #include <media/v4l2-device.h> #include <media/v4l2-event.h> @@ -229,25 +230,6 @@ #define DEFAULT_SCLK_CSIS_FREQ 166000000UL -/* MIPI CSI-2 Data Types */ -#define MIPI_CSI2_DATA_TYPE_YUV420_8 0x18 -#define MIPI_CSI2_DATA_TYPE_YUV420_10 0x19 -#define MIPI_CSI2_DATA_TYPE_LE_YUV420_8 0x1a -#define MIPI_CSI2_DATA_TYPE_CS_YUV420_8 0x1c -#define MIPI_CSI2_DATA_TYPE_CS_YUV420_10 0x1d -#define MIPI_CSI2_DATA_TYPE_YUV422_8 0x1e -#define MIPI_CSI2_DATA_TYPE_YUV422_10 0x1f -#define MIPI_CSI2_DATA_TYPE_RGB565 0x22 -#define MIPI_CSI2_DATA_TYPE_RGB666 0x23 -#define MIPI_CSI2_DATA_TYPE_RGB888 0x24 -#define MIPI_CSI2_DATA_TYPE_RAW6 0x28 -#define MIPI_CSI2_DATA_TYPE_RAW7 0x29 -#define MIPI_CSI2_DATA_TYPE_RAW8 0x2a -#define MIPI_CSI2_DATA_TYPE_RAW10 0x2b -#define MIPI_CSI2_DATA_TYPE_RAW12 0x2c -#define MIPI_CSI2_DATA_TYPE_RAW14 0x2d -#define MIPI_CSI2_DATA_TYPE_USER(x) (0x30 + (x)) - struct mipi_csis_event { bool debug; u32 mask; @@ -357,116 +339,116 @@ static const struct csis_pix_format mipi_csis_formats[] = { { .code = MEDIA_BUS_FMT_UYVY8_1X16, .output = MEDIA_BUS_FMT_UYVY8_1X16, - .data_type = MIPI_CSI2_DATA_TYPE_YUV422_8, + .data_type = MIPI_CSI2_DT_YUV422_8B, .width = 16, }, /* RGB formats. */ { .code = MEDIA_BUS_FMT_RGB565_1X16, .output = MEDIA_BUS_FMT_RGB565_1X16, - .data_type = MIPI_CSI2_DATA_TYPE_RGB565, + .data_type = MIPI_CSI2_DT_RGB565, .width = 16, }, { .code = MEDIA_BUS_FMT_BGR888_1X24, .output = MEDIA_BUS_FMT_RGB888_1X24, - .data_type = MIPI_CSI2_DATA_TYPE_RGB888, + .data_type = MIPI_CSI2_DT_RGB888, .width = 24, }, /* RAW (Bayer and greyscale) formats. */ { .code = MEDIA_BUS_FMT_SBGGR8_1X8, .output = MEDIA_BUS_FMT_SBGGR8_1X8, - .data_type = MIPI_CSI2_DATA_TYPE_RAW8, + .data_type = MIPI_CSI2_DT_RAW8, .width = 8, }, { .code = MEDIA_BUS_FMT_SGBRG8_1X8, .output = MEDIA_BUS_FMT_SGBRG8_1X8, - .data_type = MIPI_CSI2_DATA_TYPE_RAW8, + .data_type = MIPI_CSI2_DT_RAW8, .width = 8, }, { .code = MEDIA_BUS_FMT_SGRBG8_1X8, .output = MEDIA_BUS_FMT_SGRBG8_1X8, - .data_type = MIPI_CSI2_DATA_TYPE_RAW8, + .data_type = MIPI_CSI2_DT_RAW8, .width = 8, }, { .code = MEDIA_BUS_FMT_SRGGB8_1X8, .output = MEDIA_BUS_FMT_SRGGB8_1X8, - .data_type = MIPI_CSI2_DATA_TYPE_RAW8, + .data_type = MIPI_CSI2_DT_RAW8, .width = 8, }, { .code = MEDIA_BUS_FMT_Y8_1X8, .output = MEDIA_BUS_FMT_Y8_1X8, - .data_type = MIPI_CSI2_DATA_TYPE_RAW8, + .data_type = MIPI_CSI2_DT_RAW8, .width = 8, }, { .code = MEDIA_BUS_FMT_SBGGR10_1X10, .output = MEDIA_BUS_FMT_SBGGR10_1X10, - .data_type = MIPI_CSI2_DATA_TYPE_RAW10, + .data_type = MIPI_CSI2_DT_RAW10, .width = 10, }, { .code = MEDIA_BUS_FMT_SGBRG10_1X10, .output = MEDIA_BUS_FMT_SGBRG10_1X10, - .data_type = MIPI_CSI2_DATA_TYPE_RAW10, + .data_type = MIPI_CSI2_DT_RAW10, .width = 10, }, { .code = MEDIA_BUS_FMT_SGRBG10_1X10, .output = MEDIA_BUS_FMT_SGRBG10_1X10, - .data_type = MIPI_CSI2_DATA_TYPE_RAW10, + .data_type = MIPI_CSI2_DT_RAW10, .width = 10, }, { .code = MEDIA_BUS_FMT_SRGGB10_1X10, .output = MEDIA_BUS_FMT_SRGGB10_1X10, - .data_type = MIPI_CSI2_DATA_TYPE_RAW10, + .data_type = MIPI_CSI2_DT_RAW10, .width = 10, }, { .code = MEDIA_BUS_FMT_Y10_1X10, .output = MEDIA_BUS_FMT_Y10_1X10, - .data_type = MIPI_CSI2_DATA_TYPE_RAW10, + .data_type = MIPI_CSI2_DT_RAW10, .width = 10, }, { .code = MEDIA_BUS_FMT_SBGGR12_1X12, .output = MEDIA_BUS_FMT_SBGGR12_1X12, - .data_type = MIPI_CSI2_DATA_TYPE_RAW12, + .data_type = MIPI_CSI2_DT_RAW12, .width = 12, }, { .code = MEDIA_BUS_FMT_SGBRG12_1X12, .output = MEDIA_BUS_FMT_SGBRG12_1X12, - .data_type = MIPI_CSI2_DATA_TYPE_RAW12, + .data_type = MIPI_CSI2_DT_RAW12, .width = 12, }, { .code = MEDIA_BUS_FMT_SGRBG12_1X12, .output = MEDIA_BUS_FMT_SGRBG12_1X12, - .data_type = MIPI_CSI2_DATA_TYPE_RAW12, + .data_type = MIPI_CSI2_DT_RAW12, .width = 12, }, { .code = MEDIA_BUS_FMT_SRGGB12_1X12, .output = MEDIA_BUS_FMT_SRGGB12_1X12, - .data_type = MIPI_CSI2_DATA_TYPE_RAW12, + .data_type = MIPI_CSI2_DT_RAW12, .width = 12, }, { .code = MEDIA_BUS_FMT_Y12_1X12, .output = MEDIA_BUS_FMT_Y12_1X12, - .data_type = MIPI_CSI2_DATA_TYPE_RAW12, + .data_type = MIPI_CSI2_DT_RAW12, .width = 12, }, { .code = MEDIA_BUS_FMT_SBGGR14_1X14, .output = MEDIA_BUS_FMT_SBGGR14_1X14, - .data_type = MIPI_CSI2_DATA_TYPE_RAW14, + .data_type = MIPI_CSI2_DT_RAW14, .width = 14, }, { .code = MEDIA_BUS_FMT_SGBRG14_1X14, .output = MEDIA_BUS_FMT_SGBRG14_1X14, - .data_type = MIPI_CSI2_DATA_TYPE_RAW14, + .data_type = MIPI_CSI2_DT_RAW14, .width = 14, }, { .code = MEDIA_BUS_FMT_SGRBG14_1X14, .output = MEDIA_BUS_FMT_SGRBG14_1X14, - .data_type = MIPI_CSI2_DATA_TYPE_RAW14, + .data_type = MIPI_CSI2_DT_RAW14, .width = 14, }, { .code = MEDIA_BUS_FMT_SRGGB14_1X14, .output = MEDIA_BUS_FMT_SRGGB14_1X14, - .data_type = MIPI_CSI2_DATA_TYPE_RAW14, + .data_type = MIPI_CSI2_DT_RAW14, .width = 14, }, /* JPEG */ @@ -494,7 +476,7 @@ static const struct csis_pix_format mipi_csis_formats[] = { * SoC that can support quad pixel mode, this will have to be * revisited. */ - .data_type = MIPI_CSI2_DATA_TYPE_RAW8, + .data_type = MIPI_CSI2_DT_RAW8, .width = 8, } }; @@ -583,7 +565,7 @@ static void __mipi_csis_set_format(struct mipi_csis_device *csis, * * TODO: Verify which other formats require DUAL (or QUAD) modes. */ - if (csis_fmt->data_type == MIPI_CSI2_DATA_TYPE_YUV422_8) + if (csis_fmt->data_type == MIPI_CSI2_DT_YUV422_8B) val |= MIPI_CSIS_ISPCFG_PIXEL_MODE_DUAL; val |= MIPI_CSIS_ISPCFG_FMT(csis_fmt->data_type); diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c index 1e79b1211b60..981648a03113 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c @@ -3,6 +3,7 @@ * Copyright 2019-2020 NXP */ +#include <linux/bits.h> #include <linux/clk.h> #include <linux/device.h> #include <linux/errno.h> @@ -245,26 +246,41 @@ static void mxc_isi_v4l2_cleanup(struct mxc_isi_dev *isi) /* Panic will assert when the buffers are 50% full */ -/* For i.MX8QXP C0 and i.MX8MN ISI IER version */ +/* For i.MX8MN ISI IER version */ static const struct mxc_isi_ier_reg mxc_imx8_isi_ier_v1 = { - .oflw_y_buf_en = { .offset = 19, .mask = 0x80000 }, - .oflw_u_buf_en = { .offset = 21, .mask = 0x200000 }, - .oflw_v_buf_en = { .offset = 23, .mask = 0x800000 }, + .oflw_y_buf_en = { .mask = BIT(19) }, + .oflw_u_buf_en = { .mask = BIT(21) }, + .oflw_v_buf_en = { .mask = BIT(23) }, - .panic_y_buf_en = {.offset = 20, .mask = 0x100000 }, - .panic_u_buf_en = {.offset = 22, .mask = 0x400000 }, - .panic_v_buf_en = {.offset = 24, .mask = 0x1000000 }, + .panic_y_buf_en = { .mask = BIT(20) }, + .panic_u_buf_en = { .mask = BIT(22) }, + .panic_v_buf_en = { .mask = BIT(24) }, }; -/* For i.MX8MP ISI IER version */ +/* For i.MX8QXP C0 and i.MX8MP ISI IER version */ static const struct mxc_isi_ier_reg mxc_imx8_isi_ier_v2 = { - .oflw_y_buf_en = { .offset = 18, .mask = 0x40000 }, - .oflw_u_buf_en = { .offset = 20, .mask = 0x100000 }, - .oflw_v_buf_en = { .offset = 22, .mask = 0x400000 }, + .oflw_y_buf_en = { .mask = BIT(18) }, + .oflw_u_buf_en = { .mask = BIT(20) }, + .oflw_v_buf_en = { .mask = BIT(22) }, - .panic_y_buf_en = {.offset = 19, .mask = 0x80000 }, - .panic_u_buf_en = {.offset = 21, .mask = 0x200000 }, - .panic_v_buf_en = {.offset = 23, .mask = 0x800000 }, + .panic_y_buf_en = { .mask = BIT(19) }, + .panic_u_buf_en = { .mask = BIT(21) }, + .panic_v_buf_en = { .mask = BIT(23) }, +}; + +/* For i.MX8QM ISI IER version */ +static const struct mxc_isi_ier_reg mxc_imx8_isi_ier_qm = { + .oflw_y_buf_en = { .mask = BIT(16) }, + .oflw_u_buf_en = { .mask = BIT(19) }, + .oflw_v_buf_en = { .mask = BIT(22) }, + + .excs_oflw_y_buf_en = { .mask = BIT(17) }, + .excs_oflw_u_buf_en = { .mask = BIT(20) }, + .excs_oflw_v_buf_en = { .mask = BIT(23) }, + + .panic_y_buf_en = { .mask = BIT(18) }, + .panic_u_buf_en = { .mask = BIT(21) }, + .panic_v_buf_en = { .mask = BIT(24) }, }; /* Panic will assert when the buffers are 50% full */ @@ -274,11 +290,6 @@ static const struct mxc_isi_set_thd mxc_imx8_isi_thd_v1 = { .panic_set_thd_v = { .mask = 0xf0000, .offset = 16, .threshold = 0x7 }, }; -static const struct clk_bulk_data mxc_imx8mn_clks[] = { - { .id = "axi" }, - { .id = "apb" }, -}; - static const struct mxc_isi_plat_data mxc_imx8mn_data = { .model = MXC_ISI_IMX8MN, .num_ports = 1, @@ -286,8 +297,6 @@ static const struct mxc_isi_plat_data mxc_imx8mn_data = { .reg_offset = 0, .ier_reg = &mxc_imx8_isi_ier_v1, .set_thd = &mxc_imx8_isi_thd_v1, - .clks = mxc_imx8mn_clks, - .num_clks = ARRAY_SIZE(mxc_imx8mn_clks), .buf_active_reverse = false, .gasket_ops = &mxc_imx8_gasket_ops, .has_36bit_dma = false, @@ -300,8 +309,6 @@ static const struct mxc_isi_plat_data mxc_imx8mp_data = { .reg_offset = 0x2000, .ier_reg = &mxc_imx8_isi_ier_v2, .set_thd = &mxc_imx8_isi_thd_v1, - .clks = mxc_imx8mn_clks, - .num_clks = ARRAY_SIZE(mxc_imx8mn_clks), .buf_active_reverse = true, .gasket_ops = &mxc_imx8_gasket_ops, .has_36bit_dma = true, @@ -314,8 +321,6 @@ static const struct mxc_isi_plat_data mxc_imx8ulp_data = { .reg_offset = 0x0, .ier_reg = &mxc_imx8_isi_ier_v2, .set_thd = &mxc_imx8_isi_thd_v1, - .clks = mxc_imx8mn_clks, - .num_clks = ARRAY_SIZE(mxc_imx8mn_clks), .buf_active_reverse = true, .has_36bit_dma = false, }; @@ -327,13 +332,33 @@ static const struct mxc_isi_plat_data mxc_imx93_data = { .reg_offset = 0, .ier_reg = &mxc_imx8_isi_ier_v2, .set_thd = &mxc_imx8_isi_thd_v1, - .clks = mxc_imx8mn_clks, - .num_clks = ARRAY_SIZE(mxc_imx8mn_clks), .buf_active_reverse = true, .gasket_ops = &mxc_imx93_gasket_ops, .has_36bit_dma = false, }; +static const struct mxc_isi_plat_data mxc_imx8qm_data = { + .model = MXC_ISI_IMX8QM, + .num_ports = 5, + .num_channels = 8, + .reg_offset = 0x10000, + .ier_reg = &mxc_imx8_isi_ier_qm, + .set_thd = &mxc_imx8_isi_thd_v1, + .buf_active_reverse = true, + .has_36bit_dma = false, +}; + +static const struct mxc_isi_plat_data mxc_imx8qxp_data = { + .model = MXC_ISI_IMX8QXP, + .num_ports = 5, + .num_channels = 6, + .reg_offset = 0x10000, + .ier_reg = &mxc_imx8_isi_ier_v2, + .set_thd = &mxc_imx8_isi_thd_v1, + .buf_active_reverse = true, + .has_36bit_dma = false, +}; + /* ----------------------------------------------------------------------------- * Power management */ @@ -385,7 +410,7 @@ static int mxc_isi_runtime_suspend(struct device *dev) { struct mxc_isi_dev *isi = dev_get_drvdata(dev); - clk_bulk_disable_unprepare(isi->pdata->num_clks, isi->clks); + clk_bulk_disable_unprepare(isi->num_clks, isi->clks); return 0; } @@ -395,7 +420,7 @@ static int mxc_isi_runtime_resume(struct device *dev) struct mxc_isi_dev *isi = dev_get_drvdata(dev); int ret; - ret = clk_bulk_prepare_enable(isi->pdata->num_clks, isi->clks); + ret = clk_bulk_prepare_enable(isi->num_clks, isi->clks); if (ret) { dev_err(dev, "Failed to enable clocks (%d)\n", ret); return ret; @@ -413,27 +438,6 @@ static const struct dev_pm_ops mxc_isi_pm_ops = { * Probe, remove & driver */ -static int mxc_isi_clk_get(struct mxc_isi_dev *isi) -{ - unsigned int size = isi->pdata->num_clks - * sizeof(*isi->clks); - int ret; - - isi->clks = devm_kmemdup(isi->dev, isi->pdata->clks, size, GFP_KERNEL); - if (!isi->clks) - return -ENOMEM; - - ret = devm_clk_bulk_get(isi->dev, isi->pdata->num_clks, - isi->clks); - if (ret < 0) { - dev_err(isi->dev, "Failed to acquire clocks: %d\n", - ret); - return ret; - } - - return 0; -} - static int mxc_isi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -456,34 +460,25 @@ static int mxc_isi_probe(struct platform_device *pdev) if (!isi->pipes) return -ENOMEM; - ret = mxc_isi_clk_get(isi); - if (ret < 0) { - dev_err(dev, "Failed to get clocks\n"); - return ret; - } + isi->num_clks = devm_clk_bulk_get_all(dev, &isi->clks); + if (isi->num_clks < 0) + return dev_err_probe(dev, isi->num_clks, "Failed to get clocks\n"); isi->regs = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(isi->regs)) { - dev_err(dev, "Failed to get ISI register map\n"); - return PTR_ERR(isi->regs); - } + if (IS_ERR(isi->regs)) + return dev_err_probe(dev, PTR_ERR(isi->regs), + "Failed to get ISI register map\n"); if (isi->pdata->gasket_ops) { isi->gasket = syscon_regmap_lookup_by_phandle(dev->of_node, "fsl,blk-ctrl"); - if (IS_ERR(isi->gasket)) { - ret = PTR_ERR(isi->gasket); - dev_err(dev, "failed to get gasket: %d\n", ret); - return ret; - } + if (IS_ERR(isi->gasket)) + return dev_err_probe(dev, PTR_ERR(isi->gasket), + "failed to get gasket\n"); } dma_size = isi->pdata->has_36bit_dma ? 36 : 32; - ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(dma_size)); - if (ret) { - dev_err(dev, "failed to set DMA mask\n"); - return ret; - } + dma_set_mask_and_coherent(dev, DMA_BIT_MASK(dma_size)); pm_runtime_enable(dev); @@ -541,6 +536,8 @@ static void mxc_isi_remove(struct platform_device *pdev) static const struct of_device_id mxc_isi_of_match[] = { { .compatible = "fsl,imx8mn-isi", .data = &mxc_imx8mn_data }, { .compatible = "fsl,imx8mp-isi", .data = &mxc_imx8mp_data }, + { .compatible = "fsl,imx8qm-isi", .data = &mxc_imx8qm_data }, + { .compatible = "fsl,imx8qxp-isi", .data = &mxc_imx8qxp_data }, { .compatible = "fsl,imx8ulp-isi", .data = &mxc_imx8ulp_data }, { .compatible = "fsl,imx93-isi", .data = &mxc_imx93_data }, { /* sentinel */ }, diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h index 9c7fe9e5f941..206995bedca4 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h @@ -114,7 +114,6 @@ struct mxc_isi_buffer { }; struct mxc_isi_reg { - u32 offset; u32 mask; }; @@ -158,6 +157,8 @@ struct mxc_gasket_ops { enum model { MXC_ISI_IMX8MN, MXC_ISI_IMX8MP, + MXC_ISI_IMX8QM, + MXC_ISI_IMX8QXP, MXC_ISI_IMX8ULP, MXC_ISI_IMX93, }; @@ -170,8 +171,6 @@ struct mxc_isi_plat_data { const struct mxc_isi_ier_reg *ier_reg; const struct mxc_isi_set_thd *set_thd; const struct mxc_gasket_ops *gasket_ops; - const struct clk_bulk_data *clks; - unsigned int num_clks; bool buf_active_reverse; bool has_36bit_dma; }; @@ -283,6 +282,7 @@ struct mxc_isi_dev { void __iomem *regs; struct clk_bulk_data *clks; + int num_clks; struct regmap *gasket; struct mxc_isi_crossbar crossbar; diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c index 93a55c97cd17..ede6cc74c023 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c @@ -188,11 +188,12 @@ static int mxc_isi_crossbar_init_state(struct v4l2_subdev *sd, * Create a 1:1 mapping between pixel link inputs and outputs to * pipelines by default. */ - routes = kcalloc(xbar->num_sources, sizeof(*routes), GFP_KERNEL); + routing.num_routes = min(xbar->num_sinks - 1, xbar->num_sources); + routes = kcalloc(routing.num_routes, sizeof(*routes), GFP_KERNEL); if (!routes) return -ENOMEM; - for (i = 0; i < xbar->num_sources; ++i) { + for (i = 0; i < routing.num_routes; ++i) { struct v4l2_subdev_route *route = &routes[i]; route->sink_pad = i; @@ -200,7 +201,6 @@ static int mxc_isi_crossbar_init_state(struct v4l2_subdev *sd, route->flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE; } - routing.num_routes = xbar->num_sources; routing.routes = routes; ret = __mxc_isi_crossbar_set_routing(sd, state, &routing); @@ -352,9 +352,8 @@ static int mxc_isi_crossbar_enable_streams(struct v4l2_subdev *sd, sink_streams); if (ret) { dev_err(xbar->isi->dev, - "failed to %s streams 0x%llx on '%s':%u: %d\n", - "enable", sink_streams, remote_sd->name, - remote_pad, ret); + "failed to enable streams 0x%llx on '%s':%u: %d\n", + sink_streams, remote_sd->name, remote_pad, ret); mxc_isi_crossbar_gasket_disable(xbar, sink_pad); return ret; } @@ -392,9 +391,8 @@ static int mxc_isi_crossbar_disable_streams(struct v4l2_subdev *sd, sink_streams); if (ret) dev_err(xbar->isi->dev, - "failed to %s streams 0x%llx on '%s':%u: %d\n", - "disable", sink_streams, remote_sd->name, - remote_pad, ret); + "failed to disable streams 0x%llx on '%s':%u: %d\n", + sink_streams, remote_sd->name, remote_pad, ret); mxc_isi_crossbar_gasket_disable(xbar, sink_pad); } @@ -453,7 +451,7 @@ int mxc_isi_crossbar_init(struct mxc_isi_dev *isi) * the memory input. */ xbar->num_sinks = isi->pdata->num_ports + 1; - xbar->num_sources = isi->pdata->num_ports; + xbar->num_sources = isi->pdata->num_channels; num_pads = xbar->num_sinks + xbar->num_sources; xbar->pads = kcalloc(num_pads, sizeof(*xbar->pads), GFP_KERNEL); diff --git a/drivers/media/platform/nxp/imx8mq-mipi-csi2.c b/drivers/media/platform/nxp/imx8mq-mipi-csi2.c index a8bcf60e2f37..3a4645f59a44 100644 --- a/drivers/media/platform/nxp/imx8mq-mipi-csi2.c +++ b/drivers/media/platform/nxp/imx8mq-mipi-csi2.c @@ -5,6 +5,7 @@ * Copyright (C) 2021 Purism SPC */ +#include <linux/bitfield.h> #include <linux/clk.h> #include <linux/clk-provider.h> #include <linux/delay.h> @@ -62,6 +63,8 @@ #define CSI2RX_CFG_VID_P_FIFO_SEND_LEVEL 0x188 #define CSI2RX_CFG_DISABLE_PAYLOAD_1 0x130 +struct csi_state; + enum { ST_POWERED = 1, ST_STREAMING = 2, @@ -83,11 +86,11 @@ static const char * const imx8mq_mipi_csi_clk_id[CSI2_NUM_CLKS] = { #define CSI2_NUM_CLKS ARRAY_SIZE(imx8mq_mipi_csi_clk_id) -#define GPR_CSI2_1_RX_ENABLE BIT(13) -#define GPR_CSI2_1_VID_INTFC_ENB BIT(12) -#define GPR_CSI2_1_HSEL BIT(10) -#define GPR_CSI2_1_CONT_CLK_MODE BIT(8) -#define GPR_CSI2_1_S_PRG_RXHS_SETTLE(x) (((x) & 0x3f) << 2) +struct imx8mq_plat_data { + int (*enable)(struct csi_state *state, u32 hs_settle); + void (*disable)(struct csi_state *state); + bool use_reg_csr; +}; /* * The send level configures the number of entries that must accumulate in @@ -106,6 +109,7 @@ static const char * const imx8mq_mipi_csi_clk_id[CSI2_NUM_CLKS] = { struct csi_state { struct device *dev; + const struct imx8mq_plat_data *pdata; void __iomem *regs; struct clk_bulk_data clks[CSI2_NUM_CLKS]; struct reset_control *rst; @@ -137,6 +141,123 @@ struct csi2_pix_format { u8 width; }; +/* ----------------------------------------------------------------------------- + * i.MX8MQ GPR + */ + +#define GPR_CSI2_1_RX_ENABLE BIT(13) +#define GPR_CSI2_1_VID_INTFC_ENB BIT(12) +#define GPR_CSI2_1_HSEL BIT(10) +#define GPR_CSI2_1_CONT_CLK_MODE BIT(8) +#define GPR_CSI2_1_S_PRG_RXHS_SETTLE(x) (((x) & 0x3f) << 2) + +static int imx8mq_gpr_enable(struct csi_state *state, u32 hs_settle) +{ + regmap_update_bits(state->phy_gpr, + state->phy_gpr_reg, + 0x3fff, + GPR_CSI2_1_RX_ENABLE | + GPR_CSI2_1_VID_INTFC_ENB | + GPR_CSI2_1_HSEL | + GPR_CSI2_1_CONT_CLK_MODE | + GPR_CSI2_1_S_PRG_RXHS_SETTLE(hs_settle)); + + return 0; +} + +static const struct imx8mq_plat_data imx8mq_data = { + .enable = imx8mq_gpr_enable, +}; + +/* ----------------------------------------------------------------------------- + * i.MX8QXP + */ + +#define CSI2SS_PL_CLK_INTERVAL_US 100 +#define CSI2SS_PL_CLK_TIMEOUT_US 100000 + +#define CSI2SS_PLM_CTRL 0x0 +#define CSI2SS_PLM_CTRL_ENABLE_PL BIT(0) +#define CSI2SS_PLM_CTRL_VSYNC_OVERRIDE BIT(9) +#define CSI2SS_PLM_CTRL_HSYNC_OVERRIDE BIT(10) +#define CSI2SS_PLM_CTRL_VALID_OVERRIDE BIT(11) +#define CSI2SS_PLM_CTRL_POLARITY_HIGH BIT(12) +#define CSI2SS_PLM_CTRL_PL_CLK_RUN BIT(31) + +#define CSI2SS_PHY_CTRL 0x4 +#define CSI2SS_PHY_CTRL_RX_ENABLE BIT(0) +#define CSI2SS_PHY_CTRL_AUTO_PD_EN BIT(1) +#define CSI2SS_PHY_CTRL_DDRCLK_EN BIT(2) +#define CSI2SS_PHY_CTRL_CONT_CLK_MODE BIT(3) +#define CSI2SS_PHY_CTRL_RX_HS_SETTLE_MASK GENMASK(9, 4) +#define CSI2SS_PHY_CTRL_RTERM_SEL BIT(21) +#define CSI2SS_PHY_CTRL_PD BIT(22) + +#define CSI2SS_DATA_TYPE_DISABLE_BF 0x38 +#define CSI2SS_DATA_TYPE_DISABLE_BF_MASK GENMASK(23, 0) + +#define CSI2SS_CTRL_CLK_RESET 0x44 +#define CSI2SS_CTRL_CLK_RESET_EN BIT(0) + +static int imx8qxp_gpr_enable(struct csi_state *state, u32 hs_settle) +{ + int ret; + u32 val; + + /* Clear format */ + regmap_clear_bits(state->phy_gpr, CSI2SS_DATA_TYPE_DISABLE_BF, + CSI2SS_DATA_TYPE_DISABLE_BF_MASK); + + regmap_write(state->phy_gpr, CSI2SS_PLM_CTRL, 0x0); + + regmap_write(state->phy_gpr, CSI2SS_PHY_CTRL, + FIELD_PREP(CSI2SS_PHY_CTRL_RX_HS_SETTLE_MASK, hs_settle) | + CSI2SS_PHY_CTRL_RX_ENABLE | CSI2SS_PHY_CTRL_DDRCLK_EN | + CSI2SS_PHY_CTRL_CONT_CLK_MODE | CSI2SS_PHY_CTRL_PD | + CSI2SS_PHY_CTRL_RTERM_SEL | CSI2SS_PHY_CTRL_AUTO_PD_EN); + + ret = regmap_read_poll_timeout(state->phy_gpr, CSI2SS_PLM_CTRL, + val, !(val & CSI2SS_PLM_CTRL_PL_CLK_RUN), + CSI2SS_PL_CLK_INTERVAL_US, + CSI2SS_PL_CLK_TIMEOUT_US); + + if (ret) { + dev_err(state->dev, "Timeout waiting for Pixel-Link clock\n"); + return ret; + } + + /* Enable Pixel link Master */ + regmap_set_bits(state->phy_gpr, CSI2SS_PLM_CTRL, + CSI2SS_PLM_CTRL_ENABLE_PL | CSI2SS_PLM_CTRL_VALID_OVERRIDE); + + /* PHY Enable */ + regmap_clear_bits(state->phy_gpr, CSI2SS_PHY_CTRL, + CSI2SS_PHY_CTRL_PD | CSI2SS_PLM_CTRL_POLARITY_HIGH); + + /* Release Reset */ + regmap_set_bits(state->phy_gpr, CSI2SS_CTRL_CLK_RESET, CSI2SS_CTRL_CLK_RESET_EN); + + return ret; +} + +static void imx8qxp_gpr_disable(struct csi_state *state) +{ + /* Disable Pixel Link */ + regmap_write(state->phy_gpr, CSI2SS_PLM_CTRL, 0x0); + + /* Disable PHY */ + regmap_write(state->phy_gpr, CSI2SS_PHY_CTRL, 0x0); + + regmap_clear_bits(state->phy_gpr, CSI2SS_CTRL_CLK_RESET, + CSI2SS_CTRL_CLK_RESET_EN); +}; + +static const struct imx8mq_plat_data imx8qxp_data = { + .enable = imx8qxp_gpr_enable, + .disable = imx8qxp_gpr_disable, + .use_reg_csr = true, +}; + static const struct csi2_pix_format imx8mq_mipi_csi_formats[] = { /* RAW (Bayer and greyscale) formats. */ { @@ -371,14 +492,9 @@ static int imx8mq_mipi_csi_start_stream(struct csi_state *state, if (ret) return ret; - regmap_update_bits(state->phy_gpr, - state->phy_gpr_reg, - 0x3fff, - GPR_CSI2_1_RX_ENABLE | - GPR_CSI2_1_VID_INTFC_ENB | - GPR_CSI2_1_HSEL | - GPR_CSI2_1_CONT_CLK_MODE | - GPR_CSI2_1_S_PRG_RXHS_SETTLE(hs_settle)); + ret = state->pdata->enable(state, hs_settle); + if (ret) + return ret; return 0; } @@ -386,6 +502,9 @@ static int imx8mq_mipi_csi_start_stream(struct csi_state *state, static void imx8mq_mipi_csi_stop_stream(struct csi_state *state) { imx8mq_mipi_csi_write(state, CSI2RX_CFG_DISABLE_DATA_LANES, 0xf); + + if (state->pdata->disable) + state->pdata->disable(state); } /* ----------------------------------------------------------------------------- @@ -837,6 +956,25 @@ static int imx8mq_mipi_csi_parse_dt(struct csi_state *state) return PTR_ERR(state->rst); } + if (state->pdata->use_reg_csr) { + const struct regmap_config regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + }; + void __iomem *base; + + base = devm_platform_ioremap_resource(to_platform_device(dev), 1); + if (IS_ERR(base)) + return dev_err_probe(dev, PTR_ERR(base), "Missing CSR register\n"); + + state->phy_gpr = devm_regmap_init_mmio(dev, base, ®map_config); + if (IS_ERR(state->phy_gpr)) + return dev_err_probe(dev, PTR_ERR(state->phy_gpr), + "Failed to init CSI MMIO regmap\n"); + return 0; + } + ret = of_property_read_u32_array(np, "fsl,mipi-phy-gpr", out_val, ARRAY_SIZE(out_val)); if (ret) { @@ -876,6 +1014,8 @@ static int imx8mq_mipi_csi_probe(struct platform_device *pdev) state->dev = dev; + state->pdata = of_device_get_match_data(dev); + ret = imx8mq_mipi_csi_parse_dt(state); if (ret < 0) { dev_err(dev, "Failed to parse device tree: %d\n", ret); @@ -953,7 +1093,8 @@ static void imx8mq_mipi_csi_remove(struct platform_device *pdev) } static const struct of_device_id imx8mq_mipi_csi_of_match[] = { - { .compatible = "fsl,imx8mq-mipi-csi2", }, + { .compatible = "fsl,imx8mq-mipi-csi2", .data = &imx8mq_data }, + { .compatible = "fsl,imx8qxp-mipi-csi2", .data = &imx8qxp_data }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, imx8mq_mipi_csi_of_match); |