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