summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2018-04-07 09:15:50 -0400
committerTom Rini <trini@konsulko.com>2018-04-07 09:19:00 -0400
commite80fa2c2c0870f7c17e233ecc07552e1082c1513 (patch)
tree8274e5382c7b6240899ded2b6c0b3c9440c7d839
parent5270df2836761909864d9b548bf4b7f7f3a51484 (diff)
downloadu-boot-e80fa2c2c0870f7c17e233ecc07552e1082c1513.tar.gz
Revert "spi: atmel: Drop non-dm code"
As we aren't quite able to convert some platforms with a very small size limit in SPL yet, we need to revert this for now. This reverts commit 7b0947787358c6b277431d6b76ce043d8bec641d. Signed-off-by: Tom Rini <trini@konsulko.com>
-rw-r--r--drivers/spi/atmel_spi.c201
-rw-r--r--drivers/spi/atmel_spi.h16
-rw-r--r--include/configs/ma5d4evk.h2
-rw-r--r--include/configs/vinco.h2
-rw-r--r--scripts/config_whitelist.txt1
5 files changed, 222 insertions, 0 deletions
diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
index 122c6d107d..3cdfd366ab 100644
--- a/drivers/spi/atmel_spi.c
+++ b/drivers/spi/atmel_spi.c
@@ -26,6 +26,206 @@
DECLARE_GLOBAL_DATA_PTR;
+#ifndef CONFIG_DM_SPI
+
+static int spi_has_wdrbt(struct atmel_spi_slave *slave)
+{
+ unsigned int ver;
+
+ ver = spi_readl(slave, VERSION);
+
+ return (ATMEL_SPI_VERSION_REV(ver) >= 0x210);
+}
+
+void spi_init()
+{
+
+}
+
+struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
+ unsigned int max_hz, unsigned int mode)
+{
+ struct atmel_spi_slave *as;
+ unsigned int scbr;
+ u32 csrx;
+ void *regs;
+
+ if (!spi_cs_is_valid(bus, cs))
+ return NULL;
+
+ switch (bus) {
+ case 0:
+ regs = (void *)ATMEL_BASE_SPI0;
+ break;
+#ifdef ATMEL_BASE_SPI1
+ case 1:
+ regs = (void *)ATMEL_BASE_SPI1;
+ break;
+#endif
+#ifdef ATMEL_BASE_SPI2
+ case 2:
+ regs = (void *)ATMEL_BASE_SPI2;
+ break;
+#endif
+#ifdef ATMEL_BASE_SPI3
+ case 3:
+ regs = (void *)ATMEL_BASE_SPI3;
+ break;
+#endif
+ default:
+ return NULL;
+ }
+
+
+ scbr = (get_spi_clk_rate(bus) + max_hz - 1) / max_hz;
+ if (scbr > ATMEL_SPI_CSRx_SCBR_MAX)
+ /* Too low max SCK rate */
+ return NULL;
+ if (scbr < 1)
+ scbr = 1;
+
+ csrx = ATMEL_SPI_CSRx_SCBR(scbr);
+ csrx |= ATMEL_SPI_CSRx_BITS(ATMEL_SPI_BITS_8);
+ if (!(mode & SPI_CPHA))
+ csrx |= ATMEL_SPI_CSRx_NCPHA;
+ if (mode & SPI_CPOL)
+ csrx |= ATMEL_SPI_CSRx_CPOL;
+
+ as = spi_alloc_slave(struct atmel_spi_slave, bus, cs);
+ if (!as)
+ return NULL;
+
+ as->regs = regs;
+ as->mr = ATMEL_SPI_MR_MSTR | ATMEL_SPI_MR_MODFDIS
+ | ATMEL_SPI_MR_PCS(~(1 << cs) & 0xf);
+ if (spi_has_wdrbt(as))
+ as->mr |= ATMEL_SPI_MR_WDRBT;
+
+ spi_writel(as, CSR(cs), csrx);
+
+ return &as->slave;
+}
+
+void spi_free_slave(struct spi_slave *slave)
+{
+ struct atmel_spi_slave *as = to_atmel_spi(slave);
+
+ free(as);
+}
+
+int spi_claim_bus(struct spi_slave *slave)
+{
+ struct atmel_spi_slave *as = to_atmel_spi(slave);
+
+ /* Enable the SPI hardware */
+ spi_writel(as, CR, ATMEL_SPI_CR_SPIEN);
+
+ /*
+ * Select the slave. This should set SCK to the correct
+ * initial state, etc.
+ */
+ spi_writel(as, MR, as->mr);
+
+ return 0;
+}
+
+void spi_release_bus(struct spi_slave *slave)
+{
+ struct atmel_spi_slave *as = to_atmel_spi(slave);
+
+ /* Disable the SPI hardware */
+ spi_writel(as, CR, ATMEL_SPI_CR_SPIDIS);
+}
+
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
+ const void *dout, void *din, unsigned long flags)
+{
+ struct atmel_spi_slave *as = to_atmel_spi(slave);
+ unsigned int len_tx;
+ unsigned int len_rx;
+ unsigned int len;
+ u32 status;
+ const u8 *txp = dout;
+ u8 *rxp = din;
+ u8 value;
+
+ if (bitlen == 0)
+ /* Finish any previously submitted transfers */
+ goto out;
+
+ /*
+ * TODO: The controller can do non-multiple-of-8 bit
+ * transfers, but this driver currently doesn't support it.
+ *
+ * It's also not clear how such transfers are supposed to be
+ * represented as a stream of bytes...this is a limitation of
+ * the current SPI interface.
+ */
+ if (bitlen % 8) {
+ /* Errors always terminate an ongoing transfer */
+ flags |= SPI_XFER_END;
+ goto out;
+ }
+
+ len = bitlen / 8;
+
+ /*
+ * The controller can do automatic CS control, but it is
+ * somewhat quirky, and it doesn't really buy us much anyway
+ * in the context of U-Boot.
+ */
+ if (flags & SPI_XFER_BEGIN) {
+ spi_cs_activate(slave);
+ /*
+ * sometimes the RDR is not empty when we get here,
+ * in theory that should not happen, but it DOES happen.
+ * Read it here to be on the safe side.
+ * That also clears the OVRES flag. Required if the
+ * following loop exits due to OVRES!
+ */
+ spi_readl(as, RDR);
+ }
+
+ for (len_tx = 0, len_rx = 0; len_rx < len; ) {
+ status = spi_readl(as, SR);
+
+ if (status & ATMEL_SPI_SR_OVRES)
+ return -1;
+
+ if (len_tx < len && (status & ATMEL_SPI_SR_TDRE)) {
+ if (txp)
+ value = *txp++;
+ else
+ value = 0;
+ spi_writel(as, TDR, value);
+ len_tx++;
+ }
+ if (status & ATMEL_SPI_SR_RDRF) {
+ value = spi_readl(as, RDR);
+ if (rxp)
+ *rxp++ = value;
+ len_rx++;
+ }
+ }
+
+out:
+ if (flags & SPI_XFER_END) {
+ /*
+ * Wait until the transfer is completely done before
+ * we deactivate CS.
+ */
+ do {
+ status = spi_readl(as, SR);
+ } while (!(status & ATMEL_SPI_SR_TXEMPTY));
+
+ spi_cs_deactivate(slave);
+ }
+
+ return 0;
+}
+
+#else
+
#define MAX_CS_COUNT 4
struct atmel_spi_platdata {
@@ -315,3 +515,4 @@ U_BOOT_DRIVER(atmel_spi) = {
.priv_auto_alloc_size = sizeof(struct atmel_spi_priv),
.probe = atmel_spi_probe,
};
+#endif
diff --git a/drivers/spi/atmel_spi.h b/drivers/spi/atmel_spi.h
index 685eeed99e..76b8556c98 100644
--- a/drivers/spi/atmel_spi.h
+++ b/drivers/spi/atmel_spi.h
@@ -79,6 +79,22 @@
#define ATMEL_SPI_BITS_16 8
struct atmel_spi_slave {
+ struct spi_slave slave;
void *regs;
u32 mr;
};
+
+static inline struct atmel_spi_slave *to_atmel_spi(struct spi_slave *slave)
+{
+ return container_of(slave, struct atmel_spi_slave, slave);
+}
+
+/* Register access macros */
+#define spi_readl(as, reg) \
+ readl(as->regs + ATMEL_SPI_##reg)
+#define spi_writel(as, reg, value) \
+ writel(value, as->regs + ATMEL_SPI_##reg)
+
+#if !defined(CONFIG_SYS_SPI_WRITE_TOUT)
+#define CONFIG_SYS_SPI_WRITE_TOUT (5 * CONFIG_SYS_HZ)
+#endif
diff --git a/include/configs/ma5d4evk.h b/include/configs/ma5d4evk.h
index 68fe3bd67f..ed95e580c0 100644
--- a/include/configs/ma5d4evk.h
+++ b/include/configs/ma5d4evk.h
@@ -86,6 +86,8 @@
* SPI NOR (boot memory)
*/
#ifdef CONFIG_CMD_SF
+#define CONFIG_ATMEL_SPI
+#define CONFIG_ATMEL_SPI0
#define CONFIG_SPI_FLASH_ATMEL
#define CONFIG_SF_DEFAULT_BUS 0
#define CONFIG_SF_DEFAULT_CS 0
diff --git a/include/configs/vinco.h b/include/configs/vinco.h
index d1b56ac037..ca3958986b 100644
--- a/include/configs/vinco.h
+++ b/include/configs/vinco.h
@@ -38,6 +38,8 @@
/* SerialFlash */
#ifdef CONFIG_CMD_SF
+#define CONFIG_ATMEL_SPI
+#define CONFIG_ATMEL_SPI0
#define CONFIG_SPI_FLASH_STMICRO
#define CONFIG_SF_DEFAULT_BUS 0
#define CONFIG_SF_DEFAULT_CS 0
diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt
index e549708215..997ef771c7 100644
--- a/scripts/config_whitelist.txt
+++ b/scripts/config_whitelist.txt
@@ -103,6 +103,7 @@ CONFIG_ATMEL_LEGACY
CONFIG_ATMEL_MCI_8BIT
CONFIG_ATMEL_NAND_HWECC
CONFIG_ATMEL_NAND_HW_PMECC
+CONFIG_ATMEL_SPI0
CONFIG_AT_TRANS
CONFIG_AUTO_ZRELADDR
CONFIG_BACKSIDE_L2_CACHE