aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMikko Perttunen <mperttunen@nvidia.com>2019-01-25 05:22:55 -0500
committerThierry Reding <treding@nvidia.com>2019-01-25 10:18:24 -0500
commite247deae1a55089cb04cc25c91faeba083d0c39c (patch)
tree2c85583a47f879f93b7751e54fe668fbfb528a31
parentfa3bc04ef8ccccfe47db1f4030a7a43569956402 (diff)
soc/tegra: pmc: Support systems where PMC is marked secure
On Tegra210 systems with new enough boot software, direct register accesses to PMC register space from the non-secure world are not allowed. Instead a monitor call may be used to read and write PMC registers. Add code to detect such a system by attempting to write a scratch register and detecting if the write happened or not. If not, we switch to doing all register accesses through the monitor call. Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com> Signed-off-by: Thierry Reding <treding@nvidia.com> Acked-by: Jon Hunter <jonathanh@nvidia.com>
-rw-r--r--drivers/soc/tegra/pmc.c100
1 files changed, 97 insertions, 3 deletions
diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index dba89fc81a04..0df258518693 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -20,6 +20,7 @@
20 20
21#define pr_fmt(fmt) "tegra-pmc: " fmt 21#define pr_fmt(fmt) "tegra-pmc: " fmt
22 22
23#include <linux/arm-smccc.h>
23#include <linux/clk.h> 24#include <linux/clk.h>
24#include <linux/clk/tegra.h> 25#include <linux/clk/tegra.h>
25#include <linux/debugfs.h> 26#include <linux/debugfs.h>
@@ -145,6 +146,11 @@
145#define WAKE_AOWAKE_CTRL 0x4f4 146#define WAKE_AOWAKE_CTRL 0x4f4
146#define WAKE_AOWAKE_CTRL_INTR_POLARITY BIT(0) 147#define WAKE_AOWAKE_CTRL_INTR_POLARITY BIT(0)
147 148
149/* for secure PMC */
150#define TEGRA_SMC_PMC 0xc2fffe00
151#define TEGRA_SMC_PMC_READ 0xaa
152#define TEGRA_SMC_PMC_WRITE 0xbb
153
148struct tegra_powergate { 154struct tegra_powergate {
149 struct generic_pm_domain genpd; 155 struct generic_pm_domain genpd;
150 struct tegra_pmc *pmc; 156 struct tegra_pmc *pmc;
@@ -216,6 +222,7 @@ struct tegra_pmc_soc {
216 bool has_gpu_clamps; 222 bool has_gpu_clamps;
217 bool needs_mbist_war; 223 bool needs_mbist_war;
218 bool has_impl_33v_pwr; 224 bool has_impl_33v_pwr;
225 bool maybe_tz_only;
219 226
220 const struct tegra_io_pad_soc *io_pads; 227 const struct tegra_io_pad_soc *io_pads;
221 unsigned int num_io_pads; 228 unsigned int num_io_pads;
@@ -278,6 +285,7 @@ static const char * const tegra30_reset_sources[] = {
278 * @scratch: pointer to I/O remapped region for scratch registers 285 * @scratch: pointer to I/O remapped region for scratch registers
279 * @clk: pointer to pclk clock 286 * @clk: pointer to pclk clock
280 * @soc: pointer to SoC data structure 287 * @soc: pointer to SoC data structure
288 * @tz_only: flag specifying if the PMC can only be accessed via TrustZone
281 * @debugfs: pointer to debugfs entry 289 * @debugfs: pointer to debugfs entry
282 * @rate: currently configured rate of pclk 290 * @rate: currently configured rate of pclk
283 * @suspend_mode: lowest suspend mode available 291 * @suspend_mode: lowest suspend mode available
@@ -308,6 +316,7 @@ struct tegra_pmc {
308 struct dentry *debugfs; 316 struct dentry *debugfs;
309 317
310 const struct tegra_pmc_soc *soc; 318 const struct tegra_pmc_soc *soc;
319 bool tz_only;
311 320
312 unsigned long rate; 321 unsigned long rate;
313 322
@@ -346,13 +355,62 @@ to_powergate(struct generic_pm_domain *domain)
346 355
347static u32 tegra_pmc_readl(struct tegra_pmc *pmc, unsigned long offset) 356static u32 tegra_pmc_readl(struct tegra_pmc *pmc, unsigned long offset)
348{ 357{
358 struct arm_smccc_res res;
359
360 if (pmc->tz_only) {
361 arm_smccc_smc(TEGRA_SMC_PMC, TEGRA_SMC_PMC_READ, offset, 0, 0,
362 0, 0, 0, &res);
363 if (res.a0) {
364 if (pmc->dev)
365 dev_warn(pmc->dev, "%s(): SMC failed: %lu\n",
366 __func__, res.a0);
367 else
368 pr_warn("%s(): SMC failed: %lu\n", __func__,
369 res.a0);
370 }
371
372 return res.a1;
373 }
374
349 return readl(pmc->base + offset); 375 return readl(pmc->base + offset);
350} 376}
351 377
352static void tegra_pmc_writel(struct tegra_pmc *pmc, u32 value, 378static void tegra_pmc_writel(struct tegra_pmc *pmc, u32 value,
353 unsigned long offset) 379 unsigned long offset)
354{ 380{
355 writel(value, pmc->base + offset); 381 struct arm_smccc_res res;
382
383 if (pmc->tz_only) {
384 arm_smccc_smc(TEGRA_SMC_PMC, TEGRA_SMC_PMC_WRITE, offset,
385 value, 0, 0, 0, 0, &res);
386 if (res.a0) {
387 if (pmc->dev)
388 dev_warn(pmc->dev, "%s(): SMC failed: %lu\n",
389 __func__, res.a0);
390 else
391 pr_warn("%s(): SMC failed: %lu\n", __func__,
392 res.a0);
393 }
394 } else {
395 writel(value, pmc->base + offset);
396 }
397}
398
399static u32 tegra_pmc_scratch_readl(struct tegra_pmc *pmc, unsigned long offset)
400{
401 if (pmc->tz_only)
402 return tegra_pmc_readl(pmc, offset);
403
404 return readl(pmc->scratch + offset);
405}
406
407static void tegra_pmc_scratch_writel(struct tegra_pmc *pmc, u32 value,
408 unsigned long offset)
409{
410 if (pmc->tz_only)
411 tegra_pmc_writel(pmc, value, offset);
412 else
413 writel(value, pmc->scratch + offset);
356} 414}
357 415
358/* 416/*
@@ -776,7 +834,7 @@ static int tegra_pmc_restart_notify(struct notifier_block *this,
776 const char *cmd = data; 834 const char *cmd = data;
777 u32 value; 835 u32 value;
778 836
779 value = readl(pmc->scratch + pmc->soc->regs->scratch0); 837 value = tegra_pmc_scratch_readl(pmc, pmc->soc->regs->scratch0);
780 value &= ~PMC_SCRATCH0_MODE_MASK; 838 value &= ~PMC_SCRATCH0_MODE_MASK;
781 839
782 if (cmd) { 840 if (cmd) {
@@ -790,7 +848,7 @@ static int tegra_pmc_restart_notify(struct notifier_block *this,
790 value |= PMC_SCRATCH0_MODE_RCM; 848 value |= PMC_SCRATCH0_MODE_RCM;
791 } 849 }
792 850
793 writel(value, pmc->scratch + pmc->soc->regs->scratch0); 851 tegra_pmc_scratch_writel(pmc, value, pmc->soc->regs->scratch0);
794 852
795 /* reset everything but PMC_SCRATCH0 and PMC_RST_STATUS */ 853 /* reset everything but PMC_SCRATCH0 and PMC_RST_STATUS */
796 value = tegra_pmc_readl(pmc, PMC_CNTRL); 854 value = tegra_pmc_readl(pmc, PMC_CNTRL);
@@ -2071,6 +2129,7 @@ static const struct tegra_pmc_soc tegra20_pmc_soc = {
2071 .has_gpu_clamps = false, 2129 .has_gpu_clamps = false,
2072 .needs_mbist_war = false, 2130 .needs_mbist_war = false,
2073 .has_impl_33v_pwr = false, 2131 .has_impl_33v_pwr = false,
2132 .maybe_tz_only = false,
2074 .num_io_pads = 0, 2133 .num_io_pads = 0,
2075 .io_pads = NULL, 2134 .io_pads = NULL,
2076 .num_pin_descs = 0, 2135 .num_pin_descs = 0,
@@ -2117,6 +2176,7 @@ static const struct tegra_pmc_soc tegra30_pmc_soc = {
2117 .has_gpu_clamps = false, 2176 .has_gpu_clamps = false,
2118 .needs_mbist_war = false, 2177 .needs_mbist_war = false,
2119 .has_impl_33v_pwr = false, 2178 .has_impl_33v_pwr = false,
2179 .maybe_tz_only = false,
2120 .num_io_pads = 0, 2180 .num_io_pads = 0,
2121 .io_pads = NULL, 2181 .io_pads = NULL,
2122 .num_pin_descs = 0, 2182 .num_pin_descs = 0,
@@ -2167,6 +2227,7 @@ static const struct tegra_pmc_soc tegra114_pmc_soc = {
2167 .has_gpu_clamps = false, 2227 .has_gpu_clamps = false,
2168 .needs_mbist_war = false, 2228 .needs_mbist_war = false,
2169 .has_impl_33v_pwr = false, 2229 .has_impl_33v_pwr = false,
2230 .maybe_tz_only = false,
2170 .num_io_pads = 0, 2231 .num_io_pads = 0,
2171 .io_pads = NULL, 2232 .io_pads = NULL,
2172 .num_pin_descs = 0, 2233 .num_pin_descs = 0,
@@ -2277,6 +2338,7 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = {
2277 .has_gpu_clamps = true, 2338 .has_gpu_clamps = true,
2278 .needs_mbist_war = false, 2339 .needs_mbist_war = false,
2279 .has_impl_33v_pwr = false, 2340 .has_impl_33v_pwr = false,
2341 .maybe_tz_only = false,
2280 .num_io_pads = ARRAY_SIZE(tegra124_io_pads), 2342 .num_io_pads = ARRAY_SIZE(tegra124_io_pads),
2281 .io_pads = tegra124_io_pads, 2343 .io_pads = tegra124_io_pads,
2282 .num_pin_descs = ARRAY_SIZE(tegra124_pin_descs), 2344 .num_pin_descs = ARRAY_SIZE(tegra124_pin_descs),
@@ -2382,6 +2444,7 @@ static const struct tegra_pmc_soc tegra210_pmc_soc = {
2382 .has_gpu_clamps = true, 2444 .has_gpu_clamps = true,
2383 .needs_mbist_war = true, 2445 .needs_mbist_war = true,
2384 .has_impl_33v_pwr = false, 2446 .has_impl_33v_pwr = false,
2447 .maybe_tz_only = true,
2385 .num_io_pads = ARRAY_SIZE(tegra210_io_pads), 2448 .num_io_pads = ARRAY_SIZE(tegra210_io_pads),
2386 .io_pads = tegra210_io_pads, 2449 .io_pads = tegra210_io_pads,
2387 .num_pin_descs = ARRAY_SIZE(tegra210_pin_descs), 2450 .num_pin_descs = ARRAY_SIZE(tegra210_pin_descs),
@@ -2506,6 +2569,7 @@ static const struct tegra_pmc_soc tegra186_pmc_soc = {
2506 .has_gpu_clamps = false, 2569 .has_gpu_clamps = false,
2507 .needs_mbist_war = false, 2570 .needs_mbist_war = false,
2508 .has_impl_33v_pwr = true, 2571 .has_impl_33v_pwr = true,
2572 .maybe_tz_only = false,
2509 .num_io_pads = ARRAY_SIZE(tegra186_io_pads), 2573 .num_io_pads = ARRAY_SIZE(tegra186_io_pads),
2510 .io_pads = tegra186_io_pads, 2574 .io_pads = tegra186_io_pads,
2511 .num_pin_descs = ARRAY_SIZE(tegra186_pin_descs), 2575 .num_pin_descs = ARRAY_SIZE(tegra186_pin_descs),
@@ -2585,6 +2649,7 @@ static const struct tegra_pmc_soc tegra194_pmc_soc = {
2585 .has_gpu_clamps = false, 2649 .has_gpu_clamps = false,
2586 .needs_mbist_war = false, 2650 .needs_mbist_war = false,
2587 .has_impl_33v_pwr = false, 2651 .has_impl_33v_pwr = false,
2652 .maybe_tz_only = false,
2588 .num_io_pads = ARRAY_SIZE(tegra194_io_pads), 2653 .num_io_pads = ARRAY_SIZE(tegra194_io_pads),
2589 .io_pads = tegra194_io_pads, 2654 .io_pads = tegra194_io_pads,
2590 .regs = &tegra186_pmc_regs, 2655 .regs = &tegra186_pmc_regs,
@@ -2619,6 +2684,32 @@ static struct platform_driver tegra_pmc_driver = {
2619}; 2684};
2620builtin_platform_driver(tegra_pmc_driver); 2685builtin_platform_driver(tegra_pmc_driver);
2621 2686
2687static bool __init tegra_pmc_detect_tz_only(struct tegra_pmc *pmc)
2688{
2689 u32 value, saved;
2690
2691 saved = readl(pmc->base + pmc->soc->regs->scratch0);
2692 value = saved ^ 0xffffffff;
2693
2694 if (value == 0xffffffff)
2695 value = 0xdeadbeef;
2696
2697 /* write pattern and read it back */
2698 writel(value, pmc->base + pmc->soc->regs->scratch0);
2699 value = readl(pmc->base + pmc->soc->regs->scratch0);
2700
2701 /* if we read all-zeroes, access is restricted to TZ only */
2702 if (value == 0) {
2703 pr_info("access to PMC is restricted to TZ\n");
2704 return true;
2705 }
2706
2707 /* restore original value */
2708 writel(saved, pmc->base + pmc->soc->regs->scratch0);
2709
2710 return false;
2711}
2712
2622/* 2713/*
2623 * Early initialization to allow access to registers in the very early boot 2714 * Early initialization to allow access to registers in the very early boot
2624 * process. 2715 * process.
@@ -2681,6 +2772,9 @@ static int __init tegra_pmc_early_init(void)
2681 if (np) { 2772 if (np) {
2682 pmc->soc = match->data; 2773 pmc->soc = match->data;
2683 2774
2775 if (pmc->soc->maybe_tz_only)
2776 pmc->tz_only = tegra_pmc_detect_tz_only(pmc);
2777
2684 tegra_powergate_init(pmc, np); 2778 tegra_powergate_init(pmc, np);
2685 2779
2686 /* 2780 /*