586b9141490b62b605743589782532df715f3d21
[qemu] / hw / nand_bpage.c
1 /*
2  * Big page NAND flash memory emulation.  based on 256M/16 bit flash datasheet from micro(MT29F2G16ABC)
3  *
4  * Copyright (C) 2008 yajin(yajin@vm-kernel.org)
5  *
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.
10  *
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.
15  *
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,
19  * MA 02111-1307 USA
20  */
21
22 #include "hw.h"
23 #include "flash.h"
24 #include "block.h"
25 #include "sysemu.h"
26
27
28 #define MAX_PAGE                0x800
29 #define MAX_OOB         0x40
30 #define PAGE_MASK               (0xffff)
31 #define BUS_WIDTH_16  2
32 #define BUS_WIDTH_8 1
33
34 //#define DEBUG
35
36 struct nand_flash_info_s
37 {
38     uint8_t  manf_id,chip_id;
39     uint32_t size;;
40     int bus_width;
41     int page_shift;
42     int oob_shift;
43     int block_shift;
44 };
45 struct nand_flash_info_s nand_flash_info[1] =
46 {
47     {0x2c, 0xba, 256,2, 11, 6, 6}
48 };
49
50
51 struct nand_bflash_s
52 {
53         BlockDriverState *bdrv;
54     uint8_t manf_id, chip_id;
55     uint32_t size, pages;
56     uint32_t page_size, page_shift;
57     uint32_t oob_size, oob_shift;
58     uint32_t page_oob_size;
59     uint32_t page_sectors;      /*sector = 512 bytes */
60     uint32_t block_shift, block_pages;  /*how many pages in a block */
61     uint32_t bus_width;         /*bytes */
62
63     //uint8_t *internal_buf;
64     uint8_t io[MAX_PAGE + MAX_OOB + 0x400];
65     uint8_t *ioaddr;
66     int iolen;
67
68
69     uint32 addr_low, addr_high;
70     uint32 addr_cycle;
71
72     uint32 cmd, status;
73   #ifdef DEBUG  
74     FILE *fp;
75   #endif
76 };
77
78
79 #ifdef DEBUG
80 static void debug_init(struct nand_bflash_s *s)
81 {
82         s->fp=fopen("nandflash_debug.txt","w+");
83         if (s->fp==NULL)
84         {
85                 fprintf(stderr,"can not open nandflash_debug.txt \n");
86                 exit(-1);
87         }
88                 
89 }
90 static void debug_out(struct nand_bflash_s *s,const char* format, ...)
91 {
92         va_list ap;
93         if (s->fp)
94         {
95                  va_start(ap, format);
96          vfprintf(s->fp, format, ap);
97          fflush(s->fp);
98         va_end(ap);
99         }
100 }
101
102 #else
103 static void debug_init(struct nand_bflash_s *s)
104 {
105         
106 }
107 static void debug_out(struct nand_bflash_s *s,const char* format, ...)
108 {
109         
110 }
111
112 #endif
113
114 static inline uint32_t get_page_number(struct nand_bflash_s *s,
115                                        uint32_t addr_low, uint32 addr_high)
116 {
117     return (addr_high << 16) + ((addr_low >> 16) & PAGE_MASK);
118 }
119
120
121
122 /* Program a single page */
123 static void nand_blk_write(struct nand_bflash_s *s)
124 {
125     uint32_t page_number, off,  sector, soff;
126     uint8_t *iobuf=NULL;
127
128         if (!iobuf)
129         iobuf = qemu_mallocz((s->page_sectors + 2) * 0x200);
130     if (!iobuf)
131     {
132         fprintf(stderr, "can not alloc io buffer size 0x%x \n",
133                 (s->page_sectors + 2) * 0x200);
134         cpu_abort(cpu_single_env, "%s: can not alloc io buffer size 0x%x \n",
135                   __FUNCTION__, (s->page_sectors + 2) * 0x200);
136     }
137
138     page_number = get_page_number(s, s->addr_low, s->addr_high);
139
140     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);
141
142     if (page_number >= s->pages)
143         return;
144
145     off = page_number * s->page_oob_size + (s->addr_low & PAGE_MASK);
146     sector = off >> 9;
147     soff = off & 0x1ff;
148     if (bdrv_read(s->bdrv, sector, iobuf, s->page_sectors + 2) == -1)
149     {
150         printf("%s: read error in sector %i\n", __FUNCTION__, sector);
151         return;
152     }
153
154     memcpy(iobuf + soff, s->io, s->iolen);
155
156     if (bdrv_write(s->bdrv, sector, iobuf, s->page_sectors + 2) == -1)
157         printf("%s: write error in sector %i\n", __FUNCTION__, sector);
158
159     //qemu_free(iobuf);
160 }
161
162
163 static void nandb_blk_load(struct nand_bflash_s *s)
164 {
165     uint32_t page_number, offset;
166     offset = s->addr_low & PAGE_MASK;
167
168     page_number = get_page_number(s, s->addr_low, s->addr_high);
169         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);
170     if (page_number >= s->pages)
171         return;
172         
173     if (bdrv_read(s->bdrv, (page_number * s->page_oob_size + offset) >> 9,
174                   s->io, (s->page_sectors + 2)) == -1)
175         printf("%s: read error in sector %i\n",
176                __FUNCTION__, page_number * s->page_oob_size);
177     s->ioaddr = s->io + ((page_number * s->page_oob_size + offset) & 0x1ff);
178 }
179
180
181 /* Erase a single block */
182 static void nandb_blk_erase(struct nand_bflash_s *s)
183 {
184     uint32_t page_number,  sector, addr, i;
185
186     uint8_t iobuf[0x200];
187
188          memset(iobuf,0xff,sizeof(iobuf));
189          s->addr_low = s->addr_low & ~((1 << (16 + s->block_shift)) - 1);
190     page_number = get_page_number(s, s->addr_low, s->addr_high);
191     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);
192     if (page_number >= s->pages)
193         return;
194
195     addr = page_number * s->page_oob_size;
196     
197     sector = addr >> 9;
198     if (bdrv_read(s->bdrv, sector, iobuf, 1) == -1)
199         printf("%s: read error in sector %i\n", __FUNCTION__, sector);
200     memset(iobuf + (addr & 0x1ff), 0xff, (~addr & 0x1ff) + 1);
201     if (bdrv_write(s->bdrv, sector, iobuf, 1) == -1)
202         printf("%s: write error in sector %i\n", __FUNCTION__, sector);
203
204     memset(iobuf, 0xff, 0x200);
205     i = (addr & ~0x1ff) + 0x200;
206     for (addr += (s->page_oob_size*s->block_pages - 0x200); i < addr; i += 0x200)
207         if (bdrv_write(s->bdrv, i >> 9, iobuf, 1) == -1)
208             printf("%s: write error in sector %i\n", __FUNCTION__, i >> 9);
209
210     sector = i >> 9;
211     if (bdrv_read(s->bdrv, sector, iobuf, 1) == -1)
212         printf("%s: read error in sector %i\n", __FUNCTION__, sector);
213     memset(iobuf, 0xff, ((addr - 1) & 0x1ff) + 1);
214     if (bdrv_write(s->bdrv, sector, iobuf, 1) == -1)
215         printf("%s: write error in sector %i\n", __FUNCTION__, sector);
216 }
217
218 static void nandb_next_page(struct nand_bflash_s *s)
219 {
220     if ((s->addr_low + 0x10000) < s->addr_low)
221         s->addr_high++;
222     s->addr_low += 0x10000;
223 }
224
225 void nandb_write_command(struct nand_bflash_s *s, uint16_t value)
226 {
227     int id_index[4] = { 0, 1, 2, 3 };
228
229     debug_out(s,"nandb_write_command %x\n",value);
230
231     switch (value)
232     {
233     case 0x00: /* PAGE READ (cycle 1) */
234     case 0x05: /* RANDOM DATA READ (cycle 1) */
235         s->iolen = 0;
236         s->addr_cycle = 0;
237         break;
238     case 0x10: /* PROGRAM xxx / OTP PROTECT (cycle 2) */
239         nand_blk_write(s);
240         break;
241     case 0x30: /* PAGE READ / OTP DATA READ (cycle 2) */
242     case 0xe0: /* RANDOM DATA READ (cycle 2) */
243         s->iolen = s->page_oob_size - (s->addr_low & PAGE_MASK);
244         nandb_blk_load(s);
245         s->addr_cycle = 0;
246         break;
247     case 0x31: /* PAGE READ CACHE MODE START */
248     case 0x3f: /* PAGE READ CACHE MODE START LAST */
249         nandb_next_page(s);
250         s->iolen = s->page_oob_size - (s->addr_low & PAGE_MASK);
251         nandb_blk_load(s);
252         break;
253     case 0x60: /* BLOCK ERASE (cycle 1) */
254         /*erase only needs 3 address cycles. Its address is block address*/
255         s->addr_low &= ~PAGE_MASK;
256         s->addr_high =0;
257         s->addr_cycle = 2;
258         break;
259     case 0x70: /* READ STATUS */
260         if ((s->manf_id == NAND_MFR_MICRON) && (s->chip_id == 0xba))
261         {
262             s->status |= 0x60;  /*flash is ready */
263             s->status |= 0x80;  /*not protect */
264         }
265         s->io[0] = s->status;
266         s->ioaddr = s->io;
267         s->iolen = 1;
268         break;
269     case 0x80: /* PROGRAM PAGE / PROGRAM PAGE CACHE MODE (cycle 1) */
270     case 0x85: /* PROGRAM for INTERNAL DATA MOVE (cycle 1) / RANDOM DATA INPUT */
271         s->addr_cycle = 0;
272         s->ioaddr = s->io;
273         s->iolen = 0;
274         break;
275     case 0x90: /* READ ID */
276         s->iolen = 4 * s->bus_width;
277         memset(s->io, 0x0, s->iolen);
278         if (s->bus_width == BUS_WIDTH_16)
279         {
280             id_index[0] = 0;
281             id_index[1] = 2;
282             id_index[2] = 4;
283             id_index[3] = 6;
284         }
285         s->io[id_index[0]] = s->manf_id;
286         s->io[id_index[1]] = s->chip_id;
287         s->io[id_index[2]] = 'Q';       /* Don't-care byte (often 0xa5) */
288         if ((s->manf_id == NAND_MFR_MICRON) && (s->chip_id == 0xba))
289             s->io[id_index[3]] = 0x55;
290         s->ioaddr = s->io;
291         break;
292     case 0xa0: /* OTP DATA PROGRAM (cycle 1) */
293     case 0xa5: /* OTP DATA PROTECT (cycle 1) */
294     case 0xaf: /* OTP DATA READ (cycle 1) */
295         fprintf(stderr, "%s: OTP command 0x%x not implemented\n", __FUNCTION__, value);
296         break;
297     case 0xd0: /* BLOCK ERASE (cycle 2) */
298         nandb_blk_erase(s);
299         break;
300     case 0xff: /* RESET */
301         s->addr_cycle =0;
302         s->iolen=0;
303         s->addr_low =0;
304         s->addr_high =0;
305         s->ioaddr = NULL;
306         break;
307     default:
308         fprintf(stderr, "%s: unknown nand command 0x%x \n", __FUNCTION__, value);
309         exit(-1);
310     }
311     s->cmd = value;
312 }
313
314 void nandb_write_address(struct nand_bflash_s *s, uint16_t value)
315 {
316     uint32_t mask;
317     uint32_t colum_addr;
318     
319     /*fprintf(stderr, "%s: addr_cycle=%d, value=0x%04x, addr_low=0x%08x, addr_high=0x%08x\n",
320             __FUNCTION__, s->addr_cycle, value, s->addr_low, s->addr_high );*/
321     
322     if (s->cmd==0x60)
323         debug_out(s,"value %x addr_cycle %x \n",value,s->addr_cycle);
324   
325     if (s->addr_cycle < 5) {
326         if (s->addr_cycle < 4) {
327             mask = ~(0xff << (s->addr_cycle * 8));
328             s->addr_low &= mask;
329             s->addr_low |= value << (s->addr_cycle * 8);
330         } else {
331             mask = ~(0xff << ((s->addr_cycle-4) * 8));
332             s->addr_high &= mask;
333             s->addr_high |= value << ((s->addr_cycle-4) * 8);
334         }
335     }
336     else {
337         fprintf(stderr,"%s wrong addr cycle\n",__FUNCTION__);
338         exit(-1);
339     }
340     if ((s->addr_cycle==1)&&(s->bus_width!=1)) {
341         colum_addr = s->addr_low & PAGE_MASK;
342         colum_addr *= s->bus_width;
343         s->addr_low &= ~PAGE_MASK;
344         s->addr_low += colum_addr;
345     }
346     s->addr_cycle++;
347 }
348
349
350 uint16_t nandb_read_data16(struct nand_bflash_s *s)
351 {
352         uint16_t ret;
353         if ((s->iolen==0)&&(s->cmd==0x31))
354         {
355                 nandb_next_page(s);
356         s->iolen = s->page_oob_size - (s->addr_low & PAGE_MASK);
357         nandb_blk_load(s);
358         }
359         if (s->iolen <= 0)
360         {
361                 fprintf(stderr,"iolen <0 \n");
362                 exit(-1);
363         }
364         if (s->cmd!=0x70)       
365         s->iolen -=2 ;
366     ret = *((uint16_t *)s->ioaddr);
367     if (s->cmd!=0x70)   
368         s->ioaddr += 2;         
369     return ret;
370 }
371
372 void nandb_write_data16(struct nand_bflash_s *s, uint16_t value)
373 {
374          if ((s->cmd == 0x80) )
375          {
376         if (s->iolen < s->page_oob_size)
377         {
378                 s->io[s->iolen ++] = value&0xff;
379                 s->io[s->iolen ++] = (value>>8)&0xff;
380         }
381     }
382 }
383
384 struct nand_bflash_s *nandb_init(int manf_id, int chip_id)
385 {
386     //int pagesize;
387     struct nand_bflash_s *s;
388     int index;
389     int i;
390
391     s = (struct nand_bflash_s *) qemu_mallocz(sizeof(struct nand_bflash_s));
392     for (i = 0; i < sizeof(nand_flash_info); i++)
393     {
394         if ((nand_flash_info[i].manf_id == manf_id)
395             && (nand_flash_info[i].chip_id == chip_id))
396         {
397             s->manf_id = manf_id;
398             s->chip_id = chip_id;
399             s->page_shift = nand_flash_info[i].page_shift;
400             s->oob_shift = nand_flash_info[i].oob_shift;
401             s->bus_width = nand_flash_info[i].bus_width;
402             s->page_size = 1 << s->page_shift;
403             s->oob_size = 1 << s->oob_shift;
404             s->block_shift = nand_flash_info[i].block_shift;
405             s->block_pages = 1 << s->block_shift;
406             s->page_oob_size = s->page_size + s->oob_size;
407             s->page_sectors = 1 << (s->page_shift - 9);
408             /*TODO: size overflow */
409             s->size = nand_flash_info[i].size << 20;
410             s->pages = (s->size / s->page_size);
411
412             break;
413         }
414
415     }
416     if (i >= sizeof(nand_flash_info))
417     {
418         fprintf(stderr, "%s: Unsupported NAND chip ID.\n",
419                   __FUNCTION__);
420         exit(-1);
421     }
422
423     
424     index = drive_get_index(IF_MTD, 0, 0);
425     if (index != -1)
426         s->bdrv = drives_table[index].bdrv;
427     else
428     {
429         fprintf(stderr, "%s: Please use -mtdblock to specify flash image.\n",
430                   __FUNCTION__);
431         exit(-1);
432     }
433
434     if (bdrv_getlength(s->bdrv) != (s->pages*s->page_oob_size))
435     {
436         fprintf(stderr,  "%s: Invalid flash image size.\n",
437                   __FUNCTION__);
438         exit(-1);
439
440     }
441
442         debug_init(s);
443     return s;
444
445 }