xref: /linux/arch/arm/mach-tegra/reset-handler.S (revision a65dc10ffad1e041b4ad3559a026a8bb2b40b77e)
19e32366fSJoseph Lo/*
29e32366fSJoseph Lo * Copyright (c) 2012, NVIDIA Corporation. All rights reserved.
39e32366fSJoseph Lo *
49e32366fSJoseph Lo * This program is free software; you can redistribute it and/or modify it
59e32366fSJoseph Lo * under the terms and conditions of the GNU General Public License,
69e32366fSJoseph Lo * version 2, as published by the Free Software Foundation.
79e32366fSJoseph Lo *
89e32366fSJoseph Lo * This program is distributed in the hope it will be useful, but WITHOUT
99e32366fSJoseph Lo * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
109e32366fSJoseph Lo * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
119e32366fSJoseph Lo * more details.
129e32366fSJoseph Lo *
139e32366fSJoseph Lo * You should have received a copy of the GNU General Public License
149e32366fSJoseph Lo * along with this program.  If not, see <http://www.gnu.org/licenses/>.
159e32366fSJoseph Lo */
169e32366fSJoseph Lo
179e32366fSJoseph Lo#include <linux/linkage.h>
189e32366fSJoseph Lo#include <linux/init.h>
199e32366fSJoseph Lo
209e32366fSJoseph Lo#include <asm/cache.h>
219e32366fSJoseph Lo#include <asm/asm-offsets.h>
229e32366fSJoseph Lo#include <asm/hardware/cache-l2x0.h>
239e32366fSJoseph Lo
249e32366fSJoseph Lo#include "flowctrl.h"
259e32366fSJoseph Lo#include "iomap.h"
269e32366fSJoseph Lo#include "reset.h"
279e32366fSJoseph Lo#include "sleep.h"
289e32366fSJoseph Lo
299e32366fSJoseph Lo#define APB_MISC_GP_HIDREV	0x804
309e32366fSJoseph Lo#define PMC_SCRATCH41	0x140
319e32366fSJoseph Lo
329e32366fSJoseph Lo#define RESET_DATA(x)	((TEGRA_RESET_##x)*4)
339e32366fSJoseph Lo
349e32366fSJoseph Lo#ifdef CONFIG_PM_SLEEP
359e32366fSJoseph Lo/*
369e32366fSJoseph Lo *	tegra_resume
379e32366fSJoseph Lo *
389e32366fSJoseph Lo *	  CPU boot vector when restarting the a CPU following
399e32366fSJoseph Lo *	  an LP2 transition. Also branched to by LP0 and LP1 resume after
409e32366fSJoseph Lo *	  re-enabling sdram.
419e32366fSJoseph Lo */
429e32366fSJoseph LoENTRY(tegra_resume)
439e32366fSJoseph Lo	bl	v7_invalidate_l1
449e32366fSJoseph Lo
459e32366fSJoseph Lo	cpu_id	r0
469e32366fSJoseph Lo	cmp	r0, #0				@ CPU0?
47*a65dc10fSJoseph Lo THUMB(	it	ne )
489e32366fSJoseph Lo	bne	cpu_resume			@ no
499e32366fSJoseph Lo
509e32366fSJoseph Lo#ifdef CONFIG_ARCH_TEGRA_3x_SOC
519e32366fSJoseph Lo	/* Are we on Tegra20? */
529e32366fSJoseph Lo	mov32	r6, TEGRA_APB_MISC_BASE
539e32366fSJoseph Lo	ldr	r0, [r6, #APB_MISC_GP_HIDREV]
549e32366fSJoseph Lo	and	r0, r0, #0xff00
559e32366fSJoseph Lo	cmp	r0, #(0x20 << 8)
569e32366fSJoseph Lo	beq	1f				@ Yes
579e32366fSJoseph Lo	/* Clear the flow controller flags for this CPU. */
589e32366fSJoseph Lo	mov32	r2, TEGRA_FLOW_CTRL_BASE + FLOW_CTRL_CPU0_CSR	@ CPU0 CSR
599e32366fSJoseph Lo	ldr	r1, [r2]
609e32366fSJoseph Lo	/* Clear event & intr flag */
619e32366fSJoseph Lo	orr	r1, r1, \
629e32366fSJoseph Lo		#FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG
639e32366fSJoseph Lo	movw	r0, #0x0FFD	@ enable, cluster_switch, immed, & bitmaps
649e32366fSJoseph Lo	bic	r1, r1, r0
659e32366fSJoseph Lo	str	r1, [r2]
669e32366fSJoseph Lo1:
679e32366fSJoseph Lo#endif
689e32366fSJoseph Lo
699e32366fSJoseph Lo#ifdef CONFIG_HAVE_ARM_SCU
709e32366fSJoseph Lo	/* enable SCU */
719e32366fSJoseph Lo	mov32	r0, TEGRA_ARM_PERIF_BASE
729e32366fSJoseph Lo	ldr	r1, [r0]
739e32366fSJoseph Lo	orr	r1, r1, #1
749e32366fSJoseph Lo	str	r1, [r0]
759e32366fSJoseph Lo#endif
769e32366fSJoseph Lo
779e32366fSJoseph Lo	/* L2 cache resume & re-enable */
789e32366fSJoseph Lo	l2_cache_resume r0, r1, r2, l2x0_saved_regs_addr
799e32366fSJoseph Lo
809e32366fSJoseph Lo	b	cpu_resume
819e32366fSJoseph LoENDPROC(tegra_resume)
829e32366fSJoseph Lo#endif
839e32366fSJoseph Lo
849e32366fSJoseph Lo#ifdef CONFIG_CACHE_L2X0
859e32366fSJoseph Lo	.globl	l2x0_saved_regs_addr
869e32366fSJoseph Lol2x0_saved_regs_addr:
879e32366fSJoseph Lo	.long	0
889e32366fSJoseph Lo#endif
899e32366fSJoseph Lo
909e32366fSJoseph Lo	.align L1_CACHE_SHIFT
919e32366fSJoseph LoENTRY(__tegra_cpu_reset_handler_start)
929e32366fSJoseph Lo
939e32366fSJoseph Lo/*
949e32366fSJoseph Lo * __tegra_cpu_reset_handler:
959e32366fSJoseph Lo *
969e32366fSJoseph Lo * Common handler for all CPU reset events.
979e32366fSJoseph Lo *
989e32366fSJoseph Lo * Register usage within the reset handler:
999e32366fSJoseph Lo *
100c34f30e5SStephen Warren *      Others: scratch
101c34f30e5SStephen Warren *      R6  = SoC ID << 8
1029e32366fSJoseph Lo *      R7  = CPU present (to the OS) mask
1039e32366fSJoseph Lo *      R8  = CPU in LP1 state mask
1049e32366fSJoseph Lo *      R9  = CPU in LP2 state mask
1059e32366fSJoseph Lo *      R10 = CPU number
1069e32366fSJoseph Lo *      R11 = CPU mask
1079e32366fSJoseph Lo *      R12 = pointer to reset handler data
1089e32366fSJoseph Lo *
1099e32366fSJoseph Lo * NOTE: This code is copied to IRAM. All code and data accesses
1109e32366fSJoseph Lo *       must be position-independent.
1119e32366fSJoseph Lo */
1129e32366fSJoseph Lo
1139e32366fSJoseph Lo	.align L1_CACHE_SHIFT
1149e32366fSJoseph LoENTRY(__tegra_cpu_reset_handler)
1159e32366fSJoseph Lo
1169e32366fSJoseph Lo	cpsid	aif, 0x13			@ SVC mode, interrupts disabled
117c34f30e5SStephen Warren
118c34f30e5SStephen Warren	mov32	r6, TEGRA_APB_MISC_BASE
119c34f30e5SStephen Warren	ldr	r6, [r6, #APB_MISC_GP_HIDREV]
120c34f30e5SStephen Warren	and	r6, r6, #0xff00
121c34f30e5SStephen Warren#ifdef CONFIG_ARCH_TEGRA_2x_SOC
122c34f30e5SStephen Warrent20_check:
123c34f30e5SStephen Warren	cmp	r6, #(0x20 << 8)
124c34f30e5SStephen Warren	bne	after_t20_check
125c34f30e5SStephen Warrent20_errata:
126c34f30e5SStephen Warren	# Tegra20 is a Cortex-A9 r1p1
127c34f30e5SStephen Warren	mrc	p15, 0, r0, c1, c0, 0   @ read system control register
128c34f30e5SStephen Warren	orr	r0, r0, #1 << 14        @ erratum 716044
129c34f30e5SStephen Warren	mcr	p15, 0, r0, c1, c0, 0   @ write system control register
130c34f30e5SStephen Warren	mrc	p15, 0, r0, c15, c0, 1  @ read diagnostic register
131c34f30e5SStephen Warren	orr	r0, r0, #1 << 4         @ erratum 742230
132c34f30e5SStephen Warren	orr	r0, r0, #1 << 11        @ erratum 751472
133c34f30e5SStephen Warren	mcr	p15, 0, r0, c15, c0, 1  @ write diagnostic register
134c34f30e5SStephen Warren	b	after_errata
135c34f30e5SStephen Warrenafter_t20_check:
136c34f30e5SStephen Warren#endif
137c34f30e5SStephen Warren#ifdef CONFIG_ARCH_TEGRA_3x_SOC
138c34f30e5SStephen Warrent30_check:
139c34f30e5SStephen Warren	cmp	r6, #(0x30 << 8)
140c34f30e5SStephen Warren	bne	after_t30_check
141c34f30e5SStephen Warrent30_errata:
142c34f30e5SStephen Warren	# Tegra30 is a Cortex-A9 r2p9
143c34f30e5SStephen Warren	mrc	p15, 0, r0, c15, c0, 1  @ read diagnostic register
144c34f30e5SStephen Warren	orr	r0, r0, #1 << 6         @ erratum 743622
145c34f30e5SStephen Warren	orr	r0, r0, #1 << 11        @ erratum 751472
146c34f30e5SStephen Warren	mcr	p15, 0, r0, c15, c0, 1  @ write diagnostic register
147c34f30e5SStephen Warren	b	after_errata
148c34f30e5SStephen Warrenafter_t30_check:
149c34f30e5SStephen Warren#endif
150c34f30e5SStephen Warrenafter_errata:
1519e32366fSJoseph Lo	mrc	p15, 0, r10, c0, c0, 5		@ MPIDR
1529e32366fSJoseph Lo	and	r10, r10, #0x3			@ R10 = CPU number
1539e32366fSJoseph Lo	mov	r11, #1
1549e32366fSJoseph Lo	mov	r11, r11, lsl r10  		@ R11 = CPU mask
1559e32366fSJoseph Lo	adr	r12, __tegra_cpu_reset_handler_data
1569e32366fSJoseph Lo
1579e32366fSJoseph Lo#ifdef CONFIG_SMP
1589e32366fSJoseph Lo	/* Does the OS know about this CPU? */
1599e32366fSJoseph Lo	ldr	r7, [r12, #RESET_DATA(MASK_PRESENT)]
1609e32366fSJoseph Lo	tst	r7, r11 			@ if !present
1619e32366fSJoseph Lo	bleq	__die				@ CPU not present (to OS)
1629e32366fSJoseph Lo#endif
1639e32366fSJoseph Lo
1649e32366fSJoseph Lo#ifdef CONFIG_ARCH_TEGRA_2x_SOC
1659e32366fSJoseph Lo	/* Are we on Tegra20? */
166c34f30e5SStephen Warren	cmp	r6, #(0x20 << 8)
1679e32366fSJoseph Lo	bne	1f
1689e32366fSJoseph Lo	/* If not CPU0, don't let CPU0 reset CPU1 now that CPU1 is coming up. */
169c34f30e5SStephen Warren	mov32	r5, TEGRA_PMC_BASE
1709e32366fSJoseph Lo	mov	r0, #0
1719e32366fSJoseph Lo	cmp	r10, #0
172c34f30e5SStephen Warren	strne	r0, [r5, #PMC_SCRATCH41]
1739e32366fSJoseph Lo1:
1749e32366fSJoseph Lo#endif
1759e32366fSJoseph Lo
1769e32366fSJoseph Lo	/* Waking up from LP2? */
1779e32366fSJoseph Lo	ldr	r9, [r12, #RESET_DATA(MASK_LP2)]
1789e32366fSJoseph Lo	tst	r9, r11				@ if in_lp2
1799e32366fSJoseph Lo	beq	__is_not_lp2
1809e32366fSJoseph Lo	ldr	lr, [r12, #RESET_DATA(STARTUP_LP2)]
1819e32366fSJoseph Lo	cmp	lr, #0
1829e32366fSJoseph Lo	bleq	__die				@ no LP2 startup handler
1839e32366fSJoseph Lo	bx	lr
1849e32366fSJoseph Lo
1859e32366fSJoseph Lo__is_not_lp2:
1869e32366fSJoseph Lo
1879e32366fSJoseph Lo#ifdef CONFIG_SMP
1889e32366fSJoseph Lo	/*
1899e32366fSJoseph Lo	 * Can only be secondary boot (initial or hotplug) but CPU 0
1909e32366fSJoseph Lo	 * cannot be here.
1919e32366fSJoseph Lo	 */
1929e32366fSJoseph Lo	cmp	r10, #0
1939e32366fSJoseph Lo	bleq	__die				@ CPU0 cannot be here
1949e32366fSJoseph Lo	ldr	lr, [r12, #RESET_DATA(STARTUP_SECONDARY)]
1959e32366fSJoseph Lo	cmp	lr, #0
1969e32366fSJoseph Lo	bleq	__die				@ no secondary startup handler
1979e32366fSJoseph Lo	bx	lr
1989e32366fSJoseph Lo#endif
1999e32366fSJoseph Lo
2009e32366fSJoseph Lo/*
2019e32366fSJoseph Lo * We don't know why the CPU reset. Just kill it.
2029e32366fSJoseph Lo * The LR register will contain the address we died at + 4.
2039e32366fSJoseph Lo */
2049e32366fSJoseph Lo
2059e32366fSJoseph Lo__die:
2069e32366fSJoseph Lo	sub	lr, lr, #4
2079e32366fSJoseph Lo	mov32	r7, TEGRA_PMC_BASE
2089e32366fSJoseph Lo	str	lr, [r7, #PMC_SCRATCH41]
2099e32366fSJoseph Lo
2109e32366fSJoseph Lo	mov32	r7, TEGRA_CLK_RESET_BASE
2119e32366fSJoseph Lo
2129e32366fSJoseph Lo	/* Are we on Tegra20? */
2139e32366fSJoseph Lo	mov32	r6, TEGRA_APB_MISC_BASE
2149e32366fSJoseph Lo	ldr	r0, [r6, #APB_MISC_GP_HIDREV]
2159e32366fSJoseph Lo	and	r0, r0, #0xff00
2169e32366fSJoseph Lo	cmp	r0, #(0x20 << 8)
2179e32366fSJoseph Lo	bne	1f
2189e32366fSJoseph Lo
2199e32366fSJoseph Lo#ifdef CONFIG_ARCH_TEGRA_2x_SOC
2209e32366fSJoseph Lo	mov32	r0, 0x1111
2219e32366fSJoseph Lo	mov	r1, r0, lsl r10
2229e32366fSJoseph Lo	str	r1, [r7, #0x340]		@ CLK_RST_CPU_CMPLX_SET
2239e32366fSJoseph Lo#endif
2249e32366fSJoseph Lo1:
2259e32366fSJoseph Lo#ifdef CONFIG_ARCH_TEGRA_3x_SOC
2269e32366fSJoseph Lo	mov32	r6, TEGRA_FLOW_CTRL_BASE
2279e32366fSJoseph Lo
2289e32366fSJoseph Lo	cmp	r10, #0
2299e32366fSJoseph Lo	moveq	r1, #FLOW_CTRL_HALT_CPU0_EVENTS
2309e32366fSJoseph Lo	moveq	r2, #FLOW_CTRL_CPU0_CSR
2319e32366fSJoseph Lo	movne	r1, r10, lsl #3
2329e32366fSJoseph Lo	addne	r2, r1, #(FLOW_CTRL_CPU1_CSR-8)
2339e32366fSJoseph Lo	addne	r1, r1, #(FLOW_CTRL_HALT_CPU1_EVENTS-8)
2349e32366fSJoseph Lo
2359e32366fSJoseph Lo	/* Clear CPU "event" and "interrupt" flags and power gate
2369e32366fSJoseph Lo	   it when halting but not before it is in the "WFI" state. */
2379e32366fSJoseph Lo	ldr	r0, [r6, +r2]
2389e32366fSJoseph Lo	orr	r0, r0, #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG
2399e32366fSJoseph Lo	orr	r0, r0, #FLOW_CTRL_CSR_ENABLE
2409e32366fSJoseph Lo	str	r0, [r6, +r2]
2419e32366fSJoseph Lo
2429e32366fSJoseph Lo	/* Unconditionally halt this CPU */
2439e32366fSJoseph Lo	mov	r0, #FLOW_CTRL_WAITEVENT
2449e32366fSJoseph Lo	str	r0, [r6, +r1]
2459e32366fSJoseph Lo	ldr	r0, [r6, +r1]			@ memory barrier
2469e32366fSJoseph Lo
2479e32366fSJoseph Lo	dsb
2489e32366fSJoseph Lo	isb
2499e32366fSJoseph Lo	wfi					@ CPU should be power gated here
2509e32366fSJoseph Lo
2519e32366fSJoseph Lo	/* If the CPU didn't power gate above just kill it's clock. */
2529e32366fSJoseph Lo
2539e32366fSJoseph Lo	mov	r0, r11, lsl #8
2549e32366fSJoseph Lo	str	r0, [r7, #348]			@ CLK_CPU_CMPLX_SET
2559e32366fSJoseph Lo#endif
2569e32366fSJoseph Lo
2579e32366fSJoseph Lo	/* If the CPU still isn't dead, just spin here. */
2589e32366fSJoseph Lo	b	.
2599e32366fSJoseph LoENDPROC(__tegra_cpu_reset_handler)
2609e32366fSJoseph Lo
2619e32366fSJoseph Lo	.align L1_CACHE_SHIFT
2629e32366fSJoseph Lo	.type	__tegra_cpu_reset_handler_data, %object
2639e32366fSJoseph Lo	.globl	__tegra_cpu_reset_handler_data
2649e32366fSJoseph Lo__tegra_cpu_reset_handler_data:
2659e32366fSJoseph Lo	.rept	TEGRA_RESET_DATA_SIZE
2669e32366fSJoseph Lo	.long	0
2679e32366fSJoseph Lo	.endr
2689e32366fSJoseph Lo	.align L1_CACHE_SHIFT
2699e32366fSJoseph Lo
2709e32366fSJoseph LoENTRY(__tegra_cpu_reset_handler_end)
271