📄 sflash.c
字号:
/***************************************** Copyright (c) 2003-2004 Sigma Designs, Inc. All Rights Reserved Proprietary and Confidential *****************************************//* This file is part of the EM86XX boot loader *//* * sflash.c * * Serial Flash support * * by Ho Lee 02/04/2003 */#include "config.h"#include "uart.h"#include "io.h"#include "util.h"#include "hardware.h"#include "em86xxapi.h"#include "sflash.h"//// Serial Flash model information//static struct { int model; sflash_op_t *pop; sflash_db_t *pdb;} s_sflash_info = { -1, NULL, NULL};//// Serial Flash operations// extern sflash_op_t g_sflash_op_sst;extern sflash_op_t g_sflash_op_st_m25;extern sflash_op_t g_sflash_op_st_m95;static sflash_op_t *g_sflash_op_list[] = {#ifdef CONFIG_ENABLE_SFLASH_SST &g_sflash_op_sst,#endif#ifdef CONFIG_ENABLE_SFLASH_ST_M25 &g_sflash_op_st_m25,#endif#ifdef CONFIG_ENABLE_SFLASH_ST_M95 &g_sflash_op_st_m95,#endif NULL};//// Primitive functions//static int s_chipselect_nested = 0;void sflash_chipselect(void){ if (s_chipselect_nested++ == 0) __raw_writel(1, REG_BASE_HOST + SFLA_chip_select);}void sflash_chipdeselect(void){ if (--s_chipselect_nested == 0) __raw_writel(1, REG_BASE_HOST + SFLA_chip_deselect);}void sflash_sendcommand(unsigned int cmd){ __raw_writeb(cmd, REG_BASE_HOST + SFLA_send_8);}unsigned char sflash_readb(void){ __raw_writeb(0, REG_BASE_HOST + SFLA_send_get_8); // send stuff bits and get #ifdef CONFIG_ARCH_TANGO // In Tango, these operations are asynchronous // wait until 'B' bit is cleared while (__raw_readl(REG_BASE_HOST + SFLA_status) & 0x01) ;#endif return __raw_readb(REG_BASE_HOST + SFLA_read_data); // read result}void sflash_writeb(unsigned int data){ __raw_writeb(data, REG_BASE_HOST + SFLA_send_8);}unsigned short sflash_readw(void){ __raw_writew(0, REG_BASE_HOST + SFLA_send_get_16); // send stuff bits and get #ifdef CONFIG_ARCH_TANGO while (__raw_readl(REG_BASE_HOST + SFLA_status) & 0x01) ;#endif return __raw_readw(REG_BASE_HOST + SFLA_read_data); // read result}void sflash_writew(unsigned int data){ __raw_writew(data, REG_BASE_HOST + SFLA_send_16);}unsigned int sflash_readl(void){ __raw_writel(0, REG_BASE_HOST + SFLA_send_get_32); // send stuff bits and get #ifdef CONFIG_ARCH_TANGO while (__raw_readl(REG_BASE_HOST + SFLA_status) & 0x01) ;#endif return __raw_readl(REG_BASE_HOST + SFLA_read_data); // read result}void sflash_writel(unsigned int data){#if defined(CONFIG_ARCH_TANGO) && (CONFIG_ARCH_TANGO10_REV == 1) // In Tango, SFLA_send_32 seems broken // use SFLA_send_16 instead __raw_writel((data >> 16) & 0xffff, REG_BASE_HOST + SFLA_send_16); __raw_writel((data >> 0) & 0xffff, REG_BASE_HOST + SFLA_send_16);#else __raw_writel(data, REG_BASE_HOST + SFLA_send_32);#endif}void sflash_setparam(unsigned int data_param, unsigned int data_speed, int verbose){ unsigned int data;#ifdef CONFIG_ARCH_TANGO __raw_writel(1, REG_BASE_HOST + SFLA_drive_pads);#endif // try to setup parameter for serial flash data = __raw_readl(REG_BASE_HOST + SFLA_read_parameters); if (data != data_param) { if (verbose) uart_printf(" Set Serial Flash Parameter : 0x%08x => 0x%08x\n", data, data_param); __raw_writel(data_param, REG_BASE_HOST + SFLA_read_parameters); } data = __raw_readl(REG_BASE_HOST + SFLA_driver_speed); if (data != data_speed) { if (verbose) uart_printf(" Set Serial Flash Timing : 0x%08x => 0x%08x\n", data, data_speed); __raw_writel(data_speed, REG_BASE_HOST + SFLA_driver_speed); }}//// Common Functions// void sflash_chiperase(void){ sflash_op_t *pop = s_sflash_info.pop; sflash_db_t *pdb = s_sflash_info.pdb; if (pop) { pop->chiperase(pdb); }}void sflash_sectorerase(unsigned int addr){ sflash_op_t *pop = s_sflash_info.pop; sflash_db_t *pdb = s_sflash_info.pdb; if (pop) { pop->sectorerase(pdb, addr); }}void sflash_pageprogram(unsigned int addr, unsigned char *data, int len){ sflash_op_t *pop = s_sflash_info.pop; sflash_db_t *pdb = s_sflash_info.pdb; if (pop) { pop->pageprogram(pdb, addr, data, len); }}// // Advanced Functions//// return 0 or positive value if serial flash found, otherwise negative valueint sflash_force(const char *name){ int i; sflash_op_t **pop_list; sflash_db_t *pdb_list; for (pop_list = g_sflash_op_list; *pop_list != NULL; ++pop_list) { pdb_list = (*pop_list)->sflash_list; for (i = 0; pdb_list->size; ++i, ++pdb_list) { if (strcasecmp(pdb_list->name, name) == 0) { s_sflash_info.pop = *pop_list; s_sflash_info.pdb = pdb_list; s_sflash_info.model = i; (*pop_list)->setparam(pdb_list, 1); sflash_showinfo(); return s_sflash_info.model; } } } return -1;}void sflash_show_supportlist(void){ sflash_op_t **pop_list; sflash_db_t *pdb_list; for (pop_list = g_sflash_op_list; *pop_list != NULL; ++pop_list) { uart_printf("Class : %s\n", (*pop_list)->name); for (pdb_list = (*pop_list)->sflash_list; pdb_list->size; ++pdb_list) { uart_printf(" %s : ", pdb_list->name); if (pdb_list->size > 0x400) uart_printf("%dKB\n", pdb_list->size >> 10); else uart_printf("%d Bytes\n", pdb_list->size); } }}// return 0 or positive value if serial flash found, otherwise negative valueint sflash_detect(int verbose){ int i; for (i = 0; g_sflash_op_list[i] != NULL; ++i) if ((s_sflash_info.model = g_sflash_op_list[i]->detect(&s_sflash_info.pop, &s_sflash_info.pdb, verbose)) >= 0) break; sflash_showinfo(); return s_sflash_info.model;}int sflash_exist(void){ return (s_sflash_info.model >= 0) ? 1 : 0;}void sflash_showinfo(void){ if (s_sflash_info.model >= 0) { uart_printf("Serial Flash model %s ", s_sflash_info.pdb->name); if (s_sflash_info.pdb->size >= 0x400) uart_printf("(%dKB)\n", s_sflash_info.pdb->size >> 10); else uart_printf("(%d Bytes)\n", s_sflash_info.pdb->size); } else uart_puts("Serial Flash not found\n");}unsigned int sflash_getsize(void){ sflash_db_t *pdb = s_sflash_info.pdb; return pdb ? pdb->size : 0;}int sflash_calcblock(unsigned int addr, unsigned int *pstart, unsigned int *pend){ int i; unsigned int start = 0, end = 0; sflash_db_t *pdb = s_sflash_info.pdb; *pstart = 0; *pend = 0; if (s_sflash_info.model >= 0) { for (i = 0; i < pdb->nsector; ++i) { end += pdb->sectorsize; if (addr >= start && addr < end) { *pstart = start; *pend = end; return 0; } start += pdb->sectorsize; } } return -1;}int sflash_calcblockrange(unsigned int addr, int len, unsigned int *pstart, unsigned int *pend){ unsigned int dummy; if (sflash_calcblock(addr, pstart, &dummy) == 0) if (sflash_calcblock(addr + len - 1, &dummy, pend) == 0) return 0; return -1;}int sflash_writable(unsigned int addr, int len){ int i; for (i = 0; i < len; ++i) { if (((unsigned char *) (LOADER_SFLASHBASE + addr))[i] != 0xff) return 0; } return 1;}void sflash_readdata(unsigned int addr, unsigned char *data, int len){ sflash_op_t *pop = s_sflash_info.pop; sflash_db_t *pdb = s_sflash_info.pdb; if (pop) pop->read(pdb, addr, data, len);}void sflash_erasedata(unsigned int addr, int len){ unsigned int start, end; sflash_op_t *pop = s_sflash_info.pop; sflash_db_t *pdb = s_sflash_info.pdb; if (pop) { while (len > 0 && sflash_calcblock(addr, &start, &end) == 0) { pop->sectorerase(pdb, start); addr += end - start; len -= end - start; } }}void sflash_writedata(unsigned int addr, unsigned char *data, int len){ sflash_op_t *pop = s_sflash_info.pop; sflash_db_t *pdb = s_sflash_info.pdb; if (pop) { if (!sflash_writable(addr, len)) sflash_erasedata(addr, len); pop->pageprogram(pdb, addr, data, len); }}//// Test functions//#ifdef CONFIG_ENABLE_FULLFUNCTIONvoid sflash_test_status(void){ sflash_op_t *pop = s_sflash_info.pop; uart_puts("Status register test :\n"); uart_printf(" current status register : %02x\n", pop->readstatus()); pop->writeenable(); uart_printf(" after write enable : %02x\n", pop->readstatus()); pop->writedisable(); uart_printf(" after write disable : %02x\n", pop->readstatus());}void sflash_test_read(void){ sflash_op_t *pop = s_sflash_info.pop; sflash_db_t *pdb = s_sflash_info.pdb; unsigned int i, len = sflash_getsize(); unsigned char buf[0x10000], *pbuf, *pdirect; int nmiss = 0; uart_puts("Read test :\n"); if (len > sizeof buf) len = sizeof buf; pop->read(pdb, 0, buf, len); pdirect = (unsigned char *) LOADER_SFLASHBASE; pbuf = buf; if (*(unsigned int *) (pdirect + sflash_getsize() - 4) != *(unsigned int *) pbuf) { uart_puts(" Signature mismatch\n"); ++nmiss; } pbuf += 4; len -= 4; for (i = 0; i < len; ++i) { if (*pbuf++ != *pdirect++) { uart_printf(" Mismatch at addr %d\n", i + 4); ++nmiss; break; } } if (nmiss == 0) uart_puts(" OK\n");} void sflash_test_write(void){ sflash_op_t *pop = s_sflash_info.pop; sflash_db_t *pdb = s_sflash_info.pdb; unsigned int len = sflash_getsize(); unsigned char buf[0x10000], emptybuf[256]; int i, testlen = sizeof emptybuf, found = 0; uart_puts("Write test :\n"); if (len > sizeof buf) len = sizeof buf; pop->read(pdb, 0, buf, len); memset(emptybuf, 0xff, sizeof emptybuf); while (len >= testlen) { len -= testlen; if (memcmp(buf + len, emptybuf, testlen) == 0) { found = 1; break; } } if (!found) { uart_puts(" No empty block found. Test failed\n"); return; } uart_printf(" Empty block is found at address %04x (%d)\n", len, len); uart_puts(" Writing...\n"); for (i = 0; i < testlen; ++i) emptybuf[i] = i; pop->pageprogram(pdb, len, emptybuf, testlen); uart_puts(" Reading...\n"); pop->read(pdb, len, buf, testlen); uart_puts(" Verifying : "); if (memcmp(buf, emptybuf, testlen) == 0) uart_puts("OK\n"); else uart_puts("Mismatch\n");} void sflash_test(int argc, char *argv[]){ int doall = (argv[0] && strcmp(argv[0], "all") == 0) ? 1 : 0; if (argv[0] == NULL) { uart_puts("Serial Flash Test :\n"); uart_puts(" Available commands : " "status " "read " "write " "\n"); } else { if (!sflash_exist()) { uart_puts("Serial Flash doesn't exist. Test failed\n"); return; } if (doall || strcmp(argv[0], "status") == 0) sflash_test_status(); if (doall || strcmp(argv[0], "read") == 0) sflash_test_read(); if (doall || strcmp(argv[0], "write") == 0) sflash_test_write(); }}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -