Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

media: cadence: cdns-csi2rx: Support multiple pixels per clock cycle

The output pixel interface is a parallel bus (32 bits), which
supports sending multiple pixels (1, 2 or 4) per clock cycle for
smaller pixel widths like RAW8-RAW16.

Dual-pixel and Quad-pixel modes can be a requirement if the export rate
of the Cadence IP in Single-pixel mode maxes out before the maximum
supported DPHY-RX frequency, which is the case with TI's integration of
this IP [1].

So, we export a function that lets the downstream hardware block request
a higher pixel-per-clock on a particular output pad.

We check if we can support the requested pixels per clock given the
known maximum for the currently configured format. If not, we set it
to the highest feasible value and return this value to the caller.

[1] Section 12.6.1.4.8.14 CSI_RX_IF Programming Restrictions of AM62 TRM

Link: https://www.ti.com/lit/pdf/spruj16
Tested-by: Yemike Abhilash Chandra <y-abhilashchandra@ti.com> (on SK-AM68)
Signed-off-by: Jai Luthra <jai.luthra@ideasonboard.com>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>

authored by

Jai Luthra and committed by
Hans Verkuil
7b78fa86 4d09706d

+76 -18
+1
MAINTAINERS
··· 5354 5354 F: Documentation/devicetree/bindings/media/cdns,*.txt 5355 5355 F: Documentation/devicetree/bindings/media/cdns,csi2rx.yaml 5356 5356 F: drivers/media/platform/cadence/cdns-csi2* 5357 + F: include/media/cadence/cdns-csi2* 5357 5358 5358 5359 CADENCE NAND DRIVER 5359 5360 L: linux-mtd@lists.infradead.org
+56 -18
drivers/media/platform/cadence/cdns-csi2rx.c
··· 5 5 * Copyright (C) 2017 Cadence Design Systems Inc. 6 6 */ 7 7 8 + #include <linux/bitfield.h> 8 9 #include <linux/clk.h> 9 10 #include <linux/delay.h> 11 + #include <linux/export.h> 10 12 #include <linux/io.h> 11 13 #include <linux/iopoll.h> 12 14 #include <linux/module.h> ··· 19 17 #include <linux/reset.h> 20 18 #include <linux/slab.h> 21 19 20 + #include <media/cadence/cdns-csi2rx.h> 22 21 #include <media/v4l2-ctrls.h> 23 22 #include <media/v4l2-device.h> 24 23 #include <media/v4l2-fwnode.h> ··· 55 52 #define CSI2RX_STREAM_DATA_CFG_VC_SELECT(n) BIT((n) + 16) 56 53 57 54 #define CSI2RX_STREAM_CFG_REG(n) (CSI2RX_STREAM_BASE(n) + 0x00c) 58 - #define CSI2RX_STREAM_CFG_FIFO_MODE_LARGE_BUF (1 << 8) 55 + #define CSI2RX_STREAM_CFG_FIFO_MODE_LARGE_BUF BIT(8) 56 + #define CSI2RX_STREAM_CFG_NUM_PIXELS_MASK GENMASK(5, 4) 57 + #define CSI2RX_STREAM_CFG_NUM_PIXELS(n) ((n) >> 1U) 59 58 60 59 #define CSI2RX_LANES_MAX 4 61 60 #define CSI2RX_STREAMS_MAX 4 ··· 92 87 93 88 struct csi2rx_fmt { 94 89 u32 code; 90 + /* width of a single pixel on CSI-2 bus */ 95 91 u8 bpp; 92 + /* max pixels per clock supported on output bus */ 93 + u8 max_pixels; 96 94 }; 97 95 98 96 struct csi2rx_event { ··· 140 132 struct reset_control *pixel_rst[CSI2RX_STREAMS_MAX]; 141 133 struct phy *dphy; 142 134 135 + u8 num_pixels[CSI2RX_STREAMS_MAX]; 143 136 u8 lanes[CSI2RX_LANES_MAX]; 144 137 u8 num_lanes; 145 138 u8 max_lanes; ··· 158 149 }; 159 150 160 151 static const struct csi2rx_fmt formats[] = { 161 - { .code = MEDIA_BUS_FMT_YUYV8_1X16, .bpp = 16, }, 162 - { .code = MEDIA_BUS_FMT_UYVY8_1X16, .bpp = 16, }, 163 - { .code = MEDIA_BUS_FMT_YVYU8_1X16, .bpp = 16, }, 164 - { .code = MEDIA_BUS_FMT_VYUY8_1X16, .bpp = 16, }, 165 - { .code = MEDIA_BUS_FMT_SBGGR8_1X8, .bpp = 8, }, 166 - { .code = MEDIA_BUS_FMT_SGBRG8_1X8, .bpp = 8, }, 167 - { .code = MEDIA_BUS_FMT_SGRBG8_1X8, .bpp = 8, }, 168 - { .code = MEDIA_BUS_FMT_SRGGB8_1X8, .bpp = 8, }, 169 - { .code = MEDIA_BUS_FMT_Y8_1X8, .bpp = 8, }, 170 - { .code = MEDIA_BUS_FMT_SBGGR10_1X10, .bpp = 10, }, 171 - { .code = MEDIA_BUS_FMT_SGBRG10_1X10, .bpp = 10, }, 172 - { .code = MEDIA_BUS_FMT_SGRBG10_1X10, .bpp = 10, }, 173 - { .code = MEDIA_BUS_FMT_SRGGB10_1X10, .bpp = 10, }, 174 - { .code = MEDIA_BUS_FMT_RGB565_1X16, .bpp = 16, }, 175 - { .code = MEDIA_BUS_FMT_RGB888_1X24, .bpp = 24, }, 176 - { .code = MEDIA_BUS_FMT_BGR888_1X24, .bpp = 24, }, 152 + { .code = MEDIA_BUS_FMT_YUYV8_1X16, .bpp = 16, .max_pixels = 2, }, 153 + { .code = MEDIA_BUS_FMT_UYVY8_1X16, .bpp = 16, .max_pixels = 2, }, 154 + { .code = MEDIA_BUS_FMT_YVYU8_1X16, .bpp = 16, .max_pixels = 2, }, 155 + { .code = MEDIA_BUS_FMT_VYUY8_1X16, .bpp = 16, .max_pixels = 2, }, 156 + { .code = MEDIA_BUS_FMT_SBGGR8_1X8, .bpp = 8, .max_pixels = 4, }, 157 + { .code = MEDIA_BUS_FMT_SGBRG8_1X8, .bpp = 8, .max_pixels = 4, }, 158 + { .code = MEDIA_BUS_FMT_SGRBG8_1X8, .bpp = 8, .max_pixels = 4, }, 159 + { .code = MEDIA_BUS_FMT_SRGGB8_1X8, .bpp = 8, .max_pixels = 4, }, 160 + { .code = MEDIA_BUS_FMT_Y8_1X8, .bpp = 8, .max_pixels = 4, }, 161 + { .code = MEDIA_BUS_FMT_SBGGR10_1X10, .bpp = 10, .max_pixels = 2, }, 162 + { .code = MEDIA_BUS_FMT_SGBRG10_1X10, .bpp = 10, .max_pixels = 2, }, 163 + { .code = MEDIA_BUS_FMT_SGRBG10_1X10, .bpp = 10, .max_pixels = 2, }, 164 + { .code = MEDIA_BUS_FMT_SRGGB10_1X10, .bpp = 10, .max_pixels = 2, }, 165 + { .code = MEDIA_BUS_FMT_RGB565_1X16, .bpp = 16, .max_pixels = 1, }, 166 + { .code = MEDIA_BUS_FMT_RGB888_1X24, .bpp = 24, .max_pixels = 1, }, 167 + { .code = MEDIA_BUS_FMT_BGR888_1X24, .bpp = 24, .max_pixels = 1, }, 177 168 }; 178 169 179 170 static void csi2rx_configure_error_irq_mask(void __iomem *base, ··· 379 370 380 371 reset_control_deassert(csi2rx->pixel_rst[i]); 381 372 382 - writel(CSI2RX_STREAM_CFG_FIFO_MODE_LARGE_BUF, 373 + writel(CSI2RX_STREAM_CFG_FIFO_MODE_LARGE_BUF | 374 + FIELD_PREP(CSI2RX_STREAM_CFG_NUM_PIXELS_MASK, 375 + csi2rx->num_pixels[i]), 383 376 csi2rx->base + CSI2RX_STREAM_CFG_REG(i)); 384 377 385 378 /* ··· 579 568 580 569 return csi2rx_set_fmt(subdev, state, &format); 581 570 } 571 + 572 + int cdns_csi2rx_negotiate_ppc(struct v4l2_subdev *subdev, unsigned int pad, 573 + u8 *ppc) 574 + { 575 + struct csi2rx_priv *csi2rx = v4l2_subdev_to_csi2rx(subdev); 576 + const struct csi2rx_fmt *csi_fmt; 577 + struct v4l2_subdev_state *state; 578 + struct v4l2_mbus_framefmt *fmt; 579 + 580 + if (!ppc || pad < CSI2RX_PAD_SOURCE_STREAM0 || pad >= CSI2RX_PAD_MAX) 581 + return -EINVAL; 582 + 583 + state = v4l2_subdev_lock_and_get_active_state(subdev); 584 + fmt = v4l2_subdev_state_get_format(state, pad); 585 + csi_fmt = csi2rx_get_fmt_by_code(fmt->code); 586 + 587 + /* Reduce requested PPC if it is too high */ 588 + *ppc = min(*ppc, csi_fmt->max_pixels); 589 + 590 + v4l2_subdev_unlock_state(state); 591 + 592 + csi2rx->num_pixels[pad - CSI2RX_PAD_SOURCE_STREAM0] = 593 + CSI2RX_STREAM_CFG_NUM_PIXELS(*ppc); 594 + 595 + return 0; 596 + } 597 + EXPORT_SYMBOL_GPL_FOR_MODULES(cdns_csi2rx_negotiate_ppc, "j721e-csi2rx"); 582 598 583 599 static const struct v4l2_subdev_pad_ops csi2rx_pad_ops = { 584 600 .enum_mbus_code = csi2rx_enum_mbus_code,
+19
include/media/cadence/cdns-csi2rx.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0+ */ 2 + #ifndef _CDNS_CSI2RX_H 3 + #define _CDNS_CSI2RX_H 4 + 5 + #include <media/v4l2-subdev.h> 6 + 7 + /** 8 + * cdns_csi2rx_negotiate_ppc - Negotiate pixel-per-clock on output interface 9 + * 10 + * @subdev: point to &struct v4l2_subdev 11 + * @pad: pad number of the source pad 12 + * @ppc: pointer to requested pixel-per-clock value 13 + * 14 + * Returns 0 on success, negative error code otherwise. 15 + */ 16 + int cdns_csi2rx_negotiate_ppc(struct v4l2_subdev *subdev, unsigned int pad, 17 + u8 *ppc); 18 + 19 + #endif