[uboot] uboot流程系列:
[project X] tiny210(s5pv210)上电启动流程(BL0-BL2)
[project X] tiny210(s5pv210)从存储设备加载代码到DDR
[uboot] (第一章)uboot流程——概述
[uboot] (第二章)uboot流程——uboot-spl编译流程
[uboot] (第三章)uboot流程——uboot-spl代码流程
[uboot] (第四章)uboot流程——uboot编译流程
[uboot] (第五章)uboot流程——uboot启动流程
[uboot] (番外篇)global_data介绍
[uboot] (番外篇)uboot relocation介绍
[uboot] (番外篇)uboot 驱动模型
建议先看《[uboot] (番外篇)uboot 驱动模型》
=============================================================================================================
dm-gpio
一、dm-gpio架构
建议先参考《[uboot] (番外篇)uboot 驱动模型》搞懂uboot下的驱动模型。
1、dm-gpio架构图
如下:
2、说明
- gpio core
也在gpio uclass中实现,
- 主要是为上层提供接口
- 从dts中获取GPIO属性
- 从gpio uclass的设备链表中获取到相应的udevice设备,并使用其操作集
gpio uclass
- 链接属于该uclass的所有gpio udevice设备
- 为gpio udevice的driver提供统一的操作集接口
bank和gpio
- 有些平台上,将某些使用同一组寄存器的gpio构成一个bank,例如三星的s5pv210
- 当然,并不是所有平台都有bank的概念,例如高通,高通的GPIO都有自己独立的寄存器,因此,可以将高通当成只有一个bank
gpio udevice
- 一个bank对应一个gpio udevice,用bank中的偏移来表示具体的GPIO号
- gpio udevice的driver就会根据bank以及offset对相应的寄存器上的相应的bit进行操作。
3、原理介绍
这里先简单介绍一下dm下gpio的工作原理
- 一个bank对应一个udevice,udevice中私有数据中存放着该bank的信息,比如相应寄存器地址等等
- 上层用gpio_desc描述符来描述一个GPIO,其中包括该GPIO所属的udevice、在bank内的偏移、以及标志位。
- 上层通过调用gpio core的接口从dtsi获取到GPIO属性对应的gpio_desc描述符
- 上层使用gpio_desc描述符来作为调用gpio core的操作接口的参数
- gpio core从gpio_desc描述符提取udevice,并调用其driver中对应的操作集,以bank内的偏移作为其参数(这样driver就能判断出是哪个GPIO了)
- driver中提取udevice的私有数据中的bank信息,并进行相应的操作
二、dm-gpio的使用示例
这里简单的以tiny210的led_1的闪烁为例子来介绍一下GPIO的使用。
虽然uboot中已经实现了led的uclass,但是我们这里先不使用这个uclass,只是简单的实现通过dm-gpio来控制一个led。
0、硬件简单说明(具体去参考原理图吧)
s5pv210的GPIO的地址空间
参考《S5PV210_UM_REV1.1》2.1.2 SPECIAL FUNCTION REGISTER MAP,
s5pv210的GPIO的地址空间为0xE020_0000开始的1000B的区域在tiny210上,有四个led,低电平为亮,高电平为灭
- GPJ2_0 -> led_1
- GPJ2_1 -> led_2
- GPJ2_2 -> led_3
- GPJ2_3 -> led_4
GPJ2这个bank的寄存器
对应控制寄存器 0xE020_0280
对应数据寄存器 0xE020_0284
1、dtsi中的定义
这里只说明GPIO引用的节点,不说明gpio控制器的节点,gpio控制器的节点在后面driver中进行说明
arch/arm/dts/s5pv210-tiny210.dts
led_test {
compatible = "dm-gpio,test";
led1-gpio = <&gpj2 0 0>; // 属性"led1-gpio",表示gpj2 bank的第0个gpio,0是值标志
led2-gpio = <&gpj2 1 0>; // gpj2 bank的第1个gpio,0是值标志
led3-gpio = <&gpj2 2 0>; // gpj2 bank的第2个gpio,0是值标志
led4-gpio = <&gpj2 3 0>; // gpj2 bank的第3个gpio,0是值标志
};
注意,这里<&gpj2 0 0>取决于driver是如何对这个属性进行转化的。并不是所有平台都是一样的。
2、驱动中从节点中获取一个GPIO
我们在board_late_init中来实现GPIO闪烁的功能
board/samsung/tiny210/board.c
int board_late_init(void)
{
struct gpio_desc led1_gpio;
int node;
node = fdt_node_offset_by_compatible(gd->fdt_blob, 0, "dm-gpio,test");
// 注意,我们并没有使用dm模型的driver来匹配compatible = "dm-gpio,test"的节点,所