2 * Big page NAND flash memory emulation. based on 256M/16 bit flash datasheet from micro(MT29F2G16ABC)
4 * Copyright (C) 2008 yajin(yajin@vm-kernel.org)
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 or
9 * (at your option) version 3 of the License.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
28 #define MAX_PAGE 0x800
30 #define PAGE_MASK (0xffff)
31 #define BUS_WIDTH_16 2
36 struct nand_flash_info_s
38 uint8_t manf_id
,chip_id
;
46 struct nand_flash_info_s nand_flash_info
[2] =
48 {0x2c, 0xba, 256,2, 11, 6, 6},
49 {0Xec, 0xd3, 1024,1, 11, 6, 6}
55 BlockDriverState
*bdrv
;
56 uint8_t manf_id
, chip_id
;
58 uint32_t page_size
, page_shift
;
59 uint32_t oob_size
, oob_shift
;
60 uint32_t page_oob_size
;
61 uint32_t page_sectors
; /*sector = 512 bytes */
62 uint32_t block_shift
, block_pages
; /*how many pages in a block */
63 uint32_t bus_width
; /*bytes */
65 //uint8_t *internal_buf;
66 uint8_t io
[MAX_PAGE
+ MAX_OOB
+ 0x400];
71 uint32 addr_low
, addr_high
;
82 static void debug_init(struct nand_bflash_s
*s
)
84 s
->fp
=fopen("nandflash_debug.txt","w+");
87 fprintf(stderr
,"can not open nandflash_debug.txt \n");
92 static void debug_out(struct nand_bflash_s
*s
,const char* format
, ...)
98 vfprintf(s
->fp
, format
, ap
);
105 static void debug_init(struct nand_bflash_s
*s
)
109 static void debug_out(struct nand_bflash_s
*s
,const char* format
, ...)
116 static inline uint32_t get_page_number(struct nand_bflash_s
*s
,
117 uint32_t addr_low
, uint32 addr_high
)
119 return (addr_high
<< 16) + ((addr_low
>> 16) & PAGE_MASK
);
124 /* Program a single page */
125 static void nand_blk_write(struct nand_bflash_s
*s
)
127 uint32_t page_number
, off
, sector
, soff
;
131 iobuf
= qemu_mallocz((s
->page_sectors
+ 2) * 0x200);
134 fprintf(stderr
, "can not alloc io buffer size 0x%x \n",
135 (s
->page_sectors
+ 2) * 0x200);
136 cpu_abort(cpu_single_env
, "%s: can not alloc io buffer size 0x%x \n",
137 __FUNCTION__
, (s
->page_sectors
+ 2) * 0x200);
140 page_number
= get_page_number(s
, s
->addr_low
, s
->addr_high
);
142 debug_out(s
,"nand_blk_write page number %x s->addr_low %x s->addr_high %x\n",page_number
,s
->addr_low
,s
->addr_high
);
144 if (page_number
>= s
->pages
)
147 off
= page_number
* s
->page_oob_size
+ (s
->addr_low
& PAGE_MASK
);
150 if (bdrv_read(s
->bdrv
, sector
, iobuf
, s
->page_sectors
+ 2) == -1)
152 printf("%s: read error in sector %i\n", __FUNCTION__
, sector
);
156 memcpy(iobuf
+ soff
, s
->io
, s
->iolen
);
158 if (bdrv_write(s
->bdrv
, sector
, iobuf
, s
->page_sectors
+ 2) == -1)
159 printf("%s: write error in sector %i\n", __FUNCTION__
, sector
);
165 static void nandb_blk_load(struct nand_bflash_s
*s
)
167 uint32_t page_number
, offset
;
168 offset
= s
->addr_low
& PAGE_MASK
;
170 page_number
= get_page_number(s
, s
->addr_low
, s
->addr_high
);
171 debug_out(s
,"nandb_blk_load page number %x s->addr_low %x s->addr_high %x\n",page_number
,s
->addr_low
,s
->addr_high
);
172 if (page_number
>= s
->pages
)
175 if (bdrv_read(s
->bdrv
, (page_number
* s
->page_oob_size
+ offset
) >> 9,
176 s
->io
, (s
->page_sectors
+ 2)) == -1)
177 printf("%s: read error in sector %i\n",
178 __FUNCTION__
, page_number
* s
->page_oob_size
);
179 s
->ioaddr
= s
->io
+ ((page_number
* s
->page_oob_size
+ offset
) & 0x1ff);
183 /* Erase a single block */
184 static void nandb_blk_erase(struct nand_bflash_s
*s
)
186 uint32_t page_number
, sector
, addr
, i
;
188 uint8_t iobuf
[0x200];
190 memset(iobuf
,0xff,sizeof(iobuf
));
191 s
->addr_low
= s
->addr_low
& ~((1 << (16 + s
->block_shift
)) - 1);
192 page_number
= get_page_number(s
, s
->addr_low
, s
->addr_high
);
193 debug_out(s
,"nandb_blk_erase page number %x s->addr_low %x s->addr_high %x\n",page_number
,s
->addr_low
,s
->addr_high
);
194 if (page_number
>= s
->pages
)
197 addr
= page_number
* s
->page_oob_size
;
200 if (bdrv_read(s
->bdrv
, sector
, iobuf
, 1) == -1)
201 printf("%s: read error in sector %i\n", __FUNCTION__
, sector
);
202 memset(iobuf
+ (addr
& 0x1ff), 0xff, (~addr
& 0x1ff) + 1);
203 if (bdrv_write(s
->bdrv
, sector
, iobuf
, 1) == -1)
204 printf("%s: write error in sector %i\n", __FUNCTION__
, sector
);
206 memset(iobuf
, 0xff, 0x200);
207 i
= (addr
& ~0x1ff) + 0x200;
208 for (addr
+= (s
->page_oob_size
*s
->block_pages
- 0x200); i
< addr
; i
+= 0x200)
209 if (bdrv_write(s
->bdrv
, i
>> 9, iobuf
, 1) == -1)
210 printf("%s: write error in sector %i\n", __FUNCTION__
, i
>> 9);
213 if (bdrv_read(s
->bdrv
, sector
, iobuf
, 1) == -1)
214 printf("%s: read error in sector %i\n", __FUNCTION__
, sector
);
215 memset(iobuf
, 0xff, ((addr
- 1) & 0x1ff) + 1);
216 if (bdrv_write(s
->bdrv
, sector
, iobuf
, 1) == -1)
217 printf("%s: write error in sector %i\n", __FUNCTION__
, sector
);
220 static void nandb_next_page(struct nand_bflash_s
*s
)
222 if ((s
->addr_low
+ 0x10000) < s
->addr_low
)
224 s
->addr_low
+= 0x10000;
227 void nandb_write_command(struct nand_bflash_s
*s
, uint16_t value
)
229 int id_index
[5] = { 0, 1, 2, 3,4};
231 debug_out(s
,"nandb_write_command %x\n",value
);
241 /*earse only need 3 addrss cycle.Its address is block address*/
242 s
->addr_low
&= ~PAGE_MASK
;
248 s
->iolen
= s
->page_oob_size
- (s
->addr_low
& PAGE_MASK
);
254 s
->iolen
= s
->page_oob_size
- (s
->addr_low
& PAGE_MASK
);
258 s
->iolen
= 5 * s
->bus_width
;
259 memset(s
->io
, 0x0, s
->iolen
);
260 if (s
->bus_width
== BUS_WIDTH_16
)
268 s
->io
[id_index
[0]] = s
->manf_id
;
269 s
->io
[id_index
[1]] = s
->chip_id
;
270 s
->io
[id_index
[2]] = 'Q'; /* Don't-care byte (often 0xa5) */
271 if ((s
->manf_id
== NAND_MFR_MICRON
) && (s
->chip_id
== 0xba))
272 s
->io
[id_index
[3]] = 0x55;
273 if ((s
->manf_id
== NAND_MFR_SAMSUNG
) && (s
->chip_id
== 0xd3))
275 s
->io
[id_index
[3]] = 0x95;
276 s
->io
[id_index
[4]] = 0x48;
282 if ((s
->manf_id
== NAND_MFR_MICRON
) && (s
->chip_id
== 0xba))
284 s
->status
|= 0x60; /*flash is ready */
285 s
->status
|= 0x80; /*not protect */
287 if ((s
->manf_id
== NAND_MFR_SAMSUNG
) && (s
->chip_id
== 0xd3))
289 s
->status
|= 0x40; /*flash is ready */
290 s
->status
|= 0x80; /*not protect */
292 s
->io
[0] = s
->status
;
316 fprintf(stderr
, "unknown nand command 0x%x \n", value
);
322 void nandb_write_address(struct nand_bflash_s
*s
, uint16_t value
)
327 debug_out(s
,"value %x addr_cycle %x \n",value
,s
->addr_cycle
);
328 if (s
->addr_cycle
< 5)
330 if (s
->addr_cycle
< 4)
332 mask
= ~(0xff << (s
->addr_cycle
* 8));
334 s
->addr_low
|= value
<< (s
->addr_cycle
* 8);
338 mask
= ~(0xff << ((s
->addr_cycle
-4) * 8));
339 s
->addr_high
&= mask
;
340 s
->addr_high
|= value
<< ((s
->addr_cycle
-4) * 8);
345 fprintf(stderr
,"%s wrong addr cycle\n",__FUNCTION__
);
348 if ((s
->addr_cycle
==1)&&(s
->bus_width
!=1))
350 colum_addr
= s
->addr_low
& PAGE_MASK
;
351 colum_addr
*= s
->bus_width
;
352 s
->addr_low
&= ~PAGE_MASK
;
353 s
->addr_low
+= colum_addr
;
359 uint8_t nandb_read_data8(struct nand_bflash_s
*s
)
362 if ((s
->iolen
==0)&&(s
->cmd
==0x31))
365 s
->iolen
= s
->page_oob_size
- (s
->addr_low
& PAGE_MASK
);
370 fprintf(stderr
,"iolen <0 \n");
375 ret
= *((uint8_t *)s
->ioaddr
);
379 //debug_out(s," %x ",ret);
383 void nandb_write_data8(struct nand_bflash_s
*s
, uint8_t value
)
385 if ((s
->cmd
== 0x80) )
387 if (s
->iolen
< s
->page_oob_size
)
389 s
->io
[s
->iolen
++] = value
&0xff;
394 uint16_t nandb_read_data16(struct nand_bflash_s
*s
)
397 if ((s
->iolen
==0)&&(s
->cmd
==0x31))
400 s
->iolen
= s
->page_oob_size
- (s
->addr_low
& PAGE_MASK
);
405 fprintf(stderr
,"iolen <0 \n");
410 ret
= *((uint16_t *)s
->ioaddr
);
416 void nandb_write_data16(struct nand_bflash_s
*s
, uint16_t value
)
418 if ((s
->cmd
== 0x80) )
420 if (s
->iolen
< s
->page_oob_size
)
422 s
->io
[s
->iolen
++] = value
&0xff;
423 s
->io
[s
->iolen
++] = (value
>>8)&0xff;
428 struct nand_bflash_s
*nandb_init(int manf_id
, int chip_id
)
431 struct nand_bflash_s
*s
;
435 s
= (struct nand_bflash_s
*) qemu_mallocz(sizeof(struct nand_bflash_s
));
436 for (i
= 0; i
< sizeof(nand_flash_info
); i
++)
438 if ((nand_flash_info
[i
].manf_id
== manf_id
)
439 && (nand_flash_info
[i
].chip_id
== chip_id
))
441 s
->manf_id
= manf_id
;
442 s
->chip_id
= chip_id
;
443 s
->page_shift
= nand_flash_info
[i
].page_shift
;
444 s
->oob_shift
= nand_flash_info
[i
].oob_shift
;
445 s
->bus_width
= nand_flash_info
[i
].bus_width
;
446 s
->page_size
= 1 << s
->page_shift
;
447 s
->oob_size
= 1 << s
->oob_shift
;
448 s
->block_shift
= nand_flash_info
[i
].block_shift
;
449 s
->block_pages
= 1 << s
->block_shift
;
450 s
->page_oob_size
= s
->page_size
+ s
->oob_size
;
451 s
->page_sectors
= 1 << (s
->page_shift
- 9);
452 /*TODO: size overflow */
453 s
->size
= nand_flash_info
[i
].size
<< 20;
454 s
->pages
= (s
->size
/ s
->page_size
);
460 if (i
>= sizeof(nand_flash_info
))
462 fprintf(stderr
, "%s: Unsupported NAND chip ID.\n",
468 index
= drive_get_index(IF_MTD
, 0, 0);
470 s
->bdrv
= drives_table
[index
].bdrv
;
473 fprintf(stderr
, "%s: Please use -mtdblock to specify flash image.\n",
478 if (bdrv_getlength(s
->bdrv
) != (s
->pages
*s
->page_oob_size
))
480 fprintf(stderr
, "%s: Invalid flash image size.\n",