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 }