mbox series

[v2,0/4] media: raspberrypi: Support RPi5's CFE

Message ID 20240620-rp1-cfe-v2-0-b8b48fdba3b3@ideasonboard.com (mailing list archive)
Headers show
Series media: raspberrypi: Support RPi5's CFE | expand

Message

Tomi Valkeinen June 20, 2024, 11:07 a.m. UTC
This series adds support to the CFE hardware block on RaspberryPi 5. The
CFE (Camera Front End) contains a CSI-2 receiver and Front End, a small
ISP.

This series is based on linux-media-stage with Jacopo's "[PATCH v9 0/8]
media: raspberrypi: Add support for PiSP Back End".

To run this, you need the basic RPi5 kernel support plus relevant dts
changes to enable the cfe and camera. My work branch with everything
needed to run CFE can be found from:

git://git.kernel.org/pub/scm/linux/kernel/git/tomba/linux.git rp1-cfe

A few notes about the patches:

- The original work was done by RaspberryPi, mostly by Naushir Patuck.
- The second video node only sets V4L2_CAP_META_CAPTURE instead of both
  V4L2_CAP_META_CAPTURE and V4L2_CAP_META_CAPTURE like the other nodes.
  This is a temporary workaround for userspace (libcamera), and
  hopefully can be removed soon.

I have tested this with:
- A single IMX219 sensor connected to the RPi5's CSI-2 port
- Arducam's UB960 FPD-Link board with four imx219 sensors connected

 Tomi

Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
---
Changes in v2:
- Change the compatible string back to raspberrypi,rp1-cfe from raspberrypi,rpi5-rp1-cfe
- Drop the references to rp1 headers in the DT binding example. This
  allows compiling the example without the rp1 support.
- Fix missing remap lines for mono formats
- Fix csi2_pad_set_fmt() so that the format can be changed back to the
  sink's format from 16-bit or compressed format.
- Link to v1: https://lore.kernel.org/r/20240318-rp1-cfe-v1-0-ac6d960ff22d@ideasonboard.com

---
Tomi Valkeinen (4):
      media: uapi: Add meta formats for PiSP FE config and stats
      dt-bindings: media: Add bindings for raspberrypi,rp1-cfe
      media: raspberrypi: Add support for RP1-CFE
      media: admin-guide: Document the Raspberry Pi CFE (rp1-cfe)

 .../admin-guide/media/raspberrypi-rp1-cfe.dot      |   27 +
 .../admin-guide/media/raspberrypi-rp1-cfe.rst      |   78 +
 Documentation/admin-guide/media/v4l-drivers.rst    |    1 +
 .../bindings/media/raspberrypi,rp1-cfe.yaml        |   98 +
 .../userspace-api/media/v4l/meta-formats.rst       |    1 +
 .../userspace-api/media/v4l/metafmt-pisp-fe.rst    |   39 +
 MAINTAINERS                                        |    8 +
 drivers/media/platform/raspberrypi/Kconfig         |    1 +
 drivers/media/platform/raspberrypi/Makefile        |    1 +
 drivers/media/platform/raspberrypi/rp1-cfe/Kconfig |   14 +
 .../media/platform/raspberrypi/rp1-cfe/Makefile    |    6 +
 .../media/platform/raspberrypi/rp1-cfe/cfe-fmts.h  |  332 +++
 .../media/platform/raspberrypi/rp1-cfe/cfe-trace.h |  196 ++
 drivers/media/platform/raspberrypi/rp1-cfe/cfe.c   | 2526 ++++++++++++++++++++
 drivers/media/platform/raspberrypi/rp1-cfe/cfe.h   |   43 +
 drivers/media/platform/raspberrypi/rp1-cfe/csi2.c  |  583 +++++
 drivers/media/platform/raspberrypi/rp1-cfe/csi2.h  |   89 +
 drivers/media/platform/raspberrypi/rp1-cfe/dphy.c  |  175 ++
 drivers/media/platform/raspberrypi/rp1-cfe/dphy.h  |   27 +
 .../media/platform/raspberrypi/rp1-cfe/pisp-fe.c   |  581 +++++
 .../media/platform/raspberrypi/rp1-cfe/pisp-fe.h   |   53 +
 drivers/media/v4l2-core/v4l2-ioctl.c               |    2 +
 .../uapi/linux/media/raspberrypi/pisp_fe_config.h  |  273 +++
 .../linux/media/raspberrypi/pisp_fe_statistics.h   |   64 +
 include/uapi/linux/videodev2.h                     |    2 +
 25 files changed, 5220 insertions(+)
---
base-commit: 954ee38d40c98001cfdc570c4d5e90bcbc456ce1
change-id: 20240314-rp1-cfe-142b628b7214
prerequisite-message-id: <20240531080707.34568-1-jacopo.mondi@ideasonboard.com>
prerequisite-patch-id: 42749883104fffad151e25d8127eb84800d7e9ca
prerequisite-patch-id: 433ce52b6b1b72f2c29e4474d72cd5106b73c075
prerequisite-patch-id: b9b3006cd03bb4e41e03f735d97e19081a32be02
prerequisite-patch-id: abeb8c40020f0ca6140afc141e535abc86a4773b
prerequisite-patch-id: 4ddf121ee47eeadeb370a5fbabc82ca6f6caa23b
prerequisite-patch-id: ee469d3c346f55483733a04d89e87d02126501cc
prerequisite-patch-id: 9467d5cd306aa29842128294a5f76f184b72eab7
prerequisite-patch-id: e6dbee90dfbd984bd55cbe3db56d9d8de4dc86ae

Best regards,

Comments

Laurent Pinchart June 20, 2024, 4:23 p.m. UTC | #1
On Thu, Jun 20, 2024 at 02:07:52PM +0300, Tomi Valkeinen wrote:
> Add support for Raspberry Pi CFE. The CFE is a hardware block that
> contains:
> 
> - MIPI D-PHY
> - MIPI CSI-2 receiver
> - Front End ISP (FE)
> 
> The driver has been upported from the Raspberry Pi kernel commit
> 88a681df9623 ("ARM: dts: bcm2712-rpi: Add i2c<n>_pins labels").
> 
> Co-developed-by: Naushir Patuck <naush@raspberrypi.com>
> Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
> ---
>  MAINTAINERS                                        |    8 +
>  drivers/media/platform/raspberrypi/Kconfig         |    1 +
>  drivers/media/platform/raspberrypi/Makefile        |    1 +
>  drivers/media/platform/raspberrypi/rp1-cfe/Kconfig |   14 +
>  .../media/platform/raspberrypi/rp1-cfe/Makefile    |    6 +
>  .../media/platform/raspberrypi/rp1-cfe/cfe-fmts.h  |  332 +++
>  .../media/platform/raspberrypi/rp1-cfe/cfe-trace.h |  196 ++
>  drivers/media/platform/raspberrypi/rp1-cfe/cfe.c   | 2526 ++++++++++++++++++++
>  drivers/media/platform/raspberrypi/rp1-cfe/cfe.h   |   43 +
>  drivers/media/platform/raspberrypi/rp1-cfe/csi2.c  |  583 +++++
>  drivers/media/platform/raspberrypi/rp1-cfe/csi2.h  |   89 +
>  drivers/media/platform/raspberrypi/rp1-cfe/dphy.c  |  175 ++
>  drivers/media/platform/raspberrypi/rp1-cfe/dphy.h  |   27 +
>  .../media/platform/raspberrypi/rp1-cfe/pisp-fe.c   |  581 +++++
>  .../media/platform/raspberrypi/rp1-cfe/pisp-fe.h   |   53 +
>  .../uapi/linux/media/raspberrypi/pisp_fe_config.h  |  273 +++
>  .../linux/media/raspberrypi/pisp_fe_statistics.h   |   64 +
>  17 files changed, 4972 insertions(+)

[snip]

> diff --git a/drivers/media/platform/raspberrypi/rp1-cfe/dphy.c b/drivers/media/platform/raspberrypi/rp1-cfe/dphy.c
> new file mode 100644
> index 000000000000..c9e4a94fb80c
> --- /dev/null
> +++ b/drivers/media/platform/raspberrypi/rp1-cfe/dphy.c
> @@ -0,0 +1,175 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * RP1 CSI-2 Driver
> + *
> + * Copyright (c) 2021-2024 Raspberry Pi Ltd.
> + * Copyright (c) 2023-2024 Ideas on Board Oy
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/pm_runtime.h>
> +
> +#include "dphy.h"
> +
> +#define dphy_dbg(fmt, arg...) dev_dbg(dphy->dev, fmt, ##arg)
> +#define dphy_err(fmt, arg...) dev_err(dphy->dev, fmt, ##arg)
> +
> +/* DW dphy Host registers */
> +#define DPHY_VERSION		0x000
> +#define DPHY_N_LANES		0x004
> +#define DPHY_RESETN		0x008
> +#define DPHY_PHY_SHUTDOWNZ	0x040
> +#define DPHY_PHY_RSTZ		0x044
> +#define DPHY_PHY_RX		0x048
> +#define	DPHY_PHY_STOPSTATE	0x04c
> +#define DPHY_PHY_TST_CTRL0	0x050
> +#define DPHY_PHY_TST_CTRL1	0x054
> +#define DPHY_PHY2_TST_CTRL0	0x058
> +#define DPHY_PHY2_TST_CTRL1	0x05c

Quoting drivers/media/platform/renesas/rcar-csi2.c:

/* V4H BASE registers */
#define V4H_N_LANES_REG                                 0x0004
#define V4H_CSI2_RESETN_REG                             0x0008
#define V4H_PHY_MODE_REG                                0x001c
#define V4H_PHY_SHUTDOWNZ_REG                           0x0040
#define V4H_DPHY_RSTZ_REG                               0x0044

Time for a common PHY driver ?

> +
> +/* DW dphy Host Transactions */
> +#define DPHY_HS_RX_CTRL_LANE0_OFFSET	0x44
> +#define DPHY_PLL_INPUT_DIV_OFFSET	0x17
> +#define DPHY_PLL_LOOP_DIV_OFFSET	0x18
> +#define DPHY_PLL_DIV_CTRL_OFFSET	0x19
> +
> +static u32 dw_csi2_host_read(struct dphy_data *dphy, u32 offset)
> +{
> +	return readl(dphy->base + offset);
> +}
> +
> +static void dw_csi2_host_write(struct dphy_data *dphy, u32 offset, u32 data)
> +{
> +	writel(data, dphy->base + offset);
> +}
> +
> +static void set_tstclr(struct dphy_data *dphy, u32 val)
> +{
> +	u32 ctrl0 = dw_csi2_host_read(dphy, DPHY_PHY_TST_CTRL0);
> +
> +	dw_csi2_host_write(dphy, DPHY_PHY_TST_CTRL0, (ctrl0 & ~1) | val);
> +}
> +
> +static void set_tstclk(struct dphy_data *dphy, u32 val)
> +{
> +	u32 ctrl0 = dw_csi2_host_read(dphy, DPHY_PHY_TST_CTRL0);
> +
> +	dw_csi2_host_write(dphy, DPHY_PHY_TST_CTRL0, (ctrl0 & ~2) | (val << 1));
> +}
> +
> +static uint8_t get_tstdout(struct dphy_data *dphy)
> +{
> +	u32 ctrl1 = dw_csi2_host_read(dphy, DPHY_PHY_TST_CTRL1);
> +
> +	return ((ctrl1 >> 8) & 0xff);
> +}
> +
> +static void set_testen(struct dphy_data *dphy, u32 val)
> +{
> +	u32 ctrl1 = dw_csi2_host_read(dphy, DPHY_PHY_TST_CTRL1);
> +
> +	dw_csi2_host_write(dphy, DPHY_PHY_TST_CTRL1,
> +			   (ctrl1 & ~(1 << 16)) | (val << 16));
> +}
> +
> +static void set_testdin(struct dphy_data *dphy, u32 val)
> +{
> +	u32 ctrl1 = dw_csi2_host_read(dphy, DPHY_PHY_TST_CTRL1);
> +
> +	dw_csi2_host_write(dphy, DPHY_PHY_TST_CTRL1, (ctrl1 & ~0xff) | val);
> +}
> +
> +static uint8_t dphy_transaction(struct dphy_data *dphy, u8 test_code,
> +				uint8_t test_data)
> +{
> +	/* See page 101 of the MIPI DPHY databook. */
> +	set_tstclk(dphy, 1);
> +	set_testen(dphy, 0);
> +	set_testdin(dphy, test_code);
> +	set_testen(dphy, 1);
> +	set_tstclk(dphy, 0);
> +	set_testen(dphy, 0);
> +	set_testdin(dphy, test_data);
> +	set_tstclk(dphy, 1);
> +	return get_tstdout(dphy);
> +}
> +
> +static void dphy_set_hsfreqrange(struct dphy_data *dphy, uint32_t mbps)
> +{
> +	/* See Table 5-1 on page 65 of dphy databook */
> +	static const u16 hsfreqrange_table[][2] = {
> +		{ 89, 0b000000 },   { 99, 0b010000 },	{ 109, 0b100000 },
> +		{ 129, 0b000001 },  { 139, 0b010001 },	{ 149, 0b100001 },
> +		{ 169, 0b000010 },  { 179, 0b010010 },	{ 199, 0b100010 },
> +		{ 219, 0b000011 },  { 239, 0b010011 },	{ 249, 0b100011 },
> +		{ 269, 0b000100 },  { 299, 0b010100 },	{ 329, 0b000101 },
> +		{ 359, 0b010101 },  { 399, 0b100101 },	{ 449, 0b000110 },
> +		{ 499, 0b010110 },  { 549, 0b000111 },	{ 599, 0b010111 },
> +		{ 649, 0b001000 },  { 699, 0b011000 },	{ 749, 0b001001 },
> +		{ 799, 0b011001 },  { 849, 0b101001 },	{ 899, 0b111001 },
> +		{ 949, 0b001010 },  { 999, 0b011010 },	{ 1049, 0b101010 },
> +		{ 1099, 0b111010 }, { 1149, 0b001011 }, { 1199, 0b011011 },
> +		{ 1249, 0b101011 }, { 1299, 0b111011 }, { 1349, 0b001100 },
> +		{ 1399, 0b011100 }, { 1449, 0b101100 }, { 1500, 0b111100 },
> +	};
> +	unsigned int i;
> +
> +	if (mbps < 80 || mbps > 1500)
> +		dphy_err("DPHY: Datarate %u Mbps out of range\n", mbps);
> +
> +	for (i = 0; i < ARRAY_SIZE(hsfreqrange_table) - 1; i++) {
> +		if (mbps <= hsfreqrange_table[i][0])
> +			break;
> +	}
> +
> +	dphy_transaction(dphy, DPHY_HS_RX_CTRL_LANE0_OFFSET,
> +			 hsfreqrange_table[i][1] << 1);
> +}
> +
> +static void dphy_init(struct dphy_data *dphy)
> +{
> +	dw_csi2_host_write(dphy, DPHY_PHY_RSTZ, 0);
> +	dw_csi2_host_write(dphy, DPHY_PHY_SHUTDOWNZ, 0);
> +	set_tstclk(dphy, 1);
> +	set_testen(dphy, 0);
> +	set_tstclr(dphy, 1);
> +	usleep_range(15, 20);
> +	set_tstclr(dphy, 0);
> +	usleep_range(15, 20);
> +
> +	dphy_set_hsfreqrange(dphy, dphy->dphy_rate);
> +
> +	usleep_range(5, 10);
> +	dw_csi2_host_write(dphy, DPHY_PHY_SHUTDOWNZ, 1);
> +	usleep_range(5, 10);
> +	dw_csi2_host_write(dphy, DPHY_PHY_RSTZ, 1);
> +}
> +
> +void dphy_start(struct dphy_data *dphy)
> +{
> +	dw_csi2_host_write(dphy, DPHY_N_LANES, (dphy->active_lanes - 1));
> +	dphy_init(dphy);
> +	dw_csi2_host_write(dphy, DPHY_RESETN, 0xffffffff);
> +	usleep_range(10, 50);
> +}
> +
> +void dphy_stop(struct dphy_data *dphy)
> +{
> +	/* Set only one lane (lane 0) as active (ON) */
> +	dw_csi2_host_write(dphy, DPHY_N_LANES, 0);
> +	dw_csi2_host_write(dphy, DPHY_RESETN, 0);
> +}
> +
> +void dphy_probe(struct dphy_data *dphy)
> +{
> +	u32 host_ver;
> +	u8 host_ver_major, host_ver_minor;
> +
> +	host_ver = dw_csi2_host_read(dphy, DPHY_VERSION);
> +	host_ver_major = (u8)((host_ver >> 24) - '0');
> +	host_ver_minor = (u8)((host_ver >> 16) - '0');
> +	host_ver_minor = host_ver_minor * 10;
> +	host_ver_minor += (u8)((host_ver >> 8) - '0');
> +
> +	dphy_dbg("DW dphy Host HW v%u.%u\n", host_ver_major, host_ver_minor);
> +}

[snip]