OSDN Git Service

spi: spi-ti-qspi: support large flash devices
authorJean Pihet <jean.pihet@newoldbits.com>
Tue, 14 Jan 2020 12:41:24 +0000 (13:41 +0100)
committerMark Brown <broonie@kernel.org>
Tue, 14 Jan 2020 15:25:46 +0000 (15:25 +0000)
The TI QSPI IP has limitations:
- the MMIO region is 64MB in size
- in non-MMIO mode, the transfer can handle 4096 words max.

Add support for bigger devices.
Use MMIO and DMA transfers below the 64MB boundary, use
software generated transfers above.

Signed-off-by: Jean Pihet <jean.pihet@newoldbits.com>
Cc: Ryan Barnett <ryan.barnett@rockwellcollins.com>
Cc: Conrad Ratschan <conrad.ratschan@rockwellcollins.com>
Cc: Arnout Vandecappelle <arnout.vandecappelle@essensium.com>
Link: https://lore.kernel.org/r/20200114124125.361429-2-jean.pihet@newoldbits.com
Signed-off-by: Mark Brown <broonie@kernel.org>
drivers/spi/spi-ti-qspi.c

index ad2942b..0334e29 100644 (file)
@@ -525,6 +525,35 @@ static void ti_qspi_setup_mmap_read(struct spi_device *spi, u8 opcode,
                      QSPI_SPI_SETUP_REG(spi->chip_select));
 }
 
+static int ti_qspi_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
+{
+       struct ti_qspi *qspi = spi_controller_get_devdata(mem->spi->master);
+       size_t max_len;
+
+       if (op->data.dir == SPI_MEM_DATA_IN) {
+               if (op->addr.val < qspi->mmap_size) {
+                       /* Limit MMIO to the mmaped region */
+                       if (op->addr.val + op->data.nbytes > qspi->mmap_size) {
+                               max_len = qspi->mmap_size - op->addr.val;
+                               op->data.nbytes = min((size_t) op->data.nbytes,
+                                                     max_len);
+                       }
+               } else {
+                       /*
+                        * Use fallback mode (SW generated transfers) above the
+                        * mmaped region.
+                        * Adjust size to comply with the QSPI max frame length.
+                        */
+                       max_len = QSPI_FRAME;
+                       max_len -= 1 + op->addr.nbytes + op->dummy.nbytes;
+                       op->data.nbytes = min((size_t) op->data.nbytes,
+                                             max_len);
+               }
+       }
+
+       return 0;
+}
+
 static int ti_qspi_exec_mem_op(struct spi_mem *mem,
                               const struct spi_mem_op *op)
 {
@@ -575,6 +604,7 @@ static int ti_qspi_exec_mem_op(struct spi_mem *mem,
 
 static const struct spi_controller_mem_ops ti_qspi_mem_ops = {
        .exec_op = ti_qspi_exec_mem_op,
+       .adjust_op_size = ti_qspi_adjust_op_size,
 };
 
 static int ti_qspi_start_transfer_one(struct spi_master *master,