ARM uboot 源码分析9 - uboot的硬件驱动部分

news2025/1/16 5:01:28

一、uboot 与 linux 驱动

1、uboot 本身是裸机程序

(1) 裸机本来是没有驱动的概念的(狭义的驱动的概念就是,操作系统中用来具体操控硬件的那部分代码叫驱动)

(2) 裸机程序中是直接操控硬件的,操作系统中必须通过驱动来操控硬件。这两个有什么区别?本质区别就是分层。


2、uboot 的虚拟地址对硬件操作的影响

(1) 操作系统(指的是 linux)下 MMU 肯定是开启的,也就是说,linux 驱动中肯定都使用的是虚拟地址。而纯裸机程序中,根本不会开 MMU,全部使用的是物理地址。这是裸机下和驱动中操控硬件的一个重要区别。

(2) uboot 早期也是纯物理地址工作的,但是现在的 uboot 开启了 MMU, 做了虚拟地址映射,这个东西驱动也必须考虑。查 uboot 中的虚拟地址映射表,发现除了 0x30000000-0x3FFFFFFF 映射到了 0xC0000000-0xCFFFFFFF 之外,其余的虚拟地址空间全是原样映射的。

而我们驱动中,主要是操控硬件寄存器,而 S5PV210 的 SFR 都在 0xExxxxxx 地址空间,属于原地址映射,因此驱动中不必考虑虚拟地址。

在这里插入图片描述


3、uboot 借用(移植)了 linux 驱动

(1) linux 驱动本身做了模块化设计。linux 驱动本身和 linux 内核不是强耦合的,这是 linux 驱动可以被 uboot 借用(移植)的关键。

(2) uboot 移植了 linux 驱动源代码。uboot 是从源代码级别去移植 linux 驱动的,这就是 linux 系统的开源性。

(3) uboot 中的硬件驱动比 linux 简单。linux 驱动本身有更复杂的框架,需要实现更多的附带功能,而 uboot 本质上只是个裸机程序,uboot 移植 linux 驱动时,只是借用了 linux 驱动的一部分而已。


二、iNand/SD 驱动解析1

1、从 start_armboot 开始

(1) 驱动整体比较庞大,涉及很多个文件夹下的很多文件,函数更多,贸然插入根本不知道看哪里。学习时必须有顺序。

在这里插入图片描述


2、mmc_initialize

(1) 函数位于:uboot/drivers/mmc/mmc.c。

在这里插入图片描述


(2) 从名字可以看出,这个函数的作用就是,初始化开发板上 MMC 系统。MMC 系统的初始化应该包含这么几部分:

  • SoC 里的 MMC 控制器初始化(MMC 系统时钟的初始化、SFR 初始化)
  • SoC 里 MMC 相关的 GPIO 的初始化
  • SD 卡/iNand 芯片的初始化。

(3) mmc_devices 链表,是全局变量,用来记录系统中所有已经注册的 SD/iNand 设备。所以向系统中插入一个 SD卡/iNand 设备,则系统驱动就会向 mmc_devices 链表中插入一个数据结构,来表示这个注册到系统中的设备。

在这里插入图片描述


3、cpu_mmc_init

在这里插入图片描述

(1) 函数位于:uboot/cpu/s5pc11x/cpu.c中。实质是通过调用 3 个函数来完成的。


(2) setup_hsmmc_clock,在 uboot/cpu/s5pc11x/setup_hsmmc.c 中。看名字,函数是用来初始化 SoC 中 MMC 控制器中的时钟部分的。

在这里插入图片描述

在这里插入图片描述


(2) setup_hsmmc_cfg_gpio,在 uboot/cpu/s5pc11x/setup_hsmmc.c 中。看名字,函数是用来配置 SoC 中 MMC 控制器相关的 GPIO 的。

在这里插入图片描述


三、iNand/SD 驱动解析2

1、smdk_s3c_hsmmc_init

(1) 函数位于:uboot/drivers/mmc/s3c_hsmmc.c 中。

在这里插入图片描述


(2) 函数内部通过宏定义 USE_MMCx, 来决定是否调用 s3c_hsmmc_initialize 来进行具体的初始化操作。

在这里插入图片描述


2、s3c_hsmmc_initialize

(1) 函数位于:uboot/drivers/mmc/s3c_hsmmc.c中。

在这里插入图片描述


(2) 定义并且实例化一个 struct mmc 类型的对象(定义了一个指针,并且给指针指向有意义的内存,或者说给指针分配内存),然后填充它的各种成员,最后调用mmc_register 函数,来向驱动框架注册这个 mmc 设备驱动。

在这里插入图片描述


(3) mmc_register 功能是进行 mmc 设备的注册,注册方法其实就是,将当前这个 struct mmc 使用链表连接到 mmc_devices 这个全局变量中去。

在这里插入图片描述


(4) 我们在 X210 中定义了 USE_MMC0USE_MMC2,因此在我们的 uboot 初始化时,会调用2次 s3c_hsmmc_initialize 函数,传递参数分别是 0 和 2,因此完成之后,系统中会注册上 2 个 mmc 设备,表示当前系统中有 2 个 mmc 通道在工作。

在这里插入图片描述

(5) 至此 cpu_mmc_init 函数分析完成。


3、find_mmc_device

在这里插入图片描述

(1) 这个函数位于:uboot/drivers/mmc/mmc.c中。
在这里插入图片描述


(2) 这个函数其实就是通过 mmc 设备编号,来在系统中查找对应的 mmc 设备(struct mmc 的对象,根据上面分析,系统中有 2 个,编号分别是 0 和 1)。

在这里插入图片描述


(3) 函数工作原理就是,通过遍历 mmc_devices 链表,去依次寻找系统中注册的 mmc 设备,然后对比其设备编号和我们当前要查找的设备编号,如果相同,就找到了要找的设备。找到了后调用 mmc_init 函数来初始化它。


4、mmc_init

(1) 函数位于:drivers/mmc/mmc.c 中。

在这里插入图片描述


(2) 分析猜测,这个函数应该要进行 mmc 卡的初始化了(前面已经进行了 SoC 端控制器的初始化)。

(3) 函数的调用关系为:

mmc_init
	mmc_go_idle
		mmc_send_cmd
	mmc_send_if_cond
		mmc_send_cmd
	······

在这里插入图片描述

具体分析可以看出,mmc_init 函数内部就是,依次通过向 mmc 卡发送命令码(CMD0、CMD2 那些)来初始化 SD卡/iNand 内部的控制器,以达到初始化 SD 卡的目的。


3、总结

(1) 至此整个 MMC 系统初始化结束。

(2) 整个 MMC 系统初始化分为 2 大部分:SoC 这一端的 MMC 控制器的初始化,SD 卡的卡本身的初始化。前一步主要是在 cpu_mmc_init 函数中完成,后一部分主要是在mmc_init 函数中完成。

(3) 整个初始化完成后,去使用 SD卡/iNand 时,操作方法和 mmc_init 函数中初始化 SD卡的操作一样的方式。读写 SD 卡时,也是通过总线向 SD 卡发送命令、读取/写入数据来完成的。

(4) 顺着操作追下去,到了 mmc_send_cmd 函数处就断了,真正的向 SD 卡发送命令的硬件操作的函数找不到。这就是学习驱动的麻烦之处。

在这里插入图片描述


(5) struct mmc 结构体是关键。两部分初始化之间用 mmc 结构体来链接的,初始化完了后,对 mmc 卡的常规读写操作也是通过 mmc 结构体来链接的。


四、iNand/SD 驱动解析3

1、struct mmc

(1) **驱动的设计中有一个关键数据结构。**譬如 MMC 驱动的结构体就是 struct mmc。这些结构体中,包含一些变量和一些函数指针,变量用来记录驱动相关的一些属性,函数指针用来记录驱动相关的操作方法。这些变量和函数指针加起来就构成了驱动。驱动就被抽象为这个结构体。

(2) 一个驱动工作时,主要就分几部分:驱动构建(构建一个 struct mmc 然后填充它)、驱动运行时(调用这些函数指针指向的函数和变量)。


2、分离思想

(1) 分离思想就是说,在驱动中将操作方法和数据分开。

(2) 操作方法就是函数,数据就是变量。 所谓操作方法和数据分离的意思就是:在不同的地方来存储和管理驱动的操作方法和变量,这样的优势就是驱动便于移植。


3、分层思想

(1) 分层思想是指,一个整个的驱动分为好多个层次。简单理解就是,驱动分为很多个源文件,放在很多个文件夹中。譬如这里讲的 mmc 的驱动涉及到 drivers/mmc 下面的 2 个文件和 cpu/s5pc11x 下的好几个文件。

(2) 以 mmc 驱动为例,来分析各个文件的作用:
uboot/drivers/mmc/mmc.c:本文件的主要内容是和 MMC 卡操作有关的方法,譬如 MMC 卡设置空闲状态的、卡读写数据等。但是本文件中并没有具体的硬件操作函数,操作最终指向的是 struct mmc 结构体中的函数指针,这些函数指针是在驱动构建的时候,和真正硬件操作的函数挂接的(真正的硬件操作的函数在别的文件中)。

在这里插入图片描述


uboot/drivers/mmc/s3c_hsmmc.c: 本文件中是 SoC 内部 MMC 控制器的硬件操作的方法,譬如向 SD 卡发送命令的函数(s3c_hsmmc_send_command),譬如和 SD 卡读写数据的函数( s3c_hsmmc_set_ios ),这些函数就是具体操作硬件的函数,也就是 mmc.c 中需要的那些硬件操作函数。 这些函数在 mmc 驱动初始化构建时(s3c_hsmmc_initialize 函数中)和 struct mmc 挂接起来备用。

在这里插入图片描述


分析:mmc.c 和 s3c_hsmmc.c 构成了一个分层,mmc.c 中调用了 s3c_hsmmc.c 中的函数,所以 mmc.c 在上层,s3c_hsmmc.c 在下层。这两个分层后我们发现,mmc.c 中不涉及具体硬件的操作,s3c_hsmmc.c 中不涉及驱动工作时的时序操作。因此移植的时候就有好处:譬如我们要把这一套 mmc 驱动移植到别的 SoC 上, mmc.c 就不用动, s3c_hsmmc.c 动就可以了;譬如 SoC 没变,但是 SD 卡升级了,这时候只需要更换 mmc.c ,不需要更换 s3c_hsmmc.c 即可。


(3) cpu/s5pc11x/ 下面还有一个 setup_hsmmc.c,也和 MMC 驱动有关。但是这些代码为什么不能放到 drivers 目录下去,而要放到 cpu 目录下去?因为这里面的 2 个函数(setup_hsmmc_clock 和 setup_hsmmc_cfg_gpio)都是和 SoC 有关的初始化函数,这两个函数不能放到 drivers 目录下去。

实际上,如果非把这两个函数放在 uboot/drivers/mmc/s3c_hsmmc.c 文件中也凑活能说过去。


源自朱有鹏老师.

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

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

相关文章

Java 8 新特性之Stream流(二)关键

继续探索流API的高级功能之前,我们先从接口级别全面了解一下流API,这个对于我们来说是至关重要的。下面是一张流API关键知识点的UML图。 流API UML 流API定义的几个接口,都是在java.util.stream包中的.其中上图中的BaseStream接口是最基础的…

每日记录自己的Android项目(二)—Viewbinding,WebView,Navigation

今日想法今天是想把做一个跳转页面的时候调到H5页面去,但是这个页面我用app来承载,不要调到浏览器去。所以用到了下方三个东西。Viewbindingbuild.gradle配置首先在app模块的build.gradle里添加一下代码默认情况下,每一个布局xml文件都会生成…

【Linux学习】基础IO——理解缓冲区 | 理解文件系统

🐱作者:一只大喵咪1201 🐱专栏:《Linux学习》 🔥格言:你只管努力,剩下的交给时间! 基础IO☕理解缓冲区🧃缓冲区的共识🧃缓冲区的位置🧃缓冲区的刷…

Spring Boot+Vue前后端分离项目练习03之网盘项目文件夹创建及文件查询接口开发

1.集成Swagger 3接口文档 在前后端分离的项目中,接口文档的存在十分重要。swagger 是一个自动生成接口文档的工具,在需求变更十分频繁的情况下,手写接口文档是效率十分低下,这时swagger自动生生文档的的作用就体现出来了&#xf…

【uni-app教程】UniAPP 常用组件和 常用 API 简介# 知心姐姐聊天案例

五、UniAPP 常用组件简介 uni-app 为开发者提供了一系列基础组件,类似 HTML 里的基础标签元素,但 uni-app 的组件与 HTML 不同,而是与小程序相同,更适合手机端使用。 虽然不推荐使用 HTML 标签,但实际上如果开发者写了…

华为机试题:HJ105 记负均正II(python)

文章目录(1)题目描述(2)Python3实现(3)知识点详解1、input():获取控制台(任意形式)的输入。输出均为字符串类型。1.1、input() 与 list(input()) 的区别、及其相互转换方…

【Kubernetes】第十七篇 - ECS 服务停机和环境修复

一,前言 上一篇,介绍了 Secret 镜像的使用; 三台服务每天大概 15 块钱的支出,用一个月也是不少钱; 闲时可以停掉,这样每天只有 4 块钱支出,剩下一大笔; ECS 服务停机后公网 IP 会…

移除元素(每日一题)

目录 一、题目描述 二、题目分析 2.1 方法一 2.1.1 思路 2.1.2 代码 2.2 方法二 2.2.1 思路 2.2.2 代码 一、题目描述 题目链接:27. 移除元素 - 力扣(LeetCode) 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数…

【Maven】P1 Maven 基础知识

Maven 基础知识Maven基础仓库坐标快速坐标生成网站国内镜像仓库前言 本节:Maven第一节内容,记录maven是什么,解决了什么问题,进而推出他的作用;然后介绍maven中两个重要概念,仓库与坐标。 下一节&#xff1…

TIA博途中使用SCL语言实现选择排序算法并封装成FC全局库

TIA博途中使用SCL语言实现选择排序算法并封装成FC全局库 选择排序算法包括升序和降序2种: 升序排列: 第一轮从数据源中找到最小值排在第一位,第二轮从剩下的数据中寻找最小值排在第二位,依次类推,直到所有数据完成遍历;降序排列: 第一轮从数据源中找到最大值排在第一位,…

centOS 编译strongswan

安装编译环境 yum groupinstall "Development Tools" 编译strongswan Download strongSwan: wget https://download.strongswan.org/strongswan-x.x.x.tar.bz2 Unpack the tarball and navigate into the directory: tar xjf strongswan-x.x.x.tar.bz2; cd strong…

Editor.md 的使用方法及图片处理

目录1. 资源下载2. 生成页面2.1 编辑和预览页面2.2 文本渲染页面3. 图片上传3.1 前端配置3.2 后端接口4. 图片粘贴1. 资源下载 官网下载 gitee 下载 2. 生成页面 2.1 编辑和预览页面 将资源(精简后 Editor.md 资源1)导入项目: 按照官方教…

nvidia Jetson nano Linux内核编译

今天编译了nvidia 的jetson nano的内核。在网上找到的资料都比较老了。现在官网的最新版本是35.1.结合之前看到的博客的内容。关键是内核源码和交叉编译器的下载。找到官方文档后,编译成功!并且官方的文档是有一个编译脚本的。看之前的资料都是给出的命令,不知道这个nvbuild…

库函数qsort的使用以及模拟实现

首先&#xff0c;qsort函数是个库函数 那么就有头文件 #include<stdlib.h>这个函数的实现是利用快速排序的方法实现的 下面是该函数的参数//void qsort(void* base, //指向了待排序数组的第一个元素 // size_t num, //待排序的元素个数 // size_t …

FLoyd算法的入门与应用

目录 一、前言 二、FLoyd算法 1、最短路问题 2、Floyd算法 3、Floyd的特点 4、Floyd算法思想&#xff1a;动态规划 三、例题 1、蓝桥公园&#xff08;lanqiaoOJ题号1121&#xff09; 2、路径&#xff08;2021年初赛 lanqiaoOJ题号1460&#xff09; 一、前言 本文主要…

Cannot start compiler The output path is not specified for module mystatic(已解决)

1.背景&#xff1a;今天在idea上写了一些代码&#xff0c;右键run竟然跑不起来了&#xff0c;而且右下角的Event Log还报错。报错内容如下图&#xff1a;2.报错原因&#xff1a;项目代码和编译器的输出路径不在一块&#xff0c;导致idea无法找到模块的output path&#xff08;输…

Docker--(六)--Docker资源限制

前言系统压力测试Cpu资源限制Mem资源限制IO 资源限制【扩展】 1.前言 在使用 Docker 运行容器时&#xff0c;一台主机上可能会运行几百个容器&#xff0c;这些容器虽然互相隔离&#xff0c;但是底层却使用着相同的 CPU、内存和磁盘资源。如果不对容器使用的资源进行限制&#x…

VUE中给对象添加新属性时,界面不刷新怎么办

一、直接添加属性的问题 举例&#xff1a; 定义一个p标签&#xff0c;通过v-for指令进行遍历 然后给botton标签绑定点击事件&#xff0c;我们预期点击按钮时&#xff0c;数据新增一个属性&#xff0c;界面也 新增一行。 <p v-for"(value,key) in item" :key&qu…

18.用于大型程序的工具

文章目录用于大型程序的工具18.1异常处理18.1.1抛出异常栈展开栈展开过程中对象被自动销毁析构函数与异常异常对象18.1.2捕获异常查找匹配的处理代码重新抛出捕获所有异常的处理代码18.1.3函数try语句块与构造函数18.1.4noexcept异常说明违反异常说明异常说明的实参noexcept运算…

Potions (Hard Version) and (Easy Version)(背包DP + 反悔贪心)

[TOC](Potions (Hard Version) and (Easy Version)) 一、Potions(Easy Version) 1、问题 2、分析&#xff08;背包DP 贪心&#xff09; 简而言之就是我们需要从左到右开始选数字&#xff0c;选的过程中我们需要保证我们选的数字的和始终是大于等于0的&#xff0c;在满足这个…