From: Álvaro Fernández Rojas Date: Wed, 3 Jul 2024 18:30:59 +0000 (+0200) Subject: bcm27xx: update to latest RPi patches X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=0171157d45f1c8c068608b69afdcdef101e5a594;p=openwrt%2Fstaging%2Flinusw.git 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 --- diff --git a/target/linux/bcm27xx/config-6.6 b/target/linux/bcm27xx/config-6.6 index 55f5523ab5..b44aa9f8a9 100644 --- a/target/linux/bcm27xx/config-6.6 +++ b/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 diff --git a/target/linux/bcm27xx/patches-6.6/950-0714-spi-dw-dma-Get-the-last-DMA-scoop-out-of-the-FIFO.patch b/target/linux/bcm27xx/patches-6.6/950-0714-spi-dw-dma-Get-the-last-DMA-scoop-out-of-the-FIFO.patch deleted file mode 100644 index 2a2ba5d037..0000000000 --- a/target/linux/bcm27xx/patches-6.6/950-0714-spi-dw-dma-Get-the-last-DMA-scoop-out-of-the-FIFO.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 6aab06ff9f81e186b1a02b53b514e691472e5a61 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -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 ---- - drivers/spi/spi-dw-dma.c | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - ---- a/drivers/spi/spi-dw-dma.c -+++ b/drivers/spi/spi-dw-dma.c -@@ -315,8 +315,10 @@ static void dw_spi_dma_tx_done(void *arg - struct dw_spi *dws = arg; - - clear_bit(DW_SPI_TX_BUSY, &dws->dma_chan_busy); -- if (test_bit(DW_SPI_RX_BUSY, &dws->dma_chan_busy)) -+ if (test_bit(DW_SPI_RX_BUSY, &dws->dma_chan_busy)) { -+ dw_writel(dws, DW_SPI_DMARDLR, 0); - return; -+ } - - complete(&dws->dma_completion); - } -@@ -642,6 +644,8 @@ static int dw_spi_dma_transfer(struct dw - - nents = max(xfer->tx_sg.nents, xfer->rx_sg.nents); - -+ dw_writel(dws, DW_SPI_DMARDLR, xfer->tx_buf ? (dws->rxburst - 1) : 0); -+ - /* - * Execute normal DMA-based transfer (which submits the Rx and Tx SG - * lists directly to the DMA engine at once) if either full hardware diff --git a/target/linux/bcm27xx/patches-6.6/950-1146-drivers-dwc_otg-use-C11-style-variable-array-declara.patch b/target/linux/bcm27xx/patches-6.6/950-1146-drivers-dwc_otg-use-C11-style-variable-array-declara.patch new file mode 100644 index 0000000000..b5f117f7f7 --- /dev/null +++ b/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 +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 +--- + drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c | 12 ++++---- + drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h | 8 ++--- + drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 34 ++++++++++----------- + drivers/usb/host/dwc_otg/dwc_otg_hcd.h | 4 +-- + drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 4 +-- + 5 files changed, 28 insertions(+), 34 deletions(-) + +--- a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c ++++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c +@@ -240,8 +240,8 @@ static int notrace fiq_increment_dma_buf + hcdma_data_t hcdma; + int i = st->channel[n].dma_info.index; + int len; +- struct fiq_dma_blob *blob = +- (struct fiq_dma_blob *)(uintptr_t)st->dma_base; ++ struct fiq_dma_channel *split_dma = ++ (struct fiq_dma_channel *)(uintptr_t)st->dma_base; + + len = fiq_get_xfer_len(st, n); + fiq_print(FIQDBG_INT, st, "LEN: %03d", len); +@@ -250,7 +250,7 @@ static int notrace fiq_increment_dma_buf + if (i > 6) + BUG(); + +- hcdma.d32 = (u32)(uintptr_t)&blob->channel[n].index[i].buf[0]; ++ hcdma.d32 = lower_32_bits((uintptr_t)&split_dma[n].index[i].buf[0]); + FIQ_WRITE(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HC_DMA, hcdma.d32); + st->channel[n].dma_info.index = i; + return 0; +@@ -290,8 +290,8 @@ static int notrace fiq_iso_out_advance(s + hcsplt_data_t hcsplt; + hctsiz_data_t hctsiz; + hcdma_data_t hcdma; +- struct fiq_dma_blob *blob = +- (struct fiq_dma_blob *)(uintptr_t)st->dma_base; ++ struct fiq_dma_channel *split_dma = ++ (struct fiq_dma_channel *)(uintptr_t)st->dma_base; + int last = 0; + int i = st->channel[n].dma_info.index; + +@@ -303,7 +303,7 @@ static int notrace fiq_iso_out_advance(s + last = 1; + + /* New DMA address - address of bounce buffer referred to in index */ +- hcdma.d32 = (u32)(uintptr_t)blob->channel[n].index[i].buf; ++ hcdma.d32 = lower_32_bits((uintptr_t)&split_dma[n].index[i].buf[0]); + //hcdma.d32 = FIQ_READ(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HC_DMA); + //hcdma.d32 += st->channel[n].dma_info.slot_len[i]; + fiq_print(FIQDBG_INT, st, "LAST: %01d ", last); +--- a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h ++++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h +@@ -263,10 +263,6 @@ struct fiq_dma_channel { + struct fiq_split_dma_slot index[6]; + } __attribute__((packed)); + +-struct fiq_dma_blob { +- struct fiq_dma_channel channel[0]; +-} __attribute__((packed)); +- + /** + * struct fiq_hs_isoc_info - USB2.0 isochronous data + * @iso_frame: Pointer to the array of OTG URB iso_frame_descs. +@@ -352,7 +348,7 @@ struct fiq_state { + mphi_regs_t mphi_regs; + void *dwc_regs_base; + dma_addr_t dma_base; +- struct fiq_dma_blob *fiq_dmab; ++ struct fiq_dma_channel *fiq_dmab; + void *dummy_send; + dma_addr_t dummy_send_dma; + gintmsk_data_t gintmsk_saved; +@@ -365,7 +361,7 @@ struct fiq_state { + char * buffer; + unsigned int bufsiz; + #endif +- struct fiq_channel_state channel[0]; ++ struct fiq_channel_state channel[]; + }; + + #ifdef CONFIG_ARM64 +--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c ++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c +@@ -58,6 +58,7 @@ static int last_sel_trans_num_avail_hc_a + static int last_sel_trans_num_avail_hc_at_end = 0; + #endif /* DEBUG_HOST_CHANNELS */ + ++static_assert(FIQ_PASSTHROUGH == 0); + + dwc_otg_hcd_t *dwc_otg_hcd_alloc_hcd(void) + { +@@ -876,7 +877,7 @@ void dwc_otg_hcd_power_up(void *ptr) + void dwc_otg_cleanup_fiq_channel(dwc_otg_hcd_t *hcd, uint32_t num) + { + struct fiq_channel_state *st = &hcd->fiq_state->channel[num]; +- struct fiq_dma_blob *blob = hcd->fiq_dmab; ++ struct fiq_dma_channel *split_dma = hcd->fiq_dmab; + int i; + + st->fsm = FIQ_PASSTHROUGH; +@@ -898,7 +899,7 @@ void dwc_otg_cleanup_fiq_channel(dwc_otg + st->hs_isoc_info.iso_desc = NULL; + st->hs_isoc_info.nrframes = 0; + +- DWC_MEMSET(&blob->channel[num].index[0], 0x6b, 1128); ++ DWC_MEMSET(&split_dma[num].index[0], 0x6b, 1128); + } + + /** +@@ -1045,9 +1046,6 @@ int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd + spin_lock_init(&hcd->fiq_state->lock); + #endif + +- for (i = 0; i < num_channels; i++) { +- hcd->fiq_state->channel[i].fsm = FIQ_PASSTHROUGH; +- } + hcd->fiq_state->dummy_send = DWC_DMA_ALLOC_ATOMIC(dev, 16, + &hcd->fiq_state->dummy_send_dma); + +@@ -1561,7 +1559,7 @@ int fiq_fsm_setup_periodic_dma(dwc_otg_h + int frame_length, i = 0; + uint8_t *ptr = NULL; + dwc_hc_t *hc = qh->channel; +- struct fiq_dma_blob *blob; ++ struct fiq_dma_channel *split_dma; + struct dwc_otg_hcd_iso_packet_desc *frame_desc; + + for (i = 0; i < 6; i++) { +@@ -1576,10 +1574,10 @@ int fiq_fsm_setup_periodic_dma(dwc_otg_h + * Pointer arithmetic on hcd->fiq_state->dma_base (a dma_addr_t) + * to point it to the correct offset in the allocated buffers. + */ +- blob = (struct fiq_dma_blob *) ++ split_dma = (struct fiq_dma_channel *) + (uintptr_t)hcd->fiq_state->dma_base; +- st->hcdma_copy.d32 =(u32)(uintptr_t) +- blob->channel[hc->hc_num].index[0].buf; ++ st->hcdma_copy.d32 = lower_32_bits((uintptr_t) ++ &split_dma[hc->hc_num].index[0].buf[0]); + + /* Calculate the max number of CSPLITS such that the FIQ can time out + * a transaction if it fails. +@@ -1600,7 +1598,7 @@ int fiq_fsm_setup_periodic_dma(dwc_otg_h + frame_length = frame_desc->length; + + /* Virtual address for bounce buffers */ +- blob = hcd->fiq_dmab; ++ split_dma = hcd->fiq_dmab; + + ptr = qtd->urb->buf + frame_desc->offset; + if (frame_length == 0) { +@@ -1613,11 +1611,11 @@ int fiq_fsm_setup_periodic_dma(dwc_otg_h + } else { + do { + if (frame_length <= 188) { +- dwc_memcpy(&blob->channel[hc->hc_num].index[i].buf[0], ptr, frame_length); ++ dwc_memcpy(&split_dma[hc->hc_num].index[i].buf[0], ptr, frame_length); + st->dma_info.slot_len[i] = frame_length; + ptr += frame_length; + } else { +- dwc_memcpy(&blob->channel[hc->hc_num].index[i].buf[0], ptr, 188); ++ dwc_memcpy(&split_dma[hc->hc_num].index[i].buf[0], ptr, 188); + st->dma_info.slot_len[i] = 188; + ptr += 188; + } +@@ -1634,10 +1632,10 @@ int fiq_fsm_setup_periodic_dma(dwc_otg_h + * dma_addr_t) to point it to the correct offset in the + * allocated buffers. + */ +- blob = (struct fiq_dma_blob *) ++ split_dma = (struct fiq_dma_channel *) + (uintptr_t)hcd->fiq_state->dma_base; +- st->hcdma_copy.d32 = (u32)(uintptr_t) +- blob->channel[hc->hc_num].index[0].buf; ++ st->hcdma_copy.d32 = lower_32_bits((uintptr_t) ++ &split_dma[hc->hc_num].index[0].buf[0]); + + /* fixup xfersize to the actual packet size */ + st->hctsiz_copy.b.pid = 0; +@@ -1917,14 +1915,14 @@ int fiq_fsm_queue_split_transaction(dwc_ + if (hc->align_buff) { + st->hcdma_copy.d32 = hc->align_buff; + } else { +- st->hcdma_copy.d32 = ((unsigned long) hc->xfer_buff & 0xFFFFFFFF); ++ st->hcdma_copy.d32 = lower_32_bits((uintptr_t)hc->xfer_buff); + } + } + } else { + if (hc->align_buff) { + st->hcdma_copy.d32 = hc->align_buff; + } else { +- st->hcdma_copy.d32 = ((unsigned long) hc->xfer_buff & 0xFFFFFFFF); ++ st->hcdma_copy.d32 = lower_32_bits((uintptr_t)hc->xfer_buff); + } + } + /* The FIQ depends upon no other interrupts being enabled except channel halt. +@@ -1944,7 +1942,7 @@ int fiq_fsm_queue_split_transaction(dwc_ + if (hc->align_buff) { + st->hcdma_copy.d32 = hc->align_buff; + } else { +- st->hcdma_copy.d32 = ((unsigned long) hc->xfer_buff & 0xFFFFFFFF); ++ st->hcdma_copy.d32 = lower_32_bits((uintptr_t)hc->xfer_buff); + } + } + DWC_WRITE_REG32(&hc_regs->hcdma, st->hcdma_copy.d32); +--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.h ++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.h +@@ -88,7 +88,7 @@ struct dwc_otg_hcd_urb { + uint32_t flags; + uint16_t interval; + struct dwc_otg_hcd_pipe_info pipe_info; +- struct dwc_otg_hcd_iso_packet_desc iso_descs[0]; ++ struct dwc_otg_hcd_iso_packet_desc iso_descs[]; + }; + + static inline uint8_t dwc_otg_hcd_get_ep_num(struct dwc_otg_hcd_pipe_info *pipe) +@@ -592,7 +592,7 @@ struct dwc_otg_hcd { + struct fiq_state *fiq_state; + + /** Virtual address for split transaction DMA bounce buffers */ +- struct fiq_dma_blob *fiq_dmab; ++ struct fiq_dma_channel *fiq_dmab; + + #ifdef DEBUG + uint32_t frrem_samples; +--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c ++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c +@@ -2332,7 +2332,7 @@ void dwc_otg_fiq_unmangle_isoc(dwc_otg_h + int dwc_otg_fiq_unsetup_per_dma(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh, dwc_otg_qtd_t *qtd, uint32_t num) + { + dwc_hc_t *hc = qh->channel; +- struct fiq_dma_blob *blob = hcd->fiq_dmab; ++ struct fiq_dma_channel *split_dma = hcd->fiq_dmab; + struct fiq_channel_state *st = &hcd->fiq_state->channel[num]; + uint8_t *ptr = NULL; + int index = 0, len = 0; +@@ -2352,7 +2352,7 @@ int dwc_otg_fiq_unsetup_per_dma(dwc_otg_ + + for (i = 0; i < st->dma_info.index; i++) { + len += st->dma_info.slot_len[i]; +- dwc_memcpy(ptr, &blob->channel[num].index[i].buf[0], st->dma_info.slot_len[i]); ++ dwc_memcpy(ptr, &split_dma[num].index[i].buf[0], st->dma_info.slot_len[i]); + ptr += st->dma_info.slot_len[i]; + } + return len; diff --git a/target/linux/bcm27xx/patches-6.6/950-1147-media-uapi-pixfmt-luma-Document-MIPI-CSI-2-packing.patch b/target/linux/bcm27xx/patches-6.6/950-1147-media-uapi-pixfmt-luma-Document-MIPI-CSI-2-packing.patch new file mode 100644 index 0000000000..14d0a79a73 --- /dev/null +++ b/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 +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 +Reviewed-by: Laurent Pinchart +Reviewed-by: Naushir Patuck +--- + Documentation/userspace-api/media/v4l/pixfmt-yuv-luma.rst | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/Documentation/userspace-api/media/v4l/pixfmt-yuv-luma.rst ++++ b/Documentation/userspace-api/media/v4l/pixfmt-yuv-luma.rst +@@ -161,3 +161,7 @@ are often referred to as greyscale forma + For Y012 and Y12 formats, Y012 places its data in the 12 high bits, with + padding zeros in the 4 low bits, in contrast to the Y12 format, which has + its padding located in the most significant bits of the 16 bit word. ++ ++ The 'P' variations of the Y10, Y12 and Y14 formats are packed according to ++ the RAW10, RAW12 and RAW14 packing scheme as defined by the MIPI CSI-2 ++ specification. diff --git a/target/linux/bcm27xx/patches-6.6/950-1148-media-uapi-Add-a-pixel-format-for-BGR48-and-RGB48.patch b/target/linux/bcm27xx/patches-6.6/950-1148-media-uapi-Add-a-pixel-format-for-BGR48-and-RGB48.patch new file mode 100644 index 0000000000..2f459044a3 --- /dev/null +++ b/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 +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 +Reviewed-by: Kieran Bingham +Reviewed-by: Naushir Patuck +--- + .../userspace-api/media/v4l/pixfmt-rgb.rst | 54 +++++++++++++++++++ + drivers/media/v4l2-core/v4l2-common.c | 2 + + include/uapi/linux/videodev2.h | 2 + + 3 files changed, 58 insertions(+) + +--- a/Documentation/userspace-api/media/v4l/pixfmt-rgb.rst ++++ b/Documentation/userspace-api/media/v4l/pixfmt-rgb.rst +@@ -996,6 +996,60 @@ arranged in little endian order. + + \normalsize + ++16 Bits Per Component ++===================== ++ ++These formats store an RGB triplet in six bytes, with 16 bits per component ++stored in memory in little endian byte order. They are named based on the order ++of the RGB components as stored in memory. For instance, RGB48 stores R\ ++:sub:`7:0` and R\ :sub:`15:8` in bytes 0 and 1 respectively. This differs from ++the DRM format nomenclature that instead uses the order of components as seen in ++the 48-bits little endian word. ++ ++.. raw:: latex ++ ++ \small ++ ++.. flat-table:: RGB Formats With 16 Bits Per Component ++ :header-rows: 1 ++ ++ * - Identifier ++ - Code ++ - Byte 0 ++ - Byte 1 ++ - Byte 2 ++ - Byte 3 ++ - Byte 4 ++ - Byte 5 ++ ++ * .. _V4L2-PIX-FMT-BGR48: ++ ++ - ``V4L2_PIX_FMT_BGR48`` ++ - 'BGR6' ++ ++ - B\ :sub:`7-0` ++ - B\ :sub:`15-8` ++ - G\ :sub:`7-0` ++ - G\ :sub:`15-8` ++ - R\ :sub:`7-0` ++ - R\ :sub:`15-8` ++ ++ * .. _V4L2-PIX-FMT-RGB48: ++ ++ - ``V4L2_PIX_FMT_RGB48`` ++ - 'RGB6' ++ ++ - R\ :sub:`7-0` ++ - R\ :sub:`15-8` ++ - G\ :sub:`7-0` ++ - G\ :sub:`15-8` ++ - B\ :sub:`7-0` ++ - B\ :sub:`15-8` ++ ++.. raw:: latex ++ ++ \normalsize ++ + Deprecated RGB Formats + ====================== + +--- a/drivers/media/v4l2-core/v4l2-common.c ++++ b/drivers/media/v4l2-core/v4l2-common.c +@@ -253,6 +253,8 @@ const struct v4l2_format_info *v4l2_form + { .format = V4L2_PIX_FMT_RGB555, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_BGR666, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_BGR48_12, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, ++ { .format = V4L2_PIX_FMT_BGR48, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, ++ { .format = V4L2_PIX_FMT_RGB48, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_ABGR64_12, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 8, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, + + /* YUV packed formats */ +--- a/include/uapi/linux/videodev2.h ++++ b/include/uapi/linux/videodev2.h +@@ -587,6 +587,8 @@ struct v4l2_pix_format { + + /* RGB formats (6 or 8 bytes per pixel) */ + #define V4L2_PIX_FMT_BGR48_12 v4l2_fourcc('B', '3', '1', '2') /* 48 BGR 12-bit per component */ ++#define V4L2_PIX_FMT_BGR48 v4l2_fourcc('B', 'G', 'R', '6') /* 48 BGR 16-bit per component */ ++#define V4L2_PIX_FMT_RGB48 v4l2_fourcc('R', 'G', 'B', '6') /* 48 RGB 16-bit per component */ + #define V4L2_PIX_FMT_ABGR64_12 v4l2_fourcc('B', '4', '1', '2') /* 64 BGRA 12-bit per component */ + + /* RGB formats (6 bytes per pixel) */ diff --git a/target/linux/bcm27xx/patches-6.6/950-1149-media-uapi-Add-Raspberry-Pi-PiSP-Back-End-uAPI.patch b/target/linux/bcm27xx/patches-6.6/950-1149-media-uapi-Add-Raspberry-Pi-PiSP-Back-End-uAPI.patch new file mode 100644 index 0000000000..a59bcb1e97 --- /dev/null +++ b/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 +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 +--- + MAINTAINERS | 7 + + .../linux/media/raspberrypi/pisp_be_config.h | 927 ++++++++++++++++++ + .../linux/media/raspberrypi/pisp_common.h | 199 ++++ + 3 files changed, 1133 insertions(+) + create mode 100644 include/uapi/linux/media/raspberrypi/pisp_be_config.h + create mode 100644 include/uapi/linux/media/raspberrypi/pisp_common.h + +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -18032,6 +18032,13 @@ L: linux-wireless@vger.kernel.org + S: Orphan + F: drivers/net/wireless/legacy/ray* + ++RASPBERRY PI PISP BACK END ++M: Jacopo Mondi ++L: Raspberry Pi Kernel Maintenance ++L: linux-media@vger.kernel.org ++S: Maintained ++F: include/uapi/linux/media/raspberrypi/ ++ + RC-CORE / LIRC FRAMEWORK + M: Sean Young + L: linux-media@vger.kernel.org +--- /dev/null ++++ b/include/uapi/linux/media/raspberrypi/pisp_be_config.h +@@ -0,0 +1,927 @@ ++/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ ++/* ++ * PiSP Back End configuration definitions. ++ * ++ * Copyright (C) 2021 - Raspberry Pi Ltd ++ * ++ */ ++#ifndef _UAPI_PISP_BE_CONFIG_H_ ++#define _UAPI_PISP_BE_CONFIG_H_ ++ ++#include ++ ++#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 ++ ++struct pisp_image_format_config { ++ /* size in pixels */ ++ __u16 width; ++ __u16 height; ++ /* must match struct pisp_image_format below */ ++ __u32 format; ++ __s32 stride; ++ /* some planar image formats will need a second stride */ ++ __s32 stride2; ++} __attribute__((packed)); ++ ++enum pisp_bayer_order { ++ /* ++ * Note how bayer_order&1 tells you if G is on the even pixels of the ++ * checkerboard or not, and bayer_order&2 tells you if R is on the even ++ * rows or is swapped with B. Note that if the top (of the 8) bits is ++ * set, this denotes a monochrome or greyscale image, and the lower bits ++ * should all be ignored. ++ */ ++ PISP_BAYER_ORDER_RGGB = 0, ++ PISP_BAYER_ORDER_GBRG = 1, ++ PISP_BAYER_ORDER_BGGR = 2, ++ PISP_BAYER_ORDER_GRBG = 3, ++ PISP_BAYER_ORDER_GREYSCALE = 128 ++}; ++ ++enum pisp_image_format { ++ /* ++ * Precise values are mostly tbd. Generally these will be portmanteau ++ * values comprising bit fields and flags. This format must be shared ++ * throughout the PiSP. ++ */ ++ PISP_IMAGE_FORMAT_BPS_8 = 0x00000000, ++ PISP_IMAGE_FORMAT_BPS_10 = 0x00000001, ++ PISP_IMAGE_FORMAT_BPS_12 = 0x00000002, ++ PISP_IMAGE_FORMAT_BPS_16 = 0x00000003, ++ PISP_IMAGE_FORMAT_BPS_MASK = 0x00000003, ++ ++ PISP_IMAGE_FORMAT_PLANARITY_INTERLEAVED = 0x00000000, ++ PISP_IMAGE_FORMAT_PLANARITY_SEMI_PLANAR = 0x00000010, ++ PISP_IMAGE_FORMAT_PLANARITY_PLANAR = 0x00000020, ++ PISP_IMAGE_FORMAT_PLANARITY_MASK = 0x00000030, ++ ++ PISP_IMAGE_FORMAT_SAMPLING_444 = 0x00000000, ++ PISP_IMAGE_FORMAT_SAMPLING_422 = 0x00000100, ++ PISP_IMAGE_FORMAT_SAMPLING_420 = 0x00000200, ++ PISP_IMAGE_FORMAT_SAMPLING_MASK = 0x00000300, ++ ++ PISP_IMAGE_FORMAT_ORDER_NORMAL = 0x00000000, ++ PISP_IMAGE_FORMAT_ORDER_SWAPPED = 0x00001000, ++ ++ PISP_IMAGE_FORMAT_SHIFT_0 = 0x00000000, ++ PISP_IMAGE_FORMAT_SHIFT_1 = 0x00010000, ++ PISP_IMAGE_FORMAT_SHIFT_2 = 0x00020000, ++ PISP_IMAGE_FORMAT_SHIFT_3 = 0x00030000, ++ PISP_IMAGE_FORMAT_SHIFT_4 = 0x00040000, ++ PISP_IMAGE_FORMAT_SHIFT_5 = 0x00050000, ++ PISP_IMAGE_FORMAT_SHIFT_6 = 0x00060000, ++ PISP_IMAGE_FORMAT_SHIFT_7 = 0x00070000, ++ PISP_IMAGE_FORMAT_SHIFT_8 = 0x00080000, ++ PISP_IMAGE_FORMAT_SHIFT_MASK = 0x000f0000, ++ ++ PISP_IMAGE_FORMAT_UNCOMPRESSED = 0x00000000, ++ PISP_IMAGE_FORMAT_COMPRESSION_MODE_1 = 0x01000000, ++ PISP_IMAGE_FORMAT_COMPRESSION_MODE_2 = 0x02000000, ++ PISP_IMAGE_FORMAT_COMPRESSION_MODE_3 = 0x03000000, ++ PISP_IMAGE_FORMAT_COMPRESSION_MASK = 0x03000000, ++ ++ PISP_IMAGE_FORMAT_HOG_SIGNED = 0x04000000, ++ PISP_IMAGE_FORMAT_HOG_UNSIGNED = 0x08000000, ++ PISP_IMAGE_FORMAT_INTEGRAL_IMAGE = 0x10000000, ++ PISP_IMAGE_FORMAT_WALLPAPER_ROLL = 0x20000000, ++ PISP_IMAGE_FORMAT_THREE_CHANNEL = 0x40000000, ++ ++ /* Lastly a few specific instantiations of the above. */ ++ PISP_IMAGE_FORMAT_SINGLE_16 = PISP_IMAGE_FORMAT_BPS_16, ++ PISP_IMAGE_FORMAT_THREE_16 = PISP_IMAGE_FORMAT_BPS_16 | ++ PISP_IMAGE_FORMAT_THREE_CHANNEL ++}; ++ ++#define PISP_IMAGE_FORMAT_bps_8(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) == PISP_IMAGE_FORMAT_BPS_8) ++#define PISP_IMAGE_FORMAT_bps_10(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) == PISP_IMAGE_FORMAT_BPS_10) ++#define PISP_IMAGE_FORMAT_bps_12(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) == PISP_IMAGE_FORMAT_BPS_12) ++#define PISP_IMAGE_FORMAT_bps_16(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) == PISP_IMAGE_FORMAT_BPS_16) ++#define PISP_IMAGE_FORMAT_bps(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) ? \ ++ 8 + (2 << (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) - 1)) : 8) ++#define PISP_IMAGE_FORMAT_shift(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_SHIFT_MASK) / PISP_IMAGE_FORMAT_SHIFT_1) ++#define PISP_IMAGE_FORMAT_three_channel(fmt) \ ++ ((fmt) & PISP_IMAGE_FORMAT_THREE_CHANNEL) ++#define PISP_IMAGE_FORMAT_single_channel(fmt) \ ++ (!((fmt) & PISP_IMAGE_FORMAT_THREE_CHANNEL)) ++#define PISP_IMAGE_FORMAT_compressed(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_COMPRESSION_MASK) != \ ++ PISP_IMAGE_FORMAT_UNCOMPRESSED) ++#define PISP_IMAGE_FORMAT_sampling_444(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_SAMPLING_MASK) == \ ++ PISP_IMAGE_FORMAT_SAMPLING_444) ++#define PISP_IMAGE_FORMAT_sampling_422(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_SAMPLING_MASK) == \ ++ PISP_IMAGE_FORMAT_SAMPLING_422) ++#define PISP_IMAGE_FORMAT_sampling_420(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_SAMPLING_MASK) == \ ++ PISP_IMAGE_FORMAT_SAMPLING_420) ++#define PISP_IMAGE_FORMAT_order_normal(fmt) \ ++ (!((fmt) & PISP_IMAGE_FORMAT_ORDER_SWAPPED)) ++#define PISP_IMAGE_FORMAT_order_swapped(fmt) \ ++ ((fmt) & PISP_IMAGE_FORMAT_ORDER_SWAPPED) ++#define PISP_IMAGE_FORMAT_interleaved(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_PLANARITY_MASK) == \ ++ PISP_IMAGE_FORMAT_PLANARITY_INTERLEAVED) ++#define PISP_IMAGE_FORMAT_semiplanar(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_PLANARITY_MASK) == \ ++ PISP_IMAGE_FORMAT_PLANARITY_SEMI_PLANAR) ++#define PISP_IMAGE_FORMAT_planar(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_PLANARITY_MASK) == \ ++ PISP_IMAGE_FORMAT_PLANARITY_PLANAR) ++#define PISP_IMAGE_FORMAT_wallpaper(fmt) \ ++ ((fmt) & PISP_IMAGE_FORMAT_WALLPAPER_ROLL) ++#define PISP_IMAGE_FORMAT_HOG(fmt) \ ++ ((fmt) & \ ++ (PISP_IMAGE_FORMAT_HOG_SIGNED | PISP_IMAGE_FORMAT_HOG_UNSIGNED)) ++ ++#define PISP_WALLPAPER_WIDTH 128 /* in bytes */ ++ ++struct pisp_bla_config { ++ __u16 black_level_r; ++ __u16 black_level_gr; ++ __u16 black_level_gb; ++ __u16 black_level_b; ++ __u16 output_black_level; ++ __u8 pad[2]; ++} __attribute__((packed)); ++ ++struct pisp_wbg_config { ++ __u16 gain_r; ++ __u16 gain_g; ++ __u16 gain_b; ++ __u8 pad[2]; ++} __attribute__((packed)); ++ ++struct pisp_compress_config { ++ /* value subtracted from incoming data */ ++ __u16 offset; ++ __u8 pad; ++ /* 1 => Companding; 2 => Delta (recommended); 3 => Combined (for HDR) */ ++ __u8 mode; ++} __attribute__((packed)); ++ ++struct pisp_decompress_config { ++ /* value added to reconstructed data */ ++ __u16 offset; ++ __u8 pad; ++ /* 1 => Companding; 2 => Delta (recommended); 3 => Combined (for HDR) */ ++ __u8 mode; ++} __attribute__((packed)); ++ ++enum pisp_axi_flags { ++ /* ++ * round down bursts to end at a 32-byte boundary, to align following ++ * bursts ++ */ ++ PISP_AXI_FLAG_ALIGN = 128, ++ /* for FE writer: force WSTRB high, to pad output to 16-byte boundary */ ++ PISP_AXI_FLAG_PAD = 64, ++ /* for FE writer: Use Output FIFO level to trigger "panic" */ ++ PISP_AXI_FLAG_PANIC = 32, ++}; ++ ++struct pisp_axi_config { ++ /* ++ * burst length minus one, which must be in the range 0:15; OR'd with ++ * flags ++ */ ++ __u8 maxlen_flags; ++ /* { prot[2:0], cache[3:0] } fields, echoed on AXI bus */ ++ __u8 cache_prot; ++ /* QoS field(s) (4x4 bits for FE writer; 4 bits for other masters) */ ++ __u16 qos; ++} __attribute__((packed)); ++ ++#endif /* _UAPI_PISP_COMMON_H_ */ diff --git a/target/linux/bcm27xx/patches-6.6/950-1150-media-uapi-Document-meta-pixel-format-for-PiSP-BE-co.patch b/target/linux/bcm27xx/patches-6.6/950-1150-media-uapi-Document-meta-pixel-format-for-PiSP-BE-co.patch new file mode 100644 index 0000000000..0ee62a7d33 --- /dev/null +++ b/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 +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 +Reviewed-by: Naushir Patuck +--- + .../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 ++`_ ++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 ++`_. ++ ++.. kernel-doc:: include/uapi/linux/media/raspberrypi/pisp_be_config.h diff --git a/target/linux/bcm27xx/patches-6.6/950-1151-media-uapi-Document-PiSP-Compressed-RAW-Bayer-format.patch b/target/linux/bcm27xx/patches-6.6/950-1151-media-uapi-Document-PiSP-Compressed-RAW-Bayer-format.patch new file mode 100644 index 0000000000..aa4b003e5b --- /dev/null +++ b/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 +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 + from Raspberry Pi. + +Signed-off-by: Jacopo Mondi +Reviewed-by: Naushir Patuck +--- + .../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 ++`_. diff --git a/target/linux/bcm27xx/patches-6.6/950-1152-media-dt-bindings-Add-bindings-for-Raspberry-Pi-PiSP.patch b/target/linux/bcm27xx/patches-6.6/950-1152-media-dt-bindings-Add-bindings-for-Raspberry-Pi-PiSP.patch new file mode 100644 index 0000000000..30c5cb3506 --- /dev/null +++ b/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 +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 +Reviewed-by: Rob Herring +Reviewed-by: Naushir Patuck +--- + .../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 ++ - Jacopo Mondi ++ ++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 ++ ++ soc { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ++ isp@880000 { ++ compatible = "brcm,bcm2712-pispbe", "raspberrypi,pispbe"; ++ reg = <0x10 0x00880000 0x0 0x4000>; ++ interrupts = ; ++ clocks = <&firmware_clocks 7>; ++ iommus = <&iommu2>; ++ }; ++ }; +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -18037,6 +18037,7 @@ M: Jacopo Mondi + L: linux-media@vger.kernel.org + S: Maintained ++F: Documentation/devicetree/bindings/media/raspberrypi,pispbe.yaml + F: include/uapi/linux/media/raspberrypi/ + + RC-CORE / LIRC FRAMEWORK diff --git a/target/linux/bcm27xx/patches-6.6/950-1153-media-admin-guide-Document-the-Raspberry-Pi-PiSP-BE.patch b/target/linux/bcm27xx/patches-6.6/950-1153-media-admin-guide-Document-the-Raspberry-Pi-PiSP-BE.patch new file mode 100644 index 0000000000..f443cc78c7 --- /dev/null +++ b/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 +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 +--- + .../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="{{ 0 | 1 | 2 | 7} | pispbe\n | { 3 | 4 | 5 | 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 ++`_. ++ ++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 `_ as ++part of the Raspberry Pi platform support. ++ ++The pisp-be driver ++================== ++ ++The Raspberry Pi PiSP Back End (pisp-be) driver is located under ++drivers/media/platform/raspberrypi/pisp-be. It uses the `V4L2 API` to register ++a number of video capture and output devices, the `V4L2 subdev API` to register ++a subdevice for the ISP that connects the video devices in a single media graph ++realized using the `Media Controller (MC) API`. ++ ++The media topology registered by the `pisp-be` driver is represented below: ++ ++.. _pips-be-topology: ++ ++.. kernel-figure:: raspberrypi-pisp-be.dot ++ :alt: Diagram of the default media pipeline topology ++ :align: center ++ ++ ++The media graph registers the following video device nodes: ++ ++- pispbe-input: output device for images to be submitted to the ISP for ++ processing. ++- pispbe-tdn_input: output device for temporal denoise. ++- pispbe-stitch_input: output device for image stitching (HDR). ++- pispbe-output0: first capture device for processed images. ++- pispbe-output1: second capture device for processed images. ++- pispbe-tdn_output: capture device for temporal denoise. ++- pispbe-stitch_output: capture device for image stitching (HDR). ++- pispbe-config: output device for ISP configuration parameters. ++ ++pispbe-input ++------------ ++ ++Images to be processed by the ISP are queued to the `pispbe-input` output device ++node. For a list of image formats supported as input to the ISP refer to the ++`Raspberry Pi Image Signal Processor (PiSP) Specification document`_. ++ ++pispbe-tdn_input, pispbe-tdn_output ++----------------------------------- ++ ++The `pispbe-tdn_input` output video device receives images to be processed by ++the temporal denoise block which are captured from the `pispbe-tdn_output` ++capture video device. Userspace is responsible for maintaining queues on both ++devices, and ensuring that buffers completed on the output are queued to the ++input. ++ ++pispbe-stitch_input, pispbe-stitch_output ++----------------------------------------- ++ ++To realize HDR (high dynamic range) image processing the image stitching and ++tonemapping blocks are used. The `pispbe-stitch_output` writes images to memory ++and the `pispbe-stitch_input` receives the previously written frame to process ++it along with the current input image. Userspace is responsible for maintaining ++queues on both devices, and ensuring that buffers completed on the output are ++queued to the input. ++ ++pispbe-output0, pispbe-output1 ++------------------------------ ++ ++The two capture devices write to memory the pixel data as processed by the ISP. ++ ++pispbe-config ++------------- ++ ++The `pispbe-config` output video devices receives a buffer of configuration ++parameters that define the desired image processing to be performed by the ISP. ++ ++The format of the ISP configuration parameter is defined by ++:c:type:`pisp_be_tiles_config` C structure and the meaning of each parameter is ++described in the `Raspberry Pi Image Signal Processor (PiSP) Specification ++document`_. ++ ++ISP configuration ++================= ++ ++The ISP configuration is described solely by the content of the parameters ++buffer. The only parameter that userspace needs to configure using the V4L2 API ++is the image format on the output and capture video devices for validation of ++the content of the parameters buffer. ++ ++.. _Raspberry Pi Image Signal Processor (PiSP) Specification document: https://datasheets.raspberrypi.com/camera/raspberry-pi-image-signal-processor-specification.pdf +--- a/Documentation/admin-guide/media/v4l-drivers.rst ++++ b/Documentation/admin-guide/media/v4l-drivers.rst +@@ -21,6 +21,7 @@ Video4Linux (V4L) driver-specific docume + omap4_camera + philips + qcom_camss ++ raspberrypi-pisp-be + rcar-fdp1 + rkisp1 + saa7134 diff --git a/target/linux/bcm27xx/patches-6.6/950-1154-media-pisp-be-Backport-the-mainline-PiSP-BE-driver.patch b/target/linux/bcm27xx/patches-6.6/950-1154-media-pisp-be-Backport-the-mainline-PiSP-BE-driver.patch new file mode 100644 index 0000000000..a0123995fe --- /dev/null +++ b/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 +Date: Thu, 27 Jun 2024 11:41:22 +0200 +Subject: [PATCH 1154/1215] media: pisp-be: Backport the mainline PiSP BE + driver + +Backport to rpi-6.6.y the mainline version of the PiSP BE driver. + +The backported version of the driver corresponds to the one available +at: +https://lore.kernel.org/all/20240626181440.195137-1-jacopo.mondi@ideasonboard.com/ + +Signed-off-by: Jacopo Mondi +--- + .../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 + #include + #include ++#include ++#include + #include + #include + #include +@@ -15,49 +17,39 @@ + #include + #include + +-#include "pisp_be_config.h" +-#include "pisp_be_formats.h" +- +-MODULE_DESCRIPTION("PiSP Back End driver"); +-MODULE_AUTHOR("David Plowman "); +-MODULE_AUTHOR("Nick Hollinghurst "); +-MODULE_LICENSE("GPL v2"); ++#include + +-/* 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 + * 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 "); ++MODULE_AUTHOR("Nick Hollinghurst "); ++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 +- +-#include +- +-/* 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 + #include + +-#define MAX_PLANES 3 +-#define P3(x) ((x) * 8) ++#define PISPBE_MAX_PLANES 3 ++#define P3(x) ((x) * 8) + + struct pisp_be_format { + unsigned int fourcc; + unsigned int align; + unsigned int bit_depth; + /* 0P3 factor for plane sizing */ +- unsigned int plane_factor[MAX_PLANES]; ++ unsigned int plane_factor[PISPBE_MAX_PLANES]; + unsigned int num_planes; + unsigned int colorspace_mask; + enum v4l2_colorspace colorspace_default; +@@ -27,14 +27,19 @@ struct pisp_be_format { + + #define V4L2_COLORSPACE_MASK(colorspace) BIT(colorspace) + +-#define V4L2_COLORSPACE_MASK_JPEG V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_JPEG) +-#define V4L2_COLORSPACE_MASK_SMPTE170M V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_SMPTE170M) +-#define V4L2_COLORSPACE_MASK_REC709 V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_REC709) +-#define V4L2_COLORSPACE_MASK_SRGB V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_SRGB) +-#define V4L2_COLORSPACE_MASK_RAW V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_RAW) ++#define V4L2_COLORSPACE_MASK_JPEG \ ++ V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_JPEG) ++#define V4L2_COLORSPACE_MASK_SMPTE170M \ ++ V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_SMPTE170M) ++#define V4L2_COLORSPACE_MASK_REC709 \ ++ V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_REC709) ++#define V4L2_COLORSPACE_MASK_SRGB \ ++ V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_SRGB) ++#define V4L2_COLORSPACE_MASK_RAW \ ++ V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_RAW) + + /* +- * All three colour spaces JPEG, SMPTE170M and REC709 are fundamentally sRGB ++ * All three colour spaces SRGB, SMPTE170M and REC709 are fundamentally sRGB + * underneath (as near as makes no difference to us), just with different YCbCr + * encodings. Therefore the ISP can generate sRGB on its main output and any of + * the others on its low resolution output. Applications should, when using both +@@ -43,9 +48,9 @@ struct pisp_be_format { + * producing an RGB format. In turn this requires us to allow all these colour + * spaces for every YUV/RGB output format. + */ +-#define V4L2_COLORSPACE_MASK_ALL_SRGB (V4L2_COLORSPACE_MASK_JPEG | \ +- V4L2_COLORSPACE_MASK_SRGB | \ +- V4L2_COLORSPACE_MASK_SMPTE170M | \ ++#define V4L2_COLORSPACE_MASK_ALL_SRGB (V4L2_COLORSPACE_MASK_JPEG | \ ++ V4L2_COLORSPACE_MASK_SRGB | \ ++ V4L2_COLORSPACE_MASK_SMPTE170M | \ + V4L2_COLORSPACE_MASK_REC709) + + static const struct pisp_be_format supported_formats[] = { +@@ -58,7 +63,7 @@ static const struct pisp_be_format suppo + .plane_factor = { P3(1), P3(0.25), P3(0.25) }, + .num_planes = 1, + .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, +- .colorspace_default = V4L2_COLORSPACE_JPEG, ++ .colorspace_default = V4L2_COLORSPACE_SMPTE170M, + }, + { + .fourcc = V4L2_PIX_FMT_YVU420, +@@ -132,7 +137,7 @@ static const struct pisp_be_format suppo + .plane_factor = { P3(1), P3(0.25), P3(0.25) }, + .num_planes = 3, + .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, +- .colorspace_default = V4L2_COLORSPACE_JPEG, ++ .colorspace_default = V4L2_COLORSPACE_SMPTE170M, + }, + { + .fourcc = V4L2_PIX_FMT_NV12M, +@@ -168,7 +173,7 @@ static const struct pisp_be_format suppo + .plane_factor = { P3(1), P3(0.5), P3(0.5) }, + .num_planes = 3, + .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, +- .colorspace_default = V4L2_COLORSPACE_JPEG, ++ .colorspace_default = V4L2_COLORSPACE_SMPTE170M, + }, + { + .fourcc = V4L2_PIX_FMT_YVU422M, +@@ -186,7 +191,7 @@ static const struct pisp_be_format suppo + .plane_factor = { P3(1), P3(1), P3(1) }, + .num_planes = 3, + .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, +- .colorspace_default = V4L2_COLORSPACE_JPEG, ++ .colorspace_default = V4L2_COLORSPACE_SMPTE170M, + }, + { + .fourcc = V4L2_PIX_FMT_YVU444M, +@@ -502,11 +507,6 @@ static const struct pisp_be_format suppo + .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, + .colorspace_default = V4L2_COLORSPACE_RAW, + }, +- /* Opaque BE format for HW verification. */ +- { +- .fourcc = V4L2_PIX_FMT_RPI_BE, +- .align = 32, +- }, + }; + + static const struct pisp_be_format meta_out_supported_formats[] = { diff --git a/target/linux/bcm27xx/patches-6.6/950-1155-media-uapi-pisp_be_config-Drop-BIT-from-uAPI.patch b/target/linux/bcm27xx/patches-6.6/950-1155-media-uapi-pisp_be_config-Drop-BIT-from-uAPI.patch new file mode 100644 index 0000000000..f59c02c5b1 --- /dev/null +++ b/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 +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 +Reviewed-by: Tomi Valkeinen +--- + include/uapi/linux/media/raspberrypi/pisp_be_config.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/include/uapi/linux/media/raspberrypi/pisp_be_config.h ++++ b/include/uapi/linux/media/raspberrypi/pisp_be_config.h +@@ -146,7 +146,7 @@ struct pisp_be_dpc_config { + */ + struct pisp_be_geq_config { + __u16 offset; +-#define PISP_BE_GEQ_SHARPER BIT(15) ++#define PISP_BE_GEQ_SHARPER (1U << 15) + #define PISP_BE_GEQ_SLOPE ((1 << 10) - 1) + /* top bit is the "sharper" flag, slope value is bottom 10 bits */ + __u16 slope_sharper; diff --git a/target/linux/bcm27xx/patches-6.6/950-1156-media-uapi-pisp_common-Add-32-bpp-format-test.patch b/target/linux/bcm27xx/patches-6.6/950-1156-media-uapi-pisp_common-Add-32-bpp-format-test.patch new file mode 100644 index 0000000000..0cb94fe933 --- /dev/null +++ b/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 +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 +--- + include/uapi/linux/media/raspberrypi/pisp_common.h | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/include/uapi/linux/media/raspberrypi/pisp_common.h ++++ b/include/uapi/linux/media/raspberrypi/pisp_common.h +@@ -72,6 +72,8 @@ enum pisp_image_format { + PISP_IMAGE_FORMAT_SHIFT_8 = 0x00080000, + PISP_IMAGE_FORMAT_SHIFT_MASK = 0x000f0000, + ++ PISP_IMAGE_FORMAT_BPP_32 = 0x00100000, ++ + PISP_IMAGE_FORMAT_UNCOMPRESSED = 0x00000000, + PISP_IMAGE_FORMAT_COMPRESSION_MODE_1 = 0x01000000, + PISP_IMAGE_FORMAT_COMPRESSION_MODE_2 = 0x02000000, +@@ -134,6 +136,7 @@ enum pisp_image_format { + PISP_IMAGE_FORMAT_PLANARITY_PLANAR) + #define PISP_IMAGE_FORMAT_wallpaper(fmt) \ + ((fmt) & PISP_IMAGE_FORMAT_WALLPAPER_ROLL) ++#define PISP_IMAGE_FORMAT_bpp_32(fmt) ((fmt) & PISP_IMAGE_FORMAT_BPP_32) + #define PISP_IMAGE_FORMAT_HOG(fmt) \ + ((fmt) & \ + (PISP_IMAGE_FORMAT_HOG_SIGNED | PISP_IMAGE_FORMAT_HOG_UNSIGNED)) diff --git a/target/linux/bcm27xx/patches-6.6/950-1157-media-uapi-Capitalize-all-macros.patch b/target/linux/bcm27xx/patches-6.6/950-1157-media-uapi-Capitalize-all-macros.patch new file mode 100644 index 0000000000..fac2ccf163 --- /dev/null +++ b/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 +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 +--- + .../linux/media/raspberrypi/pisp_common.h | 38 +++++++++---------- + 1 file changed, 19 insertions(+), 19 deletions(-) + +--- a/include/uapi/linux/media/raspberrypi/pisp_common.h ++++ b/include/uapi/linux/media/raspberrypi/pisp_common.h +@@ -92,51 +92,51 @@ enum pisp_image_format { + PISP_IMAGE_FORMAT_THREE_CHANNEL + }; + +-#define PISP_IMAGE_FORMAT_bps_8(fmt) \ ++#define PISP_IMAGE_FORMAT_BPS_8(fmt) \ + (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) == PISP_IMAGE_FORMAT_BPS_8) +-#define PISP_IMAGE_FORMAT_bps_10(fmt) \ ++#define PISP_IMAGE_FORMAT_BPS_10(fmt) \ + (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) == PISP_IMAGE_FORMAT_BPS_10) +-#define PISP_IMAGE_FORMAT_bps_12(fmt) \ ++#define PISP_IMAGE_FORMAT_BPS_12(fmt) \ + (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) == PISP_IMAGE_FORMAT_BPS_12) +-#define PISP_IMAGE_FORMAT_bps_16(fmt) \ ++#define PISP_IMAGE_FORMAT_BPS_16(fmt) \ + (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) == PISP_IMAGE_FORMAT_BPS_16) +-#define PISP_IMAGE_FORMAT_bps(fmt) \ ++#define PISP_IMAGE_FORMAT_BPS(fmt) \ + (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) ? \ + 8 + (2 << (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) - 1)) : 8) +-#define PISP_IMAGE_FORMAT_shift(fmt) \ ++#define PISP_IMAGE_FORMAT_SHIFT(fmt) \ + (((fmt) & PISP_IMAGE_FORMAT_SHIFT_MASK) / PISP_IMAGE_FORMAT_SHIFT_1) +-#define PISP_IMAGE_FORMAT_three_channel(fmt) \ ++#define PISP_IMAGE_FORMAT_THREE_CHANNEL(fmt) \ + ((fmt) & PISP_IMAGE_FORMAT_THREE_CHANNEL) +-#define PISP_IMAGE_FORMAT_single_channel(fmt) \ ++#define PISP_IMAGE_FORMAT_SINGLE_CHANNEL(fmt) \ + (!((fmt) & PISP_IMAGE_FORMAT_THREE_CHANNEL)) +-#define PISP_IMAGE_FORMAT_compressed(fmt) \ ++#define PISP_IMAGE_FORMAT_COMPRESSED(fmt) \ + (((fmt) & PISP_IMAGE_FORMAT_COMPRESSION_MASK) != \ + PISP_IMAGE_FORMAT_UNCOMPRESSED) +-#define PISP_IMAGE_FORMAT_sampling_444(fmt) \ ++#define PISP_IMAGE_FORMAT_SAMPLING_444(fmt) \ + (((fmt) & PISP_IMAGE_FORMAT_SAMPLING_MASK) == \ + PISP_IMAGE_FORMAT_SAMPLING_444) +-#define PISP_IMAGE_FORMAT_sampling_422(fmt) \ ++#define PISP_IMAGE_FORMAT_SAMPLING_422(fmt) \ + (((fmt) & PISP_IMAGE_FORMAT_SAMPLING_MASK) == \ + PISP_IMAGE_FORMAT_SAMPLING_422) +-#define PISP_IMAGE_FORMAT_sampling_420(fmt) \ ++#define PISP_IMAGE_FORMAT_SAMPLING_420(fmt) \ + (((fmt) & PISP_IMAGE_FORMAT_SAMPLING_MASK) == \ + PISP_IMAGE_FORMAT_SAMPLING_420) +-#define PISP_IMAGE_FORMAT_order_normal(fmt) \ ++#define PISP_IMAGE_FORMAT_ORDER_NORMAL(fmt) \ + (!((fmt) & PISP_IMAGE_FORMAT_ORDER_SWAPPED)) +-#define PISP_IMAGE_FORMAT_order_swapped(fmt) \ ++#define PISP_IMAGE_FORMAT_ORDER_SWAPPED(fmt) \ + ((fmt) & PISP_IMAGE_FORMAT_ORDER_SWAPPED) +-#define PISP_IMAGE_FORMAT_interleaved(fmt) \ ++#define PISP_IMAGE_FORMAT_INTERLEAVED(fmt) \ + (((fmt) & PISP_IMAGE_FORMAT_PLANARITY_MASK) == \ + PISP_IMAGE_FORMAT_PLANARITY_INTERLEAVED) +-#define PISP_IMAGE_FORMAT_semiplanar(fmt) \ ++#define PISP_IMAGE_FORMAT_SEMIPLANAR(fmt) \ + (((fmt) & PISP_IMAGE_FORMAT_PLANARITY_MASK) == \ + PISP_IMAGE_FORMAT_PLANARITY_SEMI_PLANAR) +-#define PISP_IMAGE_FORMAT_planar(fmt) \ ++#define PISP_IMAGE_FORMAT_PLANAR(fmt) \ + (((fmt) & PISP_IMAGE_FORMAT_PLANARITY_MASK) == \ + PISP_IMAGE_FORMAT_PLANARITY_PLANAR) +-#define PISP_IMAGE_FORMAT_wallpaper(fmt) \ ++#define PISP_IMAGE_FORMAT_WALLPAPER(fmt) \ + ((fmt) & PISP_IMAGE_FORMAT_WALLPAPER_ROLL) +-#define PISP_IMAGE_FORMAT_bpp_32(fmt) ((fmt) & PISP_IMAGE_FORMAT_BPP_32) ++#define PISP_IMAGE_FORMAT_BPP_32(fmt) ((fmt) & PISP_IMAGE_FORMAT_BPP_32) + #define PISP_IMAGE_FORMAT_HOG(fmt) \ + ((fmt) & \ + (PISP_IMAGE_FORMAT_HOG_SIGNED | PISP_IMAGE_FORMAT_HOG_UNSIGNED)) diff --git a/target/linux/bcm27xx/patches-6.6/950-1158-media-uapi-pisp_be_config-Re-sort-pisp_be_tiles_conf.patch b/target/linux/bcm27xx/patches-6.6/950-1158-media-uapi-pisp_be_config-Re-sort-pisp_be_tiles_conf.patch new file mode 100644 index 0000000000..49ff9d73ff --- /dev/null +++ b/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 +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 +--- + include/uapi/linux/media/raspberrypi/pisp_be_config.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/include/uapi/linux/media/raspberrypi/pisp_be_config.h ++++ b/include/uapi/linux/media/raspberrypi/pisp_be_config.h +@@ -919,9 +919,9 @@ struct pisp_tile { + * @config: PiSP Back End configuration + */ + struct pisp_be_tiles_config { ++ struct pisp_be_config config; + struct pisp_tile tiles[PISP_BACK_END_NUM_TILES]; + __u32 num_tiles; +- struct pisp_be_config config; + } __attribute__((packed)); + + #endif /* _UAPI_PISP_BE_CONFIG_H_ */ diff --git a/target/linux/bcm27xx/patches-6.6/950-1159-media-uapi-pisp_be_config-Add-extra-config-fields.patch b/target/linux/bcm27xx/patches-6.6/950-1159-media-uapi-pisp_be_config-Add-extra-config-fields.patch new file mode 100644 index 0000000000..d18d12ec67 --- /dev/null +++ b/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 +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 +--- + .../linux/media/raspberrypi/pisp_be_config.h | 41 +++++++++++++++++++ + 1 file changed, 41 insertions(+) + +--- a/include/uapi/linux/media/raspberrypi/pisp_be_config.h ++++ b/include/uapi/linux/media/raspberrypi/pisp_be_config.h +@@ -716,6 +716,13 @@ struct pisp_be_hog_buffer_config { + /** + * struct pisp_be_config - RaspberryPi PiSP Back End Processing configuration + * ++ * @input_buffer: Input buffer addresses ++ * @tdn_input_buffer: TDN input buffer addresses ++ * @stitch_input_buffer: Stitch input buffer addresses ++ * @tdn_output_buffer: TDN output buffer addresses ++ * @stitch_output_buffer: Stitch output buffer addresses ++ * @output_buffer: Output buffers addresses ++ * @hog_buffer: HOG buffer addresses + * @global: Global PiSP configuration + * @input_format: Input image format + * @decompress: Decompress configuration +@@ -753,8 +760,30 @@ struct pisp_be_hog_buffer_config { + * @resample: Resampling configuration + * @output_format: Output format configuration + * @hog: HOG configuration ++ * @axi: AXI bus configuration ++ * @lsc_extra: LSC extra info ++ * @cac_extra: CAC extra info ++ * @downscale_extra: Downscaler extra info ++ * @resample_extra: Resample extra info ++ * @crop: Crop configuration ++ * @hog_format: HOG format info ++ * @dirty_flags_bayer: Bayer enable dirty flags ++ * (:c:type:`pisp_be_bayer_enable`) ++ * @dirty_flags_rgb: RGB enable dirty flags ++ * (:c:type:`pisp_be_rgb_enable`) ++ * @dirty_flags_extra: Extra dirty flags + */ + struct pisp_be_config { ++ /* I/O configuration: */ ++ struct pisp_be_input_buffer_config input_buffer; ++ struct pisp_be_tdn_input_buffer_config tdn_input_buffer; ++ struct pisp_be_stitch_input_buffer_config stitch_input_buffer; ++ struct pisp_be_tdn_output_buffer_config tdn_output_buffer; ++ struct pisp_be_stitch_output_buffer_config stitch_output_buffer; ++ struct pisp_be_output_buffer_config ++ output_buffer[PISP_BACK_END_NUM_OUTPUTS]; ++ struct pisp_be_hog_buffer_config hog_buffer; ++ /* Processing configuration: */ + struct pisp_be_global_config global; + struct pisp_image_format_config input_format; + struct pisp_decompress_config decompress; +@@ -793,6 +822,18 @@ struct pisp_be_config { + struct pisp_be_output_format_config + output_format[PISP_BACK_END_NUM_OUTPUTS]; + struct pisp_be_hog_config hog; ++ struct pisp_be_axi_config axi; ++ /* Non-register fields: */ ++ struct pisp_be_lsc_extra lsc_extra; ++ struct pisp_be_cac_extra cac_extra; ++ struct pisp_be_downscale_extra ++ downscale_extra[PISP_BACK_END_NUM_OUTPUTS]; ++ struct pisp_be_resample_extra resample_extra[PISP_BACK_END_NUM_OUTPUTS]; ++ struct pisp_be_crop_config crop; ++ struct pisp_image_format_config hog_format; ++ __u32 dirty_flags_bayer; /* these use pisp_be_bayer_enable */ ++ __u32 dirty_flags_rgb; /* use pisp_be_rgb_enable */ ++ __u32 dirty_flags_extra; /* these use pisp_be_dirty_t */ + } __attribute__((packed)); + + /** diff --git a/target/linux/bcm27xx/patches-6.6/950-1160-media-pisp_be-Re-introduce-multi-context-support.patch b/target/linux/bcm27xx/patches-6.6/950-1160-media-pisp_be-Re-introduce-multi-context-support.patch new file mode 100644 index 0000000000..ad667a1e69 --- /dev/null +++ b/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 +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 +--- + .../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 + * to represent one of the PiSP Back End's input or output streams. + */ +-static int pispbe_init_node(struct pispbe_dev *pispbe, unsigned int id) ++static int pispbe_init_node(struct pispbe_node_group *node_group, ++ unsigned int id) + { + bool output = NODE_DESC_IS_OUTPUT(&node_desc[id]); +- struct pispbe_node *node = &pispbe->node[id]; ++ struct pispbe_node *node = &node_group->node[id]; + struct media_entity *entity = &node->vfd.entity; ++ struct pispbe_dev *pispbe = node_group->pispbe; + struct video_device *vdev = &node->vfd; + struct vb2_queue *q = &node->queue; + int ret; + + node->id = id; +- node->pispbe = pispbe; ++ node->node_group = node_group; + node->buf_type = node_desc[id].buf_type; + + mutex_init(&node->node_lock); +@@ -1419,7 +1456,7 @@ static int pispbe_init_node(struct pispb + q->ops = &pispbe_node_queue_ops; + q->buf_struct_size = sizeof(struct pispbe_buffer); + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; +- q->dev = pispbe->dev; ++ q->dev = node->node_group->pispbe->dev; + /* get V4L2 to handle node->queue locking */ + q->lock = &node->queue_lock; + +@@ -1431,7 +1468,7 @@ static int pispbe_init_node(struct pispb + + *vdev = pispbe_videodev; /* default initialization */ + strscpy(vdev->name, node_desc[id].ent_name, sizeof(vdev->name)); +- vdev->v4l2_dev = &pispbe->v4l2_dev; ++ vdev->v4l2_dev = &node_group->v4l2_dev; + vdev->vfl_dir = output ? VFL_DIR_TX : VFL_DIR_RX; + /* get V4L2 to serialise our ioctls */ + vdev->lock = &node->node_lock; +@@ -1457,11 +1494,11 @@ static int pispbe_init_node(struct pispb + video_set_drvdata(vdev, node); + + if (output) +- ret = media_create_pad_link(entity, 0, &pispbe->sd.entity, ++ ret = media_create_pad_link(entity, 0, &node_group->sd.entity, + id, MEDIA_LNK_FL_IMMUTABLE | + MEDIA_LNK_FL_ENABLED); + else +- ret = media_create_pad_link(&pispbe->sd.entity, id, entity, ++ ret = media_create_pad_link(&node_group->sd.entity, id, entity, + 0, MEDIA_LNK_FL_IMMUTABLE | + MEDIA_LNK_FL_ENABLED); + if (ret) +@@ -1490,9 +1527,10 @@ static const struct v4l2_subdev_ops pisp + .pad = &pispbe_pad_ops, + }; + +-static int pispbe_init_subdev(struct pispbe_dev *pispbe) ++static int pispbe_init_subdev(struct pispbe_node_group *node_group) + { +- struct v4l2_subdev *sd = &pispbe->sd; ++ struct pispbe_dev *pispbe = node_group->pispbe; ++ struct v4l2_subdev *sd = &node_group->sd; + int ret; + + v4l2_subdev_init(sd, &pispbe_sd_ops); +@@ -1502,16 +1540,16 @@ static int pispbe_init_subdev(struct pis + strscpy(sd->name, PISPBE_NAME, sizeof(sd->name)); + + for (unsigned int i = 0; i < PISPBE_NUM_NODES; i++) +- pispbe->pad[i].flags = ++ node_group->pad[i].flags = + NODE_DESC_IS_OUTPUT(&node_desc[i]) ? + MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE; + + ret = media_entity_pads_init(&sd->entity, PISPBE_NUM_NODES, +- pispbe->pad); ++ node_group->pad); + if (ret) + goto error; + +- ret = v4l2_device_register_subdev(&pispbe->v4l2_dev, sd); ++ ret = v4l2_device_register_subdev(&node_group->v4l2_dev, sd); + if (ret) + goto error; + +@@ -1522,36 +1560,43 @@ error: + return ret; + } + +-static int pispbe_init_devices(struct pispbe_dev *pispbe) ++static int pispbe_init_group(struct pispbe_dev *pispbe, unsigned int id) + { ++ struct pispbe_node_group *node_group = &pispbe->node_group[id]; + struct v4l2_device *v4l2_dev; + struct media_device *mdev; + unsigned int num_regist; + int ret; + ++ node_group->id = id; ++ node_group->pispbe = pispbe; ++ node_group->streaming_map = 0; ++ ++ dev_dbg(pispbe->dev, "Register nodes for group %u\n", id); ++ + /* Register v4l2_device and media_device */ +- mdev = &pispbe->mdev; +- mdev->hw_revision = pispbe->hw_version; +- mdev->dev = pispbe->dev; ++ mdev = &node_group->mdev; ++ mdev->hw_revision = node_group->pispbe->hw_version; ++ mdev->dev = node_group->pispbe->dev; + strscpy(mdev->model, PISPBE_NAME, sizeof(mdev->model)); + media_device_init(mdev); + +- v4l2_dev = &pispbe->v4l2_dev; +- v4l2_dev->mdev = &pispbe->mdev; ++ v4l2_dev = &node_group->v4l2_dev; ++ v4l2_dev->mdev = &node_group->mdev; + strscpy(v4l2_dev->name, PISPBE_NAME, sizeof(v4l2_dev->name)); + +- ret = v4l2_device_register(pispbe->dev, v4l2_dev); ++ ret = v4l2_device_register(pispbe->dev, &node_group->v4l2_dev); + if (ret) + goto err_media_dev_cleanup; + + /* Register the PISPBE subdevice. */ +- ret = pispbe_init_subdev(pispbe); ++ ret = pispbe_init_subdev(node_group); + if (ret) + goto err_unregister_v4l2; + + /* Create device video nodes */ + for (num_regist = 0; num_regist < PISPBE_NUM_NODES; num_regist++) { +- ret = pispbe_init_node(pispbe, num_regist); ++ ret = pispbe_init_node(node_group, num_regist); + if (ret) + goto err_unregister_nodes; + } +@@ -1560,12 +1605,12 @@ static int pispbe_init_devices(struct pi + if (ret) + goto err_unregister_nodes; + +- pispbe->config = ++ node_group->config = + dma_alloc_coherent(pispbe->dev, + sizeof(struct pisp_be_tiles_config) * + PISP_BE_NUM_CONFIG_BUFFERS, +- &pispbe->config_dma_addr, GFP_KERNEL); +- if (!pispbe->config) { ++ &node_group->config_dma_addr, GFP_KERNEL); ++ if (!node_group->config) { + dev_err(pispbe->dev, "Unable to allocate cached config buffers.\n"); + ret = -ENOMEM; + goto err_unregister_mdev; +@@ -1577,11 +1622,11 @@ err_unregister_mdev: + media_device_unregister(mdev); + err_unregister_nodes: + while (num_regist-- > 0) { +- video_unregister_device(&pispbe->node[num_regist].vfd); +- vb2_queue_release(&pispbe->node[num_regist].queue); ++ video_unregister_device(&node_group->node[num_regist].vfd); ++ vb2_queue_release(&node_group->node[num_regist].queue); + } +- v4l2_device_unregister_subdev(&pispbe->sd); +- media_entity_cleanup(&pispbe->sd.entity); ++ v4l2_device_unregister_subdev(&node_group->sd); ++ media_entity_cleanup(&node_group->sd.entity); + err_unregister_v4l2: + v4l2_device_unregister(v4l2_dev); + err_media_dev_cleanup: +@@ -1589,31 +1634,33 @@ err_media_dev_cleanup: + return ret; + } + +-static void pispbe_destroy_devices(struct pispbe_dev *pispbe) ++static void pispbe_destroy_node_group(struct pispbe_node_group *node_group) + { +- if (pispbe->config) { +- dma_free_coherent(pispbe->dev, ++ struct pispbe_dev *pispbe = node_group->pispbe; ++ ++ if (node_group->config) { ++ dma_free_coherent(node_group->pispbe->dev, + sizeof(struct pisp_be_tiles_config) * + PISP_BE_NUM_CONFIG_BUFFERS, +- pispbe->config, +- pispbe->config_dma_addr); ++ node_group->config, ++ node_group->config_dma_addr); + } + + dev_dbg(pispbe->dev, "Unregister from media controller\n"); + +- v4l2_device_unregister_subdev(&pispbe->sd); +- media_entity_cleanup(&pispbe->sd.entity); +- media_device_unregister(&pispbe->mdev); ++ v4l2_device_unregister_subdev(&node_group->sd); ++ media_entity_cleanup(&node_group->sd.entity); ++ media_device_unregister(&node_group->mdev); + + for (int i = PISPBE_NUM_NODES - 1; i >= 0; i--) { +- video_unregister_device(&pispbe->node[i].vfd); +- vb2_queue_release(&pispbe->node[i].queue); +- mutex_destroy(&pispbe->node[i].node_lock); +- mutex_destroy(&pispbe->node[i].queue_lock); ++ video_unregister_device(&node_group->node[i].vfd); ++ vb2_queue_release(&node_group->node[i].queue); ++ mutex_destroy(&node_group->node[i].node_lock); ++ mutex_destroy(&node_group->node[i].queue_lock); + } + +- media_device_cleanup(&pispbe->mdev); +- v4l2_device_unregister(&pispbe->v4l2_dev); ++ media_device_cleanup(&node_group->mdev); ++ v4l2_device_unregister(&node_group->v4l2_dev); + } + + static int pispbe_runtime_suspend(struct device *dev) +@@ -1681,9 +1728,13 @@ static int pispbe_hw_init(struct pispbe_ + return 0; + } + +-/* Probe the ISP-BE hardware block, as a single platform device. */ ++/* ++ * Probe the ISP-BE hardware block, as a single platform device. ++ * This will instantiate multiple "node groups" each with many device nodes. ++ */ + static int pispbe_probe(struct platform_device *pdev) + { ++ unsigned int num_groups = 0; + struct pispbe_dev *pispbe; + int ret; + +@@ -1738,17 +1789,26 @@ static int pispbe_probe(struct platform_ + if (ret) + goto pm_runtime_suspend_err; + +- ret = pispbe_init_devices(pispbe); +- if (ret) +- goto disable_devs_err; ++ /* ++ * Initialise and register devices for each node_group, including media ++ * device ++ */ ++ for (num_groups = 0; ++ num_groups < PISPBE_NUM_NODE_GROUPS; ++ num_groups++) { ++ ret = pispbe_init_group(pispbe, num_groups); ++ if (ret) ++ goto disable_nodes_err; ++ } + + pm_runtime_mark_last_busy(pispbe->dev); + pm_runtime_put_autosuspend(pispbe->dev); + + return 0; + +-disable_devs_err: +- pispbe_destroy_devices(pispbe); ++disable_nodes_err: ++ while (num_groups-- > 0) ++ pispbe_destroy_node_group(&pispbe->node_group[num_groups]); + pm_runtime_suspend_err: + pispbe_runtime_suspend(pispbe->dev); + pm_runtime_disable_err: +@@ -1762,7 +1822,8 @@ static int pispbe_remove(struct platform + { + struct pispbe_dev *pispbe = platform_get_drvdata(pdev); + +- pispbe_destroy_devices(pispbe); ++ for (int i = PISPBE_NUM_NODE_GROUPS - 1; i >= 0; i--) ++ pispbe_destroy_node_group(&pispbe->node_group[i]); + + pispbe_runtime_suspend(pispbe->dev); + pm_runtime_dont_use_autosuspend(pispbe->dev); diff --git a/target/linux/bcm27xx/patches-6.6/950-1161-media-pisp_be-Re-introduce-video-node-offset.patch b/target/linux/bcm27xx/patches-6.6/950-1161-media-pisp_be-Re-introduce-video-node-offset.patch new file mode 100644 index 0000000000..0586f5c620 --- /dev/null +++ b/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 +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 +--- + drivers/media/platform/raspberrypi/pisp_be/pisp_be.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/drivers/media/platform/raspberrypi/pisp_be/pisp_be.c ++++ b/drivers/media/platform/raspberrypi/pisp_be/pisp_be.c +@@ -21,6 +21,9 @@ + + #include "pisp_be_formats.h" + ++/* Offset to use when registering the /dev/videoX node */ ++#define PISPBE_VIDEO_NODE_OFFSET 20 ++ + /* Maximum number of config buffers possible */ + #define PISP_BE_NUM_CONFIG_BUFFERS VB2_MAX_FRAME + +@@ -1484,7 +1487,8 @@ static int pispbe_init_node(struct pispb + goto err_unregister_queue; + } + +- ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); ++ ret = video_register_device(vdev, VFL_TYPE_VIDEO, ++ PISPBE_VIDEO_NODE_OFFSET); + if (ret) { + dev_err(pispbe->dev, + "Failed to register video %s device node\n", diff --git a/target/linux/bcm27xx/patches-6.6/950-1163-dts-Make-camN_reg-and-camN_reg_gpio-overrides-generi.patch b/target/linux/bcm27xx/patches-6.6/950-1163-dts-Make-camN_reg-and-camN_reg_gpio-overrides-generi.patch new file mode 100644 index 0000000000..38c1d3b9b6 --- /dev/null +++ b/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 +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 +--- + .../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=", ; + ++ cam0_reg = <&cam0_reg>,"status"; ++ cam0_reg_gpio = <&cam0_reg>,"gpio:4", ++ <&cam0_reg>,"gpio:0=", <&gpio>; ++ cam1_reg = <&cam1_reg>,"status"; ++ cam1_reg_gpio = <&cam1_reg>,"gpio:4", ++ <&cam1_reg>,"gpio:0=", <&gpio>; ++ + strict_gpiod = <&chosen>, "bootargs=pinctrl_bcm2835.persist_gpio_outputs=n"; + }; + }; +--- a/arch/arm/boot/dts/broadcom/bcm2710-rpi-cm3.dts ++++ b/arch/arm/boot/dts/broadcom/bcm2710-rpi-cm3.dts +@@ -211,9 +211,5 @@ i2c_csi_dsi0: &i2c0 { + act_led_gpio = <&led_act>,"gpios:4"; + act_led_activelow = <&led_act>,"gpios:8"; + act_led_trigger = <&led_act>,"linux,default-trigger"; +- cam0_reg = <&cam0_reg>,"status"; +- cam0_reg_gpio = <&cam0_reg>,"gpio:4"; +- cam1_reg = <&cam1_reg>,"status"; +- cam1_reg_gpio = <&cam1_reg>,"gpio:4"; + }; + }; +--- a/arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4.dts ++++ b/arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4.dts +@@ -498,13 +498,6 @@ i2c_csi_dsi0: &i2c0 { + <&ant2>, "output-high?=off", + <&ant2>, "output-low?=on"; + +- cam0_reg = <&cam0_reg>,"status"; +- cam0_reg_gpio = <&cam0_reg>,"gpio:4", +- <&cam0_reg>,"gpio:0=", <&gpio>; +- cam1_reg = <&cam1_reg>,"status"; +- cam1_reg_gpio = <&cam1_reg>,"gpio:4", +- <&cam1_reg>,"gpio:0=", <&gpio>; +- + pcie_tperst_clk_ms = <&pcie0>,"brcm,tperst-clk-ms:0"; + }; + }; +--- a/arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4s.dts ++++ b/arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4s.dts +@@ -289,10 +289,5 @@ i2c_csi_dsi0: &i2c0 { + act_led_gpio = <&led_act>,"gpios:4"; + act_led_activelow = <&led_act>,"gpios:8"; + act_led_trigger = <&led_act>,"linux,default-trigger"; +- +- cam0_reg = <&cam0_reg>,"status"; +- cam0_reg_gpio = <&cam0_reg>,"gpio:4"; +- cam1_reg = <&cam1_reg>,"status"; +- cam1_reg_gpio = <&cam1_reg>,"gpio:4"; + }; + }; +--- a/arch/arm/boot/dts/broadcom/bcm2712-rpi.dtsi ++++ b/arch/arm/boot/dts/broadcom/bcm2712-rpi.dtsi +@@ -106,6 +106,14 @@ + nvmem_priv_rw = <&nvmem_priv>,"rw?"; + nvmem_mac_rw = <&nvmem_mac>,"rw?"; + strict_gpiod = <&chosen>, "bootargs=pinctrl_rp1.persist_gpio_outputs=n"; ++ ++ cam0_reg = <&cam0_reg>,"status"; ++ cam0_reg_gpio = <&cam0_reg>,"gpio:4", ++ <&cam0_reg>,"gpio:0=", <&gpio>; ++ cam1_reg = <&cam1_reg>,"status"; ++ cam1_reg_gpio = <&cam1_reg>,"gpio:4", ++ <&cam1_reg>,"gpio:0=", <&gpio>; ++ + }; + }; + +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -171,21 +171,21 @@ Params: + button_debounce Set the debounce delay (in ms) on the power/ + shutdown button (default 50ms) + +- cam0_reg Enables CAM 0 regulator. +- Only required on CM1 & 3. ++ cam0_reg Controls CAM 0 regulator. ++ Disabled by default on CM1 & 3. ++ Enabled by default on all other boards. + + cam0_reg_gpio Set GPIO for CAM 0 regulator. +- Default 31 on CM1, 3, and 4S. +- Default of GPIO expander 5 on CM4, but override +- switches to normal GPIO. ++ NB override switches to the normal GPIO driver, ++ even if the original was on the GPIO expander. + +- cam1_reg Enables CAM 1 regulator. +- Only required on CM1 & 3. ++ cam1_reg Controls CAM 1 regulator. ++ Disabled by default on CM1 & 3. ++ Enabled by default on all other boards. + + cam1_reg_gpio Set GPIO for CAM 1 regulator. +- Default 3 on CM1, 3, and 4S. +- Default of GPIO expander 5 on CM4, but override +- switches to normal GPIO. ++ NB override switches to the normal GPIO driver, ++ even if the original was on the GPIO expander. + + cam0_sync Enable a GPIO to reflect frame sync from CSI0, + going high on frame start, and low on frame end. diff --git a/target/linux/bcm27xx/patches-6.6/950-1164-spi-dt-bindings-Add-RPI-RP2040-GPIO-Bridge.patch b/target/linux/bcm27xx/patches-6.6/950-1164-spi-dt-bindings-Add-RPI-RP2040-GPIO-Bridge.patch new file mode 100644 index 0000000000..487e508ea4 --- /dev/null +++ b/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 +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 +--- + .../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 ++ ++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 ++S: Maintained ++F: Documentation/devicetree/bindings/spi/raspberrypi,rp2040-gpio-bridge.yaml ++ + RAYLINK/WEBGEAR 802.11 WIRELESS LAN DRIVER + L: linux-wireless@vger.kernel.org + S: Orphan diff --git a/target/linux/bcm27xx/patches-6.6/950-1165-spi-Add-a-driver-for-the-RPI-RP2040-GPIO-bridge.patch b/target/linux/bcm27xx/patches-6.6/950-1165-spi-Add-a-driver-for-the-RPI-RP2040-GPIO-bridge.patch new file mode 100644 index 0000000000..68e2ef6007 --- /dev/null +++ b/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 +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 +--- + 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 + S: Maintained + F: Documentation/devicetree/bindings/spi/raspberrypi,rp2040-gpio-bridge.yaml ++F: drivers/spi/spi-rp2040-gpio-bridge.c + + RAYLINK/WEBGEAR 802.11 WIRELESS LAN DRIVER + L: linux-wireless@vger.kernel.org +--- a/drivers/spi/Kconfig ++++ b/drivers/spi/Kconfig +@@ -846,6 +846,18 @@ config SPI_RB4XX + help + SPI controller driver for the Mikrotik RB4xx series boards. + ++config SPI_RP2040_GPIO_BRIDGE ++ tristate "Raspberry Pi RP2040 GPIO Bridge" ++ depends on I2C && SPI && GPIOLIB ++ help ++ Support for the Raspberry Pi RP2040 GPIO bridge. ++ ++ This driver provides support for the Raspberry Pi PR2040 GPIO bridge. ++ It can be used as a GPIO expander and a Tx-only SPI master. ++ ++ Optionally, this driver is able to take advantage of Raspberry Pi RP1 ++ GPIOs to achieve faster than I2C data transfer rates. ++ + config SPI_RPCIF + tristate "Renesas RPC-IF SPI driver" + depends on RENESAS_RPCIF +--- a/drivers/spi/Makefile ++++ b/drivers/spi/Makefile +@@ -115,6 +115,7 @@ obj-$(CONFIG_SPI_ROCKCHIP) += spi-rockc + obj-$(CONFIG_SPI_ROCKCHIP_SFC) += spi-rockchip-sfc.o + obj-$(CONFIG_SPI_RB4XX) += spi-rb4xx.o + obj-$(CONFIG_MACH_REALTEK_RTL) += spi-realtek-rtl.o ++obj-$(CONFIG_SPI_RP2040_GPIO_BRIDGE) += spi-rp2040-gpio-bridge.o + obj-$(CONFIG_SPI_RPCIF) += spi-rpc-if.o + obj-$(CONFIG_SPI_RSPI) += spi-rspi.o + obj-$(CONFIG_SPI_RZV2M_CSI) += spi-rzv2m-csi.o +--- /dev/null ++++ b/drivers/spi/spi-rp2040-gpio-bridge.c +@@ -0,0 +1,1219 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * RP2040 GPIO Bridge ++ * ++ * Copyright (C) 2023, 2024, Raspberry Pi Ltd ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 "); ++MODULE_DESCRIPTION("Raspberry Pi RP2040 GPIO Bridge"); ++MODULE_LICENSE("GPL"); diff --git a/target/linux/bcm27xx/patches-6.6/950-1166-dmaengine-dw-axi-dmac-Honour-snps-block-size.patch b/target/linux/bcm27xx/patches-6.6/950-1166-dmaengine-dw-axi-dmac-Honour-snps-block-size.patch new file mode 100644 index 0000000000..85b1cf6448 --- /dev/null +++ b/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 +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 +--- + drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 15 ++++++++++++++- + 1 file changed, 14 insertions(+), 1 deletion(-) + +--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c ++++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +@@ -1470,6 +1470,7 @@ static int dw_probe(struct platform_devi + struct dw_axi_dma *dw; + struct dw_axi_dma_hcfg *hdata; + struct reset_control *resets; ++ unsigned int max_seg_size; + unsigned int flags; + u32 i; + int ret; +@@ -1585,9 +1586,21 @@ static int dw_probe(struct platform_devi + * Synopsis DesignWare AxiDMA datasheet mentioned Maximum + * supported blocks is 1024. Device register width is 4 bytes. + * Therefore, set constraint to 1024 * 4. ++ * However, if all channels specify a greater value, use that instead. + */ ++ + dw->dma.dev->dma_parms = &dw->dma_parms; +- dma_set_max_seg_size(&pdev->dev, MAX_BLOCK_SIZE); ++ max_seg_size = UINT_MAX; ++ for (i = 0; i < dw->hdata->nr_channels; i++) { ++ unsigned int block_size = chip->dw->hdata->block_size[i]; ++ ++ if (!block_size) ++ block_size = MAX_BLOCK_SIZE; ++ max_seg_size = min(block_size, max_seg_size); ++ } ++ ++ dma_set_max_seg_size(&pdev->dev, max_seg_size); ++ + platform_set_drvdata(pdev, chip); + + pm_runtime_enable(chip->dev); diff --git a/target/linux/bcm27xx/patches-6.6/950-1167-mmc-restrict-posted-write-counts-for-SD-cards-in-CQ-.patch b/target/linux/bcm27xx/patches-6.6/950-1167-mmc-restrict-posted-write-counts-for-SD-cards-in-CQ-.patch new file mode 100644 index 0000000000..2ba494958e --- /dev/null +++ b/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 +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 +--- + drivers/mmc/core/block.c | 11 +++++++++-- + drivers/mmc/core/mmc.c | 1 + + drivers/mmc/core/queue.c | 9 +++++++++ + drivers/mmc/core/queue.h | 1 + + drivers/mmc/core/sd.c | 8 ++++++++ + include/linux/mmc/card.h | 2 ++ + 6 files changed, 30 insertions(+), 2 deletions(-) + +--- a/drivers/mmc/core/block.c ++++ b/drivers/mmc/core/block.c +@@ -1555,6 +1555,8 @@ static void mmc_blk_cqe_complete_rq(stru + + spin_lock_irqsave(&mq->lock, flags); + ++ if (req_op(req) == REQ_OP_WRITE) ++ mq->pending_writes--; + mq->in_flight[issue_type] -= 1; + + put_card = (mmc_tot_in_flight(mq) == 0); +@@ -2071,6 +2073,8 @@ static void mmc_blk_mq_complete_rq(struc + struct mmc_queue_req *mqrq = req_to_mmc_queue_req(req); + unsigned int nr_bytes = mqrq->brq.data.bytes_xfered; + ++ if (req_op(req) == REQ_OP_WRITE) ++ mq->pending_writes--; + if (nr_bytes) { + if (blk_update_request(req, BLK_STS_OK, nr_bytes)) + blk_mq_requeue_request(req, true); +@@ -2165,13 +2169,16 @@ static void mmc_blk_mq_poll_completion(s + mmc_blk_urgent_bkops(mq, mqrq); + } + +-static void mmc_blk_mq_dec_in_flight(struct mmc_queue *mq, enum mmc_issue_type issue_type) ++static void mmc_blk_mq_dec_in_flight(struct mmc_queue *mq, enum mmc_issue_type issue_type, ++ struct request *req) + { + unsigned long flags; + bool put_card; + + spin_lock_irqsave(&mq->lock, flags); + ++ if (req_op(req) == REQ_OP_WRITE) ++ mq->pending_writes--; + mq->in_flight[issue_type] -= 1; + + put_card = (mmc_tot_in_flight(mq) == 0); +@@ -2205,7 +2212,7 @@ static void mmc_blk_mq_post_req(struct m + blk_mq_complete_request(req); + } + +- mmc_blk_mq_dec_in_flight(mq, issue_type); ++ mmc_blk_mq_dec_in_flight(mq, issue_type, req); + } + + void mmc_blk_mq_recovery(struct mmc_queue *mq) +--- a/drivers/mmc/core/mmc.c ++++ b/drivers/mmc/core/mmc.c +@@ -1922,6 +1922,7 @@ static int mmc_init_card(struct mmc_host + pr_info("%s: Host Software Queue enabled\n", + mmc_hostname(host)); + } ++ card->max_posted_writes = card->ext_csd.cmdq_depth; + } + } + +--- a/drivers/mmc/core/queue.c ++++ b/drivers/mmc/core/queue.c +@@ -268,6 +268,11 @@ static blk_status_t mmc_mq_queue_rq(stru + spin_unlock_irq(&mq->lock); + return BLK_STS_RESOURCE; + } ++ if (host->cqe_enabled && req_op(req) == REQ_OP_WRITE && ++ mq->pending_writes >= card->max_posted_writes) { ++ spin_unlock_irq(&mq->lock); ++ return BLK_STS_RESOURCE; ++ } + break; + default: + /* +@@ -284,6 +289,8 @@ static blk_status_t mmc_mq_queue_rq(stru + /* Parallel dispatch of requests is not supported at the moment */ + mq->busy = true; + ++ if (req_op(req) == REQ_OP_WRITE) ++ mq->pending_writes++; + mq->in_flight[issue_type] += 1; + get_card = (mmc_tot_in_flight(mq) == 1); + cqe_retune_ok = (mmc_cqe_qcnt(mq) == 1); +@@ -323,6 +330,8 @@ static blk_status_t mmc_mq_queue_rq(stru + bool put_card = false; + + spin_lock_irq(&mq->lock); ++ if (req_op(req) == REQ_OP_WRITE) ++ mq->pending_writes--; + mq->in_flight[issue_type] -= 1; + if (mmc_tot_in_flight(mq) == 0) + put_card = true; +--- a/drivers/mmc/core/queue.h ++++ b/drivers/mmc/core/queue.h +@@ -79,6 +79,7 @@ struct mmc_queue { + struct request_queue *queue; + spinlock_t lock; + int in_flight[MMC_ISSUE_MAX]; ++ int pending_writes; + unsigned int cqe_busy; + #define MMC_CQE_DCMD_BUSY BIT(0) + bool busy; +--- a/drivers/mmc/core/sd.c ++++ b/drivers/mmc/core/sd.c +@@ -1104,6 +1104,14 @@ static int sd_parse_ext_reg_perf(struct + pr_debug("%s: Command Queue supported depth %u\n", + mmc_hostname(card->host), + card->ext_csd.cmdq_depth); ++ /* ++ * If CQ is enabled, there is a contract between host and card such that VDD will ++ * be maintained and removed only if a power off notification is provided. ++ * An SD card in an accessible slot means surprise removal is a possibility. ++ * As a middle ground, limit max posted writes to 1 unless the card is "hardwired". ++ */ ++ if (mmc_card_is_removable(card->host)) ++ card->max_posted_writes = 1; + } + + card->ext_perf.fno = fno; +--- a/include/linux/mmc/card.h ++++ b/include/linux/mmc/card.h +@@ -343,6 +343,8 @@ struct mmc_card { + unsigned int nr_parts; + + struct workqueue_struct *complete_wq; /* Private workqueue */ ++ ++ unsigned int max_posted_writes; /* command queue posted write limit */ + }; + + static inline bool mmc_large_sector(struct mmc_card *card) diff --git a/target/linux/bcm27xx/patches-6.6/950-1168-fixup-mmc-restrict-posted-write-counts-for-SD-cards-.patch b/target/linux/bcm27xx/patches-6.6/950-1168-fixup-mmc-restrict-posted-write-counts-for-SD-cards-.patch new file mode 100644 index 0000000000..4f1d02c74d --- /dev/null +++ b/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 +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 +--- + drivers/mmc/core/mmc.c | 1 + + drivers/mmc/core/queue.c | 2 +- + drivers/mmc/core/sd.c | 14 ++++++++------ + 3 files changed, 10 insertions(+), 7 deletions(-) + +--- a/drivers/mmc/core/mmc.c ++++ b/drivers/mmc/core/mmc.c +@@ -1663,6 +1663,7 @@ static int mmc_init_card(struct mmc_host + card->ocr = ocr; + card->type = MMC_TYPE_MMC; + card->rca = 1; ++ card->max_posted_writes = 1; + memcpy(card->raw_cid, cid, sizeof(card->raw_cid)); + } + +--- a/drivers/mmc/core/queue.c ++++ b/drivers/mmc/core/queue.c +@@ -268,7 +268,7 @@ static blk_status_t mmc_mq_queue_rq(stru + spin_unlock_irq(&mq->lock); + return BLK_STS_RESOURCE; + } +- if (host->cqe_enabled && req_op(req) == REQ_OP_WRITE && ++ if (!host->hsq_enabled && host->cqe_enabled && req_op(req) == REQ_OP_WRITE && + mq->pending_writes >= card->max_posted_writes) { + spin_unlock_irq(&mq->lock); + return BLK_STS_RESOURCE; +--- a/drivers/mmc/core/sd.c ++++ b/drivers/mmc/core/sd.c +@@ -1105,13 +1105,14 @@ static int sd_parse_ext_reg_perf(struct + mmc_hostname(card->host), + card->ext_csd.cmdq_depth); + /* +- * If CQ is enabled, there is a contract between host and card such that VDD will +- * be maintained and removed only if a power off notification is provided. +- * An SD card in an accessible slot means surprise removal is a possibility. +- * As a middle ground, limit max posted writes to 1 unless the card is "hardwired". ++ * If CQ is enabled, there is a contract between host and card such that ++ * VDD will be maintained and removed only if a power off notification ++ * is provided. An SD card in an accessible slot means surprise removal ++ * is a possibility. As a middle ground, keep the default maximum of 1 ++ * posted write unless the card is "hardwired". + */ +- if (mmc_card_is_removable(card->host)) +- card->max_posted_writes = 1; ++ if (!mmc_card_is_removable(card->host)) ++ card->max_posted_writes = card->ext_csd.cmdq_depth; + } + + card->ext_perf.fno = fno; +@@ -1383,6 +1384,7 @@ retry: + + card->ocr = ocr; + card->type = MMC_TYPE_SD; ++ card->max_posted_writes = 1; + memcpy(card->raw_cid, cid, sizeof(card->raw_cid)); + } + diff --git a/target/linux/bcm27xx/patches-6.6/950-1169-mmc-brcmstb-don-t-squash-card-busy-detection-on-bcm2.patch b/target/linux/bcm27xx/patches-6.6/950-1169-mmc-brcmstb-don-t-squash-card-busy-detection-on-bcm2.patch new file mode 100644 index 0000000000..0d4d6cba19 --- /dev/null +++ b/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 +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 +--- + drivers/mmc/host/sdhci-brcmstb.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/mmc/host/sdhci-brcmstb.c ++++ b/drivers/mmc/host/sdhci-brcmstb.c +@@ -430,6 +430,7 @@ static const struct brcmstb_match_priv m + }; + + static const struct brcmstb_match_priv match_priv_2712 = { ++ .flags = BRCMSTB_MATCH_FLAGS_USE_CARD_BUSY, + .hs400es = sdhci_brcmstb_hs400es, + .cfginit = sdhci_brcmstb_cfginit_2712, + .ops = &sdhci_brcmstb_ops_2712, diff --git a/target/linux/bcm27xx/patches-6.6/950-1172-Revert-Update-DAC8x-to-support-384khz-6187.patch b/target/linux/bcm27xx/patches-6.6/950-1172-Revert-Update-DAC8x-to-support-384khz-6187.patch new file mode 100644 index 0000000000..1923b7aec0 --- /dev/null +++ b/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 +Date: Tue, 16 Jul 2024 11:20:54 +0200 +Subject: [PATCH 1172/1215] Revert "Update DAC8x to support 384khz (#6187)" + +This reverts commit dd7a15472b18d4bce738bb9213443c140473833b. +--- + sound/soc/bcm/rpi-simple-soundcard.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/sound/soc/bcm/rpi-simple-soundcard.c ++++ b/sound/soc/bcm/rpi-simple-soundcard.c +@@ -324,10 +324,10 @@ static int hifiberry_dac8x_init(struct s + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + + /* override the defaults to reflect 4 x PCM5102A on the card +- * and limit the sample rate to 384ksps ++ * and limit the sample rate to 192ksps + */ + codec_dai->driver->playback.channels_max = 8; +- codec_dai->driver->playback.rates = SNDRV_PCM_RATE_8000_384000; ++ codec_dai->driver->playback.rates = SNDRV_PCM_RATE_8000_192000; + + return 0; + } diff --git a/target/linux/bcm27xx/patches-6.6/950-1176-dt-bindings-clk-rp1-Add-clocks-representing-MIPI-DSI.patch b/target/linux/bcm27xx/patches-6.6/950-1176-dt-bindings-clk-rp1-Add-clocks-representing-MIPI-DSI.patch new file mode 100644 index 0000000000..af740bd305 --- /dev/null +++ b/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 +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 +--- + include/dt-bindings/clock/rp1.h | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/include/dt-bindings/clock/rp1.h ++++ b/include/dt-bindings/clock/rp1.h +@@ -54,3 +54,7 @@ + /* Extra PLL output channels - RP1B0 only */ + #define RP1_PLL_VIDEO_PRI_PH 43 + #define RP1_PLL_AUDIO_TERN 44 ++ ++/* MIPI clocks managed by the DSI driver */ ++#define RP1_CLK_MIPI0_DSI_BYTECLOCK 45 ++#define RP1_CLK_MIPI1_DSI_BYTECLOCK 46 diff --git a/target/linux/bcm27xx/patches-6.6/950-1177-clk-clk-rp1-Add-varsrc-clocks-to-represent-MIPI-byte.patch b/target/linux/bcm27xx/patches-6.6/950-1177-clk-clk-rp1-Add-varsrc-clocks-to-represent-MIPI-byte.patch new file mode 100644 index 0000000000..564ef84c9e --- /dev/null +++ b/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 +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 +--- + drivers/clk/clk-rp1.c | 73 +++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 73 insertions(+) + +--- a/drivers/clk/clk-rp1.c ++++ b/drivers/clk/clk-rp1.c +@@ -394,6 +394,11 @@ struct rp1_clock { + unsigned long cached_rate; + }; + ++struct rp1_varsrc { ++ struct clk_hw hw; ++ struct rp1_clockman *clockman; ++ unsigned long rate; ++}; + + struct rp1_clk_change { + struct clk_hw *hw; +@@ -1414,6 +1419,34 @@ static void rp1_clk_debug_init(struct cl + rp1_debugfs_regset(clockman, 0, regs, i, dentry); + } + ++static int rp1_varsrc_set_rate(struct clk_hw *hw, ++ unsigned long rate, unsigned long parent_rate) ++{ ++ struct rp1_varsrc *varsrc = container_of(hw, struct rp1_varsrc, hw); ++ ++ /* ++ * "varsrc" exists purely to let clock dividers know the frequency ++ * of an externally-managed clock source (such as MIPI DSI byte-clock) ++ * which may change at run-time as a side-effect of some other driver. ++ */ ++ varsrc->rate = rate; ++ return 0; ++} ++ ++static unsigned long rp1_varsrc_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ struct rp1_varsrc *varsrc = container_of(hw, struct rp1_varsrc, hw); ++ ++ return varsrc->rate; ++} ++ ++static long rp1_varsrc_round_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long *parent_rate) ++{ ++ return rate; ++} ++ + static const struct clk_ops rp1_pll_core_ops = { + .is_prepared = rp1_pll_core_is_on, + .prepare = rp1_pll_core_on, +@@ -1464,6 +1497,12 @@ static const struct clk_ops rp1_clk_ops + .debug_init = rp1_clk_debug_init, + }; + ++static const struct clk_ops rp1_varsrc_ops = { ++ .set_rate = rp1_varsrc_set_rate, ++ .recalc_rate = rp1_varsrc_recalc_rate, ++ .round_rate = rp1_varsrc_round_rate, ++}; ++ + static bool rp1_clk_is_claimed(const char *name); + + static struct clk_hw *rp1_register_pll_core(struct rp1_clockman *clockman, +@@ -1647,6 +1686,35 @@ static struct clk_hw *rp1_register_clock + return &clock->hw; + } + ++static struct clk_hw *rp1_register_varsrc(struct rp1_clockman *clockman, ++ const void *data) ++{ ++ const char *name = *(char const * const *)data; ++ struct rp1_varsrc *clock; ++ struct clk_init_data init; ++ int ret; ++ ++ memset(&init, 0, sizeof(init)); ++ init.parent_names = &ref_clock; ++ init.num_parents = 1; ++ init.name = name; ++ init.flags = CLK_IGNORE_UNUSED; ++ init.ops = &rp1_varsrc_ops; ++ ++ clock = devm_kzalloc(clockman->dev, sizeof(*clock), GFP_KERNEL); ++ if (!clock) ++ return NULL; ++ ++ clock->clockman = clockman; ++ clock->hw.init = &init; ++ ++ ret = devm_clk_hw_register(clockman->dev, &clock->hw); ++ if (ret) ++ return ERR_PTR(ret); ++ ++ return &clock->hw; ++} ++ + struct rp1_clk_desc { + struct clk_hw *(*clk_register)(struct rp1_clockman *clockman, + const void *data); +@@ -1676,6 +1744,8 @@ struct rp1_clk_desc { + &(struct rp1_clock_data) \ + {__VA_ARGS__}) + ++#define REGISTER_VARSRC(n) _REGISTER(&rp1_register_varsrc, &(const char *){n}) ++ + static const struct rp1_clk_desc clk_desc_array[] = { + [RP1_PLL_SYS_CORE] = REGISTER_PLL_CORE( + .name = "pll_sys_core", +@@ -2318,6 +2388,9 @@ static const struct rp1_clk_desc clk_des + .max_freq = 200 * MHz, + .fc0_src = FC_NUM(3, 6), + ), ++ ++ [RP1_CLK_MIPI0_DSI_BYTECLOCK] = REGISTER_VARSRC("clksrc_mipi0_dsi_byteclk"), ++ [RP1_CLK_MIPI1_DSI_BYTECLOCK] = REGISTER_VARSRC("clksrc_mipi1_dsi_byteclk"), + }; + + static bool rp1_clk_claimed[ARRAY_SIZE(clk_desc_array)]; diff --git a/target/linux/bcm27xx/patches-6.6/950-1178-dts-rp1-DSI-drivers-to-use-newly-defined-MIPI-byte-s.patch b/target/linux/bcm27xx/patches-6.6/950-1178-dts-rp1-DSI-drivers-to-use-newly-defined-MIPI-byte-s.patch new file mode 100644 index 0000000000..7e6032dd1f --- /dev/null +++ b/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 +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 +--- + 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 = ; + +- 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 = ; + +- clocks = <&rp1_clocks RP1_CLK_MIPI1_CFG>, // required, config bus clock +- <&rp1_clocks RP1_CLK_MIPI1_DPI>, // required, pixel clock +- <&clksrc_mipi1_dsi_byteclk>, // internal, parent for divide +- <&clk_xosc>; // hardwired to DSI "refclk" +- clock-names = "cfgclk", "dpiclk", "byteclk", "refclk"; ++ clocks = <&rp1_clocks RP1_CLK_MIPI1_CFG>, ++ <&rp1_clocks RP1_CLK_MIPI1_DPI>, ++ <&rp1_clocks RP1_CLK_MIPI1_DSI_BYTECLOCK>, ++ <&clk_xosc>, // hardwired to DSI "refclk" ++ <&rp1_clocks RP1_PLL_SYS>; // alternate parent for divide ++ clock-names = "cfgclk", "dpiclk", "byteclk", "refclk", "pllsys"; + +- assigned-clocks = <&rp1_clocks RP1_CLK_MIPI1_CFG>, +- <&rp1_clocks RP1_CLK_MIPI1_DPI>; ++ assigned-clocks = <&rp1_clocks RP1_CLK_MIPI1_CFG>; + assigned-clock-rates = <25000000>; +- assigned-clock-parents = <0>, <&clksrc_mipi1_dsi_byteclk>; + }; + + /* VEC and DPI both need to control PLL_VIDEO and cannot work together; */ +@@ -1216,24 +1214,6 @@ + clock-output-names = "core"; + clock-frequency = <50000000>; + }; +- clksrc_mipi0_dsi_byteclk: clksrc_mipi0_dsi_byteclk { +- // This clock is synthesized by MIPI0 D-PHY, when DSI is running. +- // Its frequency is not known a priori (until a panel driver attaches) +- // so assign a made-up frequency of 72MHz so it can be divided for DPI. +- compatible = "fixed-clock"; +- #clock-cells = <0>; +- clock-output-names = "clksrc_mipi0_dsi_byteclk"; +- clock-frequency = <72000000>; +- }; +- clksrc_mipi1_dsi_byteclk: clksrc_mipi1_dsi_byteclk { +- // This clock is synthesized by MIPI1 D-PHY, when DSI is running. +- // Its frequency is not known a priori (until a panel driver attaches) +- // so assign a made-up frequency of 72MHz so it can be divided for DPI. +- compatible = "fixed-clock"; +- #clock-cells = <0>; +- clock-output-names = "clksrc_mipi1_dsi_byteclk"; +- clock-frequency = <72000000>; +- }; + /* GPIO derived clock sources. Each GPIO with a GPCLK function + * can drive its output from the respective GPCLK + * generator, and provide a clock source to other internal diff --git a/target/linux/bcm27xx/patches-6.6/950-1179-drm-rp1-rp1-dsi-Switch-to-PLL_SYS-source-for-DPI-whe.patch b/target/linux/bcm27xx/patches-6.6/950-1179-drm-rp1-rp1-dsi-Switch-to-PLL_SYS-source-for-DPI-whe.patch new file mode 100644 index 0000000000..a80af9839d --- /dev/null +++ b/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 +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 +--- + 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 + #include ++#include + #include + #include + #include "drm/drm_print.h" +@@ -1111,7 +1112,7 @@ static void dphy_transaction(struct rp1_ + DSI_WRITE(DSI_PHY_TST_CTRL0, DPHY_CTRL0_PHY_TESTCLK_BITS); + } + +-static uint8_t dphy_get_div(u32 refclk_khz, u32 vco_freq_khz, u32 *ptr_m, u32 *ptr_n) ++static u64 dphy_get_div(u32 refclk, u64 vco_freq, u32 *ptr_m, u32 *ptr_n) + { + /* + * See pg 77-78 of dphy databook +@@ -1124,19 +1125,23 @@ static uint8_t dphy_get_div(u32 refclk_k + * In practice, given a 50MHz reference clock, it can produce any + * multiple of 10MHz, 11.1111MHz, 12.5MHz, 14.286MHz or 16.667MHz + * with < 1% error for all frequencies above 495MHz. ++ * ++ * vco_freq should be set to the lane bit rate (not the MIPI clock ++ * which is half of this). These frequencies are now measured in Hz. ++ * They should fit within u32, but u64 is needed for calculations. + */ + +- static const u32 REF_DIVN_MAX = 40000u; +- static const u32 REF_DIVN_MIN = 5000u; +- u32 best_n, best_m, best_err = 0x7fffffff; +- unsigned int n; ++ static const u32 REF_DIVN_MAX = 40000000; ++ static const u32 REF_DIVN_MIN = 5000000; ++ u32 n, best_n, best_m; ++ u64 best_err = vco_freq; + +- for (n = 1 + refclk_khz / REF_DIVN_MAX; n * REF_DIVN_MIN <= refclk_khz && n < 100; ++n) { +- u32 half_m = (n * vco_freq_khz + refclk_khz) / (2 * refclk_khz); ++ for (n = 1 + refclk / REF_DIVN_MAX; n * REF_DIVN_MIN <= refclk && n < 100; ++n) { ++ u32 half_m = DIV_U64_ROUND_CLOSEST(n * vco_freq, 2 * refclk); + + if (half_m < 150) { +- u32 f = (2 * half_m * refclk_khz) / n; +- u32 err = (f > vco_freq_khz) ? f - vco_freq_khz : vco_freq_khz - f; ++ u64 f = div_u64(mul_u32_u32(2 * half_m, refclk), n); ++ u64 err = (f > vco_freq) ? f - vco_freq : vco_freq - f; + + if (err < best_err) { + best_n = n; +@@ -1148,12 +1153,12 @@ static uint8_t dphy_get_div(u32 refclk_k + } + } + +- if (64 * best_err < vco_freq_khz) { /* tolerate small error */ +- *ptr_n = best_n; +- *ptr_m = best_m; +- return 1; +- } +- return 0; ++ if (64 * best_err >= vco_freq) ++ return 0; ++ ++ *ptr_n = best_n; ++ *ptr_m = best_m; ++ return div_u64(mul_u32_u32(best_m, refclk), best_n); + } + + struct hsfreq_range { +@@ -1226,13 +1231,14 @@ static void dphy_set_hsfreqrange(struct + hsfreq_table[i].hsfreqrange << 1); + } + +-static void dphy_configure_pll(struct rp1_dsi *dsi, u32 refclk_khz, u32 vco_freq_khz) ++static u32 dphy_configure_pll(struct rp1_dsi *dsi, u32 refclk, u32 vco_freq) + { + u32 m = 0; + u32 n = 0; ++ u32 actual_vco_freq = dphy_get_div(refclk, vco_freq, &m, &n); + +- if (dphy_get_div(refclk_khz, vco_freq_khz, &m, &n)) { +- dphy_set_hsfreqrange(dsi, vco_freq_khz / 1000); ++ if (actual_vco_freq) { ++ dphy_set_hsfreqrange(dsi, actual_vco_freq / 1000000); + /* Program m,n from registers */ + dphy_transaction(dsi, DPHY_PLL_DIV_CTRL_OFFSET, 0x30); + /* N (program N-1) */ +@@ -1242,18 +1248,21 @@ static void dphy_configure_pll(struct rp + /* M[4:0] (program M-1) */ + dphy_transaction(dsi, DPHY_PLL_LOOP_DIV_OFFSET, ((m - 1) & 0x1F)); + drm_dbg_driver(dsi->drm, +- "DPHY: vco freq want %dkHz got %dkHz = %d * (%dkHz / %d), hsfreqrange = 0x%02x\r\n", +- vco_freq_khz, refclk_khz * m / n, m, refclk_khz, +- n, hsfreq_table[dsi->hsfreq_index].hsfreqrange); ++ "DPHY: vco freq want %uHz got %uHz = %d * (%uHz / %d), hsfreqrange = 0x%02x\n", ++ vco_freq, actual_vco_freq, m, refclk, n, ++ hsfreq_table[dsi->hsfreq_index].hsfreqrange); + } else { +- drm_info(dsi->drm, +- "rp1dsi: Error configuring DPHY PLL! %dkHz = %d * (%dkHz / %d)\r\n", +- vco_freq_khz, m, refclk_khz, n); ++ drm_warn(dsi->drm, ++ "rp1dsi: Error configuring DPHY PLL %uHz\n", vco_freq); + } ++ ++ return actual_vco_freq; + } + +-static void dphy_init_khz(struct rp1_dsi *dsi, u32 ref_freq, u32 vco_freq) ++static u32 dphy_init(struct rp1_dsi *dsi, u32 ref_freq, u32 vco_freq) + { ++ u32 actual_vco_freq; ++ + /* Reset the PHY */ + DSI_WRITE(DSI_PHYRSTZ, 0); + DSI_WRITE(DSI_PHY_TST_CTRL0, DPHY_CTRL0_PHY_TESTCLK_BITS); +@@ -1263,13 +1272,15 @@ static void dphy_init_khz(struct rp1_dsi + DSI_WRITE(DSI_PHY_TST_CTRL0, DPHY_CTRL0_PHY_TESTCLK_BITS); + udelay(1); + /* Since we are in DSI (not CSI2) mode here, start the PLL */ +- dphy_configure_pll(dsi, ref_freq, vco_freq); ++ actual_vco_freq = dphy_configure_pll(dsi, ref_freq, vco_freq); + udelay(1); + /* Unreset */ + DSI_WRITE(DSI_PHYRSTZ, DSI_PHYRSTZ_SHUTDOWNZ_BITS); + udelay(1); + DSI_WRITE(DSI_PHYRSTZ, (DSI_PHYRSTZ_SHUTDOWNZ_BITS | DSI_PHYRSTZ_RSTZ_BITS)); + udelay(1); /* so we can see PLL coming up? */ ++ ++ return actual_vco_freq; + } + + void rp1dsi_mipicfg_setup(struct rp1_dsi *dsi) +@@ -1290,23 +1301,30 @@ static unsigned long rp1dsi_refclk_freq( + return u; + } + +-static void rp1dsi_dpiclk_start(struct rp1_dsi *dsi, unsigned int bpp, unsigned int lanes) ++static void rp1dsi_dpiclk_start(struct rp1_dsi *dsi, u32 byte_clock, ++ unsigned int bpp, unsigned int lanes) + { +- unsigned long u; +- +- if (dsi->clocks[RP1DSI_CLOCK_DPI]) { +- u = (dsi->clocks[RP1DSI_CLOCK_BYTE]) ? +- clk_get_rate(dsi->clocks[RP1DSI_CLOCK_BYTE]) : 0; +- drm_info(dsi->drm, +- "rp1dsi: Nominal byte clock %lu; scale by %u/%u", +- u, 4 * lanes, (bpp >> 1)); +- if (u < 1 || u >= (1ul << 28)) +- u = 72000000ul; /* default DUMMY frequency for byteclock */ ++ /* Dummy clk_set_rate() to declare the actual DSI byte-clock rate */ ++ clk_set_rate(dsi->clocks[RP1DSI_CLOCK_BYTE], byte_clock); + ++ /* ++ * Prefer the DSI byte-clock source where possible, so that DSI and DPI ++ * clocks will be in an exact ratio and downstream devices can recover ++ * perfect timings. But when DPI clock is faster, fall back on PLL_SYS. ++ * To defeat rounding errors, specify explicitly which source to use. ++ */ ++ if (bpp >= 8 * lanes) + clk_set_parent(dsi->clocks[RP1DSI_CLOCK_DPI], dsi->clocks[RP1DSI_CLOCK_BYTE]); +- clk_set_rate(dsi->clocks[RP1DSI_CLOCK_DPI], (4 * lanes * u) / (bpp >> 1)); +- clk_prepare_enable(dsi->clocks[RP1DSI_CLOCK_DPI]); +- } ++ else if (dsi->clocks[RP1DSI_CLOCK_PLLSYS]) ++ clk_set_parent(dsi->clocks[RP1DSI_CLOCK_DPI], dsi->clocks[RP1DSI_CLOCK_PLLSYS]); ++ ++ clk_set_rate(dsi->clocks[RP1DSI_CLOCK_DPI], (4 * lanes * byte_clock) / (bpp >> 1)); ++ clk_prepare_enable(dsi->clocks[RP1DSI_CLOCK_DPI]); ++ drm_info(dsi->drm, ++ "rp1dsi: Nominal Byte clock %u DPI clock %lu (parent rate %lu)", ++ byte_clock, ++ clk_get_rate(dsi->clocks[RP1DSI_CLOCK_DPI]), ++ clk_get_rate(clk_get_parent(dsi->clocks[RP1DSI_CLOCK_DPI]))); + } + + static void rp1dsi_dpiclk_stop(struct rp1_dsi *dsi) +@@ -1336,18 +1354,21 @@ static u32 get_colorcode(enum mipi_dsi_p + return 0x005; + } + +-/* Maximum frequency for LP escape clock (20MHz), and some magic numbers */ +-#define RP1DSI_ESC_CLK_KHZ 20000 +-#define RP1DSI_TO_CLK_DIV 5 +-#define RP1DSI_HSTX_TO_MIN 0x200 +-#define RP1DSI_LPRX_TO_VAL 0x400 ++/* Frequency limits for DPI, HS and LP clocks, and some magic numbers */ ++#define RP1DSI_DPI_MAX_KHZ 200000 ++#define RP1DSI_BYTE_CLK_MIN 10000000 ++#define RP1DSI_BYTE_CLK_MAX 187500000 ++#define RP1DSI_ESC_CLK_MAX 20000000 ++#define RP1DSI_TO_CLK_DIV 0x50 ++#define RP1DSI_LPRX_TO_VAL 0x40 + #define RP1DSI_BTA_TO_VAL 0xd00 + + void rp1dsi_dsi_setup(struct rp1_dsi *dsi, struct drm_display_mode const *mode) + { + u32 timeout, mask, vid_mode_cfg; +- int lane_kbps; + unsigned int bpp = mipi_dsi_pixel_format_to_bpp(dsi->display_format); ++ u32 byte_clock = clamp((bpp * 125 * min(mode->clock, RP1DSI_DPI_MAX_KHZ)) / dsi->lanes, ++ RP1DSI_BYTE_CLK_MIN, RP1DSI_BYTE_CLK_MAX); + + DSI_WRITE(DSI_PHY_IF_CFG, dsi->lanes - 1); + DSI_WRITE(DSI_DPI_CFG_POL, 0); +@@ -1360,6 +1381,8 @@ void rp1dsi_dsi_setup(struct rp1_dsi *ds + vid_mode_cfg = 0xbf00; + if (!(dsi->display_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)) + vid_mode_cfg |= 0x01; ++ else if (8 * dsi->lanes > bpp) ++ vid_mode_cfg &= ~0x400; /* PULSE && inexact DPICLK => fix HBP time */ + if (dsi->display_flags & MIPI_DSI_MODE_VIDEO_BURST) + vid_mode_cfg |= 0x02; + DSI_WRITE(DSI_VID_MODE_CFG, vid_mode_cfg); +@@ -1369,15 +1392,14 @@ void rp1dsi_dsi_setup(struct rp1_dsi *ds + DSI_WRITE(DSI_MODE_CFG, 1); + + /* Set timeouts and clock dividers */ +- DSI_WRITE(DSI_TO_CNT_CFG, +- (max((bpp * mode->htotal) / (7 * RP1DSI_TO_CLK_DIV * dsi->lanes), +- RP1DSI_HSTX_TO_MIN) << 16) | +- RP1DSI_LPRX_TO_VAL); ++ timeout = (bpp * mode->htotal * mode->vdisplay) / (7 * RP1DSI_TO_CLK_DIV * dsi->lanes); ++ if (timeout > 0xFFFFu) ++ timeout = 0; ++ DSI_WRITE(DSI_TO_CNT_CFG, (timeout << 16) | RP1DSI_LPRX_TO_VAL); + DSI_WRITE(DSI_BTA_TO_CNT, RP1DSI_BTA_TO_VAL); +- lane_kbps = (bpp * mode->clock) / dsi->lanes; + DSI_WRITE(DSI_CLKMGR_CFG, + (RP1DSI_TO_CLK_DIV << 8) | +- max(2, lane_kbps / (8 * RP1DSI_ESC_CLK_KHZ) + 1)); ++ max(2u, 1u + byte_clock / RP1DSI_ESC_CLK_MAX)); + + /* Configure video timings */ + DSI_WRITE(DSI_VID_PKT_SIZE, mode->hdisplay); +@@ -1394,7 +1416,7 @@ void rp1dsi_dsi_setup(struct rp1_dsi *ds + DSI_WRITE(DSI_VID_VACTIVE_LINES, mode->vdisplay); + + /* Init PHY */ +- dphy_init_khz(dsi, rp1dsi_refclk_freq(dsi) / 1000, lane_kbps); ++ byte_clock = dphy_init(dsi, rp1dsi_refclk_freq(dsi), 8 * byte_clock) >> 3; + + DSI_WRITE(DSI_PHY_TMR_LPCLK_CFG, + (hsfreq_table[dsi->hsfreq_index].clk_lp2hs << DSI_PHY_TMR_LP2HS_LSB) | +@@ -1418,7 +1440,7 @@ void rp1dsi_dsi_setup(struct rp1_dsi *ds + DSI_WRITE(DSI_PWR_UP, 0x1); /* power up */ + + /* Now it should be safe to start the external DPI clock divider */ +- rp1dsi_dpiclk_start(dsi, bpp, dsi->lanes); ++ rp1dsi_dpiclk_start(dsi, byte_clock, bpp, dsi->lanes); + + /* Wait for all lane(s) to be in Stopstate */ + mask = (1 << 4); diff --git a/target/linux/bcm27xx/patches-6.6/950-1180-arm64-dts-Move-bcm2712-and-rp1-here.patch b/target/linux/bcm27xx/patches-6.6/950-1180-arm64-dts-Move-bcm2712-and-rp1-here.patch new file mode 100644 index 0000000000..2856bb5cd8 --- /dev/null +++ b/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 +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 +--- + .../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 +-#include +-#include +-#include +-#include +-#include +- +-#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 = ; +-}; +- +-&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 ++#include ++#include ++#include ++#include ++#include ++ ++#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 +-#include +-#include +-#include +-#include +-#include +- +-#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 ++#include ++#include ++#include ++#include ++#include ++ ++#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 = ; ++}; ++ ++&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 +- +-&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 should expose the registers for the interface with DT alias +- * gpio. +- */ +- +-&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 +-#include +-#include +- +-/ { +- 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 = , +- , +- , +- ; +- 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 = ; +- #mbox-cells = <0>; +- }; +- +- pixelvalve0: pixelvalve@7c410000 { +- compatible = "brcm,bcm2712-pixelvalve0"; +- reg = <0x7c410000 0x100>; +- interrupts = ; +- status = "disabled"; +- }; +- +- pixelvalve1: pixelvalve@7c411000 { +- compatible = "brcm,bcm2712-pixelvalve1"; +- reg = <0x7c411000 0x100>; +- interrupts = ; +- 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 = ; +- 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 = ; +- 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 = ; +- 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 = ; +- 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 = ; +- 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 = ; +- 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 = ; +- clocks = <&clk_vpu>; +- #address-cells = <1>; +- #size-cells = <0>; +- status = "disabled"; +- }; +- +- spi4: spi@7d004800 { +- compatible = "brcm,bcm2835-spi"; +- reg = <0x7d004800 0x0200>; +- interrupts = ; +- clocks = <&clk_vpu>; +- #address-cells = <1>; +- #size-cells = <0>; +- status = "disabled"; +- }; +- +- spi5: spi@7d004a00 { +- compatible = "brcm,bcm2835-spi"; +- reg = <0x7d004a00 0x0200>; +- interrupts = ; +- clocks = <&clk_vpu>; +- #address-cells = <1>; +- #size-cells = <0>; +- status = "disabled"; +- }; +- +- spi6: spi@7d004c00 { +- compatible = "brcm,bcm2835-spi"; +- reg = <0x7d004c00 0x0200>; +- interrupts = ; +- 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 = ; +- 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 = ; +- 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 = ; +- 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 = ; +- 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 = ; +- 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 = ; +- 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 = ; +- 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 = ; +- interrupt-controller; +- #interrupt-cells = <1>; +- }; +- +- main_irq: intc@7d508400 { +- compatible = "brcm,bcm7271-l2-intc"; +- reg = <0x7d508400 0x10>; +- interrupts = ; +- 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 = ; +- 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 = ; +- skip-init; +- status = "disabled"; +- }; +- +- aon_intr: interrupt-controller@7d510600 { +- compatible = "brcm,bcm2711-l2-intc", "brcm,l2-intc"; +- reg = <0x7d510600 0x30>; +- interrupts = ; +- 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 = ; +- 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 = ; +- interrupt-controller; +- #interrupt-cells = <1>; +- }; +- +- bsc_aon_irq: intc@7d517b00 { +- compatible = "brcm,bcm7271-l2-intc"; +- reg = <0x7d517b00 0x10>; +- interrupts = ; +- 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 = , +- , +- , +- ; +- interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>; +- }; +- +- timer { +- compatible = "arm,armv8-timer"; +- interrupts = , +- , +- , +- ; +- /* 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 = , +- , +- , +- , +- , +- ; +- 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 = +- , /* dma4 6 */ +- , /* dma4 7 */ +- , /* dma4 8 */ +- , /* dma4 9 */ +- , /* dma4 10 */ +- ; /* 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 = , +- ; +- 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 = , +- ; +- 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 = , +- ; +- 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 = ; +- #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 = ; +- +- 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 = ; +- 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 = ; +- 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 = , +- ; +- 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 = ; +- }; +- +- pisp_be: pisp_be@880000 { +- compatible = "raspberrypi,pispbe"; +- reg = <0x10 0x00880000 0x0 0x4000>; +- interrupts = ; +- 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 +-#include +-#include +- +-&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 = ; +- 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 = ; +- 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 = ; +- 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 = ; +- 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 = ; +- 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 = ; +- 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 = ; +- 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 = ; +- 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 = ; +- 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 = ; +- 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 = ; +- 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 = ; +- 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 = ; +- 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 = ; +- 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 = ; +- 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 = ; +- 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 = ; +- 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 = ; +- 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 = ; +- 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 = ; +- 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 = ; +- 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 = ; +- 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 = ; +- 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 = ; +- 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 = ; +- 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 = , +- , +- ; +- 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 = ; +- 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 = ; +- +- 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 = ; +- +- 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 = ; +- 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 = ; +- 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 = ; +- 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 = ; +- 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 = ; +- 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 = ; +- +- 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 = ; +- +- 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 = ; +- +- 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 = ; +- +- 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 ++ ++&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 should expose the registers for the interface with DT alias ++ * gpio. ++ */ ++ ++&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 ++#include ++#include ++ ++/ { ++ 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 = , ++ , ++ , ++ ; ++ 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 = ; ++ #mbox-cells = <0>; ++ }; ++ ++ pixelvalve0: pixelvalve@7c410000 { ++ compatible = "brcm,bcm2712-pixelvalve0"; ++ reg = <0x7c410000 0x100>; ++ interrupts = ; ++ status = "disabled"; ++ }; ++ ++ pixelvalve1: pixelvalve@7c411000 { ++ compatible = "brcm,bcm2712-pixelvalve1"; ++ reg = <0x7c411000 0x100>; ++ interrupts = ; ++ 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 = ; ++ 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 = ; ++ 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 = ; ++ 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 = ; ++ 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 = ; ++ 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 = ; ++ 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 = ; ++ clocks = <&clk_vpu>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ spi4: spi@7d004800 { ++ compatible = "brcm,bcm2835-spi"; ++ reg = <0x7d004800 0x0200>; ++ interrupts = ; ++ clocks = <&clk_vpu>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ spi5: spi@7d004a00 { ++ compatible = "brcm,bcm2835-spi"; ++ reg = <0x7d004a00 0x0200>; ++ interrupts = ; ++ clocks = <&clk_vpu>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ spi6: spi@7d004c00 { ++ compatible = "brcm,bcm2835-spi"; ++ reg = <0x7d004c00 0x0200>; ++ interrupts = ; ++ 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 = ; ++ 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 = ; ++ 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 = ; ++ 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 = ; ++ 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 = ; ++ 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 = ; ++ 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 = ; ++ 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 = ; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ ++ main_irq: intc@7d508400 { ++ compatible = "brcm,bcm7271-l2-intc"; ++ reg = <0x7d508400 0x10>; ++ interrupts = ; ++ 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 = ; ++ 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 = ; ++ skip-init; ++ status = "disabled"; ++ }; ++ ++ aon_intr: interrupt-controller@7d510600 { ++ compatible = "brcm,bcm2711-l2-intc", "brcm,l2-intc"; ++ reg = <0x7d510600 0x30>; ++ interrupts = ; ++ 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 = ; ++ 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 = ; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ ++ bsc_aon_irq: intc@7d517b00 { ++ compatible = "brcm,bcm7271-l2-intc"; ++ reg = <0x7d517b00 0x10>; ++ interrupts = ; ++ 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 = , ++ , ++ , ++ ; ++ interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>; ++ }; ++ ++ timer { ++ compatible = "arm,armv8-timer"; ++ interrupts = , ++ , ++ , ++ ; ++ /* 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 = , ++ , ++ , ++ , ++ , ++ ; ++ 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 = ++ , /* dma4 6 */ ++ , /* dma4 7 */ ++ , /* dma4 8 */ ++ , /* dma4 9 */ ++ , /* dma4 10 */ ++ ; /* 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 = , ++ ; ++ 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 = , ++ ; ++ 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 = , ++ ; ++ 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 = ; ++ #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 = ; ++ ++ 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 = ; ++ 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 = ; ++ 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 = , ++ ; ++ 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 = ; ++ }; ++ ++ pisp_be: pisp_be@880000 { ++ compatible = "raspberrypi,pispbe"; ++ reg = <0x10 0x00880000 0x0 0x4000>; ++ interrupts = ; ++ 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 ++#include ++#include ++ ++&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 = ; ++ 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 = ; ++ 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 = ; ++ 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 = ; ++ 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 = ; ++ 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 = ; ++ 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 = ; ++ 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 = ; ++ 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 = ; ++ 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 = ; ++ 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 = ; ++ 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 = ; ++ 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 = ; ++ 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 = ; ++ 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 = ; ++ 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 = ; ++ 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 = ; ++ 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 = ; ++ 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 = ; ++ 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 = ; ++ 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 = ; ++ 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 = ; ++ 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 = ; ++ 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 = ; ++ 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 = ; ++ 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 = , ++ , ++ ; ++ 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 = ; ++ 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 = ; ++ ++ 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 = ; ++ ++ 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 = ; ++ 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 = ; ++ 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 = ; ++ 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 = ; ++ 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 = ; ++ 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 = ; ++ ++ 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 = ; ++ ++ 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 = ; ++ ++ 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 = ; ++ ++ clocks = <&rp1_clocks RP1_CLK_DPI>, // DPI pixel clock ++ <&rp1_clocks RP1_PLL_VIDEO>, // PLL primary divider, and ++ <&rp1_clocks RP1_PLL_VIDEO_CORE>; // VCO, which we also control ++ clock-names = "dpiclk", "plldiv", "pllcore"; ++ ++ assigned-clocks = <&rp1_clocks RP1_CLK_DPI>; ++ assigned-clock-parents = <&rp1_clocks RP1_PLL_VIDEO>; ++ }; ++ }; ++}; ++ ++&clocks { ++ clk_xosc: clk_xosc { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-output-names = "xosc"; ++ clock-frequency = <50000000>; ++ }; ++ macb_pclk: macb_pclk { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-output-names = "pclk"; ++ clock-frequency = <200000000>; ++ }; ++ macb_hclk: macb_hclk { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-output-names = "hclk"; ++ clock-frequency = <200000000>; ++ }; ++ sdio_src: sdio_src { ++ // 400 MHz on FPGA. PLL sys VCO on asic ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-output-names = "src"; ++ clock-frequency = <1000000000>; ++ }; ++ sdhci_core: sdhci_core { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-output-names = "core"; ++ clock-frequency = <50000000>; ++ }; ++ /* GPIO derived clock sources. Each GPIO with a GPCLK function ++ * can drive its output from the respective GPCLK ++ * generator, and provide a clock source to other internal ++ * dividers. Add dummy sources here so that they can be overridden ++ * with overlays. ++ */ ++ clksrc_gp0: clksrc_gp0 { ++ status = "disabled"; ++ compatible = "fixed-factor-clock"; ++ #clock-cells = <0>; ++ clock-div = <1>; ++ clock-mult = <1>; ++ clocks = <&rp1_clocks RP1_CLK_GP0>; ++ clock-output-names = "clksrc_gp0"; ++ }; ++ clksrc_gp1: clksrc_gp1 { ++ status = "disabled"; ++ compatible = "fixed-factor-clock"; ++ #clock-cells = <0>; ++ clock-div = <1>; ++ clock-mult = <1>; ++ clocks = <&rp1_clocks RP1_CLK_GP1>; ++ clock-output-names = "clksrc_gp1"; ++ }; ++ clksrc_gp2: clksrc_gp2 { ++ status = "disabled"; ++ compatible = "fixed-factor-clock"; ++ clock-div = <1>; ++ clock-mult = <1>; ++ #clock-cells = <0>; ++ clocks = <&rp1_clocks RP1_CLK_GP2>; ++ clock-output-names = "clksrc_gp2"; ++ }; ++ clksrc_gp3: clksrc_gp3 { ++ status = "disabled"; ++ compatible = "fixed-factor-clock"; ++ clock-div = <1>; ++ clock-mult = <1>; ++ #clock-cells = <0>; ++ clocks = <&rp1_clocks RP1_CLK_GP3>; ++ clock-output-names = "clksrc_gp3"; ++ }; ++ clksrc_gp4: clksrc_gp4 { ++ status = "disabled"; ++ compatible = "fixed-factor-clock"; ++ #clock-cells = <0>; ++ clock-div = <1>; ++ clock-mult = <1>; ++ clocks = <&rp1_clocks RP1_CLK_GP4>; ++ clock-output-names = "clksrc_gp4"; ++ }; ++ clksrc_gp5: clksrc_gp5 { ++ status = "disabled"; ++ compatible = "fixed-factor-clock"; ++ #clock-cells = <0>; ++ clock-div = <1>; ++ clock-mult = <1>; ++ clocks = <&rp1_clocks RP1_CLK_GP5>; ++ clock-output-names = "clksrc_gp5"; ++ }; ++}; ++ ++/ { ++ rp1_vdd_3v3: rp1_vdd_3v3 { ++ compatible = "regulator-fixed"; ++ regulator-name = "vdd-3v3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++}; diff --git a/target/linux/bcm27xx/patches-6.6/950-1181-arm64-dts-Add-cm5l-files.patch b/target/linux/bcm27xx/patches-6.6/950-1181-arm64-dts-Add-cm5l-files.patch new file mode 100644 index 0000000000..4f0544386a --- /dev/null +++ b/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 +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 +--- + arch/arm64/boot/dts/broadcom/Makefile | 2 ++ + .../dts/broadcom/bcm2712-rpi-cm5l-cm4io.dts | 20 ++++++++++++++++ + .../dts/broadcom/bcm2712-rpi-cm5l-cm5io.dts | 10 ++++++++ + .../boot/dts/broadcom/bcm2712-rpi-cm5l.dtsi | 24 +++++++++++++++++++ + 4 files changed, 56 insertions(+) + create mode 100644 arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l-cm4io.dts + create mode 100644 arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l-cm5io.dts + create mode 100644 arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l.dtsi + +--- a/arch/arm64/boot/dts/broadcom/Makefile ++++ b/arch/arm64/boot/dts/broadcom/Makefile +@@ -24,6 +24,8 @@ dtb-$(CONFIG_ARCH_BCM2835) += bcm2712-rp + dtb-$(CONFIG_ARCH_BCM2835) += bcm2712d0-rpi-5-b.dtb + dtb-$(CONFIG_ARCH_BCM2835) += bcm2712-rpi-cm5-cm5io.dtb + dtb-$(CONFIG_ARCH_BCM2835) += bcm2712-rpi-cm5-cm4io.dtb ++dtb-$(CONFIG_ARCH_BCM2835) += bcm2712-rpi-cm5l-cm5io.dtb ++dtb-$(CONFIG_ARCH_BCM2835) += bcm2712-rpi-cm5l-cm4io.dtb + + subdir-y += bcmbca + subdir-y += northstar2 +--- /dev/null ++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l-cm4io.dts +@@ -0,0 +1,20 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/dts-v1/; ++ ++#include "bcm2712-rpi-cm5l.dtsi" ++ ++// The RP1 USB3 interfaces are not usable on CM4IO ++ ++&rp1_usb0 { ++ status = "disabled"; ++}; ++ ++&rp1_usb1 { ++ status = "disabled"; ++}; ++ ++/ { ++ __overrides__ { ++ i2c_csi_dsi = <&i2c_csi_dsi>, "status"; ++ }; ++}; +--- /dev/null ++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l-cm5io.dts +@@ -0,0 +1,10 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/dts-v1/; ++ ++#include "bcm2712-rpi-cm5l.dtsi" ++ ++/ { ++ __overrides__ { ++ i2c_csi_dsi = <&i2c_csi_dsi>, "status"; ++ }; ++}; +--- /dev/null ++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l.dtsi +@@ -0,0 +1,24 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/dts-v1/; ++ ++#include "bcm2712-rpi-cm5.dtsi" ++ ++/ { ++ __overrides__ { ++ i2c_csi_dsi = <&i2c_csi_dsi>, "status"; ++ }; ++}; ++ ++&sd_io_1v8_reg { ++ compatible = "regulator-gpio"; ++ regulator-max-microvolt = <3300000>; ++ regulator-settling-time-us = <5000>; ++ gpios = <&gio_aon 3 GPIO_ACTIVE_HIGH>; ++ states = <1800000 0x1 ++ 3300000 0x0>; ++}; ++ ++&sdio1 { ++ /delete-property/ mmc-hs400-1_8v; ++ /delete-property/ mmc-hs400-enhanced-strobe; ++}; diff --git a/target/linux/bcm27xx/patches-6.6/950-1182-dts-bcm2712-Dedup-the-aliases-and-overrides.patch b/target/linux/bcm27xx/patches-6.6/950-1182-dts-bcm2712-Dedup-the-aliases-and-overrides.patch new file mode 100644 index 0000000000..6cffbdd9be --- /dev/null +++ b/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 +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 +--- + .../boot/dts/broadcom/bcm2712-rpi-5-b.dts | 115 ----------------- + .../boot/dts/broadcom/bcm2712-rpi-cm5.dtsi | 114 ----------------- + arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi | 117 +++++++++++++++++- + 3 files changed, 113 insertions(+), 233 deletions(-) + +--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts ++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts +@@ -746,122 +746,7 @@ spi10_cs_pins: &spi10_cs_gpio1 {}; + }; + + / { +- aliases: aliases { +- blconfig = &blconfig; +- blpubkey = &blpubkey; +- bluetooth = &bluetooth; +- console = &uart10; +- ethernet0 = &rp1_eth; +- wifi0 = &wifi; +- fb = &fb; +- mailbox = &mailbox; +- mmc0 = &sdio1; +- uart0 = &uart0; +- uart1 = &uart1; +- uart2 = &uart2; +- uart3 = &uart3; +- uart4 = &uart4; +- uart10 = &uart10; +- serial0 = &uart0; +- serial1 = &uart1; +- serial2 = &uart2; +- serial3 = &uart3; +- serial4 = &uart4; +- serial10 = &uart10; +- i2c = &i2c_arm; +- i2c0 = &i2c0; +- i2c1 = &i2c1; +- i2c2 = &i2c2; +- i2c3 = &i2c3; +- i2c4 = &i2c4; +- i2c5 = &i2c5; +- i2c6 = &i2c6; +- i2c10 = &i2c_rp1boot; +- // Bit-bashed i2c_gpios start at 10 +- spi0 = &spi0; +- spi1 = &spi1; +- spi2 = &spi2; +- spi3 = &spi3; +- spi4 = &spi4; +- spi5 = &spi5; +- spi10 = &spi10; +- gpio0 = &gpio; +- gpio1 = &gio; +- gpio2 = &gio_aon; +- gpio3 = &pinctrl; +- gpio4 = &pinctrl_aon; +- usb0 = &rp1_usb0; +- usb1 = &rp1_usb1; +- drm-dsi1 = &dsi0; +- drm-dsi2 = &dsi1; +- }; +- + __overrides__ { +- bdaddr = <&bluetooth>, "local-bd-address["; +- button_debounce = <&pwr_key>, "debounce-interval:0"; +- cooling_fan = <&fan>, "status", <&rp1_pwm1>, "status"; +- uart0_console = <&uart0>,"status", <&aliases>, "console=",&uart0; +- i2c0 = <&i2c0>, "status"; +- i2c1 = <&i2c1>, "status"; +- i2c = <&i2c1>, "status"; +- i2c_arm = <&i2c_arm>, "status"; +- i2c_vc = <&i2c_vc>, "status"; +- i2c_csi_dsi = <&i2c_csi_dsi>, "status"; +- i2c_csi_dsi0 = <&i2c_csi_dsi0>, "status"; +- i2c_csi_dsi1 = <&i2c_csi_dsi1>, "status"; +- i2c0_baudrate = <&i2c0>, "clock-frequency:0"; +- i2c1_baudrate = <&i2c1>, "clock-frequency:0"; +- i2c_baudrate = <&i2c_arm>, "clock-frequency:0"; +- i2c_arm_baudrate = <&i2c_arm>, "clock-frequency:0"; +- i2c_vc_baudrate = <&i2c_vc>, "clock-frequency:0"; +- krnbt = <&bluetooth>, "status"; +- nvme = <&pciex1>, "status"; +- pciex1 = <&pciex1>, "status"; +- pciex1_gen = <&pciex1> , "max-link-speed:0"; +- pciex1_no_l0s = <&pciex1>, "aspm-no-l0s?"; +- pciex1_tperst_clk_ms = <&pciex1>, "brcm,tperst-clk-ms:0"; +- pcie_tperst_clk_ms = <&pciex1>, "brcm,tperst-clk-ms:0"; +- random = <&random>, "status"; +- rtc = <&rpi_rtc>, "status"; +- rtc_bbat_vchg = <&rpi_rtc>, "trickle-charge-microvolt:0"; + sd_cqe = <&sdio1>, "supports-cqe?"; +- spi = <&spi0>, "status"; +- suspend = <&pwr_key>, "linux,code:0=205"; +- uart0 = <&uart0>, "status"; +- wifiaddr = <&wifi>, "local-mac-address["; +- +- act_led_gpio = <&led_act>,"gpios:4",<&led_act>,"gpios:0=",<&gpio>; +- act_led_activelow = <&led_act>,"gpios:8"; +- act_led_trigger = <&led_act>, "linux,default-trigger"; +- pwr_led_gpio = <&led_pwr>,"gpios:4"; +- pwr_led_activelow = <&led_pwr>, "gpios:8"; +- pwr_led_trigger = <&led_pwr>, "linux,default-trigger"; +- eth_led0 = <&phy1>,"led-modes:0"; +- eth_led1 = <&phy1>,"led-modes:4"; +- drm_fb0_rp1_dsi0 = <&aliases>, "drm-fb0=",&dsi0; +- drm_fb0_rp1_dsi1 = <&aliases>, "drm-fb0=",&dsi1; +- drm_fb0_rp1_dpi = <&aliases>, "drm-fb0=",&dpi; +- drm_fb0_vc4 = <&aliases>, "drm-fb0=",&vc4; +- drm_fb1_rp1_dsi0 = <&aliases>, "drm-fb1=",&dsi0; +- drm_fb1_rp1_dsi1 = <&aliases>, "drm-fb1=",&dsi1; +- drm_fb1_rp1_dpi = <&aliases>, "drm-fb1=",&dpi; +- drm_fb1_vc4 = <&aliases>, "drm-fb1=",&vc4; +- drm_fb2_rp1_dsi0 = <&aliases>, "drm-fb2=",&dsi0; +- drm_fb2_rp1_dsi1 = <&aliases>, "drm-fb2=",&dsi1; +- drm_fb2_rp1_dpi = <&aliases>, "drm-fb2=",&dpi; +- drm_fb2_vc4 = <&aliases>, "drm-fb2=",&vc4; +- +- fan_temp0 = <&cpu_tepid>,"temperature:0"; +- fan_temp1 = <&cpu_warm>,"temperature:0"; +- fan_temp2 = <&cpu_hot>,"temperature:0"; +- fan_temp3 = <&cpu_vhot>,"temperature:0"; +- fan_temp0_hyst = <&cpu_tepid>,"hysteresis:0"; +- fan_temp1_hyst = <&cpu_warm>,"hysteresis:0"; +- fan_temp2_hyst = <&cpu_hot>,"hysteresis:0"; +- fan_temp3_hyst = <&cpu_vhot>,"hysteresis:0"; +- fan_temp0_speed = <&fan>, "cooling-levels:4"; +- fan_temp1_speed = <&fan>, "cooling-levels:8"; +- fan_temp2_speed = <&fan>, "cooling-levels:12"; +- fan_temp3_speed = <&fan>, "cooling-levels:16"; + }; + }; +--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi ++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi +@@ -753,108 +753,7 @@ spi10_cs_pins: &spi10_cs_gpio1 {}; + }; + + / { +- aliases: aliases { +- blconfig = &blconfig; +- blpubkey = &blpubkey; +- bluetooth = &bluetooth; +- console = &uart10; +- ethernet0 = &rp1_eth; +- wifi0 = &wifi; +- fb = &fb; +- mailbox = &mailbox; +- mmc0 = &sdio1; +- uart0 = &uart0; +- uart1 = &uart1; +- uart2 = &uart2; +- uart3 = &uart3; +- uart4 = &uart4; +- uart10 = &uart10; +- serial0 = &uart0; +- serial1 = &uart1; +- serial2 = &uart2; +- serial3 = &uart3; +- serial4 = &uart4; +- serial10 = &uart10; +- i2c = &i2c_arm; +- i2c0 = &i2c0; +- i2c1 = &i2c1; +- i2c2 = &i2c2; +- i2c3 = &i2c3; +- i2c4 = &i2c4; +- i2c5 = &i2c5; +- i2c6 = &i2c6; +- i2c10 = &i2c_rp1boot; +- // Bit-bashed i2c_gpios start at 10 +- spi0 = &spi0; +- spi1 = &spi1; +- spi2 = &spi2; +- spi3 = &spi3; +- spi4 = &spi4; +- spi5 = &spi5; +- spi10 = &spi10; +- gpio0 = &gpio; +- gpio1 = &gio; +- gpio2 = &gio_aon; +- gpio3 = &pinctrl; +- gpio4 = &pinctrl_aon; +- usb0 = &rp1_usb0; +- usb1 = &rp1_usb1; +- drm-dsi1 = &dsi0; +- drm-dsi2 = &dsi1; +- }; +- + __overrides__ { +- bdaddr = <&bluetooth>, "local-bd-address["; +- button_debounce = <&pwr_key>, "debounce-interval:0"; +- cooling_fan = <&fan>, "status", <&rp1_pwm1>, "status"; +- uart0_console = <&uart0>,"status", <&aliases>, "console=",&uart0; +- i2c0 = <&i2c0>, "status"; +- i2c1 = <&i2c1>, "status"; +- i2c = <&i2c1>, "status"; +- i2c_arm = <&i2c_arm>, "status"; +- i2c_vc = <&i2c_vc>, "status"; +- i2c_csi_dsi = <&i2c_csi_dsi>, "status"; +- i2c_csi_dsi0 = <&i2c_csi_dsi0>, "status"; +- i2c_csi_dsi1 = <&i2c_csi_dsi1>, "status"; +- i2c0_baudrate = <&i2c0>, "clock-frequency:0"; +- i2c1_baudrate = <&i2c1>, "clock-frequency:0"; +- i2c_baudrate = <&i2c_arm>, "clock-frequency:0"; +- i2c_arm_baudrate = <&i2c_arm>, "clock-frequency:0"; +- i2c_vc_baudrate = <&i2c_vc>, "clock-frequency:0"; +- krnbt = <&bluetooth>, "status"; +- nvme = <&pciex1>, "status"; +- pciex1 = <&pciex1>, "status"; +- pciex1_gen = <&pciex1> , "max-link-speed:0"; +- pciex1_no_l0s = <&pciex1>, "aspm-no-l0s?"; +- pciex1_tperst_clk_ms = <&pciex1>, "brcm,tperst-clk-ms:0"; +- pcie_tperst_clk_ms = <&pciex1>, "brcm,tperst-clk-ms:0"; +- random = <&random>, "status"; +- rtc = <&rpi_rtc>, "status"; +- rtc_bbat_vchg = <&rpi_rtc>, "trickle-charge-microvolt:0"; +- spi = <&spi0>, "status"; +- suspend = <&pwr_key>, "linux,code:0=205"; +- uart0 = <&uart0>, "status"; +- wifiaddr = <&wifi>, "local-mac-address["; +- +- act_led_activelow = <&led_act>, "active-low?"; +- act_led_trigger = <&led_act>, "linux,default-trigger"; +- pwr_led_activelow = <&led_pwr>, "gpios:8"; +- pwr_led_trigger = <&led_pwr>, "linux,default-trigger"; +- eth_led0 = <&phy1>,"led-modes:0"; +- eth_led1 = <&phy1>,"led-modes:4"; +- drm_fb0_rp1_dsi0 = <&aliases>, "drm-fb0=",&dsi0; +- drm_fb0_rp1_dsi1 = <&aliases>, "drm-fb0=",&dsi1; +- drm_fb0_rp1_dpi = <&aliases>, "drm-fb0=",&dpi; +- drm_fb0_vc4 = <&aliases>, "drm-fb0=",&vc4; +- drm_fb1_rp1_dsi0 = <&aliases>, "drm-fb1=",&dsi0; +- drm_fb1_rp1_dsi1 = <&aliases>, "drm-fb1=",&dsi1; +- drm_fb1_rp1_dpi = <&aliases>, "drm-fb1=",&dpi; +- drm_fb1_vc4 = <&aliases>, "drm-fb1=",&vc4; +- drm_fb2_rp1_dsi0 = <&aliases>, "drm-fb2=",&dsi0; +- drm_fb2_rp1_dsi1 = <&aliases>, "drm-fb2=",&dsi1; +- drm_fb2_rp1_dpi = <&aliases>, "drm-fb2=",&dpi; +- drm_fb2_vc4 = <&aliases>, "drm-fb2=",&vc4; +- + ant1 = <&ant1>,"output-high?=on", + <&ant1>, "output-low?=off", + <&ant2>, "output-high?=off", +@@ -867,18 +766,5 @@ spi10_cs_pins: &spi10_cs_gpio1 {}; + <&ant1>, "output-low?=on", + <&ant2>, "output-high?=off", + <&ant2>, "output-low?=on"; +- +- fan_temp0 = <&cpu_tepid>,"temperature:0"; +- fan_temp1 = <&cpu_warm>,"temperature:0"; +- fan_temp2 = <&cpu_hot>,"temperature:0"; +- fan_temp3 = <&cpu_vhot>,"temperature:0"; +- fan_temp0_hyst = <&cpu_tepid>,"hysteresis:0"; +- fan_temp1_hyst = <&cpu_warm>,"hysteresis:0"; +- fan_temp2_hyst = <&cpu_hot>,"hysteresis:0"; +- fan_temp3_hyst = <&cpu_vhot>,"hysteresis:0"; +- fan_temp0_speed = <&fan>, "cooling-levels:4"; +- fan_temp1_speed = <&fan>, "cooling-levels:8"; +- fan_temp2_speed = <&fan>, "cooling-levels:12"; +- fan_temp3_speed = <&fan>, "cooling-levels:16"; + }; + }; +--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi ++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi +@@ -98,14 +98,124 @@ + }; + + / { ++ aliases: aliases { ++ blconfig = &blconfig; ++ blpubkey = &blpubkey; ++ bluetooth = &bluetooth; ++ console = &uart10; ++ drm-dsi1 = &dsi0; ++ drm-dsi2 = &dsi1; ++ ethernet0 = &rp1_eth; ++ fb = &fb; ++ gpio0 = &gpio; ++ gpio1 = &gio; ++ gpio2 = &gio_aon; ++ gpio3 = &pinctrl; ++ gpio4 = &pinctrl_aon; ++ i2c = &i2c_arm; ++ i2c0 = &i2c0; ++ i2c1 = &i2c1; ++ i2c10 = &i2c_rp1boot; ++ i2c2 = &i2c2; ++ i2c3 = &i2c3; ++ i2c4 = &i2c4; ++ i2c5 = &i2c5; ++ i2c6 = &i2c6; ++ mailbox = &mailbox; ++ mmc0 = &sdio1; ++ serial0 = &uart0; ++ serial1 = &uart1; ++ serial10 = &uart10; ++ serial2 = &uart2; ++ serial3 = &uart3; ++ serial4 = &uart4; ++ spi0 = &spi0; ++ spi1 = &spi1; ++ spi10 = &spi10; ++ spi2 = &spi2; ++ spi3 = &spi3; ++ spi4 = &spi4; ++ spi5 = &spi5; ++ uart0 = &uart0; ++ uart1 = &uart1; ++ uart10 = &uart10; ++ uart2 = &uart2; ++ uart3 = &uart3; ++ uart4 = &uart4; ++ usb0 = &rp1_usb0; ++ usb1 = &rp1_usb1; ++ wifi0 = &wifi; ++ }; ++ + __overrides__ { +- arm_freq; ++ act_led_gpio = <&led_act>,"gpios:4",<&led_act>,"gpios:0=",<&gpio>; ++ act_led_activelow = <&led_act>, "gpios:8"; ++ act_led_trigger = <&led_act>, "linux,default-trigger"; + axiperf = <&axiperf>,"status"; +- ++ bdaddr = <&bluetooth>, "local-bd-address["; ++ button_debounce = <&pwr_key>, "debounce-interval:0"; ++ cooling_fan = <&fan>, "status", <&rp1_pwm1>, "status"; ++ drm_fb0_rp1_dpi = <&aliases>, "drm-fb0=",&dpi; ++ drm_fb0_rp1_dsi0 = <&aliases>, "drm-fb0=",&dsi0; ++ drm_fb0_rp1_dsi1 = <&aliases>, "drm-fb0=",&dsi1; ++ drm_fb0_vc4 = <&aliases>, "drm-fb0=",&vc4; ++ drm_fb1_rp1_dpi = <&aliases>, "drm-fb1=",&dpi; ++ drm_fb1_rp1_dsi0 = <&aliases>, "drm-fb1=",&dsi0; ++ drm_fb1_rp1_dsi1 = <&aliases>, "drm-fb1=",&dsi1; ++ drm_fb1_vc4 = <&aliases>, "drm-fb1=",&vc4; ++ drm_fb2_rp1_dpi = <&aliases>, "drm-fb2=",&dpi; ++ drm_fb2_rp1_dsi0 = <&aliases>, "drm-fb2=",&dsi0; ++ drm_fb2_rp1_dsi1 = <&aliases>, "drm-fb2=",&dsi1; ++ drm_fb2_vc4 = <&aliases>, "drm-fb2=",&vc4; ++ eth_led0 = <&phy1>,"led-modes:0"; ++ eth_led1 = <&phy1>,"led-modes:4"; ++ fan_temp0 = <&cpu_tepid>,"temperature:0"; ++ fan_temp0_hyst = <&cpu_tepid>,"hysteresis:0"; ++ fan_temp0_speed = <&fan>, "cooling-levels:4"; ++ fan_temp1 = <&cpu_warm>,"temperature:0"; ++ fan_temp1_hyst = <&cpu_warm>,"hysteresis:0"; ++ fan_temp1_speed = <&fan>, "cooling-levels:8"; ++ fan_temp2 = <&cpu_hot>,"temperature:0"; ++ fan_temp2_hyst = <&cpu_hot>,"hysteresis:0"; ++ fan_temp2_speed = <&fan>, "cooling-levels:12"; ++ fan_temp3 = <&cpu_vhot>,"temperature:0"; ++ fan_temp3_hyst = <&cpu_vhot>,"hysteresis:0"; ++ fan_temp3_speed = <&fan>, "cooling-levels:16"; ++ i2c = <&i2c1>, "status"; ++ i2c_arm = <&i2c_arm>, "status"; ++ i2c_arm_baudrate = <&i2c_arm>, "clock-frequency:0"; ++ i2c_baudrate = <&i2c_arm>, "clock-frequency:0"; ++ i2c_csi_dsi = <&i2c_csi_dsi>, "status"; ++ i2c_csi_dsi0 = <&i2c_csi_dsi0>, "status"; ++ i2c_csi_dsi1 = <&i2c_csi_dsi1>, "status"; ++ i2c_vc = <&i2c_vc>, "status"; ++ i2c_vc_baudrate = <&i2c_vc>, "clock-frequency:0"; ++ i2c0 = <&i2c0>, "status"; ++ i2c0_baudrate = <&i2c0>, "clock-frequency:0"; ++ i2c1 = <&i2c1>, "status"; ++ i2c1_baudrate = <&i2c1>, "clock-frequency:0"; ++ krnbt = <&bluetooth>, "status"; ++ nvme = <&pciex1>, "status"; + nvmem_cust_rw = <&nvmem_cust>,"rw?"; +- nvmem_priv_rw = <&nvmem_priv>,"rw?"; + nvmem_mac_rw = <&nvmem_mac>,"rw?"; ++ nvmem_priv_rw = <&nvmem_priv>,"rw?"; ++ pcie_tperst_clk_ms = <&pciex1>, "brcm,tperst-clk-ms:0"; ++ pciex1 = <&pciex1>, "status"; ++ pciex1_gen = <&pciex1> , "max-link-speed:0"; ++ pciex1_no_l0s = <&pciex1>, "aspm-no-l0s?"; ++ pciex1_tperst_clk_ms = <&pciex1>, "brcm,tperst-clk-ms:0"; ++ pwr_led_gpio = <&led_pwr>, "gpios:4"; ++ pwr_led_activelow = <&led_pwr>, "gpios:8"; ++ pwr_led_trigger = <&led_pwr>, "linux,default-trigger"; ++ random = <&random>, "status"; ++ rtc = <&rpi_rtc>, "status"; ++ rtc_bbat_vchg = <&rpi_rtc>, "trickle-charge-microvolt:0"; ++ spi = <&spi0>, "status"; + strict_gpiod = <&chosen>, "bootargs=pinctrl_rp1.persist_gpio_outputs=n"; ++ suspend = <&pwr_key>, "linux,code:0=205"; ++ uart0 = <&uart0>, "status"; ++ uart0_console = <&uart0>,"status", <&aliases>, "console=",&uart0; ++ wifiaddr = <&wifi>, "local-mac-address["; + + cam0_reg = <&cam0_reg>,"status"; + cam0_reg_gpio = <&cam0_reg>,"gpio:4", +@@ -113,7 +223,6 @@ + cam1_reg = <&cam1_reg>,"status"; + cam1_reg_gpio = <&cam1_reg>,"gpio:4", + <&cam1_reg>,"gpio:0=", <&gpio>; +- + }; + }; + diff --git a/target/linux/bcm27xx/patches-6.6/950-1183-arm64-dts-Give-cm5l-its-own-model-name.patch b/target/linux/bcm27xx/patches-6.6/950-1183-arm64-dts-Give-cm5l-its-own-model-name.patch new file mode 100644 index 0000000000..72279e130c --- /dev/null +++ b/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 +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 +--- + arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l.dtsi | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l.dtsi ++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l.dtsi +@@ -4,6 +4,8 @@ + #include "bcm2712-rpi-cm5.dtsi" + + / { ++ model = "Raspberry Pi Compute Module 5 Lite"; ++ + __overrides__ { + i2c_csi_dsi = <&i2c_csi_dsi>, "status"; + }; diff --git a/target/linux/bcm27xx/patches-6.6/950-1185-pinctrl-rp1-jump-through-hoops-to-avoid-PCIe-latency.patch b/target/linux/bcm27xx/patches-6.6/950-1185-pinctrl-rp1-jump-through-hoops-to-avoid-PCIe-latency.patch new file mode 100644 index 0000000000..fecfb7a200 --- /dev/null +++ b/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 +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 +--- + drivers/pinctrl/pinctrl-rp1.c | 120 +++++++++++++++++++++++++++++----- + 1 file changed, 105 insertions(+), 15 deletions(-) + +--- a/drivers/pinctrl/pinctrl-rp1.c ++++ b/drivers/pinctrl/pinctrl-rp1.c +@@ -197,6 +197,7 @@ struct rp1_pin_info { + void __iomem *inte; + void __iomem *ints; + void __iomem *pad; ++ void __iomem *dummy; + }; + + enum funcs { +@@ -276,6 +277,7 @@ struct rp1_pinctrl { + void __iomem *gpio_base; + void __iomem *rio_base; + void __iomem *pads_base; ++ void __iomem *dummy_base; + int irq[RP1_NUM_BANKS]; + struct rp1_pin_info pins[RP1_NUM_GPIOS]; + +@@ -577,6 +579,42 @@ static bool persist_gpio_outputs = true; + module_param(persist_gpio_outputs, bool, 0644); + MODULE_PARM_DESC(persist_gpio_outputs, "Enable GPIO_OUT persistence when pin is freed"); + ++static bool pace_pin_updates = true; ++module_param(pace_pin_updates, bool, 0644); ++MODULE_PARM_DESC(pace_pin_updates, "Update pin states with guaranteed monotonicity if PCIe ASPM is enabled"); ++ ++static inline void rp1_pin_writel(u32 val, void __iomem *dummy, void __iomem *reg) ++{ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ /* ++ * Issuing 6 pipelined writes to the RC's Slot Control register will stall the ++ * peripheral bus inside 2712 if the link is in L1. This acts as a lightweight ++ * "fence" operation preventing back-to-back writes arriving at RP1 on a wake. ++ */ ++ if (dummy) { ++ writel_relaxed(0, dummy); ++ writel_relaxed(0, dummy); ++ writel_relaxed(0, dummy); ++ writel_relaxed(0, dummy); ++ writel_relaxed(0, dummy); ++ writel_relaxed(0, dummy); ++ } ++ writel_relaxed(val, reg); ++ local_irq_restore(flags); ++} ++ ++static inline u32 rp1_pin_readl(const void __iomem *ioaddr) ++{ ++ /* ++ * Prior posted writes may not yet have been emitted by the CPU - do a store-flush ++ * before reading GPIO state, as this will serialise writes versus the next issued read. ++ */ ++ __dma_wmb(); ++ return readl(ioaddr); ++} ++ + static int rp1_pinconf_set(struct pinctrl_dev *pctldev, + unsigned int offset, unsigned long *configs, + unsigned int num_configs); +@@ -603,12 +641,12 @@ static struct rp1_pin_info *rp1_get_pin_ + + static void rp1_pad_update(struct rp1_pin_info *pin, u32 clr, u32 set) + { +- u32 padctrl = readl(pin->pad); ++ u32 padctrl = rp1_pin_readl(pin->pad); + + padctrl &= ~clr; + padctrl |= set; + +- writel(padctrl, pin->pad); ++ rp1_pin_writel(padctrl, pin->dummy, pin->pad); + } + + static void rp1_input_enable(struct rp1_pin_info *pin, int value) +@@ -625,7 +663,7 @@ static void rp1_output_enable(struct rp1 + + static u32 rp1_get_fsel(struct rp1_pin_info *pin) + { +- u32 ctrl = readl(pin->gpio + RP1_GPIO_CTRL); ++ u32 ctrl = rp1_pin_readl(pin->gpio + RP1_GPIO_CTRL); + u32 oeover = FLD_GET(ctrl, RP1_GPIO_CTRL_OEOVER); + u32 fsel = FLD_GET(ctrl, RP1_GPIO_CTRL_FUNCSEL); + +@@ -637,7 +675,7 @@ static u32 rp1_get_fsel(struct rp1_pin_i + + static void rp1_set_fsel(struct rp1_pin_info *pin, u32 fsel) + { +- u32 ctrl = readl(pin->gpio + RP1_GPIO_CTRL); ++ u32 ctrl = rp1_pin_readl(pin->gpio + RP1_GPIO_CTRL); + + if (fsel >= RP1_FSEL_COUNT) + fsel = RP1_FSEL_NONE_HW; +@@ -652,12 +690,12 @@ static void rp1_set_fsel(struct rp1_pin_ + FLD_SET(ctrl, RP1_GPIO_CTRL_OEOVER, RP1_OEOVER_PERI); + } + FLD_SET(ctrl, RP1_GPIO_CTRL_FUNCSEL, fsel); +- writel(ctrl, pin->gpio + RP1_GPIO_CTRL); ++ rp1_pin_writel(ctrl, pin->dummy, pin->gpio + RP1_GPIO_CTRL); + } + + static int rp1_get_dir(struct rp1_pin_info *pin) + { +- return !(readl(pin->rio + RP1_RIO_OE) & (1 << pin->offset)) ? ++ return !(rp1_pin_readl(pin->rio + RP1_RIO_OE) & (1 << pin->offset)) ? + RP1_DIR_INPUT : RP1_DIR_OUTPUT; + } + +@@ -665,19 +703,19 @@ static void rp1_set_dir(struct rp1_pin_i + { + int offset = is_input ? RP1_CLR_OFFSET : RP1_SET_OFFSET; + +- writel(1 << pin->offset, pin->rio + RP1_RIO_OE + offset); ++ rp1_pin_writel(1 << pin->offset, pin->dummy, pin->rio + RP1_RIO_OE + offset); + } + + static int rp1_get_value(struct rp1_pin_info *pin) + { +- return !!(readl(pin->rio + RP1_RIO_IN) & (1 << pin->offset)); ++ return !!(rp1_pin_readl(pin->rio + RP1_RIO_IN) & (1 << pin->offset)); + } + + static void rp1_set_value(struct rp1_pin_info *pin, int value) + { + /* Assume the pin is already an output */ +- writel(1 << pin->offset, +- pin->rio + RP1_RIO_OUT + (value ? RP1_SET_OFFSET : RP1_CLR_OFFSET)); ++ rp1_pin_writel(1 << pin->offset, pin->dummy, ++ pin->rio + RP1_RIO_OUT + (value ? RP1_SET_OFFSET : RP1_CLR_OFFSET)); + } + + static int rp1_gpio_get(struct gpio_chip *chip, unsigned offset) +@@ -1298,7 +1336,7 @@ static const struct pinmux_ops rp1_pmx_o + + static void rp1_pull_config_set(struct rp1_pin_info *pin, unsigned int arg) + { +- u32 padctrl = readl(pin->pad); ++ u32 padctrl = rp1_pin_readl(pin->pad); + + FLD_SET(padctrl, RP1_PAD_PULL, arg & 0x3); + +@@ -1398,7 +1436,7 @@ static int rp1_pinconf_get(struct pinctr + if (!pin) + return -EINVAL; + +- padctrl = readl(pin->pad); ++ padctrl = rp1_pin_readl(pin->pad); + + switch (param) { + case PIN_CONFIG_INPUT_ENABLE: +@@ -1493,6 +1531,7 @@ static int rp1_pinctrl_probe(struct plat + { + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; ++ struct device_node *rp1_node = NULL; + struct rp1_pinctrl *pc; + struct gpio_irq_chip *girq; + int err, i; +@@ -1528,6 +1567,40 @@ static int rp1_pinctrl_probe(struct plat + pc->gpio_chip = rp1_gpio_chip; + pc->gpio_chip.parent = dev; + ++ /* ++ * Workaround for the vagaries of PCIe on BCM2712 ++ * ++ * If the link to RP1 is in L1, then the BRCMSTB RC will buffer many ++ * outbound writes - and generate write responses for them, despite the ++ * fact that the link is not yet active. This has the effect of compressing ++ * multiple writes to GPIOs together, destroying any pacing that an application ++ * may require in the 1-10us range. ++ * ++ * The RC Slot Control configuration register is special. It emits a ++ * MsgD for every write to it, will stall further writes until the message ++ * goes out on the wire. This can be (ab)used to force CPU stalls when the ++ * link is inactive, at the cost of a small amount of downstream bandwidth ++ * and some 200ns of added latency for each write. ++ * ++ * Several back-to-back configuration writes are necessary to "fill the pipe", ++ * otherwise the outbound MAC can consume a pending MMIO write and reorder ++ * it with respect to the config writes - undoing the intent. ++ * ++ * of_iomap() is used directly here as the address overlaps with the RC driver's ++ * usage. ++ */ ++ rp1_node = of_find_node_by_name(NULL, "rp1"); ++ if (!rp1_node) ++ dev_err(&pdev->dev, "failed to find RP1 DT node\n"); ++ else if (pace_pin_updates && ++ of_device_is_compatible(rp1_node->parent, "brcm,bcm2712-pcie")) { ++ pc->dummy_base = of_iomap(rp1_node->parent, 0); ++ if (IS_ERR(pc->dummy_base)) { ++ dev_warn(&pdev->dev, "could not map bcm2712 root complex registers\n"); ++ pc->dummy_base = NULL; ++ } ++ } ++ + for (i = 0; i < RP1_NUM_BANKS; i++) { + const struct rp1_iobank_desc *bank = &rp1_iobanks[i]; + int j; +@@ -1547,14 +1620,17 @@ static int rp1_pinctrl_probe(struct plat + pin->rio = pc->rio_base + bank->rio_offset; + pin->pad = pc->pads_base + bank->pads_offset + + j * sizeof(u32); ++ pin->dummy = pc->dummy_base ? pc->dummy_base + 0xc0 : NULL; + } + + raw_spin_lock_init(&pc->irq_lock[i]); + } + + pc->pctl_dev = devm_pinctrl_register(dev, &rp1_pinctrl_desc, pc); +- if (IS_ERR(pc->pctl_dev)) +- return PTR_ERR(pc->pctl_dev); ++ if (IS_ERR(pc->pctl_dev)) { ++ err = PTR_ERR(pc->pctl_dev); ++ goto out_iounmap; ++ } + + girq = &pc->gpio_chip.irq; + girq->chip = &rp1_gpio_irq_chip; +@@ -1583,7 +1659,7 @@ static int rp1_pinctrl_probe(struct plat + err = devm_gpiochip_add_data(dev, &pc->gpio_chip, pc); + if (err) { + dev_err(dev, "could not add GPIO chip\n"); +- return err; ++ goto out_iounmap; + } + + pc->gpio_range = rp1_pinctrl_gpio_range; +@@ -1592,10 +1668,24 @@ static int rp1_pinctrl_probe(struct plat + pinctrl_add_gpio_range(pc->pctl_dev, &pc->gpio_range); + + return 0; ++ ++out_iounmap: ++ if (pc->dummy_base) ++ iounmap(pc->dummy_base); ++ return err; ++} ++ ++static void rp1_pinctrl_remove(struct platform_device *pdev) ++{ ++ struct rp1_pinctrl *pc = platform_get_drvdata(pdev); ++ ++ if (pc->dummy_base) ++ iounmap(pc->dummy_base); + } + + static struct platform_driver rp1_pinctrl_driver = { + .probe = rp1_pinctrl_probe, ++ .remove_new = rp1_pinctrl_remove, + .driver = { + .name = MODULE_NAME, + .of_match_table = rp1_pinctrl_match, diff --git a/target/linux/bcm27xx/patches-6.6/950-1186-staging-bcm2835-codec-Disable-HEADER_ON_OPEN-for-vid.patch b/target/linux/bcm27xx/patches-6.6/950-1186-staging-bcm2835-codec-Disable-HEADER_ON_OPEN-for-vid.patch new file mode 100644 index 0000000000..a8fbeaf062 --- /dev/null +++ b/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 +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 +--- + .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c ++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +@@ -2731,6 +2731,13 @@ static int bcm2835_codec_create_componen + ¶ms, + sizeof(params)); + ++ } else if (dev->role == ENCODE) { ++ enable = 0; ++ vchiq_mmal_port_parameter_set(dev->instance, ++ &ctx->component->control, ++ MMAL_PARAMETER_VIDEO_ENCODE_HEADER_ON_OPEN, ++ &enable, ++ sizeof(enable)); + } else if (dev->role == ENCODE_IMAGE) { + enable = 0; + vchiq_mmal_port_parameter_set(dev->instance, diff --git a/target/linux/bcm27xx/patches-6.6/950-1188-staging-bcm2835-codec-Add-support-for-H264-level-5.0.patch b/target/linux/bcm27xx/patches-6.6/950-1188-staging-bcm2835-codec-Add-support-for-H264-level-5.0.patch new file mode 100644 index 0000000000..f3c53adf50 --- /dev/null +++ b/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 +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 +--- + .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c ++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +@@ -3273,7 +3273,7 @@ static void dec_add_profile_ctrls(struct + case V4L2_PIX_FMT_H264: + ctrl = v4l2_ctrl_new_std_menu(hdl, &bcm2835_codec_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_LEVEL, +- V4L2_MPEG_VIDEO_H264_LEVEL_4_2, ++ V4L2_MPEG_VIDEO_H264_LEVEL_5_1, + ~(BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | +@@ -3287,7 +3287,9 @@ static void dec_add_profile_ctrls(struct + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | +- BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2)), ++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | ++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | ++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1)), + V4L2_MPEG_VIDEO_H264_LEVEL_4_0); + ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + ctrl = v4l2_ctrl_new_std_menu(hdl, &bcm2835_codec_ctrl_ops, diff --git a/target/linux/bcm27xx/patches-6.6/950-1189-spi-dw-Save-bandwidth-with-the-TMOD_TO-feature.patch b/target/linux/bcm27xx/patches-6.6/950-1189-spi-dw-Save-bandwidth-with-the-TMOD_TO-feature.patch new file mode 100644 index 0000000000..66ff22eb7f --- /dev/null +++ b/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 +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 +--- + drivers/spi/spi-dw-core.c | 27 +++++++++++++++++---------- + 1 file changed, 17 insertions(+), 10 deletions(-) + +--- a/drivers/spi/spi-dw-core.c ++++ b/drivers/spi/spi-dw-core.c +@@ -225,12 +225,17 @@ static irqreturn_t dw_spi_transfer_handl + * final stage of the transfer. By doing so we'll get the next IRQ + * right when the leftover incoming data is received. + */ +- dw_reader(dws); +- if (!dws->rx_len) { +- dw_spi_mask_intr(dws, 0xff); ++ if (dws->rx_len) { ++ dw_reader(dws); ++ if (!dws->rx_len) { ++ dw_spi_mask_intr(dws, 0xff); ++ spi_finalize_current_transfer(dws->host); ++ } else if (dws->rx_len <= dw_readl(dws, DW_SPI_RXFTLR)) { ++ dw_writel(dws, DW_SPI_RXFTLR, dws->rx_len - 1); ++ } ++ } else if (!dws->tx_len) { ++ dw_spi_mask_intr(dws, DW_SPI_INT_TXEI); + spi_finalize_current_transfer(dws->host); +- } else if (dws->rx_len <= dw_readl(dws, DW_SPI_RXFTLR)) { +- dw_writel(dws, DW_SPI_RXFTLR, dws->rx_len - 1); + } + + /* +@@ -239,12 +244,9 @@ static irqreturn_t dw_spi_transfer_handl + * have the TXE IRQ flood at the final stage of the transfer. + */ + if (irq_status & DW_SPI_INT_TXEI) { +- dw_writer(dws); +- if (!dws->tx_len) { ++ if (!dws->tx_len) + dw_spi_mask_intr(dws, DW_SPI_INT_TXEI); +- if (!dws->rx_len) +- spi_finalize_current_transfer(dws->host); +- } ++ dw_writer(dws); + } + + return IRQ_HANDLED; +@@ -437,6 +439,11 @@ static int dw_spi_transfer_one(struct sp + dws->rx = transfer->rx_buf; + dws->rx_len = dws->tx_len; + ++ if (!dws->rx) { ++ dws->rx_len = 0; ++ cfg.tmode = DW_SPI_CTRLR0_TMOD_TO; ++ } ++ + /* Ensure the data above is visible for all CPUs */ + smp_mb(); + diff --git a/target/linux/bcm27xx/patches-6.6/950-1190-spi-dw-Save-bandwidth-with-the-TMOD_RO-feature.patch b/target/linux/bcm27xx/patches-6.6/950-1190-spi-dw-Save-bandwidth-with-the-TMOD_RO-feature.patch new file mode 100644 index 0000000000..7791b99b6d --- /dev/null +++ b/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 +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 +--- + 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 ++#include + #include + #include + #include +@@ -470,13 +471,12 @@ static int dw_spi_dma_setup(struct dw_sp + u16 imr, dma_ctrl; + int ret; + +- if (!xfer->tx_buf) +- return -EINVAL; +- + /* Setup DMA channels */ +- ret = dw_spi_dma_config_tx(dws); +- if (ret) +- return ret; ++ if (xfer->tx_buf) { ++ ret = dw_spi_dma_config_tx(dws); ++ if (ret) ++ return ret; ++ } + + if (xfer->rx_buf) { + ret = dw_spi_dma_config_rx(dws); +@@ -485,13 +485,17 @@ static int dw_spi_dma_setup(struct dw_sp + } + + /* Set the DMA handshaking interface */ +- dma_ctrl = DW_SPI_DMACR_TDMAE; ++ dma_ctrl = 0; ++ if (xfer->tx_buf) ++ dma_ctrl |= DW_SPI_DMACR_TDMAE; + if (xfer->rx_buf) + dma_ctrl |= DW_SPI_DMACR_RDMAE; + dw_writel(dws, DW_SPI_DMACR, dma_ctrl); + + /* Set the interrupt mask */ +- imr = DW_SPI_INT_TXOI; ++ imr = 0; ++ if (xfer->tx_buf) ++ imr |= DW_SPI_INT_TXOI; + if (xfer->rx_buf) + imr |= DW_SPI_INT_RXUI | DW_SPI_INT_RXOI; + dw_spi_umask_intr(dws, imr); +@@ -508,15 +512,16 @@ static int dw_spi_dma_transfer_all(struc + { + int ret; + +- /* Submit the DMA Tx transfer */ +- ret = dw_spi_dma_submit_tx(dws, xfer->tx_sg.sgl, xfer->tx_sg.nents); +- if (ret) +- goto err_clear_dmac; ++ /* Submit the DMA Tx transfer if required */ ++ if (xfer->tx_buf) { ++ ret = dw_spi_dma_submit_tx(dws, xfer->tx_sg.sgl, xfer->tx_sg.nents); ++ if (ret) ++ goto err_clear_dmac; ++ } + + /* Submit the DMA Rx transfer if required */ + if (xfer->rx_buf) { +- ret = dw_spi_dma_submit_rx(dws, xfer->rx_sg.sgl, +- xfer->rx_sg.nents); ++ ret = dw_spi_dma_submit_rx(dws, xfer->rx_sg.sgl, xfer->rx_sg.nents); + if (ret) + goto err_clear_dmac; + +@@ -524,7 +529,15 @@ static int dw_spi_dma_transfer_all(struc + dma_async_issue_pending(dws->rxchan); + } + +- dma_async_issue_pending(dws->txchan); ++ if (xfer->tx_buf) { ++ dma_async_issue_pending(dws->txchan); ++ } else { ++ /* Pause to allow DMA channel to fetch RX descriptor */ ++ usleep_range(5, 10); ++ ++ /* Write something to the TX FIFO to start the transfer */ ++ dw_writel(dws, DW_SPI_DR, 0); ++ } + + ret = dw_spi_dma_wait(dws, xfer->len, xfer->effective_speed_hz); + diff --git a/target/linux/bcm27xx/patches-6.6/950-1191-spi-dw-don-t-immediately-kill-DMA-transfers-if-an-er.patch b/target/linux/bcm27xx/patches-6.6/950-1191-spi-dw-don-t-immediately-kill-DMA-transfers-if-an-er.patch new file mode 100644 index 0000000000..45400204c4 --- /dev/null +++ b/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 +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 +--- + drivers/spi/spi-dw-core.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +--- a/drivers/spi/spi-dw-core.c ++++ b/drivers/spi/spi-dw-core.c +@@ -200,7 +200,18 @@ int dw_spi_check_status(struct dw_spi *d + + /* Generically handle the erroneous situation */ + if (ret) { +- dw_spi_reset_chip(dws); ++ /* ++ * Forcibly halting the controller can cause DMA to hang. ++ * Defer to dw_spi_handle_err outside of interrupt context ++ * and mask further interrupts for the current transfer. ++ */ ++ if (dws->dma_mapped) { ++ dw_spi_mask_intr(dws, 0xff); ++ dw_readl(dws, DW_SPI_ICR); ++ } else { ++ dw_spi_reset_chip(dws); ++ } ++ + if (dws->host->cur_msg) + dws->host->cur_msg->status = ret; + } diff --git a/target/linux/bcm27xx/patches-6.6/950-1192-dts-rp1-hobble-DMA-AXI-burst-lengths.patch b/target/linux/bcm27xx/patches-6.6/950-1192-dts-rp1-hobble-DMA-AXI-burst-lengths.patch new file mode 100644 index 0000000000..9cfdefec7d --- /dev/null +++ b/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 +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 +--- + arch/arm64/boot/dts/broadcom/rp1.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/arm64/boot/dts/broadcom/rp1.dtsi ++++ b/arch/arm64/boot/dts/broadcom/rp1.dtsi +@@ -1064,7 +1064,7 @@ + snps,data-width = <4>; // (8 << 4) == 128 bits + snps,block-size = <0x40000 0x40000 0x40000 0x40000 0x40000 0x40000 0x40000 0x40000>; + snps,priority = <0 1 2 3 4 5 6 7>; +- snps,axi-max-burst-len = <8>; ++ snps,axi-max-burst-len = <4>; + status = "disabled"; + }; + diff --git a/target/linux/bcm27xx/patches-6.6/950-1193-drivers-dw-axi-dmac-make-more-sensible-choices-about.patch b/target/linux/bcm27xx/patches-6.6/950-1193-drivers-dw-axi-dmac-make-more-sensible-choices-about.patch new file mode 100644 index 0000000000..d336532f46 --- /dev/null +++ b/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 +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 +--- + .../dma/dw-axi-dmac/dw-axi-dmac-platform.c | 38 ++++++++++++------- + 1 file changed, 25 insertions(+), 13 deletions(-) + +--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c ++++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +@@ -261,6 +261,15 @@ static u32 axi_chan_get_xfer_width(struc + return __ffs(src | dst | len | BIT(max_width)); + } + ++static u32 axi_dma_encode_msize(u32 max_burst) ++{ ++ if (max_burst <= 1) ++ return DWAXIDMAC_BURST_TRANS_LEN_1; ++ if (max_burst > 1024) ++ return DWAXIDMAC_BURST_TRANS_LEN_1024; ++ return fls(max_burst) - 2; ++} ++ + static inline const char *axi_chan_name(struct axi_dma_chan *chan) + { + return dma_chan_name(&chan->vc.chan); +@@ -685,41 +694,41 @@ static int dw_axi_dma_set_hw_desc(struct + size_t axi_block_ts; + size_t block_ts; + u32 ctllo, ctlhi; +- u32 burst_len; ++ u32 burst_len = 0, mem_burst_msize, reg_burst_msize; + + axi_block_ts = chan->chip->dw->hdata->block_size[chan->id]; + + mem_width = __ffs(data_width | mem_addr | len); +- if (mem_width > DWAXIDMAC_TRANS_WIDTH_32) +- mem_width = DWAXIDMAC_TRANS_WIDTH_32; + + if (!IS_ALIGNED(mem_addr, 4)) { + dev_err(chan->chip->dev, "invalid buffer alignment\n"); + return -EINVAL; + } + ++ /* Use a reasonable upper limit otherwise residue reporting granularity grows large */ ++ mem_burst_msize = axi_dma_encode_msize(16); ++ + switch (chan->direction) { + case DMA_MEM_TO_DEV: ++ reg_burst_msize = axi_dma_encode_msize(chan->config.dst_maxburst); + reg_width = __ffs(chan->config.dst_addr_width); + device_addr = phys_to_dma(chan->chip->dev, chan->config.dst_addr); + ctllo = reg_width << CH_CTL_L_DST_WIDTH_POS | + mem_width << CH_CTL_L_SRC_WIDTH_POS | +- DWAXIDMAC_BURST_TRANS_LEN_1 << CH_CTL_L_DST_MSIZE_POS | +- DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_SRC_MSIZE_POS | ++ reg_burst_msize << CH_CTL_L_DST_MSIZE_POS | ++ mem_burst_msize << CH_CTL_L_SRC_MSIZE_POS | + DWAXIDMAC_CH_CTL_L_NOINC << CH_CTL_L_DST_INC_POS | + DWAXIDMAC_CH_CTL_L_INC << CH_CTL_L_SRC_INC_POS; + block_ts = len >> mem_width; + break; + case DMA_DEV_TO_MEM: ++ reg_burst_msize = axi_dma_encode_msize(chan->config.src_maxburst); + reg_width = __ffs(chan->config.src_addr_width); +- /* Prevent partial access units getting lost */ +- if (mem_width > reg_width) +- mem_width = reg_width; + device_addr = phys_to_dma(chan->chip->dev, chan->config.src_addr); + ctllo = reg_width << CH_CTL_L_SRC_WIDTH_POS | + mem_width << CH_CTL_L_DST_WIDTH_POS | +- DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_DST_MSIZE_POS | +- DWAXIDMAC_BURST_TRANS_LEN_1 << CH_CTL_L_SRC_MSIZE_POS | ++ mem_burst_msize << CH_CTL_L_DST_MSIZE_POS | ++ reg_burst_msize << CH_CTL_L_SRC_MSIZE_POS | + DWAXIDMAC_CH_CTL_L_INC << CH_CTL_L_DST_INC_POS | + DWAXIDMAC_CH_CTL_L_NOINC << CH_CTL_L_SRC_INC_POS; + block_ts = len >> reg_width; +@@ -760,6 +769,12 @@ static int dw_axi_dma_set_hw_desc(struct + set_desc_src_master(hw_desc); + + hw_desc->len = len; ++ ++ if (burst_len && (chan->config.src_maxburst > burst_len)) ++ dev_warn_ratelimited(chan2dev(chan), ++ "%s: requested source burst length %u exceeds supported burst length %u - data may be lost\n", ++ axi_chan_name(chan), chan->config.src_maxburst, burst_len); ++ + return 0; + } + +@@ -776,9 +791,6 @@ static size_t calculate_block_len(struct + case DMA_MEM_TO_DEV: + data_width = BIT(chan->chip->dw->hdata->m_data_width); + mem_width = __ffs(data_width | dma_addr | buf_len); +- if (mem_width > DWAXIDMAC_TRANS_WIDTH_32) +- mem_width = DWAXIDMAC_TRANS_WIDTH_32; +- + block_len = axi_block_ts << mem_width; + break; + case DMA_DEV_TO_MEM: diff --git a/target/linux/bcm27xx/patches-6.6/950-1195-tty-serial-pl011-restrict-RX-burst-FIFO-threshold.patch b/target/linux/bcm27xx/patches-6.6/950-1195-tty-serial-pl011-restrict-RX-burst-FIFO-threshold.patch new file mode 100644 index 0000000000..62731aeb34 --- /dev/null +++ b/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 +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 +--- + drivers/tty/serial/amba-pl011.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/drivers/tty/serial/amba-pl011.c ++++ b/drivers/tty/serial/amba-pl011.c +@@ -487,6 +487,12 @@ static void pl011_dma_probe(struct uart_ + "RX DMA disabled - no residue processing\n"); + return; + } ++ /* ++ * DMA controllers with smaller burst capabilities than 1/4 ++ * the FIFO depth will leave more bytes than expected in the ++ * RX FIFO if mismatched. ++ */ ++ rx_conf.src_maxburst = min(caps.max_burst, rx_conf.src_maxburst); + } + dmaengine_slave_config(chan, &rx_conf); + uap->dmarx.chan = chan; diff --git a/target/linux/bcm27xx/patches-6.6/950-1196-DT-bindings-add-a-dma-maxburst-property-to-snps-desi.patch b/target/linux/bcm27xx/patches-6.6/950-1196-DT-bindings-add-a-dma-maxburst-property-to-snps-desi.patch new file mode 100644 index 0000000000..0d0afc2f9c --- /dev/null +++ b/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 +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 +--- + .../devicetree/bindings/sound/snps,designware-i2s.yaml | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/Documentation/devicetree/bindings/sound/snps,designware-i2s.yaml ++++ b/Documentation/devicetree/bindings/sound/snps,designware-i2s.yaml +@@ -69,6 +69,10 @@ properties: + - description: RX DMA Channel + minItems: 1 + ++ dma-maxburst: ++ description: FIFO DMA burst threshold limit ++ maxItems: 1 ++ + dma-names: + items: + - const: tx diff --git a/target/linux/bcm27xx/patches-6.6/950-1197-sound-soc-dwc-i2s-choose-FIFO-thresholds-based-on-DM.patch b/target/linux/bcm27xx/patches-6.6/950-1197-sound-soc-dwc-i2s-choose-FIFO-thresholds-based-on-DM.patch new file mode 100644 index 0000000000..d0e3bc1fab --- /dev/null +++ b/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 +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 +--- + sound/soc/dwc/dwc-i2s.c | 21 ++++++++++++++++----- + sound/soc/dwc/local.h | 1 + + 2 files changed, 17 insertions(+), 5 deletions(-) + +--- a/sound/soc/dwc/dwc-i2s.c ++++ b/sound/soc/dwc/dwc-i2s.c +@@ -236,6 +236,8 @@ static void dw_i2s_config(struct dw_i2s_ + u32 ch_reg; + struct i2s_clk_config_data *config = &dev->config; + u32 dmacr; ++ u32 comp1 = i2s_read_reg(dev->i2s_base, dev->i2s_reg_comp1); ++ u32 fifo_depth = 1 << (1 + COMP1_FIFO_DEPTH_GLOBAL(comp1)); + + i2s_disable_channels(dev, stream); + +@@ -251,7 +253,7 @@ static void dw_i2s_config(struct dw_i2s_ + i2s_write_reg(dev->i2s_base, TCR(ch_reg), + dev->xfer_resolution); + i2s_write_reg(dev->i2s_base, TFCR(ch_reg), +- dev->fifo_th - 1); ++ fifo_depth - dev->fifo_th - 1); + i2s_write_reg(dev->i2s_base, TER(ch_reg), TER_TXCHEN | + dev->tdm_mask << TER_TXSLOT_SHIFT); + dmacr |= (DMACR_DMAEN_TXCH0 << ch_reg); +@@ -783,8 +785,8 @@ static int dw_configure_dai_by_pd(struct + dev->capture_dma_data.pd.data = pdata->capture_dma_data; + dev->play_dma_data.pd.addr = res->start + I2S_TXDMA; + dev->capture_dma_data.pd.addr = res->start + I2S_RXDMA; +- dev->play_dma_data.pd.max_burst = 16; +- dev->capture_dma_data.pd.max_burst = 16; ++ dev->play_dma_data.pd.max_burst = dev->fifo_th; ++ dev->capture_dma_data.pd.max_burst = dev->fifo_th; + dev->play_dma_data.pd.addr_width = bus_widths[idx]; + dev->capture_dma_data.pd.addr_width = bus_widths[idx]; + dev->play_dma_data.pd.filter = pdata->filter; +@@ -815,7 +817,10 @@ static int dw_configure_dai_by_dt(struct + dev->play_dma_data.dt.addr = res->start + I2S_TXDMA; + dev->play_dma_data.dt.fifo_size = fifo_depth * + (fifo_width[idx2]) >> 8; +- dev->play_dma_data.dt.maxburst = 16; ++ if (dev->max_dma_burst) ++ dev->play_dma_data.dt.maxburst = dev->max_dma_burst; ++ else ++ dev->play_dma_data.dt.maxburst = fifo_depth / 2; + } + if (COMP1_RX_ENABLED(comp1)) { + idx2 = COMP2_RX_WORDSIZE_0(comp2); +@@ -824,9 +829,14 @@ static int dw_configure_dai_by_dt(struct + dev->capture_dma_data.dt.addr = res->start + I2S_RXDMA; + dev->capture_dma_data.dt.fifo_size = fifo_depth * + (fifo_width[idx2] >> 8); +- dev->capture_dma_data.dt.maxburst = 16; ++ if (dev->max_dma_burst) ++ dev->capture_dma_data.dt.maxburst = dev->max_dma_burst; ++ else ++ dev->capture_dma_data.dt.maxburst = fifo_depth / 2; + } + ++ if (dev->max_dma_burst) ++ dev->fifo_th = min(dev->max_dma_burst, dev->fifo_th); + return 0; + + } +@@ -1070,6 +1080,7 @@ static int dw_i2s_probe(struct platform_ + } + } + ++ of_property_read_u32(pdev->dev.of_node, "dma-maxburst", &dev->max_dma_burst); + dev->bclk_ratio = 0; + dev->i2s_reg_comp1 = I2S_COMP_PARAM_1; + dev->i2s_reg_comp2 = I2S_COMP_PARAM_2; +--- a/sound/soc/dwc/local.h ++++ b/sound/soc/dwc/local.h +@@ -133,6 +133,7 @@ struct dw_i2s_dev { + u32 ccr; + u32 xfer_resolution; + u32 fifo_th; ++ u32 max_dma_burst; + u32 l_reg; + u32 r_reg; + bool is_jh7110; /* Flag for StarFive JH7110 SoC */ diff --git a/target/linux/bcm27xx/patches-6.6/950-1198-dts-rp1-restrict-i2s-burst-lengths-to-4.patch b/target/linux/bcm27xx/patches-6.6/950-1198-dts-rp1-restrict-i2s-burst-lengths-to-4.patch new file mode 100644 index 0000000000..30b8a9f9b8 --- /dev/null +++ b/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 +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 +--- + arch/arm64/boot/dts/broadcom/rp1.dtsi | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/arch/arm64/boot/dts/broadcom/rp1.dtsi ++++ b/arch/arm64/boot/dts/broadcom/rp1.dtsi +@@ -400,6 +400,7 @@ + #sound-dai-cells = <0>; + dmas = <&rp1_dma RP1_DMA_I2S0_TX>,<&rp1_dma RP1_DMA_I2S0_RX>; + dma-names = "tx", "rx"; ++ dma-maxburst = <4>; + status = "disabled"; + }; + +@@ -413,6 +414,7 @@ + #sound-dai-cells = <0>; + dmas = <&rp1_dma RP1_DMA_I2S1_TX>,<&rp1_dma RP1_DMA_I2S1_RX>; + dma-names = "tx", "rx"; ++ dma-maxburst = <4>; + status = "disabled"; + }; + diff --git a/target/linux/bcm27xx/patches-6.6/950-1199-drm-vc4-Disable-the-2pixel-clock-odd-timings-workaro.patch b/target/linux/bcm27xx/patches-6.6/950-1199-drm-vc4-Disable-the-2pixel-clock-odd-timings-workaro.patch new file mode 100644 index 0000000000..4c429e284d --- /dev/null +++ b/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 +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 +--- + drivers/gpu/drm/vc4/vc4_crtc.c | 20 +++++++++++++++++--- + drivers/gpu/drm/vc4/vc4_drv.h | 2 ++ + drivers/gpu/drm/vc4/vc4_hdmi.c | 8 +++++++- + drivers/gpu/drm/vc4/vc4_hdmi.h | 4 ++++ + 4 files changed, 30 insertions(+), 4 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_crtc.c ++++ b/drivers/gpu/drm/vc4/vc4_crtc.c +@@ -378,7 +378,9 @@ static void vc4_crtc_config_pv(struct dr + bool is_dsi1 = vc4_encoder->type == VC4_ENCODER_TYPE_DSI1; + bool is_vec = vc4_encoder->type == VC4_ENCODER_TYPE_VEC; + u32 format = is_dsi1 ? PV_CONTROL_FORMAT_DSIV_24 : PV_CONTROL_FORMAT_24; +- u8 ppc = pv_data->pixels_per_clock; ++ u8 ppc = (mode->flags & DRM_MODE_FLAG_INTERLACE) ? ++ pv_data->pixels_per_clock_int : ++ pv_data->pixels_per_clock; + + u16 vert_bp = mode->crtc_vtotal - mode->crtc_vsync_end; + u16 vert_sync = mode->crtc_vsync_end - mode->crtc_vsync_start; +@@ -443,7 +445,8 @@ static void vc4_crtc_config_pv(struct dr + */ + CRTC_WRITE(PV_V_CONTROL, + PV_VCONTROL_CONTINUOUS | +- (vc4->gen >= VC4_GEN_6 ? PV_VCONTROL_ODD_TIMING : 0) | ++ (vc4->gen >= VC4_GEN_6 && ppc == 1 ? ++ PV_VCONTROL_ODD_TIMING : 0) | + (is_dsi ? PV_VCONTROL_DSI : 0) | + PV_VCONTROL_INTERLACE | + (odd_field_first +@@ -455,7 +458,8 @@ static void vc4_crtc_config_pv(struct dr + } else { + CRTC_WRITE(PV_V_CONTROL, + PV_VCONTROL_CONTINUOUS | +- (vc4->gen >= VC4_GEN_6 ? PV_VCONTROL_ODD_TIMING : 0) | ++ (vc4->gen >= VC4_GEN_6 && ppc == 1 ? ++ PV_VCONTROL_ODD_TIMING : 0) | + (is_dsi ? PV_VCONTROL_DSI : 0)); + CRTC_WRITE(PV_VSYNCD_EVEN, 0); + } +@@ -1223,6 +1227,7 @@ const struct vc4_pv_data bcm2835_pv0_dat + }, + .fifo_depth = 64, + .pixels_per_clock = 1, ++ .pixels_per_clock_int = 1, + .encoder_types = { + [PV_CONTROL_CLK_SELECT_DSI] = VC4_ENCODER_TYPE_DSI0, + [PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_DPI, +@@ -1238,6 +1243,7 @@ const struct vc4_pv_data bcm2835_pv1_dat + }, + .fifo_depth = 64, + .pixels_per_clock = 1, ++ .pixels_per_clock_int = 1, + .encoder_types = { + [PV_CONTROL_CLK_SELECT_DSI] = VC4_ENCODER_TYPE_DSI1, + [PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_SMI, +@@ -1253,6 +1259,7 @@ const struct vc4_pv_data bcm2835_pv2_dat + }, + .fifo_depth = 64, + .pixels_per_clock = 1, ++ .pixels_per_clock_int = 1, + .encoder_types = { + [PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_HDMI0, + [PV_CONTROL_CLK_SELECT_VEC] = VC4_ENCODER_TYPE_VEC, +@@ -1268,6 +1275,7 @@ const struct vc4_pv_data bcm2711_pv0_dat + }, + .fifo_depth = 64, + .pixels_per_clock = 1, ++ .pixels_per_clock_int = 1, + .encoder_types = { + [0] = VC4_ENCODER_TYPE_DSI0, + [1] = VC4_ENCODER_TYPE_DPI, +@@ -1283,6 +1291,7 @@ const struct vc4_pv_data bcm2711_pv1_dat + }, + .fifo_depth = 64, + .pixels_per_clock = 1, ++ .pixels_per_clock_int = 1, + .encoder_types = { + [0] = VC4_ENCODER_TYPE_DSI1, + [1] = VC4_ENCODER_TYPE_SMI, +@@ -1298,6 +1307,7 @@ const struct vc4_pv_data bcm2711_pv2_dat + }, + .fifo_depth = 256, + .pixels_per_clock = 2, ++ .pixels_per_clock_int = 2, + .encoder_types = { + [0] = VC4_ENCODER_TYPE_HDMI0, + }, +@@ -1312,6 +1322,7 @@ const struct vc4_pv_data bcm2711_pv3_dat + }, + .fifo_depth = 64, + .pixels_per_clock = 1, ++ .pixels_per_clock_int = 1, + .encoder_types = { + [PV_CONTROL_CLK_SELECT_VEC] = VC4_ENCODER_TYPE_VEC, + }, +@@ -1326,6 +1337,7 @@ const struct vc4_pv_data bcm2711_pv4_dat + }, + .fifo_depth = 64, + .pixels_per_clock = 2, ++ .pixels_per_clock_int = 2, + .encoder_types = { + [0] = VC4_ENCODER_TYPE_HDMI1, + }, +@@ -1339,6 +1351,7 @@ const struct vc4_pv_data bcm2712_pv0_dat + }, + .fifo_depth = 64, + .pixels_per_clock = 1, ++ .pixels_per_clock_int = 2, + .encoder_types = { + [0] = VC4_ENCODER_TYPE_HDMI0, + }, +@@ -1352,6 +1365,7 @@ const struct vc4_pv_data bcm2712_pv1_dat + }, + .fifo_depth = 64, + .pixels_per_clock = 1, ++ .pixels_per_clock_int = 2, + .encoder_types = { + [0] = VC4_ENCODER_TYPE_HDMI1, + }, +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -569,6 +569,8 @@ struct vc4_pv_data { + + /* Number of pixels output per clock period */ + u8 pixels_per_clock; ++ /* Number of pixels output per clock period when in an interlaced mode */ ++ u8 pixels_per_clock_int; + + enum vc4_encoder_type encoder_types[4]; + }; +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -2263,7 +2263,9 @@ static int vc4_hdmi_encoder_atomic_check + unsigned long long tmds_bit_rate; + int ret; + +- if (vc4_hdmi->variant->unsupported_odd_h_timings) { ++ if (vc4_hdmi->variant->unsupported_odd_h_timings || ++ (vc4_hdmi->variant->unsupported_int_odd_h_timings && ++ (mode->flags & DRM_MODE_FLAG_INTERLACE))) { + if (mode->flags & DRM_MODE_FLAG_DBLCLK) { + /* Only try to fixup DBLCLK modes to get 480i and 576i + * working. +@@ -3974,6 +3976,7 @@ static const struct vc4_hdmi_variant bcm + PHY_LANE_CK, + }, + .unsupported_odd_h_timings = true, ++ .unsupported_int_odd_h_timings = true, + .external_irq_controller = true, + + .init_resources = vc5_hdmi_init_resources, +@@ -4003,6 +4006,7 @@ static const struct vc4_hdmi_variant bcm + PHY_LANE_2, + }, + .unsupported_odd_h_timings = true, ++ .unsupported_int_odd_h_timings = true, + .external_irq_controller = true, + + .init_resources = vc5_hdmi_init_resources, +@@ -4032,6 +4036,7 @@ static const struct vc4_hdmi_variant bcm + PHY_LANE_CK, + }, + .unsupported_odd_h_timings = false, ++ .unsupported_int_odd_h_timings = true, + .external_irq_controller = true, + + .init_resources = vc5_hdmi_init_resources, +@@ -4059,6 +4064,7 @@ static const struct vc4_hdmi_variant bcm + PHY_LANE_CK, + }, + .unsupported_odd_h_timings = false, ++ .unsupported_int_odd_h_timings = true, + .external_irq_controller = true, + + .init_resources = vc5_hdmi_init_resources, +--- a/drivers/gpu/drm/vc4/vc4_hdmi.h ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.h +@@ -49,6 +49,10 @@ struct vc4_hdmi_variant { + + /* The BCM2711 cannot deal with odd horizontal pixel timings */ + bool unsupported_odd_h_timings; ++ /* The BCM2712 can handle odd horizontal pixel timings, but not in ++ * interlaced modes ++ */ ++ bool unsupported_int_odd_h_timings; + + /* + * The BCM2711 CEC/hotplug IRQ controller is shared between the diff --git a/target/linux/bcm27xx/patches-6.6/950-1200-ARM-dts-bcm2712-Fix-invalid-polling-delay-passive-se.patch b/target/linux/bcm27xx/patches-6.6/950-1200-ARM-dts-bcm2712-Fix-invalid-polling-delay-passive-se.patch new file mode 100644 index 0000000000..8a7d86d745 --- /dev/null +++ b/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 +Date: Tue, 30 Jul 2024 19:00:03 +0100 +Subject: [PATCH 1200/1215] ARM: dts: bcm2712: Fix invalid + polling-delay-passive setting + +This produces a hard fail on later (6.11) kernels. + +See: https://lore.kernel.org/all/5802156.DvuYhMxLoT@rjwysocki.net/ + +Signed-off-by: Dom Cobley +--- + arch/arm64/boot/dts/broadcom/bcm2712.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/arm64/boot/dts/broadcom/bcm2712.dtsi ++++ b/arch/arm64/boot/dts/broadcom/bcm2712.dtsi +@@ -40,7 +40,7 @@ + + thermal-zones { + cpu_thermal: cpu-thermal { +- polling-delay-passive = <2000>; ++ polling-delay-passive = <1000>; + polling-delay = <1000>; + coefficients = <(-550) 450000>; + thermal-sensors = <&thermal>; diff --git a/target/linux/bcm27xx/patches-6.6/950-1201-spi-dw-Fix-non-DMA-transmit-only-transfers.patch b/target/linux/bcm27xx/patches-6.6/950-1201-spi-dw-Fix-non-DMA-transmit-only-transfers.patch new file mode 100644 index 0000000000..6545c09186 --- /dev/null +++ b/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 +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 +--- + drivers/spi/spi-dw-core.c | 62 +++++++++++++++++++++++++++++++++------ + drivers/spi/spi-dw.h | 3 ++ + 2 files changed, 56 insertions(+), 9 deletions(-) + +--- a/drivers/spi/spi-dw-core.c ++++ b/drivers/spi/spi-dw-core.c +@@ -220,6 +220,32 @@ int dw_spi_check_status(struct dw_spi *d + } + EXPORT_SYMBOL_NS_GPL(dw_spi_check_status, SPI_DW_CORE); + ++static inline bool dw_spi_ctlr_busy(struct dw_spi *dws) ++{ ++ return dw_readl(dws, DW_SPI_SR) & DW_SPI_SR_BUSY; ++} ++ ++static enum hrtimer_restart dw_spi_hrtimer_handler(struct hrtimer *hr) ++{ ++ struct dw_spi *dws = container_of(hr, struct dw_spi, hrtimer); ++ ++ if (!dw_spi_ctlr_busy(dws)) { ++ spi_finalize_current_transfer(dws->host); ++ return HRTIMER_NORESTART; ++ } ++ ++ if (!dws->idle_wait_retries) { ++ dev_err(&dws->host->dev, "controller stuck at busy\n"); ++ spi_finalize_current_transfer(dws->host); ++ return HRTIMER_NORESTART; ++ } ++ ++ dws->idle_wait_retries--; ++ hrtimer_forward_now(hr, dws->idle_wait_interval); ++ ++ return HRTIMER_RESTART; ++} ++ + static irqreturn_t dw_spi_transfer_handler(struct dw_spi *dws) + { + u16 irq_status = dw_readl(dws, DW_SPI_ISR); +@@ -246,7 +272,22 @@ static irqreturn_t dw_spi_transfer_handl + } + } else if (!dws->tx_len) { + dw_spi_mask_intr(dws, DW_SPI_INT_TXEI); +- spi_finalize_current_transfer(dws->host); ++ if (dw_spi_ctlr_busy(dws)) { ++ ktime_t period = ns_to_ktime(DIV_ROUND_UP(NSEC_PER_SEC, dws->current_freq)); ++ ++ /* ++ * Make the initial wait an underestimate of how long the transfer ++ * should take, then poll rapidly to reduce the delay ++ */ ++ hrtimer_start(&dws->hrtimer, ++ period * (8 * dws->n_bytes - 1), ++ HRTIMER_MODE_REL); ++ dws->idle_wait_retries = 10; ++ dws->idle_wait_interval = period; ++ } else { ++ spi_finalize_current_transfer(dws->host); ++ } ++ return IRQ_HANDLED; + } + + /* +@@ -255,9 +296,13 @@ static irqreturn_t dw_spi_transfer_handl + * have the TXE IRQ flood at the final stage of the transfer. + */ + if (irq_status & DW_SPI_INT_TXEI) { +- if (!dws->tx_len) +- dw_spi_mask_intr(dws, DW_SPI_INT_TXEI); + dw_writer(dws); ++ if (!dws->tx_len) { ++ if (dws->rx_len) ++ dw_spi_mask_intr(dws, DW_SPI_INT_TXEI); ++ else ++ dw_writel(dws, DW_SPI_TXFTLR, 0); ++ } + } + + return IRQ_HANDLED; +@@ -428,7 +473,7 @@ static int dw_spi_poll_transfer(struct d + ret = dw_spi_check_status(dws, true); + if (ret) + return ret; +- } while (dws->rx_len); ++ } while (dws->rx_len || dws->tx_len || dw_spi_ctlr_busy(dws)); + + return 0; + } +@@ -652,11 +697,6 @@ static int dw_spi_write_then_read(struct + return 0; + } + +-static inline bool dw_spi_ctlr_busy(struct dw_spi *dws) +-{ +- return dw_readl(dws, DW_SPI_SR) & DW_SPI_SR_BUSY; +-} +- + static int dw_spi_wait_mem_op_done(struct dw_spi *dws) + { + int retry = DW_SPI_WAIT_RETRIES; +@@ -993,6 +1033,9 @@ int dw_spi_add_host(struct device *dev, + } + } + ++ hrtimer_init(&dws->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); ++ dws->hrtimer.function = dw_spi_hrtimer_handler; ++ + ret = spi_register_controller(host); + if (ret) { + dev_err_probe(dev, ret, "problem registering spi host\n"); +@@ -1018,6 +1061,7 @@ void dw_spi_remove_host(struct dw_spi *d + { + dw_spi_debugfs_remove(dws); + ++ hrtimer_cancel(&dws->hrtimer); + spi_unregister_controller(dws->host); + + if (dws->dma_ops && dws->dma_ops->dma_exit) +--- a/drivers/spi/spi-dw.h ++++ b/drivers/spi/spi-dw.h +@@ -180,6 +180,9 @@ struct dw_spi { + u32 current_freq; /* frequency in hz */ + u32 cur_rx_sample_dly; + u32 def_rx_sample_dly_ns; ++ struct hrtimer hrtimer; ++ ktime_t idle_wait_interval; ++ int idle_wait_retries; + + /* Custom memory operations */ + struct spi_controller_mem_ops mem_ops; diff --git a/target/linux/bcm27xx/patches-6.6/950-1202-spi-dw-Clamp-the-minimum-clock-speed.patch b/target/linux/bcm27xx/patches-6.6/950-1202-spi-dw-Clamp-the-minimum-clock-speed.patch new file mode 100644 index 0000000000..585173aa44 --- /dev/null +++ b/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 +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 +--- + drivers/spi/spi-dw-core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/spi/spi-dw-core.c ++++ b/drivers/spi/spi-dw-core.c +@@ -397,7 +397,7 @@ void dw_spi_update_config(struct dw_spi + dw_writel(dws, DW_SPI_CTRLR1, cfg->ndf ? cfg->ndf - 1 : 0); + + /* Note DW APB SSI clock divider doesn't support odd numbers */ +- clk_div = (DIV_ROUND_UP(dws->max_freq, cfg->freq) + 1) & 0xfffe; ++ clk_div = min(DIV_ROUND_UP(dws->max_freq, cfg->freq) + 1, 0xfffe) & 0xfffe; + speed_hz = dws->max_freq / clk_div; + + if (dws->current_freq != speed_hz) { diff --git a/target/linux/bcm27xx/patches-6.6/950-1203-overlays-i2c-rtc-Correct-bq32000-property-name.patch b/target/linux/bcm27xx/patches-6.6/950-1203-overlays-i2c-rtc-Correct-bq32000-property-name.patch new file mode 100644 index 0000000000..afd6c415ba --- /dev/null +++ b/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 +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 +--- + arch/arm/boot/dts/overlays/i2c-rtc-common.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/overlays/i2c-rtc-common.dtsi ++++ b/arch/arm/boot/dts/overlays/i2c-rtc-common.dtsi +@@ -354,7 +354,7 @@ + <&rv3028>,"trickle-resistor-ohms:0", + <&rv3032>,"trickle-resistor-ohms:0", + <&rv1805>,"abracon,tc-resistor:0", +- <&bq32000>,"abracon,tc-resistor:0"; ++ <&bq32000>,"trickle-resistor-ohms:0"; + trickle-voltage-mv = <&rv3032>,"trickle-voltage-millivolts:0"; + backup-switchover-mode = <&rv3028>,"backup-switchover-mode:0"; + wakeup-source = <&ds1339>,"wakeup-source?", diff --git a/target/linux/bcm27xx/patches-6.6/950-1204-hwmon-adt7410-Add-DT-compatible-strings.patch b/target/linux/bcm27xx/patches-6.6/950-1204-hwmon-adt7410-Add-DT-compatible-strings.patch new file mode 100644 index 0000000000..cc54c62b91 --- /dev/null +++ b/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 +Date: Wed, 31 Jul 2024 15:02:47 +0100 +Subject: [PATCH 1204/1215] hwmon: (adt7410) Add DT compatible strings + +Signed-off-by: Phil Elwell +--- + drivers/hwmon/adt7410.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/drivers/hwmon/adt7410.c ++++ b/drivers/hwmon/adt7410.c +@@ -94,10 +94,18 @@ static const struct i2c_device_id adt741 + }; + MODULE_DEVICE_TABLE(i2c, adt7410_ids); + ++static const struct of_device_id adt7410_of_ids[] = { ++ { .compatible = "adi,adt7410" }, ++ { .compatible = "adi,adt7420" }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, adt7410_of_ids); ++ + static struct i2c_driver adt7410_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "adt7410", ++ .of_match_table = adt7410_of_ids, + .pm = pm_sleep_ptr(&adt7x10_dev_pm_ops), + }, + .probe = adt7410_i2c_probe, diff --git a/target/linux/bcm27xx/patches-6.6/950-1205-fixup-pinctrl-bcm2712-pinctrl-pinconf-driver.patch b/target/linux/bcm27xx/patches-6.6/950-1205-fixup-pinctrl-bcm2712-pinctrl-pinconf-driver.patch new file mode 100644 index 0000000000..fb786e172e --- /dev/null +++ b/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 +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 +--- + drivers/pinctrl/bcm/pinctrl-bcm2712.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/pinctrl/bcm/pinctrl-bcm2712.c ++++ b/drivers/pinctrl/bcm/pinctrl-bcm2712.c +@@ -1029,7 +1029,7 @@ static int bcm2712_pinconf_get(struct pi + + *config = pinconf_to_config_packed(param, arg); + +- return -ENOTSUPP; ++ return 0; + } + + static int bcm2712_pinconf_set(struct pinctrl_dev *pctldev, diff --git a/target/linux/bcm27xx/patches-6.6/950-1206-dtoverlays-Add-overlay-for-HD44780-via-I2C-PCF8574-b.patch b/target/linux/bcm27xx/patches-6.6/950-1206-dtoverlays-Add-overlay-for-HD44780-via-I2C-PCF8574-b.patch new file mode 100644 index 0000000000..db5f472ff0 --- /dev/null +++ b/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 +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 +--- + 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,= ++Params: addr I2C address of PCF8574 ++ pin_d4 GPIO pin for data pin D4 (default 4) ++ ++ pin_d5 GPIO pin for data pin D5 (default 5) ++ ++ pin_d6 GPIO pin for data pin D6 (default 6) ++ ++ pin_d7 GPIO pin for data pin D7 (default 7) ++ ++ pin_en GPIO pin for "Enable" (default 2) ++ ++ pin_rs GPIO pin for "Register Select" (default 0) ++ ++ pin_rw GPIO pin for R/W select (default 1) ++ ++ pin_bl GPIO pin for enabling/disabling the display ++ backlight. (default 3) ++ ++ display_height Height of the display in characters (default 2) ++ ++ display_width Width of the display in characters (default 16) ++ ++ + Name: hd44780-lcd + Info: Configures an HD44780 compatible LCD display. Uses 4 gpio pins for + data, 2 gpio pins for enable and register select and 1 optional pin +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/hd44780-i2c-lcd-overlay.dts +@@ -0,0 +1,57 @@ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ fragment@0 { ++ target = <&i2c_arm>; ++ __overlay__ { ++ status = "okay"; ++ ++ pcf857x: pcf857x@27 { ++ compatible = "nxp,pcf8574"; ++ reg = <0x27>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target-path = "/"; ++ __overlay__ { ++ lcd_screen: auxdisplay { ++ compatible = "hit,hd44780"; ++ ++ data-gpios = <&pcf857x 4 0>, ++ <&pcf857x 5 0>, ++ <&pcf857x 6 0>, ++ <&pcf857x 7 0>; ++ enable-gpios = <&pcf857x 2 0>; ++ rs-gpios = <&pcf857x 0 0>; ++ rw-gpios = <&pcf857x 1 0>; ++ backlight-gpios = <&pcf857x 3 0>; ++ ++ display-width-chars = <16>; ++ display-height-chars = <2>; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ pin_d4 = <&lcd_screen>,"data-gpios:4"; ++ pin_d5 = <&lcd_screen>,"data-gpios:16"; ++ pin_d6 = <&lcd_screen>,"data-gpios:28"; ++ pin_d7 = <&lcd_screen>,"data-gpios:40"; ++ pin_en = <&lcd_screen>,"enable-gpios:4"; ++ pin_rs = <&lcd_screen>,"rs-gpios:4"; ++ pin_rw = <&lcd_screen>,"rw-gpios:4"; ++ pin_bl = <&lcd_screen>,"backlight-gpios:4"; ++ display_height = <&lcd_screen>,"display-height-chars:0"; ++ display_width = <&lcd_screen>,"display-width-chars:0"; ++ addr = <&pcf857x>,"reg:0"; ++ }; ++ ++}; diff --git a/target/linux/bcm27xx/patches-6.6/950-1207-dtoverlays-Document-display_-width-height-on-hd44780.patch b/target/linux/bcm27xx/patches-6.6/950-1207-dtoverlays-Document-display_-width-height-on-hd44780.patch new file mode 100644 index 0000000000..793cd49310 --- /dev/null +++ b/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 +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 +--- + arch/arm/boot/dts/overlays/README | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -1752,9 +1752,9 @@ Params: pin_d4 GPIO pin + pin_bl Optional pin for enabling/disabling the + display backlight. (default disabled) + +- display_height Height of the display in characters ++ display_height Height of the display in characters (default 2) + +- display_width Width of the display in characters ++ display_width Width of the display in characters (default 16) + + + Name: hdmi-backlight-hwhack-gpio diff --git a/target/linux/bcm27xx/patches-6.6/950-1208-DTS-bcm2712-enable-SD-slot-CQE-by-default-on-Pi-5.patch b/target/linux/bcm27xx/patches-6.6/950-1208-DTS-bcm2712-enable-SD-slot-CQE-by-default-on-Pi-5.patch new file mode 100644 index 0000000000..16e7603498 --- /dev/null +++ b/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 +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 +--- + arch/arm/boot/dts/overlays/README | 6 +++--- + arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts | 1 + + 2 files changed, 4 insertions(+), 3 deletions(-) + +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -378,9 +378,9 @@ Params: + non-lite SKU of CM4). + (default "on") + +- sd_cqe Use to enable Command Queueing on the SD +- interface for faster Class A2 card performance +- (Pi 5 only, default "off") ++ sd_cqe Set to "off" to disable Command Queueing if you ++ have an incompatible Class A2 SD card ++ (Pi 5 only, default "on") + + sd_overclock Clock (in MHz) to use when the MMC framework + requests 50MHz +--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts ++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts +@@ -363,6 +363,7 @@ dpi_16bit_gpio2: &rp1_dpi_16bit_g + sd-uhs-sdr50; + sd-uhs-ddr50; + sd-uhs-sdr104; ++ supports-cqe; + cd-gpios = <&gio_aon 5 GPIO_ACTIVE_LOW>; + //no-1-8-v; + status = "okay"; diff --git a/target/linux/bcm27xx/patches-6.6/950-1211-gpiolib-Override-gpiochip-numbers-with-DT-aliases.patch b/target/linux/bcm27xx/patches-6.6/950-1211-gpiolib-Override-gpiochip-numbers-with-DT-aliases.patch new file mode 100644 index 0000000000..4ce9c04658 --- /dev/null +++ b/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 +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" aliases. + +Signed-off-by: Phil Elwell +--- + drivers/gpio/gpiolib.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +--- a/drivers/gpio/gpiolib.c ++++ b/drivers/gpio/gpiolib.c +@@ -110,6 +110,7 @@ static int gpiochip_irqchip_init_valid_m + static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gc); + + static bool gpiolib_initialized; ++static int first_dynamic_gpiochip_num = -1; + + static inline void desc_set_label(struct gpio_desc *d, const char *label) + { +@@ -745,6 +746,7 @@ int gpiochip_add_data_with_key(struct gp + unsigned int i; + int base = 0; + int ret = 0; ++ int id; + + /* + * First: allocate and populate the internal stat container, and +@@ -769,7 +771,16 @@ int gpiochip_add_data_with_key(struct gp + else if (gc->parent) + device_set_node(&gdev->dev, dev_fwnode(gc->parent)); + +- gdev->id = ida_alloc(&gpio_ida, GFP_KERNEL); ++ if (first_dynamic_gpiochip_num < 0) { ++ id = of_alias_get_highest_id("gpiochip"); ++ first_dynamic_gpiochip_num = (id >= 0) ? (id + 1) : 0; ++ } ++ ++ id = of_alias_get_id(gdev->dev.of_node, "gpiochip"); ++ if (id < 0) ++ id = first_dynamic_gpiochip_num; ++ ++ gdev->id = ida_alloc_range(&gpio_ida, id, ~0, GFP_KERNEL); + if (gdev->id < 0) { + ret = gdev->id; + goto err_free_gdev; diff --git a/target/linux/bcm27xx/patches-6.6/950-1212-dts-bcm2712-rpi-Add-gpiochip0-alias.patch b/target/linux/bcm27xx/patches-6.6/950-1212-dts-bcm2712-rpi-Add-gpiochip0-alias.patch new file mode 100644 index 0000000000..21913760a7 --- /dev/null +++ b/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 +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 +--- + arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi | 1 + + 1 file changed, 1 insertion(+) + +--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi ++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi +@@ -112,6 +112,7 @@ + gpio2 = &gio_aon; + gpio3 = &pinctrl; + gpio4 = &pinctrl_aon; ++ gpiochip0 = &gpio; + i2c = &i2c_arm; + i2c0 = &i2c0; + i2c1 = &i2c1; diff --git a/target/linux/bcm27xx/patches-6.6/950-1213-dts-bcm2712-rpi-The-SoC-gpiochips-start-at-10.patch b/target/linux/bcm27xx/patches-6.6/950-1213-dts-bcm2712-rpi-The-SoC-gpiochips-start-at-10.patch new file mode 100644 index 0000000000..5bf54c3fb0 --- /dev/null +++ b/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 +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 +--- + 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;