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