mmc: use sdhci.c intead of s5p_mmc.c
Subsystems (3)
PATCH v3 2/3 mmc: use sdhci.c intead of s5p_mmc.c
In driver mmc, generic sdhci code is implemented.s5p_mmc file is dupulicated.
we are good that use the generic sdhci.
This patch supported the sdhci for Samsung-SoC.
--- arch/arm/include/asm/arch-exynos/mmc.h | 93 +++--- arch/arm/include/asm/arch-s5pc1xx/mmc.h | 93 +++--- drivers/mmc/Makefile | 2 +- drivers/mmc/s5p_mmc.c | 490 ------------------------------- drivers/mmc/s5p_sdhci.c | 98 ++++++ drivers/mmc/sdhci.c | 12 + include/sdhci.h | 6 + 7 files changed, 211 insertions(+), 583 deletions(-) delete mode 100644 drivers/mmc/s5p_mmc.c create mode 100644 drivers/mmc/s5p_sdhci.c
arch/arm/include/asm/arch-exynos/mmc.h +47 -46
@@ -21,53 +21,54 @@#ifndef __ASM_ARCH_MMC_H_#define __ASM_ARCH_MMC_H_ -#ifndef __ASSEMBLY__ -struct s5p_mmc { -unsigned int sysad; -unsigned short blksize; -unsigned short blkcnt; -unsigned int argument; -unsigned short trnmod; -unsigned short cmdreg; -unsigned int rspreg0; -unsigned int rspreg1; -unsigned int rspreg2; -unsigned int rspreg3; -unsigned int bdata; -unsigned int prnsts; -unsigned char hostctl; -unsigned char pwrcon; -unsigned char blkgap; -unsigned char wakcon; -unsigned short clkcon; -unsigned char timeoutcon; -unsigned char swrst; -unsigned int norintsts;/* errintsts */ -unsigned int norintstsen;/* errintstsen */ -unsigned int norintsigen;/* errintsigen */ -unsigned short acmd12errsts; -unsigned char res1[2 ]; -unsigned int capareg; -unsigned char res2[4 ]; -unsigned int maxcurr; -unsigned char res3[0x34 ]; -unsigned int control2; -unsigned int control3; -unsigned char res4[4 ]; -unsigned int control4; -unsigned char res5[0x6e ]; -unsigned short hcver; -unsigned char res6[0xFF00 ]; -}; +#define SDHCI_CONTROL2 0x80 +#define SDHCI_CONTROL3 0x84 +#define SDHCI_CONTROL4 0x8C -struct mmc_host { -struct s5p_mmc *reg; -unsigned int version;/* SDHCI spec. version */ -unsigned int clock;/* Current clock (MHz) */ -int dev_index; -}; +#define SDHCI_CTRL2_ENSTAASYNCCLR (1 << 31) +#define SDHCI_CTRL2_ENCMDCNFMSK (1 << 30) +#define SDHCI_CTRL2_CDINVRXD3 (1 << 29) +#define SDHCI_CTRL2_SLCARDOUT (1 << 28) -int s5p_mmc_init (int dev_index,int bus_width); +#define SDHCI_CTRL2_FLTCLKSEL_MASK (0xf << 24) +#define SDHCI_CTRL2_FLTCLKSEL_SHIFT (24) +#define SDHCI_CTRL2_FLTCLKSEL (_x) ((_x) << 24) -#endif /* __ASSEMBLY__ */ +#define SDHCI_CTRL2_LVLDAT_MASK (0xff << 16) +#define SDHCI_CTRL2_LVLDAT_SHIFT (16) +#define SDHCI_CTRL2_LVLDAT (_x) ((_x) << 16) + +#define SDHCI_CTRL2_ENFBCLKTX (1 << 15) +#define SDHCI_CTRL2_ENFBCLKRX (1 << 14) +#define SDHCI_CTRL2_SDCDSEL (1 << 13) +#define SDHCI_CTRL2_SDSIGPC (1 << 12) +#define SDHCI_CTRL2_ENBUSYCHKTXSTART (1 << 11) + +#define SDHCI_CTRL2_DFCNT_MASK (_x) ((_x) << 9) +#define SDHCI_CTRL2_DFCNT_SHIFT (9) + +#define SDHCI_CTRL2_ENCLKOUTHOLD (1 << 8) +#define SDHCI_CTRL2_RWAITMODE (1 << 7) +#define SDHCI_CTRL2_DISBUFRD (1 << 6) +#define SDHCI_CTRL2_SELBASECLK_MASK (_x) ((_x) << 4) +#define SDHCI_CTRL2_SELBASECLK_SHIFT (4) +#define SDHCI_CTRL2_PWRSYNC (1 << 3) +#define SDHCI_CTRL2_ENCLKOUTMSKCON (1 << 1) +#define SDHCI_CTRL2_HWINITFIN (1 << 0) + +#define SDHCI_CTRL3_FCSEL3 (1 << 31) +#define SDHCI_CTRL3_FCSEL2 (1 << 23) +#define SDHCI_CTRL3_FCSEL1 (1 << 15) +#define SDHCI_CTRL3_FCSEL0 (1 << 7) + +#define SDHCI_CTRL4_DRIVE_MASK (_x) ((_x) << 16) +#define SDHCI_CTRL4_DRIVE_SHIFT (16) + +int s5p_sdhci_init (u32 regbase,u32 max_clk,u32 min_clk,u32 quirks); + +static inline unsigned int s5p_mmc_init (int index,int bus_width) +{ +unsigned int base =samsung_get_base_mmc () + (0x10000 * index); +return s5p_sdhci_init (base,52000000 ,400000 , index); +}#endif
arch/arm/include/asm/arch-s5pc1xx/mmc.h +47 -46
100 lines not on this page · raw message
drivers/mmc/Makefile +1 -1
@@ -39,8 +39,8 @@ COBJS-$(CONFIG_MXS_MMC) += mxsmmc.o COBJS-$(CONFIG_OMAP_HSMMC) += omap_hsmmc.o COBJS-$(CONFIG_PXA_MMC) += pxa_mmc.o COBJS-$(CONFIG_PXA_MMC_GENERIC) += pxa_mmc_gen.o -COBJS-$(CONFIG_S5P_MMC) += s5p_mmc.o COBJS-$(CONFIG_SDHCI) += sdhci.o +COBJS-$(CONFIG_S5P_SDHCI) += s5p_sdhci.o COBJS-$(CONFIG_SH_MMCIF) += sh_mmcif.o COBJS-$(CONFIG_TEGRA2_MMC) += tegra2_mmc.o
drivers/mmc/s5p_mmc.c deleted +0 -490
490 lines not on this page · raw message
drivers/mmc/s5p_sdhci.c new file +98 -0
98 lines not on this page · raw message
drivers/mmc/sdhci.c +12 -0
@@ -337,6 +337,9 @@ void sdhci_set_ios(struct mmc *mmc)u32 ctrl;struct sdhci_host *host = (struct sdhci_host *)mmc->priv; +if (host->set_control_reg) + host->set_control_reg (host); +if (mmc->clock != host->clock)sdhci_set_clock (mmc, mmc->clock);
@@ -360,6 +363,9 @@ void sdhci_set_ios(struct mmc *mmc)else ctrl &= ~SDHCI_CTRL_HISPD ; +if (host->quirks &SDHCI_QUIRK_NO_HISPD_BIT ) + ctrl &= ~SDHCI_CTRL_HISPD ; +sdhci_writeb (host, ctrl,SDHCI_HOST_CONTROL ); }
@@ -443,9 +449,15 @@ int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk) mmc->voltages |=MMC_VDD_29_30 |MMC_VDD_30_31 ;if (caps &SDHCI_CAN_VDD_180 ) mmc->voltages |=MMC_VDD_165_195 ; + +if (host->quirks &SDHCI_QUIRK_BROKEN_VOLTAGE ) + mmc->voltages |= host->voltages; + mmc->host_caps =MMC_MODE_HS | MMC_MODE_HS_52MHz |MMC_MODE_4BIT ;if (caps &SDHCI_CAN_DO_8BIT ) mmc->host_caps |=MMC_MODE_8BIT ; +if (host->host_caps) + mmc->host_caps |= host->host_caps;sdhci_reset (host,SDHCI_RESET_ALL );mmc_register (mmc);
include/sdhci.h +6 -0
@@ -217,6 +217,8 @@#define SDHCI_QUIRK_32BIT_DMA_ADDR (1 << 0)#define SDHCI_QUIRK_REG32_RW (1 << 1)#define SDHCI_QUIRK_BROKEN_R1B (1 << 2) +#define SDHCI_QUIRK_NO_HISPD_BIT (1 << 3) +#define SDHCI_QUIRK_BROKEN_VOLTAGE (1 << 4)/* to make gcc happy */ struct sdhci_host ;
@@ -241,10 +243,14 @@ struct sdhci_host {char *name;void *ioaddr;unsigned int quirks; +unsigned int host_caps;unsigned int version;unsigned int clock;struct mmc *mmc;const struct sdhci_ops *ops; + +void (*set_control_reg)(struct sdhci_host *host); +uint voltages; };#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
A message that is not in the archive (sent off-list or not yet received): [email protected]
PATCH v3 2/3 mmc: use sdhci.c intead of s5p_mmc.c
Quoted 27 lines · Lei Wen
Hi Jaehoon,
Quoted 14 lines
-----Original Message-----
From: Jaehoon Chung [mailto:jh80.chung at samsung.com]
Sent: Monday, April 09, 2012 3:58 PM
To: u-boot at lists.denx.de; Andy Fleming; mk7.kang at samsung.com; Kyungmin Park; Lei Wen
Subject: [PATCH v3 2/3] mmc: usesdhci.cintead ofs5p_mmc.cIn driver mmc, generic sdhci code is implemented.
s5p_mmcfile is dupulicated.
we are good that use the generic sdhci.
This patch supported the sdhci for Samsung-SoC.Signed-off-by Jaehoon Chung <[email protected]>Signed-off-by Kyungmin Park <[email protected]>Quoted 9 lines
--- arch/arm/include/asm/arch-exynos/mmc.h | 93 +++--- arch/arm/include/asm/arch-s5pc1xx/mmc.h | 93 +++--- drivers/mmc/Makefile | 2 +- drivers/mmc/s5p_mmc.c | 490 ------------------------------- drivers/mmc/s5p_sdhci.c | 98 ++++++ drivers/mmc/sdhci.c | 12 + include/sdhci.h | 6 +
Quoted 2 lines
I think you'd better to separate the sdhci code change with other codes change. So that others could easily cherry pick your updated sdhci patches.
Ok..i will re-work and resend the patches.
Best Regards,
Jaehoon Chung
Quoted 904 lines
Thanks,
LeiQuoted 900 lines
7 files changed, 211 insertions(+), 583 deletions(-) delete mode 100644 drivers/mmc/s5p_mmc.c create mode 100644 drivers/mmc/s5p_sdhci.carch/arm/include/asm/arch-exynos/mmc.h +47
-46@@ -21,53 +21,54 @@#ifndef __ASM_ARCH_MMC_H_#define __ASM_ARCH_MMC_H_ -#ifndef __ASSEMBLY__ -struct s5p_mmc { -unsigned int sysad; -unsigned short blksize; -unsigned short blkcnt; -unsigned int argument; -unsigned short trnmod; -unsigned short cmdreg; -unsigned int rspreg0; -unsigned int rspreg1; -unsigned int rspreg2; -unsigned int rspreg3; -unsigned int bdata; -unsigned int prnsts; -unsigned char hostctl; -unsigned char pwrcon; -unsigned char blkgap; -unsigned char wakcon; -unsigned short clkcon; -unsigned char timeoutcon; -unsigned char swrst; -unsigned int norintsts;/* errintsts */ -unsigned int norintstsen;/* errintstsen */ -unsigned int norintsigen;/* errintsigen */ -unsigned short acmd12errsts; -unsigned char res1[2 ]; -unsigned int capareg; -unsigned char res2[4 ]; -unsigned int maxcurr; -unsigned char res3[0x34 ]; -unsigned int control2; -unsigned int control3; -unsigned char res4[4 ]; -unsigned int control4; -unsigned char res5[0x6e ]; -unsigned short hcver; -unsigned char res6[0xFF00 ]; -}; +#define SDHCI_CONTROL2 0x80 +#define SDHCI_CONTROL3 0x84 +#define SDHCI_CONTROL4 0x8C -struct mmc_host { -struct s5p_mmc *reg; -unsigned int version;/* SDHCI spec. version */ -unsigned int clock;/* Current clock (MHz) */ -int dev_index; -}; +#define SDHCI_CTRL2_ENSTAASYNCCLR (1 << 31) +#define SDHCI_CTRL2_ENCMDCNFMSK (1 << 30) +#define SDHCI_CTRL2_CDINVRXD3 (1 << 29) +#define SDHCI_CTRL2_SLCARDOUT (1 << 28) -int s5p_mmc_init (int dev_index,int bus_width); +#define SDHCI_CTRL2_FLTCLKSEL_MASK (0xf << 24) +#define SDHCI_CTRL2_FLTCLKSEL_SHIFT (24) +#define SDHCI_CTRL2_FLTCLKSEL (_x) ((_x) << 24) -#endif /* __ASSEMBLY__ */ +#define SDHCI_CTRL2_LVLDAT_MASK (0xff << 16) +#define SDHCI_CTRL2_LVLDAT_SHIFT (16) +#define SDHCI_CTRL2_LVLDAT (_x) ((_x) << 16) + +#define SDHCI_CTRL2_ENFBCLKTX (1 << 15) +#define SDHCI_CTRL2_ENFBCLKRX (1 << 14) +#define SDHCI_CTRL2_SDCDSEL (1 << 13) +#define SDHCI_CTRL2_SDSIGPC (1 << 12) +#define SDHCI_CTRL2_ENBUSYCHKTXSTART (1 << 11) + +#define SDHCI_CTRL2_DFCNT_MASK (_x) ((_x) << 9) +#define SDHCI_CTRL2_DFCNT_SHIFT (9) + +#define SDHCI_CTRL2_ENCLKOUTHOLD (1 << 8) +#define SDHCI_CTRL2_RWAITMODE (1 << 7) +#define SDHCI_CTRL2_DISBUFRD (1 << 6) +#define SDHCI_CTRL2_SELBASECLK_MASK (_x) ((_x) << 4) +#define SDHCI_CTRL2_SELBASECLK_SHIFT (4) +#define SDHCI_CTRL2_PWRSYNC (1 << 3) +#define SDHCI_CTRL2_ENCLKOUTMSKCON (1 << 1) +#define SDHCI_CTRL2_HWINITFIN (1 << 0) + +#define SDHCI_CTRL3_FCSEL3 (1 << 31) +#define SDHCI_CTRL3_FCSEL2 (1 << 23) +#define SDHCI_CTRL3_FCSEL1 (1 << 15) +#define SDHCI_CTRL3_FCSEL0 (1 << 7) + +#define SDHCI_CTRL4_DRIVE_MASK (_x) ((_x) << 16) +#define SDHCI_CTRL4_DRIVE_SHIFT (16) + +int s5p_sdhci_init (u32 regbase,u32 max_clk,u32 min_clk,u32 quirks); + +static inline unsigned int s5p_mmc_init (int index,int bus_width) +{ +unsigned int base =samsung_get_base_mmc () + (0x10000 * index); +return s5p_sdhci_init (base,52000000 ,400000 , index); +}#endif arch/arm/include/asm/arch-s5pc1xx/mmc.h +47
-46@@ -21,53 +21,54 @@#ifndef __ASM_ARCH_MMC_H_#define __ASM_ARCH_MMC_H_ -#ifndef __ASSEMBLY__ -struct s5p_mmc { -unsigned int sysad; -unsigned short blksize; -unsigned short blkcnt; -unsigned int argument; -unsigned short trnmod; -unsigned short cmdreg; -unsigned int rspreg0; -unsigned int rspreg1; -unsigned int rspreg2; -unsigned int rspreg3; -unsigned int bdata; -unsigned int prnsts; -unsigned char hostctl; -unsigned char pwrcon; -unsigned char blkgap; -unsigned char wakcon; -unsigned short clkcon; -unsigned char timeoutcon; -unsigned char swrst; -unsigned int norintsts;/* errintsts */ -unsigned int norintstsen;/* errintstsen */ -unsigned int norintsigen;/* errintsigen */ -unsigned short acmd12errsts; -unsigned char res1[2 ]; -unsigned int capareg; -unsigned char res2[4 ]; -unsigned int maxcurr; -unsigned char res3[0x34 ]; -unsigned int control2; -unsigned int control3; -unsigned char res4[4 ]; -unsigned int control4; -unsigned char res5[0x6e ]; -unsigned short hcver; -unsigned char res6[0xFFF00 ]; -}; +#define SDHCI_CONTROL2 0x80 +#define SDHCI_CONTROL3 0x84 +#define SDHCI_CONTROL4 0x8C -struct mmc_host { -struct s5p_mmc *reg; -unsigned int version;/* SDHCI spec. version */ -unsigned int clock;/* Current clock (MHz) */ -int dev_index; -}; +#define SDHCI_CTRL2_ENSTAASYNCCLR (1 << 31) +#define SDHCI_CTRL2_ENCMDCNFMSK (1 << 30) +#define SDHCI_CTRL2_CDINVRXD3 (1 << 29) +#define SDHCI_CTRL2_SLCARDOUT (1 << 28) -int s5p_mmc_init (int dev_index,int bus_width); +#define SDHCI_CTRL2_FLTCLKSEL_MASK (0xf << 24) +#define SDHCI_CTRL2_FLTCLKSEL_SHIFT (24) +#define SDHCI_CTRL2_FLTCLKSEL (_x) ((_x) << 24) -#endif /* __ASSEMBLY__ */ +#define SDHCI_CTRL2_LVLDAT_MASK (0xff << 16) +#define SDHCI_CTRL2_LVLDAT_SHIFT (16) +#define SDHCI_CTRL2_LVLDAT (_x) ((_x) << 16) + +#define SDHCI_CTRL2_ENFBCLKTX (1 << 15) +#define SDHCI_CTRL2_ENFBCLKRX (1 << 14) +#define SDHCI_CTRL2_SDCDSEL (1 << 13) +#define SDHCI_CTRL2_SDSIGPC (1 << 12) +#define SDHCI_CTRL2_ENBUSYCHKTXSTART (1 << 11) + +#define SDHCI_CTRL2_DFCNT_MASK (_x) ((_x) << 9) +#define SDHCI_CTRL2_DFCNT_SHIFT (9) + +#define SDHCI_CTRL2_ENCLKOUTHOLD (1 << 8) +#define SDHCI_CTRL2_RWAITMODE (1 << 7) +#define SDHCI_CTRL2_DISBUFRD (1 << 6) +#define SDHCI_CTRL2_SELBASECLK_MASK (_x) ((_x) << 4) +#define SDHCI_CTRL2_SELBASECLK_SHIFT (4) +#define SDHCI_CTRL2_PWRSYNC (1 << 3) +#define SDHCI_CTRL2_ENCLKOUTMSKCON (1 << 1) +#define SDHCI_CTRL2_HWINITFIN (1 << 0) + +#define SDHCI_CTRL3_FCSEL3 (1 << 31) +#define SDHCI_CTRL3_FCSEL2 (1 << 23) +#define SDHCI_CTRL3_FCSEL1 (1 << 15) +#define SDHCI_CTRL3_FCSEL0 (1 << 7) + +#define SDHCI_CTRL4_DRIVE_MASK (_x) ((_x) << 16) +#define SDHCI_CTRL4_DRIVE_SHIFT (16) + +int s5p_sdhci_init (u32 regbase,u32 max_clk,u32 min_clk,u32 quirks); + +static inline unsigned int s5p_mmc_init (int index,int bus_width) +{ +unsigned int base =samsung_get_base_mmc () + (0x10000 * index); +return s5p_sdhci_init (base,52000000 ,400000 , index); +}#endif drivers/mmc/Makefile +1
-1@@ -39,8 +39,8 @@ COBJS-$(CONFIG_MXS_MMC) += mxsmmc.o COBJS-$(CONFIG_OMAP_HSMMC) += omap_hsmmc.o COBJS-$(CONFIG_PXA_MMC) += pxa_mmc.o COBJS-$(CONFIG_PXA_MMC_GENERIC) += pxa_mmc_gen.o -COBJS-$(CONFIG_S5P_MMC) += s5p_mmc.o COBJS-$(CONFIG_SDHCI) += sdhci.o +COBJS-$(CONFIG_S5P_SDHCI) += s5p_sdhci.o COBJS-$(CONFIG_SH_MMCIF) += sh_mmcif.o COBJS-$(CONFIG_TEGRA2_MMC) += tegra2_mmc.odrivers/mmc/s5p_mmc.c deleted +0
-59@@ -1,490 +0,0 @@ -/* -* (C) Copyright 2009 SAMSUNG Electronics -* Minkyu Kang <[email protected]> -* Jaehoon Chung <[email protected]> -* -* 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/io.h> -#include <asm/arch/mmc.h> -#include <asm/arch/clk.h> - -/* support 4 mmc hosts */ -struct mmc mmc_dev[4 ]; -struct mmc_host mmc_host[4 ]; - -static inline struct s5p_mmc *s5p_get_base_mmc (int dev_index) -{ -unsigned long offset = dev_index *sizeof (struct s5p_mmc ); -return (struct s5p_mmc *)(samsung_get_base_mmc () + offset); -} - -static void mmc_prepare_data (struct mmc_host *host,struct mmc_data *data) -{ -unsigned char ctrl; - -debug ("data->dest: %08x\n" , (u32 )data->dest); -writel ((u32 )data->dest, &host->reg->sysad); -/* -* DMASEL[4:3] -* 00 = Selects SDMA -* 01 = Reserved -* 10 = Selects 32-bit Address ADMA2 -* 11 = Selects 64-bit Address ADMA2 -*/ - ctrl =readb (&host->reg->hostctl); - ctrl &= ~(3 <<3 ); -writeb (ctrl, &host->reg->hostctl); - -/* We do not handle DMA boundaries, so set it to max (512 KiB) */ -writew ((7 <<12 ) | (data->blocksize &0xFFF ), &host->reg->blksize); -writew (data->blocks, &host->reg->blkcnt); -} - -static void mmc_set_transfer_mode(struct mmc_host *host, struct mmc_data*data)
drivers/mmc/s5p_mmc.c deleted +0
-431-{ -unsigned short mode; - -/* -* TRNMOD -* MUL1SIN0[5] : Multi/Single Block Select -* RD1WT0[4] : Data Transfer Direction Select -* 1 = read -* 0 = write -* ENACMD12[2] : Auto CMD12 Enable -* ENBLKCNT[1] : Block Count Enable -* ENDMA[0] : DMA Enable -*/ - mode = (1 <<1 ) | (1 <<0 ); -if (data->blocks >1 ) - mode |= (1 <<5 ); -if (data->flags &MMC_DATA_READ ) - mode |= (1 <<4 ); - -writew (mode, &host->reg->trnmod); -} - -static int mmc_send_cmd (struct mmc *mmc,struct mmc_cmd *cmd, -struct mmc_data *data) -{ -struct mmc_host *host = (struct mmc_host *)mmc->priv; -int flags, i; -unsigned int timeout; -unsigned int mask; -unsigned int retry =0x100000 ; - -/* Wait max 10 ms */ - timeout =10 ; - -/* -* PRNSTS -* CMDINHDAT[1] : Command Inhibit (DAT) -* CMDINHCMD[0] : Command Inhibit (CMD) -*/ - mask = (1 <<0 ); -if ((data !=NULL ) || (cmd->resp_type &MMC_RSP_BUSY )) - mask |= (1 <<1 ); - -/* -* We shouldn't wait for data inihibit for stop commands, even -* though they might use busy signaling -*/ -if (data) - mask &= ~(1 <<1 ); - -while (readl (&host->reg->prnsts) & mask) { -if (timeout ==0 ) { -printf ("%s: timeout error\n" , __func__); -return -1 ; - } - timeout--; -udelay (1000 ); - } - -if (data) -mmc_prepare_data (host, data); - -debug ("cmd->arg: %08x\n" , cmd->cmdarg); -writel (cmd->cmdarg, &host->reg->argument); - -if (data) -mmc_set_transfer_mode (host, data); - -if ((cmd->resp_type &MMC_RSP_136 ) && (cmd->resp_type &MMC_RSP_BUSY )) -return -1 ; - -/* -* CMDREG -* CMDIDX[13:8] : Command index -* DATAPRNT[5] : Data Present Select -* ENCMDIDX[4] : Command Index Check Enable -* ENCMDCRC[3] : Command CRC Check Enable -* RSPTYP[1:0] -* 00 = No Response -* 01 = Length 136 -* 10 = Length 48 -* 11 = Length 48 Check busy after response -*/ -if (!(cmd->resp_type &MMC_RSP_PRESENT )) - flags =0 ; -else if (cmd->resp_type &MMC_RSP_136 ) - flags = (1 <<0 ); -else if (cmd->resp_type &MMC_RSP_BUSY ) - flags = (3 <<0 ); -else - flags = (2 <<0 ); - -if (cmd->resp_type &MMC_RSP_CRC ) - flags |= (1 <<3 ); -if (cmd->resp_type &MMC_RSP_OPCODE ) - flags |= (1 <<4 ); -if (data) - flags |= (1 <<5 ); - -debug ("cmd: %d\n" , cmd->cmdidx); - -writew ((cmd->cmdidx <<8 ) | flags, &host->reg->cmdreg); - -for (i =0 ; i < retry; i++) { - mask =readl (&host->reg->norintsts); -/* Command Complete */ -if (mask & (1 <<0 )) { -if (!data) -writel (mask, &host->reg->norintsts); -break ; - } - } - -if (i == retry) { -printf ("%s: waiting for status update\n" , __func__); -return TIMEOUT ; - } - -if (mask & (1 <<16 )) { -/* Timeout Error */ -debug ("timeout: %08x cmd %d\n" , mask, cmd->cmdidx); -return TIMEOUT ; - }else if (mask & (1 <<15 )) { -/* Error Interrupt */ -debug ("error: %08x 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. */ -for (i =0 ; i <4 ; i++) { -unsigned int offset = - (unsigned int )(&host->reg->rspreg3 - i); - cmd->response[i] =readl (offset) <<8 ; - -if (i !=3 ) { - cmd->response[i] |= -readb (offset -1 ); - } -debug ("cmd->resp[%d]: %08x\n" , - i, cmd->response[i]); - } - }else if (cmd->resp_type &MMC_RSP_BUSY ) { -for (i =0 ; i < retry; i++) { -/* PRNTDATA[23:20] : DAT[3:0] Line Signal */ -if (readl (&host->reg->prnsts) - & (1 <<20 ))/* DAT[0] */ -break ; - } - -if (i == retry) { -printf ("%s: card is still busy\n" , __func__); -return TIMEOUT ; - } - - cmd->response[0 ] =readl (&host->reg->rspreg0); -debug ("cmd->resp[0]: %08x\n" , cmd->response[0 ]); - }else { - cmd->response[0 ] =readl (&host->reg->rspreg0); -debug ("cmd->resp[0]: %08x\n" , cmd->response[0 ]); - } - } - -if (data) { -while (1 ) { - mask =readl (&host->reg->norintsts); - -if (mask & (1 <<15 )) { -/* Error Interrupt */ -writel (mask, &host->reg->norintsts); -printf ("%s: error during transfer: 0x%08x\n" , - __func__, mask); -return -1 ; - }else if (mask & (1 <<3 )) { -/* -* DMA Interrupt, restart the transfer where -* it was interrupted. -*/ -unsigned int address =readl (&host->reg->sysad); - -debug ("DMA end\n" ); -writel ((1 <<3 ), &host->reg->norintsts); -writel (address, &host->reg->sysad); - }else if (mask & (1 <<1 )) { -/* Transfer Complete */ -debug ("r/w is done\n" ); -break ; - } - } -writel (mask, &host->reg->norintsts); - } - -udelay (1000 ); -return 0 ; -} - -static void mmc_change_clock (struct mmc_host *host,uint clock) -{ -int div; -unsigned short clk; -unsigned long timeout; -unsigned long ctrl2; - -/* -* SELBASECLK[5:4] -* 00/01 = HCLK -* 10 = EPLL -* 11 = XTI or XEXTCLK -*/ - ctrl2 =readl (&host->reg->control2); - ctrl2 &= ~(3 <<4 ); - ctrl2 |= (2 <<4 ); -writel (ctrl2, &host->reg->control2); - -writew (0 , &host->reg->clkcon); - -/* XXX: we assume that clock is between 40MHz and 50MHz */ -if (clock ==0 ) - goto out; -else if (clock <=400000 ) - div =0x100 ; -else if (clock <=20000000 ) - div =4 ; -else if (clock <=26000000 ) - div =2 ; -else - div =1 ; -debug ("div: %d\n" , div); - - div >>=1 ; -/* -* CLKCON -* SELFREQ[15:8] : base clock divied by value -* ENSDCLK[2] : SD Clock Enable -* STBLINTCLK[1] : Internal Clock Stable -* ENINTCLK[0] : Internal Clock Enable -*/ - clk = (div <<8 ) | (1 <<0 ); -writew (clk, &host->reg->clkcon); - -set_mmc_clk (host->dev_index, div); - -/* Wait max 10 ms */ - timeout =10 ; -while (!(readw (&host->reg->clkcon) & (1 <<1 ))) { -if (timeout ==0 ) { -printf ("%s: timeout error\n" , __func__); -return ; - } - timeout--; -udelay (1000 ); - } - - clk |= (1 <<2 ); -writew (clk, &host->reg->clkcon); - -out: - host->clock = clock; -} - -static void mmc_set_ios (struct mmc *mmc) -{ -struct mmc_host *host = mmc->priv; -unsigned char ctrl; -unsigned long val; - -debug ("bus_width: %x, clock: %d\n" , mmc->bus_width, mmc->clock); - -/* -* SELCLKPADDS[17:16] -* 00 = 2mA -* 01 = 4mA -* 10 = 7mA -* 11 = 9mA -*/ -writel (0x3 <<16 , &host->reg->control4); - - val =readl (&host->reg->control2); - val &= (0x3 <<4 ); - - val |= (1 <<31 ) |/* write status clear async mode enable */ - (1 <<30 ) |/* command conflict mask enable */ - (1 <<14 ) |/* Feedback Clock Enable for Rx Clock */ - (1 <<8 );/* SDCLK hold enable */ - -writel (val, &host->reg->control2); - -/* -* FCSEL1[15] FCSEL0[7] -* FCSel[1:0] : Rx Feedback Clock Delay Control -* Inverter delay means10ns delay if SDCLK 50MHz setting -* 01 = Delay1 (basic delay) -* 11 = Delay2 (basic delay + 2ns) -* 00 = Delay3 (inverter delay) -* 10 = Delay4 (inverter delay + 2ns) -*/ -writel (0x8080 , &host->reg->control3); - -mmc_change_clock (host, mmc->clock); - - ctrl =readb (&host->reg->hostctl); - -/* -* WIDE8[5] -* 0 = Depend on WIDE4 -* 1 = 8-bit mode -* WIDE4[1] -* 1 = 4-bit mode -* 0 = 1-bit mode -*/ -if (mmc->bus_width ==8 ) - ctrl |= (1 <<5 ); -else if (mmc->bus_width ==4 ) - ctrl |= (1 <<1 ); -else - ctrl &= ~(1 <<1 ); - -/* -* OUTEDGEINV[2] -* 1 = Riging edge output -* 0 = Falling edge output -*/ - ctrl &= ~(1 <<2 ); - -writeb (ctrl, &host->reg->hostctl); -} - -static void mmc_reset (struct mmc_host *host) -{ -unsigned int timeout; - -/* -* RSTALL[0] : Software reset for all -* 1 = reset -* 0 = work -*/ -writeb ((1 <<0 ), &host->reg->swrst); - - host->clock =0 ; - -/* Wait max 100 ms */ - timeout =100 ; - -/* hw clears the bit when it's done */ -while (readb (&host->reg->swrst) & (1 <<0 )) { -if (timeout ==0 ) { -printf ("%s: timeout error\n" , __func__); -return ; - } - timeout--; -udelay (1000 ); - } -} - -static int mmc_core_init (struct mmc *mmc) -{ -struct mmc_host *host = (struct mmc_host *)mmc->priv; -unsigned int mask; - -mmc_reset (host); - - host->version =readw (&host->reg->hcver); - -/* mask all */ -writel (0xffffffff , &host->reg->norintstsen); -writel (0xffffffff , &host->reg->norintsigen); - -writeb (0xe , &host->reg->timeoutcon);/* TMCLK * 2^27 */ - -/* -* NORMAL Interrupt Status Enable Register init -* [5] ENSTABUFRDRDY : Buffer Read Ready Status Enable -* [4] ENSTABUFWTRDY : Buffer write Ready Status Enable -* [3] ENSTADMAINT : DMA Interrupt Status Enable -* [1] ENSTASTANSCMPLT : Transfre Complete Status Enable -* [0] ENSTACMDCMPLT : Command Complete Status Enable -*/ - mask =readl (&host->reg->norintstsen); - mask &= ~(0xffff ); - mask |= (1 <<5 ) | (1 <<4 ) | (1 <<3 ) | (1 <<1 ) | (1 <<0 ); -writel (mask, &host->reg->norintstsen); - -/* -* NORMAL Interrupt Signal Enable Register init -* [1] ENSTACMDCMPLT : Transfer Complete Signal Enable -*/ - mask =readl (&host->reg->norintsigen); - mask &= ~(0xffff ); - mask |= (1 <<1 ); -writel (mask, &host->reg->norintsigen); - -return 0 ; -} - -static int s5p_mmc_initialize (int dev_index,int bus_width) -{ -struct mmc *mmc; - - mmc = &mmc_dev[dev_index]; - -sprintf (mmc->name,"SAMSUNG SD/MMC" ); - mmc->priv = &mmc_host[dev_index]; - mmc->send_cmd = mmc_send_cmd; - mmc->set_ios = mmc_set_ios; - mmc->init = mmc_core_init; - mmc->getcd =NULL ; - - mmc->voltages =MMC_VDD_32_33 |MMC_VDD_33_34 |MMC_VDD_165_195 ; -if (bus_width ==8 ) - mmc->host_caps =MMC_MODE_8BIT ; -else - mmc->host_caps =MMC_MODE_4BIT ; - mmc->host_caps |= MMC_MODE_HS_52MHz |MMC_MODE_HS |MMC_MODE_HC ; - - mmc->f_min =400000 ; - mmc->f_max =52000000 ; - - mmc_host[dev_index].dev_index = dev_index; - mmc_host[dev_index].clock =0 ; - mmc_host[dev_index].reg =s5p_get_base_mmc (dev_index); - mmc->b_max =0 ; -mmc_register (mmc); - -return 0 ; -} - -int s5p_mmc_init (int dev_index,int bus_width) -{ -return s5p_mmc_initialize (dev_index, bus_width); -}drivers/mmc/s5p_sdhci.c new file +98
-0@@ -0,0 +1,98 @@ +/* +* (C) Copyright 2012 SAMSUNG Electronics +* Jaehoon Chung <[email protected]> +* +* 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 <malloc.h> +#include <sdhci.h> +#include <asm/arch/mmc.h> + +static char *S5P_NAME ="SAMSUNG SDHCI" ; +static void s5p_sdhci_set_control_reg (struct sdhci_host *host) +{ +unsigned long val, ctrl; +/* +* SELCLKPADDS[17:16] +* 00 = 2mA +* 01 = 4mA +* 10 = 7mA +* 11 = 9mA +*/ +sdhci_writel (host,SDHCI_CTRL4_DRIVE_MASK (0x3 ),SDHCI_CONTROL4 ); + + val =sdhci_readl (host,SDHCI_CONTROL2 ); + val &=SDHCI_CTRL2_SELBASECLK_SHIFT ; + + val |=SDHCI_CTRL2_ENSTAASYNCCLR | +SDHCI_CTRL2_ENCMDCNFMSK | +SDHCI_CTRL2_ENFBCLKRX | +SDHCI_CTRL2_ENCLKOUTHOLD ; + +sdhci_writel (host, val,SDHCI_CONTROL2 ); + +/* +* FCSEL3[31] FCSEL2[23] FCSEL1[15] FCSEL0[7] +* FCSel[1:0] : Rx Feedback Clock Delay Control +* Inverter delay means10ns delay if SDCLK 50MHz setting +* 01 = Delay1 (basic delay) +* 11 = Delay2 (basic delay + 2ns) +* 00 = Delay3 (inverter delay) +* 10 = Delay4 (inverter delay + 2ns) +*/ + val =SDHCI_CTRL3_FCSEL3 |SDHCI_CTRL3_FCSEL1 ; +sdhci_writel (host, val,SDHCI_CONTROL3 ); + +/* +* SELBASECLK[5:4] +* 00/01 = HCLK +* 10 = EPLL +* 11 = XTI or XEXTCLK +*/ + ctrl =sdhci_readl (host,SDHCI_CONTROL2 ); + ctrl &= ~SDHCI_CTRL2_SELBASECLK_MASK (0x3 ); + ctrl |=SDHCI_CTRL2_SELBASECLK_MASK (0x2 ); +sdhci_writel (host, ctrl,SDHCI_CONTROL2 ); +} + +int s5p_sdhci_init (u32 regbase,u32 max_clk,u32 min_clk,u32 quirks) +{ +struct sdhci_host *host =NULL ; + host = (struct sdhci_host *)malloc (sizeof (struct sdhci_host )); +if (!host) { +printf ("sdhci__host malloc fail!\n" ); +return 1 ; + } + + host->name =S5P_NAME ; + host->ioaddr = (void *)regbase; + host->quirks = quirks; + + host->quirks |=SDHCI_QUIRK_NO_HISPD_BIT |SDHCI_QUIRK_BROKEN_VOLTAGE ; + host->voltages =MMC_VDD_32_33 |MMC_VDD_33_34 |MMC_VDD_165_195 ; +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 ); + + host->set_control_reg = &s5p_sdhci_set_control_reg; + + host->host_caps =MMC_MODE_HC ; + +add_sdhci (host, max_clk, min_clk); +return 0 ; +}drivers/mmc/sdhci.c +12
-0@@ -337,6 +337,9 @@ void sdhci_set_ios(struct mmc *mmc)u32 ctrl;struct sdhci_host *host = (struct sdhci_host *)mmc->priv; +if (host->set_control_reg) + host->set_control_reg (host); +if (mmc->clock != host->clock)sdhci_set_clock (mmc, mmc->clock);@@ -360,6 +363,9 @@ void sdhci_set_ios(struct mmc *mmc)else ctrl &= ~SDHCI_CTRL_HISPD ; +if (host->quirks &SDHCI_QUIRK_NO_HISPD_BIT ) + ctrl &= ~SDHCI_CTRL_HISPD ; +sdhci_writeb (host, ctrl,SDHCI_HOST_CONTROL ); }@@ -443,9 +449,15 @@ int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk) mmc->voltages |= MMC_VDD_29_30 | MMC_VDD_30_31;if (caps &SDHCI_CAN_VDD_180 ) mmc->voltages |=MMC_VDD_165_195 ; + +if (host->quirks &SDHCI_QUIRK_BROKEN_VOLTAGE ) + mmc->voltages |= host->voltages; + mmc->host_caps =MMC_MODE_HS | MMC_MODE_HS_52MHz |MMC_MODE_4BIT ;if (caps &SDHCI_CAN_DO_8BIT ) mmc->host_caps |=MMC_MODE_8BIT ; +if (host->host_caps) + mmc->host_caps |= host->host_caps;sdhci_reset (host,SDHCI_RESET_ALL );mmc_register(mmc);include/sdhci.h +6
-0@@ -217,6 +217,8 @@#define SDHCI_QUIRK_32BIT_DMA_ADDR (1 << 0)#define SDHCI_QUIRK_REG32_RW (1 << 1)#define SDHCI_QUIRK_BROKEN_R1B (1 << 2) +#define SDHCI_QUIRK_NO_HISPD_BIT (1 << 3) +#define SDHCI_QUIRK_BROKEN_VOLTAGE (1 << 4)/* to make gcc happy */ struct sdhci_host ;@@ -241,10 +243,14 @@ struct sdhci_host {char *name;void *ioaddr;unsigned int quirks; +unsigned int host_caps;unsigned int version;unsigned int clock;struct mmc *mmc;const struct sdhci_ops *ops; + +void (*set_control_reg)(struct sdhci_host *host); +uint voltages; };#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS