summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorStefano Babic <sbabic@denx.de>2015-07-10 09:21:44 +0200
committerStefano Babic <sbabic@denx.de>2015-07-10 09:21:44 +0200
commit1254ff97abb7606ccd0d7bdcd9f22581c50fe535 (patch)
tree61b31e61173154abd38aaa6584e84ea77314b861 /drivers
parent54e0f96f764f662be186baae7d6c2c97423bc29d (diff)
parentf3edfd30541d6f245d7dfa6fa7354cc916cc53e1 (diff)
downloadblackbird-obmc-uboot-1254ff97abb7606ccd0d7bdcd9f22581c50fe535.tar.gz
blackbird-obmc-uboot-1254ff97abb7606ccd0d7bdcd9f22581c50fe535.zip
Merge branch 'master' of git://git.denx.de/u-boot
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/block/ahci.c40
-rw-r--r--drivers/gpio/lpc32xx_gpio.c39
-rw-r--r--drivers/mmc/bcm2835_sdhci.c4
-rw-r--r--drivers/mmc/mmc_write.c12
-rw-r--r--drivers/mtd/Makefile4
-rw-r--r--drivers/mtd/mtd_uboot.c99
-rw-r--r--drivers/mtd/nand/Makefile1
-rw-r--r--drivers/mtd/nand/omap_gpmc.c236
-rw-r--r--drivers/mtd/nand/sunxi_nand_spl.c273
-rw-r--r--drivers/mtd/spi/Kconfig48
-rw-r--r--drivers/mtd/spi/Makefile2
-rw-r--r--drivers/mtd/spi/sf_dataflash.c701
-rw-r--r--drivers/mtd/spi/sf_internal.h23
-rw-r--r--drivers/mtd/spi/sf_mtd.c104
-rw-r--r--drivers/mtd/spi/sf_params.c2
-rw-r--r--drivers/mtd/spi/sf_probe.c11
-rw-r--r--drivers/net/Kconfig1
-rw-r--r--drivers/net/designware.c6
-rw-r--r--drivers/serial/arm_dcc.c16
-rw-r--r--drivers/spi/Kconfig112
-rw-r--r--drivers/spi/Makefile13
-rw-r--r--drivers/spi/andes_spi.c284
-rw-r--r--drivers/spi/andes_spi.h115
-rw-r--r--drivers/spi/cf_qspi.c3
-rw-r--r--drivers/spi/davinci_spi.c369
-rw-r--r--drivers/spi/davinci_spi.h121
-rw-r--r--drivers/spi/ftssp010_spi.c498
-rw-r--r--drivers/spi/oc_tiny_spi.c245
-rw-r--r--drivers/spi/xilinx_spi.c318
-rw-r--r--drivers/spi/xilinx_spi.h138
-rw-r--r--drivers/spi/zynq_spi.c300
-rw-r--r--drivers/usb/dwc3/Makefile1
-rw-r--r--drivers/usb/dwc3/samsung_usb_phy.c78
-rw-r--r--drivers/usb/gadget/f_mass_storage.c2
-rw-r--r--drivers/usb/host/ehci-fsl.c2
-rw-r--r--drivers/usb/host/ehci-hcd.c26
-rw-r--r--drivers/usb/musb-new/sunxi.c80
38 files changed, 2035 insertions, 2294 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 1f4088778b..c7e526cc8a 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -57,7 +57,7 @@ source "drivers/thermal/Kconfig"
endmenu
config PHYS_TO_BUS
- bool
+ bool "Custom physical to bus address mapping"
help
Some SoCs use a different address map for CPU physical addresses and
peripheral DMA master accesses. If yours does, select this option in
diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c
index 65086484ee..4fb846ad37 100644
--- a/drivers/block/ahci.c
+++ b/drivers/block/ahci.c
@@ -39,7 +39,7 @@ u16 *ataid[AHCI_MAX_PORTS];
/* Maximum timeouts for each event */
#define WAIT_MS_SPINUP 20000
-#define WAIT_MS_DATAIO 5000
+#define WAIT_MS_DATAIO 10000
#define WAIT_MS_FLUSH 5000
#define WAIT_MS_LINKUP 200
@@ -726,18 +726,25 @@ static int ata_scsiop_inquiry(ccb *pccb)
*/
static int ata_scsiop_read_write(ccb *pccb, u8 is_write)
{
- u32 lba = 0;
+ lbaint_t lba = 0;
u16 blocks = 0;
u8 fis[20];
u8 *user_buffer = pccb->pdata;
u32 user_buffer_size = pccb->datalen;
/* Retrieve the base LBA number from the ccb structure. */
- memcpy(&lba, pccb->cmd + 2, sizeof(lba));
- lba = be32_to_cpu(lba);
+ if (pccb->cmd[0] == SCSI_READ16) {
+ memcpy(&lba, pccb->cmd + 2, 8);
+ lba = be64_to_cpu(lba);
+ } else {
+ u32 temp;
+ memcpy(&temp, pccb->cmd + 2, 4);
+ lba = be32_to_cpu(temp);
+ }
/*
- * And the number of blocks.
+ * Retrieve the base LBA number and the block count from
+ * the ccb structure.
*
* For 10-byte and 16-byte SCSI R/W commands, transfer
* length 0 means transfer 0 block of data.
@@ -746,10 +753,13 @@ static int ata_scsiop_read_write(ccb *pccb, u8 is_write)
*
* WARNING: one or two older ATA drives treat 0 as 0...
*/
- blocks = (((u16)pccb->cmd[7]) << 8) | ((u16) pccb->cmd[8]);
+ if (pccb->cmd[0] == SCSI_READ16)
+ blocks = (((u16)pccb->cmd[13]) << 8) | ((u16) pccb->cmd[14]);
+ else
+ blocks = (((u16)pccb->cmd[7]) << 8) | ((u16) pccb->cmd[8]);
- debug("scsi_ahci: %s %d blocks starting from lba 0x%x\n",
- is_write ? "write" : "read", (unsigned)lba, blocks);
+ debug("scsi_ahci: %s %u blocks starting from lba 0x" LBAFU "\n",
+ is_write ? "write" : "read", blocks, lba);
/* Preset the FIS */
memset(fis, 0, sizeof(fis));
@@ -770,14 +780,23 @@ static int ata_scsiop_read_write(ccb *pccb, u8 is_write)
return -EIO;
}
- /* LBA48 SATA command but only use 32bit address range within
- * that. The next smaller command range (28bit) is too small.
+ /*
+ * LBA48 SATA command but only use 32bit address range within
+ * that (unless we've enabled 64bit LBA support). The next
+ * smaller command range (28bit) is too small.
*/
fis[4] = (lba >> 0) & 0xff;
fis[5] = (lba >> 8) & 0xff;
fis[6] = (lba >> 16) & 0xff;
fis[7] = 1 << 6; /* device reg: set LBA mode */
fis[8] = ((lba >> 24) & 0xff);
+#ifdef CONFIG_SYS_64BIT_LBA
+ if (pccb->cmd[0] == SCSI_READ16) {
+ fis[9] = ((lba >> 32) & 0xff);
+ fis[10] = ((lba >> 40) & 0xff);
+ }
+#endif
+
fis[3] = 0xe0; /* features */
/* Block (sector) count */
@@ -883,6 +902,7 @@ int scsi_exec(ccb *pccb)
int ret;
switch (pccb->cmd[0]) {
+ case SCSI_READ16:
case SCSI_READ10:
ret = ata_scsiop_read_write(pccb, 0);
break;
diff --git a/drivers/gpio/lpc32xx_gpio.c b/drivers/gpio/lpc32xx_gpio.c
index 96b312592b..8a9826e6eb 100644
--- a/drivers/gpio/lpc32xx_gpio.c
+++ b/drivers/gpio/lpc32xx_gpio.c
@@ -37,7 +37,7 @@
#define LPC32XX_GPIOS 128
-struct lpc32xx_gpio_platdata {
+struct lpc32xx_gpio_priv {
struct gpio_regs *regs;
/* GPIO FUNCTION: SEE WARNING #2 */
signed char function[LPC32XX_GPIOS];
@@ -60,8 +60,8 @@ struct lpc32xx_gpio_platdata {
static int lpc32xx_gpio_direction_input(struct udevice *dev, unsigned offset)
{
int port, mask;
- struct lpc32xx_gpio_platdata *gpio_platdata = dev_get_platdata(dev);
- struct gpio_regs *regs = gpio_platdata->regs;
+ struct lpc32xx_gpio_priv *gpio_priv = dev_get_priv(dev);
+ struct gpio_regs *regs = gpio_priv->regs;
port = GPIO_TO_PORT(offset);
mask = GPIO_TO_MASK(offset);
@@ -83,7 +83,7 @@ static int lpc32xx_gpio_direction_input(struct udevice *dev, unsigned offset)
}
/* GPIO FUNCTION: SEE WARNING #2 */
- gpio_platdata->function[offset] = GPIOF_INPUT;
+ gpio_priv->function[offset] = GPIOF_INPUT;
return 0;
}
@@ -95,8 +95,8 @@ static int lpc32xx_gpio_direction_input(struct udevice *dev, unsigned offset)
static int lpc32xx_gpio_get_value(struct udevice *dev, unsigned offset)
{
int port, rank, mask, value;
- struct lpc32xx_gpio_platdata *gpio_platdata = dev_get_platdata(dev);
- struct gpio_regs *regs = gpio_platdata->regs;
+ struct lpc32xx_gpio_priv *gpio_priv = dev_get_priv(dev);
+ struct gpio_regs *regs = gpio_priv->regs;
port = GPIO_TO_PORT(offset);
@@ -130,8 +130,8 @@ static int lpc32xx_gpio_get_value(struct udevice *dev, unsigned offset)
static int gpio_set(struct udevice *dev, unsigned gpio)
{
int port, mask;
- struct lpc32xx_gpio_platdata *gpio_platdata = dev_get_platdata(dev);
- struct gpio_regs *regs = gpio_platdata->regs;
+ struct lpc32xx_gpio_priv *gpio_priv = dev_get_priv(dev);
+ struct gpio_regs *regs = gpio_priv->regs;
port = GPIO_TO_PORT(gpio);
mask = GPIO_TO_MASK(gpio);
@@ -162,8 +162,8 @@ static int gpio_set(struct udevice *dev, unsigned gpio)
static int gpio_clr(struct udevice *dev, unsigned gpio)
{
int port, mask;
- struct lpc32xx_gpio_platdata *gpio_platdata = dev_get_platdata(dev);
- struct gpio_regs *regs = gpio_platdata->regs;
+ struct lpc32xx_gpio_priv *gpio_priv = dev_get_priv(dev);
+ struct gpio_regs *regs = gpio_priv->regs;
port = GPIO_TO_PORT(gpio);
mask = GPIO_TO_MASK(gpio);
@@ -208,8 +208,8 @@ static int lpc32xx_gpio_direction_output(struct udevice *dev, unsigned offset,
int value)
{
int port, mask;
- struct lpc32xx_gpio_platdata *gpio_platdata = dev_get_platdata(dev);
- struct gpio_regs *regs = gpio_platdata->regs;
+ struct lpc32xx_gpio_priv *gpio_priv = dev_get_priv(dev);
+ struct gpio_regs *regs = gpio_priv->regs;
port = GPIO_TO_PORT(offset);
mask = GPIO_TO_MASK(offset);
@@ -231,7 +231,7 @@ static int lpc32xx_gpio_direction_output(struct udevice *dev, unsigned offset,
}
/* GPIO FUNCTION: SEE WARNING #2 */
- gpio_platdata->function[offset] = GPIOF_OUTPUT;
+ gpio_priv->function[offset] = GPIOF_OUTPUT;
return lpc32xx_gpio_set_value(dev, offset, value);
}
@@ -251,8 +251,8 @@ static int lpc32xx_gpio_direction_output(struct udevice *dev, unsigned offset,
static int lpc32xx_gpio_get_function(struct udevice *dev, unsigned offset)
{
- struct lpc32xx_gpio_platdata *gpio_platdata = dev_get_platdata(dev);
- return gpio_platdata->function[offset];
+ struct lpc32xx_gpio_priv *gpio_priv = dev_get_priv(dev);
+ return gpio_priv->function[offset];
}
static const struct dm_gpio_ops gpio_lpc32xx_ops = {
@@ -265,7 +265,7 @@ static const struct dm_gpio_ops gpio_lpc32xx_ops = {
static int lpc32xx_gpio_probe(struct udevice *dev)
{
- struct lpc32xx_gpio_platdata *gpio_platdata = dev_get_platdata(dev);
+ struct lpc32xx_gpio_priv *gpio_priv = dev_get_priv(dev);
struct gpio_dev_priv *uc_priv = dev->uclass_priv;
if (dev->of_offset == -1) {
@@ -274,12 +274,11 @@ static int lpc32xx_gpio_probe(struct udevice *dev)
}
/* set base address for GPIO registers */
- gpio_platdata->regs = (struct gpio_regs *)GPIO_BASE;
+ gpio_priv->regs = (struct gpio_regs *)GPIO_BASE;
/* all GPIO functions are unknown until requested */
/* GPIO FUNCTION: SEE WARNING #2 */
- memset(gpio_platdata->function, GPIOF_UNKNOWN,
- sizeof(gpio_platdata->function));
+ memset(gpio_priv->function, GPIOF_UNKNOWN, sizeof(gpio_priv->function));
return 0;
}
@@ -289,5 +288,5 @@ U_BOOT_DRIVER(gpio_lpc32xx) = {
.id = UCLASS_GPIO,
.ops = &gpio_lpc32xx_ops,
.probe = lpc32xx_gpio_probe,
- .priv_auto_alloc_size = sizeof(struct lpc32xx_gpio_platdata),
+ .priv_auto_alloc_size = sizeof(struct lpc32xx_gpio_priv),
};
diff --git a/drivers/mmc/bcm2835_sdhci.c b/drivers/mmc/bcm2835_sdhci.c
index 078ef0523a..227d2dfa2e 100644
--- a/drivers/mmc/bcm2835_sdhci.c
+++ b/drivers/mmc/bcm2835_sdhci.c
@@ -69,11 +69,11 @@ static inline void bcm2835_sdhci_raw_writel(struct sdhci_host *host, u32 val,
* (Which is just as well - otherwise we'd have to nobble the DMA engine
* too)
*/
- while (get_timer(bcm_host->last_write) < bcm_host->twoticks_delay)
+ while (timer_get_us() - bcm_host->last_write < bcm_host->twoticks_delay)
;
writel(val, host->ioaddr + reg);
- bcm_host->last_write = get_timer(0);
+ bcm_host->last_write = timer_get_us();
}
static inline u32 bcm2835_sdhci_raw_readl(struct sdhci_host *host, int reg)
diff --git a/drivers/mmc/mmc_write.c b/drivers/mmc/mmc_write.c
index 3db9669c82..7aea7e943b 100644
--- a/drivers/mmc/mmc_write.c
+++ b/drivers/mmc/mmc_write.c
@@ -10,6 +10,8 @@
#include <config.h>
#include <common.h>
#include <part.h>
+#include <div64.h>
+#include <linux/math64.h>
#include "mmc_private.h"
static ulong mmc_erase_t(struct mmc *mmc, ulong start, lbaint_t blkcnt)
@@ -66,6 +68,7 @@ err_out:
unsigned long mmc_berase(int dev_num, lbaint_t start, lbaint_t blkcnt)
{
int err = 0;
+ u32 start_rem, blkcnt_rem;
struct mmc *mmc = find_mmc_device(dev_num);
lbaint_t blk = 0, blk_r = 0;
int timeout = 1000;
@@ -73,7 +76,14 @@ unsigned long mmc_berase(int dev_num, lbaint_t start, lbaint_t blkcnt)
if (!mmc)
return -1;
- if ((start % mmc->erase_grp_size) || (blkcnt % mmc->erase_grp_size))
+ /*
+ * We want to see if the requested start or total block count are
+ * unaligned. We discard the whole numbers and only care about the
+ * remainder.
+ */
+ err = div_u64_rem(start, mmc->erase_grp_size, &start_rem);
+ err = div_u64_rem(blkcnt, mmc->erase_grp_size, &blkcnt_rem);
+ if (start_rem || blkcnt_rem)
printf("\n\nCaution! Your devices Erase group is 0x%x\n"
"The erase range would be change to "
"0x" LBAF "~0x" LBAF "\n\n",
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index 5467a951bb..a623f4c9fa 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -5,8 +5,8 @@
# SPDX-License-Identifier: GPL-2.0+
#
-ifneq (,$(findstring y,$(CONFIG_MTD_DEVICE)$(CONFIG_CMD_NAND)$(CONFIG_CMD_ONENAND)))
-obj-y += mtdcore.o
+ifneq (,$(findstring y,$(CONFIG_MTD_DEVICE)$(CONFIG_CMD_NAND)$(CONFIG_CMD_ONENAND)$(CONFIG_CMD_SF)))
+obj-y += mtdcore.o mtd_uboot.o
endif
obj-$(CONFIG_MTD_PARTITIONS) += mtdpart.o
obj-$(CONFIG_MTD_CONCAT) += mtdconcat.o
diff --git a/drivers/mtd/mtd_uboot.c b/drivers/mtd/mtd_uboot.c
new file mode 100644
index 0000000000..7197007d41
--- /dev/null
+++ b/drivers/mtd/mtd_uboot.c
@@ -0,0 +1,99 @@
+/*
+ * (C) Copyright 2014
+ * Heiko Schocher, DENX Software Engineering, hs@denx.de.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#include <common.h>
+#include <linux/mtd/mtd.h>
+#include <jffs2/jffs2.h>
+
+static int get_part(const char *partname, int *idx, loff_t *off, loff_t *size,
+ loff_t *maxsize, int devtype)
+{
+#ifdef CONFIG_CMD_MTDPARTS
+ struct mtd_device *dev;
+ struct part_info *part;
+ u8 pnum;
+ int ret;
+
+ ret = mtdparts_init();
+ if (ret)
+ return ret;
+
+ ret = find_dev_and_part(partname, &dev, &pnum, &part);
+ if (ret)
+ return ret;
+
+ if (dev->id->type != devtype) {
+ printf("not same typ %d != %d\n", dev->id->type, devtype);
+ return -1;
+ }
+
+ *off = part->offset;
+ *size = part->size;
+ *maxsize = part->size;
+ *idx = dev->id->num;
+
+ return 0;
+#else
+ puts("offset is not a number\n");
+ return -1;
+#endif
+}
+
+int mtd_arg_off(const char *arg, int *idx, loff_t *off, loff_t *size,
+ loff_t *maxsize, int devtype, int chipsize)
+{
+ if (!str2off(arg, off))
+ return get_part(arg, idx, off, size, maxsize, devtype);
+
+ if (*off >= chipsize) {
+ puts("Offset exceeds device limit\n");
+ return -1;
+ }
+
+ *maxsize = chipsize - *off;
+ *size = *maxsize;
+ return 0;
+}
+
+int mtd_arg_off_size(int argc, char *const argv[], int *idx, loff_t *off,
+ loff_t *size, loff_t *maxsize, int devtype, int chipsize)
+{
+ int ret;
+
+ if (argc == 0) {
+ *off = 0;
+ *size = chipsize;
+ *maxsize = *size;
+ goto print;
+ }
+
+ ret = mtd_arg_off(argv[0], idx, off, size, maxsize, devtype,
+ chipsize);
+ if (ret)
+ return ret;
+
+ if (argc == 1)
+ goto print;
+
+ if (!str2off(argv[1], size)) {
+ printf("'%s' is not a number\n", argv[1]);
+ return -1;
+ }
+
+ if (*size > *maxsize) {
+ puts("Size exceeds partition or device limit\n");
+ return -1;
+ }
+
+print:
+ printf("device %d ", *idx);
+ if (*size == chipsize)
+ puts("whole chip\n");
+ else
+ printf("offset 0x%llx, size 0x%llx\n",
+ (unsigned long long)*off, (unsigned long long)*size);
+ return 0;
+}
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index a0cf4d5fe4..347ea62e0b 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -73,6 +73,5 @@ obj-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_spl.o
obj-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_spl.o
obj-$(CONFIG_NAND_MXC) += mxc_nand_spl.o
obj-$(CONFIG_NAND_MXS) += mxs_nand_spl.o mxs_nand.o
-obj-$(CONFIG_NAND_SUNXI) += sunxi_nand_spl.o
endif # drivers
diff --git a/drivers/mtd/nand/omap_gpmc.c b/drivers/mtd/nand/omap_gpmc.c
index 610f9698e1..4372988ed2 100644
--- a/drivers/mtd/nand/omap_gpmc.c
+++ b/drivers/mtd/nand/omap_gpmc.c
@@ -340,6 +340,125 @@ static int omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat,
return 0;
}
+#ifdef CONFIG_NAND_OMAP_GPMC_PREFETCH
+
+#define PREFETCH_CONFIG1_CS_SHIFT 24
+#define PREFETCH_FIFOTHRESHOLD_MAX 0x40
+#define PREFETCH_FIFOTHRESHOLD(val) ((val) << 8)
+#define PREFETCH_STATUS_COUNT(val) (val & 0x00003fff)
+#define PREFETCH_STATUS_FIFO_CNT(val) ((val >> 24) & 0x7F)
+#define ENABLE_PREFETCH (1 << 7)
+
+/**
+ * omap_prefetch_enable - configures and starts prefetch transfer
+ * @fifo_th: fifo threshold to be used for read/ write
+ * @count: number of bytes to be transferred
+ * @is_write: prefetch read(0) or write post(1) mode
+ * @cs: chip select to use
+ */
+static int omap_prefetch_enable(int fifo_th, unsigned int count, int is_write, int cs)
+{
+ uint32_t val;
+
+ if (fifo_th > PREFETCH_FIFOTHRESHOLD_MAX)
+ return -EINVAL;
+
+ if (readl(&gpmc_cfg->prefetch_control))
+ return -EBUSY;
+
+ /* Set the amount of bytes to be prefetched */
+ writel(count, &gpmc_cfg->prefetch_config2);
+
+ val = (cs << PREFETCH_CONFIG1_CS_SHIFT) | (is_write & 1) |
+ PREFETCH_FIFOTHRESHOLD(fifo_th) | ENABLE_PREFETCH;
+ writel(val, &gpmc_cfg->prefetch_config1);
+
+ /* Start the prefetch engine */
+ writel(1, &gpmc_cfg->prefetch_control);
+
+ return 0;
+}
+
+/**
+ * omap_prefetch_reset - disables and stops the prefetch engine
+ */
+static void omap_prefetch_reset(void)
+{
+ writel(0, &gpmc_cfg->prefetch_control);
+ writel(0, &gpmc_cfg->prefetch_config1);
+}
+
+static int __read_prefetch_aligned(struct nand_chip *chip, uint32_t *buf, int len)
+{
+ int ret;
+ uint32_t cnt;
+ struct omap_nand_info *info = chip->priv;
+
+ ret = omap_prefetch_enable(PREFETCH_FIFOTHRESHOLD_MAX, len, 0, info->cs);
+ if (ret < 0)
+ return ret;
+
+ do {
+ int i;
+
+ cnt = readl(&gpmc_cfg->prefetch_status);
+ cnt = PREFETCH_STATUS_FIFO_CNT(cnt);
+
+ for (i = 0; i < cnt / 4; i++) {
+ *buf++ = readl(CONFIG_SYS_NAND_BASE);
+ len -= 4;
+ }
+ } while (len);
+
+ omap_prefetch_reset();
+
+ return 0;
+}
+
+static inline void omap_nand_read(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+ struct nand_chip *chip = mtd->priv;
+
+ if (chip->options & NAND_BUSWIDTH_16)
+ nand_read_buf16(mtd, buf, len);
+ else
+ nand_read_buf(mtd, buf, len);
+}
+
+static void omap_nand_read_prefetch(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+ int ret;
+ uint32_t head, tail;
+ struct nand_chip *chip = mtd->priv;
+
+ /*
+ * If the destination buffer is unaligned, start with reading
+ * the overlap byte-wise.
+ */
+ head = ((uint32_t) buf) % 4;
+ if (head) {
+ omap_nand_read(mtd, buf, head);
+ buf += head;
+ len -= head;
+ }
+
+ /*
+ * Only transfer multiples of 4 bytes in a pre-fetched fashion.
+ * If there's a residue, care for it byte-wise afterwards.
+ */
+ tail = len % 4;
+
+ ret = __read_prefetch_aligned(chip, (uint32_t *)buf, len - tail);
+ if (ret < 0) {
+ /* fallback in case the prefetch engine is busy */
+ omap_nand_read(mtd, buf, len);
+ } else if (tail) {
+ buf += len - tail;
+ omap_nand_read(mtd, buf, tail);
+ }
+}
+#endif /* CONFIG_NAND_OMAP_GPMC_PREFETCH */
+
#ifdef CONFIG_NAND_OMAP_ELM
/*
* omap_reverse_list - re-orders list elements in reverse order [internal]
@@ -452,115 +571,6 @@ static int omap_correct_data_bch(struct mtd_info *mtd, uint8_t *dat,
return (err) ? err : error_count;
}
-#ifdef CONFIG_NAND_OMAP_GPMC_PREFETCH
-
-#define PREFETCH_CONFIG1_CS_SHIFT 24
-#define PREFETCH_FIFOTHRESHOLD_MAX 0x40
-#define PREFETCH_FIFOTHRESHOLD(val) ((val) << 8)
-#define PREFETCH_STATUS_COUNT(val) (val & 0x00003fff)
-#define PREFETCH_STATUS_FIFO_CNT(val) ((val >> 24) & 0x7F)
-#define ENABLE_PREFETCH (1 << 7)
-
-/**
- * omap_prefetch_enable - configures and starts prefetch transfer
- * @fifo_th: fifo threshold to be used for read/ write
- * @count: number of bytes to be transferred
- * @is_write: prefetch read(0) or write post(1) mode
- * @cs: chip select to use
- */
-static int omap_prefetch_enable(int fifo_th, unsigned int count, int is_write, int cs)
-{
- uint32_t val;
-
- if (fifo_th > PREFETCH_FIFOTHRESHOLD_MAX)
- return -EINVAL;
-
- if (readl(&gpmc_cfg->prefetch_control))
- return -EBUSY;
-
- /* Set the amount of bytes to be prefetched */
- writel(count, &gpmc_cfg->prefetch_config2);
-
- val = (cs << PREFETCH_CONFIG1_CS_SHIFT) | (is_write & 1) |
- PREFETCH_FIFOTHRESHOLD(fifo_th) | ENABLE_PREFETCH;
- writel(val, &gpmc_cfg->prefetch_config1);
-
- /* Start the prefetch engine */
- writel(1, &gpmc_cfg->prefetch_control);
-
- return 0;
-}
-
-/**
- * omap_prefetch_reset - disables and stops the prefetch engine
- */
-static void omap_prefetch_reset(void)
-{
- writel(0, &gpmc_cfg->prefetch_control);
- writel(0, &gpmc_cfg->prefetch_config1);
-}
-
-static int __read_prefetch_aligned(struct nand_chip *chip, uint32_t *buf, int len)
-{
- int ret;
- uint32_t cnt;
- struct omap_nand_info *info = chip->priv;
-
- ret = omap_prefetch_enable(PREFETCH_FIFOTHRESHOLD_MAX, len, 0, info->cs);
- if (ret < 0)
- return ret;
-
- do {
- int i;
-
- cnt = readl(&gpmc_cfg->prefetch_status);
- cnt = PREFETCH_STATUS_FIFO_CNT(cnt);
-
- for (i = 0; i < cnt / 4; i++) {
- *buf++ = readl(CONFIG_SYS_NAND_BASE);
- len -= 4;
- }
- } while (len);
-
- omap_prefetch_reset();
-
- return 0;
-}
-
-static void omap_nand_read_prefetch8(struct mtd_info *mtd, uint8_t *buf, int len)
-{
- int ret;
- uint32_t head, tail;
- struct nand_chip *chip = mtd->priv;
-
- /*
- * If the destination buffer is unaligned, start with reading
- * the overlap byte-wise.
- */
- head = ((uint32_t) buf) % 4;
- if (head) {
- nand_read_buf(mtd, buf, head);
- buf += head;
- len -= head;
- }
-
- /*
- * Only transfer multiples of 4 bytes in a pre-fetched fashion.
- * If there's a residue, care for it byte-wise afterwards.
- */
- tail = len % 4;
-
- ret = __read_prefetch_aligned(chip, (uint32_t *) buf, len - tail);
- if (ret < 0) {
- /* fallback in case the prefetch engine is busy */
- nand_read_buf(mtd, buf, len);
- } else if (tail) {
- buf += len - tail;
- nand_read_buf(mtd, buf, tail);
- }
-}
-#endif /* CONFIG_NAND_OMAP_GPMC_PREFETCH */
-
/**
* omap_read_page_bch - hardware ecc based page read function
* @mtd: mtd info structure
@@ -1011,13 +1021,11 @@ int board_nand_init(struct nand_chip *nand)
if (err)
return err;
- /* TODO: Implement for 16-bit bus width */
- if (nand->options & NAND_BUSWIDTH_16)
- nand->read_buf = nand_read_buf16;
#ifdef CONFIG_NAND_OMAP_GPMC_PREFETCH
- else
- nand->read_buf = omap_nand_read_prefetch8;
+ nand->read_buf = omap_nand_read_prefetch;
#else
+ if (nand->options & NAND_BUSWIDTH_16)
+ nand->read_buf = nand_read_buf16;
else
nand->read_buf = nand_read_buf;
#endif
diff --git a/drivers/mtd/nand/sunxi_nand_spl.c b/drivers/mtd/nand/sunxi_nand_spl.c
deleted file mode 100644
index 75982f54cc..0000000000
--- a/drivers/mtd/nand/sunxi_nand_spl.c
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * Copyright (c) 2014, Antmicro Ltd <www.antmicro.com>
- * Copyright (c) 2015, Turtle Solutions <www.turtle-solutions.eu>
- * Copyright (c) 2015, Roy Spliet <rspliet@ultimaker.com>
- *
- * SPDX-License-Identifier: GPL-2.0+
- *
- * \todo Detect chip parameters (page size, ECC mode, randomisation...)
- */
-
-#include <common.h>
-#include <config.h>
-#include <asm/io.h>
-#include <nand.h>
-#include <asm/arch/cpu.h>
-#include <asm/arch/clock.h>
-#include <asm/arch/dma.h>
-#include <asm/arch/nand.h>
-
-void
-nand_init(void)
-{
- struct sunxi_ccm_reg * const ccm =
- (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
- struct sunxi_nand * const nand = (struct sunxi_nand *)SUNXI_NFC_BASE;
- u32 val;
-
- board_nand_init();
-
- /* "un-gate" NAND clock and clock source
- * This assumes that the clock was already correctly configured by
- * BootROM */
- setbits_le32(&ccm->ahb_gate0, (1 << AHB_GATE_OFFSET_NAND0));
-#ifdef CONFIG_MACH_SUN9I
- setbits_le32(&ccm->ahb_gate1, (1 << AHB_GATE_OFFSET_DMA));
-#else
- setbits_le32(&ccm->ahb_gate0, (1 << AHB_GATE_OFFSET_DMA));
-#endif
- setbits_le32(&ccm->nand0_clk_cfg, 0x80000000);
-
- val = readl(&nand->ctl);
- val |= SUNXI_NAND_CTL_RST;
- writel(val, &nand->ctl);
-
- /* Wait until reset pin is deasserted */
- do {
- val = readl(&nand->ctl);
- if (!(val & SUNXI_NAND_CTL_RST))
- break;
- } while (1);
-
- /** \todo Chip select, currently kind of static */
- val = readl(&nand->ctl);
- val &= 0xf0fff0f2;
- val |= SUNXI_NAND_CTL_EN;
- val |= SUNXI_NAND_CTL_PAGE_SIZE(CONFIG_NAND_SUNXI_PAGE_SIZE);
- writel(val, &nand->ctl);
-
- writel(0x100, &nand->timing_ctl);
- writel(0x7ff, &nand->timing_cfg);
-
- /* reset CMD */
- val = SUNXI_NAND_CMD_SEND_CMD1 | SUNXI_NAND_CMD_WAIT_FLAG |
- NAND_CMD_RESET;
- writel(val, &nand->cmd);
- do {
- val = readl(&nand->st);
- if (val & (1<<1))
- break;
- udelay(1000);
- } while (1);
-
- printf("Nand initialised\n");
-}
-
-int
-nand_wait_timeout(u32 *reg, u32 mask, u32 val)
-{
- unsigned long tmo = timer_get_us() + 1000000; /* 1s */
-
- while ((readl(reg) & mask) != val) {
- if (timer_get_us() > tmo)
- return -ETIMEDOUT;
- }
-
- return 0;
-}
-
-/* random seed */
-static const uint16_t random_seed[128] = {
- 0x2b75, 0x0bd0, 0x5ca3, 0x62d1, 0x1c93, 0x07e9, 0x2162, 0x3a72,
- 0x0d67, 0x67f9, 0x1be7, 0x077d, 0x032f, 0x0dac, 0x2716, 0x2436,
- 0x7922, 0x1510, 0x3860, 0x5287, 0x480f, 0x4252, 0x1789, 0x5a2d,
- 0x2a49, 0x5e10, 0x437f, 0x4b4e, 0x2f45, 0x216e, 0x5cb7, 0x7130,
- 0x2a3f, 0x60e4, 0x4dc9, 0x0ef0, 0x0f52, 0x1bb9, 0x6211, 0x7a56,
- 0x226d, 0x4ea7, 0x6f36, 0x3692, 0x38bf, 0x0c62, 0x05eb, 0x4c55,
- 0x60f4, 0x728c, 0x3b6f, 0x2037, 0x7f69, 0x0936, 0x651a, 0x4ceb,
- 0x6218, 0x79f3, 0x383f, 0x18d9, 0x4f05, 0x5c82, 0x2912, 0x6f17,
- 0x6856, 0x5938, 0x1007, 0x61ab, 0x3e7f, 0x57c2, 0x542f, 0x4f62,
- 0x7454, 0x2eac, 0x7739, 0x42d4, 0x2f90, 0x435a, 0x2e52, 0x2064,
- 0x637c, 0x66ad, 0x2c90, 0x0bad, 0x759c, 0x0029, 0x0986, 0x7126,
- 0x1ca7, 0x1605, 0x386a, 0x27f5, 0x1380, 0x6d75, 0x24c3, 0x0f8e,
- 0x2b7a, 0x1418, 0x1fd1, 0x7dc1, 0x2d8e, 0x43af, 0x2267, 0x7da3,
- 0x4e3d, 0x1338, 0x50db, 0x454d, 0x764d, 0x40a3, 0x42e6, 0x262b,
- 0x2d2e, 0x1aea, 0x2e17, 0x173d, 0x3a6e, 0x71bf, 0x25f9, 0x0a5d,
- 0x7c57, 0x0fbe, 0x46ce, 0x4939, 0x6b17, 0x37bb, 0x3e91, 0x76db,
-};
-
-uint32_t ecc_errors = 0;
-
-static void
-nand_config_ecc(struct sunxi_nand *nand, uint32_t page, int syndrome)
-{
- static u8 strength[] = {16, 24, 28, 32, 40, 48, 56, 60, 64};
- int i;
- uint32_t ecc_mode;
- u32 ecc;
- u16 seed = 0;
-
- for (i = 0; i < ARRAY_SIZE(strength); i++) {
- if (CONFIG_NAND_SUNXI_ECC_STRENGTH == strength[i]) {
- ecc_mode = i;
- break;
- }
- }
-
- if (i == ARRAY_SIZE(strength)) {
- printf("ECC strength unsupported\n");
- return;
- }
-
- ecc = SUNXI_NAND_ECC_CTL_ECC_EN |
- SUNXI_NAND_ECC_CTL_PIPELINE |
- SUNXI_NAND_ECC_CTL_RND_EN |
- SUNXI_NAND_ECC_CTL_MODE(ecc_mode);
-
- if (CONFIG_NAND_SUNXI_ECC_STEP == 512)
- ecc |= SUNXI_NAND_ECC_CTL_BS_512B;
-
- if (syndrome)
- seed = 0x4A80;
- else
- seed = random_seed[page % ARRAY_SIZE(random_seed)];
-
- ecc |= SUNXI_NAND_ECC_CTL_RND_SEED(seed);
-
- writel(ecc, &nand->ecc_ctl);
-}
-
-/* read CONFIG_NAND_SUNXI_ECC_STEP bytes from real_addr to temp_buf */
-void
-nand_read_block(struct sunxi_nand *nand, phys_addr_t src, dma_addr_t dst,
- int syndrome)
-{
- struct sunxi_dma * const dma = (struct sunxi_dma *)SUNXI_DMA_BASE;
- struct sunxi_dma_cfg * const dma_cfg = &dma->ddma[0];
-
- uint32_t shift;
- uint32_t page;
- uint32_t addr;
- uint32_t oob_offset;
- uint32_t ecc_bytes;
- u32 val;
- u32 cmd;
-
- page = src / CONFIG_NAND_SUNXI_PAGE_SIZE;
- if (page > 0xFFFF) {
- /* TODO: currently this is not supported */
- printf("Reading from address >= %08X is not allowed.\n",
- 0xFFFF * CONFIG_NAND_SUNXI_PAGE_SIZE);
- return;
- }
-
- shift = src % CONFIG_NAND_SUNXI_PAGE_SIZE;
- writel(0, &nand->ecc_st);
-
- /* ECC_CTL, randomization */
- ecc_bytes = CONFIG_NAND_SUNXI_ECC_STRENGTH *
- fls(CONFIG_NAND_SUNXI_ECC_STEP * 8);
- ecc_bytes = DIV_ROUND_UP(ecc_bytes, 8);
- ecc_bytes += (ecc_bytes & 1); /* Align to 2-bytes */
- ecc_bytes += 4;
-
- nand_config_ecc(nand, page, syndrome);
- if (syndrome) {
- /* shift every 1kB in syndrome */
- shift += (shift / CONFIG_NAND_SUNXI_ECC_STEP) * ecc_bytes;
- oob_offset = CONFIG_NAND_SUNXI_ECC_STEP + shift;
- } else {
- oob_offset = CONFIG_NAND_SUNXI_PAGE_SIZE +
- (shift / CONFIG_NAND_SUNXI_ECC_STEP) * ecc_bytes;
- }
-
- addr = (page << 16) | shift;
-
- /* DMA */
- val = readl(&nand->ctl);
- writel(val | SUNXI_NAND_CTL_RAM_METHOD_DMA, &nand->ctl);
-
- writel(oob_offset, &nand->spare_area);
-
- /* DMAC
- * \todo Separate this into a tidy driver */
- writel(0x0, &dma->irq_en); /* clear dma interrupts */
- writel((uint32_t) &nand->io_data , &dma_cfg->src_addr);
- writel(dst , &dma_cfg->dst_addr);
- writel(0x00007F0F , &dma_cfg->ddma_para);
- writel(CONFIG_NAND_SUNXI_ECC_STEP, &dma_cfg->bc);
-
- val = SUNXI_DMA_CTL_SRC_DRQ(DDMA_SRC_DRQ_NAND) |
- SUNXI_DMA_CTL_MODE_IO |
- SUNXI_DMA_CTL_SRC_DATA_WIDTH_32 |
- SUNXI_DMA_CTL_DST_DRQ(DDMA_DST_DRQ_SDRAM) |
- SUNXI_DMA_CTL_DST_DATA_WIDTH_32 |
- SUNXI_DMA_CTL_TRIGGER;
- writel(val, &dma_cfg->ctl);
-
- writel(0x00E00530, &nand->rcmd_set);
- nand_wait_timeout(&nand->st, SUNXI_NAND_ST_FIFO_FULL, 0);
-
- writel(1 , &nand->block_num);
- writel(addr, &nand->addr_low);
- writel(0 , &nand->addr_high);
-
- /* CMD (PAGE READ) */
- cmd = 0x85E80000;
- cmd |= SUNXI_NAND_CMD_ADDR_CYCLES(CONFIG_NAND_SUNXI_ADDR_CYCLES);
- cmd |= (syndrome ? SUNXI_NAND_CMD_ORDER_SEQ :
- SUNXI_NAND_CMD_ORDER_INTERLEAVE);
- writel(cmd, &nand->cmd);
-
- if(nand_wait_timeout(&nand->st, SUNXI_NAND_ST_DMA_INT,
- SUNXI_NAND_ST_DMA_INT)) {
- printf("NAND timeout reading data\n");
- return;
- }
-
- if(nand_wait_timeout(&dma_cfg->ctl, SUNXI_DMA_CTL_TRIGGER, 0)) {
- printf("NAND timeout reading data\n");
- return;
- }
-
- if (readl(&nand->ecc_st))
- ecc_errors++;
-}
-
-int
-nand_spl_load_image(uint32_t offs, unsigned int size, void *dest)
-{
- struct sunxi_nand * const nand = (struct sunxi_nand *)SUNXI_NFC_BASE;
- dma_addr_t dst_block;
- dma_addr_t dst_end;
- phys_addr_t addr = offs;
-
- dst_end = ((dma_addr_t) dest) + size;
-
- memset((void *)dest, 0x0, size);
- ecc_errors = 0;
- for (dst_block = (dma_addr_t) dest; dst_block < dst_end;
- dst_block += CONFIG_NAND_SUNXI_ECC_STEP,
- addr += CONFIG_NAND_SUNXI_ECC_STEP) {
- /* syndrome read first 4MiB to match Allwinner BootROM */
- nand_read_block(nand, addr, dst_block, addr < 0x400000);
- }
-
- if (ecc_errors)
- printf("Error: %d ECC failures detected\n", ecc_errors);
- return ecc_errors == 0;
-}
-
-void
-nand_deselect(void)
-{}
diff --git a/drivers/mtd/spi/Kconfig b/drivers/mtd/spi/Kconfig
index ac6d09f928..4f0c040214 100644
--- a/drivers/mtd/spi/Kconfig
+++ b/drivers/mtd/spi/Kconfig
@@ -1,3 +1,5 @@
+menu "SPI Flash Support"
+
config DM_SPI_FLASH
bool "Enable Driver Model for SPI flash"
depends on DM && DM_SPI
@@ -22,3 +24,49 @@ config SPI_FLASH_SANDBOX
bus (see CONFIG_SANDBOX_SPI) and SPI traffic will be routed to this
device. Typically the contents of the emulated SPI flash device is
stored in a file on the host filesystem.
+
+config SPI_FLASH
+ bool "Legacy SPI Flash Interface support"
+ help
+ Enable the legacy SPI flash support. This will include basic
+ standard support for things like probing, read / write, and
+ erasing through cmd_sf interface.
+
+ If unsure, say N
+
+config SPI_FLASH_BAR
+ bool "SPI flash Bank/Extended address register support"
+ depends on SPI_FLASH
+ help
+ Enable the SPI flash Bank/Extended address register support.
+ Bank/Extended address registers are used to access the flash
+ which has size > 16MiB in 3-byte addressing.
+
+config SPI_FLASH_DATAFLASH
+ bool "AT45xxx DataFlash support"
+ depends on SPI_FLASH && DM_SPI_FLASH
+ help
+ Enable the access for SPI-flash-based AT45xxx DataFlash chips.
+ DataFlash is a kind of SPI flash. Most AT45 chips have two buffers
+ in each chip, which may be used for double buffered I/O; but this
+ driver doesn't (yet) use these for any kind of i/o overlap or prefetching.
+
+ Sometimes DataFlash is packaged in MMC-format cards, although the
+ MMC stack can't (yet?) distinguish between MMC and DataFlash
+ protocols during enumeration.
+
+ If unsure, say N
+
+config SPI_FLASH_MTD
+ bool "SPI Flash MTD support"
+ depends on SPI_FLASH
+ help
+ Enable the MTD support for spi flash layer, this adapter is for
+ translating mtd_read/mtd_write commands into spi_flash_read/write
+ commands. It is not intended to use it within sf_cmd or the SPI
+ flash subsystem. Such an adapter is needed for subsystems like
+ UBI which can only operate on top of the MTD layer.
+
+ If unsure, say N
+
+endmenu # menu "SPI Flash Support"
diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile
index c61b784e17..ff48b25f6f 100644
--- a/drivers/mtd/spi/Makefile
+++ b/drivers/mtd/spi/Makefile
@@ -17,5 +17,7 @@ obj-$(CONFIG_SPI_FLASH) += sf_probe.o
#endif
obj-$(CONFIG_CMD_SF) += sf.o
obj-$(CONFIG_SPI_FLASH) += sf_ops.o sf_params.o
+obj-$(CONFIG_SPI_FLASH_DATAFLASH) += sf_dataflash.o
+obj-$(CONFIG_SPI_FLASH_MTD) += sf_mtd.o
obj-$(CONFIG_SPI_FLASH_SANDBOX) += sandbox.o
obj-$(CONFIG_SPI_M95XXX) += eeprom_m95xxx.o
diff --git a/drivers/mtd/spi/sf_dataflash.c b/drivers/mtd/spi/sf_dataflash.c
new file mode 100644
index 0000000000..3111f4fd12
--- /dev/null
+++ b/drivers/mtd/spi/sf_dataflash.c
@@ -0,0 +1,701 @@
+/*
+ *
+ * Atmel DataFlash probing
+ *
+ * Copyright (C) 2004-2009, 2015 Freescale Semiconductor, Inc.
+ * Haikun Wang (haikun.wang@freescale.com)
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+*/
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <spi.h>
+#include <spi_flash.h>
+#include <div64.h>
+#include <linux/err.h>
+#include <linux/math64.h>
+
+#include "sf_internal.h"
+
+/* reads can bypass the buffers */
+#define OP_READ_CONTINUOUS 0xE8
+#define OP_READ_PAGE 0xD2
+
+/* group B requests can run even while status reports "busy" */
+#define OP_READ_STATUS 0xD7 /* group B */
+
+/* move data between host and buffer */
+#define OP_READ_BUFFER1 0xD4 /* group B */
+#define OP_READ_BUFFER2 0xD6 /* group B */
+#define OP_WRITE_BUFFER1 0x84 /* group B */
+#define OP_WRITE_BUFFER2 0x87 /* group B */
+
+/* erasing flash */
+#define OP_ERASE_PAGE 0x81
+#define OP_ERASE_BLOCK 0x50
+
+/* move data between buffer and flash */
+#define OP_TRANSFER_BUF1 0x53
+#define OP_TRANSFER_BUF2 0x55
+#define OP_MREAD_BUFFER1 0xD4
+#define OP_MREAD_BUFFER2 0xD6
+#define OP_MWERASE_BUFFER1 0x83
+#define OP_MWERASE_BUFFER2 0x86
+#define OP_MWRITE_BUFFER1 0x88 /* sector must be pre-erased */
+#define OP_MWRITE_BUFFER2 0x89 /* sector must be pre-erased */
+
+/* write to buffer, then write-erase to flash */
+#define OP_PROGRAM_VIA_BUF1 0x82
+#define OP_PROGRAM_VIA_BUF2 0x85
+
+/* compare buffer to flash */
+#define OP_COMPARE_BUF1 0x60
+#define OP_COMPARE_BUF2 0x61
+
+/* read flash to buffer, then write-erase to flash */
+#define OP_REWRITE_VIA_BUF1 0x58
+#define OP_REWRITE_VIA_BUF2 0x59
+
+/*
+ * newer chips report JEDEC manufacturer and device IDs; chip
+ * serial number and OTP bits; and per-sector writeprotect.
+ */
+#define OP_READ_ID 0x9F
+#define OP_READ_SECURITY 0x77
+#define OP_WRITE_SECURITY_REVC 0x9A
+#define OP_WRITE_SECURITY 0x9B /* revision D */
+
+
+struct dataflash {
+ uint8_t command[16];
+ unsigned short page_offset; /* offset in flash address */
+};
+
+/*
+ * Return the status of the DataFlash device.
+ */
+static inline int dataflash_status(struct spi_slave *spi)
+{
+ int ret;
+ u8 status;
+ /*
+ * NOTE: at45db321c over 25 MHz wants to write
+ * a dummy byte after the opcode...
+ */
+ ret = spi_flash_cmd(spi, OP_READ_STATUS, &status, 1);
+ return ret ? -EIO : status;
+}
+
+/*
+ * Poll the DataFlash device until it is READY.
+ * This usually takes 5-20 msec or so; more for sector erase.
+ * ready: return > 0
+ */
+static int dataflash_waitready(struct spi_slave *spi)
+{
+ int status;
+ int timeout = 2 * CONFIG_SYS_HZ;
+ int timebase;
+
+ timebase = get_timer(0);
+ do {
+ status = dataflash_status(spi);
+ if (status < 0)
+ status = 0;
+
+ if (status & (1 << 7)) /* RDY/nBSY */
+ return status;
+
+ mdelay(3);
+ } while (get_timer(timebase) < timeout);
+
+ return -ETIME;
+}
+
+/*
+ * Erase pages of flash.
+ */
+static int spi_dataflash_erase(struct udevice *dev, u32 offset, size_t len)
+{
+ struct dataflash *dataflash;
+ struct spi_flash *spi_flash;
+ struct spi_slave *spi;
+ unsigned blocksize;
+ uint8_t *command;
+ uint32_t rem;
+ int status;
+
+ dataflash = dev_get_priv(dev);
+ spi_flash = dev_get_uclass_priv(dev);
+ spi = spi_flash->spi;
+
+ blocksize = spi_flash->page_size << 3;
+
+ memset(dataflash->command, 0 , sizeof(dataflash->command));
+ command = dataflash->command;
+
+ debug("%s: erase addr=0x%x len 0x%x\n", dev->name, offset, len);
+
+ div_u64_rem(len, spi_flash->page_size, &rem);
+ if (rem)
+ return -EINVAL;
+ div_u64_rem(offset, spi_flash->page_size, &rem);
+ if (rem)
+ return -EINVAL;
+
+ status = spi_claim_bus(spi);
+ if (status) {
+ debug("SPI DATAFLASH: unable to claim SPI bus\n");
+ return status;
+ }
+
+ while (len > 0) {
+ unsigned int pageaddr;
+ int do_block;
+ /*
+ * Calculate flash page address; use block erase (for speed) if
+ * we're at a block boundary and need to erase the whole block.
+ */
+ pageaddr = div_u64(offset, spi_flash->page_size);
+ do_block = (pageaddr & 0x7) == 0 && len >= blocksize;
+ pageaddr = pageaddr << dataflash->page_offset;
+
+ command[0] = do_block ? OP_ERASE_BLOCK : OP_ERASE_PAGE;
+ command[1] = (uint8_t)(pageaddr >> 16);
+ command[2] = (uint8_t)(pageaddr >> 8);
+ command[3] = 0;
+
+ debug("%s ERASE %s: (%x) %x %x %x [%d]\n",
+ dev->name, do_block ? "block" : "page",
+ command[0], command[1], command[2], command[3],
+ pageaddr);
+
+ status = spi_flash_cmd_write(spi, command, 4, NULL, 0);
+ if (status < 0) {
+ debug("%s: erase send command error!\n", dev->name);
+ return -EIO;
+ }
+
+ status = dataflash_waitready(spi);
+ if (status < 0) {
+ debug("%s: erase waitready error!\n", dev->name);
+ return status;
+ }
+
+ if (do_block) {
+ offset += blocksize;
+ len -= blocksize;
+ } else {
+ offset += spi_flash->page_size;
+ len -= spi_flash->page_size;
+ }
+ }
+
+ spi_release_bus(spi);
+
+ return 0;
+}
+
+/*
+ * Read from the DataFlash device.
+ * offset : Start offset in flash device
+ * len : Amount to read
+ * buf : Buffer containing the data
+ */
+static int spi_dataflash_read(struct udevice *dev, u32 offset, size_t len,
+ void *buf)
+{
+ struct dataflash *dataflash;
+ struct spi_flash *spi_flash;
+ struct spi_slave *spi;
+ unsigned int addr;
+ uint8_t *command;
+ int status;
+
+ dataflash = dev_get_priv(dev);
+ spi_flash = dev_get_uclass_priv(dev);
+ spi = spi_flash->spi;
+
+ memset(dataflash->command, 0 , sizeof(dataflash->command));
+ command = dataflash->command;
+
+ debug("%s: erase addr=0x%x len 0x%x\n", dev->name, offset, len);
+ debug("READ: (%x) %x %x %x\n",
+ command[0], command[1], command[2], command[3]);
+
+ /* Calculate flash page/byte address */
+ addr = (((unsigned)offset / spi_flash->page_size)
+ << dataflash->page_offset)
+ + ((unsigned)offset % spi_flash->page_size);
+
+ status = spi_claim_bus(spi);
+ if (status) {
+ debug("SPI DATAFLASH: unable to claim SPI bus\n");
+ return status;
+ }
+
+ /*
+ * Continuous read, max clock = f(car) which may be less than
+ * the peak rate available. Some chips support commands with
+ * fewer "don't care" bytes. Both buffers stay unchanged.
+ */
+ command[0] = OP_READ_CONTINUOUS;
+ command[1] = (uint8_t)(addr >> 16);
+ command[2] = (uint8_t)(addr >> 8);
+ command[3] = (uint8_t)(addr >> 0);
+
+ /* plus 4 "don't care" bytes, command len: 4 + 4 "don't care" bytes */
+ status = spi_flash_cmd_read(spi, command, 8, buf, len);
+
+ spi_release_bus(spi);
+
+ return status;
+}
+
+/*
+ * Write to the DataFlash device.
+ * offset : Start offset in flash device
+ * len : Amount to write
+ * buf : Buffer containing the data
+ */
+int spi_dataflash_write(struct udevice *dev, u32 offset, size_t len,
+ const void *buf)
+{
+ struct dataflash *dataflash;
+ struct spi_flash *spi_flash;
+ struct spi_slave *spi;
+ uint8_t *command;
+ unsigned int pageaddr, addr, to, writelen;
+ size_t remaining = len;
+ u_char *writebuf = (u_char *)buf;
+ int status = -EINVAL;
+
+ dataflash = dev_get_priv(dev);
+ spi_flash = dev_get_uclass_priv(dev);
+ spi = spi_flash->spi;
+
+ memset(dataflash->command, 0 , sizeof(dataflash->command));
+ command = dataflash->command;
+
+ debug("%s: write 0x%x..0x%x\n", dev->name, offset, (offset + len));
+
+ pageaddr = ((unsigned)offset / spi_flash->page_size);
+ to = ((unsigned)offset % spi_flash->page_size);
+ if (to + len > spi_flash->page_size)
+ writelen = spi_flash->page_size - to;
+ else
+ writelen = len;
+
+ status = spi_claim_bus(spi);
+ if (status) {
+ debug("SPI DATAFLASH: unable to claim SPI bus\n");
+ return status;
+ }
+
+ while (remaining > 0) {
+ debug("write @ %d:%d len=%d\n", pageaddr, to, writelen);
+
+ /*
+ * REVISIT:
+ * (a) each page in a sector must be rewritten at least
+ * once every 10K sibling erase/program operations.
+ * (b) for pages that are already erased, we could
+ * use WRITE+MWRITE not PROGRAM for ~30% speedup.
+ * (c) WRITE to buffer could be done while waiting for
+ * a previous MWRITE/MWERASE to complete ...
+ * (d) error handling here seems to be mostly missing.
+ *
+ * Two persistent bits per page, plus a per-sector counter,
+ * could support (a) and (b) ... we might consider using
+ * the second half of sector zero, which is just one block,
+ * to track that state. (On AT91, that sector should also
+ * support boot-from-DataFlash.)
+ */
+
+ addr = pageaddr << dataflash->page_offset;
+
+ /* (1) Maybe transfer partial page to Buffer1 */
+ if (writelen != spi_flash->page_size) {
+ command[0] = OP_TRANSFER_BUF1;
+ command[1] = (addr & 0x00FF0000) >> 16;
+ command[2] = (addr & 0x0000FF00) >> 8;
+ command[3] = 0;
+
+ debug("TRANSFER: (%x) %x %x %x\n",
+ command[0], command[1], command[2], command[3]);
+
+ status = spi_flash_cmd_write(spi, command, 4, NULL, 0);
+ if (status < 0) {
+ debug("%s: write(<pagesize) command error!\n",
+ dev->name);
+ return -EIO;
+ }
+
+ status = dataflash_waitready(spi);
+ if (status < 0) {
+ debug("%s: write(<pagesize) waitready error!\n",
+ dev->name);
+ return status;
+ }
+ }
+
+ /* (2) Program full page via Buffer1 */
+ addr += to;
+ command[0] = OP_PROGRAM_VIA_BUF1;
+ command[1] = (addr & 0x00FF0000) >> 16;
+ command[2] = (addr & 0x0000FF00) >> 8;
+ command[3] = (addr & 0x000000FF);
+
+ debug("PROGRAM: (%x) %x %x %x\n",
+ command[0], command[1], command[2], command[3]);
+
+ status = spi_flash_cmd_write(spi, command,
+ 4, writebuf, writelen);
+ if (status < 0) {
+ debug("%s: write send command error!\n", dev->name);
+ return -EIO;
+ }
+
+ status = dataflash_waitready(spi);
+ if (status < 0) {
+ debug("%s: write waitready error!\n", dev->name);
+ return status;
+ }
+
+#ifdef CONFIG_SPI_DATAFLASH_WRITE_VERIFY
+ /* (3) Compare to Buffer1 */
+ addr = pageaddr << dataflash->page_offset;
+ command[0] = OP_COMPARE_BUF1;
+ command[1] = (addr & 0x00FF0000) >> 16;
+ command[2] = (addr & 0x0000FF00) >> 8;
+ command[3] = 0;
+
+ debug("COMPARE: (%x) %x %x %x\n",
+ command[0], command[1], command[2], command[3]);
+
+ status = spi_flash_cmd_write(spi, command,
+ 4, writebuf, writelen);
+ if (status < 0) {
+ debug("%s: write(compare) send command error!\n",
+ dev->name);
+ return -EIO;
+ }
+
+ status = dataflash_waitready(spi);
+
+ /* Check result of the compare operation */
+ if (status & (1 << 6)) {
+ printf("SPI DataFlash: write compare page %u, err %d\n",
+ pageaddr, status);
+ remaining = 0;
+ status = -EIO;
+ break;
+ } else {
+ status = 0;
+ }
+
+#endif /* CONFIG_SPI_DATAFLASH_WRITE_VERIFY */
+ remaining = remaining - writelen;
+ pageaddr++;
+ to = 0;
+ writebuf += writelen;
+
+ if (remaining > spi_flash->page_size)
+ writelen = spi_flash->page_size;
+ else
+ writelen = remaining;
+ }
+
+ spi_release_bus(spi);
+
+ return 0;
+}
+
+static int add_dataflash(struct udevice *dev, char *name, int nr_pages,
+ int pagesize, int pageoffset, char revision)
+{
+ struct spi_flash *spi_flash;
+ struct dataflash *dataflash;
+
+ dataflash = dev_get_priv(dev);
+ spi_flash = dev_get_uclass_priv(dev);
+
+ dataflash->page_offset = pageoffset;
+
+ spi_flash->name = name;
+ spi_flash->page_size = pagesize;
+ spi_flash->size = nr_pages * pagesize;
+ spi_flash->erase_size = pagesize;
+
+#ifndef CONFIG_SPL_BUILD
+ printf("SPI DataFlash: Detected %s with page size ", spi_flash->name);
+ print_size(spi_flash->page_size, ", erase size ");
+ print_size(spi_flash->erase_size, ", total ");
+ print_size(spi_flash->size, "");
+ printf(", revision %c", revision);
+ puts("\n");
+#endif
+
+ return 0;
+}
+
+struct flash_info {
+ char *name;
+
+ /*
+ * JEDEC id has a high byte of zero plus three data bytes:
+ * the manufacturer id, then a two byte device id.
+ */
+ uint32_t jedec_id;
+
+ /* The size listed here is what works with OP_ERASE_PAGE. */
+ unsigned nr_pages;
+ uint16_t pagesize;
+ uint16_t pageoffset;
+
+ uint16_t flags;
+#define SUP_POW2PS 0x0002 /* supports 2^N byte pages */
+#define IS_POW2PS 0x0001 /* uses 2^N byte pages */
+};
+
+static struct flash_info dataflash_data[] = {
+ /*
+ * NOTE: chips with SUP_POW2PS (rev D and up) need two entries,
+ * one with IS_POW2PS and the other without. The entry with the
+ * non-2^N byte page size can't name exact chip revisions without
+ * losing backwards compatibility for cmdlinepart.
+ *
+ * Those two entries have different name spelling format in order to
+ * show their difference obviously.
+ * The upper case refer to the chip isn't in normal 2^N bytes page-size
+ * mode.
+ * The lower case refer to the chip is in normal 2^N bytes page-size
+ * mode.
+ *
+ * These newer chips also support 128-byte security registers (with
+ * 64 bytes one-time-programmable) and software write-protection.
+ */
+ { "AT45DB011B", 0x1f2200, 512, 264, 9, SUP_POW2PS},
+ { "at45db011d", 0x1f2200, 512, 256, 8, SUP_POW2PS | IS_POW2PS},
+
+ { "AT45DB021B", 0x1f2300, 1024, 264, 9, SUP_POW2PS},
+ { "at45db021d", 0x1f2300, 1024, 256, 8, SUP_POW2PS | IS_POW2PS},
+
+ { "AT45DB041x", 0x1f2400, 2048, 264, 9, SUP_POW2PS},
+ { "at45db041d", 0x1f2400, 2048, 256, 8, SUP_POW2PS | IS_POW2PS},
+
+ { "AT45DB081B", 0x1f2500, 4096, 264, 9, SUP_POW2PS},
+ { "at45db081d", 0x1f2500, 4096, 256, 8, SUP_POW2PS | IS_POW2PS},
+
+ { "AT45DB161x", 0x1f2600, 4096, 528, 10, SUP_POW2PS},
+ { "at45db161d", 0x1f2600, 4096, 512, 9, SUP_POW2PS | IS_POW2PS},
+
+ { "AT45DB321x", 0x1f2700, 8192, 528, 10, 0}, /* rev C */
+
+ { "AT45DB321x", 0x1f2701, 8192, 528, 10, SUP_POW2PS},
+ { "at45db321d", 0x1f2701, 8192, 512, 9, SUP_POW2PS | IS_POW2PS},
+
+ { "AT45DB642x", 0x1f2800, 8192, 1056, 11, SUP_POW2PS},
+ { "at45db642d", 0x1f2800, 8192, 1024, 10, SUP_POW2PS | IS_POW2PS},
+};
+
+static struct flash_info *jedec_probe(struct spi_slave *spi, u8 *id)
+{
+ int tmp;
+ uint32_t jedec;
+ struct flash_info *info;
+ int status;
+
+ /*
+ * JEDEC also defines an optional "extended device information"
+ * string for after vendor-specific data, after the three bytes
+ * we use here. Supporting some chips might require using it.
+ *
+ * If the vendor ID isn't Atmel's (0x1f), assume this call failed.
+ * That's not an error; only rev C and newer chips handle it, and
+ * only Atmel sells these chips.
+ */
+ if (id[0] != 0x1f)
+ return NULL;
+
+ jedec = id[0];
+ jedec = jedec << 8;
+ jedec |= id[1];
+ jedec = jedec << 8;
+ jedec |= id[2];
+
+ for (tmp = 0, info = dataflash_data;
+ tmp < ARRAY_SIZE(dataflash_data);
+ tmp++, info++) {
+ if (info->jedec_id == jedec) {
+ if (info->flags & SUP_POW2PS) {
+ status = dataflash_status(spi);
+ if (status < 0) {
+ debug("SPI DataFlash: status error %d\n",
+ status);
+ return NULL;
+ }
+ if (status & 0x1) {
+ if (info->flags & IS_POW2PS)
+ return info;
+ } else {
+ if (!(info->flags & IS_POW2PS))
+ return info;
+ }
+ } else {
+ return info;
+ }
+ }
+ }
+
+ /*
+ * Treat other chips as errors ... we won't know the right page
+ * size (it might be binary) even when we can tell which density
+ * class is involved (legacy chip id scheme).
+ */
+ printf("SPI DataFlash: Unsupported flash IDs: ");
+ printf("manuf %02x, jedec %04x, ext_jedec %04x\n",
+ id[0], jedec, id[3] << 8 | id[4]);
+ return NULL;
+}
+
+/*
+ * Detect and initialize DataFlash device, using JEDEC IDs on newer chips
+ * or else the ID code embedded in the status bits:
+ *
+ * Device Density ID code #Pages PageSize Offset
+ * AT45DB011B 1Mbit (128K) xx0011xx (0x0c) 512 264 9
+ * AT45DB021B 2Mbit (256K) xx0101xx (0x14) 1024 264 9
+ * AT45DB041B 4Mbit (512K) xx0111xx (0x1c) 2048 264 9
+ * AT45DB081B 8Mbit (1M) xx1001xx (0x24) 4096 264 9
+ * AT45DB0161B 16Mbit (2M) xx1011xx (0x2c) 4096 528 10
+ * AT45DB0321B 32Mbit (4M) xx1101xx (0x34) 8192 528 10
+ * AT45DB0642 64Mbit (8M) xx111xxx (0x3c) 8192 1056 11
+ * AT45DB1282 128Mbit (16M) xx0100xx (0x10) 16384 1056 11
+ */
+static int spi_dataflash_probe(struct udevice *dev)
+{
+ struct spi_slave *spi = dev_get_parentdata(dev);
+ struct spi_flash *spi_flash;
+ struct flash_info *info;
+ u8 idcode[5];
+ int ret, status = 0;
+
+ spi_flash = dev_get_uclass_priv(dev);
+ spi_flash->dev = dev;
+
+ ret = spi_claim_bus(spi);
+ if (ret)
+ return ret;
+
+ ret = spi_flash_cmd(spi, CMD_READ_ID, idcode, sizeof(idcode));
+ if (ret) {
+ printf("SPI DataFlash: Failed to get idcodes\n");
+ goto err_read_cmd;
+ }
+
+ /*
+ * Try to detect dataflash by JEDEC ID.
+ * If it succeeds we know we have either a C or D part.
+ * D will support power of 2 pagesize option.
+ * Both support the security register, though with different
+ * write procedures.
+ */
+ info = jedec_probe(spi, idcode);
+ if (info != NULL)
+ add_dataflash(dev, info->name, info->nr_pages,
+ info->pagesize, info->pageoffset,
+ (info->flags & SUP_POW2PS) ? 'd' : 'c');
+ else {
+ /*
+ * Older chips support only legacy commands, identifing
+ * capacity using bits in the status byte.
+ */
+ status = dataflash_status(spi);
+ if (status <= 0 || status == 0xff) {
+ printf("SPI DataFlash: read status error %d\n", status);
+ if (status == 0 || status == 0xff)
+ status = -ENODEV;
+ goto err_read_cmd;
+ }
+ /*
+ * if there's a device there, assume it's dataflash.
+ * board setup should have set spi->max_speed_max to
+ * match f(car) for continuous reads, mode 0 or 3.
+ */
+ switch (status & 0x3c) {
+ case 0x0c: /* 0 0 1 1 x x */
+ status = add_dataflash(dev, "AT45DB011B",
+ 512, 264, 9, 0);
+ break;
+ case 0x14: /* 0 1 0 1 x x */
+ status = add_dataflash(dev, "AT45DB021B",
+ 1024, 264, 9, 0);
+ break;
+ case 0x1c: /* 0 1 1 1 x x */
+ status = add_dataflash(dev, "AT45DB041x",
+ 2048, 264, 9, 0);
+ break;
+ case 0x24: /* 1 0 0 1 x x */
+ status = add_dataflash(dev, "AT45DB081B",
+ 4096, 264, 9, 0);
+ break;
+ case 0x2c: /* 1 0 1 1 x x */
+ status = add_dataflash(dev, "AT45DB161x",
+ 4096, 528, 10, 0);
+ break;
+ case 0x34: /* 1 1 0 1 x x */
+ status = add_dataflash(dev, "AT45DB321x",
+ 8192, 528, 10, 0);
+ break;
+ case 0x38: /* 1 1 1 x x x */
+ case 0x3c:
+ status = add_dataflash(dev, "AT45DB642x",
+ 8192, 1056, 11, 0);
+ break;
+ /* obsolete AT45DB1282 not (yet?) supported */
+ default:
+ dev_info(&spi->dev, "unsupported device (%x)\n",
+ status & 0x3c);
+ status = -ENODEV;
+ goto err_read_cmd;
+ }
+ }
+
+ /* Assign spi data */
+ spi_flash->spi = spi;
+ spi_flash->memory_map = spi->memory_map;
+ spi_flash->dual_flash = spi->option;
+
+ spi_release_bus(spi);
+
+ return 0;
+
+err_read_cmd:
+ spi_release_bus(spi);
+
+ return status;
+}
+
+static const struct dm_spi_flash_ops spi_dataflash_ops = {
+ .read = spi_dataflash_read,
+ .write = spi_dataflash_write,
+ .erase = spi_dataflash_erase,
+};
+
+static const struct udevice_id spi_dataflash_ids[] = {
+ { .compatible = "atmel,at45", },
+ { .compatible = "atmel,dataflash", },
+ { }
+};
+
+U_BOOT_DRIVER(spi_dataflash) = {
+ .name = "spi_dataflash",
+ .id = UCLASS_SPI_FLASH,
+ .of_match = spi_dataflash_ids,
+ .probe = spi_dataflash_probe,
+ .priv_auto_alloc_size = sizeof(struct dataflash),
+ .ops = &spi_dataflash_ops,
+};
diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
index 4158e13322..9fb555707c 100644
--- a/drivers/mtd/spi/sf_internal.h
+++ b/drivers/mtd/spi/sf_internal.h
@@ -31,9 +31,9 @@ enum spi_read_cmds {
};
/* Normal - Extended - Full command set */
-#define RD_NORM (ARRAY_SLOW | ARRAY_FAST)
-#define RD_EXTN (RD_NORM | DUAL_OUTPUT_FAST | DUAL_IO_FAST)
-#define RD_FULL (RD_EXTN | QUAD_OUTPUT_FAST | QUAD_IO_FAST)
+#define RD_NORM (ARRAY_SLOW | ARRAY_FAST)
+#define RD_EXTN (RD_NORM | DUAL_OUTPUT_FAST | DUAL_IO_FAST)
+#define RD_FULL (RD_EXTN | QUAD_OUTPUT_FAST | QUAD_IO_FAST)
/* sf param flags */
enum {
@@ -67,12 +67,12 @@ enum {
#define CMD_WRITE_STATUS 0x01
#define CMD_PAGE_PROGRAM 0x02
#define CMD_WRITE_DISABLE 0x04
-#define CMD_READ_STATUS 0x05
+#define CMD_READ_STATUS 0x05
#define CMD_QUAD_PAGE_PROGRAM 0x32
#define CMD_READ_STATUS1 0x35
#define CMD_WRITE_ENABLE 0x06
-#define CMD_READ_CONFIG 0x35
-#define CMD_FLAG_STATUS 0x70
+#define CMD_READ_CONFIG 0x35
+#define CMD_FLAG_STATUS 0x70
/* Read commands */
#define CMD_READ_ARRAY_SLOW 0x03
@@ -99,13 +99,13 @@ enum {
/* Flash timeout values */
#define SPI_FLASH_PROG_TIMEOUT (2 * CONFIG_SYS_HZ)
-#define SPI_FLASH_PAGE_ERASE_TIMEOUT (5 * CONFIG_SYS_HZ)
+#define SPI_FLASH_PAGE_ERASE_TIMEOUT (5 * CONFIG_SYS_HZ)
#define SPI_FLASH_SECTOR_ERASE_TIMEOUT (10 * CONFIG_SYS_HZ)
/* SST specific */
#ifdef CONFIG_SPI_FLASH_SST
# define CMD_SST_BP 0x02 /* Byte Program */
-# define CMD_SST_AAI_WP 0xAD /* Auto Address Incr Word Program */
+# define CMD_SST_AAI_WP 0xAD /* Auto Address Incr Word Program */
int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len,
const void *buf);
@@ -121,7 +121,7 @@ int sst_write_bp(struct spi_flash *flash, u32 offset, size_t len,
* @ext_jedec: Device ext_jedec ID
* @sector_size: Isn't necessarily a sector size from vendor,
* the size listed here is what works with CMD_ERASE_64K
- * @nr_sectors: No.of sectors on this device
+ * @nr_sectors: No.of sectors on this device
* @e_rd_cmd: Enum list for read commands
* @flags: Important param, for flash specific behaviour
*/
@@ -218,4 +218,9 @@ int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd,
int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
size_t len, void *data);
+#ifdef CONFIG_SPI_FLASH_MTD
+int spi_flash_mtd_register(struct spi_flash *flash);
+void spi_flash_mtd_unregister(void);
+#endif
+
#endif /* _SF_INTERNAL_H_ */
diff --git a/drivers/mtd/spi/sf_mtd.c b/drivers/mtd/spi/sf_mtd.c
new file mode 100644
index 0000000000..0b9cb62261
--- /dev/null
+++ b/drivers/mtd/spi/sf_mtd.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2012-2014 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <asm/errno.h>
+#include <linux/mtd/mtd.h>
+#include <spi_flash.h>
+
+static struct mtd_info sf_mtd_info;
+static char sf_mtd_name[8];
+
+static int spi_flash_mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+ struct spi_flash *flash = mtd->priv;
+ int err;
+
+ instr->state = MTD_ERASING;
+
+ err = spi_flash_erase(flash, instr->addr, instr->len);
+ if (err) {
+ instr->state = MTD_ERASE_FAILED;
+ instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
+ return -EIO;
+ }
+
+ instr->state = MTD_ERASE_DONE;
+ mtd_erase_callback(instr);
+
+ return 0;
+}
+
+static int spi_flash_mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, u_char *buf)
+{
+ struct spi_flash *flash = mtd->priv;
+ int err;
+
+ err = spi_flash_read(flash, from, len, buf);
+ if (!err)
+ *retlen = len;
+
+ return err;
+}
+
+static int spi_flash_mtd_write(struct mtd_info *mtd, loff_t to, size_t len,
+ size_t *retlen, const u_char *buf)
+{
+ struct spi_flash *flash = mtd->priv;
+ int err;
+
+ err = spi_flash_write(flash, to, len, buf);
+ if (!err)
+ *retlen = len;
+
+ return err;
+}
+
+static void spi_flash_mtd_sync(struct mtd_info *mtd)
+{
+}
+
+static int spi_flash_mtd_number(void)
+{
+#ifdef CONFIG_SYS_MAX_FLASH_BANKS
+ return CONFIG_SYS_MAX_FLASH_BANKS;
+#else
+ return 0;
+#endif
+}
+
+int spi_flash_mtd_register(struct spi_flash *flash)
+{
+ memset(&sf_mtd_info, 0, sizeof(sf_mtd_info));
+ sprintf(sf_mtd_name, "nor%d", spi_flash_mtd_number());
+
+ sf_mtd_info.name = sf_mtd_name;
+ sf_mtd_info.type = MTD_NORFLASH;
+ sf_mtd_info.flags = MTD_CAP_NORFLASH;
+ sf_mtd_info.writesize = 1;
+ sf_mtd_info.writebufsize = flash->page_size;
+
+ sf_mtd_info._erase = spi_flash_mtd_erase;
+ sf_mtd_info._read = spi_flash_mtd_read;
+ sf_mtd_info._write = spi_flash_mtd_write;
+ sf_mtd_info._sync = spi_flash_mtd_sync;
+
+ sf_mtd_info.size = flash->size;
+ sf_mtd_info.priv = flash;
+
+ /* Only uniform flash devices for now */
+ sf_mtd_info.numeraseregions = 0;
+ sf_mtd_info.erasesize = flash->sector_size;
+
+ return add_mtd_device(&sf_mtd_info);
+}
+
+void spi_flash_mtd_unregister(void)
+{
+ del_mtd_device(&sf_mtd_info);
+}
diff --git a/drivers/mtd/spi/sf_params.c b/drivers/mtd/spi/sf_params.c
index c12e8c6fe7..4a4a3afc92 100644
--- a/drivers/mtd/spi/sf_params.c
+++ b/drivers/mtd/spi/sf_params.c
@@ -100,7 +100,7 @@ const struct spi_flash_params spi_flash_params_table[] = {
{"SST25WF010", 0xbf2502, 0x0, 64 * 1024, 2, RD_NORM, SECT_4K | SST_WR},
{"SST25WF020", 0xbf2503, 0x0, 64 * 1024, 4, RD_NORM, SECT_4K | SST_WR},
{"SST25WF040", 0xbf2504, 0x0, 64 * 1024, 8, RD_NORM, SECT_4K | SST_WR},
- {"SST25WF040B", 0x621613, 0x0, 64 * 1024, 8, RD_NORM, SECT_4K | SST_WR},
+ {"SST25WF040B", 0x621613, 0x0, 64 * 1024, 8, RD_NORM, SECT_4K},
{"SST25WF080", 0xbf2505, 0x0, 64 * 1024, 16, RD_NORM, SECT_4K | SST_WR},
#endif
#ifdef CONFIG_SPI_FLASH_WINBOND /* WINBOND */
diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c
index 201471c392..e0283dc82c 100644
--- a/drivers/mtd/spi/sf_probe.c
+++ b/drivers/mtd/spi/sf_probe.c
@@ -372,11 +372,9 @@ int spi_flash_probe_slave(struct spi_slave *spi, struct spi_flash *flash)
puts(" Full access #define CONFIG_SPI_FLASH_BAR\n");
}
#endif
-
- /* Release spi bus */
- spi_release_bus(spi);
-
- return 0;
+#ifdef CONFIG_SPI_FLASH_MTD
+ ret = spi_flash_mtd_register(flash);
+#endif
err_read_id:
spi_release_bus(spi);
@@ -430,6 +428,9 @@ struct spi_flash *spi_flash_probe_fdt(const void *blob, int slave_node,
void spi_flash_free(struct spi_flash *flash)
{
+#ifdef CONFIG_SPI_FLASH_MTD
+ spi_flash_mtd_unregister();
+#endif
spi_free_slave(flash->spi);
free(flash);
}
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 973258a80c..ce76a02da0 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -11,6 +11,7 @@ config DM_ETH
menuconfig NETDEVICES
bool "Network device support"
depends on NET
+ default y if DM_ETH
help
You must select Y to enable any network device support
Generally if you have any networking support this is a given
diff --git a/drivers/net/designware.c b/drivers/net/designware.c
index ae51cf3781..645ca6427c 100644
--- a/drivers/net/designware.c
+++ b/drivers/net/designware.c
@@ -243,6 +243,12 @@ static int _dw_eth_init(struct dw_eth_dev *priv, u8 *enetaddr)
mdelay(100);
};
+ /*
+ * Soft reset above clears HW address registers.
+ * So we have to set it here once again.
+ */
+ _dw_write_hwaddr(priv, enetaddr);
+
rx_descs_init(priv);
tx_descs_init(priv);
diff --git a/drivers/serial/arm_dcc.c b/drivers/serial/arm_dcc.c
index e77773740f..df7eb05e82 100644
--- a/drivers/serial/arm_dcc.c
+++ b/drivers/serial/arm_dcc.c
@@ -61,6 +61,22 @@
#define status_dcc(x) \
__asm__ volatile ("mrc p14, 0, %0, c14, c0, 0\n" : "=r" (x))
+#elif defined(CONFIG_CPU_ARMV8)
+/*
+ * ARMV8
+ */
+#define DCC_RBIT (1 << 30)
+#define DCC_WBIT (1 << 29)
+
+#define write_dcc(x) \
+ __asm__ volatile ("msr dbgdtrtx_el0, %0\n" : : "r" (x))
+
+#define read_dcc(x) \
+ __asm__ volatile ("mrs %0, dbgdtrrx_el0\n" : "=r" (x))
+
+#define status_dcc(x) \
+ __asm__ volatile ("mrs %0, mdccsr_el0\n" : "=r" (x))
+
#else
#define DCC_RBIT (1 << 0)
#define DCC_WBIT (1 << 1)
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 357a33511f..c84a7b74d6 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -1,3 +1,5 @@
+menu "SPI Support"
+
config DM_SPI
bool "Enable Driver Model for SPI drivers"
depends on DM
@@ -11,6 +13,51 @@ config DM_SPI
typically use driver-private data instead of extending the
spi_slave structure.
+if DM_SPI
+
+config CADENCE_QSPI
+ bool "Cadence QSPI driver"
+ help
+ Enable the Cadence Quad-SPI (QSPI) driver. This driver can be
+ used to access the SPI NOR flash on platforms embedding this
+ Cadence IP core.
+
+config DESIGNWARE_SPI
+ bool "Designware SPI driver"
+ help
+ Enable the Designware SPI driver. This driver can be used to
+ access the SPI NOR flash on platforms embedding this Designware
+ IP core.
+
+config EXYNOS_SPI
+ bool "Samsung Exynos SPI driver"
+ help
+ Enable the Samsung Exynos SPI driver. This driver can be used to
+ access the SPI NOR flash on platforms embedding this Samsung
+ Exynos IP core.
+
+config FSL_DSPI
+ bool "Freescale DSPI driver"
+ help
+ Enable the Freescale DSPI driver. This driver can be used to
+ access the SPI NOR flash and SPI Data flash on platforms embedding
+ this Freescale DSPI IP core. LS102xA and Colibri VF50/VF61 platforms
+ use this driver.
+
+config FSL_QSPI
+ bool "Freescale QSPI driver"
+ help
+ Enable the Freescale Quad-SPI (QSPI) driver. This driver can be
+ used to access the SPI NOR flash on platforms embedding this
+ Freescale IP core.
+
+config ICH_SPI
+ bool "Intel ICH SPI driver"
+ help
+ Enable the Intel ICH SPI driver. This driver can be used to
+ access the SPI NOR flash on platforms embedding this Intel
+ ICH IP core.
+
config SANDBOX_SPI
bool "Sandbox SPI driver"
depends on SANDBOX && DM
@@ -34,20 +81,61 @@ config SANDBOX_SPI
spi-max-frequency = <40000000>;
sandbox,filename = "spi.bin";
};
- };
+ };
-config DESIGNWARE_SPI
- bool "Designware SPI driver"
- depends on DM_SPI
+config TEGRA114_SPI
+ bool "nVidia Tegra114 SPI driver"
help
- Enable the Designware SPI driver. This driver can be used to
- access the SPI NOR flash on platforms embedding this Designware
+ Enable the nVidia Tegra114 SPI driver. This driver can be used to
+ access the SPI NOR flash on platforms embedding this nVidia Tegra114
IP core.
-config CADENCE_QSPI
- bool "Cadence QSPI driver"
- depends on DM_SPI
+ This controller is different than the older SoCs SPI controller and
+ also register interface get changed with this controller.
+
+config TEGRA20_SFLASH
+ bool "nVidia Tegra20 Serial Flash controller driver"
help
- Enable the Cadence Quad-SPI (QSPI) driver. This driver can be
- used to access the SPI NOR flash on platforms embedding this
- Cadence IP core.
+ Enable the nVidia Tegra20 Serial Flash controller driver. This driver
+ can be used to access the SPI NOR flash on platforms embedding this
+ nVidia Tegra20 IP core.
+
+config TEGRA20_SLINK
+ bool "nVidia Tegra20/Tegra30 SLINK driver"
+ help
+ Enable the nVidia Tegra20/Tegra30 SLINK driver. This driver can
+ be used to access the SPI NOR flash on platforms embedding this
+ nVidia Tegra20/Tegra30 IP cores.
+
+config XILINX_SPI
+ bool "Xilinx SPI driver"
+ help
+ Enable the Xilinx SPI driver from the Xilinx EDK. This SPI
+ controller support 8 bit SPI transfers only, with or w/o FIFO.
+ For more info on Xilinx SPI Register Definitions and Overview
+ see driver file - drivers/spi/xilinx_spi.c
+
+config ZYNQ_SPI
+ bool "Zynq SPI driver"
+ depends on ARCH_ZYNQ || TARGET_XILINX_ZYNQMP
+ help
+ Enable the Zynq SPI driver. This driver can be used to
+ access the SPI NOR flash on platforms embedding this Zynq
+ SPI IP core.
+
+endif # if DM_SPI
+
+config FSL_ESPI
+ bool "Freescale eSPI driver"
+ help
+ Enable the Freescale eSPI driver. This driver can be used to
+ access the SPI interface and SPI NOR flash on platforms embedding
+ this Freescale eSPI IP core.
+
+config TI_QSPI
+ bool "TI QSPI driver"
+ help
+ Enable the TI Quad-SPI (QSPI) driver for DRA7xx and AM43xx evms.
+ This driver support spi flash single, quad and memory reads.
+
+endmenu # menu "SPI Support"
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index e288692f26..ee88aa162b 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -15,9 +15,7 @@ obj-y += spi.o
obj-$(CONFIG_SOFT_SPI) += soft_spi_legacy.o
endif
-obj-$(CONFIG_EP93XX_SPI) += ep93xx_spi.o
obj-$(CONFIG_ALTERA_SPI) += altera_spi.o
-obj-$(CONFIG_ANDES_SPI) += andes_spi.o
obj-$(CONFIG_ARMADA100_SPI) += armada100_spi.o
obj-$(CONFIG_ATMEL_DATAFLASH_SPI) += atmel_dataflash_spi.o
obj-$(CONFIG_ATMEL_SPI) += atmel_spi.o
@@ -28,8 +26,11 @@ obj-$(CONFIG_CF_SPI) += cf_spi.o
obj-$(CONFIG_CF_QSPI) += cf_qspi.o
obj-$(CONFIG_DAVINCI_SPI) += davinci_spi.o
obj-$(CONFIG_DESIGNWARE_SPI) += designware_spi.o
+obj-$(CONFIG_EP93XX_SPI) += ep93xx_spi.o
obj-$(CONFIG_EXYNOS_SPI) += exynos_spi.o
-obj-$(CONFIG_FTSSP010_SPI) += ftssp010_spi.o
+obj-$(CONFIG_FSL_DSPI) += fsl_dspi.o
+obj-$(CONFIG_FSL_ESPI) += fsl_espi.o
+obj-$(CONFIG_FSL_QSPI) += fsl_qspi.o
obj-$(CONFIG_ICH_SPI) += ich.o
obj-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o
obj-$(CONFIG_LPC32XX_SSP) += lpc32xx_ssp.o
@@ -37,17 +38,13 @@ obj-$(CONFIG_MPC52XX_SPI) += mpc52xx_spi.o
obj-$(CONFIG_MPC8XXX_SPI) += mpc8xxx_spi.o
obj-$(CONFIG_MXC_SPI) += mxc_spi.o
obj-$(CONFIG_MXS_SPI) += mxs_spi.o
-obj-$(CONFIG_OC_TINY_SPI) += oc_tiny_spi.o
obj-$(CONFIG_OMAP3_SPI) += omap3_spi.o
obj-$(CONFIG_SANDBOX_SPI) += sandbox_spi.o
obj-$(CONFIG_SH_SPI) += sh_spi.o
obj-$(CONFIG_SH_QSPI) += sh_qspi.o
-obj-$(CONFIG_FSL_ESPI) += fsl_espi.o
+obj-$(CONFIG_TEGRA114_SPI) += tegra114_spi.o
obj-$(CONFIG_TEGRA20_SFLASH) += tegra20_sflash.o
obj-$(CONFIG_TEGRA20_SLINK) += tegra20_slink.o
-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
-obj-$(CONFIG_FSL_DSPI) += fsl_dspi.o
diff --git a/drivers/spi/andes_spi.c b/drivers/spi/andes_spi.c
deleted file mode 100644
index 82aed75ca1..0000000000
--- a/drivers/spi/andes_spi.c
+++ /dev/null
@@ -1,284 +0,0 @@
-/*
- * Driver of Andes SPI Controller
- *
- * (C) Copyright 2011 Andes Technology
- * Macpaul Lin <macpaul@andestech.com>
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
-
-#include <common.h>
-#include <malloc.h>
-#include <spi.h>
-
-#include <asm/io.h>
-#include "andes_spi.h"
-
-void spi_init(void)
-{
- /* do nothing */
-}
-
-static void andes_spi_spit_en(struct andes_spi_slave *ds)
-{
- unsigned int dcr = readl(&ds->regs->dcr);
-
- debug("%s: dcr: %x, write value: %x\n",
- __func__, dcr, (dcr | ANDES_SPI_DCR_SPIT));
-
- writel((dcr | ANDES_SPI_DCR_SPIT), &ds->regs->dcr);
-}
-
-struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
- unsigned int max_hz, unsigned int mode)
-{
- struct andes_spi_slave *ds;
-
- if (!spi_cs_is_valid(bus, cs))
- return NULL;
-
- ds = spi_alloc_slave(struct andes_spi_slave, bus, cs);
- if (!ds)
- return NULL;
-
- ds->regs = (struct andes_spi_regs *)CONFIG_SYS_SPI_BASE;
-
- /*
- * The hardware of andes_spi will set its frequency according
- * to APB/AHB bus clock. Hence the hardware doesn't allow changing of
- * requency and so the user requested speed is always ignored.
- */
- ds->freq = max_hz;
-
- return &ds->slave;
-}
-
-void spi_free_slave(struct spi_slave *slave)
-{
- struct andes_spi_slave *ds = to_andes_spi(slave);
-
- free(ds);
-}
-
-int spi_claim_bus(struct spi_slave *slave)
-{
- struct andes_spi_slave *ds = to_andes_spi(slave);
- unsigned int apb;
- unsigned int baud;
-
- /* Enable the SPI hardware */
- writel(ANDES_SPI_CR_SPIRST, &ds->regs->cr);
- udelay(1000);
-
- /* setup format */
- baud = ((CONFIG_SYS_CLK_FREQ / CONFIG_SYS_SPI_CLK / 2) - 1) & 0xFF;
-
- /*
- * SPI_CLK = AHB bus clock / ((BAUD + 1)*2)
- * BAUD = AHB bus clock / SPI_CLK / 2) - 1
- */
- apb = (readl(&ds->regs->apb) & 0xffffff00) | baud;
- writel(apb, &ds->regs->apb);
-
- /* no interrupts */
- writel(0, &ds->regs->ie);
-
- return 0;
-}
-
-void spi_release_bus(struct spi_slave *slave)
-{
- struct andes_spi_slave *ds = to_andes_spi(slave);
-
- /* Disable the SPI hardware */
- writel(ANDES_SPI_CR_SPIRST, &ds->regs->cr);
-}
-
-static int andes_spi_read(struct spi_slave *slave, unsigned int len,
- u8 *rxp, unsigned long flags)
-{
- struct andes_spi_slave *ds = to_andes_spi(slave);
- unsigned int i, left;
- unsigned int data;
-
- debug("%s: slave: %x, len: %d, rxp: %x, flags: %d\n",
- __func__, slave, len, rxp, flags);
-
- debug("%s: data: ", __func__);
- while (len > 0) {
- left = min(len, 4);
- data = readl(&ds->regs->data);
-
- debug(" ");
- for (i = 0; i < left; i++) {
- debug("%02x ", data & 0xff);
- *rxp++ = data;
- data >>= 8;
- len--;
- }
- }
- debug("\n");
-
- return 0;
-}
-
-static int andes_spi_write(struct spi_slave *slave, unsigned int wlen,
- unsigned int rlen, const u8 *txp, unsigned long flags)
-{
- struct andes_spi_slave *ds = to_andes_spi(slave);
- unsigned int data;
- unsigned int i, left;
- unsigned int spit_enabled = 0;
-
- debug("%s: slave: %x, wlen: %d, rlen: %d, txp: %x, flags: %x\n",
- __func__, slave, wlen, rlen, txp, flags);
-
- /* The value of wlen and rlen wrote to register must minus 1 */
- if (rlen == 0) /* write only */
- writel(ANDES_SPI_DCR_MODE_WO | ANDES_SPI_DCR_WCNT(wlen-1) |
- ANDES_SPI_DCR_RCNT(0), &ds->regs->dcr);
- else /* write then read */
- writel(ANDES_SPI_DCR_MODE_WR | ANDES_SPI_DCR_WCNT(wlen-1) |
- ANDES_SPI_DCR_RCNT(rlen-1), &ds->regs->dcr);
-
- /* wait till SPIBSY is cleared */
- while (readl(&ds->regs->st) & ANDES_SPI_ST_SPIBSY)
- ;
-
- /* data write process */
- debug("%s: txp: ", __func__);
- while (wlen > 0) {
- /* clear the data */
- data = 0;
-
- /* data are usually be read 32bits once a time */
- left = min(wlen, 4);
-
- for (i = 0; i < left; i++) {
- debug("%x ", *txp);
- data |= *txp++ << (i * 8);
- wlen--;
- }
- debug("\n");
-
- debug("data: %08x\n", data);
- debug("streg before write: %08x\n", readl(&ds->regs->st));
- /* wait till TXFULL is deasserted */
- while (readl(&ds->regs->st) & ANDES_SPI_ST_TXFEL)
- ;
- writel(data, &ds->regs->data);
- debug("streg after write: %08x\n", readl(&ds->regs->st));
-
-
- if (spit_enabled == 0) {
- /* enable SPIT bit - trigger the tx and rx progress */
- andes_spi_spit_en(ds);
- spit_enabled = 1;
- }
-
- }
- debug("\n");
-
- return 0;
-}
-
-/*
- * spi_xfer:
- * Since andes_spi doesn't support independent command transaction,
- * that is, write and than read must be operated in continuous
- * execution, there is no need to set dcr and trigger spit again in
- * RX process.
- */
-int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
- const void *dout, void *din, unsigned long flags)
-{
- unsigned int len;
- static int op_nextime;
- static u8 tmp_cmd[5];
- static int tmp_wlen;
- unsigned int i;
-
- if (bitlen == 0)
- /* Finish any previously submitted transfers */
- goto out;
-
- if (bitlen % 8) {
- /* Errors always terminate an ongoing transfer */
- flags |= SPI_XFER_END;
- goto out;
- }
-
- len = bitlen / 8;
-
- debug("%s: slave: %08x, bitlen: %d, dout: "
- "%08x, din: %08x, flags: %d, len: %d\n",
- __func__, slave, bitlen, dout, din, flags, len);
-
- /*
- * Important:
- * andes_spi's hardware doesn't support 2 data channel. The read
- * and write cmd/data share the same register (data register).
- *
- * If a command has write and read transaction, you cannot do write
- * this time and then do read on next time.
- *
- * A command writes first with a read response must indicating
- * the read length in write operation. Hence the write action must
- * be stored temporary and wait until the next read action has been
- * arrived. Then we flush the write and read action out together.
- */
- if (!dout) {
- if (op_nextime == 1) {
- /* flags should be SPI_XFER_END, value is 2 */
- op_nextime = 0;
- andes_spi_write(slave, tmp_wlen, len, tmp_cmd, flags);
- }
- return andes_spi_read(slave, len, din, flags);
- } else if (!din) {
- if (flags == SPI_XFER_BEGIN) {
- /* store the write command and do operation next time */
- op_nextime = 1;
- memset(tmp_cmd, 0, sizeof(tmp_cmd));
- memcpy(tmp_cmd, dout, len);
-
- debug("%s: tmp_cmd: ", __func__);
- for (i = 0; i < len; i++)
- debug("%x ", *(tmp_cmd + i));
- debug("\n");
-
- tmp_wlen = len;
- } else {
- /*
- * flags should be (SPI_XFER_BEGIN | SPI_XFER_END),
- * the value is 3.
- */
- if (op_nextime == 1) {
- /* flags should be SPI_XFER_END, value is 2 */
- op_nextime = 0;
- /* flags 3 implies write only */
- andes_spi_write(slave, tmp_wlen, 0, tmp_cmd, 3);
- }
-
- debug("flags: %x\n", flags);
- return andes_spi_write(slave, len, 0, dout, flags);
- }
- }
-
-out:
- return 0;
-}
-
-int spi_cs_is_valid(unsigned int bus, unsigned int cs)
-{
- return bus == 0 && cs == 0;
-}
-
-void spi_cs_activate(struct spi_slave *slave)
-{
- /* do nothing */
-}
-
-void spi_cs_deactivate(struct spi_slave *slave)
-{
- /* do nothing */
-}
diff --git a/drivers/spi/andes_spi.h b/drivers/spi/andes_spi.h
deleted file mode 100644
index b7d294599a..0000000000
--- a/drivers/spi/andes_spi.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Register definitions for the Andes SPI Controller
- *
- * (C) Copyright 2011 Andes Technology
- * Macpaul Lin <macpaul@andestech.com>
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
-
-#ifndef __ANDES_SPI_H
-#define __ANDES_SPI_H
-
-struct andes_spi_regs {
- unsigned int apb; /* 0x00 - APB SPI interface setting */
- unsigned int pio; /* 0x04 - PIO reg */
- unsigned int cr; /* 0x08 - SPI Control reg */
- unsigned int st; /* 0x0c - SPI Status reg */
- unsigned int ie; /* 0x10 - Interrupt Enable reg */
- unsigned int ist; /* 0x14 - Interrupt Status reg */
- unsigned int dcr; /* 0x18 - data control reg */
- unsigned int data; /* 0x1c - data register */
- unsigned int ahb; /* 0x20 - AHB SPI interface setting */
- unsigned int ver; /* 0x3c - SPI version reg */
-};
-
-#define BIT(x) (1 << (x))
-
-/* 0x00 - APB SPI interface setting register */
-#define ANDES_SPI_APB_BAUD(x) (((x) & 0xff) < 0)
-#define ANDES_SPI_APB_CSHT(x) (((x) & 0xf) < 16)
-#define ANDES_SPI_APB_SPNTS BIT(20) /* 0: normal, 1: delay */
-#define ANDES_SPI_APB_CPHA BIT(24) /* 0: Sampling at odd edges */
-#define ANDES_SPI_APB_CPOL BIT(25) /* 0: SCK low, 1: SCK high */
-#define ANDES_SPI_APB_MSSL BIT(26) /* 0: SPI Master, 1: slave */
-
-/* 0x04 - PIO register */
-#define ANDES_SPI_PIO_MISO BIT(0) /* input value of pin MISO */
-#define ANDES_SPI_PIO_MOSI BIT(1) /* I/O value of pin MOSI */
-#define ANDES_SPI_PIO_SCK BIT(2) /* I/O value of pin SCK */
-#define ANDES_SPI_PIO_CS BIT(3) /* I/O value of pin CS */
-#define ANDES_SPI_PIO_PIOE BIT(4) /* Programming IO Enable */
-
-/* 0x08 - SPI Control register */
-#define ANDES_SPI_CR_SPIRST BIT(0) /* SPI mode reset */
-#define ANDES_SPI_CR_RXFRST BIT(1) /* RxFIFO reset */
-#define ANDES_SPI_CR_TXFRST BIT(2) /* TxFIFO reset */
-#define ANDES_SPI_CR_RXFTH(x) (((x) & 0x1f) << 10) /* RxFIFO Threshold */
-#define ANDES_SPI_CR_TXFTH(x) (((x) & 0x1f) << 18) /* TxFIFO Threshold */
-
-/* 0x0c - SPI Status register */
-#define ANDES_SPI_ST_SPIBSY BIT(0) /* SPI Transfer is active */
-#define ANDES_SPI_ST_RXFEM BIT(8) /* RxFIFO Empty Flag */
-#define ANDES_SPI_ST_RXFEL BIT(9) /* RxFIFO Full Flag */
-#define ANDES_SPI_ST_RXFVE(x) (((x) >> 10) & 0x1f)
-#define ANDES_SPI_ST_TXFEM BIT(16) /* TxFIFO Empty Flag */
-#define ANDES_SPI_ST_TXFEL BIT(7) /* TxFIFO Full Flag */
-#define ANDES_SPI_ST_TXFVE(x) (((x) >> 18) & 0x1f)
-
-/* 0x10 - Interrupt Enable register */
-#define ANDES_SPI_IE_RXFORIE BIT(0) /* RxFIFO overrun intr */
-#define ANDES_SPI_IE_TXFURIE BIT(1) /* TxFOFO underrun intr */
-#define ANDES_SPI_IE_RXFTHIE BIT(2) /* RxFIFO threshold intr */
-#define ANDES_SPI_IE_TXFTHIE BIT(3) /* TxFIFO threshold intr */
-#define ANDES_SPI_IE_SPIEIE BIT(4) /* SPI transmit END intr */
-#define ANDES_SPI_IE_SPCFIE BIT(5) /* AHB/APB TxReq conflict */
-
-/* 0x14 - Interrupt Status Register */
-#define ANDES_SPI_IST_RXFORI BIT(0) /* has RxFIFO overrun */
-#define ANDES_SPI_IST_TXFURI BIT(1) /* has TxFOFO underrun */
-#define ANDES_SPI_IST_RXFTHI BIT(2) /* has RxFIFO threshold */
-#define ANDES_SPI_IST_TXFTHI BIT(3) /* has TxFIFO threshold */
-#define ANDES_SPI_IST_SPIEI BIT(4) /* has SPI transmit END */
-#define ANDES_SPI_IST_SPCFI BIT(5) /* has AHB/APB TxReq conflict */
-
-/* 0x18 - Data Control Register */
-#define ANDES_SPI_DCR_RCNT(x) (((x) & 0x3ff) << 0)
-#define ANDES_SPI_DCR_DYCNT(x) (((x) & 0x7) << 12)
-#define ANDES_SPI_DCR_WCNT(x) (((x) & 0x3ff) << 16)
-#define ANDES_SPI_DCR_TRAMODE(x) (((x) & 0x7) << 28)
-#define ANDES_SPI_DCR_SPIT BIT(31) /* SPI bus trigger */
-
-#define ANDES_SPI_DCR_MODE_WRCON ANDES_SPI_DCR_TRAMODE(0) /* w/r at the same time */
-#define ANDES_SPI_DCR_MODE_WO ANDES_SPI_DCR_TRAMODE(1) /* write only */
-#define ANDES_SPI_DCR_MODE_RO ANDES_SPI_DCR_TRAMODE(2) /* read only */
-#define ANDES_SPI_DCR_MODE_WR ANDES_SPI_DCR_TRAMODE(3) /* write, read */
-#define ANDES_SPI_DCR_MODE_RW ANDES_SPI_DCR_TRAMODE(4) /* read, write */
-#define ANDES_SPI_DCR_MODE_WDR ANDES_SPI_DCR_TRAMODE(5) /* write, dummy, read */
-#define ANDES_SPI_DCR_MODE_RDW ANDES_SPI_DCR_TRAMODE(6) /* read, dummy, write */
-#define ANDES_SPI_DCR_MODE_RECEIVE ANDES_SPI_DCR_TRAMODE(7) /* receive */
-
-/* 0x20 - AHB SPI interface setting register */
-#define ANDES_SPI_AHB_BAUD(x) (((x) & 0xff) < 0)
-#define ANDES_SPI_AHB_CSHT(x) (((x) & 0xf) < 16)
-#define ANDES_SPI_AHB_SPNTS BIT(20) /* 0: normal, 1: delay */
-#define ANDES_SPI_AHB_CPHA BIT(24) /* 0: Sampling at odd edges */
-#define ANDES_SPI_AHB_CPOL BIT(25) /* 0: SCK low, 1: SCK high */
-#define ANDES_SPI_AHB_MSSL BIT(26) /* only Master mode */
-
-/* 0x3c - Version Register - (Year V.MAJOR.MINOR) */
-#define ANDES_SPI_VER_MINOR(x) (((x) >> 0) & 0xf)
-#define ANDES_SPI_VER_MAJOR(x) (((x) >> 8) & 0xf)
-#define ANDES_SPI_VER_YEAR(x) (((x) >> 16) & 0xf)
-
-struct andes_spi_slave {
- struct spi_slave slave;
- struct andes_spi_regs *regs;
- unsigned int freq;
-};
-
-static inline struct andes_spi_slave *to_andes_spi(struct spi_slave *slave)
-{
- return container_of(slave, struct andes_spi_slave, slave);
-}
-
-#endif /* __ANDES_SPI_H */
diff --git a/drivers/spi/cf_qspi.c b/drivers/spi/cf_qspi.c
index 834c5bd259..e57e63eb47 100644
--- a/drivers/spi/cf_qspi.c
+++ b/drivers/spi/cf_qspi.c
@@ -19,7 +19,6 @@
DECLARE_GLOBAL_DATA_PTR;
-#define clamp(x, low, high) (min(max(low, x), high))
#define to_cf_qspi_slave(s) container_of(s, struct cf_qspi_slave, slave)
struct cf_qspi_slave {
@@ -120,7 +119,7 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
dev->qmr = 2u;
else /* Get the closest baud rate */
dev->qmr = clamp(((gd->bus_clk >> 2) + max_hz - 1)/max_hz,
- 2u, 255u);
+ 2lu, 255lu);
/* Map mode to QMR[CPOL] and QMR[CPHA] */
if (mode & SPI_CPOL)
diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c
index bf18362baa..0a036ccb00 100644
--- a/drivers/spi/davinci_spi.c
+++ b/drivers/spi/davinci_spi.c
@@ -8,116 +8,122 @@
*
* SPDX-License-Identifier: GPL-2.0+
*/
+
#include <common.h>
#include <spi.h>
#include <malloc.h>
#include <asm/io.h>
#include <asm/arch/hardware.h>
-#include "davinci_spi.h"
-void spi_init()
-{
- /* do nothing */
-}
+#define BIT(x) (1 << (x))
-struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
- unsigned int max_hz, unsigned int mode)
-{
- struct davinci_spi_slave *ds;
+/* SPIGCR0 */
+#define SPIGCR0_SPIENA_MASK 0x1
+#define SPIGCR0_SPIRST_MASK 0x0
- if (!spi_cs_is_valid(bus, cs))
- return NULL;
+/* SPIGCR0 */
+#define SPIGCR1_CLKMOD_MASK BIT(1)
+#define SPIGCR1_MASTER_MASK BIT(0)
+#define SPIGCR1_SPIENA_MASK BIT(24)
- ds = spi_alloc_slave(struct davinci_spi_slave, bus, cs);
- if (!ds)
- return NULL;
+/* SPIPC0 */
+#define SPIPC0_DIFUN_MASK BIT(11) /* SIMO */
+#define SPIPC0_DOFUN_MASK BIT(10) /* SOMI */
+#define SPIPC0_CLKFUN_MASK BIT(9) /* CLK */
+#define SPIPC0_EN0FUN_MASK BIT(0)
- switch (bus) {
- case SPI0_BUS:
- ds->regs = (struct davinci_spi_regs *)SPI0_BASE;
- break;
-#ifdef CONFIG_SYS_SPI1
- case SPI1_BUS:
- ds->regs = (struct davinci_spi_regs *)SPI1_BASE;
- break;
-#endif
-#ifdef CONFIG_SYS_SPI2
- case SPI2_BUS:
- ds->regs = (struct davinci_spi_regs *)SPI2_BASE;
- break;
-#endif
- default: /* Invalid bus number */
- return NULL;
- }
+/* SPIFMT0 */
+#define SPIFMT_SHIFTDIR_SHIFT 20
+#define SPIFMT_POLARITY_SHIFT 17
+#define SPIFMT_PHASE_SHIFT 16
+#define SPIFMT_PRESCALE_SHIFT 8
- ds->freq = max_hz;
+/* SPIDAT1 */
+#define SPIDAT1_CSHOLD_SHIFT 28
+#define SPIDAT1_CSNR_SHIFT 16
- return &ds->slave;
-}
+/* SPIDELAY */
+#define SPI_C2TDELAY_SHIFT 24
+#define SPI_T2CDELAY_SHIFT 16
-void spi_free_slave(struct spi_slave *slave)
-{
- struct davinci_spi_slave *ds = to_davinci_spi(slave);
+/* SPIBUF */
+#define SPIBUF_RXEMPTY_MASK BIT(31)
+#define SPIBUF_TXFULL_MASK BIT(29)
- free(ds);
-}
-
-int spi_claim_bus(struct spi_slave *slave)
-{
- struct davinci_spi_slave *ds = to_davinci_spi(slave);
- unsigned int scalar;
-
- /* Enable the SPI hardware */
- writel(SPIGCR0_SPIRST_MASK, &ds->regs->gcr0);
- udelay(1000);
- writel(SPIGCR0_SPIENA_MASK, &ds->regs->gcr0);
+/* SPIDEF */
+#define SPIDEF_CSDEF0_MASK BIT(0)
- /* Set master mode, powered up and not activated */
- writel(SPIGCR1_MASTER_MASK | SPIGCR1_CLKMOD_MASK, &ds->regs->gcr1);
-
- /* CS, CLK, SIMO and SOMI are functional pins */
- writel(((1 << slave->cs) | SPIPC0_CLKFUN_MASK |
- SPIPC0_DOFUN_MASK | SPIPC0_DIFUN_MASK), &ds->regs->pc0);
-
- /* setup format */
- scalar = ((CONFIG_SYS_SPI_CLK / ds->freq) - 1) & 0xFF;
-
- /*
- * Use following format:
- * character length = 8,
- * clock signal delayed by half clk cycle,
- * clock low in idle state - Mode 0,
- * MSB shifted out first
- */
- writel(8 | (scalar << SPIFMT_PRESCALE_SHIFT) |
- (1 << SPIFMT_PHASE_SHIFT), &ds->regs->fmt0);
-
- /*
- * Including a minor delay. No science here. Should be good even with
- * no delay
- */
- writel((50 << SPI_C2TDELAY_SHIFT) |
- (50 << SPI_T2CDELAY_SHIFT), &ds->regs->delay);
-
- /* default chip select register */
- writel(SPIDEF_CSDEF0_MASK, &ds->regs->def);
-
- /* no interrupts */
- writel(0, &ds->regs->int0);
- writel(0, &ds->regs->lvl);
+#define SPI0_BUS 0
+#define SPI0_BASE CONFIG_SYS_SPI_BASE
+/*
+ * Define default SPI0_NUM_CS as 1 for existing platforms that uses this
+ * driver. Platform can configure number of CS using CONFIG_SYS_SPI0_NUM_CS
+ * if more than one CS is supported and by defining CONFIG_SYS_SPI0.
+ */
+#ifndef CONFIG_SYS_SPI0
+#define SPI0_NUM_CS 1
+#else
+#define SPI0_NUM_CS CONFIG_SYS_SPI0_NUM_CS
+#endif
- /* enable SPI */
- writel((readl(&ds->regs->gcr1) | SPIGCR1_SPIENA_MASK), &ds->regs->gcr1);
+/*
+ * define CONFIG_SYS_SPI1 when platform has spi-1 device (bus #1) and
+ * CONFIG_SYS_SPI1_NUM_CS defines number of CS on this bus
+ */
+#ifdef CONFIG_SYS_SPI1
+#define SPI1_BUS 1
+#define SPI1_NUM_CS CONFIG_SYS_SPI1_NUM_CS
+#define SPI1_BASE CONFIG_SYS_SPI1_BASE
+#endif
- return 0;
-}
+/*
+ * define CONFIG_SYS_SPI2 when platform has spi-2 device (bus #2) and
+ * CONFIG_SYS_SPI2_NUM_CS defines number of CS on this bus
+ */
+#ifdef CONFIG_SYS_SPI2
+#define SPI2_BUS 2
+#define SPI2_NUM_CS CONFIG_SYS_SPI2_NUM_CS
+#define SPI2_BASE CONFIG_SYS_SPI2_BASE
+#endif
-void spi_release_bus(struct spi_slave *slave)
+/* davinci spi register set */
+struct davinci_spi_regs {
+ dv_reg gcr0; /* 0x00 */
+ dv_reg gcr1; /* 0x04 */
+ dv_reg int0; /* 0x08 */
+ dv_reg lvl; /* 0x0c */
+ dv_reg flg; /* 0x10 */
+ dv_reg pc0; /* 0x14 */
+ dv_reg pc1; /* 0x18 */
+ dv_reg pc2; /* 0x1c */
+ dv_reg pc3; /* 0x20 */
+ dv_reg pc4; /* 0x24 */
+ dv_reg pc5; /* 0x28 */
+ dv_reg rsvd[3];
+ dv_reg dat0; /* 0x38 */
+ dv_reg dat1; /* 0x3c */
+ dv_reg buf; /* 0x40 */
+ dv_reg emu; /* 0x44 */
+ dv_reg delay; /* 0x48 */
+ dv_reg def; /* 0x4c */
+ dv_reg fmt0; /* 0x50 */
+ dv_reg fmt1; /* 0x54 */
+ dv_reg fmt2; /* 0x58 */
+ dv_reg fmt3; /* 0x5c */
+ dv_reg intvec0; /* 0x60 */
+ dv_reg intvec1; /* 0x64 */
+};
+
+/* davinci spi slave */
+struct davinci_spi_slave {
+ struct spi_slave slave;
+ struct davinci_spi_regs *regs;
+ unsigned int freq;
+};
+
+static inline struct davinci_spi_slave *to_davinci_spi(struct spi_slave *slave)
{
- struct davinci_spi_slave *ds = to_davinci_spi(slave);
-
- /* Disable the SPI hardware */
- writel(SPIGCR0_SPIRST_MASK, &ds->regs->gcr0);
+ return container_of(slave, struct davinci_spi_slave, slave);
}
/*
@@ -235,6 +241,149 @@ static int davinci_spi_read_write(struct spi_slave *slave, unsigned int len,
}
#endif
+int spi_cs_is_valid(unsigned int bus, unsigned int cs)
+{
+ int ret = 0;
+
+ switch (bus) {
+ case SPI0_BUS:
+ if (cs < SPI0_NUM_CS)
+ ret = 1;
+ break;
+#ifdef CONFIG_SYS_SPI1
+ case SPI1_BUS:
+ if (cs < SPI1_NUM_CS)
+ ret = 1;
+ break;
+#endif
+#ifdef CONFIG_SYS_SPI2
+ case SPI2_BUS:
+ if (cs < SPI2_NUM_CS)
+ ret = 1;
+ break;
+#endif
+ default:
+ /* Invalid bus number. Do nothing */
+ break;
+ }
+ return ret;
+}
+
+void spi_cs_activate(struct spi_slave *slave)
+{
+ /* do nothing */
+}
+
+void spi_cs_deactivate(struct spi_slave *slave)
+{
+ /* do nothing */
+}
+
+void spi_init(void)
+{
+ /* do nothing */
+}
+
+struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
+ unsigned int max_hz, unsigned int mode)
+{
+ struct davinci_spi_slave *ds;
+
+ if (!spi_cs_is_valid(bus, cs))
+ return NULL;
+
+ ds = spi_alloc_slave(struct davinci_spi_slave, bus, cs);
+ if (!ds)
+ return NULL;
+
+ switch (bus) {
+ case SPI0_BUS:
+ ds->regs = (struct davinci_spi_regs *)SPI0_BASE;
+ break;
+#ifdef CONFIG_SYS_SPI1
+ case SPI1_BUS:
+ ds->regs = (struct davinci_spi_regs *)SPI1_BASE;
+ break;
+#endif
+#ifdef CONFIG_SYS_SPI2
+ case SPI2_BUS:
+ ds->regs = (struct davinci_spi_regs *)SPI2_BASE;
+ break;
+#endif
+ default: /* Invalid bus number */
+ return NULL;
+ }
+
+ ds->freq = max_hz;
+
+ return &ds->slave;
+}
+
+void spi_free_slave(struct spi_slave *slave)
+{
+ struct davinci_spi_slave *ds = to_davinci_spi(slave);
+
+ free(ds);
+}
+
+int spi_claim_bus(struct spi_slave *slave)
+{
+ struct davinci_spi_slave *ds = to_davinci_spi(slave);
+ unsigned int scalar;
+
+ /* Enable the SPI hardware */
+ writel(SPIGCR0_SPIRST_MASK, &ds->regs->gcr0);
+ udelay(1000);
+ writel(SPIGCR0_SPIENA_MASK, &ds->regs->gcr0);
+
+ /* Set master mode, powered up and not activated */
+ writel(SPIGCR1_MASTER_MASK | SPIGCR1_CLKMOD_MASK, &ds->regs->gcr1);
+
+ /* CS, CLK, SIMO and SOMI are functional pins */
+ writel(((1 << slave->cs) | SPIPC0_CLKFUN_MASK |
+ SPIPC0_DOFUN_MASK | SPIPC0_DIFUN_MASK), &ds->regs->pc0);
+
+ /* setup format */
+ scalar = ((CONFIG_SYS_SPI_CLK / ds->freq) - 1) & 0xFF;
+
+ /*
+ * Use following format:
+ * character length = 8,
+ * clock signal delayed by half clk cycle,
+ * clock low in idle state - Mode 0,
+ * MSB shifted out first
+ */
+ writel(8 | (scalar << SPIFMT_PRESCALE_SHIFT) |
+ (1 << SPIFMT_PHASE_SHIFT), &ds->regs->fmt0);
+
+ /*
+ * Including a minor delay. No science here. Should be good even with
+ * no delay
+ */
+ writel((50 << SPI_C2TDELAY_SHIFT) |
+ (50 << SPI_T2CDELAY_SHIFT), &ds->regs->delay);
+
+ /* default chip select register */
+ writel(SPIDEF_CSDEF0_MASK, &ds->regs->def);
+
+ /* no interrupts */
+ writel(0, &ds->regs->int0);
+ writel(0, &ds->regs->lvl);
+
+ /* enable SPI */
+ writel((readl(&ds->regs->gcr1) | SPIGCR1_SPIENA_MASK), &ds->regs->gcr1);
+
+ return 0;
+}
+
+void spi_release_bus(struct spi_slave *slave)
+{
+ struct davinci_spi_slave *ds = to_davinci_spi(slave);
+
+ /* Disable the SPI hardware */
+ writel(SPIGCR0_SPIRST_MASK, &ds->regs->gcr0);
+}
+
int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
const void *dout, void *din, unsigned long flags)
{
@@ -278,41 +427,3 @@ out:
}
return 0;
}
-
-int spi_cs_is_valid(unsigned int bus, unsigned int cs)
-{
- int ret = 0;
-
- switch (bus) {
- case SPI0_BUS:
- if (cs < SPI0_NUM_CS)
- ret = 1;
- break;
-#ifdef CONFIG_SYS_SPI1
- case SPI1_BUS:
- if (cs < SPI1_NUM_CS)
- ret = 1;
- break;
-#endif
-#ifdef CONFIG_SYS_SPI2
- case SPI2_BUS:
- if (cs < SPI2_NUM_CS)
- ret = 1;
- break;
-#endif
- default:
- /* Invalid bus number. Do nothing */
- break;
- }
- return ret;
-}
-
-void spi_cs_activate(struct spi_slave *slave)
-{
- /* do nothing */
-}
-
-void spi_cs_deactivate(struct spi_slave *slave)
-{
- /* do nothing */
-}
diff --git a/drivers/spi/davinci_spi.h b/drivers/spi/davinci_spi.h
deleted file mode 100644
index d4612d3527..0000000000
--- a/drivers/spi/davinci_spi.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
- *
- * Register definitions for the DaVinci SPI Controller
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
-
-#ifndef _DAVINCI_SPI_H_
-#define _DAVINCI_SPI_H_
-
-struct davinci_spi_regs {
- dv_reg gcr0; /* 0x00 */
- dv_reg gcr1; /* 0x04 */
- dv_reg int0; /* 0x08 */
- dv_reg lvl; /* 0x0c */
- dv_reg flg; /* 0x10 */
- dv_reg pc0; /* 0x14 */
- dv_reg pc1; /* 0x18 */
- dv_reg pc2; /* 0x1c */
- dv_reg pc3; /* 0x20 */
- dv_reg pc4; /* 0x24 */
- dv_reg pc5; /* 0x28 */
- dv_reg rsvd[3];
- dv_reg dat0; /* 0x38 */
- dv_reg dat1; /* 0x3c */
- dv_reg buf; /* 0x40 */
- dv_reg emu; /* 0x44 */
- dv_reg delay; /* 0x48 */
- dv_reg def; /* 0x4c */
- dv_reg fmt0; /* 0x50 */
- dv_reg fmt1; /* 0x54 */
- dv_reg fmt2; /* 0x58 */
- dv_reg fmt3; /* 0x5c */
- dv_reg intvec0; /* 0x60 */
- dv_reg intvec1; /* 0x64 */
-};
-
-#define BIT(x) (1 << (x))
-
-/* SPIGCR0 */
-#define SPIGCR0_SPIENA_MASK 0x1
-#define SPIGCR0_SPIRST_MASK 0x0
-
-/* SPIGCR0 */
-#define SPIGCR1_CLKMOD_MASK BIT(1)
-#define SPIGCR1_MASTER_MASK BIT(0)
-#define SPIGCR1_SPIENA_MASK BIT(24)
-
-/* SPIPC0 */
-#define SPIPC0_DIFUN_MASK BIT(11) /* SIMO */
-#define SPIPC0_DOFUN_MASK BIT(10) /* SOMI */
-#define SPIPC0_CLKFUN_MASK BIT(9) /* CLK */
-#define SPIPC0_EN0FUN_MASK BIT(0)
-
-/* SPIFMT0 */
-#define SPIFMT_SHIFTDIR_SHIFT 20
-#define SPIFMT_POLARITY_SHIFT 17
-#define SPIFMT_PHASE_SHIFT 16
-#define SPIFMT_PRESCALE_SHIFT 8
-
-/* SPIDAT1 */
-#define SPIDAT1_CSHOLD_SHIFT 28
-#define SPIDAT1_CSNR_SHIFT 16
-
-/* SPIDELAY */
-#define SPI_C2TDELAY_SHIFT 24
-#define SPI_T2CDELAY_SHIFT 16
-
-/* SPIBUF */
-#define SPIBUF_RXEMPTY_MASK BIT(31)
-#define SPIBUF_TXFULL_MASK BIT(29)
-
-/* SPIDEF */
-#define SPIDEF_CSDEF0_MASK BIT(0)
-
-#define SPI0_BUS 0
-#define SPI0_BASE CONFIG_SYS_SPI_BASE
-/*
- * Define default SPI0_NUM_CS as 1 for existing platforms that uses this
- * driver. Platform can configure number of CS using CONFIG_SYS_SPI0_NUM_CS
- * if more than one CS is supported and by defining CONFIG_SYS_SPI0.
- */
-#ifndef CONFIG_SYS_SPI0
-#define SPI0_NUM_CS 1
-#else
-#define SPI0_NUM_CS CONFIG_SYS_SPI0_NUM_CS
-#endif
-
-/*
- * define CONFIG_SYS_SPI1 when platform has spi-1 device (bus #1) and
- * CONFIG_SYS_SPI1_NUM_CS defines number of CS on this bus
- */
-#ifdef CONFIG_SYS_SPI1
-#define SPI1_BUS 1
-#define SPI1_NUM_CS CONFIG_SYS_SPI1_NUM_CS
-#define SPI1_BASE CONFIG_SYS_SPI1_BASE
-#endif
-
-/*
- * define CONFIG_SYS_SPI2 when platform has spi-2 device (bus #2) and
- * CONFIG_SYS_SPI2_NUM_CS defines number of CS on this bus
- */
-#ifdef CONFIG_SYS_SPI2
-#define SPI2_BUS 2
-#define SPI2_NUM_CS CONFIG_SYS_SPI2_NUM_CS
-#define SPI2_BASE CONFIG_SYS_SPI2_BASE
-#endif
-
-struct davinci_spi_slave {
- struct spi_slave slave;
- struct davinci_spi_regs *regs;
- unsigned int freq;
-};
-
-static inline struct davinci_spi_slave *to_davinci_spi(struct spi_slave *slave)
-{
- return container_of(slave, struct davinci_spi_slave, slave);
-}
-
-#endif /* _DAVINCI_SPI_H_ */
diff --git a/drivers/spi/ftssp010_spi.c b/drivers/spi/ftssp010_spi.c
deleted file mode 100644
index c7d6480478..0000000000
--- a/drivers/spi/ftssp010_spi.c
+++ /dev/null
@@ -1,498 +0,0 @@
-/*
- * (C) Copyright 2013
- * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
- * Kuo-Jung Su <dantesu@gmail.com>
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
-
-#include <common.h>
-#include <linux/compat.h>
-#include <asm/io.h>
-#include <malloc.h>
-#include <spi.h>
-
-#ifndef CONFIG_FTSSP010_BASE_LIST
-#define CONFIG_FTSSP010_BASE_LIST { CONFIG_FTSSP010_BASE }
-#endif
-
-#ifndef CONFIG_FTSSP010_GPIO_BASE
-#define CONFIG_FTSSP010_GPIO_BASE 0
-#endif
-
-#ifndef CONFIG_FTSSP010_GPIO_LIST
-#define CONFIG_FTSSP010_GPIO_LIST { CONFIG_FTSSP010_GPIO_BASE }
-#endif
-
-#ifndef CONFIG_FTSSP010_CLOCK
-#define CONFIG_FTSSP010_CLOCK clk_get_rate("SSP");
-#endif
-
-#ifndef CONFIG_FTSSP010_TIMEOUT
-#define CONFIG_FTSSP010_TIMEOUT 100
-#endif
-
-/* FTSSP010 chip registers */
-struct ftssp010_regs {
- uint32_t cr[3];/* control register */
- uint32_t sr; /* status register */
- uint32_t icr; /* interrupt control register */
- uint32_t isr; /* interrupt status register */
- uint32_t dr; /* data register */
- uint32_t rsvd[17];
- uint32_t revr; /* revision register */
- uint32_t fear; /* feature register */
-};
-
-/* Control Register 0 */
-#define CR0_FFMT_MASK (7 << 12)
-#define CR0_FFMT_SSP (0 << 12)
-#define CR0_FFMT_SPI (1 << 12)
-#define CR0_FFMT_MICROWIRE (2 << 12)
-#define CR0_FFMT_I2S (3 << 12)
-#define CR0_FFMT_AC97 (4 << 12)
-#define CR0_FLASH (1 << 11)
-#define CR0_FSDIST(x) (((x) & 0x03) << 8)
-#define CR0_LOOP (1 << 7) /* loopback mode */
-#define CR0_LSB (1 << 6) /* LSB */
-#define CR0_FSPO (1 << 5) /* fs atcive low (I2S only) */
-#define CR0_FSJUSTIFY (1 << 4)
-#define CR0_OPM_SLAVE (0 << 2)
-#define CR0_OPM_MASTER (3 << 2)
-#define CR0_OPM_I2S_MSST (3 << 2) /* master stereo mode */
-#define CR0_OPM_I2S_MSMO (2 << 2) /* master mono mode */
-#define CR0_OPM_I2S_SLST (1 << 2) /* slave stereo mode */
-#define CR0_OPM_I2S_SLMO (0 << 2) /* slave mono mode */
-#define CR0_SCLKPO (1 << 1) /* clock polarity */
-#define CR0_SCLKPH (1 << 0) /* clock phase */
-
-/* Control Register 1 */
-#define CR1_PDL(x) (((x) & 0xff) << 24) /* padding length */
-#define CR1_SDL(x) ((((x) - 1) & 0x1f) << 16) /* data length */
-#define CR1_DIV(x) (((x) - 1) & 0xffff) /* clock divider */
-
-/* Control Register 2 */
-#define CR2_CS(x) (((x) & 3) << 10) /* CS/FS select */
-#define CR2_FS (1 << 9) /* CS/FS signal level */
-#define CR2_TXEN (1 << 8) /* tx enable */
-#define CR2_RXEN (1 << 7) /* rx enable */
-#define CR2_RESET (1 << 6) /* chip reset */
-#define CR2_TXFC (1 << 3) /* tx fifo Clear */
-#define CR2_RXFC (1 << 2) /* rx fifo Clear */
-#define CR2_TXDOE (1 << 1) /* tx data output enable */
-#define CR2_EN (1 << 0) /* chip enable */
-
-/* Status Register */
-#define SR_RFF (1 << 0) /* rx fifo full */
-#define SR_TFNF (1 << 1) /* tx fifo not full */
-#define SR_BUSY (1 << 2) /* chip busy */
-#define SR_RFVE(reg) (((reg) >> 4) & 0x1f) /* rx fifo valid entries */
-#define SR_TFVE(reg) (((reg) >> 12) & 0x1f) /* tx fifo valid entries */
-
-/* Feature Register */
-#define FEAR_BITS(reg) ((((reg) >> 0) & 0xff) + 1) /* data width */
-#define FEAR_RFSZ(reg) ((((reg) >> 8) & 0xff) + 1) /* rx fifo size */
-#define FEAR_TFSZ(reg) ((((reg) >> 16) & 0xff) + 1) /* tx fifo size */
-#define FEAR_AC97 (1 << 24)
-#define FEAR_I2S (1 << 25)
-#define FEAR_SPI_MWR (1 << 26)
-#define FEAR_SSP (1 << 27)
-#define FEAR_SPDIF (1 << 28)
-
-/* FTGPIO010 chip registers */
-struct ftgpio010_regs {
- uint32_t out; /* 0x00: Data Output */
- uint32_t in; /* 0x04: Data Input */
- uint32_t dir; /* 0x08: Direction */
- uint32_t bypass; /* 0x0c: Bypass */
- uint32_t set; /* 0x10: Data Set */
- uint32_t clr; /* 0x14: Data Clear */
- uint32_t pull_up; /* 0x18: Pull-Up Enabled */
- uint32_t pull_st; /* 0x1c: Pull State (0=pull-down, 1=pull-up) */
-};
-
-struct ftssp010_gpio {
- struct ftgpio010_regs *regs;
- uint32_t pin;
-};
-
-struct ftssp010_spi {
- struct spi_slave slave;
- struct ftssp010_gpio gpio;
- struct ftssp010_regs *regs;
- uint32_t fifo;
- uint32_t mode;
- uint32_t div;
- uint32_t clk;
- uint32_t speed;
- uint32_t revision;
-};
-
-static inline struct ftssp010_spi *to_ftssp010_spi(struct spi_slave *slave)
-{
- return container_of(slave, struct ftssp010_spi, slave);
-}
-
-static int get_spi_chip(int bus, struct ftssp010_spi *chip)
-{
- uint32_t fear, base[] = CONFIG_FTSSP010_BASE_LIST;
-
- if (bus >= ARRAY_SIZE(base) || !base[bus])
- return -1;
-
- chip->regs = (struct ftssp010_regs *)base[bus];
-
- chip->revision = readl(&chip->regs->revr);
-
- fear = readl(&chip->regs->fear);
- chip->fifo = min_t(uint32_t, FEAR_TFSZ(fear), FEAR_RFSZ(fear));
-
- return 0;
-}
-
-static int get_spi_gpio(int bus, struct ftssp010_gpio *chip)
-{
- uint32_t base[] = CONFIG_FTSSP010_GPIO_LIST;
-
- if (bus >= ARRAY_SIZE(base) || !base[bus])
- return -1;
-
- chip->regs = (struct ftgpio010_regs *)(base[bus] & 0xfff00000);
- chip->pin = base[bus] & 0x1f;
-
- /* make it an output pin */
- setbits_le32(&chip->regs->dir, 1 << chip->pin);
-
- return 0;
-}
-
-static int ftssp010_wait(struct ftssp010_spi *chip)
-{
- struct ftssp010_regs *regs = chip->regs;
- ulong t;
-
- /* wait until device idle */
- for (t = get_timer(0); get_timer(t) < CONFIG_FTSSP010_TIMEOUT; ) {
- if (!(readl(&regs->sr) & SR_BUSY))
- return 0;
- }
-
- puts("ftspi010: busy timeout\n");
-
- return -1;
-}
-
-static int ftssp010_wait_tx(struct ftssp010_spi *chip)
-{
- struct ftssp010_regs *regs = chip->regs;
- ulong t;
-
- /* wait until tx fifo not full */
- for (t = get_timer(0); get_timer(t) < CONFIG_FTSSP010_TIMEOUT; ) {
- if (readl(&regs->sr) & SR_TFNF)
- return 0;
- }
-
- puts("ftssp010: tx timeout\n");
-
- return -1;
-}
-
-static int ftssp010_wait_rx(struct ftssp010_spi *chip)
-{
- struct ftssp010_regs *regs = chip->regs;
- ulong t;
-
- /* wait until rx fifo not empty */
- for (t = get_timer(0); get_timer(t) < CONFIG_FTSSP010_TIMEOUT; ) {
- if (SR_RFVE(readl(&regs->sr)))
- return 0;
- }
-
- puts("ftssp010: rx timeout\n");
-
- return -1;
-}
-
-static int ftssp010_spi_work_transfer_v2(struct ftssp010_spi *chip,
- const void *tx_buf, void *rx_buf, int len, uint flags)
-{
- struct ftssp010_regs *regs = chip->regs;
- const uint8_t *txb = tx_buf;
- uint8_t *rxb = rx_buf;
-
- while (len > 0) {
- int i, depth = min(chip->fifo >> 2, len);
- uint32_t xmsk = 0;
-
- if (tx_buf) {
- for (i = 0; i < depth; ++i) {
- ftssp010_wait_tx(chip);
- writel(*txb++, &regs->dr);
- }
- xmsk |= CR2_TXEN | CR2_TXDOE;
- if ((readl(&regs->cr[2]) & xmsk) != xmsk)
- setbits_le32(&regs->cr[2], xmsk);
- }
- if (rx_buf) {
- xmsk |= CR2_RXEN;
- if ((readl(&regs->cr[2]) & xmsk) != xmsk)
- setbits_le32(&regs->cr[2], xmsk);
- for (i = 0; i < depth; ++i) {
- ftssp010_wait_rx(chip);
- *rxb++ = (uint8_t)readl(&regs->dr);
- }
- }
-
- len -= depth;
- }
-
- return 0;
-}
-
-static int ftssp010_spi_work_transfer_v1(struct ftssp010_spi *chip,
- const void *tx_buf, void *rx_buf, int len, uint flags)
-{
- struct ftssp010_regs *regs = chip->regs;
- const uint8_t *txb = tx_buf;
- uint8_t *rxb = rx_buf;
-
- while (len > 0) {
- int i, depth = min(chip->fifo >> 2, len);
- uint32_t tmp;
-
- for (i = 0; i < depth; ++i) {
- ftssp010_wait_tx(chip);
- writel(txb ? (*txb++) : 0, &regs->dr);
- }
- for (i = 0; i < depth; ++i) {
- ftssp010_wait_rx(chip);
- tmp = readl(&regs->dr);
- if (rxb)
- *rxb++ = (uint8_t)tmp;
- }
-
- len -= depth;
- }
-
- return 0;
-}
-
-static void ftssp010_cs_set(struct ftssp010_spi *chip, int high)
-{
- struct ftssp010_regs *regs = chip->regs;
- struct ftssp010_gpio *gpio = &chip->gpio;
- uint32_t mask;
-
- /* cs pull high/low */
- if (chip->revision >= 0x11900) {
- mask = CR2_CS(chip->slave.cs) | (high ? CR2_FS : 0);
- writel(mask, &regs->cr[2]);
- } else if (gpio->regs) {
- mask = 1 << gpio->pin;
- if (high)
- writel(mask, &gpio->regs->set);
- else
- writel(mask, &gpio->regs->clr);
- }
-
- /* extra delay for signal propagation */
- udelay_masked(1);
-}
-
-/*
- * Determine if a SPI chipselect is valid.
- * This function is provided by the board if the low-level SPI driver
- * needs it to determine if a given chipselect is actually valid.
- *
- * Returns: 1 if bus:cs identifies a valid chip on this board, 0
- * otherwise.
- */
-int spi_cs_is_valid(unsigned int bus, unsigned int cs)
-{
- struct ftssp010_spi chip;
-
- if (get_spi_chip(bus, &chip))
- return 0;
-
- if (!cs)
- return 1;
- else if ((cs < 4) && (chip.revision >= 0x11900))
- return 1;
-
- return 0;
-}
-
-/*
- * Activate a SPI chipselect.
- * This function is provided by the board code when using a driver
- * that can't control its chipselects automatically (e.g.
- * common/soft_spi.c). When called, it should activate the chip select
- * to the device identified by "slave".
- */
-void spi_cs_activate(struct spi_slave *slave)
-{
- struct ftssp010_spi *chip = to_ftssp010_spi(slave);
- struct ftssp010_regs *regs = chip->regs;
-
- /* cs pull */
- if (chip->mode & SPI_CS_HIGH)
- ftssp010_cs_set(chip, 1);
- else
- ftssp010_cs_set(chip, 0);
-
- /* chip enable + fifo clear */
- setbits_le32(&regs->cr[2], CR2_EN | CR2_TXFC | CR2_RXFC);
-}
-
-/*
- * Deactivate a SPI chipselect.
- * This function is provided by the board code when using a driver
- * that can't control its chipselects automatically (e.g.
- * common/soft_spi.c). When called, it should deactivate the chip
- * select to the device identified by "slave".
- */
-void spi_cs_deactivate(struct spi_slave *slave)
-{
- struct ftssp010_spi *chip = to_ftssp010_spi(slave);
-
- /* wait until chip idle */
- ftssp010_wait(chip);
-
- /* cs pull */
- if (chip->mode & SPI_CS_HIGH)
- ftssp010_cs_set(chip, 0);
- else
- ftssp010_cs_set(chip, 1);
-}
-
-void spi_init(void)
-{
- /* nothing to do */
-}
-
-struct spi_slave *spi_setup_slave(uint bus, uint cs, uint max_hz, uint mode)
-{
- struct ftssp010_spi *chip;
-
- if (mode & SPI_3WIRE) {
- puts("ftssp010: can't do 3-wire\n");
- return NULL;
- }
-
- if (mode & SPI_SLAVE) {
- puts("ftssp010: can't do slave mode\n");
- return NULL;
- }
-
- if (mode & SPI_PREAMBLE) {
- puts("ftssp010: can't skip preamble bytes\n");
- return NULL;
- }
-
- if (!spi_cs_is_valid(bus, cs)) {
- puts("ftssp010: invalid (bus, cs)\n");
- return NULL;
- }
-
- chip = spi_alloc_slave(struct ftssp010_spi, bus, cs);
- if (!chip)
- return NULL;
-
- if (get_spi_chip(bus, chip))
- goto free_out;
-
- if (chip->revision < 0x11900 && get_spi_gpio(bus, &chip->gpio)) {
- puts("ftssp010: Before revision 1.19.0, its clock & cs are\n"
- "controlled by tx engine which is not synced with rx engine,\n"
- "so the clock & cs might be shutdown before rx engine\n"
- "finishs its jobs.\n"
- "If possible, please add a dedicated gpio for it.\n");
- }
-
- chip->mode = mode;
- chip->clk = CONFIG_FTSSP010_CLOCK;
- chip->div = 2;
- if (max_hz) {
- while (chip->div < 0xffff) {
- if ((chip->clk / (2 * chip->div)) <= max_hz)
- break;
- chip->div += 1;
- }
- }
- chip->speed = chip->clk / (2 * chip->div);
-
- return &chip->slave;
-
-free_out:
- free(chip);
- return NULL;
-}
-
-void spi_free_slave(struct spi_slave *slave)
-{
- struct ftssp010_spi *chip = to_ftssp010_spi(slave);
-
- free(chip);
-}
-
-int spi_claim_bus(struct spi_slave *slave)
-{
- struct ftssp010_spi *chip = to_ftssp010_spi(slave);
- struct ftssp010_regs *regs = chip->regs;
-
- writel(CR1_SDL(8) | CR1_DIV(chip->div), &regs->cr[1]);
-
- if (chip->revision >= 0x11900) {
- writel(CR0_OPM_MASTER | CR0_FFMT_SPI | CR0_FSPO | CR0_FLASH,
- &regs->cr[0]);
- writel(CR2_TXFC | CR2_RXFC,
- &regs->cr[2]);
- } else {
- writel(CR0_OPM_MASTER | CR0_FFMT_SPI | CR0_FSPO,
- &regs->cr[0]);
- writel(CR2_TXFC | CR2_RXFC | CR2_EN | CR2_TXDOE,
- &regs->cr[2]);
- }
-
- if (chip->mode & SPI_LOOP)
- setbits_le32(&regs->cr[0], CR0_LOOP);
-
- if (chip->mode & SPI_CPOL)
- setbits_le32(&regs->cr[0], CR0_SCLKPO);
-
- if (chip->mode & SPI_CPHA)
- setbits_le32(&regs->cr[0], CR0_SCLKPH);
-
- spi_cs_deactivate(slave);
-
- return 0;
-}
-
-void spi_release_bus(struct spi_slave *slave)
-{
- struct ftssp010_spi *chip = to_ftssp010_spi(slave);
- struct ftssp010_regs *regs = chip->regs;
-
- writel(0, &regs->cr[2]);
-}
-
-int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
- const void *dout, void *din, unsigned long flags)
-{
- struct ftssp010_spi *chip = to_ftssp010_spi(slave);
- uint32_t len = bitlen >> 3;
-
- if (flags & SPI_XFER_BEGIN)
- spi_cs_activate(slave);
-
- if (chip->revision >= 0x11900)
- ftssp010_spi_work_transfer_v2(chip, dout, din, len, flags);
- else
- ftssp010_spi_work_transfer_v1(chip, dout, din, len, flags);
-
- if (flags & SPI_XFER_END)
- spi_cs_deactivate(slave);
-
- return 0;
-}
diff --git a/drivers/spi/oc_tiny_spi.c b/drivers/spi/oc_tiny_spi.c
deleted file mode 100644
index 4de5d008aa..0000000000
--- a/drivers/spi/oc_tiny_spi.c
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Opencore tiny_spi driver
- *
- * http://opencores.org/project,tiny_spi
- *
- * based on bfin_spi.c
- * Copyright (c) 2005-2008 Analog Devices Inc.
- * Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw>
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
-
-#include <common.h>
-#include <asm/io.h>
-#include <malloc.h>
-#include <spi.h>
-#include <asm/gpio.h>
-
-#define TINY_SPI_STATUS_TXE 0x1
-#define TINY_SPI_STATUS_TXR 0x2
-
-struct tiny_spi_regs {
- unsigned rxdata; /* Rx data reg */
- unsigned txdata; /* Tx data reg */
- unsigned status; /* Status reg */
- unsigned control; /* Control reg */
- unsigned baud; /* Baud reg */
-};
-
-struct tiny_spi_host {
- uint base;
- uint freq;
- uint baudwidth;
-};
-static const struct tiny_spi_host tiny_spi_host_list[] =
- CONFIG_SYS_TINY_SPI_LIST;
-
-struct tiny_spi_slave {
- struct spi_slave slave;
- const struct tiny_spi_host *host;
- uint mode;
- uint baud;
- uint flg;
-};
-#define to_tiny_spi_slave(s) container_of(s, struct tiny_spi_slave, slave)
-
-int spi_cs_is_valid(unsigned int bus, unsigned int cs)
-{
- return bus < ARRAY_SIZE(tiny_spi_host_list) && gpio_is_valid(cs);
-}
-
-void spi_cs_activate(struct spi_slave *slave)
-{
- struct tiny_spi_slave *tiny_spi = to_tiny_spi_slave(slave);
- unsigned int cs = slave->cs;
-
- gpio_set_value(cs, tiny_spi->flg);
- debug("%s: SPI_CS_GPIO:%x\n", __func__, gpio_get_value(cs));
-}
-
-void spi_cs_deactivate(struct spi_slave *slave)
-{
- struct tiny_spi_slave *tiny_spi = to_tiny_spi_slave(slave);
- unsigned int cs = slave->cs;
-
- gpio_set_value(cs, !tiny_spi->flg);
- debug("%s: SPI_CS_GPIO:%x\n", __func__, gpio_get_value(cs));
-}
-
-void spi_set_speed(struct spi_slave *slave, uint hz)
-{
- struct tiny_spi_slave *tiny_spi = to_tiny_spi_slave(slave);
- const struct tiny_spi_host *host = tiny_spi->host;
-
- tiny_spi->baud = min(DIV_ROUND_UP(host->freq, hz * 2),
- (1 << host->baudwidth)) - 1;
- debug("%s: speed %u actual %u\n", __func__, hz,
- host->freq / ((tiny_spi->baud + 1) * 2));
-}
-
-void spi_init(void)
-{
-}
-
-struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
- unsigned int hz, unsigned int mode)
-{
- struct tiny_spi_slave *tiny_spi;
-
- if (!spi_cs_is_valid(bus, cs) || gpio_request(cs, "tiny_spi"))
- return NULL;
-
- tiny_spi = spi_alloc_slave(struct tiny_spi_slave, bus, cs);
- if (!tiny_spi)
- return NULL;
-
- tiny_spi->host = &tiny_spi_host_list[bus];
- tiny_spi->mode = mode & (SPI_CPOL | SPI_CPHA);
- tiny_spi->flg = mode & SPI_CS_HIGH ? 1 : 0;
- spi_set_speed(&tiny_spi->slave, hz);
-
- debug("%s: bus:%i cs:%i base:%lx\n", __func__,
- bus, cs, tiny_spi->host->base);
- return &tiny_spi->slave;
-}
-
-void spi_free_slave(struct spi_slave *slave)
-{
- struct tiny_spi_slave *tiny_spi = to_tiny_spi_slave(slave);
-
- gpio_free(slave->cs);
- free(tiny_spi);
-}
-
-int spi_claim_bus(struct spi_slave *slave)
-{
- struct tiny_spi_slave *tiny_spi = to_tiny_spi_slave(slave);
- struct tiny_spi_regs *regs = (void *)tiny_spi->host->base;
-
- debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs);
- gpio_direction_output(slave->cs, !tiny_spi->flg);
- writel(tiny_spi->mode, &regs->control);
- writel(tiny_spi->baud, &regs->baud);
- return 0;
-}
-
-void spi_release_bus(struct spi_slave *slave)
-{
- debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs);
-}
-
-#ifndef CONFIG_TINY_SPI_IDLE_VAL
-# define CONFIG_TINY_SPI_IDLE_VAL 0xff
-#endif
-
-int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
- void *din, unsigned long flags)
-{
- struct tiny_spi_slave *tiny_spi = to_tiny_spi_slave(slave);
- struct tiny_spi_regs *regs = (void *)tiny_spi->host->base;
- const u8 *txp = dout;
- u8 *rxp = din;
- uint bytes = bitlen / 8;
- uint i;
-
- debug("%s: bus:%i cs:%i bitlen:%i bytes:%i flags:%lx\n", __func__,
- slave->bus, slave->cs, bitlen, bytes, flags);
- if (bitlen == 0)
- goto done;
-
- /* assume to do 8 bits transfers */
- if (bitlen % 8) {
- flags |= SPI_XFER_END;
- goto done;
- }
-
- if (flags & SPI_XFER_BEGIN)
- spi_cs_activate(slave);
-
- /* we need to tighten the transfer loop */
- if (txp && rxp) {
- writeb(*txp++, &regs->txdata);
- if (bytes > 1) {
- writeb(*txp++, &regs->txdata);
- for (i = 2; i < bytes; i++) {
- u8 rx, tx = *txp++;
- while (!(readb(&regs->status) &
- TINY_SPI_STATUS_TXR))
- ;
- rx = readb(&regs->txdata);
- writeb(tx, &regs->txdata);
- *rxp++ = rx;
- }
- while (!(readb(&regs->status) &
- TINY_SPI_STATUS_TXR))
- ;
- *rxp++ = readb(&regs->txdata);
- }
- while (!(readb(&regs->status) &
- TINY_SPI_STATUS_TXE))
- ;
- *rxp++ = readb(&regs->rxdata);
- } else if (rxp) {
- writeb(CONFIG_TINY_SPI_IDLE_VAL, &regs->txdata);
- if (bytes > 1) {
- writeb(CONFIG_TINY_SPI_IDLE_VAL,
- &regs->txdata);
- for (i = 2; i < bytes; i++) {
- u8 rx;
- while (!(readb(&regs->status) &
- TINY_SPI_STATUS_TXR))
- ;
- rx = readb(&regs->txdata);
- writeb(CONFIG_TINY_SPI_IDLE_VAL,
- &regs->txdata);
- *rxp++ = rx;
- }
- while (!(readb(&regs->status) &
- TINY_SPI_STATUS_TXR))
- ;
- *rxp++ = readb(&regs->txdata);
- }
- while (!(readb(&regs->status) &
- TINY_SPI_STATUS_TXE))
- ;
- *rxp++ = readb(&regs->rxdata);
- } else if (txp) {
- writeb(*txp++, &regs->txdata);
- if (bytes > 1) {
- writeb(*txp++, &regs->txdata);
- for (i = 2; i < bytes; i++) {
- u8 tx = *txp++;
- while (!(readb(&regs->status) &
- TINY_SPI_STATUS_TXR))
- ;
- writeb(tx, &regs->txdata);
- }
- }
- while (!(readb(&regs->status) &
- TINY_SPI_STATUS_TXE))
- ;
- } else {
- writeb(CONFIG_TINY_SPI_IDLE_VAL, &regs->txdata);
- if (bytes > 1) {
- writeb(CONFIG_TINY_SPI_IDLE_VAL,
- &regs->txdata);
- for (i = 2; i < bytes; i++) {
- while (!(readb(&regs->status) &
- TINY_SPI_STATUS_TXR))
- ;
- writeb(CONFIG_TINY_SPI_IDLE_VAL,
- &regs->txdata);
- }
- }
- while (!(readb(&regs->status) &
- TINY_SPI_STATUS_TXE))
- ;
- }
-
- done:
- if (flags & SPI_XFER_END)
- spi_cs_deactivate(slave);
-
- return 0;
-}
diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c
index 56d99d17c7..6c21acda57 100644
--- a/drivers/spi/xilinx_spi.c
+++ b/drivers/spi/xilinx_spi.c
@@ -1,149 +1,175 @@
/*
* Xilinx SPI driver
*
- * supports 8 bit SPI transfers only, with or w/o FIFO
+ * Supports 8 bit SPI transfers only, with or w/o FIFO
*
- * based on bfin_spi.c, by way of altera_spi.c
- * Copyright (c) 2005-2008 Analog Devices Inc.
- * Copyright (c) 2010 Thomas Chou <thomas@wytron.com.tw>
- * Copyright (c) 2010 Graeme Smecher <graeme.smecher@mail.mcgill.ca>
+ * Based on bfin_spi.c, by way of altera_spi.c
+ * Copyright (c) 2015 Jagan Teki <jteki@openedev.com>
* Copyright (c) 2012 Stephan Linz <linz@li-pro.net>
+ * Copyright (c) 2010 Graeme Smecher <graeme.smecher@mail.mcgill.ca>
+ * Copyright (c) 2010 Thomas Chou <thomas@wytron.com.tw>
+ * Copyright (c) 2005-2008 Analog Devices Inc.
*
* SPDX-License-Identifier: GPL-2.0+
- *
- * [0]: http://www.xilinx.com/support/documentation
- *
- * [S]: [0]/ip_documentation/xps_spi.pdf
- * [0]/ip_documentation/axi_spi_ds742.pdf
*/
+
#include <config.h>
#include <common.h>
+#include <dm.h>
+#include <errno.h>
#include <malloc.h>
#include <spi.h>
+#include <asm/io.h>
-#include "xilinx_spi.h"
+/*
+ * [0]: http://www.xilinx.com/support/documentation
+ *
+ * Xilinx SPI Register Definitions
+ * [1]: [0]/ip_documentation/xps_spi.pdf
+ * page 8, Register Descriptions
+ * [2]: [0]/ip_documentation/axi_spi_ds742.pdf
+ * page 7, Register Overview Table
+ */
-#ifndef CONFIG_SYS_XILINX_SPI_LIST
-#define CONFIG_SYS_XILINX_SPI_LIST { CONFIG_SYS_SPI_BASE }
-#endif
+/* SPI Control Register (spicr), [1] p9, [2] p8 */
+#define SPICR_LSB_FIRST (1 << 9)
+#define SPICR_MASTER_INHIBIT (1 << 8)
+#define SPICR_MANUAL_SS (1 << 7)
+#define SPICR_RXFIFO_RESEST (1 << 6)
+#define SPICR_TXFIFO_RESEST (1 << 5)
+#define SPICR_CPHA (1 << 4)
+#define SPICR_CPOL (1 << 3)
+#define SPICR_MASTER_MODE (1 << 2)
+#define SPICR_SPE (1 << 1)
+#define SPICR_LOOP (1 << 0)
+
+/* SPI Status Register (spisr), [1] p11, [2] p10 */
+#define SPISR_SLAVE_MODE_SELECT (1 << 5)
+#define SPISR_MODF (1 << 4)
+#define SPISR_TX_FULL (1 << 3)
+#define SPISR_TX_EMPTY (1 << 2)
+#define SPISR_RX_FULL (1 << 1)
+#define SPISR_RX_EMPTY (1 << 0)
+
+/* SPI Data Transmit Register (spidtr), [1] p12, [2] p12 */
+#define SPIDTR_8BIT_MASK (0xff << 0)
+#define SPIDTR_16BIT_MASK (0xffff << 0)
+#define SPIDTR_32BIT_MASK (0xffffffff << 0)
+
+/* SPI Data Receive Register (spidrr), [1] p12, [2] p12 */
+#define SPIDRR_8BIT_MASK (0xff << 0)
+#define SPIDRR_16BIT_MASK (0xffff << 0)
+#define SPIDRR_32BIT_MASK (0xffffffff << 0)
+
+/* SPI Slave Select Register (spissr), [1] p13, [2] p13 */
+#define SPISSR_MASK(cs) (1 << (cs))
+#define SPISSR_ACT(cs) ~SPISSR_MASK(cs)
+#define SPISSR_OFF ~0UL
+
+/* SPI Software Reset Register (ssr) */
+#define SPISSR_RESET_VALUE 0x0a
+
+#define XILSPI_MAX_XFER_BITS 8
+#define XILSPI_SPICR_DFLT_ON (SPICR_MANUAL_SS | SPICR_MASTER_MODE | \
+ SPICR_SPE)
+#define XILSPI_SPICR_DFLT_OFF (SPICR_MASTER_INHIBIT | SPICR_MANUAL_SS)
#ifndef CONFIG_XILINX_SPI_IDLE_VAL
#define CONFIG_XILINX_SPI_IDLE_VAL 0xff
#endif
-#define XILSPI_SPICR_DFLT_ON (SPICR_MANUAL_SS | \
- SPICR_MASTER_MODE | \
- SPICR_SPE)
-
-#define XILSPI_SPICR_DFLT_OFF (SPICR_MASTER_INHIBIT | \
- SPICR_MANUAL_SS)
+#ifndef CONFIG_SYS_XILINX_SPI_LIST
+#define CONFIG_SYS_XILINX_SPI_LIST { CONFIG_SYS_SPI_BASE }
+#endif
-#define XILSPI_MAX_XFER_BITS 8
+/* xilinx spi register set */
+struct xilinx_spi_regs {
+ u32 __space0__[7];
+ u32 dgier; /* Device Global Interrupt Enable Register (DGIER) */
+ u32 ipisr; /* IP Interrupt Status Register (IPISR) */
+ u32 __space1__;
+ u32 ipier; /* IP Interrupt Enable Register (IPIER) */
+ u32 __space2__[5];
+ u32 srr; /* Softare Reset Register (SRR) */
+ u32 __space3__[7];
+ u32 spicr; /* SPI Control Register (SPICR) */
+ u32 spisr; /* SPI Status Register (SPISR) */
+ u32 spidtr; /* SPI Data Transmit Register (SPIDTR) */
+ u32 spidrr; /* SPI Data Receive Register (SPIDRR) */
+ u32 spissr; /* SPI Slave Select Register (SPISSR) */
+ u32 spitfor; /* SPI Transmit FIFO Occupancy Register (SPITFOR) */
+ u32 spirfor; /* SPI Receive FIFO Occupancy Register (SPIRFOR) */
+};
+
+/* xilinx spi priv */
+struct xilinx_spi_priv {
+ struct xilinx_spi_regs *regs;
+ unsigned int freq;
+ unsigned int mode;
+};
static unsigned long xilinx_spi_base_list[] = CONFIG_SYS_XILINX_SPI_LIST;
-
-__attribute__((weak))
-int spi_cs_is_valid(unsigned int bus, unsigned int cs)
+static int xilinx_spi_probe(struct udevice *bus)
{
- return bus < ARRAY_SIZE(xilinx_spi_base_list) && cs < 32;
-}
+ struct xilinx_spi_priv *priv = dev_get_priv(bus);
+ struct xilinx_spi_regs *regs = priv->regs;
-__attribute__((weak))
-void spi_cs_activate(struct spi_slave *slave)
-{
- struct xilinx_spi_slave *xilspi = to_xilinx_spi_slave(slave);
+ priv->regs = (struct xilinx_spi_regs *)xilinx_spi_base_list[bus->seq];
- writel(SPISSR_ACT(slave->cs), &xilspi->regs->spissr);
-}
+ writel(SPISSR_RESET_VALUE, &regs->srr);
-__attribute__((weak))
-void spi_cs_deactivate(struct spi_slave *slave)
-{
- struct xilinx_spi_slave *xilspi = to_xilinx_spi_slave(slave);
-
- writel(SPISSR_OFF, &xilspi->regs->spissr);
+ return 0;
}
-void spi_init(void)
+static void spi_cs_activate(struct udevice *dev, uint cs)
{
- /* do nothing */
-}
+ struct udevice *bus = dev_get_parent(dev);
+ struct xilinx_spi_priv *priv = dev_get_priv(bus);
+ struct xilinx_spi_regs *regs = priv->regs;
-void spi_set_speed(struct spi_slave *slave, uint hz)
-{
- /* xilinx spi core does not support programmable speed */
+ writel(SPISSR_ACT(cs), &regs->spissr);
}
-struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
- unsigned int max_hz, unsigned int mode)
+static void spi_cs_deactivate(struct udevice *dev)
{
- struct xilinx_spi_slave *xilspi;
-
- if (!spi_cs_is_valid(bus, cs)) {
- printf("XILSPI error: %s: unsupported bus %d / cs %d\n",
- __func__, bus, cs);
- return NULL;
- }
-
- xilspi = spi_alloc_slave(struct xilinx_spi_slave, bus, cs);
- if (!xilspi) {
- printf("XILSPI error: %s: malloc of SPI structure failed\n",
- __func__);
- return NULL;
- }
- xilspi->regs = (struct xilinx_spi_reg *)xilinx_spi_base_list[bus];
- xilspi->freq = max_hz;
- xilspi->mode = mode;
- debug("%s: bus:%i cs:%i base:%p mode:%x max_hz:%d\n", __func__,
- bus, cs, xilspi->regs, xilspi->mode, xilspi->freq);
+ struct udevice *bus = dev_get_parent(dev);
+ struct xilinx_spi_priv *priv = dev_get_priv(bus);
+ struct xilinx_spi_regs *regs = priv->regs;
- writel(SPISSR_RESET_VALUE, &xilspi->regs->srr);
-
- return &xilspi->slave;
-}
-
-void spi_free_slave(struct spi_slave *slave)
-{
- struct xilinx_spi_slave *xilspi = to_xilinx_spi_slave(slave);
-
- free(xilspi);
+ writel(SPISSR_OFF, &regs->spissr);
}
-int spi_claim_bus(struct spi_slave *slave)
+static int xilinx_spi_claim_bus(struct udevice *dev)
{
- struct xilinx_spi_slave *xilspi = to_xilinx_spi_slave(slave);
- u32 spicr;
+ struct udevice *bus = dev_get_parent(dev);
+ struct xilinx_spi_priv *priv = dev_get_priv(bus);
+ struct xilinx_spi_regs *regs = priv->regs;
- debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs);
- writel(SPISSR_OFF, &xilspi->regs->spissr);
+ writel(SPISSR_OFF, &regs->spissr);
+ writel(XILSPI_SPICR_DFLT_ON, &regs->spicr);
- spicr = XILSPI_SPICR_DFLT_ON;
- if (xilspi->mode & SPI_LSB_FIRST)
- spicr |= SPICR_LSB_FIRST;
- if (xilspi->mode & SPI_CPHA)
- spicr |= SPICR_CPHA;
- if (xilspi->mode & SPI_CPOL)
- spicr |= SPICR_CPOL;
- if (xilspi->mode & SPI_LOOP)
- spicr |= SPICR_LOOP;
-
- writel(spicr, &xilspi->regs->spicr);
return 0;
}
-void spi_release_bus(struct spi_slave *slave)
+static int xilinx_spi_release_bus(struct udevice *dev)
{
- struct xilinx_spi_slave *xilspi = to_xilinx_spi_slave(slave);
+ struct udevice *bus = dev_get_parent(dev);
+ struct xilinx_spi_priv *priv = dev_get_priv(bus);
+ struct xilinx_spi_regs *regs = priv->regs;
+
+ writel(SPISSR_OFF, &regs->spissr);
+ writel(XILSPI_SPICR_DFLT_OFF, &regs->spicr);
- debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs);
- writel(SPISSR_OFF, &xilspi->regs->spissr);
- writel(XILSPI_SPICR_DFLT_OFF, &xilspi->regs->spicr);
+ return 0;
}
-int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
- void *din, unsigned long flags)
+static int xilinx_spi_xfer(struct udevice *dev, unsigned int bitlen,
+ const void *dout, void *din, unsigned long flags)
{
- struct xilinx_spi_slave *xilspi = to_xilinx_spi_slave(slave);
+ struct udevice *bus = dev_get_parent(dev);
+ struct xilinx_spi_priv *priv = dev_get_priv(bus);
+ struct xilinx_spi_regs *regs = priv->regs;
+ struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
/* assume spi core configured to do 8 bit transfers */
unsigned int bytes = bitlen / XILSPI_MAX_XFER_BITS;
const unsigned char *txp = dout;
@@ -151,65 +177,125 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
unsigned rxecount = 17; /* max. 16 elements in FIFO, leftover 1 */
unsigned global_timeout;
- debug("%s: bus:%i cs:%i bitlen:%i bytes:%i flags:%lx\n", __func__,
- slave->bus, slave->cs, bitlen, bytes, flags);
+ debug("spi_xfer: bus:%i cs:%i bitlen:%i bytes:%i flags:%lx\n",
+ bus->seq, slave_plat->cs, bitlen, bytes, flags);
+
if (bitlen == 0)
goto done;
if (bitlen % XILSPI_MAX_XFER_BITS) {
- printf("XILSPI warning: %s: Not a multiple of %d bits\n",
- __func__, XILSPI_MAX_XFER_BITS);
+ printf("XILSPI warning: Not a multiple of %d bits\n",
+ XILSPI_MAX_XFER_BITS);
flags |= SPI_XFER_END;
goto done;
}
/* empty read buffer */
- while (rxecount && !(readl(&xilspi->regs->spisr) & SPISR_RX_EMPTY)) {
- readl(&xilspi->regs->spidrr);
+ while (rxecount && !(readl(&regs->spisr) & SPISR_RX_EMPTY)) {
+ readl(&regs->spidrr);
rxecount--;
}
if (!rxecount) {
- printf("XILSPI error: %s: Rx buffer not empty\n", __func__);
+ printf("XILSPI error: Rx buffer not empty\n");
return -1;
}
if (flags & SPI_XFER_BEGIN)
- spi_cs_activate(slave);
+ spi_cs_activate(dev, slave_plat->cs);
/* at least 1usec or greater, leftover 1 */
- global_timeout = xilspi->freq > XILSPI_MAX_XFER_BITS * 1000000 ? 2 :
- (XILSPI_MAX_XFER_BITS * 1000000 / xilspi->freq) + 1;
+ global_timeout = priv->freq > XILSPI_MAX_XFER_BITS * 1000000 ? 2 :
+ (XILSPI_MAX_XFER_BITS * 1000000 / priv->freq) + 1;
while (bytes--) {
unsigned timeout = global_timeout;
/* get Tx element from data out buffer and count up */
unsigned char d = txp ? *txp++ : CONFIG_XILINX_SPI_IDLE_VAL;
- debug("%s: tx:%x ", __func__, d);
+ debug("spi_xfer: tx:%x ", d);
/* write out and wait for processing (receive data) */
- writel(d & SPIDTR_8BIT_MASK, &xilspi->regs->spidtr);
- while (timeout && readl(&xilspi->regs->spisr)
+ writel(d & SPIDTR_8BIT_MASK, &regs->spidtr);
+ while (timeout && readl(&regs->spisr)
& SPISR_RX_EMPTY) {
timeout--;
udelay(1);
}
if (!timeout) {
- printf("XILSPI error: %s: Xfer timeout\n", __func__);
+ printf("XILSPI error: Xfer timeout\n");
return -1;
}
/* read Rx element and push into data in buffer */
- d = readl(&xilspi->regs->spidrr) & SPIDRR_8BIT_MASK;
+ d = readl(&regs->spidrr) & SPIDRR_8BIT_MASK;
if (rxp)
*rxp++ = d;
- debug("rx:%x\n", d);
+ debug("spi_xfer: rx:%x\n", d);
}
done:
if (flags & SPI_XFER_END)
- spi_cs_deactivate(slave);
+ spi_cs_deactivate(dev);
return 0;
}
+
+static int xilinx_spi_set_speed(struct udevice *bus, uint speed)
+{
+ struct xilinx_spi_priv *priv = dev_get_priv(bus);
+
+ priv->freq = speed;
+
+ debug("xilinx_spi_set_speed: regs=%p, mode=%d\n", priv->regs,
+ priv->freq);
+
+ return 0;
+}
+
+static int xilinx_spi_set_mode(struct udevice *bus, uint mode)
+{
+ struct xilinx_spi_priv *priv = dev_get_priv(bus);
+ struct xilinx_spi_regs *regs = priv->regs;
+ uint32_t spicr;
+
+ spicr = readl(&regs->spicr);
+ if (priv->mode & SPI_LSB_FIRST)
+ spicr |= SPICR_LSB_FIRST;
+ if (priv->mode & SPI_CPHA)
+ spicr |= SPICR_CPHA;
+ if (priv->mode & SPI_CPOL)
+ spicr |= SPICR_CPOL;
+ if (priv->mode & SPI_LOOP)
+ spicr |= SPICR_LOOP;
+
+ writel(spicr, &regs->spicr);
+ priv->mode = mode;
+
+ debug("xilinx_spi_set_mode: regs=%p, mode=%d\n", priv->regs,
+ priv->mode);
+
+ return 0;
+}
+
+static const struct dm_spi_ops xilinx_spi_ops = {
+ .claim_bus = xilinx_spi_claim_bus,
+ .release_bus = xilinx_spi_release_bus,
+ .xfer = xilinx_spi_xfer,
+ .set_speed = xilinx_spi_set_speed,
+ .set_mode = xilinx_spi_set_mode,
+};
+
+static const struct udevice_id xilinx_spi_ids[] = {
+ { .compatible = "xlnx,xilinx-spi" },
+ { }
+};
+
+U_BOOT_DRIVER(xilinx_spi) = {
+ .name = "xilinx_spi",
+ .id = UCLASS_SPI,
+ .of_match = xilinx_spi_ids,
+ .ops = &xilinx_spi_ops,
+ .priv_auto_alloc_size = sizeof(struct xilinx_spi_priv),
+ .probe = xilinx_spi_probe,
+};
diff --git a/drivers/spi/xilinx_spi.h b/drivers/spi/xilinx_spi.h
deleted file mode 100644
index ce7d82c394..0000000000
--- a/drivers/spi/xilinx_spi.h
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Xilinx SPI driver
- *
- * XPS/AXI bus interface
- *
- * based on bfin_spi.c, by way of altera_spi.c
- * Copyright (c) 2005-2008 Analog Devices Inc.
- * Copyright (c) 2010 Thomas Chou <thomas@wytron.com.tw>
- * Copyright (c) 2010 Graeme Smecher <graeme.smecher@mail.mcgill.ca>
- * Copyright (c) 2012 Stephan Linz <linz@li-pro.net>
- *
- * SPDX-License-Identifier: GPL-2.0+
- *
- * [0]: http://www.xilinx.com/support/documentation
- *
- * [S]: [0]/ip_documentation/xps_spi.pdf
- * [0]/ip_documentation/axi_spi_ds742.pdf
- */
-#ifndef _XILINX_SPI_
-#define _XILINX_SPI_
-
-#include <asm/types.h>
-#include <asm/io.h>
-
-/*
- * Xilinx SPI Register Definition
- *
- * [1]: [0]/ip_documentation/xps_spi.pdf
- * page 8, Register Descriptions
- * [2]: [0]/ip_documentation/axi_spi_ds742.pdf
- * page 7, Register Overview Table
- */
-struct xilinx_spi_reg {
- u32 __space0__[7];
- u32 dgier; /* Device Global Interrupt Enable Register (DGIER) */
- u32 ipisr; /* IP Interrupt Status Register (IPISR) */
- u32 __space1__;
- u32 ipier; /* IP Interrupt Enable Register (IPIER) */
- u32 __space2__[5];
- u32 srr; /* Softare Reset Register (SRR) */
- u32 __space3__[7];
- u32 spicr; /* SPI Control Register (SPICR) */
- u32 spisr; /* SPI Status Register (SPISR) */
- u32 spidtr; /* SPI Data Transmit Register (SPIDTR) */
- u32 spidrr; /* SPI Data Receive Register (SPIDRR) */
- u32 spissr; /* SPI Slave Select Register (SPISSR) */
- u32 spitfor; /* SPI Transmit FIFO Occupancy Register (SPITFOR) */
- u32 spirfor; /* SPI Receive FIFO Occupancy Register (SPIRFOR) */
-};
-
-/* Device Global Interrupt Enable Register (dgier), [1] p15, [2] p15 */
-#define DGIER_GIE (1 << 31)
-
-/* IP Interrupt Status Register (ipisr), [1] p15, [2] p15 */
-#define IPISR_DRR_NOT_EMPTY (1 << 8)
-#define IPISR_SLAVE_SELECT (1 << 7)
-#define IPISR_TXF_HALF_EMPTY (1 << 6)
-#define IPISR_DRR_OVERRUN (1 << 5)
-#define IPISR_DRR_FULL (1 << 4)
-#define IPISR_DTR_UNDERRUN (1 << 3)
-#define IPISR_DTR_EMPTY (1 << 2)
-#define IPISR_SLAVE_MODF (1 << 1)
-#define IPISR_MODF (1 << 0)
-
-/* IP Interrupt Enable Register (ipier), [1] p17, [2] p18 */
-#define IPIER_DRR_NOT_EMPTY (1 << 8)
-#define IPIER_SLAVE_SELECT (1 << 7)
-#define IPIER_TXF_HALF_EMPTY (1 << 6)
-#define IPIER_DRR_OVERRUN (1 << 5)
-#define IPIER_DRR_FULL (1 << 4)
-#define IPIER_DTR_UNDERRUN (1 << 3)
-#define IPIER_DTR_EMPTY (1 << 2)
-#define IPIER_SLAVE_MODF (1 << 1)
-#define IPIER_MODF (1 << 0)
-
-/* Softare Reset Register (srr), [1] p9, [2] p8 */
-#define SRR_RESET_CODE 0x0000000A
-
-/* SPI Control Register (spicr), [1] p9, [2] p8 */
-#define SPICR_LSB_FIRST (1 << 9)
-#define SPICR_MASTER_INHIBIT (1 << 8)
-#define SPICR_MANUAL_SS (1 << 7)
-#define SPICR_RXFIFO_RESEST (1 << 6)
-#define SPICR_TXFIFO_RESEST (1 << 5)
-#define SPICR_CPHA (1 << 4)
-#define SPICR_CPOL (1 << 3)
-#define SPICR_MASTER_MODE (1 << 2)
-#define SPICR_SPE (1 << 1)
-#define SPICR_LOOP (1 << 0)
-
-/* SPI Status Register (spisr), [1] p11, [2] p10 */
-#define SPISR_SLAVE_MODE_SELECT (1 << 5)
-#define SPISR_MODF (1 << 4)
-#define SPISR_TX_FULL (1 << 3)
-#define SPISR_TX_EMPTY (1 << 2)
-#define SPISR_RX_FULL (1 << 1)
-#define SPISR_RX_EMPTY (1 << 0)
-
-/* SPI Data Transmit Register (spidtr), [1] p12, [2] p12 */
-#define SPIDTR_8BIT_MASK (0xff << 0)
-#define SPIDTR_16BIT_MASK (0xffff << 0)
-#define SPIDTR_32BIT_MASK (0xffffffff << 0)
-
-/* SPI Data Receive Register (spidrr), [1] p12, [2] p12 */
-#define SPIDRR_8BIT_MASK (0xff << 0)
-#define SPIDRR_16BIT_MASK (0xffff << 0)
-#define SPIDRR_32BIT_MASK (0xffffffff << 0)
-
-/* SPI Slave Select Register (spissr), [1] p13, [2] p13 */
-#define SPISSR_MASK(cs) (1 << (cs))
-#define SPISSR_ACT(cs) ~SPISSR_MASK(cs)
-#define SPISSR_OFF ~0UL
-
-/* SPI Transmit FIFO Occupancy Register (spitfor), [1] p13, [2] p14 */
-#define SPITFOR_OCYVAL_POS 0
-#define SPITFOR_OCYVAL_MASK (0xf << SPITFOR_OCYVAL_POS)
-
-/* SPI Receive FIFO Occupancy Register (spirfor), [1] p14, [2] p14 */
-#define SPIRFOR_OCYVAL_POS 0
-#define SPIRFOR_OCYVAL_MASK (0xf << SPIRFOR_OCYVAL_POS)
-
-/* SPI Software Reset Register (ssr) */
-#define SPISSR_RESET_VALUE 0x0a
-
-struct xilinx_spi_slave {
- struct spi_slave slave;
- struct xilinx_spi_reg *regs;
- unsigned int freq;
- unsigned int mode;
-};
-
-static inline struct xilinx_spi_slave *to_xilinx_spi_slave(
- struct spi_slave *slave)
-{
- return container_of(slave, struct xilinx_spi_slave, slave);
-}
-
-#endif /* _XILINX_SPI_ */
diff --git a/drivers/spi/zynq_spi.c b/drivers/spi/zynq_spi.c
index e9129da79d..c5c3e1044f 100644
--- a/drivers/spi/zynq_spi.c
+++ b/drivers/spi/zynq_spi.c
@@ -1,5 +1,6 @@
/*
* (C) Copyright 2013 Inc.
+ * (C) Copyright 2015 Jagan Teki <jteki@openedev.com>
*
* Xilinx Zynq PS SPI controller driver (master mode only)
*
@@ -8,11 +9,16 @@
#include <config.h>
#include <common.h>
+#include <dm.h>
+#include <errno.h>
#include <malloc.h>
#include <spi.h>
+#include <fdtdec.h>
#include <asm/io.h>
#include <asm/arch/hardware.h>
+DECLARE_GLOBAL_DATA_PTR;
+
/* zynq spi register bit masks ZYNQ_SPI_<REG>_<BIT>_MASK */
#define ZYNQ_SPI_CR_MSA_MASK (1 << 15) /* Manual start enb */
#define ZYNQ_SPI_CR_MCS_MASK (1 << 14) /* Manual chip select */
@@ -44,180 +50,141 @@ struct zynq_spi_regs {
u32 rxdr; /* 0x20 */
};
-/* zynq spi slave */
-struct zynq_spi_slave {
- struct spi_slave slave;
- struct zynq_spi_regs *base;
+
+/* zynq spi platform data */
+struct zynq_spi_platdata {
+ struct zynq_spi_regs *regs;
+ u32 frequency; /* input frequency */
+ u32 speed_hz;
+};
+
+/* zynq spi priv */
+struct zynq_spi_priv {
+ struct zynq_spi_regs *regs;
u8 mode;
u8 fifo_depth;
- u32 speed_hz;
- u32 input_hz;
- u32 req_hz;
+ u32 freq; /* required frequency */
};
-static inline struct zynq_spi_slave *to_zynq_spi_slave(struct spi_slave *slave)
+static int zynq_spi_ofdata_to_platdata(struct udevice *bus)
{
- return container_of(slave, struct zynq_spi_slave, slave);
-}
+ struct zynq_spi_platdata *plat = bus->platdata;
+ const void *blob = gd->fdt_blob;
+ int node = bus->of_offset;
-static inline struct zynq_spi_regs *get_zynq_spi_base(int dev)
-{
- if (dev)
- return (struct zynq_spi_regs *)ZYNQ_SPI_BASEADDR1;
- else
- return (struct zynq_spi_regs *)ZYNQ_SPI_BASEADDR0;
+ plat->regs = (struct zynq_spi_regs *)fdtdec_get_addr(blob, node, "reg");
+
+ /* FIXME: Use 250MHz as a suitable default */
+ plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency",
+ 250000000);
+ plat->speed_hz = plat->frequency / 2;
+
+ debug("zynq_spi_ofdata_to_platdata: regs=%p max-frequency=%d\n",
+ plat->regs, plat->frequency);
+
+ return 0;
}
-static void zynq_spi_init_hw(struct zynq_spi_slave *zslave)
+static void zynq_spi_init_hw(struct zynq_spi_priv *priv)
{
+ struct zynq_spi_regs *regs = priv->regs;
u32 confr;
/* Disable SPI */
- writel(~ZYNQ_SPI_ENR_SPI_EN_MASK, &zslave->base->enr);
+ writel(~ZYNQ_SPI_ENR_SPI_EN_MASK, &regs->enr);
/* Disable Interrupts */
- writel(ZYNQ_SPI_IXR_ALL_MASK, &zslave->base->idr);
+ writel(ZYNQ_SPI_IXR_ALL_MASK, &regs->idr);
/* Clear RX FIFO */
- while (readl(&zslave->base->isr) &
+ while (readl(&regs->isr) &
ZYNQ_SPI_IXR_RXNEMPTY_MASK)
- readl(&zslave->base->rxdr);
+ readl(&regs->rxdr);
/* Clear Interrupts */
- writel(ZYNQ_SPI_IXR_ALL_MASK, &zslave->base->isr);
+ writel(ZYNQ_SPI_IXR_ALL_MASK, &regs->isr);
/* Manual slave select and Auto start */
confr = ZYNQ_SPI_CR_MCS_MASK | ZYNQ_SPI_CR_CS_MASK |
ZYNQ_SPI_CR_MSTREN_MASK;
confr &= ~ZYNQ_SPI_CR_MSA_MASK;
- writel(confr, &zslave->base->cr);
+ writel(confr, &regs->cr);
/* Enable SPI */
- writel(ZYNQ_SPI_ENR_SPI_EN_MASK, &zslave->base->enr);
+ writel(ZYNQ_SPI_ENR_SPI_EN_MASK, &regs->enr);
}
-int spi_cs_is_valid(unsigned int bus, unsigned int cs)
+static int zynq_spi_probe(struct udevice *bus)
{
- /* 2 bus with 3 chipselect */
- return bus < 2 && cs < 3;
+ struct zynq_spi_platdata *plat = dev_get_platdata(bus);
+ struct zynq_spi_priv *priv = dev_get_priv(bus);
+
+ priv->regs = plat->regs;
+ priv->fifo_depth = ZYNQ_SPI_FIFO_DEPTH;
+
+ /* init the zynq spi hw */
+ zynq_spi_init_hw(priv);
+
+ return 0;
}
-void spi_cs_activate(struct spi_slave *slave)
+static void spi_cs_activate(struct udevice *dev, uint cs)
{
- struct zynq_spi_slave *zslave = to_zynq_spi_slave(slave);
+ struct udevice *bus = dev->parent;
+ struct zynq_spi_priv *priv = dev_get_priv(bus);
+ struct zynq_spi_regs *regs = priv->regs;
u32 cr;
- debug("spi_cs_activate: 0x%08x\n", (u32)slave);
-
- clrbits_le32(&zslave->base->cr, ZYNQ_SPI_CR_CS_MASK);
- cr = readl(&zslave->base->cr);
+ clrbits_le32(&regs->cr, ZYNQ_SPI_CR_CS_MASK);
+ cr = readl(&regs->cr);
/*
* CS cal logic: CS[13:10]
* xxx0 - cs0
* xx01 - cs1
* x011 - cs2
*/
- cr |= (~(0x1 << slave->cs) << 10) & ZYNQ_SPI_CR_CS_MASK;
- writel(cr, &zslave->base->cr);
+ cr |= (~(0x1 << cs) << 10) & ZYNQ_SPI_CR_CS_MASK;
+ writel(cr, &regs->cr);
}
-void spi_cs_deactivate(struct spi_slave *slave)
+static void spi_cs_deactivate(struct udevice *dev)
{
- struct zynq_spi_slave *zslave = to_zynq_spi_slave(slave);
-
- debug("spi_cs_deactivate: 0x%08x\n", (u32)slave);
+ struct udevice *bus = dev->parent;
+ struct zynq_spi_priv *priv = dev_get_priv(bus);
+ struct zynq_spi_regs *regs = priv->regs;
- setbits_le32(&zslave->base->cr, ZYNQ_SPI_CR_CS_MASK);
-}
-
-void spi_init()
-{
- /* nothing to do */
+ setbits_le32(&regs->cr, ZYNQ_SPI_CR_CS_MASK);
}
-struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
- unsigned int max_hz, unsigned int mode)
+static int zynq_spi_claim_bus(struct udevice *dev)
{
- struct zynq_spi_slave *zslave;
+ struct udevice *bus = dev->parent;
+ struct zynq_spi_priv *priv = dev_get_priv(bus);
+ struct zynq_spi_regs *regs = priv->regs;
- if (!spi_cs_is_valid(bus, cs))
- return NULL;
+ writel(ZYNQ_SPI_ENR_SPI_EN_MASK, &regs->enr);
- zslave = spi_alloc_slave(struct zynq_spi_slave, bus, cs);
- if (!zslave) {
- printf("SPI_error: Fail to allocate zynq_spi_slave\n");
- return NULL;
- }
-
- zslave->base = get_zynq_spi_base(bus);
- zslave->mode = mode;
- zslave->fifo_depth = ZYNQ_SPI_FIFO_DEPTH;
- zslave->input_hz = 166666700;
- zslave->speed_hz = zslave->input_hz / 2;
- zslave->req_hz = max_hz;
-
- /* init the zynq spi hw */
- zynq_spi_init_hw(zslave);
-
- return &zslave->slave;
-}
-
-void spi_free_slave(struct spi_slave *slave)
-{
- struct zynq_spi_slave *zslave = to_zynq_spi_slave(slave);
-
- debug("spi_free_slave: 0x%08x\n", (u32)slave);
- free(zslave);
+ return 0;
}
-int spi_claim_bus(struct spi_slave *slave)
+static int zynq_spi_release_bus(struct udevice *dev)
{
- struct zynq_spi_slave *zslave = to_zynq_spi_slave(slave);
- u32 confr = 0;
- u8 baud_rate_val = 0;
+ struct udevice *bus = dev->parent;
+ struct zynq_spi_priv *priv = dev_get_priv(bus);
+ struct zynq_spi_regs *regs = priv->regs;
- writel(~ZYNQ_SPI_ENR_SPI_EN_MASK, &zslave->base->enr);
-
- /* Set the SPI Clock phase and polarities */
- confr = readl(&zslave->base->cr);
- confr &= ~(ZYNQ_SPI_CR_CPHA_MASK | ZYNQ_SPI_CR_CPOL_MASK);
- if (zslave->mode & SPI_CPHA)
- confr |= ZYNQ_SPI_CR_CPHA_MASK;
- if (zslave->mode & SPI_CPOL)
- confr |= ZYNQ_SPI_CR_CPOL_MASK;
-
- /* Set the clock frequency */
- if (zslave->req_hz == 0) {
- /* Set baudrate x8, if the req_hz is 0 */
- baud_rate_val = 0x2;
- } else if (zslave->speed_hz != zslave->req_hz) {
- while ((baud_rate_val < 8) &&
- ((zslave->input_hz /
- (2 << baud_rate_val)) > zslave->req_hz))
- baud_rate_val++;
- zslave->speed_hz = zslave->req_hz / (2 << baud_rate_val);
- }
- confr &= ~ZYNQ_SPI_CR_BRD_MASK;
- confr |= (baud_rate_val << 3);
- writel(confr, &zslave->base->cr);
-
- writel(ZYNQ_SPI_ENR_SPI_EN_MASK, &zslave->base->enr);
+ writel(~ZYNQ_SPI_ENR_SPI_EN_MASK, &regs->enr);
return 0;
}
-void spi_release_bus(struct spi_slave *slave)
+static int zynq_spi_xfer(struct udevice *dev, unsigned int bitlen,
+ const void *dout, void *din, unsigned long flags)
{
- struct zynq_spi_slave *zslave = to_zynq_spi_slave(slave);
-
- debug("spi_release_bus: 0x%08x\n", (u32)slave);
- writel(~ZYNQ_SPI_ENR_SPI_EN_MASK, &zslave->base->enr);
-}
-
-int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
- void *din, unsigned long flags)
-{
- struct zynq_spi_slave *zslave = to_zynq_spi_slave(slave);
+ struct udevice *bus = dev->parent;
+ struct zynq_spi_priv *priv = dev_get_priv(bus);
+ struct zynq_spi_regs *regs = priv->regs;
+ struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
u32 len = bitlen / 8;
u32 tx_len = len, rx_len = len, tx_tvl;
const u8 *tx_buf = dout;
@@ -225,7 +192,7 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
u32 ts, status;
debug("spi_xfer: bus:%i cs:%i bitlen:%i len:%i flags:%lx\n",
- slave->bus, slave->cs, bitlen, len, flags);
+ bus->seq, slave_plat->cs, bitlen, len, flags);
if (bitlen % 8) {
debug("spi_xfer: Non byte aligned SPI transfer\n");
@@ -233,45 +200,126 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
}
if (flags & SPI_XFER_BEGIN)
- spi_cs_activate(slave);
+ spi_cs_activate(dev, slave_plat->cs);
while (rx_len > 0) {
/* Write the data into TX FIFO - tx threshold is fifo_depth */
tx_tvl = 0;
- while ((tx_tvl < zslave->fifo_depth) && tx_len) {
+ while ((tx_tvl < priv->fifo_depth) && tx_len) {
if (tx_buf)
buf = *tx_buf++;
else
buf = 0;
- writel(buf, &zslave->base->txdr);
+ writel(buf, &regs->txdr);
tx_len--;
tx_tvl++;
}
/* Check TX FIFO completion */
ts = get_timer(0);
- status = readl(&zslave->base->isr);
+ status = readl(&regs->isr);
while (!(status & ZYNQ_SPI_IXR_TXOW_MASK)) {
if (get_timer(ts) > CONFIG_SYS_ZYNQ_SPI_WAIT) {
printf("spi_xfer: Timeout! TX FIFO not full\n");
return -1;
}
- status = readl(&zslave->base->isr);
+ status = readl(&regs->isr);
}
/* Read the data from RX FIFO */
- status = readl(&zslave->base->isr);
+ status = readl(&regs->isr);
while (status & ZYNQ_SPI_IXR_RXNEMPTY_MASK) {
- buf = readl(&zslave->base->rxdr);
+ buf = readl(&regs->rxdr);
if (rx_buf)
*rx_buf++ = buf;
- status = readl(&zslave->base->isr);
+ status = readl(&regs->isr);
rx_len--;
}
}
if (flags & SPI_XFER_END)
- spi_cs_deactivate(slave);
+ spi_cs_deactivate(dev);
return 0;
}
+
+static int zynq_spi_set_speed(struct udevice *bus, uint speed)
+{
+ struct zynq_spi_platdata *plat = bus->platdata;
+ struct zynq_spi_priv *priv = dev_get_priv(bus);
+ struct zynq_spi_regs *regs = priv->regs;
+ uint32_t confr;
+ u8 baud_rate_val = 0;
+
+ if (speed > plat->frequency)
+ speed = plat->frequency;
+
+ /* Set the clock frequency */
+ confr = readl(&regs->cr);
+ if (speed == 0) {
+ /* Set baudrate x8, if the freq is 0 */
+ baud_rate_val = 0x2;
+ } else if (plat->speed_hz != speed) {
+ while ((baud_rate_val < 8) &&
+ ((plat->frequency /
+ (2 << baud_rate_val)) > speed))
+ baud_rate_val++;
+ plat->speed_hz = speed / (2 << baud_rate_val);
+ }
+ confr &= ~ZYNQ_SPI_CR_BRD_MASK;
+ confr |= (baud_rate_val << 3);
+
+ writel(confr, &regs->cr);
+ priv->freq = speed;
+
+ debug("zynq_spi_set_speed: regs=%p, mode=%d\n", priv->regs, priv->freq);
+
+ return 0;
+}
+
+static int zynq_spi_set_mode(struct udevice *bus, uint mode)
+{
+ struct zynq_spi_priv *priv = dev_get_priv(bus);
+ struct zynq_spi_regs *regs = priv->regs;
+ uint32_t confr;
+
+ /* Set the SPI Clock phase and polarities */
+ confr = readl(&regs->cr);
+ confr &= ~(ZYNQ_SPI_CR_CPHA_MASK | ZYNQ_SPI_CR_CPOL_MASK);
+
+ if (priv->mode & SPI_CPHA)
+ confr |= ZYNQ_SPI_CR_CPHA_MASK;
+ if (priv->mode & SPI_CPOL)
+ confr |= ZYNQ_SPI_CR_CPOL_MASK;
+
+ writel(confr, &regs->cr);
+ priv->mode = mode;
+
+ debug("zynq_spi_set_mode: regs=%p, mode=%d\n", priv->regs, priv->mode);
+
+ return 0;
+}
+
+static const struct dm_spi_ops zynq_spi_ops = {
+ .claim_bus = zynq_spi_claim_bus,
+ .release_bus = zynq_spi_release_bus,
+ .xfer = zynq_spi_xfer,
+ .set_speed = zynq_spi_set_speed,
+ .set_mode = zynq_spi_set_mode,
+};
+
+static const struct udevice_id zynq_spi_ids[] = {
+ { .compatible = "xlnx,zynq-spi" },
+ { }
+};
+
+U_BOOT_DRIVER(zynq_spi) = {
+ .name = "zynq_spi",
+ .id = UCLASS_SPI,
+ .of_match = zynq_spi_ids,
+ .ops = &zynq_spi_ops,
+ .ofdata_to_platdata = zynq_spi_ofdata_to_platdata,
+ .platdata_auto_alloc_size = sizeof(struct zynq_spi_platdata),
+ .priv_auto_alloc_size = sizeof(struct zynq_spi_priv),
+ .probe = zynq_spi_probe,
+};
diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
index e455a5279c..02bb216db7 100644
--- a/drivers/usb/dwc3/Makefile
+++ b/drivers/usb/dwc3/Makefile
@@ -6,3 +6,4 @@ dwc3-y += gadget.o ep0.o
obj-$(CONFIG_USB_DWC3_OMAP) += dwc3-omap.o
obj-$(CONFIG_USB_DWC3_PHY_OMAP) += ti_usb_phy.o
+obj-$(CONFIG_USB_DWC3_PHY_SAMSUNG) += samsung_usb_phy.o
diff --git a/drivers/usb/dwc3/samsung_usb_phy.c b/drivers/usb/dwc3/samsung_usb_phy.c
new file mode 100644
index 0000000000..4220986548
--- /dev/null
+++ b/drivers/usb/dwc3/samsung_usb_phy.c
@@ -0,0 +1,78 @@
+/**
+ * samsung_usb_phy.c - DesignWare USB3 (DWC3) PHY handling file
+ *
+ * Copyright (C) 2015 Samsung Electronics
+ *
+ * Author: Joonyoung Shim <jy0922.shim@samsung.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <asm/arch/power.h>
+#include <asm/arch/xhci-exynos.h>
+
+void exynos5_usb3_phy_init(struct exynos_usb3_phy *phy)
+{
+ u32 reg;
+
+ /* Reset USB 3.0 PHY */
+ writel(0x0, &phy->phy_reg0);
+
+ clrbits_le32(&phy->phy_param0,
+ /* Select PHY CLK source */
+ PHYPARAM0_REF_USE_PAD |
+ /* Set Loss-of-Signal Detector sensitivity */
+ PHYPARAM0_REF_LOSLEVEL_MASK);
+ setbits_le32(&phy->phy_param0, PHYPARAM0_REF_LOSLEVEL);
+
+
+ writel(0x0, &phy->phy_resume);
+
+ /*
+ * Setting the Frame length Adj value[6:1] to default 0x20
+ * See xHCI 1.0 spec, 5.2.4
+ */
+ setbits_le32(&phy->link_system,
+ LINKSYSTEM_XHCI_VERSION_CONTROL |
+ LINKSYSTEM_FLADJ(0x20));
+
+ /* Set Tx De-Emphasis level */
+ clrbits_le32(&phy->phy_param1, PHYPARAM1_PCS_TXDEEMPH_MASK);
+ setbits_le32(&phy->phy_param1, PHYPARAM1_PCS_TXDEEMPH);
+
+ setbits_le32(&phy->phy_batchg, PHYBATCHG_UTMI_CLKSEL);
+
+ /* PHYTEST POWERDOWN Control */
+ clrbits_le32(&phy->phy_test,
+ PHYTEST_POWERDOWN_SSP |
+ PHYTEST_POWERDOWN_HSP);
+
+ /* UTMI Power Control */
+ writel(PHYUTMI_OTGDISABLE, &phy->phy_utmi);
+
+ /* Use core clock from main PLL */
+ reg = PHYCLKRST_REFCLKSEL_EXT_REFCLK |
+ /* Default 24Mhz crystal clock */
+ PHYCLKRST_FSEL(FSEL_CLKSEL_24M) |
+ PHYCLKRST_MPLL_MULTIPLIER_24MHZ_REF |
+ PHYCLKRST_SSC_REFCLKSEL(0) |
+ /* Force PortReset of PHY */
+ PHYCLKRST_PORTRESET |
+ /* Digital power supply in normal operating mode */
+ PHYCLKRST_RETENABLEN |
+ /* Enable ref clock for SS function */
+ PHYCLKRST_REF_SSP_EN |
+ /* Enable spread spectrum */
+ PHYCLKRST_SSC_EN |
+ /* Power down HS Bias and PLL blocks in suspend mode */
+ PHYCLKRST_COMMONONN;
+
+ writel(reg, &phy->phy_clk_rst);
+
+ /* giving time to Phy clock to settle before resetting */
+ udelay(10);
+
+ reg &= ~PHYCLKRST_PORTRESET;
+ writel(reg, &phy->phy_clk_rst);
+}
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index d1bc5efa9b..abe9391d3d 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -671,7 +671,7 @@ static int sleep_thread(struct fsg_common *common)
if (common->thread_wakeup_needed)
break;
- if (++i == 50000) {
+ if (++i == 20000) {
busy_indicator();
i = 0;
k++;
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index 5fd618df87..97b7f14542 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -76,7 +76,7 @@ int ehci_hcd_init(int index, enum usb_init_type init,
break;
default:
printf("ERROR: wrong controller index!!\n");
- break;
+ return -EINVAL;
};
*hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength);
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 1e5a6e2b20..bf02221c9f 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1214,6 +1214,7 @@ static int _ehci_submit_control_msg(struct usb_device *dev, unsigned long pipe,
struct int_queue {
int elementsize;
+ unsigned long pipe;
struct QH *first;
struct QH *current;
struct QH *last;
@@ -1269,7 +1270,7 @@ static struct int_queue *_ehci_create_int_queue(struct usb_device *dev,
{
struct ehci_ctrl *ctrl = ehci_get_ctrl(dev);
struct int_queue *result = NULL;
- int i;
+ uint32_t i, toggle;
/*
* Interrupt transfers requiring several transactions are not supported
@@ -1309,6 +1310,7 @@ static struct int_queue *_ehci_create_int_queue(struct usb_device *dev,
goto fail1;
}
result->elementsize = elementsize;
+ result->pipe = pipe;
result->first = memalign(USB_DMA_MINALIGN,
sizeof(struct QH) * queuesize);
if (!result->first) {
@@ -1326,6 +1328,8 @@ static struct int_queue *_ehci_create_int_queue(struct usb_device *dev,
memset(result->first, 0, sizeof(struct QH) * queuesize);
memset(result->tds, 0, sizeof(struct qTD) * queuesize);
+ toggle = usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
+
for (i = 0; i < queuesize; i++) {
struct QH *qh = result->first + i;
struct qTD *td = result->tds + i;
@@ -1357,7 +1361,9 @@ static struct int_queue *_ehci_create_int_queue(struct usb_device *dev,
td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
debug("communication direction is '%s'\n",
usb_pipein(pipe) ? "in" : "out");
- td->qt_token = cpu_to_hc32((elementsize << 16) |
+ td->qt_token = cpu_to_hc32(
+ QT_TOKEN_DT(toggle) |
+ (elementsize << 16) |
((usb_pipein(pipe) ? 1 : 0) << 8) | /* IN/OUT token */
0x80); /* active */
td->qt_buffer[0] =
@@ -1372,6 +1378,7 @@ static struct int_queue *_ehci_create_int_queue(struct usb_device *dev,
cpu_to_hc32((td->qt_buffer[0] + 0x4000) & ~0xfff);
*buf = buffer + i * elementsize;
+ toggle ^= 1;
}
flush_dcache_range((unsigned long)buffer,
@@ -1426,6 +1433,8 @@ static void *_ehci_poll_int_queue(struct usb_device *dev,
{
struct QH *cur = queue->current;
struct qTD *cur_td;
+ uint32_t token, toggle;
+ unsigned long pipe = queue->pipe;
/* depleted queue */
if (cur == NULL) {
@@ -1436,12 +1445,15 @@ static void *_ehci_poll_int_queue(struct usb_device *dev,
cur_td = &queue->tds[queue->current - queue->first];
invalidate_dcache_range((unsigned long)cur_td,
ALIGN_END_ADDR(struct qTD, cur_td, 1));
- if (QT_TOKEN_GET_STATUS(hc32_to_cpu(cur_td->qt_token)) &
- QT_TOKEN_STATUS_ACTIVE) {
- debug("Exit poll_int_queue with no completed intr transfer. token is %x\n",
- hc32_to_cpu(cur_td->qt_token));
+ token = hc32_to_cpu(cur_td->qt_token);
+ if (QT_TOKEN_GET_STATUS(token) & QT_TOKEN_STATUS_ACTIVE) {
+ debug("Exit poll_int_queue with no completed intr transfer. token is %x\n", token);
return NULL;
}
+
+ toggle = QT_TOKEN_GET_DT(token);
+ usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), toggle);
+
if (!(cur->qh_link & QH_LINK_TERMINATE))
queue->current++;
else
@@ -1452,7 +1464,7 @@ static void *_ehci_poll_int_queue(struct usb_device *dev,
queue->elementsize));
debug("Exit poll_int_queue with completed intr transfer. token is %x at %p (first at %p)\n",
- hc32_to_cpu(cur_td->qt_token), cur, queue->first);
+ token, cur, queue->first);
return cur->buffer;
}
diff --git a/drivers/usb/musb-new/sunxi.c b/drivers/usb/musb-new/sunxi.c
index e8a3a23aa4..052e0657d0 100644
--- a/drivers/usb/musb-new/sunxi.c
+++ b/drivers/usb/musb-new/sunxi.c
@@ -105,16 +105,6 @@ static void USBC_EnableIdPullUp(__iomem void *base)
musb_writel(base, USBC_REG_o_ISCR, reg_val);
}
-static void USBC_DisableIdPullUp(__iomem void *base)
-{
- u32 reg_val;
-
- reg_val = musb_readl(base, USBC_REG_o_ISCR);
- reg_val &= ~(1 << USBC_BP_ISCR_ID_PULLUP_EN);
- reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
- musb_writel(base, USBC_REG_o_ISCR, reg_val);
-}
-
static void USBC_EnableDpDmPullUp(__iomem void *base)
{
u32 reg_val;
@@ -125,34 +115,35 @@ static void USBC_EnableDpDmPullUp(__iomem void *base)
musb_writel(base, USBC_REG_o_ISCR, reg_val);
}
-static void USBC_DisableDpDmPullUp(__iomem void *base)
+static void USBC_ForceIdToLow(__iomem void *base)
{
u32 reg_val;
reg_val = musb_readl(base, USBC_REG_o_ISCR);
- reg_val &= ~(1 << USBC_BP_ISCR_DPDM_PULLUP_EN);
+ reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_ID);
+ reg_val |= (0x02 << USBC_BP_ISCR_FORCE_ID);
reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
musb_writel(base, USBC_REG_o_ISCR, reg_val);
}
-static void USBC_ForceIdToLow(__iomem void *base)
+static void USBC_ForceIdToHigh(__iomem void *base)
{
u32 reg_val;
reg_val = musb_readl(base, USBC_REG_o_ISCR);
reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_ID);
- reg_val |= (0x02 << USBC_BP_ISCR_FORCE_ID);
+ reg_val |= (0x03 << USBC_BP_ISCR_FORCE_ID);
reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
musb_writel(base, USBC_REG_o_ISCR, reg_val);
}
-static void USBC_ForceIdToHigh(__iomem void *base)
+static void USBC_ForceVbusValidToLow(__iomem void *base)
{
u32 reg_val;
reg_val = musb_readl(base, USBC_REG_o_ISCR);
- reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_ID);
- reg_val |= (0x03 << USBC_BP_ISCR_FORCE_ID);
+ reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_VBUS_VALID);
+ reg_val |= (0x02 << USBC_BP_ISCR_FORCE_VBUS_VALID);
reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
musb_writel(base, USBC_REG_o_ISCR, reg_val);
}
@@ -205,42 +196,41 @@ static irqreturn_t sunxi_musb_interrupt(int irq, void *__hci)
return retval;
}
+/* musb_core does not call enable / disable in a balanced manner <sigh> */
+static bool enabled = false;
+
static void sunxi_musb_enable(struct musb *musb)
{
pr_debug("%s():\n", __func__);
+ if (enabled)
+ return;
+
/* select PIO mode */
musb_writeb(musb->mregs, USBC_REG_o_VEND0, 0);
- if (is_host_enabled(musb)) {
- /* port power on */
- sunxi_usb_phy_power_on(0);
- }
+ if (is_host_enabled(musb))
+ sunxi_usb_phy_power_on(0); /* port power on */
+
+ USBC_ForceVbusValidToHigh(musb->mregs);
+
+ enabled = true;
}
static void sunxi_musb_disable(struct musb *musb)
{
- struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
-
pr_debug("%s():\n", __func__);
- /* Put the controller back in a pristane state for "usb reset" */
- if (musb->is_active) {
- sunxi_usb_phy_exit(0);
-#ifdef CONFIG_SUNXI_GEN_SUN6I
- clrbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_GATE_OFFSET_USB0);
-#endif
- clrbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_USB0);
+ if (!enabled)
+ return;
- mdelay(10);
+ if (is_host_enabled(musb))
+ sunxi_usb_phy_power_off(0); /* port power off */
- setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_USB0);
-#ifdef CONFIG_SUNXI_GEN_SUN6I
- setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_GATE_OFFSET_USB0);
-#endif
- sunxi_usb_phy_init(0);
- musb->is_active = 0;
- }
+ USBC_ForceVbusValidToLow(musb->mregs);
+ mdelay(200); /* Wait for the current session to timeout */
+
+ enabled = false;
}
static int sunxi_musb_init(struct musb *musb)
@@ -282,22 +272,8 @@ static int sunxi_musb_init(struct musb *musb)
return 0;
}
-static int sunxi_musb_exit(struct musb *musb)
-{
- pr_debug("%s():\n", __func__);
-
- USBC_DisableDpDmPullUp(musb->mregs);
- USBC_DisableIdPullUp(musb->mregs);
- sunxi_usb_phy_power_off(0);
- sunxi_usb_phy_exit(0);
-
- return 0;
-}
-
const struct musb_platform_ops sunxi_musb_ops = {
.init = sunxi_musb_init,
- .exit = sunxi_musb_exit,
-
.enable = sunxi_musb_enable,
.disable = sunxi_musb_disable,
};
OpenPOWER on IntegriCloud