summaryrefslogtreecommitdiffstats
path: root/arch/arm/cpu/arm926ejs/spear/spl_boot.c
blob: c846d758c9d3fd5376b1b419c5a139d494d9694a (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
/*
 * (C) Copyright 2000-2009
 * Vipin Kumar, ST Microelectronics, vipin.kumar@st.com
 *
 * Copyright (C) 2012 Stefan Roese <sr@denx.de>
 *
 * SPDX-License-Identifier:	GPL-2.0+
 */

#include <common.h>
#include <image.h>
#include <linux/compiler.h>
#include <asm/io.h>
#include <asm/arch/spr_defs.h>
#include <linux/mtd/st_smi.h>

static const char kernel_name[] = "Linux";
static const char loader_name[] = "U-Boot";

int image_check_header(image_header_t *hdr, const char *name)
{
	if (image_check_magic(hdr) &&
	    (!strncmp(image_get_name(hdr), name, strlen(name))) &&
	    image_check_hcrc(hdr)) {
		return 1;
	}
	return 0;
}

int image_check_data(image_header_t *hdr)
{
	if (image_check_dcrc(hdr))
		return 1;

	return 0;
}

/*
 * SNOR (Serial NOR flash) related functions
 */
void snor_init(void)
{
	struct smi_regs *const smicntl =
		(struct smi_regs * const)CONFIG_SYS_SMI_BASE;

	/* Setting the fast mode values. SMI working at 166/4 = 41.5 MHz */
	writel(HOLD1 | FAST_MODE | BANK_EN | DSEL_TIME | PRESCAL4,
	       &smicntl->smi_cr1);
}

static int snor_image_load(u8 *load_addr, void (**image_p)(void),
			   const char *image_name)
{
	image_header_t *header;

	/*
	 * Since calculating the crc in the SNOR flash does not
	 * work, we copy the image to the destination address
	 * minus the header size. And point the header to this
	 * new destination. This will not work for address 0
	 * of course.
	 */
	header = (image_header_t *)load_addr;
	memcpy((ulong *)(image_get_load(header) - sizeof(image_header_t)),
	       (const ulong *)load_addr,
	       image_get_data_size(header) + sizeof(image_header_t));
	header = (image_header_t *)(image_get_load(header) -
				    sizeof(image_header_t));

	if (image_check_header(header, image_name)) {
		if (image_check_data(header)) {
			/* Jump to boot image */
			*image_p = (void *)image_get_load(header);
			return 1;
		}
	}

	return 0;
}

static void boot_image(void (*image)(void))
{
	void (*funcp)(void) __noreturn = (void *)image;

	(*funcp)();
}

/*
 * spl_boot:
 *
 * All supported booting types of all supported SoCs are listed here.
 * Generic readback APIs are provided for each supported booting type
 * eg. nand_read_skip_bad
 */
u32 spl_boot(void)
{
	void (*image)(void);

#ifdef CONFIG_SPEAR_USBTTY
	plat_late_init();
	return 1;
#endif

	/*
	 * All the supported booting devices are listed here. Each of
	 * the booting type supported by the platform would define the
	 * macro xxx_BOOT_SUPPORTED to true.
	 */

	if (SNOR_BOOT_SUPPORTED && snor_boot_selected()) {
		/* SNOR-SMI initialization */
		snor_init();

		serial_puts("Booting via SNOR\n");
		/* Serial NOR booting */
		if (1 == snor_image_load((u8 *)CONFIG_SYS_UBOOT_BASE,
					    &image, loader_name)) {
			/* Platform related late initialasations */
			plat_late_init();

			/* Jump to boot image */
			serial_puts("Jumping to U-Boot\n");
			boot_image(image);
			return 1;
		}
	}

	if (NAND_BOOT_SUPPORTED && nand_boot_selected()) {
		/* NAND booting */
		/* Not ported from XLoader to SPL yet */
		return 0;
	}

	if (PNOR_BOOT_SUPPORTED && pnor_boot_selected()) {
		/* PNOR booting */
		/* Not ported from XLoader to SPL yet */
		return 0;
	}

	if (MMC_BOOT_SUPPORTED && mmc_boot_selected()) {
		/* MMC booting */
		/* Not ported from XLoader to SPL yet */
		return 0;
	}

	if (SPI_BOOT_SUPPORTED && spi_boot_selected()) {
		/* SPI booting */
		/* Not supported for any platform as of now */
		return 0;
	}

	if (I2C_BOOT_SUPPORTED && i2c_boot_selected()) {
		/* I2C booting */
		/* Not supported for any platform as of now */
		return 0;
	}

	/*
	 * All booting types without memory are listed as below
	 * Control has to be returned to BootROM in case of all
	 * the following booting scenarios
	 */

	if (USB_BOOT_SUPPORTED && usb_boot_selected()) {
		plat_late_init();
		return 1;
	}

	if (TFTP_BOOT_SUPPORTED && tftp_boot_selected()) {
		plat_late_init();
		return 1;
	}

	if (UART_BOOT_SUPPORTED && uart_boot_selected()) {
		plat_late_init();
		return 1;
	}

	/* Ideally, the control should not reach here. */
	hang();
}
OpenPOWER on IntegriCloud