GD25Q128Datasheets
由图可知GD25Q128C 16MB
- block 64/32K 共(256/512)个块
- sector 4K 共4096个扇区
- page 256B 共64个页
一般擦除最小单位为扇区,也就是4K
GD25Q128 4个信号线
- SCLK:Serial Clock
- CS#:Chip Select
- SI: Serial Data Input
- SO: Serial Data Output
X1000-uboot spi-flash
定义drivers/spi/jz_spi.h
{
.id_manufactory = 0x1860c8,
.name = "GD25LQ128C",
.page_size = 256,
.sector_size = 4 * 1024,
.addr_size = 3,
.size = 16 * 1024 * 1024,
.quad_mode = {
.dummy_byte = 8,
.RDSR_CMD = CMD_RDSR_1,
.WRSR_CMD = CMD_WRSR,
.RDSR_DATE = 0x2,// the data is write the spi status register for QE bit
.RD_DATE_SIZE = 1,
.WRSR_DATE = 0x0200,// this bit should be the flash QUAD mode enable
.WD_DATE_SIZE = 2,
.cmd_read = CMD_QUAD_READ,
#ifdef CONFIG_JZ_SFC
.sfc_mode = TRAN_SPI_QUAD,
#endif
},
common/env_sfc.c
uboot中保存环境变量的实现方法
int saveenv(void)
{
sfc_get_env_addr(copy, &offset);
env_new.crc = crc32(0, env_new.data, ENV_SIZE);
sfc_nor_write(offset, CONFIG_ENV_SIZE , (char *)&env_new, 1);
sfc_nor_read(offset, CONFIG_ENV_SIZE, (char *)buf);
}
uboot加载时发现
uboot第一阶段启动时,加载的是common/spl/spl_sfc_nor.c
#spl_sfc_nor read
#spl_sfc_nor read
#spl_sfc_nor read
#spl_sfc_nor read
#spl?
U-Boot SPL 2013.07-00004-g4861957 (Nov 26 2016 - 15:59:33)
apll = 576000000
mpll = 600000000
cpccr = 95752210
U-Boot 2013.07-00004-g4861957 (Nov 26 2016 - 15:59:33)
Board: burner_x1000 (Ingenic XBurst X1000 SoC)
DRAM: 32 MiB
Top of RAM usable for U-Boot at: 82000000
Reserving 4642k for U-Boot at: 81b74000
加载内核时使用的是driver/spi/jz_sfc readdata函数
Logo: width 240 height 60 colors 240 cmap 240
fb:0x81febf60
dump_lcdc_registers
USB_udc_probe
jz_dwc2_udc_v1.1
Net: =======>MacBase = 0xb34b0000, DmaBase = 0xb34b1000 PhyBase = 0x00000000
GMAC-9162
Hit any key to stop autoboot: 0
#sfc_init1
#jz_sfc readdata
sfcnor read Image from 0x40000 to 0x80800000 size is 0x300000 ...
#jz_sfc readdata
sfcnor read ok!
## Starting application at 0x80800000 ...
compare suc
drivers/mtd/spi/sfc.c
->sfc_init();
spi_flash参数初始化
sfc_nor_init
for (i = 0; i < ARRAY_SIZE(jz_spi_support_table); i++) {
gparams = jz_spi_support_table[i];
if (gparams.id_manufactory == idcode){
printf("the id code = %x, the flash name is %s\n",idcode,gparams.name);
if(sfc_quad_mode == 1){
quad_mode = &jz_spi_support_table[i].quad_mode;
}
break;
}
}
jz_spi_support_table[i] 在jz_spi中定义
{
.id_manufactory = 0x1840c8,
.name = "GD25Q128C",
.page_size = 256,
.sector_size = 4 * 1024,
.addr_size = 3,
.size = 16 * 1024 * 1024,
.quad_mode = {
.dummy_byte = 8,
.RDSR_CMD = CMD_RDSR_1,
.WRSR_CMD = CMD_WRSR_1,
.RDSR_DATE = 0x2,// the data is write the spi status register for QE bit
.RD_DATE_SIZE = 1,
.WRSR_DATE = 0x2,// this bit should be the flash QUAD mode enable
.WD_DATE_SIZE = 1,
.cmd_read = CMD_QUAD_READ,
#ifdef CONFIG_JZ_SFC
.sfc_mode = TRAN_SPI_QUAD,
#endif
},
},
定义了nor共享参数 static struct nor_sharing_params pada;
具体赋值在
sfc_nor_init
->sfc_nor_read_params
->jz_sfc_read_norflash_params
sfc_nor_write示例
U_BOOT_CMD(
sfcnor, 6, 0, do_sfcnor,
"sfc nor",
"sfcnor read [src:nor flash addr] [bytes:0x..] [dst:ddr address]\n"
"sfcnor write [src:nor flash addr] [bytes:0x..] [dst:der address] [force erase:1, nor erase:0]\n"
"sfcnor erase [src:nor flash addr] [bytes:0x..]\n "
);
static int do_sfcnor(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
......
sfc_nor_read(src_addr,count,dst_addr);
......
sfc_nor_write(src_addr,count,dst_addr,erase_en);
......
sfc_nor_erase(src_addr,count);
}
jz_sfc_write分析
有程序可知一次写入空间为一页PageSize
数据写入开始地址需要PageSize对齐,不可跨页写,例如
`|----|------------------|`
a b c
例a%page_size == 0
b位offset
一次最大可写空间为c-b
jz_sfc_set_address_mode
cmd[0] = CMD_WREN; //设置可写
if(sfc_quad_mode == 1){
cmd[1] = CMD_QPP; //写入
mode = TRAN_SPI_QUAD;
}else{
cmd[1] = CMD_PP;
mode = TRAN_SPI_STANDARD;
}
cmd[flash->addr_size + 2] = CMD_RDSR;//读状态寄存器
while(length)
{
if (length >= flash->page_size)//参数错误 设置待写入长度为0
pagelen = 0;
else
pagelen = length % flash->page_size;//设置一次写入大小
sfc_send_cmd(&cmd[0],0,0,0,0,0,1);//Write enable
if (offset % flash->page_size + len > flash->page_size)//若偏移地址+待写入长度 >1PageSize
len -= offset % flash->page_size + len - flash->page_size;//保证offset对page_size对齐后+len < Page_size
cmd[2] [3] [4] = offset
sfc_send_cmd(&cmd[1], len,offset,flash->addr_size,0,1,1);//发送写入命令
sfc_write_data(send_buf ,len);
sfc_send_cmd(&cmd[flash->addr_size + 2],1,0,0,0,1,0);
sfc_read_data(&tmp, 1);
while(tmp & CMD_SR_WIP) {
sfc_send_cmd(&cmd[flash->addr_size + 2],1,0,0,0,1,0);
sfc_read_data(&tmp, 1);
}//读状态寄存器 等待处理完成
offset += retlen;//自动后移
send_buf += retlen;
length -= retlen;
}
addr1 addr2 addr3
`|--|---------------------|`
256 300 512
offset = 300 len = 500
len -= 300 % 256 + 500 - 256
= 46 + 246
= 292
jz_sfc_reader分析
if(sfc_quad_mode == 1){
cmd[0] = quad_mode->cmd_read;
mode = quad_mode->sfc_mode;
}else{
cmd[0] = CMD_READ;
mode = TRAN_SPI_STANDARD;
}
for(i = 0; i < flash->addr_size; i++){
cmd[i + 1] = offset >> (flash->addr_size - i - 1) * 8;
}//cmd[0] reader cmd[1] [2] [3]读地址
sfc_send_cmd(&cmd[0],read_len,offset,flash->addr_size,0,1,0);
sfc_read_data(data, len);
jz_sfc_erase分析
if((len >= 0x10000)&&((offset % 0x10000) == 0)){
erase_size = 0x10000;//offset为64K整数倍 且擦除大小>=64K erase_size = 64K;
}else if((len >= 0x8000)&&((offset % 0x8000) == 0)){
erase_size = 0x8000;//offset为32K整数倍 且擦除大小>=64K erase_size = 32;
}else{
erase_size = 0x1000;//4K
}
if(len % erase_size != 0){
len = len - (len % erase_size) + erase_size;//向上取整
}
cmd[0] = CMD_WREN;
cmd[1] = CMD_ERASE_64K/32K/4K;
cmd[flash->addr_size + 2] = CMD_RDSR;
while(len)
{
for(i = 0; i < flash->addr_size; i++){
cmd[i+2] = offset >> (flash->addr_size - i - 1) * 8;
}//设置擦除开始地址
sfc_send_cmd(&cmd[0],0,0,0,0,0,1);
sfc_send_cmd(&cmd[1],0,offset,flash->addr_size,0,0,1);
sfc_send_cmd(&cmd[flash->addr_size + 2], 1,0,0,0,1,0);
sfc_read_data(&buf, 1);
while(buf & CMD_SR_WIP) {//wait spi_flash not busy
sfc_send_cmd(&cmd[flash->addr_size + 2], 1,0,0,0,1,0);
sfc_read_data(&buf, 1);
}
offset += erase_size;
len -= erase_size;
}