From mboxrd@z Thu Jan 1 00:00:00 1970 From: Cyrille Pitchen Date: Tue, 15 Mar 2016 19:12:40 +0100 Subject: [U-Boot] [PATCH 18/18] sf: add driver for Atmel QSPI controller In-Reply-To: References: Message-ID: List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de This patch adds support of the Atmel QSPI controller. Signed-off-by: Cyrille Pitchen --- 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 +#include +#include +#include + +#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 +#include +#include +#include +#include +#include + +#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 + +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