diff options
Diffstat (limited to 'drivers/spi/fsl_qspi.c')
-rw-r--r-- | drivers/spi/fsl_qspi.c | 1584 |
1 files changed, 670 insertions, 914 deletions
diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c index cb8d929..a214d34 100644 --- a/drivers/spi/fsl_qspi.c +++ b/drivers/spi/fsl_qspi.c @@ -1,35 +1,174 @@ /* - * Copyright 2013-2015 Freescale Semiconductor, Inc. + * Freescale QuadSPI driver. * - * Freescale Quad Serial Peripheral Interface (QSPI) driver + * Copyright (C) 2014-2016 Freescale Semiconductor, Inc. * - * SPDX-License-Identifier: GPL-2.0+ + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. */ - #include <common.h> #include <malloc.h> #include <spi.h> + #include <asm/io.h> -#include <linux/sizes.h> -#include <dm.h> -#include <errno.h> -#include <watchdog.h> -#include "fsl_qspi.h" - -DECLARE_GLOBAL_DATA_PTR; - -#define RX_BUFFER_SIZE 0x80 -#ifdef CONFIG_MX6SX -#define TX_BUFFER_SIZE 0x200 -#else -#define TX_BUFFER_SIZE 0x40 -#endif -#define OFFSET_BITS_MASK GENMASK(23, 0) +#define QUADSPI_AHBMAP_BANK_MAXSIZE SZ_64M + +/* The registers */ +#define QUADSPI_MCR 0x00 +#define QUADSPI_MCR_RESERVED_SHIFT 16 +#define QUADSPI_MCR_RESERVED_MASK (0xF << QUADSPI_MCR_RESERVED_SHIFT) +#define QUADSPI_MCR_MDIS_SHIFT 14 +#define QUADSPI_MCR_MDIS_MASK (1 << QUADSPI_MCR_MDIS_SHIFT) +#define QUADSPI_MCR_CLR_TXF_SHIFT 11 +#define QUADSPI_MCR_CLR_TXF_MASK (1 << QUADSPI_MCR_CLR_TXF_SHIFT) +#define QUADSPI_MCR_CLR_RXF_SHIFT 10 +#define QUADSPI_MCR_CLR_RXF_MASK (1 << QUADSPI_MCR_CLR_RXF_SHIFT) +#define QUADSPI_MCR_DDR_EN_SHIFT 7 +#define QUADSPI_MCR_DDR_EN_MASK (1 << QUADSPI_MCR_DDR_EN_SHIFT) +#define QUADSPI_MCR_END_CFG_SHIFT 2 +#define QUADSPI_MCR_END_CFG_MASK (3 << QUADSPI_MCR_END_CFG_SHIFT) +#define QUADSPI_MCR_SWRSTHD_SHIFT 1 +#define QUADSPI_MCR_SWRSTHD_MASK (1 << QUADSPI_MCR_SWRSTHD_SHIFT) +#define QUADSPI_MCR_SWRSTSD_SHIFT 0 +#define QUADSPI_MCR_SWRSTSD_MASK (1 << QUADSPI_MCR_SWRSTSD_SHIFT) + +#define QUADSPI_IPCR 0x08 +#define QUADSPI_IPCR_SEQID_SHIFT 24 +#define QUADSPI_IPCR_SEQID_MASK (0xF << QUADSPI_IPCR_SEQID_SHIFT) + +#define QUADSPI_BUF0CR 0x10 +#define QUADSPI_BUF1CR 0x14 +#define QUADSPI_BUF2CR 0x18 +#define QUADSPI_BUFXCR_INVALID_MSTRID 0xe + +#define QUADSPI_BUF3CR 0x1c +#define QUADSPI_BUF3CR_ALLMST_SHIFT 31 +#define QUADSPI_BUF3CR_ALLMST_MASK (1 << QUADSPI_BUF3CR_ALLMST_SHIFT) +#define QUADSPI_BUF3CR_ADATSZ_SHIFT 8 +#define QUADSPI_BUF3CR_ADATSZ_MASK (0xFF << QUADSPI_BUF3CR_ADATSZ_SHIFT) + +#define QUADSPI_BFGENCR 0x20 +#define QUADSPI_BFGENCR_PAR_EN_SHIFT 16 +#define QUADSPI_BFGENCR_PAR_EN_MASK (1 << (QUADSPI_BFGENCR_PAR_EN_SHIFT)) +#define QUADSPI_BFGENCR_SEQID_SHIFT 12 +#define QUADSPI_BFGENCR_SEQID_MASK (0xF << QUADSPI_BFGENCR_SEQID_SHIFT) + +#define QUADSPI_BUF0IND 0x30 +#define QUADSPI_BUF1IND 0x34 +#define QUADSPI_BUF2IND 0x38 +#define QUADSPI_SFAR 0x100 + +#define QUADSPI_SMPR 0x108 +#define QUADSPI_SMPR_DDRSMP_SHIFT 16 +#define QUADSPI_SMPR_DDRSMP_MASK (7 << QUADSPI_SMPR_DDRSMP_SHIFT) +#define QUADSPI_SMPR_FSDLY_SHIFT 6 +#define QUADSPI_SMPR_FSDLY_MASK (1 << QUADSPI_SMPR_FSDLY_SHIFT) +#define QUADSPI_SMPR_FSPHS_SHIFT 5 +#define QUADSPI_SMPR_FSPHS_MASK (1 << QUADSPI_SMPR_FSPHS_SHIFT) +#define QUADSPI_SMPR_HSENA_SHIFT 0 +#define QUADSPI_SMPR_HSENA_MASK (1 << QUADSPI_SMPR_HSENA_SHIFT) + +#define QUADSPI_RBSR 0x10c +#define QUADSPI_RBSR_RDBFL_SHIFT 8 +#define QUADSPI_RBSR_RDBFL_MASK (0x3F << QUADSPI_RBSR_RDBFL_SHIFT) + +#define QUADSPI_RBCT 0x110 +#define QUADSPI_RBCT_WMRK_MASK 0x1F +#define QUADSPI_RBCT_RXBRD_SHIFT 8 +#define QUADSPI_RBCT_RXBRD_USEIPS (0x1 << QUADSPI_RBCT_RXBRD_SHIFT) + +#define QUADSPI_TBSR 0x150 +#define QUADSPI_TBDR 0x154 +#define QUADSPI_SR 0x15c +#define QUADSPI_SR_IP_ACC_SHIFT 1 +#define QUADSPI_SR_IP_ACC_MASK (0x1 << QUADSPI_SR_IP_ACC_SHIFT) +#define QUADSPI_SR_AHB_ACC_SHIFT 2 +#define QUADSPI_SR_AHB_ACC_MASK (0x1 << QUADSPI_SR_AHB_ACC_SHIFT) + + +#define QUADSPI_FR 0x160 +#define QUADSPI_FR_TFF_MASK 0x1 + +#define QUADSPI_SFA1AD 0x180 +#define QUADSPI_SFA2AD 0x184 +#define QUADSPI_SFB1AD 0x188 +#define QUADSPI_SFB2AD 0x18c +#define QUADSPI_RBDR 0x200 + +#define QUADSPI_LUTKEY 0x300 +#define QUADSPI_LUTKEY_VALUE 0x5AF05AF0 + +#define QUADSPI_LCKCR 0x304 +#define QUADSPI_LCKER_LOCK 0x1 +#define QUADSPI_LCKER_UNLOCK 0x2 + +#define QUADSPI_RSER 0x164 +#define QUADSPI_RSER_TFIE (0x1 << 0) + +#define QUADSPI_LUT_BASE 0x310 -#define FLASH_STATUS_WEL 0x02 +/* + * The definition of the LUT register shows below: + * + * --------------------------------------------------- + * | INSTR1 | PAD1 | OPRND1 | INSTR0 | PAD0 | OPRND0 | + * --------------------------------------------------- + */ +#define OPRND0_SHIFT 0 +#define PAD0_SHIFT 8 +#define INSTR0_SHIFT 10 +#define OPRND1_SHIFT 16 + +/* Instruction set for the LUT register. */ +#define LUT_STOP 0 +#define LUT_CMD 1 +#define LUT_ADDR 2 +#define LUT_DUMMY 3 +#define LUT_MODE 4 +#define LUT_MODE2 5 +#define LUT_MODE4 6 +#define LUT_READ 7 +#define LUT_WRITE 8 +#define LUT_JMP_ON_CS 9 +#define LUT_ADDR_DDR 10 +#define LUT_MODE_DDR 11 +#define LUT_MODE2_DDR 12 +#define LUT_MODE4_DDR 13 +#define LUT_READ_DDR 14 +#define LUT_WRITE_DDR 15 +#define LUT_DATA_LEARN 16 -/* SEQID */ +/* + * The PAD definitions for LUT register. + * + * The pad stands for the lines number of IO[0:3]. + * For example, the Quad read need four IO lines, so you should + * set LUT_PAD4 which means we use four IO lines. + */ +#define LUT_PAD1 0 +#define LUT_PAD2 1 +#define LUT_PAD4 2 + +/* Oprands for the LUT register. */ +#define ADDR24BIT 0x18 +#define ADDR32BIT 0x20 + +/* Macros for constructing the LUT register. */ +#define LUT0(ins, pad, opr) \ + (((opr) << OPRND0_SHIFT) | ((LUT_##pad) << PAD0_SHIFT) | \ + ((LUT_##ins) << INSTR0_SHIFT)) + +#define LUT1(ins, pad, opr) (LUT0(ins, pad, opr) << OPRND1_SHIFT) + +/* other macros for LUT register. */ +#define QUADSPI_LUT(x) (QUADSPI_LUT_BASE + (x) * 4) +#define QUADSPI_LUT_NUM 64 + +/* SEQID -- we can have 16 seqids at most. */ +#define SEQID_QUAD_READ 0 #define SEQID_WREN 1 #define SEQID_FAST_READ 2 #define SEQID_RDSR 3 @@ -37,356 +176,269 @@ DECLARE_GLOBAL_DATA_PTR; #define SEQID_CHIP_ERASE 5 #define SEQID_PP 6 #define SEQID_RDID 7 -#define SEQID_BE_4K 8 +#define SEQID_WRSR 8 +#define SEQID_RDCR 9 +#define SEQID_DDR_QUAD_READ 10 +#define SEQID_BE_4K 11 #ifdef CONFIG_SPI_FLASH_BAR -#define SEQID_BRRD 9 -#define SEQID_BRWR 10 -#define SEQID_RDEAR 11 -#define SEQID_WREAR 12 +#define SEQID_BRRD 12 +#define SEQID_BRWR 13 +#define SEQID_RDEAR 14 +#define SEQID_WREAR 15 #endif -/* QSPI CMD */ -#define QSPI_CMD_PP 0x02 /* Page program (up to 256 bytes) */ -#define QSPI_CMD_RDSR 0x05 /* Read status register */ -#define QSPI_CMD_WREN 0x06 /* Write enable */ -#define QSPI_CMD_FAST_READ 0x0b /* Read data bytes (high frequency) */ -#define QSPI_CMD_BE_4K 0x20 /* 4K erase */ -#define QSPI_CMD_CHIP_ERASE 0xc7 /* Erase whole flash chip */ -#define QSPI_CMD_SE 0xd8 /* Sector erase (usually 64KiB) */ -#define QSPI_CMD_RDID 0x9f /* Read JEDEC ID */ +/* Flash opcodes. */ +#define OPCODE_WREN 0x06 /* Write enable */ +#define OPCODE_RDSR 0x05 /* Read status register */ +#define OPCODE_WRSR 0x01 /* Write status register 1 byte */ +#define OPCODE_NORM_READ 0x03 /* Read data bytes (low frequency) */ +#define OPCODE_FAST_READ 0x0b /* Read data bytes (high frequency) */ +#define OPCODE_QUAD_READ 0x6b /* Read data bytes */ +#define OPCODE_DDR_QUAD_READ 0x6d /* Read data bytes in DDR mode*/ +#define OPCODE_PP 0x02 /* Page program (up to 256 bytes) */ +#define OPCODE_BE_4K 0x20 /* Erase 4KiB block */ +#define OPCODE_BE_4K_PMC 0xd7 /* Erase 4KiB block on PMC chips */ +#define OPCODE_BE_32K 0x52 /* Erase 32KiB block */ +#define OPCODE_CHIP_ERASE 0xc7 /* Erase whole flash chip */ +#define OPCODE_SE 0xd8 /* Sector erase (usually 64KiB) */ +#define OPCODE_RDID 0x9f /* Read JEDEC ID */ +#define OPCODE_RDCR 0x35 /* Read configuration register */ + +/* 4-byte address opcodes - used on Spansion and some Macronix flashes. */ +#define OPCODE_NORM_READ_4B 0x13 /* Read data bytes (low frequency) */ +#define OPCODE_FAST_READ_4B 0x0c /* Read data bytes (high frequency) */ +#define OPCODE_QUAD_READ_4B 0x6c /* Read data bytes */ +#define OPCODE_PP_4B 0x12 /* Page program (up to 256 bytes) */ +#define OPCODE_SE_4B 0xdc /* Sector erase (usually 64KiB) */ + +/* Used for SST flashes only. */ +#define OPCODE_BP 0x02 /* Byte program */ +#define OPCODE_WRDI 0x04 /* Write disable */ +#define OPCODE_AAI_WP 0xad /* Auto address increment word program */ + +/* Used for Macronix and Winbond flashes. */ +#define OPCODE_EN4B 0xb7 /* Enter 4-byte mode */ +#define OPCODE_EX4B 0xe9 /* Exit 4-byte mode */ /* Used for Micron, winbond and Macronix flashes */ -#define QSPI_CMD_WREAR 0xc5 /* EAR register write */ -#define QSPI_CMD_RDEAR 0xc8 /* EAR reigster read */ +#define OPCODE_WREAR 0xc5 /* EAR register write */ +#define OPCODE_RDEAR 0xc8 /* EAR reigster read */ /* Used for Spansion flashes only. */ -#define QSPI_CMD_BRRD 0x16 /* Bank register read */ -#define QSPI_CMD_BRWR 0x17 /* Bank register write */ +#define OPCODE_BRRD 0x16 /* Bank register read */ +#define OPCODE_BRWR 0x17 /* Bank register write */ -/* 4-byte address QSPI CMD - used on Spansion and some Macronix flashes */ -#define QSPI_CMD_FAST_READ_4B 0x0c /* Read data bytes (high frequency) */ -#define QSPI_CMD_PP_4B 0x12 /* Page program (up to 256 bytes) */ -#define QSPI_CMD_SE_4B 0xdc /* Sector erase (usually 64KiB) */ +/* Status Register bits. */ +#define SR_WIP 1 /* Write in progress */ +#define SR_WEL 2 /* Write enable latch */ +/* meaning of other SR_* bits may differ between vendors */ +#define SR_BP0 4 /* Block protect 0 */ +#define SR_BP1 8 /* Block protect 1 */ +#define SR_BP2 0x10 /* Block protect 2 */ +#define SR_SRWD 0x80 /* SR write protect */ -/* fsl_qspi_platdata flags */ -#define QSPI_FLAG_REGMAP_ENDIAN_BIG BIT(0) +#define SR_QUAD_EN_MX 0x40 /* Macronix Quad I/O */ -/* default SCK frequency, unit: HZ */ -#define FSL_QSPI_DEFAULT_SCK_FREQ 50000000 +/* Configuration Register bits. */ +#define CR_QUAD_EN_SPAN 0x2 /* Spansion Quad I/O */ -/* QSPI max chipselect signals number */ -#define FSL_QSPI_MAX_CHIPSELECT_NUM 4 +/* Endianess Configuration */ +#define BE_64 0x00 +#define LE_32 0x01 +#define BE_32 0x02 +#define LE_64 0x03 -#ifdef CONFIG_DM_SPI -/** - * struct fsl_qspi_platdata - platform data for Freescale QSPI - * - * @flags: Flags for QSPI QSPI_FLAG_... - * @speed_hz: Default SCK frequency - * @reg_base: Base address of QSPI registers - * @amba_base: Base address of QSPI memory mapping - * @amba_total_size: size of QSPI memory mapping - * @flash_num: Number of active slave devices - * @num_chipselect: Number of QSPI chipselect signals - */ -struct fsl_qspi_platdata { - u32 flags; - u32 speed_hz; - u32 reg_base; - u32 amba_base; - u32 amba_total_size; - u32 flash_num; - u32 num_chipselect; + + +enum fsl_qspi_devtype { + FSL_QUADSPI_VYBRID, + FSL_QUADSPI_IMX6SX, }; -#endif -/** - * struct fsl_qspi_priv - private data for Freescale QSPI - * - * @flags: Flags for QSPI QSPI_FLAG_... - * @bus_clk: QSPI input clk frequency - * @speed_hz: Default SCK frequency - * @cur_seqid: current LUT table sequence id - * @sf_addr: flash access offset - * @amba_base: Base address of QSPI memory mapping of every CS - * @amba_total_size: size of QSPI memory mapping - * @cur_amba_base: Base address of QSPI memory mapping of current CS - * @flash_num: Number of active slave devices - * @num_chipselect: Number of QSPI chipselect signals - * @regs: Point to QSPI register structure for I/O access - */ -struct fsl_qspi_priv { - u32 flags; - u32 bus_clk; - u32 speed_hz; - u32 cur_seqid; - u32 sf_addr; - u32 amba_base[FSL_QSPI_MAX_CHIPSELECT_NUM]; - u32 amba_total_size; - u32 cur_amba_base; - u32 flash_num; - u32 num_chipselect; - struct fsl_qspi_regs *regs; +struct fsl_qspi_devtype_data { + enum fsl_qspi_devtype devtype; + int rxfifo; + int txfifo; }; -#ifndef CONFIG_DM_SPI struct fsl_qspi { struct spi_slave slave; - struct fsl_qspi_priv priv; + uint32_t max_khz; + uint32_t mode; + u32 iobase; + u32 ahb_base; /* Used when read from AHB bus */ + u32 bank_memmap_phy[4]; + struct fsl_qspi_devtype_data *devtype_data; }; -#endif - -static u32 qspi_read32(u32 flags, u32 *addr) -{ - return flags & QSPI_FLAG_REGMAP_ENDIAN_BIG ? - in_be32(addr) : in_le32(addr); -} -static void qspi_write32(u32 flags, u32 *addr, u32 val) +static inline void fsl_qspi_unlock_lut(struct fsl_qspi *q) { - flags & QSPI_FLAG_REGMAP_ENDIAN_BIG ? - out_be32(addr, val) : out_le32(addr, val); + writel(QUADSPI_LUTKEY_VALUE, q->iobase + QUADSPI_LUTKEY); + writel(QUADSPI_LCKER_UNLOCK, q->iobase + QUADSPI_LCKCR); } -/* QSPI support swapping the flash read/write data - * in hardware for LS102xA, but not for VF610 */ -static inline u32 qspi_endian_xchg(u32 data) +static inline void fsl_qspi_lock_lut(struct fsl_qspi *q) { -#ifdef CONFIG_VF610 - return swab32(data); -#else - return data; -#endif + writel(QUADSPI_LUTKEY_VALUE, q->iobase + QUADSPI_LUTKEY); + writel(QUADSPI_LCKER_LOCK, q->iobase + QUADSPI_LCKCR); } -static void qspi_set_lut(struct fsl_qspi_priv *priv) +static void fsl_qspi_init_lut(struct fsl_qspi *q) { - struct fsl_qspi_regs *regs = priv->regs; + u32 base = q->iobase; + int rxfifo = q->devtype_data->rxfifo; u32 lut_base; + u8 cmd, addrlen, dummy; + int i; + + fsl_qspi_unlock_lut(q); + + /* Clear all the LUT table */ + for (i = 0; i < QUADSPI_LUT_NUM; i++) + writel(0, base + QUADSPI_LUT_BASE + i * 4); - /* Unlock the LUT */ - qspi_write32(priv->flags, ®s->lutkey, LUT_KEY_VALUE); - qspi_write32(priv->flags, ®s->lckcr, QSPI_LCKCR_UNLOCK); + /* Quad Read */ + lut_base = SEQID_QUAD_READ * 4; - /* Write Enable */ + /* U-boot SPI flash only support 24bits address*/ + cmd = OPCODE_QUAD_READ; + addrlen = ADDR24BIT; + dummy = 8; + + writel(LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen), + base + QUADSPI_LUT(lut_base)); + writel(LUT0(DUMMY, PAD1, dummy) | LUT1(READ, PAD4, rxfifo), + base + QUADSPI_LUT(lut_base + 1)); + + /* Write enable */ lut_base = SEQID_WREN * 4; - qspi_write32(priv->flags, ®s->lut[lut_base], OPRND0(QSPI_CMD_WREN) | - PAD0(LUT_PAD1) | INSTR0(LUT_CMD)); - qspi_write32(priv->flags, ®s->lut[lut_base + 1], 0); - qspi_write32(priv->flags, ®s->lut[lut_base + 2], 0); - qspi_write32(priv->flags, ®s->lut[lut_base + 3], 0); + writel(LUT0(CMD, PAD1, OPCODE_WREN), base + QUADSPI_LUT(lut_base)); /* Fast Read */ lut_base = SEQID_FAST_READ * 4; -#ifdef CONFIG_SPI_FLASH_BAR - qspi_write32(priv->flags, ®s->lut[lut_base], - OPRND0(QSPI_CMD_FAST_READ) | PAD0(LUT_PAD1) | - INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) | - PAD1(LUT_PAD1) | INSTR1(LUT_ADDR)); -#else - if (FSL_QSPI_FLASH_SIZE <= SZ_16M) - qspi_write32(priv->flags, ®s->lut[lut_base], - OPRND0(QSPI_CMD_FAST_READ) | PAD0(LUT_PAD1) | - INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) | - PAD1(LUT_PAD1) | INSTR1(LUT_ADDR)); - else - qspi_write32(priv->flags, ®s->lut[lut_base], - OPRND0(QSPI_CMD_FAST_READ_4B) | - PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | - OPRND1(ADDR32BIT) | PAD1(LUT_PAD1) | - INSTR1(LUT_ADDR)); -#endif - qspi_write32(priv->flags, ®s->lut[lut_base + 1], - OPRND0(8) | PAD0(LUT_PAD1) | INSTR0(LUT_DUMMY) | - OPRND1(RX_BUFFER_SIZE) | PAD1(LUT_PAD1) | - INSTR1(LUT_READ)); - qspi_write32(priv->flags, ®s->lut[lut_base + 2], 0); - qspi_write32(priv->flags, ®s->lut[lut_base + 3], 0); + cmd = OPCODE_FAST_READ; + addrlen = ADDR24BIT; + dummy = 8; + + writel(LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen), + base + QUADSPI_LUT(lut_base)); + writel(LUT0(DUMMY, PAD1, dummy) | LUT1(READ, PAD1, rxfifo), + base + QUADSPI_LUT(lut_base + 1)); + + /* Page Program */ + lut_base = SEQID_PP * 4; + cmd = OPCODE_PP; + addrlen = ADDR24BIT; + + writel(LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen), + base + QUADSPI_LUT(lut_base)); + writel(LUT0(WRITE, PAD1, 0), base + QUADSPI_LUT(lut_base + 1)); /* Read Status */ lut_base = SEQID_RDSR * 4; - qspi_write32(priv->flags, ®s->lut[lut_base], OPRND0(QSPI_CMD_RDSR) | - PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(1) | - PAD1(LUT_PAD1) | INSTR1(LUT_READ)); - qspi_write32(priv->flags, ®s->lut[lut_base + 1], 0); - qspi_write32(priv->flags, ®s->lut[lut_base + 2], 0); - qspi_write32(priv->flags, ®s->lut[lut_base + 3], 0); + writel(LUT0(CMD, PAD1, OPCODE_RDSR) | LUT1(READ, PAD1, 0x1), + base + QUADSPI_LUT(lut_base)); /* Erase a sector */ lut_base = SEQID_SE * 4; -#ifdef CONFIG_SPI_FLASH_BAR - qspi_write32(priv->flags, ®s->lut[lut_base], OPRND0(QSPI_CMD_SE) | - PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) | - PAD1(LUT_PAD1) | INSTR1(LUT_ADDR)); -#else - if (FSL_QSPI_FLASH_SIZE <= SZ_16M) - qspi_write32(priv->flags, ®s->lut[lut_base], - OPRND0(QSPI_CMD_SE) | PAD0(LUT_PAD1) | - INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) | - PAD1(LUT_PAD1) | INSTR1(LUT_ADDR)); - else - qspi_write32(priv->flags, ®s->lut[lut_base], - OPRND0(QSPI_CMD_SE_4B) | PAD0(LUT_PAD1) | - INSTR0(LUT_CMD) | OPRND1(ADDR32BIT) | - PAD1(LUT_PAD1) | INSTR1(LUT_ADDR)); -#endif - qspi_write32(priv->flags, ®s->lut[lut_base + 1], 0); - qspi_write32(priv->flags, ®s->lut[lut_base + 2], 0); - qspi_write32(priv->flags, ®s->lut[lut_base + 3], 0); + cmd = OPCODE_SE; + addrlen = ADDR24BIT; + + writel(LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen), + base + QUADSPI_LUT(lut_base)); /* Erase the whole chip */ lut_base = SEQID_CHIP_ERASE * 4; - qspi_write32(priv->flags, ®s->lut[lut_base], - OPRND0(QSPI_CMD_CHIP_ERASE) | - PAD0(LUT_PAD1) | INSTR0(LUT_CMD)); - qspi_write32(priv->flags, ®s->lut[lut_base + 1], 0); - qspi_write32(priv->flags, ®s->lut[lut_base + 2], 0); - qspi_write32(priv->flags, ®s->lut[lut_base + 3], 0); - - /* Page Program */ - lut_base = SEQID_PP * 4; -#ifdef CONFIG_SPI_FLASH_BAR - qspi_write32(priv->flags, ®s->lut[lut_base], OPRND0(QSPI_CMD_PP) | - PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) | - PAD1(LUT_PAD1) | INSTR1(LUT_ADDR)); -#else - if (FSL_QSPI_FLASH_SIZE <= SZ_16M) - qspi_write32(priv->flags, ®s->lut[lut_base], - OPRND0(QSPI_CMD_PP) | PAD0(LUT_PAD1) | - INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) | - PAD1(LUT_PAD1) | INSTR1(LUT_ADDR)); - else - qspi_write32(priv->flags, ®s->lut[lut_base], - OPRND0(QSPI_CMD_PP_4B) | PAD0(LUT_PAD1) | - INSTR0(LUT_CMD) | OPRND1(ADDR32BIT) | - PAD1(LUT_PAD1) | INSTR1(LUT_ADDR)); -#endif -#ifdef CONFIG_MX6SX - /* - * To MX6SX, OPRND0(TX_BUFFER_SIZE) can not work correctly. - * So, Use IDATSZ in IPCR to determine the size and here set 0. - */ - qspi_write32(priv->flags, ®s->lut[lut_base + 1], OPRND0(0) | - PAD0(LUT_PAD1) | INSTR0(LUT_WRITE)); -#else - qspi_write32(priv->flags, ®s->lut[lut_base + 1], - OPRND0(TX_BUFFER_SIZE) | - PAD0(LUT_PAD1) | INSTR0(LUT_WRITE)); -#endif - qspi_write32(priv->flags, ®s->lut[lut_base + 2], 0); - qspi_write32(priv->flags, ®s->lut[lut_base + 3], 0); + writel(LUT0(CMD, PAD1, OPCODE_CHIP_ERASE), + base + QUADSPI_LUT(lut_base)); /* READ ID */ lut_base = SEQID_RDID * 4; - qspi_write32(priv->flags, ®s->lut[lut_base], OPRND0(QSPI_CMD_RDID) | - PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(8) | - PAD1(LUT_PAD1) | INSTR1(LUT_READ)); - qspi_write32(priv->flags, ®s->lut[lut_base + 1], 0); - qspi_write32(priv->flags, ®s->lut[lut_base + 2], 0); - qspi_write32(priv->flags, ®s->lut[lut_base + 3], 0); + writel(LUT0(CMD, PAD1, OPCODE_RDID) | LUT1(READ, PAD1, 0x8), + base + QUADSPI_LUT(lut_base)); + + /* Write Register */ + lut_base = SEQID_WRSR * 4; + writel(LUT0(CMD, PAD1, OPCODE_WRSR) | LUT1(WRITE, PAD1, 0x2), + base + QUADSPI_LUT(lut_base)); + + /* Read Configuration Register */ + lut_base = SEQID_RDCR * 4; + writel(LUT0(CMD, PAD1, OPCODE_RDCR) | LUT1(READ, PAD1, 0x1), + base + QUADSPI_LUT(lut_base)); + + /* DDR QUAD Read */ + lut_base = SEQID_DDR_QUAD_READ * 4; + cmd = OPCODE_DDR_QUAD_READ; + addrlen = ADDR24BIT; + dummy = 6; + + writel(LUT0(CMD, PAD1, cmd) | LUT1(ADDR_DDR, PAD1, addrlen), + base + QUADSPI_LUT(lut_base)); + writel(LUT0(DUMMY, PAD1, dummy) | LUT1(READ_DDR, PAD4, rxfifo), + base + QUADSPI_LUT(lut_base + 1)); + writel(LUT0(JMP_ON_CS, PAD1, 0), + base + QUADSPI_LUT(lut_base + 2)); /* SUB SECTOR 4K ERASE */ lut_base = SEQID_BE_4K * 4; - qspi_write32(priv->flags, ®s->lut[lut_base], OPRND0(QSPI_CMD_BE_4K) | - PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) | - PAD1(LUT_PAD1) | INSTR1(LUT_ADDR)); + cmd = OPCODE_BE_4K; + addrlen = ADDR24BIT; + + writel(LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen), + base + QUADSPI_LUT(lut_base)); #ifdef CONFIG_SPI_FLASH_BAR /* * BRRD BRWR RDEAR WREAR are all supported, because it is hard to - * dynamically check whether to set BRRD BRWR or RDEAR WREAR during - * initialization. + * dynamically check whether to set BRRD BRWR or RDEAR WREAR. */ lut_base = SEQID_BRRD * 4; - qspi_write32(priv->flags, ®s->lut[lut_base], OPRND0(QSPI_CMD_BRRD) | - PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(1) | - PAD1(LUT_PAD1) | INSTR1(LUT_READ)); + cmd = OPCODE_BRRD; + writel(LUT0(CMD, PAD1, cmd) | LUT1(READ, PAD1, 0x1), + base + QUADSPI_LUT(lut_base)); lut_base = SEQID_BRWR * 4; - qspi_write32(priv->flags, ®s->lut[lut_base], OPRND0(QSPI_CMD_BRWR) | - PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(1) | - PAD1(LUT_PAD1) | INSTR1(LUT_WRITE)); + cmd = OPCODE_BRWR; + writel(LUT0(CMD, PAD1, cmd) | LUT1(WRITE, PAD1, 0x1), + base + QUADSPI_LUT(lut_base)); lut_base = SEQID_RDEAR * 4; - qspi_write32(priv->flags, ®s->lut[lut_base], OPRND0(QSPI_CMD_RDEAR) | - PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(1) | - PAD1(LUT_PAD1) | INSTR1(LUT_READ)); + cmd = OPCODE_RDEAR; + writel(LUT0(CMD, PAD1, cmd) | LUT1(READ, PAD1, 0x1), + base + QUADSPI_LUT(lut_base)); lut_base = SEQID_WREAR * 4; - qspi_write32(priv->flags, ®s->lut[lut_base], OPRND0(QSPI_CMD_WREAR) | - PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(1) | - PAD1(LUT_PAD1) | INSTR1(LUT_WRITE)); + cmd = OPCODE_WREAR; + writel(LUT0(CMD, PAD1, cmd) | LUT1(WRITE, PAD1, 0x1), + base + QUADSPI_LUT(lut_base)); #endif - /* Lock the LUT */ - qspi_write32(priv->flags, ®s->lutkey, LUT_KEY_VALUE); - qspi_write32(priv->flags, ®s->lckcr, QSPI_LCKCR_LOCK); -} - -#if defined(CONFIG_SYS_FSL_QSPI_AHB) -/* - * If we have changed the content of the flash by writing or erasing, - * we need to invalidate the AHB buffer. If we do not do so, we may read out - * the wrong data. The spec tells us reset the AHB domain and Serial Flash - * domain at the same time. - */ -static inline void qspi_ahb_invalid(struct fsl_qspi_priv *priv) -{ - struct fsl_qspi_regs *regs = priv->regs; - u32 reg; - reg = qspi_read32(priv->flags, ®s->mcr); - reg |= QSPI_MCR_SWRSTHD_MASK | QSPI_MCR_SWRSTSD_MASK; - qspi_write32(priv->flags, ®s->mcr, reg); - - /* - * The minimum delay : 1 AHB + 2 SFCK clocks. - * Delay 1 us is enough. - */ - udelay(1); - - reg &= ~(QSPI_MCR_SWRSTHD_MASK | QSPI_MCR_SWRSTSD_MASK); - qspi_write32(priv->flags, ®s->mcr, reg); -} - -/* Read out the data from the AHB buffer. */ -static inline void qspi_ahb_read(struct fsl_qspi_priv *priv, u8 *rxbuf, int len) -{ - struct fsl_qspi_regs *regs = priv->regs; - u32 mcr_reg; - - mcr_reg = qspi_read32(priv->flags, ®s->mcr); - - qspi_write32(priv->flags, ®s->mcr, - QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK | - QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE); - - /* Read out the data directly from the AHB buffer. */ - memcpy(rxbuf, (u8 *)(priv->cur_amba_base + priv->sf_addr), len); - - qspi_write32(priv->flags, ®s->mcr, mcr_reg); + fsl_qspi_lock_lut(q); } -static void qspi_enable_ddr_mode(struct fsl_qspi_priv *priv) +/*Enable DDR Read Mode*/ +static void fsl_enable_ddr_mode(struct fsl_qspi *q) { + u32 base = q->iobase; u32 reg, reg2; - struct fsl_qspi_regs *regs = priv->regs; - reg = qspi_read32(priv->flags, ®s->mcr); - /* Disable the module */ - qspi_write32(priv->flags, ®s->mcr, reg | QSPI_MCR_MDIS_MASK); + reg = readl(base + QUADSPI_MCR); + /* Firstly, disable the module */ + writel(reg | QUADSPI_MCR_MDIS_MASK, base + QUADSPI_MCR); /* Set the Sampling Register for DDR */ - reg2 = qspi_read32(priv->flags, ®s->smpr); - reg2 &= ~QSPI_SMPR_DDRSMP_MASK; - reg2 |= (2 << QSPI_SMPR_DDRSMP_SHIFT); - qspi_write32(priv->flags, ®s->smpr, reg2); + reg2 = readl(base + QUADSPI_SMPR); + reg2 &= ~QUADSPI_SMPR_DDRSMP_MASK; + reg2 |= (2 << QUADSPI_SMPR_DDRSMP_SHIFT); + writel(reg2, base + QUADSPI_SMPR); /* Enable the module again (enable the DDR too) */ - reg |= QSPI_MCR_DDR_EN_MASK; - /* Enable bit 29 for imx6sx */ - reg |= BIT(29); + reg |= QUADSPI_MCR_DDR_EN_MASK; + reg |= (1 << 29); /* enable bit 29 for imx6sx */ + + writel(reg, base + QUADSPI_MCR); - qspi_write32(priv->flags, ®s->mcr, reg); } /* @@ -402,715 +454,419 @@ static void qspi_enable_ddr_mode(struct fsl_qspi_priv *priv) * causes the controller to clear the buffer, and use the sequence pointed * by the QUADSPI_BFGENCR[SEQID] to initiate a read from the flash. */ -static void qspi_init_ahb_read(struct fsl_qspi_priv *priv) +static void fsl_qspi_init_abh_read(struct fsl_qspi *q) { - struct fsl_qspi_regs *regs = priv->regs; + u32 base = q->iobase; + + /* Map the SPI NOR to accessiable address, arrage max space for each bank*/ + writel(q->bank_memmap_phy[0] + QUADSPI_AHBMAP_BANK_MAXSIZE, + base + QUADSPI_SFA1AD); + writel(q->bank_memmap_phy[1] + QUADSPI_AHBMAP_BANK_MAXSIZE, + base + QUADSPI_SFA2AD); + writel(q->bank_memmap_phy[2] + QUADSPI_AHBMAP_BANK_MAXSIZE, + base + QUADSPI_SFB1AD); + writel(q->bank_memmap_phy[3] + QUADSPI_AHBMAP_BANK_MAXSIZE, + base + QUADSPI_SFB2AD); /* AHB configuration for access buffer 0/1/2 .*/ - qspi_write32(priv->flags, ®s->buf0cr, QSPI_BUFXCR_INVALID_MSTRID); - qspi_write32(priv->flags, ®s->buf1cr, QSPI_BUFXCR_INVALID_MSTRID); - qspi_write32(priv->flags, ®s->buf2cr, QSPI_BUFXCR_INVALID_MSTRID); - qspi_write32(priv->flags, ®s->buf3cr, QSPI_BUF3CR_ALLMST_MASK | - (0x80 << QSPI_BUF3CR_ADATSZ_SHIFT)); + writel(QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF0CR); + writel(QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF1CR); + writel(QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF2CR); + writel(QUADSPI_BUF3CR_ALLMST_MASK | (0x80 << QUADSPI_BUF3CR_ADATSZ_SHIFT), + base + QUADSPI_BUF3CR); /* We only use the buffer3 */ - qspi_write32(priv->flags, ®s->buf0ind, 0); - qspi_write32(priv->flags, ®s->buf1ind, 0); - qspi_write32(priv->flags, ®s->buf2ind, 0); + writel(0, base + QUADSPI_BUF0IND); + writel(0, base + QUADSPI_BUF1IND); + writel(0, base + QUADSPI_BUF2IND); - /* - * Set the default lut sequence for AHB Read. - * Parallel mode is disabled. - */ - qspi_write32(priv->flags, ®s->bfgencr, - SEQID_FAST_READ << QSPI_BFGENCR_SEQID_SHIFT); + /* Set the default lut sequence for AHB Read. */ + writel(SEQID_FAST_READ << QUADSPI_BFGENCR_SEQID_SHIFT, + base + QUADSPI_BFGENCR); /*Enable DDR Mode*/ - qspi_enable_ddr_mode(priv); + fsl_enable_ddr_mode(q); } -#endif -#ifdef CONFIG_SPI_FLASH_BAR -/* Bank register read/write, EAR register read/write */ -static void qspi_op_rdbank(struct fsl_qspi_priv *priv, u8 *rxbuf, u32 len) +static int fsl_qspi_init(struct fsl_qspi *q) { - struct fsl_qspi_regs *regs = priv->regs; - u32 reg, mcr_reg, data, seqid; - - mcr_reg = qspi_read32(priv->flags, ®s->mcr); - qspi_write32(priv->flags, ®s->mcr, - QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK | - QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE); - qspi_write32(priv->flags, ®s->rbct, QSPI_RBCT_RXBRD_USEIPS); + u32 base = q->iobase; + u32 reg; + void *ptr; - qspi_write32(priv->flags, ®s->sfar, priv->cur_amba_base); + ptr = malloc(sizeof(struct fsl_qspi_devtype_data)); + if (!ptr) { + puts("FSL_QSPI: per-type data not allocated !\n"); + return 1; + } + q->devtype_data = ptr; + q->devtype_data->rxfifo = 128; + q->devtype_data->txfifo = 512; - if (priv->cur_seqid == QSPI_CMD_BRRD) - seqid = SEQID_BRRD; - else - seqid = SEQID_RDEAR; + /* init the LUT table */ + fsl_qspi_init_lut(q); - qspi_write32(priv->flags, ®s->ipcr, - (seqid << QSPI_IPCR_SEQID_SHIFT) | len); + /* Disable the module */ + writel(QUADSPI_MCR_MDIS_MASK | QUADSPI_MCR_RESERVED_MASK, + base + QUADSPI_MCR); - /* Wait previous command complete */ - while (qspi_read32(priv->flags, ®s->sr) & QSPI_SR_BUSY_MASK) - ; + reg = readl(base + QUADSPI_SMPR); + writel(reg & ~(QUADSPI_SMPR_FSDLY_MASK + | QUADSPI_SMPR_FSPHS_MASK + | QUADSPI_SMPR_HSENA_MASK + | QUADSPI_SMPR_DDRSMP_MASK), base + QUADSPI_SMPR); - while (1) { - reg = qspi_read32(priv->flags, ®s->rbsr); - if (reg & QSPI_RBSR_RDBFL_MASK) { - data = qspi_read32(priv->flags, ®s->rbdr[0]); - data = qspi_endian_xchg(data); - memcpy(rxbuf, &data, len); - qspi_write32(priv->flags, ®s->mcr, - qspi_read32(priv->flags, ®s->mcr) | - QSPI_MCR_CLR_RXF_MASK); - break; - } - } + /* Enable the module */ + writel(QUADSPI_MCR_RESERVED_MASK | LE_64 << QUADSPI_MCR_END_CFG_SHIFT, + base + QUADSPI_MCR); - qspi_write32(priv->flags, ®s->mcr, mcr_reg); -} -#endif + /* We do not enable the interrupt */ -static void qspi_op_rdid(struct fsl_qspi_priv *priv, u32 *rxbuf, u32 len) -{ - struct fsl_qspi_regs *regs = priv->regs; - u32 mcr_reg, rbsr_reg, data, size; - int i; + /* init for AHB read */ + fsl_qspi_init_abh_read(q); - mcr_reg = qspi_read32(priv->flags, ®s->mcr); - qspi_write32(priv->flags, ®s->mcr, - QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK | - QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE); - qspi_write32(priv->flags, ®s->rbct, QSPI_RBCT_RXBRD_USEIPS); - - qspi_write32(priv->flags, ®s->sfar, priv->cur_amba_base); - - qspi_write32(priv->flags, ®s->ipcr, - (SEQID_RDID << QSPI_IPCR_SEQID_SHIFT) | 0); - while (qspi_read32(priv->flags, ®s->sr) & QSPI_SR_BUSY_MASK) - ; - - i = 0; - while ((RX_BUFFER_SIZE >= len) && (len > 0)) { - rbsr_reg = qspi_read32(priv->flags, ®s->rbsr); - if (rbsr_reg & QSPI_RBSR_RDBFL_MASK) { - data = qspi_read32(priv->flags, ®s->rbdr[i]); - data = qspi_endian_xchg(data); - size = (len < 4) ? len : 4; - memcpy(rxbuf, &data, size); - len -= size; - rxbuf++; - i++; - } - } + /* + * High level code use page_size and max_write_size to calculate + * the number of bytes that should be programmed once. + */ + q->slave.max_write_size = q->devtype_data->txfifo; - qspi_write32(priv->flags, ®s->mcr, mcr_reg); + return 0; } -#ifndef CONFIG_SYS_FSL_QSPI_AHB -/* If not use AHB read, read data from ip interface */ -static void qspi_op_read(struct fsl_qspi_priv *priv, u32 *rxbuf, u32 len) +void spi_init(void) { - struct fsl_qspi_regs *regs = priv->regs; - u32 mcr_reg, data; - int i, size; - u32 to_or_from; - - mcr_reg = qspi_read32(priv->flags, ®s->mcr); - qspi_write32(priv->flags, ®s->mcr, - QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK | - QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE); - qspi_write32(priv->flags, ®s->rbct, QSPI_RBCT_RXBRD_USEIPS); - - to_or_from = priv->sf_addr + priv->cur_amba_base; - - while (len > 0) { - WATCHDOG_RESET(); - - qspi_write32(priv->flags, ®s->sfar, to_or_from); - - size = (len > RX_BUFFER_SIZE) ? - RX_BUFFER_SIZE : len; - - qspi_write32(priv->flags, ®s->ipcr, - (SEQID_FAST_READ << QSPI_IPCR_SEQID_SHIFT) | - size); - while (qspi_read32(priv->flags, ®s->sr) & QSPI_SR_BUSY_MASK) - ; - - to_or_from += size; - len -= size; - - i = 0; - while ((RX_BUFFER_SIZE >= size) && (size > 0)) { - data = qspi_read32(priv->flags, ®s->rbdr[i]); - data = qspi_endian_xchg(data); - memcpy(rxbuf, &data, 4); - rxbuf++; - size -= 4; - i++; - } - qspi_write32(priv->flags, ®s->mcr, - qspi_read32(priv->flags, ®s->mcr) | - QSPI_MCR_CLR_RXF_MASK); - } - - qspi_write32(priv->flags, ®s->mcr, mcr_reg); } -#endif -static void qspi_op_write(struct fsl_qspi_priv *priv, u8 *txbuf, u32 len) +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode) { - struct fsl_qspi_regs *regs = priv->regs; - u32 mcr_reg, data, reg, status_reg, seqid; - int i, size, tx_size; - u32 to_or_from = 0; - - mcr_reg = qspi_read32(priv->flags, ®s->mcr); - qspi_write32(priv->flags, ®s->mcr, - QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK | - QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE); - qspi_write32(priv->flags, ®s->rbct, QSPI_RBCT_RXBRD_USEIPS); - - status_reg = 0; - while ((status_reg & FLASH_STATUS_WEL) != FLASH_STATUS_WEL) { - WATCHDOG_RESET(); - - qspi_write32(priv->flags, ®s->ipcr, - (SEQID_WREN << QSPI_IPCR_SEQID_SHIFT) | 0); - while (qspi_read32(priv->flags, ®s->sr) & QSPI_SR_BUSY_MASK) - ; - - qspi_write32(priv->flags, ®s->ipcr, - (SEQID_RDSR << QSPI_IPCR_SEQID_SHIFT) | 1); - while (qspi_read32(priv->flags, ®s->sr) & QSPI_SR_BUSY_MASK) - ; - - reg = qspi_read32(priv->flags, ®s->rbsr); - if (reg & QSPI_RBSR_RDBFL_MASK) { - status_reg = qspi_read32(priv->flags, ®s->rbdr[0]); - status_reg = qspi_endian_xchg(status_reg); - } - qspi_write32(priv->flags, ®s->mcr, - qspi_read32(priv->flags, ®s->mcr) | - QSPI_MCR_CLR_RXF_MASK); - } + struct fsl_qspi *q; + int ret; - /* Default is page programming */ - seqid = SEQID_PP; -#ifdef CONFIG_SPI_FLASH_BAR - if (priv->cur_seqid == QSPI_CMD_BRWR) - seqid = SEQID_BRWR; - else if (priv->cur_seqid == QSPI_CMD_WREAR) - seqid = SEQID_WREAR; -#endif - - to_or_from = priv->sf_addr + priv->cur_amba_base; - - qspi_write32(priv->flags, ®s->sfar, to_or_from); - - tx_size = (len > TX_BUFFER_SIZE) ? - TX_BUFFER_SIZE : len; - - size = tx_size / 4; - for (i = 0; i < size; i++) { - memcpy(&data, txbuf, 4); - data = qspi_endian_xchg(data); - qspi_write32(priv->flags, ®s->tbdr, data); - txbuf += 4; + if (bus > 1) { + puts("FSL_QSPI: Not a valid bus !\n"); + return NULL; } - size = tx_size % 4; - if (size) { - data = 0; - memcpy(&data, txbuf, size); - data = qspi_endian_xchg(data); - qspi_write32(priv->flags, ®s->tbdr, data); + if (cs > 1) { + puts("FSL_QSPI: Not a valid cs !\n"); + return NULL; } - qspi_write32(priv->flags, ®s->ipcr, - (seqid << QSPI_IPCR_SEQID_SHIFT) | tx_size); - while (qspi_read32(priv->flags, ®s->sr) & QSPI_SR_BUSY_MASK) - ; - - qspi_write32(priv->flags, ®s->mcr, mcr_reg); -} - -static void qspi_op_rdsr(struct fsl_qspi_priv *priv, void *rxbuf, u32 len) -{ - struct fsl_qspi_regs *regs = priv->regs; - u32 mcr_reg, reg, data; - - mcr_reg = qspi_read32(priv->flags, ®s->mcr); - qspi_write32(priv->flags, ®s->mcr, - QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK | - QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE); - qspi_write32(priv->flags, ®s->rbct, QSPI_RBCT_RXBRD_USEIPS); - - qspi_write32(priv->flags, ®s->sfar, priv->cur_amba_base); + q = spi_alloc_slave(struct fsl_qspi, bus, cs); + if (!q) { + puts("FSL_QSPI: SPI Slave not allocated !\n"); + return NULL; + } - qspi_write32(priv->flags, ®s->ipcr, - (SEQID_RDSR << QSPI_IPCR_SEQID_SHIFT) | 0); - while (qspi_read32(priv->flags, ®s->sr) & QSPI_SR_BUSY_MASK) - ; + q->iobase = CONFIG_QSPI_BASE; + q->bank_memmap_phy[0] = CONFIG_QSPI_MEMMAP_BASE; + q->bank_memmap_phy[1] = q->bank_memmap_phy[0] + QUADSPI_AHBMAP_BANK_MAXSIZE; + q->bank_memmap_phy[2] = q->bank_memmap_phy[1] + QUADSPI_AHBMAP_BANK_MAXSIZE; + q->bank_memmap_phy[3] = q->bank_memmap_phy[2] + QUADSPI_AHBMAP_BANK_MAXSIZE; - while (1) { - reg = qspi_read32(priv->flags, ®s->rbsr); - if (reg & QSPI_RBSR_RDBFL_MASK) { - data = qspi_read32(priv->flags, ®s->rbdr[0]); - data = qspi_endian_xchg(data); - memcpy(rxbuf, &data, len); - qspi_write32(priv->flags, ®s->mcr, - qspi_read32(priv->flags, ®s->mcr) | - QSPI_MCR_CLR_RXF_MASK); - break; - } + /* Init the QuadSPI controller */ + ret = fsl_qspi_init(q); + if (ret) { + puts("FSL_QSPI: init failed!\n"); + return NULL; } - qspi_write32(priv->flags, ®s->mcr, mcr_reg); + return &q->slave; } -static void qspi_op_erase(struct fsl_qspi_priv *priv) +void spi_free_slave(struct spi_slave *slave) { - struct fsl_qspi_regs *regs = priv->regs; - u32 mcr_reg; - u32 to_or_from = 0; - - mcr_reg = qspi_read32(priv->flags, ®s->mcr); - qspi_write32(priv->flags, ®s->mcr, - QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK | - QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE); - qspi_write32(priv->flags, ®s->rbct, QSPI_RBCT_RXBRD_USEIPS); - - to_or_from = priv->sf_addr + priv->cur_amba_base; - qspi_write32(priv->flags, ®s->sfar, to_or_from); - - qspi_write32(priv->flags, ®s->ipcr, - (SEQID_WREN << QSPI_IPCR_SEQID_SHIFT) | 0); - while (qspi_read32(priv->flags, ®s->sr) & QSPI_SR_BUSY_MASK) - ; - - if (priv->cur_seqid == QSPI_CMD_SE) { - qspi_write32(priv->flags, ®s->ipcr, - (SEQID_SE << QSPI_IPCR_SEQID_SHIFT) | 0); - } else if (priv->cur_seqid == QSPI_CMD_BE_4K) { - qspi_write32(priv->flags, ®s->ipcr, - (SEQID_BE_4K << QSPI_IPCR_SEQID_SHIFT) | 0); - } - while (qspi_read32(priv->flags, ®s->sr) & QSPI_SR_BUSY_MASK) - ; + struct fsl_qspi *q; - qspi_write32(priv->flags, ®s->mcr, mcr_reg); + q = container_of(slave, struct fsl_qspi, slave); + free(q->devtype_data); + free(q); } -int qspi_xfer(struct fsl_qspi_priv *priv, unsigned int bitlen, - const void *dout, void *din, unsigned long flags) +int spi_claim_bus(struct spi_slave *q) { - u32 bytes = DIV_ROUND_UP(bitlen, 8); - static u32 wr_sfaddr; - u32 txbuf; - - if (dout) { - if (flags & SPI_XFER_BEGIN) { - priv->cur_seqid = *(u8 *)dout; - memcpy(&txbuf, dout, 4); - } - - if (flags == SPI_XFER_END) { - priv->sf_addr = wr_sfaddr; - qspi_op_write(priv, (u8 *)dout, bytes); - return 0; - } - - if (priv->cur_seqid == QSPI_CMD_FAST_READ) { - priv->sf_addr = swab32(txbuf) & OFFSET_BITS_MASK; - } else if ((priv->cur_seqid == QSPI_CMD_SE) || - (priv->cur_seqid == QSPI_CMD_BE_4K)) { - priv->sf_addr = swab32(txbuf) & OFFSET_BITS_MASK; - qspi_op_erase(priv); - } else if (priv->cur_seqid == QSPI_CMD_PP) { - wr_sfaddr = swab32(txbuf) & OFFSET_BITS_MASK; - } else if ((priv->cur_seqid == QSPI_CMD_BRWR) || - (priv->cur_seqid == QSPI_CMD_WREAR)) { -#ifdef CONFIG_SPI_FLASH_BAR - wr_sfaddr = 0; -#endif - } - } + return 0; +} - if (din) { - if (priv->cur_seqid == QSPI_CMD_FAST_READ) { -#ifdef CONFIG_SYS_FSL_QSPI_AHB - qspi_ahb_read(priv, din, bytes); -#else - qspi_op_read(priv, din, bytes); -#endif - } else if (priv->cur_seqid == QSPI_CMD_RDID) - qspi_op_rdid(priv, din, bytes); - else if (priv->cur_seqid == QSPI_CMD_RDSR) - qspi_op_rdsr(priv, din, bytes); +void spi_release_bus(struct spi_slave *q) +{ +} + +/* Get the SEQID for the command */ +static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd) +{ + switch (cmd) { + case OPCODE_QUAD_READ: + case OPCODE_QUAD_READ_4B: + return SEQID_QUAD_READ; + case OPCODE_FAST_READ: + case OPCODE_FAST_READ_4B: + return SEQID_FAST_READ; + case OPCODE_WREN: + return SEQID_WREN; + case OPCODE_RDSR: + return SEQID_RDSR; + case OPCODE_SE: + return SEQID_SE; + case OPCODE_CHIP_ERASE: + return SEQID_CHIP_ERASE; + case OPCODE_PP: + case OPCODE_PP_4B: + return SEQID_PP; + case OPCODE_RDID: + return SEQID_RDID; + case OPCODE_WRSR: + return SEQID_WRSR; + case OPCODE_RDCR: + return SEQID_RDCR; + case OPCODE_DDR_QUAD_READ: + return SEQID_DDR_QUAD_READ; + case OPCODE_BE_4K: + return SEQID_BE_4K; #ifdef CONFIG_SPI_FLASH_BAR - else if ((priv->cur_seqid == QSPI_CMD_BRRD) || - (priv->cur_seqid == QSPI_CMD_RDEAR)) { - priv->sf_addr = 0; - qspi_op_rdbank(priv, din, bytes); - } + case OPCODE_BRRD: + return SEQID_BRRD; + case OPCODE_BRWR: + return SEQID_BRWR; + case OPCODE_RDEAR: + return SEQID_RDEAR; + case OPCODE_WREAR: + return SEQID_WREAR; #endif + default: + break; } - -#ifdef CONFIG_SYS_FSL_QSPI_AHB - if ((priv->cur_seqid == QSPI_CMD_SE) || - (priv->cur_seqid == QSPI_CMD_PP) || - (priv->cur_seqid == QSPI_CMD_BE_4K) || - (priv->cur_seqid == QSPI_CMD_WREAR) || - (priv->cur_seqid == QSPI_CMD_BRWR)) - qspi_ahb_invalid(priv); -#endif - - return 0; + return -1; } -void qspi_module_disable(struct fsl_qspi_priv *priv, u8 disable) +/* return 1 on success */ +static int fsl_qspi_wait_to_complete(struct fsl_qspi *q) { - u32 mcr_val; + u32 base = q->iobase; + u32 reg; - mcr_val = qspi_read32(priv->flags, &priv->regs->mcr); - if (disable) - mcr_val |= QSPI_MCR_MDIS_MASK; - else - mcr_val &= ~QSPI_MCR_MDIS_MASK; - qspi_write32(priv->flags, &priv->regs->mcr, mcr_val); + /*printf("QuadSPI: poll the busy bit\n");*/ + while (1) { + reg = readl(base + QUADSPI_SR); + if (reg & 1) + continue; + else + return 1; + } + + return 0; } -void qspi_cfg_smpr(struct fsl_qspi_priv *priv, u32 clear_bits, u32 set_bits) +/* + * If we have changed the content of the flash by writing or erasing, + * we need to invalidate the AHB buffer. If we do not do so, we may read out + * the wrong data. The spec tells us reset the AHB domain and Serial Flash + * domain at the same time. + */ +static inline void fsl_qspi_invalid(struct fsl_qspi *q) { - u32 smpr_val; + u32 reg; - smpr_val = qspi_read32(priv->flags, &priv->regs->smpr); - smpr_val &= ~clear_bits; - smpr_val |= set_bits; - qspi_write32(priv->flags, &priv->regs->smpr, smpr_val); -} -#ifndef CONFIG_DM_SPI -static unsigned long spi_bases[] = { - QSPI0_BASE_ADDR, -#ifdef CONFIG_MX6SX - QSPI1_BASE_ADDR, -#endif -}; + reg = readl(q->iobase + QUADSPI_MCR); + reg |= QUADSPI_MCR_SWRSTHD_MASK | QUADSPI_MCR_SWRSTSD_MASK; + writel(reg, q->iobase + QUADSPI_MCR); -static unsigned long amba_bases[] = { - QSPI0_AMBA_BASE, -#ifdef CONFIG_MX6SX - QSPI1_AMBA_BASE, -#endif -}; + /* + * The minimum delay : 1 AHB + 2 SFCK clocks. + * Delay 1 us is enough. + */ + udelay(1); -static inline struct fsl_qspi *to_qspi_spi(struct spi_slave *slave) -{ - return container_of(slave, struct fsl_qspi, slave); + reg &= ~(QUADSPI_MCR_SWRSTHD_MASK | QUADSPI_MCR_SWRSTSD_MASK); + writel(reg, q->iobase + QUADSPI_MCR); } -struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, - unsigned int max_hz, unsigned int mode) +static int +fsl_qspi_runcmd(struct fsl_qspi *q, u8 cmd, unsigned int addr, int len) { - struct fsl_qspi *qspi; - struct fsl_qspi_regs *regs; - u32 total_size; - - if (bus >= ARRAY_SIZE(spi_bases)) - return NULL; - - if (cs >= FSL_QSPI_FLASH_NUM) - return NULL; - - qspi = spi_alloc_slave(struct fsl_qspi, bus, cs); - if (!qspi) - return NULL; - -#ifdef CONFIG_SYS_FSL_QSPI_BE - qspi->priv.flags |= QSPI_FLAG_REGMAP_ENDIAN_BIG; -#endif - - regs = (struct fsl_qspi_regs *)spi_bases[bus]; - qspi->priv.regs = regs; - /* - * According cs, use different amba_base to choose the - * corresponding flash devices. - * - * If not, only one flash device is used even if passing - * different cs using `sf probe` - */ - qspi->priv.cur_amba_base = amba_bases[bus] + cs * FSL_QSPI_FLASH_SIZE; - - qspi->slave.max_write_size = TX_BUFFER_SIZE; + u32 base = q->iobase; + int seqid; + u32 reg, reg2; + int err; + int bank_id; + + /* check the SR first, wait previous cmd completed*/ + do { + reg2 = readl(base + QUADSPI_SR); + if (reg2 & (QUADSPI_SR_IP_ACC_MASK | QUADSPI_SR_AHB_ACC_MASK)) { + udelay(1); + printf("The controller is busy, 0x%x\n", reg2); + continue; + } + break; + } while (1); - qspi_write32(qspi->priv.flags, ®s->mcr, - QSPI_MCR_RESERVED_MASK | QSPI_MCR_MDIS_MASK); + /* save the reg */ + reg = readl(base + QUADSPI_MCR); - qspi_cfg_smpr(&qspi->priv, - ~(QSPI_SMPR_FSDLY_MASK | QSPI_SMPR_DDRSMP_MASK | - QSPI_SMPR_FSPHS_MASK | QSPI_SMPR_HSENA_MASK), 0); + /* get the bank index */ + bank_id = ((q->slave.bus) << 1) + (q->slave.cs); - total_size = FSL_QSPI_FLASH_SIZE * FSL_QSPI_FLASH_NUM; - /* - * Any read access to non-implemented addresses will provide - * undefined results. - * - * In case single die flash devices, TOP_ADDR_MEMA2 and - * TOP_ADDR_MEMB2 should be initialized/programmed to - * TOP_ADDR_MEMA1 and TOP_ADDR_MEMB1 respectively - in effect, - * setting the size of these devices to 0. This would ensure - * that the complete memory map is assigned to only one flash device. - */ - qspi_write32(qspi->priv.flags, ®s->sfa1ad, - FSL_QSPI_FLASH_SIZE | amba_bases[bus]); - qspi_write32(qspi->priv.flags, ®s->sfa2ad, - FSL_QSPI_FLASH_SIZE | amba_bases[bus]); - qspi_write32(qspi->priv.flags, ®s->sfb1ad, - total_size | amba_bases[bus]); - qspi_write32(qspi->priv.flags, ®s->sfb2ad, - total_size | amba_bases[bus]); - - qspi_set_lut(&qspi->priv); - -#ifdef CONFIG_SYS_FSL_QSPI_AHB - qspi_init_ahb_read(&qspi->priv); -#endif + writel(q->bank_memmap_phy[bank_id] + addr, base + QUADSPI_SFAR); + writel(QUADSPI_RBCT_WMRK_MASK | QUADSPI_RBCT_RXBRD_USEIPS, + base + QUADSPI_RBCT); + writel(reg | QUADSPI_MCR_CLR_RXF_MASK, base + QUADSPI_MCR); - qspi_module_disable(&qspi->priv, 0); + /* trigger the LUT now */ + seqid = fsl_qspi_get_seqid(q, cmd); + writel((seqid << QUADSPI_IPCR_SEQID_SHIFT) | len, base + QUADSPI_IPCR); - return &qspi->slave; -} + /* Wait until completed */ + err = fsl_qspi_wait_to_complete(q); + if (!err) + err = -1; + else + err = 0; -void spi_free_slave(struct spi_slave *slave) -{ - struct fsl_qspi *qspi = to_qspi_spi(slave); + /* restore the MCR */ + writel(reg, base + QUADSPI_MCR); - free(qspi); + /* After switch BANK, AHB buffer should also be invalid. */ + if ((OPCODE_SE == cmd) || (OPCODE_PP == cmd) || + (OPCODE_BE_4K == cmd) || (OPCODE_WREAR == cmd) || + (OPCODE_BRWR == cmd)) + fsl_qspi_invalid(q); + return err; } -int spi_claim_bus(struct spi_slave *slave) +/* + * An IC bug makes us to re-arrange the 32-bit data. + * The following chips, such as IMX6SLX, have fixed this bug. + */ +static inline u32 fsl_qspi_endian_xchg(struct fsl_qspi *q, u32 a) { - return 0; + return a; } -void spi_release_bus(struct spi_slave *slave) +/* Read out the data from the AHB buffer. */ +static void fsl_qspi_ahb_read(struct fsl_qspi *q, + unsigned int addr, int len, u8 *rxbuf) { - /* Nothing to do */ -} + int bank_id; -int spi_xfer(struct spi_slave *slave, unsigned int bitlen, - const void *dout, void *din, unsigned long flags) -{ - struct fsl_qspi *qspi = to_qspi_spi(slave); + /* get the bank index */ + bank_id = ((q->slave.bus) << 1) + (q->slave.cs); - return qspi_xfer(&qspi->priv, bitlen, dout, din, flags); + /* Read out the data directly from the AHB buffer.*/ + memcpy(rxbuf, (u8 *)(q->bank_memmap_phy[bank_id] + addr), len); } -void spi_init(void) -{ - /* Nothing to do */ -} -#else -static int fsl_qspi_child_pre_probe(struct udevice *dev) +/* Read out the data from the QUADSPI_RBDR buffer registers. */ +static void fsl_qspi_ip_read(struct fsl_qspi *q, int len, u8 *rxbuf) { - struct spi_slave *slave = dev_get_parent_priv(dev); + u32 tmp; + int i = 0; - slave->max_write_size = TX_BUFFER_SIZE; + while (len > 0) { + tmp = readl(q->iobase + QUADSPI_RBDR + i * 4); + tmp = fsl_qspi_endian_xchg(q, tmp); + + if (len >= 4) { + memcpy(rxbuf, &tmp, 4); + rxbuf += 4; + } else { + memcpy(rxbuf, &tmp, len); + break; + } - return 0; + len -= 4; + i++; + } } -static int fsl_qspi_probe(struct udevice *bus) +/* Write data to the QUADSPI_TBDR buffer registers. */ +static void fsl_qspi_write_data(struct fsl_qspi *q, int len, u8* txbuf) { - u32 total_size; - struct fsl_qspi_platdata *plat = dev_get_platdata(bus); - struct fsl_qspi_priv *priv = dev_get_priv(bus); - struct dm_spi_bus *dm_spi_bus; - - dm_spi_bus = bus->uclass_priv; - - dm_spi_bus->max_hz = plat->speed_hz; + u32 tmp; + u32 t1, t2; + int j; - priv->regs = (struct fsl_qspi_regs *)(uintptr_t)plat->reg_base; - priv->flags = plat->flags; + /* clear the TX FIFO. */ + tmp = readl(q->iobase + QUADSPI_MCR); + writel(tmp | QUADSPI_MCR_CLR_TXF_MASK, q->iobase + QUADSPI_MCR); - priv->speed_hz = plat->speed_hz; - priv->amba_base[0] = plat->amba_base; - priv->amba_total_size = plat->amba_total_size; - priv->flash_num = plat->flash_num; - priv->num_chipselect = plat->num_chipselect; + /* fill the TX data to the FIFO */ + t2 = len % 4; + t1 = len >> 2; /* 4 Bytes aligned */ - qspi_write32(priv->flags, &priv->regs->mcr, - QSPI_MCR_RESERVED_MASK | QSPI_MCR_MDIS_MASK); + for (j = 0; j < t1; j++) { + memcpy(&tmp, txbuf, 4); + tmp = fsl_qspi_endian_xchg(q, tmp); + writel(tmp, q->iobase + QUADSPI_TBDR); + txbuf += 4; + } - qspi_cfg_smpr(priv, ~(QSPI_SMPR_FSDLY_MASK | QSPI_SMPR_DDRSMP_MASK | - QSPI_SMPR_FSPHS_MASK | QSPI_SMPR_HSENA_MASK), 0); + if (t2) { + tmp = 0; + memcpy(&tmp, txbuf, t2); + tmp = fsl_qspi_endian_xchg(q, tmp); + writel(tmp, q->iobase + QUADSPI_TBDR); + } - total_size = FSL_QSPI_FLASH_SIZE * FSL_QSPI_FLASH_NUM; - /* - * Any read access to non-implemented addresses will provide - * undefined results. - * - * In case single die flash devices, TOP_ADDR_MEMA2 and - * TOP_ADDR_MEMB2 should be initialized/programmed to - * TOP_ADDR_MEMA1 and TOP_ADDR_MEMB1 respectively - in effect, - * setting the size of these devices to 0. This would ensure - * that the complete memory map is assigned to only one flash device. - */ - qspi_write32(priv->flags, &priv->regs->sfa1ad, - FSL_QSPI_FLASH_SIZE | priv->amba_base[0]); - qspi_write32(priv->flags, &priv->regs->sfa2ad, - FSL_QSPI_FLASH_SIZE | priv->amba_base[0]); - qspi_write32(priv->flags, &priv->regs->sfb1ad, - total_size | priv->amba_base[0]); - qspi_write32(priv->flags, &priv->regs->sfb2ad, - total_size | priv->amba_base[0]); - - qspi_set_lut(priv); - -#ifdef CONFIG_SYS_FSL_QSPI_AHB - qspi_init_ahb_read(priv); +#if defined(CONFIG_MX7D) || defined(CONFIG_MX6UL) + u32 t3; + /* iMX7D and MX6UL TXFIFO must be at least 16 bytes*/ + t3 = t1 + ((t2 + 3) >> 2); + for (; t3 < 4; t3++) + writel(0, q->iobase + QUADSPI_TBDR); #endif - qspi_module_disable(priv, 0); - - return 0; } -static int fsl_qspi_ofdata_to_platdata(struct udevice *bus) -{ - struct reg_data { - u32 addr; - u32 size; - } regs_data[2]; - struct fsl_qspi_platdata *plat = bus->platdata; - const void *blob = gd->fdt_blob; - int node = bus->of_offset; - int ret, flash_num = 0, subnode; - - if (fdtdec_get_bool(blob, node, "big-endian")) - plat->flags |= QSPI_FLAG_REGMAP_ENDIAN_BIG; - - ret = fdtdec_get_int_array(blob, node, "reg", (u32 *)regs_data, - sizeof(regs_data)/sizeof(u32)); - if (ret) { - debug("Error: can't get base addresses (ret = %d)!\n", ret); - return -ENOMEM; +/* see the spi_flash_read_write() */ +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, + void *din, unsigned long flags) +{ + struct fsl_qspi *q = container_of(slave, struct fsl_qspi, slave); + int len = bitlen / 8; + int ret = 0; + u8 *buf; + static u8 opcode; + static unsigned int addr; + + if (!opcode && (flags & SPI_XFER_BEGIN)) { + /* spi_xfer for cmd phase */ + buf = (u8 *)dout; + opcode = buf[0]; + if (len > 1) + addr = buf[1] << 16 | buf[2] << 8 | buf[3]; + + /* if transfer cmd only */ + if (flags & SPI_XFER_END) + ret = fsl_qspi_runcmd(q, opcode, addr, 0); + + } else if (opcode) { + /* spi_xfer for data phase */ + if (din) { + /* read*/ + buf = (u8 *)din; + if (OPCODE_FAST_READ == opcode) { + fsl_qspi_ahb_read(q, addr, len, buf); + } else { + ret = fsl_qspi_runcmd(q, opcode, addr, len); + if (!ret) + fsl_qspi_ip_read(q, len, buf); + } + } else if (dout) { + /* write data, prepare data first */ + buf = (u8 *)dout; + fsl_qspi_write_data(q, len, buf); + /* then run page program cmd */ + ret = fsl_qspi_runcmd(q, opcode, addr, len); + } } - /* Count flash numbers */ - fdt_for_each_subnode(blob, subnode, node) - ++flash_num; - - if (flash_num == 0) { - debug("Error: Missing flashes!\n"); - return -ENODEV; + if (ret || (flags & SPI_XFER_END)) { + opcode = 0; + addr = 0; } - plat->speed_hz = fdtdec_get_int(blob, node, "spi-max-frequency", - FSL_QSPI_DEFAULT_SCK_FREQ); - plat->num_chipselect = fdtdec_get_int(blob, node, "num-cs", - FSL_QSPI_MAX_CHIPSELECT_NUM); - - plat->reg_base = regs_data[0].addr; - plat->amba_base = regs_data[1].addr; - plat->amba_total_size = regs_data[1].size; - plat->flash_num = flash_num; - - debug("%s: regs=<0x%x> <0x%x, 0x%x>, max-frequency=%d, endianess=%s\n", - __func__, - plat->reg_base, - plat->amba_base, - plat->amba_total_size, - plat->speed_hz, - plat->flags & QSPI_FLAG_REGMAP_ENDIAN_BIG ? "be" : "le" - ); - - return 0; -} - -static int fsl_qspi_xfer(struct udevice *dev, unsigned int bitlen, - const void *dout, void *din, unsigned long flags) -{ - struct fsl_qspi_priv *priv; - struct udevice *bus; - - bus = dev->parent; - priv = dev_get_priv(bus); - - return qspi_xfer(priv, bitlen, dout, din, flags); -} - -static int fsl_qspi_claim_bus(struct udevice *dev) -{ - struct fsl_qspi_priv *priv; - struct udevice *bus; - struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev); - - bus = dev->parent; - priv = dev_get_priv(bus); - - priv->cur_amba_base = - priv->amba_base[0] + FSL_QSPI_FLASH_SIZE * slave_plat->cs; - - qspi_module_disable(priv, 0); - - return 0; -} - -static int fsl_qspi_release_bus(struct udevice *dev) -{ - struct fsl_qspi_priv *priv; - struct udevice *bus; - - bus = dev->parent; - priv = dev_get_priv(bus); - - qspi_module_disable(priv, 1); - - return 0; -} - -static int fsl_qspi_set_speed(struct udevice *bus, uint speed) -{ - /* Nothing to do */ - return 0; -} - -static int fsl_qspi_set_mode(struct udevice *bus, uint mode) -{ - /* Nothing to do */ - return 0; + return ret; } - -static const struct dm_spi_ops fsl_qspi_ops = { - .claim_bus = fsl_qspi_claim_bus, - .release_bus = fsl_qspi_release_bus, - .xfer = fsl_qspi_xfer, - .set_speed = fsl_qspi_set_speed, - .set_mode = fsl_qspi_set_mode, -}; - -static const struct udevice_id fsl_qspi_ids[] = { - { .compatible = "fsl,vf610-qspi" }, - { .compatible = "fsl,imx6sx-qspi" }, - { } -}; - -U_BOOT_DRIVER(fsl_qspi) = { - .name = "fsl_qspi", - .id = UCLASS_SPI, - .of_match = fsl_qspi_ids, - .ops = &fsl_qspi_ops, - .ofdata_to_platdata = fsl_qspi_ofdata_to_platdata, - .platdata_auto_alloc_size = sizeof(struct fsl_qspi_platdata), - .priv_auto_alloc_size = sizeof(struct fsl_qspi_priv), - .probe = fsl_qspi_probe, - .child_pre_probe = fsl_qspi_child_pre_probe, -}; -#endif |