uboot与linux驱动

1.uboot本身是裸机程序

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

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

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

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

(2)uboot早期也是工作在纯物理地址下,但是现在的uboot开启了MMU,做了虚拟地址映射,因此做驱动时必须考虑到这一点。

通过查看uboot中的虚拟地址映射表,发现除了0x30000000~0x3FFFFFFF映射到0xC0000000~0xCFFFFFFF之外,其余的地址空间全部是原样映射,而在驱动中主要是操控硬件寄存器,而s5pv210的SFR都在0xEXXXXXXX地址空间,因此在驱动不需要考虑虚拟地址。

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.从start_armboot开始

(1)驱动整体比较庞大,涉及很多文件夹下的很多文件,函数很多,贸然插入根本不知道看哪里,学习时必须有时序。因此这里的iNand/SD卡驱动从start_armboot开始。

(2)在start_armboot函数调用mmc_initialize函数实现mmc的初始化,该函数在lib_arm/board.c的603行被调用。

2.mmc_initialize

代码:1177 ~ 1208行(drivers/mmc/mmc.c)

int mmc_initialize(bd_t *bis)
{struct mmc *mmc;int err;INIT_LIST_HEAD(&mmc_devices);cur_dev_num = 0;if (board_mmc_init(bis) < 0)cpu_mmc_init(bis);#if defined(DEBUG_S3C_HSMMC)print_mmc_devices(',');
#endif#ifdef CONFIG_CHECK_X210CV3mmc = find_mmc_device(1);//lqm
#elsemmc = find_mmc_device(0);
#endifif (mmc) {err = mmc_init(mmc);if (err)err = mmc_init(mmc);if (err) {printf("Card init fail!\n");return err;}}printf("%ldMB\n", (mmc->capacity/(1024*1024/(1<<9))));return 0;
}

(1)从名字可以看出,这个函数的作用就是初始化开发板上的MMC系统。MMC系统的初始化应该包含这几部分:SoC中的MMC控制器初始化(MMC系统时钟的初始化、SFR初始化)、SoC中的MMC相关的GPIO的初始化、iNand/SD卡芯片的初始化。

3.mmc_devices

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

4.cpu_mmc_init

代码:232 ~ 241行(cpu/s5pc11x/cpu.c)

/** Initializes on-chip MMC controllers.* to override, implement board_mmc_init()*/
int cpu_mmc_init(bd_t *bis)
{
#ifdef CONFIG_S3C_HSMMCsetup_hsmmc_clock();setup_hsmmc_cfg_gpio();return smdk_s3c_hsmmc_init();
#elsereturn 0;
#endif
}

(1)该函数调用了3个函数:setup_hsmmc_clock、setup_hsmmc_cfg_gpio、smdk_s3c_hsmmc_init。

(2)setup_hsmmc_clock函数:位于cpu/s5pc11x/setup_hsmmc.c中,从名字上可以看出该函数是用来初始化SoC中MMC控制器的时钟部分的。

(3)setup_hsmmc_cfg_gpio函数:位于cpu/s5pc11x/setup_hsmmc.c中,从名字上可以该函数是用来配置SoC中MMC相关的GPIO的。

(4)smdk_s3c_hsmmc_init函数:位于drivers/mmc/s3c_hsmmc.c中,在它的内部通过宏定义USE_MMCx来决定是否调用s3c_hsmmc_initialize函数来进行具体的初始化操作。

(5)s3c_hsmmc_initialize函数:位于drivers/mmc/s3c_hsmmc.c中,代码如下所示:

static int s3c_hsmmc_initialize(int channel)
{struct mmc *mmc;mmc = &mmc_channel[channel];sprintf(mmc->name, "S3C_HSMMC%d", channel);mmc->priv = &mmc_host[channel];mmc->send_cmd = s3c_hsmmc_send_command;mmc->set_ios = s3c_hsmmc_set_ios;mmc->init = s3c_hsmmc_init;mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;mmc->host_caps = MMC_MODE_4BIT | MMC_MODE_HS_52MHz | MMC_MODE_HS;
#if defined(USE_MMC0_8BIT) || defined(USE_MMC2_8BIT)mmc->host_caps |= MMC_MODE_8BIT;
#endifmmc->f_min = 400000;mmc->f_max = 52000000;mmc_host[channel].clock = 0;switch(channel) {case 0:mmc_host[channel].ioaddr = (void *)ELFIN_HSMMC_0_BASE;break;case 1:mmc_host[channel].ioaddr = (void *)ELFIN_HSMMC_1_BASE;break;case 2:mmc_host[channel].ioaddr = (void *)ELFIN_HSMMC_2_BASE;break;
#ifdef USE_MMC3case 3:mmc_host[channel].ioaddr = (void *)ELFIN_HSMMC_3_BASE;break;
#endifdefault:printk("mmc err: not supported channel %d\n", channel);}return mmc_register(mmc);
}

函数解析:

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

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

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

5.find_mmc_device

代码:63 ~ 78行(drivers/mmc/mmc.c)

struct mmc *find_mmc_device(int dev_num)
{struct mmc *m;struct list_head *entry;list_for_each(entry, &mmc_devices) {m = list_entry(entry, struct mmc, link);if (m->block_dev.dev == dev_num)return m;}printf("MMC Device %d not found\n", dev_num);return NULL;
}

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

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

6.mmc_init

代码:1112 ~ 1144行(drivers/mmc/mmc.c)

int mmc_init(struct mmc *host)
{int err;err = host->init(host);if (err)return err;/* Reset the Card */err = mmc_go_idle(host);if (err)return err;/* Test for SD version 2 */err = mmc_send_if_cond(host);/* Now try to get the SD card's operating condition */err = mmc_send_app_op_cond(host);/* If the command timed out, we check for an MMC card */if (err == TIMEOUT) {err = mmc_send_op_cond(host);if (err)return UNUSABLE_ERR;} elseif (err)return UNUSABLE_ERR;return mmc_startup(host);
}

(1)该函数的功能是初始化mmc卡。

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

mmc_init
        mmc_go_idle
                mmc_send_cmd
        mmc_send_if_cond
                mmc_send_cmd
······

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

总结

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

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

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

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

驱动结构体分析

1.数据结构

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

(2)驱动工作的时候主要分为两部分:驱动构建(构建一个struct mmc,然后填充它)、驱动运行(调用结构体中变量和函数指针)

2.分离思想

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

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

3.分层思想

(1)分层思想是指一个整体的驱动分为好多个层次,简单理解就是驱动分为很多个源文件,放在很多个文件夹中。例如本课程讲的mmc的驱动设计到drivers/mmc下面的2个文件和cpu/s5pc11x下面的几个文件。

(2)以mmc驱动为例来分析各个文件的作用:

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

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目录下?因为这里面的两个函数(setup_hsmmc_clock和setup_hsmmc_cfg_gpio)都是和SoC有关的初始化函数,这两个函数不能放到drivers目录下,实际上如果非把这两个函数放在drivers/mmc/s3c_hsmmc.c中也能凑合说得过去。

uboot的硬件驱动相关推荐

  1. Linux下的硬件驱动——USB设备配置以及开发

    Linux下的硬件驱动--USB设备(上)(驱动配置部分) USB设备越来越多,而Linux在硬件配置上仍然没有做到完全即插即用,对于Linux怎样配置和使用他们,也越来越成为困扰我们的一大问题.本文 ...

  2. mtd驱动分析-硬件驱动层

    http://blog.chinaunix.net/uid-28236237-id-3989135.html 分析uboot中的nand flash.查找了一些资料,看了韦东山移植.也不是很懂,nan ...

  3. uboot移植Linux-SD驱动代码解析

    一.uboot与linux驱动 1.1.uboot本身是裸机程序 (1)狭义的驱动概念是指:操作系统中用来具体操控硬件的代码叫驱动 广义的驱动概念是指:凡是操控硬件的代码都叫驱动 (2)裸机程序中是直 ...

  4. 单片机at指令解析 开源_分享Github上几个开源单片机硬件驱动库

    Github上的项目基本上以软件为主,硬件的很少,优秀的硬件开源项目更少.单片机的开发中驱动模块化带来的好处是移植方便,不依赖于硬件,但是与裸机开发相比代码复杂不易理解.所以驱动.组件等封装的功能完善 ...

  5. 在ThinkPad W500 A98上升级Windows 7以及安装硬件驱动和相关程序(2/2)

    在ThinkPad W500 A98上升级Windows 7以及安装硬件驱动和相关程序(2/2) 升级硬件固件 在安装了升级硬件固件所必要的驱动程序后,就可以升级硬件固件了,在下载的硬件驱动和相关程序 ...

  6. [转贴]制作windows 2003自动安装盘-集成补丁/Raid及硬件驱动

    从事网游行业的工作人员,如果一款游戏上线,必须上大量服务器.用品牌机引导盘装系统,再打个补丁,速度真让人不敢恭维.为了提高效率,就尝试制作一张集成系统补丁/RAID及硬件驱动自动安windows 20 ...

  7. Linux下的硬件驱动——USB设备(下)

    Linux下的硬件驱动--USB设备(下)(驱动开发部分) 文档选项 打印本页 将此页作为电子邮件发送 未显示需要 JavaScript 的文档选项 级别: 初级 赵明, 联想软件设计中心嵌入式研发处 ...

  8. intel x520网卡驱动_手工编译linux桌面内核(二)——硬件驱动的配置 下篇

    前言: 前面的方法讲完了,接下来我们来看看实例(我自己电脑的配置). 这里我只打算列出几项重要的驱动配置来,其它的请自行查阅gentoo wiki! 再次强调,这是我自己电脑的硬件驱动配置,不可能完全 ...

  9. 3D打印机硬件驱动-马林固件最新版本2.0.X中文注释(1)marlin 2.0.9.2 截至发稿时间2021年12月16日

    马林固件最新版本翻译注释 /*============================================================================== Marlin ...

最新文章

  1. 安装yarn 心得分享
  2. 微软职位内部推荐-Senior Software Engineer
  3. 《大话存储》读书笔记一
  4. cmd中添加中文字体
  5. 突然感到很无聊当没有看书时
  6. win10无法检测java_Javac 在windows10系统不识别
  7. 马约拉纳费米子:推动量子计算的“天使粒子”
  8. Emmet:HTML/CSS代码快速编写器
  9. JavaScript==比较的规则
  10. SpringMVC的返回值和参数类型
  11. GNN上用到的Tasks,Dataset and Benchmark
  12. python scrapy框架详解_Python爬虫知识点四--scrapy框架
  13. Using Custom Assemblies with Reports
  14. bzoj 1654: [Usaco2006 Jan]The Cow Prom 奶牛舞会(Trajan)
  15. Xcode不出错误提示,Indexing | Processing files
  16. 直播视频卡顿延迟时如何优化
  17. Primeng PrimeFlex 的使用总结 (Angular 10)
  18. 最新Mac Pro详解
  19. Unity5.0 天空盒(CubeMap)
  20. 企业微信来了,尽管“定位打卡”功能愁死个人,但它有可能逼死一个产业

热门文章

  1. Java 调用构造器一定产生新对象吗
  2. linux启动注册内存失财,Linux创建者开喷英特尔:扼杀ECC内存市场
  3. 什么样的公司可以申请高新技术企业?
  4. python xlsxwriter不覆盖写入_python 2.7 使用xlsxwriter模块写入excel文件数据时,左上角出现绿色的小三角符号,无法生成表格怎么办?...
  5. 将数字格式设置为文本格式,并使其出现左上角绿色小三角
  6. 暑期Python编程打卡训练营计划!
  7. 物联网设备数据是如何流转的:基于EMQX与TDengine的前后端分离项目实践
  8. 一位逝去的华为青年胡新宇:天堂里不再有加班
  9. win7腾讯会议点开没反应/打不开(有进程无窗口)的解决方法
  10. Cadence Allegro 导出SMT钢网坐标BOM焊接文件图文教程及视频演示