[U-Boot] [PATCH 18/18] sf: add driver for Atmel QSPI controller

Cyrille Pitchen cyrille.pitchen at atmel.com
Tue Mar 15 19:12:40 CET 2016


This patch adds support of the Atmel QSPI controller.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
---
 drivers/mtd/spi/Makefile           |   1 +
 drivers/mtd/spi/atmel_qspi_flash.c | 432 +++++++++++++++++++++++++++++++++++++
 drivers/spi/Kconfig                |   9 +
 drivers/spi/Makefile               |   1 +
 drivers/spi/atmel_qspi.c           | 150 +++++++++++++
 drivers/spi/atmel_qspi.h           | 145 +++++++++++++
 6 files changed, 738 insertions(+)
 create mode 100644 drivers/mtd/spi/atmel_qspi_flash.c
 create mode 100644 drivers/spi/atmel_qspi.c
 create mode 100644 drivers/spi/atmel_qspi.h

diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile
index 90266d619ddf..207e1d556f3f 100644
--- a/drivers/mtd/spi/Makefile
+++ b/drivers/mtd/spi/Makefile
@@ -17,3 +17,4 @@ obj-$(CONFIG_SPI_FLASH_STMICRO) += sf_micron.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_ATMEL_QSPI) += atmel_qspi_flash.o
diff --git a/drivers/mtd/spi/atmel_qspi_flash.c b/drivers/mtd/spi/atmel_qspi_flash.c
new file mode 100644
index 000000000000..97f85ae2e30c
--- /dev/null
+++ b/drivers/mtd/spi/atmel_qspi_flash.c
@@ -0,0 +1,432 @@
+#include <common.h>
+#include <errno.h>
+#include <spi.h>
+#include <spi_flash.h>
+
+#include "sf_internal.h"
+#include "../../spi/atmel_qspi.h"
+
+struct atmel_qspi_command {
+	union {
+		struct {
+			unsigned int	instruction:1;
+			unsigned int	address:3;
+			unsigned int	mode:1;
+			unsigned int	dummy:1;
+			unsigned int	data:1;
+			unsigned int	reserved:25;
+		}		bits;
+		unsigned int	word;
+	}			enable;
+	unsigned char		instruction;
+	unsigned char		mode;
+	unsigned char		num_mode_cycles;
+	unsigned char		num_dummy_cycles;
+	unsigned int		address;
+
+	size_t			buf_len;
+	const void		*tx_buf;
+	void			*rx_buf;
+
+	enum spi_flash_protocol	protocol;
+	u32			ifr_tfrtype;
+};
+
+
+static void atmel_qspi_memcpy_fromio(void *dst, unsigned long src, size_t len)
+{
+	u8 *d = (u8 *)dst;
+
+	while (len--) {
+		*d++ = readb(src);
+		src++;
+	}
+}
+
+static void atmel_qspi_memcpy_toio(unsigned long dst, const void *src,
+				   size_t len)
+{
+	const u8 *s = (const u8 *)src;
+
+	while (len--) {
+		writeb(*s, dst);
+		dst++;
+		s++;
+	}
+}
+
+static int atmel_qpsi_set_ifr_width(enum spi_flash_protocol proto, u32 *ifr)
+{
+	u32 ifr_width;
+
+	switch (proto) {
+	case SPI_FLASH_PROTO_1_1_1:
+		ifr_width = QSPI_IFR_WIDTH_SINGLE_BIT_SPI;
+		break;
+
+	case SPI_FLASH_PROTO_1_1_2:
+		ifr_width = QSPI_IFR_WIDTH_DUAL_OUTPUT;
+		break;
+
+	case SPI_FLASH_PROTO_1_2_2:
+		ifr_width = QSPI_IFR_WIDTH_DUAL_IO;
+		break;
+
+	case SPI_FLASH_PROTO_2_2_2:
+		ifr_width = QSPI_IFR_WIDTH_DUAL_CMD;
+		break;
+
+	case SPI_FLASH_PROTO_1_1_4:
+		ifr_width = QSPI_IFR_WIDTH_QUAD_OUTPUT;
+		break;
+
+	case SPI_FLASH_PROTO_1_4_4:
+		ifr_width = QSPI_IFR_WIDTH_QUAD_IO;
+		break;
+
+	case SPI_FLASH_PROTO_4_4_4:
+		ifr_width = QSPI_IFR_WIDTH_QUAD_CMD;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	*ifr = (*ifr & ~QSPI_IFR_WIDTH) | ifr_width;
+	return 0;
+}
+
+static int atmel_qspi_send_command(struct atmel_qspi_priv *aq,
+				   const struct atmel_qspi_command *cmd)
+{
+	unsigned int iar, icr, ifr;
+	unsigned int offset;
+	unsigned int imr, sr;
+	unsigned long memaddr;
+	int err;
+
+	iar = 0;
+	icr = 0;
+	ifr = cmd->ifr_tfrtype;
+
+	err = atmel_qpsi_set_ifr_width(cmd->protocol, &ifr);
+	if (err)
+		return err;
+
+	/* Compute instruction parameters */
+	if (cmd->enable.bits.instruction) {
+		icr |= QSPI_ICR_INST_(cmd->instruction);
+		ifr |= QSPI_IFR_INSTEN;
+	}
+
+	/* Compute address parameters. */
+	switch (cmd->enable.bits.address) {
+	case 4:
+		ifr |= QSPI_IFR_ADDRL_32_BIT;
+		//break; /* fall through the 24bit (3 byte) address case */
+	case 3:
+		iar = (cmd->enable.bits.data) ? 0 : cmd->address;
+		ifr |= QSPI_IFR_ADDREN;
+		offset = cmd->address;
+		break;
+	case 0:
+		offset = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Compute option parameters. */
+	if (cmd->enable.bits.mode && cmd->num_mode_cycles) {
+		unsigned int mode_cycle_bits, mode_bits;
+
+		icr |= QSPI_ICR_OPT_(cmd->mode);
+		ifr |= QSPI_IFR_OPTEN;
+
+		switch (ifr & QSPI_IFR_WIDTH) {
+		case QSPI_IFR_WIDTH_SINGLE_BIT_SPI:
+		case QSPI_IFR_WIDTH_DUAL_OUTPUT:
+		case QSPI_IFR_WIDTH_QUAD_OUTPUT:
+			mode_cycle_bits = 1;
+			break;
+		case QSPI_IFR_WIDTH_DUAL_IO:
+		case QSPI_IFR_WIDTH_DUAL_CMD:
+			mode_cycle_bits = 2;
+			break;
+		case QSPI_IFR_WIDTH_QUAD_IO:
+		case QSPI_IFR_WIDTH_QUAD_CMD:
+			mode_cycle_bits = 4;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		mode_bits = cmd->num_mode_cycles * mode_cycle_bits;
+		switch (mode_bits) {
+		case 1:
+			ifr |= QSPI_IFR_OPTL_1BIT;
+			break;
+
+		case 2:
+			ifr |= QSPI_IFR_OPTL_2BIT;
+			break;
+
+		case 4:
+			ifr |= QSPI_IFR_OPTL_4BIT;
+			break;
+
+		case 8:
+			ifr |= QSPI_IFR_OPTL_8BIT;
+			break;
+
+		default:
+			return -EINVAL;
+		}
+	}
+
+	/* Set the number of dummy cycles. */
+	if (cmd->enable.bits.dummy)
+		ifr |= QSPI_IFR_NBDUM_(cmd->num_dummy_cycles);
+
+	/* Set data enable. */
+	if (cmd->enable.bits.data) {
+		ifr |= QSPI_IFR_DATAEN;
+
+		/* Special case for Continuous Read Mode. */
+		if (!cmd->tx_buf && !cmd->rx_buf)
+			ifr |= QSPI_IFR_CRM;
+	}
+
+	/* Clear pending interrupts. */
+	(void)qspi_readl(aq, QSPI_SR);
+
+	/* Set QSPI Instruction Frame registers. */
+	qspi_writel(aq, QSPI_IAR, iar);
+	qspi_writel(aq, QSPI_ICR, icr);
+	qspi_writel(aq, QSPI_IFR, ifr);
+
+	/* Skip to the final steps if there is no data. */
+	if (!cmd->enable.bits.data)
+		goto no_data;
+
+	/* Dummy read of QSPI_IFR to synchronize APB and AHB accesses. */
+	(void)qspi_readl(aq, QSPI_IFR);
+
+	/* Stop here for Continuous Read. */
+	memaddr = (unsigned long)(aq->membase + offset);
+	if (cmd->tx_buf)
+		/* Write data. */
+		atmel_qspi_memcpy_toio(memaddr, cmd->tx_buf, cmd->buf_len);
+	else if (cmd->rx_buf)
+		/* Read data. */
+		atmel_qspi_memcpy_fromio(cmd->rx_buf, memaddr, cmd->buf_len);
+	else
+		/* Stop here for continuous read */
+		return 0;
+
+	/* Release the chip-select. */
+	qspi_writel(aq, QSPI_CR, QSPI_CR_LASTXFER);
+
+no_data:
+	/* Poll INSTruction End and Chip Select Rise flags. */
+	imr = (QSPI_SR_INSTRE | QSPI_SR_CSR);
+	sr = 0;
+	while (sr != (QSPI_SR_INSTRE | QSPI_SR_CSR))
+		sr |= qspi_readl(aq, QSPI_SR) & imr;
+
+	return 0;
+}
+
+static int atmel_qspi_read_reg(struct udevice *dev, u8 opcode,
+			       size_t len, void *buf)
+{
+	struct spi_flash *flash = dev_get_uclass_priv(dev);
+	struct atmel_qspi_priv *aq = dev_get_priv(dev->parent);
+	struct atmel_qspi_command cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.enable.bits.instruction = 1;
+	cmd.enable.bits.data = 1;
+	cmd.instruction = opcode;
+	cmd.rx_buf = buf;
+	cmd.buf_len = len;
+	cmd.protocol = flash->reg_proto;
+	cmd.ifr_tfrtype = QSPI_IFR_TFRTYPE_READ;
+	return atmel_qspi_send_command(aq, &cmd);
+}
+
+static int atmel_qspi_write_reg(struct udevice *dev, u8 opcode,
+				size_t len, const void *buf)
+{
+	struct spi_flash *flash = dev_get_uclass_priv(dev);
+	struct atmel_qspi_priv *aq = dev_get_priv(dev->parent);
+	struct atmel_qspi_command cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.enable.bits.instruction = 1;
+	cmd.enable.bits.data = (buf && len);
+	cmd.instruction = opcode;
+	cmd.tx_buf = buf;
+	cmd.buf_len = len;
+	cmd.protocol = flash->reg_proto;
+	cmd.ifr_tfrtype = QSPI_IFR_TFRTYPE_WRITE;
+	return atmel_qspi_send_command(aq, &cmd);
+}
+
+static int atmel_qspi_read_impl(struct spi_flash *flash, u32 offset,
+				size_t len, void *buf)
+{
+	struct atmel_qspi_priv *aq = dev_get_priv(flash->dev->parent);
+	struct atmel_qspi_command cmd;
+	u8 lshift;
+
+	switch (SPI_FLASH_PROTO_ADR_FROM_PROTO(flash->read_proto)) {
+	case 1:
+		lshift = 3;
+		break;
+
+	case 2:
+		lshift = 2;
+		break;
+
+	case 4:
+		lshift = 1;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.enable.bits.instruction = 1;
+	cmd.enable.bits.address = flash->addr_width;
+	cmd.enable.bits.mode = 0;
+	cmd.enable.bits.dummy = (flash->dummy_byte > 0);
+	cmd.enable.bits.data = 1;
+	cmd.instruction = flash->read_cmd;
+	cmd.address = offset;
+	cmd.num_dummy_cycles = flash->dummy_byte << lshift;
+	cmd.rx_buf = buf;
+	cmd.buf_len = len;
+	cmd.protocol = flash->read_proto;
+	cmd.ifr_tfrtype = QSPI_IFR_TFRTYPE_READ_MEMORY;
+	return atmel_qspi_send_command(aq, &cmd);
+}
+
+static int atmel_qspi_read(struct udevice *dev, u32 offset,
+			   size_t len, void *buf)
+{
+	struct spi_flash *flash = dev_get_uclass_priv(dev);
+
+	return spi_flash_read_alg(flash, offset, len, buf,
+				  atmel_qspi_read_impl);
+}
+
+static int atmel_qspi_write_impl(struct spi_flash *flash, u32 offset,
+				 size_t len, const void *buf)
+{
+	struct atmel_qspi_priv *aq = dev_get_priv(flash->dev->parent);
+	struct atmel_qspi_command cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.enable.bits.instruction = 1;
+	cmd.enable.bits.address = flash->addr_width;
+	cmd.enable.bits.data = 1;
+	cmd.instruction = flash->write_cmd;
+	cmd.address = offset;
+	cmd.tx_buf = buf;
+	cmd.buf_len = len;
+	cmd.protocol = flash->write_proto;
+	cmd.ifr_tfrtype = QSPI_IFR_TFRTYPE_WRITE_MEMORY;
+	return atmel_qspi_send_command(aq, &cmd);
+}
+
+static int atmel_qspi_write(struct udevice *dev, u32 offset,
+			    size_t len, const void *buf)
+{
+	struct spi_flash *flash = dev_get_uclass_priv(dev);
+
+	return spi_flash_write_alg(flash, offset, len, buf,
+				   atmel_qspi_write_impl);
+}
+
+static int atmel_qspi_erase_impl(struct spi_flash *flash, u32 offset)
+{
+	struct atmel_qspi_priv *aq = dev_get_priv(flash->dev->parent);
+	struct atmel_qspi_command cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.enable.bits.instruction = 1;
+	cmd.enable.bits.address = flash->addr_width;
+	cmd.instruction = flash->erase_cmd;
+	cmd.address = offset;
+	cmd.protocol = flash->erase_proto;
+	cmd.ifr_tfrtype = QSPI_IFR_TFRTYPE_WRITE;
+	return atmel_qspi_send_command(aq, &cmd);
+}
+
+static int atmel_qspi_erase(struct udevice *dev, u32 offset, size_t len)
+{
+	struct spi_flash *flash = dev_get_uclass_priv(dev);
+
+	return spi_flash_erase_alg(flash, offset, len,
+				   atmel_qspi_erase_impl);
+}
+
+static const struct dm_spi_flash_ops atmel_qspi_flash_ops = {
+	.read_reg	= atmel_qspi_read_reg,
+	.write_reg	= atmel_qspi_write_reg,
+	.read		= atmel_qspi_read,
+	.write		= atmel_qspi_write,
+	.erase		= atmel_qspi_erase,
+};
+
+static int atmel_qspi_flash_probe(struct udevice *dev)
+{
+	struct spi_flash *flash = dev_get_uclass_priv(dev);
+	struct spi_slave *slave = dev_get_parent_priv(dev);
+	int ret;
+
+	flash->dev = dev;
+	flash->spi = slave;
+
+	/* Claim spi bus */
+	ret = spi_claim_bus(slave);
+	if (ret) {
+		debug("SF: Failed to claim SPI bus: %d\n", ret);
+		return ret;
+	}
+
+	/* The Quad SPI controller supports all Dual & Quad I/O protocols */
+	slave->mode |= (SPI_TX_QUAD | SPI_TX_DUAL);
+	ret = spi_flash_scan(flash, RD_FCMD);
+	if (ret) {
+		ret = -EINVAL;
+		goto release;
+	}
+
+#ifdef CONFIG_SPI_FLASH_MTD
+	ret = spi_flash_mtd_register(flash);
+#endif
+
+release:
+	spi_release_bus(slave);
+	return ret;
+}
+
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+static const struct udevice_id atmel_qspi_flash_ids[] = {
+	{ .compatible = "atmel,sama5d2-qspi-flash" },
+	{ }
+};
+#endif
+
+U_BOOT_DRIVER(atmel_qspi_flash) = {
+	.name		= "atmel_qspi_flash",
+	.id		= UCLASS_SPI_FLASH,
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+	.of_match	= atmel_qspi_flash_ids,
+#endif
+	.probe		= atmel_qspi_flash_probe,
+	.ops		= &atmel_qspi_flash_ops,
+};
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index f0258f84afeb..d478c5d953c6 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -23,6 +23,15 @@ config ALTERA_SPI
 	  IP core. Please find details on the "Embedded Peripherals IP
 	  User Guide" of Altera.
 
+config ATMEL_QSPI
+	bool "Atmel QSPI driver"
+	depends on ARCH_AT91
+	select SPI_FLASH
+	select DM_SPI_FLASH
+	help
+	  Enable the Ateml Quad-SPI (QSPI) driver. This driver can only be
+	  used to access SPI NOR flashes.
+
 config CADENCE_QSPI
 	bool "Cadence QSPI driver"
 	help
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 3eca7456d6a6..eb3bd95f5ee7 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -18,6 +18,7 @@ endif
 obj-$(CONFIG_ALTERA_SPI) += altera_spi.o
 obj-$(CONFIG_ARMADA100_SPI) += armada100_spi.o
 obj-$(CONFIG_ATMEL_DATAFLASH_SPI) += atmel_dataflash_spi.o
+obj-$(CONFIG_ATMEL_QSPI) += atmel_qspi.o
 obj-$(CONFIG_ATMEL_SPI) += atmel_spi.o
 obj-$(CONFIG_BFIN_SPI) += bfin_spi.o
 obj-$(CONFIG_BFIN_SPI6XX) += bfin_spi6xx.o
diff --git a/drivers/spi/atmel_qspi.c b/drivers/spi/atmel_qspi.c
new file mode 100644
index 000000000000..b8e280553d99
--- /dev/null
+++ b/drivers/spi/atmel_qspi.c
@@ -0,0 +1,150 @@
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <spi.h>
+#include <asm/io.h>
+#include <mach/clk.h>
+
+#include "atmel_qspi.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+
+static int atmel_qspi_xfer(struct udevice *dev, unsigned int bitlen,
+			   const void *dout, void *din, unsigned long flags)
+{
+	/* This controller can only be used with SPI NOR flashes. */
+	return -EINVAL;
+}
+
+static int atmel_qspi_set_speed(struct udevice *bus, uint hz)
+{
+	struct atmel_qspi_priv *aq = dev_get_priv(bus);
+	unsigned long src_rate;
+	u32 scr, scbr, mask, new_value;
+
+	/* Compute the QSPI baudrate */
+	src_rate = get_qspi_clk_rate(aq->dev_id);
+	scbr = DIV_ROUND_UP(src_rate, hz);
+	if (scbr > 0)
+		scbr--;
+
+	new_value = QSPI_SCR_SCBR_(scbr);
+	mask = QSPI_SCR_SCBR;
+
+	scr = qspi_readl(aq, QSPI_SCR);
+	if ((scr & mask) == new_value)
+		return 0;
+
+	scr = (scr & ~mask) | new_value;
+	qspi_writel(aq, QSPI_SCR, scr);
+
+	return 0;
+}
+
+static int atmel_qspi_set_mode(struct udevice *bus, uint mode)
+{
+	struct atmel_qspi_priv *aq = dev_get_priv(bus);
+	u32 scr, mask, new_value;
+
+	new_value = (QSPI_SCR_CPOL_((mode & SPI_CPOL) != 0) |
+		     QSPI_SCR_CPHA_((mode & SPI_CPHA) != 0));
+	mask = (QSPI_SCR_CPOL | QSPI_SCR_CPHA);
+
+	scr = qspi_readl(aq, QSPI_SCR);
+	if ((scr & mask) == new_value)
+		return 0;
+
+	scr = (scr & ~mask) | new_value;
+	qspi_writel(aq, QSPI_SCR, scr);
+
+	return 0;
+}
+
+static const struct dm_spi_ops atmel_qspi_ops = {
+	.xfer		= atmel_qspi_xfer,
+	.set_speed	= atmel_qspi_set_speed,
+	.set_mode	= atmel_qspi_set_mode,
+};
+
+static int atmel_qspi_probe(struct udevice *dev)
+{
+	const struct atmel_qspi_platdata *plat = dev_get_platdata(dev);
+	struct atmel_qspi_priv *aq = dev_get_priv(dev);
+	u32 mr;
+
+	aq->regbase = plat->regbase;
+	aq->membase = plat->membase;
+	aq->dev_id = plat->dev_id;
+
+	/* Reset the QSPI controler */
+	qspi_writel(aq, QSPI_CR, QSPI_CR_SWRST);
+
+	/* Set the QSPI controller in Serial Memory Mode */
+	mr = (QSPI_MR_NBBITS_8_BIT |
+	      QSPI_MR_SMM_MEMORY |
+	      QSPI_MR_CSMODE_LASTXFER);
+	qspi_writel(aq, QSPI_MR, mr);
+
+	/* Enable the QSPI controller */
+	qspi_writel(aq, QSPI_CR, QSPI_CR_QSPIEN);
+
+	return 0;
+}
+
+static int atmel_qspi_remove(struct udevice *dev)
+{
+	struct atmel_qspi_priv *aq = dev_get_priv(dev);
+
+	/* Disable the QSPI controller */
+	qspi_writel(aq, QSPI_CR, QSPI_CR_QSPIDIS);
+
+	return 0;
+}
+
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+static int atmel_qspi_ofdata_to_platdata(struct udevice *dev)
+{
+	struct atmel_qspi_platdata *plat = dev_get_platdata(dev);
+	const void *blob = gd->fdt_blob;
+	int node = dev->of_offset;
+	u32 data[4];
+	int ret, seq;
+
+	ret = fdtdec_get_int_array(blob, node, "reg", data, ARRAY_SIZE(data));
+	if (ret) {
+		printf("Error: Can't get base addresses (ret=%d)!\n", ret);
+		return -ENODEV;
+	}
+	plat->regbase = (void *)data[0];
+	plat->membase = (void *)data[2];
+
+	ret = fdtdec_get_alias_seq(blob, "spi", node, &seq);
+	if (ret) {
+		printf("Error: Can't get device ID (ret=%d)!\n", ret);
+		return -ENODEV;
+	}
+	plat->dev_id = (unsigned int)seq;
+
+	return 0;
+}
+
+static const struct udevice_id atmel_qspi_ids[] = {
+	{ .compatible = "atmel,sama5d2-qspi" },
+	{ }
+};
+#endif
+
+U_BOOT_DRIVER(atmel_qspi) = {
+	.name		= "atmel_qspi",
+	.id		= UCLASS_SPI,
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+	.of_match	= atmel_qspi_ids,
+	.ofdata_to_platdata = atmel_qspi_ofdata_to_platdata,
+	.platdata_auto_alloc_size = sizeof(struct atmel_qspi_platdata),
+#endif
+	.priv_auto_alloc_size = sizeof(struct atmel_qspi_priv),
+	.ops		= &atmel_qspi_ops,
+	.probe		= atmel_qspi_probe,
+	.remove		= atmel_qspi_remove,
+};
diff --git a/drivers/spi/atmel_qspi.h b/drivers/spi/atmel_qspi.h
new file mode 100644
index 000000000000..2b221dd44335
--- /dev/null
+++ b/drivers/spi/atmel_qspi.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2016
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __ATMEL_QSPI_H__
+#define __ATMEL_QSPI_H__
+
+/*
+ * Register Definitions
+ */
+#define	QSPI_CR		0x00	/* Control Register */
+#define	QSPI_MR		0x04	/* Mode Register */
+#define	QSPI_RDR	0x08	/* Receive Data Register */
+#define	QSPI_TDR	0x0c	/* Transmit Data Register */
+#define	QSPI_SR		0x10	/* Status Register */
+#define	QSPI_IER	0x14	/* Interrupt Enable Register */
+#define	QSPI_IDR	0x18	/* Interrupt Disable Register */
+#define	QSPI_IMR	0x1c	/* Interrupt Mask Register */
+#define	QSPI_SCR	0x20	/* Serial Clock Register */
+#define	QSPI_IAR	0x30	/* Instruction Address Register */
+#define	QSPI_ICR	0x34	/* Instruction Code Register */
+#define	QSPI_IFR	0x38	/* Instruction Frame Register */
+/* 0x3c Reserved */
+#define	QSPI_SMR	0x40	/* Scrambling Mode Register */
+#define	QSPI_SKR	0x44	/* Scrambling Key Register */
+/* 0x48 ~ 0xe0 */
+#define	QSPI_WPMR	0xe4	/* Write Protection Mode Register */
+#define	QSPI_WPSR	0xe8	/* Write Protection Status Register */
+/* 0xec ~ 0xf8 Reserved */
+/* 0xfc Reserved */
+
+/*
+ * Register Field Definitions
+ */
+/* QSPI_CR */
+#define	QSPI_CR_QSPIEN		(0x1 << 0)	/* QSPI Enable */
+#define	QSPI_CR_QSPIDIS		(0x1 << 1)	/* QSPI Disable */
+#define	QSPI_CR_SWRST		(0x1 << 7)	/* QSPI Software Reset */
+#define	QSPI_CR_LASTXFER	(0x1 << 24)	/* Last Transfer */
+
+/* QSPI_MR */
+#define	QSPI_MR_SMM		(0x1 << 0)	/* Serial Memort Mode */
+#define		QSPI_MR_SMM_SPI		(0x0 << 0)
+#define		QSPI_MR_SMM_MEMORY	(0x1 << 0)
+#define	QSPI_MR_LLB		(0x1 << 1)	/* Local Localback Enable */
+#define		QSPI_MR_LLB_DISABLED	(0x0 << 1)
+#define		QSPI_MR_LLB_ENABLED	(0x1 << 1)
+#define	QSPI_MR_WDRBT		(0x1 << 2)	/* Wait Data Read Before Transfer */
+#define		QSPI_MR_WDRBT_DISABLED		(0x0 << 2)
+#define		QSPI_MR_WDRBT_ENABLED		(0x1 << 2)
+#define	QSPI_MR_SMRM		(0x1 << 3)	/* Serial Memory Register Mode */
+#define		QSPI_MR_SMRM_AHB	(0x0 << 3)
+#define		QSPI_MR_SMRM_APB	(0x1 << 3)
+#define	QSPI_MR_CSMODE		(0x3 << 4)	/* Chip Select Mode */
+#define		QSPI_MR_CSMODE_NOT_RELOADED	(0x0 << 4)
+#define		QSPI_MR_CSMODE_LASTXFER		(0x1 << 4)
+#define		QSPI_MR_CSMODE_SYSTEMATICALLY	(0x2 << 4)
+#define	QSPI_MR_NBBITS		(0xf << 8)	/* Number of Bits Per Transfer */
+#define		QSPI_MR_NBBITS_8_BIT		(0x0 << 8)
+#define		QSPI_MR_NBBITS_16_BIT		(0x8 << 8)
+#define	QSPI_MR_DLYBCT		(0xff << 16)	/* Delay Between Consecutive Transfers */
+#define	QSPI_MR_DLYCS		(0xff << 24)	/* Minimum Inactive QCS Delay */
+
+/* QSPI_SR */
+#define	QSPI_SR_RDRF		(0x1 << 0)	/* Receive Data Register Full */
+#define	QSPI_SR_TDRE		(0x1 << 1)	/* Transmit Data Register Empty */
+#define	QSPI_SR_TXEMPTY		(0x1 << 2)	/* Transmission Registers Empty */
+#define	QSPI_SR_OVRES		(0x1 << 3)	/* Overrun Error Status */
+#define	QSPI_SR_CSR		(0x1 << 8)	/* Chip Select Rise */
+#define	QSPI_SR_CSS		(0x1 << 9)	/* Chip Select Status */
+#define	QSPI_SR_INSTRE		(0x1 << 10)	/* Instruction End Status */
+#define	QSPI_SR_QSPIENS		(0x1 << 24)	/* QSPI Enable Status */
+
+/* QSPI_SCR */
+#define	QSPI_SCR_CPOL		(0x1 << 0)	/* Clock Polarity */
+#define	QSPI_SCR_CPOL_(x)	((x) << 0)
+#define	QSPI_SCR_CPHA		(0x1 << 1)	/* Clock Phase */
+#define	QSPI_SCR_CPHA_(x)	((x) << 1)
+#define	QSPI_SCR_SCBR		(0xff << 8)	/* Serial Clock Baud Rate */
+#define	QSPI_SCR_SCBR_(x)	((x) << 8)
+#define	QSPI_SCR_DLYBS_(x)	((x) << 16)	/* Delay Before QSCK */
+
+/* QSPI_ICR */
+#define	QSPI_ICR_INST_(x)	((x) << 0)	/* Instruction Code */
+#define	QSPI_ICR_OPT_(x)	((x) << 16)	/* Option Code */
+
+/* QSPI_IFR */
+#define	QSPI_IFR_WIDTH		(0x7 << 0)	/* Width of Instruction Code, Address, Option Code and Data */
+#define		QSPI_IFR_WIDTH_SINGLE_BIT_SPI	(0x0 << 0)
+#define		QSPI_IFR_WIDTH_DUAL_OUTPUT	(0x1 << 0)
+#define		QSPI_IFR_WIDTH_QUAD_OUTPUT	(0x2 << 0)
+#define		QSPI_IFR_WIDTH_DUAL_IO		(0x3 << 0)
+#define		QSPI_IFR_WIDTH_QUAD_IO		(0x4 << 0)
+#define		QSPI_IFR_WIDTH_DUAL_CMD		(0x5 << 0)
+#define		QSPI_IFR_WIDTH_QUAD_CMD		(0x6 << 0)
+#define QSPI_IFR_WIDTH_(x)	(((x) << 0) & QSPI_IFR_WIDTH)
+#define	QSPI_IFR_INSTEN		(0x1 << 4)	/* Instruction Enable*/
+#define	QSPI_IFR_ADDREN		(0x1 << 5)	/* Address Enable*/
+#define	QSPI_IFR_OPTEN		(0x1 << 6)	/* Option Enable*/
+#define	QSPI_IFR_DATAEN		(0x1 << 7)	/* Data Enable*/
+#define	QSPI_IFR_OPTL		(0x3 << 8)	/* Option Code Length */
+#define		QSPI_IFR_OPTL_1BIT		(0x0 << 8)
+#define		QSPI_IFR_OPTL_2BIT		(0x1 << 8)
+#define		QSPI_IFR_OPTL_4BIT		(0x2 << 8)
+#define		QSPI_IFR_OPTL_8BIT		(0x3 << 8)
+#define	QSPI_IFR_ADDRL		(0x1 << 10)	/* Address Length */
+#define		QSPI_IFR_ADDRL_24_BIT		(0x0 << 10)
+#define		QSPI_IFR_ADDRL_32_BIT		(0x1 << 10)
+#define	QSPI_IFR_TFRTYPE	(0x3 << 12)	/* Data Transfer Type */
+#define		QSPI_IFR_TFRTYPE_READ		(0x0 << 12)
+#define		QSPI_IFR_TFRTYPE_READ_MEMORY	(0x1 << 12)
+#define		QSPI_IFR_TFRTYPE_WRITE		(0x2 << 12)
+#define		QSPI_IFR_TFRTYPE_WRITE_MEMORY	(0x3 << 12)
+#define QSPI_IFR_TFRTYPE_(x)	(((x) << 12) & QSPI_IFR_TFRTYPE)
+#define	QSPI_IFR_CRM		(0x1 << 14)	/* Continuous Read Mode */
+#define	QSPI_IFR_NBDUM_(x)	((x) << 16)	/* Number Of Dummy Cycles */
+
+
+struct atmel_qspi_platdata {
+	unsigned int	dev_id;
+	void		*regbase;
+	void		*membase;
+};
+
+struct atmel_qspi_priv {
+	unsigned int	dev_id;
+	void		*regbase;
+	void		*membase;
+};
+
+#include <asm/io.h>
+
+static inline u32 qspi_readl(struct atmel_qspi_priv *aq, u32 reg)
+{
+	return readl(aq->regbase + reg);
+}
+
+static inline void qspi_writel(struct atmel_qspi_priv *aq, u32 reg, u32 value)
+{
+	writel(value, aq->regbase + reg);
+}
+
+#endif /* __ATMEL_QSPI_H__ */
-- 
1.8.2.2



More information about the U-Boot mailing list