summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-uniphier/lowlevel_init.S
blob: fd34a4a32193c361d669fb890b45b82a7e381777 (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
/*
 * Copyright (C) 2012-2015 Masahiro Yamada <yamada.masahiro@socionext.com>
 *
 * SPDX-License-Identifier:	GPL-2.0+
 */

#include <config.h>
#include <linux/linkage.h>
#include <linux/sizes.h>
#include <asm/system.h>
#include <mach/led.h>
#include <mach/arm-mpcore.h>
#include <mach/sbc-regs.h>
#include <mach/ssc-regs.h>

ENTRY(lowlevel_init)
	mov	r8, lr			@ persevere link reg across call

	/*
	 * The UniPhier Boot ROM loads SPL code to the L2 cache.
	 * But CPUs can only do instruction fetch now because start.S has
	 * cleared C and M bits.
	 * First we need to turn on MMU and Dcache again to get back
	 * data access to L2.
	 */
	mrc	p15, 0, r0, c1, c0, 0	@ SCTLR (System Control Register)
	orr	r0, r0, #(CR_C | CR_M)	@ enable MMU and Dcache
	mcr	p15, 0, r0, c1, c0, 0

#ifdef CONFIG_DEBUG_LL
	bl	setup_lowlevel_debug
#endif

	/*
	 * Now we are using the page table embedded in the Boot ROM.
	 * It is not handy since it is not a straight mapped table for sLD3.
	 * What we need to do next is to switch over to the page table in SPL.
	 */
	ldr	r3, =init_page_table	@ page table must be 16KB aligned

	/* Disable MMU and Dcache before switching Page Table */
	mrc	p15, 0, r0, c1, c0, 0	@ SCTLR (System Control Register)
	bic	r0, r0, #(CR_C | CR_M)	@ disable MMU and Dcache
	mcr	p15, 0, r0, c1, c0, 0

	bl	enable_mmu

#ifdef CONFIG_UNIPHIER_SMP
secondary_startup:
	/*
	 * Entry point for secondary CPUs
	 *
	 * The Boot ROM has already enabled MMU for the secondary CPUs as well
	 * as for the primary one.  The MMU table embedded in the Boot ROM
	 * prohibits the DRAM access, so it is impossible to bring the
	 * secondary CPUs into DRAM directly.  They must jump here into SPL,
	 * which is run on L2 cache.
	 *
	 * Boot Sequence
	 *  [primary CPU]                    [secondary CPUs]
	 *  start from Boot ROM             start from Boot ROM
	 *     jump to SPL                    sleep in Boot ROM
	 *  kick secondaries   ---(sev)--->    jump to SPL
	 *  jump to U-Boot main               sleep in SPL
	 *  jump to Linux
	 *  kick secondaries   ---(sev)--->    jump to Linux
	 */

	/* branch by CPU ID */
	mrc	p15, 0, r0, c0, c0, 5	@ MPIDR (Multiprocessor Affinity Register)
	and  	r0, r0, #0x3
	cmp	r0, #0x0
	beq	primary_cpu
	/* only for secondary CPUs */
	ldr	r1, =ROM_BOOT_ROMRSV2	@ The last data access to L2 cache
	mrc	p15, 0, r0, c1, c0, 0	@ SCTLR (System Control Register)
	orr	r0, r0, #CR_I		@ Enable ICache
	bic	r0, r0, #(CR_C | CR_M)	@ MMU and Dcache must be disabled
	mcr	p15, 0, r0, c1, c0, 0	@ before jumping to Linux
	mov	r0, #0
	str	r0, [r1]
	b	1f
	/*
	 * L2 cache is shared among all the CPUs and it might be disabled by
	 * the primary one.  Before that, the following 5 lines must be cached
	 * on the Icaches of the secondary CPUs.
	 */
0:	wfe				@ kicked by Linux
1:	ldr	r0, [r1]
	cmp	r0, #0
	bxne	r0			@ r0: Linux entry for secondary CPUs
	b	0b
primary_cpu:
	ldr	r1, =ROM_BOOT_ROMRSV2
	ldr	r0, =secondary_startup
	str	r0, [r1]
	ldr	r0, [r1]		@ make sure str is complete before sev
	sev				@ kick the secondary CPU
#endif

	bl	setup_init_ram		@ RAM area for temporary stack pointer

	mov	lr, r8			@ restore link
	mov	pc, lr			@ back to my caller
ENDPROC(lowlevel_init)

ENTRY(enable_mmu)
	mrc	p15, 0, r0, c2, c0, 2	@ TTBCR (Translation Table Base Control Register)
	bic	r0, r0, #0x37
	orr	r0, r0, #0x20		@ disable TTBR1
	mcr	p15, 0, r0, c2, c0, 2

	orr	r0, r3, #0x8		@ Outer Cacheability for table walks: WBWA
	mcr	p15, 0, r0, c2, c0, 0   @ TTBR0

	mov	r0, #0
	mcr	p15, 0, r0, c8, c7, 0	@ invalidate TLBs

	mov	r0, #-1			@ manager for all domains (No permission check)
	mcr	p15, 0, r0, c3, c0, 0   @ DACR (Domain Access Control Register)

	dsb
	isb
	/*
	 * MMU on:
	 * TLBs was already invalidated in "../start.S"
	 * So, we don't need to invalidate it here.
	 */
	mrc	p15, 0, r0, c1, c0, 0	@ SCTLR (System Control Register)
	orr	r0, r0, #(CR_C | CR_M)	@ MMU and Dcache enable
	mcr	p15, 0, r0, c1, c0, 0

	mov	pc, lr
ENDPROC(enable_mmu)

/*
 * For PH1-Pro4 or older SoCs, the size of WAY is 32KB.
 * It is large enough for tmp RAM.
 */
#define BOOT_RAM_SIZE    (SZ_32K)
#define BOOT_WAY_BITS    (0x00000100)   /* way 8 */

ENTRY(setup_init_ram)
	/*
	 * Touch to zero for the boot way
	 */
0:
	/*
	 * set SSCOQM, SSCOQAD, SSCOQSZ, SSCOQWN in this order
	 */
	ldr	r0, = 0x00408006	@ touch to zero with address range
	ldr	r1, = SSCOQM
	str	r0, [r1]
	ldr	r0, = (CONFIG_SPL_STACK - BOOT_RAM_SIZE)	@ base address
	ldr	r1, = SSCOQAD
	str	r0, [r1]
	ldr	r0, = BOOT_RAM_SIZE
	ldr	r1, = SSCOQSZ
	str	r0, [r1]
	ldr	r0, = BOOT_WAY_BITS
	ldr	r1, = SSCOQWN
	str	r0, [r1]
	ldr	r1, = SSCOPPQSEF
	ldr	r0, [r1]
	cmp	r0, #0			@ check if the command is successfully set
	bne	0b			@ try again if an error occurs

	ldr	r1, = SSCOLPQS
1:
	ldr	r0, [r1]
	cmp	r0, #0x4
	bne	1b			@ wait until the operation is completed
	str	r0, [r1]		@ clear the complete notification flag

	mov	pc, lr
ENDPROC(setup_init_ram)
OpenPOWER on IntegriCloud