OSDN Git Service

flash_write を WE,CS,CS,WE から CS,WE,WE,CSに変更
[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 "flashmemory.h"
32 /*
33 driver for Winbond W29C020, W49F002
34 */
35 /*
36 JEDEC flash memory command
37 http://www.sst.com/downloads/software_driver/SST49LF002A.txt
38 */
39 struct flash_task{
40         long address, data;
41 };
42 enum{
43         ADDRESS_0000 = 0,
44         ADDRESS_2AAA = 0x2aaa,
45         ADDRESS_5555 = 0x5555,
46         FLASH_COMMAND_END
47 };
48 static const struct flash_task PRODUCTID_ENTRY[] = {
49         {ADDRESS_5555, 0xaa},
50         {ADDRESS_2AAA, 0x55},
51         {ADDRESS_5555, 0x90},
52         {FLASH_COMMAND_END, 0}
53 };
54 static const struct flash_task PRODUCTID_EXIT[] = {
55         {ADDRESS_5555, 0xaa},
56         {ADDRESS_2AAA, 0x55},
57         {ADDRESS_5555, 0xf0},
58         {FLASH_COMMAND_END, 0}
59 };
60 static const struct flash_task PROTECT_DISABLE[] = {
61         {ADDRESS_5555, 0xaa},
62         {ADDRESS_2AAA, 0x55},
63         {ADDRESS_5555, 0xa0},
64         {FLASH_COMMAND_END, 0}
65 };
66 static const struct flash_task PROTECT_ENABLE[] = {
67         {ADDRESS_5555, 0xaa},
68         {ADDRESS_2AAA, 0x55},
69         {ADDRESS_5555, 0x80},
70         {ADDRESS_5555, 0xaa},
71         {ADDRESS_2AAA, 0x55},
72         {ADDRESS_5555, 0x20},
73         {FLASH_COMMAND_END, 0}
74 };
75 static const struct flash_task ERASE[] = {
76         {ADDRESS_5555, 0xaa},
77         {ADDRESS_2AAA, 0x55},
78         {ADDRESS_5555, 0x80},
79         {ADDRESS_5555, 0xaa},
80         {ADDRESS_2AAA, 0x55},
81         {ADDRESS_5555, 0x10},
82         {FLASH_COMMAND_END, 0}
83 };
84
85 static const struct flash_task PP[] = {
86         {ADDRESS_5555, 0xaa},
87         {ADDRESS_2AAA, 0x55},
88         {ADDRESS_5555, 0x80},
89         {ADDRESS_5555, 0xaa},
90         {ADDRESS_2AAA, 0x55},
91         {ADDRESS_5555, 0x60},
92         {FLASH_COMMAND_END, 0}
93 };
94
95 static void command_set(const struct flash_order *d, const struct flash_task *t)
96 {
97         while(t->address != FLASH_COMMAND_END){
98                 long logical_address = 0;
99                 switch(t->address){
100                 case ADDRESS_0000: //bank ¤Ë¤è¤Ã¤Æ¤ÏÀßÄê¤Ç¤­¤Ê¤¤¤«¤â?
101                         logical_address = d->command_0000;
102                         break;
103                 case ADDRESS_2AAA:
104                         logical_address = d->command_2aaa;
105                         break;
106                 case ADDRESS_5555:
107                         logical_address = d->command_5555;
108                         break;
109                 default:
110                         assert(0); //unknown task address
111                 }
112                 d->flash_write(logical_address, t->data);
113                 t++;
114         }
115 }
116
117 /*
118 ---- product ID check ----
119 */
120 static int productid_check(const struct flash_order *d, const struct flash_driver *f)
121 {
122         u8 data[3];
123         command_set(d, PRODUCTID_ENTRY);
124         d->read(d->command_0000, 3, data);
125         command_set(d, PRODUCTID_EXIT);
126         if(f->id_manufacurer != data[0]){
127                 return NG;
128         }
129         if(f->id_device != data[1]){
130                 return NG;
131         }
132         return OK;
133 }
134
135 /*
136 ---- toggle check ----
137 databit6
138 */
139 const int CHECK_RETRY_MAX = 0x10000;
140 static int toggle_check(const struct flash_order *d, long address)
141 {
142         u8 predata;
143         int retry = 0;
144         d->read(address, 1, &predata); //read DQ6
145         predata &= 0x40;
146         while(retry < CHECK_RETRY_MAX){
147                 u8 data;
148                 d->read(address, 1, &data); //read DQ6 again
149                 data &= 0x40;
150                 if(predata == data){
151                         return OK;
152                 }
153                 predata = data;
154                 retry++;
155         }
156         return NG;
157 }
158
159 /*
160 ---- polling check ----
161 databit7
162 */
163 static int polling_check(const struct flash_order *d, long address, u8 truedata)
164 {
165         int retry = 0;
166         
167         truedata &= 0x80;
168         while(retry < CHECK_RETRY_MAX){
169                 u8 data;
170                 d->read(address, 1, &data);
171                 data &= 0x80;
172                 if(truedata == data){
173                         return OK;
174                 }
175                 retry++;
176         }
177         return NG;
178 }
179
180 static void bootblock_lockout(const struct flash_order *d)
181 {
182         u8 dummy[3];
183         command_set(d, PP);
184         d->read(0x8000 ,3, dummy);
185         printf("%02x %02x %02x \n", dummy[0], dummy[1], dummy[2]);
186         d->read(0xfff2 ,1, dummy);
187         command_set(d, PRODUCTID_EXIT);
188 }
189 /*
190 ---- erase ----
191 */
192 static void flash_erase(const struct flash_order *d)
193 {
194         if(0) bootblock_lockout(d);
195         command_set(d, ERASE);
196         toggle_check(d, d->command_2aaa);
197         Sleep(200); //Tec 0.2 sec
198 }
199
200 /*
201 ---- program ----
202 */
203 static int program_byte(const struct flash_order *d, long address, const u8 *data, long length)
204 {
205         while(length != 0){
206                 if(*data != 0xff){
207                         command_set(d, PROTECT_DISABLE);
208                         d->flash_write(address, *data);
209                         if(toggle_check(d, address) == NG){
210                                 if(DEBUG == 1){
211                                         printf("%s NG\n", __FUNCTION__);
212                                 }
213                                 return NG;
214                         }
215                         Sleep(1);
216                 }
217                 if((DEBUG == 1) && (address & 0x1f) == 0){
218                         printf("%s %06x\n", __FUNCTION__, (int) address);
219                         fflush(stdout);
220                 }
221                 address++;
222                 data++;
223                 length--;
224         }
225         return OK;
226 }
227
228 static int program_pagewrite(const struct flash_order *d, long address, const u8 *data, long length)
229 {
230         const long toggle_address = address;
231         command_set(d, PROTECT_DISABLE);
232         while(length != 0){
233                 d->flash_write(address, *data);
234                 address++;
235                 data++;
236                 length--;
237         }
238         Sleep(15);
239         int ret = toggle_check(d, toggle_address);
240         if(0){
241                 data--;
242                 address -= 1;
243                 polling_check(d, address - 1, *data);
244         }
245
246         //command_set(d, PROTECT_ENABLE);
247         //Sleep(15);
248         return ret;
249 }
250
251 /*
252 ---- block compare ----
253 */
254 static void compare(const struct flash_order *d, long address, const u8 *data, long length)
255 {
256         u8 *romdata, *r;
257         int count = 0;
258         romdata = malloc(length);
259         d->read(address, length, romdata);
260         r = romdata;
261         while(length != 0){
262                 if(*r != *data){
263                         char safix = ' ';
264                         if((count & 7) == 7){
265                                 safix = '\n';
266                         }
267                         count++;
268                         printf("%06x%c", (int)address, safix);
269                 }
270                 r++;
271                 data++;
272                 address++;
273                 length--;
274         }
275         free(romdata);
276 }
277
278 /*
279 ¸ÇÍ­¥Ç¥Ð¥¤¥¹¥É¥é¥¤¥Ð
280 */
281 static void w49f002_init(const struct flash_order *d)
282 {
283 /*
284 byte program mode ¤Ç¤Ï 1->0 ¤Ë¤¹¤ë¤À¤±¡£ 0->1 ¤Ï erase ¤Î¤ß¡£
285 ¤è¤Ã¤Æ½é´ü²½»þ¤Ë¤Ï erase ¤ò¼Â¹Ô¤¹¤ë
286 */
287         flash_erase(d);
288 }
289
290 static void w49f002_write(const struct flash_order *d, long address, long length, const u8 *data)
291 {
292         program_byte(d, address, data, length);
293         compare(d, address, data, length);
294 }
295
296 static void w29c020_init(const struct flash_order *d)
297 {
298 /*
299 page write mode ¤Ç¤Ï¤È¤¯¤Ë¤Ê¤·
300 */
301 }
302
303 static void w29c020_write(const struct flash_order *d, long address, long length, const u8 *data)
304 {
305         const long pagesize = 0x80;
306         int retry = 0;
307         {
308                 long a = address;
309                 long i = length;
310                 const u8 *dd;
311                 u8 *cmp;
312
313                 dd = data;
314                 cmp = malloc(pagesize);
315                 while(i != 0){
316                         int result = program_pagewrite(d, a, dd, pagesize);
317                         if(result == NG){
318                                 printf("%s: write error\n", __FUNCTION__);
319                                 free(cmp);
320                                 return;
321                         }
322                         d->read(a, pagesize, cmp);
323                         if(memcmp(cmp, dd, pagesize) == 0){
324                                 a += pagesize;
325                                 dd += pagesize;
326                                 i -= pagesize;
327                         }else{
328                                 if(retry >= 0x100){
329                                         break;
330                                 }
331                                 retry++;
332                         }
333                 }
334                 free(cmp);
335         }
336
337         printf("write ok. retry %d\n", retry);
338         compare(d, address, data, length);
339         Sleep(10);
340 }
341
342 static void w29c040_write(const struct flash_order *d, long address, long length, const u8 *data)
343 {
344         const long pagesize = 0x100;
345         u8 *cmp;
346         int ngblock = 0;
347         cmp = malloc(pagesize);
348         do{
349                 long a = address;
350                 long i = length;
351                 const u8 *dd;
352
353                 dd = data;
354                 ngblock = 0;
355                 while(i != 0){
356                         d->read(a, pagesize, cmp);
357                         if(memcmp(cmp, dd, pagesize) != 0){
358                                 ngblock++;
359                                 printf("write %x\n", (int) a);
360                                 int result = program_pagewrite(d, a, dd, pagesize);
361                                 if(result == NG){
362                                         printf("%s: write error\n", __FUNCTION__);
363                                         free(cmp);
364                                         return;
365                                 }
366                         }
367                         a += pagesize;
368                         dd += pagesize;
369                         i -= pagesize;
370                 }
371                 printf("ngblock %d\n", ngblock);
372                 fflush(stdout);
373         }while(ngblock != 0);
374
375         free(cmp);
376         compare(d, address, data, length);
377         Sleep(10);
378 }
379
380 /*
381 ¥Ç¥Ð¥¤¥¹¥ê¥¹¥È
382 */
383 static const struct flash_driver DRIVER_W29C020 = {
384         .name = "W29C020",
385         .capacity = 0x40000,
386         .id_manufacurer = 0xda,
387         .id_device = 0x45,
388         .productid_check = productid_check,
389 #if DEBUG==1
390         .erase = flash_erase,
391 #endif
392         .init = w29c020_init,
393         .write = w29c020_write
394 };
395
396 static const struct flash_driver DRIVER_W29C040 = {
397         .name = "W29C040",
398         .capacity = 0x80000,
399         .id_manufacurer = 0xda,
400         .id_device = 0x46,
401         .productid_check = productid_check,
402 #if DEBUG==1
403         .erase = flash_erase,
404 #endif
405         .init = w29c020_init,
406         .write = w29c040_write
407 };
408
409 static const struct flash_driver DRIVER_W49F002 = {
410         .name = "W49F002",
411         .capacity = 0x40000,
412         .id_manufacurer = 0xda,
413         .id_device = 0xae,
414         .productid_check = productid_check,
415 #if DEBUG==1
416         .erase = flash_erase,
417 #endif
418         .init = w49f002_init,
419         .write = w49f002_write
420 };
421
422 static const struct flash_driver *DRIVER_LIST[] = {
423         &DRIVER_W29C020, &DRIVER_W29C040, &DRIVER_W49F002,
424         NULL
425 };
426
427 const struct flash_driver *flash_driver_get(const char *name)
428 {
429         const struct flash_driver **d;
430         d = DRIVER_LIST;
431         while(*d != NULL){
432                 if(strcmp(name, (*d)->name) == 0){
433                         return *d;
434                 }
435                 d++;
436         }
437         return NULL;
438 }