diff options
Diffstat (limited to 'firmware/target/mips/ingenic_x1000/nand-x1000.h')
-rw-r--r-- | firmware/target/mips/ingenic_x1000/nand-x1000.h | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/firmware/target/mips/ingenic_x1000/nand-x1000.h b/firmware/target/mips/ingenic_x1000/nand-x1000.h new file mode 100644 index 0000000000..865feb38c5 --- /dev/null +++ b/firmware/target/mips/ingenic_x1000/nand-x1000.h | |||
@@ -0,0 +1,213 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2021 Aidan MacDonald | ||
11 | * | ||
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. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #ifndef __NAND_X1000_H__ | ||
23 | #define __NAND_X1000_H__ | ||
24 | |||
25 | /* NOTE: this is a very minimal API designed only to support a bootloader. | ||
26 | * Not suitable for general data storage. It doesn't have proper support for | ||
27 | * partial page writes, access to spare area, etc, which are all necessary | ||
28 | * for an effective flash translation layer. | ||
29 | */ | ||
30 | |||
31 | #include <stdint.h> | ||
32 | #include <stdbool.h> | ||
33 | #include <stddef.h> | ||
34 | |||
35 | /* Chip supports quad I/O for page read/write */ | ||
36 | #define NANDCHIP_FLAG_QUAD 0x01 | ||
37 | |||
38 | /* Set/clear the BRWD bit when enabling/disabling write protection */ | ||
39 | #define NANDCHIP_FLAG_USE_BRWD 0x02 | ||
40 | |||
41 | typedef struct nand_drv nand_drv; | ||
42 | |||
43 | /* Defines some static information about a NAND chip */ | ||
44 | typedef struct nand_chip_data { | ||
45 | const char* name; /* Name for debugging purposes */ | ||
46 | uint8_t mf_id; /* Manufacturer ID */ | ||
47 | uint8_t dev_id; /* Device ID */ | ||
48 | uint8_t rowaddr_width; /* Number of bytes in row addresses */ | ||
49 | uint8_t coladdr_width; /* Number of bytes in column addresses */ | ||
50 | uint32_t dev_conf; /* Value to write to SFC_DEV_CONF register */ | ||
51 | uint32_t clock_freq; /* Frequency to switch to after identification */ | ||
52 | uint32_t block_size; /* Number of pages per eraseblock */ | ||
53 | uint32_t page_size; /* Number of data bytes per page */ | ||
54 | uint32_t spare_size; /* Number of spare bytes per page */ | ||
55 | int flags; /* Various flags */ | ||
56 | } nand_chip_data; | ||
57 | |||
58 | /* Defines high-level operations used to implement the public API. | ||
59 | * Chips may need to override operations if the default ones aren't suitable. | ||
60 | * | ||
61 | * Negative return codes return an error, while zero or positive codes are | ||
62 | * considered successful. This allows a function to return meaningful data, | ||
63 | * if applicable. | ||
64 | */ | ||
65 | typedef struct nand_chip_ops { | ||
66 | /* Called once after identifying the chip */ | ||
67 | int(*open)(nand_drv* d); | ||
68 | |||
69 | /* Called once when the driver is closed */ | ||
70 | void(*close)(nand_drv* d); | ||
71 | |||
72 | /* Read or write a complete page including both main and spare areas. */ | ||
73 | int(*read_page)(nand_drv* d, uint32_t rowaddr, unsigned char* buf); | ||
74 | int(*write_page)(nand_drv* d, uint32_t rowaddr, const unsigned char* buf); | ||
75 | |||
76 | /* Erase a block. */ | ||
77 | int(*erase_block)(nand_drv* d, uint32_t blockaddr); | ||
78 | |||
79 | /* Enable or disable the chip's write protection. */ | ||
80 | int(*set_wp_enable)(nand_drv* d, bool en); | ||
81 | |||
82 | /* Perform error correction and detection on a raw page (main + spare). | ||
83 | * Return the number of errors detected and corrected, or a negative value | ||
84 | * if errors were detected but could not be corrected. | ||
85 | */ | ||
86 | int(*ecc_read)(nand_drv* d, unsigned char* buf); | ||
87 | |||
88 | /* Generate ECC data for a page. The buffer main area is already filled | ||
89 | * and this function should write ECC data into the spare area. | ||
90 | */ | ||
91 | void(*ecc_write)(nand_drv* d, unsigned char* buf); | ||
92 | } nand_chip_ops; | ||
93 | |||
94 | /* Struct used to list all supported NAND chips in an array */ | ||
95 | typedef struct nand_chip_desc { | ||
96 | const nand_chip_data* data; | ||
97 | const nand_chip_ops* ops; | ||
98 | } nand_chip_desc; | ||
99 | |||
100 | /* NAND driver structure. It can be accessed by chip ops, but they must not | ||
101 | * modify any fields except for "auxbuf", which is a small buffer that can | ||
102 | * be used for commands that need to read/write small amounts of data: often | ||
103 | * needed for polling status, etc. | ||
104 | */ | ||
105 | struct nand_drv { | ||
106 | const nand_chip_ops* chip_ops; | ||
107 | const nand_chip_data* chip_data; | ||
108 | unsigned char* pagebuf; | ||
109 | unsigned char* auxbuf; | ||
110 | uint32_t raw_page_size; | ||
111 | int flags; | ||
112 | }; | ||
113 | |||
114 | /* Note: sfc_init() must be called prior to nand_open() */ | ||
115 | extern int nand_open(void); | ||
116 | extern void nand_close(void); | ||
117 | |||
118 | /* Controls device-side write protection registers as well as software lock. | ||
119 | * Erase and program operations will fail unless you first enable writes. | ||
120 | */ | ||
121 | extern int nand_enable_writes(bool en); | ||
122 | |||
123 | /* Byte-based NAND operations */ | ||
124 | extern int nand_read_bytes(uint32_t byteaddr, int count, void* buf); | ||
125 | extern int nand_write_bytes(uint32_t byteaddr, int count, const void* buf); | ||
126 | extern int nand_erase_block(uint32_t byteaddr); | ||
127 | |||
128 | /* NAND command numbers */ | ||
129 | #define NAND_CMD_READ_ID 0x9f | ||
130 | #define NAND_CMD_WRITE_ENABLE 0x06 | ||
131 | #define NAND_CMD_GET_FEATURE 0x0f | ||
132 | #define NAND_CMD_SET_FEATURE 0x1f | ||
133 | #define NAND_CMD_PAGE_READ_TO_CACHE 0x13 | ||
134 | #define NAND_CMD_READ_FROM_CACHE 0x0b | ||
135 | #define NAND_CMD_READ_FROM_CACHEx4 0x6b | ||
136 | #define NAND_CMD_PROGRAM_LOAD 0x02 | ||
137 | #define NAND_CMD_PROGRAM_LOADx4 0x32 | ||
138 | #define NAND_CMD_PROGRAM_EXECUTE 0x10 | ||
139 | #define NAND_CMD_BLOCK_ERASE 0xd8 | ||
140 | |||
141 | /* NAND device register addresses for GET_FEATURE / SET_FEATURE */ | ||
142 | #define NAND_FREG_PROTECTION 0xa0 | ||
143 | #define NAND_FREG_FEATURE 0xb0 | ||
144 | #define NAND_FREG_STATUS 0xc0 | ||
145 | |||
146 | /* Protection register bits */ | ||
147 | #define NAND_FREG_PROTECTION_BRWD 0x80 | ||
148 | #define NAND_FREG_PROTECTION_BP2 0x20 | ||
149 | #define NAND_FREG_PROTECTION_BP1 0x10 | ||
150 | #define NAND_FREG_PROTECTION_BP0 0x80 | ||
151 | /* Mask of BP bits 0-2 */ | ||
152 | #define NAND_FREG_PROTECTION_ALLBP (0x38) | ||
153 | |||
154 | /* Feature register bits */ | ||
155 | #define NAND_FREG_FEATURE_QE 0x01 | ||
156 | |||
157 | /* Status register bits */ | ||
158 | #define NAND_FREG_STATUS_OIP 0x01 | ||
159 | #define NAND_FREG_STATUS_WEL 0x02 | ||
160 | #define NAND_FREG_STATUS_E_FAIL 0x04 | ||
161 | #define NAND_FREG_STATUS_P_FAIL 0x08 | ||
162 | |||
163 | /* Standard implementations for low-level NAND commands. I'm not aware of any | ||
164 | * actual standard governing these, but it seems many vendors follow the same | ||
165 | * command numbering, status bits, and behavior so these implementations should | ||
166 | * work across a wide variety of chips. | ||
167 | * | ||
168 | * If adding a new NAND chip which only has a minor deviation from these | ||
169 | * standard implementations, consider adding a flag and modifying these | ||
170 | * functions to change their behavior based on the flag, instead of writing | ||
171 | * a whole new implementation. | ||
172 | * | ||
173 | * None of these functions are directly called by the high-level driver code, | ||
174 | * except for nandcmd_std_read_id(). They can be used to implement higher-level | ||
175 | * functions in a device's "nand_chip_ops". | ||
176 | */ | ||
177 | extern int nandcmd_read_id(nand_drv* d); | ||
178 | extern int nandcmd_write_enable(nand_drv* d); | ||
179 | extern int nandcmd_get_feature(nand_drv* d, int reg); | ||
180 | extern int nandcmd_set_feature(nand_drv* d, int reg, int val); | ||
181 | extern int nandcmd_page_read_to_cache(nand_drv* d, uint32_t rowaddr); | ||
182 | extern int nandcmd_read_from_cache(nand_drv* d, unsigned char* buf); | ||
183 | extern int nandcmd_program_load(nand_drv* d, const unsigned char* buf); | ||
184 | extern int nandcmd_program_execute(nand_drv* d, uint32_t rowaddr); | ||
185 | extern int nandcmd_block_erase(nand_drv* d, uint32_t blockaddr); | ||
186 | |||
187 | /* Table filled with all the standard operations for chips which don't | ||
188 | * need to override any operations. | ||
189 | */ | ||
190 | extern const nand_chip_ops nand_chip_ops_std; | ||
191 | |||
192 | /* Standard NAND chip ops based on the standard "nandcmd" functions. | ||
193 | * | ||
194 | * Same advice applies here as there: if it's possible to support minor | ||
195 | * chip variations with a flag, modify these functions to do so. | ||
196 | */ | ||
197 | extern int nandop_std_open(nand_drv* d); | ||
198 | extern void nandop_std_close(nand_drv* d); | ||
199 | extern int nandop_std_read_page(nand_drv* d, uint32_t rowaddr, unsigned char* buf); | ||
200 | extern int nandop_std_write_page(nand_drv* d, uint32_t rowaddr, const unsigned char* buf); | ||
201 | extern int nandop_std_erase_block(nand_drv* d, uint32_t blockaddr); | ||
202 | extern int nandop_std_set_wp_enable(nand_drv* d, bool en); | ||
203 | |||
204 | /* The default ECC implementation is a no-op: reads always succeed without | ||
205 | * reporting errors and writes will fill the spare area with '0xff' bytes. | ||
206 | * | ||
207 | * For chips that support internal ECC, this often works because the chip will | ||
208 | * ignore writes to the ECC areas. | ||
209 | */ | ||
210 | extern int nandop_ecc_none_read(nand_drv* d, unsigned char* buf); | ||
211 | extern void nandop_ecc_none_write(nand_drv* d, unsigned char* buf); | ||
212 | |||
213 | #endif /* __NAND_X1000_H__ */ | ||