

























以上的阶段指的是 Command-Address-Data三阶段,Command只占用一个字节。
MT25QU512
芯片手册:https://www.mouser.com/datasheet/2/671/mict_s_a0004996076_1-2290890.pdf

国产芯片:IS25WP512M QPI https://www.mouser.cn/datasheet/2/198/25LP_WP512M-1221196.pdf
QPI(Quad Peripheral Interface) 采用DQ0传输指令,地址和数据则通过DQ0~3传输。
MT25QU512ABB8E12-0SIT
我用的那款连线属于8E系,使用Qual SPI模式(复用功能略有不同,参考手册Figure5即可):
FLASH内部架构框图

注: DQ0~DQ3 是双向复用SPI数据线DIO/QIO,用于传输FLASH的指令数据地址信息。以下是各个DQ线的传输方向:

其中Memory的储存映射分布为

E系列是Sector父扇区(64KB) - Subsector子扇区32KB - Subsector孙扇区4KB,然后才是对孙扇区每个字节的寻址
也就是:必须找到孙扇区编号后,才能寻址。
这里关键可以配置
Quad IO 协议,是指令-地址-数据 4-4-4 模式
Dual IO协议,是指令-地址-数据 2-2-2模式






第二条提到:一般来说,模式前的数字代表这部分使用了多少DQ线,如2-4-4代表 传输command部分时使用2根DQ,传输Address部分时使用4根DQ,传输Data部分时使用4根DQ。
时序:
当然我们不需要那么多种模式,我们使用Quad SPI的时候,只需要关注4-4-4, 4-0-4, 4-0-0, 4-4-0这几种即可。
另外还需要特别关注的是 3-Bytes 和 4-Bytes地址模式的区别。
内部配置寄存器Internal Configuration 由易失和非易失组成(Nonvolatile configuration和Volatile configuration + enhanced volatile configuration)

非易失寄存器提供的配置项:
注:DTR是双边沿触发的意思,比与之相对的STR单边沿触发快一倍。
易失寄存器提供的功能配置项:

其中时钟周期配置根据这个表


其作用在地址和数据之间的间隔

Security Register可配置同时锁住第n个扇区(0 ~ 15) 并设置密码
由于FLASH介质问题,而且Flash芯片没有像EMMC那么高端,写入操作和常见的磁盘并不一样。所以写入的命令也不叫Write,而是叫PROGRAM


这部分一般是JEDEC规范+厂家自己的规范,这个ID用于识别厂商型号等等,底层Bootload到UBoot再到Kernel,都会使用这个ID来匹配启用对应的从设备FLASH驱动。

多项式:

用于对比读/写的数据正确性。

更多具体请查阅数据手册,在此仅抛砖引玉。
请见我的另一篇文章:Linux内核之SPI协议
我们这里选用 Qual SPI来操作Flash。
ZYNQMP 使用 QSPI 的官方指南文档:https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18841754/Zynqmp+QSPI+Driver
设备树配置大概是这样:

这里会用到两个关键驱动 compatible = "xlnx,zynqmp-qspi-1.0"; 和 compatible = "n25q512a", "jedec,spi-nor";
这部分的驱动只处理字节流
drivers/spi/spi-zynqmp-gqspi.c

关键probe在下图1358行,它使用了spi_controller结构体(SoC片上的SPI控制器实例)



主要的操作是:
zynqmp_qspi_mem_ops仅仅是开启SoC片上的QSPI控制器而已。zynqmp_qspi_mem_ops里面只有一个.exec_op成员,指向了zynqmp_qspi_exec_op,主要是初始化QSPI传输所需的底层实现,主要是QSPI协议的实现,如Command-Addr-Data模式配置,opcode、将TX/RX BUF和SOC QSPI寄存器上的收发寄存器交互等等。Tips: 大量使用了devm_开头的函数,这是Linux内核提供给开发者的设备相关的自动管理API,其生命周期(堆栈内存)会根据设备模型自动维护。详见:Devres - Managed Device Resource
内核NOR框架文档:SPI NOR framework
驱动源码位于 drivers/mtd/spi-nor/core.c

probe函数体
static int spi_nor_probe(struct spi_mem *spimem)
{
struct spi_nor_flash_parameter *params;
struct spi_device *spi = spimem->spi;
struct flash_platform_data *data = dev_get_platdata(&spi->dev);
struct spi_nor *nor;
/*
* Enable all caps by default. The core will mask them after
* checking what's really supported using spi_mem_supports_op().
*/
const struct spi_nor_hwcaps hwcaps = { .mask = SNOR_HWCAPS_ALL };
char *flash_name;
int ret;
nor = devm_kzalloc(&spi->dev, sizeof(*nor), GFP_KERNEL);
if (!nor)
return -ENOMEM;
nor->spimem = spimem;
nor->dev = &spi->dev;
spi_nor_set_flash_node(nor, spi->dev.of_node);
if (nor->spimem)
init_completion(&nor->spimem->request_completion);
spi_mem_set_drvdata(spimem, nor);
if (data && data->name)
nor->mtd.name = data->name;
if (!nor->mtd.name)
nor->mtd.name = spi_mem_get_name(spimem);
/*
* For some (historical?) reason many platforms provide two different
* names in flash_platform_data: "name" and "type". Quite often name is
* set to "m25p80" and then "type" provides a real chip name.
* If that's the case, respect "type" and ignore a "name".
*/
if (data && data->type)
flash_name = data->type;
else if (!strcmp(spi->modalias, "spi-nor"))
flash_name = NULL; /* auto-detect */
else
flash_name = spi->modalias;
ret = spi_nor_scan(nor, flash_name, &hwcaps);
if (ret)
return ret;
spi_nor_debugfs_register(nor);
params = spi_nor_get_params(nor, 0);
/*
* None of the existing parts have > 512B pages, but let's play safe
* and add this logic so that if anyone ever adds support for such
* a NOR we don't end up with buffer overflows.
*/
if (params->page_size > PAGE_SIZE) {
nor->bouncebuf_size = params->page_size;
devm_kfree(nor->dev, nor->bouncebuf);
nor->bouncebuf = devm_kmalloc(nor->dev,
nor->bouncebuf_size,
GFP_KERNEL);
if (!nor->bouncebuf)
return -ENOMEM;
}
ret = spi_nor_create_read_dirmap(nor);
if (ret)
return ret;
ret = spi_nor_create_write_dirmap(nor);
if (ret)
return ret;
return mtd_device_register(&nor->mtd, data ? data->parts : NULL,
data ? data->nr_parts : 0);
}
主要操作有:
。。。未完待续
--------蓝天上的云_转载请注明出处.
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。