aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/spi/Kconfig8
-rw-r--r--drivers/spi/fsl_qspi.c114
2 files changed, 98 insertions, 24 deletions
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 3a8add98f76..30d808d7bb2 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -155,6 +155,14 @@ config FSL_QSPI
used to access the SPI NOR flash on platforms embedding this
Freescale IP core.
+config FSL_QSPI_AHB_FULL_MAP
+ bool "Use full AHB memory map space"
+ depends on FSL_QSPI
+ default y if ARCH_MX6 || ARCH_MX7 || ARCH_MX7ULP || ARCH_IMX8M
+ help
+ Enable the Freescale QSPI driver to use full AHB memory map space for
+ flash access.
+
config ICH_SPI
bool "Intel ICH SPI driver"
help
diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c
index d9f531a2a54..eec968e5ec1 100644
--- a/drivers/spi/fsl_qspi.c
+++ b/drivers/spi/fsl_qspi.c
@@ -46,6 +46,7 @@ DECLARE_GLOBAL_DATA_PTR;
* read operation, so let's use the last entry (15).
*/
#define SEQID_LUT 15
+#define SEQID_LUT_AHB 14
/* Registers used by the driver */
#define QUADSPI_MCR 0x00
@@ -122,6 +123,10 @@ DECLARE_GLOBAL_DATA_PTR;
#define QUADSPI_LUT_REG(idx) \
(QUADSPI_LUT_BASE + QUADSPI_LUT_OFFSET + (idx) * 4)
+#define QUADSPI_AHB_LUT_OFFSET (SEQID_LUT_AHB * 4 * 4)
+#define QUADSPI_AHB_LUT_REG(idx) \
+ (QUADSPI_LUT_BASE + QUADSPI_AHB_LUT_OFFSET + (idx) * 4)
+
/* Instruction set for the LUT register */
#define LUT_STOP 0
#define LUT_CMD 1
@@ -189,6 +194,11 @@ DECLARE_GLOBAL_DATA_PTR;
*/
#define QUADSPI_QUIRK_USE_TDH_SETTING BIT(5)
+/*
+ * Controller only has Two CS on flash A, no flash B port
+ */
+#define QUADSPI_QUIRK_SINGLE_BUS BIT(6)
+
struct fsl_qspi_devtype_data {
unsigned int rxfifo;
unsigned int txfifo;
@@ -236,7 +246,7 @@ static const struct fsl_qspi_devtype_data imx7ulp_data = {
.txfifo = SZ_64,
.ahb_buf_size = SZ_128,
.quirks = QUADSPI_QUIRK_TKT253890 | QUADSPI_QUIRK_4X_INT_CLK |
- QUADSPI_QUIRK_USE_TDH_SETTING,
+ QUADSPI_QUIRK_USE_TDH_SETTING | QUADSPI_QUIRK_SINGLE_BUS,
.little_endian = true,
};
@@ -269,6 +279,7 @@ struct fsl_qspi {
void __iomem *iobase;
void __iomem *ahb_addr;
u32 memmap_phy;
+ u32 memmap_size;
const struct fsl_qspi_devtype_data *devtype_data;
int selected;
};
@@ -303,6 +314,11 @@ static inline int needs_tdh_setting(struct fsl_qspi *q)
return q->devtype_data->quirks & QUADSPI_QUIRK_USE_TDH_SETTING;
}
+static inline int needs_single_bus(struct fsl_qspi *q)
+{
+ return q->devtype_data->quirks & QUADSPI_QUIRK_SINGLE_BUS;
+}
+
/*
* An IC bug makes it necessary to rearrange the 32-bit data.
* Later chips, such as IMX6SLX, have fixed this bug.
@@ -405,18 +421,27 @@ static void fsl_qspi_prepare_lut(struct fsl_qspi *q,
lutval[0] |= LUT_DEF(0, LUT_CMD, LUT_PAD(op->cmd.buswidth),
op->cmd.opcode);
- /*
- * For some unknown reason, using LUT_ADDR doesn't work in some
- * cases (at least with only one byte long addresses), so
- * let's use LUT_MODE to write the address bytes one by one
- */
- for (i = 0; i < op->addr.nbytes; i++) {
- u8 addrbyte = op->addr.val >> (8 * (op->addr.nbytes - i - 1));
-
- lutval[lutidx / 2] |= LUT_DEF(lutidx, LUT_MODE,
- LUT_PAD(op->addr.buswidth),
- addrbyte);
- lutidx++;
+ if (IS_ENABLED(CONFIG_FSL_QSPI_AHB_FULL_MAP)) {
+ if (op->addr.nbytes) {
+ lutval[lutidx / 2] |= LUT_DEF(lutidx, LUT_ADDR,
+ LUT_PAD(op->addr.buswidth),
+ (op->addr.nbytes == 4) ? 0x20 : 0x18);
+ lutidx++;
+ }
+ } else {
+ /*
+ * For some unknown reason, using LUT_ADDR doesn't work in some
+ * cases (at least with only one byte long addresses), so
+ * let's use LUT_MODE to write the address bytes one by one
+ */
+ for (i = 0; i < op->addr.nbytes; i++) {
+ u8 addrbyte = op->addr.val >> (8 * (op->addr.nbytes - i - 1));
+
+ lutval[lutidx / 2] |= LUT_DEF(lutidx, LUT_MODE,
+ LUT_PAD(op->addr.buswidth),
+ addrbyte);
+ lutidx++;
+ }
}
if (op->dummy.nbytes) {
@@ -449,6 +474,14 @@ static void fsl_qspi_prepare_lut(struct fsl_qspi *q,
for (i = 0; i < ARRAY_SIZE(lutval); i++)
qspi_writel(q, lutval[i], base + QUADSPI_LUT_REG(i));
+ if (IS_ENABLED(CONFIG_FSL_QSPI_AHB_FULL_MAP)) {
+ if (op->data.nbytes && op->data.dir == SPI_MEM_DATA_IN &&
+ op->addr.nbytes) {
+ for (i = 0; i < ARRAY_SIZE(lutval); i++)
+ qspi_writel(q, lutval[i], base + QUADSPI_AHB_LUT_REG(i));
+ }
+ }
+
/* lock LUT */
qspi_writel(q, QUADSPI_LUTKEY_VALUE, q->iobase + QUADSPI_LUTKEY);
qspi_writel(q, QUADSPI_LCKER_LOCK, q->iobase + QUADSPI_LCKCR);
@@ -491,10 +524,29 @@ static void fsl_qspi_select_mem(struct fsl_qspi *q, struct spi_slave *slave)
fsl_qspi_invalidate(q);
}
+static u32 fsl_qspi_memsize_per_cs(struct fsl_qspi *q)
+{
+ if (IS_ENABLED(CONFIG_FSL_QSPI_AHB_FULL_MAP)) {
+ if (needs_single_bus(q))
+ return q->memmap_size / 2;
+ else
+ return q->memmap_size / 4;
+ } else {
+ return ALIGN(q->devtype_data->ahb_buf_size, 0x400);
+ }
+}
+
static void fsl_qspi_read_ahb(struct fsl_qspi *q, const struct spi_mem_op *op)
{
+ void __iomem *ahb_read_addr = q->ahb_addr;
+
+ if (IS_ENABLED(CONFIG_FSL_QSPI_AHB_FULL_MAP)) {
+ if (op->addr.nbytes)
+ ahb_read_addr += op->addr.val;
+ }
+
memcpy_fromio(op->data.buf.in,
- q->ahb_addr + q->selected * ALIGN(q->devtype_data->ahb_buf_size, 0x400),
+ ahb_read_addr + q->selected * fsl_qspi_memsize_per_cs(q),
op->data.nbytes);
}
@@ -597,8 +649,13 @@ static int fsl_qspi_exec_op(struct spi_slave *slave,
if (needs_amba_base_offset(q))
addr_offset = q->memmap_phy;
+ if (IS_ENABLED(CONFIG_FSL_QSPI_AHB_FULL_MAP)) {
+ if (op->addr.nbytes)
+ addr_offset += op->addr.val;
+ }
+
qspi_writel(q,
- q->selected * ALIGN(q->devtype_data->ahb_buf_size, 0x400) + addr_offset,
+ q->selected * fsl_qspi_memsize_per_cs(q) + addr_offset,
base + QUADSPI_SFAR);
qspi_writel(q, qspi_readl(q, base + QUADSPI_MCR) |
@@ -655,7 +712,7 @@ static int fsl_qspi_adjust_op_size(struct spi_slave *slave,
static int fsl_qspi_default_setup(struct fsl_qspi *q)
{
void __iomem *base = q->iobase;
- u32 reg, addr_offset = 0;
+ u32 reg, addr_offset = 0, memsize_cs;
/* Reset the module */
qspi_writel(q, QUADSPI_MCR_SWRSTSD_MASK | QUADSPI_MCR_SWRSTHD_MASK,
@@ -687,8 +744,13 @@ static int fsl_qspi_default_setup(struct fsl_qspi *q)
qspi_writel(q, 0, base + QUADSPI_BUF1IND);
qspi_writel(q, 0, base + QUADSPI_BUF2IND);
- qspi_writel(q, QUADSPI_BFGENCR_SEQID(SEQID_LUT),
- q->iobase + QUADSPI_BFGENCR);
+ if (IS_ENABLED(CONFIG_FSL_QSPI_AHB_FULL_MAP))
+ qspi_writel(q, QUADSPI_BFGENCR_SEQID(SEQID_LUT_AHB),
+ q->iobase + QUADSPI_BFGENCR);
+ else
+ qspi_writel(q, QUADSPI_BFGENCR_SEQID(SEQID_LUT),
+ q->iobase + QUADSPI_BFGENCR);
+
qspi_writel(q, QUADSPI_RBCT_WMRK_MASK, base + QUADSPI_RBCT);
qspi_writel(q, QUADSPI_BUF3CR_ALLMST_MASK |
QUADSPI_BUF3CR_ADATSZ(q->devtype_data->ahb_buf_size / 8),
@@ -704,14 +766,17 @@ static int fsl_qspi_default_setup(struct fsl_qspi *q)
* We use ahb_buf_size for each chip and set SFA1AD, SFA2AD, SFB1AD,
* SFB2AD accordingly.
*/
- qspi_writel(q, ALIGN(q->devtype_data->ahb_buf_size, 0x400) + addr_offset,
+ memsize_cs = fsl_qspi_memsize_per_cs(q);
+ qspi_writel(q, memsize_cs + addr_offset,
base + QUADSPI_SFA1AD);
- qspi_writel(q, ALIGN(q->devtype_data->ahb_buf_size, 0x400) * 2 + addr_offset,
+ qspi_writel(q, memsize_cs * 2 + addr_offset,
base + QUADSPI_SFA2AD);
- qspi_writel(q, ALIGN(q->devtype_data->ahb_buf_size, 0x400) * 3 + addr_offset,
- base + QUADSPI_SFB1AD);
- qspi_writel(q, ALIGN(q->devtype_data->ahb_buf_size, 0x400) * 4 + addr_offset,
- base + QUADSPI_SFB2AD);
+ if (!needs_single_bus(q)) {
+ qspi_writel(q, memsize_cs * 3 + addr_offset,
+ base + QUADSPI_SFB1AD);
+ qspi_writel(q, memsize_cs * 4 + addr_offset,
+ base + QUADSPI_SFB2AD);
+ }
q->selected = -1;
@@ -759,6 +824,7 @@ static int fsl_qspi_probe(struct udevice *bus)
q->ahb_addr = map_physmem(res.start, res.end - res.start, MAP_NOCACHE);
q->memmap_phy = res.start;
+ q->memmap_size = res.end - res.start;
dm_bus->max_hz = fdtdec_get_int(blob, node, "spi-max-frequency",
66000000);