summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/headsmp-t3.S
blob: 7eb5c42765fdbc370f04dbbf3920ef6b08e631f9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
/*
 * arch/arm/mach-tegra/headsmp-t2.S
 *
 * SMP initialization routines for Tegra3 SoCs
 *
 * Copyright (c) 2009-2011, NVIDIA Corporation.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#include <linux/linkage.h>
#include <linux/init.h>

#include <asm/assembler.h>
#include <asm/domain.h>
#include <asm/ptrace.h>
#include <asm/cache.h>

#include <mach/iomap.h>
#include <mach/io.h>

#include "power.h"
#include "power-macros.S"

#define TTB_FLAGS 0x6A	@ IRGN_WBWA, OC_RGN_WBWA, S, NOS

#define DEBUG_HOTPLUG_STARTUP	0	/* Nonzero for hotplug startup debug */
#define DEBUG_LP2_STARTUP	0	/* Nonzero for LP2 startup debug */

#define PMC_DPD_SAMPLE	0x20
#define PMC_DPD_ENABLE	0x24
#define PMC_SCRATCH39	0x138
#define CLK_RESET_PLLX_BASE     0xe0
#define CLK_RESET_PLLX_MISC     0xe4
#define CLK_RESET_PLLP_BASE     0xa0
#define CLK_RESET_PLLP_OUTA     0xa4
#define CLK_RESET_PLLP_OUTB     0xa8
#define CLK_RESET_PLLP_MISC     0xac

/*        .section ".cpuinit.text", "ax"*/

/*
 *	__restart_plls
 *
 *	  Loads the saved PLLX and PLLP parameters into the PLLs, to
 *	  allow them to stabilize while the rest of the CPU state is restored.
 *	  Should be called after the MMU is enabled. Jumps directly
 *	  to __cortex_a9_restore
 */
	.align L1_CACHE_SHIFT
__restart_plls:
	cpu_id	r0
	cmp	r0, #0
	bne	__cortex_a9_restore
	mov32	r0, tegra_sctx
	mov32	r3, (TEGRA_CLK_RESET_BASE-IO_PPSB_PHYS+IO_PPSB_VIRT)
	mov32	r4, (TEGRA_TMRUS_BASE-IO_PPSB_PHYS+IO_PPSB_VIRT)

	ldr	r1, [r0, #0x0]	@ pllx_misc
	ldr	r2, [r0, #0x4]	@ pllx_base
	str	r1, [r3, #CLK_RESET_PLLX_MISC]
	str	r2, [r3, #CLK_RESET_PLLX_BASE]

	ldr	r1, [r0, #0x8]	@ pllp_misc
	ldr	r2, [r0, #0xc]	@ pllp_base
	str	r1, [r3, #CLK_RESET_PLLP_MISC]
	str	r2, [r3, #CLK_RESET_PLLP_BASE]

	ldr	r1, [r0, #0x10]	@ pllp_outa
	ldr	r2, [r0, #0x14]	@ pllp_outb
	str	r1, [r3, #CLK_RESET_PLLP_OUTA]
	str	r2, [r3, #CLK_RESET_PLLP_OUTB]

	/* record the time that PLLX and PLLP will be stable */
	ldr	r1, [r4]
	add	r1, r1, #300
	str	r1, [r0, #0x18]	@ pll_timeout
	/* FIXME: need to record actual power transition here */
	mov	r0, #0
	b	__cortex_a9_l2x0_restart
ENDPROC(__restart_plls)

/*
 *	tegra_lp2_startup
 *
 *	  Secondary CPU boot vector when restarting the master CPU following
 *	  an LP2 idle transition. Re-enable coresight access, re-enable
 *	  MMU, re-start PLLX, restore processor context.
 */
	.align L1_CACHE_SHIFT
ENTRY(tegra_lp2_startup)
	setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9

	mov32	r0, TEGRA_TMRUS_BASE
	ldr	r1, [r0]
	mov32	r0, TEGRA_PMC_BASE
	str	r1, [r0, #PMC_SCRATCH39]	@ save off exact lp2 exit time
	mov	r1, #0
	str	r1, [r0, #PMC_DPD_SAMPLE]
	str	r1, [r0, #PMC_DPD_ENABLE]

	bl	__invalidate_cpu_state
	bl	__enable_coresite_access

#if	DEBUG_LP2_STARTUP
	b	.
#endif
	@ Clear the flow controller flags for this CPU.
	cpu_id	r0
	subs	r0, r0, #1
	movmi	r2, #FLOW_CTLR_CPU_CSR		@ CPU0 CSR
	movpl 	r2, r0, lsl #3
	addpl	r2, r2, #FLOW_CTLR_CPU1_CSR	@ CPUn CSR, n == 1,2,3
	mov32	r4, TEGRA_FLOW_CTRL_BASE
	ldr	r1, [r4, +r2]
	orr	r1, r1, #(1 << 15) | (1 << 14)	@ write to clear event & intr
	movw	r0, #0x0FFD	@ enable, cluster_switch, immed, & bitmaps
	bic	r1, r1, r0
	str	r1, [r4, +r2]

	dsb
	mrc	p15, 0, r0, c1, c0, 1
	orr	r0, r0, #(1 << 6) | (1 << 0)	@ re-enable coherency
	mcr	p15, 0, r0, c1, c0, 1
	dsb

	/* Set power state to normal in scu power status register. */
	cpu_id	r0
	mov32	r1, (TEGRA_ARM_PERIF_BASE+0x8)
	ldrb	r4, [r1, r0]
	bic	r4, r4, #3
	strb	r4, [r1, r0]
	dsb

	/* enable SCU */
	mov32	r0, TEGRA_ARM_PERIF_BASE
	ldr	r1, [r0]
	orr	r1, r1, #1
	str	r1, [r0]
	dsb

#ifdef CONFIG_TRUSTED_FOUNDATIONS
	/* wake up */
	smc	0
#endif

	adr	r4, __tegra_lp2_data
	ldmia	r4, {r5, r7, r12}
	mov	r1, r12			@ ctx_restore = __cortex_a9_restore
	sub	r4, r4, r5
	ldr	r0, [r7, r4]		@ pgdir = tegra_pgd_phys
	b	__return_to_virtual
ENDPROC(tegra_lp2_startup)
	.type	__tegra_lp2_data, %object
__tegra_lp2_data:
	.long	.
	.long	tegra_pgd_phys
	.long	__restart_plls
	.size	__tegra_lp2_data, . - __tegra_lp2_data

#ifdef CONFIG_HOTPLUG_CPU
/*
 *	tegra_hotplug_startup
 *
 *	  Secondary CPU boot vector when restarting a CPU following a
 *	  hot-unplug. Uses the page table created by smp_prepare_cpus and
 *	  stored in tegra_pgd_phys as the safe page table for
 *	  __return_to_virtual, and jumps directly to __cortex_a9_restore.
 */
	.align L1_CACHE_SHIFT
ENTRY(tegra_hotplug_startup)
#if	DEBUG_HOTPLUG_STARTUP
	b	.
#endif
	setmode	PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9
	bl	__invalidate_cpu_state
	enable_coresite r1
	cpu_id	r0
	subs	r1, r0, #1
#ifdef	DEBUG
	bmi	.			@ should never come here for CPU0
#endif
	mov	r3, r1, lsl #3
	add	r3, r3, #0x18	 	@ CPUn CSR offset, n>0
	mov32	r2, TEGRA_FLOW_CTRL_BASE

	@ Clear the flow controller flags for this CPU.
	ldr	r1, [r2, r3]
	orr	r1, r1, #(1 << 15) | (1 << 14)	@ write to clear event & intr
	movw	r0, #0x0FFD	@ enable, cluster_switch, immed, & bitmaps
	bic	r1, r1, r0
	str	r1, [r2, r3]

	/* most of the below is a retread of what happens in __v7_setup and
	 * secondary_startup, to get the MMU re-enabled and to branch
	 * to secondary_kernel_startup */
	mrc	p15, 0, r0, c1, c0, 1
	orr	r0, r0, #(1 << 6) | (1 << 0)	@ re-enable coherency
	mcr	p15, 0, r0, c1, c0, 1
	dsb

	/* Set power state to normal in scu power status register. */
	cpu_id	r0
	mov32	r1, (TEGRA_ARM_PERIF_BASE+0x8)
	ldrb	r4, [r1, r0]
	bic	r4, r4, #3
	strb	r4, [r1, r0]
	dsb

	adr	r4, __tegra_hotplug_data
	ldmia	r4, {r5, r7, r12}
	mov	r1, r12			@ ctx_restore = __cortex_a9_restore
	sub	r4, r4, r5
	ldr	r0, [r7, r4]		@ pgdir = secondary_data.pgdir
	b	__return_to_virtual
ENDPROC(tegra_hotplug_startup)


	.type	__tegra_hotplug_data, %object
__tegra_hotplug_data:
	.long	.
	.long	tegra_pgd_phys
	.long	__cortex_a9_restore
	.size	__tegra_hotplug_data, . - __tegra_hotplug_data
#endif

/*
 *	tegra_cpu_dynamic_power_init
 *
 *	  Confirgure tegra-specific CPU power-gating.
 */

	.align L1_CACHE_SHIFT
ENTRY(tegra_cpu_dynamic_power_init)
#ifndef CONFIG_TRUSTED_FOUNDATIONS
	//TL : moved to secure
	mrc	p15, 0, r0, c0, c0, 5	@ MPIDR
	tst	r0, #(0xF<<8)		@ cluster mask
	mrc	p15, 0, r0, c15, c0, 0	@ power control
	bic	r0, r0, #(7<<8)		@ clear MAXCLKLATENCY field
	orr	r0, r0, #1		@ enable dynamic clock gating
	orreq	r0, r0, #(3<<8)		@ set MAXCLKLATENCY to 3 on G
	orrne	r0, r0, #(2<<8)		@ set MAXCLKLATENCY to 2 on LP
	mcr	p15, 0, r0, c15, c0, 0	@ power control
#endif
	bx	lr
ENDPROC(tegra_cpu_dynamic_power_init)