1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 *
4 * HDF is dual licensed: you can use it either under the terms of
5 * the GPL, or the BSD license, at your option.
6 * See the LICENSE file in the root of this repository for complete details.
7 */
8
9 #ifndef MTD_CORE_H
10 #define MTD_CORE_H
11
12 #include "los_vm_phys.h"
13
14 #include "hdf_base.h"
15 #include "osal_mutex.h"
16 #include "platform_core.h"
17
18 #define MTD_FLASH_ID_LEN_MAX 8
19 #define MTD_DEVICE_NUM_MAX 3
20
21 // if you want to debug mtd, please define macro MTD_DEBUG, for example "#define MTD_DEBUG"
22
23 struct MtdDevice;
24 struct MtdDeviceMethod;
25
26 /**
27 * @brief Enumerates the types of mtd devices.
28 *
29 */
30 enum MtdDevType {
31 MTD_TYPE_NOR,
32 MTD_TYPE_NAND,
33 MTD_TYPE_SPI_NOR,
34 MTD_TYPE_SPI_NAND,
35 MTD_TYPE_MAX,
36 };
37
38 /**
39 * @brief Enumerates the types of mtd message.
40 *
41 */
42 enum MtdMsgType {
43 MTD_MSG_TYPE_WRITE,
44 MTD_MSG_TYPE_READ,
45 MTD_MSG_TYPE_ERASE,
46 };
47
48 /**
49 * @Defines the mtd request message used during request.
50 *
51 * This struct describes a custom access request typed by MtdMsgType
52 *
53 */
54 struct MtdMsg {
55 /** Type of the mtd message */
56 enum MtdMsgType type;
57 /** Start address of the mtd device to access */
58 off_t addr;
59 /** Indicates the failed address if request failed */
60 off_t faddr;
61 /** Pointer to the buffer for storing request data */
62 uint8_t *buf;
63 /** Length of the data */
64 size_t len;
65 /** Indicates whether request with oob data */
66 bool withOob;
67 /** Indicates whether skip on bad block */
68 bool skipBad;
69 };
70
71 /**
72 * @Defines the mtd page struct used during page transfer.
73 *
74 * This struct describes a page transfer request typed by MtdMsgType
75 *
76 */
77 struct MtdPage {
78 /** Page transfer type */
79 enum MtdMsgType type;
80 /** Start address of the mtd device to transfer from */
81 off_t addr;
82 /** Indicates the failed address if transfer failed */
83 off_t failAddr;
84 /** Pointer to the data buffer */
85 uint8_t *dataBuf;
86 /** Length of the data */
87 size_t dataLen;
88 /** Pointer to the oob data buffer */
89 uint8_t *oobBuf;
90 /** Length of the oob data */
91 size_t oobLen;
92 };
93
94 /**
95 * @Defines the callback method set of a mtd device.
96 *
97 * The methods defined in this struct expected to be implemented by drivers
98 *
99 */
100 struct MtdDeviceMethod {
101 int32_t (*read)(struct MtdDevice *mtdDevice, off_t from, size_t len, uint8_t *buf);
102 int32_t (*write)(struct MtdDevice *mtdDevice, off_t to, size_t len, const uint8_t *buf);
103 int32_t (*erase)(struct MtdDevice *mtdDevice, off_t addr, size_t len, off_t *faddr);
104 int32_t (*pageTransfer)(struct MtdDevice *mtdDevice, struct MtdPage *mtdPage);
105 bool (*isBadBlock)(struct MtdDevice *mtdDevice, off_t addr);
106 int32_t (*markBadBlock)(struct MtdDevice *mtdDevice, off_t addr);
107 void (*dump)(struct MtdDevice *mtdDevice);
108 int32_t (*lock)(struct MtdDevice *mtdDevice);
109 void (*unlock)(struct MtdDevice *mtdDevice);
110 };
111
112 /**
113 * @Defines the structure used to identify a physical mtd chip.
114 *
115 */
116 struct MtdDevice {
117 /** The parent device */
118 struct PlatformDevice device;
119 /** Number of the mtd device */
120 int16_t index;
121 /** Name of the mtd device */
122 const char *name;
123 /** Chip name of the mtd device */
124 const char *chipName;
125 /** Type of the mtd device */
126 enum MtdDevType type;
127 union {
128 /** Vendor id of the mtd device */
129 uint8_t id[MTD_FLASH_ID_LEN_MAX];
130 struct {
131 uint8_t mfrId; // id[0]: Manufacture ID
132 uint8_t devId; // id[0]: Device ID
133 };
134 };
135 /** Length of the vendor id */
136 uint16_t idLen;
137 /** Length of the vendor id */
138 size_t capacity;
139 /** Erase size of the mtd device */
140 size_t eraseSize;
141 /** Write size of the mtd device */
142 size_t writeSize;
143 /** Read size of the mtd device */
144 size_t readSize;
145 /** Oob size of the mtd device */
146 size_t oobSize;
147 /** Write size shift bits of the mtd device */
148 unsigned int writeSizeShift;
149 /** Mutex lock for accessing protection */
150 struct OsalMutex lock;
151 /** The callback method set to access the device */
152 struct MtdDeviceMethod *ops;
153 /** Os specific data */
154 void *osData;
155 /** Flash memory controller specific data */
156 void *cntlr;
157 /** Private data of the mtd device */
158 void *priv;
159 };
160
161 /**
162 * @brief Get the manager of mtd
163 *
164 * @return Returns the pointer to the manager if success;
165 * returns NULL otherwise.
166 */
167 struct PlatformManager *MtdManagerGet(void);
168
169 /**
170 * @brief Add a mtd device.
171 *
172 * do not call in irq context cause it may sleep
173 *
174 * @param mtdDevice Indicates the pointer to the mtd device.
175 *
176 * @return Returns 0 if add successfully; returns a negative value otherwise.
177 */
178 int32_t MtdDeviceAdd(struct MtdDevice *mtdDevice);
179
180 /**
181 * @brief Delete a mtd device.
182 *
183 * do not call in irq context cause it may sleep
184 *
185 * @param mtdDevice Indicates the pointer to the mtd device.
186 */
187 void MtdDeviceDel(struct MtdDevice *mtdDevice);
188
189 /**
190 * @brief Increase reference count for a mtd device.
191 *
192 * @param mtdDevice Indicates the pointer to the mtd device.
193 *
194 * @return Returns the pointer to the mtd device on success; returns NULL otherwise.
195 */
MtdDeviceGet(struct MtdDevice * mtdDevice)196 static inline struct MtdDevice *MtdDeviceGet(struct MtdDevice *mtdDevice)
197 {
198 if (mtdDevice != NULL && PlatformDeviceGet(&mtdDevice->device) == HDF_SUCCESS) {
199 return mtdDevice;
200 }
201 return NULL;
202 }
203
204 /**
205 * @brief Increase reference count for a mtd device by number.
206 *
207 * @param mtdDevice Indicates the pointer to the mtd device.
208 *
209 * @return Returns the pointer to the mtd device on success; returns NULL otherwise.
210 */
MtdDeviceGetByNum(int16_t num)211 static inline struct MtdDevice *MtdDeviceGetByNum(int16_t num)
212 {
213 struct PlatformDevice *device = PlatformManagerGetDeviceByNumber(MtdManagerGet(), num);
214
215 if (device != NULL) {
216 return CONTAINER_OF(device, struct MtdDevice, device);
217 }
218 return NULL;
219 }
220
221 /**
222 * @brief Decrease reference count for a mtd device.
223 *
224 * @param mtdDevice Indicates the pointer to the mtd device.
225 */
MtdDevicePut(struct MtdDevice * mtdDevice)226 static inline void MtdDevicePut(struct MtdDevice *mtdDevice)
227 {
228 if (mtdDevice != NULL) {
229 PlatformDevicePut(&mtdDevice->device);
230 }
231 }
232
233 /**
234 * @brief Lock the mtd device exclusivly.
235 *
236 * do not call in irq context cause it may sleep
237 *
238 * @param mtdDevice Indicates the pointer to the mtd device.
239 *
240 * @return Returns 0 on success; returns a negative value otherwise.
241 */
242 int32_t MtdDeviceLock(struct MtdDevice *mtdDevice);
243
244 /**
245 * @brief Unlock the mtd device.
246 *
247 * do not call in irq context cause it may sleep
248 *
249 * @param mtdDevice Indicates the pointer to the mtd device.
250 */
251 void MtdDeviceUnlock(struct MtdDevice *mtdDevice);
252
253 /**
254 * @brief Reads data of a specified size from a mtd device.
255 *
256 * do not call in irq context cause it may sleep
257 *
258 * @param mtdDevice Indicates the pointer to the mtd device.
259 * @param from Indicates the start address to read from.
260 * @param len Indicates the size of the data to read.
261 * @param buf Indicates the pointer to the buffer for receiving the data.
262 *
263 * @return Returns the size of the data read on success; returns a negative value otherwise.
264 */
265 ssize_t MtdDeviceRead(struct MtdDevice *mtdDevice, off_t from, size_t len, uint8_t *buf);
266
267 /**
268 * @brief Writes data of a specified size to a mtd device.
269 *
270 * do not call in irq context cause it may sleep
271 *
272 * @param mtdDevice Indicates the pointer to the mtd device.
273 * @param to Indicates the start address to write to.
274 * @param len Indicates the size of the data to write.
275 * @param buf Indicates the pointer to the buffer which provide the data.
276 *
277 * @return Returns the size of the data written on success; returns a negative value otherwise.
278 */
279 ssize_t MtdDeviceWrite(struct MtdDevice *mtdDevice, off_t to, size_t len, const uint8_t *buf);
280
281 /**
282 * @brief Erases data of a specified size to a mtd device.
283 *
284 * do not call in irq context cause it may sleep
285 *
286 * @param mtdDevice Indicates the pointer to the mtd device.
287 * @param from Indicates the start address to erase from.
288 * @param len Indicates the size of the data to erase.
289 * @param faddr Indicates the pointer for receiving the address when erasing failed.
290 *
291 * @return Returns the size of the data erased on success; returns a negative value otherwise.
292 */
293 ssize_t MtdDeviceErase(struct MtdDevice *mtdDevice, off_t from, size_t len, off_t *faddr);
294
295 /**
296 * @brief Reads data of a specified size from a mtd device including oob data.
297 *
298 * It is similar to MtdDeviceRead but read oob data together.
299 *
300 * @param mtdDevice Indicates the pointer to the mtd device.
301 * @param from Indicates the start address to read from.
302 * @param len Indicates the size of the data, including oob, to read.
303 * @param buf Indicates the pointer to the buffer for receiving the data, including oob data.
304 *
305 * @return Returns the size of the data read on success; returns a negative value otherwise.
306 */
307 ssize_t MtdDeviceReadWithOob(struct MtdDevice *mtdDevice, off_t from, size_t len, uint8_t *buf);
308
309 /**
310 * @brief Writes data of a specified size to a mtd device including oob data.
311 *
312 * It is similar to MtdDeviceWrite but write oob data together.
313 *
314 * @param mtdDevice Indicates the pointer to the mtd device.
315 * @param to Indicates the start address to write to.
316 * @param len Indicates the size of the data, including oob, to .
317 * @param buf Indicates the pointer to the buffer which provide the data including oob.
318 *
319 * @return Returns the size of the data read on success; returns a negative value otherwise.
320 */
321 ssize_t MtdDeviceWriteWithOob(struct MtdDevice *mtdDevice, off_t to, size_t len, const uint8_t *buf);
322
323 /**
324 * @brief Judge whether the block where the specified address is located is a bad block
325 *
326 * @param mtdDevice Indicates the pointer to the mtd device.
327 * @param addr Indicates the address to judge, which is not necessary to align by block size.
328 *
329 * @return Returns true is the specified address falls into a bad block; returns false otherwise.
330 */
331 bool MtdDeviceIsBadBlock(struct MtdDevice *mtdDevice, off_t addr);
332
333 /**
334 * @brief Mark the block where the specified address is located as a bad block
335 *
336 * @param mtdDevice Indicates the pointer to the mtd device.
337 * @param addr Indicates the address to mark, which is not necessary to align by block size.
338 *
339 * @return Returns 0 on success; returns a negative value otherwise.
340 */
341 int32_t MtdDeviceMarkBadBlock(struct MtdDevice *mtdDevice, off_t addr);
342
343
344 /***************************** Other Utils *******************************************/
345
346 /**
347 * @brief A debugging macro which an dump all the attributes of a mtd device
348 *
349 */
350 #define MTD_DEVICE_DUMP(mtd) \
351 do { \
352 uint16_t i; \
353 HDF_LOGI("%s: name = %s(%s), type = %d", __func__, (mtd)->name, (mtd)->chipName, (mtd)->type); \
354 for (i = 0; i < (mtd)->idLen; i++) { \
355 HDF_LOGI("%s: id[%u] = 0x%x", __func__, i, (mtd)->id[i]); \
356 } \
357 HDF_LOGI("%s: capacity: %zu", __func__, (mtd)->capacity); \
358 HDF_LOGI("%s: eraseSize: %zu", __func__, (mtd)->eraseSize); \
359 HDF_LOGI("%s: writeSize: %zu", __func__, (mtd)->writeSize); \
360 HDF_LOGI("%s: readSize: %zu", __func__, (mtd)->readSize); \
361 HDF_LOGI("%s: oobSize: %zu", __func__, (mtd)->oobSize); \
362 } while (0)
363
364 /**
365 * @brief Judge whether the specified address is aligned by page size
366 *
367 */
MtdDeviceIsPageAligned(struct MtdDevice * mtdDevice,off_t addr)368 static inline bool MtdDeviceIsPageAligned(struct MtdDevice *mtdDevice, off_t addr)
369 {
370 return (((uint64_t)addr & (mtdDevice->writeSize - 1)) == 0);
371 }
372
373 /**
374 * @brief Transfer the specified address to page number
375 *
376 */
MtdDeviceAddrToPage(struct MtdDevice * mtdDevice,off_t addr)377 static inline size_t MtdDeviceAddrToPage(struct MtdDevice *mtdDevice, off_t addr)
378 {
379 return (size_t)((uint64_t)addr >> mtdDevice->writeSizeShift);
380 }
381
382 /**
383 * @brief Flush the cache for dma transfer
384 *
385 */
MtdDmaCacheClean(void * addr,size_t size)386 static inline void MtdDmaCacheClean(void *addr, size_t size)
387 {
388 uintptr_t start = (uintptr_t)addr & ~(CACHE_ALIGNED_SIZE - 1);
389 uintptr_t end = (uintptr_t)addr + (uintptr_t)size;
390
391 end = ALIGN(end, CACHE_ALIGNED_SIZE);
392 DCacheFlushRange(start, end);
393 return;
394 }
395
396 /**
397 * @brief Invalid the cache for dma transfer
398 *
399 */
MtdDmaCacheInv(void * addr,size_t size)400 static inline void MtdDmaCacheInv(void *addr, size_t size)
401 {
402 uintptr_t start = (uintptr_t)addr & ~(CACHE_ALIGNED_SIZE - 1);
403 uintptr_t end = (uintptr_t)addr + (uintptr_t)size;
404
405 end = ALIGN(end, CACHE_ALIGNED_SIZE);
406 DCacheInvRange(start, end);
407 return;
408 }
409
410 /**
411 * @brief Find the first bit set in word
412 *
413 * @return Returns the position of first bit set; returns 0 if all zero.
414 */
415 int MtdFfs(int x);
416
417 #endif /* MTD_CORE_H */
418