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