# CONFIG_RASPBERRYPI_GPIOMEM is not set
# CONFIG_REGULATOR_RASPBERRYPI_TOUCHSCREEN_V2 is not set
# CONFIG_SENSORS_RP1_ADC is not set
+# CONFIG_SPI_RP2040_GPIO_BRIDGE is not set
# CONFIG_VIDEO_AD5398 is not set
# CONFIG_VIDEO_ARDUCAM_64MP is not set
# CONFIG_VIDEO_ARDUCAM_PIVARIETY is not set
+++ /dev/null
-From 6aab06ff9f81e186b1a02b53b514e691472e5a61 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.com>
-Date: Tue, 7 Nov 2023 14:49:47 +0000
-Subject: [PATCH 0714/1085] spi: dw-dma: Get the last DMA scoop out of the FIFO
-
-With a DMA FIFO threshold greater than 1 (encoded as 0), it is possible
-for data in the FIFO to be inaccessible, causing the transfer to fail
-after a timeout. If the transfer includes a transmission, reduce the
-RX threshold when the TX completes, otherwise use 1 for the whole
-transfer (inefficient, but not catastrophic at SPI data rates).
-
-See: https://github.com/raspberrypi/linux/issues/5696
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.com>
----
- drivers/spi/spi-dw-dma.c | 6 +++++-
- 1 file changed, 5 insertions(+), 1 deletion(-)
-
---- a/drivers/spi/spi-dw-dma.c
-+++ b/drivers/spi/spi-dw-dma.c
-@@ -315,8 +315,10 @@ static void dw_spi_dma_tx_done(void *arg
- struct dw_spi *dws = arg;
-
- clear_bit(DW_SPI_TX_BUSY, &dws->dma_chan_busy);
-- if (test_bit(DW_SPI_RX_BUSY, &dws->dma_chan_busy))
-+ if (test_bit(DW_SPI_RX_BUSY, &dws->dma_chan_busy)) {
-+ dw_writel(dws, DW_SPI_DMARDLR, 0);
- return;
-+ }
-
- complete(&dws->dma_completion);
- }
-@@ -642,6 +644,8 @@ static int dw_spi_dma_transfer(struct dw
-
- nents = max(xfer->tx_sg.nents, xfer->rx_sg.nents);
-
-+ dw_writel(dws, DW_SPI_DMARDLR, xfer->tx_buf ? (dws->rxburst - 1) : 0);
-+
- /*
- * Execute normal DMA-based transfer (which submits the Rx and Tx SG
- * lists directly to the DMA engine at once) if either full hardware
--- /dev/null
+From 65fddc7301f52470fd846acede96d240a1902e67 Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <jonathan@raspberrypi.com>
+Date: Fri, 5 Jul 2024 14:00:38 +0100
+Subject: [PATCH 1146/1215] drivers: dwc_otg: use C11 style variable array
+ declarations
+
+The kernel C standard changed in 5.18.
+
+Remove a layer of indirection around the FIQ bounce buffers, be consistent
+with pointers to FIQ bounce buffers, and remove open-coded 32-bit clamping
+of DMA addresses.
+
+Also remove a pointless fiq_state initialisation loop.
+
+Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
+---
+ drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c | 12 ++++----
+ drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h | 8 ++---
+ drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 34 ++++++++++-----------
+ drivers/usb/host/dwc_otg/dwc_otg_hcd.h | 4 +--
+ drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 4 +--
+ 5 files changed, 28 insertions(+), 34 deletions(-)
+
+--- a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c
++++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c
+@@ -240,8 +240,8 @@ static int notrace fiq_increment_dma_buf
+ hcdma_data_t hcdma;
+ int i = st->channel[n].dma_info.index;
+ int len;
+- struct fiq_dma_blob *blob =
+- (struct fiq_dma_blob *)(uintptr_t)st->dma_base;
++ struct fiq_dma_channel *split_dma =
++ (struct fiq_dma_channel *)(uintptr_t)st->dma_base;
+
+ len = fiq_get_xfer_len(st, n);
+ fiq_print(FIQDBG_INT, st, "LEN: %03d", len);
+@@ -250,7 +250,7 @@ static int notrace fiq_increment_dma_buf
+ if (i > 6)
+ BUG();
+
+- hcdma.d32 = (u32)(uintptr_t)&blob->channel[n].index[i].buf[0];
++ hcdma.d32 = lower_32_bits((uintptr_t)&split_dma[n].index[i].buf[0]);
+ FIQ_WRITE(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HC_DMA, hcdma.d32);
+ st->channel[n].dma_info.index = i;
+ return 0;
+@@ -290,8 +290,8 @@ static int notrace fiq_iso_out_advance(s
+ hcsplt_data_t hcsplt;
+ hctsiz_data_t hctsiz;
+ hcdma_data_t hcdma;
+- struct fiq_dma_blob *blob =
+- (struct fiq_dma_blob *)(uintptr_t)st->dma_base;
++ struct fiq_dma_channel *split_dma =
++ (struct fiq_dma_channel *)(uintptr_t)st->dma_base;
+ int last = 0;
+ int i = st->channel[n].dma_info.index;
+
+@@ -303,7 +303,7 @@ static int notrace fiq_iso_out_advance(s
+ last = 1;
+
+ /* New DMA address - address of bounce buffer referred to in index */
+- hcdma.d32 = (u32)(uintptr_t)blob->channel[n].index[i].buf;
++ hcdma.d32 = lower_32_bits((uintptr_t)&split_dma[n].index[i].buf[0]);
+ //hcdma.d32 = FIQ_READ(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HC_DMA);
+ //hcdma.d32 += st->channel[n].dma_info.slot_len[i];
+ fiq_print(FIQDBG_INT, st, "LAST: %01d ", last);
+--- a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h
++++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h
+@@ -263,10 +263,6 @@ struct fiq_dma_channel {
+ struct fiq_split_dma_slot index[6];
+ } __attribute__((packed));
+
+-struct fiq_dma_blob {
+- struct fiq_dma_channel channel[0];
+-} __attribute__((packed));
+-
+ /**
+ * struct fiq_hs_isoc_info - USB2.0 isochronous data
+ * @iso_frame: Pointer to the array of OTG URB iso_frame_descs.
+@@ -352,7 +348,7 @@ struct fiq_state {
+ mphi_regs_t mphi_regs;
+ void *dwc_regs_base;
+ dma_addr_t dma_base;
+- struct fiq_dma_blob *fiq_dmab;
++ struct fiq_dma_channel *fiq_dmab;
+ void *dummy_send;
+ dma_addr_t dummy_send_dma;
+ gintmsk_data_t gintmsk_saved;
+@@ -365,7 +361,7 @@ struct fiq_state {
+ char * buffer;
+ unsigned int bufsiz;
+ #endif
+- struct fiq_channel_state channel[0];
++ struct fiq_channel_state channel[];
+ };
+
+ #ifdef CONFIG_ARM64
+--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
+@@ -58,6 +58,7 @@ static int last_sel_trans_num_avail_hc_a
+ static int last_sel_trans_num_avail_hc_at_end = 0;
+ #endif /* DEBUG_HOST_CHANNELS */
+
++static_assert(FIQ_PASSTHROUGH == 0);
+
+ dwc_otg_hcd_t *dwc_otg_hcd_alloc_hcd(void)
+ {
+@@ -876,7 +877,7 @@ void dwc_otg_hcd_power_up(void *ptr)
+ void dwc_otg_cleanup_fiq_channel(dwc_otg_hcd_t *hcd, uint32_t num)
+ {
+ struct fiq_channel_state *st = &hcd->fiq_state->channel[num];
+- struct fiq_dma_blob *blob = hcd->fiq_dmab;
++ struct fiq_dma_channel *split_dma = hcd->fiq_dmab;
+ int i;
+
+ st->fsm = FIQ_PASSTHROUGH;
+@@ -898,7 +899,7 @@ void dwc_otg_cleanup_fiq_channel(dwc_otg
+ st->hs_isoc_info.iso_desc = NULL;
+ st->hs_isoc_info.nrframes = 0;
+
+- DWC_MEMSET(&blob->channel[num].index[0], 0x6b, 1128);
++ DWC_MEMSET(&split_dma[num].index[0], 0x6b, 1128);
+ }
+
+ /**
+@@ -1045,9 +1046,6 @@ int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd
+ spin_lock_init(&hcd->fiq_state->lock);
+ #endif
+
+- for (i = 0; i < num_channels; i++) {
+- hcd->fiq_state->channel[i].fsm = FIQ_PASSTHROUGH;
+- }
+ hcd->fiq_state->dummy_send = DWC_DMA_ALLOC_ATOMIC(dev, 16,
+ &hcd->fiq_state->dummy_send_dma);
+
+@@ -1561,7 +1559,7 @@ int fiq_fsm_setup_periodic_dma(dwc_otg_h
+ int frame_length, i = 0;
+ uint8_t *ptr = NULL;
+ dwc_hc_t *hc = qh->channel;
+- struct fiq_dma_blob *blob;
++ struct fiq_dma_channel *split_dma;
+ struct dwc_otg_hcd_iso_packet_desc *frame_desc;
+
+ for (i = 0; i < 6; i++) {
+@@ -1576,10 +1574,10 @@ int fiq_fsm_setup_periodic_dma(dwc_otg_h
+ * Pointer arithmetic on hcd->fiq_state->dma_base (a dma_addr_t)
+ * to point it to the correct offset in the allocated buffers.
+ */
+- blob = (struct fiq_dma_blob *)
++ split_dma = (struct fiq_dma_channel *)
+ (uintptr_t)hcd->fiq_state->dma_base;
+- st->hcdma_copy.d32 =(u32)(uintptr_t)
+- blob->channel[hc->hc_num].index[0].buf;
++ st->hcdma_copy.d32 = lower_32_bits((uintptr_t)
++ &split_dma[hc->hc_num].index[0].buf[0]);
+
+ /* Calculate the max number of CSPLITS such that the FIQ can time out
+ * a transaction if it fails.
+@@ -1600,7 +1598,7 @@ int fiq_fsm_setup_periodic_dma(dwc_otg_h
+ frame_length = frame_desc->length;
+
+ /* Virtual address for bounce buffers */
+- blob = hcd->fiq_dmab;
++ split_dma = hcd->fiq_dmab;
+
+ ptr = qtd->urb->buf + frame_desc->offset;
+ if (frame_length == 0) {
+@@ -1613,11 +1611,11 @@ int fiq_fsm_setup_periodic_dma(dwc_otg_h
+ } else {
+ do {
+ if (frame_length <= 188) {
+- dwc_memcpy(&blob->channel[hc->hc_num].index[i].buf[0], ptr, frame_length);
++ dwc_memcpy(&split_dma[hc->hc_num].index[i].buf[0], ptr, frame_length);
+ st->dma_info.slot_len[i] = frame_length;
+ ptr += frame_length;
+ } else {
+- dwc_memcpy(&blob->channel[hc->hc_num].index[i].buf[0], ptr, 188);
++ dwc_memcpy(&split_dma[hc->hc_num].index[i].buf[0], ptr, 188);
+ st->dma_info.slot_len[i] = 188;
+ ptr += 188;
+ }
+@@ -1634,10 +1632,10 @@ int fiq_fsm_setup_periodic_dma(dwc_otg_h
+ * dma_addr_t) to point it to the correct offset in the
+ * allocated buffers.
+ */
+- blob = (struct fiq_dma_blob *)
++ split_dma = (struct fiq_dma_channel *)
+ (uintptr_t)hcd->fiq_state->dma_base;
+- st->hcdma_copy.d32 = (u32)(uintptr_t)
+- blob->channel[hc->hc_num].index[0].buf;
++ st->hcdma_copy.d32 = lower_32_bits((uintptr_t)
++ &split_dma[hc->hc_num].index[0].buf[0]);
+
+ /* fixup xfersize to the actual packet size */
+ st->hctsiz_copy.b.pid = 0;
+@@ -1917,14 +1915,14 @@ int fiq_fsm_queue_split_transaction(dwc_
+ if (hc->align_buff) {
+ st->hcdma_copy.d32 = hc->align_buff;
+ } else {
+- st->hcdma_copy.d32 = ((unsigned long) hc->xfer_buff & 0xFFFFFFFF);
++ st->hcdma_copy.d32 = lower_32_bits((uintptr_t)hc->xfer_buff);
+ }
+ }
+ } else {
+ if (hc->align_buff) {
+ st->hcdma_copy.d32 = hc->align_buff;
+ } else {
+- st->hcdma_copy.d32 = ((unsigned long) hc->xfer_buff & 0xFFFFFFFF);
++ st->hcdma_copy.d32 = lower_32_bits((uintptr_t)hc->xfer_buff);
+ }
+ }
+ /* The FIQ depends upon no other interrupts being enabled except channel halt.
+@@ -1944,7 +1942,7 @@ int fiq_fsm_queue_split_transaction(dwc_
+ if (hc->align_buff) {
+ st->hcdma_copy.d32 = hc->align_buff;
+ } else {
+- st->hcdma_copy.d32 = ((unsigned long) hc->xfer_buff & 0xFFFFFFFF);
++ st->hcdma_copy.d32 = lower_32_bits((uintptr_t)hc->xfer_buff);
+ }
+ }
+ DWC_WRITE_REG32(&hc_regs->hcdma, st->hcdma_copy.d32);
+--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.h
++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.h
+@@ -88,7 +88,7 @@ struct dwc_otg_hcd_urb {
+ uint32_t flags;
+ uint16_t interval;
+ struct dwc_otg_hcd_pipe_info pipe_info;
+- struct dwc_otg_hcd_iso_packet_desc iso_descs[0];
++ struct dwc_otg_hcd_iso_packet_desc iso_descs[];
+ };
+
+ static inline uint8_t dwc_otg_hcd_get_ep_num(struct dwc_otg_hcd_pipe_info *pipe)
+@@ -592,7 +592,7 @@ struct dwc_otg_hcd {
+ struct fiq_state *fiq_state;
+
+ /** Virtual address for split transaction DMA bounce buffers */
+- struct fiq_dma_blob *fiq_dmab;
++ struct fiq_dma_channel *fiq_dmab;
+
+ #ifdef DEBUG
+ uint32_t frrem_samples;
+--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
+@@ -2332,7 +2332,7 @@ void dwc_otg_fiq_unmangle_isoc(dwc_otg_h
+ int dwc_otg_fiq_unsetup_per_dma(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh, dwc_otg_qtd_t *qtd, uint32_t num)
+ {
+ dwc_hc_t *hc = qh->channel;
+- struct fiq_dma_blob *blob = hcd->fiq_dmab;
++ struct fiq_dma_channel *split_dma = hcd->fiq_dmab;
+ struct fiq_channel_state *st = &hcd->fiq_state->channel[num];
+ uint8_t *ptr = NULL;
+ int index = 0, len = 0;
+@@ -2352,7 +2352,7 @@ int dwc_otg_fiq_unsetup_per_dma(dwc_otg_
+
+ for (i = 0; i < st->dma_info.index; i++) {
+ len += st->dma_info.slot_len[i];
+- dwc_memcpy(ptr, &blob->channel[num].index[i].buf[0], st->dma_info.slot_len[i]);
++ dwc_memcpy(ptr, &split_dma[num].index[i].buf[0], st->dma_info.slot_len[i]);
+ ptr += st->dma_info.slot_len[i];
+ }
+ return len;
--- /dev/null
+From 8dea9155ab081289edd618f8373d5f980d5bb664 Mon Sep 17 00:00:00 2001
+From: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
+Date: Fri, 23 Feb 2024 10:40:47 +0100
+Subject: [PATCH 1147/1215] media: uapi: pixfmt-luma: Document MIPI CSI-2
+ packing
+
+The Y10P, Y12P and Y14P format variants are packed according to
+the RAW10, RAW12 and RAW14 formats as defined by the MIPI CSI-2
+specification. Document it.
+
+Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
+Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Reviewed-by: Naushir Patuck <naush@raspberrypi.com>
+---
+ Documentation/userspace-api/media/v4l/pixfmt-yuv-luma.rst | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/Documentation/userspace-api/media/v4l/pixfmt-yuv-luma.rst
++++ b/Documentation/userspace-api/media/v4l/pixfmt-yuv-luma.rst
+@@ -161,3 +161,7 @@ are often referred to as greyscale forma
+ For Y012 and Y12 formats, Y012 places its data in the 12 high bits, with
+ padding zeros in the 4 low bits, in contrast to the Y12 format, which has
+ its padding located in the most significant bits of the 16 bit word.
++
++ The 'P' variations of the Y10, Y12 and Y14 formats are packed according to
++ the RAW10, RAW12 and RAW14 packing scheme as defined by the MIPI CSI-2
++ specification.
--- /dev/null
+From 814c088cb7183f79ba68c8f9459505e2ac4dde3a Mon Sep 17 00:00:00 2001
+From: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
+Date: Fri, 26 Jan 2024 15:03:18 +0100
+Subject: [PATCH 1148/1215] media: uapi: Add a pixel format for BGR48 and RGB48
+
+Add BGR48 and RGB48 16-bit per component image formats.
+
+Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
+Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
+Reviewed-by: Naushir Patuck <naush@raspberrypi.com>
+---
+ .../userspace-api/media/v4l/pixfmt-rgb.rst | 54 +++++++++++++++++++
+ drivers/media/v4l2-core/v4l2-common.c | 2 +
+ include/uapi/linux/videodev2.h | 2 +
+ 3 files changed, 58 insertions(+)
+
+--- a/Documentation/userspace-api/media/v4l/pixfmt-rgb.rst
++++ b/Documentation/userspace-api/media/v4l/pixfmt-rgb.rst
+@@ -996,6 +996,60 @@ arranged in little endian order.
+
+ \normalsize
+
++16 Bits Per Component
++=====================
++
++These formats store an RGB triplet in six bytes, with 16 bits per component
++stored in memory in little endian byte order. They are named based on the order
++of the RGB components as stored in memory. For instance, RGB48 stores R\
++:sub:`7:0` and R\ :sub:`15:8` in bytes 0 and 1 respectively. This differs from
++the DRM format nomenclature that instead uses the order of components as seen in
++the 48-bits little endian word.
++
++.. raw:: latex
++
++ \small
++
++.. flat-table:: RGB Formats With 16 Bits Per Component
++ :header-rows: 1
++
++ * - Identifier
++ - Code
++ - Byte 0
++ - Byte 1
++ - Byte 2
++ - Byte 3
++ - Byte 4
++ - Byte 5
++
++ * .. _V4L2-PIX-FMT-BGR48:
++
++ - ``V4L2_PIX_FMT_BGR48``
++ - 'BGR6'
++
++ - B\ :sub:`7-0`
++ - B\ :sub:`15-8`
++ - G\ :sub:`7-0`
++ - G\ :sub:`15-8`
++ - R\ :sub:`7-0`
++ - R\ :sub:`15-8`
++
++ * .. _V4L2-PIX-FMT-RGB48:
++
++ - ``V4L2_PIX_FMT_RGB48``
++ - 'RGB6'
++
++ - R\ :sub:`7-0`
++ - R\ :sub:`15-8`
++ - G\ :sub:`7-0`
++ - G\ :sub:`15-8`
++ - B\ :sub:`7-0`
++ - B\ :sub:`15-8`
++
++.. raw:: latex
++
++ \normalsize
++
+ Deprecated RGB Formats
+ ======================
+
+--- a/drivers/media/v4l2-core/v4l2-common.c
++++ b/drivers/media/v4l2-core/v4l2-common.c
+@@ -253,6 +253,8 @@ const struct v4l2_format_info *v4l2_form
+ { .format = V4L2_PIX_FMT_RGB555, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_BGR666, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_BGR48_12, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
++ { .format = V4L2_PIX_FMT_BGR48, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
++ { .format = V4L2_PIX_FMT_RGB48, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_ABGR64_12, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 8, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+
+ /* YUV packed formats */
+--- a/include/uapi/linux/videodev2.h
++++ b/include/uapi/linux/videodev2.h
+@@ -587,6 +587,8 @@ struct v4l2_pix_format {
+
+ /* RGB formats (6 or 8 bytes per pixel) */
+ #define V4L2_PIX_FMT_BGR48_12 v4l2_fourcc('B', '3', '1', '2') /* 48 BGR 12-bit per component */
++#define V4L2_PIX_FMT_BGR48 v4l2_fourcc('B', 'G', 'R', '6') /* 48 BGR 16-bit per component */
++#define V4L2_PIX_FMT_RGB48 v4l2_fourcc('R', 'G', 'B', '6') /* 48 RGB 16-bit per component */
+ #define V4L2_PIX_FMT_ABGR64_12 v4l2_fourcc('B', '4', '1', '2') /* 64 BGRA 12-bit per component */
+
+ /* RGB formats (6 bytes per pixel) */
--- /dev/null
+From be6996ad702fac96b36ea209ae04a71bd1c6e1d4 Mon Sep 17 00:00:00 2001
+From: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
+Date: Fri, 24 May 2024 15:18:21 +0200
+Subject: [PATCH 1149/1215] media: uapi: Add Raspberry Pi PiSP Back End uAPI
+
+Add the Raspberry Pi PiSP Back End uAPI header.
+
+The header defines the data type used to configure the PiSP Back End
+ISP.
+
+The detailed description of the types and of the ISP configuration
+procedure is available at
+https://datasheets.raspberrypi.com/camera/raspberry-pi-image-signal-processor-specification.pdf
+
+Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
+---
+ MAINTAINERS | 7 +
+ .../linux/media/raspberrypi/pisp_be_config.h | 927 ++++++++++++++++++
+ .../linux/media/raspberrypi/pisp_common.h | 199 ++++
+ 3 files changed, 1133 insertions(+)
+ create mode 100644 include/uapi/linux/media/raspberrypi/pisp_be_config.h
+ create mode 100644 include/uapi/linux/media/raspberrypi/pisp_common.h
+
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -18032,6 +18032,13 @@ L: linux-wireless@vger.kernel.org
+ S: Orphan
+ F: drivers/net/wireless/legacy/ray*
+
++RASPBERRY PI PISP BACK END
++M: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
++L: Raspberry Pi Kernel Maintenance <kernel-list@raspberrypi.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++F: include/uapi/linux/media/raspberrypi/
++
+ RC-CORE / LIRC FRAMEWORK
+ M: Sean Young <sean@mess.org>
+ L: linux-media@vger.kernel.org
+--- /dev/null
++++ b/include/uapi/linux/media/raspberrypi/pisp_be_config.h
+@@ -0,0 +1,927 @@
++/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
++/*
++ * PiSP Back End configuration definitions.
++ *
++ * Copyright (C) 2021 - Raspberry Pi Ltd
++ *
++ */
++#ifndef _UAPI_PISP_BE_CONFIG_H_
++#define _UAPI_PISP_BE_CONFIG_H_
++
++#include <linux/types.h>
++
++#include "pisp_common.h"
++
++/* byte alignment for inputs */
++#define PISP_BACK_END_INPUT_ALIGN 4u
++/* alignment for compressed inputs */
++#define PISP_BACK_END_COMPRESSED_ALIGN 8u
++/* minimum required byte alignment for outputs */
++#define PISP_BACK_END_OUTPUT_MIN_ALIGN 16u
++/* preferred byte alignment for outputs */
++#define PISP_BACK_END_OUTPUT_MAX_ALIGN 64u
++
++/* minimum allowed tile width anywhere in the pipeline */
++#define PISP_BACK_END_MIN_TILE_WIDTH 16u
++/* minimum allowed tile width anywhere in the pipeline */
++#define PISP_BACK_END_MIN_TILE_HEIGHT 16u
++
++#define PISP_BACK_END_NUM_OUTPUTS 2
++#define PISP_BACK_END_HOG_OUTPUT 1
++
++#define PISP_BACK_END_NUM_TILES 64
++
++enum pisp_be_bayer_enable {
++ PISP_BE_BAYER_ENABLE_INPUT = 0x000001,
++ PISP_BE_BAYER_ENABLE_DECOMPRESS = 0x000002,
++ PISP_BE_BAYER_ENABLE_DPC = 0x000004,
++ PISP_BE_BAYER_ENABLE_GEQ = 0x000008,
++ PISP_BE_BAYER_ENABLE_TDN_INPUT = 0x000010,
++ PISP_BE_BAYER_ENABLE_TDN_DECOMPRESS = 0x000020,
++ PISP_BE_BAYER_ENABLE_TDN = 0x000040,
++ PISP_BE_BAYER_ENABLE_TDN_COMPRESS = 0x000080,
++ PISP_BE_BAYER_ENABLE_TDN_OUTPUT = 0x000100,
++ PISP_BE_BAYER_ENABLE_SDN = 0x000200,
++ PISP_BE_BAYER_ENABLE_BLC = 0x000400,
++ PISP_BE_BAYER_ENABLE_STITCH_INPUT = 0x000800,
++ PISP_BE_BAYER_ENABLE_STITCH_DECOMPRESS = 0x001000,
++ PISP_BE_BAYER_ENABLE_STITCH = 0x002000,
++ PISP_BE_BAYER_ENABLE_STITCH_COMPRESS = 0x004000,
++ PISP_BE_BAYER_ENABLE_STITCH_OUTPUT = 0x008000,
++ PISP_BE_BAYER_ENABLE_WBG = 0x010000,
++ PISP_BE_BAYER_ENABLE_CDN = 0x020000,
++ PISP_BE_BAYER_ENABLE_LSC = 0x040000,
++ PISP_BE_BAYER_ENABLE_TONEMAP = 0x080000,
++ PISP_BE_BAYER_ENABLE_CAC = 0x100000,
++ PISP_BE_BAYER_ENABLE_DEBIN = 0x200000,
++ PISP_BE_BAYER_ENABLE_DEMOSAIC = 0x400000,
++};
++
++enum pisp_be_rgb_enable {
++ PISP_BE_RGB_ENABLE_INPUT = 0x000001,
++ PISP_BE_RGB_ENABLE_CCM = 0x000002,
++ PISP_BE_RGB_ENABLE_SAT_CONTROL = 0x000004,
++ PISP_BE_RGB_ENABLE_YCBCR = 0x000008,
++ PISP_BE_RGB_ENABLE_FALSE_COLOUR = 0x000010,
++ PISP_BE_RGB_ENABLE_SHARPEN = 0x000020,
++ /* Preferred colours would occupy 0x000040 */
++ PISP_BE_RGB_ENABLE_YCBCR_INVERSE = 0x000080,
++ PISP_BE_RGB_ENABLE_GAMMA = 0x000100,
++ PISP_BE_RGB_ENABLE_CSC0 = 0x000200,
++ PISP_BE_RGB_ENABLE_CSC1 = 0x000400,
++ PISP_BE_RGB_ENABLE_DOWNSCALE0 = 0x001000,
++ PISP_BE_RGB_ENABLE_DOWNSCALE1 = 0x002000,
++ PISP_BE_RGB_ENABLE_RESAMPLE0 = 0x008000,
++ PISP_BE_RGB_ENABLE_RESAMPLE1 = 0x010000,
++ PISP_BE_RGB_ENABLE_OUTPUT0 = 0x040000,
++ PISP_BE_RGB_ENABLE_OUTPUT1 = 0x080000,
++ PISP_BE_RGB_ENABLE_HOG = 0x200000
++};
++
++#define PISP_BE_RGB_ENABLE_CSC(i) (PISP_BE_RGB_ENABLE_CSC0 << (i))
++#define PISP_BE_RGB_ENABLE_DOWNSCALE(i) (PISP_BE_RGB_ENABLE_DOWNSCALE0 << (i))
++#define PISP_BE_RGB_ENABLE_RESAMPLE(i) (PISP_BE_RGB_ENABLE_RESAMPLE0 << (i))
++#define PISP_BE_RGB_ENABLE_OUTPUT(i) (PISP_BE_RGB_ENABLE_OUTPUT0 << (i))
++
++/*
++ * We use the enable flags to show when blocks are "dirty", but we need some
++ * extra ones too.
++ */
++enum pisp_be_dirty {
++ PISP_BE_DIRTY_GLOBAL = 0x0001,
++ PISP_BE_DIRTY_SH_FC_COMBINE = 0x0002,
++ PISP_BE_DIRTY_CROP = 0x0004
++};
++
++/**
++ * struct pisp_be_global_config - PiSP global enable bitmaps
++ * @bayer_enables: Bayer input enable flags
++ * @rgb_enables: RGB output enable flags
++ * @bayer_order: Bayer input format ordering
++ * @pad: Padding bytes
++ */
++struct pisp_be_global_config {
++ __u32 bayer_enables;
++ __u32 rgb_enables;
++ __u8 bayer_order;
++ __u8 pad[3];
++} __attribute__((packed));
++
++/**
++ * struct pisp_be_input_buffer_config - PiSP Back End input buffer
++ * @addr: Input buffer address
++ */
++struct pisp_be_input_buffer_config {
++ /* low 32 bits followed by high 32 bits (for each of up to 3 planes) */
++ __u32 addr[3][2];
++} __attribute__((packed));
++
++/**
++ * struct pisp_be_dpc_config - PiSP Back End DPC config
++ *
++ * Defective Pixel Correction configuration
++ *
++ * @coeff_level: Coefficient for the darkest neighbouring pixel value
++ * @coeff_range: Coefficient for the range of pixels for this Bayer channel
++ * @pad: Padding byte
++ * @flags: DPC configuration flags
++ */
++struct pisp_be_dpc_config {
++ __u8 coeff_level;
++ __u8 coeff_range;
++ __u8 pad;
++#define PISP_BE_DPC_FLAG_FOLDBACK 1
++ __u8 flags;
++} __attribute__((packed));
++
++/**
++ * struct pisp_be_geq_config - PiSP Back End GEQ config
++ *
++ * Green Equalisation configuration
++ *
++ * @offset: Offset value for threshold calculation
++ * @slope_sharper: Slope/Sharper configuration
++ * @min: Minimum value the threshold may have
++ * @max: Maximum value the threshold may have
++ */
++struct pisp_be_geq_config {
++ __u16 offset;
++#define PISP_BE_GEQ_SHARPER BIT(15)
++#define PISP_BE_GEQ_SLOPE ((1 << 10) - 1)
++ /* top bit is the "sharper" flag, slope value is bottom 10 bits */
++ __u16 slope_sharper;
++ __u16 min;
++ __u16 max;
++} __attribute__((packed));
++
++/**
++ * struct pisp_be_tdn_input_buffer_config - PiSP Back End TDN input buffer
++ * @addr: TDN input buffer address
++ */
++struct pisp_be_tdn_input_buffer_config {
++ /* low 32 bits followed by high 32 bits */
++ __u32 addr[2];
++} __attribute__((packed));
++
++/**
++ * struct pisp_be_tdn_config - PiSP Back End TDN config
++ *
++ * Temporal Denoise configuration
++ *
++ * @black_level: Black level value subtracted from pixels
++ * @ratio: Multiplier for the LTA input frame
++ * @noise_constant: Constant offset value used in noise estimation
++ * @noise_slope: Noise estimation multiplier
++ * @threshold: Threshold for TDN operations
++ * @reset: Disable TDN operations
++ * @pad: Padding byte
++ */
++struct pisp_be_tdn_config {
++ __u16 black_level;
++ __u16 ratio;
++ __u16 noise_constant;
++ __u16 noise_slope;
++ __u16 threshold;
++ __u8 reset;
++ __u8 pad;
++} __attribute__((packed));
++
++/**
++ * struct pisp_be_tdn_output_buffer_config - PiSP Back End TDN output buffer
++ * @addr: TDN output buffer address
++ */
++struct pisp_be_tdn_output_buffer_config {
++ /* low 32 bits followed by high 32 bits */
++ __u32 addr[2];
++} __attribute__((packed));
++
++/**
++ * struct pisp_be_sdn_config - PiSP Back End SDN config
++ *
++ * Spatial Denoise configuration
++ *
++ * @black_level: Black level subtracted from pixel for noise estimation
++ * @leakage: Proportion of the original undenoised value to mix in
++ * denoised output
++ * @pad: Padding byte
++ * @noise_constant: Noise constant used for noise estimation
++ * @noise_slope: Noise slope value used for noise estimation
++ * @noise_constant2: Second noise constant used for noise estimation
++ * @noise_slope2: Second slope value used for noise estimation
++ */
++struct pisp_be_sdn_config {
++ __u16 black_level;
++ __u8 leakage;
++ __u8 pad;
++ __u16 noise_constant;
++ __u16 noise_slope;
++ __u16 noise_constant2;
++ __u16 noise_slope2;
++} __attribute__((packed));
++
++/**
++ * struct pisp_be_stitch_input_buffer_config - PiSP Back End Stitch input
++ * @addr: Stitch input buffer address
++ */
++struct pisp_be_stitch_input_buffer_config {
++ /* low 32 bits followed by high 32 bits */
++ __u32 addr[2];
++} __attribute__((packed));
++
++#define PISP_BE_STITCH_STREAMING_LONG 0x8000
++#define PISP_BE_STITCH_EXPOSURE_RATIO_MASK 0x7fff
++
++/**
++ * struct pisp_be_stitch_config - PiSP Back End Stitch config
++ *
++ * Stitch block configuration
++ *
++ * @threshold_lo: Low threshold value
++ * @threshold_diff_power: Low and high threshold difference
++ * @pad: Padding bytes
++ * @exposure_ratio: Multiplier to convert long exposure pixels into
++ * short exposure pixels
++ * @motion_threshold_256: Motion threshold above which short exposure
++ * pixels are used
++ * @motion_threshold_recip: Reciprocal of motion_threshold_256 value
++ */
++struct pisp_be_stitch_config {
++ __u16 threshold_lo;
++ __u8 threshold_diff_power;
++ __u8 pad;
++
++ /* top bit indicates whether streaming input is the long exposure */
++ __u16 exposure_ratio;
++
++ __u8 motion_threshold_256;
++ __u8 motion_threshold_recip;
++} __attribute__((packed));
++
++/**
++ * struct pisp_be_stitch_output_buffer_config - PiSP Back End Stitch output
++ * @addr: Stitch input buffer address
++ */
++struct pisp_be_stitch_output_buffer_config {
++ /* low 32 bits followed by high 32 bits */
++ __u32 addr[2];
++} __attribute__((packed));
++
++/**
++ * struct pisp_be_cdn_config - PiSP Back End CDN config
++ *
++ * Colour Denoise configuration
++ *
++ * @thresh: Constant for noise estimation
++ * @iir_strength: Relative strength of the IIR part of the filter
++ * @g_adjust: Proportion of the change assigned to the G channel
++ */
++struct pisp_be_cdn_config {
++ __u16 thresh;
++ __u8 iir_strength;
++ __u8 g_adjust;
++} __attribute__((packed));
++
++#define PISP_BE_LSC_LOG_GRID_SIZE 5
++#define PISP_BE_LSC_GRID_SIZE (1 << PISP_BE_LSC_LOG_GRID_SIZE)
++#define PISP_BE_LSC_STEP_PRECISION 18
++
++/**
++ * struct pisp_be_lsc_config - PiSP Back End LSC config
++ *
++ * Lens Shading Correction configuration
++ *
++ * @grid_step_x: Reciprocal of cell size width
++ * @grid_step_y: Reciprocal of cell size height
++ * @lut_packed: Jointly-coded RGB gains for each LSC grid
++ */
++struct pisp_be_lsc_config {
++ /* (1<<18) / grid_cell_width */
++ __u16 grid_step_x;
++ /* (1<<18) / grid_cell_height */
++ __u16 grid_step_y;
++ /* RGB gains jointly encoded in 32 bits */
++#define PISP_BE_LSC_LUT_SIZE (PISP_BE_LSC_GRID_SIZE + 1)
++ __u32 lut_packed[PISP_BE_LSC_LUT_SIZE][PISP_BE_LSC_LUT_SIZE];
++} __attribute__((packed));
++
++/**
++ * struct pisp_be_lsc_extra - PiSP Back End LSC Extra config
++ * @offset_x: Horizontal offset into the LSC table of this tile
++ * @offset_y: Vertical offset into the LSC table of this tile
++ */
++struct pisp_be_lsc_extra {
++ __u16 offset_x;
++ __u16 offset_y;
++} __attribute__((packed));
++
++#define PISP_BE_CAC_LOG_GRID_SIZE 3
++#define PISP_BE_CAC_GRID_SIZE (1 << PISP_BE_CAC_LOG_GRID_SIZE)
++#define PISP_BE_CAC_STEP_PRECISION 20
++
++/**
++ * struct pisp_be_cac_config - PiSP Back End CAC config
++ *
++ * Chromatic Aberration Correction config
++ *
++ * @grid_step_x: Reciprocal of cell size width
++ * @grid_step_y: Reciprocal of cell size height
++ * @lut: Pixel shift for the CAC grid
++ */
++struct pisp_be_cac_config {
++ /* (1<<20) / grid_cell_width */
++ __u16 grid_step_x;
++ /* (1<<20) / grid_cell_height */
++ __u16 grid_step_y;
++ /* [gridy][gridx][rb][xy] */
++#define PISP_BE_CAC_LUT_SIZE (PISP_BE_CAC_GRID_SIZE + 1)
++ __s8 lut[PISP_BE_CAC_LUT_SIZE][PISP_BE_CAC_LUT_SIZE][2][2];
++} __attribute__((packed));
++
++/**
++ * struct pisp_be_cac_extra - PiSP Back End CAC extra config
++ * @offset_x: Horizontal offset into the CAC table of this tile
++ * @offset_y: Horizontal offset into the CAC table of this tile
++ */
++struct pisp_be_cac_extra {
++ __u16 offset_x;
++ __u16 offset_y;
++} __attribute__((packed));
++
++#define PISP_BE_DEBIN_NUM_COEFFS 4
++
++/**
++ * struct pisp_be_debin_config - PiSP Back End Debin config
++ *
++ * Debinning configuration
++ *
++ * @coeffs: Filter coefficients for debinning
++ * @h_enable: Horizontal debinning enable
++ * @v_enable: Vertical debinning enable
++ * @pad: Padding bytes
++ */
++struct pisp_be_debin_config {
++ __s8 coeffs[PISP_BE_DEBIN_NUM_COEFFS];
++ __s8 h_enable;
++ __s8 v_enable;
++ __s8 pad[2];
++} __attribute__((packed));
++
++#define PISP_BE_TONEMAP_LUT_SIZE 64
++
++/**
++ * struct pisp_be_tonemap_config - PiSP Back End Tonemap config
++ *
++ * Tonemapping configuration
++ *
++ * @detail_constant: Constant value for threshold calculation
++ * @detail_slope: Slope value for threshold calculation
++ * @iir_strength: Relative strength of the IIR fiter
++ * @strength: Strength factor
++ * @lut: Look-up table for tonemap curve
++ */
++struct pisp_be_tonemap_config {
++ __u16 detail_constant;
++ __u16 detail_slope;
++ __u16 iir_strength;
++ __u16 strength;
++ __u32 lut[PISP_BE_TONEMAP_LUT_SIZE];
++} __attribute__((packed));
++
++/**
++ * struct pisp_be_demosaic_config - PiSP Back End Demosaic config
++ *
++ * Demosaic configuration
++ *
++ * @sharper: Use other Bayer channels to increase sharpness
++ * @fc_mode: Built-in false colour suppression mode
++ * @pad: Padding bytes
++ */
++struct pisp_be_demosaic_config {
++ __u8 sharper;
++ __u8 fc_mode;
++ __u8 pad[2];
++} __attribute__((packed));
++
++/**
++ * struct pisp_be_ccm_config - PiSP Back End CCM config
++ *
++ * Colour Correction Matrix configuration
++ *
++ * @coeffs: Matrix coefficients
++ * @pad: Padding bytes
++ * @offsets: Offsets triplet
++ */
++struct pisp_be_ccm_config {
++ __s16 coeffs[9];
++ __u8 pad[2];
++ __s32 offsets[3];
++} __attribute__((packed));
++
++/**
++ * struct pisp_be_sat_control_config - PiSP Back End SAT config
++ *
++ * Saturation Control configuration
++ *
++ * @shift_r: Left shift for Red colour channel
++ * @shift_g: Left shift for Green colour channel
++ * @shift_b: Left shift for Blue colour channel
++ * @pad: Padding byte
++ */
++struct pisp_be_sat_control_config {
++ __u8 shift_r;
++ __u8 shift_g;
++ __u8 shift_b;
++ __u8 pad;
++} __attribute__((packed));
++
++/**
++ * struct pisp_be_false_colour_config - PiSP Back End False Colour config
++ *
++ * False Colour configuration
++ *
++ * @distance: Distance of neighbouring pixels, either 1 or 2
++ * @pad: Padding bytes
++ */
++struct pisp_be_false_colour_config {
++ __u8 distance;
++ __u8 pad[3];
++} __attribute__((packed));
++
++#define PISP_BE_SHARPEN_SIZE 5
++#define PISP_BE_SHARPEN_FUNC_NUM_POINTS 9
++
++/**
++ * struct pisp_be_sharpen_config - PiSP Back End Sharpening config
++ *
++ * Sharpening configuration
++ *
++ * @kernel0: Coefficient for filter 0
++ * @pad0: Padding byte
++ * @kernel1: Coefficient for filter 1
++ * @pad1: Padding byte
++ * @kernel2: Coefficient for filter 2
++ * @pad2: Padding byte
++ * @kernel3: Coefficient for filter 3
++ * @pad3: Padding byte
++ * @kernel4: Coefficient for filter 4
++ * @pad4: Padding byte
++ * @threshold_offset0: Offset for filter 0 response calculation
++ * @threshold_slope0: Slope multiplier for the filter 0 response calculation
++ * @scale0: Scale factor for filter 0 response calculation
++ * @pad5: Padding byte
++ * @threshold_offset1: Offset for filter 0 response calculation
++ * @threshold_slope1: Slope multiplier for the filter 0 response calculation
++ * @scale1: Scale factor for filter 0 response calculation
++ * @pad6: Padding byte
++ * @threshold_offset2: Offset for filter 0 response calculation
++ * @threshold_slope2: Slope multiplier for the filter 0 response calculation
++ * @scale2: Scale factor for filter 0 response calculation
++ * @pad7: Padding byte
++ * @threshold_offset3: Offset for filter 0 response calculation
++ * @threshold_slope3: Slope multiplier for the filter 0 response calculation
++ * @scale3: Scale factor for filter 0 response calculation
++ * @pad8: Padding byte
++ * @threshold_offset4: Offset for filter 0 response calculation
++ * @threshold_slope4: Slope multiplier for the filter 0 response calculation
++ * @scale4: Scale factor for filter 0 response calculation
++ * @pad9: Padding byte
++ * @positive_strength: Factor to scale the positive sharpening strength
++ * @positive_pre_limit: Maximum allowed possible positive sharpening value
++ * @positive_func: Gain factor applied to positive sharpening response
++ * @positive_limit: Final gain factor applied to positive sharpening
++ * @negative_strength: Factor to scale the negative sharpening strength
++ * @negative_pre_limit: Maximum allowed possible negative sharpening value
++ * @negative_func: Gain factor applied to negative sharpening response
++ * @negative_limit: Final gain factor applied to negative sharpening
++ * @enables: Filter enable mask
++ * @white: White output pixel filter mask
++ * @black: Black output pixel filter mask
++ * @grey: Grey output pixel filter mask
++ */
++struct pisp_be_sharpen_config {
++ __s8 kernel0[PISP_BE_SHARPEN_SIZE * PISP_BE_SHARPEN_SIZE];
++ __s8 pad0[3];
++ __s8 kernel1[PISP_BE_SHARPEN_SIZE * PISP_BE_SHARPEN_SIZE];
++ __s8 pad1[3];
++ __s8 kernel2[PISP_BE_SHARPEN_SIZE * PISP_BE_SHARPEN_SIZE];
++ __s8 pad2[3];
++ __s8 kernel3[PISP_BE_SHARPEN_SIZE * PISP_BE_SHARPEN_SIZE];
++ __s8 pad3[3];
++ __s8 kernel4[PISP_BE_SHARPEN_SIZE * PISP_BE_SHARPEN_SIZE];
++ __s8 pad4[3];
++ __u16 threshold_offset0;
++ __u16 threshold_slope0;
++ __u16 scale0;
++ __u16 pad5;
++ __u16 threshold_offset1;
++ __u16 threshold_slope1;
++ __u16 scale1;
++ __u16 pad6;
++ __u16 threshold_offset2;
++ __u16 threshold_slope2;
++ __u16 scale2;
++ __u16 pad7;
++ __u16 threshold_offset3;
++ __u16 threshold_slope3;
++ __u16 scale3;
++ __u16 pad8;
++ __u16 threshold_offset4;
++ __u16 threshold_slope4;
++ __u16 scale4;
++ __u16 pad9;
++ __u16 positive_strength;
++ __u16 positive_pre_limit;
++ __u16 positive_func[PISP_BE_SHARPEN_FUNC_NUM_POINTS];
++ __u16 positive_limit;
++ __u16 negative_strength;
++ __u16 negative_pre_limit;
++ __u16 negative_func[PISP_BE_SHARPEN_FUNC_NUM_POINTS];
++ __u16 negative_limit;
++ __u8 enables;
++ __u8 white;
++ __u8 black;
++ __u8 grey;
++} __attribute__((packed));
++
++/**
++ * struct pisp_be_sh_fc_combine_config - PiSP Back End Sharpening and
++ * False Colour config
++ *
++ * Sharpening and False Colour configuration
++ *
++ * @y_factor: Control amount of desaturation of pixels being darkened
++ * @c1_factor: Control amount of brightening of a pixel for the Cb
++ * channel
++ * @c2_factor: Control amount of brightening of a pixel for the Cr
++ * channel
++ * @pad: Padding byte
++ */
++struct pisp_be_sh_fc_combine_config {
++ __u8 y_factor;
++ __u8 c1_factor;
++ __u8 c2_factor;
++ __u8 pad;
++} __attribute__((packed));
++
++#define PISP_BE_GAMMA_LUT_SIZE 64
++
++/**
++ * struct pisp_be_gamma_config - PiSP Back End Gamma configuration
++ * @lut: Gamma curve look-up table
++ */
++struct pisp_be_gamma_config {
++ __u32 lut[PISP_BE_GAMMA_LUT_SIZE];
++} __attribute__((packed));
++
++/**
++ * struct pisp_be_crop_config - PiSP Back End Crop config
++ *
++ * Crop configuration
++ *
++ * @offset_x: Number of pixels cropped from the left of the tile
++ * @offset_y: Number of pixels cropped from the top of the tile
++ * @width: Width of the cropped tile output
++ * @height: Height of the cropped tile output
++ */
++struct pisp_be_crop_config {
++ __u16 offset_x, offset_y;
++ __u16 width, height;
++} __attribute__((packed));
++
++#define PISP_BE_RESAMPLE_FILTER_SIZE 96
++
++/**
++ * struct pisp_be_resample_config - PiSP Back End Resampling config
++ *
++ * Resample configuration
++ *
++ * @scale_factor_h: Horizontal scale factor
++ * @scale_factor_v: Vertical scale factor
++ * @coef: Resample coefficients
++ */
++struct pisp_be_resample_config {
++ __u16 scale_factor_h, scale_factor_v;
++ __s16 coef[PISP_BE_RESAMPLE_FILTER_SIZE];
++} __attribute__((packed));
++
++/**
++ * struct pisp_be_resample_extra - PiSP Back End Resample config
++ *
++ * Resample configuration
++ *
++ * @scaled_width: Width in pixels of the scaled output
++ * @scaled_height: Height in pixels of the scaled output
++ * @initial_phase_h: Initial horizontal phase
++ * @initial_phase_v: Initial vertical phase
++ */
++struct pisp_be_resample_extra {
++ __u16 scaled_width;
++ __u16 scaled_height;
++ __s16 initial_phase_h[3];
++ __s16 initial_phase_v[3];
++} __attribute__((packed));
++
++/**
++ * struct pisp_be_downscale_config - PiSP Back End Downscale config
++ *
++ * Downscale configuration
++ *
++ * @scale_factor_h: Horizontal scale factor
++ * @scale_factor_v: Vertical scale factor
++ * @scale_recip_h: Horizontal reciprocal factor
++ * @scale_recip_v: Vertical reciprocal factor
++ */
++struct pisp_be_downscale_config {
++ __u16 scale_factor_h;
++ __u16 scale_factor_v;
++ __u16 scale_recip_h;
++ __u16 scale_recip_v;
++} __attribute__((packed));
++
++/**
++ * struct pisp_be_downscale_extra - PiSP Back End Downscale Extra config
++ * @scaled_width: Scaled image width
++ * @scaled_height: Scaled image height
++ */
++struct pisp_be_downscale_extra {
++ __u16 scaled_width;
++ __u16 scaled_height;
++} __attribute__((packed));
++
++/**
++ * struct pisp_be_hog_config - PiSP Back End HOG config
++ *
++ * Histogram of Oriented Gradients configuration
++ *
++ * @compute_signed: Set 0 for unsigned gradients, 1 for signed
++ * @channel_mix: Channels proportions to use
++ * @stride: Stride in bytes between blocks directly below
++ */
++struct pisp_be_hog_config {
++ __u8 compute_signed;
++ __u8 channel_mix[3];
++ __u32 stride;
++} __attribute__((packed));
++
++struct pisp_be_axi_config {
++ __u8 r_qos; /* Read QoS */
++ __u8 r_cache_prot; /* Read { prot[2:0], cache[3:0] } */
++ __u8 w_qos; /* Write QoS */
++ __u8 w_cache_prot; /* Write { prot[2:0], cache[3:0] } */
++} __attribute__((packed));
++
++/**
++ * enum pisp_be_transform - PiSP Back End Transform flags
++ * @PISP_BE_TRANSFORM_NONE: No transform
++ * @PISP_BE_TRANSFORM_HFLIP: Horizontal flip
++ * @PISP_BE_TRANSFORM_VFLIP: Vertical flip
++ * @PISP_BE_TRANSFORM_ROT180: 180 degress rotation
++ */
++enum pisp_be_transform {
++ PISP_BE_TRANSFORM_NONE = 0x0,
++ PISP_BE_TRANSFORM_HFLIP = 0x1,
++ PISP_BE_TRANSFORM_VFLIP = 0x2,
++ PISP_BE_TRANSFORM_ROT180 =
++ (PISP_BE_TRANSFORM_HFLIP | PISP_BE_TRANSFORM_VFLIP)
++};
++
++struct pisp_be_output_format_config {
++ struct pisp_image_format_config image;
++ __u8 transform;
++ __u8 pad[3];
++ __u16 lo;
++ __u16 hi;
++ __u16 lo2;
++ __u16 hi2;
++} __attribute__((packed));
++
++/**
++ * struct pisp_be_output_buffer_config - PiSP Back End Output buffer
++ * @addr: Output buffer address
++ */
++struct pisp_be_output_buffer_config {
++ /* low 32 bits followed by high 32 bits (for each of 3 planes) */
++ __u32 addr[3][2];
++} __attribute__((packed));
++
++/**
++ * struct pisp_be_hog_buffer_config - PiSP Back End HOG buffer
++ * @addr: HOG buffer address
++ */
++struct pisp_be_hog_buffer_config {
++ /* low 32 bits followed by high 32 bits */
++ __u32 addr[2];
++} __attribute__((packed));
++
++/**
++ * struct pisp_be_config - RaspberryPi PiSP Back End Processing configuration
++ *
++ * @global: Global PiSP configuration
++ * @input_format: Input image format
++ * @decompress: Decompress configuration
++ * @dpc: Defective Pixel Correction configuration
++ * @geq: Green Equalisation configuration
++ * @tdn_input_format: Temporal Denoise input format
++ * @tdn_decompress: Temporal Denoise decompress configuration
++ * @tdn: Temporal Denoise configuration
++ * @tdn_compress: Temporal Denoise compress configuration
++ * @tdn_output_format: Temporal Denoise output format
++ * @sdn: Spatial Denoise configuration
++ * @blc: Black Level Correction configuration
++ * @stitch_compress: Stitch compress configuration
++ * @stitch_output_format: Stitch output format
++ * @stitch_input_format: Stitch input format
++ * @stitch_decompress: Stitch decompress configuration
++ * @stitch: Stitch configuration
++ * @lsc: Lens Shading Correction configuration
++ * @wbg: White Balance Gain configuration
++ * @cdn: Colour Denoise configuration
++ * @cac: Colour Aberration Correction configuration
++ * @debin: Debinning configuration
++ * @tonemap: Tonemapping configuration
++ * @demosaic: Demosaicing configuration
++ * @ccm: Colour Correction Matrix configuration
++ * @sat_control: Saturation Control configuration
++ * @ycbcr: YCbCr colour correction configuration
++ * @sharpen: Sharpening configuration
++ * @false_colour: False colour correction
++ * @sh_fc_combine: Sharpening and False Colour correction
++ * @ycbcr_inverse: Inverse YCbCr colour correction
++ * @gamma: Gamma curve configuration
++ * @csc: Color Space Conversion configuration
++ * @downscale: Downscale configuration
++ * @resample: Resampling configuration
++ * @output_format: Output format configuration
++ * @hog: HOG configuration
++ */
++struct pisp_be_config {
++ struct pisp_be_global_config global;
++ struct pisp_image_format_config input_format;
++ struct pisp_decompress_config decompress;
++ struct pisp_be_dpc_config dpc;
++ struct pisp_be_geq_config geq;
++ struct pisp_image_format_config tdn_input_format;
++ struct pisp_decompress_config tdn_decompress;
++ struct pisp_be_tdn_config tdn;
++ struct pisp_compress_config tdn_compress;
++ struct pisp_image_format_config tdn_output_format;
++ struct pisp_be_sdn_config sdn;
++ struct pisp_bla_config blc;
++ struct pisp_compress_config stitch_compress;
++ struct pisp_image_format_config stitch_output_format;
++ struct pisp_image_format_config stitch_input_format;
++ struct pisp_decompress_config stitch_decompress;
++ struct pisp_be_stitch_config stitch;
++ struct pisp_be_lsc_config lsc;
++ struct pisp_wbg_config wbg;
++ struct pisp_be_cdn_config cdn;
++ struct pisp_be_cac_config cac;
++ struct pisp_be_debin_config debin;
++ struct pisp_be_tonemap_config tonemap;
++ struct pisp_be_demosaic_config demosaic;
++ struct pisp_be_ccm_config ccm;
++ struct pisp_be_sat_control_config sat_control;
++ struct pisp_be_ccm_config ycbcr;
++ struct pisp_be_sharpen_config sharpen;
++ struct pisp_be_false_colour_config false_colour;
++ struct pisp_be_sh_fc_combine_config sh_fc_combine;
++ struct pisp_be_ccm_config ycbcr_inverse;
++ struct pisp_be_gamma_config gamma;
++ struct pisp_be_ccm_config csc[PISP_BACK_END_NUM_OUTPUTS];
++ struct pisp_be_downscale_config downscale[PISP_BACK_END_NUM_OUTPUTS];
++ struct pisp_be_resample_config resample[PISP_BACK_END_NUM_OUTPUTS];
++ struct pisp_be_output_format_config
++ output_format[PISP_BACK_END_NUM_OUTPUTS];
++ struct pisp_be_hog_config hog;
++} __attribute__((packed));
++
++/**
++ * enum pisp_tile_edge - PiSP Back End Tile position
++ * @PISP_LEFT_EDGE: Left edge tile
++ * @PISP_RIGHT_EDGE: Right edge tile
++ * @PISP_TOP_EDGE: Top edge tile
++ * @PISP_BOTTOM_EDGE: Bottom edge tile
++ */
++enum pisp_tile_edge {
++ PISP_LEFT_EDGE = (1 << 0),
++ PISP_RIGHT_EDGE = (1 << 1),
++ PISP_TOP_EDGE = (1 << 2),
++ PISP_BOTTOM_EDGE = (1 << 3)
++};
++
++/**
++ * struct pisp_tile - Raspberry Pi PiSP Back End tile configuration
++ *
++ * Tile parameters: each set of tile parameters is a 160-bytes block of data
++ * which contains the tile processing parameters.
++ *
++ * @edge: Edge tile flag
++ * @pad0: Padding bytes
++ * @input_addr_offset: Top-left pixel offset, in bytes
++ * @input_addr_offset2: Top-left pixel offset, in bytes for the second/
++ * third image planes
++ * @input_offset_x: Horizontal offset in pixels of this tile in the
++ * input image
++ * @input_offset_y: Vertical offset in pixels of this tile in the
++ * input image
++ * @input_width: Width in pixels of this tile
++ * @input_height: Height in pixels of the this tile
++ * @tdn_input_addr_offset: TDN input image offset, in bytes
++ * @tdn_output_addr_offset: TDN output image offset, in bytes
++ * @stitch_input_addr_offset: Stitch input image offset, in bytes
++ * @stitch_output_addr_offset: Stitch output image offset, in bytes
++ * @lsc_grid_offset_x: Horizontal offset in the LSC table for this tile
++ * @lsc_grid_offset_y: Vertical offset in the LSC table for this tile
++ * @cac_grid_offset_x: Horizontal offset in the CAC table for this tile
++ * @cac_grid_offset_y: Horizontal offset in the CAC table for this tile
++ * @crop_x_start: Number of pixels cropped from the left of the
++ * tile
++ * @crop_x_end: Number of pixels cropped from the right of the
++ * tile
++ * @crop_y_start: Number of pixels cropped from the top of the
++ * tile
++ * @crop_y_end: Number of pixels cropped from the bottom of the
++ * tile
++ * @downscale_phase_x: Initial horizontal phase in pixels
++ * @downscale_phase_y: Initial vertical phase in pixels
++ * @resample_in_width: Width in pixels of the tile entering the
++ * Resample block
++ * @resample_in_height: Height in pixels of the tile entering the
++ * Resample block
++ * @resample_phase_x: Initial horizontal phase for the Resample block
++ * @resample_phase_y: Initial vertical phase for the Resample block
++ * @output_offset_x: Horizontal offset in pixels where the tile will
++ * be written into the output image
++ * @output_offset_y: Vertical offset in pixels where the tile will be
++ * written into the output image
++ * @output_width: Width in pixels in the output image of this tile
++ * @output_height: Height in pixels in the output image of this tile
++ * @output_addr_offset: Offset in bytes into the output buffer
++ * @output_addr_offset2: Offset in bytes into the output buffer for the
++ * second and third plane
++ * @output_hog_addr_offset: Offset in bytes into the HOG buffer where
++ * results of this tile are to be written
++ */
++struct pisp_tile {
++ __u8 edge; /* enum pisp_tile_edge */
++ __u8 pad0[3];
++ /* 4 bytes */
++ __u32 input_addr_offset;
++ __u32 input_addr_offset2;
++ __u16 input_offset_x;
++ __u16 input_offset_y;
++ __u16 input_width;
++ __u16 input_height;
++ /* 20 bytes */
++ __u32 tdn_input_addr_offset;
++ __u32 tdn_output_addr_offset;
++ __u32 stitch_input_addr_offset;
++ __u32 stitch_output_addr_offset;
++ /* 36 bytes */
++ __u32 lsc_grid_offset_x;
++ __u32 lsc_grid_offset_y;
++ /* 44 bytes */
++ __u32 cac_grid_offset_x;
++ __u32 cac_grid_offset_y;
++ /* 52 bytes */
++ __u16 crop_x_start[PISP_BACK_END_NUM_OUTPUTS];
++ __u16 crop_x_end[PISP_BACK_END_NUM_OUTPUTS];
++ __u16 crop_y_start[PISP_BACK_END_NUM_OUTPUTS];
++ __u16 crop_y_end[PISP_BACK_END_NUM_OUTPUTS];
++ /* 68 bytes */
++ /* Ordering is planes then branches */
++ __u16 downscale_phase_x[3 * PISP_BACK_END_NUM_OUTPUTS];
++ __u16 downscale_phase_y[3 * PISP_BACK_END_NUM_OUTPUTS];
++ /* 92 bytes */
++ __u16 resample_in_width[PISP_BACK_END_NUM_OUTPUTS];
++ __u16 resample_in_height[PISP_BACK_END_NUM_OUTPUTS];
++ /* 100 bytes */
++ /* Ordering is planes then branches */
++ __u16 resample_phase_x[3 * PISP_BACK_END_NUM_OUTPUTS];
++ __u16 resample_phase_y[3 * PISP_BACK_END_NUM_OUTPUTS];
++ /* 124 bytes */
++ __u16 output_offset_x[PISP_BACK_END_NUM_OUTPUTS];
++ __u16 output_offset_y[PISP_BACK_END_NUM_OUTPUTS];
++ __u16 output_width[PISP_BACK_END_NUM_OUTPUTS];
++ __u16 output_height[PISP_BACK_END_NUM_OUTPUTS];
++ /* 140 bytes */
++ __u32 output_addr_offset[PISP_BACK_END_NUM_OUTPUTS];
++ __u32 output_addr_offset2[PISP_BACK_END_NUM_OUTPUTS];
++ /* 156 bytes */
++ __u32 output_hog_addr_offset;
++ /* 160 bytes */
++} __attribute__((packed));
++
++/**
++ * struct pisp_be_tiles_config - Raspberry Pi PiSP Back End configuration
++ * @tiles: Tile descriptors
++ * @num_tiles: Number of tiles
++ * @config: PiSP Back End configuration
++ */
++struct pisp_be_tiles_config {
++ struct pisp_tile tiles[PISP_BACK_END_NUM_TILES];
++ __u32 num_tiles;
++ struct pisp_be_config config;
++} __attribute__((packed));
++
++#endif /* _UAPI_PISP_BE_CONFIG_H_ */
+--- /dev/null
++++ b/include/uapi/linux/media/raspberrypi/pisp_common.h
+@@ -0,0 +1,199 @@
++/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
++/*
++ * RP1 PiSP common definitions.
++ *
++ * Copyright (C) 2021 - Raspberry Pi Ltd.
++ *
++ */
++#ifndef _UAPI_PISP_COMMON_H_
++#define _UAPI_PISP_COMMON_H_
++
++#include <linux/types.h>
++
++struct pisp_image_format_config {
++ /* size in pixels */
++ __u16 width;
++ __u16 height;
++ /* must match struct pisp_image_format below */
++ __u32 format;
++ __s32 stride;
++ /* some planar image formats will need a second stride */
++ __s32 stride2;
++} __attribute__((packed));
++
++enum pisp_bayer_order {
++ /*
++ * Note how bayer_order&1 tells you if G is on the even pixels of the
++ * checkerboard or not, and bayer_order&2 tells you if R is on the even
++ * rows or is swapped with B. Note that if the top (of the 8) bits is
++ * set, this denotes a monochrome or greyscale image, and the lower bits
++ * should all be ignored.
++ */
++ PISP_BAYER_ORDER_RGGB = 0,
++ PISP_BAYER_ORDER_GBRG = 1,
++ PISP_BAYER_ORDER_BGGR = 2,
++ PISP_BAYER_ORDER_GRBG = 3,
++ PISP_BAYER_ORDER_GREYSCALE = 128
++};
++
++enum pisp_image_format {
++ /*
++ * Precise values are mostly tbd. Generally these will be portmanteau
++ * values comprising bit fields and flags. This format must be shared
++ * throughout the PiSP.
++ */
++ PISP_IMAGE_FORMAT_BPS_8 = 0x00000000,
++ PISP_IMAGE_FORMAT_BPS_10 = 0x00000001,
++ PISP_IMAGE_FORMAT_BPS_12 = 0x00000002,
++ PISP_IMAGE_FORMAT_BPS_16 = 0x00000003,
++ PISP_IMAGE_FORMAT_BPS_MASK = 0x00000003,
++
++ PISP_IMAGE_FORMAT_PLANARITY_INTERLEAVED = 0x00000000,
++ PISP_IMAGE_FORMAT_PLANARITY_SEMI_PLANAR = 0x00000010,
++ PISP_IMAGE_FORMAT_PLANARITY_PLANAR = 0x00000020,
++ PISP_IMAGE_FORMAT_PLANARITY_MASK = 0x00000030,
++
++ PISP_IMAGE_FORMAT_SAMPLING_444 = 0x00000000,
++ PISP_IMAGE_FORMAT_SAMPLING_422 = 0x00000100,
++ PISP_IMAGE_FORMAT_SAMPLING_420 = 0x00000200,
++ PISP_IMAGE_FORMAT_SAMPLING_MASK = 0x00000300,
++
++ PISP_IMAGE_FORMAT_ORDER_NORMAL = 0x00000000,
++ PISP_IMAGE_FORMAT_ORDER_SWAPPED = 0x00001000,
++
++ PISP_IMAGE_FORMAT_SHIFT_0 = 0x00000000,
++ PISP_IMAGE_FORMAT_SHIFT_1 = 0x00010000,
++ PISP_IMAGE_FORMAT_SHIFT_2 = 0x00020000,
++ PISP_IMAGE_FORMAT_SHIFT_3 = 0x00030000,
++ PISP_IMAGE_FORMAT_SHIFT_4 = 0x00040000,
++ PISP_IMAGE_FORMAT_SHIFT_5 = 0x00050000,
++ PISP_IMAGE_FORMAT_SHIFT_6 = 0x00060000,
++ PISP_IMAGE_FORMAT_SHIFT_7 = 0x00070000,
++ PISP_IMAGE_FORMAT_SHIFT_8 = 0x00080000,
++ PISP_IMAGE_FORMAT_SHIFT_MASK = 0x000f0000,
++
++ PISP_IMAGE_FORMAT_UNCOMPRESSED = 0x00000000,
++ PISP_IMAGE_FORMAT_COMPRESSION_MODE_1 = 0x01000000,
++ PISP_IMAGE_FORMAT_COMPRESSION_MODE_2 = 0x02000000,
++ PISP_IMAGE_FORMAT_COMPRESSION_MODE_3 = 0x03000000,
++ PISP_IMAGE_FORMAT_COMPRESSION_MASK = 0x03000000,
++
++ PISP_IMAGE_FORMAT_HOG_SIGNED = 0x04000000,
++ PISP_IMAGE_FORMAT_HOG_UNSIGNED = 0x08000000,
++ PISP_IMAGE_FORMAT_INTEGRAL_IMAGE = 0x10000000,
++ PISP_IMAGE_FORMAT_WALLPAPER_ROLL = 0x20000000,
++ PISP_IMAGE_FORMAT_THREE_CHANNEL = 0x40000000,
++
++ /* Lastly a few specific instantiations of the above. */
++ PISP_IMAGE_FORMAT_SINGLE_16 = PISP_IMAGE_FORMAT_BPS_16,
++ PISP_IMAGE_FORMAT_THREE_16 = PISP_IMAGE_FORMAT_BPS_16 |
++ PISP_IMAGE_FORMAT_THREE_CHANNEL
++};
++
++#define PISP_IMAGE_FORMAT_bps_8(fmt) \
++ (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) == PISP_IMAGE_FORMAT_BPS_8)
++#define PISP_IMAGE_FORMAT_bps_10(fmt) \
++ (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) == PISP_IMAGE_FORMAT_BPS_10)
++#define PISP_IMAGE_FORMAT_bps_12(fmt) \
++ (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) == PISP_IMAGE_FORMAT_BPS_12)
++#define PISP_IMAGE_FORMAT_bps_16(fmt) \
++ (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) == PISP_IMAGE_FORMAT_BPS_16)
++#define PISP_IMAGE_FORMAT_bps(fmt) \
++ (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) ? \
++ 8 + (2 << (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) - 1)) : 8)
++#define PISP_IMAGE_FORMAT_shift(fmt) \
++ (((fmt) & PISP_IMAGE_FORMAT_SHIFT_MASK) / PISP_IMAGE_FORMAT_SHIFT_1)
++#define PISP_IMAGE_FORMAT_three_channel(fmt) \
++ ((fmt) & PISP_IMAGE_FORMAT_THREE_CHANNEL)
++#define PISP_IMAGE_FORMAT_single_channel(fmt) \
++ (!((fmt) & PISP_IMAGE_FORMAT_THREE_CHANNEL))
++#define PISP_IMAGE_FORMAT_compressed(fmt) \
++ (((fmt) & PISP_IMAGE_FORMAT_COMPRESSION_MASK) != \
++ PISP_IMAGE_FORMAT_UNCOMPRESSED)
++#define PISP_IMAGE_FORMAT_sampling_444(fmt) \
++ (((fmt) & PISP_IMAGE_FORMAT_SAMPLING_MASK) == \
++ PISP_IMAGE_FORMAT_SAMPLING_444)
++#define PISP_IMAGE_FORMAT_sampling_422(fmt) \
++ (((fmt) & PISP_IMAGE_FORMAT_SAMPLING_MASK) == \
++ PISP_IMAGE_FORMAT_SAMPLING_422)
++#define PISP_IMAGE_FORMAT_sampling_420(fmt) \
++ (((fmt) & PISP_IMAGE_FORMAT_SAMPLING_MASK) == \
++ PISP_IMAGE_FORMAT_SAMPLING_420)
++#define PISP_IMAGE_FORMAT_order_normal(fmt) \
++ (!((fmt) & PISP_IMAGE_FORMAT_ORDER_SWAPPED))
++#define PISP_IMAGE_FORMAT_order_swapped(fmt) \
++ ((fmt) & PISP_IMAGE_FORMAT_ORDER_SWAPPED)
++#define PISP_IMAGE_FORMAT_interleaved(fmt) \
++ (((fmt) & PISP_IMAGE_FORMAT_PLANARITY_MASK) == \
++ PISP_IMAGE_FORMAT_PLANARITY_INTERLEAVED)
++#define PISP_IMAGE_FORMAT_semiplanar(fmt) \
++ (((fmt) & PISP_IMAGE_FORMAT_PLANARITY_MASK) == \
++ PISP_IMAGE_FORMAT_PLANARITY_SEMI_PLANAR)
++#define PISP_IMAGE_FORMAT_planar(fmt) \
++ (((fmt) & PISP_IMAGE_FORMAT_PLANARITY_MASK) == \
++ PISP_IMAGE_FORMAT_PLANARITY_PLANAR)
++#define PISP_IMAGE_FORMAT_wallpaper(fmt) \
++ ((fmt) & PISP_IMAGE_FORMAT_WALLPAPER_ROLL)
++#define PISP_IMAGE_FORMAT_HOG(fmt) \
++ ((fmt) & \
++ (PISP_IMAGE_FORMAT_HOG_SIGNED | PISP_IMAGE_FORMAT_HOG_UNSIGNED))
++
++#define PISP_WALLPAPER_WIDTH 128 /* in bytes */
++
++struct pisp_bla_config {
++ __u16 black_level_r;
++ __u16 black_level_gr;
++ __u16 black_level_gb;
++ __u16 black_level_b;
++ __u16 output_black_level;
++ __u8 pad[2];
++} __attribute__((packed));
++
++struct pisp_wbg_config {
++ __u16 gain_r;
++ __u16 gain_g;
++ __u16 gain_b;
++ __u8 pad[2];
++} __attribute__((packed));
++
++struct pisp_compress_config {
++ /* value subtracted from incoming data */
++ __u16 offset;
++ __u8 pad;
++ /* 1 => Companding; 2 => Delta (recommended); 3 => Combined (for HDR) */
++ __u8 mode;
++} __attribute__((packed));
++
++struct pisp_decompress_config {
++ /* value added to reconstructed data */
++ __u16 offset;
++ __u8 pad;
++ /* 1 => Companding; 2 => Delta (recommended); 3 => Combined (for HDR) */
++ __u8 mode;
++} __attribute__((packed));
++
++enum pisp_axi_flags {
++ /*
++ * round down bursts to end at a 32-byte boundary, to align following
++ * bursts
++ */
++ PISP_AXI_FLAG_ALIGN = 128,
++ /* for FE writer: force WSTRB high, to pad output to 16-byte boundary */
++ PISP_AXI_FLAG_PAD = 64,
++ /* for FE writer: Use Output FIFO level to trigger "panic" */
++ PISP_AXI_FLAG_PANIC = 32,
++};
++
++struct pisp_axi_config {
++ /*
++ * burst length minus one, which must be in the range 0:15; OR'd with
++ * flags
++ */
++ __u8 maxlen_flags;
++ /* { prot[2:0], cache[3:0] } fields, echoed on AXI bus */
++ __u8 cache_prot;
++ /* QoS field(s) (4x4 bits for FE writer; 4 bits for other masters) */
++ __u16 qos;
++} __attribute__((packed));
++
++#endif /* _UAPI_PISP_COMMON_H_ */
--- /dev/null
+From 7ca73020a5b26599d539083e413784e79891107e Mon Sep 17 00:00:00 2001
+From: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
+Date: Fri, 26 Jan 2024 15:04:59 +0100
+Subject: [PATCH 1150/1215] media: uapi: Document meta pixel format for PiSP BE
+ config
+
+Add format description for the PiSP Back End configuration parameter
+buffer.
+
+Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
+Reviewed-by: Naushir Patuck <naush@raspberrypi.com>
+---
+ .../userspace-api/media/v4l/meta-formats.rst | 1 +
+ .../media/v4l/metafmt-pisp-be.rst | 56 +++++++++++++++++++
+ 2 files changed, 57 insertions(+)
+ create mode 100644 Documentation/userspace-api/media/v4l/metafmt-pisp-be.rst
+
+--- a/Documentation/userspace-api/media/v4l/meta-formats.rst
++++ b/Documentation/userspace-api/media/v4l/meta-formats.rst
+@@ -15,6 +15,7 @@ These formats are used for the :ref:`met
+ metafmt-bcm2835-isp-stats
+ metafmt-d4xx
+ metafmt-intel-ipu3
++ metafmt-pisp-be
+ metafmt-rkisp1
+ metafmt-sensor-data
+ metafmt-uvc
+--- /dev/null
++++ b/Documentation/userspace-api/media/v4l/metafmt-pisp-be.rst
+@@ -0,0 +1,56 @@
++.. SPDX-License-Identifier: GPL-2.0
++
++.. _v4l2-meta-fmt-rpi-be-cfg:
++
++************************
++V4L2_META_FMT_RPI_BE_CFG
++************************
++
++Raspberry Pi PiSP Back End configuration format
++===============================================
++
++The Raspberry Pi PiSP Back End memory-to-memory image signal processor is
++configured by userspace by providing a buffer of configuration parameters
++to the `pispbe-config` output video device node using the
++:c:type:`v4l2_meta_format` interface.
++
++The PiSP Back End processes images in tiles, and its configuration requires
++specifying two different sets of parameters by populating the members of
++:c:type:`pisp_be_tiles_config` defined in the ``pisp_be_config.h`` header file.
++
++The `Raspberry Pi PiSP technical specification
++<https://datasheets.raspberrypi.com/camera/raspberry-pi-image-signal-processor-specification.pdf>`_
++provide detailed description of the ISP back end configuration and programming
++model.
++
++Global configuration data
++-------------------------
++
++The global configuration data describe how the pixels in a particular image are
++to be processed and is therefore shared across all the tiles of the image. So
++for example, LSC (Lens Shading Correction) or Denoise parameters would be common
++across all tiles from the same frame.
++
++Global configuration data are passed to the ISP by populating the member of
++:c:type:`pisp_be_config`.
++
++Tile parameters
++---------------
++
++As the ISP processes images in tiles, each set of tiles parameters describe how
++a single tile in an image is going to be processed. A single set of tile
++parameters consist of 160 bytes of data and to process a batch of tiles several
++sets of tiles parameters are required.
++
++Tiles parameters are passed to the ISP by populating the member of
++``pisp_tile`` and the ``num_tiles`` fields of :c:type:`pisp_be_tiles_config`.
++
++Raspberry Pi PiSP Back End uAPI data types
++==========================================
++
++This section describes the data types exposed to userspace by the Raspberry Pi
++PiSP Back End. The section is informative only, for a detailed description of
++each field refer to the `Raspberry Pi PiSP technical specification
++<https://datasheets.raspberrypi.com/camera/raspberry-pi-image-signal-processor-specification.pdf>`_.
++
++.. kernel-doc:: include/uapi/linux/media/raspberrypi/pisp_be_config.h
--- /dev/null
+From 5d6318f242cce5f9b5677baedde736a2b81061df Mon Sep 17 00:00:00 2001
+From: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
+Date: Wed, 17 Jan 2024 11:21:50 +0200
+Subject: [PATCH 1151/1215] media: uapi: Document PiSP Compressed RAW Bayer
+ formats
+
+Document the Raspberry Pi compressed RAW Bayer formats.
+
+The compression algorithm description is provided by Nick Hollinghurst
+<nick.hollinghurst@raspberrypi.com> from Raspberry Pi.
+
+Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
+Reviewed-by: Naushir Patuck <naush@raspberrypi.com>
+---
+ .../userspace-api/media/v4l/pixfmt-bayer.rst | 1 +
+ .../media/v4l/pixfmt-srggb8-pisp-comp.rst | 74 +++++++++++++++++++
+ 2 files changed, 75 insertions(+)
+ create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-srggb8-pisp-comp.rst
+
+--- a/Documentation/userspace-api/media/v4l/pixfmt-bayer.rst
++++ b/Documentation/userspace-api/media/v4l/pixfmt-bayer.rst
+@@ -20,6 +20,7 @@ orders. See also `the Wikipedia article
+ :maxdepth: 1
+
+ pixfmt-srggb8
++ pixfmt-srggb8-pisp-comp
+ pixfmt-srggb10
+ pixfmt-srggb10p
+ pixfmt-srggb10alaw8
+--- /dev/null
++++ b/Documentation/userspace-api/media/v4l/pixfmt-srggb8-pisp-comp.rst
+@@ -0,0 +1,74 @@
++.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
++
++.. _v4l2-pix-fmt-pisp-comp1-rggb:
++.. _v4l2-pix-fmt-pisp-comp1-grbg:
++.. _v4l2-pix-fmt-pisp-comp1-gbrg:
++.. _v4l2-pix-fmt-pisp-comp1-bggr:
++.. _v4l2-pix-fmt-pisp-comp1-mono:
++.. _v4l2-pix-fmt-pisp-comp2-rggb:
++.. _v4l2-pix-fmt-pisp-comp2-grbg:
++.. _v4l2-pix-fmt-pisp-comp2-gbrg:
++.. _v4l2-pix-fmt-pisp-comp2-bggr:
++.. _v4l2-pix-fmt-pisp-comp2-mono:
++
++**************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
++V4L2_PIX_FMT_PISP_COMP1_RGGB ('PC1R'), V4L2_PIX_FMT_PISP_COMP1_GRBG ('PC1G'), V4L2_PIX_FMT_PISP_COMP1_GBRG ('PC1g'), V4L2_PIX_FMT_PISP_COMP1_BGGR ('PC1B), V4L2_PIX_FMT_PISP_COMP1_MONO ('PC1M'), V4L2_PIX_FMT_PISP_COMP2_RGGB ('PC2R'), V4L2_PIX_FMT_PISP_COMP2_GRBG ('PC2G'), V4L2_PIX_FMT_PISP_COMP2_GBRG ('PC2g'), V4L2_PIX_FMT_PISP_COMP2_BGGR ('PC2B), V4L2_PIX_FMT_PISP_COMP2_MONO ('PC2M')
++**************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
++
++================================================
++Raspberry Pi PiSP compressed 8-bit Bayer formats
++================================================
++
++Description
++===========
++
++The Raspberry Pi ISP (PiSP) uses a family of three fixed-rate compressed Bayer
++formats. A black-level offset may be subtracted to improve compression
++efficiency; the nominal black level and amount of offset must be signalled out
++of band. Each scanline is padded to a multiple of 8 pixels wide, and each block
++of 8 horizontally-contiguous pixels is coded using 8 bytes.
++
++Mode 1 uses a quantization and delta-based coding scheme which preserves up to
++12 significant bits. Mode 2 is a simple sqrt-like companding scheme with 6 PWL
++chords, preserving up to 12 significant bits. Mode 3 combines both companding
++(with 4 chords) and the delta scheme, preserving up to 14 significant bits.
++
++The remainder of this description applies to Modes 1 and 3.
++
++Each block of 8 pixels is separated into even and odd phases of 4 pixels,
++coded independently by 32-bit words at successive locations in memory.
++The two LS bits of each 32-bit word give its "quantization mode".
++
++In quantization mode 0, the lowest 321 quantization levels are multiples of
++FSD/4096 and the remaining levels are successive multiples of FSD/2048.
++Quantization modes 1 and 2 use linear quantization with step sizes of
++FSD/1024 and FSD/512 respectively. Each of the four pixels is quantized
++independently, with rounding to the nearest level.
++In quantization mode 2 where the middle two samples have quantized values
++(q1,q2) both in the range [384..511], they are coded using 9 bits for q1
++followed by 7 bits for (q2 & 127). Otherwise, for quantization modes
++0, 1 and 2: a 9-bit field encodes MIN(q1,q2) which must be in the range
++[0..511] and a 7-bit field encodes (q2-q1+64) which must be in [0..127].
++
++Each of the outer samples (q0,q3) is encoded using a 7-bit field based
++on its inner neighbour q1 or q2. In quantization mode 2 where the inner
++sample has a quantized value in the range [448..511], the field value is
++(q0-384). Otherwise for quantization modes 0, 1 and 2: The outer sample
++is encoded as (q0-MAX(0,q1-64)). q3 is likewise coded based on q2.
++Each of these values must be in the range [0..127]. All these fields
++of 2, 9, 7, 7, 7 bits respectively are packed in little-endian order
++to give a 32-bit word with LE byte order.
++
++Quantization mode 3 has a "7.5-bit" escape, used when none of the above
++encodings will fit. Each pixel value is quantized to the nearest of 176
++levels, where the lowest 95 levels are multiples of FSD/256 and the
++remaining levels are multiples of FSD/128 (level 175 represents values
++very close to FSD and may require saturating arithmetic to decode).
++
++Each pair of quantized pixels (q0,q1) or (q2,q3) is jointly coded
++by a 15-bit field: 2816*(q0>>4) + 16*q1 + (q0&15).
++Three fields of 2, 15, 15 bits are packed in LE order {15,15,2}.
++
++An implementation of a software decoder of compressed formats is available
++in `Raspberry Pi camera applications code base
++<https://github.com/raspberrypi/rpicam-apps/blob/main/image/dng.cpp>`_.
--- /dev/null
+From c38a898c6877c6722ebfecea99f42e5a84c3e453 Mon Sep 17 00:00:00 2001
+From: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
+Date: Thu, 25 Jan 2024 16:42:33 +0100
+Subject: [PATCH 1152/1215] media: dt-bindings: Add bindings for Raspberry Pi
+ PiSP Back End
+
+Add bindings for the Raspberry Pi PiSP Back End memory-to-memory image
+signal processor.
+
+Datasheet:
+https://datasheets.raspberrypi.com/camera/raspberry-pi-image-signal-processor-specification.pdf
+
+Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
+Reviewed-by: Rob Herring <robh@kernel.org>
+Reviewed-by: Naushir Patuck <naush@raspberrypi.com>
+---
+ .../bindings/media/raspberrypi,pispbe.yaml | 63 +++++++++++++++++++
+ MAINTAINERS | 1 +
+ 2 files changed, 64 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/media/raspberrypi,pispbe.yaml
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/media/raspberrypi,pispbe.yaml
+@@ -0,0 +1,63 @@
++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
++%YAML 1.2
++---
++$id: http://devicetree.org/schemas/media/raspberrypi,pispbe.yaml#
++$schema: http://devicetree.org/meta-schemas/core.yaml#
++
++title: Raspberry Pi PiSP Image Signal Processor (ISP) Back End
++
++maintainers:
++ - Raspberry Pi Kernel Maintenance <kernel-list@raspberrypi.com>
++ - Jacopo Mondi <jacopo.mondi@ideasonboard.com>
++
++description: |
++ The Raspberry Pi PiSP Image Signal Processor (ISP) Back End is an image
++ processor that fetches images in Bayer or Grayscale format from DRAM memory
++ in tiles and produces images consumable by applications.
++
++ The full ISP documentation is available at
++ https://datasheets.raspberrypi.com/camera/raspberry-pi-image-signal-processor-specification.pdf
++
++properties:
++ compatible:
++ items:
++ - enum:
++ - brcm,bcm2712-pispbe
++ - const: raspberrypi,pispbe
++
++ reg:
++ maxItems: 1
++
++ interrupts:
++ maxItems: 1
++
++ clocks:
++ maxItems: 1
++
++ iommus:
++ maxItems: 1
++
++required:
++ - compatible
++ - reg
++ - interrupts
++ - clocks
++
++additionalProperties: false
++
++examples:
++ - |
++ #include <dt-bindings/interrupt-controller/arm-gic.h>
++
++ soc {
++ #address-cells = <2>;
++ #size-cells = <2>;
++
++ isp@880000 {
++ compatible = "brcm,bcm2712-pispbe", "raspberrypi,pispbe";
++ reg = <0x10 0x00880000 0x0 0x4000>;
++ interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&firmware_clocks 7>;
++ iommus = <&iommu2>;
++ };
++ };
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -18037,6 +18037,7 @@ M: Jacopo Mondi <jacopo.mondi@ideasonboa
+ L: Raspberry Pi Kernel Maintenance <kernel-list@raspberrypi.com>
+ L: linux-media@vger.kernel.org
+ S: Maintained
++F: Documentation/devicetree/bindings/media/raspberrypi,pispbe.yaml
+ F: include/uapi/linux/media/raspberrypi/
+
+ RC-CORE / LIRC FRAMEWORK
--- /dev/null
+From d68e76260316002869aea1b0edf4be399bb592b8 Mon Sep 17 00:00:00 2001
+From: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
+Date: Mon, 29 Jan 2024 17:23:55 +0100
+Subject: [PATCH 1153/1215] media: admin-guide: Document the Raspberry Pi PiSP
+ BE
+
+Add documentation for the PiSP Back End memory-to-memory ISP.
+
+Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
+---
+ .../admin-guide/media/raspberrypi-pisp-be.dot | 20 ++++
+ .../admin-guide/media/raspberrypi-pisp-be.rst | 109 ++++++++++++++++++
+ .../admin-guide/media/v4l-drivers.rst | 1 +
+ 3 files changed, 130 insertions(+)
+ create mode 100644 Documentation/admin-guide/media/raspberrypi-pisp-be.dot
+ create mode 100644 Documentation/admin-guide/media/raspberrypi-pisp-be.rst
+
+--- /dev/null
++++ b/Documentation/admin-guide/media/raspberrypi-pisp-be.dot
+@@ -0,0 +1,20 @@
++digraph board {
++ rankdir=TB
++ n00000001 [label="{{<port0> 0 | <port1> 1 | <port2> 2 | <port7> 7} | pispbe\n | {<port3> 3 | <port4> 4 | <port5> 5 | <port6> 6}}", shape=Mrecord, style=filled, fillcolor=green]
++ n00000001:port3 -> n0000001c [style=bold]
++ n00000001:port4 -> n00000022 [style=bold]
++ n00000001:port5 -> n00000028 [style=bold]
++ n00000001:port6 -> n0000002e [style=bold]
++ n0000000a [label="pispbe-input\n/dev/video0", shape=box, style=filled, fillcolor=yellow]
++ n0000000a -> n00000001:port0 [style=bold]
++ n00000010 [label="pispbe-tdn_input\n/dev/video1", shape=box, style=filled, fillcolor=yellow]
++ n00000010 -> n00000001:port1 [style=bold]
++ n00000016 [label="pispbe-stitch_input\n/dev/video2", shape=box, style=filled, fillcolor=yellow]
++ n00000016 -> n00000001:port2 [style=bold]
++ n0000001c [label="pispbe-output0\n/dev/video3", shape=box, style=filled, fillcolor=yellow]
++ n00000022 [label="pispbe-output1\n/dev/video4", shape=box, style=filled, fillcolor=yellow]
++ n00000028 [label="pispbe-tdn_output\n/dev/video5", shape=box, style=filled, fillcolor=yellow]
++ n0000002e [label="pispbe-stitch_output\n/dev/video6", shape=box, style=filled, fillcolor=yellow]
++ n00000034 [label="pispbe-config\n/dev/video7", shape=box, style=filled, fillcolor=yellow]
++ n00000034 -> n00000001:port7 [style=bold]
++}
+--- /dev/null
++++ b/Documentation/admin-guide/media/raspberrypi-pisp-be.rst
+@@ -0,0 +1,109 @@
++.. SPDX-License-Identifier: GPL-2.0
++
++=========================================================
++Raspberry Pi PiSP Back End Memory-to-Memory ISP (pisp-be)
++=========================================================
++
++The PiSP Back End
++=================
++
++The PiSP Back End is a memory-to-memory Image Signal Processor (ISP) which reads
++image data from DRAM memory and performs image processing as specified by the
++application through the parameters in a configuration buffer, before writing
++pixel data back to memory through two distinct output channels.
++
++The ISP registers and programming model are documented in the `Raspberry Pi
++Image Signal Processor (PiSP) Specification document`_
++
++The PiSP Back End ISP processes images in tiles. The handling of image
++tessellation and the computation of low-level configuration parameters is
++realized by a free software library called `libpisp
++<https://github.com/raspberrypi/libpisp>`_.
++
++The full image processing pipeline, which involves capturing RAW Bayer data from
++an image sensor through a MIPI CSI-2 compatible capture interface, storing them
++in DRAM memory and processing them in the PiSP Back End to obtain images usable
++by an application is implemented in `libcamera <https://libcamera.org>`_ as
++part of the Raspberry Pi platform support.
++
++The pisp-be driver
++==================
++
++The Raspberry Pi PiSP Back End (pisp-be) driver is located under
++drivers/media/platform/raspberrypi/pisp-be. It uses the `V4L2 API` to register
++a number of video capture and output devices, the `V4L2 subdev API` to register
++a subdevice for the ISP that connects the video devices in a single media graph
++realized using the `Media Controller (MC) API`.
++
++The media topology registered by the `pisp-be` driver is represented below:
++
++.. _pips-be-topology:
++
++.. kernel-figure:: raspberrypi-pisp-be.dot
++ :alt: Diagram of the default media pipeline topology
++ :align: center
++
++
++The media graph registers the following video device nodes:
++
++- pispbe-input: output device for images to be submitted to the ISP for
++ processing.
++- pispbe-tdn_input: output device for temporal denoise.
++- pispbe-stitch_input: output device for image stitching (HDR).
++- pispbe-output0: first capture device for processed images.
++- pispbe-output1: second capture device for processed images.
++- pispbe-tdn_output: capture device for temporal denoise.
++- pispbe-stitch_output: capture device for image stitching (HDR).
++- pispbe-config: output device for ISP configuration parameters.
++
++pispbe-input
++------------
++
++Images to be processed by the ISP are queued to the `pispbe-input` output device
++node. For a list of image formats supported as input to the ISP refer to the
++`Raspberry Pi Image Signal Processor (PiSP) Specification document`_.
++
++pispbe-tdn_input, pispbe-tdn_output
++-----------------------------------
++
++The `pispbe-tdn_input` output video device receives images to be processed by
++the temporal denoise block which are captured from the `pispbe-tdn_output`
++capture video device. Userspace is responsible for maintaining queues on both
++devices, and ensuring that buffers completed on the output are queued to the
++input.
++
++pispbe-stitch_input, pispbe-stitch_output
++-----------------------------------------
++
++To realize HDR (high dynamic range) image processing the image stitching and
++tonemapping blocks are used. The `pispbe-stitch_output` writes images to memory
++and the `pispbe-stitch_input` receives the previously written frame to process
++it along with the current input image. Userspace is responsible for maintaining
++queues on both devices, and ensuring that buffers completed on the output are
++queued to the input.
++
++pispbe-output0, pispbe-output1
++------------------------------
++
++The two capture devices write to memory the pixel data as processed by the ISP.
++
++pispbe-config
++-------------
++
++The `pispbe-config` output video devices receives a buffer of configuration
++parameters that define the desired image processing to be performed by the ISP.
++
++The format of the ISP configuration parameter is defined by
++:c:type:`pisp_be_tiles_config` C structure and the meaning of each parameter is
++described in the `Raspberry Pi Image Signal Processor (PiSP) Specification
++document`_.
++
++ISP configuration
++=================
++
++The ISP configuration is described solely by the content of the parameters
++buffer. The only parameter that userspace needs to configure using the V4L2 API
++is the image format on the output and capture video devices for validation of
++the content of the parameters buffer.
++
++.. _Raspberry Pi Image Signal Processor (PiSP) Specification document: https://datasheets.raspberrypi.com/camera/raspberry-pi-image-signal-processor-specification.pdf
+--- a/Documentation/admin-guide/media/v4l-drivers.rst
++++ b/Documentation/admin-guide/media/v4l-drivers.rst
+@@ -21,6 +21,7 @@ Video4Linux (V4L) driver-specific docume
+ omap4_camera
+ philips
+ qcom_camss
++ raspberrypi-pisp-be
+ rcar-fdp1
+ rkisp1
+ saa7134
--- /dev/null
+From c75989589bf77530f4013e0bc799169504c69937 Mon Sep 17 00:00:00 2001
+From: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
+Date: Thu, 27 Jun 2024 11:41:22 +0200
+Subject: [PATCH 1154/1215] media: pisp-be: Backport the mainline PiSP BE
+ driver
+
+Backport to rpi-6.6.y the mainline version of the PiSP BE driver.
+
+The backported version of the driver corresponds to the one available
+at:
+https://lore.kernel.org/all/20240626181440.195137-1-jacopo.mondi@ideasonboard.com/
+
+Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
+---
+ .../platform/raspberrypi/pisp_be/Kconfig | 4 +-
+ .../platform/raspberrypi/pisp_be/pisp_be.c | 1288 +++++++----------
+ .../raspberrypi/pisp_be/pisp_be_config.h | 533 -------
+ .../raspberrypi/pisp_be/pisp_be_formats.h | 44 +-
+ 4 files changed, 572 insertions(+), 1297 deletions(-)
+ delete mode 100644 drivers/media/platform/raspberrypi/pisp_be/pisp_be_config.h
+
+--- a/drivers/media/platform/raspberrypi/pisp_be/Kconfig
++++ b/drivers/media/platform/raspberrypi/pisp_be/Kconfig
+@@ -1,10 +1,10 @@
+ config VIDEO_RASPBERRYPI_PISP_BE
+ tristate "Raspberry Pi PiSP Backend (BE) ISP driver"
+- depends on VIDEO_DEV && PM
++ depends on V4L_PLATFORM_DRIVERS
++ depends on VIDEO_DEV
+ select VIDEO_V4L2_SUBDEV_API
+ select MEDIA_CONTROLLER
+ select VIDEOBUF2_DMA_CONTIG
+- select V4L2_FWNODE
+ help
+ Say Y here to enable support for the PiSP Backend (BE) ISP driver.
+
+--- a/drivers/media/platform/raspberrypi/pisp_be/pisp_be.c
++++ b/drivers/media/platform/raspberrypi/pisp_be/pisp_be.c
+@@ -1,12 +1,14 @@
+ // SPDX-License-Identifier: GPL-2.0
+ /*
+ * PiSP Back End driver.
+- * Copyright (c) 2021-2022 Raspberry Pi Limited.
++ * Copyright (c) 2021-2024 Raspberry Pi Limited.
+ *
+ */
+ #include <linux/clk.h>
+ #include <linux/interrupt.h>
+ #include <linux/io.h>
++#include <linux/kernel.h>
++#include <linux/lockdep.h>
+ #include <linux/module.h>
+ #include <linux/platform_device.h>
+ #include <linux/pm_runtime.h>
+@@ -15,49 +17,39 @@
+ #include <media/videobuf2-dma-contig.h>
+ #include <media/videobuf2-vmalloc.h>
+
+-#include "pisp_be_config.h"
+-#include "pisp_be_formats.h"
+-
+-MODULE_DESCRIPTION("PiSP Back End driver");
+-MODULE_AUTHOR("David Plowman <david.plowman@raspberrypi.com>");
+-MODULE_AUTHOR("Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>");
+-MODULE_LICENSE("GPL v2");
++#include <uapi/linux/media/raspberrypi/pisp_be_config.h>
+
+-/* Offset to use when registering the /dev/videoX node */
+-#define PISPBE_VIDEO_NODE_OFFSET 20
++#include "pisp_be_formats.h"
+
+ /* Maximum number of config buffers possible */
+ #define PISP_BE_NUM_CONFIG_BUFFERS VB2_MAX_FRAME
+
+-/*
+- * We want to support 2 independent instances allowing 2 simultaneous users
+- * of the ISP-BE (of course they share hardware, platform resources and mutex).
+- * Each such instance comprises a group of device nodes representing input
+- * and output queues, and a media controller device node to describe them.
+- */
+-#define PISPBE_NUM_NODE_GROUPS 2
+-
+ #define PISPBE_NAME "pispbe"
+
+ /* Some ISP-BE registers */
+-#define PISP_BE_VERSION_OFFSET (0x0)
+-#define PISP_BE_CONTROL_OFFSET (0x4)
+-#define PISP_BE_TILE_ADDR_LO_OFFSET (0x8)
+-#define PISP_BE_TILE_ADDR_HI_OFFSET (0xc)
+-#define PISP_BE_STATUS_OFFSET (0x10)
+-#define PISP_BE_BATCH_STATUS_OFFSET (0x14)
+-#define PISP_BE_INTERRUPT_EN_OFFSET (0x18)
+-#define PISP_BE_INTERRUPT_STATUS_OFFSET (0x1c)
+-#define PISP_BE_AXI_OFFSET (0x20)
+-#define PISP_BE_CONFIG_BASE_OFFSET (0x40)
+-#define PISP_BE_IO_INPUT_ADDR0_LO_OFFSET (PISP_BE_CONFIG_BASE_OFFSET)
+-#define PISP_BE_GLOBAL_BAYER_ENABLE_OFFSET (PISP_BE_CONFIG_BASE_OFFSET + 0x70)
+-#define PISP_BE_GLOBAL_RGB_ENABLE_OFFSET (PISP_BE_CONFIG_BASE_OFFSET + 0x74)
+-#define N_HW_ADDRESSES 14
+-#define N_HW_ENABLES 2
++#define PISP_BE_VERSION_REG 0x0
++#define PISP_BE_CONTROL_REG 0x4
++#define PISP_BE_CONTROL_COPY_CONFIG BIT(1)
++#define PISP_BE_CONTROL_QUEUE_JOB BIT(0)
++#define PISP_BE_CONTROL_NUM_TILES(n) ((n) << 16)
++#define PISP_BE_TILE_ADDR_LO_REG 0x8
++#define PISP_BE_TILE_ADDR_HI_REG 0xc
++#define PISP_BE_STATUS_REG 0x10
++#define PISP_BE_STATUS_QUEUED BIT(0)
++#define PISP_BE_BATCH_STATUS_REG 0x14
++#define PISP_BE_INTERRUPT_EN_REG 0x18
++#define PISP_BE_INTERRUPT_STATUS_REG 0x1c
++#define PISP_BE_AXI_REG 0x20
++#define PISP_BE_CONFIG_BASE_REG 0x40
++#define PISP_BE_IO_ADDR_LOW(n) (PISP_BE_CONFIG_BASE_REG + 8 * (n))
++#define PISP_BE_IO_ADDR_HIGH(n) (PISP_BE_IO_ADDR_LOW((n)) + 4)
++#define PISP_BE_GLOBAL_BAYER_ENABLE 0xb0
++#define PISP_BE_GLOBAL_RGB_ENABLE 0xb4
++#define N_HW_ADDRESSES 13
++#define N_HW_ENABLES 2
+
+-#define PISP_BE_VERSION_2712C1 0x02252700
+-#define PISP_BE_VERSION_MINOR_BITS 0xF
++#define PISP_BE_VERSION_2712 0x02252700
++#define PISP_BE_VERSION_MINOR_BITS 0xf
+
+ /*
+ * This maps our nodes onto the inputs/outputs of the actual PiSP Back End.
+@@ -65,11 +57,10 @@ MODULE_LICENSE("GPL v2");
+ * context it means an input to the hardware (source image or metadata).
+ * Elsewhere it means an output from the hardware.
+ */
+-enum node_ids {
++enum pispbe_node_ids {
+ MAIN_INPUT_NODE,
+ TDN_INPUT_NODE,
+ STITCH_INPUT_NODE,
+- HOG_OUTPUT_NODE,
+ OUTPUT0_NODE,
+ OUTPUT1_NODE,
+ TDN_OUTPUT_NODE,
+@@ -78,13 +69,13 @@ enum node_ids {
+ PISPBE_NUM_NODES
+ };
+
+-struct node_description {
++struct pispbe_node_description {
+ const char *ent_name;
+ enum v4l2_buf_type buf_type;
+ unsigned int caps;
+ };
+
+-static const struct node_description node_desc[PISPBE_NUM_NODES] = {
++static const struct pispbe_node_description node_desc[PISPBE_NUM_NODES] = {
+ /* MAIN_INPUT_NODE */
+ {
+ .ent_name = PISPBE_NAME "-input",
+@@ -103,12 +94,6 @@ static const struct node_description nod
+ .buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+ .caps = V4L2_CAP_VIDEO_OUTPUT_MPLANE,
+ },
+- /* HOG_OUTPUT_NODE */
+- {
+- .ent_name = PISPBE_NAME "-hog_output",
+- .buf_type = V4L2_BUF_TYPE_META_CAPTURE,
+- .caps = V4L2_CAP_META_CAPTURE,
+- },
+ /* OUTPUT0_NODE */
+ {
+ .ent_name = PISPBE_NAME "-output0",
+@@ -147,14 +132,12 @@ static const struct node_description nod
+ ((desc)->buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE))
+
+ #define NODE_IS_META(node) ( \
+- ((node)->buf_type == V4L2_BUF_TYPE_META_OUTPUT) || \
+- ((node)->buf_type == V4L2_BUF_TYPE_META_CAPTURE))
++ ((node)->buf_type == V4L2_BUF_TYPE_META_OUTPUT))
+ #define NODE_IS_OUTPUT(node) ( \
+ ((node)->buf_type == V4L2_BUF_TYPE_META_OUTPUT) || \
+ ((node)->buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT) || \
+ ((node)->buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE))
+ #define NODE_IS_CAPTURE(node) ( \
+- ((node)->buf_type == V4L2_BUF_TYPE_META_CAPTURE) || \
+ ((node)->buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) || \
+ ((node)->buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE))
+ #define NODE_IS_MPLANE(node) ( \
+@@ -173,9 +156,12 @@ struct pispbe_node {
+ struct media_pad pad;
+ struct media_intf_devnode *intf_devnode;
+ struct media_link *intf_link;
+- struct pispbe_node_group *node_group;
++ struct pispbe_dev *pispbe;
++ /* Video device lock */
+ struct mutex node_lock;
++ /* vb2_queue lock */
+ struct mutex queue_lock;
++ /* Protect pispbe_node->ready_queue and pispbe_buffer->ready_list */
+ spinlock_t ready_lock;
+ struct list_head ready_queue;
+ struct vb2_queue queue;
+@@ -186,29 +172,10 @@ struct pispbe_node {
+ /* For logging only, use the entity name with "pispbe" and separator removed */
+ #define NODE_NAME(node) \
+ (node_desc[(node)->id].ent_name + sizeof(PISPBE_NAME))
+-#define NODE_GET_V4L2(node) ((node)->node_group->v4l2_dev)
+-
+-/*
+- * Node group structure, which comprises all the input and output nodes that a
+- * single PiSP client will need, along with its own v4l2 and media devices.
+- */
+-struct pispbe_node_group {
+- unsigned int id;
+- struct v4l2_device v4l2_dev;
+- struct v4l2_subdev sd;
+- struct pispbe_dev *pispbe;
+- struct media_device mdev;
+- struct pispbe_node node[PISPBE_NUM_NODES];
+- u32 streaming_map; /* bitmap of which nodes are streaming */
+- struct media_pad pad[PISPBE_NUM_NODES]; /* output pads first */
+- struct pisp_be_tiles_config *config;
+- dma_addr_t config_dma_addr;
+- unsigned int sequence;
+-};
+
+ /* Records details of the jobs currently running or queued on the h/w. */
+ struct pispbe_job {
+- struct pispbe_node_group *node_group;
++ bool valid;
+ /*
+ * An array of buffer pointers - remember it's source buffers first,
+ * then captures, then metadata last.
+@@ -216,85 +183,66 @@ struct pispbe_job {
+ struct pispbe_buffer *buf[PISPBE_NUM_NODES];
+ };
+
++struct pispbe_hw_enables {
++ u32 bayer_enables;
++ u32 rgb_enables;
++};
++
++/* Records a job configuration and memory addresses. */
++struct pispbe_job_descriptor {
++ dma_addr_t hw_dma_addrs[N_HW_ADDRESSES];
++ struct pisp_be_tiles_config *config;
++ struct pispbe_hw_enables hw_enables;
++ dma_addr_t tiles;
++};
++
+ /*
+ * Structure representing the entire PiSP Back End device, comprising several
+- * node groups which share platform resources and a mutex for the actual HW.
++ * nodes which share platform resources and a mutex for the actual HW.
+ */
+ struct pispbe_dev {
+ struct device *dev;
+- struct pispbe_node_group node_group[PISPBE_NUM_NODE_GROUPS];
+- int hw_busy; /* non-zero if a job is queued or is being started */
+- struct pispbe_job queued_job, running_job;
++ struct pispbe_dev *pispbe;
++ struct pisp_be_tiles_config *config;
+ void __iomem *be_reg_base;
+ struct clk *clk;
++ struct v4l2_device v4l2_dev;
++ struct v4l2_subdev sd;
++ struct media_device mdev;
++ struct media_pad pad[PISPBE_NUM_NODES]; /* output pads first */
++ struct pispbe_node node[PISPBE_NUM_NODES];
++ dma_addr_t config_dma_addr;
++ unsigned int sequence;
++ u32 streaming_map;
++ struct pispbe_job queued_job, running_job;
++ spinlock_t hw_lock; /* protects "hw_busy" flag and streaming_map */
++ bool hw_busy; /* non-zero if a job is queued or is being started */
+ int irq;
+ u32 hw_version;
+ u8 done, started;
+- spinlock_t hw_lock; /* protects "hw_busy" flag and streaming_map */
+ };
+
+-static inline u32 read_reg(struct pispbe_dev *pispbe, unsigned int offset)
++static u32 pispbe_rd(struct pispbe_dev *pispbe, unsigned int offset)
+ {
+ return readl(pispbe->be_reg_base + offset);
+ }
+
+-static inline void write_reg(struct pispbe_dev *pispbe, unsigned int offset,
+- u32 val)
++static void pispbe_wr(struct pispbe_dev *pispbe, unsigned int offset, u32 val)
+ {
+ writel(val, pispbe->be_reg_base + offset);
+ }
+
+-/* Check and initialize hardware. */
+-static int hw_init(struct pispbe_dev *pispbe)
+-{
+- u32 u;
+-
+- /* Check the HW is present and has a known version */
+- u = read_reg(pispbe, PISP_BE_VERSION_OFFSET);
+- dev_info(pispbe->dev, "pispbe_probe: HW version: 0x%08x", u);
+- pispbe->hw_version = u;
+- if ((u & ~PISP_BE_VERSION_MINOR_BITS) != PISP_BE_VERSION_2712C1)
+- return -ENODEV;
+-
+- /* Clear leftover interrupts */
+- write_reg(pispbe, PISP_BE_INTERRUPT_STATUS_OFFSET, 0xFFFFFFFFu);
+- u = read_reg(pispbe, PISP_BE_BATCH_STATUS_OFFSET);
+- dev_info(pispbe->dev, "pispbe_probe: BatchStatus: 0x%08x", u);
+- pispbe->done = (uint8_t)u;
+- pispbe->started = (uint8_t)(u >> 8);
+- u = read_reg(pispbe, PISP_BE_STATUS_OFFSET);
+- dev_info(pispbe->dev, "pispbe_probe: Status: 0x%08x", u);
+- if (u != 0 || pispbe->done != pispbe->started) {
+- dev_err(pispbe->dev, "pispbe_probe: HW is stuck or busy\n");
+- return -EBUSY;
+- }
+- /*
+- * AXI QOS=0, CACHE=4'b0010, PROT=3'b011
+- * Also set "chicken bits" 22:20 which enable sub-64-byte bursts
+- * and AXI AWID/BID variability (on versions which support this).
+- */
+- write_reg(pispbe, PISP_BE_AXI_OFFSET, 0x32703200u);
+-
+- /* Enable both interrupt flags */
+- write_reg(pispbe, PISP_BE_INTERRUPT_EN_OFFSET, 0x00000003u);
+- return 0;
+-}
+-
+ /*
+ * Queue a job to the h/w. If the h/w is idle it will begin immediately.
+ * Caller must ensure it is "safe to queue", i.e. we don't already have a
+ * queued, unstarted job.
+ */
+-static void hw_queue_job(struct pispbe_dev *pispbe,
+- dma_addr_t hw_dma_addrs[N_HW_ADDRESSES],
+- u32 hw_enables[N_HW_ENABLES],
+- struct pisp_be_config *config, dma_addr_t tiles,
+- unsigned int num_tiles)
++static void pispbe_queue_job(struct pispbe_dev *pispbe,
++ struct pispbe_job_descriptor *job)
+ {
+ unsigned int begin, end;
+- unsigned int u;
+
+- if (read_reg(pispbe, PISP_BE_STATUS_OFFSET) & 1)
++ if (pispbe_rd(pispbe, PISP_BE_STATUS_REG) & PISP_BE_STATUS_QUEUED)
+ dev_err(pispbe->dev, "ERROR: not safe to queue new job!\n");
+
+ /*
+@@ -303,51 +251,49 @@ static void hw_queue_job(struct pispbe_d
+ * and we don't want to modify (or be vulnerable to modifications of)
+ * the mmap'd buffer.
+ */
+- for (u = 0; u < N_HW_ADDRESSES; ++u) {
+- write_reg(pispbe, PISP_BE_IO_INPUT_ADDR0_LO_OFFSET + 8 * u,
+- (u32)(hw_dma_addrs[u]));
+- write_reg(pispbe, PISP_BE_IO_INPUT_ADDR0_LO_OFFSET + 8 * u + 4,
+- (u32)(hw_dma_addrs[u] >> 32));
+- }
+- write_reg(pispbe, PISP_BE_GLOBAL_BAYER_ENABLE_OFFSET, hw_enables[0]);
+- write_reg(pispbe, PISP_BE_GLOBAL_RGB_ENABLE_OFFSET, hw_enables[1]);
++ for (unsigned int u = 0; u < N_HW_ADDRESSES; ++u) {
++ pispbe_wr(pispbe, PISP_BE_IO_ADDR_LOW(u),
++ lower_32_bits(job->hw_dma_addrs[u]));
++ pispbe_wr(pispbe, PISP_BE_IO_ADDR_HIGH(u),
++ upper_32_bits(job->hw_dma_addrs[u]));
++ }
++ pispbe_wr(pispbe, PISP_BE_GLOBAL_BAYER_ENABLE,
++ job->hw_enables.bayer_enables);
++ pispbe_wr(pispbe, PISP_BE_GLOBAL_RGB_ENABLE,
++ job->hw_enables.rgb_enables);
+
+- /*
+- * Everything else is as supplied by the user. XXX Buffer sizes not
+- * checked!
+- */
++ /* Everything else is as supplied by the user. */
+ begin = offsetof(struct pisp_be_config, global.bayer_order) /
+- sizeof(u32);
+- end = offsetof(struct pisp_be_config, axi) / sizeof(u32);
+- for (u = begin; u < end; u++) {
+- unsigned int val = ((u32 *)config)[u];
+-
+- write_reg(pispbe, PISP_BE_CONFIG_BASE_OFFSET + 4 * u, val);
+- }
++ sizeof(u32);
++ end = sizeof(struct pisp_be_config) / sizeof(u32);
++ for (unsigned int u = begin; u < end; u++)
++ pispbe_wr(pispbe, PISP_BE_CONFIG_BASE_REG + sizeof(u32) * u,
++ ((u32 *)job->config)[u]);
+
+ /* Read back the addresses -- an error here could be fatal */
+- for (u = 0; u < N_HW_ADDRESSES; ++u) {
+- unsigned int offset = PISP_BE_IO_INPUT_ADDR0_LO_OFFSET + 8 * u;
+- u64 along = read_reg(pispbe, offset);
+-
+- along += ((u64)read_reg(pispbe, offset + 4)) << 32;
+- if (along != (u64)(hw_dma_addrs[u])) {
+- dev_err(pispbe->dev,
++ for (unsigned int u = 0; u < N_HW_ADDRESSES; ++u) {
++ unsigned int offset = PISP_BE_IO_ADDR_LOW(u);
++ u64 along = pispbe_rd(pispbe, offset);
++
++ along += ((u64)pispbe_rd(pispbe, offset + 4)) << 32;
++ if (along != (u64)(job->hw_dma_addrs[u])) {
++ dev_dbg(pispbe->dev,
+ "ISP BE config error: check if ISP RAMs enabled?\n");
+ return;
+ }
+ }
+
+ /*
+- * Write tile pointer to hardware. XXX Tile offsets and sizes not
+- * checked (and even if checked, the user could subsequently modify
+- * them)!
++ * Write tile pointer to hardware. The IOMMU should prevent
++ * out-of-bounds offsets reaching non-ISP buffers.
+ */
+- write_reg(pispbe, PISP_BE_TILE_ADDR_LO_OFFSET, (u32)tiles);
+- write_reg(pispbe, PISP_BE_TILE_ADDR_HI_OFFSET, (u32)(tiles >> 32));
++ pispbe_wr(pispbe, PISP_BE_TILE_ADDR_LO_REG, lower_32_bits(job->tiles));
++ pispbe_wr(pispbe, PISP_BE_TILE_ADDR_HI_REG, upper_32_bits(job->tiles));
+
+ /* Enqueue the job */
+- write_reg(pispbe, PISP_BE_CONTROL_OFFSET, 3 + 65536 * num_tiles);
++ pispbe_wr(pispbe, PISP_BE_CONTROL_REG,
++ PISP_BE_CONTROL_COPY_CONFIG | PISP_BE_CONTROL_QUEUE_JOB |
++ PISP_BE_CONTROL_NUM_TILES(job->config->num_tiles));
+ }
+
+ struct pispbe_buffer {
+@@ -356,8 +302,8 @@ struct pispbe_buffer {
+ unsigned int config_index;
+ };
+
+-static int get_addr_3(dma_addr_t addr[3], struct pispbe_buffer *buf,
+- struct pispbe_node *node)
++static int pispbe_get_planes_addr(dma_addr_t addr[3], struct pispbe_buffer *buf,
++ struct pispbe_node *node)
+ {
+ unsigned int num_planes = node->format.fmt.pix_mp.num_planes;
+ unsigned int plane_factor = 0;
+@@ -367,22 +313,20 @@ static int get_addr_3(dma_addr_t addr[3]
+ if (!buf || !node->pisp_format)
+ return 0;
+
+- WARN_ON(!NODE_IS_MPLANE(node));
+-
+ /*
+ * Determine the base plane size. This will not be the same
+ * as node->format.fmt.pix_mp.plane_fmt[0].sizeimage for a single
+ * plane buffer in an mplane format.
+ */
+ size = node->format.fmt.pix_mp.plane_fmt[0].bytesperline *
+- node->format.fmt.pix_mp.height;
++ node->format.fmt.pix_mp.height;
+
+- for (p = 0; p < num_planes && p < 3; p++) {
++ for (p = 0; p < num_planes && p < PISPBE_MAX_PLANES; p++) {
+ addr[p] = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, p);
+ plane_factor += node->pisp_format->plane_factor[p];
+ }
+
+- for (; p < MAX_PLANES && node->pisp_format->plane_factor[p]; p++) {
++ for (; p < PISPBE_MAX_PLANES && node->pisp_format->plane_factor[p]; p++) {
+ /*
+ * Calculate the address offset of this plane as needed
+ * by the hardware. This is specifically for non-mplane
+@@ -396,41 +340,41 @@ static int get_addr_3(dma_addr_t addr[3]
+ return num_planes;
+ }
+
+-static dma_addr_t get_addr(struct pispbe_buffer *buf)
++static dma_addr_t pispbe_get_addr(struct pispbe_buffer *buf)
+ {
+ if (buf)
+ return vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0);
++
+ return 0;
+ }
+
+-static void
+-fixup_addrs_enables(dma_addr_t addrs[N_HW_ADDRESSES],
+- u32 hw_enables[N_HW_ENABLES],
+- struct pisp_be_tiles_config *config,
+- struct pispbe_buffer *buf[PISPBE_NUM_NODES],
+- struct pispbe_node_group *node_group)
+-{
+- int ret, i;
++static void pispbe_xlate_addrs(struct pispbe_dev *pispbe,
++ struct pispbe_job_descriptor *job,
++ struct pispbe_buffer *buf[PISPBE_NUM_NODES])
++{
++ struct pispbe_hw_enables *hw_en = &job->hw_enables;
++ struct pisp_be_tiles_config *config = job->config;
++ dma_addr_t *addrs = job->hw_dma_addrs;
++ int ret;
+
+ /* Take a copy of the "enable" bitmaps so we can modify them. */
+- hw_enables[0] = config->config.global.bayer_enables;
+- hw_enables[1] = config->config.global.rgb_enables;
++ hw_en->bayer_enables = config->config.global.bayer_enables;
++ hw_en->rgb_enables = config->config.global.rgb_enables;
+
+ /*
+ * Main input first. There are 3 address pointers, corresponding to up
+ * to 3 planes.
+ */
+- ret = get_addr_3(addrs, buf[MAIN_INPUT_NODE],
+- &node_group->node[MAIN_INPUT_NODE]);
++ ret = pispbe_get_planes_addr(addrs, buf[MAIN_INPUT_NODE],
++ &pispbe->node[MAIN_INPUT_NODE]);
+ if (ret <= 0) {
+ /*
+ * This shouldn't happen; pispbe_schedule_internal should insist
+ * on an input.
+ */
+- dev_warn(node_group->pispbe->dev,
+- "ISP-BE missing input\n");
+- hw_enables[0] = 0;
+- hw_enables[1] = 0;
++ dev_warn(pispbe->dev, "ISP-BE missing input\n");
++ hw_en->bayer_enables = 0;
++ hw_en->rgb_enables = 0;
+ return;
+ }
+
+@@ -439,118 +383,114 @@ fixup_addrs_enables(dma_addr_t addrs[N_H
+ * used with Bayer input. Input enables must match the requirements
+ * of the processing stages, otherwise the hardware can lock up!
+ */
+- if (hw_enables[0] & PISP_BE_BAYER_ENABLE_INPUT) {
+- addrs[3] = get_addr(buf[TDN_INPUT_NODE]);
++ if (hw_en->bayer_enables & PISP_BE_BAYER_ENABLE_INPUT) {
++ addrs[3] = pispbe_get_addr(buf[TDN_INPUT_NODE]);
+ if (addrs[3] == 0 ||
+- !(hw_enables[0] & PISP_BE_BAYER_ENABLE_TDN_INPUT) ||
+- !(hw_enables[0] & PISP_BE_BAYER_ENABLE_TDN) ||
++ !(hw_en->bayer_enables & PISP_BE_BAYER_ENABLE_TDN_INPUT) ||
++ !(hw_en->bayer_enables & PISP_BE_BAYER_ENABLE_TDN) ||
+ (config->config.tdn.reset & 1)) {
+- hw_enables[0] &= ~(PISP_BE_BAYER_ENABLE_TDN_INPUT |
+- PISP_BE_BAYER_ENABLE_TDN_DECOMPRESS);
++ hw_en->bayer_enables &=
++ ~(PISP_BE_BAYER_ENABLE_TDN_INPUT |
++ PISP_BE_BAYER_ENABLE_TDN_DECOMPRESS);
+ if (!(config->config.tdn.reset & 1))
+- hw_enables[0] &= ~PISP_BE_BAYER_ENABLE_TDN;
++ hw_en->bayer_enables &=
++ ~PISP_BE_BAYER_ENABLE_TDN;
+ }
+
+- addrs[4] = get_addr(buf[STITCH_INPUT_NODE]);
++ addrs[4] = pispbe_get_addr(buf[STITCH_INPUT_NODE]);
+ if (addrs[4] == 0 ||
+- !(hw_enables[0] & PISP_BE_BAYER_ENABLE_STITCH_INPUT) ||
+- !(hw_enables[0] & PISP_BE_BAYER_ENABLE_STITCH)) {
+- hw_enables[0] &=
++ !(hw_en->bayer_enables & PISP_BE_BAYER_ENABLE_STITCH_INPUT) ||
++ !(hw_en->bayer_enables & PISP_BE_BAYER_ENABLE_STITCH)) {
++ hw_en->bayer_enables &=
+ ~(PISP_BE_BAYER_ENABLE_STITCH_INPUT |
+ PISP_BE_BAYER_ENABLE_STITCH_DECOMPRESS |
+ PISP_BE_BAYER_ENABLE_STITCH);
+ }
+
+- addrs[5] = get_addr(buf[TDN_OUTPUT_NODE]);
++ addrs[5] = pispbe_get_addr(buf[TDN_OUTPUT_NODE]);
+ if (addrs[5] == 0)
+- hw_enables[0] &= ~(PISP_BE_BAYER_ENABLE_TDN_COMPRESS |
+- PISP_BE_BAYER_ENABLE_TDN_OUTPUT);
++ hw_en->bayer_enables &=
++ ~(PISP_BE_BAYER_ENABLE_TDN_COMPRESS |
++ PISP_BE_BAYER_ENABLE_TDN_OUTPUT);
+
+- addrs[6] = get_addr(buf[STITCH_OUTPUT_NODE]);
++ addrs[6] = pispbe_get_addr(buf[STITCH_OUTPUT_NODE]);
+ if (addrs[6] == 0)
+- hw_enables[0] &=
++ hw_en->bayer_enables &=
+ ~(PISP_BE_BAYER_ENABLE_STITCH_COMPRESS |
+ PISP_BE_BAYER_ENABLE_STITCH_OUTPUT);
+ } else {
+ /* No Bayer input? Disable entire Bayer pipe (else lockup) */
+- hw_enables[0] = 0;
++ hw_en->bayer_enables = 0;
+ }
+
+ /* Main image output channels. */
+- for (i = 0; i < PISP_BACK_END_NUM_OUTPUTS; i++) {
+- ret = get_addr_3(addrs + 7 + 3 * i, buf[OUTPUT0_NODE + i],
+- &node_group->node[OUTPUT0_NODE + i]);
++ for (unsigned int i = 0; i < PISP_BACK_END_NUM_OUTPUTS; i++) {
++ ret = pispbe_get_planes_addr(addrs + 7 + 3 * i,
++ buf[OUTPUT0_NODE + i],
++ &pispbe->node[OUTPUT0_NODE + i]);
+ if (ret <= 0)
+- hw_enables[1] &= ~(PISP_BE_RGB_ENABLE_OUTPUT0 << i);
++ hw_en->rgb_enables &= ~(PISP_BE_RGB_ENABLE_OUTPUT0 << i);
+ }
+-
+- /* HoG output (always single plane). */
+- addrs[13] = get_addr(buf[HOG_OUTPUT_NODE]);
+- if (addrs[13] == 0)
+- hw_enables[1] &= ~PISP_BE_RGB_ENABLE_HOG;
+ }
+
+ /*
+- * Internal function. Called from pispbe_schedule_one/all. Returns non-zero if
+- * we started a job.
++ * Prepare a job description to be submitted to the HW.
++ *
++ * To schedule a job, we need all streaming nodes (apart from Output0,
++ * Output1, Tdn and Stitch) to have a buffer ready, which must
++ * include at least a config buffer and a main input image.
+ *
+- * Warning: needs to be called with hw_lock taken, and releases it if it
+- * schedules a job.
++ * For Output0, Output1, Tdn and Stitch, a buffer only needs to be
++ * available if the blocks are enabled in the config.
++ *
++ * Needs to be called with hw_lock held.
++ *
++ * Returns 0 if a job has been successfully prepared, < 0 otherwise.
+ */
+-static int pispbe_schedule_internal(struct pispbe_node_group *node_group,
+- unsigned long flags)
++static int pispbe_prepare_job(struct pispbe_dev *pispbe,
++ struct pispbe_job_descriptor *job)
+ {
+- struct pisp_be_tiles_config *config_tiles_buffer;
+- struct pispbe_dev *pispbe = node_group->pispbe;
+- struct pispbe_buffer *buf[PISPBE_NUM_NODES];
+- dma_addr_t hw_dma_addrs[N_HW_ADDRESSES];
+- dma_addr_t tiles;
+- u32 hw_enables[N_HW_ENABLES];
+- struct pispbe_node *node;
+- unsigned long flags1;
++ struct pispbe_buffer *buf[PISPBE_NUM_NODES] = {};
+ unsigned int config_index;
+- int i;
++ struct pispbe_node *node;
++ unsigned long flags;
++
++ lockdep_assert_held(&pispbe->hw_lock);
++
++ memset(job, 0, sizeof(struct pispbe_job_descriptor));
+
+- /*
+- * To schedule a job, we need all streaming nodes (apart from Output0,
+- * Output1, Tdn and Stitch) to have a buffer ready, which must
+- * include at least a config buffer and a main input image.
+- *
+- * For Output0, Output1, Tdn and Stitch, a buffer only needs to be
+- * available if the blocks are enabled in the config.
+- *
+- * (Note that streaming_map is protected by hw_lock, which is held.)
+- */
+ if (((BIT(CONFIG_NODE) | BIT(MAIN_INPUT_NODE)) &
+- node_group->streaming_map) !=
+- (BIT(CONFIG_NODE) | BIT(MAIN_INPUT_NODE))) {
+- dev_dbg(pispbe->dev, "Nothing to do\n");
+- return 0;
+- }
++ pispbe->streaming_map) !=
++ (BIT(CONFIG_NODE) | BIT(MAIN_INPUT_NODE)))
++ return -ENODEV;
+
+- node = &node_group->node[CONFIG_NODE];
+- spin_lock_irqsave(&node->ready_lock, flags1);
+- buf[CONFIG_NODE] =
+- list_first_entry_or_null(&node->ready_queue, struct pispbe_buffer,
+- ready_list);
+- spin_unlock_irqrestore(&node->ready_lock, flags1);
++ node = &pispbe->node[CONFIG_NODE];
++ spin_lock_irqsave(&node->ready_lock, flags);
++ buf[CONFIG_NODE] = list_first_entry_or_null(&node->ready_queue,
++ struct pispbe_buffer,
++ ready_list);
++ if (buf[CONFIG_NODE]) {
++ list_del(&buf[CONFIG_NODE]->ready_list);
++ pispbe->queued_job.buf[CONFIG_NODE] = buf[CONFIG_NODE];
++ }
++ spin_unlock_irqrestore(&node->ready_lock, flags);
+
+ /* Exit early if no config buffer has been queued. */
+ if (!buf[CONFIG_NODE])
+- return 0;
++ return -ENODEV;
+
+ config_index = buf[CONFIG_NODE]->vb.vb2_buf.index;
+- config_tiles_buffer = &node_group->config[config_index];
+- tiles = (dma_addr_t)node_group->config_dma_addr +
+- config_index * sizeof(struct pisp_be_tiles_config) +
+- offsetof(struct pisp_be_tiles_config, tiles);
++ job->config = &pispbe->config[config_index];
++ job->tiles = pispbe->config_dma_addr +
++ config_index * sizeof(struct pisp_be_tiles_config) +
++ offsetof(struct pisp_be_tiles_config, tiles);
+
+ /* remember: srcimages, captures then metadata */
+- for (i = 0; i < PISPBE_NUM_NODES; i++) {
++ for (unsigned int i = 0; i < PISPBE_NUM_NODES; i++) {
+ unsigned int bayer_en =
+- config_tiles_buffer->config.global.bayer_enables;
++ job->config->config.global.bayer_enables;
+ unsigned int rgb_en =
+- config_tiles_buffer->config.global.rgb_enables;
++ job->config->config.global.rgb_enables;
+ bool ignore_buffers = false;
+
+ /* Config node is handled outside the loop above. */
+@@ -558,7 +498,7 @@ static int pispbe_schedule_internal(stru
+ continue;
+
+ buf[i] = NULL;
+- if (!(node_group->streaming_map & BIT(i)))
++ if (!(pispbe->streaming_map & BIT(i)))
+ continue;
+
+ if ((!(rgb_en & PISP_BE_RGB_ENABLE_OUTPUT0) &&
+@@ -578,119 +518,103 @@ static int pispbe_schedule_internal(stru
+ * global enables aren't set for these blocks. If a
+ * buffer has been provided, we dequeue it back to the
+ * user with the other in-use buffers.
+- *
+ */
+ ignore_buffers = true;
+ }
+
+- node = &node_group->node[i];
++ node = &pispbe->node[i];
+
+- spin_lock_irqsave(&node->ready_lock, flags1);
++ /* Pull a buffer from each V4L2 queue to form the queued job */
++ spin_lock_irqsave(&node->ready_lock, flags);
+ buf[i] = list_first_entry_or_null(&node->ready_queue,
+ struct pispbe_buffer,
+ ready_list);
+- spin_unlock_irqrestore(&node->ready_lock, flags1);
+- if (!buf[i] && !ignore_buffers) {
+- dev_dbg(pispbe->dev, "Nothing to do\n");
+- return 0;
+- }
+- }
+-
+- /* Pull a buffer from each V4L2 queue to form the queued job */
+- for (i = 0; i < PISPBE_NUM_NODES; i++) {
+ if (buf[i]) {
+- node = &node_group->node[i];
+-
+- spin_lock_irqsave(&node->ready_lock, flags1);
+ list_del(&buf[i]->ready_list);
+- spin_unlock_irqrestore(&node->ready_lock,
+- flags1);
++ pispbe->queued_job.buf[i] = buf[i];
+ }
+- pispbe->queued_job.buf[i] = buf[i];
++ spin_unlock_irqrestore(&node->ready_lock, flags);
++
++ if (!buf[i] && !ignore_buffers)
++ goto err_return_buffers;
+ }
+
+- pispbe->queued_job.node_group = node_group;
+- pispbe->hw_busy = 1;
+- spin_unlock_irqrestore(&pispbe->hw_lock, flags);
+-
+- /*
+- * We can kick the job off without the hw_lock, as this can
+- * never run again until hw_busy is cleared, which will happen
+- * only when the following job has been queued.
+- */
+- dev_dbg(pispbe->dev, "Have buffers - starting hardware\n");
++ pispbe->queued_job.valid = true;
+
+ /* Convert buffers to DMA addresses for the hardware */
+- fixup_addrs_enables(hw_dma_addrs, hw_enables,
+- config_tiles_buffer, buf, node_group);
+- /*
+- * This could be a spot to fill in the
+- * buf[i]->vb.vb2_buf.planes[j].bytesused fields?
+- */
+- i = config_tiles_buffer->num_tiles;
+- if (i <= 0 || i > PISP_BACK_END_NUM_TILES ||
+- !((hw_enables[0] | hw_enables[1]) &
+- PISP_BE_BAYER_ENABLE_INPUT)) {
+- /*
+- * Bad job. We can't let it proceed as it could lock up
+- * the hardware, or worse!
+- *
+- * XXX How to deal with this most cleanly? For now, just
+- * force num_tiles to 0, which causes the H/W to do
+- * something bizarre but survivable. It increments
+- * (started,done) counters by more than 1, but we seem
+- * to survive...
+- */
+- dev_err(pispbe->dev, "PROBLEM: Bad job");
+- i = 0;
+- }
+- hw_queue_job(pispbe, hw_dma_addrs, hw_enables,
+- &config_tiles_buffer->config, tiles, i);
++ pispbe_xlate_addrs(pispbe, job, buf);
+
+- return 1;
+-}
++ return 0;
+
+-/* Try and schedule a job for just a single node group. */
+-static void pispbe_schedule_one(struct pispbe_node_group *node_group)
+-{
+- struct pispbe_dev *pispbe = node_group->pispbe;
+- unsigned long flags;
+- int ret;
++err_return_buffers:
++ for (unsigned int i = 0; i < PISPBE_NUM_NODES; i++) {
++ struct pispbe_node *n = &pispbe->node[i];
+
+- spin_lock_irqsave(&pispbe->hw_lock, flags);
+- if (pispbe->hw_busy) {
+- spin_unlock_irqrestore(&pispbe->hw_lock, flags);
+- return;
++ if (!buf[i])
++ continue;
++
++ /* Return the buffer to the ready_list queue */
++ spin_lock_irqsave(&n->ready_lock, flags);
++ list_add(&buf[i]->ready_list, &n->ready_queue);
++ spin_unlock_irqrestore(&n->ready_lock, flags);
+ }
+
+- /* A non-zero return means the lock was released. */
+- ret = pispbe_schedule_internal(node_group, flags);
+- if (!ret)
+- spin_unlock_irqrestore(&pispbe->hw_lock, flags);
++ memset(&pispbe->queued_job, 0, sizeof(pispbe->queued_job));
++
++ return -ENODEV;
+ }
+
+-/* Try and schedule a job for any of the node groups. */
+-static void pispbe_schedule_any(struct pispbe_dev *pispbe, int clear_hw_busy)
++static void pispbe_schedule(struct pispbe_dev *pispbe, bool clear_hw_busy)
+ {
++ struct pispbe_job_descriptor job;
+ unsigned long flags;
++ int ret;
+
+ spin_lock_irqsave(&pispbe->hw_lock, flags);
+
+ if (clear_hw_busy)
+- pispbe->hw_busy = 0;
+- if (pispbe->hw_busy == 0) {
+- unsigned int i;
++ pispbe->hw_busy = false;
+
+- for (i = 0; i < PISPBE_NUM_NODE_GROUPS; i++) {
+- /*
+- * A non-zero return from pispbe_schedule_internal means
+- * the lock was released.
+- */
+- if (pispbe_schedule_internal(&pispbe->node_group[i],
+- flags))
+- return;
+- }
++ if (pispbe->hw_busy)
++ goto unlock_and_return;
++
++ ret = pispbe_prepare_job(pispbe, &job);
++ if (ret)
++ goto unlock_and_return;
++
++ /*
++ * We can kick the job off without the hw_lock, as this can
++ * never run again until hw_busy is cleared, which will happen
++ * only when the following job has been queued and an interrupt
++ * is rised.
++ */
++ pispbe->hw_busy = true;
++ spin_unlock_irqrestore(&pispbe->hw_lock, flags);
++
++ if (job.config->num_tiles <= 0 ||
++ job.config->num_tiles > PISP_BACK_END_NUM_TILES ||
++ !((job.hw_enables.bayer_enables | job.hw_enables.rgb_enables) &
++ PISP_BE_BAYER_ENABLE_INPUT)) {
++ /*
++ * Bad job. We can't let it proceed as it could lock up
++ * the hardware, or worse!
++ *
++ * For now, just force num_tiles to 0, which causes the
++ * H/W to do something bizarre but survivable. It
++ * increments (started,done) counters by more than 1,
++ * but we seem to survive...
++ */
++ dev_dbg(pispbe->dev, "Bad job: invalid number of tiles: %u\n",
++ job.config->num_tiles);
++ job.config->num_tiles = 0;
+ }
++
++ pispbe_queue_job(pispbe, &job);
++
++ return;
++
++unlock_and_return:
++ /* No job has been queued, just release the lock and return. */
+ spin_unlock_irqrestore(&pispbe->hw_lock, flags);
+ }
+
+@@ -699,62 +623,53 @@ static void pispbe_isr_jobdone(struct pi
+ {
+ struct pispbe_buffer **buf = job->buf;
+ u64 ts = ktime_get_ns();
+- int i;
+
+- for (i = 0; i < PISPBE_NUM_NODES; i++) {
++ for (unsigned int i = 0; i < PISPBE_NUM_NODES; i++) {
+ if (buf[i]) {
+ buf[i]->vb.vb2_buf.timestamp = ts;
+- buf[i]->vb.sequence = job->node_group->sequence;
++ buf[i]->vb.sequence = pispbe->sequence;
+ vb2_buffer_done(&buf[i]->vb.vb2_buf,
+ VB2_BUF_STATE_DONE);
+ }
+ }
+
+- job->node_group->sequence++;
++ pispbe->sequence++;
+ }
+
+ static irqreturn_t pispbe_isr(int irq, void *dev)
+ {
+ struct pispbe_dev *pispbe = (struct pispbe_dev *)dev;
++ bool can_queue_another = false;
+ u8 started, done;
+- int can_queue_another = 0;
+ u32 u;
+
+- u = read_reg(pispbe, PISP_BE_INTERRUPT_STATUS_OFFSET);
++ u = pispbe_rd(pispbe, PISP_BE_INTERRUPT_STATUS_REG);
+ if (u == 0)
+ return IRQ_NONE;
+
+- write_reg(pispbe, PISP_BE_INTERRUPT_STATUS_OFFSET, u);
+- dev_dbg(pispbe->dev, "Hardware interrupt\n");
+- u = read_reg(pispbe, PISP_BE_BATCH_STATUS_OFFSET);
++ pispbe_wr(pispbe, PISP_BE_INTERRUPT_STATUS_REG, u);
++ u = pispbe_rd(pispbe, PISP_BE_BATCH_STATUS_REG);
+ done = (uint8_t)u;
+ started = (uint8_t)(u >> 8);
+- dev_dbg(pispbe->dev,
+- "H/W started %d done %d, previously started %d done %d\n",
+- (int)started, (int)done, (int)pispbe->started,
+- (int)pispbe->done);
+
+ /*
+ * Be aware that done can go up by 2 and started by 1 when: a job that
+ * we previously saw "start" now finishes, and we then queued a new job
+ * which we see both start and finish "simultaneously".
+ */
+- if (pispbe->running_job.node_group && pispbe->done != done) {
++ if (pispbe->running_job.valid && pispbe->done != done) {
+ pispbe_isr_jobdone(pispbe, &pispbe->running_job);
+ memset(&pispbe->running_job, 0, sizeof(pispbe->running_job));
+ pispbe->done++;
+- dev_dbg(pispbe->dev, "Job done (1)\n");
+ }
+
+ if (pispbe->started != started) {
+ pispbe->started++;
+ can_queue_another = 1;
+- dev_dbg(pispbe->dev, "Job started\n");
+
+- if (pispbe->done != done && pispbe->queued_job.node_group) {
++ if (pispbe->done != done && pispbe->queued_job.valid) {
+ pispbe_isr_jobdone(pispbe, &pispbe->queued_job);
+ pispbe->done++;
+- dev_dbg(pispbe->dev, "Job done (2)\n");
+ } else {
+ pispbe->running_job = pispbe->queued_job;
+ }
+@@ -763,74 +678,81 @@ static irqreturn_t pispbe_isr(int irq, v
+ }
+
+ if (pispbe->done != done || pispbe->started != started) {
+- dev_err(pispbe->dev, "PROBLEM: counters not matching!\n");
++ dev_dbg(pispbe->dev,
++ "Job counters not matching: done = %u, expected %u - started = %u, expected %u\n",
++ pispbe->done, done, pispbe->started, started);
+ pispbe->started = started;
+ pispbe->done = done;
+ }
+
+ /* check if there's more to do before going to sleep */
+- pispbe_schedule_any(pispbe, can_queue_another);
++ pispbe_schedule(pispbe, can_queue_another);
+
+ return IRQ_HANDLED;
+ }
+
+-static int pisp_be_validate_config(struct pispbe_node_group *node_group,
++static int pisp_be_validate_config(struct pispbe_dev *pispbe,
+ struct pisp_be_tiles_config *config)
+ {
+ u32 bayer_enables = config->config.global.bayer_enables;
+ u32 rgb_enables = config->config.global.rgb_enables;
+- struct device *dev = node_group->pispbe->dev;
++ struct device *dev = pispbe->dev;
+ struct v4l2_format *fmt;
+- unsigned int bpl, size, i, j;
++ unsigned int bpl, size;
+
+ if (!(bayer_enables & PISP_BE_BAYER_ENABLE_INPUT) ==
+ !(rgb_enables & PISP_BE_RGB_ENABLE_INPUT)) {
+- dev_err(dev, "%s: Not one input enabled\n", __func__);
++ dev_dbg(dev, "%s: Not one input enabled\n", __func__);
+ return -EIO;
+ }
+
+ /* Ensure output config strides and buffer sizes match the V4L2 formats. */
+- fmt = &node_group->node[TDN_OUTPUT_NODE].format;
++ fmt = &pispbe->node[TDN_OUTPUT_NODE].format;
+ if (bayer_enables & PISP_BE_BAYER_ENABLE_TDN_OUTPUT) {
+ bpl = config->config.tdn_output_format.stride;
+ size = bpl * config->config.tdn_output_format.height;
++
+ if (fmt->fmt.pix_mp.plane_fmt[0].bytesperline < bpl) {
+- dev_err(dev, "%s: bpl mismatch on tdn_output\n",
++ dev_dbg(dev, "%s: bpl mismatch on tdn_output\n",
+ __func__);
+ return -EINVAL;
+ }
++
+ if (fmt->fmt.pix_mp.plane_fmt[0].sizeimage < size) {
+- dev_err(dev, "%s: size mismatch on tdn_output\n",
++ dev_dbg(dev, "%s: size mismatch on tdn_output\n",
+ __func__);
+ return -EINVAL;
+ }
+ }
+
+- fmt = &node_group->node[STITCH_OUTPUT_NODE].format;
++ fmt = &pispbe->node[STITCH_OUTPUT_NODE].format;
+ if (bayer_enables & PISP_BE_BAYER_ENABLE_STITCH_OUTPUT) {
+ bpl = config->config.stitch_output_format.stride;
+ size = bpl * config->config.stitch_output_format.height;
++
+ if (fmt->fmt.pix_mp.plane_fmt[0].bytesperline < bpl) {
+- dev_err(dev, "%s: bpl mismatch on stitch_output\n",
++ dev_dbg(dev, "%s: bpl mismatch on stitch_output\n",
+ __func__);
+ return -EINVAL;
+ }
++
+ if (fmt->fmt.pix_mp.plane_fmt[0].sizeimage < size) {
+- dev_err(dev, "%s: size mismatch on stitch_output\n",
++ dev_dbg(dev, "%s: size mismatch on stitch_output\n",
+ __func__);
+ return -EINVAL;
+ }
+ }
+
+- for (j = 0; j < PISP_BACK_END_NUM_OUTPUTS; j++) {
++ for (unsigned int j = 0; j < PISP_BACK_END_NUM_OUTPUTS; j++) {
+ if (!(rgb_enables & PISP_BE_RGB_ENABLE_OUTPUT(j)))
+ continue;
++
+ if (config->config.output_format[j].image.format &
+ PISP_IMAGE_FORMAT_WALLPAPER_ROLL)
+ continue; /* TODO: Size checks for wallpaper formats */
+
+- fmt = &node_group->node[OUTPUT0_NODE + j].format;
+- for (i = 0; i < fmt->fmt.pix_mp.num_planes; i++) {
++ fmt = &pispbe->node[OUTPUT0_NODE + j].format;
++ for (unsigned int i = 0; i < fmt->fmt.pix_mp.num_planes; i++) {
+ bpl = !i ? config->config.output_format[j].image.stride
+ : config->config.output_format[j].image.stride2;
+ size = bpl * config->config.output_format[j].image.height;
+@@ -838,13 +760,15 @@ static int pisp_be_validate_config(struc
+ if (config->config.output_format[j].image.format &
+ PISP_IMAGE_FORMAT_SAMPLING_420)
+ size >>= 1;
++
+ if (fmt->fmt.pix_mp.plane_fmt[i].bytesperline < bpl) {
+- dev_err(dev, "%s: bpl mismatch on output %d\n",
++ dev_dbg(dev, "%s: bpl mismatch on output %d\n",
+ __func__, j);
+ return -EINVAL;
+ }
++
+ if (fmt->fmt.pix_mp.plane_fmt[i].sizeimage < size) {
+- dev_err(dev, "%s: size mismatch on output\n",
++ dev_dbg(dev, "%s: size mismatch on output\n",
+ __func__);
+ return -EINVAL;
+ }
+@@ -859,32 +783,32 @@ static int pispbe_node_queue_setup(struc
+ struct device *alloc_devs[])
+ {
+ struct pispbe_node *node = vb2_get_drv_priv(q);
+- struct pispbe_dev *pispbe = node->node_group->pispbe;
++ struct pispbe_dev *pispbe = node->pispbe;
++ unsigned int num_planes = NODE_IS_MPLANE(node) ?
++ node->format.fmt.pix_mp.num_planes : 1;
+
+- *nplanes = 1;
+- if (NODE_IS_MPLANE(node)) {
+- unsigned int i;
+-
+- *nplanes = node->format.fmt.pix_mp.num_planes;
+- for (i = 0; i < *nplanes; i++) {
+- unsigned int size =
+- node->format.fmt.pix_mp.plane_fmt[i].sizeimage;
+- if (sizes[i] && sizes[i] < size) {
+- dev_err(pispbe->dev, "%s: size %u < %u\n",
+- __func__, sizes[i], size);
++ if (*nplanes) {
++ if (*nplanes != num_planes)
++ return -EINVAL;
++
++ for (unsigned int i = 0; i < *nplanes; i++) {
++ unsigned int size = NODE_IS_MPLANE(node) ?
++ node->format.fmt.pix_mp.plane_fmt[i].sizeimage :
++ node->format.fmt.meta.buffersize;
++
++ if (sizes[i] < size)
+ return -EINVAL;
+- }
+- sizes[i] = size;
+ }
+- } else if (NODE_IS_META(node)) {
+- sizes[0] = node->format.fmt.meta.buffersize;
+- /*
+- * Limit the config node buffer count to the number of internal
+- * buffers allocated.
+- */
+- if (node->id == CONFIG_NODE)
+- *nbuffers = min_t(unsigned int, *nbuffers,
+- PISP_BE_NUM_CONFIG_BUFFERS);
++
++ return 0;
++ }
++
++ *nplanes = num_planes;
++ for (unsigned int i = 0; i < *nplanes; i++) {
++ unsigned int size = NODE_IS_MPLANE(node) ?
++ node->format.fmt.pix_mp.plane_fmt[i].sizeimage :
++ node->format.fmt.meta.buffersize;
++ sizes[i] = size;
+ }
+
+ dev_dbg(pispbe->dev,
+@@ -897,19 +821,17 @@ static int pispbe_node_queue_setup(struc
+ static int pispbe_node_buffer_prepare(struct vb2_buffer *vb)
+ {
+ struct pispbe_node *node = vb2_get_drv_priv(vb->vb2_queue);
+- struct pispbe_dev *pispbe = node->node_group->pispbe;
+- unsigned long size = 0;
++ struct pispbe_dev *pispbe = node->pispbe;
+ unsigned int num_planes = NODE_IS_MPLANE(node) ?
+- node->format.fmt.pix_mp.num_planes : 1;
+- unsigned int i;
++ node->format.fmt.pix_mp.num_planes : 1;
+
+- for (i = 0; i < num_planes; i++) {
+- size = NODE_IS_MPLANE(node)
+- ? node->format.fmt.pix_mp.plane_fmt[i].sizeimage
+- : node->format.fmt.meta.buffersize;
++ for (unsigned int i = 0; i < num_planes; i++) {
++ unsigned long size = NODE_IS_MPLANE(node) ?
++ node->format.fmt.pix_mp.plane_fmt[i].sizeimage :
++ node->format.fmt.meta.buffersize;
+
+ if (vb2_plane_size(vb, i) < size) {
+- dev_err(pispbe->dev,
++ dev_dbg(pispbe->dev,
+ "data will not fit into plane %d (%lu < %lu)\n",
+ i, vb2_plane_size(vb, i), size);
+ return -EINVAL;
+@@ -919,11 +841,12 @@ static int pispbe_node_buffer_prepare(st
+ }
+
+ if (node->id == CONFIG_NODE) {
+- void *dst = &node->node_group->config[vb->index];
++ void *dst = &node->pispbe->config[vb->index];
+ void *src = vb2_plane_vaddr(vb, 0);
+
+ memcpy(dst, src, sizeof(struct pisp_be_tiles_config));
+- return pisp_be_validate_config(node->node_group, dst);
++
++ return pisp_be_validate_config(pispbe, dst);
+ }
+
+ return 0;
+@@ -936,8 +859,7 @@ static void pispbe_node_buffer_queue(str
+ struct pispbe_buffer *buffer =
+ container_of(vbuf, struct pispbe_buffer, vb);
+ struct pispbe_node *node = vb2_get_drv_priv(buf->vb2_queue);
+- struct pispbe_node_group *node_group = node->node_group;
+- struct pispbe_dev *pispbe = node->node_group->pispbe;
++ struct pispbe_dev *pispbe = node->pispbe;
+ unsigned long flags;
+
+ dev_dbg(pispbe->dev, "%s: for node %s\n", __func__, NODE_NAME(node));
+@@ -947,44 +869,53 @@ static void pispbe_node_buffer_queue(str
+
+ /*
+ * Every time we add a buffer, check if there's now some work for the hw
+- * to do, but only for this client.
++ * to do.
+ */
+- pispbe_schedule_one(node_group);
++ pispbe_schedule(pispbe, false);
+ }
+
+ static int pispbe_node_start_streaming(struct vb2_queue *q, unsigned int count)
+ {
+- unsigned long flags;
+ struct pispbe_node *node = vb2_get_drv_priv(q);
+- struct pispbe_node_group *node_group = node->node_group;
+- struct pispbe_dev *pispbe = node_group->pispbe;
++ struct pispbe_dev *pispbe = node->pispbe;
++ struct pispbe_buffer *buf, *tmp;
++ unsigned long flags;
+ int ret;
+
+ ret = pm_runtime_resume_and_get(pispbe->dev);
+ if (ret < 0)
+- return ret;
++ goto err_return_buffers;
+
+ spin_lock_irqsave(&pispbe->hw_lock, flags);
+- node->node_group->streaming_map |= BIT(node->id);
+- node->node_group->sequence = 0;
++ node->pispbe->streaming_map |= BIT(node->id);
++ node->pispbe->sequence = 0;
+ spin_unlock_irqrestore(&pispbe->hw_lock, flags);
+
+ dev_dbg(pispbe->dev, "%s: for node %s (count %u)\n",
+ __func__, NODE_NAME(node), count);
+- dev_dbg(pispbe->dev, "Nodes streaming for this group now 0x%x\n",
+- node->node_group->streaming_map);
++ dev_dbg(pispbe->dev, "Nodes streaming now 0x%x\n",
++ node->pispbe->streaming_map);
+
+ /* Maybe we're ready to run. */
+- pispbe_schedule_one(node_group);
++ pispbe_schedule(pispbe, false);
+
+ return 0;
++
++err_return_buffers:
++ spin_lock_irqsave(&pispbe->hw_lock, flags);
++ list_for_each_entry_safe(buf, tmp, &node->ready_queue, ready_list) {
++ list_del(&buf->ready_list);
++ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED);
++ }
++ spin_unlock_irqrestore(&pispbe->hw_lock, flags);
++
++ return ret;
+ }
+
+ static void pispbe_node_stop_streaming(struct vb2_queue *q)
+ {
+ struct pispbe_node *node = vb2_get_drv_priv(q);
+- struct pispbe_node_group *node_group = node->node_group;
+- struct pispbe_dev *pispbe = node_group->pispbe;
++ struct pispbe_dev *pispbe = node->pispbe;
+ struct pispbe_buffer *buf;
+ unsigned long flags;
+
+@@ -994,7 +925,8 @@ static void pispbe_node_stop_streaming(s
+ * partial set of buffers was queued and cannot be run. For now, just
+ * cancel all buffers stuck in the "ready queue", then wait for any
+ * running job.
+- * XXX This may return buffers out of order.
++ *
++ * This may return buffers out of order.
+ */
+ dev_dbg(pispbe->dev, "%s: for node %s\n", __func__, NODE_NAME(node));
+ spin_lock_irqsave(&pispbe->hw_lock, flags);
+@@ -1016,14 +948,14 @@ static void pispbe_node_stop_streaming(s
+ vb2_wait_for_all_buffers(&node->queue);
+
+ spin_lock_irqsave(&pispbe->hw_lock, flags);
+- node_group->streaming_map &= ~BIT(node->id);
++ pispbe->streaming_map &= ~BIT(node->id);
+ spin_unlock_irqrestore(&pispbe->hw_lock, flags);
+
+ pm_runtime_mark_last_busy(pispbe->dev);
+ pm_runtime_put_autosuspend(pispbe->dev);
+
+- dev_dbg(pispbe->dev, "Nodes streaming for this group now 0x%x\n",
+- node_group->streaming_map);
++ dev_dbg(pispbe->dev, "Nodes streaming now 0x%x\n",
++ pispbe->streaming_map);
+ }
+
+ static const struct vb2_ops pispbe_node_queue_ops = {
+@@ -1047,22 +979,15 @@ static int pispbe_node_querycap(struct f
+ struct v4l2_capability *cap)
+ {
+ struct pispbe_node *node = video_drvdata(file);
+- struct pispbe_dev *pispbe = node->node_group->pispbe;
++ struct pispbe_dev *pispbe = node->pispbe;
+
+ strscpy(cap->driver, PISPBE_NAME, sizeof(cap->driver));
+ strscpy(cap->card, PISPBE_NAME, sizeof(cap->card));
+- snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
+- dev_name(pispbe->dev));
+-
+- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE_MPLANE |
+- V4L2_CAP_VIDEO_OUTPUT_MPLANE |
+- V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS |
+- V4L2_CAP_META_OUTPUT | V4L2_CAP_META_CAPTURE;
+- cap->device_caps = node->vfd.device_caps;
+
+ dev_dbg(pispbe->dev, "Caps for node %s: %x and %x (dev %x)\n",
+ NODE_NAME(node), cap->capabilities, cap->device_caps,
+ node->vfd.device_caps);
++
+ return 0;
+ }
+
+@@ -1070,17 +995,19 @@ static int pispbe_node_g_fmt_vid_cap(str
+ struct v4l2_format *f)
+ {
+ struct pispbe_node *node = video_drvdata(file);
+- struct pispbe_dev *pispbe = node->node_group->pispbe;
++ struct pispbe_dev *pispbe = node->pispbe;
+
+ if (!NODE_IS_CAPTURE(node) || NODE_IS_META(node)) {
+- dev_err(pispbe->dev,
++ dev_dbg(pispbe->dev,
+ "Cannot get capture fmt for output node %s\n",
+ NODE_NAME(node));
+ return -EINVAL;
+ }
++
+ *f = node->format;
+ dev_dbg(pispbe->dev, "Get capture format for node %s\n",
+ NODE_NAME(node));
++
+ return 0;
+ }
+
+@@ -1088,17 +1015,19 @@ static int pispbe_node_g_fmt_vid_out(str
+ struct v4l2_format *f)
+ {
+ struct pispbe_node *node = video_drvdata(file);
+- struct pispbe_dev *pispbe = node->node_group->pispbe;
++ struct pispbe_dev *pispbe = node->pispbe;
+
+ if (NODE_IS_CAPTURE(node) || NODE_IS_META(node)) {
+- dev_err(pispbe->dev,
++ dev_dbg(pispbe->dev,
+ "Cannot get capture fmt for output node %s\n",
+ NODE_NAME(node));
+ return -EINVAL;
+ }
++
+ *f = node->format;
+ dev_dbg(pispbe->dev, "Get output format for node %s\n",
+ NODE_NAME(node));
++
+ return 0;
+ }
+
+@@ -1106,98 +1035,42 @@ static int pispbe_node_g_fmt_meta_out(st
+ struct v4l2_format *f)
+ {
+ struct pispbe_node *node = video_drvdata(file);
+- struct pispbe_dev *pispbe = node->node_group->pispbe;
++ struct pispbe_dev *pispbe = node->pispbe;
+
+ if (!NODE_IS_META(node) || NODE_IS_CAPTURE(node)) {
+- dev_err(pispbe->dev,
++ dev_dbg(pispbe->dev,
+ "Cannot get capture fmt for meta output node %s\n",
+ NODE_NAME(node));
+ return -EINVAL;
+ }
+- *f = node->format;
+- dev_dbg(pispbe->dev, "Get output format for meta node %s\n",
+- NODE_NAME(node));
+- return 0;
+-}
+
+-static int pispbe_node_g_fmt_meta_cap(struct file *file, void *priv,
+- struct v4l2_format *f)
+-{
+- struct pispbe_node *node = video_drvdata(file);
+- struct pispbe_dev *pispbe = node->node_group->pispbe;
+-
+- if (!NODE_IS_META(node) || NODE_IS_OUTPUT(node)) {
+- dev_err(pispbe->dev,
+- "Cannot get capture fmt for meta output node %s\n",
+- NODE_NAME(node));
+- return -EINVAL;
+- }
+ *f = node->format;
+ dev_dbg(pispbe->dev, "Get output format for meta node %s\n",
+ NODE_NAME(node));
+- return 0;
+-}
+-
+-static int verify_be_pix_format(const struct v4l2_format *f,
+- struct pispbe_node *node)
+-{
+- struct pispbe_dev *pispbe = node->node_group->pispbe;
+- unsigned int nplanes = f->fmt.pix_mp.num_planes;
+- unsigned int i;
+-
+- if (f->fmt.pix_mp.width == 0 || f->fmt.pix_mp.height == 0) {
+- dev_err(pispbe->dev, "Details incorrect for output node %s\n",
+- NODE_NAME(node));
+- return -EINVAL;
+- }
+-
+- if (nplanes == 0 || nplanes > MAX_PLANES) {
+- dev_err(pispbe->dev,
+- "Bad number of planes for output node %s, req =%d\n",
+- NODE_NAME(node), nplanes);
+- return -EINVAL;
+- }
+-
+- for (i = 0; i < nplanes; i++) {
+- const struct v4l2_plane_pix_format *p;
+-
+- p = &f->fmt.pix_mp.plane_fmt[i];
+- if (p->bytesperline == 0 || p->sizeimage == 0) {
+- dev_err(pispbe->dev,
+- "Invalid plane %d for output node %s\n",
+- i, NODE_NAME(node));
+- return -EINVAL;
+- }
+- }
+
+ return 0;
+ }
+
+-static const struct pisp_be_format *find_format(unsigned int fourcc)
++static const struct pisp_be_format *pispbe_find_fmt(unsigned int fourcc)
+ {
+- const struct pisp_be_format *fmt;
+- unsigned int i;
+-
+- for (i = 0; i < ARRAY_SIZE(supported_formats); i++) {
+- fmt = &supported_formats[i];
+- if (fmt->fourcc == fourcc)
+- return fmt;
++ for (unsigned int i = 0; i < ARRAY_SIZE(supported_formats); i++) {
++ if (supported_formats[i].fourcc == fourcc)
++ return &supported_formats[i];
+ }
+
+ return NULL;
+ }
+
+-static void set_plane_params(struct v4l2_format *f,
+- const struct pisp_be_format *fmt)
++static void pispbe_set_plane_params(struct v4l2_format *f,
++ const struct pisp_be_format *fmt)
+ {
+ unsigned int nplanes = f->fmt.pix_mp.num_planes;
+ unsigned int total_plane_factor = 0;
+- unsigned int i;
+
+- for (i = 0; i < MAX_PLANES; i++)
++ for (unsigned int i = 0; i < PISPBE_MAX_PLANES; i++)
+ total_plane_factor += fmt->plane_factor[i];
+
+- for (i = 0; i < nplanes; i++) {
++ for (unsigned int i = 0; i < nplanes; i++) {
+ struct v4l2_plane_pix_format *p = &f->fmt.pix_mp.plane_fmt[i];
+ unsigned int bpl, plane_size;
+
+@@ -1217,28 +1090,25 @@ static void set_plane_params(struct v4l2
+ }
+ }
+
+-static int try_format(struct v4l2_format *f, struct pispbe_node *node)
++static void pispbe_try_format(struct v4l2_format *f, struct pispbe_node *node)
+ {
+- struct pispbe_dev *pispbe = node->node_group->pispbe;
++ struct pispbe_dev *pispbe = node->pispbe;
++ u32 pixfmt = f->fmt.pix_mp.pixelformat;
+ const struct pisp_be_format *fmt;
+- unsigned int i;
+ bool is_rgb;
+- u32 pixfmt = f->fmt.pix_mp.pixelformat;
+
+ dev_dbg(pispbe->dev,
+- "%s: [%s] req %ux%u " V4L2_FOURCC_CONV ", planes %d\n",
++ "%s: [%s] req %ux%u %p4cc, planes %d\n",
+ __func__, NODE_NAME(node), f->fmt.pix_mp.width,
+- f->fmt.pix_mp.height, V4L2_FOURCC_CONV_ARGS(pixfmt),
++ f->fmt.pix_mp.height, &pixfmt,
+ f->fmt.pix_mp.num_planes);
+
+- if (pixfmt == V4L2_PIX_FMT_RPI_BE)
+- return verify_be_pix_format(f, node);
+-
+- fmt = find_format(pixfmt);
++ fmt = pispbe_find_fmt(pixfmt);
+ if (!fmt) {
+- dev_dbg(pispbe->dev, "%s: [%s] Format not found, defaulting to YUV420\n",
++ dev_dbg(pispbe->dev,
++ "%s: [%s] Format not found, defaulting to YUV420\n",
+ __func__, NODE_NAME(node));
+- fmt = find_format(V4L2_PIX_FMT_YUV420);
++ fmt = pispbe_find_fmt(V4L2_PIX_FMT_YUV420);
+ }
+
+ f->fmt.pix_mp.pixelformat = fmt->fourcc;
+@@ -1254,7 +1124,8 @@ static int try_format(struct v4l2_format
+ * not supported. This also catches the case when the "default"
+ * colour space was requested (as that's never in the mask).
+ */
+- if (!(V4L2_COLORSPACE_MASK(f->fmt.pix_mp.colorspace) & fmt->colorspace_mask))
++ if (!(V4L2_COLORSPACE_MASK(f->fmt.pix_mp.colorspace) &
++ fmt->colorspace_mask))
+ f->fmt.pix_mp.colorspace = fmt->colorspace_default;
+
+ /* In all cases, we only support the defaults for these: */
+@@ -1269,9 +1140,9 @@ static int try_format(struct v4l2_format
+ f->fmt.pix_mp.ycbcr_enc);
+
+ /* Set plane size and bytes/line for each plane. */
+- set_plane_params(f, fmt);
++ pispbe_set_plane_params(f, fmt);
+
+- for (i = 0; i < f->fmt.pix_mp.num_planes; i++) {
++ for (unsigned int i = 0; i < f->fmt.pix_mp.num_planes; i++) {
+ dev_dbg(pispbe->dev,
+ "%s: [%s] calc plane %d, %ux%u, depth %u, bpl %u size %u\n",
+ __func__, NODE_NAME(node), i, f->fmt.pix_mp.width,
+@@ -1279,27 +1150,22 @@ static int try_format(struct v4l2_format
+ f->fmt.pix_mp.plane_fmt[i].bytesperline,
+ f->fmt.pix_mp.plane_fmt[i].sizeimage);
+ }
+-
+- return 0;
+ }
+
+ static int pispbe_node_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+ {
+ struct pispbe_node *node = video_drvdata(file);
+- struct pispbe_dev *pispbe = node->node_group->pispbe;
+- int ret;
++ struct pispbe_dev *pispbe = node->pispbe;
+
+ if (!NODE_IS_CAPTURE(node) || NODE_IS_META(node)) {
+- dev_err(pispbe->dev,
++ dev_dbg(pispbe->dev,
+ "Cannot set capture fmt for output node %s\n",
+ NODE_NAME(node));
+ return -EINVAL;
+ }
+
+- ret = try_format(f, node);
+- if (ret < 0)
+- return ret;
++ pispbe_try_format(f, node);
+
+ return 0;
+ }
+@@ -1308,19 +1174,16 @@ static int pispbe_node_try_fmt_vid_out(s
+ struct v4l2_format *f)
+ {
+ struct pispbe_node *node = video_drvdata(file);
+- struct pispbe_dev *pispbe = node->node_group->pispbe;
+- int ret;
++ struct pispbe_dev *pispbe = node->pispbe;
+
+ if (!NODE_IS_OUTPUT(node) || NODE_IS_META(node)) {
+- dev_err(pispbe->dev,
++ dev_dbg(pispbe->dev,
+ "Cannot set capture fmt for output node %s\n",
+ NODE_NAME(node));
+ return -EINVAL;
+ }
+
+- ret = try_format(f, node);
+- if (ret < 0)
+- return ret;
++ pispbe_try_format(f, node);
+
+ return 0;
+ }
+@@ -1329,10 +1192,10 @@ static int pispbe_node_try_fmt_meta_out(
+ struct v4l2_format *f)
+ {
+ struct pispbe_node *node = video_drvdata(file);
+- struct pispbe_dev *pispbe = node->node_group->pispbe;
++ struct pispbe_dev *pispbe = node->pispbe;
+
+ if (!NODE_IS_META(node) || NODE_IS_CAPTURE(node)) {
+- dev_err(pispbe->dev,
++ dev_dbg(pispbe->dev,
+ "Cannot set capture fmt for meta output node %s\n",
+ NODE_NAME(node));
+ return -EINVAL;
+@@ -1344,43 +1207,26 @@ static int pispbe_node_try_fmt_meta_out(
+ return 0;
+ }
+
+-static int pispbe_node_try_fmt_meta_cap(struct file *file, void *priv,
+- struct v4l2_format *f)
+-{
+- struct pispbe_node *node = video_drvdata(file);
+- struct pispbe_dev *pispbe = node->node_group->pispbe;
+-
+- if (!NODE_IS_META(node) || NODE_IS_OUTPUT(node)) {
+- dev_err(pispbe->dev,
+- "Cannot set capture fmt for meta output node %s\n",
+- NODE_NAME(node));
+- return -EINVAL;
+- }
+-
+- f->fmt.meta.dataformat = V4L2_PIX_FMT_RPI_BE;
+- if (!f->fmt.meta.buffersize)
+- f->fmt.meta.buffersize = BIT(20);
+-
+- return 0;
+-}
+-
+ static int pispbe_node_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+ {
+ struct pispbe_node *node = video_drvdata(file);
+- struct pispbe_dev *pispbe = node->node_group->pispbe;
+- int ret = pispbe_node_try_fmt_vid_cap(file, priv, f);
++ struct pispbe_dev *pispbe = node->pispbe;
++ int ret;
+
++ ret = pispbe_node_try_fmt_vid_cap(file, priv, f);
+ if (ret < 0)
+ return ret;
+
++ if (vb2_is_busy(&node->queue))
++ return -EBUSY;
++
+ node->format = *f;
+- node->pisp_format = find_format(f->fmt.pix_mp.pixelformat);
++ node->pisp_format = pispbe_find_fmt(f->fmt.pix_mp.pixelformat);
++
++ dev_dbg(pispbe->dev, "Set capture format for node %s to %p4cc\n",
++ NODE_NAME(node), &f->fmt.pix_mp.pixelformat);
+
+- dev_dbg(pispbe->dev,
+- "Set capture format for node %s to " V4L2_FOURCC_CONV "\n",
+- NODE_NAME(node),
+- V4L2_FOURCC_CONV_ARGS(f->fmt.pix_mp.pixelformat));
+ return 0;
+ }
+
+@@ -1388,19 +1234,22 @@ static int pispbe_node_s_fmt_vid_out(str
+ struct v4l2_format *f)
+ {
+ struct pispbe_node *node = video_drvdata(file);
+- struct pispbe_dev *pispbe = node->node_group->pispbe;
+- int ret = pispbe_node_try_fmt_vid_out(file, priv, f);
++ struct pispbe_dev *pispbe = node->pispbe;
++ int ret;
+
++ ret = pispbe_node_try_fmt_vid_out(file, priv, f);
+ if (ret < 0)
+ return ret;
+
++ if (vb2_is_busy(&node->queue))
++ return -EBUSY;
++
+ node->format = *f;
+- node->pisp_format = find_format(f->fmt.pix_mp.pixelformat);
++ node->pisp_format = pispbe_find_fmt(f->fmt.pix_mp.pixelformat);
++
++ dev_dbg(pispbe->dev, "Set output format for node %s to %p4cc\n",
++ NODE_NAME(node), &f->fmt.pix_mp.pixelformat);
+
+- dev_dbg(pispbe->dev,
+- "Set output format for node %s to " V4L2_FOURCC_CONV "\n",
+- NODE_NAME(node),
+- V4L2_FOURCC_CONV_ARGS(f->fmt.pix_mp.pixelformat));
+ return 0;
+ }
+
+@@ -1408,39 +1257,22 @@ static int pispbe_node_s_fmt_meta_out(st
+ struct v4l2_format *f)
+ {
+ struct pispbe_node *node = video_drvdata(file);
+- struct pispbe_dev *pispbe = node->node_group->pispbe;
+- int ret = pispbe_node_try_fmt_meta_out(file, priv, f);
++ struct pispbe_dev *pispbe = node->pispbe;
++ int ret;
+
++ ret = pispbe_node_try_fmt_meta_out(file, priv, f);
+ if (ret < 0)
+ return ret;
+
++ if (vb2_is_busy(&node->queue))
++ return -EBUSY;
++
+ node->format = *f;
+ node->pisp_format = &meta_out_supported_formats[0];
+
+- dev_dbg(pispbe->dev,
+- "Set output format for meta node %s to " V4L2_FOURCC_CONV "\n",
+- NODE_NAME(node),
+- V4L2_FOURCC_CONV_ARGS(f->fmt.meta.dataformat));
+- return 0;
+-}
+-
+-static int pispbe_node_s_fmt_meta_cap(struct file *file, void *priv,
+- struct v4l2_format *f)
+-{
+- struct pispbe_node *node = video_drvdata(file);
+- struct pispbe_dev *pispbe = node->node_group->pispbe;
+- int ret = pispbe_node_try_fmt_meta_cap(file, priv, f);
+-
+- if (ret < 0)
+- return ret;
+-
+- node->format = *f;
+- node->pisp_format = find_format(f->fmt.meta.dataformat);
++ dev_dbg(pispbe->dev, "Set output format for meta node %s to %p4cc\n",
++ NODE_NAME(node), &f->fmt.meta.dataformat);
+
+- dev_dbg(pispbe->dev,
+- "Set capture format for meta node %s to " V4L2_FOURCC_CONV "\n",
+- NODE_NAME(node),
+- V4L2_FOURCC_CONV_ARGS(f->fmt.meta.dataformat));
+ return 0;
+ }
+
+@@ -1456,10 +1288,7 @@ static int pispbe_node_enum_fmt(struct f
+ if (f->index)
+ return -EINVAL;
+
+- if (NODE_IS_OUTPUT(node))
+- f->pixelformat = V4L2_META_FMT_RPI_BE_CFG;
+- else
+- f->pixelformat = V4L2_PIX_FMT_RPI_BE;
++ f->pixelformat = V4L2_META_FMT_RPI_BE_CFG;
+ f->flags = 0;
+ return 0;
+ }
+@@ -1477,13 +1306,13 @@ static int pispbe_enum_framesizes(struct
+ struct v4l2_frmsizeenum *fsize)
+ {
+ struct pispbe_node *node = video_drvdata(file);
+- struct pispbe_dev *pispbe = node->node_group->pispbe;
++ struct pispbe_dev *pispbe = node->pispbe;
+
+ if (NODE_IS_META(node) || fsize->index)
+ return -EINVAL;
+
+- if (!find_format(fsize->pixel_format)) {
+- dev_err(pispbe->dev, "Invalid pixel code: %x\n",
++ if (!pispbe_find_fmt(fsize->pixel_format)) {
++ dev_dbg(pispbe->dev, "Invalid pixel code: %x\n",
+ fsize->pixel_format);
+ return -EINVAL;
+ }
+@@ -1500,49 +1329,19 @@ static int pispbe_enum_framesizes(struct
+ return 0;
+ }
+
+-static int pispbe_node_streamon(struct file *file, void *priv,
+- enum v4l2_buf_type type)
+-{
+- struct pispbe_node *node = video_drvdata(file);
+- struct pispbe_dev *pispbe = node->node_group->pispbe;
+-
+- /* Do we need a node->stream_lock mutex? */
+-
+- dev_dbg(pispbe->dev, "Stream on for node %s\n", NODE_NAME(node));
+-
+- /* Do we care about the type? Each node has only one queue. */
+-
+- INIT_LIST_HEAD(&node->ready_queue);
+-
+- /* locking should be handled by the queue->lock? */
+- return vb2_streamon(&node->queue, type);
+-}
+-
+-static int pispbe_node_streamoff(struct file *file, void *priv,
+- enum v4l2_buf_type type)
+-{
+- struct pispbe_node *node = video_drvdata(file);
+-
+- return vb2_streamoff(&node->queue, type);
+-}
+-
+ static const struct v4l2_ioctl_ops pispbe_node_ioctl_ops = {
+ .vidioc_querycap = pispbe_node_querycap,
+ .vidioc_g_fmt_vid_cap_mplane = pispbe_node_g_fmt_vid_cap,
+ .vidioc_g_fmt_vid_out_mplane = pispbe_node_g_fmt_vid_out,
+ .vidioc_g_fmt_meta_out = pispbe_node_g_fmt_meta_out,
+- .vidioc_g_fmt_meta_cap = pispbe_node_g_fmt_meta_cap,
+ .vidioc_try_fmt_vid_cap_mplane = pispbe_node_try_fmt_vid_cap,
+ .vidioc_try_fmt_vid_out_mplane = pispbe_node_try_fmt_vid_out,
+ .vidioc_try_fmt_meta_out = pispbe_node_try_fmt_meta_out,
+- .vidioc_try_fmt_meta_cap = pispbe_node_try_fmt_meta_cap,
+ .vidioc_s_fmt_vid_cap_mplane = pispbe_node_s_fmt_vid_cap,
+ .vidioc_s_fmt_vid_out_mplane = pispbe_node_s_fmt_vid_out,
+ .vidioc_s_fmt_meta_out = pispbe_node_s_fmt_meta_out,
+- .vidioc_s_fmt_meta_cap = pispbe_node_s_fmt_meta_cap,
+ .vidioc_enum_fmt_vid_cap = pispbe_node_enum_fmt,
+ .vidioc_enum_fmt_vid_out = pispbe_node_enum_fmt,
+- .vidioc_enum_fmt_meta_cap = pispbe_node_enum_fmt,
+ .vidioc_enum_fmt_meta_out = pispbe_node_enum_fmt,
+ .vidioc_enum_framesizes = pispbe_enum_framesizes,
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+@@ -1552,8 +1351,8 @@ static const struct v4l2_ioctl_ops pispb
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_expbuf = vb2_ioctl_expbuf,
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+- .vidioc_streamon = pispbe_node_streamon,
+- .vidioc_streamoff = pispbe_node_streamoff,
++ .vidioc_streamon = vb2_ioctl_streamon,
++ .vidioc_streamoff = vb2_ioctl_streamoff,
+ };
+
+ static const struct video_device pispbe_videodev = {
+@@ -1565,7 +1364,7 @@ static const struct video_device pispbe_
+ .release = video_device_release_empty,
+ };
+
+-static void node_set_default_format(struct pispbe_node *node)
++static void pispbe_node_def_fmt(struct pispbe_node *node)
+ {
+ if (NODE_IS_META(node) && NODE_IS_OUTPUT(node)) {
+ /* Config node */
+@@ -1574,44 +1373,35 @@ static void node_set_default_format(stru
+ f->fmt.meta.dataformat = V4L2_META_FMT_RPI_BE_CFG;
+ f->fmt.meta.buffersize = sizeof(struct pisp_be_tiles_config);
+ f->type = node->buf_type;
+- } else if (NODE_IS_META(node) && NODE_IS_CAPTURE(node)) {
+- /* HOG output node */
+- struct v4l2_format *f = &node->format;
+-
+- f->fmt.meta.dataformat = V4L2_PIX_FMT_RPI_BE;
+- f->fmt.meta.buffersize = BIT(20);
+- f->type = node->buf_type;
+ } else {
+- struct v4l2_format f = {0};
+-
+- f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_YUV420;
+- f.fmt.pix_mp.width = 1920;
+- f.fmt.pix_mp.height = 1080;
+- f.type = node->buf_type;
+- try_format(&f, node);
++ struct v4l2_format f = {
++ .fmt.pix_mp.pixelformat = V4L2_PIX_FMT_YUV420,
++ .fmt.pix_mp.width = 1920,
++ .fmt.pix_mp.height = 1080,
++ .type = node->buf_type,
++ };
++ pispbe_try_format(&f, node);
+ node->format = f;
+ }
+
+- node->pisp_format = find_format(node->format.fmt.pix_mp.pixelformat);
++ node->pisp_format = pispbe_find_fmt(node->format.fmt.pix_mp.pixelformat);
+ }
+
+ /*
+ * Initialise a struct pispbe_node and register it as /dev/video<N>
+ * to represent one of the PiSP Back End's input or output streams.
+ */
+-static int
+-pispbe_init_node(struct pispbe_node_group *node_group, unsigned int id)
++static int pispbe_init_node(struct pispbe_dev *pispbe, unsigned int id)
+ {
+ bool output = NODE_DESC_IS_OUTPUT(&node_desc[id]);
+- struct pispbe_node *node = &node_group->node[id];
+- struct pispbe_dev *pispbe = node_group->pispbe;
++ struct pispbe_node *node = &pispbe->node[id];
+ struct media_entity *entity = &node->vfd.entity;
+ struct video_device *vdev = &node->vfd;
+ struct vb2_queue *q = &node->queue;
+ int ret;
+
+ node->id = id;
+- node->node_group = node_group;
++ node->pispbe = pispbe;
+ node->buf_type = node_desc[id].buf_type;
+
+ mutex_init(&node->node_lock);
+@@ -1620,7 +1410,7 @@ pispbe_init_node(struct pispbe_node_grou
+ spin_lock_init(&node->ready_lock);
+
+ node->format.type = node->buf_type;
+- node_set_default_format(node);
++ pispbe_node_def_fmt(node);
+
+ q->type = node->buf_type;
+ q->io_modes = VB2_MMAP | VB2_DMABUF;
+@@ -1629,19 +1419,19 @@ pispbe_init_node(struct pispbe_node_grou
+ q->ops = &pispbe_node_queue_ops;
+ q->buf_struct_size = sizeof(struct pispbe_buffer);
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+- q->dev = node->node_group->pispbe->dev;
++ q->dev = pispbe->dev;
+ /* get V4L2 to handle node->queue locking */
+ q->lock = &node->queue_lock;
+
+ ret = vb2_queue_init(q);
+ if (ret < 0) {
+ dev_err(pispbe->dev, "vb2_queue_init failed\n");
+- return ret;
++ goto err_mutex_destroy;
+ }
+
+ *vdev = pispbe_videodev; /* default initialization */
+ strscpy(vdev->name, node_desc[id].ent_name, sizeof(vdev->name));
+- vdev->v4l2_dev = &node_group->v4l2_dev;
++ vdev->v4l2_dev = &pispbe->v4l2_dev;
+ vdev->vfl_dir = output ? VFL_DIR_TX : VFL_DIR_RX;
+ /* get V4L2 to serialise our ioctls */
+ vdev->lock = &node->node_lock;
+@@ -1657,8 +1447,7 @@ pispbe_init_node(struct pispbe_node_grou
+ goto err_unregister_queue;
+ }
+
+- ret = video_register_device(vdev, VFL_TYPE_VIDEO,
+- PISPBE_VIDEO_NODE_OFFSET);
++ ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
+ if (ret) {
+ dev_err(pispbe->dev,
+ "Failed to register video %s device node\n",
+@@ -1668,25 +1457,28 @@ pispbe_init_node(struct pispbe_node_grou
+ video_set_drvdata(vdev, node);
+
+ if (output)
+- ret = media_create_pad_link(entity, 0, &node_group->sd.entity,
++ ret = media_create_pad_link(entity, 0, &pispbe->sd.entity,
+ id, MEDIA_LNK_FL_IMMUTABLE |
+ MEDIA_LNK_FL_ENABLED);
+ else
+- ret = media_create_pad_link(&node_group->sd.entity, id, entity,
++ ret = media_create_pad_link(&pispbe->sd.entity, id, entity,
+ 0, MEDIA_LNK_FL_IMMUTABLE |
+ MEDIA_LNK_FL_ENABLED);
+ if (ret)
+ goto err_unregister_video_dev;
+
+- dev_info(pispbe->dev,
+- "%s device node registered as /dev/video%d\n",
+- NODE_NAME(node), node->vfd.num);
++ dev_dbg(pispbe->dev, "%s device node registered as /dev/video%d\n",
++ NODE_NAME(node), node->vfd.num);
++
+ return 0;
+
+ err_unregister_video_dev:
+ video_unregister_device(&node->vfd);
+ err_unregister_queue:
+ vb2_queue_release(&node->queue);
++err_mutex_destroy:
++ mutex_destroy(&node->node_lock);
++ mutex_destroy(&node->queue_lock);
+ return ret;
+ }
+
+@@ -1698,11 +1490,9 @@ static const struct v4l2_subdev_ops pisp
+ .pad = &pispbe_pad_ops,
+ };
+
+-static int pispbe_init_subdev(struct pispbe_node_group *node_group)
++static int pispbe_init_subdev(struct pispbe_dev *pispbe)
+ {
+- struct pispbe_dev *pispbe = node_group->pispbe;
+- struct v4l2_subdev *sd = &node_group->sd;
+- unsigned int i;
++ struct v4l2_subdev *sd = &pispbe->sd;
+ int ret;
+
+ v4l2_subdev_init(sd, &pispbe_sd_ops);
+@@ -1711,17 +1501,17 @@ static int pispbe_init_subdev(struct pis
+ sd->dev = pispbe->dev;
+ strscpy(sd->name, PISPBE_NAME, sizeof(sd->name));
+
+- for (i = 0; i < PISPBE_NUM_NODES; i++)
+- node_group->pad[i].flags =
++ for (unsigned int i = 0; i < PISPBE_NUM_NODES; i++)
++ pispbe->pad[i].flags =
+ NODE_DESC_IS_OUTPUT(&node_desc[i]) ?
+ MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
+
+ ret = media_entity_pads_init(&sd->entity, PISPBE_NUM_NODES,
+- node_group->pad);
++ pispbe->pad);
+ if (ret)
+ goto error;
+
+- ret = v4l2_device_register_subdev(&node_group->v4l2_dev, sd);
++ ret = v4l2_device_register_subdev(&pispbe->v4l2_dev, sd);
+ if (ret)
+ goto error;
+
+@@ -1732,45 +1522,36 @@ error:
+ return ret;
+ }
+
+-static int pispbe_init_group(struct pispbe_dev *pispbe, unsigned int id)
++static int pispbe_init_devices(struct pispbe_dev *pispbe)
+ {
+- struct pispbe_node_group *node_group = &pispbe->node_group[id];
+ struct v4l2_device *v4l2_dev;
+ struct media_device *mdev;
+- unsigned int num_registered = 0;
++ unsigned int num_regist;
+ int ret;
+
+- node_group->id = id;
+- node_group->pispbe = pispbe;
+- node_group->streaming_map = 0;
+-
+- dev_info(pispbe->dev, "Register nodes for group %u\n", id);
+-
+ /* Register v4l2_device and media_device */
+- mdev = &node_group->mdev;
+- mdev->hw_revision = node_group->pispbe->hw_version;
+- mdev->dev = node_group->pispbe->dev;
++ mdev = &pispbe->mdev;
++ mdev->hw_revision = pispbe->hw_version;
++ mdev->dev = pispbe->dev;
+ strscpy(mdev->model, PISPBE_NAME, sizeof(mdev->model));
+- snprintf(mdev->bus_info, sizeof(mdev->bus_info),
+- "platform:%s", dev_name(node_group->pispbe->dev));
+ media_device_init(mdev);
+
+- v4l2_dev = &node_group->v4l2_dev;
+- v4l2_dev->mdev = &node_group->mdev;
++ v4l2_dev = &pispbe->v4l2_dev;
++ v4l2_dev->mdev = &pispbe->mdev;
+ strscpy(v4l2_dev->name, PISPBE_NAME, sizeof(v4l2_dev->name));
+
+- ret = v4l2_device_register(pispbe->dev, &node_group->v4l2_dev);
++ ret = v4l2_device_register(pispbe->dev, v4l2_dev);
+ if (ret)
+ goto err_media_dev_cleanup;
+
+ /* Register the PISPBE subdevice. */
+- ret = pispbe_init_subdev(node_group);
++ ret = pispbe_init_subdev(pispbe);
+ if (ret)
+ goto err_unregister_v4l2;
+
+ /* Create device video nodes */
+- for (; num_registered < PISPBE_NUM_NODES; num_registered++) {
+- ret = pispbe_init_node(node_group, num_registered);
++ for (num_regist = 0; num_regist < PISPBE_NUM_NODES; num_regist++) {
++ ret = pispbe_init_node(pispbe, num_regist);
+ if (ret)
+ goto err_unregister_nodes;
+ }
+@@ -1779,12 +1560,12 @@ static int pispbe_init_group(struct pisp
+ if (ret)
+ goto err_unregister_nodes;
+
+- node_group->config =
++ pispbe->config =
+ dma_alloc_coherent(pispbe->dev,
+ sizeof(struct pisp_be_tiles_config) *
+ PISP_BE_NUM_CONFIG_BUFFERS,
+- &node_group->config_dma_addr, GFP_KERNEL);
+- if (!node_group->config) {
++ &pispbe->config_dma_addr, GFP_KERNEL);
++ if (!pispbe->config) {
+ dev_err(pispbe->dev, "Unable to allocate cached config buffers.\n");
+ ret = -ENOMEM;
+ goto err_unregister_mdev;
+@@ -1795,12 +1576,12 @@ static int pispbe_init_group(struct pisp
+ err_unregister_mdev:
+ media_device_unregister(mdev);
+ err_unregister_nodes:
+- while (num_registered-- > 0) {
+- video_unregister_device(&node_group->node[num_registered].vfd);
+- vb2_queue_release(&node_group->node[num_registered].queue);
++ while (num_regist-- > 0) {
++ video_unregister_device(&pispbe->node[num_regist].vfd);
++ vb2_queue_release(&pispbe->node[num_regist].queue);
+ }
+- v4l2_device_unregister_subdev(&node_group->sd);
+- media_entity_cleanup(&node_group->sd.entity);
++ v4l2_device_unregister_subdev(&pispbe->sd);
++ media_entity_cleanup(&pispbe->sd.entity);
+ err_unregister_v4l2:
+ v4l2_device_unregister(v4l2_dev);
+ err_media_dev_cleanup:
+@@ -1808,32 +1589,31 @@ err_media_dev_cleanup:
+ return ret;
+ }
+
+-static void pispbe_destroy_node_group(struct pispbe_node_group *node_group)
++static void pispbe_destroy_devices(struct pispbe_dev *pispbe)
+ {
+- struct pispbe_dev *pispbe = node_group->pispbe;
+- int i;
+-
+- if (node_group->config) {
+- dma_free_coherent(node_group->pispbe->dev,
++ if (pispbe->config) {
++ dma_free_coherent(pispbe->dev,
+ sizeof(struct pisp_be_tiles_config) *
+ PISP_BE_NUM_CONFIG_BUFFERS,
+- node_group->config,
+- node_group->config_dma_addr);
++ pispbe->config,
++ pispbe->config_dma_addr);
+ }
+
+- dev_info(pispbe->dev, "Unregister from media controller\n");
++ dev_dbg(pispbe->dev, "Unregister from media controller\n");
+
+- v4l2_device_unregister_subdev(&node_group->sd);
+- media_entity_cleanup(&node_group->sd.entity);
+- media_device_unregister(&node_group->mdev);
++ v4l2_device_unregister_subdev(&pispbe->sd);
++ media_entity_cleanup(&pispbe->sd.entity);
++ media_device_unregister(&pispbe->mdev);
+
+- for (i = PISPBE_NUM_NODES - 1; i >= 0; i--) {
+- video_unregister_device(&node_group->node[i].vfd);
+- vb2_queue_release(&node_group->node[i].queue);
++ for (int i = PISPBE_NUM_NODES - 1; i >= 0; i--) {
++ video_unregister_device(&pispbe->node[i].vfd);
++ vb2_queue_release(&pispbe->node[i].queue);
++ mutex_destroy(&pispbe->node[i].node_lock);
++ mutex_destroy(&pispbe->node[i].queue_lock);
+ }
+
+- media_device_cleanup(&node_group->mdev);
+- v4l2_device_unregister(&node_group->v4l2_dev);
++ media_device_cleanup(&pispbe->mdev);
++ v4l2_device_unregister(&pispbe->v4l2_dev);
+ }
+
+ static int pispbe_runtime_suspend(struct device *dev)
+@@ -1862,13 +1642,48 @@ static int pispbe_runtime_resume(struct
+ return 0;
+ }
+
+-/*
+- * Probe the ISP-BE hardware block, as a single platform device.
+- * This will instantiate multiple "node groups" each with many device nodes.
+- */
++static int pispbe_hw_init(struct pispbe_dev *pispbe)
++{
++ u32 u;
++
++ /* Check the HW is present and has a known version */
++ u = pispbe_rd(pispbe, PISP_BE_VERSION_REG);
++ dev_dbg(pispbe->dev, "pispbe_probe: HW version: 0x%08x", u);
++ pispbe->hw_version = u;
++ if ((u & ~PISP_BE_VERSION_MINOR_BITS) != PISP_BE_VERSION_2712)
++ return -ENODEV;
++
++ /* Clear leftover interrupts */
++ pispbe_wr(pispbe, PISP_BE_INTERRUPT_STATUS_REG, 0xFFFFFFFFu);
++ u = pispbe_rd(pispbe, PISP_BE_BATCH_STATUS_REG);
++ dev_dbg(pispbe->dev, "pispbe_probe: BatchStatus: 0x%08x", u);
++
++ pispbe->done = (uint8_t)u;
++ pispbe->started = (uint8_t)(u >> 8);
++ u = pispbe_rd(pispbe, PISP_BE_STATUS_REG);
++ dev_dbg(pispbe->dev, "pispbe_probe: Status: 0x%08x", u);
++
++ if (u != 0 || pispbe->done != pispbe->started) {
++ dev_err(pispbe->dev, "pispbe_probe: HW is stuck or busy\n");
++ return -EBUSY;
++ }
++
++ /*
++ * AXI QOS=0, CACHE=4'b0010, PROT=3'b011
++ * Also set "chicken bits" 22:20 which enable sub-64-byte bursts
++ * and AXI AWID/BID variability (on versions which support this).
++ */
++ pispbe_wr(pispbe, PISP_BE_AXI_REG, 0x32703200u);
++
++ /* Enable both interrupt flags */
++ pispbe_wr(pispbe, PISP_BE_INTERRUPT_EN_REG, 0x00000003u);
++
++ return 0;
++}
++
++/* Probe the ISP-BE hardware block, as a single platform device. */
+ static int pispbe_probe(struct platform_device *pdev)
+ {
+- unsigned int num_groups = 0;
+ struct pispbe_dev *pispbe;
+ int ret;
+
+@@ -1913,55 +1728,43 @@ static int pispbe_probe(struct platform_
+ pm_runtime_use_autosuspend(pispbe->dev);
+ pm_runtime_enable(pispbe->dev);
+
+- ret = pm_runtime_resume_and_get(pispbe->dev);
++ ret = pispbe_runtime_resume(pispbe->dev);
+ if (ret)
+ goto pm_runtime_disable_err;
+
+- pispbe->hw_busy = 0;
++ pispbe->hw_busy = false;
+ spin_lock_init(&pispbe->hw_lock);
+- ret = hw_init(pispbe);
++ ret = pispbe_hw_init(pispbe);
+ if (ret)
+- goto pm_runtime_put_err;
++ goto pm_runtime_suspend_err;
+
+- /*
+- * Initialise and register devices for each node_group, including media
+- * device
+- */
+- for (num_groups = 0;
+- num_groups < PISPBE_NUM_NODE_GROUPS;
+- num_groups++) {
+- ret = pispbe_init_group(pispbe, num_groups);
+- if (ret)
+- goto disable_nodes_err;
+- }
++ ret = pispbe_init_devices(pispbe);
++ if (ret)
++ goto disable_devs_err;
+
+ pm_runtime_mark_last_busy(pispbe->dev);
+ pm_runtime_put_autosuspend(pispbe->dev);
+
+ return 0;
+
+-disable_nodes_err:
+- while (num_groups-- > 0)
+- pispbe_destroy_node_group(&pispbe->node_group[num_groups]);
+-pm_runtime_put_err:
+- pm_runtime_put(pispbe->dev);
++disable_devs_err:
++ pispbe_destroy_devices(pispbe);
++pm_runtime_suspend_err:
++ pispbe_runtime_suspend(pispbe->dev);
+ pm_runtime_disable_err:
+ pm_runtime_dont_use_autosuspend(pispbe->dev);
+ pm_runtime_disable(pispbe->dev);
+
+- dev_err(&pdev->dev, "%s: returning %d", __func__, ret);
+-
+ return ret;
+ }
+
+ static int pispbe_remove(struct platform_device *pdev)
+ {
+ struct pispbe_dev *pispbe = platform_get_drvdata(pdev);
+- int i;
+
+- for (i = PISPBE_NUM_NODE_GROUPS - 1; i >= 0; i--)
+- pispbe_destroy_node_group(&pispbe->node_group[i]);
++ pispbe_destroy_devices(pispbe);
+
++ pispbe_runtime_suspend(pispbe->dev);
+ pm_runtime_dont_use_autosuspend(pispbe->dev);
+ pm_runtime_disable(pispbe->dev);
+
+@@ -1991,3 +1794,8 @@ static struct platform_driver pispbe_pdr
+ };
+
+ module_platform_driver(pispbe_pdrv);
++
++MODULE_DESCRIPTION("PiSP Back End driver");
++MODULE_AUTHOR("David Plowman <david.plowman@raspberrypi.com>");
++MODULE_AUTHOR("Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>");
++MODULE_LICENSE("GPL");
+--- a/drivers/media/platform/raspberrypi/pisp_be/pisp_be_config.h
++++ /dev/null
+@@ -1,533 +0,0 @@
+-/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
+-/*
+- * PiSP Back End configuration definitions.
+- *
+- * Copyright (C) 2021 - Raspberry Pi Ltd
+- *
+- */
+-#ifndef _PISP_BE_CONFIG_H_
+-#define _PISP_BE_CONFIG_H_
+-
+-#include <linux/types.h>
+-
+-#include <media/raspberrypi/pisp_common.h>
+-
+-/* byte alignment for inputs */
+-#define PISP_BACK_END_INPUT_ALIGN 4u
+-/* alignment for compressed inputs */
+-#define PISP_BACK_END_COMPRESSED_ALIGN 8u
+-/* minimum required byte alignment for outputs */
+-#define PISP_BACK_END_OUTPUT_MIN_ALIGN 16u
+-/* preferred byte alignment for outputs */
+-#define PISP_BACK_END_OUTPUT_MAX_ALIGN 64u
+-
+-/* minimum allowed tile width anywhere in the pipeline */
+-#define PISP_BACK_END_MIN_TILE_WIDTH 16u
+-/* minimum allowed tile width anywhere in the pipeline */
+-#define PISP_BACK_END_MIN_TILE_HEIGHT 16u
+-
+-#define PISP_BACK_END_NUM_OUTPUTS 2
+-#define PISP_BACK_END_HOG_OUTPUT 1
+-
+-#define PISP_BACK_END_NUM_TILES 64
+-
+-enum pisp_be_bayer_enable {
+- PISP_BE_BAYER_ENABLE_INPUT = 0x000001,
+- PISP_BE_BAYER_ENABLE_DECOMPRESS = 0x000002,
+- PISP_BE_BAYER_ENABLE_DPC = 0x000004,
+- PISP_BE_BAYER_ENABLE_GEQ = 0x000008,
+- PISP_BE_BAYER_ENABLE_TDN_INPUT = 0x000010,
+- PISP_BE_BAYER_ENABLE_TDN_DECOMPRESS = 0x000020,
+- PISP_BE_BAYER_ENABLE_TDN = 0x000040,
+- PISP_BE_BAYER_ENABLE_TDN_COMPRESS = 0x000080,
+- PISP_BE_BAYER_ENABLE_TDN_OUTPUT = 0x000100,
+- PISP_BE_BAYER_ENABLE_SDN = 0x000200,
+- PISP_BE_BAYER_ENABLE_BLC = 0x000400,
+- PISP_BE_BAYER_ENABLE_STITCH_INPUT = 0x000800,
+- PISP_BE_BAYER_ENABLE_STITCH_DECOMPRESS = 0x001000,
+- PISP_BE_BAYER_ENABLE_STITCH = 0x002000,
+- PISP_BE_BAYER_ENABLE_STITCH_COMPRESS = 0x004000,
+- PISP_BE_BAYER_ENABLE_STITCH_OUTPUT = 0x008000,
+- PISP_BE_BAYER_ENABLE_WBG = 0x010000,
+- PISP_BE_BAYER_ENABLE_CDN = 0x020000,
+- PISP_BE_BAYER_ENABLE_LSC = 0x040000,
+- PISP_BE_BAYER_ENABLE_TONEMAP = 0x080000,
+- PISP_BE_BAYER_ENABLE_CAC = 0x100000,
+- PISP_BE_BAYER_ENABLE_DEBIN = 0x200000,
+- PISP_BE_BAYER_ENABLE_DEMOSAIC = 0x400000,
+-};
+-
+-enum pisp_be_rgb_enable {
+- PISP_BE_RGB_ENABLE_INPUT = 0x000001,
+- PISP_BE_RGB_ENABLE_CCM = 0x000002,
+- PISP_BE_RGB_ENABLE_SAT_CONTROL = 0x000004,
+- PISP_BE_RGB_ENABLE_YCBCR = 0x000008,
+- PISP_BE_RGB_ENABLE_FALSE_COLOUR = 0x000010,
+- PISP_BE_RGB_ENABLE_SHARPEN = 0x000020,
+- /* Preferred colours would occupy 0x000040 */
+- PISP_BE_RGB_ENABLE_YCBCR_INVERSE = 0x000080,
+- PISP_BE_RGB_ENABLE_GAMMA = 0x000100,
+- PISP_BE_RGB_ENABLE_CSC0 = 0x000200,
+- PISP_BE_RGB_ENABLE_CSC1 = 0x000400,
+- PISP_BE_RGB_ENABLE_DOWNSCALE0 = 0x001000,
+- PISP_BE_RGB_ENABLE_DOWNSCALE1 = 0x002000,
+- PISP_BE_RGB_ENABLE_RESAMPLE0 = 0x008000,
+- PISP_BE_RGB_ENABLE_RESAMPLE1 = 0x010000,
+- PISP_BE_RGB_ENABLE_OUTPUT0 = 0x040000,
+- PISP_BE_RGB_ENABLE_OUTPUT1 = 0x080000,
+- PISP_BE_RGB_ENABLE_HOG = 0x200000
+-};
+-
+-#define PISP_BE_RGB_ENABLE_CSC(i) (PISP_BE_RGB_ENABLE_CSC0 << (i))
+-#define PISP_BE_RGB_ENABLE_DOWNSCALE(i) (PISP_BE_RGB_ENABLE_DOWNSCALE0 << (i))
+-#define PISP_BE_RGB_ENABLE_RESAMPLE(i) (PISP_BE_RGB_ENABLE_RESAMPLE0 << (i))
+-#define PISP_BE_RGB_ENABLE_OUTPUT(i) (PISP_BE_RGB_ENABLE_OUTPUT0 << (i))
+-
+-/*
+- * We use the enable flags to show when blocks are "dirty", but we need some
+- * extra ones too.
+- */
+-enum pisp_be_dirty {
+- PISP_BE_DIRTY_GLOBAL = 0x0001,
+- PISP_BE_DIRTY_SH_FC_COMBINE = 0x0002,
+- PISP_BE_DIRTY_CROP = 0x0004
+-};
+-
+-struct pisp_be_global_config {
+- u32 bayer_enables;
+- u32 rgb_enables;
+- u8 bayer_order;
+- u8 pad[3];
+-};
+-
+-struct pisp_be_input_buffer_config {
+- /* low 32 bits followed by high 32 bits (for each of up to 3 planes) */
+- u32 addr[3][2];
+-};
+-
+-struct pisp_be_dpc_config {
+- u8 coeff_level;
+- u8 coeff_range;
+- u8 pad;
+-#define PISP_BE_DPC_FLAG_FOLDBACK 1
+- u8 flags;
+-};
+-
+-struct pisp_be_geq_config {
+- u16 offset;
+-#define PISP_BE_GEQ_SHARPER BIT(15)
+-#define PISP_BE_GEQ_SLOPE ((1 << 10) - 1)
+- /* top bit is the "sharper" flag, slope value is bottom 10 bits */
+- u16 slope_sharper;
+- u16 min;
+- u16 max;
+-};
+-
+-struct pisp_be_tdn_input_buffer_config {
+- /* low 32 bits followed by high 32 bits */
+- u32 addr[2];
+-};
+-
+-struct pisp_be_tdn_config {
+- u16 black_level;
+- u16 ratio;
+- u16 noise_constant;
+- u16 noise_slope;
+- u16 threshold;
+- u8 reset;
+- u8 pad;
+-};
+-
+-struct pisp_be_tdn_output_buffer_config {
+- /* low 32 bits followed by high 32 bits */
+- u32 addr[2];
+-};
+-
+-struct pisp_be_sdn_config {
+- u16 black_level;
+- u8 leakage;
+- u8 pad;
+- u16 noise_constant;
+- u16 noise_slope;
+- u16 noise_constant2;
+- u16 noise_slope2;
+-};
+-
+-struct pisp_be_stitch_input_buffer_config {
+- /* low 32 bits followed by high 32 bits */
+- u32 addr[2];
+-};
+-
+-#define PISP_BE_STITCH_STREAMING_LONG 0x8000
+-#define PISP_BE_STITCH_EXPOSURE_RATIO_MASK 0x7fff
+-
+-struct pisp_be_stitch_config {
+- u16 threshold_lo;
+- u8 threshold_diff_power;
+- u8 pad;
+-
+- /* top bit indicates whether streaming input is the long exposure */
+- u16 exposure_ratio;
+-
+- u8 motion_threshold_256;
+- u8 motion_threshold_recip;
+-};
+-
+-struct pisp_be_stitch_output_buffer_config {
+- /* low 32 bits followed by high 32 bits */
+- u32 addr[2];
+-};
+-
+-struct pisp_be_cdn_config {
+- u16 thresh;
+- u8 iir_strength;
+- u8 g_adjust;
+-};
+-
+-#define PISP_BE_LSC_LOG_GRID_SIZE 5
+-#define PISP_BE_LSC_GRID_SIZE (1 << PISP_BE_LSC_LOG_GRID_SIZE)
+-#define PISP_BE_LSC_STEP_PRECISION 18
+-
+-struct pisp_be_lsc_config {
+- /* (1<<18) / grid_cell_width */
+- u16 grid_step_x;
+- /* (1<<18) / grid_cell_height */
+- u16 grid_step_y;
+- /* RGB gains jointly encoded in 32 bits */
+- u32 lut_packed[PISP_BE_LSC_GRID_SIZE + 1]
+- [PISP_BE_LSC_GRID_SIZE + 1];
+-};
+-
+-struct pisp_be_lsc_extra {
+- u16 offset_x;
+- u16 offset_y;
+-};
+-
+-#define PISP_BE_CAC_LOG_GRID_SIZE 3
+-#define PISP_BE_CAC_GRID_SIZE (1 << PISP_BE_CAC_LOG_GRID_SIZE)
+-#define PISP_BE_CAC_STEP_PRECISION 20
+-
+-struct pisp_be_cac_config {
+- /* (1<<20) / grid_cell_width */
+- u16 grid_step_x;
+- /* (1<<20) / grid_cell_height */
+- u16 grid_step_y;
+- /* [gridy][gridx][rb][xy] */
+- s8 lut[PISP_BE_CAC_GRID_SIZE + 1][PISP_BE_CAC_GRID_SIZE + 1][2][2];
+-};
+-
+-struct pisp_be_cac_extra {
+- u16 offset_x;
+- u16 offset_y;
+-};
+-
+-#define PISP_BE_DEBIN_NUM_COEFFS 4
+-
+-struct pisp_be_debin_config {
+- s8 coeffs[PISP_BE_DEBIN_NUM_COEFFS];
+- s8 h_enable;
+- s8 v_enable;
+- s8 pad[2];
+-};
+-
+-#define PISP_BE_TONEMAP_LUT_SIZE 64
+-
+-struct pisp_be_tonemap_config {
+- u16 detail_constant;
+- u16 detail_slope;
+- u16 iir_strength;
+- u16 strength;
+- u32 lut[PISP_BE_TONEMAP_LUT_SIZE];
+-};
+-
+-struct pisp_be_demosaic_config {
+- u8 sharper;
+- u8 fc_mode;
+- u8 pad[2];
+-};
+-
+-struct pisp_be_ccm_config {
+- s16 coeffs[9];
+- u8 pad[2];
+- s32 offsets[3];
+-};
+-
+-struct pisp_be_sat_control_config {
+- u8 shift_r;
+- u8 shift_g;
+- u8 shift_b;
+- u8 pad;
+-};
+-
+-struct pisp_be_false_colour_config {
+- u8 distance;
+- u8 pad[3];
+-};
+-
+-#define PISP_BE_SHARPEN_SIZE 5
+-#define PISP_BE_SHARPEN_FUNC_NUM_POINTS 9
+-
+-struct pisp_be_sharpen_config {
+- s8 kernel0[PISP_BE_SHARPEN_SIZE * PISP_BE_SHARPEN_SIZE];
+- s8 pad0[3];
+- s8 kernel1[PISP_BE_SHARPEN_SIZE * PISP_BE_SHARPEN_SIZE];
+- s8 pad1[3];
+- s8 kernel2[PISP_BE_SHARPEN_SIZE * PISP_BE_SHARPEN_SIZE];
+- s8 pad2[3];
+- s8 kernel3[PISP_BE_SHARPEN_SIZE * PISP_BE_SHARPEN_SIZE];
+- s8 pad3[3];
+- s8 kernel4[PISP_BE_SHARPEN_SIZE * PISP_BE_SHARPEN_SIZE];
+- s8 pad4[3];
+- u16 threshold_offset0;
+- u16 threshold_slope0;
+- u16 scale0;
+- u16 pad5;
+- u16 threshold_offset1;
+- u16 threshold_slope1;
+- u16 scale1;
+- u16 pad6;
+- u16 threshold_offset2;
+- u16 threshold_slope2;
+- u16 scale2;
+- u16 pad7;
+- u16 threshold_offset3;
+- u16 threshold_slope3;
+- u16 scale3;
+- u16 pad8;
+- u16 threshold_offset4;
+- u16 threshold_slope4;
+- u16 scale4;
+- u16 pad9;
+- u16 positive_strength;
+- u16 positive_pre_limit;
+- u16 positive_func[PISP_BE_SHARPEN_FUNC_NUM_POINTS];
+- u16 positive_limit;
+- u16 negative_strength;
+- u16 negative_pre_limit;
+- u16 negative_func[PISP_BE_SHARPEN_FUNC_NUM_POINTS];
+- u16 negative_limit;
+- u8 enables;
+- u8 white;
+- u8 black;
+- u8 grey;
+-};
+-
+-struct pisp_be_sh_fc_combine_config {
+- u8 y_factor;
+- u8 c1_factor;
+- u8 c2_factor;
+- u8 pad;
+-};
+-
+-#define PISP_BE_GAMMA_LUT_SIZE 64
+-
+-struct pisp_be_gamma_config {
+- u32 lut[PISP_BE_GAMMA_LUT_SIZE];
+-};
+-
+-struct pisp_be_crop_config {
+- u16 offset_x, offset_y;
+- u16 width, height;
+-};
+-
+-#define PISP_BE_RESAMPLE_FILTER_SIZE 96
+-
+-struct pisp_be_resample_config {
+- u16 scale_factor_h, scale_factor_v;
+- s16 coef[PISP_BE_RESAMPLE_FILTER_SIZE];
+-};
+-
+-struct pisp_be_resample_extra {
+- u16 scaled_width;
+- u16 scaled_height;
+- s16 initial_phase_h[3];
+- s16 initial_phase_v[3];
+-};
+-
+-struct pisp_be_downscale_config {
+- u16 scale_factor_h;
+- u16 scale_factor_v;
+- u16 scale_recip_h;
+- u16 scale_recip_v;
+-};
+-
+-struct pisp_be_downscale_extra {
+- u16 scaled_width;
+- u16 scaled_height;
+-};
+-
+-struct pisp_be_hog_config {
+- u8 compute_signed;
+- u8 channel_mix[3];
+- u32 stride;
+-};
+-
+-struct pisp_be_axi_config {
+- u8 r_qos; /* Read QoS */
+- u8 r_cache_prot; /* Read { prot[2:0], cache[3:0] } */
+- u8 w_qos; /* Write QoS */
+- u8 w_cache_prot; /* Write { prot[2:0], cache[3:0] } */
+-};
+-
+-enum pisp_be_transform {
+- PISP_BE_TRANSFORM_NONE = 0x0,
+- PISP_BE_TRANSFORM_HFLIP = 0x1,
+- PISP_BE_TRANSFORM_VFLIP = 0x2,
+- PISP_BE_TRANSFORM_ROT180 =
+- (PISP_BE_TRANSFORM_HFLIP | PISP_BE_TRANSFORM_VFLIP)
+-};
+-
+-struct pisp_be_output_format_config {
+- struct pisp_image_format_config image;
+- u8 transform;
+- u8 pad[3];
+- u16 lo;
+- u16 hi;
+- u16 lo2;
+- u16 hi2;
+-};
+-
+-struct pisp_be_output_buffer_config {
+- /* low 32 bits followed by high 32 bits (for each of 3 planes) */
+- u32 addr[3][2];
+-};
+-
+-struct pisp_be_hog_buffer_config {
+- /* low 32 bits followed by high 32 bits */
+- u32 addr[2];
+-};
+-
+-struct pisp_be_config {
+- /* I/O configuration: */
+- struct pisp_be_input_buffer_config input_buffer;
+- struct pisp_be_tdn_input_buffer_config tdn_input_buffer;
+- struct pisp_be_stitch_input_buffer_config stitch_input_buffer;
+- struct pisp_be_tdn_output_buffer_config tdn_output_buffer;
+- struct pisp_be_stitch_output_buffer_config stitch_output_buffer;
+- struct pisp_be_output_buffer_config
+- output_buffer[PISP_BACK_END_NUM_OUTPUTS];
+- struct pisp_be_hog_buffer_config hog_buffer;
+- /* Processing configuration: */
+- struct pisp_be_global_config global;
+- struct pisp_image_format_config input_format;
+- struct pisp_decompress_config decompress;
+- struct pisp_be_dpc_config dpc;
+- struct pisp_be_geq_config geq;
+- struct pisp_image_format_config tdn_input_format;
+- struct pisp_decompress_config tdn_decompress;
+- struct pisp_be_tdn_config tdn;
+- struct pisp_compress_config tdn_compress;
+- struct pisp_image_format_config tdn_output_format;
+- struct pisp_be_sdn_config sdn;
+- struct pisp_bla_config blc;
+- struct pisp_compress_config stitch_compress;
+- struct pisp_image_format_config stitch_output_format;
+- struct pisp_image_format_config stitch_input_format;
+- struct pisp_decompress_config stitch_decompress;
+- struct pisp_be_stitch_config stitch;
+- struct pisp_be_lsc_config lsc;
+- struct pisp_wbg_config wbg;
+- struct pisp_be_cdn_config cdn;
+- struct pisp_be_cac_config cac;
+- struct pisp_be_debin_config debin;
+- struct pisp_be_tonemap_config tonemap;
+- struct pisp_be_demosaic_config demosaic;
+- struct pisp_be_ccm_config ccm;
+- struct pisp_be_sat_control_config sat_control;
+- struct pisp_be_ccm_config ycbcr;
+- struct pisp_be_sharpen_config sharpen;
+- struct pisp_be_false_colour_config false_colour;
+- struct pisp_be_sh_fc_combine_config sh_fc_combine;
+- struct pisp_be_ccm_config ycbcr_inverse;
+- struct pisp_be_gamma_config gamma;
+- struct pisp_be_ccm_config csc[PISP_BACK_END_NUM_OUTPUTS];
+- struct pisp_be_downscale_config downscale[PISP_BACK_END_NUM_OUTPUTS];
+- struct pisp_be_resample_config resample[PISP_BACK_END_NUM_OUTPUTS];
+- struct pisp_be_output_format_config
+- output_format[PISP_BACK_END_NUM_OUTPUTS];
+- struct pisp_be_hog_config hog;
+- struct pisp_be_axi_config axi;
+- /* Non-register fields: */
+- struct pisp_be_lsc_extra lsc_extra;
+- struct pisp_be_cac_extra cac_extra;
+- struct pisp_be_downscale_extra
+- downscale_extra[PISP_BACK_END_NUM_OUTPUTS];
+- struct pisp_be_resample_extra resample_extra[PISP_BACK_END_NUM_OUTPUTS];
+- struct pisp_be_crop_config crop;
+- struct pisp_image_format_config hog_format;
+- u32 dirty_flags_bayer; /* these use pisp_be_bayer_enable */
+- u32 dirty_flags_rgb; /* use pisp_be_rgb_enable */
+- u32 dirty_flags_extra; /* these use pisp_be_dirty_t */
+-};
+-
+-/*
+- * We also need a tile structure to describe the size of the tiles going
+- * through the pipeline.
+- */
+-
+-enum pisp_tile_edge {
+- PISP_LEFT_EDGE = (1 << 0),
+- PISP_RIGHT_EDGE = (1 << 1),
+- PISP_TOP_EDGE = (1 << 2),
+- PISP_BOTTOM_EDGE = (1 << 3)
+-};
+-
+-struct pisp_tile {
+- u8 edge; // enum pisp_tile_edge
+- u8 pad0[3];
+- // 4 bytes
+- u32 input_addr_offset;
+- u32 input_addr_offset2;
+- u16 input_offset_x;
+- u16 input_offset_y;
+- u16 input_width;
+- u16 input_height;
+- // 20 bytes
+- u32 tdn_input_addr_offset;
+- u32 tdn_output_addr_offset;
+- u32 stitch_input_addr_offset;
+- u32 stitch_output_addr_offset;
+- // 36 bytes
+- u32 lsc_grid_offset_x;
+- u32 lsc_grid_offset_y;
+- // 44 bytes
+- u32 cac_grid_offset_x;
+- u32 cac_grid_offset_y;
+- // 52 bytes
+- u16 crop_x_start[PISP_BACK_END_NUM_OUTPUTS];
+- u16 crop_x_end[PISP_BACK_END_NUM_OUTPUTS];
+- u16 crop_y_start[PISP_BACK_END_NUM_OUTPUTS];
+- u16 crop_y_end[PISP_BACK_END_NUM_OUTPUTS];
+- // 68 bytes
+- /* Ordering is planes then branches */
+- u16 downscale_phase_x[3 * PISP_BACK_END_NUM_OUTPUTS];
+- u16 downscale_phase_y[3 * PISP_BACK_END_NUM_OUTPUTS];
+- // 92 bytes
+- u16 resample_in_width[PISP_BACK_END_NUM_OUTPUTS];
+- u16 resample_in_height[PISP_BACK_END_NUM_OUTPUTS];
+- // 100 bytes
+- /* Ordering is planes then branches */
+- u16 resample_phase_x[3 * PISP_BACK_END_NUM_OUTPUTS];
+- u16 resample_phase_y[3 * PISP_BACK_END_NUM_OUTPUTS];
+- // 124 bytes
+- u16 output_offset_x[PISP_BACK_END_NUM_OUTPUTS];
+- u16 output_offset_y[PISP_BACK_END_NUM_OUTPUTS];
+- u16 output_width[PISP_BACK_END_NUM_OUTPUTS];
+- u16 output_height[PISP_BACK_END_NUM_OUTPUTS];
+- // 140 bytes
+- u32 output_addr_offset[PISP_BACK_END_NUM_OUTPUTS];
+- u32 output_addr_offset2[PISP_BACK_END_NUM_OUTPUTS];
+- // 156 bytes
+- u32 output_hog_addr_offset;
+- // 160 bytes
+-};
+-
+-static_assert(sizeof(struct pisp_tile) == 160);
+-
+-struct pisp_be_tiles_config {
+- struct pisp_be_config config;
+- struct pisp_tile tiles[PISP_BACK_END_NUM_TILES];
+- int num_tiles;
+-};
+-
+-#endif /* _PISP_BE_CONFIG_H_ */
+--- a/drivers/media/platform/raspberrypi/pisp_be/pisp_be_formats.h
++++ b/drivers/media/platform/raspberrypi/pisp_be/pisp_be_formats.h
+@@ -2,7 +2,7 @@
+ /*
+ * PiSP Back End driver image format definitions.
+ *
+- * Copyright (c) 2021 Raspberry Pi Ltd
++ * Copyright (c) 2021-2024 Raspberry Pi Ltd
+ */
+
+ #ifndef _PISP_BE_FORMATS_
+@@ -11,15 +11,15 @@
+ #include <linux/bits.h>
+ #include <linux/videodev2.h>
+
+-#define MAX_PLANES 3
+-#define P3(x) ((x) * 8)
++#define PISPBE_MAX_PLANES 3
++#define P3(x) ((x) * 8)
+
+ struct pisp_be_format {
+ unsigned int fourcc;
+ unsigned int align;
+ unsigned int bit_depth;
+ /* 0P3 factor for plane sizing */
+- unsigned int plane_factor[MAX_PLANES];
++ unsigned int plane_factor[PISPBE_MAX_PLANES];
+ unsigned int num_planes;
+ unsigned int colorspace_mask;
+ enum v4l2_colorspace colorspace_default;
+@@ -27,14 +27,19 @@ struct pisp_be_format {
+
+ #define V4L2_COLORSPACE_MASK(colorspace) BIT(colorspace)
+
+-#define V4L2_COLORSPACE_MASK_JPEG V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_JPEG)
+-#define V4L2_COLORSPACE_MASK_SMPTE170M V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_SMPTE170M)
+-#define V4L2_COLORSPACE_MASK_REC709 V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_REC709)
+-#define V4L2_COLORSPACE_MASK_SRGB V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_SRGB)
+-#define V4L2_COLORSPACE_MASK_RAW V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_RAW)
++#define V4L2_COLORSPACE_MASK_JPEG \
++ V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_JPEG)
++#define V4L2_COLORSPACE_MASK_SMPTE170M \
++ V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_SMPTE170M)
++#define V4L2_COLORSPACE_MASK_REC709 \
++ V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_REC709)
++#define V4L2_COLORSPACE_MASK_SRGB \
++ V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_SRGB)
++#define V4L2_COLORSPACE_MASK_RAW \
++ V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_RAW)
+
+ /*
+- * All three colour spaces JPEG, SMPTE170M and REC709 are fundamentally sRGB
++ * All three colour spaces SRGB, SMPTE170M and REC709 are fundamentally sRGB
+ * underneath (as near as makes no difference to us), just with different YCbCr
+ * encodings. Therefore the ISP can generate sRGB on its main output and any of
+ * the others on its low resolution output. Applications should, when using both
+@@ -43,9 +48,9 @@ struct pisp_be_format {
+ * producing an RGB format. In turn this requires us to allow all these colour
+ * spaces for every YUV/RGB output format.
+ */
+-#define V4L2_COLORSPACE_MASK_ALL_SRGB (V4L2_COLORSPACE_MASK_JPEG | \
+- V4L2_COLORSPACE_MASK_SRGB | \
+- V4L2_COLORSPACE_MASK_SMPTE170M | \
++#define V4L2_COLORSPACE_MASK_ALL_SRGB (V4L2_COLORSPACE_MASK_JPEG | \
++ V4L2_COLORSPACE_MASK_SRGB | \
++ V4L2_COLORSPACE_MASK_SMPTE170M | \
+ V4L2_COLORSPACE_MASK_REC709)
+
+ static const struct pisp_be_format supported_formats[] = {
+@@ -58,7 +63,7 @@ static const struct pisp_be_format suppo
+ .plane_factor = { P3(1), P3(0.25), P3(0.25) },
+ .num_planes = 1,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB,
+- .colorspace_default = V4L2_COLORSPACE_JPEG,
++ .colorspace_default = V4L2_COLORSPACE_SMPTE170M,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YVU420,
+@@ -132,7 +137,7 @@ static const struct pisp_be_format suppo
+ .plane_factor = { P3(1), P3(0.25), P3(0.25) },
+ .num_planes = 3,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB,
+- .colorspace_default = V4L2_COLORSPACE_JPEG,
++ .colorspace_default = V4L2_COLORSPACE_SMPTE170M,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV12M,
+@@ -168,7 +173,7 @@ static const struct pisp_be_format suppo
+ .plane_factor = { P3(1), P3(0.5), P3(0.5) },
+ .num_planes = 3,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB,
+- .colorspace_default = V4L2_COLORSPACE_JPEG,
++ .colorspace_default = V4L2_COLORSPACE_SMPTE170M,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YVU422M,
+@@ -186,7 +191,7 @@ static const struct pisp_be_format suppo
+ .plane_factor = { P3(1), P3(1), P3(1) },
+ .num_planes = 3,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB,
+- .colorspace_default = V4L2_COLORSPACE_JPEG,
++ .colorspace_default = V4L2_COLORSPACE_SMPTE170M,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YVU444M,
+@@ -502,11 +507,6 @@ static const struct pisp_be_format suppo
+ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW,
+ .colorspace_default = V4L2_COLORSPACE_RAW,
+ },
+- /* Opaque BE format for HW verification. */
+- {
+- .fourcc = V4L2_PIX_FMT_RPI_BE,
+- .align = 32,
+- },
+ };
+
+ static const struct pisp_be_format meta_out_supported_formats[] = {
--- /dev/null
+From b58aeea7e2e3afd4fb3b6dcbe5e382b2244b33a4 Mon Sep 17 00:00:00 2001
+From: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
+Date: Thu, 27 Jun 2024 13:40:29 +0200
+Subject: [PATCH 1155/1215] media: uapi: pisp_be_config: Drop BIT() from uAPI
+
+The pisp_be_config.h uAPI header file contains a bit-field definition
+that uses the BIT() helper macro.
+
+As the BIT() identifier is not defined in userspace, drop it from the
+uAPI header.
+
+Fixes: c6c49bac8770 ("media: uapi: Add Raspberry Pi PiSP Back End uAPI")
+Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
+Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
+---
+ include/uapi/linux/media/raspberrypi/pisp_be_config.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/include/uapi/linux/media/raspberrypi/pisp_be_config.h
++++ b/include/uapi/linux/media/raspberrypi/pisp_be_config.h
+@@ -146,7 +146,7 @@ struct pisp_be_dpc_config {
+ */
+ struct pisp_be_geq_config {
+ __u16 offset;
+-#define PISP_BE_GEQ_SHARPER BIT(15)
++#define PISP_BE_GEQ_SHARPER (1U << 15)
+ #define PISP_BE_GEQ_SLOPE ((1 << 10) - 1)
+ /* top bit is the "sharper" flag, slope value is bottom 10 bits */
+ __u16 slope_sharper;
--- /dev/null
+From 7c36a1feb61d964055bee777efc1db60790aa215 Mon Sep 17 00:00:00 2001
+From: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
+Date: Thu, 27 Jun 2024 16:07:43 +0200
+Subject: [PATCH 1156/1215] media: uapi: pisp_common: Add 32 bpp format test
+
+Add definition and test for 32-bits image formats to the pisp_common.h
+uAPI header.
+
+Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
+---
+ include/uapi/linux/media/raspberrypi/pisp_common.h | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/include/uapi/linux/media/raspberrypi/pisp_common.h
++++ b/include/uapi/linux/media/raspberrypi/pisp_common.h
+@@ -72,6 +72,8 @@ enum pisp_image_format {
+ PISP_IMAGE_FORMAT_SHIFT_8 = 0x00080000,
+ PISP_IMAGE_FORMAT_SHIFT_MASK = 0x000f0000,
+
++ PISP_IMAGE_FORMAT_BPP_32 = 0x00100000,
++
+ PISP_IMAGE_FORMAT_UNCOMPRESSED = 0x00000000,
+ PISP_IMAGE_FORMAT_COMPRESSION_MODE_1 = 0x01000000,
+ PISP_IMAGE_FORMAT_COMPRESSION_MODE_2 = 0x02000000,
+@@ -134,6 +136,7 @@ enum pisp_image_format {
+ PISP_IMAGE_FORMAT_PLANARITY_PLANAR)
+ #define PISP_IMAGE_FORMAT_wallpaper(fmt) \
+ ((fmt) & PISP_IMAGE_FORMAT_WALLPAPER_ROLL)
++#define PISP_IMAGE_FORMAT_bpp_32(fmt) ((fmt) & PISP_IMAGE_FORMAT_BPP_32)
+ #define PISP_IMAGE_FORMAT_HOG(fmt) \
+ ((fmt) & \
+ (PISP_IMAGE_FORMAT_HOG_SIGNED | PISP_IMAGE_FORMAT_HOG_UNSIGNED))
--- /dev/null
+From 20a3671be178fd98aac08931d809e689eaa7a9d9 Mon Sep 17 00:00:00 2001
+From: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
+Date: Fri, 28 Jun 2024 10:10:10 +0200
+Subject: [PATCH 1157/1215] media: uapi: Capitalize all macros
+
+The macro used to inspect an image format characteristic use a mixture
+of capitalized and non-capitalized letters, which is rather unusual for
+the Linux kernel style.
+
+Capitalize all identifiers.
+
+Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
+---
+ .../linux/media/raspberrypi/pisp_common.h | 38 +++++++++----------
+ 1 file changed, 19 insertions(+), 19 deletions(-)
+
+--- a/include/uapi/linux/media/raspberrypi/pisp_common.h
++++ b/include/uapi/linux/media/raspberrypi/pisp_common.h
+@@ -92,51 +92,51 @@ enum pisp_image_format {
+ PISP_IMAGE_FORMAT_THREE_CHANNEL
+ };
+
+-#define PISP_IMAGE_FORMAT_bps_8(fmt) \
++#define PISP_IMAGE_FORMAT_BPS_8(fmt) \
+ (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) == PISP_IMAGE_FORMAT_BPS_8)
+-#define PISP_IMAGE_FORMAT_bps_10(fmt) \
++#define PISP_IMAGE_FORMAT_BPS_10(fmt) \
+ (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) == PISP_IMAGE_FORMAT_BPS_10)
+-#define PISP_IMAGE_FORMAT_bps_12(fmt) \
++#define PISP_IMAGE_FORMAT_BPS_12(fmt) \
+ (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) == PISP_IMAGE_FORMAT_BPS_12)
+-#define PISP_IMAGE_FORMAT_bps_16(fmt) \
++#define PISP_IMAGE_FORMAT_BPS_16(fmt) \
+ (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) == PISP_IMAGE_FORMAT_BPS_16)
+-#define PISP_IMAGE_FORMAT_bps(fmt) \
++#define PISP_IMAGE_FORMAT_BPS(fmt) \
+ (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) ? \
+ 8 + (2 << (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) - 1)) : 8)
+-#define PISP_IMAGE_FORMAT_shift(fmt) \
++#define PISP_IMAGE_FORMAT_SHIFT(fmt) \
+ (((fmt) & PISP_IMAGE_FORMAT_SHIFT_MASK) / PISP_IMAGE_FORMAT_SHIFT_1)
+-#define PISP_IMAGE_FORMAT_three_channel(fmt) \
++#define PISP_IMAGE_FORMAT_THREE_CHANNEL(fmt) \
+ ((fmt) & PISP_IMAGE_FORMAT_THREE_CHANNEL)
+-#define PISP_IMAGE_FORMAT_single_channel(fmt) \
++#define PISP_IMAGE_FORMAT_SINGLE_CHANNEL(fmt) \
+ (!((fmt) & PISP_IMAGE_FORMAT_THREE_CHANNEL))
+-#define PISP_IMAGE_FORMAT_compressed(fmt) \
++#define PISP_IMAGE_FORMAT_COMPRESSED(fmt) \
+ (((fmt) & PISP_IMAGE_FORMAT_COMPRESSION_MASK) != \
+ PISP_IMAGE_FORMAT_UNCOMPRESSED)
+-#define PISP_IMAGE_FORMAT_sampling_444(fmt) \
++#define PISP_IMAGE_FORMAT_SAMPLING_444(fmt) \
+ (((fmt) & PISP_IMAGE_FORMAT_SAMPLING_MASK) == \
+ PISP_IMAGE_FORMAT_SAMPLING_444)
+-#define PISP_IMAGE_FORMAT_sampling_422(fmt) \
++#define PISP_IMAGE_FORMAT_SAMPLING_422(fmt) \
+ (((fmt) & PISP_IMAGE_FORMAT_SAMPLING_MASK) == \
+ PISP_IMAGE_FORMAT_SAMPLING_422)
+-#define PISP_IMAGE_FORMAT_sampling_420(fmt) \
++#define PISP_IMAGE_FORMAT_SAMPLING_420(fmt) \
+ (((fmt) & PISP_IMAGE_FORMAT_SAMPLING_MASK) == \
+ PISP_IMAGE_FORMAT_SAMPLING_420)
+-#define PISP_IMAGE_FORMAT_order_normal(fmt) \
++#define PISP_IMAGE_FORMAT_ORDER_NORMAL(fmt) \
+ (!((fmt) & PISP_IMAGE_FORMAT_ORDER_SWAPPED))
+-#define PISP_IMAGE_FORMAT_order_swapped(fmt) \
++#define PISP_IMAGE_FORMAT_ORDER_SWAPPED(fmt) \
+ ((fmt) & PISP_IMAGE_FORMAT_ORDER_SWAPPED)
+-#define PISP_IMAGE_FORMAT_interleaved(fmt) \
++#define PISP_IMAGE_FORMAT_INTERLEAVED(fmt) \
+ (((fmt) & PISP_IMAGE_FORMAT_PLANARITY_MASK) == \
+ PISP_IMAGE_FORMAT_PLANARITY_INTERLEAVED)
+-#define PISP_IMAGE_FORMAT_semiplanar(fmt) \
++#define PISP_IMAGE_FORMAT_SEMIPLANAR(fmt) \
+ (((fmt) & PISP_IMAGE_FORMAT_PLANARITY_MASK) == \
+ PISP_IMAGE_FORMAT_PLANARITY_SEMI_PLANAR)
+-#define PISP_IMAGE_FORMAT_planar(fmt) \
++#define PISP_IMAGE_FORMAT_PLANAR(fmt) \
+ (((fmt) & PISP_IMAGE_FORMAT_PLANARITY_MASK) == \
+ PISP_IMAGE_FORMAT_PLANARITY_PLANAR)
+-#define PISP_IMAGE_FORMAT_wallpaper(fmt) \
++#define PISP_IMAGE_FORMAT_WALLPAPER(fmt) \
+ ((fmt) & PISP_IMAGE_FORMAT_WALLPAPER_ROLL)
+-#define PISP_IMAGE_FORMAT_bpp_32(fmt) ((fmt) & PISP_IMAGE_FORMAT_BPP_32)
++#define PISP_IMAGE_FORMAT_BPP_32(fmt) ((fmt) & PISP_IMAGE_FORMAT_BPP_32)
+ #define PISP_IMAGE_FORMAT_HOG(fmt) \
+ ((fmt) & \
+ (PISP_IMAGE_FORMAT_HOG_SIGNED | PISP_IMAGE_FORMAT_HOG_UNSIGNED))
--- /dev/null
+From ce89955e44f3ab41262b02d8e1e65c3455d66c4d Mon Sep 17 00:00:00 2001
+From: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
+Date: Fri, 28 Jun 2024 13:59:40 +0200
+Subject: [PATCH 1158/1215] media: uapi: pisp_be_config: Re-sort
+ pisp_be_tiles_config
+
+The order of the members of pisp_be_tiles_config is relevant
+as the driver logic assumes 'config' to be at offset 0.
+
+Re-sort the member to match the driver's expectations.
+
+Fixes: c6c49bac8770 ("media: uapi: Add Raspberry Pi PiSP Back End uAPI")
+Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
+---
+ include/uapi/linux/media/raspberrypi/pisp_be_config.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/include/uapi/linux/media/raspberrypi/pisp_be_config.h
++++ b/include/uapi/linux/media/raspberrypi/pisp_be_config.h
+@@ -919,9 +919,9 @@ struct pisp_tile {
+ * @config: PiSP Back End configuration
+ */
+ struct pisp_be_tiles_config {
++ struct pisp_be_config config;
+ struct pisp_tile tiles[PISP_BACK_END_NUM_TILES];
+ __u32 num_tiles;
+- struct pisp_be_config config;
+ } __attribute__((packed));
+
+ #endif /* _UAPI_PISP_BE_CONFIG_H_ */
--- /dev/null
+From abf30420f943d03cc28fec38612d2c5f5e6edf1f Mon Sep 17 00:00:00 2001
+From: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
+Date: Fri, 28 Jun 2024 14:11:14 +0200
+Subject: [PATCH 1159/1215] media: uapi: pisp_be_config: Add extra config
+ fields
+
+Complete the pisp_be_config strcture by adding fields that even if not
+written to the HW are relevant to complete the uAPI and put it in par
+with the BSP driver.
+
+Fixes: c6c49bac8770 ("media: uapi: Add Raspberry Pi PiSP Back End uAPI")
+Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
+---
+ .../linux/media/raspberrypi/pisp_be_config.h | 41 +++++++++++++++++++
+ 1 file changed, 41 insertions(+)
+
+--- a/include/uapi/linux/media/raspberrypi/pisp_be_config.h
++++ b/include/uapi/linux/media/raspberrypi/pisp_be_config.h
+@@ -716,6 +716,13 @@ struct pisp_be_hog_buffer_config {
+ /**
+ * struct pisp_be_config - RaspberryPi PiSP Back End Processing configuration
+ *
++ * @input_buffer: Input buffer addresses
++ * @tdn_input_buffer: TDN input buffer addresses
++ * @stitch_input_buffer: Stitch input buffer addresses
++ * @tdn_output_buffer: TDN output buffer addresses
++ * @stitch_output_buffer: Stitch output buffer addresses
++ * @output_buffer: Output buffers addresses
++ * @hog_buffer: HOG buffer addresses
+ * @global: Global PiSP configuration
+ * @input_format: Input image format
+ * @decompress: Decompress configuration
+@@ -753,8 +760,30 @@ struct pisp_be_hog_buffer_config {
+ * @resample: Resampling configuration
+ * @output_format: Output format configuration
+ * @hog: HOG configuration
++ * @axi: AXI bus configuration
++ * @lsc_extra: LSC extra info
++ * @cac_extra: CAC extra info
++ * @downscale_extra: Downscaler extra info
++ * @resample_extra: Resample extra info
++ * @crop: Crop configuration
++ * @hog_format: HOG format info
++ * @dirty_flags_bayer: Bayer enable dirty flags
++ * (:c:type:`pisp_be_bayer_enable`)
++ * @dirty_flags_rgb: RGB enable dirty flags
++ * (:c:type:`pisp_be_rgb_enable`)
++ * @dirty_flags_extra: Extra dirty flags
+ */
+ struct pisp_be_config {
++ /* I/O configuration: */
++ struct pisp_be_input_buffer_config input_buffer;
++ struct pisp_be_tdn_input_buffer_config tdn_input_buffer;
++ struct pisp_be_stitch_input_buffer_config stitch_input_buffer;
++ struct pisp_be_tdn_output_buffer_config tdn_output_buffer;
++ struct pisp_be_stitch_output_buffer_config stitch_output_buffer;
++ struct pisp_be_output_buffer_config
++ output_buffer[PISP_BACK_END_NUM_OUTPUTS];
++ struct pisp_be_hog_buffer_config hog_buffer;
++ /* Processing configuration: */
+ struct pisp_be_global_config global;
+ struct pisp_image_format_config input_format;
+ struct pisp_decompress_config decompress;
+@@ -793,6 +822,18 @@ struct pisp_be_config {
+ struct pisp_be_output_format_config
+ output_format[PISP_BACK_END_NUM_OUTPUTS];
+ struct pisp_be_hog_config hog;
++ struct pisp_be_axi_config axi;
++ /* Non-register fields: */
++ struct pisp_be_lsc_extra lsc_extra;
++ struct pisp_be_cac_extra cac_extra;
++ struct pisp_be_downscale_extra
++ downscale_extra[PISP_BACK_END_NUM_OUTPUTS];
++ struct pisp_be_resample_extra resample_extra[PISP_BACK_END_NUM_OUTPUTS];
++ struct pisp_be_crop_config crop;
++ struct pisp_image_format_config hog_format;
++ __u32 dirty_flags_bayer; /* these use pisp_be_bayer_enable */
++ __u32 dirty_flags_rgb; /* use pisp_be_rgb_enable */
++ __u32 dirty_flags_extra; /* these use pisp_be_dirty_t */
+ } __attribute__((packed));
+
+ /**
--- /dev/null
+From 033e037013f2c092501a03bb1bf5bbf7b4045aa0 Mon Sep 17 00:00:00 2001
+From: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
+Date: Fri, 28 Jun 2024 17:26:26 +0200
+Subject: [PATCH 1160/1215] media: pisp_be: Re-introduce multi-context support
+
+Re-introduce multi-context support that was dropped from the
+mainline driver version.
+
+Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
+---
+ .../platform/raspberrypi/pisp_be/pisp_be.c | 355 ++++++++++--------
+ 1 file changed, 208 insertions(+), 147 deletions(-)
+
+--- a/drivers/media/platform/raspberrypi/pisp_be/pisp_be.c
++++ b/drivers/media/platform/raspberrypi/pisp_be/pisp_be.c
+@@ -24,6 +24,14 @@
+ /* Maximum number of config buffers possible */
+ #define PISP_BE_NUM_CONFIG_BUFFERS VB2_MAX_FRAME
+
++/*
++ * We want to support 2 independent instances allowing 2 simultaneous users
++ * of the ISP-BE (of course they share hardware, platform resources and mutex).
++ * Each such instance comprises a group of device nodes representing input
++ * and output queues, and a media controller device node to describe them.
++ */
++#define PISPBE_NUM_NODE_GROUPS 2
++
+ #define PISPBE_NAME "pispbe"
+
+ /* Some ISP-BE registers */
+@@ -156,7 +164,7 @@ struct pispbe_node {
+ struct media_pad pad;
+ struct media_intf_devnode *intf_devnode;
+ struct media_link *intf_link;
+- struct pispbe_dev *pispbe;
++ struct pispbe_node_group *node_group;
+ /* Video device lock */
+ struct mutex node_lock;
+ /* vb2_queue lock */
+@@ -173,9 +181,27 @@ struct pispbe_node {
+ #define NODE_NAME(node) \
+ (node_desc[(node)->id].ent_name + sizeof(PISPBE_NAME))
+
++/*
++ * Node group structure, which comprises all the input and output nodes that a
++ * single PiSP client will need, along with its own v4l2 and media devices.
++ */
++struct pispbe_node_group {
++ unsigned int id;
++ struct v4l2_device v4l2_dev;
++ struct v4l2_subdev sd;
++ struct pispbe_dev *pispbe;
++ struct media_device mdev;
++ struct pispbe_node node[PISPBE_NUM_NODES];
++ u32 streaming_map; /* bitmap of which nodes are streaming */
++ struct media_pad pad[PISPBE_NUM_NODES]; /* output pads first */
++ struct pisp_be_tiles_config *config;
++ dma_addr_t config_dma_addr;
++ unsigned int sequence;
++};
++
+ /* Records details of the jobs currently running or queued on the h/w. */
+ struct pispbe_job {
+- bool valid;
++ struct pispbe_node_group *node_group;
+ /*
+ * An array of buffer pointers - remember it's source buffers first,
+ * then captures, then metadata last.
+@@ -198,22 +224,13 @@ struct pispbe_job_descriptor {
+
+ /*
+ * Structure representing the entire PiSP Back End device, comprising several
+- * nodes which share platform resources and a mutex for the actual HW.
++ * nodes groups which share platform resources and a mutex for the actual HW.
+ */
+ struct pispbe_dev {
+ struct device *dev;
+- struct pispbe_dev *pispbe;
+- struct pisp_be_tiles_config *config;
+ void __iomem *be_reg_base;
+ struct clk *clk;
+- struct v4l2_device v4l2_dev;
+- struct v4l2_subdev sd;
+- struct media_device mdev;
+- struct media_pad pad[PISPBE_NUM_NODES]; /* output pads first */
+- struct pispbe_node node[PISPBE_NUM_NODES];
+- dma_addr_t config_dma_addr;
+- unsigned int sequence;
+- u32 streaming_map;
++ struct pispbe_node_group node_group[PISPBE_NUM_NODE_GROUPS];
+ struct pispbe_job queued_job, running_job;
+ spinlock_t hw_lock; /* protects "hw_busy" flag and streaming_map */
+ bool hw_busy; /* non-zero if a job is queued or is being started */
+@@ -348,9 +365,9 @@ static dma_addr_t pispbe_get_addr(struct
+ return 0;
+ }
+
+-static void pispbe_xlate_addrs(struct pispbe_dev *pispbe,
+- struct pispbe_job_descriptor *job,
+- struct pispbe_buffer *buf[PISPBE_NUM_NODES])
++static void pispbe_xlate_addrs(struct pispbe_job_descriptor *job,
++ struct pispbe_buffer *buf[PISPBE_NUM_NODES],
++ struct pispbe_node_group *node_group)
+ {
+ struct pispbe_hw_enables *hw_en = &job->hw_enables;
+ struct pisp_be_tiles_config *config = job->config;
+@@ -366,13 +383,13 @@ static void pispbe_xlate_addrs(struct pi
+ * to 3 planes.
+ */
+ ret = pispbe_get_planes_addr(addrs, buf[MAIN_INPUT_NODE],
+- &pispbe->node[MAIN_INPUT_NODE]);
++ &node_group->node[MAIN_INPUT_NODE]);
+ if (ret <= 0) {
+ /*
+ * This shouldn't happen; pispbe_schedule_internal should insist
+ * on an input.
+ */
+- dev_warn(pispbe->dev, "ISP-BE missing input\n");
++ dev_warn(node_group->pispbe->dev, "ISP-BE missing input\n");
+ hw_en->bayer_enables = 0;
+ hw_en->rgb_enables = 0;
+ return;
+@@ -427,7 +444,7 @@ static void pispbe_xlate_addrs(struct pi
+ for (unsigned int i = 0; i < PISP_BACK_END_NUM_OUTPUTS; i++) {
+ ret = pispbe_get_planes_addr(addrs + 7 + 3 * i,
+ buf[OUTPUT0_NODE + i],
+- &pispbe->node[OUTPUT0_NODE + i]);
++ &node_group->node[OUTPUT0_NODE + i]);
+ if (ret <= 0)
+ hw_en->rgb_enables &= ~(PISP_BE_RGB_ENABLE_OUTPUT0 << i);
+ }
+@@ -447,10 +464,11 @@ static void pispbe_xlate_addrs(struct pi
+ *
+ * Returns 0 if a job has been successfully prepared, < 0 otherwise.
+ */
+-static int pispbe_prepare_job(struct pispbe_dev *pispbe,
++static int pispbe_prepare_job(struct pispbe_node_group *node_group,
+ struct pispbe_job_descriptor *job)
+ {
+ struct pispbe_buffer *buf[PISPBE_NUM_NODES] = {};
++ struct pispbe_dev *pispbe = node_group->pispbe;
+ unsigned int config_index;
+ struct pispbe_node *node;
+ unsigned long flags;
+@@ -460,11 +478,11 @@ static int pispbe_prepare_job(struct pis
+ memset(job, 0, sizeof(struct pispbe_job_descriptor));
+
+ if (((BIT(CONFIG_NODE) | BIT(MAIN_INPUT_NODE)) &
+- pispbe->streaming_map) !=
++ node_group->streaming_map) !=
+ (BIT(CONFIG_NODE) | BIT(MAIN_INPUT_NODE)))
+ return -ENODEV;
+
+- node = &pispbe->node[CONFIG_NODE];
++ node = &node_group->node[CONFIG_NODE];
+ spin_lock_irqsave(&node->ready_lock, flags);
+ buf[CONFIG_NODE] = list_first_entry_or_null(&node->ready_queue,
+ struct pispbe_buffer,
+@@ -480,8 +498,8 @@ static int pispbe_prepare_job(struct pis
+ return -ENODEV;
+
+ config_index = buf[CONFIG_NODE]->vb.vb2_buf.index;
+- job->config = &pispbe->config[config_index];
+- job->tiles = pispbe->config_dma_addr +
++ job->config = &node_group->config[config_index];
++ job->tiles = node_group->config_dma_addr +
+ config_index * sizeof(struct pisp_be_tiles_config) +
+ offsetof(struct pisp_be_tiles_config, tiles);
+
+@@ -498,7 +516,7 @@ static int pispbe_prepare_job(struct pis
+ continue;
+
+ buf[i] = NULL;
+- if (!(pispbe->streaming_map & BIT(i)))
++ if (!(node_group->streaming_map & BIT(i)))
+ continue;
+
+ if ((!(rgb_en & PISP_BE_RGB_ENABLE_OUTPUT0) &&
+@@ -522,7 +540,7 @@ static int pispbe_prepare_job(struct pis
+ ignore_buffers = true;
+ }
+
+- node = &pispbe->node[i];
++ node = &node_group->node[i];
+
+ /* Pull a buffer from each V4L2 queue to form the queued job */
+ spin_lock_irqsave(&node->ready_lock, flags);
+@@ -539,16 +557,16 @@ static int pispbe_prepare_job(struct pis
+ goto err_return_buffers;
+ }
+
+- pispbe->queued_job.valid = true;
++ pispbe->queued_job.node_group = node_group;
+
+ /* Convert buffers to DMA addresses for the hardware */
+- pispbe_xlate_addrs(pispbe, job, buf);
++ pispbe_xlate_addrs(job, buf, node_group);
+
+ return 0;
+
+ err_return_buffers:
+ for (unsigned int i = 0; i < PISPBE_NUM_NODES; i++) {
+- struct pispbe_node *n = &pispbe->node[i];
++ struct pispbe_node *n = &node_group->node[i];
+
+ if (!buf[i])
+ continue;
+@@ -564,11 +582,12 @@ err_return_buffers:
+ return -ENODEV;
+ }
+
+-static void pispbe_schedule(struct pispbe_dev *pispbe, bool clear_hw_busy)
++static void pispbe_schedule(struct pispbe_dev *pispbe,
++ struct pispbe_node_group *node_group,
++ bool clear_hw_busy)
+ {
+ struct pispbe_job_descriptor job;
+ unsigned long flags;
+- int ret;
+
+ spin_lock_irqsave(&pispbe->hw_lock, flags);
+
+@@ -578,40 +597,53 @@ static void pispbe_schedule(struct pispb
+ if (pispbe->hw_busy)
+ goto unlock_and_return;
+
+- ret = pispbe_prepare_job(pispbe, &job);
+- if (ret)
+- goto unlock_and_return;
++ for (unsigned int i = 0; i < PISPBE_NUM_NODE_GROUPS; i++) {
++ int ret;
+
+- /*
+- * We can kick the job off without the hw_lock, as this can
+- * never run again until hw_busy is cleared, which will happen
+- * only when the following job has been queued and an interrupt
+- * is rised.
+- */
+- pispbe->hw_busy = true;
+- spin_unlock_irqrestore(&pispbe->hw_lock, flags);
++ /* Schedule jobs only for a specific group. */
++ if (node_group && &pispbe->node_group[i] != node_group)
++ continue;
+
+- if (job.config->num_tiles <= 0 ||
+- job.config->num_tiles > PISP_BACK_END_NUM_TILES ||
+- !((job.hw_enables.bayer_enables | job.hw_enables.rgb_enables) &
+- PISP_BE_BAYER_ENABLE_INPUT)) {
+ /*
+- * Bad job. We can't let it proceed as it could lock up
+- * the hardware, or worse!
+- *
+- * For now, just force num_tiles to 0, which causes the
+- * H/W to do something bizarre but survivable. It
+- * increments (started,done) counters by more than 1,
+- * but we seem to survive...
++ * Prepare a job for this group, if the group is not ready
++ * continue and try with the next one.
+ */
+- dev_dbg(pispbe->dev, "Bad job: invalid number of tiles: %u\n",
+- job.config->num_tiles);
+- job.config->num_tiles = 0;
+- }
++ ret = pispbe_prepare_job(&pispbe->node_group[i], &job);
++ if (ret)
++ continue;
++
++ /*
++ * We can kick the job off without the hw_lock, as this can
++ * never run again until hw_busy is cleared, which will happen
++ * only when the following job has been queued and an interrupt
++ * is rised.
++ */
++ pispbe->hw_busy = true;
++ spin_unlock_irqrestore(&pispbe->hw_lock, flags);
++
++ if (job.config->num_tiles <= 0 ||
++ job.config->num_tiles > PISP_BACK_END_NUM_TILES ||
++ !((job.hw_enables.bayer_enables |
++ job.hw_enables.rgb_enables) &
++ PISP_BE_BAYER_ENABLE_INPUT)) {
++ /*
++ * Bad job. We can't let it proceed as it could lock up
++ * the hardware, or worse!
++ *
++ * For now, just force num_tiles to 0, which causes the
++ * H/W to do something bizarre but survivable. It
++ * increments (started,done) counters by more than 1,
++ * but we seem to survive...
++ */
++ dev_dbg(pispbe->dev, "Bad job: invalid number of tiles: %u\n",
++ job.config->num_tiles);
++ job.config->num_tiles = 0;
++ }
+
+- pispbe_queue_job(pispbe, &job);
++ pispbe_queue_job(pispbe, &job);
+
+- return;
++ return;
++ }
+
+ unlock_and_return:
+ /* No job has been queued, just release the lock and return. */
+@@ -627,13 +659,13 @@ static void pispbe_isr_jobdone(struct pi
+ for (unsigned int i = 0; i < PISPBE_NUM_NODES; i++) {
+ if (buf[i]) {
+ buf[i]->vb.vb2_buf.timestamp = ts;
+- buf[i]->vb.sequence = pispbe->sequence;
++ buf[i]->vb.sequence = job->node_group->sequence;
+ vb2_buffer_done(&buf[i]->vb.vb2_buf,
+ VB2_BUF_STATE_DONE);
+ }
+ }
+
+- pispbe->sequence++;
++ job->node_group->sequence++;
+ }
+
+ static irqreturn_t pispbe_isr(int irq, void *dev)
+@@ -657,7 +689,7 @@ static irqreturn_t pispbe_isr(int irq, v
+ * we previously saw "start" now finishes, and we then queued a new job
+ * which we see both start and finish "simultaneously".
+ */
+- if (pispbe->running_job.valid && pispbe->done != done) {
++ if (pispbe->running_job.node_group && pispbe->done != done) {
+ pispbe_isr_jobdone(pispbe, &pispbe->running_job);
+ memset(&pispbe->running_job, 0, sizeof(pispbe->running_job));
+ pispbe->done++;
+@@ -667,7 +699,7 @@ static irqreturn_t pispbe_isr(int irq, v
+ pispbe->started++;
+ can_queue_another = 1;
+
+- if (pispbe->done != done && pispbe->queued_job.valid) {
++ if (pispbe->done != done && pispbe->queued_job.node_group) {
+ pispbe_isr_jobdone(pispbe, &pispbe->queued_job);
+ pispbe->done++;
+ } else {
+@@ -686,17 +718,17 @@ static irqreturn_t pispbe_isr(int irq, v
+ }
+
+ /* check if there's more to do before going to sleep */
+- pispbe_schedule(pispbe, can_queue_another);
++ pispbe_schedule(pispbe, NULL, can_queue_another);
+
+ return IRQ_HANDLED;
+ }
+
+-static int pisp_be_validate_config(struct pispbe_dev *pispbe,
++static int pisp_be_validate_config(struct pispbe_node_group *node_group,
+ struct pisp_be_tiles_config *config)
+ {
+ u32 bayer_enables = config->config.global.bayer_enables;
+ u32 rgb_enables = config->config.global.rgb_enables;
+- struct device *dev = pispbe->dev;
++ struct device *dev = node_group->pispbe->dev;
+ struct v4l2_format *fmt;
+ unsigned int bpl, size;
+
+@@ -707,7 +739,7 @@ static int pisp_be_validate_config(struc
+ }
+
+ /* Ensure output config strides and buffer sizes match the V4L2 formats. */
+- fmt = &pispbe->node[TDN_OUTPUT_NODE].format;
++ fmt = &node_group->node[TDN_OUTPUT_NODE].format;
+ if (bayer_enables & PISP_BE_BAYER_ENABLE_TDN_OUTPUT) {
+ bpl = config->config.tdn_output_format.stride;
+ size = bpl * config->config.tdn_output_format.height;
+@@ -725,7 +757,7 @@ static int pisp_be_validate_config(struc
+ }
+ }
+
+- fmt = &pispbe->node[STITCH_OUTPUT_NODE].format;
++ fmt = &node_group->node[STITCH_OUTPUT_NODE].format;
+ if (bayer_enables & PISP_BE_BAYER_ENABLE_STITCH_OUTPUT) {
+ bpl = config->config.stitch_output_format.stride;
+ size = bpl * config->config.stitch_output_format.height;
+@@ -751,7 +783,7 @@ static int pisp_be_validate_config(struc
+ PISP_IMAGE_FORMAT_WALLPAPER_ROLL)
+ continue; /* TODO: Size checks for wallpaper formats */
+
+- fmt = &pispbe->node[OUTPUT0_NODE + j].format;
++ fmt = &node_group->node[OUTPUT0_NODE + j].format;
+ for (unsigned int i = 0; i < fmt->fmt.pix_mp.num_planes; i++) {
+ bpl = !i ? config->config.output_format[j].image.stride
+ : config->config.output_format[j].image.stride2;
+@@ -783,7 +815,7 @@ static int pispbe_node_queue_setup(struc
+ struct device *alloc_devs[])
+ {
+ struct pispbe_node *node = vb2_get_drv_priv(q);
+- struct pispbe_dev *pispbe = node->pispbe;
++ struct pispbe_dev *pispbe = node->node_group->pispbe;
+ unsigned int num_planes = NODE_IS_MPLANE(node) ?
+ node->format.fmt.pix_mp.num_planes : 1;
+
+@@ -821,7 +853,7 @@ static int pispbe_node_queue_setup(struc
+ static int pispbe_node_buffer_prepare(struct vb2_buffer *vb)
+ {
+ struct pispbe_node *node = vb2_get_drv_priv(vb->vb2_queue);
+- struct pispbe_dev *pispbe = node->pispbe;
++ struct pispbe_dev *pispbe = node->node_group->pispbe;
+ unsigned int num_planes = NODE_IS_MPLANE(node) ?
+ node->format.fmt.pix_mp.num_planes : 1;
+
+@@ -841,12 +873,12 @@ static int pispbe_node_buffer_prepare(st
+ }
+
+ if (node->id == CONFIG_NODE) {
+- void *dst = &node->pispbe->config[vb->index];
++ void *dst = &node->node_group->config[vb->index];
+ void *src = vb2_plane_vaddr(vb, 0);
+
+ memcpy(dst, src, sizeof(struct pisp_be_tiles_config));
+
+- return pisp_be_validate_config(pispbe, dst);
++ return pisp_be_validate_config(node->node_group, dst);
+ }
+
+ return 0;
+@@ -859,7 +891,8 @@ static void pispbe_node_buffer_queue(str
+ struct pispbe_buffer *buffer =
+ container_of(vbuf, struct pispbe_buffer, vb);
+ struct pispbe_node *node = vb2_get_drv_priv(buf->vb2_queue);
+- struct pispbe_dev *pispbe = node->pispbe;
++ struct pispbe_node_group *node_group = node->node_group;
++ struct pispbe_dev *pispbe = node->node_group->pispbe;
+ unsigned long flags;
+
+ dev_dbg(pispbe->dev, "%s: for node %s\n", __func__, NODE_NAME(node));
+@@ -869,15 +902,16 @@ static void pispbe_node_buffer_queue(str
+
+ /*
+ * Every time we add a buffer, check if there's now some work for the hw
+- * to do.
++ * to do, but only for this client.
+ */
+- pispbe_schedule(pispbe, false);
++ pispbe_schedule(node_group->pispbe, node_group, false);
+ }
+
+ static int pispbe_node_start_streaming(struct vb2_queue *q, unsigned int count)
+ {
+ struct pispbe_node *node = vb2_get_drv_priv(q);
+- struct pispbe_dev *pispbe = node->pispbe;
++ struct pispbe_node_group *node_group = node->node_group;
++ struct pispbe_dev *pispbe = node_group->pispbe;
+ struct pispbe_buffer *buf, *tmp;
+ unsigned long flags;
+ int ret;
+@@ -887,17 +921,17 @@ static int pispbe_node_start_streaming(s
+ goto err_return_buffers;
+
+ spin_lock_irqsave(&pispbe->hw_lock, flags);
+- node->pispbe->streaming_map |= BIT(node->id);
+- node->pispbe->sequence = 0;
++ node->node_group->streaming_map |= BIT(node->id);
++ node->node_group->sequence = 0;
+ spin_unlock_irqrestore(&pispbe->hw_lock, flags);
+
+ dev_dbg(pispbe->dev, "%s: for node %s (count %u)\n",
+ __func__, NODE_NAME(node), count);
+- dev_dbg(pispbe->dev, "Nodes streaming now 0x%x\n",
+- node->pispbe->streaming_map);
++ dev_dbg(pispbe->dev, "Nodes streaming for this group now 0x%x\n",
++ node->node_group->streaming_map);
+
+ /* Maybe we're ready to run. */
+- pispbe_schedule(pispbe, false);
++ pispbe_schedule(node_group->pispbe, node_group, false);
+
+ return 0;
+
+@@ -915,7 +949,8 @@ err_return_buffers:
+ static void pispbe_node_stop_streaming(struct vb2_queue *q)
+ {
+ struct pispbe_node *node = vb2_get_drv_priv(q);
+- struct pispbe_dev *pispbe = node->pispbe;
++ struct pispbe_node_group *node_group = node->node_group;
++ struct pispbe_dev *pispbe = node_group->pispbe;
+ struct pispbe_buffer *buf;
+ unsigned long flags;
+
+@@ -948,14 +983,14 @@ static void pispbe_node_stop_streaming(s
+ vb2_wait_for_all_buffers(&node->queue);
+
+ spin_lock_irqsave(&pispbe->hw_lock, flags);
+- pispbe->streaming_map &= ~BIT(node->id);
++ node_group->streaming_map &= ~BIT(node->id);
+ spin_unlock_irqrestore(&pispbe->hw_lock, flags);
+
+ pm_runtime_mark_last_busy(pispbe->dev);
+ pm_runtime_put_autosuspend(pispbe->dev);
+
+- dev_dbg(pispbe->dev, "Nodes streaming now 0x%x\n",
+- pispbe->streaming_map);
++ dev_dbg(pispbe->dev, "Nodes streaming for this group now 0x%x\n",
++ node_group->streaming_map);
+ }
+
+ static const struct vb2_ops pispbe_node_queue_ops = {
+@@ -979,7 +1014,7 @@ static int pispbe_node_querycap(struct f
+ struct v4l2_capability *cap)
+ {
+ struct pispbe_node *node = video_drvdata(file);
+- struct pispbe_dev *pispbe = node->pispbe;
++ struct pispbe_dev *pispbe = node->node_group->pispbe;
+
+ strscpy(cap->driver, PISPBE_NAME, sizeof(cap->driver));
+ strscpy(cap->card, PISPBE_NAME, sizeof(cap->card));
+@@ -995,7 +1030,7 @@ static int pispbe_node_g_fmt_vid_cap(str
+ struct v4l2_format *f)
+ {
+ struct pispbe_node *node = video_drvdata(file);
+- struct pispbe_dev *pispbe = node->pispbe;
++ struct pispbe_dev *pispbe = node->node_group->pispbe;
+
+ if (!NODE_IS_CAPTURE(node) || NODE_IS_META(node)) {
+ dev_dbg(pispbe->dev,
+@@ -1015,7 +1050,7 @@ static int pispbe_node_g_fmt_vid_out(str
+ struct v4l2_format *f)
+ {
+ struct pispbe_node *node = video_drvdata(file);
+- struct pispbe_dev *pispbe = node->pispbe;
++ struct pispbe_dev *pispbe = node->node_group->pispbe;
+
+ if (NODE_IS_CAPTURE(node) || NODE_IS_META(node)) {
+ dev_dbg(pispbe->dev,
+@@ -1035,7 +1070,7 @@ static int pispbe_node_g_fmt_meta_out(st
+ struct v4l2_format *f)
+ {
+ struct pispbe_node *node = video_drvdata(file);
+- struct pispbe_dev *pispbe = node->pispbe;
++ struct pispbe_dev *pispbe = node->node_group->pispbe;
+
+ if (!NODE_IS_META(node) || NODE_IS_CAPTURE(node)) {
+ dev_dbg(pispbe->dev,
+@@ -1092,7 +1127,7 @@ static void pispbe_set_plane_params(stru
+
+ static void pispbe_try_format(struct v4l2_format *f, struct pispbe_node *node)
+ {
+- struct pispbe_dev *pispbe = node->pispbe;
++ struct pispbe_dev *pispbe = node->node_group->pispbe;
+ u32 pixfmt = f->fmt.pix_mp.pixelformat;
+ const struct pisp_be_format *fmt;
+ bool is_rgb;
+@@ -1156,7 +1191,7 @@ static int pispbe_node_try_fmt_vid_cap(s
+ struct v4l2_format *f)
+ {
+ struct pispbe_node *node = video_drvdata(file);
+- struct pispbe_dev *pispbe = node->pispbe;
++ struct pispbe_dev *pispbe = node->node_group->pispbe;
+
+ if (!NODE_IS_CAPTURE(node) || NODE_IS_META(node)) {
+ dev_dbg(pispbe->dev,
+@@ -1174,7 +1209,7 @@ static int pispbe_node_try_fmt_vid_out(s
+ struct v4l2_format *f)
+ {
+ struct pispbe_node *node = video_drvdata(file);
+- struct pispbe_dev *pispbe = node->pispbe;
++ struct pispbe_dev *pispbe = node->node_group->pispbe;
+
+ if (!NODE_IS_OUTPUT(node) || NODE_IS_META(node)) {
+ dev_dbg(pispbe->dev,
+@@ -1192,7 +1227,7 @@ static int pispbe_node_try_fmt_meta_out(
+ struct v4l2_format *f)
+ {
+ struct pispbe_node *node = video_drvdata(file);
+- struct pispbe_dev *pispbe = node->pispbe;
++ struct pispbe_dev *pispbe = node->node_group->pispbe;
+
+ if (!NODE_IS_META(node) || NODE_IS_CAPTURE(node)) {
+ dev_dbg(pispbe->dev,
+@@ -1211,7 +1246,7 @@ static int pispbe_node_s_fmt_vid_cap(str
+ struct v4l2_format *f)
+ {
+ struct pispbe_node *node = video_drvdata(file);
+- struct pispbe_dev *pispbe = node->pispbe;
++ struct pispbe_dev *pispbe = node->node_group->pispbe;
+ int ret;
+
+ ret = pispbe_node_try_fmt_vid_cap(file, priv, f);
+@@ -1234,7 +1269,7 @@ static int pispbe_node_s_fmt_vid_out(str
+ struct v4l2_format *f)
+ {
+ struct pispbe_node *node = video_drvdata(file);
+- struct pispbe_dev *pispbe = node->pispbe;
++ struct pispbe_dev *pispbe = node->node_group->pispbe;
+ int ret;
+
+ ret = pispbe_node_try_fmt_vid_out(file, priv, f);
+@@ -1257,7 +1292,7 @@ static int pispbe_node_s_fmt_meta_out(st
+ struct v4l2_format *f)
+ {
+ struct pispbe_node *node = video_drvdata(file);
+- struct pispbe_dev *pispbe = node->pispbe;
++ struct pispbe_dev *pispbe = node->node_group->pispbe;
+ int ret;
+
+ ret = pispbe_node_try_fmt_meta_out(file, priv, f);
+@@ -1306,7 +1341,7 @@ static int pispbe_enum_framesizes(struct
+ struct v4l2_frmsizeenum *fsize)
+ {
+ struct pispbe_node *node = video_drvdata(file);
+- struct pispbe_dev *pispbe = node->pispbe;
++ struct pispbe_dev *pispbe = node->node_group->pispbe;
+
+ if (NODE_IS_META(node) || fsize->index)
+ return -EINVAL;
+@@ -1391,17 +1426,19 @@ static void pispbe_node_def_fmt(struct p
+ * Initialise a struct pispbe_node and register it as /dev/video<N>
+ * to represent one of the PiSP Back End's input or output streams.
+ */
+-static int pispbe_init_node(struct pispbe_dev *pispbe, unsigned int id)
++static int pispbe_init_node(struct pispbe_node_group *node_group,
++ unsigned int id)
+ {
+ bool output = NODE_DESC_IS_OUTPUT(&node_desc[id]);
+- struct pispbe_node *node = &pispbe->node[id];
++ struct pispbe_node *node = &node_group->node[id];
+ struct media_entity *entity = &node->vfd.entity;
++ struct pispbe_dev *pispbe = node_group->pispbe;
+ struct video_device *vdev = &node->vfd;
+ struct vb2_queue *q = &node->queue;
+ int ret;
+
+ node->id = id;
+- node->pispbe = pispbe;
++ node->node_group = node_group;
+ node->buf_type = node_desc[id].buf_type;
+
+ mutex_init(&node->node_lock);
+@@ -1419,7 +1456,7 @@ static int pispbe_init_node(struct pispb
+ q->ops = &pispbe_node_queue_ops;
+ q->buf_struct_size = sizeof(struct pispbe_buffer);
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+- q->dev = pispbe->dev;
++ q->dev = node->node_group->pispbe->dev;
+ /* get V4L2 to handle node->queue locking */
+ q->lock = &node->queue_lock;
+
+@@ -1431,7 +1468,7 @@ static int pispbe_init_node(struct pispb
+
+ *vdev = pispbe_videodev; /* default initialization */
+ strscpy(vdev->name, node_desc[id].ent_name, sizeof(vdev->name));
+- vdev->v4l2_dev = &pispbe->v4l2_dev;
++ vdev->v4l2_dev = &node_group->v4l2_dev;
+ vdev->vfl_dir = output ? VFL_DIR_TX : VFL_DIR_RX;
+ /* get V4L2 to serialise our ioctls */
+ vdev->lock = &node->node_lock;
+@@ -1457,11 +1494,11 @@ static int pispbe_init_node(struct pispb
+ video_set_drvdata(vdev, node);
+
+ if (output)
+- ret = media_create_pad_link(entity, 0, &pispbe->sd.entity,
++ ret = media_create_pad_link(entity, 0, &node_group->sd.entity,
+ id, MEDIA_LNK_FL_IMMUTABLE |
+ MEDIA_LNK_FL_ENABLED);
+ else
+- ret = media_create_pad_link(&pispbe->sd.entity, id, entity,
++ ret = media_create_pad_link(&node_group->sd.entity, id, entity,
+ 0, MEDIA_LNK_FL_IMMUTABLE |
+ MEDIA_LNK_FL_ENABLED);
+ if (ret)
+@@ -1490,9 +1527,10 @@ static const struct v4l2_subdev_ops pisp
+ .pad = &pispbe_pad_ops,
+ };
+
+-static int pispbe_init_subdev(struct pispbe_dev *pispbe)
++static int pispbe_init_subdev(struct pispbe_node_group *node_group)
+ {
+- struct v4l2_subdev *sd = &pispbe->sd;
++ struct pispbe_dev *pispbe = node_group->pispbe;
++ struct v4l2_subdev *sd = &node_group->sd;
+ int ret;
+
+ v4l2_subdev_init(sd, &pispbe_sd_ops);
+@@ -1502,16 +1540,16 @@ static int pispbe_init_subdev(struct pis
+ strscpy(sd->name, PISPBE_NAME, sizeof(sd->name));
+
+ for (unsigned int i = 0; i < PISPBE_NUM_NODES; i++)
+- pispbe->pad[i].flags =
++ node_group->pad[i].flags =
+ NODE_DESC_IS_OUTPUT(&node_desc[i]) ?
+ MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
+
+ ret = media_entity_pads_init(&sd->entity, PISPBE_NUM_NODES,
+- pispbe->pad);
++ node_group->pad);
+ if (ret)
+ goto error;
+
+- ret = v4l2_device_register_subdev(&pispbe->v4l2_dev, sd);
++ ret = v4l2_device_register_subdev(&node_group->v4l2_dev, sd);
+ if (ret)
+ goto error;
+
+@@ -1522,36 +1560,43 @@ error:
+ return ret;
+ }
+
+-static int pispbe_init_devices(struct pispbe_dev *pispbe)
++static int pispbe_init_group(struct pispbe_dev *pispbe, unsigned int id)
+ {
++ struct pispbe_node_group *node_group = &pispbe->node_group[id];
+ struct v4l2_device *v4l2_dev;
+ struct media_device *mdev;
+ unsigned int num_regist;
+ int ret;
+
++ node_group->id = id;
++ node_group->pispbe = pispbe;
++ node_group->streaming_map = 0;
++
++ dev_dbg(pispbe->dev, "Register nodes for group %u\n", id);
++
+ /* Register v4l2_device and media_device */
+- mdev = &pispbe->mdev;
+- mdev->hw_revision = pispbe->hw_version;
+- mdev->dev = pispbe->dev;
++ mdev = &node_group->mdev;
++ mdev->hw_revision = node_group->pispbe->hw_version;
++ mdev->dev = node_group->pispbe->dev;
+ strscpy(mdev->model, PISPBE_NAME, sizeof(mdev->model));
+ media_device_init(mdev);
+
+- v4l2_dev = &pispbe->v4l2_dev;
+- v4l2_dev->mdev = &pispbe->mdev;
++ v4l2_dev = &node_group->v4l2_dev;
++ v4l2_dev->mdev = &node_group->mdev;
+ strscpy(v4l2_dev->name, PISPBE_NAME, sizeof(v4l2_dev->name));
+
+- ret = v4l2_device_register(pispbe->dev, v4l2_dev);
++ ret = v4l2_device_register(pispbe->dev, &node_group->v4l2_dev);
+ if (ret)
+ goto err_media_dev_cleanup;
+
+ /* Register the PISPBE subdevice. */
+- ret = pispbe_init_subdev(pispbe);
++ ret = pispbe_init_subdev(node_group);
+ if (ret)
+ goto err_unregister_v4l2;
+
+ /* Create device video nodes */
+ for (num_regist = 0; num_regist < PISPBE_NUM_NODES; num_regist++) {
+- ret = pispbe_init_node(pispbe, num_regist);
++ ret = pispbe_init_node(node_group, num_regist);
+ if (ret)
+ goto err_unregister_nodes;
+ }
+@@ -1560,12 +1605,12 @@ static int pispbe_init_devices(struct pi
+ if (ret)
+ goto err_unregister_nodes;
+
+- pispbe->config =
++ node_group->config =
+ dma_alloc_coherent(pispbe->dev,
+ sizeof(struct pisp_be_tiles_config) *
+ PISP_BE_NUM_CONFIG_BUFFERS,
+- &pispbe->config_dma_addr, GFP_KERNEL);
+- if (!pispbe->config) {
++ &node_group->config_dma_addr, GFP_KERNEL);
++ if (!node_group->config) {
+ dev_err(pispbe->dev, "Unable to allocate cached config buffers.\n");
+ ret = -ENOMEM;
+ goto err_unregister_mdev;
+@@ -1577,11 +1622,11 @@ err_unregister_mdev:
+ media_device_unregister(mdev);
+ err_unregister_nodes:
+ while (num_regist-- > 0) {
+- video_unregister_device(&pispbe->node[num_regist].vfd);
+- vb2_queue_release(&pispbe->node[num_regist].queue);
++ video_unregister_device(&node_group->node[num_regist].vfd);
++ vb2_queue_release(&node_group->node[num_regist].queue);
+ }
+- v4l2_device_unregister_subdev(&pispbe->sd);
+- media_entity_cleanup(&pispbe->sd.entity);
++ v4l2_device_unregister_subdev(&node_group->sd);
++ media_entity_cleanup(&node_group->sd.entity);
+ err_unregister_v4l2:
+ v4l2_device_unregister(v4l2_dev);
+ err_media_dev_cleanup:
+@@ -1589,31 +1634,33 @@ err_media_dev_cleanup:
+ return ret;
+ }
+
+-static void pispbe_destroy_devices(struct pispbe_dev *pispbe)
++static void pispbe_destroy_node_group(struct pispbe_node_group *node_group)
+ {
+- if (pispbe->config) {
+- dma_free_coherent(pispbe->dev,
++ struct pispbe_dev *pispbe = node_group->pispbe;
++
++ if (node_group->config) {
++ dma_free_coherent(node_group->pispbe->dev,
+ sizeof(struct pisp_be_tiles_config) *
+ PISP_BE_NUM_CONFIG_BUFFERS,
+- pispbe->config,
+- pispbe->config_dma_addr);
++ node_group->config,
++ node_group->config_dma_addr);
+ }
+
+ dev_dbg(pispbe->dev, "Unregister from media controller\n");
+
+- v4l2_device_unregister_subdev(&pispbe->sd);
+- media_entity_cleanup(&pispbe->sd.entity);
+- media_device_unregister(&pispbe->mdev);
++ v4l2_device_unregister_subdev(&node_group->sd);
++ media_entity_cleanup(&node_group->sd.entity);
++ media_device_unregister(&node_group->mdev);
+
+ for (int i = PISPBE_NUM_NODES - 1; i >= 0; i--) {
+- video_unregister_device(&pispbe->node[i].vfd);
+- vb2_queue_release(&pispbe->node[i].queue);
+- mutex_destroy(&pispbe->node[i].node_lock);
+- mutex_destroy(&pispbe->node[i].queue_lock);
++ video_unregister_device(&node_group->node[i].vfd);
++ vb2_queue_release(&node_group->node[i].queue);
++ mutex_destroy(&node_group->node[i].node_lock);
++ mutex_destroy(&node_group->node[i].queue_lock);
+ }
+
+- media_device_cleanup(&pispbe->mdev);
+- v4l2_device_unregister(&pispbe->v4l2_dev);
++ media_device_cleanup(&node_group->mdev);
++ v4l2_device_unregister(&node_group->v4l2_dev);
+ }
+
+ static int pispbe_runtime_suspend(struct device *dev)
+@@ -1681,9 +1728,13 @@ static int pispbe_hw_init(struct pispbe_
+ return 0;
+ }
+
+-/* Probe the ISP-BE hardware block, as a single platform device. */
++/*
++ * Probe the ISP-BE hardware block, as a single platform device.
++ * This will instantiate multiple "node groups" each with many device nodes.
++ */
+ static int pispbe_probe(struct platform_device *pdev)
+ {
++ unsigned int num_groups = 0;
+ struct pispbe_dev *pispbe;
+ int ret;
+
+@@ -1738,17 +1789,26 @@ static int pispbe_probe(struct platform_
+ if (ret)
+ goto pm_runtime_suspend_err;
+
+- ret = pispbe_init_devices(pispbe);
+- if (ret)
+- goto disable_devs_err;
++ /*
++ * Initialise and register devices for each node_group, including media
++ * device
++ */
++ for (num_groups = 0;
++ num_groups < PISPBE_NUM_NODE_GROUPS;
++ num_groups++) {
++ ret = pispbe_init_group(pispbe, num_groups);
++ if (ret)
++ goto disable_nodes_err;
++ }
+
+ pm_runtime_mark_last_busy(pispbe->dev);
+ pm_runtime_put_autosuspend(pispbe->dev);
+
+ return 0;
+
+-disable_devs_err:
+- pispbe_destroy_devices(pispbe);
++disable_nodes_err:
++ while (num_groups-- > 0)
++ pispbe_destroy_node_group(&pispbe->node_group[num_groups]);
+ pm_runtime_suspend_err:
+ pispbe_runtime_suspend(pispbe->dev);
+ pm_runtime_disable_err:
+@@ -1762,7 +1822,8 @@ static int pispbe_remove(struct platform
+ {
+ struct pispbe_dev *pispbe = platform_get_drvdata(pdev);
+
+- pispbe_destroy_devices(pispbe);
++ for (int i = PISPBE_NUM_NODE_GROUPS - 1; i >= 0; i--)
++ pispbe_destroy_node_group(&pispbe->node_group[i]);
+
+ pispbe_runtime_suspend(pispbe->dev);
+ pm_runtime_dont_use_autosuspend(pispbe->dev);
--- /dev/null
+From f372f2854279828a33b9b3debc233d366fb4c124 Mon Sep 17 00:00:00 2001
+From: Naushir Patuck <naush@raspberrypi.com>
+Date: Mon, 8 Jul 2024 11:47:49 +0100
+Subject: [PATCH 1161/1215] media: pisp_be: Re-introduce video node offset
+
+Offset the backend dev-nodes starting at /dev/video20
+onwards to maintain backward compatibility with the
+pre-upstreamed kernel driver.
+
+Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
+---
+ drivers/media/platform/raspberrypi/pisp_be/pisp_be.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+--- a/drivers/media/platform/raspberrypi/pisp_be/pisp_be.c
++++ b/drivers/media/platform/raspberrypi/pisp_be/pisp_be.c
+@@ -21,6 +21,9 @@
+
+ #include "pisp_be_formats.h"
+
++/* Offset to use when registering the /dev/videoX node */
++#define PISPBE_VIDEO_NODE_OFFSET 20
++
+ /* Maximum number of config buffers possible */
+ #define PISP_BE_NUM_CONFIG_BUFFERS VB2_MAX_FRAME
+
+@@ -1484,7 +1487,8 @@ static int pispbe_init_node(struct pispb
+ goto err_unregister_queue;
+ }
+
+- ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
++ ret = video_register_device(vdev, VFL_TYPE_VIDEO,
++ PISPBE_VIDEO_NODE_OFFSET);
+ if (ret) {
+ dev_err(pispbe->dev,
+ "Failed to register video %s device node\n",
--- /dev/null
+From 6e4ad40811170653431fc40a6fdc3f486863b40f Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Thu, 4 Jul 2024 18:15:00 +0100
+Subject: [PATCH 1163/1215] dts: Make camN_reg and camN_reg_gpio overrides
+ generic
+
+The camera regulator GPIO can be used for other purposes,
+so the camN_reg override to allow disabling is potentially
+useful on any platform.
+camN_gpio is less useful, but isn't invalid.
+
+Move these overrides from the CM dt files to bcm270x-rpi.dtsi
+and bcm2712-rpi.dtsi.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ .../arm/boot/dts/broadcom/bcm2708-rpi-cm.dtsi | 4 ----
+ .../arm/boot/dts/broadcom/bcm2709-rpi-cm2.dts | 4 ----
+ arch/arm/boot/dts/broadcom/bcm270x-rpi.dtsi | 7 +++++++
+ .../arm/boot/dts/broadcom/bcm2710-rpi-cm3.dts | 4 ----
+ .../arm/boot/dts/broadcom/bcm2711-rpi-cm4.dts | 7 -------
+ .../boot/dts/broadcom/bcm2711-rpi-cm4s.dts | 5 -----
+ arch/arm/boot/dts/broadcom/bcm2712-rpi.dtsi | 8 ++++++++
+ arch/arm/boot/dts/overlays/README | 20 +++++++++----------
+ 8 files changed, 25 insertions(+), 34 deletions(-)
+
+--- a/arch/arm/boot/dts/broadcom/bcm2708-rpi-cm.dtsi
++++ b/arch/arm/boot/dts/broadcom/bcm2708-rpi-cm.dtsi
+@@ -19,9 +19,5 @@ i2c_vc: &i2c0 {
+ act_led_gpio = <&led_act>,"gpios:4";
+ act_led_activelow = <&led_act>,"gpios:8";
+ act_led_trigger = <&led_act>,"linux,default-trigger";
+- cam0_reg = <&cam0_reg>,"status";
+- cam0_reg_gpio = <&cam0_reg>,"gpio:4";
+- cam1_reg = <&cam1_reg>,"status";
+- cam1_reg_gpio = <&cam1_reg>,"gpio:4";
+ };
+ };
+--- a/arch/arm/boot/dts/broadcom/bcm2709-rpi-cm2.dts
++++ b/arch/arm/boot/dts/broadcom/bcm2709-rpi-cm2.dts
+@@ -211,9 +211,5 @@ i2c_csi_dsi0: &i2c0 {
+ act_led_gpio = <&led_act>,"gpios:4";
+ act_led_activelow = <&led_act>,"gpios:8";
+ act_led_trigger = <&led_act>,"linux,default-trigger";
+- cam0_reg = <&cam0_reg>,"status";
+- cam0_reg_gpio = <&cam0_reg>,"gpio:4";
+- cam1_reg = <&cam1_reg>,"status";
+- cam1_reg_gpio = <&cam1_reg>,"gpio:4";
+ };
+ };
+--- a/arch/arm/boot/dts/broadcom/bcm270x-rpi.dtsi
++++ b/arch/arm/boot/dts/broadcom/bcm270x-rpi.dtsi
+@@ -111,6 +111,13 @@
+ <&csi0>, "sync-gpios:4",
+ <&csi0>, "sync-gpios:8=", <GPIO_ACTIVE_LOW>;
+
++ cam0_reg = <&cam0_reg>,"status";
++ cam0_reg_gpio = <&cam0_reg>,"gpio:4",
++ <&cam0_reg>,"gpio:0=", <&gpio>;
++ cam1_reg = <&cam1_reg>,"status";
++ cam1_reg_gpio = <&cam1_reg>,"gpio:4",
++ <&cam1_reg>,"gpio:0=", <&gpio>;
++
+ strict_gpiod = <&chosen>, "bootargs=pinctrl_bcm2835.persist_gpio_outputs=n";
+ };
+ };
+--- a/arch/arm/boot/dts/broadcom/bcm2710-rpi-cm3.dts
++++ b/arch/arm/boot/dts/broadcom/bcm2710-rpi-cm3.dts
+@@ -211,9 +211,5 @@ i2c_csi_dsi0: &i2c0 {
+ act_led_gpio = <&led_act>,"gpios:4";
+ act_led_activelow = <&led_act>,"gpios:8";
+ act_led_trigger = <&led_act>,"linux,default-trigger";
+- cam0_reg = <&cam0_reg>,"status";
+- cam0_reg_gpio = <&cam0_reg>,"gpio:4";
+- cam1_reg = <&cam1_reg>,"status";
+- cam1_reg_gpio = <&cam1_reg>,"gpio:4";
+ };
+ };
+--- a/arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4.dts
++++ b/arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4.dts
+@@ -498,13 +498,6 @@ i2c_csi_dsi0: &i2c0 {
+ <&ant2>, "output-high?=off",
+ <&ant2>, "output-low?=on";
+
+- cam0_reg = <&cam0_reg>,"status";
+- cam0_reg_gpio = <&cam0_reg>,"gpio:4",
+- <&cam0_reg>,"gpio:0=", <&gpio>;
+- cam1_reg = <&cam1_reg>,"status";
+- cam1_reg_gpio = <&cam1_reg>,"gpio:4",
+- <&cam1_reg>,"gpio:0=", <&gpio>;
+-
+ pcie_tperst_clk_ms = <&pcie0>,"brcm,tperst-clk-ms:0";
+ };
+ };
+--- a/arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4s.dts
++++ b/arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4s.dts
+@@ -289,10 +289,5 @@ i2c_csi_dsi0: &i2c0 {
+ act_led_gpio = <&led_act>,"gpios:4";
+ act_led_activelow = <&led_act>,"gpios:8";
+ act_led_trigger = <&led_act>,"linux,default-trigger";
+-
+- cam0_reg = <&cam0_reg>,"status";
+- cam0_reg_gpio = <&cam0_reg>,"gpio:4";
+- cam1_reg = <&cam1_reg>,"status";
+- cam1_reg_gpio = <&cam1_reg>,"gpio:4";
+ };
+ };
+--- a/arch/arm/boot/dts/broadcom/bcm2712-rpi.dtsi
++++ b/arch/arm/boot/dts/broadcom/bcm2712-rpi.dtsi
+@@ -106,6 +106,14 @@
+ nvmem_priv_rw = <&nvmem_priv>,"rw?";
+ nvmem_mac_rw = <&nvmem_mac>,"rw?";
+ strict_gpiod = <&chosen>, "bootargs=pinctrl_rp1.persist_gpio_outputs=n";
++
++ cam0_reg = <&cam0_reg>,"status";
++ cam0_reg_gpio = <&cam0_reg>,"gpio:4",
++ <&cam0_reg>,"gpio:0=", <&gpio>;
++ cam1_reg = <&cam1_reg>,"status";
++ cam1_reg_gpio = <&cam1_reg>,"gpio:4",
++ <&cam1_reg>,"gpio:0=", <&gpio>;
++
+ };
+ };
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -171,21 +171,21 @@ Params:
+ button_debounce Set the debounce delay (in ms) on the power/
+ shutdown button (default 50ms)
+
+- cam0_reg Enables CAM 0 regulator.
+- Only required on CM1 & 3.
++ cam0_reg Controls CAM 0 regulator.
++ Disabled by default on CM1 & 3.
++ Enabled by default on all other boards.
+
+ cam0_reg_gpio Set GPIO for CAM 0 regulator.
+- Default 31 on CM1, 3, and 4S.
+- Default of GPIO expander 5 on CM4, but override
+- switches to normal GPIO.
++ NB override switches to the normal GPIO driver,
++ even if the original was on the GPIO expander.
+
+- cam1_reg Enables CAM 1 regulator.
+- Only required on CM1 & 3.
++ cam1_reg Controls CAM 1 regulator.
++ Disabled by default on CM1 & 3.
++ Enabled by default on all other boards.
+
+ cam1_reg_gpio Set GPIO for CAM 1 regulator.
+- Default 3 on CM1, 3, and 4S.
+- Default of GPIO expander 5 on CM4, but override
+- switches to normal GPIO.
++ NB override switches to the normal GPIO driver,
++ even if the original was on the GPIO expander.
+
+ cam0_sync Enable a GPIO to reflect frame sync from CSI0,
+ going high on frame start, and low on frame end.
--- /dev/null
+From afd949f5f64d224cf7a016ef933257842bc170ab Mon Sep 17 00:00:00 2001
+From: Richard Oliver <richard.oliver@raspberrypi.com>
+Date: Fri, 24 May 2024 10:34:45 +0100
+Subject: [PATCH 1164/1215] spi: dt-bindings: Add RPI RP2040 GPIO Bridge
+
+Add YAML device tree bindings for the Raspberry Pi RP2040 GPIO Bridge.
+
+Signed-off-by: Richard Oliver <richard.oliver@raspberrypi.com>
+---
+ .../spi/raspberrypi,rp2040-gpio-bridge.yaml | 77 +++++++++++++++++++
+ MAINTAINERS | 5 ++
+ 2 files changed, 82 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/spi/raspberrypi,rp2040-gpio-bridge.yaml
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/spi/raspberrypi,rp2040-gpio-bridge.yaml
+@@ -0,0 +1,77 @@
++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
++%YAML 1.2
++---
++$id: http://devicetree.org/schemas/spi/raspberrypi,rp2040-gpio-bridge.yaml#
++$schema: http://devicetree.org/meta-schemas/core.yaml#
++
++title: Raspberry Pi RP2040 GPIO Bridge
++
++maintainers:
++ - Raspberry Pi <kernel-list@raspberrypi.com>
++
++description: |-
++ The Raspberry Pi PR2040 GPIO bridge can be used as a GPIO expander and
++ Tx-only SPI master.
++
++properties:
++ reg:
++ description: I2C slave address
++ const: 0x40
++
++ compatible:
++ const: raspberrypi,rp2040-gpio-bridge
++
++ power-supply:
++ description: Phandle to the regulator that powers the RP2040.
++
++ '#address-cells':
++ const: 1
++
++ '#size-cells':
++ const: 0
++
++ '#gpio-cells':
++ const: 2
++
++ gpio-controller: true
++
++ fast_xfer_requires_i2c_lock:
++ description: Set if I2C bus should be locked during fast transfer.
++
++ fast_xfer_recv_gpio_base:
++ description: RP2040 GPIO base for fast transfer pair.
++
++ fast_xfer-gpios:
++ description: RP1 GPIOs to use for fast transfer clock and data.
++
++required:
++ - reg
++ - compatible
++ - power-supply
++ - '#gpio-cells'
++ - gpio-controller
++
++additionalProperties: false
++
++examples:
++ - |
++ i2c {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ spi@40 {
++ reg = <0x40>;
++ compatible = "raspberrypi,rp2040-gpio-bridge";
++ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ power-supply = <&cam_dummy_reg>;
++
++ #gpio-cells = <2>;
++ gpio-controller;
++ };
++ };
++
++...
++
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -18027,6 +18027,11 @@ F: drivers/ras/
+ F: include/linux/ras.h
+ F: include/ras/ras_event.h
+
++RASPBERRY PI RP2040 GPIO BRIDGE DRIVER
++M: Raspberry Pi Kernel Maintenance <kernel-list@raspberrypi.com>
++S: Maintained
++F: Documentation/devicetree/bindings/spi/raspberrypi,rp2040-gpio-bridge.yaml
++
+ RAYLINK/WEBGEAR 802.11 WIRELESS LAN DRIVER
+ L: linux-wireless@vger.kernel.org
+ S: Orphan
--- /dev/null
+From 99ae83f1944f47d4338ef7a6f02536927fc6ce57 Mon Sep 17 00:00:00 2001
+From: Richard Oliver <richard.oliver@raspberrypi.com>
+Date: Tue, 21 May 2024 13:47:23 +0100
+Subject: [PATCH 1165/1215] spi: Add a driver for the RPI RP2040 GPIO bridge
+
+The Raspberry Pi RP2040 GPIO bridge is an I2C-attached device exposing
+both a Tx-only SPI controller, and a GPIO controller.
+
+Due to the relative difference in transfer rates between standard-mode
+I2C and SPI, the GPIO bridge makes use of 12 MiB of non-volatile storage
+to cache repeated transfers. This cache is arranged in ~8 KiB blocks and
+is addressed by the MD5 digest of the data contained therein.
+
+Optionally, this driver is able to take advantage of Raspberry Pi RP1
+GPIOs to achieve faster than I2C data transfer rates.
+
+Signed-off-by: Richard Oliver <richard.oliver@raspberrypi.com>
+---
+ MAINTAINERS | 1 +
+ drivers/spi/Kconfig | 12 +
+ drivers/spi/Makefile | 1 +
+ drivers/spi/spi-rp2040-gpio-bridge.c | 1219 ++++++++++++++++++++++++++
+ 4 files changed, 1233 insertions(+)
+ create mode 100644 drivers/spi/spi-rp2040-gpio-bridge.c
+
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -18031,6 +18031,7 @@ RASPBERRY PI RP2040 GPIO BRIDGE DRIVER
+ M: Raspberry Pi Kernel Maintenance <kernel-list@raspberrypi.com>
+ S: Maintained
+ F: Documentation/devicetree/bindings/spi/raspberrypi,rp2040-gpio-bridge.yaml
++F: drivers/spi/spi-rp2040-gpio-bridge.c
+
+ RAYLINK/WEBGEAR 802.11 WIRELESS LAN DRIVER
+ L: linux-wireless@vger.kernel.org
+--- a/drivers/spi/Kconfig
++++ b/drivers/spi/Kconfig
+@@ -846,6 +846,18 @@ config SPI_RB4XX
+ help
+ SPI controller driver for the Mikrotik RB4xx series boards.
+
++config SPI_RP2040_GPIO_BRIDGE
++ tristate "Raspberry Pi RP2040 GPIO Bridge"
++ depends on I2C && SPI && GPIOLIB
++ help
++ Support for the Raspberry Pi RP2040 GPIO bridge.
++
++ This driver provides support for the Raspberry Pi PR2040 GPIO bridge.
++ It can be used as a GPIO expander and a Tx-only SPI master.
++
++ Optionally, this driver is able to take advantage of Raspberry Pi RP1
++ GPIOs to achieve faster than I2C data transfer rates.
++
+ config SPI_RPCIF
+ tristate "Renesas RPC-IF SPI driver"
+ depends on RENESAS_RPCIF
+--- a/drivers/spi/Makefile
++++ b/drivers/spi/Makefile
+@@ -115,6 +115,7 @@ obj-$(CONFIG_SPI_ROCKCHIP) += spi-rockc
+ obj-$(CONFIG_SPI_ROCKCHIP_SFC) += spi-rockchip-sfc.o
+ obj-$(CONFIG_SPI_RB4XX) += spi-rb4xx.o
+ obj-$(CONFIG_MACH_REALTEK_RTL) += spi-realtek-rtl.o
++obj-$(CONFIG_SPI_RP2040_GPIO_BRIDGE) += spi-rp2040-gpio-bridge.o
+ obj-$(CONFIG_SPI_RPCIF) += spi-rpc-if.o
+ obj-$(CONFIG_SPI_RSPI) += spi-rspi.o
+ obj-$(CONFIG_SPI_RZV2M_CSI) += spi-rzv2m-csi.o
+--- /dev/null
++++ b/drivers/spi/spi-rp2040-gpio-bridge.c
+@@ -0,0 +1,1219 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * RP2040 GPIO Bridge
++ *
++ * Copyright (C) 2023, 2024, Raspberry Pi Ltd
++ */
++
++#include <crypto/hash.h>
++#include <linux/crypto.h>
++#include <linux/delay.h>
++#include <linux/firmware.h>
++#include <linux/gpio/driver.h>
++#include <linux/i2c.h>
++#include <linux/kernel.h>
++#include <linux/minmax.h>
++#include <linux/of_address.h>
++#include <linux/pm_runtime.h>
++#include <linux/spi/spi.h>
++#include <linux/stddef.h>
++#include <linux/types.h>
++
++#define MODULE_NAME "rp2040-gpio-bridge"
++
++#define I2C_RETRIES 4U
++
++#define ONE_KIB 1024U
++#define MD5_SUFFIX_SIZE 9U
++
++#define RP2040_GBDG_FLASH_BLOCK_SIZE (8U * ONE_KIB)
++#define RP2040_GBDG_BLOCK_SIZE (RP2040_GBDG_FLASH_BLOCK_SIZE - MD5_SUFFIX_SIZE)
++
++/*
++ * 1MiB transfer size is an arbitrary limit
++ * Max value is 4173330 (using a single manifest)
++ */
++#define MAX_TRANSFER_SIZE (1024U * ONE_KIB)
++
++#define HALF_BUFFER (4U * ONE_KIB)
++
++#define STATUS_SIZE 4
++#define MD5_DIGEST_SIZE 16
++#define VERSION_SIZE 4
++#define ID_SIZE 8
++#define TOTAL_RD_HDR_SIZE \
++ (STATUS_SIZE + MD5_DIGEST_SIZE + VERSION_SIZE + ID_SIZE)
++
++struct rp2040_gbdg_device_info {
++ u8 md5[MD5_DIGEST_SIZE];
++ u64 id;
++ u32 version;
++ u32 status;
++};
++
++static_assert(sizeof(struct rp2040_gbdg_device_info) == TOTAL_RD_HDR_SIZE);
++
++#define MANIFEST_UNIT_SIZE 16
++static_assert(MD5_DIGEST_SIZE == MANIFEST_UNIT_SIZE);
++#define MANIFEST_HEADER_UNITS 1
++#define MANIFEST_DATA_UNITS \
++ DIV_ROUND_UP(MAX_TRANSFER_SIZE, RP2040_GBDG_BLOCK_SIZE)
++
++#define STATUS_BUSY 0x01
++
++#define DIRECT_PREFIX 0x00
++#define DIRECT_CMD_CS 0x07
++#define DIRECT_CMD_EMIT 0x08
++
++#define WRITE_DATA_PREFIX 0x80
++#define WRITE_DATA_PREFIX_SIZE 1
++
++#define FIXED_SIZE_CMD_PREFIX 0x81
++
++#define WRITE_DATA_UPPER_PREFIX 0x82
++#define WRITE_DATA_UPPER_PREFIX_SIZE 1
++
++#define NUM_GPIO 24
++
++enum rp2040_gbdg_fixed_size_commands {
++ /* 10-byte commands */
++ CMD_SAVE_CACHE = 0x07,
++ CMD_SEND_RB = 0x08,
++ CMD_GPIO_ST_CL = 0x0b,
++ CMD_GPIO_OE = 0x0c,
++ CMD_DAT_RECV = 0x0d,
++ CMD_DAT_EMIT = 0x0e,
++ /* 18-byte commands */
++ CMD_READ_CSUM = 0x11,
++ CMD_SEND_MANI = 0x13,
++};
++
++struct rp2040_gbdg {
++ struct spi_controller *controller;
++
++ struct i2c_client *client;
++ struct crypto_shash *shash;
++ struct shash_desc *shash_desc;
++
++ struct regulator *regulator;
++
++ struct gpio_chip gc;
++ u32 gpio_requested;
++ u32 gpio_direction;
++
++ bool fast_xfer_requires_i2c_lock;
++ struct gpio_descs *fast_xfer_gpios;
++ u32 fast_xfer_recv_gpio_base;
++ u8 fast_xfer_data_index;
++ u8 fast_xfer_clock_index;
++ void __iomem *gpio_base;
++ void __iomem *rio_base;
++
++ bool bypass_cache;
++
++ u8 buffer[2 + HALF_BUFFER];
++ u8 manifest_prep[(MANIFEST_HEADER_UNITS + MANIFEST_DATA_UNITS) *
++ MANIFEST_UNIT_SIZE];
++};
++
++static int rp2040_gbdg_gpio_dir_in(struct gpio_chip *gc, unsigned int offset);
++static void rp2040_gbdg_gpio_set(struct gpio_chip *gc, unsigned int offset,
++ int value);
++static int rp2040_gbdg_fast_xfer(struct rp2040_gbdg *priv_data, const u8 *data,
++ size_t len);
++
++static int rp2040_gbdg_rp1_calc_offsets(u8 gpio, size_t *bank_offset,
++ u8 *shift_offset)
++{
++ if (!bank_offset || !shift_offset || gpio >= 54)
++ return -EINVAL;
++ if (gpio < 28) {
++ *bank_offset = 0x0000;
++ *shift_offset = gpio;
++ } else if (gpio < 34) {
++ *bank_offset = 0x4000;
++ *shift_offset = gpio - 28;
++ } else {
++ *bank_offset = 0x8000;
++ *shift_offset = gpio - 34;
++ }
++
++ return 0;
++}
++
++static int rp2040_gbdg_calc_mux_offset(u8 gpio, size_t *offset)
++{
++ size_t bank_offset;
++ u8 shift_offset;
++ int ret;
++
++ ret = rp2040_gbdg_rp1_calc_offsets(gpio, &bank_offset, &shift_offset);
++ if (ret)
++ return ret;
++ *offset = bank_offset + shift_offset * 8 + 0x4;
++
++ return 0;
++}
++
++static int rp2040_gbdg_rp1_read_mux(struct rp2040_gbdg *priv_data, u8 gpio,
++ u32 *data)
++{
++ size_t offset;
++ int ret;
++
++ ret = rp2040_gbdg_calc_mux_offset(gpio, &offset);
++ if (ret)
++ return ret;
++
++ *data = readl(priv_data->gpio_base + offset);
++
++ return 0;
++}
++
++static int rp2040_gbdg_rp1_write_mux(struct rp2040_gbdg *priv_data, u8 gpio,
++ u32 val)
++{
++ size_t offset;
++ int ret;
++
++ ret = rp2040_gbdg_calc_mux_offset(gpio, &offset);
++ if (ret)
++ return ret;
++
++ writel(val, priv_data->gpio_base + offset);
++
++ return 0;
++}
++
++static size_t rp2040_gbdg_max_transfer_size(struct spi_device *spi)
++{
++ return MAX_TRANSFER_SIZE;
++}
++
++static int rp2040_gbdg_get_device_info(struct i2c_client *client,
++ struct rp2040_gbdg_device_info *info)
++{
++ u8 buf[TOTAL_RD_HDR_SIZE];
++ u8 retries = I2C_RETRIES;
++ u8 *read_pos = buf;
++ size_t field_size;
++ int ret;
++
++ do {
++ ret = i2c_master_recv(client, buf, sizeof(buf));
++ if (!retries--)
++ break;
++ } while (ret == -ETIMEDOUT);
++
++ if (ret != sizeof(buf))
++ return ret < 0 ? ret : -EIO;
++
++ field_size = sizeof_field(struct rp2040_gbdg_device_info, status);
++ memcpy(&info->status, read_pos, field_size);
++ read_pos += field_size;
++
++ field_size = sizeof_field(struct rp2040_gbdg_device_info, md5);
++ memcpy(&info->md5, read_pos, field_size);
++ read_pos += field_size;
++
++ field_size = sizeof_field(struct rp2040_gbdg_device_info, version);
++ memcpy(&info->version, read_pos, field_size);
++ read_pos += field_size;
++
++ field_size = sizeof_field(struct rp2040_gbdg_device_info, id);
++ memcpy(&info->id, read_pos, field_size);
++
++ return 0;
++}
++
++static int rp2040_gbdg_poll_device_info(struct i2c_client *client,
++ struct rp2040_gbdg_device_info *info)
++{
++ struct rp2040_gbdg_device_info itnl;
++ int ret;
++
++ itnl.status = STATUS_BUSY;
++
++ while (itnl.status & STATUS_BUSY) {
++ ret = rp2040_gbdg_get_device_info(client, &itnl);
++ if (ret)
++ return ret;
++ }
++ memcpy(info, &itnl, sizeof(itnl));
++
++ return 0;
++}
++
++static int rp2040_gbdg_get_buffer_hash(struct i2c_client *client, u8 *md5)
++{
++ struct rp2040_gbdg_device_info info;
++ int ret;
++
++ ret = rp2040_gbdg_poll_device_info(client, &info);
++ if (ret)
++ return ret;
++
++ memcpy(md5, info.md5, MD5_DIGEST_SIZE);
++
++ return 0;
++}
++
++static int rp2040_gbdg_wait_until_free(struct i2c_client *client, u8 *status)
++{
++ struct rp2040_gbdg_device_info info;
++ int ret;
++
++ ret = rp2040_gbdg_poll_device_info(client, &info);
++ if (ret)
++ return ret;
++
++ if (status)
++ *status = info.status;
++
++ return 0;
++}
++
++static int rp2040_gbdg_i2c_send(struct i2c_client *client, const u8 *buf,
++ size_t len)
++{
++ u8 retries = I2C_RETRIES;
++ int ret;
++
++ ret = rp2040_gbdg_wait_until_free(client, NULL);
++ if (ret) {
++ dev_err(&client->dev,
++ "%s() rp2040_gbdg_wait_until_free failed\n", __func__);
++ return ret;
++ }
++
++ do {
++ ret = i2c_master_send(client, buf, len);
++ if (!retries--)
++ break;
++ } while (ret == -ETIMEDOUT);
++
++ if (ret != len) {
++ dev_err(&client->dev, "%s() i2c_master_send returned %d\n",
++ __func__, ret);
++ return ret < 0 ? ret : -EIO;
++ }
++
++ return 0;
++}
++
++static int rp2040_gbdg_10byte_cmd(struct i2c_client *client, u8 cmd, u32 addr,
++ u32 len)
++{
++ u8 buffer[10];
++
++ buffer[0] = FIXED_SIZE_CMD_PREFIX;
++ buffer[1] = cmd;
++ memcpy(&buffer[2], &addr, sizeof(addr));
++ memcpy(&buffer[6], &len, sizeof(len));
++
++ return rp2040_gbdg_i2c_send(client, buffer, sizeof(buffer));
++}
++
++static int rp2040_gbdg_18byte_cmd(struct i2c_client *client, u8 cmd,
++ const u8 *digest)
++{
++ u8 buffer[18];
++
++ buffer[0] = FIXED_SIZE_CMD_PREFIX;
++ buffer[1] = cmd;
++ memcpy(&buffer[2], digest, MD5_DIGEST_SIZE);
++
++ return rp2040_gbdg_i2c_send(client, buffer, sizeof(buffer));
++}
++
++static int rp2040_gbdg_block_hash(struct rp2040_gbdg *priv_data, const u8 *data,
++ size_t len, u8 *out)
++{
++ size_t remaining = RP2040_GBDG_BLOCK_SIZE;
++ size_t pad;
++ int ret;
++
++ static const u8 padding[64] = {
++ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++ 0xFF, 0xFF, 0xFF, 0xFF,
++ };
++
++ if (len > RP2040_GBDG_BLOCK_SIZE) {
++ return -EMSGSIZE;
++ } else if (len == RP2040_GBDG_BLOCK_SIZE) {
++ return crypto_shash_digest(priv_data->shash_desc, data, len,
++ out);
++ } else {
++ ret = crypto_shash_init(priv_data->shash_desc);
++ if (ret)
++ return ret;
++
++ ret = crypto_shash_update(priv_data->shash_desc, data, len);
++ if (ret)
++ return ret;
++ remaining -= len;
++
++ /* Pad up-to a 64-byte boundary, unless that takes us over. */
++ pad = round_up(len, 64);
++ if (pad != len && pad < RP2040_GBDG_BLOCK_SIZE) {
++ ret = crypto_shash_update(priv_data->shash_desc,
++ padding, pad - len);
++ if (ret)
++ return ret;
++ remaining -= (pad - len);
++ }
++
++ /* Pad up-to RP2040_GBDG_BLOCK_SIZE in, preferably, 64-byte chunks */
++ while (remaining) {
++ pad = min_t(size_t, remaining, (size_t)64U);
++ ret = crypto_shash_update(priv_data->shash_desc,
++ padding, pad);
++ if (ret)
++ return ret;
++ remaining -= pad;
++ }
++ return crypto_shash_final(priv_data->shash_desc, out);
++ }
++}
++
++static int rp2040_gbdg_set_remote_buffer_fast(struct rp2040_gbdg *priv_data,
++ const u8 *data, unsigned int len)
++{
++ struct i2c_client *client = priv_data->client;
++ int ret;
++
++ if (len > RP2040_GBDG_BLOCK_SIZE)
++ return -EMSGSIZE;
++ if (!priv_data->fast_xfer_gpios)
++ return -EIO;
++
++ ret = rp2040_gbdg_10byte_cmd(client, CMD_DAT_RECV,
++ priv_data->fast_xfer_recv_gpio_base, len);
++ if (ret) {
++ dev_err(&client->dev, "%s() failed to enter fast data mode\n",
++ __func__);
++ return ret;
++ }
++
++ return rp2040_gbdg_fast_xfer(priv_data, data, len);
++}
++
++static int rp2040_gbdg_set_remote_buffer_i2c(struct rp2040_gbdg *priv_data,
++ const u8 *data, unsigned int len)
++{
++ struct i2c_client *client = priv_data->client;
++ unsigned int write_len;
++ int ret;
++
++ if (len > RP2040_GBDG_BLOCK_SIZE)
++ return -EMSGSIZE;
++
++ priv_data->buffer[0] = WRITE_DATA_PREFIX;
++ write_len = min(len, HALF_BUFFER);
++ memcpy(&priv_data->buffer[1], data, write_len);
++
++ ret = rp2040_gbdg_i2c_send(client, priv_data->buffer, write_len + 1);
++ if (ret)
++ return ret;
++
++ len -= write_len;
++ data += write_len;
++
++ if (!len)
++ return 0;
++
++ priv_data->buffer[0] = WRITE_DATA_UPPER_PREFIX;
++ memcpy(&priv_data->buffer[1], data, len);
++ ret = rp2040_gbdg_i2c_send(client, priv_data->buffer, len + 1);
++
++ return ret;
++}
++
++static int rp2040_gbdg_set_remote_buffer(struct rp2040_gbdg *priv_data,
++ const u8 *data, unsigned int len)
++{
++ if (priv_data->fast_xfer_gpios)
++ return rp2040_gbdg_set_remote_buffer_fast(priv_data, data, len);
++ else
++ return rp2040_gbdg_set_remote_buffer_i2c(priv_data, data, len);
++}
++
++/* Loads data by checksum if available or resorts to sending byte-by-byte */
++static int rp2040_gbdg_load_block_remote(struct rp2040_gbdg *priv_data,
++ const void *data, unsigned int len,
++ u8 *digest, bool persist)
++{
++ u8 ascii_digest[MD5_DIGEST_SIZE * 2 + 1] = { 0 };
++ struct i2c_client *client = priv_data->client;
++ u8 remote_digest[MD5_DIGEST_SIZE];
++ u8 local_digest[MD5_DIGEST_SIZE];
++ int ret;
++
++ if (len > RP2040_GBDG_BLOCK_SIZE)
++ return -EMSGSIZE;
++
++ ret = rp2040_gbdg_block_hash(priv_data, data, len, local_digest);
++ if (ret)
++ return ret;
++
++ if (digest)
++ memcpy(digest, local_digest, MD5_DIGEST_SIZE);
++
++ /* Check if the RP2040 has the data already */
++ ret = rp2040_gbdg_18byte_cmd(client, CMD_READ_CSUM, local_digest);
++ if (ret)
++ return ret;
++
++ ret = rp2040_gbdg_get_buffer_hash(client, remote_digest);
++ if (ret)
++ return ret;
++
++ if (memcmp(local_digest, remote_digest, MD5_DIGEST_SIZE)) {
++ bin2hex(ascii_digest, local_digest, MD5_DIGEST_SIZE);
++ dev_info(&client->dev, "%s() device missing data: %s\n",
++ __func__, ascii_digest);
++ /*
++ * N.B. We're fine to send (the potentially shorter) transfer->len
++ * number of bytes here as the RP2040 will pad with 0xFF up to buffer
++ * size once we stop sending.
++ */
++ ret = rp2040_gbdg_set_remote_buffer(priv_data, data, len);
++ if (ret)
++ return ret;
++
++ /* Make sure the data actually arrived. */
++ ret = rp2040_gbdg_get_buffer_hash(client, remote_digest);
++ if (memcmp(local_digest, remote_digest, MD5_DIGEST_SIZE)) {
++ dev_err(&priv_data->client->dev,
++ "%s() unable to send data to device\n",
++ __func__);
++ return -EREMOTEIO;
++ }
++
++ if (persist) {
++ dev_info(&client->dev,
++ "%s() sent missing data to device, saving\n",
++ __func__);
++ ret = rp2040_gbdg_10byte_cmd(client, CMD_SAVE_CACHE, 0,
++ 0);
++ if (ret)
++ return ret;
++ }
++ }
++
++ return 0;
++}
++
++static int rp2040_gbdg_transfer_block(struct rp2040_gbdg *priv_data,
++ const void *data, unsigned int len)
++{
++ struct i2c_client *client = priv_data->client;
++ int ret;
++
++ if (len > RP2040_GBDG_BLOCK_SIZE)
++ return -EMSGSIZE;
++
++ ret = rp2040_gbdg_load_block_remote(priv_data, data, len, NULL, true);
++ if (ret)
++ return ret;
++
++ /* Remote rambuffer now has correct contents, send it */
++ ret = rp2040_gbdg_10byte_cmd(client, CMD_SEND_RB, 0, len);
++ if (ret)
++ return ret;
++
++ /*
++ * Wait for data to have actually completed sending as we may be de-asserting CS too quickly
++ * otherwise.
++ */
++ ret = rp2040_gbdg_wait_until_free(client, NULL);
++ if (ret)
++ return ret;
++
++ return 0;
++}
++
++static int rp2040_gbdg_transfer_manifest(struct rp2040_gbdg *priv_data,
++ const u8 *data, unsigned int len)
++{
++ struct i2c_client *client = priv_data->client;
++ static const char magic[] = "DATA_MANFST";
++ unsigned int remaining = len;
++ const u32 data_length = len;
++ u8 digest[MD5_DIGEST_SIZE];
++ u8 *digest_write_pos;
++ u8 status;
++ int ret;
++
++ memcpy(priv_data->manifest_prep, magic, sizeof(magic));
++ memcpy(priv_data->manifest_prep + sizeof(magic), &data_length,
++ sizeof(data_length));
++ digest_write_pos =
++ priv_data->manifest_prep + sizeof(magic) + sizeof(data_length);
++
++ while (remaining) {
++ unsigned int size = min(remaining, RP2040_GBDG_BLOCK_SIZE);
++
++ ret = rp2040_gbdg_block_hash(priv_data, data, size,
++ digest_write_pos);
++ if (ret)
++ return ret;
++
++ remaining -= size;
++ data += size;
++ digest_write_pos += MD5_DIGEST_SIZE;
++ }
++
++ ret = rp2040_gbdg_load_block_remote(
++ priv_data, priv_data->manifest_prep,
++ digest_write_pos - priv_data->manifest_prep, digest, true);
++ if (ret)
++ return ret;
++
++ dev_info(&client->dev, "%s() issue CMD_SEND_MANI\n", __func__);
++ ret = rp2040_gbdg_18byte_cmd(client, CMD_SEND_MANI, digest);
++ if (ret)
++ return ret;
++
++ ret = rp2040_gbdg_wait_until_free(client, &status);
++ if (ret)
++ return ret;
++
++ dev_info(&client->dev, "%s() SEND_MANI response: %02x\n", __func__,
++ status);
++
++ return status;
++}
++
++/* Precondition: correctly initialised fast_xfer_*, gpio_base, rio_base */
++static int rp2040_gbdg_fast_xfer(struct rp2040_gbdg *priv_data, const u8 *data,
++ size_t len)
++{
++ struct i2c_client *client = priv_data->client;
++ void __iomem *clock_toggle;
++ void __iomem *data_set;
++ size_t clock_bank;
++ size_t data_bank;
++ u8 clock_offset;
++ u8 data_offset;
++ u32 clock_mux;
++ u32 data_mux;
++
++ if (priv_data->fast_xfer_requires_i2c_lock)
++ i2c_lock_bus(client->adapter, I2C_LOCK_ROOT_ADAPTER);
++
++ rp2040_gbdg_rp1_read_mux(priv_data, priv_data->fast_xfer_data_index,
++ &data_mux);
++ rp2040_gbdg_rp1_read_mux(priv_data, priv_data->fast_xfer_clock_index,
++ &clock_mux);
++
++ gpiod_direction_output(priv_data->fast_xfer_gpios->desc[0], 1);
++ gpiod_direction_output(priv_data->fast_xfer_gpios->desc[1], 0);
++
++ rp2040_gbdg_rp1_calc_offsets(priv_data->fast_xfer_data_index,
++ &data_bank, &data_offset);
++ rp2040_gbdg_rp1_calc_offsets(priv_data->fast_xfer_clock_index,
++ &clock_bank, &clock_offset);
++
++ data_set = priv_data->rio_base + data_bank + 0x2000; /* SET offset */
++ clock_toggle =
++ priv_data->rio_base + clock_bank + 0x1000; /* XOR offset */
++
++ while (len--) {
++ /* MSB first ordering */
++ u32 d = ~(*data++) << 4U;
++ /*
++ * Clock out each bit of data, LSB first
++ * (DDR, achieves approx 5 Mbps)
++ */
++ for (size_t i = 0; i < 8; i++) {
++ /* Branchless set/clr data */
++ writel(1 << data_offset,
++ data_set + ((d <<= 1) & 0x1000) /* CLR offset */
++ );
++
++ /* Toggle the clock */
++ writel(1 << clock_offset, clock_toggle);
++ }
++ }
++
++ rp2040_gbdg_rp1_write_mux(priv_data, priv_data->fast_xfer_data_index,
++ data_mux);
++ rp2040_gbdg_rp1_write_mux(priv_data, priv_data->fast_xfer_clock_index,
++ clock_mux);
++
++ if (priv_data->fast_xfer_requires_i2c_lock)
++ i2c_unlock_bus(client->adapter, I2C_LOCK_ROOT_ADAPTER);
++
++ return 0;
++}
++
++static int rp2040_gbdg_transfer_bypass(struct rp2040_gbdg *priv_data,
++ const u8 *data, unsigned int length)
++{
++ int ret;
++ u8 *buf;
++
++ if (priv_data->fast_xfer_gpios) {
++ ret = rp2040_gbdg_10byte_cmd(
++ priv_data->client, CMD_DAT_EMIT,
++ priv_data->fast_xfer_recv_gpio_base, length);
++ return ret ? ret :
++ rp2040_gbdg_fast_xfer(priv_data, data, length);
++ }
++
++ buf = priv_data->buffer;
++
++ while (length) {
++ unsigned int xfer = min(length, HALF_BUFFER);
++
++ buf[0] = DIRECT_PREFIX;
++ buf[1] = DIRECT_CMD_EMIT;
++ memcpy(&buf[2], data, xfer);
++ ret = rp2040_gbdg_i2c_send(priv_data->client, buf, xfer + 2);
++ if (ret)
++ return ret;
++ length -= xfer;
++ data += xfer;
++ }
++
++ return 0;
++}
++
++static int rp2040_gbdg_transfer_cached(struct rp2040_gbdg *priv_data,
++ const u8 *data, unsigned int length)
++{
++ int ret;
++
++ /*
++ * Caching mechanism divides data into '8KiB - 9' (8183 byte)
++ * 'RP2040_GBDG_BLOCK_SIZE' blocks.
++ *
++ * If there's a large amount of data to send, instead, attempt to make use
++ * of a manifest.
++ */
++ if (length > (2 * RP2040_GBDG_BLOCK_SIZE)) {
++ if (!rp2040_gbdg_transfer_manifest(priv_data, data, length))
++ return 0;
++ }
++
++ while (length) {
++ unsigned int xfer = min(length, RP2040_GBDG_BLOCK_SIZE);
++
++ ret = rp2040_gbdg_transfer_block(priv_data, data, xfer);
++ if (ret)
++ return ret;
++ length -= xfer;
++ data += xfer;
++ }
++
++ return 0;
++}
++
++static int rp2040_gbdg_transfer_one(struct spi_controller *ctlr,
++ struct spi_device *spi,
++ struct spi_transfer *transfer)
++{
++ /* All transfers are performed in a synchronous manner. As such, return '0'
++ * on success or -ve on failure. (Returning +ve indicates async xfer)
++ */
++
++ struct rp2040_gbdg *priv_data = spi_controller_get_devdata(ctlr);
++
++ if (priv_data->bypass_cache) {
++ return rp2040_gbdg_transfer_bypass(priv_data, transfer->tx_buf,
++ transfer->len);
++ } else {
++ return rp2040_gbdg_transfer_cached(priv_data, transfer->tx_buf,
++ transfer->len);
++ }
++}
++
++static void rp2040_gbdg_set_cs(struct spi_device *spi, bool enable)
++{
++ static const char disable_cs[] = { DIRECT_PREFIX, DIRECT_CMD_CS, 0x00 };
++ static const char enable_cs[] = { DIRECT_PREFIX, DIRECT_CMD_CS, 0x10 };
++ struct rp2040_gbdg *p_data;
++
++ p_data = spi_controller_get_devdata(spi->controller);
++
++ /*
++ * 'enable' is inverted and instead describes the logic level of an
++ * active-low CS.
++ */
++ rp2040_gbdg_i2c_send(p_data->client, enable ? disable_cs : enable_cs,
++ 3);
++}
++
++static int rp2040_gbdg_gpio_request(struct gpio_chip *gc, unsigned int offset)
++{
++ struct rp2040_gbdg *priv_data = gpiochip_get_data(gc);
++ u32 pattern;
++ int ret;
++
++ if (offset >= NUM_GPIO)
++ return -EINVAL;
++
++ pattern = (1 << (offset + 8));
++ if (pattern & priv_data->gpio_requested)
++ return -EBUSY;
++
++ /* Resume if previously no gpio requested */
++ if (!priv_data->gpio_requested) {
++ ret = pm_runtime_resume_and_get(&priv_data->client->dev);
++ if (ret) {
++ dev_err(&priv_data->client->dev,
++ "%s(%u) unable to resume\n", __func__, offset);
++ return ret;
++ }
++ }
++
++ priv_data->gpio_requested |= pattern;
++
++ return 0;
++}
++
++static void rp2040_gbdg_gpio_free(struct gpio_chip *gc, unsigned int offset)
++{
++ struct rp2040_gbdg *priv_data = gpiochip_get_data(gc);
++ u32 pattern;
++ int ret;
++
++ if (offset >= NUM_GPIO || !priv_data->gpio_requested)
++ return;
++
++ pattern = (1 << (offset + 8));
++
++ priv_data->gpio_requested &= ~pattern;
++ rp2040_gbdg_gpio_dir_in(gc, offset);
++ rp2040_gbdg_gpio_set(gc, offset, 0);
++
++ if (!priv_data->gpio_requested) {
++ ret = pm_runtime_put_autosuspend(&priv_data->client->dev);
++ if (ret) {
++ dev_err(&priv_data->client->dev,
++ "%s(%u) unable to put_autosuspend\n", __func__,
++ offset);
++ }
++ }
++}
++
++static int rp2040_gbdg_gpio_get_direction(struct gpio_chip *gc,
++ unsigned int offset)
++{
++ struct rp2040_gbdg *priv_data = gpiochip_get_data(gc);
++
++ if (offset >= NUM_GPIO)
++ return -EINVAL;
++
++ return (priv_data->gpio_direction & (1 << (offset + 8))) ?
++ GPIO_LINE_DIRECTION_IN :
++ GPIO_LINE_DIRECTION_OUT;
++}
++
++static int rp2040_gbdg_gpio_dir_in(struct gpio_chip *gc, unsigned int offset)
++{
++ struct rp2040_gbdg *priv_data = gpiochip_get_data(gc);
++ struct i2c_client *client = priv_data->client;
++
++ if (offset >= NUM_GPIO)
++ return -EINVAL;
++
++ priv_data->gpio_direction |= (1 << (offset + 8));
++
++ return rp2040_gbdg_10byte_cmd(client, CMD_GPIO_OE,
++ ~priv_data->gpio_direction,
++ priv_data->gpio_direction);
++}
++
++static int rp2040_gbdg_gpio_dir_out(struct gpio_chip *gc, unsigned int offset,
++ int value)
++{
++ struct rp2040_gbdg *priv_data = gpiochip_get_data(gc);
++ struct i2c_client *client = priv_data->client;
++ u32 pattern;
++ int ret;
++
++ if (offset >= NUM_GPIO)
++ return -EINVAL;
++
++ pattern = (1 << (offset + 8));
++
++ ret = rp2040_gbdg_10byte_cmd(client, CMD_GPIO_ST_CL,
++ value ? pattern : 0, !value ? pattern : 0);
++ if (ret) {
++ dev_err(&client->dev, "%s(%u, %d) could not ST_CL\n", __func__,
++ offset, value);
++ return ret;
++ }
++
++ priv_data->gpio_direction &= ~pattern;
++ ret = rp2040_gbdg_10byte_cmd(client, CMD_GPIO_OE,
++ ~priv_data->gpio_direction,
++ priv_data->gpio_direction);
++
++ return ret;
++}
++
++static int rp2040_gbdg_gpio_get(struct gpio_chip *gc, unsigned int offset)
++{
++ struct rp2040_gbdg *priv_data = gpiochip_get_data(gc);
++ struct i2c_client *client = priv_data->client;
++ struct rp2040_gbdg_device_info info;
++ int ret;
++
++ if (offset >= NUM_GPIO)
++ return -EINVAL;
++
++ ret = rp2040_gbdg_get_device_info(client, &info);
++ if (ret)
++ return ret;
++
++ return info.status & (1 << (offset + 8)) ? 1 : 0;
++}
++
++static void rp2040_gbdg_gpio_set(struct gpio_chip *gc, unsigned int offset,
++ int value)
++{
++ struct rp2040_gbdg *priv_data = gpiochip_get_data(gc);
++ struct i2c_client *client = priv_data->client;
++ u32 pattern;
++
++ if (offset >= NUM_GPIO)
++ return;
++
++ pattern = (1 << (offset + 8));
++ rp2040_gbdg_10byte_cmd(client, CMD_GPIO_ST_CL, value ? pattern : 0,
++ !value ? pattern : 0);
++}
++
++static int rp2040_gbdg_get_regulator(struct device *dev,
++ struct rp2040_gbdg *rp2040_gbdg)
++{
++ struct regulator *reg = devm_regulator_get(dev, "power");
++
++ if (IS_ERR(reg))
++ return PTR_ERR(reg);
++
++ rp2040_gbdg->regulator = reg;
++
++ return 0;
++}
++
++static void rp2040_gbdg_parse_dt(struct rp2040_gbdg *rp2040_gbdg)
++{
++ struct i2c_client *client = rp2040_gbdg->client;
++ struct of_phandle_args of_args[2] = { 0 };
++ struct device *dev = &client->dev;
++ struct device_node *dn;
++
++ rp2040_gbdg->bypass_cache =
++ of_property_read_bool(client->dev.of_node, "bypass-cache");
++
++ /* Optionally configure fast_xfer if RP1 is being used */
++ if (of_parse_phandle_with_args(client->dev.of_node, "fast_xfer-gpios",
++ "#gpio-cells", 0, &of_args[0]) ||
++ of_parse_phandle_with_args(client->dev.of_node, "fast_xfer-gpios",
++ "#gpio-cells", 1, &of_args[1])) {
++ dev_info(dev, "Could not parse fast_xfer-gpios phandles\n");
++ goto node_put;
++ }
++
++ if (of_args[0].np != of_args[1].np) {
++ dev_info(
++ dev,
++ "fast_xfer-gpios are not provided by the same controller\n");
++ goto node_put;
++ }
++ dn = of_args[0].np;
++ if (!of_device_is_compatible(dn, "raspberrypi,rp1-gpio")) {
++ dev_info(dev, "fast_xfer-gpios controller is not an rp1\n");
++ goto node_put;
++ }
++ if (of_args[0].args_count != 2 || of_args[1].args_count != 2) {
++ dev_info(dev, "of_args count is %d\n", of_args[0].args_count);
++ goto node_put;
++ }
++
++ if (of_property_read_u32_index(
++ client->dev.of_node, "fast_xfer_recv_gpio_base", 0,
++ &rp2040_gbdg->fast_xfer_recv_gpio_base)) {
++ dev_info(dev, "Could not read fast_xfer_recv_gpio_base\n");
++ goto node_put;
++ }
++
++ rp2040_gbdg->fast_xfer_gpios =
++ devm_gpiod_get_array_optional(dev, "fast_xfer", GPIOD_ASIS);
++ if (!rp2040_gbdg->fast_xfer_gpios) {
++ dev_info(dev, "Could not acquire fast_xfer-gpios\n");
++ goto node_put;
++ }
++
++ rp2040_gbdg->fast_xfer_data_index = of_args[0].args[0];
++ rp2040_gbdg->fast_xfer_clock_index = of_args[1].args[0];
++ rp2040_gbdg->fast_xfer_requires_i2c_lock = of_property_read_bool(
++ client->dev.of_node, "fast_xfer_requires_i2c_lock");
++
++ rp2040_gbdg->gpio_base = of_iomap(dn, 0);
++ if (IS_ERR_OR_NULL(rp2040_gbdg->gpio_base)) {
++ dev_info(&client->dev, "%s() unable to map gpio_base\n",
++ __func__);
++ rp2040_gbdg->gpio_base = NULL;
++ devm_gpiod_put_array(dev, rp2040_gbdg->fast_xfer_gpios);
++ rp2040_gbdg->fast_xfer_gpios = NULL;
++ goto node_put;
++ }
++
++ rp2040_gbdg->rio_base = of_iomap(dn, 1);
++ if (IS_ERR_OR_NULL(rp2040_gbdg->rio_base)) {
++ dev_info(&client->dev, "%s() unable to map rio_base\n",
++ __func__);
++ rp2040_gbdg->rio_base = NULL;
++ iounmap(rp2040_gbdg->gpio_base);
++ rp2040_gbdg->gpio_base = NULL;
++ devm_gpiod_put_array(dev, rp2040_gbdg->fast_xfer_gpios);
++ rp2040_gbdg->fast_xfer_gpios = NULL;
++ goto node_put;
++ }
++
++node_put:
++ if (of_args[0].np)
++ of_node_put(of_args[0].np);
++ if (of_args[1].np)
++ of_node_put(of_args[1].np);
++}
++
++static int rp2040_gbdg_power_off(struct rp2040_gbdg *rp2040_gbdg)
++{
++ struct device *dev = &rp2040_gbdg->client->dev;
++ int ret;
++
++ ret = regulator_disable(rp2040_gbdg->regulator);
++ if (ret) {
++ dev_err(dev, "%s: Could not disable regulator\n", __func__);
++ return ret;
++ }
++
++ return 0;
++}
++
++static int rp2040_gbdg_power_on(struct rp2040_gbdg *rp2040_gbdg)
++{
++ struct device *dev = &rp2040_gbdg->client->dev;
++ int ret;
++
++ ret = regulator_enable(rp2040_gbdg->regulator);
++ if (ret) {
++ dev_err(dev, "%s: Could not enable regulator\n", __func__);
++ return ret;
++ }
++
++ return 0;
++}
++
++static int rp2040_gbdg_probe(struct i2c_client *client)
++{
++ struct rp2040_gbdg_device_info info;
++ struct spi_controller *controller;
++ struct device *dev = &client->dev;
++ struct rp2040_gbdg *rp2040_gbdg;
++ struct device_node *np;
++ int ret;
++
++ np = dev->of_node;
++
++ controller = devm_spi_alloc_master(dev, sizeof(struct rp2040_gbdg));
++ if (!controller)
++ return dev_err_probe(dev, ENOMEM,
++ "could not alloc spi controller\n");
++
++ rp2040_gbdg = spi_controller_get_devdata(controller);
++ i2c_set_clientdata(client, rp2040_gbdg);
++ rp2040_gbdg->controller = controller;
++ rp2040_gbdg->client = client;
++
++ ret = rp2040_gbdg_get_regulator(dev, rp2040_gbdg);
++ if (ret < 0)
++ return dev_err_probe(dev, ret, "Cannot get regulator\n");
++
++ ret = rp2040_gbdg_power_on(rp2040_gbdg);
++ if (ret)
++ return dev_err_probe(dev, ret, "Could not power on device\n");
++
++ pm_runtime_set_active(dev);
++ pm_runtime_get_noresume(dev);
++ pm_runtime_enable(dev);
++ pm_runtime_set_autosuspend_delay(dev, 1000);
++ pm_runtime_use_autosuspend(dev);
++
++ ret = rp2040_gbdg_get_device_info(client, &info);
++ if (ret) {
++ dev_err(dev, "Could not get device info\n");
++ goto err_pm;
++ }
++
++ dev_info(dev, "%s() found dev ID: %llx, fw ver. %u\n", __func__,
++ info.id, info.version);
++
++ rp2040_gbdg->shash = crypto_alloc_shash("md5", 0, 0);
++ if (IS_ERR(rp2040_gbdg->shash)) {
++ ret = PTR_ERR(rp2040_gbdg->shash);
++ dev_err(dev, "Could not allocate shash\n");
++ goto err_pm;
++ }
++
++ if (crypto_shash_digestsize(rp2040_gbdg->shash) != MD5_DIGEST_SIZE) {
++ ret = -EINVAL;
++ dev_err(dev, "error: Unexpected hash digest size\n");
++ goto err_shash;
++ }
++
++ rp2040_gbdg->shash_desc =
++ devm_kmalloc(dev,
++ sizeof(struct shash_desc) +
++ crypto_shash_descsize(rp2040_gbdg->shash),
++ 0);
++
++ if (!rp2040_gbdg->shash_desc) {
++ ret = -ENOMEM;
++ dev_err(dev,
++ "error: Could not allocate memory for shash_desc\n");
++ goto err_shash;
++ }
++ rp2040_gbdg->shash_desc->tfm = rp2040_gbdg->shash;
++
++ controller->bus_num = -1;
++ controller->num_chipselect = 1;
++ controller->mode_bits = SPI_CPOL | SPI_CPHA;
++ controller->bits_per_word_mask = SPI_BPW_MASK(8);
++ controller->min_speed_hz = 35000000;
++ controller->max_speed_hz = 35000000;
++ controller->max_transfer_size = rp2040_gbdg_max_transfer_size;
++ controller->max_message_size = rp2040_gbdg_max_transfer_size;
++ controller->transfer_one = rp2040_gbdg_transfer_one;
++ controller->set_cs = rp2040_gbdg_set_cs;
++
++ controller->dev.of_node = np;
++ controller->auto_runtime_pm = true;
++
++ ret = devm_spi_register_controller(dev, controller);
++ if (ret) {
++ dev_err(dev, "error: Could not register SPI controller\n");
++ goto err_shash;
++ }
++
++ memset(&rp2040_gbdg->gc, 0, sizeof(struct gpio_chip));
++ rp2040_gbdg->gc.parent = dev;
++ rp2040_gbdg->gc.label = MODULE_NAME;
++ rp2040_gbdg->gc.owner = THIS_MODULE;
++ rp2040_gbdg->gc.base = -1;
++ rp2040_gbdg->gc.ngpio = NUM_GPIO;
++
++ rp2040_gbdg->gc.request = rp2040_gbdg_gpio_request;
++ rp2040_gbdg->gc.free = rp2040_gbdg_gpio_free;
++ rp2040_gbdg->gc.get_direction = rp2040_gbdg_gpio_get_direction;
++ rp2040_gbdg->gc.direction_input = rp2040_gbdg_gpio_dir_in;
++ rp2040_gbdg->gc.direction_output = rp2040_gbdg_gpio_dir_out;
++ rp2040_gbdg->gc.get = rp2040_gbdg_gpio_get;
++ rp2040_gbdg->gc.set = rp2040_gbdg_gpio_set;
++ rp2040_gbdg->gc.can_sleep = true;
++
++ rp2040_gbdg->gpio_requested = 0;
++
++ /* Coming out of reset, all GPIOs are inputs */
++ rp2040_gbdg->gpio_direction = ~0;
++
++ ret = devm_gpiochip_add_data(dev, &rp2040_gbdg->gc, rp2040_gbdg);
++ if (ret) {
++ dev_err(dev, "error: Could not add data to gpiochip\n");
++ goto err_shash;
++ }
++
++ rp2040_gbdg_parse_dt(rp2040_gbdg);
++
++ pm_runtime_mark_last_busy(dev);
++ pm_runtime_put_autosuspend(dev);
++
++ return 0;
++
++err_shash:
++ crypto_free_shash(rp2040_gbdg->shash);
++err_pm:
++ pm_runtime_disable(dev);
++ pm_runtime_put_noidle(dev);
++ rp2040_gbdg_power_off(rp2040_gbdg);
++
++ return ret;
++}
++
++static void rp2040_gbdg_remove(struct i2c_client *client)
++{
++ struct rp2040_gbdg *priv_data = i2c_get_clientdata(client);
++
++ crypto_free_shash(priv_data->shash);
++
++ if (priv_data->gpio_base) {
++ iounmap(priv_data->gpio_base);
++ priv_data->gpio_base = NULL;
++ }
++ if (priv_data->rio_base) {
++ iounmap(priv_data->rio_base);
++ priv_data->rio_base = NULL;
++ }
++
++ pm_runtime_disable(&client->dev);
++ if (!pm_runtime_status_suspended(&client->dev))
++ rp2040_gbdg_power_off(priv_data);
++ pm_runtime_set_suspended(&client->dev);
++}
++
++static const struct i2c_device_id rp2040_gbdg_id[] = {
++ { "rp2040-gpio-bridge", 0 },
++ {},
++};
++MODULE_DEVICE_TABLE(i2c, rp2040_gbdg_id);
++
++static const struct of_device_id rp2040_gbdg_of_match[] = {
++ { .compatible = "raspberrypi,rp2040-gpio-bridge" },
++ {},
++};
++MODULE_DEVICE_TABLE(of, rp2040_gbdg_of_match);
++
++static int rp2040_gbdg_runtime_suspend(struct device *dev)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++
++ return rp2040_gbdg_power_off(i2c_get_clientdata(client));
++}
++
++static int rp2040_gbdg_runtime_resume(struct device *dev)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++
++ return rp2040_gbdg_power_on(i2c_get_clientdata(client));
++}
++
++static const struct dev_pm_ops rp2040_gbdg_pm_ops = { SET_RUNTIME_PM_OPS(
++ rp2040_gbdg_runtime_suspend, rp2040_gbdg_runtime_resume, NULL) };
++
++static struct i2c_driver rp2040_gbdg_driver = {
++ .driver = {
++ .name = MODULE_NAME,
++ .of_match_table = of_match_ptr(rp2040_gbdg_of_match),
++ .pm = &rp2040_gbdg_pm_ops,
++ },
++ .probe = rp2040_gbdg_probe,
++ .remove = rp2040_gbdg_remove,
++ .id_table = rp2040_gbdg_id,
++};
++
++module_i2c_driver(rp2040_gbdg_driver);
++
++MODULE_AUTHOR("Richard Oliver <richard.oliver@raspberrypi.com>");
++MODULE_DESCRIPTION("Raspberry Pi RP2040 GPIO Bridge");
++MODULE_LICENSE("GPL");
--- /dev/null
+From 475cddaba6b02584157e1c128a5a6858770a3d06 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Wed, 10 Jul 2024 14:47:17 +0100
+Subject: [PATCH 1166/1215] dmaengine: dw-axi-dmac: Honour snps,block-size
+
+The snps,block-size DT property declares the maximum block size for each
+channel of the dw-axi-dmac. However, the driver ignores these when
+setting max_seg_size and uses MAX_BLOCK_SIZE (4096) instead.
+
+To take advantage of the efficiencies of larger blocks, calculate the
+minimum block size across all channels and use that instead.
+
+See: https://github.com/raspberrypi/linux/issues/6256
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 15 ++++++++++++++-
+ 1 file changed, 14 insertions(+), 1 deletion(-)
+
+--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
++++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
+@@ -1470,6 +1470,7 @@ static int dw_probe(struct platform_devi
+ struct dw_axi_dma *dw;
+ struct dw_axi_dma_hcfg *hdata;
+ struct reset_control *resets;
++ unsigned int max_seg_size;
+ unsigned int flags;
+ u32 i;
+ int ret;
+@@ -1585,9 +1586,21 @@ static int dw_probe(struct platform_devi
+ * Synopsis DesignWare AxiDMA datasheet mentioned Maximum
+ * supported blocks is 1024. Device register width is 4 bytes.
+ * Therefore, set constraint to 1024 * 4.
++ * However, if all channels specify a greater value, use that instead.
+ */
++
+ dw->dma.dev->dma_parms = &dw->dma_parms;
+- dma_set_max_seg_size(&pdev->dev, MAX_BLOCK_SIZE);
++ max_seg_size = UINT_MAX;
++ for (i = 0; i < dw->hdata->nr_channels; i++) {
++ unsigned int block_size = chip->dw->hdata->block_size[i];
++
++ if (!block_size)
++ block_size = MAX_BLOCK_SIZE;
++ max_seg_size = min(block_size, max_seg_size);
++ }
++
++ dma_set_max_seg_size(&pdev->dev, max_seg_size);
++
+ platform_set_drvdata(pdev, chip);
+
+ pm_runtime_enable(chip->dev);
--- /dev/null
+From e6c1e862b2b8150a419f4208e5bd7749662b16a1 Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <jonathan@raspberrypi.com>
+Date: Thu, 20 Jun 2024 14:31:20 +0100
+Subject: [PATCH 1167/1215] mmc: restrict posted write counts for SD cards in
+ CQ mode
+
+Command Queueing requires Write Cache and Power off Notification support
+from the card - but using the write cache forms a contract with the host
+whereby the card expects to be told about impending power-down.
+
+The implication is that (for performance) the card can do unsafe things
+with pending write data - including reordering what gets committed to
+nonvolatile storage at what time.
+
+Exposed SD slots and platforms powered by hotpluggable means (i.e.
+Raspberry Pis) can't guarantee that surprise removal won't happen.
+
+To limit the scope for cards to invent new ways to trash filesystems,
+limit pending writes to 1 (equivalent to the non-CQ behaviour).
+
+Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
+---
+ drivers/mmc/core/block.c | 11 +++++++++--
+ drivers/mmc/core/mmc.c | 1 +
+ drivers/mmc/core/queue.c | 9 +++++++++
+ drivers/mmc/core/queue.h | 1 +
+ drivers/mmc/core/sd.c | 8 ++++++++
+ include/linux/mmc/card.h | 2 ++
+ 6 files changed, 30 insertions(+), 2 deletions(-)
+
+--- a/drivers/mmc/core/block.c
++++ b/drivers/mmc/core/block.c
+@@ -1555,6 +1555,8 @@ static void mmc_blk_cqe_complete_rq(stru
+
+ spin_lock_irqsave(&mq->lock, flags);
+
++ if (req_op(req) == REQ_OP_WRITE)
++ mq->pending_writes--;
+ mq->in_flight[issue_type] -= 1;
+
+ put_card = (mmc_tot_in_flight(mq) == 0);
+@@ -2071,6 +2073,8 @@ static void mmc_blk_mq_complete_rq(struc
+ struct mmc_queue_req *mqrq = req_to_mmc_queue_req(req);
+ unsigned int nr_bytes = mqrq->brq.data.bytes_xfered;
+
++ if (req_op(req) == REQ_OP_WRITE)
++ mq->pending_writes--;
+ if (nr_bytes) {
+ if (blk_update_request(req, BLK_STS_OK, nr_bytes))
+ blk_mq_requeue_request(req, true);
+@@ -2165,13 +2169,16 @@ static void mmc_blk_mq_poll_completion(s
+ mmc_blk_urgent_bkops(mq, mqrq);
+ }
+
+-static void mmc_blk_mq_dec_in_flight(struct mmc_queue *mq, enum mmc_issue_type issue_type)
++static void mmc_blk_mq_dec_in_flight(struct mmc_queue *mq, enum mmc_issue_type issue_type,
++ struct request *req)
+ {
+ unsigned long flags;
+ bool put_card;
+
+ spin_lock_irqsave(&mq->lock, flags);
+
++ if (req_op(req) == REQ_OP_WRITE)
++ mq->pending_writes--;
+ mq->in_flight[issue_type] -= 1;
+
+ put_card = (mmc_tot_in_flight(mq) == 0);
+@@ -2205,7 +2212,7 @@ static void mmc_blk_mq_post_req(struct m
+ blk_mq_complete_request(req);
+ }
+
+- mmc_blk_mq_dec_in_flight(mq, issue_type);
++ mmc_blk_mq_dec_in_flight(mq, issue_type, req);
+ }
+
+ void mmc_blk_mq_recovery(struct mmc_queue *mq)
+--- a/drivers/mmc/core/mmc.c
++++ b/drivers/mmc/core/mmc.c
+@@ -1922,6 +1922,7 @@ static int mmc_init_card(struct mmc_host
+ pr_info("%s: Host Software Queue enabled\n",
+ mmc_hostname(host));
+ }
++ card->max_posted_writes = card->ext_csd.cmdq_depth;
+ }
+ }
+
+--- a/drivers/mmc/core/queue.c
++++ b/drivers/mmc/core/queue.c
+@@ -268,6 +268,11 @@ static blk_status_t mmc_mq_queue_rq(stru
+ spin_unlock_irq(&mq->lock);
+ return BLK_STS_RESOURCE;
+ }
++ if (host->cqe_enabled && req_op(req) == REQ_OP_WRITE &&
++ mq->pending_writes >= card->max_posted_writes) {
++ spin_unlock_irq(&mq->lock);
++ return BLK_STS_RESOURCE;
++ }
+ break;
+ default:
+ /*
+@@ -284,6 +289,8 @@ static blk_status_t mmc_mq_queue_rq(stru
+ /* Parallel dispatch of requests is not supported at the moment */
+ mq->busy = true;
+
++ if (req_op(req) == REQ_OP_WRITE)
++ mq->pending_writes++;
+ mq->in_flight[issue_type] += 1;
+ get_card = (mmc_tot_in_flight(mq) == 1);
+ cqe_retune_ok = (mmc_cqe_qcnt(mq) == 1);
+@@ -323,6 +330,8 @@ static blk_status_t mmc_mq_queue_rq(stru
+ bool put_card = false;
+
+ spin_lock_irq(&mq->lock);
++ if (req_op(req) == REQ_OP_WRITE)
++ mq->pending_writes--;
+ mq->in_flight[issue_type] -= 1;
+ if (mmc_tot_in_flight(mq) == 0)
+ put_card = true;
+--- a/drivers/mmc/core/queue.h
++++ b/drivers/mmc/core/queue.h
+@@ -79,6 +79,7 @@ struct mmc_queue {
+ struct request_queue *queue;
+ spinlock_t lock;
+ int in_flight[MMC_ISSUE_MAX];
++ int pending_writes;
+ unsigned int cqe_busy;
+ #define MMC_CQE_DCMD_BUSY BIT(0)
+ bool busy;
+--- a/drivers/mmc/core/sd.c
++++ b/drivers/mmc/core/sd.c
+@@ -1104,6 +1104,14 @@ static int sd_parse_ext_reg_perf(struct
+ pr_debug("%s: Command Queue supported depth %u\n",
+ mmc_hostname(card->host),
+ card->ext_csd.cmdq_depth);
++ /*
++ * If CQ is enabled, there is a contract between host and card such that VDD will
++ * be maintained and removed only if a power off notification is provided.
++ * An SD card in an accessible slot means surprise removal is a possibility.
++ * As a middle ground, limit max posted writes to 1 unless the card is "hardwired".
++ */
++ if (mmc_card_is_removable(card->host))
++ card->max_posted_writes = 1;
+ }
+
+ card->ext_perf.fno = fno;
+--- a/include/linux/mmc/card.h
++++ b/include/linux/mmc/card.h
+@@ -343,6 +343,8 @@ struct mmc_card {
+ unsigned int nr_parts;
+
+ struct workqueue_struct *complete_wq; /* Private workqueue */
++
++ unsigned int max_posted_writes; /* command queue posted write limit */
+ };
+
+ static inline bool mmc_large_sector(struct mmc_card *card)
--- /dev/null
+From 19682239a60c1b53cad8319eaeb58e71d4213cee Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <jonathan@raspberrypi.com>
+Date: Mon, 15 Jul 2024 13:38:38 +0100
+Subject: [PATCH 1168/1215] fixup: mmc: restrict posted write counts for SD
+ cards in CQ mode
+
+Leaving card->max_posted_writes unintialised was a bad thing to do.
+
+Also, cqe_enable is 1 if hsq is enabled as hsq substitutes the cqhci
+implementation with its own.
+
+Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
+---
+ drivers/mmc/core/mmc.c | 1 +
+ drivers/mmc/core/queue.c | 2 +-
+ drivers/mmc/core/sd.c | 14 ++++++++------
+ 3 files changed, 10 insertions(+), 7 deletions(-)
+
+--- a/drivers/mmc/core/mmc.c
++++ b/drivers/mmc/core/mmc.c
+@@ -1663,6 +1663,7 @@ static int mmc_init_card(struct mmc_host
+ card->ocr = ocr;
+ card->type = MMC_TYPE_MMC;
+ card->rca = 1;
++ card->max_posted_writes = 1;
+ memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
+ }
+
+--- a/drivers/mmc/core/queue.c
++++ b/drivers/mmc/core/queue.c
+@@ -268,7 +268,7 @@ static blk_status_t mmc_mq_queue_rq(stru
+ spin_unlock_irq(&mq->lock);
+ return BLK_STS_RESOURCE;
+ }
+- if (host->cqe_enabled && req_op(req) == REQ_OP_WRITE &&
++ if (!host->hsq_enabled && host->cqe_enabled && req_op(req) == REQ_OP_WRITE &&
+ mq->pending_writes >= card->max_posted_writes) {
+ spin_unlock_irq(&mq->lock);
+ return BLK_STS_RESOURCE;
+--- a/drivers/mmc/core/sd.c
++++ b/drivers/mmc/core/sd.c
+@@ -1105,13 +1105,14 @@ static int sd_parse_ext_reg_perf(struct
+ mmc_hostname(card->host),
+ card->ext_csd.cmdq_depth);
+ /*
+- * If CQ is enabled, there is a contract between host and card such that VDD will
+- * be maintained and removed only if a power off notification is provided.
+- * An SD card in an accessible slot means surprise removal is a possibility.
+- * As a middle ground, limit max posted writes to 1 unless the card is "hardwired".
++ * If CQ is enabled, there is a contract between host and card such that
++ * VDD will be maintained and removed only if a power off notification
++ * is provided. An SD card in an accessible slot means surprise removal
++ * is a possibility. As a middle ground, keep the default maximum of 1
++ * posted write unless the card is "hardwired".
+ */
+- if (mmc_card_is_removable(card->host))
+- card->max_posted_writes = 1;
++ if (!mmc_card_is_removable(card->host))
++ card->max_posted_writes = card->ext_csd.cmdq_depth;
+ }
+
+ card->ext_perf.fno = fno;
+@@ -1383,6 +1384,7 @@ retry:
+
+ card->ocr = ocr;
+ card->type = MMC_TYPE_SD;
++ card->max_posted_writes = 1;
+ memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
+ }
+
--- /dev/null
+From 1abc413af44652d6a76d5b5c2afe90788595008e Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <jonathan@raspberrypi.com>
+Date: Mon, 15 Jul 2024 13:57:01 +0100
+Subject: [PATCH 1169/1215] mmc: brcmstb: don't squash card-busy detection on
+ bcm2712
+
+Commit 485d9421719b ("mmc: sdhci-brcmstb: check R1_STATUS for
+erase/trim/discard") introduced a new flag and defaulted to disabling
+card busy detection across all platforms with this controller.
+
+This is required for IO voltage switching, as the card drives CMD low
+while the switch is in progress.
+
+Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
+---
+ drivers/mmc/host/sdhci-brcmstb.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/mmc/host/sdhci-brcmstb.c
++++ b/drivers/mmc/host/sdhci-brcmstb.c
+@@ -430,6 +430,7 @@ static const struct brcmstb_match_priv m
+ };
+
+ static const struct brcmstb_match_priv match_priv_2712 = {
++ .flags = BRCMSTB_MATCH_FLAGS_USE_CARD_BUSY,
+ .hs400es = sdhci_brcmstb_hs400es,
+ .cfginit = sdhci_brcmstb_cfginit_2712,
+ .ops = &sdhci_brcmstb_ops_2712,
--- /dev/null
+From 31eb43be8cad2818b4458cf1fd2dfa60031ee5f4 Mon Sep 17 00:00:00 2001
+From: Matthew <sirfragles@gmail.com>
+Date: Tue, 16 Jul 2024 11:20:54 +0200
+Subject: [PATCH 1172/1215] Revert "Update DAC8x to support 384khz (#6187)"
+
+This reverts commit dd7a15472b18d4bce738bb9213443c140473833b.
+---
+ sound/soc/bcm/rpi-simple-soundcard.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/sound/soc/bcm/rpi-simple-soundcard.c
++++ b/sound/soc/bcm/rpi-simple-soundcard.c
+@@ -324,10 +324,10 @@ static int hifiberry_dac8x_init(struct s
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+
+ /* override the defaults to reflect 4 x PCM5102A on the card
+- * and limit the sample rate to 384ksps
++ * and limit the sample rate to 192ksps
+ */
+ codec_dai->driver->playback.channels_max = 8;
+- codec_dai->driver->playback.rates = SNDRV_PCM_RATE_8000_384000;
++ codec_dai->driver->playback.rates = SNDRV_PCM_RATE_8000_192000;
+
+ return 0;
+ }
--- /dev/null
+From 3224569a3e279bbeae4e975dfa1a890f3f595239 Mon Sep 17 00:00:00 2001
+From: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
+Date: Fri, 10 May 2024 15:18:44 +0100
+Subject: [PATCH 1176/1215] dt-bindings: clk: rp1: Add clocks representing MIPI
+ DSI byteclock
+
+Define two new RP1 clocks, representing the MIPI DSI byteclock
+sources for the dividers used to generate MIPI[01] DPI pixel clocks.
+(Previously they were represented by "fake" fixed clocks sources).
+
+Signed-off-by: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
+---
+ include/dt-bindings/clock/rp1.h | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/include/dt-bindings/clock/rp1.h
++++ b/include/dt-bindings/clock/rp1.h
+@@ -54,3 +54,7 @@
+ /* Extra PLL output channels - RP1B0 only */
+ #define RP1_PLL_VIDEO_PRI_PH 43
+ #define RP1_PLL_AUDIO_TERN 44
++
++/* MIPI clocks managed by the DSI driver */
++#define RP1_CLK_MIPI0_DSI_BYTECLOCK 45
++#define RP1_CLK_MIPI1_DSI_BYTECLOCK 46
--- /dev/null
+From 126560c909f38f00c08dd5f35f50c981d5e25e1f Mon Sep 17 00:00:00 2001
+From: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
+Date: Fri, 10 May 2024 15:30:44 +0100
+Subject: [PATCH 1177/1215] clk: clk-rp1: Add "varsrc" clocks to represent MIPI
+ byte clocks
+
+Add a new class of clocks to RP1 to represent clock sources whose
+frequency changes at run-time as a side-effect of some other driver.
+Specifically this is for the two MIPI DSI byte-clock sources.
+
+Signed-off-by: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
+---
+ drivers/clk/clk-rp1.c | 73 +++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 73 insertions(+)
+
+--- a/drivers/clk/clk-rp1.c
++++ b/drivers/clk/clk-rp1.c
+@@ -394,6 +394,11 @@ struct rp1_clock {
+ unsigned long cached_rate;
+ };
+
++struct rp1_varsrc {
++ struct clk_hw hw;
++ struct rp1_clockman *clockman;
++ unsigned long rate;
++};
+
+ struct rp1_clk_change {
+ struct clk_hw *hw;
+@@ -1414,6 +1419,34 @@ static void rp1_clk_debug_init(struct cl
+ rp1_debugfs_regset(clockman, 0, regs, i, dentry);
+ }
+
++static int rp1_varsrc_set_rate(struct clk_hw *hw,
++ unsigned long rate, unsigned long parent_rate)
++{
++ struct rp1_varsrc *varsrc = container_of(hw, struct rp1_varsrc, hw);
++
++ /*
++ * "varsrc" exists purely to let clock dividers know the frequency
++ * of an externally-managed clock source (such as MIPI DSI byte-clock)
++ * which may change at run-time as a side-effect of some other driver.
++ */
++ varsrc->rate = rate;
++ return 0;
++}
++
++static unsigned long rp1_varsrc_recalc_rate(struct clk_hw *hw,
++ unsigned long parent_rate)
++{
++ struct rp1_varsrc *varsrc = container_of(hw, struct rp1_varsrc, hw);
++
++ return varsrc->rate;
++}
++
++static long rp1_varsrc_round_rate(struct clk_hw *hw, unsigned long rate,
++ unsigned long *parent_rate)
++{
++ return rate;
++}
++
+ static const struct clk_ops rp1_pll_core_ops = {
+ .is_prepared = rp1_pll_core_is_on,
+ .prepare = rp1_pll_core_on,
+@@ -1464,6 +1497,12 @@ static const struct clk_ops rp1_clk_ops
+ .debug_init = rp1_clk_debug_init,
+ };
+
++static const struct clk_ops rp1_varsrc_ops = {
++ .set_rate = rp1_varsrc_set_rate,
++ .recalc_rate = rp1_varsrc_recalc_rate,
++ .round_rate = rp1_varsrc_round_rate,
++};
++
+ static bool rp1_clk_is_claimed(const char *name);
+
+ static struct clk_hw *rp1_register_pll_core(struct rp1_clockman *clockman,
+@@ -1647,6 +1686,35 @@ static struct clk_hw *rp1_register_clock
+ return &clock->hw;
+ }
+
++static struct clk_hw *rp1_register_varsrc(struct rp1_clockman *clockman,
++ const void *data)
++{
++ const char *name = *(char const * const *)data;
++ struct rp1_varsrc *clock;
++ struct clk_init_data init;
++ int ret;
++
++ memset(&init, 0, sizeof(init));
++ init.parent_names = &ref_clock;
++ init.num_parents = 1;
++ init.name = name;
++ init.flags = CLK_IGNORE_UNUSED;
++ init.ops = &rp1_varsrc_ops;
++
++ clock = devm_kzalloc(clockman->dev, sizeof(*clock), GFP_KERNEL);
++ if (!clock)
++ return NULL;
++
++ clock->clockman = clockman;
++ clock->hw.init = &init;
++
++ ret = devm_clk_hw_register(clockman->dev, &clock->hw);
++ if (ret)
++ return ERR_PTR(ret);
++
++ return &clock->hw;
++}
++
+ struct rp1_clk_desc {
+ struct clk_hw *(*clk_register)(struct rp1_clockman *clockman,
+ const void *data);
+@@ -1676,6 +1744,8 @@ struct rp1_clk_desc {
+ &(struct rp1_clock_data) \
+ {__VA_ARGS__})
+
++#define REGISTER_VARSRC(n) _REGISTER(&rp1_register_varsrc, &(const char *){n})
++
+ static const struct rp1_clk_desc clk_desc_array[] = {
+ [RP1_PLL_SYS_CORE] = REGISTER_PLL_CORE(
+ .name = "pll_sys_core",
+@@ -2318,6 +2388,9 @@ static const struct rp1_clk_desc clk_des
+ .max_freq = 200 * MHz,
+ .fc0_src = FC_NUM(3, 6),
+ ),
++
++ [RP1_CLK_MIPI0_DSI_BYTECLOCK] = REGISTER_VARSRC("clksrc_mipi0_dsi_byteclk"),
++ [RP1_CLK_MIPI1_DSI_BYTECLOCK] = REGISTER_VARSRC("clksrc_mipi1_dsi_byteclk"),
+ };
+
+ static bool rp1_clk_claimed[ARRAY_SIZE(clk_desc_array)];
--- /dev/null
+From 9a108c82b6f6526e0aa8a19befa1ed3f31f8fe52 Mon Sep 17 00:00:00 2001
+From: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
+Date: Fri, 10 May 2024 15:42:29 +0100
+Subject: [PATCH 1178/1215] dts: rp1: DSI drivers to use newly defined MIPI
+ byte source clocks.
+
+Remove the "dummy" 72MHz fixed clock sources and associate DSI driver
+with the new "variable" clock sources now defined in RP1 clocks.
+
+Also add PLLSYS clock to DSI, which it will need as an alternative
+clock source in those cases where DPI pixclock > DSI byteclock.
+
+Signed-off-by: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
+---
+ arch/arm/boot/dts/broadcom/rp1.dtsi | 50 +++++++++--------------------
+ 1 file changed, 15 insertions(+), 35 deletions(-)
+
+--- a/arch/arm/boot/dts/broadcom/rp1.dtsi
++++ b/arch/arm/boot/dts/broadcom/rp1.dtsi
+@@ -1109,16 +1109,15 @@
+
+ interrupts = <RP1_INT_MIPI0 IRQ_TYPE_LEVEL_HIGH>;
+
+- clocks = <&rp1_clocks RP1_CLK_MIPI0_CFG>, // required, config bus clock
+- <&rp1_clocks RP1_CLK_MIPI0_DPI>, // required, pixel clock
+- <&clksrc_mipi0_dsi_byteclk>, // internal, parent for divide
+- <&clk_xosc>; // hardwired to DSI "refclk"
+- clock-names = "cfgclk", "dpiclk", "byteclk", "refclk";
++ clocks = <&rp1_clocks RP1_CLK_MIPI0_CFG>,
++ <&rp1_clocks RP1_CLK_MIPI0_DPI>,
++ <&rp1_clocks RP1_CLK_MIPI0_DSI_BYTECLOCK>,
++ <&clk_xosc>, // hardwired to DSI "refclk"
++ <&rp1_clocks RP1_PLL_SYS>; // alternate parent for divide
++ clock-names = "cfgclk", "dpiclk", "byteclk", "refclk", "pllsys";
+
+- assigned-clocks = <&rp1_clocks RP1_CLK_MIPI0_CFG>,
+- <&rp1_clocks RP1_CLK_MIPI0_DPI>;
++ assigned-clocks = <&rp1_clocks RP1_CLK_MIPI0_CFG>;
+ assigned-clock-rates = <25000000>;
+- assigned-clock-parents = <0>, <&clksrc_mipi0_dsi_byteclk>;
+ };
+
+ rp1_dsi1: dsi@128000 {
+@@ -1130,16 +1129,15 @@
+
+ interrupts = <RP1_INT_MIPI1 IRQ_TYPE_LEVEL_HIGH>;
+
+- clocks = <&rp1_clocks RP1_CLK_MIPI1_CFG>, // required, config bus clock
+- <&rp1_clocks RP1_CLK_MIPI1_DPI>, // required, pixel clock
+- <&clksrc_mipi1_dsi_byteclk>, // internal, parent for divide
+- <&clk_xosc>; // hardwired to DSI "refclk"
+- clock-names = "cfgclk", "dpiclk", "byteclk", "refclk";
++ clocks = <&rp1_clocks RP1_CLK_MIPI1_CFG>,
++ <&rp1_clocks RP1_CLK_MIPI1_DPI>,
++ <&rp1_clocks RP1_CLK_MIPI1_DSI_BYTECLOCK>,
++ <&clk_xosc>, // hardwired to DSI "refclk"
++ <&rp1_clocks RP1_PLL_SYS>; // alternate parent for divide
++ clock-names = "cfgclk", "dpiclk", "byteclk", "refclk", "pllsys";
+
+- assigned-clocks = <&rp1_clocks RP1_CLK_MIPI1_CFG>,
+- <&rp1_clocks RP1_CLK_MIPI1_DPI>;
++ assigned-clocks = <&rp1_clocks RP1_CLK_MIPI1_CFG>;
+ assigned-clock-rates = <25000000>;
+- assigned-clock-parents = <0>, <&clksrc_mipi1_dsi_byteclk>;
+ };
+
+ /* VEC and DPI both need to control PLL_VIDEO and cannot work together; */
+@@ -1216,24 +1214,6 @@
+ clock-output-names = "core";
+ clock-frequency = <50000000>;
+ };
+- clksrc_mipi0_dsi_byteclk: clksrc_mipi0_dsi_byteclk {
+- // This clock is synthesized by MIPI0 D-PHY, when DSI is running.
+- // Its frequency is not known a priori (until a panel driver attaches)
+- // so assign a made-up frequency of 72MHz so it can be divided for DPI.
+- compatible = "fixed-clock";
+- #clock-cells = <0>;
+- clock-output-names = "clksrc_mipi0_dsi_byteclk";
+- clock-frequency = <72000000>;
+- };
+- clksrc_mipi1_dsi_byteclk: clksrc_mipi1_dsi_byteclk {
+- // This clock is synthesized by MIPI1 D-PHY, when DSI is running.
+- // Its frequency is not known a priori (until a panel driver attaches)
+- // so assign a made-up frequency of 72MHz so it can be divided for DPI.
+- compatible = "fixed-clock";
+- #clock-cells = <0>;
+- clock-output-names = "clksrc_mipi1_dsi_byteclk";
+- clock-frequency = <72000000>;
+- };
+ /* GPIO derived clock sources. Each GPIO with a GPCLK function
+ * can drive its output from the respective GPCLK
+ * generator, and provide a clock source to other internal
--- /dev/null
+From f5de8d46da4b40f2180be502c1e547fe8c9b2ac2 Mon Sep 17 00:00:00 2001
+From: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
+Date: Fri, 10 May 2024 15:48:15 +0100
+Subject: [PATCH 1179/1215] drm: rp1: rp1-dsi: Switch to PLL_SYS source for DPI
+ when 8 * lanes > bpp
+
+To support 4 lanes, re-parent DPI clock source between DSI byteclock
+(using the new "variable sources" defined in clk-rp1) and PLL_SYS.
+This is to cover cases in which byteclock < pixclock <= 200MHz.
+
+Tidying: All frequencies now in Hz (not kHz), where DSI speed is now
+represented by byteclock to simplify arithmetic. Clamp DPI and byte
+clocks to their legal ranges; fix up HSTX timeout to avoid an unsafe
+assumption that it would return to LP state for every scanline.
+
+Because of RP1's clock topology, the ratio between DSI and DPI clocks
+may not be exact with 3 or 4 lanes, leading to slightly irregular
+timings each time DSI switches between HS and LP states. Tweak to
+inhibit LP during Horizontal BP when sync pulses were requested.
+
+Signed-off-by: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
+---
+ drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.c | 3 +-
+ drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.h | 3 +-
+ drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dsi.c | 130 +++++++++++++---------
+ 3 files changed, 80 insertions(+), 56 deletions(-)
+
+--- a/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.c
++++ b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.c
+@@ -54,6 +54,7 @@ static void rp1_dsi_bridge_pre_enable(st
+ struct rp1_dsi *dsi = bridge_to_rp1_dsi(bridge);
+
+ rp1dsi_dsi_setup(dsi, &dsi->pipe.crtc.state->adjusted_mode);
++ dsi->dsi_running = true;
+ }
+
+ static void rp1_dsi_bridge_enable(struct drm_bridge *bridge,
+@@ -443,7 +444,7 @@ static int rp1dsi_platform_probe(struct
+ /* Hardware resources */
+ for (i = 0; i < RP1DSI_NUM_CLOCKS; i++) {
+ static const char * const myclocknames[RP1DSI_NUM_CLOCKS] = {
+- "cfgclk", "dpiclk", "byteclk", "refclk"
++ "cfgclk", "dpiclk", "byteclk", "refclk", "pllsys"
+ };
+ dsi->clocks[i] = devm_clk_get(dev, myclocknames[i]);
+ if (IS_ERR(dsi->clocks[i])) {
+--- a/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.h
++++ b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.h
+@@ -30,7 +30,8 @@
+ #define RP1DSI_CLOCK_DPI 1
+ #define RP1DSI_CLOCK_BYTE 2
+ #define RP1DSI_CLOCK_REF 3
+-#define RP1DSI_NUM_CLOCKS 4
++#define RP1DSI_CLOCK_PLLSYS 4
++#define RP1DSI_NUM_CLOCKS 5
+
+ /* ---------------------------------------------------------------------- */
+
+--- a/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dsi.c
++++ b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dsi.c
+@@ -7,6 +7,7 @@
+
+ #include <linux/delay.h>
+ #include <linux/errno.h>
++#include <linux/math64.h>
+ #include <linux/platform_device.h>
+ #include <linux/rp1_platform.h>
+ #include "drm/drm_print.h"
+@@ -1111,7 +1112,7 @@ static void dphy_transaction(struct rp1_
+ DSI_WRITE(DSI_PHY_TST_CTRL0, DPHY_CTRL0_PHY_TESTCLK_BITS);
+ }
+
+-static uint8_t dphy_get_div(u32 refclk_khz, u32 vco_freq_khz, u32 *ptr_m, u32 *ptr_n)
++static u64 dphy_get_div(u32 refclk, u64 vco_freq, u32 *ptr_m, u32 *ptr_n)
+ {
+ /*
+ * See pg 77-78 of dphy databook
+@@ -1124,19 +1125,23 @@ static uint8_t dphy_get_div(u32 refclk_k
+ * In practice, given a 50MHz reference clock, it can produce any
+ * multiple of 10MHz, 11.1111MHz, 12.5MHz, 14.286MHz or 16.667MHz
+ * with < 1% error for all frequencies above 495MHz.
++ *
++ * vco_freq should be set to the lane bit rate (not the MIPI clock
++ * which is half of this). These frequencies are now measured in Hz.
++ * They should fit within u32, but u64 is needed for calculations.
+ */
+
+- static const u32 REF_DIVN_MAX = 40000u;
+- static const u32 REF_DIVN_MIN = 5000u;
+- u32 best_n, best_m, best_err = 0x7fffffff;
+- unsigned int n;
++ static const u32 REF_DIVN_MAX = 40000000;
++ static const u32 REF_DIVN_MIN = 5000000;
++ u32 n, best_n, best_m;
++ u64 best_err = vco_freq;
+
+- for (n = 1 + refclk_khz / REF_DIVN_MAX; n * REF_DIVN_MIN <= refclk_khz && n < 100; ++n) {
+- u32 half_m = (n * vco_freq_khz + refclk_khz) / (2 * refclk_khz);
++ for (n = 1 + refclk / REF_DIVN_MAX; n * REF_DIVN_MIN <= refclk && n < 100; ++n) {
++ u32 half_m = DIV_U64_ROUND_CLOSEST(n * vco_freq, 2 * refclk);
+
+ if (half_m < 150) {
+- u32 f = (2 * half_m * refclk_khz) / n;
+- u32 err = (f > vco_freq_khz) ? f - vco_freq_khz : vco_freq_khz - f;
++ u64 f = div_u64(mul_u32_u32(2 * half_m, refclk), n);
++ u64 err = (f > vco_freq) ? f - vco_freq : vco_freq - f;
+
+ if (err < best_err) {
+ best_n = n;
+@@ -1148,12 +1153,12 @@ static uint8_t dphy_get_div(u32 refclk_k
+ }
+ }
+
+- if (64 * best_err < vco_freq_khz) { /* tolerate small error */
+- *ptr_n = best_n;
+- *ptr_m = best_m;
+- return 1;
+- }
+- return 0;
++ if (64 * best_err >= vco_freq)
++ return 0;
++
++ *ptr_n = best_n;
++ *ptr_m = best_m;
++ return div_u64(mul_u32_u32(best_m, refclk), best_n);
+ }
+
+ struct hsfreq_range {
+@@ -1226,13 +1231,14 @@ static void dphy_set_hsfreqrange(struct
+ hsfreq_table[i].hsfreqrange << 1);
+ }
+
+-static void dphy_configure_pll(struct rp1_dsi *dsi, u32 refclk_khz, u32 vco_freq_khz)
++static u32 dphy_configure_pll(struct rp1_dsi *dsi, u32 refclk, u32 vco_freq)
+ {
+ u32 m = 0;
+ u32 n = 0;
++ u32 actual_vco_freq = dphy_get_div(refclk, vco_freq, &m, &n);
+
+- if (dphy_get_div(refclk_khz, vco_freq_khz, &m, &n)) {
+- dphy_set_hsfreqrange(dsi, vco_freq_khz / 1000);
++ if (actual_vco_freq) {
++ dphy_set_hsfreqrange(dsi, actual_vco_freq / 1000000);
+ /* Program m,n from registers */
+ dphy_transaction(dsi, DPHY_PLL_DIV_CTRL_OFFSET, 0x30);
+ /* N (program N-1) */
+@@ -1242,18 +1248,21 @@ static void dphy_configure_pll(struct rp
+ /* M[4:0] (program M-1) */
+ dphy_transaction(dsi, DPHY_PLL_LOOP_DIV_OFFSET, ((m - 1) & 0x1F));
+ drm_dbg_driver(dsi->drm,
+- "DPHY: vco freq want %dkHz got %dkHz = %d * (%dkHz / %d), hsfreqrange = 0x%02x\r\n",
+- vco_freq_khz, refclk_khz * m / n, m, refclk_khz,
+- n, hsfreq_table[dsi->hsfreq_index].hsfreqrange);
++ "DPHY: vco freq want %uHz got %uHz = %d * (%uHz / %d), hsfreqrange = 0x%02x\n",
++ vco_freq, actual_vco_freq, m, refclk, n,
++ hsfreq_table[dsi->hsfreq_index].hsfreqrange);
+ } else {
+- drm_info(dsi->drm,
+- "rp1dsi: Error configuring DPHY PLL! %dkHz = %d * (%dkHz / %d)\r\n",
+- vco_freq_khz, m, refclk_khz, n);
++ drm_warn(dsi->drm,
++ "rp1dsi: Error configuring DPHY PLL %uHz\n", vco_freq);
+ }
++
++ return actual_vco_freq;
+ }
+
+-static void dphy_init_khz(struct rp1_dsi *dsi, u32 ref_freq, u32 vco_freq)
++static u32 dphy_init(struct rp1_dsi *dsi, u32 ref_freq, u32 vco_freq)
+ {
++ u32 actual_vco_freq;
++
+ /* Reset the PHY */
+ DSI_WRITE(DSI_PHYRSTZ, 0);
+ DSI_WRITE(DSI_PHY_TST_CTRL0, DPHY_CTRL0_PHY_TESTCLK_BITS);
+@@ -1263,13 +1272,15 @@ static void dphy_init_khz(struct rp1_dsi
+ DSI_WRITE(DSI_PHY_TST_CTRL0, DPHY_CTRL0_PHY_TESTCLK_BITS);
+ udelay(1);
+ /* Since we are in DSI (not CSI2) mode here, start the PLL */
+- dphy_configure_pll(dsi, ref_freq, vco_freq);
++ actual_vco_freq = dphy_configure_pll(dsi, ref_freq, vco_freq);
+ udelay(1);
+ /* Unreset */
+ DSI_WRITE(DSI_PHYRSTZ, DSI_PHYRSTZ_SHUTDOWNZ_BITS);
+ udelay(1);
+ DSI_WRITE(DSI_PHYRSTZ, (DSI_PHYRSTZ_SHUTDOWNZ_BITS | DSI_PHYRSTZ_RSTZ_BITS));
+ udelay(1); /* so we can see PLL coming up? */
++
++ return actual_vco_freq;
+ }
+
+ void rp1dsi_mipicfg_setup(struct rp1_dsi *dsi)
+@@ -1290,23 +1301,30 @@ static unsigned long rp1dsi_refclk_freq(
+ return u;
+ }
+
+-static void rp1dsi_dpiclk_start(struct rp1_dsi *dsi, unsigned int bpp, unsigned int lanes)
++static void rp1dsi_dpiclk_start(struct rp1_dsi *dsi, u32 byte_clock,
++ unsigned int bpp, unsigned int lanes)
+ {
+- unsigned long u;
+-
+- if (dsi->clocks[RP1DSI_CLOCK_DPI]) {
+- u = (dsi->clocks[RP1DSI_CLOCK_BYTE]) ?
+- clk_get_rate(dsi->clocks[RP1DSI_CLOCK_BYTE]) : 0;
+- drm_info(dsi->drm,
+- "rp1dsi: Nominal byte clock %lu; scale by %u/%u",
+- u, 4 * lanes, (bpp >> 1));
+- if (u < 1 || u >= (1ul << 28))
+- u = 72000000ul; /* default DUMMY frequency for byteclock */
++ /* Dummy clk_set_rate() to declare the actual DSI byte-clock rate */
++ clk_set_rate(dsi->clocks[RP1DSI_CLOCK_BYTE], byte_clock);
+
++ /*
++ * Prefer the DSI byte-clock source where possible, so that DSI and DPI
++ * clocks will be in an exact ratio and downstream devices can recover
++ * perfect timings. But when DPI clock is faster, fall back on PLL_SYS.
++ * To defeat rounding errors, specify explicitly which source to use.
++ */
++ if (bpp >= 8 * lanes)
+ clk_set_parent(dsi->clocks[RP1DSI_CLOCK_DPI], dsi->clocks[RP1DSI_CLOCK_BYTE]);
+- clk_set_rate(dsi->clocks[RP1DSI_CLOCK_DPI], (4 * lanes * u) / (bpp >> 1));
+- clk_prepare_enable(dsi->clocks[RP1DSI_CLOCK_DPI]);
+- }
++ else if (dsi->clocks[RP1DSI_CLOCK_PLLSYS])
++ clk_set_parent(dsi->clocks[RP1DSI_CLOCK_DPI], dsi->clocks[RP1DSI_CLOCK_PLLSYS]);
++
++ clk_set_rate(dsi->clocks[RP1DSI_CLOCK_DPI], (4 * lanes * byte_clock) / (bpp >> 1));
++ clk_prepare_enable(dsi->clocks[RP1DSI_CLOCK_DPI]);
++ drm_info(dsi->drm,
++ "rp1dsi: Nominal Byte clock %u DPI clock %lu (parent rate %lu)",
++ byte_clock,
++ clk_get_rate(dsi->clocks[RP1DSI_CLOCK_DPI]),
++ clk_get_rate(clk_get_parent(dsi->clocks[RP1DSI_CLOCK_DPI])));
+ }
+
+ static void rp1dsi_dpiclk_stop(struct rp1_dsi *dsi)
+@@ -1336,18 +1354,21 @@ static u32 get_colorcode(enum mipi_dsi_p
+ return 0x005;
+ }
+
+-/* Maximum frequency for LP escape clock (20MHz), and some magic numbers */
+-#define RP1DSI_ESC_CLK_KHZ 20000
+-#define RP1DSI_TO_CLK_DIV 5
+-#define RP1DSI_HSTX_TO_MIN 0x200
+-#define RP1DSI_LPRX_TO_VAL 0x400
++/* Frequency limits for DPI, HS and LP clocks, and some magic numbers */
++#define RP1DSI_DPI_MAX_KHZ 200000
++#define RP1DSI_BYTE_CLK_MIN 10000000
++#define RP1DSI_BYTE_CLK_MAX 187500000
++#define RP1DSI_ESC_CLK_MAX 20000000
++#define RP1DSI_TO_CLK_DIV 0x50
++#define RP1DSI_LPRX_TO_VAL 0x40
+ #define RP1DSI_BTA_TO_VAL 0xd00
+
+ void rp1dsi_dsi_setup(struct rp1_dsi *dsi, struct drm_display_mode const *mode)
+ {
+ u32 timeout, mask, vid_mode_cfg;
+- int lane_kbps;
+ unsigned int bpp = mipi_dsi_pixel_format_to_bpp(dsi->display_format);
++ u32 byte_clock = clamp((bpp * 125 * min(mode->clock, RP1DSI_DPI_MAX_KHZ)) / dsi->lanes,
++ RP1DSI_BYTE_CLK_MIN, RP1DSI_BYTE_CLK_MAX);
+
+ DSI_WRITE(DSI_PHY_IF_CFG, dsi->lanes - 1);
+ DSI_WRITE(DSI_DPI_CFG_POL, 0);
+@@ -1360,6 +1381,8 @@ void rp1dsi_dsi_setup(struct rp1_dsi *ds
+ vid_mode_cfg = 0xbf00;
+ if (!(dsi->display_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE))
+ vid_mode_cfg |= 0x01;
++ else if (8 * dsi->lanes > bpp)
++ vid_mode_cfg &= ~0x400; /* PULSE && inexact DPICLK => fix HBP time */
+ if (dsi->display_flags & MIPI_DSI_MODE_VIDEO_BURST)
+ vid_mode_cfg |= 0x02;
+ DSI_WRITE(DSI_VID_MODE_CFG, vid_mode_cfg);
+@@ -1369,15 +1392,14 @@ void rp1dsi_dsi_setup(struct rp1_dsi *ds
+ DSI_WRITE(DSI_MODE_CFG, 1);
+
+ /* Set timeouts and clock dividers */
+- DSI_WRITE(DSI_TO_CNT_CFG,
+- (max((bpp * mode->htotal) / (7 * RP1DSI_TO_CLK_DIV * dsi->lanes),
+- RP1DSI_HSTX_TO_MIN) << 16) |
+- RP1DSI_LPRX_TO_VAL);
++ timeout = (bpp * mode->htotal * mode->vdisplay) / (7 * RP1DSI_TO_CLK_DIV * dsi->lanes);
++ if (timeout > 0xFFFFu)
++ timeout = 0;
++ DSI_WRITE(DSI_TO_CNT_CFG, (timeout << 16) | RP1DSI_LPRX_TO_VAL);
+ DSI_WRITE(DSI_BTA_TO_CNT, RP1DSI_BTA_TO_VAL);
+- lane_kbps = (bpp * mode->clock) / dsi->lanes;
+ DSI_WRITE(DSI_CLKMGR_CFG,
+ (RP1DSI_TO_CLK_DIV << 8) |
+- max(2, lane_kbps / (8 * RP1DSI_ESC_CLK_KHZ) + 1));
++ max(2u, 1u + byte_clock / RP1DSI_ESC_CLK_MAX));
+
+ /* Configure video timings */
+ DSI_WRITE(DSI_VID_PKT_SIZE, mode->hdisplay);
+@@ -1394,7 +1416,7 @@ void rp1dsi_dsi_setup(struct rp1_dsi *ds
+ DSI_WRITE(DSI_VID_VACTIVE_LINES, mode->vdisplay);
+
+ /* Init PHY */
+- dphy_init_khz(dsi, rp1dsi_refclk_freq(dsi) / 1000, lane_kbps);
++ byte_clock = dphy_init(dsi, rp1dsi_refclk_freq(dsi), 8 * byte_clock) >> 3;
+
+ DSI_WRITE(DSI_PHY_TMR_LPCLK_CFG,
+ (hsfreq_table[dsi->hsfreq_index].clk_lp2hs << DSI_PHY_TMR_LP2HS_LSB) |
+@@ -1418,7 +1440,7 @@ void rp1dsi_dsi_setup(struct rp1_dsi *ds
+ DSI_WRITE(DSI_PWR_UP, 0x1); /* power up */
+
+ /* Now it should be safe to start the external DPI clock divider */
+- rp1dsi_dpiclk_start(dsi, bpp, dsi->lanes);
++ rp1dsi_dpiclk_start(dsi, byte_clock, bpp, dsi->lanes);
+
+ /* Wait for all lane(s) to be in Stopstate */
+ mask = (1 << 4);
--- /dev/null
+From 10c77e119eaaa2677009dea58cf69a8e5383925b Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Wed, 17 Jul 2024 17:27:36 +0100
+Subject: [PATCH 1180/1215] arm64: dts: Move bcm2712 and rp1 here
+
+It is pointless having the bcm2712 family of dts files and rp1.dtsi
+in the arch/arm directory tree, since they then require placeholders
+to include them in arch/arm64 where they are built. The files have
+no dependencies on other files in the arch/arm tree, so simply move
+them here.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ .../arm/boot/dts/broadcom/bcm2712-rpi-5-b.dts | 867 ------------------
+ .../dts/broadcom/bcm2712-rpi-cm5-cm4io.dts | 20 -
+ .../dts/broadcom/bcm2712-rpi-cm5-cm5io.dts | 10 -
+ .../boot/dts/broadcom/bcm2712d0-rpi-5-b.dts | 107 ---
+ .../boot/dts/broadcom/bcm2712-rpi-5-b.dts | 867 +++++++++++++++++-
+ .../dts/broadcom/bcm2712-rpi-cm5-cm4io.dts | 20 +-
+ .../dts/broadcom/bcm2712-rpi-cm5-cm5io.dts | 10 +-
+ .../boot/dts/broadcom/bcm2712-rpi-cm5.dtsi | 10 +-
+ .../boot/dts/broadcom/bcm2712-rpi.dtsi | 0
+ .../boot/dts/broadcom/bcm2712.dtsi | 0
+ .../boot/dts/broadcom/bcm2712d0-rpi-5-b.dts | 107 ++-
+ .../{arm => arm64}/boot/dts/broadcom/rp1.dtsi | 0
+ 12 files changed, 1002 insertions(+), 1016 deletions(-)
+ delete mode 100644 arch/arm/boot/dts/broadcom/bcm2712-rpi-5-b.dts
+ delete mode 100644 arch/arm/boot/dts/broadcom/bcm2712-rpi-cm5-cm4io.dts
+ delete mode 100644 arch/arm/boot/dts/broadcom/bcm2712-rpi-cm5-cm5io.dts
+ delete mode 100644 arch/arm/boot/dts/broadcom/bcm2712d0-rpi-5-b.dts
+ rename arch/{arm => arm64}/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi (98%)
+ rename arch/{arm => arm64}/boot/dts/broadcom/bcm2712-rpi.dtsi (100%)
+ rename arch/{arm => arm64}/boot/dts/broadcom/bcm2712.dtsi (100%)
+ rename arch/{arm => arm64}/boot/dts/broadcom/rp1.dtsi (100%)
+
+--- a/arch/arm/boot/dts/broadcom/bcm2712-rpi-5-b.dts
++++ /dev/null
+@@ -1,867 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0
+-/dts-v1/;
+-
+-#include <dt-bindings/gpio/gpio.h>
+-#include <dt-bindings/clock/rp1.h>
+-#include <dt-bindings/interrupt-controller/irq.h>
+-#include <dt-bindings/mfd/rp1.h>
+-#include <dt-bindings/pwm/pwm.h>
+-#include <dt-bindings/reset/raspberrypi,firmware-reset.h>
+-
+-#define i2c0 _i2c0
+-#define i2c3 _i2c3
+-#define i2c4 _i2c4
+-#define i2c5 _i2c5
+-#define i2c6 _i2c6
+-#define i2c8 _i2c8
+-#define i2s _i2s
+-#define pwm0 _pwm0
+-#define pwm1 _pwm1
+-#define spi0 _spi0
+-#define spi3 _spi3
+-#define spi4 _spi4
+-#define spi5 _spi5
+-#define spi6 _spi6
+-#define uart0 _uart0
+-#define uart2 _uart2
+-#define uart5 _uart5
+-
+-#include "bcm2712.dtsi"
+-
+-#undef i2c0
+-#undef i2c3
+-#undef i2c4
+-#undef i2c5
+-#undef i2c6
+-#undef i2c8
+-#undef i2s
+-#undef pwm0
+-#undef pwm1
+-#undef spi0
+-#undef spi3
+-#undef spi4
+-#undef spi5
+-#undef spi6
+-#undef uart0
+-#undef uart2
+-#undef uart3
+-#undef uart4
+-#undef uart5
+-
+-/ {
+- compatible = "raspberrypi,5-model-b", "brcm,bcm2712";
+- model = "Raspberry Pi 5";
+-
+- /* Will be filled by the bootloader */
+- memory@0 {
+- device_type = "memory";
+- reg = <0 0 0x28000000>;
+- };
+-
+- leds: leds {
+- compatible = "gpio-leds";
+-
+- led_pwr: led-pwr {
+- label = "PWR";
+- gpios = <&rp1_gpio 44 GPIO_ACTIVE_LOW>;
+- default-state = "off";
+- linux,default-trigger = "none";
+- };
+-
+- led_act: led-act {
+- label = "ACT";
+- gpios = <&gio_aon 9 GPIO_ACTIVE_LOW>;
+- default-state = "off";
+- linux,default-trigger = "mmc0";
+- };
+- };
+-
+- sd_io_1v8_reg: sd_io_1v8_reg {
+- compatible = "regulator-gpio";
+- regulator-name = "vdd-sd-io";
+- regulator-min-microvolt = <1800000>;
+- regulator-max-microvolt = <3300000>;
+- regulator-boot-on;
+- regulator-always-on;
+- regulator-settling-time-us = <5000>;
+- gpios = <&gio_aon 3 GPIO_ACTIVE_HIGH>;
+- states = <1800000 0x1
+- 3300000 0x0>;
+- status = "okay";
+- };
+-
+- sd_vcc_reg: sd_vcc_reg {
+- compatible = "regulator-fixed";
+- regulator-name = "vcc-sd";
+- regulator-min-microvolt = <3300000>;
+- regulator-max-microvolt = <3300000>;
+- regulator-boot-on;
+- enable-active-high;
+- gpios = <&gio_aon 4 GPIO_ACTIVE_HIGH>;
+- status = "okay";
+- };
+-
+- wl_on_reg: wl_on_reg {
+- compatible = "regulator-fixed";
+- regulator-name = "wl-on-regulator";
+- regulator-min-microvolt = <3300000>;
+- regulator-max-microvolt = <3300000>;
+- pinctrl-0 = <&wl_on_pins>;
+- pinctrl-names = "default";
+-
+- gpio = <&gio 28 GPIO_ACTIVE_HIGH>;
+-
+- startup-delay-us = <150000>;
+- enable-active-high;
+- };
+-
+- clocks: clocks {
+- };
+-
+- cam1_clk: cam1_clk {
+- compatible = "fixed-clock";
+- #clock-cells = <0>;
+- status = "disabled";
+- };
+-
+- cam0_clk: cam0_clk {
+- compatible = "fixed-clock";
+- #clock-cells = <0>;
+- status = "disabled";
+- };
+-
+- cam0_reg: cam0_reg {
+- compatible = "regulator-fixed";
+- regulator-name = "cam0_reg";
+- enable-active-high;
+- status = "okay";
+- gpio = <&rp1_gpio 34 0>; // CD0_IO0_MICCLK, to MIPI 0 connector
+- };
+-
+- cam1_reg: cam1_reg {
+- compatible = "regulator-fixed";
+- regulator-name = "cam1_reg";
+- enable-active-high;
+- status = "okay";
+- gpio = <&rp1_gpio 46 0>; // CD1_IO0_MICCLK, to MIPI 1 connector
+- };
+-
+- cam_dummy_reg: cam_dummy_reg {
+- compatible = "regulator-fixed";
+- regulator-name = "cam-dummy-reg";
+- status = "okay";
+- };
+-
+- dummy: dummy {
+- // A target for unwanted overlay fragments
+- };
+-
+-
+- // A few extra labels to keep overlays happy
+-
+- i2c0if: i2c0if {};
+- i2c0mux: i2c0mux {};
+-};
+-
+-rp1_target: &pcie2 {
+- brcm,enable-mps-rcb;
+- brcm,vdm-qos-map = <0xbbaa9888>;
+- aspm-no-l0s;
+- status = "okay";
+-};
+-
+-&pcie1 {
+- brcm,vdm-qos-map = <0x33333333>;
+-};
+-
+-// Add some labels to 2712 device
+-
+-// The system UART
+-uart10: &_uart0 { status = "okay"; };
+-
+-// The system SPI for the bootloader EEPROM
+-spi10: &_spi0 { status = "okay"; };
+-
+-i2c_rp1boot: &_i2c3 { };
+-
+-#include "rp1.dtsi"
+-
+-&rp1 {
+- // PCIe address space layout:
+- // 00_00000000-00_00xxxxxx = RP1 peripherals
+- // 10_00000000-1x_xxxxxxxx = up to 64GB system RAM
+-
+- // outbound access aimed at PCIe 0_00xxxxxx -> RP1 c0_40xxxxxx
+- // This is the RP1 peripheral space
+- ranges = <0xc0 0x40000000
+- 0x02000000 0x00 0x00000000
+- 0x00 0x00400000>;
+-
+- dma-ranges =
+- // inbound RP1 1x_xxxxxxxx -> PCIe 1x_xxxxxxxx
+- <0x10 0x00000000
+- 0x43000000 0x10 0x00000000
+- 0x10 0x00000000>,
+-
+- // inbound RP1 c0_40xxxxxx -> PCIe 00_00xxxxxx
+- // This allows the RP1 DMA controller to address RP1 hardware
+- <0xc0 0x40000000
+- 0x02000000 0x0 0x00000000
+- 0x0 0x00400000>,
+-
+- // inbound RP1 0x_xxxxxxxx -> PCIe 1x_xxxxxxxx
+- <0x00 0x00000000
+- 0x02000000 0x10 0x00000000
+- 0x10 0x00000000>;
+-};
+-
+-// Expose RP1 nodes as system nodes with labels
+-
+-&rp1_dma {
+- status = "okay";
+-};
+-
+-&rp1_eth {
+- status = "okay";
+- phy-handle = <&phy1>;
+- phy-reset-gpios = <&rp1_gpio 32 GPIO_ACTIVE_LOW>;
+- phy-reset-duration = <5>;
+-
+- phy1: ethernet-phy@1 {
+- reg = <0x1>;
+- brcm,powerdown-enable;
+- };
+-};
+-
+-gpio: &rp1_gpio {
+- status = "okay";
+-};
+-
+-aux: &dummy {};
+-
+-&rp1_usb0 {
+- pinctrl-0 = <&usb_vbus_pins>;
+- pinctrl-names = "default";
+- status = "okay";
+-};
+-
+-&rp1_usb1 {
+- status = "okay";
+-};
+-
+-#include "bcm2712-rpi.dtsi"
+-
+-i2c_csi_dsi0: &i2c6 { // Note: This is for MIPI0 connector only
+- pinctrl-0 = <&rp1_i2c6_38_39>;
+- pinctrl-names = "default";
+- clock-frequency = <100000>;
+-};
+-
+-i2c_csi_dsi1: &i2c4 { // Note: This is for MIPI1 connector only
+- pinctrl-0 = <&rp1_i2c4_40_41>;
+- pinctrl-names = "default";
+- clock-frequency = <100000>;
+-};
+-
+-i2c_csi_dsi: &i2c_csi_dsi1 { }; // An alias for compatibility
+-
+-csi0: &rp1_csi0 { };
+-csi1: &rp1_csi1 { };
+-dsi0: &rp1_dsi0 { };
+-dsi1: &rp1_dsi1 { };
+-dpi: &rp1_dpi { };
+-vec: &rp1_vec { };
+-dpi_gpio0: &rp1_dpi_24bit_gpio0 { };
+-dpi_gpio1: &rp1_dpi_24bit_gpio2 { };
+-dpi_18bit_cpadhi_gpio0: &rp1_dpi_18bit_cpadhi_gpio0 { };
+-dpi_18bit_cpadhi_gpio2: &rp1_dpi_18bit_cpadhi_gpio2 { };
+-dpi_18bit_gpio0: &rp1_dpi_18bit_gpio0 { };
+-dpi_18bit_gpio2: &rp1_dpi_18bit_gpio2 { };
+-dpi_16bit_cpadhi_gpio0: &rp1_dpi_16bit_cpadhi_gpio0 { };
+-dpi_16bit_cpadhi_gpio2: &rp1_dpi_16bit_cpadhi_gpio2 { };
+-dpi_16bit_gpio0: &rp1_dpi_16bit_gpio0 { };
+-dpi_16bit_gpio2: &rp1_dpi_16bit_gpio2 { };
+-
+-/* Add the IOMMUs for some RP1 bus masters */
+-
+-&csi0 {
+- iommus = <&iommu5>;
+-};
+-
+-&csi1 {
+- iommus = <&iommu5>;
+-};
+-
+-&dsi0 {
+- iommus = <&iommu5>;
+-};
+-
+-&dsi1 {
+- iommus = <&iommu5>;
+-};
+-
+-&dpi {
+- iommus = <&iommu5>;
+-};
+-
+-&vec {
+- iommus = <&iommu5>;
+-};
+-
+-&ddc0 {
+- status = "disabled";
+-};
+-
+-&ddc1 {
+- status = "disabled";
+-};
+-
+-&hdmi0 {
+- clocks = <&firmware_clocks 13>, <&firmware_clocks 14>, <&dvp 0>, <&clk_27MHz>;
+- clock-names = "hdmi", "bvb", "audio", "cec";
+- status = "disabled";
+-};
+-
+-&hdmi1 {
+- clocks = <&firmware_clocks 13>, <&firmware_clocks 14>, <&dvp 1>, <&clk_27MHz>;
+- clock-names = "hdmi", "bvb", "audio", "cec";
+- status = "disabled";
+-};
+-
+-&hvs {
+- clocks = <&firmware_clocks 4>, <&firmware_clocks 16>;
+- clock-names = "core", "disp";
+-};
+-
+-&mop {
+- status = "disabled";
+-};
+-
+-&moplet {
+- status = "disabled";
+-};
+-
+-&pixelvalve0 {
+- status = "disabled";
+-};
+-
+-&pixelvalve1 {
+- status = "disabled";
+-};
+-
+-&disp_intr {
+- status = "disabled";
+-};
+-
+-/* SDIO1 is used to drive the SD card */
+-&sdio1 {
+- pinctrl-0 = <&emmc_sd_pulls>, <&emmc_aon_cd_pins>;
+- pinctrl-names = "default";
+- vqmmc-supply = <&sd_io_1v8_reg>;
+- vmmc-supply = <&sd_vcc_reg>;
+- bus-width = <4>;
+- sd-uhs-sdr50;
+- sd-uhs-ddr50;
+- sd-uhs-sdr104;
+- cd-gpios = <&gio_aon 5 GPIO_ACTIVE_LOW>;
+- //no-1-8-v;
+- status = "okay";
+-};
+-
+-&pinctrl_aon {
+- emmc_aon_cd_pins: emmc_aon_cd_pins {
+- function = "sd_card_g";
+- pins = "aon_gpio5";
+- bias-pull-up;
+- };
+-
+- /* Slight hack - only one PWM pin (status LED) is usable */
+- aon_pwm_1pin: aon_pwm_1pin {
+- function = "aon_pwm";
+- pins = "aon_gpio9";
+- };
+-};
+-
+-&pinctrl {
+- pwr_button_pins: pwr_button_pins {
+- function = "gpio";
+- pins = "gpio20";
+- bias-pull-up;
+- };
+-
+- wl_on_pins: wl_on_pins {
+- function = "gpio";
+- pins = "gpio28";
+- };
+-
+- bt_shutdown_pins: bt_shutdown_pins {
+- function = "gpio";
+- pins = "gpio29";
+- };
+-
+- emmc_sd_pulls: emmc_sd_pulls {
+- pins = "emmc_cmd", "emmc_dat0", "emmc_dat1", "emmc_dat2", "emmc_dat3";
+- bias-pull-up;
+- };
+-};
+-
+-/* uarta communicates with the BT module */
+-&uarta {
+- uart-has-rtscts;
+- auto-flow-control;
+- status = "okay";
+- clock-frequency = <96000000>;
+- pinctrl-0 = <&uarta_24_pins &bt_shutdown_pins>;
+- pinctrl-names = "default";
+-
+- bluetooth: bluetooth {
+- compatible = "brcm,bcm43438-bt";
+- max-speed = <3000000>;
+- shutdown-gpios = <&gio 29 GPIO_ACTIVE_HIGH>;
+- local-bd-address = [ 00 00 00 00 00 00 ];
+- };
+-};
+-
+-&i2c_rp1boot {
+- clock-frequency = <400000>;
+- pinctrl-0 = <&i2c3_m4_agpio0_pins>;
+- pinctrl-names = "default";
+-};
+-
+-/ {
+- chosen: chosen {
+- bootargs = "reboot=w coherent_pool=1M 8250.nr_uarts=1 pci=pcie_bus_safe";
+- stdout-path = "serial10:115200n8";
+- };
+-
+- fan: cooling_fan {
+- status = "disabled";
+- compatible = "pwm-fan";
+- #cooling-cells = <2>;
+- cooling-min-state = <0>;
+- cooling-max-state = <3>;
+- cooling-levels = <0 75 125 175 250>;
+- pwms = <&rp1_pwm1 3 41566 PWM_POLARITY_INVERTED>;
+- rpm-regmap = <&rp1_pwm1>;
+- rpm-offset = <0x3c>;
+- };
+-
+- pwr_button {
+- compatible = "gpio-keys";
+-
+- pinctrl-names = "default";
+- pinctrl-0 = <&pwr_button_pins>;
+- status = "okay";
+-
+- pwr_key: pwr {
+- label = "pwr_button";
+- // linux,code = <205>; // KEY_SUSPEND
+- linux,code = <116>; // KEY_POWER
+- gpios = <&gio 20 GPIO_ACTIVE_LOW>;
+- debounce-interval = <50>; // ms
+- };
+- };
+-};
+-
+-&usb {
+- power-domains = <&power RPI_POWER_DOMAIN_USB>;
+-};
+-
+-/* SDIO2 drives the WLAN interface */
+-&sdio2 {
+- pinctrl-0 = <&sdio2_30_pins>;
+- pinctrl-names = "default";
+- bus-width = <4>;
+- vmmc-supply = <&wl_on_reg>;
+- sd-uhs-ddr50;
+- non-removable;
+- status = "okay";
+- #address-cells = <1>;
+- #size-cells = <0>;
+-
+- wifi: wifi@1 {
+- reg = <1>;
+- compatible = "brcm,bcm4329-fmac";
+- local-mac-address = [00 00 00 00 00 00];
+- };
+-};
+-
+-&rpivid {
+- status = "okay";
+-};
+-
+-&pinctrl {
+- spi10_gpio2: spi10_gpio2 {
+- function = "vc_spi0";
+- pins = "gpio2", "gpio3", "gpio4";
+- bias-disable;
+- };
+-
+- spi10_cs_gpio1: spi10_cs_gpio1 {
+- function = "gpio";
+- pins = "gpio1";
+- bias-pull-up;
+- };
+-};
+-
+-spi10_pins: &spi10_gpio2 {};
+-spi10_cs_pins: &spi10_cs_gpio1 {};
+-
+-&spi10 {
+- pinctrl-names = "default";
+- cs-gpios = <&gio 1 1>;
+- pinctrl-0 = <&spi10_pins &spi10_cs_pins>;
+-
+- spidev10: spidev@0 {
+- compatible = "spidev";
+- reg = <0>; /* CE0 */
+- #address-cells = <1>;
+- #size-cells = <0>;
+- spi-max-frequency = <20000000>;
+- status = "okay";
+- };
+-};
+-
+-// =============================================
+-// Board specific stuff here
+-
+-&gio_aon {
+- // Don't use GIO_AON as an interrupt controller because it will
+- // clash with the firmware monitoring the PMIC interrupt via the VPU.
+-
+- /delete-property/ interrupt-controller;
+-};
+-
+-&main_aon_irq {
+- // Don't use the MAIN_AON_IRQ interrupt controller because it will
+- // clash with the firmware monitoring the PMIC interrupt via the VPU.
+-
+- status = "disabled";
+-};
+-
+-&rp1_pwm1 {
+- status = "disabled";
+- pinctrl-0 = <&rp1_pwm1_gpio45>;
+- pinctrl-names = "default";
+-};
+-
+-&thermal_trips {
+- cpu_tepid: cpu-tepid {
+- temperature = <50000>;
+- hysteresis = <5000>;
+- type = "active";
+- };
+-
+- cpu_warm: cpu-warm {
+- temperature = <60000>;
+- hysteresis = <5000>;
+- type = "active";
+- };
+-
+- cpu_hot: cpu-hot {
+- temperature = <67500>;
+- hysteresis = <5000>;
+- type = "active";
+- };
+-
+- cpu_vhot: cpu-vhot {
+- temperature = <75000>;
+- hysteresis = <5000>;
+- type = "active";
+- };
+-};
+-
+-&cooling_maps {
+- tepid {
+- trip = <&cpu_tepid>;
+- cooling-device = <&fan 1 1>;
+- };
+-
+- warm {
+- trip = <&cpu_warm>;
+- cooling-device = <&fan 2 2>;
+- };
+-
+- hot {
+- trip = <&cpu_hot>;
+- cooling-device = <&fan 3 3>;
+- };
+-
+- vhot {
+- trip = <&cpu_vhot>;
+- cooling-device = <&fan 4 4>;
+- };
+-
+- melt {
+- trip = <&cpu_crit>;
+- cooling-device = <&fan 4 4>;
+- };
+-};
+-
+-&gio {
+- // The GPIOs above 35 are not used on Pi 5, so shrink the upper bank
+- // to reduce the clutter in gpioinfo/pinctrl
+- brcm,gpio-bank-widths = <32 4>;
+-
+- gpio-line-names =
+- "-", // GPIO_000
+- "2712_BOOT_CS_N", // GPIO_001
+- "2712_BOOT_MISO", // GPIO_002
+- "2712_BOOT_MOSI", // GPIO_003
+- "2712_BOOT_SCLK", // GPIO_004
+- "-", // GPIO_005
+- "-", // GPIO_006
+- "-", // GPIO_007
+- "-", // GPIO_008
+- "-", // GPIO_009
+- "-", // GPIO_010
+- "-", // GPIO_011
+- "-", // GPIO_012
+- "-", // GPIO_013
+- "PCIE_SDA", // GPIO_014
+- "PCIE_SCL", // GPIO_015
+- "-", // GPIO_016
+- "-", // GPIO_017
+- "-", // GPIO_018
+- "-", // GPIO_019
+- "PWR_GPIO", // GPIO_020
+- "2712_G21_FS", // GPIO_021
+- "-", // GPIO_022
+- "-", // GPIO_023
+- "BT_RTS", // GPIO_024
+- "BT_CTS", // GPIO_025
+- "BT_TXD", // GPIO_026
+- "BT_RXD", // GPIO_027
+- "WL_ON", // GPIO_028
+- "BT_ON", // GPIO_029
+- "WIFI_SDIO_CLK", // GPIO_030
+- "WIFI_SDIO_CMD", // GPIO_031
+- "WIFI_SDIO_D0", // GPIO_032
+- "WIFI_SDIO_D1", // GPIO_033
+- "WIFI_SDIO_D2", // GPIO_034
+- "WIFI_SDIO_D3"; // GPIO_035
+-};
+-
+-&gio_aon {
+- gpio-line-names =
+- "RP1_SDA", // AON_GPIO_00
+- "RP1_SCL", // AON_GPIO_01
+- "RP1_RUN", // AON_GPIO_02
+- "SD_IOVDD_SEL", // AON_GPIO_03
+- "SD_PWR_ON", // AON_GPIO_04
+- "SD_CDET_N", // AON_GPIO_05
+- "SD_FLG_N", // AON_GPIO_06
+- "-", // AON_GPIO_07
+- "2712_WAKE", // AON_GPIO_08
+- "2712_STAT_LED", // AON_GPIO_09
+- "-", // AON_GPIO_10
+- "-", // AON_GPIO_11
+- "PMIC_INT", // AON_GPIO_12
+- "UART_TX_FS", // AON_GPIO_13
+- "UART_RX_FS", // AON_GPIO_14
+- "-", // AON_GPIO_15
+- "-", // AON_GPIO_16
+-
+- // Pad bank0 out to 32 entries
+- "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
+-
+- "HDMI0_SCL", // AON_SGPIO_00
+- "HDMI0_SDA", // AON_SGPIO_01
+- "HDMI1_SCL", // AON_SGPIO_02
+- "HDMI1_SDA", // AON_SGPIO_03
+- "PMIC_SCL", // AON_SGPIO_04
+- "PMIC_SDA"; // AON_SGPIO_05
+-
+- rp1_run_hog {
+- gpio-hog;
+- gpios = <2 GPIO_ACTIVE_HIGH>;
+- output-high;
+- line-name = "RP1 RUN pin";
+- };
+-};
+-
+-&rp1_gpio {
+- gpio-line-names =
+- "ID_SDA", // GPIO0
+- "ID_SCL", // GPIO1
+- "GPIO2", // GPIO2
+- "GPIO3", // GPIO3
+- "GPIO4", // GPIO4
+- "GPIO5", // GPIO5
+- "GPIO6", // GPIO6
+- "GPIO7", // GPIO7
+- "GPIO8", // GPIO8
+- "GPIO9", // GPIO9
+- "GPIO10", // GPIO10
+- "GPIO11", // GPIO11
+- "GPIO12", // GPIO12
+- "GPIO13", // GPIO13
+- "GPIO14", // GPIO14
+- "GPIO15", // GPIO15
+- "GPIO16", // GPIO16
+- "GPIO17", // GPIO17
+- "GPIO18", // GPIO18
+- "GPIO19", // GPIO19
+- "GPIO20", // GPIO20
+- "GPIO21", // GPIO21
+- "GPIO22", // GPIO22
+- "GPIO23", // GPIO23
+- "GPIO24", // GPIO24
+- "GPIO25", // GPIO25
+- "GPIO26", // GPIO26
+- "GPIO27", // GPIO27
+-
+- "PCIE_RP1_WAKE", // GPIO28
+- "FAN_TACH", // GPIO29
+- "HOST_SDA", // GPIO30
+- "HOST_SCL", // GPIO31
+- "ETH_RST_N", // GPIO32
+- "-", // GPIO33
+-
+- "CD0_IO0_MICCLK", // GPIO34
+- "CD0_IO0_MICDAT0", // GPIO35
+- "RP1_PCIE_CLKREQ_N", // GPIO36
+- "-", // GPIO37
+- "CD0_SDA", // GPIO38
+- "CD0_SCL", // GPIO39
+- "CD1_SDA", // GPIO40
+- "CD1_SCL", // GPIO41
+- "USB_VBUS_EN", // GPIO42
+- "USB_OC_N", // GPIO43
+- "RP1_STAT_LED", // GPIO44
+- "FAN_PWM", // GPIO45
+- "CD1_IO0_MICCLK", // GPIO46
+- "2712_WAKE", // GPIO47
+- "CD1_IO1_MICDAT1", // GPIO48
+- "EN_MAX_USB_CUR", // GPIO49
+- "-", // GPIO50
+- "-", // GPIO51
+- "-", // GPIO52
+- "-"; // GPIO53
+-
+- usb_vbus_pins: usb_vbus_pins {
+- function = "vbus1";
+- pins = "gpio42", "gpio43";
+- };
+-};
+-
+-/ {
+- aliases: aliases {
+- blconfig = &blconfig;
+- blpubkey = &blpubkey;
+- bluetooth = &bluetooth;
+- console = &uart10;
+- ethernet0 = &rp1_eth;
+- wifi0 = &wifi;
+- fb = &fb;
+- mailbox = &mailbox;
+- mmc0 = &sdio1;
+- uart0 = &uart0;
+- uart1 = &uart1;
+- uart2 = &uart2;
+- uart3 = &uart3;
+- uart4 = &uart4;
+- uart10 = &uart10;
+- serial0 = &uart0;
+- serial1 = &uart1;
+- serial2 = &uart2;
+- serial3 = &uart3;
+- serial4 = &uart4;
+- serial10 = &uart10;
+- i2c = &i2c_arm;
+- i2c0 = &i2c0;
+- i2c1 = &i2c1;
+- i2c2 = &i2c2;
+- i2c3 = &i2c3;
+- i2c4 = &i2c4;
+- i2c5 = &i2c5;
+- i2c6 = &i2c6;
+- i2c10 = &i2c_rp1boot;
+- // Bit-bashed i2c_gpios start at 10
+- spi0 = &spi0;
+- spi1 = &spi1;
+- spi2 = &spi2;
+- spi3 = &spi3;
+- spi4 = &spi4;
+- spi5 = &spi5;
+- spi10 = &spi10;
+- gpio0 = &gpio;
+- gpio1 = &gio;
+- gpio2 = &gio_aon;
+- gpio3 = &pinctrl;
+- gpio4 = &pinctrl_aon;
+- usb0 = &rp1_usb0;
+- usb1 = &rp1_usb1;
+- drm-dsi1 = &dsi0;
+- drm-dsi2 = &dsi1;
+- };
+-
+- __overrides__ {
+- bdaddr = <&bluetooth>, "local-bd-address[";
+- button_debounce = <&pwr_key>, "debounce-interval:0";
+- cooling_fan = <&fan>, "status", <&rp1_pwm1>, "status";
+- uart0_console = <&uart0>,"status", <&aliases>, "console=",&uart0;
+- i2c0 = <&i2c0>, "status";
+- i2c1 = <&i2c1>, "status";
+- i2c = <&i2c1>, "status";
+- i2c_arm = <&i2c_arm>, "status";
+- i2c_vc = <&i2c_vc>, "status";
+- i2c_csi_dsi = <&i2c_csi_dsi>, "status";
+- i2c_csi_dsi0 = <&i2c_csi_dsi0>, "status";
+- i2c_csi_dsi1 = <&i2c_csi_dsi1>, "status";
+- i2c0_baudrate = <&i2c0>, "clock-frequency:0";
+- i2c1_baudrate = <&i2c1>, "clock-frequency:0";
+- i2c_baudrate = <&i2c_arm>, "clock-frequency:0";
+- i2c_arm_baudrate = <&i2c_arm>, "clock-frequency:0";
+- i2c_vc_baudrate = <&i2c_vc>, "clock-frequency:0";
+- krnbt = <&bluetooth>, "status";
+- nvme = <&pciex1>, "status";
+- pciex1 = <&pciex1>, "status";
+- pciex1_gen = <&pciex1> , "max-link-speed:0";
+- pciex1_no_l0s = <&pciex1>, "aspm-no-l0s?";
+- pciex1_tperst_clk_ms = <&pciex1>, "brcm,tperst-clk-ms:0";
+- pcie_tperst_clk_ms = <&pciex1>, "brcm,tperst-clk-ms:0";
+- random = <&random>, "status";
+- rtc = <&rpi_rtc>, "status";
+- rtc_bbat_vchg = <&rpi_rtc>, "trickle-charge-microvolt:0";
+- sd_cqe = <&sdio1>, "supports-cqe?";
+- spi = <&spi0>, "status";
+- suspend = <&pwr_key>, "linux,code:0=205";
+- uart0 = <&uart0>, "status";
+- wifiaddr = <&wifi>, "local-mac-address[";
+-
+- act_led_gpio = <&led_act>,"gpios:4",<&led_act>,"gpios:0=",<&gpio>;
+- act_led_activelow = <&led_act>,"gpios:8";
+- act_led_trigger = <&led_act>, "linux,default-trigger";
+- pwr_led_gpio = <&led_pwr>,"gpios:4";
+- pwr_led_activelow = <&led_pwr>, "gpios:8";
+- pwr_led_trigger = <&led_pwr>, "linux,default-trigger";
+- eth_led0 = <&phy1>,"led-modes:0";
+- eth_led1 = <&phy1>,"led-modes:4";
+- drm_fb0_rp1_dsi0 = <&aliases>, "drm-fb0=",&dsi0;
+- drm_fb0_rp1_dsi1 = <&aliases>, "drm-fb0=",&dsi1;
+- drm_fb0_rp1_dpi = <&aliases>, "drm-fb0=",&dpi;
+- drm_fb0_vc4 = <&aliases>, "drm-fb0=",&vc4;
+- drm_fb1_rp1_dsi0 = <&aliases>, "drm-fb1=",&dsi0;
+- drm_fb1_rp1_dsi1 = <&aliases>, "drm-fb1=",&dsi1;
+- drm_fb1_rp1_dpi = <&aliases>, "drm-fb1=",&dpi;
+- drm_fb1_vc4 = <&aliases>, "drm-fb1=",&vc4;
+- drm_fb2_rp1_dsi0 = <&aliases>, "drm-fb2=",&dsi0;
+- drm_fb2_rp1_dsi1 = <&aliases>, "drm-fb2=",&dsi1;
+- drm_fb2_rp1_dpi = <&aliases>, "drm-fb2=",&dpi;
+- drm_fb2_vc4 = <&aliases>, "drm-fb2=",&vc4;
+-
+- fan_temp0 = <&cpu_tepid>,"temperature:0";
+- fan_temp1 = <&cpu_warm>,"temperature:0";
+- fan_temp2 = <&cpu_hot>,"temperature:0";
+- fan_temp3 = <&cpu_vhot>,"temperature:0";
+- fan_temp0_hyst = <&cpu_tepid>,"hysteresis:0";
+- fan_temp1_hyst = <&cpu_warm>,"hysteresis:0";
+- fan_temp2_hyst = <&cpu_hot>,"hysteresis:0";
+- fan_temp3_hyst = <&cpu_vhot>,"hysteresis:0";
+- fan_temp0_speed = <&fan>, "cooling-levels:4";
+- fan_temp1_speed = <&fan>, "cooling-levels:8";
+- fan_temp2_speed = <&fan>, "cooling-levels:12";
+- fan_temp3_speed = <&fan>, "cooling-levels:16";
+- };
+-};
+--- a/arch/arm/boot/dts/broadcom/bcm2712-rpi-cm5-cm4io.dts
++++ /dev/null
+@@ -1,20 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0
+-/dts-v1/;
+-
+-#include "bcm2712-rpi-cm5.dtsi"
+-
+-// The RP1 USB3 interfaces are not usable on CM4IO
+-
+-&rp1_usb0 {
+- status = "disabled";
+-};
+-
+-&rp1_usb1 {
+- status = "disabled";
+-};
+-
+-/ {
+- __overrides__ {
+- i2c_csi_dsi = <&i2c_csi_dsi>, "status";
+- };
+-};
+--- a/arch/arm/boot/dts/broadcom/bcm2712-rpi-cm5-cm5io.dts
++++ /dev/null
+@@ -1,10 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0
+-/dts-v1/;
+-
+-#include "bcm2712-rpi-cm5.dtsi"
+-
+-/ {
+- __overrides__ {
+- i2c_csi_dsi = <&i2c_csi_dsi>, "status";
+- };
+-};
+--- a/arch/arm/boot/dts/broadcom/bcm2712d0-rpi-5-b.dts
++++ /dev/null
+@@ -1,107 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0
+-#include "bcm2712-rpi-5-b.dts"
+-
+-&gio {
+- brcm,gpio-bank-widths = <32 4>;
+-
+- gpio-line-names =
+- "", // GPIO_000
+- "2712_BOOT_CS_N", // GPIO_001
+- "2712_BOOT_MISO", // GPIO_002
+- "2712_BOOT_MOSI", // GPIO_003
+- "2712_BOOT_SCLK", // GPIO_004
+- "", // GPIO_005
+- "", // GPIO_006
+- "", // GPIO_007
+- "", // GPIO_008
+- "", // GPIO_009
+- "", // GPIO_010
+- "", // GPIO_011
+- "", // GPIO_012
+- "", // GPIO_013
+- "PCIE_SDA", // GPIO_014
+- "PCIE_SCL", // GPIO_015
+- "", // GPIO_016
+- "", // GPIO_017
+- "-", // GPIO_018
+- "-", // GPIO_019
+- "PWR_GPIO", // GPIO_020
+- "2712_G21_FS", // GPIO_021
+- "-", // GPIO_022
+- "-", // GPIO_023
+- "BT_RTS", // GPIO_024
+- "BT_CTS", // GPIO_025
+- "BT_TXD", // GPIO_026
+- "BT_RXD", // GPIO_027
+- "WL_ON", // GPIO_028
+- "BT_ON", // GPIO_029
+- "WIFI_SDIO_CLK", // GPIO_030
+- "WIFI_SDIO_CMD", // GPIO_031
+- "WIFI_SDIO_D0", // GPIO_032
+- "WIFI_SDIO_D1", // GPIO_033
+- "WIFI_SDIO_D2", // GPIO_034
+- "WIFI_SDIO_D3"; // GPIO_035
+-};
+-
+-&gio_aon {
+- brcm,gpio-bank-widths = <15 6>;
+-
+- gpio-line-names =
+- "RP1_SDA", // AON_GPIO_00
+- "RP1_SCL", // AON_GPIO_01
+- "RP1_RUN", // AON_GPIO_02
+- "SD_IOVDD_SEL", // AON_GPIO_03
+- "SD_PWR_ON", // AON_GPIO_04
+- "SD_CDET_N", // AON_GPIO_05
+- "SD_FLG_N", // AON_GPIO_06
+- "", // AON_GPIO_07
+- "2712_WAKE", // AON_GPIO_08
+- "2712_STAT_LED", // AON_GPIO_09
+- "", // AON_GPIO_10
+- "", // AON_GPIO_11
+- "PMIC_INT", // AON_GPIO_12
+- "UART_TX_FS", // AON_GPIO_13
+- "UART_RX_FS", // AON_GPIO_14
+- "", // AON_GPIO_15
+- "", // AON_GPIO_16
+-
+- // Pad bank0 out to 32 entries
+- "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
+-
+- "HDMI0_SCL", // AON_SGPIO_00
+- "HDMI0_SDA", // AON_SGPIO_01
+- "HDMI1_SCL", // AON_SGPIO_02
+- "HDMI1_SDA", // AON_SGPIO_03
+- "PMIC_SCL", // AON_SGPIO_04
+- "PMIC_SDA"; // AON_SGPIO_05
+-};
+-
+-&pinctrl {
+- compatible = "brcm,bcm2712d0-pinctrl";
+- reg = <0x7d504100 0x20>;
+-};
+-
+-&pinctrl_aon {
+- compatible = "brcm,bcm2712d0-aon-pinctrl";
+- reg = <0x7d510700 0x1c>;
+-};
+-
+-&vc4 {
+- compatible = "brcm,bcm2712d0-vc6";
+-};
+-
+-&uart10 {
+- interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
+-};
+-
+-&spi10 {
+- dmas = <&dma40 3>, <&dma40 4>;
+-};
+-
+-&hdmi0 {
+- dmas = <&dma40 (12|(1<<30)|(1<<24)|(10<<16)|(15<<20))>;
+-};
+-
+-&hdmi1 {
+- dmas = <&dma40 (13|(1<<30)|(1<<24)|(10<<16)|(15<<20))>;
+-};
+--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts
++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts
+@@ -1,2 +1,867 @@
+ // SPDX-License-Identifier: GPL-2.0
+-#include "arm/broadcom/bcm2712-rpi-5-b.dts"
++/dts-v1/;
++
++#include <dt-bindings/gpio/gpio.h>
++#include <dt-bindings/clock/rp1.h>
++#include <dt-bindings/interrupt-controller/irq.h>
++#include <dt-bindings/mfd/rp1.h>
++#include <dt-bindings/pwm/pwm.h>
++#include <dt-bindings/reset/raspberrypi,firmware-reset.h>
++
++#define i2c0 _i2c0
++#define i2c3 _i2c3
++#define i2c4 _i2c4
++#define i2c5 _i2c5
++#define i2c6 _i2c6
++#define i2c8 _i2c8
++#define i2s _i2s
++#define pwm0 _pwm0
++#define pwm1 _pwm1
++#define spi0 _spi0
++#define spi3 _spi3
++#define spi4 _spi4
++#define spi5 _spi5
++#define spi6 _spi6
++#define uart0 _uart0
++#define uart2 _uart2
++#define uart5 _uart5
++
++#include "bcm2712.dtsi"
++
++#undef i2c0
++#undef i2c3
++#undef i2c4
++#undef i2c5
++#undef i2c6
++#undef i2c8
++#undef i2s
++#undef pwm0
++#undef pwm1
++#undef spi0
++#undef spi3
++#undef spi4
++#undef spi5
++#undef spi6
++#undef uart0
++#undef uart2
++#undef uart3
++#undef uart4
++#undef uart5
++
++/ {
++ compatible = "raspberrypi,5-model-b", "brcm,bcm2712";
++ model = "Raspberry Pi 5";
++
++ /* Will be filled by the bootloader */
++ memory@0 {
++ device_type = "memory";
++ reg = <0 0 0x28000000>;
++ };
++
++ leds: leds {
++ compatible = "gpio-leds";
++
++ led_pwr: led-pwr {
++ label = "PWR";
++ gpios = <&rp1_gpio 44 GPIO_ACTIVE_LOW>;
++ default-state = "off";
++ linux,default-trigger = "none";
++ };
++
++ led_act: led-act {
++ label = "ACT";
++ gpios = <&gio_aon 9 GPIO_ACTIVE_LOW>;
++ default-state = "off";
++ linux,default-trigger = "mmc0";
++ };
++ };
++
++ sd_io_1v8_reg: sd_io_1v8_reg {
++ compatible = "regulator-gpio";
++ regulator-name = "vdd-sd-io";
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <3300000>;
++ regulator-boot-on;
++ regulator-always-on;
++ regulator-settling-time-us = <5000>;
++ gpios = <&gio_aon 3 GPIO_ACTIVE_HIGH>;
++ states = <1800000 0x1
++ 3300000 0x0>;
++ status = "okay";
++ };
++
++ sd_vcc_reg: sd_vcc_reg {
++ compatible = "regulator-fixed";
++ regulator-name = "vcc-sd";
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ regulator-boot-on;
++ enable-active-high;
++ gpios = <&gio_aon 4 GPIO_ACTIVE_HIGH>;
++ status = "okay";
++ };
++
++ wl_on_reg: wl_on_reg {
++ compatible = "regulator-fixed";
++ regulator-name = "wl-on-regulator";
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ pinctrl-0 = <&wl_on_pins>;
++ pinctrl-names = "default";
++
++ gpio = <&gio 28 GPIO_ACTIVE_HIGH>;
++
++ startup-delay-us = <150000>;
++ enable-active-high;
++ };
++
++ clocks: clocks {
++ };
++
++ cam1_clk: cam1_clk {
++ compatible = "fixed-clock";
++ #clock-cells = <0>;
++ status = "disabled";
++ };
++
++ cam0_clk: cam0_clk {
++ compatible = "fixed-clock";
++ #clock-cells = <0>;
++ status = "disabled";
++ };
++
++ cam0_reg: cam0_reg {
++ compatible = "regulator-fixed";
++ regulator-name = "cam0_reg";
++ enable-active-high;
++ status = "okay";
++ gpio = <&rp1_gpio 34 0>; // CD0_IO0_MICCLK, to MIPI 0 connector
++ };
++
++ cam1_reg: cam1_reg {
++ compatible = "regulator-fixed";
++ regulator-name = "cam1_reg";
++ enable-active-high;
++ status = "okay";
++ gpio = <&rp1_gpio 46 0>; // CD1_IO0_MICCLK, to MIPI 1 connector
++ };
++
++ cam_dummy_reg: cam_dummy_reg {
++ compatible = "regulator-fixed";
++ regulator-name = "cam-dummy-reg";
++ status = "okay";
++ };
++
++ dummy: dummy {
++ // A target for unwanted overlay fragments
++ };
++
++
++ // A few extra labels to keep overlays happy
++
++ i2c0if: i2c0if {};
++ i2c0mux: i2c0mux {};
++};
++
++rp1_target: &pcie2 {
++ brcm,enable-mps-rcb;
++ brcm,vdm-qos-map = <0xbbaa9888>;
++ aspm-no-l0s;
++ status = "okay";
++};
++
++&pcie1 {
++ brcm,vdm-qos-map = <0x33333333>;
++};
++
++// Add some labels to 2712 device
++
++// The system UART
++uart10: &_uart0 { status = "okay"; };
++
++// The system SPI for the bootloader EEPROM
++spi10: &_spi0 { status = "okay"; };
++
++i2c_rp1boot: &_i2c3 { };
++
++#include "rp1.dtsi"
++
++&rp1 {
++ // PCIe address space layout:
++ // 00_00000000-00_00xxxxxx = RP1 peripherals
++ // 10_00000000-1x_xxxxxxxx = up to 64GB system RAM
++
++ // outbound access aimed at PCIe 0_00xxxxxx -> RP1 c0_40xxxxxx
++ // This is the RP1 peripheral space
++ ranges = <0xc0 0x40000000
++ 0x02000000 0x00 0x00000000
++ 0x00 0x00400000>;
++
++ dma-ranges =
++ // inbound RP1 1x_xxxxxxxx -> PCIe 1x_xxxxxxxx
++ <0x10 0x00000000
++ 0x43000000 0x10 0x00000000
++ 0x10 0x00000000>,
++
++ // inbound RP1 c0_40xxxxxx -> PCIe 00_00xxxxxx
++ // This allows the RP1 DMA controller to address RP1 hardware
++ <0xc0 0x40000000
++ 0x02000000 0x0 0x00000000
++ 0x0 0x00400000>,
++
++ // inbound RP1 0x_xxxxxxxx -> PCIe 1x_xxxxxxxx
++ <0x00 0x00000000
++ 0x02000000 0x10 0x00000000
++ 0x10 0x00000000>;
++};
++
++// Expose RP1 nodes as system nodes with labels
++
++&rp1_dma {
++ status = "okay";
++};
++
++&rp1_eth {
++ status = "okay";
++ phy-handle = <&phy1>;
++ phy-reset-gpios = <&rp1_gpio 32 GPIO_ACTIVE_LOW>;
++ phy-reset-duration = <5>;
++
++ phy1: ethernet-phy@1 {
++ reg = <0x1>;
++ brcm,powerdown-enable;
++ };
++};
++
++gpio: &rp1_gpio {
++ status = "okay";
++};
++
++aux: &dummy {};
++
++&rp1_usb0 {
++ pinctrl-0 = <&usb_vbus_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++};
++
++&rp1_usb1 {
++ status = "okay";
++};
++
++#include "bcm2712-rpi.dtsi"
++
++i2c_csi_dsi0: &i2c6 { // Note: This is for MIPI0 connector only
++ pinctrl-0 = <&rp1_i2c6_38_39>;
++ pinctrl-names = "default";
++ clock-frequency = <100000>;
++};
++
++i2c_csi_dsi1: &i2c4 { // Note: This is for MIPI1 connector only
++ pinctrl-0 = <&rp1_i2c4_40_41>;
++ pinctrl-names = "default";
++ clock-frequency = <100000>;
++};
++
++i2c_csi_dsi: &i2c_csi_dsi1 { }; // An alias for compatibility
++
++csi0: &rp1_csi0 { };
++csi1: &rp1_csi1 { };
++dsi0: &rp1_dsi0 { };
++dsi1: &rp1_dsi1 { };
++dpi: &rp1_dpi { };
++vec: &rp1_vec { };
++dpi_gpio0: &rp1_dpi_24bit_gpio0 { };
++dpi_gpio1: &rp1_dpi_24bit_gpio2 { };
++dpi_18bit_cpadhi_gpio0: &rp1_dpi_18bit_cpadhi_gpio0 { };
++dpi_18bit_cpadhi_gpio2: &rp1_dpi_18bit_cpadhi_gpio2 { };
++dpi_18bit_gpio0: &rp1_dpi_18bit_gpio0 { };
++dpi_18bit_gpio2: &rp1_dpi_18bit_gpio2 { };
++dpi_16bit_cpadhi_gpio0: &rp1_dpi_16bit_cpadhi_gpio0 { };
++dpi_16bit_cpadhi_gpio2: &rp1_dpi_16bit_cpadhi_gpio2 { };
++dpi_16bit_gpio0: &rp1_dpi_16bit_gpio0 { };
++dpi_16bit_gpio2: &rp1_dpi_16bit_gpio2 { };
++
++/* Add the IOMMUs for some RP1 bus masters */
++
++&csi0 {
++ iommus = <&iommu5>;
++};
++
++&csi1 {
++ iommus = <&iommu5>;
++};
++
++&dsi0 {
++ iommus = <&iommu5>;
++};
++
++&dsi1 {
++ iommus = <&iommu5>;
++};
++
++&dpi {
++ iommus = <&iommu5>;
++};
++
++&vec {
++ iommus = <&iommu5>;
++};
++
++&ddc0 {
++ status = "disabled";
++};
++
++&ddc1 {
++ status = "disabled";
++};
++
++&hdmi0 {
++ clocks = <&firmware_clocks 13>, <&firmware_clocks 14>, <&dvp 0>, <&clk_27MHz>;
++ clock-names = "hdmi", "bvb", "audio", "cec";
++ status = "disabled";
++};
++
++&hdmi1 {
++ clocks = <&firmware_clocks 13>, <&firmware_clocks 14>, <&dvp 1>, <&clk_27MHz>;
++ clock-names = "hdmi", "bvb", "audio", "cec";
++ status = "disabled";
++};
++
++&hvs {
++ clocks = <&firmware_clocks 4>, <&firmware_clocks 16>;
++ clock-names = "core", "disp";
++};
++
++&mop {
++ status = "disabled";
++};
++
++&moplet {
++ status = "disabled";
++};
++
++&pixelvalve0 {
++ status = "disabled";
++};
++
++&pixelvalve1 {
++ status = "disabled";
++};
++
++&disp_intr {
++ status = "disabled";
++};
++
++/* SDIO1 is used to drive the SD card */
++&sdio1 {
++ pinctrl-0 = <&emmc_sd_pulls>, <&emmc_aon_cd_pins>;
++ pinctrl-names = "default";
++ vqmmc-supply = <&sd_io_1v8_reg>;
++ vmmc-supply = <&sd_vcc_reg>;
++ bus-width = <4>;
++ sd-uhs-sdr50;
++ sd-uhs-ddr50;
++ sd-uhs-sdr104;
++ cd-gpios = <&gio_aon 5 GPIO_ACTIVE_LOW>;
++ //no-1-8-v;
++ status = "okay";
++};
++
++&pinctrl_aon {
++ emmc_aon_cd_pins: emmc_aon_cd_pins {
++ function = "sd_card_g";
++ pins = "aon_gpio5";
++ bias-pull-up;
++ };
++
++ /* Slight hack - only one PWM pin (status LED) is usable */
++ aon_pwm_1pin: aon_pwm_1pin {
++ function = "aon_pwm";
++ pins = "aon_gpio9";
++ };
++};
++
++&pinctrl {
++ pwr_button_pins: pwr_button_pins {
++ function = "gpio";
++ pins = "gpio20";
++ bias-pull-up;
++ };
++
++ wl_on_pins: wl_on_pins {
++ function = "gpio";
++ pins = "gpio28";
++ };
++
++ bt_shutdown_pins: bt_shutdown_pins {
++ function = "gpio";
++ pins = "gpio29";
++ };
++
++ emmc_sd_pulls: emmc_sd_pulls {
++ pins = "emmc_cmd", "emmc_dat0", "emmc_dat1", "emmc_dat2", "emmc_dat3";
++ bias-pull-up;
++ };
++};
++
++/* uarta communicates with the BT module */
++&uarta {
++ uart-has-rtscts;
++ auto-flow-control;
++ status = "okay";
++ clock-frequency = <96000000>;
++ pinctrl-0 = <&uarta_24_pins &bt_shutdown_pins>;
++ pinctrl-names = "default";
++
++ bluetooth: bluetooth {
++ compatible = "brcm,bcm43438-bt";
++ max-speed = <3000000>;
++ shutdown-gpios = <&gio 29 GPIO_ACTIVE_HIGH>;
++ local-bd-address = [ 00 00 00 00 00 00 ];
++ };
++};
++
++&i2c_rp1boot {
++ clock-frequency = <400000>;
++ pinctrl-0 = <&i2c3_m4_agpio0_pins>;
++ pinctrl-names = "default";
++};
++
++/ {
++ chosen: chosen {
++ bootargs = "reboot=w coherent_pool=1M 8250.nr_uarts=1 pci=pcie_bus_safe";
++ stdout-path = "serial10:115200n8";
++ };
++
++ fan: cooling_fan {
++ status = "disabled";
++ compatible = "pwm-fan";
++ #cooling-cells = <2>;
++ cooling-min-state = <0>;
++ cooling-max-state = <3>;
++ cooling-levels = <0 75 125 175 250>;
++ pwms = <&rp1_pwm1 3 41566 PWM_POLARITY_INVERTED>;
++ rpm-regmap = <&rp1_pwm1>;
++ rpm-offset = <0x3c>;
++ };
++
++ pwr_button {
++ compatible = "gpio-keys";
++
++ pinctrl-names = "default";
++ pinctrl-0 = <&pwr_button_pins>;
++ status = "okay";
++
++ pwr_key: pwr {
++ label = "pwr_button";
++ // linux,code = <205>; // KEY_SUSPEND
++ linux,code = <116>; // KEY_POWER
++ gpios = <&gio 20 GPIO_ACTIVE_LOW>;
++ debounce-interval = <50>; // ms
++ };
++ };
++};
++
++&usb {
++ power-domains = <&power RPI_POWER_DOMAIN_USB>;
++};
++
++/* SDIO2 drives the WLAN interface */
++&sdio2 {
++ pinctrl-0 = <&sdio2_30_pins>;
++ pinctrl-names = "default";
++ bus-width = <4>;
++ vmmc-supply = <&wl_on_reg>;
++ sd-uhs-ddr50;
++ non-removable;
++ status = "okay";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ wifi: wifi@1 {
++ reg = <1>;
++ compatible = "brcm,bcm4329-fmac";
++ local-mac-address = [00 00 00 00 00 00];
++ };
++};
++
++&rpivid {
++ status = "okay";
++};
++
++&pinctrl {
++ spi10_gpio2: spi10_gpio2 {
++ function = "vc_spi0";
++ pins = "gpio2", "gpio3", "gpio4";
++ bias-disable;
++ };
++
++ spi10_cs_gpio1: spi10_cs_gpio1 {
++ function = "gpio";
++ pins = "gpio1";
++ bias-pull-up;
++ };
++};
++
++spi10_pins: &spi10_gpio2 {};
++spi10_cs_pins: &spi10_cs_gpio1 {};
++
++&spi10 {
++ pinctrl-names = "default";
++ cs-gpios = <&gio 1 1>;
++ pinctrl-0 = <&spi10_pins &spi10_cs_pins>;
++
++ spidev10: spidev@0 {
++ compatible = "spidev";
++ reg = <0>; /* CE0 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <20000000>;
++ status = "okay";
++ };
++};
++
++// =============================================
++// Board specific stuff here
++
++&gio_aon {
++ // Don't use GIO_AON as an interrupt controller because it will
++ // clash with the firmware monitoring the PMIC interrupt via the VPU.
++
++ /delete-property/ interrupt-controller;
++};
++
++&main_aon_irq {
++ // Don't use the MAIN_AON_IRQ interrupt controller because it will
++ // clash with the firmware monitoring the PMIC interrupt via the VPU.
++
++ status = "disabled";
++};
++
++&rp1_pwm1 {
++ status = "disabled";
++ pinctrl-0 = <&rp1_pwm1_gpio45>;
++ pinctrl-names = "default";
++};
++
++&thermal_trips {
++ cpu_tepid: cpu-tepid {
++ temperature = <50000>;
++ hysteresis = <5000>;
++ type = "active";
++ };
++
++ cpu_warm: cpu-warm {
++ temperature = <60000>;
++ hysteresis = <5000>;
++ type = "active";
++ };
++
++ cpu_hot: cpu-hot {
++ temperature = <67500>;
++ hysteresis = <5000>;
++ type = "active";
++ };
++
++ cpu_vhot: cpu-vhot {
++ temperature = <75000>;
++ hysteresis = <5000>;
++ type = "active";
++ };
++};
++
++&cooling_maps {
++ tepid {
++ trip = <&cpu_tepid>;
++ cooling-device = <&fan 1 1>;
++ };
++
++ warm {
++ trip = <&cpu_warm>;
++ cooling-device = <&fan 2 2>;
++ };
++
++ hot {
++ trip = <&cpu_hot>;
++ cooling-device = <&fan 3 3>;
++ };
++
++ vhot {
++ trip = <&cpu_vhot>;
++ cooling-device = <&fan 4 4>;
++ };
++
++ melt {
++ trip = <&cpu_crit>;
++ cooling-device = <&fan 4 4>;
++ };
++};
++
++&gio {
++ // The GPIOs above 35 are not used on Pi 5, so shrink the upper bank
++ // to reduce the clutter in gpioinfo/pinctrl
++ brcm,gpio-bank-widths = <32 4>;
++
++ gpio-line-names =
++ "-", // GPIO_000
++ "2712_BOOT_CS_N", // GPIO_001
++ "2712_BOOT_MISO", // GPIO_002
++ "2712_BOOT_MOSI", // GPIO_003
++ "2712_BOOT_SCLK", // GPIO_004
++ "-", // GPIO_005
++ "-", // GPIO_006
++ "-", // GPIO_007
++ "-", // GPIO_008
++ "-", // GPIO_009
++ "-", // GPIO_010
++ "-", // GPIO_011
++ "-", // GPIO_012
++ "-", // GPIO_013
++ "PCIE_SDA", // GPIO_014
++ "PCIE_SCL", // GPIO_015
++ "-", // GPIO_016
++ "-", // GPIO_017
++ "-", // GPIO_018
++ "-", // GPIO_019
++ "PWR_GPIO", // GPIO_020
++ "2712_G21_FS", // GPIO_021
++ "-", // GPIO_022
++ "-", // GPIO_023
++ "BT_RTS", // GPIO_024
++ "BT_CTS", // GPIO_025
++ "BT_TXD", // GPIO_026
++ "BT_RXD", // GPIO_027
++ "WL_ON", // GPIO_028
++ "BT_ON", // GPIO_029
++ "WIFI_SDIO_CLK", // GPIO_030
++ "WIFI_SDIO_CMD", // GPIO_031
++ "WIFI_SDIO_D0", // GPIO_032
++ "WIFI_SDIO_D1", // GPIO_033
++ "WIFI_SDIO_D2", // GPIO_034
++ "WIFI_SDIO_D3"; // GPIO_035
++};
++
++&gio_aon {
++ gpio-line-names =
++ "RP1_SDA", // AON_GPIO_00
++ "RP1_SCL", // AON_GPIO_01
++ "RP1_RUN", // AON_GPIO_02
++ "SD_IOVDD_SEL", // AON_GPIO_03
++ "SD_PWR_ON", // AON_GPIO_04
++ "SD_CDET_N", // AON_GPIO_05
++ "SD_FLG_N", // AON_GPIO_06
++ "-", // AON_GPIO_07
++ "2712_WAKE", // AON_GPIO_08
++ "2712_STAT_LED", // AON_GPIO_09
++ "-", // AON_GPIO_10
++ "-", // AON_GPIO_11
++ "PMIC_INT", // AON_GPIO_12
++ "UART_TX_FS", // AON_GPIO_13
++ "UART_RX_FS", // AON_GPIO_14
++ "-", // AON_GPIO_15
++ "-", // AON_GPIO_16
++
++ // Pad bank0 out to 32 entries
++ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
++
++ "HDMI0_SCL", // AON_SGPIO_00
++ "HDMI0_SDA", // AON_SGPIO_01
++ "HDMI1_SCL", // AON_SGPIO_02
++ "HDMI1_SDA", // AON_SGPIO_03
++ "PMIC_SCL", // AON_SGPIO_04
++ "PMIC_SDA"; // AON_SGPIO_05
++
++ rp1_run_hog {
++ gpio-hog;
++ gpios = <2 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "RP1 RUN pin";
++ };
++};
++
++&rp1_gpio {
++ gpio-line-names =
++ "ID_SDA", // GPIO0
++ "ID_SCL", // GPIO1
++ "GPIO2", // GPIO2
++ "GPIO3", // GPIO3
++ "GPIO4", // GPIO4
++ "GPIO5", // GPIO5
++ "GPIO6", // GPIO6
++ "GPIO7", // GPIO7
++ "GPIO8", // GPIO8
++ "GPIO9", // GPIO9
++ "GPIO10", // GPIO10
++ "GPIO11", // GPIO11
++ "GPIO12", // GPIO12
++ "GPIO13", // GPIO13
++ "GPIO14", // GPIO14
++ "GPIO15", // GPIO15
++ "GPIO16", // GPIO16
++ "GPIO17", // GPIO17
++ "GPIO18", // GPIO18
++ "GPIO19", // GPIO19
++ "GPIO20", // GPIO20
++ "GPIO21", // GPIO21
++ "GPIO22", // GPIO22
++ "GPIO23", // GPIO23
++ "GPIO24", // GPIO24
++ "GPIO25", // GPIO25
++ "GPIO26", // GPIO26
++ "GPIO27", // GPIO27
++
++ "PCIE_RP1_WAKE", // GPIO28
++ "FAN_TACH", // GPIO29
++ "HOST_SDA", // GPIO30
++ "HOST_SCL", // GPIO31
++ "ETH_RST_N", // GPIO32
++ "-", // GPIO33
++
++ "CD0_IO0_MICCLK", // GPIO34
++ "CD0_IO0_MICDAT0", // GPIO35
++ "RP1_PCIE_CLKREQ_N", // GPIO36
++ "-", // GPIO37
++ "CD0_SDA", // GPIO38
++ "CD0_SCL", // GPIO39
++ "CD1_SDA", // GPIO40
++ "CD1_SCL", // GPIO41
++ "USB_VBUS_EN", // GPIO42
++ "USB_OC_N", // GPIO43
++ "RP1_STAT_LED", // GPIO44
++ "FAN_PWM", // GPIO45
++ "CD1_IO0_MICCLK", // GPIO46
++ "2712_WAKE", // GPIO47
++ "CD1_IO1_MICDAT1", // GPIO48
++ "EN_MAX_USB_CUR", // GPIO49
++ "-", // GPIO50
++ "-", // GPIO51
++ "-", // GPIO52
++ "-"; // GPIO53
++
++ usb_vbus_pins: usb_vbus_pins {
++ function = "vbus1";
++ pins = "gpio42", "gpio43";
++ };
++};
++
++/ {
++ aliases: aliases {
++ blconfig = &blconfig;
++ blpubkey = &blpubkey;
++ bluetooth = &bluetooth;
++ console = &uart10;
++ ethernet0 = &rp1_eth;
++ wifi0 = &wifi;
++ fb = &fb;
++ mailbox = &mailbox;
++ mmc0 = &sdio1;
++ uart0 = &uart0;
++ uart1 = &uart1;
++ uart2 = &uart2;
++ uart3 = &uart3;
++ uart4 = &uart4;
++ uart10 = &uart10;
++ serial0 = &uart0;
++ serial1 = &uart1;
++ serial2 = &uart2;
++ serial3 = &uart3;
++ serial4 = &uart4;
++ serial10 = &uart10;
++ i2c = &i2c_arm;
++ i2c0 = &i2c0;
++ i2c1 = &i2c1;
++ i2c2 = &i2c2;
++ i2c3 = &i2c3;
++ i2c4 = &i2c4;
++ i2c5 = &i2c5;
++ i2c6 = &i2c6;
++ i2c10 = &i2c_rp1boot;
++ // Bit-bashed i2c_gpios start at 10
++ spi0 = &spi0;
++ spi1 = &spi1;
++ spi2 = &spi2;
++ spi3 = &spi3;
++ spi4 = &spi4;
++ spi5 = &spi5;
++ spi10 = &spi10;
++ gpio0 = &gpio;
++ gpio1 = &gio;
++ gpio2 = &gio_aon;
++ gpio3 = &pinctrl;
++ gpio4 = &pinctrl_aon;
++ usb0 = &rp1_usb0;
++ usb1 = &rp1_usb1;
++ drm-dsi1 = &dsi0;
++ drm-dsi2 = &dsi1;
++ };
++
++ __overrides__ {
++ bdaddr = <&bluetooth>, "local-bd-address[";
++ button_debounce = <&pwr_key>, "debounce-interval:0";
++ cooling_fan = <&fan>, "status", <&rp1_pwm1>, "status";
++ uart0_console = <&uart0>,"status", <&aliases>, "console=",&uart0;
++ i2c0 = <&i2c0>, "status";
++ i2c1 = <&i2c1>, "status";
++ i2c = <&i2c1>, "status";
++ i2c_arm = <&i2c_arm>, "status";
++ i2c_vc = <&i2c_vc>, "status";
++ i2c_csi_dsi = <&i2c_csi_dsi>, "status";
++ i2c_csi_dsi0 = <&i2c_csi_dsi0>, "status";
++ i2c_csi_dsi1 = <&i2c_csi_dsi1>, "status";
++ i2c0_baudrate = <&i2c0>, "clock-frequency:0";
++ i2c1_baudrate = <&i2c1>, "clock-frequency:0";
++ i2c_baudrate = <&i2c_arm>, "clock-frequency:0";
++ i2c_arm_baudrate = <&i2c_arm>, "clock-frequency:0";
++ i2c_vc_baudrate = <&i2c_vc>, "clock-frequency:0";
++ krnbt = <&bluetooth>, "status";
++ nvme = <&pciex1>, "status";
++ pciex1 = <&pciex1>, "status";
++ pciex1_gen = <&pciex1> , "max-link-speed:0";
++ pciex1_no_l0s = <&pciex1>, "aspm-no-l0s?";
++ pciex1_tperst_clk_ms = <&pciex1>, "brcm,tperst-clk-ms:0";
++ pcie_tperst_clk_ms = <&pciex1>, "brcm,tperst-clk-ms:0";
++ random = <&random>, "status";
++ rtc = <&rpi_rtc>, "status";
++ rtc_bbat_vchg = <&rpi_rtc>, "trickle-charge-microvolt:0";
++ sd_cqe = <&sdio1>, "supports-cqe?";
++ spi = <&spi0>, "status";
++ suspend = <&pwr_key>, "linux,code:0=205";
++ uart0 = <&uart0>, "status";
++ wifiaddr = <&wifi>, "local-mac-address[";
++
++ act_led_gpio = <&led_act>,"gpios:4",<&led_act>,"gpios:0=",<&gpio>;
++ act_led_activelow = <&led_act>,"gpios:8";
++ act_led_trigger = <&led_act>, "linux,default-trigger";
++ pwr_led_gpio = <&led_pwr>,"gpios:4";
++ pwr_led_activelow = <&led_pwr>, "gpios:8";
++ pwr_led_trigger = <&led_pwr>, "linux,default-trigger";
++ eth_led0 = <&phy1>,"led-modes:0";
++ eth_led1 = <&phy1>,"led-modes:4";
++ drm_fb0_rp1_dsi0 = <&aliases>, "drm-fb0=",&dsi0;
++ drm_fb0_rp1_dsi1 = <&aliases>, "drm-fb0=",&dsi1;
++ drm_fb0_rp1_dpi = <&aliases>, "drm-fb0=",&dpi;
++ drm_fb0_vc4 = <&aliases>, "drm-fb0=",&vc4;
++ drm_fb1_rp1_dsi0 = <&aliases>, "drm-fb1=",&dsi0;
++ drm_fb1_rp1_dsi1 = <&aliases>, "drm-fb1=",&dsi1;
++ drm_fb1_rp1_dpi = <&aliases>, "drm-fb1=",&dpi;
++ drm_fb1_vc4 = <&aliases>, "drm-fb1=",&vc4;
++ drm_fb2_rp1_dsi0 = <&aliases>, "drm-fb2=",&dsi0;
++ drm_fb2_rp1_dsi1 = <&aliases>, "drm-fb2=",&dsi1;
++ drm_fb2_rp1_dpi = <&aliases>, "drm-fb2=",&dpi;
++ drm_fb2_vc4 = <&aliases>, "drm-fb2=",&vc4;
++
++ fan_temp0 = <&cpu_tepid>,"temperature:0";
++ fan_temp1 = <&cpu_warm>,"temperature:0";
++ fan_temp2 = <&cpu_hot>,"temperature:0";
++ fan_temp3 = <&cpu_vhot>,"temperature:0";
++ fan_temp0_hyst = <&cpu_tepid>,"hysteresis:0";
++ fan_temp1_hyst = <&cpu_warm>,"hysteresis:0";
++ fan_temp2_hyst = <&cpu_hot>,"hysteresis:0";
++ fan_temp3_hyst = <&cpu_vhot>,"hysteresis:0";
++ fan_temp0_speed = <&fan>, "cooling-levels:4";
++ fan_temp1_speed = <&fan>, "cooling-levels:8";
++ fan_temp2_speed = <&fan>, "cooling-levels:12";
++ fan_temp3_speed = <&fan>, "cooling-levels:16";
++ };
++};
+--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5-cm4io.dts
++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5-cm4io.dts
+@@ -1,2 +1,20 @@
+ // SPDX-License-Identifier: GPL-2.0
+-#include "arm/broadcom/bcm2712-rpi-cm5-cm4io.dts"
++/dts-v1/;
++
++#include "bcm2712-rpi-cm5.dtsi"
++
++// The RP1 USB3 interfaces are not usable on CM4IO
++
++&rp1_usb0 {
++ status = "disabled";
++};
++
++&rp1_usb1 {
++ status = "disabled";
++};
++
++/ {
++ __overrides__ {
++ i2c_csi_dsi = <&i2c_csi_dsi>, "status";
++ };
++};
+--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5-cm5io.dts
++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5-cm5io.dts
+@@ -1,2 +1,10 @@
+ // SPDX-License-Identifier: GPL-2.0
+-#include "arm/broadcom/bcm2712-rpi-cm5-cm5io.dts"
++/dts-v1/;
++
++#include "bcm2712-rpi-cm5.dtsi"
++
++/ {
++ __overrides__ {
++ i2c_csi_dsi = <&i2c_csi_dsi>, "status";
++ };
++};
+--- a/arch/arm/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi
++++ /dev/null
+@@ -1,890 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0
+-
+-#include <dt-bindings/gpio/gpio.h>
+-#include <dt-bindings/clock/rp1.h>
+-#include <dt-bindings/interrupt-controller/irq.h>
+-#include <dt-bindings/mfd/rp1.h>
+-#include <dt-bindings/pwm/pwm.h>
+-#include <dt-bindings/reset/raspberrypi,firmware-reset.h>
+-
+-#define i2c0 _i2c0
+-#define i2c3 _i2c3
+-#define i2c4 _i2c4
+-#define i2c5 _i2c5
+-#define i2c6 _i2c6
+-#define i2c8 _i2c8
+-#define i2s _i2s
+-#define pwm0 _pwm0
+-#define pwm1 _pwm1
+-#define spi0 _spi0
+-#define spi3 _spi3
+-#define spi4 _spi4
+-#define spi5 _spi5
+-#define spi6 _spi6
+-#define uart0 _uart0
+-#define uart2 _uart2
+-#define uart5 _uart5
+-
+-#include "bcm2712.dtsi"
+-
+-#undef i2c0
+-#undef i2c3
+-#undef i2c4
+-#undef i2c5
+-#undef i2c6
+-#undef i2c8
+-#undef i2s
+-#undef pwm0
+-#undef pwm1
+-#undef spi0
+-#undef spi3
+-#undef spi4
+-#undef spi5
+-#undef spi6
+-#undef uart0
+-#undef uart2
+-#undef uart3
+-#undef uart4
+-#undef uart5
+-
+-/ {
+- compatible = "raspberrypi,5-compute-module", "brcm,bcm2712";
+- model = "Raspberry Pi Compute Module 5";
+-
+- /* Will be filled by the bootloader */
+- memory@0 {
+- device_type = "memory";
+- reg = <0 0 0x28000000>;
+- };
+-
+- leds: leds {
+- compatible = "gpio-leds";
+-
+- led_pwr: led-pwr {
+- label = "PWR";
+- gpios = <&rp1_gpio 44 GPIO_ACTIVE_LOW>;
+- default-state = "off";
+- linux,default-trigger = "none";
+- };
+-
+- led_act: led-act {
+- label = "ACT";
+- gpios = <&gio_aon 9 GPIO_ACTIVE_LOW>;
+- default-state = "off";
+- linux,default-trigger = "mmc0";
+- };
+- };
+-
+- sd_io_1v8_reg: sd_io_1v8_reg {
+- compatible = "regulator-gpio";
+- regulator-name = "vdd-sd-io";
+- regulator-min-microvolt = <1800000>;
+- regulator-max-microvolt = <3300000>;
+- regulator-boot-on;
+- regulator-always-on;
+- regulator-settling-time-us = <5000>;
+- gpios = <&gio_aon 3 GPIO_ACTIVE_HIGH>;
+- states = <1800000 0x1
+- 3300000 0x0>;
+- status = "okay";
+- };
+-
+- sd_vcc_reg: sd_vcc_reg {
+- compatible = "regulator-fixed";
+- regulator-name = "vcc-sd";
+- regulator-min-microvolt = <3300000>;
+- regulator-max-microvolt = <3300000>;
+- regulator-boot-on;
+- enable-active-high;
+- gpios = <&gio_aon 4 GPIO_ACTIVE_HIGH>;
+- status = "okay";
+- };
+-
+- wl_on_reg: wl_on_reg {
+- compatible = "regulator-fixed";
+- regulator-name = "wl-on-regulator";
+- regulator-min-microvolt = <3300000>;
+- regulator-max-microvolt = <3300000>;
+- pinctrl-0 = <&wl_on_pins>;
+- pinctrl-names = "default";
+-
+- gpio = <&gio 28 GPIO_ACTIVE_HIGH>;
+-
+- startup-delay-us = <150000>;
+- enable-active-high;
+- };
+-
+- clocks: clocks {
+- };
+-
+- cam1_clk: cam1_clk {
+- compatible = "fixed-clock";
+- #clock-cells = <0>;
+- status = "disabled";
+- };
+-
+- cam0_clk: cam0_clk {
+- compatible = "fixed-clock";
+- #clock-cells = <0>;
+- status = "disabled";
+- };
+-
+- cam0_reg: cam0_reg {
+- compatible = "regulator-fixed";
+- regulator-name = "cam0_reg";
+- enable-active-high;
+- status = "okay";
+- gpio = <&rp1_gpio 34 0>; // CD0_IO0_MICCLK, to CAM_GPIO on connector
+- };
+-
+- cam_dummy_reg: cam_dummy_reg {
+- compatible = "regulator-fixed";
+- regulator-name = "cam-dummy-reg";
+- status = "okay";
+- };
+-
+- dummy: dummy {
+- // A target for unwanted overlay fragments
+- };
+-
+-
+- // A few extra labels to keep overlays happy
+-
+- i2c0if: i2c0if {};
+- i2c0mux: i2c0mux {};
+-};
+-
+-rp1_target: &pcie2 {
+- brcm,enable-mps-rcb;
+- brcm,vdm-qos-map = <0xbbaa9888>;
+- aspm-no-l0s;
+- status = "okay";
+-};
+-
+-// Add some labels to 2712 device
+-
+-// The system UART
+-uart10: &_uart0 { status = "okay"; };
+-
+-// The system SPI for the bootloader EEPROM
+-spi10: &_spi0 { status = "okay"; };
+-
+-i2c_rp1boot: &_i2c3 { };
+-
+-#include "rp1.dtsi"
+-
+-&rp1 {
+- // PCIe address space layout:
+- // 00_00000000-00_00xxxxxx = RP1 peripherals
+- // 10_00000000-1x_xxxxxxxx = up to 64GB system RAM
+-
+- // outbound access aimed at PCIe 0_00xxxxxx -> RP1 c0_40xxxxxx
+- // This is the RP1 peripheral space
+- ranges = <0xc0 0x40000000
+- 0x02000000 0x00 0x00000000
+- 0x00 0x00400000>;
+-
+- dma-ranges =
+- // inbound RP1 1x_xxxxxxxx -> PCIe 1x_xxxxxxxx
+- <0x10 0x00000000
+- 0x43000000 0x10 0x00000000
+- 0x10 0x00000000>,
+-
+- // inbound RP1 c0_40xxxxxx -> PCIe 00_00xxxxxx
+- // This allows the RP1 DMA controller to address RP1 hardware
+- <0xc0 0x40000000
+- 0x02000000 0x0 0x00000000
+- 0x0 0x00400000>,
+-
+- // inbound RP1 0x_xxxxxxxx -> PCIe 1x_xxxxxxxx
+- <0x00 0x00000000
+- 0x02000000 0x10 0x00000000
+- 0x10 0x00000000>;
+-};
+-
+-// Expose RP1 nodes as system nodes with labels
+-
+-&rp1_dma {
+- status = "okay";
+-};
+-
+-&rp1_eth {
+- status = "okay";
+- phy-handle = <&phy1>;
+- phy-reset-gpios = <&rp1_gpio 32 GPIO_ACTIVE_LOW>;
+- phy-reset-duration = <5>;
+-
+- phy1: ethernet-phy@1 {
+- reg = <0x1>;
+- brcm,powerdown-enable;
+- interrupt-parent = <&gpio>;
+- interrupts = <37 IRQ_TYPE_LEVEL_LOW>;
+- };
+-};
+-
+-gpio: &rp1_gpio {
+- status = "okay";
+-};
+-
+-aux: &dummy {};
+-
+-&rp1_usb0 {
+- pinctrl-0 = <&usb_vbus_pins>;
+- pinctrl-names = "default";
+- status = "okay";
+-};
+-
+-&rp1_usb1 {
+- status = "okay";
+-};
+-
+-#include "bcm2712-rpi.dtsi"
+-
+-i2c_csi_dsi0: &i2c6 { // Note: This is for MIPI0 connector only
+- pinctrl-0 = <&rp1_i2c6_38_39>;
+- pinctrl-names = "default";
+- clock-frequency = <100000>;
+-};
+-
+-i2c_csi_dsi1: &i2c0 { // Note: This is for MIPI1 connector
+-};
+-
+-i2c_csi_dsi: &i2c_csi_dsi1 { }; // An alias for compatibility
+-
+-cam1_reg: &cam0_reg { // Shares CAM_GPIO with cam0_reg
+-};
+-
+-csi0: &rp1_csi0 { };
+-csi1: &rp1_csi1 { };
+-dsi0: &rp1_dsi0 { };
+-dsi1: &rp1_dsi1 { };
+-dpi: &rp1_dpi { };
+-vec: &rp1_vec { };
+-dpi_gpio0: &rp1_dpi_24bit_gpio0 { };
+-dpi_gpio1: &rp1_dpi_24bit_gpio2 { };
+-dpi_18bit_cpadhi_gpio0: &rp1_dpi_18bit_cpadhi_gpio0 { };
+-dpi_18bit_cpadhi_gpio2: &rp1_dpi_18bit_cpadhi_gpio2 { };
+-dpi_18bit_gpio0: &rp1_dpi_18bit_gpio0 { };
+-dpi_18bit_gpio2: &rp1_dpi_18bit_gpio2 { };
+-dpi_16bit_cpadhi_gpio0: &rp1_dpi_16bit_cpadhi_gpio0 { };
+-dpi_16bit_cpadhi_gpio2: &rp1_dpi_16bit_cpadhi_gpio2 { };
+-dpi_16bit_gpio0: &rp1_dpi_16bit_gpio0 { };
+-dpi_16bit_gpio2: &rp1_dpi_16bit_gpio2 { };
+-
+-/* Add the IOMMUs for some RP1 bus masters */
+-
+-&csi0 {
+- iommus = <&iommu5>;
+-};
+-
+-&csi1 {
+- iommus = <&iommu5>;
+-};
+-
+-&dsi0 {
+- iommus = <&iommu5>;
+-};
+-
+-&dsi1 {
+- iommus = <&iommu5>;
+-};
+-
+-&dpi {
+- iommus = <&iommu5>;
+-};
+-
+-&vec {
+- iommus = <&iommu5>;
+-};
+-
+-&ddc0 {
+- status = "disabled";
+-};
+-
+-&ddc1 {
+- status = "disabled";
+-};
+-
+-&hdmi0 {
+- clocks = <&firmware_clocks 13>, <&firmware_clocks 14>, <&dvp 0>, <&clk_27MHz>;
+- clock-names = "hdmi", "bvb", "audio", "cec";
+- status = "disabled";
+-};
+-
+-&hdmi1 {
+- clocks = <&firmware_clocks 13>, <&firmware_clocks 14>, <&dvp 1>, <&clk_27MHz>;
+- clock-names = "hdmi", "bvb", "audio", "cec";
+- status = "disabled";
+-};
+-
+-&hvs {
+- clocks = <&firmware_clocks 4>, <&firmware_clocks 16>;
+- clock-names = "core", "disp";
+-};
+-
+-&mop {
+- status = "disabled";
+-};
+-
+-&moplet {
+- status = "disabled";
+-};
+-
+-&pixelvalve0 {
+- status = "disabled";
+-};
+-
+-&pixelvalve1 {
+- status = "disabled";
+-};
+-
+-&disp_intr {
+- status = "disabled";
+-};
+-
+-/* SDIO1 is used to drive the eMMC/SD card */
+-&sdio1 {
+- pinctrl-0 = <&emmc_cmddat_pulls>, <&emmc_ds_pull>;
+- pinctrl-names = "default";
+- vqmmc-supply = <&sd_io_1v8_reg>;
+- vmmc-supply = <&sd_vcc_reg>;
+- bus-width = <8>;
+- sd-uhs-sdr50;
+- sd-uhs-ddr50;
+- sd-uhs-sdr104;
+- mmc-hs200-1_8v;
+- mmc-hs400-1_8v;
+- mmc-hs400-enhanced-strobe;
+- broken-cd;
+- supports-cqe;
+- status = "okay";
+-};
+-
+-&pinctrl_aon {
+- ant_pins: ant_pins {
+- function = "gpio";
+- pins = "aon_gpio5", "aon_gpio6";
+- };
+-
+- /* Slight hack - only one PWM pin (status LED) is usable */
+- aon_pwm_1pin: aon_pwm_1pin {
+- function = "aon_pwm";
+- pins = "aon_gpio9";
+- };
+-};
+-
+-&pinctrl {
+- pwr_button_pins: pwr_button_pins {
+- function = "gpio";
+- pins = "gpio20";
+- bias-pull-up;
+- };
+-
+- wl_on_pins: wl_on_pins {
+- function = "gpio";
+- pins = "gpio28";
+- };
+-
+- bt_shutdown_pins: bt_shutdown_pins {
+- function = "gpio";
+- pins = "gpio29";
+- };
+-
+- emmc_ds_pull: emmc_ds_pull {
+- pins = "emmc_ds";
+- bias-pull-down;
+- };
+-
+- emmc_cmddat_pulls: emmc_cmddat_pulls {
+- pins = "emmc_cmd", "emmc_dat0", "emmc_dat1", "emmc_dat2", "emmc_dat3",
+- "emmc_dat4", "emmc_dat5", "emmc_dat6", "emmc_dat7";
+- bias-pull-up;
+- };
+-};
+-
+-/* uarta communicates with the BT module */
+-&uarta {
+- uart-has-rtscts;
+- auto-flow-control;
+- status = "okay";
+- clock-frequency = <96000000>;
+- pinctrl-0 = <&uarta_24_pins &bt_shutdown_pins>;
+- pinctrl-names = "default";
+-
+- bluetooth: bluetooth {
+- compatible = "brcm,bcm43438-bt";
+- max-speed = <3000000>;
+- shutdown-gpios = <&gio 29 GPIO_ACTIVE_HIGH>;
+- local-bd-address = [ 00 00 00 00 00 00 ];
+- };
+-};
+-
+-&i2c_rp1boot {
+- clock-frequency = <400000>;
+- pinctrl-0 = <&i2c3_m4_agpio0_pins>;
+- pinctrl-names = "default";
+-};
+-
+-/ {
+- chosen: chosen {
+- bootargs = "reboot=w coherent_pool=1M 8250.nr_uarts=1 pci=pcie_bus_safe";
+- stdout-path = "serial10:115200n8";
+- };
+-
+- fan: cooling_fan {
+- status = "disabled";
+- compatible = "pwm-fan";
+- #cooling-cells = <2>;
+- cooling-min-state = <0>;
+- cooling-max-state = <3>;
+- cooling-levels = <0 75 125 175 250>;
+- pwms = <&rp1_pwm1 3 41566 PWM_POLARITY_INVERTED>;
+- rpm-regmap = <&rp1_pwm1>;
+- rpm-offset = <0x3c>;
+- };
+-
+- pwr_button {
+- compatible = "gpio-keys";
+-
+- pinctrl-names = "default";
+- pinctrl-0 = <&pwr_button_pins>;
+- status = "okay";
+-
+- pwr_key: pwr {
+- label = "pwr_button";
+- // linux,code = <205>; // KEY_SUSPEND
+- linux,code = <116>; // KEY_POWER
+- gpios = <&gio 20 GPIO_ACTIVE_LOW>;
+- debounce-interval = <50>; // ms
+- };
+- };
+-};
+-
+-&usb {
+- power-domains = <&power RPI_POWER_DOMAIN_USB>;
+-};
+-
+-/* SDIO2 drives the WLAN interface */
+-&sdio2 {
+- pinctrl-0 = <&sdio2_30_pins>, <&ant_pins>;
+- pinctrl-names = "default";
+- bus-width = <4>;
+- vmmc-supply = <&wl_on_reg>;
+- sd-uhs-ddr50;
+- non-removable;
+- status = "okay";
+- #address-cells = <1>;
+- #size-cells = <0>;
+-
+- wifi: wifi@1 {
+- reg = <1>;
+- compatible = "brcm,bcm4329-fmac";
+- local-mac-address = [00 00 00 00 00 00];
+- };
+-};
+-
+-&rpivid {
+- status = "okay";
+-};
+-
+-&pinctrl {
+- spi10_gpio2: spi10_gpio2 {
+- function = "vc_spi0";
+- pins = "gpio2", "gpio3", "gpio4";
+- bias-disable;
+- };
+-
+- spi10_cs_gpio1: spi10_cs_gpio1 {
+- function = "gpio";
+- pins = "gpio1";
+- bias-pull-up;
+- };
+-};
+-
+-spi10_pins: &spi10_gpio2 {};
+-spi10_cs_pins: &spi10_cs_gpio1 {};
+-
+-&spi10 {
+- pinctrl-names = "default";
+- cs-gpios = <&gio 1 1>;
+- pinctrl-0 = <&spi10_pins &spi10_cs_pins>;
+-
+- spidev10: spidev@0 {
+- compatible = "spidev";
+- reg = <0>; /* CE0 */
+- #address-cells = <1>;
+- #size-cells = <0>;
+- spi-max-frequency = <20000000>;
+- status = "okay";
+- };
+-};
+-
+-// =============================================
+-// Board specific stuff here
+-
+-&gio_aon {
+- // Don't use GIO_AON as an interrupt controller because it will
+- // clash with the firmware monitoring the PMIC interrupt via the VPU.
+-
+- /delete-property/ interrupt-controller;
+-};
+-
+-&main_aon_irq {
+- // Don't use the MAIN_AON_IRQ interrupt controller because it will
+- // clash with the firmware monitoring the PMIC interrupt via the VPU.
+-
+- status = "disabled";
+-};
+-
+-&rp1_pwm1 {
+- status = "disabled";
+- pinctrl-0 = <&rp1_pwm1_gpio45>;
+- pinctrl-names = "default";
+-};
+-
+-&thermal_trips {
+- cpu_tepid: cpu-tepid {
+- temperature = <50000>;
+- hysteresis = <5000>;
+- type = "active";
+- };
+-
+- cpu_warm: cpu-warm {
+- temperature = <60000>;
+- hysteresis = <5000>;
+- type = "active";
+- };
+-
+- cpu_hot: cpu-hot {
+- temperature = <67500>;
+- hysteresis = <5000>;
+- type = "active";
+- };
+-
+- cpu_vhot: cpu-vhot {
+- temperature = <75000>;
+- hysteresis = <5000>;
+- type = "active";
+- };
+-};
+-
+-&cooling_maps {
+- tepid {
+- trip = <&cpu_tepid>;
+- cooling-device = <&fan 1 1>;
+- };
+-
+- warm {
+- trip = <&cpu_warm>;
+- cooling-device = <&fan 2 2>;
+- };
+-
+- hot {
+- trip = <&cpu_hot>;
+- cooling-device = <&fan 3 3>;
+- };
+-
+- vhot {
+- trip = <&cpu_vhot>;
+- cooling-device = <&fan 4 4>;
+- };
+-
+- melt {
+- trip = <&cpu_crit>;
+- cooling-device = <&fan 4 4>;
+- };
+-};
+-
+-&gio {
+- // The GPIOs above 35 are not used on Pi 5, so shrink the upper bank
+- // to reduce the clutter in gpioinfo/pinctrl
+- brcm,gpio-bank-widths = <32 4>;
+-
+- gpio-line-names =
+- "-", // GPIO_000
+- "2712_BOOT_CS_N", // GPIO_001
+- "2712_BOOT_MISO", // GPIO_002
+- "2712_BOOT_MOSI", // GPIO_003
+- "2712_BOOT_SCLK", // GPIO_004
+- "-", // GPIO_005
+- "-", // GPIO_006
+- "-", // GPIO_007
+- "-", // GPIO_008
+- "-", // GPIO_009
+- "-", // GPIO_010
+- "-", // GPIO_011
+- "-", // GPIO_012
+- "-", // GPIO_013
+- "-", // GPIO_014
+- "-", // GPIO_015
+- "-", // GPIO_016
+- "-", // GPIO_017
+- "-", // GPIO_018
+- "-", // GPIO_019
+- "PWR_GPIO", // GPIO_020
+- "2712_G21_FS", // GPIO_021
+- "-", // GPIO_022
+- "-", // GPIO_023
+- "BT_RTS", // GPIO_024
+- "BT_CTS", // GPIO_025
+- "BT_TXD", // GPIO_026
+- "BT_RXD", // GPIO_027
+- "WL_ON", // GPIO_028
+- "BT_ON", // GPIO_029
+- "WIFI_SDIO_CLK", // GPIO_030
+- "WIFI_SDIO_CMD", // GPIO_031
+- "WIFI_SDIO_D0", // GPIO_032
+- "WIFI_SDIO_D1", // GPIO_033
+- "WIFI_SDIO_D2", // GPIO_034
+- "WIFI_SDIO_D3"; // GPIO_035
+-};
+-
+-&gio_aon {
+- gpio-line-names =
+- "RP1_SDA", // AON_GPIO_00
+- "RP1_SCL", // AON_GPIO_01
+- "RP1_RUN", // AON_GPIO_02
+- "SD_IOVDD_SEL", // AON_GPIO_03
+- "SD_PWR_ON", // AON_GPIO_04
+- "ANT1", // AON_GPIO_05
+- "ANT2", // AON_GPIO_06
+- "-", // AON_GPIO_07
+- "2712_WAKE", // AON_GPIO_08
+- "2712_STAT_LED", // AON_GPIO_09
+- "-", // AON_GPIO_10
+- "-", // AON_GPIO_11
+- "PMIC_INT", // AON_GPIO_12
+- "UART_TX_FS", // AON_GPIO_13
+- "UART_RX_FS", // AON_GPIO_14
+- "-", // AON_GPIO_15
+- "-", // AON_GPIO_16
+-
+- // Pad bank0 out to 32 entries
+- "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
+-
+- "HDMI0_SCL", // AON_SGPIO_00
+- "HDMI0_SDA", // AON_SGPIO_01
+- "HDMI1_SCL", // AON_SGPIO_02
+- "HDMI1_SDA", // AON_SGPIO_03
+- "PMIC_SCL", // AON_SGPIO_04
+- "PMIC_SDA"; // AON_SGPIO_05
+-
+- rp1_run_hog {
+- gpio-hog;
+- gpios = <2 GPIO_ACTIVE_HIGH>;
+- output-high;
+- line-name = "RP1 RUN pin";
+- };
+-
+- ant1: ant1-hog {
+- gpio-hog;
+- gpios = <5 GPIO_ACTIVE_HIGH>;
+- /* internal antenna enabled */
+- output-high;
+- line-name = "ant1";
+- };
+-
+- ant2: ant2-hog {
+- gpio-hog;
+- gpios = <6 GPIO_ACTIVE_HIGH>;
+- /* external antenna disabled */
+- output-low;
+- line-name = "ant2";
+- };
+-};
+-
+-&rp1_gpio {
+- gpio-line-names =
+- "ID_SDA", // GPIO0
+- "ID_SCL", // GPIO1
+- "GPIO2", // GPIO2
+- "GPIO3", // GPIO3
+- "GPIO4", // GPIO4
+- "GPIO5", // GPIO5
+- "GPIO6", // GPIO6
+- "GPIO7", // GPIO7
+- "GPIO8", // GPIO8
+- "GPIO9", // GPIO9
+- "GPIO10", // GPIO10
+- "GPIO11", // GPIO11
+- "GPIO12", // GPIO12
+- "GPIO13", // GPIO13
+- "GPIO14", // GPIO14
+- "GPIO15", // GPIO15
+- "GPIO16", // GPIO16
+- "GPIO17", // GPIO17
+- "GPIO18", // GPIO18
+- "GPIO19", // GPIO19
+- "GPIO20", // GPIO20
+- "GPIO21", // GPIO21
+- "GPIO22", // GPIO22
+- "GPIO23", // GPIO23
+- "GPIO24", // GPIO24
+- "GPIO25", // GPIO25
+- "GPIO26", // GPIO26
+- "GPIO27", // GPIO27
+-
+- "PCIE_PWR_EN", // GPIO28
+- "FAN_TACH", // GPIO29
+- "HOST_SDA", // GPIO30
+- "HOST_SCL", // GPIO31
+- "ETH_RST_N", // GPIO32
+- "PCIE_DET_WAKE", // GPIO33
+-
+- "CD0_IO0_MICCLK", // GPIO34
+- "CD0_IO0_MICDAT0", // GPIO35
+- "RP1_PCIE_CLKREQ_N", // GPIO36
+- "ETH_IRQ_N", // GPIO37
+- "SDA0", // GPIO38
+- "SCL0", // GPIO39
+- "-", // GPIO40
+- "-", // GPIO41
+- "USB_VBUS_EN", // GPIO42
+- "USB_OC_N", // GPIO43
+- "RP1_STAT_LED", // GPIO44
+- "FAN_PWM", // GPIO45
+- "-", // GPIO46
+- "2712_WAKE", // GPIO47
+- "-", // GPIO48
+- "-", // GPIO49
+- "-", // GPIO50
+- "-", // GPIO51
+- "-", // GPIO52
+- "-"; // GPIO53
+-
+- usb_vbus_pins: usb_vbus_pins {
+- function = "vbus1";
+- pins = "gpio42", "gpio43";
+- };
+-};
+-
+-/ {
+- aliases: aliases {
+- blconfig = &blconfig;
+- blpubkey = &blpubkey;
+- bluetooth = &bluetooth;
+- console = &uart10;
+- ethernet0 = &rp1_eth;
+- wifi0 = &wifi;
+- fb = &fb;
+- mailbox = &mailbox;
+- mmc0 = &sdio1;
+- uart0 = &uart0;
+- uart1 = &uart1;
+- uart2 = &uart2;
+- uart3 = &uart3;
+- uart4 = &uart4;
+- uart10 = &uart10;
+- serial0 = &uart0;
+- serial1 = &uart1;
+- serial2 = &uart2;
+- serial3 = &uart3;
+- serial4 = &uart4;
+- serial10 = &uart10;
+- i2c = &i2c_arm;
+- i2c0 = &i2c0;
+- i2c1 = &i2c1;
+- i2c2 = &i2c2;
+- i2c3 = &i2c3;
+- i2c4 = &i2c4;
+- i2c5 = &i2c5;
+- i2c6 = &i2c6;
+- i2c10 = &i2c_rp1boot;
+- // Bit-bashed i2c_gpios start at 10
+- spi0 = &spi0;
+- spi1 = &spi1;
+- spi2 = &spi2;
+- spi3 = &spi3;
+- spi4 = &spi4;
+- spi5 = &spi5;
+- spi10 = &spi10;
+- gpio0 = &gpio;
+- gpio1 = &gio;
+- gpio2 = &gio_aon;
+- gpio3 = &pinctrl;
+- gpio4 = &pinctrl_aon;
+- usb0 = &rp1_usb0;
+- usb1 = &rp1_usb1;
+- drm-dsi1 = &dsi0;
+- drm-dsi2 = &dsi1;
+- };
+-
+- __overrides__ {
+- bdaddr = <&bluetooth>, "local-bd-address[";
+- button_debounce = <&pwr_key>, "debounce-interval:0";
+- cooling_fan = <&fan>, "status", <&rp1_pwm1>, "status";
+- uart0_console = <&uart0>,"status", <&aliases>, "console=",&uart0;
+- i2c0 = <&i2c0>, "status";
+- i2c1 = <&i2c1>, "status";
+- i2c = <&i2c1>, "status";
+- i2c_arm = <&i2c_arm>, "status";
+- i2c_vc = <&i2c_vc>, "status";
+- i2c_csi_dsi = <&i2c_csi_dsi>, "status";
+- i2c_csi_dsi0 = <&i2c_csi_dsi0>, "status";
+- i2c_csi_dsi1 = <&i2c_csi_dsi1>, "status";
+- i2c0_baudrate = <&i2c0>, "clock-frequency:0";
+- i2c1_baudrate = <&i2c1>, "clock-frequency:0";
+- i2c_baudrate = <&i2c_arm>, "clock-frequency:0";
+- i2c_arm_baudrate = <&i2c_arm>, "clock-frequency:0";
+- i2c_vc_baudrate = <&i2c_vc>, "clock-frequency:0";
+- krnbt = <&bluetooth>, "status";
+- nvme = <&pciex1>, "status";
+- pciex1 = <&pciex1>, "status";
+- pciex1_gen = <&pciex1> , "max-link-speed:0";
+- pciex1_no_l0s = <&pciex1>, "aspm-no-l0s?";
+- pciex1_tperst_clk_ms = <&pciex1>, "brcm,tperst-clk-ms:0";
+- pcie_tperst_clk_ms = <&pciex1>, "brcm,tperst-clk-ms:0";
+- random = <&random>, "status";
+- rtc = <&rpi_rtc>, "status";
+- rtc_bbat_vchg = <&rpi_rtc>, "trickle-charge-microvolt:0";
+- spi = <&spi0>, "status";
+- suspend = <&pwr_key>, "linux,code:0=205";
+- uart0 = <&uart0>, "status";
+- wifiaddr = <&wifi>, "local-mac-address[";
+-
+- act_led_activelow = <&led_act>, "active-low?";
+- act_led_trigger = <&led_act>, "linux,default-trigger";
+- pwr_led_activelow = <&led_pwr>, "gpios:8";
+- pwr_led_trigger = <&led_pwr>, "linux,default-trigger";
+- eth_led0 = <&phy1>,"led-modes:0";
+- eth_led1 = <&phy1>,"led-modes:4";
+- drm_fb0_rp1_dsi0 = <&aliases>, "drm-fb0=",&dsi0;
+- drm_fb0_rp1_dsi1 = <&aliases>, "drm-fb0=",&dsi1;
+- drm_fb0_rp1_dpi = <&aliases>, "drm-fb0=",&dpi;
+- drm_fb0_vc4 = <&aliases>, "drm-fb0=",&vc4;
+- drm_fb1_rp1_dsi0 = <&aliases>, "drm-fb1=",&dsi0;
+- drm_fb1_rp1_dsi1 = <&aliases>, "drm-fb1=",&dsi1;
+- drm_fb1_rp1_dpi = <&aliases>, "drm-fb1=",&dpi;
+- drm_fb1_vc4 = <&aliases>, "drm-fb1=",&vc4;
+- drm_fb2_rp1_dsi0 = <&aliases>, "drm-fb2=",&dsi0;
+- drm_fb2_rp1_dsi1 = <&aliases>, "drm-fb2=",&dsi1;
+- drm_fb2_rp1_dpi = <&aliases>, "drm-fb2=",&dpi;
+- drm_fb2_vc4 = <&aliases>, "drm-fb2=",&vc4;
+-
+- ant1 = <&ant1>,"output-high?=on",
+- <&ant1>, "output-low?=off",
+- <&ant2>, "output-high?=off",
+- <&ant2>, "output-low?=on";
+- ant2 = <&ant1>,"output-high?=off",
+- <&ant1>, "output-low?=on",
+- <&ant2>, "output-high?=on",
+- <&ant2>, "output-low?=off";
+- noant = <&ant1>,"output-high?=off",
+- <&ant1>, "output-low?=on",
+- <&ant2>, "output-high?=off",
+- <&ant2>, "output-low?=on";
+-
+- fan_temp0 = <&cpu_tepid>,"temperature:0";
+- fan_temp1 = <&cpu_warm>,"temperature:0";
+- fan_temp2 = <&cpu_hot>,"temperature:0";
+- fan_temp3 = <&cpu_vhot>,"temperature:0";
+- fan_temp0_hyst = <&cpu_tepid>,"hysteresis:0";
+- fan_temp1_hyst = <&cpu_warm>,"hysteresis:0";
+- fan_temp2_hyst = <&cpu_hot>,"hysteresis:0";
+- fan_temp3_hyst = <&cpu_vhot>,"hysteresis:0";
+- fan_temp0_speed = <&fan>, "cooling-levels:4";
+- fan_temp1_speed = <&fan>, "cooling-levels:8";
+- fan_temp2_speed = <&fan>, "cooling-levels:12";
+- fan_temp3_speed = <&fan>, "cooling-levels:16";
+- };
+-};
+--- /dev/null
++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi
+@@ -0,0 +1,884 @@
++// SPDX-License-Identifier: GPL-2.0
++
++#include <dt-bindings/gpio/gpio.h>
++#include <dt-bindings/clock/rp1.h>
++#include <dt-bindings/interrupt-controller/irq.h>
++#include <dt-bindings/mfd/rp1.h>
++#include <dt-bindings/pwm/pwm.h>
++#include <dt-bindings/reset/raspberrypi,firmware-reset.h>
++
++#define i2c0 _i2c0
++#define i2c3 _i2c3
++#define i2c4 _i2c4
++#define i2c5 _i2c5
++#define i2c6 _i2c6
++#define i2c8 _i2c8
++#define i2s _i2s
++#define pwm0 _pwm0
++#define pwm1 _pwm1
++#define spi0 _spi0
++#define spi3 _spi3
++#define spi4 _spi4
++#define spi5 _spi5
++#define spi6 _spi6
++#define uart0 _uart0
++#define uart2 _uart2
++#define uart5 _uart5
++
++#include "bcm2712.dtsi"
++
++#undef i2c0
++#undef i2c3
++#undef i2c4
++#undef i2c5
++#undef i2c6
++#undef i2c8
++#undef i2s
++#undef pwm0
++#undef pwm1
++#undef spi0
++#undef spi3
++#undef spi4
++#undef spi5
++#undef spi6
++#undef uart0
++#undef uart2
++#undef uart3
++#undef uart4
++#undef uart5
++
++/ {
++ compatible = "raspberrypi,5-compute-module", "brcm,bcm2712";
++ model = "Raspberry Pi Compute Module 5";
++
++ /* Will be filled by the bootloader */
++ memory@0 {
++ device_type = "memory";
++ reg = <0 0 0x28000000>;
++ };
++
++ leds: leds {
++ compatible = "gpio-leds";
++
++ led_pwr: led-pwr {
++ label = "PWR";
++ gpios = <&rp1_gpio 44 GPIO_ACTIVE_LOW>;
++ default-state = "off";
++ linux,default-trigger = "none";
++ };
++
++ led_act: led-act {
++ label = "ACT";
++ gpios = <&gio_aon 9 GPIO_ACTIVE_LOW>;
++ default-state = "off";
++ linux,default-trigger = "mmc0";
++ };
++ };
++
++ sd_io_1v8_reg: sd_io_1v8_reg {
++ compatible = "regulator-fixed";
++ regulator-name = "vdd-sd-io";
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ regulator-always-on;
++ };
++
++ sd_vcc_reg: sd_vcc_reg {
++ compatible = "regulator-fixed";
++ regulator-name = "vcc-sd";
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ regulator-boot-on;
++ enable-active-high;
++ gpios = <&gio_aon 4 GPIO_ACTIVE_HIGH>;
++ status = "okay";
++ };
++
++ wl_on_reg: wl_on_reg {
++ compatible = "regulator-fixed";
++ regulator-name = "wl-on-regulator";
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ pinctrl-0 = <&wl_on_pins>;
++ pinctrl-names = "default";
++
++ gpio = <&gio 28 GPIO_ACTIVE_HIGH>;
++
++ startup-delay-us = <150000>;
++ enable-active-high;
++ };
++
++ clocks: clocks {
++ };
++
++ cam1_clk: cam1_clk {
++ compatible = "fixed-clock";
++ #clock-cells = <0>;
++ status = "disabled";
++ };
++
++ cam0_clk: cam0_clk {
++ compatible = "fixed-clock";
++ #clock-cells = <0>;
++ status = "disabled";
++ };
++
++ cam0_reg: cam0_reg {
++ compatible = "regulator-fixed";
++ regulator-name = "cam0_reg";
++ enable-active-high;
++ status = "okay";
++ gpio = <&rp1_gpio 34 0>; // CD0_IO0_MICCLK, to CAM_GPIO on connector
++ };
++
++ cam_dummy_reg: cam_dummy_reg {
++ compatible = "regulator-fixed";
++ regulator-name = "cam-dummy-reg";
++ status = "okay";
++ };
++
++ dummy: dummy {
++ // A target for unwanted overlay fragments
++ };
++
++
++ // A few extra labels to keep overlays happy
++
++ i2c0if: i2c0if {};
++ i2c0mux: i2c0mux {};
++};
++
++rp1_target: &pcie2 {
++ brcm,enable-mps-rcb;
++ brcm,vdm-qos-map = <0xbbaa9888>;
++ aspm-no-l0s;
++ status = "okay";
++};
++
++// Add some labels to 2712 device
++
++// The system UART
++uart10: &_uart0 { status = "okay"; };
++
++// The system SPI for the bootloader EEPROM
++spi10: &_spi0 { status = "okay"; };
++
++i2c_rp1boot: &_i2c3 { };
++
++#include "rp1.dtsi"
++
++&rp1 {
++ // PCIe address space layout:
++ // 00_00000000-00_00xxxxxx = RP1 peripherals
++ // 10_00000000-1x_xxxxxxxx = up to 64GB system RAM
++
++ // outbound access aimed at PCIe 0_00xxxxxx -> RP1 c0_40xxxxxx
++ // This is the RP1 peripheral space
++ ranges = <0xc0 0x40000000
++ 0x02000000 0x00 0x00000000
++ 0x00 0x00400000>;
++
++ dma-ranges =
++ // inbound RP1 1x_xxxxxxxx -> PCIe 1x_xxxxxxxx
++ <0x10 0x00000000
++ 0x43000000 0x10 0x00000000
++ 0x10 0x00000000>,
++
++ // inbound RP1 c0_40xxxxxx -> PCIe 00_00xxxxxx
++ // This allows the RP1 DMA controller to address RP1 hardware
++ <0xc0 0x40000000
++ 0x02000000 0x0 0x00000000
++ 0x0 0x00400000>,
++
++ // inbound RP1 0x_xxxxxxxx -> PCIe 1x_xxxxxxxx
++ <0x00 0x00000000
++ 0x02000000 0x10 0x00000000
++ 0x10 0x00000000>;
++};
++
++// Expose RP1 nodes as system nodes with labels
++
++&rp1_dma {
++ status = "okay";
++};
++
++&rp1_eth {
++ status = "okay";
++ phy-handle = <&phy1>;
++ phy-reset-gpios = <&rp1_gpio 32 GPIO_ACTIVE_LOW>;
++ phy-reset-duration = <5>;
++
++ phy1: ethernet-phy@1 {
++ reg = <0x1>;
++ brcm,powerdown-enable;
++ interrupt-parent = <&gpio>;
++ interrupts = <37 IRQ_TYPE_LEVEL_LOW>;
++ };
++};
++
++gpio: &rp1_gpio {
++ status = "okay";
++};
++
++aux: &dummy {};
++
++&rp1_usb0 {
++ pinctrl-0 = <&usb_vbus_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++};
++
++&rp1_usb1 {
++ status = "okay";
++};
++
++#include "bcm2712-rpi.dtsi"
++
++i2c_csi_dsi0: &i2c6 { // Note: This is for MIPI0 connector only
++ pinctrl-0 = <&rp1_i2c6_38_39>;
++ pinctrl-names = "default";
++ clock-frequency = <100000>;
++};
++
++i2c_csi_dsi1: &i2c0 { // Note: This is for MIPI1 connector
++};
++
++i2c_csi_dsi: &i2c_csi_dsi1 { }; // An alias for compatibility
++
++cam1_reg: &cam0_reg { // Shares CAM_GPIO with cam0_reg
++};
++
++csi0: &rp1_csi0 { };
++csi1: &rp1_csi1 { };
++dsi0: &rp1_dsi0 { };
++dsi1: &rp1_dsi1 { };
++dpi: &rp1_dpi { };
++vec: &rp1_vec { };
++dpi_gpio0: &rp1_dpi_24bit_gpio0 { };
++dpi_gpio1: &rp1_dpi_24bit_gpio2 { };
++dpi_18bit_cpadhi_gpio0: &rp1_dpi_18bit_cpadhi_gpio0 { };
++dpi_18bit_cpadhi_gpio2: &rp1_dpi_18bit_cpadhi_gpio2 { };
++dpi_18bit_gpio0: &rp1_dpi_18bit_gpio0 { };
++dpi_18bit_gpio2: &rp1_dpi_18bit_gpio2 { };
++dpi_16bit_cpadhi_gpio0: &rp1_dpi_16bit_cpadhi_gpio0 { };
++dpi_16bit_cpadhi_gpio2: &rp1_dpi_16bit_cpadhi_gpio2 { };
++dpi_16bit_gpio0: &rp1_dpi_16bit_gpio0 { };
++dpi_16bit_gpio2: &rp1_dpi_16bit_gpio2 { };
++
++/* Add the IOMMUs for some RP1 bus masters */
++
++&csi0 {
++ iommus = <&iommu5>;
++};
++
++&csi1 {
++ iommus = <&iommu5>;
++};
++
++&dsi0 {
++ iommus = <&iommu5>;
++};
++
++&dsi1 {
++ iommus = <&iommu5>;
++};
++
++&dpi {
++ iommus = <&iommu5>;
++};
++
++&vec {
++ iommus = <&iommu5>;
++};
++
++&ddc0 {
++ status = "disabled";
++};
++
++&ddc1 {
++ status = "disabled";
++};
++
++&hdmi0 {
++ clocks = <&firmware_clocks 13>, <&firmware_clocks 14>, <&dvp 0>, <&clk_27MHz>;
++ clock-names = "hdmi", "bvb", "audio", "cec";
++ status = "disabled";
++};
++
++&hdmi1 {
++ clocks = <&firmware_clocks 13>, <&firmware_clocks 14>, <&dvp 1>, <&clk_27MHz>;
++ clock-names = "hdmi", "bvb", "audio", "cec";
++ status = "disabled";
++};
++
++&hvs {
++ clocks = <&firmware_clocks 4>, <&firmware_clocks 16>;
++ clock-names = "core", "disp";
++};
++
++&mop {
++ status = "disabled";
++};
++
++&moplet {
++ status = "disabled";
++};
++
++&pixelvalve0 {
++ status = "disabled";
++};
++
++&pixelvalve1 {
++ status = "disabled";
++};
++
++&disp_intr {
++ status = "disabled";
++};
++
++/* SDIO1 is used to drive the eMMC/SD card */
++&sdio1 {
++ pinctrl-0 = <&emmc_cmddat_pulls>, <&emmc_ds_pull>;
++ pinctrl-names = "default";
++ vqmmc-supply = <&sd_io_1v8_reg>;
++ vmmc-supply = <&sd_vcc_reg>;
++ bus-width = <8>;
++ sd-uhs-sdr50;
++ sd-uhs-ddr50;
++ sd-uhs-sdr104;
++ mmc-hs200-1_8v;
++ mmc-hs400-1_8v;
++ mmc-hs400-enhanced-strobe;
++ broken-cd;
++ supports-cqe;
++ status = "okay";
++};
++
++&pinctrl_aon {
++ ant_pins: ant_pins {
++ function = "gpio";
++ pins = "aon_gpio5", "aon_gpio6";
++ };
++
++ /* Slight hack - only one PWM pin (status LED) is usable */
++ aon_pwm_1pin: aon_pwm_1pin {
++ function = "aon_pwm";
++ pins = "aon_gpio9";
++ };
++};
++
++&pinctrl {
++ pwr_button_pins: pwr_button_pins {
++ function = "gpio";
++ pins = "gpio20";
++ bias-pull-up;
++ };
++
++ wl_on_pins: wl_on_pins {
++ function = "gpio";
++ pins = "gpio28";
++ };
++
++ bt_shutdown_pins: bt_shutdown_pins {
++ function = "gpio";
++ pins = "gpio29";
++ };
++
++ emmc_ds_pull: emmc_ds_pull {
++ pins = "emmc_ds";
++ bias-pull-down;
++ };
++
++ emmc_cmddat_pulls: emmc_cmddat_pulls {
++ pins = "emmc_cmd", "emmc_dat0", "emmc_dat1", "emmc_dat2", "emmc_dat3",
++ "emmc_dat4", "emmc_dat5", "emmc_dat6", "emmc_dat7";
++ bias-pull-up;
++ };
++};
++
++/* uarta communicates with the BT module */
++&uarta {
++ uart-has-rtscts;
++ auto-flow-control;
++ status = "okay";
++ clock-frequency = <96000000>;
++ pinctrl-0 = <&uarta_24_pins &bt_shutdown_pins>;
++ pinctrl-names = "default";
++
++ bluetooth: bluetooth {
++ compatible = "brcm,bcm43438-bt";
++ max-speed = <3000000>;
++ shutdown-gpios = <&gio 29 GPIO_ACTIVE_HIGH>;
++ local-bd-address = [ 00 00 00 00 00 00 ];
++ };
++};
++
++&i2c_rp1boot {
++ clock-frequency = <400000>;
++ pinctrl-0 = <&i2c3_m4_agpio0_pins>;
++ pinctrl-names = "default";
++};
++
++/ {
++ chosen: chosen {
++ bootargs = "reboot=w coherent_pool=1M 8250.nr_uarts=1 pci=pcie_bus_safe";
++ stdout-path = "serial10:115200n8";
++ };
++
++ fan: cooling_fan {
++ status = "disabled";
++ compatible = "pwm-fan";
++ #cooling-cells = <2>;
++ cooling-min-state = <0>;
++ cooling-max-state = <3>;
++ cooling-levels = <0 75 125 175 250>;
++ pwms = <&rp1_pwm1 3 41566 PWM_POLARITY_INVERTED>;
++ rpm-regmap = <&rp1_pwm1>;
++ rpm-offset = <0x3c>;
++ };
++
++ pwr_button {
++ compatible = "gpio-keys";
++
++ pinctrl-names = "default";
++ pinctrl-0 = <&pwr_button_pins>;
++ status = "okay";
++
++ pwr_key: pwr {
++ label = "pwr_button";
++ // linux,code = <205>; // KEY_SUSPEND
++ linux,code = <116>; // KEY_POWER
++ gpios = <&gio 20 GPIO_ACTIVE_LOW>;
++ debounce-interval = <50>; // ms
++ };
++ };
++};
++
++&usb {
++ power-domains = <&power RPI_POWER_DOMAIN_USB>;
++};
++
++/* SDIO2 drives the WLAN interface */
++&sdio2 {
++ pinctrl-0 = <&sdio2_30_pins>, <&ant_pins>;
++ pinctrl-names = "default";
++ bus-width = <4>;
++ vmmc-supply = <&wl_on_reg>;
++ sd-uhs-ddr50;
++ non-removable;
++ status = "okay";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ wifi: wifi@1 {
++ reg = <1>;
++ compatible = "brcm,bcm4329-fmac";
++ local-mac-address = [00 00 00 00 00 00];
++ };
++};
++
++&rpivid {
++ status = "okay";
++};
++
++&pinctrl {
++ spi10_gpio2: spi10_gpio2 {
++ function = "vc_spi0";
++ pins = "gpio2", "gpio3", "gpio4";
++ bias-disable;
++ };
++
++ spi10_cs_gpio1: spi10_cs_gpio1 {
++ function = "gpio";
++ pins = "gpio1";
++ bias-pull-up;
++ };
++};
++
++spi10_pins: &spi10_gpio2 {};
++spi10_cs_pins: &spi10_cs_gpio1 {};
++
++&spi10 {
++ pinctrl-names = "default";
++ cs-gpios = <&gio 1 1>;
++ pinctrl-0 = <&spi10_pins &spi10_cs_pins>;
++
++ spidev10: spidev@0 {
++ compatible = "spidev";
++ reg = <0>; /* CE0 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <20000000>;
++ status = "okay";
++ };
++};
++
++// =============================================
++// Board specific stuff here
++
++&gio_aon {
++ // Don't use GIO_AON as an interrupt controller because it will
++ // clash with the firmware monitoring the PMIC interrupt via the VPU.
++
++ /delete-property/ interrupt-controller;
++};
++
++&main_aon_irq {
++ // Don't use the MAIN_AON_IRQ interrupt controller because it will
++ // clash with the firmware monitoring the PMIC interrupt via the VPU.
++
++ status = "disabled";
++};
++
++&rp1_pwm1 {
++ status = "disabled";
++ pinctrl-0 = <&rp1_pwm1_gpio45>;
++ pinctrl-names = "default";
++};
++
++&thermal_trips {
++ cpu_tepid: cpu-tepid {
++ temperature = <50000>;
++ hysteresis = <5000>;
++ type = "active";
++ };
++
++ cpu_warm: cpu-warm {
++ temperature = <60000>;
++ hysteresis = <5000>;
++ type = "active";
++ };
++
++ cpu_hot: cpu-hot {
++ temperature = <67500>;
++ hysteresis = <5000>;
++ type = "active";
++ };
++
++ cpu_vhot: cpu-vhot {
++ temperature = <75000>;
++ hysteresis = <5000>;
++ type = "active";
++ };
++};
++
++&cooling_maps {
++ tepid {
++ trip = <&cpu_tepid>;
++ cooling-device = <&fan 1 1>;
++ };
++
++ warm {
++ trip = <&cpu_warm>;
++ cooling-device = <&fan 2 2>;
++ };
++
++ hot {
++ trip = <&cpu_hot>;
++ cooling-device = <&fan 3 3>;
++ };
++
++ vhot {
++ trip = <&cpu_vhot>;
++ cooling-device = <&fan 4 4>;
++ };
++
++ melt {
++ trip = <&cpu_crit>;
++ cooling-device = <&fan 4 4>;
++ };
++};
++
++&gio {
++ // The GPIOs above 35 are not used on Pi 5, so shrink the upper bank
++ // to reduce the clutter in gpioinfo/pinctrl
++ brcm,gpio-bank-widths = <32 4>;
++
++ gpio-line-names =
++ "-", // GPIO_000
++ "2712_BOOT_CS_N", // GPIO_001
++ "2712_BOOT_MISO", // GPIO_002
++ "2712_BOOT_MOSI", // GPIO_003
++ "2712_BOOT_SCLK", // GPIO_004
++ "-", // GPIO_005
++ "-", // GPIO_006
++ "-", // GPIO_007
++ "-", // GPIO_008
++ "-", // GPIO_009
++ "-", // GPIO_010
++ "-", // GPIO_011
++ "-", // GPIO_012
++ "-", // GPIO_013
++ "-", // GPIO_014
++ "-", // GPIO_015
++ "-", // GPIO_016
++ "-", // GPIO_017
++ "-", // GPIO_018
++ "-", // GPIO_019
++ "PWR_GPIO", // GPIO_020
++ "2712_G21_FS", // GPIO_021
++ "-", // GPIO_022
++ "-", // GPIO_023
++ "BT_RTS", // GPIO_024
++ "BT_CTS", // GPIO_025
++ "BT_TXD", // GPIO_026
++ "BT_RXD", // GPIO_027
++ "WL_ON", // GPIO_028
++ "BT_ON", // GPIO_029
++ "WIFI_SDIO_CLK", // GPIO_030
++ "WIFI_SDIO_CMD", // GPIO_031
++ "WIFI_SDIO_D0", // GPIO_032
++ "WIFI_SDIO_D1", // GPIO_033
++ "WIFI_SDIO_D2", // GPIO_034
++ "WIFI_SDIO_D3"; // GPIO_035
++};
++
++&gio_aon {
++ gpio-line-names =
++ "RP1_SDA", // AON_GPIO_00
++ "RP1_SCL", // AON_GPIO_01
++ "RP1_RUN", // AON_GPIO_02
++ "SD_IOVDD_SEL", // AON_GPIO_03
++ "SD_PWR_ON", // AON_GPIO_04
++ "ANT1", // AON_GPIO_05
++ "ANT2", // AON_GPIO_06
++ "-", // AON_GPIO_07
++ "2712_WAKE", // AON_GPIO_08
++ "2712_STAT_LED", // AON_GPIO_09
++ "-", // AON_GPIO_10
++ "-", // AON_GPIO_11
++ "PMIC_INT", // AON_GPIO_12
++ "UART_TX_FS", // AON_GPIO_13
++ "UART_RX_FS", // AON_GPIO_14
++ "-", // AON_GPIO_15
++ "-", // AON_GPIO_16
++
++ // Pad bank0 out to 32 entries
++ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
++
++ "HDMI0_SCL", // AON_SGPIO_00
++ "HDMI0_SDA", // AON_SGPIO_01
++ "HDMI1_SCL", // AON_SGPIO_02
++ "HDMI1_SDA", // AON_SGPIO_03
++ "PMIC_SCL", // AON_SGPIO_04
++ "PMIC_SDA"; // AON_SGPIO_05
++
++ rp1_run_hog {
++ gpio-hog;
++ gpios = <2 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "RP1 RUN pin";
++ };
++
++ ant1: ant1-hog {
++ gpio-hog;
++ gpios = <5 GPIO_ACTIVE_HIGH>;
++ /* internal antenna enabled */
++ output-high;
++ line-name = "ant1";
++ };
++
++ ant2: ant2-hog {
++ gpio-hog;
++ gpios = <6 GPIO_ACTIVE_HIGH>;
++ /* external antenna disabled */
++ output-low;
++ line-name = "ant2";
++ };
++};
++
++&rp1_gpio {
++ gpio-line-names =
++ "ID_SDA", // GPIO0
++ "ID_SCL", // GPIO1
++ "GPIO2", // GPIO2
++ "GPIO3", // GPIO3
++ "GPIO4", // GPIO4
++ "GPIO5", // GPIO5
++ "GPIO6", // GPIO6
++ "GPIO7", // GPIO7
++ "GPIO8", // GPIO8
++ "GPIO9", // GPIO9
++ "GPIO10", // GPIO10
++ "GPIO11", // GPIO11
++ "GPIO12", // GPIO12
++ "GPIO13", // GPIO13
++ "GPIO14", // GPIO14
++ "GPIO15", // GPIO15
++ "GPIO16", // GPIO16
++ "GPIO17", // GPIO17
++ "GPIO18", // GPIO18
++ "GPIO19", // GPIO19
++ "GPIO20", // GPIO20
++ "GPIO21", // GPIO21
++ "GPIO22", // GPIO22
++ "GPIO23", // GPIO23
++ "GPIO24", // GPIO24
++ "GPIO25", // GPIO25
++ "GPIO26", // GPIO26
++ "GPIO27", // GPIO27
++
++ "PCIE_PWR_EN", // GPIO28
++ "FAN_TACH", // GPIO29
++ "HOST_SDA", // GPIO30
++ "HOST_SCL", // GPIO31
++ "ETH_RST_N", // GPIO32
++ "PCIE_DET_WAKE", // GPIO33
++
++ "CD0_IO0_MICCLK", // GPIO34
++ "CD0_IO0_MICDAT0", // GPIO35
++ "RP1_PCIE_CLKREQ_N", // GPIO36
++ "ETH_IRQ_N", // GPIO37
++ "SDA0", // GPIO38
++ "SCL0", // GPIO39
++ "-", // GPIO40
++ "-", // GPIO41
++ "USB_VBUS_EN", // GPIO42
++ "USB_OC_N", // GPIO43
++ "RP1_STAT_LED", // GPIO44
++ "FAN_PWM", // GPIO45
++ "-", // GPIO46
++ "2712_WAKE", // GPIO47
++ "-", // GPIO48
++ "-", // GPIO49
++ "-", // GPIO50
++ "-", // GPIO51
++ "-", // GPIO52
++ "-"; // GPIO53
++
++ usb_vbus_pins: usb_vbus_pins {
++ function = "vbus1";
++ pins = "gpio42", "gpio43";
++ };
++};
++
++/ {
++ aliases: aliases {
++ blconfig = &blconfig;
++ blpubkey = &blpubkey;
++ bluetooth = &bluetooth;
++ console = &uart10;
++ ethernet0 = &rp1_eth;
++ wifi0 = &wifi;
++ fb = &fb;
++ mailbox = &mailbox;
++ mmc0 = &sdio1;
++ uart0 = &uart0;
++ uart1 = &uart1;
++ uart2 = &uart2;
++ uart3 = &uart3;
++ uart4 = &uart4;
++ uart10 = &uart10;
++ serial0 = &uart0;
++ serial1 = &uart1;
++ serial2 = &uart2;
++ serial3 = &uart3;
++ serial4 = &uart4;
++ serial10 = &uart10;
++ i2c = &i2c_arm;
++ i2c0 = &i2c0;
++ i2c1 = &i2c1;
++ i2c2 = &i2c2;
++ i2c3 = &i2c3;
++ i2c4 = &i2c4;
++ i2c5 = &i2c5;
++ i2c6 = &i2c6;
++ i2c10 = &i2c_rp1boot;
++ // Bit-bashed i2c_gpios start at 10
++ spi0 = &spi0;
++ spi1 = &spi1;
++ spi2 = &spi2;
++ spi3 = &spi3;
++ spi4 = &spi4;
++ spi5 = &spi5;
++ spi10 = &spi10;
++ gpio0 = &gpio;
++ gpio1 = &gio;
++ gpio2 = &gio_aon;
++ gpio3 = &pinctrl;
++ gpio4 = &pinctrl_aon;
++ usb0 = &rp1_usb0;
++ usb1 = &rp1_usb1;
++ drm-dsi1 = &dsi0;
++ drm-dsi2 = &dsi1;
++ };
++
++ __overrides__ {
++ bdaddr = <&bluetooth>, "local-bd-address[";
++ button_debounce = <&pwr_key>, "debounce-interval:0";
++ cooling_fan = <&fan>, "status", <&rp1_pwm1>, "status";
++ uart0_console = <&uart0>,"status", <&aliases>, "console=",&uart0;
++ i2c0 = <&i2c0>, "status";
++ i2c1 = <&i2c1>, "status";
++ i2c = <&i2c1>, "status";
++ i2c_arm = <&i2c_arm>, "status";
++ i2c_vc = <&i2c_vc>, "status";
++ i2c_csi_dsi = <&i2c_csi_dsi>, "status";
++ i2c_csi_dsi0 = <&i2c_csi_dsi0>, "status";
++ i2c_csi_dsi1 = <&i2c_csi_dsi1>, "status";
++ i2c0_baudrate = <&i2c0>, "clock-frequency:0";
++ i2c1_baudrate = <&i2c1>, "clock-frequency:0";
++ i2c_baudrate = <&i2c_arm>, "clock-frequency:0";
++ i2c_arm_baudrate = <&i2c_arm>, "clock-frequency:0";
++ i2c_vc_baudrate = <&i2c_vc>, "clock-frequency:0";
++ krnbt = <&bluetooth>, "status";
++ nvme = <&pciex1>, "status";
++ pciex1 = <&pciex1>, "status";
++ pciex1_gen = <&pciex1> , "max-link-speed:0";
++ pciex1_no_l0s = <&pciex1>, "aspm-no-l0s?";
++ pciex1_tperst_clk_ms = <&pciex1>, "brcm,tperst-clk-ms:0";
++ pcie_tperst_clk_ms = <&pciex1>, "brcm,tperst-clk-ms:0";
++ random = <&random>, "status";
++ rtc = <&rpi_rtc>, "status";
++ rtc_bbat_vchg = <&rpi_rtc>, "trickle-charge-microvolt:0";
++ spi = <&spi0>, "status";
++ suspend = <&pwr_key>, "linux,code:0=205";
++ uart0 = <&uart0>, "status";
++ wifiaddr = <&wifi>, "local-mac-address[";
++
++ act_led_activelow = <&led_act>, "active-low?";
++ act_led_trigger = <&led_act>, "linux,default-trigger";
++ pwr_led_activelow = <&led_pwr>, "gpios:8";
++ pwr_led_trigger = <&led_pwr>, "linux,default-trigger";
++ eth_led0 = <&phy1>,"led-modes:0";
++ eth_led1 = <&phy1>,"led-modes:4";
++ drm_fb0_rp1_dsi0 = <&aliases>, "drm-fb0=",&dsi0;
++ drm_fb0_rp1_dsi1 = <&aliases>, "drm-fb0=",&dsi1;
++ drm_fb0_rp1_dpi = <&aliases>, "drm-fb0=",&dpi;
++ drm_fb0_vc4 = <&aliases>, "drm-fb0=",&vc4;
++ drm_fb1_rp1_dsi0 = <&aliases>, "drm-fb1=",&dsi0;
++ drm_fb1_rp1_dsi1 = <&aliases>, "drm-fb1=",&dsi1;
++ drm_fb1_rp1_dpi = <&aliases>, "drm-fb1=",&dpi;
++ drm_fb1_vc4 = <&aliases>, "drm-fb1=",&vc4;
++ drm_fb2_rp1_dsi0 = <&aliases>, "drm-fb2=",&dsi0;
++ drm_fb2_rp1_dsi1 = <&aliases>, "drm-fb2=",&dsi1;
++ drm_fb2_rp1_dpi = <&aliases>, "drm-fb2=",&dpi;
++ drm_fb2_vc4 = <&aliases>, "drm-fb2=",&vc4;
++
++ ant1 = <&ant1>,"output-high?=on",
++ <&ant1>, "output-low?=off",
++ <&ant2>, "output-high?=off",
++ <&ant2>, "output-low?=on";
++ ant2 = <&ant1>,"output-high?=off",
++ <&ant1>, "output-low?=on",
++ <&ant2>, "output-high?=on",
++ <&ant2>, "output-low?=off";
++ noant = <&ant1>,"output-high?=off",
++ <&ant1>, "output-low?=on",
++ <&ant2>, "output-high?=off",
++ <&ant2>, "output-low?=on";
++
++ fan_temp0 = <&cpu_tepid>,"temperature:0";
++ fan_temp1 = <&cpu_warm>,"temperature:0";
++ fan_temp2 = <&cpu_hot>,"temperature:0";
++ fan_temp3 = <&cpu_vhot>,"temperature:0";
++ fan_temp0_hyst = <&cpu_tepid>,"hysteresis:0";
++ fan_temp1_hyst = <&cpu_warm>,"hysteresis:0";
++ fan_temp2_hyst = <&cpu_hot>,"hysteresis:0";
++ fan_temp3_hyst = <&cpu_vhot>,"hysteresis:0";
++ fan_temp0_speed = <&fan>, "cooling-levels:4";
++ fan_temp1_speed = <&fan>, "cooling-levels:8";
++ fan_temp2_speed = <&fan>, "cooling-levels:12";
++ fan_temp3_speed = <&fan>, "cooling-levels:16";
++ };
++};
+--- a/arch/arm64/boot/dts/broadcom/bcm2712d0-rpi-5-b.dts
++++ b/arch/arm64/boot/dts/broadcom/bcm2712d0-rpi-5-b.dts
+@@ -1,2 +1,107 @@
+ // SPDX-License-Identifier: GPL-2.0
+-#include "../../../../arm/boot/dts/broadcom/bcm2712d0-rpi-5-b.dts"
++#include "bcm2712-rpi-5-b.dts"
++
++&gio {
++ brcm,gpio-bank-widths = <32 4>;
++
++ gpio-line-names =
++ "", // GPIO_000
++ "2712_BOOT_CS_N", // GPIO_001
++ "2712_BOOT_MISO", // GPIO_002
++ "2712_BOOT_MOSI", // GPIO_003
++ "2712_BOOT_SCLK", // GPIO_004
++ "", // GPIO_005
++ "", // GPIO_006
++ "", // GPIO_007
++ "", // GPIO_008
++ "", // GPIO_009
++ "", // GPIO_010
++ "", // GPIO_011
++ "", // GPIO_012
++ "", // GPIO_013
++ "PCIE_SDA", // GPIO_014
++ "PCIE_SCL", // GPIO_015
++ "", // GPIO_016
++ "", // GPIO_017
++ "-", // GPIO_018
++ "-", // GPIO_019
++ "PWR_GPIO", // GPIO_020
++ "2712_G21_FS", // GPIO_021
++ "-", // GPIO_022
++ "-", // GPIO_023
++ "BT_RTS", // GPIO_024
++ "BT_CTS", // GPIO_025
++ "BT_TXD", // GPIO_026
++ "BT_RXD", // GPIO_027
++ "WL_ON", // GPIO_028
++ "BT_ON", // GPIO_029
++ "WIFI_SDIO_CLK", // GPIO_030
++ "WIFI_SDIO_CMD", // GPIO_031
++ "WIFI_SDIO_D0", // GPIO_032
++ "WIFI_SDIO_D1", // GPIO_033
++ "WIFI_SDIO_D2", // GPIO_034
++ "WIFI_SDIO_D3"; // GPIO_035
++};
++
++&gio_aon {
++ brcm,gpio-bank-widths = <15 6>;
++
++ gpio-line-names =
++ "RP1_SDA", // AON_GPIO_00
++ "RP1_SCL", // AON_GPIO_01
++ "RP1_RUN", // AON_GPIO_02
++ "SD_IOVDD_SEL", // AON_GPIO_03
++ "SD_PWR_ON", // AON_GPIO_04
++ "SD_CDET_N", // AON_GPIO_05
++ "SD_FLG_N", // AON_GPIO_06
++ "", // AON_GPIO_07
++ "2712_WAKE", // AON_GPIO_08
++ "2712_STAT_LED", // AON_GPIO_09
++ "", // AON_GPIO_10
++ "", // AON_GPIO_11
++ "PMIC_INT", // AON_GPIO_12
++ "UART_TX_FS", // AON_GPIO_13
++ "UART_RX_FS", // AON_GPIO_14
++ "", // AON_GPIO_15
++ "", // AON_GPIO_16
++
++ // Pad bank0 out to 32 entries
++ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
++
++ "HDMI0_SCL", // AON_SGPIO_00
++ "HDMI0_SDA", // AON_SGPIO_01
++ "HDMI1_SCL", // AON_SGPIO_02
++ "HDMI1_SDA", // AON_SGPIO_03
++ "PMIC_SCL", // AON_SGPIO_04
++ "PMIC_SDA"; // AON_SGPIO_05
++};
++
++&pinctrl {
++ compatible = "brcm,bcm2712d0-pinctrl";
++ reg = <0x7d504100 0x20>;
++};
++
++&pinctrl_aon {
++ compatible = "brcm,bcm2712d0-aon-pinctrl";
++ reg = <0x7d510700 0x1c>;
++};
++
++&vc4 {
++ compatible = "brcm,bcm2712d0-vc6";
++};
++
++&uart10 {
++ interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&spi10 {
++ dmas = <&dma40 3>, <&dma40 4>;
++};
++
++&hdmi0 {
++ dmas = <&dma40 (12|(1<<30)|(1<<24)|(10<<16)|(15<<20))>;
++};
++
++&hdmi1 {
++ dmas = <&dma40 (13|(1<<30)|(1<<24)|(10<<16)|(15<<20))>;
++};
+--- a/arch/arm/boot/dts/broadcom/bcm2712-rpi.dtsi
++++ /dev/null
+@@ -1,351 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0
+-
+-#include <dt-bindings/power/raspberrypi-power.h>
+-
+-&soc {
+- firmware: firmware {
+- compatible = "raspberrypi,bcm2835-firmware", "simple-mfd";
+- #address-cells = <1>;
+- #size-cells = <1>;
+-
+- mboxes = <&mailbox>;
+- dma-ranges;
+-
+- firmware_clocks: clocks {
+- compatible = "raspberrypi,firmware-clocks";
+- #clock-cells = <1>;
+- };
+-
+- reset: reset {
+- compatible = "raspberrypi,firmware-reset";
+- #reset-cells = <1>;
+- };
+-
+- vcio: vcio {
+- compatible = "raspberrypi,vcio";
+- };
+- };
+-
+- power: power {
+- compatible = "raspberrypi,bcm2835-power";
+- firmware = <&firmware>;
+- #power-domain-cells = <1>;
+- };
+-
+- fb: fb {
+- compatible = "brcm,bcm2708-fb";
+- firmware = <&firmware>;
+- status = "okay";
+- };
+-
+- rpi_rtc: rpi_rtc {
+- compatible = "raspberrypi,rpi-rtc";
+- firmware = <&firmware>;
+- status = "okay";
+- trickle-charge-microvolt = <0>;
+- };
+-
+- nvmem {
+- compatible = "simple-bus";
+- #address-cells = <1>;
+- #size-cells = <1>;
+-
+- nvmem_otp: nvmem_otp {
+- compatible = "raspberrypi,rpi-otp";
+- firmware = <&firmware>;
+- reg = <0 192>;
+- status = "okay";
+- };
+-
+- nvmem_cust: nvmem_cust {
+- compatible = "raspberrypi,rpi-otp";
+- firmware = <&firmware>;
+- reg = <1 8>;
+- status = "okay";
+- };
+-
+- nvmem_mac: nvmem_mac {
+- compatible = "raspberrypi,rpi-otp";
+- firmware = <&firmware>;
+- reg = <2 6>;
+- status = "okay";
+- };
+-
+- nvmem_priv: nvmem_priv {
+- compatible = "raspberrypi,rpi-otp";
+- firmware = <&firmware>;
+- reg = <3 16>;
+- status = "okay";
+- };
+- };
+-
+- /* Define these notional regulators for use by overlays, etc. */
+- vdd_3v3_reg: fixedregulator_3v3 {
+- compatible = "regulator-fixed";
+- regulator-always-on;
+- regulator-max-microvolt = <3300000>;
+- regulator-min-microvolt = <3300000>;
+- regulator-name = "3v3";
+- };
+-
+- vdd_5v0_reg: fixedregulator_5v0 {
+- compatible = "regulator-fixed";
+- regulator-always-on;
+- regulator-max-microvolt = <5000000>;
+- regulator-min-microvolt = <5000000>;
+- regulator-name = "5v0";
+- };
+-};
+-
+-/ {
+- __overrides__ {
+- arm_freq;
+- axiperf = <&axiperf>,"status";
+-
+- nvmem_cust_rw = <&nvmem_cust>,"rw?";
+- nvmem_priv_rw = <&nvmem_priv>,"rw?";
+- nvmem_mac_rw = <&nvmem_mac>,"rw?";
+- strict_gpiod = <&chosen>, "bootargs=pinctrl_rp1.persist_gpio_outputs=n";
+-
+- cam0_reg = <&cam0_reg>,"status";
+- cam0_reg_gpio = <&cam0_reg>,"gpio:4",
+- <&cam0_reg>,"gpio:0=", <&gpio>;
+- cam1_reg = <&cam1_reg>,"status";
+- cam1_reg_gpio = <&cam1_reg>,"gpio:4",
+- <&cam1_reg>,"gpio:0=", <&gpio>;
+-
+- };
+-};
+-
+-pciex1: &pcie1 { };
+-pciex4: &pcie2 { };
+-
+-&dma32 {
+- /* The VPU firmware uses DMA channel 11 for VCHIQ */
+- brcm,dma-channel-mask = <0x03f>;
+-};
+-
+-&dma40 {
+- /* The VPU firmware DMA channel 11 for VCHIQ */
+- brcm,dma-channel-mask = <0x07c0>;
+-};
+-
+-&hdmi0 {
+- dmas = <&dma40 (10|(1<<30)|(1<<24)|(10<<16)|(15<<20))>;
+-};
+-
+-&hdmi1 {
+- dmas = <&dma40 (17|(1<<30)|(1<<24)|(10<<16)|(15<<20))>;
+-};
+-
+-&spi10 {
+- dmas = <&dma40 6>, <&dma40 7>;
+- dma-names = "tx", "rx";
+-};
+-
+-&usb {
+- power-domains = <&power RPI_POWER_DOMAIN_USB>;
+-};
+-
+-&rmem {
+- /*
+- * RPi5's co-processor will copy the board's bootloader configuration
+- * into memory for the OS to consume. It'll also update this node with
+- * its placement information.
+- */
+- blconfig: nvram@0 {
+- compatible = "raspberrypi,bootloader-config", "nvmem-rmem";
+- #address-cells = <1>;
+- #size-cells = <1>;
+- reg = <0x0 0x0 0x0>;
+- no-map;
+- status = "disabled";
+- };
+- /*
+- * RPi5 will copy the binary public key blob (if present) from the bootloader
+- * into memory for use by the OS.
+- */
+- blpubkey: nvram@1 {
+- compatible = "raspberrypi,bootloader-public-key", "nvmem-rmem";
+- #address-cells = <1>;
+- #size-cells = <1>;
+- reg = <0x0 0x0 0x0>;
+- no-map;
+- status = "disabled";
+- };
+-};
+-
+-&rp1_adc {
+- status = "okay";
+-};
+-
+-/* Add some gpiomem nodes to make the devices accessible to userspace.
+- * /dev/gpiomem<n> should expose the registers for the interface with DT alias
+- * gpio<n>.
+- */
+-
+-&rp1 {
+- gpiomem@d0000 {
+- /* Export IO_BANKs, RIO_BANKs and PADS_BANKs to userspace */
+- compatible = "raspberrypi,gpiomem";
+- reg = <0xc0 0x400d0000 0x0 0x30000>;
+- chardev-name = "gpiomem0";
+- };
+-};
+-
+-&soc {
+- gpiomem@7d508500 {
+- compatible = "raspberrypi,gpiomem";
+- reg = <0x7d508500 0x40>;
+- chardev-name = "gpiomem1";
+- };
+-
+- gpiomem@7d517c00 {
+- compatible = "raspberrypi,gpiomem";
+- reg = <0x7d517c00 0x40>;
+- chardev-name = "gpiomem2";
+- };
+-
+- gpiomem@7d504100 {
+- compatible = "raspberrypi,gpiomem";
+- reg = <0x7d504100 0x20>;
+- chardev-name = "gpiomem3";
+- };
+-
+- gpiomem@7d510700 {
+- compatible = "raspberrypi,gpiomem";
+- reg = <0x7d510700 0x20>;
+- chardev-name = "gpiomem4";
+- };
+-
+- sound: sound {
+- status = "disabled";
+- };
+-};
+-
+-i2c0: &rp1_i2c0 { };
+-i2c1: &rp1_i2c1 { };
+-i2c2: &rp1_i2c2 { };
+-i2c3: &rp1_i2c3 { };
+-i2c4: &rp1_i2c4 { };
+-i2c5: &rp1_i2c5 { };
+-i2c6: &rp1_i2c6 { };
+-i2s: &rp1_i2s0 { };
+-i2s_clk_producer: &rp1_i2s0 { };
+-i2s_clk_consumer: &rp1_i2s1 { };
+-pwm0: &rp1_pwm0 { };
+-pwm1: &rp1_pwm1 { };
+-pwm: &pwm0 { };
+-spi0: &rp1_spi0 { };
+-spi1: &rp1_spi1 { };
+-spi2: &rp1_spi2 { };
+-spi3: &rp1_spi3 { };
+-spi4: &rp1_spi4 { };
+-spi5: &rp1_spi5 { };
+-
+-uart0_pins: &rp1_uart0_14_15 {};
+-uart0_ctsrts_pins: &rp1_uart0_ctsrts_16_17 {};
+-uart0: &rp1_uart0 {
+- pinctrl-0 = <&uart0_pins>;
+-};
+-
+-uart1_pins: &rp1_uart1_0_1 {};
+-uart1_ctsrts_pins: &rp1_uart1_ctsrts_2_3 {};
+-uart1: &rp1_uart1 { };
+-
+-uart2_pins: &rp1_uart2_4_5 {};
+-uart2_ctsrts_pins: &rp1_uart2_ctsrts_6_7 {};
+-uart2: &rp1_uart2 { };
+-
+-uart3_pins: &rp1_uart3_8_9 {};
+-uart3_ctsrts_pins: &rp1_uart3_ctsrts_10_11 {};
+-uart3: &rp1_uart3 { };
+-
+-uart4_pins: &rp1_uart4_12_13 {};
+-uart4_ctsrts_pins: &rp1_uart4_ctsrts_14_15 {};
+-uart4: &rp1_uart4 { };
+-
+-i2c0_pins: &rp1_i2c0_0_1 {};
+-i2c_vc: &i2c0 { // This is pins 27,28 on the header (not MIPI)
+- pinctrl-0 = <&i2c0_pins>;
+- pinctrl-names = "default";
+- clock-frequency = <100000>;
+-};
+-
+-i2c1_pins: &rp1_i2c1_2_3 {};
+-i2c_arm: &i2c1 {
+- pinctrl-names = "default";
+- pinctrl-0 = <&i2c1_pins>;
+- clock-frequency = <100000>;
+-};
+-
+-i2c2_pins: &rp1_i2c2_4_5 {};
+-&i2c2 {
+- pinctrl-names = "default";
+- pinctrl-0 = <&i2c2_pins>;
+-};
+-
+-i2c3_pins: &rp1_i2c3_6_7 {};
+-&i2c3 {
+- pinctrl-names = "default";
+- pinctrl-0 = <&i2c3_pins>;
+-};
+-
+-&i2s_clk_producer {
+- pinctrl-names = "default";
+- pinctrl-0 = <&rp1_i2s0_18_21>;
+-};
+-
+-&i2s_clk_consumer {
+- pinctrl-names = "default";
+- pinctrl-0 = <&rp1_i2s1_18_21>;
+-};
+-
+-spi0_pins: &rp1_spi0_gpio9 {};
+-spi0_cs_pins: &rp1_spi0_cs_gpio7 {};
+-
+-&spi0 {
+- pinctrl-names = "default";
+- pinctrl-0 = <&spi0_pins &spi0_cs_pins>;
+- cs-gpios = <&gpio 8 1>, <&gpio 7 1>;
+-
+- spidev0: spidev@0 {
+- compatible = "spidev";
+- reg = <0>; /* CE0 */
+- #address-cells = <1>;
+- #size-cells = <0>;
+- spi-max-frequency = <125000000>;
+- };
+-
+- spidev1: spidev@1 {
+- compatible = "spidev";
+- reg = <1>; /* CE1 */
+- #address-cells = <1>;
+- #size-cells = <0>;
+- spi-max-frequency = <125000000>;
+- };
+-};
+-
+-spi2_pins: &rp1_spi2_gpio1 {};
+-&spi2 {
+- pinctrl-names = "default";
+- pinctrl-0 = <&spi2_pins>;
+-};
+-
+-spi3_pins: &rp1_spi3_gpio5 {};
+-&spi3 {
+- pinctrl-names = "default";
+- pinctrl-0 = <&spi3_pins>;
+-};
+-
+-spi4_pins: &rp1_spi4_gpio9 {};
+-&spi4 {
+- pinctrl-names = "default";
+- pinctrl-0 = <&spi4_pins>;
+-};
+-
+-spi5_pins: &rp1_spi5_gpio13 {};
+-&spi5 {
+- pinctrl-names = "default";
+- pinctrl-0 = <&spi5_pins>;
+-};
+--- a/arch/arm/boot/dts/broadcom/bcm2712.dtsi
++++ /dev/null
+@@ -1,1302 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0
+-#include <dt-bindings/interrupt-controller/arm-gic.h>
+-#include <dt-bindings/soc/bcm2835-pm.h>
+-#include <dt-bindings/phy/phy.h>
+-
+-/ {
+- compatible = "brcm,bcm2712", "brcm,bcm2711";
+- model = "BCM2712";
+-
+- #address-cells = <2>;
+- #size-cells = <1>;
+-
+- interrupt-parent = <&gicv2>;
+-
+- rmem: reserved-memory {
+- #address-cells = <2>;
+- #size-cells = <1>;
+- ranges;
+-
+- atf@0 {
+- reg = <0x0 0x0 0x80000>;
+- no-map;
+- };
+-
+- cma: linux,cma {
+- compatible = "shared-dma-pool";
+- size = <0x4000000>; /* 64MB */
+- reusable;
+- linux,cma-default;
+-
+- /*
+- * arm64 reserves the CMA by default somewhere in
+- * ZONE_DMA32, that's not good enough for the BCM2711
+- * as some devices can only address the lower 1G of
+- * memory (ZONE_DMA).
+- */
+- alloc-ranges = <0x0 0x00000000 0x40000000>;
+- };
+- };
+-
+- thermal-zones {
+- cpu_thermal: cpu-thermal {
+- polling-delay-passive = <2000>;
+- polling-delay = <1000>;
+- coefficients = <(-550) 450000>;
+- thermal-sensors = <&thermal>;
+-
+- thermal_trips: trips {
+- cpu_crit: cpu-crit {
+- temperature = <110000>;
+- hysteresis = <0>;
+- type = "critical";
+- };
+- };
+-
+- cooling_maps: cooling-maps {
+- };
+- };
+- };
+-
+- clk_27MHz: clk-27M {
+- #clock-cells = <0>;
+- compatible = "fixed-clock";
+- clock-frequency = <27000000>;
+- clock-output-names = "27MHz-clock";
+- };
+-
+- clk_108MHz: clk-108M {
+- #clock-cells = <0>;
+- compatible = "fixed-clock";
+- clock-frequency = <108000000>;
+- clock-output-names = "108MHz-clock";
+- };
+-
+- hvs: hvs@107c580000 {
+- compatible = "brcm,bcm2712-hvs";
+- reg = <0x10 0x7c580000 0x1a000>;
+- interrupt-parent = <&disp_intr>;
+- interrupts = <2>, <9>, <16>;
+- interrupt-names = "ch0-eof", "ch1-eof", "ch2-eof";
+- //iommus = <&iommu4>;
+- status = "disabled";
+- };
+-
+- soc: soc {
+- compatible = "simple-bus";
+- #address-cells = <1>;
+- #size-cells = <1>;
+-
+- ranges = <0x7c000000 0x10 0x7c000000 0x04000000>;
+- /* Emulate a contiguous 30-bit address range for DMA */
+- dma-ranges = <0xc0000000 0x00 0x00000000 0x40000000>,
+- <0x7c000000 0x10 0x7c000000 0x04000000>;
+-
+- system_timer: timer@7c003000 {
+- compatible = "brcm,bcm2835-system-timer";
+- reg = <0x7c003000 0x1000>;
+- interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
+- clock-frequency = <1000000>;
+- };
+-
+- firmwarekms: firmwarekms@7d503000 {
+- compatible = "raspberrypi,rpi-firmware-kms-2712";
+- /* SUN_L2 interrupt reg */
+- reg = <0x7d503000 0x18>;
+- interrupt-parent = <&cpu_l2_irq>;
+- interrupts = <19>;
+- brcm,firmware = <&firmware>;
+- status = "disabled";
+- };
+-
+- axiperf: axiperf {
+- compatible = "brcm,bcm2712-axiperf";
+- reg = <0x7c012800 0x100>,
+- <0x7e000000 0x100>;
+- firmware = <&firmware>;
+- status = "disabled";
+- };
+-
+- mailbox: mailbox@7c013880 {
+- compatible = "brcm,bcm2835-mbox";
+- reg = <0x7c013880 0x40>;
+- interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
+- #mbox-cells = <0>;
+- };
+-
+- pixelvalve0: pixelvalve@7c410000 {
+- compatible = "brcm,bcm2712-pixelvalve0";
+- reg = <0x7c410000 0x100>;
+- interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
+- status = "disabled";
+- };
+-
+- pixelvalve1: pixelvalve@7c411000 {
+- compatible = "brcm,bcm2712-pixelvalve1";
+- reg = <0x7c411000 0x100>;
+- interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
+- status = "disabled";
+- };
+-
+- mop: mop@7c500000 {
+- compatible = "brcm,bcm2712-mop";
+- reg = <0x7c500000 0x28>;
+- interrupt-parent = <&disp_intr>;
+- interrupts = <1>;
+- status = "disabled";
+- };
+-
+- moplet: moplet@7c501000 {
+- compatible = "brcm,bcm2712-moplet";
+- reg = <0x7c501000 0x20>;
+- interrupt-parent = <&disp_intr>;
+- interrupts = <0>;
+- status = "disabled";
+- };
+-
+- disp_intr: interrupt-controller@7c502000 {
+- compatible = "brcm,bcm2711-l2-intc", "brcm,l2-intc";
+- reg = <0x7c502000 0x30>;
+- interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
+- interrupt-controller;
+- #interrupt-cells = <1>;
+- status = "disabled";
+- };
+-
+- dvp: clock@7c700000 {
+- compatible = "brcm,brcm2711-dvp";
+- reg = <0x7c700000 0x10>;
+- clocks = <&clk_108MHz>;
+- #clock-cells = <1>;
+- #reset-cells = <1>;
+- };
+-
+- /*
+- * This node is the provider for the enable-method for
+- * bringing up secondary cores.
+- */
+- local_intc: local_intc@7cd00000 {
+- compatible = "brcm,bcm2836-l1-intc";
+- reg = <0x7cd00000 0x100>;
+- };
+-
+- uart0: serial@7d001000 {
+- compatible = "arm,pl011", "arm,primecell";
+- reg = <0x7d001000 0x200>;
+- interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clk_uart>,
+- <&clk_vpu>;
+- clock-names = "uartclk", "apb_pclk";
+- arm,primecell-periphid = <0x00241011>;
+- status = "disabled";
+- };
+-
+- uart2: serial@7d001400 {
+- compatible = "arm,pl011", "arm,primecell";
+- reg = <0x7d001400 0x200>;
+- interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clk_uart>,
+- <&clk_vpu>;
+- clock-names = "uartclk", "apb_pclk";
+- arm,primecell-periphid = <0x00241011>;
+- status = "disabled";
+- };
+-
+- uart5: serial@7d001a00 {
+- compatible = "arm,pl011", "arm,primecell";
+- reg = <0x7d001a00 0x200>;
+- interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clk_uart>,
+- <&clk_vpu>;
+- clock-names = "uartclk", "apb_pclk";
+- arm,primecell-periphid = <0x00241011>;
+- status = "disabled";
+- };
+-
+- sdhost: mmc@7d002000 {
+- compatible = "brcm,bcm2835-sdhost";
+- reg = <0x7d002000 0x100>;
+- //interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clk_vpu>;
+- status = "disabled";
+- };
+-
+- i2s: i2s@7d003000 {
+- compatible = "brcm,bcm2835-i2s";
+- reg = <0x7d003000 0x24>;
+- //clocks = <&cprman BCM2835_CLOCK_PCM>;
+- status = "disabled";
+- };
+-
+- spi0: spi@7d004000 {
+- compatible = "brcm,bcm2835-spi";
+- reg = <0x7d004000 0x200>;
+- interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clk_vpu>;
+- num-cs = <1>;
+- #address-cells = <1>;
+- #size-cells = <0>;
+- status = "disabled";
+- };
+-
+- spi3: spi@7d004600 {
+- compatible = "brcm,bcm2835-spi";
+- reg = <0x7d004600 0x0200>;
+- interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clk_vpu>;
+- #address-cells = <1>;
+- #size-cells = <0>;
+- status = "disabled";
+- };
+-
+- spi4: spi@7d004800 {
+- compatible = "brcm,bcm2835-spi";
+- reg = <0x7d004800 0x0200>;
+- interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clk_vpu>;
+- #address-cells = <1>;
+- #size-cells = <0>;
+- status = "disabled";
+- };
+-
+- spi5: spi@7d004a00 {
+- compatible = "brcm,bcm2835-spi";
+- reg = <0x7d004a00 0x0200>;
+- interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clk_vpu>;
+- #address-cells = <1>;
+- #size-cells = <0>;
+- status = "disabled";
+- };
+-
+- spi6: spi@7d004c00 {
+- compatible = "brcm,bcm2835-spi";
+- reg = <0x7d004c00 0x0200>;
+- interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clk_vpu>;
+- #address-cells = <1>;
+- #size-cells = <0>;
+- status = "disabled";
+- };
+-
+- i2c0: i2c@7d005000 {
+- compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
+- reg = <0x7d005000 0x20>;
+- interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clk_vpu>;
+- #address-cells = <1>;
+- #size-cells = <0>;
+- status = "disabled";
+- };
+-
+- i2c3: i2c@7d005600 {
+- compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
+- reg = <0x7d005600 0x20>;
+- interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clk_vpu>;
+- #address-cells = <1>;
+- #size-cells = <0>;
+- status = "disabled";
+- };
+-
+- i2c4: i2c@7d005800 {
+- compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
+- reg = <0x7d005800 0x20>;
+- interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clk_vpu>;
+- #address-cells = <1>;
+- #size-cells = <0>;
+- status = "disabled";
+- };
+-
+- i2c5: i2c@7d005a00 {
+- compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
+- reg = <0x7d005a00 0x20>;
+- interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clk_vpu>;
+- #address-cells = <1>;
+- #size-cells = <0>;
+- status = "disabled";
+- };
+-
+- i2c6: i2c@7d005c00 {
+- compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
+- reg = <0x7d005c00 0x20>;
+- interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clk_vpu>;
+- #address-cells = <1>;
+- #size-cells = <0>;
+- status = "disabled";
+- };
+-
+- i2c8: i2c@7d005e00 {
+- compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
+- reg = <0x7d005e00 0x20>;
+- interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clk_vpu>;
+- #address-cells = <1>;
+- #size-cells = <0>;
+- status = "disabled";
+- };
+-
+- pwm0: pwm@7d00c000 {
+- compatible = "brcm,bcm2835-pwm";
+- reg = <0x7d00c000 0x28>;
+- assigned-clock-rates = <50000000>;
+- #pwm-cells = <3>;
+- status = "disabled";
+- };
+-
+- pwm1: pwm@7d00c800 {
+- compatible = "brcm,bcm2835-pwm";
+- reg = <0x7d00c800 0x28>;
+- assigned-clock-rates = <50000000>;
+- #pwm-cells = <3>;
+- status = "disabled";
+- };
+-
+- pm: watchdog@7d200000 {
+- compatible = "brcm,bcm2712-pm";
+- reg = <0x7d200000 0x308>;
+- reg-names = "pm";
+- #power-domain-cells = <1>;
+- #reset-cells = <1>;
+- //clocks = <&cprman BCM2835_CLOCK_V3D>,
+- // <&cprman BCM2835_CLOCK_PERI_IMAGE>,
+- // <&cprman BCM2835_CLOCK_H264>,
+- // <&cprman BCM2835_CLOCK_ISP>;
+- clock-names = "v3d", "peri_image", "h264", "isp";
+- system-power-controller;
+- };
+-
+- cprman: cprman@7d202000 {
+- compatible = "brcm,bcm2711-cprman";
+- reg = <0x7d202000 0x2000>;
+- #clock-cells = <1>;
+-
+- /* CPRMAN derives almost everything from the
+- * platform's oscillator. However, the DSI
+- * pixel clocks come from the DSI analog PHY.
+- */
+- clocks = <&clk_osc>;
+- status = "disabled";
+- };
+-
+- random: rng@7d208000 {
+- compatible = "brcm,bcm2711-rng200";
+- reg = <0x7d208000 0x28>;
+- status = "okay";
+- };
+-
+- cpu_l2_irq: intc@7d503000 {
+- compatible = "brcm,l2-intc";
+- reg = <0x7d503000 0x18>;
+- interrupts = <GIC_SPI 238 IRQ_TYPE_LEVEL_HIGH>;
+- interrupt-controller;
+- #interrupt-cells = <1>;
+- };
+-
+- pinctrl: pinctrl@7d504100 {
+- compatible = "brcm,bcm2712-pinctrl";
+- reg = <0x7d504100 0x30>;
+-
+- uarta_24_pins: uarta_24_pins {
+- pin_rts {
+- function = "uart0";
+- pins = "gpio24";
+- bias-disable;
+- };
+- pin_cts {
+- function = "uart0";
+- pins = "gpio25";
+- bias-pull-up;
+- };
+- pin_txd {
+- function = "uart0";
+- pins = "gpio26";
+- bias-disable;
+- };
+- pin_rxd {
+- function = "uart0";
+- pins = "gpio27";
+- bias-pull-up;
+- };
+- };
+-
+- sdio2_30_pins: sdio2_30_pins {
+- pin_clk {
+- function = "sd2";
+- pins = "gpio30";
+- bias-disable;
+- };
+- pin_cmd {
+- function = "sd2";
+- pins = "gpio31";
+- bias-pull-up;
+- };
+- pins_dat {
+- function = "sd2";
+- pins = "gpio32", "gpio33", "gpio34", "gpio35";
+- bias-pull-up;
+- };
+- };
+- };
+-
+- ddc0: i2c@7d508200 {
+- compatible = "brcm,brcmstb-i2c";
+- reg = <0x7d508200 0x58>;
+- interrupt-parent = <&bsc_irq>;
+- interrupts = <1>;
+- clock-frequency = <97500>;
+- #address-cells = <1>;
+- #size-cells = <0>;
+- status = "disabled";
+- };
+-
+- ddc1: i2c@7d508280 {
+- compatible = "brcm,brcmstb-i2c";
+- reg = <0x7d508280 0x58>;
+- interrupt-parent = <&bsc_irq>;
+- interrupts = <2>;
+- clock-frequency = <97500>;
+- #address-cells = <1>;
+- #size-cells = <0>;
+- status = "disabled";
+- };
+-
+- bscd: i2c@7d508300 {
+- compatible = "brcm,brcmstb-i2c";
+- reg = <0x7d508300 0x58>;
+- interrupt-parent = <&bsc_irq>;
+- interrupts = <0>;
+- clock-frequency = <200000>;
+- #address-cells = <1>;
+- #size-cells = <0>;
+- status = "disabled";
+- };
+-
+- bsc_irq: intc@7d508380 {
+- compatible = "brcm,bcm7271-l2-intc";
+- reg = <0x7d508380 0x10>;
+- interrupts = <GIC_SPI 242 IRQ_TYPE_LEVEL_HIGH>;
+- interrupt-controller;
+- #interrupt-cells = <1>;
+- };
+-
+- main_irq: intc@7d508400 {
+- compatible = "brcm,bcm7271-l2-intc";
+- reg = <0x7d508400 0x10>;
+- interrupts = <GIC_SPI 244 IRQ_TYPE_LEVEL_HIGH>;
+- interrupt-controller;
+- #interrupt-cells = <1>;
+- };
+-
+- gio: gpio@7d508500 {
+- compatible = "brcm,brcmstb-gpio";
+- reg = <0x7d508500 0x40>;
+- interrupt-parent = <&main_irq>;
+- interrupts = <0>;
+- gpio-controller;
+- #gpio-cells = <2>;
+- interrupt-controller;
+- #interrupt-cells = <2>;
+- brcm,gpio-bank-widths = <32 22>;
+- brcm,gpio-direct;
+- };
+-
+- uarta: serial@7d50c000 {
+- compatible = "brcm,bcm7271-uart";
+- reg = <0x7d50c000 0x20>;
+- reg-names = "uart";
+- reg-shift = <2>;
+- reg-io-width = <4>;
+- interrupts = <GIC_SPI 276 IRQ_TYPE_LEVEL_HIGH>;
+- skip-init;
+- status = "disabled";
+- };
+-
+- uartb: serial@7d50d000 {
+- compatible = "brcm,bcm7271-uart";
+- reg = <0x7d50d000 0x20>;
+- reg-names = "uart";
+- reg-shift = <2>;
+- reg-io-width = <4>;
+- interrupts = <GIC_SPI 277 IRQ_TYPE_LEVEL_HIGH>;
+- skip-init;
+- status = "disabled";
+- };
+-
+- aon_intr: interrupt-controller@7d510600 {
+- compatible = "brcm,bcm2711-l2-intc", "brcm,l2-intc";
+- reg = <0x7d510600 0x30>;
+- interrupts = <GIC_SPI 239 IRQ_TYPE_LEVEL_HIGH>;
+- interrupt-controller;
+- #interrupt-cells = <1>;
+- status = "disabled";
+- };
+-
+- pinctrl_aon: pinctrl@7d510700 {
+- compatible = "brcm,bcm2712-aon-pinctrl";
+- reg = <0x7d510700 0x20>;
+-
+- i2c3_m4_agpio0_pins: i2c3_m4_agpio0_pins {
+- function = "vc_i2c3";
+- pins = "aon_gpio0", "aon_gpio1";
+- bias-pull-up;
+- };
+-
+- bsc_m1_agpio13_pins: bsc_m1_agpio13_pins {
+- function = "bsc_m1";
+- pins = "aon_gpio13", "aon_gpio14";
+- bias-pull-up;
+- };
+-
+- bsc_pmu_sgpio4_pins: bsc_pmu_sgpio4_pins {
+- function = "avs_pmu_bsc";
+- pins = "aon_sgpio4", "aon_sgpio5";
+- };
+-
+- bsc_m2_sgpio4_pins: bsc_m2_sgpio4_pins {
+- function = "bsc_m2";
+- pins = "aon_sgpio4", "aon_sgpio5";
+- };
+-
+- pwm_aon_agpio1_pins: pwm_aon_agpio1_pins {
+- function = "aon_pwm";
+- pins = "aon_gpio1", "aon_gpio2";
+- };
+-
+- pwm_aon_agpio4_pins: pwm_aon_agpio4_pins {
+- function = "vc_pwm0";
+- pins = "aon_gpio4", "aon_gpio5";
+- };
+-
+- pwm_aon_agpio7_pins: pwm_aon_agpio7_pins {
+- function = "aon_pwm";
+- pins = "aon_gpio7", "aon_gpio9";
+- };
+- };
+-
+- intc@7d517000 {
+- compatible = "brcm,bcm7271-l2-intc";
+- reg = <0x7d517000 0x10>;
+- interrupts = <GIC_SPI 247 IRQ_TYPE_LEVEL_HIGH>;
+- interrupt-controller;
+- #interrupt-cells = <1>;
+- status = "disabled";
+- };
+-
+- bscc: i2c@7d517a00 {
+- compatible = "brcm,brcmstb-i2c";
+- reg = <0x7d517a00 0x58>;
+- interrupt-parent = <&bsc_aon_irq>;
+- interrupts = <0>;
+- clock-frequency = <200000>;
+- #address-cells = <1>;
+- #size-cells = <0>;
+- status = "disabled";
+- };
+-
+- pwm_aon: pwm@7d517a80 {
+- compatible = "brcm,bcm7038-pwm";
+- reg = <0x7d517a80 0x28>;
+- #pwm-cells = <3>;
+- clocks = <&clk_27MHz>;
+- };
+-
+- main_aon_irq: intc@7d517ac0 {
+- compatible = "brcm,bcm7271-l2-intc";
+- reg = <0x7d517ac0 0x10>;
+- interrupts = <GIC_SPI 245 IRQ_TYPE_LEVEL_HIGH>;
+- interrupt-controller;
+- #interrupt-cells = <1>;
+- };
+-
+- bsc_aon_irq: intc@7d517b00 {
+- compatible = "brcm,bcm7271-l2-intc";
+- reg = <0x7d517b00 0x10>;
+- interrupts = <GIC_SPI 243 IRQ_TYPE_LEVEL_HIGH>;
+- interrupt-controller;
+- #interrupt-cells = <1>;
+- };
+-
+- gio_aon: gpio@7d517c00 {
+- compatible = "brcm,brcmstb-gpio";
+- reg = <0x7d517c00 0x40>;
+- interrupt-parent = <&main_aon_irq>;
+- interrupts = <0>;
+- gpio-controller;
+- #gpio-cells = <2>;
+- interrupt-controller;
+- #interrupt-cells = <2>;
+- brcm,gpio-bank-widths = <17 6>;
+- brcm,gpio-direct;
+- };
+-
+- avs_monitor: avs-monitor@7d542000 {
+- compatible = "brcm,bcm2711-avs-monitor",
+- "syscon", "simple-mfd";
+- reg = <0x7d542000 0xf00>;
+- status = "okay";
+-
+- thermal: thermal {
+- compatible = "brcm,bcm2711-thermal";
+- #thermal-sensor-cells = <0>;
+- };
+- };
+-
+- bsc_pmu: i2c@7d544000 {
+- compatible = "brcm,brcmstb-i2c";
+- reg = <0x7d544000 0x58>;
+- interrupt-parent = <&bsc_aon_irq>;
+- interrupts = <1>;
+- clock-frequency = <200000>;
+- status = "disabled";
+- };
+-
+- hdmi0: hdmi@7ef00700 {
+- compatible = "brcm,bcm2712-hdmi0";
+- reg = <0x7c701400 0x300>,
+- <0x7c701000 0x200>,
+- <0x7c701d00 0x300>,
+- <0x7c702000 0x80>,
+- <0x7c703800 0x200>,
+- <0x7c704000 0x800>,
+- <0x7c700100 0x80>,
+- <0x7d510800 0x100>,
+- <0x7c720000 0x100>;
+- reg-names = "hdmi",
+- "dvp",
+- "phy",
+- "rm",
+- "packet",
+- "metadata",
+- "csc",
+- "cec",
+- "hd";
+- resets = <&dvp 1>;
+- interrupt-parent = <&aon_intr>;
+- interrupts = <1>, <2>, <3>,
+- <7>, <8>;
+- interrupt-names = "cec-tx", "cec-rx", "cec-low",
+- "hpd-connected", "hpd-removed";
+- ddc = <&ddc0>;
+- dmas = <&dma32 10>;
+- dma-names = "audio-rx";
+- status = "disabled";
+- };
+-
+- hdmi1: hdmi@7ef05700 {
+- compatible = "brcm,bcm2712-hdmi1";
+- reg = <0x7c706400 0x300>,
+- <0x7c706000 0x200>,
+- <0x7c706d00 0x300>,
+- <0x7c707000 0x80>,
+- <0x7c708800 0x200>,
+- <0x7c709000 0x800>,
+- <0x7c700180 0x80>,
+- <0x7d511000 0x100>,
+- <0x7c720000 0x100>;
+- reg-names = "hdmi",
+- "dvp",
+- "phy",
+- "rm",
+- "packet",
+- "metadata",
+- "csc",
+- "cec",
+- "hd";
+- ddc = <&ddc1>;
+- resets = <&dvp 2>;
+- interrupt-parent = <&aon_intr>;
+- interrupts = <11>, <12>, <13>,
+- <14>, <15>;
+- interrupt-names = "cec-tx", "cec-rx", "cec-low",
+- "hpd-connected", "hpd-removed";
+- dmas = <&dma32 17>;
+- dma-names = "audio-rx";
+- status = "disabled";
+- };
+- };
+-
+- arm-pmu {
+- compatible = "arm,cortex-a76-pmu";
+- interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
+- interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>;
+- };
+-
+- timer {
+- compatible = "arm,armv8-timer";
+- interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) |
+- IRQ_TYPE_LEVEL_LOW)>,
+- <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) |
+- IRQ_TYPE_LEVEL_LOW)>,
+- <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) |
+- IRQ_TYPE_LEVEL_LOW)>,
+- <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) |
+- IRQ_TYPE_LEVEL_LOW)>;
+- /* This only applies to the ARMv7 stub */
+- arm,cpu-registers-not-fw-configured;
+- };
+-
+- cpus: cpus {
+- #address-cells = <1>;
+- #size-cells = <0>;
+- enable-method = "brcm,bcm2836-smp"; // for ARM 32-bit
+-
+- /* Source for d/i cache-line-size, cache-sets, cache-size
+- * https://developer.arm.com/documentation/100798/0401
+- * /L1-memory-system/About-the-L1-memory-system?lang=en
+- */
+- cpu0: cpu@0 {
+- device_type = "cpu";
+- compatible = "arm,cortex-a76";
+- reg = <0x000>;
+- enable-method = "psci";
+- d-cache-size = <0x10000>;
+- d-cache-line-size = <64>;
+- d-cache-sets = <256>; // 64KiB(size)/64(line-size)=1024ways/4-way set
+- i-cache-size = <0x10000>;
+- i-cache-line-size = <64>;
+- i-cache-sets = <256>; // 64KiB(size)/64(line-size)=1024ways/4-way set
+- next-level-cache = <&l2_cache_l0>;
+- };
+-
+- cpu1: cpu@1 {
+- device_type = "cpu";
+- compatible = "arm,cortex-a76";
+- reg = <0x100>;
+- enable-method = "psci";
+- d-cache-size = <0x10000>;
+- d-cache-line-size = <64>;
+- d-cache-sets = <256>; // 64KiB(size)/64(line-size)=1024ways/4-way set
+- i-cache-size = <0x10000>;
+- i-cache-line-size = <64>;
+- i-cache-sets = <256>; // 64KiB(size)/64(line-size)=1024ways/4-way set
+- next-level-cache = <&l2_cache_l1>;
+- };
+-
+- cpu2: cpu@2 {
+- device_type = "cpu";
+- compatible = "arm,cortex-a76";
+- reg = <0x200>;
+- enable-method = "psci";
+- d-cache-size = <0x10000>;
+- d-cache-line-size = <64>;
+- d-cache-sets = <256>; // 64KiB(size)/64(line-size)=1024ways/4-way set
+- i-cache-size = <0x10000>;
+- i-cache-line-size = <64>;
+- i-cache-sets = <256>; // 64KiB(size)/64(line-size)=1024ways/4-way set
+- next-level-cache = <&l2_cache_l2>;
+- };
+-
+- cpu3: cpu@3 {
+- device_type = "cpu";
+- compatible = "arm,cortex-a76";
+- reg = <0x300>;
+- enable-method = "psci";
+- d-cache-size = <0x10000>;
+- d-cache-line-size = <64>;
+- d-cache-sets = <256>; // 64KiB(size)/64(line-size)=1024ways/4-way set
+- i-cache-size = <0x10000>;
+- i-cache-line-size = <64>;
+- i-cache-sets = <256>; // 64KiB(size)/64(line-size)=1024ways/4-way set
+- next-level-cache = <&l2_cache_l3>;
+- };
+-
+- /* Source for cache-line-size and cache-sets:
+- * https://developer.arm.com/documentation/100798/0401
+- * /L2-memory-system/About-the-L2-memory-system?lang=en
+- * and for cache-size:
+- * https://www.raspberrypi.com/documentation/computers
+- * /processors.html#bcm2712
+- */
+- l2_cache_l0: l2-cache-l0 {
+- compatible = "cache";
+- cache-size = <0x80000>;
+- cache-line-size = <128>;
+- cache-sets = <1024>; // 512KiB(size)/64(line-size)=8192ways/8-way set
+- cache-level = <2>;
+- cache-unified;
+- next-level-cache = <&l3_cache>;
+- };
+-
+- l2_cache_l1: l2-cache-l1 {
+- compatible = "cache";
+- cache-size = <0x80000>;
+- cache-line-size = <128>;
+- cache-sets = <1024>; // 512KiB(size)/64(line-size)=8192ways/8-way set
+- cache-level = <2>;
+- cache-unified;
+- next-level-cache = <&l3_cache>;
+- };
+-
+- l2_cache_l2: l2-cache-l2 {
+- compatible = "cache";
+- cache-size = <0x80000>;
+- cache-line-size = <128>;
+- cache-sets = <1024>; // 512KiB(size)/64(line-size)=8192ways/8-way set
+- cache-level = <2>;
+- cache-unified;
+- next-level-cache = <&l3_cache>;
+- };
+-
+- l2_cache_l3: l2-cache-l3 {
+- compatible = "cache";
+- cache-size = <0x80000>;
+- cache-line-size = <128>;
+- cache-sets = <1024>; // 512KiB(size)/64(line-size)=8192ways/8-way set
+- cache-level = <2>;
+- cache-unified;
+- next-level-cache = <&l3_cache>;
+- };
+-
+- /* Source for cache-line-size and cache-sets:
+- * https://developer.arm.com/documentation/100453/0401/L3-cache?lang=en
+- * Source for cache-size:
+- * https://www.raspberrypi.com/documentation/computers/processors.html#bcm2712
+- */
+- l3_cache: l3-cache {
+- compatible = "cache";
+- cache-size = <0x200000>;
+- cache-line-size = <64>;
+- cache-sets = <2048>; // 2MiB(size)/64(line-size)=32768ways/16-way set
+- cache-level = <3>;
+- };
+- };
+-
+- psci {
+- method = "smc";
+- compatible = "arm,psci-1.0", "arm,psci-0.2", "arm,psci";
+- cpu_on = <0xc4000003>;
+- cpu_suspend = <0xc4000001>;
+- cpu_off = <0x84000002>;
+- };
+-
+- axi: axi {
+- compatible = "simple-bus";
+- #address-cells = <2>;
+- #size-cells = <2>;
+-
+- ranges = <0x00 0x00000000 0x00 0x00000000 0x10 0x00000000>,
+- <0x10 0x00000000 0x10 0x00000000 0x01 0x00000000>,
+- <0x14 0x00000000 0x14 0x00000000 0x04 0x00000000>,
+- <0x18 0x00000000 0x18 0x00000000 0x04 0x00000000>,
+- <0x1c 0x00000000 0x1c 0x00000000 0x04 0x00000000>;
+-
+- dma-ranges = <0x00 0x00000000 0x00 0x00000000 0x10 0x00000000>,
+- <0x10 0x00000000 0x10 0x00000000 0x01 0x00000000>,
+- <0x14 0x00000000 0x14 0x00000000 0x04 0x00000000>,
+- <0x18 0x00000000 0x18 0x00000000 0x04 0x00000000>,
+- <0x1c 0x00000000 0x1c 0x00000000 0x04 0x00000000>;
+-
+- vc4: gpu {
+- compatible = "brcm,bcm2712-vc6";
+- };
+-
+- iommu2: iommu@5100 {
+- /* IOMMU2 for PISP-BE, HEVC; and (unused) H264 accelerators */
+- compatible = "brcm,bcm2712-iommu";
+- reg = <0x10 0x5100 0x0 0x80>;
+- cache = <&iommuc>;
+- #iommu-cells = <0>;
+- };
+-
+- iommu4: iommu@5200 {
+- /* IOMMU4 for HVS, MPL/TXP; and (unused) Unicam, PISP-FE, MiniBVN */
+- compatible = "brcm,bcm2712-iommu";
+- reg = <0x10 0x5200 0x0 0x80>;
+- cache = <&iommuc>;
+- #iommu-cells = <0>;
+- #interconnect-cells = <0>;
+- };
+-
+- iommu5: iommu@5280 {
+- /* IOMMU5 for PCIe2 (RP1); and (unused) BSTM */
+- compatible = "brcm,bcm2712-iommu";
+- reg = <0x10 0x5280 0x0 0x80>;
+- cache = <&iommuc>;
+- #iommu-cells = <0>;
+- dma-iova-offset = <0x10 0x00000000>; // HACK for RP1 masters over PCIe
+- };
+-
+- iommuc: iommuc@5b00 {
+- compatible = "brcm,bcm2712-iommuc";
+- reg = <0x10 0x5b00 0x0 0x80>;
+- };
+-
+- dma32: dma@10000 {
+- compatible = "brcm,bcm2712-dma";
+- reg = <0x10 0x00010000 0 0x600>;
+- interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;
+- interrupt-names = "dma0",
+- "dma1",
+- "dma2",
+- "dma3",
+- "dma4",
+- "dma5";
+- #dma-cells = <1>;
+- brcm,dma-channel-mask = <0x0035>;
+- };
+-
+- dma40: dma@10600 {
+- compatible = "brcm,bcm2712-dma";
+- reg = <0x10 0x00010600 0 0x600>;
+- interrupts =
+- <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>, /* dma4 6 */
+- <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>, /* dma4 7 */
+- <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>, /* dma4 8 */
+- <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>, /* dma4 9 */
+- <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>, /* dma4 10 */
+- <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>; /* dma4 11 */
+- interrupt-names = "dma6",
+- "dma7",
+- "dma8",
+- "dma9",
+- "dma10",
+- "dma11";
+- #dma-cells = <1>;
+- brcm,dma-channel-mask = <0x0fc0>;
+- };
+-
+- // Single-lane Gen3 PCIe
+- // Outbound window at 0x14_000000-0x17_ffffff
+- pcie0: pcie@100000 {
+- compatible = "brcm,bcm2712-pcie";
+- reg = <0x10 0x00100000 0x0 0x9310>;
+- device_type = "pci";
+- max-link-speed = <2>;
+- #address-cells = <3>;
+- #interrupt-cells = <1>;
+- #size-cells = <2>;
+- /*
+- * Unused interrupts:
+- * 208: AER
+- * 215: NMI
+- * 216: PME
+- */
+- interrupt-parent = <&gicv2>;
+- interrupts = <GIC_SPI 213 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 214 IRQ_TYPE_LEVEL_HIGH>;
+- interrupt-names = "pcie", "msi";
+- interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+- interrupt-map = <0 0 0 1 &gicv2 GIC_SPI 209
+- IRQ_TYPE_LEVEL_HIGH>,
+- <0 0 0 2 &gicv2 GIC_SPI 210
+- IRQ_TYPE_LEVEL_HIGH>,
+- <0 0 0 3 &gicv2 GIC_SPI 211
+- IRQ_TYPE_LEVEL_HIGH>,
+- <0 0 0 4 &gicv2 GIC_SPI 212
+- IRQ_TYPE_LEVEL_HIGH>;
+- resets = <&bcm_reset 5>, <&bcm_reset 42>, <&pcie_rescal>;
+- reset-names = "swinit", "bridge", "rescal";
+- msi-controller;
+- msi-parent = <&pcie0>;
+-
+- ranges = <0x02000000 0x00 0x00000000
+- 0x17 0x00000000
+- 0x0 0xfffffffc>,
+- <0x43000000 0x04 0x00000000
+- 0x14 0x00000000
+- 0x3 0x00000000>;
+-
+- dma-ranges = <0x43000000 0x10 0x00000000
+- 0x00 0x00000000
+- 0x10 0x00000000>;
+-
+- status = "disabled";
+- };
+-
+- // Single-lane Gen3 PCIe
+- // Outbound window at 0x18_000000-0x1b_ffffff
+- pcie1: pcie@110000 {
+- compatible = "brcm,bcm2712-pcie";
+- reg = <0x10 0x00110000 0x0 0x9310>;
+- device_type = "pci";
+- max-link-speed = <2>;
+- #address-cells = <3>;
+- #interrupt-cells = <1>;
+- #size-cells = <2>;
+- /*
+- * Unused interrupts:
+- * 218: AER
+- * 225: NMI
+- * 226: PME
+- */
+- interrupt-parent = <&gicv2>;
+- interrupts = <GIC_SPI 223 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 224 IRQ_TYPE_LEVEL_HIGH>;
+- interrupt-names = "pcie", "msi";
+- interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+- interrupt-map = <0 0 0 1 &gicv2 GIC_SPI 219
+- IRQ_TYPE_LEVEL_HIGH>,
+- <0 0 0 2 &gicv2 GIC_SPI 220
+- IRQ_TYPE_LEVEL_HIGH>,
+- <0 0 0 3 &gicv2 GIC_SPI 221
+- IRQ_TYPE_LEVEL_HIGH>,
+- <0 0 0 4 &gicv2 GIC_SPI 222
+- IRQ_TYPE_LEVEL_HIGH>;
+- resets = <&bcm_reset 7>, <&bcm_reset 43>, <&pcie_rescal>;
+- reset-names = "swinit", "bridge", "rescal";
+- msi-controller;
+- msi-parent = <&mip1>;
+-
+- ranges = <0x02000000 0x00 0x00000000
+- 0x1b 0x00000000
+- 0x00 0xfffffffc>,
+- <0x43000000 0x04 0x00000000
+- 0x18 0x00000000
+- 0x03 0x00000000>;
+-
+- dma-ranges = <0x03000000 0x10 0x00000000
+- 0x00 0x00000000
+- 0x10 0x00000000>;
+-
+- status = "disabled";
+- };
+-
+- pcie_rescal: reset-controller@119500 {
+- compatible = "brcm,bcm7216-pcie-sata-rescal";
+- reg = <0x10 0x00119500 0x0 0x10>;
+- #reset-cells = <0>;
+- };
+-
+- // Quad-lane Gen3 PCIe
+- // Outbound window at 0x1c_000000-0x1f_ffffff
+- pcie2: pcie@120000 {
+- compatible = "brcm,bcm2712-pcie";
+- reg = <0x10 0x00120000 0x0 0x9310>;
+- device_type = "pci";
+- max-link-speed = <2>;
+- #address-cells = <3>;
+- #interrupt-cells = <1>;
+- #size-cells = <2>;
+- /*
+- * Unused interrupts:
+- * 228: AER
+- * 235: NMI
+- * 236: PME
+- */
+- interrupt-parent = <&gicv2>;
+- interrupts = <GIC_SPI 233 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 234 IRQ_TYPE_LEVEL_HIGH>;
+- interrupt-names = "pcie", "msi";
+- interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+- interrupt-map = <0 0 0 1 &gicv2 GIC_SPI 229
+- IRQ_TYPE_LEVEL_HIGH>,
+- <0 0 0 2 &gicv2 GIC_SPI 230
+- IRQ_TYPE_LEVEL_HIGH>,
+- <0 0 0 3 &gicv2 GIC_SPI 231
+- IRQ_TYPE_LEVEL_HIGH>,
+- <0 0 0 4 &gicv2 GIC_SPI 232
+- IRQ_TYPE_LEVEL_HIGH>;
+- resets = <&bcm_reset 32>, <&bcm_reset 44>, <&pcie_rescal>;
+- reset-names = "swinit", "bridge", "rescal";
+- msi-controller;
+- msi-parent = <&mip0>;
+-
+- // ~4GB, 32-bit, not-prefetchable at PCIe 00_00000000
+- ranges = <0x02000000 0x00 0x00000000
+- 0x1f 0x00000000
+- 0x0 0xfffffffc>,
+- // 12GB, 64-bit, prefetchable at PCIe 04_00000000
+- <0x43000000 0x04 0x00000000
+- 0x1c 0x00000000
+- 0x03 0x00000000>;
+-
+- // 64GB system RAM space at PCIe 10_00000000
+- dma-ranges = <0x02000000 0x00 0x00000000
+- 0x1f 0x00000000
+- 0x00 0x00400000>,
+- <0x43000000 0x10 0x00000000
+- 0x00 0x00000000
+- 0x10 0x00000000>;
+-
+- status = "disabled";
+- };
+-
+- mip0: msi-controller@130000 {
+- compatible = "brcm,bcm2712-mip-intc";
+- reg = <0x10 0x00130000 0x0 0xc0>;
+- msi-controller;
+- interrupt-controller;
+- #interrupt-cells = <2>;
+- brcm,msi-base-spi = <128>;
+- brcm,msi-num-spis = <64>;
+- brcm,msi-offset = <0>;
+- brcm,msi-pci-addr = <0xff 0xfffff000>;
+- };
+-
+- mip1: msi-controller@131000 {
+- compatible = "brcm,bcm2712-mip-intc";
+- reg = <0x10 0x00131000 0x0 0xc0>;
+- msi-controller;
+- interrupt-controller;
+- #interrupt-cells = <2>;
+- brcm,msi-base-spi = <247>;
+- /* Actually 20 total, but the others are
+- * both sparse and non-consecutive */
+- brcm,msi-num-spis = <8>;
+- brcm,msi-offset = <8>;
+- brcm,msi-pci-addr = <0xff 0xffffe000>;
+- };
+-
+- syscon_piarbctl: syscon@400018 {
+- compatible = "brcm,syscon-piarbctl", "syscon", "simple-mfd";
+- reg = <0x10 0x00400018 0x0 0x18>;
+- };
+-
+- usb: usb@480000 {
+- compatible = "brcm,bcm2835-usb";
+- reg = <0x10 0x00480000 0x0 0x10000>;
+- interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
+- #address-cells = <1>;
+- #size-cells = <0>;
+- clocks = <&clk_usb>;
+- clock-names = "otg";
+- phys = <&usbphy>;
+- phy-names = "usb2-phy";
+- status = "disabled";
+- };
+-
+- rpivid: codec@800000 {
+- compatible = "raspberrypi,rpivid-vid-decoder";
+- reg = <0x10 0x00800000 0x0 0x10000>, /* HEVC */
+- <0x10 0x00840000 0x0 0x1000>; /* INTC */
+- reg-names = "hevc",
+- "intc";
+-
+- interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
+-
+- clocks = <&firmware_clocks 11>;
+- clock-names = "hevc";
+- iommus = <&iommu2>;
+- status = "disabled";
+- };
+-
+- sdio1: mmc@fff000 {
+- compatible = "brcm,bcm2712-sdhci";
+- reg = <0x10 0x00fff000 0x0 0x260>,
+- <0x10 0x00fff400 0x0 0x200>,
+- <0x10 0x015040b0 0x0 0x4>, // Bus isolation control
+- <0x10 0x015200f0 0x0 0x24>; // LCPLL control misc0-8
+- reg-names = "host", "cfg", "busisol", "lcpll";
+- interrupts = <GIC_SPI 273 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clk_emmc2>;
+- sdhci-caps-mask = <0x0000C000 0x0>;
+- sdhci-caps = <0x0 0x0>;
+- mmc-ddr-3_3v;
+- };
+-
+- sdio2: mmc@1100000 {
+- compatible = "brcm,bcm2712-sdhci";
+- reg = <0x10 0x01100000 0x0 0x260>,
+- <0x10 0x01100400 0x0 0x200>;
+- reg-names = "host", "cfg";
+- interrupts = <GIC_SPI 274 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clk_emmc2>;
+- sdhci-caps-mask = <0x0000C000 0x0>;
+- sdhci-caps = <0x0 0x0>;
+- supports-cqe;
+- mmc-ddr-3_3v;
+- status = "disabled";
+- };
+-
+- bcm_reset: reset-controller@1504318 {
+- compatible = "brcm,brcmstb-reset";
+- reg = <0x10 0x01504318 0x0 0x30>;
+- #reset-cells = <1>;
+- };
+-
+- v3d: v3d@2000000 {
+- compatible = "brcm,2712-v3d";
+- reg = <0x10 0x02000000 0x0 0x4000>,
+- <0x10 0x02008000 0x0 0x6000>;
+- reg-names = "hub", "core0";
+-
+- power-domains = <&pm BCM2835_POWER_DOMAIN_GRAFX_V3D>;
+- resets = <&pm BCM2835_RESET_V3D>;
+- clocks = <&firmware_clocks 5>;
+- clocks-names = "v3d";
+- interrupts = <GIC_SPI 250 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 249 IRQ_TYPE_LEVEL_HIGH>;
+- status = "disabled";
+- };
+-
+- gicv2: interrupt-controller@7fff9000 {
+- interrupt-controller;
+- #interrupt-cells = <3>;
+- compatible = "arm,gic-400";
+- reg = <0x10 0x7fff9000 0x0 0x1000>,
+- <0x10 0x7fffa000 0x0 0x2000>,
+- <0x10 0x7fffc000 0x0 0x2000>,
+- <0x10 0x7fffe000 0x0 0x2000>;
+- interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) |
+- IRQ_TYPE_LEVEL_HIGH)>;
+- };
+-
+- pisp_be: pisp_be@880000 {
+- compatible = "raspberrypi,pispbe";
+- reg = <0x10 0x00880000 0x0 0x4000>;
+- interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&firmware_clocks 7>;
+- clocks-names = "isp_be";
+- status = "okay";
+- iommus = <&iommu2>;
+- };
+- };
+-
+- clocks {
+- /* The oscillator is the root of the clock tree. */
+- clk_osc: clk-osc {
+- compatible = "fixed-clock";
+- #clock-cells = <0>;
+- clock-output-names = "osc";
+- clock-frequency = <54000000>;
+- };
+-
+- clk_usb: clk-usb {
+- compatible = "fixed-clock";
+- #clock-cells = <0>;
+- clock-output-names = "otg";
+- clock-frequency = <480000000>;
+- };
+-
+- clk_vpu: clk_vpu {
+- #clock-cells = <0>;
+- compatible = "fixed-clock";
+- clock-frequency = <750000000>;
+- clock-output-names = "vpu-clock";
+- };
+-
+- clk_uart: clk_uart {
+- #clock-cells = <0>;
+- compatible = "fixed-clock";
+- clock-frequency = <9216000>;
+- clock-output-names = "uart-clock";
+- };
+-
+- clk_emmc2: clk_emmc2 {
+- #clock-cells = <0>;
+- compatible = "fixed-clock";
+- clock-frequency = <200000000>;
+- clock-output-names = "emmc2-clock";
+- };
+- };
+-
+- usbphy: phy {
+- compatible = "usb-nop-xceiv";
+- #phy-cells = <0>;
+- };
+-};
+--- a/arch/arm/boot/dts/broadcom/rp1.dtsi
++++ /dev/null
+@@ -1,1287 +0,0 @@
+-#include <dt-bindings/clock/rp1.h>
+-#include <dt-bindings/interrupt-controller/irq.h>
+-#include <dt-bindings/mfd/rp1.h>
+-
+-&rp1_target {
+- rp1: rp1 {
+- compatible = "simple-bus";
+- #address-cells = <2>;
+- #size-cells = <2>;
+- #interrupt-cells = <2>;
+- interrupt-controller;
+- interrupt-parent = <&rp1>;
+-
+- // ranges and dma-ranges must be provided by the includer
+-
+- rp1_clocks: clocks@18000 {
+- compatible = "raspberrypi,rp1-clocks";
+- #clock-cells = <1>;
+- reg = <0xc0 0x40018000 0x0 0x10038>;
+- clocks = <&clk_xosc>;
+-
+- assigned-clocks = <&rp1_clocks RP1_PLL_SYS_CORE>,
+- <&rp1_clocks RP1_PLL_AUDIO_CORE>,
+- // RP1_PLL_VIDEO_CORE and dividers are now managed by VEC,DPI drivers
+- <&rp1_clocks RP1_PLL_SYS>,
+- <&rp1_clocks RP1_PLL_SYS_SEC>,
+- <&rp1_clocks RP1_PLL_AUDIO>,
+- <&rp1_clocks RP1_PLL_AUDIO_SEC>,
+- <&rp1_clocks RP1_CLK_SYS>,
+- <&rp1_clocks RP1_PLL_SYS_PRI_PH>,
+- // RP1_CLK_SLOW_SYS is used for the frequency counter (FC0)
+- <&rp1_clocks RP1_CLK_SLOW_SYS>,
+- <&rp1_clocks RP1_CLK_SDIO_TIMER>,
+- <&rp1_clocks RP1_CLK_SDIO_ALT_SRC>,
+- <&rp1_clocks RP1_CLK_ETH_TSU>;
+-
+- assigned-clock-rates = <1000000000>, // RP1_PLL_SYS_CORE
+- <1536000000>, // RP1_PLL_AUDIO_CORE
+- <200000000>, // RP1_PLL_SYS
+- <125000000>, // RP1_PLL_SYS_SEC
+- <61440000>, // RP1_PLL_AUDIO
+- <192000000>, // RP1_PLL_AUDIO_SEC
+- <200000000>, // RP1_CLK_SYS
+- <100000000>, // RP1_PLL_SYS_PRI_PH
+- // Must match the XOSC frequency
+- <50000000>, // RP1_CLK_SLOW_SYS
+- <1000000>, // RP1_CLK_SDIO_TIMER
+- <200000000>, // RP1_CLK_SDIO_ALT_SRC
+- <50000000>; // RP1_CLK_ETH_TSU
+- };
+-
+- rp1_uart0: serial@30000 {
+- compatible = "arm,pl011-axi";
+- reg = <0xc0 0x40030000 0x0 0x100>;
+- interrupts = <RP1_INT_UART0 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&rp1_clocks RP1_CLK_UART &rp1_clocks RP1_PLL_SYS_PRI_PH>;
+- clock-names = "uartclk", "apb_pclk";
+- dmas = <&rp1_dma RP1_DMA_UART0_TX>,
+- <&rp1_dma RP1_DMA_UART0_RX>;
+- dma-names = "tx", "rx";
+- pinctrl-names = "default";
+- arm,primecell-periphid = <0x00541011>;
+- uart-has-rtscts;
+- cts-event-workaround;
+- skip-init;
+- status = "disabled";
+- };
+-
+- rp1_uart1: serial@34000 {
+- compatible = "arm,pl011-axi";
+- reg = <0xc0 0x40034000 0x0 0x100>;
+- interrupts = <RP1_INT_UART1 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&rp1_clocks RP1_CLK_UART &rp1_clocks RP1_PLL_SYS_PRI_PH>;
+- clock-names = "uartclk", "apb_pclk";
+- // dmas = <&rp1_dma RP1_DMA_UART1_TX>,
+- // <&rp1_dma RP1_DMA_UART1_RX>;
+- // dma-names = "tx", "rx";
+- pinctrl-names = "default";
+- arm,primecell-periphid = <0x00541011>;
+- uart-has-rtscts;
+- cts-event-workaround;
+- skip-init;
+- status = "disabled";
+- };
+-
+- rp1_uart2: serial@38000 {
+- compatible = "arm,pl011-axi";
+- reg = <0xc0 0x40038000 0x0 0x100>;
+- interrupts = <RP1_INT_UART2 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&rp1_clocks RP1_CLK_UART &rp1_clocks RP1_PLL_SYS_PRI_PH>;
+- clock-names = "uartclk", "apb_pclk";
+- // dmas = <&rp1_dma RP1_DMA_UART2_TX>,
+- // <&rp1_dma RP1_DMA_UART2_RX>;
+- // dma-names = "tx", "rx";
+- pinctrl-names = "default";
+- arm,primecell-periphid = <0x00541011>;
+- uart-has-rtscts;
+- cts-event-workaround;
+- skip-init;
+- status = "disabled";
+- };
+-
+- rp1_uart3: serial@3c000 {
+- compatible = "arm,pl011-axi";
+- reg = <0xc0 0x4003c000 0x0 0x100>;
+- interrupts = <RP1_INT_UART3 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&rp1_clocks RP1_CLK_UART &rp1_clocks RP1_PLL_SYS_PRI_PH>;
+- clock-names = "uartclk", "apb_pclk";
+- // dmas = <&rp1_dma RP1_DMA_UART3_TX>,
+- // <&rp1_dma RP1_DMA_UART3_RX>;
+- // dma-names = "tx", "rx";
+- pinctrl-names = "default";
+- arm,primecell-periphid = <0x00541011>;
+- uart-has-rtscts;
+- cts-event-workaround;
+- skip-init;
+- status = "disabled";
+- };
+-
+- rp1_uart4: serial@40000 {
+- compatible = "arm,pl011-axi";
+- reg = <0xc0 0x40040000 0x0 0x100>;
+- interrupts = <RP1_INT_UART4 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&rp1_clocks RP1_CLK_UART &rp1_clocks RP1_PLL_SYS_PRI_PH>;
+- clock-names = "uartclk", "apb_pclk";
+- // dmas = <&rp1_dma RP1_DMA_UART4_TX>,
+- // <&rp1_dma RP1_DMA_UART4_RX>;
+- // dma-names = "tx", "rx";
+- pinctrl-names = "default";
+- arm,primecell-periphid = <0x00541011>;
+- uart-has-rtscts;
+- cts-event-workaround;
+- skip-init;
+- status = "disabled";
+- };
+-
+- rp1_uart5: serial@44000 {
+- compatible = "arm,pl011-axi";
+- reg = <0xc0 0x40044000 0x0 0x100>;
+- interrupts = <RP1_INT_UART5 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&rp1_clocks RP1_CLK_UART &rp1_clocks RP1_PLL_SYS_PRI_PH>;
+- clock-names = "uartclk", "apb_pclk";
+- // dmas = <&rp1_dma RP1_DMA_UART5_TX>,
+- // <&rp1_dma RP1_DMA_UART5_RX>;
+- // dma-names = "tx", "rx";
+- pinctrl-names = "default";
+- arm,primecell-periphid = <0x00541011>;
+- uart-has-rtscts;
+- cts-event-workaround;
+- skip-init;
+- status = "disabled";
+- };
+-
+- rp1_spi8: spi@4c000 {
+- reg = <0xc0 0x4004c000 0x0 0x130>;
+- compatible = "snps,dw-apb-ssi";
+- interrupts = <RP1_INT_SPI8 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&rp1_clocks RP1_CLK_SYS>;
+- clock-names = "ssi_clk";
+- #address-cells = <1>;
+- #size-cells = <0>;
+- num-cs = <2>;
+- dmas = <&rp1_dma RP1_DMA_SPI8_TX>,
+- <&rp1_dma RP1_DMA_SPI8_RX>;
+- dma-names = "tx", "rx";
+- status = "disabled";
+- };
+-
+- rp1_spi0: spi@50000 {
+- reg = <0xc0 0x40050000 0x0 0x130>;
+- compatible = "snps,dw-apb-ssi";
+- interrupts = <RP1_INT_SPI0 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&rp1_clocks RP1_CLK_SYS>;
+- clock-names = "ssi_clk";
+- #address-cells = <1>;
+- #size-cells = <0>;
+- num-cs = <2>;
+- dmas = <&rp1_dma RP1_DMA_SPI0_TX>,
+- <&rp1_dma RP1_DMA_SPI0_RX>;
+- dma-names = "tx", "rx";
+- status = "disabled";
+- };
+-
+- rp1_spi1: spi@54000 {
+- reg = <0xc0 0x40054000 0x0 0x130>;
+- compatible = "snps,dw-apb-ssi";
+- interrupts = <RP1_INT_SPI1 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&rp1_clocks RP1_CLK_SYS>;
+- clock-names = "ssi_clk";
+- #address-cells = <1>;
+- #size-cells = <0>;
+- num-cs = <2>;
+- dmas = <&rp1_dma RP1_DMA_SPI1_TX>,
+- <&rp1_dma RP1_DMA_SPI1_RX>;
+- dma-names = "tx", "rx";
+- status = "disabled";
+- };
+-
+- rp1_spi2: spi@58000 {
+- reg = <0xc0 0x40058000 0x0 0x130>;
+- compatible = "snps,dw-apb-ssi";
+- interrupts = <RP1_INT_SPI2 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&rp1_clocks RP1_CLK_SYS>;
+- clock-names = "ssi_clk";
+- #address-cells = <1>;
+- #size-cells = <0>;
+- num-cs = <2>;
+- dmas = <&rp1_dma RP1_DMA_SPI2_TX>,
+- <&rp1_dma RP1_DMA_SPI2_RX>;
+- dma-names = "tx", "rx";
+- status = "disabled";
+- };
+-
+- rp1_spi3: spi@5c000 {
+- reg = <0xc0 0x4005c000 0x0 0x130>;
+- compatible = "snps,dw-apb-ssi";
+- interrupts = <RP1_INT_SPI3 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&rp1_clocks RP1_CLK_SYS>;
+- clock-names = "ssi_clk";
+- #address-cells = <1>;
+- #size-cells = <0>;
+- num-cs = <2>;
+- dmas = <&rp1_dma RP1_DMA_SPI3_TX>,
+- <&rp1_dma RP1_DMA_SPI3_RX>;
+- dma-names = "tx", "rx";
+- status = "disabled";
+- };
+-
+- // SPI4 is a target/slave interface
+- rp1_spi4: spi@60000 {
+- reg = <0xc0 0x40060000 0x0 0x130>;
+- compatible = "snps,dw-apb-ssi";
+- interrupts = <RP1_INT_SPI4 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&rp1_clocks RP1_CLK_SYS>;
+- clock-names = "ssi_clk";
+- #address-cells = <0>;
+- #size-cells = <0>;
+- num-cs = <1>;
+- spi-slave;
+- dmas = <&rp1_dma RP1_DMA_SPI4_TX>,
+- <&rp1_dma RP1_DMA_SPI4_RX>;
+- dma-names = "tx", "rx";
+- status = "disabled";
+-
+- slave {
+- compatible = "spidev";
+- spi-max-frequency = <1000000>;
+- };
+- };
+-
+- rp1_spi5: spi@64000 {
+- reg = <0xc0 0x40064000 0x0 0x130>;
+- compatible = "snps,dw-apb-ssi";
+- interrupts = <RP1_INT_SPI5 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&rp1_clocks RP1_CLK_SYS>;
+- clock-names = "ssi_clk";
+- #address-cells = <1>;
+- #size-cells = <0>;
+- num-cs = <2>;
+- dmas = <&rp1_dma RP1_DMA_SPI5_TX>,
+- <&rp1_dma RP1_DMA_SPI5_RX>;
+- dma-names = "tx", "rx";
+- status = "disabled";
+- };
+-
+- rp1_spi6: spi@68000 {
+- reg = <0xc0 0x40068000 0x0 0x130>;
+- compatible = "snps,dw-apb-ssi";
+- interrupts = <RP1_INT_SPI6 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&rp1_clocks RP1_CLK_SYS>;
+- clock-names = "ssi_clk";
+- #address-cells = <1>;
+- #size-cells = <0>;
+- num-cs = <2>;
+- dmas = <&rp1_dma RP1_DMA_SPI6_TX>,
+- <&rp1_dma RP1_DMA_SPI6_RX>;
+- dma-names = "tx", "rx";
+- status = "disabled";
+- };
+-
+- // SPI7 is a target/slave interface
+- rp1_spi7: spi@6c000 {
+- reg = <0xc0 0x4006c000 0x0 0x130>;
+- compatible = "snps,dw-apb-ssi";
+- interrupts = <RP1_INT_SPI7 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&rp1_clocks RP1_CLK_SYS>;
+- clock-names = "ssi_clk";
+- #address-cells = <0>;
+- #size-cells = <0>;
+- num-cs = <1>;
+- spi-slave;
+- dmas = <&rp1_dma RP1_DMA_SPI7_TX>,
+- <&rp1_dma RP1_DMA_SPI7_RX>;
+- dma-names = "tx", "rx";
+- status = "disabled";
+-
+- slave {
+- compatible = "spidev";
+- spi-max-frequency = <1000000>;
+- };
+- };
+-
+- rp1_i2c0: i2c@70000 {
+- reg = <0xc0 0x40070000 0x0 0x1000>;
+- compatible = "snps,designware-i2c";
+- interrupts = <RP1_INT_I2C0 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&rp1_clocks RP1_CLK_SYS>;
+- i2c-scl-rising-time-ns = <65>;
+- i2c-scl-falling-time-ns = <100>;
+- status = "disabled";
+- };
+-
+- rp1_i2c1: i2c@74000 {
+- reg = <0xc0 0x40074000 0x0 0x1000>;
+- compatible = "snps,designware-i2c";
+- interrupts = <RP1_INT_I2C1 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&rp1_clocks RP1_CLK_SYS>;
+- i2c-scl-rising-time-ns = <65>;
+- i2c-scl-falling-time-ns = <100>;
+- status = "disabled";
+- };
+-
+- rp1_i2c2: i2c@78000 {
+- reg = <0xc0 0x40078000 0x0 0x1000>;
+- compatible = "snps,designware-i2c";
+- interrupts = <RP1_INT_I2C2 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&rp1_clocks RP1_CLK_SYS>;
+- i2c-scl-rising-time-ns = <65>;
+- i2c-scl-falling-time-ns = <100>;
+- status = "disabled";
+- };
+-
+- rp1_i2c3: i2c@7c000 {
+- reg = <0xc0 0x4007c000 0x0 0x1000>;
+- compatible = "snps,designware-i2c";
+- interrupts = <RP1_INT_I2C3 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&rp1_clocks RP1_CLK_SYS>;
+- i2c-scl-rising-time-ns = <65>;
+- i2c-scl-falling-time-ns = <100>;
+- status = "disabled";
+- };
+-
+- rp1_i2c4: i2c@80000 {
+- reg = <0xc0 0x40080000 0x0 0x1000>;
+- compatible = "snps,designware-i2c";
+- interrupts = <RP1_INT_I2C4 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&rp1_clocks RP1_CLK_SYS>;
+- i2c-scl-rising-time-ns = <65>;
+- i2c-scl-falling-time-ns = <100>;
+- status = "disabled";
+- };
+-
+- rp1_i2c5: i2c@84000 {
+- reg = <0xc0 0x40084000 0x0 0x1000>;
+- compatible = "snps,designware-i2c";
+- interrupts = <RP1_INT_I2C5 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&rp1_clocks RP1_CLK_SYS>;
+- i2c-scl-rising-time-ns = <65>;
+- i2c-scl-falling-time-ns = <100>;
+- status = "disabled";
+- };
+-
+- rp1_i2c6: i2c@88000 {
+- reg = <0xc0 0x40088000 0x0 0x1000>;
+- compatible = "snps,designware-i2c";
+- interrupts = <RP1_INT_I2C6 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&rp1_clocks RP1_CLK_SYS>;
+- i2c-scl-rising-time-ns = <65>;
+- i2c-scl-falling-time-ns = <100>;
+- status = "disabled";
+- };
+-
+- rp1_pwm0: pwm@98000 {
+- compatible = "raspberrypi,rp1-pwm";
+- reg = <0xc0 0x40098000 0x0 0x100>;
+- #pwm-cells = <3>;
+- clocks = <&rp1_clocks RP1_CLK_PWM0>;
+- assigned-clocks = <&rp1_clocks RP1_CLK_PWM0>;
+- assigned-clock-rates = <50000000>;
+- status = "disabled";
+- };
+-
+- rp1_pwm1: pwm@9c000 {
+- compatible = "raspberrypi,rp1-pwm";
+- reg = <0xc0 0x4009c000 0x0 0x100>;
+- #pwm-cells = <3>;
+- clocks = <&rp1_clocks RP1_CLK_PWM1>;
+- assigned-clocks = <&rp1_clocks RP1_CLK_PWM1>;
+- assigned-clock-rates = <50000000>;
+- status = "disabled";
+- };
+-
+- rp1_i2s0: i2s@a0000 {
+- reg = <0xc0 0x400a0000 0x0 0x1000>;
+- compatible = "snps,designware-i2s";
+- // Providing an interrupt disables DMA
+- // interrupts = <RP1_INT_I2S0 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&rp1_clocks RP1_CLK_I2S>;
+- clock-names = "i2sclk";
+- #sound-dai-cells = <0>;
+- dmas = <&rp1_dma RP1_DMA_I2S0_TX>,<&rp1_dma RP1_DMA_I2S0_RX>;
+- dma-names = "tx", "rx";
+- status = "disabled";
+- };
+-
+- rp1_i2s1: i2s@a4000 {
+- reg = <0xc0 0x400a4000 0x0 0x1000>;
+- compatible = "snps,designware-i2s";
+- // Providing an interrupt disables DMA
+- // interrupts = <RP1_INT_I2S1 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&rp1_clocks RP1_CLK_I2S>;
+- clock-names = "i2sclk";
+- #sound-dai-cells = <0>;
+- dmas = <&rp1_dma RP1_DMA_I2S1_TX>,<&rp1_dma RP1_DMA_I2S1_RX>;
+- dma-names = "tx", "rx";
+- status = "disabled";
+- };
+-
+- rp1_i2s2: i2s@a8000 {
+- reg = <0xc0 0x400a8000 0x0 0x1000>;
+- compatible = "snps,designware-i2s";
+- // Providing an interrupt disables DMA
+- // interrupts = <RP1_INT_I2S2 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&rp1_clocks RP1_CLK_I2S>;
+- status = "disabled";
+- };
+-
+- rp1_sdio_clk0: sdio_clk0@b0004 {
+- compatible = "raspberrypi,rp1-sdio-clk";
+- reg = <0xc0 0x400b0004 0x0 0x1c>;
+- clocks = <&sdio_src &sdhci_core>;
+- clock-names = "src", "base";
+- #clock-cells = <0>;
+- status = "disabled";
+- };
+-
+- rp1_sdio_clk1: sdio_clk1@b4004 {
+- compatible = "raspberrypi,rp1-sdio-clk";
+- reg = <0xc0 0x400b4004 0x0 0x1c>;
+- clocks = <&sdio_src &sdhci_core>;
+- clock-names = "src", "base";
+- #clock-cells = <0>;
+- status = "disabled";
+- };
+-
+- rp1_adc: adc@c8000 {
+- compatible = "raspberrypi,rp1-adc";
+- reg = <0xc0 0x400c8000 0x0 0x4000>;
+- clocks = <&rp1_clocks RP1_CLK_ADC>;
+- clock-names = "adcclk";
+- #clock-cells = <0>;
+- vref-supply = <&rp1_vdd_3v3>;
+- status = "disabled";
+- };
+-
+- rp1_gpio: gpio@d0000 {
+- reg = <0xc0 0x400d0000 0x0 0xc000>,
+- <0xc0 0x400e0000 0x0 0xc000>,
+- <0xc0 0x400f0000 0x0 0xc000>;
+- compatible = "raspberrypi,rp1-gpio";
+- interrupts = <RP1_INT_IO_BANK0 IRQ_TYPE_LEVEL_HIGH>,
+- <RP1_INT_IO_BANK1 IRQ_TYPE_LEVEL_HIGH>,
+- <RP1_INT_IO_BANK2 IRQ_TYPE_LEVEL_HIGH>;
+- gpio-controller;
+- #gpio-cells = <2>;
+- interrupt-controller;
+- #interrupt-cells = <2>;
+- gpio-ranges = <&rp1_gpio 0 0 54>;
+-
+- rp1_uart0_14_15: rp1_uart0_14_15 {
+- pin_txd {
+- function = "uart0";
+- pins = "gpio14";
+- bias-disable;
+- };
+- pin_rxd {
+- function = "uart0";
+- pins = "gpio15";
+- bias-pull-up;
+- };
+- };
+- rp1_uart0_ctsrts_16_17: rp1_uart0_ctsrts_16_17 {
+- pin_cts {
+- function = "uart0";
+- pins = "gpio16";
+- bias-pull-up;
+- };
+- pin_rts {
+- function = "uart0";
+- pins = "gpio17";
+- bias-disable;
+- };
+- };
+- rp1_uart1_0_1: rp1_uart1_0_1 {
+- pin_txd {
+- function = "uart1";
+- pins = "gpio0";
+- bias-disable;
+- };
+- pin_rxd {
+- function = "uart1";
+- pins = "gpio1";
+- bias-pull-up;
+- };
+- };
+- rp1_uart1_ctsrts_2_3: rp1_uart1_ctsrts_2_3 {
+- pin_cts {
+- function = "uart1";
+- pins = "gpio2";
+- bias-pull-up;
+- };
+- pin_rts {
+- function = "uart1";
+- pins = "gpio3";
+- bias-disable;
+- };
+- };
+- rp1_uart2_4_5: rp1_uart2_4_5 {
+- pin_txd {
+- function = "uart2";
+- pins = "gpio4";
+- bias-disable;
+- };
+- pin_rxd {
+- function = "uart2";
+- pins = "gpio5";
+- bias-pull-up;
+- };
+- };
+- rp1_uart2_ctsrts_6_7: rp1_uart2_ctsrts_6_7 {
+- pin_cts {
+- function = "uart2";
+- pins = "gpio6";
+- bias-pull-up;
+- };
+- pin_rts {
+- function = "uart2";
+- pins = "gpio7";
+- bias-disable;
+- };
+- };
+- rp1_uart3_8_9: rp1_uart3_8_9 {
+- pin_txd {
+- function = "uart3";
+- pins = "gpio8";
+- bias-disable;
+- };
+- pin_rxd {
+- function = "uart3";
+- pins = "gpio9";
+- bias-pull-up;
+- };
+- };
+- rp1_uart3_ctsrts_10_11: rp1_uart3_ctsrts_10_11 {
+- pin_cts {
+- function = "uart3";
+- pins = "gpio10";
+- bias-pull-up;
+- };
+- pin_rts {
+- function = "uart3";
+- pins = "gpio11";
+- bias-disable;
+- };
+- };
+- rp1_uart4_12_13: rp1_uart4_12_13 {
+- pin_txd {
+- function = "uart4";
+- pins = "gpio12";
+- bias-disable;
+- };
+- pin_rxd {
+- function = "uart4";
+- pins = "gpio13";
+- bias-pull-up;
+- };
+- };
+- rp1_uart4_ctsrts_14_15: rp1_uart4_ctsrts_14_15 {
+- pin_cts {
+- function = "uart4";
+- pins = "gpio14";
+- bias-pull-up;
+- };
+- pin_rts {
+- function = "uart4";
+- pins = "gpio15";
+- bias-disable;
+- };
+- };
+-
+- rp1_sdio0_22_27: rp1_sdio0_22_27 {
+- pin_clk {
+- function = "sd0";
+- pins = "gpio22";
+- bias-disable;
+- drive-strength = <12>;
+- slew-rate = <1>;
+- };
+- pin_cmd {
+- function = "sd0";
+- pins = "gpio23";
+- bias-pull-up;
+- drive-strength = <12>;
+- slew-rate = <1>;
+- };
+- pins_dat {
+- function = "sd0";
+- pins = "gpio24", "gpio25", "gpio26", "gpio27";
+- bias-pull-up;
+- drive-strength = <12>;
+- slew-rate = <1>;
+- };
+- };
+-
+- rp1_sdio1_28_33: rp1_sdio1_28_33 {
+- pin_clk {
+- function = "sd1";
+- pins = "gpio28";
+- bias-disable;
+- drive-strength = <12>;
+- slew-rate = <1>;
+- };
+- pin_cmd {
+- function = "sd1";
+- pins = "gpio29";
+- bias-pull-up;
+- drive-strength = <12>;
+- slew-rate = <1>;
+- };
+- pins_dat {
+- function = "sd1";
+- pins = "gpio30", "gpio31", "gpio32", "gpio33";
+- bias-pull-up;
+- drive-strength = <12>;
+- slew-rate = <1>;
+- };
+- };
+-
+- rp1_i2s0_18_21: rp1_i2s0_18_21 {
+- function = "i2s0";
+- pins = "gpio18", "gpio19", "gpio20", "gpio21";
+- bias-disable;
+- };
+-
+- rp1_i2s1_18_21: rp1_i2s1_18_21 {
+- function = "i2s1";
+- pins = "gpio18", "gpio19", "gpio20", "gpio21";
+- bias-disable;
+- };
+-
+- rp1_i2c4_34_35: rp1_i2c4_34_35 {
+- function = "i2c4";
+- pins = "gpio34", "gpio35";
+- drive-strength = <12>;
+- bias-pull-up;
+- };
+- rp1_i2c6_38_39: rp1_i2c6_38_39 {
+- function = "i2c6";
+- pins = "gpio38", "gpio39";
+- drive-strength = <12>;
+- bias-pull-up;
+- };
+- rp1_i2c4_40_41: rp1_i2c4_40_41 {
+- function = "i2c4";
+- pins = "gpio40", "gpio41";
+- drive-strength = <12>;
+- bias-pull-up;
+- };
+- rp1_i2c5_44_45: rp1_i2c5_44_45 {
+- function = "i2c5";
+- pins = "gpio44", "gpio45";
+- drive-strength = <12>;
+- bias-pull-up;
+- };
+- rp1_i2c0_0_1: rp1_i2c0_0_1 {
+- function = "i2c0";
+- pins = "gpio0", "gpio1";
+- drive-strength = <12>;
+- bias-pull-up;
+- };
+- rp1_i2c0_8_9: rp1_i2c0_8_9 {
+- function = "i2c0";
+- pins = "gpio8", "gpio9";
+- drive-strength = <12>;
+- bias-pull-up;
+- };
+- rp1_i2c1_2_3: rp1_i2c1_2_3 {
+- function = "i2c1";
+- pins = "gpio2", "gpio3";
+- drive-strength = <12>;
+- bias-pull-up;
+- };
+- rp1_i2c1_10_11: rp1_i2c1_10_11 {
+- function = "i2c1";
+- pins = "gpio10", "gpio11";
+- drive-strength = <12>;
+- bias-pull-up;
+- };
+- rp1_i2c2_4_5: rp1_i2c2_4_5 {
+- function = "i2c2";
+- pins = "gpio4", "gpio5";
+- drive-strength = <12>;
+- bias-pull-up;
+- };
+- rp1_i2c2_12_13: rp1_i2c2_12_13 {
+- function = "i2c2";
+- pins = "gpio12", "gpio13";
+- drive-strength = <12>;
+- bias-pull-up;
+- };
+- rp1_i2c3_6_7: rp1_i2c3_6_7 {
+- function = "i2c3";
+- pins = "gpio6", "gpio7";
+- drive-strength = <12>;
+- bias-pull-up;
+- };
+- rp1_i2c3_14_15: rp1_i2c3_14_15 {
+- function = "i2c3";
+- pins = "gpio14", "gpio15";
+- drive-strength = <12>;
+- bias-pull-up;
+- };
+- rp1_i2c3_22_23: rp1_i2c3_22_23 {
+- function = "i2c3";
+- pins = "gpio22", "gpio23";
+- drive-strength = <12>;
+- bias-pull-up;
+- };
+-
+- // DPI mappings with HSYNC,VSYNC but without PIXCLK,DE
+- rp1_dpi_16bit_gpio2: rp1_dpi_16bit_gpio2 { /* Mode 2, not fully supported by RP1 */
+- function = "dpi";
+- pins = "gpio2", "gpio3", "gpio4", "gpio5",
+- "gpio6", "gpio7", "gpio8", "gpio9",
+- "gpio10", "gpio11", "gpio12", "gpio13",
+- "gpio14", "gpio15", "gpio16", "gpio17",
+- "gpio18", "gpio19";
+- bias-disable;
+- };
+- rp1_dpi_16bit_cpadhi_gpio2: rp1_dpi_16bit_cpadhi_gpio2 { /* Mode 3 */
+- function = "dpi";
+- pins = "gpio2", "gpio3", "gpio4", "gpio5",
+- "gpio6", "gpio7", "gpio8",
+- "gpio12", "gpio13", "gpio14", "gpio15",
+- "gpio16", "gpio17",
+- "gpio20", "gpio21", "gpio22", "gpio23",
+- "gpio24";
+- bias-disable;
+- };
+- rp1_dpi_16bit_pad666_gpio2: rp1_dpi_16bit_pad666_gpio2 { /* Mode 4 */
+- function = "dpi";
+- pins = "gpio2", "gpio3",
+- "gpio5", "gpio6", "gpio7", "gpio8",
+- "gpio9",
+- "gpio12", "gpio13", "gpio14", "gpio15",
+- "gpio16", "gpio17",
+- "gpio21", "gpio22", "gpio23", "gpio24",
+- "gpio25";
+- bias-disable;
+- };
+- rp1_dpi_18bit_gpio2: rp1_dpi_18bit_gpio2 { /* Mode 5, not fully supported by RP1 */
+- function = "dpi";
+- pins = "gpio2", "gpio3", "gpio4", "gpio5",
+- "gpio6", "gpio7", "gpio8", "gpio9",
+- "gpio10", "gpio11", "gpio12", "gpio13",
+- "gpio14", "gpio15", "gpio16", "gpio17",
+- "gpio18", "gpio19", "gpio20", "gpio21";
+- bias-disable;
+- };
+- rp1_dpi_18bit_cpadhi_gpio2: rp1_dpi_18bit_cpadhi_gpio2 { /* Mode 6 */
+- function = "dpi";
+- pins = "gpio2", "gpio3", "gpio4", "gpio5",
+- "gpio6", "gpio7", "gpio8", "gpio9",
+- "gpio12", "gpio13", "gpio14", "gpio15",
+- "gpio16", "gpio17",
+- "gpio20", "gpio21", "gpio22", "gpio23",
+- "gpio24", "gpio25";
+- bias-disable;
+- };
+- rp1_dpi_24bit_gpio2: rp1_dpi_24bit_gpio2 { /* Mode 7 */
+- function = "dpi";
+- pins = "gpio2", "gpio3", "gpio4", "gpio5",
+- "gpio6", "gpio7", "gpio8", "gpio9",
+- "gpio10", "gpio11", "gpio12", "gpio13",
+- "gpio14", "gpio15", "gpio16", "gpio17",
+- "gpio18", "gpio19", "gpio20", "gpio21",
+- "gpio22", "gpio23", "gpio24", "gpio25",
+- "gpio26", "gpio27";
+- bias-disable;
+- };
+- rp1_dpi_hvsync: rp1_dpi_hvsync { /* Sync only, for use with int VDAC */
+- function = "dpi";
+- pins = "gpio2", "gpio3";
+- bias-disable;
+- };
+-
+- // More DPI mappings, including PIXCLK,DE on GPIOs 0,1
+- rp1_dpi_16bit_gpio0: rp1_dpi_16bit_gpio0 { /* Mode 2, not fully supported by RP1 */
+- function = "dpi";
+- pins = "gpio0", "gpio1", "gpio2", "gpio3",
+- "gpio4", "gpio5", "gpio6", "gpio7",
+- "gpio8", "gpio9", "gpio10", "gpio11",
+- "gpio12", "gpio13", "gpio14", "gpio15",
+- "gpio16", "gpio17", "gpio18", "gpio19";
+- bias-disable;
+- };
+- rp1_dpi_16bit_cpadhi_gpio0: rp1_dpi_16bit_cpadhi_gpio0 { /* Mode 3 */
+- function = "dpi";
+- pins = "gpio0", "gpio1", "gpio2", "gpio3",
+- "gpio4", "gpio5", "gpio6", "gpio7",
+- "gpio8",
+- "gpio12", "gpio13", "gpio14", "gpio15",
+- "gpio16", "gpio17",
+- "gpio20", "gpio21", "gpio22", "gpio23",
+- "gpio24";
+- bias-disable;
+- };
+- rp1_dpi_16bit_pad666_gpio0: rp1_dpi_16bit_pad666_gpio0 { /* Mode 4 */
+- function = "dpi";
+- pins = "gpio0", "gpio1", "gpio2", "gpio3",
+- "gpio5", "gpio6", "gpio7", "gpio8",
+- "gpio9",
+- "gpio12", "gpio13", "gpio14", "gpio15",
+- "gpio16", "gpio17",
+- "gpio21", "gpio22", "gpio23", "gpio24",
+- "gpio25";
+- bias-disable;
+- };
+- rp1_dpi_18bit_gpio0: rp1_dpi_18bit_gpio0 { /* Mode 5, not fully supported by RP1 */
+- function = "dpi";
+- pins = "gpio0", "gpio1", "gpio2", "gpio3",
+- "gpio4", "gpio5", "gpio6", "gpio7",
+- "gpio8", "gpio9", "gpio10", "gpio11",
+- "gpio12", "gpio13", "gpio14", "gpio15",
+- "gpio16", "gpio17", "gpio18", "gpio19",
+- "gpio20", "gpio21";
+- bias-disable;
+- };
+- rp1_dpi_18bit_cpadhi_gpio0: rp1_dpi_18bit_cpadhi_gpio0 { /* Mode 6 */
+- function = "dpi";
+- pins = "gpio0", "gpio1", "gpio2", "gpio3",
+- "gpio4", "gpio5", "gpio6", "gpio7",
+- "gpio8", "gpio9",
+- "gpio12", "gpio13", "gpio14", "gpio15",
+- "gpio16", "gpio17",
+- "gpio20", "gpio21", "gpio22", "gpio23",
+- "gpio24", "gpio25";
+- bias-disable;
+- };
+- rp1_dpi_24bit_gpio0: rp1_dpi_24bit_gpio0 { /* Mode 7 -- All GPIOs used! */
+- function = "dpi";
+- pins = "gpio0", "gpio1", "gpio2", "gpio3",
+- "gpio4", "gpio5", "gpio6", "gpio7",
+- "gpio8", "gpio9", "gpio10", "gpio11",
+- "gpio12", "gpio13", "gpio14", "gpio15",
+- "gpio16", "gpio17", "gpio18", "gpio19",
+- "gpio20", "gpio21", "gpio22", "gpio23",
+- "gpio24", "gpio25", "gpio26", "gpio27";
+- bias-disable;
+- };
+-
+- rp1_gpclksrc0_gpio4: rp1_gpclksrc0_gpio4 {
+- function = "gpclk0";
+- pins = "gpio4";
+- bias-disable;
+- };
+-
+- rp1_gpclksrc0_gpio20: rp1_gpclksrc0_gpio20 {
+- function = "gpclk0";
+- pins = "gpio20";
+- bias-disable;
+- };
+-
+- rp1_gpclksrc1_gpio5: rp1_gpclksrc1_gpio5 {
+- function = "gpclk1";
+- pins = "gpio5";
+- bias-disable;
+- };
+-
+- rp1_gpclksrc1_gpio18: rp1_gpclksrc1_gpio18 {
+- function = "gpclk1";
+- pins = "gpio18";
+- bias-disable;
+- };
+-
+- rp1_gpclksrc1_gpio21: rp1_gpclksrc1_gpio21 {
+- function = "gpclk1";
+- pins = "gpio21";
+- bias-disable;
+- };
+-
+- rp1_pwm1_gpio45: rp1_pwm1_gpio45 {
+- function = "pwm1";
+- pins = "gpio45";
+- bias-pull-down;
+- };
+-
+- rp1_spi0_gpio9: rp1_spi0_gpio9 {
+- function = "spi0";
+- pins = "gpio9", "gpio10", "gpio11";
+- bias-disable;
+- drive-strength = <12>;
+- slew-rate = <1>;
+- };
+-
+- rp1_spi0_cs_gpio7: rp1_spi0_cs_gpio7 {
+- function = "spi0";
+- pins = "gpio7", "gpio8";
+- bias-pull-up;
+- };
+-
+- rp1_spi1_gpio19: rp1_spi1_gpio19 {
+- function = "spi1";
+- pins = "gpio19", "gpio20", "gpio21";
+- bias-disable;
+- drive-strength = <12>;
+- slew-rate = <1>;
+- };
+-
+- rp1_spi2_gpio1: rp1_spi2_gpio1 {
+- function = "spi2";
+- pins = "gpio1", "gpio2", "gpio3";
+- bias-disable;
+- drive-strength = <12>;
+- slew-rate = <1>;
+- };
+-
+- rp1_spi3_gpio5: rp1_spi3_gpio5 {
+- function = "spi3";
+- pins = "gpio5", "gpio6", "gpio7";
+- bias-disable;
+- drive-strength = <12>;
+- slew-rate = <1>;
+- };
+-
+- rp1_spi4_gpio9: rp1_spi4_gpio9 {
+- function = "spi4";
+- pins = "gpio9", "gpio10", "gpio11";
+- bias-disable;
+- drive-strength = <12>;
+- slew-rate = <1>;
+- };
+-
+- rp1_spi5_gpio13: rp1_spi5_gpio13 {
+- function = "spi5";
+- pins = "gpio13", "gpio14", "gpio15";
+- bias-disable;
+- drive-strength = <12>;
+- slew-rate = <1>;
+- };
+-
+- rp1_spi8_gpio49: rp1_spi8_gpio49 {
+- function = "spi8";
+- pins = "gpio49", "gpio50", "gpio51";
+- bias-disable;
+- drive-strength = <12>;
+- slew-rate = <1>;
+- };
+-
+- rp1_spi8_cs_gpio52: rp1_spi8_cs_gpio52 {
+- function = "spi0";
+- pins = "gpio52", "gpio53";
+- bias-pull-up;
+- };
+- };
+-
+- rp1_eth: ethernet@100000 {
+- reg = <0xc0 0x40100000 0x0 0x4000>;
+- compatible = "cdns,macb";
+- #address-cells = <1>;
+- #size-cells = <0>;
+- interrupts = <RP1_INT_ETH IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&macb_pclk &macb_hclk &rp1_clocks RP1_CLK_ETH_TSU>;
+- clock-names = "pclk", "hclk", "tsu_clk";
+- phy-mode = "rgmii-id";
+- cdns,aw2w-max-pipe = /bits/ 8 <8>;
+- cdns,ar2r-max-pipe = /bits/ 8 <8>;
+- cdns,use-aw2b-fill;
+- local-mac-address = [00 00 00 00 00 00];
+- status = "disabled";
+- };
+-
+- rp1_csi0: csi@110000 {
+- compatible = "raspberrypi,rp1-cfe";
+- reg = <0xc0 0x40110000 0x0 0x100>, // CSI2 DMA address
+- <0xc0 0x40114000 0x0 0x100>, // PHY/CSI Host address
+- <0xc0 0x40120000 0x0 0x100>, // MIPI CFG address
+- <0xc0 0x40124000 0x0 0x1000>; // PiSP FE address
+-
+- // interrupts must match rp1_pisp_fe setup
+- interrupts = <RP1_INT_MIPI0 IRQ_TYPE_LEVEL_HIGH>;
+-
+- clocks = <&rp1_clocks RP1_CLK_MIPI0_CFG>;
+- assigned-clocks = <&rp1_clocks RP1_CLK_MIPI0_CFG>;
+- assigned-clock-rates = <25000000>;
+-
+- #address-cells = <1>;
+- #size-cells = <0>;
+- status = "disabled";
+- };
+-
+- rp1_csi1: csi@128000 {
+- compatible = "raspberrypi,rp1-cfe";
+- reg = <0xc0 0x40128000 0x0 0x100>, // CSI2 DMA address
+- <0xc0 0x4012c000 0x0 0x100>, // PHY/CSI Host address
+- <0xc0 0x40138000 0x0 0x100>, // MIPI CFG address
+- <0xc0 0x4013c000 0x0 0x1000>; // PiSP FE address
+-
+- // interrupts must match rp1_pisp_fe setup
+- interrupts = <RP1_INT_MIPI1 IRQ_TYPE_LEVEL_HIGH>;
+-
+- clocks = <&rp1_clocks RP1_CLK_MIPI1_CFG>;
+- assigned-clocks = <&rp1_clocks RP1_CLK_MIPI1_CFG>;
+- assigned-clock-rates = <25000000>;
+-
+- #address-cells = <1>;
+- #size-cells = <0>;
+- status = "disabled";
+- };
+-
+- rp1_mmc0: mmc@180000 {
+- reg = <0xc0 0x40180000 0x0 0x100>;
+- compatible = "raspberrypi,rp1-dwcmshc";
+- interrupts = <RP1_INT_SDIO0 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&rp1_clocks RP1_CLK_SYS &sdhci_core
+- &rp1_clocks RP1_CLK_SDIO_TIMER
+- &rp1_sdio_clk0>;
+- clock-names = "bus", "core", "timeout", "sdio";
+- /* Bank 0 VDDIO is fixed */
+- no-1-8-v;
+- bus-width = <4>;
+- vmmc-supply = <&rp1_vdd_3v3>;
+- broken-cd;
+- status = "disabled";
+- };
+-
+- rp1_mmc1: mmc@184000 {
+- reg = <0xc0 0x40184000 0x0 0x100>;
+- compatible = "raspberrypi,rp1-dwcmshc";
+- interrupts = <RP1_INT_SDIO1 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&rp1_clocks RP1_CLK_SYS &sdhci_core
+- &rp1_clocks RP1_CLK_SDIO_TIMER
+- &rp1_sdio_clk1>;
+- clock-names = "bus", "core", "timeout", "sdio";
+- bus-width = <4>;
+- vmmc-supply = <&rp1_vdd_3v3>;
+- /* Nerf SDR speeds */
+- sdhci-caps-mask = <0x3 0x0>;
+- broken-cd;
+- status = "disabled";
+- };
+-
+- rp1_dma: dma@188000 {
+- reg = <0xc0 0x40188000 0x0 0x1000>;
+- compatible = "snps,axi-dma-1.01a";
+- interrupts = <RP1_INT_DMA IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&sdhci_core &rp1_clocks RP1_CLK_SYS>;
+- clock-names = "core-clk", "cfgr-clk";
+-
+- #dma-cells = <1>;
+- dma-channels = <8>;
+- snps,dma-masters = <1>;
+- snps,dma-targets = <64>;
+- snps,data-width = <4>; // (8 << 4) == 128 bits
+- snps,block-size = <0x40000 0x40000 0x40000 0x40000 0x40000 0x40000 0x40000 0x40000>;
+- snps,priority = <0 1 2 3 4 5 6 7>;
+- snps,axi-max-burst-len = <8>;
+- status = "disabled";
+- };
+-
+- rp1_usb0: usb@200000 {
+- reg = <0xc0 0x40200000 0x0 0x100000>;
+- compatible = "snps,dwc3";
+- dr_mode = "host";
+- usb3-lpm-capable;
+- snps,axi-pipe-limit = /bits/ 8 <8>;
+- snps,dis_rxdet_inp3_quirk;
+- snps,parkmode-disable-ss-quirk;
+- snps,parkmode-disable-hs-quirk;
+- snps,parkmode-disable-fsls-quirk;
+- snps,tx-max-burst = /bits/ 8 <8>;
+- snps,tx-thr-num-pkt = /bits/ 8 <2>;
+- interrupts = <RP1_INT_USBHOST0_0 IRQ_TYPE_EDGE_RISING>;
+- status = "disabled";
+- };
+-
+- rp1_usb1: usb@300000 {
+- reg = <0xc0 0x40300000 0x0 0x100000>;
+- compatible = "snps,dwc3";
+- dr_mode = "host";
+- usb3-lpm-capable;
+- snps,axi-pipe-limit = /bits/ 8 <8>;
+- snps,dis_rxdet_inp3_quirk;
+- snps,parkmode-disable-ss-quirk;
+- snps,parkmode-disable-hs-quirk;
+- snps,parkmode-disable-fsls-quirk;
+- snps,tx-max-burst = /bits/ 8 <8>;
+- snps,tx-thr-num-pkt = /bits/ 8 <2>;
+- interrupts = <RP1_INT_USBHOST1_0 IRQ_TYPE_EDGE_RISING>;
+- status = "disabled";
+- };
+-
+- rp1_dsi0: dsi@110000 {
+- compatible = "raspberrypi,rp1dsi";
+- status = "disabled";
+- reg = <0xc0 0x40118000 0x0 0x1000>, // MIPI0 DSI DMA (ArgonDPI)
+- <0xc0 0x4011c000 0x0 0x1000>, // MIPI0 DSI Host (SNPS)
+- <0xc0 0x40120000 0x0 0x1000>; // MIPI0 CFG
+-
+- interrupts = <RP1_INT_MIPI0 IRQ_TYPE_LEVEL_HIGH>;
+-
+- clocks = <&rp1_clocks RP1_CLK_MIPI0_CFG>,
+- <&rp1_clocks RP1_CLK_MIPI0_DPI>,
+- <&rp1_clocks RP1_CLK_MIPI0_DSI_BYTECLOCK>,
+- <&clk_xosc>, // hardwired to DSI "refclk"
+- <&rp1_clocks RP1_PLL_SYS>; // alternate parent for divide
+- clock-names = "cfgclk", "dpiclk", "byteclk", "refclk", "pllsys";
+-
+- assigned-clocks = <&rp1_clocks RP1_CLK_MIPI0_CFG>;
+- assigned-clock-rates = <25000000>;
+- };
+-
+- rp1_dsi1: dsi@128000 {
+- compatible = "raspberrypi,rp1dsi";
+- status = "disabled";
+- reg = <0xc0 0x40130000 0x0 0x1000>, // MIPI1 DSI DMA (ArgonDPI)
+- <0xc0 0x40134000 0x0 0x1000>, // MIPI1 DSI Host (SNPS)
+- <0xc0 0x40138000 0x0 0x1000>; // MIPI1 CFG
+-
+- interrupts = <RP1_INT_MIPI1 IRQ_TYPE_LEVEL_HIGH>;
+-
+- clocks = <&rp1_clocks RP1_CLK_MIPI1_CFG>,
+- <&rp1_clocks RP1_CLK_MIPI1_DPI>,
+- <&rp1_clocks RP1_CLK_MIPI1_DSI_BYTECLOCK>,
+- <&clk_xosc>, // hardwired to DSI "refclk"
+- <&rp1_clocks RP1_PLL_SYS>; // alternate parent for divide
+- clock-names = "cfgclk", "dpiclk", "byteclk", "refclk", "pllsys";
+-
+- assigned-clocks = <&rp1_clocks RP1_CLK_MIPI1_CFG>;
+- assigned-clock-rates = <25000000>;
+- };
+-
+- /* VEC and DPI both need to control PLL_VIDEO and cannot work together; */
+- /* config.txt should enable one or other using dtparam=vec or an overlay. */
+- rp1_vec: vec@144000 {
+- compatible = "raspberrypi,rp1vec";
+- status = "disabled";
+- reg = <0xc0 0x40144000 0x0 0x1000>, // VIDEO_OUT_VEC
+- <0xc0 0x40140000 0x0 0x1000>; // VIDEO_OUT_CFG
+-
+- interrupts = <RP1_INT_VIDEO_OUT IRQ_TYPE_LEVEL_HIGH>;
+-
+- clocks = <&rp1_clocks RP1_CLK_VEC>;
+-
+- assigned-clocks = <&rp1_clocks RP1_PLL_VIDEO_CORE>,
+- <&rp1_clocks RP1_PLL_VIDEO_SEC>,
+- <&rp1_clocks RP1_CLK_VEC>;
+- assigned-clock-rates = <1188000000>,
+- <108000000>,
+- <108000000>;
+- assigned-clock-parents = <0>,
+- <&rp1_clocks RP1_PLL_VIDEO_CORE>,
+- <&rp1_clocks RP1_PLL_VIDEO_SEC>;
+- };
+-
+- rp1_dpi: dpi@148000 {
+- compatible = "raspberrypi,rp1dpi";
+- status = "disabled";
+- reg = <0xc0 0x40148000 0x0 0x1000>, // VIDEO_OUT DPI
+- <0xc0 0x40140000 0x0 0x1000>; // VIDEO_OUT_CFG
+-
+- interrupts = <RP1_INT_VIDEO_OUT IRQ_TYPE_LEVEL_HIGH>;
+-
+- clocks = <&rp1_clocks RP1_CLK_DPI>, // DPI pixel clock
+- <&rp1_clocks RP1_PLL_VIDEO>, // PLL primary divider, and
+- <&rp1_clocks RP1_PLL_VIDEO_CORE>; // VCO, which we also control
+- clock-names = "dpiclk", "plldiv", "pllcore";
+-
+- assigned-clocks = <&rp1_clocks RP1_CLK_DPI>;
+- assigned-clock-parents = <&rp1_clocks RP1_PLL_VIDEO>;
+- };
+- };
+-};
+-
+-&clocks {
+- clk_xosc: clk_xosc {
+- compatible = "fixed-clock";
+- #clock-cells = <0>;
+- clock-output-names = "xosc";
+- clock-frequency = <50000000>;
+- };
+- macb_pclk: macb_pclk {
+- compatible = "fixed-clock";
+- #clock-cells = <0>;
+- clock-output-names = "pclk";
+- clock-frequency = <200000000>;
+- };
+- macb_hclk: macb_hclk {
+- compatible = "fixed-clock";
+- #clock-cells = <0>;
+- clock-output-names = "hclk";
+- clock-frequency = <200000000>;
+- };
+- sdio_src: sdio_src {
+- // 400 MHz on FPGA. PLL sys VCO on asic
+- compatible = "fixed-clock";
+- #clock-cells = <0>;
+- clock-output-names = "src";
+- clock-frequency = <1000000000>;
+- };
+- sdhci_core: sdhci_core {
+- compatible = "fixed-clock";
+- #clock-cells = <0>;
+- clock-output-names = "core";
+- clock-frequency = <50000000>;
+- };
+- /* GPIO derived clock sources. Each GPIO with a GPCLK function
+- * can drive its output from the respective GPCLK
+- * generator, and provide a clock source to other internal
+- * dividers. Add dummy sources here so that they can be overridden
+- * with overlays.
+- */
+- clksrc_gp0: clksrc_gp0 {
+- status = "disabled";
+- compatible = "fixed-factor-clock";
+- #clock-cells = <0>;
+- clock-div = <1>;
+- clock-mult = <1>;
+- clocks = <&rp1_clocks RP1_CLK_GP0>;
+- clock-output-names = "clksrc_gp0";
+- };
+- clksrc_gp1: clksrc_gp1 {
+- status = "disabled";
+- compatible = "fixed-factor-clock";
+- #clock-cells = <0>;
+- clock-div = <1>;
+- clock-mult = <1>;
+- clocks = <&rp1_clocks RP1_CLK_GP1>;
+- clock-output-names = "clksrc_gp1";
+- };
+- clksrc_gp2: clksrc_gp2 {
+- status = "disabled";
+- compatible = "fixed-factor-clock";
+- clock-div = <1>;
+- clock-mult = <1>;
+- #clock-cells = <0>;
+- clocks = <&rp1_clocks RP1_CLK_GP2>;
+- clock-output-names = "clksrc_gp2";
+- };
+- clksrc_gp3: clksrc_gp3 {
+- status = "disabled";
+- compatible = "fixed-factor-clock";
+- clock-div = <1>;
+- clock-mult = <1>;
+- #clock-cells = <0>;
+- clocks = <&rp1_clocks RP1_CLK_GP3>;
+- clock-output-names = "clksrc_gp3";
+- };
+- clksrc_gp4: clksrc_gp4 {
+- status = "disabled";
+- compatible = "fixed-factor-clock";
+- #clock-cells = <0>;
+- clock-div = <1>;
+- clock-mult = <1>;
+- clocks = <&rp1_clocks RP1_CLK_GP4>;
+- clock-output-names = "clksrc_gp4";
+- };
+- clksrc_gp5: clksrc_gp5 {
+- status = "disabled";
+- compatible = "fixed-factor-clock";
+- #clock-cells = <0>;
+- clock-div = <1>;
+- clock-mult = <1>;
+- clocks = <&rp1_clocks RP1_CLK_GP5>;
+- clock-output-names = "clksrc_gp5";
+- };
+-};
+-
+-/ {
+- rp1_vdd_3v3: rp1_vdd_3v3 {
+- compatible = "regulator-fixed";
+- regulator-name = "vdd-3v3";
+- regulator-min-microvolt = <3300000>;
+- regulator-max-microvolt = <3300000>;
+- regulator-always-on;
+- };
+-};
+--- /dev/null
++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi
+@@ -0,0 +1,351 @@
++// SPDX-License-Identifier: GPL-2.0
++
++#include <dt-bindings/power/raspberrypi-power.h>
++
++&soc {
++ firmware: firmware {
++ compatible = "raspberrypi,bcm2835-firmware", "simple-mfd";
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ mboxes = <&mailbox>;
++ dma-ranges;
++
++ firmware_clocks: clocks {
++ compatible = "raspberrypi,firmware-clocks";
++ #clock-cells = <1>;
++ };
++
++ reset: reset {
++ compatible = "raspberrypi,firmware-reset";
++ #reset-cells = <1>;
++ };
++
++ vcio: vcio {
++ compatible = "raspberrypi,vcio";
++ };
++ };
++
++ power: power {
++ compatible = "raspberrypi,bcm2835-power";
++ firmware = <&firmware>;
++ #power-domain-cells = <1>;
++ };
++
++ fb: fb {
++ compatible = "brcm,bcm2708-fb";
++ firmware = <&firmware>;
++ status = "okay";
++ };
++
++ rpi_rtc: rpi_rtc {
++ compatible = "raspberrypi,rpi-rtc";
++ firmware = <&firmware>;
++ status = "okay";
++ trickle-charge-microvolt = <0>;
++ };
++
++ nvmem {
++ compatible = "simple-bus";
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ nvmem_otp: nvmem_otp {
++ compatible = "raspberrypi,rpi-otp";
++ firmware = <&firmware>;
++ reg = <0 192>;
++ status = "okay";
++ };
++
++ nvmem_cust: nvmem_cust {
++ compatible = "raspberrypi,rpi-otp";
++ firmware = <&firmware>;
++ reg = <1 8>;
++ status = "okay";
++ };
++
++ nvmem_mac: nvmem_mac {
++ compatible = "raspberrypi,rpi-otp";
++ firmware = <&firmware>;
++ reg = <2 6>;
++ status = "okay";
++ };
++
++ nvmem_priv: nvmem_priv {
++ compatible = "raspberrypi,rpi-otp";
++ firmware = <&firmware>;
++ reg = <3 16>;
++ status = "okay";
++ };
++ };
++
++ /* Define these notional regulators for use by overlays, etc. */
++ vdd_3v3_reg: fixedregulator_3v3 {
++ compatible = "regulator-fixed";
++ regulator-always-on;
++ regulator-max-microvolt = <3300000>;
++ regulator-min-microvolt = <3300000>;
++ regulator-name = "3v3";
++ };
++
++ vdd_5v0_reg: fixedregulator_5v0 {
++ compatible = "regulator-fixed";
++ regulator-always-on;
++ regulator-max-microvolt = <5000000>;
++ regulator-min-microvolt = <5000000>;
++ regulator-name = "5v0";
++ };
++};
++
++/ {
++ __overrides__ {
++ arm_freq;
++ axiperf = <&axiperf>,"status";
++
++ nvmem_cust_rw = <&nvmem_cust>,"rw?";
++ nvmem_priv_rw = <&nvmem_priv>,"rw?";
++ nvmem_mac_rw = <&nvmem_mac>,"rw?";
++ strict_gpiod = <&chosen>, "bootargs=pinctrl_rp1.persist_gpio_outputs=n";
++
++ cam0_reg = <&cam0_reg>,"status";
++ cam0_reg_gpio = <&cam0_reg>,"gpio:4",
++ <&cam0_reg>,"gpio:0=", <&gpio>;
++ cam1_reg = <&cam1_reg>,"status";
++ cam1_reg_gpio = <&cam1_reg>,"gpio:4",
++ <&cam1_reg>,"gpio:0=", <&gpio>;
++
++ };
++};
++
++pciex1: &pcie1 { };
++pciex4: &pcie2 { };
++
++&dma32 {
++ /* The VPU firmware uses DMA channel 11 for VCHIQ */
++ brcm,dma-channel-mask = <0x03f>;
++};
++
++&dma40 {
++ /* The VPU firmware DMA channel 11 for VCHIQ */
++ brcm,dma-channel-mask = <0x07c0>;
++};
++
++&hdmi0 {
++ dmas = <&dma40 (10|(1<<30)|(1<<24)|(10<<16)|(15<<20))>;
++};
++
++&hdmi1 {
++ dmas = <&dma40 (17|(1<<30)|(1<<24)|(10<<16)|(15<<20))>;
++};
++
++&spi10 {
++ dmas = <&dma40 6>, <&dma40 7>;
++ dma-names = "tx", "rx";
++};
++
++&usb {
++ power-domains = <&power RPI_POWER_DOMAIN_USB>;
++};
++
++&rmem {
++ /*
++ * RPi5's co-processor will copy the board's bootloader configuration
++ * into memory for the OS to consume. It'll also update this node with
++ * its placement information.
++ */
++ blconfig: nvram@0 {
++ compatible = "raspberrypi,bootloader-config", "nvmem-rmem";
++ #address-cells = <1>;
++ #size-cells = <1>;
++ reg = <0x0 0x0 0x0>;
++ no-map;
++ status = "disabled";
++ };
++ /*
++ * RPi5 will copy the binary public key blob (if present) from the bootloader
++ * into memory for use by the OS.
++ */
++ blpubkey: nvram@1 {
++ compatible = "raspberrypi,bootloader-public-key", "nvmem-rmem";
++ #address-cells = <1>;
++ #size-cells = <1>;
++ reg = <0x0 0x0 0x0>;
++ no-map;
++ status = "disabled";
++ };
++};
++
++&rp1_adc {
++ status = "okay";
++};
++
++/* Add some gpiomem nodes to make the devices accessible to userspace.
++ * /dev/gpiomem<n> should expose the registers for the interface with DT alias
++ * gpio<n>.
++ */
++
++&rp1 {
++ gpiomem@d0000 {
++ /* Export IO_BANKs, RIO_BANKs and PADS_BANKs to userspace */
++ compatible = "raspberrypi,gpiomem";
++ reg = <0xc0 0x400d0000 0x0 0x30000>;
++ chardev-name = "gpiomem0";
++ };
++};
++
++&soc {
++ gpiomem@7d508500 {
++ compatible = "raspberrypi,gpiomem";
++ reg = <0x7d508500 0x40>;
++ chardev-name = "gpiomem1";
++ };
++
++ gpiomem@7d517c00 {
++ compatible = "raspberrypi,gpiomem";
++ reg = <0x7d517c00 0x40>;
++ chardev-name = "gpiomem2";
++ };
++
++ gpiomem@7d504100 {
++ compatible = "raspberrypi,gpiomem";
++ reg = <0x7d504100 0x20>;
++ chardev-name = "gpiomem3";
++ };
++
++ gpiomem@7d510700 {
++ compatible = "raspberrypi,gpiomem";
++ reg = <0x7d510700 0x20>;
++ chardev-name = "gpiomem4";
++ };
++
++ sound: sound {
++ status = "disabled";
++ };
++};
++
++i2c0: &rp1_i2c0 { };
++i2c1: &rp1_i2c1 { };
++i2c2: &rp1_i2c2 { };
++i2c3: &rp1_i2c3 { };
++i2c4: &rp1_i2c4 { };
++i2c5: &rp1_i2c5 { };
++i2c6: &rp1_i2c6 { };
++i2s: &rp1_i2s0 { };
++i2s_clk_producer: &rp1_i2s0 { };
++i2s_clk_consumer: &rp1_i2s1 { };
++pwm0: &rp1_pwm0 { };
++pwm1: &rp1_pwm1 { };
++pwm: &pwm0 { };
++spi0: &rp1_spi0 { };
++spi1: &rp1_spi1 { };
++spi2: &rp1_spi2 { };
++spi3: &rp1_spi3 { };
++spi4: &rp1_spi4 { };
++spi5: &rp1_spi5 { };
++
++uart0_pins: &rp1_uart0_14_15 {};
++uart0_ctsrts_pins: &rp1_uart0_ctsrts_16_17 {};
++uart0: &rp1_uart0 {
++ pinctrl-0 = <&uart0_pins>;
++};
++
++uart1_pins: &rp1_uart1_0_1 {};
++uart1_ctsrts_pins: &rp1_uart1_ctsrts_2_3 {};
++uart1: &rp1_uart1 { };
++
++uart2_pins: &rp1_uart2_4_5 {};
++uart2_ctsrts_pins: &rp1_uart2_ctsrts_6_7 {};
++uart2: &rp1_uart2 { };
++
++uart3_pins: &rp1_uart3_8_9 {};
++uart3_ctsrts_pins: &rp1_uart3_ctsrts_10_11 {};
++uart3: &rp1_uart3 { };
++
++uart4_pins: &rp1_uart4_12_13 {};
++uart4_ctsrts_pins: &rp1_uart4_ctsrts_14_15 {};
++uart4: &rp1_uart4 { };
++
++i2c0_pins: &rp1_i2c0_0_1 {};
++i2c_vc: &i2c0 { // This is pins 27,28 on the header (not MIPI)
++ pinctrl-0 = <&i2c0_pins>;
++ pinctrl-names = "default";
++ clock-frequency = <100000>;
++};
++
++i2c1_pins: &rp1_i2c1_2_3 {};
++i2c_arm: &i2c1 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c1_pins>;
++ clock-frequency = <100000>;
++};
++
++i2c2_pins: &rp1_i2c2_4_5 {};
++&i2c2 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c2_pins>;
++};
++
++i2c3_pins: &rp1_i2c3_6_7 {};
++&i2c3 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c3_pins>;
++};
++
++&i2s_clk_producer {
++ pinctrl-names = "default";
++ pinctrl-0 = <&rp1_i2s0_18_21>;
++};
++
++&i2s_clk_consumer {
++ pinctrl-names = "default";
++ pinctrl-0 = <&rp1_i2s1_18_21>;
++};
++
++spi0_pins: &rp1_spi0_gpio9 {};
++spi0_cs_pins: &rp1_spi0_cs_gpio7 {};
++
++&spi0 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&spi0_pins &spi0_cs_pins>;
++ cs-gpios = <&gpio 8 1>, <&gpio 7 1>;
++
++ spidev0: spidev@0 {
++ compatible = "spidev";
++ reg = <0>; /* CE0 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <125000000>;
++ };
++
++ spidev1: spidev@1 {
++ compatible = "spidev";
++ reg = <1>; /* CE1 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <125000000>;
++ };
++};
++
++spi2_pins: &rp1_spi2_gpio1 {};
++&spi2 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&spi2_pins>;
++};
++
++spi3_pins: &rp1_spi3_gpio5 {};
++&spi3 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&spi3_pins>;
++};
++
++spi4_pins: &rp1_spi4_gpio9 {};
++&spi4 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&spi4_pins>;
++};
++
++spi5_pins: &rp1_spi5_gpio13 {};
++&spi5 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&spi5_pins>;
++};
+--- /dev/null
++++ b/arch/arm64/boot/dts/broadcom/bcm2712.dtsi
+@@ -0,0 +1,1302 @@
++// SPDX-License-Identifier: GPL-2.0
++#include <dt-bindings/interrupt-controller/arm-gic.h>
++#include <dt-bindings/soc/bcm2835-pm.h>
++#include <dt-bindings/phy/phy.h>
++
++/ {
++ compatible = "brcm,bcm2712", "brcm,bcm2711";
++ model = "BCM2712";
++
++ #address-cells = <2>;
++ #size-cells = <1>;
++
++ interrupt-parent = <&gicv2>;
++
++ rmem: reserved-memory {
++ #address-cells = <2>;
++ #size-cells = <1>;
++ ranges;
++
++ atf@0 {
++ reg = <0x0 0x0 0x80000>;
++ no-map;
++ };
++
++ cma: linux,cma {
++ compatible = "shared-dma-pool";
++ size = <0x4000000>; /* 64MB */
++ reusable;
++ linux,cma-default;
++
++ /*
++ * arm64 reserves the CMA by default somewhere in
++ * ZONE_DMA32, that's not good enough for the BCM2711
++ * as some devices can only address the lower 1G of
++ * memory (ZONE_DMA).
++ */
++ alloc-ranges = <0x0 0x00000000 0x40000000>;
++ };
++ };
++
++ thermal-zones {
++ cpu_thermal: cpu-thermal {
++ polling-delay-passive = <2000>;
++ polling-delay = <1000>;
++ coefficients = <(-550) 450000>;
++ thermal-sensors = <&thermal>;
++
++ thermal_trips: trips {
++ cpu_crit: cpu-crit {
++ temperature = <110000>;
++ hysteresis = <0>;
++ type = "critical";
++ };
++ };
++
++ cooling_maps: cooling-maps {
++ };
++ };
++ };
++
++ clk_27MHz: clk-27M {
++ #clock-cells = <0>;
++ compatible = "fixed-clock";
++ clock-frequency = <27000000>;
++ clock-output-names = "27MHz-clock";
++ };
++
++ clk_108MHz: clk-108M {
++ #clock-cells = <0>;
++ compatible = "fixed-clock";
++ clock-frequency = <108000000>;
++ clock-output-names = "108MHz-clock";
++ };
++
++ hvs: hvs@107c580000 {
++ compatible = "brcm,bcm2712-hvs";
++ reg = <0x10 0x7c580000 0x1a000>;
++ interrupt-parent = <&disp_intr>;
++ interrupts = <2>, <9>, <16>;
++ interrupt-names = "ch0-eof", "ch1-eof", "ch2-eof";
++ //iommus = <&iommu4>;
++ status = "disabled";
++ };
++
++ soc: soc {
++ compatible = "simple-bus";
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ ranges = <0x7c000000 0x10 0x7c000000 0x04000000>;
++ /* Emulate a contiguous 30-bit address range for DMA */
++ dma-ranges = <0xc0000000 0x00 0x00000000 0x40000000>,
++ <0x7c000000 0x10 0x7c000000 0x04000000>;
++
++ system_timer: timer@7c003000 {
++ compatible = "brcm,bcm2835-system-timer";
++ reg = <0x7c003000 0x1000>;
++ interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
++ clock-frequency = <1000000>;
++ };
++
++ firmwarekms: firmwarekms@7d503000 {
++ compatible = "raspberrypi,rpi-firmware-kms-2712";
++ /* SUN_L2 interrupt reg */
++ reg = <0x7d503000 0x18>;
++ interrupt-parent = <&cpu_l2_irq>;
++ interrupts = <19>;
++ brcm,firmware = <&firmware>;
++ status = "disabled";
++ };
++
++ axiperf: axiperf {
++ compatible = "brcm,bcm2712-axiperf";
++ reg = <0x7c012800 0x100>,
++ <0x7e000000 0x100>;
++ firmware = <&firmware>;
++ status = "disabled";
++ };
++
++ mailbox: mailbox@7c013880 {
++ compatible = "brcm,bcm2835-mbox";
++ reg = <0x7c013880 0x40>;
++ interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
++ #mbox-cells = <0>;
++ };
++
++ pixelvalve0: pixelvalve@7c410000 {
++ compatible = "brcm,bcm2712-pixelvalve0";
++ reg = <0x7c410000 0x100>;
++ interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
++ status = "disabled";
++ };
++
++ pixelvalve1: pixelvalve@7c411000 {
++ compatible = "brcm,bcm2712-pixelvalve1";
++ reg = <0x7c411000 0x100>;
++ interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
++ status = "disabled";
++ };
++
++ mop: mop@7c500000 {
++ compatible = "brcm,bcm2712-mop";
++ reg = <0x7c500000 0x28>;
++ interrupt-parent = <&disp_intr>;
++ interrupts = <1>;
++ status = "disabled";
++ };
++
++ moplet: moplet@7c501000 {
++ compatible = "brcm,bcm2712-moplet";
++ reg = <0x7c501000 0x20>;
++ interrupt-parent = <&disp_intr>;
++ interrupts = <0>;
++ status = "disabled";
++ };
++
++ disp_intr: interrupt-controller@7c502000 {
++ compatible = "brcm,bcm2711-l2-intc", "brcm,l2-intc";
++ reg = <0x7c502000 0x30>;
++ interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ status = "disabled";
++ };
++
++ dvp: clock@7c700000 {
++ compatible = "brcm,brcm2711-dvp";
++ reg = <0x7c700000 0x10>;
++ clocks = <&clk_108MHz>;
++ #clock-cells = <1>;
++ #reset-cells = <1>;
++ };
++
++ /*
++ * This node is the provider for the enable-method for
++ * bringing up secondary cores.
++ */
++ local_intc: local_intc@7cd00000 {
++ compatible = "brcm,bcm2836-l1-intc";
++ reg = <0x7cd00000 0x100>;
++ };
++
++ uart0: serial@7d001000 {
++ compatible = "arm,pl011", "arm,primecell";
++ reg = <0x7d001000 0x200>;
++ interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clk_uart>,
++ <&clk_vpu>;
++ clock-names = "uartclk", "apb_pclk";
++ arm,primecell-periphid = <0x00241011>;
++ status = "disabled";
++ };
++
++ uart2: serial@7d001400 {
++ compatible = "arm,pl011", "arm,primecell";
++ reg = <0x7d001400 0x200>;
++ interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clk_uart>,
++ <&clk_vpu>;
++ clock-names = "uartclk", "apb_pclk";
++ arm,primecell-periphid = <0x00241011>;
++ status = "disabled";
++ };
++
++ uart5: serial@7d001a00 {
++ compatible = "arm,pl011", "arm,primecell";
++ reg = <0x7d001a00 0x200>;
++ interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clk_uart>,
++ <&clk_vpu>;
++ clock-names = "uartclk", "apb_pclk";
++ arm,primecell-periphid = <0x00241011>;
++ status = "disabled";
++ };
++
++ sdhost: mmc@7d002000 {
++ compatible = "brcm,bcm2835-sdhost";
++ reg = <0x7d002000 0x100>;
++ //interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clk_vpu>;
++ status = "disabled";
++ };
++
++ i2s: i2s@7d003000 {
++ compatible = "brcm,bcm2835-i2s";
++ reg = <0x7d003000 0x24>;
++ //clocks = <&cprman BCM2835_CLOCK_PCM>;
++ status = "disabled";
++ };
++
++ spi0: spi@7d004000 {
++ compatible = "brcm,bcm2835-spi";
++ reg = <0x7d004000 0x200>;
++ interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clk_vpu>;
++ num-cs = <1>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ spi3: spi@7d004600 {
++ compatible = "brcm,bcm2835-spi";
++ reg = <0x7d004600 0x0200>;
++ interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clk_vpu>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ spi4: spi@7d004800 {
++ compatible = "brcm,bcm2835-spi";
++ reg = <0x7d004800 0x0200>;
++ interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clk_vpu>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ spi5: spi@7d004a00 {
++ compatible = "brcm,bcm2835-spi";
++ reg = <0x7d004a00 0x0200>;
++ interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clk_vpu>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ spi6: spi@7d004c00 {
++ compatible = "brcm,bcm2835-spi";
++ reg = <0x7d004c00 0x0200>;
++ interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clk_vpu>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ i2c0: i2c@7d005000 {
++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
++ reg = <0x7d005000 0x20>;
++ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clk_vpu>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ i2c3: i2c@7d005600 {
++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
++ reg = <0x7d005600 0x20>;
++ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clk_vpu>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ i2c4: i2c@7d005800 {
++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
++ reg = <0x7d005800 0x20>;
++ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clk_vpu>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ i2c5: i2c@7d005a00 {
++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
++ reg = <0x7d005a00 0x20>;
++ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clk_vpu>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ i2c6: i2c@7d005c00 {
++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
++ reg = <0x7d005c00 0x20>;
++ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clk_vpu>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ i2c8: i2c@7d005e00 {
++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
++ reg = <0x7d005e00 0x20>;
++ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clk_vpu>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ pwm0: pwm@7d00c000 {
++ compatible = "brcm,bcm2835-pwm";
++ reg = <0x7d00c000 0x28>;
++ assigned-clock-rates = <50000000>;
++ #pwm-cells = <3>;
++ status = "disabled";
++ };
++
++ pwm1: pwm@7d00c800 {
++ compatible = "brcm,bcm2835-pwm";
++ reg = <0x7d00c800 0x28>;
++ assigned-clock-rates = <50000000>;
++ #pwm-cells = <3>;
++ status = "disabled";
++ };
++
++ pm: watchdog@7d200000 {
++ compatible = "brcm,bcm2712-pm";
++ reg = <0x7d200000 0x308>;
++ reg-names = "pm";
++ #power-domain-cells = <1>;
++ #reset-cells = <1>;
++ //clocks = <&cprman BCM2835_CLOCK_V3D>,
++ // <&cprman BCM2835_CLOCK_PERI_IMAGE>,
++ // <&cprman BCM2835_CLOCK_H264>,
++ // <&cprman BCM2835_CLOCK_ISP>;
++ clock-names = "v3d", "peri_image", "h264", "isp";
++ system-power-controller;
++ };
++
++ cprman: cprman@7d202000 {
++ compatible = "brcm,bcm2711-cprman";
++ reg = <0x7d202000 0x2000>;
++ #clock-cells = <1>;
++
++ /* CPRMAN derives almost everything from the
++ * platform's oscillator. However, the DSI
++ * pixel clocks come from the DSI analog PHY.
++ */
++ clocks = <&clk_osc>;
++ status = "disabled";
++ };
++
++ random: rng@7d208000 {
++ compatible = "brcm,bcm2711-rng200";
++ reg = <0x7d208000 0x28>;
++ status = "okay";
++ };
++
++ cpu_l2_irq: intc@7d503000 {
++ compatible = "brcm,l2-intc";
++ reg = <0x7d503000 0x18>;
++ interrupts = <GIC_SPI 238 IRQ_TYPE_LEVEL_HIGH>;
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++
++ pinctrl: pinctrl@7d504100 {
++ compatible = "brcm,bcm2712-pinctrl";
++ reg = <0x7d504100 0x30>;
++
++ uarta_24_pins: uarta_24_pins {
++ pin_rts {
++ function = "uart0";
++ pins = "gpio24";
++ bias-disable;
++ };
++ pin_cts {
++ function = "uart0";
++ pins = "gpio25";
++ bias-pull-up;
++ };
++ pin_txd {
++ function = "uart0";
++ pins = "gpio26";
++ bias-disable;
++ };
++ pin_rxd {
++ function = "uart0";
++ pins = "gpio27";
++ bias-pull-up;
++ };
++ };
++
++ sdio2_30_pins: sdio2_30_pins {
++ pin_clk {
++ function = "sd2";
++ pins = "gpio30";
++ bias-disable;
++ };
++ pin_cmd {
++ function = "sd2";
++ pins = "gpio31";
++ bias-pull-up;
++ };
++ pins_dat {
++ function = "sd2";
++ pins = "gpio32", "gpio33", "gpio34", "gpio35";
++ bias-pull-up;
++ };
++ };
++ };
++
++ ddc0: i2c@7d508200 {
++ compatible = "brcm,brcmstb-i2c";
++ reg = <0x7d508200 0x58>;
++ interrupt-parent = <&bsc_irq>;
++ interrupts = <1>;
++ clock-frequency = <97500>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ ddc1: i2c@7d508280 {
++ compatible = "brcm,brcmstb-i2c";
++ reg = <0x7d508280 0x58>;
++ interrupt-parent = <&bsc_irq>;
++ interrupts = <2>;
++ clock-frequency = <97500>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ bscd: i2c@7d508300 {
++ compatible = "brcm,brcmstb-i2c";
++ reg = <0x7d508300 0x58>;
++ interrupt-parent = <&bsc_irq>;
++ interrupts = <0>;
++ clock-frequency = <200000>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ bsc_irq: intc@7d508380 {
++ compatible = "brcm,bcm7271-l2-intc";
++ reg = <0x7d508380 0x10>;
++ interrupts = <GIC_SPI 242 IRQ_TYPE_LEVEL_HIGH>;
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++
++ main_irq: intc@7d508400 {
++ compatible = "brcm,bcm7271-l2-intc";
++ reg = <0x7d508400 0x10>;
++ interrupts = <GIC_SPI 244 IRQ_TYPE_LEVEL_HIGH>;
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++
++ gio: gpio@7d508500 {
++ compatible = "brcm,brcmstb-gpio";
++ reg = <0x7d508500 0x40>;
++ interrupt-parent = <&main_irq>;
++ interrupts = <0>;
++ gpio-controller;
++ #gpio-cells = <2>;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ brcm,gpio-bank-widths = <32 22>;
++ brcm,gpio-direct;
++ };
++
++ uarta: serial@7d50c000 {
++ compatible = "brcm,bcm7271-uart";
++ reg = <0x7d50c000 0x20>;
++ reg-names = "uart";
++ reg-shift = <2>;
++ reg-io-width = <4>;
++ interrupts = <GIC_SPI 276 IRQ_TYPE_LEVEL_HIGH>;
++ skip-init;
++ status = "disabled";
++ };
++
++ uartb: serial@7d50d000 {
++ compatible = "brcm,bcm7271-uart";
++ reg = <0x7d50d000 0x20>;
++ reg-names = "uart";
++ reg-shift = <2>;
++ reg-io-width = <4>;
++ interrupts = <GIC_SPI 277 IRQ_TYPE_LEVEL_HIGH>;
++ skip-init;
++ status = "disabled";
++ };
++
++ aon_intr: interrupt-controller@7d510600 {
++ compatible = "brcm,bcm2711-l2-intc", "brcm,l2-intc";
++ reg = <0x7d510600 0x30>;
++ interrupts = <GIC_SPI 239 IRQ_TYPE_LEVEL_HIGH>;
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ status = "disabled";
++ };
++
++ pinctrl_aon: pinctrl@7d510700 {
++ compatible = "brcm,bcm2712-aon-pinctrl";
++ reg = <0x7d510700 0x20>;
++
++ i2c3_m4_agpio0_pins: i2c3_m4_agpio0_pins {
++ function = "vc_i2c3";
++ pins = "aon_gpio0", "aon_gpio1";
++ bias-pull-up;
++ };
++
++ bsc_m1_agpio13_pins: bsc_m1_agpio13_pins {
++ function = "bsc_m1";
++ pins = "aon_gpio13", "aon_gpio14";
++ bias-pull-up;
++ };
++
++ bsc_pmu_sgpio4_pins: bsc_pmu_sgpio4_pins {
++ function = "avs_pmu_bsc";
++ pins = "aon_sgpio4", "aon_sgpio5";
++ };
++
++ bsc_m2_sgpio4_pins: bsc_m2_sgpio4_pins {
++ function = "bsc_m2";
++ pins = "aon_sgpio4", "aon_sgpio5";
++ };
++
++ pwm_aon_agpio1_pins: pwm_aon_agpio1_pins {
++ function = "aon_pwm";
++ pins = "aon_gpio1", "aon_gpio2";
++ };
++
++ pwm_aon_agpio4_pins: pwm_aon_agpio4_pins {
++ function = "vc_pwm0";
++ pins = "aon_gpio4", "aon_gpio5";
++ };
++
++ pwm_aon_agpio7_pins: pwm_aon_agpio7_pins {
++ function = "aon_pwm";
++ pins = "aon_gpio7", "aon_gpio9";
++ };
++ };
++
++ intc@7d517000 {
++ compatible = "brcm,bcm7271-l2-intc";
++ reg = <0x7d517000 0x10>;
++ interrupts = <GIC_SPI 247 IRQ_TYPE_LEVEL_HIGH>;
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ status = "disabled";
++ };
++
++ bscc: i2c@7d517a00 {
++ compatible = "brcm,brcmstb-i2c";
++ reg = <0x7d517a00 0x58>;
++ interrupt-parent = <&bsc_aon_irq>;
++ interrupts = <0>;
++ clock-frequency = <200000>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ pwm_aon: pwm@7d517a80 {
++ compatible = "brcm,bcm7038-pwm";
++ reg = <0x7d517a80 0x28>;
++ #pwm-cells = <3>;
++ clocks = <&clk_27MHz>;
++ };
++
++ main_aon_irq: intc@7d517ac0 {
++ compatible = "brcm,bcm7271-l2-intc";
++ reg = <0x7d517ac0 0x10>;
++ interrupts = <GIC_SPI 245 IRQ_TYPE_LEVEL_HIGH>;
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++
++ bsc_aon_irq: intc@7d517b00 {
++ compatible = "brcm,bcm7271-l2-intc";
++ reg = <0x7d517b00 0x10>;
++ interrupts = <GIC_SPI 243 IRQ_TYPE_LEVEL_HIGH>;
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++
++ gio_aon: gpio@7d517c00 {
++ compatible = "brcm,brcmstb-gpio";
++ reg = <0x7d517c00 0x40>;
++ interrupt-parent = <&main_aon_irq>;
++ interrupts = <0>;
++ gpio-controller;
++ #gpio-cells = <2>;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ brcm,gpio-bank-widths = <17 6>;
++ brcm,gpio-direct;
++ };
++
++ avs_monitor: avs-monitor@7d542000 {
++ compatible = "brcm,bcm2711-avs-monitor",
++ "syscon", "simple-mfd";
++ reg = <0x7d542000 0xf00>;
++ status = "okay";
++
++ thermal: thermal {
++ compatible = "brcm,bcm2711-thermal";
++ #thermal-sensor-cells = <0>;
++ };
++ };
++
++ bsc_pmu: i2c@7d544000 {
++ compatible = "brcm,brcmstb-i2c";
++ reg = <0x7d544000 0x58>;
++ interrupt-parent = <&bsc_aon_irq>;
++ interrupts = <1>;
++ clock-frequency = <200000>;
++ status = "disabled";
++ };
++
++ hdmi0: hdmi@7ef00700 {
++ compatible = "brcm,bcm2712-hdmi0";
++ reg = <0x7c701400 0x300>,
++ <0x7c701000 0x200>,
++ <0x7c701d00 0x300>,
++ <0x7c702000 0x80>,
++ <0x7c703800 0x200>,
++ <0x7c704000 0x800>,
++ <0x7c700100 0x80>,
++ <0x7d510800 0x100>,
++ <0x7c720000 0x100>;
++ reg-names = "hdmi",
++ "dvp",
++ "phy",
++ "rm",
++ "packet",
++ "metadata",
++ "csc",
++ "cec",
++ "hd";
++ resets = <&dvp 1>;
++ interrupt-parent = <&aon_intr>;
++ interrupts = <1>, <2>, <3>,
++ <7>, <8>;
++ interrupt-names = "cec-tx", "cec-rx", "cec-low",
++ "hpd-connected", "hpd-removed";
++ ddc = <&ddc0>;
++ dmas = <&dma32 10>;
++ dma-names = "audio-rx";
++ status = "disabled";
++ };
++
++ hdmi1: hdmi@7ef05700 {
++ compatible = "brcm,bcm2712-hdmi1";
++ reg = <0x7c706400 0x300>,
++ <0x7c706000 0x200>,
++ <0x7c706d00 0x300>,
++ <0x7c707000 0x80>,
++ <0x7c708800 0x200>,
++ <0x7c709000 0x800>,
++ <0x7c700180 0x80>,
++ <0x7d511000 0x100>,
++ <0x7c720000 0x100>;
++ reg-names = "hdmi",
++ "dvp",
++ "phy",
++ "rm",
++ "packet",
++ "metadata",
++ "csc",
++ "cec",
++ "hd";
++ ddc = <&ddc1>;
++ resets = <&dvp 2>;
++ interrupt-parent = <&aon_intr>;
++ interrupts = <11>, <12>, <13>,
++ <14>, <15>;
++ interrupt-names = "cec-tx", "cec-rx", "cec-low",
++ "hpd-connected", "hpd-removed";
++ dmas = <&dma32 17>;
++ dma-names = "audio-rx";
++ status = "disabled";
++ };
++ };
++
++ arm-pmu {
++ compatible = "arm,cortex-a76-pmu";
++ interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
++ interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>;
++ };
++
++ timer {
++ compatible = "arm,armv8-timer";
++ interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) |
++ IRQ_TYPE_LEVEL_LOW)>,
++ <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) |
++ IRQ_TYPE_LEVEL_LOW)>,
++ <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) |
++ IRQ_TYPE_LEVEL_LOW)>,
++ <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) |
++ IRQ_TYPE_LEVEL_LOW)>;
++ /* This only applies to the ARMv7 stub */
++ arm,cpu-registers-not-fw-configured;
++ };
++
++ cpus: cpus {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ enable-method = "brcm,bcm2836-smp"; // for ARM 32-bit
++
++ /* Source for d/i cache-line-size, cache-sets, cache-size
++ * https://developer.arm.com/documentation/100798/0401
++ * /L1-memory-system/About-the-L1-memory-system?lang=en
++ */
++ cpu0: cpu@0 {
++ device_type = "cpu";
++ compatible = "arm,cortex-a76";
++ reg = <0x000>;
++ enable-method = "psci";
++ d-cache-size = <0x10000>;
++ d-cache-line-size = <64>;
++ d-cache-sets = <256>; // 64KiB(size)/64(line-size)=1024ways/4-way set
++ i-cache-size = <0x10000>;
++ i-cache-line-size = <64>;
++ i-cache-sets = <256>; // 64KiB(size)/64(line-size)=1024ways/4-way set
++ next-level-cache = <&l2_cache_l0>;
++ };
++
++ cpu1: cpu@1 {
++ device_type = "cpu";
++ compatible = "arm,cortex-a76";
++ reg = <0x100>;
++ enable-method = "psci";
++ d-cache-size = <0x10000>;
++ d-cache-line-size = <64>;
++ d-cache-sets = <256>; // 64KiB(size)/64(line-size)=1024ways/4-way set
++ i-cache-size = <0x10000>;
++ i-cache-line-size = <64>;
++ i-cache-sets = <256>; // 64KiB(size)/64(line-size)=1024ways/4-way set
++ next-level-cache = <&l2_cache_l1>;
++ };
++
++ cpu2: cpu@2 {
++ device_type = "cpu";
++ compatible = "arm,cortex-a76";
++ reg = <0x200>;
++ enable-method = "psci";
++ d-cache-size = <0x10000>;
++ d-cache-line-size = <64>;
++ d-cache-sets = <256>; // 64KiB(size)/64(line-size)=1024ways/4-way set
++ i-cache-size = <0x10000>;
++ i-cache-line-size = <64>;
++ i-cache-sets = <256>; // 64KiB(size)/64(line-size)=1024ways/4-way set
++ next-level-cache = <&l2_cache_l2>;
++ };
++
++ cpu3: cpu@3 {
++ device_type = "cpu";
++ compatible = "arm,cortex-a76";
++ reg = <0x300>;
++ enable-method = "psci";
++ d-cache-size = <0x10000>;
++ d-cache-line-size = <64>;
++ d-cache-sets = <256>; // 64KiB(size)/64(line-size)=1024ways/4-way set
++ i-cache-size = <0x10000>;
++ i-cache-line-size = <64>;
++ i-cache-sets = <256>; // 64KiB(size)/64(line-size)=1024ways/4-way set
++ next-level-cache = <&l2_cache_l3>;
++ };
++
++ /* Source for cache-line-size and cache-sets:
++ * https://developer.arm.com/documentation/100798/0401
++ * /L2-memory-system/About-the-L2-memory-system?lang=en
++ * and for cache-size:
++ * https://www.raspberrypi.com/documentation/computers
++ * /processors.html#bcm2712
++ */
++ l2_cache_l0: l2-cache-l0 {
++ compatible = "cache";
++ cache-size = <0x80000>;
++ cache-line-size = <128>;
++ cache-sets = <1024>; // 512KiB(size)/64(line-size)=8192ways/8-way set
++ cache-level = <2>;
++ cache-unified;
++ next-level-cache = <&l3_cache>;
++ };
++
++ l2_cache_l1: l2-cache-l1 {
++ compatible = "cache";
++ cache-size = <0x80000>;
++ cache-line-size = <128>;
++ cache-sets = <1024>; // 512KiB(size)/64(line-size)=8192ways/8-way set
++ cache-level = <2>;
++ cache-unified;
++ next-level-cache = <&l3_cache>;
++ };
++
++ l2_cache_l2: l2-cache-l2 {
++ compatible = "cache";
++ cache-size = <0x80000>;
++ cache-line-size = <128>;
++ cache-sets = <1024>; // 512KiB(size)/64(line-size)=8192ways/8-way set
++ cache-level = <2>;
++ cache-unified;
++ next-level-cache = <&l3_cache>;
++ };
++
++ l2_cache_l3: l2-cache-l3 {
++ compatible = "cache";
++ cache-size = <0x80000>;
++ cache-line-size = <128>;
++ cache-sets = <1024>; // 512KiB(size)/64(line-size)=8192ways/8-way set
++ cache-level = <2>;
++ cache-unified;
++ next-level-cache = <&l3_cache>;
++ };
++
++ /* Source for cache-line-size and cache-sets:
++ * https://developer.arm.com/documentation/100453/0401/L3-cache?lang=en
++ * Source for cache-size:
++ * https://www.raspberrypi.com/documentation/computers/processors.html#bcm2712
++ */
++ l3_cache: l3-cache {
++ compatible = "cache";
++ cache-size = <0x200000>;
++ cache-line-size = <64>;
++ cache-sets = <2048>; // 2MiB(size)/64(line-size)=32768ways/16-way set
++ cache-level = <3>;
++ };
++ };
++
++ psci {
++ method = "smc";
++ compatible = "arm,psci-1.0", "arm,psci-0.2", "arm,psci";
++ cpu_on = <0xc4000003>;
++ cpu_suspend = <0xc4000001>;
++ cpu_off = <0x84000002>;
++ };
++
++ axi: axi {
++ compatible = "simple-bus";
++ #address-cells = <2>;
++ #size-cells = <2>;
++
++ ranges = <0x00 0x00000000 0x00 0x00000000 0x10 0x00000000>,
++ <0x10 0x00000000 0x10 0x00000000 0x01 0x00000000>,
++ <0x14 0x00000000 0x14 0x00000000 0x04 0x00000000>,
++ <0x18 0x00000000 0x18 0x00000000 0x04 0x00000000>,
++ <0x1c 0x00000000 0x1c 0x00000000 0x04 0x00000000>;
++
++ dma-ranges = <0x00 0x00000000 0x00 0x00000000 0x10 0x00000000>,
++ <0x10 0x00000000 0x10 0x00000000 0x01 0x00000000>,
++ <0x14 0x00000000 0x14 0x00000000 0x04 0x00000000>,
++ <0x18 0x00000000 0x18 0x00000000 0x04 0x00000000>,
++ <0x1c 0x00000000 0x1c 0x00000000 0x04 0x00000000>;
++
++ vc4: gpu {
++ compatible = "brcm,bcm2712-vc6";
++ };
++
++ iommu2: iommu@5100 {
++ /* IOMMU2 for PISP-BE, HEVC; and (unused) H264 accelerators */
++ compatible = "brcm,bcm2712-iommu";
++ reg = <0x10 0x5100 0x0 0x80>;
++ cache = <&iommuc>;
++ #iommu-cells = <0>;
++ };
++
++ iommu4: iommu@5200 {
++ /* IOMMU4 for HVS, MPL/TXP; and (unused) Unicam, PISP-FE, MiniBVN */
++ compatible = "brcm,bcm2712-iommu";
++ reg = <0x10 0x5200 0x0 0x80>;
++ cache = <&iommuc>;
++ #iommu-cells = <0>;
++ #interconnect-cells = <0>;
++ };
++
++ iommu5: iommu@5280 {
++ /* IOMMU5 for PCIe2 (RP1); and (unused) BSTM */
++ compatible = "brcm,bcm2712-iommu";
++ reg = <0x10 0x5280 0x0 0x80>;
++ cache = <&iommuc>;
++ #iommu-cells = <0>;
++ dma-iova-offset = <0x10 0x00000000>; // HACK for RP1 masters over PCIe
++ };
++
++ iommuc: iommuc@5b00 {
++ compatible = "brcm,bcm2712-iommuc";
++ reg = <0x10 0x5b00 0x0 0x80>;
++ };
++
++ dma32: dma@10000 {
++ compatible = "brcm,bcm2712-dma";
++ reg = <0x10 0x00010000 0 0x600>;
++ interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;
++ interrupt-names = "dma0",
++ "dma1",
++ "dma2",
++ "dma3",
++ "dma4",
++ "dma5";
++ #dma-cells = <1>;
++ brcm,dma-channel-mask = <0x0035>;
++ };
++
++ dma40: dma@10600 {
++ compatible = "brcm,bcm2712-dma";
++ reg = <0x10 0x00010600 0 0x600>;
++ interrupts =
++ <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>, /* dma4 6 */
++ <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>, /* dma4 7 */
++ <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>, /* dma4 8 */
++ <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>, /* dma4 9 */
++ <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>, /* dma4 10 */
++ <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>; /* dma4 11 */
++ interrupt-names = "dma6",
++ "dma7",
++ "dma8",
++ "dma9",
++ "dma10",
++ "dma11";
++ #dma-cells = <1>;
++ brcm,dma-channel-mask = <0x0fc0>;
++ };
++
++ // Single-lane Gen3 PCIe
++ // Outbound window at 0x14_000000-0x17_ffffff
++ pcie0: pcie@100000 {
++ compatible = "brcm,bcm2712-pcie";
++ reg = <0x10 0x00100000 0x0 0x9310>;
++ device_type = "pci";
++ max-link-speed = <2>;
++ #address-cells = <3>;
++ #interrupt-cells = <1>;
++ #size-cells = <2>;
++ /*
++ * Unused interrupts:
++ * 208: AER
++ * 215: NMI
++ * 216: PME
++ */
++ interrupt-parent = <&gicv2>;
++ interrupts = <GIC_SPI 213 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 214 IRQ_TYPE_LEVEL_HIGH>;
++ interrupt-names = "pcie", "msi";
++ interrupt-map-mask = <0x0 0x0 0x0 0x7>;
++ interrupt-map = <0 0 0 1 &gicv2 GIC_SPI 209
++ IRQ_TYPE_LEVEL_HIGH>,
++ <0 0 0 2 &gicv2 GIC_SPI 210
++ IRQ_TYPE_LEVEL_HIGH>,
++ <0 0 0 3 &gicv2 GIC_SPI 211
++ IRQ_TYPE_LEVEL_HIGH>,
++ <0 0 0 4 &gicv2 GIC_SPI 212
++ IRQ_TYPE_LEVEL_HIGH>;
++ resets = <&bcm_reset 5>, <&bcm_reset 42>, <&pcie_rescal>;
++ reset-names = "swinit", "bridge", "rescal";
++ msi-controller;
++ msi-parent = <&pcie0>;
++
++ ranges = <0x02000000 0x00 0x00000000
++ 0x17 0x00000000
++ 0x0 0xfffffffc>,
++ <0x43000000 0x04 0x00000000
++ 0x14 0x00000000
++ 0x3 0x00000000>;
++
++ dma-ranges = <0x43000000 0x10 0x00000000
++ 0x00 0x00000000
++ 0x10 0x00000000>;
++
++ status = "disabled";
++ };
++
++ // Single-lane Gen3 PCIe
++ // Outbound window at 0x18_000000-0x1b_ffffff
++ pcie1: pcie@110000 {
++ compatible = "brcm,bcm2712-pcie";
++ reg = <0x10 0x00110000 0x0 0x9310>;
++ device_type = "pci";
++ max-link-speed = <2>;
++ #address-cells = <3>;
++ #interrupt-cells = <1>;
++ #size-cells = <2>;
++ /*
++ * Unused interrupts:
++ * 218: AER
++ * 225: NMI
++ * 226: PME
++ */
++ interrupt-parent = <&gicv2>;
++ interrupts = <GIC_SPI 223 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 224 IRQ_TYPE_LEVEL_HIGH>;
++ interrupt-names = "pcie", "msi";
++ interrupt-map-mask = <0x0 0x0 0x0 0x7>;
++ interrupt-map = <0 0 0 1 &gicv2 GIC_SPI 219
++ IRQ_TYPE_LEVEL_HIGH>,
++ <0 0 0 2 &gicv2 GIC_SPI 220
++ IRQ_TYPE_LEVEL_HIGH>,
++ <0 0 0 3 &gicv2 GIC_SPI 221
++ IRQ_TYPE_LEVEL_HIGH>,
++ <0 0 0 4 &gicv2 GIC_SPI 222
++ IRQ_TYPE_LEVEL_HIGH>;
++ resets = <&bcm_reset 7>, <&bcm_reset 43>, <&pcie_rescal>;
++ reset-names = "swinit", "bridge", "rescal";
++ msi-controller;
++ msi-parent = <&mip1>;
++
++ ranges = <0x02000000 0x00 0x00000000
++ 0x1b 0x00000000
++ 0x00 0xfffffffc>,
++ <0x43000000 0x04 0x00000000
++ 0x18 0x00000000
++ 0x03 0x00000000>;
++
++ dma-ranges = <0x03000000 0x10 0x00000000
++ 0x00 0x00000000
++ 0x10 0x00000000>;
++
++ status = "disabled";
++ };
++
++ pcie_rescal: reset-controller@119500 {
++ compatible = "brcm,bcm7216-pcie-sata-rescal";
++ reg = <0x10 0x00119500 0x0 0x10>;
++ #reset-cells = <0>;
++ };
++
++ // Quad-lane Gen3 PCIe
++ // Outbound window at 0x1c_000000-0x1f_ffffff
++ pcie2: pcie@120000 {
++ compatible = "brcm,bcm2712-pcie";
++ reg = <0x10 0x00120000 0x0 0x9310>;
++ device_type = "pci";
++ max-link-speed = <2>;
++ #address-cells = <3>;
++ #interrupt-cells = <1>;
++ #size-cells = <2>;
++ /*
++ * Unused interrupts:
++ * 228: AER
++ * 235: NMI
++ * 236: PME
++ */
++ interrupt-parent = <&gicv2>;
++ interrupts = <GIC_SPI 233 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 234 IRQ_TYPE_LEVEL_HIGH>;
++ interrupt-names = "pcie", "msi";
++ interrupt-map-mask = <0x0 0x0 0x0 0x7>;
++ interrupt-map = <0 0 0 1 &gicv2 GIC_SPI 229
++ IRQ_TYPE_LEVEL_HIGH>,
++ <0 0 0 2 &gicv2 GIC_SPI 230
++ IRQ_TYPE_LEVEL_HIGH>,
++ <0 0 0 3 &gicv2 GIC_SPI 231
++ IRQ_TYPE_LEVEL_HIGH>,
++ <0 0 0 4 &gicv2 GIC_SPI 232
++ IRQ_TYPE_LEVEL_HIGH>;
++ resets = <&bcm_reset 32>, <&bcm_reset 44>, <&pcie_rescal>;
++ reset-names = "swinit", "bridge", "rescal";
++ msi-controller;
++ msi-parent = <&mip0>;
++
++ // ~4GB, 32-bit, not-prefetchable at PCIe 00_00000000
++ ranges = <0x02000000 0x00 0x00000000
++ 0x1f 0x00000000
++ 0x0 0xfffffffc>,
++ // 12GB, 64-bit, prefetchable at PCIe 04_00000000
++ <0x43000000 0x04 0x00000000
++ 0x1c 0x00000000
++ 0x03 0x00000000>;
++
++ // 64GB system RAM space at PCIe 10_00000000
++ dma-ranges = <0x02000000 0x00 0x00000000
++ 0x1f 0x00000000
++ 0x00 0x00400000>,
++ <0x43000000 0x10 0x00000000
++ 0x00 0x00000000
++ 0x10 0x00000000>;
++
++ status = "disabled";
++ };
++
++ mip0: msi-controller@130000 {
++ compatible = "brcm,bcm2712-mip-intc";
++ reg = <0x10 0x00130000 0x0 0xc0>;
++ msi-controller;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ brcm,msi-base-spi = <128>;
++ brcm,msi-num-spis = <64>;
++ brcm,msi-offset = <0>;
++ brcm,msi-pci-addr = <0xff 0xfffff000>;
++ };
++
++ mip1: msi-controller@131000 {
++ compatible = "brcm,bcm2712-mip-intc";
++ reg = <0x10 0x00131000 0x0 0xc0>;
++ msi-controller;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ brcm,msi-base-spi = <247>;
++ /* Actually 20 total, but the others are
++ * both sparse and non-consecutive */
++ brcm,msi-num-spis = <8>;
++ brcm,msi-offset = <8>;
++ brcm,msi-pci-addr = <0xff 0xffffe000>;
++ };
++
++ syscon_piarbctl: syscon@400018 {
++ compatible = "brcm,syscon-piarbctl", "syscon", "simple-mfd";
++ reg = <0x10 0x00400018 0x0 0x18>;
++ };
++
++ usb: usb@480000 {
++ compatible = "brcm,bcm2835-usb";
++ reg = <0x10 0x00480000 0x0 0x10000>;
++ interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ clocks = <&clk_usb>;
++ clock-names = "otg";
++ phys = <&usbphy>;
++ phy-names = "usb2-phy";
++ status = "disabled";
++ };
++
++ rpivid: codec@800000 {
++ compatible = "raspberrypi,rpivid-vid-decoder";
++ reg = <0x10 0x00800000 0x0 0x10000>, /* HEVC */
++ <0x10 0x00840000 0x0 0x1000>; /* INTC */
++ reg-names = "hevc",
++ "intc";
++
++ interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
++
++ clocks = <&firmware_clocks 11>;
++ clock-names = "hevc";
++ iommus = <&iommu2>;
++ status = "disabled";
++ };
++
++ sdio1: mmc@fff000 {
++ compatible = "brcm,bcm2712-sdhci";
++ reg = <0x10 0x00fff000 0x0 0x260>,
++ <0x10 0x00fff400 0x0 0x200>,
++ <0x10 0x015040b0 0x0 0x4>, // Bus isolation control
++ <0x10 0x015200f0 0x0 0x24>; // LCPLL control misc0-8
++ reg-names = "host", "cfg", "busisol", "lcpll";
++ interrupts = <GIC_SPI 273 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clk_emmc2>;
++ sdhci-caps-mask = <0x0000C000 0x0>;
++ sdhci-caps = <0x0 0x0>;
++ mmc-ddr-3_3v;
++ };
++
++ sdio2: mmc@1100000 {
++ compatible = "brcm,bcm2712-sdhci";
++ reg = <0x10 0x01100000 0x0 0x260>,
++ <0x10 0x01100400 0x0 0x200>;
++ reg-names = "host", "cfg";
++ interrupts = <GIC_SPI 274 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clk_emmc2>;
++ sdhci-caps-mask = <0x0000C000 0x0>;
++ sdhci-caps = <0x0 0x0>;
++ supports-cqe;
++ mmc-ddr-3_3v;
++ status = "disabled";
++ };
++
++ bcm_reset: reset-controller@1504318 {
++ compatible = "brcm,brcmstb-reset";
++ reg = <0x10 0x01504318 0x0 0x30>;
++ #reset-cells = <1>;
++ };
++
++ v3d: v3d@2000000 {
++ compatible = "brcm,2712-v3d";
++ reg = <0x10 0x02000000 0x0 0x4000>,
++ <0x10 0x02008000 0x0 0x6000>;
++ reg-names = "hub", "core0";
++
++ power-domains = <&pm BCM2835_POWER_DOMAIN_GRAFX_V3D>;
++ resets = <&pm BCM2835_RESET_V3D>;
++ clocks = <&firmware_clocks 5>;
++ clocks-names = "v3d";
++ interrupts = <GIC_SPI 250 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 249 IRQ_TYPE_LEVEL_HIGH>;
++ status = "disabled";
++ };
++
++ gicv2: interrupt-controller@7fff9000 {
++ interrupt-controller;
++ #interrupt-cells = <3>;
++ compatible = "arm,gic-400";
++ reg = <0x10 0x7fff9000 0x0 0x1000>,
++ <0x10 0x7fffa000 0x0 0x2000>,
++ <0x10 0x7fffc000 0x0 0x2000>,
++ <0x10 0x7fffe000 0x0 0x2000>;
++ interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) |
++ IRQ_TYPE_LEVEL_HIGH)>;
++ };
++
++ pisp_be: pisp_be@880000 {
++ compatible = "raspberrypi,pispbe";
++ reg = <0x10 0x00880000 0x0 0x4000>;
++ interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&firmware_clocks 7>;
++ clocks-names = "isp_be";
++ status = "okay";
++ iommus = <&iommu2>;
++ };
++ };
++
++ clocks {
++ /* The oscillator is the root of the clock tree. */
++ clk_osc: clk-osc {
++ compatible = "fixed-clock";
++ #clock-cells = <0>;
++ clock-output-names = "osc";
++ clock-frequency = <54000000>;
++ };
++
++ clk_usb: clk-usb {
++ compatible = "fixed-clock";
++ #clock-cells = <0>;
++ clock-output-names = "otg";
++ clock-frequency = <480000000>;
++ };
++
++ clk_vpu: clk_vpu {
++ #clock-cells = <0>;
++ compatible = "fixed-clock";
++ clock-frequency = <750000000>;
++ clock-output-names = "vpu-clock";
++ };
++
++ clk_uart: clk_uart {
++ #clock-cells = <0>;
++ compatible = "fixed-clock";
++ clock-frequency = <9216000>;
++ clock-output-names = "uart-clock";
++ };
++
++ clk_emmc2: clk_emmc2 {
++ #clock-cells = <0>;
++ compatible = "fixed-clock";
++ clock-frequency = <200000000>;
++ clock-output-names = "emmc2-clock";
++ };
++ };
++
++ usbphy: phy {
++ compatible = "usb-nop-xceiv";
++ #phy-cells = <0>;
++ };
++};
+--- /dev/null
++++ b/arch/arm64/boot/dts/broadcom/rp1.dtsi
+@@ -0,0 +1,1287 @@
++#include <dt-bindings/clock/rp1.h>
++#include <dt-bindings/interrupt-controller/irq.h>
++#include <dt-bindings/mfd/rp1.h>
++
++&rp1_target {
++ rp1: rp1 {
++ compatible = "simple-bus";
++ #address-cells = <2>;
++ #size-cells = <2>;
++ #interrupt-cells = <2>;
++ interrupt-controller;
++ interrupt-parent = <&rp1>;
++
++ // ranges and dma-ranges must be provided by the includer
++
++ rp1_clocks: clocks@18000 {
++ compatible = "raspberrypi,rp1-clocks";
++ #clock-cells = <1>;
++ reg = <0xc0 0x40018000 0x0 0x10038>;
++ clocks = <&clk_xosc>;
++
++ assigned-clocks = <&rp1_clocks RP1_PLL_SYS_CORE>,
++ <&rp1_clocks RP1_PLL_AUDIO_CORE>,
++ // RP1_PLL_VIDEO_CORE and dividers are now managed by VEC,DPI drivers
++ <&rp1_clocks RP1_PLL_SYS>,
++ <&rp1_clocks RP1_PLL_SYS_SEC>,
++ <&rp1_clocks RP1_PLL_AUDIO>,
++ <&rp1_clocks RP1_PLL_AUDIO_SEC>,
++ <&rp1_clocks RP1_CLK_SYS>,
++ <&rp1_clocks RP1_PLL_SYS_PRI_PH>,
++ // RP1_CLK_SLOW_SYS is used for the frequency counter (FC0)
++ <&rp1_clocks RP1_CLK_SLOW_SYS>,
++ <&rp1_clocks RP1_CLK_SDIO_TIMER>,
++ <&rp1_clocks RP1_CLK_SDIO_ALT_SRC>,
++ <&rp1_clocks RP1_CLK_ETH_TSU>;
++
++ assigned-clock-rates = <1000000000>, // RP1_PLL_SYS_CORE
++ <1536000000>, // RP1_PLL_AUDIO_CORE
++ <200000000>, // RP1_PLL_SYS
++ <125000000>, // RP1_PLL_SYS_SEC
++ <61440000>, // RP1_PLL_AUDIO
++ <192000000>, // RP1_PLL_AUDIO_SEC
++ <200000000>, // RP1_CLK_SYS
++ <100000000>, // RP1_PLL_SYS_PRI_PH
++ // Must match the XOSC frequency
++ <50000000>, // RP1_CLK_SLOW_SYS
++ <1000000>, // RP1_CLK_SDIO_TIMER
++ <200000000>, // RP1_CLK_SDIO_ALT_SRC
++ <50000000>; // RP1_CLK_ETH_TSU
++ };
++
++ rp1_uart0: serial@30000 {
++ compatible = "arm,pl011-axi";
++ reg = <0xc0 0x40030000 0x0 0x100>;
++ interrupts = <RP1_INT_UART0 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&rp1_clocks RP1_CLK_UART &rp1_clocks RP1_PLL_SYS_PRI_PH>;
++ clock-names = "uartclk", "apb_pclk";
++ dmas = <&rp1_dma RP1_DMA_UART0_TX>,
++ <&rp1_dma RP1_DMA_UART0_RX>;
++ dma-names = "tx", "rx";
++ pinctrl-names = "default";
++ arm,primecell-periphid = <0x00541011>;
++ uart-has-rtscts;
++ cts-event-workaround;
++ skip-init;
++ status = "disabled";
++ };
++
++ rp1_uart1: serial@34000 {
++ compatible = "arm,pl011-axi";
++ reg = <0xc0 0x40034000 0x0 0x100>;
++ interrupts = <RP1_INT_UART1 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&rp1_clocks RP1_CLK_UART &rp1_clocks RP1_PLL_SYS_PRI_PH>;
++ clock-names = "uartclk", "apb_pclk";
++ // dmas = <&rp1_dma RP1_DMA_UART1_TX>,
++ // <&rp1_dma RP1_DMA_UART1_RX>;
++ // dma-names = "tx", "rx";
++ pinctrl-names = "default";
++ arm,primecell-periphid = <0x00541011>;
++ uart-has-rtscts;
++ cts-event-workaround;
++ skip-init;
++ status = "disabled";
++ };
++
++ rp1_uart2: serial@38000 {
++ compatible = "arm,pl011-axi";
++ reg = <0xc0 0x40038000 0x0 0x100>;
++ interrupts = <RP1_INT_UART2 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&rp1_clocks RP1_CLK_UART &rp1_clocks RP1_PLL_SYS_PRI_PH>;
++ clock-names = "uartclk", "apb_pclk";
++ // dmas = <&rp1_dma RP1_DMA_UART2_TX>,
++ // <&rp1_dma RP1_DMA_UART2_RX>;
++ // dma-names = "tx", "rx";
++ pinctrl-names = "default";
++ arm,primecell-periphid = <0x00541011>;
++ uart-has-rtscts;
++ cts-event-workaround;
++ skip-init;
++ status = "disabled";
++ };
++
++ rp1_uart3: serial@3c000 {
++ compatible = "arm,pl011-axi";
++ reg = <0xc0 0x4003c000 0x0 0x100>;
++ interrupts = <RP1_INT_UART3 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&rp1_clocks RP1_CLK_UART &rp1_clocks RP1_PLL_SYS_PRI_PH>;
++ clock-names = "uartclk", "apb_pclk";
++ // dmas = <&rp1_dma RP1_DMA_UART3_TX>,
++ // <&rp1_dma RP1_DMA_UART3_RX>;
++ // dma-names = "tx", "rx";
++ pinctrl-names = "default";
++ arm,primecell-periphid = <0x00541011>;
++ uart-has-rtscts;
++ cts-event-workaround;
++ skip-init;
++ status = "disabled";
++ };
++
++ rp1_uart4: serial@40000 {
++ compatible = "arm,pl011-axi";
++ reg = <0xc0 0x40040000 0x0 0x100>;
++ interrupts = <RP1_INT_UART4 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&rp1_clocks RP1_CLK_UART &rp1_clocks RP1_PLL_SYS_PRI_PH>;
++ clock-names = "uartclk", "apb_pclk";
++ // dmas = <&rp1_dma RP1_DMA_UART4_TX>,
++ // <&rp1_dma RP1_DMA_UART4_RX>;
++ // dma-names = "tx", "rx";
++ pinctrl-names = "default";
++ arm,primecell-periphid = <0x00541011>;
++ uart-has-rtscts;
++ cts-event-workaround;
++ skip-init;
++ status = "disabled";
++ };
++
++ rp1_uart5: serial@44000 {
++ compatible = "arm,pl011-axi";
++ reg = <0xc0 0x40044000 0x0 0x100>;
++ interrupts = <RP1_INT_UART5 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&rp1_clocks RP1_CLK_UART &rp1_clocks RP1_PLL_SYS_PRI_PH>;
++ clock-names = "uartclk", "apb_pclk";
++ // dmas = <&rp1_dma RP1_DMA_UART5_TX>,
++ // <&rp1_dma RP1_DMA_UART5_RX>;
++ // dma-names = "tx", "rx";
++ pinctrl-names = "default";
++ arm,primecell-periphid = <0x00541011>;
++ uart-has-rtscts;
++ cts-event-workaround;
++ skip-init;
++ status = "disabled";
++ };
++
++ rp1_spi8: spi@4c000 {
++ reg = <0xc0 0x4004c000 0x0 0x130>;
++ compatible = "snps,dw-apb-ssi";
++ interrupts = <RP1_INT_SPI8 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&rp1_clocks RP1_CLK_SYS>;
++ clock-names = "ssi_clk";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ num-cs = <2>;
++ dmas = <&rp1_dma RP1_DMA_SPI8_TX>,
++ <&rp1_dma RP1_DMA_SPI8_RX>;
++ dma-names = "tx", "rx";
++ status = "disabled";
++ };
++
++ rp1_spi0: spi@50000 {
++ reg = <0xc0 0x40050000 0x0 0x130>;
++ compatible = "snps,dw-apb-ssi";
++ interrupts = <RP1_INT_SPI0 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&rp1_clocks RP1_CLK_SYS>;
++ clock-names = "ssi_clk";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ num-cs = <2>;
++ dmas = <&rp1_dma RP1_DMA_SPI0_TX>,
++ <&rp1_dma RP1_DMA_SPI0_RX>;
++ dma-names = "tx", "rx";
++ status = "disabled";
++ };
++
++ rp1_spi1: spi@54000 {
++ reg = <0xc0 0x40054000 0x0 0x130>;
++ compatible = "snps,dw-apb-ssi";
++ interrupts = <RP1_INT_SPI1 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&rp1_clocks RP1_CLK_SYS>;
++ clock-names = "ssi_clk";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ num-cs = <2>;
++ dmas = <&rp1_dma RP1_DMA_SPI1_TX>,
++ <&rp1_dma RP1_DMA_SPI1_RX>;
++ dma-names = "tx", "rx";
++ status = "disabled";
++ };
++
++ rp1_spi2: spi@58000 {
++ reg = <0xc0 0x40058000 0x0 0x130>;
++ compatible = "snps,dw-apb-ssi";
++ interrupts = <RP1_INT_SPI2 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&rp1_clocks RP1_CLK_SYS>;
++ clock-names = "ssi_clk";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ num-cs = <2>;
++ dmas = <&rp1_dma RP1_DMA_SPI2_TX>,
++ <&rp1_dma RP1_DMA_SPI2_RX>;
++ dma-names = "tx", "rx";
++ status = "disabled";
++ };
++
++ rp1_spi3: spi@5c000 {
++ reg = <0xc0 0x4005c000 0x0 0x130>;
++ compatible = "snps,dw-apb-ssi";
++ interrupts = <RP1_INT_SPI3 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&rp1_clocks RP1_CLK_SYS>;
++ clock-names = "ssi_clk";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ num-cs = <2>;
++ dmas = <&rp1_dma RP1_DMA_SPI3_TX>,
++ <&rp1_dma RP1_DMA_SPI3_RX>;
++ dma-names = "tx", "rx";
++ status = "disabled";
++ };
++
++ // SPI4 is a target/slave interface
++ rp1_spi4: spi@60000 {
++ reg = <0xc0 0x40060000 0x0 0x130>;
++ compatible = "snps,dw-apb-ssi";
++ interrupts = <RP1_INT_SPI4 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&rp1_clocks RP1_CLK_SYS>;
++ clock-names = "ssi_clk";
++ #address-cells = <0>;
++ #size-cells = <0>;
++ num-cs = <1>;
++ spi-slave;
++ dmas = <&rp1_dma RP1_DMA_SPI4_TX>,
++ <&rp1_dma RP1_DMA_SPI4_RX>;
++ dma-names = "tx", "rx";
++ status = "disabled";
++
++ slave {
++ compatible = "spidev";
++ spi-max-frequency = <1000000>;
++ };
++ };
++
++ rp1_spi5: spi@64000 {
++ reg = <0xc0 0x40064000 0x0 0x130>;
++ compatible = "snps,dw-apb-ssi";
++ interrupts = <RP1_INT_SPI5 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&rp1_clocks RP1_CLK_SYS>;
++ clock-names = "ssi_clk";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ num-cs = <2>;
++ dmas = <&rp1_dma RP1_DMA_SPI5_TX>,
++ <&rp1_dma RP1_DMA_SPI5_RX>;
++ dma-names = "tx", "rx";
++ status = "disabled";
++ };
++
++ rp1_spi6: spi@68000 {
++ reg = <0xc0 0x40068000 0x0 0x130>;
++ compatible = "snps,dw-apb-ssi";
++ interrupts = <RP1_INT_SPI6 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&rp1_clocks RP1_CLK_SYS>;
++ clock-names = "ssi_clk";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ num-cs = <2>;
++ dmas = <&rp1_dma RP1_DMA_SPI6_TX>,
++ <&rp1_dma RP1_DMA_SPI6_RX>;
++ dma-names = "tx", "rx";
++ status = "disabled";
++ };
++
++ // SPI7 is a target/slave interface
++ rp1_spi7: spi@6c000 {
++ reg = <0xc0 0x4006c000 0x0 0x130>;
++ compatible = "snps,dw-apb-ssi";
++ interrupts = <RP1_INT_SPI7 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&rp1_clocks RP1_CLK_SYS>;
++ clock-names = "ssi_clk";
++ #address-cells = <0>;
++ #size-cells = <0>;
++ num-cs = <1>;
++ spi-slave;
++ dmas = <&rp1_dma RP1_DMA_SPI7_TX>,
++ <&rp1_dma RP1_DMA_SPI7_RX>;
++ dma-names = "tx", "rx";
++ status = "disabled";
++
++ slave {
++ compatible = "spidev";
++ spi-max-frequency = <1000000>;
++ };
++ };
++
++ rp1_i2c0: i2c@70000 {
++ reg = <0xc0 0x40070000 0x0 0x1000>;
++ compatible = "snps,designware-i2c";
++ interrupts = <RP1_INT_I2C0 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&rp1_clocks RP1_CLK_SYS>;
++ i2c-scl-rising-time-ns = <65>;
++ i2c-scl-falling-time-ns = <100>;
++ status = "disabled";
++ };
++
++ rp1_i2c1: i2c@74000 {
++ reg = <0xc0 0x40074000 0x0 0x1000>;
++ compatible = "snps,designware-i2c";
++ interrupts = <RP1_INT_I2C1 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&rp1_clocks RP1_CLK_SYS>;
++ i2c-scl-rising-time-ns = <65>;
++ i2c-scl-falling-time-ns = <100>;
++ status = "disabled";
++ };
++
++ rp1_i2c2: i2c@78000 {
++ reg = <0xc0 0x40078000 0x0 0x1000>;
++ compatible = "snps,designware-i2c";
++ interrupts = <RP1_INT_I2C2 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&rp1_clocks RP1_CLK_SYS>;
++ i2c-scl-rising-time-ns = <65>;
++ i2c-scl-falling-time-ns = <100>;
++ status = "disabled";
++ };
++
++ rp1_i2c3: i2c@7c000 {
++ reg = <0xc0 0x4007c000 0x0 0x1000>;
++ compatible = "snps,designware-i2c";
++ interrupts = <RP1_INT_I2C3 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&rp1_clocks RP1_CLK_SYS>;
++ i2c-scl-rising-time-ns = <65>;
++ i2c-scl-falling-time-ns = <100>;
++ status = "disabled";
++ };
++
++ rp1_i2c4: i2c@80000 {
++ reg = <0xc0 0x40080000 0x0 0x1000>;
++ compatible = "snps,designware-i2c";
++ interrupts = <RP1_INT_I2C4 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&rp1_clocks RP1_CLK_SYS>;
++ i2c-scl-rising-time-ns = <65>;
++ i2c-scl-falling-time-ns = <100>;
++ status = "disabled";
++ };
++
++ rp1_i2c5: i2c@84000 {
++ reg = <0xc0 0x40084000 0x0 0x1000>;
++ compatible = "snps,designware-i2c";
++ interrupts = <RP1_INT_I2C5 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&rp1_clocks RP1_CLK_SYS>;
++ i2c-scl-rising-time-ns = <65>;
++ i2c-scl-falling-time-ns = <100>;
++ status = "disabled";
++ };
++
++ rp1_i2c6: i2c@88000 {
++ reg = <0xc0 0x40088000 0x0 0x1000>;
++ compatible = "snps,designware-i2c";
++ interrupts = <RP1_INT_I2C6 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&rp1_clocks RP1_CLK_SYS>;
++ i2c-scl-rising-time-ns = <65>;
++ i2c-scl-falling-time-ns = <100>;
++ status = "disabled";
++ };
++
++ rp1_pwm0: pwm@98000 {
++ compatible = "raspberrypi,rp1-pwm";
++ reg = <0xc0 0x40098000 0x0 0x100>;
++ #pwm-cells = <3>;
++ clocks = <&rp1_clocks RP1_CLK_PWM0>;
++ assigned-clocks = <&rp1_clocks RP1_CLK_PWM0>;
++ assigned-clock-rates = <50000000>;
++ status = "disabled";
++ };
++
++ rp1_pwm1: pwm@9c000 {
++ compatible = "raspberrypi,rp1-pwm";
++ reg = <0xc0 0x4009c000 0x0 0x100>;
++ #pwm-cells = <3>;
++ clocks = <&rp1_clocks RP1_CLK_PWM1>;
++ assigned-clocks = <&rp1_clocks RP1_CLK_PWM1>;
++ assigned-clock-rates = <50000000>;
++ status = "disabled";
++ };
++
++ rp1_i2s0: i2s@a0000 {
++ reg = <0xc0 0x400a0000 0x0 0x1000>;
++ compatible = "snps,designware-i2s";
++ // Providing an interrupt disables DMA
++ // interrupts = <RP1_INT_I2S0 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&rp1_clocks RP1_CLK_I2S>;
++ clock-names = "i2sclk";
++ #sound-dai-cells = <0>;
++ dmas = <&rp1_dma RP1_DMA_I2S0_TX>,<&rp1_dma RP1_DMA_I2S0_RX>;
++ dma-names = "tx", "rx";
++ status = "disabled";
++ };
++
++ rp1_i2s1: i2s@a4000 {
++ reg = <0xc0 0x400a4000 0x0 0x1000>;
++ compatible = "snps,designware-i2s";
++ // Providing an interrupt disables DMA
++ // interrupts = <RP1_INT_I2S1 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&rp1_clocks RP1_CLK_I2S>;
++ clock-names = "i2sclk";
++ #sound-dai-cells = <0>;
++ dmas = <&rp1_dma RP1_DMA_I2S1_TX>,<&rp1_dma RP1_DMA_I2S1_RX>;
++ dma-names = "tx", "rx";
++ status = "disabled";
++ };
++
++ rp1_i2s2: i2s@a8000 {
++ reg = <0xc0 0x400a8000 0x0 0x1000>;
++ compatible = "snps,designware-i2s";
++ // Providing an interrupt disables DMA
++ // interrupts = <RP1_INT_I2S2 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&rp1_clocks RP1_CLK_I2S>;
++ status = "disabled";
++ };
++
++ rp1_sdio_clk0: sdio_clk0@b0004 {
++ compatible = "raspberrypi,rp1-sdio-clk";
++ reg = <0xc0 0x400b0004 0x0 0x1c>;
++ clocks = <&sdio_src &sdhci_core>;
++ clock-names = "src", "base";
++ #clock-cells = <0>;
++ status = "disabled";
++ };
++
++ rp1_sdio_clk1: sdio_clk1@b4004 {
++ compatible = "raspberrypi,rp1-sdio-clk";
++ reg = <0xc0 0x400b4004 0x0 0x1c>;
++ clocks = <&sdio_src &sdhci_core>;
++ clock-names = "src", "base";
++ #clock-cells = <0>;
++ status = "disabled";
++ };
++
++ rp1_adc: adc@c8000 {
++ compatible = "raspberrypi,rp1-adc";
++ reg = <0xc0 0x400c8000 0x0 0x4000>;
++ clocks = <&rp1_clocks RP1_CLK_ADC>;
++ clock-names = "adcclk";
++ #clock-cells = <0>;
++ vref-supply = <&rp1_vdd_3v3>;
++ status = "disabled";
++ };
++
++ rp1_gpio: gpio@d0000 {
++ reg = <0xc0 0x400d0000 0x0 0xc000>,
++ <0xc0 0x400e0000 0x0 0xc000>,
++ <0xc0 0x400f0000 0x0 0xc000>;
++ compatible = "raspberrypi,rp1-gpio";
++ interrupts = <RP1_INT_IO_BANK0 IRQ_TYPE_LEVEL_HIGH>,
++ <RP1_INT_IO_BANK1 IRQ_TYPE_LEVEL_HIGH>,
++ <RP1_INT_IO_BANK2 IRQ_TYPE_LEVEL_HIGH>;
++ gpio-controller;
++ #gpio-cells = <2>;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ gpio-ranges = <&rp1_gpio 0 0 54>;
++
++ rp1_uart0_14_15: rp1_uart0_14_15 {
++ pin_txd {
++ function = "uart0";
++ pins = "gpio14";
++ bias-disable;
++ };
++ pin_rxd {
++ function = "uart0";
++ pins = "gpio15";
++ bias-pull-up;
++ };
++ };
++ rp1_uart0_ctsrts_16_17: rp1_uart0_ctsrts_16_17 {
++ pin_cts {
++ function = "uart0";
++ pins = "gpio16";
++ bias-pull-up;
++ };
++ pin_rts {
++ function = "uart0";
++ pins = "gpio17";
++ bias-disable;
++ };
++ };
++ rp1_uart1_0_1: rp1_uart1_0_1 {
++ pin_txd {
++ function = "uart1";
++ pins = "gpio0";
++ bias-disable;
++ };
++ pin_rxd {
++ function = "uart1";
++ pins = "gpio1";
++ bias-pull-up;
++ };
++ };
++ rp1_uart1_ctsrts_2_3: rp1_uart1_ctsrts_2_3 {
++ pin_cts {
++ function = "uart1";
++ pins = "gpio2";
++ bias-pull-up;
++ };
++ pin_rts {
++ function = "uart1";
++ pins = "gpio3";
++ bias-disable;
++ };
++ };
++ rp1_uart2_4_5: rp1_uart2_4_5 {
++ pin_txd {
++ function = "uart2";
++ pins = "gpio4";
++ bias-disable;
++ };
++ pin_rxd {
++ function = "uart2";
++ pins = "gpio5";
++ bias-pull-up;
++ };
++ };
++ rp1_uart2_ctsrts_6_7: rp1_uart2_ctsrts_6_7 {
++ pin_cts {
++ function = "uart2";
++ pins = "gpio6";
++ bias-pull-up;
++ };
++ pin_rts {
++ function = "uart2";
++ pins = "gpio7";
++ bias-disable;
++ };
++ };
++ rp1_uart3_8_9: rp1_uart3_8_9 {
++ pin_txd {
++ function = "uart3";
++ pins = "gpio8";
++ bias-disable;
++ };
++ pin_rxd {
++ function = "uart3";
++ pins = "gpio9";
++ bias-pull-up;
++ };
++ };
++ rp1_uart3_ctsrts_10_11: rp1_uart3_ctsrts_10_11 {
++ pin_cts {
++ function = "uart3";
++ pins = "gpio10";
++ bias-pull-up;
++ };
++ pin_rts {
++ function = "uart3";
++ pins = "gpio11";
++ bias-disable;
++ };
++ };
++ rp1_uart4_12_13: rp1_uart4_12_13 {
++ pin_txd {
++ function = "uart4";
++ pins = "gpio12";
++ bias-disable;
++ };
++ pin_rxd {
++ function = "uart4";
++ pins = "gpio13";
++ bias-pull-up;
++ };
++ };
++ rp1_uart4_ctsrts_14_15: rp1_uart4_ctsrts_14_15 {
++ pin_cts {
++ function = "uart4";
++ pins = "gpio14";
++ bias-pull-up;
++ };
++ pin_rts {
++ function = "uart4";
++ pins = "gpio15";
++ bias-disable;
++ };
++ };
++
++ rp1_sdio0_22_27: rp1_sdio0_22_27 {
++ pin_clk {
++ function = "sd0";
++ pins = "gpio22";
++ bias-disable;
++ drive-strength = <12>;
++ slew-rate = <1>;
++ };
++ pin_cmd {
++ function = "sd0";
++ pins = "gpio23";
++ bias-pull-up;
++ drive-strength = <12>;
++ slew-rate = <1>;
++ };
++ pins_dat {
++ function = "sd0";
++ pins = "gpio24", "gpio25", "gpio26", "gpio27";
++ bias-pull-up;
++ drive-strength = <12>;
++ slew-rate = <1>;
++ };
++ };
++
++ rp1_sdio1_28_33: rp1_sdio1_28_33 {
++ pin_clk {
++ function = "sd1";
++ pins = "gpio28";
++ bias-disable;
++ drive-strength = <12>;
++ slew-rate = <1>;
++ };
++ pin_cmd {
++ function = "sd1";
++ pins = "gpio29";
++ bias-pull-up;
++ drive-strength = <12>;
++ slew-rate = <1>;
++ };
++ pins_dat {
++ function = "sd1";
++ pins = "gpio30", "gpio31", "gpio32", "gpio33";
++ bias-pull-up;
++ drive-strength = <12>;
++ slew-rate = <1>;
++ };
++ };
++
++ rp1_i2s0_18_21: rp1_i2s0_18_21 {
++ function = "i2s0";
++ pins = "gpio18", "gpio19", "gpio20", "gpio21";
++ bias-disable;
++ };
++
++ rp1_i2s1_18_21: rp1_i2s1_18_21 {
++ function = "i2s1";
++ pins = "gpio18", "gpio19", "gpio20", "gpio21";
++ bias-disable;
++ };
++
++ rp1_i2c4_34_35: rp1_i2c4_34_35 {
++ function = "i2c4";
++ pins = "gpio34", "gpio35";
++ drive-strength = <12>;
++ bias-pull-up;
++ };
++ rp1_i2c6_38_39: rp1_i2c6_38_39 {
++ function = "i2c6";
++ pins = "gpio38", "gpio39";
++ drive-strength = <12>;
++ bias-pull-up;
++ };
++ rp1_i2c4_40_41: rp1_i2c4_40_41 {
++ function = "i2c4";
++ pins = "gpio40", "gpio41";
++ drive-strength = <12>;
++ bias-pull-up;
++ };
++ rp1_i2c5_44_45: rp1_i2c5_44_45 {
++ function = "i2c5";
++ pins = "gpio44", "gpio45";
++ drive-strength = <12>;
++ bias-pull-up;
++ };
++ rp1_i2c0_0_1: rp1_i2c0_0_1 {
++ function = "i2c0";
++ pins = "gpio0", "gpio1";
++ drive-strength = <12>;
++ bias-pull-up;
++ };
++ rp1_i2c0_8_9: rp1_i2c0_8_9 {
++ function = "i2c0";
++ pins = "gpio8", "gpio9";
++ drive-strength = <12>;
++ bias-pull-up;
++ };
++ rp1_i2c1_2_3: rp1_i2c1_2_3 {
++ function = "i2c1";
++ pins = "gpio2", "gpio3";
++ drive-strength = <12>;
++ bias-pull-up;
++ };
++ rp1_i2c1_10_11: rp1_i2c1_10_11 {
++ function = "i2c1";
++ pins = "gpio10", "gpio11";
++ drive-strength = <12>;
++ bias-pull-up;
++ };
++ rp1_i2c2_4_5: rp1_i2c2_4_5 {
++ function = "i2c2";
++ pins = "gpio4", "gpio5";
++ drive-strength = <12>;
++ bias-pull-up;
++ };
++ rp1_i2c2_12_13: rp1_i2c2_12_13 {
++ function = "i2c2";
++ pins = "gpio12", "gpio13";
++ drive-strength = <12>;
++ bias-pull-up;
++ };
++ rp1_i2c3_6_7: rp1_i2c3_6_7 {
++ function = "i2c3";
++ pins = "gpio6", "gpio7";
++ drive-strength = <12>;
++ bias-pull-up;
++ };
++ rp1_i2c3_14_15: rp1_i2c3_14_15 {
++ function = "i2c3";
++ pins = "gpio14", "gpio15";
++ drive-strength = <12>;
++ bias-pull-up;
++ };
++ rp1_i2c3_22_23: rp1_i2c3_22_23 {
++ function = "i2c3";
++ pins = "gpio22", "gpio23";
++ drive-strength = <12>;
++ bias-pull-up;
++ };
++
++ // DPI mappings with HSYNC,VSYNC but without PIXCLK,DE
++ rp1_dpi_16bit_gpio2: rp1_dpi_16bit_gpio2 { /* Mode 2, not fully supported by RP1 */
++ function = "dpi";
++ pins = "gpio2", "gpio3", "gpio4", "gpio5",
++ "gpio6", "gpio7", "gpio8", "gpio9",
++ "gpio10", "gpio11", "gpio12", "gpio13",
++ "gpio14", "gpio15", "gpio16", "gpio17",
++ "gpio18", "gpio19";
++ bias-disable;
++ };
++ rp1_dpi_16bit_cpadhi_gpio2: rp1_dpi_16bit_cpadhi_gpio2 { /* Mode 3 */
++ function = "dpi";
++ pins = "gpio2", "gpio3", "gpio4", "gpio5",
++ "gpio6", "gpio7", "gpio8",
++ "gpio12", "gpio13", "gpio14", "gpio15",
++ "gpio16", "gpio17",
++ "gpio20", "gpio21", "gpio22", "gpio23",
++ "gpio24";
++ bias-disable;
++ };
++ rp1_dpi_16bit_pad666_gpio2: rp1_dpi_16bit_pad666_gpio2 { /* Mode 4 */
++ function = "dpi";
++ pins = "gpio2", "gpio3",
++ "gpio5", "gpio6", "gpio7", "gpio8",
++ "gpio9",
++ "gpio12", "gpio13", "gpio14", "gpio15",
++ "gpio16", "gpio17",
++ "gpio21", "gpio22", "gpio23", "gpio24",
++ "gpio25";
++ bias-disable;
++ };
++ rp1_dpi_18bit_gpio2: rp1_dpi_18bit_gpio2 { /* Mode 5, not fully supported by RP1 */
++ function = "dpi";
++ pins = "gpio2", "gpio3", "gpio4", "gpio5",
++ "gpio6", "gpio7", "gpio8", "gpio9",
++ "gpio10", "gpio11", "gpio12", "gpio13",
++ "gpio14", "gpio15", "gpio16", "gpio17",
++ "gpio18", "gpio19", "gpio20", "gpio21";
++ bias-disable;
++ };
++ rp1_dpi_18bit_cpadhi_gpio2: rp1_dpi_18bit_cpadhi_gpio2 { /* Mode 6 */
++ function = "dpi";
++ pins = "gpio2", "gpio3", "gpio4", "gpio5",
++ "gpio6", "gpio7", "gpio8", "gpio9",
++ "gpio12", "gpio13", "gpio14", "gpio15",
++ "gpio16", "gpio17",
++ "gpio20", "gpio21", "gpio22", "gpio23",
++ "gpio24", "gpio25";
++ bias-disable;
++ };
++ rp1_dpi_24bit_gpio2: rp1_dpi_24bit_gpio2 { /* Mode 7 */
++ function = "dpi";
++ pins = "gpio2", "gpio3", "gpio4", "gpio5",
++ "gpio6", "gpio7", "gpio8", "gpio9",
++ "gpio10", "gpio11", "gpio12", "gpio13",
++ "gpio14", "gpio15", "gpio16", "gpio17",
++ "gpio18", "gpio19", "gpio20", "gpio21",
++ "gpio22", "gpio23", "gpio24", "gpio25",
++ "gpio26", "gpio27";
++ bias-disable;
++ };
++ rp1_dpi_hvsync: rp1_dpi_hvsync { /* Sync only, for use with int VDAC */
++ function = "dpi";
++ pins = "gpio2", "gpio3";
++ bias-disable;
++ };
++
++ // More DPI mappings, including PIXCLK,DE on GPIOs 0,1
++ rp1_dpi_16bit_gpio0: rp1_dpi_16bit_gpio0 { /* Mode 2, not fully supported by RP1 */
++ function = "dpi";
++ pins = "gpio0", "gpio1", "gpio2", "gpio3",
++ "gpio4", "gpio5", "gpio6", "gpio7",
++ "gpio8", "gpio9", "gpio10", "gpio11",
++ "gpio12", "gpio13", "gpio14", "gpio15",
++ "gpio16", "gpio17", "gpio18", "gpio19";
++ bias-disable;
++ };
++ rp1_dpi_16bit_cpadhi_gpio0: rp1_dpi_16bit_cpadhi_gpio0 { /* Mode 3 */
++ function = "dpi";
++ pins = "gpio0", "gpio1", "gpio2", "gpio3",
++ "gpio4", "gpio5", "gpio6", "gpio7",
++ "gpio8",
++ "gpio12", "gpio13", "gpio14", "gpio15",
++ "gpio16", "gpio17",
++ "gpio20", "gpio21", "gpio22", "gpio23",
++ "gpio24";
++ bias-disable;
++ };
++ rp1_dpi_16bit_pad666_gpio0: rp1_dpi_16bit_pad666_gpio0 { /* Mode 4 */
++ function = "dpi";
++ pins = "gpio0", "gpio1", "gpio2", "gpio3",
++ "gpio5", "gpio6", "gpio7", "gpio8",
++ "gpio9",
++ "gpio12", "gpio13", "gpio14", "gpio15",
++ "gpio16", "gpio17",
++ "gpio21", "gpio22", "gpio23", "gpio24",
++ "gpio25";
++ bias-disable;
++ };
++ rp1_dpi_18bit_gpio0: rp1_dpi_18bit_gpio0 { /* Mode 5, not fully supported by RP1 */
++ function = "dpi";
++ pins = "gpio0", "gpio1", "gpio2", "gpio3",
++ "gpio4", "gpio5", "gpio6", "gpio7",
++ "gpio8", "gpio9", "gpio10", "gpio11",
++ "gpio12", "gpio13", "gpio14", "gpio15",
++ "gpio16", "gpio17", "gpio18", "gpio19",
++ "gpio20", "gpio21";
++ bias-disable;
++ };
++ rp1_dpi_18bit_cpadhi_gpio0: rp1_dpi_18bit_cpadhi_gpio0 { /* Mode 6 */
++ function = "dpi";
++ pins = "gpio0", "gpio1", "gpio2", "gpio3",
++ "gpio4", "gpio5", "gpio6", "gpio7",
++ "gpio8", "gpio9",
++ "gpio12", "gpio13", "gpio14", "gpio15",
++ "gpio16", "gpio17",
++ "gpio20", "gpio21", "gpio22", "gpio23",
++ "gpio24", "gpio25";
++ bias-disable;
++ };
++ rp1_dpi_24bit_gpio0: rp1_dpi_24bit_gpio0 { /* Mode 7 -- All GPIOs used! */
++ function = "dpi";
++ pins = "gpio0", "gpio1", "gpio2", "gpio3",
++ "gpio4", "gpio5", "gpio6", "gpio7",
++ "gpio8", "gpio9", "gpio10", "gpio11",
++ "gpio12", "gpio13", "gpio14", "gpio15",
++ "gpio16", "gpio17", "gpio18", "gpio19",
++ "gpio20", "gpio21", "gpio22", "gpio23",
++ "gpio24", "gpio25", "gpio26", "gpio27";
++ bias-disable;
++ };
++
++ rp1_gpclksrc0_gpio4: rp1_gpclksrc0_gpio4 {
++ function = "gpclk0";
++ pins = "gpio4";
++ bias-disable;
++ };
++
++ rp1_gpclksrc0_gpio20: rp1_gpclksrc0_gpio20 {
++ function = "gpclk0";
++ pins = "gpio20";
++ bias-disable;
++ };
++
++ rp1_gpclksrc1_gpio5: rp1_gpclksrc1_gpio5 {
++ function = "gpclk1";
++ pins = "gpio5";
++ bias-disable;
++ };
++
++ rp1_gpclksrc1_gpio18: rp1_gpclksrc1_gpio18 {
++ function = "gpclk1";
++ pins = "gpio18";
++ bias-disable;
++ };
++
++ rp1_gpclksrc1_gpio21: rp1_gpclksrc1_gpio21 {
++ function = "gpclk1";
++ pins = "gpio21";
++ bias-disable;
++ };
++
++ rp1_pwm1_gpio45: rp1_pwm1_gpio45 {
++ function = "pwm1";
++ pins = "gpio45";
++ bias-pull-down;
++ };
++
++ rp1_spi0_gpio9: rp1_spi0_gpio9 {
++ function = "spi0";
++ pins = "gpio9", "gpio10", "gpio11";
++ bias-disable;
++ drive-strength = <12>;
++ slew-rate = <1>;
++ };
++
++ rp1_spi0_cs_gpio7: rp1_spi0_cs_gpio7 {
++ function = "spi0";
++ pins = "gpio7", "gpio8";
++ bias-pull-up;
++ };
++
++ rp1_spi1_gpio19: rp1_spi1_gpio19 {
++ function = "spi1";
++ pins = "gpio19", "gpio20", "gpio21";
++ bias-disable;
++ drive-strength = <12>;
++ slew-rate = <1>;
++ };
++
++ rp1_spi2_gpio1: rp1_spi2_gpio1 {
++ function = "spi2";
++ pins = "gpio1", "gpio2", "gpio3";
++ bias-disable;
++ drive-strength = <12>;
++ slew-rate = <1>;
++ };
++
++ rp1_spi3_gpio5: rp1_spi3_gpio5 {
++ function = "spi3";
++ pins = "gpio5", "gpio6", "gpio7";
++ bias-disable;
++ drive-strength = <12>;
++ slew-rate = <1>;
++ };
++
++ rp1_spi4_gpio9: rp1_spi4_gpio9 {
++ function = "spi4";
++ pins = "gpio9", "gpio10", "gpio11";
++ bias-disable;
++ drive-strength = <12>;
++ slew-rate = <1>;
++ };
++
++ rp1_spi5_gpio13: rp1_spi5_gpio13 {
++ function = "spi5";
++ pins = "gpio13", "gpio14", "gpio15";
++ bias-disable;
++ drive-strength = <12>;
++ slew-rate = <1>;
++ };
++
++ rp1_spi8_gpio49: rp1_spi8_gpio49 {
++ function = "spi8";
++ pins = "gpio49", "gpio50", "gpio51";
++ bias-disable;
++ drive-strength = <12>;
++ slew-rate = <1>;
++ };
++
++ rp1_spi8_cs_gpio52: rp1_spi8_cs_gpio52 {
++ function = "spi0";
++ pins = "gpio52", "gpio53";
++ bias-pull-up;
++ };
++ };
++
++ rp1_eth: ethernet@100000 {
++ reg = <0xc0 0x40100000 0x0 0x4000>;
++ compatible = "cdns,macb";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ interrupts = <RP1_INT_ETH IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&macb_pclk &macb_hclk &rp1_clocks RP1_CLK_ETH_TSU>;
++ clock-names = "pclk", "hclk", "tsu_clk";
++ phy-mode = "rgmii-id";
++ cdns,aw2w-max-pipe = /bits/ 8 <8>;
++ cdns,ar2r-max-pipe = /bits/ 8 <8>;
++ cdns,use-aw2b-fill;
++ local-mac-address = [00 00 00 00 00 00];
++ status = "disabled";
++ };
++
++ rp1_csi0: csi@110000 {
++ compatible = "raspberrypi,rp1-cfe";
++ reg = <0xc0 0x40110000 0x0 0x100>, // CSI2 DMA address
++ <0xc0 0x40114000 0x0 0x100>, // PHY/CSI Host address
++ <0xc0 0x40120000 0x0 0x100>, // MIPI CFG address
++ <0xc0 0x40124000 0x0 0x1000>; // PiSP FE address
++
++ // interrupts must match rp1_pisp_fe setup
++ interrupts = <RP1_INT_MIPI0 IRQ_TYPE_LEVEL_HIGH>;
++
++ clocks = <&rp1_clocks RP1_CLK_MIPI0_CFG>;
++ assigned-clocks = <&rp1_clocks RP1_CLK_MIPI0_CFG>;
++ assigned-clock-rates = <25000000>;
++
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ rp1_csi1: csi@128000 {
++ compatible = "raspberrypi,rp1-cfe";
++ reg = <0xc0 0x40128000 0x0 0x100>, // CSI2 DMA address
++ <0xc0 0x4012c000 0x0 0x100>, // PHY/CSI Host address
++ <0xc0 0x40138000 0x0 0x100>, // MIPI CFG address
++ <0xc0 0x4013c000 0x0 0x1000>; // PiSP FE address
++
++ // interrupts must match rp1_pisp_fe setup
++ interrupts = <RP1_INT_MIPI1 IRQ_TYPE_LEVEL_HIGH>;
++
++ clocks = <&rp1_clocks RP1_CLK_MIPI1_CFG>;
++ assigned-clocks = <&rp1_clocks RP1_CLK_MIPI1_CFG>;
++ assigned-clock-rates = <25000000>;
++
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ rp1_mmc0: mmc@180000 {
++ reg = <0xc0 0x40180000 0x0 0x100>;
++ compatible = "raspberrypi,rp1-dwcmshc";
++ interrupts = <RP1_INT_SDIO0 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&rp1_clocks RP1_CLK_SYS &sdhci_core
++ &rp1_clocks RP1_CLK_SDIO_TIMER
++ &rp1_sdio_clk0>;
++ clock-names = "bus", "core", "timeout", "sdio";
++ /* Bank 0 VDDIO is fixed */
++ no-1-8-v;
++ bus-width = <4>;
++ vmmc-supply = <&rp1_vdd_3v3>;
++ broken-cd;
++ status = "disabled";
++ };
++
++ rp1_mmc1: mmc@184000 {
++ reg = <0xc0 0x40184000 0x0 0x100>;
++ compatible = "raspberrypi,rp1-dwcmshc";
++ interrupts = <RP1_INT_SDIO1 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&rp1_clocks RP1_CLK_SYS &sdhci_core
++ &rp1_clocks RP1_CLK_SDIO_TIMER
++ &rp1_sdio_clk1>;
++ clock-names = "bus", "core", "timeout", "sdio";
++ bus-width = <4>;
++ vmmc-supply = <&rp1_vdd_3v3>;
++ /* Nerf SDR speeds */
++ sdhci-caps-mask = <0x3 0x0>;
++ broken-cd;
++ status = "disabled";
++ };
++
++ rp1_dma: dma@188000 {
++ reg = <0xc0 0x40188000 0x0 0x1000>;
++ compatible = "snps,axi-dma-1.01a";
++ interrupts = <RP1_INT_DMA IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&sdhci_core &rp1_clocks RP1_CLK_SYS>;
++ clock-names = "core-clk", "cfgr-clk";
++
++ #dma-cells = <1>;
++ dma-channels = <8>;
++ snps,dma-masters = <1>;
++ snps,dma-targets = <64>;
++ snps,data-width = <4>; // (8 << 4) == 128 bits
++ snps,block-size = <0x40000 0x40000 0x40000 0x40000 0x40000 0x40000 0x40000 0x40000>;
++ snps,priority = <0 1 2 3 4 5 6 7>;
++ snps,axi-max-burst-len = <8>;
++ status = "disabled";
++ };
++
++ rp1_usb0: usb@200000 {
++ reg = <0xc0 0x40200000 0x0 0x100000>;
++ compatible = "snps,dwc3";
++ dr_mode = "host";
++ usb3-lpm-capable;
++ snps,axi-pipe-limit = /bits/ 8 <8>;
++ snps,dis_rxdet_inp3_quirk;
++ snps,parkmode-disable-ss-quirk;
++ snps,parkmode-disable-hs-quirk;
++ snps,parkmode-disable-fsls-quirk;
++ snps,tx-max-burst = /bits/ 8 <8>;
++ snps,tx-thr-num-pkt = /bits/ 8 <2>;
++ interrupts = <RP1_INT_USBHOST0_0 IRQ_TYPE_EDGE_RISING>;
++ status = "disabled";
++ };
++
++ rp1_usb1: usb@300000 {
++ reg = <0xc0 0x40300000 0x0 0x100000>;
++ compatible = "snps,dwc3";
++ dr_mode = "host";
++ usb3-lpm-capable;
++ snps,axi-pipe-limit = /bits/ 8 <8>;
++ snps,dis_rxdet_inp3_quirk;
++ snps,parkmode-disable-ss-quirk;
++ snps,parkmode-disable-hs-quirk;
++ snps,parkmode-disable-fsls-quirk;
++ snps,tx-max-burst = /bits/ 8 <8>;
++ snps,tx-thr-num-pkt = /bits/ 8 <2>;
++ interrupts = <RP1_INT_USBHOST1_0 IRQ_TYPE_EDGE_RISING>;
++ status = "disabled";
++ };
++
++ rp1_dsi0: dsi@110000 {
++ compatible = "raspberrypi,rp1dsi";
++ status = "disabled";
++ reg = <0xc0 0x40118000 0x0 0x1000>, // MIPI0 DSI DMA (ArgonDPI)
++ <0xc0 0x4011c000 0x0 0x1000>, // MIPI0 DSI Host (SNPS)
++ <0xc0 0x40120000 0x0 0x1000>; // MIPI0 CFG
++
++ interrupts = <RP1_INT_MIPI0 IRQ_TYPE_LEVEL_HIGH>;
++
++ clocks = <&rp1_clocks RP1_CLK_MIPI0_CFG>,
++ <&rp1_clocks RP1_CLK_MIPI0_DPI>,
++ <&rp1_clocks RP1_CLK_MIPI0_DSI_BYTECLOCK>,
++ <&clk_xosc>, // hardwired to DSI "refclk"
++ <&rp1_clocks RP1_PLL_SYS>; // alternate parent for divide
++ clock-names = "cfgclk", "dpiclk", "byteclk", "refclk", "pllsys";
++
++ assigned-clocks = <&rp1_clocks RP1_CLK_MIPI0_CFG>;
++ assigned-clock-rates = <25000000>;
++ };
++
++ rp1_dsi1: dsi@128000 {
++ compatible = "raspberrypi,rp1dsi";
++ status = "disabled";
++ reg = <0xc0 0x40130000 0x0 0x1000>, // MIPI1 DSI DMA (ArgonDPI)
++ <0xc0 0x40134000 0x0 0x1000>, // MIPI1 DSI Host (SNPS)
++ <0xc0 0x40138000 0x0 0x1000>; // MIPI1 CFG
++
++ interrupts = <RP1_INT_MIPI1 IRQ_TYPE_LEVEL_HIGH>;
++
++ clocks = <&rp1_clocks RP1_CLK_MIPI1_CFG>,
++ <&rp1_clocks RP1_CLK_MIPI1_DPI>,
++ <&rp1_clocks RP1_CLK_MIPI1_DSI_BYTECLOCK>,
++ <&clk_xosc>, // hardwired to DSI "refclk"
++ <&rp1_clocks RP1_PLL_SYS>; // alternate parent for divide
++ clock-names = "cfgclk", "dpiclk", "byteclk", "refclk", "pllsys";
++
++ assigned-clocks = <&rp1_clocks RP1_CLK_MIPI1_CFG>;
++ assigned-clock-rates = <25000000>;
++ };
++
++ /* VEC and DPI both need to control PLL_VIDEO and cannot work together; */
++ /* config.txt should enable one or other using dtparam=vec or an overlay. */
++ rp1_vec: vec@144000 {
++ compatible = "raspberrypi,rp1vec";
++ status = "disabled";
++ reg = <0xc0 0x40144000 0x0 0x1000>, // VIDEO_OUT_VEC
++ <0xc0 0x40140000 0x0 0x1000>; // VIDEO_OUT_CFG
++
++ interrupts = <RP1_INT_VIDEO_OUT IRQ_TYPE_LEVEL_HIGH>;
++
++ clocks = <&rp1_clocks RP1_CLK_VEC>;
++
++ assigned-clocks = <&rp1_clocks RP1_PLL_VIDEO_CORE>,
++ <&rp1_clocks RP1_PLL_VIDEO_SEC>,
++ <&rp1_clocks RP1_CLK_VEC>;
++ assigned-clock-rates = <1188000000>,
++ <108000000>,
++ <108000000>;
++ assigned-clock-parents = <0>,
++ <&rp1_clocks RP1_PLL_VIDEO_CORE>,
++ <&rp1_clocks RP1_PLL_VIDEO_SEC>;
++ };
++
++ rp1_dpi: dpi@148000 {
++ compatible = "raspberrypi,rp1dpi";
++ status = "disabled";
++ reg = <0xc0 0x40148000 0x0 0x1000>, // VIDEO_OUT DPI
++ <0xc0 0x40140000 0x0 0x1000>; // VIDEO_OUT_CFG
++
++ interrupts = <RP1_INT_VIDEO_OUT IRQ_TYPE_LEVEL_HIGH>;
++
++ clocks = <&rp1_clocks RP1_CLK_DPI>, // DPI pixel clock
++ <&rp1_clocks RP1_PLL_VIDEO>, // PLL primary divider, and
++ <&rp1_clocks RP1_PLL_VIDEO_CORE>; // VCO, which we also control
++ clock-names = "dpiclk", "plldiv", "pllcore";
++
++ assigned-clocks = <&rp1_clocks RP1_CLK_DPI>;
++ assigned-clock-parents = <&rp1_clocks RP1_PLL_VIDEO>;
++ };
++ };
++};
++
++&clocks {
++ clk_xosc: clk_xosc {
++ compatible = "fixed-clock";
++ #clock-cells = <0>;
++ clock-output-names = "xosc";
++ clock-frequency = <50000000>;
++ };
++ macb_pclk: macb_pclk {
++ compatible = "fixed-clock";
++ #clock-cells = <0>;
++ clock-output-names = "pclk";
++ clock-frequency = <200000000>;
++ };
++ macb_hclk: macb_hclk {
++ compatible = "fixed-clock";
++ #clock-cells = <0>;
++ clock-output-names = "hclk";
++ clock-frequency = <200000000>;
++ };
++ sdio_src: sdio_src {
++ // 400 MHz on FPGA. PLL sys VCO on asic
++ compatible = "fixed-clock";
++ #clock-cells = <0>;
++ clock-output-names = "src";
++ clock-frequency = <1000000000>;
++ };
++ sdhci_core: sdhci_core {
++ compatible = "fixed-clock";
++ #clock-cells = <0>;
++ clock-output-names = "core";
++ clock-frequency = <50000000>;
++ };
++ /* GPIO derived clock sources. Each GPIO with a GPCLK function
++ * can drive its output from the respective GPCLK
++ * generator, and provide a clock source to other internal
++ * dividers. Add dummy sources here so that they can be overridden
++ * with overlays.
++ */
++ clksrc_gp0: clksrc_gp0 {
++ status = "disabled";
++ compatible = "fixed-factor-clock";
++ #clock-cells = <0>;
++ clock-div = <1>;
++ clock-mult = <1>;
++ clocks = <&rp1_clocks RP1_CLK_GP0>;
++ clock-output-names = "clksrc_gp0";
++ };
++ clksrc_gp1: clksrc_gp1 {
++ status = "disabled";
++ compatible = "fixed-factor-clock";
++ #clock-cells = <0>;
++ clock-div = <1>;
++ clock-mult = <1>;
++ clocks = <&rp1_clocks RP1_CLK_GP1>;
++ clock-output-names = "clksrc_gp1";
++ };
++ clksrc_gp2: clksrc_gp2 {
++ status = "disabled";
++ compatible = "fixed-factor-clock";
++ clock-div = <1>;
++ clock-mult = <1>;
++ #clock-cells = <0>;
++ clocks = <&rp1_clocks RP1_CLK_GP2>;
++ clock-output-names = "clksrc_gp2";
++ };
++ clksrc_gp3: clksrc_gp3 {
++ status = "disabled";
++ compatible = "fixed-factor-clock";
++ clock-div = <1>;
++ clock-mult = <1>;
++ #clock-cells = <0>;
++ clocks = <&rp1_clocks RP1_CLK_GP3>;
++ clock-output-names = "clksrc_gp3";
++ };
++ clksrc_gp4: clksrc_gp4 {
++ status = "disabled";
++ compatible = "fixed-factor-clock";
++ #clock-cells = <0>;
++ clock-div = <1>;
++ clock-mult = <1>;
++ clocks = <&rp1_clocks RP1_CLK_GP4>;
++ clock-output-names = "clksrc_gp4";
++ };
++ clksrc_gp5: clksrc_gp5 {
++ status = "disabled";
++ compatible = "fixed-factor-clock";
++ #clock-cells = <0>;
++ clock-div = <1>;
++ clock-mult = <1>;
++ clocks = <&rp1_clocks RP1_CLK_GP5>;
++ clock-output-names = "clksrc_gp5";
++ };
++};
++
++/ {
++ rp1_vdd_3v3: rp1_vdd_3v3 {
++ compatible = "regulator-fixed";
++ regulator-name = "vdd-3v3";
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ regulator-always-on;
++ };
++};
--- /dev/null
+From 4de4f56af7d803fa7dd9ffe42d4719b428d73e6c Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Wed, 17 Jul 2024 17:31:58 +0100
+Subject: [PATCH 1181/1215] arm64: dts: Add cm5l files
+
+CM5 Lite DTBs require minor changes compared to the "heavy" variants.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ arch/arm64/boot/dts/broadcom/Makefile | 2 ++
+ .../dts/broadcom/bcm2712-rpi-cm5l-cm4io.dts | 20 ++++++++++++++++
+ .../dts/broadcom/bcm2712-rpi-cm5l-cm5io.dts | 10 ++++++++
+ .../boot/dts/broadcom/bcm2712-rpi-cm5l.dtsi | 24 +++++++++++++++++++
+ 4 files changed, 56 insertions(+)
+ create mode 100644 arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l-cm4io.dts
+ create mode 100644 arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l-cm5io.dts
+ create mode 100644 arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l.dtsi
+
+--- a/arch/arm64/boot/dts/broadcom/Makefile
++++ b/arch/arm64/boot/dts/broadcom/Makefile
+@@ -24,6 +24,8 @@ dtb-$(CONFIG_ARCH_BCM2835) += bcm2712-rp
+ dtb-$(CONFIG_ARCH_BCM2835) += bcm2712d0-rpi-5-b.dtb
+ dtb-$(CONFIG_ARCH_BCM2835) += bcm2712-rpi-cm5-cm5io.dtb
+ dtb-$(CONFIG_ARCH_BCM2835) += bcm2712-rpi-cm5-cm4io.dtb
++dtb-$(CONFIG_ARCH_BCM2835) += bcm2712-rpi-cm5l-cm5io.dtb
++dtb-$(CONFIG_ARCH_BCM2835) += bcm2712-rpi-cm5l-cm4io.dtb
+
+ subdir-y += bcmbca
+ subdir-y += northstar2
+--- /dev/null
++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l-cm4io.dts
+@@ -0,0 +1,20 @@
++// SPDX-License-Identifier: GPL-2.0
++/dts-v1/;
++
++#include "bcm2712-rpi-cm5l.dtsi"
++
++// The RP1 USB3 interfaces are not usable on CM4IO
++
++&rp1_usb0 {
++ status = "disabled";
++};
++
++&rp1_usb1 {
++ status = "disabled";
++};
++
++/ {
++ __overrides__ {
++ i2c_csi_dsi = <&i2c_csi_dsi>, "status";
++ };
++};
+--- /dev/null
++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l-cm5io.dts
+@@ -0,0 +1,10 @@
++// SPDX-License-Identifier: GPL-2.0
++/dts-v1/;
++
++#include "bcm2712-rpi-cm5l.dtsi"
++
++/ {
++ __overrides__ {
++ i2c_csi_dsi = <&i2c_csi_dsi>, "status";
++ };
++};
+--- /dev/null
++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l.dtsi
+@@ -0,0 +1,24 @@
++// SPDX-License-Identifier: GPL-2.0
++/dts-v1/;
++
++#include "bcm2712-rpi-cm5.dtsi"
++
++/ {
++ __overrides__ {
++ i2c_csi_dsi = <&i2c_csi_dsi>, "status";
++ };
++};
++
++&sd_io_1v8_reg {
++ compatible = "regulator-gpio";
++ regulator-max-microvolt = <3300000>;
++ regulator-settling-time-us = <5000>;
++ gpios = <&gio_aon 3 GPIO_ACTIVE_HIGH>;
++ states = <1800000 0x1
++ 3300000 0x0>;
++};
++
++&sdio1 {
++ /delete-property/ mmc-hs400-1_8v;
++ /delete-property/ mmc-hs400-enhanced-strobe;
++};
--- /dev/null
+From e1c56acf3355cd539447511fdc1b886e5eb5cca3 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Thu, 2 May 2024 16:57:31 +0100
+Subject: [PATCH 1182/1215] dts: bcm2712: Dedup the aliases and overrides
+
+Move the aliases and overrrides shared by Pi 5 and CM5 into
+bcm2712-rpi.dtsi.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ .../boot/dts/broadcom/bcm2712-rpi-5-b.dts | 115 -----------------
+ .../boot/dts/broadcom/bcm2712-rpi-cm5.dtsi | 114 -----------------
+ arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi | 117 +++++++++++++++++-
+ 3 files changed, 113 insertions(+), 233 deletions(-)
+
+--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts
++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts
+@@ -746,122 +746,7 @@ spi10_cs_pins: &spi10_cs_gpio1 {};
+ };
+
+ / {
+- aliases: aliases {
+- blconfig = &blconfig;
+- blpubkey = &blpubkey;
+- bluetooth = &bluetooth;
+- console = &uart10;
+- ethernet0 = &rp1_eth;
+- wifi0 = &wifi;
+- fb = &fb;
+- mailbox = &mailbox;
+- mmc0 = &sdio1;
+- uart0 = &uart0;
+- uart1 = &uart1;
+- uart2 = &uart2;
+- uart3 = &uart3;
+- uart4 = &uart4;
+- uart10 = &uart10;
+- serial0 = &uart0;
+- serial1 = &uart1;
+- serial2 = &uart2;
+- serial3 = &uart3;
+- serial4 = &uart4;
+- serial10 = &uart10;
+- i2c = &i2c_arm;
+- i2c0 = &i2c0;
+- i2c1 = &i2c1;
+- i2c2 = &i2c2;
+- i2c3 = &i2c3;
+- i2c4 = &i2c4;
+- i2c5 = &i2c5;
+- i2c6 = &i2c6;
+- i2c10 = &i2c_rp1boot;
+- // Bit-bashed i2c_gpios start at 10
+- spi0 = &spi0;
+- spi1 = &spi1;
+- spi2 = &spi2;
+- spi3 = &spi3;
+- spi4 = &spi4;
+- spi5 = &spi5;
+- spi10 = &spi10;
+- gpio0 = &gpio;
+- gpio1 = &gio;
+- gpio2 = &gio_aon;
+- gpio3 = &pinctrl;
+- gpio4 = &pinctrl_aon;
+- usb0 = &rp1_usb0;
+- usb1 = &rp1_usb1;
+- drm-dsi1 = &dsi0;
+- drm-dsi2 = &dsi1;
+- };
+-
+ __overrides__ {
+- bdaddr = <&bluetooth>, "local-bd-address[";
+- button_debounce = <&pwr_key>, "debounce-interval:0";
+- cooling_fan = <&fan>, "status", <&rp1_pwm1>, "status";
+- uart0_console = <&uart0>,"status", <&aliases>, "console=",&uart0;
+- i2c0 = <&i2c0>, "status";
+- i2c1 = <&i2c1>, "status";
+- i2c = <&i2c1>, "status";
+- i2c_arm = <&i2c_arm>, "status";
+- i2c_vc = <&i2c_vc>, "status";
+- i2c_csi_dsi = <&i2c_csi_dsi>, "status";
+- i2c_csi_dsi0 = <&i2c_csi_dsi0>, "status";
+- i2c_csi_dsi1 = <&i2c_csi_dsi1>, "status";
+- i2c0_baudrate = <&i2c0>, "clock-frequency:0";
+- i2c1_baudrate = <&i2c1>, "clock-frequency:0";
+- i2c_baudrate = <&i2c_arm>, "clock-frequency:0";
+- i2c_arm_baudrate = <&i2c_arm>, "clock-frequency:0";
+- i2c_vc_baudrate = <&i2c_vc>, "clock-frequency:0";
+- krnbt = <&bluetooth>, "status";
+- nvme = <&pciex1>, "status";
+- pciex1 = <&pciex1>, "status";
+- pciex1_gen = <&pciex1> , "max-link-speed:0";
+- pciex1_no_l0s = <&pciex1>, "aspm-no-l0s?";
+- pciex1_tperst_clk_ms = <&pciex1>, "brcm,tperst-clk-ms:0";
+- pcie_tperst_clk_ms = <&pciex1>, "brcm,tperst-clk-ms:0";
+- random = <&random>, "status";
+- rtc = <&rpi_rtc>, "status";
+- rtc_bbat_vchg = <&rpi_rtc>, "trickle-charge-microvolt:0";
+ sd_cqe = <&sdio1>, "supports-cqe?";
+- spi = <&spi0>, "status";
+- suspend = <&pwr_key>, "linux,code:0=205";
+- uart0 = <&uart0>, "status";
+- wifiaddr = <&wifi>, "local-mac-address[";
+-
+- act_led_gpio = <&led_act>,"gpios:4",<&led_act>,"gpios:0=",<&gpio>;
+- act_led_activelow = <&led_act>,"gpios:8";
+- act_led_trigger = <&led_act>, "linux,default-trigger";
+- pwr_led_gpio = <&led_pwr>,"gpios:4";
+- pwr_led_activelow = <&led_pwr>, "gpios:8";
+- pwr_led_trigger = <&led_pwr>, "linux,default-trigger";
+- eth_led0 = <&phy1>,"led-modes:0";
+- eth_led1 = <&phy1>,"led-modes:4";
+- drm_fb0_rp1_dsi0 = <&aliases>, "drm-fb0=",&dsi0;
+- drm_fb0_rp1_dsi1 = <&aliases>, "drm-fb0=",&dsi1;
+- drm_fb0_rp1_dpi = <&aliases>, "drm-fb0=",&dpi;
+- drm_fb0_vc4 = <&aliases>, "drm-fb0=",&vc4;
+- drm_fb1_rp1_dsi0 = <&aliases>, "drm-fb1=",&dsi0;
+- drm_fb1_rp1_dsi1 = <&aliases>, "drm-fb1=",&dsi1;
+- drm_fb1_rp1_dpi = <&aliases>, "drm-fb1=",&dpi;
+- drm_fb1_vc4 = <&aliases>, "drm-fb1=",&vc4;
+- drm_fb2_rp1_dsi0 = <&aliases>, "drm-fb2=",&dsi0;
+- drm_fb2_rp1_dsi1 = <&aliases>, "drm-fb2=",&dsi1;
+- drm_fb2_rp1_dpi = <&aliases>, "drm-fb2=",&dpi;
+- drm_fb2_vc4 = <&aliases>, "drm-fb2=",&vc4;
+-
+- fan_temp0 = <&cpu_tepid>,"temperature:0";
+- fan_temp1 = <&cpu_warm>,"temperature:0";
+- fan_temp2 = <&cpu_hot>,"temperature:0";
+- fan_temp3 = <&cpu_vhot>,"temperature:0";
+- fan_temp0_hyst = <&cpu_tepid>,"hysteresis:0";
+- fan_temp1_hyst = <&cpu_warm>,"hysteresis:0";
+- fan_temp2_hyst = <&cpu_hot>,"hysteresis:0";
+- fan_temp3_hyst = <&cpu_vhot>,"hysteresis:0";
+- fan_temp0_speed = <&fan>, "cooling-levels:4";
+- fan_temp1_speed = <&fan>, "cooling-levels:8";
+- fan_temp2_speed = <&fan>, "cooling-levels:12";
+- fan_temp3_speed = <&fan>, "cooling-levels:16";
+ };
+ };
+--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi
++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi
+@@ -753,108 +753,7 @@ spi10_cs_pins: &spi10_cs_gpio1 {};
+ };
+
+ / {
+- aliases: aliases {
+- blconfig = &blconfig;
+- blpubkey = &blpubkey;
+- bluetooth = &bluetooth;
+- console = &uart10;
+- ethernet0 = &rp1_eth;
+- wifi0 = &wifi;
+- fb = &fb;
+- mailbox = &mailbox;
+- mmc0 = &sdio1;
+- uart0 = &uart0;
+- uart1 = &uart1;
+- uart2 = &uart2;
+- uart3 = &uart3;
+- uart4 = &uart4;
+- uart10 = &uart10;
+- serial0 = &uart0;
+- serial1 = &uart1;
+- serial2 = &uart2;
+- serial3 = &uart3;
+- serial4 = &uart4;
+- serial10 = &uart10;
+- i2c = &i2c_arm;
+- i2c0 = &i2c0;
+- i2c1 = &i2c1;
+- i2c2 = &i2c2;
+- i2c3 = &i2c3;
+- i2c4 = &i2c4;
+- i2c5 = &i2c5;
+- i2c6 = &i2c6;
+- i2c10 = &i2c_rp1boot;
+- // Bit-bashed i2c_gpios start at 10
+- spi0 = &spi0;
+- spi1 = &spi1;
+- spi2 = &spi2;
+- spi3 = &spi3;
+- spi4 = &spi4;
+- spi5 = &spi5;
+- spi10 = &spi10;
+- gpio0 = &gpio;
+- gpio1 = &gio;
+- gpio2 = &gio_aon;
+- gpio3 = &pinctrl;
+- gpio4 = &pinctrl_aon;
+- usb0 = &rp1_usb0;
+- usb1 = &rp1_usb1;
+- drm-dsi1 = &dsi0;
+- drm-dsi2 = &dsi1;
+- };
+-
+ __overrides__ {
+- bdaddr = <&bluetooth>, "local-bd-address[";
+- button_debounce = <&pwr_key>, "debounce-interval:0";
+- cooling_fan = <&fan>, "status", <&rp1_pwm1>, "status";
+- uart0_console = <&uart0>,"status", <&aliases>, "console=",&uart0;
+- i2c0 = <&i2c0>, "status";
+- i2c1 = <&i2c1>, "status";
+- i2c = <&i2c1>, "status";
+- i2c_arm = <&i2c_arm>, "status";
+- i2c_vc = <&i2c_vc>, "status";
+- i2c_csi_dsi = <&i2c_csi_dsi>, "status";
+- i2c_csi_dsi0 = <&i2c_csi_dsi0>, "status";
+- i2c_csi_dsi1 = <&i2c_csi_dsi1>, "status";
+- i2c0_baudrate = <&i2c0>, "clock-frequency:0";
+- i2c1_baudrate = <&i2c1>, "clock-frequency:0";
+- i2c_baudrate = <&i2c_arm>, "clock-frequency:0";
+- i2c_arm_baudrate = <&i2c_arm>, "clock-frequency:0";
+- i2c_vc_baudrate = <&i2c_vc>, "clock-frequency:0";
+- krnbt = <&bluetooth>, "status";
+- nvme = <&pciex1>, "status";
+- pciex1 = <&pciex1>, "status";
+- pciex1_gen = <&pciex1> , "max-link-speed:0";
+- pciex1_no_l0s = <&pciex1>, "aspm-no-l0s?";
+- pciex1_tperst_clk_ms = <&pciex1>, "brcm,tperst-clk-ms:0";
+- pcie_tperst_clk_ms = <&pciex1>, "brcm,tperst-clk-ms:0";
+- random = <&random>, "status";
+- rtc = <&rpi_rtc>, "status";
+- rtc_bbat_vchg = <&rpi_rtc>, "trickle-charge-microvolt:0";
+- spi = <&spi0>, "status";
+- suspend = <&pwr_key>, "linux,code:0=205";
+- uart0 = <&uart0>, "status";
+- wifiaddr = <&wifi>, "local-mac-address[";
+-
+- act_led_activelow = <&led_act>, "active-low?";
+- act_led_trigger = <&led_act>, "linux,default-trigger";
+- pwr_led_activelow = <&led_pwr>, "gpios:8";
+- pwr_led_trigger = <&led_pwr>, "linux,default-trigger";
+- eth_led0 = <&phy1>,"led-modes:0";
+- eth_led1 = <&phy1>,"led-modes:4";
+- drm_fb0_rp1_dsi0 = <&aliases>, "drm-fb0=",&dsi0;
+- drm_fb0_rp1_dsi1 = <&aliases>, "drm-fb0=",&dsi1;
+- drm_fb0_rp1_dpi = <&aliases>, "drm-fb0=",&dpi;
+- drm_fb0_vc4 = <&aliases>, "drm-fb0=",&vc4;
+- drm_fb1_rp1_dsi0 = <&aliases>, "drm-fb1=",&dsi0;
+- drm_fb1_rp1_dsi1 = <&aliases>, "drm-fb1=",&dsi1;
+- drm_fb1_rp1_dpi = <&aliases>, "drm-fb1=",&dpi;
+- drm_fb1_vc4 = <&aliases>, "drm-fb1=",&vc4;
+- drm_fb2_rp1_dsi0 = <&aliases>, "drm-fb2=",&dsi0;
+- drm_fb2_rp1_dsi1 = <&aliases>, "drm-fb2=",&dsi1;
+- drm_fb2_rp1_dpi = <&aliases>, "drm-fb2=",&dpi;
+- drm_fb2_vc4 = <&aliases>, "drm-fb2=",&vc4;
+-
+ ant1 = <&ant1>,"output-high?=on",
+ <&ant1>, "output-low?=off",
+ <&ant2>, "output-high?=off",
+@@ -867,18 +766,5 @@ spi10_cs_pins: &spi10_cs_gpio1 {};
+ <&ant1>, "output-low?=on",
+ <&ant2>, "output-high?=off",
+ <&ant2>, "output-low?=on";
+-
+- fan_temp0 = <&cpu_tepid>,"temperature:0";
+- fan_temp1 = <&cpu_warm>,"temperature:0";
+- fan_temp2 = <&cpu_hot>,"temperature:0";
+- fan_temp3 = <&cpu_vhot>,"temperature:0";
+- fan_temp0_hyst = <&cpu_tepid>,"hysteresis:0";
+- fan_temp1_hyst = <&cpu_warm>,"hysteresis:0";
+- fan_temp2_hyst = <&cpu_hot>,"hysteresis:0";
+- fan_temp3_hyst = <&cpu_vhot>,"hysteresis:0";
+- fan_temp0_speed = <&fan>, "cooling-levels:4";
+- fan_temp1_speed = <&fan>, "cooling-levels:8";
+- fan_temp2_speed = <&fan>, "cooling-levels:12";
+- fan_temp3_speed = <&fan>, "cooling-levels:16";
+ };
+ };
+--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi
++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi
+@@ -98,14 +98,124 @@
+ };
+
+ / {
++ aliases: aliases {
++ blconfig = &blconfig;
++ blpubkey = &blpubkey;
++ bluetooth = &bluetooth;
++ console = &uart10;
++ drm-dsi1 = &dsi0;
++ drm-dsi2 = &dsi1;
++ ethernet0 = &rp1_eth;
++ fb = &fb;
++ gpio0 = &gpio;
++ gpio1 = &gio;
++ gpio2 = &gio_aon;
++ gpio3 = &pinctrl;
++ gpio4 = &pinctrl_aon;
++ i2c = &i2c_arm;
++ i2c0 = &i2c0;
++ i2c1 = &i2c1;
++ i2c10 = &i2c_rp1boot;
++ i2c2 = &i2c2;
++ i2c3 = &i2c3;
++ i2c4 = &i2c4;
++ i2c5 = &i2c5;
++ i2c6 = &i2c6;
++ mailbox = &mailbox;
++ mmc0 = &sdio1;
++ serial0 = &uart0;
++ serial1 = &uart1;
++ serial10 = &uart10;
++ serial2 = &uart2;
++ serial3 = &uart3;
++ serial4 = &uart4;
++ spi0 = &spi0;
++ spi1 = &spi1;
++ spi10 = &spi10;
++ spi2 = &spi2;
++ spi3 = &spi3;
++ spi4 = &spi4;
++ spi5 = &spi5;
++ uart0 = &uart0;
++ uart1 = &uart1;
++ uart10 = &uart10;
++ uart2 = &uart2;
++ uart3 = &uart3;
++ uart4 = &uart4;
++ usb0 = &rp1_usb0;
++ usb1 = &rp1_usb1;
++ wifi0 = &wifi;
++ };
++
+ __overrides__ {
+- arm_freq;
++ act_led_gpio = <&led_act>,"gpios:4",<&led_act>,"gpios:0=",<&gpio>;
++ act_led_activelow = <&led_act>, "gpios:8";
++ act_led_trigger = <&led_act>, "linux,default-trigger";
+ axiperf = <&axiperf>,"status";
+-
++ bdaddr = <&bluetooth>, "local-bd-address[";
++ button_debounce = <&pwr_key>, "debounce-interval:0";
++ cooling_fan = <&fan>, "status", <&rp1_pwm1>, "status";
++ drm_fb0_rp1_dpi = <&aliases>, "drm-fb0=",&dpi;
++ drm_fb0_rp1_dsi0 = <&aliases>, "drm-fb0=",&dsi0;
++ drm_fb0_rp1_dsi1 = <&aliases>, "drm-fb0=",&dsi1;
++ drm_fb0_vc4 = <&aliases>, "drm-fb0=",&vc4;
++ drm_fb1_rp1_dpi = <&aliases>, "drm-fb1=",&dpi;
++ drm_fb1_rp1_dsi0 = <&aliases>, "drm-fb1=",&dsi0;
++ drm_fb1_rp1_dsi1 = <&aliases>, "drm-fb1=",&dsi1;
++ drm_fb1_vc4 = <&aliases>, "drm-fb1=",&vc4;
++ drm_fb2_rp1_dpi = <&aliases>, "drm-fb2=",&dpi;
++ drm_fb2_rp1_dsi0 = <&aliases>, "drm-fb2=",&dsi0;
++ drm_fb2_rp1_dsi1 = <&aliases>, "drm-fb2=",&dsi1;
++ drm_fb2_vc4 = <&aliases>, "drm-fb2=",&vc4;
++ eth_led0 = <&phy1>,"led-modes:0";
++ eth_led1 = <&phy1>,"led-modes:4";
++ fan_temp0 = <&cpu_tepid>,"temperature:0";
++ fan_temp0_hyst = <&cpu_tepid>,"hysteresis:0";
++ fan_temp0_speed = <&fan>, "cooling-levels:4";
++ fan_temp1 = <&cpu_warm>,"temperature:0";
++ fan_temp1_hyst = <&cpu_warm>,"hysteresis:0";
++ fan_temp1_speed = <&fan>, "cooling-levels:8";
++ fan_temp2 = <&cpu_hot>,"temperature:0";
++ fan_temp2_hyst = <&cpu_hot>,"hysteresis:0";
++ fan_temp2_speed = <&fan>, "cooling-levels:12";
++ fan_temp3 = <&cpu_vhot>,"temperature:0";
++ fan_temp3_hyst = <&cpu_vhot>,"hysteresis:0";
++ fan_temp3_speed = <&fan>, "cooling-levels:16";
++ i2c = <&i2c1>, "status";
++ i2c_arm = <&i2c_arm>, "status";
++ i2c_arm_baudrate = <&i2c_arm>, "clock-frequency:0";
++ i2c_baudrate = <&i2c_arm>, "clock-frequency:0";
++ i2c_csi_dsi = <&i2c_csi_dsi>, "status";
++ i2c_csi_dsi0 = <&i2c_csi_dsi0>, "status";
++ i2c_csi_dsi1 = <&i2c_csi_dsi1>, "status";
++ i2c_vc = <&i2c_vc>, "status";
++ i2c_vc_baudrate = <&i2c_vc>, "clock-frequency:0";
++ i2c0 = <&i2c0>, "status";
++ i2c0_baudrate = <&i2c0>, "clock-frequency:0";
++ i2c1 = <&i2c1>, "status";
++ i2c1_baudrate = <&i2c1>, "clock-frequency:0";
++ krnbt = <&bluetooth>, "status";
++ nvme = <&pciex1>, "status";
+ nvmem_cust_rw = <&nvmem_cust>,"rw?";
+- nvmem_priv_rw = <&nvmem_priv>,"rw?";
+ nvmem_mac_rw = <&nvmem_mac>,"rw?";
++ nvmem_priv_rw = <&nvmem_priv>,"rw?";
++ pcie_tperst_clk_ms = <&pciex1>, "brcm,tperst-clk-ms:0";
++ pciex1 = <&pciex1>, "status";
++ pciex1_gen = <&pciex1> , "max-link-speed:0";
++ pciex1_no_l0s = <&pciex1>, "aspm-no-l0s?";
++ pciex1_tperst_clk_ms = <&pciex1>, "brcm,tperst-clk-ms:0";
++ pwr_led_gpio = <&led_pwr>, "gpios:4";
++ pwr_led_activelow = <&led_pwr>, "gpios:8";
++ pwr_led_trigger = <&led_pwr>, "linux,default-trigger";
++ random = <&random>, "status";
++ rtc = <&rpi_rtc>, "status";
++ rtc_bbat_vchg = <&rpi_rtc>, "trickle-charge-microvolt:0";
++ spi = <&spi0>, "status";
+ strict_gpiod = <&chosen>, "bootargs=pinctrl_rp1.persist_gpio_outputs=n";
++ suspend = <&pwr_key>, "linux,code:0=205";
++ uart0 = <&uart0>, "status";
++ uart0_console = <&uart0>,"status", <&aliases>, "console=",&uart0;
++ wifiaddr = <&wifi>, "local-mac-address[";
+
+ cam0_reg = <&cam0_reg>,"status";
+ cam0_reg_gpio = <&cam0_reg>,"gpio:4",
+@@ -113,7 +223,6 @@
+ cam1_reg = <&cam1_reg>,"status";
+ cam1_reg_gpio = <&cam1_reg>,"gpio:4",
+ <&cam1_reg>,"gpio:0=", <&gpio>;
+-
+ };
+ };
+
--- /dev/null
+From ad110e5ff36de6096e1b9d7e0fe125326f45ed7d Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Fri, 19 Jul 2024 13:18:47 +0100
+Subject: [PATCH 1183/1215] arm64: dts: Give cm5l its own model name
+
+The bootloader patches the DT with the correct model string, but it
+is better not to rely on that by setting it from the start.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l.dtsi | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l.dtsi
++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l.dtsi
+@@ -4,6 +4,8 @@
+ #include "bcm2712-rpi-cm5.dtsi"
+
+ / {
++ model = "Raspberry Pi Compute Module 5 Lite";
++
+ __overrides__ {
+ i2c_csi_dsi = <&i2c_csi_dsi>, "status";
+ };
--- /dev/null
+From d24229dcef58e0162780ceffa02eb5f6a01b9a4d Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <jonathan@raspberrypi.com>
+Date: Tue, 16 Jul 2024 16:47:08 +0100
+Subject: [PATCH 1185/1215] pinctrl: rp1: jump through hoops to avoid PCIe
+ latency issues
+
+Automatic link power saving plus the ability of a root complex to buffer
+pending posted write transfers (and consider them complete before being
+transmitted on the wire) causes compression of updates to GPIO state.
+
+The large bandwidth of a Gen 2 x4 link means the writes toggle state
+inside RP1 as fast as it can go (~20MHz), which is bad for applications
+wanting bitbash with at least a few microseconds of delay between
+updates.
+
+By tailoring IO access patterns to a special Root Complex register,
+writes to GPIOs can be stalled until the link wakes - meaning all writes
+end up with a reasonably consistent minimum pacing (~200ns).
+
+Additionally, write barriers have no effect other than to arbitrarily
+delay some writes by a small, variable amount - so remove the vast
+majority of these in areas that could be hot-paths.
+
+Although the IO memory is mapped with Device strongly-ordered semantics,
+this doesn't prevent the splitter inside BCM2712 from letting an MMIO
+read request to a GPIO register get ahead of the pacing writes to the
+Root Complex register. So each pin state read must flush writes out to
+the Outer-Shareable domain.
+
+Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
+---
+ drivers/pinctrl/pinctrl-rp1.c | 120 +++++++++++++++++++++++++++++-----
+ 1 file changed, 105 insertions(+), 15 deletions(-)
+
+--- a/drivers/pinctrl/pinctrl-rp1.c
++++ b/drivers/pinctrl/pinctrl-rp1.c
+@@ -197,6 +197,7 @@ struct rp1_pin_info {
+ void __iomem *inte;
+ void __iomem *ints;
+ void __iomem *pad;
++ void __iomem *dummy;
+ };
+
+ enum funcs {
+@@ -276,6 +277,7 @@ struct rp1_pinctrl {
+ void __iomem *gpio_base;
+ void __iomem *rio_base;
+ void __iomem *pads_base;
++ void __iomem *dummy_base;
+ int irq[RP1_NUM_BANKS];
+ struct rp1_pin_info pins[RP1_NUM_GPIOS];
+
+@@ -577,6 +579,42 @@ static bool persist_gpio_outputs = true;
+ module_param(persist_gpio_outputs, bool, 0644);
+ MODULE_PARM_DESC(persist_gpio_outputs, "Enable GPIO_OUT persistence when pin is freed");
+
++static bool pace_pin_updates = true;
++module_param(pace_pin_updates, bool, 0644);
++MODULE_PARM_DESC(pace_pin_updates, "Update pin states with guaranteed monotonicity if PCIe ASPM is enabled");
++
++static inline void rp1_pin_writel(u32 val, void __iomem *dummy, void __iomem *reg)
++{
++ unsigned long flags;
++
++ local_irq_save(flags);
++ /*
++ * Issuing 6 pipelined writes to the RC's Slot Control register will stall the
++ * peripheral bus inside 2712 if the link is in L1. This acts as a lightweight
++ * "fence" operation preventing back-to-back writes arriving at RP1 on a wake.
++ */
++ if (dummy) {
++ writel_relaxed(0, dummy);
++ writel_relaxed(0, dummy);
++ writel_relaxed(0, dummy);
++ writel_relaxed(0, dummy);
++ writel_relaxed(0, dummy);
++ writel_relaxed(0, dummy);
++ }
++ writel_relaxed(val, reg);
++ local_irq_restore(flags);
++}
++
++static inline u32 rp1_pin_readl(const void __iomem *ioaddr)
++{
++ /*
++ * Prior posted writes may not yet have been emitted by the CPU - do a store-flush
++ * before reading GPIO state, as this will serialise writes versus the next issued read.
++ */
++ __dma_wmb();
++ return readl(ioaddr);
++}
++
+ static int rp1_pinconf_set(struct pinctrl_dev *pctldev,
+ unsigned int offset, unsigned long *configs,
+ unsigned int num_configs);
+@@ -603,12 +641,12 @@ static struct rp1_pin_info *rp1_get_pin_
+
+ static void rp1_pad_update(struct rp1_pin_info *pin, u32 clr, u32 set)
+ {
+- u32 padctrl = readl(pin->pad);
++ u32 padctrl = rp1_pin_readl(pin->pad);
+
+ padctrl &= ~clr;
+ padctrl |= set;
+
+- writel(padctrl, pin->pad);
++ rp1_pin_writel(padctrl, pin->dummy, pin->pad);
+ }
+
+ static void rp1_input_enable(struct rp1_pin_info *pin, int value)
+@@ -625,7 +663,7 @@ static void rp1_output_enable(struct rp1
+
+ static u32 rp1_get_fsel(struct rp1_pin_info *pin)
+ {
+- u32 ctrl = readl(pin->gpio + RP1_GPIO_CTRL);
++ u32 ctrl = rp1_pin_readl(pin->gpio + RP1_GPIO_CTRL);
+ u32 oeover = FLD_GET(ctrl, RP1_GPIO_CTRL_OEOVER);
+ u32 fsel = FLD_GET(ctrl, RP1_GPIO_CTRL_FUNCSEL);
+
+@@ -637,7 +675,7 @@ static u32 rp1_get_fsel(struct rp1_pin_i
+
+ static void rp1_set_fsel(struct rp1_pin_info *pin, u32 fsel)
+ {
+- u32 ctrl = readl(pin->gpio + RP1_GPIO_CTRL);
++ u32 ctrl = rp1_pin_readl(pin->gpio + RP1_GPIO_CTRL);
+
+ if (fsel >= RP1_FSEL_COUNT)
+ fsel = RP1_FSEL_NONE_HW;
+@@ -652,12 +690,12 @@ static void rp1_set_fsel(struct rp1_pin_
+ FLD_SET(ctrl, RP1_GPIO_CTRL_OEOVER, RP1_OEOVER_PERI);
+ }
+ FLD_SET(ctrl, RP1_GPIO_CTRL_FUNCSEL, fsel);
+- writel(ctrl, pin->gpio + RP1_GPIO_CTRL);
++ rp1_pin_writel(ctrl, pin->dummy, pin->gpio + RP1_GPIO_CTRL);
+ }
+
+ static int rp1_get_dir(struct rp1_pin_info *pin)
+ {
+- return !(readl(pin->rio + RP1_RIO_OE) & (1 << pin->offset)) ?
++ return !(rp1_pin_readl(pin->rio + RP1_RIO_OE) & (1 << pin->offset)) ?
+ RP1_DIR_INPUT : RP1_DIR_OUTPUT;
+ }
+
+@@ -665,19 +703,19 @@ static void rp1_set_dir(struct rp1_pin_i
+ {
+ int offset = is_input ? RP1_CLR_OFFSET : RP1_SET_OFFSET;
+
+- writel(1 << pin->offset, pin->rio + RP1_RIO_OE + offset);
++ rp1_pin_writel(1 << pin->offset, pin->dummy, pin->rio + RP1_RIO_OE + offset);
+ }
+
+ static int rp1_get_value(struct rp1_pin_info *pin)
+ {
+- return !!(readl(pin->rio + RP1_RIO_IN) & (1 << pin->offset));
++ return !!(rp1_pin_readl(pin->rio + RP1_RIO_IN) & (1 << pin->offset));
+ }
+
+ static void rp1_set_value(struct rp1_pin_info *pin, int value)
+ {
+ /* Assume the pin is already an output */
+- writel(1 << pin->offset,
+- pin->rio + RP1_RIO_OUT + (value ? RP1_SET_OFFSET : RP1_CLR_OFFSET));
++ rp1_pin_writel(1 << pin->offset, pin->dummy,
++ pin->rio + RP1_RIO_OUT + (value ? RP1_SET_OFFSET : RP1_CLR_OFFSET));
+ }
+
+ static int rp1_gpio_get(struct gpio_chip *chip, unsigned offset)
+@@ -1298,7 +1336,7 @@ static const struct pinmux_ops rp1_pmx_o
+
+ static void rp1_pull_config_set(struct rp1_pin_info *pin, unsigned int arg)
+ {
+- u32 padctrl = readl(pin->pad);
++ u32 padctrl = rp1_pin_readl(pin->pad);
+
+ FLD_SET(padctrl, RP1_PAD_PULL, arg & 0x3);
+
+@@ -1398,7 +1436,7 @@ static int rp1_pinconf_get(struct pinctr
+ if (!pin)
+ return -EINVAL;
+
+- padctrl = readl(pin->pad);
++ padctrl = rp1_pin_readl(pin->pad);
+
+ switch (param) {
+ case PIN_CONFIG_INPUT_ENABLE:
+@@ -1493,6 +1531,7 @@ static int rp1_pinctrl_probe(struct plat
+ {
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
++ struct device_node *rp1_node = NULL;
+ struct rp1_pinctrl *pc;
+ struct gpio_irq_chip *girq;
+ int err, i;
+@@ -1528,6 +1567,40 @@ static int rp1_pinctrl_probe(struct plat
+ pc->gpio_chip = rp1_gpio_chip;
+ pc->gpio_chip.parent = dev;
+
++ /*
++ * Workaround for the vagaries of PCIe on BCM2712
++ *
++ * If the link to RP1 is in L1, then the BRCMSTB RC will buffer many
++ * outbound writes - and generate write responses for them, despite the
++ * fact that the link is not yet active. This has the effect of compressing
++ * multiple writes to GPIOs together, destroying any pacing that an application
++ * may require in the 1-10us range.
++ *
++ * The RC Slot Control configuration register is special. It emits a
++ * MsgD for every write to it, will stall further writes until the message
++ * goes out on the wire. This can be (ab)used to force CPU stalls when the
++ * link is inactive, at the cost of a small amount of downstream bandwidth
++ * and some 200ns of added latency for each write.
++ *
++ * Several back-to-back configuration writes are necessary to "fill the pipe",
++ * otherwise the outbound MAC can consume a pending MMIO write and reorder
++ * it with respect to the config writes - undoing the intent.
++ *
++ * of_iomap() is used directly here as the address overlaps with the RC driver's
++ * usage.
++ */
++ rp1_node = of_find_node_by_name(NULL, "rp1");
++ if (!rp1_node)
++ dev_err(&pdev->dev, "failed to find RP1 DT node\n");
++ else if (pace_pin_updates &&
++ of_device_is_compatible(rp1_node->parent, "brcm,bcm2712-pcie")) {
++ pc->dummy_base = of_iomap(rp1_node->parent, 0);
++ if (IS_ERR(pc->dummy_base)) {
++ dev_warn(&pdev->dev, "could not map bcm2712 root complex registers\n");
++ pc->dummy_base = NULL;
++ }
++ }
++
+ for (i = 0; i < RP1_NUM_BANKS; i++) {
+ const struct rp1_iobank_desc *bank = &rp1_iobanks[i];
+ int j;
+@@ -1547,14 +1620,17 @@ static int rp1_pinctrl_probe(struct plat
+ pin->rio = pc->rio_base + bank->rio_offset;
+ pin->pad = pc->pads_base + bank->pads_offset +
+ j * sizeof(u32);
++ pin->dummy = pc->dummy_base ? pc->dummy_base + 0xc0 : NULL;
+ }
+
+ raw_spin_lock_init(&pc->irq_lock[i]);
+ }
+
+ pc->pctl_dev = devm_pinctrl_register(dev, &rp1_pinctrl_desc, pc);
+- if (IS_ERR(pc->pctl_dev))
+- return PTR_ERR(pc->pctl_dev);
++ if (IS_ERR(pc->pctl_dev)) {
++ err = PTR_ERR(pc->pctl_dev);
++ goto out_iounmap;
++ }
+
+ girq = &pc->gpio_chip.irq;
+ girq->chip = &rp1_gpio_irq_chip;
+@@ -1583,7 +1659,7 @@ static int rp1_pinctrl_probe(struct plat
+ err = devm_gpiochip_add_data(dev, &pc->gpio_chip, pc);
+ if (err) {
+ dev_err(dev, "could not add GPIO chip\n");
+- return err;
++ goto out_iounmap;
+ }
+
+ pc->gpio_range = rp1_pinctrl_gpio_range;
+@@ -1592,10 +1668,24 @@ static int rp1_pinctrl_probe(struct plat
+ pinctrl_add_gpio_range(pc->pctl_dev, &pc->gpio_range);
+
+ return 0;
++
++out_iounmap:
++ if (pc->dummy_base)
++ iounmap(pc->dummy_base);
++ return err;
++}
++
++static void rp1_pinctrl_remove(struct platform_device *pdev)
++{
++ struct rp1_pinctrl *pc = platform_get_drvdata(pdev);
++
++ if (pc->dummy_base)
++ iounmap(pc->dummy_base);
+ }
+
+ static struct platform_driver rp1_pinctrl_driver = {
+ .probe = rp1_pinctrl_probe,
++ .remove_new = rp1_pinctrl_remove,
+ .driver = {
+ .name = MODULE_NAME,
+ .of_match_table = rp1_pinctrl_match,
--- /dev/null
+From 43fa967811484afde0bbbee182ff8f29dc0550c2 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Fri, 5 Jul 2024 15:57:25 +0100
+Subject: [PATCH 1186/1215] staging: bcm2835-codec: Disable HEADER_ON_OPEN for
+ video encode
+
+Video encode can defer generating the header until the first
+frame is presented, which allows it to take the colourspace
+information from the frame rather than just the format.
+
+Enable that for the V4L2 driver now that the firmware populates
+all the parameters.
+
+https://github.com/raspberrypi/firmware/issues/1885
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -2731,6 +2731,13 @@ static int bcm2835_codec_create_componen
+ ¶ms,
+ sizeof(params));
+
++ } else if (dev->role == ENCODE) {
++ enable = 0;
++ vchiq_mmal_port_parameter_set(dev->instance,
++ &ctx->component->control,
++ MMAL_PARAMETER_VIDEO_ENCODE_HEADER_ON_OPEN,
++ &enable,
++ sizeof(enable));
+ } else if (dev->role == ENCODE_IMAGE) {
+ enable = 0;
+ vchiq_mmal_port_parameter_set(dev->instance,
--- /dev/null
+From 31b9871b8895d7931ee88d7cda7861f829b21d63 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Wed, 17 Jul 2024 16:59:08 +0100
+Subject: [PATCH 1188/1215] staging: bcm2835-codec: Add support for H264 level
+ 5.0 and 5.1
+
+We do NOT claim to support decoding in real-time for these levels,
+but can transcode some content, and handle 1920x1200.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -3273,7 +3273,7 @@ static void dec_add_profile_ctrls(struct
+ case V4L2_PIX_FMT_H264:
+ ctrl = v4l2_ctrl_new_std_menu(hdl, &bcm2835_codec_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_LEVEL,
+- V4L2_MPEG_VIDEO_H264_LEVEL_4_2,
++ V4L2_MPEG_VIDEO_H264_LEVEL_5_1,
+ ~(BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) |
+@@ -3287,7 +3287,9 @@ static void dec_add_profile_ctrls(struct
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) |
+- BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2)),
++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) |
++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) |
++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1)),
+ V4L2_MPEG_VIDEO_H264_LEVEL_4_0);
+ ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ ctrl = v4l2_ctrl_new_std_menu(hdl, &bcm2835_codec_ctrl_ops,
--- /dev/null
+From 6014649de765a8a1f95c146ca72214ff0ba4ba89 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Mon, 1 Jul 2024 15:49:14 +0100
+Subject: [PATCH 1189/1215] spi: dw: Save bandwidth with the TMOD_TO feature
+
+TMOD_TO is the transmit-only mode that doesn't put data into the receive
+FIFO. Using TMOD_TO when the user doesn't want the received data saves
+CPU time and memory bandwidth.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ drivers/spi/spi-dw-core.c | 27 +++++++++++++++++----------
+ 1 file changed, 17 insertions(+), 10 deletions(-)
+
+--- a/drivers/spi/spi-dw-core.c
++++ b/drivers/spi/spi-dw-core.c
+@@ -225,12 +225,17 @@ static irqreturn_t dw_spi_transfer_handl
+ * final stage of the transfer. By doing so we'll get the next IRQ
+ * right when the leftover incoming data is received.
+ */
+- dw_reader(dws);
+- if (!dws->rx_len) {
+- dw_spi_mask_intr(dws, 0xff);
++ if (dws->rx_len) {
++ dw_reader(dws);
++ if (!dws->rx_len) {
++ dw_spi_mask_intr(dws, 0xff);
++ spi_finalize_current_transfer(dws->host);
++ } else if (dws->rx_len <= dw_readl(dws, DW_SPI_RXFTLR)) {
++ dw_writel(dws, DW_SPI_RXFTLR, dws->rx_len - 1);
++ }
++ } else if (!dws->tx_len) {
++ dw_spi_mask_intr(dws, DW_SPI_INT_TXEI);
+ spi_finalize_current_transfer(dws->host);
+- } else if (dws->rx_len <= dw_readl(dws, DW_SPI_RXFTLR)) {
+- dw_writel(dws, DW_SPI_RXFTLR, dws->rx_len - 1);
+ }
+
+ /*
+@@ -239,12 +244,9 @@ static irqreturn_t dw_spi_transfer_handl
+ * have the TXE IRQ flood at the final stage of the transfer.
+ */
+ if (irq_status & DW_SPI_INT_TXEI) {
+- dw_writer(dws);
+- if (!dws->tx_len) {
++ if (!dws->tx_len)
+ dw_spi_mask_intr(dws, DW_SPI_INT_TXEI);
+- if (!dws->rx_len)
+- spi_finalize_current_transfer(dws->host);
+- }
++ dw_writer(dws);
+ }
+
+ return IRQ_HANDLED;
+@@ -437,6 +439,11 @@ static int dw_spi_transfer_one(struct sp
+ dws->rx = transfer->rx_buf;
+ dws->rx_len = dws->tx_len;
+
++ if (!dws->rx) {
++ dws->rx_len = 0;
++ cfg.tmode = DW_SPI_CTRLR0_TMOD_TO;
++ }
++
+ /* Ensure the data above is visible for all CPUs */
+ smp_mb();
+
--- /dev/null
+From cd9084ceb606a2f06c3429c2d3beae2d7c3ebd23 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Mon, 1 Jul 2024 16:41:04 +0100
+Subject: [PATCH 1190/1215] spi: dw: Save bandwidth with the TMOD_RO feature
+
+TMOD_RO is the receive-only mode that doesn't require data in the
+transmit FIFO in order to generate clock cycles. Using TMOD_RO when the
+device doesn't care about the data sent to it saves CPU time and memory
+bandwidth.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ drivers/spi/spi-dw-core.c | 31 +++++++++++++++++++++-------
+ drivers/spi/spi-dw-dma.c | 43 +++++++++++++++++++++++++--------------
+ 2 files changed, 52 insertions(+), 22 deletions(-)
+
+--- a/drivers/spi/spi-dw-core.c
++++ b/drivers/spi/spi-dw-core.c
+@@ -367,18 +367,18 @@ static void dw_spi_irq_setup(struct dw_s
+ * will be adjusted at the final stage of the IRQ-based SPI transfer
+ * execution so not to lose the leftover of the incoming data.
+ */
+- level = min_t(unsigned int, dws->fifo_len / 2, dws->tx_len);
++ level = min_t(unsigned int, dws->fifo_len / 2, dws->tx_len ? dws->tx_len : dws->rx_len);
+ dw_writel(dws, DW_SPI_TXFTLR, level);
+ dw_writel(dws, DW_SPI_RXFTLR, level - 1);
+
+ dws->transfer_handler = dw_spi_transfer_handler;
+
+- imask = 0;
+- if (dws->tx_len)
+- imask |= DW_SPI_INT_TXEI | DW_SPI_INT_TXOI;
++ imask = DW_SPI_INT_TXEI | DW_SPI_INT_TXOI;
+ if (dws->rx_len)
+ imask |= DW_SPI_INT_RXUI | DW_SPI_INT_RXOI | DW_SPI_INT_RXFI;
+ dw_spi_umask_intr(dws, imask);
++ if (!dws->tx_len)
++ dw_writel(dws, DW_SPI_DR, 0);
+ }
+
+ /*
+@@ -401,13 +401,18 @@ static int dw_spi_poll_transfer(struct d
+ delay.unit = SPI_DELAY_UNIT_SCK;
+ nbits = dws->n_bytes * BITS_PER_BYTE;
+
++ if (!dws->tx_len)
++ dw_writel(dws, DW_SPI_DR, 0);
++
+ do {
+- dw_writer(dws);
++ if (dws->tx_len)
++ dw_writer(dws);
+
+ delay.value = nbits * (dws->rx_len - dws->tx_len);
+ spi_delay_exec(&delay, transfer);
+
+- dw_reader(dws);
++ if (dws->rx_len)
++ dw_reader(dws);
+
+ ret = dw_spi_check_status(dws, true);
+ if (ret)
+@@ -427,6 +432,7 @@ static int dw_spi_transfer_one(struct sp
+ .dfs = transfer->bits_per_word,
+ .freq = transfer->speed_hz,
+ };
++ int buswidth;
+ int ret;
+
+ dws->dma_mapped = 0;
+@@ -444,6 +450,18 @@ static int dw_spi_transfer_one(struct sp
+ cfg.tmode = DW_SPI_CTRLR0_TMOD_TO;
+ }
+
++ if (!dws->rx) {
++ dws->rx_len = 0;
++ cfg.tmode = DW_SPI_CTRLR0_TMOD_TO;
++ }
++ if (!dws->tx) {
++ dws->tx_len = 0;
++ cfg.tmode = DW_SPI_CTRLR0_TMOD_RO;
++ cfg.ndf = dws->rx_len;
++ }
++ buswidth = transfer->rx_buf ? transfer->rx_nbits :
++ (transfer->tx_buf ? transfer->tx_nbits : 1);
++
+ /* Ensure the data above is visible for all CPUs */
+ smp_mb();
+
+@@ -961,7 +979,6 @@ int dw_spi_add_host(struct device *dev,
+ dev_warn(dev, "DMA init failed\n");
+ } else {
+ host->can_dma = dws->dma_ops->can_dma;
+- host->flags |= SPI_CONTROLLER_MUST_TX;
+ }
+ }
+
+--- a/drivers/spi/spi-dw-dma.c
++++ b/drivers/spi/spi-dw-dma.c
+@@ -6,6 +6,7 @@
+ */
+
+ #include <linux/completion.h>
++#include <linux/delay.h>
+ #include <linux/dma-mapping.h>
+ #include <linux/dmaengine.h>
+ #include <linux/irqreturn.h>
+@@ -470,13 +471,12 @@ static int dw_spi_dma_setup(struct dw_sp
+ u16 imr, dma_ctrl;
+ int ret;
+
+- if (!xfer->tx_buf)
+- return -EINVAL;
+-
+ /* Setup DMA channels */
+- ret = dw_spi_dma_config_tx(dws);
+- if (ret)
+- return ret;
++ if (xfer->tx_buf) {
++ ret = dw_spi_dma_config_tx(dws);
++ if (ret)
++ return ret;
++ }
+
+ if (xfer->rx_buf) {
+ ret = dw_spi_dma_config_rx(dws);
+@@ -485,13 +485,17 @@ static int dw_spi_dma_setup(struct dw_sp
+ }
+
+ /* Set the DMA handshaking interface */
+- dma_ctrl = DW_SPI_DMACR_TDMAE;
++ dma_ctrl = 0;
++ if (xfer->tx_buf)
++ dma_ctrl |= DW_SPI_DMACR_TDMAE;
+ if (xfer->rx_buf)
+ dma_ctrl |= DW_SPI_DMACR_RDMAE;
+ dw_writel(dws, DW_SPI_DMACR, dma_ctrl);
+
+ /* Set the interrupt mask */
+- imr = DW_SPI_INT_TXOI;
++ imr = 0;
++ if (xfer->tx_buf)
++ imr |= DW_SPI_INT_TXOI;
+ if (xfer->rx_buf)
+ imr |= DW_SPI_INT_RXUI | DW_SPI_INT_RXOI;
+ dw_spi_umask_intr(dws, imr);
+@@ -508,15 +512,16 @@ static int dw_spi_dma_transfer_all(struc
+ {
+ int ret;
+
+- /* Submit the DMA Tx transfer */
+- ret = dw_spi_dma_submit_tx(dws, xfer->tx_sg.sgl, xfer->tx_sg.nents);
+- if (ret)
+- goto err_clear_dmac;
++ /* Submit the DMA Tx transfer if required */
++ if (xfer->tx_buf) {
++ ret = dw_spi_dma_submit_tx(dws, xfer->tx_sg.sgl, xfer->tx_sg.nents);
++ if (ret)
++ goto err_clear_dmac;
++ }
+
+ /* Submit the DMA Rx transfer if required */
+ if (xfer->rx_buf) {
+- ret = dw_spi_dma_submit_rx(dws, xfer->rx_sg.sgl,
+- xfer->rx_sg.nents);
++ ret = dw_spi_dma_submit_rx(dws, xfer->rx_sg.sgl, xfer->rx_sg.nents);
+ if (ret)
+ goto err_clear_dmac;
+
+@@ -524,7 +529,15 @@ static int dw_spi_dma_transfer_all(struc
+ dma_async_issue_pending(dws->rxchan);
+ }
+
+- dma_async_issue_pending(dws->txchan);
++ if (xfer->tx_buf) {
++ dma_async_issue_pending(dws->txchan);
++ } else {
++ /* Pause to allow DMA channel to fetch RX descriptor */
++ usleep_range(5, 10);
++
++ /* Write something to the TX FIFO to start the transfer */
++ dw_writel(dws, DW_SPI_DR, 0);
++ }
+
+ ret = dw_spi_dma_wait(dws, xfer->len, xfer->effective_speed_hz);
+
--- /dev/null
+From 3af7822df36e36b5a74d877df7654695c0e0d34a Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <jonathan@raspberrypi.com>
+Date: Mon, 22 Jul 2024 15:27:51 +0100
+Subject: [PATCH 1191/1215] spi: dw: don't immediately kill DMA transfers if an
+ error occurs
+
+Disabling the peripheral resets controller state which has a dangerous
+side-effect of disabling the DMA handshake interface while it is active.
+This can cause DMA channels to hang.
+
+The error recovery pathway will wait for DMA to stop and reset the chip
+anyway, so mask further FIFO interrupts and let the transfer finish
+gracefully.
+
+Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
+---
+ drivers/spi/spi-dw-core.c | 13 ++++++++++++-
+ 1 file changed, 12 insertions(+), 1 deletion(-)
+
+--- a/drivers/spi/spi-dw-core.c
++++ b/drivers/spi/spi-dw-core.c
+@@ -200,7 +200,18 @@ int dw_spi_check_status(struct dw_spi *d
+
+ /* Generically handle the erroneous situation */
+ if (ret) {
+- dw_spi_reset_chip(dws);
++ /*
++ * Forcibly halting the controller can cause DMA to hang.
++ * Defer to dw_spi_handle_err outside of interrupt context
++ * and mask further interrupts for the current transfer.
++ */
++ if (dws->dma_mapped) {
++ dw_spi_mask_intr(dws, 0xff);
++ dw_readl(dws, DW_SPI_ICR);
++ } else {
++ dw_spi_reset_chip(dws);
++ }
++
+ if (dws->host->cur_msg)
+ dws->host->cur_msg->status = ret;
+ }
--- /dev/null
+From 4c1a665b465fa0e9d3369a467fc563ec812a47ce Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <jonathan@raspberrypi.com>
+Date: Fri, 19 Jul 2024 13:07:59 +0100
+Subject: [PATCH 1192/1215] dts: rp1: hobble DMA AXI burst lengths
+
+Channels 1-2 have a statically configured maximum MSIZE of 8, and
+channels 3-8 have MSIZE set to 4. The DMAC "helpfully" silently
+truncates bursts to the hardware supported maximum, so any FIFO read
+operation with an oversized burst threshold will leave a residue of
+threshold minus MSIZE rows.
+
+As channel allocation is dynamic, this means every client needs to use a
+maximum of 4 for burst length.
+
+AXI AWLEN/ARLEN constraints aren't strictly related to MSIZE, except
+that bursts won't be issued that are longer than MSIZE beats. Therefore,
+it's a useful proxy to tell clients of the DMAC the hardware
+limitations.
+
+Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
+---
+ arch/arm64/boot/dts/broadcom/rp1.dtsi | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm64/boot/dts/broadcom/rp1.dtsi
++++ b/arch/arm64/boot/dts/broadcom/rp1.dtsi
+@@ -1064,7 +1064,7 @@
+ snps,data-width = <4>; // (8 << 4) == 128 bits
+ snps,block-size = <0x40000 0x40000 0x40000 0x40000 0x40000 0x40000 0x40000 0x40000>;
+ snps,priority = <0 1 2 3 4 5 6 7>;
+- snps,axi-max-burst-len = <8>;
++ snps,axi-max-burst-len = <4>;
+ status = "disabled";
+ };
+
--- /dev/null
+From ce56098eb4dc2985f27f30ad7b7f5aed6bcf7fb1 Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <jonathan@raspberrypi.com>
+Date: Fri, 19 Jul 2024 15:55:56 +0100
+Subject: [PATCH 1193/1215] drivers: dw-axi-dmac: make more sensible choices
+ about memory accesses
+
+There's no real need to constrain MEM access widths to 32-bit (or
+narrower), as the DMAC is intelligent enough to size memory accesses
+appropriately. Wider accesses are more efficient.
+
+Similarly, MEM burst lengths don't need to be a function of DEV burst
+lengths - the DMAC packs/unpacks data into/from its internal channel
+FIFOs appropriately. Longer accesses are more efficient.
+
+However, the DMAC doesn't have complete support for unaligned accesses,
+and blocks are always defined in integer multiples of SRC_WIDTH, so odd
+source lengths or buffer alignments will prevent wide accesses being
+used, as before.
+
+There is an implicit requirement to limit requested DEV read burst
+lengths to less than the hardware's maximum configured MSIZE - otherwise
+RX data will be left over at the end of a block. There is no config
+register that reports this value, so the AXI burst length parameter is
+used to produce a facsimile of it. Warn if such a request arrives that
+doesn't respect this.
+
+Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
+---
+ .../dma/dw-axi-dmac/dw-axi-dmac-platform.c | 38 ++++++++++++-------
+ 1 file changed, 25 insertions(+), 13 deletions(-)
+
+--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
++++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
+@@ -261,6 +261,15 @@ static u32 axi_chan_get_xfer_width(struc
+ return __ffs(src | dst | len | BIT(max_width));
+ }
+
++static u32 axi_dma_encode_msize(u32 max_burst)
++{
++ if (max_burst <= 1)
++ return DWAXIDMAC_BURST_TRANS_LEN_1;
++ if (max_burst > 1024)
++ return DWAXIDMAC_BURST_TRANS_LEN_1024;
++ return fls(max_burst) - 2;
++}
++
+ static inline const char *axi_chan_name(struct axi_dma_chan *chan)
+ {
+ return dma_chan_name(&chan->vc.chan);
+@@ -685,41 +694,41 @@ static int dw_axi_dma_set_hw_desc(struct
+ size_t axi_block_ts;
+ size_t block_ts;
+ u32 ctllo, ctlhi;
+- u32 burst_len;
++ u32 burst_len = 0, mem_burst_msize, reg_burst_msize;
+
+ axi_block_ts = chan->chip->dw->hdata->block_size[chan->id];
+
+ mem_width = __ffs(data_width | mem_addr | len);
+- if (mem_width > DWAXIDMAC_TRANS_WIDTH_32)
+- mem_width = DWAXIDMAC_TRANS_WIDTH_32;
+
+ if (!IS_ALIGNED(mem_addr, 4)) {
+ dev_err(chan->chip->dev, "invalid buffer alignment\n");
+ return -EINVAL;
+ }
+
++ /* Use a reasonable upper limit otherwise residue reporting granularity grows large */
++ mem_burst_msize = axi_dma_encode_msize(16);
++
+ switch (chan->direction) {
+ case DMA_MEM_TO_DEV:
++ reg_burst_msize = axi_dma_encode_msize(chan->config.dst_maxburst);
+ reg_width = __ffs(chan->config.dst_addr_width);
+ device_addr = phys_to_dma(chan->chip->dev, chan->config.dst_addr);
+ ctllo = reg_width << CH_CTL_L_DST_WIDTH_POS |
+ mem_width << CH_CTL_L_SRC_WIDTH_POS |
+- DWAXIDMAC_BURST_TRANS_LEN_1 << CH_CTL_L_DST_MSIZE_POS |
+- DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_SRC_MSIZE_POS |
++ reg_burst_msize << CH_CTL_L_DST_MSIZE_POS |
++ mem_burst_msize << CH_CTL_L_SRC_MSIZE_POS |
+ DWAXIDMAC_CH_CTL_L_NOINC << CH_CTL_L_DST_INC_POS |
+ DWAXIDMAC_CH_CTL_L_INC << CH_CTL_L_SRC_INC_POS;
+ block_ts = len >> mem_width;
+ break;
+ case DMA_DEV_TO_MEM:
++ reg_burst_msize = axi_dma_encode_msize(chan->config.src_maxburst);
+ reg_width = __ffs(chan->config.src_addr_width);
+- /* Prevent partial access units getting lost */
+- if (mem_width > reg_width)
+- mem_width = reg_width;
+ device_addr = phys_to_dma(chan->chip->dev, chan->config.src_addr);
+ ctllo = reg_width << CH_CTL_L_SRC_WIDTH_POS |
+ mem_width << CH_CTL_L_DST_WIDTH_POS |
+- DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_DST_MSIZE_POS |
+- DWAXIDMAC_BURST_TRANS_LEN_1 << CH_CTL_L_SRC_MSIZE_POS |
++ mem_burst_msize << CH_CTL_L_DST_MSIZE_POS |
++ reg_burst_msize << CH_CTL_L_SRC_MSIZE_POS |
+ DWAXIDMAC_CH_CTL_L_INC << CH_CTL_L_DST_INC_POS |
+ DWAXIDMAC_CH_CTL_L_NOINC << CH_CTL_L_SRC_INC_POS;
+ block_ts = len >> reg_width;
+@@ -760,6 +769,12 @@ static int dw_axi_dma_set_hw_desc(struct
+ set_desc_src_master(hw_desc);
+
+ hw_desc->len = len;
++
++ if (burst_len && (chan->config.src_maxburst > burst_len))
++ dev_warn_ratelimited(chan2dev(chan),
++ "%s: requested source burst length %u exceeds supported burst length %u - data may be lost\n",
++ axi_chan_name(chan), chan->config.src_maxburst, burst_len);
++
+ return 0;
+ }
+
+@@ -776,9 +791,6 @@ static size_t calculate_block_len(struct
+ case DMA_MEM_TO_DEV:
+ data_width = BIT(chan->chip->dw->hdata->m_data_width);
+ mem_width = __ffs(data_width | dma_addr | buf_len);
+- if (mem_width > DWAXIDMAC_TRANS_WIDTH_32)
+- mem_width = DWAXIDMAC_TRANS_WIDTH_32;
+-
+ block_len = axi_block_ts << mem_width;
+ break;
+ case DMA_DEV_TO_MEM:
--- /dev/null
+From f3cb675102a2a5a330038c4e748f02b02cec989e Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <jonathan@raspberrypi.com>
+Date: Mon, 22 Jul 2024 09:30:54 +0100
+Subject: [PATCH 1195/1215] tty/serial: pl011: restrict RX burst FIFO threshold
+
+If the associated DMA controller has lower burst length support than the
+level the FIFO is set to, then bytes will be left in the RX FIFO at the
+end of a DMA block - requiring a round-trip through the timeout interrupt
+handler rather than an end-of-block DMA interrupt.
+
+Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
+---
+ drivers/tty/serial/amba-pl011.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/drivers/tty/serial/amba-pl011.c
++++ b/drivers/tty/serial/amba-pl011.c
+@@ -487,6 +487,12 @@ static void pl011_dma_probe(struct uart_
+ "RX DMA disabled - no residue processing\n");
+ return;
+ }
++ /*
++ * DMA controllers with smaller burst capabilities than 1/4
++ * the FIFO depth will leave more bytes than expected in the
++ * RX FIFO if mismatched.
++ */
++ rx_conf.src_maxburst = min(caps.max_burst, rx_conf.src_maxburst);
+ }
+ dmaengine_slave_config(chan, &rx_conf);
+ uap->dmarx.chan = chan;
--- /dev/null
+From 5112fd8cce4f1dc9bf43f0f90d35e273e1a0f555 Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <jonathan@raspberrypi.com>
+Date: Mon, 22 Jul 2024 14:32:32 +0100
+Subject: [PATCH 1196/1215] DT: bindings: add a dma-maxburst property to
+ snps,designware-i2s
+
+Do an end-run around ASoC in lieu of not being able to easily find the
+associated DMA controller capabilities.
+
+Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
+---
+ .../devicetree/bindings/sound/snps,designware-i2s.yaml | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/Documentation/devicetree/bindings/sound/snps,designware-i2s.yaml
++++ b/Documentation/devicetree/bindings/sound/snps,designware-i2s.yaml
+@@ -69,6 +69,10 @@ properties:
+ - description: RX DMA Channel
+ minItems: 1
+
++ dma-maxburst:
++ description: FIFO DMA burst threshold limit
++ maxItems: 1
++
+ dma-names:
+ items:
+ - const: tx
--- /dev/null
+From b6b4260fa546d1dc7421c7cfed059052dae04227 Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <jonathan@raspberrypi.com>
+Date: Thu, 18 Jul 2024 09:40:03 +0100
+Subject: [PATCH 1197/1215] sound/soc: dwc-i2s: choose FIFO thresholds based on
+ DMA burst constraints
+
+Valid ranges for the I2S peripheral's FIFO configuration include a depth
+of 16 - unconditionally setting the burst length to 16 with a fifo
+threshold of size/2 will cause under/overflows.
+
+For DMA engines with restricted capabilities the requested burst length
+and FIFO thresholds need to be adjusted downward accordingly.
+
+Both the RX and TX FIFOs operate on "less-than" thresholds. Setting the
+TX threshold to fifo_size minus burst means the FIFO is kept nearly-full.
+
+Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
+---
+ sound/soc/dwc/dwc-i2s.c | 21 ++++++++++++++++-----
+ sound/soc/dwc/local.h | 1 +
+ 2 files changed, 17 insertions(+), 5 deletions(-)
+
+--- a/sound/soc/dwc/dwc-i2s.c
++++ b/sound/soc/dwc/dwc-i2s.c
+@@ -236,6 +236,8 @@ static void dw_i2s_config(struct dw_i2s_
+ u32 ch_reg;
+ struct i2s_clk_config_data *config = &dev->config;
+ u32 dmacr;
++ u32 comp1 = i2s_read_reg(dev->i2s_base, dev->i2s_reg_comp1);
++ u32 fifo_depth = 1 << (1 + COMP1_FIFO_DEPTH_GLOBAL(comp1));
+
+ i2s_disable_channels(dev, stream);
+
+@@ -251,7 +253,7 @@ static void dw_i2s_config(struct dw_i2s_
+ i2s_write_reg(dev->i2s_base, TCR(ch_reg),
+ dev->xfer_resolution);
+ i2s_write_reg(dev->i2s_base, TFCR(ch_reg),
+- dev->fifo_th - 1);
++ fifo_depth - dev->fifo_th - 1);
+ i2s_write_reg(dev->i2s_base, TER(ch_reg), TER_TXCHEN |
+ dev->tdm_mask << TER_TXSLOT_SHIFT);
+ dmacr |= (DMACR_DMAEN_TXCH0 << ch_reg);
+@@ -783,8 +785,8 @@ static int dw_configure_dai_by_pd(struct
+ dev->capture_dma_data.pd.data = pdata->capture_dma_data;
+ dev->play_dma_data.pd.addr = res->start + I2S_TXDMA;
+ dev->capture_dma_data.pd.addr = res->start + I2S_RXDMA;
+- dev->play_dma_data.pd.max_burst = 16;
+- dev->capture_dma_data.pd.max_burst = 16;
++ dev->play_dma_data.pd.max_burst = dev->fifo_th;
++ dev->capture_dma_data.pd.max_burst = dev->fifo_th;
+ dev->play_dma_data.pd.addr_width = bus_widths[idx];
+ dev->capture_dma_data.pd.addr_width = bus_widths[idx];
+ dev->play_dma_data.pd.filter = pdata->filter;
+@@ -815,7 +817,10 @@ static int dw_configure_dai_by_dt(struct
+ dev->play_dma_data.dt.addr = res->start + I2S_TXDMA;
+ dev->play_dma_data.dt.fifo_size = fifo_depth *
+ (fifo_width[idx2]) >> 8;
+- dev->play_dma_data.dt.maxburst = 16;
++ if (dev->max_dma_burst)
++ dev->play_dma_data.dt.maxburst = dev->max_dma_burst;
++ else
++ dev->play_dma_data.dt.maxburst = fifo_depth / 2;
+ }
+ if (COMP1_RX_ENABLED(comp1)) {
+ idx2 = COMP2_RX_WORDSIZE_0(comp2);
+@@ -824,9 +829,14 @@ static int dw_configure_dai_by_dt(struct
+ dev->capture_dma_data.dt.addr = res->start + I2S_RXDMA;
+ dev->capture_dma_data.dt.fifo_size = fifo_depth *
+ (fifo_width[idx2] >> 8);
+- dev->capture_dma_data.dt.maxburst = 16;
++ if (dev->max_dma_burst)
++ dev->capture_dma_data.dt.maxburst = dev->max_dma_burst;
++ else
++ dev->capture_dma_data.dt.maxburst = fifo_depth / 2;
+ }
+
++ if (dev->max_dma_burst)
++ dev->fifo_th = min(dev->max_dma_burst, dev->fifo_th);
+ return 0;
+
+ }
+@@ -1070,6 +1080,7 @@ static int dw_i2s_probe(struct platform_
+ }
+ }
+
++ of_property_read_u32(pdev->dev.of_node, "dma-maxburst", &dev->max_dma_burst);
+ dev->bclk_ratio = 0;
+ dev->i2s_reg_comp1 = I2S_COMP_PARAM_1;
+ dev->i2s_reg_comp2 = I2S_COMP_PARAM_2;
+--- a/sound/soc/dwc/local.h
++++ b/sound/soc/dwc/local.h
+@@ -133,6 +133,7 @@ struct dw_i2s_dev {
+ u32 ccr;
+ u32 xfer_resolution;
+ u32 fifo_th;
++ u32 max_dma_burst;
+ u32 l_reg;
+ u32 r_reg;
+ bool is_jh7110; /* Flag for StarFive JH7110 SoC */
--- /dev/null
+From 062434ab3be76d4fa5973bb199ccfd5b68c11720 Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <jonathan@raspberrypi.com>
+Date: Tue, 23 Jul 2024 11:21:47 +0100
+Subject: [PATCH 1198/1215] dts: rp1: restrict i2s burst lengths to 4
+
+The associated DMAC has channels that do not support longer bursts.
+
+Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
+---
+ arch/arm64/boot/dts/broadcom/rp1.dtsi | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/arch/arm64/boot/dts/broadcom/rp1.dtsi
++++ b/arch/arm64/boot/dts/broadcom/rp1.dtsi
+@@ -400,6 +400,7 @@
+ #sound-dai-cells = <0>;
+ dmas = <&rp1_dma RP1_DMA_I2S0_TX>,<&rp1_dma RP1_DMA_I2S0_RX>;
+ dma-names = "tx", "rx";
++ dma-maxburst = <4>;
+ status = "disabled";
+ };
+
+@@ -413,6 +414,7 @@
+ #sound-dai-cells = <0>;
+ dmas = <&rp1_dma RP1_DMA_I2S1_TX>,<&rp1_dma RP1_DMA_I2S1_RX>;
+ dma-names = "tx", "rx";
++ dma-maxburst = <4>;
+ status = "disabled";
+ };
+
--- /dev/null
+From 485d11cfa7df2d2deb39c9b3455cebcb1a85cea2 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Thu, 25 Jul 2024 14:36:32 +0100
+Subject: [PATCH 1199/1215] drm/vc4: Disable the 2pixel/clock odd timings
+ workaround for interlaced
+
+Whilst BCM2712 does fix using odd horizontal timings, it doesn't
+work with interlaced modes.
+
+Drop the workaround for interlaced modes and revert to the same
+behaviour as BCM2711.
+
+https://github.com/raspberrypi/linux/issues/6281
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ drivers/gpu/drm/vc4/vc4_crtc.c | 20 +++++++++++++++++---
+ drivers/gpu/drm/vc4/vc4_drv.h | 2 ++
+ drivers/gpu/drm/vc4/vc4_hdmi.c | 8 +++++++-
+ drivers/gpu/drm/vc4/vc4_hdmi.h | 4 ++++
+ 4 files changed, 30 insertions(+), 4 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_crtc.c
++++ b/drivers/gpu/drm/vc4/vc4_crtc.c
+@@ -378,7 +378,9 @@ static void vc4_crtc_config_pv(struct dr
+ bool is_dsi1 = vc4_encoder->type == VC4_ENCODER_TYPE_DSI1;
+ bool is_vec = vc4_encoder->type == VC4_ENCODER_TYPE_VEC;
+ u32 format = is_dsi1 ? PV_CONTROL_FORMAT_DSIV_24 : PV_CONTROL_FORMAT_24;
+- u8 ppc = pv_data->pixels_per_clock;
++ u8 ppc = (mode->flags & DRM_MODE_FLAG_INTERLACE) ?
++ pv_data->pixels_per_clock_int :
++ pv_data->pixels_per_clock;
+
+ u16 vert_bp = mode->crtc_vtotal - mode->crtc_vsync_end;
+ u16 vert_sync = mode->crtc_vsync_end - mode->crtc_vsync_start;
+@@ -443,7 +445,8 @@ static void vc4_crtc_config_pv(struct dr
+ */
+ CRTC_WRITE(PV_V_CONTROL,
+ PV_VCONTROL_CONTINUOUS |
+- (vc4->gen >= VC4_GEN_6 ? PV_VCONTROL_ODD_TIMING : 0) |
++ (vc4->gen >= VC4_GEN_6 && ppc == 1 ?
++ PV_VCONTROL_ODD_TIMING : 0) |
+ (is_dsi ? PV_VCONTROL_DSI : 0) |
+ PV_VCONTROL_INTERLACE |
+ (odd_field_first
+@@ -455,7 +458,8 @@ static void vc4_crtc_config_pv(struct dr
+ } else {
+ CRTC_WRITE(PV_V_CONTROL,
+ PV_VCONTROL_CONTINUOUS |
+- (vc4->gen >= VC4_GEN_6 ? PV_VCONTROL_ODD_TIMING : 0) |
++ (vc4->gen >= VC4_GEN_6 && ppc == 1 ?
++ PV_VCONTROL_ODD_TIMING : 0) |
+ (is_dsi ? PV_VCONTROL_DSI : 0));
+ CRTC_WRITE(PV_VSYNCD_EVEN, 0);
+ }
+@@ -1223,6 +1227,7 @@ const struct vc4_pv_data bcm2835_pv0_dat
+ },
+ .fifo_depth = 64,
+ .pixels_per_clock = 1,
++ .pixels_per_clock_int = 1,
+ .encoder_types = {
+ [PV_CONTROL_CLK_SELECT_DSI] = VC4_ENCODER_TYPE_DSI0,
+ [PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_DPI,
+@@ -1238,6 +1243,7 @@ const struct vc4_pv_data bcm2835_pv1_dat
+ },
+ .fifo_depth = 64,
+ .pixels_per_clock = 1,
++ .pixels_per_clock_int = 1,
+ .encoder_types = {
+ [PV_CONTROL_CLK_SELECT_DSI] = VC4_ENCODER_TYPE_DSI1,
+ [PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_SMI,
+@@ -1253,6 +1259,7 @@ const struct vc4_pv_data bcm2835_pv2_dat
+ },
+ .fifo_depth = 64,
+ .pixels_per_clock = 1,
++ .pixels_per_clock_int = 1,
+ .encoder_types = {
+ [PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_HDMI0,
+ [PV_CONTROL_CLK_SELECT_VEC] = VC4_ENCODER_TYPE_VEC,
+@@ -1268,6 +1275,7 @@ const struct vc4_pv_data bcm2711_pv0_dat
+ },
+ .fifo_depth = 64,
+ .pixels_per_clock = 1,
++ .pixels_per_clock_int = 1,
+ .encoder_types = {
+ [0] = VC4_ENCODER_TYPE_DSI0,
+ [1] = VC4_ENCODER_TYPE_DPI,
+@@ -1283,6 +1291,7 @@ const struct vc4_pv_data bcm2711_pv1_dat
+ },
+ .fifo_depth = 64,
+ .pixels_per_clock = 1,
++ .pixels_per_clock_int = 1,
+ .encoder_types = {
+ [0] = VC4_ENCODER_TYPE_DSI1,
+ [1] = VC4_ENCODER_TYPE_SMI,
+@@ -1298,6 +1307,7 @@ const struct vc4_pv_data bcm2711_pv2_dat
+ },
+ .fifo_depth = 256,
+ .pixels_per_clock = 2,
++ .pixels_per_clock_int = 2,
+ .encoder_types = {
+ [0] = VC4_ENCODER_TYPE_HDMI0,
+ },
+@@ -1312,6 +1322,7 @@ const struct vc4_pv_data bcm2711_pv3_dat
+ },
+ .fifo_depth = 64,
+ .pixels_per_clock = 1,
++ .pixels_per_clock_int = 1,
+ .encoder_types = {
+ [PV_CONTROL_CLK_SELECT_VEC] = VC4_ENCODER_TYPE_VEC,
+ },
+@@ -1326,6 +1337,7 @@ const struct vc4_pv_data bcm2711_pv4_dat
+ },
+ .fifo_depth = 64,
+ .pixels_per_clock = 2,
++ .pixels_per_clock_int = 2,
+ .encoder_types = {
+ [0] = VC4_ENCODER_TYPE_HDMI1,
+ },
+@@ -1339,6 +1351,7 @@ const struct vc4_pv_data bcm2712_pv0_dat
+ },
+ .fifo_depth = 64,
+ .pixels_per_clock = 1,
++ .pixels_per_clock_int = 2,
+ .encoder_types = {
+ [0] = VC4_ENCODER_TYPE_HDMI0,
+ },
+@@ -1352,6 +1365,7 @@ const struct vc4_pv_data bcm2712_pv1_dat
+ },
+ .fifo_depth = 64,
+ .pixels_per_clock = 1,
++ .pixels_per_clock_int = 2,
+ .encoder_types = {
+ [0] = VC4_ENCODER_TYPE_HDMI1,
+ },
+--- a/drivers/gpu/drm/vc4/vc4_drv.h
++++ b/drivers/gpu/drm/vc4/vc4_drv.h
+@@ -569,6 +569,8 @@ struct vc4_pv_data {
+
+ /* Number of pixels output per clock period */
+ u8 pixels_per_clock;
++ /* Number of pixels output per clock period when in an interlaced mode */
++ u8 pixels_per_clock_int;
+
+ enum vc4_encoder_type encoder_types[4];
+ };
+--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
+@@ -2263,7 +2263,9 @@ static int vc4_hdmi_encoder_atomic_check
+ unsigned long long tmds_bit_rate;
+ int ret;
+
+- if (vc4_hdmi->variant->unsupported_odd_h_timings) {
++ if (vc4_hdmi->variant->unsupported_odd_h_timings ||
++ (vc4_hdmi->variant->unsupported_int_odd_h_timings &&
++ (mode->flags & DRM_MODE_FLAG_INTERLACE))) {
+ if (mode->flags & DRM_MODE_FLAG_DBLCLK) {
+ /* Only try to fixup DBLCLK modes to get 480i and 576i
+ * working.
+@@ -3974,6 +3976,7 @@ static const struct vc4_hdmi_variant bcm
+ PHY_LANE_CK,
+ },
+ .unsupported_odd_h_timings = true,
++ .unsupported_int_odd_h_timings = true,
+ .external_irq_controller = true,
+
+ .init_resources = vc5_hdmi_init_resources,
+@@ -4003,6 +4006,7 @@ static const struct vc4_hdmi_variant bcm
+ PHY_LANE_2,
+ },
+ .unsupported_odd_h_timings = true,
++ .unsupported_int_odd_h_timings = true,
+ .external_irq_controller = true,
+
+ .init_resources = vc5_hdmi_init_resources,
+@@ -4032,6 +4036,7 @@ static const struct vc4_hdmi_variant bcm
+ PHY_LANE_CK,
+ },
+ .unsupported_odd_h_timings = false,
++ .unsupported_int_odd_h_timings = true,
+ .external_irq_controller = true,
+
+ .init_resources = vc5_hdmi_init_resources,
+@@ -4059,6 +4064,7 @@ static const struct vc4_hdmi_variant bcm
+ PHY_LANE_CK,
+ },
+ .unsupported_odd_h_timings = false,
++ .unsupported_int_odd_h_timings = true,
+ .external_irq_controller = true,
+
+ .init_resources = vc5_hdmi_init_resources,
+--- a/drivers/gpu/drm/vc4/vc4_hdmi.h
++++ b/drivers/gpu/drm/vc4/vc4_hdmi.h
+@@ -49,6 +49,10 @@ struct vc4_hdmi_variant {
+
+ /* The BCM2711 cannot deal with odd horizontal pixel timings */
+ bool unsupported_odd_h_timings;
++ /* The BCM2712 can handle odd horizontal pixel timings, but not in
++ * interlaced modes
++ */
++ bool unsupported_int_odd_h_timings;
+
+ /*
+ * The BCM2711 CEC/hotplug IRQ controller is shared between the
--- /dev/null
+From 70636ad110715b5e1ec6b08e24f0ddaf5df7186d Mon Sep 17 00:00:00 2001
+From: Dom Cobley <popcornmix@gmail.com>
+Date: Tue, 30 Jul 2024 19:00:03 +0100
+Subject: [PATCH 1200/1215] ARM: dts: bcm2712: Fix invalid
+ polling-delay-passive setting
+
+This produces a hard fail on later (6.11) kernels.
+
+See: https://lore.kernel.org/all/5802156.DvuYhMxLoT@rjwysocki.net/
+
+Signed-off-by: Dom Cobley <popcornmix@gmail.com>
+---
+ arch/arm64/boot/dts/broadcom/bcm2712.dtsi | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm64/boot/dts/broadcom/bcm2712.dtsi
++++ b/arch/arm64/boot/dts/broadcom/bcm2712.dtsi
+@@ -40,7 +40,7 @@
+
+ thermal-zones {
+ cpu_thermal: cpu-thermal {
+- polling-delay-passive = <2000>;
++ polling-delay-passive = <1000>;
+ polling-delay = <1000>;
+ coefficients = <(-550) 450000>;
+ thermal-sensors = <&thermal>;
--- /dev/null
+From 199e611183de09ad91fe01fc79da78cc9d11ccb6 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Mon, 29 Jul 2024 11:12:38 +0100
+Subject: [PATCH 1201/1215] spi: dw: Fix non-DMA transmit-only transfers
+
+Ensure the transmit FIFO has emptied before ending the transfer by
+dropping the TX threshold to 0 when the last byte has been pushed into
+the FIFO. Include a similar fix for the non-IRQ paths.
+
+See: https://github.com/raspberrypi/linux/issues/6285
+Fixes: 6014649de765 ("spi: dw: Save bandwidth with the TMOD_TO feature")
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ drivers/spi/spi-dw-core.c | 62 +++++++++++++++++++++++++++++++++------
+ drivers/spi/spi-dw.h | 3 ++
+ 2 files changed, 56 insertions(+), 9 deletions(-)
+
+--- a/drivers/spi/spi-dw-core.c
++++ b/drivers/spi/spi-dw-core.c
+@@ -220,6 +220,32 @@ int dw_spi_check_status(struct dw_spi *d
+ }
+ EXPORT_SYMBOL_NS_GPL(dw_spi_check_status, SPI_DW_CORE);
+
++static inline bool dw_spi_ctlr_busy(struct dw_spi *dws)
++{
++ return dw_readl(dws, DW_SPI_SR) & DW_SPI_SR_BUSY;
++}
++
++static enum hrtimer_restart dw_spi_hrtimer_handler(struct hrtimer *hr)
++{
++ struct dw_spi *dws = container_of(hr, struct dw_spi, hrtimer);
++
++ if (!dw_spi_ctlr_busy(dws)) {
++ spi_finalize_current_transfer(dws->host);
++ return HRTIMER_NORESTART;
++ }
++
++ if (!dws->idle_wait_retries) {
++ dev_err(&dws->host->dev, "controller stuck at busy\n");
++ spi_finalize_current_transfer(dws->host);
++ return HRTIMER_NORESTART;
++ }
++
++ dws->idle_wait_retries--;
++ hrtimer_forward_now(hr, dws->idle_wait_interval);
++
++ return HRTIMER_RESTART;
++}
++
+ static irqreturn_t dw_spi_transfer_handler(struct dw_spi *dws)
+ {
+ u16 irq_status = dw_readl(dws, DW_SPI_ISR);
+@@ -246,7 +272,22 @@ static irqreturn_t dw_spi_transfer_handl
+ }
+ } else if (!dws->tx_len) {
+ dw_spi_mask_intr(dws, DW_SPI_INT_TXEI);
+- spi_finalize_current_transfer(dws->host);
++ if (dw_spi_ctlr_busy(dws)) {
++ ktime_t period = ns_to_ktime(DIV_ROUND_UP(NSEC_PER_SEC, dws->current_freq));
++
++ /*
++ * Make the initial wait an underestimate of how long the transfer
++ * should take, then poll rapidly to reduce the delay
++ */
++ hrtimer_start(&dws->hrtimer,
++ period * (8 * dws->n_bytes - 1),
++ HRTIMER_MODE_REL);
++ dws->idle_wait_retries = 10;
++ dws->idle_wait_interval = period;
++ } else {
++ spi_finalize_current_transfer(dws->host);
++ }
++ return IRQ_HANDLED;
+ }
+
+ /*
+@@ -255,9 +296,13 @@ static irqreturn_t dw_spi_transfer_handl
+ * have the TXE IRQ flood at the final stage of the transfer.
+ */
+ if (irq_status & DW_SPI_INT_TXEI) {
+- if (!dws->tx_len)
+- dw_spi_mask_intr(dws, DW_SPI_INT_TXEI);
+ dw_writer(dws);
++ if (!dws->tx_len) {
++ if (dws->rx_len)
++ dw_spi_mask_intr(dws, DW_SPI_INT_TXEI);
++ else
++ dw_writel(dws, DW_SPI_TXFTLR, 0);
++ }
+ }
+
+ return IRQ_HANDLED;
+@@ -428,7 +473,7 @@ static int dw_spi_poll_transfer(struct d
+ ret = dw_spi_check_status(dws, true);
+ if (ret)
+ return ret;
+- } while (dws->rx_len);
++ } while (dws->rx_len || dws->tx_len || dw_spi_ctlr_busy(dws));
+
+ return 0;
+ }
+@@ -652,11 +697,6 @@ static int dw_spi_write_then_read(struct
+ return 0;
+ }
+
+-static inline bool dw_spi_ctlr_busy(struct dw_spi *dws)
+-{
+- return dw_readl(dws, DW_SPI_SR) & DW_SPI_SR_BUSY;
+-}
+-
+ static int dw_spi_wait_mem_op_done(struct dw_spi *dws)
+ {
+ int retry = DW_SPI_WAIT_RETRIES;
+@@ -993,6 +1033,9 @@ int dw_spi_add_host(struct device *dev,
+ }
+ }
+
++ hrtimer_init(&dws->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
++ dws->hrtimer.function = dw_spi_hrtimer_handler;
++
+ ret = spi_register_controller(host);
+ if (ret) {
+ dev_err_probe(dev, ret, "problem registering spi host\n");
+@@ -1018,6 +1061,7 @@ void dw_spi_remove_host(struct dw_spi *d
+ {
+ dw_spi_debugfs_remove(dws);
+
++ hrtimer_cancel(&dws->hrtimer);
+ spi_unregister_controller(dws->host);
+
+ if (dws->dma_ops && dws->dma_ops->dma_exit)
+--- a/drivers/spi/spi-dw.h
++++ b/drivers/spi/spi-dw.h
+@@ -180,6 +180,9 @@ struct dw_spi {
+ u32 current_freq; /* frequency in hz */
+ u32 cur_rx_sample_dly;
+ u32 def_rx_sample_dly_ns;
++ struct hrtimer hrtimer;
++ ktime_t idle_wait_interval;
++ int idle_wait_retries;
+
+ /* Custom memory operations */
+ struct spi_controller_mem_ops mem_ops;
--- /dev/null
+From e9294823cf02068189a0e901223ed4991923c689 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Wed, 31 Jul 2024 10:55:19 +0100
+Subject: [PATCH 1202/1215] spi: dw: Clamp the minimum clock speed
+
+The DW SPI interface has a 16-bit clock divider, where the bottom bit
+of the divisor must be 0. Limit how low the clock speed can go to
+prevent the clock divider from being truncated, as that could lead to
+a much higher clock rate than requested.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ drivers/spi/spi-dw-core.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/spi/spi-dw-core.c
++++ b/drivers/spi/spi-dw-core.c
+@@ -397,7 +397,7 @@ void dw_spi_update_config(struct dw_spi
+ dw_writel(dws, DW_SPI_CTRLR1, cfg->ndf ? cfg->ndf - 1 : 0);
+
+ /* Note DW APB SSI clock divider doesn't support odd numbers */
+- clk_div = (DIV_ROUND_UP(dws->max_freq, cfg->freq) + 1) & 0xfffe;
++ clk_div = min(DIV_ROUND_UP(dws->max_freq, cfg->freq) + 1, 0xfffe) & 0xfffe;
+ speed_hz = dws->max_freq / clk_div;
+
+ if (dws->current_freq != speed_hz) {
--- /dev/null
+From 05e3687c6c973c30bf35f3b7f4a7589b5030a830 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Wed, 31 Jul 2024 13:19:26 +0100
+Subject: [PATCH 1203/1215] overlays: i2c-rtc: Correct bq32000 property name
+
+The DT property for the BQ32000 controlled by trickle-resistor-ohms
+parameter should be "trickle-resistor-ohms", not "abracon,tc-resistor".
+
+See: https://github.com/raspberrypi/linux/issues/6291
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ arch/arm/boot/dts/overlays/i2c-rtc-common.dtsi | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/overlays/i2c-rtc-common.dtsi
++++ b/arch/arm/boot/dts/overlays/i2c-rtc-common.dtsi
+@@ -354,7 +354,7 @@
+ <&rv3028>,"trickle-resistor-ohms:0",
+ <&rv3032>,"trickle-resistor-ohms:0",
+ <&rv1805>,"abracon,tc-resistor:0",
+- <&bq32000>,"abracon,tc-resistor:0";
++ <&bq32000>,"trickle-resistor-ohms:0";
+ trickle-voltage-mv = <&rv3032>,"trickle-voltage-millivolts:0";
+ backup-switchover-mode = <&rv3028>,"backup-switchover-mode:0";
+ wakeup-source = <&ds1339>,"wakeup-source?",
--- /dev/null
+From 16d0ee22d2c0b32cc67db73ce03263b740bba2a7 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Wed, 31 Jul 2024 15:02:47 +0100
+Subject: [PATCH 1204/1215] hwmon: (adt7410) Add DT compatible strings
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ drivers/hwmon/adt7410.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/drivers/hwmon/adt7410.c
++++ b/drivers/hwmon/adt7410.c
+@@ -94,10 +94,18 @@ static const struct i2c_device_id adt741
+ };
+ MODULE_DEVICE_TABLE(i2c, adt7410_ids);
+
++static const struct of_device_id adt7410_of_ids[] = {
++ { .compatible = "adi,adt7410" },
++ { .compatible = "adi,adt7420" },
++ {}
++};
++MODULE_DEVICE_TABLE(of, adt7410_of_ids);
++
+ static struct i2c_driver adt7410_driver = {
+ .class = I2C_CLASS_HWMON,
+ .driver = {
+ .name = "adt7410",
++ .of_match_table = adt7410_of_ids,
+ .pm = pm_sleep_ptr(&adt7x10_dev_pm_ops),
+ },
+ .probe = adt7410_i2c_probe,
--- /dev/null
+From a4bf61fad9fe102514243ed263c458b053c87681 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Fri, 2 Aug 2024 11:29:03 +0100
+Subject: [PATCH 1205/1215] fixup! pinctrl: bcm2712 pinctrl/pinconf driver
+
+Fix cut-and-paste error spotted during upstreaming process.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ drivers/pinctrl/bcm/pinctrl-bcm2712.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/pinctrl/bcm/pinctrl-bcm2712.c
++++ b/drivers/pinctrl/bcm/pinctrl-bcm2712.c
+@@ -1029,7 +1029,7 @@ static int bcm2712_pinconf_get(struct pi
+
+ *config = pinconf_to_config_packed(param, arg);
+
+- return -ENOTSUPP;
++ return 0;
+ }
+
+ static int bcm2712_pinconf_set(struct pinctrl_dev *pctldev,
--- /dev/null
+From e94e761305fa2281718adcf625d78f3cf662e12d Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Thu, 1 Aug 2024 18:12:50 +0100
+Subject: [PATCH 1206/1215] dtoverlays: Add overlay for HD44780 via I2C PCF8574
+ backpack
+
+Many HD44780 LCD displays are connected via very common I2C
+GPIO expander.
+We have an overlay for connecting the displays directly to GPIOs,
+but not one for it connected via a backpack. Add such an overlay.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 27 +++++++++
+ .../dts/overlays/hd44780-i2c-lcd-overlay.dts | 57 +++++++++++++++++++
+ 3 files changed, 85 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/hd44780-i2c-lcd-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -82,6 +82,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ gpio-no-irq.dtbo \
+ gpio-poweroff.dtbo \
+ gpio-shutdown.dtbo \
++ hd44780-i2c-lcd.dtbo \
+ hd44780-lcd.dtbo \
+ hdmi-backlight-hwhack-gpio.dtbo \
+ hifiberry-amp.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -1705,6 +1705,33 @@ Params: gpio_pin GPIO pin
+ (default 100)
+
+
++Name: hd44780-i2c-lcd
++Info: Configures an HD44780 compatible LCD display connected via a PCF8574 as
++ is often found as a backpack interface for these displays.
++Load: dtoverlay=hd44780-i2c-lcd,<param>=<val>
++Params: addr I2C address of PCF8574
++ pin_d4 GPIO pin for data pin D4 (default 4)
++
++ pin_d5 GPIO pin for data pin D5 (default 5)
++
++ pin_d6 GPIO pin for data pin D6 (default 6)
++
++ pin_d7 GPIO pin for data pin D7 (default 7)
++
++ pin_en GPIO pin for "Enable" (default 2)
++
++ pin_rs GPIO pin for "Register Select" (default 0)
++
++ pin_rw GPIO pin for R/W select (default 1)
++
++ pin_bl GPIO pin for enabling/disabling the display
++ backlight. (default 3)
++
++ display_height Height of the display in characters (default 2)
++
++ display_width Width of the display in characters (default 16)
++
++
+ Name: hd44780-lcd
+ Info: Configures an HD44780 compatible LCD display. Uses 4 gpio pins for
+ data, 2 gpio pins for enable and register select and 1 optional pin
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/hd44780-i2c-lcd-overlay.dts
+@@ -0,0 +1,57 @@
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2835";
++
++ fragment@0 {
++ target = <&i2c_arm>;
++ __overlay__ {
++ status = "okay";
++
++ pcf857x: pcf857x@27 {
++ compatible = "nxp,pcf8574";
++ reg = <0x27>;
++ gpio-controller;
++ #gpio-cells = <2>;
++ status = "okay";
++ };
++ };
++ };
++
++ fragment@1 {
++ target-path = "/";
++ __overlay__ {
++ lcd_screen: auxdisplay {
++ compatible = "hit,hd44780";
++
++ data-gpios = <&pcf857x 4 0>,
++ <&pcf857x 5 0>,
++ <&pcf857x 6 0>,
++ <&pcf857x 7 0>;
++ enable-gpios = <&pcf857x 2 0>;
++ rs-gpios = <&pcf857x 0 0>;
++ rw-gpios = <&pcf857x 1 0>;
++ backlight-gpios = <&pcf857x 3 0>;
++
++ display-width-chars = <16>;
++ display-height-chars = <2>;
++ };
++ };
++ };
++
++ __overrides__ {
++ pin_d4 = <&lcd_screen>,"data-gpios:4";
++ pin_d5 = <&lcd_screen>,"data-gpios:16";
++ pin_d6 = <&lcd_screen>,"data-gpios:28";
++ pin_d7 = <&lcd_screen>,"data-gpios:40";
++ pin_en = <&lcd_screen>,"enable-gpios:4";
++ pin_rs = <&lcd_screen>,"rs-gpios:4";
++ pin_rw = <&lcd_screen>,"rw-gpios:4";
++ pin_bl = <&lcd_screen>,"backlight-gpios:4";
++ display_height = <&lcd_screen>,"display-height-chars:0";
++ display_width = <&lcd_screen>,"display-width-chars:0";
++ addr = <&pcf857x>,"reg:0";
++ };
++
++};
--- /dev/null
+From 3c319a466a1c718f66c471a9d5ec60de6de44612 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Fri, 2 Aug 2024 10:41:28 +0100
+Subject: [PATCH 1207/1215] dtoverlays: Document display_[width|height] on
+ hd44780-lcd overlay
+
+The default values defining a 16x2 display weren't documented,
+so add them.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ arch/arm/boot/dts/overlays/README | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -1752,9 +1752,9 @@ Params: pin_d4 GPIO pin
+ pin_bl Optional pin for enabling/disabling the
+ display backlight. (default disabled)
+
+- display_height Height of the display in characters
++ display_height Height of the display in characters (default 2)
+
+- display_width Width of the display in characters
++ display_width Width of the display in characters (default 16)
+
+
+ Name: hdmi-backlight-hwhack-gpio
--- /dev/null
+From 216df57950849f905c398904e7d6cbdf278b5717 Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <jonathan@raspberrypi.com>
+Date: Mon, 5 Aug 2024 11:28:36 +0100
+Subject: [PATCH 1208/1215] DTS: bcm2712: enable SD slot CQE by default on Pi 5
+
+The corresponding driver implementation has seen sufficient testing,
+so enable by default. Retain the dtparam so it can be turned off for test.
+
+Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
+---
+ arch/arm/boot/dts/overlays/README | 6 +++---
+ arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts | 1 +
+ 2 files changed, 4 insertions(+), 3 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -378,9 +378,9 @@ Params:
+ non-lite SKU of CM4).
+ (default "on")
+
+- sd_cqe Use to enable Command Queueing on the SD
+- interface for faster Class A2 card performance
+- (Pi 5 only, default "off")
++ sd_cqe Set to "off" to disable Command Queueing if you
++ have an incompatible Class A2 SD card
++ (Pi 5 only, default "on")
+
+ sd_overclock Clock (in MHz) to use when the MMC framework
+ requests 50MHz
+--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts
++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts
+@@ -363,6 +363,7 @@ dpi_16bit_gpio2: &rp1_dpi_16bit_g
+ sd-uhs-sdr50;
+ sd-uhs-ddr50;
+ sd-uhs-sdr104;
++ supports-cqe;
+ cd-gpios = <&gio_aon 5 GPIO_ACTIVE_LOW>;
+ //no-1-8-v;
+ status = "okay";
--- /dev/null
+From 53b9d9bbb57e292c6b332a2fb9899003586e17ca Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Thu, 2 May 2024 16:17:02 +0100
+Subject: [PATCH 1211/1215] gpiolib: Override gpiochip numbers with DT aliases
+
+In the same way that other subsystems support the setting of device
+id numbers from Device Tree aliases, allow gpiochip numbers to be
+derived from "gpiochip<n>" aliases.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ drivers/gpio/gpiolib.c | 13 ++++++++++++-
+ 1 file changed, 12 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpio/gpiolib.c
++++ b/drivers/gpio/gpiolib.c
+@@ -110,6 +110,7 @@ static int gpiochip_irqchip_init_valid_m
+ static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gc);
+
+ static bool gpiolib_initialized;
++static int first_dynamic_gpiochip_num = -1;
+
+ static inline void desc_set_label(struct gpio_desc *d, const char *label)
+ {
+@@ -745,6 +746,7 @@ int gpiochip_add_data_with_key(struct gp
+ unsigned int i;
+ int base = 0;
+ int ret = 0;
++ int id;
+
+ /*
+ * First: allocate and populate the internal stat container, and
+@@ -769,7 +771,16 @@ int gpiochip_add_data_with_key(struct gp
+ else if (gc->parent)
+ device_set_node(&gdev->dev, dev_fwnode(gc->parent));
+
+- gdev->id = ida_alloc(&gpio_ida, GFP_KERNEL);
++ if (first_dynamic_gpiochip_num < 0) {
++ id = of_alias_get_highest_id("gpiochip");
++ first_dynamic_gpiochip_num = (id >= 0) ? (id + 1) : 0;
++ }
++
++ id = of_alias_get_id(gdev->dev.of_node, "gpiochip");
++ if (id < 0)
++ id = first_dynamic_gpiochip_num;
++
++ gdev->id = ida_alloc_range(&gpio_ida, id, ~0, GFP_KERNEL);
+ if (gdev->id < 0) {
+ ret = gdev->id;
+ goto err_free_gdev;
--- /dev/null
+From 1162316fd26eeb4193b23fcc1bb332f42938aa70 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Thu, 2 May 2024 16:58:59 +0100
+Subject: [PATCH 1212/1215] dts: bcm2712-rpi: Add gpiochip0 alias
+
+Add a gpiochip0 aliase pointing to the rp1 GPIO node, making it appear
+as gpiochip0.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi
++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi
+@@ -112,6 +112,7 @@
+ gpio2 = &gio_aon;
+ gpio3 = &pinctrl;
+ gpio4 = &pinctrl_aon;
++ gpiochip0 = &gpio;
+ i2c = &i2c_arm;
+ i2c0 = &i2c0;
+ i2c1 = &i2c1;
--- /dev/null
+From 70c640ce992234aacba5a717f3fb47319f451431 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Thu, 2 May 2024 17:40:25 +0100
+Subject: [PATCH 1213/1215] dts: bcm2712-rpi: The SoC gpiochips start at 10
+
+Make the BCM2712's onboard GPIOs start at gpiochip10, marking them out
+as system resources and preventing accidental use by existing Pi 5
+code.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi
++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi
+@@ -113,6 +113,7 @@
+ gpio3 = &pinctrl;
+ gpio4 = &pinctrl_aon;
+ gpiochip0 = &gpio;
++ gpiochip10 = &gio;
+ i2c = &i2c_arm;
+ i2c0 = &i2c0;
+ i2c1 = &i2c1;