mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-19 12:00:00 +00:00
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:
parent
f399051ec1
commit
25d2847158
@ -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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user