Hi Rajeshwari, This patch has too many dependence with other patches. (Pinmux and PeripID, patches for MSHCI setting). And as i mentioned, designWare controller isn't exynos specific.
I think good that separate two files. (dw_mmc.c and exynos_dw_mmc.c) Like this...dw_mmc.c is generic code and exynos_dw_mmc.c is samsung specific code.. If you want, I will send to you patch that related with them. (based-on your patch) And Added some comment On 06/12/2012 06:33 PM, Rajeshwari Birje wrote: > Hi Jaehoon Chung, > > Yes you need to apply the following patchset > http://comments.gmane.org/gmane.comp.boot-loaders.u-boot/132754 > > Regards, > Rajeshwari Shinde. > > On Tue, Jun 12, 2012 at 2:07 PM, Jaehoon Chung <jh80.ch...@samsung.com> wrote: >> Hi Rajeshwari, >> >> Before applied this patch, it must apply your patch for PINMUX. right? >> >> Best Regards, >> Jaehoon Chung >> >> On 06/12/2012 03:14 PM, Chander Kashyap wrote: >> >>> Hi, >>> >>> On 11 June 2012 19:26, Rajeshwari Birje <rajeshwari.bi...@gmail.com> wrote: >>>> Hi All, >>>> >>>> ccing Jaehoon Chung >>>> >>>> Regards, >>>> Rajeshwari Shinde. >>>> >>>> >>>> On Mon, Jun 11, 2012 at 6:18 PM, Rajeshwari Shinde >>>> <rajeshwar...@samsung.com> wrote: >>>>> Add DWMMC driver support and resgister description for same. >>>>> >>>>> Signed-off-by: Alim Akhtar <alim.akh...@samsung.com> >>>>> Signed-off-by: Terry Lambert <tlamb...@chromium.org> >>>>> Signed-off-by: Rajeshwari Shinde <rajeshwar...@samsung.com> >>>>> --- >>>>> Changes in V2: >>>>> - Incorporated comments from Jaehung Chung. >>>>> - Renamed MSHCI to DWMMC through out the driver. >>>>> - Renamed files to exynos_dwmmc from exynos_mshc. >>>>> - Removed major hard codings of values. >>>>> - Wrote dw_mci_writel and dw_mci_readl functions for writel and >>>>> readl. >>>>> - Removed structure of registers and defined each one separately. >>>>> orch/arm/include/asm/arch-exynos/exynos_dwmmc.h | 229 +++++++++ >>>>> drivers/mmc/Makefile | 1 + >>>>> drivers/mmc/exynos_dwmmc.c | 566 >>>>> +++++++++++++++++++++++ >>>>> 3 files changed, 796 insertions(+), 0 deletions(-) >>>>> create mode 100644 arch/arm/include/asm/arch-exynos/exynos_dwmmc.h >>>>> create mode 100644 drivers/mmc/exynos_dwmmc.c >>>>> >>>>> diff --git a/arch/arm/include/asm/arch-exynos/exynos_dwmmc.h >>>>> b/arch/arm/include/asm/arch-exynos/exynos_dwmmc.h >>>>> new file mode 100644 >>>>> index 0000000..349bd75 >>>>> --- /dev/null >>>>> +++ b/arch/arm/include/asm/arch-exynos/exynos_dwmmc.h >>>>> @@ -0,0 +1,229 @@ >>>>> +/* >>>>> + * (C) Copyright 2012 SAMSUNG Electronics >>>>> + * Abhilash Kesavan <a.kesa...@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_DWMMC_H >>>>> +#define __ASM_ARCH_COMMON_DWMMC_H >>>>> + >>>>> +#include <asm/arch/pinmux.h> >>>>> + >>>>> +#ifndef __ASSEMBLY__ >>>>> +struct dw_mci_host { >>>>> + void *ioaddr; >>>>> + unsigned int clock; /* Current clock in MHz */ >>>>> + enum periph_id peripheral; >>>>> + unsigned int verid; /* SDHCI spec. version */ >>>>> + unsigned int data_offset; /* DATA offset */ >>>>> +}; >>>>> + >>>>> +/* >>>>> + * Struct idma >>>>> + * Holds the descriptor list >>>>> + */ >>>>> +struct dw_mci_idmac { >>>>> + u32 des0; >>>>> + u32 des1; >>>>> + u32 des2; >>>>> + u32 des3; >>>>> +}; >>>>> + >>> #endif >>>>> +/* Control Register Register */ >>>>> +#define DWMCI_CONTROL 0x00 >>>>> +#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 DWMCI_PWREN 0x04 >>>>> +#define POWER_ENABLE (0x1 << 0) >>>>> + >>>>> +#define DWMCI_CLKDIV 0x08 >>>>> +#define DWMCI_CLKSRC 0x0c >>>>> + >>>>> +/* Clock Enable Register */ >>>>> +#define DWMCI_CLKENA 0x10 >>>>> +#define CLK_ENABLE (0x1 << 0) >>>>> +#define CLK_DISABLE (0x0 << 0) >>>>> + >>>>> +/* Timeout Register */ >>>>> +#define DWMCI_TMOUT 0x14 >>>>> +#define TMOUT_MAX 0xffffffff >>>>> + >>>>> +/* Card Type Register */ >>>>> +#define DWMCI_CTYPE 0x18 >>>>> +#define PORT0_CARD_WIDTH1 0 >>>>> +#define PORT0_CARD_WIDTH4 (0x1 << 0) >>>>> +#define PORT0_CARD_WIDTH8 (0x1 << 16) >>>>> + >>>>> +#define DWMCI_BLKSIZE 0x1c >>>>> +#define DWMCI_BYTCNT 0x20 >>>>> + >>>>> +/* Interrupt Mask Register */ >>>>> +#define DWMCI_INTMASK 0x24 >>>>> +#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) >>>>> + >>>>> +#define DWMCI_CMDARG 0x28 >>>>> + >>>>> +/* Command Register */ >>>>> +#define DWMCI_CMD 0x2c >>>>> +#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) >>>>> + >>>>> +#define DWMCI_RESP0 0x30 >>>>> +#define DWMCI_RESP1 0x34 >>>>> +#define DWMCI_RESP2 0x38 >>>>> +#define DWMCI_RESP3 0x3c >>>>> + >>>>> +#define DWMCI_MINTSTS 0x40 >>>>> + >>>>> +/* Raw Interrupt Register */ >>>>> +#define DWMCI_RINTSTS 0x44 >>>>> +#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 DWMCI_STATUS 0x48 >>>>> +#define DATA_BUSY (0x1 << 9) >>>>> + >>>>> +/* FIFO Threshold Watermark Register */ >>>>> +#define DWMCI_FIFOTH 0x4c >>>>> +#define TX_WMARK (0xFFF << 0) >>>>> +#define RX_WMARK (0xFFF << 16) >>>>> +#define MSIZE_MASK (0x7 << 28) >>>>> + >>>>> +#define DWMCI_CDETECT 0x50 >>>>> +#define DWMCI_WRTORT 0x54 >>>>> +#define DWMCI_GPIO 0x58 >>>>> +#define DWMCI_TCBCNT 0x5c >>>>> +#define DWMCI_TBBCNT 0x60 >>>>> +#define DWMCI_DEBENCE 0x64 >>>>> +#define DWMCI_USRID 0x68 >>>>> +#define DWMCI_VERID 0x6c >>>>> +#define DWMCI_HCON 0x70 >>>>> +#define DWMCI_UHS_REG 0x74 >>>>> +#define DWMCI_RST_n 0x78 >>>>> + >>>>> +/* DW DMA Mutiple Transaction Size */ >>>>> +#define MSIZE_8 (2 << 28) >>>>> + >>>>> +/* Bus Mode Register */ >>>>> +#define DWMCI_BMOD 0x80 >>>>> +#define BMOD_IDMAC_RESET (0x1 << 0) >>>>> +#define BMOD_IDMAC_FB (0x1 << 1) >>>>> +#define BMOD_IDMAC_ENABLE (0x1 << 7) >>>>> + >>>>> +#define DWMCI_PLDMND 0x84 >>>>> +#define DWMCI_DBADDR 0x88 >>>>> + >>>>> +/* IDMAC bits */ >>>>> +#define DWMCI_IDSTS 0x8c >>>>> +#define DWMCI_IDMAC_OWN (0x1 << 31) >>>>> +#define DWMCI_IDMAC_CH (0x1 << 4) >>>>> +#define DWMCI_IDMAC_FS (0x1 << 3) >>>>> +#define DWMCI_IDMAC_LD (0x1 << 2) >>>>> + >>>>> +#define DWMCI_IDINTEN 0x90 >>>>> +#define DWMCI_DSCADDR 0x94 >>>>> +#define DWMCI_BUFADDR 0x98 >>>>> + >>>>> +/* CLKSEL bits*/ >>>>> +#define DWMCI_CLKSEL 0x9c >>>>> +#define SELCLK_SAMPLE_1PHASE_Shift (0x1 << 0) >>>>> +#define SELCLK_DRV_3PHASE_SHIFT (0x3 << 16) >>>>> +#define SELCLK_DRV_2PHASE_SHIFT (0x2 << 16) >>>>> +#define SELCLK_DIV_RATIO (0x3 << 24) >>>>> + >>>>> +#define DWMCI_CARDTHRCTL 0x100 >>>>> + >>>>> +/* >>>>> + * Data offset is difference according to Version >>>>> + * Lower than 2.40a : data register offest is 0x100 >>>>> + */ >>>>> +#define DW_MMC_240A 0x240a >>>>> +#define DATA_OFFSET 0x100 >>>>> +#define DATA_240A_OFFSET 0x200 >>>>> + >>>>> +#define MAX_DWMMC_CLOCK 52000000 /* Max limit is 52MHz */ >>>>> +#define MIN_DWMMC_CLOCK 400000 /* Lower limit is 400KHz */ >>>>> +#define COMMAND_TIMEOUT 10000 >>>>> +#define TIMEOUT_MS 100 >>>>> +#define MAXCLKDIV 0xff >>>>> + >>>>> +/* Version ID register define */ >>>>> +#define GET_VERID(x) ((x) & 0xFFFF) >>>>> + >>>>> +static inline void dw_mci_writel(struct dw_mci_host *host, u32 val, int >>>>> reg) >>>>> +{ >>>>> + writel(val, host->ioaddr + reg); >>>>> +} >>>>> + >>>>> +static inline void dw_mci_writew(struct dw_mci_host *host, u16 val, int >>>>> reg) >>>>> +{ >>>>> + writew(val, host->ioaddr + reg); >>>>> +} >>>>> + >>>>> +static inline void dw_mci_writeb(struct dw_mci_host *host, u8 val, int >>>>> reg) >>>>> +{ >>>>> + writeb(val, host->ioaddr + reg); >>>>> +} >>>>> + >>>>> +static inline u32 dw_mci_readl(struct dw_mci_host *host, int reg) >>>>> +{ >>>>> + return readl(host->ioaddr + reg); >>>>> +} >>>>> + >>>>> +static inline u16 dw_mci_readw(struct dw_mci_host *host, int reg) >>>>> +{ >>>>> + return readw(host->ioaddr + reg); >>>>> +} >>>>> + >>>>> +static inline u8 dw_mci_readb(struct dw_mci_host *host, int reg) >>>>> +{ >>>>> + return readb(host->ioaddr + reg); >>>>> +} >>>>> + >>>>> +int dw_mci_init(enum periph_id periph_id, int bus_width); >>>>> + >>>>> +#endif /* __ASSEMBLY__ */ >>> remove at this place after structure declaration. >>>>> +#endif /* __ASM_ARCH_COMMON_DWMMC_H */ >>>>> diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile >>>>> index c245352..cf0be05 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_DWMMC) += exynos_dwmmc.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_dwmmc.c b/drivers/mmc/exynos_dwmmc.c >>>>> new file mode 100644 >>>>> index 0000000..96f6ceb >>>>> --- /dev/null >>>>> +++ b/drivers/mmc/exynos_dwmmc.c >>>>> @@ -0,0 +1,566 @@ >>>>> +/* >>>>> + * (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/errno.h> >>>>> +#include <asm/arch/clk.h> >>>>> +#include <asm/arch/cpu.h> >>>>> +#include <asm/arch/exynos_dwmmc.h> >>>>> +#include <asm/arch/pinmux.h> >>>>> + >>>>> +/* support 4 mmc hosts */ >>>>> +enum { >>>>> + MAX_MMC_HOSTS = 4 >>>>> +}; >>>>> + >>>>> +static struct mmc dw_mci_dev[MAX_MMC_HOSTS]; >>>>> +static struct dw_mci_host dw_mci_host[MAX_MMC_HOSTS]; >>>>> +static int num_devs; >>>>> + >>>>> +/** >>>>> + * Set bits of DWMMC host control register. >>>>> + * >>>>> + * @param host DWMMC host >>>>> + * @param bits bits to be set >>>>> + * @return 0 on success, TIMEOUT on failure >>>>> + */ >>>>> +static int dw_mci_setbits(struct dw_mci_host *host, unsigned int bits) >>>>> +{ >>>>> + ulong start; >>>>> + >>>>> + setbits_le32(host->ioaddr + DWMCI_CONTROL, bits); >>>>> + >>>>> + start = get_timer(0); >>>>> + while (dw_mci_readl(host, DWMCI_CONTROL) & bits) { >>>>> + if (get_timer(start) > TIMEOUT_MS) { >>>>> + debug("Set bits failed\n"); >>>>> + return TIMEOUT; >>>>> + } >>>>> + } >>>>> + return 0; >>>>> +} >>>>> + >>>>> +/** >>>>> + * Reset DWMMC host control register. >>>>> + * >>>>> + * @param host DWMMC host >>>>> + * @return 0 on success, TIMEOUT on failure >>>>> + */ >>>>> +static int dw_mci_reset_all(struct dw_mci_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 (dw_mci_readl(host, DWMCI_STATUS) & DATA_BUSY) { >>>>> + if (get_timer(start) > TIMEOUT_MS) { >>>>> + debug("Controller did not release" >>>>> + "data0 before ciu reset\n"); >>>>> + return TIMEOUT; >>>>> + } >>>>> + } >>>>> + return dw_mci_setbits(host, CTRL_RESET | FIFO_RESET | DMA_RESET); >>>>> +} >>>>> + >>>>> +static void dw_mci_set_mdma_desc(u8 *desc_vir, u8 *desc_phy, >>>>> + unsigned int des0, unsigned int des1, unsigned int des2) >>>>> +{ >>>>> + struct dw_mci_idmac *desc = (struct dw_mci_idmac *)desc_vir; >>>>> + >>>>> + desc->des0 = des0; >>>>> + desc->des1 = des1; >>>>> + desc->des2 = des2; >>>>> + desc->des3 = (unsigned int)desc_phy + sizeof(struct dw_mci_idmac); >>>>> +} >>>>> + >>>>> +static int dw_mci_prepare_data(struct dw_mci_host *host, struct mmc_data >>>>> *data) >>>>> +{ >>>>> + unsigned int i, data_cnt, des_flag, blksz; >>>>> + int err; >>>>> + ulong data_start, data_end; >>>>> + static struct dw_mci_idmac idmac_desc[0x10000]; >>>>> + struct dw_mci_idmac *pdesc_dmac; >>>>> + >>>>> + err = dw_mci_setbits(host, FIFO_RESET); >>>>> + if (err) { >>>>> + debug("Fail to reset FIFO\n"); >>>>> + return err; >>>>> + } >>>>> + >>>>> + pdesc_dmac = idmac_desc; >>>>> + blksz = data->blocksize; >>>>> + data_cnt = data->blocks; >>>>> + >>>>> + for (i = 0;; i++) { >>>>> + des_flag = (DWMCI_IDMAC_OWN | DWMCI_IDMAC_CH); >>>>> + des_flag |= (i == 0) ? DWMCI_IDMAC_FS : 0; >>>>> + if (data_cnt <= 8) { >>>>> + des_flag |= DWMCI_IDMAC_LD; >>>>> + dw_mci_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 */ >>>>> + dw_mci_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++; >>>>> + } >>>>> + >>>>> + data_start = (ulong)idmac_desc; >>>>> + data_end = (ulong)pdesc_dmac; >>>>> + flush_dcache_range(data_start, data_end + ARCH_DMA_MINALIGN); >>>>> + >>>>> + data_start = (ulong)data->dest; >>>>> + data_end = (ulong)(data->dest + data->blocks * data->blocksize); >>>>> + flush_dcache_range(data_start, data_end); >>>>> + >>>>> + dw_mci_writel(host, (unsigned int)virt_to_phys(idmac_desc), >>>>> + DWMCI_DBADDR); >>>>> + >>>>> + /* enable the Internal DMA Controller */ >>>>> + setbits_le32(host->ioaddr + DWMCI_CONTROL, ENABLE_IDMAC | >>>>> + DMA_ENABLE); >>>>> + setbits_le32(host->ioaddr + DWMCI_BMOD, BMOD_IDMAC_ENABLE | >>>>> + BMOD_IDMAC_FB); >>>>> + >>>>> + dw_mci_writel(host, data->blocksize, DWMCI_BLKSIZE); >>>>> + dw_mci_writel(host, data->blocksize * data->blocks, DWMCI_BYTCNT); >>>>> + >>>>> + return 0; >>>>> +} >>>>> + >>>>> +static int dw_mci_set_transfer_mode(struct dw_mci_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 error number >>>>> + */ >>>>> +static int dw_mci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, >>>>> + struct mmc_data *data) >>>>> +{ >>>>> + struct dw_mci_host *host = mmc->priv; mmc->priv's type is void type. I think good that use (struct dw_mci_host *)mmc->priv; >>>>> + >>>>> + int flags = 0, i, err; >>>>> + unsigned int mask; >>>>> + ulong start, data_start, data_end; >>>>> + >>>>> + /* >>>>> + * We shouldn't wait for data inihibit for stop commands, even >>>>> + * though they might use busy signaling >>>>> + */ >>>>> + start = get_timer(0); >>>>> + while (dw_mci_readl(host, DWMCI_STATUS) & DATA_BUSY) { >>>>> + if (get_timer(start) > COMMAND_TIMEOUT) { >>>>> + debug("timeout on data busy\n"); >>>>> + return TIMEOUT; >>>>> + } >>>>> + } >>>>> + What do the below condition? just debugging? i didn't understand why need this condition. >>>>> + if (dw_mci_readl(host, DWMCI_RINTSTS)) { >>>>> + if ((dw_mci_readl(host, DWMCI_RINTSTS) & >>>>> + (INTMSK_CDONE | INTMSK_ACD)) == 0) >>>>> + debug("there are pending interrupts 0x%x\n", >>>>> + dw_mci_readl(host, DWMCI_RINTSTS)); >>>>> + } >>>>> + /* It clears all pending interrupts before sending a command*/ >>>>> + dw_mci_writel(host, INTMSK_ALL, DWMCI_RINTSTS); >>>>> + >>>>> + if (data) { >>>>> + err = dw_mci_prepare_data(host, data); >>>>> + if (err) { >>>>> + debug("fail to prepare data\n"); >>>>> + return err; >>>>> + } >>>>> + } >>>>> + >>>>> + dw_mci_writel(host, cmd->cmdarg, DWMCI_CMDARG); >>>>> + >>>>> + if (data) >>>>> + flags = dw_mci_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 = dw_mci_readl(host, DWMCI_CMD); >>>>> + if (mask & CMD_STRT_BIT) >>>>> + debug("cmd busy, current cmd: %d", cmd->cmdidx); Also need not this condition. Debugging point? >>>>> + >>>>> + dw_mci_writel(host, flags, DWMCI_CMD); >>>>> + /* wait for command complete by busy waiting. */ >>>>> + for (i = 0; i < COMMAND_TIMEOUT; i++) { >>>>> + mask = dw_mci_readl(host, DWMCI_RINTSTS); >>>>> + if (mask & INTMSK_CDONE) { >>>>> + if (!data) >>>>> + dw_mci_writel(host, mask, DWMCI_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 == MMC_CMD_SEND_EXT_CSD || >>>>> + cmd->cmdidx == MMC_CMD_APP_CMD)) == 0) { >>>>> + debug("response timeout error: 0x%x cmd: %d\n", >>>>> + mask, cmd->cmdidx); >>>>> + } What do you check with MMC_CMD_SEND_EXT_CSD or MMC_CMD_APP_CMD? Also Debugging? >>>>> + 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] = dw_mci_readl(host, >>>>> + >>>>> DWMCI_RESP3); >>>>> + cmd->response[1] = dw_mci_readl(host, >>>>> + >>>>> DWMCI_RESP2); >>>>> + cmd->response[2] = dw_mci_readl(host, >>>>> + >>>>> DWMCI_RESP1); >>>>> + cmd->response[3] = dw_mci_readl(host, >>>>> + >>>>> DWMCI_RESP0); Fix the indent >>>>> + } else { >>>>> + cmd->response[0] = dw_mci_readl(host, >>>>> DWMCI_RESP0); >>>>> + debug("\tcmd->response[0]: 0x%08x\n", >>>>> cmd->response[0]); >>>>> + } >>>>> + } >>>>> + >>>>> + if (data) { >>>>> + while (!(mask & (DATA_ERR | DATA_TOUT | INTMSK_DTO))) >>>>> + mask = dw_mci_readl(host, DWMCI_RINTSTS); >>>>> + dw_mci_writel(host, mask, DWMCI_RINTSTS); >>>>> + if (data->flags & MMC_DATA_READ) { >>>>> + data_start = (ulong)data->dest; >>>>> + data_end = (ulong)data->dest + >>>>> + data->blocks * data->blocksize; >>>>> + invalidate_dcache_range(data_start, data_end); If didn't enable dcache? >>>>> + } >>>>> + if (mask & (DATA_ERR | DATA_TOUT)) { >>>>> + debug("error during transfer: 0x%x\n", mask); >>>>> + /* make sure disable IDMAC and IDMAC_Interrupts */ >>>>> + dw_mci_writel(host, (dw_mci_readl(host, >>>>> DWMCI_CONTROL) & >>>>> + ~(DMA_ENABLE | ENABLE_IDMAC)), DWMCI_CONTROL); >>>>> + /* mask all interrupt source of IDMAC */ >>>>> + dw_mci_writel(host, 0, DWMCI_IDINTEN); >>>>> + return -1; >>>>> + } else if (mask & INTMSK_DTO) { >>>>> + debug("dwmmc dma interrupt end\n"); >>>>> + } else { >>>>> + debug("unexpected condition 0x%x\n", mask); >>>>> + } >>>>> + /* make sure disable IDMAC and IDMAC_Interrupts */ >>>>> + dw_mci_writel(host, (dw_mci_readl(host, DWMCI_CONTROL) & >>>>> + ~(DMA_ENABLE | ENABLE_IDMAC)), >>>>> + DWMCI_CONTROL); >>>>> + /* mask all interrupt source of IDMAC */ >>>>> + dw_mci_writel(host, 0, DWMCI_IDINTEN); >>>>> + } >>>>> + >>>>> + udelay(100); >>>>> + >>>>> + return 0; >>>>> +} >>>>> + >>>>> +/* >>>>> + * ON/OFF host controller clock >>>>> + * >>>>> + * @param host pointer to dw_mci_host >>>>> + * @param val to enable/disable clock >>>>> + */ >>>>> +static void dw_mci_clock_onoff(struct dw_mci_host *host, int val) >>>>> +{ >>>>> + >>>>> + if (val) >>>>> + dw_mci_writel(host, CLK_ENABLE, DWMCI_CLKENA); >>>>> + else >>>>> + dw_mci_writel(host, CLK_DISABLE, DWMCI_CLKENA); >>>>> + >>>>> + dw_mci_writel(host, 0, DWMCI_CMD); >>>>> + dw_mci_writel(host, CMD_ONLY_CLK, DWMCI_CMD); >>>>> +} >>>>> + >>>>> +/* >>>>> + * change host controller clock >>>>> + * >>>>> + * @param host pointer to dw_mci_host >>>>> + * @param clock request clock >>>>> + */ >>>>> +static void dw_mci_change_clock(struct dw_mci_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_DWMMC_CLOCK) { >>>>> + debug("Input clock is too high\n"); >>>>> + clock = MAX_DWMMC_CLOCK; >>>>> + } >>>>> + >>>>> + /* disable the clock before changing it */ >>>>> + dw_mci_clock_onoff(host, CLK_DISABLE); >>>>> + >>>>> + /* get the clock division */ >>>>> + if (host->peripheral == PERIPH_ID_SDMMC4) >>>>> + sclk_mshc = get_dw_mci_clk_div(host->peripheral) / 2; >>>>> + else >>>>> + sclk_mshc = get_dw_mci_clk_div(host->peripheral) / 4; >>>>> + >>>>> + /* CLKDIV */ >>>>> + for (div = 1 ; div <= MAXCLKDIV; div++) { >>>>> + if ((sclk_mshc / (2 * div)) <= clock) { >>>>> + dw_mci_writel(host, div, DWMCI_CLKDIV); >>>>> + break; >>>>> + } >>>>> + } >>>>> + >>>>> + dw_mci_writel(host, 0, DWMCI_CMD); >>>>> + dw_mci_writel(host, CMD_ONLY_CLK, DWMCI_CMD); >>>>> + >>>>> + dw_mci_writel(host, dw_mci_readl(host, DWMCI_CMD) & >>>>> + (~CMD_SEND_CLK_ONLY), >>>>> + DWMCI_CMD); >>>>> + >>>>> + dw_mci_clock_onoff(host, CLK_ENABLE); >>>>> + host->clock = clock; >>>>> +} >>>>> + >>>>> +/* >>>>> + * Set ios for host controller clock >>>>> + * >>>>> + * This sets the card bus width and clksel >>>>> + */ >>>>> +static void dw_mci_set_ios(struct mmc *mmc) >>>>> +{ >>>>> + struct dw_mci_host *host = mmc->priv; Also... Best Regards, Jaehoon Chung >>>>> + int val; >>>>> + >>>>> + debug("bus_width: %x, clock: %d\n", mmc->bus_width, mmc->clock); >>>>> + >>>>> + if (mmc->clock > 0) >>>>> + dw_mci_change_clock(host, mmc->clock); >>>>> + >>>>> + if (mmc->bus_width == 8) >>>>> + dw_mci_writel(host, PORT0_CARD_WIDTH8, DWMCI_CTYPE); >>>>> + else if (mmc->bus_width == 4) >>>>> + dw_mci_writel(host, PORT0_CARD_WIDTH4, DWMCI_CTYPE); >>>>> + else >>>>> + dw_mci_writel(host, PORT0_CARD_WIDTH1, DWMCI_CTYPE); >>>>> + >>>>> + val = dw_mci_readl(host, DWMCI_CLKSEL); >>>>> + if (host->peripheral == PERIPH_ID_SDMMC0) >>>>> + val |= (SELCLK_SAMPLE_1PHASE_Shift | >>>>> SELCLK_DRV_3PHASE_SHIFT | >>>>> + SELCLK_DIV_RATIO); >>>>> + if (host->peripheral == PERIPH_ID_SDMMC2) >>>>> + val |= (SELCLK_SAMPLE_1PHASE_Shift | >>>>> SELCLK_DRV_2PHASE_SHIFT | >>>>> + SELCLK_DIV_RATIO); >>>>> + if (host->peripheral == PERIPH_ID_SDMMC4) >>>>> + val |= (SELCLK_SAMPLE_1PHASE_Shift | >>>>> SELCLK_DRV_2PHASE_SHIFT); >>>>> + >>>>> + dw_mci_writel(host, val, DWMCI_CLKSEL); >>>>> +} >>>>> + >>>>> +/* >>>>> + * Fifo init for host controller >>>>> + */ >>>>> +static void dw_mci_fifo_init(struct dw_mci_host *host) >>>>> +{ >>>>> + int fifo_val, fifo_depth, fifo_threshold; >>>>> + >>>>> + fifo_val = dw_mci_readl(host, DWMCI_FIFOTH); >>>>> + >>>>> + /* Power-on value of RX_WMark is FIFO_DEPTH-1 */ >>>>> + fifo_depth = 1 + ((fifo_val >> 16) & 0x7ff); >>>>> + fifo_threshold = fifo_depth / 2; >>>>> + >>>>> + fifo_val &= ~(RX_WMARK | TX_WMARK | MSIZE_MASK); >>>>> + fifo_val |= (fifo_threshold | (fifo_threshold << 16) | MSIZE_8); >>>>> + dw_mci_writel(host, fifo_val, DWMCI_FIFOTH); >>>>> +} >>>>> + >>>>> + >>>>> +static int dw_mci_reset(struct dw_mci_host *host) >>>>> +{ >>>>> + int err; >>>>> + >>>>> + /* power on the card */ >>>>> + dw_mci_writel(host, POWER_ENABLE, DWMCI_PWREN); >>>>> + >>>>> + err = dw_mci_reset_all(host); >>>>> + if (err) >>>>> + return err; >>>>> + >>>>> + dw_mci_fifo_init(host); >>>>> + >>>>> + /* clear all pending interrupts */ >>>>> + dw_mci_writel(host, INTMSK_ALL, DWMCI_RINTSTS); >>>>> + >>>>> + /* interrupts are not used, disable all */ >>>>> + dw_mci_writel(host, 0, DWMCI_INTMASK); >>>>> + >>>>> + return 0; >>>>> +} >>>>> + >>>>> +static int dw_mci_initialize(struct mmc *mmc) >>>>> +{ >>>>> + struct dw_mci_host *host = (struct dw_mci_host *)mmc->priv; >>>>> + unsigned int ier; >>>>> + int err; >>>>> + >>>>> + err = dw_mci_reset(host); >>>>> + if (err) >>>>> + return err; >>>>> + >>>>> + /* enumerate at 400KHz */ >>>>> + dw_mci_change_clock(host, MIN_DWMMC_CLOCK); >>>>> + >>>>> + /* set auto stop command */ >>>>> + ier = dw_mci_readl(host, DWMCI_CONTROL); >>>>> + ier |= SEND_AS_CCSD; >>>>> + dw_mci_writel(host, ier, DWMCI_CONTROL); >>>>> + >>>>> + /* set 1bit card mode */ >>>>> + dw_mci_writel(host, PORT0_CARD_WIDTH1, DWMCI_CTYPE); >>>>> + >>>>> + dw_mci_writel(host, 0xfffff, DWMCI_DEBENCE); >>>>> + >>>>> + /* set bus mode register for IDMAC */ >>>>> + dw_mci_writel(host, BMOD_IDMAC_RESET, DWMCI_BMOD); >>>>> + >>>>> + dw_mci_writel(host, 0x0, DWMCI_IDINTEN); >>>>> + >>>>> + /* set the max timeout for data and response */ >>>>> + dw_mci_writel(host, TMOUT_MAX, DWMCI_TMOUT); >>>>> + >>>>> + return 0; >>>>> +} >>>>> + >>>>> +int dw_mci_init(enum periph_id periph_id, int bus_width) >>>>> +{ >>>>> + struct dw_mci_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 dwmmc controller */ >>>>> + if (set_dw_mci_clk_div(periph_id)) { >>>>> + debug("clock_set_dw_mci failed\n"); >>>>> + return -EINVAL; >>>>> + } >>>>> + >>>>> + mmc = &dw_mci_dev[num_devs]; >>>>> + mmc_host = &dw_mci_host[num_devs]; >>>>> + >>>>> + sprintf(mmc->name, "DWMMC%d", num_devs); >>>>> + num_devs++; >>>>> + >>>>> + mmc->priv = mmc_host; >>>>> + mmc->send_cmd = dw_mci_send_command; >>>>> + mmc->set_ios = dw_mci_set_ios; >>>>> + mmc->init = dw_mci_initialize; >>>>> + >>>>> + /* >>>>> + * In 2.40a spec, Data offset is changed. >>>>> + * Need to check the version-id and set data-offset for DATA >>>>> register. >>>>> + */ >>>>> + mmc_host->verid = GET_VERID(dw_mci_readl(mmc_host, DWMCI_VERID)); >>>>> + debug("Version ID is %04x\n", mmc_host->verid); >>>>> + >>>>> + if (mmc_host->verid < DW_MMC_240A) >>>>> + mmc_host->data_offset = DATA_OFFSET; >>>>> + else >>>>> + mmc_host->data_offset = DATA_240A_OFFSET; >>>>> + >>>>> + mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34; >>>>> + mmc->host_caps = MMC_MODE_HS_52MHz | MMC_MODE_HS | MMC_MODE_HC; >>>>> + >>>>> + if (bus_width == 8) >>>>> + mmc->host_caps |= MMC_MODE_8BIT; >>>>> + else >>>>> + mmc->host_caps |= MMC_MODE_4BIT; >>>>> + >>>>> + mmc->f_min = MIN_DWMMC_CLOCK; >>>>> + mmc->f_max = MAX_DWMMC_CLOCK; >>>>> + >>>>> + exynos_pinmux_config(periph_id, >>>>> + bus_width == 8 ? PINMUX_FLAG_8BIT_MODE : 0); >>>>> + >>>>> + mmc_host->clock = 0; >>>>> + mmc_host->peripheral = periph_id; >>>>> + mmc_host->ioaddr = (void *)samsung_get_base_dwmmc(); >>>>> + mmc->b_max = 1; >>>>> + mmc_register(mmc); >>>>> + mmc->block_dev.removable = 1; >>>>> + debug("dwmmc: periph_id=%d, width=%d, ioaddr=%p\n", >>>>> + periph_id, bus_width, mmc_host->ioaddr); >>>>> + >>>>> + return 0; >>>>> +} >>>>> -- >>>>> 1.7.4.4 >>>>> >>>>> _______________________________________________ >>>>> U-Boot mailing list >>>>> U-Boot@lists.denx.de >>>>> http://lists.denx.de/mailman/listinfo/u-boot >>>> _______________________________________________ >>>> U-Boot mailing list >>>> U-Boot@lists.denx.de >>>> http://lists.denx.de/mailman/listinfo/u-boot >>> >>> >>> >> >> > _______________________________________________ > U-Boot mailing list > U-Boot@lists.denx.de > http://lists.denx.de/mailman/listinfo/u-boot > _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot