From 0c6700abfa3cc90e08d625a934ba0e06e147227e Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Thu, 13 Oct 2011 02:14:55 -0700 Subject: ARM: tegra: emc: device tree bindings Device tree bindings for the EMC tables on tegra. Signed-off-by: Olof Johansson Acked-by: Grant Likely diff --git a/Documentation/devicetree/bindings/arm/tegra/emc.txt b/Documentation/devicetree/bindings/arm/tegra/emc.txt new file mode 100644 index 0000000..09335f8 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/tegra/emc.txt @@ -0,0 +1,100 @@ +Embedded Memory Controller + +Properties: +- name : Should be emc +- #address-cells : Should be 1 +- #size-cells : Should be 0 +- compatible : Should contain "nvidia,tegra20-emc". +- reg : Offset and length of the register set for the device +- nvidia,use-ram-code : If present, the sub-nodes will be addressed + and chosen using the ramcode board selector. If omitted, only one + set of tables can be present and said tables will be used + irrespective of ram-code configuration. + +Child device nodes describe the memory settings for different configurations and clock rates. + +Example: + + emc@7000f400 { + #address-cells = < 1 >; + #size-cells = < 0 >; + compatible = "nvidia,tegra20-emc"; + reg = <0x7000f4000 0x200>; + } + + +Embedded Memory Controller ram-code table + +If the emc node has the nvidia,use-ram-code property present, then the +next level of nodes below the emc table are used to specify which settings +apply for which ram-code settings. + +If the emc node lacks the nvidia,use-ram-code property, this level is omitted +and the tables are stored directly under the emc node (see below). + +Properties: + +- name : Should be emc-tables +- nvidia,ram-code : the binary representation of the ram-code board strappings + for which this node (and children) are valid. + + + +Embedded Memory Controller configuration table + +This is a table containing the EMC register settings for the various +operating speeds of the memory controller. They are always located as +subnodes of the emc controller node. + +There are two ways of specifying which tables to use: + +* The simplest is if there is just one set of tables in the device tree, + and they will always be used (based on which frequency is used). + This is the preferred method, especially when firmware can fill in + this information based on the specific system information and just + pass it on to the kernel. + +* The slightly more complex one is when more than one memory configuration + might exist on the system. The Tegra20 platform handles this during + early boot by selecting one out of possible 4 memory settings based + on a 2-pin "ram code" bootstrap setting on the board. The values of + these strappings can be read through a register in the SoC, and thus + used to select which tables to use. + +Properties: +- name : Should be emc-table +- compatible : Should contain "nvidia,tegra20-emc-table". +- reg : either an opaque enumerator to tell different tables apart, or + the valid frequency for which the table should be used (in kHz). +- clock-frequency : the clock frequency for the EMC at which this + table should be used (in kHz). +- nvidia,emc-registers : a 46 word array of EMC registers to be programmed + for operation at the 'clock-frequency' setting. + The order and contents of the registers are: + RC, RFC, RAS, RP, R2W, W2R, R2P, W2P, RD_RCD, WR_RCD, RRD, REXT, + WDV, QUSE, QRST, QSAFE, RDV, REFRESH, BURST_REFRESH_NUM, PDEX2WR, + PDEX2RD, PCHG2PDEN, ACT2PDEN, AR2PDEN, RW2PDEN, TXSR, TCKE, TFAW, + TRPAB, TCLKSTABLE, TCLKSTOP, TREFBW, QUSE_EXTRA, FBIO_CFG6, ODT_WRITE, + ODT_READ, FBIO_CFG5, CFG_DIG_DLL, DLL_XFORM_DQS, DLL_XFORM_QUSE, + ZCAL_REF_CNT, ZCAL_WAIT_CNT, AUTO_CAL_INTERVAL, CFG_CLKTRIM_0, + CFG_CLKTRIM_1, CFG_CLKTRIM_2 + + emc-table@166000 { + reg = <166000>; + compatible = "nvidia,tegra20-emc-table"; + clock-frequency = < 166000 >; + nvidia,emc-registers = < 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 >; + }; + + emc-table@333000 { + reg = <333000>; + compatible = "nvidia,tegra20-emc-table"; + clock-frequency = < 333000 >; + nvidia,emc-registers = < 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 >; + }; diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi index 3da7afd..c162241 100644 --- a/arch/arm/boot/dts/tegra20.dtsi +++ b/arch/arm/boot/dts/tegra20.dtsi @@ -120,6 +120,13 @@ interrupts = < 0 91 0x04 >; }; + emc@7000f400 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "nvidia,tegra20-emc"; + reg = <0x7000f400 0x200>; + }; + sdhci@c8000000 { compatible = "nvidia,tegra20-sdhci"; reg = <0xc8000000 0x200>; -- cgit v0.10.2 From d8017a975cfc7f9e24a0424faf96369eb4d6c7bc Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Tue, 18 Oct 2011 11:06:06 -0700 Subject: ARM: tegra: seaboard: add EMC table to device tree Timings for the T25 version of seaboard, only one memory manufacturer and timing table (two speeds). Signed-off-by: Olof Johansson diff --git a/arch/arm/boot/dts/tegra-seaboard.dts b/arch/arm/boot/dts/tegra-seaboard.dts index b55a02e..7ccf67e 100644 --- a/arch/arm/boot/dts/tegra-seaboard.dts +++ b/arch/arm/boot/dts/tegra-seaboard.dts @@ -93,4 +93,42 @@ gpio-key,wakeup; }; }; + + emc@7000f400 { + emc-table@190000 { + reg = < 190000 >; + compatible = "nvidia,tegra20-emc-table"; + clock-frequency = < 190000 >; + nvidia,emc-registers = < 0x0000000c 0x00000026 + 0x00000009 0x00000003 0x00000004 0x00000004 + 0x00000002 0x0000000c 0x00000003 0x00000003 + 0x00000002 0x00000001 0x00000004 0x00000005 + 0x00000004 0x00000009 0x0000000d 0x0000059f + 0x00000000 0x00000003 0x00000003 0x00000003 + 0x00000003 0x00000001 0x0000000b 0x000000c8 + 0x00000003 0x00000007 0x00000004 0x0000000f + 0x00000002 0x00000000 0x00000000 0x00000002 + 0x00000000 0x00000000 0x00000083 0xa06204ae + 0x007dc010 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 >; + }; + + emc-table@380000 { + reg = < 380000 >; + compatible = "nvidia,tegra20-emc-table"; + clock-frequency = < 380000 >; + nvidia,emc-registers = < 0x00000017 0x0000004b + 0x00000012 0x00000006 0x00000004 0x00000005 + 0x00000003 0x0000000c 0x00000006 0x00000006 + 0x00000003 0x00000001 0x00000004 0x00000005 + 0x00000004 0x00000009 0x0000000d 0x00000b5f + 0x00000000 0x00000003 0x00000003 0x00000006 + 0x00000006 0x00000001 0x00000011 0x000000c8 + 0x00000003 0x0000000e 0x00000007 0x0000000f + 0x00000002 0x00000000 0x00000000 0x00000002 + 0x00000000 0x00000000 0x00000083 0xe044048b + 0x007d8010 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 >; + }; + }; }; -- cgit v0.10.2 From a38b84fce9d1f3b1f054409b6363d98bf019e263 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Wed, 4 Jan 2012 08:39:34 +0000 Subject: dt: tegra gpio: Flesh out binding documentation Document the required reg and interrupts properties. Add a complete example. Signed-off-by: Stephen Warren Acked-by: Grant Likely Signed-off-by: Olof Johansson diff --git a/Documentation/devicetree/bindings/gpio/gpio_nvidia.txt b/Documentation/devicetree/bindings/gpio/gpio_nvidia.txt index eb4b530..50b363c 100644 --- a/Documentation/devicetree/bindings/gpio/gpio_nvidia.txt +++ b/Documentation/devicetree/bindings/gpio/gpio_nvidia.txt @@ -2,7 +2,25 @@ NVIDIA Tegra 2 GPIO controller Required properties: - compatible : "nvidia,tegra20-gpio" +- reg : Physical base address and length of the controller's registers. +- interrupts : The interrupt outputs from the controller. - #gpio-cells : Should be two. The first cell is the pin number and the second cell is used to specify optional parameters: - bit 0 specifies polarity (0 for normal, 1 for inverted) - gpio-controller : Marks the device node as a GPIO controller. + +Example: + +gpio: gpio@6000d000 { + compatible = "nvidia,tegra20-gpio"; + reg = < 0x6000d000 0x1000 >; + interrupts = < 0 32 0x04 + 0 33 0x04 + 0 34 0x04 + 0 35 0x04 + 0 55 0x04 + 0 87 0x04 + 0 89 0x04 >; + #gpio-cells = <2>; + gpio-controller; +}; -- cgit v0.10.2 From 636e50a0e0f3d9a62d2097a42d751cf5825124b0 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Wed, 4 Jan 2012 08:39:35 +0000 Subject: ARM: dt: tegra30.dtsi: Reformat gpio's interrupts property The new content matches tegra20.dtsi, and is < 80 columns. Signed-off-by: Stephen Warren Acked-by: Grant Likely Signed-off-by: Olof Johansson diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi index ee7db98..e5d1406 100644 --- a/arch/arm/boot/dts/tegra30.dtsi +++ b/arch/arm/boot/dts/tegra30.dtsi @@ -55,7 +55,13 @@ gpio: gpio@6000d000 { compatible = "nvidia,tegra30-gpio", "nvidia,tegra20-gpio"; reg = < 0x6000d000 0x1000 >; - interrupts = < 0 32 0x04 0 33 0x04 0 34 0x04 0 35 0x04 0 55 0x04 0 87 0x04 0 89 0x04 >; + interrupts = < 0 32 0x04 + 0 33 0x04 + 0 34 0x04 + 0 35 0x04 + 0 55 0x04 + 0 87 0x04 + 0 89 0x04 >; #gpio-cells = <2>; gpio-controller; }; -- cgit v0.10.2 From f8196b01b9bf1a9539e1cfceece03b60f5ae2de1 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Wed, 4 Jan 2012 08:39:36 +0000 Subject: ARM: dt: tegra30.dtsi: Add extra GPIO interrupt The Tegra30 GPIO controller has one more bank than Tegra20, and hence has one more interrupt. Signed-off-by: Stephen Warren Acked-by: Grant Likely Signed-off-by: Olof Johansson diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi index e5d1406..2b3f6cd 100644 --- a/arch/arm/boot/dts/tegra30.dtsi +++ b/arch/arm/boot/dts/tegra30.dtsi @@ -61,7 +61,8 @@ 0 35 0x04 0 55 0x04 0 87 0x04 - 0 89 0x04 >; + 0 89 0x04 + 0 125 0x04 >; #gpio-cells = <2>; gpio-controller; }; -- cgit v0.10.2 From 8051b75ab32f72ebd7bf232e554d631f56f1ee42 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Wed, 11 Jan 2012 16:09:54 -0700 Subject: ARM: dt: tegra: Add Tegra APB DMA device tree binding Document binding, and add the node to tegra*.dtsi. The driver isn't actually instantiated from this node yet, but the I2S binding will rely on being able to refer to the APB DMA node using a phandle. Signed-off-by: Stephen Warren Signed-off-by: Olof Johansson diff --git a/Documentation/devicetree/bindings/dma/tegra20-apbdma.txt b/Documentation/devicetree/bindings/dma/tegra20-apbdma.txt new file mode 100644 index 0000000..90fa7da --- /dev/null +++ b/Documentation/devicetree/bindings/dma/tegra20-apbdma.txt @@ -0,0 +1,30 @@ +* NVIDIA Tegra APB DMA controller + +Required properties: +- compatible: Should be "nvidia,-apbdma" +- reg: Should contain DMA registers location and length. This shuld include + all of the per-channel registers. +- interrupts: Should contain all of the per-channel DMA interrupts. + +Examples: + +apbdma: dma@6000a000 { + compatible = "nvidia,tegra20-apbdma"; + reg = <0x6000a000 0x1200>; + interrupts = < 0 136 0x04 + 0 137 0x04 + 0 138 0x04 + 0 139 0x04 + 0 140 0x04 + 0 141 0x04 + 0 142 0x04 + 0 143 0x04 + 0 144 0x04 + 0 145 0x04 + 0 146 0x04 + 0 147 0x04 + 0 148 0x04 + 0 149 0x04 + 0 150 0x04 + 0 151 0x04 >; +}; diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi index c162241..603dc21 100644 --- a/arch/arm/boot/dts/tegra20.dtsi +++ b/arch/arm/boot/dts/tegra20.dtsi @@ -12,6 +12,27 @@ < 0x50040100 0x0100 >; }; + apbdma: dma@6000a000 { + 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 >; + }; + i2c@7000c000 { #address-cells = <1>; #size-cells = <0>; diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi index 2b3f6cd..8a7e230 100644 --- a/arch/arm/boot/dts/tegra30.dtsi +++ b/arch/arm/boot/dts/tegra30.dtsi @@ -12,6 +12,43 @@ < 0x50040100 0x0100 >; }; + apbdma: dma@6000a000 { + 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>; -- cgit v0.10.2 From 5c8ee3120ee005d8204a536ce2494660032f5f6f Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Wed, 11 Jan 2012 16:09:55 -0700 Subject: ARM: dt: tegra: Modify I2S nodes to match binding Adjust the dma-channel property name to match the binding implemented by the driver. The binding was implemented and documented in a separate change to the ASoC tree. Signed-off-by: Stephen Warren Signed-off-by: Olof Johansson diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi index 603dc21..b1f46e1 100644 --- a/arch/arm/boot/dts/tegra20.dtsi +++ b/arch/arm/boot/dts/tegra20.dtsi @@ -69,14 +69,14 @@ compatible = "nvidia,tegra20-i2s"; reg = <0x70002800 0x200>; interrupts = < 0 13 0x04 >; - dma-channel = < 2 >; + nvidia,dma-request-selector = < &apbdma 2 >; }; i2s@70002a00 { compatible = "nvidia,tegra20-i2s"; reg = <0x70002a00 0x200>; interrupts = < 0 3 0x04 >; - dma-channel = < 1 >; + nvidia,dma-request-selector = < &apbdma 1 >; }; das@70000c00 { -- cgit v0.10.2 From c404af0a16ea55bd8d0634e4cc23e0396799d836 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Wed, 11 Jan 2012 16:09:56 -0700 Subject: ARM: dt: tegra: Add labels for I2S controllers This will allow the sound node to refer to the I2S controllers by name when creating phandles. Signed-off-by: Stephen Warren Signed-off-by: Olof Johansson diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi index b1f46e1..8712449 100644 --- a/arch/arm/boot/dts/tegra20.dtsi +++ b/arch/arm/boot/dts/tegra20.dtsi @@ -65,14 +65,14 @@ interrupts = < 0 53 0x04 >; }; - i2s@70002800 { + tegra_i2s1: i2s@70002800 { compatible = "nvidia,tegra20-i2s"; reg = <0x70002800 0x200>; interrupts = < 0 13 0x04 >; nvidia,dma-request-selector = < &apbdma 2 >; }; - i2s@70002a00 { + tegra_i2s2: i2s@70002a00 { compatible = "nvidia,tegra20-i2s"; reg = <0x70002a00 0x200>; interrupts = < 0 3 0x04 >; -- cgit v0.10.2 From 797acf705bf440c736b71cc958f46a174ec87d10 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Wed, 11 Jan 2012 16:09:57 -0700 Subject: ARM: dt: tegra: Enable audio on WM8903 boards, disable others Add complete bindings to instantiate and configure the codec and top-level audio complex on all currently supported boards using the Tegra+WM8903 audio driver. On those boards, disable the I2S2 controller since it isn't used. On boards not using the WM8903 codec, disable all the audio devices; they can be re-enabled once the relevant codec and ASoC machine drivers have been ported to device-tree. Signed-off-by: Stephen Warren Signed-off-by: Olof Johansson diff --git a/arch/arm/boot/dts/tegra-harmony.dts b/arch/arm/boot/dts/tegra-harmony.dts index 80afa1b..9a52615 100644 --- a/arch/arm/boot/dts/tegra-harmony.dts +++ b/arch/arm/boot/dts/tegra-harmony.dts @@ -13,16 +13,18 @@ i2c@7000c000 { clock-frequency = <400000>; - codec: wm8903@1a { + wm8903: wm8903@1a { compatible = "wlf,wm8903"; reg = <0x1a>; - interrupts = < 347 >; + interrupt-parent = <&gpio>; + interrupts = < 187 0x04 >; gpio-controller; #gpio-cells = <2>; - /* 0x8000 = Not configured */ - gpio-cfg = < 0x8000 0x8000 0 0x8000 0x8000 >; + micdet-cfg = <0>; + micdet-delay = <100>; + gpio-cfg = < 0xffffffff 0xffffffff 0 0xffffffff 0xffffffff >; }; }; @@ -38,13 +40,32 @@ clock-frequency = <400000>; }; - sound { - compatible = "nvidia,harmony-sound", "nvidia,tegra-wm8903"; + i2s@70002a00 { + status = "disable"; + }; - spkr-en-gpios = <&codec 2 0>; - hp-det-gpios = <&gpio 178 0>; - int-mic-en-gpios = <&gpio 184 0>; - ext-mic-en-gpios = <&gpio 185 0>; + sound { + compatible = "nvidia,tegra-audio-wm8903-harmony", + "nvidia,tegra-audio-wm8903"; + nvidia,model = "NVIDIA Tegra Harmony"; + + nvidia,audio-routing = + "Headphone Jack", "HPOUTR", + "Headphone Jack", "HPOUTL", + "Int Spk", "ROP", + "Int Spk", "RON", + "Int Spk", "LOP", + "Int Spk", "LON", + "Mic Jack", "MICBIAS", + "IN1L", "Mic Jack"; + + nvidia,i2s-controller = <&tegra_i2s1>; + nvidia,audio-codec = <&wm8903>; + + nvidia,spkr-en-gpios = <&wm8903 2 0>; + nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */ + nvidia,int-mic-en-gpios = <&gpio 184 0>; /*gpio PX0 */ + nvidia,ext-mic-en-gpios = <&gpio 185 0>; /* gpio PX1 */ }; serial@70006000 { diff --git a/arch/arm/boot/dts/tegra-paz00.dts b/arch/arm/boot/dts/tegra-paz00.dts index 1a1d702..4d1bcdc 100644 --- a/arch/arm/boot/dts/tegra-paz00.dts +++ b/arch/arm/boot/dts/tegra-paz00.dts @@ -37,6 +37,18 @@ clock-frequency = <400000>; }; + i2s@70002800 { + status = "disable"; + }; + + i2s@70002a00 { + status = "disable"; + }; + + das@70000c00 { + status = "disable"; + }; + serial@70006000 { clock-frequency = <216000000>; }; diff --git a/arch/arm/boot/dts/tegra-seaboard.dts b/arch/arm/boot/dts/tegra-seaboard.dts index 7ccf67e..876d5c9 100644 --- a/arch/arm/boot/dts/tegra-seaboard.dts +++ b/arch/arm/boot/dts/tegra-seaboard.dts @@ -13,6 +13,20 @@ i2c@7000c000 { clock-frequency = <400000>; + + wm8903: wm8903@1a { + compatible = "wlf,wm8903"; + reg = <0x1a>; + interrupt-parent = <&gpio>; + interrupts = < 187 0x04 >; + + gpio-controller; + #gpio-cells = <2>; + + micdet-cfg = <0>; + micdet-delay = <100>; + gpio-cfg = < 0xffffffff 0xffffffff 0 0xffffffff 0xffffffff >; + }; }; i2c@7000c400 { @@ -32,6 +46,32 @@ }; }; + i2s@70002a00 { + status = "disable"; + }; + + sound { + compatible = "nvidia,tegra-audio-wm8903-seaboard", + "nvidia,tegra-audio-wm8903"; + nvidia,model = "NVIDIA Tegra Seaboard"; + + nvidia,audio-routing = + "Headphone Jack", "HPOUTR", + "Headphone Jack", "HPOUTL", + "Int Spk", "ROP", + "Int Spk", "RON", + "Int Spk", "LOP", + "Int Spk", "LON", + "Mic Jack", "MICBIAS", + "IN1R", "Mic Jack"; + + nvidia,i2s-controller = <&tegra_i2s1>; + nvidia,audio-codec = <&wm8903>; + + nvidia,spkr-en-gpios = <&wm8903 2 0>; + nvidia,hp-det-gpios = <&gpio 185 0>; /* gpio PX1 */ + }; + serial@70006000 { status = "disable"; }; diff --git a/arch/arm/boot/dts/tegra-trimslice.dts b/arch/arm/boot/dts/tegra-trimslice.dts index 3b3ee7d..2524768 100644 --- a/arch/arm/boot/dts/tegra-trimslice.dts +++ b/arch/arm/boot/dts/tegra-trimslice.dts @@ -26,6 +26,18 @@ status = "disable"; }; + i2s@70002800 { + status = "disable"; + }; + + i2s@70002a00 { + status = "disable"; + }; + + das@70000c00 { + status = "disable"; + }; + serial@70006000 { clock-frequency = < 216000000 >; }; diff --git a/arch/arm/boot/dts/tegra-ventana.dts b/arch/arm/boot/dts/tegra-ventana.dts index c7d3b87..2dcff87 100644 --- a/arch/arm/boot/dts/tegra-ventana.dts +++ b/arch/arm/boot/dts/tegra-ventana.dts @@ -12,6 +12,20 @@ i2c@7000c000 { clock-frequency = <400000>; + + wm8903: wm8903@1a { + compatible = "wlf,wm8903"; + reg = <0x1a>; + interrupt-parent = <&gpio>; + interrupts = < 187 0x04 >; + + gpio-controller; + #gpio-cells = <2>; + + micdet-cfg = <0>; + micdet-delay = <100>; + gpio-cfg = < 0xffffffff 0xffffffff 0 0xffffffff 0xffffffff >; + }; }; i2c@7000c400 { @@ -26,6 +40,34 @@ clock-frequency = <400000>; }; + i2s@70002a00 { + status = "disable"; + }; + + sound { + compatible = "nvidia,tegra-audio-wm8903-ventana", + "nvidia,tegra-audio-wm8903"; + nvidia,model = "NVIDIA Tegra Ventana"; + + nvidia,audio-routing = + "Headphone Jack", "HPOUTR", + "Headphone Jack", "HPOUTL", + "Int Spk", "ROP", + "Int Spk", "RON", + "Int Spk", "LOP", + "Int Spk", "LON", + "Mic Jack", "MICBIAS", + "IN1L", "Mic Jack"; + + nvidia,i2s-controller = <&tegra_i2s1>; + nvidia,audio-codec = <&wm8903>; + + nvidia,spkr-en-gpios = <&wm8903 2 0>; + nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */ + nvidia,int-mic-en-gpios = <&gpio 184 0>; /*gpio PX0 */ + nvidia,ext-mic-en-gpios = <&gpio 185 0>; /* gpio PX1 */ + }; + serial@70006000 { status = "disable"; }; -- cgit v0.10.2 From d17adfdb17fb9f182d1fc5189d4772cd03f187c3 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Wed, 25 Jan 2012 14:43:27 -0700 Subject: ARM: dt: Add binding for Tegra PMC The Tegra PMC (Power Management Controller) interfaces with an external PMU (Power Management Unit), and controls wake-up from sleep modes. This initial binding is the bare minimum required to control the PMC's inversion of the PMU's interrupt signal. Signed-off-by: Stephen Warren Signed-off-by: Olof Johansson diff --git a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt new file mode 100644 index 0000000..b5846e2 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt @@ -0,0 +1,19 @@ +NVIDIA Tegra Power Management Controller (PMC) + +Properties: +- name : Should be pmc +- compatible : Should contain "nvidia,tegra-pmc". +- reg : Offset and length of the register set for the device +- nvidia,invert-interrupt : If present, inverts the PMU interrupt signal. + The PMU is an external Power Management Unit, whose interrupt output + signal is fed into the PMC. This signal is optionally inverted, and then + fed into the ARM GIC. The PMC is not involved in the detection or + handling of this interrupt signal, merely its inversion. + +Example: + +pmc@7000f400 { + compatible = "nvidia,tegra20-pmc"; + reg = <0x7000e400 0x400>; + nvidia,invert-interrupt; +}; diff --git a/arch/arm/boot/dts/tegra-harmony.dts b/arch/arm/boot/dts/tegra-harmony.dts index 9a52615..6e8447d 100644 --- a/arch/arm/boot/dts/tegra-harmony.dts +++ b/arch/arm/boot/dts/tegra-harmony.dts @@ -10,6 +10,10 @@ reg = < 0x00000000 0x40000000 >; }; + pmc@7000f400 { + nvidia,invert-interrupt; + }; + i2c@7000c000 { clock-frequency = <400000>; diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi index 8712449..3195ad5 100644 --- a/arch/arm/boot/dts/tegra20.dtsi +++ b/arch/arm/boot/dts/tegra20.dtsi @@ -4,6 +4,11 @@ compatible = "nvidia,tegra20"; interrupt-parent = <&intc>; + pmc@7000f400 { + compatible = "nvidia,tegra20-pmc"; + reg = <0x7000e400 0x400>; + }; + intc: interrupt-controller@50041000 { compatible = "arm,cortex-a9-gic"; interrupt-controller; diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi index 8a7e230..fd25e8e 100644 --- a/arch/arm/boot/dts/tegra30.dtsi +++ b/arch/arm/boot/dts/tegra30.dtsi @@ -4,6 +4,11 @@ compatible = "nvidia,tegra30"; interrupt-parent = <&intc>; + pmc@7000f400 { + compatible = "nvidia,tegra20-pmc", "nvidia,tegra30-pmc"; + reg = <0x7000e400 0x400>; + }; + intc: interrupt-controller@50041000 { compatible = "arm,cortex-a9-gic"; interrupt-controller; -- cgit v0.10.2 From 613e9657df44eed37e6559a1f56371e7246529b4 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Thu, 2 Feb 2012 22:13:35 +0200 Subject: ARM: dt: tegra: Enable device tree audio codec on PAZ00 board. This patch adds initial device tree support of ALC5632 sound codec and machine driver for PAZ00 board. The implementation is based on the WM8903 codec. Signed-off-by: Marc Dietrich Signed-off-by: Leon Romanovsky Signed-off-by: Olof Johansson diff --git a/arch/arm/boot/dts/tegra-paz00.dts b/arch/arm/boot/dts/tegra-paz00.dts index 4d1bcdc..e6809b7 100644 --- a/arch/arm/boot/dts/tegra-paz00.dts +++ b/arch/arm/boot/dts/tegra-paz00.dts @@ -12,6 +12,13 @@ i2c@7000c000 { clock-frequency = <400000>; + + alc5632: alc5632@1e { + compatible = "realtek,alc5632"; + reg = <0x1e>; + gpio-controller; + #gpio-cells = <2>; + }; }; i2c@7000c400 { @@ -37,16 +44,26 @@ clock-frequency = <400000>; }; - i2s@70002800 { - status = "disable"; - }; - i2s@70002a00 { status = "disable"; }; - das@70000c00 { - status = "disable"; + sound { + compatible = "nvidia,tegra-audio-alc5632-paz00", + "nvidia,tegra-audio-alc5632"; + + nvidia,model = "Compal PAZ00"; + + nvidia,audio-routing = + "Int Spk", "SPKOUT", + "Int Spk", "SPKOUTN", + "Headset Mic", "MICBIAS1", + "MIC1", "Headset Mic", + "Headset Stereophone", "HPR", + "Headset Stereophone", "HPL"; + + nvidia,audio-codec = <&alc5632>; + nvidia,i2s-controller = <&tegra_i2s1>; }; serial@70006000 { -- cgit v0.10.2 From 07d4563e58dea39923456939e7d4138fb608b98b Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Thu, 2 Feb 2012 22:13:36 +0200 Subject: ARM: dt: tegra: Enable headset autodetection on PAZ00 board. This patch is adding device tree support of headset autodetection on PAZ00 board. Signed-off-by: Leon Romanovsky Signed-off-by: Olof Johansson diff --git a/arch/arm/boot/dts/tegra-paz00.dts b/arch/arm/boot/dts/tegra-paz00.dts index e6809b7..fa9dd9e 100644 --- a/arch/arm/boot/dts/tegra-paz00.dts +++ b/arch/arm/boot/dts/tegra-paz00.dts @@ -64,6 +64,7 @@ nvidia,audio-codec = <&alc5632>; nvidia,i2s-controller = <&tegra_i2s1>; + nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */ }; serial@70006000 { -- cgit v0.10.2 From 13ae3d5bdf737d6078a562154ff4fef0ba5d0de1 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Thu, 22 Dec 2011 14:17:40 +0000 Subject: ARM: tegra: Don't WARN_ON() for too early dma channel allocations Since we'll do opportunistic allocations before the dma subsystem is enabled we want just silent failures and retries instead. Signed-off-by: Olof Johansson diff --git a/arch/arm/mach-tegra/dma.c b/arch/arm/mach-tegra/dma.c index c0cf967..98b33c8 100644 --- a/arch/arm/mach-tegra/dma.c +++ b/arch/arm/mach-tegra/dma.c @@ -357,7 +357,7 @@ struct tegra_dma_channel *tegra_dma_allocate_channel(int mode) int channel; struct tegra_dma_channel *ch = NULL; - if (WARN_ON(!tegra_dma_initialized)) + if (!tegra_dma_initialized) return NULL; mutex_lock(&tegra_dma_lock); -- cgit v0.10.2 From e2f91578b35347341482f6af9e4fcf3174531efd Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 12 Oct 2011 23:52:29 -0700 Subject: ARM: tegra: use APB DMA for accessing APB devices Tegra2 hangs if APB registers are accessed from the cpu during an apb dma operation. The workaround is to use apb dma to read/write the registers instead. There is a dependency loop between fuses, clocks, and APBDMA. If dma is enabled, fuse reads must go through APBDMA to avoid corruption due to a hw bug. APBDMA requires a clock to be enabled. Clocks must read a fuse to determine allowable cpu frequencies. Separate out the fuse DMA initialization, and allow the fuse read and write functions to be called without using DMA before the DMA initialization has been completed. Access to the fuses before APBDMA is initialized won't hit the hardware bug because nothing else can be using DMA. Original fuse registar access code from Varun Wadekar , improved by Colin Cross and later moved to separate driver by Jon Mayo . Major refactoring/cleanup by Olof Johansson . Changes since v1: * fix 'return false' on error condition * dequeue dma ops in case of timeout From: Jon Mayo . Signed-off-by: Jon Mayo . Signed-off-by: Olof Johansson Acked-by: Stephen Warren diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile index e120ff5..23d15fb 100644 --- a/arch/arm/mach-tegra/Makefile +++ b/arch/arm/mach-tegra/Makefile @@ -15,7 +15,7 @@ obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += pinmux-tegra30-tables.o obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += board-dt-tegra30.o obj-$(CONFIG_SMP) += platsmp.o localtimer.o headsmp.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o -obj-$(CONFIG_TEGRA_SYSTEM_DMA) += dma.o +obj-$(CONFIG_TEGRA_SYSTEM_DMA) += dma.o apbio.o obj-$(CONFIG_CPU_FREQ) += cpu-tegra.o obj-$(CONFIG_TEGRA_PCI) += pcie.o obj-$(CONFIG_USB_SUPPORT) += usb_phy.o diff --git a/arch/arm/mach-tegra/apbio.c b/arch/arm/mach-tegra/apbio.c new file mode 100644 index 0000000..e75451e --- /dev/null +++ b/arch/arm/mach-tegra/apbio.c @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2010 NVIDIA Corporation. + * Copyright (C) 2010 Google, Inc. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "apbio.h" + +static DEFINE_MUTEX(tegra_apb_dma_lock); + +static struct tegra_dma_channel *tegra_apb_dma; +static u32 *tegra_apb_bb; +static dma_addr_t tegra_apb_bb_phys; +static DECLARE_COMPLETION(tegra_apb_wait); + +bool tegra_apb_init(void) +{ + struct tegra_dma_channel *ch; + + mutex_lock(&tegra_apb_dma_lock); + + /* Check to see if we raced to setup */ + if (tegra_apb_dma) + goto out; + + ch = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT | + TEGRA_DMA_SHARED); + + if (!ch) + goto out_fail; + + tegra_apb_bb = dma_alloc_coherent(NULL, sizeof(u32), + &tegra_apb_bb_phys, GFP_KERNEL); + if (!tegra_apb_bb) { + pr_err("%s: can not allocate bounce buffer\n", __func__); + tegra_dma_free_channel(ch); + goto out_fail; + } + + tegra_apb_dma = ch; +out: + mutex_unlock(&tegra_apb_dma_lock); + return true; + +out_fail: + mutex_unlock(&tegra_apb_dma_lock); + return false; +} + +static void apb_dma_complete(struct tegra_dma_req *req) +{ + complete(&tegra_apb_wait); +} + +u32 tegra_apb_readl(unsigned long offset) +{ + struct tegra_dma_req req; + int ret; + + if (!tegra_apb_dma && !tegra_apb_init()) + return readl(IO_TO_VIRT(offset)); + + mutex_lock(&tegra_apb_dma_lock); + req.complete = apb_dma_complete; + req.to_memory = 1; + req.dest_addr = tegra_apb_bb_phys; + req.dest_bus_width = 32; + req.dest_wrap = 1; + req.source_addr = offset; + req.source_bus_width = 32; + req.source_wrap = 4; + req.req_sel = TEGRA_DMA_REQ_SEL_CNTR; + req.size = 4; + + INIT_COMPLETION(tegra_apb_wait); + + tegra_dma_enqueue_req(tegra_apb_dma, &req); + + ret = wait_for_completion_timeout(&tegra_apb_wait, + msecs_to_jiffies(50)); + + if (WARN(ret == 0, "apb read dma timed out")) { + tegra_dma_dequeue_req(tegra_apb_dma, &req); + *(u32 *)tegra_apb_bb = 0; + } + + mutex_unlock(&tegra_apb_dma_lock); + return *((u32 *)tegra_apb_bb); +} + +void tegra_apb_writel(u32 value, unsigned long offset) +{ + struct tegra_dma_req req; + int ret; + + if (!tegra_apb_dma && !tegra_apb_init()) { + writel(value, IO_TO_VIRT(offset)); + return; + } + + mutex_lock(&tegra_apb_dma_lock); + *((u32 *)tegra_apb_bb) = value; + req.complete = apb_dma_complete; + req.to_memory = 0; + req.dest_addr = offset; + req.dest_wrap = 4; + req.dest_bus_width = 32; + req.source_addr = tegra_apb_bb_phys; + req.source_bus_width = 32; + req.source_wrap = 1; + req.req_sel = TEGRA_DMA_REQ_SEL_CNTR; + req.size = 4; + + INIT_COMPLETION(tegra_apb_wait); + + tegra_dma_enqueue_req(tegra_apb_dma, &req); + + ret = wait_for_completion_timeout(&tegra_apb_wait, + msecs_to_jiffies(50)); + + if (WARN(ret == 0, "apb write dma timed out")) + tegra_dma_dequeue_req(tegra_apb_dma, &req); + + mutex_unlock(&tegra_apb_dma_lock); +} diff --git a/arch/arm/mach-tegra/apbio.h b/arch/arm/mach-tegra/apbio.h new file mode 100644 index 0000000..8b49e8c --- /dev/null +++ b/arch/arm/mach-tegra/apbio.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2010 NVIDIA Corporation. + * Copyright (C) 2010 Google, Inc. + * + * 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. + * + */ + +#ifndef __MACH_TEGRA_APBIO_H +#define __MACH_TEGRA_APBIO_H + +#ifdef CONFIG_TEGRA_SYSTEM_DMA + +u32 tegra_apb_readl(unsigned long offset); +void tegra_apb_writel(u32 value, unsigned long offset); + +#else +#include +#include + +static inline u32 tegra_apb_readl(unsigned long offset) +{ + return readl(IO_TO_VIRT(offset)); +} + +static inline void tegra_apb_writel(u32 value, unsigned long offset) +{ + writel(value, IO_TO_VIRT(offset)); +} +#endif + +#endif diff --git a/arch/arm/mach-tegra/dma.c b/arch/arm/mach-tegra/dma.c index 98b33c8..122e467 100644 --- a/arch/arm/mach-tegra/dma.c +++ b/arch/arm/mach-tegra/dma.c @@ -33,6 +33,8 @@ #include #include +#include "apbio.h" + #define APB_DMA_GEN 0x000 #define GEN_ENABLE (1<<31) -- cgit v0.10.2 From d262f49d10554ae2908e6d1d0e93fa736c4c0d06 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Thu, 13 Oct 2011 00:14:08 -0700 Subject: ARM: tegra: fuse: use apbio dma for register access Use the apbio dma functions for accessing the fuse registers. Signed-off-by: Olof Johansson diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c index 1fa26d9..daf3f57 100644 --- a/arch/arm/mach-tegra/fuse.c +++ b/arch/arm/mach-tegra/fuse.c @@ -23,20 +23,16 @@ #include #include "fuse.h" +#include "apbio.h" #define FUSE_UID_LOW 0x108 #define FUSE_UID_HIGH 0x10c #define FUSE_SKU_INFO 0x110 #define FUSE_SPARE_BIT 0x200 -static inline u32 fuse_readl(unsigned long offset) +static inline u32 tegra_fuse_readl(unsigned long offset) { - return readl(IO_TO_VIRT(TEGRA_FUSE_BASE + offset)); -} - -static inline void fuse_writel(u32 value, unsigned long offset) -{ - writel(value, IO_TO_VIRT(TEGRA_FUSE_BASE + offset)); + return tegra_apb_readl(TEGRA_FUSE_BASE + offset); } void tegra_init_fuse(void) @@ -54,15 +50,15 @@ unsigned long long tegra_chip_uid(void) { unsigned long long lo, hi; - lo = fuse_readl(FUSE_UID_LOW); - hi = fuse_readl(FUSE_UID_HIGH); + lo = tegra_fuse_readl(FUSE_UID_LOW); + hi = tegra_fuse_readl(FUSE_UID_HIGH); return (hi << 32ull) | lo; } int tegra_sku_id(void) { int sku_id; - u32 reg = fuse_readl(FUSE_SKU_INFO); + u32 reg = tegra_fuse_readl(FUSE_SKU_INFO); sku_id = reg & 0xFF; return sku_id; } @@ -70,7 +66,7 @@ int tegra_sku_id(void) int tegra_cpu_process_id(void) { int cpu_process_id; - u32 reg = fuse_readl(FUSE_SPARE_BIT); + u32 reg = tegra_fuse_readl(FUSE_SPARE_BIT); cpu_process_id = (reg >> 6) & 3; return cpu_process_id; } @@ -78,7 +74,7 @@ int tegra_cpu_process_id(void) int tegra_core_process_id(void) { int core_process_id; - u32 reg = fuse_readl(FUSE_SPARE_BIT); + u32 reg = tegra_fuse_readl(FUSE_SPARE_BIT); core_process_id = (reg >> 12) & 3; return core_process_id; } -- cgit v0.10.2 From 9a1086da345cea8b2d1f01b47e5bbd81d640d642 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Thu, 13 Oct 2011 00:31:20 -0700 Subject: ARM: tegra: fuse: add functions to access chip revision Add function to get chip revision, and print it out at boot time. Restructure the fuse access to just use cached variables instead of always reading the fuses, and export those variables directly instead of using accessor functions. Add a SKU ID table of currently known values. Based on code originally by Colin Cross . Changes since v1: * Add A01 minor rev support * Don't decode for A03p on anything but T2x Signed-off-by: Olof Johansson Acked-by: Stephen Warren diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c index daf3f57..b1895c5 100644 --- a/arch/arm/mach-tegra/fuse.c +++ b/arch/arm/mach-tegra/fuse.c @@ -30,20 +30,75 @@ #define FUSE_SKU_INFO 0x110 #define FUSE_SPARE_BIT 0x200 +int tegra_sku_id; +int tegra_cpu_process_id; +int tegra_core_process_id; +enum tegra_revision tegra_revision; + +static const char *tegra_revision_name[TEGRA_REVISION_MAX] = { + [TEGRA_REVISION_UNKNOWN] = "unknown", + [TEGRA_REVISION_A01] = "A01", + [TEGRA_REVISION_A02] = "A02", + [TEGRA_REVISION_A03] = "A03", + [TEGRA_REVISION_A03p] = "A03 prime", + [TEGRA_REVISION_A04] = "A04", +}; + static inline u32 tegra_fuse_readl(unsigned long offset) { return tegra_apb_readl(TEGRA_FUSE_BASE + offset); } +static inline bool get_spare_fuse(int bit) +{ + return tegra_fuse_readl(FUSE_SPARE_BIT + bit * 4); +} + +static enum tegra_revision tegra_get_revision(void) +{ + void __iomem *chip_id = IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804; + u32 id = readl(chip_id); + u32 minor_rev = (id >> 16) & 0xf; + u32 chipid = (id >> 8) & 0xff; + + switch (minor_rev) { + case 1: + return TEGRA_REVISION_A01; + case 2: + return TEGRA_REVISION_A02; + case 3: + if (chipid == 0x20 && (get_spare_fuse(18) || get_spare_fuse(19))) + return TEGRA_REVISION_A03p; + else + return TEGRA_REVISION_A03; + case 4: + return TEGRA_REVISION_A04; + default: + return TEGRA_REVISION_UNKNOWN; + } +} + void tegra_init_fuse(void) { u32 reg = readl(IO_TO_VIRT(TEGRA_CLK_RESET_BASE + 0x48)); reg |= 1 << 28; writel(reg, IO_TO_VIRT(TEGRA_CLK_RESET_BASE + 0x48)); - pr_info("Tegra SKU: %d CPU Process: %d Core Process: %d\n", - tegra_sku_id(), tegra_cpu_process_id(), - tegra_core_process_id()); + reg = tegra_fuse_readl(FUSE_SKU_INFO); + tegra_sku_id = reg & 0xFF; + + reg = tegra_fuse_readl(FUSE_SPARE_BIT); + tegra_cpu_process_id = (reg >> 6) & 3; + + reg = tegra_fuse_readl(FUSE_SPARE_BIT); + tegra_core_process_id = (reg >> 12) & 3; + + tegra_revision = tegra_get_revision(); + + pr_info("Tegra Revision: %s SKU: %d CPU Process: %d Core Process: %d\n", + tegra_revision_name[tegra_get_revision()], + tegra_sku_id, tegra_cpu_process_id, + tegra_core_process_id); } unsigned long long tegra_chip_uid(void) @@ -54,27 +109,3 @@ unsigned long long tegra_chip_uid(void) hi = tegra_fuse_readl(FUSE_UID_HIGH); return (hi << 32ull) | lo; } - -int tegra_sku_id(void) -{ - int sku_id; - u32 reg = tegra_fuse_readl(FUSE_SKU_INFO); - sku_id = reg & 0xFF; - return sku_id; -} - -int tegra_cpu_process_id(void) -{ - int cpu_process_id; - u32 reg = tegra_fuse_readl(FUSE_SPARE_BIT); - cpu_process_id = (reg >> 6) & 3; - return cpu_process_id; -} - -int tegra_core_process_id(void) -{ - int core_process_id; - u32 reg = tegra_fuse_readl(FUSE_SPARE_BIT); - core_process_id = (reg >> 12) & 3; - return core_process_id; -} diff --git a/arch/arm/mach-tegra/fuse.h b/arch/arm/mach-tegra/fuse.h index 584b2e2..7576aaf 100644 --- a/arch/arm/mach-tegra/fuse.h +++ b/arch/arm/mach-tegra/fuse.h @@ -1,6 +1,4 @@ /* - * arch/arm/mach-tegra/fuse.c - * * Copyright (C) 2010 Google, Inc. * * Author: @@ -17,8 +15,32 @@ * */ +#ifndef __MACH_TEGRA_FUSE_H +#define __MACH_TEGRA_FUSE_H + +enum tegra_revision { + TEGRA_REVISION_UNKNOWN = 0, + TEGRA_REVISION_A01, + TEGRA_REVISION_A02, + TEGRA_REVISION_A03, + TEGRA_REVISION_A03p, + TEGRA_REVISION_A04, + TEGRA_REVISION_MAX, +}; + +#define SKU_ID_T20 8 +#define SKU_ID_T25SE 20 +#define SKU_ID_AP25 23 +#define SKU_ID_T25 24 +#define SKU_ID_AP25E 27 +#define SKU_ID_T25E 28 + +extern int tegra_sku_id; +extern int tegra_cpu_process_id; +extern int tegra_core_process_id; +extern enum tegra_revision tegra_revision; + unsigned long long tegra_chip_uid(void); -int tegra_sku_id(void); -int tegra_cpu_process_id(void); -int tegra_core_process_id(void); void tegra_init_fuse(void); + +#endif diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c index ff9e6b6..74d314f 100644 --- a/arch/arm/mach-tegra/tegra2_clocks.c +++ b/arch/arm/mach-tegra/tegra2_clocks.c @@ -720,7 +720,7 @@ static void tegra2_pllx_clk_init(struct clk *c) { tegra2_pll_clk_init(c); - if (tegra_sku_id() == 7) + if (tegra_sku_id == 7) c->max_rate = 750000000; } -- cgit v0.10.2 From dee47183301983139fd0ed784d0defe0ba08f8f6 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Mon, 17 Oct 2011 16:39:24 -0700 Subject: ARM: tegra: fuse: add bct strapping reading This is used by the memory setup code to pick the right memory timing table, if needed. Signed-off-by: Olof Johansson diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c index b1895c5..17fdd40 100644 --- a/arch/arm/mach-tegra/fuse.c +++ b/arch/arm/mach-tegra/fuse.c @@ -35,6 +35,17 @@ int tegra_cpu_process_id; int tegra_core_process_id; enum tegra_revision tegra_revision; +/* The BCT to use at boot is specified by board straps that can be read + * through a APB misc register and decoded. 2 bits, i.e. 4 possible BCTs. + */ +int tegra_bct_strapping; + +#define STRAP_OPT 0x008 +#define GMI_AD0 (1 << 4) +#define GMI_AD1 (1 << 5) +#define RAM_ID_MASK (GMI_AD0 | GMI_AD1) +#define RAM_CODE_SHIFT 4 + static const char *tegra_revision_name[TEGRA_REVISION_MAX] = { [TEGRA_REVISION_UNKNOWN] = "unknown", [TEGRA_REVISION_A01] = "A01", @@ -93,6 +104,9 @@ void tegra_init_fuse(void) reg = tegra_fuse_readl(FUSE_SPARE_BIT); tegra_core_process_id = (reg >> 12) & 3; + reg = tegra_apb_readl(TEGRA_APB_MISC_BASE + STRAP_OPT); + tegra_bct_strapping = (reg & RAM_ID_MASK) >> RAM_CODE_SHIFT; + tegra_revision = tegra_get_revision(); pr_info("Tegra Revision: %s SKU: %d CPU Process: %d Core Process: %d\n", diff --git a/arch/arm/mach-tegra/fuse.h b/arch/arm/mach-tegra/fuse.h index 7576aaf..d65d2ab 100644 --- a/arch/arm/mach-tegra/fuse.h +++ b/arch/arm/mach-tegra/fuse.h @@ -40,6 +40,8 @@ extern int tegra_cpu_process_id; extern int tegra_core_process_id; extern enum tegra_revision tegra_revision; +extern int tegra_bct_strapping; + unsigned long long tegra_chip_uid(void); void tegra_init_fuse(void); -- cgit v0.10.2 From 17711dbf4788ded84470941ff63a7029f73ca654 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Sun, 16 Oct 2011 16:54:51 -0700 Subject: ARM: tegra: emc: convert tegra2_emc to a platform driver This is the first step in making it device-tree aware and get rid of the in-kernel EMC tables (of which there are none in mainline, thankfully). Changes since v3: * moved to devm_request_and_ioremap() in probe() Changes since v2: * D'oh -- missed a couple of variables that were added, never used and then later removed in a later patch. Changes since v1: * Fixed messed up indentation * Removed code that should be gone (was added here and removed later in series) Signed-off-by: Olof Johansson Acked-by: Stephen Warren diff --git a/arch/arm/mach-tegra/tegra2_emc.c b/arch/arm/mach-tegra/tegra2_emc.c index 0f7ae6e..e6229bb 100644 --- a/arch/arm/mach-tegra/tegra2_emc.c +++ b/arch/arm/mach-tegra/tegra2_emc.c @@ -16,10 +16,13 @@ */ #include +#include #include #include #include #include +#include +#include #include @@ -32,18 +35,17 @@ static bool emc_enable; #endif module_param(emc_enable, bool, 0644); -static void __iomem *emc = IO_ADDRESS(TEGRA_EMC_BASE); -static const struct tegra_emc_table *tegra_emc_table; -static int tegra_emc_table_size; +static struct platform_device *emc_pdev; +static void __iomem *emc_regbase; static inline void emc_writel(u32 val, unsigned long addr) { - writel(val, emc + addr); + writel(val, emc_regbase + addr); } static inline u32 emc_readl(unsigned long addr) { - return readl(emc + addr); + return readl(emc_regbase + addr); } static const unsigned long emc_reg_addr[TEGRA_EMC_NUM_REGS] = { @@ -98,15 +100,15 @@ static const unsigned long emc_reg_addr[TEGRA_EMC_NUM_REGS] = { /* Select the closest EMC rate that is higher than the requested rate */ long tegra_emc_round_rate(unsigned long rate) { + struct tegra_emc_pdata *pdata; int i; int best = -1; unsigned long distance = ULONG_MAX; - if (!tegra_emc_table) + if (!emc_pdev) return -EINVAL; - if (!emc_enable) - return -EINVAL; + pdata = emc_pdev->dev.platform_data; pr_debug("%s: %lu\n", __func__, rate); @@ -116,10 +118,10 @@ long tegra_emc_round_rate(unsigned long rate) */ rate = rate / 2 / 1000; - for (i = 0; i < tegra_emc_table_size; i++) { - if (tegra_emc_table[i].rate >= rate && - (tegra_emc_table[i].rate - rate) < distance) { - distance = tegra_emc_table[i].rate - rate; + for (i = 0; i < pdata->num_tables; i++) { + if (pdata->tables[i].rate >= rate && + (pdata->tables[i].rate - rate) < distance) { + distance = pdata->tables[i].rate - rate; best = i; } } @@ -127,9 +129,9 @@ long tegra_emc_round_rate(unsigned long rate) if (best < 0) return -EINVAL; - pr_debug("%s: using %lu\n", __func__, tegra_emc_table[best].rate); + pr_debug("%s: using %lu\n", __func__, pdata->tables[best].rate); - return tegra_emc_table[best].rate * 2 * 1000; + return pdata->tables[best].rate * 2 * 1000; } /* @@ -142,37 +144,81 @@ long tegra_emc_round_rate(unsigned long rate) */ int tegra_emc_set_rate(unsigned long rate) { + struct tegra_emc_pdata *pdata; int i; int j; - if (!tegra_emc_table) + if (!emc_pdev) return -EINVAL; + pdata = emc_pdev->dev.platform_data; + /* * The EMC clock rate is twice the bus rate, and the bus rate is * measured in kHz */ rate = rate / 2 / 1000; - for (i = 0; i < tegra_emc_table_size; i++) - if (tegra_emc_table[i].rate == rate) + for (i = 0; i < pdata->num_tables; i++) + if (pdata->tables[i].rate == rate) break; - if (i >= tegra_emc_table_size) + if (i >= pdata->num_tables) return -EINVAL; pr_debug("%s: setting to %lu\n", __func__, rate); for (j = 0; j < TEGRA_EMC_NUM_REGS; j++) - emc_writel(tegra_emc_table[i].regs[j], emc_reg_addr[j]); + emc_writel(pdata->tables[i].regs[j], emc_reg_addr[j]); + + emc_readl(pdata->tables[i].regs[TEGRA_EMC_NUM_REGS - 1]); + + return 0; +} + +static int __devinit tegra_emc_probe(struct platform_device *pdev) +{ + struct tegra_emc_pdata *pdata; + struct resource *res; + + if (!emc_enable) { + dev_err(&pdev->dev, "disabled per module parameter\n"); + return -ENODEV; + } + + pdata = pdev->dev.platform_data; - emc_readl(tegra_emc_table[i].regs[TEGRA_EMC_NUM_REGS - 1]); + if (!pdata) { + dev_err(&pdev->dev, "missing platform data\n"); + return -ENXIO; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "missing register base\n"); + return -ENOMEM; + } + + emc_regbase = devm_request_and_ioremap(&pdev->dev, res); + if (!emc_regbase) { + dev_err(&pdev->dev, "failed to remap registers\n"); + return -ENOMEM; + } + emc_pdev = pdev; return 0; } -void tegra_init_emc(const struct tegra_emc_table *table, int table_size) +static struct platform_driver tegra_emc_driver = { + .driver = { + .name = "tegra-emc", + .owner = THIS_MODULE, + }, + .probe = tegra_emc_probe, +}; + +static int __init tegra_emc_init(void) { - tegra_emc_table = table; - tegra_emc_table_size = table_size; + return platform_driver_register(&tegra_emc_driver); } +device_initcall(tegra_emc_init); diff --git a/arch/arm/mach-tegra/tegra2_emc.h b/arch/arm/mach-tegra/tegra2_emc.h index 19f08cb..f61409b 100644 --- a/arch/arm/mach-tegra/tegra2_emc.h +++ b/arch/arm/mach-tegra/tegra2_emc.h @@ -15,13 +15,10 @@ * */ -#define TEGRA_EMC_NUM_REGS 46 - -struct tegra_emc_table { - unsigned long rate; - u32 regs[TEGRA_EMC_NUM_REGS]; -}; +#ifndef __MACH_TEGRA_TEGRA2_EMC_H_ +#define __MACH_TEGRA_TEGRA2_EMC_H int tegra_emc_set_rate(unsigned long rate); long tegra_emc_round_rate(unsigned long rate); -void tegra_init_emc(const struct tegra_emc_table *table, int table_size); + +#endif diff --git a/include/linux/platform_data/tegra_emc.h b/include/linux/platform_data/tegra_emc.h new file mode 100644 index 0000000..df67505 --- /dev/null +++ b/include/linux/platform_data/tegra_emc.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2011 Google, Inc. + * + * Author: + * Colin Cross + * Olof Johansson + * + * 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. + * + */ + +#ifndef __TEGRA_EMC_H_ +#define __TEGRA_EMC_H_ + +#define TEGRA_EMC_NUM_REGS 46 + +struct tegra_emc_table { + unsigned long rate; + u32 regs[TEGRA_EMC_NUM_REGS]; +}; + +struct tegra_emc_pdata { + int num_tables; + struct tegra_emc_table *tables; +}; + +#endif -- cgit v0.10.2 From 941b8db1df8bfc29a88fc8e3e203289d84a3f64d Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Mon, 17 Oct 2011 16:05:22 -0700 Subject: ARM: tegra: emc: device tree support Add device tree support to the emc driver, filling in the platform data based on the DT bindings. Changes since v1: * Unmangled some messed up patch squashes, moving changes to earlier patches * Flipped an of_property_read_u32 return value test * Clarified clock settings message on case where no table is provided Signed-off-by: Olof Johansson Acked-by: Stephen Warren diff --git a/arch/arm/mach-tegra/tegra2_emc.c b/arch/arm/mach-tegra/tegra2_emc.c index e6229bb..52df6ca 100644 --- a/arch/arm/mach-tegra/tegra2_emc.c +++ b/arch/arm/mach-tegra/tegra2_emc.c @@ -21,12 +21,14 @@ #include #include #include +#include #include #include #include #include "tegra2_emc.h" +#include "fuse.h" #ifdef CONFIG_TEGRA_EMC_SCALING_ENABLE static bool emc_enable = true; @@ -176,6 +178,126 @@ int tegra_emc_set_rate(unsigned long rate) return 0; } +#ifdef CONFIG_OF +static struct device_node *tegra_emc_ramcode_devnode(struct device_node *np) +{ + struct device_node *iter; + u32 reg; + + for_each_child_of_node(np, iter) { + if (of_property_read_u32(np, "nvidia,ram-code", ®)) + continue; + if (reg == tegra_bct_strapping) + return of_node_get(iter); + } + + return NULL; +} + +static struct tegra_emc_pdata *tegra_emc_dt_parse_pdata( + struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct device_node *tnp, *iter; + struct tegra_emc_pdata *pdata; + int ret, i, num_tables; + + if (!np) + return NULL; + + if (of_find_property(np, "nvidia,use-ram-code", NULL)) { + tnp = tegra_emc_ramcode_devnode(np); + if (!tnp) + dev_warn(&pdev->dev, + "can't find emc table for ram-code 0x%02x\n", + tegra_bct_strapping); + } else + tnp = of_node_get(np); + + if (!tnp) + return NULL; + + num_tables = 0; + for_each_child_of_node(tnp, iter) + if (of_device_is_compatible(iter, "nvidia,tegra20-emc-table")) + num_tables++; + + if (!num_tables) { + pdata = NULL; + goto out; + } + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + pdata->tables = devm_kzalloc(&pdev->dev, + sizeof(*pdata->tables) * num_tables, + GFP_KERNEL); + + i = 0; + for_each_child_of_node(tnp, iter) { + u32 prop; + + ret = of_property_read_u32(iter, "clock-frequency", &prop); + if (ret) { + dev_err(&pdev->dev, "no clock-frequency in %s\n", + iter->full_name); + continue; + } + pdata->tables[i].rate = prop; + + ret = of_property_read_u32_array(iter, "nvidia,emc-registers", + pdata->tables[i].regs, + TEGRA_EMC_NUM_REGS); + if (ret) { + dev_err(&pdev->dev, + "malformed emc-registers property in %s\n", + iter->full_name); + continue; + } + + i++; + } + pdata->num_tables = i; + +out: + of_node_put(tnp); + return pdata; +} +#else +static struct tegra_emc_pdata *tegra_emc_dt_parse_pdata( + struct platform_device *pdev) +{ + return NULL; +} +#endif + +static struct tegra_emc_pdata __devinit *tegra_emc_fill_pdata(struct platform_device *pdev) +{ + struct clk *c = clk_get_sys(NULL, "emc"); + struct tegra_emc_pdata *pdata; + unsigned long khz; + int i; + + WARN_ON(pdev->dev.platform_data); + BUG_ON(IS_ERR_OR_NULL(c)); + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + pdata->tables = devm_kzalloc(&pdev->dev, sizeof(*pdata->tables), + GFP_KERNEL); + + pdata->tables[0].rate = clk_get_rate(c); + + for (i = 0; i < TEGRA_EMC_NUM_REGS; i++) + pdata->tables[0].regs[i] = emc_readl(emc_reg_addr[i]); + + pdata->num_tables = 1; + + khz = pdata->tables[0].rate / 1000; + dev_info(&pdev->dev, "no tables provided, using %ld kHz emc, " + "%ld kHz mem\n", khz, khz/2); + + return pdata; +} + static int __devinit tegra_emc_probe(struct platform_device *pdev) { struct tegra_emc_pdata *pdata; @@ -186,13 +308,6 @@ static int __devinit tegra_emc_probe(struct platform_device *pdev) return -ENODEV; } - pdata = pdev->dev.platform_data; - - if (!pdata) { - dev_err(&pdev->dev, "missing platform data\n"); - return -ENXIO; - } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, "missing register base\n"); @@ -204,15 +319,32 @@ static int __devinit tegra_emc_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failed to remap registers\n"); return -ENOMEM; } + + pdata = pdev->dev.platform_data; + + if (!pdata) + pdata = tegra_emc_dt_parse_pdata(pdev); + + if (!pdata) + pdata = tegra_emc_fill_pdata(pdev); + + pdev->dev.platform_data = pdata; + emc_pdev = pdev; return 0; } +static struct of_device_id tegra_emc_of_match[] __devinitdata = { + { .compatible = "nvidia,tegra20-emc", }, + { }, +}; + static struct platform_driver tegra_emc_driver = { .driver = { .name = "tegra-emc", .owner = THIS_MODULE, + .of_match_table = tegra_emc_of_match, }, .probe = tegra_emc_probe, }; -- cgit v0.10.2 From cb3732d0dc9df198c889a26210b6b27bc51a1c4a Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Mon, 9 Jan 2012 20:05:11 +0000 Subject: ARM: tegra: Pause DMA when reading transfer count In order to read an accurate channel transfer count from the APB DMA engine, the DMA controller must be paused first. Signed-off-by: Laxman Dewangan Acked-by: Stephen Warren Tested-by: Stephen Warren Signed-off-by: Olof Johansson diff --git a/arch/arm/mach-tegra/dma.c b/arch/arm/mach-tegra/dma.c index 122e467..998c55d 100644 --- a/arch/arm/mach-tegra/dma.c +++ b/arch/arm/mach-tegra/dma.c @@ -135,6 +135,7 @@ struct tegra_dma_channel { static bool tegra_dma_initialized; static DEFINE_MUTEX(tegra_dma_lock); +static DEFINE_SPINLOCK(enable_lock); static DECLARE_BITMAP(channel_usage, NV_DMA_MAX_CHANNELS); static struct tegra_dma_channel dma_channels[NV_DMA_MAX_CHANNELS]; @@ -200,18 +201,82 @@ static int tegra_dma_cancel(struct tegra_dma_channel *ch) return 0; } +static unsigned int get_channel_status(struct tegra_dma_channel *ch, + struct tegra_dma_req *req, bool is_stop_dma) +{ + void __iomem *addr = IO_ADDRESS(TEGRA_APB_DMA_BASE); + unsigned int status; + + if (is_stop_dma) { + /* + * STOP the DMA and get the transfer count. + * Getting the transfer count is tricky. + * - Globally disable DMA on all channels + * - Read the channel's status register to know the number + * of pending bytes to be transfered. + * - Stop the dma channel + * - Globally re-enable DMA to resume other transfers + */ + spin_lock(&enable_lock); + writel(0, addr + APB_DMA_GEN); + udelay(20); + status = readl(ch->addr + APB_DMA_CHAN_STA); + tegra_dma_stop(ch); + writel(GEN_ENABLE, addr + APB_DMA_GEN); + spin_unlock(&enable_lock); + if (status & STA_ISE_EOC) { + pr_err("Got Dma Int here clearing"); + writel(status, ch->addr + APB_DMA_CHAN_STA); + } + req->status = TEGRA_DMA_REQ_ERROR_ABORTED; + } else { + status = readl(ch->addr + APB_DMA_CHAN_STA); + } + return status; +} + +/* should be called with the channel lock held */ +static unsigned int dma_active_count(struct tegra_dma_channel *ch, + struct tegra_dma_req *req, unsigned int status) +{ + unsigned int to_transfer; + unsigned int req_transfer_count; + unsigned int bytes_transferred; + + to_transfer = ((status & STA_COUNT_MASK) >> STA_COUNT_SHIFT) + 1; + req_transfer_count = ch->req_transfer_count + 1; + bytes_transferred = req_transfer_count; + if (status & STA_BUSY) + bytes_transferred -= to_transfer; + /* + * In continuous transfer mode, DMA only tracks the count of the + * half DMA buffer. So, if the DMA already finished half the DMA + * then add the half buffer to the completed count. + */ + if (ch->mode & TEGRA_DMA_MODE_CONTINOUS) { + if (req->buffer_status == TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL) + bytes_transferred += req_transfer_count; + if (status & STA_ISE_EOC) + bytes_transferred += req_transfer_count; + } + bytes_transferred *= 4; + return bytes_transferred; +} + int tegra_dma_dequeue_req(struct tegra_dma_channel *ch, struct tegra_dma_req *_req) { - unsigned int csr; unsigned int status; struct tegra_dma_req *req = NULL; int found = 0; unsigned long irq_flags; - int to_transfer; - int req_transfer_count; + int stop = 0; spin_lock_irqsave(&ch->lock, irq_flags); + + if (list_entry(ch->list.next, struct tegra_dma_req, node) == _req) + stop = 1; + list_for_each_entry(req, &ch->list, node) { if (req == _req) { list_del(&req->node); @@ -224,47 +289,12 @@ int tegra_dma_dequeue_req(struct tegra_dma_channel *ch, return 0; } - /* STOP the DMA and get the transfer count. - * Getting the transfer count is tricky. - * - Change the source selector to invalid to stop the DMA from - * FIFO to memory. - * - Read the status register to know the number of pending - * bytes to be transferred. - * - Finally stop or program the DMA to the next buffer in the - * list. - */ - csr = readl(ch->addr + APB_DMA_CHAN_CSR); - csr &= ~CSR_REQ_SEL_MASK; - csr |= CSR_REQ_SEL_INVALID; - writel(csr, ch->addr + APB_DMA_CHAN_CSR); - - /* Get the transfer count */ - status = readl(ch->addr + APB_DMA_CHAN_STA); - to_transfer = (status & STA_COUNT_MASK) >> STA_COUNT_SHIFT; - req_transfer_count = ch->req_transfer_count; - req_transfer_count += 1; - to_transfer += 1; + if (!stop) + goto skip_stop_dma; - req->bytes_transferred = req_transfer_count; + status = get_channel_status(ch, req, true); + req->bytes_transferred = dma_active_count(ch, req, status); - if (status & STA_BUSY) - req->bytes_transferred -= to_transfer; - - /* In continuous transfer mode, DMA only tracks the count of the - * half DMA buffer. So, if the DMA already finished half the DMA - * then add the half buffer to the completed count. - * - * FIXME: There can be a race here. What if the req to - * dequue happens at the same time as the DMA just moved to - * the new buffer and SW didn't yet received the interrupt? - */ - if (ch->mode & TEGRA_DMA_MODE_CONTINOUS) - if (req->buffer_status == TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL) - req->bytes_transferred += req_transfer_count; - - req->bytes_transferred *= 4; - - tegra_dma_stop(ch); if (!list_empty(&ch->list)) { /* if the list is not empty, queue the next request */ struct tegra_dma_req *next_req; @@ -272,6 +302,8 @@ int tegra_dma_dequeue_req(struct tegra_dma_channel *ch, typeof(*next_req), node); tegra_dma_update_hw(ch, next_req); } + +skip_stop_dma: req->status = -TEGRA_DMA_REQ_ERROR_ABORTED; spin_unlock_irqrestore(&ch->lock, irq_flags); -- cgit v0.10.2 From e53b7d87cc375fbe428551651094fb676764aae3 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Tue, 3 Jan 2012 12:05:47 +0000 Subject: ARM: tegra: Support Tegra30 in decompressor UART setup On Tegra20, the UART clock runs at 216MHz, whereas on Tegra30 it runs at 408MHz. Modify arch_decomp_setup() to detect Tegra20-vs-Tegra30 at run- time, and program the correct divisor. This makes uncompressor messages work correctly on Tegra30. This also fixes early printk, assuming zImage is used and this setup code runs. v2: Use CHIPID register to differentiate between chips, rather than a GIC register. This should be more future-proof. Volatile is required to prevent the compiler transforming the 32-bit apb_misc register read into an 8-bit read of address 1 higher, since the HW only supports 32- bit accesses, and will hang on an 8-bit access. Signed-off-by: Stephen Warren Signed-off-by: Olof Johansson diff --git a/arch/arm/mach-tegra/include/mach/uncompress.h b/arch/arm/mach-tegra/include/mach/uncompress.h index 4e83237..39bd5e5a 100644 --- a/arch/arm/mach-tegra/include/mach/uncompress.h +++ b/arch/arm/mach-tegra/include/mach/uncompress.h @@ -45,15 +45,23 @@ static inline void flush(void) static inline void arch_decomp_setup(void) { + volatile u32 *apb_misc = (volatile u32 *)TEGRA_APB_MISC_BASE; + u32 chip, div; volatile u8 *uart = (volatile u8 *)TEGRA_DEBUG_UART_BASE; int shift = 2; if (uart == NULL) return; + chip = (apb_misc[0x804 / 4] >> 8) & 0xff; + if (chip == 0x20) + div = 0x0075; + else + div = 0x00dd; + uart[UART_LCR << shift] |= UART_LCR_DLAB; - uart[UART_DLL << shift] = 0x75; - uart[UART_DLM << shift] = 0x0; + uart[UART_DLL << shift] = div & 0xff; + uart[UART_DLM << shift] = div >> 8; uart[UART_LCR << shift] = 3; } -- cgit v0.10.2 From 229c7b22a24b9996e3a3eb1a2748e255e16bc323 Mon Sep 17 00:00:00 2001 From: Doug Anderson Date: Fri, 6 Jan 2012 10:43:19 +0000 Subject: ARM: tegra: Introduce define DEBUG_UART_SHIFT This removes the need for the variable "shift" in all functions in uncompress.h. Signed-off-by: Doug Anderson [swarren: Extracted from a larger patch by Doug] Signed-off-by: Stephen Warren Tested-by: Doug Anderson Acked-by: Doug Anderson Signed-off-by: Olof Johansson diff --git a/arch/arm/mach-tegra/include/mach/uncompress.h b/arch/arm/mach-tegra/include/mach/uncompress.h index 39bd5e5a..9797279 100644 --- a/arch/arm/mach-tegra/include/mach/uncompress.h +++ b/arch/arm/mach-tegra/include/mach/uncompress.h @@ -2,10 +2,12 @@ * arch/arm/mach-tegra/include/mach/uncompress.h * * Copyright (C) 2010 Google, Inc. + * Copyright (C) 2011 Google, Inc. * * Author: * Colin Cross * Erik Gilling + * Doug Anderson * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -26,17 +28,18 @@ #include +#define DEBUG_UART_SHIFT 2 + static void putc(int c) { volatile u8 *uart = (volatile u8 *)TEGRA_DEBUG_UART_BASE; - int shift = 2; if (uart == NULL) return; - while (!(uart[UART_LSR << shift] & UART_LSR_THRE)) + while (!(uart[UART_LSR << DEBUG_UART_SHIFT] & UART_LSR_THRE)) barrier(); - uart[UART_TX << shift] = c; + uart[UART_TX << DEBUG_UART_SHIFT] = c; } static inline void flush(void) @@ -48,7 +51,6 @@ static inline void arch_decomp_setup(void) volatile u32 *apb_misc = (volatile u32 *)TEGRA_APB_MISC_BASE; u32 chip, div; volatile u8 *uart = (volatile u8 *)TEGRA_DEBUG_UART_BASE; - int shift = 2; if (uart == NULL) return; @@ -59,10 +61,10 @@ static inline void arch_decomp_setup(void) else div = 0x00dd; - uart[UART_LCR << shift] |= UART_LCR_DLAB; - uart[UART_DLL << shift] = div & 0xff; - uart[UART_DLM << shift] = div >> 8; - uart[UART_LCR << shift] = 3; + uart[UART_LCR << DEBUG_UART_SHIFT] |= UART_LCR_DLAB; + uart[UART_DLL << DEBUG_UART_SHIFT] = div & 0xff; + uart[UART_DLM << DEBUG_UART_SHIFT] = div >> 8; + uart[UART_LCR << DEBUG_UART_SHIFT] = 3; } static inline void arch_decomp_wdog(void) -- cgit v0.10.2 From 31bac1375bda9787f18b2f60e0e1ca62258ea09c Mon Sep 17 00:00:00 2001 From: Doug Anderson Date: Fri, 6 Jan 2012 10:43:20 +0000 Subject: ARM: tegra: uncompress.h: Store UART address in a variable This will allow a future change to auto-detect which UART to use. Signed-off-by: Doug Anderson [swarren: Extracted from a larger patch by Doug] Signed-off-by: Stephen Warren Tested-by: Doug Anderson Acked-by: Doug Anderson Signed-off-by: Olof Johansson diff --git a/arch/arm/mach-tegra/include/mach/uncompress.h b/arch/arm/mach-tegra/include/mach/uncompress.h index 9797279..bb3fd35 100644 --- a/arch/arm/mach-tegra/include/mach/uncompress.h +++ b/arch/arm/mach-tegra/include/mach/uncompress.h @@ -30,10 +30,10 @@ #define DEBUG_UART_SHIFT 2 +volatile u8 *uart; + static void putc(int c) { - volatile u8 *uart = (volatile u8 *)TEGRA_DEBUG_UART_BASE; - if (uart == NULL) return; @@ -50,8 +50,8 @@ static inline void arch_decomp_setup(void) { volatile u32 *apb_misc = (volatile u32 *)TEGRA_APB_MISC_BASE; u32 chip, div; - volatile u8 *uart = (volatile u8 *)TEGRA_DEBUG_UART_BASE; + uart = (volatile u8 *)TEGRA_DEBUG_UART_BASE; if (uart == NULL) return; -- cgit v0.10.2 From fe2639892cb618d5c42ea4570feea8dc497d0487 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Fri, 6 Jan 2012 10:43:21 +0000 Subject: ARM: tegra: uncompress.h: Choose a UART at runtime With this change we automatically detect which UART to use for for printing during decompression. The detection involves coordination with the bootloader: it's expected that the bootloader will leave a 'D' (for [D]ebug) in the UART scratchpad register for whichever UART we should use for debugging. If we don't find any such UART, we fall back to the UART that was specified during config time: CONFIG_TEGRA_DEBUG_UART_XXX. As a side effect of this change, uncompress debug messages will work if you've specified CONFIG_TEGRA_DEBUG_UART_NONE, provided the bootloader obeys the protocol. This change is in line with what is documented in Documentation/arm/Booting. Other approaches considered: * Hardcode based on machine ID (as many other ARM boards do). OK, but nice to not have yet another place to add per-board code. Better to have bootloader parse device tree and pass us this info. * Check for TXE bit (like SA1110). Nice (and doesn't require a bootloader change), but a little less explicit. Also: if bootloader (for some reason) uses another UART, it needs to remember to turn it off before jumping to the kernel or we may print to it. NOTE: adapting this patch to check TXE too would be easy if desired. Signed-off-by: Doug Anderson [swarren: Added clock/reset condition checks] Signed-off-by: Stephen Warren Tested-by: Doug Anderson Acked-by: Doug Anderson Signed-off-by: Olof Johansson diff --git a/arch/arm/mach-tegra/include/mach/uncompress.h b/arch/arm/mach-tegra/include/mach/uncompress.h index bb3fd35..6c087b6 100644 --- a/arch/arm/mach-tegra/include/mach/uncompress.h +++ b/arch/arm/mach-tegra/include/mach/uncompress.h @@ -3,11 +3,13 @@ * * Copyright (C) 2010 Google, Inc. * Copyright (C) 2011 Google, Inc. + * Copyright (C) 2011 NVIDIA CORPORATION. All Rights Reserved. * * Author: * Colin Cross * Erik Gilling * Doug Anderson + * Stephen Warren * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -23,6 +25,7 @@ #ifndef __MACH_TEGRA_UNCOMPRESS_H #define __MACH_TEGRA_UNCOMPRESS_H +#include #include #include @@ -46,12 +49,82 @@ static inline void flush(void) { } +/* + * Setup before decompression. This is where we do UART selection for + * earlyprintk and init the uart_base register. + */ static inline void arch_decomp_setup(void) { + static const struct { + u32 base; + u32 reset_reg; + u32 clock_reg; + u32 bit; + } uarts[] = { + { + TEGRA_UARTA_BASE, + TEGRA_CLK_RESET_BASE + 0x04, + TEGRA_CLK_RESET_BASE + 0x10, + 6, + }, + { + TEGRA_UARTB_BASE, + TEGRA_CLK_RESET_BASE + 0x04, + TEGRA_CLK_RESET_BASE + 0x10, + 7, + }, + { + TEGRA_UARTC_BASE, + TEGRA_CLK_RESET_BASE + 0x08, + TEGRA_CLK_RESET_BASE + 0x14, + 23, + }, + { + TEGRA_UARTD_BASE, + TEGRA_CLK_RESET_BASE + 0x0c, + TEGRA_CLK_RESET_BASE + 0x18, + 1, + }, + { + TEGRA_UARTE_BASE, + TEGRA_CLK_RESET_BASE + 0x0c, + TEGRA_CLK_RESET_BASE + 0x18, + 2, + }, + }; + int i; volatile u32 *apb_misc = (volatile u32 *)TEGRA_APB_MISC_BASE; u32 chip, div; - uart = (volatile u8 *)TEGRA_DEBUG_UART_BASE; + /* + * Look for the first UART that: + * a) Is not in reset. + * b) Is clocked. + * c) Has a 'D' in the scratchpad register. + * + * Note that on Tegra30, the first two conditions are required, since + * if not true, accesses to the UART scratch register will hang. + * Tegra20 doesn't have this issue. + * + * The intent is that the bootloader will tell the kernel which UART + * to use by setting up those conditions. If nothing found, we'll fall + * back to what's specified in TEGRA_DEBUG_UART_BASE. + */ + for (i = 0; i < ARRAY_SIZE(uarts); i++) { + if (*(u8 *)uarts[i].reset_reg & BIT(uarts[i].bit)) + continue; + + if (!(*(u8 *)uarts[i].clock_reg & BIT(uarts[i].bit))) + continue; + + uart = (volatile u8 *)uarts[i].base; + if (uart[UART_SCR << DEBUG_UART_SHIFT] != 'D') + continue; + + break; + } + if (i == ARRAY_SIZE(uarts)) + uart = (volatile u8 *)TEGRA_DEBUG_UART_BASE; if (uart == NULL) return; -- cgit v0.10.2 From 6d7d7b3ecd20a0fbcebdbdffe7b25d94cfa37d93 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Fri, 6 Jan 2012 10:43:22 +0000 Subject: ARM: tegra: Pass uncompress.h UART selection to DEBUG_LL uncompress.h now saves the selected UART's physical address in Tegra's IRAM, along with a cookie to indicate validity. The first time it's run, macro addruart in debug-macro.S looks for this cookie, and if it's present, uses the UART address stored there. If not, the static value TEGRA_DEBUG_UART_BASE is used, as was previous behaviour. The static behaviour will thus be used when not booting using a zImage. This work was inspired by work by Doug Anderson ; see http://lkml.org/lkml/2011/9/26/284. However, this patch relies on the data passing describe above, rather than duplicating the UART selection logic in debug-macro.S; the latest selection logic is more complex due to the need to check reset/clock bits too. Signed-off-by: Stephen Warren Tested-by: Doug Anderson Acked-by: Doug Anderson Signed-off-by: Olof Johansson diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c index a2eb901..76210e5 100644 --- a/arch/arm/mach-tegra/common.c +++ b/arch/arm/mach-tegra/common.c @@ -33,6 +33,23 @@ #include "clock.h" #include "fuse.h" +/* + * Storage for debug-macro.S's state. + * + * This must be in .data not .bss so that it gets initialized each time the + * kernel is loaded. The data is declared here rather than debug-macro.S so + * that multiple inclusions of debug-macro.S point at the same data. + */ +#define TEGRA_DEBUG_UART_OFFSET (TEGRA_DEBUG_UART_BASE & 0xFFFF) +u32 tegra_uart_config[3] = { + /* Debug UART initialization required */ + 1, + /* Debug UART physical address */ + (u32)(IO_APB_PHYS + TEGRA_DEBUG_UART_OFFSET), + /* Debug UART virtual address */ + (u32)(IO_APB_VIRT + TEGRA_DEBUG_UART_OFFSET), +}; + #ifdef CONFIG_OF static const struct of_device_id tegra_dt_irq_match[] __initconst = { { .compatible = "arm,cortex-a9-gic", .data = gic_of_init }, diff --git a/arch/arm/mach-tegra/include/mach/debug-macro.S b/arch/arm/mach-tegra/include/mach/debug-macro.S index 619abc6..90069ab 100644 --- a/arch/arm/mach-tegra/include/mach/debug-macro.S +++ b/arch/arm/mach-tegra/include/mach/debug-macro.S @@ -1,11 +1,17 @@ /* * arch/arm/mach-tegra/include/mach/debug-macro.S * - * Copyright (C) 2010 Google, Inc. + * Copyright (C) 2010,2011 Google, Inc. + * Copyright (C) 2011-2012 NVIDIA CORPORATION. All Rights Reserved. * * Author: * Colin Cross * Erik Gilling + * Doug Anderson + * Stephen Warren + * + * Portions based on mach-omap2's debug-macro.S + * Copyright (C) 1994-1999 Russell King * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -18,18 +24,78 @@ * */ +#include + #include #include +#include + + .macro addruart, rp, rv, tmp + adr \rp, 99f @ actual addr of 99f + ldr \rv, [\rp] @ linked addr is stored there + sub \rv, \rv, \rp @ offset between the two + ldr \rp, [\rp, #4] @ linked tegra_uart_config + sub \tmp, \rp, \rv @ actual tegra_uart_config + ldr \rp, [\tmp] @ Load tegra_uart_config + cmp \rp, #1 @ needs intitialization? + bne 100f @ no; go load the addresses + mov \rv, #0 @ yes; record init is done + str \rv, [\tmp] + mov \rp, #TEGRA_IRAM_BASE @ See if cookie is in IRAM + ldr \rv, [\rp, #TEGRA_IRAM_DEBUG_UART_OFFSET] + movw \rp, #TEGRA_IRAM_DEBUG_UART_COOKIE & 0xffff + movt \rp, #TEGRA_IRAM_DEBUG_UART_COOKIE >> 16 + cmp \rv, \rp @ Cookie present? + bne 100f @ No, use default UART + mov \rp, #TEGRA_IRAM_BASE @ Load UART address from IRAM + ldr \rv, [\rp, #TEGRA_IRAM_DEBUG_UART_OFFSET + 4] + str \rv, [\tmp, #4] @ Store in tegra_uart_phys + sub \rv, \rv, #IO_APB_PHYS @ Calculate virt address + add \rv, \rv, #IO_APB_VIRT + str \rv, [\tmp, #8] @ Store in tegra_uart_virt + b 100f + + .align +99: .word . + .word tegra_uart_config + .ltorg + +100: ldr \rp, [\tmp, #4] @ Load tegra_uart_phys + ldr \rv, [\tmp, #8] @ Load tegra_uart_virt + .endm + +#define UART_SHIFT 2 + +/* + * Code below is swiped from , but add an extra + * check to make sure that we aren't in the CONFIG_TEGRA_DEBUG_UART_NONE case. + * We use the fact that all 5 valid UART addresses all have something in the + * 2nd-to-lowest byte. + */ - .macro addruart, rp, rv, tmp - ldr \rp, =IO_APB_PHYS @ physical - ldr \rv, =IO_APB_VIRT @ virtual - orr \rp, \rp, #(TEGRA_DEBUG_UART_BASE & 0xFF) - orr \rp, \rp, #(TEGRA_DEBUG_UART_BASE & 0xFF00) - orr \rv, \rv, #(TEGRA_DEBUG_UART_BASE & 0xFF) - orr \rv, \rv, #(TEGRA_DEBUG_UART_BASE & 0xFF00) - .endm + .macro senduart, rd, rx + tst \rx, #0x0000ff00 + strneb \rd, [\rx, #UART_TX << UART_SHIFT] +1001: + .endm -#define UART_SHIFT 2 -#include + .macro busyuart, rd, rx + tst \rx, #0x0000ff00 + beq 1002f +1001: ldrb \rd, [\rx, #UART_LSR << UART_SHIFT] + and \rd, \rd, #UART_LSR_TEMT | UART_LSR_THRE + teq \rd, #UART_LSR_TEMT | UART_LSR_THRE + bne 1001b +1002: + .endm + .macro waituart, rd, rx +#ifdef FLOW_CONTROL + tst \rx, #0x0000ff00 + beq 1002f +1001: ldrb \rd, [\rx, #UART_MSR << UART_SHIFT] + tst \rd, #UART_MSR_CTS + beq 1001b +1002: +#endif + .endm diff --git a/arch/arm/mach-tegra/include/mach/irammap.h b/arch/arm/mach-tegra/include/mach/irammap.h new file mode 100644 index 0000000..0cbe632 --- /dev/null +++ b/arch/arm/mach-tegra/include/mach/irammap.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + */ + +#ifndef __MACH_TEGRA_IRAMMAP_H +#define __MACH_TEGRA_IRAMMAP_H + +#include + +/* The first 1K of IRAM is permanently reserved for the CPU reset handler */ +#define TEGRA_IRAM_RESET_HANDLER_OFFSET 0 +#define TEGRA_IRAM_RESET_HANDLER_SIZE SZ_1K + +/* + * These locations are written to by uncompress.h, and read by debug-macro.S. + * The first word holds the cookie value if the data is valid. The second + * word holds the UART physical address. + */ +#define TEGRA_IRAM_DEBUG_UART_OFFSET SZ_1K +#define TEGRA_IRAM_DEBUG_UART_SIZE 8 +#define TEGRA_IRAM_DEBUG_UART_COOKIE 0x55415254 + +#endif diff --git a/arch/arm/mach-tegra/include/mach/uncompress.h b/arch/arm/mach-tegra/include/mach/uncompress.h index 6c087b6..b066ba0 100644 --- a/arch/arm/mach-tegra/include/mach/uncompress.h +++ b/arch/arm/mach-tegra/include/mach/uncompress.h @@ -3,7 +3,7 @@ * * Copyright (C) 2010 Google, Inc. * Copyright (C) 2011 Google, Inc. - * Copyright (C) 2011 NVIDIA CORPORATION. All Rights Reserved. + * Copyright (C) 2011-2012 NVIDIA CORPORATION. All Rights Reserved. * * Author: * Colin Cross @@ -30,6 +30,7 @@ #include #include +#include #define DEBUG_UART_SHIFT 2 @@ -49,6 +50,17 @@ static inline void flush(void) { } +static inline void save_uart_address(void) +{ + u32 *buf = (u32 *)(TEGRA_IRAM_BASE + TEGRA_IRAM_DEBUG_UART_OFFSET); + + if (uart) { + buf[0] = TEGRA_IRAM_DEBUG_UART_COOKIE; + buf[1] = (u32)uart; + } else + buf[0] = 0; +} + /* * Setup before decompression. This is where we do UART selection for * earlyprintk and init the uart_base register. @@ -125,6 +137,7 @@ static inline void arch_decomp_setup(void) } if (i == ARRAY_SIZE(uarts)) uart = (volatile u8 *)TEGRA_DEBUG_UART_BASE; + save_uart_address(); if (uart == NULL) return; -- cgit v0.10.2 From 2123552d12168e744271aaf206e5826760fbd857 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Wed, 4 Jan 2012 08:39:33 +0000 Subject: ARM: tegra: Remove use of TEGRA_GPIO_TO_IRQ Replace compile-time usage of TEGRA_GPIO_TO_IRQ with run-time calls to gpio_to_irq(). This will allow the base IRQ number for the Tegra GPIO driver to be dynamically allocated in a later patch. Signed-off-by: Stephen Warren Acked-by: Grant Likely Signed-off-by: Olof Johansson diff --git a/arch/arm/mach-tegra/board-harmony.c b/arch/arm/mach-tegra/board-harmony.c index 789bdc9..c00aadb 100644 --- a/arch/arm/mach-tegra/board-harmony.c +++ b/arch/arm/mach-tegra/board-harmony.c @@ -101,7 +101,6 @@ static struct wm8903_platform_data harmony_wm8903_pdata = { static struct i2c_board_info __initdata wm8903_board_info = { I2C_BOARD_INFO("wm8903", 0x1a), .platform_data = &harmony_wm8903_pdata, - .irq = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_CDC_IRQ), }; static void __init harmony_i2c_init(void) @@ -111,6 +110,7 @@ static void __init harmony_i2c_init(void) platform_device_register(&tegra_i2c_device3); platform_device_register(&tegra_i2c_device4); + wm8903_board_info.irq = gpio_to_irq(TEGRA_GPIO_CDC_IRQ); i2c_register_board_info(0, &wm8903_board_info, 1); } diff --git a/arch/arm/mach-tegra/board-seaboard.c b/arch/arm/mach-tegra/board-seaboard.c index ebac65f..d669847 100644 --- a/arch/arm/mach-tegra/board-seaboard.c +++ b/arch/arm/mach-tegra/board-seaboard.c @@ -159,7 +159,6 @@ static struct platform_device *seaboard_devices[] __initdata = { static struct i2c_board_info __initdata isl29018_device = { I2C_BOARD_INFO("isl29018", 0x44), - .irq = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_ISL29018_IRQ), }; static struct i2c_board_info __initdata adt7461_device = { @@ -183,7 +182,6 @@ static struct wm8903_platform_data wm8903_pdata = { static struct i2c_board_info __initdata wm8903_device = { I2C_BOARD_INFO("wm8903", 0x1a), .platform_data = &wm8903_pdata, - .irq = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_CDC_IRQ), }; static int seaboard_ehci_init(void) @@ -214,7 +212,10 @@ static void __init seaboard_i2c_init(void) gpio_request(TEGRA_GPIO_ISL29018_IRQ, "isl29018"); gpio_direction_input(TEGRA_GPIO_ISL29018_IRQ); + isl29018_device.irq = gpio_to_irq(TEGRA_GPIO_ISL29018_IRQ); i2c_register_board_info(0, &isl29018_device, 1); + + wm8903_device.irq = gpio_to_irq(TEGRA_GPIO_CDC_IRQ); i2c_register_board_info(0, &wm8903_device, 1); i2c_register_board_info(3, &adt7461_device, 1); -- cgit v0.10.2 From 6f74dc9bc8de41f3de474a7269a70921e773c40f Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Wed, 4 Jan 2012 08:39:37 +0000 Subject: gpio: tegra: Dynamically allocate IRQ base, and support DT Enhance the driver to dynamically allocate the base IRQ number, and create an IRQ domain for itself. The use of an IRQ domain ensures that any device tree node interrupts properties are correctly parsed. Describe interrupt-related properties in the device tree binding docs, and the contents of "child" node interrupts property. Update tegra*.dtsi to specify the required interrupt-related properties. Finally, remove the definition of TEGRA_GPIO_TO_IRQ; this macro no longer gives correct results since the IRQ numbers for GPIOs are dynamically allocated. Signed-off-by: Stephen Warren Acked-by: Grant Likely Signed-off-by: Olof Johansson diff --git a/Documentation/devicetree/bindings/gpio/gpio_nvidia.txt b/Documentation/devicetree/bindings/gpio/gpio_nvidia.txt index 50b363c..d114e199 100644 --- a/Documentation/devicetree/bindings/gpio/gpio_nvidia.txt +++ b/Documentation/devicetree/bindings/gpio/gpio_nvidia.txt @@ -8,6 +8,16 @@ Required properties: second cell is used to specify optional parameters: - bit 0 specifies polarity (0 for normal, 1 for inverted) - gpio-controller : Marks the device node as a GPIO controller. +- #interrupt-cells : Should be 2. + The first cell is the GPIO number. + The second cell is used to specify flags: + bits[3:0] trigger type and level flags: + 1 = low-to-high edge triggered. + 2 = high-to-low edge triggered. + 4 = active high level-sensitive. + 8 = active low level-sensitive. + Valid combinations are 1, 2, 3, 4, 8. +- interrupt-controller : Marks the device node as an interrupt controller. Example: @@ -23,4 +33,6 @@ gpio: gpio@6000d000 { 0 89 0x04 >; #gpio-cells = <2>; gpio-controller; + #interrupt-cells = <2>; + interrupt-controller; }; diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi index 3195ad5..ec1f010 100644 --- a/arch/arm/boot/dts/tegra20.dtsi +++ b/arch/arm/boot/dts/tegra20.dtsi @@ -101,6 +101,8 @@ 0 89 0x04 >; #gpio-cells = <2>; gpio-controller; + #interrupt-cells = <2>; + interrupt-controller; }; pinmux: pinmux@70000000 { diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi index fd25e8e..ac4b75c 100644 --- a/arch/arm/boot/dts/tegra30.dtsi +++ b/arch/arm/boot/dts/tegra30.dtsi @@ -107,6 +107,8 @@ 0 125 0x04 >; #gpio-cells = <2>; gpio-controller; + #interrupt-cells = <2>; + interrupt-controller; }; serial@70006000 { diff --git a/arch/arm/mach-tegra/include/mach/gpio-tegra.h b/arch/arm/mach-tegra/include/mach/gpio-tegra.h index 87d37fd..6140820 100644 --- a/arch/arm/mach-tegra/include/mach/gpio-tegra.h +++ b/arch/arm/mach-tegra/include/mach/gpio-tegra.h @@ -25,8 +25,6 @@ #define TEGRA_NR_GPIOS INT_GPIO_NR -#define TEGRA_GPIO_TO_IRQ(gpio) (INT_GPIO_BASE + (gpio)) - struct tegra_gpio_table { int gpio; /* GPIO number */ bool enable; /* Enable for GPIO at init? */ diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index bdc2937..bc923c7 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -25,6 +25,7 @@ #include #include #include +#include #include @@ -74,7 +75,7 @@ struct tegra_gpio_bank { #endif }; - +static struct irq_domain irq_domain; static void __iomem *regs; static struct tegra_gpio_bank tegra_gpio_banks[7]; @@ -139,7 +140,7 @@ static int tegra_gpio_direction_output(struct gpio_chip *chip, unsigned offset, static int tegra_gpio_to_irq(struct gpio_chip *chip, unsigned offset) { - return TEGRA_GPIO_TO_IRQ(offset); + return irq_domain_to_irq(&irq_domain, offset); } static struct gpio_chip tegra_gpio_chip = { @@ -155,28 +156,28 @@ static struct gpio_chip tegra_gpio_chip = { static void tegra_gpio_irq_ack(struct irq_data *d) { - int gpio = d->irq - INT_GPIO_BASE; + int gpio = d->hwirq; tegra_gpio_writel(1 << GPIO_BIT(gpio), GPIO_INT_CLR(gpio)); } static void tegra_gpio_irq_mask(struct irq_data *d) { - int gpio = d->irq - INT_GPIO_BASE; + int gpio = d->hwirq; tegra_gpio_mask_write(GPIO_MSK_INT_ENB(gpio), gpio, 0); } static void tegra_gpio_irq_unmask(struct irq_data *d) { - int gpio = d->irq - INT_GPIO_BASE; + int gpio = d->hwirq; tegra_gpio_mask_write(GPIO_MSK_INT_ENB(gpio), gpio, 1); } static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type) { - int gpio = d->irq - INT_GPIO_BASE; + int gpio = d->hwirq; struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d); int port = GPIO_PORT(gpio); int lvl_type; @@ -343,6 +344,16 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev) int i; int j; + irq_domain.irq_base = irq_alloc_descs(-1, 0, TEGRA_NR_GPIOS, 0); + if (irq_domain.irq_base < 0) { + dev_err(&pdev->dev, "Couldn't allocate IRQ numbers\n"); + return -ENODEV; + } + irq_domain.nr_irq = TEGRA_NR_GPIOS; + irq_domain.ops = &irq_domain_simple_ops; + irq_domain.of_node = pdev->dev.of_node; + irq_domain_add(&irq_domain); + for (i = 0; i < ARRAY_SIZE(tegra_gpio_banks); i++) { res = platform_get_resource(pdev, IORESOURCE_IRQ, i); if (!res) { @@ -381,7 +392,7 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev) gpiochip_add(&tegra_gpio_chip); for (gpio = 0; gpio < TEGRA_NR_GPIOS; gpio++) { - int irq = TEGRA_GPIO_TO_IRQ(gpio); + int irq = irq_domain_to_irq(&irq_domain, gpio); /* No validity check; all Tegra GPIOs are valid IRQs */ bank = &tegra_gpio_banks[GPIO_BANK(gpio)]; -- cgit v0.10.2 From 3391811c4294da42e412ec5f83a251caf05869a4 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Thu, 19 Jan 2012 08:16:35 +0000 Subject: gpio: tegra: Parameterize the number of banks Tegra20's GPIO controller has 7 banks, and Tegra30's controller has 8 banks. Allow the number of banks to be configured at run-time by the device tree. Signed-off-by: Stephen Warren Acked-by: Grant Likely Signed-off-by: Olof Johansson diff --git a/Documentation/devicetree/bindings/gpio/gpio_nvidia.txt b/Documentation/devicetree/bindings/gpio/gpio_nvidia.txt index d114e199..023c952 100644 --- a/Documentation/devicetree/bindings/gpio/gpio_nvidia.txt +++ b/Documentation/devicetree/bindings/gpio/gpio_nvidia.txt @@ -1,9 +1,11 @@ -NVIDIA Tegra 2 GPIO controller +NVIDIA Tegra GPIO controller Required properties: -- compatible : "nvidia,tegra20-gpio" +- compatible : "nvidia,tegra-gpio" - reg : Physical base address and length of the controller's registers. -- interrupts : The interrupt outputs from the controller. +- interrupts : The interrupt outputs from the controller. For Tegra20, + there should be 7 interrupts specified, and for Tegra30, there should + be 8 interrupts specified. - #gpio-cells : Should be two. The first cell is the pin number and the second cell is used to specify optional parameters: - bit 0 specifies polarity (0 for normal, 1 for inverted) diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index bc923c7..98f3980 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -77,7 +77,8 @@ struct tegra_gpio_bank { static struct irq_domain irq_domain; static void __iomem *regs; -static struct tegra_gpio_bank tegra_gpio_banks[7]; +static u32 tegra_gpio_bank_count; +static struct tegra_gpio_bank *tegra_gpio_banks; static inline void tegra_gpio_writel(u32 val, u32 reg) { @@ -274,7 +275,7 @@ void tegra_gpio_resume(void) local_irq_save(flags); - for (b = 0; b < ARRAY_SIZE(tegra_gpio_banks); b++) { + for (b = 0; b < tegra_gpio_bank_count; b++) { struct tegra_gpio_bank *bank = &tegra_gpio_banks[b]; for (p = 0; p < ARRAY_SIZE(bank->oe); p++) { @@ -297,7 +298,7 @@ void tegra_gpio_suspend(void) int p; local_irq_save(flags); - for (b = 0; b < ARRAY_SIZE(tegra_gpio_banks); b++) { + for (b = 0; b < tegra_gpio_bank_count; b++) { struct tegra_gpio_bank *bank = &tegra_gpio_banks[b]; for (p = 0; p < ARRAY_SIZE(bank->oe); p++) { @@ -338,23 +339,46 @@ static struct lock_class_key gpio_lock_class; static int __devinit tegra_gpio_probe(struct platform_device *pdev) { + int irq_base; struct resource *res; struct tegra_gpio_bank *bank; int gpio; int i; int j; - irq_domain.irq_base = irq_alloc_descs(-1, 0, TEGRA_NR_GPIOS, 0); - if (irq_domain.irq_base < 0) { + for (;;) { + res = platform_get_resource(pdev, IORESOURCE_IRQ, tegra_gpio_bank_count); + if (!res) + break; + tegra_gpio_bank_count++; + } + if (!tegra_gpio_bank_count) { + dev_err(&pdev->dev, "Missing IRQ resource\n"); + return -ENODEV; + } + + tegra_gpio_chip.ngpio = tegra_gpio_bank_count * 32; + + tegra_gpio_banks = devm_kzalloc(&pdev->dev, + tegra_gpio_bank_count * sizeof(*tegra_gpio_banks), + GFP_KERNEL); + if (!tegra_gpio_banks) { + dev_err(&pdev->dev, "Couldn't allocate bank structure\n"); + return -ENODEV; + } + + irq_base = irq_alloc_descs(-1, 0, tegra_gpio_chip.ngpio, 0); + if (irq_base < 0) { dev_err(&pdev->dev, "Couldn't allocate IRQ numbers\n"); return -ENODEV; } - irq_domain.nr_irq = TEGRA_NR_GPIOS; + irq_domain.irq_base = irq_base; + irq_domain.nr_irq = tegra_gpio_chip.ngpio; irq_domain.ops = &irq_domain_simple_ops; irq_domain.of_node = pdev->dev.of_node; irq_domain_add(&irq_domain); - for (i = 0; i < ARRAY_SIZE(tegra_gpio_banks); i++) { + for (i = 0; i < tegra_gpio_bank_count; i++) { res = platform_get_resource(pdev, IORESOURCE_IRQ, i); if (!res) { dev_err(&pdev->dev, "Missing IRQ resource\n"); @@ -391,7 +415,7 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev) gpiochip_add(&tegra_gpio_chip); - for (gpio = 0; gpio < TEGRA_NR_GPIOS; gpio++) { + for (gpio = 0; gpio < tegra_gpio_chip.ngpio; gpio++) { int irq = irq_domain_to_irq(&irq_domain, gpio); /* No validity check; all Tegra GPIOs are valid IRQs */ @@ -404,7 +428,7 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev) set_irq_flags(irq, IRQF_VALID); } - for (i = 0; i < ARRAY_SIZE(tegra_gpio_banks); i++) { + for (i = 0; i < tegra_gpio_bank_count; i++) { bank = &tegra_gpio_banks[i]; irq_set_chained_handler(bank->irq, tegra_gpio_irq_handler); -- cgit v0.10.2 From 76c2f6e513b3df8031dda383838da2a3820adbe3 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Thu, 26 Jan 2012 15:12:23 +0000 Subject: ARM: tegra: Fix EMC pdata initialization from registers Commit d91eeb0 "ARM: tegra: emc: device tree support" modified the EMC driver to create an EMC table from existing register settings when none was provided through platform data or device tree. This code wrote the wrong clock rate into the table; the actual rate in Hz, rather than the expected half-rate in KHz. This caused the BUG_ON in tegra2_emc_clk_round_rate() to fire, since that enormous rate could not be generated. Fixes: [ 2.425921] kernel BUG at arch/arm/mach-tegra/tegra2_clocks.c:1158! ... [ 2.618766] [] (tegra2_emc_clk_round_rate+0x58/0x70) from [] (clk_round_rate+0x48/0x68) [ 2.628494] [] (clk_round_rate+0x48/0x68) from [] (clk_set_rate_locked+0x40/0x68) [ 2.637707] [] (clk_set_rate_locked+0x40/0x68) from [] (clk_set_rate+0x28/0x40) [ 2.646754] [] (clk_set_rate+0x28/0x40) from [] (tegra_update_cpu_speed+0x54/0x144) [ 2.656144] [] (tegra_update_cpu_speed+0x54/0x144) from [] (tegra_target+0xb4/0xe0) [ 2.665538] [] (tegra_target+0xb4/0xe0) from [] (__cpufreq_driver_target+0x88/0xa4) [ 2.674931] [] (__cpufreq_driver_target+0x88/0xa4) from [] (dbs_check_cpu+0x324/0x340) [ 2.684582] [] (dbs_check_cpu+0x324/0x340) from [] (do_dbs_timer+0x54/0xf4) [ 2.693277] [] (do_dbs_timer+0x54/0xf4) from [] (process_one_work+0x1d4/0x320) [ 2.702225] [] (process_one_work+0x1d4/0x320) from [] (worker_thread+0x134/0x230) [ 2.711437] [] (worker_thread+0x134/0x230) from [] (kthread+0x80/0x8c) [ 2.719700] [] (kthread+0x80/0x8c) from [] (kernel_thread_exit+0x0/0x8) Reported-by: Marc Dietrich Signed-off-by: Stephen Warren [olof: fixed calculation of printed values] Signed-off-by: Olof Johansson diff --git a/arch/arm/mach-tegra/tegra2_emc.c b/arch/arm/mach-tegra/tegra2_emc.c index 52df6ca..5070d83 100644 --- a/arch/arm/mach-tegra/tegra2_emc.c +++ b/arch/arm/mach-tegra/tegra2_emc.c @@ -284,16 +284,16 @@ static struct tegra_emc_pdata __devinit *tegra_emc_fill_pdata(struct platform_de pdata->tables = devm_kzalloc(&pdev->dev, sizeof(*pdata->tables), GFP_KERNEL); - pdata->tables[0].rate = clk_get_rate(c); + pdata->tables[0].rate = clk_get_rate(c) / 2 / 1000; for (i = 0; i < TEGRA_EMC_NUM_REGS; i++) pdata->tables[0].regs[i] = emc_readl(emc_reg_addr[i]); pdata->num_tables = 1; - khz = pdata->tables[0].rate / 1000; + khz = pdata->tables[0].rate; dev_info(&pdev->dev, "no tables provided, using %ld kHz emc, " - "%ld kHz mem\n", khz, khz/2); + "%ld kHz mem\n", khz * 2, khz); return pdata; } -- cgit v0.10.2 From 8bc4f556bd740789cf6fab36d1776d6d4d8bd375 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Tue, 24 Jan 2012 13:40:49 +0530 Subject: ARM: tegra: dma: not required to move requestor when stopping. It is not require to move the requestor of dma to INVALID option before stopping dma. Signed-off-by: Laxman Dewangan Acked-by: Stephen Warren Tested-by: Stephen Warren Signed-off-by: Olof Johansson diff --git a/arch/arm/mach-tegra/dma.c b/arch/arm/mach-tegra/dma.c index 998c55d..abea4f6 100644 --- a/arch/arm/mach-tegra/dma.c +++ b/arch/arm/mach-tegra/dma.c @@ -52,8 +52,6 @@ #define CSR_ONCE (1<<27) #define CSR_FLOW (1<<21) #define CSR_REQ_SEL_SHIFT 16 -#define CSR_REQ_SEL_MASK (0x1F<lock, irq_flags); while (!list_empty(&ch->list)) list_del(ch->list.next); - csr = readl(ch->addr + APB_DMA_CHAN_CSR); - csr &= ~CSR_REQ_SEL_MASK; - csr |= CSR_REQ_SEL_INVALID; - writel(csr, ch->addr + APB_DMA_CHAN_CSR); - tegra_dma_stop(ch); spin_unlock_irqrestore(&ch->lock, irq_flags); -- cgit v0.10.2 From d3b8bdd5f9bc538fb17466cbb7af43209b55cb93 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Wed, 25 Jan 2012 14:43:28 -0700 Subject: ARM: tegra: Add a simple PMC driver This PMC driver is enough to parse the nvidia,invert-interrupt property from device tree, and configure the PMC's to honor that. In the future, this file could expand to centralize all other PMC accesses within the mach-tegra code. Signed-off-by: Stephen Warren Signed-off-by: Olof Johansson diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile index 23d15fb..e0b7a4d 100644 --- a/arch/arm/mach-tegra/Makefile +++ b/arch/arm/mach-tegra/Makefile @@ -7,6 +7,7 @@ obj-y += clock.o obj-y += timer.o obj-y += pinmux.o obj-y += fuse.o +obj-y += pmc.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += powergate.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_clocks.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_emc.o diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c index 76210e5..43da428 100644 --- a/arch/arm/mach-tegra/common.c +++ b/arch/arm/mach-tegra/common.c @@ -32,6 +32,7 @@ #include "board.h" #include "clock.h" #include "fuse.h" +#include "pmc.h" /* * Storage for debug-macro.S's state. @@ -117,11 +118,13 @@ void __init tegra20_init_early(void) tegra2_init_clocks(); tegra_clk_init_from_table(tegra20_clk_init_table); tegra_init_cache(0x331, 0x441); + tegra_pmc_init(); } #endif #ifdef CONFIG_ARCH_TEGRA_3x_SOC void __init tegra30_init_early(void) { tegra_init_cache(0x441, 0x551); + tegra_pmc_init(); } #endif diff --git a/arch/arm/mach-tegra/pmc.c b/arch/arm/mach-tegra/pmc.c new file mode 100644 index 0000000..7af6a54 --- /dev/null +++ b/arch/arm/mach-tegra/pmc.c @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + * + */ + +#include +#include +#include + +#include + +#define PMC_CTRL 0x0 +#define PMC_CTRL_INTR_LOW (1 << 17) + +static inline u32 tegra_pmc_readl(u32 reg) +{ + return readl(IO_ADDRESS(TEGRA_PMC_BASE + reg)); +} + +static inline void tegra_pmc_writel(u32 val, u32 reg) +{ + writel(val, IO_ADDRESS(TEGRA_PMC_BASE + reg)); +} + +#ifdef CONFIG_OF +static const struct of_device_id matches[] __initconst = { + { .compatible = "nvidia,tegra20-pmc" }, + { } +}; +#endif + +void __init tegra_pmc_init(void) +{ + /* + * For now, Harmony is the only board that uses the PMC, and it wants + * the signal inverted. Seaboard would too if it used the PMC. + * Hopefully by the time other boards want to use the PMC, everything + * will be device-tree, or they also want it inverted. + */ + bool invert_interrupt = true; + u32 val; + +#ifdef CONFIG_OF + if (of_have_populated_dt()) { + struct device_node *np; + + invert_interrupt = false; + + np = of_find_matching_node(NULL, matches); + if (np) { + if (of_find_property(np, "nvidia,invert-interrupt", + NULL)) + invert_interrupt = true; + } + } +#endif + + val = tegra_pmc_readl(PMC_CTRL); + if (invert_interrupt) + val |= PMC_CTRL_INTR_LOW; + else + val &= ~PMC_CTRL_INTR_LOW; + tegra_pmc_writel(val, PMC_CTRL); +} diff --git a/arch/arm/mach-tegra/pmc.h b/arch/arm/mach-tegra/pmc.h new file mode 100644 index 0000000..8995ee4 --- /dev/null +++ b/arch/arm/mach-tegra/pmc.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + * + */ + +#ifndef __MACH_TEGRA_PMC_H +#define __MACH_TEGRA_PMC_H + +void tegra_pmc_init(void); + +#endif -- cgit v0.10.2 From 129cee1020d8031df1e3986673c64ca9eb7a2617 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Wed, 25 Jan 2012 11:43:29 +0000 Subject: ARM: tegra: Remove duplicate PMU interrupt inversion code The new PMC driver now configures the PMU interrupt inversion, so board files don't need to poke the PMC registers directly to achieve this. Signed-off-by: Stephen Warren Signed-off-by: Olof Johansson diff --git a/arch/arm/mach-tegra/board-harmony-power.c b/arch/arm/mach-tegra/board-harmony-power.c index 21d1285..976edfb0 100644 --- a/arch/arm/mach-tegra/board-harmony-power.c +++ b/arch/arm/mach-tegra/board-harmony-power.c @@ -18,18 +18,13 @@ #include #include #include -#include #include #include -#include #include #include "board-harmony.h" -#define PMC_CTRL 0x0 -#define PMC_CTRL_INTR_LOW (1 << 17) - static struct regulator_consumer_supply tps658621_ldo0_supply[] = { REGULATOR_SUPPLY("pex_clk", NULL), }; @@ -114,16 +109,6 @@ static struct i2c_board_info __initdata harmony_regulators[] = { int __init harmony_regulator_init(void) { - void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE); - u32 pmc_ctrl; - - /* - * Configure the power management controller to trigger PMU - * interrupts when low - */ - pmc_ctrl = readl(pmc + PMC_CTRL); - writel(pmc_ctrl | PMC_CTRL_INTR_LOW, pmc + PMC_CTRL); - i2c_register_board_info(3, harmony_regulators, 1); return 0; -- cgit v0.10.2 From bdc93a77da75ee421125896ce4bbd91afff63809 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Mon, 13 Feb 2012 16:21:15 -0700 Subject: gpio: tegra: Fix build issue due to irq_domain rework. Commit 7da5a66 "irq_domain: Remove 'new' irq_domain in favour of the ppc one" changed the set of available irq domain APIs. Update the Tegra GPIO driver to account for those changes, to solve a build break. Signed-off-by: Stephen Warren Signed-off-by: Olof Johansson diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 98f3980..6f17671 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -75,7 +75,7 @@ struct tegra_gpio_bank { #endif }; -static struct irq_domain irq_domain; +static struct irq_domain *irq_domain; static void __iomem *regs; static u32 tegra_gpio_bank_count; static struct tegra_gpio_bank *tegra_gpio_banks; @@ -141,7 +141,7 @@ static int tegra_gpio_direction_output(struct gpio_chip *chip, unsigned offset, static int tegra_gpio_to_irq(struct gpio_chip *chip, unsigned offset) { - return irq_domain_to_irq(&irq_domain, offset); + return irq_find_mapping(irq_domain, offset); } static struct gpio_chip tegra_gpio_chip = { @@ -372,11 +372,9 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Couldn't allocate IRQ numbers\n"); return -ENODEV; } - irq_domain.irq_base = irq_base; - irq_domain.nr_irq = tegra_gpio_chip.ngpio; - irq_domain.ops = &irq_domain_simple_ops; - irq_domain.of_node = pdev->dev.of_node; - irq_domain_add(&irq_domain); + irq_domain = irq_domain_add_legacy(pdev->dev.of_node, + tegra_gpio_chip.ngpio, irq_base, 0, + &irq_domain_simple_ops, NULL); for (i = 0; i < tegra_gpio_bank_count; i++) { res = platform_get_resource(pdev, IORESOURCE_IRQ, i); @@ -416,7 +414,7 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev) gpiochip_add(&tegra_gpio_chip); for (gpio = 0; gpio < tegra_gpio_chip.ngpio; gpio++) { - int irq = irq_domain_to_irq(&irq_domain, gpio); + int irq = irq_find_mapping(irq_domain, gpio); /* No validity check; all Tegra GPIOs are valid IRQs */ bank = &tegra_gpio_banks[GPIO_BANK(gpio)]; -- cgit v0.10.2