• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 /*
16  * simple CFI flash driver for QEMU arm 'virt' machine, with:
17  *
18  * 64M = 1 region * 256 Erase Blocks * 256K(2 banks: 64 pages * 4096B)
19  * 32 bits, Intel command set
20  */
21 
22 #include "user_copy.h"
23 #include "disk.h"
24 #include "cfiflash.h"
25 #include "cfiflash_internal.h"
26 
27 #define BIT_SHIFT8      8
28 #define WORD_ALIGN      4
29 #define BYTE_WORD_SHIFT 2
30 
CfiFlashSec2Bytes(unsigned sector)31 static inline unsigned CfiFlashSec2Bytes(unsigned sector)
32 {
33     return sector << CFIFLASH_SEC_SIZE_BITS;
34 }
35 
CfiFlashPageWordOffset(unsigned wordOffset)36 static inline unsigned CfiFlashPageWordOffset(unsigned wordOffset)
37 {
38     return wordOffset & CFIFLASH_PAGE_WORDS_MASK;
39 }
40 
CfiFlashEraseBlkWordAddr(unsigned wordOffset)41 static inline unsigned CfiFlashEraseBlkWordAddr(unsigned wordOffset)
42 {
43     return wordOffset & CFIFLASH_ERASEBLK_WORDMASK;
44 }
45 
W2B(unsigned words)46 static inline unsigned W2B(unsigned words)
47 {
48     return words << BYTE_WORD_SHIFT;
49 }
50 
B2W(unsigned bytes)51 static inline unsigned B2W(unsigned bytes)
52 {
53     return bytes >> BYTE_WORD_SHIFT;
54 }
55 
CfiFlashQueryQRY(uint8_t * p)56 static inline int CfiFlashQueryQRY(uint8_t *p)
57 {
58     unsigned wordOffset = CFIFLASH_QUERY_QRY;
59 
60     if (p[W2B(wordOffset++)] == 'Q') {
61         if (p[W2B(wordOffset++)] == 'R') {
62             if (p[W2B(wordOffset)] == 'Y') {
63                 return 0;
64             }
65         }
66     }
67     return -1;
68 }
69 
CfiFlashQueryUint8(unsigned wordOffset,uint8_t expect,uint8_t * p)70 static inline int CfiFlashQueryUint8(unsigned wordOffset, uint8_t expect, uint8_t *p)
71 {
72     if (p[W2B(wordOffset)] != expect) {
73         return -1;
74     }
75     return 0;
76 }
77 
CfiFlashQueryUint16(unsigned wordOffset,uint16_t expect,uint8_t * p)78 static inline int CfiFlashQueryUint16(unsigned wordOffset, uint16_t expect, uint8_t *p)
79 {
80     uint16_t v;
81 
82     v = (p[W2B(wordOffset + 1)] << BIT_SHIFT8) + p[W2B(wordOffset)];
83     if (v != expect) {
84         return -1;
85     }
86     return 0;
87 }
88 
CfiFlashIsReady(unsigned wordOffset,uint32_t * p)89 static inline int CfiFlashIsReady(unsigned wordOffset, uint32_t *p)
90 {
91     DSB;
92     p[wordOffset] = CFIFLASH_CMD_READ_STATUS;
93     DSB;
94     return p[wordOffset] & CFIFLASH_STATUS_READY_MASK;
95 }
96 
97 /* all in word(4 bytes) measure */
CfiFlashWriteBuf(unsigned wordOffset,const uint32_t * buffer,size_t words,uint32_t * p)98 static void CfiFlashWriteBuf(unsigned wordOffset, const uint32_t *buffer, size_t words, uint32_t *p)
99 {
100     unsigned i, blkAddr, wordCount;
101 
102     /* first write might not be Page aligned */
103     i = CFIFLASH_PAGE_WORDS - CfiFlashPageWordOffset(wordOffset);
104     wordCount = (i > words) ? words : i;
105 
106     while (words) {
107         /* command buffer-write begin to Erase Block address */
108         blkAddr = CfiFlashEraseBlkWordAddr(wordOffset);
109         p[blkAddr] = CFIFLASH_CMD_BUFWRITE;
110 
111         /* write words count, 0-based */
112         DSB;
113         p[blkAddr] = wordCount - 1;
114 
115         /* program word data to actual address */
116         for (i = 0; i < wordCount; i++, wordOffset++, buffer++) {
117             p[wordOffset] = *buffer;
118         }
119 
120         /* command buffer-write end to Erase Block address */
121         p[blkAddr] = CFIFLASH_CMD_CONFIRM;
122         while (!CfiFlashIsReady(blkAddr, p)) { }
123 
124         words -= wordCount;
125         wordCount = (words >= CFIFLASH_PAGE_WORDS) ? CFIFLASH_PAGE_WORDS : words;
126     }
127 
128     p[0] = CFIFLASH_CMD_CLEAR_STATUS;
129 }
130 
CfiFlashQuery(uint8_t * p)131 static int CfiFlashQuery(uint8_t *p)
132 {
133     uint32_t *base = (uint32_t *)p;
134     base[CFIFLASH_QUERY_BASE] = CFIFLASH_QUERY_CMD;
135 
136     if (CfiFlashQueryQRY(p)) {
137         goto ERR_OUT;
138     }
139 
140     if (CfiFlashQueryUint16(CFIFLASH_QUERY_VENDOR, CFIFLASH_EXPECT_VENDOR, p)) {
141         goto ERR_OUT;
142     }
143 
144     if (CfiFlashQueryUint8(CFIFLASH_QUERY_SIZE, CFIFLASH_ONE_BANK_BITS, p)) {
145         goto ERR_OUT;
146     }
147 
148     if (CfiFlashQueryUint16(CFIFLASH_QUERY_PAGE_BITS, CFIFLASH_EXPECT_PAGE_BITS, p)) {
149         goto ERR_OUT;
150     }
151 
152     if (CfiFlashQueryUint8(CFIFLASH_QUERY_ERASE_REGION, CFIFLASH_EXPECT_ERASE_REGION, p)) {
153         goto ERR_OUT;
154     }
155 
156     if (CfiFlashQueryUint16(CFIFLASH_QUERY_BLOCKS, CFIFLASH_EXPECT_BLOCKS, p)) {
157         goto ERR_OUT;
158     }
159 
160     if (CfiFlashQueryUint16(CFIFLASH_QUERY_BLOCK_SIZE, CFIFLASH_EXPECT_BLOCK_SIZE, p)) {
161         goto ERR_OUT;
162     }
163 
164     base[0] = CFIFLASH_CMD_RESET;
165     return 0;
166 
167 ERR_OUT:
168     dprintf("[%s]not supported CFI flash\n", __FUNCTION__);
169     return -1;
170 }
171 
CfiFlashInit(uint8_t * p)172 int CfiFlashInit(uint8_t *p)
173 {
174     struct MtdDev *slot = GetCfiMtdDev();
175 
176     dprintf("[%s]CFI flash init start ...\n", __FUNCTION__);
177     if (CfiFlashQuery(p)) {
178         return -1;
179     }
180 
181     /* slot 0 used as MTD device for jffs2 rootfs, slot 1 as block device */
182     if (slot->priv == NULL) {
183         slot->priv = p;
184     } else if (*(uint16_t *)&p[BS_SIG55AA] == BS_SIG55AA_VALUE) {
185         int id = los_alloc_diskid_byname(CFI_BLK_DRIVER);
186         (void)los_disk_init(CFI_BLK_DRIVER, GetCfiBlkOps(), p, id, NULL);
187     } else {
188         return 0;
189     }
190 
191     dprintf("[%s]CFI flash init end ...\n", __FUNCTION__);
192     return 0;
193 }
194 
CfiBlkOpen(struct Vnode * vnode)195 int CfiBlkOpen(struct Vnode *vnode)
196 {
197     return 0;
198 }
199 
CfiBlkClose(struct Vnode * vnode)200 int CfiBlkClose(struct Vnode *vnode)
201 {
202     return 0;
203 }
204 
CfiPreRead(char * buffer,unsigned bytes,char ** newbuf)205 static ssize_t CfiPreRead(char *buffer, unsigned bytes, char **newbuf)
206 {
207     if (LOS_IsUserAddressRange((VADDR_T)buffer, bytes)) {
208         *newbuf = LOS_MemAlloc(m_aucSysMem0, bytes);
209         if (*newbuf == NULL) {
210             dprintf("[%s]fatal memory allocation error\n", __FUNCTION__);
211             return -ENOMEM;
212         }
213     } else if ((VADDR_T)buffer + bytes < (VADDR_T)buffer) {
214         dprintf("[%s]invalid argument: buffer=%#x, size=%#x\n", __FUNCTION__, buffer, bytes);
215         return -EFAULT;
216     } else {
217         *newbuf = buffer;
218     }
219     return 0;
220 }
221 
CfiPostRead(char * buffer,char * newbuf,unsigned bytes,ssize_t ret)222 static ssize_t CfiPostRead(char *buffer, char *newbuf, unsigned bytes, ssize_t ret)
223 {
224     if (newbuf != buffer) {
225         if (LOS_ArchCopyToUser(buffer, newbuf, bytes) != 0) {
226             dprintf("[%s]LOS_ArchCopyToUser error\n", __FUNCTION__);
227             ret = -EFAULT;
228         }
229 
230         if (LOS_MemFree(m_aucSysMem0, newbuf) != 0) {
231             dprintf("[%s]LOS_MemFree error\n", __FUNCTION__);
232             ret = -EFAULT;
233         }
234     }
235     return ret;
236 }
237 
CfiBlkRead(struct Vnode * vnode,unsigned char * buffer,unsigned long long startSector,unsigned int nSectors)238 ssize_t CfiBlkRead(struct Vnode *vnode, unsigned char *buffer,
239                    unsigned long long startSector, unsigned int nSectors)
240 {
241     unsigned int i, wordOffset, bytes;
242     uint32_t *p;
243     uint32_t *base = ((struct drv_data*)(vnode->data))->priv;
244     ssize_t ret;
245 
246     bytes = CfiFlashSec2Bytes(nSectors);
247     wordOffset = B2W(CfiFlashSec2Bytes(startSector));
248 
249     if ((ret = CfiPreRead((char*)buffer, bytes, (char**)&p))) {
250         return ret;
251     }
252 
253     for (i = 0; i < B2W(bytes); i++) {
254         p[i] = base[wordOffset + i];
255     }
256     ret = nSectors;
257 
258     return CfiPostRead((char*)buffer, (char*)p, bytes, ret);
259 }
260 
CfiPreWrite(const char * buffer,unsigned bytes,char ** newbuf)261 static ssize_t CfiPreWrite(const char *buffer, unsigned bytes, char **newbuf)
262 {
263     if (LOS_IsUserAddressRange((VADDR_T)buffer, bytes)) {
264         *newbuf = LOS_MemAlloc(m_aucSysMem0, bytes);
265         if (*newbuf == NULL) {
266             dprintf("[%s]fatal memory allocation error\n", __FUNCTION__);
267             return -ENOMEM;
268         }
269 
270         if (LOS_ArchCopyFromUser(*newbuf, buffer, bytes)) {
271             dprintf("[%s]LOS_ArchCopyFromUser error\n", __FUNCTION__);
272             LOS_MemFree(m_aucSysMem0, *newbuf);
273             return -EFAULT;
274         }
275     } else if ((VADDR_T)buffer + bytes < (VADDR_T)buffer) {
276         dprintf("[%s]invalid argument\n", __FUNCTION__);
277         return -EFAULT;
278     } else {
279         *newbuf = (char*)buffer;
280     }
281     return 0;
282 }
283 
CfiPostWrite(const char * buffer,char * newbuf,ssize_t ret)284 static ssize_t CfiPostWrite(const char *buffer, char *newbuf, ssize_t ret)
285 {
286     if (newbuf != buffer) {
287         if (LOS_MemFree(m_aucSysMem0, newbuf) != 0) {
288             dprintf("[%s]LOS_MemFree error\n", __FUNCTION__);
289             return -EFAULT;
290         }
291     }
292     return ret;
293 }
294 
CfiBlkWrite(struct Vnode * vnode,const unsigned char * buffer,unsigned long long startSector,unsigned int nSectors)295 ssize_t CfiBlkWrite(struct Vnode *vnode, const unsigned char *buffer,
296                     unsigned long long startSector, unsigned int nSectors)
297 {
298     unsigned int wordOffset, bytes;
299     unsigned char *p;
300     ssize_t ret;
301 
302     bytes = CfiFlashSec2Bytes(nSectors);
303     wordOffset = B2W(CfiFlashSec2Bytes(startSector));
304 
305     if ((ret = CfiPreWrite((const char*)buffer, bytes, (char**)&p))) {
306         return ret;
307     }
308 
309     CfiFlashWriteBuf(wordOffset, (uint32_t *)p, B2W(bytes), ((struct drv_data*)(vnode->data))->priv);
310     ret = nSectors;
311 
312     return CfiPostWrite((const char*)buffer, (char*)p, ret);
313 }
314 
CfiBlkGeometry(struct Vnode * vnode,struct geometry * geometry)315 int CfiBlkGeometry(struct Vnode *vnode, struct geometry *geometry)
316 {
317     geometry->geo_available = TRUE,
318     geometry->geo_mediachanged = FALSE;
319     geometry->geo_writeenabled = TRUE;
320     geometry->geo_nsectors = CFIFLASH_SECTORS;
321     geometry->geo_sectorsize = CFIFLASH_SEC_SIZE;
322 
323     return 0;
324 }
325 
CfiMtdErase(struct MtdDev * mtd,UINT64 start,UINT64 bytes,UINT64 * failAddr)326 int CfiMtdErase(struct MtdDev *mtd, UINT64 start, UINT64 bytes, UINT64 *failAddr)
327 {
328     uint32_t blkAddr, count, i;
329     uint32_t *p = mtd->priv;
330 
331     blkAddr = CfiFlashEraseBlkWordAddr(B2W(start));
332     count = (CfiFlashEraseBlkWordAddr(B2W(start + bytes - 1)) - blkAddr) / CFIFLASH_ERASEBLK_WORDS + 1;
333 
334     for (i = 0; i < count; i++) {
335         p[blkAddr] = CFIFLASH_CMD_ERASE;
336         DSB;
337         p[blkAddr] = CFIFLASH_CMD_CONFIRM;
338         while (!CfiFlashIsReady(blkAddr, p)) { }
339 
340         blkAddr += CFIFLASH_ERASEBLK_WORDS;
341     }
342 
343     p[0] = CFIFLASH_CMD_CLEAR_STATUS;
344     return 0;
345 }
346 
CfiMtdRead(struct MtdDev * mtd,UINT64 start,UINT64 bytes,const char * buf)347 int CfiMtdRead(struct MtdDev *mtd, UINT64 start, UINT64 bytes, const char *buf)
348 {
349     UINT64 i;
350     char *p;
351     ssize_t ret;
352     uint8_t *base = mtd->priv;
353 
354     if ((ret = CfiPreRead((char*)buf, bytes, &p))) {
355         return ret;
356     }
357 
358     for (i = 0; i < bytes; i++) {
359         p[i] = base[start + i];
360     }
361     ret = (int)bytes;
362 
363     return CfiPostRead((char*)buf, p, bytes, ret);
364 }
365 
CfiMtdWrite(struct MtdDev * mtd,UINT64 start,UINT64 bytes,const char * buf)366 int CfiMtdWrite(struct MtdDev *mtd, UINT64 start, UINT64 bytes, const char *buf)
367 {
368     char *p;
369     ssize_t ret;
370 
371     if (!IS_ALIGNED(start, WORD_ALIGN) || !IS_ALIGNED(bytes, WORD_ALIGN)) {
372         dprintf("[%s]not aligned with 4B: start=%#0llx, bytes=%#0llx\n", __FUNCTION__, start, bytes);
373         return -EINVAL;
374     }
375 
376     if ((ret = CfiPreWrite(buf, bytes, &p))) {
377         return ret;
378     }
379 
380     CfiFlashWriteBuf((int)B2W(start), (uint32_t *)p, (size_t)B2W(bytes), mtd->priv);
381     ret = (int)bytes;
382 
383     return CfiPostWrite(buf, p, ret);
384 }
385