OSDN Git Service

am29f040 対応
[unagi/old-svn-converted.git] / client / trunk / flashmemory.c
1 /*
2 famicom ROM cartridge utility - unagi
3 flash memory driver
4
5 Copyright (C) 2008  sato_tiff
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License any later version.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20
21 flashmemory.c ¤À¤±¤Î·Ù¹ð
22 ¤³¤Î¥½¡¼¥¹¥³¡¼¥É¤ò»²¹Í¡¢Å¾ÍѤ·¤Æ¥·¥§¥¢¥¦¥§¥¢¤Ê¤É¤ÇÍø±×¤òÆÀ¤Ê¤¤¤³¤È¡£
23 ȽÌÀ¤·¤¿¾ì¹ç¤Ï LGPL ¤¬Å¬ÍѤµ¤ì¡¢³ºÅö²Õ½ê¤Î¥½¡¼¥¹¤ò¸ø³«¤¹¤ëɬÍפ¬¤¢¤ë¡£
24 */
25 #include <assert.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <windows.h>
30 #include "type.h"
31 #include "header.h"
32 #include "flashmemory.h"
33 /*
34 driver for Winbond W29C020, W49F002
35 */
36 /*
37 JEDEC flash memory command
38 http://www.sst.com/downloads/software_driver/SST49LF002A.txt
39 */
40 struct flash_task{
41         long address, data;
42 };
43 enum{
44         ADDRESS_0000 = 0,
45         ADDRESS_2AAA = 0x2aaa,
46         ADDRESS_5555 = 0x5555,
47         FLASH_COMMAND_END
48 };
49 static const struct flash_task PRODUCTID_ENTRY[] = {
50         {ADDRESS_5555, 0xaa},
51         {ADDRESS_2AAA, 0x55},
52         {ADDRESS_5555, 0x90},
53         {FLASH_COMMAND_END, 0}
54 };
55 static const struct flash_task PRODUCTID_EXIT[] = {
56         {ADDRESS_5555, 0xaa},
57         {ADDRESS_2AAA, 0x55},
58         {ADDRESS_5555, 0xf0},
59         {FLASH_COMMAND_END, 0}
60 };
61 static const struct flash_task PROTECT_DISABLE[] = {
62         {ADDRESS_5555, 0xaa},
63         {ADDRESS_2AAA, 0x55},
64         {ADDRESS_5555, 0xa0},
65         {FLASH_COMMAND_END, 0}
66 };
67 static const struct flash_task PROTECT_ENABLE[] = {
68         {ADDRESS_5555, 0xaa},
69         {ADDRESS_2AAA, 0x55},
70         {ADDRESS_5555, 0x80},
71         {ADDRESS_5555, 0xaa},
72         {ADDRESS_2AAA, 0x55},
73         {ADDRESS_5555, 0x20},
74         {FLASH_COMMAND_END, 0}
75 };
76 static const struct flash_task ERASE_CHIP[] = {
77         {ADDRESS_5555, 0xaa},
78         {ADDRESS_2AAA, 0x55},
79         {ADDRESS_5555, 0x80},
80         {ADDRESS_5555, 0xaa},
81         {ADDRESS_2AAA, 0x55},
82         {ADDRESS_5555, 0x10},
83         {FLASH_COMMAND_END, 0}
84 };
85
86 static const struct flash_task ERASE_SECTOR[] = {
87         {ADDRESS_5555, 0xaa},
88         {ADDRESS_2AAA, 0x55},
89         {ADDRESS_5555, 0x80},
90         {ADDRESS_5555, 0xaa},
91         {ADDRESS_2AAA, 0x55},
92         //¤³¤Î¤¢¤È sectoraddress ¤Ë 0x30 ¤ò write
93         {FLASH_COMMAND_END, 0}
94 };
95
96 static const struct flash_task PP[] = {
97         {ADDRESS_5555, 0xaa},
98         {ADDRESS_2AAA, 0x55},
99         {ADDRESS_5555, 0x80},
100         {ADDRESS_5555, 0xaa},
101         {ADDRESS_2AAA, 0x55},
102         {ADDRESS_5555, 0x60},
103         {FLASH_COMMAND_END, 0}
104 };
105
106 static void command_set(const struct flash_order *d, const struct flash_task *t)
107 {
108         while(t->address != FLASH_COMMAND_END){
109                 long logical_address = 0;
110                 switch(t->address){
111                 case ADDRESS_0000: //bank ¤Ë¤è¤Ã¤Æ¤ÏÀßÄê¤Ç¤­¤Ê¤¤¤«¤â?
112                         logical_address = d->command_0000;
113                         break;
114                 case ADDRESS_2AAA:
115                         logical_address = d->command_2aaa;
116                         break;
117                 case ADDRESS_5555:
118                         logical_address = d->command_5555;
119                         break;
120                 default:
121                         assert(0); //unknown task address
122                 }
123                 d->flash_write(logical_address, t->data);
124                 t++;
125         }
126 }
127
128 /*
129 ---- product ID check ----
130 */
131 static int productid_check(const struct flash_order *d, const struct flash_driver *f)
132 {
133         u8 data[3];
134         command_set(d, PRODUCTID_ENTRY);
135         d->read(d->command_0000, 3, data);
136         command_set(d, PRODUCTID_EXIT);
137         if(f->id_manufacurer != data[0]){
138                 return NG;
139         }
140         if(f->id_device != data[1]){
141                 return NG;
142         }
143         return OK;
144 }
145
146 static int productid_sram(const struct flash_order *d, const struct flash_driver *f)
147 {
148         return OK;
149 }
150 /*
151 ---- toggle check ----
152 databit6
153 */
154 const int CHECK_RETRY_MAX = 0x10000;
155 static int toggle_check(const struct flash_order *d, long address)
156 {
157         u8 predata;
158         int retry = 0;
159         d->read(address, 1, &predata); //read DQ6
160         predata &= 0x40;
161         while(retry < CHECK_RETRY_MAX){
162                 u8 data;
163                 d->read(address, 1, &data); //read DQ6 again
164                 data &= 0x40;
165                 if(predata == data){
166                         return OK;
167                 }
168                 predata = data;
169                 retry++;
170         }
171         return NG;
172 }
173
174 /*
175 ---- polling check ----
176 databit7
177 */
178 static int polling_check(const struct flash_order *d, long address, u8 truedata)
179 {
180         int retry = 0;
181         
182         truedata &= 0x80;
183         while(retry < CHECK_RETRY_MAX){
184                 u8 data;
185                 d->read(address, 1, &data);
186                 data &= 0x80;
187                 if(truedata == data){
188                         return OK;
189                 }
190                 retry++;
191         }
192         return NG;
193 }
194
195 static void bootblock_lockout(const struct flash_order *d)
196 {
197         u8 dummy[3];
198         command_set(d, PP);
199         d->read(0x8000 ,3, dummy);
200         printf("%02x %02x %02x \n", dummy[0], dummy[1], dummy[2]);
201         d->read(0xfff2 ,1, dummy);
202         command_set(d, PRODUCTID_EXIT);
203 }
204 /*
205 ---- erase ----
206 */
207 static void flash_erase_chip(const struct flash_order *d)
208 {
209         if(0) bootblock_lockout(d);
210         command_set(d, ERASE_CHIP);
211         toggle_check(d, d->command_2aaa);
212         Sleep(200); //Tec 0.2 sec
213 }
214
215 static void sram_erase(const struct flash_order *d)
216 {
217         //bank ÀÚ¤êÂؤ¨¤¬È¼¤¦¤Î¤Ç¼ÂÁõ¤Ç¤­¤Ê¤¤
218 }
219
220 /*
221 ---- program ----
222 */
223 static int program_byte(const struct flash_order *d, long address, const u8 *data, long length)
224 {
225         int retry = 0;
226         while(length != 0){
227                 if(*data != 0xff){
228                         fflush(stdout);
229                         command_set(d, PROTECT_DISABLE);
230                         d->flash_write(address, *data);
231                         if(toggle_check(d, address) == NG){
232                                 if(DEBUG == 1){
233                                         printf("%s NG\n", __FUNCTION__);
234                                 }
235                                 return NG;
236                         }
237                 }
238                 u8 dummy;
239                 d->read(address, 1, &dummy);
240                 if(*data == dummy){
241                         address++;
242                         data++;
243                         length--;
244                         retry = 0;
245                 }else if(retry > 8){
246                         printf("%s %06x error\n", __FUNCTION__, (int) address);
247                         address++;
248                         data++;
249                         length--;
250                         retry = 0;
251                 }else{
252                         retry++;
253                 }
254         }
255         return OK;
256 }
257
258 static int program_pagewrite(const struct flash_order *d, long address, const u8 *data, long length)
259 {
260         const long toggle_address = address ;
261         command_set(d, PROTECT_DISABLE);
262         while(length != 0){
263                 d->flash_write(address, *data);
264                 address++;
265                 data++;
266                 length--;
267         }
268         Sleep(15);
269         int ret = toggle_check(d, toggle_address);
270         if(0){
271                 data--;
272                 address -= 1;
273                 polling_check(d, address - 1, *data);
274         }
275
276         //command_set(d, PROTECT_ENABLE);
277         //Sleep(15);
278         return ret;
279 }
280
281 /*
282 ---- block compare ----
283 */
284 static void compare(const struct flash_order *d, long address, const u8 *data, long length)
285 {
286         u8 *romdata, *r;
287         int count = 0;
288         romdata = malloc(length);
289         d->read(address, length, romdata);
290         r = romdata;
291         while(length != 0){
292                 if(*r != *data){
293                         char safix = ' ';
294                         if((count & 7) == 7){
295                                 safix = '\n';
296                         }
297                         count++;
298                         printf("%06x%c", (int)address, safix);
299                 }
300                 r++;
301                 data++;
302                 address++;
303                 length--;
304         }
305         free(romdata);
306 }
307
308 /*
309 ¸ÇÍ­¥Ç¥Ð¥¤¥¹¥É¥é¥¤¥Ð
310 */
311 static void w49f002_init(const struct flash_order *d)
312 {
313 /*
314 byte program mode ¤Ç¤Ï 1->0 ¤Ë¤¹¤ë¤À¤±¡£ 0->1 ¤Ï erase ¤Î¤ß¡£
315 ¤è¤Ã¤Æ½é´ü²½»þ¤Ë¤Ï erase ¤ò¼Â¹Ô¤¹¤ë
316 */
317         flash_erase_chip(d);
318 }
319
320 static void w49f002_write(const struct flash_order *d, long address, long length, const struct memory *m)
321 {
322         program_byte(d, address, m->data, length);
323 }
324
325
326 static void init_nop(const struct flash_order *d)
327 {
328 /*
329 page write mode ¤Ç¤Ï¤È¤¯¤Ë¤Ê¤·
330 */
331 }
332
333 static void w29c020_write(const struct flash_order *d, long address, long length, const struct memory *m)
334 {
335         int retry = 0;
336         assert(d->pagesize != 0);
337         {
338                 long a = address;
339                 long i = length;
340                 const u8 *dd;
341                 u8 *cmp;
342
343                 dd = m->data;
344                 cmp = malloc(d->pagesize);
345                 while(i != 0){
346                         int result = program_pagewrite(d, a, dd, d->pagesize);
347                         if(result == NG){
348                                 printf("%s: write error\n", __FUNCTION__);
349                                 free(cmp);
350                                 return;
351                         }
352                         d->read(a, d->pagesize, cmp);
353                         if(memcmp(cmp, dd, d->pagesize) == 0){
354                                 a += d->pagesize;
355                                 dd += d->pagesize;
356                                 i -= d->pagesize;
357                         }else{
358                                 if(retry >= 0x100){
359                                         break;
360                                 }
361                                 retry++;
362                         }
363                 }
364                 free(cmp);
365         }
366
367         printf("write ok. retry %d\n", retry);
368         compare(d, address, m->data, length);
369         Sleep(10);
370 }
371
372 static void w29c040_write(const struct flash_order *d, long address, long length, const struct memory *m)
373 {
374         u8 *cmp;
375         int ngblock = 0;
376         int retry = 0;
377         assert(d->pagesize != 0);
378         cmp = malloc(d->pagesize);
379         do{
380                 long a = address;
381                 long i = length;
382                 long offset = m->offset;
383                 const u8 *dd;
384
385                 dd = m->data;
386                 ngblock = 0;
387                 while(i != 0){
388                         d->read(a, d->pagesize, cmp);
389                         if(memcmp(cmp, dd, d->pagesize) != 0){
390                                 ngblock++;
391                                 printf("write %s 0x%06x\n", m->name, (int) offset);
392                                 int result = program_pagewrite(d, a, dd, d->pagesize);
393                                 if(result == NG){
394                                         printf("%s: write error\n", __FUNCTION__);
395                                         free(cmp);
396                                         return;
397                                 }
398                         }
399                         a += d->pagesize;
400                         dd += d->pagesize;
401                         offset += d->pagesize;
402                         i -= d->pagesize;
403                 }
404                 printf("%s 0x%06x, ngblock %d\n", m->name, (int) offset, ngblock);
405                 if(retry >= 3 && ngblock >= 16){
406                         printf("skip\n");
407                         break;
408                 }
409                 else if(retry > 12){
410                         printf("skip\n");
411                         break;
412                 }
413                 retry++;
414                 fflush(stdout);
415         }while(ngblock != 0);
416
417         free(cmp);
418 //      compare(d, address, data, length);
419 //      Sleep(10);
420 }
421
422 static void sram_write(const struct flash_order *d, long address, long length, const struct memory *m)
423 {
424         const u8 *data;
425         data = m->data;
426         while(length != 0){
427                 d->flash_write(address, *data);
428                 address++;
429                 data++;
430                 length--;
431         }
432 }
433
434 /*
435 ¥Ç¥Ð¥¤¥¹¥ê¥¹¥È
436 */
437 enum{
438         ID_SRAM = 0
439 };
440 static const struct flash_driver DRIVER_SRAM256K = {
441         .name = "SRAM256K",
442         .capacity = 0x8000,
443         .pagesize = 0,
444         .id_manufacurer = ID_SRAM,
445         .id_device = ID_SRAM,
446         .productid_check = productid_sram,
447 #if DEBUG==1
448         .erase = sram_erase,
449 #endif
450         .init = init_nop,
451         .write = sram_write
452 };
453
454 static const struct flash_driver DRIVER_W29C020 = {
455         .name = "W29C020",
456         .capacity = 0x40000,
457         .pagesize = 0x80,
458         .id_manufacurer = 0xda,
459         .id_device = 0x45,
460         .productid_check = productid_check,
461 #if DEBUG==1
462         .erase = flash_erase_chip,
463 #endif
464         .init = init_nop,
465         .write = w29c020_write
466 };
467
468 static const struct flash_driver DRIVER_W29C040 = {
469         .name = "W29C040",
470         .capacity = 0x80000,
471         .pagesize = 0x100,
472         .id_manufacurer = 0xda,
473         .id_device = 0x46,
474         .productid_check = productid_check,
475 #if DEBUG==1
476         .erase = flash_erase_chip,
477 #endif
478         .init = init_nop,
479         .write = w29c040_write
480 };
481
482 static const struct flash_driver DRIVER_W49F002 = {
483         .name = "W49F002",
484         .capacity = 0x40000,
485         .pagesize = 0,
486         .id_manufacurer = 0xda,
487         .id_device = 0xae,
488         .productid_check = productid_check,
489 #if DEBUG==1
490         .erase = flash_erase_chip,
491 #endif
492         .init = w49f002_init,
493         .write = w49f002_write
494 };
495
496 /*
497 MANUFATUTER ID 0x7f1c
498 EN29F002T DEVICE ID 0x7f92
499 EN29F002B DEVICE ID 0x7f97
500
501 command address ¤¬ 0x00555, 0x00aaa ¤Ë¤Ê¤Ã¤Æ¤ë
502 */
503 static const struct flash_driver DRIVER_EN29F002T = {
504         .name = "EN29F002T",
505         .capacity = 0x40000,
506         .pagesize = 0,
507         .id_manufacurer = 0x1c,
508         .id_device = 0x92,
509         .productid_check = productid_check,
510 #if DEBUG==1
511         .erase = flash_erase_chip,
512 #endif
513         .init = w49f002_init,
514         .write = w49f002_write
515 };
516
517 static const struct flash_driver DRIVER_AM29F040B = {
518         .name = "AM29F040B",
519         .capacity = 0x80000,
520         .pagesize = 0,
521         .id_manufacurer = 0x01,
522         .id_device = 0xa4,
523         .productid_check = productid_check,
524 #if DEBUG==1
525         .erase = flash_erase_chip,
526 #endif
527         .init = w49f002_init,
528         .write = w49f002_write
529 };
530
531 static const struct flash_driver *DRIVER_LIST[] = {
532         &DRIVER_W29C020, &DRIVER_W29C040, &DRIVER_W49F002,
533         &DRIVER_SRAM256K, 
534         NULL
535 };
536
537 const struct flash_driver *flash_driver_get(const char *name)
538 {
539         const struct flash_driver **d;
540         d = DRIVER_LIST;
541         while(*d != NULL){
542                 if(strcmp(name, (*d)->name) == 0){
543                         return *d;
544                 }
545                 d++;
546         }
547         return NULL;
548 }