mmc: code cleanup and support DDR mode
Subsystems (3)
v2 cover mmc: code cleanup and support DDR mode
If card and host are supported DDR mode, then it can be used the DDR mode. This patch-set has dependency about beomho's patch-set. (Based-on u-boot-samsung repository)
http://patchwork.ozlabs.org/patch/331986/
http://patchwork.ozlabs.org/patch/331987/
http://patchwork.ozlabs.org/patch/331989/
http://patchwork.ozlabs.org/patch/331988/
It's result for loading image.
sdhci controller ->5260488 bytes read in 259 ms (19.4 MiB/s) dwmmc controller without DDR mode -> 5260488 bytes read in 202 ms (24.8 MiB/s) dwmmc controller with DDR mode -> 5260488 bytes read in 118 ms (42.5 MiB/s)
Download the 400M image with lthor.
sdhci controller -> 59.4sec (Avg 6.95 MB/s)
dwmmc controller without DDR mode -> 61.6sec (Avg 6.72MB/s) dwmmc controller with DDR mode -> 60.4sec (Avg 6.85MB/s)
Jaehoon Chung (10):
mmc: s5p_sdhci: add the s5p_sdhci_core_init function
ARM: exynos: board: change the mmc/sd init sequence
ARM: exynos: clock: modify the set_mmc_clk for exynos4
mmc: exynos_dw_mmc: restore the property into host
mmc: remove the unnecessary define and fix the wrong bit control
mmc: support the DDR mode for eMMC
mmc: dw_mmc: support the DDR mode
ARM: dts: exnyos: enable dw-mmc controller
mmc: exynos_dw_mmc: enable the DDR mode
ARM: exynos4: enable the dwmmc configuration
arch/arm/cpu/armv7/exynos/clock.c | 16 ++- arch/arm/dts/exynos4412-trats2.dts | 6 +- arch/arm/include/asm/arch-exynos/clk.h | 5 + board/samsung/common/board.c | 13 +- drivers/mmc/dw_mmc.c | 10 +- drivers/mmc/exynos_dw_mmc.c | 221 ++++++++++++++++++++------------ drivers/mmc/mmc.c | 16 ++- drivers/mmc/s5p_sdhci.c | 42 +++--- include/configs/exynos4-dt.h | 3 + include/dwmmc.h | 5 + include/mmc.h | 25 ++-- 11 files changed, 225 insertions(+), 137 deletions(-)
Signature · 1 line
1.7.9.5
PATCH v2 1/10 mmc: s5p_sdhci: add the s5p_sdhci_core_init function
To reuse the code, added the s5p_sdhci_core_init function. Before applied this patch, didn't use the 8-bit mode at exynos baord. Because it didn't set "MMC_MODE_8BIT".
--- drivers/mmc/s5p_sdhci.c | 42 +++++++++++++++++------------------------- 1 file changed, 17 insertions(+), 25 deletions(-)
drivers/mmc/s5p_sdhci.c +17 -25
@@ -65,17 +65,9 @@ static void s5p_sdhci_set_control_reg(struct sdhci_host *host)sdhci_writel (host, ctrl,SDHCI_CONTROL2 ); } -int s5p_sdhci_init (u32 regbase,int index,int bus_width) +static int s5p_sdhci_core_init (struct sdhci_host *host) { -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 =SDHCI_QUIRK_NO_HISPD_BIT |SDHCI_QUIRK_BROKEN_VOLTAGE | SDHCI_QUIRK_BROKEN_R1B | SDHCI_QUIRK_32BIT_DMA_ADDR |
@@ -85,15 +77,28 @@ int s5p_sdhci_init(u32 regbase, int index, int bus_width) host->set_control_reg = &s5p_sdhci_set_control_reg; host->set_clock = set_mmc_clk; - host->index = index; host->host_caps =MMC_MODE_HC ; -if (bus_width ==8 ) +if (host->bus_width ==8 ) host->host_caps |=MMC_MODE_8BIT ;return add_sdhci (host,52000000 ,400000 ); } +int s5p_sdhci_init (u32 regbase,int index,int bus_width) +{ +struct sdhci_host *host =malloc (sizeof (struct sdhci_host )); +if (!host) { +printf ("sdhci__host malloc fail!\n" ); +return 1 ; + } + host->ioaddr = (void *)regbase; + host->index = index; + host->bus_width = bus_width; + +return s5p_sdhci_core_init (host); +} +#ifdef CONFIG_OF_CONTROL struct sdhci_host sdhci_host[SDHCI_MAX_HOSTS ];
@@ -126,20 +131,7 @@ static int do_sdhci_init(struct sdhci_host *host) } } - host->name =S5P_NAME ; - - host->quirks =SDHCI_QUIRK_NO_HISPD_BIT |SDHCI_QUIRK_BROKEN_VOLTAGE | -SDHCI_QUIRK_BROKEN_R1B |SDHCI_QUIRK_32BIT_DMA_ADDR | -SDHCI_QUIRK_WAIT_SEND_CMD ; - host->voltages =MMC_VDD_32_33 |MMC_VDD_33_34 |MMC_VDD_165_195 ; - host->version =sdhci_readw (host,SDHCI_HOST_VERSION ); - - host->set_control_reg = &s5p_sdhci_set_control_reg; - host->set_clock = set_mmc_clk; - - host->host_caps =MMC_MODE_HC ; - -return add_sdhci (host,52000000 ,400000 ); +return s5p_sdhci_core_init (host); }static int sdhci_get_config (const void *blob,int node,struct sdhci_host *host)
Signature · 1 line
1.7.9.5
PATCH v2 2/10 ARM: exynos: board: change the mmc/sd init sequence
In reply to Jaehoon ChungExynos4 can be used the dwmmc controller for eMMC. Then it needs to check dwmmc_init() at first.
--- board/samsung/common/board.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-)
board/samsung/common/board.c +6 -7
@@ -243,13 +243,6 @@ int board_eth_init(bd_t *bis)int board_mmc_init (bd_t *bis) {int ret; - -#ifdef CONFIG_SDHCI -/* mmc initializattion for available channels */ - ret =exynos_mmc_init (gd->fdt_blob); -if (ret) -debug ("mmc init failed\n" ); -#endif #ifdef CONFIG_DWMMC /* dwmmc initializattion for available channels */ ret =exynos_dwmmc_init (gd->fdt_blob);
@@ -257,6 +250,12 @@ int board_mmc_init(bd_t *bis)debug ("dwmmc init failed\n" );#endif +#ifdef CONFIG_SDHCI +/* mmc initializattion for available channels */ + ret =exynos_mmc_init (gd->fdt_blob); +if (ret) +debug ("mmc init failed\n" ); +#endif return ret; }#endif
Signature · 1 line
1.7.9.5
PATCH v2 3/10 ARM: exynos: clock: modify the set_mmc_clk for exynos4
In reply to Jaehoon ChungModified the mmc_set_clock for eynos4.
The goal of this patch is that fsys-div register should be reset. And retore the div-value, not using the value of lowlevel_init. (For using SDMMC4, this patch is needs)
--- arch/arm/cpu/armv7/exynos/clock.c | 16 +++++++++++----- arch/arm/include/asm/arch-exynos/clk.h | 5 +++++ 2 files changed, 16 insertions(+), 5 deletions(-)
arch/arm/cpu/armv7/exynos/clock.c +11 -5
@@ -869,7 +869,7 @@ static void exynos4_set_mmc_clk(int dev_index, unsigned int div) {struct exynos4_clock *clk = (struct exynos4_clock *)samsung_get_base_clock (); -unsigned int addr; +unsigned int addr, clear_bit, set_bit;/* * CLK_DIV_FSYS1
@@ -877,20 +877,26 @@ static void exynos4_set_mmc_clk(int dev_index, unsigned int div)* CLK_DIV_FSYS2 * MMC2_PRE_RATIO [15:8], MMC3_PRE_RATIO [31:24] * CLK_DIV_FSYS3 -* MMC4_PRE_RATIO [15:8] +* MMC4_RATIO [3:0] */ if (dev_index <2 ) { addr = (unsigned int )&clk->div_fsys1; - }else if (dev_index ==4 ) { + clear_bit =MASK_PRE_RATIO (dev_index); + set_bit =SET_PRE_RATIO (dev_index, div); + }else if (dev_index ==4 ) { addr = (unsigned int )&clk->div_fsys3; dev_index -=4 ; +/* MMC4 is controlled with the MMC4_RATIO value */ + clear_bit =MASK_RATIO (dev_index); + set_bit =SET_RATIO (dev_index, div); }else { addr = (unsigned int )&clk->div_fsys2; dev_index -=2 ; + clear_bit =MASK_PRE_RATIO (dev_index); + set_bit =SET_PRE_RATIO (dev_index, div); } -clrsetbits_le32 (addr,0xff << ((dev_index <<4 ) +8 ), - (div &0xff ) << ((dev_index <<4 ) +8 )); +clrsetbits_le32 (addr, clear_bit, set_bit); }/* exynos5: set the mmc clock */
arch/arm/include/asm/arch-exynos/clk.h +5 -0
@@ -16,6 +16,11 @@#define BPLL 5#define RPLL 6 +#define MASK_PRE_RATIO (x) (0xff << ((x << 4) + 8)) +#define MASK_RATIO (x) (0xf << (x << 4)) +#define SET_PRE_RATIO (x, y) ((y & 0xff) << ((x << 4) + 8)) +#define SET_RATIO (x, y) ((y & 0xf) << (x << 4)) +enum pll_src_bit {EXYNOS_SRC_MPLL =6 ,EXYNOS_SRC_EPLL ,
Signature · 1 line
1.7.9.5
PATCH v2 4/10 mmc: exynos_dw_mmc: restore the property into host
In reply to Jaehoon ChungRestore the platdata(property of dt) into host struct. Then data's information is maintained and reused anywhere.
--- drivers/mmc/exynos_dw_mmc.c | 220 +++++++++++++++++++++++++++---------------- include/dwmmc.h | 2 + 2 files changed, 139 insertions(+), 83 deletions(-)
drivers/mmc/exynos_dw_mmc.c +137 -83
@@ -14,6 +14,7 @@#include <asm/arch/clk.h> #include <asm/arch/pinmux.h> #include <asm/gpio.h> +#include <asm-generic/errno.h> #define DWMMC_MAX_CH_NUM 4#define DWMMC_MAX_FREQ 52000000
@@ -45,6 +46,13 @@ unsigned int exynos_dwmci_get_clk(struct dwmci_host *host) & DWMCI_DIVRATIO_MASK) + 1; sclk =get_mmc_clk (host->dev_index); +/* +* Assume to know divider value. +* When clock unit is broken, need to set "host->div" +*/ +if (host->div) + sclk /= (host->div +1 ); +return sclk / clk_div; }
@@ -61,26 +69,17 @@ static void exynos_dwmci_board_init(struct dwmci_host *host) } } -/* -* This function adds the mmc channel to be registered with mmc core. -* index - mmc channel number. -* regbase - register base address of mmc channel specified in 'index'. -* bus_width - operating bus width of mmc channel specified in 'index'. -* clksel - value to be written into CLKSEL register in case of FDT. -* NULL in case od non-FDT. -*/ -int exynos_dwmci_add_port (int index,u32 regbase,int bus_width,u32 clksel) +static int exynos_dwmci_core_init (struct dwmci_host *host,int index) { -struct dwmci_host *host =NULL ;unsigned int div;unsigned long freq, sclk; - host =malloc (sizeof (struct dwmci_host )); -if (!host) { -printf ("dwmci_host malloc fail!\n" ); -return 1 ; - } + +if (host->bus_hz) + freq = host->bus_hz; +else + freq =DWMMC_MAX_FREQ ; +/* request mmc clock vlaue of 52MHz. */ - freq =52000000 ; sclk =get_mmc_clk (index); div =DIV_ROUND_UP (sclk, freq); div -=1 ;
@@ -88,19 +87,15 @@ int exynos_dwmci_add_port(int index, u32 regbase, int bus_width, u32 clksel)set_mmc_clk (index, div); host->name ="EXYNOS DWMMC" ; - host->ioaddr = (void *)regbase; - host->buswidth = bus_width;#ifdef CONFIG_EXYNOS5420 host->quirks =DWMCI_QUIRK_DISABLE_SMU ;#endif host->board_init = exynos_dwmci_board_init; -if (clksel) { - host->clksel_val = clksel; - }else { -if (0 == index) +if (!host->clksel_val) { +if (index ==0 ) host->clksel_val =DWMMC_MMC0_CLKSEL_VAL ; -if (2 == index) +if (index ==2 ) host->clksel_val =DWMMC_MMC2_CLKSEL_VAL ; }
@@ -115,80 +110,139 @@ int exynos_dwmci_add_port(int index, u32 regbase, int bus_width, u32 clksel)return 0 ; } +/* +* This function adds the mmc channel to be registered with mmc core. +* index - mmc channel number. +* regbase - register base address of mmc channel specified in 'index'. +* bus_width - operating bus width of mmc channel specified in 'index'. +* clksel - value to be written into CLKSEL register in case of FDT. +* NULL in case od non-FDT. +*/ +int exynos_dwmci_add_port (int index,u32 regbase,int bus_width,u32 clksel) +{ +struct dwmci_host *host =NULL ; + + host =malloc (sizeof (struct dwmci_host )); +if (!host) { +error ("dwmci_host malloc fail!\n" ); +return -ENOMEM ; + } + + host->ioaddr = (void *)regbase; + host->buswidth = bus_width; + +if (clksel) + host->clksel_val = clksel; + +return exynos_dwmci_core_init (host, index); +} +#ifdef CONFIG_OF_CONTROL -int exynos_dwmmc_init (const void *blob) +struct dwmci_host dwmci_host[DWMMC_MAX_CH_NUM ]; + +static int do_dwmci_init (struct dwmci_host *host) { -int index, bus_width; -int node_list[DWMMC_MAX_CH_NUM ]; -int err =0 , dev_id, flag, count, i, compat_id; -u32 clksel_val, base, timing[3 ]; +int index, flag =0 , err =0 ; -#ifdef CONFIG_EXYNOS4 - compat_id =COMPAT_SAMSUNG_EXYNOS4_DWMMC ; -#else - compat_id =COMPAT_SAMSUNG_EXYNOS5_DWMMC ; -#endif + index = host->dev_index; - count =fdtdec_find_aliases_for_id (blob,"mmc" , - compat_id, node_list,DWMMC_MAX_CH_NUM ); + flag = host->buswidth ==8 ?PINMUX_FLAG_8BIT_MODE :PINMUX_FLAG_NONE ; + err =exynos_pinmux_config (host->dev_id, flag); +if (err) { +debug ("DWMMC not configure\n" ); +return err; + } -for (i =0 ; i < count; i++) { -int node = node_list[i]; -struct fdt_gpio_state pwr_gpio; +return exynos_dwmci_core_init (host, index); +} -if (node <=0 ) -continue ; +static int exynos_dwmci_get_config (const void *blob,int node, +struct dwmci_host *host) +{ +int err =0 ; +u32 base, clksel_val, timing[3 ]; -/* Extract device id for each mmc channel */ - dev_id =pinmux_decode_periph_id (blob, node); +/* Extract device id for each mmc channel */ + host->dev_id =pinmux_decode_periph_id (blob, node); -/* Get the bus width from the device node */ - bus_width =fdtdec_get_int (blob, node,"samsung,bus-width" ,0 ); -if (bus_width <=0 ) { -debug ("DWMMC: Can't get bus-width\n" ); -return -1 ; - } -if (8 == bus_width) - flag =PINMUX_FLAG_8BIT_MODE ; -else - flag =PINMUX_FLAG_NONE ; - -fdtdec_decode_gpio (blob, node,"pwr-gpios" , &pwr_gpio); -if (fdt_gpio_isvalid (&pwr_gpio)) -gpio_direction_output (pwr_gpio.gpio,1 ); -/* config pinmux for each mmc channel */ - err =exynos_pinmux_config (dev_id, flag); -if (err) { -debug ("DWMMC not configured\n" ); -return err; - } +/* Get the bus width from the device node */ + host->buswidth =fdtdec_get_int (blob, node,"samsung,bus-width" ,0 ); +if (host->buswidth <=0 ) { +debug ("DWMMC: Can't get bus-width\n" ); +return -EINVAL ; + } - index =fdtdec_get_int (blob, node,"index" , dev_id); -if (index == dev_id) - index = dev_id -PERIPH_ID_SDMMC0 ; + host->dev_index =fdtdec_get_int (blob, node,"index" , host->dev_id); +if (host->dev_index == host->dev_id) + host->dev_index = host->dev_id -PERIPH_ID_SDMMC0 ; -/* Get the base address from the device node */ - base =fdtdec_get_addr (blob, node,"reg" ); -if (!base) { -debug ("DWMMC: Can't get base address\n" ); -return -1 ; - } -/* Extract the timing info from the node */ - err =fdtdec_get_int_array (blob, node,"samsung,timing" , - timing,3 ); +/* Set the base address from the device node */ + base =fdtdec_get_addr (blob, node,"reg" ); +if (!base) { +debug ("DWMMC: Can't get base address\n" ); +return -EINVAL ; + } + host->ioaddr = (void *)base; + +/* Extract the timing info from the node */ + err =fdtdec_get_int_array (blob, node,"samsung,timing" , timing,3 ); +if (err) { +debug ("Can't get sdr-timings for devider\n" ); +return -EINVAL ; + } + + clksel_val = (DWMCI_SET_SAMPLE_CLK (timing[0 ]) | +DWMCI_SET_DRV_CLK (timing[1 ]) | +DWMCI_SET_DIV_RATIO (timing[2 ])); +if (clksel_val) + host->clksel_val = clksel_val; + + host->fifoth_val =fdtdec_get_int (blob, node,"fifoth_val" ,0 ); + host->bus_hz =fdtdec_get_int (blob, node,"bus_hz" ,0 ); + host->div =fdtdec_get_int (blob, node,"div" ,0 ); + +return 0 ; +} + +static int exynos_dwmci_process_node (const void *blob, +int node_list[],int count) +{ +struct dwmci_host *host; +int i, node, err; + +for (i =0 ; i < count; i++) { + node = node_list[i]; +if (node <=0 ) +continue ; + host = &dwmci_host[i]; + err =exynos_dwmci_get_config (blob, node, host);if (err) { -debug ("Can't get sdr-timings for divider\n" ); -return -1 ; +debug ("%s: failed to decode dev %d\n" , __func__, i); +return err; } - clksel_val = (DWMCI_SET_SAMPLE_CLK (timing[0 ]) | -DWMCI_SET_DRV_CLK (timing[1 ]) | -DWMCI_SET_DIV_RATIO (timing[2 ])); -/* Initialise each mmc channel */ - err =exynos_dwmci_add_port (index, base, bus_width, clksel_val); -if (err) -debug ("dwmmc Channel-%d init failed\n" , index); +do_dwmci_init (host); }return 0 ; } + +int exynos_dwmmc_init (const void *blob) +{ +int compat_id; +int node_list[DWMMC_MAX_CH_NUM ]; +int err =0 , count; + +if (cpu_is_exynos4 ()) + compat_id =COMPAT_SAMSUNG_EXYNOS4_DWMMC ; +else if (cpu_is_exynos5 ()) + compat_id =COMPAT_SAMSUNG_EXYNOS5_DWMMC ; +else + compat_id =COMPAT_UNKNOWN ; + + count =fdtdec_find_aliases_for_id (blob,"mmc" , + compat_id, node_list,DWMMC_MAX_CH_NUM ); + err =exynos_dwmci_process_node (blob, node_list, count); + +return err; +}#endif
include/dwmmc.h +2 -0
@@ -134,7 +134,9 @@ struct dwmci_host {unsigned int version;unsigned int clock;unsigned int bus_hz; +unsigned int div;int dev_index; +int dev_id;int buswidth;u32 clksel_val;u32 fifoth_val;
Signature · 1 line
1.7.9.5
PATCH v2 5/10 mmc: remove the unnecessary define and fix the wrong bit control
In reply to Jaehoon Chung--- drivers/mmc/mmc.c | 2 +- include/mmc.h | 18 ++++++------------ 2 files changed, 7 insertions(+), 13 deletions(-)
drivers/mmc/mmc.c +1 -1
@@ -518,7 +518,7 @@ static int mmc_change_freq(struct mmc *mmc)return 0 ;/* High Speed is set, there are two types: 52MHz and 26MHz */ -if (cardtype &MMC_HS_52MHZ ) +if (cardtype &EXT_CSD_CARD_TYPE_52 ) mmc->card_caps |= MMC_MODE_HS_52MHz |MMC_MODE_HS ;else mmc->card_caps |=MMC_MODE_HS ;
include/mmc.h +6 -12
@@ -31,15 +31,12 @@#define MMC_VERSION_4_41 (MMC_VERSION_MMC | 0x429)#define MMC_VERSION_4_5 (MMC_VERSION_MMC | 0x405) -#define MMC_MODE_HS 0x001 -#define MMC_MODE_HS_52MHz 0x010 -#define MMC_MODE_4BIT 0x100 -#define MMC_MODE_8BIT 0x200 -#define MMC_MODE_SPI 0x400 -#define MMC_MODE_HC 0x800 - -#define MMC_MODE_MASK_WIDTH_BITS (MMC_MODE_4BIT | MMC_MODE_8BIT) -#define MMC_MODE_WIDTH_BITS_SHIFT 8 +#define MMC_MODE_HS (1 << 0) +#define MMC_MODE_HS_52MHz (1 << 1) +#define MMC_MODE_4BIT (1 << 2) +#define MMC_MODE_8BIT (1 << 3) +#define MMC_MODE_SPI (1 << 4) +#define MMC_MODE_HC (1 << 5)#define SD_DATA_4BIT 0x00040000
@@ -97,9 +94,6 @@#define SD_HIGHSPEED_BUSY 0x00020000#define SD_HIGHSPEED_SUPPORTED 0x00020000 -#define MMC_HS_TIMING 0x00000100 -#define MMC_HS_52MHZ 0x2 -#define OCR_BUSY 0x80000000#define OCR_HCS 0x40000000#define OCR_VOLTAGE_MASK 0x007FFF80
Signature · 1 line
1.7.9.5
PATCH v2 6/10 mmc: support the DDR mode for eMMC
In reply to Jaehoon Chung--- drivers/mmc/mmc.c | 16 +++++++++++++--- include/mmc.h | 7 +++++++ 2 files changed, 20 insertions(+), 3 deletions(-)
drivers/mmc/mmc.c +13 -3
@@ -163,6 +163,9 @@ int mmc_set_blocklen(struct mmc *mmc, int len) {struct mmc_cmd cmd; +if (mmc->card_caps & MMC_MODE_DDR_52MHz) +return 0 ; + cmd.cmdidx =MMC_CMD_SET_BLOCKLEN ; cmd.resp_type =MMC_RSP_R1 ; cmd.cmdarg = len;
@@ -518,10 +521,13 @@ static int mmc_change_freq(struct mmc *mmc)return 0 ;/* High Speed is set, there are two types: 52MHz and 26MHz */ -if (cardtype &EXT_CSD_CARD_TYPE_52 ) +if (cardtype &EXT_CSD_CARD_TYPE_52 ) { +if (cardtype &EXT_CSD_CARD_TYPE_DDR_52 ) + mmc->card_caps |= MMC_MODE_DDR_52MHz; mmc->card_caps |= MMC_MODE_HS_52MHz |MMC_MODE_HS ; -else + }else { mmc->card_caps |=MMC_MODE_HS ; + }return 0 ; }
@@ -1057,6 +1063,8 @@ static int mmc_startup(struct mmc *mmc)/* An array of possible bus widths in order of preference */ static unsigned ext_csd_bits[] = { +EXT_CSD_DDR_BUS_WIDTH_8 , +EXT_CSD_DDR_BUS_WIDTH_4 ,EXT_CSD_BUS_WIDTH_8 ,EXT_CSD_BUS_WIDTH_4 ,EXT_CSD_BUS_WIDTH_1 ,
@@ -1064,13 +1072,15 @@ static int mmc_startup(struct mmc *mmc)/* An array to map CSD bus widths to host cap bits */ static unsigned ext_to_hostcaps[] = { + [EXT_CSD_DDR_BUS_WIDTH_4 ] = MMC_MODE_DDR_52MHz, + [EXT_CSD_DDR_BUS_WIDTH_8 ] = MMC_MODE_DDR_52MHz, [EXT_CSD_BUS_WIDTH_4 ] =MMC_MODE_4BIT , [EXT_CSD_BUS_WIDTH_8 ] =MMC_MODE_8BIT , };/* An array to map chosen bus width to an integer */ static unsigned widths[] = { -8 ,4 ,1 , +8 ,4 ,8 ,4 ,1 , };for (idx=0 ; idx <ARRAY_SIZE (ext_csd_bits); idx++) {
include/mmc.h +7 -0
@@ -37,6 +37,7 @@#define MMC_MODE_8BIT (1 << 3)#define MMC_MODE_SPI (1 << 4)#define MMC_MODE_HC (1 << 5) +#define MMC_MODE_DDR_52MHz (1 << 6)#define SD_DATA_4BIT 0x00040000
@@ -167,10 +168,16 @@#define EXT_CSD_CARD_TYPE_26 (1 << 0)/* Card can run at 26MHz */ #define EXT_CSD_CARD_TYPE_52 (1 << 1)/* Card can run@52MHz */ +#define EXT_CSD_CARD_TYPE_DDR_1_8V (1 << 2) +#define EXT_CSD_CARD_TYPE_DDR_1_2V (1 << 3) +#define EXT_CSD_CARD_TYPE_DDR_52 (EXT_CSD_CARD_TYPE_DDR_1_8V \ + | EXT_CSD_CARD_TYPE_DDR_1_2V)#define EXT_CSD_BUS_WIDTH_1 0/* Card is in 1 bit mode */ #define EXT_CSD_BUS_WIDTH_4 1/* Card is in 4 bit mode */ #define EXT_CSD_BUS_WIDTH_8 2/* Card is in 8 bit mode */ +#define EXT_CSD_DDR_BUS_WIDTH_4 5/* Card is in 4 bit DDR mode */ +#define EXT_CSD_DDR_BUS_WIDTH_8 6/* Card is in 8 bit DDR mode */ #define EXT_CSD_BOOT_ACK_ENABLE (1 << 6)#define EXT_CSD_BOOT_PARTITION_ENABLE (1 << 3)
Signature · 1 line
1.7.9.5
PATCH v2 7/10 mmc: dw_mmc: support the DDR mode
In reply to Jaehoon ChungSupport the DDR mode at dw-mmc controller
--- drivers/mmc/dw_mmc.c | 10 +++++++++- include/dwmmc.h | 3 +++ 2 files changed, 12 insertions(+), 1 deletion(-)
drivers/mmc/dw_mmc.c +9 -1
@@ -285,7 +285,7 @@ static int dwmci_setup_bus(struct dwmci_host *host, u32 freq)static void dwmci_set_ios (struct mmc *mmc) {struct dwmci_host *host = (struct dwmci_host *)mmc->priv; -u32 ctype; +u32 ctype, regs;debug ("Buswidth = %d, clock: %d\n" ,mmc->bus_width, mmc->clock);
@@ -304,6 +304,14 @@ static void dwmci_set_ios(struct mmc *mmc)dwmci_writel (host,DWMCI_CTYPE , ctype); + regs =dwmci_readl (host,DWMCI_UHS_REG ); +if (mmc->card_caps & MMC_MODE_DDR_52MHz) + regs |=DWMCI_DDR_MODE ; +else + regs &=DWMCI_DDR_MODE ; + +dwmci_writel (host,DWMCI_UHS_REG , regs); +if (host->clksel) host->clksel (host); }
include/dwmmc.h +3 -0
@@ -123,6 +123,9 @@#define DWMCI_BMOD_IDMAC_FB (1 << 1)#define DWMCI_BMOD_IDMAC_EN (1 << 7) +/* UHS register */ +#define DWMCI_DDR_MODE (1 << 16) +/* quirks */ #define DWMCI_QUIRK_DISABLE_SMU (1 << 0)
Signature · 1 line
1.7.9.5
PATCH v2 8/10 ARM: dts: exnyos: enable dw-mmc controller
In reply to Jaehoon ChungEnabled the dw-mmc controller.
--- arch/arm/dts/exynos4412-trats2.dts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
arch/arm/dts/exynos4412-trats2.dts +5 -1
@@ -417,6 +417,7 @@ samsung,bus-width = <8>; samsung,timing = <1 3 3>; pwr-gpios = <&gpio 0x2004002 0>; + status = "disabled"; }; sdhci at 12520000 {
@@ -435,7 +436,10 @@ dwmmc at 12550000 { samsung,bus-width = <8>; - samsung,timing = <0 1 0>; + samsung,timing = <2 1 0>; + fifoth_val = <0x203f0040>; + bus_hz = <400000000>; + div = <0x3>; pwr-gpios = <&gpio 0x2004002 0>; index = <4>; };
Signature · 1 line
1.7.9.5
PATCH v2 9/10 mmc: exynos_dw_mmc: enable the DDR mode
In reply to Jaehoon ChungSet the ddr mode capability by default.
--- drivers/mmc/exynos_dw_mmc.c | 1 + 1 file changed, 1 insertion(+)
drivers/mmc/exynos_dw_mmc.c +1 -0
@@ -99,6 +99,7 @@ static int exynos_dwmci_core_init(struct dwmci_host *host, int index) host->clksel_val =DWMMC_MMC2_CLKSEL_VAL ; } + host->caps = MMC_MODE_DDR_52MHz; host->clksel = exynos_dwmci_clksel; host->dev_index = index; host->get_mmc_clk = exynos_dwmci_get_clk;
Signature · 1 line
1.7.9.5
PATCH v2 10/10 ARM: exynos4: enable the dwmmc configuration
In reply to Jaehoon Chung--- include/configs/exynos4-dt.h | 3 +++ 1 file changed, 3 insertions(+)
include/configs/exynos4-dt.h +3 -0
@@ -44,6 +44,9 @@#define CONFIG_S5P_SDHCI #define CONFIG_SDHCI #define CONFIG_MMC_SDMA +#define CONFIG_DWMMC +#define CONFIG_EXYNOS_DWMMC +#define CONFIG_BOUNCE_BUFFER #define CONFIG_MMC_DEFAULT_DEV 0/* PWM */
Signature · 1 line
1.7.9.5
v2 cover mmc: code cleanup and support DDR mode
In reply to Jaehoon ChungHi Jaehoon,
Quoted 16 lines
If card and host are supported DDR mode, then it can be used the DDR mode. This patch-set has dependency about beomho's patch-set. (Based-on u-boot-samsung repository)
http://patchwork.ozlabs.org/patch/331986/
http://patchwork.ozlabs.org/patch/331987/
http://patchwork.ozlabs.org/patch/331989/
http://patchwork.ozlabs.org/patch/331988/It's result for loading image.
sdhci controller ->5260488 bytes read in 259 ms (19.4 MiB/s) dwmmc controller without DDR mode -> 5260488 bytes read in 202 ms (24.8 MiB/s) dwmmc controller with DDR mode -> 5260488 bytes read in 118 ms (42.5 MiB/s)
Quoted 4 lines
Download the 400M image with lthor.
sdhci controller -> 59.4sec (Avg 6.95 MB/s)
dwmmc controller without DDR mode -> 61.6sec (Avg 6.72MB/s) dwmmc controller with DDR mode -> 60.4sec (Avg 6.85MB/s)
With downloading we aren't observing time improvement for downloading the test image and flashing it, because of the time consuming crc32 calculation.
After applying the patch:
http://patchwork.ozlabs.org/patch/335223/
The time itself reduces significantly to less than 20 seconds.
In spite of the above I've tested this patch set on Trats2, so
Signature · 5 lines
Best regards, Lukasz Majewski Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
v2 cover mmc: code cleanup and support DDR mode
In reply to Jaehoon ChungHi Jaehoon,
Quoted 32 lines · Jaehoon Chung
If card and host are supported DDR mode, then it can be used the DDR mode. This patch-set has dependency about beomho's patch-set. (Based-on u-boot-samsung repository)
http://patchwork.ozlabs.org/patch/331986/
http://patchwork.ozlabs.org/patch/331987/
http://patchwork.ozlabs.org/patch/331989/
http://patchwork.ozlabs.org/patch/331988/It's result for loading image.
sdhci controller ->5260488 bytes read in 259 ms (19.4 MiB/s) dwmmc controller without DDR mode -> 5260488 bytes read in 202 ms (24.8 MiB/s) dwmmc controller with DDR mode -> 5260488 bytes read in 118 ms (42.5 MiB/s)
Download the 400M image with lthor.
sdhci controller -> 59.4sec (Avg 6.95 MB/s)
dwmmc controller without DDR mode -> 61.6sec (Avg 6.72MB/s) dwmmc controller with DDR mode -> 60.4sec (Avg 6.85MB/s)Jaehoon Chung (10):
mmc:s5p_sdhci: add thes5p_sdhci_core_initfunction
ARM: exynos: board: change the mmc/sd init sequence
ARM: exynos: clock: modify theset_mmc_clkfor exynos4
mmc:exynos_dw_mmc: restore the property into host
mmc: remove the unnecessary define and fix the wrong bit control
mmc: support the DDR mode for eMMC
mmc:dw_mmc: support the DDR mode
ARM: dts: exnyos: enable dw-mmc controller
mmc:exynos_dw_mmc: enable the DDR mode
ARM: exynos4: enable the dwmmc configuration
Quoted 16 lines
arch/arm/cpu/armv7/exynos/clock.c | 16 ++- arch/arm/dts/exynos4412-trats2.dts | 6 +- arch/arm/include/asm/arch-exynos/clk.h | 5 + board/samsung/common/board.c | 13 +- drivers/mmc/dw_mmc.c | 10 +- drivers/mmc/exynos_dw_mmc.c | 221 ++++++++++++++++++++------------ drivers/mmc/mmc.c | 16 ++- drivers/mmc/s5p_sdhci.c | 42 +++--- include/configs/exynos4-dt.h | 3 + include/dwmmc.h | 5 + include/mmc.h | 25 ++-- 11 files changed, 225 insertions(+), 137 deletions(-)Signature · 1 line
1.7.9.5
At first glance it looks OK. I'll wait until the dependency land on master and then look into it more closely.
Regards
-- Pantelis