扩展 u-boot 功能
Extending u-boot functionality
我需要向 u-boot 添加一些新功能,例如按下指定按钮以使用闪烁的 LED 作为设备响应来设置我的设备。问题是我不知道 u-boot 从哪里开始执行 C 代码。我应该修改什么文件?
我使用 STM32F429I-Discovery 进行测试,并且已经使用 buildroot 安装 运行 内核所需的一切。其中一个 LED (GPIO_13) 不断闪烁,因此,我尝试搜索提供此类功能的代码。看起来 led.c 和 gpio_led.c 必须做这件事,但改变它们什么也没有。
更新。
好吧,我试图深入研究触发器,但看起来修改 .dts 文件对 LED 闪烁没有影响。在相应的心跳触发器中注释代码会关闭 LED,但是,没有 GPIO 选择,因此,我无法将绿色 LED 更改为红色。将 "linux,default-trigger" 移动到 .dts 文件中的 GPIO14 后,我使用 buildroot 重新编译了 u-boot 和 linux,但没有任何变化。这是我的更改(我从 stm32f746-disco.c 中获取了一些代码):
stm32f429-disco.dts
/dts-v1/;
#include "stm32f429.dtsi"
#include "stm32f429-pinctrl.dtsi"
#include <dt-bindings/input/input.h>
/ {
model = "STMicroelectronics STM32F429i-DISCO board";
compatible = "st,stm32f429i-disco", "st,stm32f429";
chosen {
bootargs = "root=/dev/ram";
stdout-path = "serial0:115200n8";
};
memory {
reg = <0x90000000 0x800000>;
};
aliases {
serial0 = &usart1;
};
leds {
compatible = "st,leds";
red {
gpios = <&gpiog 14 0>;
linux,default-trigger = "heartbeat";
};
green {
gpios = <&gpiog 13 0>;
};
};
gpio_keys {
compatible = "gpio-keys";
#address-cells = <1>;
#size-cells = <0>;
autorepeat;
button@0 {
label = "User";
linux,code = <KEY_HOME>;
gpios = <&gpioa 0 0>;
};
};
/* This turns on vbus for otg for host mode (dwc2) */
vcc5v_otg: vcc5v-otg-regulator {
compatible = "regulator-fixed";
gpio = <&gpioc 4 0>;
regulator-name = "vcc5_host1";
regulator-always-on;
};
};
&clk_hse {
clock-frequency = <8000000>;
};
stm32f429-discovery.c
#include <common.h>
#include <dm.h>
#include <ram.h>
#include <spl.h>
#include <asm/io.h>
#include <asm/armv7m.h>
#include <asm/arch/stm32.h>
#include <asm/arch/gpio.h>
#include <asm/arch/stm32_periph.h>
#include <asm/arch/stm32_defs.h>
#include <asm/gpio.h>
DECLARE_GLOBAL_DATA_PTR;
int dram_init(void)
{
int rv;
struct udevice *dev;
rv = uclass_get_device(UCLASS_RAM, 0, &dev);
if (rv) {
debug("DRAM init failed: %d\n", rv);
return rv;
}
if (fdtdec_setup_memory_size() != 0)
rv = -EINVAL;
return rv;
}
int dram_init_banksize(void)
{
fdtdec_setup_memory_banksize();
return 0;
}
u32 get_board_rev(void)
{
return 0;
}
int board_early_init_f(void)
{
return 0;
}
int board_init(void)
{
gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
struct gpio_desc gpio = {};
int node, offset_node;
node = fdt_node_offset_by_compatible(gd->fdt_blob, 0, "st,leds");
offset_node = fdt_subnode_offset(gd->fdt_blob, node, "green");
if (node < 0)
return -1;
gpio_request_by_name_nodev(offset_to_ofnode(offset_node), "gpios", 0, &gpio, GPIOD_IS_OUT);
if (dm_gpio_is_valid(&gpio)) {
dm_gpio_set_value(&gpio, 1);
}
return 0;
}
#ifdef CONFIG_MISC_INIT_R
int misc_init_r(void)
{
char serialno[25];
uint32_t u_id_low, u_id_mid, u_id_high;
if (!env_get("serial#")) {
u_id_low = readl(&STM32_U_ID->u_id_low);
u_id_mid = readl(&STM32_U_ID->u_id_mid);
u_id_high = readl(&STM32_U_ID->u_id_high);
sprintf(serialno, "%08x%08x%08x",
u_id_high, u_id_mid, u_id_low);
env_set("serial#", serialno);
}
return 0;
}
您应该在 board.c 文件中添加 u-boot 功能。可以在以下位置找到:u-boot/board/stm/stm32f429-discovery/board.c
您可能需要更改其他设置,这可以在头文件中完成。可以找到此文件:u-boot/include/configs/stm32f429-discovery.h
LED 在设备树中定义(U-Boot 文件 arch/arm/dts/stm32f429-disco.dts,Linux 内核文件 arch/arm/boot/dts/stm32f429-disco.dts)
leds {
compatible = "gpio-leds";
red {
gpios = <&gpiog 14 0>;
};
green {
gpios = <&gpiog 13 0>;
linux,default-trigger = "heartbeat";
};
};
在 Linux 中,您可以通过写入适当的触发器文件来更改触发器。这应该是
/sys/class/leds/green/trigger
GPIO 的 U-Boot 驱动程序是 drivers/gpio/stm32_gpio.c
您可以使用函数 dm_gpio_set_value() 将 GPIO 设置为输入,并使用 dm_gpio_get_value() 读取值。
您可能希望使用 board/st/stm32mp1/stm32mp1.c 的 FASTBOOT 部分作为模板。
我需要向 u-boot 添加一些新功能,例如按下指定按钮以使用闪烁的 LED 作为设备响应来设置我的设备。问题是我不知道 u-boot 从哪里开始执行 C 代码。我应该修改什么文件?
我使用 STM32F429I-Discovery 进行测试,并且已经使用 buildroot 安装 运行 内核所需的一切。其中一个 LED (GPIO_13) 不断闪烁,因此,我尝试搜索提供此类功能的代码。看起来 led.c 和 gpio_led.c 必须做这件事,但改变它们什么也没有。
更新。
好吧,我试图深入研究触发器,但看起来修改 .dts 文件对 LED 闪烁没有影响。在相应的心跳触发器中注释代码会关闭 LED,但是,没有 GPIO 选择,因此,我无法将绿色 LED 更改为红色。将 "linux,default-trigger" 移动到 .dts 文件中的 GPIO14 后,我使用 buildroot 重新编译了 u-boot 和 linux,但没有任何变化。这是我的更改(我从 stm32f746-disco.c 中获取了一些代码):
stm32f429-disco.dts
/dts-v1/;
#include "stm32f429.dtsi"
#include "stm32f429-pinctrl.dtsi"
#include <dt-bindings/input/input.h>
/ {
model = "STMicroelectronics STM32F429i-DISCO board";
compatible = "st,stm32f429i-disco", "st,stm32f429";
chosen {
bootargs = "root=/dev/ram";
stdout-path = "serial0:115200n8";
};
memory {
reg = <0x90000000 0x800000>;
};
aliases {
serial0 = &usart1;
};
leds {
compatible = "st,leds";
red {
gpios = <&gpiog 14 0>;
linux,default-trigger = "heartbeat";
};
green {
gpios = <&gpiog 13 0>;
};
};
gpio_keys {
compatible = "gpio-keys";
#address-cells = <1>;
#size-cells = <0>;
autorepeat;
button@0 {
label = "User";
linux,code = <KEY_HOME>;
gpios = <&gpioa 0 0>;
};
};
/* This turns on vbus for otg for host mode (dwc2) */
vcc5v_otg: vcc5v-otg-regulator {
compatible = "regulator-fixed";
gpio = <&gpioc 4 0>;
regulator-name = "vcc5_host1";
regulator-always-on;
};
};
&clk_hse {
clock-frequency = <8000000>;
};
stm32f429-discovery.c
#include <common.h>
#include <dm.h>
#include <ram.h>
#include <spl.h>
#include <asm/io.h>
#include <asm/armv7m.h>
#include <asm/arch/stm32.h>
#include <asm/arch/gpio.h>
#include <asm/arch/stm32_periph.h>
#include <asm/arch/stm32_defs.h>
#include <asm/gpio.h>
DECLARE_GLOBAL_DATA_PTR;
int dram_init(void)
{
int rv;
struct udevice *dev;
rv = uclass_get_device(UCLASS_RAM, 0, &dev);
if (rv) {
debug("DRAM init failed: %d\n", rv);
return rv;
}
if (fdtdec_setup_memory_size() != 0)
rv = -EINVAL;
return rv;
}
int dram_init_banksize(void)
{
fdtdec_setup_memory_banksize();
return 0;
}
u32 get_board_rev(void)
{
return 0;
}
int board_early_init_f(void)
{
return 0;
}
int board_init(void)
{
gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
struct gpio_desc gpio = {};
int node, offset_node;
node = fdt_node_offset_by_compatible(gd->fdt_blob, 0, "st,leds");
offset_node = fdt_subnode_offset(gd->fdt_blob, node, "green");
if (node < 0)
return -1;
gpio_request_by_name_nodev(offset_to_ofnode(offset_node), "gpios", 0, &gpio, GPIOD_IS_OUT);
if (dm_gpio_is_valid(&gpio)) {
dm_gpio_set_value(&gpio, 1);
}
return 0;
}
#ifdef CONFIG_MISC_INIT_R
int misc_init_r(void)
{
char serialno[25];
uint32_t u_id_low, u_id_mid, u_id_high;
if (!env_get("serial#")) {
u_id_low = readl(&STM32_U_ID->u_id_low);
u_id_mid = readl(&STM32_U_ID->u_id_mid);
u_id_high = readl(&STM32_U_ID->u_id_high);
sprintf(serialno, "%08x%08x%08x",
u_id_high, u_id_mid, u_id_low);
env_set("serial#", serialno);
}
return 0;
}
您应该在 board.c 文件中添加 u-boot 功能。可以在以下位置找到:u-boot/board/stm/stm32f429-discovery/board.c
您可能需要更改其他设置,这可以在头文件中完成。可以找到此文件:u-boot/include/configs/stm32f429-discovery.h
LED 在设备树中定义(U-Boot 文件 arch/arm/dts/stm32f429-disco.dts,Linux 内核文件 arch/arm/boot/dts/stm32f429-disco.dts)
leds {
compatible = "gpio-leds";
red {
gpios = <&gpiog 14 0>;
};
green {
gpios = <&gpiog 13 0>;
linux,default-trigger = "heartbeat";
};
};
在 Linux 中,您可以通过写入适当的触发器文件来更改触发器。这应该是
/sys/class/leds/green/trigger
GPIO 的 U-Boot 驱动程序是 drivers/gpio/stm32_gpio.c
您可以使用函数 dm_gpio_set_value() 将 GPIO 设置为输入,并使用 dm_gpio_get_value() 读取值。
您可能希望使用 board/st/stm32mp1/stm32mp1.c 的 FASTBOOT 部分作为模板。