summaryrefslogtreecommitdiffstats
path: root/drivers/spi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spi')
-rw-r--r--drivers/spi/Makefile1
-rw-r--r--drivers/spi/fsl_espi.c138
-rw-r--r--drivers/spi/fsl_qspi.c482
-rw-r--r--drivers/spi/fsl_qspi.h127
-rw-r--r--drivers/spi/soft_spi.c18
-rw-r--r--drivers/spi/ti_qspi.c1
6 files changed, 729 insertions, 38 deletions
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 81b6af6694..b587308c84 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -40,3 +40,4 @@ obj-$(CONFIG_TEGRA114_SPI) += tegra114_spi.o
obj-$(CONFIG_TI_QSPI) += ti_qspi.o
obj-$(CONFIG_XILINX_SPI) += xilinx_spi.o
obj-$(CONFIG_ZYNQ_SPI) += zynq_spi.o
+obj-$(CONFIG_FSL_QSPI) += fsl_qspi.o
diff --git a/drivers/spi/fsl_espi.c b/drivers/spi/fsl_espi.c
index 7c84582762..ae0fe58f2c 100644
--- a/drivers/spi/fsl_espi.c
+++ b/drivers/spi/fsl_espi.c
@@ -15,8 +15,10 @@
struct fsl_spi_slave {
struct spi_slave slave;
+ ccsr_espi_t *espi;
unsigned int div16;
unsigned int pm;
+ int tx_timeout;
unsigned int mode;
size_t cmd_len;
u8 cmd_buf[16];
@@ -25,11 +27,17 @@ struct fsl_spi_slave {
};
#define to_fsl_spi_slave(s) container_of(s, struct fsl_spi_slave, slave)
+#define US_PER_SECOND 1000000UL
#define ESPI_MAX_CS_NUM 4
+#define ESPI_FIFO_WIDTH_BIT 32
#define ESPI_EV_RNE (1 << 9)
#define ESPI_EV_TNF (1 << 8)
+#define ESPI_EV_DON (1 << 14)
+#define ESPI_EV_TXE (1 << 15)
+#define ESPI_EV_RFCNT_SHIFT 24
+#define ESPI_EV_RFCNT_MASK (0x3f << ESPI_EV_RFCNT_SHIFT)
#define ESPI_MODE_EN (1 << 31) /* Enable interface */
#define ESPI_MODE_TXTHR(x) ((x) << 8) /* Tx FIFO threshold */
@@ -61,6 +69,7 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
struct fsl_spi_slave *fsl;
sys_info_t sysinfo;
unsigned long spibrg = 0;
+ unsigned long spi_freq = 0;
unsigned char pm = 0;
if (!spi_cs_is_valid(bus, cs))
@@ -70,6 +79,7 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
if (!fsl)
return NULL;
+ fsl->espi = (void *)(CONFIG_SYS_MPC85xx_ESPI_ADDR);
fsl->mode = mode;
fsl->max_transfer_length = ESPI_MAX_DATA_TRANSFER_LEN;
@@ -91,6 +101,15 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
pm--;
fsl->pm = pm;
+ if (fsl->div16)
+ spi_freq = spibrg / ((pm + 1) * 2 * 16);
+ else
+ spi_freq = spibrg / ((pm + 1) * 2);
+
+ /* set tx_timeout to 10 times of one espi FIFO entry go out */
+ fsl->tx_timeout = DIV_ROUND_UP((US_PER_SECOND * ESPI_FIFO_WIDTH_BIT
+ * 10), spi_freq);
+
return &fsl->slave;
}
@@ -108,7 +127,7 @@ void spi_init(void)
int spi_claim_bus(struct spi_slave *slave)
{
struct fsl_spi_slave *fsl = to_fsl_spi_slave(slave);
- ccsr_espi_t *espi = (void *)(CONFIG_SYS_MPC85xx_ESPI_ADDR);
+ ccsr_espi_t *espi = fsl->espi;
unsigned char pm = fsl->pm;
unsigned int cs = slave->cs;
unsigned int mode = fsl->mode;
@@ -161,24 +180,86 @@ void spi_release_bus(struct spi_slave *slave)
}
+static void fsl_espi_tx(struct fsl_spi_slave *fsl, const void *dout)
+{
+ ccsr_espi_t *espi = fsl->espi;
+ unsigned int tmpdout, event;
+ int tmp_tx_timeout;
+
+ if (dout)
+ tmpdout = *(u32 *)dout;
+ else
+ tmpdout = 0;
+
+ out_be32(&espi->tx, tmpdout);
+ out_be32(&espi->event, ESPI_EV_TNF);
+ debug("***spi_xfer:...%08x written\n", tmpdout);
+
+ tmp_tx_timeout = fsl->tx_timeout;
+ /* Wait for eSPI transmit to go out */
+ while (tmp_tx_timeout--) {
+ event = in_be32(&espi->event);
+ if (event & ESPI_EV_DON || event & ESPI_EV_TXE) {
+ out_be32(&espi->event, ESPI_EV_TXE);
+ break;
+ }
+ udelay(1);
+ }
+
+ if (tmp_tx_timeout < 0)
+ debug("***spi_xfer:...Tx timeout! event = %08x\n", event);
+}
+
+static int fsl_espi_rx(struct fsl_spi_slave *fsl, void *din, unsigned int bytes)
+{
+ ccsr_espi_t *espi = fsl->espi;
+ unsigned int tmpdin, rx_times;
+ unsigned char *buf, *p_cursor;
+
+ if (bytes <= 0)
+ return 0;
+
+ rx_times = DIV_ROUND_UP(bytes, 4);
+ buf = (unsigned char *)malloc(4 * rx_times);
+ if (!buf) {
+ debug("SF: Failed to malloc memory.\n");
+ return -1;
+ }
+ p_cursor = buf;
+ while (rx_times--) {
+ tmpdin = in_be32(&espi->rx);
+ debug("***spi_xfer:...%08x readed\n", tmpdin);
+ *(u32 *)p_cursor = tmpdin;
+ p_cursor += 4;
+ }
+
+ if (din)
+ memcpy(din, buf, bytes);
+
+ free(buf);
+ out_be32(&espi->event, ESPI_EV_RNE);
+
+ return bytes;
+}
+
int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *data_out,
void *data_in, unsigned long flags)
{
struct fsl_spi_slave *fsl = to_fsl_spi_slave(slave);
- ccsr_espi_t *espi = (void *)(CONFIG_SYS_MPC85xx_ESPI_ADDR);
- unsigned int tmpdout, tmpdin, event;
+ ccsr_espi_t *espi = fsl->espi;
+ unsigned int event, rx_bytes;
const void *dout = NULL;
void *din = NULL;
int len = 0;
int num_blks, num_chunks, max_tran_len, tran_len;
int num_bytes;
- unsigned char *ch;
unsigned char *buffer = NULL;
size_t buf_len;
u8 *cmd_buf = fsl->cmd_buf;
size_t cmd_len = fsl->cmd_len;
size_t data_len = bitlen / 8;
size_t rx_offset = 0;
+ int rf_cnt;
max_tran_len = fsl->max_transfer_length;
switch (flags) {
@@ -217,9 +298,8 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *data_out,
break;
}
- debug("spi_xfer: slave %u:%u dout %08X(%p) din %08X(%p) len %u\n",
- slave->bus, slave->cs, *(uint *) dout,
- dout, *(uint *) din, din, len);
+ debug("spi_xfer: data_out %08X(%p) data_in %08X(%p) len %u\n",
+ *(uint *)data_out, data_out, *(uint *)data_in, data_in, len);
num_chunks = DIV_ROUND_UP(data_len, max_tran_len);
while (num_chunks--) {
@@ -235,41 +315,34 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *data_out,
/* Clear all eSPI events */
out_be32(&espi->event , 0xffffffff);
/* handle data in 32-bit chunks */
- while (num_blks--) {
-
+ while (num_blks) {
event = in_be32(&espi->event);
if (event & ESPI_EV_TNF) {
- tmpdout = *(u32 *)dout;
-
+ fsl_espi_tx(fsl, dout);
/* Set up the next iteration */
if (len > 4) {
len -= 4;
dout += 4;
}
-
- out_be32(&espi->tx, tmpdout);
- out_be32(&espi->event, ESPI_EV_TNF);
- debug("***spi_xfer:...%08x written\n", tmpdout);
}
- /* Wait for eSPI transmit to get out */
- udelay(80);
-
event = in_be32(&espi->event);
if (event & ESPI_EV_RNE) {
- tmpdin = in_be32(&espi->rx);
- if (num_blks == 0 && num_bytes != 0) {
- ch = (unsigned char *)&tmpdin;
- while (num_bytes--)
- *(unsigned char *)din++ = *ch++;
- } else {
- *(u32 *) din = tmpdin;
- din += 4;
+ rf_cnt = ((event & ESPI_EV_RFCNT_MASK)
+ >> ESPI_EV_RFCNT_SHIFT);
+ if (rf_cnt >= 4)
+ rx_bytes = 4;
+ else if (num_blks == 1 && rf_cnt == num_bytes)
+ rx_bytes = num_bytes;
+ else
+ continue;
+ if (fsl_espi_rx(fsl, din, rx_bytes)
+ == rx_bytes) {
+ num_blks--;
+ if (din)
+ din = (unsigned char *)din
+ + rx_bytes;
}
-
- out_be32(&espi->event, in_be32(&espi->event)
- | ESPI_EV_RNE);
- debug("***spi_xfer:...%08x readed\n", tmpdin);
}
}
if (data_in) {
@@ -295,7 +368,7 @@ int spi_cs_is_valid(unsigned int bus, unsigned int cs)
void spi_cs_activate(struct spi_slave *slave)
{
struct fsl_spi_slave *fsl = to_fsl_spi_slave(slave);
- ccsr_espi_t *espi = (void *)(CONFIG_SYS_MPC85xx_ESPI_ADDR);
+ ccsr_espi_t *espi = fsl->espi;
unsigned int com = 0;
size_t data_len = fsl->data_len;
@@ -307,7 +380,8 @@ void spi_cs_activate(struct spi_slave *slave)
void spi_cs_deactivate(struct spi_slave *slave)
{
- ccsr_espi_t *espi = (void *)(CONFIG_SYS_MPC85xx_ESPI_ADDR);
+ struct fsl_spi_slave *fsl = to_fsl_spi_slave(slave);
+ ccsr_espi_t *espi = fsl->espi;
/* clear the RXCNT and TXCNT */
out_be32(&espi->mode, in_be32(&espi->mode) & (~ESPI_MODE_EN));
diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c
new file mode 100644
index 0000000000..ba20beff4f
--- /dev/null
+++ b/drivers/spi/fsl_qspi.c
@@ -0,0 +1,482 @@
+/*
+ * Copyright 2013-2014 Freescale Semiconductor, Inc.
+ *
+ * Freescale Quad Serial Peripheral Interface (QSPI) driver
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <spi.h>
+#include <asm/io.h>
+#include <linux/sizes.h>
+#include "fsl_qspi.h"
+
+#define RX_BUFFER_SIZE 0x80
+#define TX_BUFFER_SIZE 0x40
+
+#define OFFSET_BITS_MASK 0x00ffffff
+
+#define FLASH_STATUS_WEL 0x02
+
+/* SEQID */
+#define SEQID_WREN 1
+#define SEQID_FAST_READ 2
+#define SEQID_RDSR 3
+#define SEQID_SE 4
+#define SEQID_CHIP_ERASE 5
+#define SEQID_PP 6
+#define SEQID_RDID 7
+
+/* Flash opcodes */
+#define OPCODE_PP 0x02 /* Page program (up to 256 bytes) */
+#define OPCODE_RDSR 0x05 /* Read status register */
+#define OPCODE_WREN 0x06 /* Write enable */
+#define OPCODE_FAST_READ 0x0b /* Read data bytes (high frequency) */
+#define OPCODE_CHIP_ERASE 0xc7 /* Erase whole flash chip */
+#define OPCODE_SE 0xd8 /* Sector erase (usually 64KiB) */
+#define OPCODE_RDID 0x9f /* Read JEDEC ID */
+
+/* 4-byte address opcodes - used on Spansion and some Macronix flashes */
+#define OPCODE_FAST_READ_4B 0x0c /* Read data bytes (high frequency) */
+#define OPCODE_PP_4B 0x12 /* Page program (up to 256 bytes) */
+#define OPCODE_SE_4B 0xdc /* Sector erase (usually 64KiB) */
+
+#ifdef CONFIG_SYS_FSL_QSPI_LE
+#define qspi_read32 in_le32
+#define qspi_write32 out_le32
+#elif defined(CONFIG_SYS_FSL_QSPI_BE)
+#define qspi_read32 in_be32
+#define qspi_write32 out_be32
+#endif
+
+static unsigned long spi_bases[] = {
+ QSPI0_BASE_ADDR,
+};
+
+static unsigned long amba_bases[] = {
+ QSPI0_AMBA_BASE,
+};
+
+struct fsl_qspi {
+ struct spi_slave slave;
+ unsigned long reg_base;
+ unsigned long amba_base;
+ u32 sf_addr;
+ u8 cur_seqid;
+};
+
+/* QSPI support swapping the flash read/write data
+ * in hardware for LS102xA, but not for VF610 */
+static inline u32 qspi_endian_xchg(u32 data)
+{
+#ifdef CONFIG_VF610
+ return swab32(data);
+#else
+ return data;
+#endif
+}
+
+static inline struct fsl_qspi *to_qspi_spi(struct spi_slave *slave)
+{
+ return container_of(slave, struct fsl_qspi, slave);
+}
+
+static void qspi_set_lut(struct fsl_qspi *qspi)
+{
+ struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base;
+ u32 lut_base;
+
+ /* Unlock the LUT */
+ qspi_write32(&regs->lutkey, LUT_KEY_VALUE);
+ qspi_write32(&regs->lckcr, QSPI_LCKCR_UNLOCK);
+
+ /* Write Enable */
+ lut_base = SEQID_WREN * 4;
+ qspi_write32(&regs->lut[lut_base], OPRND0(OPCODE_WREN) |
+ PAD0(LUT_PAD1) | INSTR0(LUT_CMD));
+ qspi_write32(&regs->lut[lut_base + 1], 0);
+ qspi_write32(&regs->lut[lut_base + 2], 0);
+ qspi_write32(&regs->lut[lut_base + 3], 0);
+
+ /* Fast Read */
+ lut_base = SEQID_FAST_READ * 4;
+ if (FSL_QSPI_FLASH_SIZE <= SZ_16M)
+ qspi_write32(&regs->lut[lut_base], OPRND0(OPCODE_FAST_READ) |
+ PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) |
+ PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
+ else
+ qspi_write32(&regs->lut[lut_base], OPRND0(OPCODE_FAST_READ_4B) |
+ PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR32BIT) |
+ PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
+ qspi_write32(&regs->lut[lut_base + 1], OPRND0(8) | PAD0(LUT_PAD1) |
+ INSTR0(LUT_DUMMY) | OPRND1(RX_BUFFER_SIZE) | PAD1(LUT_PAD1) |
+ INSTR1(LUT_READ));
+ qspi_write32(&regs->lut[lut_base + 2], 0);
+ qspi_write32(&regs->lut[lut_base + 3], 0);
+
+ /* Read Status */
+ lut_base = SEQID_RDSR * 4;
+ qspi_write32(&regs->lut[lut_base], OPRND0(OPCODE_RDSR) |
+ PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(1) |
+ PAD1(LUT_PAD1) | INSTR1(LUT_READ));
+ qspi_write32(&regs->lut[lut_base + 1], 0);
+ qspi_write32(&regs->lut[lut_base + 2], 0);
+ qspi_write32(&regs->lut[lut_base + 3], 0);
+
+ /* Erase a sector */
+ lut_base = SEQID_SE * 4;
+ if (FSL_QSPI_FLASH_SIZE <= SZ_16M)
+ qspi_write32(&regs->lut[lut_base], OPRND0(OPCODE_SE) |
+ PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) |
+ PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
+ else
+ qspi_write32(&regs->lut[lut_base], OPRND0(OPCODE_SE_4B) |
+ PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR32BIT) |
+ PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
+ qspi_write32(&regs->lut[lut_base + 1], 0);
+ qspi_write32(&regs->lut[lut_base + 2], 0);
+ qspi_write32(&regs->lut[lut_base + 3], 0);
+
+ /* Erase the whole chip */
+ lut_base = SEQID_CHIP_ERASE * 4;
+ qspi_write32(&regs->lut[lut_base], OPRND0(OPCODE_CHIP_ERASE) |
+ PAD0(LUT_PAD1) | INSTR0(LUT_CMD));
+ qspi_write32(&regs->lut[lut_base + 1], 0);
+ qspi_write32(&regs->lut[lut_base + 2], 0);
+ qspi_write32(&regs->lut[lut_base + 3], 0);
+
+ /* Page Program */
+ lut_base = SEQID_PP * 4;
+ if (FSL_QSPI_FLASH_SIZE <= SZ_16M)
+ qspi_write32(&regs->lut[lut_base], OPRND0(OPCODE_PP) |
+ PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) |
+ PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
+ else
+ qspi_write32(&regs->lut[lut_base], OPRND0(OPCODE_PP_4B) |
+ PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR32BIT) |
+ PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
+ qspi_write32(&regs->lut[lut_base + 1], OPRND0(TX_BUFFER_SIZE) |
+ PAD0(LUT_PAD1) | INSTR0(LUT_WRITE));
+ qspi_write32(&regs->lut[lut_base + 2], 0);
+ qspi_write32(&regs->lut[lut_base + 3], 0);
+
+ /* READ ID */
+ lut_base = SEQID_RDID * 4;
+ qspi_write32(&regs->lut[lut_base], OPRND0(OPCODE_RDID) |
+ PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(8) |
+ PAD1(LUT_PAD1) | INSTR1(LUT_READ));
+ qspi_write32(&regs->lut[lut_base + 1], 0);
+ qspi_write32(&regs->lut[lut_base + 2], 0);
+ qspi_write32(&regs->lut[lut_base + 3], 0);
+
+ /* Lock the LUT */
+ qspi_write32(&regs->lutkey, LUT_KEY_VALUE);
+ qspi_write32(&regs->lckcr, QSPI_LCKCR_LOCK);
+}
+
+void spi_init()
+{
+ /* do nothing */
+}
+
+struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
+ unsigned int max_hz, unsigned int mode)
+{
+ struct fsl_qspi *qspi;
+ struct fsl_qspi_regs *regs;
+ u32 reg_val, smpr_val;
+ u32 total_size, seq_id;
+
+ if (bus >= ARRAY_SIZE(spi_bases))
+ return NULL;
+
+ qspi = spi_alloc_slave(struct fsl_qspi, bus, cs);
+ if (!qspi)
+ return NULL;
+
+ qspi->reg_base = spi_bases[bus];
+ qspi->amba_base = amba_bases[bus];
+
+ qspi->slave.max_write_size = TX_BUFFER_SIZE;
+
+ regs = (struct fsl_qspi_regs *)qspi->reg_base;
+ qspi_write32(&regs->mcr, QSPI_MCR_RESERVED_MASK | QSPI_MCR_MDIS_MASK);
+
+ smpr_val = qspi_read32(&regs->smpr);
+ qspi_write32(&regs->smpr, smpr_val & ~(QSPI_SMPR_FSDLY_MASK |
+ QSPI_SMPR_FSPHS_MASK | QSPI_SMPR_HSENA_MASK));
+ qspi_write32(&regs->mcr, QSPI_MCR_RESERVED_MASK);
+
+ total_size = FSL_QSPI_FLASH_SIZE * FSL_QSPI_FLASH_NUM;
+ qspi_write32(&regs->sfa1ad, FSL_QSPI_FLASH_SIZE | qspi->amba_base);
+ qspi_write32(&regs->sfa2ad, FSL_QSPI_FLASH_SIZE | qspi->amba_base);
+ qspi_write32(&regs->sfb1ad, total_size | qspi->amba_base);
+ qspi_write32(&regs->sfb2ad, total_size | qspi->amba_base);
+
+ qspi_set_lut(qspi);
+
+ smpr_val = qspi_read32(&regs->smpr);
+ smpr_val &= ~QSPI_SMPR_DDRSMP_MASK;
+ qspi_write32(&regs->smpr, smpr_val);
+ qspi_write32(&regs->mcr, QSPI_MCR_RESERVED_MASK);
+
+ seq_id = 0;
+ reg_val = qspi_read32(&regs->bfgencr);
+ reg_val &= ~QSPI_BFGENCR_SEQID_MASK;
+ reg_val |= (seq_id << QSPI_BFGENCR_SEQID_SHIFT);
+ reg_val &= ~QSPI_BFGENCR_PAR_EN_MASK;
+ qspi_write32(&regs->bfgencr, reg_val);
+
+ return &qspi->slave;
+}
+
+void spi_free_slave(struct spi_slave *slave)
+{
+ struct fsl_qspi *qspi = to_qspi_spi(slave);
+
+ free(qspi);
+}
+
+int spi_claim_bus(struct spi_slave *slave)
+{
+ return 0;
+}
+
+static void qspi_op_rdid(struct fsl_qspi *qspi, u32 *rxbuf, u32 len)
+{
+ struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base;
+ u32 mcr_reg, rbsr_reg, data;
+ int i, size;
+
+ mcr_reg = qspi_read32(&regs->mcr);
+ qspi_write32(&regs->mcr, QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
+ QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
+ qspi_write32(&regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
+
+ qspi_write32(&regs->sfar, qspi->amba_base);
+
+ qspi_write32(&regs->ipcr, (SEQID_RDID << QSPI_IPCR_SEQID_SHIFT) | 0);
+ while (qspi_read32(&regs->sr) & QSPI_SR_BUSY_MASK)
+ ;
+
+ i = 0;
+ size = len;
+ while ((RX_BUFFER_SIZE >= size) && (size > 0)) {
+ rbsr_reg = qspi_read32(&regs->rbsr);
+ if (rbsr_reg & QSPI_RBSR_RDBFL_MASK) {
+ data = qspi_read32(&regs->rbdr[i]);
+ data = qspi_endian_xchg(data);
+ memcpy(rxbuf, &data, 4);
+ rxbuf++;
+ size -= 4;
+ i++;
+ }
+ }
+
+ qspi_write32(&regs->mcr, mcr_reg);
+}
+
+static void qspi_op_read(struct fsl_qspi *qspi, u32 *rxbuf, u32 len)
+{
+ struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base;
+ u32 mcr_reg, data;
+ int i, size;
+ u32 to_or_from;
+
+ mcr_reg = qspi_read32(&regs->mcr);
+ qspi_write32(&regs->mcr, QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
+ QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
+ qspi_write32(&regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
+
+ to_or_from = qspi->sf_addr + qspi->amba_base;
+
+ while (len > 0) {
+ qspi_write32(&regs->sfar, to_or_from);
+
+ size = (len > RX_BUFFER_SIZE) ?
+ RX_BUFFER_SIZE : len;
+
+ qspi_write32(&regs->ipcr,
+ (SEQID_FAST_READ << QSPI_IPCR_SEQID_SHIFT) | size);
+ while (qspi_read32(&regs->sr) & QSPI_SR_BUSY_MASK)
+ ;
+
+ to_or_from += size;
+ len -= size;
+
+ i = 0;
+ while ((RX_BUFFER_SIZE >= size) && (size > 0)) {
+ data = qspi_read32(&regs->rbdr[i]);
+ data = qspi_endian_xchg(data);
+ memcpy(rxbuf, &data, 4);
+ rxbuf++;
+ size -= 4;
+ i++;
+ }
+ qspi_write32(&regs->mcr, qspi_read32(&regs->mcr) |
+ QSPI_MCR_CLR_RXF_MASK);
+ }
+
+ qspi_write32(&regs->mcr, mcr_reg);
+}
+
+static void qspi_op_pp(struct fsl_qspi *qspi, u32 *txbuf, u32 len)
+{
+ struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base;
+ u32 mcr_reg, data, reg, status_reg;
+ int i, size, tx_size;
+ u32 to_or_from = 0;
+
+ mcr_reg = qspi_read32(&regs->mcr);
+ qspi_write32(&regs->mcr, QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
+ QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
+ qspi_write32(&regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
+
+ status_reg = 0;
+ while ((status_reg & FLASH_STATUS_WEL) != FLASH_STATUS_WEL) {
+ qspi_write32(&regs->ipcr,
+ (SEQID_WREN << QSPI_IPCR_SEQID_SHIFT) | 0);
+ while (qspi_read32(&regs->sr) & QSPI_SR_BUSY_MASK)
+ ;
+
+ qspi_write32(&regs->ipcr,
+ (SEQID_RDSR << QSPI_IPCR_SEQID_SHIFT) | 1);
+ while (qspi_read32(&regs->sr) & QSPI_SR_BUSY_MASK)
+ ;
+
+ reg = qspi_read32(&regs->rbsr);
+ if (reg & QSPI_RBSR_RDBFL_MASK) {
+ status_reg = qspi_read32(&regs->rbdr[0]);
+ status_reg = qspi_endian_xchg(status_reg);
+ }
+ qspi_write32(&regs->mcr,
+ qspi_read32(&regs->mcr) | QSPI_MCR_CLR_RXF_MASK);
+ }
+
+ to_or_from = qspi->sf_addr + qspi->amba_base;
+ qspi_write32(&regs->sfar, to_or_from);
+
+ tx_size = (len > TX_BUFFER_SIZE) ?
+ TX_BUFFER_SIZE : len;
+
+ size = (tx_size + 3) / 4;
+
+ for (i = 0; i < size; i++) {
+ data = qspi_endian_xchg(*txbuf);
+ qspi_write32(&regs->tbdr, data);
+ txbuf++;
+ }
+
+ qspi_write32(&regs->ipcr,
+ (SEQID_PP << QSPI_IPCR_SEQID_SHIFT) | tx_size);
+ while (qspi_read32(&regs->sr) & QSPI_SR_BUSY_MASK)
+ ;
+
+ qspi_write32(&regs->mcr, mcr_reg);
+}
+
+static void qspi_op_rdsr(struct fsl_qspi *qspi, u32 *rxbuf)
+{
+ struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base;
+ u32 mcr_reg, reg, data;
+
+ mcr_reg = qspi_read32(&regs->mcr);
+ qspi_write32(&regs->mcr, QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
+ QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
+ qspi_write32(&regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
+
+ qspi_write32(&regs->sfar, qspi->amba_base);
+
+ qspi_write32(&regs->ipcr,
+ (SEQID_RDSR << QSPI_IPCR_SEQID_SHIFT) | 0);
+ while (qspi_read32(&regs->sr) & QSPI_SR_BUSY_MASK)
+ ;
+
+ while (1) {
+ reg = qspi_read32(&regs->rbsr);
+ if (reg & QSPI_RBSR_RDBFL_MASK) {
+ data = qspi_read32(&regs->rbdr[0]);
+ data = qspi_endian_xchg(data);
+ memcpy(rxbuf, &data, 4);
+ qspi_write32(&regs->mcr, qspi_read32(&regs->mcr) |
+ QSPI_MCR_CLR_RXF_MASK);
+ break;
+ }
+ }
+
+ qspi_write32(&regs->mcr, mcr_reg);
+}
+
+static void qspi_op_se(struct fsl_qspi *qspi)
+{
+ struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base;
+ u32 mcr_reg;
+ u32 to_or_from = 0;
+
+ mcr_reg = qspi_read32(&regs->mcr);
+ qspi_write32(&regs->mcr, QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
+ QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
+ qspi_write32(&regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
+
+ to_or_from = qspi->sf_addr + qspi->amba_base;
+ qspi_write32(&regs->sfar, to_or_from);
+
+ qspi_write32(&regs->ipcr,
+ (SEQID_WREN << QSPI_IPCR_SEQID_SHIFT) | 0);
+ while (qspi_read32(&regs->sr) & QSPI_SR_BUSY_MASK)
+ ;
+
+ qspi_write32(&regs->ipcr,
+ (SEQID_SE << QSPI_IPCR_SEQID_SHIFT) | 0);
+ while (qspi_read32(&regs->sr) & QSPI_SR_BUSY_MASK)
+ ;
+
+ qspi_write32(&regs->mcr, mcr_reg);
+}
+
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
+ const void *dout, void *din, unsigned long flags)
+{
+ struct fsl_qspi *qspi = to_qspi_spi(slave);
+ u32 bytes = DIV_ROUND_UP(bitlen, 8);
+ static u32 pp_sfaddr;
+ u32 txbuf;
+
+ if (dout) {
+ memcpy(&txbuf, dout, 4);
+ qspi->cur_seqid = *(u8 *)dout;
+
+ if (flags == SPI_XFER_END) {
+ qspi->sf_addr = pp_sfaddr;
+ qspi_op_pp(qspi, (u32 *)dout, bytes);
+ return 0;
+ }
+
+ if (qspi->cur_seqid == OPCODE_FAST_READ) {
+ qspi->sf_addr = swab32(txbuf) & OFFSET_BITS_MASK;
+ } else if (qspi->cur_seqid == OPCODE_SE) {
+ qspi->sf_addr = swab32(txbuf) & OFFSET_BITS_MASK;
+ qspi_op_se(qspi);
+ } else if (qspi->cur_seqid == OPCODE_PP) {
+ pp_sfaddr = swab32(txbuf) & OFFSET_BITS_MASK;
+ }
+ }
+
+ if (din) {
+ if (qspi->cur_seqid == OPCODE_FAST_READ)
+ qspi_op_read(qspi, din, bytes);
+ else if (qspi->cur_seqid == OPCODE_RDID)
+ qspi_op_rdid(qspi, din, bytes);
+ else if (qspi->cur_seqid == OPCODE_RDSR)
+ qspi_op_rdsr(qspi, din);
+ }
+
+ return 0;
+}
+
+void spi_release_bus(struct spi_slave *slave)
+{
+ /* Nothing to do */
+}
diff --git a/drivers/spi/fsl_qspi.h b/drivers/spi/fsl_qspi.h
new file mode 100644
index 0000000000..db400e66b5
--- /dev/null
+++ b/drivers/spi/fsl_qspi.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2013-2014 Freescale Semiconductor, Inc.
+ *
+ * Register definitions for Freescale QSPI
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef _FSL_QSPI_H_
+#define _FSL_QSPI_H_
+
+struct fsl_qspi_regs {
+ u32 mcr;
+ u32 rsvd0[1];
+ u32 ipcr;
+ u32 flshcr;
+ u32 buf0cr;
+ u32 buf1cr;
+ u32 buf2cr;
+ u32 buf3cr;
+ u32 bfgencr;
+ u32 soccr;
+ u32 rsvd1[2];
+ u32 buf0ind;
+ u32 buf1ind;
+ u32 buf2ind;
+ u32 rsvd2[49];
+ u32 sfar;
+ u32 rsvd3[1];
+ u32 smpr;
+ u32 rbsr;
+ u32 rbct;
+ u32 rsvd4[15];
+ u32 tbsr;
+ u32 tbdr;
+ u32 rsvd5[1];
+ u32 sr;
+ u32 fr;
+ u32 rser;
+ u32 spndst;
+ u32 sptrclr;
+ u32 rsvd6[4];
+ u32 sfa1ad;
+ u32 sfa2ad;
+ u32 sfb1ad;
+ u32 sfb2ad;
+ u32 rsvd7[28];
+ u32 rbdr[32];
+ u32 rsvd8[32];
+ u32 lutkey;
+ u32 lckcr;
+ u32 rsvd9[2];
+ u32 lut[64];
+};
+
+#define QSPI_IPCR_SEQID_SHIFT 24
+#define QSPI_IPCR_SEQID_MASK (0xf << QSPI_IPCR_SEQID_SHIFT)
+
+#define QSPI_MCR_END_CFD_SHIFT 2
+#define QSPI_MCR_END_CFD_MASK (3 << QSPI_MCR_END_CFD_SHIFT)
+#define QSPI_MCR_END_CFD_LE (1 << QSPI_MCR_END_CFD_SHIFT)
+#define QSPI_MCR_DDR_EN_SHIFT 7
+#define QSPI_MCR_DDR_EN_MASK (1 << QSPI_MCR_DDR_EN_SHIFT)
+#define QSPI_MCR_CLR_RXF_SHIFT 10
+#define QSPI_MCR_CLR_RXF_MASK (1 << QSPI_MCR_CLR_RXF_SHIFT)
+#define QSPI_MCR_CLR_TXF_SHIFT 11
+#define QSPI_MCR_CLR_TXF_MASK (1 << QSPI_MCR_CLR_TXF_SHIFT)
+#define QSPI_MCR_MDIS_SHIFT 14
+#define QSPI_MCR_MDIS_MASK (1 << QSPI_MCR_MDIS_SHIFT)
+#define QSPI_MCR_RESERVED_SHIFT 16
+#define QSPI_MCR_RESERVED_MASK (0xf << QSPI_MCR_RESERVED_SHIFT)
+
+#define QSPI_SMPR_HSENA_SHIFT 0
+#define QSPI_SMPR_HSENA_MASK (1 << QSPI_SMPR_HSENA_SHIFT)
+#define QSPI_SMPR_FSPHS_SHIFT 5
+#define QSPI_SMPR_FSPHS_MASK (1 << QSPI_SMPR_FSPHS_SHIFT)
+#define QSPI_SMPR_FSDLY_SHIFT 6
+#define QSPI_SMPR_FSDLY_MASK (1 << QSPI_SMPR_FSDLY_SHIFT)
+#define QSPI_SMPR_DDRSMP_SHIFT 16
+#define QSPI_SMPR_DDRSMP_MASK (7 << QSPI_SMPR_DDRSMP_SHIFT)
+
+#define QSPI_BFGENCR_SEQID_SHIFT 12
+#define QSPI_BFGENCR_SEQID_MASK (0xf << QSPI_BFGENCR_SEQID_SHIFT)
+#define QSPI_BFGENCR_PAR_EN_SHIFT 16
+#define QSPI_BFGENCR_PAR_EN_MASK (1 << QSPI_BFGENCR_PAR_EN_SHIFT)
+
+#define QSPI_RBSR_RDBFL_SHIFT 8
+#define QSPI_RBSR_RDBFL_MASK (0x3f << QSPI_RBSR_RDBFL_SHIFT)
+
+#define QSPI_RBCT_RXBRD_SHIFT 8
+#define QSPI_RBCT_RXBRD_USEIPS (1 << QSPI_RBCT_RXBRD_SHIFT)
+
+#define QSPI_SR_BUSY_SHIFT 0
+#define QSPI_SR_BUSY_MASK (1 << QSPI_SR_BUSY_SHIFT)
+
+#define QSPI_LCKCR_LOCK 0x1
+#define QSPI_LCKCR_UNLOCK 0x2
+
+#define LUT_KEY_VALUE 0x5af05af0
+
+#define OPRND0_SHIFT 0
+#define OPRND0(x) ((x) << OPRND0_SHIFT)
+#define PAD0_SHIFT 8
+#define PAD0(x) ((x) << PAD0_SHIFT)
+#define INSTR0_SHIFT 10
+#define INSTR0(x) ((x) << INSTR0_SHIFT)
+#define OPRND1_SHIFT 16
+#define OPRND1(x) ((x) << OPRND1_SHIFT)
+#define PAD1_SHIFT 24
+#define PAD1(x) ((x) << PAD1_SHIFT)
+#define INSTR1_SHIFT 26
+#define INSTR1(x) ((x) << INSTR1_SHIFT)
+
+#define LUT_CMD 1
+#define LUT_ADDR 2
+#define LUT_DUMMY 3
+#define LUT_READ 7
+#define LUT_WRITE 8
+
+#define LUT_PAD1 0
+#define LUT_PAD2 1
+#define LUT_PAD4 2
+
+#define ADDR24BIT 0x18
+#define ADDR32BIT 0x20
+
+#endif /* _FSL_QSPI_H_ */
diff --git a/drivers/spi/soft_spi.c b/drivers/spi/soft_spi.c
index 5d22351290..c969be31eb 100644
--- a/drivers/spi/soft_spi.c
+++ b/drivers/spi/soft_spi.c
@@ -136,10 +136,14 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
/*
* Check if it is time to work on a new byte.
*/
- if((j % 8) == 0) {
- tmpdout = *txd++;
+ if ((j % 8) == 0) {
+ if (txd)
+ tmpdout = *txd++;
+ else
+ tmpdout = 0;
if(j != 0) {
- *rxd++ = tmpdin;
+ if (rxd)
+ *rxd++ = tmpdin;
}
tmpdin = 0;
}
@@ -164,9 +168,11 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
* bits over to left-justify them. Then store the last byte
* read in.
*/
- if((bitlen % 8) != 0)
- tmpdin <<= 8 - (bitlen % 8);
- *rxd++ = tmpdin;
+ if (rxd) {
+ if ((bitlen % 8) != 0)
+ tmpdin <<= 8 - (bitlen % 8);
+ *rxd++ = tmpdin;
+ }
if (flags & SPI_XFER_END)
spi_cs_deactivate(slave);
diff --git a/drivers/spi/ti_qspi.c b/drivers/spi/ti_qspi.c
index c5d2245e44..fd7fea8df5 100644
--- a/drivers/spi/ti_qspi.c
+++ b/drivers/spi/ti_qspi.c
@@ -106,6 +106,7 @@ static void ti_spi_setup_spi_register(struct ti_qspi_slave *qslave)
slave->memory_map = (void *)MMAP_START_ADDR_DRA;
#else
slave->memory_map = (void *)MMAP_START_ADDR_AM43x;
+ slave->op_mode_rx = 8;
#endif
memval |= QSPI_CMD_READ | QSPI_SETUP0_NUM_A_BYTES |
OpenPOWER on IntegriCloud