Fix an error in the TCC NAND driver which caused a panic on startup for certain users.
[kugel-rb.git] / firmware / target / arm / ata-nand-telechips.c
blob30ca302ce9cd8bc96b22d59eb2102c292d6bff2a
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2008 Rob Purchase
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
21 #include "nand.h"
22 #include "ata-nand-target.h"
23 #include "system.h"
24 #include <string.h>
25 #include "led.h"
26 #include "panic.h"
27 #include "nand_id.h"
28 #include "storage.h"
29 #include "buffer.h"
31 #define SECTOR_SIZE 512
33 /* #define USE_ECC_CORRECTION */
35 /* for compatibility */
36 int ata_spinup_time = 0;
38 long last_disk_activity = -1;
40 /** static, private data **/
41 static bool initialized = false;
43 static long next_yield = 0;
44 #define MIN_YIELD_PERIOD 1000
46 static struct mutex ata_mtx SHAREDBSS_ATTR;
48 #if defined(COWON_D2) || defined(IAUDIO_7)
49 #define FTL_V2
50 #define MAX_WRITE_CACHES 8
51 #else
52 #define FTL_V1
53 #define MAX_WRITE_CACHES 4
54 #endif
56 /* Sector type identifiers - main data area */
58 #define SECTYPE_MAIN_LPT 0x12
59 #define SECTYPE_MAIN_DATA 0x13
60 #define SECTYPE_MAIN_RANDOM_CACHE 0x15
61 #define SECTYPE_MAIN_INPLACE_CACHE 0x17
63 /* We don't touch the hidden area at all - these are for reference */
64 #define SECTYPE_HIDDEN_LPT 0x22
65 #define SECTYPE_HIDDEN_DATA 0x23
66 #define SECTYPE_HIDDEN_RANDOM_CACHE 0x25
67 #define SECTYPE_HIDDEN_INPLACE_CACHE 0x27
69 #ifdef FTL_V1
70 #define SECTYPE_FIRMWARE 0x40
71 #else
72 #define SECTYPE_FIRMWARE 0xE0
73 #endif
75 /* Offsets to data within sector's spare area */
77 #define OFF_CACHE_PAGE_LOBYTE 2
78 #define OFF_CACHE_PAGE_HIBYTE 3
79 #define OFF_SECTOR_TYPE 4
81 #ifdef FTL_V2
82 #define OFF_LOG_SEG_LOBYTE 7
83 #define OFF_LOG_SEG_HIBYTE 6
84 #else
85 #define OFF_LOG_SEG_LOBYTE 6
86 #define OFF_LOG_SEG_HIBYTE 7
87 #endif
89 /* Chip characteristics, initialised by nand_get_chip_info() */
91 static struct nand_info* nand_data = NULL;
93 static int total_banks = 0;
94 static int pages_per_bank = 0;
95 static int sectors_per_page = 0;
96 static int bytes_per_segment = 0;
97 static int sectors_per_segment = 0;
98 static int segments_per_bank = 0;
99 static int pages_per_segment = 0;
101 /* Maximum values for static buffers */
103 #define MAX_PAGE_SIZE 4096
104 #define MAX_SPARE_SIZE 128
105 #define MAX_BLOCKS_PER_BANK 8192
106 #define MAX_PAGES_PER_BLOCK 128
107 #define MAX_BANKS 4
108 #define MAX_BLOCKS_PER_SEGMENT 4
110 #define MAX_SEGMENTS (MAX_BLOCKS_PER_BANK * MAX_BANKS / MAX_BLOCKS_PER_SEGMENT)
112 /* Logical/Physical translation table */
114 struct lpt_entry
116 short bank;
117 short phys_segment;
119 #ifdef BOOTLOADER
120 static struct lpt_entry lpt_lookup[MAX_SEGMENTS];
121 #else
122 /* buffer_alloc'd in nand_init() when the correct size has been determined */
123 static struct lpt_entry* lpt_lookup = NULL;
124 #endif
126 /* Write Caches */
128 struct write_cache
130 short log_segment;
131 short inplace_bank;
132 short inplace_phys_segment;
133 short inplace_pages_used;
134 short random_bank;
135 short random_phys_segment;
136 short page_map[MAX_PAGES_PER_BLOCK * MAX_BLOCKS_PER_SEGMENT];
138 static struct write_cache write_caches[MAX_WRITE_CACHES];
140 static int write_caches_in_use = 0;
142 #ifdef USE_ECC_CORRECTION
143 static unsigned int ecc_sectors_corrected = 0;
144 static unsigned int ecc_bits_corrected = 0;
145 static unsigned int ecc_fail_count = 0;
146 #endif
149 /* Conversion functions */
151 static int phys_segment_to_page_addr(int phys_segment, int page_in_seg)
153 int page_addr = 0;
155 switch (nand_data->planes)
157 case 1:
159 page_addr = (phys_segment * nand_data->pages_per_block);
160 break;
163 case 2:
164 case 4:
166 page_addr = phys_segment * nand_data->pages_per_block * 2;
168 if (page_in_seg & 1)
170 /* Data is located in block+1 */
171 page_addr += nand_data->pages_per_block;
174 if (nand_data->planes == 4 && page_in_seg & 2)
176 /* Data is located in 2nd half of bank */
177 page_addr +=
178 (nand_data->blocks_per_bank/2) * nand_data->pages_per_block;
181 break;
185 page_addr += (page_in_seg / nand_data->planes);
187 return page_addr;
191 /* NAND physical access functions */
193 static void nand_chip_select(int bank)
195 if (bank == -1)
197 /* Disable both chip selects */
198 NAND_GPIO_CLEAR(CS_GPIO_BIT);
199 NFC_CTRL |= NFC_CS0 | NFC_CS1;
201 else
203 /* NFC chip select */
204 if (bank & 1)
206 NFC_CTRL &= ~NFC_CS0;
207 NFC_CTRL |= NFC_CS1;
209 else
211 NFC_CTRL |= NFC_CS0;
212 NFC_CTRL &= ~NFC_CS1;
215 /* Secondary chip select */
216 if (bank & 2)
217 NAND_GPIO_SET(CS_GPIO_BIT);
218 else
219 NAND_GPIO_CLEAR(CS_GPIO_BIT);
224 static void nand_read_id(int bank, unsigned char* id_buf)
226 int i;
228 /* Enable NFC bus clock */
229 BCLKCTR |= DEV_NAND;
231 /* Reset NAND controller */
232 NFC_RST = 0;
234 /* Set slow cycle timings since the chip is as yet unidentified */
235 NFC_CTRL = (NFC_CTRL &~0xFFF) | 0x353;
237 nand_chip_select(bank);
239 /* Set write protect */
240 NAND_GPIO_CLEAR(WE_GPIO_BIT);
242 /* Reset command */
243 NFC_CMD = 0xFF;
245 /* Set 8-bit data width */
246 NFC_CTRL &= ~NFC_16BIT;
248 /* Read ID command, single address cycle */
249 NFC_CMD = 0x90;
250 NFC_SADDR = 0x00;
252 /* Read the 5 chip ID bytes */
253 for (i = 0; i < 5; i++)
255 id_buf[i] = NFC_SDATA & 0xFF;
258 nand_chip_select(-1);
260 /* Disable NFC bus clock */
261 BCLKCTR &= ~DEV_NAND;
265 static void nand_read_uid(int bank, unsigned int* uid_buf)
267 int i;
269 /* Enable NFC bus clock */
270 BCLKCTR |= DEV_NAND;
272 /* Set cycle timing (stp = 1, pw = 3, hold = 1) */
273 NFC_CTRL = (NFC_CTRL &~0xFFF) | 0x131;
275 nand_chip_select(bank);
277 /* Set write protect */
278 NAND_GPIO_CLEAR(WE_GPIO_BIT);
280 /* Set 8-bit data width */
281 NFC_CTRL &= ~NFC_16BIT;
283 /* Undocumented (SAMSUNG specific?) commands set the chip into a
284 special mode allowing a normally-hidden UID block to be read. */
285 NFC_CMD = 0x30;
286 NFC_CMD = 0x65;
288 /* Read command */
289 NFC_CMD = 0x00;
291 /* Write row/column address */
292 for (i = 0; i < nand_data->col_cycles; i++) NFC_SADDR = 0;
293 for (i = 0; i < nand_data->row_cycles; i++) NFC_SADDR = 0;
295 /* End of read */
296 NFC_CMD = 0x30;
298 /* Wait until complete */
299 while (!(NFC_CTRL & NFC_READY)) {};
301 /* Copy data to buffer (data repeats after 8 words) */
302 for (i = 0; i < 8; i++)
304 uid_buf[i] = NFC_WDATA;
307 /* Reset the chip back to normal mode */
308 NFC_CMD = 0xFF;
310 nand_chip_select(-1);
312 /* Disable NFC bus clock */
313 BCLKCTR &= ~DEV_NAND;
317 static void nand_read_raw(int bank, int row, int column, int size, void* buf)
319 int i;
321 /* Enable NFC bus clock */
322 BCLKCTR |= DEV_NAND;
324 /* Set cycle timing (stp = 1, pw = 3, hold = 1) */
325 NFC_CTRL = (NFC_CTRL &~0xFFF) | 0x131;
327 nand_chip_select(bank);
329 /* Set write protect */
330 NAND_GPIO_CLEAR(WE_GPIO_BIT);
332 /* Set 8-bit data width */
333 NFC_CTRL &= ~NFC_16BIT;
335 /* Read command */
336 NFC_CMD = 0x00;
338 /* Write column address */
339 for (i = 0; i < nand_data->col_cycles; i++)
341 NFC_SADDR = column & 0xFF;
342 column = column >> 8;
345 /* Write row address */
346 for (i = 0; i < nand_data->row_cycles; i++)
348 NFC_SADDR = row & 0xFF;
349 row = row >> 8;
352 /* End of read command */
353 NFC_CMD = 0x30;
355 /* Wait until complete */
356 while (!(NFC_CTRL & NFC_READY)) {};
358 /* Read data into page buffer */
359 if (((unsigned int)buf & 3) || (size & 3))
361 /* Use byte copy since either the buffer or size are not word-aligned */
362 /* TODO: Byte copy only where necessary (use words for mid-section) */
363 for (i = 0; i < size; i++)
365 ((unsigned char*)buf)[i] = NFC_SDATA;
368 else
370 /* Use 4-byte copy as buffer and size are both word-aligned */
371 for (i = 0; i < (size/4); i++)
373 ((unsigned int*)buf)[i] = NFC_WDATA;
377 nand_chip_select(-1);
379 /* Disable NFC bus clock */
380 BCLKCTR &= ~DEV_NAND;
384 static void nand_get_chip_info(void)
386 unsigned char manuf_id;
387 unsigned char id_buf[8];
389 /* Read chip id from bank 0 */
390 nand_read_id(0, id_buf);
392 manuf_id = id_buf[0];
394 /* Identify the chip geometry */
395 nand_data = nand_identify(id_buf);
397 if (nand_data == NULL)
399 panicf("Unknown NAND: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x",
400 id_buf[0],id_buf[1],id_buf[2],id_buf[3],id_buf[4]);
403 pages_per_bank = nand_data->blocks_per_bank * nand_data->pages_per_block;
405 segments_per_bank = nand_data->blocks_per_bank / nand_data->planes;
407 bytes_per_segment = nand_data->page_size * nand_data->pages_per_block
408 * nand_data->planes;
410 sectors_per_page = nand_data->page_size / SECTOR_SIZE;
412 sectors_per_segment = bytes_per_segment / SECTOR_SIZE;
414 pages_per_segment = sectors_per_segment / sectors_per_page;
416 /* Establish how many banks are present */
417 nand_read_id(1, id_buf);
419 if (id_buf[0] == manuf_id)
421 /* Bank 1 is populated, now check if banks 2/3 are valid */
422 nand_read_id(2, id_buf);
424 if (id_buf[0] == manuf_id)
426 /* Bank 2 returned matching id - check if 2/3 are shadowing 0/1 */
427 unsigned int uid_buf0[8];
428 unsigned int uid_buf2[8];
430 nand_read_uid(0, uid_buf0);
431 nand_read_uid(2, uid_buf2);
433 if (memcmp(uid_buf0, uid_buf2, 32) == 0)
435 /* UIDs match, assume banks 2/3 are shadowing 0/1 */
436 total_banks = 2;
438 else
440 /* UIDs differ, assume banks 2/3 are valid */
441 total_banks = 4;
444 else
446 /* Bank 2 returned differing id - assume 2/3 are junk */
447 total_banks = 2;
450 else
452 /* Bank 1 returned differing id - assume it is junk */
453 total_banks = 1;
457 Sanity checks:
458 1. "BMP" tag at block 0, page 0, offset <page_size> [always present]
459 2. On most D2s, <page_size>+3 is 'M' and <page_size>+4 is no. of banks.
460 This is not present on some older players (formatted with early FW?)
463 nand_read_raw(0, 0, /* bank, page */
464 nand_data->page_size, /* offset */
465 8, id_buf); /* length, dest */
467 if (strncmp(id_buf, "BMP", 3)) panicf("BMP tag not present");
469 if (id_buf[3] == 'M')
471 if (id_buf[4] != total_banks) panicf("BMPM total_banks mismatch");
476 static bool nand_read_sector_of_phys_page(int bank, int page,
477 int sector, void* buf)
479 #ifndef USE_ECC_CORRECTION
480 nand_read_raw(bank, page,
481 sector * (SECTOR_SIZE+16),
482 SECTOR_SIZE, buf);
483 return true;
484 #else
485 /* Not yet implemented */
486 return false;
487 #endif
491 static bool nand_read_sector_of_phys_segment(int bank, int phys_segment,
492 int page_in_seg, int sector,
493 void* buf)
495 int page_addr = phys_segment_to_page_addr(phys_segment,
496 page_in_seg);
498 return nand_read_sector_of_phys_page(bank, page_addr, sector, buf);
502 static bool nand_read_sector_of_logical_segment(int log_segment, int sector,
503 void* buf)
505 int page_in_segment = sector / sectors_per_page;
506 int sector_in_page = sector % sectors_per_page;
508 int bank = lpt_lookup[log_segment].bank;
509 int phys_segment = lpt_lookup[log_segment].phys_segment;
511 /* Check if any of the write caches refer to this segment/page.
512 If present we need to read the cached page instead. */
514 int cache_num = 0;
515 bool found = false;
517 while (!found && cache_num < write_caches_in_use)
519 if (write_caches[cache_num].log_segment == log_segment)
521 if (write_caches[cache_num].page_map[page_in_segment] != -1)
523 /* data is located in random pages cache */
524 found = true;
526 bank = write_caches[cache_num].random_bank;
527 phys_segment = write_caches[cache_num].random_phys_segment;
529 page_in_segment =
530 write_caches[cache_num].page_map[page_in_segment];
532 else if (write_caches[cache_num].inplace_pages_used != -1 &&
533 write_caches[cache_num].inplace_pages_used > page_in_segment)
535 /* data is located in in-place pages cache */
536 found = true;
538 bank = write_caches[cache_num].inplace_bank;
539 phys_segment = write_caches[cache_num].inplace_phys_segment;
542 cache_num++;
545 return nand_read_sector_of_phys_segment(bank, phys_segment,
546 page_in_segment,
547 sector_in_page, buf);
551 /* Miscellaneous helper functions */
553 static inline unsigned char get_sector_type(char* spare_buf)
555 return spare_buf[OFF_SECTOR_TYPE];
558 static inline unsigned short get_log_segment_id(int phys_seg, char* spare_buf)
560 (void)phys_seg;
562 return ((spare_buf[OFF_LOG_SEG_HIBYTE] << 8) |
563 spare_buf[OFF_LOG_SEG_LOBYTE])
564 #if defined(FTL_V1)
565 + 984 * (phys_seg / 1024)
566 #endif
570 static inline unsigned short get_cached_page_id(char* spare_buf)
572 return (spare_buf[OFF_CACHE_PAGE_HIBYTE] << 8) |
573 spare_buf[OFF_CACHE_PAGE_LOBYTE];
576 static int find_write_cache(int log_segment)
578 int i;
580 for (i = 0; i < write_caches_in_use; i++)
581 if (write_caches[i].log_segment == log_segment)
582 return i;
584 return -1;
588 static void read_random_writes_cache(int bank, int phys_segment)
590 int page = 0;
591 short log_segment;
592 unsigned char spare_buf[16];
594 nand_read_raw(bank, phys_segment_to_page_addr(phys_segment, page),
595 SECTOR_SIZE, /* offset to first sector's spare */
596 16, spare_buf);
598 log_segment = get_log_segment_id(phys_segment, spare_buf);
600 if (log_segment == -1)
601 return;
603 /* Find which cache this is related to */
604 int cache_no = find_write_cache(log_segment);
606 if (cache_no == -1)
608 if (write_caches_in_use < MAX_WRITE_CACHES)
610 cache_no = write_caches_in_use;
611 write_caches_in_use++;
613 else
615 panicf("Max NAND write caches reached");
619 write_caches[cache_no].log_segment = log_segment;
620 write_caches[cache_no].random_bank = bank;
621 write_caches[cache_no].random_phys_segment = phys_segment;
623 #ifndef FTL_V1
624 /* Loop over each page in the phys segment (from page 1 onwards).
625 Read spare for 1st sector, store location of page in array. */
626 for (page = 1;
627 page < (nand_data->pages_per_block * nand_data->planes);
628 page++)
630 unsigned short cached_page;
632 nand_read_raw(bank, phys_segment_to_page_addr(phys_segment, page),
633 SECTOR_SIZE, /* offset to first sector's spare */
634 16, spare_buf);
636 cached_page = get_cached_page_id(spare_buf);
638 if (cached_page != 0xFFFF)
639 write_caches[cache_no].page_map[cached_page] = page;
641 #endif /* !FTL_V1 */
645 static void read_inplace_writes_cache(int bank, int phys_segment)
647 int page = 0;
648 short log_segment;
649 unsigned char spare_buf[16];
651 nand_read_raw(bank, phys_segment_to_page_addr(phys_segment, page),
652 SECTOR_SIZE, /* offset to first sector's spare */
653 16, spare_buf);
655 log_segment = get_log_segment_id(phys_segment, spare_buf);
657 if (log_segment == -1)
658 return;
660 /* Find which cache this is related to */
661 int cache_no = find_write_cache(log_segment);
663 if (cache_no == -1)
665 if (write_caches_in_use < MAX_WRITE_CACHES)
667 cache_no = write_caches_in_use;
668 write_caches_in_use++;
670 else
672 panicf("Max NAND write caches reached");
676 write_caches[cache_no].log_segment = log_segment;
678 /* Find how many pages have been written to the new segment */
679 while (log_segment != -1 &&
680 page < (nand_data->pages_per_block * nand_data->planes) - 1)
682 page++;
683 nand_read_raw(bank, phys_segment_to_page_addr(phys_segment, page),
684 SECTOR_SIZE, 16, spare_buf);
686 log_segment = get_log_segment_id(phys_segment, spare_buf);
689 if (page != 0)
691 write_caches[cache_no].inplace_bank = bank;
692 write_caches[cache_no].inplace_phys_segment = phys_segment;
693 write_caches[cache_no].inplace_pages_used = page;
698 int nand_read_sectors(IF_MV2(int drive,) unsigned long start, int incount,
699 void* inbuf)
701 #ifdef HAVE_MULTIVOLUME
702 (void)drive; /* unused for now */
703 #endif
704 mutex_lock(&ata_mtx);
706 while (incount > 0)
708 int done = 0;
709 int segment = start / sectors_per_segment;
710 int secmod = start % sectors_per_segment;
712 while (incount > 0 && secmod < sectors_per_segment)
714 if (!nand_read_sector_of_logical_segment(segment, secmod, inbuf))
716 mutex_unlock(&ata_mtx);
717 return -1;
720 #ifdef CPU_TCC780X /* 77x doesn't have USEC_TIMER yet */
721 if (TIME_AFTER(USEC_TIMER, next_yield))
723 next_yield = USEC_TIMER + MIN_YIELD_PERIOD;
724 yield();
726 #endif
728 inbuf += SECTOR_SIZE;
729 incount--;
730 secmod++;
731 done++;
734 if (done < 0)
736 mutex_unlock(&ata_mtx);
737 return -1;
739 start += done;
742 mutex_unlock(&ata_mtx);
743 return 0;
747 int nand_write_sectors(IF_MV2(int drive,) unsigned long start, int count,
748 const void* outbuf)
750 #ifdef HAVE_MULTIVOLUME
751 (void)drive; /* unused for now */
752 #endif
754 /* TODO: Learn more about TNFTL and implement this one day... */
755 (void)start;
756 (void)count;
757 (void)outbuf;
758 return -1;
762 #ifdef STORAGE_GET_INFO
763 void nand_get_info(struct storage_info *info)
765 /* firmware version */
766 info->revision="0.00";
768 info->vendor="Rockbox";
769 info->product="Internal Storage";
771 /* blocks count */
772 info->num_sectors = sectors_per_segment * segments_per_bank * total_banks;
773 info->sector_size = SECTOR_SIZE;
775 #endif
778 int nand_init(void)
780 int bank, phys_segment, lptbuf_size;
781 unsigned char spare_buf[16];
783 if (initialized) return 0;
785 mutex_init(&ata_mtx);
787 #ifdef CPU_TCC77X
788 CSCFG2 = 0x318a8010;
790 GPIOC_FUNC &= ~(CS_GPIO_BIT | WE_GPIO_BIT);
791 GPIOC_FUNC |= 0x1;
792 #endif
794 /* Set GPIO direction for chip select & write protect */
795 NAND_GPIO_OUT_EN(CS_GPIO_BIT | WE_GPIO_BIT);
797 /* Get chip characteristics and number of banks */
798 nand_get_chip_info();
800 #ifndef BOOTLOADER
801 /* Use chip info to allocate the correct size LPT buffer */
802 lptbuf_size = sizeof(struct lpt_entry) * segments_per_bank * total_banks;
803 lpt_lookup = buffer_alloc(lptbuf_size);
804 #else
805 /* Use a static array in the bootloader */
806 lptbuf_size = sizeof(lpt_lookup);
807 #endif
809 memset(lpt_lookup, 0xff, lptbuf_size);
810 memset(write_caches, 0xff, sizeof(write_caches));
812 write_caches_in_use = 0;
814 /* Scan banks to build up block translation table */
815 for (bank = 0; bank < total_banks; bank++)
817 for (phys_segment = 0; phys_segment < segments_per_bank; phys_segment++)
819 /* Read spare bytes from first sector of each segment */
820 nand_read_raw(bank, phys_segment_to_page_addr(phys_segment, 0),
821 SECTOR_SIZE, /* offset */
822 16, spare_buf);
824 int type = get_sector_type(spare_buf);
826 #ifdef FTL_V2
827 if (type == SECTYPE_MAIN_INPLACE_CACHE)
829 /* Since this type of segment is written to sequentially, its
830 job is complete if the final page has been written. In this
831 case we need to treat it as a normal data segment. */
832 nand_read_raw(bank, phys_segment_to_page_addr
833 (phys_segment, pages_per_segment - 1),
834 SECTOR_SIZE, 16, spare_buf);
836 if (get_sector_type(spare_buf) != 0xff)
838 type = SECTYPE_MAIN_DATA;
841 #endif
843 switch (type)
845 case SECTYPE_MAIN_DATA:
847 /* Main data area segment */
848 unsigned short log_segment =
849 get_log_segment_id(phys_segment, spare_buf);
851 if (log_segment < segments_per_bank * total_banks)
853 if (lpt_lookup[log_segment].bank == -1 ||
854 lpt_lookup[log_segment].phys_segment == -1)
856 lpt_lookup[log_segment].bank = bank;
857 lpt_lookup[log_segment].phys_segment = phys_segment;
859 else
861 //panicf("duplicate data segment 0x%x!", log_segment);
864 break;
867 case SECTYPE_MAIN_RANDOM_CACHE:
869 /* Newly-written random page data (Main data area) */
870 read_random_writes_cache(bank, phys_segment);
871 break;
874 case SECTYPE_MAIN_INPLACE_CACHE:
876 /* Newly-written sequential page data (Main data area) */
877 read_inplace_writes_cache(bank, phys_segment);
878 break;
884 initialized = true;
886 return 0;
889 long nand_last_disk_activity(void)
891 return last_disk_activity;
894 void nand_sleep(void)
898 void nand_spin(void)
902 void nand_spindown(int seconds)
904 (void)seconds;