symbian-qemu-0.9.1-12/qemu-symbian-svp/hw/nand.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     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 <balrog@zabor.org>
       
     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 static const 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 /*
       
   323  * Chip inputs are CLE, ALE, CE, WP, GND and eight I/O pins.  Chip
       
   324  * outputs are R/B and eight I/O pins.
       
   325  *
       
   326  * CE, WP and R/B are active low.
       
   327  */
       
   328 void nand_setpins(struct nand_flash_s *s,
       
   329                 int cle, int ale, int ce, int wp, int gnd)
       
   330 {
       
   331     s->cle = cle;
       
   332     s->ale = ale;
       
   333     s->ce = ce;
       
   334     s->wp = wp;
       
   335     s->gnd = gnd;
       
   336     if (wp)
       
   337         s->status |= NAND_IOSTATUS_UNPROTCT;
       
   338     else
       
   339         s->status &= ~NAND_IOSTATUS_UNPROTCT;
       
   340 }
       
   341 
       
   342 void nand_getpins(struct nand_flash_s *s, int *rb)
       
   343 {
       
   344     *rb = 1;
       
   345 }
       
   346 
       
   347 void nand_setio(struct nand_flash_s *s, uint8_t value)
       
   348 {
       
   349     if (!s->ce && s->cle) {
       
   350         if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
       
   351             if (s->cmd == NAND_CMD_READ0 && value == NAND_CMD_LPREAD2)
       
   352                 return;
       
   353             if (value == NAND_CMD_RANDOMREAD1) {
       
   354                 s->addr &= ~((1 << s->addr_shift) - 1);
       
   355                 s->addrlen = 0;
       
   356                 return;
       
   357             }
       
   358         }
       
   359         if (value == NAND_CMD_READ0)
       
   360             s->offset = 0;
       
   361 	else if (value == NAND_CMD_READ1) {
       
   362             s->offset = 0x100;
       
   363             value = NAND_CMD_READ0;
       
   364         }
       
   365 	else if (value == NAND_CMD_READ2) {
       
   366             s->offset = 1 << s->page_shift;
       
   367             value = NAND_CMD_READ0;
       
   368         }
       
   369 
       
   370         s->cmd = value;
       
   371 
       
   372         if (s->cmd == NAND_CMD_READSTATUS ||
       
   373                 s->cmd == NAND_CMD_PAGEPROGRAM2 ||
       
   374                 s->cmd == NAND_CMD_BLOCKERASE1 ||
       
   375                 s->cmd == NAND_CMD_BLOCKERASE2 ||
       
   376                 s->cmd == NAND_CMD_NOSERIALREAD2 ||
       
   377                 s->cmd == NAND_CMD_RANDOMREAD2 ||
       
   378                 s->cmd == NAND_CMD_RESET)
       
   379             nand_command(s);
       
   380 
       
   381         if (s->cmd != NAND_CMD_RANDOMREAD2) {
       
   382             s->addrlen = 0;
       
   383             s->addr = 0;
       
   384         }
       
   385     }
       
   386 
       
   387     if (s->ale) {
       
   388         s->addr |= value << (s->addrlen * 8);
       
   389         s->addrlen ++;
       
   390 
       
   391         if (s->addrlen == 1 && s->cmd == NAND_CMD_READID)
       
   392             nand_command(s);
       
   393 
       
   394         if (!(nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) &&
       
   395                 s->addrlen == 3 && (
       
   396                     s->cmd == NAND_CMD_READ0 ||
       
   397                     s->cmd == NAND_CMD_PAGEPROGRAM1))
       
   398             nand_command(s);
       
   399         if ((nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) &&
       
   400                s->addrlen == 4 && (
       
   401                     s->cmd == NAND_CMD_READ0 ||
       
   402                     s->cmd == NAND_CMD_PAGEPROGRAM1))
       
   403             nand_command(s);
       
   404     }
       
   405 
       
   406     if (!s->cle && !s->ale && s->cmd == NAND_CMD_PAGEPROGRAM1) {
       
   407         if (s->iolen < (1 << s->page_shift) + (1 << s->oob_shift))
       
   408             s->io[s->iolen ++] = value;
       
   409     } else if (!s->cle && !s->ale && s->cmd == NAND_CMD_COPYBACKPRG1) {
       
   410         if ((s->addr & ((1 << s->addr_shift) - 1)) <
       
   411                 (1 << s->page_shift) + (1 << s->oob_shift)) {
       
   412             s->io[s->iolen + (s->addr & ((1 << s->addr_shift) - 1))] = value;
       
   413             s->addr ++;
       
   414         }
       
   415     }
       
   416 }
       
   417 
       
   418 uint8_t nand_getio(struct nand_flash_s *s)
       
   419 {
       
   420     int offset;
       
   421 
       
   422     /* Allow sequential reading */
       
   423     if (!s->iolen && s->cmd == NAND_CMD_READ0) {
       
   424         offset = (s->addr & ((1 << s->addr_shift) - 1)) + s->offset;
       
   425         s->offset = 0;
       
   426 
       
   427         s->blk_load(s, s->addr, offset);
       
   428         if (s->gnd)
       
   429             s->iolen = (1 << s->page_shift) - offset;
       
   430         else
       
   431             s->iolen = (1 << s->page_shift) + (1 << s->oob_shift) - offset;
       
   432     }
       
   433 
       
   434     if (s->ce || s->iolen <= 0)
       
   435         return 0;
       
   436 
       
   437     s->iolen --;
       
   438     return *(s->ioaddr ++);
       
   439 }
       
   440 
       
   441 struct nand_flash_s *nand_init(int manf_id, int chip_id)
       
   442 {
       
   443     int pagesize;
       
   444     struct nand_flash_s *s;
       
   445     int index;
       
   446 
       
   447     if (nand_flash_ids[chip_id].size == 0) {
       
   448         cpu_abort(cpu_single_env, "%s: Unsupported NAND chip ID.\n",
       
   449                         __FUNCTION__);
       
   450     }
       
   451 
       
   452     s = (struct nand_flash_s *) qemu_mallocz(sizeof(struct nand_flash_s));
       
   453     index = drive_get_index(IF_MTD, 0, 0);
       
   454     if (index != -1)
       
   455         s->bdrv = drives_table[index].bdrv;
       
   456     s->manf_id = manf_id;
       
   457     s->chip_id = chip_id;
       
   458     s->size = nand_flash_ids[s->chip_id].size << 20;
       
   459     if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
       
   460         s->page_shift = 11;
       
   461         s->erase_shift = 6;
       
   462     } else {
       
   463         s->page_shift = nand_flash_ids[s->chip_id].page_shift;
       
   464         s->erase_shift = nand_flash_ids[s->chip_id].erase_shift;
       
   465     }
       
   466 
       
   467     switch (1 << s->page_shift) {
       
   468     case 256:
       
   469         nand_init_256(s);
       
   470         break;
       
   471     case 512:
       
   472         nand_init_512(s);
       
   473         break;
       
   474     case 2048:
       
   475         nand_init_2048(s);
       
   476         break;
       
   477     default:
       
   478         cpu_abort(cpu_single_env, "%s: Unsupported NAND block size.\n",
       
   479                         __FUNCTION__);
       
   480     }
       
   481 
       
   482     pagesize = 1 << s->oob_shift;
       
   483     s->mem_oob = 1;
       
   484     if (s->bdrv && bdrv_getlength(s->bdrv) >=
       
   485                     (s->pages << s->page_shift) + (s->pages << s->oob_shift)) {
       
   486         pagesize = 0;
       
   487         s->mem_oob = 0;
       
   488     }
       
   489 
       
   490     if (!s->bdrv)
       
   491         pagesize += 1 << s->page_shift;
       
   492     if (pagesize)
       
   493         s->storage = (uint8_t *) memset(qemu_malloc(s->pages * pagesize),
       
   494                         0xff, s->pages * pagesize);
       
   495     /* Give s->ioaddr a sane value in case we save state before it
       
   496        is used.  */
       
   497     s->ioaddr = s->io;
       
   498 
       
   499     register_savevm("nand", -1, 0, nand_save, nand_load, s);
       
   500 
       
   501     return s;
       
   502 }
       
   503 
       
   504 void nand_done(struct nand_flash_s *s)
       
   505 {
       
   506     if (s->bdrv) {
       
   507         bdrv_close(s->bdrv);
       
   508         bdrv_delete(s->bdrv);
       
   509     }
       
   510 
       
   511     if (!s->bdrv || s->mem_oob)
       
   512         free(s->storage);
       
   513 
       
   514     free(s);
       
   515 }
       
   516 
       
   517 #else
       
   518 
       
   519 /* Program a single page */
       
   520 static void glue(nand_blk_write_, PAGE_SIZE)(struct nand_flash_s *s)
       
   521 {
       
   522     uint32_t off, page, sector, soff;
       
   523     uint8_t iobuf[(PAGE_SECTORS + 2) * 0x200];
       
   524     if (PAGE(s->addr) >= s->pages)
       
   525         return;
       
   526 
       
   527     if (!s->bdrv) {
       
   528         memcpy(s->storage + PAGE_START(s->addr) + (s->addr & PAGE_MASK) +
       
   529                         s->offset, s->io, s->iolen);
       
   530     } else if (s->mem_oob) {
       
   531         sector = SECTOR(s->addr);
       
   532         off = (s->addr & PAGE_MASK) + s->offset;
       
   533         soff = SECTOR_OFFSET(s->addr);
       
   534         if (bdrv_read(s->bdrv, sector, iobuf, PAGE_SECTORS) == -1) {
       
   535             printf("%s: read error in sector %i\n", __FUNCTION__, sector);
       
   536             return;
       
   537         }
       
   538 
       
   539         memcpy(iobuf + (soff | off), s->io, MIN(s->iolen, PAGE_SIZE - off));
       
   540         if (off + s->iolen > PAGE_SIZE) {
       
   541             page = PAGE(s->addr);
       
   542             memcpy(s->storage + (page << OOB_SHIFT), s->io + PAGE_SIZE - off,
       
   543                             MIN(OOB_SIZE, off + s->iolen - PAGE_SIZE));
       
   544         }
       
   545 
       
   546         if (bdrv_write(s->bdrv, sector, iobuf, PAGE_SECTORS) == -1)
       
   547             printf("%s: write error in sector %i\n", __FUNCTION__, sector);
       
   548     } else {
       
   549         off = PAGE_START(s->addr) + (s->addr & PAGE_MASK) + s->offset;
       
   550         sector = off >> 9;
       
   551         soff = off & 0x1ff;
       
   552         if (bdrv_read(s->bdrv, sector, iobuf, PAGE_SECTORS + 2) == -1) {
       
   553             printf("%s: read error in sector %i\n", __FUNCTION__, sector);
       
   554             return;
       
   555         }
       
   556 
       
   557         memcpy(iobuf + soff, s->io, s->iolen);
       
   558 
       
   559         if (bdrv_write(s->bdrv, sector, iobuf, PAGE_SECTORS + 2) == -1)
       
   560             printf("%s: write error in sector %i\n", __FUNCTION__, sector);
       
   561     }
       
   562     s->offset = 0;
       
   563 }
       
   564 
       
   565 /* Erase a single block */
       
   566 static void glue(nand_blk_erase_, PAGE_SIZE)(struct nand_flash_s *s)
       
   567 {
       
   568     uint32_t i, page, addr;
       
   569     uint8_t iobuf[0x200] = { [0 ... 0x1ff] = 0xff, };
       
   570     addr = s->addr & ~((1 << (ADDR_SHIFT + s->erase_shift)) - 1);
       
   571 
       
   572     if (PAGE(addr) >= s->pages)
       
   573         return;
       
   574 
       
   575     if (!s->bdrv) {
       
   576         memset(s->storage + PAGE_START(addr),
       
   577                         0xff, (PAGE_SIZE + OOB_SIZE) << s->erase_shift);
       
   578     } else if (s->mem_oob) {
       
   579         memset(s->storage + (PAGE(addr) << OOB_SHIFT),
       
   580                         0xff, OOB_SIZE << s->erase_shift);
       
   581         i = SECTOR(addr);
       
   582         page = SECTOR(addr + (ADDR_SHIFT + s->erase_shift));
       
   583         for (; i < page; i ++)
       
   584             if (bdrv_write(s->bdrv, i, iobuf, 1) == -1)
       
   585                 printf("%s: write error in sector %i\n", __FUNCTION__, i);
       
   586     } else {
       
   587         addr = PAGE_START(addr);
       
   588         page = addr >> 9;
       
   589         if (bdrv_read(s->bdrv, page, iobuf, 1) == -1)
       
   590             printf("%s: read error in sector %i\n", __FUNCTION__, page);
       
   591         memset(iobuf + (addr & 0x1ff), 0xff, (~addr & 0x1ff) + 1);
       
   592         if (bdrv_write(s->bdrv, page, iobuf, 1) == -1)
       
   593             printf("%s: write error in sector %i\n", __FUNCTION__, page);
       
   594 
       
   595         memset(iobuf, 0xff, 0x200);
       
   596         i = (addr & ~0x1ff) + 0x200;
       
   597         for (addr += ((PAGE_SIZE + OOB_SIZE) << s->erase_shift) - 0x200;
       
   598                         i < addr; i += 0x200)
       
   599             if (bdrv_write(s->bdrv, i >> 9, iobuf, 1) == -1)
       
   600                 printf("%s: write error in sector %i\n", __FUNCTION__, i >> 9);
       
   601 
       
   602         page = i >> 9;
       
   603         if (bdrv_read(s->bdrv, page, iobuf, 1) == -1)
       
   604             printf("%s: read error in sector %i\n", __FUNCTION__, page);
       
   605         memset(iobuf, 0xff, ((addr - 1) & 0x1ff) + 1);
       
   606         if (bdrv_write(s->bdrv, page, iobuf, 1) == -1)
       
   607             printf("%s: write error in sector %i\n", __FUNCTION__, page);
       
   608     }
       
   609 }
       
   610 
       
   611 static void glue(nand_blk_load_, PAGE_SIZE)(struct nand_flash_s *s,
       
   612                 uint32_t addr, int offset)
       
   613 {
       
   614     if (PAGE(addr) >= s->pages)
       
   615         return;
       
   616 
       
   617     if (s->bdrv) {
       
   618         if (s->mem_oob) {
       
   619             if (bdrv_read(s->bdrv, SECTOR(addr), s->io, PAGE_SECTORS) == -1)
       
   620                 printf("%s: read error in sector %i\n",
       
   621                                 __FUNCTION__, SECTOR(addr));
       
   622             memcpy(s->io + SECTOR_OFFSET(s->addr) + PAGE_SIZE,
       
   623                             s->storage + (PAGE(s->addr) << OOB_SHIFT),
       
   624                             OOB_SIZE);
       
   625             s->ioaddr = s->io + SECTOR_OFFSET(s->addr) + offset;
       
   626         } else {
       
   627             if (bdrv_read(s->bdrv, PAGE_START(addr) >> 9,
       
   628                                     s->io, (PAGE_SECTORS + 2)) == -1)
       
   629                 printf("%s: read error in sector %i\n",
       
   630                                 __FUNCTION__, PAGE_START(addr) >> 9);
       
   631             s->ioaddr = s->io + (PAGE_START(addr) & 0x1ff) + offset;
       
   632         }
       
   633     } else {
       
   634         memcpy(s->io, s->storage + PAGE_START(s->addr) +
       
   635                         offset, PAGE_SIZE + OOB_SIZE - offset);
       
   636         s->ioaddr = s->io;
       
   637     }
       
   638 
       
   639     s->addr &= PAGE_SIZE - 1;
       
   640     s->addr += PAGE_SIZE;
       
   641 }
       
   642 
       
   643 static void glue(nand_init_, PAGE_SIZE)(struct nand_flash_s *s)
       
   644 {
       
   645     s->oob_shift = PAGE_SHIFT - 5;
       
   646     s->pages = s->size >> PAGE_SHIFT;
       
   647     s->addr_shift = ADDR_SHIFT;
       
   648 
       
   649     s->blk_erase = glue(nand_blk_erase_, PAGE_SIZE);
       
   650     s->blk_write = glue(nand_blk_write_, PAGE_SIZE);
       
   651     s->blk_load = glue(nand_blk_load_, PAGE_SIZE);
       
   652 }
       
   653 
       
   654 # undef PAGE_SIZE
       
   655 # undef PAGE_SHIFT
       
   656 # undef PAGE_SECTORS
       
   657 # undef ADDR_SHIFT
       
   658 #endif	/* NAND_IO */