1 /*
2 * Copyright (c) 2022 Talkweb 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 #include "w25qxx.h"
17
18 #define W25x_PageSize 256
19 #define W25x_PerWritePageSize 256
20 #define W25X_WriteEnable 0x06
21 #define W25X_WriteDisable 0x04
22 #define W25X_ReadStatusReg 0x05
23 #define W25X_WriteStatusReg 0x01
24 #define W25X_ReadData 0x03
25 #define W25X_FastReadData 0x0B
26 #define W25X_FastReadDual 0x3B
27 #define W25X_PageProgram 0x02
28 #define W25X_BlockErase 0xD8
29 #define W25X_SectorErase 0x20
30 #define W25X_ChipErase 0xC7
31 #define W25X_PowerDown 0xB9
32 #define W25X_ReleasePowerDown 0xAB
33 #define W25X_DeviceID 0xAB
34 #define W25X_ManufactDeviceID 0x90
35 #define W25X_JedecDeviceID 0x9F
36
37 #define WIP_Flag 0x01
38
39 #define Dummy_Byte 0xFF
40
41 #ifdef LOSCFG_DRIVERS_HDF_PLATFORM_SPI
42 DevHandle spiHandle = NULL;
W25x_InitSpiFlash(uint32_t busNum,uint32_t csNum)43 uint8_t W25x_InitSpiFlash(uint32_t busNum, uint32_t csNum)
44 {
45 struct SpiDevInfo spiDevinfo;
46 spiDevinfo.busNum = busNum;
47 spiDevinfo.csNum = csNum;
48 spiHandle = SpiOpen(&spiDevinfo);
49 if (spiHandle == NULL) {
50 HDF_LOGE("SpiOpen: failed\n");
51 return HDF_FAILURE;
52 }
53
54 return HDF_SUCCESS;
55 }
56
W25x_DeInitSpiFlash(void)57 uint8_t W25x_DeInitSpiFlash(void)
58 {
59 if (spiHandle != NULL) {
60 SpiClose(spiHandle);
61 }
62
63 return HDF_SUCCESS;
64 }
65
W25x_GetSpiHandle(void)66 DevHandle W25x_GetSpiHandle(void)
67 {
68 return spiHandle;
69 }
70
W25x_SectorErase(uint32_t SectorAddr)71 void W25x_SectorErase(uint32_t SectorAddr)
72 {
73 if (spiHandle == NULL) {
74 HDF_LOGE("spi flash haven't been inited\n");
75 return;
76 }
77 W25x_WriteEnable();
78 W25x_WaitForWriteEnd();
79 uint8_t wbuf[4] = {0x20, (SectorAddr & 0xff0000) >> 16, (SectorAddr & 0xff00) >> 8, (SectorAddr & 0xff)};
80 uint8_t rbuf[4] = {0};
81 struct SpiMsg msg = {0};
82 msg.wbuf = wbuf;
83 msg.rbuf = rbuf;
84 msg.len = sizeof(wbuf);
85 msg.keepCs = 0;
86 msg.delayUs = 0;
87 int32_t ret = SpiTransfer(spiHandle, &msg, 1);
88 if (ret != 0) {
89 HDF_LOGE("SpiTransfer: failed, ret %d\n", ret);
90 return;
91 }
92 W25x_WaitForWriteEnd();
93 }
94
W25x_BulkErase(void)95 void W25x_BulkErase(void)
96 {
97 if (spiHandle == NULL) {
98 HDF_LOGE("spi flash haven't been inited\n");
99 return;
100 }
101 W25x_WriteEnable();
102 uint8_t wbuf[1] = {W25X_ChipErase};
103 uint8_t rbuf[1] = {0};
104 struct SpiMsg msg = {0};
105 msg.wbuf = wbuf;
106 msg.rbuf = rbuf;
107 msg.len = sizeof(wbuf);
108 msg.keepCs = 0;
109 msg.delayUs = 0;
110 int32_t ret = SpiTransfer(spiHandle, &msg, 1);
111 if (ret != 0) {
112 HDF_LOGE("SpiTransfer: failed, ret %d\n", ret);
113 return;
114 }
115 W25x_WaitForWriteEnd();
116 return;
117 }
118
W25x_PageWrite(uint8_t * pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)119 void W25x_PageWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
120 {
121 if (spiHandle == NULL) {
122 HDF_LOGE("spi flash haven't been inited\n");
123 return;
124 }
125 W25x_WriteEnable();
126 uint8_t wbuf[4] = {W25X_PageProgram, (WriteAddr & 0xff0000) >> 16, (WriteAddr & 0xff00) >> 8, (WriteAddr & 0xff)};
127 uint8_t rbuf[4] = {0};
128 uint8_t *rbuf1 = NULL;
129 int32_t ret = 0;
130
131 struct SpiMsg msg = {0};
132 msg.wbuf = wbuf;
133 msg.rbuf = rbuf;
134 msg.len = sizeof(wbuf);
135 msg.keepCs = 1;
136 msg.delayUs = 0;
137 ret = SpiTransfer(spiHandle, &msg, 1);
138 if (ret != 0) {
139 HDF_LOGE("SpiTransfer: failed, ret %d\n", ret);
140 }
141
142 if (NumByteToWrite > W25x_PerWritePageSize) {
143 NumByteToWrite = W25x_PerWritePageSize;
144 HDF_LOGE("Err: W25x_PageWrite too large!\n");
145 }
146
147 rbuf1 = (uint8_t*)OsalMemAlloc(NumByteToWrite);
148 if (rbuf1 == NULL) {
149 HDF_LOGE("malloc failed\n");
150 return;
151 }
152 memset_s(rbuf1, NumByteToWrite, 0, NumByteToWrite);
153 msg.wbuf = pBuffer;
154 msg.rbuf = rbuf1;
155 msg.len = NumByteToWrite;
156 msg.keepCs = 0;
157 msg.delayUs = 0;
158 ret = SpiTransfer(spiHandle, &msg, 1);
159 if (ret != 0) {
160 HDF_LOGE("SpiTransfer: failed, ret %d\n", ret);
161 }
162 W25x_WaitForWriteEnd();
163 OsalMemFree(rbuf1);
164 return;
165 }
166
W25x_BufferWrite(uint8_t * pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)167 void W25x_BufferWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
168 {
169 uint8_t NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0, temp = 0;
170
171 Addr = WriteAddr % W25x_PageSize;
172 count = W25x_PageSize - Addr;
173 NumOfPage = NumByteToWrite / W25x_PageSize;
174 NumOfSingle = NumByteToWrite % W25x_PageSize;
175
176 if (Addr == 0) {
177 if (NumOfPage == 0) {
178 W25x_PageWrite(pBuffer, WriteAddr, NumByteToWrite);
179 } else {
180 while (NumOfPage--) {
181 W25x_PageWrite(pBuffer, WriteAddr, W25x_PageSize);
182 WriteAddr += W25x_PageSize;
183 pBuffer += W25x_PageSize;
184 }
185 W25x_PageWrite(pBuffer, WriteAddr, NumOfSingle);
186 }
187 } else {
188 if (NumOfPage == 0) {
189 if (NumOfSingle > count) {
190 temp = NumOfSingle - count;
191
192 W25x_PageWrite(pBuffer, WriteAddr, count);
193 WriteAddr += count;
194 pBuffer += count;
195
196 W25x_PageWrite(pBuffer, WriteAddr, temp);
197 } else {
198 W25x_PageWrite(pBuffer, WriteAddr, NumByteToWrite);
199 }
200 } else {
201 NumByteToWrite -= count;
202 NumOfPage = NumByteToWrite / W25x_PageSize;
203 NumOfSingle = NumByteToWrite % W25x_PageSize;
204
205 W25x_PageWrite(pBuffer, WriteAddr, count);
206 WriteAddr += count;
207 pBuffer += count;
208
209 while (NumOfPage--) {
210 W25x_PageWrite(pBuffer, WriteAddr, W25x_PageSize);
211 WriteAddr += W25x_PageSize;
212 pBuffer += W25x_PageSize;
213 }
214
215 if (NumOfSingle != 0) {
216 W25x_PageWrite(pBuffer, WriteAddr, NumOfSingle);
217 }
218 }
219 }
220 }
221
W25x_BufferRead(uint8_t * pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead)222 void W25x_BufferRead(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead)
223 {
224 if (spiHandle == NULL) {
225 HDF_LOGE("spi flash haven't been inited\n");
226 return;
227 }
228
229 int32_t ret = 0;
230
231 uint8_t wbuf[4] = {W25X_ReadData, (ReadAddr & 0xFF0000) >> 16, (ReadAddr& 0xFF00) >> 8, ReadAddr & 0xFF};
232 uint8_t rbuf[4] = {0};
233 struct SpiMsg msg = {0};
234 msg.wbuf = wbuf;
235 msg.rbuf = rbuf;
236 msg.len = sizeof(wbuf);
237 msg.keepCs = 1;
238 msg.delayUs = 0;
239 ret = SpiTransfer(spiHandle, &msg, 1);
240 if (ret != 0) {
241 HDF_LOGE("SpiTransfer: failed, ret %d\n", ret);
242 return;
243 }
244 uint8_t *wbuf1 = (uint8_t*)OsalMemAlloc(NumByteToRead);
245 if (wbuf1 == NULL) {
246 HDF_LOGE("malloc failed\n");
247 return;
248 }
249 memset_s(wbuf1, NumByteToRead, 0xff, NumByteToRead);
250 msg.wbuf = wbuf1;
251 msg.rbuf = pBuffer;
252 msg.len = NumByteToRead;
253 msg.keepCs = 0;
254 msg.delayUs = 0;
255 ret = SpiTransfer(spiHandle, &msg, 1);
256 if (ret != 0) {
257 HDF_LOGE("SpiTransfer: failed, ret %d\n", ret);
258 return;
259 }
260
261 OsalMemFree(wbuf1);
262
263 return;
264 }
265
W25x_ReadID(void)266 uint32_t W25x_ReadID(void)
267 {
268 int32_t ret = 0;
269 uint16_t flashId = 0;
270 uint8_t rbuff1[4] = { 0 };
271 uint8_t wbuff1[4] = { W25X_JedecDeviceID, Dummy_Byte, Dummy_Byte, Dummy_Byte };
272 struct SpiMsg msg1 = {0};
273 msg1.wbuf = wbuff1;
274 msg1.rbuf = rbuff1;
275 msg1.len = sizeof(wbuff1);
276 msg1.keepCs = 0;
277 msg1.delayUs = 0;
278 ret = SpiTransfer(spiHandle, &msg1, 1);
279 if (ret != 0) {
280 HDF_LOGE("SpiTransfer: failed, ret %d\n", ret);
281 } else {
282 flashId = msg1.rbuf[2]<<8 | msg1.rbuf[3];
283 }
284
285 return flashId;
286 }
287
W25x_ReadDeviceID(void)288 uint32_t W25x_ReadDeviceID(void)
289 {
290 if (spiHandle == NULL) {
291 HDF_LOGE("spi flash haven't been inited\n");
292 return 0;
293 }
294 struct SpiMsg msg;
295 uint16_t deviceId = 0;
296 uint8_t rbuff[5] = { 0 };
297 uint8_t wbuff[5] = { W25X_DeviceID, Dummy_Byte, Dummy_Byte, Dummy_Byte, Dummy_Byte };
298 int32_t ret = 0;
299 msg.wbuf = wbuff;
300 msg.rbuf = rbuff;
301 msg.len = sizeof(wbuff);
302 msg.keepCs = 0;
303 msg.delayUs = 0;
304 ret = SpiTransfer(spiHandle, &msg, 1);
305 if (ret != 0) {
306 HDF_LOGE("SpiTransfer: failed, ret %d\n", ret);
307 } else {
308 deviceId = rbuff[4];
309 }
310
311 return deviceId;
312 }
313
W25x_StartReadSequence(uint32_t ReadAddr)314 void W25x_StartReadSequence(uint32_t ReadAddr)
315 {
316 if (spiHandle == NULL) {
317 HDF_LOGE("spi flash haven't been inited\n");
318 return;
319 }
320 struct SpiMsg msg;
321 uint8_t rbuff[4] = { 0 };
322 uint8_t wbuff[4] = { W25X_ReadData, (ReadAddr & 0xff0000) >> 16, (ReadAddr & 0xff00) >> 8, ReadAddr & 0xff };
323 int32_t ret = 0;
324 msg.wbuf = wbuff;
325 msg.rbuf = rbuff;
326 msg.len = sizeof(wbuff);
327 msg.keepCs = 0;
328 msg.delayUs = 0;
329 ret = SpiTransfer(spiHandle, &msg, 1);
330 if (ret != 0) {
331 HDF_LOGE("SpiTransfer: failed, ret %d\n", ret);
332 }
333 }
334
W25x_WriteEnable(void)335 void W25x_WriteEnable(void)
336 {
337 if (spiHandle == NULL) {
338 HDF_LOGE("spi flash haven't been inited\n");
339 return;
340 }
341
342 uint8_t wbuf[1] = {W25X_WriteEnable};
343 uint8_t rbuf[1] = {0};
344 struct SpiMsg msg = {0};
345 msg.wbuf = wbuf;
346 msg.rbuf = rbuf;
347 msg.len = sizeof(wbuf);
348 msg.keepCs = 0;
349 msg.delayUs = 0;
350 int32_t ret = SpiTransfer(spiHandle, &msg, 1);
351 if (ret != 0) {
352 HDF_LOGE("SpiTransfer: failed, ret %d\n", ret);
353 }
354
355 return;
356 }
357
W25x_WaitForWriteEnd(void)358 void W25x_WaitForWriteEnd(void)
359 {
360 if (spiHandle == NULL) {
361 HDF_LOGE("spi flash haven't been inited\n");
362 return;
363 }
364
365 uint8_t FLASH_Status = 0;
366
367 /* Send "Read Status Register" instruction */
368 uint8_t wbuf[1] = {W25X_ReadStatusReg};
369 uint8_t wbuf1[1] = {0xff};
370 uint8_t rbuf[1] = {0};
371 struct SpiMsg msg = {0};
372 msg.wbuf = wbuf;
373 msg.rbuf = rbuf;
374 msg.len = sizeof(wbuf);
375 msg.keepCs = 1;
376 msg.delayUs = 0;
377 int32_t ret = SpiTransfer(spiHandle, &msg, 1);
378 if (ret != 0) {
379 HDF_LOGE("SpiTransfer: failed, ret %d\n", ret);
380 }
381
382 /* Loop as long as the memory is busy with a write cycle */
383 do {
384 msg.wbuf = wbuf1;
385 msg.rbuf = rbuf;
386 msg.len = sizeof(wbuf1);
387 msg.keepCs = 1;
388 msg.delayUs = 0;
389
390 ret = SpiTransfer(spiHandle, &msg, 1);
391 if (ret != 0) {
392 HDF_LOGE("SpiTransfer: failed, ret %d\n", ret);
393 }
394 FLASH_Status = rbuf[0];
395 }
396 while ((FLASH_Status & WIP_Flag) == 1); /* Write in progress */
397
398 msg.wbuf = wbuf1;
399 msg.rbuf = rbuf;
400 msg.len = sizeof(wbuf1);
401 msg.keepCs = 0;
402 msg.delayUs = 0;
403
404 ret = SpiTransfer(spiHandle, &msg, 1);
405 if (ret != 0) {
406 HDF_LOGE("SpiTransfer: failed, ret %d\n", ret);
407 }
408
409 return;
410 }
411
412
W25x_PowerDown(void)413 void W25x_PowerDown(void)
414 {
415 if (spiHandle == NULL) {
416 HDF_LOGE("spi flash haven't been inited\n");
417 return;
418 }
419
420 uint8_t wbuf[1] = {W25X_PowerDown};
421 uint8_t rbuf[1] = {0};
422 struct SpiMsg msg = {0};
423 msg.wbuf = wbuf;
424 msg.rbuf = rbuf;
425 msg.len = sizeof(wbuf);
426 msg.keepCs = 0;
427 msg.delayUs = 0;
428 int32_t ret = SpiTransfer(spiHandle, &msg, 1);
429 if (ret != 0) {
430 HDF_LOGE("SpiTransfer: failed, ret %d\n", ret);
431 }
432
433 return;
434 }
435
W25x_WAKEUP(void)436 void W25x_WAKEUP(void)
437 {
438 if (spiHandle == NULL) {
439 HDF_LOGE("spi flash haven't been inited\n");
440 return;
441 }
442
443 uint8_t wbuf[1] = {W25X_ReleasePowerDown};
444 uint8_t rbuf[1] = {0};
445 struct SpiMsg msg = {0};
446 msg.wbuf = wbuf;
447 msg.rbuf = rbuf;
448 msg.len = sizeof(wbuf);
449 msg.keepCs = 0;
450 msg.delayUs = 0;
451 int32_t ret = SpiTransfer(spiHandle, &msg, 1);
452 if (ret != 0) {
453 HDF_LOGE("SpiTransfer: failed, ret %d\n", ret);
454 }
455
456 return;
457 }
458 #endif
459