
Hi All,
This patch is based on: "EXYNOS5: PINMUX: Added default pinumx settings".
Regards, Rajeshwari Shinde.
On Fri, May 25, 2012 at 5:21 PM, Rajeshwari Shinde rajeshwari.s@samsung.com wrote:
Add MSHCI driver support and resgister description for same.
Signed-off-by: Alim Akhtar alim.akhtar@samsung.com Signed-off-by: Terry Lambert tlambert@chromium.org Signed-off-by: Rajeshwari Shinde rajeshwari.s@samsung.com
arch/arm/include/asm/arch-exynos/mshc.h | 174 ++++++++++ drivers/mmc/Makefile | 1 + drivers/mmc/exynos_mshc.c | 553 +++++++++++++++++++++++++++++++ 3 files changed, 728 insertions(+), 0 deletions(-) create mode 100644 arch/arm/include/asm/arch-exynos/mshc.h create mode 100644 drivers/mmc/exynos_mshc.c
diff --git a/arch/arm/include/asm/arch-exynos/mshc.h b/arch/arm/include/asm/arch-exynos/mshc.h new file mode 100644 index 0000000..7226619 --- /dev/null +++ b/arch/arm/include/asm/arch-exynos/mshc.h @@ -0,0 +1,174 @@ +/*
- (C) Copyright 2012 SAMSUNG Electronics
- Abhilash Kesavan a.kesavan@samsung.com
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
+#ifndef __ASM_ARCH_COMMON_MSHC_H +#define __ASM_ARCH_COMMON_MSHC_H
+#include <asm/arch/pinmux.h> +#ifndef __ASSEMBLY__ +struct mshci_host {
- struct exynos_mshci *reg; /* Mapped address */
- unsigned int clock; /* Current clock in MHz */
- enum periph_id peripheral;
+};
+struct exynos_mshci {
- unsigned int ctrl;
- unsigned int pwren;
- unsigned int clkdiv;
- unsigned int clksrc;
- unsigned int clkena;
- unsigned int tmout;
- unsigned int ctype;
- unsigned int blksiz;
- unsigned int bytcnt;
- unsigned int intmask;
- unsigned int cmdarg;
- unsigned int cmd;
- unsigned int resp0;
- unsigned int resp1;
- unsigned int resp2;
- unsigned int resp3;
- unsigned int mintsts;
- unsigned int rintsts;
- unsigned int status;
- unsigned int fifoth;
- unsigned int cdetect;
- unsigned int wrtprt;
- unsigned int gpio;
- unsigned int tcbcnt;
- unsigned int tbbcnt;
- unsigned int debnce;
- unsigned int usrid;
- unsigned int verid;
- unsigned int hcon;
- unsigned int uhs_reg;
- unsigned int rst_n;
- unsigned char reserved1[4];
- unsigned int bmod;
- unsigned int pldmnd;
- unsigned int dbaddr;
- unsigned int idsts;
- unsigned int idinten;
- unsigned int dscaddr;
- unsigned int bufaddr;
- unsigned int clksel;
- unsigned char reserved2[460];
- unsigned int cardthrctl;
+};
+/*
- Struct idma
- Holds the descriptor list
- */
+struct mshci_idmac {
- u32 des0;
- u32 des1;
- u32 des2;
- u32 des3;
+};
+/* Control Register Register */ +#define CTRL_RESET (0x1 << 0) +#define FIFO_RESET (0x1 << 1) +#define DMA_RESET (0x1 << 2) +#define DMA_ENABLE (0x1 << 5) +#define SEND_AS_CCSD (0x1 << 10) +#define ENABLE_IDMAC (0x1 << 25)
+/* Power Enable Register */ +#define POWER_ENABLE (0x1 << 0)
+/* Clock Enable Register */ +#define CLK_ENABLE (0x1 << 0) +#define CLK_DISABLE (0x0 << 0)
+/* Timeout Register */ +#define TMOUT_MAX 0xffffffff
+/* Card Type Register */ +#define PORT0_CARD_WIDTH1 0 +#define PORT0_CARD_WIDTH4 (0x1 << 0) +#define PORT0_CARD_WIDTH8 (0x1 << 16)
+/* Interrupt Mask Register */ +#define INTMSK_ALL 0xffffffff +#define INTMSK_RE (0x1 << 1) +#define INTMSK_CDONE (0x1 << 2) +#define INTMSK_DTO (0x1 << 3) +#define INTMSK_DCRC (0x1 << 7) +#define INTMSK_RTO (0x1 << 8) +#define INTMSK_DRTO (0x1 << 9) +#define INTMSK_HTO (0x1 << 10) +#define INTMSK_FRUN (0x1 << 11) +#define INTMSK_HLE (0x1 << 12) +#define INTMSK_SBE (0x1 << 13) +#define INTMSK_ACD (0x1 << 14) +#define INTMSK_EBE (0x1 << 15)
+/* Command Register */ +#define CMD_RESP_EXP_BIT (0x1 << 6) +#define CMD_RESP_LENGTH_BIT (0x1 << 7) +#define CMD_CHECK_CRC_BIT (0x1 << 8) +#define CMD_DATA_EXP_BIT (0x1 << 9) +#define CMD_RW_BIT (0x1 << 10) +#define CMD_SENT_AUTO_STOP_BIT (0x1 << 12) +#define CMD_WAIT_PRV_DAT_BIT (0x1 << 13) +#define CMD_SEND_CLK_ONLY (0x1 << 21) +#define CMD_USE_HOLD_REG (0x1 << 29) +#define CMD_STRT_BIT (0x1 << 31) +#define CMD_ONLY_CLK (CMD_STRT_BIT | CMD_SEND_CLK_ONLY | \
- CMD_WAIT_PRV_DAT_BIT)
+/* Raw Interrupt Register */ +#define DATA_ERR (INTMSK_EBE | INTMSK_SBE | INTMSK_HLE | \
- INTMSK_FRUN | INTMSK_EBE | INTMSK_DCRC)
+#define DATA_TOUT (INTMSK_HTO | INTMSK_DRTO)
+/* Status Register */ +#define DATA_BUSY (0x1 << 9)
+/* FIFO Threshold Watermark Register */ +#define TX_WMARK (0xFFF << 0) +#define RX_WMARK (0xFFF << 16) +#define MSIZE_MASK (0x7 << 28)
+/* DW DMA Mutiple Transaction Size */ +#define MSIZE_8 (2 << 28)
+/* Bus Mode Register */ +#define BMOD_IDMAC_RESET (0x1 << 0) +#define BMOD_IDMAC_FB (0x1 << 1) +#define BMOD_IDMAC_ENABLE (0x1 << 7)
+/* IDMAC bits */ +#define MSHCI_IDMAC_OWN (0x1 << 31) +#define MSHCI_IDMAC_CH (0x1 << 4) +#define MSHCI_IDMAC_FS (0x1 << 3) +#define MSHCI_IDMAC_LD (0x1 << 2)
+#define MAX_MSHCI_CLOCK 52000000 /* Max limit is 52MHz */ +#define MIN_MSHCI_CLOCK 400000 /* Lower limit is 400KHz */ +#define COMMAND_TIMEOUT 10000 +#define TIMEOUT_MS 100
+int exynos_mshci_init(enum periph_id periph_id, int bus_width);
+#endif +#endif diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index c245352..84e2d6a 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -27,6 +27,7 @@ LIB := $(obj)libmmc.o
COBJS-$(CONFIG_BFIN_SDH) += bfin_sdh.o COBJS-$(CONFIG_DAVINCI_MMC) += davinci_mmc.o +COBJS-$(CONFIG_EXYNOS_MSHCI) += exynos_mshc.o COBJS-$(CONFIG_FSL_ESDHC) += fsl_esdhc.o COBJS-$(CONFIG_FTSDC010) += ftsdc010_esdhc.o COBJS-$(CONFIG_GENERIC_MMC) += mmc.o diff --git a/drivers/mmc/exynos_mshc.c b/drivers/mmc/exynos_mshc.c new file mode 100644 index 0000000..eb133c0 --- /dev/null +++ b/drivers/mmc/exynos_mshc.c @@ -0,0 +1,553 @@ +/*
- (C) Copyright 2012 Samsung Electronics Co. Ltd
- See file CREDITS for list of people who contributed to this
- project.
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of
- the License, or (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- MA 02111-1307 USA
- */
+#include <common.h> +#include <mmc.h> +#include <asm/arch/clk.h> +#include <asm/arch/cpu.h> +#include <asm/arch/mshc.h> +#include <asm/arch/pinmux.h>
+/* support 4 mmc hosts */ +enum {
- MAX_MMC_HOSTS = 4
+};
+static struct mmc mshci_dev[MAX_MMC_HOSTS]; +static struct mshci_host mshci_host[MAX_MMC_HOSTS]; +static int num_devs;
+/* Struct to hold mshci register and bus width */ +struct mshci_config {
- struct exynos_mshci *reg; /* registers address in physical memory */
- int bus_width; /* bus width */
- int removable; /* removable device? */
- enum periph_id periph_id; /* Peripheral ID for this peripheral */
+};
+/**
- Set bits of MSHCI host control register.
- @param host MSHCI host
- @param bits bits to be set
- @return 0 on success, -1 on failure
- */
+static int mshci_setbits(struct mshci_host *host, unsigned int bits) +{
- ulong start;
- setbits_le32(&host->reg->ctrl, bits);
- start = get_timer(0);
- while (readl(&host->reg->ctrl) & bits) {
- if (get_timer(start) > TIMEOUT_MS) {
- debug("Set bits failed\n");
- return -1;
- }
- }
- return 0;
+}
+/**
- Reset MSHCI host control register.
- @param host MSHCI host
- @return 0 on success, -1 on failure
- */
+static int mshci_reset_all(struct mshci_host *host) +{
- ulong start;
- /*
- * Before we reset ciu check the DATA0 line. If it is low and
- * we resets the ciu then we might see some errors.
- */
- start = get_timer(0);
- while (readl(&host->reg->status) & DATA_BUSY) {
- if (get_timer(start) > TIMEOUT_MS) {
- debug("Controller did not release"
- "data0 before ciu reset\n");
- return -1;
- }
- }
- if (mshci_setbits(host, CTRL_RESET)) {
- debug("Fail to reset card.\n");
- return -1;
- }
- if (mshci_setbits(host, FIFO_RESET)) {
- debug("Fail to reset fifo.\n");
- return -1;
- }
- if (mshci_setbits(host, DMA_RESET)) {
- debug("Fail to reset dma.\n");
- return -1;
- }
- return 0;
+}
+static void mshci_set_mdma_desc(u8 *desc_vir, u8 *desc_phy,
- unsigned int des0, unsigned int des1, unsigned int des2)
+{
- struct mshci_idmac *desc = (struct mshci_idmac *)desc_vir;
- desc->des0 = des0;
- desc->des1 = des1;
- desc->des2 = des2;
- desc->des3 = (unsigned int)desc_phy + sizeof(struct mshci_idmac);
+}
+static int mshci_prepare_data(struct mshci_host *host, struct mmc_data *data) +{
- unsigned int i;
- unsigned int data_cnt;
- unsigned int des_flag;
- unsigned int blksz;
- static struct mshci_idmac idmac_desc[0x10000];
- struct mshci_idmac *pdesc_dmac;
- if (mshci_setbits(host, FIFO_RESET)) {
- debug("Fail to reset FIFO\n");
- return -1;
- }
- pdesc_dmac = idmac_desc;
- blksz = data->blocksize;
- data_cnt = data->blocks;
- for (i = 0;; i++) {
- des_flag = (MSHCI_IDMAC_OWN | MSHCI_IDMAC_CH);
- des_flag |= (i == 0) ? MSHCI_IDMAC_FS : 0;
- if (data_cnt <= 8) {
- des_flag |= MSHCI_IDMAC_LD;
- mshci_set_mdma_desc((u8 *)pdesc_dmac,
- (u8 *)virt_to_phys(pdesc_dmac),
- des_flag, blksz * data_cnt,
- (unsigned int)(virt_to_phys(data->dest)) +
- (unsigned int)(i * 0x1000));
- break;
- }
- /* max transfer size is 4KB per descriptor */
- mshci_set_mdma_desc((u8 *)pdesc_dmac,
- (u8 *)virt_to_phys(pdesc_dmac),
- des_flag, blksz * 8,
- virt_to_phys(data->dest) +
- (unsigned int)(i * 0x1000));
- data_cnt -= 8;
- pdesc_dmac++;
- }
- writel((unsigned int)virt_to_phys(idmac_desc), &host->reg->dbaddr);
- /* enable the Internal DMA Controller */
- setbits_le32(&host->reg->ctrl, ENABLE_IDMAC | DMA_ENABLE);
- setbits_le32(&host->reg->bmod, BMOD_IDMAC_ENABLE | BMOD_IDMAC_FB);
- writel(data->blocksize, &host->reg->blksiz);
- writel(data->blocksize * data->blocks, &host->reg->bytcnt);
- return 0;
+}
+static int mshci_set_transfer_mode(struct mshci_host *host,
- struct mmc_data *data)
+{
- int mode = CMD_DATA_EXP_BIT;
- if (data->blocks > 1)
- mode |= CMD_SENT_AUTO_STOP_BIT;
- if (data->flags & MMC_DATA_WRITE)
- mode |= CMD_RW_BIT;
- return mode;
+}
+/*
- Sends a command out on the bus.
- @param mmc mmc device
- @param cmd mmc_cmd to be sent on bus
- @param data mmc data to be sent (optional)
- @return return 0 if ok, else -1
- */
+static int exynos_mshci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
- struct mmc_data *data)
+{
- struct mshci_host *host = mmc->priv;
- int flags = 0, i;
- unsigned int mask;
- ulong start;
- /*
- * We shouldn't wait for data inihibit for stop commands, even
- * though they might use busy signaling
- */
- start = get_timer(0);
- while (readl(&host->reg->status) & DATA_BUSY) {
- if (get_timer(start) > COMMAND_TIMEOUT) {
- debug("timeout on data busy\n");
- return -1;
- }
- }
- if (readl(&host->reg->rintsts)) {
- if ((readl(&host->reg->rintsts) &
- (INTMSK_CDONE | INTMSK_ACD)) == 0)
- debug("there are pending interrupts 0x%x\n",
- readl(&host->reg->rintsts));
- }
- /* It clears all pending interrupts before sending a command*/
- writel(INTMSK_ALL, &host->reg->rintsts);
- if (data) {
- if (mshci_prepare_data(host, data)) {
- debug("fail to prepare data\n");
- return -1;
- }
- }
- writel(cmd->cmdarg, &host->reg->cmdarg);
- if (data)
- flags = mshci_set_transfer_mode(host, data);
- if ((cmd->resp_type & MMC_RSP_136) && (cmd->resp_type & MMC_RSP_BUSY))
- /* this is out of SD spec */
- return -1;
- if (cmd->resp_type & MMC_RSP_PRESENT) {
- flags |= CMD_RESP_EXP_BIT;
- if (cmd->resp_type & MMC_RSP_136)
- flags |= CMD_RESP_LENGTH_BIT;
- }
- if (cmd->resp_type & MMC_RSP_CRC)
- flags |= CMD_CHECK_CRC_BIT;
- flags |= (cmd->cmdidx | CMD_STRT_BIT | CMD_USE_HOLD_REG |
- CMD_WAIT_PRV_DAT_BIT);
- mask = readl(&host->reg->cmd);
- if (mask & CMD_STRT_BIT)
- debug("cmd busy, current cmd: %d", cmd->cmdidx);
- writel(flags, &host->reg->cmd);
- /* wait for command complete by busy waiting. */
- for (i = 0; i < COMMAND_TIMEOUT; i++) {
- mask = readl(&host->reg->rintsts);
- if (mask & INTMSK_CDONE) {
- if (!data)
- writel(mask, &host->reg->rintsts);
- break;
- }
- }
- /* timeout for command complete. */
- if (COMMAND_TIMEOUT == i) {
- debug("timeout waiting for status update\n");
- return TIMEOUT;
- }
- if (mask & INTMSK_RTO) {
- if (((cmd->cmdidx == 8 || cmd->cmdidx == 41 ||
- cmd->cmdidx == 55)) == 0) {
- debug("response timeout error: 0x%x cmd: %d\n",
- mask, cmd->cmdidx);
- }
- return TIMEOUT;
- } else if (mask & INTMSK_RE) {
- debug("response error: 0x%x cmd: %d\n", mask, cmd->cmdidx);
- return -1;
- }
- if (cmd->resp_type & MMC_RSP_PRESENT) {
- if (cmd->resp_type & MMC_RSP_136) {
- /* CRC is stripped so we need to do some shifting. */
- cmd->response[0] = readl(&host->reg->resp3);
- cmd->response[1] = readl(&host->reg->resp2);
- cmd->response[2] = readl(&host->reg->resp1);
- cmd->response[3] = readl(&host->reg->resp0);
- } else {
- cmd->response[0] = readl(&host->reg->resp0);
- debug("\tcmd->response[0]: 0x%08x\n", cmd->response[0]);
- }
- }
- if (data) {
- while (!(mask & (DATA_ERR | DATA_TOUT | INTMSK_DTO)))
- mask = readl(&host->reg->rintsts);
- writel(mask, &host->reg->rintsts);
- if (mask & (DATA_ERR | DATA_TOUT)) {
- debug("error during transfer: 0x%x\n", mask);
- /* make sure disable IDMAC and IDMAC_Interrupts */
- writel((readl(&host->reg->ctrl) &
- ~(DMA_ENABLE | ENABLE_IDMAC)), &host->reg->ctrl);
- /* mask all interrupt source of IDMAC */
- writel(0, &host->reg->idinten);
- return -1;
- } else if (mask & INTMSK_DTO) {
- debug("mshci dma interrupt end\n");
- } else {
- debug("unexpected condition 0x%x\n", mask);
- }
- /* make sure disable IDMAC and IDMAC_Interrupts */
- writel((readl(&host->reg->ctrl) & ~(DMA_ENABLE | ENABLE_IDMAC)),
- &host->reg->ctrl);
- /* mask all interrupt source of IDMAC */
- writel(0, &host->reg->idinten);
- }
- udelay(100);
- return 0;
+}
+/*
- ON/OFF host controller clock
- @param host pointer to mshci_host
- @param val to enable/disable clock
- */
+static void mshci_clock_onoff(struct mshci_host *host, int val) +{
- if (val) {
- writel(CLK_ENABLE, &host->reg->clkena);
- writel(0, &host->reg->cmd);
- writel(CMD_ONLY_CLK, &host->reg->cmd);
- } else {
- writel(CLK_DISABLE, &host->reg->clkena);
- writel(0, &host->reg->cmd);
- writel(CMD_ONLY_CLK, &host->reg->cmd);
- }
+}
+/*
- change host controller clock
- @param host pointer to mshci_host
- @param clock request clock
- */
+static void mshci_change_clock(struct mshci_host *host, uint clock) +{
- int div;
- u32 sclk_mshc;
- if (clock == host->clock)
- return;
- /* If Input clock is higher than maximum mshc clock */
- if (clock > MAX_MSHCI_CLOCK) {
- debug("Input clock is too high\n");
- clock = MAX_MSHCI_CLOCK;
- }
- /* disable the clock before changing it */
- mshci_clock_onoff(host, CLK_DISABLE);
- /* get the clock division */
- if (host->peripheral == PERIPH_ID_SDMMC4)
- sclk_mshc = get_mshci_clk_div(host->peripheral) / 2;
- else
- sclk_mshc = get_mshci_clk_div(host->peripheral) / 4;
- /* CLKDIV */
- for (div = 1 ; div <= 0xff; div++) {
- if ((sclk_mshc / (2 * div)) <= clock) {
- writel(div, &host->reg->clkdiv);
- break;
- }
- }
- writel(0, &host->reg->cmd);
- writel(CMD_ONLY_CLK, &host->reg->cmd);
- writel(readl(&host->reg->cmd) & (~CMD_SEND_CLK_ONLY),
- &host->reg->cmd);
- mshci_clock_onoff(host, CLK_ENABLE);
- host->clock = clock;
+}
+/*
- Set ios for host controller clock
- This sets the card bus width and clksel
- */
+static void exynos_mshci_set_ios(struct mmc *mmc) +{
- struct mshci_host *host = mmc->priv;
- debug("bus_width: %x, clock: %d\n", mmc->bus_width, mmc->clock);
- if (mmc->clock > 0)
- mshci_change_clock(host, mmc->clock);
- if (mmc->bus_width == 8)
- writel(PORT0_CARD_WIDTH8, &host->reg->ctype);
- else if (mmc->bus_width == 4)
- writel(PORT0_CARD_WIDTH4, &host->reg->ctype);
- else
- writel(PORT0_CARD_WIDTH1, &host->reg->ctype);
- if (host->peripheral == PERIPH_ID_SDMMC0)
- writel(0x03030001, &host->reg->clksel);
- if (host->peripheral == PERIPH_ID_SDMMC2)
- writel(0x03020001, &host->reg->clksel);
- if (host->peripheral == PERIPH_ID_SDMMC4)
- writel(0x00020001, &host->reg->clksel);
+}
+/*
- Fifo init for host controller
- */
+static void mshci_fifo_init(struct mshci_host *host) +{
- int fifo_val, fifo_depth, fifo_threshold;
- fifo_val = readl(&host->reg->fifoth);
- fifo_depth = 0x80;
- fifo_threshold = fifo_depth / 2;
- fifo_val &= ~(RX_WMARK | TX_WMARK | MSIZE_MASK);
- fifo_val |= (fifo_threshold | (fifo_threshold << 16) | MSIZE_8);
- writel(fifo_val, &host->reg->fifoth);
+}
+static void mshci_init(struct mshci_host *host) +{
- /* power on the card */
- writel(POWER_ENABLE, &host->reg->pwren);
- mshci_reset_all(host);
- mshci_fifo_init(host);
- /* clear all pending interrupts */
- writel(INTMSK_ALL, &host->reg->rintsts);
- /* interrupts are not used, disable all */
- writel(0, &host->reg->intmask);
+}
+static int exynos_mshci_initialize(struct mmc *mmc) +{
- struct mshci_host *host = (struct mshci_host *)mmc->priv;
- unsigned int ier;
- mshci_init(host);
- /* enumerate at 400KHz */
- mshci_change_clock(host, MIN_MSHCI_CLOCK);
- /* set auto stop command */
- ier = readl(&host->reg->ctrl);
- ier |= SEND_AS_CCSD;
- writel(ier, &host->reg->ctrl);
- /* set 1bit card mode */
- writel(PORT0_CARD_WIDTH1, &host->reg->ctype);
- writel(0xfffff, &host->reg->debnce);
- /* set bus mode register for IDMAC */
- writel(BMOD_IDMAC_RESET, &host->reg->bmod);
- writel(0x0, &host->reg->idinten);
- /* set the max timeout for data and response */
- writel(TMOUT_MAX, &host->reg->tmout);
- return 0;
+}
+static int mshci_initialize(struct mshci_config *config) +{
- struct mshci_host *mmc_host;
- struct mmc *mmc;
- if (num_devs == MAX_MMC_HOSTS) {
- debug("%s: Too many hosts\n", __func__);
- return -1;
- }
- /* set the clock for mshci controller */
- if (set_mshci_clk_div(config->periph_id)) {
- debug("clock_set_mshci failed\n");
- return -1;
- }
- mmc = &mshci_dev[num_devs];
- mmc_host = &mshci_host[num_devs];
- sprintf(mmc->name, "EXYNOS MSHCI%d", num_devs);
- num_devs++;
- mmc->priv = mmc_host;
- mmc->send_cmd = exynos_mshci_send_command;
- mmc->set_ios = exynos_mshci_set_ios;
- mmc->init = exynos_mshci_initialize;
- mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
- mmc->host_caps = MMC_MODE_HS_52MHz | MMC_MODE_HS | MMC_MODE_HC;
- if (config->bus_width == 8)
- mmc->host_caps |= MMC_MODE_8BIT;
- else
- mmc->host_caps |= MMC_MODE_4BIT;
- mmc->f_min = MIN_MSHCI_CLOCK;
- mmc->f_max = MAX_MSHCI_CLOCK;
- exynos_pinmux_config(config->periph_id,
- config->bus_width == 8 ? PINMUX_FLAG_8BIT_MODE : 0);
- mmc_host->clock = 0;
- mmc_host->reg = config->reg;
- mmc_host->peripheral = config->periph_id;
- mmc->b_max = 1;
- mmc_register(mmc);
- mmc->block_dev.removable = config->removable;
- debug("exynos_mshci: periph_id=%d, width=%d, reg=%p\n",
- config->periph_id, config->bus_width, config->reg);
- return 0;
+}
+int exynos_mshci_init(enum periph_id periph_id, int bus_width) +{
- struct mshci_config config;
- int ret = 0;
- config.bus_width = bus_width;
- config.reg = (struct exynos_mshci *)samsung_get_base_mshci();
- config.periph_id = periph_id;
- config.removable = 1;
- if (mshci_initialize(&config)) {
- debug("%s: Failed to init MSHCI\n", __func__);
- ret = -1;
- }
- return ret;
+}
1.7.4.4
U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot