没志青年
发布于 2025-06-14 / 15 阅读
0

5 Linux 设备树

设备树简介

早期 Linux 内核源码包含大量的与特定硬件平台相关的代码,代码重复度高且杂乱无章,内核维护工作量大。

后来引入设备树,这是一个描述硬件信息的数据结构,将硬件配置从 Linux 内核源码中提取出来,提高了移植性,更方便维护。

小故事:Linux 之父 Linus Torvalds 闲来无事,在翻看 ARM Linux 代码的时候,看到,有一天终于忍不住了。他在2011年3月17日的 ARM Linux 邮件列表中说道:“This whole ARM thing is a f*cking pain in the ass”。这句话迫使 ARM Linux 社区引入了设备树。

1、设备树文件类型:

  • dts 源文件:类似于C语言源文件,是描述硬件信息的asiII文本文件

  • dtsi 头文件:类似于C语言头文件,可被 dts 文件包含用;是设备树源码文件要用到的头文件,类似头文件,描述平台共性

  • dtb 编译文件:将dts文件编译成对应的二进制文件,便于运行时存放在内存加快读取信息的速度;可被 bootloader/kernel 识别并解析(先由 Bootloader 加载后再传递给 Linux 内核,有的 Bootloader 可能自己也需要这个设备树。)。

dtsi 文件跟 dts 文件的语法是完全一样的。dts 中可以包含.h 头文件,也可以包含 dtsi 文件,在.h 头文件中可以定义一些宏。

2、设备树存放在 arch/arm/boot/dts 目录下,想要编译哪些设备树文件就写在 arch/arm/boot/dts/Makefile 文件中:

ifeq ($(CONFIG_OF),y)

dtb-$(CONFIG_SOC_IMX6ULL) += \
	imx6ull-alientek-emmc.dtb

endif

always		:= $(dtb-y)
clean-files	:= *.dtb

原本是有很多厂商的几百个设备树文件,因为用不到都给删掉了,因此需要把那些都删了,否则编译的时候还会编译那些文件,就出错了。

3、编译设备树,在 linux 内核源码目录下 make dtbs -j$(nproc) ,编译后也在 arch/arm/boot/dts 目录下。

只编译一个设备树,使用 scripts/dtc/dtc 工具

编译、反编译的示例命令如下,“-I”指定输入格式,“-O”指定输出格式,“- o”指定输出文件:

// 编译 dts 为 dtb
./scripts/dtc/dtc -I dts -O dtb -o tmp.dtb arch/arm/boot/dts/xxx.dts
// 反编译 dtb 为 dts
./scripts/dtc/dtc -I dtb -O dts -o tmp.dts arch/arm/boot/dts/xxx.dtb

手动编译:

除非你对设备树比较了解,否则不建议手工使用 dtc 工具直接编译。

内核目录下 是设备树的编译工具,直接使用它的话,包 含其他文件时不能使用“#include”,而必须使用“/incldue”。

imx6ull-alientek-emmc.dts 需要的其它文件:

4、查看设备树信息

板子启动成功后,在 /sys/firmware/devicetree 目录下是以目录结构呈现的 dtb 文件, 根节 点对应 base 目录, 每一个节点对应一个目录, 每一个属性对应一个文件。

这些属性的值如果是字符串,可以使用 cat 命令把它打印出来;对于数值, 可以用 hexdump 把它打印出来。

还可以看到 /sys/firmware/fdt 文件,它就是 dtb 格式的设备树文件,可 以把它复制出来放到 ubuntu 上,执行下面的命令反编译出来

(-I dtb:输入格 式是 dtb,-O dts:输出格式是 dts):

cd 板子所用的内核源码目录
./scripts/dtc/dtc -I dtb -O dts /从板子上/复制出来的/fdt -o tmp.dts

设备树结构

  1. dts文件主体内容由多个节点组成

  2. 每个节点可以包含0或多个子节点,形成树状关系

  3. 每个dts文件都有一个根节点,其它节点都是它的子孙

  4. 根节点一般来描述整个开发板硬件平台,其它节点用来表示具体设备、总线的属性信息

  1. 各个节点可以有多个属性,每个属性用key-value键值对来表示

设备树的属性为键值对

  • 文本字符串:使用 "" 表示,例如

    • 字符串列表:使用 , 连接,例如 "", ""

  • 32位无符号整数:使用 <> 表示

  • 二进制数据:使用 [] 表示,

  • 混合表示:使用 , 连接,例如mixed-property = "string", [0x12 0x34 0x56 0x78], <1200>

父节点:

#address-cells:地址使用多少u32表示

#size-cells:长度用几个u32表示

reg:当前设备的地址和大小

range:子地址到父地址的映射

节点追加数据 &

DTS文件布局

/dts-v1/; // 表示版本
[memory reservations] // 格式为: /memreserve/ <address> <length>;
/ {
 [property definitions]
 [child nodes]
};

节点格式:

[label:] node-name[@unit-address] {    
    [properties definitions];    
    [child nodes];
};

标识

是否必选

label

节点别名,为了缩短节点访问路径,后续节点中可以使用 &label 来表示引用指定节点

node-name

节点名

unit-address

设备地址,一般填写该设备寄存器组或内存块的首地址

properties definitions

属性定义

child nodes

子节点

如何修改节点呢?

/dts-v1/;
/ {
uart0: uart@fe001000 {
 compatible="ns16550";
 reg=<0xfe001000 0x100>;
};
};

第一种修改方法:使用label引用节点

&uart0 {
 status = “disabled”;
};

第二种修改方法:使用全路径(不常使用也不推荐)

&{/uart@fe001000} {
 status = “disabled”;
};

属性格式:

属性就是以等号分隔的键值对,name=value

属性有两种格式:

  1. [label:] property-name = value;

  2. [label:] property-name; 没有值

value有四种类型:

  1. arrays of cells 1个或多个32位数据, 64位数据使用2个32位数据表示,以空格分隔,用尖括号<>表示

  2. string 字符串,使用英文双引号""表示

  3. bytestring 1个或多个字节,以空格分隔,用方括号[]表示

  4. 上面三种的任意组合,使用英文,分隔,如nodeName="hello", <0x01 0x02>, [00 00 12 34 56 78]

特殊节点

根节点 /

dts 文件中必须有一个根节点,根节点表示整块开发板的信息

根节点中必须有这些属性:

#address-cells   // 在子节点的reg属性中, 使用多少个u32整数来描述地址(address)
#size-cells      // 在子节点的reg属性中, 使用多少个u32整数来描述大小(size)
compatible       // 定义一系列的字符串, 用来指定内核中哪个machine_desc可以支持本设备,即描述其兼容哪些平台                         
model            // 比如有2款板子配置基本一致, 它们的compatible是一样的,那么就通过model来分辨这2款板子

/cpus

多核CPU支持

/cpus节点下有1个或多个cpu子节点, cpu子节点中用reg属性用来标明自己是哪一个cpu

所以 /cpus 中有以下2个属性:

#address-cells   // 在它的子节点的reg属性中, 使用多少个u32整数来描述地址(address)
#size-cells      // 在它的子节点的reg属性中, 使用多少个u32整数来描述大小(size) 必须设置为0

描述CPU信息的节点,一般不需要我们设置,在 dtsi 文件中都定义好了。SOC厂商做好了初次移植,我们做的是二次移植。

/memory

所有设备树文件的必需节点,它定义了系统物理内存的布局

芯片厂家不可能事先确定你的板子使用多大的内存,所以 memory 节点需要设置

memory {
    reg = <0x80000000 0x20000000>;
};

/chosen

除了在uboot中使用bootargs环境变量向内核传递参数,我们还可以通过设备树文件给内核传入一些启动参数

比如:

chosen {
    bootargs = "noinitrd root=/dev/mtdblock4 rw init=/linuxrc console=ttySAC0,115200";
};

常用属性

#address-cells、#size-cells

  • cell 指一个 32 位的数值,

  • address-cells:address 要用多少个 32 位数来表示

  • size-cells:size 要用多少个 32 位数来表示。

这两个值决定了reg属性中, 该如何描述一段内存的起始地址和大小。

#address-cells = <数字>;

当#address-cells为1时,0x01806000表示32位的数字;为2时,0x01806000表示64位的数字,可见它们的大小不一样,一般这个都是1

当#size-cells为0时,表示不占空间(此时子节点reg = <0>;),为1时0x2000表示32位的数字,为2时0x2000表示64位的数字

注意:若子节点中未定义#address-cells和#size-cells,则会教继承父节点中的该属性。

例如

/ {
    #address-cells = <1>;
    #size-cells = <1>;
    memory {
        reg = <0x80000000 0x20000000>;
    };
};

0x20000000转换为10进制536870912

表示内存地址从0x80000000开始,占用536870912个字节,内存的范围为0x80000000 ~ 0xA0000000。

reg

reg 的本意是 register,用来表示寄存器地址。

但是在设备树里,它可以用来描述一段空间。反正对于 ARM 系统,寄存器和 内存是统一编址的,即访问寄存器时用某块地址,访问内存时用某块地址,在访 问方法上没有区别。

reg 属性的值,是一系列的“address size”,用多少个 32 位的数来表示 address 和 size,由其父节点的#address-cells、#size-cells 决定

reg属性一般用于描述占用的空间,一般都是某个外设的寄存器地址范围信息

reg = <address1 length1 [address2 length2] [address3 length3]>;

soc {
    #address-cells = <1>;
    #size-cells = <1>;
    compatible = "simple-bus";
    interrupt-parent = <&gpc>;
    ranges;
 
    busfreq {
        compatible = "fsl,imx_busfreq";
        ......
    };
 
    gpmi: gpmi-nand@01806000{
        compatible = "fsl,imx6ull-gpmi-nand", "fsl, imx6ul-gpminand";
        #address-cells = <1>;
        #size-cells = <1>;
        reg = <0x01806000 0x2000>, <0x01808000 0x4000>;
        ......
    };
......
};
​

phandle

数字形式的节点标识,在后续节点中属性值性质表示某节点时,可以引用对应节点,相当于节点的ID

如:

pic@10000000 {    
    phandle = <1>;    
    interrupt-controller;
};
​
another-device-node {    
    interrupt-parent = <1>;   // 使用phandle值为1来引用上述节点
};

compatible

驱动和设备(设备节点)的匹配依据,compatible(兼容性)的值可以有不止一个字符串以满足不同的需求,比如:

compatible = "manufacturer,model"
compatible = "samsung,smdk2440", "samsung,mini2440";

"manufacturer,model" 其中 manufacturer 表示厂商,model 一般是模块对应的驱动名字

model

model 属性与 compatible 属性有些类似,但是有差别。

model 用来准确地定义这个硬件是什么。

比如根节点中可以这样写:

{
    compatible = "samsung,smdk2440", "samsung,mini2440";
    model = "jz2440_v3";
};

compatible 属性表示它兼容 “smdk2440” 和 “mini2440” 板子。

model 属性明确表示板子的信号。

name

(过时了,建议不用) 它的值是字符串,用来表示节点的名字。在跟 platform_driver 匹配时,优先级最低。 compatible 属性在匹配过程中,优先级最高。

device_type

(过时了,建议不用) 它的值是字符串,用来表示节点的类型。在跟 platform_driver 匹配时,优先级为中。 compatible 属性在匹配过程中,优先级最高。

status

&uart1 {
    status = "disabled";
};
  • okay:设备可用

  • disabled:设备不可用

  • fail:设备故障不可用

  • fail-sss:设备故障不可用,sss表示错误信息

最常用的就是前两个。

一个设备树文件给一系列的多个产品使用,比如一个基础版产品、一个高级版产品,基础版板子上没有这个设备就设置为 disabled,有这个设备就设置为 okay。

或者开发的时候临时禁用和开启。

与设备树有关的函数

of_gpio_named_count

函数原型:int of_gpio_named_count(struct device_node *np, const char *propname)

功能:用于获取设备树某个属性里面定义了几个 GPIO 信息,要注意的是空的 GPIO 信息也会被统计到

参数:

  • np:设备节点

  • propname:要统计的 GPIO 属性

返回值:

  • 成功:正值,统计到的 GPIO 数量

  • 失败:负值

of_gpio_count

函数原型:int of_gpio_count(struct device_node *np)

功能:和 of_gpio_named_count 函数一样,但是不同的地方在于,此函数统计的是“gpios”这个属性的 GPIO 数量,而 of_gpio_named_count 函数可以统计任意属性的 GPIO 信息

参数:

  • np:设备节点。

返回值:

  • 成功:正值,统计到的 GPIO 数量

  • 失败:负值

of_get_named_gpio

函数原型:int of_get_named_gpio(struct device_node *np, const char *propname, int index)

功能:获取 GPIO 编号,因为 Linux 内核中关于 GPIO 的 API 函数都要使用 GPIO 编号,此函数会将设备树中类似<&gpio5 7 GPIO_ACTIVE_LOW>的属性信息转换为对应的 GPIO 编号

参数:

  • np:设备节点。

  • propname:包含要获取 GPIO 信息的属性名。

  • index:GPIO 索引,因为一个属性里面可能包含多个 GPIO,此参数指定要获取哪个 GPIO的编号,如果只有一个 GPIO 信息的话此参数为 0。

返回值:

  • 成功:正值,获取到的 GPIO 编号

  • 失败:负值

驱动中获取节点信息

设备树相关的函数以 of_ 开头

#include <linux/mod_devicetable.h>

设备节点最好添加到好区分的地方,一级节点是最好的地方。

设备树与驱动的关联在 platform 中。

struct device_node 对应设备树中的一个节点 struct property 对应节点中一个属性

of_find_node_by_path

功能:通过路径查找指定节点

头文件:

函数原型:

struct device_node * of_find_node_by_path(const char *path);

参数:

  • path:带全路径的节点名,也可以是节点的别名

返回值:

  • 成功:得到节点的首地址

  • 失败:NULL

示例:

of_find_property

功能:提取指定属性的值

头文件:include/of.h

函数原型:

struct property *of_find_property(const struct device_node *np, const char *name, int *lenp);

参数:

  • np:设备节点指针

  • name:属性名称

  • lenp:属性值的字节数

返回值:

  • 成功:属性值的首地址

  • 失败:NULL

of_get_named_gpio

功能:

头文件:

函数原型:

从设备树中提取gpio口

参数:

返回值:

  • 成功:

  • 失败:

/**
 * include/of_gpio.h
 * of_get_named_gpio - 
 * @np - 设备节点指针
 * @propname - 属性名
 * @index - gpio口引脚标号 
 * 成功:得到GPIO口编号;失败:负数,绝对值是错误码
 */
int of_get_named_gpio(struct device_node *np, const char *propname, int index);

irq_of_parse_and_map

功能:

头文件:

函数原型:

参数:

返回值:

  • 成功:

  • 失败:

/*
    功能:获得设备树中的中断号并进行映射
    参数:node:设备节点
         index:序号
    返回值:成功:中断号  失败:错误码
*/
unsigned int irq_of_parse_and_map(struct device_node *node, int index);

of_property_read_string

功能:提取字符串(读属性值)

头文件:

函数原型:

int of_property_read_string(struct device_node *np, const char *propname, const char **out_string);

参数:

  • np:设备节点指针

  • propname:属性名称

  • out_string:输出参数,指向字符串(属性值)

返回值:

  • 成功:0

  • 失败:负数,绝对值是错误码

读数值

int of_property_read_u8(const struct device_node *np,const char *propname,u8 *out_value)
​
int of_property_read_u16(const struct device_node *np,const char *propname,u16 *out_value)
​
int of_property_read_u32(const struct device_node *np,const char *propname,u32 *out_value)

功能:

头文件:

函数原型:

参数:

返回值:

  • 成功:

  • 失败:

判断属性是否存在

int of_property_read_bool(const struct device_node *np,const char *propname)

功能:

头文件:

函数原型:

参数:

返回值:

  • 成功:

  • 失败:

读数组

功能:

头文件:

函数原型:

参数:

返回值:

  • 成功:

  • 失败:

int of_property_read_u32_array(const struct device_node *np,const char *propname,u32 *out_value,size_t sz)

根据原理图写设备树

每个芯片都有对应的官方参考开发板,厂商给这个开发板适配了设备树,所以拿设备树过来修改就行了来匹配自己的开发板,就是设备树模板 imx6ull.dtsi。

注意不要修改这个文件,这个文件是很多设备树文件通用的,。

我怎么知道设备树要写哪些属性?这些字段从哪来的?:

  • 查看 Linux 内核的 binding 文档 /Documentation/devicetree/bindings/

  • 查看驱动源码:看源码中是怎么解析属性的,就知道有这个属性的存在了。

  • 参考厂商开发板的设备树文件

SOC 硬件信息

这些都是特殊的节点。

1、CPU 信息

&cpu0 {
	arm-supply = <&reg_arm>;
	soc-supply = <&reg_soc>;
	dc-supply = <&reg_gpio_dvfs>;
};

&clks {
	assigned-clocks = <&clks IMX6UL_CLK_PLL4_AUDIO_DIV>;
	assigned-clock-rates = <722534400>;
};

2、DDR 信息

3、GIC 中断控制器

6、向 uboot 传参

chosen 节点不代表一个真正的设备,仅用于向 uboot 传参,设置串口波特率。

按键

LED

以太网

Linux 上有一个通用的 PHY 驱动,SR8201F 芯片有 Clause 22 标准寄存器,所以这个通用的 PHY 驱动就能用。

通用 PHY 驱动能满足上网需求,如果是一些特殊功能,比如自定义 LED,这个需要自己搞。

一些特殊的 PHY 芯片需要专门的驱动(放在在 /drivers/net/ethernet)。

直接在手册中搜 Clause,如果能搜到 Clause 22 或者 Clause 28 就表明可以。

像 YT8512H 的手册中直接有:

所以能用这个通用驱动程序。

&fec1 {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_enet1
		     &pinctrl_fec1_reset>;
	phy-mode = "rmii";
	phy-handle = <&ethphy0>;
	phy-reset-gpios = <&gpio5 7 GPIO_ACTIVE_LOW>;
	phy-reset-duration = <200>;
	status = "okay";
};

&fec2 {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_enet2
		     &pinctrl_fec2_reset>;
	phy-mode = "rmii";
	phy-handle = <&ethphy1>;
	phy-reset-gpios = <&gpio5 8 GPIO_ACTIVE_LOW>;
	phy-reset-duration = <200>;
	status = "okay";

	mdio {
		#address-cells = <1>;
		#size-cells = <0>;

		ethphy0: ethernet-phy@2 {
			compatible = "ethernet-phy-ieee802.3-c22";
			reg = <0>;
		};

		ethphy1: ethernet-phy@1 {
			compatible = "ethernet-phy-ieee802.3-c22";
			reg = <1>;
		};
	};
};

SPI 设备

QSPI 设备

I2C 设备

1、设置引脚

		pinctrl_i2c1: i2c1grp {
			fsl,pins = <
				MX6UL_PAD_UART4_TX_DATA__I2C1_SCL 0x4001b8b0
				MX6UL_PAD_UART4_RX_DATA__I2C1_SDA 0x4001b8b0
			>;
		};

		pinctrl_i2c2: i2c2grp {
			fsl,pins = <
				MX6UL_PAD_UART5_TX_DATA__I2C2_SCL 0x4001b8b0
				MX6UL_PAD_UART5_RX_DATA__I2C2_SDA 0x4001b8b0
			>;
		};

&i2c1 {
	clock-frequency = <100000>;
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_i2c1>;
	status = "okay";

	mag3110@0e {
		compatible = "fsl,mag3110";
		reg = <0x0e>;
		position = <2>;
	};

	ap3216c@1e {
		compatible = "ap3216c";
		reg = <0x1e>;
	};
};

&i2c2 {
	clock_frequency = <100000>;
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_i2c2>;
	status = "okay";

	gt9147: gt9147@14 {
        compatible = "goodix,gt9147", "goodix,gt9xx";
        reg = <0x14>;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_ts_int
                     &pinctrl_ts_reset>;
        interrupt-parent = <&gpio1>;
        interrupts = <9 0>;
        reset-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>; 
        interrupt-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>;
        status="okay";
    };

        
};

触摸芯片

RGBLCD 屏幕

引脚设置:

		pinctrl_lcdif_dat: lcdifdatgrp {
			fsl,pins = <
				MX6UL_PAD_LCD_DATA00__LCDIF_DATA00  0x79
				MX6UL_PAD_LCD_DATA01__LCDIF_DATA01  0x79
				MX6UL_PAD_LCD_DATA02__LCDIF_DATA02  0x79
				MX6UL_PAD_LCD_DATA03__LCDIF_DATA03  0x79
				MX6UL_PAD_LCD_DATA04__LCDIF_DATA04  0x79
				MX6UL_PAD_LCD_DATA05__LCDIF_DATA05  0x79
				MX6UL_PAD_LCD_DATA06__LCDIF_DATA06  0x79
				MX6UL_PAD_LCD_DATA07__LCDIF_DATA07  0x79
				MX6UL_PAD_LCD_DATA08__LCDIF_DATA08  0x79
				MX6UL_PAD_LCD_DATA09__LCDIF_DATA09  0x79
				MX6UL_PAD_LCD_DATA10__LCDIF_DATA10  0x79
				MX6UL_PAD_LCD_DATA11__LCDIF_DATA11  0x79
				MX6UL_PAD_LCD_DATA12__LCDIF_DATA12  0x79
				MX6UL_PAD_LCD_DATA13__LCDIF_DATA13  0x79
				MX6UL_PAD_LCD_DATA14__LCDIF_DATA14  0x79
				MX6UL_PAD_LCD_DATA15__LCDIF_DATA15  0x79
				MX6UL_PAD_LCD_DATA16__LCDIF_DATA16  0x79
				MX6UL_PAD_LCD_DATA17__LCDIF_DATA17  0x79
				MX6UL_PAD_LCD_DATA18__LCDIF_DATA18  0x79
				MX6UL_PAD_LCD_DATA19__LCDIF_DATA19  0x79
				MX6UL_PAD_LCD_DATA20__LCDIF_DATA20  0x79
				MX6UL_PAD_LCD_DATA21__LCDIF_DATA21  0x79
				MX6UL_PAD_LCD_DATA22__LCDIF_DATA22  0x79
				MX6UL_PAD_LCD_DATA23__LCDIF_DATA23  0x79
			>;
		};

		pinctrl_lcdif_ctrl: lcdifctrlgrp {
			fsl,pins = <
				MX6UL_PAD_LCD_CLK__LCDIF_CLK	    0x79
				MX6UL_PAD_LCD_ENABLE__LCDIF_ENABLE  0x79
				MX6UL_PAD_LCD_HSYNC__LCDIF_HSYNC    0x79
				MX6UL_PAD_LCD_VSYNC__LCDIF_VSYNC    0x79
			>;
		};

		pinctrl_pwm1: pwm1grp {
			fsl,pins = <
				MX6UL_PAD_GPIO1_IO08__PWM1_OUT   0x110b0
			>;
		};

正点原子开发板有问题,所以需要降低驱动能力,将0x79全部改为0x49

修改设备树:

&lcdif {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_lcdif_dat
		     &pinctrl_lcdif_ctrl
		     &pinctrl_lcdif_reset>;
	display = <&display0>;
	status = "okay";

	display0: display {
		bits-per-pixel = <16>;
		bus-width = <24>;

		display-timings {
			native-mode = <&timing0>;
			timing0: timing0 {
			clock-frequency = <9200000>;
			hactive = <480>;
			vactive = <272>;
			hfront-porch = <8>;
			hback-porch = <4>;
			hsync-len = <41>;
			vback-porch = <2>;
			vfront-porch = <4>;
			vsync-len = <10>;

			hsync-active = <0>;
			vsync-active = <0>;
			de-active = <1>;
			pixelclk-active = <0>;
			};
		};
	};
};

&lcdif {
    pinctrl-names = "default"; 
    pinctrl-0 = <&pinctrl_lcdif_dat /* 使用到的 IO */ 
                 &pinctrl_lcdif_ctrl>; 
    display = <&display0>; 
    status = "okay"; 

    display0: display {               /* LCD属性信息 */
    bits-per-pixel = <24>;            /* 一个像素大小24bit */ 
    bus-width = <24>;                 /* 总线宽度 */ 
  
     display-timings { 
             native-mode = <&timing0>;     /* 时序信息 */ 
             timing0: timing0 {        
             clock-frequency = <51200000>; /* LCD像素时钟,单位 Hz,51.2MHz */ 
             hactive = <1024>; /* X轴像素个数 */ 
             vactive = <600>; /* Y轴像素个数 */ 
             hfront-porch = <160>; /* hfp参数 */ 
             hback-porch = <140>; /* hbp参数 */ 
             hsync-len = <20>; /* hspw参数 */ 
             vback-porch = <20>; /* vbp参数 */ 
             vfront-porch = <12>; /* vfp参数 */ 
             vsync-len = <3>; /* vspw参数 */ 
  
             hsync-active = <0>;       /* hsync数据线极性 */ 
             vsync-active = <0>;       /* vsync数据线极性 */ 
             de-active = <1>;          /* de数据线极性 */ 
             pixelclk-active = <0>;    /* clk数据线先极性 */ 
           }; 
        }; 
     }; 
 }; 

背光设置:

屏幕左上角出现企鹅,说明屏幕配置成功。

CAN

TF 卡

USDHC = Ultra Secured Digital Host Controller,SD/MMC 控制器

这个外设用来接:

  • SD 卡

  • EMMC

  • SDIO 接口的 Wifi 模块

  • ......

/Documentation/devicetree/bindings/mmc/mmc.txt

&usdhc1 {
	pinctrl-names = "default", "state_100mhz", "state_200mhz";
	pinctrl-0 = <&pinctrl_usdhc1>;
	pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
	pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
	cd-gpios = <&gpio1 19 GPIO_ACTIVE_LOW>;
	keep-power-in-suspend;
	enable-sdio-wakeup;
	vmmc-supply = <&reg_sd1_vmmc>;
	no-1-8-v;
	status = "okay";
};

  • no-1-8-v:禁止 SD 控制器进入 1.8V UHS 模式,也就是强制 SD 卡一直用 3.3V 工作

EMMC

&usdhc2 {
	pinctrl-names = "default", "state_100mhz", "state_200mhz"; 
    pinctrl-0 = <&pinctrl_usdhc2_8bit>; 
    pinctrl-1 = <&pinctrl_usdhc2_8bit_100mhz>; 
    pinctrl-2 = <&pinctrl_usdhc2_8bit_200mhz>; 
    bus-width = <8>; 
	non-removable;
    no-1-8-v;
	status = "okay";
};

看门狗