Huge cleanup of type warnings etc.
[yaffs2.git] / direct / test-framework / nandsim.c
1 /*
2  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3  *
4  * Copyright (C) 2010-2011 Aleph One Ltd.
5  *
6  * Created by Charles Manning <charles@aleph1.co.uk>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  */
12 /*
13  * Nand simulator modelled on a Samsung K9K2G08U0A 8-bit, but capable of
14  * simulating x16 access too.
15  *
16  * Page size 2k + 64
17  * Block size 64 pages
18  * Dev size 256 Mbytes
19  */
20
21 #include "nandsim.h"
22 #include "nand_chip.h"
23
24 #include <stdint.h>
25 #include <fcntl.h>
26 #include <unistd.h>
27 #include <string.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30
31 #include "yportenv.h"
32
33 static int nandsim_debug = 0;
34
35 #define debug(n, fmt, ...) \
36         do { \
37         if (n <= nandsim_debug) \
38                 printf(fmt, ## __VA_ARGS__); \
39         } while (0)
40
41
42
43 struct nandsim_private {
44
45         struct nand_store *store;
46         /*
47         * Access buffers.
48         * Address buffer has two parts to it:
49         * 2 byte column (byte) offset
50         * 3 byte row (page) offset
51         */
52
53         unsigned char *buffer;
54         int buff_size;
55
56         unsigned char addr_buffer[5];
57
58         /*
59         * Offsets used to access address, read or write buffer.
60         * If the offset is negative then accessing is illegal.
61         */
62
63         int addr_offset;
64         int addr_expected;
65         int addr_received;
66
67         int read_offset;
68         int write_offset;
69         int read_started;
70
71         /*
72         * busy_count: If greater than zero then the device is busy.
73         * Busy count is decremented by check_busy() and by read_status()
74         */
75         int busy_count;
76         int write_prog_error;
77         int reading_status;
78         unsigned char last_cmd_byte;
79
80         int ale;
81         int cle;
82 };
83
84 static void last_cmd(struct nandsim_private *ns, unsigned char val)
85 {
86         ns->last_cmd_byte = val;
87 }
88
89 static void check_last(struct nandsim_private *ns,
90                         unsigned char should_be, int line)
91 {
92         if(ns->last_cmd_byte != should_be)
93                 debug(1, "At line %d:, last_cmd should be %02x, but is %02x\n",
94                         line, should_be, ns->last_cmd_byte);
95 }
96
97 static void idle(struct nandsim_private *ns, int line)
98 {
99         YAFFS_UNUSED(line);
100
101         ns->read_offset = -1;
102         ns->write_offset = -1;
103         ns->addr_offset = -1;
104         ns->addr_expected = -1;
105         ns->addr_received = -1;
106         last_cmd(ns, 0xff);
107         ns->busy_count = 0;
108         ns->reading_status = 0;
109         ns->read_started = 0;
110 }
111
112
113 static void expect_address(struct nandsim_private *ns,
114                         int nbytes, int line)
115 {
116         int from;
117
118         switch (nbytes) {
119         case 2:
120         case 5: /* contains an offset */
121                 from = 0;
122                 break;
123         case 3: /* no offset */
124                 from = 2;
125                 break;
126         default:
127                 debug(1, "expect_address illegal nbytes %d called at line %d\n",
128                                 nbytes, line);
129                 return;
130         }
131
132         ns->addr_offset = from;
133         ns->addr_expected = nbytes;
134         ns->addr_received = 0;
135         debug(1, "Expect %d address bytes\n",nbytes);
136 }
137
138 static int get_page_address(struct nandsim_private *ns)
139 {
140         int addr;
141
142         addr = (ns->addr_buffer[2]) |
143                 (ns->addr_buffer[3] << 8) |
144                 (ns->addr_buffer[4] << 16);
145         return addr;
146 }
147
148 static int get_page_offset(struct nandsim_private *ns)
149 {
150         int offs;
151
152         offs = (ns->addr_buffer[0]) |
153                 (ns->addr_buffer[1] << 8);
154         return offs;
155 }
156
157 static void check_address(struct nandsim_private *ns, int nbytes, int line)
158 {
159         if(ns->addr_expected != 0)
160                 debug(1, "Still expecting %d address bytes at line: %d\n",
161                                         ns->addr_expected, line);
162         if(ns->addr_received != nbytes)
163                 debug(1, "Only received %d address bytes instead of %d at line %d\n",
164                                         ns->addr_received, nbytes, line);
165 }
166
167 static void set_offset(struct nandsim_private *ns)
168 {
169         ns->read_offset = -1;
170         ns->write_offset = -1;
171
172         if(ns->last_cmd_byte == 0x80 )
173                 ns->write_offset = get_page_offset(ns);
174         else if(ns->last_cmd_byte == 0x00 || ns->last_cmd_byte == 0x05)
175                 ns->read_offset = get_page_offset(ns);
176         debug(2, "Last command was %02X offsets set to read %d write %d\n",
177                         ns->last_cmd_byte, ns->read_offset, ns->write_offset);
178 }
179
180 static void load_read_buffer(struct nandsim_private *ns)
181 {
182         int addr = get_page_address(ns);
183
184         debug(1, "Store read at address %d\n", addr);
185         ns->store->retrieve(ns->store, addr,ns->buffer);
186 }
187 static void save_write_buffer(struct nandsim_private *ns)
188 {
189         int addr = get_page_address(ns);
190
191         debug(1, "Store write at address %d\n", addr);
192         ns->store->store(ns->store, addr, ns->buffer);
193 }
194
195 static void check_read_buffer(struct nandsim_private *ns, int line)
196 {
197         YAFFS_UNUSED(ns);
198         YAFFS_UNUSED(line);
199 }
200
201 static void end_cmd(struct nandsim_private *ns, int line)
202 {
203         YAFFS_UNUSED(line);
204         ns->last_cmd_byte = 0xff;
205 }
206
207 static void set_busy(struct nandsim_private *ns, int cycles, int line)
208 {
209         YAFFS_UNUSED(line);
210
211         ns->busy_count = cycles;
212 }
213
214 static int check_not_busy(struct nandsim_private *ns, int line)
215 {
216         if(ns->busy_count > 0)
217                 debug(1, "Busy check failed at line %d\n",line);
218         return (ns->busy_count < 1);
219 }
220
221 /*
222  * Reset
223  * Cmd: 0xff
224  */
225 static void reset_0(struct nandsim_private *ns)
226 {
227         debug(2, "Reset\n");
228         last_cmd(ns, 0xff);
229         idle(ns, __LINE__);
230         end_cmd(ns, __LINE__);
231 }
232
233 /*
234  * Read
235  * cmd: 0x00, 5 address bytes, cmd: 0x30, wait not busy, read out data
236  *
237  * Note that 0x30 can also be used to exit the status reading state
238  * and return to data reading state.
239  *
240  * The following sequence uses the busy pin to wait:
241  *
242  *  Write cmd 0x00
243  *  Write 5 address bytes
244  *  Write cmd 0x30. Device now goes busy
245  *  Wait for busy pin to go idle
246  *  Read data bytes.
247  *
248  * The following sequence uses the status read to wait:
249  *  Write cmd 0x00
250  *  Write 5 address bytes
251  *  Write cmd 0x30. Device now goes busy
252  *  Write 0x70: (status)
253  *  Read status until device no longer busy
254  *  Write command byte 0x30 to exit status read. Can now read data
255  *  Read data bytes.
256
257  */
258
259
260 static void read_0(struct nandsim_private *ns)
261 {
262         debug(2, "Read 0\n");
263         check_last(ns, 0xff, __LINE__);
264         if(check_not_busy(ns, __LINE__))
265                 ns->reading_status = 0;
266         expect_address(ns, 5, __LINE__);
267         last_cmd(ns, 0x00);
268         ns->read_started = 1;
269 }
270
271 static void read_1(struct nandsim_private *ns)
272 {
273         debug(2, "Read 1\n");
274         if(check_not_busy(ns, __LINE__))
275                 ns->reading_status = 0;
276         if(ns->read_started){
277                 /* Doing a read */
278                 ns->read_started = 0;
279                 check_address(ns, 5, __LINE__);
280                 load_read_buffer(ns);
281                 set_busy(ns, 2, __LINE__);
282                 end_cmd(ns, __LINE__);
283         } else {
284                 /* reenter read mode after a status check */
285                 end_cmd(ns, __LINE__);
286         }
287 }
288
289 /*
290  * Random Data Output (sets read position in current page)
291  * Cmd: 0x05, 2-byte address, cmd: 0xE0. No busy
292  */
293
294 static void random_data_output_0(struct nandsim_private *ns)
295 {
296         debug(2, "Random data out 0\n");
297         check_last(ns, 0xff, __LINE__);
298         if(check_not_busy(ns, __LINE__))
299                 ns->reading_status = 0;
300         check_read_buffer(ns, __LINE__);
301         expect_address(ns, 2, __LINE__);
302         last_cmd(ns, 0x05);
303 }
304
305 static void random_data_output_1(struct nandsim_private *ns)
306 {
307         debug(2, "Random data out 1\n");
308         check_last(ns, 0x05, __LINE__);
309         check_address(ns, 2, __LINE__);
310 }
311
312
313 /*
314  * Program page
315  * Cmd: 0x80, 5-byte address, data bytes,  Cmd: 0x10, wait not busy
316  * That can be extended with random data input by inserting
317  * any number of random data input cycles before the 0x10 command
318  * Each random data input cycle is
319  *  Cmd 0x85 , 2 byte offset, data bytes
320  */
321
322 static void program_0(struct nandsim_private *ns)
323 {
324         debug(2, "Program 0\n");
325         check_last(ns, 0xff, __LINE__);
326         if(check_not_busy(ns, __LINE__))
327                 ns->reading_status = 0;
328         expect_address(ns, 5, __LINE__);
329         memset(ns->buffer, 0xff, ns->buff_size);
330         last_cmd(ns, 0x80);
331 }
332 static void random_data_input(struct nandsim_private *ns)
333 {
334         debug(2, "Random data input\n");
335         check_last(ns, 0x80, __LINE__);
336         expect_address(ns, 2, __LINE__);
337         last_cmd(ns, 0x80);
338 }
339
340 static void program_1(struct nandsim_private *ns)
341 {
342         debug(2, "Program 1\n");
343         if(check_not_busy(ns, __LINE__))
344                 ns->reading_status = 0;
345         check_last(ns, 0x80, __LINE__);
346         check_address(ns, 5, __LINE__);
347         save_write_buffer(ns);
348         set_busy(ns, 2, __LINE__);
349         end_cmd(ns, __LINE__);
350 }
351
352
353
354 /*
355  * Block erase
356  * Cmd: 0x60, 3-byte address, cmd: 0xD0. Wait not busy.
357  */
358 static void block_erase_0(struct nandsim_private *ns)
359 {
360         debug(2, "Block Erase 0\n");
361         check_last(ns, 0xff, __LINE__);
362         if(check_not_busy(ns, __LINE__))
363                 ns->reading_status = 0;
364         expect_address(ns, 3, __LINE__);
365         last_cmd(ns, 0x60);
366 }
367
368 static void block_erase_1(struct nandsim_private *ns)
369 {
370         int addr;
371
372         debug(2, "Block Erase 1\n");
373         check_last(ns, 0x60, __LINE__);
374         if(check_not_busy(ns, __LINE__))
375                 ns->reading_status = 0;
376         check_address(ns, 3, __LINE__);
377         set_busy(ns, 5, __LINE__);
378         addr = get_page_address(ns);
379         debug(1, "Erasing block at address %d\n", addr);
380         ns->store->erase(ns->store, addr);
381         end_cmd(ns, __LINE__);
382 }
383 /*
384  * Read stuatus
385  * Cmd 0x70
386  */
387 static void read_status(struct nandsim_private *ns)
388 {
389         debug(2, "Read status\n");
390         ns->reading_status = 1;
391 }
392
393 static void read_id(struct nandsim_private *ns)
394 {
395         YAFFS_UNUSED(ns);
396 }
397
398
399 static void unsupported(struct nandsim_private *ns)
400 {
401         YAFFS_UNUSED(ns);
402 }
403
404 static void nandsim_cl_write(struct nandsim_private *ns, unsigned char val)
405 {
406         debug(2, "CLE write %02X\n",val);
407         switch(val){
408                 case 0x00:
409                         read_0(ns);
410                         break;
411                 case 0x05:
412                         random_data_output_0(ns);
413                         break;
414                 case 0x10:
415                         program_1(ns);
416                         break;
417                 case 0x15:
418                         unsupported(ns);
419                         break;
420                 case 0x30:
421                         read_1(ns);
422                         break;
423                 case 0x35:
424                         unsupported(ns);
425                         break;
426                 case 0x60:
427                         block_erase_0(ns);
428                         break;
429                 case 0x70:
430                         read_status(ns);
431                         break;
432                 case 0x80:
433                         program_0(ns);
434                         break;
435                 case 0x85:
436                         random_data_input(ns);
437                         break;
438                 case 0x90:
439                         read_id(ns);
440                         break;
441                 case 0xD0:
442                         block_erase_1(ns);
443                         break;
444                 case 0xE0:
445                         random_data_output_1(ns);
446                         break;
447                 case 0xFF:
448                         reset_0(ns);
449                         break;
450                 default:
451                         debug(1, "CLE written with invalid value %02X.\n",val);
452                         break;
453                         /* Valid codes that we don't handle */
454                         debug(1, "CLE written with invalid value %02X.\n",val);
455         }
456 }
457
458
459 static void nandsim_al_write(struct nandsim_private *ns, unsigned char val)
460 {
461         check_not_busy(ns, __LINE__);
462         if(ns->addr_expected < 1 ||
463                 ns->addr_offset < 0 ||
464                 ns->addr_offset >= (int)sizeof(ns->addr_buffer)){
465                 debug(1, "Address write when not expected\n");
466         } else {
467                 debug(1, "Address write when expecting %d bytes\n",
468                         ns->addr_expected);
469                 ns->addr_buffer[ns->addr_offset] = val;
470                 ns->addr_offset++;
471                 ns->addr_received++;
472                 ns->addr_expected--;
473                 if(ns->addr_expected == 0)
474                         set_offset(ns);
475         }
476 }
477
478 static void nandsim_dl_write(struct nandsim_private *ns,
479                                 unsigned val,
480                                 int bus_width_shift)
481 {
482         check_not_busy(ns, __LINE__);
483         if( ns->write_offset < 0 || ns->write_offset >= ns->buff_size){
484                 debug(1, "Write at illegal buffer offset %d\n",
485                                 ns->write_offset);
486         } else if(bus_width_shift == 0) {
487                 ns->buffer[ns->write_offset] = val & 0xff;
488                 ns->write_offset++;
489         } else if(bus_width_shift == 1) {
490                 ns->buffer[ns->write_offset] = val & 0xff;
491                 ns->write_offset++;
492                 ns->buffer[ns->write_offset] = (val>>8) & 0xff;
493                 ns->write_offset++;
494         }
495 }
496
497 static unsigned nandsim_dl_read(struct nandsim_private *ns,
498                                 int bus_width_shift)
499 {
500         unsigned retval;
501         if(ns->reading_status){
502                 /*
503                  * bit 0 == 0 pass, == 1 fail.
504                  * bit 6 == 0 busy, == 1 ready
505                  */
506                 retval = 0xfe;
507                 if(ns->busy_count > 0){
508                         ns->busy_count--;
509                         retval&= ~(1<<6);
510                 }
511                 if(ns->write_prog_error)
512                         retval |= ~(1<<-0);
513                 debug(2, "Read status returning %02X\n",retval);
514         } else if(ns->busy_count > 0){
515                 debug(1, "Read while still busy\n");
516                 retval = 0;
517         } else if(ns->read_offset < 0 || ns->read_offset >= ns->buff_size){
518                 debug(1, "Read with no data available\n");
519                 retval = 0;
520         } else if(bus_width_shift == 0){
521                 retval = ns->buffer[ns->read_offset];
522                 ns->read_offset++;
523         } else if(bus_width_shift == 1){
524                 retval = ns->buffer[ns->read_offset];
525                 ns->read_offset++;
526                 retval |= (((unsigned)ns->buffer[ns->read_offset]) << 8);
527                 ns->read_offset++;
528         }
529
530         return retval;
531 }
532
533
534 static struct nandsim_private *
535 nandsim_init_private(struct nand_store *store)
536 {
537         struct nandsim_private *ns;
538         unsigned char *buffer;
539         int buff_size;
540
541         buff_size = (store->data_bytes_per_page + store->spare_bytes_per_page);
542
543         ns = malloc(sizeof(struct nandsim_private));
544         buffer = malloc(buff_size);
545         if(!ns || !buffer){
546                 free(ns);
547                 free(buffer);
548                 return NULL;
549         }
550
551         memset(ns, 0, sizeof(struct nandsim_private));
552         ns->buffer = buffer;
553         ns->buff_size = buff_size;
554         ns->store = store;
555         idle(ns, __LINE__);
556         return ns;
557 }
558
559
560 static void nandsim_set_ale(struct nand_chip * this, int ale)
561 {
562         struct nandsim_private *ns =
563                 (struct nandsim_private *)this->private_data;
564         ns->ale = ale;
565 }
566
567 static void nandsim_set_cle(struct nand_chip * this, int cle)
568 {
569         struct nandsim_private *ns =
570                 (struct nandsim_private *)this->private_data;
571         ns->cle = cle;
572 }
573
574 static unsigned nandsim_read_cycle(struct nand_chip * this)
575 {
576         unsigned retval;
577         struct nandsim_private *ns =
578                 (struct nandsim_private *)this->private_data;
579
580         if (ns->cle || ns->ale){
581                 debug(1, "Read cycle with CLE %s and ALE %s\n",
582                         ns->cle ? "high" : "low",
583                         ns->ale ? "high" : "low");
584                 retval = 0;
585         } else {
586                 retval =nandsim_dl_read(ns, this->bus_width_shift);
587         }
588         debug(5, "Read cycle returning %02X\n",retval);
589         return retval;
590 }
591
592 static void nandsim_write_cycle(struct nand_chip * this, unsigned b)
593 {
594         struct nandsim_private *ns =
595                 (struct nandsim_private *)this->private_data;
596         const char *x;
597
598         if(ns->ale && ns->cle)
599                 x = "ALE AND CLE";
600         else if (ns->ale)
601                 x = "ALE";
602         else if (ns->cle)
603                 x = "CLE";
604         else
605                 x = "data";
606
607         debug(5, "Write %02x to %s\n",
608                         b, x);
609         if (ns->cle && ns->ale)
610                 debug(1, "Write cycle with both ALE and CLE high\n");
611         else if (ns->cle)
612                 nandsim_cl_write(ns, b);
613         else if (ns->ale)
614                 nandsim_al_write(ns, b);
615         else
616                 nandsim_dl_write(ns, b, this->bus_width_shift);
617 }
618
619 static int nandsim_check_busy(struct nand_chip * this)
620 {
621         struct nandsim_private *ns =
622                 (struct nandsim_private *)this->private_data;
623
624
625         if (ns->busy_count> 0){
626                 ns->busy_count--;
627                 debug(2, "Still busy\n");
628                 return 1;
629         } else {
630                 debug(2, "Not busy\n");
631                 return 0;
632         }
633 }
634
635 static void nandsim_idle_fn(struct nand_chip *this)
636 {
637         struct nandsim_private *ns =
638                 (struct nandsim_private *)this->private_data;
639         ns = ns;
640 }
641
642 struct nand_chip *nandsim_init(struct nand_store *store, int bus_width_shift)
643 {
644         struct nand_chip *chip = NULL;
645         struct nandsim_private *ns = NULL;
646
647         chip = malloc(sizeof(struct nand_chip));
648         ns = nandsim_init_private(store);
649
650         if(chip && ns){
651                 memset(chip, 0, sizeof(struct nand_chip));;
652
653                 chip->private_data = ns;
654                 chip->set_ale = nandsim_set_ale;
655                 chip->set_cle = nandsim_set_cle;
656                 chip->read_cycle = nandsim_read_cycle;
657                 chip->write_cycle = nandsim_write_cycle;
658                 chip->check_busy = nandsim_check_busy;
659                 chip->idle_fn = nandsim_idle_fn;
660
661                 chip->bus_width_shift = bus_width_shift;
662
663                 chip->blocks = ns->store->blocks;
664                 chip->pages_per_block = ns->store->pages_per_block;
665                 chip->data_bytes_per_page = ns->store->data_bytes_per_page;
666                 chip->spare_bytes_per_page = ns->store->spare_bytes_per_page;
667
668                 return chip;
669         } else {
670                 free(chip);
671                 free(ns);
672                 return NULL;
673         }
674 }
675
676 void nandsim_set_debug(int d)
677 {
678         nandsim_debug = d;
679 }