0%

Linux驱动学习实战(6) 逐飞LS2K0300设备树修改

  学弟和我说逐飞核心板的电机输出PWM引脚坏了,买新的要等到20号才能发货,问问我有没有办法从软件上修复。我想了一下,可以通过修改设备树的配置来达到相同的效果。

解读设备树

  在逐飞开源库下载 LS2K0300 有关的开源资料,在虚拟机中输入以下命令。

git clone https://gitee.com/seekfree/LS2K0300_Library.git

  打开其中的 linux 内核文件夹,打开目录 arch/loongarch/boot/dts/loongson,可以看到有许多设备树文件:

图 1 设备树文件

  打开 seekfree_2k0300_coreboard.dts 文件,找到如下代码:

1
2
3
4
5
6
7
8
zf_pwm_motor_2{
compatible = "seekfree,pwm";
pwms = <&pwm1 0 1000000>; // pwm1 通道0 周期(用户不需要关心)
status = "okay";
freq = <17000>; // 17KHZ 频率
duty = <0>; // 默认 0% 的占空比
duty_max = <10000>; // duty最大值,不建议修改。
};

  可以看出,电机2需要一个 PWM1 控制器的 通道0 输出 pwm。接下来,我们在 loongson_2k0300.dtsi 找到 pwm1 控制器。

1
2
3
4
5
6
7
8
9
pwm1: pwm@1611b010 {
compatible = "loongson,ls300-pwm";
reg = <0 0x1611b010 0 0x10>;
clock-frequency = <160000000>;
interrupt-parent = <&icu>;
interrupts = <16>;
#pwm-cells = <2>;
status = "disabled";
};

  可以看出,他的寄存器在 0x1611b010,CPU 写这个地址就能控制 PWM 的输出。但此时信号还没有出去,因为还没有接到引脚上。于是,在 seekfree_2k0300_coreboard.dts 板级文件上,我们找到了 pwm1 控制器的出口:

1
2
3
4
5
6
7
&pwm1{
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&pwm1_mux_m1>;
clock-frequency = <160000000>;
compatible = "loongson,ls300-pwm";
};

  所以,当 pwm1 控制器启用时,默认使用 pwm1_mux_m1 引脚输出 PWM 信号。那 pwm1_mux_m1 又是什么?我们在 2k0300-pinctrl.dtsi 文件中可以找到如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
pwm1_pin: pwm1-pin{
pwm1_mux_m0: pwm1-mux-m0{
loongson,pinmux = <&gpa4 1 1>;
loongson,pinmux-funcsel = <PINCTL_FUNCTION1>;
};
pwm1_mux_m1: pwm1-mux-m1{ /* pwm1 have three multiplex methods */
loongson,pinmux = <&gpa5 7 7>;
loongson,pinmux-funcsel = <PINCTL_FUNCTION2>;
};
pwm1_mux_m2: pwm1-mux-m2{ /* pwm1 have three multiplex methods */
loongson,pinmux = <&gpa6 7 7>;
loongson,pinmux-funcsel = <PINCTL_FUNCTION2>;
};
};

  可以看出,pwm1_mux_m1 对应的引脚就是 <&gpa5 7 7>、第二功能复用,这个组又是什么意思呢?找到 gpa 有关的设备树代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
pinctrl: pinctrl@0x16000490 {
compatible = "loongson,ls2k300-pinctrl";
reg = <0 0x16000490 0 0x10
0 0x16104000 0 0x1000>;
loongson,regs-offset = <0x4>;
loongson,num-chips = <7>;
#address-cells = <2>;
#size-cells = <2>;

gpa0: gpa0@0x16104000 {
gpio-controller;
#gpio-cells = <2>;
#loongson,pinmux-cells = <2>;

interrupt-controller;
#interrupt-cells = <3>;
interrupt-parent = <&icu>;
interrupts = <53>;
};

gpa1: gpa1@0x16104000 {
gpio-controller;
#gpio-cells = <2>;
#loongson,pinmux-cells = <2>;

interrupt-controller;
#interrupt-cells = <3>;
interrupt-parent = <&icu>;
interrupts = <54>;
};

gpa2: gpa2@0x16104000 {
gpio-controller;
#gpio-cells = <2>;
#loongson,pinmux-cells = <2>;

interrupt-controller;
#interrupt-cells = <3>;
interrupt-parent = <&icu>;
interrupts = <55>;
};

gpa3: gpa3@0x16104000 {
gpio-controller;
#gpio-cells = <2>;
#loongson,pinmux-cells = <2>;

interrupt-controller;
#interrupt-cells = <3>;
interrupt-parent = <&icu>;
interrupts = <56>;
};

gpa4: gpa4@0x16104000 {
gpio-controller;
#gpio-cells = <2>;
#loongson,pinmux-cells = <2>;

interrupt-controller;
#interrupt-cells = <3>;
interrupt-parent = <&icu>;
interrupts = <57>;
};

gpa5: gpa5@0x16104000 {
gpio-controller;
#gpio-cells = <2>;
#loongson,pinmux-cells = <2>;

interrupt-controller;
#interrupt-cells = <3>;
interrupt-parent = <&icu>;
interrupts = <58>;
};

gpa6: gpa6@0x16104000 {
gpio-controller;
#gpio-cells = <2>;
#loongson,pinmux-cells = <2>;

interrupt-controller;
#interrupt-cells = <3>;
interrupt-parent = <&icu>;
interrupts = <59>;
};
};

  可以看到,设备树将 GPIO 分为 7 个 bank,而查阅龙芯数据手册后得知,这块芯片一共有 106 个 GPIO,106 / 7 约等于 15,所以可以得知一组有 16 个 GPIO,因此:

1
2
3
4
5
6
7
gpa0 : GPIO0  ~ GPIO15
gpa1 : GPIO16 ~ GPIO31
gpa2 : GPIO32 ~ GPIO47
gpa3 : GPIO48 ~ GPIO63
gpa4 : GPIO64 ~ GPIO79
gpa5 : GPIO80 ~ GPIO95
gpa6 : GPIO96 ~ GPIO111

  验算一下,<&gpa5 7 7>,5*16 + 7 = 87,正好对应板子上的 P87,组中的第三位数据就表示写当前 GPIO 复用配置寄存器的第 [2x+1:2x]位。

图 2 复用寄存器
loongson,pinmux-funcsel = <PINCTL_FUNCTION2>;

  这一句就表示使用当前 GPIO 的第二功能复用,查询数据手册,发现其第二功能正好是 pwm 输出。

图 3 GPIO 复用功能

  总结一下,PWM 控制器只负责产生波形(channel0),而 pinctrl 把这个波形接到了 GPIO87。

修改设备树

  很好,现在已经读懂了。根据学弟要求我们需要修改 PWM 输出到 P65 引脚,正好 pwm1_mux_m0 对应的就是 P65,因此,在 seekfree_2k0300_coreboard.dts 中,修改 pwm1_mux_m1 为 pwm1_mux_m0,就将输出引脚从<&gpa5 7 7> 改为了 <&gpa4 1 1>,即 P65。

1
2
3
4
5
6
7
&pwm1{
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&pwm1_mux_m0>;
clock-frequency = <160000000>;
compatible = "loongson,ls300-pwm";
};

  接下来一步非常重要,检查此 GPIO 口有没有被其他设备占用。可以看到&gpa4 1 已被占用,我们把这个设备改成 disbaled。

1
2
3
4
5
6
zf_gpio_hall_detection{
// status = "okay";
status = "disbaled";
compatible = "seekfree,gpio_in";
gpios = <&gpa4 1 GPIO_ACTIVE_HIGH>;
};

  学弟进行设备树文件的替换后,运行根目录下的 build.sh 脚本,PWM成功复活。