/*
 * Freescale QuadSPI driver.
 *
 * Copyright (C) 2014 Freescale Semiconductor, Inc.
 *
 * 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>

#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

/*
 * 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

/*
 * 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
#define SEQID_SE		4
#define SEQID_CHIP_ERASE	5
#define SEQID_PP		6
#define SEQID_RDID		7
#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		12
#define SEQID_BRWR		13
#define SEQID_RDEAR		14
#define SEQID_WREAR		15
#endif

/* 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	OPCODE_WREAR		0xc5	/* EAR register write */
#define	OPCODE_RDEAR		0xc8	/* EAR reigster read */

/* Used for Spansion flashes only. */
#define	OPCODE_BRRD		0x16	/* Bank register read */
#define	OPCODE_BRWR		0x17	/* Bank register write */

/* 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 */

#define SR_QUAD_EN_MX           0x40    /* Macronix Quad I/O */

/* Configuration Register bits. */
#define CR_QUAD_EN_SPAN		0x2     /* Spansion Quad I/O */

/* Endianess Configuration */
#define BE_64	0x00
#define LE_32	0x01
#define BE_32	0x02
#define LE_64	0x03



enum fsl_qspi_devtype {
	FSL_QUADSPI_VYBRID,
	FSL_QUADSPI_IMX6SX,
};

struct fsl_qspi_devtype_data {
	enum fsl_qspi_devtype devtype;
	int rxfifo;
	int txfifo;
};

struct fsl_qspi {
	struct spi_slave slave;
	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;
};

static inline void fsl_qspi_unlock_lut(struct fsl_qspi *q)
{
	writel(QUADSPI_LUTKEY_VALUE, q->iobase + QUADSPI_LUTKEY);
	writel(QUADSPI_LCKER_UNLOCK, q->iobase + QUADSPI_LCKCR);
}

static inline void fsl_qspi_lock_lut(struct fsl_qspi *q)
{
	writel(QUADSPI_LUTKEY_VALUE, q->iobase + QUADSPI_LUTKEY);
	writel(QUADSPI_LCKER_LOCK, q->iobase + QUADSPI_LCKCR);
}

static void fsl_qspi_init_lut(struct fsl_qspi *q)
{
	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);

	/* Quad Read */
	lut_base = SEQID_QUAD_READ * 4;

	/* 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;
	writel(LUT0(CMD, PAD1, OPCODE_WREN), base + QUADSPI_LUT(lut_base));

	/* Fast Read */
	lut_base = SEQID_FAST_READ * 4;
	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;
	writel(LUT0(CMD, PAD1, OPCODE_RDSR) | LUT1(READ, PAD1, 0x1),
			base + QUADSPI_LUT(lut_base));

	/* Erase a sector */
	lut_base = SEQID_SE * 4;
	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;
	writel(LUT0(CMD, PAD1, OPCODE_CHIP_ERASE),
			base + QUADSPI_LUT(lut_base));

	/* READ ID */
	lut_base = SEQID_RDID * 4;
	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;
	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.
	 */
	lut_base = SEQID_BRRD * 4;
	cmd = OPCODE_BRRD;
	writel(LUT0(CMD, PAD1, cmd) | LUT1(READ, PAD1, 0x1),
	       base + QUADSPI_LUT(lut_base));

	lut_base = SEQID_BRWR * 4;
	cmd = OPCODE_BRWR;
	writel(LUT0(CMD, PAD1, cmd) | LUT1(WRITE, PAD1, 0x1),
	       base + QUADSPI_LUT(lut_base));

	lut_base = SEQID_RDEAR * 4;
	cmd = OPCODE_RDEAR;
	writel(LUT0(CMD, PAD1, cmd) | LUT1(READ, PAD1, 0x1),
	       base + QUADSPI_LUT(lut_base));

	lut_base = SEQID_WREAR * 4;
	cmd = OPCODE_WREAR;
	writel(LUT0(CMD, PAD1, cmd) | LUT1(WRITE, PAD1, 0x1),
	       base + QUADSPI_LUT(lut_base));
#endif

	fsl_qspi_lock_lut(q);
}

/*Enable DDR Read Mode*/
static void fsl_enable_ddr_mode(struct fsl_qspi *q)
{
	u32 base = q->iobase;
	u32 reg, reg2;

	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 = 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 |= QUADSPI_MCR_DDR_EN_MASK;
	reg |= (1 << 29); /* enable bit 29 for imx6sx */

	writel(reg, base + QUADSPI_MCR);

}

/*
 * There are two different ways to read out the data from the flash:
 *  the "IP Command Read" and the "AHB Command Read".
 *
 * The IC guy suggests we use the "AHB Command Read" which is faster
 * then the "IP Command Read". (What's more is that there is a bug in
 * the "IP Command Read" in the Vybrid.)
 *
 * After we set up the registers for the "AHB Command Read", we can use
 * the memcpy to read the data directly. A "missed" access to the buffer
 * 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 fsl_qspi_init_abh_read(struct fsl_qspi *q)
{
	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 .*/
	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 */
	writel(0, base + QUADSPI_BUF0IND);
	writel(0, base + QUADSPI_BUF1IND);
	writel(0, base + QUADSPI_BUF2IND);

	/* Set the default lut sequence for AHB Read. */
	writel(SEQID_FAST_READ << QUADSPI_BFGENCR_SEQID_SHIFT,
		base + QUADSPI_BFGENCR);

	/*Enable DDR Mode*/
	fsl_enable_ddr_mode(q);
}

static int fsl_qspi_init(struct fsl_qspi *q)
{
	u32 base = q->iobase;
	u32 reg;
	void *ptr;

	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;

	/* init the LUT table */
	fsl_qspi_init_lut(q);

	/* Disable the module */
	writel(QUADSPI_MCR_MDIS_MASK | QUADSPI_MCR_RESERVED_MASK,
			base + QUADSPI_MCR);

	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);

	/* Enable the module */
	writel(QUADSPI_MCR_RESERVED_MASK | LE_64 << QUADSPI_MCR_END_CFG_SHIFT,
		base + QUADSPI_MCR);

	/* We do not enable the interrupt */

	/* init for AHB read */
	fsl_qspi_init_abh_read(q);

	/*
	 * 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;

	return 0;
}

void spi_init(void)
{
}

struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
		unsigned int max_hz, unsigned int mode)
{
	struct fsl_qspi *q;
	int ret;

	if (bus > 1) {
		puts("FSL_QSPI: Not a valid bus !\n");
		return NULL;
	}

	if (cs > 1) {
		puts("FSL_QSPI: Not a valid cs !\n");
		return NULL;
	}

	q = spi_alloc_slave(struct fsl_qspi, bus, cs);
	if (!q) {
		puts("FSL_QSPI: SPI Slave not allocated !\n");
		return NULL;
	}

	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;

	/* Init the QuadSPI controller */
	ret = fsl_qspi_init(q);
	if (ret) {
		puts("FSL_QSPI: init failed!\n");
		return NULL;
	}

	return &q->slave;
}

void spi_free_slave(struct spi_slave *slave)
{
	struct fsl_qspi *q;

	q = container_of(slave, struct fsl_qspi, slave);
	free(q->devtype_data);
	free(q);
}

int spi_claim_bus(struct spi_slave *q)
{
	return 0;
}

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
	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;
	}
	return -1;
}

/* return 1 on success */
static int fsl_qspi_wait_to_complete(struct fsl_qspi *q)
{
	u32 base = q->iobase;
	u32 reg;

	/*printf("QuadSPI: poll the busy bit\n");*/
	while (1) {
		reg = readl(base + QUADSPI_SR);
		if (reg & 1)
			continue;
		else
			return 1;
	}

	return 0;
}

/*
 * 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 reg;

    reg = readl(q->iobase + QUADSPI_MCR);
    reg |= QUADSPI_MCR_SWRSTHD_MASK | QUADSPI_MCR_SWRSTSD_MASK;
    writel(reg, q->iobase + QUADSPI_MCR);

    /*
     * The minimum delay : 1 AHB + 2 SFCK clocks.
     * Delay 1 us is enough.
     */
    udelay(1);

    reg &= ~(QUADSPI_MCR_SWRSTHD_MASK | QUADSPI_MCR_SWRSTSD_MASK);
    writel(reg, q->iobase + QUADSPI_MCR);
}

static int
fsl_qspi_runcmd(struct fsl_qspi *q, u8 cmd, unsigned int addr, int len)
{
	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);

	/* save the reg */
	reg = readl(base + QUADSPI_MCR);

	/* get the bank index */
	bank_id = ((q->slave.bus) << 1) + (q->slave.cs);

	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);

	/* trigger the LUT now */
	seqid = fsl_qspi_get_seqid(q, cmd);
	writel((seqid << QUADSPI_IPCR_SEQID_SHIFT) | len, base + QUADSPI_IPCR);

	/* Wait until completed */
	err = fsl_qspi_wait_to_complete(q);
	if (!err)
		err = -1;
	else
		err = 0;

	/* restore the MCR */
	writel(reg, base + QUADSPI_MCR);

	/* 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;
}

/*
 * 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 a;
}

/* 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)
{
	int bank_id;

	/* get the bank index */
	bank_id = ((q->slave.bus) << 1) + (q->slave.cs);

	/* Read out the data directly from the AHB buffer.*/
	memcpy(rxbuf, (u8 *)(q->bank_memmap_phy[bank_id] + addr), len);
}

/* Read out the data from the QUADSPI_RBDR buffer registers. */
static void fsl_qspi_ip_read(struct fsl_qspi *q, int len, u8 *rxbuf)
{
	u32 tmp;
	int i = 0;

	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;
		}

		len -= 4;
		i++;
	}
}

/* Write data to the QUADSPI_TBDR buffer registers. */
static void fsl_qspi_write_data(struct fsl_qspi *q, int len, u8* txbuf)
{
	u32 tmp;
	u32 t1, t2;
	int j;

	/* clear the TX FIFO. */
	tmp = readl(q->iobase + QUADSPI_MCR);
	writel(tmp | QUADSPI_MCR_CLR_RXF_MASK, q->iobase + QUADSPI_MCR);

	/* fill the TX data to the FIFO */
	t2 = len % 4;
	t1 = len >> 2; /* 4 Bytes aligned */

	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;
	}

	if (t2) {
		tmp = 0;
		memcpy(&tmp, txbuf, t2);
		tmp = fsl_qspi_endian_xchg(q, tmp);
		writel(tmp, q->iobase + QUADSPI_TBDR);
	}
}

/* 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);
		}
	}

	if (ret || (flags & SPI_XFER_END)) {
		opcode = 0;
		addr = 0;
	}

	return ret;
}
