📄 flash_spi.c
字号:
/* * Copyright (c) 2006 Atmark Techno, Inc. All Rights Reserved. * Yasushi SHOJI <yashi@atmark-techno.com> * * Commands to program STMicroelectronics M25P64 via Xilinx * OPB-SPI. SPI bus and flash command is not separated right now. we * will do so when we support another bus controller and/or flash chip * with difference command format. */#include <target/buffer.h>#include <target/io.h>#include <target/herrno.h>#include <target/scan.h>#include <target/flash.h>#include <arch/flash_spi.h>/* Write In Progress(WIP) wait-timeout */#define SPI_TIMEOUT 0x100000/* Proto-type declarations */static u8 spi_read_status(void);static void spi_set_cs(u32);static void spi_write8(u8);static void spi_write24(u32);static u8 spi_read8(void);static u32 spi_read24(void);#ifdef FLASH_SPI_DEBUGstatic void dump_reg(void){ hprintf("register dump\n"); hprintf("reset: 0x%x\n", read32(REG_IPIF_SOFT_RESET)); hprintf("cr : 0x%x\n", read32(REG_SPICR)); hprintf("sr : 0x%x\n", read32(REG_SPISR)); hprintf("ssr : 0x%x\n", read32(REG_SPISSR)); hprintf("tx : 0x%x\n", read32(REG_TX_FIFO_OCY)); hprintf("rx : 0x%x\n", read32(REG_RX_FIFO_OCY)); hprintf("dgie : 0x%x\n", read32(REG_DGIE)); hprintf("isr : 0x%x\n", read32(REG_IPISR)); hprintf("er : 0x%x\n", read32(REG_IPIER));}static void dump_spi_data(u32 addr, u32 size){ int i; u32 spi_addr = addr & 0x00FFFFFF; hprintf("data dump: 0x%x\n", addr); spi_set_cs(1); spi_write8(FAST_READ); spi_write24(spi_addr); spi_write8(DUMMY); for(i=0;i<size;i++){ if(i%16 == 0){ hprintf("0x%x: ", spi_addr + i); } hprintf("%b ", spi_read8()); if(i%16 == 15){ hprintf("\n"); } } spi_set_cs(0); if(i%16 != 0){ hprintf("\n"); }}#endif/** * select which cs (chip select) line to activate */inline static void spi_set_cs(u32 cs){ write32(REG_SPISSR, ~cs); write32(REG_SPICR, SPICR_MASTER|SPICR_SPE); write32(REG_SPICR, SPICR_MSSSAE|SPICR_MASTER|SPICR_SPE);}inline static int spi_is_rx_empty(void){ return read32(REG_SPISR) & SPISR_RX_EMPTY;}inline static int spi_is_tx_empty(void){ return read32(REG_SPISR) & SPISR_TX_EMPTY;}inline static void __spi_write(u8 v){ write32(REG_SPIDTR, v);}inline static u8 __spi_read(void){ return read32(REG_SPIDRR);}inline static void spi_write8(u8 v){ while (!spi_is_tx_empty()); __spi_write(v); while (spi_is_rx_empty()); __spi_read();}inline static u8 spi_read8(void){ while (!spi_is_tx_empty()); __spi_write(DUMMY); while (spi_is_rx_empty()); return __spi_read();}inline static void spi_write24(u32 data){ spi_write8((data>>16) & 0xff); spi_write8((data>> 8) & 0xff); spi_write8(data & 0xff);}inline static u32 spi_read24(void){ return (spi_read8()<<16) | (spi_read8()<<8) | spi_read8();}static void spi_write_enable(void){ spi_set_cs(1); spi_write8(WREN); spi_set_cs(0);}#if 0 /* unused */static void spi_write_disable(void){ spi_set_cs(1); spi_write8(WRDI); spi_set_cs(0);}#endifstatic u32 spi_wait_busy(void){ int i; for(i = 0; i < SPI_TIMEOUT; i++){ if(!(spi_read_status() & RDSR_WIP)) break; } if(i == SPI_TIMEOUT){#ifdef FLASH_SPI_DEBUG hprintf("wait busy - timeout\n");#endif return -1; } return 0;}static u8 spi_read_status(void){ u8 ret; spi_set_cs(1); spi_write8(RDSR); ret = spi_read8(); spi_set_cs(0); return ret;}#if 0 /* unused */static void spi_write_status(u8 v){ spi_set_cs(1); spi_write8(WRSR); spi_write8(v); spi_set_cs(0); spi_wait_busy();}#endifstatic u32 spi_read_id(void){ u32 ret; spi_set_cs(1); spi_write8(RDID); ret = spi_read24(); spi_set_cs(0); return ret;}inline u8 flash_spi_read_byte(u32 from){ u8 data; spi_set_cs(1); spi_write8(FAST_READ); spi_write24(from); spi_write8(DUMMY); data = spi_read8(); spi_set_cs(0); return data;}u32 flash_spi_copy_to_dram(const u32 from, const u32 to, const u32 size){ int i; u8 *ram_addr = (u8 *)to; spi_set_cs(1); spi_write8(FAST_READ); spi_write24(from & 0x00FFFFFF); spi_write8(DUMMY); for(i = 0; i < size; i++){ ram_addr[i] = spi_read8(); } spi_set_cs(0); return size;}#if 0 /* unused */static int spi_page_verify(const u32 data, const u32 addr, const u32 size){ int i; int ret; char *tmp = (char *)data; if (size > 256) return -1; spi_set_cs(1); spi_write8(FAST_READ); spi_write24(addr & 0x00FFFFFF); spi_write8(DUMMY); for(i = 0, ret = 0; i < size; i++){ if (tmp[i] != spi_read8()){ ret = -1; break; } } spi_set_cs(0); return ret;}#endifstatic int spi_page_program(const u32 data, const u32 addr, const u32 size){ int i; char *tmp = (char *)data; if (size > 256) return -1; spi_write_enable(); spi_set_cs(1); spi_write8(PP); spi_write24(addr & 0x00FFFFFF); for(i = 0; i < size; i++){ spi_write8(tmp[i]); } spi_set_cs(0); spi_wait_busy(); return 0;}int flash_spi_program(const u32 from, const u32 to, const u32 size){ int i; u32 remain = size; u32 program_size; if(from & UNALIGNED_MASK) return -H_EALIGN; if(to & UNALIGNED_MASK) return -H_EALIGN; for(i = 0; remain > 0; i++){ if(remain > 256){ program_size = 256; }else{ program_size = remain; } spi_page_program(from + i * 256, to + i * 256, program_size); remain -= program_size; } return 0;}static int spi_sector_erase(u32 sector){ spi_write_enable(); spi_set_cs(1); spi_write8(SE); spi_write24(sector & 0x00FFFFFF); spi_set_cs(0); spi_wait_busy(); return 0;}int flash_spi_erase(const u32 erase_addr){ u32 addr = (erase_addr & ~UNALIGNED_MASK); spi_sector_erase(addr); return 0;}u32 flash_spi_get_id(const u32 base_addr){ return spi_read_id();}#if 0 /* unused */static int spi_set_protect_mode(u8 mode){ if((mode < 0) || (mode > 0x7) return -1; spi_write_enable(); spi_write_status((mode & 0x7) << 2); return 0;}static u32 spi_get_protect_mode(void){ return (spi_read_status() >> 2) & 0x7;}#endif /* unused */int flash_spi_get_size(const u32 base_addr){ u32 id = flash_spi_get_id(0); u16 mid, did; mid = (id >> 16) & 0xffff; did = id & 0xffff; switch(mid){ case FLASH_MID_ST: switch(did){ case FLASH_DID_ST_M25P64: return FLASH_8MiB; default: return -1; } break; default: return -1; }}int flash_spi_initialize(const u32 base_addr){ /* disable/reset everything */ /* write32(REG_IPIF_SOFT_RESET); */ write32(REG_SPICR, SPICR_MTI|SPICR_RX_FIFO_RESET|SPICR_TX_FIFO_RESET); /* disable interrupt, and ack all to clear any bits */ write32(REG_DGIE, 0x0); write32(REG_IPIER, 0x0); write32(REG_IPISR, read32(REG_IPISR)); /* deselect all slaves */ write32(REG_SPISSR, 0xffffffff); /* re-enable */ write32(REG_SPICR, SPICR_MSSSAE|SPICR_MASTER|SPICR_SPE); return 0;}#ifdef FLASH_SPI_DEBUGstatic int flash_spidump_cmdfunc(int argc, char *argv[]){ addr_t addr; size_t size; if (argc != 3) return -H_EUSAGE; if (scan(*++argv, &addr)) return -H_EADDR; if (scan(*++argv, &size)) return -H_EADDR; if (addr & UNALIGNED_MASK) return -H_EALIGN; if (size & UNALIGNED_MASK) return -H_EALIGN; dump_spi_data(addr, size); return 0;}const command_t flash_spidump_command = { "spidump", "", "spi-flash dump", &flash_spidump_cmdfunc };COMMAND(flash_spidump_command);#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -