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

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