| /* |
| * c2k_flash.c |
| * |
| */ |
| |
| #include <malloc.h> |
| #include <diags.h> |
| #include <spi/spi.h> |
| #include <mach/comcerto_spi.h> |
| #include <common.h> |
| #include <linux/list.h> |
| #include <linux/types.h> |
| #include <command.h> |
| #include <config.h> |
| #include <libbb.h> |
| |
| #define DEVICE_FAST_SPI "S25FL064A0" |
| |
| #define BUF_SIZE 4 |
| |
| extern int spi_write(struct spi_device *spi, const void *buf, size_t len); |
| extern int spi_read(struct spi_device *spi, void *buf, size_t len); |
| extern int spi_write_then_read(struct spi_device *spi,\ |
| const void *txbuf, unsigned n_tx,\ |
| void *rxbuf, unsigned n_rx); |
| extern int spi_eeprom_read(struct spi_device *spi,\ |
| const void *txbuf, unsigned n_tx,\ |
| void *rxbuf, unsigned n_rx); |
| |
| static struct spi_device *ls_spi; |
| unsigned int erase_glob = 0; |
| |
| #ifdef DEBUG |
| void print_buffer(char *buf, int s) |
| { |
| int i = 0; |
| |
| printk ("Buffer: "); |
| while(i < s){ |
| printk ("0x%x:", *buf++); |
| i++; |
| } |
| printk ("\n"); |
| } |
| #endif |
| |
| u8 read_rdsr(struct spi_device *spi) |
| { |
| int ret = 0; |
| uint8_t s25fl128_rdsr_cmd[4] = { |
| 0x05, 0xa, 0xb, 0xc |
| }; |
| |
| ret = spi_write_then_read(spi, s25fl128_rdsr_cmd, 2, s25fl128_rdsr_cmd+2, 2); |
| if(ret) |
| { |
| printk ("%s:%d: RDSR failed.\n", __func__, __LINE__); |
| return -1; |
| } |
| |
| return s25fl128_rdsr_cmd[3]; |
| } |
| |
| #ifndef CONFIG_COMCERTO_ULOADER |
| /* Erase sector_num sector */ |
| int nor_s25fl128_sector_erase(struct spi_device *spi, int sector_num) |
| { |
| /* S25FL128: wren_cmd: |1B_cmd| */ |
| uint8_t s25fl128_wren_cmd[BUF_SIZE] = { |
| 0x06, 0x00, 0x00, 0x00, |
| }; |
| /* S25FL128: erase_cmd: |1B_cmd|3B_addr| */ |
| uint8_t s25fl128_erase_cmd[BUF_SIZE] = { |
| 0xd8, 0x00, 0x00, 0x00, |
| }; |
| |
| int sector_addr = sector_num * SPI_FLASH_SECTOR_SIZE; |
| u8 rdsr = 0x1; |
| int ret = 0; |
| |
| s25fl128_erase_cmd[1] = ((sector_addr & 0xff0000)>>16); |
| s25fl128_erase_cmd[2] = ((sector_addr & 0xff00)>>8); |
| s25fl128_erase_cmd[3] = (sector_addr & 0xff); |
| |
| do { |
| rdsr = read_rdsr(spi); |
| }while (rdsr & 0x1); |
| |
| ret = spi_write(spi, s25fl128_wren_cmd, 1); |
| if(ret) |
| { |
| printk ("%s:WREN failed.\n", __func__); |
| return ret; |
| } |
| |
| do { |
| rdsr = read_rdsr(spi); |
| }while (!(rdsr & 0x2)); |
| |
| if (!erase_glob) { |
| ret = spi_write(spi, s25fl128_erase_cmd, 4); |
| if(ret) |
| { |
| printk ("%s:ERASE failed.\n", __func__); |
| return ret; |
| } |
| |
| do { |
| rdsr = read_rdsr(spi); |
| }while (rdsr & 0x1); |
| |
| printk ("Erasing Done.\n"); |
| |
| return ret; |
| }else |
| return 0; |
| |
| } |
| |
| int spi_sector_erase(int sec, int num_sec) |
| { |
| struct device_d *d_fast_spi = get_device_by_name(DEVICE_FAST_SPI); |
| int ret = 0; |
| |
| num_sec += sec; |
| |
| ls_spi = d_fast_spi->type_data; |
| |
| while(sec < num_sec){ |
| printf ("%s: erase sector %d\n", __func__, sec); |
| ret = nor_s25fl128_sector_erase(ls_spi, sec++); |
| if(ret) |
| { |
| printk ("%s: failed.\n", __func__); |
| return ret; |
| } |
| } |
| |
| return 0; |
| } |
| EXPORT_SYMBOL(spi_sector_erase); |
| |
| #define WRITE_BYTES 8 |
| int write_bytes_page_addr(struct spi_device *spi, u8 *b, int num_buytes, u8 p, unsigned int a) |
| { |
| /* S25FL128: pp_cmd: |1B_cmd|3B_addr|at_least_1B_data|erite_buf| */ |
| uint8_t s25fl128_pp_cmd[4+WRITE_BYTES] = { |
| 0x02, 0x00, 0x00, 0x00, |
| }; |
| /* S25FL128: wren_cmd: |1B_cmd| */ |
| uint8_t s25fl128_wren_cmd[BUF_SIZE] = { |
| 0x06, 0x00, 0x00, 0x00, |
| }; |
| |
| int ret = 0; |
| u8 rdsr = 0x1; |
| |
| int addr = (SPI_FLASH_SECTOR_SIZE * p)+a; |
| s25fl128_pp_cmd[1] = ((addr & 0xff0000)>>16); |
| s25fl128_pp_cmd[2] = ((addr & 0xff00)>>8); |
| s25fl128_pp_cmd[3] = (addr & 0xff); |
| |
| memcpy(s25fl128_pp_cmd+4, b, num_buytes); |
| |
| do { |
| rdsr = read_rdsr(spi); |
| }while (rdsr & 0x1); |
| |
| ret = spi_write(spi, s25fl128_wren_cmd, 1); |
| if(ret) |
| { |
| printk ("%s:WREN failed.\n", __func__); |
| return ret; |
| } |
| |
| do { |
| rdsr = read_rdsr(spi); |
| }while (!(rdsr & 0x2)); |
| |
| ret = spi_write(spi, s25fl128_pp_cmd, 4+num_buytes); |
| if(ret) |
| { |
| printk ("%s:PP failed.\n", __func__); |
| return ret; |
| } |
| |
| do { |
| rdsr = read_rdsr(spi); |
| }while (rdsr & 0x1); |
| |
| return ret; |
| } |
| #endif |
| |
| #define READ_BYTES 8 |
| int read_bytes_page_addr(struct spi_device *spi, u8 *b, int num_buytes, u8 p, unsigned int a) |
| { |
| int ret = 0; |
| u8 rdsr = 0x1; |
| /* S25FL128: rd_cmd: |1B_cmd|3B_addr|dummy_bytes| */ |
| uint8_t s25fl128_rd_cmd[4+READ_BYTES] = { |
| 0x03, 0x00, 0x00, 0x00, |
| }; |
| |
| |
| int addr = (SPI_FLASH_SECTOR_SIZE * p)+a; |
| s25fl128_rd_cmd[1] = ((addr & 0xff0000)>>16); |
| s25fl128_rd_cmd[2] = ((addr & 0xff00)>>8); |
| s25fl128_rd_cmd[3] = (addr & 0xff); |
| |
| do { |
| rdsr = read_rdsr(spi); |
| }while (rdsr & 0x1); |
| |
| ret = spi_write_then_read(spi, s25fl128_rd_cmd, 4+num_buytes, b, 4+num_buytes); |
| if(ret) |
| { |
| printk ("%s:Read failed.\n", __func__); |
| return ret; |
| } |
| |
| do { |
| rdsr = read_rdsr(spi); |
| }while (rdsr & 0x1); |
| |
| return ret; |
| } |
| |
| #ifndef CONFIG_COMCERTO_ULOADER |
| static int spi_copy_write(char *src, unsigned int len, unsigned int sec, unsigned int off) |
| { |
| unsigned int l=0; |
| int ret = 0; |
| struct device_d *d_fast_spi = get_device_by_name(DEVICE_FAST_SPI); |
| |
| ls_spi = d_fast_spi->type_data; |
| |
| ret = nor_s25fl128_sector_erase(ls_spi, sec); |
| if(ret) |
| { |
| printk ("%s: failed.\n", __func__); |
| return ret; |
| } |
| |
| while (l < (len/WRITE_BYTES)) |
| { |
| ret = write_bytes_page_addr(ls_spi, src, WRITE_BYTES, sec, off); |
| if(ret) |
| { |
| printk ("%s: failed.\n", __func__); |
| return ret; |
| } |
| src += WRITE_BYTES; |
| off += WRITE_BYTES; |
| l++; |
| } |
| |
| if(len%WRITE_BYTES) |
| { |
| l = len%WRITE_BYTES; |
| |
| ret = write_bytes_page_addr(ls_spi, src, l, sec, off); |
| if(ret) |
| { |
| printk ("%s: failed.\n", __func__); |
| return ret; |
| } |
| } |
| |
| return 0; |
| } |
| #endif |
| |
| int spi_copy_read(char *dst, unsigned int len, unsigned int sec, unsigned int off) |
| { |
| unsigned int l=0; |
| int ret = 0; |
| char tmp[4+READ_BYTES]; |
| struct device_d *d_fast_spi = get_device_by_name(DEVICE_FAST_SPI); |
| |
| ls_spi = d_fast_spi->type_data; |
| |
| while (l < (len/READ_BYTES)) |
| { |
| ret = read_bytes_page_addr(ls_spi, tmp, READ_BYTES, sec, off); |
| if(ret) |
| { |
| printk ("%s: failed.\n", __func__); |
| return ret; |
| } |
| |
| memcpy(dst, tmp+4, READ_BYTES); |
| |
| dst += READ_BYTES; |
| off += READ_BYTES; |
| l++; |
| } |
| |
| if(len%READ_BYTES) |
| { |
| l = len%READ_BYTES; |
| |
| ret = read_bytes_page_addr(ls_spi, tmp, l, sec, off); |
| if(ret) |
| { |
| printk ("%s: failed.\n", __func__); |
| return ret; |
| } |
| memcpy(dst, tmp+4, l); |
| dst += l; |
| off += l; |
| } |
| |
| return 0; |
| } |
| EXPORT_SYMBOL(spi_copy_read); |
| |
| #ifndef CONFIG_COMCERTO_ULOADER |
| static void spi_flash_write(unsigned char *src, ulong sec, ulong offset, ulong count) |
| { |
| int wl = 0; |
| unsigned int off = 0; |
| unsigned int itr = SPI_FLASH_SECTOR_SIZE/SPI_FLASH_NOR_PAGE_SIZE; |
| int write_bytes = SPI_FLASH_NOR_PAGE_SIZE; |
| unsigned int *ptr_w; |
| int s; |
| ulong size; |
| |
| ptr_w = (unsigned int *)src; |
| s = sec; |
| size = count; |
| off = offset; |
| |
| while(size) |
| { |
| itr = SPI_FLASH_SECTOR_SIZE/SPI_FLASH_NOR_PAGE_SIZE; |
| erase_glob=0; |
| |
| if(size < SPI_FLASH_SECTOR_SIZE) { |
| if(size%write_bytes) |
| itr = size/write_bytes + 1; |
| else |
| itr = size/write_bytes; |
| |
| size = 0; |
| } else { |
| size -= SPI_FLASH_SECTOR_SIZE; |
| } |
| |
| for (wl = 0 ; wl < itr ; wl++) |
| { |
| spi_copy_write((char*)ptr_w, write_bytes, s, off); |
| |
| erase_glob=1; |
| ptr_w += 64; |
| off += write_bytes; |
| } |
| printk ("Wrote %d bytes at sec %d in %d iterations.\n", \ |
| write_bytes*itr, s, itr); |
| s++; |
| off = 0; |
| } |
| } |
| |
| int update_spi_flash(unsigned char *src, ulong sec, ulong off, ulong count) |
| { |
| spi_flash_write(src, sec, off, count); |
| |
| return 0; |
| } |
| |
| EXPORT_SYMBOL(update_spi_flash); |
| #endif |