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 33static uint32_t g_cfiDrvBase[CFIFLASH_MAX_NUM]; 34 35static 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 49static int SetCfiDrvPriv(uint32_t pdrv, uint32_t priv) 50{ 51 g_cfiDrvBase[pdrv] = priv; 52 return FLASH_OK; 53} 54 55unsigned CfiFlashSec2Bytes(unsigned sector) 56{ 57 return sector << CFIFLASH_SEC_SIZE_BITS; 58} 59 60static inline unsigned CfiFlashPageWordOffset(unsigned wordOffset) 61{ 62 return wordOffset & CFIFLASH_PAGE_WORDS_MASK; 63} 64 65static inline unsigned CfiFlashEraseBlkWordAddr(unsigned wordOffset) 66{ 67 return wordOffset & CFIFLASH_ERASEBLK_WORDMASK; 68} 69 70static inline unsigned W2B(unsigned words) 71{ 72 return words << BYTE_WORD_SHIFT; 73} 74 75static inline unsigned B2W(unsigned bytes) 76{ 77 return bytes >> BYTE_WORD_SHIFT; 78} 79 80static 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 94static 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 103static 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 115static 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 */ 124static 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 157int 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 206int CfiFlashInit(uint32_t pdrv, uint32_t priv) 207{ 208 return SetCfiDrvPriv(pdrv, priv); 209} 210 211int32_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 237int32_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 260int32_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}