blob: f659083d92e7bec74f6e08f7a9108bc9f0aa5fc4 [file] [log] [blame]
/*
* c2k_fast_spi_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 "s25fl2560"
static struct spi_device *fast_spi;
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);
#define CMD_BUF_SIZE 4
/* S25FL256: wren_cmd: |1B_cmd| */
static uint8_t s25fl256_wren_cmd[CMD_BUF_SIZE] = {
0x06, 0x00, 0x00, 0x00,
};
/* S25FL256: erase_cmd: |1B_cmd|3B_addr| */
static uint8_t s25fl256_erase_cmd[CMD_BUF_SIZE] = {
0xd8, 0x00, 0x00, 0x00,
};
/* S25FL256: pp_cmd: |1B_cmd|3B_addr|at_least_1B_data|erite_buf| */
static uint8_t s25fl256_pp_cmd[CMD_BUF_SIZE+FAST_SPI_FLASH_PAGE_SIZE] = {
0x02, 0x00, 0x00, 0x00,
};
/* S25FL256: rd_cmd: |1B_cmd|3B_addr|dummy_bytes| */
static uint8_t s25fl256_rd_cmd[CMD_BUF_SIZE] = {
0x03, 0x00, 0x00, 0x00,
};
//#define FAST_SPI_FLASH_DEBUG
#ifdef FAST_SPI_FLASH_DEBUG
static void print_buffer(char *buf, int s)
{
int i = 0;
printk ("Buffer: ");
while(i < s){
printk ("0x%x:", *buf++);
i++;
}
printk ("\n");
}
#endif
static u8 read_rdsr(struct spi_device *spi)
{
int ret = 0;
uint8_t s25fl256_rdsr_cmd[4] = {
0x05, 0xa, 0xb, 0xc
};
ret = spi_write_then_read(spi, s25fl256_rdsr_cmd, 2, s25fl256_rdsr_cmd+2, 2);
if(ret)
{
printk ("%s:%d: RDSR failed.\n", __func__, __LINE__);
return -1;
}
return s25fl256_rdsr_cmd[3];
}
/* Erase sector_num sector */
static int nor_s25fl256_sector_erase(struct spi_device *spi, int sector_num)
{
int sector_addr = sector_num * FAST_SPI_FLASH_SECTOR_SIZE;
u8 rdsr = 0x1;
int ret = 0;
s25fl256_erase_cmd[1] = ((sector_addr & 0xff0000)>>16);
s25fl256_erase_cmd[2] = ((sector_addr & 0xff00)>>8);
s25fl256_erase_cmd[3] = (sector_addr & 0xff);
#ifdef FAST_SPI_FLASH_DEBUG
printk ("%s: Erasing sec %d using (cmd):address (0x%x):0x%x:0x%x:0x%x \n", __func__, sector_num, \
s25fl256_erase_cmd[0], s25fl256_erase_cmd[1], s25fl256_erase_cmd[2],\
s25fl256_erase_cmd[3]);
#endif
do {
rdsr = read_rdsr(spi);
}while (rdsr & 0x1);
#ifdef FAST_SPI_FLASH_DEBUG
printk ("%s: WREN sending...\n", __func__);
#endif
ret = spi_write(spi, s25fl256_wren_cmd, 1);
if(ret)
{
printk ("%s:%d: WREN failed ret=%d\n", __func__, __LINE__, ret);
return ret;
}
do {
rdsr = read_rdsr(spi);
}while (!(rdsr & 0x2));
#ifdef FAST_SPI_FLASH_DEBUG
printk ("%s: Erase sending...\n", __func__);
#endif
ret = spi_write(spi, s25fl256_erase_cmd, 4);
if(ret)
{
printk ("%s:%d: ERASE failed.\n", __func__, __LINE__);
return ret;
}
do {
rdsr = read_rdsr(spi);
}while (rdsr & 0x1);
#ifdef FAST_SPI_FLASH_DEBUG
printk ("%s: Erase done...\n", __func__);
#endif
return ret;
}
static int write_bytes_page_addr(struct spi_device *spi, u8 *b, int num_buytes, u8 p, int a)
{
int ret = 0;
u8 rdsr = 0x1;
int c = 0;
int addr = (FAST_SPI_FLASH_SECTOR_SIZE * p)+a;
s25fl256_pp_cmd[1] = ((addr & 0xff0000)>>16);
s25fl256_pp_cmd[2] = ((addr & 0xff00)>>8);
s25fl256_pp_cmd[3] = (addr & 0xff);
while (c < num_buytes)
{
s25fl256_pp_cmd[4+c] = b[c];
c++;
}
#ifdef FAST_SPI_FLASH_DEBUG
printk ("%s: Writing %d bytes at (cmd):addr (0x%x):0x%x:0x%x:0x%x 0x%x\n", __func__, num_buytes,\
s25fl256_pp_cmd[0], s25fl256_pp_cmd[1], s25fl256_pp_cmd[2], s25fl256_pp_cmd[3], s25fl256_pp_cmd[4]);
#endif
do {
rdsr = read_rdsr(spi);
}while (rdsr & 0x1);
ret = spi_write(spi, s25fl256_wren_cmd, 1);
if(ret)
{
printk ("%s:%d: WREN failed.\n", __func__, __LINE__);
return ret;
}
do {
rdsr = read_rdsr(spi);
}while (!(rdsr & 0x2));
ret = spi_write(spi, s25fl256_pp_cmd, 4+num_buytes);
if(ret)
{
printk ("%s:%d: PageProgram failed.\n", __func__, __LINE__);
return ret;
}
do {
rdsr = read_rdsr(spi);
}while (rdsr & 0x1);
return ret;
}
#define WRITE_CHUNKS 128
static int write_one_sector(struct spi_device *spi, u8 *b, int count, u8 s, u8 of)
{
int cnt = 0;
int bytes = count; //num bytes to write
u8 sec = s; //sector
int off = of; //offset
u8 *wbuf = b; //buf to use
int chunks = WRITE_CHUNKS;
int ret = 0;
cnt = bytes/chunks;
if(count%chunks)
cnt += 1;
if (cnt == 1)
chunks = bytes;
printk("\nWriting %d bytes at sec %d and offset %d\n", count, sec, off);
while(cnt) {
printk(".");
ret = write_bytes_page_addr(spi, wbuf, chunks, sec, off);
off += chunks;
wbuf += chunks;
cnt--;
bytes -= chunks;
if(bytes <= WRITE_CHUNKS)
chunks = bytes;
else
chunks = WRITE_CHUNKS;
}
printk ("\n");
return ret;
}
static int fast_spi_flash_write(struct spi_device *spi, unsigned char *src, \
ulong sec, ulong offset, ulong count)
{
int bytes = count;
int num_sec;
int c = sec;
int ret = 0;
int off = offset;
if(bytes < FAST_SPI_FLASH_SECTOR_SIZE){
num_sec = 1;
}else{
num_sec = bytes/FAST_SPI_FLASH_SECTOR_SIZE;
if(bytes % FAST_SPI_FLASH_SECTOR_SIZE){
num_sec += 1;
}
}
num_sec += c; //increasing count as per starting sector
while(c < num_sec){
ret = nor_s25fl256_sector_erase(spi, c);
if(ret)
{
printk ("%s: nor_s25fl256_sector_erase failed. ret=%d\n", \
__func__, ret);
return ret;
}
if(count > FAST_SPI_FLASH_SECTOR_SIZE){
bytes = FAST_SPI_FLASH_SECTOR_SIZE;
}else{
bytes = count;
}
ret = write_one_sector(spi, src, bytes, c, off);
if(ret)
{
printk ("%s: write_one_sector failed. ret=%d\n", \
__func__, ret);
return ret;
}
c++;
src += bytes;
count -= bytes;//FAST_SPI_FLASH_SECTOR_SIZE;
off = 0; //start new sector write at offset 0
}
return ret;
}
static int read_bytes_page_addr(struct spi_device *spi, u8 *b, int num_buytes, u8 p, int a)
{
int ret = 0;
u8 rdsr = 0x1;
int addr = (FAST_SPI_FLASH_SECTOR_SIZE * p)+a;
s25fl256_rd_cmd[1] = ((addr & 0xff0000)>>16);
s25fl256_rd_cmd[2] = ((addr & 0xff00)>>8);
s25fl256_rd_cmd[3] = (addr & 0xff);
#ifdef FAST_SPI_FLASH_DEBUG
printk ("%s: Reading %d bytes from (cmd):addr (0x%x):0x%x:0x%x:0x%x \n", __func__, num_buytes,\
s25fl256_rd_cmd[0], s25fl256_rd_cmd[1], s25fl256_rd_cmd[2], s25fl256_rd_cmd[3]);
#endif
do {
rdsr = read_rdsr(spi);
}while (rdsr & 0x1);
if (!s25fl256_rd_cmd[0])
s25fl256_rd_cmd[0] = 0x3;
ret = spi_write_then_read(spi, s25fl256_rd_cmd, 4+num_buytes, b, 4+num_buytes);
if(ret)
{
printk ("%s:%d: Read failed.\n", __func__, __LINE__);
return ret;
}
memcpy(b, b+4, num_buytes);
do {
rdsr = read_rdsr(spi);
}while (rdsr & 0x1);
return ret;
}
#define READ_CHUNKS 128
static int read_one_sector(struct spi_device *spi, u8 *b, int count, u8 s, u8 of)
{
int cnt = 0;
int bytes = count; //num bytes to read
u8 sec = s; //sector
int off = of; //offset
u8 *rbuf = b; //buf to use
int chunks = READ_CHUNKS;
int ret = 0;
cnt = bytes/chunks;
if(count%chunks)
cnt += 1;
if (cnt == 1)
chunks = bytes;
printk (".");
while(cnt) {
ret = read_bytes_page_addr(spi, rbuf, chunks, sec, off);
off += chunks;
rbuf += chunks;
cnt--;
bytes -= chunks;
if(bytes <= READ_CHUNKS)
chunks = bytes;
else
chunks = READ_CHUNKS;
}
return ret;
}
static int fast_spi_flash_read(struct spi_device *spi, u8 *recbuf, \
u8 sect, u8 offset, int count)
{
int bytes = count;
int num_sec;
int c = sect;
int ret = 0;
if(bytes < FAST_SPI_FLASH_SECTOR_SIZE){
num_sec = 1;
}else{
num_sec = bytes/FAST_SPI_FLASH_SECTOR_SIZE;
if(bytes % FAST_SPI_FLASH_SECTOR_SIZE){
num_sec += 1;
}
}
while(c < num_sec){
if(count > FAST_SPI_FLASH_SECTOR_SIZE){
bytes = FAST_SPI_FLASH_SECTOR_SIZE;
}else{
bytes = count;
}
ret = read_one_sector(spi, recbuf, bytes, c, offset);
if(ret)
{
printk ("%s: fast_spi_flash_read failed. ret=%d\n", \
__func__, ret);
return ret;
}
c++;
recbuf += bytes;
count -= bytes;
offset = 0;
}
return ret;
}
int fast_spi_copy_read(char *recbuf, unsigned int len, unsigned int sec, unsigned int off)
{
int ret = 0;
struct device_d *fast_spi_dev = get_device_by_name(DEVICE_FAST_SPI);
fast_spi = fast_spi_dev->type_data;
ret = fast_spi_flash_read(fast_spi, recbuf, sec, off, len);
if(ret)
{
printk ("%s: fast_spi_copy_read failed. ret=%d\n", \
__func__, ret);
return ret;
}
return ret;
}
EXPORT_SYMBOL(fast_spi_copy_read);
int update_fast_spi_flash(unsigned char *src, ulong sec, ulong off, ulong count)
{
struct device_d *fast_spi_dev = get_device_by_name(DEVICE_FAST_SPI);
fast_spi = fast_spi_dev->type_data;
#ifdef FAST_SPI_FLASH_DEBUG
printk ("%s: \
\nSector = 0x%x \
\nOffset = 0x%x \
\nBytes = %d \
\nmax_speed_hz=%d \
\nchip_select=0x%x \
\nmodalias=%s\n", __func__, \
(unsigned int)sec, (unsigned int)off, (int)count, fast_spi->max_speed_hz, \
fast_spi->chip_select, fast_spi->modalias);
#endif
fast_spi_flash_write(fast_spi, src, sec, off, count);
return 0;
}
EXPORT_SYMBOL(update_fast_spi_flash);