]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
mtd: rawnand: cadence: support 64-bit slave dma interface
authorValentin Korenblit <vkorenblit@sequans.com>
Tue, 18 Oct 2022 09:30:00 +0000 (11:30 +0200)
committerMiquel Raynal <miquel.raynal@bootlin.com>
Tue, 18 Oct 2022 09:41:30 +0000 (11:41 +0200)
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
drivers/mtd/nand/raw/cadence-nand-controller.c

index 9dac3ca69d576e085c7b07479796ea5013d8c23f..7661a5cf1883a6c6c387721cdb85ad8e88046838 100644 (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;