Annotation of qemu/hw/nand.c, revision 1.1.1.6

1.1       root        1: /*
                      2:  * Flash NAND memory emulation.  Based on "16M x 8 Bit NAND Flash
                      3:  * Memory" datasheet for the KM29U128AT / K9F2808U0A chips from
                      4:  * Samsung Electronic.
                      5:  *
                      6:  * Copyright (c) 2006 Openedhand Ltd.
                      7:  * Written by Andrzej Zaborowski <[email protected]>
                      8:  *
                      9:  * This code is licensed under the GNU GPL v2.
                     10:  */
                     11: 
                     12: #ifndef NAND_IO
                     13: 
                     14: # include "hw.h"
                     15: # include "flash.h"
1.1.1.5   root       16: # include "blockdev.h"
1.1       root       17: /* FIXME: Pass block device as an argument.  */
                     18: 
                     19: # define NAND_CMD_READ0                0x00
                     20: # define NAND_CMD_READ1                0x01
                     21: # define NAND_CMD_READ2                0x50
                     22: # define NAND_CMD_LPREAD2      0x30
                     23: # define NAND_CMD_NOSERIALREAD2        0x35
                     24: # define NAND_CMD_RANDOMREAD1  0x05
                     25: # define NAND_CMD_RANDOMREAD2  0xe0
                     26: # define NAND_CMD_READID       0x90
                     27: # define NAND_CMD_RESET                0xff
                     28: # define NAND_CMD_PAGEPROGRAM1 0x80
                     29: # define NAND_CMD_PAGEPROGRAM2 0x10
                     30: # define NAND_CMD_CACHEPROGRAM2        0x15
                     31: # define NAND_CMD_BLOCKERASE1  0x60
                     32: # define NAND_CMD_BLOCKERASE2  0xd0
                     33: # define NAND_CMD_READSTATUS   0x70
                     34: # define NAND_CMD_COPYBACKPRG1 0x85
                     35: 
                     36: # define NAND_IOSTATUS_ERROR   (1 << 0)
                     37: # define NAND_IOSTATUS_PLANE0  (1 << 1)
                     38: # define NAND_IOSTATUS_PLANE1  (1 << 2)
                     39: # define NAND_IOSTATUS_PLANE2  (1 << 3)
                     40: # define NAND_IOSTATUS_PLANE3  (1 << 4)
                     41: # define NAND_IOSTATUS_BUSY    (1 << 6)
                     42: # define NAND_IOSTATUS_UNPROTCT        (1 << 7)
                     43: 
                     44: # define MAX_PAGE              0x800
                     45: # define MAX_OOB               0x40
                     46: 
1.1.1.3   root       47: struct NANDFlashState {
1.1       root       48:     uint8_t manf_id, chip_id;
                     49:     int size, pages;
                     50:     int page_shift, oob_shift, erase_shift, addr_shift;
                     51:     uint8_t *storage;
                     52:     BlockDriverState *bdrv;
                     53:     int mem_oob;
                     54: 
1.1.1.6 ! root       55:     uint8_t cle, ale, ce, wp, gnd;
1.1       root       56: 
                     57:     uint8_t io[MAX_PAGE + MAX_OOB + 0x400];
                     58:     uint8_t *ioaddr;
                     59:     int iolen;
                     60: 
                     61:     uint32_t cmd, addr;
                     62:     int addrlen;
                     63:     int status;
                     64:     int offset;
                     65: 
1.1.1.3   root       66:     void (*blk_write)(NANDFlashState *s);
                     67:     void (*blk_erase)(NANDFlashState *s);
                     68:     void (*blk_load)(NANDFlashState *s, uint32_t addr, int offset);
1.1.1.6 ! root       69: 
        !            70:     uint32_t ioaddr_vmstate;
1.1       root       71: };
                     72: 
                     73: # define NAND_NO_AUTOINCR      0x00000001
                     74: # define NAND_BUSWIDTH_16      0x00000002
                     75: # define NAND_NO_PADDING       0x00000004
                     76: # define NAND_CACHEPRG         0x00000008
                     77: # define NAND_COPYBACK         0x00000010
                     78: # define NAND_IS_AND           0x00000020
                     79: # define NAND_4PAGE_ARRAY      0x00000040
                     80: # define NAND_NO_READRDY       0x00000100
                     81: # define NAND_SAMSUNG_LP       (NAND_NO_PADDING | NAND_COPYBACK)
                     82: 
                     83: # define NAND_IO
                     84: 
                     85: # define PAGE(addr)            ((addr) >> ADDR_SHIFT)
                     86: # define PAGE_START(page)      (PAGE(page) * (PAGE_SIZE + OOB_SIZE))
                     87: # define PAGE_MASK             ((1 << ADDR_SHIFT) - 1)
                     88: # define OOB_SHIFT             (PAGE_SHIFT - 5)
                     89: # define OOB_SIZE              (1 << OOB_SHIFT)
                     90: # define SECTOR(addr)          ((addr) >> (9 + ADDR_SHIFT - PAGE_SHIFT))
                     91: # define SECTOR_OFFSET(addr)   ((addr) & ((511 >> PAGE_SHIFT) << 8))
                     92: 
                     93: # define PAGE_SIZE             256
                     94: # define PAGE_SHIFT            8
                     95: # define PAGE_SECTORS          1
                     96: # define ADDR_SHIFT            8
                     97: # include "nand.c"
                     98: # define PAGE_SIZE             512
                     99: # define PAGE_SHIFT            9
                    100: # define PAGE_SECTORS          1
                    101: # define ADDR_SHIFT            8
                    102: # include "nand.c"
                    103: # define PAGE_SIZE             2048
                    104: # define PAGE_SHIFT            11
                    105: # define PAGE_SECTORS          4
                    106: # define ADDR_SHIFT            16
                    107: # include "nand.c"
                    108: 
                    109: /* Information based on Linux drivers/mtd/nand/nand_ids.c */
1.1.1.3   root      110: static const struct {
1.1       root      111:     int size;
                    112:     int width;
                    113:     int page_shift;
                    114:     int erase_shift;
                    115:     uint32_t options;
                    116: } nand_flash_ids[0x100] = {
                    117:     [0 ... 0xff] = { 0 },
                    118: 
                    119:     [0x6e] = { 1,      8,      8, 4, 0 },
                    120:     [0x64] = { 2,      8,      8, 4, 0 },
                    121:     [0x6b] = { 4,      8,      9, 4, 0 },
                    122:     [0xe8] = { 1,      8,      8, 4, 0 },
                    123:     [0xec] = { 1,      8,      8, 4, 0 },
                    124:     [0xea] = { 2,      8,      8, 4, 0 },
                    125:     [0xd5] = { 4,      8,      9, 4, 0 },
                    126:     [0xe3] = { 4,      8,      9, 4, 0 },
                    127:     [0xe5] = { 4,      8,      9, 4, 0 },
                    128:     [0xd6] = { 8,      8,      9, 4, 0 },
                    129: 
                    130:     [0x39] = { 8,      8,      9, 4, 0 },
                    131:     [0xe6] = { 8,      8,      9, 4, 0 },
                    132:     [0x49] = { 8,      16,     9, 4, NAND_BUSWIDTH_16 },
                    133:     [0x59] = { 8,      16,     9, 4, NAND_BUSWIDTH_16 },
                    134: 
                    135:     [0x33] = { 16,     8,      9, 5, 0 },
                    136:     [0x73] = { 16,     8,      9, 5, 0 },
                    137:     [0x43] = { 16,     16,     9, 5, NAND_BUSWIDTH_16 },
                    138:     [0x53] = { 16,     16,     9, 5, NAND_BUSWIDTH_16 },
                    139: 
                    140:     [0x35] = { 32,     8,      9, 5, 0 },
                    141:     [0x75] = { 32,     8,      9, 5, 0 },
                    142:     [0x45] = { 32,     16,     9, 5, NAND_BUSWIDTH_16 },
                    143:     [0x55] = { 32,     16,     9, 5, NAND_BUSWIDTH_16 },
                    144: 
                    145:     [0x36] = { 64,     8,      9, 5, 0 },
                    146:     [0x76] = { 64,     8,      9, 5, 0 },
                    147:     [0x46] = { 64,     16,     9, 5, NAND_BUSWIDTH_16 },
                    148:     [0x56] = { 64,     16,     9, 5, NAND_BUSWIDTH_16 },
                    149: 
                    150:     [0x78] = { 128,    8,      9, 5, 0 },
                    151:     [0x39] = { 128,    8,      9, 5, 0 },
                    152:     [0x79] = { 128,    8,      9, 5, 0 },
                    153:     [0x72] = { 128,    16,     9, 5, NAND_BUSWIDTH_16 },
                    154:     [0x49] = { 128,    16,     9, 5, NAND_BUSWIDTH_16 },
                    155:     [0x74] = { 128,    16,     9, 5, NAND_BUSWIDTH_16 },
                    156:     [0x59] = { 128,    16,     9, 5, NAND_BUSWIDTH_16 },
                    157: 
                    158:     [0x71] = { 256,    8,      9, 5, 0 },
                    159: 
                    160:     /*
                    161:      * These are the new chips with large page size. The pagesize and the
                    162:      * erasesize is determined from the extended id bytes
                    163:      */
                    164: # define LP_OPTIONS    (NAND_SAMSUNG_LP | NAND_NO_READRDY | NAND_NO_AUTOINCR)
                    165: # define LP_OPTIONS16  (LP_OPTIONS | NAND_BUSWIDTH_16)
                    166: 
                    167:     /* 512 Megabit */
                    168:     [0xa2] = { 64,     8,      0, 0, LP_OPTIONS },
                    169:     [0xf2] = { 64,     8,      0, 0, LP_OPTIONS },
                    170:     [0xb2] = { 64,     16,     0, 0, LP_OPTIONS16 },
                    171:     [0xc2] = { 64,     16,     0, 0, LP_OPTIONS16 },
                    172: 
                    173:     /* 1 Gigabit */
                    174:     [0xa1] = { 128,    8,      0, 0, LP_OPTIONS },
                    175:     [0xf1] = { 128,    8,      0, 0, LP_OPTIONS },
                    176:     [0xb1] = { 128,    16,     0, 0, LP_OPTIONS16 },
                    177:     [0xc1] = { 128,    16,     0, 0, LP_OPTIONS16 },
                    178: 
                    179:     /* 2 Gigabit */
                    180:     [0xaa] = { 256,    8,      0, 0, LP_OPTIONS },
                    181:     [0xda] = { 256,    8,      0, 0, LP_OPTIONS },
                    182:     [0xba] = { 256,    16,     0, 0, LP_OPTIONS16 },
                    183:     [0xca] = { 256,    16,     0, 0, LP_OPTIONS16 },
                    184: 
                    185:     /* 4 Gigabit */
                    186:     [0xac] = { 512,    8,      0, 0, LP_OPTIONS },
                    187:     [0xdc] = { 512,    8,      0, 0, LP_OPTIONS },
                    188:     [0xbc] = { 512,    16,     0, 0, LP_OPTIONS16 },
                    189:     [0xcc] = { 512,    16,     0, 0, LP_OPTIONS16 },
                    190: 
                    191:     /* 8 Gigabit */
                    192:     [0xa3] = { 1024,   8,      0, 0, LP_OPTIONS },
                    193:     [0xd3] = { 1024,   8,      0, 0, LP_OPTIONS },
                    194:     [0xb3] = { 1024,   16,     0, 0, LP_OPTIONS16 },
                    195:     [0xc3] = { 1024,   16,     0, 0, LP_OPTIONS16 },
                    196: 
                    197:     /* 16 Gigabit */
                    198:     [0xa5] = { 2048,   8,      0, 0, LP_OPTIONS },
                    199:     [0xd5] = { 2048,   8,      0, 0, LP_OPTIONS },
                    200:     [0xb5] = { 2048,   16,     0, 0, LP_OPTIONS16 },
                    201:     [0xc5] = { 2048,   16,     0, 0, LP_OPTIONS16 },
                    202: };
                    203: 
1.1.1.3   root      204: static void nand_reset(NANDFlashState *s)
1.1       root      205: {
                    206:     s->cmd = NAND_CMD_READ0;
                    207:     s->addr = 0;
                    208:     s->addrlen = 0;
                    209:     s->iolen = 0;
                    210:     s->offset = 0;
                    211:     s->status &= NAND_IOSTATUS_UNPROTCT;
                    212: }
                    213: 
1.1.1.3   root      214: static void nand_command(NANDFlashState *s)
1.1       root      215: {
1.1.1.5   root      216:     unsigned int offset;
1.1       root      217:     switch (s->cmd) {
                    218:     case NAND_CMD_READ0:
                    219:         s->iolen = 0;
                    220:         break;
                    221: 
                    222:     case NAND_CMD_READID:
                    223:         s->io[0] = s->manf_id;
                    224:         s->io[1] = s->chip_id;
                    225:         s->io[2] = 'Q';                /* Don't-care byte (often 0xa5) */
                    226:         if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP)
                    227:             s->io[3] = 0x15;   /* Page Size, Block Size, Spare Size.. */
                    228:         else
                    229:             s->io[3] = 0xc0;   /* Multi-plane */
                    230:         s->ioaddr = s->io;
                    231:         s->iolen = 4;
                    232:         break;
                    233: 
                    234:     case NAND_CMD_RANDOMREAD2:
                    235:     case NAND_CMD_NOSERIALREAD2:
                    236:         if (!(nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP))
                    237:             break;
1.1.1.5   root      238:         offset = s->addr & ((1 << s->addr_shift) - 1);
                    239:         s->blk_load(s, s->addr, offset);
                    240:         if (s->gnd)
                    241:             s->iolen = (1 << s->page_shift) - offset;
                    242:         else
                    243:             s->iolen = (1 << s->page_shift) + (1 << s->oob_shift) - offset;
1.1       root      244:         break;
                    245: 
                    246:     case NAND_CMD_RESET:
                    247:         nand_reset(s);
                    248:         break;
                    249: 
                    250:     case NAND_CMD_PAGEPROGRAM1:
                    251:         s->ioaddr = s->io;
                    252:         s->iolen = 0;
                    253:         break;
                    254: 
                    255:     case NAND_CMD_PAGEPROGRAM2:
                    256:         if (s->wp) {
                    257:             s->blk_write(s);
                    258:         }
                    259:         break;
                    260: 
                    261:     case NAND_CMD_BLOCKERASE1:
                    262:         break;
                    263: 
                    264:     case NAND_CMD_BLOCKERASE2:
                    265:         if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP)
                    266:             s->addr <<= 16;
                    267:         else
                    268:             s->addr <<= 8;
                    269: 
                    270:         if (s->wp) {
                    271:             s->blk_erase(s);
                    272:         }
                    273:         break;
                    274: 
                    275:     case NAND_CMD_READSTATUS:
                    276:         s->io[0] = s->status;
                    277:         s->ioaddr = s->io;
                    278:         s->iolen = 1;
                    279:         break;
                    280: 
                    281:     default:
                    282:         printf("%s: Unknown NAND command 0x%02x\n", __FUNCTION__, s->cmd);
                    283:     }
                    284: }
                    285: 
1.1.1.6 ! root      286: static void nand_pre_save(void *opaque)
        !           287: {
        !           288:     NANDFlashState *s = opaque;
        !           289: 
        !           290:     s->ioaddr_vmstate = s->ioaddr - s->io;
        !           291: }
        !           292: 
        !           293: static int nand_post_load(void *opaque, int version_id)
1.1       root      294: {
1.1.1.6 ! root      295:     NANDFlashState *s = opaque;
        !           296: 
        !           297:     if (s->ioaddr_vmstate > sizeof(s->io)) {
1.1       root      298:         return -EINVAL;
1.1.1.6 ! root      299:     }
        !           300:     s->ioaddr = s->io + s->ioaddr_vmstate;
1.1       root      301: 
                    302:     return 0;
                    303: }
                    304: 
1.1.1.6 ! root      305: static const VMStateDescription vmstate_nand = {
        !           306:     .name = "nand",
        !           307:     .version_id = 0,
        !           308:     .minimum_version_id = 0,
        !           309:     .minimum_version_id_old = 0,
        !           310:     .pre_save = nand_pre_save,
        !           311:     .post_load = nand_post_load,
        !           312:     .fields      = (VMStateField[]) {
        !           313:         VMSTATE_UINT8(cle, NANDFlashState),
        !           314:         VMSTATE_UINT8(ale, NANDFlashState),
        !           315:         VMSTATE_UINT8(ce, NANDFlashState),
        !           316:         VMSTATE_UINT8(wp, NANDFlashState),
        !           317:         VMSTATE_UINT8(gnd, NANDFlashState),
        !           318:         VMSTATE_BUFFER(io, NANDFlashState),
        !           319:         VMSTATE_UINT32(ioaddr_vmstate, NANDFlashState),
        !           320:         VMSTATE_INT32(iolen, NANDFlashState),
        !           321:         VMSTATE_UINT32(cmd, NANDFlashState),
        !           322:         VMSTATE_UINT32(addr, NANDFlashState),
        !           323:         VMSTATE_INT32(addrlen, NANDFlashState),
        !           324:         VMSTATE_INT32(status, NANDFlashState),
        !           325:         VMSTATE_INT32(offset, NANDFlashState),
        !           326:         /* XXX: do we want to save s->storage too? */
        !           327:         VMSTATE_END_OF_LIST()
        !           328:     }
        !           329: };
        !           330: 
1.1       root      331: /*
                    332:  * Chip inputs are CLE, ALE, CE, WP, GND and eight I/O pins.  Chip
                    333:  * outputs are R/B and eight I/O pins.
                    334:  *
                    335:  * CE, WP and R/B are active low.
                    336:  */
1.1.1.6 ! root      337: void nand_setpins(NANDFlashState *s, uint8_t cle, uint8_t ale,
        !           338:                   uint8_t ce, uint8_t wp, uint8_t gnd)
1.1       root      339: {
                    340:     s->cle = cle;
                    341:     s->ale = ale;
                    342:     s->ce = ce;
                    343:     s->wp = wp;
                    344:     s->gnd = gnd;
                    345:     if (wp)
                    346:         s->status |= NAND_IOSTATUS_UNPROTCT;
                    347:     else
                    348:         s->status &= ~NAND_IOSTATUS_UNPROTCT;
                    349: }
                    350: 
1.1.1.3   root      351: void nand_getpins(NANDFlashState *s, int *rb)
1.1       root      352: {
                    353:     *rb = 1;
                    354: }
                    355: 
1.1.1.3   root      356: void nand_setio(NANDFlashState *s, uint8_t value)
1.1       root      357: {
                    358:     if (!s->ce && s->cle) {
                    359:         if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
                    360:             if (s->cmd == NAND_CMD_READ0 && value == NAND_CMD_LPREAD2)
                    361:                 return;
                    362:             if (value == NAND_CMD_RANDOMREAD1) {
                    363:                 s->addr &= ~((1 << s->addr_shift) - 1);
                    364:                 s->addrlen = 0;
                    365:                 return;
                    366:             }
                    367:         }
                    368:         if (value == NAND_CMD_READ0)
                    369:             s->offset = 0;
                    370:        else if (value == NAND_CMD_READ1) {
                    371:             s->offset = 0x100;
                    372:             value = NAND_CMD_READ0;
                    373:         }
                    374:        else if (value == NAND_CMD_READ2) {
                    375:             s->offset = 1 << s->page_shift;
                    376:             value = NAND_CMD_READ0;
                    377:         }
                    378: 
                    379:         s->cmd = value;
                    380: 
                    381:         if (s->cmd == NAND_CMD_READSTATUS ||
                    382:                 s->cmd == NAND_CMD_PAGEPROGRAM2 ||
                    383:                 s->cmd == NAND_CMD_BLOCKERASE1 ||
                    384:                 s->cmd == NAND_CMD_BLOCKERASE2 ||
                    385:                 s->cmd == NAND_CMD_NOSERIALREAD2 ||
                    386:                 s->cmd == NAND_CMD_RANDOMREAD2 ||
                    387:                 s->cmd == NAND_CMD_RESET)
                    388:             nand_command(s);
                    389: 
                    390:         if (s->cmd != NAND_CMD_RANDOMREAD2) {
                    391:             s->addrlen = 0;
                    392:         }
                    393:     }
                    394: 
                    395:     if (s->ale) {
1.1.1.5   root      396:         unsigned int shift = s->addrlen * 8;
                    397:         unsigned int mask = ~(0xff << shift);
                    398:         unsigned int v = value << shift;
                    399: 
                    400:         s->addr = (s->addr & mask) | v;
1.1       root      401:         s->addrlen ++;
                    402: 
                    403:         if (s->addrlen == 1 && s->cmd == NAND_CMD_READID)
                    404:             nand_command(s);
                    405: 
                    406:         if (!(nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) &&
                    407:                 s->addrlen == 3 && (
                    408:                     s->cmd == NAND_CMD_READ0 ||
                    409:                     s->cmd == NAND_CMD_PAGEPROGRAM1))
                    410:             nand_command(s);
                    411:         if ((nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) &&
                    412:                s->addrlen == 4 && (
                    413:                     s->cmd == NAND_CMD_READ0 ||
                    414:                     s->cmd == NAND_CMD_PAGEPROGRAM1))
                    415:             nand_command(s);
                    416:     }
                    417: 
                    418:     if (!s->cle && !s->ale && s->cmd == NAND_CMD_PAGEPROGRAM1) {
                    419:         if (s->iolen < (1 << s->page_shift) + (1 << s->oob_shift))
                    420:             s->io[s->iolen ++] = value;
                    421:     } else if (!s->cle && !s->ale && s->cmd == NAND_CMD_COPYBACKPRG1) {
                    422:         if ((s->addr & ((1 << s->addr_shift) - 1)) <
                    423:                 (1 << s->page_shift) + (1 << s->oob_shift)) {
                    424:             s->io[s->iolen + (s->addr & ((1 << s->addr_shift) - 1))] = value;
                    425:             s->addr ++;
                    426:         }
                    427:     }
                    428: }
                    429: 
1.1.1.3   root      430: uint8_t nand_getio(NANDFlashState *s)
1.1       root      431: {
                    432:     int offset;
                    433: 
                    434:     /* Allow sequential reading */
                    435:     if (!s->iolen && s->cmd == NAND_CMD_READ0) {
                    436:         offset = (s->addr & ((1 << s->addr_shift) - 1)) + s->offset;
                    437:         s->offset = 0;
                    438: 
                    439:         s->blk_load(s, s->addr, offset);
                    440:         if (s->gnd)
                    441:             s->iolen = (1 << s->page_shift) - offset;
                    442:         else
                    443:             s->iolen = (1 << s->page_shift) + (1 << s->oob_shift) - offset;
                    444:     }
                    445: 
                    446:     if (s->ce || s->iolen <= 0)
                    447:         return 0;
                    448: 
                    449:     s->iolen --;
1.1.1.5   root      450:     s->addr++;
1.1       root      451:     return *(s->ioaddr ++);
                    452: }
                    453: 
1.1.1.3   root      454: NANDFlashState *nand_init(int manf_id, int chip_id)
1.1       root      455: {
                    456:     int pagesize;
1.1.1.3   root      457:     NANDFlashState *s;
1.1.1.4   root      458:     DriveInfo *dinfo;
1.1       root      459: 
                    460:     if (nand_flash_ids[chip_id].size == 0) {
1.1.1.3   root      461:         hw_error("%s: Unsupported NAND chip ID.\n", __FUNCTION__);
1.1       root      462:     }
                    463: 
1.1.1.3   root      464:     s = (NANDFlashState *) qemu_mallocz(sizeof(NANDFlashState));
1.1.1.4   root      465:     dinfo = drive_get(IF_MTD, 0, 0);
                    466:     if (dinfo)
                    467:         s->bdrv = dinfo->bdrv;
1.1       root      468:     s->manf_id = manf_id;
                    469:     s->chip_id = chip_id;
                    470:     s->size = nand_flash_ids[s->chip_id].size << 20;
                    471:     if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
                    472:         s->page_shift = 11;
                    473:         s->erase_shift = 6;
                    474:     } else {
                    475:         s->page_shift = nand_flash_ids[s->chip_id].page_shift;
                    476:         s->erase_shift = nand_flash_ids[s->chip_id].erase_shift;
                    477:     }
                    478: 
                    479:     switch (1 << s->page_shift) {
                    480:     case 256:
                    481:         nand_init_256(s);
                    482:         break;
                    483:     case 512:
                    484:         nand_init_512(s);
                    485:         break;
                    486:     case 2048:
                    487:         nand_init_2048(s);
                    488:         break;
                    489:     default:
1.1.1.3   root      490:         hw_error("%s: Unsupported NAND block size.\n", __FUNCTION__);
1.1       root      491:     }
                    492: 
                    493:     pagesize = 1 << s->oob_shift;
                    494:     s->mem_oob = 1;
                    495:     if (s->bdrv && bdrv_getlength(s->bdrv) >=
                    496:                     (s->pages << s->page_shift) + (s->pages << s->oob_shift)) {
                    497:         pagesize = 0;
                    498:         s->mem_oob = 0;
                    499:     }
                    500: 
                    501:     if (!s->bdrv)
                    502:         pagesize += 1 << s->page_shift;
                    503:     if (pagesize)
                    504:         s->storage = (uint8_t *) memset(qemu_malloc(s->pages * pagesize),
                    505:                         0xff, s->pages * pagesize);
1.1.1.2   root      506:     /* Give s->ioaddr a sane value in case we save state before it
                    507:        is used.  */
                    508:     s->ioaddr = s->io;
1.1       root      509: 
1.1.1.6 ! root      510:     vmstate_register(NULL, -1, &vmstate_nand, s);
1.1       root      511: 
                    512:     return s;
                    513: }
                    514: 
1.1.1.3   root      515: void nand_done(NANDFlashState *s)
1.1       root      516: {
                    517:     if (s->bdrv) {
                    518:         bdrv_close(s->bdrv);
                    519:         bdrv_delete(s->bdrv);
                    520:     }
                    521: 
                    522:     if (!s->bdrv || s->mem_oob)
1.1.1.4   root      523:         qemu_free(s->storage);
1.1       root      524: 
1.1.1.4   root      525:     qemu_free(s);
1.1       root      526: }
                    527: 
                    528: #else
                    529: 
                    530: /* Program a single page */
1.1.1.3   root      531: static void glue(nand_blk_write_, PAGE_SIZE)(NANDFlashState *s)
1.1       root      532: {
                    533:     uint32_t off, page, sector, soff;
                    534:     uint8_t iobuf[(PAGE_SECTORS + 2) * 0x200];
                    535:     if (PAGE(s->addr) >= s->pages)
                    536:         return;
                    537: 
                    538:     if (!s->bdrv) {
                    539:         memcpy(s->storage + PAGE_START(s->addr) + (s->addr & PAGE_MASK) +
                    540:                         s->offset, s->io, s->iolen);
                    541:     } else if (s->mem_oob) {
                    542:         sector = SECTOR(s->addr);
                    543:         off = (s->addr & PAGE_MASK) + s->offset;
                    544:         soff = SECTOR_OFFSET(s->addr);
                    545:         if (bdrv_read(s->bdrv, sector, iobuf, PAGE_SECTORS) == -1) {
                    546:             printf("%s: read error in sector %i\n", __FUNCTION__, sector);
                    547:             return;
                    548:         }
                    549: 
                    550:         memcpy(iobuf + (soff | off), s->io, MIN(s->iolen, PAGE_SIZE - off));
                    551:         if (off + s->iolen > PAGE_SIZE) {
                    552:             page = PAGE(s->addr);
                    553:             memcpy(s->storage + (page << OOB_SHIFT), s->io + PAGE_SIZE - off,
                    554:                             MIN(OOB_SIZE, off + s->iolen - PAGE_SIZE));
                    555:         }
                    556: 
                    557:         if (bdrv_write(s->bdrv, sector, iobuf, PAGE_SECTORS) == -1)
                    558:             printf("%s: write error in sector %i\n", __FUNCTION__, sector);
                    559:     } else {
                    560:         off = PAGE_START(s->addr) + (s->addr & PAGE_MASK) + s->offset;
                    561:         sector = off >> 9;
                    562:         soff = off & 0x1ff;
                    563:         if (bdrv_read(s->bdrv, sector, iobuf, PAGE_SECTORS + 2) == -1) {
                    564:             printf("%s: read error in sector %i\n", __FUNCTION__, sector);
                    565:             return;
                    566:         }
                    567: 
                    568:         memcpy(iobuf + soff, s->io, s->iolen);
                    569: 
                    570:         if (bdrv_write(s->bdrv, sector, iobuf, PAGE_SECTORS + 2) == -1)
                    571:             printf("%s: write error in sector %i\n", __FUNCTION__, sector);
                    572:     }
                    573:     s->offset = 0;
                    574: }
                    575: 
                    576: /* Erase a single block */
1.1.1.3   root      577: static void glue(nand_blk_erase_, PAGE_SIZE)(NANDFlashState *s)
1.1       root      578: {
                    579:     uint32_t i, page, addr;
                    580:     uint8_t iobuf[0x200] = { [0 ... 0x1ff] = 0xff, };
                    581:     addr = s->addr & ~((1 << (ADDR_SHIFT + s->erase_shift)) - 1);
                    582: 
                    583:     if (PAGE(addr) >= s->pages)
                    584:         return;
                    585: 
                    586:     if (!s->bdrv) {
                    587:         memset(s->storage + PAGE_START(addr),
                    588:                         0xff, (PAGE_SIZE + OOB_SIZE) << s->erase_shift);
                    589:     } else if (s->mem_oob) {
                    590:         memset(s->storage + (PAGE(addr) << OOB_SHIFT),
                    591:                         0xff, OOB_SIZE << s->erase_shift);
                    592:         i = SECTOR(addr);
                    593:         page = SECTOR(addr + (ADDR_SHIFT + s->erase_shift));
                    594:         for (; i < page; i ++)
                    595:             if (bdrv_write(s->bdrv, i, iobuf, 1) == -1)
                    596:                 printf("%s: write error in sector %i\n", __FUNCTION__, i);
                    597:     } else {
                    598:         addr = PAGE_START(addr);
                    599:         page = addr >> 9;
                    600:         if (bdrv_read(s->bdrv, page, iobuf, 1) == -1)
                    601:             printf("%s: read error in sector %i\n", __FUNCTION__, page);
                    602:         memset(iobuf + (addr & 0x1ff), 0xff, (~addr & 0x1ff) + 1);
                    603:         if (bdrv_write(s->bdrv, page, iobuf, 1) == -1)
                    604:             printf("%s: write error in sector %i\n", __FUNCTION__, page);
                    605: 
                    606:         memset(iobuf, 0xff, 0x200);
                    607:         i = (addr & ~0x1ff) + 0x200;
                    608:         for (addr += ((PAGE_SIZE + OOB_SIZE) << s->erase_shift) - 0x200;
                    609:                         i < addr; i += 0x200)
                    610:             if (bdrv_write(s->bdrv, i >> 9, iobuf, 1) == -1)
                    611:                 printf("%s: write error in sector %i\n", __FUNCTION__, i >> 9);
                    612: 
                    613:         page = i >> 9;
                    614:         if (bdrv_read(s->bdrv, page, iobuf, 1) == -1)
                    615:             printf("%s: read error in sector %i\n", __FUNCTION__, page);
                    616:         memset(iobuf, 0xff, ((addr - 1) & 0x1ff) + 1);
                    617:         if (bdrv_write(s->bdrv, page, iobuf, 1) == -1)
                    618:             printf("%s: write error in sector %i\n", __FUNCTION__, page);
                    619:     }
                    620: }
                    621: 
1.1.1.3   root      622: static void glue(nand_blk_load_, PAGE_SIZE)(NANDFlashState *s,
1.1       root      623:                 uint32_t addr, int offset)
                    624: {
                    625:     if (PAGE(addr) >= s->pages)
                    626:         return;
                    627: 
                    628:     if (s->bdrv) {
                    629:         if (s->mem_oob) {
                    630:             if (bdrv_read(s->bdrv, SECTOR(addr), s->io, PAGE_SECTORS) == -1)
                    631:                 printf("%s: read error in sector %i\n",
                    632:                                 __FUNCTION__, SECTOR(addr));
                    633:             memcpy(s->io + SECTOR_OFFSET(s->addr) + PAGE_SIZE,
                    634:                             s->storage + (PAGE(s->addr) << OOB_SHIFT),
                    635:                             OOB_SIZE);
                    636:             s->ioaddr = s->io + SECTOR_OFFSET(s->addr) + offset;
                    637:         } else {
                    638:             if (bdrv_read(s->bdrv, PAGE_START(addr) >> 9,
                    639:                                     s->io, (PAGE_SECTORS + 2)) == -1)
                    640:                 printf("%s: read error in sector %i\n",
                    641:                                 __FUNCTION__, PAGE_START(addr) >> 9);
                    642:             s->ioaddr = s->io + (PAGE_START(addr) & 0x1ff) + offset;
                    643:         }
                    644:     } else {
                    645:         memcpy(s->io, s->storage + PAGE_START(s->addr) +
                    646:                         offset, PAGE_SIZE + OOB_SIZE - offset);
                    647:         s->ioaddr = s->io;
                    648:     }
                    649: }
                    650: 
1.1.1.3   root      651: static void glue(nand_init_, PAGE_SIZE)(NANDFlashState *s)
1.1       root      652: {
                    653:     s->oob_shift = PAGE_SHIFT - 5;
                    654:     s->pages = s->size >> PAGE_SHIFT;
                    655:     s->addr_shift = ADDR_SHIFT;
                    656: 
                    657:     s->blk_erase = glue(nand_blk_erase_, PAGE_SIZE);
                    658:     s->blk_write = glue(nand_blk_write_, PAGE_SIZE);
                    659:     s->blk_load = glue(nand_blk_load_, PAGE_SIZE);
                    660: }
                    661: 
                    662: # undef PAGE_SIZE
                    663: # undef PAGE_SHIFT
                    664: # undef PAGE_SECTORS
                    665: # undef ADDR_SHIFT
                    666: #endif /* NAND_IO */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.