Fix & cleanup OMAP3 MMC emulation
[qemu] / hw / beagle.c
1 /*\r
2  * Beagle board emulation. http://beagleboard.org/\r
3  * \r
4  * Copyright (C) 2008 yajin(yajin@vm-kernel.org)\r
5  *\r
6  * This program is free software; you can redistribute it and/or\r
7  * modify it under the terms of the GNU General Public License as\r
8  * published by the Free Software Foundation; either version 2 or\r
9  * (at your option) version 3 of the License.\r
10  *\r
11  * This program is distributed in the hope that it will be useful,\r
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14  * GNU General Public License for more details.\r
15  *\r
16  * You should have received a copy of the GNU General Public License\r
17  * along with this program; if not, write to the Free Software\r
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,\r
19  * MA 02111-1307 USA\r
20  */\r
21 \r
22 #include "qemu-common.h"\r
23 #include "sysemu.h"\r
24 #include "omap.h"\r
25 #include "arm-misc.h"\r
26 #include "irq.h"\r
27 #include "console.h"\r
28 #include "boards.h"\r
29 #include "i2c.h"\r
30 #include "devices.h"\r
31 #include "flash.h"\r
32 #include "hw.h"\r
33 #include "block.h"\r
34 \r
35 #define BEAGLE_NAND_CS                  0\r
36 #define BEAGLE_TWL4030_ADDR             0x4b    /* Power management */\r
37 \r
38 #define GPMC_NOR             0\r
39 #define GPMC_NAND           1\r
40 #define GPMC_MDOC           2\r
41 #define GPMC_ONENAND    3\r
42 #define MMC_NAND            4\r
43 #define MMC_ONENAND     5\r
44 \r
45 \r
46 #define TST_DEVICE              0x0\r
47 #define EMU_DEVICE              0x1\r
48 #define HS_DEVICE               0x2\r
49 #define GP_DEVICE               0x3\r
50 \r
51 #define DEBUG_BEAGLE\r
52 \r
53 #ifdef DEBUG_BEAGLE\r
54 #define BEAGLE_DEBUG(...)    do { fprintf(stderr, __VA_ARGS__); } while(0)\r
55 #else\r
56 #define BEAGLE_DEBUG(x)    \r
57 #endif\r
58 \r
59 /* Beagle board support */\r
60 struct beagle_s {\r
61     struct omap_mpu_state_s *cpu;\r
62     \r
63     struct nand_bflash_s *nand;\r
64     struct omap3_lcd_panel_s *lcd_panel;\r
65     i2c_bus *i2c;\r
66 };\r
67 \r
68 \r
69 \r
70 static struct arm_boot_info beagle_binfo = {\r
71     .ram_size = 0x08000000,\r
72 };\r
73 \r
74 \r
75 static uint32_t beagle_nand_read16(void *opaque, target_phys_addr_t addr)\r
76 {\r
77         struct beagle_s *s = (struct beagle_s *) opaque;\r
78     //BEAGLE_DEBUG("beagle_nand_read16 offset %x\n",addr);\r
79 \r
80         switch (addr)\r
81         {\r
82                 case 0x7C: /*NAND_COMMAND*/\r
83                 case 0x80: /*NAND_ADDRESS*/\r
84                         OMAP_BAD_REG(addr);\r
85                         break;\r
86                 case 0x84: /*NAND_DATA*/\r
87                         return nandb_read_data16(s->nand);\r
88                         break;\r
89                 default:\r
90                         OMAP_BAD_REG(addr);\r
91                         break;\r
92         }\r
93     return 0;\r
94 }\r
95 \r
96 static void beagle_nand_write16(void *opaque, target_phys_addr_t addr,\r
97                 uint32_t value)\r
98 {\r
99         struct beagle_s *s = (struct beagle_s *) opaque;\r
100     switch (addr)\r
101         {\r
102                 case 0x7C: /*NAND_COMMAND*/\r
103                         nandb_write_command(s->nand,value);\r
104                         break;\r
105                 case 0x80: /*NAND_ADDRESS*/\r
106                         nandb_write_address(s->nand,value);\r
107                         break;\r
108                 case 0x84: /*NAND_DATA*/\r
109                         nandb_write_data16(s->nand,value);\r
110                         break;\r
111                 default:\r
112                         OMAP_BAD_REG(addr);\r
113                         break;\r
114         }\r
115 }\r
116 \r
117 \r
118 static CPUReadMemoryFunc *beagle_nand_readfn[] = {\r
119         beagle_nand_read16,\r
120         beagle_nand_read16,\r
121         omap_badwidth_read32,\r
122 };\r
123 \r
124 static CPUWriteMemoryFunc *beagle_nand_writefn[] = {\r
125         beagle_nand_write16,\r
126         beagle_nand_write16,\r
127         omap_badwidth_write32,\r
128 };\r
129 \r
130 static void beagle_nand_setup(struct beagle_s *s)\r
131 {\r
132         //int iomemtype;\r
133         \r
134         /*MT29F2G16ABC*/\r
135         s->nand = nandb_init(NAND_MFR_MICRON,0xba);\r
136         /*wp=1, no write protect!!! */\r
137         //nand_set_wp(s->nand, 1);\r
138 \r
139 /*      iomemtype = cpu_register_io_memory(0, beagle_nand_readfn,\r
140                     beagle_nand_writefn, s);\r
141     cpu_register_physical_memory(0x6e00007c, 0xc, iomemtype);*/\r
142     omap_gpmc_attach(s->cpu->gpmc, 0, 0, NULL, NULL, s, beagle_nand_readfn, beagle_nand_writefn);\r
143 \r
144          /*BOOT from nand*/\r
145     omap3_set_mem_type(s->cpu,GPMC_NAND);\r
146 \r
147 }\r
148 \r
149 static int beagle_nand_read_page(struct beagle_s *s,uint8_t *buf, uint16_t page_addr)\r
150 {\r
151         uint16_t *p;\r
152         int i;\r
153 \r
154         p=(uint16_t *)buf;\r
155 \r
156         /*send command 0x0*/\r
157         beagle_nand_write16(s,0x7C,0);\r
158         /*send page address */\r
159         beagle_nand_write16(s,0x80,page_addr&0xff);\r
160         beagle_nand_write16(s,0x80,(page_addr>>8)&0x7);\r
161         beagle_nand_write16(s,0x80,(page_addr>>11)&0xff);\r
162         beagle_nand_write16(s,0x80,(page_addr>>19)&0xff);\r
163         beagle_nand_write16(s,0x80,(page_addr>>27)&0xff);\r
164         /*send command 0x30*/\r
165         beagle_nand_write16(s,0x7C,0x30);\r
166 \r
167         for (i=0;i<0x800/2;i++)\r
168         {\r
169                 *p++ = beagle_nand_read16(s,0x84);\r
170         }\r
171         return 1;\r
172 }\r
173 \r
174 static uint32_t get_le32(void *p)\r
175 {\r
176     uint8_t *q = (uint8_t *)p;\r
177     uint32_t v;\r
178     v = q[3]; v <<= 8;\r
179     v |= q[2]; v <<= 8;\r
180     v |= q[1]; v <<= 8;\r
181     v |= q[0];\r
182     return v;\r
183 }\r
184 \r
185 static uint32_t get_le16(void *p)\r
186 {\r
187     uint8_t *q = (uint8_t *)p;\r
188     uint32_t v;\r
189     v = q[1]; v <<= 8;\r
190     v |= q[0];\r
191     return v;\r
192 }\r
193 \r
194 /* returns ptr to matching dir entry / zero entry or 0 if unsuccessful */\r
195 static uint8_t *beagle_scan_fat_dir_sector(uint8_t *s)\r
196 {\r
197     int i;\r
198 \r
199     /* there are 0x10 items with 0x20 bytes per item */\r
200     for (i = 0x10; i--; s += 0x20) {\r
201         if (*s == 0xe5 || (s[0x0b] & 0x0f) == 0x0f) continue; /* erased or LFN */\r
202         if (!*s || !strncasecmp((void *)s, "mlo        ", 8+3)) return s;\r
203     }\r
204     return 0;\r
205 }\r
206 \r
207 struct beagle_fat_drv_s {\r
208     BlockDriverState *bs;\r
209     uint8_t ptype; // 12, 16, 32\r
210     uint64_t c0; // physical byte offset for data cluster 0\r
211     uint64_t fat; // physical byte offset for used FAT sector 0\r
212     uint32_t spc; // sectors per cluster\r
213 };\r
214 \r
215 /* returns cluster data in the buffer and next cluster chain number or 0 if unsuccessful */\r
216 static uint32_t beagle_read_fat_cluster(uint8_t *data,\r
217                                         struct beagle_fat_drv_s *drv,\r
218                                         uint32_t cl)\r
219 {\r
220     uint8_t buf[ 4 ];\r
221     uint32_t len = drv->spc * 0x200; // number of bytes to read i.e. bytes per cluster\r
222     \r
223     switch (drv->ptype) { /* check for EOF */\r
224         case 12: if (cl > 0xff0) return 0; break;\r
225         case 16: if (cl > 0xfff0) return 0; break;\r
226         case 32: if (cl > 0x0ffffff0) return 0; break;\r
227         default: return 0;\r
228     }\r
229 \r
230     if (bdrv_pread(drv->bs, drv->c0 + ((drv->ptype == 32 ? cl - 2 : cl) * len), data, len) != len) return 0;\r
231     \r
232     switch (drv->ptype) { /* determine next cluster # */\r
233         case 12: fprintf(stderr, "%s: FAT12 parsing not implemented!\n", __FUNCTION__); break;\r
234         case 16: return (bdrv_pread(drv->bs, drv->fat + cl * 2, buf, 2) != 2) ? 0 : get_le16(buf);\r
235         case 32: return (bdrv_pread(drv->bs, drv->fat + cl * 4, buf, 4) != 4) ? 0 : get_le32(buf) & 0x0fffffff;\r
236         default: break;\r
237     }\r
238     return 0;\r
239 }\r
240 \r
241 static int beagle_boot_from_mmc(struct beagle_s *s)\r
242 {\r
243     struct beagle_fat_drv_s drv;\r
244     int sdindex = drive_get_index(IF_SD, 0, 0);\r
245     uint8_t sector[0x200], *p, *q;\r
246     uint32_t pstart, i, j, k, cluster0, fatsize, bootsize, rootsize;\r
247     uint32_t img_size, img_addr;\r
248     int result = -1;\r
249     \r
250     /* very simple implementation, requires MBR partitioning with an active FAT partition\r
251        and does no sanity checks for the partition table or FAT boot sector entries */\r
252     if (sdindex >= 0) {\r
253         drv.bs = drives_table[sdindex].bdrv;\r
254         if (bdrv_pread(drv.bs, 0, sector, 0x200) == 0x200\r
255             && sector[0x1fe] == 0x55 && sector[0x1ff] == 0xaa) { /* MBR signature */\r
256             for (i = 0, p = sector + 0x1be; i < 4; i++, p += 0x10) if (p[0] == 0x80) break;\r
257             if (i < 4 /* was there an active partition? */\r
258                 && (p[4] == 1 || p[4] == 4 || p[4] == 6 || p[4] == 11 \r
259                     || p[4] == 12 || p[4] == 14 || p[4] == 15) /* FAT partition type */\r
260                 && bdrv_pread(drv.bs, (pstart = get_le32(p + 8)) * 0x200, sector, 0x200) == 0x200\r
261                 && sector[0x1fe] ==0x55 && sector[0x1ff] == 0xaa) { /* boot sector signature */\r
262                 /* determine FAT type */\r
263                 fatsize = get_le16(sector + 0x16); if (!fatsize) fatsize = get_le32(sector + 0x24);\r
264                 bootsize = get_le16(sector + 0x0e);\r
265                 cluster0 = bootsize + fatsize * sector[0x10];\r
266                 rootsize = get_le16(sector + 0x11); if (rootsize & 0x0f) rootsize += 0x10; rootsize >>= 4;\r
267                 drv.spc = sector[0x0d];\r
268                 i = get_le16(sector + 0x13); if (!i) i = get_le32(sector + 0x20);\r
269                 i = (i - (cluster0 + rootsize)) / drv.spc;\r
270                 drv.ptype = (i < 4085) ? 12 : (i < 65525) ? 16 : 32;\r
271                 /* search for MLO file */\r
272                 drv.fat = (bootsize + pstart) * 0x200;\r
273                 drv.c0 = (cluster0 + pstart) * 0x200;\r
274                 if (drv.ptype == 32) {\r
275                     i = get_le32(sector + 0x2c); /* first root cluster # */\r
276                     j = get_le16(sector + 0x28);\r
277                     if (j & 0x80) drv.fat += (j & 0x0f) * fatsize * 0x200;\r
278                     uint8_t *cluster = qemu_mallocz(drv.spc * 0x200);\r
279                     for (p = 0; !p && (i = beagle_read_fat_cluster(cluster, &drv, i)); ) {\r
280                         for (j = drv.spc, q=cluster; j-- & !p; q += 0x200)\r
281                             p = beagle_scan_fat_dir_sector(q);\r
282                         if (p) memcpy(sector, q - 0x200, 0x200); // save the sector\r
283                     }\r
284                     free(cluster);\r
285                 } else { /* FAT12/16 */\r
286                     for (i = rootsize, j = 0, p = 0; i-- && !p; j++) {\r
287                         if (bdrv_pread(drv.bs, drv.c0 + j * 0x200, sector, 0x200) != 0x200) break;\r
288                         p = beagle_scan_fat_dir_sector(sector);\r
289                     }\r
290                 }\r
291                 if (p && *p) { // did we indeed find the file?\r
292                     i = get_le16(p + 0x14); i <<= 16; i |= get_le16(p + 0x1a);\r
293                     j = drv.spc * 0x200;\r
294                     uint8 *data = qemu_mallocz(j);\r
295                     if ((i = beagle_read_fat_cluster(data, &drv, i))) {\r
296                         /* TODO: support HS device boot - for now only GP device is supported */\r
297                         img_size = get_le32(data);\r
298                         img_addr = get_le32(data + 4);\r
299                         s->cpu->env->regs[15] = img_addr;\r
300                         cpu_physical_memory_write(img_addr, data + 8, \r
301                                                   (k = (j - 8 >= img_size) ? img_size : j - 8));\r
302                         for (img_addr += k, img_size -= k;\r
303                              img_size && (i = beagle_read_fat_cluster(data, &drv, i));\r
304                              img_addr += k, img_size -= k) {\r
305                             cpu_physical_memory_write(img_addr, data, \r
306                                                       (k = (j >= img_size) ? img_size : j));\r
307                         }\r
308                         result = 0;\r
309                     } else\r
310                         fprintf(stderr, "%s: unable to read MLO file contents from SD card\n", __FUNCTION__);\r
311                     free(data);\r
312                 } else\r
313                     fprintf(stderr, "%s: MLO file not found in the root directory\n", __FUNCTION__);\r
314             } else\r
315                 fprintf(stderr, "%s: no active FAT partition found on SD card\n", __FUNCTION__);\r
316         } else\r
317             fprintf(stderr, "%s: MBR not found on SD card\n", __FUNCTION__);\r
318     }\r
319     \r
320         return result;\r
321 }\r
322 \r
323 /*read the xloader from NAND Flash into internal RAM*/\r
324 static int beagle_boot_from_nand(struct beagle_s *s)\r
325 {\r
326         uint32_t        loadaddr, len;\r
327         uint8_t nand_page[0x800],*load_dest;\r
328         uint32_t nand_pages,i;\r
329 \r
330         /* The first two words(8 bytes) in first nand flash page have special meaning.\r
331                 First word:x-loader len\r
332                 Second word: x-load address in internal ram */\r
333         beagle_nand_read_page(s,nand_page,0);\r
334         len = *((uint32_t*)nand_page);\r
335         loadaddr =  *((uint32_t*)(nand_page+4));\r
336         if ((len==0)||(loadaddr==0)||(len==0xffffffff)||(loadaddr==0xffffffff))\r
337                 return (-1);\r
338 \r
339         /*put the first page into internal ram*/\r
340         load_dest = phys_ram_base +beagle_binfo.ram_size;\r
341         load_dest += loadaddr-OMAP3_SRAM_BASE;\r
342         \r
343         BEAGLE_DEBUG("load_dest %x phys_ram_base %x \n",(unsigned)load_dest,(unsigned)phys_ram_base);\r
344         \r
345         memcpy(load_dest,nand_page+8,0x800-8);\r
346         load_dest += 0x800-8;\r
347 \r
348         nand_pages = len/0x800;\r
349         if (len%0x800!=0)\r
350                 nand_pages++;\r
351 \r
352         for (i=1;i<nand_pages;i++)\r
353         {\r
354                 beagle_nand_read_page(s,nand_page,i*0x800);\r
355                 memcpy(load_dest,nand_page,0x800);\r
356                 load_dest += 0x800;\r
357         }\r
358         s->cpu->env->regs[15] = loadaddr;\r
359         return 0;\r
360 \r
361 }\r
362  static int beagle_rom_emu(struct beagle_s *s)\r
363 {\r
364         if (beagle_boot_from_mmc(s)<0)\r
365         {\r
366                 if (beagle_boot_from_nand(s)<0)\r
367                         return (-1); \r
368         }\r
369         return (0);\r
370 }\r
371 \r
372 static void beagle_dss_setup(struct beagle_s *s, DisplayState *ds)\r
373 {\r
374         s->lcd_panel = omap3_lcd_panel_init(ds);\r
375         omap3_lcd_panel_attach(s->cpu->dss, 0, s->lcd_panel);\r
376         s->lcd_panel->dss = s->cpu->dss;\r
377 }\r
378 \r
379 static void beagle_mmc_cs_cb(void *opaque, int line, int level)\r
380 {\r
381     /* TODO: this seems to actually be connected to the menelaus, to\r
382      * which also both MMC slots connect.  */\r
383     omap_mmc_enable((struct omap_mmc_s *) opaque, !level);\r
384 \r
385     printf("%s: MMC slot %i active\n", __FUNCTION__, level + 1);\r
386 }\r
387 \r
388 static void beagle_i2c_setup(struct beagle_s *s)\r
389 {\r
390 \r
391     /* Attach the CPU on one end of our I2C bus.  */\r
392     s->i2c = omap_i2c_bus(s->cpu->i2c[0]);\r
393 \r
394     /* Attach a menelaus PM chip */\r
395     i2c_set_slave_address(\r
396                     twl4030_init(s->i2c,\r
397                             s->cpu->irq[0][OMAP_INT_35XX_SYS_NIRQ]),\r
398                     BEAGLE_TWL4030_ADDR);\r
399 }\r
400 \r
401 \r
402 static void beagle_init(ram_addr_t ram_size, int vga_ram_size,\r
403                 const char *boot_device, DisplayState *ds,\r
404                 const char *kernel_filename, const char *kernel_cmdline,\r
405                 const char *initrd_filename, const char *cpu_model)\r
406 {\r
407     struct beagle_s *s = (struct beagle_s *) qemu_mallocz(sizeof(*s));\r
408     int sdram_size = beagle_binfo.ram_size;\r
409 \r
410         if (ram_size < sdram_size +  OMAP3530_SRAM_SIZE) {\r
411         fprintf(stderr, "This architecture uses %i bytes of memory\n",\r
412                         sdram_size + OMAP3530_SRAM_SIZE);\r
413         exit(1);\r
414     }\r
415         s->cpu = omap3530_mpu_init(sdram_size, NULL, NULL);\r
416         beagle_nand_setup(s);\r
417         beagle_i2c_setup(s);\r
418         beagle_dss_setup(s,ds);\r
419         omap3_set_device_type(s->cpu,GP_DEVICE);\r
420     if (beagle_rom_emu(s) < 0) {\r
421                 fprintf(stderr,"boot from MMC and nand failed \n");\r
422                 exit(-1);\r
423         }\r
424 }\r
425 \r
426 \r
427 \r
428 QEMUMachine beagle_machine = {\r
429     .name = "beagle",\r
430     .desc =     "Beagle board (OMAP3530)",\r
431     .init =     beagle_init,\r
432     .ram_require =     (0x08000000 +  OMAP3530_SRAM_SIZE) | RAMSIZE_FIXED,\r
433 };\r
434 \r