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

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