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 *)&reg);
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 *)&reg);
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 *)&reg);
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 }