Patchwork [U-Boot,v2,2/2] Tegra: MMC: Add DT support to MMC driver for all T20 boards

login
register
mail settings
Submitter Tom Warren
Date Feb. 11, 2013, 5:17 p.m.
Message ID <1360603051-29478-3-git-send-email-twarren@nvidia.com>
Download mbox | patch
Permalink /patch/219649/
State Superseded
Delegated to: Tom Warren
Headers show

Comments

Tom Warren - Feb. 11, 2013, 5:17 p.m.
tegra_mmc_init() now parses the DT info for bus width, WP/CD GPIOs, etc.
Tested on Seaboard, fully functional.

Tamonten boards (medcom-wide, plutux, and tec) use a different/new
dtsi file w/common settings.

Signed-off-by: Tom Warren <twarren@nvidia.com>
---
v2:
- all boards now call tegra_mmc_init once, w/no params
- count MMC controllers, not aliases
- AD boards (medcom/plutux/tec) use common tegra20-tamonten.dtsi

 arch/arm/include/asm/arch-tegra/mmc.h             |    2 +-
 arch/arm/include/asm/arch-tegra/tegra_mmc.h       |   13 +-
 board/avionic-design/common/tamonten.c            |    4 +-
 board/compal/paz00/paz00.c                        |   11 +-
 board/compulab/trimslice/trimslice.c              |    9 +-
 board/nvidia/harmony/harmony.c                    |   11 +-
 board/nvidia/seaboard/seaboard.c                  |   11 +-
 board/nvidia/whistler/whistler.c                  |    7 +-
 board/toradex/colibri_t20_iris/colibri_t20_iris.c |    2 +-
 drivers/mmc/tegra_mmc.c                           |  259 +++++++++++++--------
 include/configs/medcom-wide.h                     |    2 +
 include/configs/plutux.h                          |    2 +
 include/configs/tec.h                             |    2 +
 include/fdtdec.h                                  |    1 +
 lib/fdtdec.c                                      |    1 +
 15 files changed, 197 insertions(+), 140 deletions(-)
Lucas Stach - Feb. 11, 2013, 5:33 p.m.
Am Montag, den 11.02.2013, 10:17 -0700 schrieb Tom Warren:
> tegra_mmc_init() now parses the DT info for bus width, WP/CD GPIOs, etc.
> Tested on Seaboard, fully functional.
> 
> Tamonten boards (medcom-wide, plutux, and tec) use a different/new
> dtsi file w/common settings.
> 
> Signed-off-by: Tom Warren <twarren@nvidia.com>
> ---
> v2:
> - all boards now call tegra_mmc_init once, w/no params
> - count MMC controllers, not aliases
> - AD boards (medcom/plutux/tec) use common tegra20-tamonten.dtsi
> 
>  arch/arm/include/asm/arch-tegra/mmc.h             |    2 +-
>  arch/arm/include/asm/arch-tegra/tegra_mmc.h       |   13 +-
>  board/avionic-design/common/tamonten.c            |    4 +-
>  board/compal/paz00/paz00.c                        |   11 +-
>  board/compulab/trimslice/trimslice.c              |    9 +-
>  board/nvidia/harmony/harmony.c                    |   11 +-
>  board/nvidia/seaboard/seaboard.c                  |   11 +-
>  board/nvidia/whistler/whistler.c                  |    7 +-
>  board/toradex/colibri_t20_iris/colibri_t20_iris.c |    2 +-
>  drivers/mmc/tegra_mmc.c                           |  259 +++++++++++++--------
>  include/configs/medcom-wide.h                     |    2 +
>  include/configs/plutux.h                          |    2 +
>  include/configs/tec.h                             |    2 +
>  include/fdtdec.h                                  |    1 +
>  lib/fdtdec.c                                      |    1 +
>  15 files changed, 197 insertions(+), 140 deletions(-)
> 
[...]
> diff --git a/board/nvidia/harmony/harmony.c b/board/nvidia/harmony/harmony.c
> index 93430ed..fba06c2 100644
> --- a/board/nvidia/harmony/harmony.c
> +++ b/board/nvidia/harmony/harmony.c
> @@ -58,18 +58,13 @@ static void pin_mux_mmc(void)
>  /* this is a weak define that we are overriding */
>  int board_mmc_init(bd_t *bd)
>  {
> -	debug("board_mmc_init called\n");
> +	debug("%s called\n", __func__);
>  
>  	/* Enable muxes, etc. for SDMMC controllers */
>  	pin_mux_mmc();
>  
> -	debug("board_mmc_init: init SD slot J26\n");
> -	/* init dev 0, SD slot J26, with 8-bit bus */
> -	tegra_mmc_init(0, 8, GPIO_PI6, GPIO_PH2);
> -
> -	debug("board_mmc_init: init SD slot J5\n");
> -	/* init dev 2, SD slot J5, with 4-bit bus */
> -	tegra_mmc_init(2, 4, GPIO_PT3, GPIO_PI5);
> +	debug("%s: init MMC devs\n", __func__);
> +	tegra_mmc_init();
>  
tegra_mmc_init should not be called from every individual board file,
but from the common nvidia tegra board file. Only the pinmux should stay
in the individual board code, same thing as was done to all the other
functions like NAND and USB.
>  	return 0;
>  }
[...]

Regards,
Lucas
Tom Warren - Feb. 11, 2013, 5:59 p.m.
Lucas,

On Mon, Feb 11, 2013 at 10:33 AM, Lucas Stach <dev@lynxeye.de> wrote:
> Am Montag, den 11.02.2013, 10:17 -0700 schrieb Tom Warren:
>> tegra_mmc_init() now parses the DT info for bus width, WP/CD GPIOs, etc.
>> Tested on Seaboard, fully functional.
>>
>> Tamonten boards (medcom-wide, plutux, and tec) use a different/new
>> dtsi file w/common settings.
>>
>> Signed-off-by: Tom Warren <twarren@nvidia.com>
>> ---
>> v2:
>> - all boards now call tegra_mmc_init once, w/no params
>> - count MMC controllers, not aliases
>> - AD boards (medcom/plutux/tec) use common tegra20-tamonten.dtsi
>>
>>  arch/arm/include/asm/arch-tegra/mmc.h             |    2 +-
>>  arch/arm/include/asm/arch-tegra/tegra_mmc.h       |   13 +-
>>  board/avionic-design/common/tamonten.c            |    4 +-
>>  board/compal/paz00/paz00.c                        |   11 +-
>>  board/compulab/trimslice/trimslice.c              |    9 +-
>>  board/nvidia/harmony/harmony.c                    |   11 +-
>>  board/nvidia/seaboard/seaboard.c                  |   11 +-
>>  board/nvidia/whistler/whistler.c                  |    7 +-
>>  board/toradex/colibri_t20_iris/colibri_t20_iris.c |    2 +-
>>  drivers/mmc/tegra_mmc.c                           |  259 +++++++++++++--------
>>  include/configs/medcom-wide.h                     |    2 +
>>  include/configs/plutux.h                          |    2 +
>>  include/configs/tec.h                             |    2 +
>>  include/fdtdec.h                                  |    1 +
>>  lib/fdtdec.c                                      |    1 +
>>  15 files changed, 197 insertions(+), 140 deletions(-)
>>
> [...]
>> diff --git a/board/nvidia/harmony/harmony.c b/board/nvidia/harmony/harmony.c
>> index 93430ed..fba06c2 100644
>> --- a/board/nvidia/harmony/harmony.c
>> +++ b/board/nvidia/harmony/harmony.c
>> @@ -58,18 +58,13 @@ static void pin_mux_mmc(void)
>>  /* this is a weak define that we are overriding */
>>  int board_mmc_init(bd_t *bd)
>>  {
>> -     debug("board_mmc_init called\n");
>> +     debug("%s called\n", __func__);
>>
>>       /* Enable muxes, etc. for SDMMC controllers */
>>       pin_mux_mmc();
>>
>> -     debug("board_mmc_init: init SD slot J26\n");
>> -     /* init dev 0, SD slot J26, with 8-bit bus */
>> -     tegra_mmc_init(0, 8, GPIO_PI6, GPIO_PH2);
>> -
>> -     debug("board_mmc_init: init SD slot J5\n");
>> -     /* init dev 2, SD slot J5, with 4-bit bus */
>> -     tegra_mmc_init(2, 4, GPIO_PT3, GPIO_PI5);
>> +     debug("%s: init MMC devs\n", __func__);
>> +     tegra_mmc_init();
>>
> tegra_mmc_init should not be called from every individual board file,
> but from the common nvidia tegra board file. Only the pinmux should stay
> in the individual board code, same thing as was done to all the other
> functions like NAND and USB.

True. I was originally just adapting the current config-file driven
MMC to DT step-by-step, but you're right - it should be called just
once for all boards in the common board file. I'll change it in V3.

Thanks,

Tom
>>       return 0;
>>  }
> [...]
>
> Regards,
> Lucas
>
Tom Warren - Feb. 12, 2013, 7:24 p.m.
Lucas,

On Mon, Feb 11, 2013 at 10:59 AM, Tom Warren <twarren.nvidia@gmail.com> wrote:
> Lucas,
>
> On Mon, Feb 11, 2013 at 10:33 AM, Lucas Stach <dev@lynxeye.de> wrote:
>> Am Montag, den 11.02.2013, 10:17 -0700 schrieb Tom Warren:
>>> tegra_mmc_init() now parses the DT info for bus width, WP/CD GPIOs, etc.
>>> Tested on Seaboard, fully functional.
>>>
>>> Tamonten boards (medcom-wide, plutux, and tec) use a different/new
>>> dtsi file w/common settings.
>>>
>>> Signed-off-by: Tom Warren <twarren@nvidia.com>
>>> ---
>>> v2:
>>> - all boards now call tegra_mmc_init once, w/no params
>>> - count MMC controllers, not aliases
>>> - AD boards (medcom/plutux/tec) use common tegra20-tamonten.dtsi
>>>
>>>  arch/arm/include/asm/arch-tegra/mmc.h             |    2 +-
>>>  arch/arm/include/asm/arch-tegra/tegra_mmc.h       |   13 +-
>>>  board/avionic-design/common/tamonten.c            |    4 +-
>>>  board/compal/paz00/paz00.c                        |   11 +-
>>>  board/compulab/trimslice/trimslice.c              |    9 +-
>>>  board/nvidia/harmony/harmony.c                    |   11 +-
>>>  board/nvidia/seaboard/seaboard.c                  |   11 +-
>>>  board/nvidia/whistler/whistler.c                  |    7 +-
>>>  board/toradex/colibri_t20_iris/colibri_t20_iris.c |    2 +-
>>>  drivers/mmc/tegra_mmc.c                           |  259 +++++++++++++--------
>>>  include/configs/medcom-wide.h                     |    2 +
>>>  include/configs/plutux.h                          |    2 +
>>>  include/configs/tec.h                             |    2 +
>>>  include/fdtdec.h                                  |    1 +
>>>  lib/fdtdec.c                                      |    1 +
>>>  15 files changed, 197 insertions(+), 140 deletions(-)
>>>
>> [...]
>>> diff --git a/board/nvidia/harmony/harmony.c b/board/nvidia/harmony/harmony.c
>>> index 93430ed..fba06c2 100644
>>> --- a/board/nvidia/harmony/harmony.c
>>> +++ b/board/nvidia/harmony/harmony.c
>>> @@ -58,18 +58,13 @@ static void pin_mux_mmc(void)
>>>  /* this is a weak define that we are overriding */
>>>  int board_mmc_init(bd_t *bd)
>>>  {
>>> -     debug("board_mmc_init called\n");
>>> +     debug("%s called\n", __func__);
>>>
>>>       /* Enable muxes, etc. for SDMMC controllers */
>>>       pin_mux_mmc();
>>>
>>> -     debug("board_mmc_init: init SD slot J26\n");
>>> -     /* init dev 0, SD slot J26, with 8-bit bus */
>>> -     tegra_mmc_init(0, 8, GPIO_PI6, GPIO_PH2);
>>> -
>>> -     debug("board_mmc_init: init SD slot J5\n");
>>> -     /* init dev 2, SD slot J5, with 4-bit bus */
>>> -     tegra_mmc_init(2, 4, GPIO_PT3, GPIO_PI5);
>>> +     debug("%s: init MMC devs\n", __func__);
>>> +     tegra_mmc_init();
>>>
>> tegra_mmc_init should not be called from every individual board file,
>> but from the common nvidia tegra board file. Only the pinmux should stay
>> in the individual board code, same thing as was done to all the other
>> functions like NAND and USB.
>
> True. I was originally just adapting the current config-file driven
> MMC to DT step-by-step, but you're right - it should be called just
> once for all boards in the common board file. I'll change it in V3.

I've looked into this some more, and it appears that I can't just add
a call to tegra_mmc_init() from board_init() in
boards/nvidia/common/board.c.

board_init() is where the other periphs do their pin_mux and
xxx_init() calls (USB, SPI, etc.).  board_init() is called early in
board_init_r(), before mmc_initialize() is called. mmc_initialize() is
needed before tegra_mmc_init() can use the mmc_device struct, etc. So
tegra_mmc_init() needs to be called after mmc_initialize(), and right
now that's in each board's board_mmc_init().  In board_mmc_init(),
each board sets up any power rails needed for SD-card or eMMC access,
sets up it's pin muxes for MMC, and then calls tegra_mmc_init() to
parse the DT file and populate the mmc structs.

I could move the pin_mux_mmc() function calls from each board file
into nvidia/common/board.c's board_init(), but it wouldn't really
change much. So I'll leave it as it is for now, with pin_mux_mmc() and
tegra_mmc_init() being called from each board's 'board' file
(seaboard.c, colibri_t20_iris.c, etc).

Let me know if you see another way to move Tegra MMC init to a common
board file that doesn't break the MMC driver flow.

Thanks,

Tom
>
> Thanks,
>
> Tom
>>>       return 0;
>>>  }
>> [...]
>>
>> Regards,
>> Lucas
>>
Lucas Stach - Feb. 12, 2013, 7:41 p.m.
Hello Tom,

Am Dienstag, den 12.02.2013, 12:24 -0700 schrieb Tom Warren:
> Lucas,

> >>>
> >> tegra_mmc_init should not be called from every individual board file,
> >> but from the common nvidia tegra board file. Only the pinmux should stay
> >> in the individual board code, same thing as was done to all the other
> >> functions like NAND and USB.
> >
> > True. I was originally just adapting the current config-file driven
> > MMC to DT step-by-step, but you're right - it should be called just
> > once for all boards in the common board file. I'll change it in V3.
> 
> I've looked into this some more, and it appears that I can't just add
> a call to tegra_mmc_init() from board_init() in
> boards/nvidia/common/board.c.
> 
> board_init() is where the other periphs do their pin_mux and
> xxx_init() calls (USB, SPI, etc.).  board_init() is called early in
> board_init_r(), before mmc_initialize() is called. mmc_initialize() is
> needed before tegra_mmc_init() can use the mmc_device struct, etc. So
> tegra_mmc_init() needs to be called after mmc_initialize(), and right
> now that's in each board's board_mmc_init().  In board_mmc_init(),
> each board sets up any power rails needed for SD-card or eMMC access,
> sets up it's pin muxes for MMC, and then calls tegra_mmc_init() to
> parse the DT file and populate the mmc structs.
> 
> I could move the pin_mux_mmc() function calls from each board file
> into nvidia/common/board.c's board_init(), but it wouldn't really
> change much. So I'll leave it as it is for now, with pin_mux_mmc() and
> tegra_mmc_init() being called from each board's 'board' file
> (seaboard.c, colibri_t20_iris.c, etc).
> 
> Let me know if you see another way to move Tegra MMC init to a common
> board file that doesn't break the MMC driver flow.
> 

I didn't look up the flow myself, as I don't have time for that right
now, but I think I've got a pretty good picture from your description.

I think we should really try to make the Tegra MMC init flow as similar
as possible to the other peripherals, so I suggest doing the following:
1. Provide a pin_mux_mmc() (possibly with a weak define as done with
other peripherals). Boards should do pinmux and rail enabling within
this function.
2. Move board_mmc_init() into nvidia/common/board.c, this function
should call into the board specific pinmux function and then call
tegra_mmc_init().

So even while we don't get the complete same flow as for other
peripherals as the board_mmc_init() still has to be a freestanding
function, instead of those things being folded into board_init(), we at
least gain a clear distinction between the board specific parts and
Tegra common code.

Regards,
Lucas
Tom Warren - Feb. 12, 2013, 7:50 p.m.
Lucas,

On Tue, Feb 12, 2013 at 12:41 PM, Lucas Stach <dev@lynxeye.de> wrote:
> Hello Tom,
>
> Am Dienstag, den 12.02.2013, 12:24 -0700 schrieb Tom Warren:
>> Lucas,
>
>> >>>
>> >> tegra_mmc_init should not be called from every individual board file,
>> >> but from the common nvidia tegra board file. Only the pinmux should stay
>> >> in the individual board code, same thing as was done to all the other
>> >> functions like NAND and USB.
>> >
>> > True. I was originally just adapting the current config-file driven
>> > MMC to DT step-by-step, but you're right - it should be called just
>> > once for all boards in the common board file. I'll change it in V3.
>>
>> I've looked into this some more, and it appears that I can't just add
>> a call to tegra_mmc_init() from board_init() in
>> boards/nvidia/common/board.c.
>>
>> board_init() is where the other periphs do their pin_mux and
>> xxx_init() calls (USB, SPI, etc.).  board_init() is called early in
>> board_init_r(), before mmc_initialize() is called. mmc_initialize() is
>> needed before tegra_mmc_init() can use the mmc_device struct, etc. So
>> tegra_mmc_init() needs to be called after mmc_initialize(), and right
>> now that's in each board's board_mmc_init().  In board_mmc_init(),
>> each board sets up any power rails needed for SD-card or eMMC access,
>> sets up it's pin muxes for MMC, and then calls tegra_mmc_init() to
>> parse the DT file and populate the mmc structs.
>>
>> I could move the pin_mux_mmc() function calls from each board file
>> into nvidia/common/board.c's board_init(), but it wouldn't really
>> change much. So I'll leave it as it is for now, with pin_mux_mmc() and
>> tegra_mmc_init() being called from each board's 'board' file
>> (seaboard.c, colibri_t20_iris.c, etc).
>>
>> Let me know if you see another way to move Tegra MMC init to a common
>> board file that doesn't break the MMC driver flow.
>>
>
> I didn't look up the flow myself, as I don't have time for that right
> now, but I think I've got a pretty good picture from your description.
Thanks for the quick response.

>
> I think we should really try to make the Tegra MMC init flow as similar
> as possible to the other peripherals, so I suggest doing the following:
> 1. Provide a pin_mux_mmc() (possibly with a weak define as done with
> other peripherals). Boards should do pinmux and rail enabling within
> this function.
(Almost) every Tegra board already has a pin_mux_mmc(). Few boards do
any power-rail enabling, but I can move those that do into
pin_mux_mmc().

> 2. Move board_mmc_init() into nvidia/common/board.c, this function
> should call into the board specific pinmux function and then call
> tegra_mmc_init().
Current board_mmc_init() does call pin_mux_mmc() and then
tegra_mmc_init(). Moving it from each board file into common/board.c
is a good idea. I'll try that.

Thanks
>
> So even while we don't get the complete same flow as for other
> peripherals as the board_mmc_init() still has to be a freestanding
> function, instead of those things being folded into board_init(), we at
> least gain a clear distinction between the board specific parts and
> Tegra common code.
>
> Regards,
> Lucas
>
Stephen Warren - Feb. 12, 2013, 8:38 p.m.
On 02/11/2013 10:17 AM, Tom Warren wrote:
> tegra_mmc_init() now parses the DT info for bus width, WP/CD GPIOs, etc.
> Tested on Seaboard, fully functional.
> 
> Tamonten boards (medcom-wide, plutux, and tec) use a different/new
> dtsi file w/common settings.

> diff --git a/drivers/mmc/tegra_mmc.c b/drivers/mmc/tegra_mmc.c

> +static int process_nodes(const void *blob, int node_list[], int count)
...
> +	/* build mmc_host[] for each controller */
> +	for (i = 0; i < count; i++) {
...
> +		/* Mark position as used */
> +		node_list[i] = -1;

Is that needed? Does anything use that array after this function?

> diff --git a/include/configs/medcom-wide.h b/include/configs/medcom-wide.h
> diff --git a/include/configs/plutux.h b/include/configs/plutux.h
> diff --git a/include/configs/tec.h b/include/configs/tec.h

In all 3 of those files ...

>  #define CONFIG_DEFAULT_DEVICE_TREE	tegra20-medcom-wide

Why not change that define ...

>  #define CONFIG_OF_CONTROL
>  #define CONFIG_OF_SEPARATE
> +#undef CONFIG_ARCH_DEVICE_TREE
> +#define CONFIG_ARCH_DEVICE_TREE		tegra20-tamonten

rather than adding that one? All the other Tegra boards only set
CONFIG_DEFAULT_DEVICE_TREE.

Aside from the few comments I and others have made, this series looks good.
Tom Warren - Feb. 12, 2013, 8:57 p.m.
Stephen,

On Tue, Feb 12, 2013 at 1:38 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 02/11/2013 10:17 AM, Tom Warren wrote:
>> tegra_mmc_init() now parses the DT info for bus width, WP/CD GPIOs, etc.
>> Tested on Seaboard, fully functional.
>>
>> Tamonten boards (medcom-wide, plutux, and tec) use a different/new
>> dtsi file w/common settings.
>
>> diff --git a/drivers/mmc/tegra_mmc.c b/drivers/mmc/tegra_mmc.c
>
>> +static int process_nodes(const void *blob, int node_list[], int count)
> ...
>> +     /* build mmc_host[] for each controller */
>> +     for (i = 0; i < count; i++) {
> ...
>> +             /* Mark position as used */
>> +             node_list[i] = -1;
>
> Is that needed? Does anything use that array after this function?
No idea. I took this code from the tegra_i2c.c driver.

>
>> diff --git a/include/configs/medcom-wide.h b/include/configs/medcom-wide.h
>> diff --git a/include/configs/plutux.h b/include/configs/plutux.h
>> diff --git a/include/configs/tec.h b/include/configs/tec.h
>
> In all 3 of those files ...
>
>>  #define CONFIG_DEFAULT_DEVICE_TREE   tegra20-medcom-wide
>
> Why not change that define ...
>
>>  #define CONFIG_OF_CONTROL
>>  #define CONFIG_OF_SEPARATE
>> +#undef CONFIG_ARCH_DEVICE_TREE
>> +#define CONFIG_ARCH_DEVICE_TREE              tegra20-tamonten
>
> rather than adding that one? All the other Tegra boards only set
> CONFIG_DEFAULT_DEVICE_TREE.

CONFIG_DEFAULT_DEVICE_TREE is the .dts file (board/nvidia/dts).
CONFIG_ARCH_DEVICE_TREE is the .dtsi file (arch/arm/dts). See
Thierry's explanation, also.

>
> Aside from the few comments I and others have made, this series looks good.
Thanks. Working on V3.
Stephen Warren - Feb. 12, 2013, 9:06 p.m.
On 02/12/2013 01:57 PM, Tom Warren wrote:
> Stephen,
> 
> On Tue, Feb 12, 2013 at 1:38 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>> On 02/11/2013 10:17 AM, Tom Warren wrote:
>>> tegra_mmc_init() now parses the DT info for bus width, WP/CD GPIOs, etc.
>>> Tested on Seaboard, fully functional.
>>>
>>> Tamonten boards (medcom-wide, plutux, and tec) use a different/new
>>> dtsi file w/common settings.

>>> diff --git a/include/configs/medcom-wide.h b/include/configs/medcom-wide.h
>>> diff --git a/include/configs/plutux.h b/include/configs/plutux.h
>>> diff --git a/include/configs/tec.h b/include/configs/tec.h
>>
>> In all 3 of those files ...
>>
>>>  #define CONFIG_DEFAULT_DEVICE_TREE   tegra20-medcom-wide
>>
>> Why not change that define ...
>>
>>>  #define CONFIG_OF_CONTROL
>>>  #define CONFIG_OF_SEPARATE
>>> +#undef CONFIG_ARCH_DEVICE_TREE
>>> +#define CONFIG_ARCH_DEVICE_TREE              tegra20-tamonten
>>
>> rather than adding that one? All the other Tegra boards only set
>> CONFIG_DEFAULT_DEVICE_TREE.
> 
> CONFIG_DEFAULT_DEVICE_TREE is the .dts file (board/nvidia/dts).
> CONFIG_ARCH_DEVICE_TREE is the .dtsi file (arch/arm/dts). See
> Thierry's explanation, also.

So why set CONFIG_ARCH_DEVICE_TREE to tegra20-tamonten here; if that
variable is supposed to point at the SoC .dtsi file, that value is
wrong; it *should* be tegra20.dtsi.

Oh yuck. I see what's going on now. e.g. tegra20-medcom-wide.dts is
including ARCH_CPU_DTS. It should be including tegra20-tamonten.dtsi,
which then includes ARCH_CPU_DTS. The ARCH_CPU_DTS variable is supposed
to only ever point at the SoC .dtsi file, not any "intermediate" .dtsi
file... You probably need to put tegra20-tamonten.dtsi into
board/avionic-design/dts rather than arch/arm/dts to make that work.
Tom Warren - Feb. 13, 2013, 7:59 p.m.
Stephen,

On Tue, Feb 12, 2013 at 2:06 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 02/12/2013 01:57 PM, Tom Warren wrote:
>> Stephen,
>>
>> On Tue, Feb 12, 2013 at 1:38 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>>> On 02/11/2013 10:17 AM, Tom Warren wrote:
>>>> tegra_mmc_init() now parses the DT info for bus width, WP/CD GPIOs, etc.
>>>> Tested on Seaboard, fully functional.
>>>>
>>>> Tamonten boards (medcom-wide, plutux, and tec) use a different/new
>>>> dtsi file w/common settings.
>
>>>> diff --git a/include/configs/medcom-wide.h b/include/configs/medcom-wide.h
>>>> diff --git a/include/configs/plutux.h b/include/configs/plutux.h
>>>> diff --git a/include/configs/tec.h b/include/configs/tec.h
>>>
>>> In all 3 of those files ...
>>>
>>>>  #define CONFIG_DEFAULT_DEVICE_TREE   tegra20-medcom-wide
>>>
>>> Why not change that define ...
>>>
>>>>  #define CONFIG_OF_CONTROL
>>>>  #define CONFIG_OF_SEPARATE
>>>> +#undef CONFIG_ARCH_DEVICE_TREE
>>>> +#define CONFIG_ARCH_DEVICE_TREE              tegra20-tamonten
>>>
>>> rather than adding that one? All the other Tegra boards only set
>>> CONFIG_DEFAULT_DEVICE_TREE.
>>
>> CONFIG_DEFAULT_DEVICE_TREE is the .dts file (board/nvidia/dts).
>> CONFIG_ARCH_DEVICE_TREE is the .dtsi file (arch/arm/dts). See
>> Thierry's explanation, also.
>
> So why set CONFIG_ARCH_DEVICE_TREE to tegra20-tamonten here; if that
> variable is supposed to point at the SoC .dtsi file, that value is
> wrong; it *should* be tegra20.dtsi.
>
> Oh yuck. I see what's going on now. e.g. tegra20-medcom-wide.dts is
> including ARCH_CPU_DTS. It should be including tegra20-tamonten.dtsi,
> which then includes ARCH_CPU_DTS. The ARCH_CPU_DTS variable is supposed
> to only ever point at the SoC .dtsi file, not any "intermediate" .dtsi
> file... You probably need to put tegra20-tamonten.dtsi into
> board/avionic-design/dts rather than arch/arm/dts to make that work.

OK, I've removed the overrides for CONFIG_ARCH_DEVICE_TREE in the AD
config files, and added 'tegra20-tamonten.dtsi' to the include line in
the AD .dts files. I have to add an include path to the DTC command
line in dts/Makefile so it can find tegra20-tamonten.dtsi in
arch/$(ARCH)/dts, but it all builds fine. I'll have to rely on Thierry
for testing. This will all be in v3, going up today or tomorrow.

Thanks,

Tom
Stephen Warren - Feb. 13, 2013, 8:02 p.m.
On 02/13/2013 12:59 PM, Tom Warren wrote:
> Stephen,
> 
> On Tue, Feb 12, 2013 at 2:06 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>> On 02/12/2013 01:57 PM, Tom Warren wrote:
>>> Stephen,
>>>
>>> On Tue, Feb 12, 2013 at 1:38 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>>>> On 02/11/2013 10:17 AM, Tom Warren wrote:
>>>>> tegra_mmc_init() now parses the DT info for bus width, WP/CD GPIOs, etc.
>>>>> Tested on Seaboard, fully functional.
>>>>>
>>>>> Tamonten boards (medcom-wide, plutux, and tec) use a different/new
>>>>> dtsi file w/common settings.
>>
>>>>> diff --git a/include/configs/medcom-wide.h b/include/configs/medcom-wide.h
>>>>> diff --git a/include/configs/plutux.h b/include/configs/plutux.h
>>>>> diff --git a/include/configs/tec.h b/include/configs/tec.h
>>>>
>>>> In all 3 of those files ...
>>>>
>>>>>  #define CONFIG_DEFAULT_DEVICE_TREE   tegra20-medcom-wide
>>>>
>>>> Why not change that define ...
>>>>
>>>>>  #define CONFIG_OF_CONTROL
>>>>>  #define CONFIG_OF_SEPARATE
>>>>> +#undef CONFIG_ARCH_DEVICE_TREE
>>>>> +#define CONFIG_ARCH_DEVICE_TREE              tegra20-tamonten
>>>>
>>>> rather than adding that one? All the other Tegra boards only set
>>>> CONFIG_DEFAULT_DEVICE_TREE.
>>>
>>> CONFIG_DEFAULT_DEVICE_TREE is the .dts file (board/nvidia/dts).
>>> CONFIG_ARCH_DEVICE_TREE is the .dtsi file (arch/arm/dts). See
>>> Thierry's explanation, also.
>>
>> So why set CONFIG_ARCH_DEVICE_TREE to tegra20-tamonten here; if that
>> variable is supposed to point at the SoC .dtsi file, that value is
>> wrong; it *should* be tegra20.dtsi.
>>
>> Oh yuck. I see what's going on now. e.g. tegra20-medcom-wide.dts is
>> including ARCH_CPU_DTS. It should be including tegra20-tamonten.dtsi,
>> which then includes ARCH_CPU_DTS. The ARCH_CPU_DTS variable is supposed
>> to only ever point at the SoC .dtsi file, not any "intermediate" .dtsi
>> file... You probably need to put tegra20-tamonten.dtsi into
>> board/avionic-design/dts rather than arch/arm/dts to make that work.
> 
> OK, I've removed the overrides for CONFIG_ARCH_DEVICE_TREE in the AD
> config files, and added 'tegra20-tamonten.dtsi' to the include line in
> the AD .dts files.

Great.

> I have to add an include path to the DTC command
> line in dts/Makefile so it can find tegra20-tamonten.dtsi in
> arch/$(ARCH)/dts, but it all builds fine.

If you move tegra20-tamonten.dtsi to boards/avionic-design/dts, do you
still need an include path? Since that file is board-/vendor-specific,
it really shouldn't be in arch/arm/dts if that directory typically only
contains SoC .dtsi files.
Tom Warren - Feb. 13, 2013, 8:06 p.m.
Stephen,

On Wed, Feb 13, 2013 at 1:02 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 02/13/2013 12:59 PM, Tom Warren wrote:
>> Stephen,
>>
>> On Tue, Feb 12, 2013 at 2:06 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>>> On 02/12/2013 01:57 PM, Tom Warren wrote:
>>>> Stephen,
>>>>
>>>> On Tue, Feb 12, 2013 at 1:38 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>>>>> On 02/11/2013 10:17 AM, Tom Warren wrote:
>>>>>> tegra_mmc_init() now parses the DT info for bus width, WP/CD GPIOs, etc.
>>>>>> Tested on Seaboard, fully functional.
>>>>>>
>>>>>> Tamonten boards (medcom-wide, plutux, and tec) use a different/new
>>>>>> dtsi file w/common settings.
>>>
>>>>>> diff --git a/include/configs/medcom-wide.h b/include/configs/medcom-wide.h
>>>>>> diff --git a/include/configs/plutux.h b/include/configs/plutux.h
>>>>>> diff --git a/include/configs/tec.h b/include/configs/tec.h
>>>>>
>>>>> In all 3 of those files ...
>>>>>
>>>>>>  #define CONFIG_DEFAULT_DEVICE_TREE   tegra20-medcom-wide
>>>>>
>>>>> Why not change that define ...
>>>>>
>>>>>>  #define CONFIG_OF_CONTROL
>>>>>>  #define CONFIG_OF_SEPARATE
>>>>>> +#undef CONFIG_ARCH_DEVICE_TREE
>>>>>> +#define CONFIG_ARCH_DEVICE_TREE              tegra20-tamonten
>>>>>
>>>>> rather than adding that one? All the other Tegra boards only set
>>>>> CONFIG_DEFAULT_DEVICE_TREE.
>>>>
>>>> CONFIG_DEFAULT_DEVICE_TREE is the .dts file (board/nvidia/dts).
>>>> CONFIG_ARCH_DEVICE_TREE is the .dtsi file (arch/arm/dts). See
>>>> Thierry's explanation, also.
>>>
>>> So why set CONFIG_ARCH_DEVICE_TREE to tegra20-tamonten here; if that
>>> variable is supposed to point at the SoC .dtsi file, that value is
>>> wrong; it *should* be tegra20.dtsi.
>>>
>>> Oh yuck. I see what's going on now. e.g. tegra20-medcom-wide.dts is
>>> including ARCH_CPU_DTS. It should be including tegra20-tamonten.dtsi,
>>> which then includes ARCH_CPU_DTS. The ARCH_CPU_DTS variable is supposed
>>> to only ever point at the SoC .dtsi file, not any "intermediate" .dtsi
>>> file... You probably need to put tegra20-tamonten.dtsi into
>>> board/avionic-design/dts rather than arch/arm/dts to make that work.
>>
>> OK, I've removed the overrides for CONFIG_ARCH_DEVICE_TREE in the AD
>> config files, and added 'tegra20-tamonten.dtsi' to the include line in
>> the AD .dts files.
>
> Great.
>
>> I have to add an include path to the DTC command
>> line in dts/Makefile so it can find tegra20-tamonten.dtsi in
>> arch/$(ARCH)/dts, but it all builds fine.
>
> If you move tegra20-tamonten.dtsi to boards/avionic-design/dts, do you
> still need an include path? Since that file is board-/vendor-specific,
> it really shouldn't be in arch/arm/dts if that directory typically only
> contains SoC .dtsi files.
I tried both places, and had to add the include path to get it to build.

I'll try it from board/avionic-design/dts with a new include path.

Tom
Stephen Warren - Feb. 13, 2013, 8:09 p.m.
On 02/13/2013 01:06 PM, Tom Warren wrote:
> Stephen,
> 
> On Wed, Feb 13, 2013 at 1:02 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>> On 02/13/2013 12:59 PM, Tom Warren wrote:
>>> Stephen,
>>>
>>> On Tue, Feb 12, 2013 at 2:06 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>>>> On 02/12/2013 01:57 PM, Tom Warren wrote:
>>>>> Stephen,
>>>>>
>>>>> On Tue, Feb 12, 2013 at 1:38 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>>>>>> On 02/11/2013 10:17 AM, Tom Warren wrote:
>>>>>>> tegra_mmc_init() now parses the DT info for bus width, WP/CD GPIOs, etc.
>>>>>>> Tested on Seaboard, fully functional.
>>>>>>>
>>>>>>> Tamonten boards (medcom-wide, plutux, and tec) use a different/new
>>>>>>> dtsi file w/common settings.
>>>>
>>>>>>> diff --git a/include/configs/medcom-wide.h b/include/configs/medcom-wide.h
>>>>>>> diff --git a/include/configs/plutux.h b/include/configs/plutux.h
>>>>>>> diff --git a/include/configs/tec.h b/include/configs/tec.h
>>>>>>
>>>>>> In all 3 of those files ...
>>>>>>
>>>>>>>  #define CONFIG_DEFAULT_DEVICE_TREE   tegra20-medcom-wide
>>>>>>
>>>>>> Why not change that define ...
>>>>>>
>>>>>>>  #define CONFIG_OF_CONTROL
>>>>>>>  #define CONFIG_OF_SEPARATE
>>>>>>> +#undef CONFIG_ARCH_DEVICE_TREE
>>>>>>> +#define CONFIG_ARCH_DEVICE_TREE              tegra20-tamonten
>>>>>>
>>>>>> rather than adding that one? All the other Tegra boards only set
>>>>>> CONFIG_DEFAULT_DEVICE_TREE.
>>>>>
>>>>> CONFIG_DEFAULT_DEVICE_TREE is the .dts file (board/nvidia/dts).
>>>>> CONFIG_ARCH_DEVICE_TREE is the .dtsi file (arch/arm/dts). See
>>>>> Thierry's explanation, also.
>>>>
>>>> So why set CONFIG_ARCH_DEVICE_TREE to tegra20-tamonten here; if that
>>>> variable is supposed to point at the SoC .dtsi file, that value is
>>>> wrong; it *should* be tegra20.dtsi.
>>>>
>>>> Oh yuck. I see what's going on now. e.g. tegra20-medcom-wide.dts is
>>>> including ARCH_CPU_DTS. It should be including tegra20-tamonten.dtsi,
>>>> which then includes ARCH_CPU_DTS. The ARCH_CPU_DTS variable is supposed
>>>> to only ever point at the SoC .dtsi file, not any "intermediate" .dtsi
>>>> file... You probably need to put tegra20-tamonten.dtsi into
>>>> board/avionic-design/dts rather than arch/arm/dts to make that work.
>>>
>>> OK, I've removed the overrides for CONFIG_ARCH_DEVICE_TREE in the AD
>>> config files, and added 'tegra20-tamonten.dtsi' to the include line in
>>> the AD .dts files.
>>
>> Great.
>>
>>> I have to add an include path to the DTC command
>>> line in dts/Makefile so it can find tegra20-tamonten.dtsi in
>>> arch/$(ARCH)/dts, but it all builds fine.
>>
>> If you move tegra20-tamonten.dtsi to boards/avionic-design/dts, do you
>> still need an include path? Since that file is board-/vendor-specific,
>> it really shouldn't be in arch/arm/dts if that directory typically only
>> contains SoC .dtsi files.
>
> I tried both places, and had to add the include path to get it to build.
> 
> I'll try it from board/avionic-design/dts with a new include path.

Hmmm. Odd.

Since IIRC U-Boot is already running the .dts files through the C
pre-processor, you could try:

#include "tegra20-tamonten.dtsi"

rather than:

/include/ "tegra20-tamonten.dtsi";

The kernel is likely moving to this scheme, so U-Boot might want to
follow this, even pre-emptively, in order to re-use DT files sometime
anyway.

Patch

diff --git a/arch/arm/include/asm/arch-tegra/mmc.h b/arch/arm/include/asm/arch-tegra/mmc.h
index 5c95047..71ad407 100644
--- a/arch/arm/include/asm/arch-tegra/mmc.h
+++ b/arch/arm/include/asm/arch-tegra/mmc.h
@@ -22,6 +22,6 @@ 
 #ifndef _TEGRA_MMC_H_
 #define _TEGRA_MMC_H_
 
-int tegra_mmc_init(int dev_index, int bus_width, int pwr_gpio, int cd_gpio);
+void tegra_mmc_init(void);
 
 #endif /* _TEGRA_MMC_H_ */
diff --git a/arch/arm/include/asm/arch-tegra/tegra_mmc.h b/arch/arm/include/asm/arch-tegra/tegra_mmc.h
index dd746ca..bd18f5f 100644
--- a/arch/arm/include/asm/arch-tegra/tegra_mmc.h
+++ b/arch/arm/include/asm/arch-tegra/tegra_mmc.h
@@ -27,6 +27,8 @@ 
 #define TEGRA_SDMMC3_BASE	0xC8000400
 #define TEGRA_SDMMC4_BASE	0xC8000600
 
+#define MAX_HOSTS		4	/* Max number of 'hosts'/controllers */
+
 #ifndef __ASSEMBLY__
 struct tegra_mmc {
 	unsigned int	sysad;		/* _SYSTEM_ADDRESS_0 */
@@ -119,12 +121,15 @@  struct tegra_mmc {
 
 struct mmc_host {
 	struct tegra_mmc *reg;
+	int id;			/* device id/number, 0-3 */
+	int enabled;		/* 1 to enable, 0 to disable */
+	int width;		/* Bus Width, 1, 4 or 8 */
+	enum periph_id mmc_id;	/* Peripheral ID: PERIPH_ID_... */
+	struct fdt_gpio_state cd_gpio;		/* Change Detect GPIO */
+	struct fdt_gpio_state pwr_gpio;		/* Power GPIO */
+	struct fdt_gpio_state wp_gpio;		/* Write Protect GPIO */
 	unsigned int version;	/* SDHCI spec. version */
 	unsigned int clock;	/* Current clock (MHz) */
-	unsigned int base;	/* Base address, SDMMC1/2/3/4 */
-	enum periph_id mmc_id;	/* Peripheral ID: PERIPH_ID_... */
-	int pwr_gpio;		/* Power GPIO */
-	int cd_gpio;		/* Change Detect GPIO */
 };
 
 #endif	/* __ASSEMBLY__ */
diff --git a/board/avionic-design/common/tamonten.c b/board/avionic-design/common/tamonten.c
index e6a932e..a7dd598 100644
--- a/board/avionic-design/common/tamonten.c
+++ b/board/avionic-design/common/tamonten.c
@@ -69,8 +69,8 @@  int board_mmc_init(bd_t *bd)
 	/* Enable muxes, etc. for SDMMC controllers */
 	pin_mux_mmc();
 
-	/* init dev 0, SD slot, with 4-bit bus */
-	tegra_mmc_init(0, 4, GPIO_PI6, GPIO_PH2);
+	/* init mmc devs */
+	tegra_mmc_init();
 
 	return 0;
 }
diff --git a/board/compal/paz00/paz00.c b/board/compal/paz00/paz00.c
index 1447f47..5bd72bb 100644
--- a/board/compal/paz00/paz00.c
+++ b/board/compal/paz00/paz00.c
@@ -55,18 +55,13 @@  static void pin_mux_mmc(void)
 /* this is a weak define that we are overriding */
 int board_mmc_init(bd_t *bd)
 {
-	debug("board_mmc_init called\n");
+	debug("%s called\n", __func__);
 
 	/* Enable muxes, etc. for SDMMC controllers */
 	pin_mux_mmc();
 
-	debug("board_mmc_init: init eMMC\n");
-	/* init dev 0, eMMC chip, with 8-bit bus */
-	tegra_mmc_init(0, 8, -1, -1);
-
-	debug("board_mmc_init: init SD slot\n");
-	/* init dev 3, SD slot, with 4-bit bus */
-	tegra_mmc_init(3, 4, GPIO_PV1, GPIO_PV5);
+	debug("%s: init MMC\n", __func__);
+	tegra_mmc_init();
 
 	return 0;
 }
diff --git a/board/compulab/trimslice/trimslice.c b/board/compulab/trimslice/trimslice.c
index 8f4dd09..020283c 100644
--- a/board/compulab/trimslice/trimslice.c
+++ b/board/compulab/trimslice/trimslice.c
@@ -64,16 +64,13 @@  static void pin_mux_mmc(void)
 /* this is a weak define that we are overriding */
 int board_mmc_init(bd_t *bd)
 {
-	debug("board_mmc_init called\n");
+	debug("%s called\n", __func__);
 
 	/* Enable muxes, etc. for SDMMC controllers */
 	pin_mux_mmc();
 
-	/* init dev 0 (SDMMC4), (micro-SD slot) with 4-bit bus */
-	tegra_mmc_init(0, 4, -1, GPIO_PP1);
-
-	/* init dev 3 (SDMMC1), (SD slot) with 4-bit bus */
-	tegra_mmc_init(3, 4, -1, -1);
+	/* init mmc devs */
+	tegra_mmc_init();
 
 	return 0;
 }
diff --git a/board/nvidia/harmony/harmony.c b/board/nvidia/harmony/harmony.c
index 93430ed..fba06c2 100644
--- a/board/nvidia/harmony/harmony.c
+++ b/board/nvidia/harmony/harmony.c
@@ -58,18 +58,13 @@  static void pin_mux_mmc(void)
 /* this is a weak define that we are overriding */
 int board_mmc_init(bd_t *bd)
 {
-	debug("board_mmc_init called\n");
+	debug("%s called\n", __func__);
 
 	/* Enable muxes, etc. for SDMMC controllers */
 	pin_mux_mmc();
 
-	debug("board_mmc_init: init SD slot J26\n");
-	/* init dev 0, SD slot J26, with 8-bit bus */
-	tegra_mmc_init(0, 8, GPIO_PI6, GPIO_PH2);
-
-	debug("board_mmc_init: init SD slot J5\n");
-	/* init dev 2, SD slot J5, with 4-bit bus */
-	tegra_mmc_init(2, 4, GPIO_PT3, GPIO_PI5);
+	debug("%s: init MMC devs\n", __func__);
+	tegra_mmc_init();
 
 	return 0;
 }
diff --git a/board/nvidia/seaboard/seaboard.c b/board/nvidia/seaboard/seaboard.c
index 3e33da0..fbc9d2e 100644
--- a/board/nvidia/seaboard/seaboard.c
+++ b/board/nvidia/seaboard/seaboard.c
@@ -65,18 +65,13 @@  static void pin_mux_mmc(void)
 /* this is a weak define that we are overriding */
 int board_mmc_init(bd_t *bd)
 {
-	debug("board_mmc_init called\n");
+	debug("%s called\n", __func__);
 
 	/* Enable muxes, etc. for SDMMC controllers */
 	pin_mux_mmc();
 
-	debug("board_mmc_init: init eMMC\n");
-	/* init dev 0, eMMC chip, with 8-bit bus */
-	tegra_mmc_init(0, 8, -1, -1);
-
-	debug("board_mmc_init: init SD slot\n");
-	/* init dev 1, SD slot, with 4-bit bus */
-	tegra_mmc_init(1, 4, GPIO_PI6, GPIO_PI5);
+	debug("%s: init MMC\n", __func__);
+	tegra_mmc_init();
 
 	return 0;
 }
diff --git a/board/nvidia/whistler/whistler.c b/board/nvidia/whistler/whistler.c
index 592cd6b..79fdbda 100644
--- a/board/nvidia/whistler/whistler.c
+++ b/board/nvidia/whistler/whistler.c
@@ -73,11 +73,8 @@  int board_mmc_init(bd_t *bd)
 	/* Enable muxes, etc. for SDMMC controllers */
 	pin_mux_mmc();
 
-	/* init dev 0 (SDMMC4), (J29 "HSMMC") with 8-bit bus */
-	tegra_mmc_init(0, 8, -1, -1);
-
-	/* init dev 1 (SDMMC3), (J40 "SDIO3") with 8-bit bus */
-	tegra_mmc_init(1, 8, -1, -1);
+	/* init MMC devs */
+	tegra_mmc_init();
 
 	return 0;
 }
diff --git a/board/toradex/colibri_t20_iris/colibri_t20_iris.c b/board/toradex/colibri_t20_iris/colibri_t20_iris.c
index e40a986..9cc7a87 100644
--- a/board/toradex/colibri_t20_iris/colibri_t20_iris.c
+++ b/board/toradex/colibri_t20_iris/colibri_t20_iris.c
@@ -39,7 +39,7 @@  int board_mmc_init(bd_t *bd)
 	funcmux_select(PERIPH_ID_SDMMC4, FUNCMUX_SDMMC4_ATB_GMA_4_BIT);
 	pinmux_tristate_disable(PINGRP_GMB);
 
-	tegra_mmc_init(0, 4, -1, GPIO_PC7);
+	tegra_mmc_init();
 
 	return 0;
 }
diff --git a/drivers/mmc/tegra_mmc.c b/drivers/mmc/tegra_mmc.c
index d749ab0..e8e8512 100644
--- a/drivers/mmc/tegra_mmc.c
+++ b/drivers/mmc/tegra_mmc.c
@@ -21,6 +21,7 @@ 
 
 #include <bouncebuf.h>
 #include <common.h>
+#include <fdtdec.h>
 #include <asm/gpio.h>
 #include <asm/io.h>
 #include <asm/arch/clock.h>
@@ -28,54 +29,23 @@ 
 #include <asm/arch-tegra/tegra_mmc.h>
 #include <mmc.h>
 
-/* support 4 mmc hosts */
-struct mmc mmc_dev[4];
-struct mmc_host mmc_host[4];
+DECLARE_GLOBAL_DATA_PTR;
 
+struct mmc mmc_dev[MAX_HOSTS];
+struct mmc_host mmc_host[MAX_HOSTS];
 
-/**
- * Get the host address and peripheral ID for a device. Devices are numbered
- * from 0 to 3.
- *
- * @param host		Structure to fill in (base, reg, mmc_id)
- * @param dev_index	Device index (0-3)
- */
-static void tegra_get_setup(struct mmc_host *host, int dev_index)
-{
-	debug("tegra_get_setup: dev_index = %d\n", dev_index);
-
-	switch (dev_index) {
-	case 1:
-		host->base = TEGRA_SDMMC3_BASE;
-		host->mmc_id = PERIPH_ID_SDMMC3;
-		break;
-	case 2:
-		host->base = TEGRA_SDMMC2_BASE;
-		host->mmc_id = PERIPH_ID_SDMMC2;
-		break;
-	case 3:
-		host->base = TEGRA_SDMMC1_BASE;
-		host->mmc_id = PERIPH_ID_SDMMC1;
-		break;
-	case 0:
-	default:
-		host->base = TEGRA_SDMMC4_BASE;
-		host->mmc_id = PERIPH_ID_SDMMC4;
-		break;
-	}
-
-	host->reg = (struct tegra_mmc *)host->base;
-}
+#ifndef CONFIG_OF_CONTROL
+#error "Please enable device tree support to use this driver"
+#endif
 
 static void mmc_prepare_data(struct mmc_host *host, struct mmc_data *data,
 				struct bounce_buffer *bbstate)
 {
 	unsigned char ctrl;
 
-
-	debug("buf: %p (%p), data->blocks: %u, data->blocksize: %u\n",
-		bbstate->bounce_buffer, bbstate->user_buffer, data->blocks,
-		data->blocksize);
+	debug("%s: buf: %p (%p), data->blocks: %u, data->blocksize: %u\n",
+		__func__, bbstate->bounce_buffer, bbstate->user_buffer,
+		data->blocks, data->blocksize);
 
 	writel((u32)bbstate->bounce_buffer, &host->reg->sysad);
 	/*
@@ -98,7 +68,7 @@  static void mmc_prepare_data(struct mmc_host *host, struct mmc_data *data,
 static void mmc_set_transfer_mode(struct mmc_host *host, struct mmc_data *data)
 {
 	unsigned short mode;
-	debug(" mmc_set_transfer_mode called\n");
+	debug("%s called\n", __func__);
 	/*
 	 * TRNMOD
 	 * MUL1SIN0[5]	: Multi/Single Block Select
@@ -121,10 +91,8 @@  static void mmc_set_transfer_mode(struct mmc_host *host, struct mmc_data *data)
 	writew(mode, &host->reg->trnmod);
 }
 
-static int mmc_wait_inhibit(struct mmc_host *host,
-			    struct mmc_cmd *cmd,
-			    struct mmc_data *data,
-			    unsigned int timeout)
+static int mmc_wait_inhibit(struct mmc_host *host, struct mmc_cmd *cmd,
+		struct mmc_data *data, unsigned int timeout)
 {
 	/*
 	 * PRNSTS
@@ -148,19 +116,18 @@  static int mmc_wait_inhibit(struct mmc_host *host,
 		timeout--;
 		udelay(1000);
 	}
-
 	return 0;
 }
 
 static int mmc_send_cmd_bounced(struct mmc *mmc, struct mmc_cmd *cmd,
-			struct mmc_data *data, struct bounce_buffer *bbstate)
+		struct mmc_data *data, struct bounce_buffer *bbstate)
 {
 	struct mmc_host *host = (struct mmc_host *)mmc->priv;
 	int flags, i;
 	int result;
 	unsigned int mask = 0;
 	unsigned int retry = 0x100000;
-	debug(" mmc_send_cmd called\n");
+	debug("%s called\n", __func__);
 
 	result = mmc_wait_inhibit(host, cmd, data, 10 /* ms */);
 
@@ -170,7 +137,7 @@  static int mmc_send_cmd_bounced(struct mmc *mmc, struct mmc_cmd *cmd,
 	if (data)
 		mmc_prepare_data(host, data, bbstate);
 
-	debug("cmd->arg: %08x\n", cmd->cmdarg);
+	debug("%s: cmd->arg: %08x\n", __func__, cmd->cmdarg);
 	writel(cmd->cmdarg, &host->reg->argument);
 
 	if (data)
@@ -207,7 +174,7 @@  static int mmc_send_cmd_bounced(struct mmc *mmc, struct mmc_cmd *cmd,
 	if (data)
 		flags |= TEGRA_MMC_TRNMOD_DATA_PRESENT_SELECT_DATA_TRANSFER;
 
-	debug("cmd: %d\n", cmd->cmdidx);
+	debug("%s: cmd: %d\n", __func__, cmd->cmdidx);
 
 	writew((cmd->cmdidx << 8) | flags, &host->reg->cmdreg);
 
@@ -229,12 +196,14 @@  static int mmc_send_cmd_bounced(struct mmc *mmc, struct mmc_cmd *cmd,
 
 	if (mask & TEGRA_MMC_NORINTSTS_CMD_TIMEOUT) {
 		/* Timeout Error */
-		debug("timeout: %08x cmd %d\n", mask, cmd->cmdidx);
+		debug("%s: timeout: %08x cmd %d\n", __func__, mask,
+			cmd->cmdidx);
 		writel(mask, &host->reg->norintsts);
 		return TIMEOUT;
 	} else if (mask & TEGRA_MMC_NORINTSTS_ERR_INTERRUPT) {
 		/* Error Interrupt */
-		debug("error: %08x cmd %d\n", mask, cmd->cmdidx);
+		debug("%s: error: %08x cmd %d\n", __func__, mask,
+			cmd->cmdidx);
 		writel(mask, &host->reg->norintsts);
 		return -1;
 	}
@@ -251,8 +220,8 @@  static int mmc_send_cmd_bounced(struct mmc *mmc, struct mmc_cmd *cmd,
 					cmd->response[i] |=
 						readb(offset - 1);
 				}
-				debug("cmd->resp[%d]: %08x\n",
-						i, cmd->response[i]);
+				debug("%s: cmd->resp[%d]: %08x\n",
+					__func__, i, cmd->response[i]);
 			}
 		} else if (cmd->resp_type & MMC_RSP_BUSY) {
 			for (i = 0; i < retry; i++) {
@@ -269,10 +238,12 @@  static int mmc_send_cmd_bounced(struct mmc *mmc, struct mmc_cmd *cmd,
 			}
 
 			cmd->response[0] = readl(&host->reg->rspreg0);
-			debug("cmd->resp[0]: %08x\n", cmd->response[0]);
+			debug("%s: cmd->resp[0]: %08x\n",
+				__func__, cmd->response[0]);
 		} else {
 			cmd->response[0] = readl(&host->reg->rspreg0);
-			debug("cmd->resp[0]: %08x\n", cmd->response[0]);
+			debug("%s: cmd->resp[0]: %08x\n",
+				__func__, cmd->response[0]);
 		}
 	}
 
@@ -295,13 +266,13 @@  static int mmc_send_cmd_bounced(struct mmc *mmc, struct mmc_cmd *cmd,
 				 */
 				unsigned int address = readl(&host->reg->sysad);
 
-				debug("DMA end\n");
+				debug("%s: DMA end\n", __func__);
 				writel(TEGRA_MMC_NORINTSTS_DMA_INTERRUPT,
-				       &host->reg->norintsts);
+					&host->reg->norintsts);
 				writel(address, &host->reg->sysad);
 			} else if (mask & TEGRA_MMC_NORINTSTS_XFER_COMPLETE) {
 				/* Transfer Complete */
-				debug("r/w is done\n");
+				debug("%s: r/w is done\n", __func__);
 				break;
 			} else if (get_timer(start) > 2000UL) {
 				writel(mask, &host->reg->norintsts);
@@ -325,13 +296,14 @@  static int mmc_send_cmd_bounced(struct mmc *mmc, struct mmc_cmd *cmd,
 }
 
 static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
-			struct mmc_data *data)
+		struct mmc_data *data)
 {
 	void *buf;
 	unsigned int bbflags;
 	size_t len;
 	struct bounce_buffer bbstate;
 	int ret;
+	debug("%s: called\n", __func__);
 
 	if (data) {
 		if (data->flags & MMC_DATA_READ) {
@@ -359,8 +331,7 @@  static void mmc_change_clock(struct mmc_host *host, uint clock)
 	int div;
 	unsigned short clk;
 	unsigned long timeout;
-
-	debug(" mmc_change_clock called\n");
+	debug("%s called\n", __func__);
 
 	/*
 	 * Change Tegra SDMMCx clock divisor here. Source is 216MHz,
@@ -368,9 +339,8 @@  static void mmc_change_clock(struct mmc_host *host, uint clock)
 	 */
 	if (clock == 0)
 		goto out;
-	clock_adjust_periph_pll_div(host->mmc_id, CLOCK_ID_PERIPH, clock,
-				    &div);
-	debug("div = %d\n", div);
+	clock_adjust_periph_pll_div(host->mmc_id, CLOCK_ID_PERIPH, clock, &div);
+	debug("%s: div = %d\n", __func__, div);
 
 	writew(0, &host->reg->clkcon);
 
@@ -383,7 +353,7 @@  static void mmc_change_clock(struct mmc_host *host, uint clock)
 	 */
 	div >>= 1;
 	clk = ((div << TEGRA_MMC_CLKCON_SDCLK_FREQ_SEL_SHIFT) |
-	       TEGRA_MMC_CLKCON_INTERNAL_CLOCK_ENABLE);
+		TEGRA_MMC_CLKCON_INTERNAL_CLOCK_ENABLE);
 	writew(clk, &host->reg->clkcon);
 
 	/* Wait max 10 ms */
@@ -401,7 +371,7 @@  static void mmc_change_clock(struct mmc_host *host, uint clock)
 	clk |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
 	writew(clk, &host->reg->clkcon);
 
-	debug("mmc_change_clock: clkcon = %08X\n", clk);
+	debug("%s: clkcon = %08X\n", __func__, clk);
 
 out:
 	host->clock = clock;
@@ -411,9 +381,8 @@  static void mmc_set_ios(struct mmc *mmc)
 {
 	struct mmc_host *host = mmc->priv;
 	unsigned char ctrl;
-	debug(" mmc_set_ios called\n");
-
-	debug("bus_width: %x, clock: %d\n", mmc->bus_width, mmc->clock);
+	debug("%s: bus_width: %x, clock: %d\n", __func__, mmc->bus_width,
+		mmc->clock);
 
 	/* Change clock first */
 	mmc_change_clock(host, mmc->clock);
@@ -436,13 +405,13 @@  static void mmc_set_ios(struct mmc *mmc)
 		ctrl &= ~(1 << 1);
 
 	writeb(ctrl, &host->reg->hostctl);
-	debug("mmc_set_ios: hostctl = %08X\n", ctrl);
+	debug("%s: hostctl = %08X\n", __func__, ctrl);
 }
 
 static void mmc_reset(struct mmc_host *host)
 {
 	unsigned int timeout;
-	debug(" mmc_reset called\n");
+	debug("%s called\n", __func__);
 
 	/*
 	 * RSTALL[0] : Software reset for all
@@ -471,12 +440,11 @@  static int mmc_core_init(struct mmc *mmc)
 {
 	struct mmc_host *host = (struct mmc_host *)mmc->priv;
 	unsigned int mask;
-	debug(" mmc_core_init called\n");
 
 	mmc_reset(host);
 
 	host->version = readw(&host->reg->hcver);
-	debug("host version = %x\n", host->version);
+	debug("%s: host version = %x\n", __func__, host->version);
 
 	/* mask all */
 	writel(0xffffffff, &host->reg->norintstsen);
@@ -515,44 +483,47 @@  static int mmc_core_init(struct mmc *mmc)
 int tegra_mmc_getcd(struct mmc *mmc)
 {
 	struct mmc_host *host = (struct mmc_host *)mmc->priv;
+	debug("%s called, host->cd_gpio = 0x%08X\n", __func__,
+		(unsigned)&host->cd_gpio);
 
-	debug("tegra_mmc_getcd called\n");
-
-	if (host->cd_gpio >= 0)
-		return !gpio_get_value(host->cd_gpio);
+	if (fdt_gpio_isvalid(&host->cd_gpio))
+		return !fdtdec_get_gpio(&host->cd_gpio);
 
 	return 1;
 }
 
-int tegra_mmc_init(int dev_index, int bus_width, int pwr_gpio, int cd_gpio)
+static int do_mmc_init(int dev_index)
 {
 	struct mmc_host *host;
 	char gpusage[12]; /* "SD/MMCn PWR" or "SD/MMCn CD" */
 	struct mmc *mmc;
+	int card_det = 0;
 
-	debug(" tegra_mmc_init: index %d, bus width %d "
-		"pwr_gpio %d cd_gpio %d\n",
-		dev_index, bus_width, pwr_gpio, cd_gpio);
-
+	/* DT should have been read & host config filled in */
 	host = &mmc_host[dev_index];
+	if (!host->enabled)
+		return -1;
 
-	host->clock = 0;
-	host->pwr_gpio = pwr_gpio;
-	host->cd_gpio = cd_gpio;
-	tegra_get_setup(host, dev_index);
+	debug("%s: index %d, bus width %d pwr_gpio %d cd_gpio %d\n",
+		__func__, dev_index, host->width,
+		host->pwr_gpio.gpio, host->cd_gpio.gpio);
 
+	host->clock = 0;
 	clock_start_periph_pll(host->mmc_id, CLOCK_ID_PERIPH, 20000000);
 
-	if (host->pwr_gpio >= 0) {
+	if (fdt_gpio_isvalid(&host->pwr_gpio)) {
 		sprintf(gpusage, "SD/MMC%d PWR", dev_index);
-		gpio_request(host->pwr_gpio, gpusage);
-		gpio_direction_output(host->pwr_gpio, 1);
+		gpio_request(host->pwr_gpio.gpio, gpusage);
+		fdtdec_set_gpio(&host->pwr_gpio, 1);
+		debug(" Power GPIO name = %s\n", host->pwr_gpio.name);
 	}
 
-	if (host->cd_gpio >= 0) {
+	if (fdt_gpio_isvalid(&host->cd_gpio)) {
 		sprintf(gpusage, "SD/MMC%d CD", dev_index);
-		gpio_request(host->cd_gpio, gpusage);
-		gpio_direction_input(host->cd_gpio);
+		gpio_request(host->cd_gpio.gpio, gpusage);
+		card_det = fdtdec_get_gpio(&host->cd_gpio);
+		debug(" CD GPIO name = %s\n", host->cd_gpio.name);
+		debug("%s: CD state = %d\n", __func__, card_det);
 	}
 
 	mmc = &mmc_dev[dev_index];
@@ -566,9 +537,10 @@  int tegra_mmc_init(int dev_index, int bus_width, int pwr_gpio, int cd_gpio)
 
 	mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
 	mmc->host_caps = 0;
-	if (bus_width == 8)
+	debug("%s: bus width = %d\n", __func__, host->width);
+	if (host->width == 8)
 		mmc->host_caps |= MMC_MODE_8BIT;
-	if (bus_width >= 4)
+	if (host->width >= 4)
 		mmc->host_caps |= MMC_MODE_4BIT;
 	mmc->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS | MMC_MODE_HC;
 
@@ -577,8 +549,6 @@  int tegra_mmc_init(int dev_index, int bus_width, int pwr_gpio, int cd_gpio)
 	 *  low-speed SDIO card frequency (actually 400KHz)
 	 * max freq is highest HS eMMC clock as per the SD/MMC spec
 	 *  (actually 52MHz)
-	 * Both of these are the closest equivalents w/216MHz source
-	 *  clock and Tegra SDMMC divisors.
 	 */
 	mmc->f_min = 375000;
 	mmc->f_max = 48000000;
@@ -587,3 +557,98 @@  int tegra_mmc_init(int dev_index, int bus_width, int pwr_gpio, int cd_gpio)
 
 	return 0;
 }
+
+/**
+ * Get the host address and peripheral ID for a node.
+ *
+ * @param blob		fdt blob
+ * @param node		Device index (0-3)
+ * @param host		Structure to fill in (reg, width, mmc_id)
+ */
+static int mmc_get_config(const void *blob, int node, struct mmc_host *host)
+{
+	debug("%s: node = %d\n", __func__, node);
+
+	host->enabled = fdtdec_get_is_enabled(blob, node);
+
+	host->reg = (struct tegra_mmc *)fdtdec_get_addr(blob, node, "reg");
+	if ((fdt_addr_t)host->reg == FDT_ADDR_T_NONE) {
+		debug("%s: no sdmmc base reg info found\n", __func__);
+		return -FDT_ERR_NOTFOUND;
+	}
+
+	host->mmc_id = clock_decode_periph_id(blob, node);
+	if (host->mmc_id == PERIPH_ID_NONE) {
+		debug("%s: could not decode periph id\n", __func__);
+		return -FDT_ERR_NOTFOUND;
+	}
+
+	/*
+	 * NOTE: mmc->bus_width is determined by mmc.c dynamically.
+	 * TBD: Override it with this value?
+	 */
+	host->width = fdtdec_get_int(blob, node, "bus-width", 0);
+	if (!host->width)
+		debug("%s: no sdmmc width found\n", __func__);
+
+	/* These GPIOs are optional */
+	fdtdec_decode_gpio(blob, node, "cd-gpios", &host->cd_gpio);
+	fdtdec_decode_gpio(blob, node, "wp-gpios", &host->wp_gpio);
+	fdtdec_decode_gpio(blob, node, "power-gpios", &host->pwr_gpio);
+
+	debug("%s: found controller at %p, width = %d, periph_id = %d\n",
+		__func__, host->reg, host->width, host->mmc_id);
+	return 0;
+}
+
+/*
+ * Process a list of nodes, adding them to our list of SDMMC ports.
+ *
+ * @param blob          fdt blob
+ * @param node_list     list of nodes to process (any <=0 are ignored)
+ * @param count         number of nodes to process
+ * @return 0 if ok, -1 on error
+ */
+static int process_nodes(const void *blob, int node_list[], int count)
+{
+	struct mmc_host *host;
+	int i, node;
+
+	debug("%s: count = %d\n", __func__, count);
+
+	/* build mmc_host[] for each controller */
+	for (i = 0; i < count; i++) {
+		node = node_list[i];
+		if (node <= 0)
+			continue;
+
+		host = &mmc_host[i];
+		host->id = i;
+
+		if (mmc_get_config(blob, node, host)) {
+			printf("%s: failed to decode dev %d\n",	__func__, i);
+			return -1;
+		}
+		do_mmc_init(i);
+
+		/* Mark position as used */
+		node_list[i] = -1;
+	}
+	return 0;
+}
+
+void tegra_mmc_init(void)
+{
+	int node_list[MAX_HOSTS], count;
+	const void *blob = gd->fdt_blob;
+	debug("%s entry\n", __func__);
+
+	count = fdtdec_find_aliases_for_id(blob, "sdhci",
+		COMPAT_NVIDIA_TEGRA20_SDMMC, node_list, MAX_HOSTS);
+	debug("%s: count of sdhci nodes is %d\n", __func__, count);
+
+	if (process_nodes(blob, node_list, count)) {
+		printf("%s: Error processing mmc node(s)!\n", __func__);
+		return;
+	}
+}
diff --git a/include/configs/medcom-wide.h b/include/configs/medcom-wide.h
index bae4ba0..c355993 100644
--- a/include/configs/medcom-wide.h
+++ b/include/configs/medcom-wide.h
@@ -32,6 +32,8 @@ 
 #define CONFIG_DEFAULT_DEVICE_TREE	tegra20-medcom-wide
 #define CONFIG_OF_CONTROL
 #define CONFIG_OF_SEPARATE
+#undef CONFIG_ARCH_DEVICE_TREE
+#define CONFIG_ARCH_DEVICE_TREE		tegra20-tamonten
 
 /* High-level configuration options */
 #define V_PROMPT			"Tegra20 (Medcom-Wide) # "
diff --git a/include/configs/plutux.h b/include/configs/plutux.h
index deee237..928a2ea 100644
--- a/include/configs/plutux.h
+++ b/include/configs/plutux.h
@@ -32,6 +32,8 @@ 
 #define CONFIG_DEFAULT_DEVICE_TREE	tegra20-plutux
 #define CONFIG_OF_CONTROL
 #define CONFIG_OF_SEPARATE
+#undef CONFIG_ARCH_DEVICE_TREE
+#define CONFIG_ARCH_DEVICE_TREE		tegra20-tamonten
 
 /* High-level configuration options */
 #define V_PROMPT			"Tegra20 (Plutux) # "
diff --git a/include/configs/tec.h b/include/configs/tec.h
index caeb9cd..9a340e3 100644
--- a/include/configs/tec.h
+++ b/include/configs/tec.h
@@ -32,6 +32,8 @@ 
 #define CONFIG_DEFAULT_DEVICE_TREE	tegra20-tec
 #define CONFIG_OF_CONTROL
 #define CONFIG_OF_SEPARATE
+#undef CONFIG_ARCH_DEVICE_TREE
+#define CONFIG_ARCH_DEVICE_TREE		tegra20-tamonten
 
 /* High-level configuration options */
 #define V_PROMPT			"Tegra20 (TEC) # "
diff --git a/include/fdtdec.h b/include/fdtdec.h
index c7a92d5..32730d2 100644
--- a/include/fdtdec.h
+++ b/include/fdtdec.h
@@ -71,6 +71,7 @@  enum fdt_compat_id {
 	COMPAT_NVIDIA_TEGRA20_NAND,	/* Tegra2 NAND controller */
 	COMPAT_NVIDIA_TEGRA20_PWM,	/* Tegra 2 PWM controller */
 	COMPAT_NVIDIA_TEGRA20_DC,	/* Tegra 2 Display controller */
+	COMPAT_NVIDIA_TEGRA20_SDMMC,	/* Tegra SDMMC controller */
 	COMPAT_NVIDIA_TEGRA20_SFLASH,	/* Tegra 2 SPI flash controller */
 	COMPAT_NVIDIA_TEGRA20_SLINK,	/* Tegra 2 SPI SLINK controller */
 	COMPAT_SMSC_LAN9215,		/* SMSC 10/100 Ethernet LAN9215 */
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index 7c7fc83..000130f 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -46,6 +46,7 @@  static const char * const compat_names[COMPAT_COUNT] = {
 	COMPAT(NVIDIA_TEGRA20_NAND, "nvidia,tegra20-nand"),
 	COMPAT(NVIDIA_TEGRA20_PWM, "nvidia,tegra20-pwm"),
 	COMPAT(NVIDIA_TEGRA20_DC, "nvidia,tegra20-dc"),
+	COMPAT(NVIDIA_TEGRA20_SDMMC, "nvidia,tegra20-sdhci"),
 	COMPAT(NVIDIA_TEGRA20_SFLASH, "nvidia,tegra20-sflash"),
 	COMPAT(NVIDIA_TEGRA20_SLINK, "nvidia,tegra20-slink"),
 	COMPAT(SMSC_LAN9215, "smsc,lan9215"),