[U-Boot] [PATCH v2 0/9] tegra: SPI drivers

This series updates the tegra20 SPI driver to add fdt support and adds a new tegra30 SPI driver. This series depends on the following patches:
Allen Martin: fdt: fix dts preprocessor options tegra: remove IRDA pinmux synonym
Testing was done on seaboard (tegra20) and cardhu (tegra30).
Changes in v2: -Added new patch to sort dts files prior to adding new nodes -Moved "max-spi-frequency" out to board dts files -Moved tegra20 SFLASH fdt changes out to separate patch -Added valid flag to slink driver controller structure
Allen Martin (9): tegra: fdt: sort dts files tegra: fdt: add apbdma node tegra20: fdt: add SPI SFLASH node tegra: spi: add fdt support to tegra SPI SFLASH driver tegra30: add SBC1 to periph id mapping table tegra30: fdt: add SPI SLINK nodes tegra: add addresses of SPI SLINK controllers tegra: add SPI SLINK driver tegra: cardhu: config: enable SPI
arch/arm/cpu/tegra30-common/clock.c | 2 +- arch/arm/dts/tegra20.dtsi | 412 +++++++++++++------------ arch/arm/dts/tegra30.dtsi | 125 +++++++- arch/arm/include/asm/arch-tegra/tegra.h | 6 + arch/arm/include/asm/arch-tegra/tegra_slink.h | 84 +++++ board/nvidia/common/board.c | 3 +- board/nvidia/dts/tegra20-harmony.dts | 32 +- board/nvidia/dts/tegra20-seaboard.dts | 141 ++++----- board/nvidia/dts/tegra20-ventana.dts | 18 +- board/nvidia/dts/tegra20-whistler.dts | 12 +- board/nvidia/dts/tegra30-cardhu.dts | 22 +- drivers/spi/Makefile | 1 + drivers/spi/tegra_slink.c | 335 ++++++++++++++++++++ drivers/spi/tegra_spi.c | 42 ++- include/configs/cardhu.h | 11 + include/fdtdec.h | 2 + lib/fdtdec.c | 2 + 17 files changed, 940 insertions(+), 310 deletions(-) create mode 100644 arch/arm/include/asm/arch-tegra/tegra_slink.h create mode 100644 drivers/spi/tegra_slink.c

Sort nodes in dts files according the the following rules:
1) Any nodes that already exist in any /include/d file, in the order they appear in the /include/d file.
2) Any nodes with a reg property, in order of their address.
3) Any nodes without a reg property, alphabetically by node name.
Signed-off-by: Allen Martin amartin@nvidia.com --- arch/arm/dts/tegra20.dtsi | 379 ++++++++++++++++----------------- arch/arm/dts/tegra30.dtsi | 20 +- board/nvidia/dts/tegra20-harmony.dts | 32 +-- board/nvidia/dts/tegra20-seaboard.dts | 137 ++++++------ board/nvidia/dts/tegra20-ventana.dts | 18 +- board/nvidia/dts/tegra20-whistler.dts | 12 +- board/nvidia/dts/tegra30-cardhu.dts | 18 +- 7 files changed, 307 insertions(+), 309 deletions(-)
diff --git a/arch/arm/dts/tegra20.dtsi b/arch/arm/dts/tegra20.dtsi index 636ec2c..c316864 100644 --- a/arch/arm/dts/tegra20.dtsi +++ b/arch/arm/dts/tegra20.dtsi @@ -4,19 +4,101 @@ compatible = "nvidia,tegra20"; interrupt-parent = <&intc>;
- tegra_car: clock@60006000 { - compatible = "nvidia,tegra20-car"; - reg = <0x60006000 0x1000>; - #clock-cells = <1>; - }; + host1x { + compatible = "nvidia,tegra20-host1x", "simple-bus"; + reg = <0x50000000 0x00024000>; + interrupts = <0 65 0x04 /* mpcore syncpt */ + 0 67 0x04>; /* mpcore general */ + status = "disabled";
- clocks { #address-cells = <1>; - #size-cells = <0>; + #size-cells = <1>;
- osc: clock { - compatible = "fixed-clock"; - #clock-cells = <0>; + ranges = <0x54000000 0x54000000 0x04000000>; + + /* video-encoding/decoding */ + mpe { + reg = <0x54040000 0x00040000>; + interrupts = <0 68 0x04>; + status = "disabled"; + }; + + /* video input */ + vi { + reg = <0x54080000 0x00040000>; + interrupts = <0 69 0x04>; + status = "disabled"; + }; + + /* EPP */ + epp { + reg = <0x540c0000 0x00040000>; + interrupts = <0 70 0x04>; + status = "disabled"; + }; + + /* ISP */ + isp { + reg = <0x54100000 0x00040000>; + interrupts = <0 71 0x04>; + status = "disabled"; + }; + + /* 2D engine */ + gr2d { + reg = <0x54140000 0x00040000>; + interrupts = <0 72 0x04>; + status = "disabled"; + }; + + /* 3D engine */ + gr3d { + reg = <0x54180000 0x00040000>; + status = "disabled"; + }; + + /* display controllers */ + dc@54200000 { + compatible = "nvidia,tegra20-dc"; + reg = <0x54200000 0x00040000>; + interrupts = <0 73 0x04>; + status = "disabled"; + + rgb { + status = "disabled"; + }; + }; + + dc@54240000 { + compatible = "nvidia,tegra20-dc"; + reg = <0x54240000 0x00040000>; + interrupts = <0 74 0x04>; + status = "disabled"; + + rgb { + status = "disabled"; + }; + }; + + /* outputs */ + hdmi { + compatible = "nvidia,tegra20-hdmi"; + reg = <0x54280000 0x00040000>; + interrupts = <0 75 0x04>; + status = "disabled"; + }; + + tvo { + compatible = "nvidia,tegra20-tvo"; + reg = <0x542c0000 0x00040000>; + interrupts = <0 76 0x04>; + status = "disabled"; + }; + + dsi { + compatible = "nvidia,tegra20-dsi"; + reg = <0x54300000 0x00040000>; + status = "disabled"; }; };
@@ -28,44 +110,33 @@ < 0x50040100 0x0100 >; };
- i2c@7000c000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "nvidia,tegra20-i2c"; - reg = <0x7000C000 0x100>; - interrupts = < 70 >; - /* PERIPH_ID_I2C1, PLL_P_OUT3 */ - clocks = <&tegra_car 12>, <&tegra_car 124>; + tegra_car: clock@60006000 { + compatible = "nvidia,tegra20-car"; + reg = <0x60006000 0x1000>; + #clock-cells = <1>; };
- i2c@7000c400 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "nvidia,tegra20-i2c"; - reg = <0x7000C400 0x100>; - interrupts = < 116 >; - /* PERIPH_ID_I2C2, PLL_P_OUT3 */ - clocks = <&tegra_car 54>, <&tegra_car 124>; + gpio: gpio@6000d000 { + compatible = "nvidia,tegra20-gpio"; + reg = < 0x6000d000 0x1000 >; + interrupts = < 64 65 66 67 87 119 121 >; + #gpio-cells = <2>; + gpio-controller; };
- i2c@7000c500 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "nvidia,tegra20-i2c"; - reg = <0x7000C500 0x100>; - interrupts = < 124 >; - /* PERIPH_ID_I2C3, PLL_P_OUT3 */ - clocks = <&tegra_car 67>, <&tegra_car 124>; + pinmux: pinmux@70000000 { + compatible = "nvidia,tegra20-pinmux"; + reg = < 0x70000014 0x10 /* Tri-state registers */ + 0x70000080 0x20 /* Mux registers */ + 0x700000a0 0x14 /* Pull-up/down registers */ + 0x70000868 0xa8 >; /* Pad control registers */ };
- i2c@7000d000 { + das@70000c00 { #address-cells = <1>; #size-cells = <0>; - compatible = "nvidia,tegra20-i2c-dvc"; - reg = <0x7000D000 0x200>; - interrupts = < 85 >; - /* PERIPH_ID_DVC_I2C, PLL_P_OUT3 */ - clocks = <&tegra_car 47>, <&tegra_car 124>; + compatible = "nvidia,tegra20-das"; + reg = <0x70000c00 0x80>; };
i2s@70002800 { @@ -86,29 +157,6 @@ dma-channel = < 1 >; };
- das@70000c00 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "nvidia,tegra20-das"; - reg = <0x70000c00 0x80>; - }; - - gpio: gpio@6000d000 { - compatible = "nvidia,tegra20-gpio"; - reg = < 0x6000d000 0x1000 >; - interrupts = < 64 65 66 67 87 119 121 >; - #gpio-cells = <2>; - gpio-controller; - }; - - pinmux: pinmux@70000000 { - compatible = "nvidia,tegra20-pinmux"; - reg = < 0x70000014 0x10 /* Tri-state registers */ - 0x70000080 0x20 /* Mux registers */ - 0x700000a0 0x14 /* Pull-up/down registers */ - 0x70000868 0xa8 >; /* Pad control registers */ - }; - serial@70006000 { compatible = "nvidia,tegra20-uart"; reg = <0x70006000 0x40>; @@ -144,28 +192,69 @@ interrupts = < 123 >; };
- sdhci@c8000000 { - compatible = "nvidia,tegra20-sdhci"; - reg = <0xc8000000 0x200>; - interrupts = < 46 >; + nand: nand-controller@70008000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "nvidia,tegra20-nand"; + reg = <0x70008000 0x100>; };
- sdhci@c8000200 { - compatible = "nvidia,tegra20-sdhci"; - reg = <0xc8000200 0x200>; - interrupts = < 47 >; + pwm: pwm@7000a000 { + compatible = "nvidia,tegra20-pwm"; + reg = <0x7000a000 0x100>; + #pwm-cells = <2>; };
- sdhci@c8000400 { - compatible = "nvidia,tegra20-sdhci"; - reg = <0xc8000400 0x200>; - interrupts = < 51 >; + i2c@7000c000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "nvidia,tegra20-i2c"; + reg = <0x7000C000 0x100>; + interrupts = < 70 >; + /* PERIPH_ID_I2C1, PLL_P_OUT3 */ + clocks = <&tegra_car 12>, <&tegra_car 124>; };
- sdhci@c8000600 { - compatible = "nvidia,tegra20-sdhci"; - reg = <0xc8000600 0x200>; - interrupts = < 63 >; + i2c@7000c400 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "nvidia,tegra20-i2c"; + reg = <0x7000C400 0x100>; + interrupts = < 116 >; + /* PERIPH_ID_I2C2, PLL_P_OUT3 */ + clocks = <&tegra_car 54>, <&tegra_car 124>; + }; + + i2c@7000c500 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "nvidia,tegra20-i2c"; + reg = <0x7000C500 0x100>; + interrupts = < 124 >; + /* PERIPH_ID_I2C3, PLL_P_OUT3 */ + clocks = <&tegra_car 67>, <&tegra_car 124>; + }; + + i2c@7000d000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "nvidia,tegra20-i2c-dvc"; + reg = <0x7000D000 0x200>; + interrupts = < 85 >; + /* PERIPH_ID_DVC_I2C, PLL_P_OUT3 */ + clocks = <&tegra_car 47>, <&tegra_car 124>; + }; + + kbc@7000e200 { + compatible = "nvidia,tegra20-kbc"; + reg = <0x7000e200 0x0078>; + }; + + emc@7000f400 { + #address-cells = < 1 >; + #size-cells = < 0 >; + compatible = "nvidia,tegra20-emc"; + reg = <0x7000f400 0x200>; };
usb@c5000000 { @@ -193,127 +282,37 @@ clocks = <&tegra_car 59>; /* PERIPH_ID_USB3 */ };
- emc@7000f400 { - #address-cells = < 1 >; - #size-cells = < 0 >; - compatible = "nvidia,tegra20-emc"; - reg = <0x7000f400 0x200>; + sdhci@c8000000 { + compatible = "nvidia,tegra20-sdhci"; + reg = <0xc8000000 0x200>; + interrupts = < 46 >; };
- kbc@7000e200 { - compatible = "nvidia,tegra20-kbc"; - reg = <0x7000e200 0x0078>; + sdhci@c8000200 { + compatible = "nvidia,tegra20-sdhci"; + reg = <0xc8000200 0x200>; + interrupts = < 47 >; };
- nand: nand-controller@70008000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "nvidia,tegra20-nand"; - reg = <0x70008000 0x100>; + sdhci@c8000400 { + compatible = "nvidia,tegra20-sdhci"; + reg = <0xc8000400 0x200>; + interrupts = < 51 >; };
- pwm: pwm@7000a000 { - compatible = "nvidia,tegra20-pwm"; - reg = <0x7000a000 0x100>; - #pwm-cells = <2>; + sdhci@c8000600 { + compatible = "nvidia,tegra20-sdhci"; + reg = <0xc8000600 0x200>; + interrupts = < 63 >; };
- host1x { - compatible = "nvidia,tegra20-host1x", "simple-bus"; - reg = <0x50000000 0x00024000>; - interrupts = <0 65 0x04 /* mpcore syncpt */ - 0 67 0x04>; /* mpcore general */ - status = "disabled"; - + clocks { #address-cells = <1>; - #size-cells = <1>; - - ranges = <0x54000000 0x54000000 0x04000000>; - - /* video-encoding/decoding */ - mpe { - reg = <0x54040000 0x00040000>; - interrupts = <0 68 0x04>; - status = "disabled"; - }; - - /* video input */ - vi { - reg = <0x54080000 0x00040000>; - interrupts = <0 69 0x04>; - status = "disabled"; - }; - - /* EPP */ - epp { - reg = <0x540c0000 0x00040000>; - interrupts = <0 70 0x04>; - status = "disabled"; - }; - - /* ISP */ - isp { - reg = <0x54100000 0x00040000>; - interrupts = <0 71 0x04>; - status = "disabled"; - }; - - /* 2D engine */ - gr2d { - reg = <0x54140000 0x00040000>; - interrupts = <0 72 0x04>; - status = "disabled"; - }; - - /* 3D engine */ - gr3d { - reg = <0x54180000 0x00040000>; - status = "disabled"; - }; - - /* display controllers */ - dc@54200000 { - compatible = "nvidia,tegra20-dc"; - reg = <0x54200000 0x00040000>; - interrupts = <0 73 0x04>; - status = "disabled"; - - rgb { - status = "disabled"; - }; - }; - - dc@54240000 { - compatible = "nvidia,tegra20-dc"; - reg = <0x54240000 0x00040000>; - interrupts = <0 74 0x04>; - status = "disabled"; - - rgb { - status = "disabled"; - }; - }; - - /* outputs */ - hdmi { - compatible = "nvidia,tegra20-hdmi"; - reg = <0x54280000 0x00040000>; - interrupts = <0 75 0x04>; - status = "disabled"; - }; - - tvo { - compatible = "nvidia,tegra20-tvo"; - reg = <0x542c0000 0x00040000>; - interrupts = <0 76 0x04>; - status = "disabled"; - }; + #size-cells = <0>;
- dsi { - compatible = "nvidia,tegra20-dsi"; - reg = <0x54300000 0x00040000>; - status = "disabled"; + osc: clock { + compatible = "fixed-clock"; + #clock-cells = <0>; }; }; - }; diff --git a/arch/arm/dts/tegra30.dtsi b/arch/arm/dts/tegra30.dtsi index 664c397..b0e070b 100644 --- a/arch/arm/dts/tegra30.dtsi +++ b/arch/arm/dts/tegra30.dtsi @@ -9,16 +9,6 @@ #clock-cells = <1>; };
- clocks { - #address-cells = <1>; - #size-cells = <0>; - - osc: clock { - compatible = "fixed-clock"; - #clock-cells = <0>; - }; - }; - i2c@7000c000 { #address-cells = <1>; #size-cells = <0>; @@ -63,4 +53,14 @@ /* PERIPH_ID_I2C_DVC, CLK_M */ clocks = <&tegra_car 47>; }; + + clocks { + #address-cells = <1>; + #size-cells = <0>; + + osc: clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + }; + }; }; diff --git a/board/nvidia/dts/tegra20-harmony.dts b/board/nvidia/dts/tegra20-harmony.dts index 5645a8d..4db7215 100644 --- a/board/nvidia/dts/tegra20-harmony.dts +++ b/board/nvidia/dts/tegra20-harmony.dts @@ -15,15 +15,6 @@ reg = <0x00000000 0x40000000>; };
- clocks { - clk_32k: clk_32k { - clock-frequency = <32000>; - }; - osc { - clock-frequency = <12000000>; - }; - }; - clock@60006000 { clocks = <&clk_32k &osc>; }; @@ -32,6 +23,16 @@ clock-frequency = < 216000000 >; };
+ nand-controller@70008000 { + nvidia,wp-gpios = <&gpio 23 0>; /* PC7 */ + nvidia,width = <8>; + nvidia,timing = <26 100 20 80 20 10 12 10 70>; + nand@0 { + reg = <0>; + compatible = "hynix,hy27uf4g2b", "nand-flash"; + }; + }; + i2c@7000c000 { status = "disabled"; }; @@ -56,13 +57,12 @@ nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */ };
- nand-controller@70008000 { - nvidia,wp-gpios = <&gpio 23 0>; /* PC7 */ - nvidia,width = <8>; - nvidia,timing = <26 100 20 80 20 10 12 10 70>; - nand@0 { - reg = <0>; - compatible = "hynix,hy27uf4g2b", "nand-flash"; + clocks { + clk_32k: clk_32k { + clock-frequency = <32000>; + }; + osc { + clock-frequency = <12000000>; }; }; }; diff --git a/board/nvidia/dts/tegra20-seaboard.dts b/board/nvidia/dts/tegra20-seaboard.dts index dd98ca4..b0da0be 100644 --- a/board/nvidia/dts/tegra20-seaboard.dts +++ b/board/nvidia/dts/tegra20-seaboard.dts @@ -27,6 +27,21 @@ reg = < 0x00000000 0x40000000 >; };
+ host1x { + status = "okay"; + dc@54200000 { + status = "okay"; + rgb { + status = "okay"; + nvidia,panel = <&lcd_panel>; + }; + }; + }; + + clock@60006000 { + clocks = <&clk_32k &osc>; + }; + /* This is not used in U-Boot, but is expected to be in kernel .dts */ i2c@7000d000 { clock-frequency = <100000>; @@ -45,37 +60,18 @@ }; };
- clocks { - osc { - clock-frequency = <12000000>; - }; - }; - - clock@60006000 { - clocks = <&clk_32k &osc>; - }; - serial@70006300 { clock-frequency = < 216000000 >; };
- sdhci@c8000400 { - cd-gpios = <&gpio 69 0>; /* gpio PI5 */ - wp-gpios = <&gpio 57 0>; /* gpio PH1 */ - power-gpios = <&gpio 70 0>; /* gpio PI6 */ - }; - - sdhci@c8000600 { - support-8bit; - }; - - usb@c5000000 { - nvidia,vbus-gpio = <&gpio 24 0>; /* PD0 */ - dr_mode = "otg"; - }; - - usb@c5004000 { - status = "disabled"; + nand-controller@70008000 { + nvidia,wp-gpios = <&gpio 59 0>; /* PH3 */ + nvidia,width = <8>; + nvidia,timing = <26 100 20 80 20 10 12 10 70>; + nand@0 { + reg = <0>; + compatible = "hynix,hy27uf4g2b", "nand-flash"; + }; };
i2c@7000c000 { @@ -90,6 +86,33 @@ clock-frequency = <100000>; };
+ kbc@7000e200 { + linux,keymap = <0x00020011 0x0003001f 0x0004001e 0x0005002c + 0x000701d0 0x0107007d 0x02060064 0x02070038 0x03000006 + 0x03010005 0x03020013 0x03030012 0x03040021 0x03050020 + 0x0306002d 0x04000008 0x04010007 0x04020014 0x04030023 + 0x04040022 0x0405002f 0x0406002e 0x04070039 0x0500000a + 0x05010009 0x05020016 0x05030015 0x05040024 0x05050031 + 0x05060030 0x0507002b 0x0600000c 0x0601000b 0x06020018 + 0x06030017 0x06040026 0x06050025 0x06060033 0x06070032 + 0x0701000d 0x0702001b 0x0703001c 0x0707008b 0x08040036 + 0x0805002a 0x09050061 0x0907001d 0x0b00001a 0x0b010019 + 0x0b020028 0x0b030027 0x0b040035 0x0b050034 0x0c000044 + 0x0c010043 0x0c02000e 0x0c030004 0x0c040003 0x0c050067 + 0x0c0600d2 0x0c070077 0x0d00006e 0x0d01006f 0x0d030068 + 0x0d04006d 0x0d05006a 0x0d06006c 0x0d070069 0x0e000057 + 0x0e010058 0x0e020042 0x0e030010 0x0e04003e 0x0e05003d + 0x0e060002 0x0e070041 0x0f000001 0x0f010029 0x0f02003f + 0x0f03000f 0x0f04003b 0x0f05003c 0x0f06003a 0x0f070040 + 0x14000047 0x15000049 0x15010048 0x1502004b 0x1504004f + 0x16010062 0x1602004d 0x1603004c 0x16040051 0x16050050 + 0x16070052 0x1b010037 0x1b03004a 0x1b04004e 0x1b050053 + 0x1c050073 0x1d030066 0x1d04006b 0x1d0500e0 0x1d060072 + 0x1d0700e1 0x1e000045 0x1e010046 0x1e020071 + 0x1f04008a>; + linux,fn-keymap = <0x05040002>; + }; + emc@7000f400 { emc-table@190000 { reg = < 190000 >; @@ -127,51 +150,28 @@ }; };
- kbc@7000e200 { - linux,keymap = <0x00020011 0x0003001f 0x0004001e 0x0005002c - 0x000701d0 0x0107007d 0x02060064 0x02070038 0x03000006 - 0x03010005 0x03020013 0x03030012 0x03040021 0x03050020 - 0x0306002d 0x04000008 0x04010007 0x04020014 0x04030023 - 0x04040022 0x0405002f 0x0406002e 0x04070039 0x0500000a - 0x05010009 0x05020016 0x05030015 0x05040024 0x05050031 - 0x05060030 0x0507002b 0x0600000c 0x0601000b 0x06020018 - 0x06030017 0x06040026 0x06050025 0x06060033 0x06070032 - 0x0701000d 0x0702001b 0x0703001c 0x0707008b 0x08040036 - 0x0805002a 0x09050061 0x0907001d 0x0b00001a 0x0b010019 - 0x0b020028 0x0b030027 0x0b040035 0x0b050034 0x0c000044 - 0x0c010043 0x0c02000e 0x0c030004 0x0c040003 0x0c050067 - 0x0c0600d2 0x0c070077 0x0d00006e 0x0d01006f 0x0d030068 - 0x0d04006d 0x0d05006a 0x0d06006c 0x0d070069 0x0e000057 - 0x0e010058 0x0e020042 0x0e030010 0x0e04003e 0x0e05003d - 0x0e060002 0x0e070041 0x0f000001 0x0f010029 0x0f02003f - 0x0f03000f 0x0f04003b 0x0f05003c 0x0f06003a 0x0f070040 - 0x14000047 0x15000049 0x15010048 0x1502004b 0x1504004f - 0x16010062 0x1602004d 0x1603004c 0x16040051 0x16050050 - 0x16070052 0x1b010037 0x1b03004a 0x1b04004e 0x1b050053 - 0x1c050073 0x1d030066 0x1d04006b 0x1d0500e0 0x1d060072 - 0x1d0700e1 0x1e000045 0x1e010046 0x1e020071 - 0x1f04008a>; - linux,fn-keymap = <0x05040002>; + usb@c5000000 { + nvidia,vbus-gpio = <&gpio 24 0>; /* PD0 */ + dr_mode = "otg"; };
- nand-controller@70008000 { - nvidia,wp-gpios = <&gpio 59 0>; /* PH3 */ - nvidia,width = <8>; - nvidia,timing = <26 100 20 80 20 10 12 10 70>; - nand@0 { - reg = <0>; - compatible = "hynix,hy27uf4g2b", "nand-flash"; - }; + usb@c5004000 { + status = "disabled"; };
- host1x { - status = "okay"; - dc@54200000 { - status = "okay"; - rgb { - status = "okay"; - nvidia,panel = <&lcd_panel>; - }; + sdhci@c8000400 { + cd-gpios = <&gpio 69 0>; /* gpio PI5 */ + wp-gpios = <&gpio 57 0>; /* gpio PH1 */ + power-gpios = <&gpio 70 0>; /* gpio PI6 */ + }; + + sdhci@c8000600 { + support-8bit; + }; + + clocks { + osc { + clock-frequency = <12000000>; }; };
@@ -195,5 +195,4 @@ nvidia,panel-vdd-gpios = <&gpio 22 0>; /* PC6 */ nvidia,panel-timings = <400 4 203 17 15>; }; - }; diff --git a/board/nvidia/dts/tegra20-ventana.dts b/board/nvidia/dts/tegra20-ventana.dts index 38b7b13..9f7759a 100644 --- a/board/nvidia/dts/tegra20-ventana.dts +++ b/board/nvidia/dts/tegra20-ventana.dts @@ -14,15 +14,6 @@ reg = <0x00000000 0x40000000>; };
- clocks { - clk_32k: clk_32k { - clock-frequency = <32000>; - }; - osc { - clock-frequency = <12000000>; - }; - }; - clock@60006000 { clocks = <&clk_32k &osc>; }; @@ -54,4 +45,13 @@ usb@c5004000 { status = "disabled"; }; + + clocks { + clk_32k: clk_32k { + clock-frequency = <32000>; + }; + osc { + clock-frequency = <12000000>; + }; + }; }; diff --git a/board/nvidia/dts/tegra20-whistler.dts b/board/nvidia/dts/tegra20-whistler.dts index f830cf3..9d64969 100644 --- a/board/nvidia/dts/tegra20-whistler.dts +++ b/board/nvidia/dts/tegra20-whistler.dts @@ -16,12 +16,6 @@ reg = < 0x00000000 0x20000000 >; };
- clocks { - osc { - clock-frequency = <12000000>; - }; - }; - clock@60006000 { clocks = <&clk_32k &osc>; }; @@ -67,4 +61,10 @@ usb@c5004000 { status = "disabled"; }; + + clocks { + osc { + clock-frequency = <12000000>; + }; + }; }; diff --git a/board/nvidia/dts/tegra30-cardhu.dts b/board/nvidia/dts/tegra30-cardhu.dts index 4eddde6..64c2ee2 100644 --- a/board/nvidia/dts/tegra30-cardhu.dts +++ b/board/nvidia/dts/tegra30-cardhu.dts @@ -19,15 +19,6 @@ reg = <0x80000000 0x40000000>; };
- clocks { - clk_32k: clk_32K { - clock-frequency = <32768>; - }; - osc { - clock-frequency = <12000000>; - }; - }; - clock@60006000 { clocks = <&clk_32k &osc>; }; @@ -51,4 +42,13 @@ i2c@7000d000 { clock-frequency = <100000>; }; + + clocks { + clk_32k: clk_32K { + clock-frequency = <32768>; + }; + osc { + clock-frequency = <12000000>; + }; + }; };

On Sat, Jan 12, 2013 at 1:07 AM, Allen Martin amartin@nvidia.com wrote:
Sort nodes in dts files according the the following rules:
- Any nodes that already exist in any /include/d file, in the order
they appear in the /include/d file.
Any nodes with a reg property, in order of their address.
Any nodes without a reg property, alphabetically by node name.
Signed-off-by: Allen Martin amartin@nvidia.com
Acked-by: Simon Glass sjg@chromium.org

Add apbdma node for tegra20 and tegra30, copied directly from tegra Linux dtsi files.
Signed-off-by: Allen Martin amartin@nvidia.com --- arch/arm/dts/tegra20.dtsi | 21 +++++++++++++++++++++ arch/arm/dts/tegra30.dtsi | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+)
diff --git a/arch/arm/dts/tegra20.dtsi b/arch/arm/dts/tegra20.dtsi index c316864..9739f91 100644 --- a/arch/arm/dts/tegra20.dtsi +++ b/arch/arm/dts/tegra20.dtsi @@ -116,6 +116,27 @@ #clock-cells = <1>; };
+ apbdma: dma { + compatible = "nvidia,tegra20-apbdma"; + reg = <0x6000a000 0x1200>; + interrupts = <0 104 0x04 + 0 105 0x04 + 0 106 0x04 + 0 107 0x04 + 0 108 0x04 + 0 109 0x04 + 0 110 0x04 + 0 111 0x04 + 0 112 0x04 + 0 113 0x04 + 0 114 0x04 + 0 115 0x04 + 0 116 0x04 + 0 117 0x04 + 0 118 0x04 + 0 119 0x04>; + }; + gpio: gpio@6000d000 { compatible = "nvidia,tegra20-gpio"; reg = < 0x6000d000 0x1000 >; diff --git a/arch/arm/dts/tegra30.dtsi b/arch/arm/dts/tegra30.dtsi index b0e070b..d58054c 100644 --- a/arch/arm/dts/tegra30.dtsi +++ b/arch/arm/dts/tegra30.dtsi @@ -9,6 +9,43 @@ #clock-cells = <1>; };
+ apbdma: dma { + compatible = "nvidia,tegra30-apbdma", "nvidia,tegra20-apbdma"; + reg = <0x6000a000 0x1400>; + interrupts = <0 104 0x04 + 0 105 0x04 + 0 106 0x04 + 0 107 0x04 + 0 108 0x04 + 0 109 0x04 + 0 110 0x04 + 0 111 0x04 + 0 112 0x04 + 0 113 0x04 + 0 114 0x04 + 0 115 0x04 + 0 116 0x04 + 0 117 0x04 + 0 118 0x04 + 0 119 0x04 + 0 128 0x04 + 0 129 0x04 + 0 130 0x04 + 0 131 0x04 + 0 132 0x04 + 0 133 0x04 + 0 134 0x04 + 0 135 0x04 + 0 136 0x04 + 0 137 0x04 + 0 138 0x04 + 0 139 0x04 + 0 140 0x04 + 0 141 0x04 + 0 142 0x04 + 0 143 0x04>; + }; + i2c@7000c000 { #address-cells = <1>; #size-cells = <0>;

Add node for tegra20 SPI SFLASH controller to fdt.
Signed-off-by: Allen Martin amartin@nvidia.com --- arch/arm/dts/tegra20.dtsi | 12 ++++++++++++ board/nvidia/dts/tegra20-seaboard.dts | 4 ++++ 2 files changed, 16 insertions(+)
diff --git a/arch/arm/dts/tegra20.dtsi b/arch/arm/dts/tegra20.dtsi index 9739f91..4d7dee9 100644 --- a/arch/arm/dts/tegra20.dtsi +++ b/arch/arm/dts/tegra20.dtsi @@ -236,6 +236,18 @@ clocks = <&tegra_car 12>, <&tegra_car 124>; };
+ spi@7000c380 { + compatible = "nvidia,tegra20-sflash"; + reg = <0x7000c380 0x80>; + interrupts = <0 39 0x04>; + nvidia,dma-request-selector = <&apbdma 11>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + /* PERIPH_ID_SPI1, PLLP_OUT0 */ + clocks = <&tegra_car 43>; + }; + i2c@7000c400 { #address-cells = <1>; #size-cells = <0>; diff --git a/board/nvidia/dts/tegra20-seaboard.dts b/board/nvidia/dts/tegra20-seaboard.dts index b0da0be..eb92e06 100644 --- a/board/nvidia/dts/tegra20-seaboard.dts +++ b/board/nvidia/dts/tegra20-seaboard.dts @@ -78,6 +78,10 @@ clock-frequency = <100000>; };
+ spi@7000c380 { + spi-max-frequency = <25000000>; + }; + i2c@7000c400 { status = "disabled"; };

On 01/12/2013 02:07 AM, Allen Martin wrote:
Add node for tegra20 SPI SFLASH controller to fdt.
diff --git a/board/nvidia/dts/tegra20-seaboard.dts b/board/nvidia/dts/tegra20-seaboard.dts
- spi@7000c380 {
spi-max-frequency = <25000000>;
- };
Seaboard doesn't actually have SPI enabled, and probably shouldn't given that would require the hacky UART/SPI switch cruft.
TrimSlice on the other hand does have SPI enabled, so its .dts file would need the above change.

Add support for configuring tegra SPI driver from devicetree. Support is keyed off CONFIG_OF_CONTROL. Add entry in seaboard dts file for spi controller to describe seaboard spi.
Signed-off-by: Allen Martin amartin@nvidia.com --- drivers/spi/tegra_spi.c | 42 +++++++++++++++++++++++++++++++++++++++++- include/fdtdec.h | 1 + lib/fdtdec.c | 1 + 3 files changed, 43 insertions(+), 1 deletion(-)
diff --git a/drivers/spi/tegra_spi.c b/drivers/spi/tegra_spi.c index 9bb34e2..36b0cd0 100644 --- a/drivers/spi/tegra_spi.c +++ b/drivers/spi/tegra_spi.c @@ -32,6 +32,11 @@ #include <asm/arch-tegra/clk_rst.h> #include <asm/arch-tegra/tegra_spi.h> #include <spi.h> +#ifdef CONFIG_OF_CONTROL +#include <fdtdec.h> +#endif + +DECLARE_GLOBAL_DATA_PTR;
#if defined(CONFIG_SPI_CORRUPTS_UART) #define corrupt_delay() udelay(CONFIG_SPI_CORRUPTS_UART_DLY); @@ -44,6 +49,7 @@ struct tegra_spi_slave { struct spi_tegra *regs; unsigned int freq; unsigned int mode; + int periph_id; };
static inline struct tegra_spi_slave *to_tegra_spi(struct spi_slave *slave) @@ -85,7 +91,41 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, spi->slave.bus = bus; spi->slave.cs = cs; spi->freq = max_hz; +#ifdef CONFIG_OF_CONTROL + int node = fdtdec_next_compatible(gd->fdt_blob, 0, + COMPAT_NVIDIA_TEGRA20_SFLASH); + if (node < 0) { + debug("%s: cannot locate sflash node\n", __func__); + return NULL; + } + spi->regs = (struct spi_tegra *)fdtdec_get_addr(gd->fdt_blob, + node, "reg"); + if ((fdt_addr_t)spi->regs == FDT_ADDR_T_NONE) { + debug("%s: no sflash register found\n", __func__); + return NULL; + } + spi->freq = fdtdec_get_int(gd->fdt_blob, node, "spi-max-frequency", 0); + if (!spi->freq) { + debug("%s: no sflash max frequency found\n", __func__); + return NULL; + } + spi->periph_id = clock_decode_periph_id(gd->fdt_blob, node); + if (spi->periph_id == PERIPH_ID_NONE) { + debug("%s: could not decode periph id\n", __func__); + return NULL; + } +#else spi->regs = (struct spi_tegra *)NV_PA_SPI_BASE; + spi->freq = TEGRA_SPI_MAX_FREQ; + spi->periph_id = PERIPH_ID_SPI1; +#endif + if (max_hz < spi->freq) { + debug("%s: limiting frequency from %u to %u\n", __func__, + spi->freq, max_hz); + spi->freq = max_hz; + } + debug("%s: controller initialized at %p, freq = %u, periph_id = %d\n", + __func__, spi->regs, spi->freq, spi->periph_id); spi->mode = mode;
return &spi->slave; @@ -110,7 +150,7 @@ int spi_claim_bus(struct spi_slave *slave) u32 reg;
/* Change SPI clock to correct frequency, PLLP_OUT0 source */ - clock_start_periph_pll(PERIPH_ID_SPI1, CLOCK_ID_PERIPH, spi->freq); + clock_start_periph_pll(spi->periph_id, CLOCK_ID_PERIPH, spi->freq);
/* Clear stale status here */ reg = SPI_STAT_RDY | SPI_STAT_RXF_FLUSH | SPI_STAT_TXF_FLUSH | \ diff --git a/include/fdtdec.h b/include/fdtdec.h index 70d0e97..1504336 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_SFLASH, /* Tegra 2 SPI flash controller */
COMPAT_COUNT, }; diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 6dba438..6779278 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_SFLASH, "nvidia,tegra20-sflash"), };
const char *fdtdec_get_compatible(enum fdt_compat_id id)

SBC1 is SPI controller 1 on tegra30
Signed-off-by: Allen Martin amartin@nvidia.com --- arch/arm/cpu/tegra30-common/clock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/cpu/tegra30-common/clock.c b/arch/arm/cpu/tegra30-common/clock.c index c67a2e1..db5ac1e 100644 --- a/arch/arm/cpu/tegra30-common/clock.c +++ b/arch/arm/cpu/tegra30-common/clock.c @@ -318,7 +318,7 @@ static s8 periph_id_to_internal_id[PERIPH_ID_COUNT] = {
/* 40 */ NONE(KFUSE), - NONE(SBC1), /* SBC1, 0x34, is this SPI1? */ + PERIPHC_SBC1, PERIPHC_NOR, NONE(RESERVED43), PERIPHC_SBC2,

On Sat, Jan 12, 2013 at 1:07 AM, Allen Martin amartin@nvidia.com wrote:
SBC1 is SPI controller 1 on tegra30
Signed-off-by: Allen Martin amartin@nvidia.com
Acked-by: Simon Glass sjg@chromium.org
arch/arm/cpu/tegra30-common/clock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/cpu/tegra30-common/clock.c b/arch/arm/cpu/tegra30-common/clock.c index c67a2e1..db5ac1e 100644 --- a/arch/arm/cpu/tegra30-common/clock.c +++ b/arch/arm/cpu/tegra30-common/clock.c @@ -318,7 +318,7 @@ static s8 periph_id_to_internal_id[PERIPH_ID_COUNT] = {
/* 40 */ NONE(KFUSE),
NONE(SBC1), /* SBC1, 0x34, is this SPI1? */
PERIPHC_SBC1, PERIPHC_NOR, NONE(RESERVED43), PERIPHC_SBC2,
-- 1.7.10.4

Add tegra30 SPI SLINK nodes to fdt.
Signed-off-by: Allen Martin amartin@nvidia.com --- arch/arm/dts/tegra30.dtsi | 72 +++++++++++++++++++++++++++++++++++ board/nvidia/dts/tegra30-cardhu.dts | 4 ++ 2 files changed, 76 insertions(+)
diff --git a/arch/arm/dts/tegra30.dtsi b/arch/arm/dts/tegra30.dtsi index d58054c..5f02515 100644 --- a/arch/arm/dts/tegra30.dtsi +++ b/arch/arm/dts/tegra30.dtsi @@ -91,6 +91,78 @@ clocks = <&tegra_car 47>; };
+ spi@7000d400 { + compatible = "nvidia,tegra30-slink", "nvidia,tegra20-slink"; + reg = <0x7000d400 0x200>; + interrupts = <0 59 0x04>; + nvidia,dma-request-selector = <&apbdma 15>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + /* PERIPH_ID_SBC1, PLLP_OUT0 */ + clocks = <&tegra_car 41>; + }; + + spi@7000d600 { + compatible = "nvidia,tegra30-slink", "nvidia,tegra20-slink"; + reg = <0x7000d600 0x200>; + interrupts = <0 82 0x04>; + nvidia,dma-request-selector = <&apbdma 16>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + /* PERIPH_ID_SBC2, PLLP_OUT0 */ + clocks = <&tegra_car 44>; + }; + + spi@7000d800 { + compatible = "nvidia,tegra30-slink", "nvidia,tegra20-slink"; + reg = <0x7000d480 0x200>; + interrupts = <0 83 0x04>; + nvidia,dma-request-selector = <&apbdma 17>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + /* PERIPH_ID_SBC3, PLLP_OUT0 */ + clocks = <&tegra_car 46>; + }; + + spi@7000da00 { + compatible = "nvidia,tegra30-slink", "nvidia,tegra20-slink"; + reg = <0x7000da00 0x200>; + interrupts = <0 93 0x04>; + nvidia,dma-request-selector = <&apbdma 18>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + /* PERIPH_ID_SBC4, PLLP_OUT0 */ + clocks = <&tegra_car 68>; + }; + + spi@7000dc00 { + compatible = "nvidia,tegra30-slink", "nvidia,tegra20-slink"; + reg = <0x7000dc00 0x200>; + interrupts = <0 94 0x04>; + nvidia,dma-request-selector = <&apbdma 27>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + /* PERIPH_ID_SBC5, PLLP_OUT0 */ + clocks = <&tegra_car 104>; + }; + + spi@7000de00 { + compatible = "nvidia,tegra30-slink", "nvidia,tegra20-slink"; + reg = <0x7000de00 0x200>; + interrupts = <0 79 0x04>; + nvidia,dma-request-selector = <&apbdma 28>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + /* PERIPH_ID_SBC6, PLLP_OUT0 */ + clocks = <&tegra_car 105>; + }; + clocks { #address-cells = <1>; #size-cells = <0>; diff --git a/board/nvidia/dts/tegra30-cardhu.dts b/board/nvidia/dts/tegra30-cardhu.dts index 64c2ee2..887d3e7 100644 --- a/board/nvidia/dts/tegra30-cardhu.dts +++ b/board/nvidia/dts/tegra30-cardhu.dts @@ -43,6 +43,10 @@ clock-frequency = <100000>; };
+ spi@7000da00 { + spi-max-frequency = <25000000>; + }; + clocks { clk_32k: clk_32K { clock-frequency = <32768>;

On Sat, Jan 12, 2013 at 1:07 AM, Allen Martin amartin@nvidia.com wrote:
Add tegra30 SPI SLINK nodes to fdt.
Signed-off-by: Allen Martin amartin@nvidia.com
Acked-by: Simon Glass sjg@chromium.org

Add I/O addresses of SPI SLINK controllers 1-6
Signed-off-by: Allen Martin amartin@nvidia.com --- arch/arm/include/asm/arch-tegra/tegra.h | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/arch/arm/include/asm/arch-tegra/tegra.h b/arch/arm/include/asm/arch-tegra/tegra.h index 67e6fd0..d2435c1 100644 --- a/arch/arm/include/asm/arch-tegra/tegra.h +++ b/arch/arm/include/asm/arch-tegra/tegra.h @@ -40,6 +40,12 @@ #define NV_PA_APB_UARTE_BASE (NV_PA_APB_MISC_BASE + 0x6400) #define NV_PA_NAND_BASE (NV_PA_APB_MISC_BASE + 0x8000) #define NV_PA_SPI_BASE (NV_PA_APB_MISC_BASE + 0xC380) +#define NV_PA_SLINK1_BASE (NV_PA_APB_MISC_BASE + 0xD400) +#define NV_PA_SLINK2_BASE (NV_PA_APB_MISC_BASE + 0xD600) +#define NV_PA_SLINK3_BASE (NV_PA_APB_MISC_BASE + 0xD800) +#define NV_PA_SLINK4_BASE (NV_PA_APB_MISC_BASE + 0xDA00) +#define NV_PA_SLINK5_BASE (NV_PA_APB_MISC_BASE + 0xDC00) +#define NV_PA_SLINK6_BASE (NV_PA_APB_MISC_BASE + 0xDE00) #define TEGRA_DVC_BASE (NV_PA_APB_MISC_BASE + 0xD000) #define NV_PA_PMC_BASE (NV_PA_APB_MISC_BASE + 0xE400) #define NV_PA_EMC_BASE (NV_PA_APB_MISC_BASE + 0xF400)

On Sat, Jan 12, 2013 at 1:07 AM, Allen Martin amartin@nvidia.com wrote:
Add I/O addresses of SPI SLINK controllers 1-6
Signed-off-by: Allen Martin amartin@nvidia.com
Acked-by: Simon Glass sjg@chromium.org
(optional thought below)
arch/arm/include/asm/arch-tegra/tegra.h | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/arch/arm/include/asm/arch-tegra/tegra.h b/arch/arm/include/asm/arch-tegra/tegra.h index 67e6fd0..d2435c1 100644 --- a/arch/arm/include/asm/arch-tegra/tegra.h +++ b/arch/arm/include/asm/arch-tegra/tegra.h @@ -40,6 +40,12 @@ #define NV_PA_APB_UARTE_BASE (NV_PA_APB_MISC_BASE + 0x6400) #define NV_PA_NAND_BASE (NV_PA_APB_MISC_BASE + 0x8000) #define NV_PA_SPI_BASE (NV_PA_APB_MISC_BASE + 0xC380) +#define NV_PA_SLINK1_BASE (NV_PA_APB_MISC_BASE + 0xD400) +#define NV_PA_SLINK2_BASE (NV_PA_APB_MISC_BASE + 0xD600) +#define NV_PA_SLINK3_BASE (NV_PA_APB_MISC_BASE + 0xD800) +#define NV_PA_SLINK4_BASE (NV_PA_APB_MISC_BASE + 0xDA00) +#define NV_PA_SLINK5_BASE (NV_PA_APB_MISC_BASE + 0xDC00) +#define NV_PA_SLINK6_BASE (NV_PA_APB_MISC_BASE + 0xDE00)
Perhaps add #ifdef CONFIG_SPL_BUILD around this so people don't use it accidentially?
#define TEGRA_DVC_BASE (NV_PA_APB_MISC_BASE + 0xD000) #define NV_PA_PMC_BASE (NV_PA_APB_MISC_BASE + 0xE400)
#define NV_PA_EMC_BASE (NV_PA_APB_MISC_BASE + 0xF400)
1.7.10.4
Regards, Simon

Add driver for tegra SPI "SLINK" style driver. This controller is similar to the tegra20 SPI "SFLASH" controller. The difference is that the SLINK controller is a genernal purpose SPI controller and the SFLASH controller is special purpose and can only talk to FLASH devices. In addition there are potentially many instances of an SLINK controller on tegra and only a single instance of SFLASH. Tegra20 is currently ths only version of tegra that instantiates an SFLASH controller.
This driver supports basic PIO mode of operation and is configurable (CONFIG_OF_CONTROL) to be driven off devicetree bindings. Up to 4 devices per controller may be attached, although typically only a single chip select line is exposed from tegra per controller so in reality this is usually limited to 1.
To enable this driver, use CONFIG_TEGRA_SLINK
Signed-off-by: Allen Martin amartin@nvidia.com --- arch/arm/include/asm/arch-tegra/tegra_slink.h | 84 +++++++ board/nvidia/common/board.c | 3 +- drivers/spi/Makefile | 1 + drivers/spi/tegra_slink.c | 335 +++++++++++++++++++++++++ include/fdtdec.h | 1 + lib/fdtdec.c | 1 + 6 files changed, 424 insertions(+), 1 deletion(-) create mode 100644 arch/arm/include/asm/arch-tegra/tegra_slink.h create mode 100644 drivers/spi/tegra_slink.c
diff --git a/arch/arm/include/asm/arch-tegra/tegra_slink.h b/arch/arm/include/asm/arch-tegra/tegra_slink.h new file mode 100644 index 0000000..74804b5 --- /dev/null +++ b/arch/arm/include/asm/arch-tegra/tegra_slink.h @@ -0,0 +1,84 @@ +/* + * NVIDIA Tegra SPI-SLINK controller + * + * Copyright 2010-2013 NVIDIA Corporation + * + * This software may be used and distributed according to the + * terms of the GNU Public License, Version 2, incorporated + * herein by reference. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _TEGRA_SLINK_H_ +#define _TEGRA_SLINK_H_ + +#include <asm/types.h> + +struct slink_tegra { + u32 command; /* SLINK_COMMAND_0 register */ + u32 command2; /* SLINK_COMMAND2_0 reg */ + u32 status; /* SLINK_STATUS_0 register */ + u32 reserved; /* Reserved offset 0C */ + u32 mas_data; /* SLINK_MAS_DATA_0 reg */ + u32 slav_data; /* SLINK_SLAVE_DATA_0 reg */ + u32 dma_ctl; /* SLINK_DMA_CTL_0 register */ + u32 status2; /* SLINK_STATUS2_0 reg */ + u32 rsvd[56]; /* 0x20 to 0xFF reserved */ + u32 tx_fifo; /* SLINK_TX_FIFO_0 reg off 100h */ + u32 rsvd2[31]; /* 0x104 to 0x17F reserved */ + u32 rx_fifo; /* SLINK_RX_FIFO_0 reg off 180h */ +}; + +/* COMMAND */ +#define SLINK_CMD_ENB (1 << 31) +#define SLINK_CMD_GO (1 << 30) +#define SLINK_CMD_M_S (1 << 28) +#define SLINK_CMD_CK_SDA (1 << 21) +#define SLINK_CMD_CS_POL (1 << 13) +#define SLINK_CMD_CS_VAL (1 << 12) +#define SLINK_CMD_CS_SOFT (1 << 11) +#define SLINK_CMD_BIT_LENGTH (1 << 4) +#define SLINK_CMD_BIT_LENGTH_MASK 0x0000001F +/* COMMAND2 */ +#define SLINK_CMD2_TXEN (1 << 30) +#define SLINK_CMD2_RXEN (1 << 31) +#define SLINK_CMD2_SS_EN (1 << 18) +#define SLINK_CMD2_SS_EN_SHIFT 18 +#define SLINK_CMD2_SS_EN_MASK 0x000C0000 +#define SLINK_CMD2_CS_ACTIVE_BETWEEN (1 << 17) +/* STATUS */ +#define SLINK_STAT_BSY (1 << 31) +#define SLINK_STAT_RDY (1 << 30) +#define SLINK_STAT_ERR (1 << 29) +#define SLINK_STAT_RXF_FLUSH (1 << 27) +#define SLINK_STAT_TXF_FLUSH (1 << 26) +#define SLINK_STAT_RXF_OVF (1 << 25) +#define SLINK_STAT_TXF_UNR (1 << 24) +#define SLINK_STAT_RXF_EMPTY (1 << 23) +#define SLINK_STAT_RXF_FULL (1 << 22) +#define SLINK_STAT_TXF_EMPTY (1 << 21) +#define SLINK_STAT_TXF_FULL (1 << 20) +#define SLINK_STAT_TXF_OVF (1 << 19) +#define SLINK_STAT_RXF_UNR (1 << 18) +#define SLINK_STAT_CUR_BLKCNT (1 << 15) +/* STATUS2 */ +#define SLINK_STAT2_RXF_FULL_CNT (1 << 16) +#define SLINK_STAT2_TXF_FULL_CNT (1 << 0) + +#define SPI_TIMEOUT 1000 +#define TEGRA_SPI_MAX_FREQ 52000000 + +#endif /* _TEGRA_SLINK_H_ */ diff --git a/board/nvidia/common/board.c b/board/nvidia/common/board.c index a4af539..63a7fcb 100644 --- a/board/nvidia/common/board.c +++ b/board/nvidia/common/board.c @@ -131,10 +131,11 @@ int board_init(void) #ifdef CONFIG_SPI_UART_SWITCH gpio_config_uart(); #endif -#ifdef CONFIG_TEGRA_SPI +#if defined(CONFIG_TEGRA_SPI) || defined(CONFIG_TEGRA_SLINK) pin_mux_spi(); spi_init(); #endif + #ifdef CONFIG_PWM_TEGRA if (pwm_init(gd->fdt_blob)) debug("%s: Failed to init pwm\n", __func__); diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 824d357..83abcbd 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -46,6 +46,7 @@ COBJS-$(CONFIG_SOFT_SPI) += soft_spi.o COBJS-$(CONFIG_SH_SPI) += sh_spi.o COBJS-$(CONFIG_FSL_ESPI) += fsl_espi.o COBJS-$(CONFIG_TEGRA_SPI) += tegra_spi.o +COBJS-$(CONFIG_TEGRA_SLINK) += tegra_slink.o COBJS-$(CONFIG_XILINX_SPI) += xilinx_spi.o
COBJS := $(COBJS-y) diff --git a/drivers/spi/tegra_slink.c b/drivers/spi/tegra_slink.c new file mode 100644 index 0000000..6e1c436 --- /dev/null +++ b/drivers/spi/tegra_slink.c @@ -0,0 +1,335 @@ +/* + * NVIDIA Tegra SPI-SLINK controller + * + * Copyright (c) 2010-2013 NVIDIA Corporation + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <malloc.h> +#include <asm/io.h> +#include <asm/gpio.h> +#include <asm/arch/clock.h> +#include <asm/arch-tegra/clk_rst.h> +#include <asm/arch-tegra/tegra_slink.h> +#include <spi.h> +#ifdef CONFIG_OF_CONTROL +#include <fdtdec.h> +#endif + +DECLARE_GLOBAL_DATA_PTR; + +struct tegra_spi_ctrl { + struct slink_tegra *regs; + unsigned int freq; + unsigned int mode; + int periph_id; + int valid; +}; + +struct tegra_spi_slave { + struct spi_slave slave; + struct tegra_spi_ctrl *ctrl; +}; + +static struct tegra_spi_ctrl spi_ctrls[CONFIG_TEGRA_SLINK_CTRLS]; + +static inline struct tegra_spi_slave *to_tegra_spi(struct spi_slave *slave) +{ + return container_of(slave, struct tegra_spi_slave, slave); +} + +int spi_cs_is_valid(unsigned int bus, unsigned int cs) +{ + if (bus >= CONFIG_TEGRA_SLINK_CTRLS || cs > 3 || !spi_ctrls[bus].valid) + return 0; + else + return 1; +} + +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode) +{ + struct tegra_spi_slave *spi; + + debug("%s: bus: %u, cs: %u, max_hz: %u, mode: %u\n", __func__, + bus, cs, max_hz, mode); + + if (!spi_cs_is_valid(bus, cs)) { + printf("SPI error: unsupported bus %d / chip select %d\n", + bus, cs); + return NULL; + } + + if (max_hz > TEGRA_SPI_MAX_FREQ) { + printf("SPI error: unsupported frequency %d Hz. Max frequency" + " is %d Hz\n", max_hz, TEGRA_SPI_MAX_FREQ); + return NULL; + } + + spi = malloc(sizeof(struct tegra_spi_slave)); + if (!spi) { + printf("SPI error: malloc of SPI structure failed\n"); + return NULL; + } + spi->slave.bus = bus; + spi->slave.cs = cs; + spi->ctrl = &spi_ctrls[bus]; + if (!spi->ctrl) { + printf("SPI error: could not find controller for bus %d\n", + bus); + return NULL; + } + + if (max_hz < spi->ctrl->freq) { + debug("%s: limiting frequency from %u to %u\n", __func__, + spi->ctrl->freq, max_hz); + spi->ctrl->freq = max_hz; + } + spi->ctrl->mode = mode; + + return &spi->slave; +} + +void spi_free_slave(struct spi_slave *slave) +{ + struct tegra_spi_slave *spi = to_tegra_spi(slave); + + free(spi); +} + +void spi_init(void) +{ + int node = 0, i; + struct tegra_spi_ctrl *ctrl; + for (i = 0; i < CONFIG_TEGRA_SLINK_CTRLS; i++) { + ctrl = &spi_ctrls[i]; +#ifdef CONFIG_OF_CONTROL + node = fdtdec_next_compatible(gd->fdt_blob, node, + COMPAT_NVIDIA_TEGRA20_SLINK); + if (!node) + break; + ctrl->regs = (struct slink_tegra *)fdtdec_get_addr(gd->fdt_blob, + node, "reg"); + if ((fdt_addr_t)ctrl->regs == FDT_ADDR_T_NONE) { + debug("%s: no slink register found\n", __func__); + continue; + } + ctrl->freq = fdtdec_get_int(gd->fdt_blob, node, + "spi-max-frequency", 0); + if (!ctrl->freq) { + debug("%s: no slink max frequency found\n", __func__); + continue; + } + + ctrl->periph_id = clock_decode_periph_id(gd->fdt_blob, node); + if (ctrl->periph_id == PERIPH_ID_NONE) { + debug("%s: could not decode periph id\n", __func__); + continue; + } + ctrl->valid = 1; +#else + u32 base_regs[] = { + NV_PA_SLINK1_BASE, + NV_PA_SLINK2_BASE, + NV_PA_SLINK3_BASE, + NV_PA_SLINK4_BASE, + NV_PA_SLINK5_BASE, + NV_PA_SLINK6_BASE, + }; + int periph_ids[] = { + PERIPH_ID_SBC1, + PERIPH_ID_SBC2, + PERIPH_ID_SBC3, + PERIPH_ID_SBC4, + PERIPH_ID_SBC5, + PERIPH_ID_SBC6, + } + ctrl->regs = (struct slink_tegra *)base_regs[i]; + ctrl->freq = TEGRA_SPI_MAX_FREQ; + ctrl->periph_id = periph_ids[i]; + ctrl->valid = 1; +#endif + + debug("%s: found controller at %p, freq = %u, periph_id = %d\n", + __func__, ctrl->regs, ctrl->freq, ctrl->periph_id); + } +} + +int spi_claim_bus(struct spi_slave *slave) +{ + struct tegra_spi_slave *spi = to_tegra_spi(slave); + struct slink_tegra *regs = spi->ctrl->regs; + u32 reg; + + /* Change SPI clock to correct frequency, PLLP_OUT0 source */ + clock_start_periph_pll(spi->ctrl->periph_id, CLOCK_ID_PERIPH, + spi->ctrl->freq); + + /* Clear stale status here */ + reg = SLINK_STAT_RDY | SLINK_STAT_RXF_FLUSH | SLINK_STAT_TXF_FLUSH | \ + SLINK_STAT_RXF_UNR | SLINK_STAT_TXF_OVF; + writel(reg, ®s->status); + debug("%s: STATUS = %08x\n", __func__, readl(®s->status)); + + /* Set master mode and sw controlled CS */ + reg = readl(®s->command); + reg |= SLINK_CMD_M_S | SLINK_CMD_CS_SOFT; + writel(reg, ®s->command); + debug("%s: COMMAND = %08x\n", __func__, readl(®s->command)); + + return 0; +} + +void spi_release_bus(struct spi_slave *slave) +{ +} + +void spi_cs_activate(struct spi_slave *slave) +{ + struct tegra_spi_slave *spi = to_tegra_spi(slave); + struct slink_tegra *regs = spi->ctrl->regs; + + /* CS is negated on Tegra, so drive a 1 to get a 0 */ + setbits_le32(®s->command, SLINK_CMD_CS_VAL); +} + +void spi_cs_deactivate(struct spi_slave *slave) +{ + struct tegra_spi_slave *spi = to_tegra_spi(slave); + struct slink_tegra *regs = spi->ctrl->regs; + + /* CS is negated on Tegra, so drive a 0 to get a 1 */ + clrbits_le32(®s->command, SLINK_CMD_CS_VAL); +} + +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, + const void *data_out, void *data_in, unsigned long flags) +{ + struct tegra_spi_slave *spi = to_tegra_spi(slave); + struct slink_tegra *regs = spi->ctrl->regs; + u32 reg, tmpdout, tmpdin = 0; + const u8 *dout = data_out; + u8 *din = data_in; + int num_bytes; + int ret; + + debug("%s: slave %u:%u dout %p din %p bitlen %u\n", + __func__, slave->bus, slave->cs, dout, din, bitlen); + if (bitlen % 8) + return -1; + num_bytes = bitlen / 8; + + ret = 0; + + reg = readl(®s->status); + writel(reg, ®s->status); /* Clear all SPI events via R/W */ + debug("%s entry: STATUS = %08x\n", __func__, reg); + + reg = readl(®s->status2); + writel(reg, ®s->status2); /* Clear all STATUS2 events via R/W */ + debug("%s entry: STATUS2 = %08x\n", __func__, reg); + + debug("%s entry: COMMAND = %08x\n", __func__, readl(®s->command)); + + reg = readl(®s->command2); + reg |= SLINK_CMD2_TXEN | SLINK_CMD2_RXEN | + (slave->cs << SLINK_CMD2_SS_EN_SHIFT); + writel(reg, ®s->command2); + debug("%s entry: COMMAND2 = %08x\n", __func__, reg); + + if (flags & SPI_XFER_BEGIN) + spi_cs_activate(slave); + + /* handle data in 32-bit chunks */ + while (num_bytes > 0) { + int bytes; + int is_read = 0; + int tm, i; + + tmpdout = 0; + bytes = (num_bytes > 4) ? 4 : num_bytes; + + if (dout != NULL) { + for (i = 0; i < bytes; ++i) + tmpdout = (tmpdout << 8) | dout[i]; + } + + num_bytes -= bytes; + if (dout) + dout += bytes; + + clrsetbits_le32(®s->command, SLINK_CMD_BIT_LENGTH_MASK, + bytes * 8 - 1); + writel(tmpdout, ®s->tx_fifo); + setbits_le32(®s->command, SLINK_CMD_GO); + + /* + * Wait for SPI transmit FIFO to empty, or to time out. + * The RX FIFO status will be read and cleared last + */ + for (tm = 0, is_read = 0; tm < SPI_TIMEOUT; ++tm) { + u32 status; + + status = readl(®s->status); + + /* We can exit when we've had both RX and TX activity */ + if (is_read && (status & SLINK_STAT_TXF_EMPTY)) + break; + + if ((status & (SLINK_STAT_BSY | SLINK_STAT_RDY)) != + SLINK_STAT_RDY) + tm++; + + else if (!(status & SLINK_STAT_RXF_EMPTY)) { + tmpdin = readl(®s->rx_fifo); + is_read = 1; + + /* swap bytes read in */ + if (din != NULL) { + for (i = bytes - 1; i >= 0; --i) { + din[i] = tmpdin & 0xff; + tmpdin >>= 8; + } + din += bytes; + } + } + } + + if (tm >= SPI_TIMEOUT) + ret = tm; + + /* clear ACK RDY, etc. bits */ + writel(readl(®s->status), ®s->status); + } + + if (flags & SPI_XFER_END) + spi_cs_deactivate(slave); + + debug("%s: transfer ended. Value=%08x, status = %08x\n", + __func__, tmpdin, readl(®s->status)); + + if (ret) { + printf("%s: timeout during SPI transfer, tm %d\n", + __func__, ret); + return -1; + } + + return 0; +} diff --git a/include/fdtdec.h b/include/fdtdec.h index 1504336..14aa308 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -71,6 +71,7 @@ enum fdt_compat_id { COMPAT_NVIDIA_TEGRA20_PWM, /* Tegra 2 PWM controller */ COMPAT_NVIDIA_TEGRA20_DC, /* Tegra 2 Display controller */ COMPAT_NVIDIA_TEGRA20_SFLASH, /* Tegra 2 SPI flash controller */ + COMPAT_NVIDIA_TEGRA20_SLINK, /* Tegra 2 SPI SLINK controller */
COMPAT_COUNT, }; diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 6779278..4fef428 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -46,6 +46,7 @@ static const char * const compat_names[COMPAT_COUNT] = { COMPAT(NVIDIA_TEGRA20_PWM, "nvidia,tegra20-pwm"), COMPAT(NVIDIA_TEGRA20_DC, "nvidia,tegra20-dc"), COMPAT(NVIDIA_TEGRA20_SFLASH, "nvidia,tegra20-sflash"), + COMPAT(NVIDIA_TEGRA20_SLINK, "nvidia,tegra20-slink"), };
const char *fdtdec_get_compatible(enum fdt_compat_id id)

Hi,
On Sat, Jan 12, 2013 at 1:07 AM, Allen Martin amartin@nvidia.com wrote:
Add driver for tegra SPI "SLINK" style driver. This controller is similar to the tegra20 SPI "SFLASH" controller. The difference is that the SLINK controller is a genernal purpose SPI controller and the SFLASH controller is special purpose and can only talk to FLASH devices. In addition there are potentially many instances of an SLINK controller on tegra and only a single instance of SFLASH. Tegra20 is currently ths only version of tegra that instantiates an SFLASH controller.
This driver supports basic PIO mode of operation and is configurable (CONFIG_OF_CONTROL) to be driven off devicetree bindings. Up to 4 devices per controller may be attached, although typically only a single chip select line is exposed from tegra per controller so in reality this is usually limited to 1.
To enable this driver, use CONFIG_TEGRA_SLINK
A few comments - note I am on holiday next week so please don't wait for my response on the next version.
Signed-off-by: Allen Martin amartin@nvidia.com
arch/arm/include/asm/arch-tegra/tegra_slink.h | 84 +++++++ board/nvidia/common/board.c | 3 +- drivers/spi/Makefile | 1 + drivers/spi/tegra_slink.c | 335 +++++++++++++++++++++++++ include/fdtdec.h | 1 + lib/fdtdec.c | 1 + 6 files changed, 424 insertions(+), 1 deletion(-) create mode 100644 arch/arm/include/asm/arch-tegra/tegra_slink.h create mode 100644 drivers/spi/tegra_slink.c
diff --git a/arch/arm/include/asm/arch-tegra/tegra_slink.h b/arch/arm/include/asm/arch-tegra/tegra_slink.h new file mode 100644 index 0000000..74804b5 --- /dev/null +++ b/arch/arm/include/asm/arch-tegra/tegra_slink.h @@ -0,0 +1,84 @@ +/*
- NVIDIA Tegra SPI-SLINK controller
- Copyright 2010-2013 NVIDIA Corporation
- This software may be used and distributed according to the
- terms of the GNU Public License, Version 2, incorporated
- herein by reference.
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- Version 2 as published by the Free Software Foundation.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- MA 02111-1307 USA
- */
+#ifndef _TEGRA_SLINK_H_ +#define _TEGRA_SLINK_H_
+#include <asm/types.h>
+struct slink_tegra {
u32 command; /* SLINK_COMMAND_0 register */
u32 command2; /* SLINK_COMMAND2_0 reg */
u32 status; /* SLINK_STATUS_0 register */
u32 reserved; /* Reserved offset 0C */
u32 mas_data; /* SLINK_MAS_DATA_0 reg */
u32 slav_data; /* SLINK_SLAVE_DATA_0 reg */
u32 dma_ctl; /* SLINK_DMA_CTL_0 register */
u32 status2; /* SLINK_STATUS2_0 reg */
u32 rsvd[56]; /* 0x20 to 0xFF reserved */
u32 tx_fifo; /* SLINK_TX_FIFO_0 reg off 100h */
u32 rsvd2[31]; /* 0x104 to 0x17F reserved */
u32 rx_fifo; /* SLINK_RX_FIFO_0 reg off 180h */
+};
+/* COMMAND */ +#define SLINK_CMD_ENB (1 << 31) +#define SLINK_CMD_GO (1 << 30) +#define SLINK_CMD_M_S (1 << 28) +#define SLINK_CMD_CK_SDA (1 << 21) +#define SLINK_CMD_CS_POL (1 << 13) +#define SLINK_CMD_CS_VAL (1 << 12) +#define SLINK_CMD_CS_SOFT (1 << 11) +#define SLINK_CMD_BIT_LENGTH (1 << 4) +#define SLINK_CMD_BIT_LENGTH_MASK 0x0000001F +/* COMMAND2 */ +#define SLINK_CMD2_TXEN (1 << 30) +#define SLINK_CMD2_RXEN (1 << 31) +#define SLINK_CMD2_SS_EN (1 << 18) +#define SLINK_CMD2_SS_EN_SHIFT 18 +#define SLINK_CMD2_SS_EN_MASK 0x000C0000 +#define SLINK_CMD2_CS_ACTIVE_BETWEEN (1 << 17) +/* STATUS */ +#define SLINK_STAT_BSY (1 << 31) +#define SLINK_STAT_RDY (1 << 30) +#define SLINK_STAT_ERR (1 << 29) +#define SLINK_STAT_RXF_FLUSH (1 << 27) +#define SLINK_STAT_TXF_FLUSH (1 << 26) +#define SLINK_STAT_RXF_OVF (1 << 25) +#define SLINK_STAT_TXF_UNR (1 << 24) +#define SLINK_STAT_RXF_EMPTY (1 << 23) +#define SLINK_STAT_RXF_FULL (1 << 22) +#define SLINK_STAT_TXF_EMPTY (1 << 21) +#define SLINK_STAT_TXF_FULL (1 << 20) +#define SLINK_STAT_TXF_OVF (1 << 19) +#define SLINK_STAT_RXF_UNR (1 << 18) +#define SLINK_STAT_CUR_BLKCNT (1 << 15) +/* STATUS2 */ +#define SLINK_STAT2_RXF_FULL_CNT (1 << 16) +#define SLINK_STAT2_TXF_FULL_CNT (1 << 0)
+#define SPI_TIMEOUT 1000 +#define TEGRA_SPI_MAX_FREQ 52000000
+#endif /* _TEGRA_SLINK_H_ */ diff --git a/board/nvidia/common/board.c b/board/nvidia/common/board.c index a4af539..63a7fcb 100644 --- a/board/nvidia/common/board.c +++ b/board/nvidia/common/board.c @@ -131,10 +131,11 @@ int board_init(void) #ifdef CONFIG_SPI_UART_SWITCH gpio_config_uart(); #endif -#ifdef CONFIG_TEGRA_SPI +#if defined(CONFIG_TEGRA_SPI) || defined(CONFIG_TEGRA_SLINK) pin_mux_spi(); spi_init(); #endif
#ifdef CONFIG_PWM_TEGRA if (pwm_init(gd->fdt_blob)) debug("%s: Failed to init pwm\n", __func__); diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 824d357..83abcbd 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -46,6 +46,7 @@ COBJS-$(CONFIG_SOFT_SPI) += soft_spi.o COBJS-$(CONFIG_SH_SPI) += sh_spi.o COBJS-$(CONFIG_FSL_ESPI) += fsl_espi.o COBJS-$(CONFIG_TEGRA_SPI) += tegra_spi.o +COBJS-$(CONFIG_TEGRA_SLINK) += tegra_slink.o COBJS-$(CONFIG_XILINX_SPI) += xilinx_spi.o
COBJS := $(COBJS-y) diff --git a/drivers/spi/tegra_slink.c b/drivers/spi/tegra_slink.c new file mode 100644 index 0000000..6e1c436 --- /dev/null +++ b/drivers/spi/tegra_slink.c @@ -0,0 +1,335 @@ +/*
- NVIDIA Tegra SPI-SLINK controller
- Copyright (c) 2010-2013 NVIDIA Corporation
- See file CREDITS for list of people who contributed to this
- project.
- This software is licensed under the terms of the GNU General Public
- License version 2, as published by the Free Software Foundation, and
- may be copied, distributed, and modified under those terms.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- MA 02111-1307 USA
- */
+#include <common.h> +#include <malloc.h> +#include <asm/io.h> +#include <asm/gpio.h> +#include <asm/arch/clock.h> +#include <asm/arch-tegra/clk_rst.h> +#include <asm/arch-tegra/tegra_slink.h> +#include <spi.h> +#ifdef CONFIG_OF_CONTROL
You probably don't need this ifdef
+#include <fdtdec.h> +#endif
+DECLARE_GLOBAL_DATA_PTR;
+struct tegra_spi_ctrl {
struct slink_tegra *regs;
unsigned int freq;
unsigned int mode;
int periph_id;
int valid;
+};
+struct tegra_spi_slave {
struct spi_slave slave;
struct tegra_spi_ctrl *ctrl;
+};
+static struct tegra_spi_ctrl spi_ctrls[CONFIG_TEGRA_SLINK_CTRLS];
+static inline struct tegra_spi_slave *to_tegra_spi(struct spi_slave *slave) +{
return container_of(slave, struct tegra_spi_slave, slave);
+}
+int spi_cs_is_valid(unsigned int bus, unsigned int cs) +{
if (bus >= CONFIG_TEGRA_SLINK_CTRLS || cs > 3 || !spi_ctrls[bus].valid)
return 0;
else
return 1;
+}
+struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
unsigned int max_hz, unsigned int mode)
+{
struct tegra_spi_slave *spi;
debug("%s: bus: %u, cs: %u, max_hz: %u, mode: %u\n", __func__,
bus, cs, max_hz, mode);
if (!spi_cs_is_valid(bus, cs)) {
printf("SPI error: unsupported bus %d / chip select %d\n",
bus, cs);
return NULL;
}
if (max_hz > TEGRA_SPI_MAX_FREQ) {
printf("SPI error: unsupported frequency %d Hz. Max frequency"
" is %d Hz\n", max_hz, TEGRA_SPI_MAX_FREQ);
return NULL;
}
spi = malloc(sizeof(struct tegra_spi_slave));
Please also look at my SPI series where I added an allocate function for this.
http://patchwork.ozlabs.org/patch/208226/ http://patchwork.ozlabs.org/patch/208229/
if (!spi) {
printf("SPI error: malloc of SPI structure failed\n");
return NULL;
}
spi->slave.bus = bus;
spi->slave.cs = cs;
spi->ctrl = &spi_ctrls[bus];
if (!spi->ctrl) {
printf("SPI error: could not find controller for bus %d\n",
bus);
return NULL;
}
if (max_hz < spi->ctrl->freq) {
debug("%s: limiting frequency from %u to %u\n", __func__,
spi->ctrl->freq, max_hz);
spi->ctrl->freq = max_hz;
}
spi->ctrl->mode = mode;
return &spi->slave;
+}
+void spi_free_slave(struct spi_slave *slave) +{
struct tegra_spi_slave *spi = to_tegra_spi(slave);
free(spi);
+}
+void spi_init(void) +{
int node = 0, i;
struct tegra_spi_ctrl *ctrl;
blank line here
for (i = 0; i < CONFIG_TEGRA_SLINK_CTRLS; i++) {
ctrl = &spi_ctrls[i];
+#ifdef CONFIG_OF_CONTROL
node = fdtdec_next_compatible(gd->fdt_blob, node,
COMPAT_NVIDIA_TEGRA20_SLINK);
if (!node)
break;
I think you should be using fdtdec_find_aliases_for_id() so that aliases work.
ctrl->regs = (struct slink_tegra *)fdtdec_get_addr(gd->fdt_blob,
node, "reg");
if ((fdt_addr_t)ctrl->regs == FDT_ADDR_T_NONE) {
debug("%s: no slink register found\n", __func__);
continue;
}
ctrl->freq = fdtdec_get_int(gd->fdt_blob, node,
"spi-max-frequency", 0);
if (!ctrl->freq) {
debug("%s: no slink max frequency found\n", __func__);
continue;
}
ctrl->periph_id = clock_decode_periph_id(gd->fdt_blob, node);
if (ctrl->periph_id == PERIPH_ID_NONE) {
debug("%s: could not decode periph id\n", __func__);
continue;
}
ctrl->valid = 1;
+#else
u32 base_regs[] = {
NV_PA_SLINK1_BASE,
NV_PA_SLINK2_BASE,
NV_PA_SLINK3_BASE,
NV_PA_SLINK4_BASE,
NV_PA_SLINK5_BASE,
NV_PA_SLINK6_BASE,
};
int periph_ids[] = {
PERIPH_ID_SBC1,
PERIPH_ID_SBC2,
PERIPH_ID_SBC3,
PERIPH_ID_SBC4,
PERIPH_ID_SBC5,
PERIPH_ID_SBC6,
}
ctrl->regs = (struct slink_tegra *)base_regs[i];
ctrl->freq = TEGRA_SPI_MAX_FREQ;
ctrl->periph_id = periph_ids[i];
ctrl->valid = 1;
+#endif
debug("%s: found controller at %p, freq = %u, periph_id = %d\n",
__func__, ctrl->regs, ctrl->freq, ctrl->periph_id);
}
+}
+int spi_claim_bus(struct spi_slave *slave) +{
struct tegra_spi_slave *spi = to_tegra_spi(slave);
struct slink_tegra *regs = spi->ctrl->regs;
u32 reg;
/* Change SPI clock to correct frequency, PLLP_OUT0 source */
clock_start_periph_pll(spi->ctrl->periph_id, CLOCK_ID_PERIPH,
spi->ctrl->freq);
/* Clear stale status here */
reg = SLINK_STAT_RDY | SLINK_STAT_RXF_FLUSH | SLINK_STAT_TXF_FLUSH | \
SLINK_STAT_RXF_UNR | SLINK_STAT_TXF_OVF;
writel(reg, ®s->status);
debug("%s: STATUS = %08x\n", __func__, readl(®s->status));
/* Set master mode and sw controlled CS */
reg = readl(®s->command);
reg |= SLINK_CMD_M_S | SLINK_CMD_CS_SOFT;
writel(reg, ®s->command);
debug("%s: COMMAND = %08x\n", __func__, readl(®s->command));
return 0;
+}
+void spi_release_bus(struct spi_slave *slave) +{ +}
+void spi_cs_activate(struct spi_slave *slave) +{
struct tegra_spi_slave *spi = to_tegra_spi(slave);
struct slink_tegra *regs = spi->ctrl->regs;
/* CS is negated on Tegra, so drive a 1 to get a 0 */
setbits_le32(®s->command, SLINK_CMD_CS_VAL);
+}
+void spi_cs_deactivate(struct spi_slave *slave) +{
struct tegra_spi_slave *spi = to_tegra_spi(slave);
struct slink_tegra *regs = spi->ctrl->regs;
/* CS is negated on Tegra, so drive a 0 to get a 1 */
clrbits_le32(®s->command, SLINK_CMD_CS_VAL);
+}
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
const void *data_out, void *data_in, unsigned long flags)
+{
struct tegra_spi_slave *spi = to_tegra_spi(slave);
struct slink_tegra *regs = spi->ctrl->regs;
u32 reg, tmpdout, tmpdin = 0;
const u8 *dout = data_out;
u8 *din = data_in;
int num_bytes;
int ret;
debug("%s: slave %u:%u dout %p din %p bitlen %u\n",
__func__, slave->bus, slave->cs, dout, din, bitlen);
if (bitlen % 8)
debug()
return -1;
num_bytes = bitlen / 8;
ret = 0;
reg = readl(®s->status);
writel(reg, ®s->status); /* Clear all SPI events via R/W */
debug("%s entry: STATUS = %08x\n", __func__, reg);
reg = readl(®s->status2);
writel(reg, ®s->status2); /* Clear all STATUS2 events via R/W */
debug("%s entry: STATUS2 = %08x\n", __func__, reg);
debug("%s entry: COMMAND = %08x\n", __func__, readl(®s->command));
reg = readl(®s->command2);
reg |= SLINK_CMD2_TXEN | SLINK_CMD2_RXEN |
(slave->cs << SLINK_CMD2_SS_EN_SHIFT);
writel(reg, ®s->command2);
Could use clrsetbits_le32() if you like
debug("%s entry: COMMAND2 = %08x\n", __func__, reg);
if (flags & SPI_XFER_BEGIN)
spi_cs_activate(slave);
/* handle data in 32-bit chunks */
while (num_bytes > 0) {
int bytes;
int is_read = 0;
int tm, i;
tmpdout = 0;
bytes = (num_bytes > 4) ? 4 : num_bytes;
if (dout != NULL) {
for (i = 0; i < bytes; ++i)
tmpdout = (tmpdout << 8) | dout[i];
dout += bytes here...
}
num_bytes -= bytes;
if (dout)
dout += bytes;
instead of here?
clrsetbits_le32(®s->command, SLINK_CMD_BIT_LENGTH_MASK,
bytes * 8 - 1);
writel(tmpdout, ®s->tx_fifo);
setbits_le32(®s->command, SLINK_CMD_GO);
/*
* Wait for SPI transmit FIFO to empty, or to time out.
* The RX FIFO status will be read and cleared last
*/
for (tm = 0, is_read = 0; tm < SPI_TIMEOUT; ++tm) {
u32 status;
This says timeout but doesn't seem to actually check get_timer(). Also is it possible to separate the code that waits for completion from the code below?
status = readl(®s->status);
/* We can exit when we've had both RX and TX activity */
if (is_read && (status & SLINK_STAT_TXF_EMPTY))
break;
if ((status & (SLINK_STAT_BSY | SLINK_STAT_RDY)) !=
SLINK_STAT_RDY)
tm++;
else if (!(status & SLINK_STAT_RXF_EMPTY)) {
tmpdin = readl(®s->rx_fifo);
is_read = 1;
/* swap bytes read in */
if (din != NULL) {
for (i = bytes - 1; i >= 0; --i) {
din[i] = tmpdin & 0xff;
tmpdin >>= 8;
}
din += bytes;
}
}
}
if (tm >= SPI_TIMEOUT)
ret = tm;
/* clear ACK RDY, etc. bits */
writel(readl(®s->status), ®s->status);
}
if (flags & SPI_XFER_END)
spi_cs_deactivate(slave);
debug("%s: transfer ended. Value=%08x, status = %08x\n",
__func__, tmpdin, readl(®s->status));
if (ret) {
printf("%s: timeout during SPI transfer, tm %d\n",
__func__, ret);
return -1;
}
return 0;
+} diff --git a/include/fdtdec.h b/include/fdtdec.h index 1504336..14aa308 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -71,6 +71,7 @@ enum fdt_compat_id { COMPAT_NVIDIA_TEGRA20_PWM, /* Tegra 2 PWM controller */ COMPAT_NVIDIA_TEGRA20_DC, /* Tegra 2 Display controller */ COMPAT_NVIDIA_TEGRA20_SFLASH, /* Tegra 2 SPI flash controller */
COMPAT_NVIDIA_TEGRA20_SLINK, /* Tegra 2 SPI SLINK controller */ COMPAT_COUNT,
}; diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 6779278..4fef428 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -46,6 +46,7 @@ static const char * const compat_names[COMPAT_COUNT] = { COMPAT(NVIDIA_TEGRA20_PWM, "nvidia,tegra20-pwm"), COMPAT(NVIDIA_TEGRA20_DC, "nvidia,tegra20-dc"), COMPAT(NVIDIA_TEGRA20_SFLASH, "nvidia,tegra20-sflash"),
COMPAT(NVIDIA_TEGRA20_SLINK, "nvidia,tegra20-slink"),
};
const char *fdtdec_get_compatible(enum fdt_compat_id id)
1.7.10.4
Regards, Simon

On 01/12/2013 09:56 AM, Simon Glass wrote:
Hi,
On Sat, Jan 12, 2013 at 1:07 AM, Allen Martin amartin@nvidia.com wrote:
Add driver for tegra SPI "SLINK" style driver. This controller is similar to the tegra20 SPI "SFLASH" controller. The difference is that the SLINK controller is a genernal purpose SPI controller and the SFLASH controller is special purpose and can only talk to FLASH devices. In addition there are potentially many instances of an SLINK controller on tegra and only a single instance of SFLASH. Tegra20 is currently ths only version of tegra that instantiates an SFLASH controller.
This driver supports basic PIO mode of operation and is configurable (CONFIG_OF_CONTROL) to be driven off devicetree bindings. Up to 4 devices per controller may be attached, although typically only a single chip select line is exposed from tegra per controller so in reality this is usually limited to 1.
To enable this driver, use CONFIG_TEGRA_SLINK
diff --git a/drivers/spi/tegra_slink.c b/drivers/spi/tegra_slink.c
+#ifdef CONFIG_OF_CONTROL
You probably don't need this ifdef
If we did assume CONFIG_OF_CONTROL was on, then we could get rid of the previous patch; all the device addresses would come from device tree, so there would be no need to add them to any header file:-)
+void spi_init(void) +{
int node = 0, i;
struct tegra_spi_ctrl *ctrl;
blank line here
for (i = 0; i < CONFIG_TEGRA_SLINK_CTRLS; i++) {
ctrl = &spi_ctrls[i];
+#ifdef CONFIG_OF_CONTROL
node = fdtdec_next_compatible(gd->fdt_blob, node,
COMPAT_NVIDIA_TEGRA20_SLINK);
if (!node)
break;
I think you should be using fdtdec_find_aliases_for_id() so that aliases work.
I strongly believe we shouldn't be using aliases for enumeration, which is what fdtdec_find_aliases_for_id() does, IIRC. Instead, we should enumerate all the devices in the correct fashion, and then apply aliases as a separate step if they exists. Hence, I believe it's not correct to use fdtdec_find_aliases_for_id() anywhere.

On Mon, Jan 14, 2013 at 10:49:53AM -0800, Stephen Warren wrote:
On 01/12/2013 09:56 AM, Simon Glass wrote:
Hi,
On Sat, Jan 12, 2013 at 1:07 AM, Allen Martin amartin@nvidia.com wrote:
Add driver for tegra SPI "SLINK" style driver. This controller is similar to the tegra20 SPI "SFLASH" controller. The difference is that the SLINK controller is a genernal purpose SPI controller and the SFLASH controller is special purpose and can only talk to FLASH devices. In addition there are potentially many instances of an SLINK controller on tegra and only a single instance of SFLASH. Tegra20 is currently ths only version of tegra that instantiates an SFLASH controller.
This driver supports basic PIO mode of operation and is configurable (CONFIG_OF_CONTROL) to be driven off devicetree bindings. Up to 4 devices per controller may be attached, although typically only a single chip select line is exposed from tegra per controller so in reality this is usually limited to 1.
To enable this driver, use CONFIG_TEGRA_SLINK
diff --git a/drivers/spi/tegra_slink.c b/drivers/spi/tegra_slink.c
+#ifdef CONFIG_OF_CONTROL
You probably don't need this ifdef
If we did assume CONFIG_OF_CONTROL was on, then we could get rid of the previous patch; all the device addresses would come from device tree, so there would be no need to add them to any header file:-)
I took Simon's comment to mean it's safe to include fdtdec.h even if the fdt code is ifdef'ed out.
+void spi_init(void) +{
int node = 0, i;
struct tegra_spi_ctrl *ctrl;
blank line here
for (i = 0; i < CONFIG_TEGRA_SLINK_CTRLS; i++) {
ctrl = &spi_ctrls[i];
+#ifdef CONFIG_OF_CONTROL
node = fdtdec_next_compatible(gd->fdt_blob, node,
COMPAT_NVIDIA_TEGRA20_SLINK);
if (!node)
break;
I think you should be using fdtdec_find_aliases_for_id() so that aliases work.
I strongly believe we shouldn't be using aliases for enumeration, which is what fdtdec_find_aliases_for_id() does, IIRC. Instead, we should enumerate all the devices in the correct fashion, and then apply aliases as a separate step if they exists. Hence, I believe it's not correct to use fdtdec_find_aliases_for_id() anywhere.
I'm a bit confused about the usage of fdt aliases in u-boot. My understanding of aliases is that they are intended to give drivers hints about device naming. Since u-boot doesn't really name devices, what are aliases supposed to do?
-Allen

On 01/14/2013 09:33 PM, Allen Martin wrote:
On Mon, Jan 14, 2013 at 10:49:53AM -0800, Stephen Warren wrote:
On 01/12/2013 09:56 AM, Simon Glass wrote:
Hi,
On Sat, Jan 12, 2013 at 1:07 AM, Allen Martin amartin@nvidia.com wrote:
Add driver for tegra SPI "SLINK" style driver. This controller is similar to the tegra20 SPI "SFLASH" controller. The difference is that the SLINK controller is a genernal purpose SPI controller and the SFLASH controller is special purpose and can only talk to FLASH devices. In addition there are potentially many instances of an SLINK controller on tegra and only a single instance of SFLASH. Tegra20 is currently ths only version of tegra that instantiates an SFLASH controller.
This driver supports basic PIO mode of operation and is configurable (CONFIG_OF_CONTROL) to be driven off devicetree bindings. Up to 4 devices per controller may be attached, although typically only a single chip select line is exposed from tegra per controller so in reality this is usually limited to 1.
To enable this driver, use CONFIG_TEGRA_SLINK
+void spi_init(void) +{
int node = 0, i;
struct tegra_spi_ctrl *ctrl;
blank line here
for (i = 0; i < CONFIG_TEGRA_SLINK_CTRLS; i++) {
ctrl = &spi_ctrls[i];
+#ifdef CONFIG_OF_CONTROL
node = fdtdec_next_compatible(gd->fdt_blob, node,
COMPAT_NVIDIA_TEGRA20_SLINK);
if (!node)
break;
I think you should be using fdtdec_find_aliases_for_id() so that aliases work.
I strongly believe we shouldn't be using aliases for enumeration, which is what fdtdec_find_aliases_for_id() does, IIRC. Instead, we should enumerate all the devices in the correct fashion, and then apply aliases as a separate step if they exists. Hence, I believe it's not correct to use fdtdec_find_aliases_for_id() anywhere.
I'm a bit confused about the usage of fdt aliases in u-boot. My understanding of aliases is that they are intended to give drivers hints about device naming. Since u-boot doesn't really name devices, what are aliases supposed to do?
Most U-Boot command use IDs to identify devices/interfaces, e.g. in "ext2load mmc 0:1", the "0" means MMC instance #0. The instance number is parsed out from the end of the alias name.

Hi Stephen,
On Mon, Jan 14, 2013 at 10:49 AM, Stephen Warren swarren@wwwdotorg.org wrote:
On 01/12/2013 09:56 AM, Simon Glass wrote:
Hi,
On Sat, Jan 12, 2013 at 1:07 AM, Allen Martin amartin@nvidia.com wrote:
Add driver for tegra SPI "SLINK" style driver. This controller is similar to the tegra20 SPI "SFLASH" controller. The difference is that the SLINK controller is a genernal purpose SPI controller and the SFLASH controller is special purpose and can only talk to FLASH devices. In addition there are potentially many instances of an SLINK controller on tegra and only a single instance of SFLASH. Tegra20 is currently ths only version of tegra that instantiates an SFLASH controller.
This driver supports basic PIO mode of operation and is configurable (CONFIG_OF_CONTROL) to be driven off devicetree bindings. Up to 4 devices per controller may be attached, although typically only a single chip select line is exposed from tegra per controller so in reality this is usually limited to 1.
To enable this driver, use CONFIG_TEGRA_SLINK
diff --git a/drivers/spi/tegra_slink.c b/drivers/spi/tegra_slink.c
+#ifdef CONFIG_OF_CONTROL
You probably don't need this ifdef
If we did assume CONFIG_OF_CONTROL was on, then we could get rid of the previous patch; all the device addresses would come from device tree, so there would be no need to add them to any header file:-)
As Allen said I just mean we shouldn't need to put #ifdefs around #include <fdtdec.h>
+void spi_init(void) +{
int node = 0, i;
struct tegra_spi_ctrl *ctrl;
blank line here
for (i = 0; i < CONFIG_TEGRA_SLINK_CTRLS; i++) {
ctrl = &spi_ctrls[i];
+#ifdef CONFIG_OF_CONTROL
node = fdtdec_next_compatible(gd->fdt_blob, node,
COMPAT_NVIDIA_TEGRA20_SLINK);
if (!node)
break;
I think you should be using fdtdec_find_aliases_for_id() so that aliases work.
I strongly believe we shouldn't be using aliases for enumeration, which is what fdtdec_find_aliases_for_id() does, IIRC. Instead, we should enumerate all the devices in the correct fashion, and then apply aliases as a separate step if they exists. Hence, I believe it's not correct to use fdtdec_find_aliases_for_id() anywhere.
We might be saying the same thing, but I can't tell. We had quite a long discussion about this when the function was written and I thought it was then considered correct.
The function does not ignore nodes without an alias. It simply returns a list of nodes that your driver should init, in the order in which U-Boot expects to find them. So I think it is safe to call, and in fact should be called in any driver that has more than one device and wants to provide the ability to select device ordering. Please can you take another look at the function and see what you think?
We should not enumerate devices that are not supposed to be used, so checking fdtdec_get_is_enabled() might be good too.
Regards, Simon

On Sat, Jan 12, 2013 at 08:56:23AM -0800, Simon Glass wrote:
Hi,
On Sat, Jan 12, 2013 at 1:07 AM, Allen Martin amartin@nvidia.com wrote:
Add driver for tegra SPI "SLINK" style driver. This controller is similar to the tegra20 SPI "SFLASH" controller. The difference is that the SLINK controller is a genernal purpose SPI controller and the SFLASH controller is special purpose and can only talk to FLASH devices. In addition there are potentially many instances of an SLINK controller on tegra and only a single instance of SFLASH. Tegra20 is currently ths only version of tegra that instantiates an SFLASH controller.
This driver supports basic PIO mode of operation and is configurable (CONFIG_OF_CONTROL) to be driven off devicetree bindings. Up to 4 devices per controller may be attached, although typically only a single chip select line is exposed from tegra per controller so in reality this is usually limited to 1.
To enable this driver, use CONFIG_TEGRA_SLINK
A few comments - note I am on holiday next week so please don't wait for my response on the next version.
... +#include <spi.h> +#ifdef CONFIG_OF_CONTROL
You probably don't need this ifdef
ok
spi = malloc(sizeof(struct tegra_spi_slave));
Please also look at my SPI series where I added an allocate function for this.
http://patchwork.ozlabs.org/patch/208226/ http://patchwork.ozlabs.org/patch/208229/
Nice, thanks. I propose I should wait for that to land in u-boot/master and trick back down to u-boot-arm and u-boot-tegra, and then add it in a separate patch. That way I don't have to add a cross repo dependency.
+{
int node = 0, i;
struct tegra_spi_ctrl *ctrl;
blank line here
ok
for (i = 0; i < CONFIG_TEGRA_SLINK_CTRLS; i++) {
ctrl = &spi_ctrls[i];
+#ifdef CONFIG_OF_CONTROL
node = fdtdec_next_compatible(gd->fdt_blob, node,
COMPAT_NVIDIA_TEGRA20_SLINK);
if (!node)
break;
I think you should be using fdtdec_find_aliases_for_id() so that aliases work.
I'll reply in Stephen's follow-up on this.
(slave->cs << SLINK_CMD2_SS_EN_SHIFT);
writel(reg, ®s->command2);
Could use clrsetbits_le32() if you like
Ok
bytes = (num_bytes > 4) ? 4 : num_bytes;
if (dout != NULL) {
for (i = 0; i < bytes; ++i)
tmpdout = (tmpdout << 8) | dout[i];
dout += bytes here...
}
num_bytes -= bytes;
if (dout)
dout += bytes;
instead of here?
ok
clrsetbits_le32(®s->command, SLINK_CMD_BIT_LENGTH_MASK,
bytes * 8 - 1);
writel(tmpdout, ®s->tx_fifo);
setbits_le32(®s->command, SLINK_CMD_GO);
/*
* Wait for SPI transmit FIFO to empty, or to time out.
* The RX FIFO status will be read and cleared last
*/
for (tm = 0, is_read = 0; tm < SPI_TIMEOUT; ++tm) {
u32 status;
This says timeout but doesn't seem to actually check get_timer(). Also is it possible to separate the code that waits for completion from the code below?
You're right about get_timer(), I'll fix that.
I pulled this loop directly from the tegra20 tegra_spi driver, so I'm not the original author, but I believe the reason it's written this way is so there's a single timeout loop around the wait for STAT_BSY to drop, RXF_EMPTY to drop, and TXF_EMPTY to go high. It *should* be ok to move the TXF_EMPTY wait to a separate wait loop, but I'm a little hesitant to touch the code since it's beeen well tested in the tegra20 driver, and this part of the driver is identical.
status = readl(®s->status);
/* We can exit when we've had both RX and TX activity */
if (is_read && (status & SLINK_STAT_TXF_EMPTY))
break;
if ((status & (SLINK_STAT_BSY | SLINK_STAT_RDY)) !=
SLINK_STAT_RDY)
tm++;
else if (!(status & SLINK_STAT_RXF_EMPTY)) {
tmpdin = readl(®s->rx_fifo);
is_read = 1;
/* swap bytes read in */
if (din != NULL) {
for (i = bytes - 1; i >= 0; --i) {
din[i] = tmpdin & 0xff;
tmpdin >>= 8;
}
din += bytes;
}
}
}
if (tm >= SPI_TIMEOUT)
ret = tm;
/* clear ACK RDY, etc. bits */
writel(readl(®s->status), ®s->status);
}
if (flags & SPI_XFER_END)
spi_cs_deactivate(slave);
debug("%s: transfer ended. Value=%08x, status = %08x\n",
__func__, tmpdin, readl(®s->status));
if (ret) {
printf("%s: timeout during SPI transfer, tm %d\n",
__func__, ret);
return -1;
}
return 0;
+} diff --git a/include/fdtdec.h b/include/fdtdec.h index 1504336..14aa308 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -71,6 +71,7 @@ enum fdt_compat_id { COMPAT_NVIDIA_TEGRA20_PWM, /* Tegra 2 PWM controller */ COMPAT_NVIDIA_TEGRA20_DC, /* Tegra 2 Display controller */ COMPAT_NVIDIA_TEGRA20_SFLASH, /* Tegra 2 SPI flash controller */
COMPAT_NVIDIA_TEGRA20_SLINK, /* Tegra 2 SPI SLINK controller */ COMPAT_COUNT,
}; diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 6779278..4fef428 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -46,6 +46,7 @@ static const char * const compat_names[COMPAT_COUNT] = { COMPAT(NVIDIA_TEGRA20_PWM, "nvidia,tegra20-pwm"), COMPAT(NVIDIA_TEGRA20_DC, "nvidia,tegra20-dc"), COMPAT(NVIDIA_TEGRA20_SFLASH, "nvidia,tegra20-sflash"),
COMPAT(NVIDIA_TEGRA20_SLINK, "nvidia,tegra20-slink"),
};
const char *fdtdec_get_compatible(enum fdt_compat_id id)
1.7.10.4
Regards, Simon
-Allen

Hi Allen,
On Mon, Jan 14, 2013 at 8:27 PM, Allen Martin amartin@nvidia.com wrote:
On Sat, Jan 12, 2013 at 08:56:23AM -0800, Simon Glass wrote:
Hi,
On Sat, Jan 12, 2013 at 1:07 AM, Allen Martin amartin@nvidia.com wrote:
Add driver for tegra SPI "SLINK" style driver. This controller is similar to the tegra20 SPI "SFLASH" controller. The difference is that the SLINK controller is a genernal purpose SPI controller and the SFLASH controller is special purpose and can only talk to FLASH devices. In addition there are potentially many instances of an SLINK controller on tegra and only a single instance of SFLASH. Tegra20 is currently ths only version of tegra that instantiates an SFLASH controller.
This driver supports basic PIO mode of operation and is configurable (CONFIG_OF_CONTROL) to be driven off devicetree bindings. Up to 4 devices per controller may be attached, although typically only a single chip select line is exposed from tegra per controller so in reality this is usually limited to 1.
To enable this driver, use CONFIG_TEGRA_SLINK
A few comments - note I am on holiday next week so please don't wait for my response on the next version.
... +#include <spi.h> +#ifdef CONFIG_OF_CONTROL
You probably don't need this ifdef
ok
spi = malloc(sizeof(struct tegra_spi_slave));
Please also look at my SPI series where I added an allocate function for this.
http://patchwork.ozlabs.org/patch/208226/ http://patchwork.ozlabs.org/patch/208229/
Nice, thanks. I propose I should wait for that to land in u-boot/master and trick back down to u-boot-arm and u-boot-tegra, and then add it in a separate patch. That way I don't have to add a cross repo dependency.
Yes, sounds good.
+{
int node = 0, i;
struct tegra_spi_ctrl *ctrl;
blank line here
ok
for (i = 0; i < CONFIG_TEGRA_SLINK_CTRLS; i++) {
ctrl = &spi_ctrls[i];
+#ifdef CONFIG_OF_CONTROL
node = fdtdec_next_compatible(gd->fdt_blob, node,
COMPAT_NVIDIA_TEGRA20_SLINK);
if (!node)
break;
I think you should be using fdtdec_find_aliases_for_id() so that aliases work.
I'll reply in Stephen's follow-up on this.
(slave->cs << SLINK_CMD2_SS_EN_SHIFT);
writel(reg, ®s->command2);
Could use clrsetbits_le32() if you like
Ok
bytes = (num_bytes > 4) ? 4 : num_bytes;
if (dout != NULL) {
for (i = 0; i < bytes; ++i)
tmpdout = (tmpdout << 8) | dout[i];
dout += bytes here...
}
num_bytes -= bytes;
if (dout)
dout += bytes;
instead of here?
ok
clrsetbits_le32(®s->command, SLINK_CMD_BIT_LENGTH_MASK,
bytes * 8 - 1);
writel(tmpdout, ®s->tx_fifo);
setbits_le32(®s->command, SLINK_CMD_GO);
/*
* Wait for SPI transmit FIFO to empty, or to time out.
* The RX FIFO status will be read and cleared last
*/
for (tm = 0, is_read = 0; tm < SPI_TIMEOUT; ++tm) {
u32 status;
This says timeout but doesn't seem to actually check get_timer(). Also is it possible to separate the code that waits for completion from the code below?
You're right about get_timer(), I'll fix that.
I pulled this loop directly from the tegra20 tegra_spi driver, so I'm not the original author, but I believe the reason it's written this way is so there's a single timeout loop around the wait for STAT_BSY to drop, RXF_EMPTY to drop, and TXF_EMPTY to go high. It *should* be ok to move the TXF_EMPTY wait to a separate wait loop, but I'm a little hesitant to touch the code since it's beeen well tested in the tegra20 driver, and this part of the driver is identical.
OK, well it's up to you - just a suggestion and what you have works.
status = readl(®s->status);
/* We can exit when we've had both RX and TX activity */
if (is_read && (status & SLINK_STAT_TXF_EMPTY))
break;
if ((status & (SLINK_STAT_BSY | SLINK_STAT_RDY)) !=
SLINK_STAT_RDY)
tm++;
else if (!(status & SLINK_STAT_RXF_EMPTY)) {
tmpdin = readl(®s->rx_fifo);
is_read = 1;
/* swap bytes read in */
if (din != NULL) {
for (i = bytes - 1; i >= 0; --i) {
din[i] = tmpdin & 0xff;
tmpdin >>= 8;
}
din += bytes;
}
}
}
if (tm >= SPI_TIMEOUT)
ret = tm;
/* clear ACK RDY, etc. bits */
writel(readl(®s->status), ®s->status);
}
if (flags & SPI_XFER_END)
spi_cs_deactivate(slave);
debug("%s: transfer ended. Value=%08x, status = %08x\n",
__func__, tmpdin, readl(®s->status));
if (ret) {
printf("%s: timeout during SPI transfer, tm %d\n",
__func__, ret);
return -1;
}
return 0;
+} diff --git a/include/fdtdec.h b/include/fdtdec.h index 1504336..14aa308 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -71,6 +71,7 @@ enum fdt_compat_id { COMPAT_NVIDIA_TEGRA20_PWM, /* Tegra 2 PWM controller */ COMPAT_NVIDIA_TEGRA20_DC, /* Tegra 2 Display controller */ COMPAT_NVIDIA_TEGRA20_SFLASH, /* Tegra 2 SPI flash controller */
COMPAT_NVIDIA_TEGRA20_SLINK, /* Tegra 2 SPI SLINK controller */ COMPAT_COUNT,
}; diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 6779278..4fef428 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -46,6 +46,7 @@ static const char * const compat_names[COMPAT_COUNT] = { COMPAT(NVIDIA_TEGRA20_PWM, "nvidia,tegra20-pwm"), COMPAT(NVIDIA_TEGRA20_DC, "nvidia,tegra20-dc"), COMPAT(NVIDIA_TEGRA20_SFLASH, "nvidia,tegra20-sflash"),
COMPAT(NVIDIA_TEGRA20_SLINK, "nvidia,tegra20-slink"),
};
const char *fdtdec_get_compatible(enum fdt_compat_id id)
1.7.10.4
Regards, Simon
-Allen
nvpublic

Turn on SPI in cardhu config file
Signed-off-by: Allen Martin amartin@nvidia.com --- include/configs/cardhu.h | 11 +++++++++++ 1 file changed, 11 insertions(+)
diff --git a/include/configs/cardhu.h b/include/configs/cardhu.h index aa725ba..1616b39 100644 --- a/include/configs/cardhu.h +++ b/include/configs/cardhu.h @@ -49,6 +49,17 @@
#define CONFIG_ENV_IS_NOWHERE
+/* SPI */ +#define CONFIG_TEGRA_SLINK +#define CONFIG_TEGRA_SLINK_CTRLS 6 +#define CONFIG_SPI_FLASH +#define CONFIG_SPI_FLASH_WINBOND +#define CONFIG_SF_DEFAULT_MODE SPI_MODE_0 +#define CONFIG_SF_DEFAULT_SPEED 24000000 +#define CONFIG_CMD_SPI +#define CONFIG_CMD_SF +#define CONFIG_SPI_FLASH_SIZE (4 << 20) + #include "tegra-common-post.h"
#endif /* __CONFIG_H */

On Sat, Jan 12, 2013 at 1:07 AM, Allen Martin amartin@nvidia.com wrote:
Turn on SPI in cardhu config file
Signed-off-by: Allen Martin amartin@nvidia.com
Acked-by: Simon Glass sjg@chromium.org
include/configs/cardhu.h | 11 +++++++++++ 1 file changed, 11 insertions(+)
diff --git a/include/configs/cardhu.h b/include/configs/cardhu.h index aa725ba..1616b39 100644 --- a/include/configs/cardhu.h +++ b/include/configs/cardhu.h @@ -49,6 +49,17 @@
#define CONFIG_ENV_IS_NOWHERE
+/* SPI */ +#define CONFIG_TEGRA_SLINK +#define CONFIG_TEGRA_SLINK_CTRLS 6 +#define CONFIG_SPI_FLASH +#define CONFIG_SPI_FLASH_WINBOND +#define CONFIG_SF_DEFAULT_MODE SPI_MODE_0 +#define CONFIG_SF_DEFAULT_SPEED 24000000 +#define CONFIG_CMD_SPI +#define CONFIG_CMD_SF +#define CONFIG_SPI_FLASH_SIZE (4 << 20)
#include "tegra-common-post.h"
#endif /* __CONFIG_H */
1.7.10.4

On 01/12/2013 02:07 AM, Allen Martin wrote:
This series updates the tegra20 SPI driver to add fdt support and adds a new tegra30 SPI driver.
Aside from any comments I or anyone has made, Reviewed-by: Stephen Warren swarren@nvidia.com
participants (3)
-
Allen Martin
-
Simon Glass
-
Stephen Warren