board.c中 spi_flash_probe(0, 0, 0, 0); 函数调用了 drivers/mtd/spi下对应文件,如这里的spi_compatible.c;
继续调用了hifmc100_spi_nor_probe ;
-> hifmc100_spi_nor_probe
-> hifmc_dev_type_switch(FLASH_TYPE_SPI_NOR);//配置当前类型为spi nor
-> hifmc100_driver_probe
-> hifmc_ip_ver_check //检查版本
-> hifmc100_spi_nor_init
赋值基地址即存储空间起始地址,normal操作模式切换; spi timing配置
-> hifmc100_host_init(host);
-> hifmc_set_fmc_system_clock//FMC MUX IO端时钟选择;
-> hifmc100_spi_nor_scan
-> hifmc_spi_nor_probe
-> hifmc100_read_ids //读取id,如SPI Nor(cs 0) ID: 0xc2 0x20 0x18
-> hifmc_spi_nor_serach_ids //根据id匹配flash表;
-> hifmc_spi_nor_search_rw //根据读/写填充spi中的read/write参数;
-> hifmc_spi_nor_get_erase
-> hifmc_map_iftype_and_clock //根据iftype找到最好的时钟
-> hifmc100_get_bp_lock_level //bp转level
-> spi_nor_flash->erase = hifmc100_reg_erase;
-> hifmc100_reg_erase_one_block //通过下发指令完成擦除
-> spi_nor_flash->write = hifmc100_dma_write;
//下发指令且使能dma开启数据读、写;
-> hifmc100_dma_transfer(host, to, (u_char *)buf, RW_OP_WRITE, len);
-> spi_nor_flash->read = hifmc100_dma_read;
-> hifmc100_dma_transfer(host, from, (u_char *)buf, RW_OP_READ, len);
-> hifmc100_get_spi_nor_info
-> hifmc100_probe_spi_size //计算flash总大小
-> add_shutdown(hifmc100_driver_shutdown); //关机回调
上述流程中重要的几个结构体: (1)struct mtd_info_ex (2)struct spi_flash (3)struct hifmc_host
struct mtd_info_ex
{
u_char type; /* chip type MTD_NORFLASH / MTD_NANDFLASH */
uint64_t chipsize; /* total size of the nand/spi chip */
u_int32_t erasesize;
u_int32_t pagesize;
u_int32_t numchips; /* number of nand chips */
//OOB:特殊数据,用于硬件纠错和坏块管理; https://blog.csdn.net/qq_41882586/article/details/123232813
u_int32_t oobsize;
u_int32_t addrcycle;
//ECC校验纠错能力;如8bit/1kb,16bit/1kb,24bit/1kb,28bit/1kb;
//如8bit/1kb表示1kb数据中最大能纠正8bit错误;
u_int32_t ecctype;
u_char ids[8]; //id 如SPI Nor(cs 0) ID: 0xc2 0x20 0x18
u_int32_t id_length;//id长度
char name[16]; /* chip names 芯片名*/
int hostver; /* host controller version 主机控制器版本*/
};
struct spi_flash {
struct spi_slave *spi;
const char *name;
u32 size;
#ifdef CONFIG_SPI_BLOCK_PROTECT
unsigned int bp_level_max;
void (*lock)(unsigned char cmp, unsigned char level,
unsigned char op);
#endif
//读/写/擦除 回调函数
int (*read)(struct spi_flash *flash, u32 offset,
size_t len, void *buf);
int (*write)(struct spi_flash *flash, u32 offset,
size_t len, const void *buf);
int (*erase)(struct spi_flash *flash, u32 offset,
size_t len);
};
//其中 struct spi_slave 如下
struct spi_slave {
unsigned int bus; //总线id
unsigned int cs; //芯片片选id
};
struct hifmc_host {
struct spi_flash spi_nor_flash[1];
struct mtd_info_ex *spi_nor_info;
struct hifmc_spi spi[CONFIG_SPI_NOR_MAX_CHIP_NUM];
void *regbase; //FMC控制寄存器基地址
void *iobase;//spi flash存储空间起始地址
void (*set_system_clock)(struct spi_op *op, int clk_en);
void (*set_host_addr_mode)(struct hifmc_host *host, int enable);
#ifdef CONFIG_SPI_BLOCK_PROTECT
unsigned int start_addr;
unsigned int end_addr;
unsigned char cmp;
unsigned int bp_num;
/* the BT bit location, decide the data num count */
unsigned int bt_loc;
unsigned char level;
#endif
};
struct hifmc_host 结构体表示海思flash memory control host 部分;
其中最重要的函数为 flashd的读/写/擦除函数; 这里读写看dma版本;
hifmc100_dma_read / hifmc100_dma_write 函数中都调用了 hifmc100_dma_transfer
/*
功能:实现dma数据读/写传输
参数1:主机控制器
参数2:读/写的起始地址
参数3:需要传输的数据/读取后放入数据的buf;
参数4:用于区分读/写操作
参数5:读时表需要读取的长度, 写时表示写入数据的长度;
*/
static void hifmc100_dma_transfer(struct hifmc_host *host,
unsigned int spi_start_addr, unsigned char *dma_buffer,
unsigned char rw_op, unsigned int size)
{
unsigned char if_type = 0, dummy = 0;
unsigned char w_cmd = 0, r_cmd = 0;
unsigned int regval;
struct hifmc_spi *spi = host->spi;
FMC_PR(DMA_DB, "\t\t *-Start dma transfer => [%#x], len[%#x].\n",
spi_start_addr, size);
regval = FMC_INT_CLR_ALL;
hifmc_write(host, FMC_INT_CLR, regval);//清除所有中断
FMC_PR(DMA_DB, "\t\t Set INT_CLR[%#x]%#x\n", FMC_INT_CLR, regval);
regval = spi_start_addr;
hifmc_write(host, FMC_ADDRL, regval); //配置flash器件操作地址的低4bit; nor flash表配置器件地址;
FMC_PR(DMA_DB, "\t\t Set ADDRL[%#x]%#x\n", FMC_ADDRL, regval);
//区分读还是写
/*if_type: 五种spi接口类型,分别为standard spi,dual-output/input spi, quad-output/input spi,dual i/o spi, quad i/o spi; */
if (rw_op == RW_OP_WRITE) {
if_type = spi->write->iftype;
dummy = spi->write->dummy;
w_cmd = spi->write->cmd;
} else if (rw_op == RW_OP_READ) {
if_type = spi->read->iftype;
dummy = spi->read->dummy;
r_cmd = spi->read->cmd;
}
regval = OP_CFG_FM_CS(spi->chipselect) //片选 CS0还是CS1
| OP_CFG_MEM_IF_TYPE(if_type) //接口类型
| OP_CFG_ADDR_NUM(spi->addrcycle) //发送给flash的地址byte数
| OP_CFG_DUMMY_NUM(dummy); //对于dummy_en的操作Byte数
hifmc_write(host, FMC_OP_CFG, regval);
FMC_PR(DMA_DB, "\t\t Set OP_CFG[%#x]%#x\n", FMC_OP_CFG, regval);
regval = FMC_DMA_LEN_SET(size);
hifmc_write(host, FMC_DMA_LEN, regval);//dma 操作长度寄存器
FMC_PR(DMA_DB, "\t\t Set DMA_LEN[%#x]%#x\n", FMC_DMA_LEN, regval);
regval = (unsigned int)dma_buffer;
hifmc_write(host, FMC_DMA_SADDR_D0, regval); //对于spi nor 表示dma操作DDR起始地址寄存器;
FMC_PR(DMA_DB, "\t\t Set DMA_SADDR_D0[%#x]%#x\n", FMC_DMA_SADDR_D0,
regval);
regval = OP_CTRL_RD_OPCODE(r_cmd) //dma读操作命令
| OP_CTRL_WR_OPCODE(w_cmd) //dma写操作命令
| OP_CTRL_RW_OP(rw_op) //0=读 1=写
| OP_CTRL_DMA_OP_READY; //下发操作控制器状态 1=控制器忙
hifmc_write(host, FMC_OP_CTRL, regval); //操作控制寄存器
FMC_PR(DMA_DB, "\t\t Set OP_CTRL[%#x]%#x\n", FMC_OP_CTRL, regval);
FMC_DMA_WAIT_INT_FINISH(host); //等待控制器本次操作结束
FMC_PR(DMA_DB, "\t\t *-End dma transfer.\n");
return;
}
擦除函数 hifmc100_reg_erase 中 核心部分如下:
static int hifmc100_reg_erase(struct spi_flash *spiflash, u_int offset,
size_t length)
{
...
while (length) {
...
if (hifmc100_reg_erase_one_block(host, spi, offset)) {
hifmc_ip_user--;
return -1;
}
offset += spi->erase->size;
length -= spi->erase->size;
}
}
依次调用 hifmc100_reg_erase_one_block 擦除块;
//参数1:主机控制器
//参数2:spi flash设备
参数3:偏移
static int hifmc100_reg_erase_one_block(struct hifmc_host *host,
struct hifmc_spi *spi, unsigned int offset)
{
unsigned int regval;
FMC_PR(OP_DBG, "\t\t * Start erase one block, offset:%#x\n", offset);
regval = spi->driver->wait_ready(spi);
if (regval) {
DB_MSG("Error: Erase wait ready fail! reg:%#x\n", regval);
return 1;
}
spi->driver->write_enable(spi);
host->set_system_clock(spi->erase, ENABLE);
regval = FMC_CMD_CMD1(spi->erase->cmd);
hifmc_write(host, FMC_CMD, regval); //控制器发送给flash的操作命令
FMC_PR(OP_DBG, "\t\t Set CMD[%#x]%#x\n", FMC_CMD, regval);
regval = offset;
hifmc_write(host, FMC_ADDRL, regval);//配置器件地址
FMC_PR(OP_DBG, "\t\t Set ADDRL[%#x]%#x\n", FMC_ADDRL, regval);
regval = OP_CFG_FM_CS(spi->chipselect) //片选
| OP_CFG_MEM_IF_TYPE(spi->erase->iftype) //接口类型
| OP_CFG_ADDR_NUM(spi->addrcycle) //发送给flash的地址byte数
| OP_CFG_DUMMY_NUM(spi->erase->dummy);//根据器件读操作时序中dummy周期
hifmc_write(host, FMC_OP_CFG, regval);
FMC_PR(OP_DBG, "\t\t Set OP_CFG[%#x]%#x\n", FMC_OP_CFG, regval);
regval = FMC_OP_CMD1_EN(ENABLE) //使能向lash发送command1命令
| FMC_OP_ADDR_EN(ENABLE) //向flash写操作使能
| FMC_OP_REG_OP_START; //下发op操作控制器状态 1=忙
hifmc_write(host, FMC_OP, regval);
FMC_PR(OP_DBG, "\t\t Set OP[%#x]%#x\n", FMC_OP, regval);
FMC_CMD_WAIT_CPU_FINISH(host);
FMC_PR(OP_DBG, "\t\t * End erase one block.\n");
return 0;
}