linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/12] Add NVIDIA Tegra FUSE driver
@ 2014-07-11 12:15 Thierry Reding
  2014-07-11 12:16 ` [PATCH 01/12] ARM: tegra: Sort includes alphabetically Thierry Reding
                   ` (12 more replies)
  0 siblings, 13 replies; 38+ messages in thread
From: Thierry Reding @ 2014-07-11 12:15 UTC (permalink / raw)
  To: linux-arm-kernel

From: Thierry Reding <treding@nvidia.com>

This series is an extension of Peter's original series to add a proper
driver for the FUSE block on Tegra.

Patches 1 and 2 are preparatory work that cleans up include lists and
introduces a function to query the Tegra chip ID rather than accessing
a simple variable. This is used by subsequent patches to allow us to
execute code when the variable is accessed to help in pin-pointing
locations where it's accessed before the driver had a chance to
initialize.

Patches 3 through 8 are Peter's series with a fixup patch by Stephen. I
also moved the driver to drivers/soc/tegra/fuse as requested by Olof.

Patches 9 and 10 defer usages of the tegra_get_chip_id() function to a
later stage (pure_initcall). This allows patch 11 to set up the early
FUSE support code from an early initcall. This has the advantage of not
requiring an explicit call from SoC setup code in arch/arm/mach-tegra
and will allow the code to be shared on 64-bit variants of Tegra.

Patch 12 finally turns the PMC and powergate support code into a proper
driver which also sets up a minimal environment from an early initcall.
The driver isn't moved out of arch/arm/mach-tegra yet because people
have suggested drivers/power as a good home, but that whole directory
depends on the POWER_SUPPLY Kconfig symbol yet this driver doesn't have
anything to do with that. Once that debate has been settled the driver
can easily be moved out in a separate patch.

Some of the patches in this series introduce diagnostic WARN() messages
if functions are called without setup having completed. I've booted the
v3.16-rc1 kernel with these changes on top on Tegra20 (TrimSlice),
Tegra30 (Beaver), Tegra114 (Dalmore) and Tegra124 (Jetson TK1) without
encountering any of the diagnostic warnings and without noticing any
breakage.

Olof, this series should address the concerns you expressed after
reviewing Stephen's earlier pull request for Peter's FUSE driver series.
It would be great if you could take another look to see if this is more
according to your taste. I'll see if I can take this through linux-next
for a little and if you have no objections will submit another pull
request next week.

Thierry

Peter De Schrijver (5):
  ARM: tegra: export apb dma readl/writel
  ARM: tegra: move fuse exports to tegra-soc.h
  soc/tegra: Add efuse driver for Tegra
  soc/tegra: Add efuse and apbmisc bindings
  soc/tegra: fuse: move APB DMA into Tegra20 fuse driver

Stephen Warren (1):
  misc: fuse: fix dummy functions

Thierry Reding (6):
  ARM: tegra: Sort includes alphabetically
  ARM: tegra: Use a function to get the chip ID
  ARM: tegra: Setup CPU hotplug in a pure initcall
  ARM: tegra: Always lock the CPU reset vector
  soc/tegra: fuse: Set up in early initcall
  ARM: tegra: Convert PMC to a driver

 Documentation/ABI/testing/sysfs-driver-tegra-fuse  |  11 +
 .../bindings/fuse/nvidia,tegra20-fuse.txt          |  40 +
 .../bindings/misc/nvidia,tegra20-apbmisc.txt       |  13 +
 arch/arm/boot/dts/tegra114.dtsi                    |  15 +
 arch/arm/boot/dts/tegra124.dtsi                    |  15 +
 arch/arm/boot/dts/tegra20.dtsi                     |  15 +
 arch/arm/boot/dts/tegra30.dtsi                     |  15 +
 arch/arm/mach-tegra/Makefile                       |   8 +-
 arch/arm/mach-tegra/apbio.c                        | 206 -----
 arch/arm/mach-tegra/apbio.h                        |  22 -
 arch/arm/mach-tegra/board-paz00.c                  |   3 +-
 arch/arm/mach-tegra/board.h                        |   7 -
 arch/arm/mach-tegra/cpuidle-tegra114.c             |  10 +-
 arch/arm/mach-tegra/cpuidle-tegra20.c              |  16 +-
 arch/arm/mach-tegra/cpuidle-tegra30.c              |  10 +-
 arch/arm/mach-tegra/cpuidle.c                      |   6 +-
 arch/arm/mach-tegra/flowctrl.c                     |  10 +-
 arch/arm/mach-tegra/fuse.c                         | 252 ------
 arch/arm/mach-tegra/fuse.h                         |  79 --
 arch/arm/mach-tegra/hotplug.c                      |  25 +-
 arch/arm/mach-tegra/io.c                           |   8 +-
 arch/arm/mach-tegra/irq.c                          |   8 +-
 arch/arm/mach-tegra/platsmp.c                      |  27 +-
 arch/arm/mach-tegra/pm-tegra20.c                   |   1 +
 arch/arm/mach-tegra/pm-tegra30.c                   |   1 +
 arch/arm/mach-tegra/pm.c                           |  60 +-
 arch/arm/mach-tegra/pm.h                           |  10 +-
 arch/arm/mach-tegra/pmc.c                          | 413 ---------
 arch/arm/mach-tegra/pmc.h                          |  49 --
 arch/arm/mach-tegra/powergate.c                    | 515 -----------
 arch/arm/mach-tegra/reset-handler.S                |   6 +-
 arch/arm/mach-tegra/reset.c                        |  18 +-
 arch/arm/mach-tegra/sleep-tegra30.S                |   6 +-
 arch/arm/mach-tegra/sleep.h                        |   3 -
 arch/arm/mach-tegra/tegra-pmc.c                    | 948 +++++++++++++++++++++
 arch/arm/mach-tegra/tegra.c                        |  35 +-
 drivers/misc/fuse/Makefile                         |   1 +
 drivers/soc/Makefile                               |   1 +
 drivers/soc/tegra/Makefile                         |   1 +
 drivers/soc/tegra/fuse/Makefile                    |   8 +
 drivers/soc/tegra/fuse/fuse-tegra.c                | 158 ++++
 drivers/soc/tegra/fuse/fuse-tegra20.c              | 214 +++++
 drivers/soc/tegra/fuse/fuse-tegra30.c              | 223 +++++
 drivers/soc/tegra/fuse/fuse.h                      |  71 ++
 .../soc/tegra/fuse/speedo-tegra114.c               |  53 +-
 drivers/soc/tegra/fuse/speedo-tegra124.c           | 167 ++++
 .../soc/tegra/fuse/speedo-tegra20.c                |  42 +-
 .../soc/tegra/fuse/speedo-tegra30.c                | 173 ++--
 drivers/soc/tegra/fuse/tegra-apbmisc.c             | 114 +++
 include/linux/tegra-soc.h                          |  89 ++
 50 files changed, 2387 insertions(+), 1814 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-driver-tegra-fuse
 create mode 100644 Documentation/devicetree/bindings/fuse/nvidia,tegra20-fuse.txt
 create mode 100644 Documentation/devicetree/bindings/misc/nvidia,tegra20-apbmisc.txt
 delete mode 100644 arch/arm/mach-tegra/apbio.c
 delete mode 100644 arch/arm/mach-tegra/apbio.h
 delete mode 100644 arch/arm/mach-tegra/fuse.c
 delete mode 100644 arch/arm/mach-tegra/fuse.h
 delete mode 100644 arch/arm/mach-tegra/pmc.c
 delete mode 100644 arch/arm/mach-tegra/pmc.h
 delete mode 100644 arch/arm/mach-tegra/powergate.c
 create mode 100644 arch/arm/mach-tegra/tegra-pmc.c
 create mode 100644 drivers/misc/fuse/Makefile
 create mode 100644 drivers/soc/tegra/Makefile
 create mode 100644 drivers/soc/tegra/fuse/Makefile
 create mode 100644 drivers/soc/tegra/fuse/fuse-tegra.c
 create mode 100644 drivers/soc/tegra/fuse/fuse-tegra20.c
 create mode 100644 drivers/soc/tegra/fuse/fuse-tegra30.c
 create mode 100644 drivers/soc/tegra/fuse/fuse.h
 rename arch/arm/mach-tegra/tegra114_speedo.c => drivers/soc/tegra/fuse/speedo-tegra114.c (55%)
 create mode 100644 drivers/soc/tegra/fuse/speedo-tegra124.c
 rename arch/arm/mach-tegra/tegra20_speedo.c => drivers/soc/tegra/fuse/speedo-tegra20.c (67%)
 rename arch/arm/mach-tegra/tegra30_speedo.c => drivers/soc/tegra/fuse/speedo-tegra30.c (52%)
 create mode 100644 drivers/soc/tegra/fuse/tegra-apbmisc.c

-- 
2.0.1

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 01/12] ARM: tegra: Sort includes alphabetically
  2014-07-11 12:15 [PATCH 00/12] Add NVIDIA Tegra FUSE driver Thierry Reding
@ 2014-07-11 12:16 ` Thierry Reding
  2014-07-11 12:16 ` [PATCH 02/12] ARM: tegra: Use a function to get the chip ID Thierry Reding
                   ` (11 subsequent siblings)
  12 siblings, 0 replies; 38+ messages in thread
From: Thierry Reding @ 2014-07-11 12:16 UTC (permalink / raw)
  To: linux-arm-kernel

From: Thierry Reding <treding@nvidia.com>

If these aren't sorted alphabetically, then the logical choice is to
append new ones, however that creates a lot of potential for conflicts
because every change will then add new includes in the same location.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 arch/arm/mach-tegra/apbio.c            | 12 ++++++------
 arch/arm/mach-tegra/board-paz00.c      |  3 ++-
 arch/arm/mach-tegra/cpuidle-tegra114.c | 10 +++++-----
 arch/arm/mach-tegra/cpuidle-tegra20.c  | 16 ++++++++--------
 arch/arm/mach-tegra/cpuidle-tegra30.c  | 10 +++++-----
 arch/arm/mach-tegra/flowctrl.c         |  4 ++--
 arch/arm/mach-tegra/fuse.c             |  8 ++++----
 arch/arm/mach-tegra/hotplug.c          |  3 ++-
 arch/arm/mach-tegra/io.c               |  8 ++++----
 arch/arm/mach-tegra/irq.c              |  8 ++++----
 arch/arm/mach-tegra/platsmp.c          | 20 ++++++++++----------
 arch/arm/mach-tegra/pm-tegra20.c       |  1 +
 arch/arm/mach-tegra/pm-tegra30.c       |  1 +
 arch/arm/mach-tegra/pm.c               | 22 +++++++++++-----------
 arch/arm/mach-tegra/pmc.c              |  2 +-
 arch/arm/mach-tegra/powergate.c        |  4 ++--
 arch/arm/mach-tegra/reset-handler.S    |  4 ++--
 arch/arm/mach-tegra/reset.c            |  8 ++++----
 arch/arm/mach-tegra/sleep-tegra30.S    |  6 +++---
 arch/arm/mach-tegra/tegra.c            | 18 +++++++++---------
 arch/arm/mach-tegra/tegra114_speedo.c  |  2 +-
 arch/arm/mach-tegra/tegra20_speedo.c   |  2 +-
 arch/arm/mach-tegra/tegra30_speedo.c   |  2 +-
 23 files changed, 89 insertions(+), 85 deletions(-)

diff --git a/arch/arm/mach-tegra/apbio.c b/arch/arm/mach-tegra/apbio.c
index bc471973cf04..5f9647b3f81d 100644
--- a/arch/arm/mach-tegra/apbio.c
+++ b/arch/arm/mach-tegra/apbio.c
@@ -13,15 +13,15 @@
  *
  */
 
-#include <linux/kernel.h>
-#include <linux/io.h>
-#include <linux/of.h>
+#include <linux/completion.h>
 #include <linux/dmaengine.h>
 #include <linux/dma-mapping.h>
-#include <linux/spinlock.h>
-#include <linux/completion.h>
-#include <linux/sched.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
 #include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
 
 #include "apbio.h"
 #include "iomap.h"
diff --git a/arch/arm/mach-tegra/board-paz00.c b/arch/arm/mach-tegra/board-paz00.c
index 9c6029ba526f..bb4782a32713 100644
--- a/arch/arm/mach-tegra/board-paz00.c
+++ b/arch/arm/mach-tegra/board-paz00.c
@@ -17,9 +17,10 @@
  *
  */
 
-#include <linux/platform_device.h>
 #include <linux/gpio/driver.h>
+#include <linux/platform_device.h>
 #include <linux/rfkill-gpio.h>
+
 #include "board.h"
 
 static struct rfkill_gpio_platform_data wifi_rfkill_platform_data = {
diff --git a/arch/arm/mach-tegra/cpuidle-tegra114.c b/arch/arm/mach-tegra/cpuidle-tegra114.c
index b5fb7c110c64..e3ebdce3e71f 100644
--- a/arch/arm/mach-tegra/cpuidle-tegra114.c
+++ b/arch/arm/mach-tegra/cpuidle-tegra114.c
@@ -14,16 +14,16 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <linux/kernel.h>
-#include <linux/module.h>
+#include <asm/firmware.h>
+#include <linux/clockchips.h>
 #include <linux/cpuidle.h>
 #include <linux/cpu_pm.h>
-#include <linux/clockchips.h>
-#include <asm/firmware.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
 
 #include <asm/cpuidle.h>
-#include <asm/suspend.h>
 #include <asm/smp_plat.h>
+#include <asm/suspend.h>
 
 #include "pm.h"
 #include "sleep.h"
diff --git a/arch/arm/mach-tegra/cpuidle-tegra20.c b/arch/arm/mach-tegra/cpuidle-tegra20.c
index b82dcaee2ef4..b30bf5cba65b 100644
--- a/arch/arm/mach-tegra/cpuidle-tegra20.c
+++ b/arch/arm/mach-tegra/cpuidle-tegra20.c
@@ -19,23 +19,23 @@
  * more details.
  */
 
-#include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/clk/tegra.h>
+#include <linux/clockchips.h>
 #include <linux/cpuidle.h>
 #include <linux/cpu_pm.h>
-#include <linux/clockchips.h>
-#include <linux/clk/tegra.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
 
 #include <asm/cpuidle.h>
 #include <asm/proc-fns.h>
-#include <asm/suspend.h>
 #include <asm/smp_plat.h>
+#include <asm/suspend.h>
 
-#include "pm.h"
-#include "sleep.h"
+#include "flowctrl.h"
 #include "iomap.h"
 #include "irq.h"
-#include "flowctrl.h"
+#include "pm.h"
+#include "sleep.h"
 
 #ifdef CONFIG_PM_SLEEP
 static bool abort_flag;
diff --git a/arch/arm/mach-tegra/cpuidle-tegra30.c b/arch/arm/mach-tegra/cpuidle-tegra30.c
index ed2a2a7bae4d..35561274f6cf 100644
--- a/arch/arm/mach-tegra/cpuidle-tegra30.c
+++ b/arch/arm/mach-tegra/cpuidle-tegra30.c
@@ -19,17 +19,17 @@
  * more details.
  */
 
-#include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/clk/tegra.h>
+#include <linux/clockchips.h>
 #include <linux/cpuidle.h>
 #include <linux/cpu_pm.h>
-#include <linux/clockchips.h>
-#include <linux/clk/tegra.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
 
 #include <asm/cpuidle.h>
 #include <asm/proc-fns.h>
-#include <asm/suspend.h>
 #include <asm/smp_plat.h>
+#include <asm/suspend.h>
 
 #include "pm.h"
 #include "sleep.h"
diff --git a/arch/arm/mach-tegra/flowctrl.c b/arch/arm/mach-tegra/flowctrl.c
index ce8ab8abf061..fde581d78398 100644
--- a/arch/arm/mach-tegra/flowctrl.c
+++ b/arch/arm/mach-tegra/flowctrl.c
@@ -18,10 +18,10 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <linux/cpumask.h>
 #include <linux/init.h>
-#include <linux/kernel.h>
 #include <linux/io.h>
-#include <linux/cpumask.h>
+#include <linux/kernel.h>
 
 #include "flowctrl.h"
 #include "iomap.h"
diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c
index c9ac23b385be..573414eaf7ae 100644
--- a/arch/arm/mach-tegra/fuse.c
+++ b/arch/arm/mach-tegra/fuse.c
@@ -18,16 +18,16 @@
  *
  */
 
-#include <linux/kernel.h>
-#include <linux/io.h>
+#include <linux/clk.h>
 #include <linux/export.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
 #include <linux/random.h>
-#include <linux/clk.h>
 #include <linux/tegra-soc.h>
 
+#include "apbio.h"
 #include "fuse.h"
 #include "iomap.h"
-#include "apbio.h"
 
 /* Tegra20 only */
 #define FUSE_UID_LOW		0x108
diff --git a/arch/arm/mach-tegra/hotplug.c b/arch/arm/mach-tegra/hotplug.c
index ff26af26bd0c..7842b252dda5 100644
--- a/arch/arm/mach-tegra/hotplug.c
+++ b/arch/arm/mach-tegra/hotplug.c
@@ -7,9 +7,10 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
+
+#include <linux/clk/tegra.h>
 #include <linux/kernel.h>
 #include <linux/smp.h>
-#include <linux/clk/tegra.h>
 
 #include <asm/smp_plat.h>
 
diff --git a/arch/arm/mach-tegra/io.c b/arch/arm/mach-tegra/io.c
index bb9c9c29d181..352de159d2c5 100644
--- a/arch/arm/mach-tegra/io.c
+++ b/arch/arm/mach-tegra/io.c
@@ -18,14 +18,14 @@
  *
  */
 
-#include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/init.h>
-#include <linux/mm.h>
 #include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
 
-#include <asm/page.h>
 #include <asm/mach/map.h>
+#include <asm/page.h>
 
 #include "board.h"
 #include "iomap.h"
diff --git a/arch/arm/mach-tegra/irq.c b/arch/arm/mach-tegra/irq.c
index 1a74d562dca1..da7be13aecce 100644
--- a/arch/arm/mach-tegra/irq.c
+++ b/arch/arm/mach-tegra/irq.c
@@ -17,14 +17,14 @@
  *
  */
 
-#include <linux/kernel.h>
 #include <linux/cpu_pm.h>
 #include <linux/interrupt.h>
-#include <linux/irq.h>
 #include <linux/io.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
 #include <linux/irqchip/arm-gic.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/of_address.h>
+#include <linux/of.h>
 #include <linux/syscore_ops.h>
 
 #include "board.h"
diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c
index 929d1046e2b4..c403edd0fcc7 100644
--- a/arch/arm/mach-tegra/platsmp.c
+++ b/arch/arm/mach-tegra/platsmp.c
@@ -11,27 +11,27 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-#include <linux/init.h>
-#include <linux/errno.h>
+
+#include <linux/clk/tegra.h>
 #include <linux/delay.h>
 #include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/io.h>
 #include <linux/jiffies.h>
 #include <linux/smp.h>
-#include <linux/io.h>
-#include <linux/clk/tegra.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"
+#include <asm/smp_scu.h>
 
 #include "common.h"
+#include "flowctrl.h"
+#include "fuse.h"
 #include "iomap.h"
+#include "pmc.h"
+#include "reset.h"
 
 static cpumask_t tegra_cpu_init_mask;
 
diff --git a/arch/arm/mach-tegra/pm-tegra20.c b/arch/arm/mach-tegra/pm-tegra20.c
index d65e1d786400..39ac2b723f2e 100644
--- a/arch/arm/mach-tegra/pm-tegra20.c
+++ b/arch/arm/mach-tegra/pm-tegra20.c
@@ -13,6 +13,7 @@
  * 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 "pm.h"
diff --git a/arch/arm/mach-tegra/pm-tegra30.c b/arch/arm/mach-tegra/pm-tegra30.c
index 8fa326d6ff1a..46cc19de9916 100644
--- a/arch/arm/mach-tegra/pm-tegra30.c
+++ b/arch/arm/mach-tegra/pm-tegra30.c
@@ -13,6 +13,7 @@
  * 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 "pm.h"
diff --git a/arch/arm/mach-tegra/pm.c b/arch/arm/mach-tegra/pm.c
index f55b05a29b55..ae4826e43171 100644
--- a/arch/arm/mach-tegra/pm.c
+++ b/arch/arm/mach-tegra/pm.c
@@ -16,30 +16,30 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <linux/kernel.h>
-#include <linux/spinlock.h>
-#include <linux/io.h>
+#include <linux/clk/tegra.h>
 #include <linux/cpumask.h>
-#include <linux/delay.h>
 #include <linux/cpu_pm.h>
-#include <linux/suspend.h>
+#include <linux/delay.h>
 #include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
 #include <linux/slab.h>
-#include <linux/clk/tegra.h>
+#include <linux/spinlock.h>
+#include <linux/suspend.h>
 
-#include <asm/smp_plat.h>
 #include <asm/cacheflush.h>
-#include <asm/suspend.h>
 #include <asm/idmap.h>
 #include <asm/proc-fns.h>
+#include <asm/smp_plat.h>
+#include <asm/suspend.h>
 #include <asm/tlbflush.h>
 
-#include "iomap.h"
-#include "reset.h"
 #include "flowctrl.h"
 #include "fuse.h"
-#include "pm.h"
+#include "iomap.h"
 #include "pmc.h"
+#include "pm.h"
+#include "reset.h"
 #include "sleep.h"
 
 #ifdef CONFIG_PM_SLEEP
diff --git a/arch/arm/mach-tegra/pmc.c b/arch/arm/mach-tegra/pmc.c
index 7c7123e7557b..cff318c17f2c 100644
--- a/arch/arm/mach-tegra/pmc.c
+++ b/arch/arm/mach-tegra/pmc.c
@@ -15,9 +15,9 @@
  *
  */
 
-#include <linux/kernel.h>
 #include <linux/clk.h>
 #include <linux/io.h>
+#include <linux/kernel.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/tegra-powergate.h>
diff --git a/arch/arm/mach-tegra/powergate.c b/arch/arm/mach-tegra/powergate.c
index 4cefc5cd6bed..bbffc9e6d498 100644
--- a/arch/arm/mach-tegra/powergate.c
+++ b/arch/arm/mach-tegra/powergate.c
@@ -17,18 +17,18 @@
  *
  */
 
-#include <linux/kernel.h>
 #include <linux/clk.h>
+#include <linux/clk/tegra.h>
 #include <linux/debugfs.h>
 #include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/export.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/kernel.h>
 #include <linux/reset.h>
 #include <linux/seq_file.h>
 #include <linux/spinlock.h>
-#include <linux/clk/tegra.h>
 #include <linux/tegra-powergate.h>
 
 #include "fuse.h"
diff --git a/arch/arm/mach-tegra/reset-handler.S b/arch/arm/mach-tegra/reset-handler.S
index 578d4d1ad648..d916c84487ae 100644
--- a/arch/arm/mach-tegra/reset-handler.S
+++ b/arch/arm/mach-tegra/reset-handler.S
@@ -14,11 +14,11 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <linux/linkage.h>
 #include <linux/init.h>
+#include <linux/linkage.h>
 
-#include <asm/cache.h>
 #include <asm/asm-offsets.h>
+#include <asm/cache.h>
 
 #include "flowctrl.h"
 #include "fuse.h"
diff --git a/arch/arm/mach-tegra/reset.c b/arch/arm/mach-tegra/reset.c
index 146fe8e0ae7c..b90507922a8c 100644
--- a/arch/arm/mach-tegra/reset.c
+++ b/arch/arm/mach-tegra/reset.c
@@ -14,20 +14,20 @@
  *
  */
 
+#include <linux/bitops.h>
+#include <linux/cpumask.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/cpumask.h>
-#include <linux/bitops.h>
 
 #include <asm/cacheflush.h>
-#include <asm/hardware/cache-l2x0.h>
 #include <asm/firmware.h>
+#include <asm/hardware/cache-l2x0.h>
 
+#include "fuse.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 b16d4a57fa59..e240b875183b 100644
--- a/arch/arm/mach-tegra/sleep-tegra30.S
+++ b/arch/arm/mach-tegra/sleep-tegra30.S
@@ -16,14 +16,14 @@
 
 #include <linux/linkage.h>
 
-#include <asm/assembler.h>
 #include <asm/asm-offsets.h>
+#include <asm/assembler.h>
 #include <asm/cache.h>
 
-#include "irammap.h"
+#include "flowctrl.h"
 #include "fuse.h"
+#include "irammap.h"
 #include "sleep.h"
-#include "flowctrl.h"
 
 #define EMC_CFG				0xc
 #define EMC_ADR_CFG			0x10
diff --git a/arch/arm/mach-tegra/tegra.c b/arch/arm/mach-tegra/tegra.c
index 15ac9fcc96b1..7a9f30289049 100644
--- a/arch/arm/mach-tegra/tegra.c
+++ b/arch/arm/mach-tegra/tegra.c
@@ -16,29 +16,29 @@
  *
  */
 
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/serial_8250.h>
 #include <linux/clk.h>
+#include <linux/clk/tegra.h>
 #include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/irqchip.h>
 #include <linux/irqdomain.h>
-#include <linux/of.h>
+#include <linux/kernel.h>
 #include <linux/of_address.h>
 #include <linux/of_fdt.h>
+#include <linux/of.h>
 #include <linux/of_platform.h>
 #include <linux/pda_power.h>
-#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/serial_8250.h>
 #include <linux/slab.h>
 #include <linux/sys_soc.h>
 #include <linux/usb/tegra_usb_phy.h>
-#include <linux/clk/tegra.h>
-#include <linux/irqchip.h>
 
 #include <asm/hardware/cache-l2x0.h>
-#include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
+#include <asm/mach-types.h>
 #include <asm/setup.h>
 #include <asm/trusted_foundations.h>
 
diff --git a/arch/arm/mach-tegra/tegra114_speedo.c b/arch/arm/mach-tegra/tegra114_speedo.c
index 5218d4853cd3..86eca17e5286 100644
--- a/arch/arm/mach-tegra/tegra114_speedo.c
+++ b/arch/arm/mach-tegra/tegra114_speedo.c
@@ -14,8 +14,8 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <linux/kernel.h>
 #include <linux/bug.h>
+#include <linux/kernel.h>
 
 #include "fuse.h"
 
diff --git a/arch/arm/mach-tegra/tegra20_speedo.c b/arch/arm/mach-tegra/tegra20_speedo.c
index fa6eb570623f..dcd29a0b0187 100644
--- a/arch/arm/mach-tegra/tegra20_speedo.c
+++ b/arch/arm/mach-tegra/tegra20_speedo.c
@@ -14,8 +14,8 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <linux/kernel.h>
 #include <linux/bug.h>
+#include <linux/kernel.h>
 
 #include "fuse.h"
 
diff --git a/arch/arm/mach-tegra/tegra30_speedo.c b/arch/arm/mach-tegra/tegra30_speedo.c
index 125cb16424a6..7c0038326cf5 100644
--- a/arch/arm/mach-tegra/tegra30_speedo.c
+++ b/arch/arm/mach-tegra/tegra30_speedo.c
@@ -14,8 +14,8 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <linux/kernel.h>
 #include <linux/bug.h>
+#include <linux/kernel.h>
 
 #include "fuse.h"
 
-- 
2.0.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 02/12] ARM: tegra: Use a function to get the chip ID
  2014-07-11 12:15 [PATCH 00/12] Add NVIDIA Tegra FUSE driver Thierry Reding
  2014-07-11 12:16 ` [PATCH 01/12] ARM: tegra: Sort includes alphabetically Thierry Reding
@ 2014-07-11 12:16 ` Thierry Reding
  2014-07-11 12:16 ` [PATCH 03/12] ARM: tegra: export apb dma readl/writel Thierry Reding
                   ` (10 subsequent siblings)
  12 siblings, 0 replies; 38+ messages in thread
From: Thierry Reding @ 2014-07-11 12:16 UTC (permalink / raw)
  To: linux-arm-kernel

From: Thierry Reding <treding@nvidia.com>

Instead of using a simple variable access to get at the Tegra chip ID,
use a function so that we can run additional code. This can be used to
determine where the chip ID is being accessed without being available.
That in turn will be handy for resolving boot sequence dependencies in
order to convert more code to regular initcalls rather than a sequence
fixed by Tegra SoC setup code.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 arch/arm/mach-tegra/cpuidle.c       |  6 +++---
 arch/arm/mach-tegra/flowctrl.c      |  6 +++---
 arch/arm/mach-tegra/fuse.c          | 19 +++++++++++++------
 arch/arm/mach-tegra/fuse.h          |  6 ------
 arch/arm/mach-tegra/hotplug.c       | 10 +++++-----
 arch/arm/mach-tegra/platsmp.c       | 10 +++++-----
 arch/arm/mach-tegra/pm.c            | 10 +++++-----
 arch/arm/mach-tegra/pmc.c           |  4 ++--
 arch/arm/mach-tegra/powergate.c     |  8 ++++----
 arch/arm/mach-tegra/reset-handler.S |  2 +-
 arch/arm/mach-tegra/reset.c         |  3 ++-
 arch/arm/mach-tegra/sleep-tegra30.S |  2 +-
 arch/arm/mach-tegra/tegra.c         |  3 ++-
 include/linux/tegra-soc.h           | 10 ++++++++++
 14 files changed, 56 insertions(+), 43 deletions(-)

diff --git a/arch/arm/mach-tegra/cpuidle.c b/arch/arm/mach-tegra/cpuidle.c
index 7bc5d8d667fe..b27330c7bf6c 100644
--- a/arch/arm/mach-tegra/cpuidle.c
+++ b/arch/arm/mach-tegra/cpuidle.c
@@ -23,13 +23,13 @@
 
 #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)
 {
-	switch (tegra_chip_id) {
+	switch (tegra_get_chip_id()) {
 	case TEGRA20:
 		if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC))
 			tegra20_cpuidle_init();
@@ -49,7 +49,7 @@ void __init tegra_cpuidle_init(void)
 
 void tegra_cpuidle_pcie_irqs_in_use(void)
 {
-	switch (tegra_chip_id) {
+	switch (tegra_get_chip_id()) {
 	case TEGRA20:
 		if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC))
 			tegra20_cpuidle_pcie_irqs_in_use();
diff --git a/arch/arm/mach-tegra/flowctrl.c b/arch/arm/mach-tegra/flowctrl.c
index fde581d78398..2106b3dd36bd 100644
--- a/arch/arm/mach-tegra/flowctrl.c
+++ b/arch/arm/mach-tegra/flowctrl.c
@@ -22,10 +22,10 @@
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/kernel.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,
@@ -76,7 +76,7 @@ void flowctrl_cpu_suspend_enter(unsigned int cpuid)
 	int i;
 
 	reg = flowctrl_read_cpu_csr(cpuid);
-	switch (tegra_chip_id) {
+	switch (tegra_get_chip_id()) {
 	case TEGRA20:
 		/* clear wfe bitmap */
 		reg &= ~TEGRA20_FLOW_CTRL_CSR_WFE_BITMAP;
@@ -117,7 +117,7 @@ void flowctrl_cpu_suspend_exit(unsigned int cpuid)
 
 	/* Disable powergating via flow controller for CPU0 */
 	reg = flowctrl_read_cpu_csr(cpuid);
-	switch (tegra_chip_id) {
+	switch (tegra_get_chip_id()) {
 	case TEGRA20:
 		/* clear wfe bitmap */
 		reg &= ~TEGRA20_FLOW_CTRL_CSR_WFE_BITMAP;
diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c
index 573414eaf7ae..e9b01a5cf40e 100644
--- a/arch/arm/mach-tegra/fuse.c
+++ b/arch/arm/mach-tegra/fuse.c
@@ -50,7 +50,6 @@
 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;
@@ -123,7 +122,7 @@ static enum tegra_revision tegra_get_revision(u32 id)
 	case 2:
 		return TEGRA_REVISION_A02;
 	case 3:
-		if (tegra_chip_id == TEGRA20 &&
+		if (tegra_get_chip_id() == TEGRA20 &&
 			(tegra_spare_fuse(18) || tegra_spare_fuse(19)))
 			return TEGRA_REVISION_A03p;
 		else
@@ -154,6 +153,13 @@ u32 tegra_read_chipid(void)
 	return readl_relaxed(IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804);
 }
 
+u8 tegra_get_chip_id(void)
+{
+	u32 id = tegra_read_chipid();
+
+	return (id >> 8) & 0xff;
+}
+
 static void __init tegra20_fuse_init_randomness(void)
 {
 	u32 randomness[2];
@@ -184,6 +190,7 @@ void __init tegra_init_fuse(void)
 {
 	u32 id;
 	u32 randomness[5];
+	u8 chip_id;
 
 	u32 reg = readl(IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x48));
 	reg |= 1 << 28;
@@ -208,9 +215,9 @@ void __init tegra_init_fuse(void)
 
 	id = tegra_read_chipid();
 	randomness[2] = id;
-	tegra_chip_id = (id >> 8) & 0xff;
+	chip_id = (id >> 8) & 0xff;
 
-	switch (tegra_chip_id) {
+	switch (chip_id) {
 	case TEGRA20:
 		tegra_fuse_spare_bit = TEGRA20_FUSE_SPARE_BIT;
 		tegra_init_speedo_data = &tegra20_init_speedo_data;
@@ -223,7 +230,7 @@ void __init tegra_init_fuse(void)
 		tegra_init_speedo_data = &tegra114_init_speedo_data;
 		break;
 	default:
-		pr_warn("Tegra: unknown chip id %d\n", tegra_chip_id);
+		pr_warn("Tegra: unknown chip id %d\n", chip_id);
 		tegra_fuse_spare_bit = TEGRA20_FUSE_SPARE_BIT;
 		tegra_init_speedo_data = &tegra_get_process_id;
 	}
@@ -234,7 +241,7 @@ void __init tegra_init_fuse(void)
 	randomness[4] = (tegra_cpu_speedo_id << 16) | tegra_soc_speedo_id;
 
 	add_device_randomness(randomness, sizeof(randomness));
-	switch (tegra_chip_id) {
+	switch (chip_id) {
 	case TEGRA20:
 		tegra20_fuse_init_randomness();
 		break;
diff --git a/arch/arm/mach-tegra/fuse.h b/arch/arm/mach-tegra/fuse.h
index c01d04785d67..7a08b4b70c8d 100644
--- a/arch/arm/mach-tegra/fuse.h
+++ b/arch/arm/mach-tegra/fuse.h
@@ -26,11 +26,6 @@
 #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,
@@ -45,7 +40,6 @@ enum tegra_revision {
 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;
diff --git a/arch/arm/mach-tegra/hotplug.c b/arch/arm/mach-tegra/hotplug.c
index 7842b252dda5..d0a37dcbbb5d 100644
--- a/arch/arm/mach-tegra/hotplug.c
+++ b/arch/arm/mach-tegra/hotplug.c
@@ -11,10 +11,10 @@
 #include <linux/clk/tegra.h>
 #include <linux/kernel.h>
 #include <linux/smp.h>
+#include <linux/tegra-soc.h>
 
 #include <asm/smp_plat.h>
 
-#include "fuse.h"
 #include "sleep.h"
 
 static void (*tegra_hotplug_shutdown)(void);
@@ -52,12 +52,12 @@ void __init tegra_hotplug_init(void)
 	if (!IS_ENABLED(CONFIG_HOTPLUG_CPU))
 		return;
 
-	if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) && tegra_chip_id == TEGRA20)
+	if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) && tegra_get_chip_id() == TEGRA20)
 		tegra_hotplug_shutdown = tegra20_hotplug_shutdown;
-	if (IS_ENABLED(CONFIG_ARCH_TEGRA_3x_SOC) && tegra_chip_id == TEGRA30)
+	if (IS_ENABLED(CONFIG_ARCH_TEGRA_3x_SOC) && tegra_get_chip_id() == TEGRA30)
 		tegra_hotplug_shutdown = tegra30_hotplug_shutdown;
-	if (IS_ENABLED(CONFIG_ARCH_TEGRA_114_SOC) && tegra_chip_id == TEGRA114)
+	if (IS_ENABLED(CONFIG_ARCH_TEGRA_114_SOC) && tegra_get_chip_id() == TEGRA114)
 		tegra_hotplug_shutdown = tegra30_hotplug_shutdown;
-	if (IS_ENABLED(CONFIG_ARCH_TEGRA_124_SOC) && tegra_chip_id == TEGRA124)
+	if (IS_ENABLED(CONFIG_ARCH_TEGRA_124_SOC) && tegra_get_chip_id() == TEGRA124)
 		tegra_hotplug_shutdown = tegra30_hotplug_shutdown;
 }
diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c
index c403edd0fcc7..9679984650bd 100644
--- a/arch/arm/mach-tegra/platsmp.c
+++ b/arch/arm/mach-tegra/platsmp.c
@@ -20,6 +20,7 @@
 #include <linux/io.h>
 #include <linux/jiffies.h>
 #include <linux/smp.h>
+#include <linux/tegra-soc.h>
 
 #include <asm/cacheflush.h>
 #include <asm/mach-types.h>
@@ -28,7 +29,6 @@
 
 #include "common.h"
 #include "flowctrl.h"
-#include "fuse.h"
 #include "iomap.h"
 #include "pmc.h"
 #include "reset.h"
@@ -170,13 +170,13 @@ static int tegra114_boot_secondary(unsigned int cpu, struct task_struct *idle)
 static int tegra_boot_secondary(unsigned int cpu,
 					  struct task_struct *idle)
 {
-	if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) && tegra_chip_id == TEGRA20)
+	if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) && tegra_get_chip_id() == TEGRA20)
 		return tegra20_boot_secondary(cpu, idle);
-	if (IS_ENABLED(CONFIG_ARCH_TEGRA_3x_SOC) && tegra_chip_id == TEGRA30)
+	if (IS_ENABLED(CONFIG_ARCH_TEGRA_3x_SOC) && tegra_get_chip_id() == TEGRA30)
 		return tegra30_boot_secondary(cpu, idle);
-	if (IS_ENABLED(CONFIG_ARCH_TEGRA_114_SOC) && tegra_chip_id == TEGRA114)
+	if (IS_ENABLED(CONFIG_ARCH_TEGRA_114_SOC) && tegra_get_chip_id() == TEGRA114)
 		return tegra114_boot_secondary(cpu, idle);
-	if (IS_ENABLED(CONFIG_ARCH_TEGRA_124_SOC) && tegra_chip_id == TEGRA124)
+	if (IS_ENABLED(CONFIG_ARCH_TEGRA_124_SOC) && tegra_get_chip_id() == TEGRA124)
 		return tegra114_boot_secondary(cpu, idle);
 
 	return -EINVAL;
diff --git a/arch/arm/mach-tegra/pm.c b/arch/arm/mach-tegra/pm.c
index ae4826e43171..cd5bb6d876c7 100644
--- a/arch/arm/mach-tegra/pm.c
+++ b/arch/arm/mach-tegra/pm.c
@@ -26,6 +26,7 @@
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/suspend.h>
+#include <linux/tegra-soc.h>
 
 #include <asm/cacheflush.h>
 #include <asm/idmap.h>
@@ -35,7 +36,6 @@
 #include <asm/tlbflush.h>
 
 #include "flowctrl.h"
-#include "fuse.h"
 #include "iomap.h"
 #include "pmc.h"
 #include "pm.h"
@@ -53,7 +53,7 @@ static int (*tegra_sleep_func)(unsigned long v2p);
 
 static void tegra_tear_down_cpu_init(void)
 {
-	switch (tegra_chip_id) {
+	switch (tegra_get_chip_id()) {
 	case TEGRA20:
 		if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC))
 			tegra_tear_down_cpu = tegra20_tear_down_cpu;
@@ -143,7 +143,7 @@ bool tegra_set_cpu_in_lp2(void)
 
 	if ((phy_cpu_id == 0) && cpumask_equal(cpu_lp2_mask, cpu_online_mask))
 		last_cpu = true;
-	else if (tegra_chip_id == TEGRA20 && phy_cpu_id == 1)
+	else if (tegra_get_chip_id() == TEGRA20 && phy_cpu_id == 1)
 		tegra20_cpu_set_resettable_soon();
 
 	spin_unlock(&tegra_lp2_lock);
@@ -212,7 +212,7 @@ static int tegra_sleep_core(unsigned long v2p)
  */
 static bool tegra_lp1_iram_hook(void)
 {
-	switch (tegra_chip_id) {
+	switch (tegra_get_chip_id()) {
 	case TEGRA20:
 		if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC))
 			tegra20_lp1_iram_hook();
@@ -242,7 +242,7 @@ static bool tegra_lp1_iram_hook(void)
 
 static bool tegra_sleep_core_init(void)
 {
-	switch (tegra_chip_id) {
+	switch (tegra_get_chip_id()) {
 	case TEGRA20:
 		if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC))
 			tegra20_sleep_core_init();
diff --git a/arch/arm/mach-tegra/pmc.c b/arch/arm/mach-tegra/pmc.c
index cff318c17f2c..e255d39f8657 100644
--- a/arch/arm/mach-tegra/pmc.c
+++ b/arch/arm/mach-tegra/pmc.c
@@ -21,9 +21,9 @@
 #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"
@@ -251,7 +251,7 @@ void tegra_pmc_pm_set(enum tegra_suspend_mode mode)
 	reg |= TEGRA_POWER_CPU_PWRREQ_OE;
 	reg &= ~TEGRA_POWER_EFFECT_LP0;
 
-	switch (tegra_chip_id) {
+	switch (tegra_get_chip_id()) {
 	case TEGRA20:
 	case TEGRA30:
 		break;
diff --git a/arch/arm/mach-tegra/powergate.c b/arch/arm/mach-tegra/powergate.c
index bbffc9e6d498..1408f7e7321d 100644
--- a/arch/arm/mach-tegra/powergate.c
+++ b/arch/arm/mach-tegra/powergate.c
@@ -30,8 +30,8 @@
 #include <linux/seq_file.h>
 #include <linux/spinlock.h>
 #include <linux/tegra-powergate.h>
+#include <linux/tegra-soc.h>
 
-#include "fuse.h"
 #include "iomap.h"
 
 #define DPD_SAMPLE		0x020
@@ -157,7 +157,7 @@ int tegra_powergate_remove_clamping(int id)
 	 * The Tegra124 GPU has a separate register (with different semantics)
 	 * to remove clamps.
 	 */
-	if (tegra_chip_id == TEGRA124) {
+	if (tegra_get_chip_id() == TEGRA124) {
 		if (id == TEGRA_POWERGATE_3D) {
 			pmc_write(0, GPU_RG_CNTRL);
 			return 0;
@@ -227,7 +227,7 @@ int tegra_cpu_powergate_id(int cpuid)
 
 int __init tegra_powergate_init(void)
 {
-	switch (tegra_chip_id) {
+	switch (tegra_get_chip_id()) {
 	case TEGRA20:
 		tegra_num_powerdomains = 7;
 		break;
@@ -368,7 +368,7 @@ int __init tegra_powergate_debugfs_init(void)
 {
 	struct dentry *d;
 
-	switch (tegra_chip_id) {
+	switch (tegra_get_chip_id()) {
 	case TEGRA20:
 		powergate_name = powergate_name_t20;
 		break;
diff --git a/arch/arm/mach-tegra/reset-handler.S b/arch/arm/mach-tegra/reset-handler.S
index d916c84487ae..be2eaa8e84fb 100644
--- a/arch/arm/mach-tegra/reset-handler.S
+++ b/arch/arm/mach-tegra/reset-handler.S
@@ -16,12 +16,12 @@
 
 #include <linux/init.h>
 #include <linux/linkage.h>
+#include <linux/tegra-soc.h>
 
 #include <asm/asm-offsets.h>
 #include <asm/cache.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 b90507922a8c..bb1e5a12d1d7 100644
--- a/arch/arm/mach-tegra/reset.c
+++ b/arch/arm/mach-tegra/reset.c
@@ -18,6 +18,7 @@
 #include <linux/cpumask.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/tegra-soc.h>
 
 #include <asm/cacheflush.h>
 #include <asm/firmware.h>
@@ -53,7 +54,7 @@ static void __init tegra_cpu_reset_handler_set(const u32 reset_address)
 	 * Prevent further modifications to the physical reset vector.
 	 *  NOTE: Has no effect on chips prior to Tegra30.
 	 */
-	if (tegra_chip_id != TEGRA20) {
+	if (tegra_get_chip_id() != TEGRA20) {
 		reg = readl(sb_ctrl);
 		reg |= 2;
 		writel(reg, sb_ctrl);
diff --git a/arch/arm/mach-tegra/sleep-tegra30.S b/arch/arm/mach-tegra/sleep-tegra30.S
index e240b875183b..3700fe92abd8 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/asm-offsets.h>
 #include <asm/assembler.h>
 #include <asm/cache.h>
 
 #include "flowctrl.h"
-#include "fuse.h"
 #include "irammap.h"
 #include "sleep.h"
 
diff --git a/arch/arm/mach-tegra/tegra.c b/arch/arm/mach-tegra/tegra.c
index 7a9f30289049..e36b81870e66 100644
--- a/arch/arm/mach-tegra/tegra.c
+++ b/arch/arm/mach-tegra/tegra.c
@@ -33,6 +33,7 @@
 #include <linux/serial_8250.h>
 #include <linux/slab.h>
 #include <linux/sys_soc.h>
+#include <linux/tegra-soc.h>
 #include <linux/usb/tegra_usb_phy.h>
 
 #include <asm/hardware/cache-l2x0.h>
@@ -104,7 +105,7 @@ static void __init tegra_dt_init(void)
 
 	soc_dev_attr->family = kasprintf(GFP_KERNEL, "Tegra");
 	soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%d", tegra_revision);
-	soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "%d", tegra_chip_id);
+	soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "%u", tegra_get_chip_id());
 
 	soc_dev = soc_device_register(soc_dev_attr);
 	if (IS_ERR(soc_dev)) {
diff --git a/include/linux/tegra-soc.h b/include/linux/tegra-soc.h
index 95f611d78f3a..34c068989806 100644
--- a/include/linux/tegra-soc.h
+++ b/include/linux/tegra-soc.h
@@ -17,6 +17,16 @@
 #ifndef __LINUX_TEGRA_SOC_H_
 #define __LINUX_TEGRA_SOC_H_
 
+#define TEGRA20		0x20
+#define TEGRA30		0x30
+#define TEGRA114	0x35
+#define TEGRA124	0x40
+
+#ifndef __ASSEMBLY__
+
 u32 tegra_read_chipid(void);
+u8 tegra_get_chip_id(void);
+
+#endif /* __ASSEMBLY__ */
 
 #endif /* __LINUX_TEGRA_SOC_H_ */
-- 
2.0.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 03/12] ARM: tegra: export apb dma readl/writel
  2014-07-11 12:15 [PATCH 00/12] Add NVIDIA Tegra FUSE driver Thierry Reding
  2014-07-11 12:16 ` [PATCH 01/12] ARM: tegra: Sort includes alphabetically Thierry Reding
  2014-07-11 12:16 ` [PATCH 02/12] ARM: tegra: Use a function to get the chip ID Thierry Reding
@ 2014-07-11 12:16 ` Thierry Reding
  2014-07-11 12:16 ` [PATCH 04/12] ARM: tegra: move fuse exports to tegra-soc.h Thierry Reding
                   ` (9 subsequent siblings)
  12 siblings, 0 replies; 38+ messages in thread
From: Thierry Reding @ 2014-07-11 12:16 UTC (permalink / raw)
  To: linux-arm-kernel

From: Peter De Schrijver <pdeschrijver@nvidia.com>

Export APB DMA readl and writel. These are needed because we can't
access the fuses directly on Tegra20 without potentially causing a
system hang. Also have the APB DMA readl and writel return an error in
case of a read failure instead of just returning zero or ignore write
failures.

Signed-off-by: Peter De Schrijver <pdeschrijver@nvidia.com>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 arch/arm/mach-tegra/apbio.c | 51 +++++++++++++++++++++++++++------------------
 include/linux/tegra-soc.h   | 14 +++++++++++++
 2 files changed, 45 insertions(+), 20 deletions(-)

diff --git a/arch/arm/mach-tegra/apbio.c b/arch/arm/mach-tegra/apbio.c
index 5f9647b3f81d..f2488722c79c 100644
--- a/arch/arm/mach-tegra/apbio.c
+++ b/arch/arm/mach-tegra/apbio.c
@@ -32,8 +32,8 @@ 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 int tegra_apb_readl_direct(unsigned long offset, u32 *value);
+static int tegra_apb_writel_direct(u32 value, unsigned long offset);
 
 static struct dma_chan *tegra_apb_dma_chan;
 static struct dma_slave_config dma_sconfig;
@@ -128,58 +128,64 @@ static int do_dma_transfer(unsigned long apb_add,
 	return 0;
 }
 
-static u32 tegra_apb_readl_using_dma(unsigned long offset)
+int tegra_apb_readl_using_dma(unsigned long offset, u32 *value)
 {
 	int ret;
 
 	if (!tegra_apb_dma_chan && !tegra_apb_dma_init())
-		return tegra_apb_readl_direct(offset);
+		return tegra_apb_readl_direct(offset, value);
 
 	mutex_lock(&tegra_apb_dma_lock);
 	ret = do_dma_transfer(offset, DMA_DEV_TO_MEM);
-	if (ret < 0) {
+	if (ret < 0)
 		pr_err("error in reading offset 0x%08lx using dma\n", offset);
-		*(u32 *)tegra_apb_bb = 0;
-	}
+	else
+		*value = *tegra_apb_bb;
+
 	mutex_unlock(&tegra_apb_dma_lock);
-	return *((u32 *)tegra_apb_bb);
+
+	return ret;
 }
 
-static void tegra_apb_writel_using_dma(u32 value, unsigned long offset)
+int 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;
-	}
+	if (!tegra_apb_dma_chan && !tegra_apb_dma_init())
+		return tegra_apb_writel_direct(value, offset);
 
 	mutex_lock(&tegra_apb_dma_lock);
 	*((u32 *)tegra_apb_bb) = value;
 	ret = do_dma_transfer(offset, DMA_MEM_TO_DEV);
+	mutex_unlock(&tegra_apb_dma_lock);
 	if (ret < 0)
 		pr_err("error in writing offset 0x%08lx using dma\n", offset);
-	mutex_unlock(&tegra_apb_dma_lock);
+
+	return ret;
 }
 #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);
+typedef int (*apbio_read_fptr)(unsigned long offset, u32 *value);
+typedef int (*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)
+static int tegra_apb_readl_direct(unsigned long offset, u32 *value)
 {
-	return readl(IO_ADDRESS(offset));
+	*value = readl(IO_ADDRESS(offset));
+
+	return 0;
 }
 
-static void tegra_apb_writel_direct(u32 value, unsigned long offset)
+static int tegra_apb_writel_direct(u32 value, unsigned long offset)
 {
 	writel(value, IO_ADDRESS(offset));
+
+	return 0;
 }
 
 void tegra_apb_io_init(void)
@@ -197,7 +203,12 @@ void tegra_apb_io_init(void)
 
 u32 tegra_apb_readl(unsigned long offset)
 {
-	return apbio_read(offset);
+	u32 val;
+
+	if (apbio_read(offset, &val) < 0)
+		return 0;
+	else
+		return val;
 }
 
 void tegra_apb_writel(u32 value, unsigned long offset)
diff --git a/include/linux/tegra-soc.h b/include/linux/tegra-soc.h
index 34c068989806..5b419760ff5f 100644
--- a/include/linux/tegra-soc.h
+++ b/include/linux/tegra-soc.h
@@ -27,6 +27,20 @@
 u32 tegra_read_chipid(void);
 u8 tegra_get_chip_id(void);
 
+#if defined(CONFIG_TEGRA20_APB_DMA)
+int tegra_apb_readl_using_dma(unsigned long offset, u32 *value);
+int tegra_apb_writel_using_dma(u32 value, unsigned long offset);
+#else
+static inline int tegra_apb_readl_using_dma(unsigned long offset, u32 *value)
+{
+	return -EINVAL;
+}
+static inline int tegra_apb_writel_using_dma(u32 value, unsigned long offset)
+{
+	return -EINVAL;
+}
+#endif /* CONFIG_TEGRA20_APB_DMA */
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* __LINUX_TEGRA_SOC_H_ */
-- 
2.0.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 04/12] ARM: tegra: move fuse exports to tegra-soc.h
  2014-07-11 12:15 [PATCH 00/12] Add NVIDIA Tegra FUSE driver Thierry Reding
                   ` (2 preceding siblings ...)
  2014-07-11 12:16 ` [PATCH 03/12] ARM: tegra: export apb dma readl/writel Thierry Reding
@ 2014-07-11 12:16 ` Thierry Reding
  2014-07-11 12:16 ` [PATCH 05/12] soc/tegra: Add efuse driver for Tegra Thierry Reding
                   ` (8 subsequent siblings)
  12 siblings, 0 replies; 38+ messages in thread
From: Thierry Reding @ 2014-07-11 12:16 UTC (permalink / raw)
  To: linux-arm-kernel

From: Peter De Schrijver <pdeschrijver@nvidia.com>

All fuse related functionality will move to a driver in the following
patches. To prepare for this, export all the required functionality in a
global header file and move all users of fuse.h to tegra-soc.h. While
we're at it, remove tegra_bct_strapping, as its only user was removed in
Commit a7cbe92cef27 ("ARM: tegra: remove tegra EMC scaling driver").

Signed-off-by: Peter De Schrijver <pdeschrijver@nvidia.com>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 arch/arm/mach-tegra/fuse.h            | 13 -------------
 arch/arm/mach-tegra/tegra.c           |  1 -
 arch/arm/mach-tegra/tegra114_speedo.c |  1 +
 arch/arm/mach-tegra/tegra20_speedo.c  |  1 +
 arch/arm/mach-tegra/tegra30_speedo.c  |  1 +
 include/linux/tegra-soc.h             | 16 ++++++++++++++++
 6 files changed, 19 insertions(+), 14 deletions(-)

diff --git a/arch/arm/mach-tegra/fuse.h b/arch/arm/mach-tegra/fuse.h
index 7a08b4b70c8d..48a48861c19b 100644
--- a/arch/arm/mach-tegra/fuse.h
+++ b/arch/arm/mach-tegra/fuse.h
@@ -27,27 +27,14 @@
 #define SKU_ID_T25E	28
 
 #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_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);
 
diff --git a/arch/arm/mach-tegra/tegra.c b/arch/arm/mach-tegra/tegra.c
index e36b81870e66..f4c5f6469ee4 100644
--- a/arch/arm/mach-tegra/tegra.c
+++ b/arch/arm/mach-tegra/tegra.c
@@ -47,7 +47,6 @@
 #include "board.h"
 #include "common.h"
 #include "cpuidle.h"
-#include "fuse.h"
 #include "iomap.h"
 #include "irq.h"
 #include "pmc.h"
diff --git a/arch/arm/mach-tegra/tegra114_speedo.c b/arch/arm/mach-tegra/tegra114_speedo.c
index 86eca17e5286..f086a3ea291e 100644
--- a/arch/arm/mach-tegra/tegra114_speedo.c
+++ b/arch/arm/mach-tegra/tegra114_speedo.c
@@ -16,6 +16,7 @@
 
 #include <linux/bug.h>
 #include <linux/kernel.h>
+#include <linux/tegra-soc.h>
 
 #include "fuse.h"
 
diff --git a/arch/arm/mach-tegra/tegra20_speedo.c b/arch/arm/mach-tegra/tegra20_speedo.c
index dcd29a0b0187..83431011a23c 100644
--- a/arch/arm/mach-tegra/tegra20_speedo.c
+++ b/arch/arm/mach-tegra/tegra20_speedo.c
@@ -16,6 +16,7 @@
 
 #include <linux/bug.h>
 #include <linux/kernel.h>
+#include <linux/tegra-soc.h>
 
 #include "fuse.h"
 
diff --git a/arch/arm/mach-tegra/tegra30_speedo.c b/arch/arm/mach-tegra/tegra30_speedo.c
index 7c0038326cf5..4dda681bdaf9 100644
--- a/arch/arm/mach-tegra/tegra30_speedo.c
+++ b/arch/arm/mach-tegra/tegra30_speedo.c
@@ -16,6 +16,7 @@
 
 #include <linux/bug.h>
 #include <linux/kernel.h>
+#include <linux/tegra-soc.h>
 
 #include "fuse.h"
 
diff --git a/include/linux/tegra-soc.h b/include/linux/tegra-soc.h
index 5b419760ff5f..3a00b3419594 100644
--- a/include/linux/tegra-soc.h
+++ b/include/linux/tegra-soc.h
@@ -27,6 +27,22 @@
 u32 tegra_read_chipid(void);
 u8 tegra_get_chip_id(void);
 
+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,
+};
+
+u32 tegra_read_straps(void);
+u32 tegra_read_chipid(void);
+void tegra_init_fuse(void);
+
+extern enum tegra_revision tegra_revision;
+
 #if defined(CONFIG_TEGRA20_APB_DMA)
 int tegra_apb_readl_using_dma(unsigned long offset, u32 *value);
 int tegra_apb_writel_using_dma(u32 value, unsigned long offset);
-- 
2.0.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 05/12] soc/tegra: Add efuse driver for Tegra
  2014-07-11 12:15 [PATCH 00/12] Add NVIDIA Tegra FUSE driver Thierry Reding
                   ` (3 preceding siblings ...)
  2014-07-11 12:16 ` [PATCH 04/12] ARM: tegra: move fuse exports to tegra-soc.h Thierry Reding
@ 2014-07-11 12:16 ` Thierry Reding
  2014-10-19  3:12   ` Shawn Guo
  2014-07-11 12:16 ` [PATCH 06/12] soc/tegra: Add efuse and apbmisc bindings Thierry Reding
                   ` (7 subsequent siblings)
  12 siblings, 1 reply; 38+ messages in thread
From: Thierry Reding @ 2014-07-11 12:16 UTC (permalink / raw)
  To: linux-arm-kernel

From: Peter De Schrijver <pdeschrijver@nvidia.com>

Implement fuse driver for Tegra20, Tegra30, Tegra114 and Tegra124. This
replaces functionality previously provided in arch/arm/mach-tegra, which
is removed in this patch.

While at it, move the only user of the global tegra_revision variable
over to tegra_sku_info.revision and export tegra_fuse_readl() to allow
drivers to read calibration fuses.

Signed-off-by: Peter De Schrijver <pdeschrijver@nvidia.com>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 Documentation/ABI/testing/sysfs-driver-tegra-fuse  |  11 +
 arch/arm/mach-tegra/Makefile                       |   4 -
 arch/arm/mach-tegra/fuse.c                         | 259 ---------------------
 arch/arm/mach-tegra/fuse.h                         |  60 -----
 arch/arm/mach-tegra/reset.c                        |   1 -
 arch/arm/mach-tegra/tegra.c                        |   3 +-
 drivers/misc/fuse/Makefile                         |   1 +
 drivers/soc/Makefile                               |   1 +
 drivers/soc/tegra/Makefile                         |   1 +
 drivers/soc/tegra/fuse/Makefile                    |   8 +
 drivers/soc/tegra/fuse/fuse-tegra.c                | 155 ++++++++++++
 drivers/soc/tegra/fuse/fuse-tegra20.c              | 141 +++++++++++
 drivers/soc/tegra/fuse/fuse-tegra30.c              | 223 ++++++++++++++++++
 drivers/soc/tegra/fuse/fuse.h                      |  71 ++++++
 .../soc/tegra/fuse/speedo-tegra114.c               |  54 +++--
 drivers/soc/tegra/fuse/speedo-tegra124.c           | 167 +++++++++++++
 .../soc/tegra/fuse/speedo-tegra20.c                |  43 ++--
 .../soc/tegra/fuse/speedo-tegra30.c                | 174 +++++++-------
 drivers/soc/tegra/fuse/tegra-apbmisc.c             | 111 +++++++++
 include/linux/tegra-soc.h                          |  20 +-
 20 files changed, 1045 insertions(+), 463 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-driver-tegra-fuse
 delete mode 100644 arch/arm/mach-tegra/fuse.c
 delete mode 100644 arch/arm/mach-tegra/fuse.h
 create mode 100644 drivers/misc/fuse/Makefile
 create mode 100644 drivers/soc/tegra/Makefile
 create mode 100644 drivers/soc/tegra/fuse/Makefile
 create mode 100644 drivers/soc/tegra/fuse/fuse-tegra.c
 create mode 100644 drivers/soc/tegra/fuse/fuse-tegra20.c
 create mode 100644 drivers/soc/tegra/fuse/fuse-tegra30.c
 create mode 100644 drivers/soc/tegra/fuse/fuse.h
 rename arch/arm/mach-tegra/tegra114_speedo.c => drivers/soc/tegra/fuse/speedo-tegra114.c (56%)
 create mode 100644 drivers/soc/tegra/fuse/speedo-tegra124.c
 rename arch/arm/mach-tegra/tegra20_speedo.c => drivers/soc/tegra/fuse/speedo-tegra20.c (68%)
 rename arch/arm/mach-tegra/tegra30_speedo.c => drivers/soc/tegra/fuse/speedo-tegra30.c (53%)
 create mode 100644 drivers/soc/tegra/fuse/tegra-apbmisc.c

diff --git a/Documentation/ABI/testing/sysfs-driver-tegra-fuse b/Documentation/ABI/testing/sysfs-driver-tegra-fuse
new file mode 100644
index 000000000000..69f5af632657
--- /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/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index 6fbfbb77dcd9..e8601bb56f98 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -2,7 +2,6 @@ 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
@@ -13,13 +12,11 @@ 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 +25,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/fuse.c b/arch/arm/mach-tegra/fuse.c
deleted file mode 100644
index e9b01a5cf40e..000000000000
--- a/arch/arm/mach-tegra/fuse.c
+++ /dev/null
@@ -1,259 +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/clk.h>
-#include <linux/export.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/random.h>
-#include <linux/tegra-soc.h>
-
-#include "apbio.h"
-#include "fuse.h"
-#include "iomap.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_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_get_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);
-}
-
-u8 tegra_get_chip_id(void)
-{
-	u32 id = tegra_read_chipid();
-
-	return (id >> 8) & 0xff;
-}
-
-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];
-	u8 chip_id;
-
-	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;
-	chip_id = (id >> 8) & 0xff;
-
-	switch (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", 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 (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 48a48861c19b..000000000000
--- a/arch/arm/mach-tegra/fuse.h
+++ /dev/null
@@ -1,60 +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
-
-#ifndef __ASSEMBLY__
-
-extern int tegra_sku_id;
-extern int tegra_cpu_process_id;
-extern int tegra_core_process_id;
-extern int tegra_cpu_speedo_id;		/* only exist in Tegra30 and later */
-extern int tegra_soc_speedo_id;
-
-unsigned long long tegra_chip_uid(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/reset.c b/arch/arm/mach-tegra/reset.c
index bb1e5a12d1d7..e997b2573893 100644
--- a/arch/arm/mach-tegra/reset.c
+++ b/arch/arm/mach-tegra/reset.c
@@ -24,7 +24,6 @@
 #include <asm/firmware.h>
 #include <asm/hardware/cache-l2x0.h>
 
-#include "fuse.h"
 #include "iomap.h"
 #include "irammap.h"
 #include "reset.h"
diff --git a/arch/arm/mach-tegra/tegra.c b/arch/arm/mach-tegra/tegra.c
index f4c5f6469ee4..1d60be4975b8 100644
--- a/arch/arm/mach-tegra/tegra.c
+++ b/arch/arm/mach-tegra/tegra.c
@@ -103,7 +103,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, "%u", tegra_get_chip_id());
 
 	soc_dev = soc_device_register(soc_dev_attr);
diff --git a/drivers/misc/fuse/Makefile b/drivers/misc/fuse/Makefile
new file mode 100644
index 000000000000..0679c4febc89
--- /dev/null
+++ b/drivers/misc/fuse/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_ARCH_TEGRA)	+= tegra/
diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile
index 0f7c44793b29..3b1b95d932d1 100644
--- a/drivers/soc/Makefile
+++ b/drivers/soc/Makefile
@@ -3,3 +3,4 @@
 #
 
 obj-$(CONFIG_ARCH_QCOM)		+= qcom/
+obj-$(CONFIG_ARCH_TEGRA)	+= tegra/
diff --git a/drivers/soc/tegra/Makefile b/drivers/soc/tegra/Makefile
new file mode 100644
index 000000000000..236600f91bb3
--- /dev/null
+++ b/drivers/soc/tegra/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_ARCH_TEGRA) += fuse/
diff --git a/drivers/soc/tegra/fuse/Makefile b/drivers/soc/tegra/fuse/Makefile
new file mode 100644
index 000000000000..3af357da91f3
--- /dev/null
+++ b/drivers/soc/tegra/fuse/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/soc/tegra/fuse/fuse-tegra.c b/drivers/soc/tegra/fuse/fuse-tegra.c
new file mode 100644
index 000000000000..6a6dac1754b1
--- /dev/null
+++ b/drivers/soc/tegra/fuse/fuse-tegra.c
@@ -0,0 +1,155 @@
+/*
+ * 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(unsigned long offset, u32 *value)
+{
+	if (!fuse_readl)
+		return -EPROBE_DEFER;
+
+	*value = fuse_readl(offset);
+
+	return 0;
+}
+EXPORT_SYMBOL(tegra_fuse_readl);
+
+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_get_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/soc/tegra/fuse/fuse-tegra20.c b/drivers/soc/tegra/fuse/fuse-tegra20.c
new file mode 100644
index 000000000000..09f91bf8c743
--- /dev/null
+++ b/drivers/soc/tegra/fuse/fuse-tegra20.c
@@ -0,0 +1,141 @@
+/*
+ * 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/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 u32 tegra20_fuse_readl(const unsigned int offset)
+{
+	int ret;
+	u32 val;
+
+	clk_prepare_enable(fuse_clk);
+
+	ret = tegra_apb_readl_using_dma(fuse_phys + FUSE_BEGIN + offset, &val);
+
+	clk_disable_unprepare(fuse_clk);
+
+	return (ret < 0) ? 0 : val;
+}
+
+static const struct of_device_id tegra20_fuse_of_match[] = {
+	{ .compatible = "nvidia,tegra20-efuse" },
+	{},
+};
+
+static int tegra20_fuse_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+
+	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;
+
+	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/soc/tegra/fuse/fuse-tegra30.c b/drivers/soc/tegra/fuse/fuse-tegra30.c
new file mode 100644
index 000000000000..a4cfb11ac15c
--- /dev/null
+++ b/drivers/soc/tegra/fuse/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_get_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_get_chip_id());
+		return;
+	}
+
+	tegra_init_revision();
+	speedo_tbl[fuse_info->speedo_idx](&tegra_sku_info);
+	tegra30_fuse_add_randomness();
+}
diff --git a/drivers/soc/tegra/fuse/fuse.h b/drivers/soc/tegra/fuse/fuse.h
new file mode 100644
index 000000000000..b3442770df09
--- /dev/null
+++ b/drivers/soc/tegra/fuse/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, void *fuse_base)
+{
+			return false;
+}
+static inline void tegra20_init_fuse_early(void);
+static inline 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/arch/arm/mach-tegra/tegra114_speedo.c b/drivers/soc/tegra/fuse/speedo-tegra114.c
similarity index 56%
rename from arch/arm/mach-tegra/tegra114_speedo.c
rename to drivers/soc/tegra/fuse/speedo-tegra114.c
index f086a3ea291e..98d6cde33646 100644
--- a/arch/arm/mach-tegra/tegra114_speedo.c
+++ b/drivers/soc/tegra/fuse/speedo-tegra114.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, NVIDIA CORPORATION.  All rights reserved.
+ * 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,
@@ -14,14 +14,15 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <linux/bug.h>
+#include <linux/device.h>
 #include <linux/kernel.h>
+#include <linux/bug.h>
 #include <linux/tegra-soc.h>
 
 #include "fuse.h"
 
-#define CORE_PROCESS_CORNERS_NUM	2
-#define CPU_PROCESS_CORNERS_NUM		2
+#define CORE_PROCESS_CORNERS	2
+#define CPU_PROCESS_CORNERS	2
 
 enum {
 	THRESHOLD_INDEX_0,
@@ -29,54 +30,57 @@ enum {
 	THRESHOLD_INDEX_COUNT,
 };
 
-static const u32 core_process_speedos[][CORE_PROCESS_CORNERS_NUM] = {
+static const u32 __initconst core_process_speedos[][CORE_PROCESS_CORNERS] = {
 	{1123,     UINT_MAX},
 	{0,        UINT_MAX},
 };
 
-static const u32 cpu_process_speedos[][CPU_PROCESS_CORNERS_NUM] = {
+static const u32 __initconst cpu_process_speedos[][CPU_PROCESS_CORNERS] = {
 	{1695,     UINT_MAX},
 	{0,        UINT_MAX},
 };
 
-static void rev_sku_to_speedo_ids(int rev, int sku, int *threshold)
+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:
-		tegra_cpu_speedo_id = 1;
-		tegra_soc_speedo_id = 0;
+		sku_info->cpu_speedo_id = 1;
+		sku_info->soc_speedo_id = 0;
 		*threshold = THRESHOLD_INDEX_0;
 		break;
 
 	case 0x03:
 	case 0x04:
-		tegra_cpu_speedo_id = 2;
-		tegra_soc_speedo_id = 1;
+		sku_info->cpu_speedo_id = 2;
+		sku_info->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;
+		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 = tegra_fuse_readl(0x270) << 1;
-		tmp |= tegra_fuse_readl(0x26c);
+		tmp = tegra30_fuse_readl(0x270) << 1;
+		tmp |= tegra30_fuse_readl(0x26c);
 		if (!tmp)
-			tegra_cpu_speedo_id = 0;
+			sku_info->cpu_speedo_id = 0;
 	}
 }
 
-void tegra114_init_speedo_data(void)
+void __init tegra114_init_speedo_data(struct tegra_sku_info *sku_info)
 {
 	u32 cpu_speedo_val;
 	u32 core_speedo_val;
@@ -88,18 +92,18 @@ void tegra114_init_speedo_data(void)
 	BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) !=
 			THRESHOLD_INDEX_COUNT);
 
-	rev_sku_to_speedo_ids(tegra_revision, tegra_sku_id, &threshold);
+	rev_sku_to_speedo_ids(sku_info, &threshold);
 
-	cpu_speedo_val = tegra_fuse_readl(0x12c) + 1024;
-	core_speedo_val = tegra_fuse_readl(0x134);
+	cpu_speedo_val = tegra30_fuse_readl(0x12c) + 1024;
+	core_speedo_val = tegra30_fuse_readl(0x134);
 
-	for (i = 0; i < CPU_PROCESS_CORNERS_NUM; i++)
+	for (i = 0; i < CPU_PROCESS_CORNERS; i++)
 		if (cpu_speedo_val < cpu_process_speedos[threshold][i])
 			break;
-	tegra_cpu_process_id = i;
+	sku_info->cpu_process_id = i;
 
-	for (i = 0; i < CORE_PROCESS_CORNERS_NUM; i++)
+	for (i = 0; i < CORE_PROCESS_CORNERS; i++)
 		if (core_speedo_val < core_process_speedos[threshold][i])
 			break;
-	tegra_core_process_id = i;
+	sku_info->core_process_id = i;
 }
diff --git a/drivers/soc/tegra/fuse/speedo-tegra124.c b/drivers/soc/tegra/fuse/speedo-tegra124.c
new file mode 100644
index 000000000000..a15dd537f2ab
--- /dev/null
+++ b/drivers/soc/tegra/fuse/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/arch/arm/mach-tegra/tegra20_speedo.c b/drivers/soc/tegra/fuse/speedo-tegra20.c
similarity index 68%
rename from arch/arm/mach-tegra/tegra20_speedo.c
rename to drivers/soc/tegra/fuse/speedo-tegra20.c
index 83431011a23c..c951fa45ad34 100644
--- a/arch/arm/mach-tegra/tegra20_speedo.c
+++ b/drivers/soc/tegra/fuse/speedo-tegra20.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
+ * 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,
@@ -14,8 +14,9 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <linux/bug.h>
 #include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/bug.h>
 #include <linux/tegra-soc.h>
 
 #include "fuse.h"
@@ -48,19 +49,19 @@ enum {
 	SPEEDO_ID_COUNT,
 };
 
-static const u32 cpu_process_speedos[][PROCESS_CORNERS_NUM] = {
+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 core_process_speedos[][PROCESS_CORNERS_NUM] = {
+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 tegra20_init_speedo_data(void)
+void __init tegra20_init_speedo_data(struct tegra_sku_info *sku_info)
 {
 	u32 reg;
 	u32 val;
@@ -69,42 +70,40 @@ void tegra20_init_speedo_data(void)
 	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;
+	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
-		tegra_soc_speedo_id = SPEEDO_ID_2;
+		sku_info->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);
+		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("%s CPU speedo value %u\n", __func__, val);
+	pr_debug("Tegra CPU speedo value %u\n", val);
 
 	for (i = 0; i < (PROCESS_CORNERS_NUM - 1); i++) {
-		if (val <= cpu_process_speedos[tegra_soc_speedo_id][i])
+		if (val <= cpu_process_speedos[sku_info->soc_speedo_id][i])
 			break;
 	}
-	tegra_cpu_process_id = i;
+	sku_info->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);
+		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("%s Core speedo value %u\n", __func__, val);
+	pr_debug("Core speedo value %u\n", val);
 
 	for (i = 0; i < (PROCESS_CORNERS_NUM - 1); i++) {
-		if (val <= core_process_speedos[tegra_soc_speedo_id][i])
+		if (val <= core_process_speedos[sku_info->soc_speedo_id][i])
 			break;
 	}
-	tegra_core_process_id = i;
-
-	pr_info("Tegra20 Soc Speedo ID %d", tegra_soc_speedo_id);
+	sku_info->core_process_id = i;
 }
diff --git a/arch/arm/mach-tegra/tegra30_speedo.c b/drivers/soc/tegra/fuse/speedo-tegra30.c
similarity index 53%
rename from arch/arm/mach-tegra/tegra30_speedo.c
rename to drivers/soc/tegra/fuse/speedo-tegra30.c
index 4dda681bdaf9..1a85ad83fe5a 100644
--- a/arch/arm/mach-tegra/tegra30_speedo.c
+++ b/drivers/soc/tegra/fuse/speedo-tegra30.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
+ * 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,
@@ -14,18 +14,19 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <linux/bug.h>
+#include <linux/device.h>
 #include <linux/kernel.h>
+#include <linux/bug.h>
 #include <linux/tegra-soc.h>
 
 #include "fuse.h"
 
-#define CORE_PROCESS_CORNERS_NUM	1
-#define CPU_PROCESS_CORNERS_NUM		6
+#define CORE_PROCESS_CORNERS	1
+#define CPU_PROCESS_CORNERS	6
 
-#define FUSE_SPEEDO_CALIB_0	0x114
-#define FUSE_PACKAGE_INFO	0X1FC
-#define FUSE_TEST_PROG_VER	0X128
+#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
@@ -52,7 +53,7 @@ enum {
 	THRESHOLD_INDEX_COUNT,
 };
 
-static const u32 core_process_speedos[][CORE_PROCESS_CORNERS_NUM] = {
+static const u32 __initconst core_process_speedos[][CORE_PROCESS_CORNERS] = {
 	{180},
 	{170},
 	{195},
@@ -67,7 +68,7 @@ static const u32 core_process_speedos[][CORE_PROCESS_CORNERS_NUM] = {
 	{180},
 };
 
-static const u32 cpu_process_speedos[][CPU_PROCESS_CORNERS_NUM] = {
+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},
@@ -82,35 +83,34 @@ static const u32 cpu_process_speedos[][CPU_PROCESS_CORNERS_NUM] = {
 	{295, 336, 358, 375, 391, UINT_MAX},
 };
 
-static int threshold_index;
-static int package_id;
+static int threshold_index __initdata;
 
-static void fuse_speedo_calib(u32 *speedo_g, u32 *speedo_lp)
+static void __init 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);
+	reg = tegra30_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);
+	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 = 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);
+		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 = 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);
+		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;
@@ -118,133 +118,131 @@ static void fuse_speedo_calib(u32 *speedo_g, u32 *speedo_lp)
 	}
 }
 
-static void rev_sku_to_speedo_ids(int rev, int sku)
+static void __init rev_sku_to_speedo_ids(struct tegra_sku_info *sku_info)
 {
-	switch (rev) {
+	int package_id = tegra30_fuse_readl(FUSE_PACKAGE_INFO) & 0x0F;
+
+	switch (sku_info->revision) {
 	case TEGRA_REVISION_A01:
-		tegra_cpu_speedo_id = 0;
-		tegra_soc_speedo_id = 0;
+		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) {
+		switch (sku_info->sku_id) {
 		case 0x87:
 		case 0x82:
-			tegra_cpu_speedo_id = 1;
-			tegra_soc_speedo_id = 1;
+			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:
-				tegra_cpu_speedo_id = 2;
-				tegra_soc_speedo_id = 2;
+				sku_info->cpu_speedo_id = 2;
+				sku_info->soc_speedo_id = 2;
 				threshold_index = THRESHOLD_INDEX_2;
 				break;
 			case 2:
-				tegra_cpu_speedo_id = 4;
-				tegra_soc_speedo_id = 1;
+				sku_info->cpu_speedo_id = 4;
+				sku_info->soc_speedo_id = 1;
 				threshold_index = THRESHOLD_INDEX_7;
 				break;
 			default:
-				pr_err("Tegra30: Unknown pkg %d\n", package_id);
-				BUG();
+				pr_err("Tegra Unknown pkg %d\n", package_id);
 				break;
 			}
 			break;
 		case 0x80:
 			switch (package_id) {
 			case 1:
-				tegra_cpu_speedo_id = 5;
-				tegra_soc_speedo_id = 2;
+				sku_info->cpu_speedo_id = 5;
+				sku_info->soc_speedo_id = 2;
 				threshold_index = THRESHOLD_INDEX_8;
 				break;
 			case 2:
-				tegra_cpu_speedo_id = 6;
-				tegra_soc_speedo_id = 2;
+				sku_info->cpu_speedo_id = 6;
+				sku_info->soc_speedo_id = 2;
 				threshold_index = THRESHOLD_INDEX_9;
 				break;
 			default:
-				pr_err("Tegra30: Unknown pkg %d\n", package_id);
-				BUG();
+				pr_err("Tegra Unknown pkg %d\n", package_id);
 				break;
 			}
 			break;
 		case 0x83:
 			switch (package_id) {
 			case 1:
-				tegra_cpu_speedo_id = 7;
-				tegra_soc_speedo_id = 1;
+				sku_info->cpu_speedo_id = 7;
+				sku_info->soc_speedo_id = 1;
 				threshold_index = THRESHOLD_INDEX_10;
 				break;
 			case 2:
-				tegra_cpu_speedo_id = 3;
-				tegra_soc_speedo_id = 2;
+				sku_info->cpu_speedo_id = 3;
+				sku_info->soc_speedo_id = 2;
 				threshold_index = THRESHOLD_INDEX_3;
 				break;
 			default:
-				pr_err("Tegra30: Unknown pkg %d\n", package_id);
-				BUG();
+				pr_err("Tegra Unknown pkg %d\n", package_id);
 				break;
 			}
 			break;
 		case 0x8F:
-			tegra_cpu_speedo_id = 8;
-			tegra_soc_speedo_id = 1;
+			sku_info->cpu_speedo_id = 8;
+			sku_info->soc_speedo_id = 1;
 			threshold_index = THRESHOLD_INDEX_11;
 			break;
 		case 0x08:
-			tegra_cpu_speedo_id = 1;
-			tegra_soc_speedo_id = 1;
+			sku_info->cpu_speedo_id = 1;
+			sku_info->soc_speedo_id = 1;
 			threshold_index = THRESHOLD_INDEX_4;
 			break;
 		case 0x02:
-			tegra_cpu_speedo_id = 2;
-			tegra_soc_speedo_id = 2;
+			sku_info->cpu_speedo_id = 2;
+			sku_info->soc_speedo_id = 2;
 			threshold_index = THRESHOLD_INDEX_5;
 			break;
 		case 0x04:
-			tegra_cpu_speedo_id = 3;
-			tegra_soc_speedo_id = 2;
+			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:
-				tegra_cpu_speedo_id = 2;
-				tegra_soc_speedo_id = 2;
+				sku_info->cpu_speedo_id = 2;
+				sku_info->soc_speedo_id = 2;
 				threshold_index = THRESHOLD_INDEX_2;
 				break;
 			case 2:
-				tegra_cpu_speedo_id = 3;
-				tegra_soc_speedo_id = 2;
+				sku_info->cpu_speedo_id = 3;
+				sku_info->soc_speedo_id = 2;
 				threshold_index = THRESHOLD_INDEX_3;
 				break;
 			default:
-				pr_err("Tegra30: Unknown pkg %d\n", package_id);
-				BUG();
+				pr_err("Tegra Unknown pkg %d\n", package_id);
 				break;
 			}
 			break;
 		default:
-			pr_warn("Tegra30: Unknown SKU %d\n", sku);
-			tegra_cpu_speedo_id = 0;
-			tegra_soc_speedo_id = 0;
+			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("Tegra30: Unknown chip rev %d\n", rev);
-		tegra_cpu_speedo_id = 0;
-		tegra_soc_speedo_id = 0;
+		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 tegra30_init_speedo_data(void)
+void __init tegra30_init_speedo_data(struct tegra_sku_info *sku_info)
 {
 	u32 cpu_speedo_val;
 	u32 core_speedo_val;
@@ -255,39 +253,35 @@ void tegra30_init_speedo_data(void)
 	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);
+	rev_sku_to_speedo_ids(sku_info);
 	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);
+	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_NUM; i++) {
+	for (i = 0; i < CPU_PROCESS_CORNERS; i++) {
 		if (cpu_speedo_val < cpu_process_speedos[threshold_index][i])
 			break;
 	}
-	tegra_cpu_process_id = i - 1;
+	sku_info->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;
+	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_NUM; i++) {
+	for (i = 0; i < CORE_PROCESS_CORNERS; i++) {
 		if (core_speedo_val < core_process_speedos[threshold_index][i])
 			break;
 	}
-	tegra_core_process_id = i - 1;
+	sku_info->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;
+	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;
 	}
-
-	pr_info("Tegra30: CPU Speedo ID %d, Soc Speedo ID %d",
-		tegra_cpu_speedo_id, tegra_soc_speedo_id);
 }
diff --git a/drivers/soc/tegra/fuse/tegra-apbmisc.c b/drivers/soc/tegra/fuse/tegra-apbmisc.c
new file mode 100644
index 000000000000..d51d8159a3f8
--- /dev/null
+++ b/drivers/soc/tegra/fuse/tegra-apbmisc.c
@@ -0,0 +1,111 @@
+/*
+ * 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
+
+static void __iomem *apbmisc_base;
+static void __iomem *strapping_base;
+
+u32 tegra_read_chipid(void)
+{
+	return readl_relaxed(apbmisc_base + 4);
+}
+
+u8 tegra_get_chip_id(void)
+{
+	u32 id = tegra_read_chipid();
+
+	return (id >> 8) & 0xff;
+}
+
+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, chip_id, minor_rev;
+	int rev;
+
+	id = tegra_read_chipid();
+	chip_id = (id >> 8) & 0xff;
+	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 (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 (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;
+
+	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);
+	}
+
+	strapping_base = of_iomap(np, 1);
+	if (!strapping_base)
+		pr_err("ioremap tegra strapping_base failed\n");
+}
diff --git a/include/linux/tegra-soc.h b/include/linux/tegra-soc.h
index 3a00b3419594..3d984219aaa1 100644
--- a/include/linux/tegra-soc.h
+++ b/include/linux/tegra-soc.h
@@ -22,6 +22,9 @@
 #define TEGRA114	0x35
 #define TEGRA124	0x40
 
+#define TEGRA_FUSE_SKU_CALIB_0	0xf0
+#define TEGRA30_FUSE_SATA_CALIB	0x124
+
 #ifndef __ASSEMBLY__
 
 u32 tegra_read_chipid(void);
@@ -37,11 +40,26 @@ enum tegra_revision {
 	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(unsigned long offset, u32 *value);
 
-extern enum tegra_revision tegra_revision;
+extern struct tegra_sku_info tegra_sku_info;
 
 #if defined(CONFIG_TEGRA20_APB_DMA)
 int tegra_apb_readl_using_dma(unsigned long offset, u32 *value);
-- 
2.0.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 06/12] soc/tegra: Add efuse and apbmisc bindings
  2014-07-11 12:15 [PATCH 00/12] Add NVIDIA Tegra FUSE driver Thierry Reding
                   ` (4 preceding siblings ...)
  2014-07-11 12:16 ` [PATCH 05/12] soc/tegra: Add efuse driver for Tegra Thierry Reding
@ 2014-07-11 12:16 ` Thierry Reding
  2014-07-11 12:16 ` [PATCH 07/12] soc/tegra: fuse: move APB DMA into Tegra20 fuse driver Thierry Reding
                   ` (6 subsequent siblings)
  12 siblings, 0 replies; 38+ messages in thread
From: Thierry Reding @ 2014-07-11 12:16 UTC (permalink / raw)
  To: linux-arm-kernel

From: Peter De Schrijver <pdeschrijver@nvidia.com>

Add efuse and apbmisc bindings for Tegra20, Tegra30, Tegra114 and
Tegra124.

Signed-off-by: Peter De Schrijver <pdeschrijver@nvidia.com>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 .../bindings/fuse/nvidia,tegra20-fuse.txt          | 40 ++++++++++++++++++++++
 .../bindings/misc/nvidia,tegra20-apbmisc.txt       | 13 +++++++
 arch/arm/boot/dts/tegra114.dtsi                    | 15 ++++++++
 arch/arm/boot/dts/tegra124.dtsi                    | 15 ++++++++
 arch/arm/boot/dts/tegra20.dtsi                     | 15 ++++++++
 arch/arm/boot/dts/tegra30.dtsi                     | 15 ++++++++
 6 files changed, 113 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/fuse/nvidia,tegra20-fuse.txt
 create mode 100644 Documentation/devicetree/bindings/misc/nvidia,tegra20-apbmisc.txt

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 000000000000..d8c98c7614d0
--- /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 at 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 000000000000..b97b8bef1fe5
--- /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/arch/arm/boot/dts/tegra114.dtsi b/arch/arm/boot/dts/tegra114.dtsi
index fdc559ab2db3..335a1d8047f2 100644
--- a/arch/arm/boot/dts/tegra114.dtsi
+++ b/arch/arm/boot/dts/tegra114.dtsi
@@ -220,6 +220,12 @@
 		interrupt-controller;
 	};
 
+	apbmisc at 70000800 {
+		compatible = "nvidia,tegra114-apbmisc", "nvidia,tegra20-apbmisc";
+		reg = <0x70000800 0x64   /* Chip revision */
+		       0x70000008 0x04>; /* Strapping options */
+	};
+
 	pinmux: pinmux at 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 at 70019010 {
 		compatible = "nvidia,tegra114-smmu", "nvidia,tegra30-smmu";
 		reg = <0x70019010 0x02c
diff --git a/arch/arm/boot/dts/tegra124.dtsi b/arch/arm/boot/dts/tegra124.dtsi
index 6e6bc4e8185c..226941c07d15 100644
--- a/arch/arm/boot/dts/tegra124.dtsi
+++ b/arch/arm/boot/dts/tegra124.dtsi
@@ -179,6 +179,12 @@
 		#dma-cells = <1>;
 	};
 
+	apbmisc at 0,70000800 {
+		compatible = "nvidia,tegra124-apbmisc", "nvidia,tegra20-apbmisc";
+		reg = <0x0 0x70000800 0x0 0x64>,   /* Chip revision */
+		      <0x0 0x7000E864 0x0 0x04>;   /* Strapping options */
+	};
+
 	pinmux: pinmux at 0,70000868 {
 		compatible = "nvidia,tegra124-pinmux";
 		reg = <0x0 0x70000868 0x0 0x164>, /* Pad control registers */
@@ -449,6 +455,15 @@
 		clock-names = "pclk", "clk32k_in";
 	};
 
+	fuse at 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";
+	};
+
 	sdhci at 0,700b0000 {
 		compatible = "nvidia,tegra124-sdhci";
 		reg = <0x0 0x700b0000 0x0 0x200>;
diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi
index a7ddf70df50b..243d84cdbae8 100644
--- a/arch/arm/boot/dts/tegra20.dtsi
+++ b/arch/arm/boot/dts/tegra20.dtsi
@@ -236,6 +236,12 @@
 		interrupt-controller;
 	};
 
+	apbmisc at 70000800 {
+		compatible = "nvidia,tegra20-apbmisc";
+		reg = <0x70000800 0x64   /* Chip revision */
+		       0x70000008 0x04>; /* Strapping options */
+	};
+
 	pinmux: pinmux at 70000014 {
 		compatible = "nvidia,tegra20-pinmux";
 		reg = <0x70000014 0x10   /* Tri-state registers */
@@ -545,6 +551,15 @@
 		#size-cells = <0>;
 	};
 
+	fuse at 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 at 80003000 {
 		compatible = "nvidia,tegra20-pcie";
 		device_type = "pci";
diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi
index dec4fc823901..0b1ede940d1f 100644
--- a/arch/arm/boot/dts/tegra30.dtsi
+++ b/arch/arm/boot/dts/tegra30.dtsi
@@ -335,6 +335,12 @@
 		interrupt-controller;
 	};
 
+	apbmisc at 70000800 {
+		compatible = "nvidia,tegra30-apbmisc", "nvidia,tegra20-apbmisc";
+		reg = <0x70000800 0x64   /* Chip revision */
+		       0x70000008 0x04>; /* Strapping options */
+	};
+
 	pinmux: pinmux at 70000868 {
 		compatible = "nvidia,tegra30-pinmux";
 		reg = <0x70000868 0xd4    /* Pad control registers */
@@ -631,6 +637,15 @@
 		nvidia,ahb = <&ahb>;
 	};
 
+	fuse at 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 at 70080000 {
 		compatible = "nvidia,tegra30-ahub";
 		reg = <0x70080000 0x200
-- 
2.0.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 07/12] soc/tegra: fuse: move APB DMA into Tegra20 fuse driver
  2014-07-11 12:15 [PATCH 00/12] Add NVIDIA Tegra FUSE driver Thierry Reding
                   ` (5 preceding siblings ...)
  2014-07-11 12:16 ` [PATCH 06/12] soc/tegra: Add efuse and apbmisc bindings Thierry Reding
@ 2014-07-11 12:16 ` Thierry Reding
  2014-07-11 12:16 ` [PATCH 08/12] misc: fuse: fix dummy functions Thierry Reding
                   ` (5 subsequent siblings)
  12 siblings, 0 replies; 38+ messages in thread
From: Thierry Reding @ 2014-07-11 12:16 UTC (permalink / raw)
  To: linux-arm-kernel

From: Peter De Schrijver <pdeschrijver@nvidia.com>

The Tegra20 fuse driver is the only user of tegra_apb_readl_using_dma().
Therefore we can simply the code by incorporating the APB DMA handling into
the driver directly. tegra_apb_writel_using_dma() is dropped because there
are no users.

Signed-off-by: Peter De Schrijver <pdeschrijver@nvidia.com>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 arch/arm/mach-tegra/Makefile          |   1 -
 arch/arm/mach-tegra/apbio.c           | 217 ----------------------------------
 arch/arm/mach-tegra/apbio.h           |  22 ----
 arch/arm/mach-tegra/tegra.c           |   2 -
 drivers/soc/tegra/fuse/fuse-tegra20.c |  79 ++++++++++++-
 include/linux/tegra-soc.h             |  14 ---
 6 files changed, 76 insertions(+), 259 deletions(-)
 delete mode 100644 arch/arm/mach-tegra/apbio.c
 delete mode 100644 arch/arm/mach-tegra/apbio.h

diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index e8601bb56f98..c303b55de22e 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -5,7 +5,6 @@ obj-y                                   += irq.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
diff --git a/arch/arm/mach-tegra/apbio.c b/arch/arm/mach-tegra/apbio.c
deleted file mode 100644
index f2488722c79c..000000000000
--- a/arch/arm/mach-tegra/apbio.c
+++ /dev/null
@@ -1,217 +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/completion.h>
-#include <linux/dmaengine.h>
-#include <linux/dma-mapping.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/mutex.h>
-#include <linux/of.h>
-#include <linux/sched.h>
-#include <linux/spinlock.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 int tegra_apb_readl_direct(unsigned long offset, u32 *value);
-static int 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;
-}
-
-int tegra_apb_readl_using_dma(unsigned long offset, u32 *value)
-{
-	int ret;
-
-	if (!tegra_apb_dma_chan && !tegra_apb_dma_init())
-		return tegra_apb_readl_direct(offset, value);
-
-	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);
-	else
-		*value = *tegra_apb_bb;
-
-	mutex_unlock(&tegra_apb_dma_lock);
-
-	return ret;
-}
-
-int tegra_apb_writel_using_dma(u32 value, unsigned long offset)
-{
-	int ret;
-
-	if (!tegra_apb_dma_chan && !tegra_apb_dma_init())
-		return tegra_apb_writel_direct(value, offset);
-
-	mutex_lock(&tegra_apb_dma_lock);
-	*((u32 *)tegra_apb_bb) = value;
-	ret = do_dma_transfer(offset, DMA_MEM_TO_DEV);
-	mutex_unlock(&tegra_apb_dma_lock);
-	if (ret < 0)
-		pr_err("error in writing offset 0x%08lx using dma\n", offset);
-
-	return ret;
-}
-#else
-#define tegra_apb_readl_using_dma tegra_apb_readl_direct
-#define tegra_apb_writel_using_dma tegra_apb_writel_direct
-#endif
-
-typedef int (*apbio_read_fptr)(unsigned long offset, u32 *value);
-typedef int (*apbio_write_fptr)(u32 value, unsigned long offset);
-
-static apbio_read_fptr apbio_read;
-static apbio_write_fptr apbio_write;
-
-static int tegra_apb_readl_direct(unsigned long offset, u32 *value)
-{
-	*value = readl(IO_ADDRESS(offset));
-
-	return 0;
-}
-
-static int tegra_apb_writel_direct(u32 value, unsigned long offset)
-{
-	writel(value, IO_ADDRESS(offset));
-
-	return 0;
-}
-
-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)
-{
-	u32 val;
-
-	if (apbio_read(offset, &val) < 0)
-		return 0;
-	else
-		return val;
-}
-
-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 f05d71c303c7..000000000000
--- 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/tegra.c b/arch/arm/mach-tegra/tegra.c
index 1d60be4975b8..869fddd7e83e 100644
--- a/arch/arm/mach-tegra/tegra.c
+++ b/arch/arm/mach-tegra/tegra.c
@@ -43,7 +43,6 @@
 #include <asm/setup.h>
 #include <asm/trusted_foundations.h>
 
-#include "apbio.h"
 #include "board.h"
 #include "common.h"
 #include "cpuidle.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();
diff --git a/drivers/soc/tegra/fuse/fuse-tegra20.c b/drivers/soc/tegra/fuse/fuse-tegra20.c
index 09f91bf8c743..c3dcf1118337 100644
--- a/drivers/soc/tegra/fuse/fuse-tegra20.c
+++ b/drivers/soc/tegra/fuse/fuse-tegra20.c
@@ -18,6 +18,9 @@
 
 #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>
@@ -38,18 +41,58 @@ 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;
+	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);
 
-	ret = tegra_apb_readl_using_dma(fuse_phys + FUSE_BEGIN + offset, &val);
+	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 (ret < 0) ? 0 : val;
+	return val;
 }
 
 static const struct of_device_id tegra20_fuse_of_match[] = {
@@ -57,9 +100,35 @@ static const struct of_device_id tegra20_fuse_of_match[] = {
 	{},
 };
 
+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)) {
@@ -72,6 +141,10 @@ static int tegra20_fuse_probe(struct platform_device *pdev)
 		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;
 
diff --git a/include/linux/tegra-soc.h b/include/linux/tegra-soc.h
index 3d984219aaa1..7e8a33a88545 100644
--- a/include/linux/tegra-soc.h
+++ b/include/linux/tegra-soc.h
@@ -61,20 +61,6 @@ int tegra_fuse_readl(unsigned long offset, u32 *value);
 
 extern struct tegra_sku_info tegra_sku_info;
 
-#if defined(CONFIG_TEGRA20_APB_DMA)
-int tegra_apb_readl_using_dma(unsigned long offset, u32 *value);
-int tegra_apb_writel_using_dma(u32 value, unsigned long offset);
-#else
-static inline int tegra_apb_readl_using_dma(unsigned long offset, u32 *value)
-{
-	return -EINVAL;
-}
-static inline int tegra_apb_writel_using_dma(u32 value, unsigned long offset)
-{
-	return -EINVAL;
-}
-#endif /* CONFIG_TEGRA20_APB_DMA */
-
 #endif /* __ASSEMBLY__ */
 
 #endif /* __LINUX_TEGRA_SOC_H_ */
-- 
2.0.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 08/12] misc: fuse: fix dummy functions
  2014-07-11 12:15 [PATCH 00/12] Add NVIDIA Tegra FUSE driver Thierry Reding
                   ` (6 preceding siblings ...)
  2014-07-11 12:16 ` [PATCH 07/12] soc/tegra: fuse: move APB DMA into Tegra20 fuse driver Thierry Reding
@ 2014-07-11 12:16 ` Thierry Reding
  2014-07-11 12:16 ` [PATCH 09/12] ARM: tegra: Setup CPU hotplug in a pure initcall Thierry Reding
                   ` (4 subsequent siblings)
  12 siblings, 0 replies; 38+ messages in thread
From: Thierry Reding @ 2014-07-11 12:16 UTC (permalink / raw)
  To: linux-arm-kernel

From: Stephen Warren <swarren@nvidia.com>

The Tegra fuse header's dummy functions for the case where Tegra20 is
disabled are inconsistent with the correct prototypes, and have some
syntax errors. Fix these. While at it, fix the indentation level of
the dummy function bodies.

Fixes: 3aa9ba4b265b ("soc/tegra: Add efuse driver for Tegra")
Cc: Peter De Schrijver <pdeschrijver@nvidia.com>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 drivers/soc/tegra/fuse/fuse.h | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/soc/tegra/fuse/fuse.h b/drivers/soc/tegra/fuse/fuse.h
index b3442770df09..3a398bf3572c 100644
--- a/drivers/soc/tegra/fuse/fuse.h
+++ b/drivers/soc/tegra/fuse/fuse.h
@@ -38,14 +38,14 @@ 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, void *fuse_base)
+static inline bool tegra20_spare_fuse_early(int spare_bit)
 {
-			return false;
+	return false;
 }
-static inline void tegra20_init_fuse_early(void);
-static inline tegra20_fuse_early(const unsigned int offset);
+static inline void tegra20_init_fuse_early(void) {}
+static inline u32 tegra20_fuse_early(const unsigned int offset)
 {
-			return 0;
+	return 0;
 }
 #endif
 
-- 
2.0.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 09/12] ARM: tegra: Setup CPU hotplug in a pure initcall
  2014-07-11 12:15 [PATCH 00/12] Add NVIDIA Tegra FUSE driver Thierry Reding
                   ` (7 preceding siblings ...)
  2014-07-11 12:16 ` [PATCH 08/12] misc: fuse: fix dummy functions Thierry Reding
@ 2014-07-11 12:16 ` Thierry Reding
  2014-07-11 12:16 ` [PATCH 10/12] ARM: tegra: Always lock the CPU reset vector Thierry Reding
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 38+ messages in thread
From: Thierry Reding @ 2014-07-11 12:16 UTC (permalink / raw)
  To: linux-arm-kernel

From: Thierry Reding <treding@nvidia.com>

CPU hotplug support doesn't have to be set up until fairly late in the
boot process, so it can be done in a regular initcall. To make sure that
we don't miss any ordering problems in the future, output a warning if
any of the functions are called before initialization has completed.

This is part of untangling the boot order dependencies on Tegra so that
more code can be shared between 32-bit and 64-bit ARM.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 arch/arm/mach-tegra/hotplug.c | 12 ++++++++++--
 arch/arm/mach-tegra/sleep.h   |  3 ---
 arch/arm/mach-tegra/tegra.c   |  1 -
 3 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/arch/arm/mach-tegra/hotplug.c b/arch/arm/mach-tegra/hotplug.c
index d0a37dcbbb5d..e2ea4aa8f675 100644
--- a/arch/arm/mach-tegra/hotplug.c
+++ b/arch/arm/mach-tegra/hotplug.c
@@ -37,6 +37,11 @@ int tegra_cpu_kill(unsigned cpu)
  */
 void __ref tegra_cpu_die(unsigned int cpu)
 {
+	if (!tegra_hotplug_shutdown) {
+		WARN(1, "hotplug is not yet initialized\n");
+		return;
+	}
+
 	/* Clean L1 data cache */
 	tegra_disable_clean_inv_dcache(TEGRA_FLUSH_CACHE_LOUIS);
 
@@ -47,10 +52,10 @@ void __ref tegra_cpu_die(unsigned int cpu)
 	BUG();
 }
 
-void __init tegra_hotplug_init(void)
+static int __init tegra_hotplug_init(void)
 {
 	if (!IS_ENABLED(CONFIG_HOTPLUG_CPU))
-		return;
+		return 0;
 
 	if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) && tegra_get_chip_id() == TEGRA20)
 		tegra_hotplug_shutdown = tegra20_hotplug_shutdown;
@@ -60,4 +65,7 @@ void __init tegra_hotplug_init(void)
 		tegra_hotplug_shutdown = tegra30_hotplug_shutdown;
 	if (IS_ENABLED(CONFIG_ARCH_TEGRA_124_SOC) && tegra_get_chip_id() == TEGRA124)
 		tegra_hotplug_shutdown = tegra30_hotplug_shutdown;
+
+	return 0;
 }
+pure_initcall(tegra_hotplug_init);
diff --git a/arch/arm/mach-tegra/sleep.h b/arch/arm/mach-tegra/sleep.h
index 339fe42cd6fb..92d46ec1361a 100644
--- a/arch/arm/mach-tegra/sleep.h
+++ b/arch/arm/mach-tegra/sleep.h
@@ -130,9 +130,6 @@ void tegra_disable_clean_inv_dcache(u32 flag);
 #ifdef CONFIG_HOTPLUG_CPU
 void tegra20_hotplug_shutdown(void);
 void tegra30_hotplug_shutdown(void);
-void tegra_hotplug_init(void);
-#else
-static inline void tegra_hotplug_init(void) {}
 #endif
 
 void tegra20_cpu_shutdown(int cpu);
diff --git a/arch/arm/mach-tegra/tegra.c b/arch/arm/mach-tegra/tegra.c
index 869fddd7e83e..b7d57027ae67 100644
--- a/arch/arm/mach-tegra/tegra.c
+++ b/arch/arm/mach-tegra/tegra.c
@@ -75,7 +75,6 @@ static void __init tegra_init_early(void)
 	tegra_init_fuse();
 	tegra_cpu_reset_handler_init();
 	tegra_powergate_init();
-	tegra_hotplug_init();
 }
 
 static void __init tegra_dt_init_irq(void)
-- 
2.0.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 10/12] ARM: tegra: Always lock the CPU reset vector
  2014-07-11 12:15 [PATCH 00/12] Add NVIDIA Tegra FUSE driver Thierry Reding
                   ` (8 preceding siblings ...)
  2014-07-11 12:16 ` [PATCH 09/12] ARM: tegra: Setup CPU hotplug in a pure initcall Thierry Reding
@ 2014-07-11 12:16 ` Thierry Reding
  2014-07-11 12:16 ` [PATCH 11/12] soc/tegra: fuse: Set up in early initcall Thierry Reding
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 38+ messages in thread
From: Thierry Reding @ 2014-07-11 12:16 UTC (permalink / raw)
  To: linux-arm-kernel

From: Thierry Reding <treding@nvidia.com>

Currently the reset vector is not locked on Tegra20 because the hardware
doesn't support it. However in order not to depend on the chip ID, which
becomes available only later in the boot process, we set the bit anyway.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 arch/arm/mach-tegra/reset.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/arch/arm/mach-tegra/reset.c b/arch/arm/mach-tegra/reset.c
index e997b2573893..96cafc426cdb 100644
--- a/arch/arm/mach-tegra/reset.c
+++ b/arch/arm/mach-tegra/reset.c
@@ -53,12 +53,10 @@ static void __init tegra_cpu_reset_handler_set(const u32 reset_address)
 	 * Prevent further modifications to the physical reset vector.
 	 *  NOTE: Has no effect on chips prior to Tegra30.
 	 */
-	if (tegra_get_chip_id() != TEGRA20) {
-		reg = readl(sb_ctrl);
-		reg |= 2;
-		writel(reg, sb_ctrl);
-		wmb();
-	}
+	reg = readl(sb_ctrl);
+	reg |= 2;
+	writel(reg, sb_ctrl);
+	wmb();
 }
 
 static void __init tegra_cpu_reset_handler_enable(void)
-- 
2.0.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 11/12] soc/tegra: fuse: Set up in early initcall
  2014-07-11 12:15 [PATCH 00/12] Add NVIDIA Tegra FUSE driver Thierry Reding
                   ` (9 preceding siblings ...)
  2014-07-11 12:16 ` [PATCH 10/12] ARM: tegra: Always lock the CPU reset vector Thierry Reding
@ 2014-07-11 12:16 ` Thierry Reding
  2014-07-11 12:16 ` [PATCH 12/12] ARM: tegra: Convert PMC to a driver Thierry Reding
  2014-07-13  6:38 ` [PATCH 00/12] Add NVIDIA Tegra FUSE driver Olof Johansson
  12 siblings, 0 replies; 38+ messages in thread
From: Thierry Reding @ 2014-07-11 12:16 UTC (permalink / raw)
  To: linux-arm-kernel

From: Thierry Reding <treding@nvidia.com>

Rather than rely on explicit initialization order called from SoC setup
code, use a plain initcall and rely on initcall ordering to take care of
dependencies.

This driver exposes some functionality (querying the chip ID) needed at
very early stages of the boot process. An early initcall is good enough
provided that some of the dependencies are deferred to later stages. To
make sure any abuses are easily caught, output a warning message if the
chip ID is queried while it can't be read yet.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 arch/arm/mach-tegra/tegra.c            | 1 -
 drivers/soc/tegra/fuse/fuse-tegra.c    | 7 +++++--
 drivers/soc/tegra/fuse/tegra-apbmisc.c | 7 +++++--
 include/linux/tegra-soc.h              | 1 -
 4 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/arch/arm/mach-tegra/tegra.c b/arch/arm/mach-tegra/tegra.c
index b7d57027ae67..f05c4a648370 100644
--- a/arch/arm/mach-tegra/tegra.c
+++ b/arch/arm/mach-tegra/tegra.c
@@ -72,7 +72,6 @@ u32 tegra_uart_config[3] = {
 static void __init tegra_init_early(void)
 {
 	of_register_trusted_foundations();
-	tegra_init_fuse();
 	tegra_cpu_reset_handler_init();
 	tegra_powergate_init();
 }
diff --git a/drivers/soc/tegra/fuse/fuse-tegra.c b/drivers/soc/tegra/fuse/fuse-tegra.c
index 6a6dac1754b1..7cf83ddb7643 100644
--- a/drivers/soc/tegra/fuse/fuse-tegra.c
+++ b/drivers/soc/tegra/fuse/fuse-tegra.c
@@ -124,7 +124,7 @@ int tegra_fuse_create_sysfs(struct device *dev, int size,
 	return device_create_bin_file(dev, &fuse_bin_attr);
 }
 
-void __init tegra_init_fuse(void)
+static int __init tegra_init_fuse(void)
 {
 	struct device_node *np;
 	void __iomem *car_base;
@@ -138,7 +138,7 @@ void __init tegra_init_fuse(void)
 		iounmap(car_base);
 	} else {
 		pr_err("Could not enable fuse clk. ioremap tegra car failed.\n");
-		return;
+		return -ENXIO;
 	}
 
 	if (tegra_get_chip_id() == TEGRA20)
@@ -152,4 +152,7 @@ void __init tegra_init_fuse(void)
 		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);
+
+	return 0;
 }
+early_initcall(tegra_init_fuse);
diff --git a/drivers/soc/tegra/fuse/tegra-apbmisc.c b/drivers/soc/tegra/fuse/tegra-apbmisc.c
index d51d8159a3f8..30126e6ac68e 100644
--- a/drivers/soc/tegra/fuse/tegra-apbmisc.c
+++ b/drivers/soc/tegra/fuse/tegra-apbmisc.c
@@ -37,9 +37,12 @@ u32 tegra_read_chipid(void)
 
 u8 tegra_get_chip_id(void)
 {
-	u32 id = tegra_read_chipid();
+	if (!apbmisc_base) {
+		WARN(1, "Tegra Chip ID not yet available\n");
+		return 0;
+	}
 
-	return (id >> 8) & 0xff;
+	return (tegra_read_chipid() >> 8) & 0xff;
 }
 
 u32 tegra_read_straps(void)
diff --git a/include/linux/tegra-soc.h b/include/linux/tegra-soc.h
index 7e8a33a88545..f50416851fa9 100644
--- a/include/linux/tegra-soc.h
+++ b/include/linux/tegra-soc.h
@@ -56,7 +56,6 @@ struct tegra_sku_info {
 
 u32 tegra_read_straps(void);
 u32 tegra_read_chipid(void);
-void tegra_init_fuse(void);
 int tegra_fuse_readl(unsigned long offset, u32 *value);
 
 extern struct tegra_sku_info tegra_sku_info;
-- 
2.0.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 12/12] ARM: tegra: Convert PMC to a driver
  2014-07-11 12:15 [PATCH 00/12] Add NVIDIA Tegra FUSE driver Thierry Reding
                   ` (10 preceding siblings ...)
  2014-07-11 12:16 ` [PATCH 11/12] soc/tegra: fuse: Set up in early initcall Thierry Reding
@ 2014-07-11 12:16 ` Thierry Reding
  2014-07-11 13:58   ` Peter De Schrijver
  2014-07-16 11:56   ` Arnd Bergmann
  2014-07-13  6:38 ` [PATCH 00/12] Add NVIDIA Tegra FUSE driver Olof Johansson
  12 siblings, 2 replies; 38+ messages in thread
From: Thierry Reding @ 2014-07-11 12:16 UTC (permalink / raw)
  To: linux-arm-kernel

From: Thierry Reding <treding@nvidia.com>

This commit converts the PMC support code to a platform driver. Because
the boot process needs to cal into this driver very early, also set up a
minimal environment via an early initcall.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 arch/arm/mach-tegra/Makefile    |   3 +-
 arch/arm/mach-tegra/board.h     |   7 -
 arch/arm/mach-tegra/platsmp.c   |   1 -
 arch/arm/mach-tegra/pm.c        |  30 +-
 arch/arm/mach-tegra/pm.h        |  10 +-
 arch/arm/mach-tegra/pmc.c       | 413 -----------------
 arch/arm/mach-tegra/pmc.h       |  49 ---
 arch/arm/mach-tegra/powergate.c | 515 ----------------------
 arch/arm/mach-tegra/tegra-pmc.c | 948 ++++++++++++++++++++++++++++++++++++++++
 arch/arm/mach-tegra/tegra.c     |   6 -
 include/linux/tegra-soc.h       |  46 ++
 11 files changed, 1018 insertions(+), 1010 deletions(-)
 delete mode 100644 arch/arm/mach-tegra/pmc.c
 delete mode 100644 arch/arm/mach-tegra/pmc.h
 delete mode 100644 arch/arm/mach-tegra/powergate.c
 create mode 100644 arch/arm/mach-tegra/tegra-pmc.c

diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index c303b55de22e..34c05b775d7f 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -2,14 +2,13 @@ asflags-y				+= -march=armv7-a
 
 obj-y                                   += io.o
 obj-y                                   += irq.o
-obj-y					+= pmc.o
 obj-y					+= flowctrl.o
-obj-y					+= powergate.o
 obj-y					+= pm.o
 obj-y					+= reset.o
 obj-y					+= reset-handler.o
 obj-y					+= sleep.o
 obj-y					+= tegra.o
+obj-y					+= tegra-pmc.o
 obj-$(CONFIG_CPU_IDLE)			+= cpuidle.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= sleep-tegra20.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= pm-tegra20.o
diff --git a/arch/arm/mach-tegra/board.h b/arch/arm/mach-tegra/board.h
index bcf5dbf69d58..da90c89296b9 100644
--- a/arch/arm/mach-tegra/board.h
+++ b/arch/arm/mach-tegra/board.h
@@ -28,13 +28,6 @@
 void __init tegra_map_common_io(void);
 void __init tegra_init_irq(void);
 
-int __init tegra_powergate_init(void);
-#if defined(CONFIG_ARCH_TEGRA_2x_SOC) && defined(CONFIG_DEBUG_FS)
-int __init tegra_powergate_debugfs_init(void);
-#else
-static inline int tegra_powergate_debugfs_init(void) { return 0; }
-#endif
-
 void __init tegra_paz00_wifikill_init(void);
 
 #endif
diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c
index 9679984650bd..53e8442b2e06 100644
--- a/arch/arm/mach-tegra/platsmp.c
+++ b/arch/arm/mach-tegra/platsmp.c
@@ -30,7 +30,6 @@
 #include "common.h"
 #include "flowctrl.h"
 #include "iomap.h"
-#include "pmc.h"
 #include "reset.h"
 
 static cpumask_t tegra_cpu_init_mask;
diff --git a/arch/arm/mach-tegra/pm.c b/arch/arm/mach-tegra/pm.c
index cd5bb6d876c7..d9637d81805f 100644
--- a/arch/arm/mach-tegra/pm.c
+++ b/arch/arm/mach-tegra/pm.c
@@ -37,7 +37,6 @@
 
 #include "flowctrl.h"
 #include "iomap.h"
-#include "pmc.h"
 #include "pm.h"
 #include "reset.h"
 #include "sleep.h"
@@ -166,9 +165,29 @@ static int tegra_sleep_cpu(unsigned long v2p)
 	return 0;
 }
 
+static void tegra_pm_set(enum tegra_suspend_mode mode)
+{
+	u32 value;
+
+	switch (tegra_get_chip_id()) {
+	case TEGRA20:
+	case TEGRA30:
+		break;
+	default:
+		/* Turn off CRAIL */
+		value = flowctrl_read_cpu_csr(0);
+		value &= ~FLOW_CTRL_CSR_ENABLE_EXT_MASK;
+		value |= FLOW_CTRL_CSR_ENABLE_EXT_CRAIL;
+		flowctrl_write_cpu_csr(0, value);
+		break;
+	}
+
+	tegra_pmc_enter_suspend_mode(mode);
+}
+
 void tegra_idle_lp2_last(void)
 {
-	tegra_pmc_pm_set(TEGRA_SUSPEND_LP2);
+	tegra_pm_set(TEGRA_SUSPEND_LP2);
 
 	cpu_cluster_pm_enter();
 	suspend_cpu_complex();
@@ -267,8 +286,6 @@ static bool tegra_sleep_core_init(void)
 
 static void tegra_suspend_enter_lp1(void)
 {
-	tegra_pmc_suspend();
-
 	/* copy the reset vector & SDRAM shutdown code into IRAM */
 	memcpy(iram_save_addr, IO_ADDRESS(TEGRA_IRAM_LPx_RESUME_AREA),
 		iram_save_size);
@@ -280,8 +297,6 @@ static void tegra_suspend_enter_lp1(void)
 
 static void tegra_suspend_exit_lp1(void)
 {
-	tegra_pmc_resume();
-
 	/* restore IRAM */
 	memcpy(IO_ADDRESS(TEGRA_IRAM_LPx_RESUME_AREA), iram_save_addr,
 		iram_save_size);
@@ -306,7 +321,7 @@ static int tegra_suspend_enter(suspend_state_t state)
 
 	pr_info("Entering suspend state %s\n", lp_state[mode]);
 
-	tegra_pmc_pm_set(mode);
+	tegra_pm_set(mode);
 
 	local_fiq_disable();
 
@@ -354,7 +369,6 @@ void __init tegra_init_suspend(void)
 		return;
 
 	tegra_tear_down_cpu_init();
-	tegra_pmc_suspend_init();
 
 	if (mode >= TEGRA_SUSPEND_LP1) {
 		if (!tegra_lp1_iram_hook() || !tegra_sleep_core_init()) {
diff --git a/arch/arm/mach-tegra/pm.h b/arch/arm/mach-tegra/pm.h
index f4a89698e5b0..83bc87583446 100644
--- a/arch/arm/mach-tegra/pm.h
+++ b/arch/arm/mach-tegra/pm.h
@@ -21,12 +21,11 @@
 #ifndef _MACH_TEGRA_PM_H_
 #define _MACH_TEGRA_PM_H_
 
-#include "pmc.h"
-
 struct tegra_lp1_iram {
 	void	*start_addr;
 	void	*end_addr;
 };
+
 extern struct tegra_lp1_iram tegra_lp1_iram;
 extern void (*tegra_sleep_core_finish)(unsigned long v2p);
 
@@ -42,15 +41,8 @@ void tegra_idle_lp2_last(void);
 extern void (*tegra_tear_down_cpu)(void);
 
 #ifdef CONFIG_PM_SLEEP
-enum tegra_suspend_mode tegra_pm_validate_suspend_mode(
-				enum tegra_suspend_mode mode);
 void tegra_init_suspend(void);
 #else
-static inline enum tegra_suspend_mode tegra_pm_validate_suspend_mode(
-				enum tegra_suspend_mode mode)
-{
-	return TEGRA_SUSPEND_NONE;
-}
 static inline void tegra_init_suspend(void) {}
 #endif
 
diff --git a/arch/arm/mach-tegra/pmc.c b/arch/arm/mach-tegra/pmc.c
deleted file mode 100644
index e255d39f8657..000000000000
--- a/arch/arm/mach-tegra/pmc.c
+++ /dev/null
@@ -1,413 +0,0 @@
-/*
- * Copyright (C) 2012,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/clk.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/tegra-powergate.h>
-#include <linux/tegra-soc.h>
-
-#include "flowctrl.h"
-#include "pm.h"
-#include "pmc.h"
-#include "sleep.h"
-
-#define TEGRA_POWER_SYSCLK_POLARITY	(1 << 10)  /* sys clk polarity */
-#define TEGRA_POWER_SYSCLK_OE		(1 << 11)  /* system clock enable */
-#define TEGRA_POWER_EFFECT_LP0		(1 << 14)  /* LP0 when CPU pwr gated */
-#define TEGRA_POWER_CPU_PWRREQ_POLARITY	(1 << 15)  /* CPU pwr req polarity */
-#define TEGRA_POWER_CPU_PWRREQ_OE	(1 << 16)  /* CPU pwr req enable */
-
-#define PMC_CTRL			0x0
-#define PMC_CTRL_INTR_LOW		(1 << 17)
-#define PMC_PWRGATE_TOGGLE		0x30
-#define PMC_PWRGATE_TOGGLE_START	(1 << 8)
-#define PMC_REMOVE_CLAMPING		0x34
-#define PMC_PWRGATE_STATUS		0x38
-
-#define PMC_SCRATCH0			0x50
-#define PMC_SCRATCH0_MODE_RECOVERY	(1 << 31)
-#define PMC_SCRATCH0_MODE_BOOTLOADER	(1 << 30)
-#define PMC_SCRATCH0_MODE_RCM		(1 << 1)
-#define PMC_SCRATCH0_MODE_MASK		(PMC_SCRATCH0_MODE_RECOVERY | \
-					 PMC_SCRATCH0_MODE_BOOTLOADER | \
-					 PMC_SCRATCH0_MODE_RCM)
-
-#define PMC_CPUPWRGOOD_TIMER	0xc8
-#define PMC_CPUPWROFF_TIMER	0xcc
-
-static u8 tegra_cpu_domains[] = {
-	0xFF,			/* not available for CPU0 */
-	TEGRA_POWERGATE_CPU1,
-	TEGRA_POWERGATE_CPU2,
-	TEGRA_POWERGATE_CPU3,
-};
-static DEFINE_SPINLOCK(tegra_powergate_lock);
-
-static void __iomem *tegra_pmc_base;
-static bool tegra_pmc_invert_interrupt;
-static struct clk *tegra_pclk;
-
-struct pmc_pm_data {
-	u32 cpu_good_time;	/* CPU power good time in uS */
-	u32 cpu_off_time;	/* CPU power off time in uS */
-	u32 core_osc_time;	/* Core power good osc time in uS */
-	u32 core_pmu_time;	/* Core power good pmu time in uS */
-	u32 core_off_time;	/* Core power off time in uS */
-	bool corereq_high;	/* Core power request active-high */
-	bool sysclkreq_high;	/* System clock request active-high */
-	bool combined_req;	/* Combined pwr req for CPU & Core */
-	bool cpu_pwr_good_en;	/* CPU power good signal is enabled */
-	u32 lp0_vec_phy_addr;	/* The phy addr of LP0 warm boot code */
-	u32 lp0_vec_size;	/* The size of LP0 warm boot code */
-	enum tegra_suspend_mode suspend_mode;
-};
-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())
-		return -EINVAL;
-	return tegra_cpu_domains[cpuid];
-}
-
-static bool tegra_pmc_powergate_is_powered(int id)
-{
-	return (tegra_pmc_readl(PMC_PWRGATE_STATUS) >> id) & 1;
-}
-
-static int tegra_pmc_powergate_set(int id, bool new_state)
-{
-	bool old_state;
-	unsigned long flags;
-
-	spin_lock_irqsave(&tegra_powergate_lock, flags);
-
-	old_state = tegra_pmc_powergate_is_powered(id);
-	WARN_ON(old_state == new_state);
-
-	tegra_pmc_writel(PMC_PWRGATE_TOGGLE_START | id, PMC_PWRGATE_TOGGLE);
-
-	spin_unlock_irqrestore(&tegra_powergate_lock, flags);
-
-	return 0;
-}
-
-static int tegra_pmc_powergate_remove_clamping(int id)
-{
-	u32 mask;
-
-	/*
-	 * Tegra has a bug where PCIE and VDE clamping masks are
-	 * swapped relatively to the partition ids.
-	 */
-	if (id ==  TEGRA_POWERGATE_VDEC)
-		mask = (1 << TEGRA_POWERGATE_PCIE);
-	else if	(id == TEGRA_POWERGATE_PCIE)
-		mask = (1 << TEGRA_POWERGATE_VDEC);
-	else
-		mask = (1 << id);
-
-	tegra_pmc_writel(mask, PMC_REMOVE_CLAMPING);
-
-	return 0;
-}
-
-bool tegra_pmc_cpu_is_powered(int cpuid)
-{
-	int id;
-
-	id = tegra_pmc_get_cpu_powerdomain_id(cpuid);
-	if (id < 0)
-		return false;
-	return tegra_pmc_powergate_is_powered(id);
-}
-
-int tegra_pmc_cpu_power_on(int cpuid)
-{
-	int id;
-
-	id = tegra_pmc_get_cpu_powerdomain_id(cpuid);
-	if (id < 0)
-		return id;
-	return tegra_pmc_powergate_set(id, true);
-}
-
-int tegra_pmc_cpu_remove_clamping(int cpuid)
-{
-	int id;
-
-	id = tegra_pmc_get_cpu_powerdomain_id(cpuid);
-	if (id < 0)
-		return id;
-	return tegra_pmc_powergate_remove_clamping(id);
-}
-
-void tegra_pmc_restart(enum reboot_mode mode, const char *cmd)
-{
-	u32 val;
-
-	val = tegra_pmc_readl(PMC_SCRATCH0);
-	val &= ~PMC_SCRATCH0_MODE_MASK;
-
-	if (cmd) {
-		if (strcmp(cmd, "recovery") == 0)
-			val |= PMC_SCRATCH0_MODE_RECOVERY;
-
-		if (strcmp(cmd, "bootloader") == 0)
-			val |= PMC_SCRATCH0_MODE_BOOTLOADER;
-
-		if (strcmp(cmd, "forced-recovery") == 0)
-			val |= PMC_SCRATCH0_MODE_RCM;
-	}
-
-	tegra_pmc_writel(val, PMC_SCRATCH0);
-
-	val = tegra_pmc_readl(0);
-	val |= 0x10;
-	tegra_pmc_writel(val, 0);
-}
-
-#ifdef CONFIG_PM_SLEEP
-static void set_power_timers(u32 us_on, u32 us_off, unsigned long rate)
-{
-	unsigned long long ticks;
-	unsigned long long pclk;
-	static unsigned long tegra_last_pclk;
-
-	if (WARN_ON_ONCE(rate <= 0))
-		pclk = 100000000;
-	else
-		pclk = rate;
-
-	if ((rate != tegra_last_pclk)) {
-		ticks = (us_on * pclk) + 999999ull;
-		do_div(ticks, 1000000);
-		tegra_pmc_writel((unsigned long)ticks, PMC_CPUPWRGOOD_TIMER);
-
-		ticks = (us_off * pclk) + 999999ull;
-		do_div(ticks, 1000000);
-		tegra_pmc_writel((unsigned long)ticks, PMC_CPUPWROFF_TIMER);
-		wmb();
-	}
-	tegra_last_pclk = pclk;
-}
-
-enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void)
-{
-	return pmc_pm_data.suspend_mode;
-}
-
-void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode)
-{
-	if (mode < TEGRA_SUSPEND_NONE || mode >= TEGRA_MAX_SUSPEND_MODE)
-		return;
-
-	pmc_pm_data.suspend_mode = mode;
-}
-
-void tegra_pmc_suspend(void)
-{
-	tegra_pmc_writel(virt_to_phys(tegra_resume), PMC_SCRATCH41);
-}
-
-void tegra_pmc_resume(void)
-{
-	tegra_pmc_writel(0x0, PMC_SCRATCH41);
-}
-
-void tegra_pmc_pm_set(enum tegra_suspend_mode mode)
-{
-	u32 reg, csr_reg;
-	unsigned long rate = 0;
-
-	reg = tegra_pmc_readl(PMC_CTRL);
-	reg |= TEGRA_POWER_CPU_PWRREQ_OE;
-	reg &= ~TEGRA_POWER_EFFECT_LP0;
-
-	switch (tegra_get_chip_id()) {
-	case TEGRA20:
-	case TEGRA30:
-		break;
-	default:
-		/* Turn off CRAIL */
-		csr_reg = flowctrl_read_cpu_csr(0);
-		csr_reg &= ~FLOW_CTRL_CSR_ENABLE_EXT_MASK;
-		csr_reg |= FLOW_CTRL_CSR_ENABLE_EXT_CRAIL;
-		flowctrl_write_cpu_csr(0, csr_reg);
-		break;
-	}
-
-	switch (mode) {
-	case TEGRA_SUSPEND_LP1:
-		rate = 32768;
-		break;
-	case TEGRA_SUSPEND_LP2:
-		rate = clk_get_rate(tegra_pclk);
-		break;
-	default:
-		break;
-	}
-
-	set_power_timers(pmc_pm_data.cpu_good_time, pmc_pm_data.cpu_off_time,
-			 rate);
-
-	tegra_pmc_writel(reg, PMC_CTRL);
-}
-
-void tegra_pmc_suspend_init(void)
-{
-	u32 reg;
-
-	/* Always enable CPU power request */
-	reg = tegra_pmc_readl(PMC_CTRL);
-	reg |= TEGRA_POWER_CPU_PWRREQ_OE;
-	tegra_pmc_writel(reg, PMC_CTRL);
-
-	reg = tegra_pmc_readl(PMC_CTRL);
-
-	if (!pmc_pm_data.sysclkreq_high)
-		reg |= TEGRA_POWER_SYSCLK_POLARITY;
-	else
-		reg &= ~TEGRA_POWER_SYSCLK_POLARITY;
-
-	/* configure the output polarity while the request is tristated */
-	tegra_pmc_writel(reg, PMC_CTRL);
-
-	/* now enable the request */
-	reg |= TEGRA_POWER_SYSCLK_OE;
-	tegra_pmc_writel(reg, PMC_CTRL);
-}
-#endif
-
-static const struct of_device_id matches[] __initconst = {
-	{ .compatible = "nvidia,tegra124-pmc" },
-	{ .compatible = "nvidia,tegra114-pmc" },
-	{ .compatible = "nvidia,tegra30-pmc" },
-	{ .compatible = "nvidia,tegra20-pmc" },
-	{ }
-};
-
-void __init tegra_pmc_init_irq(void)
-{
-	struct device_node *np;
-	u32 val;
-
-	np = of_find_matching_node(NULL, matches);
-	BUG_ON(!np);
-
-	tegra_pmc_base = of_iomap(np, 0);
-
-	tegra_pmc_invert_interrupt = of_property_read_bool(np,
-				     "nvidia,invert-interrupt");
-
-	val = tegra_pmc_readl(PMC_CTRL);
-	if (tegra_pmc_invert_interrupt)
-		val |= PMC_CTRL_INTR_LOW;
-	else
-		val &= ~PMC_CTRL_INTR_LOW;
-	tegra_pmc_writel(val, PMC_CTRL);
-}
-
-void __init tegra_pmc_init(void)
-{
-	struct device_node *np;
-	u32 prop;
-	enum tegra_suspend_mode suspend_mode;
-	u32 core_good_time[2] = {0, 0};
-	u32 lp0_vec[2] = {0, 0};
-
-	np = of_find_matching_node(NULL, matches);
-	BUG_ON(!np);
-
-	tegra_pclk = of_clk_get_by_name(np, "pclk");
-	WARN_ON(IS_ERR(tegra_pclk));
-
-	/* Grabbing the power management configurations */
-	if (of_property_read_u32(np, "nvidia,suspend-mode", &prop)) {
-		suspend_mode = TEGRA_SUSPEND_NONE;
-	} else {
-		switch (prop) {
-		case 0:
-			suspend_mode = TEGRA_SUSPEND_LP0;
-			break;
-		case 1:
-			suspend_mode = TEGRA_SUSPEND_LP1;
-			break;
-		case 2:
-			suspend_mode = TEGRA_SUSPEND_LP2;
-			break;
-		default:
-			suspend_mode = TEGRA_SUSPEND_NONE;
-			break;
-		}
-	}
-	suspend_mode = tegra_pm_validate_suspend_mode(suspend_mode);
-
-	if (of_property_read_u32(np, "nvidia,cpu-pwr-good-time", &prop))
-		suspend_mode = TEGRA_SUSPEND_NONE;
-	pmc_pm_data.cpu_good_time = prop;
-
-	if (of_property_read_u32(np, "nvidia,cpu-pwr-off-time", &prop))
-		suspend_mode = TEGRA_SUSPEND_NONE;
-	pmc_pm_data.cpu_off_time = prop;
-
-	if (of_property_read_u32_array(np, "nvidia,core-pwr-good-time",
-			core_good_time, ARRAY_SIZE(core_good_time)))
-		suspend_mode = TEGRA_SUSPEND_NONE;
-	pmc_pm_data.core_osc_time = core_good_time[0];
-	pmc_pm_data.core_pmu_time = core_good_time[1];
-
-	if (of_property_read_u32(np, "nvidia,core-pwr-off-time",
-				 &prop))
-		suspend_mode = TEGRA_SUSPEND_NONE;
-	pmc_pm_data.core_off_time = prop;
-
-	pmc_pm_data.corereq_high = of_property_read_bool(np,
-				"nvidia,core-power-req-active-high");
-
-	pmc_pm_data.sysclkreq_high = of_property_read_bool(np,
-				"nvidia,sys-clock-req-active-high");
-
-	pmc_pm_data.combined_req = of_property_read_bool(np,
-				"nvidia,combined-power-req");
-
-	pmc_pm_data.cpu_pwr_good_en = of_property_read_bool(np,
-				"nvidia,cpu-pwr-good-en");
-
-	if (of_property_read_u32_array(np, "nvidia,lp0-vec", lp0_vec,
-				       ARRAY_SIZE(lp0_vec)))
-		if (suspend_mode == TEGRA_SUSPEND_LP0)
-			suspend_mode = TEGRA_SUSPEND_LP1;
-
-	pmc_pm_data.lp0_vec_phy_addr = lp0_vec[0];
-	pmc_pm_data.lp0_vec_size = lp0_vec[1];
-
-	pmc_pm_data.suspend_mode = suspend_mode;
-}
diff --git a/arch/arm/mach-tegra/pmc.h b/arch/arm/mach-tegra/pmc.h
deleted file mode 100644
index 59e19c344298..000000000000
--- a/arch/arm/mach-tegra/pmc.h
+++ /dev/null
@@ -1,49 +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/>.
- *
- */
-
-#ifndef __MACH_TEGRA_PMC_H
-#define __MACH_TEGRA_PMC_H
-
-#include <linux/reboot.h>
-
-enum tegra_suspend_mode {
-	TEGRA_SUSPEND_NONE = 0,
-	TEGRA_SUSPEND_LP2,	/* CPU voltage off */
-	TEGRA_SUSPEND_LP1,	/* CPU voltage off, DRAM self-refresh */
-	TEGRA_SUSPEND_LP0,      /* CPU + core voltage off, DRAM self-refresh */
-	TEGRA_MAX_SUSPEND_MODE,
-};
-
-#ifdef CONFIG_PM_SLEEP
-enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void);
-void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode);
-void tegra_pmc_suspend(void);
-void tegra_pmc_resume(void);
-void tegra_pmc_pm_set(enum tegra_suspend_mode mode);
-void tegra_pmc_suspend_init(void);
-#endif
-
-bool tegra_pmc_cpu_is_powered(int cpuid);
-int tegra_pmc_cpu_power_on(int cpuid);
-int tegra_pmc_cpu_remove_clamping(int cpuid);
-
-void tegra_pmc_restart(enum reboot_mode mode, const char *cmd);
-
-void tegra_pmc_init_irq(void);
-void tegra_pmc_init(void);
-
-#endif
diff --git a/arch/arm/mach-tegra/powergate.c b/arch/arm/mach-tegra/powergate.c
deleted file mode 100644
index 1408f7e7321d..000000000000
--- a/arch/arm/mach-tegra/powergate.c
+++ /dev/null
@@ -1,515 +0,0 @@
-/*
- * drivers/powergate/tegra-powergate.c
- *
- * Copyright (c) 2010 Google, Inc
- *
- * Author:
- *	Colin Cross <ccross@google.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/clk.h>
-#include <linux/clk/tegra.h>
-#include <linux/debugfs.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/export.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/reset.h>
-#include <linux/seq_file.h>
-#include <linux/spinlock.h>
-#include <linux/tegra-powergate.h>
-#include <linux/tegra-soc.h>
-
-#include "iomap.h"
-
-#define DPD_SAMPLE		0x020
-#define  DPD_SAMPLE_ENABLE	(1 << 0)
-#define  DPD_SAMPLE_DISABLE	(0 << 0)
-
-#define PWRGATE_TOGGLE		0x30
-#define  PWRGATE_TOGGLE_START	(1 << 8)
-
-#define REMOVE_CLAMPING		0x34
-
-#define PWRGATE_STATUS		0x38
-
-#define IO_DPD_REQ		0x1b8
-#define  IO_DPD_REQ_CODE_IDLE	(0 << 30)
-#define  IO_DPD_REQ_CODE_OFF	(1 << 30)
-#define  IO_DPD_REQ_CODE_ON	(2 << 30)
-#define  IO_DPD_REQ_CODE_MASK	(3 << 30)
-
-#define IO_DPD_STATUS		0x1bc
-#define IO_DPD2_REQ		0x1c0
-#define IO_DPD2_STATUS		0x1c4
-#define SEL_DPD_TIM		0x1c8
-
-#define GPU_RG_CNTRL		0x2d4
-
-static int tegra_num_powerdomains;
-static int tegra_num_cpu_domains;
-static const u8 *tegra_cpu_domains;
-
-static const u8 tegra30_cpu_domains[] = {
-	TEGRA_POWERGATE_CPU,
-	TEGRA_POWERGATE_CPU1,
-	TEGRA_POWERGATE_CPU2,
-	TEGRA_POWERGATE_CPU3,
-};
-
-static const u8 tegra114_cpu_domains[] = {
-	TEGRA_POWERGATE_CPU0,
-	TEGRA_POWERGATE_CPU1,
-	TEGRA_POWERGATE_CPU2,
-	TEGRA_POWERGATE_CPU3,
-};
-
-static const u8 tegra124_cpu_domains[] = {
-	TEGRA_POWERGATE_CPU0,
-	TEGRA_POWERGATE_CPU1,
-	TEGRA_POWERGATE_CPU2,
-	TEGRA_POWERGATE_CPU3,
-};
-
-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;
-	unsigned long flags;
-
-	spin_lock_irqsave(&tegra_powergate_lock, flags);
-
-	status = pmc_read(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);
-
-	spin_unlock_irqrestore(&tegra_powergate_lock, flags);
-
-	return 0;
-}
-
-int tegra_powergate_power_on(int id)
-{
-	if (id < 0 || id >= tegra_num_powerdomains)
-		return -EINVAL;
-
-	return tegra_powergate_set(id, true);
-}
-
-int tegra_powergate_power_off(int id)
-{
-	if (id < 0 || id >= tegra_num_powerdomains)
-		return -EINVAL;
-
-	return tegra_powergate_set(id, false);
-}
-EXPORT_SYMBOL(tegra_powergate_power_off);
-
-int tegra_powergate_is_powered(int id)
-{
-	u32 status;
-
-	if (id < 0 || id >= tegra_num_powerdomains)
-		return -EINVAL;
-
-	status = pmc_read(PWRGATE_STATUS) & (1 << id);
-	return !!status;
-}
-
-int tegra_powergate_remove_clamping(int id)
-{
-	u32 mask;
-
-	if (id < 0 || id >= tegra_num_powerdomains)
-		return -EINVAL;
-
-	/*
-	 * The Tegra124 GPU has a separate register (with different semantics)
-	 * to remove clamps.
-	 */
-	if (tegra_get_chip_id() == TEGRA124) {
-		if (id == TEGRA_POWERGATE_3D) {
-			pmc_write(0, GPU_RG_CNTRL);
-			return 0;
-		}
-	}
-
-	/*
-	 * Tegra 2 has a bug where PCIE and VDE clamping masks are
-	 * swapped relatively to the partition ids
-	 */
-	if (id == TEGRA_POWERGATE_VDEC)
-		mask = (1 << TEGRA_POWERGATE_PCIE);
-	else if (id == TEGRA_POWERGATE_PCIE)
-		mask = (1 << TEGRA_POWERGATE_VDEC);
-	else
-		mask = (1 << id);
-
-	pmc_write(mask, REMOVE_CLAMPING);
-
-	return 0;
-}
-EXPORT_SYMBOL(tegra_powergate_remove_clamping);
-
-/* Must be called with clk disabled, and returns with clk enabled */
-int tegra_powergate_sequence_power_up(int id, struct clk *clk,
-					struct reset_control *rst)
-{
-	int ret;
-
-	reset_control_assert(rst);
-
-	ret = tegra_powergate_power_on(id);
-	if (ret)
-		goto err_power;
-
-	ret = clk_prepare_enable(clk);
-	if (ret)
-		goto err_clk;
-
-	udelay(10);
-
-	ret = tegra_powergate_remove_clamping(id);
-	if (ret)
-		goto err_clamp;
-
-	udelay(10);
-	reset_control_deassert(rst);
-
-	return 0;
-
-err_clamp:
-	clk_disable_unprepare(clk);
-err_clk:
-	tegra_powergate_power_off(id);
-err_power:
-	return ret;
-}
-EXPORT_SYMBOL(tegra_powergate_sequence_power_up);
-
-int tegra_cpu_powergate_id(int cpuid)
-{
-	if (cpuid > 0 && cpuid < tegra_num_cpu_domains)
-		return tegra_cpu_domains[cpuid];
-
-	return -EINVAL;
-}
-
-int __init tegra_powergate_init(void)
-{
-	switch (tegra_get_chip_id()) {
-	case TEGRA20:
-		tegra_num_powerdomains = 7;
-		break;
-	case TEGRA30:
-		tegra_num_powerdomains = 14;
-		tegra_num_cpu_domains = 4;
-		tegra_cpu_domains = tegra30_cpu_domains;
-		break;
-	case TEGRA114:
-		tegra_num_powerdomains = 23;
-		tegra_num_cpu_domains = 4;
-		tegra_cpu_domains = tegra114_cpu_domains;
-		break;
-	case TEGRA124:
-		tegra_num_powerdomains = 25;
-		tegra_num_cpu_domains = 4;
-		tegra_cpu_domains = tegra124_cpu_domains;
-		break;
-	default:
-		/* Unknown Tegra variant. Disable powergating */
-		tegra_num_powerdomains = 0;
-		break;
-	}
-
-	return 0;
-}
-
-#ifdef CONFIG_DEBUG_FS
-
-static const char * const *powergate_name;
-
-static const char * const powergate_name_t20[] = {
-	[TEGRA_POWERGATE_CPU]	= "cpu",
-	[TEGRA_POWERGATE_3D]	= "3d",
-	[TEGRA_POWERGATE_VENC]	= "venc",
-	[TEGRA_POWERGATE_VDEC]	= "vdec",
-	[TEGRA_POWERGATE_PCIE]	= "pcie",
-	[TEGRA_POWERGATE_L2]	= "l2",
-	[TEGRA_POWERGATE_MPE]	= "mpe",
-};
-
-static const char * const powergate_name_t30[] = {
-	[TEGRA_POWERGATE_CPU]	= "cpu0",
-	[TEGRA_POWERGATE_3D]	= "3d0",
-	[TEGRA_POWERGATE_VENC]	= "venc",
-	[TEGRA_POWERGATE_VDEC]	= "vdec",
-	[TEGRA_POWERGATE_PCIE]	= "pcie",
-	[TEGRA_POWERGATE_L2]	= "l2",
-	[TEGRA_POWERGATE_MPE]	= "mpe",
-	[TEGRA_POWERGATE_HEG]	= "heg",
-	[TEGRA_POWERGATE_SATA]	= "sata",
-	[TEGRA_POWERGATE_CPU1]	= "cpu1",
-	[TEGRA_POWERGATE_CPU2]	= "cpu2",
-	[TEGRA_POWERGATE_CPU3]	= "cpu3",
-	[TEGRA_POWERGATE_CELP]	= "celp",
-	[TEGRA_POWERGATE_3D1]	= "3d1",
-};
-
-static const char * const powergate_name_t114[] = {
-	[TEGRA_POWERGATE_CPU]	= "crail",
-	[TEGRA_POWERGATE_3D]	= "3d",
-	[TEGRA_POWERGATE_VENC]	= "venc",
-	[TEGRA_POWERGATE_VDEC]	= "vdec",
-	[TEGRA_POWERGATE_MPE]	= "mpe",
-	[TEGRA_POWERGATE_HEG]	= "heg",
-	[TEGRA_POWERGATE_CPU1]	= "cpu1",
-	[TEGRA_POWERGATE_CPU2]	= "cpu2",
-	[TEGRA_POWERGATE_CPU3]	= "cpu3",
-	[TEGRA_POWERGATE_CELP]	= "celp",
-	[TEGRA_POWERGATE_CPU0]	= "cpu0",
-	[TEGRA_POWERGATE_C0NC]	= "c0nc",
-	[TEGRA_POWERGATE_C1NC]	= "c1nc",
-	[TEGRA_POWERGATE_DIS]	= "dis",
-	[TEGRA_POWERGATE_DISB]	= "disb",
-	[TEGRA_POWERGATE_XUSBA]	= "xusba",
-	[TEGRA_POWERGATE_XUSBB]	= "xusbb",
-	[TEGRA_POWERGATE_XUSBC]	= "xusbc",
-};
-
-static const char * const powergate_name_t124[] = {
-	[TEGRA_POWERGATE_CPU]	= "crail",
-	[TEGRA_POWERGATE_3D]	= "3d",
-	[TEGRA_POWERGATE_VENC]	= "venc",
-	[TEGRA_POWERGATE_PCIE]	= "pcie",
-	[TEGRA_POWERGATE_VDEC]	= "vdec",
-	[TEGRA_POWERGATE_L2]	= "l2",
-	[TEGRA_POWERGATE_MPE]	= "mpe",
-	[TEGRA_POWERGATE_HEG]	= "heg",
-	[TEGRA_POWERGATE_SATA]	= "sata",
-	[TEGRA_POWERGATE_CPU1]	= "cpu1",
-	[TEGRA_POWERGATE_CPU2]	= "cpu2",
-	[TEGRA_POWERGATE_CPU3]	= "cpu3",
-	[TEGRA_POWERGATE_CELP]	= "celp",
-	[TEGRA_POWERGATE_CPU0]	= "cpu0",
-	[TEGRA_POWERGATE_C0NC]	= "c0nc",
-	[TEGRA_POWERGATE_C1NC]	= "c1nc",
-	[TEGRA_POWERGATE_SOR]	= "sor",
-	[TEGRA_POWERGATE_DIS]	= "dis",
-	[TEGRA_POWERGATE_DISB]	= "disb",
-	[TEGRA_POWERGATE_XUSBA]	= "xusba",
-	[TEGRA_POWERGATE_XUSBB]	= "xusbb",
-	[TEGRA_POWERGATE_XUSBC]	= "xusbc",
-	[TEGRA_POWERGATE_VIC]	= "vic",
-	[TEGRA_POWERGATE_IRAM]	= "iram",
-};
-
-static int powergate_show(struct seq_file *s, void *data)
-{
-	int i;
-
-	seq_printf(s, " powergate powered\n");
-	seq_printf(s, "------------------\n");
-
-	for (i = 0; i < tegra_num_powerdomains; i++) {
-		if (!powergate_name[i])
-			continue;
-
-		seq_printf(s, " %9s %7s\n", powergate_name[i],
-			tegra_powergate_is_powered(i) ? "yes" : "no");
-	}
-
-	return 0;
-}
-
-static int powergate_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, powergate_show, inode->i_private);
-}
-
-static const struct file_operations powergate_fops = {
-	.open		= powergate_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-};
-
-int __init tegra_powergate_debugfs_init(void)
-{
-	struct dentry *d;
-
-	switch (tegra_get_chip_id()) {
-	case TEGRA20:
-		powergate_name = powergate_name_t20;
-		break;
-	case TEGRA30:
-		powergate_name = powergate_name_t30;
-		break;
-	case TEGRA114:
-		powergate_name = powergate_name_t114;
-		break;
-	case TEGRA124:
-		powergate_name = powergate_name_t124;
-		break;
-	}
-
-	if (powergate_name) {
-		d = debugfs_create_file("powergate", S_IRUGO, NULL, NULL,
-			&powergate_fops);
-		if (!d)
-			return -ENOMEM;
-	}
-
-	return 0;
-}
-
-#endif
-
-static int tegra_io_rail_prepare(int id, unsigned long *request,
-				 unsigned long *status, unsigned int *bit)
-{
-	unsigned long rate, value;
-	struct clk *clk;
-
-	*bit = id % 32;
-
-	/*
-	 * There are two sets of 30 bits to select IO rails, but bits 30 and
-	 * 31 are control bits rather than IO rail selection bits.
-	 */
-	if (id > 63 || *bit == 30 || *bit == 31)
-		return -EINVAL;
-
-	if (id < 32) {
-		*status = IO_DPD_STATUS;
-		*request = IO_DPD_REQ;
-	} else {
-		*status = IO_DPD2_STATUS;
-		*request = IO_DPD2_REQ;
-	}
-
-	clk = clk_get_sys(NULL, "pclk");
-	if (IS_ERR(clk))
-		return PTR_ERR(clk);
-
-	rate = clk_get_rate(clk);
-	clk_put(clk);
-
-	pmc_write(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);
-
-	return 0;
-}
-
-static int tegra_io_rail_poll(unsigned long offset, unsigned long mask,
-			      unsigned long val, unsigned long timeout)
-{
-	unsigned long value;
-
-	timeout = jiffies + msecs_to_jiffies(timeout);
-
-	while (time_after(timeout, jiffies)) {
-		value = pmc_read(offset);
-		if ((value & mask) == val)
-			return 0;
-
-		usleep_range(250, 1000);
-	}
-
-	return -ETIMEDOUT;
-}
-
-static void tegra_io_rail_unprepare(void)
-{
-	pmc_write(DPD_SAMPLE_DISABLE, DPD_SAMPLE);
-}
-
-int tegra_io_rail_power_on(int id)
-{
-	unsigned long request, status, value;
-	unsigned int bit, mask;
-	int err;
-
-	err = tegra_io_rail_prepare(id, &request, &status, &bit);
-	if (err < 0)
-		return err;
-
-	mask = 1 << bit;
-
-	value = pmc_read(request);
-	value |= mask;
-	value &= ~IO_DPD_REQ_CODE_MASK;
-	value |= IO_DPD_REQ_CODE_OFF;
-	pmc_write(value, request);
-
-	err = tegra_io_rail_poll(status, mask, 0, 250);
-	if (err < 0)
-		return err;
-
-	tegra_io_rail_unprepare();
-
-	return 0;
-}
-EXPORT_SYMBOL(tegra_io_rail_power_on);
-
-int tegra_io_rail_power_off(int id)
-{
-	unsigned long request, status, value;
-	unsigned int bit, mask;
-	int err;
-
-	err = tegra_io_rail_prepare(id, &request, &status, &bit);
-	if (err < 0)
-		return err;
-
-	mask = 1 << bit;
-
-	value = pmc_read(request);
-	value |= mask;
-	value &= ~IO_DPD_REQ_CODE_MASK;
-	value |= IO_DPD_REQ_CODE_ON;
-	pmc_write(value, request);
-
-	err = tegra_io_rail_poll(status, mask, mask, 250);
-	if (err < 0)
-		return err;
-
-	tegra_io_rail_unprepare();
-
-	return 0;
-}
-EXPORT_SYMBOL(tegra_io_rail_power_off);
diff --git a/arch/arm/mach-tegra/tegra-pmc.c b/arch/arm/mach-tegra/tegra-pmc.c
new file mode 100644
index 000000000000..b6bc758a9262
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra-pmc.c
@@ -0,0 +1,948 @@
+/*
+ * drivers/soc/tegra/pmc.c
+ *
+ * Copyright (c) 2010 Google, Inc
+ *
+ * Author:
+ *	Colin Cross <ccross@google.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/clk.h>
+#include <linux/clk/tegra.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/export.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/reboot.h>
+#include <linux/reset.h>
+#include <linux/seq_file.h>
+#include <linux/spinlock.h>
+#include <linux/tegra-powergate.h>
+#include <linux/tegra-soc.h>
+
+#define PMC_CNTRL			0x0
+#define  PMC_CNTRL_SYSCLK_POLARITY	(1 << 10)  /* sys clk polarity */
+#define  PMC_CNTRL_SYSCLK_OE		(1 << 11)  /* system clock enable */
+#define  PMC_CNTRL_SIDE_EFFECT_LP0	(1 << 14)  /* LP0 when CPU pwr gated */
+#define  PMC_CNTRL_CPU_PWRREQ_POLARITY	(1 << 15)  /* CPU pwr req polarity */
+#define  PMC_CNTRL_CPU_PWRREQ_OE	(1 << 16)  /* CPU pwr req enable */
+#define  PMC_CNTRL_INTR_POLARITY	(1 << 17)  /* inverts INTR polarity */
+
+#define DPD_SAMPLE			0x020
+#define  DPD_SAMPLE_ENABLE		(1 << 0)
+#define  DPD_SAMPLE_DISABLE		(0 << 0)
+
+#define PWRGATE_TOGGLE			0x30
+#define  PWRGATE_TOGGLE_START		(1 << 8)
+
+#define REMOVE_CLAMPING			0x34
+
+#define PWRGATE_STATUS			0x38
+
+#define PMC_SCRATCH0			0x50
+#define  PMC_SCRATCH0_MODE_RECOVERY	(1 << 31)
+#define  PMC_SCRATCH0_MODE_BOOTLOADER	(1 << 30)
+#define  PMC_SCRATCH0_MODE_RCM		(1 << 1)
+#define  PMC_SCRATCH0_MODE_MASK		(PMC_SCRATCH0_MODE_RECOVERY | \
+					 PMC_SCRATCH0_MODE_BOOTLOADER | \
+					 PMC_SCRATCH0_MODE_RCM)
+
+#define PMC_CPUPWRGOOD_TIMER		0xc8
+#define PMC_CPUPWROFF_TIMER		0xcc
+
+#define PMC_SCRATCH41			0x140
+
+#define IO_DPD_REQ			0x1b8
+#define  IO_DPD_REQ_CODE_IDLE		(0 << 30)
+#define  IO_DPD_REQ_CODE_OFF		(1 << 30)
+#define  IO_DPD_REQ_CODE_ON		(2 << 30)
+#define  IO_DPD_REQ_CODE_MASK		(3 << 30)
+
+#define IO_DPD_STATUS			0x1bc
+#define IO_DPD2_REQ			0x1c0
+#define IO_DPD2_STATUS			0x1c4
+#define SEL_DPD_TIM			0x1c8
+
+#define GPU_RG_CNTRL			0x2d4
+
+struct tegra_pmc_soc {
+	unsigned int num_powergates;
+	const char *const *powergates;
+	unsigned int num_cpu_powergates;
+	const u8 *cpu_powergates;
+};
+
+/**
+ * struct tegra_pmc - NVIDIA Tegra PMC
+ * @base: pointer to I/O remapped register region
+ * @clk: pointer to pclk clock
+ * @rate: currently configured rate of pclk
+ * @suspend_mode: lowest suspend mode available
+ * @cpu_good_time: CPU power good time (in microseconds)
+ * @cpu_off_time: CPU power off time (in microsecends)
+ * @core_osc_time: core power good OSC time (in microseconds)
+ * @core_pmu_time: core power good PMU time (in microseconds)
+ * @core_off_time: core power off time (in microseconds)
+ * @corereq_high: core power request is active-high
+ * @sysclkreq_high: system clock request is active-high
+ * @combined_req: combined power request for CPU & core
+ * @cpu_pwr_good_en: CPU power good signal is enabled
+ * @lp0_vec_phys: physical base address of the LP0 warm boot code
+ * @lp0_vec_size: size of the LP0 warm boot code
+ * @powergates_lock: mutex for power gate register access
+ */
+struct tegra_pmc {
+	void __iomem *base;
+	struct clk *clk;
+
+	const struct tegra_pmc_soc *soc;
+
+	unsigned long rate;
+
+	enum tegra_suspend_mode suspend_mode;
+	u32 cpu_good_time;
+	u32 cpu_off_time;
+	u32 core_osc_time;
+	u32 core_pmu_time;
+	u32 core_off_time;
+	bool corereq_high;
+	bool sysclkreq_high;
+	bool combined_req;
+	bool cpu_pwr_good_en;
+	u32 lp0_vec_phys;
+	u32 lp0_vec_size;
+
+	struct mutex powergates_lock;
+};
+
+static struct tegra_pmc *pmc = &(struct tegra_pmc) {
+	.base = NULL,
+	.suspend_mode = TEGRA_SUSPEND_NONE,
+};
+
+static u32 tegra_pmc_readl(unsigned long offset)
+{
+	return readl(pmc->base + offset);
+}
+
+static void tegra_pmc_writel(u32 value, unsigned long offset)
+{
+	writel(value, pmc->base + offset);
+}
+
+/**
+ * tegra_powergate_set() - set the state of a partition
+ * @id: partition ID
+ * @new_state: new state of the partition
+ */
+static int tegra_powergate_set(int id, bool new_state)
+{
+	bool status;
+
+	mutex_lock(&pmc->powergates_lock);
+
+	status = tegra_pmc_readl(PWRGATE_STATUS) & (1 << id);
+
+	if (status == new_state) {
+		mutex_unlock(&pmc->powergates_lock);
+		return 0;
+	}
+
+	tegra_pmc_writel(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE);
+
+	mutex_unlock(&pmc->powergates_lock);
+
+	return 0;
+}
+
+/**
+ * tegra_powergate_power_on() - power on partition
+ * @id: partition ID
+ */
+int tegra_powergate_power_on(int id)
+{
+	if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
+		return -EINVAL;
+
+	return tegra_powergate_set(id, true);
+}
+
+/**
+ * tegra_powergate_power_off() - power off partition
+ * @id: partition ID
+ */
+int tegra_powergate_power_off(int id)
+{
+	if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
+		return -EINVAL;
+
+	return tegra_powergate_set(id, false);
+}
+EXPORT_SYMBOL(tegra_powergate_power_off);
+
+/**
+ * tegra_powergate_is_powered() - check if partition is powered
+ * @id: partition ID
+ */
+int tegra_powergate_is_powered(int id)
+{
+	u32 status;
+
+	if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
+		return -EINVAL;
+
+	status = tegra_pmc_readl(PWRGATE_STATUS) & (1 << id);
+	return !!status;
+}
+
+/**
+ * tegra_powergate_remove_clamping() - remove power clamps for partition
+ * @id: partition ID
+ */
+int tegra_powergate_remove_clamping(int id)
+{
+	u32 mask;
+
+	if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
+		return -EINVAL;
+
+	/*
+	 * The Tegra124 GPU has a separate register (with different semantics)
+	 * to remove clamps.
+	 */
+	if (tegra_get_chip_id() == TEGRA124) {
+		if (id == TEGRA_POWERGATE_3D) {
+			tegra_pmc_writel(0, GPU_RG_CNTRL);
+			return 0;
+		}
+	}
+
+	/*
+	 * Tegra 2 has a bug where PCIE and VDE clamping masks are
+	 * swapped relatively to the partition ids
+	 */
+	if (id == TEGRA_POWERGATE_VDEC)
+		mask = (1 << TEGRA_POWERGATE_PCIE);
+	else if (id == TEGRA_POWERGATE_PCIE)
+		mask = (1 << TEGRA_POWERGATE_VDEC);
+	else
+		mask = (1 << id);
+
+	tegra_pmc_writel(mask, REMOVE_CLAMPING);
+
+	return 0;
+}
+EXPORT_SYMBOL(tegra_powergate_remove_clamping);
+
+/**
+ * tegra_powergate_sequence_power_up() - power up partition
+ * @id: partition ID
+ * @clk: clock for partition
+ * @rst: reset for partition
+ *
+ * Must be called with clk disabled, and returns with clk enabled.
+ */
+int tegra_powergate_sequence_power_up(int id, struct clk *clk,
+				      struct reset_control *rst)
+{
+	int ret;
+
+	reset_control_assert(rst);
+
+	ret = tegra_powergate_power_on(id);
+	if (ret)
+		goto err_power;
+
+	ret = clk_prepare_enable(clk);
+	if (ret)
+		goto err_clk;
+
+	usleep_range(10, 20);
+
+	ret = tegra_powergate_remove_clamping(id);
+	if (ret)
+		goto err_clamp;
+
+	usleep_range(10, 20);
+	reset_control_deassert(rst);
+
+	return 0;
+
+err_clamp:
+	clk_disable_unprepare(clk);
+err_clk:
+	tegra_powergate_power_off(id);
+err_power:
+	return ret;
+}
+EXPORT_SYMBOL(tegra_powergate_sequence_power_up);
+
+/**
+ * tegra_get_cpu_powergate_id() - convert from CPU ID to partition ID
+ * @cpuid: CPU partition ID
+ *
+ * Returns the partition ID corresponding to the CPU partition ID or a
+ * negative error code on failure.
+ */
+static int tegra_get_cpu_powergate_id(int cpuid)
+{
+	if (pmc->soc && cpuid > 0 && cpuid < pmc->soc->num_cpu_powergates)
+		return pmc->soc->cpu_powergates[cpuid];
+
+	return -EINVAL;
+}
+
+/**
+ * tegra_pmc_cpu_is_powered() - check if CPU partition is powered
+ * @cpuid: CPU partition ID
+ */
+bool tegra_pmc_cpu_is_powered(int cpuid)
+{
+	int id;
+
+	id = tegra_get_cpu_powergate_id(cpuid);
+	if (id < 0)
+		return false;
+
+	return tegra_powergate_is_powered(id);
+}
+
+/**
+ * tegra_pmc_cpu_power_on() - power on CPU partition
+ * @cpuid: CPU partition ID
+ */
+int tegra_pmc_cpu_power_on(int cpuid)
+{
+	int id;
+
+	id = tegra_get_cpu_powergate_id(cpuid);
+	if (id < 0)
+		return id;
+
+	return tegra_powergate_set(id, true);
+}
+
+/**
+ * tegra_pmc_cpu_remove_clamping() - remove power clamps for CPU partition
+ * @cpuid: CPU partition ID
+ */
+int tegra_pmc_cpu_remove_clamping(int cpuid)
+{
+	int id;
+
+	id = tegra_get_cpu_powergate_id(cpuid);
+	if (id < 0)
+		return id;
+
+	return tegra_powergate_remove_clamping(id);
+}
+
+/**
+ * tegra_pmc_restart() - reboot the system
+ * @mode: which mode to reboot in
+ * @cmd: reboot command
+ */
+void tegra_pmc_restart(enum reboot_mode mode, const char *cmd)
+{
+	u32 value;
+
+	value = tegra_pmc_readl(PMC_SCRATCH0);
+	value &= ~PMC_SCRATCH0_MODE_MASK;
+
+	if (cmd) {
+		if (strcmp(cmd, "recovery") == 0)
+			value |= PMC_SCRATCH0_MODE_RECOVERY;
+
+		if (strcmp(cmd, "bootloader") == 0)
+			value |= PMC_SCRATCH0_MODE_BOOTLOADER;
+
+		if (strcmp(cmd, "forced-recovery") == 0)
+			value |= PMC_SCRATCH0_MODE_RCM;
+	}
+
+	tegra_pmc_writel(value, PMC_SCRATCH0);
+
+	value = tegra_pmc_readl(0);
+	value |= 0x10;
+	tegra_pmc_writel(value, 0);
+}
+
+static int powergate_show(struct seq_file *s, void *data)
+{
+	unsigned int i;
+
+	seq_printf(s, " powergate powered\n");
+	seq_printf(s, "------------------\n");
+
+	for (i = 0; i < pmc->soc->num_powergates; i++) {
+		if (!pmc->soc->powergates[i])
+			continue;
+
+		seq_printf(s, " %9s %7s\n", pmc->soc->powergates[i],
+			   tegra_powergate_is_powered(i) ? "yes" : "no");
+	}
+
+	return 0;
+}
+
+static int powergate_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, powergate_show, inode->i_private);
+}
+
+static const struct file_operations powergate_fops = {
+	.open = powergate_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static int tegra_powergate_debugfs_init(void)
+{
+	struct dentry *d;
+
+	d = debugfs_create_file("powergate", S_IRUGO, NULL, NULL,
+				&powergate_fops);
+	if (!d)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static int tegra_io_rail_prepare(int id, unsigned long *request,
+				 unsigned long *status, unsigned int *bit)
+{
+	unsigned long rate, value;
+	struct clk *clk;
+
+	*bit = id % 32;
+
+	/*
+	 * There are two sets of 30 bits to select IO rails, but bits 30 and
+	 * 31 are control bits rather than IO rail selection bits.
+	 */
+	if (id > 63 || *bit == 30 || *bit == 31)
+		return -EINVAL;
+
+	if (id < 32) {
+		*status = IO_DPD_STATUS;
+		*request = IO_DPD_REQ;
+	} else {
+		*status = IO_DPD2_STATUS;
+		*request = IO_DPD2_REQ;
+	}
+
+	clk = clk_get_sys(NULL, "pclk");
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
+
+	rate = clk_get_rate(clk);
+	clk_put(clk);
+
+	tegra_pmc_writel(DPD_SAMPLE_ENABLE, DPD_SAMPLE);
+
+	/* must be@least 200 ns, in APB (PCLK) clock cycles */
+	value = DIV_ROUND_UP(1000000000, rate);
+	value = DIV_ROUND_UP(200, value);
+	tegra_pmc_writel(value, SEL_DPD_TIM);
+
+	return 0;
+}
+
+static int tegra_io_rail_poll(unsigned long offset, unsigned long mask,
+			      unsigned long val, unsigned long timeout)
+{
+	unsigned long value;
+
+	timeout = jiffies + msecs_to_jiffies(timeout);
+
+	while (time_after(timeout, jiffies)) {
+		value = tegra_pmc_readl(offset);
+		if ((value & mask) == val)
+			return 0;
+
+		usleep_range(250, 1000);
+	}
+
+	return -ETIMEDOUT;
+}
+
+static void tegra_io_rail_unprepare(void)
+{
+	tegra_pmc_writel(DPD_SAMPLE_DISABLE, DPD_SAMPLE);
+}
+
+int tegra_io_rail_power_on(int id)
+{
+	unsigned long request, status, value;
+	unsigned int bit, mask;
+	int err;
+
+	err = tegra_io_rail_prepare(id, &request, &status, &bit);
+	if (err < 0)
+		return err;
+
+	mask = 1 << bit;
+
+	value = tegra_pmc_readl(request);
+	value |= mask;
+	value &= ~IO_DPD_REQ_CODE_MASK;
+	value |= IO_DPD_REQ_CODE_OFF;
+	tegra_pmc_writel(value, request);
+
+	err = tegra_io_rail_poll(status, mask, 0, 250);
+	if (err < 0)
+		return err;
+
+	tegra_io_rail_unprepare();
+
+	return 0;
+}
+EXPORT_SYMBOL(tegra_io_rail_power_on);
+
+int tegra_io_rail_power_off(int id)
+{
+	unsigned long request, status, value;
+	unsigned int bit, mask;
+	int err;
+
+	err = tegra_io_rail_prepare(id, &request, &status, &bit);
+	if (err < 0)
+		return err;
+
+	mask = 1 << bit;
+
+	value = tegra_pmc_readl(request);
+	value |= mask;
+	value &= ~IO_DPD_REQ_CODE_MASK;
+	value |= IO_DPD_REQ_CODE_ON;
+	tegra_pmc_writel(value, request);
+
+	err = tegra_io_rail_poll(status, mask, mask, 250);
+	if (err < 0)
+		return err;
+
+	tegra_io_rail_unprepare();
+
+	return 0;
+}
+EXPORT_SYMBOL(tegra_io_rail_power_off);
+
+enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void)
+{
+	return pmc->suspend_mode;
+}
+
+void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode)
+{
+	if (mode < TEGRA_SUSPEND_NONE || mode >= TEGRA_MAX_SUSPEND_MODE)
+		return;
+
+	pmc->suspend_mode = mode;
+}
+
+void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode)
+{
+	unsigned long long rate = 0;
+	u32 value;
+
+	switch (mode) {
+	case TEGRA_SUSPEND_LP1:
+		rate = 32768;
+		break;
+
+	case TEGRA_SUSPEND_LP2:
+		rate = clk_get_rate(pmc->clk);
+		break;
+
+	default:
+		break;
+	}
+
+	if (WARN_ON_ONCE(rate == 0))
+		rate = 100000000;
+
+	if (rate != pmc->rate) {
+		u64 ticks;
+
+		ticks = pmc->cpu_good_time * rate + USEC_PER_SEC - 1;
+		do_div(ticks, USEC_PER_SEC);
+		tegra_pmc_writel(ticks, PMC_CPUPWRGOOD_TIMER);
+
+		ticks = pmc->cpu_off_time * rate + USEC_PER_SEC - 1;
+		do_div(ticks, USEC_PER_SEC);
+		tegra_pmc_writel(ticks, PMC_CPUPWROFF_TIMER);
+
+		wmb();
+
+		pmc->rate = rate;
+	}
+
+	value = tegra_pmc_readl(PMC_CNTRL);
+	value &= ~PMC_CNTRL_SIDE_EFFECT_LP0;
+	value |= PMC_CNTRL_CPU_PWRREQ_OE;
+	tegra_pmc_writel(value, PMC_CNTRL);
+}
+
+static int tegra_pmc_parse_dt(struct tegra_pmc *pmc, struct device_node *np)
+{
+	u32 value, values[2];
+
+	if (of_property_read_u32(np, "nvidia,suspend-mode", &value)) {
+	} else {
+		switch (value) {
+		case 0:
+			pmc->suspend_mode = TEGRA_SUSPEND_LP0;
+			break;
+
+		case 1:
+			pmc->suspend_mode = TEGRA_SUSPEND_LP1;
+			break;
+
+		case 2:
+			pmc->suspend_mode = TEGRA_SUSPEND_LP2;
+			break;
+
+		default:
+			pmc->suspend_mode = TEGRA_SUSPEND_NONE;
+			break;
+		}
+	}
+
+	pmc->suspend_mode = tegra_pm_validate_suspend_mode(pmc->suspend_mode);
+
+	if (of_property_read_u32(np, "nvidia,cpu-pwr-good-time", &value))
+		pmc->suspend_mode = TEGRA_SUSPEND_NONE;
+
+	pmc->cpu_good_time = value;
+
+	if (of_property_read_u32(np, "nvidia,cpu-pwr-off-time", &value))
+		pmc->suspend_mode = TEGRA_SUSPEND_NONE;
+
+	pmc->cpu_off_time = value;
+
+	if (of_property_read_u32_array(np, "nvidia,core-pwr-good-time",
+				       values, ARRAY_SIZE(values)))
+		pmc->suspend_mode = TEGRA_SUSPEND_NONE;
+
+	pmc->core_osc_time = values[0];
+	pmc->core_pmu_time = values[1];
+
+	if (of_property_read_u32(np, "nvidia,core-pwr-off-time", &value))
+		pmc->suspend_mode = TEGRA_SUSPEND_NONE;
+
+	pmc->core_off_time = value;
+
+	pmc->corereq_high = of_property_read_bool(np,
+				"nvidia,core-power-req-active-high");
+
+	pmc->sysclkreq_high = of_property_read_bool(np,
+				"nvidia,sys-clock-req-active-high");
+
+	pmc->combined_req = of_property_read_bool(np,
+				"nvidia,combined-power-req");
+
+	pmc->cpu_pwr_good_en = of_property_read_bool(np,
+				"nvidia,cpu-pwr-good-en");
+
+	if (of_property_read_u32_array(np, "nvidia,lp0-vec", values,
+				       ARRAY_SIZE(values)))
+		if (pmc->suspend_mode == TEGRA_SUSPEND_LP0)
+			pmc->suspend_mode = TEGRA_SUSPEND_LP1;
+
+	pmc->lp0_vec_phys = values[0];
+	pmc->lp0_vec_size = values[1];
+
+	return 0;
+}
+
+static void tegra_pmc_init(struct tegra_pmc *pmc)
+{
+	u32 value;
+
+	/* Always enable CPU power request */
+	value = tegra_pmc_readl(PMC_CNTRL);
+	value |= PMC_CNTRL_CPU_PWRREQ_OE;
+	tegra_pmc_writel(value, PMC_CNTRL);
+
+	value = tegra_pmc_readl(PMC_CNTRL);
+
+	if (pmc->sysclkreq_high)
+		value &= ~PMC_CNTRL_SYSCLK_POLARITY;
+	else
+		value |= PMC_CNTRL_SYSCLK_POLARITY;
+
+	/* configure the output polarity while the request is tristated */
+	tegra_pmc_writel(value, PMC_CNTRL);
+
+	/* now enable the request */
+	value = tegra_pmc_readl(PMC_CNTRL);
+	value |= PMC_CNTRL_SYSCLK_OE;
+	tegra_pmc_writel(value, PMC_CNTRL);
+}
+
+static int tegra_pmc_probe(struct platform_device *pdev)
+{
+	void __iomem *base = pmc->base;
+	struct resource *res;
+	int err;
+
+	err = tegra_pmc_parse_dt(pmc, pdev->dev.of_node);
+	if (err < 0)
+		return err;
+
+	/* take over the memory region from the early initialization */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	pmc->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(pmc->base))
+		return PTR_ERR(pmc->base);
+
+	iounmap(base);
+
+	pmc->clk = devm_clk_get(&pdev->dev, "pclk");
+	if (IS_ERR(pmc->clk)) {
+		err = PTR_ERR(pmc->clk);
+		dev_err(&pdev->dev, "failed to get pclk: %d\n", err);
+		return err;
+	}
+
+	tegra_pmc_init(pmc);
+
+	if (IS_ENABLED(CONFIG_DEBUG_FS)) {
+		err = tegra_powergate_debugfs_init();
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int tegra_pmc_suspend(struct device *dev)
+{
+	tegra_pmc_writel(virt_to_phys(tegra_resume), PMC_SCRATCH41);
+
+	return 0;
+}
+
+static int tegra_pmc_resume(struct device *dev)
+{
+	tegra_pmc_writel(0x0, PMC_SCRATCH41);
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(tegra_pmc_pm_ops, tegra_pmc_suspend, tegra_pmc_resume);
+
+static const char * const tegra20_powergates[] = {
+	[TEGRA_POWERGATE_CPU] = "cpu",
+	[TEGRA_POWERGATE_3D] = "3d",
+	[TEGRA_POWERGATE_VENC] = "venc",
+	[TEGRA_POWERGATE_VDEC] = "vdec",
+	[TEGRA_POWERGATE_PCIE] = "pcie",
+	[TEGRA_POWERGATE_L2] = "l2",
+	[TEGRA_POWERGATE_MPE] = "mpe",
+};
+
+static const struct tegra_pmc_soc tegra20_pmc_soc = {
+	.num_powergates = ARRAY_SIZE(tegra20_powergates),
+	.powergates = tegra20_powergates,
+	.num_cpu_powergates = 0,
+	.cpu_powergates = NULL,
+};
+
+static const char * const tegra30_powergates[] = {
+	[TEGRA_POWERGATE_CPU] = "cpu0",
+	[TEGRA_POWERGATE_3D] = "3d0",
+	[TEGRA_POWERGATE_VENC] = "venc",
+	[TEGRA_POWERGATE_VDEC] = "vdec",
+	[TEGRA_POWERGATE_PCIE] = "pcie",
+	[TEGRA_POWERGATE_L2] = "l2",
+	[TEGRA_POWERGATE_MPE] = "mpe",
+	[TEGRA_POWERGATE_HEG] = "heg",
+	[TEGRA_POWERGATE_SATA] = "sata",
+	[TEGRA_POWERGATE_CPU1] = "cpu1",
+	[TEGRA_POWERGATE_CPU2] = "cpu2",
+	[TEGRA_POWERGATE_CPU3] = "cpu3",
+	[TEGRA_POWERGATE_CELP] = "celp",
+	[TEGRA_POWERGATE_3D1] = "3d1",
+};
+
+static const u8 tegra30_cpu_powergates[] = {
+	TEGRA_POWERGATE_CPU,
+	TEGRA_POWERGATE_CPU1,
+	TEGRA_POWERGATE_CPU2,
+	TEGRA_POWERGATE_CPU3,
+};
+
+static const struct tegra_pmc_soc tegra30_pmc_soc = {
+	.num_powergates = ARRAY_SIZE(tegra30_powergates),
+	.powergates = tegra30_powergates,
+	.num_cpu_powergates = ARRAY_SIZE(tegra30_cpu_powergates),
+	.cpu_powergates = tegra30_cpu_powergates,
+};
+
+static const char * const tegra114_powergates[] = {
+	[TEGRA_POWERGATE_CPU] = "crail",
+	[TEGRA_POWERGATE_3D] = "3d",
+	[TEGRA_POWERGATE_VENC] = "venc",
+	[TEGRA_POWERGATE_VDEC] = "vdec",
+	[TEGRA_POWERGATE_MPE] = "mpe",
+	[TEGRA_POWERGATE_HEG] = "heg",
+	[TEGRA_POWERGATE_CPU1] = "cpu1",
+	[TEGRA_POWERGATE_CPU2] = "cpu2",
+	[TEGRA_POWERGATE_CPU3] = "cpu3",
+	[TEGRA_POWERGATE_CELP] = "celp",
+	[TEGRA_POWERGATE_CPU0] = "cpu0",
+	[TEGRA_POWERGATE_C0NC] = "c0nc",
+	[TEGRA_POWERGATE_C1NC] = "c1nc",
+	[TEGRA_POWERGATE_DIS] = "dis",
+	[TEGRA_POWERGATE_DISB] = "disb",
+	[TEGRA_POWERGATE_XUSBA] = "xusba",
+	[TEGRA_POWERGATE_XUSBB] = "xusbb",
+	[TEGRA_POWERGATE_XUSBC] = "xusbc",
+};
+
+static const u8 tegra114_cpu_powergates[] = {
+	TEGRA_POWERGATE_CPU0,
+	TEGRA_POWERGATE_CPU1,
+	TEGRA_POWERGATE_CPU2,
+	TEGRA_POWERGATE_CPU3,
+};
+
+static const struct tegra_pmc_soc tegra114_pmc_soc = {
+	.num_powergates = ARRAY_SIZE(tegra114_powergates),
+	.powergates = tegra114_powergates,
+	.num_cpu_powergates = ARRAY_SIZE(tegra114_cpu_powergates),
+	.cpu_powergates = tegra114_cpu_powergates,
+};
+
+static const char * const tegra124_powergates[] = {
+	[TEGRA_POWERGATE_CPU] = "crail",
+	[TEGRA_POWERGATE_3D] = "3d",
+	[TEGRA_POWERGATE_VENC] = "venc",
+	[TEGRA_POWERGATE_PCIE] = "pcie",
+	[TEGRA_POWERGATE_VDEC] = "vdec",
+	[TEGRA_POWERGATE_L2] = "l2",
+	[TEGRA_POWERGATE_MPE] = "mpe",
+	[TEGRA_POWERGATE_HEG] = "heg",
+	[TEGRA_POWERGATE_SATA] = "sata",
+	[TEGRA_POWERGATE_CPU1] = "cpu1",
+	[TEGRA_POWERGATE_CPU2] = "cpu2",
+	[TEGRA_POWERGATE_CPU3] = "cpu3",
+	[TEGRA_POWERGATE_CELP] = "celp",
+	[TEGRA_POWERGATE_CPU0] = "cpu0",
+	[TEGRA_POWERGATE_C0NC] = "c0nc",
+	[TEGRA_POWERGATE_C1NC] = "c1nc",
+	[TEGRA_POWERGATE_SOR] = "sor",
+	[TEGRA_POWERGATE_DIS] = "dis",
+	[TEGRA_POWERGATE_DISB] = "disb",
+	[TEGRA_POWERGATE_XUSBA] = "xusba",
+	[TEGRA_POWERGATE_XUSBB] = "xusbb",
+	[TEGRA_POWERGATE_XUSBC] = "xusbc",
+	[TEGRA_POWERGATE_VIC] = "vic",
+	[TEGRA_POWERGATE_IRAM] = "iram",
+};
+
+static const u8 tegra124_cpu_powergates[] = {
+	TEGRA_POWERGATE_CPU0,
+	TEGRA_POWERGATE_CPU1,
+	TEGRA_POWERGATE_CPU2,
+	TEGRA_POWERGATE_CPU3,
+};
+
+static const struct tegra_pmc_soc tegra124_pmc_soc = {
+	.num_powergates = ARRAY_SIZE(tegra124_powergates),
+	.powergates = tegra124_powergates,
+	.num_cpu_powergates = ARRAY_SIZE(tegra124_cpu_powergates),
+	.cpu_powergates = tegra124_cpu_powergates,
+};
+
+static const struct of_device_id tegra_pmc_match[] = {
+	{ .compatible = "nvidia,tegra124-pmc", .data = &tegra124_pmc_soc },
+	{ .compatible = "nvidia,tegra114-pmc", .data = &tegra114_pmc_soc },
+	{ .compatible = "nvidia,tegra30-pmc", .data = &tegra30_pmc_soc },
+	{ .compatible = "nvidia,tegra20-pmc", .data = &tegra20_pmc_soc },
+	{ }
+};
+
+static struct platform_driver tegra_pmc_driver = {
+	.driver = {
+		.name = "tegra-pmc",
+		.suppress_bind_attrs = true,
+		.of_match_table = tegra_pmc_match,
+		.pm = &tegra_pmc_pm_ops,
+	},
+	.probe = tegra_pmc_probe,
+};
+module_platform_driver(tegra_pmc_driver);
+
+/*
+ * Early initialization to allow access to registers in the very early boot
+ * process.
+ */
+static int __init tegra_pmc_early_init(void)
+{
+	const struct of_device_id *match;
+	struct device_node *np;
+	struct resource regs;
+	bool invert;
+	u32 value;
+
+	np = of_find_matching_node_and_match(NULL, tegra_pmc_match, &match);
+	if (!np) {
+		pr_warn("PMC device node not found, disabling powergating\n");
+
+		regs.start = 0x7000e400;
+		regs.end = 0x7000e7ff;
+		regs.flags = IORESOURCE_MEM;
+
+		pr_warn("Using memory region %pR\n", &regs);
+	} else {
+		pmc->soc = match->data;
+	}
+
+	if (of_address_to_resource(np, 0, &regs) < 0) {
+		pr_err("failed to get PMC registers\n");
+		return -ENXIO;
+	}
+
+	pmc->base = ioremap_nocache(regs.start, resource_size(&regs));
+	if (!pmc->base) {
+		pr_err("failed to map PMC registers\n");
+		return -ENXIO;
+	}
+
+	mutex_init(&pmc->powergates_lock);
+
+	invert = of_property_read_bool(np, "nvidia,invert-interrupt");
+
+	value = tegra_pmc_readl(PMC_CNTRL);
+
+	if (invert)
+		value |= PMC_CNTRL_INTR_POLARITY;
+	else
+		value &= ~PMC_CNTRL_INTR_POLARITY;
+
+	tegra_pmc_writel(value, PMC_CNTRL);
+
+	return 0;
+}
+early_initcall(tegra_pmc_early_init);
diff --git a/arch/arm/mach-tegra/tegra.c b/arch/arm/mach-tegra/tegra.c
index f05c4a648370..4482ad8c3872 100644
--- a/arch/arm/mach-tegra/tegra.c
+++ b/arch/arm/mach-tegra/tegra.c
@@ -48,7 +48,6 @@
 #include "cpuidle.h"
 #include "iomap.h"
 #include "irq.h"
-#include "pmc.h"
 #include "pm.h"
 #include "reset.h"
 #include "sleep.h"
@@ -73,12 +72,10 @@ static void __init tegra_init_early(void)
 {
 	of_register_trusted_foundations();
 	tegra_cpu_reset_handler_init();
-	tegra_powergate_init();
 }
 
 static void __init tegra_dt_init_irq(void)
 {
-	tegra_pmc_init_irq();
 	tegra_init_irq();
 	irqchip_init();
 	tegra_legacy_irq_syscore_init();
@@ -90,8 +87,6 @@ static void __init tegra_dt_init(void)
 	struct soc_device *soc_dev;
 	struct device *parent = NULL;
 
-	tegra_pmc_init();
-
 	tegra_clocks_apply_init_table();
 
 	soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
@@ -141,7 +136,6 @@ static void __init tegra_dt_init_late(void)
 
 	tegra_init_suspend();
 	tegra_cpuidle_init();
-	tegra_powergate_debugfs_init();
 
 	for (i = 0; i < ARRAY_SIZE(board_init_funcs); i++) {
 		if (of_machine_is_compatible(board_init_funcs[i].machine)) {
diff --git a/include/linux/tegra-soc.h b/include/linux/tegra-soc.h
index f50416851fa9..70a612442cda 100644
--- a/include/linux/tegra-soc.h
+++ b/include/linux/tegra-soc.h
@@ -27,6 +27,8 @@
 
 #ifndef __ASSEMBLY__
 
+#include <linux/reboot.h>
+
 u32 tegra_read_chipid(void);
 u8 tegra_get_chip_id(void);
 
@@ -60,6 +62,50 @@ int tegra_fuse_readl(unsigned long offset, u32 *value);
 
 extern struct tegra_sku_info tegra_sku_info;
 
+/*
+ * PMC
+ */
+enum tegra_suspend_mode {
+	TEGRA_SUSPEND_NONE = 0,
+	TEGRA_SUSPEND_LP2, /* CPU voltage off */
+	TEGRA_SUSPEND_LP1, /* CPU voltage off, DRAM self-refresh */
+	TEGRA_SUSPEND_LP0, /* CPU + core voltage off, DRAM self-refresh */
+	TEGRA_MAX_SUSPEND_MODE,
+};
+
+#ifdef CONFIG_PM_SLEEP
+enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void);
+void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode);
+void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode);
+
+bool tegra_pmc_cpu_is_powered(int cpuid);
+int tegra_pmc_cpu_power_on(int cpuid);
+int tegra_pmc_cpu_remove_clamping(int cpuid);
+
+void tegra_pmc_restart(enum reboot_mode mode, const char *cmd);
+#endif
+
+/*
+ * PM
+ */
+#ifdef CONFIG_PM_SLEEP
+enum tegra_suspend_mode
+tegra_pm_validate_suspend_mode(enum tegra_suspend_mode mode);
+
+/* low-level resume entry point */
+void tegra_resume(void);
+#else
+static inline enum tegra_suspend_mode
+tegra_pm_validate_suspend_mode(enum tegra_suspend_mode mode)
+{
+	return TEGRA_SUSPEND_NONE;
+}
+
+static inline void tegra_resume(void)
+{
+}
+#endif /* CONFIG_PM_SLEEP */
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* __LINUX_TEGRA_SOC_H_ */
-- 
2.0.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 12/12] ARM: tegra: Convert PMC to a driver
  2014-07-11 12:16 ` [PATCH 12/12] ARM: tegra: Convert PMC to a driver Thierry Reding
@ 2014-07-11 13:58   ` Peter De Schrijver
  2014-07-14  8:06     ` Thierry Reding
  2014-07-16 11:56   ` Arnd Bergmann
  1 sibling, 1 reply; 38+ messages in thread
From: Peter De Schrijver @ 2014-07-11 13:58 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jul 11, 2014 at 02:16:11PM +0200, Thierry Reding wrote:
> From: Thierry Reding <treding@nvidia.com>
> 
> This commit converts the PMC support code to a platform driver. Because
> the boot process needs to cal into this driver very early, also set up a

Small typo: 'call' :)

Cheers,

Peter.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 00/12] Add NVIDIA Tegra FUSE driver
  2014-07-11 12:15 [PATCH 00/12] Add NVIDIA Tegra FUSE driver Thierry Reding
                   ` (11 preceding siblings ...)
  2014-07-11 12:16 ` [PATCH 12/12] ARM: tegra: Convert PMC to a driver Thierry Reding
@ 2014-07-13  6:38 ` Olof Johansson
  2014-07-14  6:57   ` Thierry Reding
  12 siblings, 1 reply; 38+ messages in thread
From: Olof Johansson @ 2014-07-13  6:38 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jul 11, 2014 at 02:15:59PM +0200, Thierry Reding wrote:
> From: Thierry Reding <treding@nvidia.com>
> 
> This series is an extension of Peter's original series to add a proper
> driver for the FUSE block on Tegra.
> 
> Patches 1 and 2 are preparatory work that cleans up include lists and
> introduces a function to query the Tegra chip ID rather than accessing
> a simple variable. This is used by subsequent patches to allow us to
> execute code when the variable is accessed to help in pin-pointing
> locations where it's accessed before the driver had a chance to
> initialize.
> 
> Patches 3 through 8 are Peter's series with a fixup patch by Stephen. I
> also moved the driver to drivers/soc/tegra/fuse as requested by Olof.
> 
> Patches 9 and 10 defer usages of the tegra_get_chip_id() function to a
> later stage (pure_initcall). This allows patch 11 to set up the early
> FUSE support code from an early initcall. This has the advantage of not
> requiring an explicit call from SoC setup code in arch/arm/mach-tegra
> and will allow the code to be shared on 64-bit variants of Tegra.
> 
> Patch 12 finally turns the PMC and powergate support code into a proper
> driver which also sets up a minimal environment from an early initcall.
> The driver isn't moved out of arch/arm/mach-tegra yet because people
> have suggested drivers/power as a good home, but that whole directory
> depends on the POWER_SUPPLY Kconfig symbol yet this driver doesn't have
> anything to do with that. Once that debate has been settled the driver
> can easily be moved out in a separate patch.
> 
> Some of the patches in this series introduce diagnostic WARN() messages
> if functions are called without setup having completed. I've booted the
> v3.16-rc1 kernel with these changes on top on Tegra20 (TrimSlice),
> Tegra30 (Beaver), Tegra114 (Dalmore) and Tegra124 (Jetson TK1) without
> encountering any of the diagnostic warnings and without noticing any
> breakage.
> 
> Olof, this series should address the concerns you expressed after
> reviewing Stephen's earlier pull request for Peter's FUSE driver series.
> It would be great if you could take another look to see if this is more
> according to your taste. I'll see if I can take this through linux-next
> for a little and if you have no objections will submit another pull
> request next week.

I haven't looked at all the patches in detail yet, but I do like
the approach in general. I've also applied and pushed them out for
build+test here, but they're queued behind a couple of other builds
so I won't have it until morning (you can poll for boot logs at
arm-soc.lixom.net/bootlogs/misc/v3.16-rc4-371-g2c9d948 if you want to
preempt me).

> Peter De Schrijver (5):
>   ARM: tegra: export apb dma readl/writel

I thought I saw a patch from Peter that moved the apbio read code to
the fuse driver since there are no other consumers. I think that's a
reasonable thing to do.


-Olof

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 00/12] Add NVIDIA Tegra FUSE driver
  2014-07-13  6:38 ` [PATCH 00/12] Add NVIDIA Tegra FUSE driver Olof Johansson
@ 2014-07-14  6:57   ` Thierry Reding
  0 siblings, 0 replies; 38+ messages in thread
From: Thierry Reding @ 2014-07-14  6:57 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, Jul 12, 2014 at 11:38:15PM -0700, Olof Johansson wrote:
> On Fri, Jul 11, 2014 at 02:15:59PM +0200, Thierry Reding wrote:
> > From: Thierry Reding <treding@nvidia.com>
> > 
> > This series is an extension of Peter's original series to add a proper
> > driver for the FUSE block on Tegra.
> > 
> > Patches 1 and 2 are preparatory work that cleans up include lists and
> > introduces a function to query the Tegra chip ID rather than accessing
> > a simple variable. This is used by subsequent patches to allow us to
> > execute code when the variable is accessed to help in pin-pointing
> > locations where it's accessed before the driver had a chance to
> > initialize.
> > 
> > Patches 3 through 8 are Peter's series with a fixup patch by Stephen. I
> > also moved the driver to drivers/soc/tegra/fuse as requested by Olof.
> > 
> > Patches 9 and 10 defer usages of the tegra_get_chip_id() function to a
> > later stage (pure_initcall). This allows patch 11 to set up the early
> > FUSE support code from an early initcall. This has the advantage of not
> > requiring an explicit call from SoC setup code in arch/arm/mach-tegra
> > and will allow the code to be shared on 64-bit variants of Tegra.
> > 
> > Patch 12 finally turns the PMC and powergate support code into a proper
> > driver which also sets up a minimal environment from an early initcall.
> > The driver isn't moved out of arch/arm/mach-tegra yet because people
> > have suggested drivers/power as a good home, but that whole directory
> > depends on the POWER_SUPPLY Kconfig symbol yet this driver doesn't have
> > anything to do with that. Once that debate has been settled the driver
> > can easily be moved out in a separate patch.
> > 
> > Some of the patches in this series introduce diagnostic WARN() messages
> > if functions are called without setup having completed. I've booted the
> > v3.16-rc1 kernel with these changes on top on Tegra20 (TrimSlice),
> > Tegra30 (Beaver), Tegra114 (Dalmore) and Tegra124 (Jetson TK1) without
> > encountering any of the diagnostic warnings and without noticing any
> > breakage.
> > 
> > Olof, this series should address the concerns you expressed after
> > reviewing Stephen's earlier pull request for Peter's FUSE driver series.
> > It would be great if you could take another look to see if this is more
> > according to your taste. I'll see if I can take this through linux-next
> > for a little and if you have no objections will submit another pull
> > request next week.
> 
> I haven't looked at all the patches in detail yet, but I do like
> the approach in general. I've also applied and pushed them out for
> build+test here, but they're queued behind a couple of other builds
> so I won't have it until morning (you can poll for boot logs at
> arm-soc.lixom.net/bootlogs/misc/v3.16-rc4-371-g2c9d948 if you want to
> preempt me).

Looks like Tegra boards are all fine. Thanks for testing these.

> > Peter De Schrijver (5):
> >   ARM: tegra: export apb dma readl/writel
> 
> I thought I saw a patch from Peter that moved the apbio read code to
> the fuse driver since there are no other consumers. I think that's a
> reasonable thing to do.

That's a later patch in this series:

	soc/tegra: fuse: move APB DMA into Tegra20 fuse driver

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140714/39e3fcd8/attachment-0001.sig>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 12/12] ARM: tegra: Convert PMC to a driver
  2014-07-11 13:58   ` Peter De Schrijver
@ 2014-07-14  8:06     ` Thierry Reding
  0 siblings, 0 replies; 38+ messages in thread
From: Thierry Reding @ 2014-07-14  8:06 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jul 11, 2014 at 04:58:00PM +0300, Peter De Schrijver wrote:
> On Fri, Jul 11, 2014 at 02:16:11PM +0200, Thierry Reding wrote:
> > From: Thierry Reding <treding@nvidia.com>
> > 
> > This commit converts the PMC support code to a platform driver. Because
> > the boot process needs to cal into this driver very early, also set up a
> 
> Small typo: 'call' :)

Fixed, thanks.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140714/3c8483b4/attachment.sig>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 12/12] ARM: tegra: Convert PMC to a driver
  2014-07-11 12:16 ` [PATCH 12/12] ARM: tegra: Convert PMC to a driver Thierry Reding
  2014-07-11 13:58   ` Peter De Schrijver
@ 2014-07-16 11:56   ` Arnd Bergmann
  2014-07-16 13:22     ` Thierry Reding
  1 sibling, 1 reply; 38+ messages in thread
From: Arnd Bergmann @ 2014-07-16 11:56 UTC (permalink / raw)
  To: linux-arm-kernel

On Friday 11 July 2014, Thierry Reding wrote:
> +/*
> + * PMC
> + */
> +enum tegra_suspend_mode {
> +       TEGRA_SUSPEND_NONE = 0,
> +       TEGRA_SUSPEND_LP2, /* CPU voltage off */
> +       TEGRA_SUSPEND_LP1, /* CPU voltage off, DRAM self-refresh */
> +       TEGRA_SUSPEND_LP0, /* CPU + core voltage off, DRAM self-refresh */
> +       TEGRA_MAX_SUSPEND_MODE,
> +};
> +
> +#ifdef CONFIG_PM_SLEEP
> +enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void);
> +void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode);
> +void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode);
> +
> +bool tegra_pmc_cpu_is_powered(int cpuid);
> +int tegra_pmc_cpu_power_on(int cpuid);
> +int tegra_pmc_cpu_remove_clamping(int cpuid);
> +
> +void tegra_pmc_restart(enum reboot_mode mode, const char *cmd);
> +#endif
> +
> +/*

This part is causing multiple build failures in the randconfig tests.
You can avoid them by removing the #ifdef.

On a more general note, why are you adding this stuff into a global
header file in the first place? All users are in the same directory
in which the functions are defined.

	Arnd

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 12/12] ARM: tegra: Convert PMC to a driver
  2014-07-16 11:56   ` Arnd Bergmann
@ 2014-07-16 13:22     ` Thierry Reding
  2014-07-16 14:12       ` Arnd Bergmann
  0 siblings, 1 reply; 38+ messages in thread
From: Thierry Reding @ 2014-07-16 13:22 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jul 16, 2014 at 01:56:44PM +0200, Arnd Bergmann wrote:
> On Friday 11 July 2014, Thierry Reding wrote:
> > +/*
> > + * PMC
> > + */
> > +enum tegra_suspend_mode {
> > +       TEGRA_SUSPEND_NONE = 0,
> > +       TEGRA_SUSPEND_LP2, /* CPU voltage off */
> > +       TEGRA_SUSPEND_LP1, /* CPU voltage off, DRAM self-refresh */
> > +       TEGRA_SUSPEND_LP0, /* CPU + core voltage off, DRAM self-refresh */
> > +       TEGRA_MAX_SUSPEND_MODE,
> > +};
> > +
> > +#ifdef CONFIG_PM_SLEEP
> > +enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void);
> > +void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode);
> > +void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode);
> > +
> > +bool tegra_pmc_cpu_is_powered(int cpuid);
> > +int tegra_pmc_cpu_power_on(int cpuid);
> > +int tegra_pmc_cpu_remove_clamping(int cpuid);
> > +
> > +void tegra_pmc_restart(enum reboot_mode mode, const char *cmd);
> > +#endif
> > +
> > +/*
> 
> This part is causing multiple build failures in the randconfig tests.
> You can avoid them by removing the #ifdef.

How is this causing build failures? I only see them used wherever
CONFIG_PM_SLEEP is defined.

Although I guess tegra-pmc.c could cause sparse warnings since it
implements these functions regardless of CONFIG_PM_SLEEP, which probably
is the bug that should be fixed.

Do you have a randconfig that I can use to reproduce this and come up
with a fix?

> On a more general note, why are you adding this stuff into a global
> header file in the first place? All users are in the same directory
> in which the functions are defined.

That's mostly preparatory work. We'll need to move tegra-pmc.c out of
arch/arm/mach-tegra at some point. I've proposed two patches already to
do that, one move the driver to drivers/soc/tegra and was massively
NAK'ed (I'm still not sure I agree) and people requested that this be
moved into drivers/power. I then posted a 2 patch series to move power
supply drivers into a subdirectory (drivers/power/supply) so that
drivers in drivers/power didn't have to depend on CONFIG_POWER_SUPPLY
for no good reason.

The latter series didn't receive any comments whatsoever in over a week,
so in order to keep things moving forward I respun the PMC patch to do
the conversion without moving the code out of arch/arm/mach-tegra yet.
That way moving the driver out of arch/arm/mach-tegra will be a simple
matter of moving and the rework will already be done. You were Cc'ed on
the second series, so if you want to take a look (and maybe help get
things moving) the patches are called:

	[PATCH 0/2] Restructure driver/power and add Tegra PMC driver
	[PATCH 1/2] power: Move power-supply drivers to subdirectory
	[PATCH 2/2] ARM: tegra: Convert PMC to a driver

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140716/3836f4bb/attachment.sig>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 12/12] ARM: tegra: Convert PMC to a driver
  2014-07-16 13:22     ` Thierry Reding
@ 2014-07-16 14:12       ` Arnd Bergmann
  2014-07-16 15:14         ` Thierry Reding
  0 siblings, 1 reply; 38+ messages in thread
From: Arnd Bergmann @ 2014-07-16 14:12 UTC (permalink / raw)
  To: linux-arm-kernel

On Wednesday 16 July 2014 15:22:41 Thierry Reding wrote:
> On Wed, Jul 16, 2014 at 01:56:44PM +0200, Arnd Bergmann wrote:
> > On Friday 11 July 2014, Thierry Reding wrote:
> > > +/*
> > > + * PMC
> > > + */
> > > +enum tegra_suspend_mode {
> > > +       TEGRA_SUSPEND_NONE = 0,
> > > +       TEGRA_SUSPEND_LP2, /* CPU voltage off */
> > > +       TEGRA_SUSPEND_LP1, /* CPU voltage off, DRAM self-refresh */
> > > +       TEGRA_SUSPEND_LP0, /* CPU + core voltage off, DRAM self-refresh */
> > > +       TEGRA_MAX_SUSPEND_MODE,
> > > +};
> > > +
> > > +#ifdef CONFIG_PM_SLEEP
> > > +enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void);
> > > +void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode);
> > > +void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode);
> > > +
> > > +bool tegra_pmc_cpu_is_powered(int cpuid);
> > > +int tegra_pmc_cpu_power_on(int cpuid);
> > > +int tegra_pmc_cpu_remove_clamping(int cpuid);
> > > +
> > > +void tegra_pmc_restart(enum reboot_mode mode, const char *cmd);
> > > +#endif
> > > +
> > > +/*
> > 
> > This part is causing multiple build failures in the randconfig tests.
> > You can avoid them by removing the #ifdef.
> 
> How is this causing build failures? I only see them used wherever
> CONFIG_PM_SLEEP is defined.
> 
> Although I guess tegra-pmc.c could cause sparse warnings since it
> implements these functions regardless of CONFIG_PM_SLEEP, which probably
> is the bug that should be fixed.
> 
> Do you have a randconfig that I can use to reproduce this and come up
> with a fix?

I got this error (always):

/git/arm-soc/arch/arm/mach-tegra/tegra.c:165:13: error: 'tegra_pmc_restart' undeclared here (not in a function)
  .restart = tegra_pmc_restart,
             ^
make[3]: *** [arch/arm/mach-tegra/tegra.o] Error 1

when CONFIG_PM_SLEEP is disabled, and also this one when SMP is
turned on in addition:


/git/arm-soc/arch/arm/mach-tegra/platsmp.c: In function 'tegra30_boot_secondary':
/git/arm-soc/arch/arm/mach-tegra/platsmp.c:97:4: error: implicit declaration of function 'tegra_pmc_cpu_is_powered' [-Werror=implicit-function-declaration]
    if (tegra_pmc_cpu_is_powered(cpu))
    ^
/git/arm-soc/arch/arm/mach-tegra/platsmp.c:110:3: error: implicit declaration of function 'tegra_pmc_cpu_power_on' [-Werror=implicit-function-declaration]
   ret = tegra_pmc_cpu_power_on(cpu);
   ^
/git/arm-soc/arch/arm/mach-tegra/platsmp.c:129:2: error: implicit declaration of function 'tegra_pmc_cpu_remove_clamping' [-Werror=implicit-function-declaration]
  ret = tegra_pmc_cpu_remove_clamping(cpu);
  ^
cc1: some warnings being treated as errors

I applied this hack locally to work around that:

diff --git a/include/linux/tegra-soc.h b/include/linux/tegra-soc.h
index 70a612442cda..a89fe9e588ac 100644
--- a/include/linux/tegra-soc.h
+++ b/include/linux/tegra-soc.h
@@ -73,7 +73,6 @@ enum tegra_suspend_mode {
 	TEGRA_MAX_SUSPEND_MODE,
 };
 
-#ifdef CONFIG_PM_SLEEP
 enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void);
 void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode);
 void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode);
@@ -83,7 +82,6 @@ int tegra_pmc_cpu_power_on(int cpuid);
 int tegra_pmc_cpu_remove_clamping(int cpuid);
 
 void tegra_pmc_restart(enum reboot_mode mode, const char *cmd);
-#endif
 
 /*
  * PM

> > On a more general note, why are you adding this stuff into a global
> > header file in the first place? All users are in the same directory
> > in which the functions are defined.
> 
> That's mostly preparatory work. We'll need to move tegra-pmc.c out of
> arch/arm/mach-tegra at some point. I've proposed two patches already to
> do that, one move the driver to drivers/soc/tegra and was massively
> NAK'ed (I'm still not sure I agree) and people requested that this be
> moved into drivers/power. I then posted a 2 patch series to move power
> supply drivers into a subdirectory (drivers/power/supply) so that
> drivers in drivers/power didn't have to depend on CONFIG_POWER_SUPPLY
> for no good reason.
> 
> The latter series didn't receive any comments whatsoever in over a week,
> so in order to keep things moving forward I respun the PMC patch to do
> the conversion without moving the code out of arch/arm/mach-tegra yet.
> That way moving the driver out of arch/arm/mach-tegra will be a simple
> matter of moving and the rework will already be done. You were Cc'ed on
> the second series, so if you want to take a look (and maybe help get
> things moving) the patches are called:
> 
> 	[PATCH 0/2] Restructure driver/power and add Tegra PMC driver
> 	[PATCH 1/2] power: Move power-supply drivers to subdirectory
> 	[PATCH 2/2] ARM: tegra: Convert PMC to a driver

Ok, I'll have a look. I think when this becomes a separate driver, it
should also have its own header file, so maybe you can in the meantime
make it a local header file in mach-tegra until we have found a good
place for it.

	Arnd

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 12/12] ARM: tegra: Convert PMC to a driver
  2014-07-16 14:12       ` Arnd Bergmann
@ 2014-07-16 15:14         ` Thierry Reding
  2014-07-16 15:22           ` Arnd Bergmann
  0 siblings, 1 reply; 38+ messages in thread
From: Thierry Reding @ 2014-07-16 15:14 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jul 16, 2014 at 04:12:29PM +0200, Arnd Bergmann wrote:
> On Wednesday 16 July 2014 15:22:41 Thierry Reding wrote:
> > On Wed, Jul 16, 2014 at 01:56:44PM +0200, Arnd Bergmann wrote:
> > > On Friday 11 July 2014, Thierry Reding wrote:
> > > > +/*
> > > > + * PMC
> > > > + */
> > > > +enum tegra_suspend_mode {
> > > > +       TEGRA_SUSPEND_NONE = 0,
> > > > +       TEGRA_SUSPEND_LP2, /* CPU voltage off */
> > > > +       TEGRA_SUSPEND_LP1, /* CPU voltage off, DRAM self-refresh */
> > > > +       TEGRA_SUSPEND_LP0, /* CPU + core voltage off, DRAM self-refresh */
> > > > +       TEGRA_MAX_SUSPEND_MODE,
> > > > +};
> > > > +
> > > > +#ifdef CONFIG_PM_SLEEP
> > > > +enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void);
> > > > +void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode);
> > > > +void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode);
> > > > +
> > > > +bool tegra_pmc_cpu_is_powered(int cpuid);
> > > > +int tegra_pmc_cpu_power_on(int cpuid);
> > > > +int tegra_pmc_cpu_remove_clamping(int cpuid);
> > > > +
> > > > +void tegra_pmc_restart(enum reboot_mode mode, const char *cmd);
> > > > +#endif
> > > > +
> > > > +/*
> > > 
> > > This part is causing multiple build failures in the randconfig tests.
> > > You can avoid them by removing the #ifdef.
> > 
> > How is this causing build failures? I only see them used wherever
> > CONFIG_PM_SLEEP is defined.
> > 
> > Although I guess tegra-pmc.c could cause sparse warnings since it
> > implements these functions regardless of CONFIG_PM_SLEEP, which probably
> > is the bug that should be fixed.
> > 
> > Do you have a randconfig that I can use to reproduce this and come up
> > with a fix?
> 
> I got this error (always):
> 
> /git/arm-soc/arch/arm/mach-tegra/tegra.c:165:13: error: 'tegra_pmc_restart' undeclared here (not in a function)
>   .restart = tegra_pmc_restart,
>              ^
> make[3]: *** [arch/arm/mach-tegra/tegra.o] Error 1
> 
> when CONFIG_PM_SLEEP is disabled, and also this one when SMP is
> turned on in addition:
> 
> 
> /git/arm-soc/arch/arm/mach-tegra/platsmp.c: In function 'tegra30_boot_secondary':
> /git/arm-soc/arch/arm/mach-tegra/platsmp.c:97:4: error: implicit declaration of function 'tegra_pmc_cpu_is_powered' [-Werror=implicit-function-declaration]
>     if (tegra_pmc_cpu_is_powered(cpu))
>     ^
> /git/arm-soc/arch/arm/mach-tegra/platsmp.c:110:3: error: implicit declaration of function 'tegra_pmc_cpu_power_on' [-Werror=implicit-function-declaration]
>    ret = tegra_pmc_cpu_power_on(cpu);
>    ^
> /git/arm-soc/arch/arm/mach-tegra/platsmp.c:129:2: error: implicit declaration of function 'tegra_pmc_cpu_remove_clamping' [-Werror=implicit-function-declaration]
>   ret = tegra_pmc_cpu_remove_clamping(cpu);
>   ^
> cc1: some warnings being treated as errors
> 
> I applied this hack locally to work around that:
> 
> diff --git a/include/linux/tegra-soc.h b/include/linux/tegra-soc.h
> index 70a612442cda..a89fe9e588ac 100644
> --- a/include/linux/tegra-soc.h
> +++ b/include/linux/tegra-soc.h
> @@ -73,7 +73,6 @@ enum tegra_suspend_mode {
>  	TEGRA_MAX_SUSPEND_MODE,
>  };
>  
> -#ifdef CONFIG_PM_SLEEP
>  enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void);
>  void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode);
>  void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode);
> @@ -83,7 +82,6 @@ int tegra_pmc_cpu_power_on(int cpuid);
>  int tegra_pmc_cpu_remove_clamping(int cpuid);
>  
>  void tegra_pmc_restart(enum reboot_mode mode, const char *cmd);
> -#endif
>  
>  /*
>   * PM

I pushed fixes for these to Tegra's for-next branch (and for-3.17/soc).

> 
> > > On a more general note, why are you adding this stuff into a global
> > > header file in the first place? All users are in the same directory
> > > in which the functions are defined.
> > 
> > That's mostly preparatory work. We'll need to move tegra-pmc.c out of
> > arch/arm/mach-tegra at some point. I've proposed two patches already to
> > do that, one move the driver to drivers/soc/tegra and was massively
> > NAK'ed (I'm still not sure I agree) and people requested that this be
> > moved into drivers/power. I then posted a 2 patch series to move power
> > supply drivers into a subdirectory (drivers/power/supply) so that
> > drivers in drivers/power didn't have to depend on CONFIG_POWER_SUPPLY
> > for no good reason.
> > 
> > The latter series didn't receive any comments whatsoever in over a week,
> > so in order to keep things moving forward I respun the PMC patch to do
> > the conversion without moving the code out of arch/arm/mach-tegra yet.
> > That way moving the driver out of arch/arm/mach-tegra will be a simple
> > matter of moving and the rework will already be done. You were Cc'ed on
> > the second series, so if you want to take a look (and maybe help get
> > things moving) the patches are called:
> > 
> > 	[PATCH 0/2] Restructure driver/power and add Tegra PMC driver
> > 	[PATCH 1/2] power: Move power-supply drivers to subdirectory
> > 	[PATCH 2/2] ARM: tegra: Convert PMC to a driver
> 
> Ok, I'll have a look. I think when this becomes a separate driver, it
> should also have its own header file, so maybe you can in the meantime
> make it a local header file in mach-tegra until we have found a good
> place for it.

Why do you think it should be a separate header? We already have a
couple in include/linux and I'm not sure it's useful to add even more.
If anything I would've thought it made sense to move the content of the
other headers into tegra-soc.h.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140716/1f01ff94/attachment.sig>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 12/12] ARM: tegra: Convert PMC to a driver
  2014-07-16 15:14         ` Thierry Reding
@ 2014-07-16 15:22           ` Arnd Bergmann
  2014-07-16 18:57             ` Thierry Reding
  0 siblings, 1 reply; 38+ messages in thread
From: Arnd Bergmann @ 2014-07-16 15:22 UTC (permalink / raw)
  To: linux-arm-kernel

On Wednesday 16 July 2014 17:14:29 Thierry Reding wrote:
> > 
> > Ok, I'll have a look. I think when this becomes a separate driver, it
> > should also have its own header file, so maybe you can in the meantime
> > make it a local header file in mach-tegra until we have found a good
> > place for it.
> 
> Why do you think it should be a separate header? We already have a
> couple in include/linux and I'm not sure it's useful to add even more.
> If anything I would've thought it made sense to move the content of the
> other headers into tegra-soc.h.

I very much dislike the idea of having a per-vendor header file that
everything gets crammed into. We should try to have proper subsystems
and generic interfaces for these wherever possible.

	Arnd

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 12/12] ARM: tegra: Convert PMC to a driver
  2014-07-16 15:22           ` Arnd Bergmann
@ 2014-07-16 18:57             ` Thierry Reding
  2014-07-16 19:34               ` Olof Johansson
  2014-07-17  8:53               ` Peter De Schrijver
  0 siblings, 2 replies; 38+ messages in thread
From: Thierry Reding @ 2014-07-16 18:57 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jul 16, 2014 at 05:22:03PM +0200, Arnd Bergmann wrote:
> On Wednesday 16 July 2014 17:14:29 Thierry Reding wrote:
> > > 
> > > Ok, I'll have a look. I think when this becomes a separate driver, it
> > > should also have its own header file, so maybe you can in the meantime
> > > make it a local header file in mach-tegra until we have found a good
> > > place for it.
> > 
> > Why do you think it should be a separate header? We already have a
> > couple in include/linux and I'm not sure it's useful to add even more.
> > If anything I would've thought it made sense to move the content of the
> > other headers into tegra-soc.h.
> 
> I very much dislike the idea of having a per-vendor header file that
> everything gets crammed into. We should try to have proper subsystems
> and generic interfaces for these wherever possible.

I completely agree. However spreading the SoC-specific functions across
multiple header files isn't going to help. If we keep all the per-vendor
APIs in one file it makes it easier to see what could still be moved off
into a separate subsystem.

Now for PMC specifically, we've investigated converting the powergate
API to power domains. I don't think it will be possible to make that
work. The issue is that there's a defined sequence that needs to be
respected to make sure the device is powered up properly. That sequence
involves the primary clock and reset of the device. It's been proposed
to make these clocks available to the PMC driver so that it can control
them, but then we can't make sure that clocks are really off if they
need to be, since we have two drivers accessing them. The only way I see
to make that work reliably is by moving complete control of the
powergate into drivers so that they can make sure clocks and resets are
in the correct states.

The PMC driver also provides access to I/O rails and specifically a deep
power down state. Some modules are in deep power down state by default,
so they need to be brought out of that state. I suppose this would be
easier to turn into a generic framework because there aren't any cross-
dependencies like for powergates, but I'm not aware of any other SoC
having a similar feature (or implementation thereof in the kernel). And
adding a subsystem just for the sake of it if only one implementation is
available isn't a good idea in my opinion because it will be naturally
designed to work best (and therefore maybe only) for the one instance.

This issue is a fundamental one and there are bound to be other SoCs
that have similarly unique blocks for which it's impractical to add a
framework. I suspect the primary reason why we haven't run into it this
frequently is because a lot of it is still hidden in arch/arm/mach-*.

I'm open to suggestions of course, but the best option I currently see
is to collect these custom APIs in a central place so that we can easily
compare various SoCs for commonalities as time goes by and factor them
out into subsystems where appropriate.

For the same reason I think it's valid to put this type of code into
drivers/soc. That way we have one subdirectory to look through for
potential unification rather than various ones sprinkled across arch
directories. It makes little sense in my opinion to move this code to
drivers/power if there's no common framework anyway.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140716/11839690/attachment-0001.sig>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 12/12] ARM: tegra: Convert PMC to a driver
  2014-07-16 18:57             ` Thierry Reding
@ 2014-07-16 19:34               ` Olof Johansson
  2014-07-17  8:54                 ` Arnd Bergmann
  2014-07-17  8:53               ` Peter De Schrijver
  1 sibling, 1 reply; 38+ messages in thread
From: Olof Johansson @ 2014-07-16 19:34 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jul 16, 2014 at 11:57 AM, Thierry Reding
<thierry.reding@gmail.com> wrote:
> On Wed, Jul 16, 2014 at 05:22:03PM +0200, Arnd Bergmann wrote:
>> On Wednesday 16 July 2014 17:14:29 Thierry Reding wrote:
>> > >
>> > > Ok, I'll have a look. I think when this becomes a separate driver, it
>> > > should also have its own header file, so maybe you can in the meantime
>> > > make it a local header file in mach-tegra until we have found a good
>> > > place for it.
>> >
>> > Why do you think it should be a separate header? We already have a
>> > couple in include/linux and I'm not sure it's useful to add even more.
>> > If anything I would've thought it made sense to move the content of the
>> > other headers into tegra-soc.h.
>>
>> I very much dislike the idea of having a per-vendor header file that
>> everything gets crammed into. We should try to have proper subsystems
>> and generic interfaces for these wherever possible.
>
> I completely agree. However spreading the SoC-specific functions across
> multiple header files isn't going to help. If we keep all the per-vendor
> APIs in one file it makes it easier to see what could still be moved off
> into a separate subsystem.
>
> Now for PMC specifically, we've investigated converting the powergate
> API to power domains. I don't think it will be possible to make that
> work. The issue is that there's a defined sequence that needs to be
> respected to make sure the device is powered up properly. That sequence
> involves the primary clock and reset of the device. It's been proposed
> to make these clocks available to the PMC driver so that it can control
> them, but then we can't make sure that clocks are really off if they
> need to be, since we have two drivers accessing them. The only way I see
> to make that work reliably is by moving complete control of the
> powergate into drivers so that they can make sure clocks and resets are
> in the correct states.
>
> The PMC driver also provides access to I/O rails and specifically a deep
> power down state. Some modules are in deep power down state by default,
> so they need to be brought out of that state. I suppose this would be
> easier to turn into a generic framework because there aren't any cross-
> dependencies like for powergates, but I'm not aware of any other SoC
> having a similar feature (or implementation thereof in the kernel). And
> adding a subsystem just for the sake of it if only one implementation is
> available isn't a good idea in my opinion because it will be naturally
> designed to work best (and therefore maybe only) for the one instance.
>
> This issue is a fundamental one and there are bound to be other SoCs
> that have similarly unique blocks for which it's impractical to add a
> framework. I suspect the primary reason why we haven't run into it this
> frequently is because a lot of it is still hidden in arch/arm/mach-*.
>
> I'm open to suggestions of course, but the best option I currently see
> is to collect these custom APIs in a central place so that we can easily
> compare various SoCs for commonalities as time goes by and factor them
> out into subsystems where appropriate.
>
> For the same reason I think it's valid to put this type of code into
> drivers/soc. That way we have one subdirectory to look through for
> potential unification rather than various ones sprinkled across arch
> directories. It makes little sense in my opinion to move this code to
> drivers/power if there's no common framework anyway.

I agree. We can move them out and make them common them later if needed.

We're sometimes trying too hard to find proper homes for various new
drivers, which means that we're proliferating the kernel with a lot of
new driver directories that have only one or two drivers in them.

I'd rather collect stuff in drivers/soc, and move it out as needed
later. Especially since we merge drivers/soc through one merge path
(arm-soc) and can keep an eye on it, while the
scatter-drivers-everywhere approach merges through various
maintainers.



-Olof

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 12/12] ARM: tegra: Convert PMC to a driver
  2014-07-16 18:57             ` Thierry Reding
  2014-07-16 19:34               ` Olof Johansson
@ 2014-07-17  8:53               ` Peter De Schrijver
  2014-07-17  9:01                 ` Peter De Schrijver
  1 sibling, 1 reply; 38+ messages in thread
From: Peter De Schrijver @ 2014-07-17  8:53 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jul 16, 2014 at 08:57:16PM +0200, Thierry Reding wrote:
> * PGP Signed by an unknown key
> 
> On Wed, Jul 16, 2014 at 05:22:03PM +0200, Arnd Bergmann wrote:
> > On Wednesday 16 July 2014 17:14:29 Thierry Reding wrote:
> > > > 
> > > > Ok, I'll have a look. I think when this becomes a separate driver, it
> > > > should also have its own header file, so maybe you can in the meantime
> > > > make it a local header file in mach-tegra until we have found a good
> > > > place for it.
> > > 
> > > Why do you think it should be a separate header? We already have a
> > > couple in include/linux and I'm not sure it's useful to add even more.
> > > If anything I would've thought it made sense to move the content of the
> > > other headers into tegra-soc.h.
> > 
> > I very much dislike the idea of having a per-vendor header file that
> > everything gets crammed into. We should try to have proper subsystems
> > and generic interfaces for these wherever possible.
> 
> I completely agree. However spreading the SoC-specific functions across
> multiple header files isn't going to help. If we keep all the per-vendor
> APIs in one file it makes it easier to see what could still be moved off
> into a separate subsystem.
> 
> Now for PMC specifically, we've investigated converting the powergate
> API to power domains. I don't think it will be possible to make that
> work. The issue is that there's a defined sequence that needs to be
> respected to make sure the device is powered up properly. That sequence
> involves the primary clock and reset of the device. It's been proposed
> to make these clocks available to the PMC driver so that it can control
> them, but then we can't make sure that clocks are really off if they
> need to be, since we have two drivers accessing them. The only way I see

resets do not have reference counts, so they can be controlled by a
powerdomain driver without any problems. For clocks, there would only be
a problem for the module clocks if the drivers don't use runtime PM. If
we move all drivers to runtime PM, the clock control can move into the
powerdomain code and runtime PM will ensure domains are not turned off
with active modules.

> to make that work reliably is by moving complete control of the
> powergate into drivers so that they can make sure clocks and resets are
> in the correct states.
> 

Which won't work if you have domains which contain several modules.

Peter.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 12/12] ARM: tegra: Convert PMC to a driver
  2014-07-16 19:34               ` Olof Johansson
@ 2014-07-17  8:54                 ` Arnd Bergmann
  2014-07-17 11:06                   ` Thierry Reding
  0 siblings, 1 reply; 38+ messages in thread
From: Arnd Bergmann @ 2014-07-17  8:54 UTC (permalink / raw)
  To: linux-arm-kernel

On Wednesday 16 July 2014 12:34:56 Olof Johansson wrote:
> On Wed, Jul 16, 2014 at 11:57 AM, Thierry Reding
> <thierry.reding@gmail.com> wrote:
> > On Wed, Jul 16, 2014 at 05:22:03PM +0200, Arnd Bergmann wrote:
> >> On Wednesday 16 July 2014 17:14:29 Thierry Reding wrote:
> >> > >
> >> > > Ok, I'll have a look. I think when this becomes a separate driver, it
> >> > > should also have its own header file, so maybe you can in the meantime
> >> > > make it a local header file in mach-tegra until we have found a good
> >> > > place for it.
> >> >
> >> > Why do you think it should be a separate header? We already have a
> >> > couple in include/linux and I'm not sure it's useful to add even more.
> >> > If anything I would've thought it made sense to move the content of the
> >> > other headers into tegra-soc.h.
> >>
> >> I very much dislike the idea of having a per-vendor header file that
> >> everything gets crammed into. We should try to have proper subsystems
> >> and generic interfaces for these wherever possible.
> >
> > I completely agree. However spreading the SoC-specific functions across
> > multiple header files isn't going to help. If we keep all the per-vendor
> > APIs in one file it makes it easier to see what could still be moved off
> > into a separate subsystem.
> >
> > Now for PMC specifically, we've investigated converting the powergate
> > API to power domains. I don't think it will be possible to make that
> > work. The issue is that there's a defined sequence that needs to be
> > respected to make sure the device is powered up properly. That sequence
> > involves the primary clock and reset of the device. It's been proposed
> > to make these clocks available to the PMC driver so that it can control
> > them, but then we can't make sure that clocks are really off if they
> > need to be, since we have two drivers accessing them. The only way I see
> > to make that work reliably is by moving complete control of the
> > powergate into drivers so that they can make sure clocks and resets are
> > in the correct states.

I don't completely follow, but that's ok ;-)

> > The PMC driver also provides access to I/O rails and specifically a deep
> > power down state. Some modules are in deep power down state by default,
> > so they need to be brought out of that state. I suppose this would be
> > easier to turn into a generic framework because there aren't any cross-
> > dependencies like for powergates, but I'm not aware of any other SoC
> > having a similar feature (or implementation thereof in the kernel). And
> > adding a subsystem just for the sake of it if only one implementation is
> > available isn't a good idea in my opinion because it will be naturally
> > designed to work best (and therefore maybe only) for the one instance.
> >
> > This issue is a fundamental one and there are bound to be other SoCs
> > that have similarly unique blocks for which it's impractical to add a
> > framework. I suspect the primary reason why we haven't run into it this
> > frequently is because a lot of it is still hidden in arch/arm/mach-*.
> >
> > I'm open to suggestions of course, but the best option I currently see
> > is to collect these custom APIs in a central place so that we can easily
> > compare various SoCs for commonalities as time goes by and factor them
> > out into subsystems where appropriate.
> >
> > For the same reason I think it's valid to put this type of code into
> > drivers/soc. That way we have one subdirectory to look through for
> > potential unification rather than various ones sprinkled across arch
> > directories. It makes little sense in my opinion to move this code to
> > drivers/power if there's no common framework anyway.
> 
> I agree. We can move them out and make them common them later if needed.
> 
> We're sometimes trying too hard to find proper homes for various new
> drivers, which means that we're proliferating the kernel with a lot of
> new driver directories that have only one or two drivers in them.
> 
> I'd rather collect stuff in drivers/soc, and move it out as needed
> later. Especially since we merge drivers/soc through one merge path
> (arm-soc) and can keep an eye on it, while the
> scatter-drivers-everywhere approach merges through various
> maintainers.

Ok. I'm fine with having one driver in drivers/soc for the pmc (and
a few associated bits if necessary) and a header file for that. If you
end up with two separate drivers in drivers/soc, I'd also prefer two
separate header files.

It may be a good idea to put these headers somewhere other than
include/linux/*.h, which is completely overloaded by random stuff.
We could use include/linux/soc/*.h or include/soc/*.h for those.

	Arnd

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 12/12] ARM: tegra: Convert PMC to a driver
  2014-07-17  8:53               ` Peter De Schrijver
@ 2014-07-17  9:01                 ` Peter De Schrijver
  2014-07-17 11:01                   ` Thierry Reding
  0 siblings, 1 reply; 38+ messages in thread
From: Peter De Schrijver @ 2014-07-17  9:01 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jul 17, 2014 at 10:53:08AM +0200, Peter De Schrijver wrote:
> On Wed, Jul 16, 2014 at 08:57:16PM +0200, Thierry Reding wrote:
> > * PGP Signed by an unknown key
> > 
> > On Wed, Jul 16, 2014 at 05:22:03PM +0200, Arnd Bergmann wrote:
> > > On Wednesday 16 July 2014 17:14:29 Thierry Reding wrote:
> > > > > 
> > > > > Ok, I'll have a look. I think when this becomes a separate driver, it
> > > > > should also have its own header file, so maybe you can in the meantime
> > > > > make it a local header file in mach-tegra until we have found a good
> > > > > place for it.
> > > > 
> > > > Why do you think it should be a separate header? We already have a
> > > > couple in include/linux and I'm not sure it's useful to add even more.
> > > > If anything I would've thought it made sense to move the content of the
> > > > other headers into tegra-soc.h.
> > > 
> > > I very much dislike the idea of having a per-vendor header file that
> > > everything gets crammed into. We should try to have proper subsystems
> > > and generic interfaces for these wherever possible.
> > 
> > I completely agree. However spreading the SoC-specific functions across
> > multiple header files isn't going to help. If we keep all the per-vendor
> > APIs in one file it makes it easier to see what could still be moved off
> > into a separate subsystem.
> > 
> > Now for PMC specifically, we've investigated converting the powergate
> > API to power domains. I don't think it will be possible to make that
> > work. The issue is that there's a defined sequence that needs to be
> > respected to make sure the device is powered up properly. That sequence
> > involves the primary clock and reset of the device. It's been proposed
> > to make these clocks available to the PMC driver so that it can control
> > them, but then we can't make sure that clocks are really off if they
> > need to be, since we have two drivers accessing them. The only way I see
> 
> resets do not have reference counts, so they can be controlled by a
> powerdomain driver without any problems. For clocks, there would only be
> a problem for the module clocks if the drivers don't use runtime PM. If
> we move all drivers to runtime PM, the clock control can move into the
> powerdomain code and runtime PM will ensure domains are not turned off
> with active modules.
> 
> > to make that work reliably is by moving complete control of the
> > powergate into drivers so that they can make sure clocks and resets are
> > in the correct states.
> > 
> 
> Which won't work if you have domains which contain several modules.

We also need to control the memory clients in the domains using
MC_CLIENT_HOTRESET_CTRL.

Cheers,

Peter.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 12/12] ARM: tegra: Convert PMC to a driver
  2014-07-17  9:01                 ` Peter De Schrijver
@ 2014-07-17 11:01                   ` Thierry Reding
  2014-07-21  7:09                     ` Vince Hsu
  0 siblings, 1 reply; 38+ messages in thread
From: Thierry Reding @ 2014-07-17 11:01 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jul 17, 2014 at 12:01:56PM +0300, Peter De Schrijver wrote:
> On Thu, Jul 17, 2014 at 10:53:08AM +0200, Peter De Schrijver wrote:
> > On Wed, Jul 16, 2014 at 08:57:16PM +0200, Thierry Reding wrote:
> > > * PGP Signed by an unknown key
> > > 
> > > On Wed, Jul 16, 2014 at 05:22:03PM +0200, Arnd Bergmann wrote:
> > > > On Wednesday 16 July 2014 17:14:29 Thierry Reding wrote:
> > > > > > 
> > > > > > Ok, I'll have a look. I think when this becomes a separate driver, it
> > > > > > should also have its own header file, so maybe you can in the meantime
> > > > > > make it a local header file in mach-tegra until we have found a good
> > > > > > place for it.
> > > > > 
> > > > > Why do you think it should be a separate header? We already have a
> > > > > couple in include/linux and I'm not sure it's useful to add even more.
> > > > > If anything I would've thought it made sense to move the content of the
> > > > > other headers into tegra-soc.h.
> > > > 
> > > > I very much dislike the idea of having a per-vendor header file that
> > > > everything gets crammed into. We should try to have proper subsystems
> > > > and generic interfaces for these wherever possible.
> > > 
> > > I completely agree. However spreading the SoC-specific functions across
> > > multiple header files isn't going to help. If we keep all the per-vendor
> > > APIs in one file it makes it easier to see what could still be moved off
> > > into a separate subsystem.
> > > 
> > > Now for PMC specifically, we've investigated converting the powergate
> > > API to power domains. I don't think it will be possible to make that
> > > work. The issue is that there's a defined sequence that needs to be
> > > respected to make sure the device is powered up properly. That sequence
> > > involves the primary clock and reset of the device. It's been proposed
> > > to make these clocks available to the PMC driver so that it can control
> > > them, but then we can't make sure that clocks are really off if they
> > > need to be, since we have two drivers accessing them. The only way I see
> > 
> > resets do not have reference counts, so they can be controlled by a
> > powerdomain driver without any problems. For clocks, there would only be
> > a problem for the module clocks if the drivers don't use runtime PM. If
> > we move all drivers to runtime PM, the clock control can move into the
> > powerdomain code and runtime PM will ensure domains are not turned off
> > with active modules.
> > 
> > > to make that work reliably is by moving complete control of the
> > > powergate into drivers so that they can make sure clocks and resets are
> > > in the correct states.
> > > 
> > 
> > Which won't work if you have domains which contain several modules.
> 
> We also need to control the memory clients in the domains using
> MC_CLIENT_HOTRESET_CTRL.

Oh, great. More interdependencies...

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140717/1fca334e/attachment.sig>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 12/12] ARM: tegra: Convert PMC to a driver
  2014-07-17  8:54                 ` Arnd Bergmann
@ 2014-07-17 11:06                   ` Thierry Reding
  2014-07-21 12:06                     ` Arnd Bergmann
  0 siblings, 1 reply; 38+ messages in thread
From: Thierry Reding @ 2014-07-17 11:06 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jul 17, 2014 at 10:54:17AM +0200, Arnd Bergmann wrote:
> On Wednesday 16 July 2014 12:34:56 Olof Johansson wrote:
> > On Wed, Jul 16, 2014 at 11:57 AM, Thierry Reding
> > <thierry.reding@gmail.com> wrote:
> > > On Wed, Jul 16, 2014 at 05:22:03PM +0200, Arnd Bergmann wrote:
> > >> On Wednesday 16 July 2014 17:14:29 Thierry Reding wrote:
> > >> > >
> > >> > > Ok, I'll have a look. I think when this becomes a separate driver, it
> > >> > > should also have its own header file, so maybe you can in the meantime
> > >> > > make it a local header file in mach-tegra until we have found a good
> > >> > > place for it.
> > >> >
> > >> > Why do you think it should be a separate header? We already have a
> > >> > couple in include/linux and I'm not sure it's useful to add even more.
> > >> > If anything I would've thought it made sense to move the content of the
> > >> > other headers into tegra-soc.h.
> > >>
> > >> I very much dislike the idea of having a per-vendor header file that
> > >> everything gets crammed into. We should try to have proper subsystems
> > >> and generic interfaces for these wherever possible.
> > >
> > > I completely agree. However spreading the SoC-specific functions across
> > > multiple header files isn't going to help. If we keep all the per-vendor
> > > APIs in one file it makes it easier to see what could still be moved off
> > > into a separate subsystem.
> > >
> > > Now for PMC specifically, we've investigated converting the powergate
> > > API to power domains. I don't think it will be possible to make that
> > > work. The issue is that there's a defined sequence that needs to be
> > > respected to make sure the device is powered up properly. That sequence
> > > involves the primary clock and reset of the device. It's been proposed
> > > to make these clocks available to the PMC driver so that it can control
> > > them, but then we can't make sure that clocks are really off if they
> > > need to be, since we have two drivers accessing them. The only way I see
> > > to make that work reliably is by moving complete control of the
> > > powergate into drivers so that they can make sure clocks and resets are
> > > in the correct states.
> 
> I don't completely follow, but that's ok ;-)
> 
> > > The PMC driver also provides access to I/O rails and specifically a deep
> > > power down state. Some modules are in deep power down state by default,
> > > so they need to be brought out of that state. I suppose this would be
> > > easier to turn into a generic framework because there aren't any cross-
> > > dependencies like for powergates, but I'm not aware of any other SoC
> > > having a similar feature (or implementation thereof in the kernel). And
> > > adding a subsystem just for the sake of it if only one implementation is
> > > available isn't a good idea in my opinion because it will be naturally
> > > designed to work best (and therefore maybe only) for the one instance.
> > >
> > > This issue is a fundamental one and there are bound to be other SoCs
> > > that have similarly unique blocks for which it's impractical to add a
> > > framework. I suspect the primary reason why we haven't run into it this
> > > frequently is because a lot of it is still hidden in arch/arm/mach-*.
> > >
> > > I'm open to suggestions of course, but the best option I currently see
> > > is to collect these custom APIs in a central place so that we can easily
> > > compare various SoCs for commonalities as time goes by and factor them
> > > out into subsystems where appropriate.
> > >
> > > For the same reason I think it's valid to put this type of code into
> > > drivers/soc. That way we have one subdirectory to look through for
> > > potential unification rather than various ones sprinkled across arch
> > > directories. It makes little sense in my opinion to move this code to
> > > drivers/power if there's no common framework anyway.
> > 
> > I agree. We can move them out and make them common them later if needed.
> > 
> > We're sometimes trying too hard to find proper homes for various new
> > drivers, which means that we're proliferating the kernel with a lot of
> > new driver directories that have only one or two drivers in them.
> > 
> > I'd rather collect stuff in drivers/soc, and move it out as needed
> > later. Especially since we merge drivers/soc through one merge path
> > (arm-soc) and can keep an eye on it, while the
> > scatter-drivers-everywhere approach merges through various
> > maintainers.
> 
> Ok. I'm fine with having one driver in drivers/soc for the pmc (and
> a few associated bits if necessary) and a header file for that. If you
> end up with two separate drivers in drivers/soc, I'd also prefer two
> separate header files.
> 
> It may be a good idea to put these headers somewhere other than
> include/linux/*.h, which is completely overloaded by random stuff.
> We could use include/linux/soc/*.h or include/soc/*.h for those.

We could go all the way and make it include/soc/tegra/*.h for better
namespacing. I guess either way would be fine, really, since the number
of files in those directories should be small by definition, so we
should be able to do without the extra SoC directory, too. I have a
slight preference for a separate SoC directory, do you have any
objections?

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140717/afc16874/attachment-0001.sig>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 12/12] ARM: tegra: Convert PMC to a driver
  2014-07-17 11:01                   ` Thierry Reding
@ 2014-07-21  7:09                     ` Vince Hsu
  2014-07-21  9:02                       ` Thierry Reding
  0 siblings, 1 reply; 38+ messages in thread
From: Vince Hsu @ 2014-07-21  7:09 UTC (permalink / raw)
  To: linux-arm-kernel


On 07/17/2014 07:01 PM, Thierry Reding wrote:
> * PGP Signed by an unknown key
>
> On Thu, Jul 17, 2014 at 12:01:56PM +0300, Peter De Schrijver wrote:
>> On Thu, Jul 17, 2014 at 10:53:08AM +0200, Peter De Schrijver wrote:
>>> On Wed, Jul 16, 2014 at 08:57:16PM +0200, Thierry Reding wrote:
>>>>> Old Signed by an unknown key
>>>> On Wed, Jul 16, 2014 at 05:22:03PM +0200, Arnd Bergmann wrote:
>>>>> On Wednesday 16 July 2014 17:14:29 Thierry Reding wrote:
>>>>>>> Ok, I'll have a look. I think when this becomes a separate driver, it
>>>>>>> should also have its own header file, so maybe you can in the meantime
>>>>>>> make it a local header file in mach-tegra until we have found a good
>>>>>>> place for it.
>>>>>> Why do you think it should be a separate header? We already have a
>>>>>> couple in include/linux and I'm not sure it's useful to add even more.
>>>>>> If anything I would've thought it made sense to move the content of the
>>>>>> other headers into tegra-soc.h.
>>>>> I very much dislike the idea of having a per-vendor header file that
>>>>> everything gets crammed into. We should try to have proper subsystems
>>>>> and generic interfaces for these wherever possible.
>>>> I completely agree. However spreading the SoC-specific functions across
>>>> multiple header files isn't going to help. If we keep all the per-vendor
>>>> APIs in one file it makes it easier to see what could still be moved off
>>>> into a separate subsystem.
>>>>
>>>> Now for PMC specifically, we've investigated converting the powergate
>>>> API to power domains. I don't think it will be possible to make that
>>>> work. The issue is that there's a defined sequence that needs to be
>>>> respected to make sure the device is powered up properly. That sequence
>>>> involves the primary clock and reset of the device. It's been proposed
>>>> to make these clocks available to the PMC driver so that it can control
>>>> them, but then we can't make sure that clocks are really off if they
>>>> need to be, since we have two drivers accessing them. The only way I see
>>> resets do not have reference counts, so they can be controlled by a
>>> powerdomain driver without any problems. For clocks, there would only be
>>> a problem for the module clocks if the drivers don't use runtime PM. If
>>> we move all drivers to runtime PM, the clock control can move into the
>>> powerdomain code and runtime PM will ensure domains are not turned off
>>> with active modules.
>>>
>>>> to make that work reliably is by moving complete control of the
>>>> powergate into drivers so that they can make sure clocks and resets are
>>>> in the correct states.
>>>>
>>> Which won't work if you have domains which contain several modules.
>> We also need to control the memory clients in the domains using
>> MC_CLIENT_HOTRESET_CTRL.
> Oh, great. More interdependencies...
Some domains depend on others. Can we take this into account?

Thanks,
Vince

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 12/12] ARM: tegra: Convert PMC to a driver
  2014-07-21  7:09                     ` Vince Hsu
@ 2014-07-21  9:02                       ` Thierry Reding
  2014-07-22  3:34                         ` Vince Hsu
  0 siblings, 1 reply; 38+ messages in thread
From: Thierry Reding @ 2014-07-21  9:02 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jul 21, 2014 at 03:09:29PM +0800, Vince Hsu wrote:
> 
> On 07/17/2014 07:01 PM, Thierry Reding wrote:
> >* PGP Signed by an unknown key
> >
> >On Thu, Jul 17, 2014 at 12:01:56PM +0300, Peter De Schrijver wrote:
> >>On Thu, Jul 17, 2014 at 10:53:08AM +0200, Peter De Schrijver wrote:
> >>>On Wed, Jul 16, 2014 at 08:57:16PM +0200, Thierry Reding wrote:
> >>>>>Old Signed by an unknown key
> >>>>On Wed, Jul 16, 2014 at 05:22:03PM +0200, Arnd Bergmann wrote:
> >>>>>On Wednesday 16 July 2014 17:14:29 Thierry Reding wrote:
> >>>>>>>Ok, I'll have a look. I think when this becomes a separate driver, it
> >>>>>>>should also have its own header file, so maybe you can in the meantime
> >>>>>>>make it a local header file in mach-tegra until we have found a good
> >>>>>>>place for it.
> >>>>>>Why do you think it should be a separate header? We already have a
> >>>>>>couple in include/linux and I'm not sure it's useful to add even more.
> >>>>>>If anything I would've thought it made sense to move the content of the
> >>>>>>other headers into tegra-soc.h.
> >>>>>I very much dislike the idea of having a per-vendor header file that
> >>>>>everything gets crammed into. We should try to have proper subsystems
> >>>>>and generic interfaces for these wherever possible.
> >>>>I completely agree. However spreading the SoC-specific functions across
> >>>>multiple header files isn't going to help. If we keep all the per-vendor
> >>>>APIs in one file it makes it easier to see what could still be moved off
> >>>>into a separate subsystem.
> >>>>
> >>>>Now for PMC specifically, we've investigated converting the powergate
> >>>>API to power domains. I don't think it will be possible to make that
> >>>>work. The issue is that there's a defined sequence that needs to be
> >>>>respected to make sure the device is powered up properly. That sequence
> >>>>involves the primary clock and reset of the device. It's been proposed
> >>>>to make these clocks available to the PMC driver so that it can control
> >>>>them, but then we can't make sure that clocks are really off if they
> >>>>need to be, since we have two drivers accessing them. The only way I see
> >>>resets do not have reference counts, so they can be controlled by a
> >>>powerdomain driver without any problems. For clocks, there would only be
> >>>a problem for the module clocks if the drivers don't use runtime PM. If
> >>>we move all drivers to runtime PM, the clock control can move into the
> >>>powerdomain code and runtime PM will ensure domains are not turned off
> >>>with active modules.
> >>>
> >>>>to make that work reliably is by moving complete control of the
> >>>>powergate into drivers so that they can make sure clocks and resets are
> >>>>in the correct states.
> >>>>
> >>>Which won't work if you have domains which contain several modules.
> >>We also need to control the memory clients in the domains using
> >>MC_CLIENT_HOTRESET_CTRL.
> >Oh, great. More interdependencies...
> Some domains depend on others. Can we take this into account?

I'm not aware of any dependencies. Can you point me at the relevant
section in the TRM?

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140721/6ddc88eb/attachment.sig>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 12/12] ARM: tegra: Convert PMC to a driver
  2014-07-17 11:06                   ` Thierry Reding
@ 2014-07-21 12:06                     ` Arnd Bergmann
  2014-07-21 13:12                       ` Thierry Reding
  0 siblings, 1 reply; 38+ messages in thread
From: Arnd Bergmann @ 2014-07-21 12:06 UTC (permalink / raw)
  To: linux-arm-kernel

On Thursday 17 July 2014 13:06:53 Thierry Reding wrote:
> 
> We could go all the way and make it include/soc/tegra/*.h for better
> namespacing. I guess either way would be fine, really, since the number
> of files in those directories should be small by definition, so we
> should be able to do without the extra SoC directory, too. I have a
> slight preference for a separate SoC directory, do you have any
> objections?

I'm fine with it either way. I just noticed that you have now
moved the file, which resulted in a build error:

../drivers/ata/ahci_tegra.c:27:35: fatal error: linux/tegra-powergate.h: No such file or directory
 #include <linux/tegra-powergate.h>
                                   ^
compilation terminated.
make[4]: *** [drivers/ata/ahci_tegra.o] Error 1

so somebody needs to pick up this patch:

diff --git a/drivers/ata/ahci_tegra.c b/drivers/ata/ahci_tegra.c
index d30bb21afd67..d7c6b1f550cd 100644
--- a/drivers/ata/ahci_tegra.c
+++ b/drivers/ata/ahci_tegra.c
@@ -24,8 +24,8 @@
 #include <linux/module.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
-#include <linux/tegra-powergate.h>
 #include <linux/regulator/consumer.h>
+#include <soc/tegra/pmc.h>
 #include "ahci.h"
 
 #define SATA_CONFIGURATION_0				0x180


I haven't checked which trees are affected of if you have already posted
a patch to do this.

	Arnd

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 12/12] ARM: tegra: Convert PMC to a driver
  2014-07-21 12:06                     ` Arnd Bergmann
@ 2014-07-21 13:12                       ` Thierry Reding
  2014-07-21 13:16                         ` Tejun Heo
  0 siblings, 1 reply; 38+ messages in thread
From: Thierry Reding @ 2014-07-21 13:12 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jul 21, 2014 at 02:06:10PM +0200, Arnd Bergmann wrote:
> On Thursday 17 July 2014 13:06:53 Thierry Reding wrote:
> > 
> > We could go all the way and make it include/soc/tegra/*.h for better
> > namespacing. I guess either way would be fine, really, since the number
> > of files in those directories should be small by definition, so we
> > should be able to do without the extra SoC directory, too. I have a
> > slight preference for a separate SoC directory, do you have any
> > objections?
> 
> I'm fine with it either way. I just noticed that you have now
> moved the file, which resulted in a build error:
> 
> ../drivers/ata/ahci_tegra.c:27:35: fatal error: linux/tegra-powergate.h: No such file or directory
>  #include <linux/tegra-powergate.h>
>                                    ^
> compilation terminated.
> make[4]: *** [drivers/ata/ahci_tegra.o] Error 1
> 
> so somebody needs to pick up this patch:
> 
> diff --git a/drivers/ata/ahci_tegra.c b/drivers/ata/ahci_tegra.c
> index d30bb21afd67..d7c6b1f550cd 100644
> --- a/drivers/ata/ahci_tegra.c
> +++ b/drivers/ata/ahci_tegra.c
> @@ -24,8 +24,8 @@
>  #include <linux/module.h>
>  #include <linux/of_device.h>
>  #include <linux/platform_device.h>
> -#include <linux/tegra-powergate.h>
>  #include <linux/regulator/consumer.h>
> +#include <soc/tegra/pmc.h>
>  #include "ahci.h"
>  
>  #define SATA_CONFIGURATION_0				0x180
> 
> 
> I haven't checked which trees are affected of if you have already posted
> a patch to do this.
> 
> 	Arnd

Adding Tejun, since he took this into his tree on Friday I think, just a
few hours after I sent out pull requests for this.

I hadn't considered this build dependency. We could resolve this in two
ways I think:

	- merge the for-3.17/fuse-move branch from the Tegra tree into
	  the libata tree and apply Arnd's patch to the libata tree

	- provide a dummy include/linux/tegra-powergate.h header that
	  includes soc/tegra/powergate.h

In the latter case the dummy could possibly be removed right after
v3.17-rc1 along with a patch to convert the AHCI driver to use the new
header file. Or we could keep the compatibility header until the v3.18
merge window. I have a slight preference for this, even though it's a
wee bit of churn.

The problem is that we can't simply apply the patch that Arnd provided
because it would break the standalone libata tree if somebody were to
build Tegra with the new driver enabled.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140721/90b6b262/attachment-0001.sig>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 12/12] ARM: tegra: Convert PMC to a driver
  2014-07-21 13:12                       ` Thierry Reding
@ 2014-07-21 13:16                         ` Tejun Heo
  2014-07-21 13:39                           ` Thierry Reding
  0 siblings, 1 reply; 38+ messages in thread
From: Tejun Heo @ 2014-07-21 13:16 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jul 21, 2014 at 03:12:34PM +0200, Thierry Reding wrote:
> Adding Tejun, since he took this into his tree on Friday I think, just a
> few hours after I sent out pull requests for this.
> 
> I hadn't considered this build dependency. We could resolve this in two
> ways I think:
> 
> 	- merge the for-3.17/fuse-move branch from the Tegra tree into
> 	  the libata tree and apply Arnd's patch to the libata tree

I can pull the tegra tree into the libata if the tegra maintainer is
okay with it.

Thanks.

-- 
tejun

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 12/12] ARM: tegra: Convert PMC to a driver
  2014-07-21 13:16                         ` Tejun Heo
@ 2014-07-21 13:39                           ` Thierry Reding
  0 siblings, 0 replies; 38+ messages in thread
From: Thierry Reding @ 2014-07-21 13:39 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jul 21, 2014 at 09:16:19AM -0400, Tejun Heo wrote:
> On Mon, Jul 21, 2014 at 03:12:34PM +0200, Thierry Reding wrote:
> > Adding Tejun, since he took this into his tree on Friday I think, just a
> > few hours after I sent out pull requests for this.
> > 
> > I hadn't considered this build dependency. We could resolve this in two
> > ways I think:
> > 
> > 	- merge the for-3.17/fuse-move branch from the Tegra tree into
> > 	  the libata tree and apply Arnd's patch to the libata tree
> 
> I can pull the tegra tree into the libata if the tegra maintainer is
> okay with it.

It's fine with me, but maybe give Stephen, Arnd and Olof an opportunity
to object.

If you plan to go ahead with merging it in, this would be the right
signed tag to use:

	https://git.kernel.org/cgit/linux/kernel/git/tegra/linux.git/tag/?id=tegra-for-3.17-soc

And then you simply need to replace #include <linux/tegra-powergate.h>
with #include <soc/tegra/pmc.h> as Arnd showed.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140721/11965731/attachment.sig>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 12/12] ARM: tegra: Convert PMC to a driver
  2014-07-21  9:02                       ` Thierry Reding
@ 2014-07-22  3:34                         ` Vince Hsu
  0 siblings, 0 replies; 38+ messages in thread
From: Vince Hsu @ 2014-07-22  3:34 UTC (permalink / raw)
  To: linux-arm-kernel

On 07/21/2014 05:02 PM, Thierry Reding wrote:
> * PGP Signed by an unknown key
>
> On Mon, Jul 21, 2014 at 03:09:29PM +0800, Vince Hsu wrote:
>> On 07/17/2014 07:01 PM, Thierry Reding wrote:
>>>> Old Signed by an unknown key
>>> On Thu, Jul 17, 2014 at 12:01:56PM +0300, Peter De Schrijver wrote:
>>>> On Thu, Jul 17, 2014 at 10:53:08AM +0200, Peter De Schrijver wrote:
>>>>> On Wed, Jul 16, 2014 at 08:57:16PM +0200, Thierry Reding wrote:
>>>>>>> Old Signed by an unknown key
>>>>>> On Wed, Jul 16, 2014 at 05:22:03PM +0200, Arnd Bergmann wrote:
>>>>>>> On Wednesday 16 July 2014 17:14:29 Thierry Reding wrote:
>>>>>>>>> Ok, I'll have a look. I think when this becomes a separate driver, it
>>>>>>>>> should also have its own header file, so maybe you can in the meantime
>>>>>>>>> make it a local header file in mach-tegra until we have found a good
>>>>>>>>> place for it.
>>>>>>>> Why do you think it should be a separate header? We already have a
>>>>>>>> couple in include/linux and I'm not sure it's useful to add even more.
>>>>>>>> If anything I would've thought it made sense to move the content of the
>>>>>>>> other headers into tegra-soc.h.
>>>>>>> I very much dislike the idea of having a per-vendor header file that
>>>>>>> everything gets crammed into. We should try to have proper subsystems
>>>>>>> and generic interfaces for these wherever possible.
>>>>>> I completely agree. However spreading the SoC-specific functions across
>>>>>> multiple header files isn't going to help. If we keep all the per-vendor
>>>>>> APIs in one file it makes it easier to see what could still be moved off
>>>>>> into a separate subsystem.
>>>>>>
>>>>>> Now for PMC specifically, we've investigated converting the powergate
>>>>>> API to power domains. I don't think it will be possible to make that
>>>>>> work. The issue is that there's a defined sequence that needs to be
>>>>>> respected to make sure the device is powered up properly. That sequence
>>>>>> involves the primary clock and reset of the device. It's been proposed
>>>>>> to make these clocks available to the PMC driver so that it can control
>>>>>> them, but then we can't make sure that clocks are really off if they
>>>>>> need to be, since we have two drivers accessing them. The only way I see
>>>>> resets do not have reference counts, so they can be controlled by a
>>>>> powerdomain driver without any problems. For clocks, there would only be
>>>>> a problem for the module clocks if the drivers don't use runtime PM. If
>>>>> we move all drivers to runtime PM, the clock control can move into the
>>>>> powerdomain code and runtime PM will ensure domains are not turned off
>>>>> with active modules.
>>>>>
>>>>>> to make that work reliably is by moving complete control of the
>>>>>> powergate into drivers so that they can make sure clocks and resets are
>>>>>> in the correct states.
>>>>>>
>>>>> Which won't work if you have domains which contain several modules.
>>>> We also need to control the memory clients in the domains using
>>>> MC_CLIENT_HOTRESET_CTRL.
>>> Oh, great. More interdependencies...
>> Some domains depend on others. Can we take this into account?
> I'm not aware of any dependencies. Can you point me at the relevant
> section in the TRM?
As we talked offline yesterday, that's in 5.6.6.7 - 5.6.6.9.

Thanks,
Vince

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 05/12] soc/tegra: Add efuse driver for Tegra
  2014-07-11 12:16 ` [PATCH 05/12] soc/tegra: Add efuse driver for Tegra Thierry Reding
@ 2014-10-19  3:12   ` Shawn Guo
  2014-11-10 15:10     ` Thierry Reding
  0 siblings, 1 reply; 38+ messages in thread
From: Shawn Guo @ 2014-10-19  3:12 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jul 11, 2014 at 02:16:04PM +0200, Thierry Reding wrote:
> diff --git a/drivers/misc/fuse/Makefile b/drivers/misc/fuse/Makefile
> new file mode 100644
> index 000000000000..0679c4febc89
> --- /dev/null
> +++ b/drivers/misc/fuse/Makefile
> @@ -0,0 +1 @@
> +obj-$(CONFIG_ARCH_TEGRA)	+= tegra/

I just happened to notice this change on linux-next introduced by this
patch?  It's a leftover from early version of the patch, I guess?

Shawn

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 05/12] soc/tegra: Add efuse driver for Tegra
  2014-10-19  3:12   ` Shawn Guo
@ 2014-11-10 15:10     ` Thierry Reding
  0 siblings, 0 replies; 38+ messages in thread
From: Thierry Reding @ 2014-11-10 15:10 UTC (permalink / raw)
  To: linux-arm-kernel

On Sun, Oct 19, 2014 at 11:12:45AM +0800, Shawn Guo wrote:
> On Fri, Jul 11, 2014 at 02:16:04PM +0200, Thierry Reding wrote:
> > diff --git a/drivers/misc/fuse/Makefile b/drivers/misc/fuse/Makefile
> > new file mode 100644
> > index 000000000000..0679c4febc89
> > --- /dev/null
> > +++ b/drivers/misc/fuse/Makefile
> > @@ -0,0 +1 @@
> > +obj-$(CONFIG_ARCH_TEGRA)	+= tegra/
> 
> I just happened to notice this change on linux-next introduced by this
> patch?  It's a leftover from early version of the patch, I guess?

Indeed so. I've sent out a patch to fix this.

Thanks,
Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20141110/842be9cd/attachment.sig>

^ permalink raw reply	[flat|nested] 38+ messages in thread

end of thread, other threads:[~2014-11-10 15:10 UTC | newest]

Thread overview: 38+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-07-11 12:15 [PATCH 00/12] Add NVIDIA Tegra FUSE driver Thierry Reding
2014-07-11 12:16 ` [PATCH 01/12] ARM: tegra: Sort includes alphabetically Thierry Reding
2014-07-11 12:16 ` [PATCH 02/12] ARM: tegra: Use a function to get the chip ID Thierry Reding
2014-07-11 12:16 ` [PATCH 03/12] ARM: tegra: export apb dma readl/writel Thierry Reding
2014-07-11 12:16 ` [PATCH 04/12] ARM: tegra: move fuse exports to tegra-soc.h Thierry Reding
2014-07-11 12:16 ` [PATCH 05/12] soc/tegra: Add efuse driver for Tegra Thierry Reding
2014-10-19  3:12   ` Shawn Guo
2014-11-10 15:10     ` Thierry Reding
2014-07-11 12:16 ` [PATCH 06/12] soc/tegra: Add efuse and apbmisc bindings Thierry Reding
2014-07-11 12:16 ` [PATCH 07/12] soc/tegra: fuse: move APB DMA into Tegra20 fuse driver Thierry Reding
2014-07-11 12:16 ` [PATCH 08/12] misc: fuse: fix dummy functions Thierry Reding
2014-07-11 12:16 ` [PATCH 09/12] ARM: tegra: Setup CPU hotplug in a pure initcall Thierry Reding
2014-07-11 12:16 ` [PATCH 10/12] ARM: tegra: Always lock the CPU reset vector Thierry Reding
2014-07-11 12:16 ` [PATCH 11/12] soc/tegra: fuse: Set up in early initcall Thierry Reding
2014-07-11 12:16 ` [PATCH 12/12] ARM: tegra: Convert PMC to a driver Thierry Reding
2014-07-11 13:58   ` Peter De Schrijver
2014-07-14  8:06     ` Thierry Reding
2014-07-16 11:56   ` Arnd Bergmann
2014-07-16 13:22     ` Thierry Reding
2014-07-16 14:12       ` Arnd Bergmann
2014-07-16 15:14         ` Thierry Reding
2014-07-16 15:22           ` Arnd Bergmann
2014-07-16 18:57             ` Thierry Reding
2014-07-16 19:34               ` Olof Johansson
2014-07-17  8:54                 ` Arnd Bergmann
2014-07-17 11:06                   ` Thierry Reding
2014-07-21 12:06                     ` Arnd Bergmann
2014-07-21 13:12                       ` Thierry Reding
2014-07-21 13:16                         ` Tejun Heo
2014-07-21 13:39                           ` Thierry Reding
2014-07-17  8:53               ` Peter De Schrijver
2014-07-17  9:01                 ` Peter De Schrijver
2014-07-17 11:01                   ` Thierry Reding
2014-07-21  7:09                     ` Vince Hsu
2014-07-21  9:02                       ` Thierry Reding
2014-07-22  3:34                         ` Vince Hsu
2014-07-13  6:38 ` [PATCH 00/12] Add NVIDIA Tegra FUSE driver Olof Johansson
2014-07-14  6:57   ` Thierry Reding

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).