mtd: rawnand: cadence: support 64-bit slave dma interface

32-bit accesses on 64-bit sdma trigger sdma_err in intr_status register.

Check dma capabilities before reading/writing from/to sdma interface.

Link: https://lore.kernel.org/all/b7e5ebb4-0de8-4958-9bc4-fe06ec4c3635@www.fastmail.com/t/

Signed-off-by: Valentin Korenblit <vkorenblit@sequans.com>
Reviewed-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Link: https://lore.kernel.org/linux-mtd/20221018093000.12072-1-vkorenblit@sequans.com
This commit is contained in:
Valentin Korenblit 2022-10-18 11:30:00 +02:00 committed by Miquel Raynal
parent 6154c7a583
commit 7c3fc99819
1 changed files with 58 additions and 12 deletions

View File

@ -1184,6 +1184,14 @@ static int cadence_nand_hw_init(struct cdns_nand_ctrl *cdns_ctrl)
if (cadence_nand_read_bch_caps(cdns_ctrl))
return -EIO;
#ifndef CONFIG_64BIT
if (cdns_ctrl->caps2.data_dma_width == 8) {
dev_err(cdns_ctrl->dev,
"cannot access 64-bit dma on !64-bit architectures");
return -EIO;
}
#endif
/*
* Set IO width access to 8.
* It is because during SW device discovering width access
@ -1882,17 +1890,36 @@ static int cadence_nand_read_buf(struct cdns_nand_ctrl *cdns_ctrl,
return status;
if (!cdns_ctrl->caps1->has_dma) {
int len_in_words = len >> 2;
u8 data_dma_width = cdns_ctrl->caps2.data_dma_width;
int len_in_words = (data_dma_width == 4) ? len >> 2 : len >> 3;
/* read alingment data */
ioread32_rep(cdns_ctrl->io.virt, buf, len_in_words);
if (data_dma_width == 4)
ioread32_rep(cdns_ctrl->io.virt, buf, len_in_words);
#ifdef CONFIG_64BIT
else
readsq(cdns_ctrl->io.virt, buf, len_in_words);
#endif
if (sdma_size > len) {
int read_bytes = (data_dma_width == 4) ?
len_in_words << 2 : len_in_words << 3;
/* read rest data from slave DMA interface if any */
ioread32_rep(cdns_ctrl->io.virt, cdns_ctrl->buf,
sdma_size / 4 - len_in_words);
if (data_dma_width == 4)
ioread32_rep(cdns_ctrl->io.virt,
cdns_ctrl->buf,
sdma_size / 4 - len_in_words);
#ifdef CONFIG_64BIT
else
readsq(cdns_ctrl->io.virt, cdns_ctrl->buf,
sdma_size / 8 - len_in_words);
#endif
/* copy rest of data */
memcpy(buf + (len_in_words << 2), cdns_ctrl->buf,
len - (len_in_words << 2));
memcpy(buf + read_bytes, cdns_ctrl->buf,
len - read_bytes);
}
return 0;
}
@ -1936,16 +1963,35 @@ static int cadence_nand_write_buf(struct cdns_nand_ctrl *cdns_ctrl,
return status;
if (!cdns_ctrl->caps1->has_dma) {
int len_in_words = len >> 2;
u8 data_dma_width = cdns_ctrl->caps2.data_dma_width;
int len_in_words = (data_dma_width == 4) ? len >> 2 : len >> 3;
if (data_dma_width == 4)
iowrite32_rep(cdns_ctrl->io.virt, buf, len_in_words);
#ifdef CONFIG_64BIT
else
writesq(cdns_ctrl->io.virt, buf, len_in_words);
#endif
iowrite32_rep(cdns_ctrl->io.virt, buf, len_in_words);
if (sdma_size > len) {
int written_bytes = (data_dma_width == 4) ?
len_in_words << 2 : len_in_words << 3;
/* copy rest of data */
memcpy(cdns_ctrl->buf, buf + (len_in_words << 2),
len - (len_in_words << 2));
memcpy(cdns_ctrl->buf, buf + written_bytes,
len - written_bytes);
/* write all expected by nand controller data */
iowrite32_rep(cdns_ctrl->io.virt, cdns_ctrl->buf,
sdma_size / 4 - len_in_words);
if (data_dma_width == 4)
iowrite32_rep(cdns_ctrl->io.virt,
cdns_ctrl->buf,
sdma_size / 4 - len_in_words);
#ifdef CONFIG_64BIT
else
writesq(cdns_ctrl->io.virt, cdns_ctrl->buf,
sdma_size / 8 - len_in_words);
#endif
}
return 0;