Browse Source

Merge branch 'for-3.4/soc-drivers' into for-3.4/t30-smp

Conflicts:
	arch/arm/mach-tegra/Makefile
Olof Johansson 13 years ago
parent
commit
0f830e5c90
32 changed files with 1465 additions and 193 deletions
  1. 100 0
      Documentation/devicetree/bindings/arm/tegra/emc.txt
  2. 19 0
      Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt
  3. 30 0
      Documentation/devicetree/bindings/dma/tegra20-apbdma.txt
  4. 34 2
      Documentation/devicetree/bindings/gpio/gpio_nvidia.txt
  5. 35 10
      arch/arm/boot/dts/tegra-harmony.dts
  6. 30 0
      arch/arm/boot/dts/tegra-paz00.dts
  7. 78 0
      arch/arm/boot/dts/tegra-seaboard.dts
  8. 12 0
      arch/arm/boot/dts/tegra-trimslice.dts
  9. 42 0
      arch/arm/boot/dts/tegra-ventana.dts
  10. 39 4
      arch/arm/boot/dts/tegra20.dtsi
  11. 52 1
      arch/arm/boot/dts/tegra30.dtsi
  12. 2 1
      arch/arm/mach-tegra/Makefile
  13. 145 0
      arch/arm/mach-tegra/apbio.c
  14. 39 0
      arch/arm/mach-tegra/apbio.h
  15. 0 15
      arch/arm/mach-tegra/board-harmony-power.c
  16. 1 1
      arch/arm/mach-tegra/board-harmony.c
  17. 3 2
      arch/arm/mach-tegra/board-seaboard.c
  18. 20 0
      arch/arm/mach-tegra/common.c
  19. 77 51
      arch/arm/mach-tegra/dma.c
  20. 74 33
      arch/arm/mach-tegra/fuse.c
  21. 29 5
      arch/arm/mach-tegra/fuse.h
  22. 77 11
      arch/arm/mach-tegra/include/mach/debug-macro.S
  23. 0 2
      arch/arm/mach-tegra/include/mach/gpio-tegra.h
  24. 35 0
      arch/arm/mach-tegra/include/mach/irammap.h
  25. 107 11
      arch/arm/mach-tegra/include/mach/uncompress.h
  26. 76 0
      arch/arm/mach-tegra/pmc.c
  27. 23 0
      arch/arm/mach-tegra/pmc.h
  28. 1 1
      arch/arm/mach-tegra/tegra2_clocks.c
  29. 201 23
      arch/arm/mach-tegra/tegra2_emc.c
  30. 4 7
      arch/arm/mach-tegra/tegra2_emc.h
  31. 46 13
      drivers/gpio/gpio-tegra.c
  32. 34 0
      include/linux/platform_data/tegra_emc.h

+ 100 - 0
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 >;
+		};

+ 19 - 0
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<chip>-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;
+};

+ 30 - 0
Documentation/devicetree/bindings/dma/tegra20-apbdma.txt

@@ -0,0 +1,30 @@
+* NVIDIA Tegra APB DMA controller
+
+Required properties:
+- compatible: Should be "nvidia,<chip>-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 >;
+};

+ 34 - 2
Documentation/devicetree/bindings/gpio/gpio_nvidia.txt

@@ -1,8 +1,40 @@
-NVIDIA Tegra 2 GPIO controller
+NVIDIA Tegra GPIO controller
 
 Required properties:
-- compatible : "nvidia,tegra20-gpio"
+- compatible : "nvidia,tegra<chip>-gpio"
+- reg : Physical base address and length of the controller's registers.
+- 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)
 - 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:
+
+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;
+	#interrupt-cells = <2>;
+	interrupt-controller;
+};

+ 35 - 10
arch/arm/boot/dts/tegra-harmony.dts

@@ -10,19 +10,25 @@
 		reg = < 0x00000000 0x40000000 >;
 	};
 
+	pmc@7000f400 {
+		nvidia,invert-interrupt;
+	};
+
 	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 +44,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 {

+ 30 - 0
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,6 +44,29 @@
 		clock-frequency = <400000>;
 	};
 
+	i2s@70002a00 {
+		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>;
+		nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */
+	};
+
 	serial@70006000 {
 		clock-frequency = <216000000>;
 	};

+ 78 - 0
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";
 	};
@@ -93,4 +133,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 >;
+		};
+	};
 };

+ 12 - 0
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 >;
 	};

+ 42 - 0
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";
 	};

+ 39 - 4
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;
@@ -12,6 +17,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>;
@@ -44,18 +70,18 @@
 		interrupts = < 0 53 0x04 >;
 	};
 
-	i2s@70002800 {
+	tegra_i2s1: i2s@70002800 {
 		compatible = "nvidia,tegra20-i2s";
 		reg = <0x70002800 0x200>;
 		interrupts = < 0 13 0x04 >;
-		dma-channel = < 2 >;
+		nvidia,dma-request-selector = < &apbdma 2 >;
 	};
 
-	i2s@70002a00 {
+	tegra_i2s2: i2s@70002a00 {
 		compatible = "nvidia,tegra20-i2s";
 		reg = <0x70002a00 0x200>;
 		interrupts = < 0 3 0x04 >;
-		dma-channel = < 1 >;
+		nvidia,dma-request-selector = < &apbdma 1 >;
 	};
 
 	das@70000c00 {
@@ -75,6 +101,8 @@
 			       0 89 0x04 >;
 		#gpio-cells = <2>;
 		gpio-controller;
+		#interrupt-cells = <2>;
+		interrupt-controller;
 	};
 
 	pinmux: pinmux@70000000 {
@@ -120,6 +148,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>;

+ 52 - 1
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;
@@ -12,6 +17,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>;
@@ -55,9 +97,18 @@
 	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
+			       0 125 0x04 >;
 		#gpio-cells = <2>;
 		gpio-controller;
+		#interrupt-cells = <2>;
+		interrupt-controller;
 	};
 
 	serial@70006000 {

+ 2 - 1
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_CPU_IDLE)			+= cpuidle.o
 obj-$(CONFIG_CPU_IDLE)			+= sleep.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= powergate.o
@@ -18,7 +19,7 @@ obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= board-dt-tegra30.o
 obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= tegra30_clocks.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

+ 145 - 0
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 <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/sched.h>
+#include <linux/mutex.h>
+
+#include <mach/dma.h>
+#include <mach/iomap.h>
+
+#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);
+}

+ 39 - 0
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 <asm/io.h>
+#include <mach/io.h>
+
+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

+ 0 - 15
arch/arm/mach-tegra/board-harmony-power.c

@@ -18,18 +18,13 @@
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
 #include <linux/gpio.h>
-#include <linux/io.h>
 #include <linux/regulator/machine.h>
 #include <linux/mfd/tps6586x.h>
 
-#include <mach/iomap.h>
 #include <mach/irqs.h>
 
 #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;

+ 1 - 1
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);
 }
 

+ 3 - 2
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);

+ 20 - 0
arch/arm/mach-tegra/common.c

@@ -32,6 +32,24 @@
 #include "board.h"
 #include "clock.h"
 #include "fuse.h"
+#include "pmc.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 = {
@@ -100,6 +118,7 @@ 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
@@ -107,5 +126,6 @@ void __init tegra30_init_early(void)
 {
 	tegra30_init_clocks();
 	tegra_init_cache(0x441, 0x551);
+	tegra_pmc_init();
 }
 #endif

+ 77 - 51
arch/arm/mach-tegra/dma.c

@@ -33,6 +33,8 @@
 #include <mach/iomap.h>
 #include <mach/suspend.h>
 
+#include "apbio.h"
+
 #define APB_DMA_GEN				0x000
 #define GEN_ENABLE				(1<<31)
 
@@ -50,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<<CSR_REQ_SEL_SHIFT)
-#define CSR_REQ_SEL_INVALID			(31<<CSR_REQ_SEL_SHIFT)
 #define CSR_WCOUNT_SHIFT			2
 #define CSR_WCOUNT_MASK				0xFFFC
 
@@ -133,6 +133,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];
@@ -180,36 +181,94 @@ static void tegra_dma_stop(struct tegra_dma_channel *ch)
 
 static int tegra_dma_cancel(struct tegra_dma_channel *ch)
 {
-	u32 csr;
 	unsigned long irq_flags;
 
 	spin_lock_irqsave(&ch->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);
 	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);
@@ -222,47 +281,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;
-
-	req->bytes_transferred = req_transfer_count;
-
-	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;
+	if (!stop)
+		goto skip_stop_dma;
 
-	req->bytes_transferred *= 4;
+	status = get_channel_status(ch, req, true);
+	req->bytes_transferred = dma_active_count(ch, req, status);
 
-	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;
@@ -270,6 +294,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);
@@ -357,7 +383,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);

+ 74 - 33
arch/arm/mach-tegra/fuse.c

@@ -23,20 +23,70 @@
 #include <mach/iomap.h>
 
 #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)
+int tegra_sku_id;
+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",
+	[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 readl(IO_TO_VIRT(TEGRA_FUSE_BASE + offset));
+	return tegra_fuse_readl(FUSE_SPARE_BIT + bit * 4);
 }
 
-static inline void fuse_writel(u32 value, unsigned long offset)
+static enum tegra_revision tegra_get_revision(void)
 {
-	writel(value, IO_TO_VIRT(TEGRA_FUSE_BASE + offset));
+	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)
@@ -45,40 +95,31 @@ void tegra_init_fuse(void)
 	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;
 
-unsigned long long tegra_chip_uid(void)
-{
-	unsigned long long lo, hi;
+	reg = tegra_fuse_readl(FUSE_SPARE_BIT);
+	tegra_cpu_process_id = (reg >> 6) & 3;
 
-	lo = fuse_readl(FUSE_UID_LOW);
-	hi = fuse_readl(FUSE_UID_HIGH);
-	return (hi << 32ull) | lo;
-}
+	reg = tegra_fuse_readl(FUSE_SPARE_BIT);
+	tegra_core_process_id = (reg >> 12) & 3;
 
-int tegra_sku_id(void)
-{
-	int sku_id;
-	u32 reg = fuse_readl(FUSE_SKU_INFO);
-	sku_id = reg & 0xFF;
-	return sku_id;
-}
+	reg = tegra_apb_readl(TEGRA_APB_MISC_BASE + STRAP_OPT);
+	tegra_bct_strapping = (reg & RAM_ID_MASK) >> RAM_CODE_SHIFT;
 
-int tegra_cpu_process_id(void)
-{
-	int cpu_process_id;
-	u32 reg = fuse_readl(FUSE_SPARE_BIT);
-	cpu_process_id = (reg >> 6) & 3;
-	return cpu_process_id;
+	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);
 }
 
-int tegra_core_process_id(void)
+unsigned long long tegra_chip_uid(void)
 {
-	int core_process_id;
-	u32 reg = fuse_readl(FUSE_SPARE_BIT);
-	core_process_id = (reg >> 12) & 3;
-	return core_process_id;
+	unsigned long long lo, hi;
+
+	lo = tegra_fuse_readl(FUSE_UID_LOW);
+	hi = tegra_fuse_readl(FUSE_UID_HIGH);
+	return (hi << 32ull) | lo;
 }

+ 29 - 5
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,34 @@
  *
  */
 
+#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;
+
+extern int tegra_bct_strapping;
+
 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

+ 77 - 11
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 <ccross@google.com>
  *	Erik Gilling <konkers@google.com>
+ *	Doug Anderson <dianders@chromium.org>
+ *	Stephen Warren <swarren@nvidia.com>
+ *
+ * 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 <linux/serial_reg.h>
+
 #include <mach/io.h>
 #include <mach/iomap.h>
+#include <mach/irammap.h>
+
+		.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 <asm/hardware/debug-8250.S>, 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 <asm/hardware/debug-8250.S>
+		.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

+ 0 - 2
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? */

+ 35 - 0
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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MACH_TEGRA_IRAMMAP_H
+#define __MACH_TEGRA_IRAMMAP_H
+
+#include <asm/sizes.h>
+
+/* 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

+ 107 - 11
arch/arm/mach-tegra/include/mach/uncompress.h

@@ -2,10 +2,14 @@
  * arch/arm/mach-tegra/include/mach/uncompress.h
  *
  * Copyright (C) 2010 Google, Inc.
+ * Copyright (C) 2011 Google, Inc.
+ * Copyright (C) 2011-2012 NVIDIA CORPORATION. All Rights Reserved.
  *
  * Author:
  *	Colin Cross <ccross@google.com>
  *	Erik Gilling <konkers@google.com>
+ *	Doug Anderson <dianders@chromium.org>
+ *	Stephen Warren <swarren@nvidia.com>
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -21,40 +25,132 @@
 #ifndef __MACH_TEGRA_UNCOMPRESS_H
 #define __MACH_TEGRA_UNCOMPRESS_H
 
+#include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/serial_reg.h>
 
 #include <mach/iomap.h>
+#include <mach/irammap.h>
+
+#define DEBUG_UART_SHIFT 2
+
+volatile u8 *uart;
 
 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)
 {
 }
 
+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.
+ */
 static inline void arch_decomp_setup(void)
 {
-	volatile u8 *uart = (volatile u8 *)TEGRA_DEBUG_UART_BASE;
-	int shift = 2;
+	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;
+
+	/*
+	 * 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;
+	save_uart_address();
 	if (uart == NULL)
 		return;
 
-	uart[UART_LCR << shift] |= UART_LCR_DLAB;
-	uart[UART_DLL << shift] = 0x75;
-	uart[UART_DLM << shift] = 0x0;
-	uart[UART_LCR << shift] = 3;
+	chip = (apb_misc[0x804 / 4] >> 8) & 0xff;
+	if (chip == 0x20)
+		div = 0x0075;
+	else
+		div = 0x00dd;
+
+	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)

+ 76 - 0
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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/of.h>
+
+#include <mach/iomap.h>
+
+#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);
+}

+ 23 - 0
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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef __MACH_TEGRA_PMC_H
+#define __MACH_TEGRA_PMC_H
+
+void tegra_pmc_init(void);
+
+#endif

+ 1 - 1
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;
 }
 

+ 201 - 23
arch/arm/mach-tegra/tegra2_emc.c

@@ -16,14 +16,19 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/device.h>
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/io.h>
 #include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/tegra_emc.h>
 
 #include <mach/iomap.h>
 
 #include "tegra2_emc.h"
+#include "fuse.h"
 
 #ifdef CONFIG_TEGRA_EMC_SCALING_ENABLE
 static bool emc_enable = true;
@@ -32,18 +37,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 +102,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 +120,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 +131,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 +146,211 @@ 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(tegra_emc_table[i].regs[TEGRA_EMC_NUM_REGS - 1]);
+	emc_readl(pdata->tables[i].regs[TEGRA_EMC_NUM_REGS - 1]);
 
 	return 0;
 }
 
-void tegra_init_emc(const struct tegra_emc_table *table, int table_size)
+#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", &reg))
+			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) / 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;
+	dev_info(&pdev->dev, "no tables provided, using %ld kHz emc, "
+		 "%ld kHz mem\n", khz * 2, khz);
+
+	return pdata;
+}
+
+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;
+	}
+
+	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;
+	}
+
+	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,
+};
+
+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);

+ 4 - 7
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

+ 46 - 13
drivers/gpio/gpio-tegra.c

@@ -25,6 +25,7 @@
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/module.h>
+#include <linux/irqdomain.h>
 
 #include <asm/mach/irq.h>
 
@@ -74,9 +75,10 @@ struct tegra_gpio_bank {
 #endif
 };
 
-
+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)
 {
@@ -139,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 TEGRA_GPIO_TO_IRQ(offset);
+	return irq_find_mapping(irq_domain, offset);
 }
 
 static struct gpio_chip tegra_gpio_chip = {
@@ -155,28 +157,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;
@@ -273,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++) {
@@ -296,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++) {
@@ -337,13 +339,44 @@ 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;
 
-	for (i = 0; i < ARRAY_SIZE(tegra_gpio_banks); i++) {
+	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 = 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);
 		if (!res) {
 			dev_err(&pdev->dev, "Missing IRQ resource\n");
@@ -380,8 +413,8 @@ 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);
+	for (gpio = 0; gpio < tegra_gpio_chip.ngpio; 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)];
@@ -393,7 +426,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);

+ 34 - 0
include/linux/platform_data/tegra_emc.h

@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * Author:
+ *	Colin Cross <ccross@android.com>
+ *	Olof Johansson <olof@lixom.net>
+ *
+ * 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