硬件介绍
Verdin AM62 所使用的 AM623/AM625 处理器的 GPIO 控制器如下图所示。GPIO 控制器根据不同的处理器可能有多个模块,AM623/AM625 拥有一个 MCU_GPIO0,一个 GPIO0 和一个 GPIO1 共三个模块。每个模块有 9 个 bank,每个 bank 有 16 个引脚,所以理论上最多有 3x9x46 = 432 个引脚。但 AM623/AM625 SoC 并不能使用所有引脚,SoC 实际可用的为 198 个引脚。Verdin AM62 模块并没有把 SoC 的引脚都引出,因而可用的引脚少于 198。
Device Tree 配置
在写本文章时,Verdin AM62 使用 toradex_ti-linux-6.1.y分支内核。每个 GPIO 根据用途的不同,相应的配置分布在多个 device tree 文件中。如下图,k3-am62-mcu.dtsi 和 k3-am62-main.dtsi 中定义了三个 GPIO 控制器模块以及对应的物理地址,k3-am62-verdin.dtsi 中包含每个引脚的具体配置。三个 GPIO 控制器分为两种,MCU_GPIO 和 GPIO0/1,它们可以使用各自专门的函数来配置所控制的引脚。&mcu_pmx0 和 &main_pmx0 分别使用 AM62X_MCU_IOPAD 和 AM62X_IOPAD 配置。下面将介绍如何修改和使用 mcu_gpio0,main_gpio0 和 main_gpio1 模块所控制的引脚。
我们分别选择来自如下三个不同 IO 控制器的引脚,分别是 SOIDMM 19、21、61。 查看 Verdi AM62 Datatsheet 的 Table 12: Alternate functions 可以确定对应引脚的 SoC Ball ID 和 SoC ball name。在 TI AM623/AM625处理器的 Datasheet 中 Table 6-1. Pin Attributes 可以找到对应 SoC Ball ID 的 PADCONFIG Address。有了这些信息就能够在 Device tree 中进行配置。
SODIMM | SoC Ball ID | SoC ball name | PADCONFIG Address | ALT7 |
61 | A6 | MCU_UART0_CTSn | 0x0408401C | MCU_GPIO0_7 |
21 | U24 | GPMC0_AD15 | 0x000F4078 | GPIO0_30 |
19 | A14 | SPI0_CLK | 0x000F41BC | GPIO1_17 |
k3-am62-verdin.dtsi 中提供了默认引脚的配置。Toradex 在代码中做了详细的注释,例如以 SODIMM 19 为关键字搜索,可以找到该引脚的默认配置,这里发现关于 SODIMM 19 的配置有两个。SODIMM 19 属于 GPIO1 控制器,所以该配置是 main_pmx0 下面的子节点,并使用 AM62X_IOPAD 函数进行配置。A14(Ball ID)的 PADCONFIG 地址是 0x000F41BC,对应的掩码是 0x1fff,AM62X_IOPAD 使用 0x01bc。 PIN_OUTPUT/PIN_INPUT 表示把该引脚配置为输出/输入状态。数字 2 表示该引脚使用第二个复用配置,即当作 PWM1_A 使用。数字 7 表示该引脚使用第七个复用配置,即当作 GPIO 使用。引脚所有可用的复用关系可在 Verdi AM62 Datatsheet Table 12: Alternate functions 查看。AM62 处理器的引脚最多可以有 10 个复用配置可选,在 Table 12 中由 ALT0 到 ALT9 表示。部分引脚可能少于 10 个复用配置。后面的注释中,A14 为 SoC Ball ID,SPI0_CLK 是 SoC Ball Name,GPIO1_17 指当前选择第七个复用配置,作为 GPIO 对应的编号 GPIO1_17。当配置为 PWM 功能时就由 GPIO1_17 改为 EHRPWM1_A。在修改为其他复用配置后,建议也对应修改注释,便于理解代码。
/* Verdin PWM_3_DSI */
pinctrl_epwm1_a: main-epwm1a-pins-default {
pinctrl-single,pins = <
AM62X_IOPAD(0x01bc, PIN_OUTPUT, 2)
/* (A14) SPI0_CLK.EHRPWM1_A */ /* SODIMM 19 */
>;
};
pinctrl_pwm3_dsi_gpio: main-gpio1-17-pins-default {
pinctrl-single,pins = <
AM62X_IOPAD(0x01bc, PIN_INPUT, 7)
/* (A14) SPI0_CLK.GPIO1_17 */ /* SODIMM 19 */
>;
};
上面 AM62X_IOPAD 中配置的 PIN_OUTPUT/PIN_INPUT 将设置 PADCONFIG 的寄存器。PIN_OUTPUT/PIN_INPUT 在 k3-pinctrl.h 定义。
/* Only these macros are expected be used directly in device tree files */
#define PIN_OUTPUT (INPUT_DISABLE | PULL_DISABLE)
#define PIN_OUTPUT_PULLUP (INPUT_DISABLE | PULL_UP)
#define PIN_OUTPUT_PULLDOWN (INPUT_DISABLE | PULL_DOWN)
#define PIN_INPUT (INPUT_EN | PULL_DISABLE)
#define PIN_INPUT_PULLUP (INPUT_EN | PULL_UP)
#define PIN_INPUT_PULLDOWN (INPUT_EN | PULL_DOWN)
PIN_OUTPUT/PIN_INPUT 定义的值最终被写入 Pad Configuration 寄存器,具体的说明可以参考 AM623/625 的 Technical Reference Manual中 Table 6-2045. Description Of The Pad Configuration Register Bits 相关说明。
根据 pinctrl_epwm1_a 查找,发现该引脚被分配到 epwm1,为了将 SODIMM 19 作为 GPIO 使用,在device tree 需要确保 epwm1 处于 disabled 状态。
/* Verdin PWM_3_DSI */
&epwm1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_epwm1_a>;
status = "disabled";
};
如果使用 k3-am625-verdin-nonwifi-dev.dtb,那么在 k3-am62-verdin-dev.dtsi 中需要将 epwm1 禁用。
/* Verdin PWM_3_DSI */
&epwm1 {
status = "disabled";
};
在 k3-am62-verdin.dtsi 的 main_gpio1 可以为 GPIO1 控制器的引脚添加 line-name,这样在 Linux 中 libgpiod 就能够使用更直观 line-name 直接访问引脚。gpio-line-names 从 gpio1_0 开始为每个引脚添加 line-name,gpio1_17 则设置为 SODIMM_19。
&main_gpio1 {
gpio-line-names =
"", /* 0 */
"",
"",
"",
"",
"",
"",
"",
"",
"",
"", /* 10 */
"",
"",
"",
"",
"SODIMM_15",
"SODIMM_16",
"SODIMM_19",
由于 SOIDMM 19 属于 GPIO1 控制器,在 k3-am62-verdin-dev.dtsi 中需要添加 main_gpio1 节点并将 pinctrl_pwm3_dsi_gpio 添加到节点中。
&main_gpio1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_pwm3_dsi_gpio>;
};
SODIMM 21 也是类似的方法。在 Verdi AM62 Datatsheet Table 12: Alternate functions 中看到 SOIDMM 21 对应的 SoC Ball ID 为 U24,第七复用配置 ALT7 可以作为 GPIO 功能,编号 GPIO0_30,这属于 GPIO0 控制器。TI AM623/AM625处理器的 Datasheet 中 Table 6-1. Pin Attributes 中找到 U24 对应的 PADCONFIG Address 是 0x000F4078。因此,在 AM62X_IOPAD 使用 0x0078。
/* Verdin DSI_1_BKL_EN */
pinctrl_dsi1_bkl_en: main-gpio0-30-pins-default {
pinctrl-single,pins = <
AM62X_IOPAD(0x0078, PIN_INPUT, 7)
/* (U24) GPMC0_AD15.GPIO0_30 */ /* SODIMM 21 */
>;
};
在 main_gpio0 中,GPIO0_30 的 line-name 已经被定义为 SODIMM_21。
&main_gpio0 {
gpio-line-names =
"",
"SODIMM_76",
"SODIMM_21", /* 30 */
SODIMM 21 属于 GPIO0 控制器,在 k3-am62-verdin-dev.dtsi 中,将 pinctrl_dsi1_bkl_en 添加到 main_gpio0 节点中。
&main_gpio0 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_ctrl_sleep_moci>,
<&pinctrl_gpio_5>,
<&pinctrl_gpio_6>,
<&pinctrl_gpio_7>,
<&pinctrl_gpio_8>,
<&pinctrl_dsi1_bkl_en>;
};
在 Verdi AM62 Datatsheet 的 Table 12 发现 SODIMM 61 对应 ALT7 为 MCU_GPIO0_7,SoC Ball ID 为 A6,SoC ball name 为 MCU_UART0_CTSn。在 TI AM623/AM625 处理器的 Datasheet 中 Table 6-1 中对应的 PADCONFIG Address 是 0x0408401C。使用 0x010c 作为关键字在 k3-am62-verdin.dtsi 检索只发现下面配置,但该子节点属于 main_pmx0 而非为 mcu_pmx0。所以在 k3-am625-verdin-nonwifi-dev.dtb 并未配置 SODIMM 61。那么就需要在 k3-am62-verdin.dtsi 添加相关配置。
pinctrl_sdhci2: main-mmc2-pins-default {
pinctrl-single,pins = <
AM62X_IOPAD(0x120, PIN_INPUT, 0)
/* (C24) MMC2_CMD */ /* WiFi_SDIO_CMD */
AM62X_IOPAD(0x118, PIN_INPUT, 0)
/* (D25) MMC2_CLK */ /* WiFi_SDIO_CLK */
AM62X_IOPAD(0x114, PIN_INPUT, 0)
/* (B24) MMC2_DAT0 */ /* WiFi_SDIO_DATA0 */
AM62X_IOPAD(0x110, PIN_INPUT, 0)
/* (C25) MMC2_DAT1 */ /* WiFi_SDIO_DATA1 */
AM62X_IOPAD(0x10c, PIN_INPUT, 0)
/* (E23) MMC2_DAT2 */ /* WiFi_SDIO_DATA2 */
在 mcu_pmx0 中把 SODIMM 61 配置作为子节点添加进去。注意,由于 SODIMM 61 属于 MCU_GPIO 控制器,所以这里使用 AM62X_MCU_IOPAD 来配置。
&mcu_pmx0 {
/* Verdin GPIO_9 */
pinctrl_gpio_9: mcu-gpio0-7-pins-default {
pinctrl-single,pins = <
AM62X_MCU_IOPAD(0x001c, PIN_INPUT, 7)
/* (A6) MCU_UART0_CTSn.MCU_GPIO0_7 */ /* SODIMM 61 */
>;
};
在 &mcu_gpio0 中第八个位置添加 MCU_GPIO0_7 对应的 line-name 为 SODIMM_61。其中第一行 SODIMM_244 对应的是 MCU_GPIO0_0,第二行 SODIMM_206 对应的是 MCU_GPIO0_1。
&mcu_gpio0 {
gpio-line-names =
"SODIMM_244",
"SODIMM_206",
"SODIMM_208",
"SODIMM_210",
"SODIMM_212",
"",
"",
"SODIMM_61",
在 k3-am62-verdin-dev.dtsi 中的 mcu_gpio0 节点中添加前面配置的 pinctrl_gpio_9。
&mcu_gpio0 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_gpio_1>,
<&pinctrl_gpio_2>,
<&pinctrl_gpio_3>,
<&pinctrl_gpio_4>,
<&pinctrl_pcie_1_reset>,
<&pinctrl_gpio_9>;
};
引脚测试
上面配置完成后,重新编译 device tree,并部署到的开发板上。
make ti/k3-am625-verdin-nonwifi-dev.dtb
重启后使用 gpioinfo 命令找到上面配置三个引脚在 Linux 系统中对应的 bank 和 line 编号。
gpiochip1 - 24 lines:
line 7: "SODIMM_61" unused input active-high
gpiochip2 - 92 lines:
line 30: "SODIMM_21" unused input active-high
gpiochip3 - 52 lines:
line 17: "SODIMM_19" unused input active-high
下面三个命令分别可以把对应的引脚拉高或拉低。
root@verdin-am62:~# gpioset 3 17=1
root@verdin-am62:~# gpioset 2 30=1
root@verdin-am62:~# gpioset 1 7=1
root@verdin-am62:~# gpioset 3 17=0
root@verdin-am62:~# gpioset 2 30=0
root@verdin-am62:~# gpioset 1 7=0
除了像上面直接在 user space 控制 GPIO 的状态,驱动中也可以控制相关引脚。例如在 k3-am62-verdin-dev.dtsi 的根节点下添加一个 LED 子节点并使用 SOIDMM 61 来控制。首先,需要把 pinctrl_gpio_9 从原来 &mcu_gpio0 删除,因为这里该引脚不再作为普通的 GPIO 使用,而是用于 LED 驱动。在 gpios 参数中使用 &mcu_gpio0 7 来引用 SODIMM 61。如果是 main_gpio0 控制器下的 SODIMM 21,则对应需要使用 &main_gpio0 30 来引用。
gpio-leds {
compatible = "gpio-leds";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_gpio_9>;
led-yellow {
gpios = <&mcu_gpio0 7 GPIO_ACTIVE_HIGH>;
default-state = "on";
label = "status";
};
};
总结文章就 AM623/625 SoC 介绍了如何在 Device tree 中配置和使用 GPIO,需要注意区分 GPIO 来自哪个控制器,并使用对应的函数和引用符号。