mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-10 23:24:38 +00:00
of-platdata and dtoc improvements
sandbox SPL tests binman support for compressed sections -----BEGIN PGP SIGNATURE----- iQFFBAABCgAvFiEEslwAIq+Gp8wWVbYnfxc6PpAIreYFAl+cXssRHHNqZ0BjaHJv bWl1bS5vcmcACgkQfxc6PpAIreaYuAgAjG05oxt8a4DXhdzGuXBCbehZv2T7X5Lg 2+i9uwyg3MkKWp0Spm2J+0flWs+1Bynw335hgNVgq+bh29sajOQz2BtgfDKFY+Aw D+D16YBEiEuIbIXLzSsv+ct1va83A3JmlxxoaJ7+ZvoN/5Z3ZvJIZ7F4AzmwlAFT 5pOFgDEfVM4MYFU4R2wZAaJMnYKQrqR5Tvrxecc6OkhvWIgq7j3elE4xOuh2hL/L Bz/KM+4Eq+EUALG+quyEzd+gDKoPY2rNOojxS/lg7PRsN6S8engwE+LkcAkMaNG3 uDVrTYsA8lCJJwso0in25fUy8sEYWaCSVr/82xfRJMWksPajubem7w== =9u1O -----END PGP SIGNATURE----- Merge tag 'dm-pull-30oct20' of https://gitlab.denx.de/u-boot/custodians/u-boot-dm of-platdata and dtoc improvements sandbox SPL tests binman support for compressed sections
This commit is contained in:
commit
63d4607e03
89 changed files with 1861 additions and 502 deletions
|
@ -182,7 +182,7 @@ jobs:
|
|||
OVERRIDE: "-O clang-10"
|
||||
sandbox_spl:
|
||||
TEST_PY_BD: "sandbox_spl"
|
||||
TEST_PY_TEST_SPEC: "test_ofplatdata or test_handoff"
|
||||
TEST_PY_TEST_SPEC: "test_ofplatdata or test_handoff or test_spl"
|
||||
sandbox_flattree:
|
||||
TEST_PY_BD: "sandbox_flattree"
|
||||
evb_ast2500:
|
||||
|
|
|
@ -198,7 +198,7 @@ sandbox_spl test.py:
|
|||
tags: [ 'all' ]
|
||||
variables:
|
||||
TEST_PY_BD: "sandbox_spl"
|
||||
TEST_PY_TEST_SPEC: "test_ofplatdata or test_handoff"
|
||||
TEST_PY_TEST_SPEC: "test_ofplatdata or test_handoff or test_spl"
|
||||
<<: *buildman_and_testpy_dfn
|
||||
|
||||
evb-ast2500 test.py:
|
||||
|
|
|
@ -512,7 +512,7 @@ matrix:
|
|||
- name: "test/py sandbox_spl"
|
||||
env:
|
||||
- TEST_PY_BD="sandbox_spl"
|
||||
TEST_PY_TEST_SPEC="test_ofplatdata or test_handoff"
|
||||
TEST_PY_TEST_SPEC="test_ofplatdata or test_handoff or test_spl"
|
||||
TOOLCHAIN="i386"
|
||||
TEST_PY_TOOLS="yes"
|
||||
- name: "test/py sandbox_flattree"
|
||||
|
|
2
Makefile
2
Makefile
|
@ -807,7 +807,7 @@ libs-$(CONFIG_API) += api/
|
|||
ifdef CONFIG_POST
|
||||
libs-y += post/
|
||||
endif
|
||||
libs-$(CONFIG_UNIT_TEST) += test/ test/dm/
|
||||
libs-$(CONFIG_UNIT_TEST) += test/
|
||||
libs-$(CONFIG_UT_ENV) += test/env/
|
||||
libs-$(CONFIG_UT_OPTEE) += test/optee/
|
||||
libs-$(CONFIG_UT_OVERLAY) += test/overlay/
|
||||
|
|
|
@ -34,7 +34,7 @@ struct scu_regs {
|
|||
u32 fpga_rev;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_IMX_THERMAL)
|
||||
#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_IMX_THERMAL)
|
||||
static const struct imx_thermal_plat imx6_thermal_plat = {
|
||||
.regs = (void *)ANATOP_BASE_ADDR,
|
||||
.fuse_bank = 1,
|
||||
|
|
|
@ -127,7 +127,8 @@ int sandbox_sdl_init_display(int width, int height, int log2_bpp,
|
|||
sdl.pitch = sdl.width * sdl.depth / 8;
|
||||
SDL_Window *screen = SDL_CreateWindow("U-Boot", SDL_WINDOWPOS_UNDEFINED,
|
||||
SDL_WINDOWPOS_UNDEFINED,
|
||||
sdl.vis_width, sdl.vis_height, 0);
|
||||
sdl.vis_width, sdl.vis_height,
|
||||
SDL_WINDOW_RESIZABLE);
|
||||
if (!screen) {
|
||||
printf("Unable to initialise SDL screen: %s\n",
|
||||
SDL_GetError());
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <spl.h>
|
||||
#include <asm/spl.h>
|
||||
#include <asm/state.h>
|
||||
#include <test/test.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
|
@ -53,19 +54,14 @@ SPL_LOAD_IMAGE_METHOD("sandbox", 9, BOOT_DEVICE_BOARD, spl_board_load_image);
|
|||
void spl_board_init(void)
|
||||
{
|
||||
struct sandbox_state *state = state_get_current();
|
||||
struct udevice *dev;
|
||||
|
||||
preloader_console_init();
|
||||
if (state->show_of_platdata) {
|
||||
/*
|
||||
* Scan all the devices so that we can output their platform
|
||||
* data. See sandbox_spl_probe().
|
||||
*/
|
||||
printf("Scanning misc devices\n");
|
||||
for (uclass_first_device(UCLASS_MISC, &dev);
|
||||
dev;
|
||||
uclass_next_device(&dev))
|
||||
;
|
||||
|
||||
if (state->run_unittests) {
|
||||
int ret;
|
||||
|
||||
ret = dm_test_main(state->select_unittests);
|
||||
/* continue execution into U-Boot */
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -365,14 +365,23 @@ static int sandbox_cmdline_cb_log_level(struct sandbox_state *state,
|
|||
SANDBOX_CMDLINE_OPT_SHORT(log_level, 'L', 1,
|
||||
"Set log level (0=panic, 7=debug)");
|
||||
|
||||
static int sandbox_cmdline_cb_show_of_platdata(struct sandbox_state *state,
|
||||
static int sandbox_cmdline_cb_unittests(struct sandbox_state *state,
|
||||
const char *arg)
|
||||
{
|
||||
state->show_of_platdata = true;
|
||||
state->run_unittests = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
SANDBOX_CMDLINE_OPT(show_of_platdata, 0, "Show of-platdata in SPL");
|
||||
SANDBOX_CMDLINE_OPT_SHORT(unittests, 'u', 0, "Run unit tests");
|
||||
|
||||
static int sandbox_cmdline_cb_select_unittests(struct sandbox_state *state,
|
||||
const char *arg)
|
||||
{
|
||||
state->select_unittests = arg;
|
||||
|
||||
return 0;
|
||||
}
|
||||
SANDBOX_CMDLINE_OPT_SHORT(select_unittests, 'k', 1, "Select unit tests to run");
|
||||
|
||||
static void setup_ram_buf(struct sandbox_state *state)
|
||||
{
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
clock-frequency = <400000>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_i2c0>;
|
||||
u-boot,dm-pre-reloc;
|
||||
};
|
||||
|
||||
pcic: pci@0 {
|
||||
|
|
|
@ -29,6 +29,32 @@
|
|||
};
|
||||
};
|
||||
|
||||
clk_fixed: clk-fixed {
|
||||
u-boot,dm-pre-reloc;
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <1234>;
|
||||
};
|
||||
|
||||
clk_sandbox: clk-sbox {
|
||||
u-boot,dm-pre-reloc;
|
||||
compatible = "sandbox,clk";
|
||||
#clock-cells = <1>;
|
||||
assigned-clocks = <&clk_sandbox 3>;
|
||||
assigned-clock-rates = <321>;
|
||||
};
|
||||
|
||||
clk-test {
|
||||
u-boot,dm-pre-reloc;
|
||||
compatible = "sandbox,clk-test";
|
||||
clocks = <&clk_fixed>,
|
||||
<&clk_sandbox 1>,
|
||||
<&clk_sandbox 0>,
|
||||
<&clk_sandbox 3>,
|
||||
<&clk_sandbox 2>;
|
||||
clock-names = "fixed", "i2c", "spi", "uart2", "uart1";
|
||||
};
|
||||
|
||||
gpio_a: gpios@0 {
|
||||
u-boot,dm-pre-reloc;
|
||||
gpio-controller;
|
||||
|
@ -64,6 +90,7 @@
|
|||
reg = <0x43>;
|
||||
compatible = "sandbox-rtc";
|
||||
sandbox,emul = <&emul0>;
|
||||
u-boot,dm-pre-reloc;
|
||||
};
|
||||
sandbox_pmic: sandbox_pmic {
|
||||
reg = <0x40>;
|
||||
|
|
|
@ -90,8 +90,9 @@ struct sandbox_state {
|
|||
bool skip_delays; /* Ignore any time delays (for test) */
|
||||
bool show_test_output; /* Don't suppress stdout in tests */
|
||||
int default_log_level; /* Default log level for sandbox */
|
||||
bool show_of_platdata; /* Show of-platdata in SPL */
|
||||
bool ram_buf_read; /* true if we read the RAM buffer */
|
||||
bool run_unittests; /* Run unit tests */
|
||||
const char *select_unittests; /* Unit test to run */
|
||||
|
||||
/* Pointer to information for each SPI bus/cs */
|
||||
struct sandbox_spi_info spi[CONFIG_SANDBOX_SPI_MAX_BUS]
|
||||
|
|
|
@ -85,6 +85,8 @@ config APL_SPI_FLASH_BOOT
|
|||
bool "Support booting with SPI-flash driver instead memory-mapped SPI"
|
||||
select TPL_SPI_FLASH_SUPPORT
|
||||
select TPL_SPI_SUPPORT
|
||||
select TPL_DM_SPI
|
||||
select TPL_DM_SPI_FLASH
|
||||
help
|
||||
This enables SPI and SPI flash in TPL. Without the this only
|
||||
available boot method is to use memory-mapped SPI. Since this is
|
||||
|
|
|
@ -90,7 +90,8 @@ static int apl_flash_probe(struct udevice *dev)
|
|||
*/
|
||||
static int apl_flash_bind(struct udevice *dev)
|
||||
{
|
||||
if (CONFIG_IS_ENABLED(OF_PLATDATA)) {
|
||||
if (CONFIG_IS_ENABLED(OF_PLATDATA) &&
|
||||
!CONFIG_IS_ENABLED(OF_PLATDATA_PARENT)) {
|
||||
struct dm_spi_slave_platdata *plat;
|
||||
struct udevice *spi;
|
||||
int ret;
|
||||
|
|
|
@ -21,10 +21,12 @@
|
|||
*/
|
||||
gd_t *gd;
|
||||
|
||||
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
/* Add a simple GPIO device */
|
||||
U_BOOT_DEVICE(gpio_sandbox) = {
|
||||
.name = "sandbox_gpio",
|
||||
};
|
||||
#endif
|
||||
|
||||
void flush_cache(unsigned long start, unsigned long size)
|
||||
{
|
||||
|
|
|
@ -296,20 +296,21 @@ static int initr_noncached(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_OF_LIVE
|
||||
static int initr_of_live(void)
|
||||
{
|
||||
if (CONFIG_IS_ENABLED(OF_LIVE)) {
|
||||
int ret;
|
||||
|
||||
bootstage_start(BOOTSTAGE_ID_ACCUM_OF_LIVE, "of_live");
|
||||
ret = of_live_build(gd->fdt_blob, (struct device_node **)&gd->of_root);
|
||||
ret = of_live_build(gd->fdt_blob,
|
||||
(struct device_node **)gd_of_root_ptr());
|
||||
bootstage_accum(BOOTSTAGE_ID_ACCUM_OF_LIVE);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DM
|
||||
static int initr_dm(void)
|
||||
|
@ -713,9 +714,7 @@ static init_fnc_t init_sequence_r[] = {
|
|||
#ifdef CONFIG_SYS_NONCACHED_MEMORY
|
||||
initr_noncached,
|
||||
#endif
|
||||
#ifdef CONFIG_OF_LIVE
|
||||
initr_of_live,
|
||||
#endif
|
||||
#ifdef CONFIG_DM
|
||||
initr_dm,
|
||||
#endif
|
||||
|
|
|
@ -22,11 +22,12 @@ CONFIG_BOOTSTAGE_STASH=y
|
|||
CONFIG_BOOTSTAGE_STASH_SIZE=0x4096
|
||||
CONFIG_CONSOLE_RECORD=y
|
||||
CONFIG_CONSOLE_RECORD_OUT_SIZE=0x1000
|
||||
CONFIG_SILENT_CONSOLE=y
|
||||
CONFIG_DISPLAY_BOARDINFO_LATE=y
|
||||
CONFIG_HANDOFF=y
|
||||
CONFIG_SPL_BOARD_INIT=y
|
||||
CONFIG_SPL_ENV_SUPPORT=y
|
||||
CONFIG_SPL_I2C_SUPPORT=y
|
||||
CONFIG_SPL_RTC_SUPPORT=y
|
||||
CONFIG_CMD_CPU=y
|
||||
CONFIG_CMD_LICENSE=y
|
||||
CONFIG_CMD_BOOTZ=y
|
||||
|
@ -105,6 +106,7 @@ CONFIG_ADC_SANDBOX=y
|
|||
CONFIG_AXI=y
|
||||
CONFIG_AXI_SANDBOX=y
|
||||
CONFIG_CLK=y
|
||||
CONFIG_SPL_CLK=y
|
||||
CONFIG_CPU=y
|
||||
CONFIG_DM_DEMO=y
|
||||
CONFIG_DM_DEMO_SIMPLE=y
|
||||
|
@ -120,7 +122,6 @@ CONFIG_I2C_CROS_EC_LDO=y
|
|||
CONFIG_DM_I2C_GPIO=y
|
||||
CONFIG_SYS_I2C_SANDBOX=y
|
||||
CONFIG_I2C_MUX=y
|
||||
CONFIG_SPL_I2C_MUX=y
|
||||
CONFIG_I2C_ARB_GPIO_CHALLENGE=y
|
||||
CONFIG_CROS_EC_KEYB=y
|
||||
CONFIG_I8042_KEYB=y
|
||||
|
@ -187,6 +188,7 @@ CONFIG_REMOTEPROC_SANDBOX=y
|
|||
CONFIG_DM_RESET=y
|
||||
CONFIG_SANDBOX_RESET=y
|
||||
CONFIG_DM_RTC=y
|
||||
CONFIG_SPL_DM_RTC=y
|
||||
CONFIG_SANDBOX_SERIAL=y
|
||||
CONFIG_SOUND=y
|
||||
CONFIG_SOUND_SANDBOX=y
|
||||
|
@ -221,5 +223,6 @@ CONFIG_TPM=y
|
|||
CONFIG_LZ4=y
|
||||
CONFIG_ERRNO_STR=y
|
||||
CONFIG_UNIT_TEST=y
|
||||
CONFIG_SPL_UNIT_TEST=y
|
||||
CONFIG_UT_TIME=y
|
||||
CONFIG_UT_DM=y
|
||||
|
|
|
@ -66,12 +66,6 @@ strictly necessary. Notable problems include:
|
|||
normally also supports device tree it must use #ifdef to separate
|
||||
out this code, since the structures are only available in SPL.
|
||||
|
||||
- Correct relations between nodes are not implemented. This means that
|
||||
parent/child relations (like bus device iteration) do not work yet.
|
||||
Some phandles (those that are recognised as such) are converted into
|
||||
a pointer to struct driver_info. This pointer can be used to access
|
||||
the referenced device.
|
||||
|
||||
|
||||
How it works
|
||||
------------
|
||||
|
@ -134,10 +128,14 @@ the following C struct declaration:
|
|||
fdt32_t vmmc_supply;
|
||||
};
|
||||
|
||||
and the following device declaration:
|
||||
and the following device declarations:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* Node /clock-controller@ff760000 index 0 */
|
||||
...
|
||||
|
||||
/* Node /dwmmc@ff0c0000 index 2 */
|
||||
static struct dtd_rockchip_rk3288_dw_mshc dtv_dwmmc_at_ff0c0000 = {
|
||||
.fifo_depth = 0x100,
|
||||
.cap_sd_highspeed = true,
|
||||
|
@ -145,10 +143,10 @@ and the following device declaration:
|
|||
.clock_freq_min_max = {0x61a80, 0x8f0d180},
|
||||
.vmmc_supply = 0xb,
|
||||
.num_slots = 0x1,
|
||||
.clocks = {{NULL, 456},
|
||||
{NULL, 68},
|
||||
{NULL, 114},
|
||||
{NULL, 118}},
|
||||
.clocks = {{0, 456},
|
||||
{0, 68},
|
||||
{0, 114},
|
||||
{0, 118}},
|
||||
.cap_mmc_highspeed = true,
|
||||
.disable_wp = true,
|
||||
.bus_width = 0x4,
|
||||
|
@ -161,13 +159,10 @@ and the following device declaration:
|
|||
.name = "rockchip_rk3288_dw_mshc",
|
||||
.platdata = &dtv_dwmmc_at_ff0c0000,
|
||||
.platdata_size = sizeof(dtv_dwmmc_at_ff0c0000),
|
||||
.parent_idx = -1,
|
||||
};
|
||||
|
||||
void dm_populate_phandle_data(void) {
|
||||
dtv_dwmmc_at_ff0c0000.clocks[0].node = DM_GET_DEVICE(clock_controller_at_ff760000);
|
||||
dtv_dwmmc_at_ff0c0000.clocks[1].node = DM_GET_DEVICE(clock_controller_at_ff760000);
|
||||
dtv_dwmmc_at_ff0c0000.clocks[2].node = DM_GET_DEVICE(clock_controller_at_ff760000);
|
||||
dtv_dwmmc_at_ff0c0000.clocks[3].node = DM_GET_DEVICE(clock_controller_at_ff760000);
|
||||
}
|
||||
|
||||
The device is then instantiated at run-time and the platform data can be
|
||||
|
@ -193,6 +188,13 @@ In order to make this a bit more flexible U_BOOT_DRIVER_ALIAS macro can be
|
|||
used to declare an alias for a driver name, typically a 'compatible' string.
|
||||
This macro produces no code, but it is by dtoc tool.
|
||||
|
||||
The parent_idx is the index of the parent driver_info structure within its
|
||||
linker list (instantiated by the U_BOOT_DEVICE() macro). This is used to support
|
||||
dev_get_parent(). The dm_populate_phandle_data() is included to allow for
|
||||
fix-ups required by dtoc. It is not currently used. The values in 'clocks' are
|
||||
the index of the driver_info for the target device followed by any phandle
|
||||
arguments. This is used to support device_get_by_driver_info_idx().
|
||||
|
||||
During the build process dtoc parses both U_BOOT_DRIVER and U_BOOT_DRIVER_ALIAS
|
||||
to build a list of valid driver names and driver aliases. If the 'compatible'
|
||||
string used for a device does not not match a valid driver name, it will be
|
||||
|
@ -339,12 +341,7 @@ spl/dt-platdata.c. It additionally contains the definition of
|
|||
dm_populate_phandle_data() which is responsible of filling the phandle
|
||||
information by adding references to U_BOOT_DEVICE by using DM_GET_DEVICE
|
||||
|
||||
The beginnings of a libfdt Python module are provided. So far this only
|
||||
implements a subset of the features.
|
||||
|
||||
The 'swig' tool is needed to build the libfdt Python module. If this is not
|
||||
found then the Python model is not used and a fallback is used instead, which
|
||||
makes use of fdtget.
|
||||
The pylibfdt Python module is used to access the devicetree.
|
||||
|
||||
|
||||
Credits
|
||||
|
@ -357,11 +354,10 @@ Future work
|
|||
-----------
|
||||
- Consider programmatically reading binding files instead of device tree
|
||||
contents
|
||||
- Complete the phandle feature
|
||||
- Move to using a full Python libfdt module
|
||||
|
||||
|
||||
.. Simon Glass <sjg@chromium.org>
|
||||
.. Google, Inc
|
||||
.. 6/6/16
|
||||
.. Updated Independence Day 2016
|
||||
.. Updated 1st October 2020
|
||||
|
|
|
@ -38,8 +38,7 @@ int clk_get_by_driver_info(struct udevice *dev, struct phandle_1_arg *cells,
|
|||
{
|
||||
int ret;
|
||||
|
||||
ret = device_get_by_driver_info((struct driver_info *)cells->node,
|
||||
&clk->dev);
|
||||
ret = device_get_by_driver_info_idx(cells->idx, &clk->dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
clk->id = cells->arg[0];
|
||||
|
|
|
@ -46,8 +46,8 @@ static const struct udevice_id clk_fixed_rate_match[] = {
|
|||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(clk_fixed_rate) = {
|
||||
.name = "fixed_rate_clock",
|
||||
U_BOOT_DRIVER(fixed_clock) = {
|
||||
.name = "fixed_clock",
|
||||
.id = UCLASS_CLK,
|
||||
.of_match = clk_fixed_rate_match,
|
||||
.ofdata_to_platdata = clk_fixed_rate_ofdata_to_platdata,
|
||||
|
|
|
@ -124,8 +124,8 @@ static const struct udevice_id sandbox_clk_ids[] = {
|
|||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(clk_sandbox) = {
|
||||
.name = "clk_sandbox",
|
||||
U_BOOT_DRIVER(sandbox_clk) = {
|
||||
.name = "sandbox_clk",
|
||||
.id = UCLASS_CLK,
|
||||
.of_match = sandbox_clk_ids,
|
||||
.ops = &sandbox_clk_ops,
|
||||
|
|
|
@ -40,10 +40,24 @@ config DM_WARN
|
|||
depends on DM
|
||||
default y
|
||||
help
|
||||
Enable this to see warnings related to driver model.
|
||||
|
||||
Warnings may help with debugging, such as when expected devices do
|
||||
not bind correctly. If the option is disabled, dm_warn() is compiled
|
||||
out - it will do nothing when called.
|
||||
|
||||
config SPL_DM_WARN
|
||||
bool "Enable warnings in driver model wuth SPL"
|
||||
depends on SPL_DM
|
||||
help
|
||||
Enable this to see warnings related to driver model in SPL
|
||||
|
||||
The dm_warn() function can use up quite a bit of space for its
|
||||
strings. By default this is disabled for SPL builds to save space.
|
||||
This will cause dm_warn() to be compiled out - it will do nothing
|
||||
when called.
|
||||
|
||||
Warnings may help with debugging, such as when expected devices do
|
||||
not bind correctly. If the option is disabled, dm_warn() is compiled
|
||||
out - it will do nothing when called.
|
||||
|
||||
config DM_DEBUG
|
||||
bool "Enable debug messages in driver model core"
|
||||
|
|
|
@ -11,7 +11,7 @@ obj-$(CONFIG_SIMPLE_PM_BUS) += simple-pm-bus.o
|
|||
obj-$(CONFIG_DM) += dump.o
|
||||
obj-$(CONFIG_$(SPL_TPL_)REGMAP) += regmap.o
|
||||
obj-$(CONFIG_$(SPL_TPL_)SYSCON) += syscon-uclass.o
|
||||
obj-$(CONFIG_OF_LIVE) += of_access.o of_addr.o
|
||||
obj-$(CONFIG_$(SPL_)OF_LIVE) += of_access.o of_addr.o
|
||||
ifndef CONFIG_DM_DEV_READ_INLINE
|
||||
obj-$(CONFIG_OF_CONTROL) += read.o
|
||||
endif
|
||||
|
|
|
@ -249,7 +249,7 @@ int device_bind_ofnode(struct udevice *parent, const struct driver *drv,
|
|||
}
|
||||
|
||||
int device_bind_by_name(struct udevice *parent, bool pre_reloc_only,
|
||||
struct driver_info *info, struct udevice **devp)
|
||||
const struct driver_info *info, struct udevice **devp)
|
||||
{
|
||||
struct driver *drv;
|
||||
uint platdata_size = 0;
|
||||
|
@ -269,9 +269,6 @@ int device_bind_by_name(struct udevice *parent, bool pre_reloc_only,
|
|||
platdata_size, devp);
|
||||
if (ret)
|
||||
return ret;
|
||||
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
info->dev = *devp;
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -764,9 +761,25 @@ int device_get_global_by_ofnode(ofnode ofnode, struct udevice **devp)
|
|||
int device_get_by_driver_info(const struct driver_info *info,
|
||||
struct udevice **devp)
|
||||
{
|
||||
struct driver_info *info_base =
|
||||
ll_entry_start(struct driver_info, driver_info);
|
||||
int idx = info - info_base;
|
||||
struct driver_rt *drt = gd_dm_driver_rt() + idx;
|
||||
struct udevice *dev;
|
||||
|
||||
dev = info->dev;
|
||||
dev = drt->dev;
|
||||
*devp = NULL;
|
||||
|
||||
return device_get_device_tail(dev, dev ? 0 : -ENOENT, devp);
|
||||
}
|
||||
|
||||
int device_get_by_driver_info_idx(uint idx, struct udevice **devp)
|
||||
{
|
||||
struct driver_rt *drt = gd_dm_driver_rt() + idx;
|
||||
struct udevice *dev;
|
||||
|
||||
dev = drt->dev;
|
||||
*devp = NULL;
|
||||
|
||||
return device_get_device_tail(dev, dev ? 0 : -ENOENT, devp);
|
||||
}
|
||||
|
|
|
@ -51,25 +51,81 @@ struct uclass_driver *lists_uclass_lookup(enum uclass_id id)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
int lists_bind_drivers(struct udevice *parent, bool pre_reloc_only)
|
||||
static int bind_drivers_pass(struct udevice *parent, bool pre_reloc_only)
|
||||
{
|
||||
struct driver_info *info =
|
||||
ll_entry_start(struct driver_info, driver_info);
|
||||
const int n_ents = ll_entry_count(struct driver_info, driver_info);
|
||||
struct driver_info *entry;
|
||||
struct udevice *dev;
|
||||
bool missing_parent = false;
|
||||
int result = 0;
|
||||
uint idx;
|
||||
|
||||
/*
|
||||
* Do one iteration through the driver_info records. For of-platdata,
|
||||
* bind only devices whose parent is already bound. If we find any
|
||||
* device we can't bind, set missing_parent to true, which will cause
|
||||
* this function to be called again.
|
||||
*/
|
||||
for (idx = 0; idx < n_ents; idx++) {
|
||||
struct udevice *par = parent;
|
||||
const struct driver_info *entry = info + idx;
|
||||
struct driver_rt *drt = gd_dm_driver_rt() + idx;
|
||||
struct udevice *dev;
|
||||
int ret;
|
||||
|
||||
for (entry = info; entry != info + n_ents; entry++) {
|
||||
ret = device_bind_by_name(parent, pre_reloc_only, entry, &dev);
|
||||
if (ret && ret != -EPERM) {
|
||||
if (CONFIG_IS_ENABLED(OF_PLATDATA)) {
|
||||
int parent_idx = driver_info_parent_id(entry);
|
||||
|
||||
if (drt->dev)
|
||||
continue;
|
||||
|
||||
if (CONFIG_IS_ENABLED(OF_PLATDATA_PARENT) &&
|
||||
parent_idx != -1) {
|
||||
struct driver_rt *parent_drt;
|
||||
|
||||
parent_drt = gd_dm_driver_rt() + parent_idx;
|
||||
if (!parent_drt->dev) {
|
||||
missing_parent = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
par = parent_drt->dev;
|
||||
}
|
||||
}
|
||||
ret = device_bind_by_name(par, pre_reloc_only, entry, &dev);
|
||||
if (!ret) {
|
||||
if (CONFIG_IS_ENABLED(OF_PLATDATA))
|
||||
drt->dev = dev;
|
||||
} else if (ret != -EPERM) {
|
||||
dm_warn("No match for driver '%s'\n", entry->name);
|
||||
if (!result || ret != -ENOENT)
|
||||
result = ret;
|
||||
}
|
||||
}
|
||||
|
||||
return result ? result : missing_parent ? -EAGAIN : 0;
|
||||
}
|
||||
|
||||
int lists_bind_drivers(struct udevice *parent, bool pre_reloc_only)
|
||||
{
|
||||
int result = 0;
|
||||
int pass;
|
||||
|
||||
/*
|
||||
* 10 passes is 10 levels deep in the devicetree, which is plenty. If
|
||||
* OF_PLATDATA_PARENT is not enabled, then bind_drivers_pass() will
|
||||
* always succeed on the first pass.
|
||||
*/
|
||||
for (pass = 0; pass < 10; pass++) {
|
||||
int ret;
|
||||
|
||||
ret = bind_drivers_pass(parent, pre_reloc_only);
|
||||
if (!ret)
|
||||
break;
|
||||
if (ret != -EAGAIN && !result)
|
||||
result = ret;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -50,7 +50,6 @@ void dm_fixup_for_gd_move(struct global_data *new_gd)
|
|||
}
|
||||
}
|
||||
|
||||
#if defined(CONFIG_NEEDS_MANUAL_RELOC)
|
||||
void fix_drivers(void)
|
||||
{
|
||||
struct driver *drv =
|
||||
|
@ -61,7 +60,7 @@ void fix_drivers(void)
|
|||
for (entry = drv; entry != drv + n_ents; entry++) {
|
||||
if (entry->of_match)
|
||||
entry->of_match = (const struct udevice_id *)
|
||||
((u32)entry->of_match + gd->reloc_off);
|
||||
((ulong)entry->of_match + gd->reloc_off);
|
||||
if (entry->bind)
|
||||
entry->bind += gd->reloc_off;
|
||||
if (entry->probe)
|
||||
|
@ -129,8 +128,6 @@ void fix_devices(void)
|
|||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int dm_init(bool of_live)
|
||||
{
|
||||
int ret;
|
||||
|
@ -141,21 +138,19 @@ int dm_init(bool of_live)
|
|||
}
|
||||
INIT_LIST_HEAD(&DM_UCLASS_ROOT_NON_CONST);
|
||||
|
||||
#if defined(CONFIG_NEEDS_MANUAL_RELOC)
|
||||
if (IS_ENABLED(CONFIG_NEEDS_MANUAL_RELOC)) {
|
||||
fix_drivers();
|
||||
fix_uclass();
|
||||
fix_devices();
|
||||
#endif
|
||||
}
|
||||
|
||||
ret = device_bind_by_name(NULL, false, &root_info, &DM_ROOT_NON_CONST);
|
||||
if (ret)
|
||||
return ret;
|
||||
#if CONFIG_IS_ENABLED(OF_CONTROL)
|
||||
# if CONFIG_IS_ENABLED(OF_LIVE)
|
||||
if (of_live)
|
||||
DM_ROOT_NON_CONST->node = np_to_ofnode(gd->of_root);
|
||||
if (CONFIG_IS_ENABLED(OF_LIVE) && of_live)
|
||||
DM_ROOT_NON_CONST->node = np_to_ofnode(gd_of_root());
|
||||
else
|
||||
#endif
|
||||
DM_ROOT_NON_CONST->node = offset_to_ofnode(0);
|
||||
#endif
|
||||
ret = device_probe(DM_ROOT_NON_CONST);
|
||||
|
@ -187,6 +182,17 @@ int dm_scan_platdata(bool pre_reloc_only)
|
|||
{
|
||||
int ret;
|
||||
|
||||
if (CONFIG_IS_ENABLED(OF_PLATDATA)) {
|
||||
struct driver_rt *dyn;
|
||||
int n_ents;
|
||||
|
||||
n_ents = ll_entry_count(struct driver_info, driver_info);
|
||||
dyn = calloc(n_ents, sizeof(struct driver_rt));
|
||||
if (!dyn)
|
||||
return -ENOMEM;
|
||||
gd_set_dm_driver_rt(dyn);
|
||||
}
|
||||
|
||||
ret = lists_bind_drivers(DM_ROOT_NON_CONST, pre_reloc_only);
|
||||
if (ret == -ENOENT) {
|
||||
dm_warn("Some drivers were not found\n");
|
||||
|
@ -196,7 +202,7 @@ int dm_scan_platdata(bool pre_reloc_only)
|
|||
return ret;
|
||||
}
|
||||
|
||||
#if CONFIG_IS_ENABLED(OF_LIVE)
|
||||
#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
static int dm_scan_fdt_live(struct udevice *parent,
|
||||
const struct device_node *node_parent,
|
||||
bool pre_reloc_only)
|
||||
|
@ -223,9 +229,7 @@ static int dm_scan_fdt_live(struct udevice *parent,
|
|||
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_IS_ENABLED(OF_LIVE) */
|
||||
|
||||
#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
/**
|
||||
* dm_scan_fdt_node() - Scan the device tree and bind drivers for a node
|
||||
*
|
||||
|
@ -272,24 +276,20 @@ int dm_scan_fdt_dev(struct udevice *dev)
|
|||
if (!dev_of_valid(dev))
|
||||
return 0;
|
||||
|
||||
#if CONFIG_IS_ENABLED(OF_LIVE)
|
||||
if (of_live_active())
|
||||
return dm_scan_fdt_live(dev, dev_np(dev),
|
||||
gd->flags & GD_FLG_RELOC ? false : true);
|
||||
else
|
||||
#endif
|
||||
|
||||
return dm_scan_fdt_node(dev, gd->fdt_blob, dev_of_offset(dev),
|
||||
gd->flags & GD_FLG_RELOC ? false : true);
|
||||
}
|
||||
|
||||
int dm_scan_fdt(const void *blob, bool pre_reloc_only)
|
||||
{
|
||||
#if CONFIG_IS_ENABLED(OF_LIVE)
|
||||
if (of_live_active())
|
||||
return dm_scan_fdt_live(gd->dm_root, gd->of_root,
|
||||
return dm_scan_fdt_live(gd->dm_root, gd_of_root(),
|
||||
pre_reloc_only);
|
||||
else
|
||||
#endif
|
||||
|
||||
return dm_scan_fdt_node(gd->dm_root, blob, 0, pre_reloc_only);
|
||||
}
|
||||
|
||||
|
@ -302,10 +302,9 @@ static int dm_scan_fdt_ofnode_path(const void *blob, const char *path,
|
|||
if (!ofnode_valid(node))
|
||||
return 0;
|
||||
|
||||
#if CONFIG_IS_ENABLED(OF_LIVE)
|
||||
if (of_live_active())
|
||||
return dm_scan_fdt_live(gd->dm_root, node.np, pre_reloc_only);
|
||||
#endif
|
||||
|
||||
return dm_scan_fdt_node(gd->dm_root, blob, node.of_offset,
|
||||
pre_reloc_only);
|
||||
}
|
||||
|
@ -348,11 +347,10 @@ int dm_init_and_scan(bool pre_reloc_only)
|
|||
{
|
||||
int ret;
|
||||
|
||||
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
if (CONFIG_IS_ENABLED(OF_PLATDATA))
|
||||
dm_populate_phandle_data();
|
||||
#endif
|
||||
|
||||
ret = dm_init(IS_ENABLED(CONFIG_OF_LIVE));
|
||||
ret = dm_init(CONFIG_IS_ENABLED(OF_LIVE));
|
||||
if (ret) {
|
||||
debug("dm_init() failed: %d\n", ret);
|
||||
return ret;
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#include <linux/libfdt.h>
|
||||
#include <vsprintf.h>
|
||||
|
||||
#ifdef CONFIG_DM_WARN
|
||||
#if CONFIG_IS_ENABLED(DM_WARN)
|
||||
void dm_warn(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
|
|
@ -6,7 +6,7 @@ obj-$(CONFIG_DM_I2C) += i2c-uclass.o
|
|||
ifdef CONFIG_ACPIGEN
|
||||
obj-$(CONFIG_DM_I2C) += acpi_i2c.o
|
||||
endif
|
||||
obj-$(CONFIG_DM_I2C_GPIO) += i2c-gpio.o
|
||||
obj-$(CONFIG_$(SPL_)DM_I2C_GPIO) += i2c-gpio.o
|
||||
obj-$(CONFIG_$(SPL_)I2C_CROS_EC_TUNNEL) += cros_ec_tunnel.o
|
||||
obj-$(CONFIG_$(SPL_)I2C_CROS_EC_LDO) += cros_ec_ldo.o
|
||||
|
||||
|
|
|
@ -76,7 +76,9 @@ UCLASS_DRIVER(i2c_emul) = {
|
|||
UCLASS_DRIVER(i2c_emul_parent) = {
|
||||
.id = UCLASS_I2C_EMUL_PARENT,
|
||||
.name = "i2c_emul_parent",
|
||||
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
.post_bind = dm_scan_fdt_dev,
|
||||
#endif
|
||||
};
|
||||
|
||||
static const struct udevice_id i2c_emul_parent_ids[] = {
|
||||
|
|
|
@ -93,8 +93,8 @@ static const struct udevice_id sandbox_i2c_ids[] = {
|
|||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(i2c_sandbox) = {
|
||||
.name = "i2c_sandbox",
|
||||
U_BOOT_DRIVER(sandbox_i2c) = {
|
||||
.name = "sandbox_i2c",
|
||||
.id = UCLASS_I2C,
|
||||
.of_match = sandbox_i2c_ids,
|
||||
.ops = &sandbox_i2c_ops,
|
||||
|
|
|
@ -69,7 +69,7 @@ int irq_get_by_driver_info(struct udevice *dev,
|
|||
{
|
||||
int ret;
|
||||
|
||||
ret = device_get_by_driver_info(cells->node, &irq->dev);
|
||||
ret = device_get_by_driver_info_idx(cells->idx, &irq->dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
irq->id = cells->arg[0];
|
||||
|
|
|
@ -174,19 +174,20 @@ int p2sb_set_port_id(struct udevice *dev, int portid)
|
|||
if (!CONFIG_IS_ENABLED(OF_PLATDATA))
|
||||
return -ENOSYS;
|
||||
|
||||
if (!CONFIG_IS_ENABLED(OF_PLATDATA_PARENT)) {
|
||||
uclass_find_first_device(UCLASS_P2SB, &ps2b);
|
||||
if (!ps2b)
|
||||
return -EDEADLK;
|
||||
dev->parent = ps2b;
|
||||
|
||||
/*
|
||||
* We must allocate this, since when the device was bound it did not
|
||||
* have a parent.
|
||||
* TODO(sjg@chromium.org): Add a parent pointer to child devices in dtoc
|
||||
* We must allocate this, since when the device was bound it did
|
||||
* not have a parent.
|
||||
*/
|
||||
dev->parent_platdata = malloc(sizeof(*pplat));
|
||||
if (!dev->parent_platdata)
|
||||
return -ENOMEM;
|
||||
}
|
||||
pplat = dev_get_parent_platdata(dev);
|
||||
pplat->pid = portid;
|
||||
|
||||
|
|
|
@ -8,43 +8,8 @@
|
|||
#include <dm.h>
|
||||
#include <dt-structs.h>
|
||||
|
||||
static int sandbox_spl_probe(struct udevice *dev)
|
||||
{
|
||||
struct dtd_sandbox_spl_test *plat = dev_get_platdata(dev);
|
||||
int i;
|
||||
|
||||
printf("of-platdata probe:\n");
|
||||
printf("bool %d\n", plat->boolval);
|
||||
|
||||
printf("byte %02x\n", plat->byteval);
|
||||
printf("bytearray");
|
||||
for (i = 0; i < sizeof(plat->bytearray); i++)
|
||||
printf(" %02x", plat->bytearray[i]);
|
||||
printf("\n");
|
||||
|
||||
printf("int %d\n", plat->intval);
|
||||
printf("intarray");
|
||||
for (i = 0; i < ARRAY_SIZE(plat->intarray); i++)
|
||||
printf(" %d", plat->intarray[i]);
|
||||
printf("\n");
|
||||
|
||||
printf("longbytearray");
|
||||
for (i = 0; i < sizeof(plat->longbytearray); i++)
|
||||
printf(" %02x", plat->longbytearray[i]);
|
||||
printf("\n");
|
||||
|
||||
printf("string %s\n", plat->stringval);
|
||||
printf("stringarray");
|
||||
for (i = 0; i < ARRAY_SIZE(plat->stringarray); i++)
|
||||
printf(" \"%s\"", plat->stringarray[i]);
|
||||
printf("\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_DRIVER(sandbox_spl_test) = {
|
||||
.name = "sandbox_spl_test",
|
||||
.id = UCLASS_MISC,
|
||||
.flags = DM_FLAG_PRE_RELOC,
|
||||
.probe = sandbox_spl_probe,
|
||||
};
|
||||
|
|
|
@ -1504,12 +1504,9 @@ static int fsl_esdhc_probe(struct udevice *dev)
|
|||
|
||||
if (CONFIG_IS_ENABLED(DM_GPIO) && !priv->non_removable) {
|
||||
struct udevice *gpiodev;
|
||||
struct driver_info *info;
|
||||
|
||||
info = (struct driver_info *)dtplat->cd_gpios->node;
|
||||
|
||||
ret = device_get_by_driver_info(info, &gpiodev);
|
||||
|
||||
ret = device_get_by_driver_info_idx(dtplat->cd_gpios->idx,
|
||||
&gpiodev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
|
@ -174,5 +174,7 @@ int rtc_write32(struct udevice *dev, unsigned int reg, u32 value)
|
|||
UCLASS_DRIVER(rtc) = {
|
||||
.name = "rtc",
|
||||
.id = UCLASS_RTC,
|
||||
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
.post_bind = dm_scan_fdt_dev,
|
||||
#endif
|
||||
};
|
||||
|
|
|
@ -92,8 +92,8 @@ static const struct udevice_id sandbox_rtc_ids[] = {
|
|||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(rtc_sandbox) = {
|
||||
.name = "rtc-sandbox",
|
||||
U_BOOT_DRIVER(sandbox_rtc) = {
|
||||
.name = "sandbox_rtc",
|
||||
.id = UCLASS_RTC,
|
||||
.of_match = sandbox_rtc_ids,
|
||||
.ops = &sandbox_rtc_ops,
|
||||
|
|
|
@ -267,6 +267,7 @@ U_BOOT_DRIVER(sandbox_serial) = {
|
|||
.flags = DM_FLAG_PRE_RELOC,
|
||||
};
|
||||
|
||||
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
static const struct sandbox_serial_platdata platdata_non_fdt = {
|
||||
.colour = -1,
|
||||
};
|
||||
|
@ -275,4 +276,6 @@ U_BOOT_DEVICE(serial_sandbox_non_fdt) = {
|
|||
.name = "sandbox_serial",
|
||||
.platdata = &platdata_non_fdt,
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_IS_ENABLED(OF_CONTROL) */
|
||||
|
|
|
@ -615,6 +615,7 @@ static int ich_spi_exec_op(struct spi_slave *slave, const struct spi_mem_op *op)
|
|||
return ret;
|
||||
}
|
||||
|
||||
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
/**
|
||||
* ich_spi_get_basics() - Get basic information about the ICH device
|
||||
*
|
||||
|
@ -657,6 +658,7 @@ static int ich_spi_get_basics(struct udevice *bus, bool can_probe,
|
|||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* ich_get_mmap_bus() - Handle the get_mmap() method for a bus
|
||||
|
@ -946,10 +948,10 @@ static int ich_spi_child_pre_probe(struct udevice *dev)
|
|||
static int ich_spi_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct ich_spi_platdata *plat = dev_get_platdata(dev);
|
||||
int ret;
|
||||
|
||||
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
struct ich_spi_priv *priv = dev_get_priv(dev);
|
||||
int ret;
|
||||
|
||||
ret = ich_spi_get_basics(dev, true, &priv->pch, &plat->ich_version,
|
||||
&plat->mmio_base);
|
||||
|
|
|
@ -130,7 +130,9 @@ U_BOOT_DRIVER(warm_sysreset_sandbox) = {
|
|||
.ops = &sandbox_warm_sysreset_ops,
|
||||
};
|
||||
|
||||
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
/* This is here in case we don't have a device tree */
|
||||
U_BOOT_DEVICE(sysreset_sandbox_non_fdt) = {
|
||||
.name = "sysreset_sandbox",
|
||||
};
|
||||
#endif
|
||||
|
|
18
dts/Kconfig
18
dts/Kconfig
|
@ -355,6 +355,15 @@ config SPL_OF_PLATDATA
|
|||
compatible string, then adding platform data and U_BOOT_DEVICE
|
||||
declarations for each node. See of-plat.txt for more information.
|
||||
|
||||
config SPL_OF_PLATDATA_PARENT
|
||||
bool "Support parent information in devices"
|
||||
depends on SPL_OF_PLATDATA
|
||||
default y
|
||||
help
|
||||
Generally it is useful to be able to access the parent of a device
|
||||
with of-platdata. To save space this can be disabled, but in that
|
||||
case dev_get_parent() will always return NULL;
|
||||
|
||||
config TPL_OF_PLATDATA
|
||||
bool "Generate platform data for use in TPL"
|
||||
depends on TPL_OF_CONTROL
|
||||
|
@ -376,4 +385,13 @@ config TPL_OF_PLATDATA
|
|||
compatible string, then adding platform data and U_BOOT_DEVICE
|
||||
declarations for each node. See of-plat.txt for more information.
|
||||
|
||||
config TPL_OF_PLATDATA_PARENT
|
||||
bool "Support parent information in devices"
|
||||
depends on TPL_OF_PLATDATA
|
||||
default y
|
||||
help
|
||||
Generally it is useful to be able to access the parent of a device
|
||||
with of-platdata. To save space this can be disabled, but in that
|
||||
case dev_get_parent() will always return NULL;
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
#include <membuff.h>
|
||||
#include <linux/list.h>
|
||||
|
||||
struct driver_rt;
|
||||
|
||||
typedef struct global_data gd_t;
|
||||
|
||||
/**
|
||||
|
@ -192,6 +194,10 @@ struct global_data {
|
|||
* @uclass_root: head of core tree
|
||||
*/
|
||||
struct list_head uclass_root;
|
||||
# if CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
/** Dynamic info about the driver */
|
||||
struct driver_rt *dm_driver_rt;
|
||||
# endif
|
||||
#endif
|
||||
#ifdef CONFIG_TIMER
|
||||
/**
|
||||
|
@ -211,7 +217,7 @@ struct global_data {
|
|||
* @fdt_size: space reserved for relocated device space
|
||||
*/
|
||||
unsigned long fdt_size;
|
||||
#ifdef CONFIG_OF_LIVE
|
||||
#if CONFIG_IS_ENABLED(OF_LIVE)
|
||||
/**
|
||||
* @of_root: root node of the live tree
|
||||
*/
|
||||
|
@ -427,6 +433,25 @@ struct global_data {
|
|||
#define gd_board_type() 0
|
||||
#endif
|
||||
|
||||
/* These macros help avoid #ifdefs in the code */
|
||||
#if CONFIG_IS_ENABLED(OF_LIVE)
|
||||
#define gd_of_root() gd->of_root
|
||||
#define gd_of_root_ptr() &gd->of_root
|
||||
#define gd_set_of_root(_root) gd->of_root = (_root)
|
||||
#else
|
||||
#define gd_of_root() NULL
|
||||
#define gd_of_root_ptr() NULL
|
||||
#define gd_set_of_root(_root)
|
||||
#endif
|
||||
|
||||
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
#define gd_set_dm_driver_rt(dyn) gd->dm_driver_rt = dyn
|
||||
#define gd_dm_driver_rt() gd->dm_driver_rt
|
||||
#else
|
||||
#define gd_set_dm_driver_rt(dyn)
|
||||
#define gd_dm_driver_rt() NULL
|
||||
#endif
|
||||
|
||||
/**
|
||||
* enum gd_flags - global data flags
|
||||
*
|
||||
|
|
|
@ -42,6 +42,13 @@ int binman_entry_map(ofnode parent, const char *name, void **bufp, int *sizep);
|
|||
*/
|
||||
void binman_set_rom_offset(int rom_offset);
|
||||
|
||||
/**
|
||||
* binman_get_rom_offset() - Get the ROM memory-map offset
|
||||
*
|
||||
* @returns offset from an image_pos to the memory-mapped address
|
||||
*/
|
||||
int binman_get_rom_offset(void);
|
||||
|
||||
/**
|
||||
* binman_entry_find() - Find a binman symbol
|
||||
*
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#undef CONFIG_DM_SPI
|
||||
#endif
|
||||
|
||||
#undef CONFIG_DM_WARN
|
||||
#undef CONFIG_DM_STDIO
|
||||
|
||||
#endif /* CONFIG_SPL_BUILD */
|
||||
|
|
|
@ -81,7 +81,7 @@ int device_bind_with_driver_data(struct udevice *parent,
|
|||
* @return 0 if OK, -ve on error
|
||||
*/
|
||||
int device_bind_by_name(struct udevice *parent, bool pre_reloc_only,
|
||||
struct driver_info *info, struct udevice **devp);
|
||||
const struct driver_info *info, struct udevice **devp);
|
||||
|
||||
/**
|
||||
* device_reparent: reparent the device to a new parent
|
||||
|
|
|
@ -553,6 +553,20 @@ int device_get_global_by_ofnode(ofnode node, struct udevice **devp);
|
|||
int device_get_by_driver_info(const struct driver_info *info,
|
||||
struct udevice **devp);
|
||||
|
||||
/**
|
||||
* device_get_by_driver_info_idx() - Get a device based on driver_info index
|
||||
*
|
||||
* Locates a device by its struct driver_info, by using its index number which
|
||||
* is written into the idx field of struct phandle_1_arg, etc.
|
||||
*
|
||||
* The device is probed to activate it ready for use.
|
||||
*
|
||||
* @idx: Index number of the driver_info structure (0=first)
|
||||
* @devp: Returns pointer to device if found, otherwise this is set to NULL
|
||||
* @return 0 if OK, -ve on error
|
||||
*/
|
||||
int device_get_by_driver_info_idx(uint idx, struct udevice **devp);
|
||||
|
||||
/**
|
||||
* device_find_first_child() - Find the first child of a device
|
||||
*
|
||||
|
@ -823,7 +837,7 @@ static inline bool device_is_on_pci_bus(const struct udevice *dev)
|
|||
_ret = device_next_child_err(&dev))
|
||||
|
||||
/**
|
||||
* dm_scan_fdt_dev() - Bind child device in a the device tree
|
||||
* dm_scan_fdt_dev() - Bind child device in the device tree
|
||||
*
|
||||
* This handles device which have sub-nodes in the device tree. It scans all
|
||||
* sub-nodes and binds drivers for each node where a driver can be found.
|
||||
|
|
|
@ -90,17 +90,10 @@ DECLARE_GLOBAL_DATA_PTR;
|
|||
*
|
||||
* @returns true if livetree is active, false it not
|
||||
*/
|
||||
#ifdef CONFIG_OF_LIVE
|
||||
static inline bool of_live_active(void)
|
||||
{
|
||||
return gd->of_root != NULL;
|
||||
return gd_of_root() != NULL;
|
||||
}
|
||||
#else
|
||||
static inline bool of_live_active(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define OF_BAD_ADDR ((u64)-1)
|
||||
|
||||
|
|
|
@ -22,30 +22,71 @@
|
|||
* @name: Driver name
|
||||
* @platdata: Driver-specific platform data
|
||||
* @platdata_size: Size of platform data structure
|
||||
* @dev: Device created from this structure data
|
||||
* @parent_idx: Index of the parent driver_info structure
|
||||
*/
|
||||
struct driver_info {
|
||||
const char *name;
|
||||
const void *platdata;
|
||||
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
uint platdata_size;
|
||||
struct udevice *dev;
|
||||
unsigned short platdata_size;
|
||||
short parent_idx;
|
||||
#endif
|
||||
};
|
||||
|
||||
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
#define driver_info_parent_id(driver_info) driver_info->parent_idx
|
||||
#else
|
||||
#define driver_info_parent_id(driver_info) (-1)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* driver_rt - runtime information set up by U-Boot
|
||||
*
|
||||
* There is one of these for every driver_info in the linker list, indexed by
|
||||
* the driver_info idx value.
|
||||
*
|
||||
* @dev: Device created from this idx
|
||||
*/
|
||||
struct driver_rt {
|
||||
struct udevice *dev;
|
||||
};
|
||||
|
||||
/**
|
||||
* NOTE: Avoid using these except in extreme circumstances, where device tree
|
||||
* is not feasible (e.g. serial driver in SPL where <8KB of SRAM is
|
||||
* available). U-Boot's driver model uses device tree for configuration.
|
||||
*
|
||||
* When of-platdata is in use, U_BOOT_DEVICE() cannot be used outside of the
|
||||
* dt-platdata.c file created by dtoc
|
||||
*/
|
||||
#if CONFIG_IS_ENABLED(OF_PLATDATA) && !defined(DT_PLATDATA_C)
|
||||
#define U_BOOT_DEVICE(__name) _Static_assert(false, \
|
||||
"Cannot use U_BOOT_DEVICE with of-platdata. Please use devicetree instead")
|
||||
#else
|
||||
#define U_BOOT_DEVICE(__name) \
|
||||
ll_entry_declare(struct driver_info, __name, driver_info)
|
||||
#endif
|
||||
|
||||
/* Declare a list of devices. The argument is a driver_info[] array */
|
||||
#define U_BOOT_DEVICES(__name) \
|
||||
ll_entry_declare_list(struct driver_info, __name, driver_info)
|
||||
|
||||
/* Get a pointer to a given driver */
|
||||
/**
|
||||
* Get a pointer to a given device info given its name
|
||||
*
|
||||
* With the declaration U_BOOT_DEVICE(name), DM_GET_DEVICE(name) will return a
|
||||
* pointer to the struct driver_info created by that declaration.
|
||||
*
|
||||
* if OF_PLATDATA is enabled, from this it is possible to use the @dev member of
|
||||
* struct driver_info to find the device pointer itself.
|
||||
*
|
||||
* TODO(sjg@chromium.org): U_BOOT_DEVICE() tells U-Boot to create a device, so
|
||||
* the naming seems sensible, but DM_GET_DEVICE() is a bit of misnomer, since it
|
||||
* finds the driver_info record, not the device.
|
||||
*
|
||||
* @__name: Driver name (C identifier, not a string. E.g. gpio7_at_ff7e0000)
|
||||
* @return struct driver_info * to the driver that created the device
|
||||
*/
|
||||
#define DM_GET_DEVICE(__name) \
|
||||
ll_entry_get(struct driver_info, __name, driver_info)
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#ifndef __DM_UTIL_H
|
||||
#define __DM_UTIL_H
|
||||
|
||||
#ifdef CONFIG_DM_WARN
|
||||
#if CONFIG_IS_ENABLED(DM_WARN)
|
||||
void dm_warn(const char *fmt, ...);
|
||||
#else
|
||||
static inline void dm_warn(const char *fmt, ...)
|
||||
|
|
|
@ -8,18 +8,20 @@
|
|||
|
||||
/* These structures may only be used in SPL */
|
||||
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
struct driver_info;
|
||||
|
||||
struct phandle_0_arg {
|
||||
const void *node;
|
||||
uint idx;
|
||||
int arg[0];
|
||||
};
|
||||
|
||||
struct phandle_1_arg {
|
||||
const void *node;
|
||||
uint idx;
|
||||
int arg[1];
|
||||
};
|
||||
|
||||
struct phandle_2_arg {
|
||||
const void *node;
|
||||
uint idx;
|
||||
int arg[2];
|
||||
};
|
||||
#include <generated/dt-structs-gen.h>
|
||||
|
|
|
@ -94,4 +94,15 @@ enum {
|
|||
TEST_DEVRES_SIZE3 = 37,
|
||||
};
|
||||
|
||||
/**
|
||||
* dm_test_main() - Run driver model tests
|
||||
*
|
||||
* Run all the available driver model tests, or a selection
|
||||
*
|
||||
* @test_name: Name of single test to run (e.g. "dm_test_fdt_pre_reloc" or just
|
||||
* "fdt_pre_reloc"), or NULL to run all
|
||||
* @return 0 if all tests passed, 1 if not
|
||||
*/
|
||||
int dm_test_main(const char *test_name);
|
||||
|
||||
#endif /* __TEST_TEST_H */
|
||||
|
|
14
lib/binman.c
14
lib/binman.c
|
@ -43,7 +43,7 @@ static int binman_entry_find_internal(ofnode node, const char *name,
|
|||
|
||||
ret = ofnode_read_u32(node, "image-pos", &entry->image_pos);
|
||||
if (ret)
|
||||
return log_msg_ret("import-pos", ret);
|
||||
return log_msg_ret("image-pos", ret);
|
||||
ret = ofnode_read_u32(node, "size", &entry->size);
|
||||
if (ret)
|
||||
return log_msg_ret("size", ret);
|
||||
|
@ -83,6 +83,11 @@ void binman_set_rom_offset(int rom_offset)
|
|||
binman->rom_offset = rom_offset;
|
||||
}
|
||||
|
||||
int binman_get_rom_offset(void)
|
||||
{
|
||||
return binman->rom_offset;
|
||||
}
|
||||
|
||||
int binman_init(void)
|
||||
{
|
||||
binman = malloc(sizeof(struct binman_info));
|
||||
|
@ -91,6 +96,13 @@ int binman_init(void)
|
|||
binman->image = ofnode_path("/binman");
|
||||
if (!ofnode_valid(binman->image))
|
||||
return log_msg_ret("binman node", -EINVAL);
|
||||
if (ofnode_read_bool(binman->image, "multiple-images")) {
|
||||
ofnode node = ofnode_first_subnode(binman->image);
|
||||
|
||||
if (!ofnode_valid(node))
|
||||
return log_msg_ret("first image", -ENOENT);
|
||||
binman->image = node;
|
||||
}
|
||||
binman->rom_offset = ROM_OFFSET_NONE;
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -99,6 +99,7 @@ libs-y += dts/
|
|||
libs-y += fs/
|
||||
libs-$(CONFIG_SPL_POST_MEM_SUPPORT) += post/drivers/
|
||||
libs-$(CONFIG_SPL_NET_SUPPORT) += net/
|
||||
libs-$(CONFIG_SPL_UNIT_TEST) += test/
|
||||
|
||||
head-y := $(addprefix $(obj)/,$(head-y))
|
||||
libs-y := $(addprefix $(obj)/,$(libs-y))
|
||||
|
@ -213,7 +214,7 @@ spl/boot.bin: $(obj)/$(SPL_BIN)-align.bin FORCE
|
|||
$(call if_changed,mkimage)
|
||||
endif
|
||||
|
||||
INPUTS-y += $(obj)/$(SPL_BIN).bin
|
||||
INPUTS-y += $(obj)/$(SPL_BIN).bin $(obj)/$(SPL_BIN).sym
|
||||
|
||||
ifdef CONFIG_SAMSUNG
|
||||
INPUTS-y += $(obj)/$(BOARD)-spl.bin
|
||||
|
@ -407,6 +408,11 @@ MKIMAGEFLAGS_u-boot-spl-mtk.bin = -T mtk_image \
|
|||
$(obj)/u-boot-spl-mtk.bin: $(obj)/u-boot-spl.bin FORCE
|
||||
$(call if_changed,mkimage)
|
||||
|
||||
quiet_cmd_sym ?= SYM $@
|
||||
cmd_sym ?= $(OBJDUMP) -t $< > $@
|
||||
$(obj)/$(SPL_BIN).sym: $(obj)/$(SPL_BIN) FORCE
|
||||
$(call if_changed,sym)
|
||||
|
||||
# Rule to link u-boot-spl
|
||||
# May be overridden by arch/$(ARCH)/config.mk
|
||||
quiet_cmd_u-boot-spl ?= LD $@
|
||||
|
|
10
test/Kconfig
10
test/Kconfig
|
@ -6,6 +6,16 @@ menuconfig UNIT_TEST
|
|||
This does not require sandbox to be included, but it is most
|
||||
often used there.
|
||||
|
||||
config SPL_UNIT_TEST
|
||||
bool "Unit tests in SPL"
|
||||
# We need to be able to unbind devices for tests to work
|
||||
select SPL_DM_DEVICE_REMOVE
|
||||
help
|
||||
Select this to enable unit tests in SPL. Most test are designed for
|
||||
running in U-Boot proper, but some are intended for SPL, such as
|
||||
of-platdata and SPL handover. To run these tests with the sandbox_spl
|
||||
board, use the -u (unit test) option.
|
||||
|
||||
config UT_LIB
|
||||
bool "Unit tests for library functions"
|
||||
depends on UNIT_TEST
|
||||
|
|
|
@ -2,15 +2,19 @@
|
|||
#
|
||||
# (C) Copyright 2012 The Chromium Authors
|
||||
|
||||
obj-$(CONFIG_SANDBOX) += bloblist.o
|
||||
obj-$(CONFIG_CMDLINE) += cmd/
|
||||
obj-$(CONFIG_UNIT_TEST) += cmd_ut.o
|
||||
obj-$(CONFIG_UNIT_TEST) += ut.o
|
||||
obj-$(CONFIG_SANDBOX) += command_ut.o
|
||||
obj-$(CONFIG_SANDBOX) += compression.o
|
||||
obj-$(CONFIG_SANDBOX) += print_ut.o
|
||||
obj-$(CONFIG_SANDBOX) += str_ut.o
|
||||
obj-$(CONFIG_$(SPL_)CMDLINE) += bloblist.o
|
||||
obj-$(CONFIG_$(SPL_)CMDLINE) += cmd/
|
||||
obj-$(CONFIG_$(SPL_)CMDLINE) += cmd_ut.o
|
||||
obj-$(CONFIG_$(SPL_)CMDLINE) += command_ut.o
|
||||
obj-$(CONFIG_$(SPL_)CMDLINE) += compression.o
|
||||
obj-y += dm/
|
||||
obj-$(CONFIG_$(SPL_)CMDLINE) += print_ut.o
|
||||
obj-$(CONFIG_$(SPL_)CMDLINE) += str_ut.o
|
||||
obj-$(CONFIG_UT_TIME) += time_ut.o
|
||||
obj-$(CONFIG_UT_UNICODE) += unicode_ut.o
|
||||
obj-y += log/
|
||||
obj-y += ut.o
|
||||
|
||||
ifeq ($(CONFIG_SPL_BUILD),)
|
||||
obj-$(CONFIG_UNIT_TEST) += lib/
|
||||
obj-y += log/
|
||||
obj-$(CONFIG_$(SPL_)UT_UNICODE) += unicode_ut.o
|
||||
endif
|
||||
|
|
|
@ -2,15 +2,18 @@
|
|||
#
|
||||
# Copyright (c) 2013 Google, Inc
|
||||
|
||||
obj-$(CONFIG_UT_DM) += bus.o
|
||||
obj-$(CONFIG_UT_DM) += nop.o
|
||||
obj-$(CONFIG_UT_DM) += test-driver.o
|
||||
obj-$(CONFIG_UT_DM) += test-fdt.o
|
||||
obj-$(CONFIG_UT_DM) += test-main.o
|
||||
obj-$(CONFIG_UT_DM) += test-uclass.o
|
||||
|
||||
# Tests for particular subsystems - when enabling driver model for a new
|
||||
# subsystem you must add sandbox tests here.
|
||||
ifeq ($(CONFIG_SPL_BUILD),y)
|
||||
obj-$(CONFIG_SPL_OF_PLATDATA) += of_platdata.o
|
||||
else
|
||||
obj-$(CONFIG_UT_DM) += bus.o
|
||||
obj-$(CONFIG_UT_DM) += test-driver.o
|
||||
obj-$(CONFIG_UT_DM) += test-fdt.o
|
||||
obj-$(CONFIG_UT_DM) += test-uclass.o
|
||||
|
||||
obj-$(CONFIG_UT_DM) += core.o
|
||||
ifneq ($(CONFIG_SANDBOX),)
|
||||
obj-$(CONFIG_ACPIGEN) += acpi.o
|
||||
|
@ -36,6 +39,7 @@ obj-$(CONFIG_DM_MAILBOX) += mailbox.o
|
|||
obj-$(CONFIG_DM_MMC) += mmc.o
|
||||
obj-$(CONFIG_CMD_MUX) += mux-cmd.o
|
||||
obj-y += fdtdec.o
|
||||
obj-$(CONFIG_UT_DM) += nop.o
|
||||
obj-y += ofnode.o
|
||||
obj-y += ofread.o
|
||||
obj-$(CONFIG_OSD) += osd.o
|
||||
|
@ -88,3 +92,4 @@ ifneq ($(CONFIG_PINMUX),)
|
|||
obj-$(CONFIG_PINCONF) += pinmux.o
|
||||
endif
|
||||
endif
|
||||
endif # !SPL
|
||||
|
|
222
test/dm/of_platdata.c
Normal file
222
test/dm/of_platdata.c
Normal file
|
@ -0,0 +1,222 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <dt-structs.h>
|
||||
#include <dm/test.h>
|
||||
#include <test/test.h>
|
||||
#include <test/ut.h>
|
||||
|
||||
/* Test that we can find a device using of-platdata */
|
||||
static int dm_test_of_platdata_base(struct unit_test_state *uts)
|
||||
{
|
||||
struct udevice *dev;
|
||||
|
||||
ut_assertok(uclass_first_device_err(UCLASS_SERIAL, &dev));
|
||||
ut_asserteq_str("sandbox_serial", dev->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
DM_TEST(dm_test_of_platdata_base, UT_TESTF_SCAN_PDATA);
|
||||
|
||||
/* Test that we can read properties from a device */
|
||||
static int dm_test_of_platdata_props(struct unit_test_state *uts)
|
||||
{
|
||||
struct dtd_sandbox_spl_test *plat;
|
||||
struct udevice *dev;
|
||||
int i;
|
||||
|
||||
/* Skip the clock */
|
||||
ut_assertok(uclass_first_device_err(UCLASS_MISC, &dev));
|
||||
ut_asserteq_str("sandbox_clk_test", dev->name);
|
||||
|
||||
ut_assertok(uclass_next_device_err(&dev));
|
||||
plat = dev_get_platdata(dev);
|
||||
ut_assert(plat->boolval);
|
||||
ut_asserteq(1, plat->intval);
|
||||
ut_asserteq(4, ARRAY_SIZE(plat->intarray));
|
||||
ut_asserteq(2, plat->intarray[0]);
|
||||
ut_asserteq(3, plat->intarray[1]);
|
||||
ut_asserteq(4, plat->intarray[2]);
|
||||
ut_asserteq(0, plat->intarray[3]);
|
||||
ut_asserteq(5, plat->byteval);
|
||||
ut_asserteq(3, ARRAY_SIZE(plat->bytearray));
|
||||
ut_asserteq(6, plat->bytearray[0]);
|
||||
ut_asserteq(0, plat->bytearray[1]);
|
||||
ut_asserteq(0, plat->bytearray[2]);
|
||||
ut_asserteq(9, ARRAY_SIZE(plat->longbytearray));
|
||||
for (i = 0; i < ARRAY_SIZE(plat->longbytearray); i++)
|
||||
ut_asserteq(9 + i, plat->longbytearray[i]);
|
||||
ut_asserteq_str("message", plat->stringval);
|
||||
ut_asserteq(3, ARRAY_SIZE(plat->stringarray));
|
||||
ut_asserteq_str("multi-word", plat->stringarray[0]);
|
||||
ut_asserteq_str("message", plat->stringarray[1]);
|
||||
ut_asserteq_str("", plat->stringarray[2]);
|
||||
|
||||
ut_assertok(uclass_next_device_err(&dev));
|
||||
plat = dev_get_platdata(dev);
|
||||
ut_assert(!plat->boolval);
|
||||
ut_asserteq(3, plat->intval);
|
||||
ut_asserteq(5, plat->intarray[0]);
|
||||
ut_asserteq(0, plat->intarray[1]);
|
||||
ut_asserteq(0, plat->intarray[2]);
|
||||
ut_asserteq(0, plat->intarray[3]);
|
||||
ut_asserteq(8, plat->byteval);
|
||||
ut_asserteq(3, ARRAY_SIZE(plat->bytearray));
|
||||
ut_asserteq(1, plat->bytearray[0]);
|
||||
ut_asserteq(0x23, plat->bytearray[1]);
|
||||
ut_asserteq(0x34, plat->bytearray[2]);
|
||||
for (i = 0; i < ARRAY_SIZE(plat->longbytearray); i++)
|
||||
ut_asserteq(i < 4 ? 9 + i : 0, plat->longbytearray[i]);
|
||||
ut_asserteq_str("message2", plat->stringval);
|
||||
ut_asserteq_str("another", plat->stringarray[0]);
|
||||
ut_asserteq_str("multi-word", plat->stringarray[1]);
|
||||
ut_asserteq_str("message", plat->stringarray[2]);
|
||||
|
||||
ut_assertok(uclass_next_device_err(&dev));
|
||||
plat = dev_get_platdata(dev);
|
||||
ut_assert(!plat->boolval);
|
||||
ut_asserteq_str("one", plat->stringarray[0]);
|
||||
ut_asserteq_str("", plat->stringarray[1]);
|
||||
ut_asserteq_str("", plat->stringarray[2]);
|
||||
|
||||
ut_assertok(uclass_next_device_err(&dev));
|
||||
plat = dev_get_platdata(dev);
|
||||
ut_assert(!plat->boolval);
|
||||
ut_asserteq_str("spl", plat->stringarray[0]);
|
||||
|
||||
ut_asserteq(-ENODEV, uclass_next_device_err(&dev));
|
||||
|
||||
return 0;
|
||||
}
|
||||
DM_TEST(dm_test_of_platdata_props, UT_TESTF_SCAN_PDATA);
|
||||
|
||||
/*
|
||||
* find_driver_info - recursively find the driver_info for a device
|
||||
*
|
||||
* This sets found[idx] to true when it finds the driver_info record for a
|
||||
* device, where idx is the index in the driver_info linker list.
|
||||
*
|
||||
* @uts: Test state
|
||||
* @parent: Parent to search
|
||||
* @found: bool array to update
|
||||
* @return 0 if OK, non-zero on error
|
||||
*/
|
||||
static int find_driver_info(struct unit_test_state *uts, struct udevice *parent,
|
||||
bool found[])
|
||||
{
|
||||
struct udevice *dev;
|
||||
|
||||
/* If not the root device, find the entry that caused it to be bound */
|
||||
if (parent->parent) {
|
||||
const int n_ents =
|
||||
ll_entry_count(struct driver_info, driver_info);
|
||||
int idx = -1;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n_ents; i++) {
|
||||
const struct driver_rt *drt = gd_dm_driver_rt() + i;
|
||||
|
||||
if (drt->dev == parent) {
|
||||
idx = i;
|
||||
found[idx] = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ut_assert(idx != -1);
|
||||
}
|
||||
|
||||
device_foreach_child(dev, parent) {
|
||||
int ret;
|
||||
|
||||
ret = find_driver_info(uts, dev, found);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check that every device is recorded in its driver_info struct */
|
||||
static int dm_test_of_platdata_dev(struct unit_test_state *uts)
|
||||
{
|
||||
const struct driver_info *info =
|
||||
ll_entry_start(struct driver_info, driver_info);
|
||||
const int n_ents = ll_entry_count(struct driver_info, driver_info);
|
||||
bool found[n_ents];
|
||||
uint i;
|
||||
|
||||
/* Record the indexes that are found */
|
||||
memset(found, '\0', sizeof(found));
|
||||
ut_assertok(find_driver_info(uts, gd->dm_root, found));
|
||||
|
||||
/* Make sure that the driver entries without devices have no ->dev */
|
||||
for (i = 0; i < n_ents; i++) {
|
||||
const struct driver_rt *drt = gd_dm_driver_rt() + i;
|
||||
const struct driver_info *entry = info + i;
|
||||
struct udevice *dev;
|
||||
|
||||
if (found[i]) {
|
||||
/* Make sure we can find it */
|
||||
ut_assertnonnull(drt->dev);
|
||||
ut_assertok(device_get_by_driver_info(entry, &dev));
|
||||
ut_asserteq_ptr(dev, drt->dev);
|
||||
} else {
|
||||
ut_assertnull(drt->dev);
|
||||
ut_asserteq(-ENOENT,
|
||||
device_get_by_driver_info(entry, &dev));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
DM_TEST(dm_test_of_platdata_dev, UT_TESTF_SCAN_PDATA);
|
||||
|
||||
/* Test handling of phandles that point to other devices */
|
||||
static int dm_test_of_platdata_phandle(struct unit_test_state *uts)
|
||||
{
|
||||
struct dtd_sandbox_clk_test *plat;
|
||||
struct udevice *dev, *clk;
|
||||
|
||||
ut_assertok(uclass_first_device_err(UCLASS_MISC, &dev));
|
||||
ut_asserteq_str("sandbox_clk_test", dev->name);
|
||||
plat = dev_get_platdata(dev);
|
||||
|
||||
ut_assertok(device_get_by_driver_info_idx(plat->clocks[0].idx, &clk));
|
||||
ut_asserteq_str("fixed_clock", clk->name);
|
||||
|
||||
ut_assertok(device_get_by_driver_info_idx(plat->clocks[1].idx, &clk));
|
||||
ut_asserteq_str("sandbox_clk", clk->name);
|
||||
ut_asserteq(1, plat->clocks[1].arg[0]);
|
||||
|
||||
ut_assertok(device_get_by_driver_info_idx(plat->clocks[2].idx, &clk));
|
||||
ut_asserteq_str("sandbox_clk", clk->name);
|
||||
ut_asserteq(0, plat->clocks[2].arg[0]);
|
||||
|
||||
ut_assertok(device_get_by_driver_info_idx(plat->clocks[3].idx, &clk));
|
||||
ut_asserteq_str("sandbox_clk", clk->name);
|
||||
ut_asserteq(3, plat->clocks[3].arg[0]);
|
||||
|
||||
ut_assertok(device_get_by_driver_info_idx(plat->clocks[4].idx, &clk));
|
||||
ut_asserteq_str("sandbox_clk", clk->name);
|
||||
ut_asserteq(2, plat->clocks[4].arg[0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
DM_TEST(dm_test_of_platdata_phandle, UT_TESTF_SCAN_PDATA);
|
||||
|
||||
#if CONFIG_IS_ENABLED(OF_PLATDATA_PARENT)
|
||||
/* Test that device parents are correctly set up */
|
||||
static int dm_test_of_platdata_parent(struct unit_test_state *uts)
|
||||
{
|
||||
struct udevice *rtc, *i2c;
|
||||
|
||||
ut_assertok(uclass_first_device_err(UCLASS_RTC, &rtc));
|
||||
ut_assertok(uclass_first_device_err(UCLASS_I2C, &i2c));
|
||||
ut_asserteq_ptr(i2c, dev_get_parent(rtc));
|
||||
|
||||
return 0;
|
||||
}
|
||||
DM_TEST(dm_test_of_platdata_parent, UT_TESTF_SCAN_PDATA);
|
||||
#endif
|
|
@ -30,13 +30,12 @@ static int dm_test_init(struct unit_test_state *uts, bool of_live)
|
|||
|
||||
memset(dms, '\0', sizeof(*dms));
|
||||
gd->dm_root = NULL;
|
||||
if (!CONFIG_IS_ENABLED(OF_PLATDATA))
|
||||
memset(dm_testdrv_op_count, '\0', sizeof(dm_testdrv_op_count));
|
||||
state_reset_for_test(state_get_current());
|
||||
|
||||
#ifdef CONFIG_OF_LIVE
|
||||
/* Determine whether to make the live tree available */
|
||||
gd->of_root = of_live ? uts->of_root : NULL;
|
||||
#endif
|
||||
gd_set_of_root(of_live ? uts->of_root : NULL);
|
||||
ut_assertok(dm_init(of_live));
|
||||
dms->root = dm_root();
|
||||
|
||||
|
@ -93,7 +92,8 @@ static int dm_do_test(struct unit_test_state *uts, struct unit_test *test,
|
|||
ut_assertok(dm_scan_platdata(false));
|
||||
if (test->flags & UT_TESTF_PROBE_TEST)
|
||||
ut_assertok(do_autoprobe(uts));
|
||||
if (test->flags & UT_TESTF_SCAN_FDT)
|
||||
if (!CONFIG_IS_ENABLED(OF_PLATDATA) &&
|
||||
(test->flags & UT_TESTF_SCAN_FDT))
|
||||
ut_assertok(dm_extended_scan_fdt(gd->fdt_blob, false));
|
||||
|
||||
/*
|
||||
|
@ -127,7 +127,25 @@ static bool dm_test_run_on_flattree(struct unit_test *test)
|
|||
return !strstr(fname, "video") || strstr(test->name, "video_base");
|
||||
}
|
||||
|
||||
static int dm_test_main(const char *test_name)
|
||||
static bool test_matches(const char *test_name, const char *find_name)
|
||||
{
|
||||
if (!find_name)
|
||||
return true;
|
||||
|
||||
if (!strcmp(test_name, find_name))
|
||||
return true;
|
||||
|
||||
/* All tests have this prefix */
|
||||
if (!strncmp(test_name, "dm_test_", 8))
|
||||
test_name += 8;
|
||||
|
||||
if (!strcmp(test_name, find_name))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int dm_test_main(const char *test_name)
|
||||
{
|
||||
struct unit_test *tests = ll_entry_start(struct unit_test, dm_test);
|
||||
const int n_ents = ll_entry_count(struct unit_test, dm_test);
|
||||
|
@ -138,36 +156,34 @@ static int dm_test_main(const char *test_name)
|
|||
uts->priv = &_global_priv_dm_test_state;
|
||||
uts->fail_count = 0;
|
||||
|
||||
if (!CONFIG_IS_ENABLED(OF_PLATDATA)) {
|
||||
/*
|
||||
* If we have no device tree, or it only has a root node, then these
|
||||
* tests clearly aren't going to work...
|
||||
* If we have no device tree, or it only has a root node, then
|
||||
* these * tests clearly aren't going to work...
|
||||
*/
|
||||
if (!gd->fdt_blob || fdt_next_node(gd->fdt_blob, 0, NULL) < 0) {
|
||||
puts("Please run with test device tree:\n"
|
||||
" ./u-boot -d arch/sandbox/dts/test.dtb\n");
|
||||
ut_assert(gd->fdt_blob);
|
||||
}
|
||||
}
|
||||
|
||||
if (!test_name)
|
||||
printf("Running %d driver model tests\n", n_ents);
|
||||
else
|
||||
|
||||
found = 0;
|
||||
#ifdef CONFIG_OF_LIVE
|
||||
uts->of_root = gd->of_root;
|
||||
#endif
|
||||
uts->of_root = gd_of_root();
|
||||
for (test = tests; test < tests + n_ents; test++) {
|
||||
const char *name = test->name;
|
||||
int runs;
|
||||
|
||||
/* All tests have this prefix */
|
||||
if (!strncmp(name, "dm_test_", 8))
|
||||
name += 8;
|
||||
if (test_name && strcmp(test_name, name))
|
||||
if (!test_matches(name, test_name))
|
||||
continue;
|
||||
|
||||
/* Run with the live tree if possible */
|
||||
runs = 0;
|
||||
if (IS_ENABLED(CONFIG_OF_LIVE)) {
|
||||
if (CONFIG_IS_ENABLED(OF_LIVE)) {
|
||||
if (!(test->flags & UT_TESTF_FLAT_TREE)) {
|
||||
ut_assertok(dm_do_test(uts, test, true));
|
||||
runs++;
|
||||
|
@ -192,12 +208,11 @@ static int dm_test_main(const char *test_name)
|
|||
printf("Failures: %d\n", uts->fail_count);
|
||||
|
||||
/* Put everything back to normal so that sandbox works as expected */
|
||||
#ifdef CONFIG_OF_LIVE
|
||||
gd->of_root = uts->of_root;
|
||||
#endif
|
||||
gd_set_of_root(uts->of_root);
|
||||
gd->dm_root = NULL;
|
||||
ut_assertok(dm_init(IS_ENABLED(CONFIG_OF_LIVE)));
|
||||
ut_assertok(dm_init(CONFIG_IS_ENABLED(OF_LIVE)));
|
||||
dm_scan_platdata(false);
|
||||
if (!CONFIG_IS_ENABLED(OF_PLATDATA))
|
||||
dm_scan_fdt(gd->fdt_blob, false);
|
||||
|
||||
return uts->fail_count ? CMD_RET_FAILURE : 0;
|
||||
|
|
|
@ -227,7 +227,7 @@ def pytest_configure(config):
|
|||
console = u_boot_console_exec_attach.ConsoleExecAttach(log, ubconfig)
|
||||
|
||||
re_ut_test_list = re.compile(r'_u_boot_list_2_(.*)_test_2_\1_test_(.*)\s*$')
|
||||
def generate_ut_subtest(metafunc, fixture_name):
|
||||
def generate_ut_subtest(metafunc, fixture_name, sym_path):
|
||||
"""Provide parametrization for a ut_subtest fixture.
|
||||
|
||||
Determines the set of unit tests built into a U-Boot binary by parsing the
|
||||
|
@ -237,12 +237,13 @@ def generate_ut_subtest(metafunc, fixture_name):
|
|||
Args:
|
||||
metafunc: The pytest test function.
|
||||
fixture_name: The fixture name to test.
|
||||
sym_path: Relative path to the symbol file with preceding '/'
|
||||
(e.g. '/u-boot.sym')
|
||||
|
||||
Returns:
|
||||
Nothing.
|
||||
"""
|
||||
|
||||
fn = console.config.build_dir + '/u-boot.sym'
|
||||
fn = console.config.build_dir + sym_path
|
||||
try:
|
||||
with open(fn, 'rt') as f:
|
||||
lines = f.readlines()
|
||||
|
@ -317,10 +318,12 @@ def pytest_generate_tests(metafunc):
|
|||
Returns:
|
||||
Nothing.
|
||||
"""
|
||||
|
||||
for fn in metafunc.fixturenames:
|
||||
if fn == 'ut_subtest':
|
||||
generate_ut_subtest(metafunc, fn)
|
||||
generate_ut_subtest(metafunc, fn, '/u-boot.sym')
|
||||
continue
|
||||
if fn == 'ut_spl_subtest':
|
||||
generate_ut_subtest(metafunc, fn, '/spl/u-boot-spl.sym')
|
||||
continue
|
||||
generate_config(metafunc, fn)
|
||||
|
||||
|
|
|
@ -4,53 +4,6 @@
|
|||
import pytest
|
||||
import u_boot_utils as util
|
||||
|
||||
OF_PLATDATA_OUTPUT = '''
|
||||
of-platdata probe:
|
||||
bool 1
|
||||
byte 05
|
||||
bytearray 06 00 00
|
||||
int 1
|
||||
intarray 2 3 4 0
|
||||
longbytearray 09 0a 0b 0c 0d 0e 0f 10 11
|
||||
string message
|
||||
stringarray "multi-word" "message" ""
|
||||
of-platdata probe:
|
||||
bool 0
|
||||
byte 08
|
||||
bytearray 01 23 34
|
||||
int 3
|
||||
intarray 5 0 0 0
|
||||
longbytearray 09 00 00 00 00 00 00 00 00
|
||||
string message2
|
||||
stringarray "another" "multi-word" "message"
|
||||
of-platdata probe:
|
||||
bool 0
|
||||
byte 00
|
||||
bytearray 00 00 00
|
||||
int 0
|
||||
intarray 0 0 0 0
|
||||
longbytearray 00 00 00 00 00 00 00 00 00
|
||||
string <NULL>
|
||||
stringarray "one" "" ""
|
||||
of-platdata probe:
|
||||
bool 0
|
||||
byte 00
|
||||
bytearray 00 00 00
|
||||
int 0
|
||||
intarray 0 0 0 0
|
||||
longbytearray 00 00 00 00 00 00 00 00 00
|
||||
string <NULL>
|
||||
stringarray "spl" "" ""
|
||||
'''
|
||||
|
||||
@pytest.mark.buildconfigspec('spl_of_platdata')
|
||||
def test_ofplatdata(u_boot_console):
|
||||
"""Test that of-platdata can be generated and used in sandbox"""
|
||||
cons = u_boot_console
|
||||
cons.restart_uboot_with_flags(['--show_of_platdata'])
|
||||
output = cons.get_spawn_output().replace('\r', '')
|
||||
assert OF_PLATDATA_OUTPUT in output
|
||||
|
||||
@pytest.mark.buildconfigspec('spl_of_platdata')
|
||||
def test_spl_devicetree(u_boot_console):
|
||||
"""Test content of spl device-tree"""
|
||||
|
|
34
test/py/tests/test_spl.py
Normal file
34
test/py/tests/test_spl.py
Normal file
|
@ -0,0 +1,34 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Copyright 2020 Google LLC
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
|
||||
import os.path
|
||||
import pytest
|
||||
|
||||
def test_spl(u_boot_console, ut_spl_subtest):
|
||||
"""Execute a "ut" subtest.
|
||||
|
||||
The subtests are collected in function generate_ut_subtest() from linker
|
||||
generated lists by applying a regular expression to the lines of file
|
||||
spl/u-boot-spl.sym. The list entries are created using the C macro
|
||||
UNIT_TEST().
|
||||
|
||||
Strict naming conventions have to be followed to match the regular
|
||||
expression. Use UNIT_TEST(foo_test_bar, _flags, foo_test) for a test bar in
|
||||
test suite foo that can be executed via command 'ut foo bar' and is
|
||||
implemented in C function foo_test_bar().
|
||||
|
||||
Args:
|
||||
u_boot_console (ConsoleBase): U-Boot console
|
||||
ut_subtest (str): SPL test to be executed (e.g. 'dm platdata_phandle')
|
||||
"""
|
||||
try:
|
||||
cons = u_boot_console
|
||||
cons.restart_uboot_with_flags(['-u', '-k', ut_spl_subtest.split()[1]])
|
||||
output = cons.get_spawn_output().replace('\r', '')
|
||||
assert 'Failures: 0' in output
|
||||
finally:
|
||||
# Restart afterward in case a non-SPL test is run next. This should not
|
||||
# happen since SPL tests are run in their own invocation of test.py, but
|
||||
# the cost of doing this is not too great at present.
|
||||
u_boot_console.restart_uboot()
|
2
test/run
2
test/run
|
@ -28,7 +28,7 @@ fi
|
|||
|
||||
# Run tests which require sandbox_spl
|
||||
run_test "sandbox_spl" ./test/py/test.py --bd sandbox_spl --build \
|
||||
-k 'test_ofplatdata or test_handoff'
|
||||
-k 'test_ofplatdata or test_handoff or test_spl'
|
||||
|
||||
if [ -z "$tools_only" ]; then
|
||||
# Run tests for the flat-device-tree version of sandbox. This is a special
|
||||
|
|
|
@ -278,9 +278,12 @@ offset:
|
|||
|
||||
align:
|
||||
This sets the alignment of the entry. The entry offset is adjusted
|
||||
so that the entry starts on an aligned boundary within the image. For
|
||||
example 'align = <16>' means that the entry will start on a 16-byte
|
||||
boundary. Alignment shold be a power of 2. If 'align' is not
|
||||
so that the entry starts on an aligned boundary within the containing
|
||||
section or image. For example 'align = <16>' means that the entry will
|
||||
start on a 16-byte boundary. This may mean that padding is added before
|
||||
the entry. The padding is part of the containing section but is not
|
||||
included in the entry, meaning that an empty space may be created before
|
||||
the entry starts. Alignment should be a power of 2. If 'align' is not
|
||||
provided, no alignment is performed.
|
||||
|
||||
size:
|
||||
|
@ -290,26 +293,40 @@ size:
|
|||
|
||||
pad-before:
|
||||
Padding before the contents of the entry. Normally this is 0, meaning
|
||||
that the contents start at the beginning of the entry. This can be
|
||||
offset the entry contents a little. Defaults to 0.
|
||||
that the contents start at the beginning of the entry. This can be used
|
||||
to offset the entry contents a little. While this does not affect the
|
||||
contents of the entry within binman itself (the padding is performed
|
||||
only when its parent section is assembled), the end result will be that
|
||||
the entry starts with the padding bytes, so may grow. Defaults to 0.
|
||||
|
||||
pad-after:
|
||||
Padding after the contents of the entry. Normally this is 0, meaning
|
||||
that the entry ends at the last byte of content (unless adjusted by
|
||||
other properties). This allows room to be created in the image for
|
||||
this entry to expand later. Defaults to 0.
|
||||
this entry to expand later. While this does not affect the contents of
|
||||
the entry within binman itself (the padding is performed only when its
|
||||
parent section is assembled), the end result will be that the entry ends
|
||||
with the padding bytes, so may grow. Defaults to 0.
|
||||
|
||||
align-size:
|
||||
This sets the alignment of the entry size. For example, to ensure
|
||||
that the size of an entry is a multiple of 64 bytes, set this to 64.
|
||||
If 'align-size' is not provided, no alignment is performed.
|
||||
While this does not affect the contents of the entry within binman
|
||||
itself (the padding is performed only when its parent section is
|
||||
assembled), the end result is that the entry ends with the padding
|
||||
bytes, so may grow. If 'align-size' is not provided, no alignment is
|
||||
performed.
|
||||
|
||||
align-end:
|
||||
This sets the alignment of the end of an entry. Some entries require
|
||||
that they end on an alignment boundary, regardless of where they
|
||||
start. This does not move the start of the entry, so the contents of
|
||||
the entry will still start at the beginning. But there may be padding
|
||||
at the end. If 'align-end' is not provided, no alignment is performed.
|
||||
This sets the alignment of the end of an entry with respect to the
|
||||
containing section. Some entries require that they end on an alignment
|
||||
boundary, regardless of where they start. This does not move the start
|
||||
of the entry, so the contents of the entry will still start at the
|
||||
beginning. But there may be padding at the end. While this does not
|
||||
affect the contents of the entry within binman itself (the padding is
|
||||
performed only when its parent section is assembled), the end result
|
||||
is that the entry ends with the padding bytes, so may grow.
|
||||
If 'align-end' is not provided, no alignment is performed.
|
||||
|
||||
filename:
|
||||
For 'blob' types this provides the filename containing the binary to
|
||||
|
@ -695,41 +712,38 @@ size of an entry. The 'current' image offset is passed in, and the function
|
|||
returns the offset immediately after the entry being packed. The default
|
||||
implementation of Pack() is usually sufficient.
|
||||
|
||||
6. CheckSize() - checks that the contents of all the entries fits within
|
||||
the image size. If the image does not have a defined size, the size is set
|
||||
large enough to hold all the entries.
|
||||
Note: for sections, this also checks that the entries do not overlap, nor extend
|
||||
outside the section. If the section does not have a defined size, the size is
|
||||
set large enough to hold all the entries.
|
||||
|
||||
7. CheckEntries() - checks that the entries do not overlap, nor extend
|
||||
outside the image.
|
||||
|
||||
8. SetImagePos() - sets the image position of every entry. This is the absolute
|
||||
6. SetImagePos() - sets the image position of every entry. This is the absolute
|
||||
position 'image-pos', as opposed to 'offset' which is relative to the containing
|
||||
section. This must be done after all offsets are known, which is why it is quite
|
||||
late in the ordering.
|
||||
|
||||
9. SetCalculatedProperties() - update any calculated properties in the device
|
||||
7. SetCalculatedProperties() - update any calculated properties in the device
|
||||
tree. This sets the correct 'offset' and 'size' vaues, for example.
|
||||
|
||||
10. ProcessEntryContents() - this calls Entry.ProcessContents() on each entry.
|
||||
8. ProcessEntryContents() - this calls Entry.ProcessContents() on each entry.
|
||||
The default implementatoin does nothing. This can be overriden to adjust the
|
||||
contents of an entry in some way. For example, it would be possible to create
|
||||
an entry containing a hash of the contents of some other entries. At this
|
||||
stage the offset and size of entries should not be adjusted unless absolutely
|
||||
necessary, since it requires a repack (going back to PackEntries()).
|
||||
|
||||
11. ResetForPack() - if the ProcessEntryContents() step failed, in that an entry
|
||||
9. ResetForPack() - if the ProcessEntryContents() step failed, in that an entry
|
||||
has changed its size, then there is no alternative but to go back to step 5 and
|
||||
try again, repacking the entries with the updated size. ResetForPack() removes
|
||||
the fixed offset/size values added by binman, so that the packing can start from
|
||||
scratch.
|
||||
|
||||
12. WriteSymbols() - write the value of symbols into the U-Boot SPL binary.
|
||||
10. WriteSymbols() - write the value of symbols into the U-Boot SPL binary.
|
||||
See 'Access to binman entry offsets at run time' below for a description of
|
||||
what happens in this stage.
|
||||
|
||||
13. BuildImage() - builds the image and writes it to a file
|
||||
11. BuildImage() - builds the image and writes it to a file
|
||||
|
||||
14. WriteMap() - writes a text file containing a map of the image. This is the
|
||||
12. WriteMap() - writes a text file containing a map of the image. This is the
|
||||
final step.
|
||||
|
||||
|
||||
|
@ -839,6 +853,14 @@ The entry will then contain the compressed data, using the 'lz4' compression
|
|||
algorithm. Currently this is the only one that is supported. The uncompressed
|
||||
size is written to the node in an 'uncomp-size' property, if -u is used.
|
||||
|
||||
Compression is also supported for sections. In that case the entire section is
|
||||
compressed in one block, including all its contents. This means that accessing
|
||||
an entry from the section required decompressing the entire section. Also, the
|
||||
size of a section indicates the space that it consumes in its parent section
|
||||
(and typically the image). With compression, the section may contain more data,
|
||||
and the uncomp-size property indicates that, as above. The contents of the
|
||||
section is compressed first, before any padding is added. This ensures that the
|
||||
padding itself is not compressed, which would be a waste of time.
|
||||
|
||||
|
||||
Map files
|
||||
|
|
|
@ -299,7 +299,7 @@ Entry: files: Entry containing a set of files
|
|||
|
||||
Properties / Entry arguments:
|
||||
- pattern: Filename pattern to match the files to include
|
||||
- compress: Compression algorithm to use:
|
||||
- files-compress: Compression algorithm to use:
|
||||
none: No compression
|
||||
lz4: Use lz4 compression (via 'lz4' command-line utility)
|
||||
|
||||
|
@ -406,6 +406,10 @@ The 'default' property, if present, will be automatically set to the name
|
|||
if of configuration whose devicetree matches the 'default-dt' entry
|
||||
argument, e.g. with '-a default-dt=sun50i-a64-pine64-lts'.
|
||||
|
||||
Available substitutions for '@' property values are:
|
||||
|
||||
DEFAULT-SEQ Sequence number of the default fdt,as provided by the
|
||||
'default-dt' entry argument
|
||||
|
||||
Properties (in the 'fit' node itself):
|
||||
fit,external-offset: Indicates that the contents of the FIT are external
|
||||
|
@ -739,6 +743,16 @@ placed at offset 'RESET_VECTOR_ADDRESS - 0xffc'.
|
|||
|
||||
|
||||
|
||||
Entry: scp: Entry containing a System Control Processor (SCP) firmware blob
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Properties / Entry arguments:
|
||||
- scp-path: Filename of file to read into the entry, typically scp.bin
|
||||
|
||||
This entry holds firmware for an external platform-specific coprocessor.
|
||||
|
||||
|
||||
|
||||
Entry: section: Entry that contains other entries
|
||||
-------------------------------------------------
|
||||
|
||||
|
@ -878,6 +892,15 @@ relocated to any address for execution.
|
|||
|
||||
|
||||
|
||||
Entry: u-boot-env: An entry which contains a U-Boot environment
|
||||
---------------------------------------------------------------
|
||||
|
||||
Properties / Entry arguments:
|
||||
- filename: File containing the environment text, with each line in the
|
||||
form var=value
|
||||
|
||||
|
||||
|
||||
Entry: u-boot-img: U-Boot legacy image
|
||||
--------------------------------------
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ controlled by a description in the board device tree.'''
|
|||
'3=info, 4=detail, 5=debug')
|
||||
|
||||
subparsers = parser.add_subparsers(dest='cmd')
|
||||
subparsers.required = True
|
||||
|
||||
build_parser = subparsers.add_parser('build', help='Build firmware image')
|
||||
build_parser.add_argument('-a', '--entry-arg', type=str, action='append',
|
||||
|
|
|
@ -462,7 +462,7 @@ def PrepareImagesAndDtbs(dtb_fname, select_images, update_fdt):
|
|||
for image in images.values():
|
||||
image.ExpandEntries()
|
||||
if update_fdt:
|
||||
image.AddMissingProperties()
|
||||
image.AddMissingProperties(True)
|
||||
image.ProcessFdt(dtb)
|
||||
|
||||
for dtb_item in state.GetAllFdts():
|
||||
|
@ -513,8 +513,6 @@ def ProcessImage(image, update_fdt, write_map, get_contents=True,
|
|||
for pack_pass in range(passes):
|
||||
try:
|
||||
image.PackEntries()
|
||||
image.CheckSize()
|
||||
image.CheckEntries()
|
||||
except Exception as e:
|
||||
if write_map:
|
||||
fname = image.WriteMap()
|
||||
|
|
|
@ -48,12 +48,22 @@ class Entry(object):
|
|||
uncomp_size: Size of uncompressed data in bytes, if the entry is
|
||||
compressed, else None
|
||||
contents_size: Size of contents in bytes, 0 by default
|
||||
align: Entry start offset alignment, or None
|
||||
align: Entry start offset alignment relative to the start of the
|
||||
containing section, or None
|
||||
align_size: Entry size alignment, or None
|
||||
align_end: Entry end offset alignment, or None
|
||||
pad_before: Number of pad bytes before the contents, 0 if none
|
||||
pad_after: Number of pad bytes after the contents, 0 if none
|
||||
data: Contents of entry (string of bytes)
|
||||
align_end: Entry end offset alignment relative to the start of the
|
||||
containing section, or None
|
||||
pad_before: Number of pad bytes before the contents when it is placed
|
||||
in the containing section, 0 if none. The pad bytes become part of
|
||||
the entry.
|
||||
pad_after: Number of pad bytes after the contents when it is placed in
|
||||
the containing section, 0 if none. The pad bytes become part of
|
||||
the entry.
|
||||
data: Contents of entry (string of bytes). This does not include
|
||||
padding created by pad_before or pad_after. If the entry is
|
||||
compressed, this contains the compressed data.
|
||||
uncomp_data: Original uncompressed data, if this entry is compressed,
|
||||
else None
|
||||
compress: Compression algoithm used (e.g. 'lz4'), 'none' if none
|
||||
orig_offset: Original offset value read from node
|
||||
orig_size: Original size value read from node
|
||||
|
@ -76,6 +86,7 @@ class Entry(object):
|
|||
self.pre_reset_size = None
|
||||
self.uncomp_size = None
|
||||
self.data = None
|
||||
self.uncomp_data = None
|
||||
self.contents_size = 0
|
||||
self.align = None
|
||||
self.align_size = None
|
||||
|
@ -180,6 +191,9 @@ class Entry(object):
|
|||
self.expand_size = fdt_util.GetBool(self._node, 'expand-size')
|
||||
self.missing_msg = fdt_util.GetString(self._node, 'missing-msg')
|
||||
|
||||
# This is only supported by blobs and sections at present
|
||||
self.compress = fdt_util.GetString(self._node, 'compress', 'none')
|
||||
|
||||
def GetDefaultFilename(self):
|
||||
return None
|
||||
|
||||
|
@ -199,11 +213,20 @@ class Entry(object):
|
|||
def ExpandEntries(self):
|
||||
pass
|
||||
|
||||
def AddMissingProperties(self):
|
||||
"""Add new properties to the device tree as needed for this entry"""
|
||||
for prop in ['offset', 'size', 'image-pos']:
|
||||
def AddMissingProperties(self, have_image_pos):
|
||||
"""Add new properties to the device tree as needed for this entry
|
||||
|
||||
Args:
|
||||
have_image_pos: True if this entry has an image position. This can
|
||||
be False if its parent section is compressed, since compression
|
||||
groups all entries together into a compressed block of data,
|
||||
obscuring the start of each individual child entry
|
||||
"""
|
||||
for prop in ['offset', 'size']:
|
||||
if not prop in self._node.props:
|
||||
state.AddZeroProp(self._node, prop)
|
||||
if have_image_pos and 'image-pos' not in self._node.props:
|
||||
state.AddZeroProp(self._node, 'image-pos')
|
||||
if self.GetImage().allow_repack:
|
||||
if self.orig_offset is not None:
|
||||
state.AddZeroProp(self._node, 'orig-offset', True)
|
||||
|
@ -221,7 +244,8 @@ class Entry(object):
|
|||
state.SetInt(self._node, 'offset', self.offset)
|
||||
state.SetInt(self._node, 'size', self.size)
|
||||
base = self.section.GetRootSkipAtStart() if self.section else 0
|
||||
state.SetInt(self._node, 'image-pos', self.image_pos - base)
|
||||
if self.image_pos is not None:
|
||||
state.SetInt(self._node, 'image-pos', self.image_pos)
|
||||
if self.GetImage().allow_repack:
|
||||
if self.orig_offset is not None:
|
||||
state.SetInt(self._node, 'orig-offset', self.orig_offset, True)
|
||||
|
@ -423,6 +447,12 @@ class Entry(object):
|
|||
return self._node.path
|
||||
|
||||
def GetData(self):
|
||||
"""Get the contents of an entry
|
||||
|
||||
Returns:
|
||||
bytes content of the entry, excluding any padding. If the entry is
|
||||
compressed, the compressed data is returned
|
||||
"""
|
||||
self.Detail('GetData: size %s' % ToHexSize(self.data))
|
||||
return self.data
|
||||
|
||||
|
@ -490,7 +520,7 @@ class Entry(object):
|
|||
"""
|
||||
pass
|
||||
|
||||
def CheckOffset(self):
|
||||
def CheckEntries(self):
|
||||
"""Check that the entry offsets are correct
|
||||
|
||||
This is used for entries which have extra offset requirements (other
|
||||
|
@ -836,3 +866,18 @@ features to produce new behaviours.
|
|||
list of possible tags, most desirable first
|
||||
"""
|
||||
return list(filter(None, [self.missing_msg, self.name, self.etype]))
|
||||
|
||||
def CompressData(self, indata):
|
||||
"""Compress data according to the entry's compression method
|
||||
|
||||
Args:
|
||||
indata: Data to compress
|
||||
|
||||
Returns:
|
||||
Compressed data (first word is the compressed size)
|
||||
"""
|
||||
self.uncomp_data = indata
|
||||
if self.compress != 'none':
|
||||
self.uncomp_size = len(indata)
|
||||
data = tools.Compress(indata, self.compress)
|
||||
return data
|
||||
|
|
|
@ -33,7 +33,6 @@ class Entry_blob(Entry):
|
|||
def __init__(self, section, etype, node):
|
||||
super().__init__(section, etype, node)
|
||||
self._filename = fdt_util.GetString(self._node, 'filename', self.etype)
|
||||
self.compress = fdt_util.GetString(self._node, 'compress', 'none')
|
||||
|
||||
def ObtainContents(self):
|
||||
self._filename = self.GetDefaultFilename()
|
||||
|
@ -48,12 +47,6 @@ class Entry_blob(Entry):
|
|||
self.ReadBlobContents()
|
||||
return True
|
||||
|
||||
def CompressData(self, indata):
|
||||
if self.compress != 'none':
|
||||
self.uncomp_size = len(indata)
|
||||
data = tools.Compress(indata, self.compress)
|
||||
return data
|
||||
|
||||
def ReadBlobContents(self):
|
||||
"""Read blob contents into memory
|
||||
|
||||
|
|
|
@ -237,10 +237,10 @@ class Entry_cbfs(Entry):
|
|||
if entry._cbfs_compress:
|
||||
entry.uncomp_size = cfile.memlen
|
||||
|
||||
def AddMissingProperties(self):
|
||||
super().AddMissingProperties()
|
||||
def AddMissingProperties(self, have_image_pos):
|
||||
super().AddMissingProperties(have_image_pos)
|
||||
for entry in self._cbfs_entries.values():
|
||||
entry.AddMissingProperties()
|
||||
entry.AddMissingProperties(have_image_pos)
|
||||
if entry._cbfs_compress:
|
||||
state.AddZeroProp(entry._node, 'uncomp-size')
|
||||
# Store the 'compress' property, since we don't look at
|
||||
|
|
|
@ -19,7 +19,7 @@ class Entry_files(Entry_section):
|
|||
|
||||
Properties / Entry arguments:
|
||||
- pattern: Filename pattern to match the files to include
|
||||
- compress: Compression algorithm to use:
|
||||
- files-compress: Compression algorithm to use:
|
||||
none: No compression
|
||||
lz4: Use lz4 compression (via 'lz4' command-line utility)
|
||||
|
||||
|
@ -36,7 +36,8 @@ class Entry_files(Entry_section):
|
|||
self._pattern = fdt_util.GetString(self._node, 'pattern')
|
||||
if not self._pattern:
|
||||
self.Raise("Missing 'pattern' property")
|
||||
self._compress = fdt_util.GetString(self._node, 'compress', 'none')
|
||||
self._files_compress = fdt_util.GetString(self._node, 'files-compress',
|
||||
'none')
|
||||
self._require_matches = fdt_util.GetBool(self._node,
|
||||
'require-matches')
|
||||
|
||||
|
@ -53,7 +54,7 @@ class Entry_files(Entry_section):
|
|||
subnode = state.AddSubnode(self._node, name)
|
||||
state.AddString(subnode, 'type', 'blob')
|
||||
state.AddString(subnode, 'filename', fname)
|
||||
state.AddString(subnode, 'compress', self._compress)
|
||||
state.AddString(subnode, 'compress', self._files_compress)
|
||||
|
||||
# Read entries again, now that we have some
|
||||
self._ReadEntries()
|
||||
|
|
|
@ -16,6 +16,7 @@ from binman.entry import Entry
|
|||
from dtoc import fdt_util
|
||||
from patman import tools
|
||||
from patman import tout
|
||||
from patman.tools import ToHexSize
|
||||
|
||||
|
||||
class Entry_section(Entry):
|
||||
|
@ -56,7 +57,7 @@ class Entry_section(Entry):
|
|||
self._end_4gb = False
|
||||
|
||||
def ReadNode(self):
|
||||
"""Read properties from the image node"""
|
||||
"""Read properties from the section node"""
|
||||
super().ReadNode()
|
||||
self._pad_byte = fdt_util.GetInt(self._node, 'pad-byte', 0)
|
||||
self._sort = fdt_util.GetBool(self._node, 'sort-by-offset')
|
||||
|
@ -135,32 +136,113 @@ class Entry_section(Entry):
|
|||
for entry in self._entries.values():
|
||||
entry.ExpandEntries()
|
||||
|
||||
def AddMissingProperties(self):
|
||||
def AddMissingProperties(self, have_image_pos):
|
||||
"""Add new properties to the device tree as needed for this entry"""
|
||||
super().AddMissingProperties()
|
||||
super().AddMissingProperties(have_image_pos)
|
||||
if self.compress != 'none':
|
||||
have_image_pos = False
|
||||
for entry in self._entries.values():
|
||||
entry.AddMissingProperties()
|
||||
entry.AddMissingProperties(have_image_pos)
|
||||
|
||||
def ObtainContents(self):
|
||||
return self.GetEntryContents()
|
||||
|
||||
def GetData(self):
|
||||
def GetPaddedDataForEntry(self, entry, entry_data):
|
||||
"""Get the data for an entry including any padding
|
||||
|
||||
Gets the entry data and uses the section pad-byte value to add padding
|
||||
before and after as defined by the pad-before and pad-after properties.
|
||||
This does not consider alignment.
|
||||
|
||||
Args:
|
||||
entry: Entry to check
|
||||
|
||||
Returns:
|
||||
Contents of the entry along with any pad bytes before and
|
||||
after it (bytes)
|
||||
"""
|
||||
pad_byte = (entry._pad_byte if isinstance(entry, Entry_section)
|
||||
else self._pad_byte)
|
||||
|
||||
data = b''
|
||||
# Handle padding before the entry
|
||||
if entry.pad_before:
|
||||
data += tools.GetBytes(self._pad_byte, entry.pad_before)
|
||||
|
||||
# Add in the actual entry data
|
||||
data += entry_data
|
||||
|
||||
# Handle padding after the entry
|
||||
if entry.pad_after:
|
||||
data += tools.GetBytes(self._pad_byte, entry.pad_after)
|
||||
|
||||
if entry.size:
|
||||
data += tools.GetBytes(pad_byte, entry.size - len(data))
|
||||
|
||||
self.Detail('GetPaddedDataForEntry: size %s' % ToHexSize(self.data))
|
||||
|
||||
return data
|
||||
|
||||
def _BuildSectionData(self):
|
||||
"""Build the contents of a section
|
||||
|
||||
This places all entries at the right place, dealing with padding before
|
||||
and after entries. It does not do padding for the section itself (the
|
||||
pad-before and pad-after properties in the section items) since that is
|
||||
handled by the parent section.
|
||||
|
||||
Returns:
|
||||
Contents of the section (bytes)
|
||||
"""
|
||||
section_data = b''
|
||||
|
||||
for entry in self._entries.values():
|
||||
data = entry.GetData()
|
||||
base = self.pad_before + (entry.offset or 0) - self._skip_at_start
|
||||
pad = base - len(section_data) + (entry.pad_before or 0)
|
||||
data = self.GetPaddedDataForEntry(entry, entry.GetData())
|
||||
# Handle empty space before the entry
|
||||
pad = (entry.offset or 0) - self._skip_at_start - len(section_data)
|
||||
if pad > 0:
|
||||
section_data += tools.GetBytes(self._pad_byte, pad)
|
||||
|
||||
# Add in the actual entry data
|
||||
section_data += data
|
||||
if self.size:
|
||||
pad = self.size - len(section_data)
|
||||
if pad > 0:
|
||||
section_data += tools.GetBytes(self._pad_byte, pad)
|
||||
|
||||
self.Detail('GetData: %d entries, total size %#x' %
|
||||
(len(self._entries), len(section_data)))
|
||||
return section_data
|
||||
return self.CompressData(section_data)
|
||||
|
||||
def GetPaddedData(self, data=None):
|
||||
"""Get the data for a section including any padding
|
||||
|
||||
Gets the section data and uses the parent section's pad-byte value to
|
||||
add padding before and after as defined by the pad-before and pad-after
|
||||
properties. If this is a top-level section (i.e. an image), this is the
|
||||
same as GetData(), since padding is not supported.
|
||||
|
||||
This does not consider alignment.
|
||||
|
||||
Returns:
|
||||
Contents of the section along with any pad bytes before and
|
||||
after it (bytes)
|
||||
"""
|
||||
section = self.section or self
|
||||
if data is None:
|
||||
data = self.GetData()
|
||||
return section.GetPaddedDataForEntry(self, data)
|
||||
|
||||
def GetData(self):
|
||||
"""Get the contents of an entry
|
||||
|
||||
This builds the contents of the section, stores this as the contents of
|
||||
the section and returns it
|
||||
|
||||
Returns:
|
||||
bytes content of the section, made up for all all of its subentries.
|
||||
This excludes any padding. If the section is compressed, the
|
||||
compressed data is returned
|
||||
"""
|
||||
data = self._BuildSectionData()
|
||||
self.SetContents(data)
|
||||
return data
|
||||
|
||||
def GetOffsets(self):
|
||||
"""Handle entries that want to set the offset/size of other entries
|
||||
|
@ -180,14 +262,25 @@ class Entry_section(Entry):
|
|||
def Pack(self, offset):
|
||||
"""Pack all entries into the section"""
|
||||
self._PackEntries()
|
||||
return super().Pack(offset)
|
||||
if self._sort:
|
||||
self._SortEntries()
|
||||
self._ExpandEntries()
|
||||
|
||||
data = self._BuildSectionData()
|
||||
self.SetContents(data)
|
||||
|
||||
self.CheckSize()
|
||||
|
||||
offset = super().Pack(offset)
|
||||
self.CheckEntries()
|
||||
return offset
|
||||
|
||||
def _PackEntries(self):
|
||||
"""Pack all entries into the image"""
|
||||
"""Pack all entries into the section"""
|
||||
offset = self._skip_at_start
|
||||
for entry in self._entries.values():
|
||||
offset = entry.Pack(offset)
|
||||
self.size = self.CheckSize()
|
||||
return offset
|
||||
|
||||
def _ExpandEntries(self):
|
||||
"""Expand any entries that are permitted to"""
|
||||
|
@ -209,21 +302,22 @@ class Entry_section(Entry):
|
|||
self._entries[entry._node.name] = entry
|
||||
|
||||
def CheckEntries(self):
|
||||
"""Check that entries do not overlap or extend outside the image"""
|
||||
if self._sort:
|
||||
self._SortEntries()
|
||||
self._ExpandEntries()
|
||||
"""Check that entries do not overlap or extend outside the section"""
|
||||
max_size = self.size if self.uncomp_size is None else self.uncomp_size
|
||||
|
||||
offset = 0
|
||||
prev_name = 'None'
|
||||
for entry in self._entries.values():
|
||||
entry.CheckOffset()
|
||||
entry.CheckEntries()
|
||||
if (entry.offset < self._skip_at_start or
|
||||
entry.offset + entry.size > self._skip_at_start +
|
||||
self.size):
|
||||
entry.Raise("Offset %#x (%d) is outside the section starting "
|
||||
"at %#x (%d)" %
|
||||
(entry.offset, entry.offset, self._skip_at_start,
|
||||
self._skip_at_start))
|
||||
max_size):
|
||||
entry.Raise('Offset %#x (%d) size %#x (%d) is outside the '
|
||||
"section '%s' starting at %#x (%d) "
|
||||
'of size %#x (%d)' %
|
||||
(entry.offset, entry.offset, entry.size, entry.size,
|
||||
self._node.path, self._skip_at_start,
|
||||
self._skip_at_start, max_size, max_size))
|
||||
if entry.offset < offset and entry.size:
|
||||
entry.Raise("Offset %#x (%d) overlaps with previous entry '%s' "
|
||||
"ending at %#x (%d)" %
|
||||
|
@ -243,6 +337,7 @@ class Entry_section(Entry):
|
|||
|
||||
def SetImagePos(self, image_pos):
|
||||
super().SetImagePos(image_pos)
|
||||
if self.compress == 'none':
|
||||
for entry in self._entries.values():
|
||||
entry.SetImagePos(image_pos + self.offset)
|
||||
|
||||
|
@ -254,9 +349,6 @@ class Entry_section(Entry):
|
|||
sizes_ok = False
|
||||
return sizes_ok and sizes_ok_base
|
||||
|
||||
def CheckOffset(self):
|
||||
self.CheckEntries()
|
||||
|
||||
def WriteMap(self, fd, indent):
|
||||
"""Write a map of the section to a .map file
|
||||
|
||||
|
@ -412,7 +504,7 @@ class Entry_section(Entry):
|
|||
return None
|
||||
|
||||
def GetEntryContents(self):
|
||||
"""Call ObtainContents() for the section
|
||||
"""Call ObtainContents() for each entry in the section
|
||||
"""
|
||||
todo = self._entries.values()
|
||||
for passnum in range(3):
|
||||
|
@ -454,18 +546,13 @@ class Entry_section(Entry):
|
|||
for name, info in offset_dict.items():
|
||||
self._SetEntryOffsetSize(name, *info)
|
||||
|
||||
|
||||
def CheckSize(self):
|
||||
"""Check that the image contents does not exceed its size, etc."""
|
||||
contents_size = 0
|
||||
for entry in self._entries.values():
|
||||
contents_size = max(contents_size, entry.offset + entry.size)
|
||||
|
||||
contents_size -= self._skip_at_start
|
||||
contents_size = len(self.data)
|
||||
|
||||
size = self.size
|
||||
if not size:
|
||||
size = self.pad_before + contents_size + self.pad_after
|
||||
data = self.GetPaddedData(self.data)
|
||||
size = len(data)
|
||||
size = tools.Align(size, self.align_size)
|
||||
|
||||
if self.size and contents_size > self.size:
|
||||
|
|
|
@ -81,6 +81,7 @@ class Entry_u_boot_ucode(Entry_blob):
|
|||
if fdt_entry:
|
||||
break
|
||||
if not fdt_entry:
|
||||
self.data = b''
|
||||
return True
|
||||
if not fdt_entry.ready:
|
||||
return False
|
||||
|
|
|
@ -70,6 +70,7 @@ VBLOCK_DATA = b'vblk'
|
|||
FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
|
||||
b"sorry you're alive\n")
|
||||
COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
|
||||
COMPRESS_DATA_BIG = COMPRESS_DATA * 2
|
||||
REFCODE_DATA = b'refcode'
|
||||
FSP_M_DATA = b'fsp_m'
|
||||
FSP_S_DATA = b'fsp_s'
|
||||
|
@ -175,6 +176,7 @@ class TestFunctional(unittest.TestCase):
|
|||
os.path.join(cls._indir, 'files'))
|
||||
|
||||
TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
|
||||
TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
|
||||
TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
|
||||
TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
|
||||
|
||||
|
@ -785,9 +787,9 @@ class TestFunctional(unittest.TestCase):
|
|||
|
||||
def testPackExtra(self):
|
||||
"""Test that extra packing feature works as expected"""
|
||||
retcode = self._DoTestFile('009_pack_extra.dts')
|
||||
data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
|
||||
update_dtb=True)
|
||||
|
||||
self.assertEqual(0, retcode)
|
||||
self.assertIn('image', control.images)
|
||||
image = control.images['image']
|
||||
entries = image.GetEntries()
|
||||
|
@ -799,34 +801,82 @@ class TestFunctional(unittest.TestCase):
|
|||
self.assertEqual(0, entry.offset)
|
||||
self.assertEqual(3, entry.pad_before)
|
||||
self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
|
||||
self.assertEqual(U_BOOT_DATA, entry.data)
|
||||
self.assertEqual(tools.GetBytes(0, 3) + U_BOOT_DATA +
|
||||
tools.GetBytes(0, 5), data[:entry.size])
|
||||
pos = entry.size
|
||||
|
||||
# Second u-boot has an aligned size, but it has no effect
|
||||
self.assertIn('u-boot-align-size-nop', entries)
|
||||
entry = entries['u-boot-align-size-nop']
|
||||
self.assertEqual(12, entry.offset)
|
||||
self.assertEqual(4, entry.size)
|
||||
self.assertEqual(pos, entry.offset)
|
||||
self.assertEqual(len(U_BOOT_DATA), entry.size)
|
||||
self.assertEqual(U_BOOT_DATA, entry.data)
|
||||
self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
|
||||
pos += entry.size
|
||||
|
||||
# Third u-boot has an aligned size too
|
||||
self.assertIn('u-boot-align-size', entries)
|
||||
entry = entries['u-boot-align-size']
|
||||
self.assertEqual(16, entry.offset)
|
||||
self.assertEqual(pos, entry.offset)
|
||||
self.assertEqual(32, entry.size)
|
||||
self.assertEqual(U_BOOT_DATA, entry.data)
|
||||
self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 32 - len(U_BOOT_DATA)),
|
||||
data[pos:pos + entry.size])
|
||||
pos += entry.size
|
||||
|
||||
# Fourth u-boot has an aligned end
|
||||
self.assertIn('u-boot-align-end', entries)
|
||||
entry = entries['u-boot-align-end']
|
||||
self.assertEqual(48, entry.offset)
|
||||
self.assertEqual(16, entry.size)
|
||||
self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
|
||||
self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 16 - len(U_BOOT_DATA)),
|
||||
data[pos:pos + entry.size])
|
||||
pos += entry.size
|
||||
|
||||
# Fifth u-boot immediately afterwards
|
||||
self.assertIn('u-boot-align-both', entries)
|
||||
entry = entries['u-boot-align-both']
|
||||
self.assertEqual(64, entry.offset)
|
||||
self.assertEqual(64, entry.size)
|
||||
self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
|
||||
self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 64 - len(U_BOOT_DATA)),
|
||||
data[pos:pos + entry.size])
|
||||
|
||||
self.CheckNoGaps(entries)
|
||||
self.assertEqual(128, image.size)
|
||||
|
||||
dtb = fdt.Fdt(out_dtb_fname)
|
||||
dtb.Scan()
|
||||
props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
|
||||
expected = {
|
||||
'image-pos': 0,
|
||||
'offset': 0,
|
||||
'size': 128,
|
||||
|
||||
'u-boot:image-pos': 0,
|
||||
'u-boot:offset': 0,
|
||||
'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
|
||||
|
||||
'u-boot-align-size-nop:image-pos': 12,
|
||||
'u-boot-align-size-nop:offset': 12,
|
||||
'u-boot-align-size-nop:size': 4,
|
||||
|
||||
'u-boot-align-size:image-pos': 16,
|
||||
'u-boot-align-size:offset': 16,
|
||||
'u-boot-align-size:size': 32,
|
||||
|
||||
'u-boot-align-end:image-pos': 48,
|
||||
'u-boot-align-end:offset': 48,
|
||||
'u-boot-align-end:size': 16,
|
||||
|
||||
'u-boot-align-both:image-pos': 64,
|
||||
'u-boot-align-both:offset': 64,
|
||||
'u-boot-align-both:size': 64,
|
||||
}
|
||||
self.assertEqual(expected, props)
|
||||
|
||||
def testPackAlignPowerOf2(self):
|
||||
"""Test that invalid entry alignment is detected"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
|
@ -970,8 +1020,9 @@ class TestFunctional(unittest.TestCase):
|
|||
"""Test that the end-at-4gb property checks for offset boundaries"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
self._DoTestFile('028_pack_4gb_outside.dts')
|
||||
self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
|
||||
"the section starting at 0xffffffe0 (4294967264)",
|
||||
self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
|
||||
"is outside the section '/binman' starting at "
|
||||
'0xffffffe0 (4294967264) of size 0x20 (32)',
|
||||
str(e.exception))
|
||||
|
||||
def testPackX86Rom(self):
|
||||
|
@ -1761,6 +1812,20 @@ class TestFunctional(unittest.TestCase):
|
|||
props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
|
||||
orig = self._decompress(data)
|
||||
self.assertEquals(COMPRESS_DATA, orig)
|
||||
|
||||
# Do a sanity check on various fields
|
||||
image = control.images['image']
|
||||
entries = image.GetEntries()
|
||||
self.assertEqual(1, len(entries))
|
||||
|
||||
entry = entries['blob']
|
||||
self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
|
||||
self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
|
||||
orig = self._decompress(entry.data)
|
||||
self.assertEqual(orig, entry.uncomp_data)
|
||||
|
||||
self.assertEqual(image.data, entry.data)
|
||||
|
||||
expected = {
|
||||
'blob:uncomp-size': len(COMPRESS_DATA),
|
||||
'blob:size': len(data),
|
||||
|
@ -1961,7 +2026,7 @@ class TestFunctional(unittest.TestCase):
|
|||
self.assertTrue(os.path.exists(map_fname))
|
||||
map_data = tools.ReadFile(map_fname, binary=False)
|
||||
self.assertEqual('''ImagePos Offset Size Name
|
||||
<none> 00000000 00000007 main-section
|
||||
<none> 00000000 00000008 main-section
|
||||
<none> 00000000 00000004 u-boot
|
||||
<none> 00000003 00000004 u-boot-align
|
||||
''', map_data)
|
||||
|
@ -3530,12 +3595,39 @@ class TestFunctional(unittest.TestCase):
|
|||
|
||||
def testPadInSections(self):
|
||||
"""Test pad-before, pad-after for entries in sections"""
|
||||
data = self._DoReadFile('166_pad_in_sections.dts')
|
||||
data, _, _, out_dtb_fname = self._DoReadFileDtb(
|
||||
'166_pad_in_sections.dts', update_dtb=True)
|
||||
expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
|
||||
U_BOOT_DATA + tools.GetBytes(ord('!'), 6) +
|
||||
U_BOOT_DATA)
|
||||
self.assertEqual(expected, data)
|
||||
|
||||
dtb = fdt.Fdt(out_dtb_fname)
|
||||
dtb.Scan()
|
||||
props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
|
||||
expected = {
|
||||
'image-pos': 0,
|
||||
'offset': 0,
|
||||
'size': 12 + 6 + 3 * len(U_BOOT_DATA),
|
||||
|
||||
'section:image-pos': 0,
|
||||
'section:offset': 0,
|
||||
'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
|
||||
|
||||
'section/before:image-pos': 0,
|
||||
'section/before:offset': 0,
|
||||
'section/before:size': len(U_BOOT_DATA),
|
||||
|
||||
'section/u-boot:image-pos': 4,
|
||||
'section/u-boot:offset': 4,
|
||||
'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
|
||||
|
||||
'section/after:image-pos': 26,
|
||||
'section/after:offset': 26,
|
||||
'section/after:size': len(U_BOOT_DATA),
|
||||
}
|
||||
self.assertEqual(expected, props)
|
||||
|
||||
def testFitImageSubentryAlignment(self):
|
||||
"""Test relative alignability of FIT image subentries"""
|
||||
entry_args = {
|
||||
|
@ -3737,14 +3829,14 @@ class TestFunctional(unittest.TestCase):
|
|||
def testEnvironmentNoSize(self):
|
||||
"""Test that a missing 'size' property is detected"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
data = self._DoTestFile('175_env_no_size.dts')
|
||||
self._DoTestFile('175_env_no_size.dts')
|
||||
self.assertIn("'u-boot-env' entry must have a size property",
|
||||
str(e.exception))
|
||||
|
||||
def testEnvironmentTooSmall(self):
|
||||
"""Test handling of an environment that does not fit"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
data = self._DoTestFile('176_env_too_small.dts')
|
||||
self._DoTestFile('176_env_too_small.dts')
|
||||
|
||||
# checksum, start byte, environment with \0 terminator, final \0
|
||||
need = 4 + 1 + len(ENV_DATA) + 1 + 1
|
||||
|
@ -3752,6 +3844,301 @@ class TestFunctional(unittest.TestCase):
|
|||
self.assertIn("too small to hold data (need %#x more bytes)" % short,
|
||||
str(e.exception))
|
||||
|
||||
def testSkipAtStart(self):
|
||||
"""Test handling of skip-at-start section"""
|
||||
data = self._DoReadFile('177_skip_at_start.dts')
|
||||
self.assertEqual(U_BOOT_DATA, data)
|
||||
|
||||
image = control.images['image']
|
||||
entries = image.GetEntries()
|
||||
section = entries['section']
|
||||
self.assertEqual(0, section.offset)
|
||||
self.assertEqual(len(U_BOOT_DATA), section.size)
|
||||
self.assertEqual(U_BOOT_DATA, section.GetData())
|
||||
|
||||
entry = section.GetEntries()['u-boot']
|
||||
self.assertEqual(16, entry.offset)
|
||||
self.assertEqual(len(U_BOOT_DATA), entry.size)
|
||||
self.assertEqual(U_BOOT_DATA, entry.data)
|
||||
|
||||
def testSkipAtStartPad(self):
|
||||
"""Test handling of skip-at-start section with padded entry"""
|
||||
data = self._DoReadFile('178_skip_at_start_pad.dts')
|
||||
before = tools.GetBytes(0, 8)
|
||||
after = tools.GetBytes(0, 4)
|
||||
all = before + U_BOOT_DATA + after
|
||||
self.assertEqual(all, data)
|
||||
|
||||
image = control.images['image']
|
||||
entries = image.GetEntries()
|
||||
section = entries['section']
|
||||
self.assertEqual(0, section.offset)
|
||||
self.assertEqual(len(all), section.size)
|
||||
self.assertEqual(all, section.GetData())
|
||||
|
||||
entry = section.GetEntries()['u-boot']
|
||||
self.assertEqual(16, entry.offset)
|
||||
self.assertEqual(len(all), entry.size)
|
||||
self.assertEqual(U_BOOT_DATA, entry.data)
|
||||
|
||||
def testSkipAtStartSectionPad(self):
|
||||
"""Test handling of skip-at-start section with padding"""
|
||||
data = self._DoReadFile('179_skip_at_start_section_pad.dts')
|
||||
before = tools.GetBytes(0, 8)
|
||||
after = tools.GetBytes(0, 4)
|
||||
all = before + U_BOOT_DATA + after
|
||||
self.assertEqual(all, data)
|
||||
|
||||
image = control.images['image']
|
||||
entries = image.GetEntries()
|
||||
section = entries['section']
|
||||
self.assertEqual(0, section.offset)
|
||||
self.assertEqual(len(all), section.size)
|
||||
self.assertEqual(U_BOOT_DATA, section.data)
|
||||
self.assertEqual(all, section.GetPaddedData())
|
||||
|
||||
entry = section.GetEntries()['u-boot']
|
||||
self.assertEqual(16, entry.offset)
|
||||
self.assertEqual(len(U_BOOT_DATA), entry.size)
|
||||
self.assertEqual(U_BOOT_DATA, entry.data)
|
||||
|
||||
def testSectionPad(self):
|
||||
"""Testing padding with sections"""
|
||||
data = self._DoReadFile('180_section_pad.dts')
|
||||
expected = (tools.GetBytes(ord('&'), 3) +
|
||||
tools.GetBytes(ord('!'), 5) +
|
||||
U_BOOT_DATA +
|
||||
tools.GetBytes(ord('!'), 1) +
|
||||
tools.GetBytes(ord('&'), 2))
|
||||
self.assertEqual(expected, data)
|
||||
|
||||
def testSectionAlign(self):
|
||||
"""Testing alignment with sections"""
|
||||
data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
|
||||
expected = (b'\0' + # fill section
|
||||
tools.GetBytes(ord('&'), 1) + # padding to section align
|
||||
b'\0' + # fill section
|
||||
tools.GetBytes(ord('!'), 3) + # padding to u-boot align
|
||||
U_BOOT_DATA +
|
||||
tools.GetBytes(ord('!'), 4) + # padding to u-boot size
|
||||
tools.GetBytes(ord('!'), 4)) # padding to section size
|
||||
self.assertEqual(expected, data)
|
||||
|
||||
def testCompressImage(self):
|
||||
"""Test compression of the entire image"""
|
||||
self._CheckLz4()
|
||||
data, _, _, out_dtb_fname = self._DoReadFileDtb(
|
||||
'182_compress_image.dts', use_real_dtb=True, update_dtb=True)
|
||||
dtb = fdt.Fdt(out_dtb_fname)
|
||||
dtb.Scan()
|
||||
props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
|
||||
'uncomp-size'])
|
||||
orig = self._decompress(data)
|
||||
self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
|
||||
|
||||
# Do a sanity check on various fields
|
||||
image = control.images['image']
|
||||
entries = image.GetEntries()
|
||||
self.assertEqual(2, len(entries))
|
||||
|
||||
entry = entries['blob']
|
||||
self.assertEqual(COMPRESS_DATA, entry.data)
|
||||
self.assertEqual(len(COMPRESS_DATA), entry.size)
|
||||
|
||||
entry = entries['u-boot']
|
||||
self.assertEqual(U_BOOT_DATA, entry.data)
|
||||
self.assertEqual(len(U_BOOT_DATA), entry.size)
|
||||
|
||||
self.assertEqual(len(data), image.size)
|
||||
self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
|
||||
self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
|
||||
orig = self._decompress(image.data)
|
||||
self.assertEqual(orig, image.uncomp_data)
|
||||
|
||||
expected = {
|
||||
'blob:offset': 0,
|
||||
'blob:size': len(COMPRESS_DATA),
|
||||
'u-boot:offset': len(COMPRESS_DATA),
|
||||
'u-boot:size': len(U_BOOT_DATA),
|
||||
'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
|
||||
'offset': 0,
|
||||
'image-pos': 0,
|
||||
'size': len(data),
|
||||
}
|
||||
self.assertEqual(expected, props)
|
||||
|
||||
def testCompressImageLess(self):
|
||||
"""Test compression where compression reduces the image size"""
|
||||
self._CheckLz4()
|
||||
data, _, _, out_dtb_fname = self._DoReadFileDtb(
|
||||
'183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
|
||||
dtb = fdt.Fdt(out_dtb_fname)
|
||||
dtb.Scan()
|
||||
props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
|
||||
'uncomp-size'])
|
||||
orig = self._decompress(data)
|
||||
|
||||
self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
|
||||
|
||||
# Do a sanity check on various fields
|
||||
image = control.images['image']
|
||||
entries = image.GetEntries()
|
||||
self.assertEqual(2, len(entries))
|
||||
|
||||
entry = entries['blob']
|
||||
self.assertEqual(COMPRESS_DATA_BIG, entry.data)
|
||||
self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
|
||||
|
||||
entry = entries['u-boot']
|
||||
self.assertEqual(U_BOOT_DATA, entry.data)
|
||||
self.assertEqual(len(U_BOOT_DATA), entry.size)
|
||||
|
||||
self.assertEqual(len(data), image.size)
|
||||
self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
|
||||
self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
|
||||
image.uncomp_size)
|
||||
orig = self._decompress(image.data)
|
||||
self.assertEqual(orig, image.uncomp_data)
|
||||
|
||||
expected = {
|
||||
'blob:offset': 0,
|
||||
'blob:size': len(COMPRESS_DATA_BIG),
|
||||
'u-boot:offset': len(COMPRESS_DATA_BIG),
|
||||
'u-boot:size': len(U_BOOT_DATA),
|
||||
'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
|
||||
'offset': 0,
|
||||
'image-pos': 0,
|
||||
'size': len(data),
|
||||
}
|
||||
self.assertEqual(expected, props)
|
||||
|
||||
def testCompressSectionSize(self):
|
||||
"""Test compression of a section with a fixed size"""
|
||||
self._CheckLz4()
|
||||
data, _, _, out_dtb_fname = self._DoReadFileDtb(
|
||||
'184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
|
||||
dtb = fdt.Fdt(out_dtb_fname)
|
||||
dtb.Scan()
|
||||
props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
|
||||
'uncomp-size'])
|
||||
orig = self._decompress(data)
|
||||
self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
|
||||
expected = {
|
||||
'section/blob:offset': 0,
|
||||
'section/blob:size': len(COMPRESS_DATA),
|
||||
'section/u-boot:offset': len(COMPRESS_DATA),
|
||||
'section/u-boot:size': len(U_BOOT_DATA),
|
||||
'section:offset': 0,
|
||||
'section:image-pos': 0,
|
||||
'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
|
||||
'section:size': 0x30,
|
||||
'offset': 0,
|
||||
'image-pos': 0,
|
||||
'size': 0x30,
|
||||
}
|
||||
self.assertEqual(expected, props)
|
||||
|
||||
def testCompressSection(self):
|
||||
"""Test compression of a section with no fixed size"""
|
||||
self._CheckLz4()
|
||||
data, _, _, out_dtb_fname = self._DoReadFileDtb(
|
||||
'185_compress_section.dts', use_real_dtb=True, update_dtb=True)
|
||||
dtb = fdt.Fdt(out_dtb_fname)
|
||||
dtb.Scan()
|
||||
props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
|
||||
'uncomp-size'])
|
||||
orig = self._decompress(data)
|
||||
self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
|
||||
expected = {
|
||||
'section/blob:offset': 0,
|
||||
'section/blob:size': len(COMPRESS_DATA),
|
||||
'section/u-boot:offset': len(COMPRESS_DATA),
|
||||
'section/u-boot:size': len(U_BOOT_DATA),
|
||||
'section:offset': 0,
|
||||
'section:image-pos': 0,
|
||||
'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
|
||||
'section:size': len(data),
|
||||
'offset': 0,
|
||||
'image-pos': 0,
|
||||
'size': len(data),
|
||||
}
|
||||
self.assertEqual(expected, props)
|
||||
|
||||
def testCompressExtra(self):
|
||||
"""Test compression of a section with no fixed size"""
|
||||
self._CheckLz4()
|
||||
data, _, _, out_dtb_fname = self._DoReadFileDtb(
|
||||
'186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
|
||||
dtb = fdt.Fdt(out_dtb_fname)
|
||||
dtb.Scan()
|
||||
props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
|
||||
'uncomp-size'])
|
||||
|
||||
base = data[len(U_BOOT_DATA):]
|
||||
self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
|
||||
rest = base[len(U_BOOT_DATA):]
|
||||
|
||||
# Check compressed data
|
||||
section1 = self._decompress(rest)
|
||||
expect1 = tools.Compress(COMPRESS_DATA + U_BOOT_DATA, 'lz4')
|
||||
self.assertEquals(expect1, rest[:len(expect1)])
|
||||
self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
|
||||
rest1 = rest[len(expect1):]
|
||||
|
||||
section2 = self._decompress(rest1)
|
||||
expect2 = tools.Compress(COMPRESS_DATA + COMPRESS_DATA, 'lz4')
|
||||
self.assertEquals(expect2, rest1[:len(expect2)])
|
||||
self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
|
||||
rest2 = rest1[len(expect2):]
|
||||
|
||||
expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
|
||||
len(expect2) + len(U_BOOT_DATA))
|
||||
#self.assertEquals(expect_size, len(data))
|
||||
|
||||
#self.assertEquals(U_BOOT_DATA, rest2)
|
||||
|
||||
self.maxDiff = None
|
||||
expected = {
|
||||
'u-boot:offset': 0,
|
||||
'u-boot:image-pos': 0,
|
||||
'u-boot:size': len(U_BOOT_DATA),
|
||||
|
||||
'base:offset': len(U_BOOT_DATA),
|
||||
'base:image-pos': len(U_BOOT_DATA),
|
||||
'base:size': len(data) - len(U_BOOT_DATA),
|
||||
'base/u-boot:offset': 0,
|
||||
'base/u-boot:image-pos': len(U_BOOT_DATA),
|
||||
'base/u-boot:size': len(U_BOOT_DATA),
|
||||
'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
|
||||
len(expect2),
|
||||
'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
|
||||
len(expect2),
|
||||
'base/u-boot2:size': len(U_BOOT_DATA),
|
||||
|
||||
'base/section:offset': len(U_BOOT_DATA),
|
||||
'base/section:image-pos': len(U_BOOT_DATA) * 2,
|
||||
'base/section:size': len(expect1),
|
||||
'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
|
||||
'base/section/blob:offset': 0,
|
||||
'base/section/blob:size': len(COMPRESS_DATA),
|
||||
'base/section/u-boot:offset': len(COMPRESS_DATA),
|
||||
'base/section/u-boot:size': len(U_BOOT_DATA),
|
||||
|
||||
'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
|
||||
'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
|
||||
'base/section2:size': len(expect2),
|
||||
'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
|
||||
'base/section2/blob:offset': 0,
|
||||
'base/section2/blob:size': len(COMPRESS_DATA),
|
||||
'base/section2/blob2:offset': len(COMPRESS_DATA),
|
||||
'base/section2/blob2:size': len(COMPRESS_DATA),
|
||||
|
||||
'offset': 0,
|
||||
'image-pos': 0,
|
||||
'size': len(data),
|
||||
}
|
||||
self.assertEqual(expected, props)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
@ -146,7 +146,7 @@ class Image(section.Entry_section):
|
|||
fname = tools.GetOutputFilename(self._filename)
|
||||
tout.Info("Writing image to '%s'" % fname)
|
||||
with open(fname, 'wb') as fd:
|
||||
data = self.GetData()
|
||||
data = self.GetPaddedData()
|
||||
fd.write(data)
|
||||
tout.Info("Wrote %#x bytes" % len(data))
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
|
||||
u-boot-align-both {
|
||||
type = "u-boot";
|
||||
align= <64>;
|
||||
align = <64>;
|
||||
align-end = <128>;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
binman {
|
||||
files {
|
||||
pattern = "files/*.dat";
|
||||
compress = "lz4";
|
||||
files-compress = "lz4";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
19
tools/binman/test/177_skip_at_start.dts
Normal file
19
tools/binman/test/177_skip_at_start.dts
Normal file
|
@ -0,0 +1,19 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2018 NXP
|
||||
*/
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
section {
|
||||
skip-at-start = <16>;
|
||||
u-boot {
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
21
tools/binman/test/178_skip_at_start_pad.dts
Normal file
21
tools/binman/test/178_skip_at_start_pad.dts
Normal file
|
@ -0,0 +1,21 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2018 NXP
|
||||
*/
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
section {
|
||||
skip-at-start = <16>;
|
||||
u-boot {
|
||||
pad-before = <8>;
|
||||
pad-after = <4>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
22
tools/binman/test/179_skip_at_start_section_pad.dts
Normal file
22
tools/binman/test/179_skip_at_start_section_pad.dts
Normal file
|
@ -0,0 +1,22 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2018 NXP
|
||||
*/
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
section {
|
||||
skip-at-start = <16>;
|
||||
pad-before = <8>;
|
||||
pad-after = <4>;
|
||||
|
||||
u-boot {
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
27
tools/binman/test/180_section_pad.dts
Normal file
27
tools/binman/test/180_section_pad.dts
Normal file
|
@ -0,0 +1,27 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
pad-byte = <0x26>;
|
||||
section@0 {
|
||||
read-only;
|
||||
|
||||
/* Padding for the section uses the 0x26 pad byte */
|
||||
pad-before = <3>;
|
||||
pad-after = <2>;
|
||||
|
||||
/* Set the padding byte for entries, i.e. u-boot */
|
||||
pad-byte = <0x21>;
|
||||
|
||||
u-boot {
|
||||
pad-before = <5>;
|
||||
pad-after = <1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
34
tools/binman/test/181_section_align.dts
Normal file
34
tools/binman/test/181_section_align.dts
Normal file
|
@ -0,0 +1,34 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
pad-byte = <0x26>;
|
||||
fill {
|
||||
size = <1>;
|
||||
};
|
||||
section@1 {
|
||||
read-only;
|
||||
|
||||
/* Padding for the section uses the 0x26 pad byte */
|
||||
align = <2>;
|
||||
align-size = <0x10>;
|
||||
|
||||
/* Set the padding byte for entries, i.e. u-boot */
|
||||
pad-byte = <0x21>;
|
||||
|
||||
fill {
|
||||
size = <1>;
|
||||
};
|
||||
|
||||
u-boot {
|
||||
align = <4>;
|
||||
align-size = <8>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
14
tools/binman/test/182_compress_image.dts
Normal file
14
tools/binman/test/182_compress_image.dts
Normal file
|
@ -0,0 +1,14 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
binman {
|
||||
compress = "lz4";
|
||||
blob {
|
||||
filename = "compress";
|
||||
};
|
||||
|
||||
u-boot {
|
||||
};
|
||||
};
|
||||
};
|
14
tools/binman/test/183_compress_image_less.dts
Normal file
14
tools/binman/test/183_compress_image_less.dts
Normal file
|
@ -0,0 +1,14 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
binman {
|
||||
compress = "lz4";
|
||||
blob {
|
||||
filename = "compress_big";
|
||||
};
|
||||
|
||||
u-boot {
|
||||
};
|
||||
};
|
||||
};
|
17
tools/binman/test/184_compress_section_size.dts
Normal file
17
tools/binman/test/184_compress_section_size.dts
Normal file
|
@ -0,0 +1,17 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
binman {
|
||||
section {
|
||||
size = <0x30>;
|
||||
compress = "lz4";
|
||||
blob {
|
||||
filename = "compress";
|
||||
};
|
||||
|
||||
u-boot {
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
16
tools/binman/test/185_compress_section.dts
Normal file
16
tools/binman/test/185_compress_section.dts
Normal file
|
@ -0,0 +1,16 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
binman {
|
||||
section {
|
||||
compress = "lz4";
|
||||
blob {
|
||||
filename = "compress";
|
||||
};
|
||||
|
||||
u-boot {
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
37
tools/binman/test/186_compress_extra.dts
Normal file
37
tools/binman/test/186_compress_extra.dts
Normal file
|
@ -0,0 +1,37 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
binman {
|
||||
u-boot {
|
||||
};
|
||||
base {
|
||||
type = "section";
|
||||
u-boot {
|
||||
};
|
||||
section {
|
||||
compress = "lz4";
|
||||
blob {
|
||||
filename = "compress";
|
||||
};
|
||||
|
||||
u-boot {
|
||||
};
|
||||
};
|
||||
section2 {
|
||||
type = "section";
|
||||
compress = "lz4";
|
||||
blob {
|
||||
filename = "compress";
|
||||
};
|
||||
blob2 {
|
||||
type = "blob";
|
||||
filename = "compress";
|
||||
};
|
||||
};
|
||||
u-boot2 {
|
||||
type = "u-boot";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
|
@ -54,6 +54,13 @@ VAL_PREFIX = 'dtv_'
|
|||
# phandles is len(args). This is a list of integers.
|
||||
PhandleInfo = collections.namedtuple('PhandleInfo', ['max_args', 'args'])
|
||||
|
||||
# Holds a single phandle link, allowing a C struct value to be assigned to point
|
||||
# to a device
|
||||
#
|
||||
# var_node: C variable to assign (e.g. 'dtv_mmc.clocks[0].node')
|
||||
# dev_name: Name of device to assign to (e.g. 'clock')
|
||||
PhandleLink = collections.namedtuple('PhandleLink', ['var_node', 'dev_name'])
|
||||
|
||||
|
||||
def conv_name_to_c(name):
|
||||
"""Convert a device-tree name to a C identifier
|
||||
|
@ -136,7 +143,8 @@ class DtbPlatdata(object):
|
|||
Properties:
|
||||
_fdt: Fdt object, referencing the device tree
|
||||
_dtb_fname: Filename of the input device tree binary file
|
||||
_valid_nodes: A list of Node object with compatible strings
|
||||
_valid_nodes: A list of Node object with compatible strings. The list
|
||||
is ordered by conv_name_to_c(node.name)
|
||||
_include_disabled: true to include nodes marked status = "disabled"
|
||||
_outfile: The current output file (sys.stdout or a real file)
|
||||
_warning_disabled: true to disable warnings about driver names not found
|
||||
|
@ -146,7 +154,6 @@ class DtbPlatdata(object):
|
|||
key: Driver alias declared with
|
||||
U_BOOT_DRIVER_ALIAS(driver_alias, driver_name)
|
||||
value: Driver name declared with U_BOOT_DRIVER(driver_name)
|
||||
_links: List of links to be included in dm_populate_phandle_data()
|
||||
_drivers_additional: List of additional drivers to use during scanning
|
||||
"""
|
||||
def __init__(self, dtb_fname, include_disabled, warning_disabled,
|
||||
|
@ -160,7 +167,6 @@ class DtbPlatdata(object):
|
|||
self._lines = []
|
||||
self._drivers = []
|
||||
self._driver_aliases = {}
|
||||
self._links = []
|
||||
self._drivers_additional = drivers_additional
|
||||
|
||||
def get_normalized_compat_name(self, node):
|
||||
|
@ -359,23 +365,24 @@ class DtbPlatdata(object):
|
|||
"""
|
||||
self._fdt = fdt.FdtScan(self._dtb_fname)
|
||||
|
||||
def scan_node(self, root):
|
||||
def scan_node(self, root, valid_nodes):
|
||||
"""Scan a node and subnodes to build a tree of node and phandle info
|
||||
|
||||
This adds each node to self._valid_nodes.
|
||||
|
||||
Args:
|
||||
root: Root node for scan
|
||||
valid_nodes: List of Node objects to add to
|
||||
"""
|
||||
for node in root.subnodes:
|
||||
if 'compatible' in node.props:
|
||||
status = node.props.get('status')
|
||||
if (not self._include_disabled and not status or
|
||||
status.value != 'disabled'):
|
||||
self._valid_nodes.append(node)
|
||||
valid_nodes.append(node)
|
||||
|
||||
# recurse to handle any subnodes
|
||||
self.scan_node(node)
|
||||
self.scan_node(node, valid_nodes)
|
||||
|
||||
def scan_tree(self):
|
||||
"""Scan the device tree for useful information
|
||||
|
@ -384,8 +391,12 @@ class DtbPlatdata(object):
|
|||
_valid_nodes: A list of nodes we wish to consider include in the
|
||||
platform data
|
||||
"""
|
||||
self._valid_nodes = []
|
||||
return self.scan_node(self._fdt.GetRoot())
|
||||
valid_nodes = []
|
||||
self.scan_node(self._fdt.GetRoot(), valid_nodes)
|
||||
self._valid_nodes = sorted(valid_nodes,
|
||||
key=lambda x: conv_name_to_c(x.name))
|
||||
for idx, node in enumerate(self._valid_nodes):
|
||||
node.idx = idx
|
||||
|
||||
@staticmethod
|
||||
def get_num_cells(node):
|
||||
|
@ -458,8 +469,15 @@ class DtbPlatdata(object):
|
|||
|
||||
Once the widest property is determined, all other properties are
|
||||
updated to match that width.
|
||||
|
||||
Returns:
|
||||
dict containing structures:
|
||||
key (str): Node name, as a C identifier
|
||||
value: dict containing structure fields:
|
||||
key (str): Field name
|
||||
value: Prop object with field information
|
||||
"""
|
||||
structs = {}
|
||||
structs = collections.OrderedDict()
|
||||
for node in self._valid_nodes:
|
||||
node_name, _ = self.get_normalized_compat_name(node)
|
||||
fields = {}
|
||||
|
@ -528,6 +546,14 @@ class DtbPlatdata(object):
|
|||
This writes out the body of a header file consisting of structure
|
||||
definitions for node in self._valid_nodes. See the documentation in
|
||||
doc/driver-model/of-plat.rst for more information.
|
||||
|
||||
Args:
|
||||
structs: dict containing structures:
|
||||
key (str): Node name, as a C identifier
|
||||
value: dict containing structure fields:
|
||||
key (str): Field name
|
||||
value: Prop object with field information
|
||||
|
||||
"""
|
||||
self.out_header()
|
||||
self.out('#include <stdbool.h>\n')
|
||||
|
@ -560,19 +586,13 @@ class DtbPlatdata(object):
|
|||
Args:
|
||||
node: node to output
|
||||
"""
|
||||
struct_name, _ = self.get_normalized_compat_name(node)
|
||||
var_name = conv_name_to_c(node.name)
|
||||
self.buf('static struct %s%s %s%s = {\n' %
|
||||
(STRUCT_PREFIX, struct_name, VAL_PREFIX, var_name))
|
||||
for pname in sorted(node.props):
|
||||
prop = node.props[pname]
|
||||
if pname in PROP_IGNORE_LIST or pname[0] == '#':
|
||||
continue
|
||||
member_name = conv_name_to_c(prop.name)
|
||||
self.buf('\t%s= ' % tab_to(3, '.' + member_name))
|
||||
def _output_list(node, prop):
|
||||
"""Output the C code for a devicetree property that holds a list
|
||||
|
||||
# Special handling for lists
|
||||
if isinstance(prop.value, list):
|
||||
Args:
|
||||
node (fdt.Node): Node to output
|
||||
prop (fdt.Prop): Prop to output
|
||||
"""
|
||||
self.buf('{')
|
||||
vals = []
|
||||
# For phandles, output a reference to the platform data
|
||||
|
@ -589,17 +609,11 @@ class DtbPlatdata(object):
|
|||
name = conv_name_to_c(target_node.name)
|
||||
arg_values = []
|
||||
for i in range(args):
|
||||
arg_values.append(str(fdt_util.fdt32_to_cpu(prop.value[pos + 1 + i])))
|
||||
arg_values.append(
|
||||
str(fdt_util.fdt32_to_cpu(prop.value[pos + 1 + i])))
|
||||
pos += 1 + args
|
||||
# node member is filled with NULL as the real value
|
||||
# will be update at run-time during dm_init_and_scan()
|
||||
# by dm_populate_phandle_data()
|
||||
vals.append('\t{NULL, {%s}}' % (', '.join(arg_values)))
|
||||
var_node = '%s%s.%s[%d].node' % \
|
||||
(VAL_PREFIX, var_name, member_name, item)
|
||||
# Save the the link information to be use to define
|
||||
# dm_populate_phandle_data()
|
||||
self._links.append({'var_node': var_node, 'dev_name': name})
|
||||
vals.append('\t{%d, {%s}}' % (target_node.idx,
|
||||
', '.join(arg_values)))
|
||||
item += 1
|
||||
for val in vals:
|
||||
self.buf('\n\t\t%s,' % val)
|
||||
|
@ -613,6 +627,22 @@ class DtbPlatdata(object):
|
|||
self.buf(',\n\t\t')
|
||||
self.buf(', '.join(vals[i:i + 8]))
|
||||
self.buf('}')
|
||||
|
||||
struct_name, _ = self.get_normalized_compat_name(node)
|
||||
var_name = conv_name_to_c(node.name)
|
||||
self.buf('/* Node %s index %d */\n' % (node.path, node.idx))
|
||||
self.buf('static struct %s%s %s%s = {\n' %
|
||||
(STRUCT_PREFIX, struct_name, VAL_PREFIX, var_name))
|
||||
for pname in sorted(node.props):
|
||||
prop = node.props[pname]
|
||||
if pname in PROP_IGNORE_LIST or pname[0] == '#':
|
||||
continue
|
||||
member_name = conv_name_to_c(prop.name)
|
||||
self.buf('\t%s= ' % tab_to(3, '.' + member_name))
|
||||
|
||||
# Special handling for lists
|
||||
if isinstance(prop.value, list):
|
||||
_output_list(node, prop)
|
||||
else:
|
||||
self.buf(get_value(prop.type, prop.value))
|
||||
self.buf(',\n')
|
||||
|
@ -623,6 +653,10 @@ class DtbPlatdata(object):
|
|||
self.buf('\t.name\t\t= "%s",\n' % struct_name)
|
||||
self.buf('\t.platdata\t= &%s%s,\n' % (VAL_PREFIX, var_name))
|
||||
self.buf('\t.platdata_size\t= sizeof(%s%s),\n' % (VAL_PREFIX, var_name))
|
||||
idx = -1
|
||||
if node.parent and node.parent in self._valid_nodes:
|
||||
idx = node.parent.idx
|
||||
self.buf('\t.parent_idx\t= %d,\n' % idx)
|
||||
self.buf('};\n')
|
||||
self.buf('\n')
|
||||
|
||||
|
@ -639,6 +673,9 @@ class DtbPlatdata(object):
|
|||
information.
|
||||
"""
|
||||
self.out_header()
|
||||
self.out('/* Allow use of U_BOOT_DEVICE() in this file */\n')
|
||||
self.out('#define DT_PLATDATA_C\n')
|
||||
self.out('\n')
|
||||
self.out('#include <common.h>\n')
|
||||
self.out('#include <dm.h>\n')
|
||||
self.out('#include <dt-structs.h>\n')
|
||||
|
@ -660,9 +697,6 @@ class DtbPlatdata(object):
|
|||
# nodes using DM_GET_DEVICE
|
||||
# dtv_dmc_at_xxx.clocks[0].node = DM_GET_DEVICE(clock_controller_at_xxx)
|
||||
self.buf('void dm_populate_phandle_data(void) {\n')
|
||||
for l in self._links:
|
||||
self.buf('\t%s = DM_GET_DEVICE(%s);\n' %
|
||||
(l['var_node'], l['dev_name']))
|
||||
self.buf('}\n')
|
||||
|
||||
self.out(''.join(self.get_buf()))
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
u-boot,dm-pre-reloc;
|
||||
compatible = "sandbox,spl-test";
|
||||
stringarray = "one";
|
||||
longbytearray = [09 0a 0b 0c 0d 0e 0f 10];
|
||||
};
|
||||
|
||||
spl-test4 {
|
||||
|
|
|
@ -129,6 +129,15 @@ class Prop:
|
|||
specific.
|
||||
"""
|
||||
if newprop.type < self.type:
|
||||
# Special handling to convert an int into bytes
|
||||
if self.type == TYPE_INT and newprop.type == TYPE_BYTE:
|
||||
if type(self.value) == list:
|
||||
new_value = []
|
||||
for val in self.value:
|
||||
new_value += [tools.ToChar(by) for by in val]
|
||||
else:
|
||||
new_value = [tools.ToChar(by) for by in self.value]
|
||||
self.value = new_value
|
||||
self.type = newprop.type
|
||||
|
||||
if type(newprop.value) == list and type(self.value) != list:
|
||||
|
|
|
@ -44,6 +44,9 @@ C_HEADER = '''/*
|
|||
* This file was generated by dtoc from a .dtb (device tree binary) file.
|
||||
*/
|
||||
|
||||
/* Allow use of U_BOOT_DEVICE() in this file */
|
||||
#define DT_PLATDATA_C
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <dt-structs.h>
|
||||
|
@ -209,6 +212,29 @@ struct dtd_sandbox_spl_test_2 {
|
|||
with open(output) as infile:
|
||||
data = infile.read()
|
||||
self._CheckStrings(C_HEADER + '''
|
||||
/* Node /i2c@0 index 0 */
|
||||
static struct dtd_sandbox_i2c_test dtv_i2c_at_0 = {
|
||||
};
|
||||
U_BOOT_DEVICE(i2c_at_0) = {
|
||||
\t.name\t\t= "sandbox_i2c_test",
|
||||
\t.platdata\t= &dtv_i2c_at_0,
|
||||
\t.platdata_size\t= sizeof(dtv_i2c_at_0),
|
||||
\t.parent_idx\t= -1,
|
||||
};
|
||||
|
||||
/* Node /i2c@0/pmic@9 index 1 */
|
||||
static struct dtd_sandbox_pmic_test dtv_pmic_at_9 = {
|
||||
\t.low_power\t\t= true,
|
||||
\t.reg\t\t\t= {0x9, 0x0},
|
||||
};
|
||||
U_BOOT_DEVICE(pmic_at_9) = {
|
||||
\t.name\t\t= "sandbox_pmic_test",
|
||||
\t.platdata\t= &dtv_pmic_at_9,
|
||||
\t.platdata_size\t= sizeof(dtv_pmic_at_9),
|
||||
\t.parent_idx\t= 0,
|
||||
};
|
||||
|
||||
/* Node /spl-test index 2 */
|
||||
static struct dtd_sandbox_spl_test dtv_spl_test = {
|
||||
\t.boolval\t\t= true,
|
||||
\t.bytearray\t\t= {0x6, 0x0, 0x0},
|
||||
|
@ -225,15 +251,17 @@ U_BOOT_DEVICE(spl_test) = {
|
|||
\t.name\t\t= "sandbox_spl_test",
|
||||
\t.platdata\t= &dtv_spl_test,
|
||||
\t.platdata_size\t= sizeof(dtv_spl_test),
|
||||
\t.parent_idx\t= -1,
|
||||
};
|
||||
|
||||
/* Node /spl-test2 index 3 */
|
||||
static struct dtd_sandbox_spl_test dtv_spl_test2 = {
|
||||
\t.acpi_name\t\t= "\\\\_SB.GPO0",
|
||||
\t.bytearray\t\t= {0x1, 0x23, 0x34},
|
||||
\t.byteval\t\t= 0x8,
|
||||
\t.intarray\t\t= {0x5, 0x0, 0x0, 0x0},
|
||||
\t.intval\t\t\t= 0x3,
|
||||
\t.longbytearray\t\t= {0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
\t.longbytearray\t\t= {0x9, 0xa, 0xb, 0xc, 0x0, 0x0, 0x0, 0x0,
|
||||
\t\t0x0},
|
||||
\t.stringarray\t\t= {"another", "multi-word", "message"},
|
||||
\t.stringval\t\t= "message2",
|
||||
|
@ -242,41 +270,30 @@ U_BOOT_DEVICE(spl_test2) = {
|
|||
\t.name\t\t= "sandbox_spl_test",
|
||||
\t.platdata\t= &dtv_spl_test2,
|
||||
\t.platdata_size\t= sizeof(dtv_spl_test2),
|
||||
\t.parent_idx\t= -1,
|
||||
};
|
||||
|
||||
/* Node /spl-test3 index 4 */
|
||||
static struct dtd_sandbox_spl_test dtv_spl_test3 = {
|
||||
\t.longbytearray\t\t= {0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10,
|
||||
\t\t0x0},
|
||||
\t.stringarray\t\t= {"one", "", ""},
|
||||
};
|
||||
U_BOOT_DEVICE(spl_test3) = {
|
||||
\t.name\t\t= "sandbox_spl_test",
|
||||
\t.platdata\t= &dtv_spl_test3,
|
||||
\t.platdata_size\t= sizeof(dtv_spl_test3),
|
||||
\t.parent_idx\t= -1,
|
||||
};
|
||||
|
||||
/* Node /spl-test4 index 5 */
|
||||
static struct dtd_sandbox_spl_test_2 dtv_spl_test4 = {
|
||||
};
|
||||
U_BOOT_DEVICE(spl_test4) = {
|
||||
\t.name\t\t= "sandbox_spl_test_2",
|
||||
\t.platdata\t= &dtv_spl_test4,
|
||||
\t.platdata_size\t= sizeof(dtv_spl_test4),
|
||||
};
|
||||
|
||||
static struct dtd_sandbox_i2c_test dtv_i2c_at_0 = {
|
||||
};
|
||||
U_BOOT_DEVICE(i2c_at_0) = {
|
||||
\t.name\t\t= "sandbox_i2c_test",
|
||||
\t.platdata\t= &dtv_i2c_at_0,
|
||||
\t.platdata_size\t= sizeof(dtv_i2c_at_0),
|
||||
};
|
||||
|
||||
static struct dtd_sandbox_pmic_test dtv_pmic_at_9 = {
|
||||
\t.low_power\t\t= true,
|
||||
\t.reg\t\t\t= {0x9, 0x0},
|
||||
};
|
||||
U_BOOT_DEVICE(pmic_at_9) = {
|
||||
\t.name\t\t= "sandbox_pmic_test",
|
||||
\t.platdata\t= &dtv_pmic_at_9,
|
||||
\t.platdata_size\t= sizeof(dtv_pmic_at_9),
|
||||
\t.parent_idx\t= -1,
|
||||
};
|
||||
|
||||
''' + C_EMPTY_POPULATE_PHANDLE_DATA, data)
|
||||
|
@ -300,6 +317,7 @@ struct dtd_sandbox_gpio {
|
|||
with open(output) as infile:
|
||||
data = infile.read()
|
||||
self._CheckStrings(C_HEADER + '''
|
||||
/* Node /gpios@0 index 0 */
|
||||
static struct dtd_sandbox_gpio dtv_gpios_at_0 = {
|
||||
\t.gpio_bank_name\t\t= "a",
|
||||
\t.gpio_controller\t= true,
|
||||
|
@ -309,6 +327,7 @@ U_BOOT_DEVICE(gpios_at_0) = {
|
|||
\t.name\t\t= "sandbox_gpio",
|
||||
\t.platdata\t= &dtv_gpios_at_0,
|
||||
\t.platdata_size\t= sizeof(dtv_gpios_at_0),
|
||||
\t.parent_idx\t= -1,
|
||||
};
|
||||
|
||||
void dm_populate_phandle_data(void) {
|
||||
|
@ -333,12 +352,14 @@ struct dtd_invalid {
|
|||
with open(output) as infile:
|
||||
data = infile.read()
|
||||
self._CheckStrings(C_HEADER + '''
|
||||
/* Node /spl-test index 0 */
|
||||
static struct dtd_invalid dtv_spl_test = {
|
||||
};
|
||||
U_BOOT_DEVICE(spl_test) = {
|
||||
\t.name\t\t= "invalid",
|
||||
\t.platdata\t= &dtv_spl_test,
|
||||
\t.platdata_size\t= sizeof(dtv_spl_test),
|
||||
\t.parent_idx\t= -1,
|
||||
};
|
||||
|
||||
void dm_populate_phandle_data(void) {
|
||||
|
@ -365,15 +386,7 @@ struct dtd_target {
|
|||
with open(output) as infile:
|
||||
data = infile.read()
|
||||
self._CheckStrings(C_HEADER + '''
|
||||
static struct dtd_target dtv_phandle_target = {
|
||||
\t.intval\t\t\t= 0x0,
|
||||
};
|
||||
U_BOOT_DEVICE(phandle_target) = {
|
||||
\t.name\t\t= "target",
|
||||
\t.platdata\t= &dtv_phandle_target,
|
||||
\t.platdata_size\t= sizeof(dtv_phandle_target),
|
||||
};
|
||||
|
||||
/* Node /phandle2-target index 0 */
|
||||
static struct dtd_target dtv_phandle2_target = {
|
||||
\t.intval\t\t\t= 0x1,
|
||||
};
|
||||
|
@ -381,8 +394,10 @@ U_BOOT_DEVICE(phandle2_target) = {
|
|||
\t.name\t\t= "target",
|
||||
\t.platdata\t= &dtv_phandle2_target,
|
||||
\t.platdata_size\t= sizeof(dtv_phandle2_target),
|
||||
\t.parent_idx\t= -1,
|
||||
};
|
||||
|
||||
/* Node /phandle3-target index 1 */
|
||||
static struct dtd_target dtv_phandle3_target = {
|
||||
\t.intval\t\t\t= 0x2,
|
||||
};
|
||||
|
@ -390,37 +405,48 @@ U_BOOT_DEVICE(phandle3_target) = {
|
|||
\t.name\t\t= "target",
|
||||
\t.platdata\t= &dtv_phandle3_target,
|
||||
\t.platdata_size\t= sizeof(dtv_phandle3_target),
|
||||
\t.parent_idx\t= -1,
|
||||
};
|
||||
|
||||
/* Node /phandle-target index 4 */
|
||||
static struct dtd_target dtv_phandle_target = {
|
||||
\t.intval\t\t\t= 0x0,
|
||||
};
|
||||
U_BOOT_DEVICE(phandle_target) = {
|
||||
\t.name\t\t= "target",
|
||||
\t.platdata\t= &dtv_phandle_target,
|
||||
\t.platdata_size\t= sizeof(dtv_phandle_target),
|
||||
\t.parent_idx\t= -1,
|
||||
};
|
||||
|
||||
/* Node /phandle-source index 2 */
|
||||
static struct dtd_source dtv_phandle_source = {
|
||||
\t.clocks\t\t\t= {
|
||||
\t\t\t{NULL, {}},
|
||||
\t\t\t{NULL, {11}},
|
||||
\t\t\t{NULL, {12, 13}},
|
||||
\t\t\t{NULL, {}},},
|
||||
\t\t\t{4, {}},
|
||||
\t\t\t{0, {11}},
|
||||
\t\t\t{1, {12, 13}},
|
||||
\t\t\t{4, {}},},
|
||||
};
|
||||
U_BOOT_DEVICE(phandle_source) = {
|
||||
\t.name\t\t= "source",
|
||||
\t.platdata\t= &dtv_phandle_source,
|
||||
\t.platdata_size\t= sizeof(dtv_phandle_source),
|
||||
\t.parent_idx\t= -1,
|
||||
};
|
||||
|
||||
/* Node /phandle-source2 index 3 */
|
||||
static struct dtd_source dtv_phandle_source2 = {
|
||||
\t.clocks\t\t\t= {
|
||||
\t\t\t{NULL, {}},},
|
||||
\t\t\t{4, {}},},
|
||||
};
|
||||
U_BOOT_DEVICE(phandle_source2) = {
|
||||
\t.name\t\t= "source",
|
||||
\t.platdata\t= &dtv_phandle_source2,
|
||||
\t.platdata_size\t= sizeof(dtv_phandle_source2),
|
||||
\t.parent_idx\t= -1,
|
||||
};
|
||||
|
||||
void dm_populate_phandle_data(void) {
|
||||
\tdtv_phandle_source.clocks[0].node = DM_GET_DEVICE(phandle_target);
|
||||
\tdtv_phandle_source.clocks[1].node = DM_GET_DEVICE(phandle2_target);
|
||||
\tdtv_phandle_source.clocks[2].node = DM_GET_DEVICE(phandle3_target);
|
||||
\tdtv_phandle_source.clocks[3].node = DM_GET_DEVICE(phandle_target);
|
||||
\tdtv_phandle_source2.clocks[0].node = DM_GET_DEVICE(phandle_target);
|
||||
}
|
||||
''', data)
|
||||
|
||||
|
@ -448,26 +474,29 @@ struct dtd_target {
|
|||
with open(output) as infile:
|
||||
data = infile.read()
|
||||
self._CheckStrings(C_HEADER + '''
|
||||
/* Node /phandle-target index 1 */
|
||||
static struct dtd_target dtv_phandle_target = {
|
||||
};
|
||||
U_BOOT_DEVICE(phandle_target) = {
|
||||
\t.name\t\t= "target",
|
||||
\t.platdata\t= &dtv_phandle_target,
|
||||
\t.platdata_size\t= sizeof(dtv_phandle_target),
|
||||
\t.parent_idx\t= -1,
|
||||
};
|
||||
|
||||
/* Node /phandle-source2 index 0 */
|
||||
static struct dtd_source dtv_phandle_source2 = {
|
||||
\t.clocks\t\t\t= {
|
||||
\t\t\t{NULL, {}},},
|
||||
\t\t\t{1, {}},},
|
||||
};
|
||||
U_BOOT_DEVICE(phandle_source2) = {
|
||||
\t.name\t\t= "source",
|
||||
\t.platdata\t= &dtv_phandle_source2,
|
||||
\t.platdata_size\t= sizeof(dtv_phandle_source2),
|
||||
\t.parent_idx\t= -1,
|
||||
};
|
||||
|
||||
void dm_populate_phandle_data(void) {
|
||||
\tdtv_phandle_source2.clocks[0].node = DM_GET_DEVICE(phandle_target);
|
||||
}
|
||||
''', data)
|
||||
|
||||
|
@ -479,15 +508,7 @@ void dm_populate_phandle_data(void) {
|
|||
with open(output) as infile:
|
||||
data = infile.read()
|
||||
self._CheckStrings(C_HEADER + '''
|
||||
static struct dtd_target dtv_phandle_target = {
|
||||
\t.intval\t\t\t= 0x0,
|
||||
};
|
||||
U_BOOT_DEVICE(phandle_target) = {
|
||||
\t.name\t\t= "target",
|
||||
\t.platdata\t= &dtv_phandle_target,
|
||||
\t.platdata_size\t= sizeof(dtv_phandle_target),
|
||||
};
|
||||
|
||||
/* Node /phandle2-target index 0 */
|
||||
static struct dtd_target dtv_phandle2_target = {
|
||||
\t.intval\t\t\t= 0x1,
|
||||
};
|
||||
|
@ -495,8 +516,10 @@ U_BOOT_DEVICE(phandle2_target) = {
|
|||
\t.name\t\t= "target",
|
||||
\t.platdata\t= &dtv_phandle2_target,
|
||||
\t.platdata_size\t= sizeof(dtv_phandle2_target),
|
||||
\t.parent_idx\t= -1,
|
||||
};
|
||||
|
||||
/* Node /phandle3-target index 1 */
|
||||
static struct dtd_target dtv_phandle3_target = {
|
||||
\t.intval\t\t\t= 0x2,
|
||||
};
|
||||
|
@ -504,37 +527,48 @@ U_BOOT_DEVICE(phandle3_target) = {
|
|||
\t.name\t\t= "target",
|
||||
\t.platdata\t= &dtv_phandle3_target,
|
||||
\t.platdata_size\t= sizeof(dtv_phandle3_target),
|
||||
\t.parent_idx\t= -1,
|
||||
};
|
||||
|
||||
/* Node /phandle-target index 4 */
|
||||
static struct dtd_target dtv_phandle_target = {
|
||||
\t.intval\t\t\t= 0x0,
|
||||
};
|
||||
U_BOOT_DEVICE(phandle_target) = {
|
||||
\t.name\t\t= "target",
|
||||
\t.platdata\t= &dtv_phandle_target,
|
||||
\t.platdata_size\t= sizeof(dtv_phandle_target),
|
||||
\t.parent_idx\t= -1,
|
||||
};
|
||||
|
||||
/* Node /phandle-source index 2 */
|
||||
static struct dtd_source dtv_phandle_source = {
|
||||
\t.cd_gpios\t\t= {
|
||||
\t\t\t{NULL, {}},
|
||||
\t\t\t{NULL, {11}},
|
||||
\t\t\t{NULL, {12, 13}},
|
||||
\t\t\t{NULL, {}},},
|
||||
\t\t\t{4, {}},
|
||||
\t\t\t{0, {11}},
|
||||
\t\t\t{1, {12, 13}},
|
||||
\t\t\t{4, {}},},
|
||||
};
|
||||
U_BOOT_DEVICE(phandle_source) = {
|
||||
\t.name\t\t= "source",
|
||||
\t.platdata\t= &dtv_phandle_source,
|
||||
\t.platdata_size\t= sizeof(dtv_phandle_source),
|
||||
\t.parent_idx\t= -1,
|
||||
};
|
||||
|
||||
/* Node /phandle-source2 index 3 */
|
||||
static struct dtd_source dtv_phandle_source2 = {
|
||||
\t.cd_gpios\t\t= {
|
||||
\t\t\t{NULL, {}},},
|
||||
\t\t\t{4, {}},},
|
||||
};
|
||||
U_BOOT_DEVICE(phandle_source2) = {
|
||||
\t.name\t\t= "source",
|
||||
\t.platdata\t= &dtv_phandle_source2,
|
||||
\t.platdata_size\t= sizeof(dtv_phandle_source2),
|
||||
\t.parent_idx\t= -1,
|
||||
};
|
||||
|
||||
void dm_populate_phandle_data(void) {
|
||||
\tdtv_phandle_source.cd_gpios[0].node = DM_GET_DEVICE(phandle_target);
|
||||
\tdtv_phandle_source.cd_gpios[1].node = DM_GET_DEVICE(phandle2_target);
|
||||
\tdtv_phandle_source.cd_gpios[2].node = DM_GET_DEVICE(phandle3_target);
|
||||
\tdtv_phandle_source.cd_gpios[3].node = DM_GET_DEVICE(phandle_target);
|
||||
\tdtv_phandle_source2.cd_gpios[0].node = DM_GET_DEVICE(phandle_target);
|
||||
}
|
||||
''', data)
|
||||
|
||||
|
@ -581,6 +615,7 @@ struct dtd_test3 {
|
|||
with open(output) as infile:
|
||||
data = infile.read()
|
||||
self._CheckStrings(C_HEADER + '''
|
||||
/* Node /test1 index 0 */
|
||||
static struct dtd_test1 dtv_test1 = {
|
||||
\t.reg\t\t\t= {0x1234, 0x5678},
|
||||
};
|
||||
|
@ -588,8 +623,10 @@ U_BOOT_DEVICE(test1) = {
|
|||
\t.name\t\t= "test1",
|
||||
\t.platdata\t= &dtv_test1,
|
||||
\t.platdata_size\t= sizeof(dtv_test1),
|
||||
\t.parent_idx\t= -1,
|
||||
};
|
||||
|
||||
/* Node /test2 index 1 */
|
||||
static struct dtd_test2 dtv_test2 = {
|
||||
\t.reg\t\t\t= {0x1234567890123456, 0x9876543210987654},
|
||||
};
|
||||
|
@ -597,8 +634,10 @@ U_BOOT_DEVICE(test2) = {
|
|||
\t.name\t\t= "test2",
|
||||
\t.platdata\t= &dtv_test2,
|
||||
\t.platdata_size\t= sizeof(dtv_test2),
|
||||
\t.parent_idx\t= -1,
|
||||
};
|
||||
|
||||
/* Node /test3 index 2 */
|
||||
static struct dtd_test3 dtv_test3 = {
|
||||
\t.reg\t\t\t= {0x1234567890123456, 0x9876543210987654, 0x2, 0x3},
|
||||
};
|
||||
|
@ -606,6 +645,7 @@ U_BOOT_DEVICE(test3) = {
|
|||
\t.name\t\t= "test3",
|
||||
\t.platdata\t= &dtv_test3,
|
||||
\t.platdata_size\t= sizeof(dtv_test3),
|
||||
\t.parent_idx\t= -1,
|
||||
};
|
||||
|
||||
''' + C_EMPTY_POPULATE_PHANDLE_DATA, data)
|
||||
|
@ -630,6 +670,7 @@ struct dtd_test2 {
|
|||
with open(output) as infile:
|
||||
data = infile.read()
|
||||
self._CheckStrings(C_HEADER + '''
|
||||
/* Node /test1 index 0 */
|
||||
static struct dtd_test1 dtv_test1 = {
|
||||
\t.reg\t\t\t= {0x1234, 0x5678},
|
||||
};
|
||||
|
@ -637,8 +678,10 @@ U_BOOT_DEVICE(test1) = {
|
|||
\t.name\t\t= "test1",
|
||||
\t.platdata\t= &dtv_test1,
|
||||
\t.platdata_size\t= sizeof(dtv_test1),
|
||||
\t.parent_idx\t= -1,
|
||||
};
|
||||
|
||||
/* Node /test2 index 1 */
|
||||
static struct dtd_test2 dtv_test2 = {
|
||||
\t.reg\t\t\t= {0x12345678, 0x98765432, 0x2, 0x3},
|
||||
};
|
||||
|
@ -646,6 +689,7 @@ U_BOOT_DEVICE(test2) = {
|
|||
\t.name\t\t= "test2",
|
||||
\t.platdata\t= &dtv_test2,
|
||||
\t.platdata_size\t= sizeof(dtv_test2),
|
||||
\t.parent_idx\t= -1,
|
||||
};
|
||||
|
||||
''' + C_EMPTY_POPULATE_PHANDLE_DATA, data)
|
||||
|
@ -673,6 +717,7 @@ struct dtd_test3 {
|
|||
with open(output) as infile:
|
||||
data = infile.read()
|
||||
self._CheckStrings(C_HEADER + '''
|
||||
/* Node /test1 index 0 */
|
||||
static struct dtd_test1 dtv_test1 = {
|
||||
\t.reg\t\t\t= {0x123400000000, 0x5678},
|
||||
};
|
||||
|
@ -680,8 +725,10 @@ U_BOOT_DEVICE(test1) = {
|
|||
\t.name\t\t= "test1",
|
||||
\t.platdata\t= &dtv_test1,
|
||||
\t.platdata_size\t= sizeof(dtv_test1),
|
||||
\t.parent_idx\t= -1,
|
||||
};
|
||||
|
||||
/* Node /test2 index 1 */
|
||||
static struct dtd_test2 dtv_test2 = {
|
||||
\t.reg\t\t\t= {0x1234567890123456, 0x98765432},
|
||||
};
|
||||
|
@ -689,8 +736,10 @@ U_BOOT_DEVICE(test2) = {
|
|||
\t.name\t\t= "test2",
|
||||
\t.platdata\t= &dtv_test2,
|
||||
\t.platdata_size\t= sizeof(dtv_test2),
|
||||
\t.parent_idx\t= -1,
|
||||
};
|
||||
|
||||
/* Node /test3 index 2 */
|
||||
static struct dtd_test3 dtv_test3 = {
|
||||
\t.reg\t\t\t= {0x1234567890123456, 0x98765432, 0x2, 0x3},
|
||||
};
|
||||
|
@ -698,6 +747,7 @@ U_BOOT_DEVICE(test3) = {
|
|||
\t.name\t\t= "test3",
|
||||
\t.platdata\t= &dtv_test3,
|
||||
\t.platdata_size\t= sizeof(dtv_test3),
|
||||
\t.parent_idx\t= -1,
|
||||
};
|
||||
|
||||
''' + C_EMPTY_POPULATE_PHANDLE_DATA, data)
|
||||
|
@ -725,6 +775,7 @@ struct dtd_test3 {
|
|||
with open(output) as infile:
|
||||
data = infile.read()
|
||||
self._CheckStrings(C_HEADER + '''
|
||||
/* Node /test1 index 0 */
|
||||
static struct dtd_test1 dtv_test1 = {
|
||||
\t.reg\t\t\t= {0x1234, 0x567800000000},
|
||||
};
|
||||
|
@ -732,8 +783,10 @@ U_BOOT_DEVICE(test1) = {
|
|||
\t.name\t\t= "test1",
|
||||
\t.platdata\t= &dtv_test1,
|
||||
\t.platdata_size\t= sizeof(dtv_test1),
|
||||
\t.parent_idx\t= -1,
|
||||
};
|
||||
|
||||
/* Node /test2 index 1 */
|
||||
static struct dtd_test2 dtv_test2 = {
|
||||
\t.reg\t\t\t= {0x12345678, 0x9876543210987654},
|
||||
};
|
||||
|
@ -741,8 +794,10 @@ U_BOOT_DEVICE(test2) = {
|
|||
\t.name\t\t= "test2",
|
||||
\t.platdata\t= &dtv_test2,
|
||||
\t.platdata_size\t= sizeof(dtv_test2),
|
||||
\t.parent_idx\t= -1,
|
||||
};
|
||||
|
||||
/* Node /test3 index 2 */
|
||||
static struct dtd_test3 dtv_test3 = {
|
||||
\t.reg\t\t\t= {0x12345678, 0x9876543210987654, 0x2, 0x3},
|
||||
};
|
||||
|
@ -750,6 +805,7 @@ U_BOOT_DEVICE(test3) = {
|
|||
\t.name\t\t= "test3",
|
||||
\t.platdata\t= &dtv_test3,
|
||||
\t.platdata_size\t= sizeof(dtv_test3),
|
||||
\t.parent_idx\t= -1,
|
||||
};
|
||||
|
||||
''' + C_EMPTY_POPULATE_PHANDLE_DATA, data)
|
||||
|
@ -792,6 +848,7 @@ struct dtd_sandbox_spl_test {
|
|||
with open(output) as infile:
|
||||
data = infile.read()
|
||||
self._CheckStrings(C_HEADER + '''
|
||||
/* Node /spl-test index 0 */
|
||||
static struct dtd_sandbox_spl_test dtv_spl_test = {
|
||||
\t.intval\t\t\t= 0x1,
|
||||
};
|
||||
|
@ -799,8 +856,10 @@ U_BOOT_DEVICE(spl_test) = {
|
|||
\t.name\t\t= "sandbox_spl_test",
|
||||
\t.platdata\t= &dtv_spl_test,
|
||||
\t.platdata_size\t= sizeof(dtv_spl_test),
|
||||
\t.parent_idx\t= -1,
|
||||
};
|
||||
|
||||
/* Node /spl-test2 index 1 */
|
||||
static struct dtd_sandbox_spl_test dtv_spl_test2 = {
|
||||
\t.intarray\t\t= 0x5,
|
||||
};
|
||||
|
@ -808,6 +867,7 @@ U_BOOT_DEVICE(spl_test2) = {
|
|||
\t.name\t\t= "sandbox_spl_test",
|
||||
\t.platdata\t= &dtv_spl_test2,
|
||||
\t.platdata_size\t= sizeof(dtv_spl_test2),
|
||||
\t.parent_idx\t= -1,
|
||||
};
|
||||
|
||||
''' + C_EMPTY_POPULATE_PHANDLE_DATA, data)
|
||||
|
|
|
@ -298,6 +298,7 @@ class TestProp(unittest.TestCase):
|
|||
def testWiden(self):
|
||||
"""Test widening of values"""
|
||||
node2 = self.dtb.GetNode('/spl-test2')
|
||||
node3 = self.dtb.GetNode('/spl-test3')
|
||||
prop = self.node.props['intval']
|
||||
|
||||
# No action
|
||||
|
@ -316,11 +317,20 @@ class TestProp(unittest.TestCase):
|
|||
# byte array, it should turn into an array.
|
||||
prop = self.node.props['longbytearray']
|
||||
prop2 = node2.props['longbytearray']
|
||||
prop3 = node3.props['longbytearray']
|
||||
self.assertFalse(isinstance(prop2.value, list))
|
||||
self.assertEqual(4, len(prop2.value))
|
||||
self.assertEqual(b'\x09\x0a\x0b\x0c', prop2.value)
|
||||
prop2.Widen(prop)
|
||||
self.assertTrue(isinstance(prop2.value, list))
|
||||
self.assertEqual(9, len(prop2.value))
|
||||
self.assertEqual(['\x09', '\x0a', '\x0b', '\x0c', '\0',
|
||||
'\0', '\0', '\0', '\0'], prop2.value)
|
||||
prop3.Widen(prop)
|
||||
self.assertTrue(isinstance(prop3.value, list))
|
||||
self.assertEqual(9, len(prop3.value))
|
||||
self.assertEqual(['\x09', '\x0a', '\x0b', '\x0c', '\x0d',
|
||||
'\x0e', '\x0f', '\x10', '\0'], prop3.value)
|
||||
|
||||
# Similarly for a string array
|
||||
prop = self.node.props['stringval']
|
||||
|
|
Loading…
Reference in a new issue