summaryrefslogtreecommitdiff
path: root/drivers/mmc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/Makefile1
-rw-r--r--drivers/mmc/bfin_sdh.c1
-rw-r--r--drivers/mmc/dw_mmc.c2
-rw-r--r--drivers/mmc/exynos_dw_mmc.c17
-rw-r--r--drivers/mmc/kona_sdhci.c134
-rw-r--r--drivers/mmc/mmc.c79
-rw-r--r--drivers/mmc/tegra_mmc.c9
-rw-r--r--drivers/mmc/zynq_sdhci.c3
8 files changed, 191 insertions, 55 deletions
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index e793ed9..931922b 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_OMAP_HSMMC) += omap_hsmmc.o
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_S5P_SDHCI) += s5p_sdhci.o
obj-$(CONFIG_SH_MMCIF) += sh_mmcif.o
obj-$(CONFIG_SPEAR_SDHCI) += spear_sdhci.o
diff --git a/drivers/mmc/bfin_sdh.c b/drivers/mmc/bfin_sdh.c
index 2631174..bd9b641 100644
--- a/drivers/mmc/bfin_sdh.c
+++ b/drivers/mmc/bfin_sdh.c
@@ -15,6 +15,7 @@
#include <asm/errno.h>
#include <asm/byteorder.h>
#include <asm/blackfin.h>
+#include <asm/clock.h>
#include <asm/portmux.h>
#include <asm/mach-common/bits/sdh.h>
#include <asm/mach-common/bits/dma.h>
diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c
index 4cec5aa..d45c15c 100644
--- a/drivers/mmc/dw_mmc.c
+++ b/drivers/mmc/dw_mmc.c
@@ -237,7 +237,7 @@ static int dwmci_setup_bus(struct dwmci_host *host, u32 freq)
* host->bus_hz should be set from user.
*/
if (host->get_mmc_clk)
- sclk = host->get_mmc_clk(host->dev_index);
+ sclk = host->get_mmc_clk(host);
else if (host->bus_hz)
sclk = host->bus_hz;
else {
diff --git a/drivers/mmc/exynos_dw_mmc.c b/drivers/mmc/exynos_dw_mmc.c
index b3e5c5e..de8cdcc 100644
--- a/drivers/mmc/exynos_dw_mmc.c
+++ b/drivers/mmc/exynos_dw_mmc.c
@@ -29,9 +29,22 @@ static void exynos_dwmci_clksel(struct dwmci_host *host)
dwmci_writel(host, DWMCI_CLKSEL, host->clksel_val);
}
-unsigned int exynos_dwmci_get_clk(int dev_index)
+unsigned int exynos_dwmci_get_clk(struct dwmci_host *host)
{
- return get_mmc_clk(dev_index);
+ unsigned long sclk;
+ int8_t clk_div;
+
+ /*
+ * Since SDCLKIN is divided inside controller by the DIVRATIO
+ * value set in the CLKSEL register, we need to use the same output
+ * clock value to calculate the CLKDIV value.
+ * as per user manual:cclk_in = SDCLKIN / (DIVRATIO + 1)
+ */
+ clk_div = ((dwmci_readl(host, DWMCI_CLKSEL) >> DWMCI_DIVRATIO_BIT)
+ & DWMCI_DIVRATIO_MASK) + 1;
+ sclk = get_mmc_clk(host->dev_index);
+
+ return sclk / clk_div;
}
static void exynos_dwmci_board_init(struct dwmci_host *host)
diff --git a/drivers/mmc/kona_sdhci.c b/drivers/mmc/kona_sdhci.c
new file mode 100644
index 0000000..77e42c8
--- /dev/null
+++ b/drivers/mmc/kona_sdhci.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2013 Broadcom Corporation.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <sdhci.h>
+#include <asm/errno.h>
+#include <asm/kona-common/clk.h>
+
+#define SDHCI_CORECTRL_OFFSET 0x00008000
+#define SDHCI_CORECTRL_EN 0x01
+#define SDHCI_CORECTRL_RESET 0x02
+
+#define SDHCI_CORESTAT_OFFSET 0x00008004
+#define SDHCI_CORESTAT_CD_SW 0x01
+
+#define SDHCI_COREIMR_OFFSET 0x00008008
+#define SDHCI_COREIMR_IP 0x01
+
+static int init_kona_mmc_core(struct sdhci_host *host)
+{
+ unsigned int mask;
+ unsigned int timeout;
+
+ if (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & SDHCI_RESET_ALL) {
+ printf("%s: sd host controller reset error\n", __func__);
+ return 1;
+ }
+
+ /* For kona a hardware reset before anything else. */
+ mask = sdhci_readl(host, SDHCI_CORECTRL_OFFSET) | SDHCI_CORECTRL_RESET;
+ sdhci_writel(host, mask, SDHCI_CORECTRL_OFFSET);
+
+ /* Wait max 100 ms */
+ timeout = 1000;
+ do {
+ if (timeout == 0) {
+ printf("%s: reset timeout error\n", __func__);
+ return 1;
+ }
+ timeout--;
+ udelay(100);
+ } while (0 ==
+ (sdhci_readl(host, SDHCI_CORECTRL_OFFSET) &
+ SDHCI_CORECTRL_RESET));
+
+ /* Clear the reset bit. */
+ mask = mask & ~SDHCI_CORECTRL_RESET;
+ sdhci_writel(host, mask, SDHCI_CORECTRL_OFFSET);
+
+ /* Enable AHB clock */
+ mask = sdhci_readl(host, SDHCI_CORECTRL_OFFSET);
+ sdhci_writel(host, mask | SDHCI_CORECTRL_EN, SDHCI_CORECTRL_OFFSET);
+
+ /* Enable interrupts */
+ sdhci_writel(host, SDHCI_COREIMR_IP, SDHCI_COREIMR_OFFSET);
+
+ /* Make sure Card is detected in controller */
+ mask = sdhci_readl(host, SDHCI_CORESTAT_OFFSET);
+ sdhci_writel(host, mask | SDHCI_CORESTAT_CD_SW, SDHCI_CORESTAT_OFFSET);
+
+ /* Wait max 100 ms */
+ timeout = 1000;
+ while (!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) {
+ if (timeout == 0) {
+ printf("%s: CARD DETECT timeout error\n", __func__);
+ return 1;
+ }
+ timeout--;
+ udelay(100);
+ }
+ return 0;
+}
+
+int kona_sdhci_init(int dev_index, u32 min_clk, u32 quirks)
+{
+ int ret = 0;
+ u32 max_clk;
+ void *reg_base;
+ struct sdhci_host *host = NULL;
+
+ host = (struct sdhci_host *)malloc(sizeof(struct sdhci_host));
+ if (!host) {
+ printf("%s: sdhci host malloc fail!\n", __func__);
+ return -ENOMEM;
+ }
+ switch (dev_index) {
+ case 0:
+ reg_base = (void *)CONFIG_SYS_SDIO_BASE0;
+ ret = clk_sdio_enable(reg_base, CONFIG_SYS_SDIO0_MAX_CLK,
+ &max_clk);
+ break;
+ case 1:
+ reg_base = (void *)CONFIG_SYS_SDIO_BASE1;
+ ret = clk_sdio_enable(reg_base, CONFIG_SYS_SDIO1_MAX_CLK,
+ &max_clk);
+ break;
+ case 2:
+ reg_base = (void *)CONFIG_SYS_SDIO_BASE2;
+ ret = clk_sdio_enable(reg_base, CONFIG_SYS_SDIO2_MAX_CLK,
+ &max_clk);
+ break;
+ case 3:
+ reg_base = (void *)CONFIG_SYS_SDIO_BASE3;
+ ret = clk_sdio_enable(reg_base, CONFIG_SYS_SDIO3_MAX_CLK,
+ &max_clk);
+ break;
+ default:
+ printf("%s: sdio dev index %d not supported\n",
+ __func__, dev_index);
+ ret = -EINVAL;
+ }
+ if (ret)
+ return ret;
+
+ host->name = "kona-sdhci";
+ host->ioaddr = reg_base;
+ host->quirks = quirks;
+ host->host_caps = MMC_MODE_HC;
+
+ if (init_kona_mmc_core(host))
+ return -EINVAL;
+
+ if (quirks & SDHCI_QUIRK_REG32_RW)
+ host->version = sdhci_readl(host, SDHCI_HOST_VERSION - 2) >> 16;
+ else
+ host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
+
+ add_sdhci(host, max_clk, min_clk);
+ return ret;
+}
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index c6a1c23..8ab0bc9 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -430,7 +430,7 @@ int mmc_complete_op_cond(struct mmc *mmc)
mmc->ocr = cmd.response[0];
mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
- mmc->rca = 0;
+ mmc->rca = 1;
return 0;
}
@@ -1442,67 +1442,44 @@ int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize,
}
/*
- * This function shall form and send the commands to open / close the
- * boot partition specified by user.
- *
- * Input Parameters:
- * ack: 0x0 - No boot acknowledge sent (default)
- * 0x1 - Boot acknowledge sent during boot operation
- * part_num: User selects boot data that will be sent to master
- * 0x0 - Device not boot enabled (default)
- * 0x1 - Boot partition 1 enabled for boot
- * 0x2 - Boot partition 2 enabled for boot
- * access: User selects partitions to access
- * 0x0 : No access to boot partition (default)
- * 0x1 : R/W boot partition 1
- * 0x2 : R/W boot partition 2
- * 0x3 : R/W Replay Protected Memory Block (RPMB)
+ * Modify EXT_CSD[177] which is BOOT_BUS_WIDTH
+ * based on the passed in values for BOOT_BUS_WIDTH, RESET_BOOT_BUS_WIDTH
+ * and BOOT_MODE.
*
* Returns 0 on success.
*/
-int mmc_boot_part_access(struct mmc *mmc, u8 ack, u8 part_num, u8 access)
+int mmc_set_boot_bus_width(struct mmc *mmc, u8 width, u8 reset, u8 mode)
{
int err;
- struct mmc_cmd cmd;
- /* Boot ack enable, boot partition enable , boot partition access */
- cmd.cmdidx = MMC_CMD_SWITCH;
- cmd.resp_type = MMC_RSP_R1b;
-
- cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
- (EXT_CSD_PART_CONF << 16) |
- ((EXT_CSD_BOOT_ACK(ack) |
- EXT_CSD_BOOT_PART_NUM(part_num) |
- EXT_CSD_PARTITION_ACCESS(access)) << 8);
+ err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_BUS_WIDTH,
+ EXT_CSD_BOOT_BUS_WIDTH_MODE(mode) |
+ EXT_CSD_BOOT_BUS_WIDTH_RESET(reset) |
+ EXT_CSD_BOOT_BUS_WIDTH_WIDTH(width));
- err = mmc_send_cmd(mmc, &cmd, NULL);
- if (err) {
- if (access) {
- debug("mmc boot partition#%d open fail:Error1 = %d\n",
- part_num, err);
- } else {
- debug("mmc boot partition#%d close fail:Error = %d\n",
- part_num, err);
- }
+ if (err)
return err;
- }
+ return 0;
+}
- if (access) {
- /* 4bit transfer mode at booting time. */
- cmd.cmdidx = MMC_CMD_SWITCH;
- cmd.resp_type = MMC_RSP_R1b;
+/*
+ * Modify EXT_CSD[179] which is PARTITION_CONFIG (formerly BOOT_CONFIG)
+ * based on the passed in values for BOOT_ACK, BOOT_PARTITION_ENABLE and
+ * PARTITION_ACCESS.
+ *
+ * Returns 0 on success.
+ */
+int mmc_set_part_conf(struct mmc *mmc, u8 ack, u8 part_num, u8 access)
+{
+ int err;
- cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
- (EXT_CSD_BOOT_BUS_WIDTH << 16) |
- ((1 << 0) << 8);
+ err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
+ EXT_CSD_BOOT_ACK(ack) |
+ EXT_CSD_BOOT_PART_NUM(part_num) |
+ EXT_CSD_PARTITION_ACCESS(access));
- err = mmc_send_cmd(mmc, &cmd, NULL);
- if (err) {
- debug("mmc boot partition#%d open fail:Error2 = %d\n",
- part_num, err);
- return err;
- }
- }
+ if (err)
+ return err;
return 0;
}
#endif
diff --git a/drivers/mmc/tegra_mmc.c b/drivers/mmc/tegra_mmc.c
index e1817e2..3d1ce12 100644
--- a/drivers/mmc/tegra_mmc.c
+++ b/drivers/mmc/tegra_mmc.c
@@ -668,6 +668,15 @@ void tegra_mmc_init(void)
const void *blob = gd->fdt_blob;
debug("%s entry\n", __func__);
+ /* See if any Tegra124 MMC controllers are present */
+ count = fdtdec_find_aliases_for_id(blob, "sdhci",
+ COMPAT_NVIDIA_TEGRA124_SDMMC, node_list, MAX_HOSTS);
+ debug("%s: count of Tegra124 sdhci nodes is %d\n", __func__, count);
+ if (process_nodes(blob, node_list, count)) {
+ printf("%s: Error processing T30 mmc node(s)!\n", __func__);
+ return;
+ }
+
/* See if any Tegra30 MMC controllers are present */
count = fdtdec_find_aliases_for_id(blob, "sdhci",
COMPAT_NVIDIA_TEGRA30_SDMMC, node_list, MAX_HOSTS);
diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c
index 610bef5..72a272f 100644
--- a/drivers/mmc/zynq_sdhci.c
+++ b/drivers/mmc/zynq_sdhci.c
@@ -23,7 +23,8 @@ int zynq_sdhci_init(u32 regbase)
host->name = "zynq_sdhci";
host->ioaddr = (void *)regbase;
- host->quirks = SDHCI_QUIRK_NO_CD | SDHCI_QUIRK_WAIT_SEND_CMD;
+ host->quirks = SDHCI_QUIRK_NO_CD | SDHCI_QUIRK_WAIT_SEND_CMD |
+ SDHCI_QUIRK_BROKEN_R1B;
host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
host->host_caps = MMC_MODE_HC;