• 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 riscv 'virt' machine, with:
17  *
18  * 32M = 1 region * 128 Erase Blocks * 256K(2 banks: 64 pages * 4096B)
19  * 32 bits, Intel command set
20  */
21 
22 #include "stdint.h"
23 #include "stddef.h"
24 #include "los_arch_context.h"
25 #include "los_debug.h"
26 #include "los_compiler.h"
27 #include "cfiflash.h"
28 #include "cfiflash_internal.h"
29 #include "ff_gen_drv.h"
30 #include "diskio.h"
31 
32 #define BIT_SHIFT8      8
33 #define BYTE_WORD_SHIFT 2
34 
35 static uint32_t g_cfiDrvBase[CFIFLASH_MAX_NUM];
36 
GetCfiDrvPriv(BYTE pdrv)37 static uint8_t *GetCfiDrvPriv(BYTE pdrv)
38 {
39     uint8_t *ret = NULL;
40     if (pdrv >= 0 && pdrv < CFIFLASH_MAX_NUM) {
41         ret = (uint8_t *)g_cfiDrvBase[pdrv];
42     }
43 
44     if (ret == NULL) {
45         PRINT_ERR("Get CfiFlash driver base failed!\n");
46     }
47 
48     return ret;
49 }
50 
SetCfiDrvPriv(BYTE pdrv,uint32_t priv)51 static DRESULT SetCfiDrvPriv(BYTE pdrv, uint32_t priv)
52 {
53     g_cfiDrvBase[pdrv] = priv;
54     return RES_OK;
55 }
56 
CfiFlashSec2Bytes(unsigned sector)57 static inline unsigned CfiFlashSec2Bytes(unsigned sector)
58 {
59     return sector << CFIFLASH_SEC_SIZE_BITS;
60 }
61 
CfiFlashPageWordOffset(unsigned wordOffset)62 static inline unsigned CfiFlashPageWordOffset(unsigned wordOffset)
63 {
64     return wordOffset & CFIFLASH_PAGE_WORDS_MASK;
65 }
66 
CfiFlashEraseBlkWordAddr(unsigned wordOffset)67 static inline unsigned CfiFlashEraseBlkWordAddr(unsigned wordOffset)
68 {
69     return wordOffset & CFIFLASH_ERASEBLK_WORDMASK;
70 }
71 
W2B(unsigned words)72 static inline unsigned W2B(unsigned words)
73 {
74     return words << BYTE_WORD_SHIFT;
75 }
76 
B2W(unsigned bytes)77 static inline unsigned B2W(unsigned bytes)
78 {
79     return bytes >> BYTE_WORD_SHIFT;
80 }
81 
CfiFlashQueryQRY(uint8_t * p)82 static inline DRESULT CfiFlashQueryQRY(uint8_t *p)
83 {
84     unsigned wordOffset = CFIFLASH_QUERY_QRY;
85 
86     if (p[W2B(wordOffset++)] == 'Q') {
87         if (p[W2B(wordOffset++)] == 'R') {
88             if (p[W2B(wordOffset)] == 'Y') {
89                 return RES_OK;
90             }
91         }
92     }
93     return RES_ERROR;
94 }
95 
CfiFlashQueryUint8(unsigned wordOffset,uint8_t expect,uint8_t * p)96 static inline DRESULT CfiFlashQueryUint8(unsigned wordOffset, uint8_t expect, uint8_t *p)
97 {
98     if (p[W2B(wordOffset)] != expect) {
99         PRINT_ERR("[%s]name:0x%x value:%u expect:%u \n", __func__, wordOffset, p[W2B(wordOffset)], expect);
100         return RES_ERROR;
101     }
102     return RES_OK;
103 }
104 
CfiFlashQueryUint16(unsigned wordOffset,uint16_t expect,uint8_t * p)105 static inline DRESULT CfiFlashQueryUint16(unsigned wordOffset, uint16_t expect, uint8_t *p)
106 {
107     uint16_t v;
108 
109     v = (p[W2B(wordOffset + 1)] << BIT_SHIFT8) + p[W2B(wordOffset)];
110     if (v != expect) {
111         PRINT_ERR("[%s]name:0x%x value:%u expect:%u \n", __func__, wordOffset, v, expect);
112         return RES_ERROR;
113     }
114     return RES_OK;
115 }
116 
CfiFlashIsReady(unsigned wordOffset,uint32_t * p)117 static inline int CfiFlashIsReady(unsigned wordOffset, uint32_t *p)
118 {
119     dsb();
120     p[wordOffset] = CFIFLASH_CMD_READ_STATUS;
121     dsb();
122     return p[wordOffset] & CFIFLASH_STATUS_READY_MASK;
123 }
124 
125 /* all in word(4 bytes) measure */
CfiFlashWriteBuf(unsigned wordOffset,const uint32_t * buffer,size_t words,uint32_t * p)126 static void CfiFlashWriteBuf(unsigned wordOffset, const uint32_t *buffer, size_t words, uint32_t *p)
127 {
128     unsigned blkAddr = 0;
129 
130     /* first write might not be Page aligned */
131     unsigned i = CFIFLASH_PAGE_WORDS - CfiFlashPageWordOffset(wordOffset);
132     unsigned wordCount = (i > words) ? words : i;
133 
134     while (words) {
135         /* command buffer-write begin to Erase Block address */
136         blkAddr = CfiFlashEraseBlkWordAddr(wordOffset);
137         p[blkAddr] = CFIFLASH_CMD_BUFWRITE;
138 
139         /* write words count, 0-based */
140         dsb();
141         p[blkAddr] = wordCount - 1;
142 
143         /* program word data to actual address */
144         for (i = 0; i < wordCount; i++, wordOffset++, buffer++) {
145             p[wordOffset] = *buffer;
146         }
147 
148         /* command buffer-write end to Erase Block address */
149         p[blkAddr] = CFIFLASH_CMD_CONFIRM;
150         while (!CfiFlashIsReady(blkAddr, p)) { }
151 
152         words -= wordCount;
153         wordCount = (words >= CFIFLASH_PAGE_WORDS) ? CFIFLASH_PAGE_WORDS : words;
154     }
155 
156     p[0] = CFIFLASH_CMD_CLEAR_STATUS;
157 }
158 
CfiFlashQuery(uint8_t * p)159 static DSTATUS CfiFlashQuery(uint8_t *p)
160 {
161     uint32_t *base = (uint32_t *)p;
162     base[CFIFLASH_QUERY_BASE] = CFIFLASH_QUERY_CMD;
163 
164     dsb();
165     if (CfiFlashQueryQRY(p)) {
166         PRINT_ERR("[%s: %d]not supported CFI flash : not found QRY\n", __func__, __LINE__);
167         return RES_ERROR;
168     }
169 
170     if (CfiFlashQueryUint16(CFIFLASH_QUERY_VENDOR, CFIFLASH_EXPECT_VENDOR, p)) {
171         PRINT_ERR("[%s: %d]not supported CFI flash : unexpected VENDOR\n", __func__, __LINE__);
172         return RES_ERROR;
173     }
174 
175     if (CfiFlashQueryUint8(CFIFLASH_QUERY_SIZE, CFIFLASH_ONE_BANK_BITS, p)) {
176         PRINT_ERR("[%s: %d]not supported CFI flash : unexpected BANK_BITS\n", __func__, __LINE__);
177         return RES_ERROR;
178     }
179 
180     if (CfiFlashQueryUint16(CFIFLASH_QUERY_PAGE_BITS, CFIFLASH_EXPECT_PAGE_BITS, p)) {
181         PRINT_ERR("[%s: %d]not supported CFI flash : unexpected PAGE_BITS\n", __func__, __LINE__);
182         return RES_ERROR;
183     }
184 
185     if (CfiFlashQueryUint8(CFIFLASH_QUERY_ERASE_REGION, CFIFLASH_EXPECT_ERASE_REGION, p)) {
186         PRINT_ERR("[%s: %d]not supported CFI flash : unexpected ERASE_REGION\n", __func__, __LINE__);
187         return RES_ERROR;
188     }
189 
190     if (CfiFlashQueryUint16(CFIFLASH_QUERY_BLOCKS, CFIFLASH_EXPECT_BLOCKS, p)) {
191         PRINT_ERR("[%s: %d]not supported CFI flash : unexpected BLOCKS\n", __func__, __LINE__);
192         return RES_ERROR;
193     }
194 
195     if (CfiFlashQueryUint16(CFIFLASH_QUERY_BLOCK_SIZE, CFIFLASH_EXPECT_BLOCK_SIZE, p)) {
196         PRINT_ERR("[%s: %d]not supported CFI flash : unexpected BLOCK_SIZE\n", __func__, __LINE__);
197         return RES_ERROR;
198     }
199 
200     base[0] = CFIFLASH_CMD_RESET;
201     return RES_OK;
202 }
203 
CfiFlashInit(BYTE pdrv,uint32_t priv)204 DRESULT CfiFlashInit(BYTE pdrv, uint32_t priv)
205 {
206     return SetCfiDrvPriv(pdrv, priv);
207 }
208 
DiskInit(BYTE pdrv)209 DSTATUS DiskInit(BYTE pdrv)
210 {
211     uint8_t *pbase = GetCfiDrvPriv(pdrv);
212     if (pbase == NULL) {
213         return RES_ERROR;
214     }
215 
216     if (CfiFlashQuery(pbase)) {
217         return RES_ERROR;
218     }
219 
220     g_diskDrv.initialized[pdrv] = 1;
221     return RES_OK;
222 }
223 
DiskStatus(BYTE pdrv)224 DSTATUS DiskStatus(BYTE pdrv)
225 {
226     uint8_t *pbase = GetCfiDrvPriv(pdrv);
227     if (pbase == NULL) {
228         return RES_ERROR;
229     }
230 
231     return RES_OK;
232 }
233 
DisckRead(BYTE pdrv,BYTE * buffer,DWORD startSector,UINT nSectors)234 DSTATUS DisckRead(BYTE pdrv, BYTE *buffer, DWORD startSector, UINT nSectors)
235 {
236     unsigned int i = 0;
237 
238     uint32_t *p = (uint32_t *)buffer;
239 
240     uint8_t *pbase = GetCfiDrvPriv(pdrv);
241     if (pbase == NULL) {
242         return RES_ERROR;
243     }
244 
245     unsigned int bytes = CfiFlashSec2Bytes(nSectors);
246     unsigned int wordOffset = B2W(CfiFlashSec2Bytes(startSector));
247 
248     uint32_t *base = (uint32_t *)pbase;
249     for (i = 0; i < B2W(bytes); i++) {
250         p[i] = base[wordOffset + i];
251     }
252 
253     return RES_OK;
254 }
255 
DiskWrite(BYTE pdrv,const BYTE * buffer,DWORD startSector,UINT nSectors)256 DSTATUS DiskWrite(BYTE pdrv, const BYTE *buffer, DWORD startSector, UINT nSectors)
257 {
258     uint32_t *p = (uint32_t *)buffer;
259 
260     uint8_t *pbase = GetCfiDrvPriv(pdrv);
261     if (pbase == NULL) {
262         return RES_ERROR;
263     }
264 
265     unsigned int bytes = CfiFlashSec2Bytes(nSectors);
266     unsigned int wordOffset = B2W(CfiFlashSec2Bytes(startSector));
267 
268     uint32_t *base = (uint32_t *)pbase;
269     CfiFlashWriteBuf(wordOffset, (uint32_t *)p, B2W(bytes), base);
270 
271     return RES_OK;
272 }
273 
DiskIoctl(BYTE pdrv,BYTE cmd,void * buff)274 DSTATUS DiskIoctl(BYTE pdrv, BYTE cmd, void *buff)
275 {
276     uint8_t *pbase = GetCfiDrvPriv(pdrv);
277     if (pbase == NULL) {
278         return RES_ERROR;
279     }
280 
281     switch (cmd) {
282         case CTRL_SYNC:
283             break;
284         case GET_SECTOR_COUNT:
285             *(DWORD *)buff = CFIFLASH_SECTORS;
286             break;
287         case GET_SECTOR_SIZE:
288             *(WORD *)buff = CFIFLASH_SEC_SIZE;
289             break;
290         case GET_BLOCK_SIZE:
291             *(WORD *)buff = CFIFLASH_EXPECT_ERASE_REGION;
292             break;
293         default:
294             return RES_PARERR;
295     }
296 
297     return RES_OK;
298 }
299