summaryrefslogtreecommitdiff
path: root/drivers/mmc/fsl_esdhc_spl.c
blob: 6d7c0cff22a5fd6794ceafc1ea6fd775e788cf7e (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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
// SPDX-License-Identifier: GPL-2.0+
/*
 * Copyright 2013 Freescale Semiconductor, Inc.
 */

#include <common.h>
#include <cpu_func.h>
#include <hang.h>
#include <mmc.h>
#include <malloc.h>

#ifndef CFG_SYS_MMC_U_BOOT_OFFS
extern uchar mmc_u_boot_offs[];
#endif

/*
 * The environment variables are written to just after the u-boot image
 * on SDCard, so we must read the MBR to get the start address and code
 * length of the u-boot image, then calculate the address of the env.
 */
#define ESDHC_BOOT_SIGNATURE_OFF 0x40
#define ESDHC_BOOT_SIGNATURE	0x424f4f54
#define ESDHC_BOOT_IMAGE_SIZE	0x48
#define ESDHC_BOOT_IMAGE_ADDR	0x50
#define MBRDBR_BOOT_SIG_55	0x1fe
#define MBRDBR_BOOT_SIG_AA	0x1ff


void mmc_spl_load_image(uint32_t offs, unsigned int size, void *vdst)
{
	uint blk_start, blk_cnt, err;

	struct mmc *mmc = find_mmc_device(0);
	if (!mmc) {
		puts("spl: mmc device not found!!\n");
		hang();
	}

	if (mmc_init(mmc)) {
		puts("MMC init failed\n");
		return;
	}

	blk_start = ALIGN(offs, mmc->read_bl_len) / mmc->read_bl_len;
	blk_cnt = ALIGN(size, mmc->read_bl_len) / mmc->read_bl_len;

	err = mmc->block_dev.block_read(&mmc->block_dev, blk_start, blk_cnt,
					vdst);
	if (err != blk_cnt) {
		puts("spl: mmc read failed!!\n");
		hang();
	}
}

/*
 * The main entry for mmc booting. It's necessary that SDRAM is already
 * configured and available since this code loads the main U-Boot image
 * from mmc into SDRAM and starts it from there.
 */

void __noreturn mmc_boot(void)
{
	__attribute__((noreturn)) void (*uboot)(void);
	uint blk_start, blk_cnt, err;
	uchar *tmp_buf;
	u32 blklen;
	u32 blk_off;
#ifndef CONFIG_FSL_CORENET
	uchar val;
#ifndef CONFIG_SPL_FSL_PBL
	u32 val32;
#endif
	uint i, byte_num;
	u32 sector;
#endif
	u32 offset, code_len;
	struct mmc *mmc;

	mmc = find_mmc_device(0);
	if (!mmc) {
		puts("spl: mmc device not found!!\n");
		hang();
	}

	if (mmc_init(mmc)) {
		puts("spl: mmc device init failed!\n");
		hang();
	}

	blklen = mmc->read_bl_len;
	if (blklen < 512)
		blklen = 512;
	tmp_buf = malloc(blklen);
	if (!tmp_buf) {
		puts("spl: malloc memory failed!!\n");
		hang();
	}

#ifdef CONFIG_FSL_CORENET
	offset = CFG_SYS_MMC_U_BOOT_OFFS;
#else
	sector = 0;
again:
	memset(tmp_buf, 0, blklen);

	/*
	* Read source addr from sd card
	*/
	blk_start = (sector * 512) / mmc->read_bl_len;
	blk_off = (sector * 512) % mmc->read_bl_len;
	blk_cnt = DIV_ROUND_UP(512,  mmc->read_bl_len);
	err = mmc->block_dev.block_read(&mmc->block_dev, blk_start, blk_cnt, tmp_buf);
	if (err != blk_cnt) {
		puts("spl: mmc read failed!!\n");
		hang();
	}

#ifdef CONFIG_SPL_FSL_PBL
	val = *(tmp_buf + blk_off + MBRDBR_BOOT_SIG_55);
	if (0x55 != val) {
		puts("spl: mmc MBR/DBR signature is not valid!!\n");
		hang();
	}
	val = *(tmp_buf + blk_off + MBRDBR_BOOT_SIG_AA);
	if (0xAA != val) {
		puts("spl: mmc MBR/DBR signature is not valid!!\n");
		hang();
	}
#else
	/*
	 * Booting from On-Chip ROM (eSDHC or eSPI), Document Number: AN3659, Rev. 2, 06/2012.
	 * Pre-PBL BootROMs (MPC8536E, MPC8569E, P2020, P1011, P1012, P1013, P1020, P1021, P1022)
	 * require custom BOOT signature on sector 0 and MBR/DBR signature is not required at all.
	 */
	byte_num = 4;
	val32 = 0;
	for (i = 0; i < byte_num; i++) {
		val = *(tmp_buf + blk_off + ESDHC_BOOT_SIGNATURE_OFF + i);
		val32 = (val32 << 8) + val;
	}
	if (val32 != ESDHC_BOOT_SIGNATURE) {
		/* BOOT signature may be on the first 24 sectors (each being 512 bytes) */
		if (++sector < 24)
			goto again;
		puts("spl: mmc BOOT signature is not valid!!\n");
		hang();
	}
#endif

	byte_num = 4;
	offset = 0;
	for (i = 0; i < byte_num; i++) {
		val = *(tmp_buf + blk_off + ESDHC_BOOT_IMAGE_ADDR + i);
		offset = (offset << 8) + val;
	}
#ifndef CFG_SYS_MMC_U_BOOT_OFFS
	offset += (ulong)&mmc_u_boot_offs - CONFIG_SPL_TEXT_BASE;
#else
	offset += CFG_SYS_MMC_U_BOOT_OFFS;
#endif
#endif
	/*
	* Load U-Boot image from mmc into RAM
	*/
	code_len = CFG_SYS_MMC_U_BOOT_SIZE;
	blk_start = offset / mmc->read_bl_len;
	blk_off = offset % mmc->read_bl_len;
	blk_cnt = ALIGN(code_len, mmc->read_bl_len) / mmc->read_bl_len + 1;
	if (blk_off) {
		err = mmc->block_dev.block_read(&mmc->block_dev,
						blk_start, 1, tmp_buf);
		if (err != 1) {
			puts("spl: mmc read failed!!\n");
			hang();
		}
		blk_start++;
	}
	err = mmc->block_dev.block_read(&mmc->block_dev, blk_start, blk_cnt,
					(uchar *)CFG_SYS_MMC_U_BOOT_DST +
					(blk_off ? (mmc->read_bl_len - blk_off) : 0));
	if (err != blk_cnt) {
		puts("spl: mmc read failed!!\n");
		free(tmp_buf);
		hang();
	}
	/*
	 * SDHC DMA may erase bytes at dst + bl_len - blk_off - 8
	 * due to unaligned access. So copy leading bytes from tmp_buf
	 * after SDHC DMA transfer.
	 */
	if (blk_off)
		memcpy((uchar *)CFG_SYS_MMC_U_BOOT_DST,
		       tmp_buf + blk_off, mmc->read_bl_len - blk_off);

	/*
	* Clean d-cache and invalidate i-cache, to
	* make sure that no stale data is executed.
	*/
	flush_cache(CFG_SYS_MMC_U_BOOT_DST, CFG_SYS_MMC_U_BOOT_SIZE);

	/*
	* Jump to U-Boot image
	*/
	uboot = (void *)CFG_SYS_MMC_U_BOOT_START;
	(*uboot)();
}