1 //==========================================================================
5 // SPI NOR flash support
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //========================================================================*/
42 #include <pkgconf/hal.h>
43 #include <pkgconf/system.h>
45 #include CYGHWR_MEMORY_LAYOUT_H
46 #include <cyg/hal/hal_io.h>
47 #define _FLASH_PRIVATE_
48 #include <cyg/io/flash.h>
50 #include <cyg/io/imx_spi.h>
51 #include <cyg/io/imx_spi_nor.h>
53 static unsigned char g_tx_buf[256];
54 static unsigned char g_rx_buf[256];
55 static int spi_nor_init_ok;
57 #define WRITE_ENABLE() spi_nor_cmd_1byte(WREN)
58 #define WRITE_DISABLE() spi_nor_cmd_1byte(WRDI)
59 #define ENABLE_WRITE_STATUS() spi_nor_cmd_1byte(EWSR)
61 #ifndef MXCFLASH_SELECT_MULTI
62 void flash_query(void* data)
64 void spi_norflash_query(void* data)
68 unsigned char *ptr = (unsigned char *)data;
70 g_tx_buf[3] = JEDEC_ID;
71 if (spi_nor_xfer(&imx_spi_nor, g_tx_buf, tmp, 4) != 0) {
74 diag_printf("JEDEC ID: 0x%02x:0x%02x:0x%02x\n", tmp[2], tmp[1], tmp[0]);
80 #ifndef MXCFLASH_SELECT_MULTI
81 int flash_program_buf(void* addr, void* data, int len)
83 int spi_norflash_program_buf(void* addr, void* data, int len)
86 return spi_nor_program_buf(addr, data, len);
89 #ifndef MXCFLASH_SELECT_MULTI
90 int flash_erase_block(void* block, unsigned int size)
92 int spi_norflash_erase_block(void* block, unsigned int size)
95 return spi_nor_erase_block(block, size);
98 #ifndef MXCFLASH_SELECT_MULTI
99 bool flash_code_overlaps(void *start, void *end)
101 bool spi_norflash_code_overlaps(void *start, void *end)
104 extern unsigned char _stext[], _etext[];
106 return ((((unsigned long)&_stext >= (unsigned long)start) &&
107 ((unsigned long)&_stext < (unsigned long)end)) ||
108 (((unsigned long)&_etext >= (unsigned long)start) &&
109 ((unsigned long)&_etext < (unsigned long)end)));
112 #ifndef MXCFLASH_SELECT_MULTI
113 int flash_hwr_map_error(int e)
115 int spi_norflash_hwr_map_error(int e)
121 //----------------------------------------------------------------------------
122 // Now that device properties are defined, include magic for defining
123 // accessor type and constants.
124 #include <cyg/io/flash_dev.h>
126 // Information about supported devices
127 typedef struct flash_dev_info {
129 cyg_uint8 device_id2;
130 cyg_uint8 device_id3;
131 cyg_uint8 device_id4;
132 cyg_uint32 block_size;
133 cyg_int32 block_count;
134 cyg_uint32 device_size;
135 cyg_uint32 fis_start_addr;
136 cyg_uint8 vendor_info[96];
137 } __attribute__((aligned(4),packed))flash_dev_info_t;
139 static const flash_dev_info_t* flash_dev_info;
140 static const flash_dev_info_t supported_devices[] = {
141 #include <cyg/io/spi_nor_parts.inl>
144 #define NUM_DEVICES (sizeof(supported_devices)/sizeof(flash_dev_info_t))
146 #define ASSERT_SPI_NOR_INIT() \
148 if (spi_nor_init(&imx_spi_nor) != 0) { \
149 diag_printf("Error: failed to initialize SPI NOR\n"); \
155 #ifndef MXCFLASH_SELECT_MULTI
158 spi_norflash_hwr_init(void)
164 if (!spi_nor_init_ok) {
165 diag_printf("Initializing SPI-NOR flash...\n");
166 if (spi_nor_init(&imx_spi_nor) != 0) {
167 diag_printf("Error: failed to initialize SPI NOR\n");
172 // Look through table for device data
174 flash_dev_info = supported_devices;
175 for (i = 0; i < NUM_DEVICES; i++) {
176 if ((flash_dev_info->device_id == id[0]) &&
177 (flash_dev_info->device_id2 == id[1]) &&
178 (flash_dev_info->device_id3 == id[2]))
183 // Do we find the device? If not, return error.
184 if (NUM_DEVICES == i) {
185 diag_printf("Unrecognized SPI NOR part: 0x%02x, 0x%02x, 0x%02x\n",
186 id[0], id[1], id[2]);
187 return FLASH_ERR_DRV_WRONG_PART;
190 // Hard wired for now
191 flash_info.block_size = flash_dev_info->block_size;
192 flash_info.blocks = flash_dev_info->block_count;
193 flash_info.start = (void *)0;
194 flash_info.end = (void *)flash_dev_info->device_size;
196 diag_printf("SPI NOR: block_size=0x%x, blocks=0x%x, start=%p, end=%p\n",
197 flash_info.block_size, flash_info.blocks,
198 flash_info.start, flash_info.end);
203 // used by redboot/current/src/flash.c
204 int mxc_spi_nor_fis_start(void)
206 return (flash_dev_info->fis_start_addr);
209 static int spi_nor_cmd_1byte(unsigned char cmd)
212 if (spi_nor_xfer(&imx_spi_nor, g_tx_buf, g_rx_buf, 1) != 0) {
213 diag_printf("Error: %s(): %d\n", __FUNCTION__, __LINE__);
220 * Read from SPI NOR at src address to RAM at dest with len bytes
221 * @param src source address in the flash
222 * @param dest destination address in the RAM
223 * @param len # of bytes to copy
225 int spi_nor_read(void *src, void *dest, int len)
227 unsigned int *cmd = (unsigned int *)g_tx_buf;
228 unsigned int max_rx_sz = imx_spi_nor.fifo_sz - 4; // max rx bytes per burst
229 unsigned char *d_buf = (unsigned char *) dest;
230 unsigned char *s_buf;
233 imx_spi_nor.us_delay = 100;
234 diag_printf1("%s(from flash=%p to ram=%p len=0x%x)\n", __FUNCTION__,
240 *cmd = (READ << 24) | ((unsigned int)src & 0x00FFFFFF);
244 imx_spi_nor.us_delay = 0;
247 if (len < max_rx_sz) {
248 diag_printf1("last read len=0x%x\n", len);
249 // deal with the last read
250 if (spi_nor_xfer(&imx_spi_nor, g_tx_buf, g_rx_buf, len + 4) != 0) {
251 diag_printf("Error: %s(%d): failed\n", __FILE__, __LINE__);
254 s_buf = g_rx_buf + 4; // throw away 4 bytes (5th received bytes is real)
255 // now adjust the endianness
256 for (i = len; i >= 0; i -= 4, s_buf += 4) {
268 imx_spi_nor.us_delay = 0;
278 // now grab max_rx_sz data (+4 is needed due to 4-throw away bytes
279 if (spi_nor_xfer(&imx_spi_nor, g_tx_buf, g_rx_buf, max_rx_sz + 4) != 0) {
280 diag_printf("Error: %s(%d): failed\n", __FILE__, __LINE__);
283 s_buf = g_rx_buf + 4; // throw away 4 bytes (5th received bytes is real)
284 // now adjust the endianness
285 for (i = 0; i < max_rx_sz; i += 4, s_buf += 4) {
291 *cmd += max_rx_sz; // increase # of bytes in NOR address as cmd == g_tx_buf
292 len -= max_rx_sz; // # of bytes left
294 diag_printf1("d_buf=%p, g_rx_buf=%p, len=0x%x\n", d_buf, g_rx_buf, len);
297 imx_spi_nor.us_delay = 0;
300 static int spi_nor_program_1byte(unsigned char data, void *addr)
302 unsigned int addr_val = (unsigned int) addr;
304 // need to do write-enable command
305 if (WRITE_ENABLE() != 0) {
306 diag_printf("Error : %d\n", __LINE__);
309 g_tx_buf[0] = BYTE_PROG; // need to skip bytes 1, 2, 3
311 g_tx_buf[5] = addr_val & 0xFF;
312 g_tx_buf[6] = (addr_val >> 8) & 0xFF;
313 g_tx_buf[7] = (addr_val >> 16) & 0xFF;
315 diag_printf("0x%x: 0x%x\n", *(unsigned int*)g_tx_buf, *(unsigned int*)(g_tx_buf + 4));
316 diag_printf("addr=0x%x\n", addr_val);
318 if (spi_nor_xfer(&imx_spi_nor, g_tx_buf, g_rx_buf, 5) != 0) {
319 diag_printf("Error: %s(%d): failed\n", __FILE__, __LINE__);
323 while (spi_nor_status() & RDSR_BUSY) {
329 * program data from RAM to flash
330 * @param addr destination address in flash
331 * @param data source address in RAM
332 * @param len # of bytes to program
333 * Note: - when starting AAI programming,
334 * 1) the starting addr has to be 16-bit aligned
335 * 2) the prog len has to be even number of bytes
337 int spi_nor_program_buf(void *addr, void *data, int len)
339 unsigned int d_addr = (unsigned int) addr;
340 unsigned char *s_buf = (unsigned char *) data;
345 diag_printf1("%s(flash addr=%p, ram=%p, len=0x%x)\n", __FUNCTION__, addr, data, len);
346 imx_spi_nor.us_delay = 0;
348 if (ENABLE_WRITE_STATUS() != 0 || spi_nor_write_status(0) != 0) {
349 diag_printf("Error: %s: %d\n", __FUNCTION__, __LINE__);
353 if ((d_addr & 1) != 0) {
355 if (spi_nor_program_1byte(s_buf[0], (void *)d_addr) != 0) {
356 diag_printf("Error: %s(%d)\n", __FUNCTION__, __LINE__);
365 // need to do write-enable command
366 if (WRITE_ENABLE() != 0) {
367 diag_printf("Error : %d\n", __LINE__);
371 // These two bytes write will be copied to txfifo first with
372 // g_tx_buf[1] being shifted out and followed by g_tx_buf[0].
373 // The reason for this is we will specify burst len=6. So SPI will
374 // do this kind of data movement.
375 g_tx_buf[0] = d_addr >> 16;
376 g_tx_buf[1] = AAI_PROG; // need to skip bytes 1, 2
377 // byte shifted order is: 7, 6, 5, 4
378 g_tx_buf[4] = s_buf[1];
379 g_tx_buf[5] = s_buf[0];
380 g_tx_buf[6] = d_addr;
381 g_tx_buf[7] = d_addr >> 8;
382 if (spi_nor_xfer(&imx_spi_nor, g_tx_buf, g_rx_buf, 6) != 0) {
383 diag_printf("Error: %s(%d): failed\n", __FILE__, __LINE__);
387 while (spi_nor_status() & RDSR_BUSY) {
390 for (d_addr += 2, s_buf += 2, len -= 2 ;
392 d_addr += 2, s_buf += 2, len -= 2) {
393 // byte shifted order is: 2,1,0
394 g_tx_buf[2] = AAI_PROG;
395 g_tx_buf[1] = s_buf[0];
396 g_tx_buf[0] = s_buf[1];
398 if (spi_nor_xfer(&imx_spi_nor, g_tx_buf, g_rx_buf, 3) != 0) {
399 diag_printf("Error: %s(%d): failed\n", __FILE__, __LINE__);
403 while (spi_nor_status() & RDSR_BUSY) {
405 if ((len % flash_dev_info->block_size) == 0) {
410 while (spi_nor_status() & RDSR_BUSY) {
413 if (WRITE_ENABLE() != 0) {
414 diag_printf("Error : %d\n", __LINE__);
418 // need to do write-enable command
420 if (spi_nor_program_1byte(s_buf[0], (void *)d_addr) != 0) {
421 diag_printf("Error: %s(%d)\n", __FUNCTION__, __LINE__);
428 static int spi_nor_status(void)
431 if (spi_nor_xfer(&imx_spi_nor, g_tx_buf, g_rx_buf, 2) != 0) {
432 diag_printf("Error: %s(): %d\n", __FUNCTION__, __LINE__);
439 * Write 'val' to flash WRSR (write status register)
441 static int spi_nor_write_status(unsigned char val)
445 if (spi_nor_xfer(&imx_spi_nor, g_tx_buf, g_rx_buf, 2) != 0) {
446 diag_printf("Error: %s(): %d\n", __FUNCTION__, __LINE__);
453 * Erase a block_size data from block_addr offset in the flash
455 int spi_nor_erase_block(void* block_addr, unsigned int block_size)
457 unsigned int *cmd = (unsigned int *)g_tx_buf;
458 unsigned int addr = (unsigned int) block_addr;
460 imx_spi_nor.us_delay = 0;
462 if (block_size != SZ_64K && block_size != SZ_32K && block_size != SZ_4K) {
463 diag_printf("Error - block_size is not 64kB: 0x%x\n", block_size);
467 if ((addr & (block_size -1)) != 0) {
468 diag_printf("Error - block_addr is not 64kB aligned: %p\n", block_addr);
471 if (ENABLE_WRITE_STATUS() != 0 || spi_nor_write_status(0) != 0) {
472 diag_printf("Error: %s: %d\n", __FUNCTION__, __LINE__);
476 // need to do write-enable command
477 if (WRITE_ENABLE() != 0) {
478 diag_printf("Error : %d\n", __LINE__);
482 if (block_size == SZ_64K) {
483 *cmd = (ERASE_64K << 24) | (addr & 0x00FFFFFF);
484 } else if (block_size == SZ_32K) {
485 *cmd = (ERASE_32K << 24) | (addr & 0x00FFFFFF);
486 } else if (block_size == SZ_4K) {
487 *cmd = (ERASE_4K << 24) | (addr & 0x00FFFFFF);
490 // now do the block erase
491 if (spi_nor_xfer(&imx_spi_nor, g_tx_buf, g_rx_buf, 4) != 0) {
495 while (spi_nor_status() & RDSR_BUSY) {
501 * Erase a variable bytes data from SPI NOR flash for 64K blocks
502 * @param block_addr starting addresss in the SPI NOR flash
503 * @param size # of bytes to erase
505 int spi_nor_erase_64k(void* block_addr, unsigned int size)
507 unsigned int addr = (unsigned int) block_addr;
509 if ((size % SZ_64K) != 0 || size == 0) {
510 diag_printf("Error: size (0x%x) is not integer multiples of 64kB(0x10000)\n", size);
513 if ((addr & (SZ_64K -1)) != 0) {
514 diag_printf("Error - addr is not 64kB(0x10000) aligned: %p\n", block_addr);
517 for (; size > 0; size -= SZ_64K, addr += SZ_64K) {
518 if (spi_nor_erase_block((void *)addr, SZ_64K) != 0) {
519 diag_printf("Error: spi_nor_erase_64k(): %d\n", __LINE__);
526 void spi_nor_setup(void)
528 if (!spi_nor_init_ok) {
529 diag_printf("Initializing SPI-NOR flash...\n");
530 if (spi_nor_init(&imx_spi_nor) != 0) {
531 diag_printf("Error: failed to initialize SPI NOR\n");
537 RedBoot_init(spi_nor_setup, RedBoot_INIT_PRIO(6800));
539 ////////////////////////////// commands ///////////////////
540 static void do_spi_nor_op(int argc, char *argv[]);
541 RedBoot_cmd("spiflash",
542 "Read/Write/Erase SPI NOR flash",
543 "<ram-addr> <flash-addr> <len-bytes> <r/w/e>",
547 static void do_spi_nor_op(int argc,char *argv[])
549 unsigned int ram, flash, len;
553 if (argc == 1 || argc != 5) {
554 diag_printf("\tRead: spiflash <ram-addr> <flash-addr> <len-bytes> <r>\n");
555 diag_printf("\tWrite: spiflash <ram-addr> <flash-addr> <len-bytes> <w>\n");
556 diag_printf("\tErase: spiflash <ram-addr> <flash-addr> <len-bytes> <e>\n");
557 diag_printf(" NOTE: For erase, the ram-addr is ignored\n");
561 if (!parse_num(*(&argv[1]), (unsigned long *)&ram, &argv[1], ":")) {
562 diag_printf("Error: Invalid ram parameter\n");
566 if (!parse_num(*(&argv[2]), (unsigned long *)&flash, &argv[2], ":")) {
567 diag_printf("Error: Invalid flash parameter\n");
571 if (!parse_num(*(&argv[3]), (unsigned long *)&len, &argv[3], ":")) {
572 diag_printf("Error: Invalid length parameter\n");
580 diag_printf("Reading SPI NOR flash 0x%x [0x%x bytes] -> ram 0x%x\n", flash, len, ram);
581 stat = spi_nor_read((void *)flash, (void *)ram, len);
585 diag_printf("Writing SPI NOR flash 0x%x [0x%x bytes] <- ram 0x%x\n", flash, len, ram);
586 stat = spi_nor_program_buf((void *)flash, (void *)ram, len);
590 diag_printf("Erasing SPI NOR flash 0x%x [0x%x bytes]\n", flash, len);
591 stat = spi_nor_erase_64k((void *)flash, len);
594 diag_printf("Error: unknown operation: 0x%02x\n", op);
596 diag_printf("%s\n\n", (stat == 0)? "SUCCESS": "FAILED");