Эх сурвалжийг харах

Merge tag 'tegra-for-4.12-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux into next/drivers

soc/tegra: Core SoC changes for v4.12-rc1

This contains PMC support for Tegra186 as well as a proper driver for
the flow controller found on SoCs up to Tegra210. This also turns the
fuse driver into an explicitly non-modular driver.

* tag 'tegra-for-4.12-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux:
  soc/tegra: Add initial flowctrl support for Tegra132/210
  soc/tegra: flowctrl: Add basic platform driver
  soc/tegra: Move Tegra flowctrl driver
  ARM: tegra: Remove unnecessary inclusion of flowctrl header
  soc: tegra: make fuse-tegra explicitly non-modular
  soc/tegra: Fix link errors with PMC disabled
  soc/tegra: Implement Tegra186 PMC support

Signed-off-by: Olof Johansson <olof@lixom.net>
Olof Johansson 8 жил өмнө
parent
commit
55de807595

+ 34 - 0
Documentation/devicetree/bindings/arm/tegra/nvidia,tegra186-pmc.txt

@@ -0,0 +1,34 @@
+NVIDIA Tegra Power Management Controller (PMC)
+
+Required properties:
+- compatible: Should contain one of the following:
+  - "nvidia,tegra186-pmc": for Tegra186
+- reg: Must contain an (offset, length) pair of the register set for each
+  entry in reg-names.
+- reg-names: Must include the following entries:
+  - "pmc"
+  - "wake"
+  - "aotag"
+  - "scratch"
+
+Optional properties:
+- nvidia,invert-interrupt: If present, inverts the PMU interrupt signal.
+
+Example:
+
+SoC DTSI:
+
+	pmc@c3600000 {
+		compatible = "nvidia,tegra186-pmc";
+		reg = <0 0x0c360000 0 0x10000>,
+		      <0 0x0c370000 0 0x10000>,
+		      <0 0x0c380000 0 0x10000>,
+		      <0 0x0c390000 0 0x10000>;
+		reg-names = "pmc", "wake", "aotag", "scratch";
+	};
+
+Board DTS:
+
+	pmc@c360000 {
+		nvidia,invert-interrupt;
+	};

+ 0 - 1
arch/arm/mach-tegra/Makefile

@@ -2,7 +2,6 @@ asflags-y				+= -march=armv7-a
 
 
 obj-y                                   += io.o
 obj-y                                   += io.o
 obj-y                                   += irq.o
 obj-y                                   += irq.o
-obj-y					+= flowctrl.o
 obj-y					+= pm.o
 obj-y					+= pm.o
 obj-y					+= reset.o
 obj-y					+= reset.o
 obj-y					+= reset-handler.o
 obj-y					+= reset-handler.o

+ 2 - 1
arch/arm/mach-tegra/cpuidle-tegra20.c

@@ -26,12 +26,13 @@
 #include <linux/kernel.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/module.h>
 
 
+#include <soc/tegra/flowctrl.h>
+
 #include <asm/cpuidle.h>
 #include <asm/cpuidle.h>
 #include <asm/smp_plat.h>
 #include <asm/smp_plat.h>
 #include <asm/suspend.h>
 #include <asm/suspend.h>
 
 
 #include "cpuidle.h"
 #include "cpuidle.h"
-#include "flowctrl.h"
 #include "iomap.h"
 #include "iomap.h"
 #include "irq.h"
 #include "irq.h"
 #include "pm.h"
 #include "pm.h"

+ 1 - 1
arch/arm/mach-tegra/platsmp.c

@@ -21,6 +21,7 @@
 #include <linux/jiffies.h>
 #include <linux/jiffies.h>
 #include <linux/smp.h>
 #include <linux/smp.h>
 
 
+#include <soc/tegra/flowctrl.h>
 #include <soc/tegra/fuse.h>
 #include <soc/tegra/fuse.h>
 #include <soc/tegra/pmc.h>
 #include <soc/tegra/pmc.h>
 
 
@@ -30,7 +31,6 @@
 #include <asm/smp_scu.h>
 #include <asm/smp_scu.h>
 
 
 #include "common.h"
 #include "common.h"
-#include "flowctrl.h"
 #include "iomap.h"
 #include "iomap.h"
 #include "reset.h"
 #include "reset.h"
 
 

+ 1 - 1
arch/arm/mach-tegra/pm.c

@@ -27,6 +27,7 @@
 #include <linux/spinlock.h>
 #include <linux/spinlock.h>
 #include <linux/suspend.h>
 #include <linux/suspend.h>
 
 
+#include <soc/tegra/flowctrl.h>
 #include <soc/tegra/fuse.h>
 #include <soc/tegra/fuse.h>
 #include <soc/tegra/pm.h>
 #include <soc/tegra/pm.h>
 #include <soc/tegra/pmc.h>
 #include <soc/tegra/pmc.h>
@@ -38,7 +39,6 @@
 #include <asm/suspend.h>
 #include <asm/suspend.h>
 #include <asm/tlbflush.h>
 #include <asm/tlbflush.h>
 
 
-#include "flowctrl.h"
 #include "iomap.h"
 #include "iomap.h"
 #include "pm.h"
 #include "pm.h"
 #include "reset.h"
 #include "reset.h"

+ 1 - 1
arch/arm/mach-tegra/reset-handler.S

@@ -17,12 +17,12 @@
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/linkage.h>
 #include <linux/linkage.h>
 
 
+#include <soc/tegra/flowctrl.h>
 #include <soc/tegra/fuse.h>
 #include <soc/tegra/fuse.h>
 
 
 #include <asm/asm-offsets.h>
 #include <asm/asm-offsets.h>
 #include <asm/cache.h>
 #include <asm/cache.h>
 
 
-#include "flowctrl.h"
 #include "iomap.h"
 #include "iomap.h"
 #include "reset.h"
 #include "reset.h"
 #include "sleep.h"
 #include "sleep.h"

+ 2 - 1
arch/arm/mach-tegra/sleep-tegra20.S

@@ -20,6 +20,8 @@
 
 
 #include <linux/linkage.h>
 #include <linux/linkage.h>
 
 
+#include <soc/tegra/flowctrl.h>
+
 #include <asm/assembler.h>
 #include <asm/assembler.h>
 #include <asm/proc-fns.h>
 #include <asm/proc-fns.h>
 #include <asm/cp15.h>
 #include <asm/cp15.h>
@@ -27,7 +29,6 @@
 
 
 #include "irammap.h"
 #include "irammap.h"
 #include "sleep.h"
 #include "sleep.h"
-#include "flowctrl.h"
 
 
 #define EMC_CFG				0xc
 #define EMC_CFG				0xc
 #define EMC_ADR_CFG			0x10
 #define EMC_ADR_CFG			0x10

+ 1 - 1
arch/arm/mach-tegra/sleep-tegra30.S

@@ -16,13 +16,13 @@
 
 
 #include <linux/linkage.h>
 #include <linux/linkage.h>
 
 
+#include <soc/tegra/flowctrl.h>
 #include <soc/tegra/fuse.h>
 #include <soc/tegra/fuse.h>
 
 
 #include <asm/asm-offsets.h>
 #include <asm/asm-offsets.h>
 #include <asm/assembler.h>
 #include <asm/assembler.h>
 #include <asm/cache.h>
 #include <asm/cache.h>
 
 
-#include "flowctrl.h"
 #include "irammap.h"
 #include "irammap.h"
 #include "sleep.h"
 #include "sleep.h"
 
 

+ 0 - 2
arch/arm/mach-tegra/sleep.S

@@ -30,8 +30,6 @@
 #include <asm/hardware/cache-l2x0.h>
 #include <asm/hardware/cache-l2x0.h>
 
 
 #include "iomap.h"
 #include "iomap.h"
-
-#include "flowctrl.h"
 #include "sleep.h"
 #include "sleep.h"
 
 
 #define CLK_RESET_CCLK_BURST	0x20
 #define CLK_RESET_CCLK_BURST	0x20

+ 0 - 2
arch/arm/mach-tegra/tegra.c

@@ -48,7 +48,6 @@
 #include "board.h"
 #include "board.h"
 #include "common.h"
 #include "common.h"
 #include "cpuidle.h"
 #include "cpuidle.h"
-#include "flowctrl.h"
 #include "iomap.h"
 #include "iomap.h"
 #include "irq.h"
 #include "irq.h"
 #include "pm.h"
 #include "pm.h"
@@ -75,7 +74,6 @@ static void __init tegra_init_early(void)
 {
 {
 	of_register_trusted_foundations();
 	of_register_trusted_foundations();
 	tegra_cpu_reset_handler_init();
 	tegra_cpu_reset_handler_init();
-	tegra_flowctrl_init();
 }
 }
 
 
 static void __init tegra_dt_init_irq(void)
 static void __init tegra_dt_init_irq(void)

+ 22 - 0
drivers/soc/tegra/Kconfig

@@ -12,6 +12,8 @@ config ARCH_TEGRA_2x_SOC
 	select PINCTRL_TEGRA20
 	select PINCTRL_TEGRA20
 	select PL310_ERRATA_727915 if CACHE_L2X0
 	select PL310_ERRATA_727915 if CACHE_L2X0
 	select PL310_ERRATA_769419 if CACHE_L2X0
 	select PL310_ERRATA_769419 if CACHE_L2X0
+	select SOC_TEGRA_FLOWCTRL
+	select SOC_TEGRA_PMC
 	select TEGRA_TIMER
 	select TEGRA_TIMER
 	help
 	help
 	  Support for NVIDIA Tegra AP20 and T20 processors, based on the
 	  Support for NVIDIA Tegra AP20 and T20 processors, based on the
@@ -23,6 +25,8 @@ config ARCH_TEGRA_3x_SOC
 	select ARM_ERRATA_764369 if SMP
 	select ARM_ERRATA_764369 if SMP
 	select PINCTRL_TEGRA30
 	select PINCTRL_TEGRA30
 	select PL310_ERRATA_769419 if CACHE_L2X0
 	select PL310_ERRATA_769419 if CACHE_L2X0
+	select SOC_TEGRA_FLOWCTRL
+	select SOC_TEGRA_PMC
 	select TEGRA_TIMER
 	select TEGRA_TIMER
 	help
 	help
 	  Support for NVIDIA Tegra T30 processor family, based on the
 	  Support for NVIDIA Tegra T30 processor family, based on the
@@ -33,6 +37,8 @@ config ARCH_TEGRA_114_SOC
 	select ARM_ERRATA_798181 if SMP
 	select ARM_ERRATA_798181 if SMP
 	select HAVE_ARM_ARCH_TIMER
 	select HAVE_ARM_ARCH_TIMER
 	select PINCTRL_TEGRA114
 	select PINCTRL_TEGRA114
+	select SOC_TEGRA_FLOWCTRL
+	select SOC_TEGRA_PMC
 	select TEGRA_TIMER
 	select TEGRA_TIMER
 	help
 	help
 	  Support for NVIDIA Tegra T114 processor family, based on the
 	  Support for NVIDIA Tegra T114 processor family, based on the
@@ -42,6 +48,8 @@ config ARCH_TEGRA_124_SOC
 	bool "Enable support for Tegra124 family"
 	bool "Enable support for Tegra124 family"
 	select HAVE_ARM_ARCH_TIMER
 	select HAVE_ARM_ARCH_TIMER
 	select PINCTRL_TEGRA124
 	select PINCTRL_TEGRA124
+	select SOC_TEGRA_FLOWCTRL
+	select SOC_TEGRA_PMC
 	select TEGRA_TIMER
 	select TEGRA_TIMER
 	help
 	help
 	  Support for NVIDIA Tegra T124 processor family, based on the
 	  Support for NVIDIA Tegra T124 processor family, based on the
@@ -55,6 +63,8 @@ if ARM64
 config ARCH_TEGRA_132_SOC
 config ARCH_TEGRA_132_SOC
 	bool "NVIDIA Tegra132 SoC"
 	bool "NVIDIA Tegra132 SoC"
 	select PINCTRL_TEGRA124
 	select PINCTRL_TEGRA124
+	select SOC_TEGRA_FLOWCTRL
+	select SOC_TEGRA_PMC
 	help
 	help
 	  Enable support for NVIDIA Tegra132 SoC, based on the Denver
 	  Enable support for NVIDIA Tegra132 SoC, based on the Denver
 	  ARMv8 CPU.  The Tegra132 SoC is similar to the Tegra124 SoC,
 	  ARMv8 CPU.  The Tegra132 SoC is similar to the Tegra124 SoC,
@@ -64,6 +74,8 @@ config ARCH_TEGRA_132_SOC
 config ARCH_TEGRA_210_SOC
 config ARCH_TEGRA_210_SOC
 	bool "NVIDIA Tegra210 SoC"
 	bool "NVIDIA Tegra210 SoC"
 	select PINCTRL_TEGRA210
 	select PINCTRL_TEGRA210
+	select SOC_TEGRA_FLOWCTRL
+	select SOC_TEGRA_PMC
 	help
 	help
 	  Enable support for the NVIDIA Tegra210 SoC. Also known as Tegra X1,
 	  Enable support for the NVIDIA Tegra210 SoC. Also known as Tegra X1,
 	  the Tegra210 has four Cortex-A57 cores paired with four Cortex-A53
 	  the Tegra210 has four Cortex-A57 cores paired with four Cortex-A53
@@ -83,6 +95,7 @@ config ARCH_TEGRA_186_SOC
 	select TEGRA_BPMP
 	select TEGRA_BPMP
 	select TEGRA_HSP_MBOX
 	select TEGRA_HSP_MBOX
 	select TEGRA_IVC
 	select TEGRA_IVC
+	select SOC_TEGRA_PMC_TEGRA186
 	help
 	help
 	  Enable support for the NVIDIA Tegar186 SoC. The Tegra186 features a
 	  Enable support for the NVIDIA Tegar186 SoC. The Tegra186 features a
 	  combination of Denver and Cortex-A57 CPU cores and a GPU based on
 	  combination of Denver and Cortex-A57 CPU cores and a GPU based on
@@ -93,3 +106,12 @@ config ARCH_TEGRA_186_SOC
 
 
 endif
 endif
 endif
 endif
+
+config SOC_TEGRA_FLOWCTRL
+	bool
+
+config SOC_TEGRA_PMC
+	bool
+
+config SOC_TEGRA_PMC_TEGRA186
+	bool

+ 3 - 1
drivers/soc/tegra/Makefile

@@ -1,4 +1,6 @@
 obj-y += fuse/
 obj-y += fuse/
 
 
 obj-y += common.o
 obj-y += common.o
-obj-y += pmc.o
+obj-$(CONFIG_SOC_TEGRA_FLOWCTRL) += flowctrl.o
+obj-$(CONFIG_SOC_TEGRA_PMC) += pmc.o
+obj-$(CONFIG_SOC_TEGRA_PMC_TEGRA186) += pmc-tegra186.o

+ 70 - 17
arch/arm/mach-tegra/flowctrl.c → drivers/soc/tegra/flowctrl.c

@@ -1,7 +1,7 @@
 /*
 /*
- * arch/arm/mach-tegra/flowctrl.c
+ * drivers/soc/tegra/flowctrl.c
  *
  *
- * functions and macros to control the flowcontroller
+ * Functions and macros to control the flowcontroller
  *
  *
  * Copyright (c) 2010-2012, NVIDIA Corporation. All rights reserved.
  * Copyright (c) 2010-2012, NVIDIA Corporation. All rights reserved.
  *
  *
@@ -24,11 +24,12 @@
 #include <linux/kernel.h>
 #include <linux/kernel.h>
 #include <linux/of.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_address.h>
+#include <linux/platform_device.h>
 
 
+#include <soc/tegra/common.h>
+#include <soc/tegra/flowctrl.h>
 #include <soc/tegra/fuse.h>
 #include <soc/tegra/fuse.h>
 
 
-#include "flowctrl.h"
-
 static u8 flowctrl_offset_halt_cpu[] = {
 static u8 flowctrl_offset_halt_cpu[] = {
 	FLOW_CTRL_HALT_CPU0_EVENTS,
 	FLOW_CTRL_HALT_CPU0_EVENTS,
 	FLOW_CTRL_HALT_CPU1_EVENTS,
 	FLOW_CTRL_HALT_CPU1_EVENTS,
@@ -47,6 +48,10 @@ static void __iomem *tegra_flowctrl_base;
 
 
 static void flowctrl_update(u8 offset, u32 value)
 static void flowctrl_update(u8 offset, u32 value)
 {
 {
+	if (WARN_ONCE(IS_ERR_OR_NULL(tegra_flowctrl_base),
+		      "Tegra flowctrl not initialised!\n"))
+		return;
+
 	writel(value, tegra_flowctrl_base + offset);
 	writel(value, tegra_flowctrl_base + offset);
 
 
 	/* ensure the update has reached the flow controller */
 	/* ensure the update has reached the flow controller */
@@ -58,6 +63,10 @@ u32 flowctrl_read_cpu_csr(unsigned int cpuid)
 {
 {
 	u8 offset = flowctrl_offset_cpu_csr[cpuid];
 	u8 offset = flowctrl_offset_cpu_csr[cpuid];
 
 
+	if (WARN_ONCE(IS_ERR_OR_NULL(tegra_flowctrl_base),
+		      "Tegra flowctrl not initialised!\n"))
+		return 0;
+
 	return readl(tegra_flowctrl_base + offset);
 	return readl(tegra_flowctrl_base + offset);
 }
 }
 
 
@@ -140,7 +149,23 @@ void flowctrl_cpu_suspend_exit(unsigned int cpuid)
 	flowctrl_write_cpu_csr(cpuid, reg);
 	flowctrl_write_cpu_csr(cpuid, reg);
 }
 }
 
 
-static const struct of_device_id matches[] __initconst = {
+static int tegra_flowctrl_probe(struct platform_device *pdev)
+{
+	void __iomem *base = tegra_flowctrl_base;
+	struct resource *res;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	tegra_flowctrl_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(tegra_flowctrl_base))
+		return PTR_ERR(base);
+
+	iounmap(base);
+
+	return 0;
+}
+
+static const struct of_device_id tegra_flowctrl_match[] = {
+	{ .compatible = "nvidia,tegra210-flowctrl" },
 	{ .compatible = "nvidia,tegra124-flowctrl" },
 	{ .compatible = "nvidia,tegra124-flowctrl" },
 	{ .compatible = "nvidia,tegra114-flowctrl" },
 	{ .compatible = "nvidia,tegra114-flowctrl" },
 	{ .compatible = "nvidia,tegra30-flowctrl" },
 	{ .compatible = "nvidia,tegra30-flowctrl" },
@@ -148,24 +173,52 @@ static const struct of_device_id matches[] __initconst = {
 	{ }
 	{ }
 };
 };
 
 
-void __init tegra_flowctrl_init(void)
+static struct platform_driver tegra_flowctrl_driver = {
+	.driver = {
+		.name = "tegra-flowctrl",
+		.suppress_bind_attrs = true,
+		.of_match_table = tegra_flowctrl_match,
+	},
+	.probe = tegra_flowctrl_probe,
+};
+builtin_platform_driver(tegra_flowctrl_driver);
+
+static int __init tegra_flowctrl_init(void)
 {
 {
-	/* hardcoded fallback if device tree node is missing */
-	unsigned long base = 0x60007000;
-	unsigned long size = SZ_4K;
+	struct resource res;
 	struct device_node *np;
 	struct device_node *np;
 
 
-	np = of_find_matching_node(NULL, matches);
-	if (np) {
-		struct resource res;
+	if (!soc_is_tegra())
+		return 0;
 
 
-		if (of_address_to_resource(np, 0, &res) == 0) {
-			size = resource_size(&res);
-			base = res.start;
+	np = of_find_matching_node(NULL, tegra_flowctrl_match);
+	if (np) {
+		if (of_address_to_resource(np, 0, &res) < 0) {
+			pr_err("failed to get flowctrl register\n");
+			return -ENXIO;
 		}
 		}
-
 		of_node_put(np);
 		of_node_put(np);
+	} else if (IS_ENABLED(CONFIG_ARM)) {
+		/*
+		 * Hardcoded fallback for 32-bit Tegra
+		 * devices if device tree node is missing.
+		 */
+		res.start = 0x60007000;
+		res.end = 0x60007fff;
+		res.flags = IORESOURCE_MEM;
+	} else {
+		/*
+		 * At this point we're running on a Tegra,
+		 * that doesn't support the flow controller
+		 * (eg. Tegra186), so just return.
+		 */
+		return 0;
 	}
 	}
 
 
-	tegra_flowctrl_base = ioremap_nocache(base, size);
+	tegra_flowctrl_base = ioremap_nocache(res.start, resource_size(&res));
+	if (!tegra_flowctrl_base)
+		return -ENXIO;
+
+	return 0;
 }
 }
+early_initcall(tegra_flowctrl_init);

+ 2 - 2
drivers/soc/tegra/fuse/fuse-tegra.c

@@ -18,7 +18,7 @@
 #include <linux/clk.h>
 #include <linux/clk.h>
 #include <linux/device.h>
 #include <linux/device.h>
 #include <linux/kobject.h>
 #include <linux/kobject.h>
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/of.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_address.h>
@@ -168,7 +168,7 @@ static struct platform_driver tegra_fuse_driver = {
 	},
 	},
 	.probe = tegra_fuse_probe,
 	.probe = tegra_fuse_probe,
 };
 };
-module_platform_driver(tegra_fuse_driver);
+builtin_platform_driver(tegra_fuse_driver);
 
 
 bool __init tegra_fuse_read_spare(unsigned int spare)
 bool __init tegra_fuse_read_spare(unsigned int spare)
 {
 {

+ 169 - 0
drivers/soc/tegra/pmc-tegra186.c

@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+#define pr_fmt(fmt) "tegra-pmc: " fmt
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/reboot.h>
+
+#include <asm/system_misc.h>
+
+#define PMC_CNTRL 0x000
+#define  PMC_CNTRL_MAIN_RST BIT(4)
+
+#define PMC_RST_STATUS 0x070
+
+#define WAKE_AOWAKE_CTRL 0x4f4
+#define  WAKE_AOWAKE_CTRL_INTR_POLARITY BIT(0)
+
+#define SCRATCH_SCRATCH0 0x2000
+#define  SCRATCH_SCRATCH0_MODE_RECOVERY BIT(31)
+#define  SCRATCH_SCRATCH0_MODE_BOOTLOADER BIT(30)
+#define  SCRATCH_SCRATCH0_MODE_RCM BIT(1)
+#define  SCRATCH_SCRATCH0_MODE_MASK (SCRATCH_SCRATCH0_MODE_RECOVERY | \
+				     SCRATCH_SCRATCH0_MODE_BOOTLOADER | \
+				     SCRATCH_SCRATCH0_MODE_RCM)
+
+struct tegra_pmc {
+	struct device *dev;
+	void __iomem *regs;
+	void __iomem *wake;
+	void __iomem *aotag;
+	void __iomem *scratch;
+
+	void (*system_restart)(enum reboot_mode mode, const char *cmd);
+	struct notifier_block restart;
+};
+
+static int tegra186_pmc_restart_notify(struct notifier_block *nb,
+				       unsigned long action,
+				       void *data)
+{
+	struct tegra_pmc *pmc = container_of(nb, struct tegra_pmc, restart);
+	const char *cmd = data;
+	u32 value;
+
+	value = readl(pmc->scratch + SCRATCH_SCRATCH0);
+	value &= ~SCRATCH_SCRATCH0_MODE_MASK;
+
+	if (cmd) {
+		if (strcmp(cmd, "recovery") == 0)
+			value |= SCRATCH_SCRATCH0_MODE_RECOVERY;
+
+		if (strcmp(cmd, "bootloader") == 0)
+			value |= SCRATCH_SCRATCH0_MODE_BOOTLOADER;
+
+		if (strcmp(cmd, "forced-recovery") == 0)
+			value |= SCRATCH_SCRATCH0_MODE_RCM;
+	}
+
+	writel(value, pmc->scratch + SCRATCH_SCRATCH0);
+
+	/*
+	 * If available, call the system restart implementation that was
+	 * registered earlier (typically PSCI).
+	 */
+	if (pmc->system_restart) {
+		pmc->system_restart(reboot_mode, cmd);
+		return NOTIFY_DONE;
+	}
+
+	/* reset everything but SCRATCH0_SCRATCH0 and PMC_RST_STATUS */
+	value = readl(pmc->regs + PMC_CNTRL);
+	value |= PMC_CNTRL_MAIN_RST;
+	writel(value, pmc->regs + PMC_CNTRL);
+
+	return NOTIFY_DONE;
+}
+
+static int tegra186_pmc_setup(struct tegra_pmc *pmc)
+{
+	struct device_node *np = pmc->dev->of_node;
+	bool invert;
+	u32 value;
+
+	invert = of_property_read_bool(np, "nvidia,invert-interrupt");
+
+	value = readl(pmc->wake + WAKE_AOWAKE_CTRL);
+
+	if (invert)
+		value |= WAKE_AOWAKE_CTRL_INTR_POLARITY;
+	else
+		value &= ~WAKE_AOWAKE_CTRL_INTR_POLARITY;
+
+	writel(value, pmc->wake + WAKE_AOWAKE_CTRL);
+
+	/*
+	 * We need to hook any system restart implementation registered
+	 * previously so we can write SCRATCH_SCRATCH0 before reset.
+	 */
+	pmc->system_restart = arm_pm_restart;
+	arm_pm_restart = NULL;
+
+	pmc->restart.notifier_call = tegra186_pmc_restart_notify;
+	pmc->restart.priority = 128;
+
+	return register_restart_handler(&pmc->restart);
+}
+
+static int tegra186_pmc_probe(struct platform_device *pdev)
+{
+	struct tegra_pmc *pmc;
+	struct resource *res;
+
+	pmc = devm_kzalloc(&pdev->dev, sizeof(*pmc), GFP_KERNEL);
+	if (!pmc)
+		return -ENOMEM;
+
+	pmc->dev = &pdev->dev;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pmc");
+	pmc->regs = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(pmc->regs))
+		return PTR_ERR(pmc->regs);
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "wake");
+	pmc->wake = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(pmc->wake))
+		return PTR_ERR(pmc->wake);
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "aotag");
+	pmc->aotag = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(pmc->aotag))
+		return PTR_ERR(pmc->aotag);
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "scratch");
+	pmc->scratch = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(pmc->scratch))
+		return PTR_ERR(pmc->scratch);
+
+	return tegra186_pmc_setup(pmc);
+}
+
+static const struct of_device_id tegra186_pmc_of_match[] = {
+	{ .compatible = "nvidia,tegra186-pmc" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, tegra186_pmc_of_match);
+
+static struct platform_driver tegra186_pmc_driver = {
+	.driver = {
+		.name = "tegra186-pmc",
+		.of_match_table = tegra186_pmc_of_match,
+	},
+	.probe = tegra186_pmc_probe,
+};
+builtin_platform_driver(tegra186_pmc_driver);

+ 24 - 8
arch/arm/mach-tegra/flowctrl.h → include/soc/tegra/flowctrl.h

@@ -1,7 +1,5 @@
 /*
 /*
- * arch/arm/mach-tegra/flowctrl.h
- *
- * functions and macros to control the flowcontroller
+ * Functions and macros to control the flowcontroller
  *
  *
  * Copyright (c) 2010-2012, NVIDIA Corporation. All rights reserved.
  * Copyright (c) 2010-2012, NVIDIA Corporation. All rights reserved.
  *
  *
@@ -18,8 +16,8 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
  */
 
 
-#ifndef __MACH_TEGRA_FLOWCTRL_H
-#define __MACH_TEGRA_FLOWCTRL_H
+#ifndef __SOC_TEGRA_FLOWCTRL_H__
+#define __SOC_TEGRA_FLOWCTRL_H__
 
 
 #define FLOW_CTRL_HALT_CPU0_EVENTS	0x0
 #define FLOW_CTRL_HALT_CPU0_EVENTS	0x0
 #define FLOW_CTRL_WAITEVENT		(2 << 29)
 #define FLOW_CTRL_WAITEVENT		(2 << 29)
@@ -53,14 +51,32 @@
 #define TEGRA30_FLOW_CTRL_CSR_WFI_BITMAP	(0xF << 8)
 #define TEGRA30_FLOW_CTRL_CSR_WFI_BITMAP	(0xF << 8)
 
 
 #ifndef __ASSEMBLY__
 #ifndef __ASSEMBLY__
+#ifdef CONFIG_SOC_TEGRA_FLOWCTRL
 u32 flowctrl_read_cpu_csr(unsigned int cpuid);
 u32 flowctrl_read_cpu_csr(unsigned int cpuid);
 void flowctrl_write_cpu_csr(unsigned int cpuid, u32 value);
 void flowctrl_write_cpu_csr(unsigned int cpuid, u32 value);
 void flowctrl_write_cpu_halt(unsigned int cpuid, u32 value);
 void flowctrl_write_cpu_halt(unsigned int cpuid, u32 value);
 
 
 void flowctrl_cpu_suspend_enter(unsigned int cpuid);
 void flowctrl_cpu_suspend_enter(unsigned int cpuid);
 void flowctrl_cpu_suspend_exit(unsigned int cpuid);
 void flowctrl_cpu_suspend_exit(unsigned int cpuid);
+#else
+static inline u32 flowctrl_read_cpu_csr(unsigned int cpuid)
+{
+	return 0;
+}
+
+static inline void flowctrl_write_cpu_csr(unsigned int cpuid, u32 value)
+{
+}
+
+static inline void flowctrl_write_cpu_halt(unsigned int cpuid, u32 value) {}
 
 
-void tegra_flowctrl_init(void);
-#endif
+static inline void flowctrl_cpu_suspend_enter(unsigned int cpuid)
+{
+}
 
 
-#endif
+static inline void flowctrl_cpu_suspend_exit(unsigned int cpuid)
+{
+}
+#endif /* CONFIG_SOC_TEGRA_FLOWCTRL */
+#endif /* __ASSEMBLY */
+#endif /* __SOC_TEGRA_FLOWCTRL_H__ */

+ 21 - 8
include/soc/tegra/pmc.h

@@ -26,12 +26,6 @@
 struct clk;
 struct clk;
 struct reset_control;
 struct reset_control;
 
 
-#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);
-#endif /* CONFIG_PM_SLEEP */
-
 #ifdef CONFIG_SMP
 #ifdef CONFIG_SMP
 bool tegra_pmc_cpu_is_powered(unsigned int cpuid);
 bool tegra_pmc_cpu_is_powered(unsigned int cpuid);
 int tegra_pmc_cpu_power_on(unsigned int cpuid);
 int tegra_pmc_cpu_power_on(unsigned int cpuid);
@@ -144,7 +138,7 @@ enum tegra_io_pad_voltage {
 	TEGRA_IO_PAD_3300000UV,
 	TEGRA_IO_PAD_3300000UV,
 };
 };
 
 
-#ifdef CONFIG_ARCH_TEGRA
+#ifdef CONFIG_SOC_TEGRA_PMC
 int tegra_powergate_is_powered(unsigned int id);
 int tegra_powergate_is_powered(unsigned int id);
 int tegra_powergate_power_on(unsigned int id);
 int tegra_powergate_power_on(unsigned int id);
 int tegra_powergate_power_off(unsigned int id);
 int tegra_powergate_power_off(unsigned int id);
@@ -163,6 +157,11 @@ int tegra_io_pad_get_voltage(enum tegra_io_pad id);
 /* deprecated, use tegra_io_pad_power_{enable,disable}() instead */
 /* deprecated, use tegra_io_pad_power_{enable,disable}() instead */
 int tegra_io_rail_power_on(unsigned int id);
 int tegra_io_rail_power_on(unsigned int id);
 int tegra_io_rail_power_off(unsigned int id);
 int tegra_io_rail_power_off(unsigned int id);
+
+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);
+
 #else
 #else
 static inline int tegra_powergate_is_powered(unsigned int id)
 static inline int tegra_powergate_is_powered(unsigned int id)
 {
 {
@@ -221,6 +220,20 @@ static inline int tegra_io_rail_power_off(unsigned int id)
 {
 {
 	return -ENOSYS;
 	return -ENOSYS;
 }
 }
-#endif /* CONFIG_ARCH_TEGRA */
+
+static inline enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void)
+{
+	return TEGRA_SUSPEND_NONE;
+}
+
+static inline void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode)
+{
+}
+
+static inline void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode)
+{
+}
+
+#endif /* CONFIG_SOC_TEGRA_PMC */
 
 
 #endif /* __SOC_TEGRA_PMC_H__ */
 #endif /* __SOC_TEGRA_PMC_H__ */