1 /**
2 *
3 * \file
4 *
5 * \brief WINC1500 SPI Flash.
6 *
7 * Copyright (c) 2016-2017 Atmel Corporation. All rights reserved.
8 *
9 * \asf_license_start
10 *
11 * \page License
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions are met:
15 *
16 * 1. Redistributions of source code must retain the above copyright notice,
17 * this list of conditions and the following disclaimer.
18 *
19 * 2. Redistributions in binary form must reproduce the above copyright notice,
20 * this list of conditions and the following disclaimer in the documentation
21 * and/or other materials provided with the distribution.
22 *
23 * 3. The name of Atmel may not be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
27 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
28 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
29 * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
30 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
34 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 *
38 * \asf_license_stop
39 *
40 */
41
42 #ifdef PROFILING
43 #include "windows.h"
44 #endif
45 #include "spi_flash/include/spi_flash.h"
46 #define DUMMY_REGISTER (0x1084)
47
48 #define TIMEOUT (-1) /*MS*/
49
50 //#define DISABLE_UNSED_FLASH_FUNCTIONS
51
52 #define FLASH_BLOCK_SIZE (32UL * 1024)
53 /*!<Block Size in Flash Memory
54 */
55 #define FLASH_SECTOR_SZ (4 * 1024UL)
56 /*!<Sector Size in Flash Memory
57 */
58 #define FLASH_PAGE_SZ (256)
59 /*!<Page Size in Flash Memory */
60
61
62 #define HOST_SHARE_MEM_BASE (0xd0000UL)
63 #define CORTUS_SHARE_MEM_BASE (0x60000000UL)
64 #define NMI_SPI_FLASH_ADDR (0x111c)
65 /***********************************************************
66 SPI Flash DMA
67 ***********************************************************/
68 #define GET_UINT32(X,Y) (X[0+Y] + ((uint32)X[1+Y]<<8) + ((uint32)X[2+Y]<<16) +((uint32)X[3+Y]<<24))
69 #define SPI_FLASH_BASE (0x10200)
70 #define SPI_FLASH_MODE (SPI_FLASH_BASE + 0x00)
71 #define SPI_FLASH_CMD_CNT (SPI_FLASH_BASE + 0x04)
72 #define SPI_FLASH_DATA_CNT (SPI_FLASH_BASE + 0x08)
73 #define SPI_FLASH_BUF1 (SPI_FLASH_BASE + 0x0c)
74 #define SPI_FLASH_BUF2 (SPI_FLASH_BASE + 0x10)
75 #define SPI_FLASH_BUF_DIR (SPI_FLASH_BASE + 0x14)
76 #define SPI_FLASH_TR_DONE (SPI_FLASH_BASE + 0x18)
77 #define SPI_FLASH_DMA_ADDR (SPI_FLASH_BASE + 0x1c)
78 #define SPI_FLASH_MSB_CTL (SPI_FLASH_BASE + 0x20)
79 #define SPI_FLASH_TX_CTL (SPI_FLASH_BASE + 0x24)
80
81 /*********************************************/
82 /* STATIC FUNCTIONS */
83 /*********************************************/
84
85 /**
86 * @fn spi_flash_read_status_reg
87 * @brief Read status register
88 * @param[OUT] val
89 value of status reg
90 * @return Status of execution
91 * @note Compatible with MX25L6465E
92 * @author M. Abdelmawla
93 * @version 1.0
94 */
spi_flash_read_status_reg(uint8 * val)95 static sint8 spi_flash_read_status_reg(uint8 * val)
96 {
97 sint8 ret = M2M_SUCCESS;
98 uint8 cmd[1];
99 uint32 reg;
100
101 cmd[0] = 0x05;
102
103 ret += nm_write_reg(SPI_FLASH_DATA_CNT, 4);
104 ret += nm_write_reg(SPI_FLASH_BUF1, cmd[0]);
105 ret += nm_write_reg(SPI_FLASH_BUF_DIR, 0x01);
106 ret += nm_write_reg(SPI_FLASH_DMA_ADDR, DUMMY_REGISTER);
107 ret += nm_write_reg(SPI_FLASH_CMD_CNT, 1 | (1<<7));
108 do
109 {
110 ret += nm_read_reg_with_ret(SPI_FLASH_TR_DONE, (uint32 *)®);
111 if(M2M_SUCCESS != ret) break;
112 }
113 while(reg != 1);
114
115 reg = (M2M_SUCCESS == ret)?(nm_read_reg(DUMMY_REGISTER)):(0);
116 *val = (uint8)(reg & 0xff);
117 return ret;
118 }
119
120 #ifdef DISABLE_UNSED_FLASH_FUNCTIONS
121 /**
122 * @fn spi_flash_read_security_reg
123 * @brief Read security register
124 * @return Security register value
125 * @note Compatible with MX25L6465E
126 * @author M. Abdelmawla
127 * @version 1.0
128 */
spi_flash_read_security_reg(void)129 static uint8 spi_flash_read_security_reg(void)
130 {
131 uint8 cmd[1];
132 uint32 reg;
133 sint8 ret = M2M_SUCCESS;
134
135 cmd[0] = 0x2b;
136
137 ret += nm_write_reg(SPI_FLASH_DATA_CNT, 1);
138 ret += nm_write_reg(SPI_FLASH_BUF1, cmd[0]);
139 ret += nm_write_reg(SPI_FLASH_BUF_DIR, 0x01);
140 ret += nm_write_reg(SPI_FLASH_DMA_ADDR, DUMMY_REGISTER);
141 ret += nm_write_reg(SPI_FLASH_CMD_CNT, 1 | (1<<7));
142 do
143 {
144 ret += nm_read_reg_with_ret(SPI_FLASH_TR_DONE, (uint32 *)®);
145 if(M2M_SUCCESS != ret) break;
146 }
147 while(reg != 1);
148 reg = (M2M_SUCCESS == ret)?(nm_read_reg(DUMMY_REGISTER)):(0);
149
150 return (sint8)reg & 0xff;
151 }
152
153 /**
154 * @fn spi_flash_gang_unblock
155 * @brief Unblock all flash area
156 * @note Compatible with MX25L6465E
157 * @author M. Abdelmawla
158 * @version 1.0
159 */
spi_flash_gang_unblock(void)160 static sint8 spi_flash_gang_unblock(void)
161 {
162 uint8 cmd[1];
163 uint32 val = 0;
164 sint8 ret = M2M_SUCCESS;
165
166 cmd[0] = 0x98;
167
168 ret += nm_write_reg(SPI_FLASH_DATA_CNT, 0);
169 ret += nm_write_reg(SPI_FLASH_BUF1, cmd[0]);
170 ret += nm_write_reg(SPI_FLASH_BUF_DIR, 0x01);
171 ret += nm_write_reg(SPI_FLASH_DMA_ADDR, 0);
172 ret += nm_write_reg(SPI_FLASH_CMD_CNT, 1 | (1<<7));
173 do
174 {
175 ret += nm_read_reg_with_ret(SPI_FLASH_TR_DONE, (uint32 *)&val);
176 if(M2M_SUCCESS != ret) break;
177 }
178 while(val != 1);
179
180 return ret;
181 }
182
183 /**
184 * @fn spi_flash_clear_security_flags
185 * @brief Clear all security flags
186 * @note Compatible with MX25L6465E
187 * @author M. Abdelmawla
188 * @version 1.0
189 */
spi_flash_clear_security_flags(void)190 static sint8 spi_flash_clear_security_flags(void)
191 {
192 uint8 cmd[1];
193 uint32 val = 0;
194 sint8 ret = M2M_SUCCESS;
195
196 cmd[0] = 0x30;
197
198 ret += nm_write_reg(SPI_FLASH_DATA_CNT, 0);
199 ret += nm_write_reg(SPI_FLASH_BUF1, cmd[0]);
200 ret += nm_write_reg(SPI_FLASH_BUF_DIR, 0x01);
201 ret += nm_write_reg(SPI_FLASH_DMA_ADDR, 0);
202 ret += nm_write_reg(SPI_FLASH_CMD_CNT, 1 | (1<<7));
203 do
204 {
205 ret += nm_read_reg_with_ret(SPI_FLASH_TR_DONE, (uint32 *)&val);
206 if(M2M_SUCCESS != ret) break;
207 }
208 while(val != 1);
209
210 return ret;
211 }
212 #endif
213
214 /**
215 * @fn spi_flash_load_to_cortus_mem
216 * @brief Load data from SPI flash into cortus memory
217 * @param[IN] u32MemAdr
218 * Cortus load address. It must be set to its AHB access address
219 * @param[IN] u32FlashAdr
220 * Address to read from at the SPI flash
221 * @param[IN] u32Sz
222 * Data size
223 * @return Status of execution
224 * @note Compatible with MX25L6465E and should be working with other types
225 * @author M. Abdelmawla
226 * @version 1.0
227 */
spi_flash_load_to_cortus_mem(uint32 u32MemAdr,uint32 u32FlashAdr,uint32 u32Sz)228 static sint8 spi_flash_load_to_cortus_mem(uint32 u32MemAdr, uint32 u32FlashAdr, uint32 u32Sz)
229 {
230 uint8 cmd[5];
231 uint32 val = 0;
232 sint8 ret = M2M_SUCCESS;
233
234 cmd[0] = 0x0b;
235 cmd[1] = (uint8)(u32FlashAdr >> 16);
236 cmd[2] = (uint8)(u32FlashAdr >> 8);
237 cmd[3] = (uint8)(u32FlashAdr);
238 cmd[4] = 0xA5;
239
240 ret += nm_write_reg(SPI_FLASH_DATA_CNT, u32Sz);
241 ret += nm_write_reg(SPI_FLASH_BUF1, cmd[0]|(cmd[1]<<8)|(cmd[2]<<16)|(cmd[3]<<24));
242 ret += nm_write_reg(SPI_FLASH_BUF2, cmd[4]);
243 ret += nm_write_reg(SPI_FLASH_BUF_DIR, 0x1f);
244 ret += nm_write_reg(SPI_FLASH_DMA_ADDR, u32MemAdr);
245 ret += nm_write_reg(SPI_FLASH_CMD_CNT, 5 | (1<<7));
246 do
247 {
248 ret += nm_read_reg_with_ret(SPI_FLASH_TR_DONE, (uint32 *)&val);
249 if(M2M_SUCCESS != ret) break;
250 }
251 while(val != 1);
252
253 return ret;
254 }
255
256 /**
257 * @fn spi_flash_sector_erase
258 * @brief Erase sector (4KB)
259 * @param[IN] u32FlashAdr
260 * Any memory address within the sector
261 * @return Status of execution
262 * @note Compatible with MX25L6465E and should be working with other types
263 * @author M. Abdelmawla
264 * @version 1.0
265 */
spi_flash_sector_erase(uint32 u32FlashAdr)266 static sint8 spi_flash_sector_erase(uint32 u32FlashAdr)
267 {
268 uint8 cmd[4];
269 uint32 val = 0;
270 sint8 ret = M2M_SUCCESS;
271
272 cmd[0] = 0x20;
273 cmd[1] = (uint8)(u32FlashAdr >> 16);
274 cmd[2] = (uint8)(u32FlashAdr >> 8);
275 cmd[3] = (uint8)(u32FlashAdr);
276
277 ret += nm_write_reg(SPI_FLASH_DATA_CNT, 0);
278 ret += nm_write_reg(SPI_FLASH_BUF1, cmd[0]|(cmd[1]<<8)|(cmd[2]<<16)|(cmd[3]<<24));
279 ret += nm_write_reg(SPI_FLASH_BUF_DIR, 0x0f);
280 ret += nm_write_reg(SPI_FLASH_DMA_ADDR, 0);
281 ret += nm_write_reg(SPI_FLASH_CMD_CNT, 4 | (1<<7));
282 do
283 {
284 ret += nm_read_reg_with_ret(SPI_FLASH_TR_DONE, (uint32 *)&val);
285 if(M2M_SUCCESS != ret) break;
286 }
287 while(val != 1);
288
289 return ret;
290 }
291
292 /**
293 * @fn spi_flash_write_enable
294 * @brief Send write enable command to SPI flash
295 * @return Status of execution
296 * @note Compatible with MX25L6465E and should be working with other types
297 * @author M. Abdelmawla
298 * @version 1.0
299 */
spi_flash_write_enable(void)300 static sint8 spi_flash_write_enable(void)
301 {
302 uint8 cmd[1];
303 uint32 val = 0;
304 sint8 ret = M2M_SUCCESS;
305
306 cmd[0] = 0x06;
307
308 ret += nm_write_reg(SPI_FLASH_DATA_CNT, 0);
309 ret += nm_write_reg(SPI_FLASH_BUF1, cmd[0]);
310 ret += nm_write_reg(SPI_FLASH_BUF_DIR, 0x01);
311 ret += nm_write_reg(SPI_FLASH_DMA_ADDR, 0);
312 ret += nm_write_reg(SPI_FLASH_CMD_CNT, 1 | (1<<7));
313 do
314 {
315 ret += nm_read_reg_with_ret(SPI_FLASH_TR_DONE, (uint32 *)&val);
316 if(M2M_SUCCESS != ret) break;
317 }
318 while(val != 1);
319
320 return ret;
321 }
322
323 /**
324 * @fn spi_flash_write_disable
325 * @brief Send write disable command to SPI flash
326 * @note Compatible with MX25L6465E and should be working with other types
327 * @author M. Abdelmawla
328 * @version 1.0
329 */
spi_flash_write_disable(void)330 static sint8 spi_flash_write_disable(void)
331 {
332 uint8 cmd[1];
333 uint32 val = 0;
334 sint8 ret = M2M_SUCCESS;
335 cmd[0] = 0x04;
336
337 ret += nm_write_reg(SPI_FLASH_DATA_CNT, 0);
338 ret += nm_write_reg(SPI_FLASH_BUF1, cmd[0]);
339 ret += nm_write_reg(SPI_FLASH_BUF_DIR, 0x01);
340 ret += nm_write_reg(SPI_FLASH_DMA_ADDR, 0);
341 ret += nm_write_reg(SPI_FLASH_CMD_CNT, 1 | (1<<7));
342 do
343 {
344 ret += nm_read_reg_with_ret(SPI_FLASH_TR_DONE, (uint32 *)&val);
345 if(M2M_SUCCESS != ret) break;
346 }
347 while(val != 1);
348
349 return ret;
350 }
351
352 /**
353 * @fn spi_flash_page_program
354 * @brief Write data (less than page size) from cortus memory to SPI flash
355 * @param[IN] u32MemAdr
356 * Cortus data address. It must be set to its AHB access address
357 * @param[IN] u32FlashAdr
358 * Address to write to at the SPI flash
359 * @param[IN] u32Sz
360 * Data size
361 * @note Compatible with MX25L6465E and should be working with other types
362 * @author M. Abdelmawla
363 * @version 1.0
364 */
spi_flash_page_program(uint32 u32MemAdr,uint32 u32FlashAdr,uint32 u32Sz)365 static sint8 spi_flash_page_program(uint32 u32MemAdr, uint32 u32FlashAdr, uint32 u32Sz)
366 {
367 uint8 cmd[4];
368 uint32 val = 0;
369 sint8 ret = M2M_SUCCESS;
370
371 cmd[0] = 0x02;
372 cmd[1] = (uint8)(u32FlashAdr >> 16);
373 cmd[2] = (uint8)(u32FlashAdr >> 8);
374 cmd[3] = (uint8)(u32FlashAdr);
375
376 ret += nm_write_reg(SPI_FLASH_DATA_CNT, 0);
377 ret += nm_write_reg(SPI_FLASH_BUF1, cmd[0]|(cmd[1]<<8)|(cmd[2]<<16)|(cmd[3]<<24));
378 ret += nm_write_reg(SPI_FLASH_BUF_DIR, 0x0f);
379 ret += nm_write_reg(SPI_FLASH_DMA_ADDR, u32MemAdr);
380 ret += nm_write_reg(SPI_FLASH_CMD_CNT, 4 | (1<<7) | ((u32Sz & 0xfffff) << 8));
381 do
382 {
383 ret += nm_read_reg_with_ret(SPI_FLASH_TR_DONE, (uint32 *)&val);
384 if(M2M_SUCCESS != ret) break;
385 }
386 while(val != 1);
387
388 return ret;
389 }
390
391 /**
392 * @fn spi_flash_read_internal
393 * @brief Read from data from SPI flash
394 * @param[OUT] pu8Buf
395 * Pointer to data buffer
396 * @param[IN] u32Addr
397 * Address to read from at the SPI flash
398 * @param[IN] u32Sz
399 * Data size
400 * @note Data size must be < 64KB (limitation imposed by the bus wrapper)
401 * @author M. Abdelmawla
402 * @version 1.0
403 */
spi_flash_read_internal(uint8 * pu8Buf,uint32 u32Addr,uint32 u32Sz)404 static sint8 spi_flash_read_internal(uint8 *pu8Buf, uint32 u32Addr, uint32 u32Sz)
405 {
406 sint8 ret = M2M_SUCCESS;
407 /* read size must be < 64KB */
408 ret = spi_flash_load_to_cortus_mem(HOST_SHARE_MEM_BASE, u32Addr, u32Sz);
409 if(M2M_SUCCESS != ret) goto ERR;
410 ret = nm_read_block(HOST_SHARE_MEM_BASE, pu8Buf, u32Sz);
411 ERR:
412 return ret;
413 }
414
415 /**
416 * @fn spi_flash_pp
417 * @brief Program data of size less than a page (256 bytes) at the SPI flash
418 * @param[IN] u32Offset
419 * Address to write to at the SPI flash
420 * @param[IN] pu8Buf
421 * Pointer to data buffer
422 * @param[IN] u32Sz
423 * Data size
424 * @return Status of execution
425 * @author M. Abdelmawla
426 * @version 1.0
427 */
spi_flash_pp(uint32 u32Offset,uint8 * pu8Buf,uint16 u16Sz)428 static sint8 spi_flash_pp(uint32 u32Offset, uint8 *pu8Buf, uint16 u16Sz)
429 {
430 sint8 ret = M2M_SUCCESS;
431 uint8 tmp;
432 spi_flash_write_enable();
433 /* use shared packet memory as temp mem */
434 ret += nm_write_block(HOST_SHARE_MEM_BASE, pu8Buf, u16Sz);
435 ret += spi_flash_page_program(HOST_SHARE_MEM_BASE, u32Offset, u16Sz);
436 ret += spi_flash_read_status_reg(&tmp);
437 do
438 {
439 if(ret != M2M_SUCCESS) goto ERR;
440 ret += spi_flash_read_status_reg(&tmp);
441 }while(tmp & 0x01);
442 ret += spi_flash_write_disable();
443 ERR:
444 return ret;
445 }
446
447 /**
448 * @fn spi_flash_rdid
449 * @brief Read SPI Flash ID
450 * @return SPI FLash ID
451 * @author M.S.M
452 * @version 1.0
453 */
spi_flash_rdid(void)454 static uint32 spi_flash_rdid(void)
455 {
456 unsigned char cmd[1];
457 uint32 reg = 0;
458 uint32 cnt = 0;
459 sint8 ret = M2M_SUCCESS;
460
461 cmd[0] = 0x9f;
462
463 ret += nm_write_reg(SPI_FLASH_DATA_CNT, 4);
464 ret += nm_write_reg(SPI_FLASH_BUF1, cmd[0]);
465 ret += nm_write_reg(SPI_FLASH_BUF_DIR, 0x1);
466 ret += nm_write_reg(SPI_FLASH_DMA_ADDR, DUMMY_REGISTER);
467 ret += nm_write_reg(SPI_FLASH_CMD_CNT, 1 | (1<<7));
468 do
469 {
470 ret += nm_read_reg_with_ret(SPI_FLASH_TR_DONE, (uint32 *)®);
471 if(M2M_SUCCESS != ret) break;
472 if(++cnt > 500)
473 {
474 ret = M2M_ERR_INIT;
475 break;
476 }
477 }
478 while(reg != 1);
479 reg = (M2M_SUCCESS == ret)?(nm_read_reg(DUMMY_REGISTER)):(0);
480 M2M_PRINT("Flash ID %x \n",(unsigned int)reg);
481 return reg;
482 }
483
484 /**
485 * @fn spi_flash_unlock
486 * @brief Unlock SPI Flash
487 * @author M.S.M
488 * @version 1.0
489 */
490 #if 0
491 static void spi_flash_unlock(void)
492 {
493 uint8 tmp;
494 tmp = spi_flash_read_security_reg();
495 spi_flash_clear_security_flags();
496 if(tmp & 0x80)
497 {
498 spi_flash_write_enable();
499 spi_flash_gang_unblock();
500 }
501 }
502 #endif
spi_flash_enter_low_power_mode(void)503 static void spi_flash_enter_low_power_mode(void) {
504 volatile unsigned long tmp;
505 unsigned char* cmd = (unsigned char*) &tmp;
506
507 cmd[0] = 0xb9;
508
509 nm_write_reg(SPI_FLASH_DATA_CNT, 0);
510 nm_write_reg(SPI_FLASH_BUF1, cmd[0]);
511 nm_write_reg(SPI_FLASH_BUF_DIR, 0x1);
512 nm_write_reg(SPI_FLASH_DMA_ADDR, 0);
513 nm_write_reg(SPI_FLASH_CMD_CNT, 1 | (1 << 7));
514 while(nm_read_reg(SPI_FLASH_TR_DONE) != 1);
515 }
516
517
spi_flash_leave_low_power_mode(void)518 static void spi_flash_leave_low_power_mode(void) {
519 volatile unsigned long tmp;
520 unsigned char* cmd = (unsigned char*) &tmp;
521
522 cmd[0] = 0xab;
523
524 nm_write_reg(SPI_FLASH_DATA_CNT, 0);
525 nm_write_reg(SPI_FLASH_BUF1, cmd[0]);
526 nm_write_reg(SPI_FLASH_BUF_DIR, 0x1);
527 nm_write_reg(SPI_FLASH_DMA_ADDR, 0);
528 nm_write_reg(SPI_FLASH_CMD_CNT, 1 | (1 << 7));
529 while(nm_read_reg(SPI_FLASH_TR_DONE) != 1);
530 }
531 /*********************************************/
532 /* GLOBAL FUNCTIONS */
533 /*********************************************/
534 /**
535 * @fn spi_flash_enable
536 * @brief Enable spi flash operations
537 * @author M. Abdelmawla
538 * @version 1.0
539 */
spi_flash_enable(uint8 enable)540 sint8 spi_flash_enable(uint8 enable)
541 {
542 sint8 s8Ret = M2M_SUCCESS;
543 if(REV(nmi_get_chipid()) >= REV_3A0) {
544 uint32 u32Val;
545
546 /* Enable pinmux to SPI flash. */
547 s8Ret = nm_read_reg_with_ret(0x1410, &u32Val);
548 if(s8Ret != M2M_SUCCESS) {
549 goto ERR1;
550 }
551 /* GPIO15/16/17/18 */
552 u32Val &= ~((0x7777ul) << 12);
553 u32Val |= ((0x1111ul) << 12);
554 nm_write_reg(0x1410, u32Val);
555 if(enable) {
556 spi_flash_leave_low_power_mode();
557 } else {
558 spi_flash_enter_low_power_mode();
559 }
560 /* Disable pinmux to SPI flash to minimize leakage. */
561 u32Val &= ~((0x7777ul) << 12);
562 u32Val |= ((0x0010ul) << 12);
563 nm_write_reg(0x1410, u32Val);
564 }
565 ERR1:
566 return s8Ret;
567 }
568 /**
569 * @fn spi_flash_read
570 * @brief Read from data from SPI flash
571 * @param[OUT] pu8Buf
572 * Pointer to data buffer
573 * @param[IN] u32offset
574 * Address to read from at the SPI flash
575 * @param[IN] u32Sz
576 * Data size
577 * @return Status of execution
578 * @note Data size is limited by the SPI flash size only
579 * @author M. Abdelmawla
580 * @version 1.0
581 */
spi_flash_read(uint8 * pu8Buf,uint32 u32offset,uint32 u32Sz)582 sint8 spi_flash_read(uint8 *pu8Buf, uint32 u32offset, uint32 u32Sz)
583 {
584 sint8 ret = M2M_SUCCESS;
585 if(u32Sz > FLASH_BLOCK_SIZE)
586 {
587 do
588 {
589 ret = spi_flash_read_internal(pu8Buf, u32offset, FLASH_BLOCK_SIZE);
590 if(M2M_SUCCESS != ret) goto ERR;
591 u32Sz -= FLASH_BLOCK_SIZE;
592 u32offset += FLASH_BLOCK_SIZE;
593 pu8Buf += FLASH_BLOCK_SIZE;
594 } while(u32Sz > FLASH_BLOCK_SIZE);
595 }
596
597 ret = spi_flash_read_internal(pu8Buf, u32offset, u32Sz);
598
599 ERR:
600 return ret;
601 }
602
603 /**
604 * @fn spi_flash_write
605 * @brief Proram SPI flash
606 * @param[IN] pu8Buf
607 * Pointer to data buffer
608 * @param[IN] u32Offset
609 * Address to write to at the SPI flash
610 * @param[IN] u32Sz
611 * Data size
612 * @return Status of execution
613 * @author M. Abdelmawla
614 * @version 1.0
615 */
spi_flash_write(uint8 * pu8Buf,uint32 u32Offset,uint32 u32Sz)616 sint8 spi_flash_write(uint8* pu8Buf, uint32 u32Offset, uint32 u32Sz)
617 {
618 #ifdef PROFILING
619 uint32 t1 = 0;
620 uint32 percent =0;
621 uint32 tpercent =0;
622 #endif
623 sint8 ret = M2M_SUCCESS;
624 uint32 u32wsz;
625 uint32 u32off;
626 uint32 u32Blksz;
627 u32Blksz = FLASH_PAGE_SZ;
628 u32off = u32Offset % u32Blksz;
629 #ifdef PROFILING
630 tpercent = (u32Sz/u32Blksz)+((u32Sz%u32Blksz)>0);
631 t1 = GetTickCount();
632 M2M_PRINT(">Start programming...\r\n");
633 #endif
634 if(u32Sz<=0)
635 {
636 M2M_ERR("Data size = %d",(int)u32Sz);
637 ret = M2M_ERR_FAIL;
638 goto ERR;
639 }
640
641 if (u32off)/*first part of data in the address page*/
642 {
643 u32wsz = u32Blksz - u32off;
644 if(spi_flash_pp(u32Offset, pu8Buf, (uint16)BSP_MIN(u32Sz, u32wsz))!=M2M_SUCCESS)
645 {
646 ret = M2M_ERR_FAIL;
647 goto ERR;
648 }
649 if (u32Sz < u32wsz) goto EXIT;
650 pu8Buf += u32wsz;
651 u32Offset += u32wsz;
652 u32Sz -= u32wsz;
653 }
654 while (u32Sz > 0)
655 {
656 u32wsz = BSP_MIN(u32Sz, u32Blksz);
657
658 /*write complete page or the remaining data*/
659 if(spi_flash_pp(u32Offset, pu8Buf, (uint16)u32wsz)!=M2M_SUCCESS)
660 {
661 ret = M2M_ERR_FAIL;
662 goto ERR;
663 }
664 pu8Buf += u32wsz;
665 u32Offset += u32wsz;
666 u32Sz -= u32wsz;
667 #ifdef PROFILING
668 percent++;
669 printf("\r>Complete Percentage = %d%%.\r",((percent*100)/tpercent));
670 #endif
671 }
672 EXIT:
673 #ifdef PROFILING
674 M2M_PRINT("\rDone\t\t\t\t\t\t");
675 M2M_PRINT("\n#Programming time = %f sec\n\r",(GetTickCount() - t1)/1000.0);
676 #endif
677 ERR:
678 return ret;
679 }
680
681 /**
682 * @fn spi_flash_erase
683 * @brief Erase from data from SPI flash
684 * @param[IN] u32Offset
685 * Address to write to at the SPI flash
686 * @param[IN] u32Sz
687 * Data size
688 * @return Status of execution
689 * @note Data size is limited by the SPI flash size only
690 * @author M. Abdelmawla
691 * @version 1.0
692 */
spi_flash_erase(uint32 u32Offset,uint32 u32Sz)693 sint8 spi_flash_erase(uint32 u32Offset, uint32 u32Sz)
694 {
695 uint32 i = 0;
696 sint8 ret = M2M_SUCCESS;
697 uint8 tmp = 0;
698 #ifdef PROFILING
699 uint32 t;
700 t = GetTickCount();
701 #endif
702 M2M_PRINT("\r\n>Start erasing...\r\n");
703 for(i = u32Offset; i < (u32Sz +u32Offset); i += (16*FLASH_PAGE_SZ))
704 {
705 ret += spi_flash_write_enable();
706 ret += spi_flash_read_status_reg(&tmp);
707 ret += spi_flash_sector_erase(i + 10);
708 ret += spi_flash_read_status_reg(&tmp);
709 do
710 {
711 if(ret != M2M_SUCCESS) goto ERR;
712 ret += spi_flash_read_status_reg(&tmp);
713 }while(tmp & 0x01);
714
715 }
716 M2M_PRINT("Done\r\n");
717 #ifdef PROFILING
718 M2M_PRINT("#Erase time = %f sec\n", (GetTickCount()-t)/1000.0);
719 #endif
720 ERR:
721 return ret;
722 }
723
724 /**
725 * @fn spi_flash_get_size
726 * @brief Get size of SPI Flash
727 * @return Size of Flash
728 * @author M.S.M
729 * @version 1.0
730 */
spi_flash_get_size(void)731 uint32 spi_flash_get_size(void)
732 {
733 uint32 u32FlashId = 0, u32FlashPwr = 0;
734 static uint32 gu32InernalFlashSize= 0;
735
736 if(!gu32InernalFlashSize)
737 {
738 u32FlashId = spi_flash_rdid();//spi_flash_probe();
739 if(u32FlashId != 0xffffffff)
740 {
741 /*flash size is the third byte from the FLASH RDID*/
742 u32FlashPwr = ((u32FlashId>>16)&0xff) - 0x11; /*2MBIT is the min*/
743 /*That number power 2 to get the flash size*/
744 gu32InernalFlashSize = 1<<u32FlashPwr;
745 M2M_INFO("Flash Size %lu Mb\n",gu32InernalFlashSize);
746 }
747 else
748 {
749 M2M_ERR("Cann't Detect Flash size\n");
750 }
751 }
752
753 return gu32InernalFlashSize;
754 }