فهرست منبع

bcm27xx: update to latest RPi patches

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 <[email protected]>
Álvaro Fernández Rojas 1 سال پیش
والد
کامیت
0171157d45
59فایلهای تغییر یافته به همراه20609 افزوده شده و 41 حذف شده
  1. 1 0
      target/linux/bcm27xx/config-6.6
  2. 0 41
      target/linux/bcm27xx/patches-6.6/950-0714-spi-dw-dma-Get-the-last-DMA-scoop-out-of-the-FIFO.patch
  3. 260 0
      target/linux/bcm27xx/patches-6.6/950-1146-drivers-dwc_otg-use-C11-style-variable-array-declara.patch
  4. 27 0
      target/linux/bcm27xx/patches-6.6/950-1147-media-uapi-pixfmt-luma-Document-MIPI-CSI-2-packing.patch
  5. 101 0
      target/linux/bcm27xx/patches-6.6/950-1148-media-uapi-Add-a-pixel-format-for-BGR48-and-RGB48.patch
  6. 1171 0
      target/linux/bcm27xx/patches-6.6/950-1149-media-uapi-Add-Raspberry-Pi-PiSP-Back-End-uAPI.patch
  7. 86 0
      target/linux/bcm27xx/patches-6.6/950-1150-media-uapi-Document-meta-pixel-format-for-PiSP-BE-co.patch
  8. 106 0
      target/linux/bcm27xx/patches-6.6/950-1151-media-uapi-Document-PiSP-Compressed-RAW-Bayer-format.patch
  9. 97 0
      target/linux/bcm27xx/patches-6.6/950-1152-media-dt-bindings-Add-bindings-for-Raspberry-Pi-PiSP.patch
  10. 162 0
      target/linux/bcm27xx/patches-6.6/950-1153-media-admin-guide-Document-the-Raspberry-Pi-PiSP-BE.patch
  11. 2927 0
      target/linux/bcm27xx/patches-6.6/950-1154-media-pisp-be-Backport-the-mainline-PiSP-BE-driver.patch
  12. 29 0
      target/linux/bcm27xx/patches-6.6/950-1155-media-uapi-pisp_be_config-Drop-BIT-from-uAPI.patch
  13. 32 0
      target/linux/bcm27xx/patches-6.6/950-1156-media-uapi-pisp_common-Add-32-bpp-format-test.patch
  14. 89 0
      target/linux/bcm27xx/patches-6.6/950-1157-media-uapi-Capitalize-all-macros.patch
  15. 30 0
      target/linux/bcm27xx/patches-6.6/950-1158-media-uapi-pisp_be_config-Re-sort-pisp_be_tiles_conf.patch
  16. 82 0
      target/linux/bcm27xx/patches-6.6/950-1159-media-uapi-pisp_be_config-Add-extra-config-fields.patch
  17. 886 0
      target/linux/bcm27xx/patches-6.6/950-1160-media-pisp_be-Re-introduce-multi-context-support.patch
  18. 36 0
      target/linux/bcm27xx/patches-6.6/950-1161-media-pisp_be-Re-introduce-video-node-offset.patch
  19. 158 0
      target/linux/bcm27xx/patches-6.6/950-1163-dts-Make-camN_reg-and-camN_reg_gpio-overrides-generi.patch
  20. 108 0
      target/linux/bcm27xx/patches-6.6/950-1164-spi-dt-bindings-Add-RPI-RP2040-GPIO-Bridge.patch
  21. 1288 0
      target/linux/bcm27xx/patches-6.6/950-1165-spi-Add-a-driver-for-the-RPI-RP2040-GPIO-bridge.patch
  22. 52 0
      target/linux/bcm27xx/patches-6.6/950-1166-dmaengine-dw-axi-dmac-Honour-snps-block-size.patch
  23. 157 0
      target/linux/bcm27xx/patches-6.6/950-1167-mmc-restrict-posted-write-counts-for-SD-cards-in-CQ-.patch
  24. 70 0
      target/linux/bcm27xx/patches-6.6/950-1168-fixup-mmc-restrict-posted-write-counts-for-SD-cards-.patch
  25. 28 0
      target/linux/bcm27xx/patches-6.6/950-1169-mmc-brcmstb-don-t-squash-card-busy-detection-on-bcm2.patch
  26. 25 0
      target/linux/bcm27xx/patches-6.6/950-1172-Revert-Update-DAC8x-to-support-384khz-6187.patch
  27. 25 0
      target/linux/bcm27xx/patches-6.6/950-1176-dt-bindings-clk-rp1-Add-clocks-representing-MIPI-DSI.patch
  28. 132 0
      target/linux/bcm27xx/patches-6.6/950-1177-clk-clk-rp1-Add-varsrc-clocks-to-represent-MIPI-byte.patch
  29. 92 0
      target/linux/bcm27xx/patches-6.6/950-1178-dts-rp1-DSI-drivers-to-use-newly-defined-MIPI-byte-s.patch
  30. 313 0
      target/linux/bcm27xx/patches-6.6/950-1179-drm-rp1-rp1-dsi-Switch-to-PLL_SYS-source-for-DPI-whe.patch
  31. 9749 0
      target/linux/bcm27xx/patches-6.6/950-1180-arm64-dts-Move-bcm2712-and-rp1-here.patch
  32. 92 0
      target/linux/bcm27xx/patches-6.6/950-1181-arm64-dts-Add-cm5l-files.patch
  33. 408 0
      target/linux/bcm27xx/patches-6.6/950-1182-dts-bcm2712-Dedup-the-aliases-and-overrides.patch
  34. 24 0
      target/linux/bcm27xx/patches-6.6/950-1183-arm64-dts-Give-cm5l-its-own-model-name.patch
  35. 288 0
      target/linux/bcm27xx/patches-6.6/950-1185-pinctrl-rp1-jump-through-hoops-to-avoid-PCIe-latency.patch
  36. 36 0
      target/linux/bcm27xx/patches-6.6/950-1186-staging-bcm2835-codec-Disable-HEADER_ON_OPEN-for-vid.patch
  37. 36 0
      target/linux/bcm27xx/patches-6.6/950-1188-staging-bcm2835-codec-Add-support-for-H264-level-5.0.patch
  38. 66 0
      target/linux/bcm27xx/patches-6.6/950-1189-spi-dw-Save-bandwidth-with-the-TMOD_TO-feature.patch
  39. 186 0
      target/linux/bcm27xx/patches-6.6/950-1190-spi-dw-Save-bandwidth-with-the-TMOD_RO-feature.patch
  40. 41 0
      target/linux/bcm27xx/patches-6.6/950-1191-spi-dw-don-t-immediately-kill-DMA-transfers-if-an-er.patch
  41. 35 0
      target/linux/bcm27xx/patches-6.6/950-1192-dts-rp1-hobble-DMA-AXI-burst-lengths.patch
  42. 124 0
      target/linux/bcm27xx/patches-6.6/950-1193-drivers-dw-axi-dmac-make-more-sensible-choices-about.patch
  43. 30 0
      target/linux/bcm27xx/patches-6.6/950-1195-tty-serial-pl011-restrict-RX-burst-FIFO-threshold.patch
  44. 27 0
      target/linux/bcm27xx/patches-6.6/950-1196-DT-bindings-add-a-dma-maxburst-property-to-snps-desi.patch
  45. 99 0
      target/linux/bcm27xx/patches-6.6/950-1197-sound-soc-dwc-i2s-choose-FIFO-thresholds-based-on-DM.patch
  46. 30 0
      target/linux/bcm27xx/patches-6.6/950-1198-dts-rp1-restrict-i2s-burst-lengths-to-4.patch
  47. 204 0
      target/linux/bcm27xx/patches-6.6/950-1199-drm-vc4-Disable-the-2pixel-clock-odd-timings-workaro.patch
  48. 26 0
      target/linux/bcm27xx/patches-6.6/950-1200-ARM-dts-bcm2712-Fix-invalid-polling-delay-passive-se.patch
  49. 143 0
      target/linux/bcm27xx/patches-6.6/950-1201-spi-dw-Fix-non-DMA-transmit-only-transfers.patch
  50. 26 0
      target/linux/bcm27xx/patches-6.6/950-1202-spi-dw-Clamp-the-minimum-clock-speed.patch
  51. 26 0
      target/linux/bcm27xx/patches-6.6/950-1203-overlays-i2c-rtc-Correct-bq32000-property-name.patch
  52. 31 0
      target/linux/bcm27xx/patches-6.6/950-1204-hwmon-adt7410-Add-DT-compatible-strings.patch
  53. 23 0
      target/linux/bcm27xx/patches-6.6/950-1205-fixup-pinctrl-bcm2712-pinctrl-pinconf-driver.patch
  54. 125 0
      target/linux/bcm27xx/patches-6.6/950-1206-dtoverlays-Add-overlay-for-HD44780-via-I2C-PCF8574-b.patch
  55. 28 0
      target/linux/bcm27xx/patches-6.6/950-1207-dtoverlays-Document-display_-width-height-on-hd44780.patch
  56. 39 0
      target/linux/bcm27xx/patches-6.6/950-1208-DTS-bcm2712-enable-SD-slot-CQE-by-default-on-Pi-5.patch
  57. 50 0
      target/linux/bcm27xx/patches-6.6/950-1211-gpiolib-Override-gpiochip-numbers-with-DT-aliases.patch
  58. 23 0
      target/linux/bcm27xx/patches-6.6/950-1212-dts-bcm2712-rpi-Add-gpiochip0-alias.patch
  59. 24 0
      target/linux/bcm27xx/patches-6.6/950-1213-dts-bcm2712-rpi-The-SoC-gpiochips-start-at-10.patch

+ 1 - 0
target/linux/bcm27xx/config-6.6

@@ -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

+ 0 - 41
target/linux/bcm27xx/patches-6.6/950-0714-spi-dw-dma-Get-the-last-DMA-scoop-out-of-the-FIFO.patch

@@ -1,41 +0,0 @@
-From 6aab06ff9f81e186b1a02b53b514e691472e5a61 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <[email protected]>
-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 <[email protected]>
----
- 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

+ 260 - 0
target/linux/bcm27xx/patches-6.6/950-1146-drivers-dwc_otg-use-C11-style-variable-array-declara.patch

@@ -0,0 +1,260 @@
+From 65fddc7301f52470fd846acede96d240a1902e67 Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <[email protected]>
+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 <[email protected]>
+---
+ 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;

+ 27 - 0
target/linux/bcm27xx/patches-6.6/950-1147-media-uapi-pixfmt-luma-Document-MIPI-CSI-2-packing.patch

@@ -0,0 +1,27 @@
+From 8dea9155ab081289edd618f8373d5f980d5bb664 Mon Sep 17 00:00:00 2001
+From: Jacopo Mondi <[email protected]>
+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 <[email protected]>
+Reviewed-by: Laurent Pinchart <[email protected]>
+Reviewed-by: Naushir Patuck <[email protected]>
+---
+ 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.

+ 101 - 0
target/linux/bcm27xx/patches-6.6/950-1148-media-uapi-Add-a-pixel-format-for-BGR48-and-RGB48.patch

@@ -0,0 +1,101 @@
+From 814c088cb7183f79ba68c8f9459505e2ac4dde3a Mon Sep 17 00:00:00 2001
+From: Jacopo Mondi <[email protected]>
+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 <[email protected]>
+Reviewed-by: Kieran Bingham <[email protected]>
+Reviewed-by: Naushir Patuck <[email protected]>
+---
+ .../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) */

+ 1171 - 0
target/linux/bcm27xx/patches-6.6/950-1149-media-uapi-Add-Raspberry-Pi-PiSP-Back-End-uAPI.patch

@@ -0,0 +1,1171 @@
+From be6996ad702fac96b36ea209ae04a71bd1c6e1d4 Mon Sep 17 00:00:00 2001
+From: Jacopo Mondi <[email protected]>
+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 <[email protected]>
+---
+ 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:	[email protected]
+ S:	Orphan
+ F:	drivers/net/wireless/legacy/ray*
+ 
++RASPBERRY PI PISP BACK END
++M:	Jacopo Mondi <[email protected]>
++L:	Raspberry Pi Kernel Maintenance <[email protected]>
++L:	[email protected]
++S:	Maintained
++F:	include/uapi/linux/media/raspberrypi/
++
+ RC-CORE / LIRC FRAMEWORK
+ M:	Sean Young <[email protected]>
+ L:	[email protected]
+--- /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_ */

+ 86 - 0
target/linux/bcm27xx/patches-6.6/950-1150-media-uapi-Document-meta-pixel-format-for-PiSP-BE-co.patch

@@ -0,0 +1,86 @@
+From 7ca73020a5b26599d539083e413784e79891107e Mon Sep 17 00:00:00 2001
+From: Jacopo Mondi <[email protected]>
+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 <[email protected]>
+Reviewed-by: Naushir Patuck <[email protected]>
+---
+ .../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

+ 106 - 0
target/linux/bcm27xx/patches-6.6/950-1151-media-uapi-Document-PiSP-Compressed-RAW-Bayer-format.patch

@@ -0,0 +1,106 @@
+From 5d6318f242cce5f9b5677baedde736a2b81061df Mon Sep 17 00:00:00 2001
+From: Jacopo Mondi <[email protected]>
+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
+<[email protected]> from Raspberry Pi.
+
+Signed-off-by: Jacopo Mondi <[email protected]>
+Reviewed-by: Naushir Patuck <[email protected]>
+---
+ .../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>`_.

+ 97 - 0
target/linux/bcm27xx/patches-6.6/950-1152-media-dt-bindings-Add-bindings-for-Raspberry-Pi-PiSP.patch

@@ -0,0 +1,97 @@
+From c38a898c6877c6722ebfecea99f42e5a84c3e453 Mon Sep 17 00:00:00 2001
+From: Jacopo Mondi <[email protected]>
+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 <[email protected]>
+Reviewed-by: Rob Herring <[email protected]>
+Reviewed-by: Naushir Patuck <[email protected]>
+---
+ .../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 <[email protected]>
++  - Jacopo Mondi <[email protected]>
++
++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 <[email protected]>
+ L:	[email protected]
+ S:	Maintained
++F:	Documentation/devicetree/bindings/media/raspberrypi,pispbe.yaml
+ F:	include/uapi/linux/media/raspberrypi/
+ 
+ RC-CORE / LIRC FRAMEWORK

+ 162 - 0
target/linux/bcm27xx/patches-6.6/950-1153-media-admin-guide-Document-the-Raspberry-Pi-PiSP-BE.patch

@@ -0,0 +1,162 @@
+From d68e76260316002869aea1b0edf4be399bb592b8 Mon Sep 17 00:00:00 2001
+From: Jacopo Mondi <[email protected]>
+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 <[email protected]>
+---
+ .../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

+ 2927 - 0
target/linux/bcm27xx/patches-6.6/950-1154-media-pisp-be-Backport-the-mainline-PiSP-BE-driver.patch

@@ -0,0 +1,2927 @@
+From c75989589bf77530f4013e0bc799169504c69937 Mon Sep 17 00:00:00 2001
+From: Jacopo Mondi <[email protected]>
+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/[email protected]/
+
+Signed-off-by: Jacopo Mondi <[email protected]>
+---
+ .../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 <[email protected]>");
+-MODULE_AUTHOR("Nick Hollinghurst <[email protected]>");
+-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 <[email protected]>");
++MODULE_AUTHOR("Nick Hollinghurst <[email protected]>");
++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[] = {

+ 29 - 0
target/linux/bcm27xx/patches-6.6/950-1155-media-uapi-pisp_be_config-Drop-BIT-from-uAPI.patch

@@ -0,0 +1,29 @@
+From b58aeea7e2e3afd4fb3b6dcbe5e382b2244b33a4 Mon Sep 17 00:00:00 2001
+From: Jacopo Mondi <[email protected]>
+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 <[email protected]>
+Reviewed-by: Tomi Valkeinen <[email protected]>
+---
+ 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;

+ 32 - 0
target/linux/bcm27xx/patches-6.6/950-1156-media-uapi-pisp_common-Add-32-bpp-format-test.patch

@@ -0,0 +1,32 @@
+From 7c36a1feb61d964055bee777efc1db60790aa215 Mon Sep 17 00:00:00 2001
+From: Jacopo Mondi <[email protected]>
+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 <[email protected]>
+---
+ 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))

+ 89 - 0
target/linux/bcm27xx/patches-6.6/950-1157-media-uapi-Capitalize-all-macros.patch

@@ -0,0 +1,89 @@
+From 20a3671be178fd98aac08931d809e689eaa7a9d9 Mon Sep 17 00:00:00 2001
+From: Jacopo Mondi <[email protected]>
+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 <[email protected]>
+---
+ .../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))

+ 30 - 0
target/linux/bcm27xx/patches-6.6/950-1158-media-uapi-pisp_be_config-Re-sort-pisp_be_tiles_conf.patch

@@ -0,0 +1,30 @@
+From ce89955e44f3ab41262b02d8e1e65c3455d66c4d Mon Sep 17 00:00:00 2001
+From: Jacopo Mondi <[email protected]>
+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 <[email protected]>
+---
+ 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_ */

+ 82 - 0
target/linux/bcm27xx/patches-6.6/950-1159-media-uapi-pisp_be_config-Add-extra-config-fields.patch

@@ -0,0 +1,82 @@
+From abf30420f943d03cc28fec38612d2c5f5e6edf1f Mon Sep 17 00:00:00 2001
+From: Jacopo Mondi <[email protected]>
+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 <[email protected]>
+---
+ .../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));
+ 
+ /**

+ 886 - 0
target/linux/bcm27xx/patches-6.6/950-1160-media-pisp_be-Re-introduce-multi-context-support.patch

@@ -0,0 +1,886 @@
+From 033e037013f2c092501a03bb1bf5bbf7b4045aa0 Mon Sep 17 00:00:00 2001
+From: Jacopo Mondi <[email protected]>
+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 <[email protected]>
+---
+ .../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);

+ 36 - 0
target/linux/bcm27xx/patches-6.6/950-1161-media-pisp_be-Re-introduce-video-node-offset.patch

@@ -0,0 +1,36 @@
+From f372f2854279828a33b9b3debc233d366fb4c124 Mon Sep 17 00:00:00 2001
+From: Naushir Patuck <[email protected]>
+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 <[email protected]>
+---
+ 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",

+ 158 - 0
target/linux/bcm27xx/patches-6.6/950-1163-dts-Make-camN_reg-and-camN_reg_gpio-overrides-generi.patch

@@ -0,0 +1,158 @@
+From 6e4ad40811170653431fc40a6fdc3f486863b40f Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <[email protected]>
+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 <[email protected]>
+---
+ .../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.

+ 108 - 0
target/linux/bcm27xx/patches-6.6/950-1164-spi-dt-bindings-Add-RPI-RP2040-GPIO-Bridge.patch

@@ -0,0 +1,108 @@
+From afd949f5f64d224cf7a016ef933257842bc170ab Mon Sep 17 00:00:00 2001
+From: Richard Oliver <[email protected]>
+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 <[email protected]>
+---
+ .../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 <[email protected]>
++
++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 <[email protected]>
++S:	Maintained
++F:	Documentation/devicetree/bindings/spi/raspberrypi,rp2040-gpio-bridge.yaml
++
+ RAYLINK/WEBGEAR 802.11 WIRELESS LAN DRIVER
+ L:	[email protected]
+ S:	Orphan

+ 1288 - 0
target/linux/bcm27xx/patches-6.6/950-1165-spi-Add-a-driver-for-the-RPI-RP2040-GPIO-bridge.patch

@@ -0,0 +1,1288 @@
+From 99ae83f1944f47d4338ef7a6f02536927fc6ce57 Mon Sep 17 00:00:00 2001
+From: Richard Oliver <[email protected]>
+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 <[email protected]>
+---
+ 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 <[email protected]>
+ 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:	[email protected]
+--- 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 <[email protected]>");
++MODULE_DESCRIPTION("Raspberry Pi RP2040 GPIO Bridge");
++MODULE_LICENSE("GPL");

+ 52 - 0
target/linux/bcm27xx/patches-6.6/950-1166-dmaengine-dw-axi-dmac-Honour-snps-block-size.patch

@@ -0,0 +1,52 @@
+From 475cddaba6b02584157e1c128a5a6858770a3d06 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <[email protected]>
+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 <[email protected]>
+---
+ 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);

+ 157 - 0
target/linux/bcm27xx/patches-6.6/950-1167-mmc-restrict-posted-write-counts-for-SD-cards-in-CQ-.patch

@@ -0,0 +1,157 @@
+From e6c1e862b2b8150a419f4208e5bd7749662b16a1 Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <[email protected]>
+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 <[email protected]>
+---
+ 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)

+ 70 - 0
target/linux/bcm27xx/patches-6.6/950-1168-fixup-mmc-restrict-posted-write-counts-for-SD-cards-.patch

@@ -0,0 +1,70 @@
+From 19682239a60c1b53cad8319eaeb58e71d4213cee Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <[email protected]>
+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 <[email protected]>
+---
+ 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));
+ 	}
+ 

+ 28 - 0
target/linux/bcm27xx/patches-6.6/950-1169-mmc-brcmstb-don-t-squash-card-busy-detection-on-bcm2.patch

@@ -0,0 +1,28 @@
+From 1abc413af44652d6a76d5b5c2afe90788595008e Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <[email protected]>
+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 <[email protected]>
+---
+ 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,

+ 25 - 0
target/linux/bcm27xx/patches-6.6/950-1172-Revert-Update-DAC8x-to-support-384khz-6187.patch

@@ -0,0 +1,25 @@
+From 31eb43be8cad2818b4458cf1fd2dfa60031ee5f4 Mon Sep 17 00:00:00 2001
+From: Matthew <[email protected]>
+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;
+ }

+ 25 - 0
target/linux/bcm27xx/patches-6.6/950-1176-dt-bindings-clk-rp1-Add-clocks-representing-MIPI-DSI.patch

@@ -0,0 +1,25 @@
+From 3224569a3e279bbeae4e975dfa1a890f3f595239 Mon Sep 17 00:00:00 2001
+From: Nick Hollinghurst <[email protected]>
+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 <[email protected]>
+---
+ 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

+ 132 - 0
target/linux/bcm27xx/patches-6.6/950-1177-clk-clk-rp1-Add-varsrc-clocks-to-represent-MIPI-byte.patch

@@ -0,0 +1,132 @@
+From 126560c909f38f00c08dd5f35f50c981d5e25e1f Mon Sep 17 00:00:00 2001
+From: Nick Hollinghurst <[email protected]>
+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 <[email protected]>
+---
+ 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)];

+ 92 - 0
target/linux/bcm27xx/patches-6.6/950-1178-dts-rp1-DSI-drivers-to-use-newly-defined-MIPI-byte-s.patch

@@ -0,0 +1,92 @@
+From 9a108c82b6f6526e0aa8a19befa1ed3f31f8fe52 Mon Sep 17 00:00:00 2001
+From: Nick Hollinghurst <[email protected]>
+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 <[email protected]>
+---
+ 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

+ 313 - 0
target/linux/bcm27xx/patches-6.6/950-1179-drm-rp1-rp1-dsi-Switch-to-PLL_SYS-source-for-DPI-whe.patch

@@ -0,0 +1,313 @@
+From f5de8d46da4b40f2180be502c1e547fe8c9b2ac2 Mon Sep 17 00:00:00 2001
+From: Nick Hollinghurst <[email protected]>
+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 <[email protected]>
+---
+ 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);

+ 9749 - 0
target/linux/bcm27xx/patches-6.6/950-1180-arm64-dts-Move-bcm2712-and-rp1-here.patch

@@ -0,0 +1,9749 @@
+From 10c77e119eaaa2677009dea58cf69a8e5383925b Mon Sep 17 00:00:00 2001
+From: Phil Elwell <[email protected]>
+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 <[email protected]>
+---
+ .../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;
++	};
++};

+ 92 - 0
target/linux/bcm27xx/patches-6.6/950-1181-arm64-dts-Add-cm5l-files.patch

@@ -0,0 +1,92 @@
+From 4de4f56af7d803fa7dd9ffe42d4719b428d73e6c Mon Sep 17 00:00:00 2001
+From: Phil Elwell <[email protected]>
+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 <[email protected]>
+---
+ 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;
++};

+ 408 - 0
target/linux/bcm27xx/patches-6.6/950-1182-dts-bcm2712-Dedup-the-aliases-and-overrides.patch

@@ -0,0 +1,408 @@
+From e1c56acf3355cd539447511fdc1b886e5eb5cca3 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <[email protected]>
+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 <[email protected]>
+---
+ .../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>;
+-
+ 	};
+ };
+ 

+ 24 - 0
target/linux/bcm27xx/patches-6.6/950-1183-arm64-dts-Give-cm5l-its-own-model-name.patch

@@ -0,0 +1,24 @@
+From ad110e5ff36de6096e1b9d7e0fe125326f45ed7d Mon Sep 17 00:00:00 2001
+From: Phil Elwell <[email protected]>
+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 <[email protected]>
+---
+ 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";
+ 	};

+ 288 - 0
target/linux/bcm27xx/patches-6.6/950-1185-pinctrl-rp1-jump-through-hoops-to-avoid-PCIe-latency.patch

@@ -0,0 +1,288 @@
+From d24229dcef58e0162780ceffa02eb5f6a01b9a4d Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <[email protected]>
+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 <[email protected]>
+---
+ 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,

+ 36 - 0
target/linux/bcm27xx/patches-6.6/950-1186-staging-bcm2835-codec-Disable-HEADER_ON_OPEN-for-vid.patch

@@ -0,0 +1,36 @@
+From 43fa967811484afde0bbbee182ff8f29dc0550c2 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <[email protected]>
+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 <[email protected]>
+---
+ .../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,

+ 36 - 0
target/linux/bcm27xx/patches-6.6/950-1188-staging-bcm2835-codec-Add-support-for-H264-level-5.0.patch

@@ -0,0 +1,36 @@
+From 31b9871b8895d7931ee88d7cda7861f829b21d63 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <[email protected]>
+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 <[email protected]>
+---
+ .../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,

+ 66 - 0
target/linux/bcm27xx/patches-6.6/950-1189-spi-dw-Save-bandwidth-with-the-TMOD_TO-feature.patch

@@ -0,0 +1,66 @@
+From 6014649de765a8a1f95c146ca72214ff0ba4ba89 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <[email protected]>
+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 <[email protected]>
+---
+ 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();
+ 

+ 186 - 0
target/linux/bcm27xx/patches-6.6/950-1190-spi-dw-Save-bandwidth-with-the-TMOD_RO-feature.patch

@@ -0,0 +1,186 @@
+From cd9084ceb606a2f06c3429c2d3beae2d7c3ebd23 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <[email protected]>
+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 <[email protected]>
+---
+ 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);
+ 

+ 41 - 0
target/linux/bcm27xx/patches-6.6/950-1191-spi-dw-don-t-immediately-kill-DMA-transfers-if-an-er.patch

@@ -0,0 +1,41 @@
+From 3af7822df36e36b5a74d877df7654695c0e0d34a Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <[email protected]>
+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 <[email protected]>
+---
+ 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;
+ 	}

+ 35 - 0
target/linux/bcm27xx/patches-6.6/950-1192-dts-rp1-hobble-DMA-AXI-burst-lengths.patch

@@ -0,0 +1,35 @@
+From 4c1a665b465fa0e9d3369a467fc563ec812a47ce Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <[email protected]>
+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 <[email protected]>
+---
+ 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";
+ 		};
+ 

+ 124 - 0
target/linux/bcm27xx/patches-6.6/950-1193-drivers-dw-axi-dmac-make-more-sensible-choices-about.patch

@@ -0,0 +1,124 @@
+From ce56098eb4dc2985f27f30ad7b7f5aed6bcf7fb1 Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <[email protected]>
+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 <[email protected]>
+---
+ .../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:

+ 30 - 0
target/linux/bcm27xx/patches-6.6/950-1195-tty-serial-pl011-restrict-RX-burst-FIFO-threshold.patch

@@ -0,0 +1,30 @@
+From f3cb675102a2a5a330038c4e748f02b02cec989e Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <[email protected]>
+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 <[email protected]>
+---
+ 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;

+ 27 - 0
target/linux/bcm27xx/patches-6.6/950-1196-DT-bindings-add-a-dma-maxburst-property-to-snps-desi.patch

@@ -0,0 +1,27 @@
+From 5112fd8cce4f1dc9bf43f0f90d35e273e1a0f555 Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <[email protected]>
+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 <[email protected]>
+---
+ .../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

+ 99 - 0
target/linux/bcm27xx/patches-6.6/950-1197-sound-soc-dwc-i2s-choose-FIFO-thresholds-based-on-DM.patch

@@ -0,0 +1,99 @@
+From b6b4260fa546d1dc7421c7cfed059052dae04227 Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <[email protected]>
+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 <[email protected]>
+---
+ 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 */

+ 30 - 0
target/linux/bcm27xx/patches-6.6/950-1198-dts-rp1-restrict-i2s-burst-lengths-to-4.patch

@@ -0,0 +1,30 @@
+From 062434ab3be76d4fa5973bb199ccfd5b68c11720 Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <[email protected]>
+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 <[email protected]>
+---
+ 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";
+ 		};
+ 

+ 204 - 0
target/linux/bcm27xx/patches-6.6/950-1199-drm-vc4-Disable-the-2pixel-clock-odd-timings-workaro.patch

@@ -0,0 +1,204 @@
+From 485d11cfa7df2d2deb39c9b3455cebcb1a85cea2 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <[email protected]>
+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 <[email protected]>
+---
+ 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

+ 26 - 0
target/linux/bcm27xx/patches-6.6/950-1200-ARM-dts-bcm2712-Fix-invalid-polling-delay-passive-se.patch

@@ -0,0 +1,26 @@
+From 70636ad110715b5e1ec6b08e24f0ddaf5df7186d Mon Sep 17 00:00:00 2001
+From: Dom Cobley <[email protected]>
+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/[email protected]/
+
+Signed-off-by: Dom Cobley <[email protected]>
+---
+ 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>;

+ 143 - 0
target/linux/bcm27xx/patches-6.6/950-1201-spi-dw-Fix-non-DMA-transmit-only-transfers.patch

@@ -0,0 +1,143 @@
+From 199e611183de09ad91fe01fc79da78cc9d11ccb6 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <[email protected]>
+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 <[email protected]>
+---
+ 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;

+ 26 - 0
target/linux/bcm27xx/patches-6.6/950-1202-spi-dw-Clamp-the-minimum-clock-speed.patch

@@ -0,0 +1,26 @@
+From e9294823cf02068189a0e901223ed4991923c689 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <[email protected]>
+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 <[email protected]>
+---
+ 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) {

+ 26 - 0
target/linux/bcm27xx/patches-6.6/950-1203-overlays-i2c-rtc-Correct-bq32000-property-name.patch

@@ -0,0 +1,26 @@
+From 05e3687c6c973c30bf35f3b7f4a7589b5030a830 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <[email protected]>
+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 <[email protected]>
+---
+ 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?",

+ 31 - 0
target/linux/bcm27xx/patches-6.6/950-1204-hwmon-adt7410-Add-DT-compatible-strings.patch

@@ -0,0 +1,31 @@
+From 16d0ee22d2c0b32cc67db73ce03263b740bba2a7 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <[email protected]>
+Date: Wed, 31 Jul 2024 15:02:47 +0100
+Subject: [PATCH 1204/1215] hwmon: (adt7410) Add DT compatible strings
+
+Signed-off-by: Phil Elwell <[email protected]>
+---
+ 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,

+ 23 - 0
target/linux/bcm27xx/patches-6.6/950-1205-fixup-pinctrl-bcm2712-pinctrl-pinconf-driver.patch

@@ -0,0 +1,23 @@
+From a4bf61fad9fe102514243ed263c458b053c87681 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <[email protected]>
+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 <[email protected]>
+---
+ 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,

+ 125 - 0
target/linux/bcm27xx/patches-6.6/950-1206-dtoverlays-Add-overlay-for-HD44780-via-I2C-PCF8574-b.patch

@@ -0,0 +1,125 @@
+From e94e761305fa2281718adcf625d78f3cf662e12d Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <[email protected]>
+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 <[email protected]>
+---
+ 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";
++	};
++
++};

+ 28 - 0
target/linux/bcm27xx/patches-6.6/950-1207-dtoverlays-Document-display_-width-height-on-hd44780.patch

@@ -0,0 +1,28 @@
+From 3c319a466a1c718f66c471a9d5ec60de6de44612 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <[email protected]>
+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 <[email protected]>
+---
+ 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

+ 39 - 0
target/linux/bcm27xx/patches-6.6/950-1208-DTS-bcm2712-enable-SD-slot-CQE-by-default-on-Pi-5.patch

@@ -0,0 +1,39 @@
+From 216df57950849f905c398904e7d6cbdf278b5717 Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <[email protected]>
+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 <[email protected]>
+---
+ 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";

+ 50 - 0
target/linux/bcm27xx/patches-6.6/950-1211-gpiolib-Override-gpiochip-numbers-with-DT-aliases.patch

@@ -0,0 +1,50 @@
+From 53b9d9bbb57e292c6b332a2fb9899003586e17ca Mon Sep 17 00:00:00 2001
+From: Phil Elwell <[email protected]>
+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 <[email protected]>
+---
+ 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;

+ 23 - 0
target/linux/bcm27xx/patches-6.6/950-1212-dts-bcm2712-rpi-Add-gpiochip0-alias.patch

@@ -0,0 +1,23 @@
+From 1162316fd26eeb4193b23fcc1bb332f42938aa70 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <[email protected]>
+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 <[email protected]>
+---
+ 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;

+ 24 - 0
target/linux/bcm27xx/patches-6.6/950-1213-dts-bcm2712-rpi-The-SoC-gpiochips-start-at-10.patch

@@ -0,0 +1,24 @@
+From 70c640ce992234aacba5a717f3fb47319f451431 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <[email protected]>
+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 <[email protected]>
+---
+ 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;