diff options
author | Nicolas Chauvet <kwizart@gmail.com> | 2014-06-26 17:13:37 +0200 |
---|---|---|
committer | Nicolas Chauvet <kwizart@gmail.com> | 2014-07-07 16:21:19 +0200 |
commit | a5fca2b83cd4dcf2d94c717aaa17897d85516be3 (patch) | |
tree | 8193bd815ccf8f233fe419a15a0ef24fe7e3d99b | |
parent | 93b95b9dfa283ccd1062a997d550b260bbb4a51d (diff) | |
download | kernel-a5fca2b83cd4dcf2d94c717aaa17897d85516be3.tar.gz kernel-a5fca2b83cd4dcf2d94c717aaa17897d85516be3.tar.xz kernel-a5fca2b83cd4dcf2d94c717aaa17897d85516be3.zip |
Add tegra-bp-next-3.17.patch
-rw-r--r-- | tegra-bp-next-3.17.patch | 5510 |
1 files changed, 5510 insertions, 0 deletions
diff --git a/tegra-bp-next-3.17.patch b/tegra-bp-next-3.17.patch new file mode 100644 index 00000000..946f8707 --- /dev/null +++ b/tegra-bp-next-3.17.patch @@ -0,0 +1,5510 @@ +diff --git a/Documentation/ABI/testing/sysfs-driver-tegra-fuse b/Documentation/ABI/testing/sysfs-driver-tegra-fuse +new file mode 100644 +index 0000000..69f5af6 +--- /dev/null ++++ b/Documentation/ABI/testing/sysfs-driver-tegra-fuse +@@ -0,0 +1,11 @@ ++What: /sys/devices/*/<our-device>/fuse ++Date: February 2014 ++Contact: Peter De Schrijver <pdeschrijver@nvidia.com> ++Description: read-only access to the efuses on Tegra20, Tegra30, Tegra114 ++ and Tegra124 SoC's from NVIDIA. The efuses contain write once ++ data programmed at the factory. The data is layed out in 32bit ++ words in LSB first format. Each bit represents a single value ++ as decoded from the fuse registers. Bits order/assignment ++ exactly matches the HW registers, including any unused bits. ++Users: any user space application which wants to read the efuses on ++ Tegra SoC's +diff --git a/Documentation/devicetree/bindings/arm/tegra.txt b/Documentation/devicetree/bindings/arm/tegra.txt +index 558ed4b..73278c6 100644 +--- a/Documentation/devicetree/bindings/arm/tegra.txt ++++ b/Documentation/devicetree/bindings/arm/tegra.txt +@@ -30,6 +30,8 @@ board-specific compatible values: + nvidia,seaboard + nvidia,ventana + nvidia,whistler ++ toradex,apalis_t30 ++ toradex,apalis_t30-eval + toradex,colibri_t20-512 + toradex,iris + +diff --git a/Documentation/devicetree/bindings/fuse/nvidia,tegra20-fuse.txt b/Documentation/devicetree/bindings/fuse/nvidia,tegra20-fuse.txt +new file mode 100644 +index 0000000..d8c98c7 +--- /dev/null ++++ b/Documentation/devicetree/bindings/fuse/nvidia,tegra20-fuse.txt +@@ -0,0 +1,40 @@ ++NVIDIA Tegra20/Tegra30/Tegr114/Tegra124 fuse block. ++ ++Required properties: ++- compatible : should be: ++ "nvidia,tegra20-efuse" ++ "nvidia,tegra30-efuse" ++ "nvidia,tegra114-efuse" ++ "nvidia,tegra124-efuse" ++ Details: ++ nvidia,tegra20-efuse: Tegra20 requires using APB DMA to read the fuse data ++ due to a hardware bug. Tegra20 also lacks certain information which is ++ available in later generations such as fab code, lot code, wafer id,.. ++ nvidia,tegra30-efuse, nvidia,tegra114-efuse and nvidia,tegra124-efuse: ++ The differences between these SoCs are the size of the efuse array, ++ the location of the spare (OEM programmable) bits and the location of ++ the speedo data. ++- reg: Should contain 1 entry: the entry gives the physical address and length ++ of the fuse registers. ++- clocks: Must contain an entry for each entry in clock-names. ++ See ../clocks/clock-bindings.txt for details. ++- clock-names: Must include the following entries: ++ - fuse ++- resets: Must contain an entry for each entry in reset-names. ++ See ../reset/reset.txt for details. ++- reset-names: Must include the following entries: ++ - fuse ++ ++Example: ++ ++ fuse@7000f800 { ++ compatible = "nvidia,tegra20-efuse"; ++ reg = <0x7000F800 0x400>, ++ <0x70000000 0x400>; ++ clocks = <&tegra_car TEGRA20_CLK_FUSE>; ++ clock-names = "fuse"; ++ resets = <&tegra_car 39>; ++ reset-names = "fuse"; ++ }; ++ ++ +diff --git a/Documentation/devicetree/bindings/misc/nvidia,tegra20-apbmisc.txt b/Documentation/devicetree/bindings/misc/nvidia,tegra20-apbmisc.txt +new file mode 100644 +index 0000000..b97b8be +--- /dev/null ++++ b/Documentation/devicetree/bindings/misc/nvidia,tegra20-apbmisc.txt +@@ -0,0 +1,13 @@ ++NVIDIA Tegra20/Tegra30/Tegr114/Tegra124 apbmisc block ++ ++Required properties: ++- compatible : should be: ++ "nvidia,tegra20-apbmisc" ++ "nvidia,tegra30-apbmisc" ++ "nvidia,tegra114-apbmisc" ++ "nvidia,tegra124-apbmisc" ++- reg: Should contain 2 entries: the first entry gives the physical address ++ and length of the registers which contain revision and debug features. ++ The second entry gives the physical address and length of the ++ registers indicating the strapping options. ++ +diff --git a/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt b/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt +index c300391..0823362 100644 +--- a/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt ++++ b/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt +@@ -14,9 +14,6 @@ Required properties: + - interrupt-names: Must include the following entries: + "intr": The Tegra interrupt that is asserted for controller interrupts + "msi": The Tegra interrupt that is asserted when an MSI is received +-- pex-clk-supply: Supply voltage for internal reference clock +-- vdd-supply: Power supply for controller (1.05V) +-- avdd-supply: Power supply for controller (1.05V) (not required for Tegra20) + - bus-range: Range of bus numbers associated with this controller + - #address-cells: Address representation for root ports (must be 3) + - cell 0 specifies the bus and device numbers of the root port: +@@ -60,6 +57,33 @@ Required properties: + - afi + - pcie_x + ++Power supplies for Tegra20: ++- avdd-pex-supply: Power supply for analog PCIe logic. Must supply 1.05 V. ++- vdd-pex-supply: Power supply for digital PCIe I/O. Must supply 1.05 V. ++- avdd-pex-pll-supply: Power supply for dedicated (internal) PCIe PLL. Must ++ supply 1.05 V. ++- avdd-plle-supply: Power supply for PLLE, which is shared with SATA. Must ++ supply 1.05 V. ++- vddio-pex-clk-supply: Power supply for PCIe clock. Must supply 3.3 V. ++ ++Power supplies for Tegra30: ++- Required: ++ - avdd-pex-pll-supply: Power supply for dedicated (internal) PCIe PLL. Must ++ supply 1.05 V. ++ - avdd-plle-supply: Power supply for PLLE, which is shared with SATA. Must ++ supply 1.05 V. ++ - vddio-pex-ctl-supply: Power supply for PCIe control I/O partition. Must ++ supply 1.8 V. ++ - hvdd-pex-supply: High-voltage supply for PCIe I/O and PCIe output clocks. ++ Must supply 3.3 V. ++- Optional: ++ - If lanes 0 to 3 are used: ++ - avdd-pexa-supply: Power supply for analog PCIe logic. Must supply 1.05 V. ++ - vdd-pexa-supply: Power supply for digital PCIe I/O. Must supply 1.05 V. ++ - If lanes 4 or 5 are used: ++ - avdd-pexb-supply: Power supply for analog PCIe logic. Must supply 1.05 V. ++ - vdd-pexb-supply: Power supply for digital PCIe I/O. Must supply 1.05 V. ++ + Root ports are defined as subnodes of the PCIe controller node. + + Required properties: +diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile +index 5986ff6..906fb67 100644 +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -390,6 +390,7 @@ dtb-$(CONFIG_ARCH_TEGRA) += tegra20-harmony.dtb \ + tegra20-trimslice.dtb \ + tegra20-ventana.dtb \ + tegra20-whistler.dtb \ ++ tegra30-apalis-eval.dtb \ + tegra30-beaver.dtb \ + tegra30-cardhu-a02.dtb \ + tegra30-cardhu-a04.dtb \ +diff --git a/arch/arm/boot/dts/cros-ec-keyboard.dtsi b/arch/arm/boot/dts/cros-ec-keyboard.dtsi +new file mode 100644 +index 0000000..9c7fb0a +--- /dev/null ++++ b/arch/arm/boot/dts/cros-ec-keyboard.dtsi +@@ -0,0 +1,105 @@ ++/* ++ * Keyboard dts fragment for devices that use cros-ec-keyboard ++ * ++ * Copyright (c) 2014 Google, Inc ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++*/ ++ ++#include <dt-bindings/input/input.h> ++ ++&cros_ec { ++ keyboard-controller { ++ compatible = "google,cros-ec-keyb"; ++ keypad,num-rows = <8>; ++ keypad,num-columns = <13>; ++ google,needs-ghost-filter; ++ ++ linux,keymap = < ++ MATRIX_KEY(0x00, 0x01, KEY_LEFTMETA) ++ MATRIX_KEY(0x00, 0x02, KEY_F1) ++ MATRIX_KEY(0x00, 0x03, KEY_B) ++ MATRIX_KEY(0x00, 0x04, KEY_F10) ++ MATRIX_KEY(0x00, 0x06, KEY_N) ++ MATRIX_KEY(0x00, 0x08, KEY_EQUAL) ++ MATRIX_KEY(0x00, 0x0a, KEY_RIGHTALT) ++ ++ MATRIX_KEY(0x01, 0x01, KEY_ESC) ++ MATRIX_KEY(0x01, 0x02, KEY_F4) ++ MATRIX_KEY(0x01, 0x03, KEY_G) ++ MATRIX_KEY(0x01, 0x04, KEY_F7) ++ MATRIX_KEY(0x01, 0x06, KEY_H) ++ MATRIX_KEY(0x01, 0x08, KEY_APOSTROPHE) ++ MATRIX_KEY(0x01, 0x09, KEY_F9) ++ MATRIX_KEY(0x01, 0x0b, KEY_BACKSPACE) ++ ++ MATRIX_KEY(0x02, 0x00, KEY_LEFTCTRL) ++ MATRIX_KEY(0x02, 0x01, KEY_TAB) ++ MATRIX_KEY(0x02, 0x02, KEY_F3) ++ MATRIX_KEY(0x02, 0x03, KEY_T) ++ MATRIX_KEY(0x02, 0x04, KEY_F6) ++ MATRIX_KEY(0x02, 0x05, KEY_RIGHTBRACE) ++ MATRIX_KEY(0x02, 0x06, KEY_Y) ++ MATRIX_KEY(0x02, 0x07, KEY_102ND) ++ MATRIX_KEY(0x02, 0x08, KEY_LEFTBRACE) ++ MATRIX_KEY(0x02, 0x09, KEY_F8) ++ ++ MATRIX_KEY(0x03, 0x01, KEY_GRAVE) ++ MATRIX_KEY(0x03, 0x02, KEY_F2) ++ MATRIX_KEY(0x03, 0x03, KEY_5) ++ MATRIX_KEY(0x03, 0x04, KEY_F5) ++ MATRIX_KEY(0x03, 0x06, KEY_6) ++ MATRIX_KEY(0x03, 0x08, KEY_MINUS) ++ MATRIX_KEY(0x03, 0x0b, KEY_BACKSLASH) ++ ++ MATRIX_KEY(0x04, 0x00, KEY_RIGHTCTRL) ++ MATRIX_KEY(0x04, 0x01, KEY_A) ++ MATRIX_KEY(0x04, 0x02, KEY_D) ++ MATRIX_KEY(0x04, 0x03, KEY_F) ++ MATRIX_KEY(0x04, 0x04, KEY_S) ++ MATRIX_KEY(0x04, 0x05, KEY_K) ++ MATRIX_KEY(0x04, 0x06, KEY_J) ++ MATRIX_KEY(0x04, 0x08, KEY_SEMICOLON) ++ MATRIX_KEY(0x04, 0x09, KEY_L) ++ MATRIX_KEY(0x04, 0x0a, KEY_BACKSLASH) ++ MATRIX_KEY(0x04, 0x0b, KEY_ENTER) ++ ++ MATRIX_KEY(0x05, 0x01, KEY_Z) ++ MATRIX_KEY(0x05, 0x02, KEY_C) ++ MATRIX_KEY(0x05, 0x03, KEY_V) ++ MATRIX_KEY(0x05, 0x04, KEY_X) ++ MATRIX_KEY(0x05, 0x05, KEY_COMMA) ++ MATRIX_KEY(0x05, 0x06, KEY_M) ++ MATRIX_KEY(0x05, 0x07, KEY_LEFTSHIFT) ++ MATRIX_KEY(0x05, 0x08, KEY_SLASH) ++ MATRIX_KEY(0x05, 0x09, KEY_DOT) ++ MATRIX_KEY(0x05, 0x0b, KEY_SPACE) ++ ++ MATRIX_KEY(0x06, 0x01, KEY_1) ++ MATRIX_KEY(0x06, 0x02, KEY_3) ++ MATRIX_KEY(0x06, 0x03, KEY_4) ++ MATRIX_KEY(0x06, 0x04, KEY_2) ++ MATRIX_KEY(0x06, 0x05, KEY_8) ++ MATRIX_KEY(0x06, 0x06, KEY_7) ++ MATRIX_KEY(0x06, 0x08, KEY_0) ++ MATRIX_KEY(0x06, 0x09, KEY_9) ++ MATRIX_KEY(0x06, 0x0a, KEY_LEFTALT) ++ MATRIX_KEY(0x06, 0x0b, KEY_DOWN) ++ MATRIX_KEY(0x06, 0x0c, KEY_RIGHT) ++ ++ MATRIX_KEY(0x07, 0x01, KEY_Q) ++ MATRIX_KEY(0x07, 0x02, KEY_E) ++ MATRIX_KEY(0x07, 0x03, KEY_R) ++ MATRIX_KEY(0x07, 0x04, KEY_W) ++ MATRIX_KEY(0x07, 0x05, KEY_I) ++ MATRIX_KEY(0x07, 0x06, KEY_U) ++ MATRIX_KEY(0x07, 0x07, KEY_RIGHTSHIFT) ++ MATRIX_KEY(0x07, 0x08, KEY_P) ++ MATRIX_KEY(0x07, 0x09, KEY_O) ++ MATRIX_KEY(0x07, 0x0b, KEY_UP) ++ MATRIX_KEY(0x07, 0x0c, KEY_LEFT) ++ >; ++ }; ++}; +diff --git a/arch/arm/boot/dts/exynos5250-snow.dts b/arch/arm/boot/dts/exynos5250-snow.dts +index 079fdf9..7bd2df1 100644 +--- a/arch/arm/boot/dts/exynos5250-snow.dts ++++ b/arch/arm/boot/dts/exynos5250-snow.dts +@@ -137,7 +137,7 @@ + sbs,poll-retry-count = <1>; + }; + +- ec: embedded-controller { ++ cros_ec: embedded-controller { + compatible = "google,cros-ec-i2c"; + reg = <0x1e>; + interrupts = <6 0>; +@@ -145,95 +145,6 @@ + pinctrl-names = "default"; + pinctrl-0 = <&ec_irq>; + wakeup-source; +- +- keyboard-controller { +- compatible = "google,cros-ec-keyb"; +- keypad,num-rows = <8>; +- keypad,num-columns = <13>; +- google,needs-ghost-filter; +- linux,keymap = <0x0001007d /* L_META */ +- 0x0002003b /* F1 */ +- 0x00030030 /* B */ +- 0x00040044 /* F10 */ +- 0x00060031 /* N */ +- 0x0008000d /* = */ +- 0x000a0064 /* R_ALT */ +- +- 0x01010001 /* ESC */ +- 0x0102003e /* F4 */ +- 0x01030022 /* G */ +- 0x01040041 /* F7 */ +- 0x01060023 /* H */ +- 0x01080028 /* ' */ +- 0x01090043 /* F9 */ +- 0x010b000e /* BKSPACE */ +- +- 0x0200001d /* L_CTRL */ +- 0x0201000f /* TAB */ +- 0x0202003d /* F3 */ +- 0x02030014 /* T */ +- 0x02040040 /* F6 */ +- 0x0205001b /* ] */ +- 0x02060015 /* Y */ +- 0x02070056 /* 102ND */ +- 0x0208001a /* [ */ +- 0x02090042 /* F8 */ +- +- 0x03010029 /* GRAVE */ +- 0x0302003c /* F2 */ +- 0x03030006 /* 5 */ +- 0x0304003f /* F5 */ +- 0x03060007 /* 6 */ +- 0x0308000c /* - */ +- 0x030b002b /* \ */ +- +- 0x04000061 /* R_CTRL */ +- 0x0401001e /* A */ +- 0x04020020 /* D */ +- 0x04030021 /* F */ +- 0x0404001f /* S */ +- 0x04050025 /* K */ +- 0x04060024 /* J */ +- 0x04080027 /* ; */ +- 0x04090026 /* L */ +- 0x040a002b /* \ */ +- 0x040b001c /* ENTER */ +- +- 0x0501002c /* Z */ +- 0x0502002e /* C */ +- 0x0503002f /* V */ +- 0x0504002d /* X */ +- 0x05050033 /* , */ +- 0x05060032 /* M */ +- 0x0507002a /* L_SHIFT */ +- 0x05080035 /* / */ +- 0x05090034 /* . */ +- 0x050B0039 /* SPACE */ +- +- 0x06010002 /* 1 */ +- 0x06020004 /* 3 */ +- 0x06030005 /* 4 */ +- 0x06040003 /* 2 */ +- 0x06050009 /* 8 */ +- 0x06060008 /* 7 */ +- 0x0608000b /* 0 */ +- 0x0609000a /* 9 */ +- 0x060a0038 /* L_ALT */ +- 0x060b006c /* DOWN */ +- 0x060c006a /* RIGHT */ +- +- 0x07010010 /* Q */ +- 0x07020012 /* E */ +- 0x07030013 /* R */ +- 0x07040011 /* W */ +- 0x07050017 /* I */ +- 0x07060016 /* U */ +- 0x07070036 /* R_SHIFT */ +- 0x07080019 /* P */ +- 0x07090018 /* O */ +- 0x070b0067 /* UP */ +- 0x070c0069>; /* LEFT */ +- }; + }; + + power-regulator { +@@ -431,3 +342,5 @@ + }; + }; + }; ++ ++#include "cros-ec-keyboard.dtsi" +diff --git a/arch/arm/boot/dts/tegra114.dtsi b/arch/arm/boot/dts/tegra114.dtsi +index fdc559a..335a1d8 100644 +--- a/arch/arm/boot/dts/tegra114.dtsi ++++ b/arch/arm/boot/dts/tegra114.dtsi +@@ -220,6 +220,12 @@ + interrupt-controller; + }; + ++ apbmisc@70000800 { ++ compatible = "nvidia,tegra114-apbmisc", "nvidia,tegra20-apbmisc"; ++ reg = <0x70000800 0x64 /* Chip revision */ ++ 0x70000008 0x04>; /* Strapping options */ ++ }; ++ + pinmux: pinmux@70000868 { + compatible = "nvidia,tegra114-pinmux"; + reg = <0x70000868 0x148 /* Pad control registers */ +@@ -485,6 +491,15 @@ + clock-names = "pclk", "clk32k_in"; + }; + ++ fuse@7000f800 { ++ compatible = "nvidia,tegra114-efuse"; ++ reg = <0x7000f800 0x400>; ++ clocks = <&tegra_car TEGRA114_CLK_FUSE>; ++ clock-names = "fuse"; ++ resets = <&tegra_car 39>; ++ reset-names = "fuse"; ++ }; ++ + iommu@70019010 { + compatible = "nvidia,tegra114-smmu", "nvidia,tegra30-smmu"; + reg = <0x70019010 0x02c +diff --git a/arch/arm/boot/dts/tegra124-jetson-tk1.dts b/arch/arm/boot/dts/tegra124-jetson-tk1.dts +index e31fb61..16082c0 100644 +--- a/arch/arm/boot/dts/tegra124-jetson-tk1.dts ++++ b/arch/arm/boot/dts/tegra124-jetson-tk1.dts +@@ -1633,6 +1633,7 @@ + sdhci@0,700b0600 { + status = "okay"; + bus-width = <8>; ++ non-removable; + }; + + ahub@0,70300000 { +diff --git a/arch/arm/boot/dts/tegra124-venice2.dts b/arch/arm/boot/dts/tegra124-venice2.dts +index f0bb842..f1a5bac 100644 +--- a/arch/arm/boot/dts/tegra124-venice2.dts ++++ b/arch/arm/boot/dts/tegra124-venice2.dts +@@ -816,7 +816,7 @@ + spi@0,7000d400 { + status = "okay"; + +- cros-ec@0 { ++ cros_ec: cros-ec@0 { + compatible = "google,cros-ec-spi"; + spi-max-frequency = <4000000>; + interrupt-parent = <&gpio>; +@@ -825,96 +825,30 @@ + + google,cros-ec-spi-msg-delay = <2000>; + +- cros-ec-keyb { +- compatible = "google,cros-ec-keyb"; +- keypad,num-rows = <8>; +- keypad,num-columns = <13>; +- google,needs-ghost-filter; +- +- linux,keymap = < +- MATRIX_KEY(0x00, 0x01, KEY_LEFTMETA) +- MATRIX_KEY(0x00, 0x02, KEY_F1) +- MATRIX_KEY(0x00, 0x03, KEY_B) +- MATRIX_KEY(0x00, 0x04, KEY_F10) +- MATRIX_KEY(0x00, 0x06, KEY_N) +- MATRIX_KEY(0x00, 0x08, KEY_EQUAL) +- MATRIX_KEY(0x00, 0x0a, KEY_RIGHTALT) +- +- MATRIX_KEY(0x01, 0x01, KEY_ESC) +- MATRIX_KEY(0x01, 0x02, KEY_F4) +- MATRIX_KEY(0x01, 0x03, KEY_G) +- MATRIX_KEY(0x01, 0x04, KEY_F7) +- MATRIX_KEY(0x01, 0x06, KEY_H) +- MATRIX_KEY(0x01, 0x08, KEY_APOSTROPHE) +- MATRIX_KEY(0x01, 0x09, KEY_F9) +- MATRIX_KEY(0x01, 0x0b, KEY_BACKSPACE) +- +- MATRIX_KEY(0x02, 0x00, KEY_LEFTCTRL) +- MATRIX_KEY(0x02, 0x01, KEY_TAB) +- MATRIX_KEY(0x02, 0x02, KEY_F3) +- MATRIX_KEY(0x02, 0x03, KEY_T) +- MATRIX_KEY(0x02, 0x04, KEY_F6) +- MATRIX_KEY(0x02, 0x05, KEY_RIGHTBRACE) +- MATRIX_KEY(0x02, 0x06, KEY_Y) +- MATRIX_KEY(0x02, 0x07, KEY_102ND) +- MATRIX_KEY(0x02, 0x08, KEY_LEFTBRACE) +- MATRIX_KEY(0x02, 0x09, KEY_F8) +- +- MATRIX_KEY(0x03, 0x01, KEY_GRAVE) +- MATRIX_KEY(0x03, 0x02, KEY_F2) +- MATRIX_KEY(0x03, 0x03, KEY_5) +- MATRIX_KEY(0x03, 0x04, KEY_F5) +- MATRIX_KEY(0x03, 0x06, KEY_6) +- MATRIX_KEY(0x03, 0x08, KEY_MINUS) +- MATRIX_KEY(0x03, 0x0b, KEY_BACKSLASH) +- +- MATRIX_KEY(0x04, 0x00, KEY_RIGHTCTRL) +- MATRIX_KEY(0x04, 0x01, KEY_A) +- MATRIX_KEY(0x04, 0x02, KEY_D) +- MATRIX_KEY(0x04, 0x03, KEY_F) +- MATRIX_KEY(0x04, 0x04, KEY_S) +- MATRIX_KEY(0x04, 0x05, KEY_K) +- MATRIX_KEY(0x04, 0x06, KEY_J) +- MATRIX_KEY(0x04, 0x08, KEY_SEMICOLON) +- MATRIX_KEY(0x04, 0x09, KEY_L) +- MATRIX_KEY(0x04, 0x0a, KEY_BACKSLASH) +- MATRIX_KEY(0x04, 0x0b, KEY_ENTER) +- +- MATRIX_KEY(0x05, 0x01, KEY_Z) +- MATRIX_KEY(0x05, 0x02, KEY_C) +- MATRIX_KEY(0x05, 0x03, KEY_V) +- MATRIX_KEY(0x05, 0x04, KEY_X) +- MATRIX_KEY(0x05, 0x05, KEY_COMMA) +- MATRIX_KEY(0x05, 0x06, KEY_M) +- MATRIX_KEY(0x05, 0x07, KEY_LEFTSHIFT) +- MATRIX_KEY(0x05, 0x08, KEY_SLASH) +- MATRIX_KEY(0x05, 0x09, KEY_DOT) +- MATRIX_KEY(0x05, 0x0b, KEY_SPACE) +- +- MATRIX_KEY(0x06, 0x01, KEY_1) +- MATRIX_KEY(0x06, 0x02, KEY_3) +- MATRIX_KEY(0x06, 0x03, KEY_4) +- MATRIX_KEY(0x06, 0x04, KEY_2) +- MATRIX_KEY(0x06, 0x05, KEY_8) +- MATRIX_KEY(0x06, 0x06, KEY_7) +- MATRIX_KEY(0x06, 0x08, KEY_0) +- MATRIX_KEY(0x06, 0x09, KEY_9) +- MATRIX_KEY(0x06, 0x0a, KEY_LEFTALT) +- MATRIX_KEY(0x06, 0x0b, KEY_DOWN) +- MATRIX_KEY(0x06, 0x0c, KEY_RIGHT) +- +- MATRIX_KEY(0x07, 0x01, KEY_Q) +- MATRIX_KEY(0x07, 0x02, KEY_E) +- MATRIX_KEY(0x07, 0x03, KEY_R) +- MATRIX_KEY(0x07, 0x04, KEY_W) +- MATRIX_KEY(0x07, 0x05, KEY_I) +- MATRIX_KEY(0x07, 0x06, KEY_U) +- MATRIX_KEY(0x07, 0x07, KEY_RIGHTSHIFT) +- MATRIX_KEY(0x07, 0x08, KEY_P) +- MATRIX_KEY(0x07, 0x09, KEY_O) +- MATRIX_KEY(0x07, 0x0b, KEY_UP) +- MATRIX_KEY(0x07, 0x0c, KEY_LEFT) +- >; ++ i2c-tunnel { ++ compatible = "google,cros-ec-i2c-tunnel"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ google,remote-bus = <0>; ++ ++ charger: bq24735@9 { ++ compatible = "ti,bq24735"; ++ reg = <0x9>; ++ interrupt-parent = <&gpio>; ++ interrupts = <TEGRA_GPIO(J, 0) ++ GPIO_ACTIVE_HIGH>; ++ ti,ac-detect-gpios = <&gpio ++ TEGRA_GPIO(J, 0) ++ GPIO_ACTIVE_HIGH>; ++ }; ++ ++ battery: sbs-battery@b { ++ compatible = "sbs,sbs-battery"; ++ reg = <0xb>; ++ sbs,i2c-retry-count = <2>; ++ sbs,poll-retry-count = <1>; ++ }; + }; + }; + }; +@@ -940,6 +874,10 @@ + nvidia,sys-clock-req-active-high; + }; + ++ hda@0,70030000 { ++ status = "okay"; ++ }; ++ + sdhci@0,700b0400 { + cd-gpios = <&gpio TEGRA_GPIO(V, 2) GPIO_ACTIVE_HIGH>; + power-gpios = <&gpio TEGRA_GPIO(R, 0) GPIO_ACTIVE_HIGH>; +@@ -1205,3 +1143,5 @@ + clock-names = "pll_a", "pll_a_out0", "mclk"; + }; + }; ++ ++#include "cros-ec-keyboard.dtsi" +diff --git a/arch/arm/boot/dts/tegra124.dtsi b/arch/arm/boot/dts/tegra124.dtsi +index 6e6bc4e..d675186 100644 +--- a/arch/arm/boot/dts/tegra124.dtsi ++++ b/arch/arm/boot/dts/tegra124.dtsi +@@ -179,6 +179,12 @@ + #dma-cells = <1>; + }; + ++ apbmisc@0,70000800 { ++ compatible = "nvidia,tegra124-apbmisc", "nvidia,tegra20-apbmisc"; ++ reg = <0x0 0x70000800 0x0 0x64>, /* Chip revision */ ++ <0x0 0x7000E864 0x0 0x04>; /* Strapping options */ ++ }; ++ + pinmux: pinmux@0,70000868 { + compatible = "nvidia,tegra124-pinmux"; + reg = <0x0 0x70000868 0x0 0x164>, /* Pad control registers */ +@@ -449,6 +455,30 @@ + clock-names = "pclk", "clk32k_in"; + }; + ++ fuse@0,7000f800 { ++ compatible = "nvidia,tegra124-efuse"; ++ reg = <0x0 0x7000f800 0x0 0x400>; ++ clocks = <&tegra_car TEGRA124_CLK_FUSE>; ++ clock-names = "fuse"; ++ resets = <&tegra_car 39>; ++ reset-names = "fuse"; ++ }; ++ ++ hda@0,70030000 { ++ compatible = "nvidia,tegra124-hda", "nvidia,tegra30-hda"; ++ reg = <0x0 0x70030000 0x0 0x10000>; ++ interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&tegra_car TEGRA124_CLK_HDA>, ++ <&tegra_car TEGRA124_CLK_HDA2HDMI>, ++ <&tegra_car TEGRA124_CLK_HDA2CODEC_2X>; ++ clock-names = "hda", "hda2hdmi", "hdacodec_2x"; ++ resets = <&tegra_car 125>, /* hda */ ++ <&tegra_car 128>, /* hda2hdmi */ ++ <&tegra_car 111>; /* hda2codec_2x */ ++ reset-names = "hda", "hda2hdmi", "hdacodec_2x"; ++ status = "disabled"; ++ }; ++ + sdhci@0,700b0000 { + compatible = "nvidia,tegra124-sdhci"; + reg = <0x0 0x700b0000 0x0 0x200>; +diff --git a/arch/arm/boot/dts/tegra20-harmony.dts b/arch/arm/boot/dts/tegra20-harmony.dts +index f45aad6..a37279a 100644 +--- a/arch/arm/boot/dts/tegra20-harmony.dts ++++ b/arch/arm/boot/dts/tegra20-harmony.dts +@@ -562,10 +562,14 @@ + }; + + pcie-controller@80003000 { +- pex-clk-supply = <&pci_clk_reg>; +- vdd-supply = <&pci_vdd_reg>; + status = "okay"; + ++ avdd-pex-supply = <&pci_vdd_reg>; ++ vdd-pex-supply = <&pci_vdd_reg>; ++ avdd-pex-pll-supply = <&pci_vdd_reg>; ++ avdd-plle-supply = <&pci_vdd_reg>; ++ vddio-pex-clk-supply = <&pci_clk_reg>; ++ + pci@1,0 { + status = "okay"; + }; +diff --git a/arch/arm/boot/dts/tegra20-medcom-wide.dts b/arch/arm/boot/dts/tegra20-medcom-wide.dts +index 6d3a4cb..1b7c56b 100644 +--- a/arch/arm/boot/dts/tegra20-medcom-wide.dts ++++ b/arch/arm/boot/dts/tegra20-medcom-wide.dts +@@ -10,6 +10,15 @@ + status = "okay"; + }; + ++ host1x@50000000 { ++ dc@54200000 { ++ rgb { ++ status = "okay"; ++ nvidia,panel = <&panel>; ++ }; ++ }; ++ }; ++ + i2c@7000c000 { + wm8903: wm8903@1a { + compatible = "wlf,wm8903"; +@@ -30,7 +39,7 @@ + }; + }; + +- backlight { ++ backlight: backlight { + compatible = "pwm-backlight"; + pwms = <&pwm 0 5000000>; + +@@ -38,6 +47,15 @@ + default-brightness-level = <6>; + }; + ++ panel: panel { ++ compatible = "innolux,n156bge-l21", "simple-panel"; ++ ++ power-supply = <&vdd_1v8_reg>, <&vdd_3v3_reg>; ++ enable-gpios = <&gpio TEGRA_GPIO(B, 2) GPIO_ACTIVE_HIGH>; ++ ++ backlight = <&backlight>; ++ }; ++ + sound { + compatible = "ad,tegra-audio-wm8903-medcom-wide", + "nvidia,tegra-audio-wm8903"; +@@ -64,4 +82,45 @@ + <&tegra_car TEGRA20_CLK_CDEV1>; + clock-names = "pll_a", "pll_a_out0", "mclk"; + }; ++ ++ regulators { ++ vcc_24v_reg: regulator@100 { ++ compatible = "regulator-fixed"; ++ reg = <100>; ++ regulator-name = "vcc_24v"; ++ regulator-min-microvolt = <24000000>; ++ regulator-max-microvolt = <24000000>; ++ regulator-always-on; ++ }; ++ ++ vdd_5v0_reg: regulator@101 { ++ compatible = "regulator-fixed"; ++ reg = <101>; ++ regulator-name = "vdd_5v0"; ++ vin-supply = <&vcc_24v_reg>; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ regulator-always-on; ++ }; ++ ++ vdd_3v3_reg: regulator@102 { ++ compatible = "regulator-fixed"; ++ reg = <102>; ++ regulator-name = "vdd_3v3"; ++ vin-supply = <&vcc_24v_reg>; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ vdd_1v8_reg: regulator@103 { ++ compatible = "regulator-fixed"; ++ reg = <103>; ++ regulator-name = "vdd_1v8"; ++ vin-supply = <&vdd_3v3_reg>; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-always-on; ++ }; ++ }; + }; +diff --git a/arch/arm/boot/dts/tegra20-plutux.dts b/arch/arm/boot/dts/tegra20-plutux.dts +index 29051a2..a10b415 100644 +--- a/arch/arm/boot/dts/tegra20-plutux.dts ++++ b/arch/arm/boot/dts/tegra20-plutux.dts +@@ -58,4 +58,45 @@ + <&tegra_car TEGRA20_CLK_CDEV1>; + clock-names = "pll_a", "pll_a_out0", "mclk"; + }; ++ ++ regulators { ++ vcc_24v_reg: regulator@100 { ++ compatible = "regulator-fixed"; ++ reg = <100>; ++ regulator-name = "vcc_24v"; ++ regulator-min-microvolt = <24000000>; ++ regulator-max-microvolt = <24000000>; ++ regulator-always-on; ++ }; ++ ++ vdd_5v0_reg: regulator@101 { ++ compatible = "regulator-fixed"; ++ reg = <101>; ++ regulator-name = "vdd_5v0"; ++ vin-supply = <&vcc_24v_reg>; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ regulator-always-on; ++ }; ++ ++ vdd_3v3_reg: regulator@102 { ++ compatible = "regulator-fixed"; ++ reg = <102>; ++ regulator-name = "vdd_3v3"; ++ vin-supply = <&vcc_24v_reg>; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ vdd_1v8_reg: regulator@103 { ++ compatible = "regulator-fixed"; ++ reg = <103>; ++ regulator-name = "vdd_1v8"; ++ vin-supply = <&vdd_3v3_reg>; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-always-on; ++ }; ++ }; + }; +diff --git a/arch/arm/boot/dts/tegra20-tamonten.dtsi b/arch/arm/boot/dts/tegra20-tamonten.dtsi +index a1b0d96..80e7d38 100644 +--- a/arch/arm/boot/dts/tegra20-tamonten.dtsi ++++ b/arch/arm/boot/dts/tegra20-tamonten.dtsi +@@ -334,6 +334,7 @@ + #gpio-cells = <2>; + gpio-controller; + ++ /* vdd_5v0_reg must be provided by the base board */ + sys-supply = <&vdd_5v0_reg>; + vin-sm0-supply = <&sys_reg>; + vin-sm1-supply = <&sys_reg>; +@@ -473,8 +474,11 @@ + }; + + pcie-controller@80003000 { +- pex-clk-supply = <&pci_clk_reg>; +- vdd-supply = <&pci_vdd_reg>; ++ avdd-pex-supply = <&pci_vdd_reg>; ++ vdd-pex-supply = <&pci_vdd_reg>; ++ avdd-pex-pll-supply = <&pci_vdd_reg>; ++ avdd-plle-supply = <&pci_vdd_reg>; ++ vddio-pex-clk-supply = <&pci_clk_reg>; + }; + + usb@c5008000 { +@@ -511,15 +515,6 @@ + #address-cells = <1>; + #size-cells = <0>; + +- vdd_5v0_reg: regulator@0 { +- compatible = "regulator-fixed"; +- reg = <0>; +- regulator-name = "vdd_5v0"; +- regulator-min-microvolt = <5000000>; +- regulator-max-microvolt = <5000000>; +- regulator-always-on; +- }; +- + pci_vdd_reg: regulator@1 { + compatible = "regulator-fixed"; + reg = <1>; +diff --git a/arch/arm/boot/dts/tegra20-tec.dts b/arch/arm/boot/dts/tegra20-tec.dts +index 890562c..c12d8be 100644 +--- a/arch/arm/boot/dts/tegra20-tec.dts ++++ b/arch/arm/boot/dts/tegra20-tec.dts +@@ -67,4 +67,45 @@ + <&tegra_car TEGRA20_CLK_CDEV1>; + clock-names = "pll_a", "pll_a_out0", "mclk"; + }; ++ ++ regulators { ++ vcc_24v_reg: regulator@100 { ++ compatible = "regulator-fixed"; ++ reg = <100>; ++ regulator-name = "vcc_24v"; ++ regulator-min-microvolt = <24000000>; ++ regulator-max-microvolt = <24000000>; ++ regulator-always-on; ++ }; ++ ++ vdd_5v0_reg: regulator@101 { ++ compatible = "regulator-fixed"; ++ reg = <101>; ++ regulator-name = "vdd_5v0"; ++ vin-supply = <&vcc_24v_reg>; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ regulator-always-on; ++ }; ++ ++ vdd_3v3_reg: regulator@102 { ++ compatible = "regulator-fixed"; ++ reg = <102>; ++ regulator-name = "vdd_3v3"; ++ vin-supply = <&vcc_24v_reg>; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ vdd_1v8_reg: regulator@103 { ++ compatible = "regulator-fixed"; ++ reg = <103>; ++ regulator-name = "vdd_1v8"; ++ vin-supply = <&vdd_3v3_reg>; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-always-on; ++ }; ++ }; + }; +diff --git a/arch/arm/boot/dts/tegra20-trimslice.dts b/arch/arm/boot/dts/tegra20-trimslice.dts +index 216fa6d..5ad8797 100644 +--- a/arch/arm/boot/dts/tegra20-trimslice.dts ++++ b/arch/arm/boot/dts/tegra20-trimslice.dts +@@ -318,8 +318,12 @@ + + pcie-controller@80003000 { + status = "okay"; +- pex-clk-supply = <&pci_clk_reg>; +- vdd-supply = <&pci_vdd_reg>; ++ ++ avdd-pex-supply = <&pci_vdd_reg>; ++ vdd-pex-supply = <&pci_vdd_reg>; ++ avdd-pex-pll-supply = <&pci_vdd_reg>; ++ avdd-plle-supply = <&pci_vdd_reg>; ++ vddio-pex-clk-supply = <&pci_clk_reg>; + + pci@1,0 { + status = "okay"; +diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi +index a7ddf70..243d84c 100644 +--- a/arch/arm/boot/dts/tegra20.dtsi ++++ b/arch/arm/boot/dts/tegra20.dtsi +@@ -236,6 +236,12 @@ + interrupt-controller; + }; + ++ apbmisc@70000800 { ++ compatible = "nvidia,tegra20-apbmisc"; ++ reg = <0x70000800 0x64 /* Chip revision */ ++ 0x70000008 0x04>; /* Strapping options */ ++ }; ++ + pinmux: pinmux@70000014 { + compatible = "nvidia,tegra20-pinmux"; + reg = <0x70000014 0x10 /* Tri-state registers */ +@@ -545,6 +551,15 @@ + #size-cells = <0>; + }; + ++ fuse@7000f800 { ++ compatible = "nvidia,tegra20-efuse"; ++ reg = <0x7000F800 0x400>; ++ clocks = <&tegra_car TEGRA20_CLK_FUSE>; ++ clock-names = "fuse"; ++ resets = <&tegra_car 39>; ++ reset-names = "fuse"; ++ }; ++ + pcie-controller@80003000 { + compatible = "nvidia,tegra20-pcie"; + device_type = "pci"; +diff --git a/arch/arm/boot/dts/tegra30-apalis-eval.dts b/arch/arm/boot/dts/tegra30-apalis-eval.dts +new file mode 100644 +index 0000000..9921433 +--- /dev/null ++++ b/arch/arm/boot/dts/tegra30-apalis-eval.dts +@@ -0,0 +1,260 @@ ++/dts-v1/; ++ ++#include <dt-bindings/input/input.h> ++#include "tegra30-apalis.dtsi" ++ ++/ { ++ model = "Toradex Apalis T30 on Apalis Evaluation Board"; ++ compatible = "toradex,apalis_t30-eval", "nvidia,tegra30"; ++ ++ aliases { ++ rtc0 = "/i2c@7000c000/rtc@68"; ++ rtc1 = "/i2c@7000d000/tps65911@2d"; ++ rtc2 = "/rtc@7000e000"; ++ }; ++ ++ pcie-controller@00003000 { ++ status = "okay"; ++ ++ pci@1,0 { ++ status = "okay"; ++ }; ++ ++ pci@2,0 { ++ status = "okay"; ++ }; ++ ++ pci@3,0 { ++ status = "okay"; ++ }; ++ }; ++ ++ host1x@50000000 { ++ dc@54200000 { ++ rgb { ++ status = "okay"; ++ nvidia,panel = <&panel>; ++ }; ++ }; ++ hdmi@54280000 { ++ status = "okay"; ++ }; ++ }; ++ ++ serial@70006000 { ++ status = "okay"; ++ }; ++ ++ serial@70006040 { ++ compatible = "nvidia,tegra30-hsuart"; ++ status = "okay"; ++ }; ++ ++ serial@70006200 { ++ compatible = "nvidia,tegra30-hsuart"; ++ status = "okay"; ++ }; ++ ++ serial@70006300 { ++ compatible = "nvidia,tegra30-hsuart"; ++ status = "okay"; ++ }; ++ ++ pwm@7000a000 { ++ status = "okay"; ++ }; ++ ++ /* ++ * GEN1_I2C: I2C1_SDA/SCL on MXM3 pin 209/211 (e.g. RTC on carrier ++ * board) ++ */ ++ i2c@7000c000 { ++ status = "okay"; ++ clock-frequency = <100000>; ++ ++ pcie-switch@58 { ++ compatible = "plx,pex8605"; ++ reg = <0x58>; ++ }; ++ ++ /* M41T0M6 real time clock on carrier board */ ++ rtc@68 { ++ compatible = "st,m41t00"; ++ reg = <0x68>; ++ }; ++ }; ++ ++ /* GEN2_I2C: unused */ ++ ++ /* ++ * CAM_I2C: I2C3_SDA/SCL on MXM3 pin 201/203 (e.g. camera sensor on ++ * carrier board) ++ */ ++ cami2c: i2c@7000c500 { ++ status = "okay"; ++ clock-frequency = <400000>; ++ }; ++ ++ /* DDC: I2C2_SDA/SCL on MXM3 pin 205/207 (e.g. display EDID) */ ++ hdmiddc: i2c@7000c700 { ++ status = "okay"; ++ }; ++ ++ /* SPI1: Apalis SPI1 */ ++ spi@7000d400 { ++ status = "okay"; ++ spi-max-frequency = <25000000>; ++ spidev0: spidev@1 { ++ compatible = "spidev"; ++ reg = <1>; ++ spi-max-frequency = <25000000>; ++ }; ++ }; ++ ++ /* SPI5: Apalis SPI2 */ ++ spi@7000dc00 { ++ status = "okay"; ++ spi-max-frequency = <25000000>; ++ spidev1: spidev@2 { ++ compatible = "spidev"; ++ reg = <2>; ++ spi-max-frequency = <25000000>; ++ }; ++ }; ++ ++ sd1: sdhci@78000000 { ++ status = "okay"; ++ bus-width = <4>; ++ /* SD1_CD# */ ++ cd-gpios = <&gpio TEGRA_GPIO(CC, 5) GPIO_ACTIVE_LOW>; ++ no-1-8-v; ++ }; ++ ++ mmc1: sdhci@78000400 { ++ status = "okay"; ++ bus-width = <8>; ++ /* MMC1_CD# */ ++ cd-gpios = <&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_LOW>; ++ no-1-8-v; ++ }; ++ ++ /* EHCI instance 0: USB1_DP/N -> USBO1_DP/N */ ++ usb@7d000000 { ++ status = "okay"; ++ }; ++ ++ usb-phy@7d000000 { ++ status = "okay"; ++ vbus-supply = <&usbo1_vbus_reg>; ++ }; ++ ++ /* EHCI instance 1: USB2_DP/N -> USBH2_DP/N */ ++ usb@7d004000 { ++ status = "okay"; ++ }; ++ ++ usb-phy@7d004000 { ++ status = "okay"; ++ vbus-supply = <&usbh_vbus_reg>; ++ }; ++ ++ /* EHCI instance 2: USB3_DP/N -> USBH3_DP/N */ ++ usb@7d008000 { ++ status = "okay"; ++ }; ++ ++ usb-phy@7d008000 { ++ status = "okay"; ++ vbus-supply = <&usbh_vbus_reg>; ++ }; ++ ++ backlight: backlight { ++ compatible = "pwm-backlight"; ++ ++ /* PWM0 */ ++ pwms = <&pwm 0 5000000>; ++ brightness-levels = <255 231 223 207 191 159 127 0>; ++ default-brightness-level = <6>; ++ /* BKL1_ON */ ++ enable-gpios = <&gpio TEGRA_GPIO(V, 2) GPIO_ACTIVE_HIGH>; ++ }; ++ ++ gpio-keys { ++ compatible = "gpio-keys"; ++ ++ power { ++ label = "Power"; ++ gpios = <&gpio TEGRA_GPIO(V, 1) GPIO_ACTIVE_LOW>; ++ linux,code = <KEY_POWER>; ++ debounce-interval = <10>; ++ gpio-key,wakeup; ++ }; ++ }; ++ ++ panel: panel { ++ /* ++ * edt,et057090dhu: EDT 5.7" LCD TFT ++ * edt,et070080dh6: EDT 7.0" LCD TFT ++ */ ++ compatible = "edt,et057090dhu", "simple-panel"; ++ ++ backlight = <&backlight>; ++ }; ++ ++ pwmleds { ++ compatible = "pwm-leds"; ++ ++ pwm1 { ++ label = "PWM1"; ++ pwms = <&pwm 3 19600>; ++ max-brightness = <255>; ++ }; ++ ++ pwm2 { ++ label = "PWM2"; ++ pwms = <&pwm 2 19600>; ++ max-brightness = <255>; ++ }; ++ ++ pwm3 { ++ label = "PWM3"; ++ pwms = <&pwm 1 19600>; ++ max-brightness = <255>; ++ }; ++ }; ++ ++ regulators { ++ sys_5v0_reg: regulator@1 { ++ compatible = "regulator-fixed"; ++ reg = <1>; ++ regulator-name = "5v0"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ regulator-always-on; ++ }; ++ ++ /* USBO1_EN */ ++ usbo1_vbus_reg: regulator@2 { ++ compatible = "regulator-fixed"; ++ reg = <2>; ++ regulator-name = "usbo1_vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ gpio = <&gpio TEGRA_GPIO(T, 5) GPIO_ACTIVE_HIGH>; ++ enable-active-high; ++ vin-supply = <&sys_5v0_reg>; ++ }; ++ ++ /* USBH_EN */ ++ usbh_vbus_reg: regulator@3 { ++ compatible = "regulator-fixed"; ++ reg = <3>; ++ regulator-name = "usbh_vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ gpio = <&gpio TEGRA_GPIO(DD, 1) GPIO_ACTIVE_HIGH>; ++ enable-active-high; ++ vin-supply = <&sys_5v0_reg>; ++ }; ++ }; ++}; +diff --git a/arch/arm/boot/dts/tegra30-apalis.dtsi b/arch/arm/boot/dts/tegra30-apalis.dtsi +new file mode 100644 +index 0000000..8adaa78 +--- /dev/null ++++ b/arch/arm/boot/dts/tegra30-apalis.dtsi +@@ -0,0 +1,678 @@ ++#include "tegra30.dtsi" ++ ++/* ++ * Toradex Apalis T30 Device Tree ++ * Compatible for Revisions 1GB: V1.0A; 2GB: V1.0B, V1.0C ++ */ ++/ { ++ model = "Toradex Apalis T30"; ++ compatible = "toradex,apalis_t30", "nvidia,tegra30"; ++ ++ pcie-controller@00003000 { ++ avdd-pexa-supply = <&vdd2_reg>; ++ vdd-pexa-supply = <&vdd2_reg>; ++ avdd-pexb-supply = <&vdd2_reg>; ++ vdd-pexb-supply = <&vdd2_reg>; ++ avdd-pex-pll-supply = <&vdd2_reg>; ++ avdd-plle-supply = <&ldo6_reg>; ++ vddio-pex-ctl-supply = <&sys_3v3_reg>; ++ hvdd-pex-supply = <&sys_3v3_reg>; ++ ++ pci@1,0 { ++ nvidia,num-lanes = <4>; ++ }; ++ ++ pci@2,0 { ++ nvidia,num-lanes = <1>; ++ }; ++ ++ pci@3,0 { ++ nvidia,num-lanes = <1>; ++ }; ++ }; ++ ++ host1x@50000000 { ++ hdmi@54280000 { ++ vdd-supply = <&sys_3v3_reg>; ++ pll-supply = <&vio_reg>; ++ ++ nvidia,hpd-gpio = ++ <&gpio TEGRA_GPIO(N, 7) GPIO_ACTIVE_HIGH>; ++ nvidia,ddc-i2c-bus = <&hdmiddc>; ++ }; ++ }; ++ ++ pinmux@70000868 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&state_default>; ++ ++ state_default: pinmux { ++ /* Apalis BKL1_ON */ ++ pv2 { ++ nvidia,pins = "pv2"; ++ nvidia,function = "rsvd4"; ++ nvidia,pull = <TEGRA_PIN_PULL_NONE>; ++ nvidia,tristate = <TEGRA_PIN_DISABLE>; ++ }; ++ ++ /* Apalis BKL1_PWM */ ++ uart3_rts_n_pc0 { ++ nvidia,pins = "uart3_rts_n_pc0"; ++ nvidia,function = "pwm0"; ++ nvidia,pull = <TEGRA_PIN_PULL_NONE>; ++ nvidia,tristate = <TEGRA_PIN_DISABLE>; ++ }; ++ /* BKL1_PWM_EN#, disable TPS65911 PMIC PWM backlight */ ++ uart3_cts_n_pa1 { ++ nvidia,pins = "uart3_cts_n_pa1"; ++ nvidia,function = "rsvd1"; ++ nvidia,pull = <TEGRA_PIN_PULL_UP>; ++ nvidia,tristate = <TEGRA_PIN_DISABLE>; ++ }; ++ ++ /* Apalis CAN1 on SPI6 */ ++ spi2_cs0_n_px3 { ++ nvidia,pins = "spi2_cs0_n_px3", ++ "spi2_miso_px1", ++ "spi2_mosi_px0", ++ "spi2_sck_px2"; ++ nvidia,function = "spi6"; ++ nvidia,pull = <TEGRA_PIN_PULL_NONE>; ++ nvidia,tristate = <TEGRA_PIN_DISABLE>; ++ }; ++ /* CAN_INT1 */ ++ spi2_cs1_n_pw2 { ++ nvidia,pins = "spi2_cs1_n_pw2"; ++ nvidia,function = "spi3"; ++ nvidia,pull = <TEGRA_PIN_PULL_NONE>; ++ nvidia,tristate = <TEGRA_PIN_DISABLE>; ++ nvidia,enable-input = <TEGRA_PIN_ENABLE>; ++ }; ++ ++ /* Apalis CAN2 on SPI4 */ ++ gmi_a16_pj7 { ++ nvidia,pins = "gmi_a16_pj7", ++ "gmi_a17_pb0", ++ "gmi_a18_pb1", ++ "gmi_a19_pk7"; ++ nvidia,function = "spi4"; ++ nvidia,pull = <TEGRA_PIN_PULL_NONE>; ++ nvidia,tristate = <TEGRA_PIN_DISABLE>; ++ }; ++ /* CAN_INT2 */ ++ spi2_cs2_n_pw3 { ++ nvidia,pins = "spi2_cs2_n_pw3"; ++ nvidia,function = "spi3"; ++ nvidia,pull = <TEGRA_PIN_PULL_NONE>; ++ nvidia,tristate = <TEGRA_PIN_DISABLE>; ++ nvidia,enable-input = <TEGRA_PIN_ENABLE>; ++ }; ++ ++ /* Apalis I2C3 */ ++ cam_i2c_scl_pbb1 { ++ nvidia,pins = "cam_i2c_scl_pbb1", ++ "cam_i2c_sda_pbb2"; ++ nvidia,function = "i2c3"; ++ nvidia,pull = <TEGRA_PIN_PULL_NONE>; ++ nvidia,tristate = <TEGRA_PIN_DISABLE>; ++ nvidia,enable-input = <TEGRA_PIN_ENABLE>; ++ nvidia,lock = <TEGRA_PIN_DISABLE>; ++ nvidia,open-drain = <TEGRA_PIN_ENABLE>; ++ }; ++ ++ /* Apalis MMC1 */ ++ sdmmc3_clk_pa6 { ++ nvidia,pins = "sdmmc3_clk_pa6", ++ "sdmmc3_cmd_pa7"; ++ nvidia,function = "sdmmc3"; ++ nvidia,pull = <TEGRA_PIN_PULL_NONE>; ++ nvidia,tristate = <TEGRA_PIN_DISABLE>; ++ }; ++ sdmmc3_dat0_pb7 { ++ nvidia,pins = "sdmmc3_dat0_pb7", ++ "sdmmc3_dat1_pb6", ++ "sdmmc3_dat2_pb5", ++ "sdmmc3_dat3_pb4", ++ "sdmmc3_dat4_pd1", ++ "sdmmc3_dat5_pd0", ++ "sdmmc3_dat6_pd3", ++ "sdmmc3_dat7_pd4"; ++ nvidia,function = "sdmmc3"; ++ nvidia,pull = <TEGRA_PIN_PULL_UP>; ++ nvidia,tristate = <TEGRA_PIN_DISABLE>; ++ }; ++ /* Apalis MMC1_CD# */ ++ pv3 { ++ nvidia,pins = "pv3"; ++ nvidia,function = "rsvd2"; ++ nvidia,pull = <TEGRA_PIN_PULL_NONE>; ++ nvidia,tristate = <TEGRA_PIN_DISABLE>; ++ nvidia,enable-input = <TEGRA_PIN_ENABLE>; ++ }; ++ ++ /* Apalis PWM1 */ ++ gpio_pu6 { ++ nvidia,pins = "gpio_pu6"; ++ nvidia,function = "pwm3"; ++ nvidia,pull = <TEGRA_PIN_PULL_NONE>; ++ nvidia,tristate = <TEGRA_PIN_DISABLE>; ++ }; ++ ++ /* Apalis PWM2 */ ++ gpio_pu5 { ++ nvidia,pins = "gpio_pu5"; ++ nvidia,function = "pwm2"; ++ nvidia,pull = <TEGRA_PIN_PULL_NONE>; ++ nvidia,tristate = <TEGRA_PIN_DISABLE>; ++ }; ++ ++ /* Apalis PWM3 */ ++ gpio_pu4 { ++ nvidia,pins = "gpio_pu4"; ++ nvidia,function = "pwm1"; ++ nvidia,pull = <TEGRA_PIN_PULL_NONE>; ++ nvidia,tristate = <TEGRA_PIN_DISABLE>; ++ }; ++ ++ /* Apalis PWM4 */ ++ gpio_pu3 { ++ nvidia,pins = "gpio_pu3"; ++ nvidia,function = "pwm0"; ++ nvidia,pull = <TEGRA_PIN_PULL_NONE>; ++ nvidia,tristate = <TEGRA_PIN_DISABLE>; ++ }; ++ ++ /* Apalis RESET_MOCI# */ ++ gmi_rst_n_pi4 { ++ nvidia,pins = "gmi_rst_n_pi4"; ++ nvidia,function = "gmi"; ++ nvidia,pull = <TEGRA_PIN_PULL_NONE>; ++ nvidia,tristate = <TEGRA_PIN_DISABLE>; ++ }; ++ ++ /* Apalis SD1 */ ++ sdmmc1_clk_pz0 { ++ nvidia,pins = "sdmmc1_clk_pz0"; ++ nvidia,function = "sdmmc1"; ++ nvidia,pull = <TEGRA_PIN_PULL_NONE>; ++ nvidia,tristate = <TEGRA_PIN_DISABLE>; ++ }; ++ sdmmc1_cmd_pz1 { ++ nvidia,pins = "sdmmc1_cmd_pz1", ++ "sdmmc1_dat0_py7", ++ "sdmmc1_dat1_py6", ++ "sdmmc1_dat2_py5", ++ "sdmmc1_dat3_py4"; ++ nvidia,function = "sdmmc1"; ++ nvidia,pull = <TEGRA_PIN_PULL_UP>; ++ nvidia,tristate = <TEGRA_PIN_DISABLE>; ++ }; ++ /* Apalis SD1_CD# */ ++ clk2_req_pcc5 { ++ nvidia,pins = "clk2_req_pcc5"; ++ nvidia,function = "rsvd2"; ++ nvidia,pull = <TEGRA_PIN_PULL_NONE>; ++ nvidia,tristate = <TEGRA_PIN_DISABLE>; ++ nvidia,enable-input = <TEGRA_PIN_ENABLE>; ++ }; ++ ++ /* Apalis SPI1 */ ++ spi1_sck_px5 { ++ nvidia,pins = "spi1_sck_px5", ++ "spi1_mosi_px4", ++ "spi1_miso_px7", ++ "spi1_cs0_n_px6"; ++ nvidia,function = "spi1"; ++ nvidia,pull = <TEGRA_PIN_PULL_NONE>; ++ nvidia,tristate = <TEGRA_PIN_DISABLE>; ++ }; ++ ++ /* Apalis SPI2 */ ++ lcd_sck_pz4 { ++ nvidia,pins = "lcd_sck_pz4", ++ "lcd_sdout_pn5", ++ "lcd_sdin_pz2", ++ "lcd_cs0_n_pn4"; ++ nvidia,function = "spi5"; ++ nvidia,pull = <TEGRA_PIN_PULL_NONE>; ++ nvidia,tristate = <TEGRA_PIN_DISABLE>; ++ }; ++ ++ /* Apalis UART1 */ ++ ulpi_data0 { ++ nvidia,pins = "ulpi_data0_po1", ++ "ulpi_data1_po2", ++ "ulpi_data2_po3", ++ "ulpi_data3_po4", ++ "ulpi_data4_po5", ++ "ulpi_data5_po6", ++ "ulpi_data6_po7", ++ "ulpi_data7_po0"; ++ nvidia,function = "uarta"; ++ nvidia,pull = <TEGRA_PIN_PULL_NONE>; ++ nvidia,tristate = <TEGRA_PIN_DISABLE>; ++ }; ++ ++ /* Apalis UART2 */ ++ ulpi_clk_py0 { ++ nvidia,pins = "ulpi_clk_py0", ++ "ulpi_dir_py1", ++ "ulpi_nxt_py2", ++ "ulpi_stp_py3"; ++ nvidia,function = "uartd"; ++ nvidia,pull = <TEGRA_PIN_PULL_NONE>; ++ nvidia,tristate = <TEGRA_PIN_DISABLE>; ++ }; ++ ++ /* Apalis UART3 */ ++ uart2_rxd_pc3 { ++ nvidia,pins = "uart2_rxd_pc3", ++ "uart2_txd_pc2"; ++ nvidia,function = "uartb"; ++ nvidia,pull = <TEGRA_PIN_PULL_NONE>; ++ nvidia,tristate = <TEGRA_PIN_DISABLE>; ++ }; ++ ++ /* Apalis UART4 */ ++ uart3_rxd_pw7 { ++ nvidia,pins = "uart3_rxd_pw7", ++ "uart3_txd_pw6"; ++ nvidia,function = "uartc"; ++ nvidia,pull = <TEGRA_PIN_PULL_NONE>; ++ nvidia,tristate = <TEGRA_PIN_DISABLE>; ++ }; ++ ++ /* Apalis USBO1_EN */ ++ gen2_i2c_scl_pt5 { ++ nvidia,pins = "gen2_i2c_scl_pt5"; ++ nvidia,function = "rsvd4"; ++ nvidia,open-drain = <TEGRA_PIN_DISABLE>; ++ nvidia,pull = <TEGRA_PIN_PULL_NONE>; ++ nvidia,tristate = <TEGRA_PIN_DISABLE>; ++ }; ++ ++ /* Apalis USBO1_OC# */ ++ gen2_i2c_sda_pt6 { ++ nvidia,pins = "gen2_i2c_sda_pt6"; ++ nvidia,function = "rsvd4"; ++ nvidia,open-drain = <TEGRA_PIN_DISABLE>; ++ nvidia,pull = <TEGRA_PIN_PULL_NONE>; ++ nvidia,tristate = <TEGRA_PIN_DISABLE>; ++ nvidia,enable-input = <TEGRA_PIN_ENABLE>; ++ }; ++ ++ /* Apalis WAKE1_MICO */ ++ pv1 { ++ nvidia,pins = "pv1"; ++ nvidia,function = "rsvd1"; ++ nvidia,pull = <TEGRA_PIN_PULL_NONE>; ++ nvidia,tristate = <TEGRA_PIN_DISABLE>; ++ nvidia,enable-input = <TEGRA_PIN_ENABLE>; ++ }; ++ ++ /* eMMC (On-module) */ ++ sdmmc4_clk_pcc4 { ++ nvidia,pins = "sdmmc4_clk_pcc4", ++ "sdmmc4_rst_n_pcc3"; ++ nvidia,function = "sdmmc4"; ++ nvidia,pull = <TEGRA_PIN_PULL_NONE>; ++ nvidia,tristate = <TEGRA_PIN_DISABLE>; ++ }; ++ sdmmc4_dat0_paa0 { ++ nvidia,pins = "sdmmc4_dat0_paa0", ++ "sdmmc4_dat1_paa1", ++ "sdmmc4_dat2_paa2", ++ "sdmmc4_dat3_paa3", ++ "sdmmc4_dat4_paa4", ++ "sdmmc4_dat5_paa5", ++ "sdmmc4_dat6_paa6", ++ "sdmmc4_dat7_paa7"; ++ nvidia,function = "sdmmc4"; ++ nvidia,pull = <TEGRA_PIN_PULL_UP>; ++ nvidia,tristate = <TEGRA_PIN_DISABLE>; ++ }; ++ ++ /* LVDS Transceiver Configuration */ ++ pbb0 { ++ nvidia,pins = "pbb0", ++ "pbb7", ++ "pcc1", ++ "pcc2"; ++ nvidia,function = "rsvd2"; ++ nvidia,pull = <TEGRA_PIN_PULL_NONE>; ++ nvidia,tristate = <TEGRA_PIN_DISABLE>; ++ nvidia,enable-input = <TEGRA_PIN_DISABLE>; ++ nvidia,lock = <TEGRA_PIN_DISABLE>; ++ }; ++ pbb3 { ++ nvidia,pins = "pbb3", ++ "pbb4", ++ "pbb5", ++ "pbb6"; ++ nvidia,function = "displayb"; ++ nvidia,pull = <TEGRA_PIN_PULL_NONE>; ++ nvidia,tristate = <TEGRA_PIN_DISABLE>; ++ nvidia,enable-input = <TEGRA_PIN_DISABLE>; ++ nvidia,lock = <TEGRA_PIN_DISABLE>; ++ }; ++ ++ /* Power I2C (On-module) */ ++ pwr_i2c_scl_pz6 { ++ nvidia,pins = "pwr_i2c_scl_pz6", ++ "pwr_i2c_sda_pz7"; ++ nvidia,function = "i2cpwr"; ++ nvidia,pull = <TEGRA_PIN_PULL_NONE>; ++ nvidia,tristate = <TEGRA_PIN_DISABLE>; ++ nvidia,enable-input = <TEGRA_PIN_ENABLE>; ++ nvidia,lock = <TEGRA_PIN_DISABLE>; ++ nvidia,open-drain = <TEGRA_PIN_ENABLE>; ++ }; ++ ++ /* ++ * THERMD_ALERT#, unlatched I2C address pin of LM95245 ++ * temperature sensor therefore requires disabling for ++ * now ++ */ ++ lcd_dc1_pd2 { ++ nvidia,pins = "lcd_dc1_pd2"; ++ nvidia,function = "rsvd3"; ++ nvidia,pull = <TEGRA_PIN_PULL_NONE>; ++ nvidia,tristate = <TEGRA_PIN_DISABLE>; ++ nvidia,enable-input = <TEGRA_PIN_ENABLE>; ++ }; ++ ++ /* TOUCH_PEN_INT# */ ++ pv0 { ++ nvidia,pins = "pv0"; ++ nvidia,function = "rsvd1"; ++ nvidia,pull = <TEGRA_PIN_PULL_NONE>; ++ nvidia,tristate = <TEGRA_PIN_DISABLE>; ++ nvidia,enable-input = <TEGRA_PIN_ENABLE>; ++ }; ++ }; ++ }; ++ ++ hdmiddc: i2c@7000c700 { ++ clock-frequency = <100000>; ++ }; ++ ++ /* ++ * PWR_I2C: power I2C to audio codec, PMIC, temperature sensor and ++ * touch screen controller ++ */ ++ i2c@7000d000 { ++ status = "okay"; ++ clock-frequency = <100000>; ++ ++ pmic: tps65911@2d { ++ compatible = "ti,tps65911"; ++ reg = <0x2d>; ++ ++ interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>; ++ #interrupt-cells = <2>; ++ interrupt-controller; ++ ++ ti,system-power-controller; ++ ++ #gpio-cells = <2>; ++ gpio-controller; ++ ++ vcc1-supply = <&sys_3v3_reg>; ++ vcc2-supply = <&sys_3v3_reg>; ++ vcc3-supply = <&vio_reg>; ++ vcc4-supply = <&sys_3v3_reg>; ++ vcc5-supply = <&sys_3v3_reg>; ++ vcc6-supply = <&vio_reg>; ++ vcc7-supply = <&sys_5v0_reg>; ++ vccio-supply = <&sys_3v3_reg>; ++ ++ regulators { ++ /* SW1: +V1.35_VDDIO_DDR */ ++ vdd1_reg: vdd1 { ++ regulator-name = "vddio_ddr_1v35"; ++ regulator-min-microvolt = <1350000>; ++ regulator-max-microvolt = <1350000>; ++ regulator-always-on; ++ }; ++ ++ /* SW2: +V1.05 */ ++ vdd2_reg: vdd2 { ++ regulator-name = ++ "vdd_pexa,vdd_pexb,vdd_sata"; ++ regulator-min-microvolt = <1050000>; ++ regulator-max-microvolt = <1050000>; ++ }; ++ ++ /* SW CTRL: +V1.0_VDD_CPU */ ++ vddctrl_reg: vddctrl { ++ regulator-name = "vdd_cpu,vdd_sys"; ++ regulator-min-microvolt = <1150000>; ++ regulator-max-microvolt = <1150000>; ++ regulator-always-on; ++ }; ++ ++ /* SWIO: +V1.8 */ ++ vio_reg: vio { ++ regulator-name = "vdd_1v8_gen"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-always-on; ++ }; ++ ++ /* LDO1: unused */ ++ ++ /* ++ * EN_+V3.3 switching via FET: ++ * +V3.3_AUDIO_AVDD_S, +V3.3 and +V1.8_VDD_LAN ++ * see also v3_3 fixed supply ++ */ ++ ldo2_reg: ldo2 { ++ regulator-name = "en_3v3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ /* +V1.2_CSI */ ++ ldo3_reg: ldo3 { ++ regulator-name = ++ "avdd_dsi_csi,pwrdet_mipi"; ++ regulator-min-microvolt = <1200000>; ++ regulator-max-microvolt = <1200000>; ++ }; ++ ++ /* +V1.2_VDD_RTC */ ++ ldo4_reg: ldo4 { ++ regulator-name = "vdd_rtc"; ++ regulator-min-microvolt = <1200000>; ++ regulator-max-microvolt = <1200000>; ++ regulator-always-on; ++ }; ++ ++ /* ++ * +V2.8_AVDD_VDAC: ++ * only required for analog RGB ++ */ ++ ldo5_reg: ldo5 { ++ regulator-name = "avdd_vdac"; ++ regulator-min-microvolt = <2800000>; ++ regulator-max-microvolt = <2800000>; ++ regulator-always-on; ++ }; ++ ++ /* ++ * +V1.05_AVDD_PLLE: avdd_plle should be 1.05V ++ * but LDO6 can't set voltage in 50mV ++ * granularity ++ */ ++ ldo6_reg: ldo6 { ++ regulator-name = "avdd_plle"; ++ regulator-min-microvolt = <1100000>; ++ regulator-max-microvolt = <1100000>; ++ }; ++ ++ /* +V1.2_AVDD_PLL */ ++ ldo7_reg: ldo7 { ++ regulator-name = "avdd_pll"; ++ regulator-min-microvolt = <1200000>; ++ regulator-max-microvolt = <1200000>; ++ regulator-always-on; ++ }; ++ ++ /* +V1.0_VDD_DDR_HS */ ++ ldo8_reg: ldo8 { ++ regulator-name = "vdd_ddr_hs"; ++ regulator-min-microvolt = <1000000>; ++ regulator-max-microvolt = <1000000>; ++ regulator-always-on; ++ }; ++ }; ++ }; ++ ++ /* STMPE811 touch screen controller */ ++ stmpe811@41 { ++ compatible = "st,stmpe811"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x41>; ++ interrupts = <TEGRA_GPIO(V, 0) IRQ_TYPE_LEVEL_LOW>; ++ interrupt-parent = <&gpio>; ++ interrupt-controller; ++ id = <0>; ++ blocks = <0x5>; ++ irq-trigger = <0x1>; ++ ++ stmpe_touchscreen { ++ compatible = "st,stmpe-ts"; ++ reg = <0>; ++ /* 3.25 MHz ADC clock speed */ ++ st,adc-freq = <1>; ++ /* 8 sample average control */ ++ st,ave-ctrl = <3>; ++ /* 7 length fractional part in z */ ++ st,fraction-z = <7>; ++ /* ++ * 50 mA typical 80 mA max touchscreen drivers ++ * current limit value ++ */ ++ st,i-drive = <1>; ++ /* 12-bit ADC */ ++ st,mod-12b = <1>; ++ /* internal ADC reference */ ++ st,ref-sel = <0>; ++ /* ADC converstion time: 80 clocks */ ++ st,sample-time = <4>; ++ /* 1 ms panel driver settling time */ ++ st,settling = <3>; ++ /* 5 ms touch detect interrupt delay */ ++ st,touch-det-delay = <5>; ++ }; ++ }; ++ ++ /* ++ * LM95245 temperature sensor ++ * Note: OVERT_N directly connected to PMIC PWRDN ++ */ ++ temp-sensor@4c { ++ compatible = "national,lm95245"; ++ reg = <0x4c>; ++ }; ++ ++ /* SW: +V1.2_VDD_CORE */ ++ tps62362@60 { ++ compatible = "ti,tps62362"; ++ reg = <0x60>; ++ ++ regulator-name = "tps62362-vout"; ++ regulator-min-microvolt = <900000>; ++ regulator-max-microvolt = <1400000>; ++ regulator-boot-on; ++ regulator-always-on; ++ ti,vsel0-state-low; ++ /* VSEL1: EN_CORE_DVFS_N low for DVFS */ ++ ti,vsel1-state-low; ++ }; ++ }; ++ ++ /* SPI4: CAN2 */ ++ spi@7000da00 { ++ status = "okay"; ++ spi-max-frequency = <10000000>; ++ ++ can@1 { ++ compatible = "microchip,mcp2515"; ++ reg = <1>; ++ clocks = <&clk16m>; ++ interrupt-parent = <&gpio>; ++ interrupts = <TEGRA_GPIO(W, 3) GPIO_ACTIVE_LOW>; ++ spi-max-frequency = <10000000>; ++ }; ++ }; ++ ++ /* SPI6: CAN1 */ ++ spi@7000de00 { ++ status = "okay"; ++ spi-max-frequency = <10000000>; ++ ++ can@0 { ++ compatible = "microchip,mcp2515"; ++ reg = <0>; ++ clocks = <&clk16m>; ++ interrupt-parent = <&gpio>; ++ interrupts = <TEGRA_GPIO(W, 2) GPIO_ACTIVE_LOW>; ++ spi-max-frequency = <10000000>; ++ }; ++ }; ++ ++ pmc@7000e400 { ++ nvidia,invert-interrupt; ++ nvidia,suspend-mode = <1>; ++ nvidia,cpu-pwr-good-time = <5000>; ++ nvidia,cpu-pwr-off-time = <5000>; ++ nvidia,core-pwr-good-time = <3845 3845>; ++ nvidia,core-pwr-off-time = <0>; ++ nvidia,core-power-req-active-high; ++ nvidia,sys-clock-req-active-high; ++ }; ++ ++ sdhci@78000600 { ++ status = "okay"; ++ bus-width = <8>; ++ non-removable; ++ }; ++ ++ clocks { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ clk32k_in: clk@0 { ++ compatible = "fixed-clock"; ++ reg=<0>; ++ #clock-cells = <0>; ++ clock-frequency = <32768>; ++ }; ++ clk16m: clk@1 { ++ compatible = "fixed-clock"; ++ reg=<1>; ++ #clock-cells = <0>; ++ clock-frequency = <16000000>; ++ clock-output-names = "clk16m"; ++ }; ++ }; ++ ++ regulators { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ sys_3v3_reg: regulator@100 { ++ compatible = "regulator-fixed"; ++ reg = <100>; ++ regulator-name = "3v3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ }; ++}; +diff --git a/arch/arm/boot/dts/tegra30-beaver.dts b/arch/arm/boot/dts/tegra30-beaver.dts +index 3189791..cee8f22 100644 +--- a/arch/arm/boot/dts/tegra30-beaver.dts ++++ b/arch/arm/boot/dts/tegra30-beaver.dts +@@ -17,9 +17,15 @@ + + pcie-controller@00003000 { + status = "okay"; +- pex-clk-supply = <&sys_3v3_pexs_reg>; +- vdd-supply = <&ldo1_reg>; +- avdd-supply = <&ldo2_reg>; ++ ++ avdd-pexa-supply = <&ldo1_reg>; ++ vdd-pexa-supply = <&ldo1_reg>; ++ avdd-pexb-supply = <&ldo1_reg>; ++ vdd-pexb-supply = <&ldo1_reg>; ++ avdd-pex-pll-supply = <&ldo1_reg>; ++ avdd-plle-supply = <&ldo1_reg>; ++ vddio-pex-ctl-supply = <&sys_3v3_reg>; ++ hvdd-pex-supply = <&sys_3v3_pexs_reg>; + + pci@1,0 { + status = "okay"; +diff --git a/arch/arm/boot/dts/tegra30-cardhu.dtsi b/arch/arm/boot/dts/tegra30-cardhu.dtsi +index 0cf0848..2063795 100644 +--- a/arch/arm/boot/dts/tegra30-cardhu.dtsi ++++ b/arch/arm/boot/dts/tegra30-cardhu.dtsi +@@ -38,9 +38,14 @@ + + pcie-controller@00003000 { + status = "okay"; +- pex-clk-supply = <&pex_hvdd_3v3_reg>; +- vdd-supply = <&ldo1_reg>; +- avdd-supply = <&ldo2_reg>; ++ ++ /* AVDD_PEXA and VDD_PEXA inputs are grounded on Cardhu. */ ++ avdd-pexb-supply = <&ldo1_reg>; ++ vdd-pexb-supply = <&ldo1_reg>; ++ avdd-pex-pll-supply = <&ldo1_reg>; ++ hvdd-pex-supply = <&pex_hvdd_3v3_reg>; ++ vddio-pex-ctl-supply = <&sys_3v3_reg>; ++ avdd-plle-supply = <&ldo2_reg>; + + pci@1,0 { + nvidia,num-lanes = <4>; +diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi +index dec4fc8..0b1ede9 100644 +--- a/arch/arm/boot/dts/tegra30.dtsi ++++ b/arch/arm/boot/dts/tegra30.dtsi +@@ -335,6 +335,12 @@ + interrupt-controller; + }; + ++ apbmisc@70000800 { ++ compatible = "nvidia,tegra30-apbmisc", "nvidia,tegra20-apbmisc"; ++ reg = <0x70000800 0x64 /* Chip revision */ ++ 0x70000008 0x04>; /* Strapping options */ ++ }; ++ + pinmux: pinmux@70000868 { + compatible = "nvidia,tegra30-pinmux"; + reg = <0x70000868 0xd4 /* Pad control registers */ +@@ -631,6 +637,15 @@ + nvidia,ahb = <&ahb>; + }; + ++ fuse@7000f800 { ++ compatible = "nvidia,tegra30-efuse"; ++ reg = <0x7000f800 0x400>; ++ clocks = <&tegra_car TEGRA30_CLK_FUSE>; ++ clock-names = "fuse"; ++ resets = <&tegra_car 39>; ++ reset-names = "fuse"; ++ }; ++ + ahub@70080000 { + compatible = "nvidia,tegra30-ahub"; + reg = <0x70080000 0x200 +diff --git a/arch/arm/configs/tegra_defconfig b/arch/arm/configs/tegra_defconfig +index 157a4f1..285c433 100644 +--- a/arch/arm/configs/tegra_defconfig ++++ b/arch/arm/configs/tegra_defconfig +@@ -104,6 +104,7 @@ CONFIG_SCSI_MULTI_LUN=y + # CONFIG_SCSI_LOWLEVEL is not set + CONFIG_NETDEVICES=y + CONFIG_DUMMY=y ++CONFIG_IGB=y + CONFIG_R8169=y + CONFIG_USB_PEGASUS=y + CONFIG_USB_USBNET=y +@@ -118,6 +119,8 @@ CONFIG_KEYBOARD_GPIO=y + CONFIG_KEYBOARD_TEGRA=y + CONFIG_KEYBOARD_CROS_EC=y + CONFIG_MOUSE_PS2_ELANTECH=y ++CONFIG_INPUT_TOUCHSCREEN=y ++CONFIG_TOUCHSCREEN_STMPE=y + CONFIG_INPUT_MISC=y + CONFIG_INPUT_MPU3050=y + # CONFIG_LEGACY_PTYS is not set +@@ -128,6 +131,7 @@ CONFIG_SERIAL_TEGRA=y + CONFIG_SERIAL_OF_PLATFORM=y + # CONFIG_HW_RANDOM is not set + # CONFIG_I2C_COMPAT is not set ++CONFIG_I2C_CHARDEV=y + CONFIG_I2C_MUX_PCA954x=y + CONFIG_I2C_MUX_PINCTRL=y + CONFIG_I2C_TEGRA=y +@@ -149,10 +153,12 @@ CONFIG_POWER_RESET=y + CONFIG_POWER_RESET_AS3722=y + CONFIG_POWER_RESET_GPIO=y + CONFIG_SENSORS_LM90=y ++CONFIG_SENSORS_LM95245=y + CONFIG_MFD_AS3722=y + CONFIG_MFD_CROS_EC=y + CONFIG_MFD_CROS_EC_SPI=y + CONFIG_MFD_MAX8907=y ++CONFIG_MFD_STMPE=y + CONFIG_MFD_PALMAS=y + CONFIG_MFD_TPS65090=y + CONFIG_MFD_TPS6586X=y +@@ -215,6 +221,7 @@ CONFIG_MMC_SDHCI_TEGRA=y + CONFIG_NEW_LEDS=y + CONFIG_LEDS_CLASS=y + CONFIG_LEDS_GPIO=y ++CONFIG_LEDS_PWM=y + CONFIG_LEDS_TRIGGERS=y + CONFIG_LEDS_TRIGGER_TIMER=y + CONFIG_LEDS_TRIGGER_ONESHOT=y +diff --git a/arch/arm/lib/delay.c b/arch/arm/lib/delay.c +index 5306de3..312d43e 100644 +--- a/arch/arm/lib/delay.c ++++ b/arch/arm/lib/delay.c +@@ -19,6 +19,7 @@ + * Author: Will Deacon <will.deacon@arm.com> + */ + ++#include <linux/clocksource.h> + #include <linux/delay.h> + #include <linux/init.h> + #include <linux/kernel.h> +@@ -36,6 +37,7 @@ struct arm_delay_ops arm_delay_ops = { + + static const struct delay_timer *delay_timer; + static bool delay_calibrated; ++static u64 delay_res; + + int read_current_timer(unsigned long *timer_val) + { +@@ -47,6 +49,11 @@ int read_current_timer(unsigned long *timer_val) + } + EXPORT_SYMBOL_GPL(read_current_timer); + ++static inline u64 cyc_to_ns(u64 cyc, u32 mult, u32 shift) ++{ ++ return (cyc * mult) >> shift; ++} ++ + static void __timer_delay(unsigned long cycles) + { + cycles_t start = get_cycles(); +@@ -69,18 +76,24 @@ static void __timer_udelay(unsigned long usecs) + + void __init register_current_timer_delay(const struct delay_timer *timer) + { +- if (!delay_calibrated) { +- pr_info("Switching to timer-based delay loop\n"); ++ u32 new_mult, new_shift; ++ u64 res; ++ ++ clocks_calc_mult_shift(&new_mult, &new_shift, timer->freq, ++ NSEC_PER_SEC, 3600); ++ res = cyc_to_ns(1ULL, new_mult, new_shift); ++ ++ if (!delay_calibrated && (!delay_res || (res < delay_res))) { ++ pr_info("Switching to timer-based delay loop, resolution %lluns\n", res); + delay_timer = timer; + lpj_fine = timer->freq / HZ; ++ delay_res = res; + + /* cpufreq may scale loops_per_jiffy, so keep a private copy */ + arm_delay_ops.ticks_per_jiffy = lpj_fine; + arm_delay_ops.delay = __timer_delay; + arm_delay_ops.const_udelay = __timer_const_udelay; + arm_delay_ops.udelay = __timer_udelay; +- +- delay_calibrated = true; + } else { + pr_info("Ignoring duplicate/late registration of read_current_timer delay\n"); + } +@@ -91,3 +104,8 @@ unsigned long calibrate_delay_is_known(void) + delay_calibrated = true; + return lpj_fine; + } ++ ++void calibration_delay_done(void) ++{ ++ delay_calibrated = true; ++} +diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile +index 6fbfbb7..c303b55 100644 +--- a/arch/arm/mach-tegra/Makefile ++++ b/arch/arm/mach-tegra/Makefile +@@ -2,24 +2,20 @@ asflags-y += -march=armv7-a + + obj-y += io.o + obj-y += irq.o +-obj-y += fuse.o + obj-y += pmc.o + obj-y += flowctrl.o + obj-y += powergate.o +-obj-y += apbio.o + obj-y += pm.o + obj-y += reset.o + obj-y += reset-handler.o + obj-y += sleep.o + obj-y += tegra.o + obj-$(CONFIG_CPU_IDLE) += cpuidle.o +-obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_speedo.o + obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += sleep-tegra20.o + obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += pm-tegra20.o + ifeq ($(CONFIG_CPU_IDLE),y) + obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += cpuidle-tegra20.o + endif +-obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_speedo.o + obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += sleep-tegra30.o + obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += pm-tegra30.o + ifeq ($(CONFIG_CPU_IDLE),y) +@@ -28,7 +24,6 @@ endif + obj-$(CONFIG_SMP) += platsmp.o headsmp.o + obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o + +-obj-$(CONFIG_ARCH_TEGRA_114_SOC) += tegra114_speedo.o + obj-$(CONFIG_ARCH_TEGRA_114_SOC) += sleep-tegra30.o + obj-$(CONFIG_ARCH_TEGRA_114_SOC) += pm-tegra30.o + ifeq ($(CONFIG_CPU_IDLE),y) +diff --git a/arch/arm/mach-tegra/apbio.c b/arch/arm/mach-tegra/apbio.c +deleted file mode 100644 +index bc47197..0000000 +--- a/arch/arm/mach-tegra/apbio.c ++++ /dev/null +@@ -1,206 +0,0 @@ +-/* +- * 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/of.h> +-#include <linux/dmaengine.h> +-#include <linux/dma-mapping.h> +-#include <linux/spinlock.h> +-#include <linux/completion.h> +-#include <linux/sched.h> +-#include <linux/mutex.h> +- +-#include "apbio.h" +-#include "iomap.h" +- +-#if defined(CONFIG_TEGRA20_APB_DMA) +-static DEFINE_MUTEX(tegra_apb_dma_lock); +-static u32 *tegra_apb_bb; +-static dma_addr_t tegra_apb_bb_phys; +-static DECLARE_COMPLETION(tegra_apb_wait); +- +-static u32 tegra_apb_readl_direct(unsigned long offset); +-static void tegra_apb_writel_direct(u32 value, unsigned long offset); +- +-static struct dma_chan *tegra_apb_dma_chan; +-static struct dma_slave_config dma_sconfig; +- +-static bool tegra_apb_dma_init(void) +-{ +- dma_cap_mask_t mask; +- +- mutex_lock(&tegra_apb_dma_lock); +- +- /* Check to see if we raced to setup */ +- if (tegra_apb_dma_chan) +- goto skip_init; +- +- dma_cap_zero(mask); +- dma_cap_set(DMA_SLAVE, mask); +- tegra_apb_dma_chan = dma_request_channel(mask, NULL, NULL); +- if (!tegra_apb_dma_chan) { +- /* +- * This is common until the device is probed, so don't +- * shout about it. +- */ +- pr_debug("%s: can not allocate dma channel\n", __func__); +- goto err_dma_alloc; +- } +- +- 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__); +- goto err_buff_alloc; +- } +- +- dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; +- dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; +- dma_sconfig.src_maxburst = 1; +- dma_sconfig.dst_maxburst = 1; +- +-skip_init: +- mutex_unlock(&tegra_apb_dma_lock); +- return true; +- +-err_buff_alloc: +- dma_release_channel(tegra_apb_dma_chan); +- tegra_apb_dma_chan = NULL; +- +-err_dma_alloc: +- mutex_unlock(&tegra_apb_dma_lock); +- return false; +-} +- +-static void apb_dma_complete(void *args) +-{ +- complete(&tegra_apb_wait); +-} +- +-static int do_dma_transfer(unsigned long apb_add, +- enum dma_transfer_direction dir) +-{ +- struct dma_async_tx_descriptor *dma_desc; +- int ret; +- +- if (dir == DMA_DEV_TO_MEM) +- dma_sconfig.src_addr = apb_add; +- else +- dma_sconfig.dst_addr = apb_add; +- +- ret = dmaengine_slave_config(tegra_apb_dma_chan, &dma_sconfig); +- if (ret) +- return ret; +- +- dma_desc = dmaengine_prep_slave_single(tegra_apb_dma_chan, +- tegra_apb_bb_phys, sizeof(u32), dir, +- DMA_PREP_INTERRUPT | DMA_CTRL_ACK); +- if (!dma_desc) +- return -EINVAL; +- +- dma_desc->callback = apb_dma_complete; +- dma_desc->callback_param = NULL; +- +- reinit_completion(&tegra_apb_wait); +- +- dmaengine_submit(dma_desc); +- dma_async_issue_pending(tegra_apb_dma_chan); +- ret = wait_for_completion_timeout(&tegra_apb_wait, +- msecs_to_jiffies(50)); +- +- if (WARN(ret == 0, "apb read dma timed out")) { +- dmaengine_terminate_all(tegra_apb_dma_chan); +- return -EFAULT; +- } +- return 0; +-} +- +-static u32 tegra_apb_readl_using_dma(unsigned long offset) +-{ +- int ret; +- +- if (!tegra_apb_dma_chan && !tegra_apb_dma_init()) +- return tegra_apb_readl_direct(offset); +- +- mutex_lock(&tegra_apb_dma_lock); +- ret = do_dma_transfer(offset, DMA_DEV_TO_MEM); +- if (ret < 0) { +- pr_err("error in reading offset 0x%08lx using dma\n", offset); +- *(u32 *)tegra_apb_bb = 0; +- } +- mutex_unlock(&tegra_apb_dma_lock); +- return *((u32 *)tegra_apb_bb); +-} +- +-static void tegra_apb_writel_using_dma(u32 value, unsigned long offset) +-{ +- int ret; +- +- if (!tegra_apb_dma_chan && !tegra_apb_dma_init()) { +- tegra_apb_writel_direct(value, offset); +- return; +- } +- +- mutex_lock(&tegra_apb_dma_lock); +- *((u32 *)tegra_apb_bb) = value; +- ret = do_dma_transfer(offset, DMA_MEM_TO_DEV); +- if (ret < 0) +- pr_err("error in writing offset 0x%08lx using dma\n", offset); +- mutex_unlock(&tegra_apb_dma_lock); +-} +-#else +-#define tegra_apb_readl_using_dma tegra_apb_readl_direct +-#define tegra_apb_writel_using_dma tegra_apb_writel_direct +-#endif +- +-typedef u32 (*apbio_read_fptr)(unsigned long offset); +-typedef void (*apbio_write_fptr)(u32 value, unsigned long offset); +- +-static apbio_read_fptr apbio_read; +-static apbio_write_fptr apbio_write; +- +-static u32 tegra_apb_readl_direct(unsigned long offset) +-{ +- return readl(IO_ADDRESS(offset)); +-} +- +-static void tegra_apb_writel_direct(u32 value, unsigned long offset) +-{ +- writel(value, IO_ADDRESS(offset)); +-} +- +-void tegra_apb_io_init(void) +-{ +- /* Need to use dma only when it is Tegra20 based platform */ +- if (of_machine_is_compatible("nvidia,tegra20") || +- !of_have_populated_dt()) { +- apbio_read = tegra_apb_readl_using_dma; +- apbio_write = tegra_apb_writel_using_dma; +- } else { +- apbio_read = tegra_apb_readl_direct; +- apbio_write = tegra_apb_writel_direct; +- } +-} +- +-u32 tegra_apb_readl(unsigned long offset) +-{ +- return apbio_read(offset); +-} +- +-void tegra_apb_writel(u32 value, unsigned long offset) +-{ +- apbio_write(value, offset); +-} +diff --git a/arch/arm/mach-tegra/apbio.h b/arch/arm/mach-tegra/apbio.h +deleted file mode 100644 +index f05d71c..0000000 +--- a/arch/arm/mach-tegra/apbio.h ++++ /dev/null +@@ -1,22 +0,0 @@ +-/* +- * 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 +- +-void tegra_apb_io_init(void); +-u32 tegra_apb_readl(unsigned long offset); +-void tegra_apb_writel(u32 value, unsigned long offset); +-#endif +diff --git a/arch/arm/mach-tegra/cpuidle.c b/arch/arm/mach-tegra/cpuidle.c +index 7bc5d8d..ff0a10b 100644 +--- a/arch/arm/mach-tegra/cpuidle.c ++++ b/arch/arm/mach-tegra/cpuidle.c +@@ -23,8 +23,8 @@ + + #include <linux/kernel.h> + #include <linux/module.h> ++#include <linux/tegra-soc.h> + +-#include "fuse.h" + #include "cpuidle.h" + + void __init tegra_cpuidle_init(void) +diff --git a/arch/arm/mach-tegra/flowctrl.c b/arch/arm/mach-tegra/flowctrl.c +index ce8ab8a..4b31091 100644 +--- a/arch/arm/mach-tegra/flowctrl.c ++++ b/arch/arm/mach-tegra/flowctrl.c +@@ -22,10 +22,10 @@ + #include <linux/kernel.h> + #include <linux/io.h> + #include <linux/cpumask.h> ++#include <linux/tegra-soc.h> + + #include "flowctrl.h" + #include "iomap.h" +-#include "fuse.h" + + static u8 flowctrl_offset_halt_cpu[] = { + FLOW_CTRL_HALT_CPU0_EVENTS, +diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c +deleted file mode 100644 +index c9ac23b..0000000 +--- a/arch/arm/mach-tegra/fuse.c ++++ /dev/null +@@ -1,252 +0,0 @@ +-/* +- * arch/arm/mach-tegra/fuse.c +- * +- * Copyright (C) 2010 Google, Inc. +- * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. +- * +- * Author: +- * Colin Cross <ccross@android.com> +- * +- * 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/export.h> +-#include <linux/random.h> +-#include <linux/clk.h> +-#include <linux/tegra-soc.h> +- +-#include "fuse.h" +-#include "iomap.h" +-#include "apbio.h" +- +-/* Tegra20 only */ +-#define FUSE_UID_LOW 0x108 +-#define FUSE_UID_HIGH 0x10c +- +-/* Tegra30 and later */ +-#define FUSE_VENDOR_CODE 0x200 +-#define FUSE_FAB_CODE 0x204 +-#define FUSE_LOT_CODE_0 0x208 +-#define FUSE_LOT_CODE_1 0x20c +-#define FUSE_WAFER_ID 0x210 +-#define FUSE_X_COORDINATE 0x214 +-#define FUSE_Y_COORDINATE 0x218 +- +-#define FUSE_SKU_INFO 0x110 +- +-#define TEGRA20_FUSE_SPARE_BIT 0x200 +-#define TEGRA30_FUSE_SPARE_BIT 0x244 +- +-int tegra_sku_id; +-int tegra_cpu_process_id; +-int tegra_core_process_id; +-int tegra_chip_id; +-int tegra_cpu_speedo_id; /* only exist in Tegra30 and later */ +-int tegra_soc_speedo_id; +-enum tegra_revision tegra_revision; +- +-static struct clk *fuse_clk; +-static int tegra_fuse_spare_bit; +-static void (*tegra_init_speedo_data)(void); +- +-/* 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 void tegra_fuse_enable_clk(void) +-{ +- if (IS_ERR(fuse_clk)) +- fuse_clk = clk_get_sys(NULL, "fuse"); +- if (IS_ERR(fuse_clk)) +- return; +- clk_prepare_enable(fuse_clk); +-} +- +-static void tegra_fuse_disable_clk(void) +-{ +- if (IS_ERR(fuse_clk)) +- return; +- clk_disable_unprepare(fuse_clk); +-} +- +-u32 tegra_fuse_readl(unsigned long offset) +-{ +- return tegra_apb_readl(TEGRA_FUSE_BASE + offset); +-} +- +-bool tegra_spare_fuse(int bit) +-{ +- bool ret; +- +- tegra_fuse_enable_clk(); +- +- ret = tegra_fuse_readl(tegra_fuse_spare_bit + bit * 4); +- +- tegra_fuse_disable_clk(); +- +- return ret; +-} +- +-static enum tegra_revision tegra_get_revision(u32 id) +-{ +- u32 minor_rev = (id >> 16) & 0xf; +- +- switch (minor_rev) { +- case 1: +- return TEGRA_REVISION_A01; +- case 2: +- return TEGRA_REVISION_A02; +- case 3: +- if (tegra_chip_id == TEGRA20 && +- (tegra_spare_fuse(18) || tegra_spare_fuse(19))) +- return TEGRA_REVISION_A03p; +- else +- return TEGRA_REVISION_A03; +- case 4: +- return TEGRA_REVISION_A04; +- default: +- return TEGRA_REVISION_UNKNOWN; +- } +-} +- +-static void tegra_get_process_id(void) +-{ +- u32 reg; +- +- tegra_fuse_enable_clk(); +- +- reg = tegra_fuse_readl(tegra_fuse_spare_bit); +- tegra_cpu_process_id = (reg >> 6) & 3; +- reg = tegra_fuse_readl(tegra_fuse_spare_bit); +- tegra_core_process_id = (reg >> 12) & 3; +- +- tegra_fuse_disable_clk(); +-} +- +-u32 tegra_read_chipid(void) +-{ +- return readl_relaxed(IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804); +-} +- +-static void __init tegra20_fuse_init_randomness(void) +-{ +- u32 randomness[2]; +- +- randomness[0] = tegra_fuse_readl(FUSE_UID_LOW); +- randomness[1] = tegra_fuse_readl(FUSE_UID_HIGH); +- +- add_device_randomness(randomness, sizeof(randomness)); +-} +- +-/* Applies to Tegra30 or later */ +-static void __init tegra30_fuse_init_randomness(void) +-{ +- u32 randomness[7]; +- +- randomness[0] = tegra_fuse_readl(FUSE_VENDOR_CODE); +- randomness[1] = tegra_fuse_readl(FUSE_FAB_CODE); +- randomness[2] = tegra_fuse_readl(FUSE_LOT_CODE_0); +- randomness[3] = tegra_fuse_readl(FUSE_LOT_CODE_1); +- randomness[4] = tegra_fuse_readl(FUSE_WAFER_ID); +- randomness[5] = tegra_fuse_readl(FUSE_X_COORDINATE); +- randomness[6] = tegra_fuse_readl(FUSE_Y_COORDINATE); +- +- add_device_randomness(randomness, sizeof(randomness)); +-} +- +-void __init tegra_init_fuse(void) +-{ +- u32 id; +- u32 randomness[5]; +- +- u32 reg = readl(IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x48)); +- reg |= 1 << 28; +- writel(reg, IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x48)); +- +- /* +- * Enable FUSE clock. This needs to be hardcoded because the clock +- * subsystem is not active during early boot. +- */ +- reg = readl(IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x14)); +- reg |= 1 << 7; +- writel(reg, IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x14)); +- fuse_clk = ERR_PTR(-EINVAL); +- +- reg = tegra_fuse_readl(FUSE_SKU_INFO); +- randomness[0] = reg; +- tegra_sku_id = reg & 0xFF; +- +- reg = tegra_apb_readl(TEGRA_APB_MISC_BASE + STRAP_OPT); +- randomness[1] = reg; +- tegra_bct_strapping = (reg & RAM_ID_MASK) >> RAM_CODE_SHIFT; +- +- id = tegra_read_chipid(); +- randomness[2] = id; +- tegra_chip_id = (id >> 8) & 0xff; +- +- switch (tegra_chip_id) { +- case TEGRA20: +- tegra_fuse_spare_bit = TEGRA20_FUSE_SPARE_BIT; +- tegra_init_speedo_data = &tegra20_init_speedo_data; +- break; +- case TEGRA30: +- tegra_fuse_spare_bit = TEGRA30_FUSE_SPARE_BIT; +- tegra_init_speedo_data = &tegra30_init_speedo_data; +- break; +- case TEGRA114: +- tegra_init_speedo_data = &tegra114_init_speedo_data; +- break; +- default: +- pr_warn("Tegra: unknown chip id %d\n", tegra_chip_id); +- tegra_fuse_spare_bit = TEGRA20_FUSE_SPARE_BIT; +- tegra_init_speedo_data = &tegra_get_process_id; +- } +- +- tegra_revision = tegra_get_revision(id); +- tegra_init_speedo_data(); +- randomness[3] = (tegra_cpu_process_id << 16) | tegra_core_process_id; +- randomness[4] = (tegra_cpu_speedo_id << 16) | tegra_soc_speedo_id; +- +- add_device_randomness(randomness, sizeof(randomness)); +- switch (tegra_chip_id) { +- case TEGRA20: +- tegra20_fuse_init_randomness(); +- break; +- case TEGRA30: +- case TEGRA114: +- default: +- tegra30_fuse_init_randomness(); +- break; +- } +- +- pr_info("Tegra Revision: %s SKU: %d CPU Process: %d Core Process: %d\n", +- tegra_revision_name[tegra_revision], +- tegra_sku_id, tegra_cpu_process_id, +- tegra_core_process_id); +-} +diff --git a/arch/arm/mach-tegra/fuse.h b/arch/arm/mach-tegra/fuse.h +deleted file mode 100644 +index c01d047..0000000 +--- a/arch/arm/mach-tegra/fuse.h ++++ /dev/null +@@ -1,79 +0,0 @@ +-/* +- * Copyright (C) 2010 Google, Inc. +- * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. +- * +- * Author: +- * Colin Cross <ccross@android.com> +- * +- * 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_FUSE_H +-#define __MACH_TEGRA_FUSE_H +- +-#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 +- +-#define TEGRA20 0x20 +-#define TEGRA30 0x30 +-#define TEGRA114 0x35 +-#define TEGRA124 0x40 +- +-#ifndef __ASSEMBLY__ +-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, +-}; +- +-extern int tegra_sku_id; +-extern int tegra_cpu_process_id; +-extern int tegra_core_process_id; +-extern int tegra_chip_id; +-extern int tegra_cpu_speedo_id; /* only exist in Tegra30 and later */ +-extern int tegra_soc_speedo_id; +-extern enum tegra_revision tegra_revision; +- +-extern int tegra_bct_strapping; +- +-unsigned long long tegra_chip_uid(void); +-void tegra_init_fuse(void); +-bool tegra_spare_fuse(int bit); +-u32 tegra_fuse_readl(unsigned long offset); +- +-#ifdef CONFIG_ARCH_TEGRA_2x_SOC +-void tegra20_init_speedo_data(void); +-#else +-static inline void tegra20_init_speedo_data(void) {} +-#endif +- +-#ifdef CONFIG_ARCH_TEGRA_3x_SOC +-void tegra30_init_speedo_data(void); +-#else +-static inline void tegra30_init_speedo_data(void) {} +-#endif +- +-#ifdef CONFIG_ARCH_TEGRA_114_SOC +-void tegra114_init_speedo_data(void); +-#else +-static inline void tegra114_init_speedo_data(void) {} +-#endif +-#endif /* __ASSEMBLY__ */ +- +-#endif +diff --git a/arch/arm/mach-tegra/hotplug.c b/arch/arm/mach-tegra/hotplug.c +index ff26af2..38c5170 100644 +--- a/arch/arm/mach-tegra/hotplug.c ++++ b/arch/arm/mach-tegra/hotplug.c +@@ -10,10 +10,10 @@ + #include <linux/kernel.h> + #include <linux/smp.h> + #include <linux/clk/tegra.h> ++#include <linux/tegra-soc.h> + + #include <asm/smp_plat.h> + +-#include "fuse.h" + #include "sleep.h" + + static void (*tegra_hotplug_shutdown)(void); +diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c +index 929d104..d9878ac 100644 +--- a/arch/arm/mach-tegra/platsmp.c ++++ b/arch/arm/mach-tegra/platsmp.c +@@ -19,13 +19,13 @@ + #include <linux/smp.h> + #include <linux/io.h> + #include <linux/clk/tegra.h> ++#include <linux/tegra-soc.h> + + #include <asm/cacheflush.h> + #include <asm/mach-types.h> + #include <asm/smp_scu.h> + #include <asm/smp_plat.h> + +-#include "fuse.h" + #include "flowctrl.h" + #include "reset.h" + #include "pmc.h" +diff --git a/arch/arm/mach-tegra/pm.c b/arch/arm/mach-tegra/pm.c +index f55b05a..d7e6370 100644 +--- a/arch/arm/mach-tegra/pm.c ++++ b/arch/arm/mach-tegra/pm.c +@@ -26,6 +26,7 @@ + #include <linux/err.h> + #include <linux/slab.h> + #include <linux/clk/tegra.h> ++#include <linux/tegra-soc.h> + + #include <asm/smp_plat.h> + #include <asm/cacheflush.h> +@@ -37,7 +38,6 @@ + #include "iomap.h" + #include "reset.h" + #include "flowctrl.h" +-#include "fuse.h" + #include "pm.h" + #include "pmc.h" + #include "sleep.h" +diff --git a/arch/arm/mach-tegra/pmc.c b/arch/arm/mach-tegra/pmc.c +index 7c7123e..e1677c0 100644 +--- a/arch/arm/mach-tegra/pmc.c ++++ b/arch/arm/mach-tegra/pmc.c +@@ -17,13 +17,12 @@ + + #include <linux/kernel.h> + #include <linux/clk.h> +-#include <linux/io.h> + #include <linux/of.h> + #include <linux/of_address.h> + #include <linux/tegra-powergate.h> ++#include <linux/tegra-soc.h> + + #include "flowctrl.h" +-#include "fuse.h" + #include "pm.h" + #include "pmc.h" + #include "sleep.h" +@@ -60,9 +59,9 @@ static u8 tegra_cpu_domains[] = { + }; + static DEFINE_SPINLOCK(tegra_powergate_lock); + +-static void __iomem *tegra_pmc_base; + static bool tegra_pmc_invert_interrupt; + static struct clk *tegra_pclk; ++void __iomem *tegra_pmc_base; + + struct pmc_pm_data { + u32 cpu_good_time; /* CPU power good time in uS */ +@@ -80,16 +79,6 @@ struct pmc_pm_data { + }; + static struct pmc_pm_data pmc_pm_data; + +-static inline u32 tegra_pmc_readl(u32 reg) +-{ +- return readl(tegra_pmc_base + reg); +-} +- +-static inline void tegra_pmc_writel(u32 val, u32 reg) +-{ +- writel(val, tegra_pmc_base + reg); +-} +- + static int tegra_pmc_get_cpu_powerdomain_id(int cpuid) + { + if (cpuid <= 0 || cpuid >= num_possible_cpus()) +diff --git a/arch/arm/mach-tegra/pmc.h b/arch/arm/mach-tegra/pmc.h +index 59e19c34..139a3086 100644 +--- a/arch/arm/mach-tegra/pmc.h ++++ b/arch/arm/mach-tegra/pmc.h +@@ -18,6 +18,7 @@ + #ifndef __MACH_TEGRA_PMC_H + #define __MACH_TEGRA_PMC_H + ++#include <linux/io.h> + #include <linux/reboot.h> + + enum tegra_suspend_mode { +@@ -37,6 +38,18 @@ void tegra_pmc_pm_set(enum tegra_suspend_mode mode); + void tegra_pmc_suspend_init(void); + #endif + ++extern void __iomem *tegra_pmc_base; ++ ++static inline u32 tegra_pmc_readl(u32 reg) ++{ ++ return readl(tegra_pmc_base + reg); ++} ++ ++static inline void tegra_pmc_writel(u32 val, u32 reg) ++{ ++ writel(val, tegra_pmc_base + reg); ++} ++ + bool tegra_pmc_cpu_is_powered(int cpuid); + int tegra_pmc_cpu_power_on(int cpuid); + int tegra_pmc_cpu_remove_clamping(int cpuid); +diff --git a/arch/arm/mach-tegra/powergate.c b/arch/arm/mach-tegra/powergate.c +index 4cefc5c..c90f303 100644 +--- a/arch/arm/mach-tegra/powergate.c ++++ b/arch/arm/mach-tegra/powergate.c +@@ -30,9 +30,9 @@ + #include <linux/spinlock.h> + #include <linux/clk/tegra.h> + #include <linux/tegra-powergate.h> ++#include <linux/tegra-soc.h> + +-#include "fuse.h" +-#include "iomap.h" ++#include "pmc.h" + + #define DPD_SAMPLE 0x020 + #define DPD_SAMPLE_ENABLE (1 << 0) +@@ -85,18 +85,6 @@ static const u8 tegra124_cpu_domains[] = { + + static DEFINE_SPINLOCK(tegra_powergate_lock); + +-static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE); +- +-static u32 pmc_read(unsigned long reg) +-{ +- return readl(pmc + reg); +-} +- +-static void pmc_write(u32 val, unsigned long reg) +-{ +- writel(val, pmc + reg); +-} +- + static int tegra_powergate_set(int id, bool new_state) + { + bool status; +@@ -104,14 +92,14 @@ static int tegra_powergate_set(int id, bool new_state) + + spin_lock_irqsave(&tegra_powergate_lock, flags); + +- status = pmc_read(PWRGATE_STATUS) & (1 << id); ++ status = tegra_pmc_readl(PWRGATE_STATUS) & (1 << id); + + if (status == new_state) { + spin_unlock_irqrestore(&tegra_powergate_lock, flags); + return 0; + } + +- pmc_write(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE); ++ tegra_pmc_writel(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE); + + spin_unlock_irqrestore(&tegra_powergate_lock, flags); + +@@ -142,7 +130,7 @@ int tegra_powergate_is_powered(int id) + if (id < 0 || id >= tegra_num_powerdomains) + return -EINVAL; + +- status = pmc_read(PWRGATE_STATUS) & (1 << id); ++ status = tegra_pmc_readl(PWRGATE_STATUS) & (1 << id); + return !!status; + } + +@@ -159,7 +147,7 @@ int tegra_powergate_remove_clamping(int id) + */ + if (tegra_chip_id == TEGRA124) { + if (id == TEGRA_POWERGATE_3D) { +- pmc_write(0, GPU_RG_CNTRL); ++ tegra_pmc_writel(0, GPU_RG_CNTRL); + return 0; + } + } +@@ -175,7 +163,7 @@ int tegra_powergate_remove_clamping(int id) + else + mask = (1 << id); + +- pmc_write(mask, REMOVE_CLAMPING); ++ tegra_pmc_writel(mask, REMOVE_CLAMPING); + + return 0; + } +@@ -425,12 +413,12 @@ static int tegra_io_rail_prepare(int id, unsigned long *request, + rate = clk_get_rate(clk); + clk_put(clk); + +- pmc_write(DPD_SAMPLE_ENABLE, DPD_SAMPLE); ++ tegra_pmc_writel(DPD_SAMPLE_ENABLE, DPD_SAMPLE); + + /* must be at least 200 ns, in APB (PCLK) clock cycles */ + value = DIV_ROUND_UP(1000000000, rate); + value = DIV_ROUND_UP(200, value); +- pmc_write(value, SEL_DPD_TIM); ++ tegra_pmc_writel(value, SEL_DPD_TIM); + + return 0; + } +@@ -443,7 +431,7 @@ static int tegra_io_rail_poll(unsigned long offset, unsigned long mask, + timeout = jiffies + msecs_to_jiffies(timeout); + + while (time_after(timeout, jiffies)) { +- value = pmc_read(offset); ++ value = tegra_pmc_readl(offset); + if ((value & mask) == val) + return 0; + +@@ -455,7 +443,7 @@ static int tegra_io_rail_poll(unsigned long offset, unsigned long mask, + + static void tegra_io_rail_unprepare(void) + { +- pmc_write(DPD_SAMPLE_DISABLE, DPD_SAMPLE); ++ tegra_pmc_writel(DPD_SAMPLE_DISABLE, DPD_SAMPLE); + } + + int tegra_io_rail_power_on(int id) +@@ -470,11 +458,11 @@ int tegra_io_rail_power_on(int id) + + mask = 1 << bit; + +- value = pmc_read(request); ++ value = tegra_pmc_readl(request); + value |= mask; + value &= ~IO_DPD_REQ_CODE_MASK; + value |= IO_DPD_REQ_CODE_OFF; +- pmc_write(value, request); ++ tegra_pmc_writel(value, request); + + err = tegra_io_rail_poll(status, mask, 0, 250); + if (err < 0) +@@ -498,11 +486,11 @@ int tegra_io_rail_power_off(int id) + + mask = 1 << bit; + +- value = pmc_read(request); ++ value = tegra_pmc_readl(request); + value |= mask; + value &= ~IO_DPD_REQ_CODE_MASK; + value |= IO_DPD_REQ_CODE_ON; +- pmc_write(value, request); ++ tegra_pmc_writel(value, request); + + err = tegra_io_rail_poll(status, mask, mask, 250); + if (err < 0) +diff --git a/arch/arm/mach-tegra/reset-handler.S b/arch/arm/mach-tegra/reset-handler.S +index 578d4d1..b9ff929 100644 +--- a/arch/arm/mach-tegra/reset-handler.S ++++ b/arch/arm/mach-tegra/reset-handler.S +@@ -19,9 +19,9 @@ + + #include <asm/cache.h> + #include <asm/asm-offsets.h> ++#include <linux/tegra-soc.h> + + #include "flowctrl.h" +-#include "fuse.h" + #include "iomap.h" + #include "reset.h" + #include "sleep.h" +diff --git a/arch/arm/mach-tegra/reset.c b/arch/arm/mach-tegra/reset.c +index 146fe8e..203bac5 100644 +--- a/arch/arm/mach-tegra/reset.c ++++ b/arch/arm/mach-tegra/reset.c +@@ -22,12 +22,12 @@ + #include <asm/cacheflush.h> + #include <asm/hardware/cache-l2x0.h> + #include <asm/firmware.h> ++#include <linux/tegra-soc.h> + + #include "iomap.h" + #include "irammap.h" + #include "reset.h" + #include "sleep.h" +-#include "fuse.h" + + #define TEGRA_IRAM_RESET_BASE (TEGRA_IRAM_BASE + \ + TEGRA_IRAM_RESET_HANDLER_OFFSET) +diff --git a/arch/arm/mach-tegra/sleep-tegra30.S b/arch/arm/mach-tegra/sleep-tegra30.S +index b16d4a57..f808c2c 100644 +--- a/arch/arm/mach-tegra/sleep-tegra30.S ++++ b/arch/arm/mach-tegra/sleep-tegra30.S +@@ -15,13 +15,13 @@ + */ + + #include <linux/linkage.h> ++#include <linux/tegra-soc.h> + + #include <asm/assembler.h> + #include <asm/asm-offsets.h> + #include <asm/cache.h> + + #include "irammap.h" +-#include "fuse.h" + #include "sleep.h" + #include "flowctrl.h" + +diff --git a/arch/arm/mach-tegra/tegra.c b/arch/arm/mach-tegra/tegra.c +index 15ac9fc..cf6a7ac 100644 +--- a/arch/arm/mach-tegra/tegra.c ++++ b/arch/arm/mach-tegra/tegra.c +@@ -34,6 +34,7 @@ + #include <linux/usb/tegra_usb_phy.h> + #include <linux/clk/tegra.h> + #include <linux/irqchip.h> ++#include <linux/tegra-soc.h> + + #include <asm/hardware/cache-l2x0.h> + #include <asm/mach-types.h> +@@ -42,11 +43,9 @@ + #include <asm/setup.h> + #include <asm/trusted_foundations.h> + +-#include "apbio.h" + #include "board.h" + #include "common.h" + #include "cpuidle.h" +-#include "fuse.h" + #include "iomap.h" + #include "irq.h" + #include "pmc.h" +@@ -73,7 +72,6 @@ u32 tegra_uart_config[3] = { + static void __init tegra_init_early(void) + { + of_register_trusted_foundations(); +- tegra_apb_io_init(); + tegra_init_fuse(); + tegra_cpu_reset_handler_init(); + tegra_powergate_init(); +@@ -103,7 +101,8 @@ static void __init tegra_dt_init(void) + goto out; + + soc_dev_attr->family = kasprintf(GFP_KERNEL, "Tegra"); +- soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%d", tegra_revision); ++ soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%d", ++ tegra_sku_info.revision); + soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "%d", tegra_chip_id); + + soc_dev = soc_device_register(soc_dev_attr); +diff --git a/arch/arm/mach-tegra/tegra114_speedo.c b/arch/arm/mach-tegra/tegra114_speedo.c +deleted file mode 100644 +index 5218d48..0000000 +--- a/arch/arm/mach-tegra/tegra114_speedo.c ++++ /dev/null +@@ -1,104 +0,0 @@ +-/* +- * Copyright (c) 2013, 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/bug.h> +- +-#include "fuse.h" +- +-#define CORE_PROCESS_CORNERS_NUM 2 +-#define CPU_PROCESS_CORNERS_NUM 2 +- +-enum { +- THRESHOLD_INDEX_0, +- THRESHOLD_INDEX_1, +- THRESHOLD_INDEX_COUNT, +-}; +- +-static const u32 core_process_speedos[][CORE_PROCESS_CORNERS_NUM] = { +- {1123, UINT_MAX}, +- {0, UINT_MAX}, +-}; +- +-static const u32 cpu_process_speedos[][CPU_PROCESS_CORNERS_NUM] = { +- {1695, UINT_MAX}, +- {0, UINT_MAX}, +-}; +- +-static void rev_sku_to_speedo_ids(int rev, int sku, int *threshold) +-{ +- u32 tmp; +- +- switch (sku) { +- case 0x00: +- case 0x10: +- case 0x05: +- case 0x06: +- tegra_cpu_speedo_id = 1; +- tegra_soc_speedo_id = 0; +- *threshold = THRESHOLD_INDEX_0; +- break; +- +- case 0x03: +- case 0x04: +- tegra_cpu_speedo_id = 2; +- tegra_soc_speedo_id = 1; +- *threshold = THRESHOLD_INDEX_1; +- break; +- +- default: +- pr_err("Tegra114 Unknown SKU %d\n", sku); +- tegra_cpu_speedo_id = 0; +- tegra_soc_speedo_id = 0; +- *threshold = THRESHOLD_INDEX_0; +- break; +- } +- +- if (rev == TEGRA_REVISION_A01) { +- tmp = tegra_fuse_readl(0x270) << 1; +- tmp |= tegra_fuse_readl(0x26c); +- if (!tmp) +- tegra_cpu_speedo_id = 0; +- } +-} +- +-void tegra114_init_speedo_data(void) +-{ +- u32 cpu_speedo_val; +- u32 core_speedo_val; +- int threshold; +- int i; +- +- BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) != +- THRESHOLD_INDEX_COUNT); +- BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) != +- THRESHOLD_INDEX_COUNT); +- +- rev_sku_to_speedo_ids(tegra_revision, tegra_sku_id, &threshold); +- +- cpu_speedo_val = tegra_fuse_readl(0x12c) + 1024; +- core_speedo_val = tegra_fuse_readl(0x134); +- +- for (i = 0; i < CPU_PROCESS_CORNERS_NUM; i++) +- if (cpu_speedo_val < cpu_process_speedos[threshold][i]) +- break; +- tegra_cpu_process_id = i; +- +- for (i = 0; i < CORE_PROCESS_CORNERS_NUM; i++) +- if (core_speedo_val < core_process_speedos[threshold][i]) +- break; +- tegra_core_process_id = i; +-} +diff --git a/arch/arm/mach-tegra/tegra20_speedo.c b/arch/arm/mach-tegra/tegra20_speedo.c +deleted file mode 100644 +index fa6eb57..0000000 +--- a/arch/arm/mach-tegra/tegra20_speedo.c ++++ /dev/null +@@ -1,109 +0,0 @@ +-/* +- * 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/bug.h> +- +-#include "fuse.h" +- +-#define CPU_SPEEDO_LSBIT 20 +-#define CPU_SPEEDO_MSBIT 29 +-#define CPU_SPEEDO_REDUND_LSBIT 30 +-#define CPU_SPEEDO_REDUND_MSBIT 39 +-#define CPU_SPEEDO_REDUND_OFFS (CPU_SPEEDO_REDUND_MSBIT - CPU_SPEEDO_MSBIT) +- +-#define CORE_SPEEDO_LSBIT 40 +-#define CORE_SPEEDO_MSBIT 47 +-#define CORE_SPEEDO_REDUND_LSBIT 48 +-#define CORE_SPEEDO_REDUND_MSBIT 55 +-#define CORE_SPEEDO_REDUND_OFFS (CORE_SPEEDO_REDUND_MSBIT - CORE_SPEEDO_MSBIT) +- +-#define SPEEDO_MULT 4 +- +-#define PROCESS_CORNERS_NUM 4 +- +-#define SPEEDO_ID_SELECT_0(rev) ((rev) <= 2) +-#define SPEEDO_ID_SELECT_1(sku) \ +- (((sku) != 20) && ((sku) != 23) && ((sku) != 24) && \ +- ((sku) != 27) && ((sku) != 28)) +- +-enum { +- SPEEDO_ID_0, +- SPEEDO_ID_1, +- SPEEDO_ID_2, +- SPEEDO_ID_COUNT, +-}; +- +-static const u32 cpu_process_speedos[][PROCESS_CORNERS_NUM] = { +- {315, 366, 420, UINT_MAX}, +- {303, 368, 419, UINT_MAX}, +- {316, 331, 383, UINT_MAX}, +-}; +- +-static const u32 core_process_speedos[][PROCESS_CORNERS_NUM] = { +- {165, 195, 224, UINT_MAX}, +- {165, 195, 224, UINT_MAX}, +- {165, 195, 224, UINT_MAX}, +-}; +- +-void tegra20_init_speedo_data(void) +-{ +- u32 reg; +- u32 val; +- int i; +- +- BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) != SPEEDO_ID_COUNT); +- BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) != SPEEDO_ID_COUNT); +- +- if (SPEEDO_ID_SELECT_0(tegra_revision)) +- tegra_soc_speedo_id = SPEEDO_ID_0; +- else if (SPEEDO_ID_SELECT_1(tegra_sku_id)) +- tegra_soc_speedo_id = SPEEDO_ID_1; +- else +- tegra_soc_speedo_id = SPEEDO_ID_2; +- +- val = 0; +- for (i = CPU_SPEEDO_MSBIT; i >= CPU_SPEEDO_LSBIT; i--) { +- reg = tegra_spare_fuse(i) | +- tegra_spare_fuse(i + CPU_SPEEDO_REDUND_OFFS); +- val = (val << 1) | (reg & 0x1); +- } +- val = val * SPEEDO_MULT; +- pr_debug("%s CPU speedo value %u\n", __func__, val); +- +- for (i = 0; i < (PROCESS_CORNERS_NUM - 1); i++) { +- if (val <= cpu_process_speedos[tegra_soc_speedo_id][i]) +- break; +- } +- tegra_cpu_process_id = i; +- +- val = 0; +- for (i = CORE_SPEEDO_MSBIT; i >= CORE_SPEEDO_LSBIT; i--) { +- reg = tegra_spare_fuse(i) | +- tegra_spare_fuse(i + CORE_SPEEDO_REDUND_OFFS); +- val = (val << 1) | (reg & 0x1); +- } +- val = val * SPEEDO_MULT; +- pr_debug("%s Core speedo value %u\n", __func__, val); +- +- for (i = 0; i < (PROCESS_CORNERS_NUM - 1); i++) { +- if (val <= core_process_speedos[tegra_soc_speedo_id][i]) +- break; +- } +- tegra_core_process_id = i; +- +- pr_info("Tegra20 Soc Speedo ID %d", tegra_soc_speedo_id); +-} +diff --git a/arch/arm/mach-tegra/tegra30_speedo.c b/arch/arm/mach-tegra/tegra30_speedo.c +deleted file mode 100644 +index 125cb16..0000000 +--- a/arch/arm/mach-tegra/tegra30_speedo.c ++++ /dev/null +@@ -1,292 +0,0 @@ +-/* +- * 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/bug.h> +- +-#include "fuse.h" +- +-#define CORE_PROCESS_CORNERS_NUM 1 +-#define CPU_PROCESS_CORNERS_NUM 6 +- +-#define FUSE_SPEEDO_CALIB_0 0x114 +-#define FUSE_PACKAGE_INFO 0X1FC +-#define FUSE_TEST_PROG_VER 0X128 +- +-#define G_SPEEDO_BIT_MINUS1 58 +-#define G_SPEEDO_BIT_MINUS1_R 59 +-#define G_SPEEDO_BIT_MINUS2 60 +-#define G_SPEEDO_BIT_MINUS2_R 61 +-#define LP_SPEEDO_BIT_MINUS1 62 +-#define LP_SPEEDO_BIT_MINUS1_R 63 +-#define LP_SPEEDO_BIT_MINUS2 64 +-#define LP_SPEEDO_BIT_MINUS2_R 65 +- +-enum { +- THRESHOLD_INDEX_0, +- THRESHOLD_INDEX_1, +- THRESHOLD_INDEX_2, +- THRESHOLD_INDEX_3, +- THRESHOLD_INDEX_4, +- THRESHOLD_INDEX_5, +- THRESHOLD_INDEX_6, +- THRESHOLD_INDEX_7, +- THRESHOLD_INDEX_8, +- THRESHOLD_INDEX_9, +- THRESHOLD_INDEX_10, +- THRESHOLD_INDEX_11, +- THRESHOLD_INDEX_COUNT, +-}; +- +-static const u32 core_process_speedos[][CORE_PROCESS_CORNERS_NUM] = { +- {180}, +- {170}, +- {195}, +- {180}, +- {168}, +- {192}, +- {180}, +- {170}, +- {195}, +- {180}, +- {180}, +- {180}, +-}; +- +-static const u32 cpu_process_speedos[][CPU_PROCESS_CORNERS_NUM] = { +- {306, 338, 360, 376, UINT_MAX}, +- {295, 336, 358, 375, UINT_MAX}, +- {325, 325, 358, 375, UINT_MAX}, +- {325, 325, 358, 375, UINT_MAX}, +- {292, 324, 348, 364, UINT_MAX}, +- {324, 324, 348, 364, UINT_MAX}, +- {324, 324, 348, 364, UINT_MAX}, +- {295, 336, 358, 375, UINT_MAX}, +- {358, 358, 358, 358, 397, UINT_MAX}, +- {364, 364, 364, 364, 397, UINT_MAX}, +- {295, 336, 358, 375, 391, UINT_MAX}, +- {295, 336, 358, 375, 391, UINT_MAX}, +-}; +- +-static int threshold_index; +-static int package_id; +- +-static void fuse_speedo_calib(u32 *speedo_g, u32 *speedo_lp) +-{ +- u32 reg; +- int ate_ver; +- int bit_minus1; +- int bit_minus2; +- +- reg = tegra_fuse_readl(FUSE_SPEEDO_CALIB_0); +- +- *speedo_lp = (reg & 0xFFFF) * 4; +- *speedo_g = ((reg >> 16) & 0xFFFF) * 4; +- +- ate_ver = tegra_fuse_readl(FUSE_TEST_PROG_VER); +- pr_info("%s: ATE prog ver %d.%d\n", __func__, ate_ver/10, ate_ver%10); +- +- if (ate_ver >= 26) { +- bit_minus1 = tegra_spare_fuse(LP_SPEEDO_BIT_MINUS1); +- bit_minus1 |= tegra_spare_fuse(LP_SPEEDO_BIT_MINUS1_R); +- bit_minus2 = tegra_spare_fuse(LP_SPEEDO_BIT_MINUS2); +- bit_minus2 |= tegra_spare_fuse(LP_SPEEDO_BIT_MINUS2_R); +- *speedo_lp |= (bit_minus1 << 1) | bit_minus2; +- +- bit_minus1 = tegra_spare_fuse(G_SPEEDO_BIT_MINUS1); +- bit_minus1 |= tegra_spare_fuse(G_SPEEDO_BIT_MINUS1_R); +- bit_minus2 = tegra_spare_fuse(G_SPEEDO_BIT_MINUS2); +- bit_minus2 |= tegra_spare_fuse(G_SPEEDO_BIT_MINUS2_R); +- *speedo_g |= (bit_minus1 << 1) | bit_minus2; +- } else { +- *speedo_lp |= 0x3; +- *speedo_g |= 0x3; +- } +-} +- +-static void rev_sku_to_speedo_ids(int rev, int sku) +-{ +- switch (rev) { +- case TEGRA_REVISION_A01: +- tegra_cpu_speedo_id = 0; +- tegra_soc_speedo_id = 0; +- threshold_index = THRESHOLD_INDEX_0; +- break; +- case TEGRA_REVISION_A02: +- case TEGRA_REVISION_A03: +- switch (sku) { +- case 0x87: +- case 0x82: +- tegra_cpu_speedo_id = 1; +- tegra_soc_speedo_id = 1; +- threshold_index = THRESHOLD_INDEX_1; +- break; +- case 0x81: +- switch (package_id) { +- case 1: +- tegra_cpu_speedo_id = 2; +- tegra_soc_speedo_id = 2; +- threshold_index = THRESHOLD_INDEX_2; +- break; +- case 2: +- tegra_cpu_speedo_id = 4; +- tegra_soc_speedo_id = 1; +- threshold_index = THRESHOLD_INDEX_7; +- break; +- default: +- pr_err("Tegra30: Unknown pkg %d\n", package_id); +- BUG(); +- break; +- } +- break; +- case 0x80: +- switch (package_id) { +- case 1: +- tegra_cpu_speedo_id = 5; +- tegra_soc_speedo_id = 2; +- threshold_index = THRESHOLD_INDEX_8; +- break; +- case 2: +- tegra_cpu_speedo_id = 6; +- tegra_soc_speedo_id = 2; +- threshold_index = THRESHOLD_INDEX_9; +- break; +- default: +- pr_err("Tegra30: Unknown pkg %d\n", package_id); +- BUG(); +- break; +- } +- break; +- case 0x83: +- switch (package_id) { +- case 1: +- tegra_cpu_speedo_id = 7; +- tegra_soc_speedo_id = 1; +- threshold_index = THRESHOLD_INDEX_10; +- break; +- case 2: +- tegra_cpu_speedo_id = 3; +- tegra_soc_speedo_id = 2; +- threshold_index = THRESHOLD_INDEX_3; +- break; +- default: +- pr_err("Tegra30: Unknown pkg %d\n", package_id); +- BUG(); +- break; +- } +- break; +- case 0x8F: +- tegra_cpu_speedo_id = 8; +- tegra_soc_speedo_id = 1; +- threshold_index = THRESHOLD_INDEX_11; +- break; +- case 0x08: +- tegra_cpu_speedo_id = 1; +- tegra_soc_speedo_id = 1; +- threshold_index = THRESHOLD_INDEX_4; +- break; +- case 0x02: +- tegra_cpu_speedo_id = 2; +- tegra_soc_speedo_id = 2; +- threshold_index = THRESHOLD_INDEX_5; +- break; +- case 0x04: +- tegra_cpu_speedo_id = 3; +- tegra_soc_speedo_id = 2; +- threshold_index = THRESHOLD_INDEX_6; +- break; +- case 0: +- switch (package_id) { +- case 1: +- tegra_cpu_speedo_id = 2; +- tegra_soc_speedo_id = 2; +- threshold_index = THRESHOLD_INDEX_2; +- break; +- case 2: +- tegra_cpu_speedo_id = 3; +- tegra_soc_speedo_id = 2; +- threshold_index = THRESHOLD_INDEX_3; +- break; +- default: +- pr_err("Tegra30: Unknown pkg %d\n", package_id); +- BUG(); +- break; +- } +- break; +- default: +- pr_warn("Tegra30: Unknown SKU %d\n", sku); +- tegra_cpu_speedo_id = 0; +- tegra_soc_speedo_id = 0; +- threshold_index = THRESHOLD_INDEX_0; +- break; +- } +- break; +- default: +- pr_warn("Tegra30: Unknown chip rev %d\n", rev); +- tegra_cpu_speedo_id = 0; +- tegra_soc_speedo_id = 0; +- threshold_index = THRESHOLD_INDEX_0; +- break; +- } +-} +- +-void tegra30_init_speedo_data(void) +-{ +- u32 cpu_speedo_val; +- u32 core_speedo_val; +- int i; +- +- BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) != +- THRESHOLD_INDEX_COUNT); +- BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) != +- THRESHOLD_INDEX_COUNT); +- +- package_id = tegra_fuse_readl(FUSE_PACKAGE_INFO) & 0x0F; +- +- rev_sku_to_speedo_ids(tegra_revision, tegra_sku_id); +- fuse_speedo_calib(&cpu_speedo_val, &core_speedo_val); +- pr_debug("%s CPU speedo value %u\n", __func__, cpu_speedo_val); +- pr_debug("%s Core speedo value %u\n", __func__, core_speedo_val); +- +- for (i = 0; i < CPU_PROCESS_CORNERS_NUM; i++) { +- if (cpu_speedo_val < cpu_process_speedos[threshold_index][i]) +- break; +- } +- tegra_cpu_process_id = i - 1; +- +- if (tegra_cpu_process_id == -1) { +- pr_warn("Tegra30: CPU speedo value %3d out of range", +- cpu_speedo_val); +- tegra_cpu_process_id = 0; +- tegra_cpu_speedo_id = 1; +- } +- +- for (i = 0; i < CORE_PROCESS_CORNERS_NUM; i++) { +- if (core_speedo_val < core_process_speedos[threshold_index][i]) +- break; +- } +- tegra_core_process_id = i - 1; +- +- if (tegra_core_process_id == -1) { +- pr_warn("Tegra30: CORE speedo value %3d out of range", +- core_speedo_val); +- tegra_core_process_id = 0; +- tegra_soc_speedo_id = 1; +- } +- +- pr_info("Tegra30: CPU Speedo ID %d, Soc Speedo ID %d", +- tegra_cpu_speedo_id, tegra_soc_speedo_id); +-} +diff --git a/drivers/clocksource/tegra20_timer.c b/drivers/clocksource/tegra20_timer.c +index d1869f0..d2616ef 100644 +--- a/drivers/clocksource/tegra20_timer.c ++++ b/drivers/clocksource/tegra20_timer.c +@@ -27,6 +27,7 @@ + #include <linux/of_address.h> + #include <linux/of_irq.h> + #include <linux/sched_clock.h> ++#include <linux/delay.h> + + #include <asm/mach/time.h> + #include <asm/smp_twd.h> +@@ -53,6 +54,8 @@ static void __iomem *rtc_base; + static struct timespec persistent_ts; + static u64 persistent_ms, last_persistent_ms; + ++static struct delay_timer tegra_delay_timer; ++ + #define timer_writel(value, reg) \ + __raw_writel(value, timer_reg_base + (reg)) + #define timer_readl(reg) \ +@@ -139,6 +142,11 @@ static void tegra_read_persistent_clock(struct timespec *ts) + *ts = *tsp; + } + ++static unsigned long tegra_delay_timer_read_counter_long(void) ++{ ++ return readl(timer_reg_base + TIMERUS_CNTR_1US); ++} ++ + static irqreturn_t tegra_timer_interrupt(int irq, void *dev_id) + { + struct clock_event_device *evt = (struct clock_event_device *)dev_id; +@@ -206,6 +214,11 @@ static void __init tegra20_init_timer(struct device_node *np) + BUG(); + } + ++ tegra_delay_timer.read_current_timer = ++ tegra_delay_timer_read_counter_long; ++ tegra_delay_timer.freq = 1000000; ++ register_current_timer_delay(&tegra_delay_timer); ++ + ret = setup_irq(tegra_timer_irq.irq, &tegra_timer_irq); + if (ret) { + pr_err("Failed to register timer IRQ: %d\n", ret); +diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile +index d59ce12..f4ac83b 100644 +--- a/drivers/misc/Makefile ++++ b/drivers/misc/Makefile +@@ -56,3 +56,4 @@ obj-y += mic/ + obj-$(CONFIG_GENWQE) += genwqe/ + obj-$(CONFIG_ECHO) += echo/ + obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o ++obj-y += fuse/ +diff --git a/drivers/misc/fuse/Makefile b/drivers/misc/fuse/Makefile +new file mode 100644 +index 0000000..0679c4f +--- /dev/null ++++ b/drivers/misc/fuse/Makefile +@@ -0,0 +1 @@ ++obj-$(CONFIG_ARCH_TEGRA) += tegra/ +diff --git a/drivers/misc/fuse/tegra/Makefile b/drivers/misc/fuse/tegra/Makefile +new file mode 100644 +index 0000000..3af357d +--- /dev/null ++++ b/drivers/misc/fuse/tegra/Makefile +@@ -0,0 +1,8 @@ ++obj-y += fuse-tegra.o ++obj-y += fuse-tegra30.o ++obj-y += tegra-apbmisc.o ++obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += fuse-tegra20.o ++obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += speedo-tegra20.o ++obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += speedo-tegra30.o ++obj-$(CONFIG_ARCH_TEGRA_114_SOC) += speedo-tegra114.o ++obj-$(CONFIG_ARCH_TEGRA_124_SOC) += speedo-tegra124.o +diff --git a/drivers/misc/fuse/tegra/fuse-tegra.c b/drivers/misc/fuse/tegra/fuse-tegra.c +new file mode 100644 +index 0000000..934073e +--- /dev/null ++++ b/drivers/misc/fuse/tegra/fuse-tegra.c +@@ -0,0 +1,154 @@ ++/* ++ * Copyright (c) 2013-2014, 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/device.h> ++#include <linux/kobject.h> ++#include <linux/kernel.h> ++#include <linux/platform_device.h> ++#include <linux/of.h> ++#include <linux/of_address.h> ++#include <linux/io.h> ++#include <linux/tegra-soc.h> ++ ++#include "fuse.h" ++ ++static u32 (*fuse_readl)(const unsigned int offset); ++static int fuse_size; ++struct tegra_sku_info tegra_sku_info; ++ ++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 u8 fuse_readb(const unsigned int offset) ++{ ++ u32 val; ++ ++ val = fuse_readl(round_down(offset, 4)); ++ val >>= (offset % 4) * 8; ++ val &= 0xff; ++ ++ return val; ++} ++ ++static ssize_t fuse_read(struct file *fd, struct kobject *kobj, ++ struct bin_attribute *attr, char *buf, ++ loff_t pos, size_t size) ++{ ++ int i; ++ ++ if (pos < 0 || pos >= fuse_size) ++ return 0; ++ ++ if (size > fuse_size - pos) ++ size = fuse_size - pos; ++ ++ for (i = 0; i < size; i++) ++ buf[i] = fuse_readb(pos + i); ++ ++ return i; ++} ++ ++static struct bin_attribute fuse_bin_attr = { ++ .attr = { .name = "fuse", .mode = S_IRUGO, }, ++ .read = fuse_read, ++}; ++ ++static const struct of_device_id car_match[] __initconst = { ++ { .compatible = "nvidia,tegra20-car", }, ++ { .compatible = "nvidia,tegra30-car", }, ++ { .compatible = "nvidia,tegra114-car", }, ++ { .compatible = "nvidia,tegra124-car", }, ++ {}, ++}; ++ ++static void tegra_enable_fuse_clk(void __iomem *base) ++{ ++ u32 reg; ++ ++ reg = readl_relaxed(base + 0x48); ++ reg |= 1 << 28; ++ writel(reg, base + 0x48); ++ ++ /* ++ * Enable FUSE clock. This needs to be hardcoded because the clock ++ * subsystem is not active during early boot. ++ */ ++ reg = readl(base + 0x14); ++ reg |= 1 << 7; ++ writel(reg, base + 0x14); ++} ++ ++int tegra_fuse_readl(u32 offset, u32 *val) ++{ ++ if (!fuse_readl) ++ return -EPROBE_DEFER; ++ ++ *val = fuse_readl(offset); ++ ++ return 0; ++} ++ ++int tegra_fuse_create_sysfs(struct device *dev, int size, ++ u32 (*readl)(const unsigned int offset)) ++{ ++ if (fuse_size) ++ return -ENODEV; ++ ++ fuse_bin_attr.size = size; ++ fuse_bin_attr.read = fuse_read; ++ ++ fuse_size = size; ++ fuse_readl = readl; ++ ++ return device_create_bin_file(dev, &fuse_bin_attr); ++} ++ ++void __init tegra_init_fuse(void) ++{ ++ struct device_node *np; ++ void __iomem *car_base; ++ ++ tegra_init_apbmisc(); ++ ++ np = of_find_matching_node(NULL, car_match); ++ car_base = of_iomap(np, 0); ++ if (car_base) { ++ tegra_enable_fuse_clk(car_base); ++ iounmap(car_base); ++ } else { ++ pr_err("Could not enable fuse clk. ioremap tegra car failed.\n"); ++ return; ++ } ++ ++ if (tegra_chip_id == TEGRA20) ++ tegra20_init_fuse_early(); ++ else ++ tegra30_init_fuse_early(); ++ ++ pr_info("Tegra Revision: %s SKU: %d CPU Process: %d Core Process: %d\n", ++ tegra_revision_name[tegra_sku_info.revision], ++ tegra_sku_info.sku_id, tegra_sku_info.cpu_process_id, ++ tegra_sku_info.core_process_id); ++ pr_debug("Tegra CPU Speedo ID %d, Soc Speedo ID %d\n", ++ tegra_sku_info.cpu_speedo_id, tegra_sku_info.soc_speedo_id); ++} +diff --git a/drivers/misc/fuse/tegra/fuse-tegra20.c b/drivers/misc/fuse/tegra/fuse-tegra20.c +new file mode 100644 +index 0000000..c3dcf11 +--- /dev/null ++++ b/drivers/misc/fuse/tegra/fuse-tegra20.c +@@ -0,0 +1,214 @@ ++/* ++ * Copyright (c) 2013-2014, 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/>. ++ * ++ * Based on drivers/misc/eeprom/sunxi_sid.c ++ */ ++ ++#include <linux/device.h> ++#include <linux/clk.h> ++#include <linux/completion.h> ++#include <linux/dmaengine.h> ++#include <linux/dma-mapping.h> ++#include <linux/err.h> ++#include <linux/io.h> ++#include <linux/kernel.h> ++#include <linux/kobject.h> ++#include <linux/of_device.h> ++#include <linux/platform_device.h> ++#include <linux/random.h> ++#include <linux/tegra-soc.h> ++ ++#include "fuse.h" ++ ++#define FUSE_BEGIN 0x100 ++#define FUSE_SIZE 0x1f8 ++#define FUSE_UID_LOW 0x08 ++#define FUSE_UID_HIGH 0x0c ++ ++static phys_addr_t fuse_phys; ++static struct clk *fuse_clk; ++static void __iomem __initdata *fuse_base; ++ ++static DEFINE_MUTEX(apb_dma_lock); ++static DECLARE_COMPLETION(apb_dma_wait); ++static struct dma_chan *apb_dma_chan; ++static struct dma_slave_config dma_sconfig; ++static u32 *apb_buffer; ++static dma_addr_t apb_buffer_phys; ++ ++static void apb_dma_complete(void *args) ++{ ++ complete(&apb_dma_wait); ++} ++ ++static u32 tegra20_fuse_readl(const unsigned int offset) ++{ ++ int ret; ++ u32 val = 0; ++ struct dma_async_tx_descriptor *dma_desc; ++ ++ mutex_lock(&apb_dma_lock); ++ ++ dma_sconfig.src_addr = fuse_phys + FUSE_BEGIN + offset; ++ ret = dmaengine_slave_config(apb_dma_chan, &dma_sconfig); ++ if (ret) ++ goto out; ++ ++ dma_desc = dmaengine_prep_slave_single(apb_dma_chan, apb_buffer_phys, ++ sizeof(u32), DMA_DEV_TO_MEM, ++ DMA_PREP_INTERRUPT | DMA_CTRL_ACK); ++ if (!dma_desc) ++ goto out; ++ ++ dma_desc->callback = apb_dma_complete; ++ dma_desc->callback_param = NULL; ++ ++ reinit_completion(&apb_dma_wait); ++ ++ clk_prepare_enable(fuse_clk); ++ ++ dmaengine_submit(dma_desc); ++ dma_async_issue_pending(apb_dma_chan); ++ ret = wait_for_completion_timeout(&apb_dma_wait, msecs_to_jiffies(50)); ++ ++ if (WARN(ret == 0, "apb read dma timed out")) ++ dmaengine_terminate_all(apb_dma_chan); ++ else ++ val = *apb_buffer; ++ ++ clk_disable_unprepare(fuse_clk); ++out: ++ mutex_unlock(&apb_dma_lock); ++ ++ return val; ++} ++ ++static const struct of_device_id tegra20_fuse_of_match[] = { ++ { .compatible = "nvidia,tegra20-efuse" }, ++ {}, ++}; ++ ++static int apb_dma_init(void) ++{ ++ dma_cap_mask_t mask; ++ ++ dma_cap_zero(mask); ++ dma_cap_set(DMA_SLAVE, mask); ++ apb_dma_chan = dma_request_channel(mask, NULL, NULL); ++ if (!apb_dma_chan) ++ return -EPROBE_DEFER; ++ ++ apb_buffer = dma_alloc_coherent(NULL, sizeof(u32), &apb_buffer_phys, ++ GFP_KERNEL); ++ if (!apb_buffer) { ++ dma_release_channel(apb_dma_chan); ++ return -ENOMEM; ++ } ++ ++ dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; ++ dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; ++ dma_sconfig.src_maxburst = 1; ++ dma_sconfig.dst_maxburst = 1; ++ ++ return 0; ++} ++ ++static int tegra20_fuse_probe(struct platform_device *pdev) ++{ ++ struct resource *res; ++ int err; ++ ++ fuse_clk = devm_clk_get(&pdev->dev, NULL); ++ if (IS_ERR(fuse_clk)) { ++ dev_err(&pdev->dev, "missing clock"); ++ return PTR_ERR(fuse_clk); ++ } ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) ++ return -EINVAL; ++ fuse_phys = res->start; ++ ++ err = apb_dma_init(); ++ if (err) ++ return err; ++ ++ if (tegra_fuse_create_sysfs(&pdev->dev, FUSE_SIZE, tegra20_fuse_readl)) ++ return -ENODEV; ++ ++ dev_dbg(&pdev->dev, "loaded\n"); ++ ++ return 0; ++} ++ ++static struct platform_driver tegra20_fuse_driver = { ++ .probe = tegra20_fuse_probe, ++ .driver = { ++ .name = "tegra20_fuse", ++ .owner = THIS_MODULE, ++ .of_match_table = tegra20_fuse_of_match, ++ } ++}; ++ ++static int __init tegra20_fuse_init(void) ++{ ++ return platform_driver_register(&tegra20_fuse_driver); ++} ++postcore_initcall(tegra20_fuse_init); ++ ++/* Early boot code. This code is called before the devices are created */ ++ ++u32 __init tegra20_fuse_early(const unsigned int offset) ++{ ++ return readl_relaxed(fuse_base + FUSE_BEGIN + offset); ++} ++ ++bool __init tegra20_spare_fuse_early(int spare_bit) ++{ ++ u32 offset = spare_bit * 4; ++ bool value; ++ ++ value = tegra20_fuse_early(offset + 0x100); ++ ++ return value; ++} ++ ++static void __init tegra20_fuse_add_randomness(void) ++{ ++ u32 randomness[7]; ++ ++ randomness[0] = tegra_sku_info.sku_id; ++ randomness[1] = tegra_read_straps(); ++ randomness[2] = tegra_read_chipid(); ++ randomness[3] = tegra_sku_info.cpu_process_id << 16; ++ randomness[3] |= tegra_sku_info.core_process_id; ++ randomness[4] = tegra_sku_info.cpu_speedo_id << 16; ++ randomness[4] |= tegra_sku_info.soc_speedo_id; ++ randomness[5] = tegra20_fuse_early(FUSE_UID_LOW); ++ randomness[6] = tegra20_fuse_early(FUSE_UID_HIGH); ++ ++ add_device_randomness(randomness, sizeof(randomness)); ++} ++ ++void __init tegra20_init_fuse_early(void) ++{ ++ fuse_base = ioremap(TEGRA_FUSE_BASE, TEGRA_FUSE_SIZE); ++ ++ tegra_init_revision(); ++ tegra20_init_speedo_data(&tegra_sku_info); ++ tegra20_fuse_add_randomness(); ++ ++ iounmap(fuse_base); ++} +diff --git a/drivers/misc/fuse/tegra/fuse-tegra30.c b/drivers/misc/fuse/tegra/fuse-tegra30.c +new file mode 100644 +index 0000000..8aef5d0 +--- /dev/null ++++ b/drivers/misc/fuse/tegra/fuse-tegra30.c +@@ -0,0 +1,223 @@ ++/* ++ * Copyright (c) 2013-2014, 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/device.h> ++#include <linux/clk.h> ++#include <linux/err.h> ++#include <linux/io.h> ++#include <linux/kernel.h> ++#include <linux/of_device.h> ++#include <linux/of_address.h> ++#include <linux/platform_device.h> ++#include <linux/random.h> ++#include <linux/tegra-soc.h> ++ ++#include "fuse.h" ++ ++#define FUSE_BEGIN 0x100 ++ ++/* Tegra30 and later */ ++#define FUSE_VENDOR_CODE 0x100 ++#define FUSE_FAB_CODE 0x104 ++#define FUSE_LOT_CODE_0 0x108 ++#define FUSE_LOT_CODE_1 0x10c ++#define FUSE_WAFER_ID 0x110 ++#define FUSE_X_COORDINATE 0x114 ++#define FUSE_Y_COORDINATE 0x118 ++ ++#define FUSE_HAS_REVISION_INFO BIT(0) ++ ++enum speedo_idx { ++ SPEEDO_TEGRA30 = 0, ++ SPEEDO_TEGRA114, ++ SPEEDO_TEGRA124, ++}; ++ ++struct tegra_fuse_info { ++ int size; ++ int spare_bit; ++ enum speedo_idx speedo_idx; ++}; ++ ++static void __iomem *fuse_base; ++static struct clk *fuse_clk; ++static struct tegra_fuse_info *fuse_info; ++ ++u32 tegra30_fuse_readl(const unsigned int offset) ++{ ++ u32 val; ++ ++ /* ++ * early in the boot, the fuse clock will be enabled by ++ * tegra_init_fuse() ++ */ ++ ++ if (fuse_clk) ++ clk_prepare_enable(fuse_clk); ++ ++ val = readl_relaxed(fuse_base + FUSE_BEGIN + offset); ++ ++ if (fuse_clk) ++ clk_disable_unprepare(fuse_clk); ++ ++ return val; ++} ++ ++static struct tegra_fuse_info tegra30_info = { ++ .size = 0x2a4, ++ .spare_bit = 0x144, ++ .speedo_idx = SPEEDO_TEGRA30, ++}; ++ ++static struct tegra_fuse_info tegra114_info = { ++ .size = 0x2a0, ++ .speedo_idx = SPEEDO_TEGRA114, ++}; ++ ++static struct tegra_fuse_info tegra124_info = { ++ .size = 0x300, ++ .speedo_idx = SPEEDO_TEGRA124, ++}; ++ ++static const struct of_device_id tegra30_fuse_of_match[] = { ++ { .compatible = "nvidia,tegra30-efuse", .data = &tegra30_info }, ++ { .compatible = "nvidia,tegra114-efuse", .data = &tegra114_info }, ++ { .compatible = "nvidia,tegra124-efuse", .data = &tegra124_info }, ++ {}, ++}; ++ ++static int tegra30_fuse_probe(struct platform_device *pdev) ++{ ++ const struct of_device_id *of_dev_id; ++ ++ of_dev_id = of_match_device(tegra30_fuse_of_match, &pdev->dev); ++ if (!of_dev_id) ++ return -ENODEV; ++ ++ fuse_clk = devm_clk_get(&pdev->dev, NULL); ++ if (IS_ERR(fuse_clk)) { ++ dev_err(&pdev->dev, "missing clock"); ++ return PTR_ERR(fuse_clk); ++ } ++ ++ platform_set_drvdata(pdev, NULL); ++ ++ if (tegra_fuse_create_sysfs(&pdev->dev, fuse_info->size, ++ tegra30_fuse_readl)) ++ return -ENODEV; ++ ++ dev_dbg(&pdev->dev, "loaded\n"); ++ ++ return 0; ++} ++ ++static struct platform_driver tegra30_fuse_driver = { ++ .probe = tegra30_fuse_probe, ++ .driver = { ++ .name = "tegra_fuse", ++ .owner = THIS_MODULE, ++ .of_match_table = tegra30_fuse_of_match, ++ } ++}; ++ ++static int __init tegra30_fuse_init(void) ++{ ++ return platform_driver_register(&tegra30_fuse_driver); ++} ++postcore_initcall(tegra30_fuse_init); ++ ++/* Early boot code. This code is called before the devices are created */ ++ ++typedef void (*speedo_f)(struct tegra_sku_info *sku_info); ++ ++static speedo_f __initdata speedo_tbl[] = { ++ [SPEEDO_TEGRA30] = tegra30_init_speedo_data, ++ [SPEEDO_TEGRA114] = tegra114_init_speedo_data, ++ [SPEEDO_TEGRA124] = tegra124_init_speedo_data, ++}; ++ ++static void __init tegra30_fuse_add_randomness(void) ++{ ++ u32 randomness[12]; ++ ++ randomness[0] = tegra_sku_info.sku_id; ++ randomness[1] = tegra_read_straps(); ++ randomness[2] = tegra_read_chipid(); ++ randomness[3] = tegra_sku_info.cpu_process_id << 16; ++ randomness[3] |= tegra_sku_info.core_process_id; ++ randomness[4] = tegra_sku_info.cpu_speedo_id << 16; ++ randomness[4] |= tegra_sku_info.soc_speedo_id; ++ randomness[5] = tegra30_fuse_readl(FUSE_VENDOR_CODE); ++ randomness[6] = tegra30_fuse_readl(FUSE_FAB_CODE); ++ randomness[7] = tegra30_fuse_readl(FUSE_LOT_CODE_0); ++ randomness[8] = tegra30_fuse_readl(FUSE_LOT_CODE_1); ++ randomness[9] = tegra30_fuse_readl(FUSE_WAFER_ID); ++ randomness[10] = tegra30_fuse_readl(FUSE_X_COORDINATE); ++ randomness[11] = tegra30_fuse_readl(FUSE_Y_COORDINATE); ++ ++ add_device_randomness(randomness, sizeof(randomness)); ++} ++ ++static void __init legacy_fuse_init(void) ++{ ++ switch (tegra_chip_id) { ++ case TEGRA30: ++ fuse_info = &tegra30_info; ++ break; ++ case TEGRA114: ++ fuse_info = &tegra114_info; ++ break; ++ case TEGRA124: ++ fuse_info = &tegra124_info; ++ break; ++ default: ++ return; ++ } ++ ++ fuse_base = ioremap(TEGRA_FUSE_BASE, TEGRA_FUSE_SIZE); ++} ++ ++bool __init tegra30_spare_fuse(int spare_bit) ++{ ++ u32 offset = fuse_info->spare_bit + spare_bit * 4; ++ ++ return tegra30_fuse_readl(offset) & 1; ++} ++ ++void __init tegra30_init_fuse_early(void) ++{ ++ struct device_node *np; ++ const struct of_device_id *of_match; ++ ++ np = of_find_matching_node_and_match(NULL, tegra30_fuse_of_match, ++ &of_match); ++ if (np) { ++ fuse_base = of_iomap(np, 0); ++ fuse_info = (struct tegra_fuse_info *)of_match->data; ++ } else ++ legacy_fuse_init(); ++ ++ if (!fuse_base) { ++ pr_warn("fuse DT node missing and unknown chip id: 0x%02x\n", ++ tegra_chip_id); ++ return; ++ } ++ ++ tegra_init_revision(); ++ speedo_tbl[fuse_info->speedo_idx](&tegra_sku_info); ++ tegra30_fuse_add_randomness(); ++} +diff --git a/drivers/misc/fuse/tegra/fuse.h b/drivers/misc/fuse/tegra/fuse.h +new file mode 100644 +index 0000000..3a398bf3 +--- /dev/null ++++ b/drivers/misc/fuse/tegra/fuse.h +@@ -0,0 +1,71 @@ ++/* ++ * Copyright (C) 2010 Google, Inc. ++ * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. ++ * ++ * Author: ++ * Colin Cross <ccross@android.com> ++ * ++ * 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 __DRIVERS_MISC_TEGRA_FUSE_H ++#define __DRIVERS_MISC_TEGRA_FUSE_H ++ ++#define TEGRA_FUSE_BASE 0x7000f800 ++#define TEGRA_FUSE_SIZE 0x400 ++ ++int tegra_fuse_create_sysfs(struct device *dev, int size, ++ u32 (*readl)(const unsigned int offset)); ++ ++bool tegra30_spare_fuse(int bit); ++u32 tegra30_fuse_readl(const unsigned int offset); ++void tegra30_init_fuse_early(void); ++void tegra_init_revision(void); ++void tegra_init_apbmisc(void); ++ ++#ifdef CONFIG_ARCH_TEGRA_2x_SOC ++void tegra20_init_speedo_data(struct tegra_sku_info *sku_info); ++bool tegra20_spare_fuse_early(int spare_bit); ++void tegra20_init_fuse_early(void); ++u32 tegra20_fuse_early(const unsigned int offset); ++#else ++static inline void tegra20_init_speedo_data(struct tegra_sku_info *sku_info) {} ++static inline bool tegra20_spare_fuse_early(int spare_bit) ++{ ++ return false; ++} ++static inline void tegra20_init_fuse_early(void) {} ++static inline u32 tegra20_fuse_early(const unsigned int offset) ++{ ++ return 0; ++} ++#endif ++ ++ ++#ifdef CONFIG_ARCH_TEGRA_3x_SOC ++void tegra30_init_speedo_data(struct tegra_sku_info *sku_info); ++#else ++static inline void tegra30_init_speedo_data(struct tegra_sku_info *sku_info) {} ++#endif ++ ++#ifdef CONFIG_ARCH_TEGRA_114_SOC ++void tegra114_init_speedo_data(struct tegra_sku_info *sku_info); ++#else ++static inline void tegra114_init_speedo_data(struct tegra_sku_info *sku_info) {} ++#endif ++ ++#ifdef CONFIG_ARCH_TEGRA_124_SOC ++void tegra124_init_speedo_data(struct tegra_sku_info *sku_info); ++#else ++static inline void tegra124_init_speedo_data(struct tegra_sku_info *sku_info) {} ++#endif ++ ++#endif +diff --git a/drivers/misc/fuse/tegra/speedo-tegra114.c b/drivers/misc/fuse/tegra/speedo-tegra114.c +new file mode 100644 +index 0000000..98d6cde +--- /dev/null ++++ b/drivers/misc/fuse/tegra/speedo-tegra114.c +@@ -0,0 +1,109 @@ ++/* ++ * Copyright (c) 2013-2014, 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/device.h> ++#include <linux/kernel.h> ++#include <linux/bug.h> ++#include <linux/tegra-soc.h> ++ ++#include "fuse.h" ++ ++#define CORE_PROCESS_CORNERS 2 ++#define CPU_PROCESS_CORNERS 2 ++ ++enum { ++ THRESHOLD_INDEX_0, ++ THRESHOLD_INDEX_1, ++ THRESHOLD_INDEX_COUNT, ++}; ++ ++static const u32 __initconst core_process_speedos[][CORE_PROCESS_CORNERS] = { ++ {1123, UINT_MAX}, ++ {0, UINT_MAX}, ++}; ++ ++static const u32 __initconst cpu_process_speedos[][CPU_PROCESS_CORNERS] = { ++ {1695, UINT_MAX}, ++ {0, UINT_MAX}, ++}; ++ ++static void __init rev_sku_to_speedo_ids(struct tegra_sku_info *sku_info, ++ int *threshold) ++{ ++ u32 tmp; ++ u32 sku = sku_info->sku_id; ++ enum tegra_revision rev = sku_info->revision; ++ ++ switch (sku) { ++ case 0x00: ++ case 0x10: ++ case 0x05: ++ case 0x06: ++ sku_info->cpu_speedo_id = 1; ++ sku_info->soc_speedo_id = 0; ++ *threshold = THRESHOLD_INDEX_0; ++ break; ++ ++ case 0x03: ++ case 0x04: ++ sku_info->cpu_speedo_id = 2; ++ sku_info->soc_speedo_id = 1; ++ *threshold = THRESHOLD_INDEX_1; ++ break; ++ ++ default: ++ pr_err("Tegra Unknown SKU %d\n", sku); ++ sku_info->cpu_speedo_id = 0; ++ sku_info->soc_speedo_id = 0; ++ *threshold = THRESHOLD_INDEX_0; ++ break; ++ } ++ ++ if (rev == TEGRA_REVISION_A01) { ++ tmp = tegra30_fuse_readl(0x270) << 1; ++ tmp |= tegra30_fuse_readl(0x26c); ++ if (!tmp) ++ sku_info->cpu_speedo_id = 0; ++ } ++} ++ ++void __init tegra114_init_speedo_data(struct tegra_sku_info *sku_info) ++{ ++ u32 cpu_speedo_val; ++ u32 core_speedo_val; ++ int threshold; ++ int i; ++ ++ BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) != ++ THRESHOLD_INDEX_COUNT); ++ BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) != ++ THRESHOLD_INDEX_COUNT); ++ ++ rev_sku_to_speedo_ids(sku_info, &threshold); ++ ++ cpu_speedo_val = tegra30_fuse_readl(0x12c) + 1024; ++ core_speedo_val = tegra30_fuse_readl(0x134); ++ ++ for (i = 0; i < CPU_PROCESS_CORNERS; i++) ++ if (cpu_speedo_val < cpu_process_speedos[threshold][i]) ++ break; ++ sku_info->cpu_process_id = i; ++ ++ for (i = 0; i < CORE_PROCESS_CORNERS; i++) ++ if (core_speedo_val < core_process_speedos[threshold][i]) ++ break; ++ sku_info->core_process_id = i; ++} +diff --git a/drivers/misc/fuse/tegra/speedo-tegra124.c b/drivers/misc/fuse/tegra/speedo-tegra124.c +new file mode 100644 +index 0000000..a15dd53 +--- /dev/null ++++ b/drivers/misc/fuse/tegra/speedo-tegra124.c +@@ -0,0 +1,167 @@ ++/* ++ * Copyright (c) 2013-2014, 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/device.h> ++#include <linux/kernel.h> ++#include <linux/bug.h> ++#include <linux/tegra-soc.h> ++ ++#include "fuse.h" ++ ++#define CPU_PROCESS_CORNERS 2 ++#define GPU_PROCESS_CORNERS 2 ++#define CORE_PROCESS_CORNERS 2 ++ ++#define FUSE_CPU_SPEEDO_0 0x14 ++#define FUSE_CPU_SPEEDO_1 0x2c ++#define FUSE_CPU_SPEEDO_2 0x30 ++#define FUSE_SOC_SPEEDO_0 0x34 ++#define FUSE_SOC_SPEEDO_1 0x38 ++#define FUSE_SOC_SPEEDO_2 0x3c ++#define FUSE_CPU_IDDQ 0x18 ++#define FUSE_SOC_IDDQ 0x40 ++#define FUSE_GPU_IDDQ 0x128 ++#define FUSE_FT_REV 0x28 ++ ++enum { ++ THRESHOLD_INDEX_0, ++ THRESHOLD_INDEX_1, ++ THRESHOLD_INDEX_COUNT, ++}; ++ ++static const u32 __initconst cpu_process_speedos[][CPU_PROCESS_CORNERS] = { ++ {2190, UINT_MAX}, ++ {0, UINT_MAX}, ++}; ++ ++static const u32 __initconst gpu_process_speedos[][GPU_PROCESS_CORNERS] = { ++ {1965, UINT_MAX}, ++ {0, UINT_MAX}, ++}; ++ ++static const u32 __initconst core_process_speedos[][CORE_PROCESS_CORNERS] = { ++ {2101, UINT_MAX}, ++ {0, UINT_MAX}, ++}; ++ ++static void __init rev_sku_to_speedo_ids(struct tegra_sku_info *sku_info, ++ int *threshold) ++{ ++ int sku = sku_info->sku_id; ++ ++ /* Assign to default */ ++ sku_info->cpu_speedo_id = 0; ++ sku_info->soc_speedo_id = 0; ++ sku_info->gpu_speedo_id = 0; ++ *threshold = THRESHOLD_INDEX_0; ++ ++ switch (sku) { ++ case 0x00: /* Eng sku */ ++ case 0x0F: ++ case 0x23: ++ /* Using the default */ ++ break; ++ case 0x83: ++ sku_info->cpu_speedo_id = 2; ++ break; ++ ++ case 0x1F: ++ case 0x87: ++ case 0x27: ++ sku_info->cpu_speedo_id = 2; ++ sku_info->soc_speedo_id = 0; ++ sku_info->gpu_speedo_id = 1; ++ *threshold = THRESHOLD_INDEX_0; ++ break; ++ case 0x81: ++ case 0x21: ++ case 0x07: ++ sku_info->cpu_speedo_id = 1; ++ sku_info->soc_speedo_id = 1; ++ sku_info->gpu_speedo_id = 1; ++ *threshold = THRESHOLD_INDEX_1; ++ break; ++ case 0x49: ++ case 0x4A: ++ case 0x48: ++ sku_info->cpu_speedo_id = 4; ++ sku_info->soc_speedo_id = 2; ++ sku_info->gpu_speedo_id = 3; ++ *threshold = THRESHOLD_INDEX_1; ++ break; ++ default: ++ pr_err("Tegra Unknown SKU %d\n", sku); ++ /* Using the default for the error case */ ++ break; ++ } ++} ++ ++void __init tegra124_init_speedo_data(struct tegra_sku_info *sku_info) ++{ ++ int i, threshold, cpu_speedo_0_value, soc_speedo_0_value; ++ int cpu_iddq_value, gpu_iddq_value, soc_iddq_value; ++ ++ BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) != ++ THRESHOLD_INDEX_COUNT); ++ BUILD_BUG_ON(ARRAY_SIZE(gpu_process_speedos) != ++ THRESHOLD_INDEX_COUNT); ++ BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) != ++ THRESHOLD_INDEX_COUNT); ++ ++ cpu_speedo_0_value = tegra30_fuse_readl(FUSE_CPU_SPEEDO_0); ++ ++ /* GPU Speedo is stored in CPU_SPEEDO_2 */ ++ sku_info->gpu_speedo_value = tegra30_fuse_readl(FUSE_CPU_SPEEDO_2); ++ ++ soc_speedo_0_value = tegra30_fuse_readl(FUSE_SOC_SPEEDO_0); ++ ++ cpu_iddq_value = tegra30_fuse_readl(FUSE_CPU_IDDQ); ++ soc_iddq_value = tegra30_fuse_readl(FUSE_SOC_IDDQ); ++ gpu_iddq_value = tegra30_fuse_readl(FUSE_GPU_IDDQ); ++ ++ sku_info->cpu_speedo_value = cpu_speedo_0_value; ++ ++ if (sku_info->cpu_speedo_value == 0) { ++ pr_warn("Tegra Warning: Speedo value not fused.\n"); ++ WARN_ON(1); ++ return; ++ } ++ ++ rev_sku_to_speedo_ids(sku_info, &threshold); ++ ++ sku_info->cpu_iddq_value = tegra30_fuse_readl(FUSE_CPU_IDDQ); ++ ++ for (i = 0; i < GPU_PROCESS_CORNERS; i++) ++ if (sku_info->gpu_speedo_value < ++ gpu_process_speedos[threshold][i]) ++ break; ++ sku_info->gpu_process_id = i; ++ ++ for (i = 0; i < CPU_PROCESS_CORNERS; i++) ++ if (sku_info->cpu_speedo_value < ++ cpu_process_speedos[threshold][i]) ++ break; ++ sku_info->cpu_process_id = i; ++ ++ for (i = 0; i < CORE_PROCESS_CORNERS; i++) ++ if (soc_speedo_0_value < ++ core_process_speedos[threshold][i]) ++ break; ++ sku_info->core_process_id = i; ++ ++ pr_debug("Tegra GPU Speedo ID=%d, Speedo Value=%d\n", ++ sku_info->gpu_speedo_id, sku_info->gpu_speedo_value); ++} +diff --git a/drivers/misc/fuse/tegra/speedo-tegra20.c b/drivers/misc/fuse/tegra/speedo-tegra20.c +new file mode 100644 +index 0000000..c951fa4 +--- /dev/null ++++ b/drivers/misc/fuse/tegra/speedo-tegra20.c +@@ -0,0 +1,109 @@ ++/* ++ * Copyright (c) 2012-2014, 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/device.h> ++#include <linux/bug.h> ++#include <linux/tegra-soc.h> ++ ++#include "fuse.h" ++ ++#define CPU_SPEEDO_LSBIT 20 ++#define CPU_SPEEDO_MSBIT 29 ++#define CPU_SPEEDO_REDUND_LSBIT 30 ++#define CPU_SPEEDO_REDUND_MSBIT 39 ++#define CPU_SPEEDO_REDUND_OFFS (CPU_SPEEDO_REDUND_MSBIT - CPU_SPEEDO_MSBIT) ++ ++#define CORE_SPEEDO_LSBIT 40 ++#define CORE_SPEEDO_MSBIT 47 ++#define CORE_SPEEDO_REDUND_LSBIT 48 ++#define CORE_SPEEDO_REDUND_MSBIT 55 ++#define CORE_SPEEDO_REDUND_OFFS (CORE_SPEEDO_REDUND_MSBIT - CORE_SPEEDO_MSBIT) ++ ++#define SPEEDO_MULT 4 ++ ++#define PROCESS_CORNERS_NUM 4 ++ ++#define SPEEDO_ID_SELECT_0(rev) ((rev) <= 2) ++#define SPEEDO_ID_SELECT_1(sku) \ ++ (((sku) != 20) && ((sku) != 23) && ((sku) != 24) && \ ++ ((sku) != 27) && ((sku) != 28)) ++ ++enum { ++ SPEEDO_ID_0, ++ SPEEDO_ID_1, ++ SPEEDO_ID_2, ++ SPEEDO_ID_COUNT, ++}; ++ ++static const u32 __initconst cpu_process_speedos[][PROCESS_CORNERS_NUM] = { ++ {315, 366, 420, UINT_MAX}, ++ {303, 368, 419, UINT_MAX}, ++ {316, 331, 383, UINT_MAX}, ++}; ++ ++static const u32 __initconst core_process_speedos[][PROCESS_CORNERS_NUM] = { ++ {165, 195, 224, UINT_MAX}, ++ {165, 195, 224, UINT_MAX}, ++ {165, 195, 224, UINT_MAX}, ++}; ++ ++void __init tegra20_init_speedo_data(struct tegra_sku_info *sku_info) ++{ ++ u32 reg; ++ u32 val; ++ int i; ++ ++ BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) != SPEEDO_ID_COUNT); ++ BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) != SPEEDO_ID_COUNT); ++ ++ if (SPEEDO_ID_SELECT_0(sku_info->revision)) ++ sku_info->soc_speedo_id = SPEEDO_ID_0; ++ else if (SPEEDO_ID_SELECT_1(sku_info->sku_id)) ++ sku_info->soc_speedo_id = SPEEDO_ID_1; ++ else ++ sku_info->soc_speedo_id = SPEEDO_ID_2; ++ ++ val = 0; ++ for (i = CPU_SPEEDO_MSBIT; i >= CPU_SPEEDO_LSBIT; i--) { ++ reg = tegra20_spare_fuse_early(i) | ++ tegra20_spare_fuse_early(i + CPU_SPEEDO_REDUND_OFFS); ++ val = (val << 1) | (reg & 0x1); ++ } ++ val = val * SPEEDO_MULT; ++ pr_debug("Tegra CPU speedo value %u\n", val); ++ ++ for (i = 0; i < (PROCESS_CORNERS_NUM - 1); i++) { ++ if (val <= cpu_process_speedos[sku_info->soc_speedo_id][i]) ++ break; ++ } ++ sku_info->cpu_process_id = i; ++ ++ val = 0; ++ for (i = CORE_SPEEDO_MSBIT; i >= CORE_SPEEDO_LSBIT; i--) { ++ reg = tegra20_spare_fuse_early(i) | ++ tegra20_spare_fuse_early(i + CORE_SPEEDO_REDUND_OFFS); ++ val = (val << 1) | (reg & 0x1); ++ } ++ val = val * SPEEDO_MULT; ++ pr_debug("Core speedo value %u\n", val); ++ ++ for (i = 0; i < (PROCESS_CORNERS_NUM - 1); i++) { ++ if (val <= core_process_speedos[sku_info->soc_speedo_id][i]) ++ break; ++ } ++ sku_info->core_process_id = i; ++} +diff --git a/drivers/misc/fuse/tegra/speedo-tegra30.c b/drivers/misc/fuse/tegra/speedo-tegra30.c +new file mode 100644 +index 0000000..1a85ad8 +--- /dev/null ++++ b/drivers/misc/fuse/tegra/speedo-tegra30.c +@@ -0,0 +1,287 @@ ++/* ++ * Copyright (c) 2012-2014, 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/device.h> ++#include <linux/kernel.h> ++#include <linux/bug.h> ++#include <linux/tegra-soc.h> ++ ++#include "fuse.h" ++ ++#define CORE_PROCESS_CORNERS 1 ++#define CPU_PROCESS_CORNERS 6 ++ ++#define FUSE_SPEEDO_CALIB_0 0x14 ++#define FUSE_PACKAGE_INFO 0XFC ++#define FUSE_TEST_PROG_VER 0X28 ++ ++#define G_SPEEDO_BIT_MINUS1 58 ++#define G_SPEEDO_BIT_MINUS1_R 59 ++#define G_SPEEDO_BIT_MINUS2 60 ++#define G_SPEEDO_BIT_MINUS2_R 61 ++#define LP_SPEEDO_BIT_MINUS1 62 ++#define LP_SPEEDO_BIT_MINUS1_R 63 ++#define LP_SPEEDO_BIT_MINUS2 64 ++#define LP_SPEEDO_BIT_MINUS2_R 65 ++ ++enum { ++ THRESHOLD_INDEX_0, ++ THRESHOLD_INDEX_1, ++ THRESHOLD_INDEX_2, ++ THRESHOLD_INDEX_3, ++ THRESHOLD_INDEX_4, ++ THRESHOLD_INDEX_5, ++ THRESHOLD_INDEX_6, ++ THRESHOLD_INDEX_7, ++ THRESHOLD_INDEX_8, ++ THRESHOLD_INDEX_9, ++ THRESHOLD_INDEX_10, ++ THRESHOLD_INDEX_11, ++ THRESHOLD_INDEX_COUNT, ++}; ++ ++static const u32 __initconst core_process_speedos[][CORE_PROCESS_CORNERS] = { ++ {180}, ++ {170}, ++ {195}, ++ {180}, ++ {168}, ++ {192}, ++ {180}, ++ {170}, ++ {195}, ++ {180}, ++ {180}, ++ {180}, ++}; ++ ++static const u32 __initconst cpu_process_speedos[][CPU_PROCESS_CORNERS] = { ++ {306, 338, 360, 376, UINT_MAX}, ++ {295, 336, 358, 375, UINT_MAX}, ++ {325, 325, 358, 375, UINT_MAX}, ++ {325, 325, 358, 375, UINT_MAX}, ++ {292, 324, 348, 364, UINT_MAX}, ++ {324, 324, 348, 364, UINT_MAX}, ++ {324, 324, 348, 364, UINT_MAX}, ++ {295, 336, 358, 375, UINT_MAX}, ++ {358, 358, 358, 358, 397, UINT_MAX}, ++ {364, 364, 364, 364, 397, UINT_MAX}, ++ {295, 336, 358, 375, 391, UINT_MAX}, ++ {295, 336, 358, 375, 391, UINT_MAX}, ++}; ++ ++static int threshold_index __initdata; ++ ++static void __init fuse_speedo_calib(u32 *speedo_g, u32 *speedo_lp) ++{ ++ u32 reg; ++ int ate_ver; ++ int bit_minus1; ++ int bit_minus2; ++ ++ reg = tegra30_fuse_readl(FUSE_SPEEDO_CALIB_0); ++ ++ *speedo_lp = (reg & 0xFFFF) * 4; ++ *speedo_g = ((reg >> 16) & 0xFFFF) * 4; ++ ++ ate_ver = tegra30_fuse_readl(FUSE_TEST_PROG_VER); ++ pr_debug("Tegra ATE prog ver %d.%d\n", ate_ver/10, ate_ver%10); ++ ++ if (ate_ver >= 26) { ++ bit_minus1 = tegra30_spare_fuse(LP_SPEEDO_BIT_MINUS1); ++ bit_minus1 |= tegra30_spare_fuse(LP_SPEEDO_BIT_MINUS1_R); ++ bit_minus2 = tegra30_spare_fuse(LP_SPEEDO_BIT_MINUS2); ++ bit_minus2 |= tegra30_spare_fuse(LP_SPEEDO_BIT_MINUS2_R); ++ *speedo_lp |= (bit_minus1 << 1) | bit_minus2; ++ ++ bit_minus1 = tegra30_spare_fuse(G_SPEEDO_BIT_MINUS1); ++ bit_minus1 |= tegra30_spare_fuse(G_SPEEDO_BIT_MINUS1_R); ++ bit_minus2 = tegra30_spare_fuse(G_SPEEDO_BIT_MINUS2); ++ bit_minus2 |= tegra30_spare_fuse(G_SPEEDO_BIT_MINUS2_R); ++ *speedo_g |= (bit_minus1 << 1) | bit_minus2; ++ } else { ++ *speedo_lp |= 0x3; ++ *speedo_g |= 0x3; ++ } ++} ++ ++static void __init rev_sku_to_speedo_ids(struct tegra_sku_info *sku_info) ++{ ++ int package_id = tegra30_fuse_readl(FUSE_PACKAGE_INFO) & 0x0F; ++ ++ switch (sku_info->revision) { ++ case TEGRA_REVISION_A01: ++ sku_info->cpu_speedo_id = 0; ++ sku_info->soc_speedo_id = 0; ++ threshold_index = THRESHOLD_INDEX_0; ++ break; ++ case TEGRA_REVISION_A02: ++ case TEGRA_REVISION_A03: ++ switch (sku_info->sku_id) { ++ case 0x87: ++ case 0x82: ++ sku_info->cpu_speedo_id = 1; ++ sku_info->soc_speedo_id = 1; ++ threshold_index = THRESHOLD_INDEX_1; ++ break; ++ case 0x81: ++ switch (package_id) { ++ case 1: ++ sku_info->cpu_speedo_id = 2; ++ sku_info->soc_speedo_id = 2; ++ threshold_index = THRESHOLD_INDEX_2; ++ break; ++ case 2: ++ sku_info->cpu_speedo_id = 4; ++ sku_info->soc_speedo_id = 1; ++ threshold_index = THRESHOLD_INDEX_7; ++ break; ++ default: ++ pr_err("Tegra Unknown pkg %d\n", package_id); ++ break; ++ } ++ break; ++ case 0x80: ++ switch (package_id) { ++ case 1: ++ sku_info->cpu_speedo_id = 5; ++ sku_info->soc_speedo_id = 2; ++ threshold_index = THRESHOLD_INDEX_8; ++ break; ++ case 2: ++ sku_info->cpu_speedo_id = 6; ++ sku_info->soc_speedo_id = 2; ++ threshold_index = THRESHOLD_INDEX_9; ++ break; ++ default: ++ pr_err("Tegra Unknown pkg %d\n", package_id); ++ break; ++ } ++ break; ++ case 0x83: ++ switch (package_id) { ++ case 1: ++ sku_info->cpu_speedo_id = 7; ++ sku_info->soc_speedo_id = 1; ++ threshold_index = THRESHOLD_INDEX_10; ++ break; ++ case 2: ++ sku_info->cpu_speedo_id = 3; ++ sku_info->soc_speedo_id = 2; ++ threshold_index = THRESHOLD_INDEX_3; ++ break; ++ default: ++ pr_err("Tegra Unknown pkg %d\n", package_id); ++ break; ++ } ++ break; ++ case 0x8F: ++ sku_info->cpu_speedo_id = 8; ++ sku_info->soc_speedo_id = 1; ++ threshold_index = THRESHOLD_INDEX_11; ++ break; ++ case 0x08: ++ sku_info->cpu_speedo_id = 1; ++ sku_info->soc_speedo_id = 1; ++ threshold_index = THRESHOLD_INDEX_4; ++ break; ++ case 0x02: ++ sku_info->cpu_speedo_id = 2; ++ sku_info->soc_speedo_id = 2; ++ threshold_index = THRESHOLD_INDEX_5; ++ break; ++ case 0x04: ++ sku_info->cpu_speedo_id = 3; ++ sku_info->soc_speedo_id = 2; ++ threshold_index = THRESHOLD_INDEX_6; ++ break; ++ case 0: ++ switch (package_id) { ++ case 1: ++ sku_info->cpu_speedo_id = 2; ++ sku_info->soc_speedo_id = 2; ++ threshold_index = THRESHOLD_INDEX_2; ++ break; ++ case 2: ++ sku_info->cpu_speedo_id = 3; ++ sku_info->soc_speedo_id = 2; ++ threshold_index = THRESHOLD_INDEX_3; ++ break; ++ default: ++ pr_err("Tegra Unknown pkg %d\n", package_id); ++ break; ++ } ++ break; ++ default: ++ pr_warn("Tegra Unknown SKU %d\n", sku_info->sku_id); ++ sku_info->cpu_speedo_id = 0; ++ sku_info->soc_speedo_id = 0; ++ threshold_index = THRESHOLD_INDEX_0; ++ break; ++ } ++ break; ++ default: ++ pr_warn("Tegra Unknown chip rev %d\n", sku_info->revision); ++ sku_info->cpu_speedo_id = 0; ++ sku_info->soc_speedo_id = 0; ++ threshold_index = THRESHOLD_INDEX_0; ++ break; ++ } ++} ++ ++void __init tegra30_init_speedo_data(struct tegra_sku_info *sku_info) ++{ ++ u32 cpu_speedo_val; ++ u32 core_speedo_val; ++ int i; ++ ++ BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) != ++ THRESHOLD_INDEX_COUNT); ++ BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) != ++ THRESHOLD_INDEX_COUNT); ++ ++ ++ rev_sku_to_speedo_ids(sku_info); ++ fuse_speedo_calib(&cpu_speedo_val, &core_speedo_val); ++ pr_debug("Tegra CPU speedo value %u\n", cpu_speedo_val); ++ pr_debug("Tegra Core speedo value %u\n", core_speedo_val); ++ ++ for (i = 0; i < CPU_PROCESS_CORNERS; i++) { ++ if (cpu_speedo_val < cpu_process_speedos[threshold_index][i]) ++ break; ++ } ++ sku_info->cpu_process_id = i - 1; ++ ++ if (sku_info->cpu_process_id == -1) { ++ pr_warn("Tegra CPU speedo value %3d out of range", ++ cpu_speedo_val); ++ sku_info->cpu_process_id = 0; ++ sku_info->cpu_speedo_id = 1; ++ } ++ ++ for (i = 0; i < CORE_PROCESS_CORNERS; i++) { ++ if (core_speedo_val < core_process_speedos[threshold_index][i]) ++ break; ++ } ++ sku_info->core_process_id = i - 1; ++ ++ if (sku_info->core_process_id == -1) { ++ pr_warn("Tegra CORE speedo value %3d out of range", ++ core_speedo_val); ++ sku_info->core_process_id = 0; ++ sku_info->soc_speedo_id = 1; ++ } ++} +diff --git a/drivers/misc/fuse/tegra/tegra-apbmisc.c b/drivers/misc/fuse/tegra/tegra-apbmisc.c +new file mode 100644 +index 0000000..43e5bd5 +--- /dev/null ++++ b/drivers/misc/fuse/tegra/tegra-apbmisc.c +@@ -0,0 +1,110 @@ ++/* ++ * Copyright (c) 2014, 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/of.h> ++#include <linux/of_address.h> ++#include <linux/io.h> ++#include <linux/tegra-soc.h> ++ ++#include "fuse.h" ++ ++#define APBMISC_BASE 0x70000800 ++#define APBMISC_SIZE 0x64 ++#define FUSE_SKU_INFO 0x10 ++ ++int tegra_chip_id; ++ ++static void __iomem *apbmisc_base; ++static void __iomem *strapping_base; ++ ++u32 tegra_read_chipid(void) ++{ ++ return readl_relaxed(apbmisc_base + 4); ++} ++ ++u32 tegra_read_straps(void) ++{ ++ if (strapping_base) ++ return readl_relaxed(strapping_base); ++ else ++ return 0; ++} ++ ++static const struct of_device_id apbmisc_match[] __initconst = { ++ { .compatible = "nvidia,tegra20-apbmisc", }, ++ {}, ++}; ++ ++void __init tegra_init_revision(void) ++{ ++ u32 id, minor_rev; ++ int rev; ++ ++ id = tegra_read_chipid(); ++ minor_rev = (id >> 16) & 0xf; ++ ++ switch (minor_rev) { ++ case 1: ++ rev = TEGRA_REVISION_A01; ++ break; ++ case 2: ++ rev = TEGRA_REVISION_A02; ++ break; ++ case 3: ++ if (tegra_chip_id == TEGRA20 && ++ (tegra20_spare_fuse_early(18) || ++ tegra20_spare_fuse_early(19))) ++ rev = TEGRA_REVISION_A03p; ++ else ++ rev = TEGRA_REVISION_A03; ++ break; ++ case 4: ++ rev = TEGRA_REVISION_A04; ++ break; ++ default: ++ rev = TEGRA_REVISION_UNKNOWN; ++ } ++ ++ tegra_sku_info.revision = rev; ++ ++ if (tegra_chip_id == TEGRA20) ++ tegra_sku_info.sku_id = tegra20_fuse_early(FUSE_SKU_INFO); ++ else ++ tegra_sku_info.sku_id = tegra30_fuse_readl(FUSE_SKU_INFO); ++} ++ ++void __init tegra_init_apbmisc(void) ++{ ++ struct device_node *np; ++ u32 id; ++ ++ np = of_find_matching_node(NULL, apbmisc_match); ++ apbmisc_base = of_iomap(np, 0); ++ if (!apbmisc_base) { ++ pr_warn("ioremap tegra apbmisc failed. using %08x instead\n", ++ APBMISC_BASE); ++ apbmisc_base = ioremap(APBMISC_BASE, APBMISC_SIZE); ++ } ++ ++ id = tegra_read_chipid(); ++ tegra_chip_id = (id >> 8) & 0xff; ++ ++ strapping_base = of_iomap(np, 1); ++ if (!strapping_base) ++ pr_err("ioremap tegra strapping_base failed\n"); ++} +diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c +index 083cf37..7df5aaf 100644 +--- a/drivers/pci/host/pci-tegra.c ++++ b/drivers/pci/host/pci-tegra.c +@@ -233,7 +233,6 @@ struct tegra_pcie_soc_data { + bool has_pex_clkreq_en; + bool has_pex_bias_ctrl; + bool has_intr_prsnt_sense; +- bool has_avdd_supply; + bool has_cml_clk; + }; + +@@ -272,9 +271,8 @@ struct tegra_pcie { + unsigned int num_ports; + u32 xbar_config; + +- struct regulator *pex_clk_supply; +- struct regulator *vdd_supply; +- struct regulator *avdd_supply; ++ struct regulator_bulk_data *supplies; ++ unsigned int num_supplies; + + const struct tegra_pcie_soc_data *soc_data; + }; +@@ -894,7 +892,6 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie) + + static void tegra_pcie_power_off(struct tegra_pcie *pcie) + { +- const struct tegra_pcie_soc_data *soc = pcie->soc_data; + int err; + + /* TODO: disable and unprepare clocks? */ +@@ -905,23 +902,9 @@ static void tegra_pcie_power_off(struct tegra_pcie *pcie) + + tegra_powergate_power_off(TEGRA_POWERGATE_PCIE); + +- if (soc->has_avdd_supply) { +- err = regulator_disable(pcie->avdd_supply); +- if (err < 0) +- dev_warn(pcie->dev, +- "failed to disable AVDD regulator: %d\n", +- err); +- } +- +- err = regulator_disable(pcie->pex_clk_supply); ++ err = regulator_bulk_disable(pcie->num_supplies, pcie->supplies); + if (err < 0) +- dev_warn(pcie->dev, "failed to disable pex-clk regulator: %d\n", +- err); +- +- err = regulator_disable(pcie->vdd_supply); +- if (err < 0) +- dev_warn(pcie->dev, "failed to disable VDD regulator: %d\n", +- err); ++ dev_warn(pcie->dev, "failed to disable regulators: %d\n", err); + } + + static int tegra_pcie_power_on(struct tegra_pcie *pcie) +@@ -936,28 +919,9 @@ static int tegra_pcie_power_on(struct tegra_pcie *pcie) + tegra_powergate_power_off(TEGRA_POWERGATE_PCIE); + + /* enable regulators */ +- err = regulator_enable(pcie->vdd_supply); +- if (err < 0) { +- dev_err(pcie->dev, "failed to enable VDD regulator: %d\n", err); +- return err; +- } +- +- err = regulator_enable(pcie->pex_clk_supply); +- if (err < 0) { +- dev_err(pcie->dev, "failed to enable pex-clk regulator: %d\n", +- err); +- return err; +- } +- +- if (soc->has_avdd_supply) { +- err = regulator_enable(pcie->avdd_supply); +- if (err < 0) { +- dev_err(pcie->dev, +- "failed to enable AVDD regulator: %d\n", +- err); +- return err; +- } +- } ++ err = regulator_bulk_enable(pcie->num_supplies, pcie->supplies); ++ if (err < 0) ++ dev_err(pcie->dev, "failed to enable regulators: %d\n", err); + + err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCIE, + pcie->pex_clk, +@@ -1394,14 +1358,83 @@ static int tegra_pcie_get_xbar_config(struct tegra_pcie *pcie, u32 lanes, + return -EINVAL; + } + ++/* ++ * Obtains the list of regulators required for a particular generation of the ++ * IP block. ++ * ++ * This would've been nice to do simply by providing static tables for use ++ * with the regulator_bulk_*() API, but unfortunately Tegra30 is a bit quirky ++ * in that it has two pairs or AVDD_PEX and VDD_PEX supplies (PEXA and PEXB) ++ * and either seems to be optional depending on which ports are being used. ++ */ ++static int tegra_pcie_get_regulators(struct tegra_pcie *pcie, u32 lane_mask) ++{ ++ struct device_node *np = pcie->dev->of_node; ++ unsigned int i = 0; ++ ++ if (of_device_is_compatible(np, "nvidia,tegra30-pcie")) { ++ bool need_pexa = false, need_pexb = false; ++ ++ /* VDD_PEXA and AVDD_PEXA supply lanes 0 to 3 */ ++ if (lane_mask & 0x0f) ++ need_pexa = true; ++ ++ /* VDD_PEXB and AVDD_PEXB supply lanes 4 to 5 */ ++ if (lane_mask & 0x30) ++ need_pexb = true; ++ ++ pcie->num_supplies = 4 + (need_pexa ? 2 : 0) + ++ (need_pexb ? 2 : 0); ++ ++ pcie->supplies = devm_kcalloc(pcie->dev, pcie->num_supplies, ++ sizeof(*pcie->supplies), ++ GFP_KERNEL); ++ if (!pcie->supplies) ++ return -ENOMEM; ++ ++ pcie->supplies[i++].supply = "avdd-pex-pll"; ++ pcie->supplies[i++].supply = "hvdd-pex"; ++ pcie->supplies[i++].supply = "vddio-pex-ctl"; ++ pcie->supplies[i++].supply = "avdd-plle"; ++ ++ if (need_pexa) { ++ pcie->supplies[i++].supply = "avdd-pexa"; ++ pcie->supplies[i++].supply = "vdd-pexa"; ++ } ++ ++ if (need_pexb) { ++ pcie->supplies[i++].supply = "avdd-pexb"; ++ pcie->supplies[i++].supply = "vdd-pexb"; ++ } ++ } else if (of_device_is_compatible(np, "nvidia,tegra20-pcie")) { ++ pcie->num_supplies = 5; ++ ++ pcie->supplies = devm_kcalloc(pcie->dev, pcie->num_supplies, ++ sizeof(*pcie->supplies), ++ GFP_KERNEL); ++ if (!pcie->supplies) ++ return -ENOMEM; ++ ++ pcie->supplies[0].supply = "avdd-pex"; ++ pcie->supplies[1].supply = "vdd-pex"; ++ pcie->supplies[2].supply = "avdd-pex-pll"; ++ pcie->supplies[3].supply = "avdd-plle"; ++ pcie->supplies[4].supply = "vddio-pex-clk"; ++ } ++ ++ return devm_regulator_bulk_get(pcie->dev, pcie->num_supplies, ++ pcie->supplies); ++} ++ + static int tegra_pcie_parse_dt(struct tegra_pcie *pcie) + { + const struct tegra_pcie_soc_data *soc = pcie->soc_data; + struct device_node *np = pcie->dev->of_node, *port; + struct of_pci_range_parser parser; + struct of_pci_range range; ++ u32 lanes = 0, mask = 0; ++ unsigned int lane = 0; + struct resource res; +- u32 lanes = 0; + int err; + + if (of_pci_range_parser_init(&parser, np)) { +@@ -1409,20 +1442,6 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie) + return -EINVAL; + } + +- pcie->vdd_supply = devm_regulator_get(pcie->dev, "vdd"); +- if (IS_ERR(pcie->vdd_supply)) +- return PTR_ERR(pcie->vdd_supply); +- +- pcie->pex_clk_supply = devm_regulator_get(pcie->dev, "pex-clk"); +- if (IS_ERR(pcie->pex_clk_supply)) +- return PTR_ERR(pcie->pex_clk_supply); +- +- if (soc->has_avdd_supply) { +- pcie->avdd_supply = devm_regulator_get(pcie->dev, "avdd"); +- if (IS_ERR(pcie->avdd_supply)) +- return PTR_ERR(pcie->avdd_supply); +- } +- + for_each_of_pci_range(&parser, &range) { + of_pci_range_to_resource(&range, np, &res); + +@@ -1490,8 +1509,13 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie) + + lanes |= value << (index << 3); + +- if (!of_device_is_available(port)) ++ if (!of_device_is_available(port)) { ++ lane += value; + continue; ++ } ++ ++ mask |= ((1 << value) - 1) << lane; ++ lane += value; + + rp = devm_kzalloc(pcie->dev, sizeof(*rp), GFP_KERNEL); + if (!rp) +@@ -1522,6 +1546,10 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie) + return err; + } + ++ err = tegra_pcie_get_regulators(pcie, mask); ++ if (err < 0) ++ return err; ++ + return 0; + } + +@@ -1615,7 +1643,6 @@ static const struct tegra_pcie_soc_data tegra20_pcie_data = { + .has_pex_clkreq_en = false, + .has_pex_bias_ctrl = false, + .has_intr_prsnt_sense = false, +- .has_avdd_supply = false, + .has_cml_clk = false, + }; + +@@ -1627,7 +1654,6 @@ static const struct tegra_pcie_soc_data tegra30_pcie_data = { + .has_pex_clkreq_en = true, + .has_pex_bias_ctrl = true, + .has_intr_prsnt_sense = true, +- .has_avdd_supply = true, + .has_cml_clk = true, + }; + +diff --git a/include/linux/tegra-soc.h b/include/linux/tegra-soc.h +index 95f611d..fcf65ec 100644 +--- a/include/linux/tegra-soc.h ++++ b/include/linux/tegra-soc.h +@@ -17,6 +17,48 @@ + #ifndef __LINUX_TEGRA_SOC_H_ + #define __LINUX_TEGRA_SOC_H_ + ++#define TEGRA20 0x20 ++#define TEGRA30 0x30 ++#define TEGRA114 0x35 ++#define TEGRA124 0x40 ++ ++#define TEGRA_FUSE_SKU_CALIB_0 0xf0 ++#define TEGRA30_FUSE_SATA_CALIB 0x124 ++ ++#ifndef __ASSEMBLY__ ++ ++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, ++}; ++ ++struct tegra_sku_info { ++ int sku_id; ++ int cpu_process_id; ++ int cpu_speedo_id; ++ int cpu_speedo_value; ++ int cpu_iddq_value; ++ int core_process_id; ++ int soc_speedo_id; ++ int gpu_speedo_id; ++ int gpu_process_id; ++ int gpu_speedo_value; ++ enum tegra_revision revision; ++}; ++ ++u32 tegra_read_straps(void); + u32 tegra_read_chipid(void); ++void tegra_init_fuse(void); ++int tegra_fuse_readl(u32 offset, u32 *val); ++ ++extern int tegra_chip_id; ++extern struct tegra_sku_info tegra_sku_info; ++ ++#endif /* __ASSEMBLY__ */ + + #endif /* __LINUX_TEGRA_SOC_H_ */ +diff --git a/init/calibrate.c b/init/calibrate.c +index 520702d..ce635dc 100644 +--- a/init/calibrate.c ++++ b/init/calibrate.c +@@ -262,6 +262,15 @@ unsigned long __attribute__((weak)) calibrate_delay_is_known(void) + return 0; + } + ++/* ++ * Indicate the cpu delay calibration is done. This can be used by ++ * architectures to stop accepting delay timer registrations after this point. ++ */ ++ ++void __attribute__((weak)) calibration_delay_done(void) ++{ ++} ++ + void calibrate_delay(void) + { + unsigned long lpj; +@@ -301,4 +310,6 @@ void calibrate_delay(void) + + loops_per_jiffy = lpj; + printed = true; ++ ++ calibration_delay_done(); + } |