Skip to content

Commit

Permalink
spi: spi-mem: rtl-snand: Correctly handle DMA transfers
Browse files Browse the repository at this point in the history
The RTL9300 has some limitations on the maximum DMA transfers possible.
For reads this is 2080 bytes (520*4) for writes this is 520 bytes. Deal
with this by splitting transfers into appropriately sized parts.

Fixes: 42d20a6 ("spi: spi-mem: Add Realtek SPI-NAND controller")
Signed-off-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
Link: https://patch.msgid.link/20241030194920.3202282-1-chris.packham@alliedtelesis.co.nz
Signed-off-by: Mark Brown <broonie@kernel.org>
  • Loading branch information
cpackham-atlnz authored and broonie committed Nov 1, 2024
1 parent f399051 commit 25d2847
Showing 1 changed file with 30 additions and 16 deletions.
46 changes: 30 additions & 16 deletions drivers/spi/spi-realtek-rtl-snand.c
Original file line number Diff line number Diff line change
Expand Up @@ -231,19 +231,22 @@ static int rtl_snand_xfer(struct rtl_snand *snand, int cs, const struct spi_mem_

static int rtl_snand_dma_xfer(struct rtl_snand *snand, int cs, const struct spi_mem_op *op)
{
unsigned int pos, nbytes;
int ret;
dma_addr_t buf_dma;
enum dma_data_direction dir;
u32 trig;
u32 trig, len, maxlen;

ret = rtl_snand_xfer_head(snand, cs, op);
if (ret)
goto out_deselect;

if (op->data.dir == SPI_MEM_DATA_IN) {
maxlen = 2080;
dir = DMA_FROM_DEVICE;
trig = 0;
} else if (op->data.dir == SPI_MEM_DATA_OUT) {
maxlen = 520;
dir = DMA_TO_DEVICE;
trig = 1;
} else {
Expand All @@ -264,26 +267,37 @@ static int rtl_snand_dma_xfer(struct rtl_snand *snand, int cs, const struct spi_
if (ret)
goto out_unmap;

reinit_completion(&snand->comp);
pos = 0;
len = op->data.nbytes;

ret = regmap_write(snand->regmap, SNAFDRSAR, buf_dma);
if (ret)
goto out_disable_int;
while (pos < len) {
nbytes = len - pos;
if (nbytes > maxlen)
nbytes = maxlen;

ret = regmap_write(snand->regmap, SNAFDLR,
CMR_WID(op->data.buswidth) | (op->data.nbytes & 0xffff));
if (ret)
goto out_disable_int;
reinit_completion(&snand->comp);

ret = regmap_write(snand->regmap, SNAFDTR, trig);
if (ret)
goto out_disable_int;
ret = regmap_write(snand->regmap, SNAFDRSAR, buf_dma + pos);
if (ret)
goto out_disable_int;

if (!wait_for_completion_timeout(&snand->comp, usecs_to_jiffies(20000)))
ret = -ETIMEDOUT;
pos += nbytes;

if (ret)
goto out_disable_int;
ret = regmap_write(snand->regmap, SNAFDLR,
CMR_WID(op->data.buswidth) | nbytes);
if (ret)
goto out_disable_int;

ret = regmap_write(snand->regmap, SNAFDTR, trig);
if (ret)
goto out_disable_int;

if (!wait_for_completion_timeout(&snand->comp, usecs_to_jiffies(20000)))
ret = -ETIMEDOUT;

if (ret)
goto out_disable_int;
}

out_disable_int:
regmap_update_bits(snand->regmap, SNAFCFR, SNAFCFR_DMA_IE, 0);
Expand Down

0 comments on commit 25d2847

Please sign in to comment.