blob: 15141cf743273f1c11fc8856b590e1d9d20b84f6 [file] [log] [blame]
Aubrey.Li3f0606a2007-03-09 13:38:44 +08001/****************************************************************************
2 * SPI flash driver for M25P64
3 ****************************************************************************/
4#include <common.h>
5#include <linux/ctype.h>
Aubrey Li8440bb12007-03-12 00:25:14 +08006#include <asm/io.h>
Mike Frysingerd4d77302008-02-04 19:26:55 -05007#include <asm/mach-common/bits/spi.h>
Aubrey.Li3f0606a2007-03-09 13:38:44 +08008
9#if defined(CONFIG_SPI)
10
11 /*Application definitions */
12
13#define NUM_SECTORS 128 /* number of sectors */
14#define SECTOR_SIZE 0x10000
15#define NOP_NUM 1000
16
17#define COMMON_SPI_SETTINGS (SPE|MSTR|CPHA|CPOL) /*Settings to the SPI_CTL */
18#define TIMOD01 (0x01) /*stes the SPI to work with core instructions */
19
20 /*Flash commands */
21#define SPI_WREN (0x06) /*Set Write Enable Latch */
22#define SPI_WRDI (0x04) /*Reset Write Enable Latch */
23#define SPI_RDSR (0x05) /*Read Status Register */
24#define SPI_WRSR (0x01) /*Write Status Register */
25#define SPI_READ (0x03) /*Read data from memory */
26#define SPI_PP (0x02) /*Program Data into memory */
27#define SPI_SE (0xD8) /*Erase one sector in memory */
28#define SPI_BE (0xC7) /*Erase all memory */
29#define WIP (0x1) /*Check the write in progress bit of the SPI status register */
30#define WEL (0x2) /*Check the write enable bit of the SPI status register */
31
32#define TIMEOUT 350000000
33
34typedef enum {
35 NO_ERR,
36 POLL_TIMEOUT,
37 INVALID_SECTOR,
38 INVALID_BLOCK,
39} ERROR_CODE;
40
41void spi_init_f(void);
42void spi_init_r(void);
43ssize_t spi_read(uchar *, int, uchar *, int);
44ssize_t spi_write(uchar *, int, uchar *, int);
45
46char ReadStatusRegister(void);
47void Wait_For_SPIF(void);
48void SetupSPI(const int spi_setting);
49void SPI_OFF(void);
50void SendSingleCommand(const int iCommand);
51
52ERROR_CODE GetSectorNumber(unsigned long ulOffset, int *pnSector);
53ERROR_CODE EraseBlock(int nBlock);
54ERROR_CODE ReadData(unsigned long ulStart, long lCount, int *pnData);
55ERROR_CODE WriteData(unsigned long ulStart, long lCount, int *pnData);
56ERROR_CODE Wait_For_Status(char Statusbit);
57ERROR_CODE Wait_For_WEL(void);
58
59/* -------------------
60 * Variables
61 * ------------------- */
62
63/* **************************************************************************
64 *
65 * Function: spi_init_f
66 *
67 * Description: Init SPI-Controller (ROM part)
68 *
69 * return: ---
70 *
71 * *********************************************************************** */
72void spi_init_f(void)
73{
74}
75
76/* **************************************************************************
77 *
78 * Function: spi_init_r
79 *
80 * Description: Init SPI-Controller (RAM part) -
81 * The malloc engine is ready and we can move our buffers to
82 * normal RAM
83 *
84 * return: ---
85 *
86 * *********************************************************************** */
87void spi_init_r(void)
88{
89 return;
90}
91
92/****************************************************************************
93 * Function: spi_write
94 **************************************************************************** */
95ssize_t spi_write(uchar * addr, int alen, uchar * buffer, int len)
96{
97 unsigned long offset;
98 int start_block, end_block;
99 int start_byte, end_byte;
100 ERROR_CODE result = NO_ERR;
101 uchar temp[SECTOR_SIZE];
102 int i, num;
103
104 offset = addr[0] << 16 | addr[1] << 8 | addr[2];
105 /* Get the start block number */
106 result = GetSectorNumber(offset, &start_block);
107 if (result == INVALID_SECTOR) {
108 printf("Invalid sector! ");
109 return 0;
110 }
111 /* Get the end block number */
112 result = GetSectorNumber(offset + len - 1, &end_block);
113 if (result == INVALID_SECTOR) {
114 printf("Invalid sector! ");
115 return 0;
116 }
117
118 for (num = start_block; num <= end_block; num++) {
119 ReadData(num * SECTOR_SIZE, SECTOR_SIZE, (int *)temp);
120 start_byte = num * SECTOR_SIZE;
121 end_byte = (num + 1) * SECTOR_SIZE - 1;
122 if (start_byte < offset)
123 start_byte = offset;
124 if (end_byte > (offset + len))
125 end_byte = (offset + len - 1);
126 for (i = start_byte; i <= end_byte; i++)
127 temp[i - num * SECTOR_SIZE] = buffer[i - offset];
128 EraseBlock(num);
129 result = WriteData(num * SECTOR_SIZE, SECTOR_SIZE, (int *)temp);
130 if (result != NO_ERR)
131 return 0;
132 printf(".");
133 }
134 return len;
135}
136
137/****************************************************************************
138 * Function: spi_read
139 **************************************************************************** */
140ssize_t spi_read(uchar * addr, int alen, uchar * buffer, int len)
141{
142 unsigned long offset;
143 offset = addr[0] << 16 | addr[1] << 8 | addr[2];
144 ReadData(offset, len, (int *)buffer);
145 return len;
146}
147
148void SendSingleCommand(const int iCommand)
149{
150 unsigned short dummy;
151
152 /*turns on the SPI in single write mode */
153 SetupSPI((COMMON_SPI_SETTINGS | TIMOD01));
154
155 /*sends the actual command to the SPI TX register */
156 *pSPI_TDBR = iCommand;
Mike Frysingerd4d77302008-02-04 19:26:55 -0500157 SSYNC();
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800158
159 /*The SPI status register will be polled to check the SPIF bit */
160 Wait_For_SPIF();
161
162 dummy = *pSPI_RDBR;
163
164 /*The SPI will be turned off */
165 SPI_OFF();
166
167}
168
169void SetupSPI(const int spi_setting)
170{
171
172 if (icache_status() || dcache_status())
173 udelay(CONFIG_CCLK_HZ / 50000000);
174 /*sets up the PF2 to be the slave select of the SPI */
175 *pSPI_FLG = 0xFB04;
176 *pSPI_BAUD = CONFIG_SPI_BAUD;
177 *pSPI_CTL = spi_setting;
Mike Frysingerd4d77302008-02-04 19:26:55 -0500178 SSYNC();
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800179}
180
181void SPI_OFF(void)
182{
183
184 *pSPI_CTL = 0x0400; /* disable SPI */
185 *pSPI_FLG = 0;
186 *pSPI_BAUD = 0;
Mike Frysingerd4d77302008-02-04 19:26:55 -0500187 SSYNC();
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800188 udelay(CONFIG_CCLK_HZ / 50000000);
189
190}
191
192void Wait_For_SPIF(void)
193{
194 unsigned short dummyread;
195 while ((*pSPI_STAT & TXS)) ;
196 while (!(*pSPI_STAT & SPIF)) ;
197 while (!(*pSPI_STAT & RXS)) ;
198 dummyread = *pSPI_RDBR; /* Read dummy to empty the receive register */
199
200}
201
202ERROR_CODE Wait_For_WEL(void)
203{
204 int i;
205 char status_register = 0;
206 ERROR_CODE ErrorCode = NO_ERR; /* tells us if there was an error erasing flash */
207
208 for (i = 0; i < TIMEOUT; i++) {
209 status_register = ReadStatusRegister();
210 if ((status_register & WEL)) {
211 ErrorCode = NO_ERR; /* tells us if there was an error erasing flash */
212 break;
213 }
214 ErrorCode = POLL_TIMEOUT; /* Time out error */
215 };
216
217 return ErrorCode;
218}
219
220ERROR_CODE Wait_For_Status(char Statusbit)
221{
222 int i;
223 char status_register = 0xFF;
224 ERROR_CODE ErrorCode = NO_ERR; /* tells us if there was an error erasing flash */
225
226 for (i = 0; i < TIMEOUT; i++) {
227 status_register = ReadStatusRegister();
228 if (!(status_register & Statusbit)) {
229 ErrorCode = NO_ERR; /* tells us if there was an error erasing flash */
230 break;
231 }
232 ErrorCode = POLL_TIMEOUT; /* Time out error */
233 };
234
235 return ErrorCode;
236}
237
238char ReadStatusRegister(void)
239{
240 char status_register = 0;
241
242 SetupSPI((COMMON_SPI_SETTINGS | TIMOD01)); /* Turn on the SPI */
243
244 *pSPI_TDBR = SPI_RDSR; /* send instruction to read status register */
Mike Frysingerd4d77302008-02-04 19:26:55 -0500245 SSYNC();
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800246 Wait_For_SPIF(); /*wait until the instruction has been sent */
247 *pSPI_TDBR = 0; /*send dummy to receive the status register */
Mike Frysingerd4d77302008-02-04 19:26:55 -0500248 SSYNC();
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800249 Wait_For_SPIF(); /*wait until the data has been sent */
250 status_register = *pSPI_RDBR; /*read the status register */
251
252 SPI_OFF(); /* Turn off the SPI */
253
254 return status_register;
255}
256
257ERROR_CODE GetSectorNumber(unsigned long ulOffset, int *pnSector)
258{
259 int nSector = 0;
260 ERROR_CODE ErrorCode = NO_ERR;
261
262 if (ulOffset > (NUM_SECTORS * 0x10000 - 1)) {
263 ErrorCode = INVALID_SECTOR;
264 return ErrorCode;
265 }
266
267 nSector = (int)ulOffset / 0x10000;
268 *pnSector = nSector;
269
270 /* ok */
271 return ErrorCode;
272}
273
274ERROR_CODE EraseBlock(int nBlock)
275{
276 unsigned long ulSectorOff = 0x0, ShiftValue;
277 ERROR_CODE ErrorCode = NO_ERR;
278
279 /* if the block is invalid just return */
280 if ((nBlock < 0) || (nBlock > NUM_SECTORS)) {
281 ErrorCode = INVALID_BLOCK; /* tells us if there was an error erasing flash */
282 return ErrorCode;
283 }
284 /* figure out the offset of the block in flash */
285 if ((nBlock >= 0) && (nBlock < NUM_SECTORS)) {
286 ulSectorOff = (nBlock * SECTOR_SIZE);
287
288 } else {
289 ErrorCode = INVALID_BLOCK; /* tells us if there was an error erasing flash */
290 return ErrorCode;
291 }
292
293 /* A write enable instruction must previously have been executed */
294 SendSingleCommand(SPI_WREN);
295
296 /*The status register will be polled to check the write enable latch "WREN" */
297 ErrorCode = Wait_For_WEL();
298
299 if (POLL_TIMEOUT == ErrorCode) {
300 printf("SPI Erase block error\n");
301 return ErrorCode;
302 } else
303 /*Turn on the SPI to send single commands */
304 SetupSPI((COMMON_SPI_SETTINGS | TIMOD01));
305
306 /* Send the erase block command to the flash followed by the 24 address */
307 /* to point to the start of a sector. */
308 *pSPI_TDBR = SPI_SE;
Mike Frysingerd4d77302008-02-04 19:26:55 -0500309 SSYNC();
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800310 Wait_For_SPIF();
311 ShiftValue = (ulSectorOff >> 16); /* Send the highest byte of the 24 bit address at first */
312 *pSPI_TDBR = ShiftValue;
Mike Frysingerd4d77302008-02-04 19:26:55 -0500313 SSYNC();
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800314 Wait_For_SPIF(); /* Wait until the instruction has been sent */
315 ShiftValue = (ulSectorOff >> 8); /* Send the middle byte of the 24 bit address at second */
316 *pSPI_TDBR = ShiftValue;
Mike Frysingerd4d77302008-02-04 19:26:55 -0500317 SSYNC();
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800318 Wait_For_SPIF(); /* Wait until the instruction has been sent */
319 *pSPI_TDBR = ulSectorOff; /* Send the lowest byte of the 24 bit address finally */
Mike Frysingerd4d77302008-02-04 19:26:55 -0500320 SSYNC();
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800321 Wait_For_SPIF(); /* Wait until the instruction has been sent */
322
323 /*Turns off the SPI */
324 SPI_OFF();
325
326 /* Poll the status register to check the Write in Progress bit */
327 /* Sector erase takes time */
328 ErrorCode = Wait_For_Status(WIP);
329
330 /* block erase should be complete */
331 return ErrorCode;
332}
333
334/*****************************************************************************
335* ERROR_CODE ReadData()
336*
337* Read a value from flash for verify purpose
338*
339* Inputs: unsigned long ulStart - holds the SPI start address
340* int pnData - pointer to store value read from flash
341* long lCount - number of elements to read
342***************************************************************************** */
343ERROR_CODE ReadData(unsigned long ulStart, long lCount, int *pnData)
344{
345 unsigned long ShiftValue;
346 char *cnData;
347 int i;
348
349 cnData = (char *)pnData; /* Pointer cast to be able to increment byte wise */
350
351 /* Start SPI interface */
352 SetupSPI((COMMON_SPI_SETTINGS | TIMOD01));
353
354 *pSPI_TDBR = SPI_READ; /* Send the read command to SPI device */
Mike Frysingerd4d77302008-02-04 19:26:55 -0500355 SSYNC();
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800356 Wait_For_SPIF(); /* Wait until the instruction has been sent */
357 ShiftValue = (ulStart >> 16); /* Send the highest byte of the 24 bit address at first */
358 *pSPI_TDBR = ShiftValue; /* Send the byte to the SPI device */
Mike Frysingerd4d77302008-02-04 19:26:55 -0500359 SSYNC();
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800360 Wait_For_SPIF(); /* Wait until the instruction has been sent */
361 ShiftValue = (ulStart >> 8); /* Send the middle byte of the 24 bit address at second */
362 *pSPI_TDBR = ShiftValue; /* Send the byte to the SPI device */
Mike Frysingerd4d77302008-02-04 19:26:55 -0500363 SSYNC();
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800364 Wait_For_SPIF(); /* Wait until the instruction has been sent */
365 *pSPI_TDBR = ulStart; /* Send the lowest byte of the 24 bit address finally */
Mike Frysingerd4d77302008-02-04 19:26:55 -0500366 SSYNC();
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800367 Wait_For_SPIF(); /* Wait until the instruction has been sent */
368
369 /* After the SPI device address has been placed on the MOSI pin the data can be */
370 /* received on the MISO pin. */
371 for (i = 0; i < lCount; i++) {
372 *pSPI_TDBR = 0; /*send dummy */
Mike Frysingerd4d77302008-02-04 19:26:55 -0500373 SSYNC();
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800374 while (!(*pSPI_STAT & RXS)) ;
375 *cnData++ = *pSPI_RDBR; /*read */
376
377 if ((i >= SECTOR_SIZE) && (i % SECTOR_SIZE == 0))
378 printf(".");
379 }
380
381 SPI_OFF(); /* Turn off the SPI */
382
383 return NO_ERR;
384}
385
386ERROR_CODE WriteFlash(unsigned long ulStartAddr, long lTransferCount,
387 int *iDataSource, long *lWriteCount)
388{
389
390 unsigned long ulWAddr;
391 long lWTransferCount = 0;
392 int i;
393 char iData;
394 char *temp = (char *)iDataSource;
395 ERROR_CODE ErrorCode = NO_ERR; /* tells us if there was an error erasing flash */
396
397 /* First, a Write Enable Command must be sent to the SPI. */
398 SendSingleCommand(SPI_WREN);
399
400 /* Second, the SPI Status Register will be tested whether the */
401 /* Write Enable Bit has been set. */
402 ErrorCode = Wait_For_WEL();
403 if (POLL_TIMEOUT == ErrorCode) {
404 printf("SPI Write Time Out\n");
405 return ErrorCode;
406 } else
407 /* Third, the 24 bit address will be shifted out the SPI MOSI bytewise. */
408 SetupSPI((COMMON_SPI_SETTINGS | TIMOD01)); /* Turns the SPI on */
409 *pSPI_TDBR = SPI_PP;
Mike Frysingerd4d77302008-02-04 19:26:55 -0500410 SSYNC();
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800411 Wait_For_SPIF(); /*wait until the instruction has been sent */
412 ulWAddr = (ulStartAddr >> 16);
413 *pSPI_TDBR = ulWAddr;
Mike Frysingerd4d77302008-02-04 19:26:55 -0500414 SSYNC();
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800415 Wait_For_SPIF(); /*wait until the instruction has been sent */
416 ulWAddr = (ulStartAddr >> 8);
417 *pSPI_TDBR = ulWAddr;
Mike Frysingerd4d77302008-02-04 19:26:55 -0500418 SSYNC();
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800419 Wait_For_SPIF(); /*wait until the instruction has been sent */
420 ulWAddr = ulStartAddr;
421 *pSPI_TDBR = ulWAddr;
Mike Frysingerd4d77302008-02-04 19:26:55 -0500422 SSYNC();
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800423 Wait_For_SPIF(); /*wait until the instruction has been sent */
424 /* Fourth, maximum number of 256 bytes will be taken from the Buffer */
425 /* and sent to the SPI device. */
426 for (i = 0; (i < lTransferCount) && (i < 256); i++, lWTransferCount++) {
427 iData = *temp;
428 *pSPI_TDBR = iData;
Mike Frysingerd4d77302008-02-04 19:26:55 -0500429 SSYNC();
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800430 Wait_For_SPIF(); /*wait until the instruction has been sent */
431 temp++;
432 }
433
434 SPI_OFF(); /* Turns the SPI off */
435
436 /* Sixth, the SPI Write in Progress Bit must be toggled to ensure the */
437 /* programming is done before start of next transfer. */
438 ErrorCode = Wait_For_Status(WIP);
439
440 if (POLL_TIMEOUT == ErrorCode) {
441 printf("SPI Program Time out!\n");
442 return ErrorCode;
443 } else
444
445 *lWriteCount = lWTransferCount;
446
447 return ErrorCode;
448}
449
450ERROR_CODE WriteData(unsigned long ulStart, long lCount, int *pnData)
451{
452
453 unsigned long ulWStart = ulStart;
454 long lWCount = lCount, lWriteCount;
455 long *pnWriteCount = &lWriteCount;
456
457 ERROR_CODE ErrorCode = NO_ERR;
458
459 while (lWCount != 0) {
460 ErrorCode = WriteFlash(ulWStart, lWCount, pnData, pnWriteCount);
461
462 /* After each function call of WriteFlash the counter must be adjusted */
463 lWCount -= *pnWriteCount;
464
465 /* Also, both address pointers must be recalculated. */
466 ulWStart += *pnWriteCount;
467 pnData += *pnWriteCount / 4;
468 }
469
470 /* return the appropriate error code */
471 return ErrorCode;
472}
473
474#endif /* CONFIG_SPI */