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