Linux kernel调试 SPI NORFLASH--W25Q128

news2024/11/25 22:56:38

W25Q128介绍

W25Q128 是华邦公司推出的一款 SPI 接口的 NOR Flash 芯片,其存储空间为 128Mbit,相当于 16M 字节。W25Q128 可以支持 SPI 的模式 0 和模式 3,也就是 CPOL=0/CPHA=0 和CPOL=1/CPHA=1 这两种模式。
    
Flash 写入数据时和 EEPROM 类似,不能跨页写入,一次最多写入一页,W25Q128的一页是 256 字节。写入数据一旦跨页,必须在写满上一页的时候,等待 Flash 将数据从缓存搬移到非易失区,重新再次往里写。Flash 有一个特点,就是可以将 1 写成 0,但是不能将 0 写成 1,要想将 0 写成 1,必须进行擦除操作。因此通常要改写某部分空间的数据,必须首先进行一定物理存储空间擦除,最小的擦除空间,通常称之为扇区,扇区擦除就是将这整个扇区每个字节全部变成 0xFF。每款 Flash 的扇区大小不一定相同,W25Q128 的一个扇区是 4096 字节。为了提高擦除效率,使用不同的擦除指令还可以一次性进行 32K(8 个扇区)、64K(16 个扇区)以及整片擦除。
    
W25Q128的擦写周期多达10W次,可将数据保存达20年之久,支持2.7~3.6V的电压,支持标准的SPI,还支持双输出/四输出的SPI,最大SPI时钟可达80MHz。

本文使用的硬件平台: RockChip ITX-3588J,在其平台上添加 W25Q128 芯片(SPI 设备),Linux 内核版本为 kernel-5.15.0,采用 DeviceTree 描述硬件连接信息。

硬件连接

在这里插入图片描述

Linux Kernel驱动代码分析

理论–MTD子系统框架

在这里插入图片描述
在这里插入图片描述

MTD(Memory Technology Device)即常说的Flash等使用存储芯片的存储设备,MTD子系统对应的是块设备驱动框架中的设备驱动层,可以说,MTD就是针对Flash设备设计的标准化硬件驱动框架。

MTD层为NOR FLASH和NAND FLASH设备提供统一接口。MTD将文件系统与底层FLASH存储器进行了隔离。如图2.1所示,MTD设备通常可分为五层,从上到下依次是:设备节点、MTD设备层、MTD原始设备层、硬件驱动层和硬件设备层。
    Flash硬件驱动层:(相当于spi driver/i2c driver),Flash硬件驱动层负责对Flash硬件的读、写和擦除操作。MTD设备的Nand Flash芯片的驱动则在drivers/mtd/nand/子目录下,Nor Flash芯片驱动位于drivers/mtd/chips/子目录下。
    MTD原始设备层:(相当于spi master/i2c client),用于描述MTD原始设备的数据结构是mtd_info,它定义了大量的关于MTD的数据和操作函数。其中mtdcore.c: MTD原始设备接口相关实现,mtdpart.c : MTD分区接口相关实现。
    MTD设备层:基于MTD原始设备,linux系统可以定义出MTD的块设备(主设备号31)和字符设备(设备号90)。其中mtdchar.c : MTD字符设备接口相关实现,mtdblock.c : MTD块设备接口相关实现。
    设备节点:通过mknod在/dev子目录下建立MTD块设备节点(主设备号为31)和MTD字符设备节点(主设备号为90)。通过访问此设备节点即可访问MTD字符设备和块设备。

设备树节点

根据实际的硬件连接情况修改设备树文件。查看rk3588linux/rk3588_repo_sdk_v1.0.2a/kernel/arch/arm64/boot/dts/rockchip下设备树文件(rk3588s.dtsi 和rk3588-firefly-itx-3588j .dtsi)中spi1节点的属性;

	spi1: spi@feb10000 {
		compatible = "rockchip,rk3066-spi", "rockchip,rk3066-spi";
		reg = <0x0 0xfeb10000 0x0 0x1000>;
		interrupts = <GIC_SPI 327 IRQ_TYPE_LEVEL_HIGH>;
		#address-cells = <1>;
		#size-cells = <0>;
		clocks = <&cru CLK_SPI1>, <&cru PCLK_SPI1>;
		clock-names = "spiclk", "apb_pclk";
		dmas = <&dmac0 16>, <&dmac0 17>;
		dma-names = "tx", "rx";
		pinctrl-names = "default";
		pinctrl-0 = <&spi1m1_cs0 &spi1m1_cs1 &spi1m1_pins>;
		num-cs = <2>;
		status = "okay";
	};

而在板级设备树rk3588-firefly-itx-3588j .dtsi中并没有相关的定义,添加如下:

/* spi norflash w25q128 on spi1 controller */
&spi1 {
	status = "okay";
	#address-cells = <1>;
	#size-cells = <0>;
	pinctrl-0 = <&spi1m2_cs0 &spi1m2_cs1 &spi1m2_pins>;
	w25q128@0 {
		compatible = "jedec,spi-nor";
		//label = "spi_nor";
		reg = <0x00>;
		spi-tx-bus-width = <1>;
		spi-rx-bus-width = <4>;
		spi-max-frequency = <50000000>;
		status = "okay";
	};
};

JEDEC是一个定义半导体行业标准的机构,大部分的SPI FLASH都遵循其制定的SFDP标准,软件开发按照标准操作即可。

m25p80.c(https://elixir.bootlin.com/linux/v4.5/source/drivers/mtd/devices/m25p80.c)基于SPI NOR框架提供了对常用flash的支持,包括对W25Q128的支持。历史上,许多闪存设备通过其名称绑定到此驱动程序。但大多数这些flash在某种程度上是兼容的。

在rk3588linux/rk3588_repo_sdk_v1.0.2a/kernel/drivers/mtd/devices下面并没有m25p80.c的驱动代码,但是在rk3588linux/rk3588_repo_sdk_v1.0.2a/kernel/drivers/mtd/spi-nor下面有一个叫core.c的文件,该文件开头注释为

// SPDX-License-Identifier: GPL-2.0
/*
 * Based on m25p80.c, by Mike Lavender (mike@steroidmicros.com), with
 * influence from lart.c (Abraham Van Der Merwe) and mtd_dataflash.c
 *
 * Copyright (C) 2005, Intec Automation Inc.
 * Copyright (C) 2014, Freescale Semiconductor, Inc.
 */

这是一份基于m25p80.c的驱动代码,通过查看ids结构体发现也支持W25Q128。

/*
 * Do NOT add to this array without reading the following:
 *
 * Historically, many flash devices are bound to this driver by their name. But
 * since most of these flash are compatible to some extent, and their
 * differences can often be differentiated by the JEDEC read-ID command, we
 * encourage new users to add support to the spi-nor library, and simply bind
 * against a generic string here (e.g., "jedec,spi-nor").
 *
 * Many flash names are kept here in this list (as well as in spi-nor.c) to
 * keep them available as module aliases for existing platforms.
 */
static const struct spi_device_id spi_nor_dev_ids[] = {
	/*
	 * Allow non-DT platform devices to bind to the "spi-nor" modalias, and
	 * hack around the fact that the SPI core does not provide uevent
	 * matching for .of_match_table
	 */
	{"spi-nor"},

	/*
	 * Entries not used in DTs that should be safe to drop after replacing
	 * them with "spi-nor" in platform data.
	 */
	{"s25sl064a"},	{"w25x16"},	{"m25p10"},	{"m25px64"},

	/*
	 * Entries that were used in DTs without "jedec,spi-nor" fallback and
	 * should be kept for backward compatibility.
	 */
	{"at25df321a"},	{"at25df641"},	{"at26df081a"},
	{"mx25l4005a"},	{"mx25l1606e"},	{"mx25l6405d"},	{"mx25l12805d"},
	{"mx25l25635e"},{"mx66l51235l"},
	{"n25q064"},	{"n25q128a11"},	{"n25q128a13"},	{"n25q512a"},
	{"s25fl256s1"},	{"s25fl512s"},	{"s25sl12801"},	{"s25fl008k"},
	{"s25fl064k"},
	{"sst25vf040b"},{"sst25vf016b"},{"sst25vf032b"},{"sst25wf040"},
	{"m25p40"},	{"m25p80"},	{"m25p16"},	{"m25p32"},
	{"m25p64"},	{"m25p128"},
	{"w25x80"},	{"w25x32"},	{"w25q32"},	{"w25q32dw"},
	{"w25q80bl"},	{"w25q128"},	{"w25q256"},

	/* Flashes that can't be detected using JEDEC */
	{"m25p05-nonjedec"},	{"m25p10-nonjedec"},	{"m25p20-nonjedec"},
	{"m25p40-nonjedec"},	{"m25p80-nonjedec"},	{"m25p16-nonjedec"},
	{"m25p32-nonjedec"},	{"m25p64-nonjedec"},	{"m25p128-nonjedec"},

	/* Everspin MRAMs (non-JEDEC) */
	{ "mr25h128" }, /* 128 Kib, 40 MHz */
	{ "mr25h256" }, /* 256 Kib, 40 MHz */
	{ "mr25h10" },  /*   1 Mib, 40 MHz */
	{ "mr25h40" },  /*   4 Mib, 40 MHz */

	{ },
};

在这里插入图片描述

SPI NorFlash驱动流程的分析
在这里插入图片描述

这里要把SPI flash设备注册为MTD设备,MTD子系统实现了SPI flash芯片驱动程序,其驱动 Demo 为:

drivers/mtd/devices/mtd_dataflash.c
(*Atmel AT45xxx DataFlash MTD driver for lightweight SPI framework)

drivers/mtd/devices/m25p80.c
(MTD SPI driver for ST M25Pxx (and similar) serial flash chips)

我们这里使用的是与m25p80相似的flash,所以套用源码文件m25p80.c,并没有对该文件进行修改。通读 m25p80.c 驱动代码,我们可以找出大概的脉络。首先是通过 module_spi_driver 函数注册 m25p80_driver 驱动,其中实现了 probe 和 remove 函数,分别是 m25p_probe 和 m25p_remove。并且填写了一张名为 m25p_ids 的兼容设备表,设备表中包含了"w25q128"。

m25p_probe

/*
 * board specific setup should have ensured the SPI clock used here
 * matches what the READ command supports, at least until this driver
 * understands FAST_READ (for clocks over 25 MHz).
 */
static int m25p_probe(struct spi_device *spi)
{
    struct flash_platform_data  *data;
    struct m25p *flash;
    struct spi_nor *nor;
    struct spi_nor_hwcaps hwcaps = {
        .mask = (SNOR_HWCAPS_READ |
             SNOR_HWCAPS_READ_FAST |
             SNOR_HWCAPS_PP),
    };
    char *flash_name;
    int ret;

    data = dev_get_platdata(&spi->dev);

    flash = devm_kzalloc(&spi->dev, sizeof(*flash), GFP_KERNEL);
    if (!flash)
        return -ENOMEM;

    nor = &flash->spi_nor;

    /* install the hooks */
    nor->read = m25p80_read;
    nor->write = m25p80_write;
    nor->write_reg = m25p80_write_reg;
    nor->read_reg = m25p80_read_reg;

    nor->dev = &spi->dev;
    spi_nor_set_flash_node(nor, spi->dev.of_node);
    nor->priv = flash;

    spi_set_drvdata(spi, flash);
    flash->spi = spi;

    if (spi->mode & SPI_RX_QUAD) {
        hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4;

        if (spi->mode & SPI_TX_QUAD)
            hwcaps.mask |= (SNOR_HWCAPS_READ_1_4_4 |
                    SNOR_HWCAPS_PP_1_1_4 |
                    SNOR_HWCAPS_PP_1_4_4);
    } else if (spi->mode & SPI_RX_DUAL) {
        hwcaps.mask |= SNOR_HWCAPS_READ_1_1_2;

        if (spi->mode & SPI_TX_DUAL)
            hwcaps.mask |= SNOR_HWCAPS_READ_1_2_2;
    }

    if (data && data->name)
        nor->mtd.name = data->name;

    /* 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;

    return mtd_device_register(&nor->mtd, data ? data->parts : NULL,
                   data ? data->nr_parts : 0);
}

在 m25p_probe 函数中指定了 m25p80_read、m25p80_write 和m25p80_erase 等文件操作函数,当应用程序使用 read、write、ioctl 等接口操作时最终会调用到这里。那 open 和 close 函数呢? 我们把 W25Q128注册成 MTD 设备了,所以另外一些操作函数在 drivers/mtd/mtdchar.c 中定义。实际上,它不仅有 mtdchar_open、mtdchar_close 等函数,还有 mtdchar_read 和 mtdchar_write 函数,而它们会调用 m25p80.c 中的 m25p80_read 和 m25p80_write 函数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/587635.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Linux初阶】基础IO - 文件操作(使用系统接口实现) | vim批量注释代码

&#x1f31f;hello&#xff0c;各位读者大大们你们好呀&#x1f31f; &#x1f36d;&#x1f36d;系列专栏&#xff1a;【Linux初阶】 ✒️✒️本篇内容&#xff1a;重新理解文件和文件操作&#xff0c;C语言实现的简单文件操作&#xff0c;文本初始权限&#xff0c;系统接口介…

【spring源码系列-01】spring底层源码整体概述

JVM系列整体栏目 内容链接地址【一】spring源码整体概述https://blog.csdn.net/zhenghuishengq/article/details/130940885 初识虚拟机与java虚拟机 一&#xff0c;spring源码整体概述1&#xff0c;初步概述2&#xff0c;扩展点机制3&#xff0c;核心方法refresh4&#xff0c;B…

【wpf】xaml 中的参数复用

背景 xaml中有几种复用的方式&#xff1a; 有时在xaml中&#xff0c;我们需要复用一些参数&#xff0c;比如 固定的一个值。 有时是固定的一个样式。 资源&#xff0c;sys的引入 有时多个控件都要设置一个高度&#xff0c;我可以引入sys 声明 我就使用这个吧&#xff1a…

扬帆出海正当时,企业应该做好哪些准备?

在跨境出海的时代大潮中&#xff0c;想要拓展海外市场的中国企业&#xff0c;应该事先做好哪些准备&#xff1f; 中国企业出海的新格局 首先来看一组令人振奋的数据。来自中国信通院的数据显示&#xff0c;在2020年的时候&#xff0c;中国数字经济的规模就达到了39.2万亿元人民…

本地Linux搭建web服务并发布公网访问

文章目录 前言1. 本地环境服务搭建2. 局域网测试访问3. 内网穿透3.1 ubuntu本地安装cpolar内网穿透3.2 创建隧道3.3 测试公网访问 4. 配置固定二级子域名4.1 保留一个二级子域名4.2 配置二级子域名4.3 测试访问公网固定二级子域名 转载自cpolar极点云的文章&#xff1a;在Ubunt…

玩转华为云Astro低代码体验季

目录 Astro轻应用应用场景 零代码应用构建 轻应用构建 行业应用构建 业务大屏构建 使用体验 功能建议 总体评价 Astro轻应用&#xff08;Astro Zero&#xff0c;简称AstroZero&#xff09;是华为云为行业客户、合作伙伴、开发者量身打造的低代码/零代码应用开发平台&#xff0c…

C++ A lambda function

lambda 函数是 C 中的匿名函数&#xff0c;可以内联定义并用作函数对象。 下面是定义 lambda 函数的一般语法&#xff1a; [capture list] (parameter list) -> return type { function body }lambda 语法的每个部分&#xff1a; - capture list&#xff1a;这是一个可选的…

R实践——【rgplates】功能函数解析

【rgplates】功能函数解析 1. 板块和特征重建2. 构造模型表示2.1 用法2.2 参数2.3 值2.4 示例 3. 实用工具3.1 用法3.2 参数3.3. 值3.4 示例 1. 板块和特征重建 一切与几何形状重建到过去状态有关的东西 reconstruct()&#xff1a;重建地理特征 详见R语言实践——古今地理坐…

4. WebGPU 存储缓冲区 (WebGPU Storage Buffers)

这篇文章是关于存储缓冲区的&#xff0c;我们从上一篇文章暂停的地方继续。 存储缓冲区在许多方面类似于统一缓冲区。如果我们所做的只是将 JavaScript 中的 UNIFORM 更改为 STORAGE 并将 WGSL 中的 var 更改为 var<storage, read> &#xff0c;那么上一页中的示例就可以…

Zabbix“专家坐诊”第193期问答汇总

问题一 Q&#xff1a;大佬们&#xff0c;怎么才能将zabbix-server接收到的数据全部展示出来呢&#xff1f;目前我的显示数据无法全部显示。 A&#xff1a;这个是用zabbix_sender发送过来的&#xff1f;确认下数据中是否包含空格等&#xff0c;如果有空格使用反斜杠转义或者单…

uniapp内置组件

目录 3.1、视图容器 view scroll-view swiper match-media 3.2、表单组件 form input App平台iOS端软键盘上方横条去除方案 关于软键盘弹出的逻辑说明 关于软键盘收起的逻辑说明 picker 3.3、 路由与页面跳转 navigator组件 3.4、 地图 map 3.1、视图容器 所有…

2.5. 重载与覆盖

在 Java 中&#xff0c;方法的重载&#xff08;Overloading&#xff09;和覆盖&#xff08;Overriding&#xff09;是两个重要的概念。它们都涉及到方法的定义与使用&#xff0c;但作用和规则有所不同。 重载&#xff08;Overloading&#xff09; 重载是指在同一个类中定义多…

2023年6月18日DAMA-CDGA/CDGP数据治理认证报名到这里

DAMA认证为数据管理专业人士提供职业目标晋升规划&#xff0c;彰显了职业发展里程碑及发展阶梯定义&#xff0c;帮助数据管理从业人士获得企业数字化转型战略下的必备职业能力&#xff0c;促进开展工作实践应用及实际问题解决&#xff0c;形成企业所需的新数字经济下的核心职业…

在家远程使用公司用友ERP财务软件 【远程办公】

文章目录 前言1.本地访问简介2. cpolar内网穿透3. 公网远程访问4. 固定公网地址 转发自cpolar极点云的文章&#xff1a;外网远程访问公司内网用友畅捷通T财务软件 – 远程办公 前言 用友畅捷通T适用于异地多组织、多机构对企业财务汇总的管理需求&#xff1b;全面支持企业对远…

webpack简单的搭建和使用(1)

随便创建一个空的文件夹&#xff0c;例如说&#xff1a;explore 然后我们测试一下我们的node是否存在 可以正确打印出版本 我们再次输入&#xff1a;npm init -y 创建一个package.json文件 出现这样的情况就成功了 然后我们要安装webpack在终端上输入命令&#xff1a; npm i …

数据结构图的基础概念

1、图的概念 图(Graph)&#xff1a;是由顶点的有穷非空集合和顶点之间边的集合组成。顶点(Vertex)&#xff1a;图中的数据元素。边(Edge)&#xff1a;顶点之间的逻辑关系,边可以是有向的或无向的&#xff0c;也可以带有权重&#xff08;可以表示距离&#xff0c;花费等&#xf…

GaussDB云数据库SQL应用系列-视图管理

一、前言 GaussDB是一款基于云计算技术的高性能关系型数据库&#xff0c;支持多种数据模型和分布式架构。在GaussDB中&#xff0c;视图管理是非常重要的一项功能&#xff0c;它可以帮助用户更方便地管理和查询数据。 数据库视图管理是指对数据库中的视图进行创建、修改、删除…

美债危机现曙光,比特币再破2万8

* * * 原创&#xff1a;刘教链 * * * 号外&#xff1a;今天在小号“刘教链Pro”发表了一篇《常常自律&#xff0c;偶尔放纵》&#xff0c;谈了一下关于意志力和自制力的非同寻常的科学研究结论&#xff0c;及其对投资方法的启迪&#xff0c;欢迎关注“刘教链Pro”并阅读。 * *…

AI专业教您保姆级在暗影精灵8Windows11上本地部署实现AI绘画:Stable Diffusion(万字教程,多图预警)

目录 一、Stable Diffusion介绍 二、Stable Diffusion环境搭建 1.Anaconda下载与安装 2.Pycharm&#xff08;IDE&#xff09;下载与安装 3.CUDA、CuDNN下载与安装 三、Stable Diffusion的本地部署 1.克隆项目到本地 2.初始化打开项目 3.安装环境所需库 4.运行代码…

《逆袭进大厂》之C++篇49问49答

它是在 github 上的 clone 下来的仓库笔记 自己看书理解到的知识点 网上相关问题的博客总结这几大基础上慢慢总结形成的&#xff0c;并不仅仅只是简单的收集整理&#xff0c;没有加入自己思考的笔记没有灵魂。 在接下来的十篇文章里我会陆陆续续将自己的秋招笔记整理出来&…