soc_info.c 13.1 KB
Newer Older
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
/*
 * Copyright (C) 2012  Henrik Nordstrom <henrik@henriknordstrom.net>
 * Copyright (C) 2015  Siarhei Siamashka <siarhei.siamashka@gmail.com>
 * Copyright (C) 2016  Bernhard Nortmann <bernhard.nortmann@web.de>
 *
 * 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, see <http://www.gnu.org/licenses/>.
 */

/**********************************************************************
 * SoC information and retrieval of soc_sram_info
 **********************************************************************/
#include "soc_info.h"

#include <stdio.h>
26
#include <string.h>
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

/*
 * The FEL code from BROM in A10/A13/A20 sets up two stacks for itself. One
 * at 0x2000 (and growing down) for the IRQ handler. And another one at 0x7000
 * (and also growing down) for the regular code. In order to use the whole
 * 32 KiB in the A1/A2 sections of SRAM, we need to temporarily move these
 * stacks elsewhere. And the addresses 0x7D00-0x7FFF contain something
 * important too (overwriting them kills FEL). On A10/A13/A20 we can use
 * the SRAM sections A3/A4 (0x8000-0xBFFF) for this purpose.
 */
sram_swap_buffers a10_a13_a20_sram_swap_buffers[] = {
	/* 0x1C00-0x1FFF (IRQ stack) */
	{ .buf1 = 0x1C00, .buf2 = 0xA400, .size = 0x0400 },
	/* 0x5C00-0x6FFF (Stack) */
	{ .buf1 = 0x5C00, .buf2 = 0xA800, .size = 0x1400 },
	/* 0x7C00-0x7FFF (Something important) */
	{ .buf1 = 0x7C00, .buf2 = 0xBC00, .size = 0x0400 },
	{ .size = 0 }  /* End of the table */
};

/*
 * A31 is very similar to A10/A13/A20, except that it has no SRAM at 0x8000.
 * So we use the SRAM section B at 0x20000-0x2FFFF instead. In the FEL mode,
 * the MMU translation table is allocated by the BROM at 0x20000. But we can
 * also safely use it as the backup storage because the MMU is temporarily
 * disabled during the time of the SPL execution.
 */
sram_swap_buffers a31_sram_swap_buffers[] = {
	{ .buf1 = 0x1800, .buf2 = 0x20000, .size = 0x800 },
	{ .buf1 = 0x5C00, .buf2 = 0x20800, .size = 0x8000 - 0x5C00 },
	{ .size = 0 }  /* End of the table */
};

/*
 * A64 has 32KiB of SRAM A at 0x10000 and a large SRAM C at 0x18000. SRAM A
 * and SRAM C reside in the address space back-to-back without any gaps, thus
63
64
65
66
 * representing a singe large contiguous area. The BROM FEL code memory areas
 * are the same as on A10/A13/A20, but just shifted by 0x10000.
 * We put the backup buffers towards the end of SRAM C, in a location that
 * is also available on the H5.
67
68
69
 */
sram_swap_buffers a64_sram_swap_buffers[] = {
	/* 0x11C00-0x11FFF (IRQ stack) */
70
	{ .buf1 = 0x11C00, .buf2 = 0x31400, .size = 0x0400 },
71
	/* 0x15C00-0x16FFF (Stack) */
72
	{ .buf1 = 0x15C00, .buf2 = 0x31800, .size = 0x1400 },
73
	/* 0x17C00-0x17FFF (Something important) */
74
	{ .buf1 = 0x17C00, .buf2 = 0x32c00, .size = 0x0400 },
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
	{ .size = 0 }  /* End of the table */
};

/*
 * Use the SRAM section at 0x44000 as the backup storage. This is the memory,
 * which is normally shared with the OpenRISC core (should we do an extra check
 * to ensure that this core is powered off and can't interfere?).
 */
sram_swap_buffers ar100_abusing_sram_swap_buffers[] = {
	{ .buf1 = 0x1800, .buf2 = 0x44000, .size = 0x800 },
	{ .buf1 = 0x5C00, .buf2 = 0x44800, .size = 0x8000 - 0x5C00 },
	{ .size = 0 }  /* End of the table */
};

/*
 * A80 has 40KiB SRAM A1 at 0x10000 where the SPL has to be loaded to. The
 * secure SRAM B at 0x20000 is used as backup area for FEL stacks and data.
 */
sram_swap_buffers a80_sram_swap_buffers[] = {
	{ .buf1 = 0x11800, .buf2 = 0x20000, .size = 0x800 },
	{ .buf1 = 0x15400, .buf2 = 0x20800, .size = 0x18000 - 0x15400 },
	{ .size = 0 }  /* End of the table */
};

Icenowy Zheng's avatar
Icenowy Zheng committed
99
100
101
102
103
104
105
106
/*
 * H6 has 32KiB of SRAM A at 0x20000 and a large SRAM C at 0x28000. SRAM A
 * and SRAM C reside in the address space back-to-back without any gaps, thus
 * representing a singe large contiguous area. Everything is the same as on
 * A10/A13/A20, but just shifted by 0x20000.
 */
sram_swap_buffers h6_sram_swap_buffers[] = {
	/* 0x21C00-0x21FFF (IRQ stack) */
107
	{ .buf1 = 0x21C00, .buf2 = 0x42400, .size = 0x0400 },
Icenowy Zheng's avatar
Icenowy Zheng committed
108
	/* 0x25C00-0x26FFF (Stack) */
109
	{ .buf1 = 0x25C00, .buf2 = 0x42800, .size = 0x1400 },
Icenowy Zheng's avatar
Icenowy Zheng committed
110
	/* 0x27C00-0x27FFF (Something important) */
111
	{ .buf1 = 0x27C00, .buf2 = 0x43c00, .size = 0x0400 },
Icenowy Zheng's avatar
Icenowy Zheng committed
112
113
114
	{ .size = 0 }  /* End of the table */
};

115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/*
 * V831 has 96KiB SRAM A1 at 0x20000 where the SPL has to be loaded to.
 * SRAM C is continuous with SRAM A1, and both SRAMs are tried to be used
 * by BROM. Memory space is allocated both from the start of SRAM A1 and
 * the end of SRAM C.
 * The start of SRAM C is in between these areas, and can serve as backup
 * of IRQ stack, which is inside the first 32KiB of SRAM A1. Other areas
 * that are critical on older SoCs seem to be already in SRAM C, which
 * we do not need to preserve.
 */
sram_swap_buffers v831_sram_swap_buffers[] = {
	{ .buf1 = 0x21000, .buf2 = 0x38000, .size = 0x1000 },
	{ .size = 0 }  /* End of the table */
};

Jernej Skrabec's avatar
Jernej Skrabec committed
130
131
/* H616 situation is the same as V831 one, except it has 32 KiB of SRAM A1. */
sram_swap_buffers h616_sram_swap_buffers[] = {
132
	{ .buf1 = 0x21000, .buf2 = 0x52a00, .size = 0x1000 },
Jernej Skrabec's avatar
Jernej Skrabec committed
133
134
135
	{ .size = 0 }  /* End of the table */
};

136
137
138
139
140
141
142
143
144
145
const watchdog_info wd_a10_compat = {
	.reg_mode = 0x01C20C94,
	.reg_mode_value = 3,
};

const watchdog_info wd_h3_compat = {
	.reg_mode = 0x01C20Cb8,
	.reg_mode_value = 1,
};

Andre Przywara's avatar
Andre Przywara committed
146
147
148
149
150
151
152
153
154
155
const watchdog_info wd_a80 = {
	.reg_mode = 0x06000CB8,
	.reg_mode_value = 1,
};

const watchdog_info wd_h6_compat = {
	.reg_mode = 0x030090b8,
	.reg_mode_value = 1,
};

156
157
158
soc_info_t soc_info_table[] = {
	{
		.soc_id       = 0x1623, /* Allwinner A10 */
159
		.name         = "A10",
160
161
162
		.scratch_addr = 0x1000,
		.thunk_addr   = 0xA200, .thunk_size = 0x200,
		.swap_buffers = a10_a13_a20_sram_swap_buffers,
Andre Przywara's avatar
Andre Przywara committed
163
		.sram_size    = 48 * 1024,
164
		.needs_l2en   = true,
165
		.sid_base     = 0x01C23800,
166
		.watchdog     = &wd_a10_compat,
167
	},{
168
		.soc_id       = 0x1625, /* Allwinner A10s, A13, R8 */
169
		.name         = "A13",
170
171
172
		.scratch_addr = 0x1000,
		.thunk_addr   = 0xA200, .thunk_size = 0x200,
		.swap_buffers = a10_a13_a20_sram_swap_buffers,
Andre Przywara's avatar
Andre Przywara committed
173
		.sram_size    = 48 * 1024,
174
		.needs_l2en   = true,
175
		.sid_base     = 0x01C23800,
Andre Przywara's avatar
Andre Przywara committed
176
		.watchdog     = &wd_a10_compat,
177
178
	},{
		.soc_id       = 0x1651, /* Allwinner A20 */
179
		.name         = "A20",
180
181
182
		.scratch_addr = 0x1000,
		.thunk_addr   = 0xA200, .thunk_size = 0x200,
		.swap_buffers = a10_a13_a20_sram_swap_buffers,
Andre Przywara's avatar
Andre Przywara committed
183
		.sram_size    = 48 * 1024,
184
		.sid_base     = 0x01C23800,
185
		.watchdog     = &wd_a10_compat,
186
187
	},{
		.soc_id       = 0x1650, /* Allwinner A23 */
188
		.name         = "A23",
189
190
191
		.scratch_addr = 0x1000,
		.thunk_addr   = 0x46E00, .thunk_size = 0x200,
		.swap_buffers = ar100_abusing_sram_swap_buffers,
Andre Przywara's avatar
Andre Przywara committed
192
		.sram_size    = 64 * 1024,
193
		.sid_base     = 0x01C23800,
Andre Przywara's avatar
Andre Przywara committed
194
		.watchdog     = &wd_h3_compat,
195
196
	},{
		.soc_id       = 0x1633, /* Allwinner A31 */
197
		.name         = "A31",
198
199
200
		.scratch_addr = 0x1000,
		.thunk_addr   = 0x22E00, .thunk_size = 0x200,
		.swap_buffers = a31_sram_swap_buffers,
Andre Przywara's avatar
Andre Przywara committed
201
		.sram_size    = 32 * 1024,
Andre Przywara's avatar
Andre Przywara committed
202
		.watchdog     = &wd_h3_compat,
203
204
	},{
		.soc_id       = 0x1667, /* Allwinner A33, R16 */
205
		.name         = "A33",
206
207
208
		.scratch_addr = 0x1000,
		.thunk_addr   = 0x46E00, .thunk_size = 0x200,
		.swap_buffers = ar100_abusing_sram_swap_buffers,
Andre Przywara's avatar
Andre Przywara committed
209
		.sram_size    = 32 * 1024,
210
		.sid_base     = 0x01C23800,
Andre Przywara's avatar
Andre Przywara committed
211
		.watchdog     = &wd_h3_compat,
212
213
	},{
		.soc_id       = 0x1689, /* Allwinner A64 */
214
		.name         = "A64",
215
216
		.spl_addr     = 0x10000,
		.scratch_addr = 0x11000,
217
		.thunk_addr   = 0x31200, .thunk_size = 0x200,
218
		.swap_buffers = a64_sram_swap_buffers,
219
		.sram_size    = 140 * 1024,
220
221
		.sid_base     = 0x01C14000,
		.sid_offset   = 0x200,
222
		.rvbar_reg    = 0x017000A0,
223
224
		/* Check L.NOP in the OpenRISC reset vector */
		.needs_smc_workaround_if_zero_word_at_addr = 0x40004,
Andre Przywara's avatar
Andre Przywara committed
225
		.watchdog     = &wd_h3_compat,
226
227
	},{
		.soc_id       = 0x1639, /* Allwinner A80 */
228
		.name         = "A80",
229
230
231
232
		.spl_addr     = 0x10000,
		.scratch_addr = 0x11000,
		.thunk_addr   = 0x23400, .thunk_size = 0x200,
		.swap_buffers = a80_sram_swap_buffers,
Andre Przywara's avatar
Andre Przywara committed
233
		.sram_size    = 40 * 1024,
234
235
		.sid_base     = 0X01C0E000,
		.sid_offset   = 0x200,
Andre Przywara's avatar
Andre Przywara committed
236
		.watchdog     = &wd_a80,
237
238
	},{
		.soc_id       = 0x1673, /* Allwinner A83T */
239
		.name         = "A83T",
240
		.scratch_addr = 0x1000,
Jack Mitchell's avatar
Jack Mitchell committed
241
		.mmu_tt_addr  = 0x44000,
242
243
		.thunk_addr   = 0x46E00, .thunk_size = 0x200,
		.swap_buffers = ar100_abusing_sram_swap_buffers,
Andre Przywara's avatar
Andre Przywara committed
244
		.sram_size    = 32 * 1024,
245
246
		.sid_base     = 0x01C14000,
		.sid_offset   = 0x200,
Andre Przywara's avatar
Andre Przywara committed
247
		.watchdog     = &wd_h3_compat,
248
249
	},{
		.soc_id       = 0x1680, /* Allwinner H3, H2+ */
250
		.name         = "H3",
251
252
253
254
		.scratch_addr = 0x1000,
		.mmu_tt_addr  = 0x8000,
		.thunk_addr   = 0xA200, .thunk_size = 0x200,
		.swap_buffers = a10_a13_a20_sram_swap_buffers,
Andre Przywara's avatar
Andre Przywara committed
255
		.sram_size    = 108 * 1024,
256
257
		.sid_base     = 0x01C14000,
		.sid_offset   = 0x200,
Icenowy Zheng's avatar
Icenowy Zheng committed
258
		.sid_fix      = true,
259
260
		/* Check L.NOP in the OpenRISC reset vector */
		.needs_smc_workaround_if_zero_word_at_addr = 0x40004,
261
		.watchdog     = &wd_h3_compat,
262
263
264
265
266
267
268
	},{
		.soc_id       = 0x1681, /* Allwinner V3s */
		.name         = "V3s",
		.scratch_addr = 0x1000,
		.mmu_tt_addr  = 0x8000,
		.thunk_addr   = 0xA200, .thunk_size = 0x200,
		.swap_buffers = a10_a13_a20_sram_swap_buffers,
Andre Przywara's avatar
Andre Przywara committed
269
		.sram_size    = 60 * 1024,
270
		.sid_base     = 0x01C23800,
Andre Przywara's avatar
Andre Przywara committed
271
		.watchdog     = &wd_h3_compat,
272
273
	},{
		.soc_id       = 0x1718, /* Allwinner H5 */
274
		.name         = "H5",
275
276
		.spl_addr     = 0x10000,
		.scratch_addr = 0x11000,
277
		.thunk_addr   = 0x31200, .thunk_size = 0x200,
278
		.swap_buffers = a64_sram_swap_buffers,
279
		.sram_size    = 140 * 1024,
280
281
		.sid_base     = 0x01C14000,
		.sid_offset   = 0x200,
282
		.rvbar_reg    = 0x017000A0,
283
284
		/* Check L.NOP in the OpenRISC reset vector */
		.needs_smc_workaround_if_zero_word_at_addr = 0x40004,
285
		.watchdog     = &wd_h3_compat,
286
287
	},{
		.soc_id       = 0x1701, /* Allwinner R40 */
288
		.name         = "R40",
289
290
291
		.scratch_addr = 0x1000,
		.thunk_addr   = 0xA200, .thunk_size = 0x200,
		.swap_buffers = a10_a13_a20_sram_swap_buffers,
Andre Przywara's avatar
Andre Przywara committed
292
		.sram_size    = 48 * 1024,
293
294
		.sid_base     = 0x01C1B000,
		.sid_offset   = 0x200,
Andre Przywara's avatar
Andre Przywara committed
295
		.watchdog     = &wd_a10_compat,
Icenowy Zheng's avatar
Icenowy Zheng committed
296
297
298
299
300
	},{
		.soc_id       = 0x1728, /* Allwinner H6 */
		.name         = "H6",
		.spl_addr     = 0x20000,
		.scratch_addr = 0x21000,
301
		.thunk_addr   = 0x42200, .thunk_size = 0x200,
Icenowy Zheng's avatar
Icenowy Zheng committed
302
		.swap_buffers = h6_sram_swap_buffers,
303
		.sram_size    = 144 * 1024,
Icenowy Zheng's avatar
Icenowy Zheng committed
304
305
306
307
308
		.sid_base     = 0x03006000,
		.sid_offset   = 0x200,
		.rvbar_reg    = 0x09010040,
		/* Check L.NOP in the OpenRISC reset vector */
		.needs_smc_workaround_if_zero_word_at_addr = 0x100004,
Andre Przywara's avatar
Andre Przywara committed
309
		.watchdog     = &wd_h6_compat,
310
311
312
313
314
315
316
	},{
		.soc_id       = 0x1817, /* Allwinner V831 */
		.name         = "V831",
		.spl_addr     = 0x20000,
		.scratch_addr = 0x21000,
		.thunk_addr   = 0x2A200, .thunk_size = 0x200,
		.swap_buffers = v831_sram_swap_buffers,
Andre Przywara's avatar
Andre Przywara committed
317
		.sram_size    = 228 * 1024,
318
319
		.sid_base     = 0x03006000,
		.sid_offset   = 0x200,
Andre Przywara's avatar
Andre Przywara committed
320
		.watchdog     = &wd_h6_compat,
Jernej Skrabec's avatar
Jernej Skrabec committed
321
322
323
324
325
	},{
		.soc_id       = 0x1823, /* Allwinner H616 */
		.name         = "H616",
		.spl_addr     = 0x20000,
		.scratch_addr = 0x21000,
326
		.thunk_addr   = 0x53a00, .thunk_size = 0x200,
Jernej Skrabec's avatar
Jernej Skrabec committed
327
		.swap_buffers = h616_sram_swap_buffers,
328
		.sram_size    = 207 * 1024,
Jernej Skrabec's avatar
Jernej Skrabec committed
329
330
331
		.sid_base     = 0x03006000,
		.sid_offset   = 0x200,
		.rvbar_reg    = 0x09010040,
Andre Przywara's avatar
Andre Przywara committed
332
		.watchdog     = &wd_h6_compat,
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
	},{
		.swap_buffers = NULL /* End of the table */
	}
};

/*
 * This generic record assumes BROM with similar properties to A10/A13/A20/A31,
 * but no extra SRAM sections beyond 0x8000. It also assumes that the IRQ
 * handler stack usage never exceeds 0x400 bytes.
 *
 * The users may or may not hope that the 0x7000-0x8000 area is also unused
 * by the BROM and re-purpose it for the SPL stack.
 *
 * The size limit for the ".text + .data" sections is ~21 KiB.
 */
sram_swap_buffers generic_sram_swap_buffers[] = {
	{ .buf1 = 0x1C00, .buf2 = 0x5800, .size = 0x400 },
	{ .size = 0 }  /* End of the table */
};

soc_info_t generic_soc_info = {
	.scratch_addr = 0x1000,
	.thunk_addr   = 0x5680, .thunk_size = 0x180,
	.swap_buffers = generic_sram_swap_buffers,
};

/* functions to retrieve SoC information */

soc_info_t *get_soc_info_from_id(uint32_t soc_id)
{
363
	soc_info_t *soc, *result = NULL;
364

365
366
367
	for (soc = soc_info_table; soc->swap_buffers; soc++)
		if (soc->soc_id == soc_id) {
			result = soc;
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
			break;
		}

	if (!result) {
		printf("Warning: no 'soc_sram_info' data for your SoC (id=%04X)\n",
		       soc_id);
		result = &generic_soc_info;
	}
	return result;
}

soc_info_t *get_soc_info_from_version(struct aw_fel_version *buf)
{
	return get_soc_info_from_id(buf->soc_id);
}
383
384
385

void get_soc_name_from_id(soc_name_t buffer, uint32_t soc_id)
{
386
387
388
389
	soc_info_t *soc;
	for (soc = soc_info_table; soc->swap_buffers; soc++)
		if (soc->soc_id == soc_id && soc->name != NULL) {
			strncpy(buffer, soc->name, sizeof(soc_name_t) - 1);
390
391
392
393
394
395
			return;
		}

	/* unknown SoC (or name string missing), use the hexadecimal ID */
	snprintf(buffer, sizeof(soc_name_t) - 1, "0x%04X", soc_id);
}