xref: /linux/arch/arm/mach-tegra/reset-handler.S (revision 7ae9fb1b7ecbb5d85d07857943f677fd1a559b18)
19952f691SThomas Gleixner/* SPDX-License-Identifier: GPL-2.0-only */
29e32366fSJoseph Lo/*
39e32366fSJoseph Lo * Copyright (c) 2012, NVIDIA Corporation. All rights reserved.
49e32366fSJoseph Lo */
59e32366fSJoseph Lo
69e32366fSJoseph Lo#include <linux/init.h>
7a0524accSThierry Reding#include <linux/linkage.h>
89e32366fSJoseph Lo
97e10cf74SJon Hunter#include <soc/tegra/flowctrl.h>
10304664eaSThierry Reding#include <soc/tegra/fuse.h>
11304664eaSThierry Reding
1278ee399fSDmitry Osipenko#include <asm/assembler.h>
139e32366fSJoseph Lo#include <asm/asm-offsets.h>
14a0524accSThierry Reding#include <asm/cache.h>
159e32366fSJoseph Lo
169e32366fSJoseph Lo#include "iomap.h"
179e32366fSJoseph Lo#include "reset.h"
189e32366fSJoseph Lo#include "sleep.h"
199e32366fSJoseph Lo
209e32366fSJoseph Lo#define PMC_SCRATCH41	0x140
219e32366fSJoseph Lo
22*a2faac39SNick Desaulniers.arch armv7-a
23*a2faac39SNick Desaulniers
249e32366fSJoseph Lo#ifdef CONFIG_PM_SLEEP
259e32366fSJoseph Lo/*
269e32366fSJoseph Lo *	tegra_resume
279e32366fSJoseph Lo *
289e32366fSJoseph Lo *	  CPU boot vector when restarting the a CPU following
299e32366fSJoseph Lo *	  an LP2 transition. Also branched to by LP0 and LP1 resume after
309e32366fSJoseph Lo *	  re-enabling sdram.
3133d5c019SJoseph Lo *
3233d5c019SJoseph Lo *	r6: SoC ID
33c04c7754SJoseph Lo *	r8: CPU part number
349e32366fSJoseph Lo */
359e32366fSJoseph LoENTRY(tegra_resume)
36c04c7754SJoseph Lo	check_cpu_part_num 0xc09, r8, r9
37c04c7754SJoseph Lo	bleq	v7_invalidate_l1
389e32366fSJoseph Lo
399e32366fSJoseph Lo	cpu_id	r0
409e32366fSJoseph Lo	cmp	r0, #0				@ CPU0?
41a65dc10fSJoseph Lo THUMB(	it	ne )
429e32366fSJoseph Lo	bne	cpu_resume			@ no
439e32366fSJoseph Lo
44e4a68009SDmitry Osipenko	tegra_get_soc_id TEGRA_APB_MISC_BASE, r6
459e32366fSJoseph Lo	/* Are we on Tegra20? */
464b3e2edaSJoseph Lo	cmp	r6, #TEGRA20
479e32366fSJoseph Lo	beq	1f				@ Yes
489e32366fSJoseph Lo	/* Clear the flow controller flags for this CPU. */
49d70f7d31SDmitry Osipenko	cpu_to_csr_reg r3, r0
50ecc4d9daSJoseph Lo	mov32	r2, TEGRA_FLOW_CTRL_BASE
51d70f7d31SDmitry Osipenko	ldr	r1, [r2, r3]
529e32366fSJoseph Lo	/* Clear event & intr flag */
539e32366fSJoseph Lo	orr	r1, r1, \
549e32366fSJoseph Lo		#FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG
55ecc4d9daSJoseph Lo	movw	r0, #0x3FFD	@ enable, cluster_switch, immed, bitmaps
56ecc4d9daSJoseph Lo				@ & ext flags for CPU power mgnt
579e32366fSJoseph Lo	bic	r1, r1, r0
58d70f7d31SDmitry Osipenko	str	r1, [r2, r3]
599e32366fSJoseph Lo1:
609e32366fSJoseph Lo
61c04c7754SJoseph Lo	mov32	r9, 0xc09
62c04c7754SJoseph Lo	cmp	r8, r9
63d127e9c5SJoseph Lo	bne	end_ca9_scu_l2_resume
649e32366fSJoseph Lo#ifdef CONFIG_HAVE_ARM_SCU
659e32366fSJoseph Lo	/* enable SCU */
669e32366fSJoseph Lo	mov32	r0, TEGRA_ARM_PERIF_BASE
679e32366fSJoseph Lo	ldr	r1, [r0]
689e32366fSJoseph Lo	orr	r1, r1, #1
699e32366fSJoseph Lo	str	r1, [r0]
709e32366fSJoseph Lo#endif
7178ee399fSDmitry Osipenko	bl	tegra_resume_trusted_foundations
729e32366fSJoseph Lo
73b16cee70SRussell King#ifdef CONFIG_CACHE_L2X0
749e32366fSJoseph Lo	/* L2 cache resume & re-enable */
75b16cee70SRussell King	bl	l2c310_early_resume
76b16cee70SRussell King#endif
77d127e9c5SJoseph Loend_ca9_scu_l2_resume:
78d127e9c5SJoseph Lo	mov32	r9, 0xc0f
79d127e9c5SJoseph Lo	cmp	r8, r9
80d127e9c5SJoseph Lo	bleq	tegra_init_l2_for_a15
819e32366fSJoseph Lo
829e32366fSJoseph Lo	b	cpu_resume
839e32366fSJoseph LoENDPROC(tegra_resume)
8478ee399fSDmitry Osipenko
8578ee399fSDmitry Osipenko/*
8678ee399fSDmitry Osipenko *	tegra_resume_trusted_foundations
8778ee399fSDmitry Osipenko *
8878ee399fSDmitry Osipenko *	  Trusted Foundations firmware initialization.
8978ee399fSDmitry Osipenko *
9078ee399fSDmitry Osipenko *	Doesn't return if firmware presents.
9178ee399fSDmitry Osipenko *	Corrupted registers: r1, r2
9278ee399fSDmitry Osipenko */
9378ee399fSDmitry OsipenkoENTRY(tegra_resume_trusted_foundations)
9478ee399fSDmitry Osipenko	/* Check whether Trusted Foundations firmware presents. */
9578ee399fSDmitry Osipenko	mov32	r2, TEGRA_IRAM_BASE + TEGRA_IRAM_RESET_HANDLER_OFFSET
9678ee399fSDmitry Osipenko	ldr	r1, =__tegra_cpu_reset_handler_data_offset + \
9778ee399fSDmitry Osipenko							RESET_DATA(TF_PRESENT)
9878ee399fSDmitry Osipenko	ldr	r1, [r2, r1]
9978ee399fSDmitry Osipenko	cmp	r1, #0
10078ee399fSDmitry Osipenko	reteq	lr
10178ee399fSDmitry Osipenko
10278ee399fSDmitry Osipenko .arch_extension sec
10336dc3b1aSDmitry Osipenko	/*
10436dc3b1aSDmitry Osipenko	 * First call after suspend wakes firmware. No arguments required
10536dc3b1aSDmitry Osipenko	 * for some firmware versions. Downstream kernel of ASUS TF300T uses
10636dc3b1aSDmitry Osipenko	 * r0=3 for the wake-up notification.
10736dc3b1aSDmitry Osipenko	 */
10836dc3b1aSDmitry Osipenko	mov	r0, #3
10978ee399fSDmitry Osipenko	smc	#0
11078ee399fSDmitry Osipenko
11178ee399fSDmitry Osipenko	b	cpu_resume
11278ee399fSDmitry OsipenkoENDPROC(tegra_resume_trusted_foundations)
1139e32366fSJoseph Lo#endif
1149e32366fSJoseph Lo
1159e32366fSJoseph Lo	.align L1_CACHE_SHIFT
1169e32366fSJoseph LoENTRY(__tegra_cpu_reset_handler_start)
1179e32366fSJoseph Lo
1189e32366fSJoseph Lo/*
1199e32366fSJoseph Lo * __tegra_cpu_reset_handler:
1209e32366fSJoseph Lo *
1219e32366fSJoseph Lo * Common handler for all CPU reset events.
1229e32366fSJoseph Lo *
1239e32366fSJoseph Lo * Register usage within the reset handler:
1249e32366fSJoseph Lo *
125c34f30e5SStephen Warren *      Others: scratch
1264b3e2edaSJoseph Lo *      R6  = SoC ID
1279e32366fSJoseph Lo *      R7  = CPU present (to the OS) mask
1289e32366fSJoseph Lo *      R8  = CPU in LP1 state mask
1299e32366fSJoseph Lo *      R9  = CPU in LP2 state mask
1309e32366fSJoseph Lo *      R10 = CPU number
1319e32366fSJoseph Lo *      R11 = CPU mask
1329e32366fSJoseph Lo *      R12 = pointer to reset handler data
1339e32366fSJoseph Lo *
1349e32366fSJoseph Lo * NOTE: This code is copied to IRAM. All code and data accesses
1359e32366fSJoseph Lo *       must be position-independent.
1369e32366fSJoseph Lo */
1379e32366fSJoseph Lo
138dae84be5SDmitry Osipenko	.arm
1399e32366fSJoseph Lo	.align L1_CACHE_SHIFT
1409e32366fSJoseph LoENTRY(__tegra_cpu_reset_handler)
1419e32366fSJoseph Lo
1429e32366fSJoseph Lo	cpsid	aif, 0x13			@ SVC mode, interrupts disabled
143c34f30e5SStephen Warren
1444b3e2edaSJoseph Lo	tegra_get_soc_id TEGRA_APB_MISC_BASE, r6
1452af6597aSDmitry Osipenko
1462af6597aSDmitry Osipenko	adr	r12, __tegra_cpu_reset_handler_data
1472af6597aSDmitry Osipenko	ldr	r5, [r12, #RESET_DATA(TF_PRESENT)]
1482af6597aSDmitry Osipenko	cmp	r5, #0
1492af6597aSDmitry Osipenko	bne	after_errata
1502af6597aSDmitry Osipenko
151c34f30e5SStephen Warren#ifdef CONFIG_ARCH_TEGRA_2x_SOC
152c34f30e5SStephen Warrent20_check:
1534b3e2edaSJoseph Lo	cmp	r6, #TEGRA20
154c34f30e5SStephen Warren	bne	after_t20_check
155c34f30e5SStephen Warrent20_errata:
156c34f30e5SStephen Warren	# Tegra20 is a Cortex-A9 r1p1
157c34f30e5SStephen Warren	mrc	p15, 0, r0, c1, c0, 0   @ read system control register
158c34f30e5SStephen Warren	orr	r0, r0, #1 << 14        @ erratum 716044
159c34f30e5SStephen Warren	mcr	p15, 0, r0, c1, c0, 0   @ write system control register
160c34f30e5SStephen Warren	mrc	p15, 0, r0, c15, c0, 1  @ read diagnostic register
161c34f30e5SStephen Warren	orr	r0, r0, #1 << 4         @ erratum 742230
162c34f30e5SStephen Warren	orr	r0, r0, #1 << 11        @ erratum 751472
163c34f30e5SStephen Warren	mcr	p15, 0, r0, c15, c0, 1  @ write diagnostic register
164c34f30e5SStephen Warren	b	after_errata
165c34f30e5SStephen Warrenafter_t20_check:
166c34f30e5SStephen Warren#endif
167c34f30e5SStephen Warren#ifdef CONFIG_ARCH_TEGRA_3x_SOC
168c34f30e5SStephen Warrent30_check:
1694b3e2edaSJoseph Lo	cmp	r6, #TEGRA30
170c34f30e5SStephen Warren	bne	after_t30_check
171c34f30e5SStephen Warrent30_errata:
172c34f30e5SStephen Warren	# Tegra30 is a Cortex-A9 r2p9
173c34f30e5SStephen Warren	mrc	p15, 0, r0, c15, c0, 1  @ read diagnostic register
174c34f30e5SStephen Warren	orr	r0, r0, #1 << 6         @ erratum 743622
175c34f30e5SStephen Warren	orr	r0, r0, #1 << 11        @ erratum 751472
176c34f30e5SStephen Warren	mcr	p15, 0, r0, c15, c0, 1  @ write diagnostic register
177c34f30e5SStephen Warren	b	after_errata
178c34f30e5SStephen Warrenafter_t30_check:
179c34f30e5SStephen Warren#endif
180c34f30e5SStephen Warrenafter_errata:
1819e32366fSJoseph Lo	mrc	p15, 0, r10, c0, c0, 5		@ MPIDR
1829e32366fSJoseph Lo	and	r10, r10, #0x3			@ R10 = CPU number
1839e32366fSJoseph Lo	mov	r11, #1
1849e32366fSJoseph Lo	mov	r11, r11, lsl r10  		@ R11 = CPU mask
1859e32366fSJoseph Lo
1869e32366fSJoseph Lo#ifdef CONFIG_SMP
1879e32366fSJoseph Lo	/* Does the OS know about this CPU? */
1889e32366fSJoseph Lo	ldr	r7, [r12, #RESET_DATA(MASK_PRESENT)]
1899e32366fSJoseph Lo	tst	r7, r11 			@ if !present
1909e32366fSJoseph Lo	bleq	__die				@ CPU not present (to OS)
1919e32366fSJoseph Lo#endif
1929e32366fSJoseph Lo
1935b795d05SJoseph Lo	/* Waking up from LP1? */
1945b795d05SJoseph Lo	ldr	r8, [r12, #RESET_DATA(MASK_LP1)]
1955b795d05SJoseph Lo	tst	r8, r11				@ if in_lp1
1965b795d05SJoseph Lo	beq	__is_not_lp1
1975b795d05SJoseph Lo	cmp	r10, #0
1985b795d05SJoseph Lo	bne	__die				@ only CPU0 can be here
1995b795d05SJoseph Lo	ldr	lr, [r12, #RESET_DATA(STARTUP_LP1)]
2005b795d05SJoseph Lo	cmp	lr, #0
2015b795d05SJoseph Lo	bleq	__die				@ no LP1 startup handler
2025b795d05SJoseph Lo THUMB(	add	lr, lr, #1 )			@ switch to Thumb mode
2035b795d05SJoseph Lo	bx	lr
2045b795d05SJoseph Lo__is_not_lp1:
2055b795d05SJoseph Lo
2069e32366fSJoseph Lo	/* Waking up from LP2? */
2079e32366fSJoseph Lo	ldr	r9, [r12, #RESET_DATA(MASK_LP2)]
2089e32366fSJoseph Lo	tst	r9, r11				@ if in_lp2
2099e32366fSJoseph Lo	beq	__is_not_lp2
2109e32366fSJoseph Lo	ldr	lr, [r12, #RESET_DATA(STARTUP_LP2)]
2119e32366fSJoseph Lo	cmp	lr, #0
2129e32366fSJoseph Lo	bleq	__die				@ no LP2 startup handler
2139e32366fSJoseph Lo	bx	lr
2149e32366fSJoseph Lo
2159e32366fSJoseph Lo__is_not_lp2:
2169e32366fSJoseph Lo
2179e32366fSJoseph Lo#ifdef CONFIG_SMP
2189e32366fSJoseph Lo	/*
21933d5c019SJoseph Lo	 * Can only be secondary boot (initial or hotplug)
22033d5c019SJoseph Lo	 * CPU0 can't be here for Tegra20/30
2219e32366fSJoseph Lo	 */
22233d5c019SJoseph Lo	cmp	r6, #TEGRA114
22333d5c019SJoseph Lo	beq	__no_cpu0_chk
2249e32366fSJoseph Lo	cmp	r10, #0
2259e32366fSJoseph Lo	bleq	__die				@ CPU0 cannot be here
22633d5c019SJoseph Lo__no_cpu0_chk:
2279e32366fSJoseph Lo	ldr	lr, [r12, #RESET_DATA(STARTUP_SECONDARY)]
2289e32366fSJoseph Lo	cmp	lr, #0
2299e32366fSJoseph Lo	bleq	__die				@ no secondary startup handler
2309e32366fSJoseph Lo	bx	lr
2319e32366fSJoseph Lo#endif
2329e32366fSJoseph Lo
2339e32366fSJoseph Lo/*
2349e32366fSJoseph Lo * We don't know why the CPU reset. Just kill it.
2359e32366fSJoseph Lo * The LR register will contain the address we died at + 4.
2369e32366fSJoseph Lo */
2379e32366fSJoseph Lo
2389e32366fSJoseph Lo__die:
2399e32366fSJoseph Lo	sub	lr, lr, #4
2409e32366fSJoseph Lo	mov32	r7, TEGRA_PMC_BASE
2419e32366fSJoseph Lo	str	lr, [r7, #PMC_SCRATCH41]
2429e32366fSJoseph Lo
2439e32366fSJoseph Lo	mov32	r7, TEGRA_CLK_RESET_BASE
2449e32366fSJoseph Lo
2459e32366fSJoseph Lo	/* Are we on Tegra20? */
2464b3e2edaSJoseph Lo	cmp	r6, #TEGRA20
2479e32366fSJoseph Lo	bne	1f
2489e32366fSJoseph Lo
2499e32366fSJoseph Lo#ifdef CONFIG_ARCH_TEGRA_2x_SOC
2509e32366fSJoseph Lo	mov32	r0, 0x1111
2519e32366fSJoseph Lo	mov	r1, r0, lsl r10
2529e32366fSJoseph Lo	str	r1, [r7, #0x340]		@ CLK_RST_CPU_CMPLX_SET
2539e32366fSJoseph Lo#endif
2549e32366fSJoseph Lo1:
2559e32366fSJoseph Lo#ifdef CONFIG_ARCH_TEGRA_3x_SOC
2569e32366fSJoseph Lo	mov32	r6, TEGRA_FLOW_CTRL_BASE
2579e32366fSJoseph Lo
2589e32366fSJoseph Lo	cmp	r10, #0
2599e32366fSJoseph Lo	moveq	r1, #FLOW_CTRL_HALT_CPU0_EVENTS
2609e32366fSJoseph Lo	moveq	r2, #FLOW_CTRL_CPU0_CSR
2619e32366fSJoseph Lo	movne	r1, r10, lsl #3
2629e32366fSJoseph Lo	addne	r2, r1, #(FLOW_CTRL_CPU1_CSR-8)
2639e32366fSJoseph Lo	addne	r1, r1, #(FLOW_CTRL_HALT_CPU1_EVENTS-8)
2649e32366fSJoseph Lo
2659e32366fSJoseph Lo	/* Clear CPU "event" and "interrupt" flags and power gate
2669e32366fSJoseph Lo	   it when halting but not before it is in the "WFI" state. */
2679e32366fSJoseph Lo	ldr	r0, [r6, +r2]
2689e32366fSJoseph Lo	orr	r0, r0, #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG
2699e32366fSJoseph Lo	orr	r0, r0, #FLOW_CTRL_CSR_ENABLE
2709e32366fSJoseph Lo	str	r0, [r6, +r2]
2719e32366fSJoseph Lo
2729e32366fSJoseph Lo	/* Unconditionally halt this CPU */
2739e32366fSJoseph Lo	mov	r0, #FLOW_CTRL_WAITEVENT
2749e32366fSJoseph Lo	str	r0, [r6, +r1]
2759e32366fSJoseph Lo	ldr	r0, [r6, +r1]			@ memory barrier
2769e32366fSJoseph Lo
2779e32366fSJoseph Lo	dsb
2789e32366fSJoseph Lo	isb
2799e32366fSJoseph Lo	wfi					@ CPU should be power gated here
2809e32366fSJoseph Lo
2819e32366fSJoseph Lo	/* If the CPU didn't power gate above just kill it's clock. */
2829e32366fSJoseph Lo
2839e32366fSJoseph Lo	mov	r0, r11, lsl #8
2849e32366fSJoseph Lo	str	r0, [r7, #348]			@ CLK_CPU_CMPLX_SET
2859e32366fSJoseph Lo#endif
2869e32366fSJoseph Lo
2879e32366fSJoseph Lo	/* If the CPU still isn't dead, just spin here. */
2889e32366fSJoseph Lo	b	.
2899e32366fSJoseph LoENDPROC(__tegra_cpu_reset_handler)
2909e32366fSJoseph Lo
2919e32366fSJoseph Lo	.align L1_CACHE_SHIFT
2929e32366fSJoseph Lo	.type	__tegra_cpu_reset_handler_data, %object
2939e32366fSJoseph Lo	.globl	__tegra_cpu_reset_handler_data
2942af6597aSDmitry Osipenko	.globl	__tegra_cpu_reset_handler_data_offset
2952af6597aSDmitry Osipenko	.equ	__tegra_cpu_reset_handler_data_offset, \
2962af6597aSDmitry Osipenko					. - __tegra_cpu_reset_handler_start
2979e32366fSJoseph Lo__tegra_cpu_reset_handler_data:
2989e32366fSJoseph Lo	.rept   TEGRA_RESET_DATA_SIZE
2999e32366fSJoseph Lo	.long   0
3009e32366fSJoseph Lo	.endr
3019e32366fSJoseph Lo	.align L1_CACHE_SHIFT
3029e32366fSJoseph Lo
3039e32366fSJoseph LoENTRY(__tegra_cpu_reset_handler_end)
304