blob: c48c3c7c7e22f7beeb4cd2c6639c7adfa1c83a1d [file] [log] [blame]
Aubrey Li26bf7de2007-03-19 01:24:52 +08001/****************************************************************************
2 * SPI flash driver for M25P64
3 ****************************************************************************/
4#include <common.h>
5#include <linux/ctype.h>
6#include <asm/io.h>
Mike Frysingerd4d77302008-02-04 19:26:55 -05007#include <asm/mach-common/bits/spi.h>
Aubrey Li26bf7de2007-03-19 01:24:52 +08008
9#if defined(CONFIG_SPI)
10
11/* Application definitions */
12
Wolfgang Denk1636d1c2007-06-22 23:59:00 +020013#define NUM_SECTORS 128 /* number of sectors */
Aubrey Li26bf7de2007-03-19 01:24:52 +080014#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_FAST_READ (0x0B) /*Read data from memory */
27#define SPI_PP (0x02) /*Program Data into memory */
28#define SPI_SE (0xD8) /*Erase one sector in memory */
29#define SPI_BE (0xC7) /*Erase all memory */
30#define WIP (0x1) /*Check the write in progress bit of the SPI status register */
31#define WEL (0x2) /*Check the write enable bit of the SPI status register */
32
33#define TIMEOUT 350000000
34
35typedef enum {
36 NO_ERR,
37 POLL_TIMEOUT,
38 INVALID_SECTOR,
39 INVALID_BLOCK,
40} ERROR_CODE;
41
42void spi_init_f(void);
43void spi_init_r(void);
44ssize_t spi_read(uchar *, int, uchar *, int);
45ssize_t spi_write(uchar *, int, uchar *, int);
46
47char ReadStatusRegister(void);
48void Wait_For_SPIF(void);
49void SetupSPI(const int spi_setting);
50void SPI_OFF(void);
51void SendSingleCommand(const int iCommand);
52
53ERROR_CODE GetSectorNumber(unsigned long ulOffset, int *pnSector);
54ERROR_CODE EraseBlock(int nBlock);
55ERROR_CODE ReadData(unsigned long ulStart, long lCount, int *pnData);
56ERROR_CODE WriteData(unsigned long ulStart, long lCount, int *pnData);
57ERROR_CODE Wait_For_Status(char Statusbit);
58ERROR_CODE Wait_For_WEL(void);
59
60/*
61 * Function: spi_init_f
62 * Description: Init SPI-Controller (ROM part)
63 * return: ---
64 */
65void spi_init_f(void)
66{
67}
68
69/*
70 * Function: spi_init_r
71 * Description: Init SPI-Controller (RAM part) -
72 * The malloc engine is ready and we can move our buffers to
73 * normal RAM
74 * return: ---
75 */
76void spi_init_r(void)
77{
78 return;
79}
80
81/*
82 * Function: spi_write
83 */
84ssize_t spi_write(uchar * addr, int alen, uchar * buffer, int len)
85{
86 unsigned long offset;
87 int start_block, end_block;
88 int start_byte, end_byte;
89 ERROR_CODE result = NO_ERR;
90 uchar temp[SECTOR_SIZE];
91 int i, num;
92
93 offset = addr[0] << 16 | addr[1] << 8 | addr[2];
94 /* Get the start block number */
95 result = GetSectorNumber(offset, &start_block);
96 if (result == INVALID_SECTOR) {
97 printf("Invalid sector! ");
98 return 0;
99 }
100 /* Get the end block number */
101 result = GetSectorNumber(offset + len - 1, &end_block);
102 if (result == INVALID_SECTOR) {
103 printf("Invalid sector! ");
104 return 0;
105 }
106
107 for (num = start_block; num <= end_block; num++) {
108 ReadData(num * SECTOR_SIZE, SECTOR_SIZE, (int *)temp);
109 start_byte = num * SECTOR_SIZE;
110 end_byte = (num + 1) * SECTOR_SIZE - 1;
111 if (start_byte < offset)
112 start_byte = offset;
113 if (end_byte > (offset + len))
114 end_byte = (offset + len - 1);
115 for (i = start_byte; i <= end_byte; i++)
116 temp[i - num * SECTOR_SIZE] = buffer[i - offset];
117 EraseBlock(num);
118 result = WriteData(num * SECTOR_SIZE, SECTOR_SIZE, (int *)temp);
119 if (result != NO_ERR)
120 return 0;
121 printf(".");
122 }
123 return len;
124}
125
126/*
127 * Function: spi_read
128 */
129ssize_t spi_read(uchar * addr, int alen, uchar * buffer, int len)
130{
131 unsigned long offset;
132 offset = addr[0] << 16 | addr[1] << 8 | addr[2];
133 ReadData(offset, len, (int *)buffer);
134 return len;
135}
136
137void SendSingleCommand(const int iCommand)
138{
139 unsigned short dummy;
140
141 /* turns on the SPI in single write mode */
142 SetupSPI((COMMON_SPI_SETTINGS | TIMOD01));
143
144 /* sends the actual command to the SPI TX register */
145 *pSPI_TDBR = iCommand;
Mike Frysingerd4d77302008-02-04 19:26:55 -0500146 SSYNC();
Aubrey Li26bf7de2007-03-19 01:24:52 +0800147
148 /* The SPI status register will be polled to check the SPIF bit */
149 Wait_For_SPIF();
150
151 dummy = *pSPI_RDBR;
152
153 /* The SPI will be turned off */
154 SPI_OFF();
155
156}
157
158void SetupSPI(const int spi_setting)
159{
160
161 if (icache_status() || dcache_status())
162 udelay(CONFIG_CCLK_HZ / 50000000);
163 /*sets up the PF10 to be the slave select of the SPI */
164 *pPORTF_FER |= (PF10 | PF11 | PF12 | PF13);
165 *pSPI_FLG = 0xFF02;
166 *pSPI_BAUD = CONFIG_SPI_BAUD;
167 *pSPI_CTL = spi_setting;
Mike Frysingerd4d77302008-02-04 19:26:55 -0500168 SSYNC();
Aubrey Li26bf7de2007-03-19 01:24:52 +0800169
170 *pSPI_FLG = 0xFD02;
Mike Frysingerd4d77302008-02-04 19:26:55 -0500171 SSYNC();
Aubrey Li26bf7de2007-03-19 01:24:52 +0800172}
173
174void SPI_OFF(void)
175{
176
177 *pSPI_CTL = 0x0400; /* disable SPI */
178 *pSPI_FLG = 0;
179 *pSPI_BAUD = 0;
Mike Frysingerd4d77302008-02-04 19:26:55 -0500180 SSYNC();
Aubrey Li26bf7de2007-03-19 01:24:52 +0800181 udelay(CONFIG_CCLK_HZ / 50000000);
182
183}
184
185void Wait_For_SPIF(void)
186{
187 unsigned short dummyread;
188 while ((*pSPI_STAT & TXS)) ;
189 while (!(*pSPI_STAT & SPIF)) ;
190 while (!(*pSPI_STAT & RXS)) ;
191 /* Read dummy to empty the receive register */
192 dummyread = *pSPI_RDBR;
193}
194
195ERROR_CODE Wait_For_WEL(void)
196{
197 int i;
198 char status_register = 0;
199 ERROR_CODE ErrorCode = NO_ERR;
200
201 for (i = 0; i < TIMEOUT; i++) {
202 status_register = ReadStatusRegister();
203 if ((status_register & WEL)) {
204 ErrorCode = NO_ERR;
205 break;
206 }
207 ErrorCode = POLL_TIMEOUT; /* Time out error */
208 };
209
210 return ErrorCode;
211}
212
213ERROR_CODE Wait_For_Status(char Statusbit)
214{
215 int i;
216 char status_register = 0xFF;
217 ERROR_CODE ErrorCode = NO_ERR;
218
219 for (i = 0; i < TIMEOUT; i++) {
220 status_register = ReadStatusRegister();
221 if (!(status_register & Statusbit)) {
222 ErrorCode = NO_ERR;
223 break;
224 }
225 ErrorCode = POLL_TIMEOUT; /* Time out error */
226 };
227
228 return ErrorCode;
229}
230
231char ReadStatusRegister(void)
232{
233 char status_register = 0;
234
235 SetupSPI((COMMON_SPI_SETTINGS | TIMOD01)); /* Turn on the SPI */
236
237 *pSPI_TDBR = SPI_RDSR; /* send instruction to read status register */
Mike Frysingerd4d77302008-02-04 19:26:55 -0500238 SSYNC();
Aubrey Li26bf7de2007-03-19 01:24:52 +0800239 Wait_For_SPIF(); /*wait until the instruction has been sent */
240 *pSPI_TDBR = 0; /*send dummy to receive the status register */
Mike Frysingerd4d77302008-02-04 19:26:55 -0500241 SSYNC();
Aubrey Li26bf7de2007-03-19 01:24:52 +0800242 Wait_For_SPIF(); /*wait until the data has been sent */
243 status_register = *pSPI_RDBR; /*read the status register */
244
245 SPI_OFF(); /* Turn off the SPI */
246
247 return status_register;
248}
249
250ERROR_CODE GetSectorNumber(unsigned long ulOffset, int *pnSector)
251{
252 int nSector = 0;
253 ERROR_CODE ErrorCode = NO_ERR;
254
255 if (ulOffset > (NUM_SECTORS * 0x10000 - 1)) {
256 ErrorCode = INVALID_SECTOR;
257 return ErrorCode;
258 }
259
260 nSector = (int)ulOffset / 0x10000;
261 *pnSector = nSector;
262
263 return ErrorCode;
264}
265
266ERROR_CODE EraseBlock(int nBlock)
267{
268 unsigned long ulSectorOff = 0x0, ShiftValue;
269 ERROR_CODE ErrorCode = NO_ERR;
270
271 /* if the block is invalid just return */
272 if ((nBlock < 0) || (nBlock > NUM_SECTORS)) {
273 ErrorCode = INVALID_BLOCK;
274 return ErrorCode;
275 }
276 /* figure out the offset of the block in flash */
277 if ((nBlock >= 0) && (nBlock < NUM_SECTORS)) {
278 ulSectorOff = (nBlock * SECTOR_SIZE);
279
280 } else {
281 ErrorCode = INVALID_BLOCK;
282 return ErrorCode;
283 }
284
285 /* A write enable instruction must previously have been executed */
286 SendSingleCommand(SPI_WREN);
287
288 /* The status register will be polled to check the write enable latch "WREN" */
289 ErrorCode = Wait_For_WEL();
290
291 if (POLL_TIMEOUT == ErrorCode) {
292 printf("SPI Erase block error\n");
293 return ErrorCode;
294 } else
295
296 /* Turn on the SPI to send single commands */
297 SetupSPI((COMMON_SPI_SETTINGS | TIMOD01));
298
299 /*
300 * Send the erase block command to the flash followed by the 24 address
301 * to point to the start of a sector
302 */
303 *pSPI_TDBR = SPI_SE;
Mike Frysingerd4d77302008-02-04 19:26:55 -0500304 SSYNC();
Aubrey Li26bf7de2007-03-19 01:24:52 +0800305 Wait_For_SPIF();
306 /* Send the highest byte of the 24 bit address at first */
307 ShiftValue = (ulSectorOff >> 16);
308 *pSPI_TDBR = ShiftValue;
Mike Frysingerd4d77302008-02-04 19:26:55 -0500309 SSYNC();
Aubrey Li26bf7de2007-03-19 01:24:52 +0800310 /* Wait until the instruction has been sent */
311 Wait_For_SPIF();
312 /* Send the middle byte of the 24 bit address at second */
313 ShiftValue = (ulSectorOff >> 8);
314 *pSPI_TDBR = ShiftValue;
Mike Frysingerd4d77302008-02-04 19:26:55 -0500315 SSYNC();
Aubrey Li26bf7de2007-03-19 01:24:52 +0800316 /* Wait until the instruction has been sent */
317 Wait_For_SPIF();
318 /* Send the lowest byte of the 24 bit address finally */
319 *pSPI_TDBR = ulSectorOff;
Mike Frysingerd4d77302008-02-04 19:26:55 -0500320 SSYNC();
Aubrey Li26bf7de2007-03-19 01:24:52 +0800321 /* Wait until the instruction has been sent */
322 Wait_For_SPIF();
323
324 /* Turns off the SPI */
325 SPI_OFF();
326
327 /* Poll the status register to check the Write in Progress bit */
328 /* Sector erase takes time */
329 ErrorCode = Wait_For_Status(WIP);
330
331 /* block erase should be complete */
332 return ErrorCode;
333}
334
335/*
336 * ERROR_CODE ReadData()
337 * Read a value from flash for verify purpose
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 /* Pointer cast to be able to increment byte wise */
349
350 cnData = (char *)pnData;
351 /* Start SPI interface */
352 SetupSPI((COMMON_SPI_SETTINGS | TIMOD01));
353
354#ifdef CONFIG_SPI_FLASH_FAST_READ
355 /* Send the read command to SPI device */
356 *pSPI_TDBR = SPI_FAST_READ;
357#else
358 /* Send the read command to SPI device */
359 *pSPI_TDBR = SPI_READ;
360#endif
Mike Frysingerd4d77302008-02-04 19:26:55 -0500361 SSYNC();
Aubrey Li26bf7de2007-03-19 01:24:52 +0800362 /* Wait until the instruction has been sent */
363 Wait_For_SPIF();
364 /* Send the highest byte of the 24 bit address at first */
365 ShiftValue = (ulStart >> 16);
366 /* Send the byte to the SPI device */
367 *pSPI_TDBR = ShiftValue;
Mike Frysingerd4d77302008-02-04 19:26:55 -0500368 SSYNC();
Aubrey Li26bf7de2007-03-19 01:24:52 +0800369 /* Wait until the instruction has been sent */
370 Wait_For_SPIF();
371 /* Send the middle byte of the 24 bit address at second */
372 ShiftValue = (ulStart >> 8);
373 /* Send the byte to the SPI device */
374 *pSPI_TDBR = ShiftValue;
Mike Frysingerd4d77302008-02-04 19:26:55 -0500375 SSYNC();
Aubrey Li26bf7de2007-03-19 01:24:52 +0800376 /* Wait until the instruction has been sent */
377 Wait_For_SPIF();
378 /* Send the lowest byte of the 24 bit address finally */
379 *pSPI_TDBR = ulStart;
Mike Frysingerd4d77302008-02-04 19:26:55 -0500380 SSYNC();
Aubrey Li26bf7de2007-03-19 01:24:52 +0800381 /* Wait until the instruction has been sent */
382 Wait_For_SPIF();
383
384#ifdef CONFIG_SPI_FLASH_FAST_READ
385 /* Send dummy for FAST_READ */
386 *pSPI_TDBR = 0;
Mike Frysingerd4d77302008-02-04 19:26:55 -0500387 SSYNC();
Aubrey Li26bf7de2007-03-19 01:24:52 +0800388 /* Wait until the instruction has been sent */
389 Wait_For_SPIF();
390#endif
391
392 /* After the SPI device address has been placed on the MOSI pin the data can be */
393 /* received on the MISO pin. */
394 for (i = 0; i < lCount; i++) {
395 *pSPI_TDBR = 0;
Mike Frysingerd4d77302008-02-04 19:26:55 -0500396 SSYNC();
Aubrey Li26bf7de2007-03-19 01:24:52 +0800397 while (!(*pSPI_STAT & RXS)) ;
398 *cnData++ = *pSPI_RDBR;
399
400 if ((i >= SECTOR_SIZE) && (i % SECTOR_SIZE == 0))
401 printf(".");
402 }
403
404 /* Turn off the SPI */
405 SPI_OFF();
406
407 return NO_ERR;
408}
409
410ERROR_CODE WriteFlash(unsigned long ulStartAddr, long lTransferCount,
411 int *iDataSource, long *lWriteCount)
412{
413
414 unsigned long ulWAddr;
415 long lWTransferCount = 0;
416 int i;
417 char iData;
418 char *temp = (char *)iDataSource;
419 ERROR_CODE ErrorCode = NO_ERR;
420
421 /* First, a Write Enable Command must be sent to the SPI. */
422 SendSingleCommand(SPI_WREN);
423
424 /*
425 * Second, the SPI Status Register will be tested whether the
426 * Write Enable Bit has been set
427 */
428 ErrorCode = Wait_For_WEL();
429 if (POLL_TIMEOUT == ErrorCode) {
430 printf("SPI Write Time Out\n");
431 return ErrorCode;
432 } else
433 /* Third, the 24 bit address will be shifted out
434 * the SPI MOSI bytewise.
435 * Turns the SPI on
436 */
437 SetupSPI((COMMON_SPI_SETTINGS | TIMOD01));
438 *pSPI_TDBR = SPI_PP;
Mike Frysingerd4d77302008-02-04 19:26:55 -0500439 SSYNC();
Aubrey Li26bf7de2007-03-19 01:24:52 +0800440 /*wait until the instruction has been sent */
441 Wait_For_SPIF();
442 ulWAddr = (ulStartAddr >> 16);
443 *pSPI_TDBR = ulWAddr;
Mike Frysingerd4d77302008-02-04 19:26:55 -0500444 SSYNC();
Aubrey Li26bf7de2007-03-19 01:24:52 +0800445 /*wait until the instruction has been sent */
446 Wait_For_SPIF();
447 ulWAddr = (ulStartAddr >> 8);
448 *pSPI_TDBR = ulWAddr;
Mike Frysingerd4d77302008-02-04 19:26:55 -0500449 SSYNC();
Aubrey Li26bf7de2007-03-19 01:24:52 +0800450 /*wait until the instruction has been sent */
451 Wait_For_SPIF();
452 ulWAddr = ulStartAddr;
453 *pSPI_TDBR = ulWAddr;
Mike Frysingerd4d77302008-02-04 19:26:55 -0500454 SSYNC();
Aubrey Li26bf7de2007-03-19 01:24:52 +0800455 /*wait until the instruction has been sent */
456 Wait_For_SPIF();
457 /*
458 * Fourth, maximum number of 256 bytes will be taken from the Buffer
459 * and sent to the SPI device.
460 */
461 for (i = 0; (i < lTransferCount) && (i < 256); i++, lWTransferCount++) {
462 iData = *temp;
463 *pSPI_TDBR = iData;
Mike Frysingerd4d77302008-02-04 19:26:55 -0500464 SSYNC();
Aubrey Li26bf7de2007-03-19 01:24:52 +0800465 /*wait until the instruction has been sent */
466 Wait_For_SPIF();
467 temp++;
468 }
469
470 /* Turns the SPI off */
471 SPI_OFF();
472
473 /*
474 * Sixth, the SPI Write in Progress Bit must be toggled to ensure the
475 * programming is done before start of next transfer
476 */
477 ErrorCode = Wait_For_Status(WIP);
478
479 if (POLL_TIMEOUT == ErrorCode) {
480 printf("SPI Program Time out!\n");
481 return ErrorCode;
482 } else
483
484 *lWriteCount = lWTransferCount;
485
486 return ErrorCode;
487}
488
489ERROR_CODE WriteData(unsigned long ulStart, long lCount, int *pnData)
490{
491
492 unsigned long ulWStart = ulStart;
493 long lWCount = lCount, lWriteCount;
494 long *pnWriteCount = &lWriteCount;
495
496 ERROR_CODE ErrorCode = NO_ERR;
497
498 while (lWCount != 0) {
499 ErrorCode = WriteFlash(ulWStart, lWCount, pnData, pnWriteCount);
500
501 /*
502 * After each function call of WriteFlash the counter
503 * must be adjusted
504 */
505 lWCount -= *pnWriteCount;
506
507 /* Also, both address pointers must be recalculated. */
508 ulWStart += *pnWriteCount;
509 pnData += *pnWriteCount / 4;
510 }
511
512 /* return the appropriate error code */
513 return ErrorCode;
514}
515
516#endif /* CONFIG_SPI */