diff options
Diffstat (limited to 'firmware/target/mips/ingenic_x1000/nand-x1000.h')
-rw-r--r-- | firmware/target/mips/ingenic_x1000/nand-x1000.h | 207 |
1 files changed, 141 insertions, 66 deletions
diff --git a/firmware/target/mips/ingenic_x1000/nand-x1000.h b/firmware/target/mips/ingenic_x1000/nand-x1000.h index cc56b836f8..711bf190b5 100644 --- a/firmware/target/mips/ingenic_x1000/nand-x1000.h +++ b/firmware/target/mips/ingenic_x1000/nand-x1000.h | |||
@@ -22,86 +22,161 @@ | |||
22 | #ifndef __NAND_X1000_H__ | 22 | #ifndef __NAND_X1000_H__ |
23 | #define __NAND_X1000_H__ | 23 | #define __NAND_X1000_H__ |
24 | 24 | ||
25 | /* NOTE: this is a very minimal API designed only to support a bootloader. | 25 | #include <stdint.h> |
26 | * Not suitable for general data storage. It doesn't have proper support for | 26 | #include <stddef.h> |
27 | * partial page writes, access to spare area, etc, which are all necessary | 27 | #include <stdbool.h> |
28 | * for an effective flash translation layer. | 28 | #include "kernel.h" |
29 | |||
30 | #define NAND_SUCCESS 0 | ||
31 | #define NAND_ERR_UNKNOWN_CHIP (-1) | ||
32 | #define NAND_ERR_PROGRAM_FAIL (-2) | ||
33 | #define NAND_ERR_ERASE_FAIL (-3) | ||
34 | #define NAND_ERR_UNALIGNED (-4) | ||
35 | |||
36 | /* keep max page size in sync with the NAND chip table in the .c file */ | ||
37 | #define NAND_DRV_SCRATCHSIZE 32 | ||
38 | #define NAND_DRV_MAXPAGESIZE 2112 | ||
39 | |||
40 | /* Quad I/O support bit */ | ||
41 | #define NAND_CHIPFLAG_QUAD 0x0001 | ||
42 | /* Chip requires QE bit set to enable quad I/O mode */ | ||
43 | #define NAND_CHIPFLAG_HAS_QE_BIT 0x0002 | ||
44 | |||
45 | /* Types to distinguish between block & page addresses in the API. | ||
29 | * | 46 | * |
30 | * There's no ECC support. This can be added if necessary, but it's unlikely | 47 | * BIT 31 log2_ppb bits |
31 | * the boot area on any X1000 device uses software ECC as Ingenic's SPL simply | 48 | * +-------------------------------+---------------+ |
32 | * doesn't have much room for more code (theirs programmed to work on multiple | 49 | * nand_page_t = | block nr | page nr | |
33 | * hardware configurations, so it's bigger than ours). | 50 | * +-------------------------------+---------------+ |
51 | * BIT 0 | ||
52 | * | ||
53 | * The page address is split into block and page numbers. Page numbers occupy | ||
54 | * the lower log2_ppb bits, and the block number occupies the upper bits. | ||
55 | * | ||
56 | * Block addresses are structured the same as page addresses, but with a page | ||
57 | * number of 0. So block number N has address N << log2_ppb. | ||
34 | */ | 58 | */ |
59 | typedef uint32_t nand_block_t; | ||
60 | typedef uint32_t nand_page_t; | ||
35 | 61 | ||
36 | #include <stdint.h> | 62 | typedef struct nand_chip { |
37 | #include <stdbool.h> | 63 | /* Manufacturer and device ID bytes */ |
38 | #include <stddef.h> | 64 | uint8_t mf_id; |
65 | uint8_t dev_id; | ||
39 | 66 | ||
40 | /* Error codes which can be returned by the NAND API */ | 67 | /* Row/column address width */ |
41 | #define NAND_SUCCESS 0 | 68 | uint8_t row_cycles; |
42 | #define NAND_ERR_UNKNOWN_CHIP (-1) | 69 | uint8_t col_cycles; |
43 | #define NAND_ERR_UNALIGNED (-2) | ||
44 | #define NAND_ERR_WRITE_PROTECT (-3) | ||
45 | #define NAND_ERR_CONTROLLER (-4) | ||
46 | #define NAND_ERR_COMMAND (-5) | ||
47 | 70 | ||
48 | /* Chip supports quad I/O for page read/write */ | 71 | /* Base2 logarithm of the number of pages per block */ |
49 | #define NANDCHIP_FLAG_QUAD 0x01 | 72 | unsigned log2_ppb; |
50 | 73 | ||
51 | /* Set/clear the BRWD bit when enabling/disabling write protection */ | 74 | /* Size of a page's main / oob areas, in bytes. */ |
52 | #define NANDCHIP_FLAG_USE_BRWD 0x02 | 75 | unsigned page_size; |
76 | unsigned oob_size; | ||
53 | 77 | ||
54 | typedef struct nand_chip_data { | 78 | /* Total number of blocks in the chip */ |
55 | /* Chip manufacturer / device ID */ | 79 | unsigned nr_blocks; |
56 | uint8_t mf_id; | ||
57 | uint8_t dev_id; | ||
58 | 80 | ||
59 | /* Width of row/column addresses in bytes */ | 81 | /* Clock frequency to use */ |
60 | uint8_t rowaddr_width; | 82 | uint32_t clock_freq; |
61 | uint8_t coladdr_width; | ||
62 | 83 | ||
63 | /* SFC dev conf and clock frequency to use for this device */ | 84 | /* Value of sfc_dev_conf */ |
64 | uint32_t dev_conf; | 85 | uint32_t dev_conf; |
65 | uint32_t clock_freq; | ||
66 | 86 | ||
67 | /* Page size in bytes = 1 << log2_page_size */ | 87 | /* Chip specific flags */ |
68 | uint32_t log2_page_size; | 88 | uint32_t flags; |
89 | } nand_chip; | ||
90 | |||
91 | typedef struct nand_drv { | ||
92 | /* NAND access lock. Needs to be held during any operations. */ | ||
93 | struct mutex mutex; | ||
94 | |||
95 | /* Reference count for open/close operations */ | ||
96 | unsigned refcount; | ||
97 | |||
98 | /* Scratch and page buffers. Both need to be cacheline-aligned and are | ||
99 | * provided externally by the caller prior to nand_open(). | ||
100 | * | ||
101 | * - The scratch buffer is NAND_DRV_SCRATCHSIZE bytes long and is used | ||
102 | * for small data transfers associated with commands. It must not be | ||
103 | * disturbed while any NAND operation is in progress. | ||
104 | * | ||
105 | * - The page buffer is used by certain functions like nand_read_bytes(), | ||
106 | * but it's main purpose is to provide a common temporary buffer for | ||
107 | * driver users to perform I/O with. Must be fpage_size bytes long. | ||
108 | */ | ||
109 | uint8_t* scratch_buf; | ||
110 | uint8_t* page_buf; | ||
111 | |||
112 | /* Pointer to the chip data. */ | ||
113 | const nand_chip* chip; | ||
114 | |||
115 | /* Pages per block = 1 << chip->log2_ppb */ | ||
116 | unsigned ppb; | ||
117 | |||
118 | /* Full page size = chip->page_size + chip->oob_size */ | ||
119 | unsigned fpage_size; | ||
120 | |||
121 | /* Probed mf_id / dev_id for debugging, in case identification fails. */ | ||
122 | uint8_t mf_id; | ||
123 | uint8_t dev_id; | ||
124 | |||
125 | /* SFC commands used for I/O, these are set based on chip data */ | ||
126 | uint32_t cmd_page_read; | ||
127 | uint32_t cmd_read_cache; | ||
128 | uint32_t cmd_program_load; | ||
129 | uint32_t cmd_program_execute; | ||
130 | uint32_t cmd_block_erase; | ||
131 | } nand_drv; | ||
132 | |||
133 | extern const nand_chip supported_nand_chips[]; | ||
134 | extern const size_t nr_supported_nand_chips; | ||
135 | |||
136 | /* Return the static NAND driver instance. | ||
137 | * | ||
138 | * ALL normal Rockbox code should use this instance. The SPL does not | ||
139 | * use it, because it needs to manually place buffers in external RAM. | ||
140 | */ | ||
141 | extern nand_drv* nand_init(void); | ||
142 | |||
143 | static inline void nand_lock(nand_drv* drv) | ||
144 | { | ||
145 | mutex_lock(&drv->mutex); | ||
146 | } | ||
69 | 147 | ||
70 | /* Block size in number of pages = 1 << log2_block_size */ | 148 | static inline void nand_unlock(nand_drv* drv) |
71 | uint32_t log2_block_size; | 149 | { |
150 | mutex_unlock(&drv->mutex); | ||
151 | } | ||
72 | 152 | ||
73 | /* Chip flags */ | 153 | /* Open or close the NAND driver |
74 | uint32_t flags; | 154 | * |
75 | } nand_chip_data; | 155 | * The NAND driver is reference counted, and opening / closing it will |
156 | * increment and decrement the reference count. The hardware is only | ||
157 | * controlled when the reference count rises above or falls to 0, else | ||
158 | * these functions are no-ops which always succeed. | ||
159 | * | ||
160 | * These functions require the lock to be held. | ||
161 | */ | ||
162 | extern int nand_open(nand_drv* drv); | ||
163 | extern void nand_close(nand_drv* drv); | ||
164 | |||
165 | /* Read / program / erase operations. Buffer needs to be cache-aligned for DMA. | ||
166 | * Read and program operate on full page data, ie. including OOB data areas. | ||
167 | * | ||
168 | * NOTE: ECC is not implemented. If it ever needs to be, these functions will | ||
169 | * probably use ECC transparently. All code should be written to expect this. | ||
170 | */ | ||
171 | extern int nand_block_erase(nand_drv* drv, nand_block_t block); | ||
172 | extern int nand_page_program(nand_drv* drv, nand_page_t page, const void* buffer); | ||
173 | extern int nand_page_read(nand_drv* drv, nand_page_t page, void* buffer); | ||
76 | 174 | ||
77 | /* Open or close the NAND driver. The NAND driver takes control of the SFC, | 175 | /* Wrappers to read/write bytes. For simple access to the main data area only. |
78 | * so that driver must be in the closed state before opening the NAND driver. | 176 | * The write address / length must align to a block boundary. Reads do not have |
177 | * any alignment requirement. OOB data is never read, and is written as 0xff. | ||
79 | */ | 178 | */ |
80 | extern int nand_open(void); | 179 | extern int nand_read_bytes(nand_drv* drv, uint32_t byte_addr, uint32_t byte_len, void* buffer); |
81 | extern void nand_close(void); | 180 | extern int nand_write_bytes(nand_drv* drv, uint32_t byte_addr, uint32_t byte_len, const void* buffer); |
82 | |||
83 | /* Identify the NAND chip. This must be done after opening the driver and | ||
84 | * prior to any data access, in order to set the chip parameters. */ | ||
85 | extern int nand_identify(int* mf_id, int* dev_id); | ||
86 | |||
87 | /* Return the chip data for the identified NAND chip. | ||
88 | * Returns NULL if the chip is not identified. */ | ||
89 | const nand_chip_data* nand_get_chip_data(void); | ||
90 | |||
91 | /* Controls the chip's write protect features. The driver also keeps track of | ||
92 | * this flag and refuses to perform write or erase operations unless you have | ||
93 | * enabled writes. Writes should be disabled again when you finish writing. */ | ||
94 | extern int nand_enable_writes(bool en); | ||
95 | |||
96 | /* Reading and writing operates on whole pages at a time. If the address or | ||
97 | * size is not aligned to a multiple of the page size, no data will be read | ||
98 | * or written and an error code is returned. */ | ||
99 | extern int nand_read(uint32_t addr, uint32_t size, uint8_t* buf); | ||
100 | extern int nand_write(uint32_t addr, uint32_t size, const uint8_t* buf); | ||
101 | |||
102 | /* Erase operates on whole blocks. Like the page read/write operations, | ||
103 | * the address and size must be aligned to a multiple of the block size. | ||
104 | * If not, no blocks are erased and an error code is returned. */ | ||
105 | extern int nand_erase(uint32_t addr, uint32_t size); | ||
106 | 181 | ||
107 | #endif /* __NAND_X1000_H__ */ | 182 | #endif /* __NAND_X1000_H__ */ |