Linux_driver
Linux Driver
0x00 ENV Setup
共享网络 (可以ssh不能上网的情况)
ifconfig命令查看wifi网卡和有线网卡,需要將流量从wifi网卡转发到有线网卡,如下所示wifi卡(wlo1),有线(eno1)
$ ifconfig
docker0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
ether 02:42:46:24:2c:35 txqueuelen 0 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 155 overruns 0 carrier 0 collisions 0
eno1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.42.0.1 netmask 255.255.255.0 broadcast 10.42.0.255
inet6 fe80::d8ea:b4fd:d1b0:1445 prefixlen 64 scopeid 0x20<link>
ether 04:0e:3c:04:37:f0 txqueuelen 1000 (Ethernet)
RX packets 19935 bytes 12312967 (12.3 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 14446 bytes 2897490 (2.8 MB)
TX errors 0 dropped 18 overruns 0 carrier 0 collisions 0
enx0826ae35f08d: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
ether 08:26:ae:35:f0:8d txqueuelen 1000 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 2 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 1089779 bytes 4159784997 (4.1 GB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 1089779 bytes 4159784997 (4.1 GB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
wlo1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.31.182 netmask 255.255.255.0 broadcast 192.168.31.255
inet6 fe80::5ded:4ab:d586:b60c prefixlen 64 scopeid 0x20<link>
ether 50:e0:85:e8:58:0f txqueuelen 1000 (Ethernet)
RX packets 3582838 bytes 4974553253 (4.9 GB)
RX errors 0 dropped 6 overruns 0 frame 0
TX packets 788343 bytes 101990756 (101.9 MB)
TX errors 0 dropped 34 overruns 0 carrier 0 collisions 0
输入以下命令进行转发配置:
$ sudo iptables -t nat -A POSTROUTING -o wlo1 -j MASQUERADE
$ sudo iptables -A FORWARD -i eno1 -o wlo1 -j ACCEPT
$ sudo iptables -A FORWARD -i wlo1 -o eno1 -m state --state RELATED,ESTABLISHED -j ACCEPT
$ sudo netfilter-persistent save
随后在单板端创建文件/etc/netplan/50-cloud-init.yaml,内容如下
network:
version: 2
ethernets:
eth0:
addresses: [10.42.0.218/24] # 与PC同子网
routes:
- to: 0.0.0.0/0
via: 10.42.0.1 # PC的有线IP
nameservers:
addresses: [8.8.8.8, 1.1.1.1] # 手动指定DNS
使能刚才的配置并确认已经转发到对应端口并尝试ping外网
$ sudo netplan apply
$ ip route show | grep default
default via 10.42.0.1 dev enP4p65s0 proto dhcp metric 100
$ ping baidu.com
ING baidu.com (110.242.68.66) 56(84) bytes of data.
64 bytes from baidu.com (110.242.68.66): icmp_seq=1 ttl=49 time=84.8 ms
64 bytes from baidu.com (110.242.68.66): icmp_seq=3 ttl=49 time=101 ms
tftp启动内核
setenv ipaddr 10.42.0.218
setenv netmask 255.255.255.0
setenv gatewayip 10.42.0.1
setenv serverip 10.42.0.1
setenv bootargs root=/dev/nfs rw nfsroot=${serverip}:/home/songyj/embedded/nfs,v3,tcp ip=${ipaddr}::${serverip}:255.255.255.0::eth0:off console=ttyS0,1500000n8
pci enum
tftpboot ${kernel_addr_r} Image
tftpboot ${fdt_addr_r} rk3588-rock-5b.dtb
booti ${kernel_addr_r} - ${fdt_addr_r}
如何编译驱动?
在PC上编译驱动需要内核源码以及交叉编译工具链,驱动文件可以在内核外随便找地方存放,编译之前需要先设置环境变量:
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
在Makefile中指定内核路径。make -C表示到KDIR这个路径执行make,随后將生成的.ko复制到板上。
KDIR ?= /home/songyj/embedded/rk5b/kernel
PWD := $(shell pwd)
obj-m += gpio.o
all:
make -C ${KDIR} M=$(PWD) modules
clean:
make -C ${KDIR} M=$(PWD) clean
0x01 Device Tree
DT basics
冒号之前的是Lable,相当于节点的别名,如果后续需要修改节点的的property可以通过引用别名来追加修改或者新建property。
看一个例子,下面是截取rock5B的RGB LED的设备树节点。结合原理图可以确认user-led2是控制蓝色LED的引脚,RK_PB7和GPIO_ACTIVE_HIGH代表引脚编号以及电平设置,这两个宏定义在dt-binding相关的文档。这些格式都是内核文档中已经规定好的,在Documentation/devicetree/bindings中搜索具体的规则。
// arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts
/{
...
gpio-leds {
compatible = "gpio-leds";
pinctrl-names = "default";
user-led2 {
gpios = <&gpio0 RK_PB7 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "heartbeat";
default-state = "on";
};
};
...
}
// include/dt-bindings/pinctrl/rockchip.h
#define RK_PB7 15
// include/dt-bindings/gpio/gpio.h
#define GPIO_ACTIVE_HIGH 0
cells
DeveiceTree中有个比较重要的概念cells,cells表示property相关的32bits的数字。
reg = <0x50027000>, <0x4>, <0x500273f0>, <0x10>; // 4 entriy 4 cell
reg = <0x50027000 0x4 0x500273f0>, <0x10>; // 2 entriy 4 cell
reg = <0x50027000>, <0x4 0x500273f0 0x10>; // 2 entriy 4 cell
reg = <0x50027000 0x4 0x500273f0 0x10>; // 1 entriy 4 cell
cells如何规定怎么填写property值,以下面设备树为例:在spi3节点中使用到之前定义的三个外设节点intc,rcc以及dmamux1,他们的cells与后面spi3使用时正好对应(注意类似&rcc和&dmamux1不是cell,因为他们不是和property相关的值,不计入cells数量)
// 定义三个外设
intc: interrupt-controller@a0021000 {
compatible = "arm,cortex-a7-gic";
#interrupt-cells = <3>;
interrupt-controller;
reg = <0xa0021000 0x1000>, <0xa0022000 0x2000>;
};
rcc: rcc@50000000 {
compatible = "st,stm32mp1-rcc", "syscon";
reg = <0x50000000 0x1000>;
#clock-cells = <1>;
#reset-cells = <1>;
};
dmamux1: dma-router@48002000 {
compatible = "st,stm32h7-dmamux";
reg = <0x48002000 0x1c>;
#dma-cells = <3>;
clocks = <&rcc DMAMUX>;
resets = <&rcc DMAMUX_R>;
};
// spi3需要配置这三个外设
spi3: spi@4000c000 {
interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&rcc SPI3_K>;
resets = <&rcc SPI3_R>;
dmas = <&dmamux1 61 0x400 0x05>, <&dmamux1 62 0x400 0x05>;
};
DTB使用
- 设备树编译命令
dtc -@ -I dts -O dtb -o ./gpio.dtbo ./gpio.dts
- 使能自己的dtbo
方法1:/boot/extlinux/extlinux.conf
这个配置文件是uboot的启动参数,l0是默认启动参数,l0r是recovery启动参数,添加fdtoverlays /lib/firmware/5.10.0-1012-rockchip/device-tree/rockchip/gpio.dtbo指定要加载的dtbo文件。设置好路径之后重启设备,在/sys/firmware/devicetree/base中检查有没有对应的节点。
## /boot/extlinux/extlinux.conf
##
## IMPORTANT WARNING
##
## The configuration of this file is generated automatically.
## Do not edit this file manually, use: u-boot-update
default l0
menu title U-Boot menu
prompt 1
timeout 20
label l0
menu label Ubuntu 22.04.5 LTS 5.10.0-1012-rockchip
linux /boot/vmlinuz-5.10.0-1012-rockchip
initrd /boot/initrd.img-5.10.0-1012-rockchip
fdtdir /lib/firmware/5.10.0-1012-rockchip/device-tree/
fdtoverlays /lib/firmware/5.10.0-1012-rockchip/device-tree/rockchip/overlay/gpio.dtbo
append root=UUID=cbf6ee10-c4b9-49e9-b246-f17a818913e1 rootwait rw console=ttyS2,1500000 console=tty1 cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory quiet splash plymouth.ignore-serial-consoles
label l0r
menu label Ubuntu 22.04.5 LTS 5.10.0-1012-rockchip (rescue target)
linux /boot/vmlinuz-5.10.0-1012-rockchip
initrd /boot/initrd.img-5.10.0-1012-rockchip
fdtdir /lib/firmware/5.10.0-1012-rockchip/device-tree/
append root=UUID=cbf6ee10-c4b9-49e9-b246-f17a818913e1 rootwait rw console=ttyS2,1500000 console=tty1 cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory splash plymouth.ignore-serial-consoles single
dtbo有时候很难给原设备树节点覆盖上