summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorStefano Babic <sbabic@denx.de>2014-08-11 10:21:03 +0200
committerStefano Babic <sbabic@denx.de>2014-08-11 10:21:03 +0200
commite82abaeb7f2a0833fccf90460c48b9f2100258f8 (patch)
treede701f5c90b7373966412d566b5c00d3837954bc /drivers
parentf93f21906e374d46c6abfbdf4eb9cb1ab51b6384 (diff)
parent1899fac925eda817e12234aef3d01d354788662e (diff)
Merge branch 'master' of git://git.denx.de/u-boot-arm
Conflicts: boards.cfg Signed-off-by: Stefano Babic <sbabic@denx.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/block/ahci.c16
-rw-r--r--drivers/bootcount/bootcount.c2
-rw-r--r--drivers/ddr/fsl/ctrl_regs.c3
-rw-r--r--drivers/ddr/fsl/fsl_ddr_gen4.c7
-rw-r--r--drivers/misc/cros_ec_spi.c4
-rw-r--r--drivers/mmc/Makefile2
-rw-r--r--drivers/mmc/bcm2835_sdhci.c2
-rw-r--r--drivers/mmc/dw_mmc.c5
-rw-r--r--drivers/mmc/gen_atmel_mci.c63
-rw-r--r--drivers/mmc/mvebu_mmc.c361
-rw-r--r--drivers/mmc/s3c_sdi.c321
-rw-r--r--drivers/mtd/nand/fsl_ifc_nand.c45
-rw-r--r--drivers/mtd/nand/fsl_ifc_spl.c6
-rw-r--r--drivers/mtd/spi/sf_ops.c1
-rw-r--r--drivers/net/fm/fm.h3
-rw-r--r--drivers/net/fm/init.c6
-rw-r--r--drivers/net/fm/memac_phy.c2
-rw-r--r--drivers/net/fm/tgec_phy.c2
-rw-r--r--drivers/pci/fsl_pci_init.c10
-rw-r--r--drivers/qe/qe.c2
-rw-r--r--drivers/qe/uccf.c2
-rw-r--r--drivers/qe/uccf.h2
-rw-r--r--drivers/qe/uec.c2
-rw-r--r--drivers/qe/uec_phy.c2
-rw-r--r--drivers/spi/exynos_spi.c9
-rw-r--r--drivers/spi/mxc_spi.c17
-rw-r--r--drivers/spi/spi.c2
-rw-r--r--drivers/usb/host/Makefile1
-rw-r--r--drivers/usb/host/ehci-sunxi.c201
29 files changed, 1056 insertions, 45 deletions
diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c
index 4df804671a..dce99adc6b 100644
--- a/drivers/block/ahci.c
+++ b/drivers/block/ahci.c
@@ -129,6 +129,14 @@ int __weak ahci_link_up(struct ahci_probe_ent *probe_ent, u8 port)
return 1;
}
+#ifdef CONFIG_SUNXI_AHCI
+/* The sunxi AHCI controller requires this undocumented setup */
+static void sunxi_dma_init(volatile u8 *port_mmio)
+{
+ clrsetbits_le32(port_mmio + PORT_P0DMACR, 0x0000ff00, 0x00004400);
+}
+#endif
+
static int ahci_host_init(struct ahci_probe_ent *probe_ent)
{
#ifndef CONFIG_SCSI_AHCI_PLAT
@@ -213,6 +221,10 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent)
msleep(500);
}
+#ifdef CONFIG_SUNXI_AHCI
+ sunxi_dma_init(port_mmio);
+#endif
+
/* Add the spinup command to whatever mode bits may
* already be on in the command register.
*/
@@ -545,6 +557,10 @@ static int ahci_port_start(u8 port)
writel_with_flush(pp->rx_fis, port_mmio + PORT_FIS_ADDR);
+#ifdef CONFIG_SUNXI_AHCI
+ sunxi_dma_init(port_mmio);
+#endif
+
writel_with_flush(PORT_CMD_ICC_ACTIVE | PORT_CMD_FIS_RX |
PORT_CMD_POWER_ON | PORT_CMD_SPIN_UP |
PORT_CMD_START, port_mmio + PORT_CMD);
diff --git a/drivers/bootcount/bootcount.c b/drivers/bootcount/bootcount.c
index 3ad441393e..e0343f71d7 100644
--- a/drivers/bootcount/bootcount.c
+++ b/drivers/bootcount/bootcount.c
@@ -36,7 +36,7 @@
#endif /* defined(CONFIG_MPC8260) */
#if defined(CONFIG_QE)
-#include <asm/immap_qe.h>
+#include <linux/immap_qe.h>
#define CONFIG_SYS_BOOTCOUNT_ADDR (CONFIG_SYS_IMMR + 0x110000 + \
QE_MURAM_SIZE - 2 * sizeof(u32))
diff --git a/drivers/ddr/fsl/ctrl_regs.c b/drivers/ddr/fsl/ctrl_regs.c
index dcf6287f66..04e4178b15 100644
--- a/drivers/ddr/fsl/ctrl_regs.c
+++ b/drivers/ddr/fsl/ctrl_regs.c
@@ -1857,6 +1857,9 @@ static void set_timing_cfg_8(fsl_ddr_cfg_regs_t *ddr,
acttoact_bg = picos_to_mclk(common_dimm->trrdl_ps);
wrtord_bg = max(4, picos_to_mclk(7500));
+ if (popts->otf_burst_chop_en)
+ wrtord_bg += 2;
+
pre_all_rec = 0;
ddr->timing_cfg_8 = (0
diff --git a/drivers/ddr/fsl/fsl_ddr_gen4.c b/drivers/ddr/fsl/fsl_ddr_gen4.c
index 7cd878aeec..bfc76b3485 100644
--- a/drivers/ddr/fsl/fsl_ddr_gen4.c
+++ b/drivers/ddr/fsl/fsl_ddr_gen4.c
@@ -8,6 +8,7 @@
#include <asm/io.h>
#include <fsl_ddr_sdram.h>
#include <asm/processor.h>
+#include <fsl_immap.h>
#include <fsl_ddr.h>
#if (CONFIG_CHIP_SELECTS_PER_CTRL > 4)
@@ -183,12 +184,14 @@ step2:
* we choose the max, that is 500 us for all of case.
*/
udelay(500);
- asm volatile("sync;isync");
+ mb();
+ isb();
/* Let the controller go */
temp_sdram_cfg = ddr_in32(&ddr->sdram_cfg) & ~SDRAM_CFG_BI;
ddr_out32(&ddr->sdram_cfg, temp_sdram_cfg | SDRAM_CFG_MEM_EN);
- asm volatile("sync;isync");
+ mb();
+ isb();
total_gb_size_per_controller = 0;
for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
diff --git a/drivers/misc/cros_ec_spi.c b/drivers/misc/cros_ec_spi.c
index 7df709cc71..015333f139 100644
--- a/drivers/misc/cros_ec_spi.c
+++ b/drivers/misc/cros_ec_spi.c
@@ -98,7 +98,7 @@ int cros_ec_spi_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
}
out = dev->dout;
- out[0] = cmd_version;
+ out[0] = EC_CMD_VERSION0 + cmd_version;
out[1] = cmd;
out[2] = (uint8_t)dout_len;
memcpy(out + 3, dout, dout_len);
@@ -165,7 +165,7 @@ int cros_ec_spi_decode_fdt(struct cros_ec_dev *dev, const void *blob)
*/
int cros_ec_spi_init(struct cros_ec_dev *dev, const void *blob)
{
- dev->spi = spi_setup_slave_fdt(blob, dev->parent_node, dev->node);
+ dev->spi = spi_setup_slave_fdt(blob, dev->node, dev->parent_node);
if (!dev->spi) {
debug("%s: Could not setup SPI slave\n", __func__);
return -1;
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 34febf52f0..464cee16d1 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_PXA_MMC_GENERIC) += pxa_mmc_gen.o
obj-$(CONFIG_SDHCI) += sdhci.o
obj-$(CONFIG_BCM2835_SDHCI) += bcm2835_sdhci.o
obj-$(CONFIG_KONA_SDHCI) += kona_sdhci.o
+obj-$(CONFIG_S3C_SDI) += s3c_sdi.o
obj-$(CONFIG_S5P_SDHCI) += s5p_sdhci.o
obj-$(CONFIG_SH_MMCIF) += sh_mmcif.o
obj-$(CONFIG_SPEAR_SDHCI) += spear_sdhci.o
@@ -37,3 +38,4 @@ obj-$(CONFIG_SPL_MMC_BOOT) += fsl_esdhc_spl.o
else
obj-$(CONFIG_GENERIC_MMC) += mmc_write.o
endif
+obj-$(CONFIG_MVEBU_MMC) += mvebu_mmc.o
diff --git a/drivers/mmc/bcm2835_sdhci.c b/drivers/mmc/bcm2835_sdhci.c
index 54cfabfb91..82079d67cd 100644
--- a/drivers/mmc/bcm2835_sdhci.c
+++ b/drivers/mmc/bcm2835_sdhci.c
@@ -179,7 +179,7 @@ int bcm2835_sdhci_init(u32 regbase, u32 emmc_freq)
host->name = "bcm2835_sdhci";
host->ioaddr = (void *)regbase;
host->quirks = SDHCI_QUIRK_BROKEN_VOLTAGE | SDHCI_QUIRK_BROKEN_R1B |
- SDHCI_QUIRK_WAIT_SEND_CMD;
+ SDHCI_QUIRK_WAIT_SEND_CMD | SDHCI_QUIRK_NO_HISPD_BIT;
host->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
host->ops = &bcm2835_ops;
diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c
index 5bf36a0309..0df30bc045 100644
--- a/drivers/mmc/dw_mmc.c
+++ b/drivers/mmc/dw_mmc.c
@@ -245,7 +245,10 @@ static int dwmci_setup_bus(struct dwmci_host *host, u32 freq)
return -EINVAL;
}
- div = DIV_ROUND_UP(sclk, 2 * freq);
+ if (sclk == freq)
+ div = 0; /* bypass mode */
+ else
+ div = DIV_ROUND_UP(sclk, 2 * freq);
dwmci_writel(host, DWMCI_CLKENA, 0);
dwmci_writel(host, DWMCI_CLKSRC, 0);
diff --git a/drivers/mmc/gen_atmel_mci.c b/drivers/mmc/gen_atmel_mci.c
index a57a9b1faf..45bcffb6b2 100644
--- a/drivers/mmc/gen_atmel_mci.c
+++ b/drivers/mmc/gen_atmel_mci.c
@@ -58,30 +58,61 @@ static void mci_set_mode(struct mmc *mmc, u32 hz, u32 blklen)
atmel_mci_t *mci = mmc->priv;
u32 bus_hz = get_mci_clk_rate();
u32 clkdiv = 255;
+ unsigned int version = atmel_mci_get_version(mci);
+ u32 clkodd = 0;
+ u32 mr;
debug("mci: bus_hz is %u, setting clock %u Hz, block size %u\n",
bus_hz, hz, blklen);
if (hz > 0) {
- /* find lowest clkdiv yielding a rate <= than requested */
- for (clkdiv=0; clkdiv<255; clkdiv++) {
- if ((bus_hz / (clkdiv+1) / 2) <= hz)
- break;
+ if (version >= 0x500) {
+ clkdiv = DIV_ROUND_UP(bus_hz, hz) - 2;
+ if (clkdiv > 511)
+ clkdiv = 511;
+
+ clkodd = clkdiv & 1;
+ clkdiv >>= 1;
+
+ printf("mci: setting clock %u Hz, block size %u\n",
+ bus_hz / (clkdiv * 2 + clkodd + 2), blklen);
+ } else {
+ /* find clkdiv yielding a rate <= than requested */
+ for (clkdiv = 0; clkdiv < 255; clkdiv++) {
+ if ((bus_hz / (clkdiv + 1) / 2) <= hz)
+ break;
+ }
+ printf("mci: setting clock %u Hz, block size %u\n",
+ (bus_hz / (clkdiv + 1)) / 2, blklen);
+
}
}
- printf("mci: setting clock %u Hz, block size %u\n",
- (bus_hz / (clkdiv+1)) / 2, blklen);
blklen &= 0xfffc;
- /* On some platforms RDPROOF and WRPROOF are ignored */
- writel((MMCI_BF(CLKDIV, clkdiv)
- | MMCI_BF(BLKLEN, blklen)
- | MMCI_BIT(RDPROOF)
- | MMCI_BIT(WRPROOF)), &mci->mr);
+
+ mr = MMCI_BF(CLKDIV, clkdiv);
+
+ /* MCI IP version >= 0x200 has R/WPROOF */
+ if (version >= 0x200)
+ mr |= MMCI_BIT(RDPROOF) | MMCI_BIT(WRPROOF);
+
/*
- * On some new platforms BLKLEN in mci->mr is ignored.
- * Should use the BLKLEN in the block register.
+ * MCI IP version >= 0x500 use bit 16 as clkodd.
+ * MCI IP version < 0x500 use upper 16 bits for blklen.
*/
- writel(MMCI_BF(BLKLEN, blklen), &mci->blkr);
+ if (version >= 0x500)
+ mr |= MMCI_BF(CLKODD, clkodd);
+ else
+ mr |= MMCI_BF(BLKLEN, blklen);
+
+ writel(mr, &mci->mr);
+
+ /* MCI IP version >= 0x200 has blkr */
+ if (version >= 0x200)
+ writel(MMCI_BF(BLKLEN, blklen), &mci->blkr);
+
+ if (mmc->card_caps & mmc->cfg->host_caps & MMC_MODE_HS)
+ writel(MMCI_BIT(HSMODE), &mci->cfg);
+
initialized = 1;
}
@@ -376,8 +407,10 @@ int atmel_mci_init(void *regs)
/* need to be able to pass these in on a board by board basis */
cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
version = atmel_mci_get_version(mci);
- if ((version & 0xf00) >= 0x300)
+ if ((version & 0xf00) >= 0x300) {
cfg->host_caps = MMC_MODE_8BIT;
+ cfg->host_caps |= MMC_MODE_HS | MMC_MODE_HS_52MHz;
+ }
cfg->host_caps |= MMC_MODE_4BIT;
diff --git a/drivers/mmc/mvebu_mmc.c b/drivers/mmc/mvebu_mmc.c
new file mode 100644
index 0000000000..97591983d2
--- /dev/null
+++ b/drivers/mmc/mvebu_mmc.c
@@ -0,0 +1,361 @@
+/*
+ * Marvell MMC/SD/SDIO driver
+ *
+ * (C) Copyright 2012
+ * Marvell Semiconductor <www.marvell.com>
+ * Written-by: Maen Suleiman, Gerald Kerma
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <part.h>
+#include <mmc.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/kirkwood.h>
+#include <mvebu_mmc.h>
+
+#define DRIVER_NAME "MVEBU_MMC"
+
+static void mvebu_mmc_write(u32 offs, u32 val)
+{
+ writel(val, CONFIG_SYS_MMC_BASE + (offs));
+}
+
+static u32 mvebu_mmc_read(u32 offs)
+{
+ return readl(CONFIG_SYS_MMC_BASE + (offs));
+}
+
+static int mvebu_mmc_setup_data(struct mmc_data *data)
+{
+ u32 ctrl_reg;
+
+ debug("%s, data %s : blocks=%d blksz=%d\n", DRIVER_NAME,
+ (data->flags & MMC_DATA_READ) ? "read" : "write",
+ data->blocks, data->blocksize);
+
+ /* default to maximum timeout */
+ ctrl_reg = mvebu_mmc_read(SDIO_HOST_CTRL);
+ ctrl_reg |= SDIO_HOST_CTRL_TMOUT(SDIO_HOST_CTRL_TMOUT_MAX);
+ mvebu_mmc_write(SDIO_HOST_CTRL, ctrl_reg);
+
+ if (data->flags & MMC_DATA_READ) {
+ mvebu_mmc_write(SDIO_SYS_ADDR_LOW, (u32)data->dest & 0xffff);
+ mvebu_mmc_write(SDIO_SYS_ADDR_HI, (u32)data->dest >> 16);
+ } else {
+ mvebu_mmc_write(SDIO_SYS_ADDR_LOW, (u32)data->src & 0xffff);
+ mvebu_mmc_write(SDIO_SYS_ADDR_HI, (u32)data->src >> 16);
+ }
+
+ mvebu_mmc_write(SDIO_BLK_COUNT, data->blocks);
+ mvebu_mmc_write(SDIO_BLK_SIZE, data->blocksize);
+
+ return 0;
+}
+
+static int mvebu_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
+ struct mmc_data *data)
+{
+ int timeout = 10;
+ ushort waittype = 0;
+ ushort resptype = 0;
+ ushort xfertype = 0;
+ ushort resp_indx = 0;
+
+ debug("cmdidx [0x%x] resp_type[0x%x] cmdarg[0x%x]\n",
+ cmd->cmdidx, cmd->resp_type, cmd->cmdarg);
+
+ udelay(10*1000);
+
+ debug("%s: cmd %d (hw state 0x%04x)\n", DRIVER_NAME,
+ cmd->cmdidx, mvebu_mmc_read(SDIO_HW_STATE));
+
+ /* Checking if card is busy */
+ while ((mvebu_mmc_read(SDIO_HW_STATE) & CARD_BUSY)) {
+ if (timeout == 0) {
+ printf("%s: card busy!\n", DRIVER_NAME);
+ return -1;
+ }
+ timeout--;
+ udelay(1000);
+ }
+
+ /* Set up for a data transfer if we have one */
+ if (data) {
+ int err = mvebu_mmc_setup_data(data);
+
+ if (err)
+ return err;
+ }
+
+ resptype = SDIO_CMD_INDEX(cmd->cmdidx);
+
+ /* Analyzing resptype/xfertype/waittype for the command */
+ if (cmd->resp_type & MMC_RSP_BUSY)
+ resptype |= SDIO_CMD_RSP_48BUSY;
+ else if (cmd->resp_type & MMC_RSP_136)
+ resptype |= SDIO_CMD_RSP_136;
+ else if (cmd->resp_type & MMC_RSP_PRESENT)
+ resptype |= SDIO_CMD_RSP_48;
+ else
+ resptype |= SDIO_CMD_RSP_NONE;
+
+ if (cmd->resp_type & MMC_RSP_CRC)
+ resptype |= SDIO_CMD_CHECK_CMDCRC;
+
+ if (cmd->resp_type & MMC_RSP_OPCODE)
+ resptype |= SDIO_CMD_INDX_CHECK;
+
+ if (cmd->resp_type & MMC_RSP_PRESENT) {
+ resptype |= SDIO_UNEXPECTED_RESP;
+ waittype |= SDIO_NOR_UNEXP_RSP;
+ }
+
+ if (data) {
+ resptype |= SDIO_CMD_DATA_PRESENT | SDIO_CMD_CHECK_DATACRC16;
+ xfertype |= SDIO_XFER_MODE_HW_WR_DATA_EN;
+ if (data->flags & MMC_DATA_READ) {
+ xfertype |= SDIO_XFER_MODE_TO_HOST;
+ waittype = SDIO_NOR_DMA_INI;
+ } else {
+ waittype |= SDIO_NOR_XFER_DONE;
+ }
+ } else {
+ waittype |= SDIO_NOR_CMD_DONE;
+ }
+
+ /* Setting cmd arguments */
+ mvebu_mmc_write(SDIO_ARG_LOW, cmd->cmdarg & 0xffff);
+ mvebu_mmc_write(SDIO_ARG_HI, cmd->cmdarg >> 16);
+
+ /* Setting Xfer mode */
+ mvebu_mmc_write(SDIO_XFER_MODE, xfertype);
+
+ mvebu_mmc_write(SDIO_NOR_INTR_STATUS, ~SDIO_NOR_CARD_INT);
+ mvebu_mmc_write(SDIO_ERR_INTR_STATUS, SDIO_POLL_MASK);
+
+ /* Sending command */
+ mvebu_mmc_write(SDIO_CMD, resptype);
+
+ mvebu_mmc_write(SDIO_NOR_INTR_EN, SDIO_POLL_MASK);
+ mvebu_mmc_write(SDIO_ERR_INTR_EN, SDIO_POLL_MASK);
+
+ /* Waiting for completion */
+ timeout = 1000000;
+
+ while (!((mvebu_mmc_read(SDIO_NOR_INTR_STATUS)) & waittype)) {
+ if (mvebu_mmc_read(SDIO_NOR_INTR_STATUS) & SDIO_NOR_ERROR) {
+ debug("%s: error! cmdidx : %d, err reg: %04x\n",
+ DRIVER_NAME, cmd->cmdidx,
+ mvebu_mmc_read(SDIO_ERR_INTR_STATUS));
+ if (mvebu_mmc_read(SDIO_ERR_INTR_STATUS) &
+ (SDIO_ERR_CMD_TIMEOUT | SDIO_ERR_DATA_TIMEOUT))
+ return TIMEOUT;
+ return COMM_ERR;
+ }
+
+ timeout--;
+ udelay(1);
+ if (timeout <= 0) {
+ printf("%s: command timed out\n", DRIVER_NAME);
+ return TIMEOUT;
+ }
+ }
+
+ /* Handling response */
+ if (cmd->resp_type & MMC_RSP_136) {
+ uint response[8];
+
+ for (resp_indx = 0; resp_indx < 8; resp_indx++)
+ response[resp_indx]
+ = mvebu_mmc_read(SDIO_RSP(resp_indx));
+
+ cmd->response[0] = ((response[0] & 0x03ff) << 22) |
+ ((response[1] & 0xffff) << 6) |
+ ((response[2] & 0xfc00) >> 10);
+ cmd->response[1] = ((response[2] & 0x03ff) << 22) |
+ ((response[3] & 0xffff) << 6) |
+ ((response[4] & 0xfc00) >> 10);
+ cmd->response[2] = ((response[4] & 0x03ff) << 22) |
+ ((response[5] & 0xffff) << 6) |
+ ((response[6] & 0xfc00) >> 10);
+ cmd->response[3] = ((response[6] & 0x03ff) << 22) |
+ ((response[7] & 0x3fff) << 8);
+ } else if (cmd->resp_type & MMC_RSP_PRESENT) {
+ uint response[3];
+
+ for (resp_indx = 0; resp_indx < 3; resp_indx++)
+ response[resp_indx]
+ = mvebu_mmc_read(SDIO_RSP(resp_indx));
+
+ cmd->response[0] = ((response[2] & 0x003f) << (8 - 8)) |
+ ((response[1] & 0xffff) << (14 - 8)) |
+ ((response[0] & 0x03ff) << (30 - 8));
+ cmd->response[1] = ((response[0] & 0xfc00) >> 10);
+ cmd->response[2] = 0;
+ cmd->response[3] = 0;
+ }
+
+ debug("%s: resp[0x%x] ", DRIVER_NAME, cmd->resp_type);
+ debug("[0x%x] ", cmd->response[0]);
+ debug("[0x%x] ", cmd->response[1]);
+ debug("[0x%x] ", cmd->response[2]);
+ debug("[0x%x] ", cmd->response[3]);
+ debug("\n");
+
+ return 0;
+}
+
+static void mvebu_mmc_power_up(void)
+{
+ debug("%s: power up\n", DRIVER_NAME);
+
+ /* disable interrupts */
+ mvebu_mmc_write(SDIO_NOR_INTR_EN, 0);
+ mvebu_mmc_write(SDIO_ERR_INTR_EN, 0);
+
+ /* SW reset */
+ mvebu_mmc_write(SDIO_SW_RESET, SDIO_SW_RESET_NOW);
+
+ mvebu_mmc_write(SDIO_XFER_MODE, 0);
+
+ /* enable status */
+ mvebu_mmc_write(SDIO_NOR_STATUS_EN, SDIO_POLL_MASK);
+ mvebu_mmc_write(SDIO_ERR_STATUS_EN, SDIO_POLL_MASK);
+
+ /* enable interrupts status */
+ mvebu_mmc_write(SDIO_NOR_INTR_STATUS, SDIO_POLL_MASK);
+ mvebu_mmc_write(SDIO_ERR_INTR_STATUS, SDIO_POLL_MASK);
+}
+
+static void mvebu_mmc_set_clk(unsigned int clock)
+{
+ unsigned int m;
+
+ if (clock == 0) {
+ debug("%s: clock off\n", DRIVER_NAME);
+ mvebu_mmc_write(SDIO_XFER_MODE, SDIO_XFER_MODE_STOP_CLK);
+ mvebu_mmc_write(SDIO_CLK_DIV, MVEBU_MMC_BASE_DIV_MAX);
+ } else {
+ m = MVEBU_MMC_BASE_FAST_CLOCK/(2*clock) - 1;
+ if (m > MVEBU_MMC_BASE_DIV_MAX)
+ m = MVEBU_MMC_BASE_DIV_MAX;
+ mvebu_mmc_write(SDIO_CLK_DIV, m & MVEBU_MMC_BASE_DIV_MAX);
+ }
+
+ udelay(10*1000);
+}
+
+static void mvebu_mmc_set_bus(unsigned int bus)
+{
+ u32 ctrl_reg = 0;
+
+ ctrl_reg = mvebu_mmc_read(SDIO_HOST_CTRL);
+ ctrl_reg &= ~SDIO_HOST_CTRL_DATA_WIDTH_4_BITS;
+
+ switch (bus) {
+ case 4:
+ ctrl_reg |= SDIO_HOST_CTRL_DATA_WIDTH_4_BITS;
+ break;
+ case 1:
+ default:
+ ctrl_reg |= SDIO_HOST_CTRL_DATA_WIDTH_1_BIT;
+ }
+
+ /* default transfer mode */
+ ctrl_reg |= SDIO_HOST_CTRL_BIG_ENDIAN;
+ ctrl_reg &= ~SDIO_HOST_CTRL_LSB_FIRST;
+
+ /* default to maximum timeout */
+ ctrl_reg |= SDIO_HOST_CTRL_TMOUT(SDIO_HOST_CTRL_TMOUT_MAX);
+
+ ctrl_reg |= SDIO_HOST_CTRL_PUSH_PULL_EN;
+
+ ctrl_reg |= SDIO_HOST_CTRL_CARD_TYPE_MEM_ONLY;
+
+ debug("%s: ctrl 0x%04x: %s %s %s\n", DRIVER_NAME, ctrl_reg,
+ (ctrl_reg & SDIO_HOST_CTRL_PUSH_PULL_EN) ?
+ "push-pull" : "open-drain",
+ (ctrl_reg & SDIO_HOST_CTRL_DATA_WIDTH_4_BITS) ?
+ "4bit-width" : "1bit-width",
+ (ctrl_reg & SDIO_HOST_CTRL_HI_SPEED_EN) ?
+ "high-speed" : "");
+
+ mvebu_mmc_write(SDIO_HOST_CTRL, ctrl_reg);
+ udelay(10*1000);
+}
+
+static void mvebu_mmc_set_ios(struct mmc *mmc)
+{
+ debug("%s: bus[%d] clock[%d]\n", DRIVER_NAME,
+ mmc->bus_width, mmc->clock);
+ mvebu_mmc_set_bus(mmc->bus_width);
+ mvebu_mmc_set_clk(mmc->clock);
+}
+
+static int mvebu_mmc_initialize(struct mmc *mmc)
+{
+ debug("%s: mvebu_mmc_initialize", DRIVER_NAME);
+
+ /*
+ * Setting host parameters
+ * Initial Host Ctrl : Timeout : max , Normal Speed mode,
+ * 4-bit data mode, Big Endian, SD memory Card, Push_pull CMD Line
+ */
+ mvebu_mmc_write(SDIO_HOST_CTRL,
+ SDIO_HOST_CTRL_TMOUT(SDIO_HOST_CTRL_TMOUT_MAX) |
+ SDIO_HOST_CTRL_DATA_WIDTH_4_BITS |
+ SDIO_HOST_CTRL_BIG_ENDIAN |
+ SDIO_HOST_CTRL_PUSH_PULL_EN |
+ SDIO_HOST_CTRL_CARD_TYPE_MEM_ONLY);
+
+ mvebu_mmc_write(SDIO_CLK_CTRL, 0);
+
+ /* enable status */
+ mvebu_mmc_write(SDIO_NOR_STATUS_EN, SDIO_POLL_MASK);
+ mvebu_mmc_write(SDIO_ERR_STATUS_EN, SDIO_POLL_MASK);
+
+ /* disable interrupts */
+ mvebu_mmc_write(SDIO_NOR_INTR_EN, 0);
+ mvebu_mmc_write(SDIO_ERR_INTR_EN, 0);
+
+ /* SW reset */
+ mvebu_mmc_write(SDIO_SW_RESET, SDIO_SW_RESET_NOW);
+
+ udelay(10*1000);
+
+ return 0;
+}
+
+static const struct mmc_ops mvebu_mmc_ops = {
+ .send_cmd = mvebu_mmc_send_cmd,
+ .set_ios = mvebu_mmc_set_ios,
+ .init = mvebu_mmc_initialize,
+};
+
+static struct mmc_config mvebu_mmc_cfg = {
+ .name = DRIVER_NAME,
+ .ops = &mvebu_mmc_ops,
+ .f_min = MVEBU_MMC_BASE_FAST_CLOCK / MVEBU_MMC_BASE_DIV_MAX,
+ .f_max = MVEBU_MMC_CLOCKRATE_MAX,
+ .voltages = MMC_VDD_32_33 | MMC_VDD_33_34,
+ .host_caps = MMC_MODE_4BIT | MMC_MODE_HS,
+ .part_type = PART_TYPE_DOS,
+ .b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT,
+};
+
+int mvebu_mmc_init(bd_t *bis)
+{
+ struct mmc *mmc;
+
+ mvebu_mmc_power_up();
+
+ mmc = mmc_create(&mvebu_mmc_cfg, bis);
+ if (mmc == NULL)
+ return -1;
+
+ return 0;
+}
diff --git a/drivers/mmc/s3c_sdi.c b/drivers/mmc/s3c_sdi.c
new file mode 100644
index 0000000000..1b5b70512d
--- /dev/null
+++ b/drivers/mmc/s3c_sdi.c
@@ -0,0 +1,321 @@
+/*
+ * S3C24xx SD/MMC driver
+ *
+ * Based on OpenMoko S3C24xx driver by Harald Welte <laforge@openmoko.org>
+ *
+ * Copyright (C) 2014 Marek Vasut <marex@denx.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <mmc.h>
+#include <errno.h>
+#include <asm/arch/s3c24x0_cpu.h>
+#include <asm/io.h>
+#include <asm/unaligned.h>
+
+#define S3C2440_SDICON_SDRESET (1 << 8)
+#define S3C2410_SDICON_FIFORESET (1 << 1)
+#define S3C2410_SDICON_CLOCKTYPE (1 << 0)
+
+#define S3C2410_SDICMDCON_LONGRSP (1 << 10)
+#define S3C2410_SDICMDCON_WAITRSP (1 << 9)
+#define S3C2410_SDICMDCON_CMDSTART (1 << 8)
+#define S3C2410_SDICMDCON_SENDERHOST (1 << 6)
+#define S3C2410_SDICMDCON_INDEX 0x3f
+
+#define S3C2410_SDICMDSTAT_CRCFAIL (1 << 12)
+#define S3C2410_SDICMDSTAT_CMDSENT (1 << 11)
+#define S3C2410_SDICMDSTAT_CMDTIMEOUT (1 << 10)
+#define S3C2410_SDICMDSTAT_RSPFIN (1 << 9)
+
+#define S3C2440_SDIDCON_DS_WORD (2 << 22)
+#define S3C2410_SDIDCON_TXAFTERRESP (1 << 20)
+#define S3C2410_SDIDCON_RXAFTERCMD (1 << 19)
+#define S3C2410_SDIDCON_BLOCKMODE (1 << 17)
+#define S3C2410_SDIDCON_WIDEBUS (1 << 16)
+#define S3C2440_SDIDCON_DATSTART (1 << 14)
+#define S3C2410_SDIDCON_XFER_RXSTART (2 << 12)
+#define S3C2410_SDIDCON_XFER_TXSTART (3 << 12)
+#define S3C2410_SDIDCON_BLKNUM 0x7ff
+
+#define S3C2410_SDIDSTA_FIFOFAIL (1 << 8)
+#define S3C2410_SDIDSTA_CRCFAIL (1 << 7)
+#define S3C2410_SDIDSTA_RXCRCFAIL (1 << 6)
+#define S3C2410_SDIDSTA_DATATIMEOUT (1 << 5)
+#define S3C2410_SDIDSTA_XFERFINISH (1 << 4)
+
+#define S3C2410_SDIFSTA_TFHALF (1 << 11)
+#define S3C2410_SDIFSTA_COUNTMASK 0x7f
+
+/*
+ * WARNING: We only support one SD IP block.
+ * NOTE: It's not likely there will ever exist an S3C24xx with two,
+ * at least not in this universe all right.
+ */
+static int wide_bus;
+
+static int
+s3cmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
+{
+ struct s3c24x0_sdi *sdi_regs = s3c24x0_get_base_sdi();
+ uint32_t sdiccon, sdicsta, sdidcon, sdidsta, sdidat, sdifsta;
+ uint32_t sdicsta_wait_bit = S3C2410_SDICMDSTAT_CMDSENT;
+ unsigned int timeout = 100000;
+ int ret = 0, xfer_len, data_offset = 0;
+ const uint32_t sdidsta_err_mask = S3C2410_SDIDSTA_FIFOFAIL |
+ S3C2410_SDIDSTA_CRCFAIL | S3C2410_SDIDSTA_RXCRCFAIL |
+ S3C2410_SDIDSTA_DATATIMEOUT;
+
+
+ writel(0xffffffff, &sdi_regs->sdicsta);
+ writel(0xffffffff, &sdi_regs->sdidsta);
+ writel(0xffffffff, &sdi_regs->sdifsta);
+
+ /* Set up data transfer (if applicable). */
+ if (data) {
+ writel(data->blocksize, &sdi_regs->sdibsize);
+
+ sdidcon = data->blocks & S3C2410_SDIDCON_BLKNUM;
+ sdidcon |= S3C2410_SDIDCON_BLOCKMODE;
+#if defined(CONFIG_S3C2440)
+ sdidcon |= S3C2440_SDIDCON_DS_WORD | S3C2440_SDIDCON_DATSTART;
+#endif
+ if (wide_bus)
+ sdidcon |= S3C2410_SDIDCON_WIDEBUS;
+
+ if (data->flags & MMC_DATA_READ) {
+ sdidcon |= S3C2410_SDIDCON_RXAFTERCMD;
+ sdidcon |= S3C2410_SDIDCON_XFER_RXSTART;
+ } else {
+ sdidcon |= S3C2410_SDIDCON_TXAFTERRESP;
+ sdidcon |= S3C2410_SDIDCON_XFER_TXSTART;
+ }
+
+ writel(sdidcon, &sdi_regs->sdidcon);
+ }
+
+ /* Write CMD arg. */
+ writel(cmd->cmdarg, &sdi_regs->sdicarg);
+
+ /* Write CMD index. */
+ sdiccon = cmd->cmdidx & S3C2410_SDICMDCON_INDEX;
+ sdiccon |= S3C2410_SDICMDCON_SENDERHOST;
+ sdiccon |= S3C2410_SDICMDCON_CMDSTART;
+
+ /* Command with short response. */
+ if (cmd->resp_type & MMC_RSP_PRESENT) {
+ sdiccon |= S3C2410_SDICMDCON_WAITRSP;
+ sdicsta_wait_bit = S3C2410_SDICMDSTAT_RSPFIN;
+ }
+
+ /* Command with long response. */
+ if (cmd->resp_type & MMC_RSP_136)
+ sdiccon |= S3C2410_SDICMDCON_LONGRSP;
+
+ /* Start the command. */
+ writel(sdiccon, &sdi_regs->sdiccon);
+
+ /* Wait for the command to complete or for response. */
+ for (timeout = 100000; timeout; timeout--) {
+ sdicsta = readl(&sdi_regs->sdicsta);
+ if (sdicsta & sdicsta_wait_bit)
+ break;
+
+ if (sdicsta & S3C2410_SDICMDSTAT_CMDTIMEOUT)
+ timeout = 1;
+ }
+
+ /* Clean the status bits. */
+ setbits_le32(&sdi_regs->sdicsta, 0xf << 9);
+
+ if (!timeout) {
+ puts("S3C SDI: Command timed out!\n");
+ ret = TIMEOUT;
+ goto error;
+ }
+
+ /* Read out the response. */
+ if (cmd->resp_type & MMC_RSP_136) {
+ cmd->response[0] = readl(&sdi_regs->sdirsp0);
+ cmd->response[1] = readl(&sdi_regs->sdirsp1);
+ cmd->response[2] = readl(&sdi_regs->sdirsp2);
+ cmd->response[3] = readl(&sdi_regs->sdirsp3);
+ } else {
+ cmd->response[0] = readl(&sdi_regs->sdirsp0);
+ }
+
+ /* If there are no data, we're done. */
+ if (!data)
+ return 0;
+
+ xfer_len = data->blocksize * data->blocks;
+
+ while (xfer_len > 0) {
+ sdidsta = readl(&sdi_regs->sdidsta);
+ sdifsta = readl(&sdi_regs->sdifsta);
+
+ if (sdidsta & sdidsta_err_mask) {
+ printf("S3C SDI: Data error (sdta=0x%08x)\n", sdidsta);
+ ret = -EIO;
+ goto error;
+ }
+
+ if (data->flags & MMC_DATA_READ) {
+ if ((sdifsta & S3C2410_SDIFSTA_COUNTMASK) < 4)
+ continue;
+ sdidat = readl(&sdi_regs->sdidat);
+ put_unaligned_le32(sdidat, data->dest + data_offset);
+ } else { /* Write */
+ /* TX FIFO half full. */
+ if (!(sdifsta & S3C2410_SDIFSTA_TFHALF))
+ continue;
+
+ /* TX FIFO is below 32b full, write. */
+ sdidat = get_unaligned_le32(data->src + data_offset);
+ writel(sdidat, &sdi_regs->sdidat);
+ }
+ data_offset += 4;
+ xfer_len -= 4;
+ }
+
+ /* Wait for the command to complete or for response. */
+ for (timeout = 100000; timeout; timeout--) {
+ sdidsta = readl(&sdi_regs->sdidsta);
+ if (sdidsta & S3C2410_SDIDSTA_XFERFINISH)
+ break;
+
+ if (sdidsta & S3C2410_SDIDSTA_DATATIMEOUT)
+ timeout = 1;
+ }
+
+ /* Clear status bits. */
+ writel(0x6f8, &sdi_regs->sdidsta);
+
+ if (!timeout) {
+ puts("S3C SDI: Command timed out!\n");
+ ret = TIMEOUT;
+ goto error;
+ }
+
+ writel(0, &sdi_regs->sdidcon);
+
+ return 0;
+error:
+ return ret;
+}
+
+static void s3cmmc_set_ios(struct mmc *mmc)
+{
+ struct s3c24x0_sdi *sdi_regs = s3c24x0_get_base_sdi();
+ uint32_t divider = 0;
+
+ wide_bus = (mmc->bus_width == 4);
+
+ if (!mmc->clock)
+ return;
+
+ divider = DIV_ROUND_UP(get_PCLK(), mmc->clock);
+ if (divider)
+ divider--;
+
+ writel(divider, &sdi_regs->sdipre);
+ mdelay(125);
+}
+
+static int s3cmmc_init(struct mmc *mmc)
+{
+ struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power();
+ struct s3c24x0_sdi *sdi_regs = s3c24x0_get_base_sdi();
+
+ /* Start the clock. */
+ setbits_le32(&clk_power->clkcon, 1 << 9);
+
+#if defined(CONFIG_S3C2440)
+ writel(S3C2440_SDICON_SDRESET, &sdi_regs->sdicon);
+ mdelay(10);
+ writel(0x7fffff, &sdi_regs->sdidtimer);
+#else
+ writel(0xffff, &sdi_regs->sdidtimer);
+#endif
+ writel(MMC_MAX_BLOCK_LEN, &sdi_regs->sdibsize);
+ writel(0x0, &sdi_regs->sdiimsk);
+
+ writel(S3C2410_SDICON_FIFORESET | S3C2410_SDICON_CLOCKTYPE,
+ &sdi_regs->sdicon);
+
+ mdelay(125);
+
+ return 0;
+}
+
+struct s3cmmc_priv {
+ struct mmc_config cfg;
+ int (*getcd)(struct mmc *);
+ int (*getwp)(struct mmc *);
+};
+
+static int s3cmmc_getcd(struct mmc *mmc)
+{
+ struct s3cmmc_priv *priv = mmc->priv;
+ if (priv->getcd)
+ return priv->getcd(mmc);
+ else
+ return 0;
+}
+
+static int s3cmmc_getwp(struct mmc *mmc)
+{
+ struct s3cmmc_priv *priv = mmc->priv;
+ if (priv->getwp)
+ return priv->getwp(mmc);
+ else
+ return 0;
+}
+
+static const struct mmc_ops s3cmmc_ops = {
+ .send_cmd = s3cmmc_send_cmd,
+ .set_ios = s3cmmc_set_ios,
+ .init = s3cmmc_init,
+ .getcd = s3cmmc_getcd,
+ .getwp = s3cmmc_getwp,
+};
+
+int s3cmmc_initialize(bd_t *bis, int (*getcd)(struct mmc *),
+ int (*getwp)(struct mmc *))
+{
+ struct s3cmmc_priv *priv;
+ struct mmc *mmc;
+ struct mmc_config *cfg;
+
+ priv = calloc(1, sizeof(*priv));
+ if (!priv)
+ return -ENOMEM;
+ cfg = &priv->cfg;
+
+ cfg->name = "S3C MMC";
+ cfg->ops = &s3cmmc_ops;
+ cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
+ cfg->host_caps = MMC_MODE_4BIT | MMC_MODE_HC | MMC_MODE_HS;
+ cfg->f_min = 400000;
+ cfg->f_max = get_PCLK() / 2;
+ cfg->b_max = 0x80;
+
+#if defined(CONFIG_S3C2410)
+ /*
+ * S3C2410 has some bug that prevents reliable
+ * operation at higher speed
+ */
+ cfg->f_max /= 2;
+#endif
+
+ mmc = mmc_create(cfg, priv);
+ if (!mmc) {
+ free(priv);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c
index be5a16a1ba..8b453cb383 100644
--- a/drivers/mtd/nand/fsl_ifc_nand.c
+++ b/drivers/mtd/nand/fsl_ifc_nand.c
@@ -19,8 +19,11 @@
#include <asm/errno.h>
#include <fsl_ifc.h>
-#define FSL_IFC_V1_1_0 0x01010000
-#define MAX_BANKS 4
+#ifndef CONFIG_SYS_FSL_IFC_BANK_COUNT
+#define CONFIG_SYS_FSL_IFC_BANK_COUNT 4
+#endif
+
+#define MAX_BANKS CONFIG_SYS_FSL_IFC_BANK_COUNT
#define ERR_BYTE 0xFF /* Value returned for read bytes
when read failed */
#define IFC_TIMEOUT_MSECS 10 /* Maximum number of mSecs to wait for IFC
@@ -802,12 +805,30 @@ static void fsl_ifc_select_chip(struct mtd_info *mtd, int chip)
{
}
-static void fsl_ifc_sram_init(void)
+static int fsl_ifc_sram_init(uint32_t ver)
{
struct fsl_ifc *ifc = ifc_ctrl->regs;
uint32_t cs = 0, csor = 0, csor_8k = 0, csor_ext = 0;
+ uint32_t ncfgr = 0;
long long end_tick;
+ if (ver > FSL_IFC_V1_1_0) {
+ ncfgr = ifc_in32(&ifc->ifc_nand.ncfgr);
+ ifc_out32(&ifc->ifc_nand.ncfgr, ncfgr | IFC_NAND_SRAM_INIT_EN);
+
+ /* wait for SRAM_INIT bit to be clear or timeout */
+ end_tick = usec2ticks(IFC_TIMEOUT_MSECS * 1000) + get_ticks();
+ while (end_tick > get_ticks()) {
+ ifc_ctrl->status =
+ ifc_in32(&ifc->ifc_nand.nand_evter_stat);
+
+ if (!(ifc_ctrl->status & IFC_NAND_SRAM_INIT_EN))
+ return 0;
+ }
+ printf("fsl-ifc: Failed to Initialise SRAM\n");
+ return 1;
+ }
+
cs = ifc_ctrl->cs_nand >> IFC_NAND_CSEL_SHIFT;
/* Save CSOR and CSOR_ext */
@@ -850,11 +871,18 @@ static void fsl_ifc_sram_init(void)
break;
}
+ if (ifc_ctrl->status != IFC_NAND_EVTER_STAT_OPC) {
+ printf("fsl-ifc: Failed to Initialise SRAM\n");
+ return 1;
+ }
+
ifc_out32(&ifc->ifc_nand.nand_evter_stat, ifc_ctrl->status);
/* Restore CSOR and CSOR_ext */
ifc_out32(&ifc_ctrl->regs->csor_cs[cs].csor, csor);
ifc_out32(&ifc_ctrl->regs->csor_cs[cs].csor_ext, csor_ext);
+
+ return 0;
}
static int fsl_ifc_chip_init(int devnum, u8 *addr)
@@ -864,7 +892,7 @@ static int fsl_ifc_chip_init(int devnum, u8 *addr)
struct fsl_ifc_mtd *priv;
struct nand_ecclayout *layout;
uint32_t cspr = 0, csor = 0, ver = 0;
- int ret;
+ int ret = 0;
if (!ifc_ctrl) {
fsl_ifc_ctrl_init();
@@ -1006,8 +1034,13 @@ static int fsl_ifc_chip_init(int devnum, u8 *addr)
}
ver = ifc_in32(&ifc_ctrl->regs->ifc_rev);
- if (ver == FSL_IFC_V1_1_0)
- fsl_ifc_sram_init();
+ if (ver >= FSL_IFC_V1_1_0)
+ ret = fsl_ifc_sram_init(ver);
+ if (ret)
+ return ret;
+
+ if (ver >= FSL_IFC_V2_0_0)
+ priv->bufnum_mask = (priv->bufnum_mask * 2) + 1;
ret = nand_scan_ident(mtd, 1, NULL);
if (ret)
diff --git a/drivers/mtd/nand/fsl_ifc_spl.c b/drivers/mtd/nand/fsl_ifc_spl.c
index 510077282c..e336cb1c94 100644
--- a/drivers/mtd/nand/fsl_ifc_spl.c
+++ b/drivers/mtd/nand/fsl_ifc_spl.c
@@ -97,7 +97,7 @@ int nand_spl_load_image(uint32_t offs, unsigned int uboot_size, void *vdst)
int pages_per_blk;
int blk_size;
int bad_marker = 0;
- int bufnum_mask, bufnum;
+ int bufnum_mask, bufnum, ver = 0;
int csor, cspr;
int pos = 0;
@@ -130,6 +130,10 @@ int nand_spl_load_image(uint32_t offs, unsigned int uboot_size, void *vdst)
bad_marker = 5;
}
+ ver = ifc_in32(&ifc->ifc_rev);
+ if (ver >= FSL_IFC_V2_0_0)
+ bufnum_mask = (bufnum_mask * 2) + 1;
+
pages_per_blk =
32 << ((csor & CSOR_NAND_PB_MASK) >> CSOR_NAND_PB_SHIFT);
diff --git a/drivers/mtd/spi/sf_ops.c b/drivers/mtd/spi/sf_ops.c
index ef91b924d7..85cf22d42e 100644
--- a/drivers/mtd/spi/sf_ops.c
+++ b/drivers/mtd/spi/sf_ops.c
@@ -421,6 +421,7 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
data += read_len;
}
+ free(cmd);
return ret;
}
diff --git a/drivers/net/fm/fm.h b/drivers/net/fm/fm.h
index 43de114b52..316e06e17e 100644
--- a/drivers/net/fm/fm.h
+++ b/drivers/net/fm/fm.h
@@ -143,6 +143,7 @@ struct fm_eth {
#define MAX_RXBUF_LOG2 11
#define MAX_RXBUF_LEN (1 << MAX_RXBUF_LOG2)
-#define PORT_IS_ENABLED(port) fm_info[fm_port_to_index(port)].enabled
+#define PORT_IS_ENABLED(port) (fm_port_to_index(port) == -1 ? \
+ 0 : fm_info[fm_port_to_index(port)].enabled)
#endif /* __FM_H__ */
diff --git a/drivers/net/fm/init.c b/drivers/net/fm/init.c
index cd787f4eed..ff04695c32 100644
--- a/drivers/net/fm/init.c
+++ b/drivers/net/fm/init.c
@@ -147,6 +147,9 @@ void fm_disable_port(enum fm_port port)
{
int i = fm_port_to_index(port);
+ if (i == -1)
+ return;
+
fm_info[i].enabled = 0;
fman_disable_port(port);
}
@@ -155,6 +158,9 @@ void fm_enable_port(enum fm_port port)
{
int i = fm_port_to_index(port);
+ if (i == -1)
+ return;
+
fm_info[i].enabled = 1;
fman_enable_port(port);
}
diff --git a/drivers/net/fm/memac_phy.c b/drivers/net/fm/memac_phy.c
index de9c0e9cd2..5f910c2cdd 100644
--- a/drivers/net/fm/memac_phy.c
+++ b/drivers/net/fm/memac_phy.c
@@ -1,6 +1,6 @@
/*
* Copyright 2012 Freescale Semiconductor, Inc.
- * Andy Fleming <afleming@freescale.com>
+ * Andy Fleming <afleming@gmail.com>
* Roy Zang <tie-fei.zang@freescale.com>
*
* SPDX-License-Identifier: GPL-2.0+
diff --git a/drivers/net/fm/tgec_phy.c b/drivers/net/fm/tgec_phy.c
index faec317a0a..095f00cf97 100644
--- a/drivers/net/fm/tgec_phy.c
+++ b/drivers/net/fm/tgec_phy.c
@@ -1,6 +1,6 @@
/*
* Copyright 2009-2011 Freescale Semiconductor, Inc.
- * Andy Fleming <afleming@freescale.com>
+ * Andy Fleming <afleming@gmail.com>
*
* SPDX-License-Identifier: GPL-2.0+
* Some part is taken from tsec.c
diff --git a/drivers/pci/fsl_pci_init.c b/drivers/pci/fsl_pci_init.c
index 3a41b0ec17..231b07573f 100644
--- a/drivers/pci/fsl_pci_init.c
+++ b/drivers/pci/fsl_pci_init.c
@@ -504,8 +504,14 @@ void fsl_pci_init(struct pci_controller *hose, struct fsl_pci_info *pci_info)
}
#endif
if (!enabled) {
- /* Let the user know there's no PCIe link */
- printf("no link, regs @ 0x%lx\n", pci_info->regs);
+ /* Let the user know there's no PCIe link for root
+ * complex. for endpoint, the link may not setup, so
+ * print undetermined.
+ */
+ if (fsl_is_pci_agent(hose))
+ printf("undetermined, regs @ 0x%lx\n", pci_info->regs);
+ else
+ printf("no link, regs @ 0x%lx\n", pci_info->regs);
hose->last_busno = hose->first_busno;
return;
}
diff --git a/drivers/qe/qe.c b/drivers/qe/qe.c
index 9c5fbd1d69..be09a17297 100644
--- a/drivers/qe/qe.c
+++ b/drivers/qe/qe.c
@@ -11,7 +11,7 @@
#include <command.h>
#include "asm/errno.h"
#include "asm/io.h"
-#include "asm/immap_qe.h"
+#include "linux/immap_qe.h"
#include "qe.h"
#define MPC85xx_DEVDISR_QE_DISABLE 0x1
diff --git a/drivers/qe/uccf.c b/drivers/qe/uccf.c
index 593d96d1a2..85386bfc70 100644
--- a/drivers/qe/uccf.c
+++ b/drivers/qe/uccf.c
@@ -11,7 +11,7 @@
#include "malloc.h"
#include "asm/errno.h"
#include "asm/io.h"
-#include "asm/immap_qe.h"
+#include "linux/immap_qe.h"
#include "qe.h"
#include "uccf.h"
diff --git a/drivers/qe/uccf.h b/drivers/qe/uccf.h
index 0b57e2f422..55941e4601 100644
--- a/drivers/qe/uccf.h
+++ b/drivers/qe/uccf.h
@@ -12,7 +12,7 @@
#include "common.h"
#include "qe.h"
-#include "asm/immap_qe.h"
+#include "linux/immap_qe.h"
/* Fast or Giga ethernet
*/
diff --git a/drivers/qe/uec.c b/drivers/qe/uec.c
index 68045733b8..c91f084a7c 100644
--- a/drivers/qe/uec.c
+++ b/drivers/qe/uec.c
@@ -11,7 +11,7 @@
#include "malloc.h"
#include "asm/errno.h"
#include "asm/io.h"
-#include "asm/immap_qe.h"
+#include "linux/immap_qe.h"
#include "qe.h"
#include "uccf.h"
#include "uec.h"
diff --git a/drivers/qe/uec_phy.c b/drivers/qe/uec_phy.c
index 5dc4641bf6..e701787c41 100644
--- a/drivers/qe/uec_phy.c
+++ b/drivers/qe/uec_phy.c
@@ -14,7 +14,7 @@
#include "net.h"
#include "malloc.h"
#include "asm/errno.h"
-#include "asm/immap_qe.h"
+#include "linux/immap_qe.h"
#include "asm/io.h"
#include "qe.h"
#include "uccf.h"
diff --git a/drivers/spi/exynos_spi.c b/drivers/spi/exynos_spi.c
index c92276fdf7..2969184ee8 100644
--- a/drivers/spi/exynos_spi.c
+++ b/drivers/spi/exynos_spi.c
@@ -428,10 +428,6 @@ void spi_cs_activate(struct spi_slave *slave)
clrbits_le32(&spi_slave->regs->cs_reg, SPI_SLAVE_SIG_INACT);
debug("Activate CS, bus %d\n", spi_slave->slave.bus);
spi_slave->skip_preamble = spi_slave->mode & SPI_PREAMBLE;
-
- /* Remember time of this transaction so we can honour the bus delay */
- if (spi_slave->bus->deactivate_delay_us)
- spi_slave->last_transaction_us = timer_get_us();
}
/**
@@ -445,6 +441,11 @@ void spi_cs_deactivate(struct spi_slave *slave)
struct exynos_spi_slave *spi_slave = to_exynos_spi(slave);
setbits_le32(&spi_slave->regs->cs_reg, SPI_SLAVE_SIG_INACT);
+
+ /* Remember time of this transaction so we can honour the bus delay */
+ if (spi_slave->bus->deactivate_delay_us)
+ spi_slave->last_transaction_us = timer_get_us();
+
debug("Deactivate CS, bus %d\n", spi_slave->slave.bus);
}
diff --git a/drivers/spi/mxc_spi.c b/drivers/spi/mxc_spi.c
index f3f029d634..2d5f3850da 100644
--- a/drivers/spi/mxc_spi.c
+++ b/drivers/spi/mxc_spi.c
@@ -30,6 +30,10 @@ static unsigned long spi_bases[] = {
#define reg_read readl
#define reg_write(a, v) writel(v, a)
+#if !defined(CONFIG_SYS_SPI_MXC_WAIT)
+#define CONFIG_SYS_SPI_MXC_WAIT (CONFIG_SYS_HZ/100) /* 10 ms */
+#endif
+
struct mxc_spi_slave {
struct spi_slave slave;
unsigned long base;
@@ -212,6 +216,8 @@ int spi_xchg_single(struct spi_slave *slave, unsigned int bitlen,
int nbytes = DIV_ROUND_UP(bitlen, 8);
u32 data, cnt, i;
struct cspi_regs *regs = (struct cspi_regs *)mxcs->base;
+ u32 ts;
+ int status;
debug("%s: bitlen %d dout 0x%x din 0x%x\n",
__func__, bitlen, (u32)dout, (u32)din);
@@ -272,9 +278,16 @@ int spi_xchg_single(struct spi_slave *slave, unsigned int bitlen,
reg_write(&regs->ctrl, mxcs->ctrl_reg |
MXC_CSPICTRL_EN | MXC_CSPICTRL_XCH);
+ ts = get_timer(0);
+ status = reg_read(&regs->stat);
/* Wait until the TC (Transfer completed) bit is set */
- while ((reg_read(&regs->stat) & MXC_CSPICTRL_TC) == 0)
- ;
+ while ((status & MXC_CSPICTRL_TC) == 0) {
+ if (get_timer(ts) > CONFIG_SYS_SPI_MXC_WAIT) {
+ printf("spi_xchg_single: Timeout!\n");
+ return -1;
+ }
+ status = reg_read(&regs->stat);
+ }
/* Transfer completed, clear any pending request */
reg_write(&regs->stat, MXC_CSPICTRL_TC | MXC_CSPICTRL_RXOVF);
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 7ddea9b026..7d81fbd7f8 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -53,6 +53,8 @@ struct spi_slave *spi_base_setup_slave_fdt(const void *blob, int busnum,
mode |= SPI_CPHA;
if (fdtdec_get_bool(blob, node, "spi-cs-high"))
mode |= SPI_CS_HIGH;
+ if (fdtdec_get_bool(blob, node, "spi-half-duplex"))
+ mode |= SPI_PREAMBLE;
return spi_setup_slave(busnum, cs, max_hz, mode);
}
#endif
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 04c1a642a3..c4f5157a84 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -35,6 +35,7 @@ obj-$(CONFIG_USB_EHCI_PPC4XX) += ehci-ppc4xx.o
obj-$(CONFIG_USB_EHCI_MARVELL) += ehci-marvell.o
obj-$(CONFIG_USB_EHCI_PCI) += ehci-pci.o
obj-$(CONFIG_USB_EHCI_SPEAR) += ehci-spear.o
+obj-$(CONFIG_USB_EHCI_SUNXI) += ehci-sunxi.o
obj-$(CONFIG_USB_EHCI_TEGRA) += ehci-tegra.o
obj-$(CONFIG_USB_EHCI_VCT) += ehci-vct.o
obj-$(CONFIG_USB_EHCI_RMOBILE) += ehci-rmobile.o
diff --git a/drivers/usb/host/ehci-sunxi.c b/drivers/usb/host/ehci-sunxi.c
new file mode 100644
index 0000000000..23617b7adc
--- /dev/null
+++ b/drivers/usb/host/ehci-sunxi.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2014 Roman Byshko
+ *
+ * Roman Byshko <rbyshko@gmail.com>
+ *
+ * Based on code from
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <asm/arch/clock.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <common.h>
+#include "ehci.h"
+
+#define SUNXI_USB1_IO_BASE 0x01c14000
+#define SUNXI_USB2_IO_BASE 0x01c1c000
+
+#define SUNXI_USB_PMU_IRQ_ENABLE 0x800
+#define SUNXI_USB_CSR 0x01c13404
+#define SUNXI_USB_PASSBY_EN 1
+
+#define SUNXI_EHCI_AHB_ICHR8_EN (1 << 10)
+#define SUNXI_EHCI_AHB_INCR4_BURST_EN (1 << 9)
+#define SUNXI_EHCI_AHB_INCRX_ALIGN_EN (1 << 8)
+#define SUNXI_EHCI_ULPI_BYPASS_EN (1 << 0)
+
+static struct sunxi_ehci_hcd {
+ struct usb_hcd *hcd;
+ int usb_rst_mask;
+ int ahb_clk_mask;
+ int gpio_vbus;
+ void *csr;
+ int irq;
+ int id;
+} sunxi_echi_hcd[] = {
+ {
+ .usb_rst_mask = CCM_USB_CTRL_PHY1_RST,
+ .ahb_clk_mask = 1 << AHB_GATE_OFFSET_USB_EHCI0,
+ .gpio_vbus = CONFIG_SUNXI_USB_VBUS0_GPIO,
+ .csr = (void *)SUNXI_USB_CSR,
+ .irq = 39,
+ .id = 1,
+ },
+#if (CONFIG_USB_MAX_CONTROLLER_COUNT > 1)
+ {
+ .usb_rst_mask = CCM_USB_CTRL_PHY2_RST,
+ .ahb_clk_mask = 1 << AHB_GATE_OFFSET_USB_EHCI1,
+ .gpio_vbus = CONFIG_SUNXI_USB_VBUS1_GPIO,
+ .csr = (void *)SUNXI_USB_CSR,
+ .irq = 40,
+ .id = 2,
+ }
+#endif
+};
+
+static int enabled_hcd_count;
+
+static void *get_io_base(int hcd_id)
+{
+ if (hcd_id == 1)
+ return (void *)SUNXI_USB1_IO_BASE;
+ else if (hcd_id == 2)
+ return (void *)SUNXI_USB2_IO_BASE;
+ else
+ return NULL;
+}
+
+static void usb_phy_write(struct sunxi_ehci_hcd *sunxi_ehci, int addr,
+ int data, int len)
+{
+ int j = 0, usbc_bit = 0;
+ void *dest = sunxi_ehci->csr;
+
+ usbc_bit = 1 << (sunxi_ehci->id * 2);
+ for (j = 0; j < len; j++) {
+ /* set the bit address to be written */
+ clrbits_le32(dest, 0xff << 8);
+ setbits_le32(dest, (addr + j) << 8);
+
+ clrbits_le32(dest, usbc_bit);
+ /* set data bit */
+ if (data & 0x1)
+ setbits_le32(dest, 1 << 7);
+ else
+ clrbits_le32(dest, 1 << 7);
+
+ setbits_le32(dest, usbc_bit);
+
+ clrbits_le32(dest, usbc_bit);
+
+ data >>= 1;
+ }
+}
+
+static void sunxi_usb_phy_init(struct sunxi_ehci_hcd *sunxi_ehci)
+{
+ /* The following comments are machine
+ * translated from Chinese, you have been warned!
+ */
+
+ /* adjust PHY's magnitude and rate */
+ usb_phy_write(sunxi_ehci, 0x20, 0x14, 5);
+
+ /* threshold adjustment disconnect */
+#ifdef CONFIG_SUN4I
+ usb_phy_write(sunxi_ehci, 0x2a, 3, 2);
+#else
+ usb_phy_write(sunxi_ehci, 0x2a, 2, 2);
+#endif
+
+ return;
+}
+
+static void sunxi_usb_passby(struct sunxi_ehci_hcd *sunxi_ehci, int enable)
+{
+ unsigned long bits = 0;
+ void *addr = get_io_base(sunxi_ehci->id) + SUNXI_USB_PMU_IRQ_ENABLE;
+
+ bits = SUNXI_EHCI_AHB_ICHR8_EN |
+ SUNXI_EHCI_AHB_INCR4_BURST_EN |
+ SUNXI_EHCI_AHB_INCRX_ALIGN_EN |
+ SUNXI_EHCI_ULPI_BYPASS_EN;
+
+ if (enable)
+ setbits_le32(addr, bits);
+ else
+ clrbits_le32(addr, bits);
+
+ return;
+}
+
+static void sunxi_ehci_enable(struct sunxi_ehci_hcd *sunxi_ehci)
+{
+ struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+
+ setbits_le32(&ccm->usb_clk_cfg, sunxi_ehci->usb_rst_mask);
+ setbits_le32(&ccm->ahb_gate0, sunxi_ehci->ahb_clk_mask);
+
+ sunxi_usb_phy_init(sunxi_ehci);
+
+ sunxi_usb_passby(sunxi_ehci, SUNXI_USB_PASSBY_EN);
+
+ gpio_direction_output(sunxi_ehci->gpio_vbus, 1);
+}
+
+static void sunxi_ehci_disable(struct sunxi_ehci_hcd *sunxi_ehci)
+{
+ struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+
+ gpio_direction_output(sunxi_ehci->gpio_vbus, 0);
+
+ sunxi_usb_passby(sunxi_ehci, !SUNXI_USB_PASSBY_EN);
+
+ clrbits_le32(&ccm->ahb_gate0, sunxi_ehci->ahb_clk_mask);
+ clrbits_le32(&ccm->usb_clk_cfg, sunxi_ehci->usb_rst_mask);
+}
+
+int ehci_hcd_init(int index, enum usb_init_type init, struct ehci_hccr **hccr,
+ struct ehci_hcor **hcor)
+{
+ struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+ struct sunxi_ehci_hcd *sunxi_ehci = &sunxi_echi_hcd[index];
+
+ /* enable common PHY only once */
+ if (index == 0)
+ setbits_le32(&ccm->usb_clk_cfg, CCM_USB_CTRL_PHYGATE);
+
+ sunxi_ehci_enable(sunxi_ehci);
+
+ *hccr = get_io_base(sunxi_ehci->id);
+
+ *hcor = (struct ehci_hcor *)((uint32_t) *hccr
+ + HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
+
+ debug("sunxi-ehci: init hccr %x and hcor %x hc_length %d\n",
+ (uint32_t)*hccr, (uint32_t)*hcor,
+ (uint32_t)HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
+
+ enabled_hcd_count++;
+
+ return 0;
+}
+
+int ehci_hcd_stop(int index)
+{
+ struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+ struct sunxi_ehci_hcd *sunxi_ehci = &sunxi_echi_hcd[index];
+
+ sunxi_ehci_disable(sunxi_ehci);
+
+ /* disable common PHY only once, for the last enabled hcd */
+ if (enabled_hcd_count == 1)
+ clrbits_le32(&ccm->usb_clk_cfg, CCM_USB_CTRL_PHYGATE);
+
+ enabled_hcd_count--;
+
+ return 0;
+}