首页 > 系统相关 >Linux内核源码-存储驱动之 QSPI Flash

Linux内核源码-存储驱动之 QSPI Flash

时间:2024-04-29 17:44:45浏览次数:30  
标签:name Linux Flash spi 地址 源码 寄存器 SPI nor

传输方式 DIO/QIO/DOUT/QPI

  • QPI模式(Quad Peripheral Interface),所有阶段都通过4线传输。与之相对的是SPI。
  • SPI模式:
    • 纯种SPI(MISO/MOSI两个数据线)
    • DOUT 全称 Dual I/O,命令字和地址字均为单线,仅在数据阶段为双线。
    • QOUT 全称 Quad I/O,命令字和地址字均为单线,仅在数据阶段为双线。
    • DIO 全称 Dual I/O (DQ0,DQ1两个数据线),首个命令字为单线传输,后面地址和数据为双线。
    • QIO 全称 Quad I/O (DQ0~DQ3四个数据线),首个命令字为单线传输,后面地址和数据为四线。

以上的阶段指的是 Command-Address-Data三阶段,Command只占用一个字节。

常见FLASH芯片详解

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即可):

  • S# 接上拉电阻+SPI片选引脚
  • C 时钟线
  • DQ0
  • DQ1
  • DQ2/W# 写保护
  • DQ3/HOLD#
  • RESET# 复位,QIO-SPI模式下不可用。

FLASH内部架构框图
框图

  1. 控制线连接到控制逻辑Control logic,用于整体的状态操作,类似于FPGA的全局开关Flag。全程状态寄存器用于指示闪存模块Memory就绪等状态。
  2. DQ连接到I/O移位寄存器(这个是SPI原理),然后根据DQ内容执行以下分支:
  3. 如果DQ是地址,那么通过地址寄存器和计数器用于寻址,映射到闪存模块Memory上的X,Y二维地址矩阵。
  4. 如果DQ是数据,那么则Buffer模块作为缓冲,用于从闪存模块Memory储存上读写数据后置于移位寄存器,这涉及串并转换。
  5. 如果DQ是OTP,则对应到"64 OTP bytes"模块,执行对应的指令。OTP(全称ONE-TIME PROGRAMMABLE)这种只能写入一次的空间常用于放置加密密钥或者唯一ID。
  6. 如果是状态指令,可对两个8位的状态寄存器进行读写。状态寄存器TOP BP3~BP0可以组合指示FLASH只读保护区

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

其中Memory的储存映射分布为
image

E系列是Sector父扇区(64KB) - Subsector子扇区32KB - Subsector孙扇区4KB,然后才是对孙扇区每个字节的寻址
也就是:必须找到孙扇区编号后,才能寻址。

关于JEDEC标准

寄存器

Nonvolatile Configuration Register

这里关键可以配置

  • 协议模式,如Quad/Dual
  • 地址模式4-byte或3-byte address mode
  • XIP速度模式
  • 时钟周期(Number of dummy clock cycles),周期数必须和时钟频率一致,否则储存器读取到的数据不正确

I/O protocol

Quad IO 协议,是指令-地址-数据 4-4-4 模式
Dual IO协议,是指令-地址-数据 2-2-2模式
image
image
image
image
image

Note
第二条提到:一般来说,模式前的数字代表这部分使用了多少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/4字节地址模式

另外还需要特别关注的是 3-Bytes 和 4-Bytes地址模式的区别。

  • 4Bytes地址模式会直接使用Address寄存器,地址寻址为A[31:0]
  • 3Bytes地址模式,仅仅支持128MB储存,它有个Extened Address寄存器,低3位表示储存所在的段序号,高5位表示地址,组成地址寻址A[31:24]。

内部配置寄存器(Internal Configuration Register)

内部配置寄存器Internal Configuration 由易失和非易失组成(Nonvolatile configuration和Volatile configuration + enhanced volatile configuration)
image

非易失寄存器提供的配置项:

  • 4/3字节地址模式
  • 3字节地址模式所选的128MB段,
  • Quad I/O 协议开关
  • Dual I/O 协议开关
  • DTR(Double transfer rate) 协议开关
  • 电流驱动力
  • XIP模式:Fast/Dual/Quad等等
  • 时钟周期(Number of dummy clock cycles),周期数必须和时钟频率一致,否则储存器读取到的数据不正确

注:DTR是双边沿触发的意思,比与之相对的STR单边沿触发快一倍。

易失寄存器提供的功能配置项:

  • 时钟周期(Number of dummy clock cycles),周期数必须和时钟频率一致,否则储存器读取到的数据不正确
  • XIP开关
  • Wrap 填充 用于N字节对齐(连续不需对齐/64B/32B/16B对齐),也和字节顺序有关,效果如下表
    image
    增强易失寄存器提供的功能配置项:
  • Quad I/O协议开关
  • Dual I/O协议开关
  • DTR 协议开关
  • Reset/Hold 开关位
  • 电流驱动能力

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

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

安全寄存器

Security Register可配置同时锁住第n个扇区(0 ~ 15) 并设置密码

写入操作/PROGRAM

由于FLASH介质问题,而且Flash芯片没有像EMMC那么高端,写入操作和常见的磁盘并不一样。所以写入的命令也不叫Write,而是叫PROGRAM

  1. 读取STATUS寄存器查看BUSY位,只有芯片不BUSY的时候才能继续下面的操作
  2. 发送Write Enable指令
  3. 发送PROGRAM指令
  4. FLASH芯片会自动回到Write Disabled状态

PROGRAM
QUAD_PROGRAM

常用指令

Device ID Data

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

CRC

image
多项式:
image
用于对比读/写的数据正确性。

STATUS Table

image

更多具体请查阅数据手册,在此仅抛砖引玉。

Linux驱动部分

SPI驱动

请见我的另一篇文章:Linux内核之SPI协议

配置驱动

我们这里选用 Qual SPI来操作Flash。

ZYNQMP 使用 QSPI 的官方指南文档:https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18841754/Zynqmp+QSPI+Driver
设备树配置大概是这样:
image

这里会用到两个关键驱动 compatible = "xlnx,zynqmp-qspi-1.0";compatible = "n25q512a", "jedec,spi-nor";

QSPI控制器驱动源码

这部分的驱动只处理字节流

drivers/spi/spi-zynqmp-gqspi.c

image

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

image

image

主要的操作是:

  1. 分配spi_controller控制器实例
  2. 配置platform驱动私有数据pdev
  3. 设备树匹配和处理
  4. plarform驱动的资源ioremap (寄存器映射)
  5. 时钟配置
  6. 电源管理pm_runtime_开头的API
  7. SPI模式配置(相位、极性、Dual/Quad模式、速率、片选等)
  8. QSPI硬件控制器初始化
  9. 中断处理
  10. DMA掩码配置
  11. fops指针赋值(zynqmp_qspi_mem_ops、zynqmp_qspi_setup_op)
  • 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寄存器上的收发寄存器交互等等。
  1. devm_spi_register_controller
  2. 启动pm_runtime

Tips: 大量使用了devm_开头的函数,这是Linux内核提供给开发者的设备相关的自动管理API,其生命周期(堆栈内存)会根据设备模型自动维护。详见:Devres - Managed Device Resource

NOR FLASH 驱动源码

内核NOR框架文档:SPI NOR framework

驱动源码位于 drivers/mtd/spi-nor/core.c

image

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);
}

主要操作有:

  1. 配置支持的特性
  2. 分配内存并赋值
  3. 私有数据
  4. name处理
  5. 通过spi_nor_scan扫描总线
  6. debugfs注册
  7. 从FLASH硬件获取参数
  8. 创建读写所需的dirmap
  9. 注册mtd设备

。。。未完待续

标签:name,Linux,Flash,spi,地址,源码,寄存器,SPI,nor
From: https://www.cnblogs.com/yucloud/p/18154638/Linux_Kernel_driver_QSPI_NorFLash

相关文章

  • linux安装selenium步骤
    1,安装selenium模块pip3installselenium2,安装谷歌浏览器yuminstallhttps://dl.google.com/linux/direct/google-chrome-stable_current_x86_64.rpm-y3安装chromedriver1)运行下面命令查看浏览器版本google-chrome--version 出现这个代表谷歌浏览器安装成功2)谷歌......
  • linux6-touch&cat&more
    linux6-touch&cat&moretouch创建文件在/tmp目录下创建test.txt文件touch/tmp/test.txt填写多个参数创建多个文件touchtest1.txttest2.txttest3.txtcatcat,concatnate,查看文件内容查看/etc/目录下的service文件内容cat/etc/servicemore查看文件内容cat......
  • linux7-cp&rf&rm
    linux7-cp&mv&rmcpcp,copy,用于复制文件/文件夹将当前目录下的test.txt复制到当前目录下的test2.txt,不存在时自动创建cptest.txttest2.txt选项:-r可用于复制文件夹使用,表示递归不添加-r选项时,包括目录时会略过添加-r选项mvmv,move移动文件/文件夹移动......
  • Linux下制作Nginx绿色免安装包
    前言linux下安装nginx比较繁琐,遇到内网部署环境更是麻烦,所以研究了下nginx绿色免安装版的部署包制作,开箱即用,特此记录分享,一下操作在centos8环境下安装,如果需要其他内核系统的安装(Debian/Ubuntu等),请在对应环境虚拟机下安装制作安装包制作安装依赖yuminstallgcc-c++pcreper......
  • linux系统 centos7禁止root账号登录
    没有账号的新增账号:sudouseradd-m账号名称sudopasswd账号名称执行完上面命令会让你输入密码输入密码:xxxxxxx1、(注意:禁止root账户登陆前确保有其他账户可以正常使用)编辑配置文件`/etc/ssh/sshd_config`,将`PermitRootLoginyes`改为`PermitRootLoginno`  2、执......
  • linux修改shell,以及安装zsh配置oh-my-zsh.md
    查看当前shellecho$SHELL查看系统中有哪些shellcat/etc/shells修改shell,输入要切换的shell,例/bin/zshchsh-s/bin/zsh安装zshyuminstall-yzshoh-my-zsh克隆zshgitclonehttps://github.com/robbyrussell/oh-my-zsh.git~/.oh-my-zshgithub拉不下来的话去gitee......
  • 2-LinuxJava安装
    环境CentOS7.5Java8卸载现有JDKrpm-qa|grep-ijava|xargs-n1sudorpm-e--nodseps上传Java压缩包将jdk-8u212-linux-x64.tar文件上传到/opt/software目录中解压Java压缩包进入/opt/software目录cd/opt/software解压缩文件到指定目录tar......
  • 1-Linux集群搭建,分发脚本,ssh免密登录
    Linux集群部署集群规划模板机安装创建完成后全部打开并登录root账户修改克隆主机名vim/etc/sysconfig/network-scripts/ifcfg-ens33esc退出并输入:wq保存按i修改IPADDR为192.168.10.101/192.168.10.102/192.168.10.103vim/etc/hostname按i修改名字......
  • LINUX 网络
    LINUX网络网络配置命令ifconfig来源于net-tools[root@localhost~]#yuminstallnet-tools-y ifconfig 查看网卡信息,只显示开启的网卡ifconfig -a 查看所以网卡信息ifconfig 网卡名称 up|down 开启|关......
  • winscp/putty 免密登录linux server
    参考 puttyWinScp免密登录远程Linux 原理生成一对公钥和私钥,私钥以文件的形式保存在本地,公钥保存在远程机器上,一般是/home/users/username/.ssh/authorized_keys。这样每次登录只需指定私钥文件,远程机器通过比对公钥和私钥来验证登录的合法性第一步:生成公钥/私钥双击putt......