bcm27xx: update to latest RPi patches
authorÁlvaro Fernández Rojas <noltari@gmail.com>
Wed, 3 Jul 2024 18:30:59 +0000 (20:30 +0200)
committerÁlvaro Fernández Rojas <noltari@gmail.com>
Tue, 6 Aug 2024 16:38:00 +0000 (18:38 +0200)
The patches were generated from the RPi repo with the following command:
git format-patch v6.6.44..rpi-6.6.y

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
59 files changed:
target/linux/bcm27xx/config-6.6
target/linux/bcm27xx/patches-6.6/950-0714-spi-dw-dma-Get-the-last-DMA-scoop-out-of-the-FIFO.patch [deleted file]
target/linux/bcm27xx/patches-6.6/950-1146-drivers-dwc_otg-use-C11-style-variable-array-declara.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1147-media-uapi-pixfmt-luma-Document-MIPI-CSI-2-packing.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1148-media-uapi-Add-a-pixel-format-for-BGR48-and-RGB48.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1149-media-uapi-Add-Raspberry-Pi-PiSP-Back-End-uAPI.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1150-media-uapi-Document-meta-pixel-format-for-PiSP-BE-co.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1151-media-uapi-Document-PiSP-Compressed-RAW-Bayer-format.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1152-media-dt-bindings-Add-bindings-for-Raspberry-Pi-PiSP.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1153-media-admin-guide-Document-the-Raspberry-Pi-PiSP-BE.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1154-media-pisp-be-Backport-the-mainline-PiSP-BE-driver.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1155-media-uapi-pisp_be_config-Drop-BIT-from-uAPI.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1156-media-uapi-pisp_common-Add-32-bpp-format-test.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1157-media-uapi-Capitalize-all-macros.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1158-media-uapi-pisp_be_config-Re-sort-pisp_be_tiles_conf.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1159-media-uapi-pisp_be_config-Add-extra-config-fields.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1160-media-pisp_be-Re-introduce-multi-context-support.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1161-media-pisp_be-Re-introduce-video-node-offset.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1163-dts-Make-camN_reg-and-camN_reg_gpio-overrides-generi.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1164-spi-dt-bindings-Add-RPI-RP2040-GPIO-Bridge.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1165-spi-Add-a-driver-for-the-RPI-RP2040-GPIO-bridge.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1166-dmaengine-dw-axi-dmac-Honour-snps-block-size.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1167-mmc-restrict-posted-write-counts-for-SD-cards-in-CQ-.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1168-fixup-mmc-restrict-posted-write-counts-for-SD-cards-.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1169-mmc-brcmstb-don-t-squash-card-busy-detection-on-bcm2.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1172-Revert-Update-DAC8x-to-support-384khz-6187.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1176-dt-bindings-clk-rp1-Add-clocks-representing-MIPI-DSI.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1177-clk-clk-rp1-Add-varsrc-clocks-to-represent-MIPI-byte.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1178-dts-rp1-DSI-drivers-to-use-newly-defined-MIPI-byte-s.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1179-drm-rp1-rp1-dsi-Switch-to-PLL_SYS-source-for-DPI-whe.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1180-arm64-dts-Move-bcm2712-and-rp1-here.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1181-arm64-dts-Add-cm5l-files.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1182-dts-bcm2712-Dedup-the-aliases-and-overrides.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1183-arm64-dts-Give-cm5l-its-own-model-name.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1185-pinctrl-rp1-jump-through-hoops-to-avoid-PCIe-latency.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1186-staging-bcm2835-codec-Disable-HEADER_ON_OPEN-for-vid.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1188-staging-bcm2835-codec-Add-support-for-H264-level-5.0.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1189-spi-dw-Save-bandwidth-with-the-TMOD_TO-feature.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1190-spi-dw-Save-bandwidth-with-the-TMOD_RO-feature.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1191-spi-dw-don-t-immediately-kill-DMA-transfers-if-an-er.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1192-dts-rp1-hobble-DMA-AXI-burst-lengths.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1193-drivers-dw-axi-dmac-make-more-sensible-choices-about.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1195-tty-serial-pl011-restrict-RX-burst-FIFO-threshold.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1196-DT-bindings-add-a-dma-maxburst-property-to-snps-desi.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1197-sound-soc-dwc-i2s-choose-FIFO-thresholds-based-on-DM.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1198-dts-rp1-restrict-i2s-burst-lengths-to-4.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1199-drm-vc4-Disable-the-2pixel-clock-odd-timings-workaro.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1200-ARM-dts-bcm2712-Fix-invalid-polling-delay-passive-se.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1201-spi-dw-Fix-non-DMA-transmit-only-transfers.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1202-spi-dw-Clamp-the-minimum-clock-speed.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1203-overlays-i2c-rtc-Correct-bq32000-property-name.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1204-hwmon-adt7410-Add-DT-compatible-strings.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1205-fixup-pinctrl-bcm2712-pinctrl-pinconf-driver.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1206-dtoverlays-Add-overlay-for-HD44780-via-I2C-PCF8574-b.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1207-dtoverlays-Document-display_-width-height-on-hd44780.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1208-DTS-bcm2712-enable-SD-slot-CQE-by-default-on-Pi-5.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1211-gpiolib-Override-gpiochip-numbers-with-DT-aliases.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1212-dts-bcm2712-rpi-Add-gpiochip0-alias.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1213-dts-bcm2712-rpi-The-SoC-gpiochips-start-at-10.patch [new file with mode: 0644]

index 55f5523ab547a970851ed638a870f22ebedca09a..b44aa9f8a9b35d4222fd4f1269b98b01c214e2c0 100644 (file)
@@ -23,6 +23,7 @@
 # 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
diff --git a/target/linux/bcm27xx/patches-6.6/950-0714-spi-dw-dma-Get-the-last-DMA-scoop-out-of-the-FIFO.patch b/target/linux/bcm27xx/patches-6.6/950-0714-spi-dw-dma-Get-the-last-DMA-scoop-out-of-the-FIFO.patch
deleted file mode 100644 (file)
index 2a2ba5d..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-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
diff --git a/target/linux/bcm27xx/patches-6.6/950-1146-drivers-dwc_otg-use-C11-style-variable-array-declara.patch b/target/linux/bcm27xx/patches-6.6/950-1146-drivers-dwc_otg-use-C11-style-variable-array-declara.patch
new file mode 100644 (file)
index 0000000..b5f117f
--- /dev/null
@@ -0,0 +1,260 @@
+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;
diff --git a/target/linux/bcm27xx/patches-6.6/950-1147-media-uapi-pixfmt-luma-Document-MIPI-CSI-2-packing.patch b/target/linux/bcm27xx/patches-6.6/950-1147-media-uapi-pixfmt-luma-Document-MIPI-CSI-2-packing.patch
new file mode 100644 (file)
index 0000000..14d0a79
--- /dev/null
@@ -0,0 +1,27 @@
+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.
diff --git a/target/linux/bcm27xx/patches-6.6/950-1148-media-uapi-Add-a-pixel-format-for-BGR48-and-RGB48.patch b/target/linux/bcm27xx/patches-6.6/950-1148-media-uapi-Add-a-pixel-format-for-BGR48-and-RGB48.patch
new file mode 100644 (file)
index 0000000..2f45904
--- /dev/null
@@ -0,0 +1,101 @@
+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) */
diff --git a/target/linux/bcm27xx/patches-6.6/950-1149-media-uapi-Add-Raspberry-Pi-PiSP-Back-End-uAPI.patch b/target/linux/bcm27xx/patches-6.6/950-1149-media-uapi-Add-Raspberry-Pi-PiSP-Back-End-uAPI.patch
new file mode 100644 (file)
index 0000000..a59bcb1
--- /dev/null
@@ -0,0 +1,1171 @@
+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_ */
diff --git a/target/linux/bcm27xx/patches-6.6/950-1150-media-uapi-Document-meta-pixel-format-for-PiSP-BE-co.patch b/target/linux/bcm27xx/patches-6.6/950-1150-media-uapi-Document-meta-pixel-format-for-PiSP-BE-co.patch
new file mode 100644 (file)
index 0000000..0ee62a7
--- /dev/null
@@ -0,0 +1,86 @@
+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
diff --git a/target/linux/bcm27xx/patches-6.6/950-1151-media-uapi-Document-PiSP-Compressed-RAW-Bayer-format.patch b/target/linux/bcm27xx/patches-6.6/950-1151-media-uapi-Document-PiSP-Compressed-RAW-Bayer-format.patch
new file mode 100644 (file)
index 0000000..aa4b003
--- /dev/null
@@ -0,0 +1,106 @@
+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>`_.
diff --git a/target/linux/bcm27xx/patches-6.6/950-1152-media-dt-bindings-Add-bindings-for-Raspberry-Pi-PiSP.patch b/target/linux/bcm27xx/patches-6.6/950-1152-media-dt-bindings-Add-bindings-for-Raspberry-Pi-PiSP.patch
new file mode 100644 (file)
index 0000000..30c5cb3
--- /dev/null
@@ -0,0 +1,97 @@
+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
diff --git a/target/linux/bcm27xx/patches-6.6/950-1153-media-admin-guide-Document-the-Raspberry-Pi-PiSP-BE.patch b/target/linux/bcm27xx/patches-6.6/950-1153-media-admin-guide-Document-the-Raspberry-Pi-PiSP-BE.patch
new file mode 100644 (file)
index 0000000..f443cc7
--- /dev/null
@@ -0,0 +1,162 @@
+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
diff --git a/target/linux/bcm27xx/patches-6.6/950-1154-media-pisp-be-Backport-the-mainline-PiSP-BE-driver.patch b/target/linux/bcm27xx/patches-6.6/950-1154-media-pisp-be-Backport-the-mainline-PiSP-BE-driver.patch
new file mode 100644 (file)
index 0000000..a012399
--- /dev/null
@@ -0,0 +1,2927 @@
+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[] = {
diff --git a/target/linux/bcm27xx/patches-6.6/950-1155-media-uapi-pisp_be_config-Drop-BIT-from-uAPI.patch b/target/linux/bcm27xx/patches-6.6/950-1155-media-uapi-pisp_be_config-Drop-BIT-from-uAPI.patch
new file mode 100644 (file)
index 0000000..f59c02c
--- /dev/null
@@ -0,0 +1,29 @@
+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;
diff --git a/target/linux/bcm27xx/patches-6.6/950-1156-media-uapi-pisp_common-Add-32-bpp-format-test.patch b/target/linux/bcm27xx/patches-6.6/950-1156-media-uapi-pisp_common-Add-32-bpp-format-test.patch
new file mode 100644 (file)
index 0000000..0cb94fe
--- /dev/null
@@ -0,0 +1,32 @@
+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))
diff --git a/target/linux/bcm27xx/patches-6.6/950-1157-media-uapi-Capitalize-all-macros.patch b/target/linux/bcm27xx/patches-6.6/950-1157-media-uapi-Capitalize-all-macros.patch
new file mode 100644 (file)
index 0000000..fac2ccf
--- /dev/null
@@ -0,0 +1,89 @@
+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))
diff --git a/target/linux/bcm27xx/patches-6.6/950-1158-media-uapi-pisp_be_config-Re-sort-pisp_be_tiles_conf.patch b/target/linux/bcm27xx/patches-6.6/950-1158-media-uapi-pisp_be_config-Re-sort-pisp_be_tiles_conf.patch
new file mode 100644 (file)
index 0000000..49ff9d7
--- /dev/null
@@ -0,0 +1,30 @@
+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_ */
diff --git a/target/linux/bcm27xx/patches-6.6/950-1159-media-uapi-pisp_be_config-Add-extra-config-fields.patch b/target/linux/bcm27xx/patches-6.6/950-1159-media-uapi-pisp_be_config-Add-extra-config-fields.patch
new file mode 100644 (file)
index 0000000..d18d12e
--- /dev/null
@@ -0,0 +1,82 @@
+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));
+ /**
diff --git a/target/linux/bcm27xx/patches-6.6/950-1160-media-pisp_be-Re-introduce-multi-context-support.patch b/target/linux/bcm27xx/patches-6.6/950-1160-media-pisp_be-Re-introduce-multi-context-support.patch
new file mode 100644 (file)
index 0000000..ad667a1
--- /dev/null
@@ -0,0 +1,886 @@
+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);
diff --git a/target/linux/bcm27xx/patches-6.6/950-1161-media-pisp_be-Re-introduce-video-node-offset.patch b/target/linux/bcm27xx/patches-6.6/950-1161-media-pisp_be-Re-introduce-video-node-offset.patch
new file mode 100644 (file)
index 0000000..0586f5c
--- /dev/null
@@ -0,0 +1,36 @@
+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",
diff --git a/target/linux/bcm27xx/patches-6.6/950-1163-dts-Make-camN_reg-and-camN_reg_gpio-overrides-generi.patch b/target/linux/bcm27xx/patches-6.6/950-1163-dts-Make-camN_reg-and-camN_reg_gpio-overrides-generi.patch
new file mode 100644 (file)
index 0000000..38c1d3b
--- /dev/null
@@ -0,0 +1,158 @@
+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.
diff --git a/target/linux/bcm27xx/patches-6.6/950-1164-spi-dt-bindings-Add-RPI-RP2040-GPIO-Bridge.patch b/target/linux/bcm27xx/patches-6.6/950-1164-spi-dt-bindings-Add-RPI-RP2040-GPIO-Bridge.patch
new file mode 100644 (file)
index 0000000..487e508
--- /dev/null
@@ -0,0 +1,108 @@
+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
diff --git a/target/linux/bcm27xx/patches-6.6/950-1165-spi-Add-a-driver-for-the-RPI-RP2040-GPIO-bridge.patch b/target/linux/bcm27xx/patches-6.6/950-1165-spi-Add-a-driver-for-the-RPI-RP2040-GPIO-bridge.patch
new file mode 100644 (file)
index 0000000..68e2ef6
--- /dev/null
@@ -0,0 +1,1288 @@
+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");
diff --git a/target/linux/bcm27xx/patches-6.6/950-1166-dmaengine-dw-axi-dmac-Honour-snps-block-size.patch b/target/linux/bcm27xx/patches-6.6/950-1166-dmaengine-dw-axi-dmac-Honour-snps-block-size.patch
new file mode 100644 (file)
index 0000000..85b1cf6
--- /dev/null
@@ -0,0 +1,52 @@
+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);
diff --git a/target/linux/bcm27xx/patches-6.6/950-1167-mmc-restrict-posted-write-counts-for-SD-cards-in-CQ-.patch b/target/linux/bcm27xx/patches-6.6/950-1167-mmc-restrict-posted-write-counts-for-SD-cards-in-CQ-.patch
new file mode 100644 (file)
index 0000000..2ba4949
--- /dev/null
@@ -0,0 +1,157 @@
+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)
diff --git a/target/linux/bcm27xx/patches-6.6/950-1168-fixup-mmc-restrict-posted-write-counts-for-SD-cards-.patch b/target/linux/bcm27xx/patches-6.6/950-1168-fixup-mmc-restrict-posted-write-counts-for-SD-cards-.patch
new file mode 100644 (file)
index 0000000..4f1d02c
--- /dev/null
@@ -0,0 +1,70 @@
+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));
+       }
diff --git a/target/linux/bcm27xx/patches-6.6/950-1169-mmc-brcmstb-don-t-squash-card-busy-detection-on-bcm2.patch b/target/linux/bcm27xx/patches-6.6/950-1169-mmc-brcmstb-don-t-squash-card-busy-detection-on-bcm2.patch
new file mode 100644 (file)
index 0000000..0d4d6cb
--- /dev/null
@@ -0,0 +1,28 @@
+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,
diff --git a/target/linux/bcm27xx/patches-6.6/950-1172-Revert-Update-DAC8x-to-support-384khz-6187.patch b/target/linux/bcm27xx/patches-6.6/950-1172-Revert-Update-DAC8x-to-support-384khz-6187.patch
new file mode 100644 (file)
index 0000000..1923b7a
--- /dev/null
@@ -0,0 +1,25 @@
+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;
+ }
diff --git a/target/linux/bcm27xx/patches-6.6/950-1176-dt-bindings-clk-rp1-Add-clocks-representing-MIPI-DSI.patch b/target/linux/bcm27xx/patches-6.6/950-1176-dt-bindings-clk-rp1-Add-clocks-representing-MIPI-DSI.patch
new file mode 100644 (file)
index 0000000..af740bd
--- /dev/null
@@ -0,0 +1,25 @@
+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
diff --git a/target/linux/bcm27xx/patches-6.6/950-1177-clk-clk-rp1-Add-varsrc-clocks-to-represent-MIPI-byte.patch b/target/linux/bcm27xx/patches-6.6/950-1177-clk-clk-rp1-Add-varsrc-clocks-to-represent-MIPI-byte.patch
new file mode 100644 (file)
index 0000000..564ef84
--- /dev/null
@@ -0,0 +1,132 @@
+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)];
diff --git a/target/linux/bcm27xx/patches-6.6/950-1178-dts-rp1-DSI-drivers-to-use-newly-defined-MIPI-byte-s.patch b/target/linux/bcm27xx/patches-6.6/950-1178-dts-rp1-DSI-drivers-to-use-newly-defined-MIPI-byte-s.patch
new file mode 100644 (file)
index 0000000..7e6032d
--- /dev/null
@@ -0,0 +1,92 @@
+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
diff --git a/target/linux/bcm27xx/patches-6.6/950-1179-drm-rp1-rp1-dsi-Switch-to-PLL_SYS-source-for-DPI-whe.patch b/target/linux/bcm27xx/patches-6.6/950-1179-drm-rp1-rp1-dsi-Switch-to-PLL_SYS-source-for-DPI-whe.patch
new file mode 100644 (file)
index 0000000..a80af98
--- /dev/null
@@ -0,0 +1,313 @@
+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);
diff --git a/target/linux/bcm27xx/patches-6.6/950-1180-arm64-dts-Move-bcm2712-and-rp1-here.patch b/target/linux/bcm27xx/patches-6.6/950-1180-arm64-dts-Move-bcm2712-and-rp1-here.patch
new file mode 100644 (file)
index 0000000..2856bb5
--- /dev/null
@@ -0,0 +1,9749 @@
+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;
++      };
++};
diff --git a/target/linux/bcm27xx/patches-6.6/950-1181-arm64-dts-Add-cm5l-files.patch b/target/linux/bcm27xx/patches-6.6/950-1181-arm64-dts-Add-cm5l-files.patch
new file mode 100644 (file)
index 0000000..4f05443
--- /dev/null
@@ -0,0 +1,92 @@
+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;
++};
diff --git a/target/linux/bcm27xx/patches-6.6/950-1182-dts-bcm2712-Dedup-the-aliases-and-overrides.patch b/target/linux/bcm27xx/patches-6.6/950-1182-dts-bcm2712-Dedup-the-aliases-and-overrides.patch
new file mode 100644 (file)
index 0000000..6cffbdd
--- /dev/null
@@ -0,0 +1,408 @@
+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>;
+-
+       };
+ };
diff --git a/target/linux/bcm27xx/patches-6.6/950-1183-arm64-dts-Give-cm5l-its-own-model-name.patch b/target/linux/bcm27xx/patches-6.6/950-1183-arm64-dts-Give-cm5l-its-own-model-name.patch
new file mode 100644 (file)
index 0000000..72279e1
--- /dev/null
@@ -0,0 +1,24 @@
+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";
+       };
diff --git a/target/linux/bcm27xx/patches-6.6/950-1185-pinctrl-rp1-jump-through-hoops-to-avoid-PCIe-latency.patch b/target/linux/bcm27xx/patches-6.6/950-1185-pinctrl-rp1-jump-through-hoops-to-avoid-PCIe-latency.patch
new file mode 100644 (file)
index 0000000..fecfb7a
--- /dev/null
@@ -0,0 +1,288 @@
+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,
diff --git a/target/linux/bcm27xx/patches-6.6/950-1186-staging-bcm2835-codec-Disable-HEADER_ON_OPEN-for-vid.patch b/target/linux/bcm27xx/patches-6.6/950-1186-staging-bcm2835-codec-Disable-HEADER_ON_OPEN-for-vid.patch
new file mode 100644 (file)
index 0000000..a8fbeaf
--- /dev/null
@@ -0,0 +1,36 @@
+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
+                                             &params,
+                                             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,
diff --git a/target/linux/bcm27xx/patches-6.6/950-1188-staging-bcm2835-codec-Add-support-for-H264-level-5.0.patch b/target/linux/bcm27xx/patches-6.6/950-1188-staging-bcm2835-codec-Add-support-for-H264-level-5.0.patch
new file mode 100644 (file)
index 0000000..f3c53ad
--- /dev/null
@@ -0,0 +1,36 @@
+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,
diff --git a/target/linux/bcm27xx/patches-6.6/950-1189-spi-dw-Save-bandwidth-with-the-TMOD_TO-feature.patch b/target/linux/bcm27xx/patches-6.6/950-1189-spi-dw-Save-bandwidth-with-the-TMOD_TO-feature.patch
new file mode 100644 (file)
index 0000000..66ff22e
--- /dev/null
@@ -0,0 +1,66 @@
+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();
diff --git a/target/linux/bcm27xx/patches-6.6/950-1190-spi-dw-Save-bandwidth-with-the-TMOD_RO-feature.patch b/target/linux/bcm27xx/patches-6.6/950-1190-spi-dw-Save-bandwidth-with-the-TMOD_RO-feature.patch
new file mode 100644 (file)
index 0000000..7791b99
--- /dev/null
@@ -0,0 +1,186 @@
+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);
diff --git a/target/linux/bcm27xx/patches-6.6/950-1191-spi-dw-don-t-immediately-kill-DMA-transfers-if-an-er.patch b/target/linux/bcm27xx/patches-6.6/950-1191-spi-dw-don-t-immediately-kill-DMA-transfers-if-an-er.patch
new file mode 100644 (file)
index 0000000..4540020
--- /dev/null
@@ -0,0 +1,41 @@
+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;
+       }
diff --git a/target/linux/bcm27xx/patches-6.6/950-1192-dts-rp1-hobble-DMA-AXI-burst-lengths.patch b/target/linux/bcm27xx/patches-6.6/950-1192-dts-rp1-hobble-DMA-AXI-burst-lengths.patch
new file mode 100644 (file)
index 0000000..9cfdefe
--- /dev/null
@@ -0,0 +1,35 @@
+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";
+               };
diff --git a/target/linux/bcm27xx/patches-6.6/950-1193-drivers-dw-axi-dmac-make-more-sensible-choices-about.patch b/target/linux/bcm27xx/patches-6.6/950-1193-drivers-dw-axi-dmac-make-more-sensible-choices-about.patch
new file mode 100644 (file)
index 0000000..d336532
--- /dev/null
@@ -0,0 +1,124 @@
+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:
diff --git a/target/linux/bcm27xx/patches-6.6/950-1195-tty-serial-pl011-restrict-RX-burst-FIFO-threshold.patch b/target/linux/bcm27xx/patches-6.6/950-1195-tty-serial-pl011-restrict-RX-burst-FIFO-threshold.patch
new file mode 100644 (file)
index 0000000..62731ae
--- /dev/null
@@ -0,0 +1,30 @@
+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;
diff --git a/target/linux/bcm27xx/patches-6.6/950-1196-DT-bindings-add-a-dma-maxburst-property-to-snps-desi.patch b/target/linux/bcm27xx/patches-6.6/950-1196-DT-bindings-add-a-dma-maxburst-property-to-snps-desi.patch
new file mode 100644 (file)
index 0000000..0d0afc2
--- /dev/null
@@ -0,0 +1,27 @@
+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
diff --git a/target/linux/bcm27xx/patches-6.6/950-1197-sound-soc-dwc-i2s-choose-FIFO-thresholds-based-on-DM.patch b/target/linux/bcm27xx/patches-6.6/950-1197-sound-soc-dwc-i2s-choose-FIFO-thresholds-based-on-DM.patch
new file mode 100644 (file)
index 0000000..d0e3bc1
--- /dev/null
@@ -0,0 +1,99 @@
+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 */
diff --git a/target/linux/bcm27xx/patches-6.6/950-1198-dts-rp1-restrict-i2s-burst-lengths-to-4.patch b/target/linux/bcm27xx/patches-6.6/950-1198-dts-rp1-restrict-i2s-burst-lengths-to-4.patch
new file mode 100644 (file)
index 0000000..30b8a9f
--- /dev/null
@@ -0,0 +1,30 @@
+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";
+               };
diff --git a/target/linux/bcm27xx/patches-6.6/950-1199-drm-vc4-Disable-the-2pixel-clock-odd-timings-workaro.patch b/target/linux/bcm27xx/patches-6.6/950-1199-drm-vc4-Disable-the-2pixel-clock-odd-timings-workaro.patch
new file mode 100644 (file)
index 0000000..4c429e2
--- /dev/null
@@ -0,0 +1,204 @@
+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
diff --git a/target/linux/bcm27xx/patches-6.6/950-1200-ARM-dts-bcm2712-Fix-invalid-polling-delay-passive-se.patch b/target/linux/bcm27xx/patches-6.6/950-1200-ARM-dts-bcm2712-Fix-invalid-polling-delay-passive-se.patch
new file mode 100644 (file)
index 0000000..8a7d86d
--- /dev/null
@@ -0,0 +1,26 @@
+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>;
diff --git a/target/linux/bcm27xx/patches-6.6/950-1201-spi-dw-Fix-non-DMA-transmit-only-transfers.patch b/target/linux/bcm27xx/patches-6.6/950-1201-spi-dw-Fix-non-DMA-transmit-only-transfers.patch
new file mode 100644 (file)
index 0000000..6545c09
--- /dev/null
@@ -0,0 +1,143 @@
+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;
diff --git a/target/linux/bcm27xx/patches-6.6/950-1202-spi-dw-Clamp-the-minimum-clock-speed.patch b/target/linux/bcm27xx/patches-6.6/950-1202-spi-dw-Clamp-the-minimum-clock-speed.patch
new file mode 100644 (file)
index 0000000..585173a
--- /dev/null
@@ -0,0 +1,26 @@
+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) {
diff --git a/target/linux/bcm27xx/patches-6.6/950-1203-overlays-i2c-rtc-Correct-bq32000-property-name.patch b/target/linux/bcm27xx/patches-6.6/950-1203-overlays-i2c-rtc-Correct-bq32000-property-name.patch
new file mode 100644 (file)
index 0000000..afd6c41
--- /dev/null
@@ -0,0 +1,26 @@
+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?",
diff --git a/target/linux/bcm27xx/patches-6.6/950-1204-hwmon-adt7410-Add-DT-compatible-strings.patch b/target/linux/bcm27xx/patches-6.6/950-1204-hwmon-adt7410-Add-DT-compatible-strings.patch
new file mode 100644 (file)
index 0000000..cc54c62
--- /dev/null
@@ -0,0 +1,31 @@
+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,
diff --git a/target/linux/bcm27xx/patches-6.6/950-1205-fixup-pinctrl-bcm2712-pinctrl-pinconf-driver.patch b/target/linux/bcm27xx/patches-6.6/950-1205-fixup-pinctrl-bcm2712-pinctrl-pinconf-driver.patch
new file mode 100644 (file)
index 0000000..fb786e1
--- /dev/null
@@ -0,0 +1,23 @@
+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,
diff --git a/target/linux/bcm27xx/patches-6.6/950-1206-dtoverlays-Add-overlay-for-HD44780-via-I2C-PCF8574-b.patch b/target/linux/bcm27xx/patches-6.6/950-1206-dtoverlays-Add-overlay-for-HD44780-via-I2C-PCF8574-b.patch
new file mode 100644 (file)
index 0000000..db5f472
--- /dev/null
@@ -0,0 +1,125 @@
+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";
++      };
++
++};
diff --git a/target/linux/bcm27xx/patches-6.6/950-1207-dtoverlays-Document-display_-width-height-on-hd44780.patch b/target/linux/bcm27xx/patches-6.6/950-1207-dtoverlays-Document-display_-width-height-on-hd44780.patch
new file mode 100644 (file)
index 0000000..793cd49
--- /dev/null
@@ -0,0 +1,28 @@
+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
diff --git a/target/linux/bcm27xx/patches-6.6/950-1208-DTS-bcm2712-enable-SD-slot-CQE-by-default-on-Pi-5.patch b/target/linux/bcm27xx/patches-6.6/950-1208-DTS-bcm2712-enable-SD-slot-CQE-by-default-on-Pi-5.patch
new file mode 100644 (file)
index 0000000..16e7603
--- /dev/null
@@ -0,0 +1,39 @@
+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";
diff --git a/target/linux/bcm27xx/patches-6.6/950-1211-gpiolib-Override-gpiochip-numbers-with-DT-aliases.patch b/target/linux/bcm27xx/patches-6.6/950-1211-gpiolib-Override-gpiochip-numbers-with-DT-aliases.patch
new file mode 100644 (file)
index 0000000..4ce9c04
--- /dev/null
@@ -0,0 +1,50 @@
+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;
diff --git a/target/linux/bcm27xx/patches-6.6/950-1212-dts-bcm2712-rpi-Add-gpiochip0-alias.patch b/target/linux/bcm27xx/patches-6.6/950-1212-dts-bcm2712-rpi-Add-gpiochip0-alias.patch
new file mode 100644 (file)
index 0000000..2191376
--- /dev/null
@@ -0,0 +1,23 @@
+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;
diff --git a/target/linux/bcm27xx/patches-6.6/950-1213-dts-bcm2712-rpi-The-SoC-gpiochips-start-at-10.patch b/target/linux/bcm27xx/patches-6.6/950-1213-dts-bcm2712-rpi-The-SoC-gpiochips-start-at-10.patch
new file mode 100644 (file)
index 0000000..5bf54c3
--- /dev/null
@@ -0,0 +1,24 @@
+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;