From 02d6db7ff11ad8fadd105432f3373e9b48697828 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 15 Jun 2026 16:24:55 +0100 Subject: [PATCH 1/2] misc: rp1-pio: Include maxburst in PIO_DMACTRL The PIO DMA interface exposes empty/not empty signals as well as the threshold signals required for bursts. If the FIFO is not ready for a burst, a single beat burst can still be performed. It is therefore safe to set the PIO FIFO thresholds to the burst size used by the DMA controller. See: https://forums.raspberrypi.com/viewtopic.php?t=398882 Signed-off-by: Phil Elwell --- drivers/misc/rp1-pio.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/misc/rp1-pio.c b/drivers/misc/rp1-pio.c index 24c1cc5f887b77..89fa7f53ca2c39 100644 --- a/drivers/misc/rp1-pio.c +++ b/drivers/misc/rp1-pio.c @@ -50,7 +50,9 @@ #define RP1_PIO_FIFO_RX2 0x18 #define RP1_PIO_FIFO_RX3 0x1c -#define RP1_PIO_DMACTRL_DEFAULT 0x80000104 +#define RP1_PIO_FIFO_DEPTH 8 + +#define RP1_PIO_DMACTRL_DEFAULT 0x80000100 #define HANDLER(_n, _f) \ [_IOC_NR(PIO_IOC_ ## _n)] = { #_n, rp1_pio_ ## _f, _IOC_SIZE(PIO_IOC_ ## _n) } @@ -679,6 +681,8 @@ static int rp1_pio_sm_config_xfer_internal(struct rp1_pio_client *client, uint s config.direction = (dir == RP1_PIO_DIR_TO_SM) ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; dma_caps.max_burst = 4; dma_get_slave_caps(dma->chan, &dma_caps); + if (dma_caps.max_burst > RP1_PIO_FIFO_DEPTH) + dma_caps.max_burst = RP1_PIO_FIFO_DEPTH; if (dir == RP1_PIO_DIR_TO_SM) config.dst_maxburst = dma_caps.max_burst; else @@ -690,9 +694,11 @@ static int rp1_pio_sm_config_xfer_internal(struct rp1_pio_client *client, uint s set_dmactrl_args.sm = sm; set_dmactrl_args.is_tx = (dir == RP1_PIO_DIR_TO_SM); - set_dmactrl_args.ctrl = RP1_PIO_DMACTRL_DEFAULT; if (dir == RP1_PIO_DIR_FROM_SM) - set_dmactrl_args.ctrl = (RP1_PIO_DMACTRL_DEFAULT & ~0x1f) | 1; + set_dmactrl_args.ctrl = RP1_PIO_DMACTRL_DEFAULT | config.src_maxburst; + else + set_dmactrl_args.ctrl = RP1_PIO_DMACTRL_DEFAULT | + (RP1_PIO_FIFO_DEPTH - config.dst_maxburst); ret = rp1_pio_sm_set_dmactrl(client, &set_dmactrl_args); if (ret) From 7cfdd3fbcc82d989686d4e655b96070c0750aaba Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 16 Jun 2026 12:48:50 +0100 Subject: [PATCH 2/2] misc: rp1-pio: Ensure transfers are configured Fail transfers if they haven't first been configured. Signed-off-by: Phil Elwell --- drivers/misc/rp1-pio.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/drivers/misc/rp1-pio.c b/drivers/misc/rp1-pio.c index 89fa7f53ca2c39..e9a437bcc0b2fa 100644 --- a/drivers/misc/rp1-pio.c +++ b/drivers/misc/rp1-pio.c @@ -615,7 +615,7 @@ static int rp1_pio_sm_config_xfer_internal(struct rp1_pio_client *client, uint s struct dma_slave_config config = {}; struct dma_slave_caps dma_caps; phys_addr_t fifo_addr; - struct dma_info *dma; + struct dma_info *dma = NULL; uint32_t dma_mask; char chan_name[4]; int ret = 0; @@ -629,14 +629,17 @@ static int rp1_pio_sm_config_xfer_internal(struct rp1_pio_client *client, uint s dma_mask = 1 << (sm * 2 + dir); - dma = &pio->dma_configs[sm][dir]; - spin_lock(&pio->lock); - if (pio->claimed_dmas & dma_mask) - rp1_pio_sm_dma_free(dev, dma); - pio->claimed_dmas |= dma_mask; - client->claimed_dmas |= dma_mask; + if (!(pio->claimed_dmas & dma_mask & ~client->claimed_dmas)) { + dma = &pio->dma_configs[sm][dir]; + if (client->claimed_dmas & dma_mask) + rp1_pio_sm_dma_free(dev, dma); + pio->claimed_dmas |= dma_mask; + client->claimed_dmas |= dma_mask; + } spin_unlock(&pio->lock); + if (!dma) + return -EBUSY; dma->buf_size = buf_size; /* Round up the allocations */ @@ -879,13 +882,20 @@ static int rp1_pio_sm_xfer_data32_user(struct rp1_pio_client *client, void *para { struct rp1_pio_sm_xfer_data32_args *args = param; struct rp1_pio_device *pio = client->pio; - struct dma_info *dma; + struct dma_info *dma = NULL; + uint32_t dma_mask; if (args->sm >= RP1_PIO_SMS_COUNT || args->dir >= RP1_PIO_DIR_COUNT || !args->data_bytes || !args->data) return -EINVAL; - dma = &pio->dma_configs[args->sm][args->dir]; + dma_mask = 1 << (args->sm * 2 + args->dir); + spin_lock(&pio->lock); + if (client->claimed_dmas & dma_mask) + dma = &pio->dma_configs[args->sm][args->dir]; + spin_unlock(&pio->lock); + if (!dma) + return -EINVAL; if (args->dir == RP1_PIO_DIR_TO_SM) return rp1_pio_sm_tx_user(pio, dma, args->data, args->data_bytes);