2 * TI OMAP3 boot ROM emulation. Based on information in the OMAP34xx 3.1
3 * Technical Reference Manual from Texas Instruments.
5 * Copyright (C) 2009 Nokia Corporation
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 or
10 * (at your option) version 3 of the License.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #include "qemu-char.h"
29 /* list of supported NAND devices according to the OMAP34xx TRM */
34 } omap3_boot_nand_devices[] = {
35 {0xe6, 512, 64}, {0x33, 512, 128}, {0x73, 512, 128},
36 {0x43, 512, 128}, {0x53, 512, 128}, {0x35, 512, 256},
37 {0x75, 512, 256}, {0x45, 512, 256}, {0x55, 512, 256},
38 {0x36, 512, 512}, {0x76, 512, 512}, {0x46, 512, 512},
39 {0x56, 512, 512}, {0xa2, 2048, 512}, {0xf2, 2048, 512},
40 {0xb2, 2048, 512}, {0xc2, 2048, 512}, {0x39, 512, 1024},
41 {0x79, 512, 1024}, {0x49, 512, 1024}, {0x59, 512, 1024},
42 {0x78, 512, 1024}, {0x72, 512, 1024}, {0x74, 512, 1024},
43 {0xa1, 2048, 1024}, {0xf1, 2048, 1024}, {0xb1, 2048, 1024},
44 {0xc1, 2048, 1024}, {0xaa, 2048, 2048}, {0xda, 2048, 2048},
45 {0xba, 2048, 2048}, {0xca, 2048, 2048}, {0x71, 512, 2048},
46 {0x51, 512, 2048}, {0x31, 512, 2048}, {0x41, 512, 2048},
47 {0xac, 2048, 4096}, {0xdc, 2048, 4096}, {0xbc, 2048, 4096},
48 {0xcc, 2048, 4096}, {0xa3, 2048, 8192}, {0xd3, 2048, 8192},
49 {0xb3, 2048, 8192}, {0xc3, 2048, 8192}, {0xa5, 2048, 16384},
50 {0xd5, 2048, 16384}, {0xb5, 2048, 16384}, {0xc5, 2048, 16384},
51 {0xa7, 2048, 32768}, {0xb7, 2048, 32768}, {0xae, 2048, 65536},
56 struct omap3_nand_boot_desc_s {
62 static const uint8_t omap3_boot_rom[] = { /* 0x40014000-0x4001bfff */
63 /* 0x40014000: ROM Exception vectors */
64 0x3e, 0x00, 0x00, 0xea, /* b 0x40014100 */
65 0x18, 0xf0, 0x9f, 0xe5, /* ldr pc, [pc, #0x18] */
66 0x18, 0xf0, 0x9f, 0xe5, /* ldr pc, [pc, #0x18] */
67 0x18, 0xf0, 0x9f, 0xe5, /* ldr pc, [pc, #0x18] */
68 0x18, 0xf0, 0x9f, 0xe5, /* ldr pc, [pc, #0x18] */
69 0x18, 0xf0, 0x9f, 0xe5, /* ldr pc, [pc, #0x18] */
70 0x18, 0xf0, 0x9f, 0xe5, /* ldr pc, [pc, #0x18] */
71 0x18, 0xf0, 0x9f, 0xe5, /* ldr pc, [pc, #0x18] */
72 /* 0x40014020: ROM CRC */
73 0xff, 0xff, 0xff, 0xff,
74 /* 0x40014024: unused(?), we use it for some data */
75 0xc8, 0xff, 0x20, 0x40, /* 0x40014024: undef sram vector address */
76 0xcc, 0xff, 0x20, 0x40, /* 0x40014028: swi sram vector address */
77 0xd0, 0xff, 0x20, 0x40, /* 0x4001402c: pabt sram vector address */
78 0xd4, 0xff, 0x20, 0x40, /* 0x40014030: dabt sram vector address */
79 0xd8, 0xff, 0x20, 0x40, /* 0x40014034: unused sram vector address */
80 0xdc, 0xff, 0x20, 0x40, /* 0x40014038: irq sram vector address */
81 0xe0, 0xff, 0x20, 0x40, /* 0x4001403c: fiq sram vector address */
82 0xff, 0xff, 0xff, 0xff, /* 0x40014040: boot loader image start address */
83 0xff, 0xff, 0xff, 0xff, /* 0x40014044: booting parameter structure 0-3 */
84 0xff, 0xff, 0xff, 0xff, /* 0x40014048: booting parameter structure 4-7 */
85 0xff, 0xff, 0xff, 0xff, /* 0x4001404c: booting parameter structure 8-11 */
86 0x0e, 0xf0, 0xb0, 0xe1, /* 0x40014050: "movs pc, lr" */
87 0xff, 0xff, 0xff, 0xff,
88 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
89 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
90 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
91 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
92 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
93 /* 0x40014080: Dead loops */
94 0xfe, 0xff, 0xff, 0xea, /* b 0x40014080 @ undefined exception */
95 0xfe, 0xff, 0xff, 0xea, /* b 0x40014084 @ swi exception */
96 0xfe, 0xff, 0xff, 0xea, /* b 0x40014088 @ prefetch abort exception */
97 0xfe, 0xff, 0xff, 0xea, /* b 0x4001408c @ data abort exception */
98 0xfe, 0xff, 0xff, 0xea, /* b 0x40014090 @ unused exception */
99 0xfe, 0xff, 0xff, 0xea, /* b 0x40014094 @ irq exception */
100 0xfe, 0xff, 0xff, 0xea, /* b 0x40014098 @ fiq exception */
101 0xfe, 0xff, 0xff, 0xea, /* b 0x4001409c @ validation tests pass */
102 0xfe, 0xff, 0xff, 0xea, /* b 0x400140a0 @ validation tests fail */
103 0xfe, 0xff, 0xff, 0xea, /* b 0x400140a4 @ boot failed: no more devices */
104 0xfe, 0xff, 0xff, 0xea, /* b 0x400140a8 @ image not executed or returned */
105 0xfe, 0xff, 0xff, 0xea, /* b 0x400140ac @ reserved */
106 0xfe, 0xff, 0xff, 0xea, /* b 0x400140b0 @ reserved */
107 0xfe, 0xff, 0xff, 0xea, /* b 0x400140b4 @ reserved */
108 0xfe, 0xff, 0xff, 0xea, /* b 0x400140b8 @ reserved */
109 0xfe, 0xff, 0xff, 0xea, /* b 0x400140bc @ reserved */
110 /* 0x400140c0: should perform a software reset & jump to r0 */
111 0x00, 0xf0, 0xa0, 0xe1, /* mov pc, r0 */
112 0xff, 0xff, 0xff, 0xff,
113 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
114 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
115 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
116 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
117 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
118 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
119 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
120 /* 0x40014100: code, ROM emulation uses this to launch the
121 * boot loader after it has been read into memory */
122 0xc8, 0x10, 0x1f, 0xe5, /* ldr r1, [#0x40014040] @ boot loader start */
123 0xb0, 0x0c, 0x0f, 0xe3, /* movw r0, #0xfcb0 */
124 0x20, 0x00, 0x44, 0xe3, /* movt r0, #0x4020 @ stack top at 0x4020fcb0 */
125 0xdf, 0xf0, 0x21, 0xe3, /* msr cpsr_c, #0xdf @ enter SYS mode */
126 0x00, 0xd0, 0xa0, 0xe1, /* mov sp, r0 */
127 0x80, 0x0c, 0x40, 0xe2, /* sub r0, r0, #32768 @ 32kB SYS/USR stack */
128 0xd1, 0xf0, 0x21, 0xe3, /* msr cpsr_c, #0xd1 @ enter FIQ mode */
129 0x00, 0xd0, 0xa0, 0xe1, /* mov sp, r0 */
130 0x08, 0x0c, 0x40, 0xe2, /* sub r0, r0, #2048 @ 2kB FIQ stack */
131 0xd2, 0xf0, 0x21, 0xe3, /* msr cpsr_c, #0xd2 @ enter IRQ mode */
132 0x00, 0xd0, 0xa0, 0xe1, /* mov sp, r0 */
133 0x08, 0x0c, 0x40, 0xe2, /* sub r0, r0, #2048 @ 2kB IRQ stack */
134 0xd7, 0xf0, 0x21, 0xe3, /* msr cpsr_c, #0xd7 @ enter ABT mode */
135 0x00, 0xd0, 0xa0, 0xe1, /* mov sp, r0 */
136 0x08, 0x0c, 0x40, 0xe2, /* sub r0, r0, #2048 @ 2kB ABT stack */
137 0xdb, 0xf0, 0x21, 0xe3, /* msr cpsr_c, #0xdb @ enter UND mode */
138 0x00, 0xd0, 0xa0, 0xe1, /* mov sp, r0 */
139 0x08, 0x0c, 0x40, 0xe2, /* sub r0, r0, #2048 @ 2kB UND stack */
140 0xd3, 0xf0, 0x21, 0xe3, /* msr cpsr_c, #0xd3 @ enter SVC mode */
141 0x00, 0xd0, 0xa0, 0xe1, /* mov sp, r0 @ 23kB left for SVC stack */
142 0x44, 0x00, 0x04, 0xe3, /* movw r0, #0x4044 */
143 0x01, 0x00, 0x44, 0xe3, /* movt r0, #0x4001 @ r0 -> booting parameter struct */
144 0x01, 0xf0, 0xa0, 0xe1, /* mov pc, r1 */
147 /* SRAM exception vectors, to be placed at 0x4020ffc8 */
148 static const uint8_t omap3_sram_vectors[] = {
149 0x14, 0xf0, 0x9f, 0xe5, /* ldr pc, [#0x4020ffe4] @ undefined */
150 0x14, 0xf0, 0x9f, 0xe5, /* ldr pc, [#0x4020ffe8] @ swi */
151 0x14, 0xf0, 0x9f, 0xe5, /* ldr pc, [#0x4020ffec] @ prefetch abort */
152 0x14, 0xf0, 0x9f, 0xe5, /* ldr pc, [#0x4020fff0] @ data abort */
153 0x14, 0xf0, 0x9f, 0xe5, /* ldr pc, [#0x4020fff4] @ unused */
154 0x14, 0xf0, 0x9f, 0xe5, /* ldr pc, [#0x4020fff8] @ irq */
155 0x14, 0xf0, 0x9f, 0xe5, /* ldr pc, [#0x4020fffc] @ fiq */
156 0x80, 0x40, 0x01, 0x00, /* 0x14080 */
157 0x50, 0x40, 0x01, 0x40, /* 0x40014050 (default is 0x14084) */
158 0x88, 0x40, 0x01, 0x00, /* 0x14088 */
159 0x8c, 0x40, 0x01, 0x00, /* 0x1408c */
160 0x90, 0x40, 0x01, 0x00, /* 0x14090 */
161 0x94, 0x40, 0x01, 0x00, /* 0x14094 */
162 0x98, 0x40, 0x01, 0x00, /* 0x14098 */
165 static inline uint32_t omap3_get_le32(const void *p)
167 const uint8_t *q = (const uint8_t *)p;
176 static inline uint32_t omap3_get_le16(const void *p)
178 const uint8_t *q = (const uint8_t *)p;
185 static inline void omap3_boot_setlsb(target_phys_addr_t addr, uint16_t lsb)
189 cpu_physical_memory_read(addr, x, 4);
191 x[1] = (lsb >> 8) & 0xff;
192 cpu_physical_memory_write(addr, x, 4);
205 } omap3_boot_device_t;
207 struct omap3_boot_s {
208 struct omap_mpu_state_s *mpu;
209 omap3_boot_device_t devicetype;
219 target_phys_addr_t addr;
223 static struct omap3_boot_s *omap3_boot_init(struct omap_mpu_state_s *mpu,
224 omap3_boot_device_t dtype,
228 struct omap3_boot_s *s = qemu_mallocz(sizeof(struct omap3_boot_s));
230 s->devicetype = dtype;
232 if (data_len >= 512) {
233 if (!strncasecmp((char *)(data + 0x14), "chsettings", 10)
234 || !strncasecmp((char *)(data + 0x14), "chram", 5)
235 || !strncasecmp((char *)(data + 0x14), "chflash", 7)
236 || !strncasecmp((char *)(data + 0x14), "chmmcsd", 7))
237 s->state = confighdr;
242 static void omap3_boot_chsettings(struct omap3_boot_s *boot,
243 const uint8_t *chtoc)
247 if (omap3_get_le32(chtoc) != 0xc0c0c0c1) {
248 fprintf(stderr, "%s: invalid section verification key\n", __FUNCTION__);
251 if (!chtoc[4]) { /* section disabled? */
254 if (omap3_get_le16(chtoc + 5) != 0x0001) {
255 fprintf(stderr, "%s: unsupported CH version (0x%04x)\n", __FUNCTION__,
256 omap3_get_le16(chtoc));
259 boot->chflags |= 0x01;
260 flags = omap3_get_le32(chtoc + 8);
263 cpu_physical_memory_write(0x48307270, chtoc + 0x00, 4); /* PRM_CLKSRC_CTRL */
264 cpu_physical_memory_write(0x48306d40, chtoc + 0x04, 4); /* PRM_CLKSEL */
265 cpu_physical_memory_write(0x48005140, chtoc + 0x08, 4); /* CM_CLKSEL1_EMU */
266 if (flags & (1 << 2)) { /* clock configuration */
267 cpu_physical_memory_write(0x48004a40, chtoc + 0x0c, 4); /* CM_CLKSEL_CORE */
268 cpu_physical_memory_write(0x48004c40, chtoc + 0x10, 4); /* CM_CLKSEL_WKUP */
270 if (flags & (1 << 5)) { /* DPLL3 CORE */
271 if (flags & (1 << 8)) { /* enable DPLL3 bypass */
272 cpu_physical_memory_read(0x48004d00, (uint8_t *)&x, 4);
273 x &= ~7; x |= 5; /* set DPLL3 bypass */
274 cpu_physical_memory_write(0x48004d00, (uint8_t *)&x, 4);
276 cpu_physical_memory_write(0x48004d00, chtoc + 0x14, 4); /* CM_CLKEN_PLL */
277 cpu_physical_memory_write(0x48004d30, chtoc + 0x18, 4); /* CM_AUTOIDLE_PLL */
278 cpu_physical_memory_write(0x48004d40, chtoc + 0x1c, 4); /* CM_CLKSEL1_PLL */
280 if (flags & (1 << 3)) { /* DPLL4 PER */
281 if (flags & (1 << 6)) { /* enable DPLL4 bypass */
282 cpu_physical_memory_read(0x48004d00, (uint8_t *)&x, 4);
283 x &= ~0x70000; x |= 0x10000; /* set DPLL4 in stop mode */
284 cpu_physical_memory_write(0x48004d00, (uint8_t *)&x, 4);
286 cpu_physical_memory_write(0x48004d00, chtoc + 0x20, 4); /* CM_CLKEN_PLL */
287 cpu_physical_memory_write(0x48004d30, chtoc + 0x24, 4); /* CM_AUTOIDLE_PLL */
288 cpu_physical_memory_write(0x48004d44, chtoc + 0x28, 4); /* CM_CLKSEL2_PLL */
289 cpu_physical_memory_write(0x48004d48, chtoc + 0x2c, 4); /* CM_CLKSEL3_PLL */
291 if (flags & (1 << 3)) { /* DPLL1 MPU */
292 if (flags & (1 << 7)) { /* enable DPLL1 bypass */
293 cpu_physical_memory_read(0x48004904, (uint8_t *)&x, 4);
294 x &= ~7; x |= 5; /* set DPLL1 bypass */
295 cpu_physical_memory_write(0x48004904, (uint8_t *)&x, 4);
297 cpu_physical_memory_write(0x48004904, chtoc + 0x30, 4); /* CM_CLKEN_PLL_MPU */
298 cpu_physical_memory_write(0x48004934, chtoc + 0x34, 4); /* CM_AUTOIDLE_PLL_MPU */
299 cpu_physical_memory_write(0x48004940, chtoc + 0x38, 4); /* CM_CLKSEL1_PLL_MPU */
300 cpu_physical_memory_write(0x48004944, chtoc + 0x3c, 4); /* CM_CLKSEL2_PLL_MPU */
301 cpu_physical_memory_write(0x48004948, chtoc + 0x40, 4); /* CM_CLKSTCTRL_MPU */
303 switch ((flags >> 24) & 0xff) {
304 case 0x01: x = 0; break; /* 12MHz */
305 case 0x02: x = 1; break; /* 13MHz */
306 case 0x03: x = 5; break; /* 16.8MHz */
307 case 0x04: x = 2; break; /* 19.2MHz */
308 case 0x05: x = 3; break; /* 26MHz */
309 case 0x06: x = 4; break; /* 38.4MHz */
311 fprintf(stderr, "%s: unsupported SYS.CLK setting\n", __FUNCTION__);
315 if (x != omap3_get_le32(chtoc + 0x04)) {
316 fprintf(stderr, "%s: mismatch in SYS.CLK id and PRM_CLKSEL value\n", __FUNCTION__);
321 static void omap3_boot_chram(struct omap3_boot_s *boot,
322 const uint8_t *chtoc)
324 if (omap3_get_le32(chtoc) != 0xc0c0c0c2) {
325 fprintf(stderr, "%s: invalid section verification key\n", __FUNCTION__);
328 if (!chtoc[4]) { /* section disabled? */
331 boot->chflags |= 0x02;
332 omap3_boot_setlsb(0x6d000040, omap3_get_le16(chtoc + 0x0a)); /* SDRC_CS_CFG */
333 omap3_boot_setlsb(0x6d000044, omap3_get_le16(chtoc + 0x0c)); /* SDRC_SHARING */
334 cpu_physical_memory_write(0x6d000060, chtoc + 0x10, 4); /* SDRC_DLLA_CTRL */
336 cpu_physical_memory_write(0x6d000080, chtoc + 0x20, 4); /* SDRC_MCFG_0 */
337 omap3_boot_setlsb(0x6d000084, omap3_get_le16(chtoc + 0x24)); /* SDRC_MR_0 */
338 omap3_boot_setlsb(0x6d000088, omap3_get_le16(chtoc + 0x26)); /* SDRC_EMR1_0? */
339 omap3_boot_setlsb(0x6d00008c, omap3_get_le16(chtoc + 0x28)); /* SDRC_EMR2_0 */
340 omap3_boot_setlsb(0x6d000090, omap3_get_le16(chtoc + 0x2a)); /* SDRC_EMR3_0? */
341 cpu_physical_memory_write(0x6d00009c, chtoc + 0x2c, 4); /* SDRC_ACTIM_CTRLA_0 */
342 cpu_physical_memory_write(0x6d0000a0, chtoc + 0x30, 4); /* SDRC_ACTIM_CTRLB_0 */
343 cpu_physical_memory_write(0x6d0000a4, chtoc + 0x34, 4); /* SDRC_RFR_CTRL_0 */
345 cpu_physical_memory_write(0x6d0000b0, chtoc + 0x20, 4); /* SDRC_MCFG_1 */
346 omap3_boot_setlsb(0x6d0000b4, omap3_get_le16(chtoc + 0x24)); /* SDRC_MR_1 */
347 omap3_boot_setlsb(0x6d0000b8, omap3_get_le16(chtoc + 0x26)); /* SDRC_EMR1_1? */
348 omap3_boot_setlsb(0x6d0000bc, omap3_get_le16(chtoc + 0x28)); /* SDRC_EMR2_1 */
349 omap3_boot_setlsb(0x6d0000c0, omap3_get_le16(chtoc + 0x2a)); /* SDRC_EMR3_1? */
350 cpu_physical_memory_write(0x6d0000cc, chtoc + 0x2c, 4); /* SDRC_ACTIM_CTRLA_1 */
351 cpu_physical_memory_write(0x6d0000d0, chtoc + 0x30, 4); /* SDRC_ACTIM_CTRLB_1 */
352 cpu_physical_memory_write(0x6d0000d4, chtoc + 0x34, 4); /* SDRC_RFR_CTRL_1 */
355 static void omap3_boot_chflash(struct omap3_boot_s *boot,
356 const uint8_t *chtoc)
358 if (omap3_get_le32(chtoc) != 0xc0c0c0c3) {
359 fprintf(stderr, "%s: invalid section verification key\n", __FUNCTION__);
362 if (!chtoc[4]) { /* section disabled? */
365 boot->chflags |= 0x04;
366 omap3_boot_setlsb(0x6e000010, omap3_get_le16(chtoc + 0x08)); /* GPMC_SYSCONFIG */
367 omap3_boot_setlsb(0x6e00001c, omap3_get_le16(chtoc + 0x0a)); /* GPMC_IRQENABLE */
368 omap3_boot_setlsb(0x6e000040, omap3_get_le16(chtoc + 0x0c)); /* GPMC_TIMEOUT_CONTROL */
369 omap3_boot_setlsb(0x6e000050, omap3_get_le16(chtoc + 0x0e)); /* GPMC_CONFIG */
370 cpu_physical_memory_write(0x6e000060, chtoc + 0x10, 4); /* GPMC_CONFIG1_0 */
371 cpu_physical_memory_write(0x6e000064, chtoc + 0x14, 4); /* GPMC_CONFIG2_0 */
372 cpu_physical_memory_write(0x6e000068, chtoc + 0x18, 4); /* GPMC_CONFIG3_0 */
373 cpu_physical_memory_write(0x6e00006c, chtoc + 0x1c, 4); /* GPMC_CONFIG4_0 */
374 cpu_physical_memory_write(0x6e000070, chtoc + 0x20, 4); /* GPMC_CONFIG5_0 */
375 cpu_physical_memory_write(0x6e000074, chtoc + 0x24, 4); /* GPMC_CONFIG6_0 */
376 cpu_physical_memory_write(0x6e000078, chtoc + 0x28, 4); /* GPMC_CONFIG7_0 */
377 cpu_physical_memory_write(0x6e0001e0, chtoc + 0x2c, 4); /* GPMC_PREFETCH_CONFIG1 */
378 omap3_boot_setlsb(0x6e0001e4, omap3_get_le16(chtoc + 0x30)); /* GPMC_PREFETCH_CONFIG2 */
379 omap3_boot_setlsb(0x6e0001ec, omap3_get_le16(chtoc + 0x32)); /* GPMC_PREFETCH_CONTROL */
380 /* TODO: ECC config registers. The TRM spec is not clear on these */
383 static void omap3_boot_chmmcsd(struct omap3_boot_s *boot,
384 const uint8_t *chtoc)
386 if (omap3_get_le32(chtoc) != 0xc0c0c0c4) {
387 fprintf(stderr, "%s: invalid section verification key\n", __FUNCTION__);
390 if (!chtoc[4]) { /* section disabled? */
393 boot->chflags |= 0x08;
394 /* TODO: MMCHS registers */
397 /* returns non-zero if more blocks are needed */
398 static uint32_t omap3_boot_block(const uint8_t *data,
400 struct omap3_boot_s *s)
402 const uint8_t *p = 0;
408 for (p = data; i >= 32 && omap3_get_le32(p) != 0xffffffff; p += 32, i -= 32) {
409 if (!strcasecmp((char *)(p + 0x14), "chsettings"))
410 omap3_boot_chsettings(s, p + omap3_get_le32(p));
411 else if (!strcasecmp((char *)(p + 0x14), "chram"))
412 omap3_boot_chram(s, p + omap3_get_le32(p));
413 else if (!strcasecmp((char *)(p + 0x14), "chflash"))
414 omap3_boot_chflash(s, p + omap3_get_le32(p));
415 else if (!strcasecmp((char *)(p + 0x14), "chmmcsd"))
416 omap3_boot_chmmcsd(s, p + omap3_get_le32(p));
418 fprintf(stderr, "%s: unknown CHTOC item \"%s\"\n",
419 __FUNCTION__, (char *)(p + 0x14));
433 s->count = omap3_get_le32(data);
434 s->addr = omap3_get_le32(data + 4);
435 if (!s->count || (s->count >> 24) || !s->addr || s->addr == 0xffffffff)
437 /* patch image start address in boot ROM */
438 cpu_physical_memory_write_rom(0x40014040, data + 4, 4);
439 /* start copying image */
445 i = (s->count >= data_len) ? data_len : s->count;
446 cpu_physical_memory_write(s->addr, data, i);
458 /* returns non-zero if boot has finished succesfully */
459 static int omap3_boot_finish(struct omap3_boot_s *s)
462 0, 0, 0, 0, /* last received booting message */
463 (uint8_t)s->devicetype,
467 0, 0, 0, 0 /* device descriptor */
469 int result = (s->state == done);
472 /* fill in the booting parameter structure */
473 cpu_physical_memory_write_rom(0x40014044, x, 12);
479 /* returns ptr to matching dir entry / zero entry or 0 if unsuccessful */
480 static const uint8_t *omap3_scan_fat_dir_sector(const uint8_t *s)
484 /* there are 0x10 items with 0x20 bytes per item */
485 for (i = 0x10; i--; s += 0x20) {
486 if (*s == 0xe5 || (s[0x0b] & 0x0f) == 0x0f) continue; /* erased/LFN */
487 if (!*s || !strncasecmp((void *)s, "mlo ", 8+3)) return s;
492 struct omap3_fat_drv_s {
493 BlockDriverState *bs;
494 uint8_t ptype; /* 12, 16, 32 */
495 uint64_t c0; /* physical byte offset for data cluster 0 */
496 uint64_t fat; /* physical byte offset for used FAT sector 0 */
497 uint32_t spc; /* sectors per cluster */
500 /* returns cluster data in the buffer and next cluster chain number
501 or 0 if unsuccessful */
502 static uint32_t omap3_read_fat_cluster(uint8_t *data,
503 struct omap3_fat_drv_s *drv,
507 uint32_t len = drv->spc * 0x200; /* number of bytes to read */
509 switch (drv->ptype) { /* check for EOF */
510 case 12: if (cl > 0xff0) return 0; break;
511 case 16: if (cl > 0xfff0) return 0; break;
512 case 32: if (cl > 0x0ffffff0) return 0; break;
516 if (bdrv_pread(drv->bs,
517 drv->c0 + ((drv->ptype == 32 ? cl - 2 : cl) * len),
521 switch (drv->ptype) { /* determine next cluster # */
523 fprintf(stderr, "%s: FAT12 parsing not implemented!\n",
527 return (bdrv_pread(drv->bs, drv->fat + cl * 2, buf, 2) != 2)
528 ? 0 : omap3_get_le16(buf);
530 return (bdrv_pread(drv->bs, drv->fat + cl * 4, buf, 4) != 4)
531 ? 0 : omap3_get_le32(buf) & 0x0fffffff;
538 static int omap3_mmc_fat_boot(BlockDriverState *bs,
541 struct omap_mpu_state_s *mpu)
543 struct omap3_fat_drv_s drv;
544 struct omap3_boot_s *boot;
545 uint32_t i, j, cluster0, fatsize, bootsize, rootsize;
546 const uint8_t *p, *q;
550 /* determine FAT type */
553 fatsize = omap3_get_le16(sector + 0x16);
555 fatsize = omap3_get_le32(sector + 0x24);
556 bootsize = omap3_get_le16(sector + 0x0e);
557 cluster0 = bootsize + fatsize * sector[0x10];
558 rootsize = omap3_get_le16(sector + 0x11);
562 drv.spc = sector[0x0d];
563 i = omap3_get_le16(sector + 0x13);
565 i = omap3_get_le32(sector + 0x20);
566 i = (i - (cluster0 + rootsize)) / drv.spc;
567 drv.ptype = (i < 4085) ? 12 : (i < 65525) ? 16 : 32;
569 /* search for boot loader file */
571 drv.fat = (bootsize + pstart) * 0x200;
572 drv.c0 = (cluster0 + pstart) * 0x200;
573 if (drv.ptype == 32) {
574 i = omap3_get_le32(sector + 0x2c); /* first root cluster # */
575 j = omap3_get_le16(sector + 0x28);
577 drv.fat += (j & 0x0f) * fatsize * 0x200;
578 cluster = qemu_mallocz(drv.spc * 0x200);
579 for (p = 0; !p && (i = omap3_read_fat_cluster(cluster, &drv, i)); ) {
580 for (j = drv.spc, q=cluster; j-- & !p; q += 0x200)
581 p = omap3_scan_fat_dir_sector(q);
583 memcpy(sector, q - 0x200, 0x200); /* save the sector */
586 } else { /* FAT12/16 */
587 for (i = rootsize, j = 0, p = 0; i-- && !p; j++) {
588 if (bdrv_pread(drv.bs, drv.c0 + j * 0x200, sector, 0x200) != 0x200)
590 p = omap3_scan_fat_dir_sector(sector);
594 if (p && *p) { /* did we indeed find the file? */
595 i = omap3_get_le16(p + 0x14);
597 i |= omap3_get_le16(p + 0x1a);
599 uint8 *data = qemu_mallocz(j);
600 if ((i = omap3_read_fat_cluster(data, &drv, i))) {
601 boot = omap3_boot_init(mpu, mmc1, data, j);
602 boot->state = imagehdr; /* override CH detection */
603 while (omap3_boot_block(data, j, boot))
604 i = omap3_read_fat_cluster(data, &drv, i);
605 result = omap3_boot_finish(boot);
607 fprintf(stderr, "%s: unable to read MLO file contents from SD card\n",
611 fprintf(stderr, "%s: MLO file not found in the root directory\n",
617 static int omap3_mmc_raw_boot(BlockDriverState *bs,
619 struct omap_mpu_state_s *mpu)
621 struct omap3_boot_s *boot;
625 if (bdrv_pread(bs, 0, sector, 0x200) == 0x200) {
626 boot = omap3_boot_init(mpu, mmc1, sector, 0x200);
627 if (boot->state == confighdr) { /* CH must be present for raw boot */
628 while (omap3_boot_block(sector, 0x200, boot)) {
629 if (bdrv_pread(bs, ++i, sector, 0x200) != 0x200) {
630 fprintf(stderr, "%s: error trying to read sector %u on boot device\n",
636 result = (boot->state == done);
642 /* returns non-zero if successful, zero if unsuccessful */
643 static int omap3_mmc_boot(struct omap_mpu_state_s *s)
645 BlockDriverState *bs;
646 int sdindex = drive_get_index(IF_SD, 0, 0);
651 /* very simple implementation for GP device boot,
652 supports only two modes:
653 1. MBR partition table with an active FAT partition
654 and boot loader file (MLO) in its root directory, or
655 2. CH sector located on first sector, followed by boot loader image */
657 bs = drives_table[sdindex].bdrv;
658 sector = qemu_mallocz(0x200);
659 if (bdrv_pread(bs, 0, sector, 0x200) == 0x200) {
660 for (i = 0, p = sector + 0x1be; i < 4; i++, p += 0x10)
661 if (p[0] == 0x80) break;
662 if (sector[0x1fe] == 0x55 && sector[0x1ff] == 0xaa /* signature */
663 && i < 4 /* active partition exists */
664 && (p[4] == 1 || p[4] == 4 || p[4] == 6 || p[4] == 11
665 || p[4] == 12 || p[4] == 14 || p[4] == 15) /* FAT */
666 && bdrv_pread(bs, (pstart = omap3_get_le32(p + 8)) * 0x200,
667 sector, 0x200) == 0x200
668 && sector[0x1fe] == 0x55 && sector[0x1ff] == 0xaa)
669 result = omap3_mmc_fat_boot(bs, sector, pstart, s);
671 result = omap3_mmc_raw_boot(bs, sector, s);
678 static inline void omap3_nand_sendcmd(struct omap3_nand_boot_desc_s *nd,
681 uint8_t x[2] = { cmd, 0 };
683 cpu_physical_memory_write(0x6e00007c, x, nd->bus16 ? 2 : 1);
686 static inline void omap3_nand_sendaddr_byte(struct omap3_nand_boot_desc_s *nd,
689 uint8_t x[2] = { a, 0 };
691 cpu_physical_memory_write(0x6e000080, x, nd->bus16 ? 2 : 1);
694 static inline uint8_t omap3_nand_readbyte(struct omap3_nand_boot_desc_s *nd)
698 cpu_physical_memory_read(0x6e000084, x, nd->bus16 ? 2 : 1);
702 static inline void omap3_nand_readpage(struct omap3_nand_boot_desc_s *nd,
708 omap3_nand_sendcmd(nd, 0x00); /* read page */
709 omap3_nand_sendaddr_byte(nd, 0x00);
710 if (nd->pagesize >= 2048) {
711 omap3_nand_sendaddr_byte(nd, 0x00);
712 omap3_nand_sendaddr_byte(nd, (uint8_t)(pageaddr & 0xff));
713 omap3_nand_sendaddr_byte(nd, (uint8_t)((pageaddr >> 8) & 0xff));
714 if (nd->capacity_Mb >= 2048)
715 omap3_nand_sendaddr_byte(nd, (uint8_t)((pageaddr >> 16) & 0xff));
716 omap3_nand_sendcmd(nd, 0x30); /* confirm read */
718 omap3_nand_sendaddr_byte(nd, (uint8_t)(pageaddr & 0xff));
719 omap3_nand_sendaddr_byte(nd, (uint8_t)((pageaddr >> 8) & 0xff));
722 for (i = nd->pagesize / 2; i--; data += 2)
723 cpu_physical_memory_read(0x6e000084, data, 2);
725 for (i = nd->pagesize; i--; data++)
726 cpu_physical_memory_read(0x6e000084, data, 1);
730 /* returns non-zero if successful, zero if unsuccessful */
731 static int omap3_nand_boot(struct omap_mpu_state_s *mpu, int bus16)
733 struct omap3_nand_boot_desc_s *nd;
734 struct omap3_boot_s *boot;
740 /* TODO: support bad block marks */
741 nd = qemu_mallocz(sizeof(struct omap3_nand_boot_desc_s));
743 omap3_nand_sendcmd(nd, 0xff); /* reset */
744 omap3_nand_sendcmd(nd, 0x90); /* read id */
745 omap3_nand_sendaddr_byte(nd, 0);
746 id[0] = omap3_nand_readbyte(nd); /* manufacturer id */
747 id[1] = omap3_nand_readbyte(nd); /* device id */
748 id[2] = omap3_nand_readbyte(nd); /* don't care */
749 id[3] = omap3_nand_readbyte(nd); /* attributes */
750 for (i = 0; omap3_boot_nand_devices[i].id; i++) {
751 if (omap3_boot_nand_devices[i].id == id[1]) {
752 nd->capacity_Mb = omap3_boot_nand_devices[i].capacity_Mb;
753 if (nd->capacity_Mb > 1024)
754 nd->pagesize = 1024 * (1 << (id[3] & 3));
756 nd->pagesize = omap3_boot_nand_devices[i].pagesize;
760 /* TODO: if device is not recognized at this state, we should
761 * issue READ ID2 command to the device and get device parameters
764 data = qemu_mallocz(nd->pagesize);
765 /* TODO: scan through 4 first blocks for image */
766 omap3_nand_readpage(nd, 0, data);
767 boot = omap3_boot_init(mpu, nand, data, nd->pagesize);
768 while (omap3_boot_block(data, nd->pagesize, boot))
769 omap3_nand_readpage(nd, ++page, data);
770 result = omap3_boot_finish(boot);
778 void omap3_boot_rom_emu(struct omap_mpu_state_s *s)
780 const uint8_t rom_version[4] = { 0x00, 0x14, 0x00, 0x00 }; /* v. 14.00 */
781 uint8_t x[4] = {0, 0, 0, 0};
784 cpu_physical_memory_write_rom(OMAP3_Q1_BASE + 0x14000,
786 sizeof(omap3_boot_rom));
787 cpu_physical_memory_write_rom(OMAP3_Q1_BASE + 0x1bffc,
789 sizeof(rom_version));
790 cpu_physical_memory_write(OMAP3_SRAM_BASE + 0xffc8,
792 sizeof(omap3_sram_vectors));
794 /* if we have NAND in GPMC CS0, try to read boot loader from there.
795 * here we are relying on all memories to be attached and gpmc_attach
796 * to fill in DEVICETYPE field correctly for CS0 for us */
797 cpu_physical_memory_read(0x6e000060, x, 4); /* GPMC_CONFIG1_0 */
798 if (((x[1] >> 2) & 3) == 2) /* DEVICETYPE == NAND? */
799 result = omap3_nand_boot(s, ((x[1] >> 4) & 3) == 1);
801 /* TODO: support OneNAND and XIP */
803 /* if no boot loader found yet, try the MMC/SD card... */
805 result = omap3_mmc_boot(s);
807 if (!result) { /* no boot device found */
808 /* move PC to the appropriate ROM dead loop address */
809 s->env->regs[15] = 0x400140a4;
810 /* ...on second thought, let's just call it a day and quit */
811 cpu_abort(s->env, "no boot device found");