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 <noltari@gmail.com>
This commit is contained in:
Álvaro Fernández Rojas 2024-07-03 20:30:59 +02:00
parent ef8c1adb61
commit 0171157d45
59 changed files with 20609 additions and 41 deletions

View File

@ -23,6 +23,7 @@
# CONFIG_RASPBERRYPI_GPIOMEM is not set # CONFIG_RASPBERRYPI_GPIOMEM is not set
# CONFIG_REGULATOR_RASPBERRYPI_TOUCHSCREEN_V2 is not set # CONFIG_REGULATOR_RASPBERRYPI_TOUCHSCREEN_V2 is not set
# CONFIG_SENSORS_RP1_ADC 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_AD5398 is not set
# CONFIG_VIDEO_ARDUCAM_64MP is not set # CONFIG_VIDEO_ARDUCAM_64MP is not set
# CONFIG_VIDEO_ARDUCAM_PIVARIETY is not set # CONFIG_VIDEO_ARDUCAM_PIVARIETY is not set

View File

@ -1,41 +0,0 @@
From 6aab06ff9f81e186b1a02b53b514e691472e5a61 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
Date: Tue, 7 Nov 2023 14:49:47 +0000
Subject: [PATCH 0714/1085] spi: dw-dma: Get the last DMA scoop out of the FIFO
With a DMA FIFO threshold greater than 1 (encoded as 0), it is possible
for data in the FIFO to be inaccessible, causing the transfer to fail
after a timeout. If the transfer includes a transmission, reduce the
RX threshold when the TX completes, otherwise use 1 for the whole
transfer (inefficient, but not catastrophic at SPI data rates).
See: https://github.com/raspberrypi/linux/issues/5696
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
---
drivers/spi/spi-dw-dma.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
--- a/drivers/spi/spi-dw-dma.c
+++ b/drivers/spi/spi-dw-dma.c
@@ -315,8 +315,10 @@ static void dw_spi_dma_tx_done(void *arg
struct dw_spi *dws = arg;
clear_bit(DW_SPI_TX_BUSY, &dws->dma_chan_busy);
- if (test_bit(DW_SPI_RX_BUSY, &dws->dma_chan_busy))
+ if (test_bit(DW_SPI_RX_BUSY, &dws->dma_chan_busy)) {
+ dw_writel(dws, DW_SPI_DMARDLR, 0);
return;
+ }
complete(&dws->dma_completion);
}
@@ -642,6 +644,8 @@ static int dw_spi_dma_transfer(struct dw
nents = max(xfer->tx_sg.nents, xfer->rx_sg.nents);
+ dw_writel(dws, DW_SPI_DMARDLR, xfer->tx_buf ? (dws->rxburst - 1) : 0);
+
/*
* Execute normal DMA-based transfer (which submits the Rx and Tx SG
* lists directly to the DMA engine at once) if either full hardware

View File

@ -0,0 +1,260 @@
From 65fddc7301f52470fd846acede96d240a1902e67 Mon Sep 17 00:00:00 2001
From: Jonathan Bell <jonathan@raspberrypi.com>
Date: Fri, 5 Jul 2024 14:00:38 +0100
Subject: [PATCH 1146/1215] drivers: dwc_otg: use C11 style variable array
declarations
The kernel C standard changed in 5.18.
Remove a layer of indirection around the FIQ bounce buffers, be consistent
with pointers to FIQ bounce buffers, and remove open-coded 32-bit clamping
of DMA addresses.
Also remove a pointless fiq_state initialisation loop.
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
---
drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c | 12 ++++----
drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h | 8 ++---
drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 34 ++++++++++-----------
drivers/usb/host/dwc_otg/dwc_otg_hcd.h | 4 +--
drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 4 +--
5 files changed, 28 insertions(+), 34 deletions(-)
--- a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c
+++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c
@@ -240,8 +240,8 @@ static int notrace fiq_increment_dma_buf
hcdma_data_t hcdma;
int i = st->channel[n].dma_info.index;
int len;
- struct fiq_dma_blob *blob =
- (struct fiq_dma_blob *)(uintptr_t)st->dma_base;
+ struct fiq_dma_channel *split_dma =
+ (struct fiq_dma_channel *)(uintptr_t)st->dma_base;
len = fiq_get_xfer_len(st, n);
fiq_print(FIQDBG_INT, st, "LEN: %03d", len);
@@ -250,7 +250,7 @@ static int notrace fiq_increment_dma_buf
if (i > 6)
BUG();
- hcdma.d32 = (u32)(uintptr_t)&blob->channel[n].index[i].buf[0];
+ hcdma.d32 = lower_32_bits((uintptr_t)&split_dma[n].index[i].buf[0]);
FIQ_WRITE(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HC_DMA, hcdma.d32);
st->channel[n].dma_info.index = i;
return 0;
@@ -290,8 +290,8 @@ static int notrace fiq_iso_out_advance(s
hcsplt_data_t hcsplt;
hctsiz_data_t hctsiz;
hcdma_data_t hcdma;
- struct fiq_dma_blob *blob =
- (struct fiq_dma_blob *)(uintptr_t)st->dma_base;
+ struct fiq_dma_channel *split_dma =
+ (struct fiq_dma_channel *)(uintptr_t)st->dma_base;
int last = 0;
int i = st->channel[n].dma_info.index;
@@ -303,7 +303,7 @@ static int notrace fiq_iso_out_advance(s
last = 1;
/* New DMA address - address of bounce buffer referred to in index */
- hcdma.d32 = (u32)(uintptr_t)blob->channel[n].index[i].buf;
+ hcdma.d32 = lower_32_bits((uintptr_t)&split_dma[n].index[i].buf[0]);
//hcdma.d32 = FIQ_READ(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HC_DMA);
//hcdma.d32 += st->channel[n].dma_info.slot_len[i];
fiq_print(FIQDBG_INT, st, "LAST: %01d ", last);
--- a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h
+++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h
@@ -263,10 +263,6 @@ struct fiq_dma_channel {
struct fiq_split_dma_slot index[6];
} __attribute__((packed));
-struct fiq_dma_blob {
- struct fiq_dma_channel channel[0];
-} __attribute__((packed));
-
/**
* struct fiq_hs_isoc_info - USB2.0 isochronous data
* @iso_frame: Pointer to the array of OTG URB iso_frame_descs.
@@ -352,7 +348,7 @@ struct fiq_state {
mphi_regs_t mphi_regs;
void *dwc_regs_base;
dma_addr_t dma_base;
- struct fiq_dma_blob *fiq_dmab;
+ struct fiq_dma_channel *fiq_dmab;
void *dummy_send;
dma_addr_t dummy_send_dma;
gintmsk_data_t gintmsk_saved;
@@ -365,7 +361,7 @@ struct fiq_state {
char * buffer;
unsigned int bufsiz;
#endif
- struct fiq_channel_state channel[0];
+ struct fiq_channel_state channel[];
};
#ifdef CONFIG_ARM64
--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
@@ -58,6 +58,7 @@ static int last_sel_trans_num_avail_hc_a
static int last_sel_trans_num_avail_hc_at_end = 0;
#endif /* DEBUG_HOST_CHANNELS */
+static_assert(FIQ_PASSTHROUGH == 0);
dwc_otg_hcd_t *dwc_otg_hcd_alloc_hcd(void)
{
@@ -876,7 +877,7 @@ void dwc_otg_hcd_power_up(void *ptr)
void dwc_otg_cleanup_fiq_channel(dwc_otg_hcd_t *hcd, uint32_t num)
{
struct fiq_channel_state *st = &hcd->fiq_state->channel[num];
- struct fiq_dma_blob *blob = hcd->fiq_dmab;
+ struct fiq_dma_channel *split_dma = hcd->fiq_dmab;
int i;
st->fsm = FIQ_PASSTHROUGH;
@@ -898,7 +899,7 @@ void dwc_otg_cleanup_fiq_channel(dwc_otg
st->hs_isoc_info.iso_desc = NULL;
st->hs_isoc_info.nrframes = 0;
- DWC_MEMSET(&blob->channel[num].index[0], 0x6b, 1128);
+ DWC_MEMSET(&split_dma[num].index[0], 0x6b, 1128);
}
/**
@@ -1045,9 +1046,6 @@ int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd
spin_lock_init(&hcd->fiq_state->lock);
#endif
- for (i = 0; i < num_channels; i++) {
- hcd->fiq_state->channel[i].fsm = FIQ_PASSTHROUGH;
- }
hcd->fiq_state->dummy_send = DWC_DMA_ALLOC_ATOMIC(dev, 16,
&hcd->fiq_state->dummy_send_dma);
@@ -1561,7 +1559,7 @@ int fiq_fsm_setup_periodic_dma(dwc_otg_h
int frame_length, i = 0;
uint8_t *ptr = NULL;
dwc_hc_t *hc = qh->channel;
- struct fiq_dma_blob *blob;
+ struct fiq_dma_channel *split_dma;
struct dwc_otg_hcd_iso_packet_desc *frame_desc;
for (i = 0; i < 6; i++) {
@@ -1576,10 +1574,10 @@ int fiq_fsm_setup_periodic_dma(dwc_otg_h
* Pointer arithmetic on hcd->fiq_state->dma_base (a dma_addr_t)
* to point it to the correct offset in the allocated buffers.
*/
- blob = (struct fiq_dma_blob *)
+ split_dma = (struct fiq_dma_channel *)
(uintptr_t)hcd->fiq_state->dma_base;
- st->hcdma_copy.d32 =(u32)(uintptr_t)
- blob->channel[hc->hc_num].index[0].buf;
+ st->hcdma_copy.d32 = lower_32_bits((uintptr_t)
+ &split_dma[hc->hc_num].index[0].buf[0]);
/* Calculate the max number of CSPLITS such that the FIQ can time out
* a transaction if it fails.
@@ -1600,7 +1598,7 @@ int fiq_fsm_setup_periodic_dma(dwc_otg_h
frame_length = frame_desc->length;
/* Virtual address for bounce buffers */
- blob = hcd->fiq_dmab;
+ split_dma = hcd->fiq_dmab;
ptr = qtd->urb->buf + frame_desc->offset;
if (frame_length == 0) {
@@ -1613,11 +1611,11 @@ int fiq_fsm_setup_periodic_dma(dwc_otg_h
} else {
do {
if (frame_length <= 188) {
- dwc_memcpy(&blob->channel[hc->hc_num].index[i].buf[0], ptr, frame_length);
+ dwc_memcpy(&split_dma[hc->hc_num].index[i].buf[0], ptr, frame_length);
st->dma_info.slot_len[i] = frame_length;
ptr += frame_length;
} else {
- dwc_memcpy(&blob->channel[hc->hc_num].index[i].buf[0], ptr, 188);
+ dwc_memcpy(&split_dma[hc->hc_num].index[i].buf[0], ptr, 188);
st->dma_info.slot_len[i] = 188;
ptr += 188;
}
@@ -1634,10 +1632,10 @@ int fiq_fsm_setup_periodic_dma(dwc_otg_h
* dma_addr_t) to point it to the correct offset in the
* allocated buffers.
*/
- blob = (struct fiq_dma_blob *)
+ split_dma = (struct fiq_dma_channel *)
(uintptr_t)hcd->fiq_state->dma_base;
- st->hcdma_copy.d32 = (u32)(uintptr_t)
- blob->channel[hc->hc_num].index[0].buf;
+ st->hcdma_copy.d32 = lower_32_bits((uintptr_t)
+ &split_dma[hc->hc_num].index[0].buf[0]);
/* fixup xfersize to the actual packet size */
st->hctsiz_copy.b.pid = 0;
@@ -1917,14 +1915,14 @@ int fiq_fsm_queue_split_transaction(dwc_
if (hc->align_buff) {
st->hcdma_copy.d32 = hc->align_buff;
} else {
- st->hcdma_copy.d32 = ((unsigned long) hc->xfer_buff & 0xFFFFFFFF);
+ st->hcdma_copy.d32 = lower_32_bits((uintptr_t)hc->xfer_buff);
}
}
} else {
if (hc->align_buff) {
st->hcdma_copy.d32 = hc->align_buff;
} else {
- st->hcdma_copy.d32 = ((unsigned long) hc->xfer_buff & 0xFFFFFFFF);
+ st->hcdma_copy.d32 = lower_32_bits((uintptr_t)hc->xfer_buff);
}
}
/* The FIQ depends upon no other interrupts being enabled except channel halt.
@@ -1944,7 +1942,7 @@ int fiq_fsm_queue_split_transaction(dwc_
if (hc->align_buff) {
st->hcdma_copy.d32 = hc->align_buff;
} else {
- st->hcdma_copy.d32 = ((unsigned long) hc->xfer_buff & 0xFFFFFFFF);
+ st->hcdma_copy.d32 = lower_32_bits((uintptr_t)hc->xfer_buff);
}
}
DWC_WRITE_REG32(&hc_regs->hcdma, st->hcdma_copy.d32);
--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.h
+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.h
@@ -88,7 +88,7 @@ struct dwc_otg_hcd_urb {
uint32_t flags;
uint16_t interval;
struct dwc_otg_hcd_pipe_info pipe_info;
- struct dwc_otg_hcd_iso_packet_desc iso_descs[0];
+ struct dwc_otg_hcd_iso_packet_desc iso_descs[];
};
static inline uint8_t dwc_otg_hcd_get_ep_num(struct dwc_otg_hcd_pipe_info *pipe)
@@ -592,7 +592,7 @@ struct dwc_otg_hcd {
struct fiq_state *fiq_state;
/** Virtual address for split transaction DMA bounce buffers */
- struct fiq_dma_blob *fiq_dmab;
+ struct fiq_dma_channel *fiq_dmab;
#ifdef DEBUG
uint32_t frrem_samples;
--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
@@ -2332,7 +2332,7 @@ void dwc_otg_fiq_unmangle_isoc(dwc_otg_h
int dwc_otg_fiq_unsetup_per_dma(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh, dwc_otg_qtd_t *qtd, uint32_t num)
{
dwc_hc_t *hc = qh->channel;
- struct fiq_dma_blob *blob = hcd->fiq_dmab;
+ struct fiq_dma_channel *split_dma = hcd->fiq_dmab;
struct fiq_channel_state *st = &hcd->fiq_state->channel[num];
uint8_t *ptr = NULL;
int index = 0, len = 0;
@@ -2352,7 +2352,7 @@ int dwc_otg_fiq_unsetup_per_dma(dwc_otg_
for (i = 0; i < st->dma_info.index; i++) {
len += st->dma_info.slot_len[i];
- dwc_memcpy(ptr, &blob->channel[num].index[i].buf[0], st->dma_info.slot_len[i]);
+ dwc_memcpy(ptr, &split_dma[num].index[i].buf[0], st->dma_info.slot_len[i]);
ptr += st->dma_info.slot_len[i];
}
return len;

View File

@ -0,0 +1,27 @@
From 8dea9155ab081289edd618f8373d5f980d5bb664 Mon Sep 17 00:00:00 2001
From: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Date: Fri, 23 Feb 2024 10:40:47 +0100
Subject: [PATCH 1147/1215] media: uapi: pixfmt-luma: Document MIPI CSI-2
packing
The Y10P, Y12P and Y14P format variants are packed according to
the RAW10, RAW12 and RAW14 formats as defined by the MIPI CSI-2
specification. Document it.
Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Naushir Patuck <naush@raspberrypi.com>
---
Documentation/userspace-api/media/v4l/pixfmt-yuv-luma.rst | 4 ++++
1 file changed, 4 insertions(+)
--- a/Documentation/userspace-api/media/v4l/pixfmt-yuv-luma.rst
+++ b/Documentation/userspace-api/media/v4l/pixfmt-yuv-luma.rst
@@ -161,3 +161,7 @@ are often referred to as greyscale forma
For Y012 and Y12 formats, Y012 places its data in the 12 high bits, with
padding zeros in the 4 low bits, in contrast to the Y12 format, which has
its padding located in the most significant bits of the 16 bit word.
+
+ The 'P' variations of the Y10, Y12 and Y14 formats are packed according to
+ the RAW10, RAW12 and RAW14 packing scheme as defined by the MIPI CSI-2
+ specification.

View File

@ -0,0 +1,101 @@
From 814c088cb7183f79ba68c8f9459505e2ac4dde3a Mon Sep 17 00:00:00 2001
From: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Date: Fri, 26 Jan 2024 15:03:18 +0100
Subject: [PATCH 1148/1215] media: uapi: Add a pixel format for BGR48 and RGB48
Add BGR48 and RGB48 16-bit per component image formats.
Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Reviewed-by: Naushir Patuck <naush@raspberrypi.com>
---
.../userspace-api/media/v4l/pixfmt-rgb.rst | 54 +++++++++++++++++++
drivers/media/v4l2-core/v4l2-common.c | 2 +
include/uapi/linux/videodev2.h | 2 +
3 files changed, 58 insertions(+)
--- a/Documentation/userspace-api/media/v4l/pixfmt-rgb.rst
+++ b/Documentation/userspace-api/media/v4l/pixfmt-rgb.rst
@@ -996,6 +996,60 @@ arranged in little endian order.
\normalsize
+16 Bits Per Component
+=====================
+
+These formats store an RGB triplet in six bytes, with 16 bits per component
+stored in memory in little endian byte order. They are named based on the order
+of the RGB components as stored in memory. For instance, RGB48 stores R\
+:sub:`7:0` and R\ :sub:`15:8` in bytes 0 and 1 respectively. This differs from
+the DRM format nomenclature that instead uses the order of components as seen in
+the 48-bits little endian word.
+
+.. raw:: latex
+
+ \small
+
+.. flat-table:: RGB Formats With 16 Bits Per Component
+ :header-rows: 1
+
+ * - Identifier
+ - Code
+ - Byte 0
+ - Byte 1
+ - Byte 2
+ - Byte 3
+ - Byte 4
+ - Byte 5
+
+ * .. _V4L2-PIX-FMT-BGR48:
+
+ - ``V4L2_PIX_FMT_BGR48``
+ - 'BGR6'
+
+ - B\ :sub:`7-0`
+ - B\ :sub:`15-8`
+ - G\ :sub:`7-0`
+ - G\ :sub:`15-8`
+ - R\ :sub:`7-0`
+ - R\ :sub:`15-8`
+
+ * .. _V4L2-PIX-FMT-RGB48:
+
+ - ``V4L2_PIX_FMT_RGB48``
+ - 'RGB6'
+
+ - R\ :sub:`7-0`
+ - R\ :sub:`15-8`
+ - G\ :sub:`7-0`
+ - G\ :sub:`15-8`
+ - B\ :sub:`7-0`
+ - B\ :sub:`15-8`
+
+.. raw:: latex
+
+ \normalsize
+
Deprecated RGB Formats
======================
--- a/drivers/media/v4l2-core/v4l2-common.c
+++ b/drivers/media/v4l2-core/v4l2-common.c
@@ -253,6 +253,8 @@ const struct v4l2_format_info *v4l2_form
{ .format = V4L2_PIX_FMT_RGB555, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_BGR666, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_BGR48_12, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_BGR48, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_RGB48, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_ABGR64_12, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 8, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
/* YUV packed formats */
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -587,6 +587,8 @@ struct v4l2_pix_format {
/* RGB formats (6 or 8 bytes per pixel) */
#define V4L2_PIX_FMT_BGR48_12 v4l2_fourcc('B', '3', '1', '2') /* 48 BGR 12-bit per component */
+#define V4L2_PIX_FMT_BGR48 v4l2_fourcc('B', 'G', 'R', '6') /* 48 BGR 16-bit per component */
+#define V4L2_PIX_FMT_RGB48 v4l2_fourcc('R', 'G', 'B', '6') /* 48 RGB 16-bit per component */
#define V4L2_PIX_FMT_ABGR64_12 v4l2_fourcc('B', '4', '1', '2') /* 64 BGRA 12-bit per component */
/* RGB formats (6 bytes per pixel) */

View File

@ -0,0 +1,86 @@
From 7ca73020a5b26599d539083e413784e79891107e Mon Sep 17 00:00:00 2001
From: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Date: Fri, 26 Jan 2024 15:04:59 +0100
Subject: [PATCH 1150/1215] media: uapi: Document meta pixel format for PiSP BE
config
Add format description for the PiSP Back End configuration parameter
buffer.
Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Reviewed-by: Naushir Patuck <naush@raspberrypi.com>
---
.../userspace-api/media/v4l/meta-formats.rst | 1 +
.../media/v4l/metafmt-pisp-be.rst | 56 +++++++++++++++++++
2 files changed, 57 insertions(+)
create mode 100644 Documentation/userspace-api/media/v4l/metafmt-pisp-be.rst
--- a/Documentation/userspace-api/media/v4l/meta-formats.rst
+++ b/Documentation/userspace-api/media/v4l/meta-formats.rst
@@ -15,6 +15,7 @@ These formats are used for the :ref:`met
metafmt-bcm2835-isp-stats
metafmt-d4xx
metafmt-intel-ipu3
+ metafmt-pisp-be
metafmt-rkisp1
metafmt-sensor-data
metafmt-uvc
--- /dev/null
+++ b/Documentation/userspace-api/media/v4l/metafmt-pisp-be.rst
@@ -0,0 +1,56 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. _v4l2-meta-fmt-rpi-be-cfg:
+
+************************
+V4L2_META_FMT_RPI_BE_CFG
+************************
+
+Raspberry Pi PiSP Back End configuration format
+===============================================
+
+The Raspberry Pi PiSP Back End memory-to-memory image signal processor is
+configured by userspace by providing a buffer of configuration parameters
+to the `pispbe-config` output video device node using the
+:c:type:`v4l2_meta_format` interface.
+
+The PiSP Back End processes images in tiles, and its configuration requires
+specifying two different sets of parameters by populating the members of
+:c:type:`pisp_be_tiles_config` defined in the ``pisp_be_config.h`` header file.
+
+The `Raspberry Pi PiSP technical specification
+<https://datasheets.raspberrypi.com/camera/raspberry-pi-image-signal-processor-specification.pdf>`_
+provide detailed description of the ISP back end configuration and programming
+model.
+
+Global configuration data
+-------------------------
+
+The global configuration data describe how the pixels in a particular image are
+to be processed and is therefore shared across all the tiles of the image. So
+for example, LSC (Lens Shading Correction) or Denoise parameters would be common
+across all tiles from the same frame.
+
+Global configuration data are passed to the ISP by populating the member of
+:c:type:`pisp_be_config`.
+
+Tile parameters
+---------------
+
+As the ISP processes images in tiles, each set of tiles parameters describe how
+a single tile in an image is going to be processed. A single set of tile
+parameters consist of 160 bytes of data and to process a batch of tiles several
+sets of tiles parameters are required.
+
+Tiles parameters are passed to the ISP by populating the member of
+``pisp_tile`` and the ``num_tiles`` fields of :c:type:`pisp_be_tiles_config`.
+
+Raspberry Pi PiSP Back End uAPI data types
+==========================================
+
+This section describes the data types exposed to userspace by the Raspberry Pi
+PiSP Back End. The section is informative only, for a detailed description of
+each field refer to the `Raspberry Pi PiSP technical specification
+<https://datasheets.raspberrypi.com/camera/raspberry-pi-image-signal-processor-specification.pdf>`_.
+
+.. kernel-doc:: include/uapi/linux/media/raspberrypi/pisp_be_config.h

View File

@ -0,0 +1,106 @@
From 5d6318f242cce5f9b5677baedde736a2b81061df Mon Sep 17 00:00:00 2001
From: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Date: Wed, 17 Jan 2024 11:21:50 +0200
Subject: [PATCH 1151/1215] media: uapi: Document PiSP Compressed RAW Bayer
formats
Document the Raspberry Pi compressed RAW Bayer formats.
The compression algorithm description is provided by Nick Hollinghurst
<nick.hollinghurst@raspberrypi.com> from Raspberry Pi.
Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Reviewed-by: Naushir Patuck <naush@raspberrypi.com>
---
.../userspace-api/media/v4l/pixfmt-bayer.rst | 1 +
.../media/v4l/pixfmt-srggb8-pisp-comp.rst | 74 +++++++++++++++++++
2 files changed, 75 insertions(+)
create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-srggb8-pisp-comp.rst
--- a/Documentation/userspace-api/media/v4l/pixfmt-bayer.rst
+++ b/Documentation/userspace-api/media/v4l/pixfmt-bayer.rst
@@ -20,6 +20,7 @@ orders. See also `the Wikipedia article
:maxdepth: 1
pixfmt-srggb8
+ pixfmt-srggb8-pisp-comp
pixfmt-srggb10
pixfmt-srggb10p
pixfmt-srggb10alaw8
--- /dev/null
+++ b/Documentation/userspace-api/media/v4l/pixfmt-srggb8-pisp-comp.rst
@@ -0,0 +1,74 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+
+.. _v4l2-pix-fmt-pisp-comp1-rggb:
+.. _v4l2-pix-fmt-pisp-comp1-grbg:
+.. _v4l2-pix-fmt-pisp-comp1-gbrg:
+.. _v4l2-pix-fmt-pisp-comp1-bggr:
+.. _v4l2-pix-fmt-pisp-comp1-mono:
+.. _v4l2-pix-fmt-pisp-comp2-rggb:
+.. _v4l2-pix-fmt-pisp-comp2-grbg:
+.. _v4l2-pix-fmt-pisp-comp2-gbrg:
+.. _v4l2-pix-fmt-pisp-comp2-bggr:
+.. _v4l2-pix-fmt-pisp-comp2-mono:
+
+**************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
+V4L2_PIX_FMT_PISP_COMP1_RGGB ('PC1R'), V4L2_PIX_FMT_PISP_COMP1_GRBG ('PC1G'), V4L2_PIX_FMT_PISP_COMP1_GBRG ('PC1g'), V4L2_PIX_FMT_PISP_COMP1_BGGR ('PC1B), V4L2_PIX_FMT_PISP_COMP1_MONO ('PC1M'), V4L2_PIX_FMT_PISP_COMP2_RGGB ('PC2R'), V4L2_PIX_FMT_PISP_COMP2_GRBG ('PC2G'), V4L2_PIX_FMT_PISP_COMP2_GBRG ('PC2g'), V4L2_PIX_FMT_PISP_COMP2_BGGR ('PC2B), V4L2_PIX_FMT_PISP_COMP2_MONO ('PC2M')
+**************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
+
+================================================
+Raspberry Pi PiSP compressed 8-bit Bayer formats
+================================================
+
+Description
+===========
+
+The Raspberry Pi ISP (PiSP) uses a family of three fixed-rate compressed Bayer
+formats. A black-level offset may be subtracted to improve compression
+efficiency; the nominal black level and amount of offset must be signalled out
+of band. Each scanline is padded to a multiple of 8 pixels wide, and each block
+of 8 horizontally-contiguous pixels is coded using 8 bytes.
+
+Mode 1 uses a quantization and delta-based coding scheme which preserves up to
+12 significant bits. Mode 2 is a simple sqrt-like companding scheme with 6 PWL
+chords, preserving up to 12 significant bits. Mode 3 combines both companding
+(with 4 chords) and the delta scheme, preserving up to 14 significant bits.
+
+The remainder of this description applies to Modes 1 and 3.
+
+Each block of 8 pixels is separated into even and odd phases of 4 pixels,
+coded independently by 32-bit words at successive locations in memory.
+The two LS bits of each 32-bit word give its "quantization mode".
+
+In quantization mode 0, the lowest 321 quantization levels are multiples of
+FSD/4096 and the remaining levels are successive multiples of FSD/2048.
+Quantization modes 1 and 2 use linear quantization with step sizes of
+FSD/1024 and FSD/512 respectively. Each of the four pixels is quantized
+independently, with rounding to the nearest level.
+In quantization mode 2 where the middle two samples have quantized values
+(q1,q2) both in the range [384..511], they are coded using 9 bits for q1
+followed by 7 bits for (q2 & 127). Otherwise, for quantization modes
+0, 1 and 2: a 9-bit field encodes MIN(q1,q2) which must be in the range
+[0..511] and a 7-bit field encodes (q2-q1+64) which must be in [0..127].
+
+Each of the outer samples (q0,q3) is encoded using a 7-bit field based
+on its inner neighbour q1 or q2. In quantization mode 2 where the inner
+sample has a quantized value in the range [448..511], the field value is
+(q0-384). Otherwise for quantization modes 0, 1 and 2: The outer sample
+is encoded as (q0-MAX(0,q1-64)). q3 is likewise coded based on q2.
+Each of these values must be in the range [0..127]. All these fields
+of 2, 9, 7, 7, 7 bits respectively are packed in little-endian order
+to give a 32-bit word with LE byte order.
+
+Quantization mode 3 has a "7.5-bit" escape, used when none of the above
+encodings will fit. Each pixel value is quantized to the nearest of 176
+levels, where the lowest 95 levels are multiples of FSD/256 and the
+remaining levels are multiples of FSD/128 (level 175 represents values
+very close to FSD and may require saturating arithmetic to decode).
+
+Each pair of quantized pixels (q0,q1) or (q2,q3) is jointly coded
+by a 15-bit field: 2816*(q0>>4) + 16*q1 + (q0&15).
+Three fields of 2, 15, 15 bits are packed in LE order {15,15,2}.
+
+An implementation of a software decoder of compressed formats is available
+in `Raspberry Pi camera applications code base
+<https://github.com/raspberrypi/rpicam-apps/blob/main/image/dng.cpp>`_.

View File

@ -0,0 +1,97 @@
From c38a898c6877c6722ebfecea99f42e5a84c3e453 Mon Sep 17 00:00:00 2001
From: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Date: Thu, 25 Jan 2024 16:42:33 +0100
Subject: [PATCH 1152/1215] media: dt-bindings: Add bindings for Raspberry Pi
PiSP Back End
Add bindings for the Raspberry Pi PiSP Back End memory-to-memory image
signal processor.
Datasheet:
https://datasheets.raspberrypi.com/camera/raspberry-pi-image-signal-processor-specification.pdf
Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Reviewed-by: Rob Herring <robh@kernel.org>
Reviewed-by: Naushir Patuck <naush@raspberrypi.com>
---
.../bindings/media/raspberrypi,pispbe.yaml | 63 +++++++++++++++++++
MAINTAINERS | 1 +
2 files changed, 64 insertions(+)
create mode 100644 Documentation/devicetree/bindings/media/raspberrypi,pispbe.yaml
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/raspberrypi,pispbe.yaml
@@ -0,0 +1,63 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/raspberrypi,pispbe.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Raspberry Pi PiSP Image Signal Processor (ISP) Back End
+
+maintainers:
+ - Raspberry Pi Kernel Maintenance <kernel-list@raspberrypi.com>
+ - Jacopo Mondi <jacopo.mondi@ideasonboard.com>
+
+description: |
+ The Raspberry Pi PiSP Image Signal Processor (ISP) Back End is an image
+ processor that fetches images in Bayer or Grayscale format from DRAM memory
+ in tiles and produces images consumable by applications.
+
+ The full ISP documentation is available at
+ https://datasheets.raspberrypi.com/camera/raspberry-pi-image-signal-processor-specification.pdf
+
+properties:
+ compatible:
+ items:
+ - enum:
+ - brcm,bcm2712-pispbe
+ - const: raspberrypi,pispbe
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ iommus:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - clocks
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+ soc {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ isp@880000 {
+ compatible = "brcm,bcm2712-pispbe", "raspberrypi,pispbe";
+ reg = <0x10 0x00880000 0x0 0x4000>;
+ interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&firmware_clocks 7>;
+ iommus = <&iommu2>;
+ };
+ };
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -18037,6 +18037,7 @@ M: Jacopo Mondi <jacopo.mondi@ideasonboa
L: Raspberry Pi Kernel Maintenance <kernel-list@raspberrypi.com>
L: linux-media@vger.kernel.org
S: Maintained
+F: Documentation/devicetree/bindings/media/raspberrypi,pispbe.yaml
F: include/uapi/linux/media/raspberrypi/
RC-CORE / LIRC FRAMEWORK

View File

@ -0,0 +1,162 @@
From d68e76260316002869aea1b0edf4be399bb592b8 Mon Sep 17 00:00:00 2001
From: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Date: Mon, 29 Jan 2024 17:23:55 +0100
Subject: [PATCH 1153/1215] media: admin-guide: Document the Raspberry Pi PiSP
BE
Add documentation for the PiSP Back End memory-to-memory ISP.
Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
---
.../admin-guide/media/raspberrypi-pisp-be.dot | 20 ++++
.../admin-guide/media/raspberrypi-pisp-be.rst | 109 ++++++++++++++++++
.../admin-guide/media/v4l-drivers.rst | 1 +
3 files changed, 130 insertions(+)
create mode 100644 Documentation/admin-guide/media/raspberrypi-pisp-be.dot
create mode 100644 Documentation/admin-guide/media/raspberrypi-pisp-be.rst
--- /dev/null
+++ b/Documentation/admin-guide/media/raspberrypi-pisp-be.dot
@@ -0,0 +1,20 @@
+digraph board {
+ rankdir=TB
+ n00000001 [label="{{<port0> 0 | <port1> 1 | <port2> 2 | <port7> 7} | pispbe\n | {<port3> 3 | <port4> 4 | <port5> 5 | <port6> 6}}", shape=Mrecord, style=filled, fillcolor=green]
+ n00000001:port3 -> n0000001c [style=bold]
+ n00000001:port4 -> n00000022 [style=bold]
+ n00000001:port5 -> n00000028 [style=bold]
+ n00000001:port6 -> n0000002e [style=bold]
+ n0000000a [label="pispbe-input\n/dev/video0", shape=box, style=filled, fillcolor=yellow]
+ n0000000a -> n00000001:port0 [style=bold]
+ n00000010 [label="pispbe-tdn_input\n/dev/video1", shape=box, style=filled, fillcolor=yellow]
+ n00000010 -> n00000001:port1 [style=bold]
+ n00000016 [label="pispbe-stitch_input\n/dev/video2", shape=box, style=filled, fillcolor=yellow]
+ n00000016 -> n00000001:port2 [style=bold]
+ n0000001c [label="pispbe-output0\n/dev/video3", shape=box, style=filled, fillcolor=yellow]
+ n00000022 [label="pispbe-output1\n/dev/video4", shape=box, style=filled, fillcolor=yellow]
+ n00000028 [label="pispbe-tdn_output\n/dev/video5", shape=box, style=filled, fillcolor=yellow]
+ n0000002e [label="pispbe-stitch_output\n/dev/video6", shape=box, style=filled, fillcolor=yellow]
+ n00000034 [label="pispbe-config\n/dev/video7", shape=box, style=filled, fillcolor=yellow]
+ n00000034 -> n00000001:port7 [style=bold]
+}
--- /dev/null
+++ b/Documentation/admin-guide/media/raspberrypi-pisp-be.rst
@@ -0,0 +1,109 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=========================================================
+Raspberry Pi PiSP Back End Memory-to-Memory ISP (pisp-be)
+=========================================================
+
+The PiSP Back End
+=================
+
+The PiSP Back End is a memory-to-memory Image Signal Processor (ISP) which reads
+image data from DRAM memory and performs image processing as specified by the
+application through the parameters in a configuration buffer, before writing
+pixel data back to memory through two distinct output channels.
+
+The ISP registers and programming model are documented in the `Raspberry Pi
+Image Signal Processor (PiSP) Specification document`_
+
+The PiSP Back End ISP processes images in tiles. The handling of image
+tessellation and the computation of low-level configuration parameters is
+realized by a free software library called `libpisp
+<https://github.com/raspberrypi/libpisp>`_.
+
+The full image processing pipeline, which involves capturing RAW Bayer data from
+an image sensor through a MIPI CSI-2 compatible capture interface, storing them
+in DRAM memory and processing them in the PiSP Back End to obtain images usable
+by an application is implemented in `libcamera <https://libcamera.org>`_ as
+part of the Raspberry Pi platform support.
+
+The pisp-be driver
+==================
+
+The Raspberry Pi PiSP Back End (pisp-be) driver is located under
+drivers/media/platform/raspberrypi/pisp-be. It uses the `V4L2 API` to register
+a number of video capture and output devices, the `V4L2 subdev API` to register
+a subdevice for the ISP that connects the video devices in a single media graph
+realized using the `Media Controller (MC) API`.
+
+The media topology registered by the `pisp-be` driver is represented below:
+
+.. _pips-be-topology:
+
+.. kernel-figure:: raspberrypi-pisp-be.dot
+ :alt: Diagram of the default media pipeline topology
+ :align: center
+
+
+The media graph registers the following video device nodes:
+
+- pispbe-input: output device for images to be submitted to the ISP for
+ processing.
+- pispbe-tdn_input: output device for temporal denoise.
+- pispbe-stitch_input: output device for image stitching (HDR).
+- pispbe-output0: first capture device for processed images.
+- pispbe-output1: second capture device for processed images.
+- pispbe-tdn_output: capture device for temporal denoise.
+- pispbe-stitch_output: capture device for image stitching (HDR).
+- pispbe-config: output device for ISP configuration parameters.
+
+pispbe-input
+------------
+
+Images to be processed by the ISP are queued to the `pispbe-input` output device
+node. For a list of image formats supported as input to the ISP refer to the
+`Raspberry Pi Image Signal Processor (PiSP) Specification document`_.
+
+pispbe-tdn_input, pispbe-tdn_output
+-----------------------------------
+
+The `pispbe-tdn_input` output video device receives images to be processed by
+the temporal denoise block which are captured from the `pispbe-tdn_output`
+capture video device. Userspace is responsible for maintaining queues on both
+devices, and ensuring that buffers completed on the output are queued to the
+input.
+
+pispbe-stitch_input, pispbe-stitch_output
+-----------------------------------------
+
+To realize HDR (high dynamic range) image processing the image stitching and
+tonemapping blocks are used. The `pispbe-stitch_output` writes images to memory
+and the `pispbe-stitch_input` receives the previously written frame to process
+it along with the current input image. Userspace is responsible for maintaining
+queues on both devices, and ensuring that buffers completed on the output are
+queued to the input.
+
+pispbe-output0, pispbe-output1
+------------------------------
+
+The two capture devices write to memory the pixel data as processed by the ISP.
+
+pispbe-config
+-------------
+
+The `pispbe-config` output video devices receives a buffer of configuration
+parameters that define the desired image processing to be performed by the ISP.
+
+The format of the ISP configuration parameter is defined by
+:c:type:`pisp_be_tiles_config` C structure and the meaning of each parameter is
+described in the `Raspberry Pi Image Signal Processor (PiSP) Specification
+document`_.
+
+ISP configuration
+=================
+
+The ISP configuration is described solely by the content of the parameters
+buffer. The only parameter that userspace needs to configure using the V4L2 API
+is the image format on the output and capture video devices for validation of
+the content of the parameters buffer.
+
+.. _Raspberry Pi Image Signal Processor (PiSP) Specification document: https://datasheets.raspberrypi.com/camera/raspberry-pi-image-signal-processor-specification.pdf
--- a/Documentation/admin-guide/media/v4l-drivers.rst
+++ b/Documentation/admin-guide/media/v4l-drivers.rst
@@ -21,6 +21,7 @@ Video4Linux (V4L) driver-specific docume
omap4_camera
philips
qcom_camss
+ raspberrypi-pisp-be
rcar-fdp1
rkisp1
saa7134

View File

@ -0,0 +1,29 @@
From b58aeea7e2e3afd4fb3b6dcbe5e382b2244b33a4 Mon Sep 17 00:00:00 2001
From: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Date: Thu, 27 Jun 2024 13:40:29 +0200
Subject: [PATCH 1155/1215] media: uapi: pisp_be_config: Drop BIT() from uAPI
The pisp_be_config.h uAPI header file contains a bit-field definition
that uses the BIT() helper macro.
As the BIT() identifier is not defined in userspace, drop it from the
uAPI header.
Fixes: c6c49bac8770 ("media: uapi: Add Raspberry Pi PiSP Back End uAPI")
Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
---
include/uapi/linux/media/raspberrypi/pisp_be_config.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/include/uapi/linux/media/raspberrypi/pisp_be_config.h
+++ b/include/uapi/linux/media/raspberrypi/pisp_be_config.h
@@ -146,7 +146,7 @@ struct pisp_be_dpc_config {
*/
struct pisp_be_geq_config {
__u16 offset;
-#define PISP_BE_GEQ_SHARPER BIT(15)
+#define PISP_BE_GEQ_SHARPER (1U << 15)
#define PISP_BE_GEQ_SLOPE ((1 << 10) - 1)
/* top bit is the "sharper" flag, slope value is bottom 10 bits */
__u16 slope_sharper;

View File

@ -0,0 +1,32 @@
From 7c36a1feb61d964055bee777efc1db60790aa215 Mon Sep 17 00:00:00 2001
From: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Date: Thu, 27 Jun 2024 16:07:43 +0200
Subject: [PATCH 1156/1215] media: uapi: pisp_common: Add 32 bpp format test
Add definition and test for 32-bits image formats to the pisp_common.h
uAPI header.
Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
---
include/uapi/linux/media/raspberrypi/pisp_common.h | 3 +++
1 file changed, 3 insertions(+)
--- a/include/uapi/linux/media/raspberrypi/pisp_common.h
+++ b/include/uapi/linux/media/raspberrypi/pisp_common.h
@@ -72,6 +72,8 @@ enum pisp_image_format {
PISP_IMAGE_FORMAT_SHIFT_8 = 0x00080000,
PISP_IMAGE_FORMAT_SHIFT_MASK = 0x000f0000,
+ PISP_IMAGE_FORMAT_BPP_32 = 0x00100000,
+
PISP_IMAGE_FORMAT_UNCOMPRESSED = 0x00000000,
PISP_IMAGE_FORMAT_COMPRESSION_MODE_1 = 0x01000000,
PISP_IMAGE_FORMAT_COMPRESSION_MODE_2 = 0x02000000,
@@ -134,6 +136,7 @@ enum pisp_image_format {
PISP_IMAGE_FORMAT_PLANARITY_PLANAR)
#define PISP_IMAGE_FORMAT_wallpaper(fmt) \
((fmt) & PISP_IMAGE_FORMAT_WALLPAPER_ROLL)
+#define PISP_IMAGE_FORMAT_bpp_32(fmt) ((fmt) & PISP_IMAGE_FORMAT_BPP_32)
#define PISP_IMAGE_FORMAT_HOG(fmt) \
((fmt) & \
(PISP_IMAGE_FORMAT_HOG_SIGNED | PISP_IMAGE_FORMAT_HOG_UNSIGNED))

View File

@ -0,0 +1,89 @@
From 20a3671be178fd98aac08931d809e689eaa7a9d9 Mon Sep 17 00:00:00 2001
From: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Date: Fri, 28 Jun 2024 10:10:10 +0200
Subject: [PATCH 1157/1215] media: uapi: Capitalize all macros
The macro used to inspect an image format characteristic use a mixture
of capitalized and non-capitalized letters, which is rather unusual for
the Linux kernel style.
Capitalize all identifiers.
Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
---
.../linux/media/raspberrypi/pisp_common.h | 38 +++++++++----------
1 file changed, 19 insertions(+), 19 deletions(-)
--- a/include/uapi/linux/media/raspberrypi/pisp_common.h
+++ b/include/uapi/linux/media/raspberrypi/pisp_common.h
@@ -92,51 +92,51 @@ enum pisp_image_format {
PISP_IMAGE_FORMAT_THREE_CHANNEL
};
-#define PISP_IMAGE_FORMAT_bps_8(fmt) \
+#define PISP_IMAGE_FORMAT_BPS_8(fmt) \
(((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) == PISP_IMAGE_FORMAT_BPS_8)
-#define PISP_IMAGE_FORMAT_bps_10(fmt) \
+#define PISP_IMAGE_FORMAT_BPS_10(fmt) \
(((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) == PISP_IMAGE_FORMAT_BPS_10)
-#define PISP_IMAGE_FORMAT_bps_12(fmt) \
+#define PISP_IMAGE_FORMAT_BPS_12(fmt) \
(((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) == PISP_IMAGE_FORMAT_BPS_12)
-#define PISP_IMAGE_FORMAT_bps_16(fmt) \
+#define PISP_IMAGE_FORMAT_BPS_16(fmt) \
(((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) == PISP_IMAGE_FORMAT_BPS_16)
-#define PISP_IMAGE_FORMAT_bps(fmt) \
+#define PISP_IMAGE_FORMAT_BPS(fmt) \
(((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) ? \
8 + (2 << (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) - 1)) : 8)
-#define PISP_IMAGE_FORMAT_shift(fmt) \
+#define PISP_IMAGE_FORMAT_SHIFT(fmt) \
(((fmt) & PISP_IMAGE_FORMAT_SHIFT_MASK) / PISP_IMAGE_FORMAT_SHIFT_1)
-#define PISP_IMAGE_FORMAT_three_channel(fmt) \
+#define PISP_IMAGE_FORMAT_THREE_CHANNEL(fmt) \
((fmt) & PISP_IMAGE_FORMAT_THREE_CHANNEL)
-#define PISP_IMAGE_FORMAT_single_channel(fmt) \
+#define PISP_IMAGE_FORMAT_SINGLE_CHANNEL(fmt) \
(!((fmt) & PISP_IMAGE_FORMAT_THREE_CHANNEL))
-#define PISP_IMAGE_FORMAT_compressed(fmt) \
+#define PISP_IMAGE_FORMAT_COMPRESSED(fmt) \
(((fmt) & PISP_IMAGE_FORMAT_COMPRESSION_MASK) != \
PISP_IMAGE_FORMAT_UNCOMPRESSED)
-#define PISP_IMAGE_FORMAT_sampling_444(fmt) \
+#define PISP_IMAGE_FORMAT_SAMPLING_444(fmt) \
(((fmt) & PISP_IMAGE_FORMAT_SAMPLING_MASK) == \
PISP_IMAGE_FORMAT_SAMPLING_444)
-#define PISP_IMAGE_FORMAT_sampling_422(fmt) \
+#define PISP_IMAGE_FORMAT_SAMPLING_422(fmt) \
(((fmt) & PISP_IMAGE_FORMAT_SAMPLING_MASK) == \
PISP_IMAGE_FORMAT_SAMPLING_422)
-#define PISP_IMAGE_FORMAT_sampling_420(fmt) \
+#define PISP_IMAGE_FORMAT_SAMPLING_420(fmt) \
(((fmt) & PISP_IMAGE_FORMAT_SAMPLING_MASK) == \
PISP_IMAGE_FORMAT_SAMPLING_420)
-#define PISP_IMAGE_FORMAT_order_normal(fmt) \
+#define PISP_IMAGE_FORMAT_ORDER_NORMAL(fmt) \
(!((fmt) & PISP_IMAGE_FORMAT_ORDER_SWAPPED))
-#define PISP_IMAGE_FORMAT_order_swapped(fmt) \
+#define PISP_IMAGE_FORMAT_ORDER_SWAPPED(fmt) \
((fmt) & PISP_IMAGE_FORMAT_ORDER_SWAPPED)
-#define PISP_IMAGE_FORMAT_interleaved(fmt) \
+#define PISP_IMAGE_FORMAT_INTERLEAVED(fmt) \
(((fmt) & PISP_IMAGE_FORMAT_PLANARITY_MASK) == \
PISP_IMAGE_FORMAT_PLANARITY_INTERLEAVED)
-#define PISP_IMAGE_FORMAT_semiplanar(fmt) \
+#define PISP_IMAGE_FORMAT_SEMIPLANAR(fmt) \
(((fmt) & PISP_IMAGE_FORMAT_PLANARITY_MASK) == \
PISP_IMAGE_FORMAT_PLANARITY_SEMI_PLANAR)
-#define PISP_IMAGE_FORMAT_planar(fmt) \
+#define PISP_IMAGE_FORMAT_PLANAR(fmt) \
(((fmt) & PISP_IMAGE_FORMAT_PLANARITY_MASK) == \
PISP_IMAGE_FORMAT_PLANARITY_PLANAR)
-#define PISP_IMAGE_FORMAT_wallpaper(fmt) \
+#define PISP_IMAGE_FORMAT_WALLPAPER(fmt) \
((fmt) & PISP_IMAGE_FORMAT_WALLPAPER_ROLL)
-#define PISP_IMAGE_FORMAT_bpp_32(fmt) ((fmt) & PISP_IMAGE_FORMAT_BPP_32)
+#define PISP_IMAGE_FORMAT_BPP_32(fmt) ((fmt) & PISP_IMAGE_FORMAT_BPP_32)
#define PISP_IMAGE_FORMAT_HOG(fmt) \
((fmt) & \
(PISP_IMAGE_FORMAT_HOG_SIGNED | PISP_IMAGE_FORMAT_HOG_UNSIGNED))

View File

@ -0,0 +1,30 @@
From ce89955e44f3ab41262b02d8e1e65c3455d66c4d Mon Sep 17 00:00:00 2001
From: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Date: Fri, 28 Jun 2024 13:59:40 +0200
Subject: [PATCH 1158/1215] media: uapi: pisp_be_config: Re-sort
pisp_be_tiles_config
The order of the members of pisp_be_tiles_config is relevant
as the driver logic assumes 'config' to be at offset 0.
Re-sort the member to match the driver's expectations.
Fixes: c6c49bac8770 ("media: uapi: Add Raspberry Pi PiSP Back End uAPI")
Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
---
include/uapi/linux/media/raspberrypi/pisp_be_config.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/include/uapi/linux/media/raspberrypi/pisp_be_config.h
+++ b/include/uapi/linux/media/raspberrypi/pisp_be_config.h
@@ -919,9 +919,9 @@ struct pisp_tile {
* @config: PiSP Back End configuration
*/
struct pisp_be_tiles_config {
+ struct pisp_be_config config;
struct pisp_tile tiles[PISP_BACK_END_NUM_TILES];
__u32 num_tiles;
- struct pisp_be_config config;
} __attribute__((packed));
#endif /* _UAPI_PISP_BE_CONFIG_H_ */

View File

@ -0,0 +1,82 @@
From abf30420f943d03cc28fec38612d2c5f5e6edf1f Mon Sep 17 00:00:00 2001
From: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Date: Fri, 28 Jun 2024 14:11:14 +0200
Subject: [PATCH 1159/1215] media: uapi: pisp_be_config: Add extra config
fields
Complete the pisp_be_config strcture by adding fields that even if not
written to the HW are relevant to complete the uAPI and put it in par
with the BSP driver.
Fixes: c6c49bac8770 ("media: uapi: Add Raspberry Pi PiSP Back End uAPI")
Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
---
.../linux/media/raspberrypi/pisp_be_config.h | 41 +++++++++++++++++++
1 file changed, 41 insertions(+)
--- a/include/uapi/linux/media/raspberrypi/pisp_be_config.h
+++ b/include/uapi/linux/media/raspberrypi/pisp_be_config.h
@@ -716,6 +716,13 @@ struct pisp_be_hog_buffer_config {
/**
* struct pisp_be_config - RaspberryPi PiSP Back End Processing configuration
*
+ * @input_buffer: Input buffer addresses
+ * @tdn_input_buffer: TDN input buffer addresses
+ * @stitch_input_buffer: Stitch input buffer addresses
+ * @tdn_output_buffer: TDN output buffer addresses
+ * @stitch_output_buffer: Stitch output buffer addresses
+ * @output_buffer: Output buffers addresses
+ * @hog_buffer: HOG buffer addresses
* @global: Global PiSP configuration
* @input_format: Input image format
* @decompress: Decompress configuration
@@ -753,8 +760,30 @@ struct pisp_be_hog_buffer_config {
* @resample: Resampling configuration
* @output_format: Output format configuration
* @hog: HOG configuration
+ * @axi: AXI bus configuration
+ * @lsc_extra: LSC extra info
+ * @cac_extra: CAC extra info
+ * @downscale_extra: Downscaler extra info
+ * @resample_extra: Resample extra info
+ * @crop: Crop configuration
+ * @hog_format: HOG format info
+ * @dirty_flags_bayer: Bayer enable dirty flags
+ * (:c:type:`pisp_be_bayer_enable`)
+ * @dirty_flags_rgb: RGB enable dirty flags
+ * (:c:type:`pisp_be_rgb_enable`)
+ * @dirty_flags_extra: Extra dirty flags
*/
struct pisp_be_config {
+ /* I/O configuration: */
+ struct pisp_be_input_buffer_config input_buffer;
+ struct pisp_be_tdn_input_buffer_config tdn_input_buffer;
+ struct pisp_be_stitch_input_buffer_config stitch_input_buffer;
+ struct pisp_be_tdn_output_buffer_config tdn_output_buffer;
+ struct pisp_be_stitch_output_buffer_config stitch_output_buffer;
+ struct pisp_be_output_buffer_config
+ output_buffer[PISP_BACK_END_NUM_OUTPUTS];
+ struct pisp_be_hog_buffer_config hog_buffer;
+ /* Processing configuration: */
struct pisp_be_global_config global;
struct pisp_image_format_config input_format;
struct pisp_decompress_config decompress;
@@ -793,6 +822,18 @@ struct pisp_be_config {
struct pisp_be_output_format_config
output_format[PISP_BACK_END_NUM_OUTPUTS];
struct pisp_be_hog_config hog;
+ struct pisp_be_axi_config axi;
+ /* Non-register fields: */
+ struct pisp_be_lsc_extra lsc_extra;
+ struct pisp_be_cac_extra cac_extra;
+ struct pisp_be_downscale_extra
+ downscale_extra[PISP_BACK_END_NUM_OUTPUTS];
+ struct pisp_be_resample_extra resample_extra[PISP_BACK_END_NUM_OUTPUTS];
+ struct pisp_be_crop_config crop;
+ struct pisp_image_format_config hog_format;
+ __u32 dirty_flags_bayer; /* these use pisp_be_bayer_enable */
+ __u32 dirty_flags_rgb; /* use pisp_be_rgb_enable */
+ __u32 dirty_flags_extra; /* these use pisp_be_dirty_t */
} __attribute__((packed));
/**

View File

@ -0,0 +1,886 @@
From 033e037013f2c092501a03bb1bf5bbf7b4045aa0 Mon Sep 17 00:00:00 2001
From: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Date: Fri, 28 Jun 2024 17:26:26 +0200
Subject: [PATCH 1160/1215] media: pisp_be: Re-introduce multi-context support
Re-introduce multi-context support that was dropped from the
mainline driver version.
Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
---
.../platform/raspberrypi/pisp_be/pisp_be.c | 355 ++++++++++--------
1 file changed, 208 insertions(+), 147 deletions(-)
--- a/drivers/media/platform/raspberrypi/pisp_be/pisp_be.c
+++ b/drivers/media/platform/raspberrypi/pisp_be/pisp_be.c
@@ -24,6 +24,14 @@
/* Maximum number of config buffers possible */
#define PISP_BE_NUM_CONFIG_BUFFERS VB2_MAX_FRAME
+/*
+ * We want to support 2 independent instances allowing 2 simultaneous users
+ * of the ISP-BE (of course they share hardware, platform resources and mutex).
+ * Each such instance comprises a group of device nodes representing input
+ * and output queues, and a media controller device node to describe them.
+ */
+#define PISPBE_NUM_NODE_GROUPS 2
+
#define PISPBE_NAME "pispbe"
/* Some ISP-BE registers */
@@ -156,7 +164,7 @@ struct pispbe_node {
struct media_pad pad;
struct media_intf_devnode *intf_devnode;
struct media_link *intf_link;
- struct pispbe_dev *pispbe;
+ struct pispbe_node_group *node_group;
/* Video device lock */
struct mutex node_lock;
/* vb2_queue lock */
@@ -173,9 +181,27 @@ struct pispbe_node {
#define NODE_NAME(node) \
(node_desc[(node)->id].ent_name + sizeof(PISPBE_NAME))
+/*
+ * Node group structure, which comprises all the input and output nodes that a
+ * single PiSP client will need, along with its own v4l2 and media devices.
+ */
+struct pispbe_node_group {
+ unsigned int id;
+ struct v4l2_device v4l2_dev;
+ struct v4l2_subdev sd;
+ struct pispbe_dev *pispbe;
+ struct media_device mdev;
+ struct pispbe_node node[PISPBE_NUM_NODES];
+ u32 streaming_map; /* bitmap of which nodes are streaming */
+ struct media_pad pad[PISPBE_NUM_NODES]; /* output pads first */
+ struct pisp_be_tiles_config *config;
+ dma_addr_t config_dma_addr;
+ unsigned int sequence;
+};
+
/* Records details of the jobs currently running or queued on the h/w. */
struct pispbe_job {
- bool valid;
+ struct pispbe_node_group *node_group;
/*
* An array of buffer pointers - remember it's source buffers first,
* then captures, then metadata last.
@@ -198,22 +224,13 @@ struct pispbe_job_descriptor {
/*
* Structure representing the entire PiSP Back End device, comprising several
- * nodes which share platform resources and a mutex for the actual HW.
+ * nodes groups which share platform resources and a mutex for the actual HW.
*/
struct pispbe_dev {
struct device *dev;
- struct pispbe_dev *pispbe;
- struct pisp_be_tiles_config *config;
void __iomem *be_reg_base;
struct clk *clk;
- struct v4l2_device v4l2_dev;
- struct v4l2_subdev sd;
- struct media_device mdev;
- struct media_pad pad[PISPBE_NUM_NODES]; /* output pads first */
- struct pispbe_node node[PISPBE_NUM_NODES];
- dma_addr_t config_dma_addr;
- unsigned int sequence;
- u32 streaming_map;
+ struct pispbe_node_group node_group[PISPBE_NUM_NODE_GROUPS];
struct pispbe_job queued_job, running_job;
spinlock_t hw_lock; /* protects "hw_busy" flag and streaming_map */
bool hw_busy; /* non-zero if a job is queued or is being started */
@@ -348,9 +365,9 @@ static dma_addr_t pispbe_get_addr(struct
return 0;
}
-static void pispbe_xlate_addrs(struct pispbe_dev *pispbe,
- struct pispbe_job_descriptor *job,
- struct pispbe_buffer *buf[PISPBE_NUM_NODES])
+static void pispbe_xlate_addrs(struct pispbe_job_descriptor *job,
+ struct pispbe_buffer *buf[PISPBE_NUM_NODES],
+ struct pispbe_node_group *node_group)
{
struct pispbe_hw_enables *hw_en = &job->hw_enables;
struct pisp_be_tiles_config *config = job->config;
@@ -366,13 +383,13 @@ static void pispbe_xlate_addrs(struct pi
* to 3 planes.
*/
ret = pispbe_get_planes_addr(addrs, buf[MAIN_INPUT_NODE],
- &pispbe->node[MAIN_INPUT_NODE]);
+ &node_group->node[MAIN_INPUT_NODE]);
if (ret <= 0) {
/*
* This shouldn't happen; pispbe_schedule_internal should insist
* on an input.
*/
- dev_warn(pispbe->dev, "ISP-BE missing input\n");
+ dev_warn(node_group->pispbe->dev, "ISP-BE missing input\n");
hw_en->bayer_enables = 0;
hw_en->rgb_enables = 0;
return;
@@ -427,7 +444,7 @@ static void pispbe_xlate_addrs(struct pi
for (unsigned int i = 0; i < PISP_BACK_END_NUM_OUTPUTS; i++) {
ret = pispbe_get_planes_addr(addrs + 7 + 3 * i,
buf[OUTPUT0_NODE + i],
- &pispbe->node[OUTPUT0_NODE + i]);
+ &node_group->node[OUTPUT0_NODE + i]);
if (ret <= 0)
hw_en->rgb_enables &= ~(PISP_BE_RGB_ENABLE_OUTPUT0 << i);
}
@@ -447,10 +464,11 @@ static void pispbe_xlate_addrs(struct pi
*
* Returns 0 if a job has been successfully prepared, < 0 otherwise.
*/
-static int pispbe_prepare_job(struct pispbe_dev *pispbe,
+static int pispbe_prepare_job(struct pispbe_node_group *node_group,
struct pispbe_job_descriptor *job)
{
struct pispbe_buffer *buf[PISPBE_NUM_NODES] = {};
+ struct pispbe_dev *pispbe = node_group->pispbe;
unsigned int config_index;
struct pispbe_node *node;
unsigned long flags;
@@ -460,11 +478,11 @@ static int pispbe_prepare_job(struct pis
memset(job, 0, sizeof(struct pispbe_job_descriptor));
if (((BIT(CONFIG_NODE) | BIT(MAIN_INPUT_NODE)) &
- pispbe->streaming_map) !=
+ node_group->streaming_map) !=
(BIT(CONFIG_NODE) | BIT(MAIN_INPUT_NODE)))
return -ENODEV;
- node = &pispbe->node[CONFIG_NODE];
+ node = &node_group->node[CONFIG_NODE];
spin_lock_irqsave(&node->ready_lock, flags);
buf[CONFIG_NODE] = list_first_entry_or_null(&node->ready_queue,
struct pispbe_buffer,
@@ -480,8 +498,8 @@ static int pispbe_prepare_job(struct pis
return -ENODEV;
config_index = buf[CONFIG_NODE]->vb.vb2_buf.index;
- job->config = &pispbe->config[config_index];
- job->tiles = pispbe->config_dma_addr +
+ job->config = &node_group->config[config_index];
+ job->tiles = node_group->config_dma_addr +
config_index * sizeof(struct pisp_be_tiles_config) +
offsetof(struct pisp_be_tiles_config, tiles);
@@ -498,7 +516,7 @@ static int pispbe_prepare_job(struct pis
continue;
buf[i] = NULL;
- if (!(pispbe->streaming_map & BIT(i)))
+ if (!(node_group->streaming_map & BIT(i)))
continue;
if ((!(rgb_en & PISP_BE_RGB_ENABLE_OUTPUT0) &&
@@ -522,7 +540,7 @@ static int pispbe_prepare_job(struct pis
ignore_buffers = true;
}
- node = &pispbe->node[i];
+ node = &node_group->node[i];
/* Pull a buffer from each V4L2 queue to form the queued job */
spin_lock_irqsave(&node->ready_lock, flags);
@@ -539,16 +557,16 @@ static int pispbe_prepare_job(struct pis
goto err_return_buffers;
}
- pispbe->queued_job.valid = true;
+ pispbe->queued_job.node_group = node_group;
/* Convert buffers to DMA addresses for the hardware */
- pispbe_xlate_addrs(pispbe, job, buf);
+ pispbe_xlate_addrs(job, buf, node_group);
return 0;
err_return_buffers:
for (unsigned int i = 0; i < PISPBE_NUM_NODES; i++) {
- struct pispbe_node *n = &pispbe->node[i];
+ struct pispbe_node *n = &node_group->node[i];
if (!buf[i])
continue;
@@ -564,11 +582,12 @@ err_return_buffers:
return -ENODEV;
}
-static void pispbe_schedule(struct pispbe_dev *pispbe, bool clear_hw_busy)
+static void pispbe_schedule(struct pispbe_dev *pispbe,
+ struct pispbe_node_group *node_group,
+ bool clear_hw_busy)
{
struct pispbe_job_descriptor job;
unsigned long flags;
- int ret;
spin_lock_irqsave(&pispbe->hw_lock, flags);
@@ -578,40 +597,53 @@ static void pispbe_schedule(struct pispb
if (pispbe->hw_busy)
goto unlock_and_return;
- ret = pispbe_prepare_job(pispbe, &job);
- if (ret)
- goto unlock_and_return;
+ for (unsigned int i = 0; i < PISPBE_NUM_NODE_GROUPS; i++) {
+ int ret;
- /*
- * We can kick the job off without the hw_lock, as this can
- * never run again until hw_busy is cleared, which will happen
- * only when the following job has been queued and an interrupt
- * is rised.
- */
- pispbe->hw_busy = true;
- spin_unlock_irqrestore(&pispbe->hw_lock, flags);
+ /* Schedule jobs only for a specific group. */
+ if (node_group && &pispbe->node_group[i] != node_group)
+ continue;
- if (job.config->num_tiles <= 0 ||
- job.config->num_tiles > PISP_BACK_END_NUM_TILES ||
- !((job.hw_enables.bayer_enables | job.hw_enables.rgb_enables) &
- PISP_BE_BAYER_ENABLE_INPUT)) {
/*
- * Bad job. We can't let it proceed as it could lock up
- * the hardware, or worse!
- *
- * For now, just force num_tiles to 0, which causes the
- * H/W to do something bizarre but survivable. It
- * increments (started,done) counters by more than 1,
- * but we seem to survive...
+ * Prepare a job for this group, if the group is not ready
+ * continue and try with the next one.
*/
- dev_dbg(pispbe->dev, "Bad job: invalid number of tiles: %u\n",
- job.config->num_tiles);
- job.config->num_tiles = 0;
- }
+ ret = pispbe_prepare_job(&pispbe->node_group[i], &job);
+ if (ret)
+ continue;
+
+ /*
+ * We can kick the job off without the hw_lock, as this can
+ * never run again until hw_busy is cleared, which will happen
+ * only when the following job has been queued and an interrupt
+ * is rised.
+ */
+ pispbe->hw_busy = true;
+ spin_unlock_irqrestore(&pispbe->hw_lock, flags);
+
+ if (job.config->num_tiles <= 0 ||
+ job.config->num_tiles > PISP_BACK_END_NUM_TILES ||
+ !((job.hw_enables.bayer_enables |
+ job.hw_enables.rgb_enables) &
+ PISP_BE_BAYER_ENABLE_INPUT)) {
+ /*
+ * Bad job. We can't let it proceed as it could lock up
+ * the hardware, or worse!
+ *
+ * For now, just force num_tiles to 0, which causes the
+ * H/W to do something bizarre but survivable. It
+ * increments (started,done) counters by more than 1,
+ * but we seem to survive...
+ */
+ dev_dbg(pispbe->dev, "Bad job: invalid number of tiles: %u\n",
+ job.config->num_tiles);
+ job.config->num_tiles = 0;
+ }
- pispbe_queue_job(pispbe, &job);
+ pispbe_queue_job(pispbe, &job);
- return;
+ return;
+ }
unlock_and_return:
/* No job has been queued, just release the lock and return. */
@@ -627,13 +659,13 @@ static void pispbe_isr_jobdone(struct pi
for (unsigned int i = 0; i < PISPBE_NUM_NODES; i++) {
if (buf[i]) {
buf[i]->vb.vb2_buf.timestamp = ts;
- buf[i]->vb.sequence = pispbe->sequence;
+ buf[i]->vb.sequence = job->node_group->sequence;
vb2_buffer_done(&buf[i]->vb.vb2_buf,
VB2_BUF_STATE_DONE);
}
}
- pispbe->sequence++;
+ job->node_group->sequence++;
}
static irqreturn_t pispbe_isr(int irq, void *dev)
@@ -657,7 +689,7 @@ static irqreturn_t pispbe_isr(int irq, v
* we previously saw "start" now finishes, and we then queued a new job
* which we see both start and finish "simultaneously".
*/
- if (pispbe->running_job.valid && pispbe->done != done) {
+ if (pispbe->running_job.node_group && pispbe->done != done) {
pispbe_isr_jobdone(pispbe, &pispbe->running_job);
memset(&pispbe->running_job, 0, sizeof(pispbe->running_job));
pispbe->done++;
@@ -667,7 +699,7 @@ static irqreturn_t pispbe_isr(int irq, v
pispbe->started++;
can_queue_another = 1;
- if (pispbe->done != done && pispbe->queued_job.valid) {
+ if (pispbe->done != done && pispbe->queued_job.node_group) {
pispbe_isr_jobdone(pispbe, &pispbe->queued_job);
pispbe->done++;
} else {
@@ -686,17 +718,17 @@ static irqreturn_t pispbe_isr(int irq, v
}
/* check if there's more to do before going to sleep */
- pispbe_schedule(pispbe, can_queue_another);
+ pispbe_schedule(pispbe, NULL, can_queue_another);
return IRQ_HANDLED;
}
-static int pisp_be_validate_config(struct pispbe_dev *pispbe,
+static int pisp_be_validate_config(struct pispbe_node_group *node_group,
struct pisp_be_tiles_config *config)
{
u32 bayer_enables = config->config.global.bayer_enables;
u32 rgb_enables = config->config.global.rgb_enables;
- struct device *dev = pispbe->dev;
+ struct device *dev = node_group->pispbe->dev;
struct v4l2_format *fmt;
unsigned int bpl, size;
@@ -707,7 +739,7 @@ static int pisp_be_validate_config(struc
}
/* Ensure output config strides and buffer sizes match the V4L2 formats. */
- fmt = &pispbe->node[TDN_OUTPUT_NODE].format;
+ fmt = &node_group->node[TDN_OUTPUT_NODE].format;
if (bayer_enables & PISP_BE_BAYER_ENABLE_TDN_OUTPUT) {
bpl = config->config.tdn_output_format.stride;
size = bpl * config->config.tdn_output_format.height;
@@ -725,7 +757,7 @@ static int pisp_be_validate_config(struc
}
}
- fmt = &pispbe->node[STITCH_OUTPUT_NODE].format;
+ fmt = &node_group->node[STITCH_OUTPUT_NODE].format;
if (bayer_enables & PISP_BE_BAYER_ENABLE_STITCH_OUTPUT) {
bpl = config->config.stitch_output_format.stride;
size = bpl * config->config.stitch_output_format.height;
@@ -751,7 +783,7 @@ static int pisp_be_validate_config(struc
PISP_IMAGE_FORMAT_WALLPAPER_ROLL)
continue; /* TODO: Size checks for wallpaper formats */
- fmt = &pispbe->node[OUTPUT0_NODE + j].format;
+ fmt = &node_group->node[OUTPUT0_NODE + j].format;
for (unsigned int i = 0; i < fmt->fmt.pix_mp.num_planes; i++) {
bpl = !i ? config->config.output_format[j].image.stride
: config->config.output_format[j].image.stride2;
@@ -783,7 +815,7 @@ static int pispbe_node_queue_setup(struc
struct device *alloc_devs[])
{
struct pispbe_node *node = vb2_get_drv_priv(q);
- struct pispbe_dev *pispbe = node->pispbe;
+ struct pispbe_dev *pispbe = node->node_group->pispbe;
unsigned int num_planes = NODE_IS_MPLANE(node) ?
node->format.fmt.pix_mp.num_planes : 1;
@@ -821,7 +853,7 @@ static int pispbe_node_queue_setup(struc
static int pispbe_node_buffer_prepare(struct vb2_buffer *vb)
{
struct pispbe_node *node = vb2_get_drv_priv(vb->vb2_queue);
- struct pispbe_dev *pispbe = node->pispbe;
+ struct pispbe_dev *pispbe = node->node_group->pispbe;
unsigned int num_planes = NODE_IS_MPLANE(node) ?
node->format.fmt.pix_mp.num_planes : 1;
@@ -841,12 +873,12 @@ static int pispbe_node_buffer_prepare(st
}
if (node->id == CONFIG_NODE) {
- void *dst = &node->pispbe->config[vb->index];
+ void *dst = &node->node_group->config[vb->index];
void *src = vb2_plane_vaddr(vb, 0);
memcpy(dst, src, sizeof(struct pisp_be_tiles_config));
- return pisp_be_validate_config(pispbe, dst);
+ return pisp_be_validate_config(node->node_group, dst);
}
return 0;
@@ -859,7 +891,8 @@ static void pispbe_node_buffer_queue(str
struct pispbe_buffer *buffer =
container_of(vbuf, struct pispbe_buffer, vb);
struct pispbe_node *node = vb2_get_drv_priv(buf->vb2_queue);
- struct pispbe_dev *pispbe = node->pispbe;
+ struct pispbe_node_group *node_group = node->node_group;
+ struct pispbe_dev *pispbe = node->node_group->pispbe;
unsigned long flags;
dev_dbg(pispbe->dev, "%s: for node %s\n", __func__, NODE_NAME(node));
@@ -869,15 +902,16 @@ static void pispbe_node_buffer_queue(str
/*
* Every time we add a buffer, check if there's now some work for the hw
- * to do.
+ * to do, but only for this client.
*/
- pispbe_schedule(pispbe, false);
+ pispbe_schedule(node_group->pispbe, node_group, false);
}
static int pispbe_node_start_streaming(struct vb2_queue *q, unsigned int count)
{
struct pispbe_node *node = vb2_get_drv_priv(q);
- struct pispbe_dev *pispbe = node->pispbe;
+ struct pispbe_node_group *node_group = node->node_group;
+ struct pispbe_dev *pispbe = node_group->pispbe;
struct pispbe_buffer *buf, *tmp;
unsigned long flags;
int ret;
@@ -887,17 +921,17 @@ static int pispbe_node_start_streaming(s
goto err_return_buffers;
spin_lock_irqsave(&pispbe->hw_lock, flags);
- node->pispbe->streaming_map |= BIT(node->id);
- node->pispbe->sequence = 0;
+ node->node_group->streaming_map |= BIT(node->id);
+ node->node_group->sequence = 0;
spin_unlock_irqrestore(&pispbe->hw_lock, flags);
dev_dbg(pispbe->dev, "%s: for node %s (count %u)\n",
__func__, NODE_NAME(node), count);
- dev_dbg(pispbe->dev, "Nodes streaming now 0x%x\n",
- node->pispbe->streaming_map);
+ dev_dbg(pispbe->dev, "Nodes streaming for this group now 0x%x\n",
+ node->node_group->streaming_map);
/* Maybe we're ready to run. */
- pispbe_schedule(pispbe, false);
+ pispbe_schedule(node_group->pispbe, node_group, false);
return 0;
@@ -915,7 +949,8 @@ err_return_buffers:
static void pispbe_node_stop_streaming(struct vb2_queue *q)
{
struct pispbe_node *node = vb2_get_drv_priv(q);
- struct pispbe_dev *pispbe = node->pispbe;
+ struct pispbe_node_group *node_group = node->node_group;
+ struct pispbe_dev *pispbe = node_group->pispbe;
struct pispbe_buffer *buf;
unsigned long flags;
@@ -948,14 +983,14 @@ static void pispbe_node_stop_streaming(s
vb2_wait_for_all_buffers(&node->queue);
spin_lock_irqsave(&pispbe->hw_lock, flags);
- pispbe->streaming_map &= ~BIT(node->id);
+ node_group->streaming_map &= ~BIT(node->id);
spin_unlock_irqrestore(&pispbe->hw_lock, flags);
pm_runtime_mark_last_busy(pispbe->dev);
pm_runtime_put_autosuspend(pispbe->dev);
- dev_dbg(pispbe->dev, "Nodes streaming now 0x%x\n",
- pispbe->streaming_map);
+ dev_dbg(pispbe->dev, "Nodes streaming for this group now 0x%x\n",
+ node_group->streaming_map);
}
static const struct vb2_ops pispbe_node_queue_ops = {
@@ -979,7 +1014,7 @@ static int pispbe_node_querycap(struct f
struct v4l2_capability *cap)
{
struct pispbe_node *node = video_drvdata(file);
- struct pispbe_dev *pispbe = node->pispbe;
+ struct pispbe_dev *pispbe = node->node_group->pispbe;
strscpy(cap->driver, PISPBE_NAME, sizeof(cap->driver));
strscpy(cap->card, PISPBE_NAME, sizeof(cap->card));
@@ -995,7 +1030,7 @@ static int pispbe_node_g_fmt_vid_cap(str
struct v4l2_format *f)
{
struct pispbe_node *node = video_drvdata(file);
- struct pispbe_dev *pispbe = node->pispbe;
+ struct pispbe_dev *pispbe = node->node_group->pispbe;
if (!NODE_IS_CAPTURE(node) || NODE_IS_META(node)) {
dev_dbg(pispbe->dev,
@@ -1015,7 +1050,7 @@ static int pispbe_node_g_fmt_vid_out(str
struct v4l2_format *f)
{
struct pispbe_node *node = video_drvdata(file);
- struct pispbe_dev *pispbe = node->pispbe;
+ struct pispbe_dev *pispbe = node->node_group->pispbe;
if (NODE_IS_CAPTURE(node) || NODE_IS_META(node)) {
dev_dbg(pispbe->dev,
@@ -1035,7 +1070,7 @@ static int pispbe_node_g_fmt_meta_out(st
struct v4l2_format *f)
{
struct pispbe_node *node = video_drvdata(file);
- struct pispbe_dev *pispbe = node->pispbe;
+ struct pispbe_dev *pispbe = node->node_group->pispbe;
if (!NODE_IS_META(node) || NODE_IS_CAPTURE(node)) {
dev_dbg(pispbe->dev,
@@ -1092,7 +1127,7 @@ static void pispbe_set_plane_params(stru
static void pispbe_try_format(struct v4l2_format *f, struct pispbe_node *node)
{
- struct pispbe_dev *pispbe = node->pispbe;
+ struct pispbe_dev *pispbe = node->node_group->pispbe;
u32 pixfmt = f->fmt.pix_mp.pixelformat;
const struct pisp_be_format *fmt;
bool is_rgb;
@@ -1156,7 +1191,7 @@ static int pispbe_node_try_fmt_vid_cap(s
struct v4l2_format *f)
{
struct pispbe_node *node = video_drvdata(file);
- struct pispbe_dev *pispbe = node->pispbe;
+ struct pispbe_dev *pispbe = node->node_group->pispbe;
if (!NODE_IS_CAPTURE(node) || NODE_IS_META(node)) {
dev_dbg(pispbe->dev,
@@ -1174,7 +1209,7 @@ static int pispbe_node_try_fmt_vid_out(s
struct v4l2_format *f)
{
struct pispbe_node *node = video_drvdata(file);
- struct pispbe_dev *pispbe = node->pispbe;
+ struct pispbe_dev *pispbe = node->node_group->pispbe;
if (!NODE_IS_OUTPUT(node) || NODE_IS_META(node)) {
dev_dbg(pispbe->dev,
@@ -1192,7 +1227,7 @@ static int pispbe_node_try_fmt_meta_out(
struct v4l2_format *f)
{
struct pispbe_node *node = video_drvdata(file);
- struct pispbe_dev *pispbe = node->pispbe;
+ struct pispbe_dev *pispbe = node->node_group->pispbe;
if (!NODE_IS_META(node) || NODE_IS_CAPTURE(node)) {
dev_dbg(pispbe->dev,
@@ -1211,7 +1246,7 @@ static int pispbe_node_s_fmt_vid_cap(str
struct v4l2_format *f)
{
struct pispbe_node *node = video_drvdata(file);
- struct pispbe_dev *pispbe = node->pispbe;
+ struct pispbe_dev *pispbe = node->node_group->pispbe;
int ret;
ret = pispbe_node_try_fmt_vid_cap(file, priv, f);
@@ -1234,7 +1269,7 @@ static int pispbe_node_s_fmt_vid_out(str
struct v4l2_format *f)
{
struct pispbe_node *node = video_drvdata(file);
- struct pispbe_dev *pispbe = node->pispbe;
+ struct pispbe_dev *pispbe = node->node_group->pispbe;
int ret;
ret = pispbe_node_try_fmt_vid_out(file, priv, f);
@@ -1257,7 +1292,7 @@ static int pispbe_node_s_fmt_meta_out(st
struct v4l2_format *f)
{
struct pispbe_node *node = video_drvdata(file);
- struct pispbe_dev *pispbe = node->pispbe;
+ struct pispbe_dev *pispbe = node->node_group->pispbe;
int ret;
ret = pispbe_node_try_fmt_meta_out(file, priv, f);
@@ -1306,7 +1341,7 @@ static int pispbe_enum_framesizes(struct
struct v4l2_frmsizeenum *fsize)
{
struct pispbe_node *node = video_drvdata(file);
- struct pispbe_dev *pispbe = node->pispbe;
+ struct pispbe_dev *pispbe = node->node_group->pispbe;
if (NODE_IS_META(node) || fsize->index)
return -EINVAL;
@@ -1391,17 +1426,19 @@ static void pispbe_node_def_fmt(struct p
* Initialise a struct pispbe_node and register it as /dev/video<N>
* to represent one of the PiSP Back End's input or output streams.
*/
-static int pispbe_init_node(struct pispbe_dev *pispbe, unsigned int id)
+static int pispbe_init_node(struct pispbe_node_group *node_group,
+ unsigned int id)
{
bool output = NODE_DESC_IS_OUTPUT(&node_desc[id]);
- struct pispbe_node *node = &pispbe->node[id];
+ struct pispbe_node *node = &node_group->node[id];
struct media_entity *entity = &node->vfd.entity;
+ struct pispbe_dev *pispbe = node_group->pispbe;
struct video_device *vdev = &node->vfd;
struct vb2_queue *q = &node->queue;
int ret;
node->id = id;
- node->pispbe = pispbe;
+ node->node_group = node_group;
node->buf_type = node_desc[id].buf_type;
mutex_init(&node->node_lock);
@@ -1419,7 +1456,7 @@ static int pispbe_init_node(struct pispb
q->ops = &pispbe_node_queue_ops;
q->buf_struct_size = sizeof(struct pispbe_buffer);
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- q->dev = pispbe->dev;
+ q->dev = node->node_group->pispbe->dev;
/* get V4L2 to handle node->queue locking */
q->lock = &node->queue_lock;
@@ -1431,7 +1468,7 @@ static int pispbe_init_node(struct pispb
*vdev = pispbe_videodev; /* default initialization */
strscpy(vdev->name, node_desc[id].ent_name, sizeof(vdev->name));
- vdev->v4l2_dev = &pispbe->v4l2_dev;
+ vdev->v4l2_dev = &node_group->v4l2_dev;
vdev->vfl_dir = output ? VFL_DIR_TX : VFL_DIR_RX;
/* get V4L2 to serialise our ioctls */
vdev->lock = &node->node_lock;
@@ -1457,11 +1494,11 @@ static int pispbe_init_node(struct pispb
video_set_drvdata(vdev, node);
if (output)
- ret = media_create_pad_link(entity, 0, &pispbe->sd.entity,
+ ret = media_create_pad_link(entity, 0, &node_group->sd.entity,
id, MEDIA_LNK_FL_IMMUTABLE |
MEDIA_LNK_FL_ENABLED);
else
- ret = media_create_pad_link(&pispbe->sd.entity, id, entity,
+ ret = media_create_pad_link(&node_group->sd.entity, id, entity,
0, MEDIA_LNK_FL_IMMUTABLE |
MEDIA_LNK_FL_ENABLED);
if (ret)
@@ -1490,9 +1527,10 @@ static const struct v4l2_subdev_ops pisp
.pad = &pispbe_pad_ops,
};
-static int pispbe_init_subdev(struct pispbe_dev *pispbe)
+static int pispbe_init_subdev(struct pispbe_node_group *node_group)
{
- struct v4l2_subdev *sd = &pispbe->sd;
+ struct pispbe_dev *pispbe = node_group->pispbe;
+ struct v4l2_subdev *sd = &node_group->sd;
int ret;
v4l2_subdev_init(sd, &pispbe_sd_ops);
@@ -1502,16 +1540,16 @@ static int pispbe_init_subdev(struct pis
strscpy(sd->name, PISPBE_NAME, sizeof(sd->name));
for (unsigned int i = 0; i < PISPBE_NUM_NODES; i++)
- pispbe->pad[i].flags =
+ node_group->pad[i].flags =
NODE_DESC_IS_OUTPUT(&node_desc[i]) ?
MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
ret = media_entity_pads_init(&sd->entity, PISPBE_NUM_NODES,
- pispbe->pad);
+ node_group->pad);
if (ret)
goto error;
- ret = v4l2_device_register_subdev(&pispbe->v4l2_dev, sd);
+ ret = v4l2_device_register_subdev(&node_group->v4l2_dev, sd);
if (ret)
goto error;
@@ -1522,36 +1560,43 @@ error:
return ret;
}
-static int pispbe_init_devices(struct pispbe_dev *pispbe)
+static int pispbe_init_group(struct pispbe_dev *pispbe, unsigned int id)
{
+ struct pispbe_node_group *node_group = &pispbe->node_group[id];
struct v4l2_device *v4l2_dev;
struct media_device *mdev;
unsigned int num_regist;
int ret;
+ node_group->id = id;
+ node_group->pispbe = pispbe;
+ node_group->streaming_map = 0;
+
+ dev_dbg(pispbe->dev, "Register nodes for group %u\n", id);
+
/* Register v4l2_device and media_device */
- mdev = &pispbe->mdev;
- mdev->hw_revision = pispbe->hw_version;
- mdev->dev = pispbe->dev;
+ mdev = &node_group->mdev;
+ mdev->hw_revision = node_group->pispbe->hw_version;
+ mdev->dev = node_group->pispbe->dev;
strscpy(mdev->model, PISPBE_NAME, sizeof(mdev->model));
media_device_init(mdev);
- v4l2_dev = &pispbe->v4l2_dev;
- v4l2_dev->mdev = &pispbe->mdev;
+ v4l2_dev = &node_group->v4l2_dev;
+ v4l2_dev->mdev = &node_group->mdev;
strscpy(v4l2_dev->name, PISPBE_NAME, sizeof(v4l2_dev->name));
- ret = v4l2_device_register(pispbe->dev, v4l2_dev);
+ ret = v4l2_device_register(pispbe->dev, &node_group->v4l2_dev);
if (ret)
goto err_media_dev_cleanup;
/* Register the PISPBE subdevice. */
- ret = pispbe_init_subdev(pispbe);
+ ret = pispbe_init_subdev(node_group);
if (ret)
goto err_unregister_v4l2;
/* Create device video nodes */
for (num_regist = 0; num_regist < PISPBE_NUM_NODES; num_regist++) {
- ret = pispbe_init_node(pispbe, num_regist);
+ ret = pispbe_init_node(node_group, num_regist);
if (ret)
goto err_unregister_nodes;
}
@@ -1560,12 +1605,12 @@ static int pispbe_init_devices(struct pi
if (ret)
goto err_unregister_nodes;
- pispbe->config =
+ node_group->config =
dma_alloc_coherent(pispbe->dev,
sizeof(struct pisp_be_tiles_config) *
PISP_BE_NUM_CONFIG_BUFFERS,
- &pispbe->config_dma_addr, GFP_KERNEL);
- if (!pispbe->config) {
+ &node_group->config_dma_addr, GFP_KERNEL);
+ if (!node_group->config) {
dev_err(pispbe->dev, "Unable to allocate cached config buffers.\n");
ret = -ENOMEM;
goto err_unregister_mdev;
@@ -1577,11 +1622,11 @@ err_unregister_mdev:
media_device_unregister(mdev);
err_unregister_nodes:
while (num_regist-- > 0) {
- video_unregister_device(&pispbe->node[num_regist].vfd);
- vb2_queue_release(&pispbe->node[num_regist].queue);
+ video_unregister_device(&node_group->node[num_regist].vfd);
+ vb2_queue_release(&node_group->node[num_regist].queue);
}
- v4l2_device_unregister_subdev(&pispbe->sd);
- media_entity_cleanup(&pispbe->sd.entity);
+ v4l2_device_unregister_subdev(&node_group->sd);
+ media_entity_cleanup(&node_group->sd.entity);
err_unregister_v4l2:
v4l2_device_unregister(v4l2_dev);
err_media_dev_cleanup:
@@ -1589,31 +1634,33 @@ err_media_dev_cleanup:
return ret;
}
-static void pispbe_destroy_devices(struct pispbe_dev *pispbe)
+static void pispbe_destroy_node_group(struct pispbe_node_group *node_group)
{
- if (pispbe->config) {
- dma_free_coherent(pispbe->dev,
+ struct pispbe_dev *pispbe = node_group->pispbe;
+
+ if (node_group->config) {
+ dma_free_coherent(node_group->pispbe->dev,
sizeof(struct pisp_be_tiles_config) *
PISP_BE_NUM_CONFIG_BUFFERS,
- pispbe->config,
- pispbe->config_dma_addr);
+ node_group->config,
+ node_group->config_dma_addr);
}
dev_dbg(pispbe->dev, "Unregister from media controller\n");
- v4l2_device_unregister_subdev(&pispbe->sd);
- media_entity_cleanup(&pispbe->sd.entity);
- media_device_unregister(&pispbe->mdev);
+ v4l2_device_unregister_subdev(&node_group->sd);
+ media_entity_cleanup(&node_group->sd.entity);
+ media_device_unregister(&node_group->mdev);
for (int i = PISPBE_NUM_NODES - 1; i >= 0; i--) {
- video_unregister_device(&pispbe->node[i].vfd);
- vb2_queue_release(&pispbe->node[i].queue);
- mutex_destroy(&pispbe->node[i].node_lock);
- mutex_destroy(&pispbe->node[i].queue_lock);
+ video_unregister_device(&node_group->node[i].vfd);
+ vb2_queue_release(&node_group->node[i].queue);
+ mutex_destroy(&node_group->node[i].node_lock);
+ mutex_destroy(&node_group->node[i].queue_lock);
}
- media_device_cleanup(&pispbe->mdev);
- v4l2_device_unregister(&pispbe->v4l2_dev);
+ media_device_cleanup(&node_group->mdev);
+ v4l2_device_unregister(&node_group->v4l2_dev);
}
static int pispbe_runtime_suspend(struct device *dev)
@@ -1681,9 +1728,13 @@ static int pispbe_hw_init(struct pispbe_
return 0;
}
-/* Probe the ISP-BE hardware block, as a single platform device. */
+/*
+ * Probe the ISP-BE hardware block, as a single platform device.
+ * This will instantiate multiple "node groups" each with many device nodes.
+ */
static int pispbe_probe(struct platform_device *pdev)
{
+ unsigned int num_groups = 0;
struct pispbe_dev *pispbe;
int ret;
@@ -1738,17 +1789,26 @@ static int pispbe_probe(struct platform_
if (ret)
goto pm_runtime_suspend_err;
- ret = pispbe_init_devices(pispbe);
- if (ret)
- goto disable_devs_err;
+ /*
+ * Initialise and register devices for each node_group, including media
+ * device
+ */
+ for (num_groups = 0;
+ num_groups < PISPBE_NUM_NODE_GROUPS;
+ num_groups++) {
+ ret = pispbe_init_group(pispbe, num_groups);
+ if (ret)
+ goto disable_nodes_err;
+ }
pm_runtime_mark_last_busy(pispbe->dev);
pm_runtime_put_autosuspend(pispbe->dev);
return 0;
-disable_devs_err:
- pispbe_destroy_devices(pispbe);
+disable_nodes_err:
+ while (num_groups-- > 0)
+ pispbe_destroy_node_group(&pispbe->node_group[num_groups]);
pm_runtime_suspend_err:
pispbe_runtime_suspend(pispbe->dev);
pm_runtime_disable_err:
@@ -1762,7 +1822,8 @@ static int pispbe_remove(struct platform
{
struct pispbe_dev *pispbe = platform_get_drvdata(pdev);
- pispbe_destroy_devices(pispbe);
+ for (int i = PISPBE_NUM_NODE_GROUPS - 1; i >= 0; i--)
+ pispbe_destroy_node_group(&pispbe->node_group[i]);
pispbe_runtime_suspend(pispbe->dev);
pm_runtime_dont_use_autosuspend(pispbe->dev);

View File

@ -0,0 +1,36 @@
From f372f2854279828a33b9b3debc233d366fb4c124 Mon Sep 17 00:00:00 2001
From: Naushir Patuck <naush@raspberrypi.com>
Date: Mon, 8 Jul 2024 11:47:49 +0100
Subject: [PATCH 1161/1215] media: pisp_be: Re-introduce video node offset
Offset the backend dev-nodes starting at /dev/video20
onwards to maintain backward compatibility with the
pre-upstreamed kernel driver.
Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
---
drivers/media/platform/raspberrypi/pisp_be/pisp_be.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
--- a/drivers/media/platform/raspberrypi/pisp_be/pisp_be.c
+++ b/drivers/media/platform/raspberrypi/pisp_be/pisp_be.c
@@ -21,6 +21,9 @@
#include "pisp_be_formats.h"
+/* Offset to use when registering the /dev/videoX node */
+#define PISPBE_VIDEO_NODE_OFFSET 20
+
/* Maximum number of config buffers possible */
#define PISP_BE_NUM_CONFIG_BUFFERS VB2_MAX_FRAME
@@ -1484,7 +1487,8 @@ static int pispbe_init_node(struct pispb
goto err_unregister_queue;
}
- ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
+ ret = video_register_device(vdev, VFL_TYPE_VIDEO,
+ PISPBE_VIDEO_NODE_OFFSET);
if (ret) {
dev_err(pispbe->dev,
"Failed to register video %s device node\n",

View File

@ -0,0 +1,158 @@
From 6e4ad40811170653431fc40a6fdc3f486863b40f Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
Date: Thu, 4 Jul 2024 18:15:00 +0100
Subject: [PATCH 1163/1215] dts: Make camN_reg and camN_reg_gpio overrides
generic
The camera regulator GPIO can be used for other purposes,
so the camN_reg override to allow disabling is potentially
useful on any platform.
camN_gpio is less useful, but isn't invalid.
Move these overrides from the CM dt files to bcm270x-rpi.dtsi
and bcm2712-rpi.dtsi.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
.../arm/boot/dts/broadcom/bcm2708-rpi-cm.dtsi | 4 ----
.../arm/boot/dts/broadcom/bcm2709-rpi-cm2.dts | 4 ----
arch/arm/boot/dts/broadcom/bcm270x-rpi.dtsi | 7 +++++++
.../arm/boot/dts/broadcom/bcm2710-rpi-cm3.dts | 4 ----
.../arm/boot/dts/broadcom/bcm2711-rpi-cm4.dts | 7 -------
.../boot/dts/broadcom/bcm2711-rpi-cm4s.dts | 5 -----
arch/arm/boot/dts/broadcom/bcm2712-rpi.dtsi | 8 ++++++++
arch/arm/boot/dts/overlays/README | 20 +++++++++----------
8 files changed, 25 insertions(+), 34 deletions(-)
--- a/arch/arm/boot/dts/broadcom/bcm2708-rpi-cm.dtsi
+++ b/arch/arm/boot/dts/broadcom/bcm2708-rpi-cm.dtsi
@@ -19,9 +19,5 @@ i2c_vc: &i2c0 {
act_led_gpio = <&led_act>,"gpios:4";
act_led_activelow = <&led_act>,"gpios:8";
act_led_trigger = <&led_act>,"linux,default-trigger";
- cam0_reg = <&cam0_reg>,"status";
- cam0_reg_gpio = <&cam0_reg>,"gpio:4";
- cam1_reg = <&cam1_reg>,"status";
- cam1_reg_gpio = <&cam1_reg>,"gpio:4";
};
};
--- a/arch/arm/boot/dts/broadcom/bcm2709-rpi-cm2.dts
+++ b/arch/arm/boot/dts/broadcom/bcm2709-rpi-cm2.dts
@@ -211,9 +211,5 @@ i2c_csi_dsi0: &i2c0 {
act_led_gpio = <&led_act>,"gpios:4";
act_led_activelow = <&led_act>,"gpios:8";
act_led_trigger = <&led_act>,"linux,default-trigger";
- cam0_reg = <&cam0_reg>,"status";
- cam0_reg_gpio = <&cam0_reg>,"gpio:4";
- cam1_reg = <&cam1_reg>,"status";
- cam1_reg_gpio = <&cam1_reg>,"gpio:4";
};
};
--- a/arch/arm/boot/dts/broadcom/bcm270x-rpi.dtsi
+++ b/arch/arm/boot/dts/broadcom/bcm270x-rpi.dtsi
@@ -111,6 +111,13 @@
<&csi0>, "sync-gpios:4",
<&csi0>, "sync-gpios:8=", <GPIO_ACTIVE_LOW>;
+ cam0_reg = <&cam0_reg>,"status";
+ cam0_reg_gpio = <&cam0_reg>,"gpio:4",
+ <&cam0_reg>,"gpio:0=", <&gpio>;
+ cam1_reg = <&cam1_reg>,"status";
+ cam1_reg_gpio = <&cam1_reg>,"gpio:4",
+ <&cam1_reg>,"gpio:0=", <&gpio>;
+
strict_gpiod = <&chosen>, "bootargs=pinctrl_bcm2835.persist_gpio_outputs=n";
};
};
--- a/arch/arm/boot/dts/broadcom/bcm2710-rpi-cm3.dts
+++ b/arch/arm/boot/dts/broadcom/bcm2710-rpi-cm3.dts
@@ -211,9 +211,5 @@ i2c_csi_dsi0: &i2c0 {
act_led_gpio = <&led_act>,"gpios:4";
act_led_activelow = <&led_act>,"gpios:8";
act_led_trigger = <&led_act>,"linux,default-trigger";
- cam0_reg = <&cam0_reg>,"status";
- cam0_reg_gpio = <&cam0_reg>,"gpio:4";
- cam1_reg = <&cam1_reg>,"status";
- cam1_reg_gpio = <&cam1_reg>,"gpio:4";
};
};
--- a/arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4.dts
+++ b/arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4.dts
@@ -498,13 +498,6 @@ i2c_csi_dsi0: &i2c0 {
<&ant2>, "output-high?=off",
<&ant2>, "output-low?=on";
- cam0_reg = <&cam0_reg>,"status";
- cam0_reg_gpio = <&cam0_reg>,"gpio:4",
- <&cam0_reg>,"gpio:0=", <&gpio>;
- cam1_reg = <&cam1_reg>,"status";
- cam1_reg_gpio = <&cam1_reg>,"gpio:4",
- <&cam1_reg>,"gpio:0=", <&gpio>;
-
pcie_tperst_clk_ms = <&pcie0>,"brcm,tperst-clk-ms:0";
};
};
--- a/arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4s.dts
+++ b/arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4s.dts
@@ -289,10 +289,5 @@ i2c_csi_dsi0: &i2c0 {
act_led_gpio = <&led_act>,"gpios:4";
act_led_activelow = <&led_act>,"gpios:8";
act_led_trigger = <&led_act>,"linux,default-trigger";
-
- cam0_reg = <&cam0_reg>,"status";
- cam0_reg_gpio = <&cam0_reg>,"gpio:4";
- cam1_reg = <&cam1_reg>,"status";
- cam1_reg_gpio = <&cam1_reg>,"gpio:4";
};
};
--- a/arch/arm/boot/dts/broadcom/bcm2712-rpi.dtsi
+++ b/arch/arm/boot/dts/broadcom/bcm2712-rpi.dtsi
@@ -106,6 +106,14 @@
nvmem_priv_rw = <&nvmem_priv>,"rw?";
nvmem_mac_rw = <&nvmem_mac>,"rw?";
strict_gpiod = <&chosen>, "bootargs=pinctrl_rp1.persist_gpio_outputs=n";
+
+ cam0_reg = <&cam0_reg>,"status";
+ cam0_reg_gpio = <&cam0_reg>,"gpio:4",
+ <&cam0_reg>,"gpio:0=", <&gpio>;
+ cam1_reg = <&cam1_reg>,"status";
+ cam1_reg_gpio = <&cam1_reg>,"gpio:4",
+ <&cam1_reg>,"gpio:0=", <&gpio>;
+
};
};
--- a/arch/arm/boot/dts/overlays/README
+++ b/arch/arm/boot/dts/overlays/README
@@ -171,21 +171,21 @@ Params:
button_debounce Set the debounce delay (in ms) on the power/
shutdown button (default 50ms)
- cam0_reg Enables CAM 0 regulator.
- Only required on CM1 & 3.
+ cam0_reg Controls CAM 0 regulator.
+ Disabled by default on CM1 & 3.
+ Enabled by default on all other boards.
cam0_reg_gpio Set GPIO for CAM 0 regulator.
- Default 31 on CM1, 3, and 4S.
- Default of GPIO expander 5 on CM4, but override
- switches to normal GPIO.
+ NB override switches to the normal GPIO driver,
+ even if the original was on the GPIO expander.
- cam1_reg Enables CAM 1 regulator.
- Only required on CM1 & 3.
+ cam1_reg Controls CAM 1 regulator.
+ Disabled by default on CM1 & 3.
+ Enabled by default on all other boards.
cam1_reg_gpio Set GPIO for CAM 1 regulator.
- Default 3 on CM1, 3, and 4S.
- Default of GPIO expander 5 on CM4, but override
- switches to normal GPIO.
+ NB override switches to the normal GPIO driver,
+ even if the original was on the GPIO expander.
cam0_sync Enable a GPIO to reflect frame sync from CSI0,
going high on frame start, and low on frame end.

View File

@ -0,0 +1,108 @@
From afd949f5f64d224cf7a016ef933257842bc170ab Mon Sep 17 00:00:00 2001
From: Richard Oliver <richard.oliver@raspberrypi.com>
Date: Fri, 24 May 2024 10:34:45 +0100
Subject: [PATCH 1164/1215] spi: dt-bindings: Add RPI RP2040 GPIO Bridge
Add YAML device tree bindings for the Raspberry Pi RP2040 GPIO Bridge.
Signed-off-by: Richard Oliver <richard.oliver@raspberrypi.com>
---
.../spi/raspberrypi,rp2040-gpio-bridge.yaml | 77 +++++++++++++++++++
MAINTAINERS | 5 ++
2 files changed, 82 insertions(+)
create mode 100644 Documentation/devicetree/bindings/spi/raspberrypi,rp2040-gpio-bridge.yaml
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/raspberrypi,rp2040-gpio-bridge.yaml
@@ -0,0 +1,77 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/spi/raspberrypi,rp2040-gpio-bridge.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Raspberry Pi RP2040 GPIO Bridge
+
+maintainers:
+ - Raspberry Pi <kernel-list@raspberrypi.com>
+
+description: |-
+ The Raspberry Pi PR2040 GPIO bridge can be used as a GPIO expander and
+ Tx-only SPI master.
+
+properties:
+ reg:
+ description: I2C slave address
+ const: 0x40
+
+ compatible:
+ const: raspberrypi,rp2040-gpio-bridge
+
+ power-supply:
+ description: Phandle to the regulator that powers the RP2040.
+
+ '#address-cells':
+ const: 1
+
+ '#size-cells':
+ const: 0
+
+ '#gpio-cells':
+ const: 2
+
+ gpio-controller: true
+
+ fast_xfer_requires_i2c_lock:
+ description: Set if I2C bus should be locked during fast transfer.
+
+ fast_xfer_recv_gpio_base:
+ description: RP2040 GPIO base for fast transfer pair.
+
+ fast_xfer-gpios:
+ description: RP1 GPIOs to use for fast transfer clock and data.
+
+required:
+ - reg
+ - compatible
+ - power-supply
+ - '#gpio-cells'
+ - gpio-controller
+
+additionalProperties: false
+
+examples:
+ - |
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ spi@40 {
+ reg = <0x40>;
+ compatible = "raspberrypi,rp2040-gpio-bridge";
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ power-supply = <&cam_dummy_reg>;
+
+ #gpio-cells = <2>;
+ gpio-controller;
+ };
+ };
+
+...
+
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -18027,6 +18027,11 @@ F: drivers/ras/
F: include/linux/ras.h
F: include/ras/ras_event.h
+RASPBERRY PI RP2040 GPIO BRIDGE DRIVER
+M: Raspberry Pi Kernel Maintenance <kernel-list@raspberrypi.com>
+S: Maintained
+F: Documentation/devicetree/bindings/spi/raspberrypi,rp2040-gpio-bridge.yaml
+
RAYLINK/WEBGEAR 802.11 WIRELESS LAN DRIVER
L: linux-wireless@vger.kernel.org
S: Orphan

View File

@ -0,0 +1,52 @@
From 475cddaba6b02584157e1c128a5a6858770a3d06 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
Date: Wed, 10 Jul 2024 14:47:17 +0100
Subject: [PATCH 1166/1215] dmaengine: dw-axi-dmac: Honour snps,block-size
The snps,block-size DT property declares the maximum block size for each
channel of the dw-axi-dmac. However, the driver ignores these when
setting max_seg_size and uses MAX_BLOCK_SIZE (4096) instead.
To take advantage of the efficiencies of larger blocks, calculate the
minimum block size across all channels and use that instead.
See: https://github.com/raspberrypi/linux/issues/6256
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
---
drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
+++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
@@ -1470,6 +1470,7 @@ static int dw_probe(struct platform_devi
struct dw_axi_dma *dw;
struct dw_axi_dma_hcfg *hdata;
struct reset_control *resets;
+ unsigned int max_seg_size;
unsigned int flags;
u32 i;
int ret;
@@ -1585,9 +1586,21 @@ static int dw_probe(struct platform_devi
* Synopsis DesignWare AxiDMA datasheet mentioned Maximum
* supported blocks is 1024. Device register width is 4 bytes.
* Therefore, set constraint to 1024 * 4.
+ * However, if all channels specify a greater value, use that instead.
*/
+
dw->dma.dev->dma_parms = &dw->dma_parms;
- dma_set_max_seg_size(&pdev->dev, MAX_BLOCK_SIZE);
+ max_seg_size = UINT_MAX;
+ for (i = 0; i < dw->hdata->nr_channels; i++) {
+ unsigned int block_size = chip->dw->hdata->block_size[i];
+
+ if (!block_size)
+ block_size = MAX_BLOCK_SIZE;
+ max_seg_size = min(block_size, max_seg_size);
+ }
+
+ dma_set_max_seg_size(&pdev->dev, max_seg_size);
+
platform_set_drvdata(pdev, chip);
pm_runtime_enable(chip->dev);

View File

@ -0,0 +1,157 @@
From e6c1e862b2b8150a419f4208e5bd7749662b16a1 Mon Sep 17 00:00:00 2001
From: Jonathan Bell <jonathan@raspberrypi.com>
Date: Thu, 20 Jun 2024 14:31:20 +0100
Subject: [PATCH 1167/1215] mmc: restrict posted write counts for SD cards in
CQ mode
Command Queueing requires Write Cache and Power off Notification support
from the card - but using the write cache forms a contract with the host
whereby the card expects to be told about impending power-down.
The implication is that (for performance) the card can do unsafe things
with pending write data - including reordering what gets committed to
nonvolatile storage at what time.
Exposed SD slots and platforms powered by hotpluggable means (i.e.
Raspberry Pis) can't guarantee that surprise removal won't happen.
To limit the scope for cards to invent new ways to trash filesystems,
limit pending writes to 1 (equivalent to the non-CQ behaviour).
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
---
drivers/mmc/core/block.c | 11 +++++++++--
drivers/mmc/core/mmc.c | 1 +
drivers/mmc/core/queue.c | 9 +++++++++
drivers/mmc/core/queue.h | 1 +
drivers/mmc/core/sd.c | 8 ++++++++
include/linux/mmc/card.h | 2 ++
6 files changed, 30 insertions(+), 2 deletions(-)
--- a/drivers/mmc/core/block.c
+++ b/drivers/mmc/core/block.c
@@ -1555,6 +1555,8 @@ static void mmc_blk_cqe_complete_rq(stru
spin_lock_irqsave(&mq->lock, flags);
+ if (req_op(req) == REQ_OP_WRITE)
+ mq->pending_writes--;
mq->in_flight[issue_type] -= 1;
put_card = (mmc_tot_in_flight(mq) == 0);
@@ -2071,6 +2073,8 @@ static void mmc_blk_mq_complete_rq(struc
struct mmc_queue_req *mqrq = req_to_mmc_queue_req(req);
unsigned int nr_bytes = mqrq->brq.data.bytes_xfered;
+ if (req_op(req) == REQ_OP_WRITE)
+ mq->pending_writes--;
if (nr_bytes) {
if (blk_update_request(req, BLK_STS_OK, nr_bytes))
blk_mq_requeue_request(req, true);
@@ -2165,13 +2169,16 @@ static void mmc_blk_mq_poll_completion(s
mmc_blk_urgent_bkops(mq, mqrq);
}
-static void mmc_blk_mq_dec_in_flight(struct mmc_queue *mq, enum mmc_issue_type issue_type)
+static void mmc_blk_mq_dec_in_flight(struct mmc_queue *mq, enum mmc_issue_type issue_type,
+ struct request *req)
{
unsigned long flags;
bool put_card;
spin_lock_irqsave(&mq->lock, flags);
+ if (req_op(req) == REQ_OP_WRITE)
+ mq->pending_writes--;
mq->in_flight[issue_type] -= 1;
put_card = (mmc_tot_in_flight(mq) == 0);
@@ -2205,7 +2212,7 @@ static void mmc_blk_mq_post_req(struct m
blk_mq_complete_request(req);
}
- mmc_blk_mq_dec_in_flight(mq, issue_type);
+ mmc_blk_mq_dec_in_flight(mq, issue_type, req);
}
void mmc_blk_mq_recovery(struct mmc_queue *mq)
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1922,6 +1922,7 @@ static int mmc_init_card(struct mmc_host
pr_info("%s: Host Software Queue enabled\n",
mmc_hostname(host));
}
+ card->max_posted_writes = card->ext_csd.cmdq_depth;
}
}
--- a/drivers/mmc/core/queue.c
+++ b/drivers/mmc/core/queue.c
@@ -268,6 +268,11 @@ static blk_status_t mmc_mq_queue_rq(stru
spin_unlock_irq(&mq->lock);
return BLK_STS_RESOURCE;
}
+ if (host->cqe_enabled && req_op(req) == REQ_OP_WRITE &&
+ mq->pending_writes >= card->max_posted_writes) {
+ spin_unlock_irq(&mq->lock);
+ return BLK_STS_RESOURCE;
+ }
break;
default:
/*
@@ -284,6 +289,8 @@ static blk_status_t mmc_mq_queue_rq(stru
/* Parallel dispatch of requests is not supported at the moment */
mq->busy = true;
+ if (req_op(req) == REQ_OP_WRITE)
+ mq->pending_writes++;
mq->in_flight[issue_type] += 1;
get_card = (mmc_tot_in_flight(mq) == 1);
cqe_retune_ok = (mmc_cqe_qcnt(mq) == 1);
@@ -323,6 +330,8 @@ static blk_status_t mmc_mq_queue_rq(stru
bool put_card = false;
spin_lock_irq(&mq->lock);
+ if (req_op(req) == REQ_OP_WRITE)
+ mq->pending_writes--;
mq->in_flight[issue_type] -= 1;
if (mmc_tot_in_flight(mq) == 0)
put_card = true;
--- a/drivers/mmc/core/queue.h
+++ b/drivers/mmc/core/queue.h
@@ -79,6 +79,7 @@ struct mmc_queue {
struct request_queue *queue;
spinlock_t lock;
int in_flight[MMC_ISSUE_MAX];
+ int pending_writes;
unsigned int cqe_busy;
#define MMC_CQE_DCMD_BUSY BIT(0)
bool busy;
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1104,6 +1104,14 @@ static int sd_parse_ext_reg_perf(struct
pr_debug("%s: Command Queue supported depth %u\n",
mmc_hostname(card->host),
card->ext_csd.cmdq_depth);
+ /*
+ * If CQ is enabled, there is a contract between host and card such that VDD will
+ * be maintained and removed only if a power off notification is provided.
+ * An SD card in an accessible slot means surprise removal is a possibility.
+ * As a middle ground, limit max posted writes to 1 unless the card is "hardwired".
+ */
+ if (mmc_card_is_removable(card->host))
+ card->max_posted_writes = 1;
}
card->ext_perf.fno = fno;
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -343,6 +343,8 @@ struct mmc_card {
unsigned int nr_parts;
struct workqueue_struct *complete_wq; /* Private workqueue */
+
+ unsigned int max_posted_writes; /* command queue posted write limit */
};
static inline bool mmc_large_sector(struct mmc_card *card)

View File

@ -0,0 +1,70 @@
From 19682239a60c1b53cad8319eaeb58e71d4213cee Mon Sep 17 00:00:00 2001
From: Jonathan Bell <jonathan@raspberrypi.com>
Date: Mon, 15 Jul 2024 13:38:38 +0100
Subject: [PATCH 1168/1215] fixup: mmc: restrict posted write counts for SD
cards in CQ mode
Leaving card->max_posted_writes unintialised was a bad thing to do.
Also, cqe_enable is 1 if hsq is enabled as hsq substitutes the cqhci
implementation with its own.
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
---
drivers/mmc/core/mmc.c | 1 +
drivers/mmc/core/queue.c | 2 +-
drivers/mmc/core/sd.c | 14 ++++++++------
3 files changed, 10 insertions(+), 7 deletions(-)
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1663,6 +1663,7 @@ static int mmc_init_card(struct mmc_host
card->ocr = ocr;
card->type = MMC_TYPE_MMC;
card->rca = 1;
+ card->max_posted_writes = 1;
memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
}
--- a/drivers/mmc/core/queue.c
+++ b/drivers/mmc/core/queue.c
@@ -268,7 +268,7 @@ static blk_status_t mmc_mq_queue_rq(stru
spin_unlock_irq(&mq->lock);
return BLK_STS_RESOURCE;
}
- if (host->cqe_enabled && req_op(req) == REQ_OP_WRITE &&
+ if (!host->hsq_enabled && host->cqe_enabled && req_op(req) == REQ_OP_WRITE &&
mq->pending_writes >= card->max_posted_writes) {
spin_unlock_irq(&mq->lock);
return BLK_STS_RESOURCE;
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1105,13 +1105,14 @@ static int sd_parse_ext_reg_perf(struct
mmc_hostname(card->host),
card->ext_csd.cmdq_depth);
/*
- * If CQ is enabled, there is a contract between host and card such that VDD will
- * be maintained and removed only if a power off notification is provided.
- * An SD card in an accessible slot means surprise removal is a possibility.
- * As a middle ground, limit max posted writes to 1 unless the card is "hardwired".
+ * If CQ is enabled, there is a contract between host and card such that
+ * VDD will be maintained and removed only if a power off notification
+ * is provided. An SD card in an accessible slot means surprise removal
+ * is a possibility. As a middle ground, keep the default maximum of 1
+ * posted write unless the card is "hardwired".
*/
- if (mmc_card_is_removable(card->host))
- card->max_posted_writes = 1;
+ if (!mmc_card_is_removable(card->host))
+ card->max_posted_writes = card->ext_csd.cmdq_depth;
}
card->ext_perf.fno = fno;
@@ -1383,6 +1384,7 @@ retry:
card->ocr = ocr;
card->type = MMC_TYPE_SD;
+ card->max_posted_writes = 1;
memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
}

View File

@ -0,0 +1,28 @@
From 1abc413af44652d6a76d5b5c2afe90788595008e Mon Sep 17 00:00:00 2001
From: Jonathan Bell <jonathan@raspberrypi.com>
Date: Mon, 15 Jul 2024 13:57:01 +0100
Subject: [PATCH 1169/1215] mmc: brcmstb: don't squash card-busy detection on
bcm2712
Commit 485d9421719b ("mmc: sdhci-brcmstb: check R1_STATUS for
erase/trim/discard") introduced a new flag and defaulted to disabling
card busy detection across all platforms with this controller.
This is required for IO voltage switching, as the card drives CMD low
while the switch is in progress.
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
---
drivers/mmc/host/sdhci-brcmstb.c | 1 +
1 file changed, 1 insertion(+)
--- a/drivers/mmc/host/sdhci-brcmstb.c
+++ b/drivers/mmc/host/sdhci-brcmstb.c
@@ -430,6 +430,7 @@ static const struct brcmstb_match_priv m
};
static const struct brcmstb_match_priv match_priv_2712 = {
+ .flags = BRCMSTB_MATCH_FLAGS_USE_CARD_BUSY,
.hs400es = sdhci_brcmstb_hs400es,
.cfginit = sdhci_brcmstb_cfginit_2712,
.ops = &sdhci_brcmstb_ops_2712,

View File

@ -0,0 +1,25 @@
From 31eb43be8cad2818b4458cf1fd2dfa60031ee5f4 Mon Sep 17 00:00:00 2001
From: Matthew <sirfragles@gmail.com>
Date: Tue, 16 Jul 2024 11:20:54 +0200
Subject: [PATCH 1172/1215] Revert "Update DAC8x to support 384khz (#6187)"
This reverts commit dd7a15472b18d4bce738bb9213443c140473833b.
---
sound/soc/bcm/rpi-simple-soundcard.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
--- a/sound/soc/bcm/rpi-simple-soundcard.c
+++ b/sound/soc/bcm/rpi-simple-soundcard.c
@@ -324,10 +324,10 @@ static int hifiberry_dac8x_init(struct s
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
/* override the defaults to reflect 4 x PCM5102A on the card
- * and limit the sample rate to 384ksps
+ * and limit the sample rate to 192ksps
*/
codec_dai->driver->playback.channels_max = 8;
- codec_dai->driver->playback.rates = SNDRV_PCM_RATE_8000_384000;
+ codec_dai->driver->playback.rates = SNDRV_PCM_RATE_8000_192000;
return 0;
}

View File

@ -0,0 +1,25 @@
From 3224569a3e279bbeae4e975dfa1a890f3f595239 Mon Sep 17 00:00:00 2001
From: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
Date: Fri, 10 May 2024 15:18:44 +0100
Subject: [PATCH 1176/1215] dt-bindings: clk: rp1: Add clocks representing MIPI
DSI byteclock
Define two new RP1 clocks, representing the MIPI DSI byteclock
sources for the dividers used to generate MIPI[01] DPI pixel clocks.
(Previously they were represented by "fake" fixed clocks sources).
Signed-off-by: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
---
include/dt-bindings/clock/rp1.h | 4 ++++
1 file changed, 4 insertions(+)
--- a/include/dt-bindings/clock/rp1.h
+++ b/include/dt-bindings/clock/rp1.h
@@ -54,3 +54,7 @@
/* Extra PLL output channels - RP1B0 only */
#define RP1_PLL_VIDEO_PRI_PH 43
#define RP1_PLL_AUDIO_TERN 44
+
+/* MIPI clocks managed by the DSI driver */
+#define RP1_CLK_MIPI0_DSI_BYTECLOCK 45
+#define RP1_CLK_MIPI1_DSI_BYTECLOCK 46

View File

@ -0,0 +1,132 @@
From 126560c909f38f00c08dd5f35f50c981d5e25e1f Mon Sep 17 00:00:00 2001
From: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
Date: Fri, 10 May 2024 15:30:44 +0100
Subject: [PATCH 1177/1215] clk: clk-rp1: Add "varsrc" clocks to represent MIPI
byte clocks
Add a new class of clocks to RP1 to represent clock sources whose
frequency changes at run-time as a side-effect of some other driver.
Specifically this is for the two MIPI DSI byte-clock sources.
Signed-off-by: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
---
drivers/clk/clk-rp1.c | 73 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 73 insertions(+)
--- a/drivers/clk/clk-rp1.c
+++ b/drivers/clk/clk-rp1.c
@@ -394,6 +394,11 @@ struct rp1_clock {
unsigned long cached_rate;
};
+struct rp1_varsrc {
+ struct clk_hw hw;
+ struct rp1_clockman *clockman;
+ unsigned long rate;
+};
struct rp1_clk_change {
struct clk_hw *hw;
@@ -1414,6 +1419,34 @@ static void rp1_clk_debug_init(struct cl
rp1_debugfs_regset(clockman, 0, regs, i, dentry);
}
+static int rp1_varsrc_set_rate(struct clk_hw *hw,
+ unsigned long rate, unsigned long parent_rate)
+{
+ struct rp1_varsrc *varsrc = container_of(hw, struct rp1_varsrc, hw);
+
+ /*
+ * "varsrc" exists purely to let clock dividers know the frequency
+ * of an externally-managed clock source (such as MIPI DSI byte-clock)
+ * which may change at run-time as a side-effect of some other driver.
+ */
+ varsrc->rate = rate;
+ return 0;
+}
+
+static unsigned long rp1_varsrc_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct rp1_varsrc *varsrc = container_of(hw, struct rp1_varsrc, hw);
+
+ return varsrc->rate;
+}
+
+static long rp1_varsrc_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ return rate;
+}
+
static const struct clk_ops rp1_pll_core_ops = {
.is_prepared = rp1_pll_core_is_on,
.prepare = rp1_pll_core_on,
@@ -1464,6 +1497,12 @@ static const struct clk_ops rp1_clk_ops
.debug_init = rp1_clk_debug_init,
};
+static const struct clk_ops rp1_varsrc_ops = {
+ .set_rate = rp1_varsrc_set_rate,
+ .recalc_rate = rp1_varsrc_recalc_rate,
+ .round_rate = rp1_varsrc_round_rate,
+};
+
static bool rp1_clk_is_claimed(const char *name);
static struct clk_hw *rp1_register_pll_core(struct rp1_clockman *clockman,
@@ -1647,6 +1686,35 @@ static struct clk_hw *rp1_register_clock
return &clock->hw;
}
+static struct clk_hw *rp1_register_varsrc(struct rp1_clockman *clockman,
+ const void *data)
+{
+ const char *name = *(char const * const *)data;
+ struct rp1_varsrc *clock;
+ struct clk_init_data init;
+ int ret;
+
+ memset(&init, 0, sizeof(init));
+ init.parent_names = &ref_clock;
+ init.num_parents = 1;
+ init.name = name;
+ init.flags = CLK_IGNORE_UNUSED;
+ init.ops = &rp1_varsrc_ops;
+
+ clock = devm_kzalloc(clockman->dev, sizeof(*clock), GFP_KERNEL);
+ if (!clock)
+ return NULL;
+
+ clock->clockman = clockman;
+ clock->hw.init = &init;
+
+ ret = devm_clk_hw_register(clockman->dev, &clock->hw);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return &clock->hw;
+}
+
struct rp1_clk_desc {
struct clk_hw *(*clk_register)(struct rp1_clockman *clockman,
const void *data);
@@ -1676,6 +1744,8 @@ struct rp1_clk_desc {
&(struct rp1_clock_data) \
{__VA_ARGS__})
+#define REGISTER_VARSRC(n) _REGISTER(&rp1_register_varsrc, &(const char *){n})
+
static const struct rp1_clk_desc clk_desc_array[] = {
[RP1_PLL_SYS_CORE] = REGISTER_PLL_CORE(
.name = "pll_sys_core",
@@ -2318,6 +2388,9 @@ static const struct rp1_clk_desc clk_des
.max_freq = 200 * MHz,
.fc0_src = FC_NUM(3, 6),
),
+
+ [RP1_CLK_MIPI0_DSI_BYTECLOCK] = REGISTER_VARSRC("clksrc_mipi0_dsi_byteclk"),
+ [RP1_CLK_MIPI1_DSI_BYTECLOCK] = REGISTER_VARSRC("clksrc_mipi1_dsi_byteclk"),
};
static bool rp1_clk_claimed[ARRAY_SIZE(clk_desc_array)];

View File

@ -0,0 +1,92 @@
From 9a108c82b6f6526e0aa8a19befa1ed3f31f8fe52 Mon Sep 17 00:00:00 2001
From: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
Date: Fri, 10 May 2024 15:42:29 +0100
Subject: [PATCH 1178/1215] dts: rp1: DSI drivers to use newly defined MIPI
byte source clocks.
Remove the "dummy" 72MHz fixed clock sources and associate DSI driver
with the new "variable" clock sources now defined in RP1 clocks.
Also add PLLSYS clock to DSI, which it will need as an alternative
clock source in those cases where DPI pixclock > DSI byteclock.
Signed-off-by: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
---
arch/arm/boot/dts/broadcom/rp1.dtsi | 50 +++++++++--------------------
1 file changed, 15 insertions(+), 35 deletions(-)
--- a/arch/arm/boot/dts/broadcom/rp1.dtsi
+++ b/arch/arm/boot/dts/broadcom/rp1.dtsi
@@ -1109,16 +1109,15 @@
interrupts = <RP1_INT_MIPI0 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&rp1_clocks RP1_CLK_MIPI0_CFG>, // required, config bus clock
- <&rp1_clocks RP1_CLK_MIPI0_DPI>, // required, pixel clock
- <&clksrc_mipi0_dsi_byteclk>, // internal, parent for divide
- <&clk_xosc>; // hardwired to DSI "refclk"
- clock-names = "cfgclk", "dpiclk", "byteclk", "refclk";
+ clocks = <&rp1_clocks RP1_CLK_MIPI0_CFG>,
+ <&rp1_clocks RP1_CLK_MIPI0_DPI>,
+ <&rp1_clocks RP1_CLK_MIPI0_DSI_BYTECLOCK>,
+ <&clk_xosc>, // hardwired to DSI "refclk"
+ <&rp1_clocks RP1_PLL_SYS>; // alternate parent for divide
+ clock-names = "cfgclk", "dpiclk", "byteclk", "refclk", "pllsys";
- assigned-clocks = <&rp1_clocks RP1_CLK_MIPI0_CFG>,
- <&rp1_clocks RP1_CLK_MIPI0_DPI>;
+ assigned-clocks = <&rp1_clocks RP1_CLK_MIPI0_CFG>;
assigned-clock-rates = <25000000>;
- assigned-clock-parents = <0>, <&clksrc_mipi0_dsi_byteclk>;
};
rp1_dsi1: dsi@128000 {
@@ -1130,16 +1129,15 @@
interrupts = <RP1_INT_MIPI1 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&rp1_clocks RP1_CLK_MIPI1_CFG>, // required, config bus clock
- <&rp1_clocks RP1_CLK_MIPI1_DPI>, // required, pixel clock
- <&clksrc_mipi1_dsi_byteclk>, // internal, parent for divide
- <&clk_xosc>; // hardwired to DSI "refclk"
- clock-names = "cfgclk", "dpiclk", "byteclk", "refclk";
+ clocks = <&rp1_clocks RP1_CLK_MIPI1_CFG>,
+ <&rp1_clocks RP1_CLK_MIPI1_DPI>,
+ <&rp1_clocks RP1_CLK_MIPI1_DSI_BYTECLOCK>,
+ <&clk_xosc>, // hardwired to DSI "refclk"
+ <&rp1_clocks RP1_PLL_SYS>; // alternate parent for divide
+ clock-names = "cfgclk", "dpiclk", "byteclk", "refclk", "pllsys";
- assigned-clocks = <&rp1_clocks RP1_CLK_MIPI1_CFG>,
- <&rp1_clocks RP1_CLK_MIPI1_DPI>;
+ assigned-clocks = <&rp1_clocks RP1_CLK_MIPI1_CFG>;
assigned-clock-rates = <25000000>;
- assigned-clock-parents = <0>, <&clksrc_mipi1_dsi_byteclk>;
};
/* VEC and DPI both need to control PLL_VIDEO and cannot work together; */
@@ -1216,24 +1214,6 @@
clock-output-names = "core";
clock-frequency = <50000000>;
};
- clksrc_mipi0_dsi_byteclk: clksrc_mipi0_dsi_byteclk {
- // This clock is synthesized by MIPI0 D-PHY, when DSI is running.
- // Its frequency is not known a priori (until a panel driver attaches)
- // so assign a made-up frequency of 72MHz so it can be divided for DPI.
- compatible = "fixed-clock";
- #clock-cells = <0>;
- clock-output-names = "clksrc_mipi0_dsi_byteclk";
- clock-frequency = <72000000>;
- };
- clksrc_mipi1_dsi_byteclk: clksrc_mipi1_dsi_byteclk {
- // This clock is synthesized by MIPI1 D-PHY, when DSI is running.
- // Its frequency is not known a priori (until a panel driver attaches)
- // so assign a made-up frequency of 72MHz so it can be divided for DPI.
- compatible = "fixed-clock";
- #clock-cells = <0>;
- clock-output-names = "clksrc_mipi1_dsi_byteclk";
- clock-frequency = <72000000>;
- };
/* GPIO derived clock sources. Each GPIO with a GPCLK function
* can drive its output from the respective GPCLK
* generator, and provide a clock source to other internal

View File

@ -0,0 +1,313 @@
From f5de8d46da4b40f2180be502c1e547fe8c9b2ac2 Mon Sep 17 00:00:00 2001
From: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
Date: Fri, 10 May 2024 15:48:15 +0100
Subject: [PATCH 1179/1215] drm: rp1: rp1-dsi: Switch to PLL_SYS source for DPI
when 8 * lanes > bpp
To support 4 lanes, re-parent DPI clock source between DSI byteclock
(using the new "variable sources" defined in clk-rp1) and PLL_SYS.
This is to cover cases in which byteclock < pixclock <= 200MHz.
Tidying: All frequencies now in Hz (not kHz), where DSI speed is now
represented by byteclock to simplify arithmetic. Clamp DPI and byte
clocks to their legal ranges; fix up HSTX timeout to avoid an unsafe
assumption that it would return to LP state for every scanline.
Because of RP1's clock topology, the ratio between DSI and DPI clocks
may not be exact with 3 or 4 lanes, leading to slightly irregular
timings each time DSI switches between HS and LP states. Tweak to
inhibit LP during Horizontal BP when sync pulses were requested.
Signed-off-by: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
---
drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.c | 3 +-
drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.h | 3 +-
drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dsi.c | 130 +++++++++++++---------
3 files changed, 80 insertions(+), 56 deletions(-)
--- a/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.c
+++ b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.c
@@ -54,6 +54,7 @@ static void rp1_dsi_bridge_pre_enable(st
struct rp1_dsi *dsi = bridge_to_rp1_dsi(bridge);
rp1dsi_dsi_setup(dsi, &dsi->pipe.crtc.state->adjusted_mode);
+ dsi->dsi_running = true;
}
static void rp1_dsi_bridge_enable(struct drm_bridge *bridge,
@@ -443,7 +444,7 @@ static int rp1dsi_platform_probe(struct
/* Hardware resources */
for (i = 0; i < RP1DSI_NUM_CLOCKS; i++) {
static const char * const myclocknames[RP1DSI_NUM_CLOCKS] = {
- "cfgclk", "dpiclk", "byteclk", "refclk"
+ "cfgclk", "dpiclk", "byteclk", "refclk", "pllsys"
};
dsi->clocks[i] = devm_clk_get(dev, myclocknames[i]);
if (IS_ERR(dsi->clocks[i])) {
--- a/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.h
+++ b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.h
@@ -30,7 +30,8 @@
#define RP1DSI_CLOCK_DPI 1
#define RP1DSI_CLOCK_BYTE 2
#define RP1DSI_CLOCK_REF 3
-#define RP1DSI_NUM_CLOCKS 4
+#define RP1DSI_CLOCK_PLLSYS 4
+#define RP1DSI_NUM_CLOCKS 5
/* ---------------------------------------------------------------------- */
--- a/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dsi.c
+++ b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dsi.c
@@ -7,6 +7,7 @@
#include <linux/delay.h>
#include <linux/errno.h>
+#include <linux/math64.h>
#include <linux/platform_device.h>
#include <linux/rp1_platform.h>
#include "drm/drm_print.h"
@@ -1111,7 +1112,7 @@ static void dphy_transaction(struct rp1_
DSI_WRITE(DSI_PHY_TST_CTRL0, DPHY_CTRL0_PHY_TESTCLK_BITS);
}
-static uint8_t dphy_get_div(u32 refclk_khz, u32 vco_freq_khz, u32 *ptr_m, u32 *ptr_n)
+static u64 dphy_get_div(u32 refclk, u64 vco_freq, u32 *ptr_m, u32 *ptr_n)
{
/*
* See pg 77-78 of dphy databook
@@ -1124,19 +1125,23 @@ static uint8_t dphy_get_div(u32 refclk_k
* In practice, given a 50MHz reference clock, it can produce any
* multiple of 10MHz, 11.1111MHz, 12.5MHz, 14.286MHz or 16.667MHz
* with < 1% error for all frequencies above 495MHz.
+ *
+ * vco_freq should be set to the lane bit rate (not the MIPI clock
+ * which is half of this). These frequencies are now measured in Hz.
+ * They should fit within u32, but u64 is needed for calculations.
*/
- static const u32 REF_DIVN_MAX = 40000u;
- static const u32 REF_DIVN_MIN = 5000u;
- u32 best_n, best_m, best_err = 0x7fffffff;
- unsigned int n;
+ static const u32 REF_DIVN_MAX = 40000000;
+ static const u32 REF_DIVN_MIN = 5000000;
+ u32 n, best_n, best_m;
+ u64 best_err = vco_freq;
- for (n = 1 + refclk_khz / REF_DIVN_MAX; n * REF_DIVN_MIN <= refclk_khz && n < 100; ++n) {
- u32 half_m = (n * vco_freq_khz + refclk_khz) / (2 * refclk_khz);
+ for (n = 1 + refclk / REF_DIVN_MAX; n * REF_DIVN_MIN <= refclk && n < 100; ++n) {
+ u32 half_m = DIV_U64_ROUND_CLOSEST(n * vco_freq, 2 * refclk);
if (half_m < 150) {
- u32 f = (2 * half_m * refclk_khz) / n;
- u32 err = (f > vco_freq_khz) ? f - vco_freq_khz : vco_freq_khz - f;
+ u64 f = div_u64(mul_u32_u32(2 * half_m, refclk), n);
+ u64 err = (f > vco_freq) ? f - vco_freq : vco_freq - f;
if (err < best_err) {
best_n = n;
@@ -1148,12 +1153,12 @@ static uint8_t dphy_get_div(u32 refclk_k
}
}
- if (64 * best_err < vco_freq_khz) { /* tolerate small error */
- *ptr_n = best_n;
- *ptr_m = best_m;
- return 1;
- }
- return 0;
+ if (64 * best_err >= vco_freq)
+ return 0;
+
+ *ptr_n = best_n;
+ *ptr_m = best_m;
+ return div_u64(mul_u32_u32(best_m, refclk), best_n);
}
struct hsfreq_range {
@@ -1226,13 +1231,14 @@ static void dphy_set_hsfreqrange(struct
hsfreq_table[i].hsfreqrange << 1);
}
-static void dphy_configure_pll(struct rp1_dsi *dsi, u32 refclk_khz, u32 vco_freq_khz)
+static u32 dphy_configure_pll(struct rp1_dsi *dsi, u32 refclk, u32 vco_freq)
{
u32 m = 0;
u32 n = 0;
+ u32 actual_vco_freq = dphy_get_div(refclk, vco_freq, &m, &n);
- if (dphy_get_div(refclk_khz, vco_freq_khz, &m, &n)) {
- dphy_set_hsfreqrange(dsi, vco_freq_khz / 1000);
+ if (actual_vco_freq) {
+ dphy_set_hsfreqrange(dsi, actual_vco_freq / 1000000);
/* Program m,n from registers */
dphy_transaction(dsi, DPHY_PLL_DIV_CTRL_OFFSET, 0x30);
/* N (program N-1) */
@@ -1242,18 +1248,21 @@ static void dphy_configure_pll(struct rp
/* M[4:0] (program M-1) */
dphy_transaction(dsi, DPHY_PLL_LOOP_DIV_OFFSET, ((m - 1) & 0x1F));
drm_dbg_driver(dsi->drm,
- "DPHY: vco freq want %dkHz got %dkHz = %d * (%dkHz / %d), hsfreqrange = 0x%02x\r\n",
- vco_freq_khz, refclk_khz * m / n, m, refclk_khz,
- n, hsfreq_table[dsi->hsfreq_index].hsfreqrange);
+ "DPHY: vco freq want %uHz got %uHz = %d * (%uHz / %d), hsfreqrange = 0x%02x\n",
+ vco_freq, actual_vco_freq, m, refclk, n,
+ hsfreq_table[dsi->hsfreq_index].hsfreqrange);
} else {
- drm_info(dsi->drm,
- "rp1dsi: Error configuring DPHY PLL! %dkHz = %d * (%dkHz / %d)\r\n",
- vco_freq_khz, m, refclk_khz, n);
+ drm_warn(dsi->drm,
+ "rp1dsi: Error configuring DPHY PLL %uHz\n", vco_freq);
}
+
+ return actual_vco_freq;
}
-static void dphy_init_khz(struct rp1_dsi *dsi, u32 ref_freq, u32 vco_freq)
+static u32 dphy_init(struct rp1_dsi *dsi, u32 ref_freq, u32 vco_freq)
{
+ u32 actual_vco_freq;
+
/* Reset the PHY */
DSI_WRITE(DSI_PHYRSTZ, 0);
DSI_WRITE(DSI_PHY_TST_CTRL0, DPHY_CTRL0_PHY_TESTCLK_BITS);
@@ -1263,13 +1272,15 @@ static void dphy_init_khz(struct rp1_dsi
DSI_WRITE(DSI_PHY_TST_CTRL0, DPHY_CTRL0_PHY_TESTCLK_BITS);
udelay(1);
/* Since we are in DSI (not CSI2) mode here, start the PLL */
- dphy_configure_pll(dsi, ref_freq, vco_freq);
+ actual_vco_freq = dphy_configure_pll(dsi, ref_freq, vco_freq);
udelay(1);
/* Unreset */
DSI_WRITE(DSI_PHYRSTZ, DSI_PHYRSTZ_SHUTDOWNZ_BITS);
udelay(1);
DSI_WRITE(DSI_PHYRSTZ, (DSI_PHYRSTZ_SHUTDOWNZ_BITS | DSI_PHYRSTZ_RSTZ_BITS));
udelay(1); /* so we can see PLL coming up? */
+
+ return actual_vco_freq;
}
void rp1dsi_mipicfg_setup(struct rp1_dsi *dsi)
@@ -1290,23 +1301,30 @@ static unsigned long rp1dsi_refclk_freq(
return u;
}
-static void rp1dsi_dpiclk_start(struct rp1_dsi *dsi, unsigned int bpp, unsigned int lanes)
+static void rp1dsi_dpiclk_start(struct rp1_dsi *dsi, u32 byte_clock,
+ unsigned int bpp, unsigned int lanes)
{
- unsigned long u;
-
- if (dsi->clocks[RP1DSI_CLOCK_DPI]) {
- u = (dsi->clocks[RP1DSI_CLOCK_BYTE]) ?
- clk_get_rate(dsi->clocks[RP1DSI_CLOCK_BYTE]) : 0;
- drm_info(dsi->drm,
- "rp1dsi: Nominal byte clock %lu; scale by %u/%u",
- u, 4 * lanes, (bpp >> 1));
- if (u < 1 || u >= (1ul << 28))
- u = 72000000ul; /* default DUMMY frequency for byteclock */
+ /* Dummy clk_set_rate() to declare the actual DSI byte-clock rate */
+ clk_set_rate(dsi->clocks[RP1DSI_CLOCK_BYTE], byte_clock);
+ /*
+ * Prefer the DSI byte-clock source where possible, so that DSI and DPI
+ * clocks will be in an exact ratio and downstream devices can recover
+ * perfect timings. But when DPI clock is faster, fall back on PLL_SYS.
+ * To defeat rounding errors, specify explicitly which source to use.
+ */
+ if (bpp >= 8 * lanes)
clk_set_parent(dsi->clocks[RP1DSI_CLOCK_DPI], dsi->clocks[RP1DSI_CLOCK_BYTE]);
- clk_set_rate(dsi->clocks[RP1DSI_CLOCK_DPI], (4 * lanes * u) / (bpp >> 1));
- clk_prepare_enable(dsi->clocks[RP1DSI_CLOCK_DPI]);
- }
+ else if (dsi->clocks[RP1DSI_CLOCK_PLLSYS])
+ clk_set_parent(dsi->clocks[RP1DSI_CLOCK_DPI], dsi->clocks[RP1DSI_CLOCK_PLLSYS]);
+
+ clk_set_rate(dsi->clocks[RP1DSI_CLOCK_DPI], (4 * lanes * byte_clock) / (bpp >> 1));
+ clk_prepare_enable(dsi->clocks[RP1DSI_CLOCK_DPI]);
+ drm_info(dsi->drm,
+ "rp1dsi: Nominal Byte clock %u DPI clock %lu (parent rate %lu)",
+ byte_clock,
+ clk_get_rate(dsi->clocks[RP1DSI_CLOCK_DPI]),
+ clk_get_rate(clk_get_parent(dsi->clocks[RP1DSI_CLOCK_DPI])));
}
static void rp1dsi_dpiclk_stop(struct rp1_dsi *dsi)
@@ -1336,18 +1354,21 @@ static u32 get_colorcode(enum mipi_dsi_p
return 0x005;
}
-/* Maximum frequency for LP escape clock (20MHz), and some magic numbers */
-#define RP1DSI_ESC_CLK_KHZ 20000
-#define RP1DSI_TO_CLK_DIV 5
-#define RP1DSI_HSTX_TO_MIN 0x200
-#define RP1DSI_LPRX_TO_VAL 0x400
+/* Frequency limits for DPI, HS and LP clocks, and some magic numbers */
+#define RP1DSI_DPI_MAX_KHZ 200000
+#define RP1DSI_BYTE_CLK_MIN 10000000
+#define RP1DSI_BYTE_CLK_MAX 187500000
+#define RP1DSI_ESC_CLK_MAX 20000000
+#define RP1DSI_TO_CLK_DIV 0x50
+#define RP1DSI_LPRX_TO_VAL 0x40
#define RP1DSI_BTA_TO_VAL 0xd00
void rp1dsi_dsi_setup(struct rp1_dsi *dsi, struct drm_display_mode const *mode)
{
u32 timeout, mask, vid_mode_cfg;
- int lane_kbps;
unsigned int bpp = mipi_dsi_pixel_format_to_bpp(dsi->display_format);
+ u32 byte_clock = clamp((bpp * 125 * min(mode->clock, RP1DSI_DPI_MAX_KHZ)) / dsi->lanes,
+ RP1DSI_BYTE_CLK_MIN, RP1DSI_BYTE_CLK_MAX);
DSI_WRITE(DSI_PHY_IF_CFG, dsi->lanes - 1);
DSI_WRITE(DSI_DPI_CFG_POL, 0);
@@ -1360,6 +1381,8 @@ void rp1dsi_dsi_setup(struct rp1_dsi *ds
vid_mode_cfg = 0xbf00;
if (!(dsi->display_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE))
vid_mode_cfg |= 0x01;
+ else if (8 * dsi->lanes > bpp)
+ vid_mode_cfg &= ~0x400; /* PULSE && inexact DPICLK => fix HBP time */
if (dsi->display_flags & MIPI_DSI_MODE_VIDEO_BURST)
vid_mode_cfg |= 0x02;
DSI_WRITE(DSI_VID_MODE_CFG, vid_mode_cfg);
@@ -1369,15 +1392,14 @@ void rp1dsi_dsi_setup(struct rp1_dsi *ds
DSI_WRITE(DSI_MODE_CFG, 1);
/* Set timeouts and clock dividers */
- DSI_WRITE(DSI_TO_CNT_CFG,
- (max((bpp * mode->htotal) / (7 * RP1DSI_TO_CLK_DIV * dsi->lanes),
- RP1DSI_HSTX_TO_MIN) << 16) |
- RP1DSI_LPRX_TO_VAL);
+ timeout = (bpp * mode->htotal * mode->vdisplay) / (7 * RP1DSI_TO_CLK_DIV * dsi->lanes);
+ if (timeout > 0xFFFFu)
+ timeout = 0;
+ DSI_WRITE(DSI_TO_CNT_CFG, (timeout << 16) | RP1DSI_LPRX_TO_VAL);
DSI_WRITE(DSI_BTA_TO_CNT, RP1DSI_BTA_TO_VAL);
- lane_kbps = (bpp * mode->clock) / dsi->lanes;
DSI_WRITE(DSI_CLKMGR_CFG,
(RP1DSI_TO_CLK_DIV << 8) |
- max(2, lane_kbps / (8 * RP1DSI_ESC_CLK_KHZ) + 1));
+ max(2u, 1u + byte_clock / RP1DSI_ESC_CLK_MAX));
/* Configure video timings */
DSI_WRITE(DSI_VID_PKT_SIZE, mode->hdisplay);
@@ -1394,7 +1416,7 @@ void rp1dsi_dsi_setup(struct rp1_dsi *ds
DSI_WRITE(DSI_VID_VACTIVE_LINES, mode->vdisplay);
/* Init PHY */
- dphy_init_khz(dsi, rp1dsi_refclk_freq(dsi) / 1000, lane_kbps);
+ byte_clock = dphy_init(dsi, rp1dsi_refclk_freq(dsi), 8 * byte_clock) >> 3;
DSI_WRITE(DSI_PHY_TMR_LPCLK_CFG,
(hsfreq_table[dsi->hsfreq_index].clk_lp2hs << DSI_PHY_TMR_LP2HS_LSB) |
@@ -1418,7 +1440,7 @@ void rp1dsi_dsi_setup(struct rp1_dsi *ds
DSI_WRITE(DSI_PWR_UP, 0x1); /* power up */
/* Now it should be safe to start the external DPI clock divider */
- rp1dsi_dpiclk_start(dsi, bpp, dsi->lanes);
+ rp1dsi_dpiclk_start(dsi, byte_clock, bpp, dsi->lanes);
/* Wait for all lane(s) to be in Stopstate */
mask = (1 << 4);

View File

@ -0,0 +1,92 @@
From 4de4f56af7d803fa7dd9ffe42d4719b428d73e6c Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
Date: Wed, 17 Jul 2024 17:31:58 +0100
Subject: [PATCH 1181/1215] arm64: dts: Add cm5l files
CM5 Lite DTBs require minor changes compared to the "heavy" variants.
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
---
arch/arm64/boot/dts/broadcom/Makefile | 2 ++
.../dts/broadcom/bcm2712-rpi-cm5l-cm4io.dts | 20 ++++++++++++++++
.../dts/broadcom/bcm2712-rpi-cm5l-cm5io.dts | 10 ++++++++
.../boot/dts/broadcom/bcm2712-rpi-cm5l.dtsi | 24 +++++++++++++++++++
4 files changed, 56 insertions(+)
create mode 100644 arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l-cm4io.dts
create mode 100644 arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l-cm5io.dts
create mode 100644 arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l.dtsi
--- a/arch/arm64/boot/dts/broadcom/Makefile
+++ b/arch/arm64/boot/dts/broadcom/Makefile
@@ -24,6 +24,8 @@ dtb-$(CONFIG_ARCH_BCM2835) += bcm2712-rp
dtb-$(CONFIG_ARCH_BCM2835) += bcm2712d0-rpi-5-b.dtb
dtb-$(CONFIG_ARCH_BCM2835) += bcm2712-rpi-cm5-cm5io.dtb
dtb-$(CONFIG_ARCH_BCM2835) += bcm2712-rpi-cm5-cm4io.dtb
+dtb-$(CONFIG_ARCH_BCM2835) += bcm2712-rpi-cm5l-cm5io.dtb
+dtb-$(CONFIG_ARCH_BCM2835) += bcm2712-rpi-cm5l-cm4io.dtb
subdir-y += bcmbca
subdir-y += northstar2
--- /dev/null
+++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l-cm4io.dts
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+
+#include "bcm2712-rpi-cm5l.dtsi"
+
+// The RP1 USB3 interfaces are not usable on CM4IO
+
+&rp1_usb0 {
+ status = "disabled";
+};
+
+&rp1_usb1 {
+ status = "disabled";
+};
+
+/ {
+ __overrides__ {
+ i2c_csi_dsi = <&i2c_csi_dsi>, "status";
+ };
+};
--- /dev/null
+++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l-cm5io.dts
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+
+#include "bcm2712-rpi-cm5l.dtsi"
+
+/ {
+ __overrides__ {
+ i2c_csi_dsi = <&i2c_csi_dsi>, "status";
+ };
+};
--- /dev/null
+++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l.dtsi
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+
+#include "bcm2712-rpi-cm5.dtsi"
+
+/ {
+ __overrides__ {
+ i2c_csi_dsi = <&i2c_csi_dsi>, "status";
+ };
+};
+
+&sd_io_1v8_reg {
+ compatible = "regulator-gpio";
+ regulator-max-microvolt = <3300000>;
+ regulator-settling-time-us = <5000>;
+ gpios = <&gio_aon 3 GPIO_ACTIVE_HIGH>;
+ states = <1800000 0x1
+ 3300000 0x0>;
+};
+
+&sdio1 {
+ /delete-property/ mmc-hs400-1_8v;
+ /delete-property/ mmc-hs400-enhanced-strobe;
+};

View File

@ -0,0 +1,408 @@
From e1c56acf3355cd539447511fdc1b886e5eb5cca3 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
Date: Thu, 2 May 2024 16:57:31 +0100
Subject: [PATCH 1182/1215] dts: bcm2712: Dedup the aliases and overrides
Move the aliases and overrrides shared by Pi 5 and CM5 into
bcm2712-rpi.dtsi.
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
---
.../boot/dts/broadcom/bcm2712-rpi-5-b.dts | 115 -----------------
.../boot/dts/broadcom/bcm2712-rpi-cm5.dtsi | 114 -----------------
arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi | 117 +++++++++++++++++-
3 files changed, 113 insertions(+), 233 deletions(-)
--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts
+++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts
@@ -746,122 +746,7 @@ spi10_cs_pins: &spi10_cs_gpio1 {};
};
/ {
- aliases: aliases {
- blconfig = &blconfig;
- blpubkey = &blpubkey;
- bluetooth = &bluetooth;
- console = &uart10;
- ethernet0 = &rp1_eth;
- wifi0 = &wifi;
- fb = &fb;
- mailbox = &mailbox;
- mmc0 = &sdio1;
- uart0 = &uart0;
- uart1 = &uart1;
- uart2 = &uart2;
- uart3 = &uart3;
- uart4 = &uart4;
- uart10 = &uart10;
- serial0 = &uart0;
- serial1 = &uart1;
- serial2 = &uart2;
- serial3 = &uart3;
- serial4 = &uart4;
- serial10 = &uart10;
- i2c = &i2c_arm;
- i2c0 = &i2c0;
- i2c1 = &i2c1;
- i2c2 = &i2c2;
- i2c3 = &i2c3;
- i2c4 = &i2c4;
- i2c5 = &i2c5;
- i2c6 = &i2c6;
- i2c10 = &i2c_rp1boot;
- // Bit-bashed i2c_gpios start at 10
- spi0 = &spi0;
- spi1 = &spi1;
- spi2 = &spi2;
- spi3 = &spi3;
- spi4 = &spi4;
- spi5 = &spi5;
- spi10 = &spi10;
- gpio0 = &gpio;
- gpio1 = &gio;
- gpio2 = &gio_aon;
- gpio3 = &pinctrl;
- gpio4 = &pinctrl_aon;
- usb0 = &rp1_usb0;
- usb1 = &rp1_usb1;
- drm-dsi1 = &dsi0;
- drm-dsi2 = &dsi1;
- };
-
__overrides__ {
- bdaddr = <&bluetooth>, "local-bd-address[";
- button_debounce = <&pwr_key>, "debounce-interval:0";
- cooling_fan = <&fan>, "status", <&rp1_pwm1>, "status";
- uart0_console = <&uart0>,"status", <&aliases>, "console=",&uart0;
- i2c0 = <&i2c0>, "status";
- i2c1 = <&i2c1>, "status";
- i2c = <&i2c1>, "status";
- i2c_arm = <&i2c_arm>, "status";
- i2c_vc = <&i2c_vc>, "status";
- i2c_csi_dsi = <&i2c_csi_dsi>, "status";
- i2c_csi_dsi0 = <&i2c_csi_dsi0>, "status";
- i2c_csi_dsi1 = <&i2c_csi_dsi1>, "status";
- i2c0_baudrate = <&i2c0>, "clock-frequency:0";
- i2c1_baudrate = <&i2c1>, "clock-frequency:0";
- i2c_baudrate = <&i2c_arm>, "clock-frequency:0";
- i2c_arm_baudrate = <&i2c_arm>, "clock-frequency:0";
- i2c_vc_baudrate = <&i2c_vc>, "clock-frequency:0";
- krnbt = <&bluetooth>, "status";
- nvme = <&pciex1>, "status";
- pciex1 = <&pciex1>, "status";
- pciex1_gen = <&pciex1> , "max-link-speed:0";
- pciex1_no_l0s = <&pciex1>, "aspm-no-l0s?";
- pciex1_tperst_clk_ms = <&pciex1>, "brcm,tperst-clk-ms:0";
- pcie_tperst_clk_ms = <&pciex1>, "brcm,tperst-clk-ms:0";
- random = <&random>, "status";
- rtc = <&rpi_rtc>, "status";
- rtc_bbat_vchg = <&rpi_rtc>, "trickle-charge-microvolt:0";
sd_cqe = <&sdio1>, "supports-cqe?";
- spi = <&spi0>, "status";
- suspend = <&pwr_key>, "linux,code:0=205";
- uart0 = <&uart0>, "status";
- wifiaddr = <&wifi>, "local-mac-address[";
-
- act_led_gpio = <&led_act>,"gpios:4",<&led_act>,"gpios:0=",<&gpio>;
- act_led_activelow = <&led_act>,"gpios:8";
- act_led_trigger = <&led_act>, "linux,default-trigger";
- pwr_led_gpio = <&led_pwr>,"gpios:4";
- pwr_led_activelow = <&led_pwr>, "gpios:8";
- pwr_led_trigger = <&led_pwr>, "linux,default-trigger";
- eth_led0 = <&phy1>,"led-modes:0";
- eth_led1 = <&phy1>,"led-modes:4";
- drm_fb0_rp1_dsi0 = <&aliases>, "drm-fb0=",&dsi0;
- drm_fb0_rp1_dsi1 = <&aliases>, "drm-fb0=",&dsi1;
- drm_fb0_rp1_dpi = <&aliases>, "drm-fb0=",&dpi;
- drm_fb0_vc4 = <&aliases>, "drm-fb0=",&vc4;
- drm_fb1_rp1_dsi0 = <&aliases>, "drm-fb1=",&dsi0;
- drm_fb1_rp1_dsi1 = <&aliases>, "drm-fb1=",&dsi1;
- drm_fb1_rp1_dpi = <&aliases>, "drm-fb1=",&dpi;
- drm_fb1_vc4 = <&aliases>, "drm-fb1=",&vc4;
- drm_fb2_rp1_dsi0 = <&aliases>, "drm-fb2=",&dsi0;
- drm_fb2_rp1_dsi1 = <&aliases>, "drm-fb2=",&dsi1;
- drm_fb2_rp1_dpi = <&aliases>, "drm-fb2=",&dpi;
- drm_fb2_vc4 = <&aliases>, "drm-fb2=",&vc4;
-
- fan_temp0 = <&cpu_tepid>,"temperature:0";
- fan_temp1 = <&cpu_warm>,"temperature:0";
- fan_temp2 = <&cpu_hot>,"temperature:0";
- fan_temp3 = <&cpu_vhot>,"temperature:0";
- fan_temp0_hyst = <&cpu_tepid>,"hysteresis:0";
- fan_temp1_hyst = <&cpu_warm>,"hysteresis:0";
- fan_temp2_hyst = <&cpu_hot>,"hysteresis:0";
- fan_temp3_hyst = <&cpu_vhot>,"hysteresis:0";
- fan_temp0_speed = <&fan>, "cooling-levels:4";
- fan_temp1_speed = <&fan>, "cooling-levels:8";
- fan_temp2_speed = <&fan>, "cooling-levels:12";
- fan_temp3_speed = <&fan>, "cooling-levels:16";
};
};
--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi
+++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi
@@ -753,108 +753,7 @@ spi10_cs_pins: &spi10_cs_gpio1 {};
};
/ {
- aliases: aliases {
- blconfig = &blconfig;
- blpubkey = &blpubkey;
- bluetooth = &bluetooth;
- console = &uart10;
- ethernet0 = &rp1_eth;
- wifi0 = &wifi;
- fb = &fb;
- mailbox = &mailbox;
- mmc0 = &sdio1;
- uart0 = &uart0;
- uart1 = &uart1;
- uart2 = &uart2;
- uart3 = &uart3;
- uart4 = &uart4;
- uart10 = &uart10;
- serial0 = &uart0;
- serial1 = &uart1;
- serial2 = &uart2;
- serial3 = &uart3;
- serial4 = &uart4;
- serial10 = &uart10;
- i2c = &i2c_arm;
- i2c0 = &i2c0;
- i2c1 = &i2c1;
- i2c2 = &i2c2;
- i2c3 = &i2c3;
- i2c4 = &i2c4;
- i2c5 = &i2c5;
- i2c6 = &i2c6;
- i2c10 = &i2c_rp1boot;
- // Bit-bashed i2c_gpios start at 10
- spi0 = &spi0;
- spi1 = &spi1;
- spi2 = &spi2;
- spi3 = &spi3;
- spi4 = &spi4;
- spi5 = &spi5;
- spi10 = &spi10;
- gpio0 = &gpio;
- gpio1 = &gio;
- gpio2 = &gio_aon;
- gpio3 = &pinctrl;
- gpio4 = &pinctrl_aon;
- usb0 = &rp1_usb0;
- usb1 = &rp1_usb1;
- drm-dsi1 = &dsi0;
- drm-dsi2 = &dsi1;
- };
-
__overrides__ {
- bdaddr = <&bluetooth>, "local-bd-address[";
- button_debounce = <&pwr_key>, "debounce-interval:0";
- cooling_fan = <&fan>, "status", <&rp1_pwm1>, "status";
- uart0_console = <&uart0>,"status", <&aliases>, "console=",&uart0;
- i2c0 = <&i2c0>, "status";
- i2c1 = <&i2c1>, "status";
- i2c = <&i2c1>, "status";
- i2c_arm = <&i2c_arm>, "status";
- i2c_vc = <&i2c_vc>, "status";
- i2c_csi_dsi = <&i2c_csi_dsi>, "status";
- i2c_csi_dsi0 = <&i2c_csi_dsi0>, "status";
- i2c_csi_dsi1 = <&i2c_csi_dsi1>, "status";
- i2c0_baudrate = <&i2c0>, "clock-frequency:0";
- i2c1_baudrate = <&i2c1>, "clock-frequency:0";
- i2c_baudrate = <&i2c_arm>, "clock-frequency:0";
- i2c_arm_baudrate = <&i2c_arm>, "clock-frequency:0";
- i2c_vc_baudrate = <&i2c_vc>, "clock-frequency:0";
- krnbt = <&bluetooth>, "status";
- nvme = <&pciex1>, "status";
- pciex1 = <&pciex1>, "status";
- pciex1_gen = <&pciex1> , "max-link-speed:0";
- pciex1_no_l0s = <&pciex1>, "aspm-no-l0s?";
- pciex1_tperst_clk_ms = <&pciex1>, "brcm,tperst-clk-ms:0";
- pcie_tperst_clk_ms = <&pciex1>, "brcm,tperst-clk-ms:0";
- random = <&random>, "status";
- rtc = <&rpi_rtc>, "status";
- rtc_bbat_vchg = <&rpi_rtc>, "trickle-charge-microvolt:0";
- spi = <&spi0>, "status";
- suspend = <&pwr_key>, "linux,code:0=205";
- uart0 = <&uart0>, "status";
- wifiaddr = <&wifi>, "local-mac-address[";
-
- act_led_activelow = <&led_act>, "active-low?";
- act_led_trigger = <&led_act>, "linux,default-trigger";
- pwr_led_activelow = <&led_pwr>, "gpios:8";
- pwr_led_trigger = <&led_pwr>, "linux,default-trigger";
- eth_led0 = <&phy1>,"led-modes:0";
- eth_led1 = <&phy1>,"led-modes:4";
- drm_fb0_rp1_dsi0 = <&aliases>, "drm-fb0=",&dsi0;
- drm_fb0_rp1_dsi1 = <&aliases>, "drm-fb0=",&dsi1;
- drm_fb0_rp1_dpi = <&aliases>, "drm-fb0=",&dpi;
- drm_fb0_vc4 = <&aliases>, "drm-fb0=",&vc4;
- drm_fb1_rp1_dsi0 = <&aliases>, "drm-fb1=",&dsi0;
- drm_fb1_rp1_dsi1 = <&aliases>, "drm-fb1=",&dsi1;
- drm_fb1_rp1_dpi = <&aliases>, "drm-fb1=",&dpi;
- drm_fb1_vc4 = <&aliases>, "drm-fb1=",&vc4;
- drm_fb2_rp1_dsi0 = <&aliases>, "drm-fb2=",&dsi0;
- drm_fb2_rp1_dsi1 = <&aliases>, "drm-fb2=",&dsi1;
- drm_fb2_rp1_dpi = <&aliases>, "drm-fb2=",&dpi;
- drm_fb2_vc4 = <&aliases>, "drm-fb2=",&vc4;
-
ant1 = <&ant1>,"output-high?=on",
<&ant1>, "output-low?=off",
<&ant2>, "output-high?=off",
@@ -867,18 +766,5 @@ spi10_cs_pins: &spi10_cs_gpio1 {};
<&ant1>, "output-low?=on",
<&ant2>, "output-high?=off",
<&ant2>, "output-low?=on";
-
- fan_temp0 = <&cpu_tepid>,"temperature:0";
- fan_temp1 = <&cpu_warm>,"temperature:0";
- fan_temp2 = <&cpu_hot>,"temperature:0";
- fan_temp3 = <&cpu_vhot>,"temperature:0";
- fan_temp0_hyst = <&cpu_tepid>,"hysteresis:0";
- fan_temp1_hyst = <&cpu_warm>,"hysteresis:0";
- fan_temp2_hyst = <&cpu_hot>,"hysteresis:0";
- fan_temp3_hyst = <&cpu_vhot>,"hysteresis:0";
- fan_temp0_speed = <&fan>, "cooling-levels:4";
- fan_temp1_speed = <&fan>, "cooling-levels:8";
- fan_temp2_speed = <&fan>, "cooling-levels:12";
- fan_temp3_speed = <&fan>, "cooling-levels:16";
};
};
--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi
+++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi
@@ -98,14 +98,124 @@
};
/ {
+ aliases: aliases {
+ blconfig = &blconfig;
+ blpubkey = &blpubkey;
+ bluetooth = &bluetooth;
+ console = &uart10;
+ drm-dsi1 = &dsi0;
+ drm-dsi2 = &dsi1;
+ ethernet0 = &rp1_eth;
+ fb = &fb;
+ gpio0 = &gpio;
+ gpio1 = &gio;
+ gpio2 = &gio_aon;
+ gpio3 = &pinctrl;
+ gpio4 = &pinctrl_aon;
+ i2c = &i2c_arm;
+ i2c0 = &i2c0;
+ i2c1 = &i2c1;
+ i2c10 = &i2c_rp1boot;
+ i2c2 = &i2c2;
+ i2c3 = &i2c3;
+ i2c4 = &i2c4;
+ i2c5 = &i2c5;
+ i2c6 = &i2c6;
+ mailbox = &mailbox;
+ mmc0 = &sdio1;
+ serial0 = &uart0;
+ serial1 = &uart1;
+ serial10 = &uart10;
+ serial2 = &uart2;
+ serial3 = &uart3;
+ serial4 = &uart4;
+ spi0 = &spi0;
+ spi1 = &spi1;
+ spi10 = &spi10;
+ spi2 = &spi2;
+ spi3 = &spi3;
+ spi4 = &spi4;
+ spi5 = &spi5;
+ uart0 = &uart0;
+ uart1 = &uart1;
+ uart10 = &uart10;
+ uart2 = &uart2;
+ uart3 = &uart3;
+ uart4 = &uart4;
+ usb0 = &rp1_usb0;
+ usb1 = &rp1_usb1;
+ wifi0 = &wifi;
+ };
+
__overrides__ {
- arm_freq;
+ act_led_gpio = <&led_act>,"gpios:4",<&led_act>,"gpios:0=",<&gpio>;
+ act_led_activelow = <&led_act>, "gpios:8";
+ act_led_trigger = <&led_act>, "linux,default-trigger";
axiperf = <&axiperf>,"status";
-
+ bdaddr = <&bluetooth>, "local-bd-address[";
+ button_debounce = <&pwr_key>, "debounce-interval:0";
+ cooling_fan = <&fan>, "status", <&rp1_pwm1>, "status";
+ drm_fb0_rp1_dpi = <&aliases>, "drm-fb0=",&dpi;
+ drm_fb0_rp1_dsi0 = <&aliases>, "drm-fb0=",&dsi0;
+ drm_fb0_rp1_dsi1 = <&aliases>, "drm-fb0=",&dsi1;
+ drm_fb0_vc4 = <&aliases>, "drm-fb0=",&vc4;
+ drm_fb1_rp1_dpi = <&aliases>, "drm-fb1=",&dpi;
+ drm_fb1_rp1_dsi0 = <&aliases>, "drm-fb1=",&dsi0;
+ drm_fb1_rp1_dsi1 = <&aliases>, "drm-fb1=",&dsi1;
+ drm_fb1_vc4 = <&aliases>, "drm-fb1=",&vc4;
+ drm_fb2_rp1_dpi = <&aliases>, "drm-fb2=",&dpi;
+ drm_fb2_rp1_dsi0 = <&aliases>, "drm-fb2=",&dsi0;
+ drm_fb2_rp1_dsi1 = <&aliases>, "drm-fb2=",&dsi1;
+ drm_fb2_vc4 = <&aliases>, "drm-fb2=",&vc4;
+ eth_led0 = <&phy1>,"led-modes:0";
+ eth_led1 = <&phy1>,"led-modes:4";
+ fan_temp0 = <&cpu_tepid>,"temperature:0";
+ fan_temp0_hyst = <&cpu_tepid>,"hysteresis:0";
+ fan_temp0_speed = <&fan>, "cooling-levels:4";
+ fan_temp1 = <&cpu_warm>,"temperature:0";
+ fan_temp1_hyst = <&cpu_warm>,"hysteresis:0";
+ fan_temp1_speed = <&fan>, "cooling-levels:8";
+ fan_temp2 = <&cpu_hot>,"temperature:0";
+ fan_temp2_hyst = <&cpu_hot>,"hysteresis:0";
+ fan_temp2_speed = <&fan>, "cooling-levels:12";
+ fan_temp3 = <&cpu_vhot>,"temperature:0";
+ fan_temp3_hyst = <&cpu_vhot>,"hysteresis:0";
+ fan_temp3_speed = <&fan>, "cooling-levels:16";
+ i2c = <&i2c1>, "status";
+ i2c_arm = <&i2c_arm>, "status";
+ i2c_arm_baudrate = <&i2c_arm>, "clock-frequency:0";
+ i2c_baudrate = <&i2c_arm>, "clock-frequency:0";
+ i2c_csi_dsi = <&i2c_csi_dsi>, "status";
+ i2c_csi_dsi0 = <&i2c_csi_dsi0>, "status";
+ i2c_csi_dsi1 = <&i2c_csi_dsi1>, "status";
+ i2c_vc = <&i2c_vc>, "status";
+ i2c_vc_baudrate = <&i2c_vc>, "clock-frequency:0";
+ i2c0 = <&i2c0>, "status";
+ i2c0_baudrate = <&i2c0>, "clock-frequency:0";
+ i2c1 = <&i2c1>, "status";
+ i2c1_baudrate = <&i2c1>, "clock-frequency:0";
+ krnbt = <&bluetooth>, "status";
+ nvme = <&pciex1>, "status";
nvmem_cust_rw = <&nvmem_cust>,"rw?";
- nvmem_priv_rw = <&nvmem_priv>,"rw?";
nvmem_mac_rw = <&nvmem_mac>,"rw?";
+ nvmem_priv_rw = <&nvmem_priv>,"rw?";
+ pcie_tperst_clk_ms = <&pciex1>, "brcm,tperst-clk-ms:0";
+ pciex1 = <&pciex1>, "status";
+ pciex1_gen = <&pciex1> , "max-link-speed:0";
+ pciex1_no_l0s = <&pciex1>, "aspm-no-l0s?";
+ pciex1_tperst_clk_ms = <&pciex1>, "brcm,tperst-clk-ms:0";
+ pwr_led_gpio = <&led_pwr>, "gpios:4";
+ pwr_led_activelow = <&led_pwr>, "gpios:8";
+ pwr_led_trigger = <&led_pwr>, "linux,default-trigger";
+ random = <&random>, "status";
+ rtc = <&rpi_rtc>, "status";
+ rtc_bbat_vchg = <&rpi_rtc>, "trickle-charge-microvolt:0";
+ spi = <&spi0>, "status";
strict_gpiod = <&chosen>, "bootargs=pinctrl_rp1.persist_gpio_outputs=n";
+ suspend = <&pwr_key>, "linux,code:0=205";
+ uart0 = <&uart0>, "status";
+ uart0_console = <&uart0>,"status", <&aliases>, "console=",&uart0;
+ wifiaddr = <&wifi>, "local-mac-address[";
cam0_reg = <&cam0_reg>,"status";
cam0_reg_gpio = <&cam0_reg>,"gpio:4",
@@ -113,7 +223,6 @@
cam1_reg = <&cam1_reg>,"status";
cam1_reg_gpio = <&cam1_reg>,"gpio:4",
<&cam1_reg>,"gpio:0=", <&gpio>;
-
};
};

View File

@ -0,0 +1,24 @@
From ad110e5ff36de6096e1b9d7e0fe125326f45ed7d Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
Date: Fri, 19 Jul 2024 13:18:47 +0100
Subject: [PATCH 1183/1215] arm64: dts: Give cm5l its own model name
The bootloader patches the DT with the correct model string, but it
is better not to rely on that by setting it from the start.
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
---
arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l.dtsi | 2 ++
1 file changed, 2 insertions(+)
--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l.dtsi
+++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l.dtsi
@@ -4,6 +4,8 @@
#include "bcm2712-rpi-cm5.dtsi"
/ {
+ model = "Raspberry Pi Compute Module 5 Lite";
+
__overrides__ {
i2c_csi_dsi = <&i2c_csi_dsi>, "status";
};

View File

@ -0,0 +1,288 @@
From d24229dcef58e0162780ceffa02eb5f6a01b9a4d Mon Sep 17 00:00:00 2001
From: Jonathan Bell <jonathan@raspberrypi.com>
Date: Tue, 16 Jul 2024 16:47:08 +0100
Subject: [PATCH 1185/1215] pinctrl: rp1: jump through hoops to avoid PCIe
latency issues
Automatic link power saving plus the ability of a root complex to buffer
pending posted write transfers (and consider them complete before being
transmitted on the wire) causes compression of updates to GPIO state.
The large bandwidth of a Gen 2 x4 link means the writes toggle state
inside RP1 as fast as it can go (~20MHz), which is bad for applications
wanting bitbash with at least a few microseconds of delay between
updates.
By tailoring IO access patterns to a special Root Complex register,
writes to GPIOs can be stalled until the link wakes - meaning all writes
end up with a reasonably consistent minimum pacing (~200ns).
Additionally, write barriers have no effect other than to arbitrarily
delay some writes by a small, variable amount - so remove the vast
majority of these in areas that could be hot-paths.
Although the IO memory is mapped with Device strongly-ordered semantics,
this doesn't prevent the splitter inside BCM2712 from letting an MMIO
read request to a GPIO register get ahead of the pacing writes to the
Root Complex register. So each pin state read must flush writes out to
the Outer-Shareable domain.
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
---
drivers/pinctrl/pinctrl-rp1.c | 120 +++++++++++++++++++++++++++++-----
1 file changed, 105 insertions(+), 15 deletions(-)
--- a/drivers/pinctrl/pinctrl-rp1.c
+++ b/drivers/pinctrl/pinctrl-rp1.c
@@ -197,6 +197,7 @@ struct rp1_pin_info {
void __iomem *inte;
void __iomem *ints;
void __iomem *pad;
+ void __iomem *dummy;
};
enum funcs {
@@ -276,6 +277,7 @@ struct rp1_pinctrl {
void __iomem *gpio_base;
void __iomem *rio_base;
void __iomem *pads_base;
+ void __iomem *dummy_base;
int irq[RP1_NUM_BANKS];
struct rp1_pin_info pins[RP1_NUM_GPIOS];
@@ -577,6 +579,42 @@ static bool persist_gpio_outputs = true;
module_param(persist_gpio_outputs, bool, 0644);
MODULE_PARM_DESC(persist_gpio_outputs, "Enable GPIO_OUT persistence when pin is freed");
+static bool pace_pin_updates = true;
+module_param(pace_pin_updates, bool, 0644);
+MODULE_PARM_DESC(pace_pin_updates, "Update pin states with guaranteed monotonicity if PCIe ASPM is enabled");
+
+static inline void rp1_pin_writel(u32 val, void __iomem *dummy, void __iomem *reg)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ /*
+ * Issuing 6 pipelined writes to the RC's Slot Control register will stall the
+ * peripheral bus inside 2712 if the link is in L1. This acts as a lightweight
+ * "fence" operation preventing back-to-back writes arriving at RP1 on a wake.
+ */
+ if (dummy) {
+ writel_relaxed(0, dummy);
+ writel_relaxed(0, dummy);
+ writel_relaxed(0, dummy);
+ writel_relaxed(0, dummy);
+ writel_relaxed(0, dummy);
+ writel_relaxed(0, dummy);
+ }
+ writel_relaxed(val, reg);
+ local_irq_restore(flags);
+}
+
+static inline u32 rp1_pin_readl(const void __iomem *ioaddr)
+{
+ /*
+ * Prior posted writes may not yet have been emitted by the CPU - do a store-flush
+ * before reading GPIO state, as this will serialise writes versus the next issued read.
+ */
+ __dma_wmb();
+ return readl(ioaddr);
+}
+
static int rp1_pinconf_set(struct pinctrl_dev *pctldev,
unsigned int offset, unsigned long *configs,
unsigned int num_configs);
@@ -603,12 +641,12 @@ static struct rp1_pin_info *rp1_get_pin_
static void rp1_pad_update(struct rp1_pin_info *pin, u32 clr, u32 set)
{
- u32 padctrl = readl(pin->pad);
+ u32 padctrl = rp1_pin_readl(pin->pad);
padctrl &= ~clr;
padctrl |= set;
- writel(padctrl, pin->pad);
+ rp1_pin_writel(padctrl, pin->dummy, pin->pad);
}
static void rp1_input_enable(struct rp1_pin_info *pin, int value)
@@ -625,7 +663,7 @@ static void rp1_output_enable(struct rp1
static u32 rp1_get_fsel(struct rp1_pin_info *pin)
{
- u32 ctrl = readl(pin->gpio + RP1_GPIO_CTRL);
+ u32 ctrl = rp1_pin_readl(pin->gpio + RP1_GPIO_CTRL);
u32 oeover = FLD_GET(ctrl, RP1_GPIO_CTRL_OEOVER);
u32 fsel = FLD_GET(ctrl, RP1_GPIO_CTRL_FUNCSEL);
@@ -637,7 +675,7 @@ static u32 rp1_get_fsel(struct rp1_pin_i
static void rp1_set_fsel(struct rp1_pin_info *pin, u32 fsel)
{
- u32 ctrl = readl(pin->gpio + RP1_GPIO_CTRL);
+ u32 ctrl = rp1_pin_readl(pin->gpio + RP1_GPIO_CTRL);
if (fsel >= RP1_FSEL_COUNT)
fsel = RP1_FSEL_NONE_HW;
@@ -652,12 +690,12 @@ static void rp1_set_fsel(struct rp1_pin_
FLD_SET(ctrl, RP1_GPIO_CTRL_OEOVER, RP1_OEOVER_PERI);
}
FLD_SET(ctrl, RP1_GPIO_CTRL_FUNCSEL, fsel);
- writel(ctrl, pin->gpio + RP1_GPIO_CTRL);
+ rp1_pin_writel(ctrl, pin->dummy, pin->gpio + RP1_GPIO_CTRL);
}
static int rp1_get_dir(struct rp1_pin_info *pin)
{
- return !(readl(pin->rio + RP1_RIO_OE) & (1 << pin->offset)) ?
+ return !(rp1_pin_readl(pin->rio + RP1_RIO_OE) & (1 << pin->offset)) ?
RP1_DIR_INPUT : RP1_DIR_OUTPUT;
}
@@ -665,19 +703,19 @@ static void rp1_set_dir(struct rp1_pin_i
{
int offset = is_input ? RP1_CLR_OFFSET : RP1_SET_OFFSET;
- writel(1 << pin->offset, pin->rio + RP1_RIO_OE + offset);
+ rp1_pin_writel(1 << pin->offset, pin->dummy, pin->rio + RP1_RIO_OE + offset);
}
static int rp1_get_value(struct rp1_pin_info *pin)
{
- return !!(readl(pin->rio + RP1_RIO_IN) & (1 << pin->offset));
+ return !!(rp1_pin_readl(pin->rio + RP1_RIO_IN) & (1 << pin->offset));
}
static void rp1_set_value(struct rp1_pin_info *pin, int value)
{
/* Assume the pin is already an output */
- writel(1 << pin->offset,
- pin->rio + RP1_RIO_OUT + (value ? RP1_SET_OFFSET : RP1_CLR_OFFSET));
+ rp1_pin_writel(1 << pin->offset, pin->dummy,
+ pin->rio + RP1_RIO_OUT + (value ? RP1_SET_OFFSET : RP1_CLR_OFFSET));
}
static int rp1_gpio_get(struct gpio_chip *chip, unsigned offset)
@@ -1298,7 +1336,7 @@ static const struct pinmux_ops rp1_pmx_o
static void rp1_pull_config_set(struct rp1_pin_info *pin, unsigned int arg)
{
- u32 padctrl = readl(pin->pad);
+ u32 padctrl = rp1_pin_readl(pin->pad);
FLD_SET(padctrl, RP1_PAD_PULL, arg & 0x3);
@@ -1398,7 +1436,7 @@ static int rp1_pinconf_get(struct pinctr
if (!pin)
return -EINVAL;
- padctrl = readl(pin->pad);
+ padctrl = rp1_pin_readl(pin->pad);
switch (param) {
case PIN_CONFIG_INPUT_ENABLE:
@@ -1493,6 +1531,7 @@ static int rp1_pinctrl_probe(struct plat
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
+ struct device_node *rp1_node = NULL;
struct rp1_pinctrl *pc;
struct gpio_irq_chip *girq;
int err, i;
@@ -1528,6 +1567,40 @@ static int rp1_pinctrl_probe(struct plat
pc->gpio_chip = rp1_gpio_chip;
pc->gpio_chip.parent = dev;
+ /*
+ * Workaround for the vagaries of PCIe on BCM2712
+ *
+ * If the link to RP1 is in L1, then the BRCMSTB RC will buffer many
+ * outbound writes - and generate write responses for them, despite the
+ * fact that the link is not yet active. This has the effect of compressing
+ * multiple writes to GPIOs together, destroying any pacing that an application
+ * may require in the 1-10us range.
+ *
+ * The RC Slot Control configuration register is special. It emits a
+ * MsgD for every write to it, will stall further writes until the message
+ * goes out on the wire. This can be (ab)used to force CPU stalls when the
+ * link is inactive, at the cost of a small amount of downstream bandwidth
+ * and some 200ns of added latency for each write.
+ *
+ * Several back-to-back configuration writes are necessary to "fill the pipe",
+ * otherwise the outbound MAC can consume a pending MMIO write and reorder
+ * it with respect to the config writes - undoing the intent.
+ *
+ * of_iomap() is used directly here as the address overlaps with the RC driver's
+ * usage.
+ */
+ rp1_node = of_find_node_by_name(NULL, "rp1");
+ if (!rp1_node)
+ dev_err(&pdev->dev, "failed to find RP1 DT node\n");
+ else if (pace_pin_updates &&
+ of_device_is_compatible(rp1_node->parent, "brcm,bcm2712-pcie")) {
+ pc->dummy_base = of_iomap(rp1_node->parent, 0);
+ if (IS_ERR(pc->dummy_base)) {
+ dev_warn(&pdev->dev, "could not map bcm2712 root complex registers\n");
+ pc->dummy_base = NULL;
+ }
+ }
+
for (i = 0; i < RP1_NUM_BANKS; i++) {
const struct rp1_iobank_desc *bank = &rp1_iobanks[i];
int j;
@@ -1547,14 +1620,17 @@ static int rp1_pinctrl_probe(struct plat
pin->rio = pc->rio_base + bank->rio_offset;
pin->pad = pc->pads_base + bank->pads_offset +
j * sizeof(u32);
+ pin->dummy = pc->dummy_base ? pc->dummy_base + 0xc0 : NULL;
}
raw_spin_lock_init(&pc->irq_lock[i]);
}
pc->pctl_dev = devm_pinctrl_register(dev, &rp1_pinctrl_desc, pc);
- if (IS_ERR(pc->pctl_dev))
- return PTR_ERR(pc->pctl_dev);
+ if (IS_ERR(pc->pctl_dev)) {
+ err = PTR_ERR(pc->pctl_dev);
+ goto out_iounmap;
+ }
girq = &pc->gpio_chip.irq;
girq->chip = &rp1_gpio_irq_chip;
@@ -1583,7 +1659,7 @@ static int rp1_pinctrl_probe(struct plat
err = devm_gpiochip_add_data(dev, &pc->gpio_chip, pc);
if (err) {
dev_err(dev, "could not add GPIO chip\n");
- return err;
+ goto out_iounmap;
}
pc->gpio_range = rp1_pinctrl_gpio_range;
@@ -1592,10 +1668,24 @@ static int rp1_pinctrl_probe(struct plat
pinctrl_add_gpio_range(pc->pctl_dev, &pc->gpio_range);
return 0;
+
+out_iounmap:
+ if (pc->dummy_base)
+ iounmap(pc->dummy_base);
+ return err;
+}
+
+static void rp1_pinctrl_remove(struct platform_device *pdev)
+{
+ struct rp1_pinctrl *pc = platform_get_drvdata(pdev);
+
+ if (pc->dummy_base)
+ iounmap(pc->dummy_base);
}
static struct platform_driver rp1_pinctrl_driver = {
.probe = rp1_pinctrl_probe,
+ .remove_new = rp1_pinctrl_remove,
.driver = {
.name = MODULE_NAME,
.of_match_table = rp1_pinctrl_match,

View File

@ -0,0 +1,36 @@
From 43fa967811484afde0bbbee182ff8f29dc0550c2 Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
Date: Fri, 5 Jul 2024 15:57:25 +0100
Subject: [PATCH 1186/1215] staging: bcm2835-codec: Disable HEADER_ON_OPEN for
video encode
Video encode can defer generating the header until the first
frame is presented, which allows it to take the colourspace
information from the frame rather than just the format.
Enable that for the V4L2 driver now that the firmware populates
all the parameters.
https://github.com/raspberrypi/firmware/issues/1885
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
.../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 7 +++++++
1 file changed, 7 insertions(+)
--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
@@ -2731,6 +2731,13 @@ static int bcm2835_codec_create_componen
&params,
sizeof(params));
+ } else if (dev->role == ENCODE) {
+ enable = 0;
+ vchiq_mmal_port_parameter_set(dev->instance,
+ &ctx->component->control,
+ MMAL_PARAMETER_VIDEO_ENCODE_HEADER_ON_OPEN,
+ &enable,
+ sizeof(enable));
} else if (dev->role == ENCODE_IMAGE) {
enable = 0;
vchiq_mmal_port_parameter_set(dev->instance,

View File

@ -0,0 +1,36 @@
From 31b9871b8895d7931ee88d7cda7861f829b21d63 Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
Date: Wed, 17 Jul 2024 16:59:08 +0100
Subject: [PATCH 1188/1215] staging: bcm2835-codec: Add support for H264 level
5.0 and 5.1
We do NOT claim to support decoding in real-time for these levels,
but can transcode some content, and handle 1920x1200.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
.../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
@@ -3273,7 +3273,7 @@ static void dec_add_profile_ctrls(struct
case V4L2_PIX_FMT_H264:
ctrl = v4l2_ctrl_new_std_menu(hdl, &bcm2835_codec_ctrl_ops,
V4L2_CID_MPEG_VIDEO_H264_LEVEL,
- V4L2_MPEG_VIDEO_H264_LEVEL_4_2,
+ V4L2_MPEG_VIDEO_H264_LEVEL_5_1,
~(BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) |
BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) |
BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) |
@@ -3287,7 +3287,9 @@ static void dec_add_profile_ctrls(struct
BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) |
BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) |
BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) |
- BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2)),
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1)),
V4L2_MPEG_VIDEO_H264_LEVEL_4_0);
ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
ctrl = v4l2_ctrl_new_std_menu(hdl, &bcm2835_codec_ctrl_ops,

View File

@ -0,0 +1,66 @@
From 6014649de765a8a1f95c146ca72214ff0ba4ba89 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
Date: Mon, 1 Jul 2024 15:49:14 +0100
Subject: [PATCH 1189/1215] spi: dw: Save bandwidth with the TMOD_TO feature
TMOD_TO is the transmit-only mode that doesn't put data into the receive
FIFO. Using TMOD_TO when the user doesn't want the received data saves
CPU time and memory bandwidth.
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
---
drivers/spi/spi-dw-core.c | 27 +++++++++++++++++----------
1 file changed, 17 insertions(+), 10 deletions(-)
--- a/drivers/spi/spi-dw-core.c
+++ b/drivers/spi/spi-dw-core.c
@@ -225,12 +225,17 @@ static irqreturn_t dw_spi_transfer_handl
* final stage of the transfer. By doing so we'll get the next IRQ
* right when the leftover incoming data is received.
*/
- dw_reader(dws);
- if (!dws->rx_len) {
- dw_spi_mask_intr(dws, 0xff);
+ if (dws->rx_len) {
+ dw_reader(dws);
+ if (!dws->rx_len) {
+ dw_spi_mask_intr(dws, 0xff);
+ spi_finalize_current_transfer(dws->host);
+ } else if (dws->rx_len <= dw_readl(dws, DW_SPI_RXFTLR)) {
+ dw_writel(dws, DW_SPI_RXFTLR, dws->rx_len - 1);
+ }
+ } else if (!dws->tx_len) {
+ dw_spi_mask_intr(dws, DW_SPI_INT_TXEI);
spi_finalize_current_transfer(dws->host);
- } else if (dws->rx_len <= dw_readl(dws, DW_SPI_RXFTLR)) {
- dw_writel(dws, DW_SPI_RXFTLR, dws->rx_len - 1);
}
/*
@@ -239,12 +244,9 @@ static irqreturn_t dw_spi_transfer_handl
* have the TXE IRQ flood at the final stage of the transfer.
*/
if (irq_status & DW_SPI_INT_TXEI) {
- dw_writer(dws);
- if (!dws->tx_len) {
+ if (!dws->tx_len)
dw_spi_mask_intr(dws, DW_SPI_INT_TXEI);
- if (!dws->rx_len)
- spi_finalize_current_transfer(dws->host);
- }
+ dw_writer(dws);
}
return IRQ_HANDLED;
@@ -437,6 +439,11 @@ static int dw_spi_transfer_one(struct sp
dws->rx = transfer->rx_buf;
dws->rx_len = dws->tx_len;
+ if (!dws->rx) {
+ dws->rx_len = 0;
+ cfg.tmode = DW_SPI_CTRLR0_TMOD_TO;
+ }
+
/* Ensure the data above is visible for all CPUs */
smp_mb();

View File

@ -0,0 +1,186 @@
From cd9084ceb606a2f06c3429c2d3beae2d7c3ebd23 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
Date: Mon, 1 Jul 2024 16:41:04 +0100
Subject: [PATCH 1190/1215] spi: dw: Save bandwidth with the TMOD_RO feature
TMOD_RO is the receive-only mode that doesn't require data in the
transmit FIFO in order to generate clock cycles. Using TMOD_RO when the
device doesn't care about the data sent to it saves CPU time and memory
bandwidth.
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
---
drivers/spi/spi-dw-core.c | 31 +++++++++++++++++++++-------
drivers/spi/spi-dw-dma.c | 43 +++++++++++++++++++++++++--------------
2 files changed, 52 insertions(+), 22 deletions(-)
--- a/drivers/spi/spi-dw-core.c
+++ b/drivers/spi/spi-dw-core.c
@@ -367,18 +367,18 @@ static void dw_spi_irq_setup(struct dw_s
* will be adjusted at the final stage of the IRQ-based SPI transfer
* execution so not to lose the leftover of the incoming data.
*/
- level = min_t(unsigned int, dws->fifo_len / 2, dws->tx_len);
+ level = min_t(unsigned int, dws->fifo_len / 2, dws->tx_len ? dws->tx_len : dws->rx_len);
dw_writel(dws, DW_SPI_TXFTLR, level);
dw_writel(dws, DW_SPI_RXFTLR, level - 1);
dws->transfer_handler = dw_spi_transfer_handler;
- imask = 0;
- if (dws->tx_len)
- imask |= DW_SPI_INT_TXEI | DW_SPI_INT_TXOI;
+ imask = DW_SPI_INT_TXEI | DW_SPI_INT_TXOI;
if (dws->rx_len)
imask |= DW_SPI_INT_RXUI | DW_SPI_INT_RXOI | DW_SPI_INT_RXFI;
dw_spi_umask_intr(dws, imask);
+ if (!dws->tx_len)
+ dw_writel(dws, DW_SPI_DR, 0);
}
/*
@@ -401,13 +401,18 @@ static int dw_spi_poll_transfer(struct d
delay.unit = SPI_DELAY_UNIT_SCK;
nbits = dws->n_bytes * BITS_PER_BYTE;
+ if (!dws->tx_len)
+ dw_writel(dws, DW_SPI_DR, 0);
+
do {
- dw_writer(dws);
+ if (dws->tx_len)
+ dw_writer(dws);
delay.value = nbits * (dws->rx_len - dws->tx_len);
spi_delay_exec(&delay, transfer);
- dw_reader(dws);
+ if (dws->rx_len)
+ dw_reader(dws);
ret = dw_spi_check_status(dws, true);
if (ret)
@@ -427,6 +432,7 @@ static int dw_spi_transfer_one(struct sp
.dfs = transfer->bits_per_word,
.freq = transfer->speed_hz,
};
+ int buswidth;
int ret;
dws->dma_mapped = 0;
@@ -444,6 +450,18 @@ static int dw_spi_transfer_one(struct sp
cfg.tmode = DW_SPI_CTRLR0_TMOD_TO;
}
+ if (!dws->rx) {
+ dws->rx_len = 0;
+ cfg.tmode = DW_SPI_CTRLR0_TMOD_TO;
+ }
+ if (!dws->tx) {
+ dws->tx_len = 0;
+ cfg.tmode = DW_SPI_CTRLR0_TMOD_RO;
+ cfg.ndf = dws->rx_len;
+ }
+ buswidth = transfer->rx_buf ? transfer->rx_nbits :
+ (transfer->tx_buf ? transfer->tx_nbits : 1);
+
/* Ensure the data above is visible for all CPUs */
smp_mb();
@@ -961,7 +979,6 @@ int dw_spi_add_host(struct device *dev,
dev_warn(dev, "DMA init failed\n");
} else {
host->can_dma = dws->dma_ops->can_dma;
- host->flags |= SPI_CONTROLLER_MUST_TX;
}
}
--- a/drivers/spi/spi-dw-dma.c
+++ b/drivers/spi/spi-dw-dma.c
@@ -6,6 +6,7 @@
*/
#include <linux/completion.h>
+#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/irqreturn.h>
@@ -470,13 +471,12 @@ static int dw_spi_dma_setup(struct dw_sp
u16 imr, dma_ctrl;
int ret;
- if (!xfer->tx_buf)
- return -EINVAL;
-
/* Setup DMA channels */
- ret = dw_spi_dma_config_tx(dws);
- if (ret)
- return ret;
+ if (xfer->tx_buf) {
+ ret = dw_spi_dma_config_tx(dws);
+ if (ret)
+ return ret;
+ }
if (xfer->rx_buf) {
ret = dw_spi_dma_config_rx(dws);
@@ -485,13 +485,17 @@ static int dw_spi_dma_setup(struct dw_sp
}
/* Set the DMA handshaking interface */
- dma_ctrl = DW_SPI_DMACR_TDMAE;
+ dma_ctrl = 0;
+ if (xfer->tx_buf)
+ dma_ctrl |= DW_SPI_DMACR_TDMAE;
if (xfer->rx_buf)
dma_ctrl |= DW_SPI_DMACR_RDMAE;
dw_writel(dws, DW_SPI_DMACR, dma_ctrl);
/* Set the interrupt mask */
- imr = DW_SPI_INT_TXOI;
+ imr = 0;
+ if (xfer->tx_buf)
+ imr |= DW_SPI_INT_TXOI;
if (xfer->rx_buf)
imr |= DW_SPI_INT_RXUI | DW_SPI_INT_RXOI;
dw_spi_umask_intr(dws, imr);
@@ -508,15 +512,16 @@ static int dw_spi_dma_transfer_all(struc
{
int ret;
- /* Submit the DMA Tx transfer */
- ret = dw_spi_dma_submit_tx(dws, xfer->tx_sg.sgl, xfer->tx_sg.nents);
- if (ret)
- goto err_clear_dmac;
+ /* Submit the DMA Tx transfer if required */
+ if (xfer->tx_buf) {
+ ret = dw_spi_dma_submit_tx(dws, xfer->tx_sg.sgl, xfer->tx_sg.nents);
+ if (ret)
+ goto err_clear_dmac;
+ }
/* Submit the DMA Rx transfer if required */
if (xfer->rx_buf) {
- ret = dw_spi_dma_submit_rx(dws, xfer->rx_sg.sgl,
- xfer->rx_sg.nents);
+ ret = dw_spi_dma_submit_rx(dws, xfer->rx_sg.sgl, xfer->rx_sg.nents);
if (ret)
goto err_clear_dmac;
@@ -524,7 +529,15 @@ static int dw_spi_dma_transfer_all(struc
dma_async_issue_pending(dws->rxchan);
}
- dma_async_issue_pending(dws->txchan);
+ if (xfer->tx_buf) {
+ dma_async_issue_pending(dws->txchan);
+ } else {
+ /* Pause to allow DMA channel to fetch RX descriptor */
+ usleep_range(5, 10);
+
+ /* Write something to the TX FIFO to start the transfer */
+ dw_writel(dws, DW_SPI_DR, 0);
+ }
ret = dw_spi_dma_wait(dws, xfer->len, xfer->effective_speed_hz);

View File

@ -0,0 +1,41 @@
From 3af7822df36e36b5a74d877df7654695c0e0d34a Mon Sep 17 00:00:00 2001
From: Jonathan Bell <jonathan@raspberrypi.com>
Date: Mon, 22 Jul 2024 15:27:51 +0100
Subject: [PATCH 1191/1215] spi: dw: don't immediately kill DMA transfers if an
error occurs
Disabling the peripheral resets controller state which has a dangerous
side-effect of disabling the DMA handshake interface while it is active.
This can cause DMA channels to hang.
The error recovery pathway will wait for DMA to stop and reset the chip
anyway, so mask further FIFO interrupts and let the transfer finish
gracefully.
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
---
drivers/spi/spi-dw-core.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
--- a/drivers/spi/spi-dw-core.c
+++ b/drivers/spi/spi-dw-core.c
@@ -200,7 +200,18 @@ int dw_spi_check_status(struct dw_spi *d
/* Generically handle the erroneous situation */
if (ret) {
- dw_spi_reset_chip(dws);
+ /*
+ * Forcibly halting the controller can cause DMA to hang.
+ * Defer to dw_spi_handle_err outside of interrupt context
+ * and mask further interrupts for the current transfer.
+ */
+ if (dws->dma_mapped) {
+ dw_spi_mask_intr(dws, 0xff);
+ dw_readl(dws, DW_SPI_ICR);
+ } else {
+ dw_spi_reset_chip(dws);
+ }
+
if (dws->host->cur_msg)
dws->host->cur_msg->status = ret;
}

View File

@ -0,0 +1,35 @@
From 4c1a665b465fa0e9d3369a467fc563ec812a47ce Mon Sep 17 00:00:00 2001
From: Jonathan Bell <jonathan@raspberrypi.com>
Date: Fri, 19 Jul 2024 13:07:59 +0100
Subject: [PATCH 1192/1215] dts: rp1: hobble DMA AXI burst lengths
Channels 1-2 have a statically configured maximum MSIZE of 8, and
channels 3-8 have MSIZE set to 4. The DMAC "helpfully" silently
truncates bursts to the hardware supported maximum, so any FIFO read
operation with an oversized burst threshold will leave a residue of
threshold minus MSIZE rows.
As channel allocation is dynamic, this means every client needs to use a
maximum of 4 for burst length.
AXI AWLEN/ARLEN constraints aren't strictly related to MSIZE, except
that bursts won't be issued that are longer than MSIZE beats. Therefore,
it's a useful proxy to tell clients of the DMAC the hardware
limitations.
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
---
arch/arm64/boot/dts/broadcom/rp1.dtsi | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/arch/arm64/boot/dts/broadcom/rp1.dtsi
+++ b/arch/arm64/boot/dts/broadcom/rp1.dtsi
@@ -1064,7 +1064,7 @@
snps,data-width = <4>; // (8 << 4) == 128 bits
snps,block-size = <0x40000 0x40000 0x40000 0x40000 0x40000 0x40000 0x40000 0x40000>;
snps,priority = <0 1 2 3 4 5 6 7>;
- snps,axi-max-burst-len = <8>;
+ snps,axi-max-burst-len = <4>;
status = "disabled";
};

View File

@ -0,0 +1,124 @@
From ce56098eb4dc2985f27f30ad7b7f5aed6bcf7fb1 Mon Sep 17 00:00:00 2001
From: Jonathan Bell <jonathan@raspberrypi.com>
Date: Fri, 19 Jul 2024 15:55:56 +0100
Subject: [PATCH 1193/1215] drivers: dw-axi-dmac: make more sensible choices
about memory accesses
There's no real need to constrain MEM access widths to 32-bit (or
narrower), as the DMAC is intelligent enough to size memory accesses
appropriately. Wider accesses are more efficient.
Similarly, MEM burst lengths don't need to be a function of DEV burst
lengths - the DMAC packs/unpacks data into/from its internal channel
FIFOs appropriately. Longer accesses are more efficient.
However, the DMAC doesn't have complete support for unaligned accesses,
and blocks are always defined in integer multiples of SRC_WIDTH, so odd
source lengths or buffer alignments will prevent wide accesses being
used, as before.
There is an implicit requirement to limit requested DEV read burst
lengths to less than the hardware's maximum configured MSIZE - otherwise
RX data will be left over at the end of a block. There is no config
register that reports this value, so the AXI burst length parameter is
used to produce a facsimile of it. Warn if such a request arrives that
doesn't respect this.
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
---
.../dma/dw-axi-dmac/dw-axi-dmac-platform.c | 38 ++++++++++++-------
1 file changed, 25 insertions(+), 13 deletions(-)
--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
+++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
@@ -261,6 +261,15 @@ static u32 axi_chan_get_xfer_width(struc
return __ffs(src | dst | len | BIT(max_width));
}
+static u32 axi_dma_encode_msize(u32 max_burst)
+{
+ if (max_burst <= 1)
+ return DWAXIDMAC_BURST_TRANS_LEN_1;
+ if (max_burst > 1024)
+ return DWAXIDMAC_BURST_TRANS_LEN_1024;
+ return fls(max_burst) - 2;
+}
+
static inline const char *axi_chan_name(struct axi_dma_chan *chan)
{
return dma_chan_name(&chan->vc.chan);
@@ -685,41 +694,41 @@ static int dw_axi_dma_set_hw_desc(struct
size_t axi_block_ts;
size_t block_ts;
u32 ctllo, ctlhi;
- u32 burst_len;
+ u32 burst_len = 0, mem_burst_msize, reg_burst_msize;
axi_block_ts = chan->chip->dw->hdata->block_size[chan->id];
mem_width = __ffs(data_width | mem_addr | len);
- if (mem_width > DWAXIDMAC_TRANS_WIDTH_32)
- mem_width = DWAXIDMAC_TRANS_WIDTH_32;
if (!IS_ALIGNED(mem_addr, 4)) {
dev_err(chan->chip->dev, "invalid buffer alignment\n");
return -EINVAL;
}
+ /* Use a reasonable upper limit otherwise residue reporting granularity grows large */
+ mem_burst_msize = axi_dma_encode_msize(16);
+
switch (chan->direction) {
case DMA_MEM_TO_DEV:
+ reg_burst_msize = axi_dma_encode_msize(chan->config.dst_maxburst);
reg_width = __ffs(chan->config.dst_addr_width);
device_addr = phys_to_dma(chan->chip->dev, chan->config.dst_addr);
ctllo = reg_width << CH_CTL_L_DST_WIDTH_POS |
mem_width << CH_CTL_L_SRC_WIDTH_POS |
- DWAXIDMAC_BURST_TRANS_LEN_1 << CH_CTL_L_DST_MSIZE_POS |
- DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_SRC_MSIZE_POS |
+ reg_burst_msize << CH_CTL_L_DST_MSIZE_POS |
+ mem_burst_msize << CH_CTL_L_SRC_MSIZE_POS |
DWAXIDMAC_CH_CTL_L_NOINC << CH_CTL_L_DST_INC_POS |
DWAXIDMAC_CH_CTL_L_INC << CH_CTL_L_SRC_INC_POS;
block_ts = len >> mem_width;
break;
case DMA_DEV_TO_MEM:
+ reg_burst_msize = axi_dma_encode_msize(chan->config.src_maxburst);
reg_width = __ffs(chan->config.src_addr_width);
- /* Prevent partial access units getting lost */
- if (mem_width > reg_width)
- mem_width = reg_width;
device_addr = phys_to_dma(chan->chip->dev, chan->config.src_addr);
ctllo = reg_width << CH_CTL_L_SRC_WIDTH_POS |
mem_width << CH_CTL_L_DST_WIDTH_POS |
- DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_DST_MSIZE_POS |
- DWAXIDMAC_BURST_TRANS_LEN_1 << CH_CTL_L_SRC_MSIZE_POS |
+ mem_burst_msize << CH_CTL_L_DST_MSIZE_POS |
+ reg_burst_msize << CH_CTL_L_SRC_MSIZE_POS |
DWAXIDMAC_CH_CTL_L_INC << CH_CTL_L_DST_INC_POS |
DWAXIDMAC_CH_CTL_L_NOINC << CH_CTL_L_SRC_INC_POS;
block_ts = len >> reg_width;
@@ -760,6 +769,12 @@ static int dw_axi_dma_set_hw_desc(struct
set_desc_src_master(hw_desc);
hw_desc->len = len;
+
+ if (burst_len && (chan->config.src_maxburst > burst_len))
+ dev_warn_ratelimited(chan2dev(chan),
+ "%s: requested source burst length %u exceeds supported burst length %u - data may be lost\n",
+ axi_chan_name(chan), chan->config.src_maxburst, burst_len);
+
return 0;
}
@@ -776,9 +791,6 @@ static size_t calculate_block_len(struct
case DMA_MEM_TO_DEV:
data_width = BIT(chan->chip->dw->hdata->m_data_width);
mem_width = __ffs(data_width | dma_addr | buf_len);
- if (mem_width > DWAXIDMAC_TRANS_WIDTH_32)
- mem_width = DWAXIDMAC_TRANS_WIDTH_32;
-
block_len = axi_block_ts << mem_width;
break;
case DMA_DEV_TO_MEM:

View File

@ -0,0 +1,30 @@
From f3cb675102a2a5a330038c4e748f02b02cec989e Mon Sep 17 00:00:00 2001
From: Jonathan Bell <jonathan@raspberrypi.com>
Date: Mon, 22 Jul 2024 09:30:54 +0100
Subject: [PATCH 1195/1215] tty/serial: pl011: restrict RX burst FIFO threshold
If the associated DMA controller has lower burst length support than the
level the FIFO is set to, then bytes will be left in the RX FIFO at the
end of a DMA block - requiring a round-trip through the timeout interrupt
handler rather than an end-of-block DMA interrupt.
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
---
drivers/tty/serial/amba-pl011.c | 6 ++++++
1 file changed, 6 insertions(+)
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -487,6 +487,12 @@ static void pl011_dma_probe(struct uart_
"RX DMA disabled - no residue processing\n");
return;
}
+ /*
+ * DMA controllers with smaller burst capabilities than 1/4
+ * the FIFO depth will leave more bytes than expected in the
+ * RX FIFO if mismatched.
+ */
+ rx_conf.src_maxburst = min(caps.max_burst, rx_conf.src_maxburst);
}
dmaengine_slave_config(chan, &rx_conf);
uap->dmarx.chan = chan;

View File

@ -0,0 +1,27 @@
From 5112fd8cce4f1dc9bf43f0f90d35e273e1a0f555 Mon Sep 17 00:00:00 2001
From: Jonathan Bell <jonathan@raspberrypi.com>
Date: Mon, 22 Jul 2024 14:32:32 +0100
Subject: [PATCH 1196/1215] DT: bindings: add a dma-maxburst property to
snps,designware-i2s
Do an end-run around ASoC in lieu of not being able to easily find the
associated DMA controller capabilities.
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
---
.../devicetree/bindings/sound/snps,designware-i2s.yaml | 4 ++++
1 file changed, 4 insertions(+)
--- a/Documentation/devicetree/bindings/sound/snps,designware-i2s.yaml
+++ b/Documentation/devicetree/bindings/sound/snps,designware-i2s.yaml
@@ -69,6 +69,10 @@ properties:
- description: RX DMA Channel
minItems: 1
+ dma-maxburst:
+ description: FIFO DMA burst threshold limit
+ maxItems: 1
+
dma-names:
items:
- const: tx

View File

@ -0,0 +1,99 @@
From b6b4260fa546d1dc7421c7cfed059052dae04227 Mon Sep 17 00:00:00 2001
From: Jonathan Bell <jonathan@raspberrypi.com>
Date: Thu, 18 Jul 2024 09:40:03 +0100
Subject: [PATCH 1197/1215] sound/soc: dwc-i2s: choose FIFO thresholds based on
DMA burst constraints
Valid ranges for the I2S peripheral's FIFO configuration include a depth
of 16 - unconditionally setting the burst length to 16 with a fifo
threshold of size/2 will cause under/overflows.
For DMA engines with restricted capabilities the requested burst length
and FIFO thresholds need to be adjusted downward accordingly.
Both the RX and TX FIFOs operate on "less-than" thresholds. Setting the
TX threshold to fifo_size minus burst means the FIFO is kept nearly-full.
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
---
sound/soc/dwc/dwc-i2s.c | 21 ++++++++++++++++-----
sound/soc/dwc/local.h | 1 +
2 files changed, 17 insertions(+), 5 deletions(-)
--- a/sound/soc/dwc/dwc-i2s.c
+++ b/sound/soc/dwc/dwc-i2s.c
@@ -236,6 +236,8 @@ static void dw_i2s_config(struct dw_i2s_
u32 ch_reg;
struct i2s_clk_config_data *config = &dev->config;
u32 dmacr;
+ u32 comp1 = i2s_read_reg(dev->i2s_base, dev->i2s_reg_comp1);
+ u32 fifo_depth = 1 << (1 + COMP1_FIFO_DEPTH_GLOBAL(comp1));
i2s_disable_channels(dev, stream);
@@ -251,7 +253,7 @@ static void dw_i2s_config(struct dw_i2s_
i2s_write_reg(dev->i2s_base, TCR(ch_reg),
dev->xfer_resolution);
i2s_write_reg(dev->i2s_base, TFCR(ch_reg),
- dev->fifo_th - 1);
+ fifo_depth - dev->fifo_th - 1);
i2s_write_reg(dev->i2s_base, TER(ch_reg), TER_TXCHEN |
dev->tdm_mask << TER_TXSLOT_SHIFT);
dmacr |= (DMACR_DMAEN_TXCH0 << ch_reg);
@@ -783,8 +785,8 @@ static int dw_configure_dai_by_pd(struct
dev->capture_dma_data.pd.data = pdata->capture_dma_data;
dev->play_dma_data.pd.addr = res->start + I2S_TXDMA;
dev->capture_dma_data.pd.addr = res->start + I2S_RXDMA;
- dev->play_dma_data.pd.max_burst = 16;
- dev->capture_dma_data.pd.max_burst = 16;
+ dev->play_dma_data.pd.max_burst = dev->fifo_th;
+ dev->capture_dma_data.pd.max_burst = dev->fifo_th;
dev->play_dma_data.pd.addr_width = bus_widths[idx];
dev->capture_dma_data.pd.addr_width = bus_widths[idx];
dev->play_dma_data.pd.filter = pdata->filter;
@@ -815,7 +817,10 @@ static int dw_configure_dai_by_dt(struct
dev->play_dma_data.dt.addr = res->start + I2S_TXDMA;
dev->play_dma_data.dt.fifo_size = fifo_depth *
(fifo_width[idx2]) >> 8;
- dev->play_dma_data.dt.maxburst = 16;
+ if (dev->max_dma_burst)
+ dev->play_dma_data.dt.maxburst = dev->max_dma_burst;
+ else
+ dev->play_dma_data.dt.maxburst = fifo_depth / 2;
}
if (COMP1_RX_ENABLED(comp1)) {
idx2 = COMP2_RX_WORDSIZE_0(comp2);
@@ -824,9 +829,14 @@ static int dw_configure_dai_by_dt(struct
dev->capture_dma_data.dt.addr = res->start + I2S_RXDMA;
dev->capture_dma_data.dt.fifo_size = fifo_depth *
(fifo_width[idx2] >> 8);
- dev->capture_dma_data.dt.maxburst = 16;
+ if (dev->max_dma_burst)
+ dev->capture_dma_data.dt.maxburst = dev->max_dma_burst;
+ else
+ dev->capture_dma_data.dt.maxburst = fifo_depth / 2;
}
+ if (dev->max_dma_burst)
+ dev->fifo_th = min(dev->max_dma_burst, dev->fifo_th);
return 0;
}
@@ -1070,6 +1080,7 @@ static int dw_i2s_probe(struct platform_
}
}
+ of_property_read_u32(pdev->dev.of_node, "dma-maxburst", &dev->max_dma_burst);
dev->bclk_ratio = 0;
dev->i2s_reg_comp1 = I2S_COMP_PARAM_1;
dev->i2s_reg_comp2 = I2S_COMP_PARAM_2;
--- a/sound/soc/dwc/local.h
+++ b/sound/soc/dwc/local.h
@@ -133,6 +133,7 @@ struct dw_i2s_dev {
u32 ccr;
u32 xfer_resolution;
u32 fifo_th;
+ u32 max_dma_burst;
u32 l_reg;
u32 r_reg;
bool is_jh7110; /* Flag for StarFive JH7110 SoC */

View File

@ -0,0 +1,30 @@
From 062434ab3be76d4fa5973bb199ccfd5b68c11720 Mon Sep 17 00:00:00 2001
From: Jonathan Bell <jonathan@raspberrypi.com>
Date: Tue, 23 Jul 2024 11:21:47 +0100
Subject: [PATCH 1198/1215] dts: rp1: restrict i2s burst lengths to 4
The associated DMAC has channels that do not support longer bursts.
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
---
arch/arm64/boot/dts/broadcom/rp1.dtsi | 2 ++
1 file changed, 2 insertions(+)
--- a/arch/arm64/boot/dts/broadcom/rp1.dtsi
+++ b/arch/arm64/boot/dts/broadcom/rp1.dtsi
@@ -400,6 +400,7 @@
#sound-dai-cells = <0>;
dmas = <&rp1_dma RP1_DMA_I2S0_TX>,<&rp1_dma RP1_DMA_I2S0_RX>;
dma-names = "tx", "rx";
+ dma-maxburst = <4>;
status = "disabled";
};
@@ -413,6 +414,7 @@
#sound-dai-cells = <0>;
dmas = <&rp1_dma RP1_DMA_I2S1_TX>,<&rp1_dma RP1_DMA_I2S1_RX>;
dma-names = "tx", "rx";
+ dma-maxburst = <4>;
status = "disabled";
};

View File

@ -0,0 +1,204 @@
From 485d11cfa7df2d2deb39c9b3455cebcb1a85cea2 Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
Date: Thu, 25 Jul 2024 14:36:32 +0100
Subject: [PATCH 1199/1215] drm/vc4: Disable the 2pixel/clock odd timings
workaround for interlaced
Whilst BCM2712 does fix using odd horizontal timings, it doesn't
work with interlaced modes.
Drop the workaround for interlaced modes and revert to the same
behaviour as BCM2711.
https://github.com/raspberrypi/linux/issues/6281
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
drivers/gpu/drm/vc4/vc4_crtc.c | 20 +++++++++++++++++---
drivers/gpu/drm/vc4/vc4_drv.h | 2 ++
drivers/gpu/drm/vc4/vc4_hdmi.c | 8 +++++++-
drivers/gpu/drm/vc4/vc4_hdmi.h | 4 ++++
4 files changed, 30 insertions(+), 4 deletions(-)
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
@@ -378,7 +378,9 @@ static void vc4_crtc_config_pv(struct dr
bool is_dsi1 = vc4_encoder->type == VC4_ENCODER_TYPE_DSI1;
bool is_vec = vc4_encoder->type == VC4_ENCODER_TYPE_VEC;
u32 format = is_dsi1 ? PV_CONTROL_FORMAT_DSIV_24 : PV_CONTROL_FORMAT_24;
- u8 ppc = pv_data->pixels_per_clock;
+ u8 ppc = (mode->flags & DRM_MODE_FLAG_INTERLACE) ?
+ pv_data->pixels_per_clock_int :
+ pv_data->pixels_per_clock;
u16 vert_bp = mode->crtc_vtotal - mode->crtc_vsync_end;
u16 vert_sync = mode->crtc_vsync_end - mode->crtc_vsync_start;
@@ -443,7 +445,8 @@ static void vc4_crtc_config_pv(struct dr
*/
CRTC_WRITE(PV_V_CONTROL,
PV_VCONTROL_CONTINUOUS |
- (vc4->gen >= VC4_GEN_6 ? PV_VCONTROL_ODD_TIMING : 0) |
+ (vc4->gen >= VC4_GEN_6 && ppc == 1 ?
+ PV_VCONTROL_ODD_TIMING : 0) |
(is_dsi ? PV_VCONTROL_DSI : 0) |
PV_VCONTROL_INTERLACE |
(odd_field_first
@@ -455,7 +458,8 @@ static void vc4_crtc_config_pv(struct dr
} else {
CRTC_WRITE(PV_V_CONTROL,
PV_VCONTROL_CONTINUOUS |
- (vc4->gen >= VC4_GEN_6 ? PV_VCONTROL_ODD_TIMING : 0) |
+ (vc4->gen >= VC4_GEN_6 && ppc == 1 ?
+ PV_VCONTROL_ODD_TIMING : 0) |
(is_dsi ? PV_VCONTROL_DSI : 0));
CRTC_WRITE(PV_VSYNCD_EVEN, 0);
}
@@ -1223,6 +1227,7 @@ const struct vc4_pv_data bcm2835_pv0_dat
},
.fifo_depth = 64,
.pixels_per_clock = 1,
+ .pixels_per_clock_int = 1,
.encoder_types = {
[PV_CONTROL_CLK_SELECT_DSI] = VC4_ENCODER_TYPE_DSI0,
[PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_DPI,
@@ -1238,6 +1243,7 @@ const struct vc4_pv_data bcm2835_pv1_dat
},
.fifo_depth = 64,
.pixels_per_clock = 1,
+ .pixels_per_clock_int = 1,
.encoder_types = {
[PV_CONTROL_CLK_SELECT_DSI] = VC4_ENCODER_TYPE_DSI1,
[PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_SMI,
@@ -1253,6 +1259,7 @@ const struct vc4_pv_data bcm2835_pv2_dat
},
.fifo_depth = 64,
.pixels_per_clock = 1,
+ .pixels_per_clock_int = 1,
.encoder_types = {
[PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_HDMI0,
[PV_CONTROL_CLK_SELECT_VEC] = VC4_ENCODER_TYPE_VEC,
@@ -1268,6 +1275,7 @@ const struct vc4_pv_data bcm2711_pv0_dat
},
.fifo_depth = 64,
.pixels_per_clock = 1,
+ .pixels_per_clock_int = 1,
.encoder_types = {
[0] = VC4_ENCODER_TYPE_DSI0,
[1] = VC4_ENCODER_TYPE_DPI,
@@ -1283,6 +1291,7 @@ const struct vc4_pv_data bcm2711_pv1_dat
},
.fifo_depth = 64,
.pixels_per_clock = 1,
+ .pixels_per_clock_int = 1,
.encoder_types = {
[0] = VC4_ENCODER_TYPE_DSI1,
[1] = VC4_ENCODER_TYPE_SMI,
@@ -1298,6 +1307,7 @@ const struct vc4_pv_data bcm2711_pv2_dat
},
.fifo_depth = 256,
.pixels_per_clock = 2,
+ .pixels_per_clock_int = 2,
.encoder_types = {
[0] = VC4_ENCODER_TYPE_HDMI0,
},
@@ -1312,6 +1322,7 @@ const struct vc4_pv_data bcm2711_pv3_dat
},
.fifo_depth = 64,
.pixels_per_clock = 1,
+ .pixels_per_clock_int = 1,
.encoder_types = {
[PV_CONTROL_CLK_SELECT_VEC] = VC4_ENCODER_TYPE_VEC,
},
@@ -1326,6 +1337,7 @@ const struct vc4_pv_data bcm2711_pv4_dat
},
.fifo_depth = 64,
.pixels_per_clock = 2,
+ .pixels_per_clock_int = 2,
.encoder_types = {
[0] = VC4_ENCODER_TYPE_HDMI1,
},
@@ -1339,6 +1351,7 @@ const struct vc4_pv_data bcm2712_pv0_dat
},
.fifo_depth = 64,
.pixels_per_clock = 1,
+ .pixels_per_clock_int = 2,
.encoder_types = {
[0] = VC4_ENCODER_TYPE_HDMI0,
},
@@ -1352,6 +1365,7 @@ const struct vc4_pv_data bcm2712_pv1_dat
},
.fifo_depth = 64,
.pixels_per_clock = 1,
+ .pixels_per_clock_int = 2,
.encoder_types = {
[0] = VC4_ENCODER_TYPE_HDMI1,
},
--- a/drivers/gpu/drm/vc4/vc4_drv.h
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
@@ -569,6 +569,8 @@ struct vc4_pv_data {
/* Number of pixels output per clock period */
u8 pixels_per_clock;
+ /* Number of pixels output per clock period when in an interlaced mode */
+ u8 pixels_per_clock_int;
enum vc4_encoder_type encoder_types[4];
};
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -2263,7 +2263,9 @@ static int vc4_hdmi_encoder_atomic_check
unsigned long long tmds_bit_rate;
int ret;
- if (vc4_hdmi->variant->unsupported_odd_h_timings) {
+ if (vc4_hdmi->variant->unsupported_odd_h_timings ||
+ (vc4_hdmi->variant->unsupported_int_odd_h_timings &&
+ (mode->flags & DRM_MODE_FLAG_INTERLACE))) {
if (mode->flags & DRM_MODE_FLAG_DBLCLK) {
/* Only try to fixup DBLCLK modes to get 480i and 576i
* working.
@@ -3974,6 +3976,7 @@ static const struct vc4_hdmi_variant bcm
PHY_LANE_CK,
},
.unsupported_odd_h_timings = true,
+ .unsupported_int_odd_h_timings = true,
.external_irq_controller = true,
.init_resources = vc5_hdmi_init_resources,
@@ -4003,6 +4006,7 @@ static const struct vc4_hdmi_variant bcm
PHY_LANE_2,
},
.unsupported_odd_h_timings = true,
+ .unsupported_int_odd_h_timings = true,
.external_irq_controller = true,
.init_resources = vc5_hdmi_init_resources,
@@ -4032,6 +4036,7 @@ static const struct vc4_hdmi_variant bcm
PHY_LANE_CK,
},
.unsupported_odd_h_timings = false,
+ .unsupported_int_odd_h_timings = true,
.external_irq_controller = true,
.init_resources = vc5_hdmi_init_resources,
@@ -4059,6 +4064,7 @@ static const struct vc4_hdmi_variant bcm
PHY_LANE_CK,
},
.unsupported_odd_h_timings = false,
+ .unsupported_int_odd_h_timings = true,
.external_irq_controller = true,
.init_resources = vc5_hdmi_init_resources,
--- a/drivers/gpu/drm/vc4/vc4_hdmi.h
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.h
@@ -49,6 +49,10 @@ struct vc4_hdmi_variant {
/* The BCM2711 cannot deal with odd horizontal pixel timings */
bool unsupported_odd_h_timings;
+ /* The BCM2712 can handle odd horizontal pixel timings, but not in
+ * interlaced modes
+ */
+ bool unsupported_int_odd_h_timings;
/*
* The BCM2711 CEC/hotplug IRQ controller is shared between the

View File

@ -0,0 +1,26 @@
From 70636ad110715b5e1ec6b08e24f0ddaf5df7186d Mon Sep 17 00:00:00 2001
From: Dom Cobley <popcornmix@gmail.com>
Date: Tue, 30 Jul 2024 19:00:03 +0100
Subject: [PATCH 1200/1215] ARM: dts: bcm2712: Fix invalid
polling-delay-passive setting
This produces a hard fail on later (6.11) kernels.
See: https://lore.kernel.org/all/5802156.DvuYhMxLoT@rjwysocki.net/
Signed-off-by: Dom Cobley <popcornmix@gmail.com>
---
arch/arm64/boot/dts/broadcom/bcm2712.dtsi | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/arch/arm64/boot/dts/broadcom/bcm2712.dtsi
+++ b/arch/arm64/boot/dts/broadcom/bcm2712.dtsi
@@ -40,7 +40,7 @@
thermal-zones {
cpu_thermal: cpu-thermal {
- polling-delay-passive = <2000>;
+ polling-delay-passive = <1000>;
polling-delay = <1000>;
coefficients = <(-550) 450000>;
thermal-sensors = <&thermal>;

View File

@ -0,0 +1,143 @@
From 199e611183de09ad91fe01fc79da78cc9d11ccb6 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
Date: Mon, 29 Jul 2024 11:12:38 +0100
Subject: [PATCH 1201/1215] spi: dw: Fix non-DMA transmit-only transfers
Ensure the transmit FIFO has emptied before ending the transfer by
dropping the TX threshold to 0 when the last byte has been pushed into
the FIFO. Include a similar fix for the non-IRQ paths.
See: https://github.com/raspberrypi/linux/issues/6285
Fixes: 6014649de765 ("spi: dw: Save bandwidth with the TMOD_TO feature")
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
---
drivers/spi/spi-dw-core.c | 62 +++++++++++++++++++++++++++++++++------
drivers/spi/spi-dw.h | 3 ++
2 files changed, 56 insertions(+), 9 deletions(-)
--- a/drivers/spi/spi-dw-core.c
+++ b/drivers/spi/spi-dw-core.c
@@ -220,6 +220,32 @@ int dw_spi_check_status(struct dw_spi *d
}
EXPORT_SYMBOL_NS_GPL(dw_spi_check_status, SPI_DW_CORE);
+static inline bool dw_spi_ctlr_busy(struct dw_spi *dws)
+{
+ return dw_readl(dws, DW_SPI_SR) & DW_SPI_SR_BUSY;
+}
+
+static enum hrtimer_restart dw_spi_hrtimer_handler(struct hrtimer *hr)
+{
+ struct dw_spi *dws = container_of(hr, struct dw_spi, hrtimer);
+
+ if (!dw_spi_ctlr_busy(dws)) {
+ spi_finalize_current_transfer(dws->host);
+ return HRTIMER_NORESTART;
+ }
+
+ if (!dws->idle_wait_retries) {
+ dev_err(&dws->host->dev, "controller stuck at busy\n");
+ spi_finalize_current_transfer(dws->host);
+ return HRTIMER_NORESTART;
+ }
+
+ dws->idle_wait_retries--;
+ hrtimer_forward_now(hr, dws->idle_wait_interval);
+
+ return HRTIMER_RESTART;
+}
+
static irqreturn_t dw_spi_transfer_handler(struct dw_spi *dws)
{
u16 irq_status = dw_readl(dws, DW_SPI_ISR);
@@ -246,7 +272,22 @@ static irqreturn_t dw_spi_transfer_handl
}
} else if (!dws->tx_len) {
dw_spi_mask_intr(dws, DW_SPI_INT_TXEI);
- spi_finalize_current_transfer(dws->host);
+ if (dw_spi_ctlr_busy(dws)) {
+ ktime_t period = ns_to_ktime(DIV_ROUND_UP(NSEC_PER_SEC, dws->current_freq));
+
+ /*
+ * Make the initial wait an underestimate of how long the transfer
+ * should take, then poll rapidly to reduce the delay
+ */
+ hrtimer_start(&dws->hrtimer,
+ period * (8 * dws->n_bytes - 1),
+ HRTIMER_MODE_REL);
+ dws->idle_wait_retries = 10;
+ dws->idle_wait_interval = period;
+ } else {
+ spi_finalize_current_transfer(dws->host);
+ }
+ return IRQ_HANDLED;
}
/*
@@ -255,9 +296,13 @@ static irqreturn_t dw_spi_transfer_handl
* have the TXE IRQ flood at the final stage of the transfer.
*/
if (irq_status & DW_SPI_INT_TXEI) {
- if (!dws->tx_len)
- dw_spi_mask_intr(dws, DW_SPI_INT_TXEI);
dw_writer(dws);
+ if (!dws->tx_len) {
+ if (dws->rx_len)
+ dw_spi_mask_intr(dws, DW_SPI_INT_TXEI);
+ else
+ dw_writel(dws, DW_SPI_TXFTLR, 0);
+ }
}
return IRQ_HANDLED;
@@ -428,7 +473,7 @@ static int dw_spi_poll_transfer(struct d
ret = dw_spi_check_status(dws, true);
if (ret)
return ret;
- } while (dws->rx_len);
+ } while (dws->rx_len || dws->tx_len || dw_spi_ctlr_busy(dws));
return 0;
}
@@ -652,11 +697,6 @@ static int dw_spi_write_then_read(struct
return 0;
}
-static inline bool dw_spi_ctlr_busy(struct dw_spi *dws)
-{
- return dw_readl(dws, DW_SPI_SR) & DW_SPI_SR_BUSY;
-}
-
static int dw_spi_wait_mem_op_done(struct dw_spi *dws)
{
int retry = DW_SPI_WAIT_RETRIES;
@@ -993,6 +1033,9 @@ int dw_spi_add_host(struct device *dev,
}
}
+ hrtimer_init(&dws->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+ dws->hrtimer.function = dw_spi_hrtimer_handler;
+
ret = spi_register_controller(host);
if (ret) {
dev_err_probe(dev, ret, "problem registering spi host\n");
@@ -1018,6 +1061,7 @@ void dw_spi_remove_host(struct dw_spi *d
{
dw_spi_debugfs_remove(dws);
+ hrtimer_cancel(&dws->hrtimer);
spi_unregister_controller(dws->host);
if (dws->dma_ops && dws->dma_ops->dma_exit)
--- a/drivers/spi/spi-dw.h
+++ b/drivers/spi/spi-dw.h
@@ -180,6 +180,9 @@ struct dw_spi {
u32 current_freq; /* frequency in hz */
u32 cur_rx_sample_dly;
u32 def_rx_sample_dly_ns;
+ struct hrtimer hrtimer;
+ ktime_t idle_wait_interval;
+ int idle_wait_retries;
/* Custom memory operations */
struct spi_controller_mem_ops mem_ops;

View File

@ -0,0 +1,26 @@
From e9294823cf02068189a0e901223ed4991923c689 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
Date: Wed, 31 Jul 2024 10:55:19 +0100
Subject: [PATCH 1202/1215] spi: dw: Clamp the minimum clock speed
The DW SPI interface has a 16-bit clock divider, where the bottom bit
of the divisor must be 0. Limit how low the clock speed can go to
prevent the clock divider from being truncated, as that could lead to
a much higher clock rate than requested.
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
---
drivers/spi/spi-dw-core.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/spi/spi-dw-core.c
+++ b/drivers/spi/spi-dw-core.c
@@ -397,7 +397,7 @@ void dw_spi_update_config(struct dw_spi
dw_writel(dws, DW_SPI_CTRLR1, cfg->ndf ? cfg->ndf - 1 : 0);
/* Note DW APB SSI clock divider doesn't support odd numbers */
- clk_div = (DIV_ROUND_UP(dws->max_freq, cfg->freq) + 1) & 0xfffe;
+ clk_div = min(DIV_ROUND_UP(dws->max_freq, cfg->freq) + 1, 0xfffe) & 0xfffe;
speed_hz = dws->max_freq / clk_div;
if (dws->current_freq != speed_hz) {

View File

@ -0,0 +1,26 @@
From 05e3687c6c973c30bf35f3b7f4a7589b5030a830 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
Date: Wed, 31 Jul 2024 13:19:26 +0100
Subject: [PATCH 1203/1215] overlays: i2c-rtc: Correct bq32000 property name
The DT property for the BQ32000 controlled by trickle-resistor-ohms
parameter should be "trickle-resistor-ohms", not "abracon,tc-resistor".
See: https://github.com/raspberrypi/linux/issues/6291
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
---
arch/arm/boot/dts/overlays/i2c-rtc-common.dtsi | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/arch/arm/boot/dts/overlays/i2c-rtc-common.dtsi
+++ b/arch/arm/boot/dts/overlays/i2c-rtc-common.dtsi
@@ -354,7 +354,7 @@
<&rv3028>,"trickle-resistor-ohms:0",
<&rv3032>,"trickle-resistor-ohms:0",
<&rv1805>,"abracon,tc-resistor:0",
- <&bq32000>,"abracon,tc-resistor:0";
+ <&bq32000>,"trickle-resistor-ohms:0";
trickle-voltage-mv = <&rv3032>,"trickle-voltage-millivolts:0";
backup-switchover-mode = <&rv3028>,"backup-switchover-mode:0";
wakeup-source = <&ds1339>,"wakeup-source?",

View File

@ -0,0 +1,31 @@
From 16d0ee22d2c0b32cc67db73ce03263b740bba2a7 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
Date: Wed, 31 Jul 2024 15:02:47 +0100
Subject: [PATCH 1204/1215] hwmon: (adt7410) Add DT compatible strings
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
---
drivers/hwmon/adt7410.c | 8 ++++++++
1 file changed, 8 insertions(+)
--- a/drivers/hwmon/adt7410.c
+++ b/drivers/hwmon/adt7410.c
@@ -94,10 +94,18 @@ static const struct i2c_device_id adt741
};
MODULE_DEVICE_TABLE(i2c, adt7410_ids);
+static const struct of_device_id adt7410_of_ids[] = {
+ { .compatible = "adi,adt7410" },
+ { .compatible = "adi,adt7420" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, adt7410_of_ids);
+
static struct i2c_driver adt7410_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "adt7410",
+ .of_match_table = adt7410_of_ids,
.pm = pm_sleep_ptr(&adt7x10_dev_pm_ops),
},
.probe = adt7410_i2c_probe,

View File

@ -0,0 +1,23 @@
From a4bf61fad9fe102514243ed263c458b053c87681 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
Date: Fri, 2 Aug 2024 11:29:03 +0100
Subject: [PATCH 1205/1215] fixup! pinctrl: bcm2712 pinctrl/pinconf driver
Fix cut-and-paste error spotted during upstreaming process.
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
---
drivers/pinctrl/bcm/pinctrl-bcm2712.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/pinctrl/bcm/pinctrl-bcm2712.c
+++ b/drivers/pinctrl/bcm/pinctrl-bcm2712.c
@@ -1029,7 +1029,7 @@ static int bcm2712_pinconf_get(struct pi
*config = pinconf_to_config_packed(param, arg);
- return -ENOTSUPP;
+ return 0;
}
static int bcm2712_pinconf_set(struct pinctrl_dev *pctldev,

View File

@ -0,0 +1,125 @@
From e94e761305fa2281718adcf625d78f3cf662e12d Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
Date: Thu, 1 Aug 2024 18:12:50 +0100
Subject: [PATCH 1206/1215] dtoverlays: Add overlay for HD44780 via I2C PCF8574
backpack
Many HD44780 LCD displays are connected via very common I2C
GPIO expander.
We have an overlay for connecting the displays directly to GPIOs,
but not one for it connected via a backpack. Add such an overlay.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
arch/arm/boot/dts/overlays/Makefile | 1 +
arch/arm/boot/dts/overlays/README | 27 +++++++++
.../dts/overlays/hd44780-i2c-lcd-overlay.dts | 57 +++++++++++++++++++
3 files changed, 85 insertions(+)
create mode 100644 arch/arm/boot/dts/overlays/hd44780-i2c-lcd-overlay.dts
--- a/arch/arm/boot/dts/overlays/Makefile
+++ b/arch/arm/boot/dts/overlays/Makefile
@@ -82,6 +82,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
gpio-no-irq.dtbo \
gpio-poweroff.dtbo \
gpio-shutdown.dtbo \
+ hd44780-i2c-lcd.dtbo \
hd44780-lcd.dtbo \
hdmi-backlight-hwhack-gpio.dtbo \
hifiberry-amp.dtbo \
--- a/arch/arm/boot/dts/overlays/README
+++ b/arch/arm/boot/dts/overlays/README
@@ -1705,6 +1705,33 @@ Params: gpio_pin GPIO pin
(default 100)
+Name: hd44780-i2c-lcd
+Info: Configures an HD44780 compatible LCD display connected via a PCF8574 as
+ is often found as a backpack interface for these displays.
+Load: dtoverlay=hd44780-i2c-lcd,<param>=<val>
+Params: addr I2C address of PCF8574
+ pin_d4 GPIO pin for data pin D4 (default 4)
+
+ pin_d5 GPIO pin for data pin D5 (default 5)
+
+ pin_d6 GPIO pin for data pin D6 (default 6)
+
+ pin_d7 GPIO pin for data pin D7 (default 7)
+
+ pin_en GPIO pin for "Enable" (default 2)
+
+ pin_rs GPIO pin for "Register Select" (default 0)
+
+ pin_rw GPIO pin for R/W select (default 1)
+
+ pin_bl GPIO pin for enabling/disabling the display
+ backlight. (default 3)
+
+ display_height Height of the display in characters (default 2)
+
+ display_width Width of the display in characters (default 16)
+
+
Name: hd44780-lcd
Info: Configures an HD44780 compatible LCD display. Uses 4 gpio pins for
data, 2 gpio pins for enable and register select and 1 optional pin
--- /dev/null
+++ b/arch/arm/boot/dts/overlays/hd44780-i2c-lcd-overlay.dts
@@ -0,0 +1,57 @@
+/dts-v1/;
+/plugin/;
+
+/ {
+ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2c_arm>;
+ __overlay__ {
+ status = "okay";
+
+ pcf857x: pcf857x@27 {
+ compatible = "nxp,pcf8574";
+ reg = <0x27>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ status = "okay";
+ };
+ };
+ };
+
+ fragment@1 {
+ target-path = "/";
+ __overlay__ {
+ lcd_screen: auxdisplay {
+ compatible = "hit,hd44780";
+
+ data-gpios = <&pcf857x 4 0>,
+ <&pcf857x 5 0>,
+ <&pcf857x 6 0>,
+ <&pcf857x 7 0>;
+ enable-gpios = <&pcf857x 2 0>;
+ rs-gpios = <&pcf857x 0 0>;
+ rw-gpios = <&pcf857x 1 0>;
+ backlight-gpios = <&pcf857x 3 0>;
+
+ display-width-chars = <16>;
+ display-height-chars = <2>;
+ };
+ };
+ };
+
+ __overrides__ {
+ pin_d4 = <&lcd_screen>,"data-gpios:4";
+ pin_d5 = <&lcd_screen>,"data-gpios:16";
+ pin_d6 = <&lcd_screen>,"data-gpios:28";
+ pin_d7 = <&lcd_screen>,"data-gpios:40";
+ pin_en = <&lcd_screen>,"enable-gpios:4";
+ pin_rs = <&lcd_screen>,"rs-gpios:4";
+ pin_rw = <&lcd_screen>,"rw-gpios:4";
+ pin_bl = <&lcd_screen>,"backlight-gpios:4";
+ display_height = <&lcd_screen>,"display-height-chars:0";
+ display_width = <&lcd_screen>,"display-width-chars:0";
+ addr = <&pcf857x>,"reg:0";
+ };
+
+};

View File

@ -0,0 +1,28 @@
From 3c319a466a1c718f66c471a9d5ec60de6de44612 Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
Date: Fri, 2 Aug 2024 10:41:28 +0100
Subject: [PATCH 1207/1215] dtoverlays: Document display_[width|height] on
hd44780-lcd overlay
The default values defining a 16x2 display weren't documented,
so add them.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
arch/arm/boot/dts/overlays/README | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
--- a/arch/arm/boot/dts/overlays/README
+++ b/arch/arm/boot/dts/overlays/README
@@ -1752,9 +1752,9 @@ Params: pin_d4 GPIO pin
pin_bl Optional pin for enabling/disabling the
display backlight. (default disabled)
- display_height Height of the display in characters
+ display_height Height of the display in characters (default 2)
- display_width Width of the display in characters
+ display_width Width of the display in characters (default 16)
Name: hdmi-backlight-hwhack-gpio

View File

@ -0,0 +1,39 @@
From 216df57950849f905c398904e7d6cbdf278b5717 Mon Sep 17 00:00:00 2001
From: Jonathan Bell <jonathan@raspberrypi.com>
Date: Mon, 5 Aug 2024 11:28:36 +0100
Subject: [PATCH 1208/1215] DTS: bcm2712: enable SD slot CQE by default on Pi 5
The corresponding driver implementation has seen sufficient testing,
so enable by default. Retain the dtparam so it can be turned off for test.
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
---
arch/arm/boot/dts/overlays/README | 6 +++---
arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts | 1 +
2 files changed, 4 insertions(+), 3 deletions(-)
--- a/arch/arm/boot/dts/overlays/README
+++ b/arch/arm/boot/dts/overlays/README
@@ -378,9 +378,9 @@ Params:
non-lite SKU of CM4).
(default "on")
- sd_cqe Use to enable Command Queueing on the SD
- interface for faster Class A2 card performance
- (Pi 5 only, default "off")
+ sd_cqe Set to "off" to disable Command Queueing if you
+ have an incompatible Class A2 SD card
+ (Pi 5 only, default "on")
sd_overclock Clock (in MHz) to use when the MMC framework
requests 50MHz
--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts
+++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts
@@ -363,6 +363,7 @@ dpi_16bit_gpio2: &rp1_dpi_16bit_g
sd-uhs-sdr50;
sd-uhs-ddr50;
sd-uhs-sdr104;
+ supports-cqe;
cd-gpios = <&gio_aon 5 GPIO_ACTIVE_LOW>;
//no-1-8-v;
status = "okay";

View File

@ -0,0 +1,50 @@
From 53b9d9bbb57e292c6b332a2fb9899003586e17ca Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
Date: Thu, 2 May 2024 16:17:02 +0100
Subject: [PATCH 1211/1215] gpiolib: Override gpiochip numbers with DT aliases
In the same way that other subsystems support the setting of device
id numbers from Device Tree aliases, allow gpiochip numbers to be
derived from "gpiochip<n>" aliases.
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
---
drivers/gpio/gpiolib.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -110,6 +110,7 @@ static int gpiochip_irqchip_init_valid_m
static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gc);
static bool gpiolib_initialized;
+static int first_dynamic_gpiochip_num = -1;
static inline void desc_set_label(struct gpio_desc *d, const char *label)
{
@@ -745,6 +746,7 @@ int gpiochip_add_data_with_key(struct gp
unsigned int i;
int base = 0;
int ret = 0;
+ int id;
/*
* First: allocate and populate the internal stat container, and
@@ -769,7 +771,16 @@ int gpiochip_add_data_with_key(struct gp
else if (gc->parent)
device_set_node(&gdev->dev, dev_fwnode(gc->parent));
- gdev->id = ida_alloc(&gpio_ida, GFP_KERNEL);
+ if (first_dynamic_gpiochip_num < 0) {
+ id = of_alias_get_highest_id("gpiochip");
+ first_dynamic_gpiochip_num = (id >= 0) ? (id + 1) : 0;
+ }
+
+ id = of_alias_get_id(gdev->dev.of_node, "gpiochip");
+ if (id < 0)
+ id = first_dynamic_gpiochip_num;
+
+ gdev->id = ida_alloc_range(&gpio_ida, id, ~0, GFP_KERNEL);
if (gdev->id < 0) {
ret = gdev->id;
goto err_free_gdev;

View File

@ -0,0 +1,23 @@
From 1162316fd26eeb4193b23fcc1bb332f42938aa70 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
Date: Thu, 2 May 2024 16:58:59 +0100
Subject: [PATCH 1212/1215] dts: bcm2712-rpi: Add gpiochip0 alias
Add a gpiochip0 aliase pointing to the rp1 GPIO node, making it appear
as gpiochip0.
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
---
arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi | 1 +
1 file changed, 1 insertion(+)
--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi
+++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi
@@ -112,6 +112,7 @@
gpio2 = &gio_aon;
gpio3 = &pinctrl;
gpio4 = &pinctrl_aon;
+ gpiochip0 = &gpio;
i2c = &i2c_arm;
i2c0 = &i2c0;
i2c1 = &i2c1;

View File

@ -0,0 +1,24 @@
From 70c640ce992234aacba5a717f3fb47319f451431 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
Date: Thu, 2 May 2024 17:40:25 +0100
Subject: [PATCH 1213/1215] dts: bcm2712-rpi: The SoC gpiochips start at 10
Make the BCM2712's onboard GPIOs start at gpiochip10, marking them out
as system resources and preventing accidental use by existing Pi 5
code.
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
---
arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi | 1 +
1 file changed, 1 insertion(+)
--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi
+++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi
@@ -113,6 +113,7 @@
gpio3 = &pinctrl;
gpio4 = &pinctrl_aon;
gpiochip0 = &gpio;
+ gpiochip10 = &gio;
i2c = &i2c_arm;
i2c0 = &i2c0;
i2c1 = &i2c1;