spi: spi-mem: rtl-snand: Correctly handle DMA transfers

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: 42d20a6a61b8 ("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>
This commit is contained in:
Chris Packham 2024-10-31 08:49:20 +13:00 committed by Mark Brown
parent f399051ec1
commit 25d2847158
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0

View File

@ -231,19 +231,22 @@ out_deselect:
static int rtl_snand_dma_xfer(struct rtl_snand *snand, int cs, const struct spi_mem_op *op) static int rtl_snand_dma_xfer(struct rtl_snand *snand, int cs, const struct spi_mem_op *op)
{ {
unsigned int pos, nbytes;
int ret; int ret;
dma_addr_t buf_dma; dma_addr_t buf_dma;
enum dma_data_direction dir; enum dma_data_direction dir;
u32 trig; u32 trig, len, maxlen;
ret = rtl_snand_xfer_head(snand, cs, op); ret = rtl_snand_xfer_head(snand, cs, op);
if (ret) if (ret)
goto out_deselect; goto out_deselect;
if (op->data.dir == SPI_MEM_DATA_IN) { if (op->data.dir == SPI_MEM_DATA_IN) {
maxlen = 2080;
dir = DMA_FROM_DEVICE; dir = DMA_FROM_DEVICE;
trig = 0; trig = 0;
} else if (op->data.dir == SPI_MEM_DATA_OUT) { } else if (op->data.dir == SPI_MEM_DATA_OUT) {
maxlen = 520;
dir = DMA_TO_DEVICE; dir = DMA_TO_DEVICE;
trig = 1; trig = 1;
} else { } else {
@ -264,14 +267,24 @@ static int rtl_snand_dma_xfer(struct rtl_snand *snand, int cs, const struct spi_
if (ret) if (ret)
goto out_unmap; goto out_unmap;
pos = 0;
len = op->data.nbytes;
while (pos < len) {
nbytes = len - pos;
if (nbytes > maxlen)
nbytes = maxlen;
reinit_completion(&snand->comp); reinit_completion(&snand->comp);
ret = regmap_write(snand->regmap, SNAFDRSAR, buf_dma); ret = regmap_write(snand->regmap, SNAFDRSAR, buf_dma + pos);
if (ret) if (ret)
goto out_disable_int; goto out_disable_int;
pos += nbytes;
ret = regmap_write(snand->regmap, SNAFDLR, ret = regmap_write(snand->regmap, SNAFDLR,
CMR_WID(op->data.buswidth) | (op->data.nbytes & 0xffff)); CMR_WID(op->data.buswidth) | nbytes);
if (ret) if (ret)
goto out_disable_int; goto out_disable_int;
@ -284,6 +297,7 @@ static int rtl_snand_dma_xfer(struct rtl_snand *snand, int cs, const struct spi_
if (ret) if (ret)
goto out_disable_int; goto out_disable_int;
}
out_disable_int: out_disable_int:
regmap_update_bits(snand->regmap, SNAFCFR, SNAFCFR_DMA_IE, 0); regmap_update_bits(snand->regmap, SNAFCFR, SNAFCFR_DMA_IE, 0);