mirror of
https://github.com/u-boot/u-boot.git
synced 2025-05-09 03:21:51 +00:00
Merge branch '2021-05-13-extension-board-detection-and-DT-overlay-application'
- Improve support for various forms of extension boards and add DT overlay application support.
This commit is contained in:
commit
530c8d4af2
36 changed files with 837 additions and 84 deletions
|
@ -121,6 +121,7 @@ config SANDBOX
|
|||
select SUPPORT_OF_CONTROL
|
||||
select SYSRESET_CMD_POWEROFF
|
||||
select IRQ
|
||||
select SUPPORT_EXTENSION_SCAN
|
||||
imply BITREVERSE
|
||||
select BLOBLIST
|
||||
imply CMD_DM
|
||||
|
@ -165,6 +166,7 @@ config SANDBOX
|
|||
imply BOOTARGS_SUBST
|
||||
imply PHY_FIXED
|
||||
imply DM_DSA
|
||||
imply CMD_EXTENSION
|
||||
|
||||
config SH
|
||||
bool "SuperH architecture"
|
||||
|
|
|
@ -34,6 +34,7 @@ config TARGET_AM335X_EVM
|
|||
select DM_GPIO
|
||||
select DM_SERIAL
|
||||
select TI_I2C_BOARD_DETECT
|
||||
select SUPPORT_EXTENSION_SCAN
|
||||
imply CMD_DM
|
||||
imply SPL_DM
|
||||
imply SPL_DM_SEQ_ALIAS
|
||||
|
|
|
@ -220,6 +220,7 @@ void enable_basic_clocks(void)
|
|||
&cmper->gpio2clkctrl,
|
||||
&cmper->gpio3clkctrl,
|
||||
&cmper->i2c1clkctrl,
|
||||
&cmper->i2c2clkctrl,
|
||||
&cmper->cpgmac0clkctrl,
|
||||
&cmper->spi0clkctrl,
|
||||
&cmrtc->rtcclkctrl,
|
||||
|
|
|
@ -36,6 +36,7 @@ config TARGET_AM57XX_EVM
|
|||
select CMD_DDR3
|
||||
select DRA7XX
|
||||
select TI_I2C_BOARD_DETECT
|
||||
select SUPPORT_EXTENSION_SCAN
|
||||
imply DM_THERMAL
|
||||
imply SCSI
|
||||
imply SPL_THERMAL
|
||||
|
|
|
@ -1089,3 +1089,12 @@ config BLUETOOTH_DT_DEVICE_FIXUP
|
|||
flipped elsewise.
|
||||
|
||||
endif
|
||||
|
||||
config CHIP_DIP_SCAN
|
||||
bool "Enable DIPs detection for CHIP board"
|
||||
select SUPPORT_EXTENSION_SCAN
|
||||
select W1
|
||||
select W1_GPIO
|
||||
select W1_EEPROM
|
||||
select W1_EEPROM_DS24XXX
|
||||
select CMD_EXTENSION
|
||||
|
|
|
@ -6,6 +6,7 @@ else
|
|||
dtb-$(CONFIG_SANDBOX) += sandbox.dtb
|
||||
endif
|
||||
dtb-$(CONFIG_UT_DM) += test.dtb
|
||||
dtb-$(CONFIG_CMD_EXTENSION) += overlay0.dtbo overlay1.dtbo
|
||||
|
||||
targets += $(dtb-y)
|
||||
|
||||
|
|
9
arch/sandbox/dts/overlay0.dts
Normal file
9
arch/sandbox/dts/overlay0.dts
Normal file
|
@ -0,0 +1,9 @@
|
|||
/dts-v1/;
|
||||
/plugin/;
|
||||
|
||||
&{/buttons} {
|
||||
btn3 {
|
||||
gpios = <&gpio_a 5 0>;
|
||||
label = "button3";
|
||||
};
|
||||
};
|
9
arch/sandbox/dts/overlay1.dts
Normal file
9
arch/sandbox/dts/overlay1.dts
Normal file
|
@ -0,0 +1,9 @@
|
|||
/dts-v1/;
|
||||
/plugin/;
|
||||
|
||||
&{/buttons} {
|
||||
btn4 {
|
||||
gpios = <&gpio_a 5 0>;
|
||||
label = "button4";
|
||||
};
|
||||
};
|
|
@ -14,6 +14,9 @@
|
|||
#include <asm/global_data.h>
|
||||
#include <asm/test.h>
|
||||
#include <asm/u-boot-sandbox.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#include <extension_board.h>
|
||||
|
||||
/*
|
||||
* Pointer to initial global data area
|
||||
|
@ -79,6 +82,26 @@ int ft_board_setup(void *fdt, struct bd_info *bd)
|
|||
return fdt_add_mem_rsv(fdt, 0x00d02000, 0x4000);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CMD_EXTENSION
|
||||
int extension_board_scan(struct list_head *extension_list)
|
||||
{
|
||||
struct extension *extension;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
extension = calloc(1, sizeof(struct extension));
|
||||
snprintf(extension->overlay, sizeof(extension->overlay), "overlay%d.dtbo", i);
|
||||
snprintf(extension->name, sizeof(extension->name), "extension board %d", i);
|
||||
snprintf(extension->owner, sizeof(extension->owner), "sandbox");
|
||||
snprintf(extension->version, sizeof(extension->version), "1.1");
|
||||
snprintf(extension->other, sizeof(extension->other), "Fictionnal extension board");
|
||||
list_add_tail(&extension->list, extension_list);
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BOARD_LATE_INIT
|
||||
int board_late_init(void)
|
||||
{
|
||||
|
|
|
@ -11,3 +11,4 @@ obj-$(CONFIG_SUN7I_GMAC) += gmac.o
|
|||
obj-$(CONFIG_MACH_SUN4I) += dram_sun4i_auto.o
|
||||
obj-$(CONFIG_MACH_SUN5I) += dram_sun5i_auto.o
|
||||
obj-$(CONFIG_MACH_SUN7I) += dram_sun5i_auto.o
|
||||
obj-$(CONFIG_CHIP_DIP_SCAN) += chip.o
|
||||
|
|
100
board/sunxi/chip.c
Normal file
100
board/sunxi/chip.c
Normal file
|
@ -0,0 +1,100 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2021
|
||||
* Köry Maincent, Bootlin, <kory.maincent@bootlin.com>
|
||||
* Based on initial code from Maxime Ripard
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <malloc.h>
|
||||
#include <dm.h>
|
||||
#include <w1.h>
|
||||
#include <w1-eeprom.h>
|
||||
#include <dm/device-internal.h>
|
||||
|
||||
#include <asm/arch/gpio.h>
|
||||
|
||||
#include <extension_board.h>
|
||||
|
||||
#define for_each_w1_device(b, d) \
|
||||
for (device_find_first_child(b, d); *d; device_find_next_child(d))
|
||||
|
||||
#define dip_convert(field) \
|
||||
( \
|
||||
(sizeof(field) == 1) ? field : \
|
||||
(sizeof(field) == 2) ? be16_to_cpu(field) : \
|
||||
(sizeof(field) == 4) ? be32_to_cpu(field) : \
|
||||
-1 \
|
||||
)
|
||||
|
||||
#define DIP_MAGIC 0x50494843 /* CHIP */
|
||||
|
||||
struct dip_w1_header {
|
||||
u32 magic; /* CHIP */
|
||||
u8 version; /* spec version */
|
||||
u32 vendor_id;
|
||||
u16 product_id;
|
||||
u8 product_version;
|
||||
char vendor_name[32];
|
||||
char product_name[32];
|
||||
u8 rsvd[36]; /* rsvd for future spec versions */
|
||||
u8 data[16]; /* user data, per-dip specific */
|
||||
} __packed;
|
||||
|
||||
int extension_board_scan(struct list_head *extension_list)
|
||||
{
|
||||
struct extension *dip;
|
||||
struct dip_w1_header w1_header;
|
||||
struct udevice *bus, *dev;
|
||||
u32 vid;
|
||||
u16 pid;
|
||||
int ret;
|
||||
|
||||
int num_dip = 0;
|
||||
|
||||
sunxi_gpio_set_pull(SUNXI_GPD(2), SUNXI_GPIO_PULL_UP);
|
||||
|
||||
ret = w1_get_bus(0, &bus);
|
||||
if (ret) {
|
||||
printf("one wire interface not found\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for_each_w1_device(bus, &dev) {
|
||||
if (w1_get_device_family(dev) != W1_FAMILY_DS2431)
|
||||
continue;
|
||||
|
||||
ret = device_probe(dev);
|
||||
if (ret) {
|
||||
printf("Couldn't probe device %s: error %d",
|
||||
dev->name, ret);
|
||||
continue;
|
||||
}
|
||||
|
||||
w1_eeprom_read_buf(dev, 0, (u8 *)&w1_header, sizeof(w1_header));
|
||||
|
||||
if (w1_header.magic != DIP_MAGIC)
|
||||
continue;
|
||||
|
||||
vid = dip_convert(w1_header.vendor_id);
|
||||
pid = dip_convert(w1_header.product_id);
|
||||
|
||||
printf("DIP: %s (0x%x) from %s (0x%x)\n",
|
||||
w1_header.product_name, pid,
|
||||
w1_header.vendor_name, vid);
|
||||
|
||||
dip = calloc(1, sizeof(struct extension));
|
||||
if (!dip) {
|
||||
printf("Error in memory allocation\n");
|
||||
return num_dip;
|
||||
}
|
||||
|
||||
snprintf(dip->overlay, sizeof(dip->overlay), "dip-%x-%x.dtbo",
|
||||
vid, pid);
|
||||
strncpy(dip->name, w1_header.product_name, 32);
|
||||
strncpy(dip->owner, w1_header.vendor_name, 32);
|
||||
list_add_tail(&dip->list, extension_list);
|
||||
num_dip++;
|
||||
}
|
||||
return num_dip;
|
||||
}
|
|
@ -44,6 +44,7 @@
|
|||
#include <env_internal.h>
|
||||
#include <watchdog.h>
|
||||
#include "../common/board_detect.h"
|
||||
#include "../common/cape_detect.h"
|
||||
#include "board.h"
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
@ -77,8 +78,10 @@ static struct ctrl_dev *cdev = (struct ctrl_dev *)CTRL_DEVICE_BASE;
|
|||
void do_board_detect(void)
|
||||
{
|
||||
enable_i2c0_pin_mux();
|
||||
enable_i2c2_pin_mux();
|
||||
#if !CONFIG_IS_ENABLED(DM_I2C)
|
||||
i2c_init(CONFIG_SYS_OMAP24_I2C_SPEED, CONFIG_SYS_OMAP24_I2C_SLAVE);
|
||||
i2c_init(CONFIG_SYS_OMAP24_I2C_SPEED2, CONFIG_SYS_OMAP24_I2C_SLAVE2);
|
||||
#endif
|
||||
if (ti_i2c_eeprom_am_get(CONFIG_EEPROM_BUS_ADDRESS,
|
||||
CONFIG_EEPROM_CHIP_ADDRESS))
|
||||
|
|
|
@ -93,5 +93,6 @@ void enable_uart3_pin_mux(void);
|
|||
void enable_uart4_pin_mux(void);
|
||||
void enable_uart5_pin_mux(void);
|
||||
void enable_i2c0_pin_mux(void);
|
||||
void enable_i2c2_pin_mux(void);
|
||||
void enable_board_pin_mux(void);
|
||||
#endif
|
||||
|
|
|
@ -124,6 +124,14 @@ static struct module_pin_mux i2c1_pin_mux[] = {
|
|||
{-1},
|
||||
};
|
||||
|
||||
static struct module_pin_mux i2c2_pin_mux[] = {
|
||||
{OFFSET(uart1_ctsn), (MODE(3) | RXACTIVE |
|
||||
PULLUDEN | PULLUP_EN | SLEWCTRL)}, /* I2C_DATA */
|
||||
{OFFSET(uart1_rtsn), (MODE(3) | RXACTIVE |
|
||||
PULLUDEN | PULLUP_EN | SLEWCTRL)}, /* I2C_SCLK */
|
||||
{-1},
|
||||
};
|
||||
|
||||
static struct module_pin_mux spi0_pin_mux[] = {
|
||||
{OFFSET(spi0_sclk), (MODE(0) | RXACTIVE | PULLUDEN)}, /* SPI0_SCLK */
|
||||
{OFFSET(spi0_d0), (MODE(0) | RXACTIVE |
|
||||
|
@ -308,6 +316,11 @@ void enable_i2c0_pin_mux(void)
|
|||
configure_module_pin_mux(i2c0_pin_mux);
|
||||
}
|
||||
|
||||
void enable_i2c2_pin_mux(void)
|
||||
{
|
||||
configure_module_pin_mux(i2c2_pin_mux);
|
||||
}
|
||||
|
||||
/*
|
||||
* The AM335x GP EVM, if daughter card(s) are connected, can have 8
|
||||
* different profiles. These profiles determine what peripherals are
|
||||
|
@ -367,6 +380,7 @@ void enable_board_pin_mux(void)
|
|||
#else
|
||||
configure_module_pin_mux(mmc1_pin_mux);
|
||||
#endif
|
||||
configure_module_pin_mux(i2c2_pin_mux);
|
||||
} else if (board_is_gp_evm()) {
|
||||
/* General Purpose EVM */
|
||||
unsigned short profile = detect_daughter_board_profile();
|
||||
|
@ -411,6 +425,7 @@ void enable_board_pin_mux(void)
|
|||
#else
|
||||
configure_module_pin_mux(mmc1_pin_mux);
|
||||
#endif
|
||||
configure_module_pin_mux(i2c2_pin_mux);
|
||||
} else if (board_is_pb()) {
|
||||
configure_module_pin_mux(mii1_pin_mux);
|
||||
configure_module_pin_mux(mmc0_pin_mux);
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include <hang.h>
|
||||
|
||||
#include "../common/board_detect.h"
|
||||
#include "../common/cape_detect.h"
|
||||
#include "mux_data.h"
|
||||
|
||||
#ifdef CONFIG_SUPPORT_EMMC_BOOT
|
||||
|
|
|
@ -16,6 +16,12 @@ config EEPROM_CHIP_ADDRESS
|
|||
default 0x50
|
||||
depends on TI_I2C_BOARD_DETECT
|
||||
|
||||
config CAPE_EEPROM_BUS_NUM
|
||||
int "Cape EEPROM's I2C bus address"
|
||||
range 0 8
|
||||
default 2
|
||||
depends on CMD_EXTENSION
|
||||
|
||||
config TI_COMMON_CMD_OPTIONS
|
||||
bool "Enable cmd options on TI platforms"
|
||||
imply CMD_ASKENV
|
||||
|
|
|
@ -2,3 +2,4 @@
|
|||
# Copyright (C) 2015-2016 Texas Instruments Incorporated - http://www.ti.com/
|
||||
|
||||
obj-${CONFIG_TI_I2C_BOARD_DETECT} += board_detect.o
|
||||
obj-${CONFIG_CMD_EXTENSION} += cape_detect.o
|
||||
|
|
96
board/ti/common/cape_detect.c
Normal file
96
board/ti/common/cape_detect.c
Normal file
|
@ -0,0 +1,96 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2021
|
||||
* Köry Maincent, Bootlin, <kory.maincent@bootlin.com>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <malloc.h>
|
||||
#include <i2c.h>
|
||||
#include <extension_board.h>
|
||||
|
||||
#include "cape_detect.h"
|
||||
|
||||
static void sanitize_field(char *text, size_t size)
|
||||
{
|
||||
char *c = NULL;
|
||||
|
||||
for (c = text; c < text + (int)size; c++) {
|
||||
if (*c == 0xFF)
|
||||
*c = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int extension_board_scan(struct list_head *extension_list)
|
||||
{
|
||||
struct extension *cape;
|
||||
struct am335x_cape_eeprom_id eeprom_header;
|
||||
|
||||
int num_capes = 0;
|
||||
int ret, i;
|
||||
struct udevice *dev;
|
||||
unsigned char addr;
|
||||
|
||||
char process_cape_part_number[17] = {'0'};
|
||||
char process_cape_version[5] = {'0'};
|
||||
uint8_t cursor = 0;
|
||||
|
||||
for (addr = CAPE_EEPROM_FIRST_ADDR; addr <= CAPE_EEPROM_LAST_ADDR; addr++) {
|
||||
ret = i2c_get_chip_for_busnum(CONFIG_CAPE_EEPROM_BUS_NUM, addr, 1, &dev);
|
||||
if (ret)
|
||||
continue;
|
||||
|
||||
/* Move the read cursor to the beginning of the EEPROM */
|
||||
dm_i2c_write(dev, 0, &cursor, 1);
|
||||
ret = dm_i2c_read(dev, 0, (uint8_t *)&eeprom_header,
|
||||
sizeof(struct am335x_cape_eeprom_id));
|
||||
if (ret) {
|
||||
printf("Cannot read i2c EEPROM\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (eeprom_header.header != CAPE_MAGIC)
|
||||
continue;
|
||||
|
||||
sanitize_field(eeprom_header.board_name, sizeof(eeprom_header.board_name));
|
||||
sanitize_field(eeprom_header.version, sizeof(eeprom_header.version));
|
||||
sanitize_field(eeprom_header.manufacturer, sizeof(eeprom_header.manufacturer));
|
||||
sanitize_field(eeprom_header.part_number, sizeof(eeprom_header.part_number));
|
||||
|
||||
/* Process cape part_number */
|
||||
memset(process_cape_part_number, 0, sizeof(process_cape_part_number));
|
||||
strncpy(process_cape_part_number, eeprom_header.part_number, 16);
|
||||
/* Some capes end with '.' */
|
||||
for (i = 15; i >= 0; i--) {
|
||||
if (process_cape_part_number[i] == '.')
|
||||
process_cape_part_number[i] = '\0';
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
/* Process cape version */
|
||||
memset(process_cape_version, 0, sizeof(process_cape_version));
|
||||
strncpy(process_cape_version, eeprom_header.version, 4);
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (process_cape_version[i] == 0)
|
||||
process_cape_version[i] = '0';
|
||||
}
|
||||
|
||||
printf("BeagleBone Cape: %s (0x%x)\n", eeprom_header.board_name, addr);
|
||||
|
||||
cape = calloc(1, sizeof(struct extension));
|
||||
if (!cape) {
|
||||
printf("Error in memory allocation\n");
|
||||
return num_capes;
|
||||
}
|
||||
|
||||
snprintf(cape->overlay, sizeof(cape->overlay), "%s-%s.dtbo",
|
||||
process_cape_part_number, process_cape_version);
|
||||
strncpy(cape->name, eeprom_header.board_name, 32);
|
||||
strncpy(cape->version, process_cape_version, 4);
|
||||
strncpy(cape->owner, eeprom_header.manufacturer, 16);
|
||||
list_add_tail(&cape->list, extension_list);
|
||||
num_capes++;
|
||||
}
|
||||
return num_capes;
|
||||
}
|
28
board/ti/common/cape_detect.h
Normal file
28
board/ti/common/cape_detect.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* (C) Copyright 2021
|
||||
* Köry Maincent, Bootlin, <kory.maincent@bootlin.com>
|
||||
*/
|
||||
|
||||
#ifndef __CAPE_DETECT_H
|
||||
#define __CAPE_DETECT_H
|
||||
|
||||
struct am335x_cape_eeprom_id {
|
||||
unsigned int header;
|
||||
char eeprom_rev[2];
|
||||
char board_name[32];
|
||||
char version[4];
|
||||
char manufacturer[16];
|
||||
char part_number[16];
|
||||
};
|
||||
|
||||
#define CAPE_EEPROM_FIRST_ADDR 0x54
|
||||
#define CAPE_EEPROM_LAST_ADDR 0x57
|
||||
|
||||
#define CAPE_EEPROM_ADDR_LEN 0x10
|
||||
|
||||
#define CAPE_MAGIC 0xEE3355AA
|
||||
|
||||
int extension_board_scan(struct list_head *extension_list);
|
||||
|
||||
#endif /* __CAPE_DETECT_H */
|
12
cmd/Kconfig
12
cmd/Kconfig
|
@ -332,6 +332,18 @@ config CMD_FDT
|
|||
help
|
||||
Do FDT related setup before booting into the Operating System.
|
||||
|
||||
config SUPPORT_EXTENSION_SCAN
|
||||
bool
|
||||
|
||||
config CMD_EXTENSION
|
||||
bool "Extension board management command"
|
||||
select CMD_FDT
|
||||
depends on SUPPORT_EXTENSION_SCAN
|
||||
help
|
||||
Enables the "extension" command, which allows to detect
|
||||
extension boards connected to the system, and apply
|
||||
corresponding Device Tree overlays.
|
||||
|
||||
config CMD_GO
|
||||
bool "go"
|
||||
default y
|
||||
|
|
|
@ -54,6 +54,7 @@ obj-$(CONFIG_CMD_DIAG) += diag.o
|
|||
endif
|
||||
obj-$(CONFIG_CMD_ADTIMG) += adtimg.o
|
||||
obj-$(CONFIG_CMD_ABOOTIMG) += abootimg.o
|
||||
obj-$(CONFIG_CMD_EXTENSION) += extension_board.o
|
||||
obj-$(CONFIG_CMD_ECHO) += echo.o
|
||||
obj-$(CONFIG_ENV_IS_IN_EEPROM) += eeprom.o
|
||||
obj-$(CONFIG_CMD_EEPROM) += eeprom.o
|
||||
|
|
167
cmd/extension_board.c
Normal file
167
cmd/extension_board.c
Normal file
|
@ -0,0 +1,167 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2021
|
||||
* Köry Maincent, Bootlin, <kory.maincent@bootlin.com>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <malloc.h>
|
||||
#include <extension_board.h>
|
||||
#include <mapmem.h>
|
||||
#include <linux/libfdt.h>
|
||||
#include <fdt_support.h>
|
||||
|
||||
static LIST_HEAD(extension_list);
|
||||
|
||||
static int extension_apply(struct extension *extension)
|
||||
{
|
||||
char *overlay_cmd;
|
||||
ulong extrasize, overlay_addr;
|
||||
struct fdt_header *blob;
|
||||
|
||||
if (!working_fdt) {
|
||||
printf("No FDT memory address configured. Please configure\n"
|
||||
"the FDT address via \"fdt addr <address>\" command.\n");
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
overlay_cmd = env_get("extension_overlay_cmd");
|
||||
if (!overlay_cmd) {
|
||||
printf("Environment extension_overlay_cmd is missing\n");
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
overlay_addr = env_get_hex("extension_overlay_addr", 0);
|
||||
if (!overlay_addr) {
|
||||
printf("Environment extension_overlay_addr is missing\n");
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
env_set("extension_overlay_name", extension->overlay);
|
||||
if (run_command(overlay_cmd, 0) != 0)
|
||||
return CMD_RET_FAILURE;
|
||||
|
||||
extrasize = env_get_hex("filesize", 0);
|
||||
if (!extrasize)
|
||||
return CMD_RET_FAILURE;
|
||||
|
||||
fdt_shrink_to_minimum(working_fdt, extrasize);
|
||||
|
||||
blob = map_sysmem(overlay_addr, 0);
|
||||
if (!fdt_valid(&blob))
|
||||
return CMD_RET_FAILURE;
|
||||
|
||||
/* apply method prints messages on error */
|
||||
if (fdt_overlay_apply_verbose(working_fdt, blob))
|
||||
return CMD_RET_FAILURE;
|
||||
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
static int do_extension_list(struct cmd_tbl *cmdtp, int flag,
|
||||
int argc, char *const argv[])
|
||||
{
|
||||
int i = 0;
|
||||
struct extension *extension;
|
||||
|
||||
if (list_empty(&extension_list)) {
|
||||
printf("No extension registered - Please run \"extension scan\"\n");
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
list_for_each_entry(extension, &extension_list, list) {
|
||||
printf("Extension %d: %s\n", i++, extension->name);
|
||||
printf("\tManufacturer: \t\t%s\n", extension->owner);
|
||||
printf("\tVersion: \t\t%s\n", extension->version);
|
||||
printf("\tDevicetree overlay: \t%s\n", extension->overlay);
|
||||
printf("\tOther information: \t%s\n", extension->other);
|
||||
}
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
static int do_extension_scan(struct cmd_tbl *cmdtp, int flag,
|
||||
int argc, char *const argv[])
|
||||
{
|
||||
struct extension *extension, *next;
|
||||
int extension_num;
|
||||
|
||||
list_for_each_entry_safe(extension, next, &extension_list, list) {
|
||||
list_del(&extension->list);
|
||||
free(extension);
|
||||
}
|
||||
extension_num = extension_board_scan(&extension_list);
|
||||
|
||||
if (extension_num < 0)
|
||||
return CMD_RET_FAILURE;
|
||||
|
||||
printf("Found %d extension board(s).\n", extension_num);
|
||||
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
static int do_extension_apply(struct cmd_tbl *cmdtp, int flag,
|
||||
int argc, char *const argv[])
|
||||
{
|
||||
struct extension *extension = NULL;
|
||||
struct list_head *entry;
|
||||
int i = 0, extension_id, ret;
|
||||
|
||||
if (argc < 2)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
if (strcmp(argv[1], "all") == 0) {
|
||||
list_for_each_entry(extension, &extension_list, list) {
|
||||
ret = extension_apply(extension);
|
||||
if (ret != CMD_RET_SUCCESS)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
extension_id = simple_strtol(argv[1], NULL, 10);
|
||||
list_for_each(entry, &extension_list) {
|
||||
if (i == extension_id) {
|
||||
extension = list_entry(entry, struct extension, list);
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if (!extension) {
|
||||
printf("Wrong extension number\n");
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
ret = extension_apply(extension);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct cmd_tbl cmd_extension[] = {
|
||||
U_BOOT_CMD_MKENT(scan, 1, 1, do_extension_scan, "", ""),
|
||||
U_BOOT_CMD_MKENT(list, 1, 0, do_extension_list, "", ""),
|
||||
U_BOOT_CMD_MKENT(apply, 2, 0, do_extension_apply, "", ""),
|
||||
};
|
||||
|
||||
static int do_extensionops(struct cmd_tbl *cmdtp, int flag, int argc,
|
||||
char *const argv[])
|
||||
{
|
||||
struct cmd_tbl *cp;
|
||||
|
||||
/* Drop the extension command */
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
cp = find_cmd_tbl(argv[0], cmd_extension, ARRAY_SIZE(cmd_extension));
|
||||
if (cp)
|
||||
return cp->cmd(cmdtp, flag, argc, argv);
|
||||
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(extension, 3, 1, do_extensionops,
|
||||
"Extension board management sub system",
|
||||
"scan - scan plugged extension(s) board(s)\n"
|
||||
"extension list - lists available extension(s) board(s)\n"
|
||||
"extension apply <extension number|all> - applies DT overlays corresponding to extension boards\n"
|
||||
);
|
49
cmd/fdt.c
49
cmd/fdt.c
|
@ -27,7 +27,6 @@
|
|||
*/
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
static int fdt_valid(struct fdt_header **blobp);
|
||||
static int fdt_parse_prop(char *const*newval, int count, char *data, int *len);
|
||||
static int fdt_print(const char *pathp, char *prop, int depth);
|
||||
static int is_printable_string(const void *data, int len);
|
||||
|
@ -732,54 +731,6 @@ static int do_fdt(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
|||
|
||||
/****************************************************************************/
|
||||
|
||||
/**
|
||||
* fdt_valid() - Check if an FDT is valid. If not, change it to NULL
|
||||
*
|
||||
* @blobp: Pointer to FDT pointer
|
||||
* @return 1 if OK, 0 if bad (in which case *blobp is set to NULL)
|
||||
*/
|
||||
static int fdt_valid(struct fdt_header **blobp)
|
||||
{
|
||||
const void *blob = *blobp;
|
||||
int err;
|
||||
|
||||
if (blob == NULL) {
|
||||
printf ("The address of the fdt is invalid (NULL).\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = fdt_check_header(blob);
|
||||
if (err == 0)
|
||||
return 1; /* valid */
|
||||
|
||||
if (err < 0) {
|
||||
printf("libfdt fdt_check_header(): %s", fdt_strerror(err));
|
||||
/*
|
||||
* Be more informative on bad version.
|
||||
*/
|
||||
if (err == -FDT_ERR_BADVERSION) {
|
||||
if (fdt_version(blob) <
|
||||
FDT_FIRST_SUPPORTED_VERSION) {
|
||||
printf (" - too old, fdt %d < %d",
|
||||
fdt_version(blob),
|
||||
FDT_FIRST_SUPPORTED_VERSION);
|
||||
}
|
||||
if (fdt_last_comp_version(blob) >
|
||||
FDT_LAST_SUPPORTED_VERSION) {
|
||||
printf (" - too new, fdt %d > %d",
|
||||
fdt_version(blob),
|
||||
FDT_LAST_SUPPORTED_VERSION);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
*blobp = NULL;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/*
|
||||
* Parse the user's input, partially heuristic. Valid formats:
|
||||
* <0x00112233 4 05> - an array of cells. Numbers follow standard
|
||||
|
|
|
@ -1904,3 +1904,49 @@ int fdt_overlay_apply_verbose(void *fdt, void *fdto)
|
|||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* fdt_valid() - Check if an FDT is valid. If not, change it to NULL
|
||||
*
|
||||
* @blobp: Pointer to FDT pointer
|
||||
* @return 1 if OK, 0 if bad (in which case *blobp is set to NULL)
|
||||
*/
|
||||
int fdt_valid(struct fdt_header **blobp)
|
||||
{
|
||||
const void *blob = *blobp;
|
||||
int err;
|
||||
|
||||
if (!blob) {
|
||||
printf("The address of the fdt is invalid (NULL).\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = fdt_check_header(blob);
|
||||
if (err == 0)
|
||||
return 1; /* valid */
|
||||
|
||||
if (err < 0) {
|
||||
printf("libfdt fdt_check_header(): %s", fdt_strerror(err));
|
||||
/*
|
||||
* Be more informative on bad version.
|
||||
*/
|
||||
if (err == -FDT_ERR_BADVERSION) {
|
||||
if (fdt_version(blob) <
|
||||
FDT_FIRST_SUPPORTED_VERSION) {
|
||||
printf(" - too old, fdt %d < %d",
|
||||
fdt_version(blob),
|
||||
FDT_FIRST_SUPPORTED_VERSION);
|
||||
}
|
||||
if (fdt_last_comp_version(blob) >
|
||||
FDT_LAST_SUPPORTED_VERSION) {
|
||||
printf(" - too new, fdt %d > %d",
|
||||
fdt_version(blob),
|
||||
FDT_LAST_SUPPORTED_VERSION);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
*blobp = NULL;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
CONFIG_ARM=y
|
||||
CONFIG_ARCH_SUNXI=y
|
||||
CONFIG_SPL=y
|
||||
CONFIG_CHIP_DIP_SCAN=y
|
||||
CONFIG_MACH_SUN5I=y
|
||||
CONFIG_DRAM_TIMINGS_DDR3_800E_1066G_1333J=y
|
||||
CONFIG_USB0_VBUS_PIN="PB10"
|
||||
|
|
|
@ -8,6 +8,7 @@ CONFIG_MISC_INIT_F=y
|
|||
# CONFIG_CMD_BOOTD is not set
|
||||
# CONFIG_CMD_BOOTM is not set
|
||||
# CONFIG_CMD_ELF is not set
|
||||
# CONFIG_CMD_EXTENSION is not set
|
||||
CONFIG_BOOTP_DNS2=y
|
||||
# CONFIG_CMD_DATE is not set
|
||||
CONFIG_OF_CONTROL=y
|
||||
|
|
111
doc/usage/extension.rst
Normal file
111
doc/usage/extension.rst
Normal file
|
@ -0,0 +1,111 @@
|
|||
.. SPDX-License-Identifier: GPL-2.0+
|
||||
.. Copyright 2021, Kory Maincent <kory.maincent@bootlin.com>
|
||||
|
||||
U-Boot extension board usage (CONFIG_EXTENSION)
|
||||
===============================================
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
|
||||
::
|
||||
|
||||
extension scan
|
||||
extension list
|
||||
extension apply <extension number|all>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The "extension" command proposes a generic U-Boot mechanism to detect
|
||||
extension boards connected to the HW platform, and apply the appropriate
|
||||
Device Tree overlays depending on the detected extension boards.
|
||||
|
||||
The "extension" command comes with three sub-commands:
|
||||
|
||||
- "extension scan" makes the generic code call the board-specific
|
||||
extension_board_scan() function to retrieve the list of detected
|
||||
extension boards.
|
||||
|
||||
- "extension list" allows to list the detected extension boards.
|
||||
|
||||
- "extension apply <number>|all" allows to apply the Device Tree
|
||||
overlay(s) corresponding to one, or all, extension boards
|
||||
|
||||
The latter requires two environment variables to exist:
|
||||
|
||||
- extension_overlay_addr: the RAM address where to load the Device
|
||||
Tree overlays
|
||||
|
||||
- extension_overlay_cmd: the U-Boot command to load one overlay.
|
||||
Indeed, the location and mechanism to load DT overlays is very setup
|
||||
specific.
|
||||
|
||||
In order to enable this mechanism, board-specific code must implement
|
||||
the extension_board_scan() function that fills in a linked list of
|
||||
"struct extension", each describing one extension board. In addition,
|
||||
the board-specific code must select the SUPPORT_EXTENSION_SCAN Kconfig
|
||||
boolean.
|
||||
|
||||
Usage example
|
||||
-------------
|
||||
|
||||
1. Make sure your devicetree is loaded and set as the working fdt tree.
|
||||
|
||||
::
|
||||
|
||||
=> run loadfdt
|
||||
=> fdt addr $fdtaddr
|
||||
|
||||
2. Prepare the environment variables
|
||||
|
||||
::
|
||||
|
||||
=> setenv extension_overlay_addr 0x88080000
|
||||
=> setenv extension_overlay_cmd 'load mmc 0:1 ${extension_overlay_addr} /boot/${extension_overlay_name}'
|
||||
|
||||
3. Detect the plugged extension board
|
||||
|
||||
::
|
||||
|
||||
=> extension scan
|
||||
|
||||
4. List the plugged extension board information and the devicetree
|
||||
overlay name
|
||||
|
||||
::
|
||||
|
||||
=> extension list
|
||||
|
||||
5. Apply the appropriate devicetree overlay
|
||||
|
||||
For apply the selected overlay:
|
||||
|
||||
::
|
||||
|
||||
=> extension apply 0
|
||||
|
||||
For apply all the overlays:
|
||||
|
||||
::
|
||||
|
||||
=> extension apply all
|
||||
|
||||
Simple extension_board_scan function example
|
||||
--------------------------------------------
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
int extension_board_scan(struct list_head *extension_list)
|
||||
{
|
||||
struct extension *extension;
|
||||
|
||||
extension = calloc(1, sizeof(struct extension));
|
||||
snprintf(extension->overlay, sizeof(extension->overlay), "overlay.dtbo");
|
||||
snprintf(extension->name, sizeof(extension->name), "extension board");
|
||||
snprintf(extension->owner, sizeof(extension->owner), "sandbox");
|
||||
snprintf(extension->version, sizeof(extension->version), "1.1");
|
||||
snprintf(extension->other, sizeof(extension->other), "Extension board information");
|
||||
list_add_tail(&extension->list, extension_list);
|
||||
|
||||
return 1;
|
||||
}
|
|
@ -53,3 +53,10 @@ U_BOOT_DRIVER(ds24xxx) = {
|
|||
.ops = &ds24xxx_ops,
|
||||
.probe = ds24xxx_probe,
|
||||
};
|
||||
|
||||
u8 family_supported[] = {
|
||||
W1_FAMILY_DS24B33,
|
||||
W1_FAMILY_DS2431,
|
||||
};
|
||||
|
||||
U_BOOT_W1_DEVICE(ds24xxx, family_supported);
|
||||
|
|
|
@ -243,3 +243,9 @@ U_BOOT_DRIVER(ds2502) = {
|
|||
.ops = &ds2502_ops,
|
||||
.probe = ds2502_probe,
|
||||
};
|
||||
|
||||
u8 family_supported[] = {
|
||||
W1_FAMILY_DS2502,
|
||||
};
|
||||
|
||||
U_BOOT_W1_DEVICE(ds2502, family_supported);
|
||||
|
|
|
@ -37,37 +37,6 @@ int w1_eeprom_read_buf(struct udevice *dev, unsigned int offset,
|
|||
return ops->read_buf(dev, offset, buf, count);
|
||||
}
|
||||
|
||||
int w1_eeprom_register_new_device(u64 id)
|
||||
{
|
||||
u8 family = id & 0xff;
|
||||
int ret;
|
||||
struct udevice *dev;
|
||||
|
||||
for (ret = uclass_first_device(UCLASS_W1_EEPROM, &dev);
|
||||
!ret && dev;
|
||||
uclass_next_device(&dev)) {
|
||||
if (ret || !dev) {
|
||||
debug("cannot find w1 eeprom dev\n");
|
||||
return ret;
|
||||
}
|
||||
if (dev_get_driver_data(dev) == family) {
|
||||
struct w1_device *w1;
|
||||
|
||||
w1 = dev_get_parent_plat(dev);
|
||||
if (w1->id) /* device already in use */
|
||||
continue;
|
||||
w1->id = id;
|
||||
debug("%s: Match found: %s:%s %llx\n", __func__,
|
||||
dev->name, dev->driver->name, id);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
debug("%s: No matches found: error %d\n", __func__, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int w1_eeprom_get_id(struct udevice *dev, u64 *id)
|
||||
{
|
||||
struct w1_device *w1 = dev_get_parent_plat(dev);
|
||||
|
|
|
@ -4,9 +4,11 @@
|
|||
* Copyright (c) 2015 Free Electrons
|
||||
* Copyright (c) 2015 NextThing Co.
|
||||
* Copyright (c) 2018 Microchip Technology, Inc.
|
||||
* Copyright (c) 2021 Bootlin
|
||||
*
|
||||
* Maxime Ripard <maxime.ripard@free-electrons.com>
|
||||
* Eugen Hristev <eugen.hristev@microchip.com>
|
||||
* Kory Maincent <kory.maincent@bootlin.com>
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -26,6 +28,76 @@ struct w1_bus {
|
|||
u64 search_id;
|
||||
};
|
||||
|
||||
int w1_bus_find_dev(const struct udevice *bus, u64 id, struct udevice
|
||||
**devp)
|
||||
{
|
||||
struct udevice *dev;
|
||||
u8 family = id & 0xff;
|
||||
int ret;
|
||||
|
||||
for (ret = uclass_first_device(UCLASS_W1_EEPROM, &dev);
|
||||
!ret && dev;
|
||||
uclass_next_device(&dev)) {
|
||||
if (ret || !dev) {
|
||||
debug("cannot find w1 eeprom dev\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (dev_get_driver_data(dev) == family) {
|
||||
*devp = dev;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int w1_register_new_device(u64 id, struct udevice *bus)
|
||||
{
|
||||
u8 family = id & 0xff;
|
||||
int n_ents, ret = 0;
|
||||
struct udevice *dev;
|
||||
|
||||
struct w1_driver_entry *start, *entry;
|
||||
|
||||
start = ll_entry_start(struct w1_driver_entry, w1_driver_entry);
|
||||
n_ents = ll_entry_count(struct w1_driver_entry, w1_driver_entry);
|
||||
|
||||
for (entry = start; entry != start + n_ents; entry++) {
|
||||
const u8 *match_family;
|
||||
const struct driver *drv;
|
||||
struct w1_device *w1;
|
||||
|
||||
for (match_family = entry->family; match_family;
|
||||
match_family++) {
|
||||
if (*match_family != family)
|
||||
continue;
|
||||
|
||||
ret = w1_bus_find_dev(bus, id, &dev);
|
||||
|
||||
/* If nothing in the device tree, bind a device */
|
||||
if (ret == -ENODEV) {
|
||||
drv = entry->driver;
|
||||
ret = device_bind(bus, drv, drv->name,
|
||||
NULL, ofnode_null(), &dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
device_probe(dev);
|
||||
|
||||
w1 = dev_get_parent_plat(dev);
|
||||
w1->id = id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
debug("%s: No matches found: error %d\n", __func__, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int w1_enumerate(struct udevice *bus)
|
||||
{
|
||||
const struct w1_ops *ops = device_get_ops(bus);
|
||||
|
@ -97,8 +169,8 @@ static int w1_enumerate(struct udevice *bus)
|
|||
debug("%s: Detected new device 0x%llx (family 0x%x)\n",
|
||||
bus->name, rn, (u8)(rn & 0xff));
|
||||
|
||||
/* attempt to register as w1-eeprom device */
|
||||
w1_eeprom_register_new_device(rn);
|
||||
/* attempt to register as w1 device */
|
||||
w1_register_new_device(rn, bus);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
31
include/extension_board.h
Normal file
31
include/extension_board.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* (C) Copyright 2021
|
||||
* Köry Maincent, Bootlin, <kory.maincent@bootlin.com>
|
||||
*/
|
||||
|
||||
#ifndef __EXTENSION_SUPPORT_H
|
||||
#define __EXTENSION_SUPPORT_H
|
||||
|
||||
struct extension {
|
||||
struct list_head list;
|
||||
char name[32];
|
||||
char owner[32];
|
||||
char version[32];
|
||||
char overlay[32];
|
||||
char other[32];
|
||||
};
|
||||
|
||||
/**
|
||||
* extension_board_scan - Add system-specific function to scan extension board.
|
||||
* @param extension_list List of extension board information to update.
|
||||
* @return the number of extension.
|
||||
*
|
||||
* This function is called if CONFIG_CMD_EXTENSION is defined.
|
||||
* Needs to fill the list extension_list with elements.
|
||||
* Each element need to be allocated to an extension structure.
|
||||
*
|
||||
*/
|
||||
int extension_board_scan(struct list_head *extension_list);
|
||||
|
||||
#endif /* __EXTENSION_SUPPORT_H */
|
|
@ -352,6 +352,8 @@ int fdt_setup_simplefb_node(void *fdt, int node, u64 base_address, u32 width,
|
|||
|
||||
int fdt_overlay_apply_verbose(void *fdt, void *fdto);
|
||||
|
||||
int fdt_valid(struct fdt_header **blobp);
|
||||
|
||||
/**
|
||||
* fdt_get_cells_len() - Get the length of a type of cell in top-level nodes
|
||||
*
|
||||
|
|
|
@ -27,7 +27,5 @@ int w1_eeprom_read_buf(struct udevice *dev, unsigned int offset,
|
|||
|
||||
int w1_eeprom_dm_init(void);
|
||||
|
||||
int w1_eeprom_register_new_device(u64 id);
|
||||
|
||||
int w1_eeprom_get_id(struct udevice *dev, u64 *id);
|
||||
#endif
|
||||
|
|
17
include/w1.h
17
include/w1.h
|
@ -15,6 +15,23 @@ struct udevice;
|
|||
#define W1_FAMILY_DS2502 0x09
|
||||
#define W1_FAMILY_EEP_SANDBOX 0xfe
|
||||
|
||||
struct w1_driver_entry {
|
||||
struct driver *driver;
|
||||
u8 *family;
|
||||
};
|
||||
|
||||
/* U_BOOT_W1_DEVICE() tells U-Boot to create a one-wire device.
|
||||
*
|
||||
* @__name: Device name (C identifier, not a string. E.g. gpio7_at_ff7e0000)
|
||||
* @__driver: Driver name (C identifier, not a string. E.g. gpio7_at_ff7e0000)
|
||||
* @__family: Family code number of the one-wire
|
||||
*/
|
||||
#define U_BOOT_W1_DEVICE(__name, __family) \
|
||||
ll_entry_declare(struct w1_driver_entry, __name, w1_driver_entry) = { \
|
||||
.driver = llsym(struct driver, __name, driver), \
|
||||
.family = __family, \
|
||||
}
|
||||
|
||||
struct w1_device {
|
||||
u64 id;
|
||||
};
|
||||
|
|
53
test/py/tests/test_extension.py
Normal file
53
test/py/tests/test_extension.py
Normal file
|
@ -0,0 +1,53 @@
|
|||
# SPDX-License-Identifier: GPL-2.0+
|
||||
# Copyright (c) 2020
|
||||
# Author: Kory Maincent <kory.maincent@bootlin.com>
|
||||
|
||||
# Test U-Boot's "extension" commands.
|
||||
|
||||
import os
|
||||
import pytest
|
||||
import u_boot_utils
|
||||
|
||||
overlay_addr = 0x1000
|
||||
|
||||
SANDBOX_DTB='arch/sandbox/dts/sandbox.dtb'
|
||||
OVERLAY_DIR='arch/sandbox/dts/'
|
||||
|
||||
def load_dtb(u_boot_console):
|
||||
u_boot_console.log.action('Loading devicetree to RAM...')
|
||||
u_boot_console.run_command('host load hostfs - $fdt_addr_r %s' % (os.path.join(u_boot_console.config.build_dir, SANDBOX_DTB)))
|
||||
u_boot_console.run_command('fdt addr $fdt_addr_r')
|
||||
|
||||
@pytest.mark.buildconfigspec('cmd_fdt')
|
||||
@pytest.mark.boardspec('sandbox')
|
||||
def test_extension(u_boot_console):
|
||||
"""Test the 'extension' command."""
|
||||
|
||||
load_dtb(u_boot_console)
|
||||
|
||||
output = u_boot_console.run_command('extension list')
|
||||
assert('No extension' in output)
|
||||
|
||||
output = u_boot_console.run_command('extension scan')
|
||||
assert output == 'Found 2 extension board(s).'
|
||||
|
||||
output = u_boot_console.run_command('extension list')
|
||||
assert('overlay0.dtbo' in output)
|
||||
assert('overlay1.dtbo' in output)
|
||||
|
||||
u_boot_console.run_command_list([
|
||||
'setenv extension_overlay_addr %s' % (overlay_addr),
|
||||
'setenv extension_overlay_cmd \'host load hostfs - ${extension_overlay_addr} %s${extension_overlay_name}\'' % (os.path.join(u_boot_console.config.build_dir, OVERLAY_DIR))])
|
||||
|
||||
output = u_boot_console.run_command('extension apply 0')
|
||||
assert('bytes read' in output)
|
||||
|
||||
output = u_boot_console.run_command('fdt print')
|
||||
assert('button3' in output)
|
||||
|
||||
output = u_boot_console.run_command('extension apply all')
|
||||
assert('bytes read' in output)
|
||||
|
||||
output = u_boot_console.run_command('fdt print')
|
||||
assert('button4' in output)
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue