diff mbox

[U-Boot,V3,4/9] EXYNOS5: DWMMC: Added FDT support for DWMMC

Message ID 1356951500-22490-5-git-send-email-amarendra.xt@samsung.com
State Superseded
Delegated to: Minkyu Kang
Headers show

Commit Message

Amar Dec. 31, 2012, 10:58 a.m. UTC
This patch adds FDT support for DWMMC, by reading the DWMMC node data
from the device tree and initialising DWMMC channels as per data
obtained from the node.

Changes from V1:
	1)Updated code to have same signature for the function
	exynos_dwmci_init() for both FDT and non-FDT versions.
	2)Updated code to pass device_id parameter to the function
	exynos5_mmc_set_clk_div() instead of index.
	3)Updated code to decode the value of "samsung,width" from FDT.
	4)Channel index is computed instead of getting from FDT.

Changes from V2:
	1)Updation of commit message and resubmition of proper patch set.

Signed-off-by: Vivek Gautam <gautam.vivek@samsung.com>
Signed-off-by: Amar <amarendra.xt@samsung.com>
---
 arch/arm/include/asm/arch-exynos/dwmmc.h |   4 ++
 drivers/mmc/exynos_dw_mmc.c              | 116 +++++++++++++++++++++++++++++--
 include/dwmmc.h                          |   4 ++
 3 files changed, 117 insertions(+), 7 deletions(-)

Comments

Jaehoon Chung Jan. 2, 2013, 5:20 a.m. UTC | #1
On 12/31/2012 07:58 PM, Amar wrote:
> This patch adds FDT support for DWMMC, by reading the DWMMC node data
> from the device tree and initialising DWMMC channels as per data
> obtained from the node.
> 
> Changes from V1:
> 	1)Updated code to have same signature for the function
> 	exynos_dwmci_init() for both FDT and non-FDT versions.
> 	2)Updated code to pass device_id parameter to the function
> 	exynos5_mmc_set_clk_div() instead of index.
> 	3)Updated code to decode the value of "samsung,width" from FDT.
> 	4)Channel index is computed instead of getting from FDT.
> 
> Changes from V2:
> 	1)Updation of commit message and resubmition of proper patch set.
> 
> Signed-off-by: Vivek Gautam <gautam.vivek@samsung.com>
> Signed-off-by: Amar <amarendra.xt@samsung.com>
> ---
>  arch/arm/include/asm/arch-exynos/dwmmc.h |   4 ++
>  drivers/mmc/exynos_dw_mmc.c              | 116 +++++++++++++++++++++++++++++--
>  include/dwmmc.h                          |   4 ++
>  3 files changed, 117 insertions(+), 7 deletions(-)
> 
> diff --git a/arch/arm/include/asm/arch-exynos/dwmmc.h b/arch/arm/include/asm/arch-exynos/dwmmc.h
> index 8acdf9b..40dcc7b 100644
> --- a/arch/arm/include/asm/arch-exynos/dwmmc.h
> +++ b/arch/arm/include/asm/arch-exynos/dwmmc.h
> @@ -29,8 +29,12 @@
>  
>  int exynos_dwmci_init(u32 regbase, int bus_width, int index);
>  
> +#ifdef CONFIG_OF_CONTROL
> +unsigned int exynos_dwmmc_init(const void *blob);
> +#else
>  static inline unsigned int exynos_dwmmc_init(int index, int bus_width)
>  {
>  	unsigned int base = samsung_get_base_mmc() + (0x10000 * index);
>  	return exynos_dwmci_init(base, bus_width, index);
>  }
> +#endif
> diff --git a/drivers/mmc/exynos_dw_mmc.c b/drivers/mmc/exynos_dw_mmc.c
> index 72a31b7..541889f 100644
> --- a/drivers/mmc/exynos_dw_mmc.c
> +++ b/drivers/mmc/exynos_dw_mmc.c
> @@ -19,39 +19,141 @@
>   */
>  
>  #include <common.h>
> -#include <malloc.h>
>  #include <dwmmc.h>
> +#include <fdtdec.h>
> +#include <libfdt.h>
> +#include <malloc.h>
>  #include <asm/arch/dwmmc.h>
>  #include <asm/arch/clk.h>
> +#include <asm/arch/pinmux.h>
> +
> +#define	DWMMC_MAX_CH_NUM		4
> +#define	DWMMC_MAX_FREQ			52000000
> +#define	DWMMC_MIN_FREQ			400000
> +#define	DWMMC_MMC0_CLKSEL_VAL		0x03030001
> +#define	DWMMC_MMC2_CLKSEL_VAL		0x03020001
>  
>  static char *EXYNOS_NAME = "EXYNOS DWMMC";
> +u32 timing[3];
>  
> +/*
> + * Function used as callback function to initialise the
> + * CLKSEL register for every mmc channel.
> + */
>  static void exynos_dwmci_clksel(struct dwmci_host *host)
>  {
> -	u32 val;
> -	val = DWMCI_SET_SAMPLE_CLK(DWMCI_SHIFT_0) |
> -		DWMCI_SET_DRV_CLK(DWMCI_SHIFT_0) | DWMCI_SET_DIV_RATIO(0);
> +	dwmci_writel(host, DWMCI_CLKSEL, host->clksel_val);
> +}
>  
> -	dwmci_writel(host, DWMCI_CLKSEL, val);
> +unsigned int exynos_dwmci_get_clk(int dev_index)
> +{
> +	return get_mmc_clk(dev_index);
>  }
>  
>  int exynos_dwmci_init(u32 regbase, int bus_width, int index)
>  {
>  	struct dwmci_host *host = NULL;
> +	int dev_id = 0;
>  	host = malloc(sizeof(struct dwmci_host));
>  	if (!host) {
>  		printf("dwmci_host malloc fail!\n");
>  		return 1;
>  	}
> +	/* Convert index into corresponding peripheral ID */
> +	dev_id = index + PERIPH_ID_SDMMC0;
Is it right at every case?
> +
> +	/* set the clock divisor - clk_div_fsys for mmc */
> +	if (exynos5_mmc_set_clk_div(dev_id)) {
> +		debug("mmc clock div set failed\n");
> +		return -1;
> +	}
>  
>  	host->name = EXYNOS_NAME;
>  	host->ioaddr = (void *)regbase;
>  	host->buswidth = bus_width;
> +#ifdef CONFIG_OF_CONTROL
> +	host->clksel_val = (DWMCI_SET_SAMPLE_CLK(timing[0]) |
> +				DWMCI_SET_DRV_CLK(timing[1]) |
> +				DWMCI_SET_DIV_RATIO(timing[2]));
> +#else
> +	if (0 == index)
> +		host->clksel_val = DWMMC_MMC0_CLKSEL_VAL;
> +	if (2 == index)
> +		host->clksel_val = DWMMC_MMC2_CLKSEL_VAL;
> +#endif
>  	host->clksel = exynos_dwmci_clksel;
>  	host->dev_index = index;
> -
> -	add_dwmci(host, 52000000, 400000);
> +	host->mmc_clk = exynos_dwmci_get_clk;
> +	/* Add the mmc chennel to be registered with mmc core */
> +	add_dwmci(host, DWMMC_MAX_FREQ, DWMMC_MIN_FREQ);
>  
>  	return 0;
>  }
>  
> +#ifdef CONFIG_OF_CONTROL
> +unsigned int exynos_dwmmc_init(const void *blob)
> +{
> +	u32 base;
> +	int index, bus_width;
> +	int node_list[DWMMC_MAX_CH_NUM];
> +	int err = 0;
> +	int dev_id, flag;
> +	int count, i;
> +
> +	count = fdtdec_find_aliases_for_id(blob, "dwmmc",
> +				COMPAT_SAMSUNG_EXYNOS5_DWMMC, node_list,
> +				DWMMC_MAX_CH_NUM);
> +
> +	for (i = 0; i < count; i++) {
> +		int node = node_list[i];
> +
> +		if (node <= 0)
> +			continue;
> +
> +		/* Extract device id for each mmc channel */
> +		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;
> +
> +		/* config pinmux for each mmc channel */
> +		err = exynos_pinmux_config(dev_id, flag);
> +		if (err) {
> +			debug("DWMMC not configured\n");
> +			return err;
> +		}
> +
> +		index = 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);
> +		if (err) {
> +			debug("Can't get sdr-timings for divider\n");
> +			return -1;
> +		}
> +		/* Initialise each mmc channel */
> +		err =  exynos_dwmci_init(base, bus_width, index);
> +		if (err) {
> +			debug("Can't do dwmci init\n");
> +			return -1;
> +		}
> +	}
> +
> +	return 0;
> +}
> +#endif
> diff --git a/include/dwmmc.h b/include/dwmmc.h
> index c8b1d40..4a42849 100644
> --- a/include/dwmmc.h
> +++ b/include/dwmmc.h
> @@ -123,6 +123,9 @@
>  #define MSIZE(x)		((x) << 28)
>  #define RX_WMARK(x)		((x) << 16)
>  #define TX_WMARK(x)		(x)
> +#define RX_WMARK_SHIFT		16
> +#define RX_WMARK_MASK		(0xfff << RX_WMARK_SHIFT)
> +
>  
>  #define DWMCI_IDMAC_OWN		(1 << 31)
>  #define DWMCI_IDMAC_CH		(1 << 4)
> @@ -144,6 +147,7 @@ struct dwmci_host {
>  	unsigned int bus_hz;
>  	int dev_index;
>  	int buswidth;
> +	u32 clksel_val;
>  	u32 fifoth_val;
>  	struct mmc *mmc;
>  
>
Amarendra Reddy Jan. 3, 2013, 4:32 a.m. UTC | #2
Hi Jaehoon,
Thanks for the comments.
Please find my response below.

Thanks & Regards
Amarendra

On 2 January 2013 10:50, Jaehoon Chung <jh80.chung@samsung.com> wrote:

>  On 12/31/2012 07:58 PM, Amar wrote:
> > This patch adds FDT support for DWMMC, by reading the DWMMC node data
> > from the device tree and initialising DWMMC channels as per data
> > obtained from the node.
> >
> > Changes from V1:
> >       1)Updated code to have same signature for the function
> >       exynos_dwmci_init() for both FDT and non-FDT versions.
> >       2)Updated code to pass device_id parameter to the function
> >       exynos5_mmc_set_clk_div() instead of index.
> >       3)Updated code to decode the value of "samsung,width" from FDT.
> >       4)Channel index is computed instead of getting from FDT.
> >
> > Changes from V2:
> >       1)Updation of commit message and resubmition of proper patch set.
> >
> > Signed-off-by: Vivek Gautam <gautam.vivek@samsung.com>
> > Signed-off-by: Amar <amarendra.xt@samsung.com>
> > ---
> >  arch/arm/include/asm/arch-exynos/dwmmc.h |   4 ++
> >  drivers/mmc/exynos_dw_mmc.c              | 116
> +++++++++++++++++++++++++++++--
> >  include/dwmmc.h                          |   4 ++
> >  3 files changed, 117 insertions(+), 7 deletions(-)
> >
> > diff --git a/arch/arm/include/asm/arch-exynos/dwmmc.h
> b/arch/arm/include/asm/arch-exynos/dwmmc.h
> > index 8acdf9b..40dcc7b 100644
> > --- a/arch/arm/include/asm/arch-exynos/dwmmc.h
> > +++ b/arch/arm/include/asm/arch-exynos/dwmmc.h
> > @@ -29,8 +29,12 @@
> >
> >  int exynos_dwmci_init(u32 regbase, int bus_width, int index);
> >
> > +#ifdef CONFIG_OF_CONTROL
> > +unsigned int exynos_dwmmc_init(const void *blob);
> > +#else
> >  static inline unsigned int exynos_dwmmc_init(int index, int bus_width)
> >  {
> >       unsigned int base = samsung_get_base_mmc() + (0x10000 * index);
> >       return exynos_dwmci_init(base, bus_width, index);
> >  }
> > +#endif
> > diff --git a/drivers/mmc/exynos_dw_mmc.c b/drivers/mmc/exynos_dw_mmc.c
> > index 72a31b7..541889f 100644
> > --- a/drivers/mmc/exynos_dw_mmc.c
> > +++ b/drivers/mmc/exynos_dw_mmc.c
> > @@ -19,39 +19,141 @@
> >   */
> >
> >  #include <common.h>
> > -#include <malloc.h>
> >  #include <dwmmc.h>
> > +#include <fdtdec.h>
> > +#include <libfdt.h>
> > +#include <malloc.h>
> >  #include <asm/arch/dwmmc.h>
> >  #include <asm/arch/clk.h>
> > +#include <asm/arch/pinmux.h>
> > +
> > +#define      DWMMC_MAX_CH_NUM                4
> > +#define      DWMMC_MAX_FREQ                  52000000
> > +#define      DWMMC_MIN_FREQ                  400000
> > +#define      DWMMC_MMC0_CLKSEL_VAL           0x03030001
> > +#define      DWMMC_MMC2_CLKSEL_VAL           0x03020001
> >
> >  static char *EXYNOS_NAME = "EXYNOS DWMMC";
> > +u32 timing[3];
> >
> > +/*
> > + * Function used as callback function to initialise the
> > + * CLKSEL register for every mmc channel.
> > + */
> >  static void exynos_dwmci_clksel(struct dwmci_host *host)
> >  {
> > -     u32 val;
> > -     val = DWMCI_SET_SAMPLE_CLK(DWMCI_SHIFT_0) |
> > -             DWMCI_SET_DRV_CLK(DWMCI_SHIFT_0) | DWMCI_SET_DIV_RATIO(0);
> > +     dwmci_writel(host, DWMCI_CLKSEL, host->clksel_val);
> > +}
> >
> > -     dwmci_writel(host, DWMCI_CLKSEL, val);
> > +unsigned int exynos_dwmci_get_clk(int dev_index)
> > +{
> > +     return get_mmc_clk(dev_index);
> >  }
> >
> >  int exynos_dwmci_init(u32 regbase, int bus_width, int index)
> >  {
> >       struct dwmci_host *host = NULL;
> > +     int dev_id = 0;
> >       host = malloc(sizeof(struct dwmci_host));
> >       if (!host) {
> >               printf("dwmci_host malloc fail!\n");
> >               return 1;
> >       }
> > +     /* Convert index into corresponding peripheral ID */
> > +     dev_id = index + PERIPH_ID_SDMMC0;
> Is it right at every case?
>

Yes, it is right in every case.

Consider the finction "int exynos_dwmci_init(u32 regbase, int bus_width,
int index)"
If the input argument 'index' is between (0-3), then the statement "dev_id
= index + PERIPH_ID_SDMMC0;" works good.

So, the function exynos_dwmci_init(u32 regbase, int bus_width, int index)
is being called as below
1) FDT Case:
The function exynos_dwmmc_init() calls exynos_dwmmc_init()
The dev_id is extracted from arch/arm/dts/exynos5250.dtsi. The dev_id is
nothing but the interrupt number.
dwmmc0 - dev_id = 75
dwmmc1 - dev_id = 76
dwmmc2 - dev_id = 77
dwmmc3 - dev_id = 78

At same time the enum values are (Refer
"arch/arm/include/asm/arch-exynos/periph.h")
PERIPH_ID_SDMMC0 = 75,
PERIPH_ID_SDMMC1,
PERIPH_ID_SDMMC2,
PERIPH_ID_SDMMC3,

 Here "index = dev_id - PERIPH_ID_SDMMC0" works good for all channels
(mmc0 - mmc3)

As proper values are mentioned in arch/arm/dts/exynos5250.dtsi, proper
values of "index" (i.e 0 - 3) will be computed here.

2) Non-FDT case:
The function board_mmc_init() calls exynos_dwmmc_init() as shown below
int board_mmc_init(bd_t *bis)
{
 ....
 ....
        /*EMMC: dwmmc Channel-0 with 8 bit bus width */
        err = exynos_dwmmc_init(0, 8);
}
Here the coder shall ensure to pass proper index number (0 to 3) for porper
working.


>  > +
> > +     /* set the clock divisor - clk_div_fsys for mmc */
> > +     if (exynos5_mmc_set_clk_div(dev_id)) {
> > +             debug("mmc clock div set failed\n");
> > +             return -1;
> > +     }
> >
> >       host->name = EXYNOS_NAME;
> >       host->ioaddr = (void *)regbase;
> >       host->buswidth = bus_width;
> > +#ifdef CONFIG_OF_CONTROL
> > +     host->clksel_val = (DWMCI_SET_SAMPLE_CLK(timing[0]) |
> > +                             DWMCI_SET_DRV_CLK(timing[1]) |
> > +                             DWMCI_SET_DIV_RATIO(timing[2]));
> > +#else
> > +     if (0 == index)
> > +             host->clksel_val = DWMMC_MMC0_CLKSEL_VAL;
> > +     if (2 == index)
> > +             host->clksel_val = DWMMC_MMC2_CLKSEL_VAL;
> > +#endif
> >       host->clksel = exynos_dwmci_clksel;
> >       host->dev_index = index;
> > -
> > -     add_dwmci(host, 52000000, 400000);
> > +     host->mmc_clk = exynos_dwmci_get_clk;
> > +     /* Add the mmc chennel to be registered with mmc core */
> > +     add_dwmci(host, DWMMC_MAX_FREQ, DWMMC_MIN_FREQ);
> >
> >       return 0;
> >  }
> >
> > +#ifdef CONFIG_OF_CONTROL
> > +unsigned int exynos_dwmmc_init(const void *blob)
> > +{
> > +     u32 base;
> > +     int index, bus_width;
> > +     int node_list[DWMMC_MAX_CH_NUM];
> > +     int err = 0;
> > +     int dev_id, flag;
> > +     int count, i;
> > +
> > +     count = fdtdec_find_aliases_for_id(blob, "dwmmc",
> > +                             COMPAT_SAMSUNG_EXYNOS5_DWMMC, node_list,
> > +                             DWMMC_MAX_CH_NUM);
> > +
> > +     for (i = 0; i < count; i++) {
> > +             int node = node_list[i];
> > +
> > +             if (node <= 0)
> > +                     continue;
> > +
> > +             /* Extract device id for each mmc channel */
> > +             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;
> > +
> > +             /* config pinmux for each mmc channel */
> > +             err = exynos_pinmux_config(dev_id, flag);
> > +             if (err) {
> > +                     debug("DWMMC not configured\n");
> > +                     return err;
> > +             }
> > +
> > +             index = 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);
> > +             if (err) {
> > +                     debug("Can't get sdr-timings for divider\n");
> > +                     return -1;
> > +             }
> > +             /* Initialise each mmc channel */
> > +             err =  exynos_dwmci_init(base, bus_width, index);
> > +             if (err) {
> > +                     debug("Can't do dwmci init\n");
> > +                     return -1;
> > +             }
> > +     }
> > +
> > +     return 0;
> > +}
> > +#endif
> > diff --git a/include/dwmmc.h b/include/dwmmc.h
> > index c8b1d40..4a42849 100644
> > --- a/include/dwmmc.h
> > +++ b/include/dwmmc.h
> > @@ -123,6 +123,9 @@
> >  #define MSIZE(x)             ((x) << 28)
> >  #define RX_WMARK(x)          ((x) << 16)
> >  #define TX_WMARK(x)          (x)
> > +#define RX_WMARK_SHIFT               16
> > +#define RX_WMARK_MASK                (0xfff << RX_WMARK_SHIFT)
> > +
> >
> >  #define DWMCI_IDMAC_OWN              (1 << 31)
> >  #define DWMCI_IDMAC_CH               (1 << 4)
> > @@ -144,6 +147,7 @@ struct dwmci_host {
> >       unsigned int bus_hz;
> >       int dev_index;
> >       int buswidth;
> > +     u32 clksel_val;
> >       u32 fifoth_val;
> >       struct mmc *mmc;
> >
> >
>
>  _______________________________________________
> U-Boot mailing list
> U-Boot@lists.denx.de
> http://lists.denx.de/mailman/listinfo/u-boot
>
Jaehoon Chung Jan. 3, 2013, 6:48 a.m. UTC | #3
Hi Amar,

..snip..
>>>  }
>>>
>>>  int exynos_dwmci_init(u32 regbase, int bus_width, int index)
>>>  {
>>>       struct dwmci_host *host = NULL;
>>> +     int dev_id = 0;
>>>       host = malloc(sizeof(struct dwmci_host));
>>>       if (!host) {
>>>               printf("dwmci_host malloc fail!\n");
>>>               return 1;
>>>       }
>>> +     /* Convert index into corresponding peripheral ID */
>>> +     dev_id = index + PERIPH_ID_SDMMC0;
>> Is it right at every case?
>>
> 
> Yes, it is right in every case.
> 
> Consider the finction "int exynos_dwmci_init(u32 regbase, int bus_width,
> int index)"
> If the input argument 'index' is between (0-3), then the statement "dev_id
> = index + PERIPH_ID_SDMMC0;" works good.
> 
> So, the function exynos_dwmci_init(u32 regbase, int bus_width, int index)
> is being called as below
> 1) FDT Case:
> The function exynos_dwmmc_init() calls exynos_dwmmc_init()
> The dev_id is extracted from arch/arm/dts/exynos5250.dtsi. The dev_id is
> nothing but the interrupt number.
> dwmmc0 - dev_id = 75
> dwmmc1 - dev_id = 76
> dwmmc2 - dev_id = 77
> dwmmc3 - dev_id = 78
> 
> At same time the enum values are (Refer
> "arch/arm/include/asm/arch-exynos/periph.h")
> PERIPH_ID_SDMMC0 = 75,
> PERIPH_ID_SDMMC1,
> PERIPH_ID_SDMMC2,
> PERIPH_ID_SDMMC3,
> 
>  Here "index = dev_id - PERIPH_ID_SDMMC0" works good for all channels
> (mmc0 - mmc3)
> 
> As proper values are mentioned in arch/arm/dts/exynos5250.dtsi, proper
> values of "index" (i.e 0 - 3) will be computed here.
> 
> 2) Non-FDT case:
> The function board_mmc_init() calls exynos_dwmmc_init() as shown below
> int board_mmc_init(bd_t *bis)
> {
>  ....
>  ....
>         /*EMMC: dwmmc Channel-0 with 8 bit bus width */
>         err = exynos_dwmmc_init(0, 8);
> }
> Here the coder shall ensure to pass proper index number (0 to 3) for porper
> working.

Sorry, i confused the dev_id and dev_index..Thank you for explanation.

Best Regards,
Jaehoon Chung
> 
> 
>>  > +
>>> +     /* set the clock divisor - clk_div_fsys for mmc */
>>> +     if (exynos5_mmc_set_clk_div(dev_id)) {
>>> +             debug("mmc clock div set failed\n");
>>> +             return -1;
>>> +     }
>>>
>>>       host->name = EXYNOS_NAME;
>>>       host->ioaddr = (void *)regbase;
>>>       host->buswidth = bus_width;
>>> +#ifdef CONFIG_OF_CONTROL
>>> +     host->clksel_val = (DWMCI_SET_SAMPLE_CLK(timing[0]) |
>>> +                             DWMCI_SET_DRV_CLK(timing[1]) |
>>> +                             DWMCI_SET_DIV_RATIO(timing[2]));
>>> +#else
>>> +     if (0 == index)
>>> +             host->clksel_val = DWMMC_MMC0_CLKSEL_VAL;
>>> +     if (2 == index)
>>> +             host->clksel_val = DWMMC_MMC2_CLKSEL_VAL;
>>> +#endif
>>>       host->clksel = exynos_dwmci_clksel;
>>>       host->dev_index = index;
>>> -
>>> -     add_dwmci(host, 52000000, 400000);
>>> +     host->mmc_clk = exynos_dwmci_get_clk;
>>> +     /* Add the mmc chennel to be registered with mmc core */
>>> +     add_dwmci(host, DWMMC_MAX_FREQ, DWMMC_MIN_FREQ);
>>>
>>>       return 0;
>>>  }
>>>
>>> +#ifdef CONFIG_OF_CONTROL
>>> +unsigned int exynos_dwmmc_init(const void *blob)
>>> +{
>>> +     u32 base;
>>> +     int index, bus_width;
>>> +     int node_list[DWMMC_MAX_CH_NUM];
>>> +     int err = 0;
>>> +     int dev_id, flag;
>>> +     int count, i;
>>> +
>>> +     count = fdtdec_find_aliases_for_id(blob, "dwmmc",
>>> +                             COMPAT_SAMSUNG_EXYNOS5_DWMMC, node_list,
>>> +                             DWMMC_MAX_CH_NUM);
>>> +
>>> +     for (i = 0; i < count; i++) {
>>> +             int node = node_list[i];
>>> +
>>> +             if (node <= 0)
>>> +                     continue;
>>> +
>>> +             /* Extract device id for each mmc channel */
>>> +             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;
>>> +
>>> +             /* config pinmux for each mmc channel */
>>> +             err = exynos_pinmux_config(dev_id, flag);
>>> +             if (err) {
>>> +                     debug("DWMMC not configured\n");
>>> +                     return err;
>>> +             }
>>> +
>>> +             index = 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);
>>> +             if (err) {
>>> +                     debug("Can't get sdr-timings for divider\n");
>>> +                     return -1;
>>> +             }
>>> +             /* Initialise each mmc channel */
>>> +             err =  exynos_dwmci_init(base, bus_width, index);
>>> +             if (err) {
>>> +                     debug("Can't do dwmci init\n");
>>> +                     return -1;
>>> +             }
>>> +     }
>>> +
>>> +     return 0;
>>> +}
>>> +#endif
>>> diff --git a/include/dwmmc.h b/include/dwmmc.h
>>> index c8b1d40..4a42849 100644
>>> --- a/include/dwmmc.h
>>> +++ b/include/dwmmc.h
>>> @@ -123,6 +123,9 @@
>>>  #define MSIZE(x)             ((x) << 28)
>>>  #define RX_WMARK(x)          ((x) << 16)
>>>  #define TX_WMARK(x)          (x)
>>> +#define RX_WMARK_SHIFT               16
>>> +#define RX_WMARK_MASK                (0xfff << RX_WMARK_SHIFT)
>>> +
>>>
>>>  #define DWMCI_IDMAC_OWN              (1 << 31)
>>>  #define DWMCI_IDMAC_CH               (1 << 4)
>>> @@ -144,6 +147,7 @@ struct dwmci_host {
>>>       unsigned int bus_hz;
>>>       int dev_index;
>>>       int buswidth;
>>> +     u32 clksel_val;
>>>       u32 fifoth_val;
>>>       struct mmc *mmc;
>>>
>>>
>>
>>  _______________________________________________
>> 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
>
diff mbox

Patch

diff --git a/arch/arm/include/asm/arch-exynos/dwmmc.h b/arch/arm/include/asm/arch-exynos/dwmmc.h
index 8acdf9b..40dcc7b 100644
--- a/arch/arm/include/asm/arch-exynos/dwmmc.h
+++ b/arch/arm/include/asm/arch-exynos/dwmmc.h
@@ -29,8 +29,12 @@ 
 
 int exynos_dwmci_init(u32 regbase, int bus_width, int index);
 
+#ifdef CONFIG_OF_CONTROL
+unsigned int exynos_dwmmc_init(const void *blob);
+#else
 static inline unsigned int exynos_dwmmc_init(int index, int bus_width)
 {
 	unsigned int base = samsung_get_base_mmc() + (0x10000 * index);
 	return exynos_dwmci_init(base, bus_width, index);
 }
+#endif
diff --git a/drivers/mmc/exynos_dw_mmc.c b/drivers/mmc/exynos_dw_mmc.c
index 72a31b7..541889f 100644
--- a/drivers/mmc/exynos_dw_mmc.c
+++ b/drivers/mmc/exynos_dw_mmc.c
@@ -19,39 +19,141 @@ 
  */
 
 #include <common.h>
-#include <malloc.h>
 #include <dwmmc.h>
+#include <fdtdec.h>
+#include <libfdt.h>
+#include <malloc.h>
 #include <asm/arch/dwmmc.h>
 #include <asm/arch/clk.h>
+#include <asm/arch/pinmux.h>
+
+#define	DWMMC_MAX_CH_NUM		4
+#define	DWMMC_MAX_FREQ			52000000
+#define	DWMMC_MIN_FREQ			400000
+#define	DWMMC_MMC0_CLKSEL_VAL		0x03030001
+#define	DWMMC_MMC2_CLKSEL_VAL		0x03020001
 
 static char *EXYNOS_NAME = "EXYNOS DWMMC";
+u32 timing[3];
 
+/*
+ * Function used as callback function to initialise the
+ * CLKSEL register for every mmc channel.
+ */
 static void exynos_dwmci_clksel(struct dwmci_host *host)
 {
-	u32 val;
-	val = DWMCI_SET_SAMPLE_CLK(DWMCI_SHIFT_0) |
-		DWMCI_SET_DRV_CLK(DWMCI_SHIFT_0) | DWMCI_SET_DIV_RATIO(0);
+	dwmci_writel(host, DWMCI_CLKSEL, host->clksel_val);
+}
 
-	dwmci_writel(host, DWMCI_CLKSEL, val);
+unsigned int exynos_dwmci_get_clk(int dev_index)
+{
+	return get_mmc_clk(dev_index);
 }
 
 int exynos_dwmci_init(u32 regbase, int bus_width, int index)
 {
 	struct dwmci_host *host = NULL;
+	int dev_id = 0;
 	host = malloc(sizeof(struct dwmci_host));
 	if (!host) {
 		printf("dwmci_host malloc fail!\n");
 		return 1;
 	}
+	/* Convert index into corresponding peripheral ID */
+	dev_id = index + PERIPH_ID_SDMMC0;
+
+	/* set the clock divisor - clk_div_fsys for mmc */
+	if (exynos5_mmc_set_clk_div(dev_id)) {
+		debug("mmc clock div set failed\n");
+		return -1;
+	}
 
 	host->name = EXYNOS_NAME;
 	host->ioaddr = (void *)regbase;
 	host->buswidth = bus_width;
+#ifdef CONFIG_OF_CONTROL
+	host->clksel_val = (DWMCI_SET_SAMPLE_CLK(timing[0]) |
+				DWMCI_SET_DRV_CLK(timing[1]) |
+				DWMCI_SET_DIV_RATIO(timing[2]));
+#else
+	if (0 == index)
+		host->clksel_val = DWMMC_MMC0_CLKSEL_VAL;
+	if (2 == index)
+		host->clksel_val = DWMMC_MMC2_CLKSEL_VAL;
+#endif
 	host->clksel = exynos_dwmci_clksel;
 	host->dev_index = index;
-
-	add_dwmci(host, 52000000, 400000);
+	host->mmc_clk = exynos_dwmci_get_clk;
+	/* Add the mmc chennel to be registered with mmc core */
+	add_dwmci(host, DWMMC_MAX_FREQ, DWMMC_MIN_FREQ);
 
 	return 0;
 }
 
+#ifdef CONFIG_OF_CONTROL
+unsigned int exynos_dwmmc_init(const void *blob)
+{
+	u32 base;
+	int index, bus_width;
+	int node_list[DWMMC_MAX_CH_NUM];
+	int err = 0;
+	int dev_id, flag;
+	int count, i;
+
+	count = fdtdec_find_aliases_for_id(blob, "dwmmc",
+				COMPAT_SAMSUNG_EXYNOS5_DWMMC, node_list,
+				DWMMC_MAX_CH_NUM);
+
+	for (i = 0; i < count; i++) {
+		int node = node_list[i];
+
+		if (node <= 0)
+			continue;
+
+		/* Extract device id for each mmc channel */
+		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;
+
+		/* config pinmux for each mmc channel */
+		err = exynos_pinmux_config(dev_id, flag);
+		if (err) {
+			debug("DWMMC not configured\n");
+			return err;
+		}
+
+		index = 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);
+		if (err) {
+			debug("Can't get sdr-timings for divider\n");
+			return -1;
+		}
+		/* Initialise each mmc channel */
+		err =  exynos_dwmci_init(base, bus_width, index);
+		if (err) {
+			debug("Can't do dwmci init\n");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+#endif
diff --git a/include/dwmmc.h b/include/dwmmc.h
index c8b1d40..4a42849 100644
--- a/include/dwmmc.h
+++ b/include/dwmmc.h
@@ -123,6 +123,9 @@ 
 #define MSIZE(x)		((x) << 28)
 #define RX_WMARK(x)		((x) << 16)
 #define TX_WMARK(x)		(x)
+#define RX_WMARK_SHIFT		16
+#define RX_WMARK_MASK		(0xfff << RX_WMARK_SHIFT)
+
 
 #define DWMCI_IDMAC_OWN		(1 << 31)
 #define DWMCI_IDMAC_CH		(1 << 4)
@@ -144,6 +147,7 @@  struct dwmci_host {
 	unsigned int bus_hz;
 	int dev_index;
 	int buswidth;
+	u32 clksel_val;
 	u32 fifoth_val;
 	struct mmc *mmc;