diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/macb.c | 113 | ||||
-rw-r--r-- | drivers/spi/Makefile | 1 | ||||
-rw-r--r-- | drivers/spi/fsl_qspi.c | 482 | ||||
-rw-r--r-- | drivers/spi/fsl_qspi.h | 127 | ||||
-rw-r--r-- | drivers/video/atmel_hlcdfb.c | 6 |
5 files changed, 700 insertions, 29 deletions
diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 781a272cff2..01a94a4c4d1 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -40,17 +40,21 @@ #include "macb.h" -#define CONFIG_SYS_MACB_RX_BUFFER_SIZE 4096 -#define CONFIG_SYS_MACB_RX_RING_SIZE (CONFIG_SYS_MACB_RX_BUFFER_SIZE / 128) -#define CONFIG_SYS_MACB_TX_RING_SIZE 16 -#define CONFIG_SYS_MACB_TX_TIMEOUT 1000 -#define CONFIG_SYS_MACB_AUTONEG_TIMEOUT 5000000 +#define MACB_RX_BUFFER_SIZE 4096 +#define MACB_RX_RING_SIZE (MACB_RX_BUFFER_SIZE / 128) +#define MACB_TX_RING_SIZE 16 +#define MACB_TX_TIMEOUT 1000 +#define MACB_AUTONEG_TIMEOUT 5000000 struct macb_dma_desc { u32 addr; u32 ctrl; }; +#define DMA_DESC_BYTES(n) (n * sizeof(struct macb_dma_desc)) +#define MACB_TX_DMA_DESC_SIZE (DMA_DESC_BYTES(MACB_TX_RING_SIZE)) +#define MACB_RX_DMA_DESC_SIZE (DMA_DESC_BYTES(MACB_RX_RING_SIZE)) + #define RXADDR_USED 0x00000001 #define RXADDR_WRAP 0x00000002 @@ -170,7 +174,7 @@ int macb_miiphy_read(const char *devname, u8 phy_adr, u8 reg, u16 *value) struct eth_device *dev = eth_get_dev_by_name(devname); struct macb_device *macb = to_macb(dev); - if ( macb->phy_addr != phy_adr ) + if (macb->phy_addr != phy_adr) return -1; arch_get_mdio_control(devname); @@ -184,7 +188,7 @@ int macb_miiphy_write(const char *devname, u8 phy_adr, u8 reg, u16 value) struct eth_device *dev = eth_get_dev_by_name(devname); struct macb_device *macb = to_macb(dev); - if ( macb->phy_addr != phy_adr ) + if (macb->phy_addr != phy_adr) return -1; arch_get_mdio_control(devname); @@ -194,6 +198,39 @@ int macb_miiphy_write(const char *devname, u8 phy_adr, u8 reg, u16 value) } #endif +#define RX 1 +#define TX 0 +static inline void macb_invalidate_ring_desc(struct macb_device *macb, bool rx) +{ + if (rx) + invalidate_dcache_range(macb->rx_ring_dma, macb->rx_ring_dma + + MACB_RX_DMA_DESC_SIZE); + else + invalidate_dcache_range(macb->tx_ring_dma, macb->tx_ring_dma + + MACB_TX_DMA_DESC_SIZE); +} + +static inline void macb_flush_ring_desc(struct macb_device *macb, bool rx) +{ + if (rx) + flush_dcache_range(macb->rx_ring_dma, macb->rx_ring_dma + + MACB_RX_DMA_DESC_SIZE); + else + flush_dcache_range(macb->tx_ring_dma, macb->tx_ring_dma + + MACB_TX_DMA_DESC_SIZE); +} + +static inline void macb_flush_rx_buffer(struct macb_device *macb) +{ + flush_dcache_range(macb->rx_buffer_dma, macb->rx_buffer_dma + + MACB_RX_BUFFER_SIZE); +} + +static inline void macb_invalidate_rx_buffer(struct macb_device *macb) +{ + invalidate_dcache_range(macb->rx_buffer_dma, macb->rx_buffer_dma + + MACB_RX_BUFFER_SIZE); +} #if defined(CONFIG_CMD_NET) @@ -208,23 +245,28 @@ static int macb_send(struct eth_device *netdev, void *packet, int length) ctrl = length & TXBUF_FRMLEN_MASK; ctrl |= TXBUF_FRAME_END; - if (tx_head == (CONFIG_SYS_MACB_TX_RING_SIZE - 1)) { + if (tx_head == (MACB_TX_RING_SIZE - 1)) { ctrl |= TXBUF_WRAP; macb->tx_head = 0; - } else + } else { macb->tx_head++; + } macb->tx_ring[tx_head].ctrl = ctrl; macb->tx_ring[tx_head].addr = paddr; barrier(); + macb_flush_ring_desc(macb, TX); + /* Do we need check paddr and length is dcache line aligned? */ + flush_dcache_range(paddr, paddr + length); macb_writel(macb, NCR, MACB_BIT(TE) | MACB_BIT(RE) | MACB_BIT(TSTART)); /* * I guess this is necessary because the networking core may * re-use the transmit buffer as soon as we return... */ - for (i = 0; i <= CONFIG_SYS_MACB_TX_TIMEOUT; i++) { + for (i = 0; i <= MACB_TX_TIMEOUT; i++) { barrier(); + macb_invalidate_ring_desc(macb, TX); ctrl = macb->tx_ring[tx_head].ctrl; if (ctrl & TXBUF_USED) break; @@ -233,7 +275,7 @@ static int macb_send(struct eth_device *netdev, void *packet, int length) dma_unmap_single(packet, length, paddr); - if (i <= CONFIG_SYS_MACB_TX_TIMEOUT) { + if (i <= MACB_TX_TIMEOUT) { if (ctrl & TXBUF_UNDERRUN) printf("%s: TX underrun\n", netdev->name); if (ctrl & TXBUF_EXHAUSTED) @@ -253,10 +295,12 @@ static void reclaim_rx_buffers(struct macb_device *macb, unsigned int i; i = macb->rx_tail; + + macb_invalidate_ring_desc(macb, RX); while (i > new_tail) { macb->rx_ring[i].addr &= ~RXADDR_USED; i++; - if (i > CONFIG_SYS_MACB_RX_RING_SIZE) + if (i > MACB_RX_RING_SIZE) i = 0; } @@ -266,6 +310,7 @@ static void reclaim_rx_buffers(struct macb_device *macb, } barrier(); + macb_flush_ring_desc(macb, RX); macb->rx_tail = new_tail; } @@ -279,6 +324,8 @@ static int macb_recv(struct eth_device *netdev) u32 status; for (;;) { + macb_invalidate_ring_desc(macb, RX); + if (!(macb->rx_ring[rx_tail].addr & RXADDR_USED)) return -1; @@ -292,10 +339,12 @@ static int macb_recv(struct eth_device *netdev) if (status & RXBUF_FRAME_END) { buffer = macb->rx_buffer + 128 * macb->rx_tail; length = status & RXBUF_FRMLEN_MASK; + + macb_invalidate_rx_buffer(macb); if (wrapped) { unsigned int headlen, taillen; - headlen = 128 * (CONFIG_SYS_MACB_RX_RING_SIZE + headlen = 128 * (MACB_RX_RING_SIZE - macb->rx_tail); taillen = length - headlen; memcpy((void *)NetRxPackets[0], @@ -306,11 +355,11 @@ static int macb_recv(struct eth_device *netdev) } NetReceive(buffer, length); - if (++rx_tail >= CONFIG_SYS_MACB_RX_RING_SIZE) + if (++rx_tail >= MACB_RX_RING_SIZE) rx_tail = 0; reclaim_rx_buffers(macb, rx_tail); } else { - if (++rx_tail >= CONFIG_SYS_MACB_RX_RING_SIZE) { + if (++rx_tail >= MACB_RX_RING_SIZE) { wrapped = 1; rx_tail = 0; } @@ -333,7 +382,7 @@ static void macb_phy_reset(struct macb_device *macb) macb_mdio_write(macb, MII_BMCR, (BMCR_ANENABLE | BMCR_ANRESTART)); - for (i = 0; i < CONFIG_SYS_MACB_AUTONEG_TIMEOUT / 100; i++) { + for (i = 0; i < MACB_AUTONEG_TIMEOUT / 100; i++) { status = macb_mdio_read(macb, MII_BMSR); if (status & BMSR_ANEGCOMPLETE) break; @@ -385,9 +434,8 @@ static int macb_phy_init(struct macb_device *macb) arch_get_mdio_control(netdev->name); #ifdef CONFIG_MACB_SEARCH_PHY /* Auto-detect phy_addr */ - if (!macb_phy_find(macb)) { + if (!macb_phy_find(macb)) return 0; - } #endif /* CONFIG_MACB_SEARCH_PHY */ /* Check if the PHY is up to snuff... */ @@ -414,7 +462,7 @@ static int macb_phy_init(struct macb_device *macb) /* Try to re-negotiate if we don't have link already. */ macb_phy_reset(macb); - for (i = 0; i < CONFIG_SYS_MACB_AUTONEG_TIMEOUT / 100; i++) { + for (i = 0; i < MACB_AUTONEG_TIMEOUT / 100; i++) { status = macb_mdio_read(macb, MII_BMSR); if (status & BMSR_LSTATUS) break; @@ -499,21 +547,28 @@ static int macb_init(struct eth_device *netdev, bd_t *bd) /* initialize DMA descriptors */ paddr = macb->rx_buffer_dma; - for (i = 0; i < CONFIG_SYS_MACB_RX_RING_SIZE; i++) { - if (i == (CONFIG_SYS_MACB_RX_RING_SIZE - 1)) + for (i = 0; i < MACB_RX_RING_SIZE; i++) { + if (i == (MACB_RX_RING_SIZE - 1)) paddr |= RXADDR_WRAP; macb->rx_ring[i].addr = paddr; macb->rx_ring[i].ctrl = 0; paddr += 128; } - for (i = 0; i < CONFIG_SYS_MACB_TX_RING_SIZE; i++) { + macb_flush_ring_desc(macb, RX); + macb_flush_rx_buffer(macb); + + for (i = 0; i < MACB_TX_RING_SIZE; i++) { macb->tx_ring[i].addr = 0; - if (i == (CONFIG_SYS_MACB_TX_RING_SIZE - 1)) + if (i == (MACB_TX_RING_SIZE - 1)) macb->tx_ring[i].ctrl = TXBUF_USED | TXBUF_WRAP; else macb->tx_ring[i].ctrl = TXBUF_USED; } - macb->rx_tail = macb->tx_head = macb->tx_tail = 0; + macb_flush_ring_desc(macb, TX); + + macb->rx_tail = 0; + macb->tx_head = 0; + macb->tx_tail = 0; macb_writel(macb, RBQP, macb->rx_ring_dma); macb_writel(macb, TBQP, macb->tx_ring_dma); @@ -654,15 +709,15 @@ int macb_eth_initialize(int id, void *regs, unsigned int phy_addr) netdev = &macb->netdev; - macb->rx_buffer = dma_alloc_coherent(CONFIG_SYS_MACB_RX_BUFFER_SIZE, + macb->rx_buffer = dma_alloc_coherent(MACB_RX_BUFFER_SIZE, &macb->rx_buffer_dma); - macb->rx_ring = dma_alloc_coherent(CONFIG_SYS_MACB_RX_RING_SIZE - * sizeof(struct macb_dma_desc), + macb->rx_ring = dma_alloc_coherent(MACB_RX_DMA_DESC_SIZE, &macb->rx_ring_dma); - macb->tx_ring = dma_alloc_coherent(CONFIG_SYS_MACB_TX_RING_SIZE - * sizeof(struct macb_dma_desc), + macb->tx_ring = dma_alloc_coherent(MACB_TX_DMA_DESC_SIZE, &macb->tx_ring_dma); + /* TODO: we need check the rx/tx_ring_dma is dcache line aligned */ + macb->regs = regs; macb->phy_addr = phy_addr; diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 81b6af66949..b587308c849 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -40,3 +40,4 @@ obj-$(CONFIG_TEGRA114_SPI) += tegra114_spi.o obj-$(CONFIG_TI_QSPI) += ti_qspi.o obj-$(CONFIG_XILINX_SPI) += xilinx_spi.o obj-$(CONFIG_ZYNQ_SPI) += zynq_spi.o +obj-$(CONFIG_FSL_QSPI) += fsl_qspi.o diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c new file mode 100644 index 00000000000..ba20beff4f9 --- /dev/null +++ b/drivers/spi/fsl_qspi.c @@ -0,0 +1,482 @@ +/* + * Copyright 2013-2014 Freescale Semiconductor, Inc. + * + * Freescale Quad Serial Peripheral Interface (QSPI) driver + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <malloc.h> +#include <spi.h> +#include <asm/io.h> +#include <linux/sizes.h> +#include "fsl_qspi.h" + +#define RX_BUFFER_SIZE 0x80 +#define TX_BUFFER_SIZE 0x40 + +#define OFFSET_BITS_MASK 0x00ffffff + +#define FLASH_STATUS_WEL 0x02 + +/* SEQID */ +#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 + +/* Flash opcodes */ +#define OPCODE_PP 0x02 /* Page program (up to 256 bytes) */ +#define OPCODE_RDSR 0x05 /* Read status register */ +#define OPCODE_WREN 0x06 /* Write enable */ +#define OPCODE_FAST_READ 0x0b /* Read data bytes (high frequency) */ +#define OPCODE_CHIP_ERASE 0xc7 /* Erase whole flash chip */ +#define OPCODE_SE 0xd8 /* Sector erase (usually 64KiB) */ +#define OPCODE_RDID 0x9f /* Read JEDEC ID */ + +/* 4-byte address opcodes - used on Spansion and some Macronix flashes */ +#define OPCODE_FAST_READ_4B 0x0c /* Read data bytes (high frequency) */ +#define OPCODE_PP_4B 0x12 /* Page program (up to 256 bytes) */ +#define OPCODE_SE_4B 0xdc /* Sector erase (usually 64KiB) */ + +#ifdef CONFIG_SYS_FSL_QSPI_LE +#define qspi_read32 in_le32 +#define qspi_write32 out_le32 +#elif defined(CONFIG_SYS_FSL_QSPI_BE) +#define qspi_read32 in_be32 +#define qspi_write32 out_be32 +#endif + +static unsigned long spi_bases[] = { + QSPI0_BASE_ADDR, +}; + +static unsigned long amba_bases[] = { + QSPI0_AMBA_BASE, +}; + +struct fsl_qspi { + struct spi_slave slave; + unsigned long reg_base; + unsigned long amba_base; + u32 sf_addr; + u8 cur_seqid; +}; + +/* QSPI support swapping the flash read/write data + * in hardware for LS102xA, but not for VF610 */ +static inline u32 qspi_endian_xchg(u32 data) +{ +#ifdef CONFIG_VF610 + return swab32(data); +#else + return data; +#endif +} + +static inline struct fsl_qspi *to_qspi_spi(struct spi_slave *slave) +{ + return container_of(slave, struct fsl_qspi, slave); +} + +static void qspi_set_lut(struct fsl_qspi *qspi) +{ + struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base; + u32 lut_base; + + /* Unlock the LUT */ + qspi_write32(®s->lutkey, LUT_KEY_VALUE); + qspi_write32(®s->lckcr, QSPI_LCKCR_UNLOCK); + + /* Write Enable */ + lut_base = SEQID_WREN * 4; + qspi_write32(®s->lut[lut_base], OPRND0(OPCODE_WREN) | + PAD0(LUT_PAD1) | INSTR0(LUT_CMD)); + qspi_write32(®s->lut[lut_base + 1], 0); + qspi_write32(®s->lut[lut_base + 2], 0); + qspi_write32(®s->lut[lut_base + 3], 0); + + /* Fast Read */ + lut_base = SEQID_FAST_READ * 4; + if (FSL_QSPI_FLASH_SIZE <= SZ_16M) + qspi_write32(®s->lut[lut_base], OPRND0(OPCODE_FAST_READ) | + PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) | + PAD1(LUT_PAD1) | INSTR1(LUT_ADDR)); + else + qspi_write32(®s->lut[lut_base], OPRND0(OPCODE_FAST_READ_4B) | + PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR32BIT) | + PAD1(LUT_PAD1) | INSTR1(LUT_ADDR)); + qspi_write32(®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(®s->lut[lut_base + 2], 0); + qspi_write32(®s->lut[lut_base + 3], 0); + + /* Read Status */ + lut_base = SEQID_RDSR * 4; + qspi_write32(®s->lut[lut_base], OPRND0(OPCODE_RDSR) | + PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(1) | + PAD1(LUT_PAD1) | INSTR1(LUT_READ)); + qspi_write32(®s->lut[lut_base + 1], 0); + qspi_write32(®s->lut[lut_base + 2], 0); + qspi_write32(®s->lut[lut_base + 3], 0); + + /* Erase a sector */ + lut_base = SEQID_SE * 4; + if (FSL_QSPI_FLASH_SIZE <= SZ_16M) + qspi_write32(®s->lut[lut_base], OPRND0(OPCODE_SE) | + PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) | + PAD1(LUT_PAD1) | INSTR1(LUT_ADDR)); + else + qspi_write32(®s->lut[lut_base], OPRND0(OPCODE_SE_4B) | + PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR32BIT) | + PAD1(LUT_PAD1) | INSTR1(LUT_ADDR)); + qspi_write32(®s->lut[lut_base + 1], 0); + qspi_write32(®s->lut[lut_base + 2], 0); + qspi_write32(®s->lut[lut_base + 3], 0); + + /* Erase the whole chip */ + lut_base = SEQID_CHIP_ERASE * 4; + qspi_write32(®s->lut[lut_base], OPRND0(OPCODE_CHIP_ERASE) | + PAD0(LUT_PAD1) | INSTR0(LUT_CMD)); + qspi_write32(®s->lut[lut_base + 1], 0); + qspi_write32(®s->lut[lut_base + 2], 0); + qspi_write32(®s->lut[lut_base + 3], 0); + + /* Page Program */ + lut_base = SEQID_PP * 4; + if (FSL_QSPI_FLASH_SIZE <= SZ_16M) + qspi_write32(®s->lut[lut_base], OPRND0(OPCODE_PP) | + PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) | + PAD1(LUT_PAD1) | INSTR1(LUT_ADDR)); + else + qspi_write32(®s->lut[lut_base], OPRND0(OPCODE_PP_4B) | + PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR32BIT) | + PAD1(LUT_PAD1) | INSTR1(LUT_ADDR)); + qspi_write32(®s->lut[lut_base + 1], OPRND0(TX_BUFFER_SIZE) | + PAD0(LUT_PAD1) | INSTR0(LUT_WRITE)); + qspi_write32(®s->lut[lut_base + 2], 0); + qspi_write32(®s->lut[lut_base + 3], 0); + + /* READ ID */ + lut_base = SEQID_RDID * 4; + qspi_write32(®s->lut[lut_base], OPRND0(OPCODE_RDID) | + PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(8) | + PAD1(LUT_PAD1) | INSTR1(LUT_READ)); + qspi_write32(®s->lut[lut_base + 1], 0); + qspi_write32(®s->lut[lut_base + 2], 0); + qspi_write32(®s->lut[lut_base + 3], 0); + + /* Lock the LUT */ + qspi_write32(®s->lutkey, LUT_KEY_VALUE); + qspi_write32(®s->lckcr, QSPI_LCKCR_LOCK); +} + +void spi_init() +{ + /* do nothing */ +} + +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode) +{ + struct fsl_qspi *qspi; + struct fsl_qspi_regs *regs; + u32 reg_val, smpr_val; + u32 total_size, seq_id; + + if (bus >= ARRAY_SIZE(spi_bases)) + return NULL; + + qspi = spi_alloc_slave(struct fsl_qspi, bus, cs); + if (!qspi) + return NULL; + + qspi->reg_base = spi_bases[bus]; + qspi->amba_base = amba_bases[bus]; + + qspi->slave.max_write_size = TX_BUFFER_SIZE; + + regs = (struct fsl_qspi_regs *)qspi->reg_base; + qspi_write32(®s->mcr, QSPI_MCR_RESERVED_MASK | QSPI_MCR_MDIS_MASK); + + smpr_val = qspi_read32(®s->smpr); + qspi_write32(®s->smpr, smpr_val & ~(QSPI_SMPR_FSDLY_MASK | + QSPI_SMPR_FSPHS_MASK | QSPI_SMPR_HSENA_MASK)); + qspi_write32(®s->mcr, QSPI_MCR_RESERVED_MASK); + + total_size = FSL_QSPI_FLASH_SIZE * FSL_QSPI_FLASH_NUM; + qspi_write32(®s->sfa1ad, FSL_QSPI_FLASH_SIZE | qspi->amba_base); + qspi_write32(®s->sfa2ad, FSL_QSPI_FLASH_SIZE | qspi->amba_base); + qspi_write32(®s->sfb1ad, total_size | qspi->amba_base); + qspi_write32(®s->sfb2ad, total_size | qspi->amba_base); + + qspi_set_lut(qspi); + + smpr_val = qspi_read32(®s->smpr); + smpr_val &= ~QSPI_SMPR_DDRSMP_MASK; + qspi_write32(®s->smpr, smpr_val); + qspi_write32(®s->mcr, QSPI_MCR_RESERVED_MASK); + + seq_id = 0; + reg_val = qspi_read32(®s->bfgencr); + reg_val &= ~QSPI_BFGENCR_SEQID_MASK; + reg_val |= (seq_id << QSPI_BFGENCR_SEQID_SHIFT); + reg_val &= ~QSPI_BFGENCR_PAR_EN_MASK; + qspi_write32(®s->bfgencr, reg_val); + + return &qspi->slave; +} + +void spi_free_slave(struct spi_slave *slave) +{ + struct fsl_qspi *qspi = to_qspi_spi(slave); + + free(qspi); +} + +int spi_claim_bus(struct spi_slave *slave) +{ + return 0; +} + +static void qspi_op_rdid(struct fsl_qspi *qspi, u32 *rxbuf, u32 len) +{ + struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base; + u32 mcr_reg, rbsr_reg, data; + int i, size; + + mcr_reg = qspi_read32(®s->mcr); + qspi_write32(®s->mcr, QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK | + QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE); + qspi_write32(®s->rbct, QSPI_RBCT_RXBRD_USEIPS); + + qspi_write32(®s->sfar, qspi->amba_base); + + qspi_write32(®s->ipcr, (SEQID_RDID << QSPI_IPCR_SEQID_SHIFT) | 0); + while (qspi_read32(®s->sr) & QSPI_SR_BUSY_MASK) + ; + + i = 0; + size = len; + while ((RX_BUFFER_SIZE >= size) && (size > 0)) { + rbsr_reg = qspi_read32(®s->rbsr); + if (rbsr_reg & QSPI_RBSR_RDBFL_MASK) { + data = qspi_read32(®s->rbdr[i]); + data = qspi_endian_xchg(data); + memcpy(rxbuf, &data, 4); + rxbuf++; + size -= 4; + i++; + } + } + + qspi_write32(®s->mcr, mcr_reg); +} + +static void qspi_op_read(struct fsl_qspi *qspi, u32 *rxbuf, u32 len) +{ + struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base; + u32 mcr_reg, data; + int i, size; + u32 to_or_from; + + mcr_reg = qspi_read32(®s->mcr); + qspi_write32(®s->mcr, QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK | + QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE); + qspi_write32(®s->rbct, QSPI_RBCT_RXBRD_USEIPS); + + to_or_from = qspi->sf_addr + qspi->amba_base; + + while (len > 0) { + qspi_write32(®s->sfar, to_or_from); + + size = (len > RX_BUFFER_SIZE) ? + RX_BUFFER_SIZE : len; + + qspi_write32(®s->ipcr, + (SEQID_FAST_READ << QSPI_IPCR_SEQID_SHIFT) | size); + while (qspi_read32(®s->sr) & QSPI_SR_BUSY_MASK) + ; + + to_or_from += size; + len -= size; + + i = 0; + while ((RX_BUFFER_SIZE >= size) && (size > 0)) { + data = qspi_read32(®s->rbdr[i]); + data = qspi_endian_xchg(data); + memcpy(rxbuf, &data, 4); + rxbuf++; + size -= 4; + i++; + } + qspi_write32(®s->mcr, qspi_read32(®s->mcr) | + QSPI_MCR_CLR_RXF_MASK); + } + + qspi_write32(®s->mcr, mcr_reg); +} + +static void qspi_op_pp(struct fsl_qspi *qspi, u32 *txbuf, u32 len) +{ + struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base; + u32 mcr_reg, data, reg, status_reg; + int i, size, tx_size; + u32 to_or_from = 0; + + mcr_reg = qspi_read32(®s->mcr); + qspi_write32(®s->mcr, QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK | + QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE); + qspi_write32(®s->rbct, QSPI_RBCT_RXBRD_USEIPS); + + status_reg = 0; + while ((status_reg & FLASH_STATUS_WEL) != FLASH_STATUS_WEL) { + qspi_write32(®s->ipcr, + (SEQID_WREN << QSPI_IPCR_SEQID_SHIFT) | 0); + while (qspi_read32(®s->sr) & QSPI_SR_BUSY_MASK) + ; + + qspi_write32(®s->ipcr, + (SEQID_RDSR << QSPI_IPCR_SEQID_SHIFT) | 1); + while (qspi_read32(®s->sr) & QSPI_SR_BUSY_MASK) + ; + + reg = qspi_read32(®s->rbsr); + if (reg & QSPI_RBSR_RDBFL_MASK) { + status_reg = qspi_read32(®s->rbdr[0]); + status_reg = qspi_endian_xchg(status_reg); + } + qspi_write32(®s->mcr, + qspi_read32(®s->mcr) | QSPI_MCR_CLR_RXF_MASK); + } + + to_or_from = qspi->sf_addr + qspi->amba_base; + qspi_write32(®s->sfar, to_or_from); + + tx_size = (len > TX_BUFFER_SIZE) ? + TX_BUFFER_SIZE : len; + + size = (tx_size + 3) / 4; + + for (i = 0; i < size; i++) { + data = qspi_endian_xchg(*txbuf); + qspi_write32(®s->tbdr, data); + txbuf++; + } + + qspi_write32(®s->ipcr, + (SEQID_PP << QSPI_IPCR_SEQID_SHIFT) | tx_size); + while (qspi_read32(®s->sr) & QSPI_SR_BUSY_MASK) + ; + + qspi_write32(®s->mcr, mcr_reg); +} + +static void qspi_op_rdsr(struct fsl_qspi *qspi, u32 *rxbuf) +{ + struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base; + u32 mcr_reg, reg, data; + + mcr_reg = qspi_read32(®s->mcr); + qspi_write32(®s->mcr, QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK | + QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE); + qspi_write32(®s->rbct, QSPI_RBCT_RXBRD_USEIPS); + + qspi_write32(®s->sfar, qspi->amba_base); + + qspi_write32(®s->ipcr, + (SEQID_RDSR << QSPI_IPCR_SEQID_SHIFT) | 0); + while (qspi_read32(®s->sr) & QSPI_SR_BUSY_MASK) + ; + + while (1) { + reg = qspi_read32(®s->rbsr); + if (reg & QSPI_RBSR_RDBFL_MASK) { + data = qspi_read32(®s->rbdr[0]); + data = qspi_endian_xchg(data); + memcpy(rxbuf, &data, 4); + qspi_write32(®s->mcr, qspi_read32(®s->mcr) | + QSPI_MCR_CLR_RXF_MASK); + break; + } + } + + qspi_write32(®s->mcr, mcr_reg); +} + +static void qspi_op_se(struct fsl_qspi *qspi) +{ + struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base; + u32 mcr_reg; + u32 to_or_from = 0; + + mcr_reg = qspi_read32(®s->mcr); + qspi_write32(®s->mcr, QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK | + QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE); + qspi_write32(®s->rbct, QSPI_RBCT_RXBRD_USEIPS); + + to_or_from = qspi->sf_addr + qspi->amba_base; + qspi_write32(®s->sfar, to_or_from); + + qspi_write32(®s->ipcr, + (SEQID_WREN << QSPI_IPCR_SEQID_SHIFT) | 0); + while (qspi_read32(®s->sr) & QSPI_SR_BUSY_MASK) + ; + + qspi_write32(®s->ipcr, + (SEQID_SE << QSPI_IPCR_SEQID_SHIFT) | 0); + while (qspi_read32(®s->sr) & QSPI_SR_BUSY_MASK) + ; + + qspi_write32(®s->mcr, mcr_reg); +} + +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); + u32 bytes = DIV_ROUND_UP(bitlen, 8); + static u32 pp_sfaddr; + u32 txbuf; + + if (dout) { + memcpy(&txbuf, dout, 4); + qspi->cur_seqid = *(u8 *)dout; + + if (flags == SPI_XFER_END) { + qspi->sf_addr = pp_sfaddr; + qspi_op_pp(qspi, (u32 *)dout, bytes); + return 0; + } + + if (qspi->cur_seqid == OPCODE_FAST_READ) { + qspi->sf_addr = swab32(txbuf) & OFFSET_BITS_MASK; + } else if (qspi->cur_seqid == OPCODE_SE) { + qspi->sf_addr = swab32(txbuf) & OFFSET_BITS_MASK; + qspi_op_se(qspi); + } else if (qspi->cur_seqid == OPCODE_PP) { + pp_sfaddr = swab32(txbuf) & OFFSET_BITS_MASK; + } + } + + if (din) { + if (qspi->cur_seqid == OPCODE_FAST_READ) + qspi_op_read(qspi, din, bytes); + else if (qspi->cur_seqid == OPCODE_RDID) + qspi_op_rdid(qspi, din, bytes); + else if (qspi->cur_seqid == OPCODE_RDSR) + qspi_op_rdsr(qspi, din); + } + + return 0; +} + +void spi_release_bus(struct spi_slave *slave) +{ + /* Nothing to do */ +} diff --git a/drivers/spi/fsl_qspi.h b/drivers/spi/fsl_qspi.h new file mode 100644 index 00000000000..db400e66b50 --- /dev/null +++ b/drivers/spi/fsl_qspi.h @@ -0,0 +1,127 @@ +/* + * Copyright 2013-2014 Freescale Semiconductor, Inc. + * + * Register definitions for Freescale QSPI + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _FSL_QSPI_H_ +#define _FSL_QSPI_H_ + +struct fsl_qspi_regs { + u32 mcr; + u32 rsvd0[1]; + u32 ipcr; + u32 flshcr; + u32 buf0cr; + u32 buf1cr; + u32 buf2cr; + u32 buf3cr; + u32 bfgencr; + u32 soccr; + u32 rsvd1[2]; + u32 buf0ind; + u32 buf1ind; + u32 buf2ind; + u32 rsvd2[49]; + u32 sfar; + u32 rsvd3[1]; + u32 smpr; + u32 rbsr; + u32 rbct; + u32 rsvd4[15]; + u32 tbsr; + u32 tbdr; + u32 rsvd5[1]; + u32 sr; + u32 fr; + u32 rser; + u32 spndst; + u32 sptrclr; + u32 rsvd6[4]; + u32 sfa1ad; + u32 sfa2ad; + u32 sfb1ad; + u32 sfb2ad; + u32 rsvd7[28]; + u32 rbdr[32]; + u32 rsvd8[32]; + u32 lutkey; + u32 lckcr; + u32 rsvd9[2]; + u32 lut[64]; +}; + +#define QSPI_IPCR_SEQID_SHIFT 24 +#define QSPI_IPCR_SEQID_MASK (0xf << QSPI_IPCR_SEQID_SHIFT) + +#define QSPI_MCR_END_CFD_SHIFT 2 +#define QSPI_MCR_END_CFD_MASK (3 << QSPI_MCR_END_CFD_SHIFT) +#define QSPI_MCR_END_CFD_LE (1 << QSPI_MCR_END_CFD_SHIFT) +#define QSPI_MCR_DDR_EN_SHIFT 7 +#define QSPI_MCR_DDR_EN_MASK (1 << QSPI_MCR_DDR_EN_SHIFT) +#define QSPI_MCR_CLR_RXF_SHIFT 10 +#define QSPI_MCR_CLR_RXF_MASK (1 << QSPI_MCR_CLR_RXF_SHIFT) +#define QSPI_MCR_CLR_TXF_SHIFT 11 +#define QSPI_MCR_CLR_TXF_MASK (1 << QSPI_MCR_CLR_TXF_SHIFT) +#define QSPI_MCR_MDIS_SHIFT 14 +#define QSPI_MCR_MDIS_MASK (1 << QSPI_MCR_MDIS_SHIFT) +#define QSPI_MCR_RESERVED_SHIFT 16 +#define QSPI_MCR_RESERVED_MASK (0xf << QSPI_MCR_RESERVED_SHIFT) + +#define QSPI_SMPR_HSENA_SHIFT 0 +#define QSPI_SMPR_HSENA_MASK (1 << QSPI_SMPR_HSENA_SHIFT) +#define QSPI_SMPR_FSPHS_SHIFT 5 +#define QSPI_SMPR_FSPHS_MASK (1 << QSPI_SMPR_FSPHS_SHIFT) +#define QSPI_SMPR_FSDLY_SHIFT 6 +#define QSPI_SMPR_FSDLY_MASK (1 << QSPI_SMPR_FSDLY_SHIFT) +#define QSPI_SMPR_DDRSMP_SHIFT 16 +#define QSPI_SMPR_DDRSMP_MASK (7 << QSPI_SMPR_DDRSMP_SHIFT) + +#define QSPI_BFGENCR_SEQID_SHIFT 12 +#define QSPI_BFGENCR_SEQID_MASK (0xf << QSPI_BFGENCR_SEQID_SHIFT) +#define QSPI_BFGENCR_PAR_EN_SHIFT 16 +#define QSPI_BFGENCR_PAR_EN_MASK (1 << QSPI_BFGENCR_PAR_EN_SHIFT) + +#define QSPI_RBSR_RDBFL_SHIFT 8 +#define QSPI_RBSR_RDBFL_MASK (0x3f << QSPI_RBSR_RDBFL_SHIFT) + +#define QSPI_RBCT_RXBRD_SHIFT 8 +#define QSPI_RBCT_RXBRD_USEIPS (1 << QSPI_RBCT_RXBRD_SHIFT) + +#define QSPI_SR_BUSY_SHIFT 0 +#define QSPI_SR_BUSY_MASK (1 << QSPI_SR_BUSY_SHIFT) + +#define QSPI_LCKCR_LOCK 0x1 +#define QSPI_LCKCR_UNLOCK 0x2 + +#define LUT_KEY_VALUE 0x5af05af0 + +#define OPRND0_SHIFT 0 +#define OPRND0(x) ((x) << OPRND0_SHIFT) +#define PAD0_SHIFT 8 +#define PAD0(x) ((x) << PAD0_SHIFT) +#define INSTR0_SHIFT 10 +#define INSTR0(x) ((x) << INSTR0_SHIFT) +#define OPRND1_SHIFT 16 +#define OPRND1(x) ((x) << OPRND1_SHIFT) +#define PAD1_SHIFT 24 +#define PAD1(x) ((x) << PAD1_SHIFT) +#define INSTR1_SHIFT 26 +#define INSTR1(x) ((x) << INSTR1_SHIFT) + +#define LUT_CMD 1 +#define LUT_ADDR 2 +#define LUT_DUMMY 3 +#define LUT_READ 7 +#define LUT_WRITE 8 + +#define LUT_PAD1 0 +#define LUT_PAD2 1 +#define LUT_PAD4 2 + +#define ADDR24BIT 0x18 +#define ADDR32BIT 0x20 + +#endif /* _FSL_QSPI_H_ */ diff --git a/drivers/video/atmel_hlcdfb.c b/drivers/video/atmel_hlcdfb.c index bb4d7d8c147..935ae42a9c8 100644 --- a/drivers/video/atmel_hlcdfb.c +++ b/drivers/video/atmel_hlcdfb.c @@ -171,6 +171,9 @@ void lcd_ctrl_init(void *lcdbase) | LCDC_BASECTRL_DMAIEN | LCDC_BASECTRL_DFETCH; desc->next = (u32)desc; + /* Flush the DMA descriptor if we enabled dcache */ + flush_dcache_range((u32)desc, (u32)desc + sizeof(*desc)); + lcdc_writel(®s->lcdc_baseaddr, desc->address); lcdc_writel(®s->lcdc_basectrl, desc->control); lcdc_writel(®s->lcdc_basenext, desc->next); @@ -194,4 +197,7 @@ void lcd_ctrl_init(void *lcdbase) lcdc_writel(®s->lcdc_lcden, value | LCDC_LCDEN_PWMEN); while (!(lcdc_readl(®s->lcdc_lcdsr) & LCDC_LCDSR_PWMSTS)) udelay(1); + + /* Enable flushing if we enabled dcache */ + lcd_set_flush_dcache(1); } |