ARM: tegra: Support TZ-only access to PMC
Some devices may restrict access to the PMC to TrustZone software only. Non-TZ software can detect this and use SMC calls to the firmware that runs in the TrustZone to perform accesses to PMC registers. Note that this also fixes reset_cpu() and the enterrcm command on Tegra186 where they were previously trying to access the PMC at a wrong physical address. Based on work by Kalyani Chidambaram <kalyanic@nvidia.com> and Tom Warren <twarren@nvidia.com>. Signed-off-by: Thierry Reding <treding@nvidia.com> Signed-off-by: Tom Warren <twarren@nvidia.com>
This commit is contained in:
		
							parent
							
								
									147fac6aef
								
							
						
					
					
						commit
						f9ec2ec850
					
				| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
/* SPDX-License-Identifier: GPL-2.0+ */
 | 
					/* SPDX-License-Identifier: GPL-2.0+ */
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 *  (C) Copyright 2010-2015
 | 
					 *  (C) Copyright 2010-2019
 | 
				
			||||||
 *  NVIDIA Corporation <www.nvidia.com>
 | 
					 *  NVIDIA Corporation <www.nvidia.com>
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -388,4 +388,22 @@ struct pmc_ctlr {
 | 
				
			||||||
/* APBDEV_PMC_CNTRL2_0 0x440 */
 | 
					/* APBDEV_PMC_CNTRL2_0 0x440 */
 | 
				
			||||||
#define HOLD_CKE_LOW_EN				(1 << 12)
 | 
					#define HOLD_CKE_LOW_EN				(1 << 12)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* PMC read/write functions */
 | 
				
			||||||
 | 
					u32 tegra_pmc_readl(unsigned long offset);
 | 
				
			||||||
 | 
					void tegra_pmc_writel(u32 value, unsigned long offset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define PMC_CNTRL		0x0
 | 
				
			||||||
 | 
					#define  PMC_CNTRL_MAIN_RST	BIT(4)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if IS_ENABLED(CONFIG_TEGRA186)
 | 
				
			||||||
 | 
					#  define PMC_SCRATCH0 0x32000
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#  define PMC_SCRATCH0 0x00050
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* for secure PMC */
 | 
				
			||||||
 | 
					#define TEGRA_SMC_PMC		0xc2fffe00
 | 
				
			||||||
 | 
					#define  TEGRA_SMC_PMC_READ	0xaa
 | 
				
			||||||
 | 
					#define  TEGRA_SMC_PMC_WRITE	0xbb
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif	/* PMC_H */
 | 
					#endif	/* PMC_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,7 +30,13 @@
 | 
				
			||||||
#define NV_PA_SLINK5_BASE	(NV_PA_APB_MISC_BASE + 0xDC00)
 | 
					#define NV_PA_SLINK5_BASE	(NV_PA_APB_MISC_BASE + 0xDC00)
 | 
				
			||||||
#define NV_PA_SLINK6_BASE	(NV_PA_APB_MISC_BASE + 0xDE00)
 | 
					#define NV_PA_SLINK6_BASE	(NV_PA_APB_MISC_BASE + 0xDE00)
 | 
				
			||||||
#define TEGRA_DVC_BASE		(NV_PA_APB_MISC_BASE + 0xD000)
 | 
					#define TEGRA_DVC_BASE		(NV_PA_APB_MISC_BASE + 0xD000)
 | 
				
			||||||
 | 
					#if defined(CONFIG_TEGRA20) || defined(CONFIG_TEGRA30) || \
 | 
				
			||||||
 | 
						defined(CONFIG_TEGRA114) || defined(CONFIG_TEGRA124) || \
 | 
				
			||||||
 | 
						defined(CONFIG_TEGRA132) || defined(CONFIG_TEGRA210)
 | 
				
			||||||
#define NV_PA_PMC_BASE		(NV_PA_APB_MISC_BASE + 0xE400)
 | 
					#define NV_PA_PMC_BASE		(NV_PA_APB_MISC_BASE + 0xE400)
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#define NV_PA_PMC_BASE		0xc360000
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
#define NV_PA_EMC_BASE		(NV_PA_APB_MISC_BASE + 0xF400)
 | 
					#define NV_PA_EMC_BASE		(NV_PA_APB_MISC_BASE + 0xF400)
 | 
				
			||||||
#define NV_PA_FUSE_BASE		(NV_PA_APB_MISC_BASE + 0xF800)
 | 
					#define NV_PA_FUSE_BASE		(NV_PA_APB_MISC_BASE + 0xF800)
 | 
				
			||||||
#if defined(CONFIG_TEGRA20) || defined(CONFIG_TEGRA30) || \
 | 
					#if defined(CONFIG_TEGRA20) || defined(CONFIG_TEGRA30) || \
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,6 +35,10 @@ config TEGRA_PINCTRL
 | 
				
			||||||
config TEGRA_PMC
 | 
					config TEGRA_PMC
 | 
				
			||||||
	bool
 | 
						bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config TEGRA_PMC_SECURE
 | 
				
			||||||
 | 
						bool
 | 
				
			||||||
 | 
						depends on TEGRA_PMC
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config TEGRA_COMMON
 | 
					config TEGRA_COMMON
 | 
				
			||||||
	bool "Tegra common options"
 | 
						bool "Tegra common options"
 | 
				
			||||||
	select BINMAN
 | 
						select BINMAN
 | 
				
			||||||
| 
						 | 
					@ -127,6 +131,7 @@ config TEGRA210
 | 
				
			||||||
	select TEGRA_NO_BPMP
 | 
						select TEGRA_NO_BPMP
 | 
				
			||||||
	select TEGRA_PINCTRL
 | 
						select TEGRA_PINCTRL
 | 
				
			||||||
	select TEGRA_PMC
 | 
						select TEGRA_PMC
 | 
				
			||||||
 | 
						select TEGRA_PMC_SECURE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config TEGRA186
 | 
					config TEGRA186
 | 
				
			||||||
	bool "Tegra186 family"
 | 
						bool "Tegra186 family"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
# SPDX-License-Identifier: GPL-2.0+
 | 
					# SPDX-License-Identifier: GPL-2.0+
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# (C) Copyright 2010-2015 Nvidia Corporation.
 | 
					# (C) Copyright 2010-2019 Nvidia Corporation.
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# (C) Copyright 2000-2008
 | 
					# (C) Copyright 2000-2008
 | 
				
			||||||
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
 | 
					# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
 | 
				
			||||||
| 
						 | 
					@ -27,11 +27,11 @@ obj-y += dt-setup.o
 | 
				
			||||||
obj-$(CONFIG_TEGRA_CLOCK_SCALING) += emc.o
 | 
					obj-$(CONFIG_TEGRA_CLOCK_SCALING) += emc.o
 | 
				
			||||||
obj-$(CONFIG_TEGRA_GPU) += gpu.o
 | 
					obj-$(CONFIG_TEGRA_GPU) += gpu.o
 | 
				
			||||||
obj-$(CONFIG_TEGRA_IVC) += ivc.o
 | 
					obj-$(CONFIG_TEGRA_IVC) += ivc.o
 | 
				
			||||||
obj-y += lowlevel_init.o
 | 
					 | 
				
			||||||
ifndef CONFIG_SPL_BUILD
 | 
					ifndef CONFIG_SPL_BUILD
 | 
				
			||||||
obj-$(CONFIG_ARMV7_PSCI) += psci.o
 | 
					obj-$(CONFIG_ARMV7_PSCI) += psci.o
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
obj-$(CONFIG_DISPLAY_CPUINFO) += sys_info.o
 | 
					obj-$(CONFIG_DISPLAY_CPUINFO) += sys_info.o
 | 
				
			||||||
 | 
					obj-y += pmc.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
obj-$(CONFIG_TEGRA20) += tegra20/
 | 
					obj-$(CONFIG_TEGRA20) += tegra20/
 | 
				
			||||||
obj-$(CONFIG_TEGRA30) += tegra30/
 | 
					obj-$(CONFIG_TEGRA30) += tegra30/
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
// SPDX-License-Identifier: GPL-2.0
 | 
					// SPDX-License-Identifier: GPL-2.0
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Copyright (c) 2010-2015, NVIDIA CORPORATION.  All rights reserved.
 | 
					 * Copyright (c) 2010-2019, NVIDIA CORPORATION.  All rights reserved.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Tegra SoC common clock control functions */
 | 
					/* Tegra SoC common clock control functions */
 | 
				
			||||||
| 
						 | 
					@ -815,11 +815,16 @@ void tegra30_set_up_pllp(void)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int clock_external_output(int clk_id)
 | 
					int clock_external_output(int clk_id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
 | 
						u32 val;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (clk_id >= 1 && clk_id <= 3) {
 | 
						if (clk_id >= 1 && clk_id <= 3) {
 | 
				
			||||||
		setbits_le32(&pmc->pmc_clk_out_cntrl,
 | 
							val = tegra_pmc_readl(offsetof(struct pmc_ctlr,
 | 
				
			||||||
			     1 << (2 + (clk_id - 1) * 8));
 | 
									      pmc_clk_out_cntrl));
 | 
				
			||||||
 | 
							val |= 1 << (2 + (clk_id - 1) * 8);
 | 
				
			||||||
 | 
							tegra_pmc_writel(val,
 | 
				
			||||||
 | 
									 offsetof(struct pmc_ctlr,
 | 
				
			||||||
 | 
									 pmc_clk_out_cntrl));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		printf("%s: Unknown output clock id %d\n", __func__, clk_id);
 | 
							printf("%s: Unknown output clock id %d\n", __func__, clk_id);
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
// SPDX-License-Identifier: GPL-2.0+
 | 
					// SPDX-License-Identifier: GPL-2.0+
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
 | 
					 * Copyright (c) 2012-2019, NVIDIA CORPORATION. All rights reserved.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Derived from code (arch/arm/lib/reset.c) that is:
 | 
					 * Derived from code (arch/arm/lib/reset.c) that is:
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
| 
						 | 
					@ -31,12 +31,10 @@
 | 
				
			||||||
static int do_enterrcm(cmd_tbl_t *cmdtp, int flag, int argc,
 | 
					static int do_enterrcm(cmd_tbl_t *cmdtp, int flag, int argc,
 | 
				
			||||||
		       char * const argv[])
 | 
							       char * const argv[])
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	puts("Entering RCM...\n");
 | 
						puts("Entering RCM...\n");
 | 
				
			||||||
	udelay(50000);
 | 
						udelay(50000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pmc->pmc_scratch0 = 2;
 | 
						tegra_pmc_writel(2, PMC_SCRATCH0);
 | 
				
			||||||
	disable_interrupts();
 | 
						disable_interrupts();
 | 
				
			||||||
	reset_cpu(0);
 | 
						reset_cpu(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
// SPDX-License-Identifier: GPL-2.0
 | 
					// SPDX-License-Identifier: GPL-2.0
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Copyright (c) 2010-2015, NVIDIA CORPORATION.  All rights reserved.
 | 
					 * Copyright (c) 2010-2019, NVIDIA CORPORATION.  All rights reserved.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <common.h>
 | 
					#include <common.h>
 | 
				
			||||||
| 
						 | 
					@ -299,21 +299,19 @@ void enable_cpu_clock(int enable)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int is_cpu_powered(void)
 | 
					static int is_cpu_powered(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
 | 
						return (tegra_pmc_readl(offsetof(struct pmc_ctlr,
 | 
				
			||||||
 | 
									pmc_pwrgate_status)) & CPU_PWRED) ? 1 : 0;
 | 
				
			||||||
	return (readl(&pmc->pmc_pwrgate_status) & CPU_PWRED) ? 1 : 0;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void remove_cpu_io_clamps(void)
 | 
					static void remove_cpu_io_clamps(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
 | 
					 | 
				
			||||||
	u32 reg;
 | 
						u32 reg;
 | 
				
			||||||
	debug("%s entry\n", __func__);
 | 
						debug("%s entry\n", __func__);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Remove the clamps on the CPU I/O signals */
 | 
						/* Remove the clamps on the CPU I/O signals */
 | 
				
			||||||
	reg = readl(&pmc->pmc_remove_clamping);
 | 
						reg = tegra_pmc_readl(offsetof(struct pmc_ctlr, pmc_remove_clamping));
 | 
				
			||||||
	reg |= CPU_CLMP;
 | 
						reg |= CPU_CLMP;
 | 
				
			||||||
	writel(reg, &pmc->pmc_remove_clamping);
 | 
						tegra_pmc_writel(reg, offsetof(struct pmc_ctlr, pmc_remove_clamping));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Give I/O signals time to stabilize */
 | 
						/* Give I/O signals time to stabilize */
 | 
				
			||||||
	udelay(IO_STABILIZATION_DELAY);
 | 
						udelay(IO_STABILIZATION_DELAY);
 | 
				
			||||||
| 
						 | 
					@ -321,17 +319,19 @@ static void remove_cpu_io_clamps(void)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void powerup_cpu(void)
 | 
					void powerup_cpu(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
 | 
					 | 
				
			||||||
	u32 reg;
 | 
						u32 reg;
 | 
				
			||||||
	int timeout = IO_STABILIZATION_DELAY;
 | 
						int timeout = IO_STABILIZATION_DELAY;
 | 
				
			||||||
	debug("%s entry\n", __func__);
 | 
						debug("%s entry\n", __func__);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!is_cpu_powered()) {
 | 
						if (!is_cpu_powered()) {
 | 
				
			||||||
		/* Toggle the CPU power state (OFF -> ON) */
 | 
							/* Toggle the CPU power state (OFF -> ON) */
 | 
				
			||||||
		reg = readl(&pmc->pmc_pwrgate_toggle);
 | 
							reg = tegra_pmc_readl(offsetof(struct pmc_ctlr,
 | 
				
			||||||
 | 
									      pmc_pwrgate_toggle));
 | 
				
			||||||
		reg &= PARTID_CP;
 | 
							reg &= PARTID_CP;
 | 
				
			||||||
		reg |= START_CP;
 | 
							reg |= START_CP;
 | 
				
			||||||
		writel(reg, &pmc->pmc_pwrgate_toggle);
 | 
							tegra_pmc_writel(reg,
 | 
				
			||||||
 | 
									 offsetof(struct pmc_ctlr,
 | 
				
			||||||
 | 
									 pmc_pwrgate_toggle));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Wait for the power to come up */
 | 
							/* Wait for the power to come up */
 | 
				
			||||||
		while (!is_cpu_powered()) {
 | 
							while (!is_cpu_powered()) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,39 +0,0 @@
 | 
				
			||||||
/* SPDX-License-Identifier: GPL-2.0+ */
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * SoC-specific setup info
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * (C) Copyright 2010,2011
 | 
					 | 
				
			||||||
 * NVIDIA Corporation <www.nvidia.com>
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <config.h>
 | 
					 | 
				
			||||||
#include <linux/linkage.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef CONFIG_ARM64
 | 
					 | 
				
			||||||
	.align	5
 | 
					 | 
				
			||||||
ENTRY(reset_cpu)
 | 
					 | 
				
			||||||
	/* get address for global reset register */
 | 
					 | 
				
			||||||
	ldr	x1, =PRM_RSTCTRL
 | 
					 | 
				
			||||||
	ldr	w3, [x1]
 | 
					 | 
				
			||||||
	/* force reset */
 | 
					 | 
				
			||||||
	orr	w3, w3, #0x10
 | 
					 | 
				
			||||||
	str	w3, [x1]
 | 
					 | 
				
			||||||
	mov	w0, w0
 | 
					 | 
				
			||||||
1:
 | 
					 | 
				
			||||||
	b	1b
 | 
					 | 
				
			||||||
ENDPROC(reset_cpu)
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
	.align	5
 | 
					 | 
				
			||||||
ENTRY(reset_cpu)
 | 
					 | 
				
			||||||
	ldr	r1, rstctl			@ get addr for global reset
 | 
					 | 
				
			||||||
						@ reg
 | 
					 | 
				
			||||||
	ldr	r3, [r1]
 | 
					 | 
				
			||||||
	orr	r3, r3, #0x10
 | 
					 | 
				
			||||||
	str	r3, [r1]			@ force reset
 | 
					 | 
				
			||||||
	mov	r0, r0
 | 
					 | 
				
			||||||
_loop_forever:
 | 
					 | 
				
			||||||
	b	_loop_forever
 | 
					 | 
				
			||||||
rstctl:
 | 
					 | 
				
			||||||
	.word	PRM_RSTCTRL
 | 
					 | 
				
			||||||
ENDPROC(reset_cpu)
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,92 @@
 | 
				
			||||||
 | 
					/* SPDX-License-Identifier: GPL-2.0 */
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <common.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/arm-smccc.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <asm/io.h>
 | 
				
			||||||
 | 
					#include <asm/arch-tegra/pmc.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DECLARE_GLOBAL_DATA_PTR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if IS_ENABLED(CONFIG_TEGRA_PMC_SECURE)
 | 
				
			||||||
 | 
					static bool tegra_pmc_detect_tz_only(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						static bool initialized = false;
 | 
				
			||||||
 | 
						static bool is_tz_only = false;
 | 
				
			||||||
 | 
						u32 value, saved;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!initialized) {
 | 
				
			||||||
 | 
							saved = readl(NV_PA_PMC_BASE + PMC_SCRATCH0);
 | 
				
			||||||
 | 
							value = saved ^ 0xffffffff;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (value == 0xffffffff)
 | 
				
			||||||
 | 
								value = 0xdeadbeef;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* write pattern and read it back */
 | 
				
			||||||
 | 
							writel(value, NV_PA_PMC_BASE + PMC_SCRATCH0);
 | 
				
			||||||
 | 
							value = readl(NV_PA_PMC_BASE + PMC_SCRATCH0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* if we read all-zeroes, access is restricted to TZ only */
 | 
				
			||||||
 | 
							if (value == 0) {
 | 
				
			||||||
 | 
								debug("access to PMC is restricted to TZ\n");
 | 
				
			||||||
 | 
								is_tz_only = true;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								/* restore original value */
 | 
				
			||||||
 | 
								writel(saved, NV_PA_PMC_BASE + PMC_SCRATCH0);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							initialized = true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return is_tz_only;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint32_t tegra_pmc_readl(unsigned long offset)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					#if IS_ENABLED(CONFIG_TEGRA_PMC_SECURE)
 | 
				
			||||||
 | 
						if (tegra_pmc_detect_tz_only()) {
 | 
				
			||||||
 | 
							struct arm_smccc_res res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							arm_smccc_smc(TEGRA_SMC_PMC, TEGRA_SMC_PMC_READ, offset, 0, 0,
 | 
				
			||||||
 | 
								      0, 0, 0, &res);
 | 
				
			||||||
 | 
							if (res.a0)
 | 
				
			||||||
 | 
								printf("%s(): SMC failed: %lu\n", __func__, res.a0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return res.a1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return readl(NV_PA_PMC_BASE + offset);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void tegra_pmc_writel(u32 value, unsigned long offset)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					#if IS_ENABLED(CONFIG_TEGRA_PMC_SECURE)
 | 
				
			||||||
 | 
						if (tegra_pmc_detect_tz_only()) {
 | 
				
			||||||
 | 
							struct arm_smccc_res res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							arm_smccc_smc(TEGRA_SMC_PMC, TEGRA_SMC_PMC_WRITE, offset,
 | 
				
			||||||
 | 
								      value, 0, 0, 0, 0, &res);
 | 
				
			||||||
 | 
							if (res.a0)
 | 
				
			||||||
 | 
								printf("%s(): SMC failed: %lu\n", __func__, res.a0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						writel(value, NV_PA_PMC_BASE + offset);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void reset_cpu(ulong addr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u32 value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						value = tegra_pmc_readl(PMC_CNTRL);
 | 
				
			||||||
 | 
						value |= PMC_CNTRL_MAIN_RST;
 | 
				
			||||||
 | 
						tegra_pmc_writel(value, PMC_CNTRL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
// SPDX-License-Identifier: GPL-2.0
 | 
					// SPDX-License-Identifier: GPL-2.0
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Copyright (c) 2014, NVIDIA CORPORATION.  All rights reserved.
 | 
					 * Copyright (c) 2014-2019, NVIDIA CORPORATION.  All rights reserved.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <common.h>
 | 
					#include <common.h>
 | 
				
			||||||
| 
						 | 
					@ -11,6 +11,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <asm/arch/powergate.h>
 | 
					#include <asm/arch/powergate.h>
 | 
				
			||||||
#include <asm/arch/tegra.h>
 | 
					#include <asm/arch/tegra.h>
 | 
				
			||||||
 | 
					#include <asm/arch-tegra/pmc.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define PWRGATE_TOGGLE 0x30
 | 
					#define PWRGATE_TOGGLE 0x30
 | 
				
			||||||
#define  PWRGATE_TOGGLE_START (1 << 8)
 | 
					#define  PWRGATE_TOGGLE_START (1 << 8)
 | 
				
			||||||
| 
						 | 
					@ -24,18 +25,18 @@ static int tegra_powergate_set(enum tegra_powergate id, bool state)
 | 
				
			||||||
	u32 value, mask = state ? (1 << id) : 0, old_mask;
 | 
						u32 value, mask = state ? (1 << id) : 0, old_mask;
 | 
				
			||||||
	unsigned long start, timeout = 25;
 | 
						unsigned long start, timeout = 25;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	value = readl(NV_PA_PMC_BASE + PWRGATE_STATUS);
 | 
						value = tegra_pmc_readl(PWRGATE_STATUS);
 | 
				
			||||||
	old_mask = value & (1 << id);
 | 
						old_mask = value & (1 << id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (mask == old_mask)
 | 
						if (mask == old_mask)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	writel(PWRGATE_TOGGLE_START | id, NV_PA_PMC_BASE + PWRGATE_TOGGLE);
 | 
						tegra_pmc_writel(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	start = get_timer(0);
 | 
						start = get_timer(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while (get_timer(start) < timeout) {
 | 
						while (get_timer(start) < timeout) {
 | 
				
			||||||
		value = readl(NV_PA_PMC_BASE + PWRGATE_STATUS);
 | 
							value = tegra_pmc_readl(PWRGATE_STATUS);
 | 
				
			||||||
		if ((value & (1 << id)) == mask)
 | 
							if ((value & (1 << id)) == mask)
 | 
				
			||||||
			return 0;
 | 
								return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -69,7 +70,7 @@ static int tegra_powergate_remove_clamping(enum tegra_powergate id)
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		value = 1 << id;
 | 
							value = 1 << id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	writel(value, NV_PA_PMC_BASE + REMOVE_CLAMPING);
 | 
						tegra_pmc_writel(value, REMOVE_CLAMPING);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue