aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThierry Reding <treding@nvidia.com>2017-02-23 12:11:57 -0500
committerThierry Reding <treding@nvidia.com>2017-04-04 09:43:50 -0400
commit5e7d4c65294174d6f58fe36df3edd55cd3b859d6 (patch)
treeebdf2ddfd0f345b671a3d803155de6ad81657987
parentc1ae3cfa0e89fa1a7ecc4c99031f5e9ae99d9201 (diff)
soc/tegra: Implement Tegra186 PMC support
The power management controller on Tegra186 has changed in backwards- incompatible ways with respect to earlier generations. This implements a new driver that supports inversion of the PMU interrupt as well as the "recovery", "bootloader" and "forced-recovery" reboot commands. Acked-by: Rob Herring <robh@kernel.org> Signed-off-by: Thierry Reding <treding@nvidia.com>
-rw-r--r--Documentation/devicetree/bindings/arm/tegra/nvidia,tegra186-pmc.txt34
-rw-r--r--drivers/soc/tegra/Kconfig13
-rw-r--r--drivers/soc/tegra/Makefile3
-rw-r--r--drivers/soc/tegra/pmc-tegra186.c169
4 files changed, 218 insertions, 1 deletions
diff --git a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra186-pmc.txt b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra186-pmc.txt
new file mode 100644
index 000000000000..078a58b0302f
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra186-pmc.txt
@@ -0,0 +1,34 @@
1NVIDIA Tegra Power Management Controller (PMC)
2
3Required properties:
4- compatible: Should contain one of the following:
5 - "nvidia,tegra186-pmc": for Tegra186
6- reg: Must contain an (offset, length) pair of the register set for each
7 entry in reg-names.
8- reg-names: Must include the following entries:
9 - "pmc"
10 - "wake"
11 - "aotag"
12 - "scratch"
13
14Optional properties:
15- nvidia,invert-interrupt: If present, inverts the PMU interrupt signal.
16
17Example:
18
19SoC DTSI:
20
21 pmc@c3600000 {
22 compatible = "nvidia,tegra186-pmc";
23 reg = <0 0x0c360000 0 0x10000>,
24 <0 0x0c370000 0 0x10000>,
25 <0 0x0c380000 0 0x10000>,
26 <0 0x0c390000 0 0x10000>;
27 reg-names = "pmc", "wake", "aotag", "scratch";
28 };
29
30Board DTS:
31
32 pmc@c360000 {
33 nvidia,invert-interrupt;
34 };
diff --git a/drivers/soc/tegra/Kconfig b/drivers/soc/tegra/Kconfig
index e5e124c07066..208d6edb3fdb 100644
--- a/drivers/soc/tegra/Kconfig
+++ b/drivers/soc/tegra/Kconfig
@@ -12,6 +12,7 @@ config ARCH_TEGRA_2x_SOC
12 select PINCTRL_TEGRA20 12 select PINCTRL_TEGRA20
13 select PL310_ERRATA_727915 if CACHE_L2X0 13 select PL310_ERRATA_727915 if CACHE_L2X0
14 select PL310_ERRATA_769419 if CACHE_L2X0 14 select PL310_ERRATA_769419 if CACHE_L2X0
15 select SOC_TEGRA_PMC
15 select TEGRA_TIMER 16 select TEGRA_TIMER
16 help 17 help
17 Support for NVIDIA Tegra AP20 and T20 processors, based on the 18 Support for NVIDIA Tegra AP20 and T20 processors, based on the
@@ -23,6 +24,7 @@ config ARCH_TEGRA_3x_SOC
23 select ARM_ERRATA_764369 if SMP 24 select ARM_ERRATA_764369 if SMP
24 select PINCTRL_TEGRA30 25 select PINCTRL_TEGRA30
25 select PL310_ERRATA_769419 if CACHE_L2X0 26 select PL310_ERRATA_769419 if CACHE_L2X0
27 select SOC_TEGRA_PMC
26 select TEGRA_TIMER 28 select TEGRA_TIMER
27 help 29 help
28 Support for NVIDIA Tegra T30 processor family, based on the 30 Support for NVIDIA Tegra T30 processor family, based on the
@@ -33,6 +35,7 @@ config ARCH_TEGRA_114_SOC
33 select ARM_ERRATA_798181 if SMP 35 select ARM_ERRATA_798181 if SMP
34 select HAVE_ARM_ARCH_TIMER 36 select HAVE_ARM_ARCH_TIMER
35 select PINCTRL_TEGRA114 37 select PINCTRL_TEGRA114
38 select SOC_TEGRA_PMC
36 select TEGRA_TIMER 39 select TEGRA_TIMER
37 help 40 help
38 Support for NVIDIA Tegra T114 processor family, based on the 41 Support for NVIDIA Tegra T114 processor family, based on the
@@ -42,6 +45,7 @@ config ARCH_TEGRA_124_SOC
42 bool "Enable support for Tegra124 family" 45 bool "Enable support for Tegra124 family"
43 select HAVE_ARM_ARCH_TIMER 46 select HAVE_ARM_ARCH_TIMER
44 select PINCTRL_TEGRA124 47 select PINCTRL_TEGRA124
48 select SOC_TEGRA_PMC
45 select TEGRA_TIMER 49 select TEGRA_TIMER
46 help 50 help
47 Support for NVIDIA Tegra T124 processor family, based on the 51 Support for NVIDIA Tegra T124 processor family, based on the
@@ -55,6 +59,7 @@ if ARM64
55config ARCH_TEGRA_132_SOC 59config ARCH_TEGRA_132_SOC
56 bool "NVIDIA Tegra132 SoC" 60 bool "NVIDIA Tegra132 SoC"
57 select PINCTRL_TEGRA124 61 select PINCTRL_TEGRA124
62 select SOC_TEGRA_PMC
58 help 63 help
59 Enable support for NVIDIA Tegra132 SoC, based on the Denver 64 Enable support for NVIDIA Tegra132 SoC, based on the Denver
60 ARMv8 CPU. The Tegra132 SoC is similar to the Tegra124 SoC, 65 ARMv8 CPU. The Tegra132 SoC is similar to the Tegra124 SoC,
@@ -64,6 +69,7 @@ config ARCH_TEGRA_132_SOC
64config ARCH_TEGRA_210_SOC 69config ARCH_TEGRA_210_SOC
65 bool "NVIDIA Tegra210 SoC" 70 bool "NVIDIA Tegra210 SoC"
66 select PINCTRL_TEGRA210 71 select PINCTRL_TEGRA210
72 select SOC_TEGRA_PMC
67 help 73 help
68 Enable support for the NVIDIA Tegra210 SoC. Also known as Tegra X1, 74 Enable support for the NVIDIA Tegra210 SoC. Also known as Tegra X1,
69 the Tegra210 has four Cortex-A57 cores paired with four Cortex-A53 75 the Tegra210 has four Cortex-A57 cores paired with four Cortex-A53
@@ -83,6 +89,7 @@ config ARCH_TEGRA_186_SOC
83 select TEGRA_BPMP 89 select TEGRA_BPMP
84 select TEGRA_HSP_MBOX 90 select TEGRA_HSP_MBOX
85 select TEGRA_IVC 91 select TEGRA_IVC
92 select SOC_TEGRA_PMC_TEGRA186
86 help 93 help
87 Enable support for the NVIDIA Tegar186 SoC. The Tegra186 features a 94 Enable support for the NVIDIA Tegar186 SoC. The Tegra186 features a
88 combination of Denver and Cortex-A57 CPU cores and a GPU based on 95 combination of Denver and Cortex-A57 CPU cores and a GPU based on
@@ -93,3 +100,9 @@ config ARCH_TEGRA_186_SOC
93 100
94endif 101endif
95endif 102endif
103
104config SOC_TEGRA_PMC
105 bool
106
107config SOC_TEGRA_PMC_TEGRA186
108 bool
diff --git a/drivers/soc/tegra/Makefile b/drivers/soc/tegra/Makefile
index ae857ff7d53d..b4425e4319ff 100644
--- a/drivers/soc/tegra/Makefile
+++ b/drivers/soc/tegra/Makefile
@@ -1,4 +1,5 @@
1obj-y += fuse/ 1obj-y += fuse/
2 2
3obj-y += common.o 3obj-y += common.o
4obj-y += pmc.o 4obj-$(CONFIG_SOC_TEGRA_PMC) += pmc.o
5obj-$(CONFIG_SOC_TEGRA_PMC_TEGRA186) += pmc-tegra186.o
diff --git a/drivers/soc/tegra/pmc-tegra186.c b/drivers/soc/tegra/pmc-tegra186.c
new file mode 100644
index 000000000000..6f5c6f98ba92
--- /dev/null
+++ b/drivers/soc/tegra/pmc-tegra186.c
@@ -0,0 +1,169 @@
1/*
2 * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 */
13
14#define pr_fmt(fmt) "tegra-pmc: " fmt
15
16#include <linux/io.h>
17#include <linux/module.h>
18#include <linux/of.h>
19#include <linux/platform_device.h>
20#include <linux/reboot.h>
21
22#include <asm/system_misc.h>
23
24#define PMC_CNTRL 0x000
25#define PMC_CNTRL_MAIN_RST BIT(4)
26
27#define PMC_RST_STATUS 0x070
28
29#define WAKE_AOWAKE_CTRL 0x4f4
30#define WAKE_AOWAKE_CTRL_INTR_POLARITY BIT(0)
31
32#define SCRATCH_SCRATCH0 0x2000
33#define SCRATCH_SCRATCH0_MODE_RECOVERY BIT(31)
34#define SCRATCH_SCRATCH0_MODE_BOOTLOADER BIT(30)
35#define SCRATCH_SCRATCH0_MODE_RCM BIT(1)
36#define SCRATCH_SCRATCH0_MODE_MASK (SCRATCH_SCRATCH0_MODE_RECOVERY | \
37 SCRATCH_SCRATCH0_MODE_BOOTLOADER | \
38 SCRATCH_SCRATCH0_MODE_RCM)
39
40struct tegra_pmc {
41 struct device *dev;
42 void __iomem *regs;
43 void __iomem *wake;
44 void __iomem *aotag;
45 void __iomem *scratch;
46
47 void (*system_restart)(enum reboot_mode mode, const char *cmd);
48 struct notifier_block restart;
49};
50
51static int tegra186_pmc_restart_notify(struct notifier_block *nb,
52 unsigned long action,
53 void *data)
54{
55 struct tegra_pmc *pmc = container_of(nb, struct tegra_pmc, restart);
56 const char *cmd = data;
57 u32 value;
58
59 value = readl(pmc->scratch + SCRATCH_SCRATCH0);
60 value &= ~SCRATCH_SCRATCH0_MODE_MASK;
61
62 if (cmd) {
63 if (strcmp(cmd, "recovery") == 0)
64 value |= SCRATCH_SCRATCH0_MODE_RECOVERY;
65
66 if (strcmp(cmd, "bootloader") == 0)
67 value |= SCRATCH_SCRATCH0_MODE_BOOTLOADER;
68
69 if (strcmp(cmd, "forced-recovery") == 0)
70 value |= SCRATCH_SCRATCH0_MODE_RCM;
71 }
72
73 writel(value, pmc->scratch + SCRATCH_SCRATCH0);
74
75 /*
76 * If available, call the system restart implementation that was
77 * registered earlier (typically PSCI).
78 */
79 if (pmc->system_restart) {
80 pmc->system_restart(reboot_mode, cmd);
81 return NOTIFY_DONE;
82 }
83
84 /* reset everything but SCRATCH0_SCRATCH0 and PMC_RST_STATUS */
85 value = readl(pmc->regs + PMC_CNTRL);
86 value |= PMC_CNTRL_MAIN_RST;
87 writel(value, pmc->regs + PMC_CNTRL);
88
89 return NOTIFY_DONE;
90}
91
92static int tegra186_pmc_setup(struct tegra_pmc *pmc)
93{
94 struct device_node *np = pmc->dev->of_node;
95 bool invert;
96 u32 value;
97
98 invert = of_property_read_bool(np, "nvidia,invert-interrupt");
99
100 value = readl(pmc->wake + WAKE_AOWAKE_CTRL);
101
102 if (invert)
103 value |= WAKE_AOWAKE_CTRL_INTR_POLARITY;
104 else
105 value &= ~WAKE_AOWAKE_CTRL_INTR_POLARITY;
106
107 writel(value, pmc->wake + WAKE_AOWAKE_CTRL);
108
109 /*
110 * We need to hook any system restart implementation registered
111 * previously so we can write SCRATCH_SCRATCH0 before reset.
112 */
113 pmc->system_restart = arm_pm_restart;
114 arm_pm_restart = NULL;
115
116 pmc->restart.notifier_call = tegra186_pmc_restart_notify;
117 pmc->restart.priority = 128;
118
119 return register_restart_handler(&pmc->restart);
120}
121
122static int tegra186_pmc_probe(struct platform_device *pdev)
123{
124 struct tegra_pmc *pmc;
125 struct resource *res;
126
127 pmc = devm_kzalloc(&pdev->dev, sizeof(*pmc), GFP_KERNEL);
128 if (!pmc)
129 return -ENOMEM;
130
131 pmc->dev = &pdev->dev;
132
133 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pmc");
134 pmc->regs = devm_ioremap_resource(&pdev->dev, res);
135 if (IS_ERR(pmc->regs))
136 return PTR_ERR(pmc->regs);
137
138 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "wake");
139 pmc->wake = devm_ioremap_resource(&pdev->dev, res);
140 if (IS_ERR(pmc->wake))
141 return PTR_ERR(pmc->wake);
142
143 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "aotag");
144 pmc->aotag = devm_ioremap_resource(&pdev->dev, res);
145 if (IS_ERR(pmc->aotag))
146 return PTR_ERR(pmc->aotag);
147
148 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "scratch");
149 pmc->scratch = devm_ioremap_resource(&pdev->dev, res);
150 if (IS_ERR(pmc->scratch))
151 return PTR_ERR(pmc->scratch);
152
153 return tegra186_pmc_setup(pmc);
154}
155
156static const struct of_device_id tegra186_pmc_of_match[] = {
157 { .compatible = "nvidia,tegra186-pmc" },
158 { /* sentinel */ }
159};
160MODULE_DEVICE_TABLE(of, tegra186_pmc_of_match);
161
162static struct platform_driver tegra186_pmc_driver = {
163 .driver = {
164 .name = "tegra186-pmc",
165 .of_match_table = tegra186_pmc_of_match,
166 },
167 .probe = tegra186_pmc_probe,
168};
169builtin_platform_driver(tegra186_pmc_driver);