1 /*
2  * This file is subject to the terms and conditions of the GNU General Public
3  * License.  See the file "COPYING" in the main directory of this archive
4  * for more details.
5  *
6  * Copyright (C) 2004-2017 Cavium, Inc.
7  */
8 
9 
10 /*
11   We install this program at the bootvector:
12 ------------------------------------
13 	.set noreorder
14 	.set nomacro
15 	.set noat
16 reset_vector:
17 	dmtc0	$k0, $31, 0	# Save $k0 to DESAVE
18 	dmtc0	$k1, $31, 3	# Save $k1 to KScratch2
19 
20 	mfc0	$k0, $12, 0	# Status
21 	mfc0	$k1, $15, 1	# Ebase
22 
23 	ori	$k0, 0x84	# Enable 64-bit addressing, set
24 				# ERL (should already be set)
25 	andi	$k1, 0x3ff	# mask out core ID
26 
27 	mtc0	$k0, $12, 0	# Status
28 	sll	$k1, 5
29 
30 	lui	$k0, 0xbfc0
31 	cache	17, 0($0)	# Core-14345, clear L1 Dcache virtual
32 				# tags if the core hit an NMI
33 
34 	ld	$k0, 0x78($k0)	# k0 <- (bfc00078) pointer to the reset vector
35 	synci	0($0)		# Invalidate ICache to get coherent
36 				# view of target code.
37 
38 	daddu	$k0, $k0, $k1
39 	nop
40 
41 	ld	$k0, 0($k0)	# k0 <- core specific target address
42 	dmfc0	$k1, $31, 3	# Restore $k1 from KScratch2
43 
44 	beqz	$k0, wait_loop	# Spin in wait loop
45 	nop
46 
47 	jr	$k0
48 	nop
49 
50 	nop			# NOPs needed here to fill delay slots
51 	nop			# on endian reversal of previous instructions
52 
53 wait_loop:
54 	wait
55 	nop
56 
57 	b	wait_loop
58 	nop
59 
60 	nop
61 	nop
62 ------------------------------------
63 
64 0000000000000000 <reset_vector>:
65    0:	40baf800	dmtc0	k0,c0_desave
66    4:	40bbf803	dmtc0	k1,c0_kscratch2
67 
68    8:	401a6000	mfc0	k0,c0_status
69    c:	401b7801	mfc0	k1,c0_ebase
70 
71   10:	375a0084	ori	k0,k0,0x84
72   14:	337b03ff	andi	k1,k1,0x3ff
73 
74   18:	409a6000	mtc0	k0,c0_status
75   1c:	001bd940	sll	k1,k1,0x5
76 
77   20:	3c1abfc0	lui	k0,0xbfc0
78   24:	bc110000	cache	0x11,0(zero)
79 
80   28:	df5a0078	ld	k0,120(k0)
81   2c:	041f0000	synci	0(zero)
82 
83   30:	035bd02d	daddu	k0,k0,k1
84   34:	00000000	nop
85 
86   38:	df5a0000	ld	k0,0(k0)
87   3c:	403bf803	dmfc0	k1,c0_kscratch2
88 
89   40:	13400005	beqz	k0,58 <wait_loop>
90   44:	00000000	nop
91 
92   48:	03400008	jr	k0
93   4c:	00000000	nop
94 
95   50:	00000000	nop
96   54:	00000000	nop
97 
98 0000000000000058 <wait_loop>:
99   58:	42000020	wait
100   5c:	00000000	nop
101 
102   60:	1000fffd	b	58 <wait_loop>
103   64:	00000000	nop
104 
105   68:	00000000	nop
106   6c:	00000000	nop
107 
108  */
109 
110 #include <asm/octeon/cvmx-boot-vector.h>
111 
112 static unsigned long long _cvmx_bootvector_data[16] = {
113 	0x40baf80040bbf803ull,  /* patch low order 8-bits if no KScratch*/
114 	0x401a6000401b7801ull,
115 	0x375a0084337b03ffull,
116 	0x409a6000001bd940ull,
117 	0x3c1abfc0bc110000ull,
118 	0xdf5a0078041f0000ull,
119 	0x035bd02d00000000ull,
120 	0xdf5a0000403bf803ull,  /* patch low order 8-bits if no KScratch*/
121 	0x1340000500000000ull,
122 	0x0340000800000000ull,
123 	0x0000000000000000ull,
124 	0x4200002000000000ull,
125 	0x1000fffd00000000ull,
126 	0x0000000000000000ull,
127 	OCTEON_BOOT_MOVEABLE_MAGIC1,
128 	0 /* To be filled in with address of vector block*/
129 };
130 
131 /* 2^10 CPUs */
132 #define VECTOR_TABLE_SIZE (1024 * sizeof(struct cvmx_boot_vector_element))
133 
134 static void cvmx_boot_vector_init(void *mem)
135 {
136 	uint64_t kseg0_mem;
137 	int i;
138 
139 	memset(mem, 0, VECTOR_TABLE_SIZE);
140 	kseg0_mem = cvmx_ptr_to_phys(mem) | 0x8000000000000000ull;
141 
142 	for (i = 0; i < 15; i++) {
143 		uint64_t v = _cvmx_bootvector_data[i];
144 
145 		if (OCTEON_IS_OCTEON1PLUS() && (i == 0 || i == 7))
146 			v &= 0xffffffff00000000ull; /* KScratch not availble. */
147 		cvmx_write_csr(CVMX_MIO_BOOT_LOC_ADR, i * 8);
148 		cvmx_write_csr(CVMX_MIO_BOOT_LOC_DAT, v);
149 	}
150 	cvmx_write_csr(CVMX_MIO_BOOT_LOC_ADR, 15 * 8);
151 	cvmx_write_csr(CVMX_MIO_BOOT_LOC_DAT, kseg0_mem);
152 	cvmx_write_csr(CVMX_MIO_BOOT_LOC_CFGX(0), 0x81fc0000);
153 }
154 
155 /**
156  * Get a pointer to the per-core table of reset vector pointers
157  *
158  */
159 struct cvmx_boot_vector_element *cvmx_boot_vector_get(void)
160 {
161 	struct cvmx_boot_vector_element *ret;
162 
163 	ret = cvmx_bootmem_alloc_named_range_once(VECTOR_TABLE_SIZE, 0,
164 		(1ull << 32) - 1, 8, "__boot_vector1__", cvmx_boot_vector_init);
165 	return ret;
166 }
167 EXPORT_SYMBOL(cvmx_boot_vector_get);
168