mirror of
https://xff.cz/git/u-boot/
synced 2025-09-01 08:42:12 +02:00
Merge branch 'master' of git://git.denx.de/u-boot-arm
This commit is contained in:
@@ -14,3 +14,4 @@ obj-y += twserial/
|
||||
obj-y += video/
|
||||
obj-y += watchdog/
|
||||
obj-$(CONFIG_QE) += qe/
|
||||
obj-y += memory/
|
||||
|
@@ -17,6 +17,7 @@
|
||||
#include <asm/io.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <asm/arch/clock.h>
|
||||
#include <asm/arch/sys_proto.h>
|
||||
#include "dwc_ahsata.h"
|
||||
|
||||
struct sata_port_regs {
|
||||
@@ -558,6 +559,10 @@ int init_sata(int dev)
|
||||
u32 linkmap;
|
||||
struct ahci_probe_ent *probe_ent = NULL;
|
||||
|
||||
#if defined(CONFIG_MX6)
|
||||
if (!is_cpu_type(MXC_CPU_MX6Q) && !is_cpu_type(MXC_CPU_MX6D))
|
||||
return 1;
|
||||
#endif
|
||||
if (dev < 0 || dev > (CONFIG_SYS_SATA_MAX_DEVICE - 1)) {
|
||||
printf("The sata index %d is out of ranges\n\r", dev);
|
||||
return -1;
|
||||
|
1
drivers/memory/Makefile
Normal file
1
drivers/memory/Makefile
Normal file
@@ -0,0 +1 @@
|
||||
obj-$(CONFIG_TI_AEMIF) += ti-aemif.o
|
80
drivers/memory/ti-aemif.c
Normal file
80
drivers/memory/ti-aemif.c
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Keystone2: Asynchronous EMIF Configuration
|
||||
*
|
||||
* (C) Copyright 2012-2014
|
||||
* Texas Instruments Incorporated, <www.ti.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/ti-common/ti-aemif.h>
|
||||
|
||||
#define AEMIF_WAITCYCLE_CONFIG (CONFIG_AEMIF_CNTRL_BASE + 0x4)
|
||||
#define AEMIF_NAND_CONTROL (CONFIG_AEMIF_CNTRL_BASE + 0x60)
|
||||
#define AEMIF_ONENAND_CONTROL (CONFIG_AEMIF_CNTRL_BASE + 0x5c)
|
||||
#define AEMIF_CONFIG(cs) (CONFIG_AEMIF_CNTRL_BASE + 0x10 \
|
||||
+ (cs * 4))
|
||||
|
||||
#define AEMIF_CFG_SELECT_STROBE(v) ((v) ? 1 << 31 : 0)
|
||||
#define AEMIF_CFG_EXTEND_WAIT(v) ((v) ? 1 << 30 : 0)
|
||||
#define AEMIF_CFG_WR_SETUP(v) (((v) & 0x0f) << 26)
|
||||
#define AEMIF_CFG_WR_STROBE(v) (((v) & 0x3f) << 20)
|
||||
#define AEMIF_CFG_WR_HOLD(v) (((v) & 0x07) << 17)
|
||||
#define AEMIF_CFG_RD_SETUP(v) (((v) & 0x0f) << 13)
|
||||
#define AEMIF_CFG_RD_STROBE(v) (((v) & 0x3f) << 7)
|
||||
#define AEMIF_CFG_RD_HOLD(v) (((v) & 0x07) << 4)
|
||||
#define AEMIF_CFG_TURN_AROUND(v) (((v) & 0x03) << 2)
|
||||
#define AEMIF_CFG_WIDTH(v) (((v) & 0x03) << 0)
|
||||
|
||||
#define set_config_field(reg, field, val) \
|
||||
do { \
|
||||
if (val != -1) { \
|
||||
reg &= ~AEMIF_CFG_##field(0xffffffff); \
|
||||
reg |= AEMIF_CFG_##field(val); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static void aemif_configure(int cs, struct aemif_config *cfg)
|
||||
{
|
||||
unsigned long tmp;
|
||||
|
||||
if (cfg->mode == AEMIF_MODE_NAND) {
|
||||
tmp = __raw_readl(AEMIF_NAND_CONTROL);
|
||||
tmp |= (1 << cs);
|
||||
__raw_writel(tmp, AEMIF_NAND_CONTROL);
|
||||
|
||||
} else if (cfg->mode == AEMIF_MODE_ONENAND) {
|
||||
tmp = __raw_readl(AEMIF_ONENAND_CONTROL);
|
||||
tmp |= (1 << cs);
|
||||
__raw_writel(tmp, AEMIF_ONENAND_CONTROL);
|
||||
}
|
||||
|
||||
tmp = __raw_readl(AEMIF_CONFIG(cs));
|
||||
|
||||
set_config_field(tmp, SELECT_STROBE, cfg->select_strobe);
|
||||
set_config_field(tmp, EXTEND_WAIT, cfg->extend_wait);
|
||||
set_config_field(tmp, WR_SETUP, cfg->wr_setup);
|
||||
set_config_field(tmp, WR_STROBE, cfg->wr_strobe);
|
||||
set_config_field(tmp, WR_HOLD, cfg->wr_hold);
|
||||
set_config_field(tmp, RD_SETUP, cfg->rd_setup);
|
||||
set_config_field(tmp, RD_STROBE, cfg->rd_strobe);
|
||||
set_config_field(tmp, RD_HOLD, cfg->rd_hold);
|
||||
set_config_field(tmp, TURN_AROUND, cfg->turn_around);
|
||||
set_config_field(tmp, WIDTH, cfg->width);
|
||||
|
||||
__raw_writel(tmp, AEMIF_CONFIG(cs));
|
||||
}
|
||||
|
||||
void aemif_init(int num_cs, struct aemif_config *config)
|
||||
{
|
||||
int cs;
|
||||
|
||||
if (num_cs > AEMIF_NUM_CS) {
|
||||
num_cs = AEMIF_NUM_CS;
|
||||
printf("AEMIF: csnum has to be <= 5");
|
||||
}
|
||||
|
||||
for (cs = 0; cs < num_cs; cs++)
|
||||
aemif_configure(cs, config + cs);
|
||||
}
|
@@ -68,5 +68,6 @@ else # minimal SPL drivers
|
||||
obj-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_spl.o
|
||||
obj-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_spl.o
|
||||
obj-$(CONFIG_NAND_MXC) += mxc_nand_spl.o
|
||||
obj-$(CONFIG_NAND_MXS) += mxs_nand_spl.o mxs_nand.o
|
||||
|
||||
endif # drivers
|
||||
|
@@ -32,8 +32,7 @@
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <nand.h>
|
||||
#include <asm/arch/nand_defs.h>
|
||||
#include <asm/arch/emif_defs.h>
|
||||
#include <asm/ti-common/davinci_nand.h>
|
||||
|
||||
/* Definitions for 4-bit hardware ECC */
|
||||
#define NAND_TIMEOUT 10240
|
||||
|
231
drivers/mtd/nand/mxs_nand_spl.c
Normal file
231
drivers/mtd/nand/mxs_nand_spl.c
Normal file
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Gateworks Corporation
|
||||
* Author: Tim Harvey <tharvey@gateworks.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <nand.h>
|
||||
#include <malloc.h>
|
||||
|
||||
static nand_info_t mtd;
|
||||
static struct nand_chip nand_chip;
|
||||
|
||||
static void mxs_nand_command(struct mtd_info *mtd, unsigned int command,
|
||||
int column, int page_addr)
|
||||
{
|
||||
register struct nand_chip *chip = mtd->priv;
|
||||
u32 timeo, time_start;
|
||||
|
||||
/* write out the command to the device */
|
||||
chip->cmd_ctrl(mtd, command, NAND_CLE);
|
||||
|
||||
/* Serially input address */
|
||||
if (column != -1) {
|
||||
chip->cmd_ctrl(mtd, column, NAND_ALE);
|
||||
chip->cmd_ctrl(mtd, column >> 8, NAND_ALE);
|
||||
}
|
||||
if (page_addr != -1) {
|
||||
chip->cmd_ctrl(mtd, page_addr, NAND_ALE);
|
||||
chip->cmd_ctrl(mtd, page_addr >> 8, NAND_ALE);
|
||||
/* One more address cycle for devices > 128MiB */
|
||||
if (chip->chipsize > (128 << 20))
|
||||
chip->cmd_ctrl(mtd, page_addr >> 16, NAND_ALE);
|
||||
}
|
||||
chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0);
|
||||
|
||||
if (command == NAND_CMD_READ0) {
|
||||
chip->cmd_ctrl(mtd, NAND_CMD_READSTART, NAND_CLE);
|
||||
chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0);
|
||||
}
|
||||
|
||||
/* wait for nand ready */
|
||||
ndelay(100);
|
||||
timeo = (CONFIG_SYS_HZ * 20) / 1000;
|
||||
time_start = get_timer(0);
|
||||
while (get_timer(time_start) < timeo) {
|
||||
if (chip->dev_ready(mtd))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int mxs_flash_ident(struct mtd_info *mtd)
|
||||
{
|
||||
register struct nand_chip *chip = mtd->priv;
|
||||
int i;
|
||||
u8 mfg_id, dev_id;
|
||||
u8 id_data[8];
|
||||
struct nand_onfi_params *p = &chip->onfi_params;
|
||||
|
||||
/* Reset the chip */
|
||||
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
|
||||
|
||||
/* Send the command for reading device ID */
|
||||
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
|
||||
|
||||
/* Read manufacturer and device IDs */
|
||||
mfg_id = chip->read_byte(mtd);
|
||||
dev_id = chip->read_byte(mtd);
|
||||
|
||||
/* Try again to make sure */
|
||||
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
|
||||
for (i = 0; i < 8; i++)
|
||||
id_data[i] = chip->read_byte(mtd);
|
||||
if (id_data[0] != mfg_id || id_data[1] != dev_id) {
|
||||
printf("second ID read did not match");
|
||||
return -1;
|
||||
}
|
||||
debug("0x%02x:0x%02x ", mfg_id, dev_id);
|
||||
|
||||
/* read ONFI */
|
||||
chip->onfi_version = 0;
|
||||
chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1);
|
||||
if (chip->read_byte(mtd) != 'O' || chip->read_byte(mtd) != 'N' ||
|
||||
chip->read_byte(mtd) != 'F' || chip->read_byte(mtd) != 'I') {
|
||||
return -2;
|
||||
}
|
||||
|
||||
/* we have ONFI, probe it */
|
||||
chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1);
|
||||
chip->read_buf(mtd, (uint8_t *)p, sizeof(*p));
|
||||
mtd->name = p->model;
|
||||
mtd->writesize = le32_to_cpu(p->byte_per_page);
|
||||
mtd->erasesize = le32_to_cpu(p->pages_per_block) * mtd->writesize;
|
||||
mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
|
||||
chip->chipsize = le32_to_cpu(p->blocks_per_lun);
|
||||
chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
|
||||
/* Calculate the address shift from the page size */
|
||||
chip->page_shift = ffs(mtd->writesize) - 1;
|
||||
chip->phys_erase_shift = ffs(mtd->erasesize) - 1;
|
||||
/* Convert chipsize to number of pages per chip -1 */
|
||||
chip->pagemask = (chip->chipsize >> chip->page_shift) - 1;
|
||||
chip->badblockbits = 8;
|
||||
|
||||
debug("erasesize=%d (>>%d)\n", mtd->erasesize, chip->phys_erase_shift);
|
||||
debug("writesize=%d (>>%d)\n", mtd->writesize, chip->page_shift);
|
||||
debug("oobsize=%d\n", mtd->oobsize);
|
||||
debug("chipsize=%lld\n", chip->chipsize);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mxs_read_page_ecc(struct mtd_info *mtd, void *buf, unsigned int page)
|
||||
{
|
||||
register struct nand_chip *chip = mtd->priv;
|
||||
int ret;
|
||||
|
||||
chip->cmdfunc(mtd, NAND_CMD_READ0, 0x0, page);
|
||||
ret = nand_chip.ecc.read_page(mtd, chip, buf, 1, page);
|
||||
if (ret < 0) {
|
||||
printf("read_page failed %d\n", ret);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int is_badblock(struct mtd_info *mtd, loff_t offs, int allowbbt)
|
||||
{
|
||||
register struct nand_chip *chip = mtd->priv;
|
||||
unsigned int block = offs >> chip->phys_erase_shift;
|
||||
unsigned int page = offs >> chip->page_shift;
|
||||
|
||||
debug("%s offs=0x%08x block:%d page:%d\n", __func__, (int)offs, block,
|
||||
page);
|
||||
chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page);
|
||||
memset(chip->oob_poi, 0, mtd->oobsize);
|
||||
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
|
||||
|
||||
return chip->oob_poi[0] != 0xff;
|
||||
}
|
||||
|
||||
/* setup mtd and nand structs and init mxs_nand driver */
|
||||
static int mxs_nand_init(void)
|
||||
{
|
||||
/* return if already initalized */
|
||||
if (nand_chip.numchips)
|
||||
return 0;
|
||||
|
||||
/* init mxs nand driver */
|
||||
board_nand_init(&nand_chip);
|
||||
mtd.priv = &nand_chip;
|
||||
/* set mtd functions */
|
||||
nand_chip.cmdfunc = mxs_nand_command;
|
||||
nand_chip.numchips = 1;
|
||||
|
||||
/* identify flash device */
|
||||
puts("NAND : ");
|
||||
if (mxs_flash_ident(&mtd)) {
|
||||
printf("Failed to identify\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* allocate and initialize buffers */
|
||||
nand_chip.buffers = memalign(ARCH_DMA_MINALIGN,
|
||||
sizeof(*nand_chip.buffers));
|
||||
nand_chip.oob_poi = nand_chip.buffers->databuf + mtd.writesize;
|
||||
/* setup flash layout (does not scan as we override that) */
|
||||
mtd.size = nand_chip.chipsize;
|
||||
nand_chip.scan_bbt(&mtd);
|
||||
|
||||
printf("%llu MiB\n", (mtd.size / (1024 * 1024)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nand_spl_load_image(uint32_t offs, unsigned int size, void *buf)
|
||||
{
|
||||
struct nand_chip *chip;
|
||||
unsigned int page;
|
||||
unsigned int nand_page_per_block;
|
||||
unsigned int sz = 0;
|
||||
|
||||
if (mxs_nand_init())
|
||||
return -ENODEV;
|
||||
chip = mtd.priv;
|
||||
page = offs >> chip->page_shift;
|
||||
nand_page_per_block = mtd.erasesize / mtd.writesize;
|
||||
|
||||
debug("%s offset:0x%08x len:%d page:%d\n", __func__, offs, size, page);
|
||||
|
||||
size = roundup(size, mtd.writesize);
|
||||
while (sz < size) {
|
||||
if (mxs_read_page_ecc(&mtd, buf, page) < 0)
|
||||
return -1;
|
||||
sz += mtd.writesize;
|
||||
offs += mtd.writesize;
|
||||
page++;
|
||||
buf += mtd.writesize;
|
||||
|
||||
/*
|
||||
* Check if we have crossed a block boundary, and if so
|
||||
* check for bad block.
|
||||
*/
|
||||
if (!(page % nand_page_per_block)) {
|
||||
/*
|
||||
* Yes, new block. See if this block is good. If not,
|
||||
* loop until we find a good block.
|
||||
*/
|
||||
while (is_badblock(&mtd, offs, 1)) {
|
||||
page = page + nand_page_per_block;
|
||||
/* Check i we've reached the end of flash. */
|
||||
if (page >= mtd.size >> chip->page_shift)
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nand_default_bbt(struct mtd_info *mtd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nand_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
void nand_deselect(void)
|
||||
{
|
||||
}
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -210,6 +210,10 @@ int pmic_init(unsigned char bus)
|
||||
{
|
||||
static const char name[] = "MAX77686_PMIC";
|
||||
struct pmic *p = pmic_alloc();
|
||||
#ifdef CONFIG_OF_CONTROL
|
||||
const void *blob = gd->fdt_blob;
|
||||
int node, parent, tmp;
|
||||
#endif
|
||||
|
||||
if (!p) {
|
||||
printf("%s: POWER allocation error!\n", __func__);
|
||||
@@ -217,9 +221,6 @@ int pmic_init(unsigned char bus)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF_CONTROL
|
||||
const void *blob = gd->fdt_blob;
|
||||
int node, parent;
|
||||
|
||||
node = fdtdec_next_compatible(blob, 0, COMPAT_MAXIM_MAX77686_PMIC);
|
||||
if (node < 0) {
|
||||
debug("PMIC: No node for PMIC Chip in device tree\n");
|
||||
@@ -233,11 +234,13 @@ int pmic_init(unsigned char bus)
|
||||
return -1;
|
||||
}
|
||||
|
||||
p->bus = i2c_get_bus_num_fdt(parent);
|
||||
if (p->bus < 0) {
|
||||
/* tmp since p->bus is unsigned */
|
||||
tmp = i2c_get_bus_num_fdt(parent);
|
||||
if (tmp < 0) {
|
||||
debug("%s: Cannot find I2C bus\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
p->bus = tmp;
|
||||
p->hw.i2c.addr = fdtdec_get_int(blob, node, "reg", 9);
|
||||
#else
|
||||
p->bus = bus;
|
||||
|
@@ -77,7 +77,7 @@
|
||||
#define UCR3_DSR (1<<10) /* Data set ready */
|
||||
#define UCR3_DCD (1<<9) /* Data carrier detect */
|
||||
#define UCR3_RI (1<<8) /* Ring indicator */
|
||||
#define UCR3_TIMEOUTEN (1<<7) /* Timeout interrupt enable */
|
||||
#define UCR3_ADNIMP (1<<7) /* Autobaud Detection Not Improved */
|
||||
#define UCR3_RXDSEN (1<<6) /* Receive status interrupt enable */
|
||||
#define UCR3_AIRINTEN (1<<5) /* Async IR wake interrupt enable */
|
||||
#define UCR3_AWAKEN (1<<4) /* Async wake interrupt enable */
|
||||
@@ -186,7 +186,7 @@ static int mxc_serial_init(void)
|
||||
|
||||
while (!(__REG(UART_PHYS + UCR2) & UCR2_SRST));
|
||||
|
||||
__REG(UART_PHYS + UCR3) = 0x0704;
|
||||
__REG(UART_PHYS + UCR3) = 0x0704 | UCR3_ADNIMP;
|
||||
__REG(UART_PHYS + UCR4) = 0x8000;
|
||||
__REG(UART_PHYS + UESC) = 0x002b;
|
||||
__REG(UART_PHYS + UTIM) = 0x0;
|
||||
|
@@ -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
|
||||
|
@@ -41,7 +41,7 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
|
||||
break;
|
||||
#ifdef CONFIG_SYS_SPI1
|
||||
case SPI1_BUS:
|
||||
ds->regs = (struct davinci_spi_regs *)SPI0_BASE;
|
||||
ds->regs = (struct davinci_spi_regs *)SPI1_BASE;
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_SPI2
|
||||
|
@@ -302,7 +302,10 @@ static int spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo,
|
||||
}
|
||||
} else {
|
||||
if (rxp || stopping) {
|
||||
*rxp = temp;
|
||||
if (step == 4)
|
||||
*(uint32_t *)rxp = temp;
|
||||
else
|
||||
*rxp = temp;
|
||||
rxp += step;
|
||||
}
|
||||
in_bytes -= step;
|
||||
|
482
drivers/spi/fsl_qspi.c
Normal file
482
drivers/spi/fsl_qspi.c
Normal file
@@ -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 */
|
||||
}
|
127
drivers/spi/fsl_qspi.h
Normal file
127
drivers/spi/fsl_qspi.h
Normal file
@@ -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_ */
|
@@ -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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user