[U-Boot] [PATCH v4 0/4] Tegra: MMC: Add DT support for MMC to T20 boards

This patchset adds device-tree support to the Tegra MMC driver. All device config is done via properties in the DT files instead of hard-coded config options/function arguments.
I've tested this on my Seaboard and everything works fine, including card detect. For the other T20 boards, I've used the Linux kernel DTS files for the sdhci nodes where there wasn't one already, or expanded the info that was already there. Everything builds fine, but I haven't tested anything but Seaboard.
v2: Changes as per Stephen's & Simon's review v3: Changes as per Stephen/Lucas/Thierry/Simon's feedback v4: Additional changes as per Stephen/Lucas/Thierry/Simon
Tom Warren (4): fdt: Add dts/dtsi file include paths to DTC command line Tegra: fdt: Add/enhance sdhci (mmc) nodes for all T20 DT files Tegra: fdt: tamonten: Add common tamonten.dtsi file from linux Tegra: MMC: Add DT support to MMC driver for all T20 boards
arch/arm/dts/tegra20.dtsi | 16 +- 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 | 19 +- board/avionic-design/dts/tegra20-medcom-wide.dts | 3 +- board/avionic-design/dts/tegra20-plutux.dts | 3 +- board/avionic-design/dts/tegra20-tamonten.dtsi | 489 +++++++++++++++++++++ board/avionic-design/dts/tegra20-tec.dts | 3 +- board/compal/dts/tegra20-paz00.dts | 19 +- board/compal/paz00/paz00.c | 26 +- board/compulab/dts/tegra20-trimslice.dts | 14 + board/compulab/trimslice/trimslice.c | 23 +- board/nvidia/common/board.c | 25 + board/nvidia/dts/tegra20-harmony.dts | 18 + board/nvidia/dts/tegra20-seaboard.dts | 10 +- board/nvidia/dts/tegra20-ventana.dts | 15 + board/nvidia/dts/tegra20-whistler.dts | 13 + board/nvidia/harmony/harmony.c | 26 +- board/nvidia/seaboard/seaboard.c | 25 +- board/nvidia/whistler/whistler.c | 30 +- board/toradex/colibri_t20_iris/colibri_t20_iris.c | 11 +- board/toradex/dts/tegra20-colibri_t20_iris.dts | 7 + drivers/mmc/tegra_mmc.c | 256 +++++++---- dts/Makefile | 2 +- include/fdtdec.h | 1 + lib/fdtdec.c | 1 + 26 files changed, 810 insertions(+), 260 deletions(-) create mode 100644 board/avionic-design/dts/tegra20-tamonten.dtsi

This requires a version of dtc that can handle the 'i' argument
Signed-off-by: Tom Warren twarren@nvidia.com --- v4: new
dts/Makefile | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/dts/Makefile b/dts/Makefile index 922c78c..2ef31e9 100644 --- a/dts/Makefile +++ b/dts/Makefile @@ -50,7 +50,7 @@ DT_BIN := $(obj)dt.dtb $(DT_BIN): $(TOPDIR)/board/$(VENDOR)/dts/$(DEVICE_TREE).dts rc=$$( \ cat $< | $(CPP) -P $(DTS_CPPFLAGS) - | \ - { { $(DTC) -R 4 -p 0x1000 -O dtb -o ${DT_BIN} - 2>&1 ; \ + { { $(DTC) -R 4 -p 0x1000 -i $(TOPDIR)/board/$(VENDOR)/dts -i $(TOPDIR)/arch/$(ARCH)/dts -O dtb -o ${DT_BIN} - 2>&1 ; \ echo $$? >&3 ; } | \ grep -v '^DTC: dts->dtb on file' ; \ } 3>&1 1>&2 ) ; \

Linux dts files were used for those boards that didn't already have sdhci info populated. Tamonten has their own dtsi file with common sdhci nodes (sourced from Linux).
Signed-off-by: Tom Warren twarren@nvidia.com Tested-by: Thierry Reding thierry.reding@avionic-design.de --- v2: - cleanup comments in dts files/match w/kernel files - add sdhci aliases in all dts files - use tegra20-tamonten.dtsi from the kernel for AD boards v3: - include tamonten.dtsi file directly in AD dts files - fix Seaboard power-gpios flags - add cd-gpios for Colibri T20 Iris - add include paths to DTC command v4: - move dts Makefile change to separate patch
arch/arm/dts/tegra20.dtsi | 16 ++++++++++++---- board/avionic-design/dts/tegra20-medcom-wide.dts | 3 ++- board/avionic-design/dts/tegra20-plutux.dts | 3 ++- board/avionic-design/dts/tegra20-tec.dts | 3 ++- board/compal/dts/tegra20-paz00.dts | 19 +++++++++++++++++-- board/compulab/dts/tegra20-trimslice.dts | 14 ++++++++++++++ board/nvidia/dts/tegra20-harmony.dts | 18 ++++++++++++++++++ board/nvidia/dts/tegra20-seaboard.dts | 10 +++++++--- board/nvidia/dts/tegra20-ventana.dts | 15 +++++++++++++++ board/nvidia/dts/tegra20-whistler.dts | 13 +++++++++++++ board/toradex/dts/tegra20-colibri_t20_iris.dts | 7 +++++++ 11 files changed, 109 insertions(+), 12 deletions(-)
diff --git a/arch/arm/dts/tegra20.dtsi b/arch/arm/dts/tegra20.dtsi index 9a89685..982a070 100644 --- a/arch/arm/dts/tegra20.dtsi +++ b/arch/arm/dts/tegra20.dtsi @@ -318,24 +318,32 @@ sdhci@c8000000 { compatible = "nvidia,tegra20-sdhci"; reg = <0xc8000000 0x200>; - interrupts = < 46 >; + interrupts = <0 14 0x04>; + clocks = <&tegra_car 14>; + status = "disabled"; };
sdhci@c8000200 { compatible = "nvidia,tegra20-sdhci"; reg = <0xc8000200 0x200>; - interrupts = < 47 >; + interrupts = <0 15 0x04>; + clocks = <&tegra_car 9>; + status = "disabled"; };
sdhci@c8000400 { compatible = "nvidia,tegra20-sdhci"; reg = <0xc8000400 0x200>; - interrupts = < 51 >; + interrupts = <0 19 0x04>; + clocks = <&tegra_car 69>; + status = "disabled"; };
sdhci@c8000600 { compatible = "nvidia,tegra20-sdhci"; reg = <0xc8000600 0x200>; - interrupts = < 63 >; + interrupts = <0 31 0x04>; + clocks = <&tegra_car 15>; + status = "disabled"; }; }; diff --git a/board/avionic-design/dts/tegra20-medcom-wide.dts b/board/avionic-design/dts/tegra20-medcom-wide.dts index e46afbe..01a4451 100644 --- a/board/avionic-design/dts/tegra20-medcom-wide.dts +++ b/board/avionic-design/dts/tegra20-medcom-wide.dts @@ -1,6 +1,6 @@ /dts-v1/;
-/include/ ARCH_CPU_DTS +/include/ "tegra20-tamonten.dtsi"
/ { model = "Avionic Design Medcom-Wide"; @@ -8,6 +8,7 @@
aliases { usb0 = "/usb@c5008000"; + sdhci0 = "/sdhci@c8000600"; };
memory { diff --git a/board/avionic-design/dts/tegra20-plutux.dts b/board/avionic-design/dts/tegra20-plutux.dts index 3e6cce0..f574542 100644 --- a/board/avionic-design/dts/tegra20-plutux.dts +++ b/board/avionic-design/dts/tegra20-plutux.dts @@ -1,6 +1,6 @@ /dts-v1/;
-/include/ ARCH_CPU_DTS +/include/ "tegra20-tamonten.dtsi"
/ { model = "Avionic Design Plutux"; @@ -8,6 +8,7 @@
aliases { usb0 = "/usb@c5008000"; + sdhci0 = "/sdhci@c8000600"; };
memory { diff --git a/board/avionic-design/dts/tegra20-tec.dts b/board/avionic-design/dts/tegra20-tec.dts index bf3ff1d..376d279 100644 --- a/board/avionic-design/dts/tegra20-tec.dts +++ b/board/avionic-design/dts/tegra20-tec.dts @@ -1,6 +1,6 @@ /dts-v1/;
-/include/ ARCH_CPU_DTS +/include/ "tegra20-tamonten.dtsi"
/ { model = "Avionic Design Tamonten Evaluation Carrier"; @@ -8,6 +8,7 @@
aliases { usb0 = "/usb@c5008000"; + sdhci0 = "/sdhci@c8000600"; };
memory { diff --git a/board/compal/dts/tegra20-paz00.dts b/board/compal/dts/tegra20-paz00.dts index 31b064d..6476940 100644 --- a/board/compal/dts/tegra20-paz00.dts +++ b/board/compal/dts/tegra20-paz00.dts @@ -3,11 +3,13 @@ /include/ ARCH_CPU_DTS
/ { - model = "Toshiba AC100 / Dynabook AZ"; - compatible = "compal,paz00", "nvidia,tegra20"; + model = "Toshiba AC100 / Dynabook AZ"; + compatible = "compal,paz00", "nvidia,tegra20";
aliases { usb0 = "/usb@c5008000"; + sdhci0 = "/sdhci@c8000600"; + sdhci1 = "/sdhci@c8000000"; };
memory { @@ -53,6 +55,19 @@ status = "disabled"; };
+ sdhci@c8000000 { + status = "okay"; + cd-gpios = <&gpio 173 0>; /* gpio PV5 */ + wp-gpios = <&gpio 57 0>; /* gpio PH1 */ + power-gpios = <&gpio 169 0>; /* gpio PV1 */ + bus-width = <4>; + }; + + sdhci@c8000600 { + status = "okay"; + bus-width = <8>; + }; + lcd_panel: panel { /* PAZ00 has 1024x600 */ clock = <54030000>; diff --git a/board/compulab/dts/tegra20-trimslice.dts b/board/compulab/dts/tegra20-trimslice.dts index 7aeed67..2957f45 100644 --- a/board/compulab/dts/tegra20-trimslice.dts +++ b/board/compulab/dts/tegra20-trimslice.dts @@ -9,6 +9,8 @@ aliases { usb0 = "/usb@c5008000"; usb1 = "/usb@c5000000"; + sdhci0 = "/sdhci@c8000600"; + sdhci1 = "/sdhci@c8000000"; };
memory { @@ -47,4 +49,16 @@ usb@c5004000 { status = "disabled"; }; + + sdhci@c8000000 { + status = "okay"; + bus-width = <4>; + }; + + sdhci@c8000600 { + status = "okay"; + cd-gpios = <&gpio 121 0>; /* gpio PP1 */ + wp-gpios = <&gpio 122 0>; /* gpio PP2 */ + bus-width = <4>; + }; }; diff --git a/board/nvidia/dts/tegra20-harmony.dts b/board/nvidia/dts/tegra20-harmony.dts index aeda3a1..593885d 100644 --- a/board/nvidia/dts/tegra20-harmony.dts +++ b/board/nvidia/dts/tegra20-harmony.dts @@ -9,6 +9,8 @@ aliases { usb0 = "/usb@c5008000"; usb1 = "/usb@c5004000"; + sdhci0 = "/sdhci@c8000600"; + sdhci1 = "/sdhci@c8000200"; };
memory { @@ -52,4 +54,20 @@ usb@c5004000 { nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */ }; + + sdhci@c8000200 { + status = "okay"; + cd-gpios = <&gpio 69 0>; /* gpio PI5 */ + wp-gpios = <&gpio 57 0>; /* gpio PH1 */ + power-gpios = <&gpio 155 0>; /* gpio PT3 */ + bus-width = <4>; + }; + + sdhci@c8000600 { + status = "okay"; + cd-gpios = <&gpio 58 0>; /* gpio PH2 */ + wp-gpios = <&gpio 59 0>; /* gpio PH3 */ + power-gpios = <&gpio 70 0>; /* gpio PI6 */ + bus-width = <8>; + }; }; diff --git a/board/nvidia/dts/tegra20-seaboard.dts b/board/nvidia/dts/tegra20-seaboard.dts index 527a296..4c10631 100644 --- a/board/nvidia/dts/tegra20-seaboard.dts +++ b/board/nvidia/dts/tegra20-seaboard.dts @@ -12,14 +12,15 @@ };
aliases { - /* This defines the order of our USB ports */ + /* This defines the order of our ports */ usb0 = "/usb@c5008000"; usb1 = "/usb@c5000000"; - i2c0 = "/i2c@7000d000"; i2c1 = "/i2c@7000c000"; i2c2 = "/i2c@7000c400"; i2c3 = "/i2c@7000c500"; + sdhci0 = "/sdhci@c8000600"; + sdhci1 = "/sdhci@c8000400"; };
memory { @@ -156,13 +157,16 @@ };
sdhci@c8000400 { + status = "okay"; cd-gpios = <&gpio 69 0>; /* gpio PI5 */ wp-gpios = <&gpio 57 0>; /* gpio PH1 */ power-gpios = <&gpio 70 0>; /* gpio PI6 */ + bus-width = <4>; };
sdhci@c8000600 { - support-8bit; + status = "okay"; + bus-width = <8>; };
lcd_panel: panel { diff --git a/board/nvidia/dts/tegra20-ventana.dts b/board/nvidia/dts/tegra20-ventana.dts index 3e5e39d..0423595 100644 --- a/board/nvidia/dts/tegra20-ventana.dts +++ b/board/nvidia/dts/tegra20-ventana.dts @@ -8,6 +8,8 @@
aliases { usb0 = "/usb@c5008000"; + sdhci0 = "/sdhci@c8000600"; + sdhci1 = "/sdhci@c8000400"; };
memory { @@ -41,4 +43,17 @@ usb@c5004000 { status = "disabled"; }; + + sdhci@c8000400 { + status = "okay"; + cd-gpios = <&gpio 69 0>; /* gpio PI5 */ + wp-gpios = <&gpio 57 0>; /* gpio PH1 */ + power-gpios = <&gpio 70 0>; /* gpio PI6 */ + bus-width = <4>; + }; + + sdhci@c8000600 { + status = "okay"; + bus-width = <8>; + }; }; diff --git a/board/nvidia/dts/tegra20-whistler.dts b/board/nvidia/dts/tegra20-whistler.dts index 4579557..2d0a2ab 100644 --- a/board/nvidia/dts/tegra20-whistler.dts +++ b/board/nvidia/dts/tegra20-whistler.dts @@ -9,6 +9,8 @@ aliases { i2c0 = "/i2c@7000d000"; usb0 = "/usb@c5008000"; + sdhci0 = "/sdhci@c8000600"; + sdhci1 = "/sdhci@c8000400"; };
memory { @@ -57,4 +59,15 @@ usb@c5004000 { status = "disabled"; }; + + sdhci@c8000400 { + status = "okay"; + wp-gpios = <&gpio 173 0>; /* gpio PV5 */ + bus-width = <8>; + }; + + sdhci@c8000600 { + status = "okay"; + bus-width = <8>; + }; }; diff --git a/board/toradex/dts/tegra20-colibri_t20_iris.dts b/board/toradex/dts/tegra20-colibri_t20_iris.dts index c29b43a..a2c5a0e 100644 --- a/board/toradex/dts/tegra20-colibri_t20_iris.dts +++ b/board/toradex/dts/tegra20-colibri_t20_iris.dts @@ -10,6 +10,7 @@ usb0 = "/usb@c5008000"; usb1 = "/usb@c5000000"; usb2 = "/usb@c5004000"; + sdhci0 = "/sdhci@c8000600"; };
usb@c5000000 { @@ -35,4 +36,10 @@ compatible = "nand-flash"; }; }; + + sdhci@c8000600 { + status = "okay"; + cd-gpios = <&gpio 23 0>; /* gpio PC7 */ + bus-width = <4>; + }; };

Tamonten boards (medcom-wide, plutux, and tec) use a different/new dtsi file w/common settings.
Signed-off-by: Tom Warren twarren@nvidia.com Acked-by: Thierry Reding thierry.reding@avionic-design.de --- v3: new v4: no change
board/avionic-design/dts/tegra20-tamonten.dtsi | 489 ++++++++++++++++++++++++ 1 files changed, 489 insertions(+), 0 deletions(-) create mode 100644 board/avionic-design/dts/tegra20-tamonten.dtsi
diff --git a/board/avionic-design/dts/tegra20-tamonten.dtsi b/board/avionic-design/dts/tegra20-tamonten.dtsi new file mode 100644 index 0000000..4766aba --- /dev/null +++ b/board/avionic-design/dts/tegra20-tamonten.dtsi @@ -0,0 +1,489 @@ +/include/ "tegra20.dtsi" + +/ { + model = "Avionic Design Tamonten SOM"; + compatible = "ad,tamonten", "nvidia,tegra20"; + + memory { + reg = <0x00000000 0x20000000>; + }; + + host1x { + hdmi { + vdd-supply = <&hdmi_vdd_reg>; + pll-supply = <&hdmi_pll_reg>; + + nvidia,ddc-i2c-bus = <&hdmi_ddc>; + nvidia,hpd-gpio = <&gpio 111 0>; /* PN7 */ + }; + }; + + pinmux { + pinctrl-names = "default"; + pinctrl-0 = <&state_default>; + + state_default: pinmux { + ata { + nvidia,pins = "ata"; + nvidia,function = "ide"; + }; + atb { + nvidia,pins = "atb", "gma", "gme"; + nvidia,function = "sdio4"; + }; + atc { + nvidia,pins = "atc"; + nvidia,function = "nand"; + }; + atd { + nvidia,pins = "atd", "ate", "gmb", "gmd", "gpu", + "spia", "spib", "spic"; + nvidia,function = "gmi"; + }; + cdev1 { + nvidia,pins = "cdev1"; + nvidia,function = "plla_out"; + }; + cdev2 { + nvidia,pins = "cdev2"; + nvidia,function = "pllp_out4"; + }; + crtp { + nvidia,pins = "crtp"; + nvidia,function = "crt"; + }; + csus { + nvidia,pins = "csus"; + nvidia,function = "vi_sensor_clk"; + }; + dap1 { + nvidia,pins = "dap1"; + nvidia,function = "dap1"; + }; + dap2 { + nvidia,pins = "dap2"; + nvidia,function = "dap2"; + }; + dap3 { + nvidia,pins = "dap3"; + nvidia,function = "dap3"; + }; + dap4 { + nvidia,pins = "dap4"; + nvidia,function = "dap4"; + }; + dta { + nvidia,pins = "dta", "dtd"; + nvidia,function = "sdio2"; + }; + dtb { + nvidia,pins = "dtb", "dtc", "dte"; + nvidia,function = "rsvd1"; + }; + dtf { + nvidia,pins = "dtf"; + nvidia,function = "i2c3"; + }; + gmc { + nvidia,pins = "gmc"; + nvidia,function = "uartd"; + }; + gpu7 { + nvidia,pins = "gpu7"; + nvidia,function = "rtck"; + }; + gpv { + nvidia,pins = "gpv", "slxa", "slxk"; + nvidia,function = "pcie"; + }; + hdint { + nvidia,pins = "hdint"; + nvidia,function = "hdmi"; + }; + i2cp { + nvidia,pins = "i2cp"; + nvidia,function = "i2cp"; + }; + irrx { + nvidia,pins = "irrx", "irtx"; + nvidia,function = "uarta"; + }; + kbca { + nvidia,pins = "kbca", "kbcb", "kbcc", "kbcd", + "kbce", "kbcf"; + nvidia,function = "kbc"; + }; + lcsn { + nvidia,pins = "lcsn", "ld0", "ld1", "ld2", + "ld3", "ld4", "ld5", "ld6", "ld7", + "ld8", "ld9", "ld10", "ld11", "ld12", + "ld13", "ld14", "ld15", "ld16", "ld17", + "ldc", "ldi", "lhp0", "lhp1", "lhp2", + "lhs", "lm0", "lm1", "lpp", "lpw0", + "lpw1", "lpw2", "lsc0", "lsc1", "lsck", + "lsda", "lsdi", "lspi", "lvp0", "lvp1", + "lvs"; + nvidia,function = "displaya"; + }; + owc { + nvidia,pins = "owc", "spdi", "spdo", "uac"; + nvidia,function = "rsvd2"; + }; + pmc { + nvidia,pins = "pmc"; + nvidia,function = "pwr_on"; + }; + rm { + nvidia,pins = "rm"; + nvidia,function = "i2c1"; + }; + sdb { + nvidia,pins = "sdb", "sdc", "sdd"; + nvidia,function = "pwm"; + }; + sdio1 { + nvidia,pins = "sdio1"; + nvidia,function = "sdio1"; + }; + slxc { + nvidia,pins = "slxc", "slxd"; + nvidia,function = "spdif"; + }; + spid { + nvidia,pins = "spid", "spie", "spif"; + nvidia,function = "spi1"; + }; + spig { + nvidia,pins = "spig", "spih"; + nvidia,function = "spi2_alt"; + }; + uaa { + nvidia,pins = "uaa", "uab", "uda"; + nvidia,function = "ulpi"; + }; + uad { + nvidia,pins = "uad"; + nvidia,function = "irda"; + }; + uca { + nvidia,pins = "uca", "ucb"; + nvidia,function = "uartc"; + }; + conf_ata { + nvidia,pins = "ata", "atb", "atc", "atd", "ate", + "cdev1", "cdev2", "dap1", "dtb", "gma", + "gmb", "gmc", "gmd", "gme", "gpu7", + "gpv", "i2cp", "pta", "rm", "slxa", + "slxk", "spia", "spib", "uac"; + nvidia,pull = <0>; + nvidia,tristate = <0>; + }; + conf_ck32 { + nvidia,pins = "ck32", "ddrc", "pmca", "pmcb", + "pmcc", "pmcd", "pmce", "xm2c", "xm2d"; + nvidia,pull = <0>; + }; + conf_csus { + nvidia,pins = "csus", "spid", "spif"; + nvidia,pull = <1>; + nvidia,tristate = <1>; + }; + conf_crtp { + nvidia,pins = "crtp", "dap2", "dap3", "dap4", + "dtc", "dte", "dtf", "gpu", "sdio1", + "slxc", "slxd", "spdi", "spdo", "spig", + "uda"; + nvidia,pull = <0>; + nvidia,tristate = <1>; + }; + conf_ddc { + nvidia,pins = "ddc", "dta", "dtd", "kbca", + "kbcb", "kbcc", "kbcd", "kbce", "kbcf", + "sdc"; + nvidia,pull = <2>; + nvidia,tristate = <0>; + }; + conf_hdint { + nvidia,pins = "hdint", "lcsn", "ldc", "lm1", + "lpw1", "lsc1", "lsck", "lsda", "lsdi", + "lvp0", "owc", "sdb"; + nvidia,tristate = <1>; + }; + conf_irrx { + nvidia,pins = "irrx", "irtx", "sdd", "spic", + "spie", "spih", "uaa", "uab", "uad", + "uca", "ucb"; + nvidia,pull = <2>; + nvidia,tristate = <1>; + }; + conf_lc { + nvidia,pins = "lc", "ls"; + nvidia,pull = <2>; + }; + conf_ld0 { + nvidia,pins = "ld0", "ld1", "ld2", "ld3", "ld4", + "ld5", "ld6", "ld7", "ld8", "ld9", + "ld10", "ld11", "ld12", "ld13", "ld14", + "ld15", "ld16", "ld17", "ldi", "lhp0", + "lhp1", "lhp2", "lhs", "lm0", "lpp", + "lpw0", "lpw2", "lsc0", "lspi", "lvp1", + "lvs", "pmc"; + nvidia,tristate = <0>; + }; + conf_ld17_0 { + nvidia,pins = "ld17_0", "ld19_18", "ld21_20", + "ld23_22"; + nvidia,pull = <1>; + }; + }; + + state_i2cmux_ddc: pinmux_i2cmux_ddc { + ddc { + nvidia,pins = "ddc"; + nvidia,function = "i2c2"; + }; + pta { + nvidia,pins = "pta"; + nvidia,function = "rsvd4"; + }; + }; + + state_i2cmux_pta: pinmux_i2cmux_pta { + ddc { + nvidia,pins = "ddc"; + nvidia,function = "rsvd4"; + }; + pta { + nvidia,pins = "pta"; + nvidia,function = "i2c2"; + }; + }; + + state_i2cmux_idle: pinmux_i2cmux_idle { + ddc { + nvidia,pins = "ddc"; + nvidia,function = "rsvd4"; + }; + pta { + nvidia,pins = "pta"; + nvidia,function = "rsvd4"; + }; + }; + }; + + i2s@70002800 { + status = "okay"; + }; + + serial@70006300 { + status = "okay"; + }; + + i2c@7000c000 { + clock-frequency = <400000>; + status = "okay"; + }; + + i2c@7000c400 { + clock-frequency = <100000>; + status = "okay"; + }; + + i2cmux { + compatible = "i2c-mux-pinctrl"; + #address-cells = <1>; + #size-cells = <0>; + + i2c-parent = <&{/i2c@7000c400}>; + + pinctrl-names = "ddc", "pta", "idle"; + pinctrl-0 = <&state_i2cmux_ddc>; + pinctrl-1 = <&state_i2cmux_pta>; + pinctrl-2 = <&state_i2cmux_idle>; + + hdmi_ddc: i2c@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + }; + + i2c@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + }; + }; + + i2c@7000d000 { + clock-frequency = <400000>; + status = "okay"; + + pmic: tps6586x@34 { + compatible = "ti,tps6586x"; + reg = <0x34>; + interrupts = <0 86 0x4>; + + ti,system-power-controller; + + #gpio-cells = <2>; + gpio-controller; + + sys-supply = <&vdd_5v0_reg>; + vin-sm0-supply = <&sys_reg>; + vin-sm1-supply = <&sys_reg>; + vin-sm2-supply = <&sys_reg>; + vinldo01-supply = <&sm2_reg>; + vinldo23-supply = <&sm2_reg>; + vinldo4-supply = <&sm2_reg>; + vinldo678-supply = <&sm2_reg>; + vinldo9-supply = <&sm2_reg>; + + regulators { + sys_reg: sys { + regulator-name = "vdd_sys"; + regulator-always-on; + }; + + sm0 { + regulator-name = "vdd_sys_sm0,vdd_core"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + }; + + sm1 { + regulator-name = "vdd_sys_sm1,vdd_cpu"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + }; + + sm2_reg: sm2 { + regulator-name = "vdd_sys_sm2,vin_ldo*"; + regulator-min-microvolt = <3700000>; + regulator-max-microvolt = <3700000>; + regulator-always-on; + }; + + ldo0 { + regulator-name = "vdd_ldo0,vddio_pex_clk"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + ldo1 { + regulator-name = "vdd_ldo1,avdd_pll*"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-always-on; + }; + + ldo2 { + regulator-name = "vdd_ldo2,vdd_rtc"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + }; + + ldo3 { + regulator-name = "vdd_ldo3,avdd_usb*"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + ldo4 { + regulator-name = "vdd_ldo4,avdd_osc,vddio_sys"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + }; + + ldo5 { + regulator-name = "vdd_ldo5,vcore_mmc"; + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2850000>; + }; + + ldo6 { + regulator-name = "vdd_ldo6,avdd_vdac"; + /* + * According to the Tegra 2 Automotive + * DataSheet, a typical value for this + * would be 2.8V, but the PMIC only + * supports 2.85V. + */ + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2850000>; + }; + + hdmi_vdd_reg: ldo7 { + regulator-name = "vdd_ldo7,avdd_hdmi"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + hdmi_pll_reg: ldo8 { + regulator-name = "vdd_ldo8,avdd_hdmi_pll"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + ldo9 { + regulator-name = "vdd_ldo9,vdd_ddr_rx,avdd_cam"; + /* + * According to the Tegra 2 Automotive + * DataSheet, a typical value for this + * would be 2.8V, but the PMIC only + * supports 2.85V. + */ + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2850000>; + regulator-always-on; + }; + + ldo_rtc { + regulator-name = "vdd_rtc_out"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + }; + }; + + temperature-sensor@4c { + compatible = "onnn,nct1008"; + reg = <0x4c>; + }; + }; + + pmc { + nvidia,invert-interrupt; + }; + + usb@c5008000 { + status = "okay"; + }; + + sdhci@c8000600 { + cd-gpios = <&gpio 58 0>; /* gpio PH2 */ + wp-gpios = <&gpio 59 0>; /* gpio PH3 */ + bus-width = <4>; + status = "okay"; + }; + + regulators { + compatible = "simple-bus"; + + #address-cells = <1>; + #size-cells = <0>; + + vdd_5v0_reg: regulator@0 { + compatible = "regulator-fixed"; + reg = <0>; + regulator-name = "vdd_5v0"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + }; + }; +};

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 Signed-off-by: Thierry Reding thierry.reding@avionic-design.de --- 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 v3: - move any power init inside board's pin_mux_mmc function, and/or create pin_mux_mmc function if necessary. - move board_mmc_init out of each board file and into ../common/board.c v4: - remove #ifdef CONFIG_TEGRA_MMC from trimslice.c - fix minor whitespace issue in board/nvidia/common/board.c - remove marking of used node_list entries in MMC driver, not needed
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 | 19 +-- board/compal/paz00/paz00.c | 26 +-- board/compulab/trimslice/trimslice.c | 23 +-- board/nvidia/common/board.c | 25 ++ board/nvidia/harmony/harmony.c | 26 +-- board/nvidia/seaboard/seaboard.c | 25 +-- board/nvidia/whistler/whistler.c | 30 +-- board/toradex/colibri_t20_iris/colibri_t20_iris.c | 11 +- drivers/mmc/tegra_mmc.c | 256 +++++++++++++-------- include/fdtdec.h | 1 + lib/fdtdec.c | 1 + 13 files changed, 211 insertions(+), 247 deletions(-)
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..ea95e43 100644 --- a/board/avionic-design/common/tamonten.c +++ b/board/avionic-design/common/tamonten.c @@ -33,13 +33,8 @@ #include <asm/arch/tegra.h> #include <asm/arch-tegra/board.h> #include <asm/arch-tegra/clk_rst.h> -#include <asm/arch-tegra/mmc.h> #include <asm/arch-tegra/sys_proto.h> #include <asm/arch-tegra/uart.h> -#ifdef CONFIG_TEGRA_MMC -#include <mmc.h> -#endif -
#ifdef CONFIG_BOARD_EARLY_INIT_F void gpio_early_init(void) @@ -54,7 +49,7 @@ void gpio_early_init(void) * Routine: pin_mux_mmc * Description: setup the pin muxes/tristate values for the SDMMC(s) */ -static void pin_mux_mmc(void) +void pin_mux_mmc(void) { funcmux_select(PERIPH_ID_SDMMC4, FUNCMUX_SDMMC4_ATB_GMA_GME_8_BIT); /* for write-protect GPIO PI6 */ @@ -62,16 +57,4 @@ static void pin_mux_mmc(void) /* for CD GPIO PH2 */ pinmux_tristate_disable(PINGRP_ATD); } - -/* this is a weak define that we are overriding */ -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); - - return 0; -} #endif diff --git a/board/compal/paz00/paz00.c b/board/compal/paz00/paz00.c index 1447f47..d6e5c37 100644 --- a/board/compal/paz00/paz00.c +++ b/board/compal/paz00/paz00.c @@ -18,19 +18,14 @@ #include <asm/io.h> #include <asm/arch/tegra.h> #include <asm/arch/pinmux.h> -#include <asm/arch-tegra/mmc.h> #include <asm/gpio.h> -#ifdef CONFIG_TEGRA_MMC -#include <mmc.h> -#endif -
#ifdef CONFIG_TEGRA_MMC /* * Routine: pin_mux_mmc * Description: setup the pin muxes/tristate values for the SDMMC(s) */ -static void pin_mux_mmc(void) +void pin_mux_mmc(void) { /* SDMMC4: config 3, x8 on 2nd set of pins */ pinmux_set_func(PINGRP_ATB, PMUX_FUNC_SDIO4); @@ -51,25 +46,6 @@ static void pin_mux_mmc(void) /* For CD GPIO PV5 */ pinmux_tristate_disable(PINGRP_GPV); } - -/* this is a weak define that we are overriding */ -int board_mmc_init(bd_t *bd) -{ - debug("board_mmc_init called\n"); - - /* 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); - - return 0; -} #endif
#ifdef CONFIG_LCD diff --git a/board/compulab/trimslice/trimslice.c b/board/compulab/trimslice/trimslice.c index 8f4dd09..8401100 100644 --- a/board/compulab/trimslice/trimslice.c +++ b/board/compulab/trimslice/trimslice.c @@ -27,12 +27,8 @@ #include <asm/arch/clock.h> #include <asm/arch/funcmux.h> #include <asm/arch/pinmux.h> -#include <asm/arch-tegra/mmc.h> #include <asm/gpio.h> #include <i2c.h> -#ifdef CONFIG_TEGRA_MMC -#include <mmc.h> -#endif
void pin_mux_usb(void) { @@ -52,7 +48,7 @@ void pin_mux_spi(void) * Routine: pin_mux_mmc * Description: setup the pin muxes/tristate values for the SDMMC(s) */ -static void pin_mux_mmc(void) +void pin_mux_mmc(void) { funcmux_select(PERIPH_ID_SDMMC1, FUNCMUX_SDMMC1_SDIO1_4BIT); funcmux_select(PERIPH_ID_SDMMC4, FUNCMUX_SDMMC4_ATB_GMA_4_BIT); @@ -60,20 +56,3 @@ static void pin_mux_mmc(void) /* For CD GPIO PP1 */ pinmux_tristate_disable(PINGRP_DAP3); } - -/* this is a weak define that we are overriding */ -int board_mmc_init(bd_t *bd) -{ - debug("board_mmc_init called\n"); - - /* 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); - - return 0; -} diff --git a/board/nvidia/common/board.c b/board/nvidia/common/board.c index d1d8a29..474a4a2 100644 --- a/board/nvidia/common/board.c +++ b/board/nvidia/common/board.c @@ -48,6 +48,9 @@ #ifdef CONFIG_USB_EHCI_TEGRA #include <asm/arch/usb.h> #endif +#ifdef CONFIG_TEGRA_MMC +#include <asm/arch-tegra/mmc.h> +#endif #include <i2c.h> #include <spi.h> #include "emc.h" @@ -221,3 +224,25 @@ int board_late_init(void) #endif return 0; } + +#if defined(CONFIG_TEGRA_MMC) +void __pin_mux_mmc(void) +{ +} + +void pin_mux_mmc(void) __attribute__((weak, alias("__pin_mux_mmc"))); + +/* this is a weak define that we are overriding */ +int board_mmc_init(bd_t *bd) +{ + debug("%s called\n", __func__); + + /* Enable muxes, etc. for SDMMC controllers */ + pin_mux_mmc(); + + debug("%s: init MMC\n", __func__); + tegra_mmc_init(); + + return 0; +} +#endif diff --git a/board/nvidia/harmony/harmony.c b/board/nvidia/harmony/harmony.c index 93430ed..3122441 100644 --- a/board/nvidia/harmony/harmony.c +++ b/board/nvidia/harmony/harmony.c @@ -27,19 +27,14 @@ #include <asm/arch/funcmux.h> #include <asm/arch/pinmux.h> #include <asm/arch/tegra.h> -#include <asm/arch-tegra/mmc.h> #include <asm/gpio.h> -#ifdef CONFIG_TEGRA_MMC -#include <mmc.h> -#endif -
#ifdef CONFIG_TEGRA_MMC /* * Routine: pin_mux_mmc * Description: setup the pin muxes/tristate values for the SDMMC(s) */ -static void pin_mux_mmc(void) +void pin_mux_mmc(void) { funcmux_select(PERIPH_ID_SDMMC4, FUNCMUX_SDMMC4_ATB_GMA_GME_8_BIT); funcmux_select(PERIPH_ID_SDMMC2, FUNCMUX_SDMMC2_DTA_DTD_8BIT); @@ -54,25 +49,6 @@ static void pin_mux_mmc(void) /* For CD GPIO PI5 */ pinmux_tristate_disable(PINGRP_ATC); } - -/* this is a weak define that we are overriding */ -int board_mmc_init(bd_t *bd) -{ - debug("board_mmc_init called\n"); - - /* 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); - - return 0; -} #endif
void pin_mux_usb(void) diff --git a/board/nvidia/seaboard/seaboard.c b/board/nvidia/seaboard/seaboard.c index 3e33da0..e581fdd 100644 --- a/board/nvidia/seaboard/seaboard.c +++ b/board/nvidia/seaboard/seaboard.c @@ -28,11 +28,7 @@ #include <asm/arch/funcmux.h> #include <asm/arch/gpio.h> #include <asm/arch/pinmux.h> -#include <asm/arch-tegra/mmc.h> #include <asm/gpio.h> -#ifdef CONFIG_TEGRA_MMC -#include <mmc.h> -#endif
/* TODO: Remove this code when the SPI switch is working */ #if !defined(CONFIG_SPI_UART_SWITCH) && (CONFIG_MACH_TYPE != MACH_TYPE_VENTANA) @@ -51,7 +47,7 @@ void gpio_early_init_uart(void) * Routine: pin_mux_mmc * Description: setup the pin muxes/tristate values for the SDMMC(s) */ -static void pin_mux_mmc(void) +void pin_mux_mmc(void) { funcmux_select(PERIPH_ID_SDMMC4, FUNCMUX_SDMMC4_ATB_GMA_GME_8_BIT); funcmux_select(PERIPH_ID_SDMMC3, FUNCMUX_SDMMC3_SDB_4BIT); @@ -61,25 +57,6 @@ static void pin_mux_mmc(void) /* For CD GPIO PI5 */ pinmux_tristate_disable(PINGRP_ATC); } - -/* this is a weak define that we are overriding */ -int board_mmc_init(bd_t *bd) -{ - debug("board_mmc_init called\n"); - - /* 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); - - return 0; -} #endif
void pin_mux_usb(void) diff --git a/board/nvidia/whistler/whistler.c b/board/nvidia/whistler/whistler.c index 592cd6b..f18aa27 100644 --- a/board/nvidia/whistler/whistler.c +++ b/board/nvidia/whistler/whistler.c @@ -27,32 +27,19 @@ #include <asm/arch/clock.h> #include <asm/arch/funcmux.h> #include <asm/arch/pinmux.h> -#include <asm/arch-tegra/mmc.h> #include <asm/gpio.h> #include <i2c.h> -#ifdef CONFIG_TEGRA_MMC -#include <mmc.h> -#endif -
+#ifdef CONFIG_TEGRA_MMC /* * Routine: pin_mux_mmc * Description: setup the pin muxes/tristate values for the SDMMC(s) */ -static void pin_mux_mmc(void) -{ - funcmux_select(PERIPH_ID_SDMMC3, FUNCMUX_SDMMC3_SDB_SLXA_8BIT); - funcmux_select(PERIPH_ID_SDMMC4, FUNCMUX_SDMMC4_ATC_ATD_8BIT); -} - -/* this is a weak define that we are overriding */ -int board_mmc_init(bd_t *bd) +void pin_mux_mmc(void) { uchar val; int ret;
- debug("board_mmc_init called\n"); - /* Turn on MAX8907B LDO12 to 2.8V for J40 power */ ret = i2c_set_bus_num(0); if (ret) @@ -70,17 +57,10 @@ int board_mmc_init(bd_t *bd) if (ret) printf("i2c_write 0 0x3c 0x44 failed: %d\n", ret);
- /* 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); - - return 0; + funcmux_select(PERIPH_ID_SDMMC3, FUNCMUX_SDMMC3_SDB_SLXA_8BIT); + funcmux_select(PERIPH_ID_SDMMC4, FUNCMUX_SDMMC4_ATC_ATD_8BIT); } +#endif
/* this is a weak define that we are overriding */ void pin_mux_usb(void) diff --git a/board/toradex/colibri_t20_iris/colibri_t20_iris.c b/board/toradex/colibri_t20_iris/colibri_t20_iris.c index e40a986..aa76f65 100644 --- a/board/toradex/colibri_t20_iris/colibri_t20_iris.c +++ b/board/toradex/colibri_t20_iris/colibri_t20_iris.c @@ -19,7 +19,6 @@ #include <asm/arch/funcmux.h> #include <asm/arch/pinmux.h> #include <asm/arch-tegra/board.h> -#include <asm/arch-tegra/mmc.h>
#include "../colibri_t20-common/colibri_t20-common.h"
@@ -34,13 +33,13 @@ void pin_mux_usb(void) #endif
#ifdef CONFIG_TEGRA_MMC -int board_mmc_init(bd_t *bd) +/* + * Routine: pin_mux_mmc + * Description: setup the pin muxes/tristate values for the SDMMC(s) + */ +void pin_mux_mmc(void) { funcmux_select(PERIPH_ID_SDMMC4, FUNCMUX_SDMMC4_ATB_GMA_4_BIT); pinmux_tristate_disable(PINGRP_GMB); - - tegra_mmc_init(0, 4, -1, GPIO_PC7); - - return 0; } #endif diff --git a/drivers/mmc/tegra_mmc.c b/drivers/mmc/tegra_mmc.c index d749ab0..918a98d 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,95 @@ 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); + } + 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/fdtdec.h b/include/fdtdec.h index 77f244f..4f9dbcf 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -70,6 +70,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 3ae348d..57e552c 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -45,6 +45,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"),

On 02/14/2013 02:04 PM, 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
@@ -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);
That last line should be:
host->cd_gpio.gpio;
The case is because it's a struct address, not the GPIO you want to print.
+static int do_mmc_init(int dev_index)
- 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);
That change completely removes the call to gpio_direction_output; fdtdec_set_gpio() doesn't do that. This is the cause of the problem on PAZ00, and Harmony.
- 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);
Similarly, this change removes the call to gpio_direction_input(); fdtdec_get_gpio() just reads the GPIO's value and is pointless here.
I'll go retest all the boards after fixing that...

Stephen,
On Thursday 14 February 2013 16:12:42 Stephen Warren wrote:
On 02/14/2013 02:04 PM, 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
@@ -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);
That last line should be:
host->cd_gpio.gpio;
The case is because it's a struct address, not the GPIO you want to print.
+static int do_mmc_init(int dev_index)
- 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);
That change completely removes the call to gpio_direction_output; fdtdec_set_gpio() doesn't do that. This is the cause of the problem on PAZ00, and Harmony.
- 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);
Similarly, this change removes the call to gpio_direction_input(); fdtdec_get_gpio() just reads the GPIO's value and is pointless here.
I'll go retest all the boards after fixing that...
yup - with these changes, everything is fine again on PAZ00.
Marc

Marc/Stephen,
On Fri, Feb 15, 2013 at 9:42 AM, Marc Dietrich marvin24@gmx.de wrote:
Stephen,
On Thursday 14 February 2013 16:12:42 Stephen Warren wrote:
On 02/14/2013 02:04 PM, 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
@@ -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);
That last line should be:
host->cd_gpio.gpio;
The case is because it's a struct address, not the GPIO you want to print.
+static int do_mmc_init(int dev_index)
- 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);
That change completely removes the call to gpio_direction_output; fdtdec_set_gpio() doesn't do that. This is the cause of the problem on PAZ00, and Harmony.
- 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);
Similarly, this change removes the call to gpio_direction_input(); fdtdec_get_gpio() just reads the GPIO's value and is pointless here.
I'll go retest all the boards after fixing that...
yup - with these changes, everything is fine again on PAZ00.
Thanks, guys. I'll roll out a v5 patchset later today.
Tom
Marc

Stephen,
On Thu, Feb 14, 2013 at 4:12 PM, Stephen Warren swarren@wwwdotorg.org wrote:
On 02/14/2013 02:04 PM, 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
@@ -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);
That last line should be:
host->cd_gpio.gpio;
The case is because it's a struct address, not the GPIO you want to print.
Actually, I did want to print the address of the cd_gpio struct, so I could look at it from the cmd line w/md and/or w/JTAG. But I'll just remove the debug printf entirely, since it was only useful early on.
+static int do_mmc_init(int dev_index)
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);
That change completely removes the call to gpio_direction_output; fdtdec_set_gpio() doesn't do that. This is the cause of the problem on PAZ00, and Harmony.
OK, cool. Good catch. I thought the fdtdec_xxx_gpio calls did it all, but now I see that they don't.
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);
Similarly, this change removes the call to gpio_direction_input(); fdtdec_get_gpio() just reads the GPIO's value and is pointless here.
No, not pointless - I was checking the CD pin state and printing it out during debug. But it's not of much interest to anyone but me at this point, so I'll remove the card_det lines.
I'll go retest all the boards after fixing that...
Thanks

On Thu, Feb 14, 2013 at 3:04 PM, Tom Warren twarren.nvidia@gmail.comwrote:
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 Signed-off-by: Thierry Reding thierry.reding@avionic-design.de
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
v3:
- move any power init inside board's pin_mux_mmc function, and/or
create pin_mux_mmc function if necessary.
- move board_mmc_init out of each board file and into ../common/board.c
v4:
- remove #ifdef CONFIG_TEGRA_MMC from trimslice.c
- fix minor whitespace issue in board/nvidia/common/board.c
- remove marking of used node_list entries in MMC driver, not needed
diff --git a/drivers/mmc/tegra_mmc.c b/drivers/mmc/tegra_mmc.c index d749ab0..918a98d 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);
This patch is FULL of these changes. It makes it almost impossible to identify the substantive changes to this code. In the future, please put changes to debug output in a separate patch, unless it directly applies to the relevant change. Also, I note that you didn't mention the fact that you reworked all the debug() calls to prefix with the function name in your patch description.
+/*
- 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);
}
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;
}
+}
Hmmm.... what does fdtdec_find_aliases_for_id() do? It looks like you are attempting to go through all of the sdhci nodes, and I can't help but wonder why you wouldn't use the approach the kernel uses -- for_each_compatible_node()? I'm a little worried that "aliases" are being overused, here.
Andy

On 02/18/2013 04:10 PM, Andy Fleming wrote:
On Thu, Feb 14, 2013 at 3:04 PM, Tom Warren twarren.nvidia@gmail.comwrote:
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.
...
+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;
}
+}
Hmmm.... what does fdtdec_find_aliases_for_id() do? It looks like you are attempting to go through all of the sdhci nodes, and I can't help but wonder why you wouldn't use the approach the kernel uses -- for_each_compatible_node()? I'm a little worried that "aliases" are being overused, here.
IIRC, the implementation of fdtdec_find_aliases_for_id() basically is for_each_compatible_node(), followed by looking up any alias definitions for alias name "sdhci" that reference those nodes.

Andy,
On Mon, Feb 18, 2013 at 4:10 PM, Andy Fleming afleming@gmail.com wrote:
On Thu, Feb 14, 2013 at 3:04 PM, Tom Warren twarren.nvidia@gmail.com 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.
Signed-off-by: Tom Warren twarren@nvidia.com Signed-off-by: Thierry Reding thierry.reding@avionic-design.de
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
v3:
- move any power init inside board's pin_mux_mmc function, and/or
create pin_mux_mmc function if necessary.
- move board_mmc_init out of each board file and into ../common/board.c
v4:
- remove #ifdef CONFIG_TEGRA_MMC from trimslice.c
- fix minor whitespace issue in board/nvidia/common/board.c
- remove marking of used node_list entries in MMC driver, not needed
diff --git a/drivers/mmc/tegra_mmc.c b/drivers/mmc/tegra_mmc.c index d749ab0..918a98d 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);
This patch is FULL of these changes. It makes it almost impossible to identify the substantive changes to this code. In the future, please put changes to debug output in a separate patch, unless it directly applies to the relevant change. Also, I note that you didn't mention the fact that you reworked all the debug() calls to prefix with the function name in your patch description.
I can move the debug changes to a separate patch, no problem. I added the function name prefix because, in some cases, the hard-coded string didn't identify the function correctly (someone moved or renamed the function during a feature add/rewrite (bounce buffer, etc.) and didn't update the debug printf string). So I thought it best to add the function name to each debug printf, making it easier to identify where the info was coming from. I'll add a comment about that to the new patch, too. Thanks.
+/*
- 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);
}
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;
}
+}
Hmmm.... what does fdtdec_find_aliases_for_id() do? It looks like you are attempting to go through all of the sdhci nodes, and I can't help but wonder why you wouldn't use the approach the kernel uses -- for_each_compatible_node()? I'm a little worried that "aliases" are being overused, here.
I used the same basic code that's in every other DT-supporting driver in U-Boot right now. As Stephen points out in his response, the code iterates over the compatible nodes, and then takes into account the aliases, allowing you to number the devices as you see fit according to how people use (or have used) the devices on your board, i.e. MMC 0 is the eMMC chip and MMC 1 is the SD-Card slot, even though (on Tegra) the SDIO register space(s) come before the eMMC reg base.
And again, not to harp on this, but I don't usually look to the kernel for examples of how to do things in U-Boot - I look for pre-existing U-Boot code that does what I need, and if it works for my application, I don't over-analyze it or try to dissect it too deeply. But if a feature is too new to have much extant U-Boot code (like DT files), then I'll go looking for kernel examples or ask Stephen or another kernel guru for help. But that's the exception, and not the rule.
Thanks,
Tom
Andy

Hi Tom,
On Thursday 14 February 2013 14:03:57 Tom Warren wrote:
This patchset adds device-tree support to the Tegra MMC driver. All device config is done via properties in the DT files instead of hard-coded config options/function arguments.
I've tested this on my Seaboard and everything works fine, including card detect. For the other T20 boards, I've used the Linux kernel DTS files for the sdhci nodes where there wasn't one already, or expanded the info that was already there. Everything builds fine, but I haven't tested anything but Seaboard.
unfortunately, this is still no go on PAZ00.
U-Boot SPL 2013.01-00093-g206c157-dirty (Feb 14 2013 - 23:37:03)
U-Boot 2013.01-00093-g206c157-dirty (Feb 14 2013 - 23:37:03)
TEGRA20 Board: Compal Paz00 DRAM: 512 MiB MMC: tegra_mmc_init entry tegra_mmc_init: count of sdhci nodes is 2 process_nodes: count = 2 mmc_get_config: node = 5772 mmc_get_config: found controller at c8000600, width = 8, periph_id = 15 do_mmc_init: index 0, bus width 8 pwr_gpio -1 cd_gpio -1 do_mmc_init: bus width = 8 mmc_get_config: node = 5244 mmc_get_config: found controller at c8000000, width = 4, periph_id = 14 do_mmc_init: index 1, bus width 4 pwr_gpio 169 cd_gpio 173 Power GPIO name = power-gpios CD GPIO name = cd-gpios do_mmc_init: CD state = 0 do_mmc_init: bus width = 4 Tegra SD/MMC: 0, Tegra SD/MMC: 1 tegra_mmc_getcd called, host->cd_gpio = 0x1FBCC044 mmc_reset called
... so far so good
# ext2ls mmc 1 tegra_mmc_getcd called, host->cd_gpio = 0x1FBCC084 mmc_reset called mmc_core_init: host version = 0 mmc_set_ios: bus_width: 1, clock: 375000 mmc_change_clock called mmc_change_clock: div = 8 mmc_change_clock: clkcon = 00000405 mmc_set_ios: hostctl = 00000000 mmc_set_ios: bus_width: 1, clock: 375000 mmc_change_clock called mmc_change_clock: div = 8 mmc_change_clock: clkcon = 00000405 mmc_set_ios: hostctl = 00000000 mmc_send_cmd: called mmc_send_cmd_bounced called mmc_send_cmd_bounced: cmd->arg: 00000000 mmc_send_cmd_bounced: cmd: 0 mmc_send_cmd: called mmc_send_cmd_bounced called mmc_send_cmd_bounced: cmd->arg: 000001aa mmc_send_cmd_bounced: cmd: 8 mmc_send_cmd_bounced: error: 010c8001 cmd 8 mmc_send_cmd: called mmc_send_cmd_bounced called mmc_send_cmd_bounced: cmd->arg: 00000000 mmc_send_cmd_bounced: cmd: 55 mmc_send_cmd_bounced: error: 010c8001 cmd 55 mmc_send_cmd: called mmc_send_cmd_bounced called mmc_send_cmd_bounced: cmd->arg: 00000000 mmc_send_cmd_bounced: cmd: 2 mmc_send_cmd_bounced: error: 00048001 cmd 2 ** Bad device mmc 1 **
any ideas?
Marc

Marc,
On Thu, Feb 14, 2013 at 3:48 PM, Marc Dietrich marvin24@gmx.de wrote:
Hi Tom,
On Thursday 14 February 2013 14:03:57 Tom Warren wrote:
This patchset adds device-tree support to the Tegra MMC driver. All device config is done via properties in the DT files instead of hard-coded config options/function arguments.
I've tested this on my Seaboard and everything works fine, including card detect. For the other T20 boards, I've used the Linux kernel DTS files for the sdhci nodes where there wasn't one already, or expanded the info that was already there. Everything builds fine, but I haven't tested anything but Seaboard.
unfortunately, this is still no go on PAZ00.
U-Boot SPL 2013.01-00093-g206c157-dirty (Feb 14 2013 - 23:37:03)
U-Boot 2013.01-00093-g206c157-dirty (Feb 14 2013 - 23:37:03)
TEGRA20 Board: Compal Paz00 DRAM: 512 MiB MMC: tegra_mmc_init entry tegra_mmc_init: count of sdhci nodes is 2 process_nodes: count = 2 mmc_get_config: node = 5772 mmc_get_config: found controller at c8000600, width = 8, periph_id = 15 do_mmc_init: index 0, bus width 8 pwr_gpio -1 cd_gpio -1 do_mmc_init: bus width = 8 mmc_get_config: node = 5244 mmc_get_config: found controller at c8000000, width = 4, periph_id = 14 do_mmc_init: index 1, bus width 4 pwr_gpio 169 cd_gpio 173 Power GPIO name = power-gpios CD GPIO name = cd-gpios do_mmc_init: CD state = 0 do_mmc_init: bus width = 4 Tegra SD/MMC: 0, Tegra SD/MMC: 1 tegra_mmc_getcd called, host->cd_gpio = 0x1FBCC044 mmc_reset called
... so far so good
# ext2ls mmc 1 tegra_mmc_getcd called, host->cd_gpio = 0x1FBCC084 mmc_reset called mmc_core_init: host version = 0 mmc_set_ios: bus_width: 1, clock: 375000 mmc_change_clock called mmc_change_clock: div = 8 mmc_change_clock: clkcon = 00000405 mmc_set_ios: hostctl = 00000000 mmc_set_ios: bus_width: 1, clock: 375000 mmc_change_clock called mmc_change_clock: div = 8 mmc_change_clock: clkcon = 00000405 mmc_set_ios: hostctl = 00000000 mmc_send_cmd: called mmc_send_cmd_bounced called mmc_send_cmd_bounced: cmd->arg: 00000000 mmc_send_cmd_bounced: cmd: 0 mmc_send_cmd: called mmc_send_cmd_bounced called mmc_send_cmd_bounced: cmd->arg: 000001aa mmc_send_cmd_bounced: cmd: 8 mmc_send_cmd_bounced: error: 010c8001 cmd 8 mmc_send_cmd: called mmc_send_cmd_bounced called mmc_send_cmd_bounced: cmd->arg: 00000000 mmc_send_cmd_bounced: cmd: 55 mmc_send_cmd_bounced: error: 010c8001 cmd 55 mmc_send_cmd: called mmc_send_cmd_bounced called mmc_send_cmd_bounced: cmd->arg: 00000000 mmc_send_cmd_bounced: cmd: 2 mmc_send_cmd_bounced: error: 00048001 cmd 2 ** Bad device mmc 1 **
any ideas?
I'm going to be gone for a few days, but I think Stephen agreed to look into it. He has a PAZ00 board.
Thanks,
Tom
Marc

On 02/14/2013 03:48 PM, Marc Dietrich wrote:
Hi Tom,
On Thursday 14 February 2013 14:03:57 Tom Warren wrote:
This patchset adds device-tree support to the Tegra MMC driver. All device config is done via properties in the DT files instead of hard-coded config options/function arguments.
I've tested this on my Seaboard and everything works fine, including card detect. For the other T20 boards, I've used the Linux kernel DTS files for the sdhci nodes where there wasn't one already, or expanded the info that was already there. Everything builds fine, but I haven't tested anything but Seaboard.
unfortunately, this is still no go on PAZ00.
...
# ext2ls mmc 1
...
** Bad device mmc 1 **
I see this too. I also see it on Harmony. I'm actively debugging it.

Am Donnerstag, den 14.02.2013, 14:03 -0700 schrieb Tom Warren:
This patchset adds device-tree support to the Tegra MMC driver. All device config is done via properties in the DT files instead of hard-coded config options/function arguments.
I've tested this on my Seaboard and everything works fine, including card detect. For the other T20 boards, I've used the Linux kernel DTS files for the sdhci nodes where there wasn't one already, or expanded the info that was already there. Everything builds fine, but I haven't tested anything but Seaboard.
v2: Changes as per Stephen's & Simon's review v3: Changes as per Stephen/Lucas/Thierry/Simon's feedback v4: Additional changes as per Stephen/Lucas/Thierry/Simon
Tom Warren (4): fdt: Add dts/dtsi file include paths to DTC command line Tegra: fdt: Add/enhance sdhci (mmc) nodes for all T20 DT files Tegra: fdt: tamonten: Add common tamonten.dtsi file from linux Tegra: MMC: Add DT support to MMC driver for all T20 boards
When applying, patches 2 and 3 should be swapped around to avoid intermediate breakage in the series.
Regards, Lucas
participants (5)
-
Andy Fleming
-
Lucas Stach
-
Marc Dietrich
-
Stephen Warren
-
Tom Warren