diff --git a/drivers/misc/rp1-pio.c b/drivers/misc/rp1-pio.c index 24c1cc5f887b77..e9a437bcc0b2fa 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) } @@ -613,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; @@ -627,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 */ @@ -679,6 +684,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 +697,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) @@ -873,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);