]> Git Repo - qemu.git/blob - hw/onenand.c
onenand: Handle various ID fields separately
[qemu.git] / hw / onenand.c
1 /*
2  * OneNAND flash memories emulation.
3  *
4  * Copyright (C) 2008 Nokia Corporation
5  * Written by Andrzej Zaborowski <[email protected]>
6  *
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.
11  *
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.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include "qemu-common.h"
22 #include "hw.h"
23 #include "flash.h"
24 #include "irq.h"
25 #include "blockdev.h"
26
27 /* 11 for 2kB-page OneNAND ("2nd generation") and 10 for 1kB-page chips */
28 #define PAGE_SHIFT      11
29
30 /* Fixed */
31 #define BLOCK_SHIFT     (PAGE_SHIFT + 6)
32
33 typedef struct {
34     struct {
35         uint16_t man;
36         uint16_t dev;
37         uint16_t ver;
38     } id;
39     int shift;
40     target_phys_addr_t base;
41     qemu_irq intr;
42     qemu_irq rdy;
43     BlockDriverState *bdrv;
44     BlockDriverState *bdrv_cur;
45     uint8_t *image;
46     uint8_t *otp;
47     uint8_t *current;
48     ram_addr_t ram;
49     uint8_t *boot[2];
50     uint8_t *data[2][2];
51     int iomemtype;
52     int cycle;
53     int otpmode;
54
55     uint16_t addr[8];
56     uint16_t unladdr[8];
57     int bufaddr;
58     int count;
59     uint16_t command;
60     uint16_t config[2];
61     uint16_t status;
62     uint16_t intstatus;
63     uint16_t wpstatus;
64
65     ECCState ecc;
66
67     int density_mask;
68     int secs;
69     int secs_cur;
70     int blocks;
71     uint8_t *blockwp;
72 } OneNANDState;
73
74 enum {
75     ONEN_BUF_BLOCK = 0,
76     ONEN_BUF_BLOCK2 = 1,
77     ONEN_BUF_DEST_BLOCK = 2,
78     ONEN_BUF_DEST_PAGE = 3,
79     ONEN_BUF_PAGE = 7,
80 };
81
82 enum {
83     ONEN_ERR_CMD = 1 << 10,
84     ONEN_ERR_ERASE = 1 << 11,
85     ONEN_ERR_PROG = 1 << 12,
86     ONEN_ERR_LOAD = 1 << 13,
87 };
88
89 enum {
90     ONEN_INT_RESET = 1 << 4,
91     ONEN_INT_ERASE = 1 << 5,
92     ONEN_INT_PROG = 1 << 6,
93     ONEN_INT_LOAD = 1 << 7,
94     ONEN_INT = 1 << 15,
95 };
96
97 enum {
98     ONEN_LOCK_LOCKTIGHTEN = 1 << 0,
99     ONEN_LOCK_LOCKED = 1 << 1,
100     ONEN_LOCK_UNLOCKED = 1 << 2,
101 };
102
103 void onenand_base_update(void *opaque, target_phys_addr_t new)
104 {
105     OneNANDState *s = (OneNANDState *) opaque;
106
107     s->base = new;
108
109     /* XXX: We should use IO_MEM_ROMD but we broke it earlier...
110      * Both 0x0000 ... 0x01ff and 0x8000 ... 0x800f can be used to
111      * write boot commands.  Also take note of the BWPS bit.  */
112     cpu_register_physical_memory(s->base + (0x0000 << s->shift),
113                     0x0200 << s->shift, s->iomemtype);
114     cpu_register_physical_memory(s->base + (0x0200 << s->shift),
115                     0xbe00 << s->shift,
116                     (s->ram +(0x0200 << s->shift)) | IO_MEM_RAM);
117     if (s->iomemtype)
118         cpu_register_physical_memory_offset(s->base + (0xc000 << s->shift),
119                     0x4000 << s->shift, s->iomemtype, (0xc000 << s->shift));
120 }
121
122 void onenand_base_unmap(void *opaque)
123 {
124     OneNANDState *s = (OneNANDState *) opaque;
125
126     cpu_register_physical_memory(s->base,
127                     0x10000 << s->shift, IO_MEM_UNASSIGNED);
128 }
129
130 static void onenand_intr_update(OneNANDState *s)
131 {
132     qemu_set_irq(s->intr, ((s->intstatus >> 15) ^ (~s->config[0] >> 6)) & 1);
133 }
134
135 /* Hot reset (Reset OneNAND command) or warm reset (RP pin low) */
136 static void onenand_reset(OneNANDState *s, int cold)
137 {
138     memset(&s->addr, 0, sizeof(s->addr));
139     s->command = 0;
140     s->count = 1;
141     s->bufaddr = 0;
142     s->config[0] = 0x40c0;
143     s->config[1] = 0x0000;
144     onenand_intr_update(s);
145     qemu_irq_raise(s->rdy);
146     s->status = 0x0000;
147     s->intstatus = cold ? 0x8080 : 0x8010;
148     s->unladdr[0] = 0;
149     s->unladdr[1] = 0;
150     s->wpstatus = 0x0002;
151     s->cycle = 0;
152     s->otpmode = 0;
153     s->bdrv_cur = s->bdrv;
154     s->current = s->image;
155     s->secs_cur = s->secs;
156
157     if (cold) {
158         /* Lock the whole flash */
159         memset(s->blockwp, ONEN_LOCK_LOCKED, s->blocks);
160
161         if (s->bdrv && bdrv_read(s->bdrv, 0, s->boot[0], 8) < 0)
162             hw_error("%s: Loading the BootRAM failed.\n", __FUNCTION__);
163     }
164 }
165
166 static inline int onenand_load_main(OneNANDState *s, int sec, int secn,
167                 void *dest)
168 {
169     if (s->bdrv_cur)
170         return bdrv_read(s->bdrv_cur, sec, dest, secn) < 0;
171     else if (sec + secn > s->secs_cur)
172         return 1;
173
174     memcpy(dest, s->current + (sec << 9), secn << 9);
175
176     return 0;
177 }
178
179 static inline int onenand_prog_main(OneNANDState *s, int sec, int secn,
180                 void *src)
181 {
182     if (s->bdrv_cur)
183         return bdrv_write(s->bdrv_cur, sec, src, secn) < 0;
184     else if (sec + secn > s->secs_cur)
185         return 1;
186
187     memcpy(s->current + (sec << 9), src, secn << 9);
188
189     return 0;
190 }
191
192 static inline int onenand_load_spare(OneNANDState *s, int sec, int secn,
193                 void *dest)
194 {
195     uint8_t buf[512];
196
197     if (s->bdrv_cur) {
198         if (bdrv_read(s->bdrv_cur, s->secs_cur + (sec >> 5), buf, 1) < 0)
199             return 1;
200         memcpy(dest, buf + ((sec & 31) << 4), secn << 4);
201     } else if (sec + secn > s->secs_cur)
202         return 1;
203     else
204         memcpy(dest, s->current + (s->secs_cur << 9) + (sec << 4), secn << 4);
205  
206     return 0;
207 }
208
209 static inline int onenand_prog_spare(OneNANDState *s, int sec, int secn,
210                 void *src)
211 {
212     uint8_t buf[512];
213
214     if (s->bdrv_cur) {
215         if (bdrv_read(s->bdrv_cur, s->secs_cur + (sec >> 5), buf, 1) < 0)
216             return 1;
217         memcpy(buf + ((sec & 31) << 4), src, secn << 4);
218         return bdrv_write(s->bdrv_cur, s->secs_cur + (sec >> 5), buf, 1) < 0;
219     } else if (sec + secn > s->secs_cur)
220         return 1;
221
222     memcpy(s->current + (s->secs_cur << 9) + (sec << 4), src, secn << 4);
223  
224     return 0;
225 }
226
227 static inline int onenand_erase(OneNANDState *s, int sec, int num)
228 {
229     /* TODO: optimise */
230     uint8_t buf[512];
231
232     memset(buf, 0xff, sizeof(buf));
233     for (; num > 0; num --, sec ++) {
234         if (onenand_prog_main(s, sec, 1, buf))
235             return 1;
236         if (onenand_prog_spare(s, sec, 1, buf))
237             return 1;
238     }
239
240     return 0;
241 }
242
243 static void onenand_command(OneNANDState *s, int cmd)
244 {
245     int b;
246     int sec;
247     void *buf;
248 #define SETADDR(block, page)                    \
249     sec = (s->addr[page] & 3) +                 \
250             ((((s->addr[page] >> 2) & 0x3f) +   \
251               (((s->addr[block] & 0xfff) |      \
252                 (s->addr[block] >> 15 ?         \
253                  s->density_mask : 0)) << 6)) << (PAGE_SHIFT - 9));
254 #define SETBUF_M()                              \
255     buf = (s->bufaddr & 8) ?                    \
256             s->data[(s->bufaddr >> 2) & 1][0] : s->boot[0];     \
257     buf += (s->bufaddr & 3) << 9;
258 #define SETBUF_S()                              \
259     buf = (s->bufaddr & 8) ?                    \
260             s->data[(s->bufaddr >> 2) & 1][1] : s->boot[1];     \
261     buf += (s->bufaddr & 3) << 4;
262
263     switch (cmd) {
264     case 0x00:  /* Load single/multiple sector data unit into buffer */
265         SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
266
267         SETBUF_M()
268         if (onenand_load_main(s, sec, s->count, buf))
269             s->status |= ONEN_ERR_CMD | ONEN_ERR_LOAD;
270
271 #if 0
272         SETBUF_S()
273         if (onenand_load_spare(s, sec, s->count, buf))
274             s->status |= ONEN_ERR_CMD | ONEN_ERR_LOAD;
275 #endif
276
277         /* TODO: if (s->bufaddr & 3) + s->count was > 4 (2k-pages)
278          * or    if (s->bufaddr & 1) + s->count was > 2 (1k-pages)
279          * then we need two split the read/write into two chunks.
280          */
281         s->intstatus |= ONEN_INT | ONEN_INT_LOAD;
282         break;
283     case 0x13:  /* Load single/multiple spare sector into buffer */
284         SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
285
286         SETBUF_S()
287         if (onenand_load_spare(s, sec, s->count, buf))
288             s->status |= ONEN_ERR_CMD | ONEN_ERR_LOAD;
289
290         /* TODO: if (s->bufaddr & 3) + s->count was > 4 (2k-pages)
291          * or    if (s->bufaddr & 1) + s->count was > 2 (1k-pages)
292          * then we need two split the read/write into two chunks.
293          */
294         s->intstatus |= ONEN_INT | ONEN_INT_LOAD;
295         break;
296     case 0x80:  /* Program single/multiple sector data unit from buffer */
297         SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
298
299         SETBUF_M()
300         if (onenand_prog_main(s, sec, s->count, buf))
301             s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
302
303 #if 0
304         SETBUF_S()
305         if (onenand_prog_spare(s, sec, s->count, buf))
306             s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
307 #endif
308
309         /* TODO: if (s->bufaddr & 3) + s->count was > 4 (2k-pages)
310          * or    if (s->bufaddr & 1) + s->count was > 2 (1k-pages)
311          * then we need two split the read/write into two chunks.
312          */
313         s->intstatus |= ONEN_INT | ONEN_INT_PROG;
314         break;
315     case 0x1a:  /* Program single/multiple spare area sector from buffer */
316         SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
317
318         SETBUF_S()
319         if (onenand_prog_spare(s, sec, s->count, buf))
320             s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
321
322         /* TODO: if (s->bufaddr & 3) + s->count was > 4 (2k-pages)
323          * or    if (s->bufaddr & 1) + s->count was > 2 (1k-pages)
324          * then we need two split the read/write into two chunks.
325          */
326         s->intstatus |= ONEN_INT | ONEN_INT_PROG;
327         break;
328     case 0x1b:  /* Copy-back program */
329         SETBUF_S()
330
331         SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
332         if (onenand_load_main(s, sec, s->count, buf))
333             s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
334
335         SETADDR(ONEN_BUF_DEST_BLOCK, ONEN_BUF_DEST_PAGE)
336         if (onenand_prog_main(s, sec, s->count, buf))
337             s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
338
339         /* TODO: spare areas */
340
341         s->intstatus |= ONEN_INT | ONEN_INT_PROG;
342         break;
343
344     case 0x23:  /* Unlock NAND array block(s) */
345         s->intstatus |= ONEN_INT;
346
347         /* XXX the previous (?) area should be locked automatically */
348         for (b = s->unladdr[0]; b <= s->unladdr[1]; b ++) {
349             if (b >= s->blocks) {
350                 s->status |= ONEN_ERR_CMD;
351                 break;
352             }
353             if (s->blockwp[b] == ONEN_LOCK_LOCKTIGHTEN)
354                 break;
355
356             s->wpstatus = s->blockwp[b] = ONEN_LOCK_UNLOCKED;
357         }
358         break;
359     case 0x27:  /* Unlock All NAND array blocks */
360         s->intstatus |= ONEN_INT;
361
362         for (b = 0; b < s->blocks; b ++) {
363             if (b >= s->blocks) {
364                 s->status |= ONEN_ERR_CMD;
365                 break;
366             }
367             if (s->blockwp[b] == ONEN_LOCK_LOCKTIGHTEN)
368                 break;
369
370             s->wpstatus = s->blockwp[b] = ONEN_LOCK_UNLOCKED;
371         }
372         break;
373
374     case 0x2a:  /* Lock NAND array block(s) */
375         s->intstatus |= ONEN_INT;
376
377         for (b = s->unladdr[0]; b <= s->unladdr[1]; b ++) {
378             if (b >= s->blocks) {
379                 s->status |= ONEN_ERR_CMD;
380                 break;
381             }
382             if (s->blockwp[b] == ONEN_LOCK_LOCKTIGHTEN)
383                 break;
384
385             s->wpstatus = s->blockwp[b] = ONEN_LOCK_LOCKED;
386         }
387         break;
388     case 0x2c:  /* Lock-tight NAND array block(s) */
389         s->intstatus |= ONEN_INT;
390
391         for (b = s->unladdr[0]; b <= s->unladdr[1]; b ++) {
392             if (b >= s->blocks) {
393                 s->status |= ONEN_ERR_CMD;
394                 break;
395             }
396             if (s->blockwp[b] == ONEN_LOCK_UNLOCKED)
397                 continue;
398
399             s->wpstatus = s->blockwp[b] = ONEN_LOCK_LOCKTIGHTEN;
400         }
401         break;
402
403     case 0x71:  /* Erase-Verify-Read */
404         s->intstatus |= ONEN_INT;
405         break;
406     case 0x95:  /* Multi-block erase */
407         qemu_irq_pulse(s->intr);
408         /* Fall through.  */
409     case 0x94:  /* Block erase */
410         sec = ((s->addr[ONEN_BUF_BLOCK] & 0xfff) |
411                         (s->addr[ONEN_BUF_BLOCK] >> 15 ? s->density_mask : 0))
412                 << (BLOCK_SHIFT - 9);
413         if (onenand_erase(s, sec, 1 << (BLOCK_SHIFT - 9)))
414             s->status |= ONEN_ERR_CMD | ONEN_ERR_ERASE;
415
416         s->intstatus |= ONEN_INT | ONEN_INT_ERASE;
417         break;
418     case 0xb0:  /* Erase suspend */
419         break;
420     case 0x30:  /* Erase resume */
421         s->intstatus |= ONEN_INT | ONEN_INT_ERASE;
422         break;
423
424     case 0xf0:  /* Reset NAND Flash core */
425         onenand_reset(s, 0);
426         break;
427     case 0xf3:  /* Reset OneNAND */
428         onenand_reset(s, 0);
429         break;
430
431     case 0x65:  /* OTP Access */
432         s->intstatus |= ONEN_INT;
433         s->bdrv_cur = NULL;
434         s->current = s->otp;
435         s->secs_cur = 1 << (BLOCK_SHIFT - 9);
436         s->addr[ONEN_BUF_BLOCK] = 0;
437         s->otpmode = 1;
438         break;
439
440     default:
441         s->status |= ONEN_ERR_CMD;
442         s->intstatus |= ONEN_INT;
443         fprintf(stderr, "%s: unknown OneNAND command %x\n",
444                         __FUNCTION__, cmd);
445     }
446
447     onenand_intr_update(s);
448 }
449
450 static uint32_t onenand_read(void *opaque, target_phys_addr_t addr)
451 {
452     OneNANDState *s = (OneNANDState *) opaque;
453     int offset = addr >> s->shift;
454
455     switch (offset) {
456     case 0x0000 ... 0xc000:
457         return lduw_le_p(s->boot[0] + addr);
458
459     case 0xf000:        /* Manufacturer ID */
460         return s->id.man;
461     case 0xf001:        /* Device ID */
462         return s->id.dev;
463     case 0xf002:        /* Version ID */
464         return s->id.ver;
465     /* TODO: get the following values from a real chip!  */
466     case 0xf003:        /* Data Buffer size */
467         return 1 << PAGE_SHIFT;
468     case 0xf004:        /* Boot Buffer size */
469         return 0x200;
470     case 0xf005:        /* Amount of buffers */
471         return 1 | (2 << 8);
472     case 0xf006:        /* Technology */
473         return 0;
474
475     case 0xf100 ... 0xf107:     /* Start addresses */
476         return s->addr[offset - 0xf100];
477
478     case 0xf200:        /* Start buffer */
479         return (s->bufaddr << 8) | ((s->count - 1) & (1 << (PAGE_SHIFT - 10)));
480
481     case 0xf220:        /* Command */
482         return s->command;
483     case 0xf221:        /* System Configuration 1 */
484         return s->config[0] & 0xffe0;
485     case 0xf222:        /* System Configuration 2 */
486         return s->config[1];
487
488     case 0xf240:        /* Controller Status */
489         return s->status;
490     case 0xf241:        /* Interrupt */
491         return s->intstatus;
492     case 0xf24c:        /* Unlock Start Block Address */
493         return s->unladdr[0];
494     case 0xf24d:        /* Unlock End Block Address */
495         return s->unladdr[1];
496     case 0xf24e:        /* Write Protection Status */
497         return s->wpstatus;
498
499     case 0xff00:        /* ECC Status */
500         return 0x00;
501     case 0xff01:        /* ECC Result of main area data */
502     case 0xff02:        /* ECC Result of spare area data */
503     case 0xff03:        /* ECC Result of main area data */
504     case 0xff04:        /* ECC Result of spare area data */
505         hw_error("%s: imeplement ECC\n", __FUNCTION__);
506         return 0x0000;
507     }
508
509     fprintf(stderr, "%s: unknown OneNAND register %x\n",
510                     __FUNCTION__, offset);
511     return 0;
512 }
513
514 static void onenand_write(void *opaque, target_phys_addr_t addr,
515                 uint32_t value)
516 {
517     OneNANDState *s = (OneNANDState *) opaque;
518     int offset = addr >> s->shift;
519     int sec;
520
521     switch (offset) {
522     case 0x0000 ... 0x01ff:
523     case 0x8000 ... 0x800f:
524         if (s->cycle) {
525             s->cycle = 0;
526
527             if (value == 0x0000) {
528                 SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
529                 onenand_load_main(s, sec,
530                                 1 << (PAGE_SHIFT - 9), s->data[0][0]);
531                 s->addr[ONEN_BUF_PAGE] += 4;
532                 s->addr[ONEN_BUF_PAGE] &= 0xff;
533             }
534             break;
535         }
536
537         switch (value) {
538         case 0x00f0:    /* Reset OneNAND */
539             onenand_reset(s, 0);
540             break;
541
542         case 0x00e0:    /* Load Data into Buffer */
543             s->cycle = 1;
544             break;
545
546         case 0x0090:    /* Read Identification Data */
547             memset(s->boot[0], 0, 3 << s->shift);
548             s->boot[0][0 << s->shift] = s->id.man & 0xff;
549             s->boot[0][1 << s->shift] = s->id.dev & 0xff;
550             s->boot[0][2 << s->shift] = s->wpstatus & 0xff;
551             break;
552
553         default:
554             fprintf(stderr, "%s: unknown OneNAND boot command %x\n",
555                             __FUNCTION__, value);
556         }
557         break;
558
559     case 0xf100 ... 0xf107:     /* Start addresses */
560         s->addr[offset - 0xf100] = value;
561         break;
562
563     case 0xf200:        /* Start buffer */
564         s->bufaddr = (value >> 8) & 0xf;
565         if (PAGE_SHIFT == 11)
566             s->count = (value & 3) ?: 4;
567         else if (PAGE_SHIFT == 10)
568             s->count = (value & 1) ?: 2;
569         break;
570
571     case 0xf220:        /* Command */
572         if (s->intstatus & (1 << 15))
573             break;
574         s->command = value;
575         onenand_command(s, s->command);
576         break;
577     case 0xf221:        /* System Configuration 1 */
578         s->config[0] = value;
579         onenand_intr_update(s);
580         qemu_set_irq(s->rdy, (s->config[0] >> 7) & 1);
581         break;
582     case 0xf222:        /* System Configuration 2 */
583         s->config[1] = value;
584         break;
585
586     case 0xf241:        /* Interrupt */
587         s->intstatus &= value;
588         if ((1 << 15) & ~s->intstatus)
589             s->status &= ~(ONEN_ERR_CMD | ONEN_ERR_ERASE |
590                             ONEN_ERR_PROG | ONEN_ERR_LOAD);
591         onenand_intr_update(s);
592         break;
593     case 0xf24c:        /* Unlock Start Block Address */
594         s->unladdr[0] = value & (s->blocks - 1);
595         /* For some reason we have to set the end address to by default
596          * be same as start because the software forgets to write anything
597          * in there.  */
598         s->unladdr[1] = value & (s->blocks - 1);
599         break;
600     case 0xf24d:        /* Unlock End Block Address */
601         s->unladdr[1] = value & (s->blocks - 1);
602         break;
603
604     default:
605         fprintf(stderr, "%s: unknown OneNAND register %x\n",
606                         __FUNCTION__, offset);
607     }
608 }
609
610 static CPUReadMemoryFunc * const onenand_readfn[] = {
611     onenand_read,       /* TODO */
612     onenand_read,
613     onenand_read,
614 };
615
616 static CPUWriteMemoryFunc * const onenand_writefn[] = {
617     onenand_write,      /* TODO */
618     onenand_write,
619     onenand_write,
620 };
621
622 void *onenand_init(BlockDriverState *bdrv,
623                 uint16_t man_id, uint16_t dev_id, uint16_t ver_id,
624                 int regshift, qemu_irq irq)
625 {
626     OneNANDState *s = (OneNANDState *) qemu_mallocz(sizeof(*s));
627     uint32_t size = 1 << (24 + ((dev_id >> 4) & 7));
628     void *ram;
629
630     s->shift = regshift;
631     s->intr = irq;
632     s->rdy = NULL;
633     s->id.man = man_id;
634     s->id.dev = dev_id;
635     s->id.ver = ver_id;
636     s->blocks = size >> BLOCK_SHIFT;
637     s->secs = size >> 9;
638     s->blockwp = qemu_malloc(s->blocks);
639     s->density_mask = (dev_id & 0x08) ? (1 << (6 + ((dev_id >> 4) & 7))) : 0;
640     s->iomemtype = cpu_register_io_memory(onenand_readfn,
641                     onenand_writefn, s, DEVICE_NATIVE_ENDIAN);
642     s->bdrv = bdrv;
643     if (!s->bdrv) {
644         s->image = memset(qemu_malloc(size + (size >> 5)),
645                         0xff, size + (size >> 5));
646     s->otp = memset(qemu_malloc((64 + 2) << PAGE_SHIFT),
647                     0xff, (64 + 2) << PAGE_SHIFT);
648     s->ram = qemu_ram_alloc(NULL, "onenand.ram", 0xc000 << s->shift);
649     ram = qemu_get_ram_ptr(s->ram);
650     s->boot[0] = ram + (0x0000 << s->shift);
651     s->boot[1] = ram + (0x8000 << s->shift);
652     s->data[0][0] = ram + ((0x0200 + (0 << (PAGE_SHIFT - 1))) << s->shift);
653     s->data[0][1] = ram + ((0x8010 + (0 << (PAGE_SHIFT - 6))) << s->shift);
654     s->data[1][0] = ram + ((0x0200 + (1 << (PAGE_SHIFT - 1))) << s->shift);
655     s->data[1][1] = ram + ((0x8010 + (1 << (PAGE_SHIFT - 6))) << s->shift);
656
657     onenand_reset(s, 1);
658
659     return s;
660 }
661
662 void *onenand_raw_otp(void *opaque)
663 {
664     OneNANDState *s = (OneNANDState *) opaque;
665
666     return s->otp;
667 }
This page took 0.064335 seconds and 4 git commands to generate.