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