ARM uboot 源码分析9 - uboot的硬件驱动部分
一、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_MMC0 和 USE_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_initmmc_go_idlemmc_send_cmdmmc_send_if_condmmc_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 文件中也凑活能说过去。
源自朱有鹏老师.
相关文章:

ARM uboot 源码分析9 - uboot的硬件驱动部分
一、uboot 与 linux 驱动 1、uboot 本身是裸机程序 (1) 裸机本来是没有驱动的概念的(狭义的驱动的概念就是,操作系统中用来具体操控硬件的那部分代码叫驱动) (2) 裸机程序中是直接操控硬件的,操作系统中必须通过驱动来操控硬件…...

Mybatis动态sql语句foreach中拼接正则表达式字符串注意事项
今天要说到的查询情况,平时项目里边其实用到的并不是很多,使用正则表达式无非是为了匹配结果比较灵活,最常见的,我们的查询条件一般一个参数仅仅只是一种情况的筛选,对于如何选择查询方式,主要还是要看前端…...

JVM内置锁synchronized关键字详解
目录 JVM内置锁synchronized关键字详解 设计同步器的意义 如何解决线程并发安全问题? synchronized原理详解 synchronized底层原理 synchronized在jdk1.6前后的变化【重点】 jdk小于1.6时 jdk>1.6时 轻量级锁何时升级为重量级锁??…...

【2021.12.25】xv6系统入门学习
【2021.12.28】为xv6系统添加一个开机密码 文章目录【2021.12.28】为xv6系统添加一个开机密码0、说明1、Ubuntu20上安装xv62、测试指令3、修改系统代码4、添加自己的程序命令0、说明 xv6 是 MIT 设计的一个教学型操纵系统。 记录Ubuntu上安装x86版本的xv6系统,为其…...

Linux内核4.14版本——drm框架分析(4)——crtc分析
目录 1. struct drm_crtc结构体 2. crtc相关的API 2.1 drm_crtc_init_with_planes 2.5 drm_mode_setcrtc 3. func的一些介绍 3.1 struct drm_crtc_helper_funcs 3.2 struct drm_crtc_funcs 4. 应用层的调用 4.1 drmModeSetCrtc (drmlib库里)---…...

用原生js手写分页功能
分页功能如下: 数据分页显示,每页显示若干条数据,默认当前页码为第一页。例如:每页5条数据,则第一页显示 1-5 条,第二页显示 6-10 条,依此类推。当页码为第一页时,上一页为禁用状态…...

CornerNet介绍
CornerNet: Detecting Objects as Paired Keypoints ECCV 2018 Paper:https://arxiv.org/pdf/1808.01244v2.pdf Code:GitHub - princeton-vl/CornerNet 摘要: 提出了一种single-stage的目标检测算法CornerNet,它把每个目标检…...

【SpringBoot】日志使用
默认配置 Spring Boot默认帮我们配置好了日志 //记录器Logger logger LoggerFactory.getLogger(getClass());Testpublic void contextLoads() {//System.out.println();//日志的级别;//由低到高 trace<debug<info<warn<error//可以调整输出的日志级…...

关于slice扩容性能损耗的探究
背景 如果让我评选最伟大的数据结构,在我心中答案只有两个,数组和哈希表,这两个是我的程序的重要组成部分,同时也是我饭碗的重要组成部分。slice和map简洁明了的API很容易让我们有一种他们提供了无限大的空间,可以…...

Java实现单向链表
✅作者简介:热爱Java后端开发的一名学习者,大家可以跟我一起讨论各种问题喔。 🍎个人主页:Hhzzy99 🍊个人信条:坚持就是胜利! 💞当前专栏:Java数据结构与算法 ǹ…...

3月4日,30秒知全网,精选7个热点
///印度最大供电商罕见于现货市场购煤,能源供应短缺成忧 据知情人士透露,这家印度国有发电公司计划在下周左右发布300万吨的招标 ///QQ音乐推出AIGC黑胶播放器 这是国内音乐行业首个运用AI技术,通过文字、图片指令快速生成不同风格的播放器…...

EXCEL-职业版本(2)
Excel-职业版本(2) 定位 1.如何快速定位到不连续的空值,填充为0 1.在任意空单元格里复制0 2.选中数据区域CtrlA 3.CtrlG 4.选择【定位条件】 5.选择【空值】 6.ctrlV 粘贴 即可 2.怎么一次性计算每个小组的数量 单价和金额的和? 1.选中…...

java中延时队列的实现
大家好,我是一名CRUD工程师,最近我朋友突然来问我如何实现延时队列,我脱口而出就是MQ。不过突然想到公司的项目好像用的是java的一个原生类。于是我就想着趁周末的时间好好的去探究一下各方法实现延时队列的优缺点。 延迟消息 延迟消息就是字…...

基于java的circle buffer的实现
总目录链接==>> AutoSAR入门和实战系列总目录 文章目录 缓冲区示例什么是循环缓冲区?方法 1:使用数组插入元素删除元素方法 2:使用链表插入元素:删除元素:当数据经常从一个地方移动到另一个地方或从一个进程移动到另一个进程或被频繁访问时,它不能存储在永久性内存…...

通用方法——为什么重写equals还要重写hashcode
本文介绍java.lang.Object类中的两个方法:equals和hashCode。这两个方法大家应该都知道,但是这两个方法的作用是什么、为什么重写equals还要重写hashCode、它们之间有什么关系和约定等,今天就来带大家了解一下。 1、hashCode hashCode即散列…...

JavaSE学习进阶day2_01 包和权限修饰符
第一章 包 1.1 包 包在操作系统中其实就是一个文件夹。包是用来分门别类的管理技术,不同的技术类放在不同的包下,方便管理和维护。 在IDEA项目中,建包的操作如下: 这个咱们在基础班就谈到过。 包名的命名规范: 路径…...

Android性能调优 - 省电优化
省电:通过工具Battery Historian查看到:耗电大头: 屏幕、网络、cpuled/oled屏幕显示:降低亮度,开深色模式;锁屏间隔缩短到 ;亮屏需要一直持有唤醒锁,还有gps定位也需要用到唤醒锁;网络: 常用的网络优化措施…...

ElasticSearch - SpringBoot整合ES之全文搜索匹配查询 match
文章目录1. 数据准备2. match 匹配查询1. 全文检索2. 简化查询DSL语句3. match 匹配查询原理官方文档地址:https://www.elastic.co/guide/en/elasticsearch/reference/index.html权威指南:https://www.elastic.co/guide/cn/elasticsearch/guide/current/…...

句子的改写和扩写
目录 1.句子改写 2.句子扩写 (不低于15个句子算是长句子,不能太多长句子) 1.句子改写 我绝不会嫁给你的。 如果你是世界上最后一个男人,我就去寺庙。 If you married me,I would jump into the well. 如果你嫁给我,我…...

DockerFile创建及案例
DockerFile dockerfile是用来构建docker镜像的文件,命令脚本参数脚本! 构建步骤 编写一个dockerfile文件docker build 构建成为一个对象docker run 运行镜像docker push 发布镜像(DockerHub、阿里云镜像仓库) 去官网Docker-Hub…...

第十四届蓝桥杯三月真题刷题训练——第 1 天
目录 题目1:数列求值 代码: 题目2:质数 代码: 题目3:饮料换购 代码: 题目1:数列求值 题目描述 本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出…...

基于容器云提交spark job任务
容器云提交spark job任务 容器云提交KindJob类型的spark任务,首先需要申请具有Job任务提交权限的rbac,然后编写对应的yaml文件,通过spark内置的spark-submit命令,提交用户程序(jar包)到集群执行。 1、创建任务job提交权限rbac …...

Linux系统调用之目录操作函数
前言 如果,想要深入的学习Linux系统调用中mkdir,rmdir,rename,chdir,getcwd等这些有关于目录操作函数,还是需要去自己阅读Linux系统中的帮助文档。 具体输入命令: man 2 mkdir/rmdir/rename/ch…...

设计模式-策略模式
前言 作为一名合格的前端开发工程师,全面的掌握面向对象的设计思想非常重要,而“设计模式”是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的,代表了面向对象设计思想的最佳实践。正如《HeadFirst设计模式》中说的一句话&…...

面试+算法:罗马数字及Excel列名与数字互相转换
概述 算法是一个程序员的核心竞争力,也是面试最重要的考查环节。 试题 判断一个罗马数字是否有效 罗马数字包含七种字符:I,V,X,L,C,D和M,如下 字符数值I1V5X10L50C100D500M1000…...

Connext DDS路由服务Routing Service(1)
1 简介 RTI路由服务是一种开箱即用的解决方案,允许开发人员快速扩展和集成不同或地理位置分散的实时系统。它跨域、LAN和WAN扩展RTI ConnextDDS应用程序,包括防火墙和NAT穿越。 它还支持DDS到DDS的桥接,允许您对数据进行转换。这允许未修改的DDS应用程序进行通信,即使它们是…...

如何使用SaleSmartly进行Facebook Messenger 营销、销售和支持
如何使用SaleSmartly(ss客服)进行Facebook Messenger 营销、销售和支持上篇文章我们讲了什么是Facebook Messenger CRM以及获得Facebook Messenger CRM的注意事项,现在你有更多时间与客户聊天,让我们看看你如何使用SaleSmartly&am…...

教资教育知识与能力中学教学
目录 3.1 教学概述 3.2 教学过程 3.3 教学原则*【简答/辨析重点】 3.4 教学方法 3.5 教学组织形式 3.6 教学工作基本环节 3.7 教学评价 3.1 教学概述 1、教学的意义【14/18辨析】 教学是传授系统知识、促进学生发展的最有效形式; 教学是学校进行全面发展教…...

IDEA中使用Tomcat的两种方式:集成本地Tomcat使用Tomcat Maven插件
一、前言 在IDEA中创建完一个Maven Web项目,并补齐了目录以后,准备使用Tomcat时,就需要在自己创建的项目中去部署Tomcat,前文已经介绍了如何创建Maven Web,所以这里就不多加赘述,直接讲述部署Tomcat的方法…...

IP 地址的简介
IP 地址 Internet 依靠 TCP/IP 协议,在全球范围内实现不同硬件结构、不同操作系统、不同网络系统的主机之间的互联。在 Internet 上,每一个节点都依靠唯一的 IP 地址相互区分和相互联系,IP 地址用于标识互联网中的每台主机的身份,…...