summaryrefslogtreecommitdiffstats
path: root/arch/arm/boards/raspberry-pi/lowlevel.c
blob: 40d36f0cff782a3e813928e2699d2584f92c0de2 (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
// SPDX-License-Identifier: GPL-2.0-only

#include <asm/barebox-arm.h>
#include <asm/cache.h>
#include <common.h>
#include <linux/sizes.h>
#include <asm/unaligned.h>
#include <mach/platform.h>
#include <debug_ll.h>
#include <mach/mbox.h>
#include <of.h>

#include "lowlevel.h"

static void copy_vc_fdt(void *dest, void *src, unsigned long max_size)
{
	struct fdt_header *oftree_src = src;
	struct fdt_header *oftree_dest = dest;
	unsigned long size;

	if (!src) {
		oftree_dest->magic = cpu_to_be32(VIDEOCORE_FDT_ERROR);
		oftree_dest->totalsize = cpu_to_be32(0);
		return;
	}

	size = be32_to_cpu(oftree_src->totalsize);
	if (size > max_size) {
		oftree_dest->magic = cpu_to_be32(VIDEOCORE_FDT_ERROR);
		/* Save an error code after the magic value for easier
		 * debugging. We can't print out anything this early */
		oftree_dest->totalsize = cpu_to_be32(ENOMEM);
		return;
	}

	memmove(dest, src, size);
}

/* A pointer to the FDT created by VideoCore was passed to us in x0/r2. We
 * reserve some memory just above the region used for Barebox and copy
 * this FDT there. We fetch it from there later in rpi_devices_init().
 */
#define rpi_stack_top(memsize) \
	arm_mem_stack_top(BCM2835_SDRAM_BASE, BCM2835_SDRAM_BASE + memsize - VIDEOCORE_FDT_SZ)

static inline void start_raspberry_pi(unsigned long memsize, void *fdt,
								void *vc_fdt)
{
	unsigned long endmem = rpi_stack_top(memsize);

	copy_vc_fdt((void *)endmem, vc_fdt, VIDEOCORE_FDT_SZ);

	fdt += get_runtime_offset();

	barebox_arm_entry(BCM2835_SDRAM_BASE, endmem - BCM2835_SDRAM_BASE, fdt);
}

#ifdef CONFIG_CPU_V8
#define RPI_ENTRY_FUNCTION(name, memsize, fdt) \
	ENTRY_FUNCTION_WITHSTACK(name, rpi_stack_top(memsize), fdt, __x1, __x2)
#else
#define RPI_ENTRY_FUNCTION(name, memsize, fdt) \
	ENTRY_FUNCTION_WITHSTACK(name, rpi_stack_top(memsize), __r0, __r1, fdt)
#endif

extern char __dtb_z_bcm2835_rpi_start[];
extern char __dtb_z_bcm2836_rpi_2_start[];
extern char __dtb_z_bcm2837_rpi_3_start[];
extern char __dtb_z_bcm2837_rpi_cm3_start[];

RPI_ENTRY_FUNCTION(start_raspberry_pi1, SZ_128M, fdt)
{
	arm_cpu_lowlevel_init();

	start_raspberry_pi(SZ_128M, __dtb_z_bcm2835_rpi_start, (void *)fdt);
}

RPI_ENTRY_FUNCTION(start_raspberry_pi2, SZ_512M, fdt)
{
	arm_cpu_lowlevel_init();

	start_raspberry_pi(SZ_512M, __dtb_z_bcm2836_rpi_2_start, (void *)fdt);
}

RPI_ENTRY_FUNCTION(start_raspberry_pi3, SZ_512M, fdt)
{
	arm_cpu_lowlevel_init();

	start_raspberry_pi(SZ_512M, __dtb_z_bcm2837_rpi_3_start, (void *)fdt);
}

RPI_ENTRY_FUNCTION(start_raspberry_pi_cm3, SZ_512M, fdt)
{
	arm_cpu_lowlevel_init();

	start_raspberry_pi(SZ_512M, __dtb_z_bcm2837_rpi_cm3_start, (void *)fdt);
}

#define DT_IF_ENABLED(dt, cfg) \
	(IS_ENABLED(cfg) ? (dt) : NULL)

static void *rpi_get_board_fdt(int rev)
{
	if (!(rev & 0x800000))
		return DT_IF_ENABLED(__dtb_z_bcm2835_rpi_start, CONFIG_MACH_RPI);

	switch (((rev >> 4) & 0xff)) {
	case BCM2835_BOARD_REV_A:
	case BCM2835_BOARD_REV_B:
	case BCM2835_BOARD_REV_A_PLUS:
	case BCM2835_BOARD_REV_B_PLUS:
	case BCM2835_BOARD_REV_CM1:
	case BCM2835_BOARD_REV_ZERO:
	case BCM2835_BOARD_REV_ZERO_W:
		return DT_IF_ENABLED(__dtb_z_bcm2835_rpi_start, CONFIG_MACH_RPI);

	case BCM2836_BOARD_REV_2_B:
		return DT_IF_ENABLED(__dtb_z_bcm2836_rpi_2_start, CONFIG_MACH_RPI2);

	case BCM2837_BOARD_REV_3_B:
	case BCM2837B0_BOARD_REV_3B_PLUS:
	case BCM2837B0_BOARD_REV_3A_PLUS:
	case BCM2837B0_BOARD_REV_ZERO_2:
		return DT_IF_ENABLED(__dtb_z_bcm2837_rpi_3_start, CONFIG_MACH_RPI3);

	case BCM2837_BOARD_REV_CM3:
	case BCM2837B0_BOARD_REV_CM3_PLUS:
		return DT_IF_ENABLED(__dtb_z_bcm2837_rpi_cm3_start, CONFIG_MACH_RPI_CM3);
	}

	return NULL;
}

RPI_ENTRY_FUNCTION(start_raspberry_pi_generic, SZ_128M, vc_fdt)
{
	void *fdt = NULL;
	ssize_t memsize;
	int rev;

	arm_cpu_lowlevel_init();

	debug_ll_init();

	putc_ll('>');

	relocate_to_current_adr();
	setup_c();

	memsize = rpi_get_arm_mem();
	if (memsize < 0) {
		pr_warn("mbox: failed to query ARM memory size. 128M assumed.\n");
		memsize = SZ_128M;
	}

	rev = rpi_get_board_rev();
	if (rev >= 0) {
		pr_debug("Detected revision %08x\n", rev);
		fdt = rpi_get_board_fdt(rev);
	}

	if (!fdt) {
		fdt = (void *)vc_fdt;

		pr_warn("Unknown Rpi board with rev %08x.\n", rev);

		if (get_unaligned_be32(fdt) != 0xd00dfeed)
			panic("No suitable built-in or videocore-supplied DT\n");
	}

	start_raspberry_pi(memsize, fdt, (void *)vc_fdt);
}