mirror of
https://github.com/u-boot/u-boot.git
synced 2025-04-26 15:28:50 +00:00
dtoc support for of-platdata-inst
driver model support for of-platdata-inst support of-platdata-inst on x86 / coral binman support for exapanded entries binman convert docs to reST ti-sysc fix for duplicate uclass driver patman minor improvements pylibfdt build only if needed correct obscure CI error with OF_PLATDATA_INST -----BEGIN PGP SIGNATURE----- iQFFBAABCgAvFiEEslwAIq+Gp8wWVbYnfxc6PpAIreYFAmBdZYURHHNqZ0BjaHJv bWl1bS5vcmcACgkQfxc6PpAIreb2rQgAyr1rufrt1UGjZlVjk0HtqX0sdmcOoE4e 6NIuatWXPcP2QR93O9zeGgf/yqNIf3lVIa6Cy3baJBfP6fceZ8B24/xgKKEauPFf g99sec+q7LPL/oigajXIaWorFXK/NDRtQcSIQFu/EmvCmi0m8Iu0HKFa7YBqa7dc YdhGnJZZOdYuQmlKewq9q4cIr6qNtTZczsozt4PNZVgB2lKusBNyKRPZErNEFiN6 7A56bb8tcfWgGXenKVTUUcyjWRXM2tt4QtrPFedZsF6cLa8D5v4MfWMs0QBRFl/u fMzxyeb46x0wsYBNqIBOC7DQWaU/ZeFlr5mQObIH0ypdcsUnEX98sw== =Ld3P -----END PGP SIGNATURE----- Merge tag 'dm-pull-26mar21-take2' of git://git.denx.de/u-boot-dm into next dtoc support for of-platdata-inst driver model support for of-platdata-inst support of-platdata-inst on x86 / coral binman support for exapanded entries binman convert docs to reST ti-sysc fix for duplicate uclass driver patman minor improvements pylibfdt build only if needed correct obscure CI error with OF_PLATDATA_INST
This commit is contained in:
commit
9c7335e4e6
192 changed files with 6561 additions and 1546 deletions
|
@ -148,7 +148,7 @@ jobs:
|
||||||
export UBOOT_TRAVIS_BUILD_DIR=/tmp/sandbox_spl
|
export UBOOT_TRAVIS_BUILD_DIR=/tmp/sandbox_spl
|
||||||
export PYTHONPATH=${UBOOT_TRAVIS_BUILD_DIR}/scripts/dtc/pylibfdt
|
export PYTHONPATH=${UBOOT_TRAVIS_BUILD_DIR}/scripts/dtc/pylibfdt
|
||||||
export PATH=${UBOOT_TRAVIS_BUILD_DIR}/scripts/dtc:${PATH}
|
export PATH=${UBOOT_TRAVIS_BUILD_DIR}/scripts/dtc:${PATH}
|
||||||
./tools/buildman/buildman -T0 -o ${UBOOT_TRAVIS_BUILD_DIR} -w sandbox_spl
|
./tools/buildman/buildman -T0 -o ${UBOOT_TRAVIS_BUILD_DIR} -w --board sandbox_spl
|
||||||
./tools/binman/binman --toolpath ${UBOOT_TRAVIS_BUILD_DIR}/tools test
|
./tools/binman/binman --toolpath ${UBOOT_TRAVIS_BUILD_DIR}/tools test
|
||||||
./tools/buildman/buildman -t
|
./tools/buildman/buildman -t
|
||||||
./tools/dtoc/dtoc -t
|
./tools/dtoc/dtoc -t
|
||||||
|
@ -187,6 +187,9 @@ jobs:
|
||||||
sandbox_spl:
|
sandbox_spl:
|
||||||
TEST_PY_BD: "sandbox_spl"
|
TEST_PY_BD: "sandbox_spl"
|
||||||
TEST_PY_TEST_SPEC: "test_ofplatdata or test_handoff or test_spl"
|
TEST_PY_TEST_SPEC: "test_ofplatdata or test_handoff or test_spl"
|
||||||
|
sandbox_noinst:
|
||||||
|
TEST_PY_BD: "sandbox_noinst"
|
||||||
|
TEST_PY_TEST_SPEC: "test_ofplatdata or test_handoff or test_spl"
|
||||||
sandbox_flattree:
|
sandbox_flattree:
|
||||||
TEST_PY_BD: "sandbox_flattree"
|
TEST_PY_BD: "sandbox_flattree"
|
||||||
evb_ast2500:
|
evb_ast2500:
|
||||||
|
|
|
@ -168,7 +168,8 @@ Run binman, buildman, dtoc, Kconfig and patman testsuites:
|
||||||
export UBOOT_TRAVIS_BUILD_DIR=/tmp/sandbox_spl;
|
export UBOOT_TRAVIS_BUILD_DIR=/tmp/sandbox_spl;
|
||||||
export PYTHONPATH="${UBOOT_TRAVIS_BUILD_DIR}/scripts/dtc/pylibfdt";
|
export PYTHONPATH="${UBOOT_TRAVIS_BUILD_DIR}/scripts/dtc/pylibfdt";
|
||||||
export PATH="${UBOOT_TRAVIS_BUILD_DIR}/scripts/dtc:${PATH}";
|
export PATH="${UBOOT_TRAVIS_BUILD_DIR}/scripts/dtc:${PATH}";
|
||||||
./tools/buildman/buildman -T0 -o ${UBOOT_TRAVIS_BUILD_DIR} -w sandbox_spl;
|
./tools/buildman/buildman -T0 -o ${UBOOT_TRAVIS_BUILD_DIR} -w
|
||||||
|
--board sandbox_spl;
|
||||||
./tools/binman/binman --toolpath ${UBOOT_TRAVIS_BUILD_DIR}/tools test;
|
./tools/binman/binman --toolpath ${UBOOT_TRAVIS_BUILD_DIR}/tools test;
|
||||||
./tools/buildman/buildman -t;
|
./tools/buildman/buildman -t;
|
||||||
./tools/dtoc/dtoc -t;
|
./tools/dtoc/dtoc -t;
|
||||||
|
@ -204,6 +205,13 @@ sandbox_spl test.py:
|
||||||
TEST_PY_TEST_SPEC: "test_ofplatdata or test_handoff or test_spl"
|
TEST_PY_TEST_SPEC: "test_ofplatdata or test_handoff or test_spl"
|
||||||
<<: *buildman_and_testpy_dfn
|
<<: *buildman_and_testpy_dfn
|
||||||
|
|
||||||
|
sandbox_noinst_test.py:
|
||||||
|
tags: [ 'all' ]
|
||||||
|
variables:
|
||||||
|
TEST_PY_BD: "sandbox_noinst"
|
||||||
|
TEST_PY_TEST_SPEC: "test_ofplatdata or test_handoff or test_spl"
|
||||||
|
<<: *buildman_and_testpy_dfn
|
||||||
|
|
||||||
evb-ast2500 test.py:
|
evb-ast2500 test.py:
|
||||||
tags: [ 'all' ]
|
tags: [ 'all' ]
|
||||||
variables:
|
variables:
|
||||||
|
|
16
Makefile
16
Makefile
|
@ -17,9 +17,13 @@ NAME =
|
||||||
# o Look for make include files relative to root of kernel src
|
# o Look for make include files relative to root of kernel src
|
||||||
MAKEFLAGS += -rR --include-dir=$(CURDIR)
|
MAKEFLAGS += -rR --include-dir=$(CURDIR)
|
||||||
|
|
||||||
# Determine host architecture
|
# Determine target architecture for the sandbox
|
||||||
include include/host_arch.h
|
include include/host_arch.h
|
||||||
|
ifeq ("", "$(CROSS_COMPILE)")
|
||||||
MK_ARCH="${shell uname -m}"
|
MK_ARCH="${shell uname -m}"
|
||||||
|
else
|
||||||
|
MK_ARCH="${shell echo $(CROSS_COMPILE) | sed -n 's/^\s*\([^\/]*\/\)*\([^-]*\)-\S*/\2/p'}"
|
||||||
|
endif
|
||||||
unexport HOST_ARCH
|
unexport HOST_ARCH
|
||||||
ifeq ("x86_64", $(MK_ARCH))
|
ifeq ("x86_64", $(MK_ARCH))
|
||||||
export HOST_ARCH=$(HOST_ARCH_X86_64)
|
export HOST_ARCH=$(HOST_ARCH_X86_64)
|
||||||
|
@ -27,7 +31,7 @@ else ifneq (,$(findstring $(MK_ARCH), "i386" "i486" "i586" "i686"))
|
||||||
export HOST_ARCH=$(HOST_ARCH_X86)
|
export HOST_ARCH=$(HOST_ARCH_X86)
|
||||||
else ifneq (,$(findstring $(MK_ARCH), "aarch64" "armv8l"))
|
else ifneq (,$(findstring $(MK_ARCH), "aarch64" "armv8l"))
|
||||||
export HOST_ARCH=$(HOST_ARCH_AARCH64)
|
export HOST_ARCH=$(HOST_ARCH_AARCH64)
|
||||||
else ifeq ("armv7l", $(MK_ARCH))
|
else ifneq (,$(findstring $(MK_ARCH), "arm" "armv7" "armv7l"))
|
||||||
export HOST_ARCH=$(HOST_ARCH_ARM)
|
export HOST_ARCH=$(HOST_ARCH_ARM)
|
||||||
else ifeq ("riscv32", $(MK_ARCH))
|
else ifeq ("riscv32", $(MK_ARCH))
|
||||||
export HOST_ARCH=$(HOST_ARCH_RISCV32)
|
export HOST_ARCH=$(HOST_ARCH_RISCV32)
|
||||||
|
@ -1328,6 +1332,11 @@ u-boot.ldr: u-boot
|
||||||
# Use 'make BINMAN_DEBUG=1' to enable debugging
|
# Use 'make BINMAN_DEBUG=1' to enable debugging
|
||||||
# Use 'make BINMAN_VERBOSE=3' to set vebosity level
|
# Use 'make BINMAN_VERBOSE=3' to set vebosity level
|
||||||
default_dt := $(if $(DEVICE_TREE),$(DEVICE_TREE),$(CONFIG_DEFAULT_DEVICE_TREE))
|
default_dt := $(if $(DEVICE_TREE),$(DEVICE_TREE),$(CONFIG_DEFAULT_DEVICE_TREE))
|
||||||
|
|
||||||
|
# Tell binman whether we have a devicetree for SPL and TPL
|
||||||
|
have_spl_dt := $(if $(CONFIG_SPL_OF_PLATDATA),,$(CONFIG_SPL_OF_CONTROL))
|
||||||
|
have_tpl_dt := $(if $(CONFIG_TPL_OF_PLATDATA),,$(CONFIG_TPL_OF_CONTROL))
|
||||||
|
|
||||||
quiet_cmd_binman = BINMAN $@
|
quiet_cmd_binman = BINMAN $@
|
||||||
cmd_binman = $(srctree)/tools/binman/binman $(if $(BINMAN_DEBUG),-D) \
|
cmd_binman = $(srctree)/tools/binman/binman $(if $(BINMAN_DEBUG),-D) \
|
||||||
--toolpath $(objtree)/tools \
|
--toolpath $(objtree)/tools \
|
||||||
|
@ -1338,6 +1347,9 @@ cmd_binman = $(srctree)/tools/binman/binman $(if $(BINMAN_DEBUG),-D) \
|
||||||
-a atf-bl31-path=${BL31} \
|
-a atf-bl31-path=${BL31} \
|
||||||
-a default-dt=$(default_dt) \
|
-a default-dt=$(default_dt) \
|
||||||
-a scp-path=$(SCP) \
|
-a scp-path=$(SCP) \
|
||||||
|
-a spl-bss-pad=$(if $(CONFIG_SPL_SEPARATE_BSS),,1) \
|
||||||
|
-a tpl-bss-pad=$(if $(CONFIG_TPL_SEPARATE_BSS),,1) \
|
||||||
|
-a spl-dtb=$(have_spl_dt) -a tpl-dtb=$(have_tpl_dt) \
|
||||||
$(BINMAN_$(@F))
|
$(BINMAN_$(@F))
|
||||||
|
|
||||||
OBJCOPYFLAGS_u-boot.ldr.hex := -I binary -O ihex
|
OBJCOPYFLAGS_u-boot.ldr.hex := -I binary -O ihex
|
||||||
|
|
|
@ -845,7 +845,6 @@ int os_spl_to_uboot(const char *fname)
|
||||||
{
|
{
|
||||||
struct sandbox_state *state = state_get_current();
|
struct sandbox_state *state = state_get_current();
|
||||||
|
|
||||||
printf("%s\n", __func__);
|
|
||||||
/* U-Boot will delete ram buffer after read: "--rm_memory"*/
|
/* U-Boot will delete ram buffer after read: "--rm_memory"*/
|
||||||
state->ram_buf_rm = true;
|
state->ram_buf_rm = true;
|
||||||
return os_jump_to_file(fname);
|
return os_jump_to_file(fname);
|
||||||
|
|
|
@ -13,6 +13,14 @@ SECTIONS
|
||||||
KEEP(*(SORT(.u_boot_list*)));
|
KEEP(*(SORT(.u_boot_list*)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Private data for devices with OF_PLATDATA_RT */
|
||||||
|
. = ALIGN(4);
|
||||||
|
.priv_data : {
|
||||||
|
__priv_data_start = .;
|
||||||
|
*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.priv_data*)))
|
||||||
|
__priv_data_end = .;
|
||||||
|
}
|
||||||
|
|
||||||
__u_boot_sandbox_option_start = .;
|
__u_boot_sandbox_option_start = .;
|
||||||
_u_boot_sandbox_getopt : { KEEP(*(.u_boot_sandbox_getopt)) }
|
_u_boot_sandbox_getopt : { KEEP(*(.u_boot_sandbox_getopt)) }
|
||||||
__u_boot_sandbox_option_end = .;
|
__u_boot_sandbox_option_end = .;
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
|
|
||||||
clk_fixed: clk-fixed {
|
clk_fixed: clk-fixed {
|
||||||
u-boot,dm-pre-reloc;
|
u-boot,dm-pre-reloc;
|
||||||
compatible = "fixed-clock";
|
compatible = "sandbox,fixed-clock";
|
||||||
#clock-cells = <0>;
|
#clock-cells = <0>;
|
||||||
clock-frequency = <1234>;
|
clock-frequency = <1234>;
|
||||||
};
|
};
|
||||||
|
@ -101,15 +101,19 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
i2c_emul: emul {
|
i2c_emul: emul {
|
||||||
|
u-boot,dm-pre-reloc;
|
||||||
reg = <0xff>;
|
reg = <0xff>;
|
||||||
compatible = "sandbox,i2c-emul-parent";
|
compatible = "sandbox,i2c-emul-parent";
|
||||||
emul_eeprom: emul-eeprom {
|
emul_eeprom: emul-eeprom {
|
||||||
compatible = "sandbox,i2c-eeprom";
|
compatible = "sandbox,i2c-eeprom";
|
||||||
sandbox,filename = "i2c.bin";
|
sandbox,filename = "i2c.bin";
|
||||||
sandbox,size = <256>;
|
sandbox,size = <256>;
|
||||||
|
#emul-cells = <0>;
|
||||||
};
|
};
|
||||||
emul0: emul0 {
|
emul0: emul0 {
|
||||||
compatible = "sandbox,i2c-rtc";
|
u-boot,dm-pre-reloc;
|
||||||
|
compatible = "sandbox,i2c-rtc-emul";
|
||||||
|
#emul-cells = <0>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -260,15 +264,11 @@
|
||||||
stringarray = "pre-proper";
|
stringarray = "pre-proper";
|
||||||
};
|
};
|
||||||
|
|
||||||
test-bus {
|
|
||||||
compatible = "simple-bus";
|
|
||||||
u-boot,dm-spl;
|
|
||||||
spl-test7 {
|
spl-test7 {
|
||||||
u-boot,dm-spl;
|
u-boot,dm-spl;
|
||||||
compatible = "sandbox,spl-test";
|
compatible = "sandbox,spl-test";
|
||||||
stringarray = "spl";
|
stringarray = "spl";
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
square {
|
square {
|
||||||
compatible = "demo-shape";
|
compatible = "demo-shape";
|
||||||
|
|
|
@ -604,10 +604,10 @@
|
||||||
sandbox,size = <256>;
|
sandbox,size = <256>;
|
||||||
};
|
};
|
||||||
emul0: emul0 {
|
emul0: emul0 {
|
||||||
compatible = "sandbox,i2c-rtc";
|
compatible = "sandbox,i2c-rtc-emul";
|
||||||
};
|
};
|
||||||
emul1: emull {
|
emul1: emull {
|
||||||
compatible = "sandbox,i2c-rtc";
|
compatible = "sandbox,i2c-rtc-emul";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1402,3 +1402,4 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
#include "sandbox_pmic.dtsi"
|
#include "sandbox_pmic.dtsi"
|
||||||
|
#include "cros-ec-keyboard.dtsi"
|
||||||
|
|
|
@ -7,6 +7,9 @@
|
||||||
#define __SANDBOX_CLK_H
|
#define __SANDBOX_CLK_H
|
||||||
|
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
|
#include <clk.h>
|
||||||
|
#include <dt-structs.h>
|
||||||
|
#include <linux/clk-provider.h>
|
||||||
|
|
||||||
struct udevice;
|
struct udevice;
|
||||||
|
|
||||||
|
@ -45,6 +48,27 @@ enum sandbox_clk_test_id {
|
||||||
|
|
||||||
#define SANDBOX_CLK_TEST_NON_DEVM_COUNT SANDBOX_CLK_TEST_ID_DEVM1
|
#define SANDBOX_CLK_TEST_NON_DEVM_COUNT SANDBOX_CLK_TEST_ID_DEVM1
|
||||||
|
|
||||||
|
struct sandbox_clk_priv {
|
||||||
|
bool probed;
|
||||||
|
ulong rate[SANDBOX_CLK_ID_COUNT];
|
||||||
|
bool enabled[SANDBOX_CLK_ID_COUNT];
|
||||||
|
bool requested[SANDBOX_CLK_ID_COUNT];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sandbox_clk_test {
|
||||||
|
struct clk clks[SANDBOX_CLK_TEST_NON_DEVM_COUNT];
|
||||||
|
struct clk *clkps[SANDBOX_CLK_TEST_ID_COUNT];
|
||||||
|
struct clk_bulk bulk;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Platform data for the sandbox fixed-rate clock driver */
|
||||||
|
struct sandbox_clk_fixed_rate_plat {
|
||||||
|
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||||
|
struct dtd_sandbox_fixed_clock dtplat;
|
||||||
|
#endif
|
||||||
|
struct clk_fixed_rate fixed;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sandbox_clk_query_rate - Query the current rate of a sandbox clock.
|
* sandbox_clk_query_rate - Query the current rate of a sandbox clock.
|
||||||
*
|
*
|
||||||
|
|
|
@ -11,4 +11,19 @@ struct sandbox_i2c_priv {
|
||||||
bool test_mode;
|
bool test_mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct i2c_emul_uc_plat - information about the emulator for this device
|
||||||
|
*
|
||||||
|
* This is used by devices in UCLASS_I2C_EMUL to record information about the
|
||||||
|
* device being emulated. It is accessible with dev_get_uclass_plat()
|
||||||
|
*
|
||||||
|
* @dev: Device being emulated
|
||||||
|
* @idx: of-platdata index, set up by the device's bind() method if of-platdata
|
||||||
|
* is in use
|
||||||
|
*/
|
||||||
|
struct i2c_emul_uc_plat {
|
||||||
|
struct udevice *dev;
|
||||||
|
int idx;
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* __asn_i2c_h */
|
#endif /* __asn_i2c_h */
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
#ifndef __asm_rtc_h
|
#ifndef __asm_rtc_h
|
||||||
#define __asm_rtc_h
|
#define __asm_rtc_h
|
||||||
|
|
||||||
|
#include <dt-structs.h>
|
||||||
|
|
||||||
/* Register numbers in the sandbox RTC */
|
/* Register numbers in the sandbox RTC */
|
||||||
enum {
|
enum {
|
||||||
REG_SEC = 5,
|
REG_SEC = 5,
|
||||||
|
@ -29,4 +31,26 @@ enum {
|
||||||
REG_COUNT = 0x80,
|
REG_COUNT = 0x80,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct sandbox_i2c_rtc_plat_data - platform data for the RTC
|
||||||
|
*
|
||||||
|
* @base_time: Base system time when RTC device was bound
|
||||||
|
* @offset: RTC offset from current system time
|
||||||
|
* @use_system_time: true to use system time, false to use @base_time
|
||||||
|
* @reg: Register values
|
||||||
|
*/
|
||||||
|
struct sandbox_i2c_rtc_plat_data {
|
||||||
|
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||||
|
struct dtd_sandbox_i2c_rtc_emul dtplat;
|
||||||
|
#endif
|
||||||
|
long base_time;
|
||||||
|
long offset;
|
||||||
|
bool use_system_time;
|
||||||
|
u8 reg[REG_COUNT];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sandbox_i2c_rtc {
|
||||||
|
unsigned int offset_secs;
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -21,6 +21,8 @@ config INTEL_APOLLOLAKE
|
||||||
select INTEL_GMA_SWSMISCI
|
select INTEL_GMA_SWSMISCI
|
||||||
select ACPI_GNVS_EXTERNAL
|
select ACPI_GNVS_EXTERNAL
|
||||||
select TPL_OF_PLATDATA_PARENT
|
select TPL_OF_PLATDATA_PARENT
|
||||||
|
select TPL_OF_PLATDATA_INST
|
||||||
|
select TPL_READ_ONLY
|
||||||
imply ENABLE_MRC_CACHE
|
imply ENABLE_MRC_CACHE
|
||||||
imply AHCI_PCI
|
imply AHCI_PCI
|
||||||
imply SCSI
|
imply SCSI
|
||||||
|
|
|
@ -9,8 +9,8 @@
|
||||||
#define LOG_CATEGORY UCLASS_ACPI_PMC
|
#define LOG_CATEGORY UCLASS_ACPI_PMC
|
||||||
|
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
#include <dt-structs.h>
|
|
||||||
#include <dm.h>
|
#include <dm.h>
|
||||||
|
#include <dt-structs.h>
|
||||||
#include <log.h>
|
#include <log.h>
|
||||||
#include <spl.h>
|
#include <spl.h>
|
||||||
#include <acpi/acpi_s3.h>
|
#include <acpi/acpi_s3.h>
|
||||||
|
|
|
@ -93,4 +93,5 @@ U_BOOT_DRIVER(intel_apl_punit) = {
|
||||||
.id = UCLASS_SYSCON,
|
.id = UCLASS_SYSCON,
|
||||||
.of_match = apl_syscon_ids,
|
.of_match = apl_syscon_ids,
|
||||||
.probe = apl_punit_probe,
|
.probe = apl_punit_probe,
|
||||||
|
DM_HEADER(<asm/cpu.h>) /* for X86_SYSCON_PUNIT */
|
||||||
};
|
};
|
||||||
|
|
|
@ -153,8 +153,9 @@ static int route_pmc_gpio_gpe(struct udevice *dev, uint pmc_gpe_num)
|
||||||
|
|
||||||
static int itss_bind(struct udevice *dev)
|
static int itss_bind(struct udevice *dev)
|
||||||
{
|
{
|
||||||
/* This is not set with of-platdata, so set it manually */
|
/* This is not set with basic of-platdata, so set it manually */
|
||||||
if (CONFIG_IS_ENABLED(OF_PLATDATA))
|
if (CONFIG_IS_ENABLED(OF_PLATDATA) &&
|
||||||
|
!CONFIG_IS_ENABLED(OF_PLATDATA_INST))
|
||||||
dev->driver_data = X86_IRQT_ITSS;
|
dev->driver_data = X86_IRQT_ITSS;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -32,6 +32,14 @@ SECTIONS
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
|
.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
|
||||||
|
|
||||||
|
. = ALIGN(4);
|
||||||
|
|
||||||
|
.priv_data : {
|
||||||
|
__priv_data_start = .;
|
||||||
|
*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.priv_data*)))
|
||||||
|
__priv_data_end = .;
|
||||||
|
}
|
||||||
|
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
.data : { *(.data*) }
|
.data : { *(.data*) }
|
||||||
|
|
||||||
|
|
|
@ -100,7 +100,7 @@
|
||||||
clk: clock {
|
clk: clock {
|
||||||
compatible = "intel,apl-clk";
|
compatible = "intel,apl-clk";
|
||||||
#clock-cells = <1>;
|
#clock-cells = <1>;
|
||||||
u-boot,dm-pre-reloc;
|
u-boot,dm-pre-proper;
|
||||||
};
|
};
|
||||||
|
|
||||||
cpus {
|
cpus {
|
||||||
|
@ -141,7 +141,7 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
acpi_gpe: general-purpose-events {
|
acpi_gpe: general-purpose-events {
|
||||||
u-boot,dm-pre-reloc;
|
u-boot,dm-pre-proper;
|
||||||
reg = <IOMAP_ACPI_BASE IOMAP_ACPI_SIZE>;
|
reg = <IOMAP_ACPI_BASE IOMAP_ACPI_SIZE>;
|
||||||
compatible = "intel,acpi-gpe";
|
compatible = "intel,acpi-gpe";
|
||||||
interrupt-controller;
|
interrupt-controller;
|
||||||
|
@ -423,7 +423,7 @@
|
||||||
compatible = "intel,apl-i2c", "snps,designware-i2c-pci";
|
compatible = "intel,apl-i2c", "snps,designware-i2c-pci";
|
||||||
reg = <0x0200b210 0 0 0 0>;
|
reg = <0x0200b210 0 0 0 0>;
|
||||||
early-regs = <IOMAP_I2C2_BASE 0x1000>;
|
early-regs = <IOMAP_I2C2_BASE 0x1000>;
|
||||||
u-boot,dm-pre-reloc;
|
u-boot,dm-pre-proper;
|
||||||
#address-cells = <1>;
|
#address-cells = <1>;
|
||||||
#size-cells = <0>;
|
#size-cells = <0>;
|
||||||
clock-frequency = <400000>;
|
clock-frequency = <400000>;
|
||||||
|
@ -434,7 +434,7 @@
|
||||||
tpm: tpm@50 {
|
tpm: tpm@50 {
|
||||||
reg = <0x50>;
|
reg = <0x50>;
|
||||||
compatible = "google,cr50";
|
compatible = "google,cr50";
|
||||||
u-boot,dm-pre-reloc;
|
u-boot,dm-pre-proper;
|
||||||
u-boot,i2c-offset-len = <0>;
|
u-boot,i2c-offset-len = <0>;
|
||||||
ready-gpios = <&gpio_n 28 GPIO_ACTIVE_LOW>;
|
ready-gpios = <&gpio_n 28 GPIO_ACTIVE_LOW>;
|
||||||
interrupts-extended = <&acpi_gpe GPIO_28_IRQ
|
interrupts-extended = <&acpi_gpe GPIO_28_IRQ
|
||||||
|
@ -1233,5 +1233,5 @@
|
||||||
&rtc {
|
&rtc {
|
||||||
#address-cells = <1>;
|
#address-cells = <1>;
|
||||||
#size-cells = <0>;
|
#size-cells = <0>;
|
||||||
u-boot,dm-pre-reloc;
|
u-boot,dm-pre-proper;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/ {
|
/ {
|
||||||
reset: reset {
|
reset: reset {
|
||||||
compatible = "x86,reset";
|
compatible = "x86,reset";
|
||||||
u-boot,dm-pre-reloc;
|
u-boot,dm-pre-proper;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -38,20 +38,11 @@
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
spl {
|
spl {
|
||||||
type = "section";
|
type = "u-boot-spl";
|
||||||
offset = <CONFIG_X86_OFFSET_SPL>;
|
offset = <CONFIG_X86_OFFSET_SPL>;
|
||||||
u-boot-spl {
|
|
||||||
};
|
|
||||||
u-boot-spl-dtb {
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
u-boot {
|
u-boot {
|
||||||
type = "section";
|
|
||||||
offset = <CONFIG_X86_OFFSET_U_BOOT>;
|
offset = <CONFIG_X86_OFFSET_U_BOOT>;
|
||||||
u-boot-nodtb {
|
|
||||||
};
|
|
||||||
u-boot-dtb {
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
#elif defined(CONFIG_SPL)
|
#elif defined(CONFIG_SPL)
|
||||||
u-boot-spl-with-ucode-ptr {
|
u-boot-spl-with-ucode-ptr {
|
||||||
|
@ -64,11 +55,7 @@
|
||||||
offset = <CONFIG_X86_OFFSET_U_BOOT>;
|
offset = <CONFIG_X86_OFFSET_U_BOOT>;
|
||||||
};
|
};
|
||||||
#else
|
#else
|
||||||
# ifdef CONFIG_SPL
|
# ifdef CONFIG_HAVE_MICROCODE
|
||||||
u-boot {
|
|
||||||
offset = <CONFIG_SYS_TEXT_BASE>;
|
|
||||||
};
|
|
||||||
# elif defined(CONFIG_HAVE_MICROCODE)
|
|
||||||
/* If there is no SPL then we need to put microcode in U-Boot */
|
/* If there is no SPL then we need to put microcode in U-Boot */
|
||||||
u-boot-with-ucode-ptr {
|
u-boot-with-ucode-ptr {
|
||||||
offset = <CONFIG_X86_OFFSET_U_BOOT>;
|
offset = <CONFIG_X86_OFFSET_U_BOOT>;
|
||||||
|
|
|
@ -150,5 +150,6 @@ U_BOOT_DRIVER(pci_x86) = {
|
||||||
.name = "pci_x86",
|
.name = "pci_x86",
|
||||||
.id = UCLASS_SIMPLE_BUS,
|
.id = UCLASS_SIMPLE_BUS,
|
||||||
.of_match = of_match_ptr(tpl_fake_pci_ids),
|
.of_match = of_match_ptr(tpl_fake_pci_ids),
|
||||||
|
DM_PHASE(tpl)
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -20,6 +20,13 @@ F: board/sandbox/
|
||||||
F: include/configs/sandbox_spl.h
|
F: include/configs/sandbox_spl.h
|
||||||
F: configs/sandbox_spl_defconfig
|
F: configs/sandbox_spl_defconfig
|
||||||
|
|
||||||
|
SANDBOX NOINST BOARD
|
||||||
|
M: Simon Glass <sjg@chromium.org>
|
||||||
|
S: Maintained
|
||||||
|
F: board/sandbox/
|
||||||
|
F: include/configs/sandbox_spl.h
|
||||||
|
F: configs/sandbox_noinst_defconfig
|
||||||
|
|
||||||
SANDBOX FLAT TREE BOARD
|
SANDBOX FLAT TREE BOARD
|
||||||
M: Simon Glass <sjg@chromium.org>
|
M: Simon Glass <sjg@chromium.org>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
|
|
|
@ -48,6 +48,7 @@ unsigned long timer_read_counter(void)
|
||||||
static enum env_location env_locations[] = {
|
static enum env_location env_locations[] = {
|
||||||
ENVL_NOWHERE,
|
ENVL_NOWHERE,
|
||||||
ENVL_EXT4,
|
ENVL_EXT4,
|
||||||
|
ENVL_FAT,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum env_location env_get_location(enum env_operation op, int prio)
|
enum env_location env_get_location(enum env_operation op, int prio)
|
||||||
|
|
|
@ -276,6 +276,19 @@ config SPL_SEPARATE_BSS
|
||||||
location is used. Normally we put the device tree at the end of BSS
|
location is used. Normally we put the device tree at the end of BSS
|
||||||
but with this option enabled, it goes at _image_binary_end.
|
but with this option enabled, it goes at _image_binary_end.
|
||||||
|
|
||||||
|
config SPL_READ_ONLY
|
||||||
|
bool
|
||||||
|
depends on SPL_OF_PLATDATA
|
||||||
|
# Bind cannot be supported because the udevice structs are in read-only
|
||||||
|
# memory so we cannot update the linked lists.
|
||||||
|
select SPL_OF_PLATDATA_NO_BIND
|
||||||
|
select SPL_OF_PLATDATA_RT
|
||||||
|
help
|
||||||
|
Some platforms (e.g. x86 Apollo Lake) load SPL into a read-only
|
||||||
|
section of memory. This means that of-platdata must make a copy (in
|
||||||
|
writeable memory) of anything it wants to modify, such as
|
||||||
|
device-private data.
|
||||||
|
|
||||||
config SPL_BANNER_PRINT
|
config SPL_BANNER_PRINT
|
||||||
bool "Enable output of the SPL banner 'U-Boot SPL ...'"
|
bool "Enable output of the SPL banner 'U-Boot SPL ...'"
|
||||||
default y
|
default y
|
||||||
|
@ -1440,6 +1453,17 @@ config TPL_STACK
|
||||||
The address of the initial stack-pointer for the TPL stage.
|
The address of the initial stack-pointer for the TPL stage.
|
||||||
Usually this will be the (aligned) top-of-stack.
|
Usually this will be the (aligned) top-of-stack.
|
||||||
|
|
||||||
|
config TPL_READ_ONLY
|
||||||
|
bool
|
||||||
|
depends on TPL_OF_PLATDATA
|
||||||
|
select TPL_OF_PLATDATA_NO_BIND
|
||||||
|
select TPL_OF_PLATDATA_RT
|
||||||
|
help
|
||||||
|
Some platforms (e.g. x86 Apollo Lake) load SPL into a read-only
|
||||||
|
section of memory. This means that of-platdata must make a copy (in
|
||||||
|
writeable memory) of anything it wants to modify, such as
|
||||||
|
device-private data.
|
||||||
|
|
||||||
config TPL_BOOTROM_SUPPORT
|
config TPL_BOOTROM_SUPPORT
|
||||||
bool "Support returning to the BOOTROM (from TPL)"
|
bool "Support returning to the BOOTROM (from TPL)"
|
||||||
help
|
help
|
||||||
|
|
|
@ -73,6 +73,7 @@ CONFIG_MAC_PARTITION=y
|
||||||
CONFIG_ISO_PARTITION=y
|
CONFIG_ISO_PARTITION=y
|
||||||
CONFIG_EFI_PARTITION=y
|
CONFIG_EFI_PARTITION=y
|
||||||
# CONFIG_SPL_EFI_PARTITION is not set
|
# CONFIG_SPL_EFI_PARTITION is not set
|
||||||
|
CONFIG_OF_SPL_REMOVE_PROPS="clocks clock-names interrupt-parent interrupts linux-name acpi,name acpi,path u-boot,acpi-dsdt-order u-boot,acpi-ssdt-order"
|
||||||
CONFIG_ENV_OVERWRITE=y
|
CONFIG_ENV_OVERWRITE=y
|
||||||
CONFIG_REGMAP=y
|
CONFIG_REGMAP=y
|
||||||
CONFIG_SYSCON=y
|
CONFIG_SYSCON=y
|
||||||
|
|
231
configs/sandbox_noinst_defconfig
Normal file
231
configs/sandbox_noinst_defconfig
Normal file
|
@ -0,0 +1,231 @@
|
||||||
|
CONFIG_SYS_TEXT_BASE=0x200000
|
||||||
|
CONFIG_SPL_LIBCOMMON_SUPPORT=y
|
||||||
|
CONFIG_SPL_LIBGENERIC_SUPPORT=y
|
||||||
|
CONFIG_NR_DRAM_BANKS=1
|
||||||
|
CONFIG_SYS_MEMTEST_START=0x00100000
|
||||||
|
CONFIG_SYS_MEMTEST_END=0x00101000
|
||||||
|
CONFIG_ENV_SIZE=0x2000
|
||||||
|
CONFIG_SPL_SERIAL_SUPPORT=y
|
||||||
|
CONFIG_SPL_DRIVERS_MISC_SUPPORT=y
|
||||||
|
CONFIG_SPL_SYS_MALLOC_F_LEN=0x8000
|
||||||
|
CONFIG_SPL=y
|
||||||
|
CONFIG_BOOTSTAGE_STASH_ADDR=0x0
|
||||||
|
CONFIG_DEFAULT_DEVICE_TREE="sandbox"
|
||||||
|
CONFIG_SANDBOX_SPL=y
|
||||||
|
CONFIG_DEBUG_UART=y
|
||||||
|
CONFIG_DISTRO_DEFAULTS=y
|
||||||
|
CONFIG_FIT=y
|
||||||
|
CONFIG_FIT_SIGNATURE=y
|
||||||
|
CONFIG_FIT_VERBOSE=y
|
||||||
|
CONFIG_SPL_LOAD_FIT=y
|
||||||
|
# CONFIG_USE_SPL_FIT_GENERATOR is not set
|
||||||
|
CONFIG_BOOTSTAGE=y
|
||||||
|
CONFIG_BOOTSTAGE_REPORT=y
|
||||||
|
CONFIG_BOOTSTAGE_FDT=y
|
||||||
|
CONFIG_BOOTSTAGE_STASH=y
|
||||||
|
CONFIG_BOOTSTAGE_STASH_SIZE=0x4096
|
||||||
|
CONFIG_CONSOLE_RECORD=y
|
||||||
|
CONFIG_CONSOLE_RECORD_OUT_SIZE=0x1000
|
||||||
|
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
|
||||||
|
CONFIG_CMD_BOOTEFI_HELLO=y
|
||||||
|
# CONFIG_CMD_ELF is not set
|
||||||
|
CONFIG_CMD_ASKENV=y
|
||||||
|
CONFIG_CMD_GREPENV=y
|
||||||
|
CONFIG_CMD_ERASEENV=y
|
||||||
|
CONFIG_CMD_ENV_CALLBACK=y
|
||||||
|
CONFIG_CMD_ENV_FLAGS=y
|
||||||
|
CONFIG_CMD_NVEDIT_INFO=y
|
||||||
|
CONFIG_CMD_NVEDIT_LOAD=y
|
||||||
|
CONFIG_CMD_NVEDIT_SELECT=y
|
||||||
|
CONFIG_LOOPW=y
|
||||||
|
CONFIG_CMD_MD5SUM=y
|
||||||
|
CONFIG_CMD_MEMINFO=y
|
||||||
|
CONFIG_CMD_MX_CYCLIC=y
|
||||||
|
CONFIG_CMD_MEMTEST=y
|
||||||
|
CONFIG_CMD_DEMO=y
|
||||||
|
CONFIG_CMD_GPIO=y
|
||||||
|
CONFIG_CMD_GPT=y
|
||||||
|
CONFIG_CMD_IDE=y
|
||||||
|
CONFIG_CMD_I2C=y
|
||||||
|
CONFIG_CMD_OSD=y
|
||||||
|
CONFIG_CMD_PCI=y
|
||||||
|
CONFIG_CMD_REMOTEPROC=y
|
||||||
|
CONFIG_CMD_SPI=y
|
||||||
|
CONFIG_CMD_USB=y
|
||||||
|
CONFIG_BOOTP_DNS2=y
|
||||||
|
CONFIG_CMD_TFTPPUT=y
|
||||||
|
CONFIG_CMD_TFTPSRV=y
|
||||||
|
CONFIG_CMD_RARP=y
|
||||||
|
CONFIG_CMD_CDP=y
|
||||||
|
CONFIG_CMD_SNTP=y
|
||||||
|
CONFIG_CMD_DNS=y
|
||||||
|
CONFIG_CMD_LINK_LOCAL=y
|
||||||
|
CONFIG_CMD_BMP=y
|
||||||
|
CONFIG_CMD_EFIDEBUG=y
|
||||||
|
CONFIG_CMD_TIME=y
|
||||||
|
CONFIG_CMD_TIMER=y
|
||||||
|
CONFIG_CMD_SOUND=y
|
||||||
|
CONFIG_CMD_QFW=y
|
||||||
|
CONFIG_CMD_BOOTSTAGE=y
|
||||||
|
CONFIG_CMD_PMIC=y
|
||||||
|
CONFIG_CMD_REGULATOR=y
|
||||||
|
CONFIG_CMD_TPM=y
|
||||||
|
CONFIG_CMD_TPM_TEST=y
|
||||||
|
CONFIG_CMD_CBFS=y
|
||||||
|
CONFIG_CMD_CRAMFS=y
|
||||||
|
CONFIG_CMD_EXT4_WRITE=y
|
||||||
|
CONFIG_MAC_PARTITION=y
|
||||||
|
CONFIG_AMIGA_PARTITION=y
|
||||||
|
CONFIG_OF_CONTROL=y
|
||||||
|
CONFIG_SPL_OF_CONTROL=y
|
||||||
|
CONFIG_OF_HOSTFILE=y
|
||||||
|
CONFIG_SPL_OF_PLATDATA=y
|
||||||
|
CONFIG_ENV_IS_NOWHERE=y
|
||||||
|
CONFIG_ENV_IS_IN_EXT4=y
|
||||||
|
CONFIG_ENV_EXT4_INTERFACE="host"
|
||||||
|
CONFIG_ENV_EXT4_DEVICE_AND_PART="0:0"
|
||||||
|
CONFIG_BOOTP_SEND_HOSTNAME=y
|
||||||
|
CONFIG_NETCONSOLE=y
|
||||||
|
CONFIG_IP_DEFRAG=y
|
||||||
|
CONFIG_SPL_DM=y
|
||||||
|
CONFIG_DM_DMA=y
|
||||||
|
CONFIG_REGMAP=y
|
||||||
|
CONFIG_SPL_REGMAP=y
|
||||||
|
CONFIG_SYSCON=y
|
||||||
|
CONFIG_SPL_SYSCON=y
|
||||||
|
CONFIG_DEVRES=y
|
||||||
|
CONFIG_DEBUG_DEVRES=y
|
||||||
|
# CONFIG_SPL_SIMPLE_BUS is not set
|
||||||
|
CONFIG_ADC=y
|
||||||
|
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
|
||||||
|
CONFIG_DM_DEMO_SHAPE=y
|
||||||
|
CONFIG_SPL_FIRMWARE=y
|
||||||
|
CONFIG_GPIO_HOG=y
|
||||||
|
CONFIG_PM8916_GPIO=y
|
||||||
|
CONFIG_SANDBOX_GPIO=y
|
||||||
|
CONFIG_I2C_CROS_EC_TUNNEL=y
|
||||||
|
CONFIG_I2C_CROS_EC_LDO=y
|
||||||
|
CONFIG_DM_I2C_GPIO=y
|
||||||
|
CONFIG_SYS_I2C_SANDBOX=y
|
||||||
|
CONFIG_I2C_MUX=y
|
||||||
|
CONFIG_I2C_ARB_GPIO_CHALLENGE=y
|
||||||
|
CONFIG_CROS_EC_KEYB=y
|
||||||
|
CONFIG_I8042_KEYB=y
|
||||||
|
CONFIG_LED=y
|
||||||
|
CONFIG_LED_BLINK=y
|
||||||
|
CONFIG_LED_GPIO=y
|
||||||
|
CONFIG_DM_MAILBOX=y
|
||||||
|
CONFIG_SANDBOX_MBOX=y
|
||||||
|
CONFIG_MISC=y
|
||||||
|
CONFIG_CROS_EC=y
|
||||||
|
CONFIG_CROS_EC_I2C=y
|
||||||
|
CONFIG_CROS_EC_LPC=y
|
||||||
|
CONFIG_CROS_EC_SANDBOX=y
|
||||||
|
CONFIG_CROS_EC_SPI=y
|
||||||
|
CONFIG_IRQ=y
|
||||||
|
CONFIG_P2SB=y
|
||||||
|
CONFIG_PWRSEQ=y
|
||||||
|
CONFIG_SPL_PWRSEQ=y
|
||||||
|
CONFIG_MMC_SANDBOX=y
|
||||||
|
CONFIG_SPI_FLASH_SANDBOX=y
|
||||||
|
CONFIG_SPI_FLASH_ATMEL=y
|
||||||
|
CONFIG_SPI_FLASH_EON=y
|
||||||
|
CONFIG_SPI_FLASH_GIGADEVICE=y
|
||||||
|
CONFIG_SPI_FLASH_MACRONIX=y
|
||||||
|
CONFIG_SPI_FLASH_SPANSION=y
|
||||||
|
CONFIG_SPI_FLASH_STMICRO=y
|
||||||
|
CONFIG_SPI_FLASH_SST=y
|
||||||
|
CONFIG_SPI_FLASH_WINBOND=y
|
||||||
|
CONFIG_DM_ETH=y
|
||||||
|
CONFIG_NVME=y
|
||||||
|
CONFIG_PCI=y
|
||||||
|
CONFIG_DM_PCI=y
|
||||||
|
CONFIG_DM_PCI_COMPAT=y
|
||||||
|
CONFIG_PCI_SANDBOX=y
|
||||||
|
CONFIG_PHY=y
|
||||||
|
CONFIG_PHY_SANDBOX=y
|
||||||
|
CONFIG_PINCTRL=y
|
||||||
|
CONFIG_PINCONF=y
|
||||||
|
CONFIG_PINCTRL_SANDBOX=y
|
||||||
|
CONFIG_DM_PMIC=y
|
||||||
|
CONFIG_PMIC_ACT8846=y
|
||||||
|
CONFIG_DM_PMIC_PFUZE100=y
|
||||||
|
CONFIG_DM_PMIC_MAX77686=y
|
||||||
|
CONFIG_DM_PMIC_MC34708=y
|
||||||
|
CONFIG_PMIC_PM8916=y
|
||||||
|
CONFIG_PMIC_RK8XX=y
|
||||||
|
CONFIG_PMIC_S2MPS11=y
|
||||||
|
CONFIG_DM_PMIC_SANDBOX=y
|
||||||
|
CONFIG_PMIC_S5M8767=y
|
||||||
|
CONFIG_PMIC_TPS65090=y
|
||||||
|
CONFIG_DM_REGULATOR=y
|
||||||
|
CONFIG_REGULATOR_ACT8846=y
|
||||||
|
CONFIG_DM_REGULATOR_PFUZE100=y
|
||||||
|
CONFIG_DM_REGULATOR_MAX77686=y
|
||||||
|
CONFIG_DM_REGULATOR_FIXED=y
|
||||||
|
CONFIG_REGULATOR_RK8XX=y
|
||||||
|
CONFIG_REGULATOR_S5M8767=y
|
||||||
|
CONFIG_DM_REGULATOR_SANDBOX=y
|
||||||
|
CONFIG_REGULATOR_TPS65090=y
|
||||||
|
CONFIG_DM_PWM=y
|
||||||
|
CONFIG_PWM_SANDBOX=y
|
||||||
|
CONFIG_RAM=y
|
||||||
|
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
|
||||||
|
CONFIG_SOC_DEVICE=y
|
||||||
|
CONFIG_SANDBOX_SPI=y
|
||||||
|
CONFIG_SPMI=y
|
||||||
|
CONFIG_SPMI_SANDBOX=y
|
||||||
|
CONFIG_SYSINFO=y
|
||||||
|
CONFIG_SYSINFO_SANDBOX=y
|
||||||
|
CONFIG_SYSRESET=y
|
||||||
|
CONFIG_SPL_SYSRESET=y
|
||||||
|
CONFIG_TIMER=y
|
||||||
|
CONFIG_TIMER_EARLY=y
|
||||||
|
CONFIG_SANDBOX_TIMER=y
|
||||||
|
CONFIG_USB=y
|
||||||
|
CONFIG_DM_USB=y
|
||||||
|
CONFIG_USB_EMUL=y
|
||||||
|
CONFIG_USB_KEYBOARD=y
|
||||||
|
CONFIG_DM_VIDEO=y
|
||||||
|
CONFIG_CONSOLE_ROTATION=y
|
||||||
|
CONFIG_CONSOLE_TRUETYPE=y
|
||||||
|
CONFIG_CONSOLE_TRUETYPE_CANTORAONE=y
|
||||||
|
CONFIG_VIDEO_SANDBOX_SDL=y
|
||||||
|
CONFIG_OSD=y
|
||||||
|
CONFIG_SANDBOX_OSD=y
|
||||||
|
CONFIG_SPLASH_SCREEN_ALIGN=y
|
||||||
|
CONFIG_VIDEO_BMP_RLE8=y
|
||||||
|
CONFIG_FS_CBFS=y
|
||||||
|
CONFIG_FS_CRAMFS=y
|
||||||
|
# CONFIG_SPL_USE_TINY_PRINTF is not set
|
||||||
|
CONFIG_CMD_DHRYSTONE=y
|
||||||
|
CONFIG_RSA_VERIFY_WITH_PKEY=y
|
||||||
|
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
|
|
@ -7,6 +7,7 @@ CONFIG_SYS_MEMTEST_END=0x00101000
|
||||||
CONFIG_ENV_SIZE=0x2000
|
CONFIG_ENV_SIZE=0x2000
|
||||||
CONFIG_SPL_SERIAL_SUPPORT=y
|
CONFIG_SPL_SERIAL_SUPPORT=y
|
||||||
CONFIG_SPL_DRIVERS_MISC_SUPPORT=y
|
CONFIG_SPL_DRIVERS_MISC_SUPPORT=y
|
||||||
|
CONFIG_SPL_SYS_MALLOC_F_LEN=0x8000
|
||||||
CONFIG_SPL=y
|
CONFIG_SPL=y
|
||||||
CONFIG_BOOTSTAGE_STASH_ADDR=0x0
|
CONFIG_BOOTSTAGE_STASH_ADDR=0x0
|
||||||
CONFIG_DEFAULT_DEVICE_TREE="sandbox"
|
CONFIG_DEFAULT_DEVICE_TREE="sandbox"
|
||||||
|
@ -87,6 +88,7 @@ CONFIG_OF_CONTROL=y
|
||||||
CONFIG_SPL_OF_CONTROL=y
|
CONFIG_SPL_OF_CONTROL=y
|
||||||
CONFIG_OF_HOSTFILE=y
|
CONFIG_OF_HOSTFILE=y
|
||||||
CONFIG_SPL_OF_PLATDATA=y
|
CONFIG_SPL_OF_PLATDATA=y
|
||||||
|
CONFIG_SPL_OF_PLATDATA_INST=y
|
||||||
CONFIG_ENV_IS_NOWHERE=y
|
CONFIG_ENV_IS_NOWHERE=y
|
||||||
CONFIG_ENV_IS_IN_EXT4=y
|
CONFIG_ENV_IS_IN_EXT4=y
|
||||||
CONFIG_ENV_EXT4_INTERFACE="host"
|
CONFIG_ENV_EXT4_INTERFACE="host"
|
||||||
|
@ -102,6 +104,7 @@ CONFIG_SYSCON=y
|
||||||
CONFIG_SPL_SYSCON=y
|
CONFIG_SPL_SYSCON=y
|
||||||
CONFIG_DEVRES=y
|
CONFIG_DEVRES=y
|
||||||
CONFIG_DEBUG_DEVRES=y
|
CONFIG_DEBUG_DEVRES=y
|
||||||
|
# CONFIG_SPL_SIMPLE_BUS is not set
|
||||||
CONFIG_ADC=y
|
CONFIG_ADC=y
|
||||||
CONFIG_ADC_SANDBOX=y
|
CONFIG_ADC_SANDBOX=y
|
||||||
CONFIG_AXI=y
|
CONFIG_AXI=y
|
||||||
|
|
|
@ -709,8 +709,8 @@ to load a 'u-boot-payload.efi', see below test logs on QEMU.
|
||||||
No controllers found
|
No controllers found
|
||||||
Hit any key to stop autoboot: 0
|
Hit any key to stop autoboot: 0
|
||||||
|
|
||||||
See :doc:`../uefi/u-boot_on_efi` and :doc:`../uefi/uefi` for details of
|
See :doc:`../develop/uefi/u-boot_on_efi` and :doc:`../develop/uefi/uefi` for
|
||||||
EFI support in U-Boot.
|
details of EFI support in U-Boot.
|
||||||
|
|
||||||
Chain-loading
|
Chain-loading
|
||||||
-------------
|
-------------
|
||||||
|
|
|
@ -3,6 +3,10 @@
|
||||||
Driver Model
|
Driver Model
|
||||||
============
|
============
|
||||||
|
|
||||||
|
The following holds information on the U-Boot device driver framework:
|
||||||
|
driver-model, including the design details of itself and several driver
|
||||||
|
subsystems
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 2
|
:maxdepth: 2
|
||||||
|
|
913
doc/develop/driver-model/of-plat.rst
Normal file
913
doc/develop/driver-model/of-plat.rst
Normal file
|
@ -0,0 +1,913 @@
|
||||||
|
.. SPDX-License-Identifier: GPL-2.0+
|
||||||
|
|
||||||
|
Compiled-in Device Tree / Platform Data
|
||||||
|
=======================================
|
||||||
|
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
------------
|
||||||
|
|
||||||
|
Device tree is the standard configuration method in U-Boot. It is used to
|
||||||
|
define what devices are in the system and provide configuration information
|
||||||
|
to these devices.
|
||||||
|
|
||||||
|
The overhead of adding devicetree access to U-Boot is fairly modest,
|
||||||
|
approximately 3KB on Thumb 2 (plus the size of the DT itself). This means
|
||||||
|
that in most cases it is best to use devicetree for configuration.
|
||||||
|
|
||||||
|
However there are some very constrained environments where U-Boot needs to
|
||||||
|
work. These include SPL with severe memory limitations. For example, some
|
||||||
|
SoCs require a 16KB SPL image which must include a full MMC stack. In this
|
||||||
|
case the overhead of devicetree access may be too great.
|
||||||
|
|
||||||
|
It is possible to create platform data manually by defining C structures
|
||||||
|
for it, and reference that data in a `U_BOOT_DRVINFO()` declaration. This
|
||||||
|
bypasses the use of devicetree completely, effectively creating a parallel
|
||||||
|
configuration mechanism. But it is an available option for SPL.
|
||||||
|
|
||||||
|
As an alternative, the 'of-platdata' feature is provided. This converts the
|
||||||
|
devicetree contents into C code which can be compiled into the SPL binary.
|
||||||
|
This saves the 3KB of code overhead and perhaps a few hundred more bytes due
|
||||||
|
to more efficient storage of the data.
|
||||||
|
|
||||||
|
|
||||||
|
How it works
|
||||||
|
------------
|
||||||
|
|
||||||
|
The feature is enabled by CONFIG OF_PLATDATA. This is only available in
|
||||||
|
SPL/TPL and should be tested with:
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||||
|
|
||||||
|
A tool called 'dtoc' converts a devicetree file either into a set of
|
||||||
|
struct declarations, one for each compatible node, and a set of
|
||||||
|
`U_BOOT_DRVINFO()` declarations along with the actual platform data for each
|
||||||
|
device. As an example, consider this MMC node:
|
||||||
|
|
||||||
|
.. code-block:: none
|
||||||
|
|
||||||
|
sdmmc: dwmmc@ff0c0000 {
|
||||||
|
compatible = "rockchip,rk3288-dw-mshc";
|
||||||
|
clock-freq-min-max = <400000 150000000>;
|
||||||
|
clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>,
|
||||||
|
<&cru SCLK_SDMMC_DRV>, <&cru SCLK_SDMMC_SAMPLE>;
|
||||||
|
clock-names = "biu", "ciu", "ciu_drv", "ciu_sample";
|
||||||
|
fifo-depth = <0x100>;
|
||||||
|
interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
|
reg = <0xff0c0000 0x4000>;
|
||||||
|
bus-width = <4>;
|
||||||
|
cap-mmc-highspeed;
|
||||||
|
cap-sd-highspeed;
|
||||||
|
card-detect-delay = <200>;
|
||||||
|
disable-wp;
|
||||||
|
num-slots = <1>;
|
||||||
|
pinctrl-names = "default";
|
||||||
|
pinctrl-0 = <&sdmmc_clk>, <&sdmmc_cmd>, <&sdmmc_cd>, <&sdmmc_bus4>;
|
||||||
|
vmmc-supply = <&vcc_sd>;
|
||||||
|
status = "okay";
|
||||||
|
u-boot,dm-pre-reloc;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Some of these properties are dropped by U-Boot under control of the
|
||||||
|
CONFIG_OF_SPL_REMOVE_PROPS option. The rest are processed. This will produce
|
||||||
|
the following C struct declaration:
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
struct dtd_rockchip_rk3288_dw_mshc {
|
||||||
|
fdt32_t bus_width;
|
||||||
|
bool cap_mmc_highspeed;
|
||||||
|
bool cap_sd_highspeed;
|
||||||
|
fdt32_t card_detect_delay;
|
||||||
|
fdt32_t clock_freq_min_max[2];
|
||||||
|
struct phandle_1_arg clocks[4];
|
||||||
|
bool disable_wp;
|
||||||
|
fdt32_t fifo_depth;
|
||||||
|
fdt32_t interrupts[3];
|
||||||
|
fdt32_t num_slots;
|
||||||
|
fdt32_t reg[2];
|
||||||
|
fdt32_t vmmc_supply;
|
||||||
|
};
|
||||||
|
|
||||||
|
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,
|
||||||
|
.interrupts = {0x0, 0x20, 0x4},
|
||||||
|
.clock_freq_min_max = {0x61a80, 0x8f0d180},
|
||||||
|
.vmmc_supply = 0xb,
|
||||||
|
.num_slots = 0x1,
|
||||||
|
.clocks = {{0, 456},
|
||||||
|
{0, 68},
|
||||||
|
{0, 114},
|
||||||
|
{0, 118}},
|
||||||
|
.cap_mmc_highspeed = true,
|
||||||
|
.disable_wp = true,
|
||||||
|
.bus_width = 0x4,
|
||||||
|
.u_boot_dm_pre_reloc = true,
|
||||||
|
.reg = {0xff0c0000, 0x4000},
|
||||||
|
.card_detect_delay = 0xc8,
|
||||||
|
};
|
||||||
|
|
||||||
|
U_BOOT_DRVINFO(dwmmc_at_ff0c0000) = {
|
||||||
|
.name = "rockchip_rk3288_dw_mshc",
|
||||||
|
.plat = &dtv_dwmmc_at_ff0c0000,
|
||||||
|
.plat_size = sizeof(dtv_dwmmc_at_ff0c0000),
|
||||||
|
.parent_idx = -1,
|
||||||
|
};
|
||||||
|
|
||||||
|
The device is then instantiated at run-time and the platform data can be
|
||||||
|
accessed using:
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
struct udevice *dev;
|
||||||
|
struct dtd_rockchip_rk3288_dw_mshc *plat = dev_get_plat(dev);
|
||||||
|
|
||||||
|
This avoids the code overhead of converting the devicetree data to
|
||||||
|
platform data in the driver. The `of_to_plat()` method should
|
||||||
|
therefore do nothing in such a driver.
|
||||||
|
|
||||||
|
Note that for the platform data to be matched with a driver, the 'name'
|
||||||
|
property of the `U_BOOT_DRVINFO()` declaration has to match a driver declared
|
||||||
|
via `U_BOOT_DRIVER()`. This effectively means that a `U_BOOT_DRIVER()` with a
|
||||||
|
'name' corresponding to the devicetree 'compatible' string (after converting
|
||||||
|
it to a valid name for C) is needed, so a dedicated driver is required for
|
||||||
|
each 'compatible' string.
|
||||||
|
|
||||||
|
In order to make this a bit more flexible, the `DM_DRIVER_ALIAS()` macro can be
|
||||||
|
used to declare an alias for a driver name, typically a 'compatible' string.
|
||||||
|
This macro produces no code, but is used by dtoc tool. It must be located in the
|
||||||
|
same file as its associated driver, ideally just after it.
|
||||||
|
|
||||||
|
The parent_idx is the index of the parent `driver_info` structure within its
|
||||||
|
linker list (instantiated by the `U_BOOT_DRVINFO()` macro). This is used to
|
||||||
|
support `dev_get_parent()`.
|
||||||
|
|
||||||
|
During the build process dtoc parses both `U_BOOT_DRIVER()` and
|
||||||
|
`DM_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 checked against the list of driver aliases in order to get the
|
||||||
|
right driver name to use. If in this step there is no match found a warning is
|
||||||
|
issued to avoid run-time failures.
|
||||||
|
|
||||||
|
Where a node has multiple compatible strings, dtoc generates a `#define` to
|
||||||
|
make them equivalent, e.g.:
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
#define dtd_rockchip_rk3299_dw_mshc dtd_rockchip_rk3288_dw_mshc
|
||||||
|
|
||||||
|
|
||||||
|
Converting of-platdata to a useful form
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
Of course it would be possible to use the of-platdata directly in your driver
|
||||||
|
whenever configuration information is required. However this means that the
|
||||||
|
driver will not be able to support devicetree, since the of-platdata
|
||||||
|
structure is not available when devicetree is used. It would make no sense
|
||||||
|
to use this structure if devicetree were available, since the structure has
|
||||||
|
all the limitations metioned in caveats below.
|
||||||
|
|
||||||
|
Therefore it is recommended that the of-platdata structure should be used
|
||||||
|
only in the `probe()` method of your driver. It cannot be used in the
|
||||||
|
`of_to_plat()` method since this is not called when platform data is
|
||||||
|
already present.
|
||||||
|
|
||||||
|
|
||||||
|
How to structure your driver
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
Drivers should always support devicetree as an option. The of-platdata
|
||||||
|
feature is intended as a add-on to existing drivers.
|
||||||
|
|
||||||
|
Your driver should convert the plat struct in its `probe()` method. The
|
||||||
|
existing devicetree decoding logic should be kept in the
|
||||||
|
`of_to_plat()` method and wrapped with `#if`.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
#include <dt-structs.h>
|
||||||
|
|
||||||
|
struct mmc_plat {
|
||||||
|
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||||
|
/* Put this first since driver model will copy the data here */
|
||||||
|
struct dtd_mmc dtplat;
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
* Other fields can go here, to be filled in by decoding from
|
||||||
|
* the devicetree (or the C structures when of-platdata is used).
|
||||||
|
*/
|
||||||
|
int fifo_depth;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int mmc_of_to_plat(struct udevice *dev)
|
||||||
|
{
|
||||||
|
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||||
|
/* Decode the devicetree data */
|
||||||
|
struct mmc_plat *plat = dev_get_plat(dev);
|
||||||
|
const void *blob = gd->fdt_blob;
|
||||||
|
int node = dev_of_offset(dev);
|
||||||
|
|
||||||
|
plat->fifo_depth = fdtdec_get_int(blob, node, "fifo-depth", 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mmc_probe(struct udevice *dev)
|
||||||
|
{
|
||||||
|
struct mmc_plat *plat = dev_get_plat(dev);
|
||||||
|
|
||||||
|
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||||
|
/* Decode the of-platdata from the C structures */
|
||||||
|
struct dtd_mmc *dtplat = &plat->dtplat;
|
||||||
|
|
||||||
|
plat->fifo_depth = dtplat->fifo_depth;
|
||||||
|
#endif
|
||||||
|
/* Set up the device from the plat data */
|
||||||
|
writel(plat->fifo_depth, ...)
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct udevice_id mmc_ids[] = {
|
||||||
|
{ .compatible = "vendor,mmc" },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
U_BOOT_DRIVER(mmc_drv) = {
|
||||||
|
.name = "mmc_drv",
|
||||||
|
.id = UCLASS_MMC,
|
||||||
|
.of_match = mmc_ids,
|
||||||
|
.of_to_plat = mmc_of_to_plat,
|
||||||
|
.probe = mmc_probe,
|
||||||
|
.priv_auto = sizeof(struct mmc_priv),
|
||||||
|
.plat_auto = sizeof(struct mmc_plat),
|
||||||
|
};
|
||||||
|
|
||||||
|
DM_DRIVER_ALIAS(mmc_drv, vendor_mmc) /* matches compatible string */
|
||||||
|
|
||||||
|
Note that `struct mmc_plat` is defined in the C file, not in a header. This
|
||||||
|
is to avoid needing to include dt-structs.h in a header file. The idea is to
|
||||||
|
keep the use of each of-platdata struct to the smallest possible code area.
|
||||||
|
There is just one driver C file for each struct, that can convert from the
|
||||||
|
of-platdata struct to the standard one used by the driver.
|
||||||
|
|
||||||
|
In the case where SPL_OF_PLATDATA is enabled, `plat_auto` is
|
||||||
|
still used to allocate space for the platform data. This is different from
|
||||||
|
the normal behaviour and is triggered by the use of of-platdata (strictly
|
||||||
|
speaking it is a non-zero `plat_size` which triggers this).
|
||||||
|
|
||||||
|
The of-platdata struct contents is copied from the C structure data to the
|
||||||
|
start of the newly allocated area. In the case where devicetree is used,
|
||||||
|
the platform data is allocated, and starts zeroed. In this case the
|
||||||
|
`of_to_plat()` method should still set up the platform data (and the
|
||||||
|
of-platdata struct will not be present).
|
||||||
|
|
||||||
|
SPL must use either of-platdata or devicetree. Drivers cannot use both at
|
||||||
|
the same time, but they must support devicetree. Supporting of-platdata is
|
||||||
|
optional.
|
||||||
|
|
||||||
|
The devicetree becomes inaccessible when CONFIG_SPL_OF_PLATDATA is enabled,
|
||||||
|
since the devicetree access code is not compiled in. A corollary is that
|
||||||
|
a board can only move to using of-platdata if all the drivers it uses support
|
||||||
|
it. There would be little point in having some drivers require the device
|
||||||
|
tree data, since then libfdt would still be needed for those drivers and
|
||||||
|
there would be no code-size benefit.
|
||||||
|
|
||||||
|
|
||||||
|
Build-time instantiation
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
Even with of-platdata there is a fair amount of code required in driver model.
|
||||||
|
It is possible to have U-Boot handle the instantiation of devices at build-time,
|
||||||
|
so avoiding the need for the `device_bind()` code and some parts of
|
||||||
|
`device_probe()`.
|
||||||
|
|
||||||
|
The feature is enabled by CONFIG_OF_PLATDATA_INST.
|
||||||
|
|
||||||
|
Here is an example device, as generated by dtoc::
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Node /serial index 6
|
||||||
|
* driver sandbox_serial parent root_driver
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <asm/serial.h>
|
||||||
|
struct sandbox_serial_plat __attribute__ ((section (".priv_data")))
|
||||||
|
_sandbox_serial_plat_serial = {
|
||||||
|
.dtplat = {
|
||||||
|
.sandbox_text_colour = "cyan",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
#include <asm/serial.h>
|
||||||
|
u8 _sandbox_serial_priv_serial[sizeof(struct sandbox_serial_priv)]
|
||||||
|
__attribute__ ((section (".priv_data")));
|
||||||
|
#include <serial.h>
|
||||||
|
u8 _sandbox_serial_uc_priv_serial[sizeof(struct serial_dev_priv)]
|
||||||
|
__attribute__ ((section (".priv_data")));
|
||||||
|
|
||||||
|
DM_DEVICE_INST(serial) = {
|
||||||
|
.driver = DM_DRIVER_REF(sandbox_serial),
|
||||||
|
.name = "sandbox_serial",
|
||||||
|
.plat_ = &_sandbox_serial_plat_serial,
|
||||||
|
.priv_ = _sandbox_serial_priv_serial,
|
||||||
|
.uclass = DM_UCLASS_REF(serial),
|
||||||
|
.uclass_priv_ = _sandbox_serial_uc_priv_serial,
|
||||||
|
.uclass_node = {
|
||||||
|
.prev = &DM_UCLASS_REF(serial)->dev_head,
|
||||||
|
.next = &DM_UCLASS_REF(serial)->dev_head,
|
||||||
|
},
|
||||||
|
.child_head = {
|
||||||
|
.prev = &DM_DEVICE_REF(serial)->child_head,
|
||||||
|
.next = &DM_DEVICE_REF(serial)->child_head,
|
||||||
|
},
|
||||||
|
.sibling_node = {
|
||||||
|
.prev = &DM_DEVICE_REF(i2c_at_0)->sibling_node,
|
||||||
|
.next = &DM_DEVICE_REF(spl_test)->sibling_node,
|
||||||
|
},
|
||||||
|
.seq_ = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
Here is part of the driver, for reference::
|
||||||
|
|
||||||
|
static const struct udevice_id sandbox_serial_ids[] = {
|
||||||
|
{ .compatible = "sandbox,serial" },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
U_BOOT_DRIVER(sandbox_serial) = {
|
||||||
|
.name = "sandbox_serial",
|
||||||
|
.id = UCLASS_SERIAL,
|
||||||
|
.of_match = sandbox_serial_ids,
|
||||||
|
.of_to_plat = sandbox_serial_of_to_plat,
|
||||||
|
.plat_auto = sizeof(struct sandbox_serial_plat),
|
||||||
|
.priv_auto = sizeof(struct sandbox_serial_priv),
|
||||||
|
.probe = sandbox_serial_probe,
|
||||||
|
.remove = sandbox_serial_remove,
|
||||||
|
.ops = &sandbox_serial_ops,
|
||||||
|
.flags = DM_FLAG_PRE_RELOC,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
The `DM_DEVICE_INST()` macro declares a struct udevice so you can see that the
|
||||||
|
members are from that struct. The private data is declared immediately above,
|
||||||
|
as `_sandbox_serial_priv_serial`, so there is no need for run-time memory
|
||||||
|
allocation. The #include lines are generated as well, since dtoc searches the
|
||||||
|
U-Boot source code for the definition of `struct sandbox_serial_priv` and adds
|
||||||
|
the relevant header so that the code will compile without errors.
|
||||||
|
|
||||||
|
The `plat_` member is set to the dtv data which is declared immediately above
|
||||||
|
the device. This is similar to how it would look without of-platdata-inst, but
|
||||||
|
node that the `dtplat` member inside is part of the wider
|
||||||
|
`_sandbox_serial_plat_serial` struct. This is because the driver declares its
|
||||||
|
own platform data, and the part generated by dtoc can only be a portion of it.
|
||||||
|
The `dtplat` part is always first in the struct. If the device has no
|
||||||
|
`.plat_auto` field, then a simple dtv struct can be used as with this example::
|
||||||
|
|
||||||
|
static struct dtd_sandbox_clk dtv_clk_sbox = {
|
||||||
|
.assigned_clock_rates = 0x141,
|
||||||
|
.assigned_clocks = {0x7, 0x3},
|
||||||
|
};
|
||||||
|
|
||||||
|
#include <asm/clk.h>
|
||||||
|
u8 _sandbox_clk_priv_clk_sbox[sizeof(struct sandbox_clk_priv)]
|
||||||
|
__attribute__ ((section (".priv_data")));
|
||||||
|
|
||||||
|
DM_DEVICE_INST(clk_sbox) = {
|
||||||
|
.driver = DM_DRIVER_REF(sandbox_clk),
|
||||||
|
.name = "sandbox_clk",
|
||||||
|
.plat_ = &dtv_clk_sbox,
|
||||||
|
|
||||||
|
Here is part of the driver, for reference::
|
||||||
|
|
||||||
|
static const struct udevice_id sandbox_clk_ids[] = {
|
||||||
|
{ .compatible = "sandbox,clk" },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
U_BOOT_DRIVER(sandbox_clk) = {
|
||||||
|
.name = "sandbox_clk",
|
||||||
|
.id = UCLASS_CLK,
|
||||||
|
.of_match = sandbox_clk_ids,
|
||||||
|
.ops = &sandbox_clk_ops,
|
||||||
|
.probe = sandbox_clk_probe,
|
||||||
|
.priv_auto = sizeof(struct sandbox_clk_priv),
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
You can see that `dtv_clk_sbox` just has the devicetree contents and there is
|
||||||
|
no need for the `dtplat` separation, since the driver has no platform data of
|
||||||
|
its own, besides that provided by the devicetree (i.e. no `.plat_auto` field).
|
||||||
|
|
||||||
|
The doubly linked lists are handled by explicitly declaring the value of each
|
||||||
|
node, as you can see with the `.prev` and `.next` values in the example above.
|
||||||
|
Since dtoc knows the order of devices it can link them into the appropriate
|
||||||
|
lists correctly.
|
||||||
|
|
||||||
|
One of the features of driver model is the ability for a uclass to have a
|
||||||
|
small amount of private data for each device in that uclass. This is used to
|
||||||
|
provide a generic data structure that the uclass can use for all devices, thus
|
||||||
|
allowing generic features to be implemented in common code. An example is I2C,
|
||||||
|
which stores the bus speed there.
|
||||||
|
|
||||||
|
Similarly, parent devices can have data associated with each of their children.
|
||||||
|
This is used to provide information common to all children of a particular bus.
|
||||||
|
For an I2C bus, this is used to store the I2C address of each child on the bus.
|
||||||
|
|
||||||
|
This is all handled automatically by dtoc::
|
||||||
|
|
||||||
|
#include <asm/i2c.h>
|
||||||
|
u8 _sandbox_i2c_priv_i2c_at_0[sizeof(struct sandbox_i2c_priv)]
|
||||||
|
__attribute__ ((section (".priv_data")));
|
||||||
|
#include <i2c.h>
|
||||||
|
u8 _sandbox_i2c_uc_priv_i2c_at_0[sizeof(struct dm_i2c_bus)]
|
||||||
|
__attribute__ ((section (".priv_data")));
|
||||||
|
|
||||||
|
DM_DEVICE_INST(i2c_at_0) = {
|
||||||
|
.driver = DM_DRIVER_REF(sandbox_i2c),
|
||||||
|
.name = "sandbox_i2c",
|
||||||
|
.plat_ = &dtv_i2c_at_0,
|
||||||
|
.priv_ = _sandbox_i2c_priv_i2c_at_0,
|
||||||
|
.uclass = DM_UCLASS_REF(i2c),
|
||||||
|
.uclass_priv_ = _sandbox_i2c_uc_priv_i2c_at_0,
|
||||||
|
...
|
||||||
|
|
||||||
|
Part of driver, for reference::
|
||||||
|
|
||||||
|
static const struct udevice_id sandbox_i2c_ids[] = {
|
||||||
|
{ .compatible = "sandbox,i2c" },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
U_BOOT_DRIVER(sandbox_i2c) = {
|
||||||
|
.name = "sandbox_i2c",
|
||||||
|
.id = UCLASS_I2C,
|
||||||
|
.of_match = sandbox_i2c_ids,
|
||||||
|
.ops = &sandbox_i2c_ops,
|
||||||
|
.priv_auto = sizeof(struct sandbox_i2c_priv),
|
||||||
|
};
|
||||||
|
|
||||||
|
Part of I2C uclass, for reference::
|
||||||
|
|
||||||
|
UCLASS_DRIVER(i2c) = {
|
||||||
|
.id = UCLASS_I2C,
|
||||||
|
.name = "i2c",
|
||||||
|
.flags = DM_UC_FLAG_SEQ_ALIAS,
|
||||||
|
.post_bind = i2c_post_bind,
|
||||||
|
.pre_probe = i2c_pre_probe,
|
||||||
|
.post_probe = i2c_post_probe,
|
||||||
|
.per_device_auto = sizeof(struct dm_i2c_bus),
|
||||||
|
.per_child_plat_auto = sizeof(struct dm_i2c_chip),
|
||||||
|
.child_post_bind = i2c_child_post_bind,
|
||||||
|
};
|
||||||
|
|
||||||
|
Here, `_sandbox_i2c_uc_priv_i2c_at_0` is required by the uclass but is declared
|
||||||
|
in the device, as required by driver model. The required header file is included
|
||||||
|
so that the code will compile without errors. A similar mechanism is used for
|
||||||
|
child devices, but is not shown by this example.
|
||||||
|
|
||||||
|
It would not be that useful to avoid binding devices but still need to allocate
|
||||||
|
uclasses at runtime. So dtoc generates uclass instances as well::
|
||||||
|
|
||||||
|
struct list_head uclass_head = {
|
||||||
|
.prev = &DM_UCLASS_REF(serial)->sibling_node,
|
||||||
|
.next = &DM_UCLASS_REF(clk)->sibling_node,
|
||||||
|
};
|
||||||
|
|
||||||
|
DM_UCLASS_INST(clk) = {
|
||||||
|
.uc_drv = DM_UCLASS_DRIVER_REF(clk),
|
||||||
|
.sibling_node = {
|
||||||
|
.prev = &uclass_head,
|
||||||
|
.next = &DM_UCLASS_REF(i2c)->sibling_node,
|
||||||
|
},
|
||||||
|
.dev_head = {
|
||||||
|
.prev = &DM_DEVICE_REF(clk_sbox)->uclass_node,
|
||||||
|
.next = &DM_DEVICE_REF(clk_fixed)->uclass_node,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
At the top is the list head. Driver model uses this on start-up, instead of
|
||||||
|
creating its own.
|
||||||
|
|
||||||
|
Below that are a set of `DM_UCLASS_INST()` macros, each declaring a
|
||||||
|
`struct uclass`. The doubly linked lists work as for devices.
|
||||||
|
|
||||||
|
All private data is placed into a `.priv_data` section so that it is contiguous
|
||||||
|
in the resulting output binary.
|
||||||
|
|
||||||
|
|
||||||
|
Indexes
|
||||||
|
-------
|
||||||
|
|
||||||
|
U-Boot stores drivers, devices and many other things in linker_list structures.
|
||||||
|
These are sorted by name, so dtoc knows the order that they will appear when
|
||||||
|
the linker runs. Each driver_info / udevice is referenced by its index in the
|
||||||
|
linker_list array, called 'idx' in the code.
|
||||||
|
|
||||||
|
When CONFIG_OF_PLATDATA_INST is enabled, idx is the udevice index, otherwise it
|
||||||
|
is the driver_info index. In either case, indexes are used to reference devices
|
||||||
|
using device_get_by_ofplat_idx(). This allows phandles to work as expected.
|
||||||
|
|
||||||
|
|
||||||
|
Phases
|
||||||
|
------
|
||||||
|
|
||||||
|
U-Boot operates in several phases, typically TPL, SPL and U-Boot proper.
|
||||||
|
The latter does not use dtoc.
|
||||||
|
|
||||||
|
In some rare cases different drivers are used for two phases. For example,
|
||||||
|
in TPL it may not be necessary to use the full PCI subsystem, so a simple
|
||||||
|
driver can be used instead.
|
||||||
|
|
||||||
|
This works in the build system simply by compiling in one driver or the
|
||||||
|
other (e.g. PCI driver + uclass for SPL; simple_bus for TPL). But dtoc has
|
||||||
|
no way of knowing which code is compiled in for which phase, since it does
|
||||||
|
not inspect Makefiles or dependency graphs.
|
||||||
|
|
||||||
|
So to make this work for dtoc, we need to be able to explicitly mark
|
||||||
|
drivers with their phase. This is done by adding a macro to the driver::
|
||||||
|
|
||||||
|
/* code in tpl.c only compiled into TPL */
|
||||||
|
U_BOOT_DRIVER(pci_x86) = {
|
||||||
|
.name = "pci_x86",
|
||||||
|
.id = UCLASS_SIMPLE_BUS,
|
||||||
|
.of_match = of_match_ptr(tpl_fake_pci_ids),
|
||||||
|
DM_PHASE(tpl)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* code in pci_x86.c compiled into SPL and U-Boot proper */
|
||||||
|
U_BOOT_DRIVER(pci_x86) = {
|
||||||
|
.name = "pci_x86",
|
||||||
|
.id = UCLASS_PCI,
|
||||||
|
.of_match = pci_x86_ids,
|
||||||
|
.ops = &pci_x86_ops,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Notice that the second driver has the same name but no DM_PHASE(), so it will be
|
||||||
|
used for SPL and U-Boot.
|
||||||
|
|
||||||
|
Note also that this only affects the code generated by dtoc. You still need to
|
||||||
|
make sure that only the required driver is build into each phase.
|
||||||
|
|
||||||
|
|
||||||
|
Header files
|
||||||
|
------------
|
||||||
|
|
||||||
|
With OF_PLATDATA_INST, dtoc must include the correct header file in the
|
||||||
|
generated code for any structs that are used, so that the code will compile.
|
||||||
|
For example, if `struct ns16550_plat` is used, the code must include the
|
||||||
|
`ns16550.h` header file.
|
||||||
|
|
||||||
|
Typically dtoc can detect the header file needed for a driver by looking
|
||||||
|
for the structs that it uses. For example, if a driver as a `.priv_auto`
|
||||||
|
that uses `struct ns16550_plat`, then dtoc can search header files for the
|
||||||
|
definition of that struct and use the file.
|
||||||
|
|
||||||
|
In some cases, enums are used in drivers, typically with the `.data` field
|
||||||
|
of `struct udevice_id`. Since dtoc does not support searching for these,
|
||||||
|
you must use the `DM_HDR()` macro to tell dtoc which header to use. This works
|
||||||
|
as a macro included in the driver definition::
|
||||||
|
|
||||||
|
static const struct udevice_id apl_syscon_ids[] = {
|
||||||
|
{ .compatible = "intel,apl-punit", .data = X86_SYSCON_PUNIT },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
U_BOOT_DRIVER(intel_apl_punit) = {
|
||||||
|
.name = "intel_apl_punit",
|
||||||
|
.id = UCLASS_SYSCON,
|
||||||
|
.of_match = apl_syscon_ids,
|
||||||
|
.probe = apl_punit_probe,
|
||||||
|
DM_HEADER(<asm/cpu.h>) /* for X86_SYSCON_PUNIT */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Caveats
|
||||||
|
-------
|
||||||
|
|
||||||
|
There are various complications with this feature which mean it should only
|
||||||
|
be used when strictly necessary, i.e. in SPL with limited memory. Notable
|
||||||
|
caveats include:
|
||||||
|
|
||||||
|
- Device tree does not describe data types. But the C code must define a
|
||||||
|
type for each property. These are guessed using heuristics which
|
||||||
|
are wrong in several fairly common cases. For example an 8-byte value
|
||||||
|
is considered to be a 2-item integer array, and is byte-swapped. A
|
||||||
|
boolean value that is not present means 'false', but cannot be
|
||||||
|
included in the structures since there is generally no mention of it
|
||||||
|
in the devicetree file.
|
||||||
|
|
||||||
|
- Naming of nodes and properties is automatic. This means that they follow
|
||||||
|
the naming in the devicetree, which may result in C identifiers that
|
||||||
|
look a bit strange.
|
||||||
|
|
||||||
|
- It is not possible to find a value given a property name. Code must use
|
||||||
|
the associated C member variable directly in the code. This makes
|
||||||
|
the code less robust in the face of devicetree changes. To avoid having
|
||||||
|
a second struct with similar members and names you need to explicitly
|
||||||
|
declare it as an alias with `DM_DRIVER_ALIAS()`.
|
||||||
|
|
||||||
|
- The platform data is provided to drivers as a C structure. The driver
|
||||||
|
must use the same structure to access the data. Since a driver
|
||||||
|
normally also supports devicetree it must use `#ifdef` to separate
|
||||||
|
out this code, since the structures are only available in SPL. This could
|
||||||
|
be fixed fairly easily by making the structs available outside SPL, so
|
||||||
|
that `IS_ENABLED()` could be used.
|
||||||
|
|
||||||
|
- With CONFIG_OF_PLATDATA_INST all binding happens at build-time, meaning
|
||||||
|
that (by default) it is not possible to call `device_bind()` from C code.
|
||||||
|
This means that all devices must have an associated devicetree node and
|
||||||
|
compatible string. For example if a GPIO device currently creates child
|
||||||
|
devices in its `bind()` method, it will not work with
|
||||||
|
CONFIG_OF_PLATDATA_INST. Arguably this is bad practice anyway and the
|
||||||
|
devicetree binding should be updated to declare compatible strings for
|
||||||
|
the child devices. It is possible to disable OF_PLATDATA_NO_BIND but this
|
||||||
|
is not recommended since it increases code size.
|
||||||
|
|
||||||
|
|
||||||
|
Internals
|
||||||
|
---------
|
||||||
|
|
||||||
|
Generated files
|
||||||
|
```````````````
|
||||||
|
|
||||||
|
When enabled, dtoc generates the following five files:
|
||||||
|
|
||||||
|
include/generated/dt-decl.h (OF_PLATDATA_INST only)
|
||||||
|
Contains declarations for all drivers, devices and uclasses. This allows
|
||||||
|
any `struct udevice`, `struct driver` or `struct uclass` to be located by its
|
||||||
|
name
|
||||||
|
|
||||||
|
include/generated/dt-structs-gen.h
|
||||||
|
Contains the struct definitions for the devicetree nodes that are used. This
|
||||||
|
is the same as without OF_PLATDATA_INST
|
||||||
|
|
||||||
|
spl/dts/dt-plat.c (only with !OF_PLATDATA_INST)
|
||||||
|
Contains the `U_BOOT_DRVINFO()` declarations that U-Boot uses to bind devices
|
||||||
|
at start-up. See above for an example
|
||||||
|
|
||||||
|
spl/dts/dt-device.c (only with OF_PLATDATA_INST)
|
||||||
|
Contains `DM_DEVICE_INST()` declarations for each device that can be used at
|
||||||
|
run-time. These are declared in the file along with any private/platform data
|
||||||
|
that they use. Every device has an idx, as above. Since each device must be
|
||||||
|
part of a double-linked list, the nodes are declared in the code as well.
|
||||||
|
|
||||||
|
spl/dts/dt-uclass.c (only with OF_PLATDATA_INST)
|
||||||
|
Contains `DM_UCLASS_INST()` declarations for each uclass that can be used at
|
||||||
|
run-time. These are declared in the file along with any private data
|
||||||
|
associated with the uclass itself (the `.priv_auto` member). Since each
|
||||||
|
uclass must be part of a double-linked list, the nodes are declared in the
|
||||||
|
code as well.
|
||||||
|
|
||||||
|
The dt-structs.h file includes the generated file
|
||||||
|
`(include/generated/dt-structs.h`) if CONFIG_SPL_OF_PLATDATA is enabled.
|
||||||
|
Otherwise (such as in U-Boot proper) these structs are not available. This
|
||||||
|
prevents them being used inadvertently. All usage must be bracketed with
|
||||||
|
`#if CONFIG_IS_ENABLED(OF_PLATDATA)`.
|
||||||
|
|
||||||
|
The dt-plat.c file contains the device declarations and is is built in
|
||||||
|
spl/dt-plat.c.
|
||||||
|
|
||||||
|
|
||||||
|
CONFIG options
|
||||||
|
``````````````
|
||||||
|
|
||||||
|
Several CONFIG options are used to control the behaviour of of-platdata, all
|
||||||
|
available for both SPL and TPL:
|
||||||
|
|
||||||
|
OF_PLATDATA
|
||||||
|
This is the main option which enables the of-platdata feature
|
||||||
|
|
||||||
|
OF_PLATDATA_PARENT
|
||||||
|
This allows `device_get_parent()` to work. Without this, all devices exist as
|
||||||
|
direct children of the root node. This option is highly desirable (if not
|
||||||
|
always absolutely essential) for buses such as I2C.
|
||||||
|
|
||||||
|
OF_PLATDATA_INST
|
||||||
|
This controls the instantiation of devices at build time. With it disabled,
|
||||||
|
only `U_BOOT_DRVINFO()` records are created, with U-Boot handling the binding
|
||||||
|
in `device_bind()` on start-up. With it enabled, only `DM_DEVICE_INST()` and
|
||||||
|
`DM_UCLASS_INST()` records are created, and `device_bind()` is not needed at
|
||||||
|
runtime.
|
||||||
|
|
||||||
|
OF_PLATDATA_NO_BIND
|
||||||
|
This controls whether `device_bind()` is supported. It is enabled by default
|
||||||
|
with OF_PLATDATA_INST since code-size reduction is really the main point of
|
||||||
|
the feature. It can be disabled if needed but is not likely to be supported
|
||||||
|
in the long term.
|
||||||
|
|
||||||
|
OF_PLATDATA_DRIVER_RT
|
||||||
|
This controls whether the `struct driver_rt` records are used by U-Boot.
|
||||||
|
Normally when a device is bound, U-Boot stores the device pointer in one of
|
||||||
|
these records. There is one for every `struct driver_info` in the system,
|
||||||
|
i.e. one for every device that is bound from those records. It provides a
|
||||||
|
way to locate a device in the code and is used by
|
||||||
|
`device_get_by_ofplat_idx()`. This option is always enabled with of-platdata,
|
||||||
|
provided OF_PLATDATA_INST is not. In that case the records are useless since
|
||||||
|
we don't have any `struct driver_info` records.
|
||||||
|
|
||||||
|
OF_PLATDATA_RT
|
||||||
|
This controls whether the `struct udevice_rt` records are used by U-Boot.
|
||||||
|
It moves the updatable fields from `struct udevice` (currently only `flags`)
|
||||||
|
into a separate structure, allowing the records to be kept in read-only
|
||||||
|
memory. It is generally enabled if OF_PLATDATA_INST is enabled. This option
|
||||||
|
also controls whether the private data is used in situ, or first copied into
|
||||||
|
an allocated region. Again this is to allow the private data declared by
|
||||||
|
dtoc-generated code to be in read-only memory. Note that access to private
|
||||||
|
data must be done via accessor functions, such as `dev_get_priv()`, so that
|
||||||
|
the relocation is handled.
|
||||||
|
|
||||||
|
READ_ONLY
|
||||||
|
This indicates that the data generated by dtoc should not be modified. Only
|
||||||
|
a few fields actually do get changed in U-Boot, such as device flags. This
|
||||||
|
option causes those to move into an allocated space (see OF_PLATDATA_RT).
|
||||||
|
Also, since updating doubly linked lists is generally impossible when some of
|
||||||
|
the nodes cannot be updated, OF_PLATDATA_NO_BIND is enabled.
|
||||||
|
|
||||||
|
Data structures
|
||||||
|
```````````````
|
||||||
|
|
||||||
|
A few extra data structures are used with of-platdata:
|
||||||
|
|
||||||
|
`struct udevice_rt`
|
||||||
|
Run-time information for devices. When OF_PLATDATA_RT is enabled, this holds
|
||||||
|
the flags for each device, so that `struct udevice` can remain unchanged by
|
||||||
|
U-Boot, and potentially reside in read-only memory. Access to flags is then
|
||||||
|
via functions like `dev_get_flags()` and `dev_or_flags()`. This data
|
||||||
|
structure is allocated on start-up, where the private data is also copied.
|
||||||
|
All flags values start at 0 and any changes are handled by `dev_or_flags()`
|
||||||
|
and `dev_bic_flags()`. It would be more correct for the flags to be set to
|
||||||
|
`DM_FLAG_BOUND`, or perhaps `DM_FLAG_BOUND | DM_FLAG_ALLOC_PDATA`, but since
|
||||||
|
there is no code to bind/unbind devices and no code to allocate/free
|
||||||
|
private data / platform data, it doesn't matter.
|
||||||
|
|
||||||
|
`struct driver_rt`
|
||||||
|
Run-time information for `struct driver_info` records. When
|
||||||
|
OF_PLATDATA_DRIVER_RT is enabled, this holds a pointer to the device
|
||||||
|
created by each record. This is needed so that is it possible to locate a
|
||||||
|
device from C code. Specifically, the code can use `DM_DRVINFO_GET(name)` to
|
||||||
|
get a reference to a particular `struct driver_info`, with `name` being the
|
||||||
|
name of the devicetree node. This is very convenient. It is also fast, since
|
||||||
|
no searching or string comparison is needed. This data structure is
|
||||||
|
allocated on start-up, filled out by `device_bind()` and used by
|
||||||
|
`device_get_by_ofplat_idx()`.
|
||||||
|
|
||||||
|
Other changes
|
||||||
|
`````````````
|
||||||
|
|
||||||
|
Some other changes are made with of-platdata:
|
||||||
|
|
||||||
|
Accessor functions
|
||||||
|
Accessing private / platform data via functions such as `dev_get_priv()` has
|
||||||
|
always been encouraged. With OF_PLATDATA_RT this is essential, since the
|
||||||
|
`priv_` and `plat_` (etc.) values point to the data generated by dtoc, not
|
||||||
|
the read-write copy that is sometimes made on start-up. Changing the
|
||||||
|
private / platform data pointers has always been discouraged (the API is
|
||||||
|
marked internal) but with OF_PLATDATA_RT this is not currently supported in
|
||||||
|
general, since it assumes that all such pointers point to the relocated data.
|
||||||
|
Note also that the renaming of struct members to have a trailing underscore
|
||||||
|
was partly done to make people aware that they should not be accessed
|
||||||
|
directly.
|
||||||
|
|
||||||
|
`gd->uclass_root_s`
|
||||||
|
Normally U-Boot sets up the head of the uclass list here and makes
|
||||||
|
`gd->uclass_root` point to it. With OF_PLATDATA_INST, dtoc generates a
|
||||||
|
declaration of `uclass_head` in `dt-uclass.c` since it needs to link the
|
||||||
|
head node into the list. In that case, `gd->uclass_root_s` is not used and
|
||||||
|
U-Boot just makes `gd->uclass_root` point to `uclass_head`.
|
||||||
|
|
||||||
|
`gd->dm_driver_rt`
|
||||||
|
This holds a pointer to a list of `struct driver_rt` records, one for each
|
||||||
|
`struct driver_info`. The list is in alphabetical order by the name used
|
||||||
|
in `U_BOOT_DRVINFO(name)` and indexed by idx, with the first record having
|
||||||
|
an index of 0. It is only used if OF_PLATDATA_INST is not enabled. This is
|
||||||
|
accessed via macros so that it can be used inside IS_ENABLED(), rather than
|
||||||
|
requiring #ifdefs in the C code when it is not present.
|
||||||
|
|
||||||
|
`gd->dm_udevice_rt`
|
||||||
|
This holds a pointer to a list of `struct udevice_rt` records, one for each
|
||||||
|
`struct udevice`. The list is in alphabetical order by the name used
|
||||||
|
in `DM_DEVICE_INST(name)` (a C version of the devicetree node) and indexed by
|
||||||
|
idx, with the first record having an index of 0. It is only used if
|
||||||
|
OF_PLATDATA_INST is enabled. This is accessed via macros so that it can be
|
||||||
|
used inside `IS_ENABLED()`, rather than requiring #ifdefs in the C code when
|
||||||
|
it is not present.
|
||||||
|
|
||||||
|
`gd->dm_priv_base`
|
||||||
|
When OF_PLATDATA_RT is enabled, the private/platform data for each device is
|
||||||
|
copied into an allocated region by U-Boot on start-up. This points to that
|
||||||
|
region. All calls to accessor functions (e.g. `dev_get_priv()`) then
|
||||||
|
translate from the pointer provided by the caller (assumed to lie between
|
||||||
|
`__priv_data_start` and `__priv_data_end`) to the new allocated region. This
|
||||||
|
member is accessed via macros so that it can be used inside IS_ENABLED(),
|
||||||
|
rather than required #ifdefs in the C code when it is not present.
|
||||||
|
|
||||||
|
`struct udevice->flags_`
|
||||||
|
When OF_PLATDATA_RT is enabled, device flags are no-longer part of
|
||||||
|
`struct udevice`, but are instead kept in `struct udevice_rt`, as described
|
||||||
|
above. Flags are accessed via functions, such as `dev_get_flags()` and
|
||||||
|
`dev_or_flags()`.
|
||||||
|
|
||||||
|
`struct udevice->node_`
|
||||||
|
When OF_PLATDATA is enabled, there is no devicetree at runtime, so no need
|
||||||
|
for this field. It is removed, just to save space.
|
||||||
|
|
||||||
|
`DM_PHASE`
|
||||||
|
This macro is used to indicate which phase of U-Boot a driver is intended
|
||||||
|
for. See above for details.
|
||||||
|
|
||||||
|
`DM_HDR`
|
||||||
|
This macro is used to indicate which header file dtoc should use to allow
|
||||||
|
a driver declaration to compile correctly. See above for details.
|
||||||
|
|
||||||
|
`device_get_by_ofplat_idx()`
|
||||||
|
There used to be a function called `device_get_by_driver_info()` which
|
||||||
|
looked up a `struct driver_info` pointer and returned the `struct udevice`
|
||||||
|
that was created from it. It was only available for use with of-platdata.
|
||||||
|
This has been removed in favour of `device_get_by_ofplat_idx()` which uses
|
||||||
|
`idx`, the index of the `struct driver_info` or `struct udevice` in the
|
||||||
|
linker_list. Similarly, the `struct phandle_0_arg` (etc.) structs have been
|
||||||
|
updated to use this index instead of a pointer to `struct driver_info`.
|
||||||
|
|
||||||
|
`DM_DRVINFO_GET`
|
||||||
|
This has been removed since we now use indexes to obtain a driver from
|
||||||
|
`struct phandle_0_arg` and the like.
|
||||||
|
|
||||||
|
Two-pass binding
|
||||||
|
The original of-platdata tried to order `U_BOOT_DRVINFO()` in the generated
|
||||||
|
files so as to have parents declared ahead of children. This was convenient
|
||||||
|
as it avoided any special code in U-Boot. With OF_PLATDATA_INST this does
|
||||||
|
not work as the idx value relies on using alphabetical order for everything,
|
||||||
|
so that dtoc and U-Boot's linker_lists agree on the idx value. Devices are
|
||||||
|
then bound in order of idx, having no regard to parent/child relationships.
|
||||||
|
For this reason, device binding now hapens in multiple passes, with parents
|
||||||
|
being bound before their children. This is important so that children can
|
||||||
|
find their parents in the bind() method if needed.
|
||||||
|
|
||||||
|
Root device
|
||||||
|
The root device is generally bound by U-Boot but with OF_PLATDATA_INST it
|
||||||
|
cannot be, since binding needs to be done at build time. So in this case
|
||||||
|
dtoc sets up a root device using `DM_DEVICE_INST()` in `dt-device.c` and
|
||||||
|
U-Boot makes use of that. When OF_PLATDATA_INST is not enabled, U-Boot
|
||||||
|
generally ignores the root node and does not create a `U_BOOT_DRVINFO()`
|
||||||
|
record for it. This means that the idx numbers used by `struct driver_info`
|
||||||
|
(when OF_PLATDATA_INST is disabled) and the idx numbers used by
|
||||||
|
`struct udevice` (when OF_PLATDATA_INST is enabled) differ, since one has a
|
||||||
|
root node and the other does not. This does not actually matter, since only
|
||||||
|
one of them is actually used for any particular build, but it is worth
|
||||||
|
keeping in mind if comparing index values and switching OF_PLATDATA_INST on
|
||||||
|
and off.
|
||||||
|
|
||||||
|
`__priv_data_start` and `__priv_data_end`
|
||||||
|
The private/platform data declared by dtoc is all collected together in
|
||||||
|
a linker section and these symbols mark the start and end of it. This allows
|
||||||
|
U-Boot to relocate the area to a new location if needed (with
|
||||||
|
OF_PLATDATA_RT)
|
||||||
|
|
||||||
|
`dm_priv_to_rw()`
|
||||||
|
This function converts a private- or platform-data pointer value generated by
|
||||||
|
dtoc into one that can be used by U-Boot. It is a NOP unless OF_PLATDATA_RT
|
||||||
|
is enabled, in which case it translates the address to the relocated
|
||||||
|
region. See above for more information.
|
||||||
|
|
||||||
|
The dm_populate_phandle_data() function that was previous needed has now been
|
||||||
|
removed, since dtoc can address the drivers directly from dt-plat.c and does
|
||||||
|
not need to fix up things at runtime.
|
||||||
|
|
||||||
|
The pylibfdt Python module is used to access the devicetree.
|
||||||
|
|
||||||
|
|
||||||
|
Credits
|
||||||
|
-------
|
||||||
|
|
||||||
|
This is an implementation of an idea by Tom Rini <trini@konsulko.com>.
|
||||||
|
|
||||||
|
|
||||||
|
Future work
|
||||||
|
-----------
|
||||||
|
- Consider programmatically reading binding files instead of devicetree
|
||||||
|
contents
|
||||||
|
- Allow IS_ENABLED() to be used in the C code instead of #if
|
||||||
|
|
||||||
|
|
||||||
|
.. Simon Glass <sjg@chromium.org>
|
||||||
|
.. Google, Inc
|
||||||
|
.. 6/6/16
|
||||||
|
.. Updated Independence Day 2016
|
||||||
|
.. Updated 1st October 2020
|
||||||
|
.. Updated 5th February 2021
|
|
@ -125,6 +125,7 @@ emulator driver. For example::
|
||||||
compatible = "sandbox,pci-emul-parent";
|
compatible = "sandbox,pci-emul-parent";
|
||||||
emul_1f: emul@1f,0 {
|
emul_1f: emul@1f,0 {
|
||||||
compatible = "sandbox,swap-case";
|
compatible = "sandbox,swap-case";
|
||||||
|
#emul-cells = <0>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,9 +10,11 @@ Implementation
|
||||||
:maxdepth: 1
|
:maxdepth: 1
|
||||||
|
|
||||||
commands
|
commands
|
||||||
|
driver-model/index
|
||||||
global_data
|
global_data
|
||||||
logging
|
logging
|
||||||
menus
|
menus
|
||||||
|
uefi/index
|
||||||
version
|
version
|
||||||
|
|
||||||
Debugging
|
Debugging
|
||||||
|
@ -24,6 +26,14 @@ Debugging
|
||||||
crash_dumps
|
crash_dumps
|
||||||
trace
|
trace
|
||||||
|
|
||||||
|
Packaging
|
||||||
|
---------
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
|
||||||
|
package/index
|
||||||
|
|
||||||
Testing
|
Testing
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
|
1
doc/develop/package/binman.rst
Symbolic link
1
doc/develop/package/binman.rst
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../../tools/binman/binman.rst
|
1
doc/develop/package/entries.rst
Symbolic link
1
doc/develop/package/entries.rst
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../../tools/binman/entries.rst
|
19
doc/develop/package/index.rst
Normal file
19
doc/develop/package/index.rst
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
.. SPDX-License-Identifier: GPL-2.0+
|
||||||
|
|
||||||
|
Package U-Boot
|
||||||
|
==============
|
||||||
|
|
||||||
|
U-Boot uses Flat Image Tree (FIT) as a standard file format for packaging
|
||||||
|
images that it it reads and boots. Documentation about FIT is available at
|
||||||
|
doc/uImage.FIT
|
||||||
|
|
||||||
|
U-Boot also provides binman for cases not covered by FIT. Examples include
|
||||||
|
initial execution (since FIT itself does not have an executable header) and
|
||||||
|
dealing with device boundaries, such as the read-only/read-write separation in
|
||||||
|
SPI flash.
|
||||||
|
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
binman
|
|
@ -3,6 +3,10 @@
|
||||||
Unified Extensible Firmware (UEFI)
|
Unified Extensible Firmware (UEFI)
|
||||||
==================================
|
==================================
|
||||||
|
|
||||||
|
U-Boot provides an implementation of the UEFI API allowing to run UEFI
|
||||||
|
compliant software like Linux, GRUB, and iPXE. Furthermore U-Boot itself
|
||||||
|
can be run an UEFI payload.
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 2
|
:maxdepth: 2
|
||||||
|
|
|
@ -1,359 +0,0 @@
|
||||||
.. SPDX-License-Identifier: GPL-2.0+
|
|
||||||
|
|
||||||
Compiled-in Device Tree / Platform Data
|
|
||||||
=======================================
|
|
||||||
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
------------
|
|
||||||
|
|
||||||
Device tree is the standard configuration method in U-Boot. It is used to
|
|
||||||
define what devices are in the system and provide configuration information
|
|
||||||
to these devices.
|
|
||||||
|
|
||||||
The overhead of adding device tree access to U-Boot is fairly modest,
|
|
||||||
approximately 3KB on Thumb 2 (plus the size of the DT itself). This means
|
|
||||||
that in most cases it is best to use device tree for configuration.
|
|
||||||
|
|
||||||
However there are some very constrained environments where U-Boot needs to
|
|
||||||
work. These include SPL with severe memory limitations. For example, some
|
|
||||||
SoCs require a 16KB SPL image which must include a full MMC stack. In this
|
|
||||||
case the overhead of device tree access may be too great.
|
|
||||||
|
|
||||||
It is possible to create platform data manually by defining C structures
|
|
||||||
for it, and reference that data in a U_BOOT_DRVINFO() declaration. This
|
|
||||||
bypasses the use of device tree completely, effectively creating a parallel
|
|
||||||
configuration mechanism. But it is an available option for SPL.
|
|
||||||
|
|
||||||
As an alternative, a new 'of-platdata' feature is provided. This converts the
|
|
||||||
device tree contents into C code which can be compiled into the SPL binary.
|
|
||||||
This saves the 3KB of code overhead and perhaps a few hundred more bytes due
|
|
||||||
to more efficient storage of the data.
|
|
||||||
|
|
||||||
Note: Quite a bit of thought has gone into the design of this feature.
|
|
||||||
However it still has many rough edges and comments and suggestions are
|
|
||||||
strongly encouraged! Quite possibly there is a much better approach.
|
|
||||||
|
|
||||||
|
|
||||||
Caveats
|
|
||||||
-------
|
|
||||||
|
|
||||||
There are many problems with this features. It should only be used when
|
|
||||||
strictly necessary. Notable problems include:
|
|
||||||
|
|
||||||
- Device tree does not describe data types. But the C code must define a
|
|
||||||
type for each property. These are guessed using heuristics which
|
|
||||||
are wrong in several fairly common cases. For example an 8-byte value
|
|
||||||
is considered to be a 2-item integer array, and is byte-swapped. A
|
|
||||||
boolean value that is not present means 'false', but cannot be
|
|
||||||
included in the structures since there is generally no mention of it
|
|
||||||
in the device tree file.
|
|
||||||
|
|
||||||
- Naming of nodes and properties is automatic. This means that they follow
|
|
||||||
the naming in the device tree, which may result in C identifiers that
|
|
||||||
look a bit strange.
|
|
||||||
|
|
||||||
- It is not possible to find a value given a property name. Code must use
|
|
||||||
the associated C member variable directly in the code. This makes
|
|
||||||
the code less robust in the face of device-tree changes. It also
|
|
||||||
makes it very unlikely that your driver code will be useful for more
|
|
||||||
than one SoC. Even if the code is common, each SoC will end up with
|
|
||||||
a different C struct name, and a likely a different format for the
|
|
||||||
platform data.
|
|
||||||
|
|
||||||
- The platform data is provided to drivers as a C structure. The driver
|
|
||||||
must use the same structure to access the data. Since a driver
|
|
||||||
normally also supports device tree it must use #ifdef to separate
|
|
||||||
out this code, since the structures are only available in SPL.
|
|
||||||
|
|
||||||
|
|
||||||
How it works
|
|
||||||
------------
|
|
||||||
|
|
||||||
The feature is enabled by CONFIG OF_PLATDATA. This is only available in
|
|
||||||
SPL/TPL and should be tested with:
|
|
||||||
|
|
||||||
.. code-block:: c
|
|
||||||
|
|
||||||
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
|
||||||
|
|
||||||
A new tool called 'dtoc' converts a device tree file either into a set of
|
|
||||||
struct declarations, one for each compatible node, and a set of
|
|
||||||
U_BOOT_DRVINFO() declarations along with the actual platform data for each
|
|
||||||
device. As an example, consider this MMC node:
|
|
||||||
|
|
||||||
.. code-block:: none
|
|
||||||
|
|
||||||
sdmmc: dwmmc@ff0c0000 {
|
|
||||||
compatible = "rockchip,rk3288-dw-mshc";
|
|
||||||
clock-freq-min-max = <400000 150000000>;
|
|
||||||
clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>,
|
|
||||||
<&cru SCLK_SDMMC_DRV>, <&cru SCLK_SDMMC_SAMPLE>;
|
|
||||||
clock-names = "biu", "ciu", "ciu_drv", "ciu_sample";
|
|
||||||
fifo-depth = <0x100>;
|
|
||||||
interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
|
|
||||||
reg = <0xff0c0000 0x4000>;
|
|
||||||
bus-width = <4>;
|
|
||||||
cap-mmc-highspeed;
|
|
||||||
cap-sd-highspeed;
|
|
||||||
card-detect-delay = <200>;
|
|
||||||
disable-wp;
|
|
||||||
num-slots = <1>;
|
|
||||||
pinctrl-names = "default";
|
|
||||||
pinctrl-0 = <&sdmmc_clk>, <&sdmmc_cmd>, <&sdmmc_cd>, <&sdmmc_bus4>;
|
|
||||||
vmmc-supply = <&vcc_sd>;
|
|
||||||
status = "okay";
|
|
||||||
u-boot,dm-pre-reloc;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
Some of these properties are dropped by U-Boot under control of the
|
|
||||||
CONFIG_OF_SPL_REMOVE_PROPS option. The rest are processed. This will produce
|
|
||||||
the following C struct declaration:
|
|
||||||
|
|
||||||
.. code-block:: c
|
|
||||||
|
|
||||||
struct dtd_rockchip_rk3288_dw_mshc {
|
|
||||||
fdt32_t bus_width;
|
|
||||||
bool cap_mmc_highspeed;
|
|
||||||
bool cap_sd_highspeed;
|
|
||||||
fdt32_t card_detect_delay;
|
|
||||||
fdt32_t clock_freq_min_max[2];
|
|
||||||
struct phandle_1_arg clocks[4];
|
|
||||||
bool disable_wp;
|
|
||||||
fdt32_t fifo_depth;
|
|
||||||
fdt32_t interrupts[3];
|
|
||||||
fdt32_t num_slots;
|
|
||||||
fdt32_t reg[2];
|
|
||||||
fdt32_t vmmc_supply;
|
|
||||||
};
|
|
||||||
|
|
||||||
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,
|
|
||||||
.interrupts = {0x0, 0x20, 0x4},
|
|
||||||
.clock_freq_min_max = {0x61a80, 0x8f0d180},
|
|
||||||
.vmmc_supply = 0xb,
|
|
||||||
.num_slots = 0x1,
|
|
||||||
.clocks = {{0, 456},
|
|
||||||
{0, 68},
|
|
||||||
{0, 114},
|
|
||||||
{0, 118}},
|
|
||||||
.cap_mmc_highspeed = true,
|
|
||||||
.disable_wp = true,
|
|
||||||
.bus_width = 0x4,
|
|
||||||
.u_boot_dm_pre_reloc = true,
|
|
||||||
.reg = {0xff0c0000, 0x4000},
|
|
||||||
.card_detect_delay = 0xc8,
|
|
||||||
};
|
|
||||||
|
|
||||||
U_BOOT_DRVINFO(dwmmc_at_ff0c0000) = {
|
|
||||||
.name = "rockchip_rk3288_dw_mshc",
|
|
||||||
.plat = &dtv_dwmmc_at_ff0c0000,
|
|
||||||
.plat_size = sizeof(dtv_dwmmc_at_ff0c0000),
|
|
||||||
.parent_idx = -1,
|
|
||||||
};
|
|
||||||
|
|
||||||
The device is then instantiated at run-time and the platform data can be
|
|
||||||
accessed using:
|
|
||||||
|
|
||||||
.. code-block:: c
|
|
||||||
|
|
||||||
struct udevice *dev;
|
|
||||||
struct dtd_rockchip_rk3288_dw_mshc *plat = dev_get_plat(dev);
|
|
||||||
|
|
||||||
This avoids the code overhead of converting the device tree data to
|
|
||||||
platform data in the driver. The of_to_plat() method should
|
|
||||||
therefore do nothing in such a driver.
|
|
||||||
|
|
||||||
Note that for the platform data to be matched with a driver, the 'name'
|
|
||||||
property of the U_BOOT_DRVINFO() declaration has to match a driver declared
|
|
||||||
via U_BOOT_DRIVER(). This effectively means that a U_BOOT_DRIVER() with a
|
|
||||||
'name' corresponding to the devicetree 'compatible' string (after converting
|
|
||||||
it to a valid name for C) is needed, so a dedicated driver is required for
|
|
||||||
each 'compatible' string.
|
|
||||||
|
|
||||||
In order to make this a bit more flexible DM_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_DRVINFO() macro). This is used to support
|
|
||||||
dev_get_parent().
|
|
||||||
|
|
||||||
During the build process dtoc parses both U_BOOT_DRIVER and DM_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
|
|
||||||
checked against the list of driver aliases in order to get the right driver
|
|
||||||
name to use. If in this step there is no match found a warning is issued to
|
|
||||||
avoid run-time failures.
|
|
||||||
|
|
||||||
Where a node has multiple compatible strings, a #define is used to make them
|
|
||||||
equivalent, e.g.:
|
|
||||||
|
|
||||||
.. code-block:: c
|
|
||||||
|
|
||||||
#define dtd_rockchip_rk3299_dw_mshc dtd_rockchip_rk3288_dw_mshc
|
|
||||||
|
|
||||||
|
|
||||||
Converting of-platdata to a useful form
|
|
||||||
---------------------------------------
|
|
||||||
|
|
||||||
Of course it would be possible to use the of-platdata directly in your driver
|
|
||||||
whenever configuration information is required. However this means that the
|
|
||||||
driver will not be able to support device tree, since the of-platdata
|
|
||||||
structure is not available when device tree is used. It would make no sense
|
|
||||||
to use this structure if device tree were available, since the structure has
|
|
||||||
all the limitations metioned in caveats above.
|
|
||||||
|
|
||||||
Therefore it is recommended that the of-platdata structure should be used
|
|
||||||
only in the probe() method of your driver. It cannot be used in the
|
|
||||||
of_to_plat() method since this is not called when platform data is
|
|
||||||
already present.
|
|
||||||
|
|
||||||
|
|
||||||
How to structure your driver
|
|
||||||
----------------------------
|
|
||||||
|
|
||||||
Drivers should always support device tree as an option. The of-platdata
|
|
||||||
feature is intended as a add-on to existing drivers.
|
|
||||||
|
|
||||||
Your driver should convert the plat struct in its probe() method. The
|
|
||||||
existing device tree decoding logic should be kept in the
|
|
||||||
of_to_plat() method and wrapped with #if.
|
|
||||||
|
|
||||||
For example:
|
|
||||||
|
|
||||||
.. code-block:: c
|
|
||||||
|
|
||||||
#include <dt-structs.h>
|
|
||||||
|
|
||||||
struct mmc_plat {
|
|
||||||
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
|
||||||
/* Put this first since driver model will copy the data here */
|
|
||||||
struct dtd_mmc dtplat;
|
|
||||||
#endif
|
|
||||||
/*
|
|
||||||
* Other fields can go here, to be filled in by decoding from
|
|
||||||
* the device tree (or the C structures when of-platdata is used).
|
|
||||||
*/
|
|
||||||
int fifo_depth;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int mmc_of_to_plat(struct udevice *dev)
|
|
||||||
{
|
|
||||||
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
|
|
||||||
/* Decode the device tree data */
|
|
||||||
struct mmc_plat *plat = dev_get_plat(dev);
|
|
||||||
const void *blob = gd->fdt_blob;
|
|
||||||
int node = dev_of_offset(dev);
|
|
||||||
|
|
||||||
plat->fifo_depth = fdtdec_get_int(blob, node, "fifo-depth", 0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mmc_probe(struct udevice *dev)
|
|
||||||
{
|
|
||||||
struct mmc_plat *plat = dev_get_plat(dev);
|
|
||||||
|
|
||||||
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
|
||||||
/* Decode the of-platdata from the C structures */
|
|
||||||
struct dtd_mmc *dtplat = &plat->dtplat;
|
|
||||||
|
|
||||||
plat->fifo_depth = dtplat->fifo_depth;
|
|
||||||
#endif
|
|
||||||
/* Set up the device from the plat data */
|
|
||||||
writel(plat->fifo_depth, ...)
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct udevice_id mmc_ids[] = {
|
|
||||||
{ .compatible = "vendor,mmc" },
|
|
||||||
{ }
|
|
||||||
};
|
|
||||||
|
|
||||||
U_BOOT_DRIVER(mmc_drv) = {
|
|
||||||
.name = "mmc_drv",
|
|
||||||
.id = UCLASS_MMC,
|
|
||||||
.of_match = mmc_ids,
|
|
||||||
.of_to_plat = mmc_of_to_plat,
|
|
||||||
.probe = mmc_probe,
|
|
||||||
.priv_auto = sizeof(struct mmc_priv),
|
|
||||||
.plat_auto = sizeof(struct mmc_plat),
|
|
||||||
};
|
|
||||||
|
|
||||||
DM_DRIVER_ALIAS(mmc_drv, vendor_mmc) /* matches compatible string */
|
|
||||||
|
|
||||||
Note that struct mmc_plat is defined in the C file, not in a header. This
|
|
||||||
is to avoid needing to include dt-structs.h in a header file. The idea is to
|
|
||||||
keep the use of each of-platdata struct to the smallest possible code area.
|
|
||||||
There is just one driver C file for each struct, that can convert from the
|
|
||||||
of-platdata struct to the standard one used by the driver.
|
|
||||||
|
|
||||||
In the case where SPL_OF_PLATDATA is enabled, plat_auto is
|
|
||||||
still used to allocate space for the platform data. This is different from
|
|
||||||
the normal behaviour and is triggered by the use of of-platdata (strictly
|
|
||||||
speaking it is a non-zero plat_size which triggers this).
|
|
||||||
|
|
||||||
The of-platdata struct contents is copied from the C structure data to the
|
|
||||||
start of the newly allocated area. In the case where device tree is used,
|
|
||||||
the platform data is allocated, and starts zeroed. In this case the
|
|
||||||
of_to_plat() method should still set up the platform data (and the
|
|
||||||
of-platdata struct will not be present).
|
|
||||||
|
|
||||||
SPL must use either of-platdata or device tree. Drivers cannot use both at
|
|
||||||
the same time, but they must support device tree. Supporting of-platdata is
|
|
||||||
optional.
|
|
||||||
|
|
||||||
The device tree becomes in accessible when CONFIG_SPL_OF_PLATDATA is enabled,
|
|
||||||
since the device-tree access code is not compiled in. A corollary is that
|
|
||||||
a board can only move to using of-platdata if all the drivers it uses support
|
|
||||||
it. There would be little point in having some drivers require the device
|
|
||||||
tree data, since then libfdt would still be needed for those drivers and
|
|
||||||
there would be no code-size benefit.
|
|
||||||
|
|
||||||
Internals
|
|
||||||
---------
|
|
||||||
|
|
||||||
The dt-structs.h file includes the generated file
|
|
||||||
(include/generated//dt-structs.h) if CONFIG_SPL_OF_PLATDATA is enabled.
|
|
||||||
Otherwise (such as in U-Boot proper) these structs are not available. This
|
|
||||||
prevents them being used inadvertently. All usage must be bracketed with
|
|
||||||
#if CONFIG_IS_ENABLED(OF_PLATDATA).
|
|
||||||
|
|
||||||
The dt-plat.c file contains the device declarations and is is built in
|
|
||||||
spl/dt-plat.c.
|
|
||||||
|
|
||||||
The dm_populate_phandle_data() function that was previous needed has now been
|
|
||||||
removed, since dtoc can address the drivers directly from dt-plat.c and does
|
|
||||||
not need to fix up things at runtime.
|
|
||||||
|
|
||||||
The pylibfdt Python module is used to access the devicetree.
|
|
||||||
|
|
||||||
|
|
||||||
Credits
|
|
||||||
-------
|
|
||||||
|
|
||||||
This is an implementation of an idea by Tom Rini <trini@konsulko.com>.
|
|
||||||
|
|
||||||
|
|
||||||
Future work
|
|
||||||
-----------
|
|
||||||
- Consider programmatically reading binding files instead of device tree
|
|
||||||
contents
|
|
||||||
|
|
||||||
|
|
||||||
.. Simon Glass <sjg@chromium.org>
|
|
||||||
.. Google, Inc
|
|
||||||
.. 6/6/16
|
|
||||||
.. Updated Independence Day 2016
|
|
||||||
.. Updated 1st October 2020
|
|
|
@ -38,29 +38,6 @@ want to contribute to U-Boot.
|
||||||
|
|
||||||
develop/index
|
develop/index
|
||||||
|
|
||||||
Unified Extensible Firmware (UEFI)
|
|
||||||
----------------------------------
|
|
||||||
|
|
||||||
U-Boot provides an implementation of the UEFI API allowing to run UEFI
|
|
||||||
compliant software like Linux, GRUB, and iPXE. Furthermore U-Boot itself
|
|
||||||
can be run an UEFI payload.
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 2
|
|
||||||
|
|
||||||
uefi/index
|
|
||||||
|
|
||||||
Driver-Model documentation
|
|
||||||
--------------------------
|
|
||||||
|
|
||||||
The following holds information on the U-Boot device driver framework:
|
|
||||||
driver-model, including the design details of itself and several driver
|
|
||||||
subsystems.
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 2
|
|
||||||
|
|
||||||
driver-model/index
|
|
||||||
|
|
||||||
U-Boot API documentation
|
U-Boot API documentation
|
||||||
------------------------
|
------------------------
|
||||||
|
|
8
doc/usage/fit.rst
Normal file
8
doc/usage/fit.rst
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
.. SPDX-License-Identifier: GPL-2.0+
|
||||||
|
|
||||||
|
Flat Image Tree (FIT)
|
||||||
|
=====================
|
||||||
|
|
||||||
|
U-Boot uses Flat Image Tree (FIT) as a standard file format for packaging
|
||||||
|
images that it it reads and boots. Documentation about FIT is available at
|
||||||
|
doc/uImage.FIT
|
|
@ -5,6 +5,7 @@ Use U-Boot
|
||||||
:maxdepth: 1
|
:maxdepth: 1
|
||||||
|
|
||||||
fdt_overlays
|
fdt_overlays
|
||||||
|
fit
|
||||||
netconsole
|
netconsole
|
||||||
partitions
|
partitions
|
||||||
|
|
||||||
|
|
|
@ -148,12 +148,6 @@ clocks_err:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
UCLASS_DRIVER(ti_sysc) = {
|
|
||||||
.id = UCLASS_SIMPLE_BUS,
|
|
||||||
.name = "ti_sysc",
|
|
||||||
.post_bind = dm_scan_fdt_dev
|
|
||||||
};
|
|
||||||
|
|
||||||
U_BOOT_DRIVER(ti_sysc) = {
|
U_BOOT_DRIVER(ti_sysc) = {
|
||||||
.name = "ti_sysc",
|
.name = "ti_sysc",
|
||||||
.id = UCLASS_SIMPLE_BUS,
|
.id = UCLASS_SIMPLE_BUS,
|
||||||
|
|
|
@ -39,7 +39,7 @@ int clk_get_by_driver_info(struct udevice *dev, struct phandle_1_arg *cells,
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = device_get_by_driver_info_idx(cells->idx, &clk->dev);
|
ret = device_get_by_ofplat_idx(cells->idx, &clk->dev);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
clk->id = cells->arg[0];
|
clk->id = cells->arg[0];
|
||||||
|
|
|
@ -25,18 +25,24 @@ const struct clk_ops clk_fixed_rate_ops = {
|
||||||
.enable = dummy_enable,
|
.enable = dummy_enable,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int clk_fixed_rate_of_to_plat(struct udevice *dev)
|
void clk_fixed_rate_ofdata_to_plat_(struct udevice *dev,
|
||||||
|
struct clk_fixed_rate *plat)
|
||||||
{
|
{
|
||||||
struct clk *clk = &to_clk_fixed_rate(dev)->clk;
|
struct clk *clk = &plat->clk;
|
||||||
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
|
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||||
to_clk_fixed_rate(dev)->fixed_rate =
|
plat->fixed_rate = dev_read_u32_default(dev, "clock-frequency", 0);
|
||||||
dev_read_u32_default(dev, "clock-frequency", 0);
|
|
||||||
#endif
|
#endif
|
||||||
/* Make fixed rate clock accessible from higher level struct clk */
|
/* Make fixed rate clock accessible from higher level struct clk */
|
||||||
/* FIXME: This is not allowed */
|
/* FIXME: This is not allowed */
|
||||||
dev_set_uclass_priv(dev, clk);
|
dev_set_uclass_priv(dev, clk);
|
||||||
|
|
||||||
clk->dev = dev;
|
clk->dev = dev;
|
||||||
clk->enable_count = 0;
|
clk->enable_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int clk_fixed_rate_of_to_plat(struct udevice *dev)
|
||||||
|
{
|
||||||
|
clk_fixed_rate_ofdata_to_plat_(dev, to_clk_fixed_rate(dev));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,13 +9,7 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <asm/clk.h>
|
#include <asm/clk.h>
|
||||||
|
#include <linux/clk-provider.h>
|
||||||
struct sandbox_clk_priv {
|
|
||||||
bool probed;
|
|
||||||
ulong rate[SANDBOX_CLK_ID_COUNT];
|
|
||||||
bool enabled[SANDBOX_CLK_ID_COUNT];
|
|
||||||
bool requested[SANDBOX_CLK_ID_COUNT];
|
|
||||||
};
|
|
||||||
|
|
||||||
static ulong sandbox_clk_get_rate(struct clk *clk)
|
static ulong sandbox_clk_get_rate(struct clk *clk)
|
||||||
{
|
{
|
||||||
|
@ -178,3 +172,35 @@ int sandbox_clk_query_requested(struct udevice *dev, int id)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
return priv->requested[id];
|
return priv->requested[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int clk_fixed_rate_of_to_plat(struct udevice *dev)
|
||||||
|
{
|
||||||
|
struct clk_fixed_rate *cplat;
|
||||||
|
|
||||||
|
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||||
|
struct sandbox_clk_fixed_rate_plat *plat = dev_get_plat(dev);
|
||||||
|
|
||||||
|
cplat = &plat->fixed;
|
||||||
|
cplat->fixed_rate = plat->dtplat.clock_frequency;
|
||||||
|
#else
|
||||||
|
cplat = to_clk_fixed_rate(dev);
|
||||||
|
#endif
|
||||||
|
clk_fixed_rate_ofdata_to_plat_(dev, cplat);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct udevice_id sandbox_clk_fixed_rate_match[] = {
|
||||||
|
{ .compatible = "sandbox,fixed-clock" },
|
||||||
|
{ /* sentinel */ }
|
||||||
|
};
|
||||||
|
|
||||||
|
U_BOOT_DRIVER(sandbox_fixed_clock) = {
|
||||||
|
.name = "sandbox_fixed_clock",
|
||||||
|
.id = UCLASS_CLK,
|
||||||
|
.of_match = sandbox_clk_fixed_rate_match,
|
||||||
|
.of_to_plat = clk_fixed_rate_of_to_plat,
|
||||||
|
.plat_auto = sizeof(struct sandbox_clk_fixed_rate_plat),
|
||||||
|
.ops = &clk_fixed_rate_ops,
|
||||||
|
.flags = DM_FLAG_PRE_RELOC,
|
||||||
|
};
|
||||||
|
|
|
@ -11,12 +11,6 @@
|
||||||
#include <dm/device_compat.h>
|
#include <dm/device_compat.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
|
|
||||||
struct sandbox_clk_test {
|
|
||||||
struct clk clks[SANDBOX_CLK_TEST_NON_DEVM_COUNT];
|
|
||||||
struct clk *clkps[SANDBOX_CLK_TEST_ID_COUNT];
|
|
||||||
struct clk_bulk bulk;
|
|
||||||
};
|
|
||||||
|
|
||||||
static const char * const sandbox_clk_test_names[] = {
|
static const char * const sandbox_clk_test_names[] = {
|
||||||
[SANDBOX_CLK_TEST_ID_FIXED] = "fixed",
|
[SANDBOX_CLK_TEST_ID_FIXED] = "fixed",
|
||||||
[SANDBOX_CLK_TEST_ID_SPI] = "spi",
|
[SANDBOX_CLK_TEST_ID_SPI] = "spi",
|
||||||
|
|
|
@ -45,6 +45,9 @@ static int device_bind_common(struct udevice *parent, const struct driver *drv,
|
||||||
bool auto_seq = true;
|
bool auto_seq = true;
|
||||||
void *ptr;
|
void *ptr;
|
||||||
|
|
||||||
|
if (CONFIG_IS_ENABLED(OF_PLATDATA_NO_BIND))
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
if (devp)
|
if (devp)
|
||||||
*devp = NULL;
|
*devp = NULL;
|
||||||
if (!name)
|
if (!name)
|
||||||
|
@ -395,6 +398,11 @@ int device_of_to_plat(struct udevice *dev)
|
||||||
if (dev_get_flags(dev) & DM_FLAG_PLATDATA_VALID)
|
if (dev_get_flags(dev) & DM_FLAG_PLATDATA_VALID)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is not needed if binding is disabled, since data is allocated
|
||||||
|
* at build time.
|
||||||
|
*/
|
||||||
|
if (!CONFIG_IS_ENABLED(OF_PLATDATA_NO_BIND)) {
|
||||||
/* Ensure all parents have ofdata */
|
/* Ensure all parents have ofdata */
|
||||||
if (dev->parent) {
|
if (dev->parent) {
|
||||||
ret = device_of_to_plat(dev->parent);
|
ret = device_of_to_plat(dev->parent);
|
||||||
|
@ -414,7 +422,7 @@ int device_of_to_plat(struct udevice *dev)
|
||||||
ret = device_alloc_priv(dev);
|
ret = device_alloc_priv(dev);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
}
|
||||||
drv = dev->driver;
|
drv = dev->driver;
|
||||||
assert(drv);
|
assert(drv);
|
||||||
|
|
||||||
|
@ -592,7 +600,7 @@ void *dev_get_plat(const struct udevice *dev)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return dev->plat_;
|
return dm_priv_to_rw(dev->plat_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *dev_get_parent_plat(const struct udevice *dev)
|
void *dev_get_parent_plat(const struct udevice *dev)
|
||||||
|
@ -602,7 +610,7 @@ void *dev_get_parent_plat(const struct udevice *dev)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return dev->parent_plat_;
|
return dm_priv_to_rw(dev->parent_plat_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *dev_get_uclass_plat(const struct udevice *dev)
|
void *dev_get_uclass_plat(const struct udevice *dev)
|
||||||
|
@ -612,7 +620,7 @@ void *dev_get_uclass_plat(const struct udevice *dev)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return dev->uclass_plat_;
|
return dm_priv_to_rw(dev->uclass_plat_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *dev_get_priv(const struct udevice *dev)
|
void *dev_get_priv(const struct udevice *dev)
|
||||||
|
@ -622,7 +630,7 @@ void *dev_get_priv(const struct udevice *dev)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return dev->priv_;
|
return dm_priv_to_rw(dev->priv_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *dev_get_uclass_priv(const struct udevice *dev)
|
void *dev_get_uclass_priv(const struct udevice *dev)
|
||||||
|
@ -632,7 +640,7 @@ void *dev_get_uclass_priv(const struct udevice *dev)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return dev->uclass_priv_;
|
return dm_priv_to_rw(dev->uclass_priv_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *dev_get_parent_priv(const struct udevice *dev)
|
void *dev_get_parent_priv(const struct udevice *dev)
|
||||||
|
@ -642,7 +650,7 @@ void *dev_get_parent_priv(const struct udevice *dev)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return dev->parent_priv_;
|
return dm_priv_to_rw(dev->parent_priv_);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int device_get_device_tail(struct udevice *dev, int ret,
|
static int device_get_device_tail(struct udevice *dev, int ret,
|
||||||
|
@ -803,27 +811,19 @@ int device_get_global_by_ofnode(ofnode ofnode, struct udevice **devp)
|
||||||
}
|
}
|
||||||
|
|
||||||
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||||
int device_get_by_driver_info(const struct driver_info *info,
|
int device_get_by_ofplat_idx(uint idx, struct udevice **devp)
|
||||||
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;
|
struct udevice *dev;
|
||||||
|
|
||||||
dev = drt->dev;
|
if (CONFIG_IS_ENABLED(OF_PLATDATA_INST)) {
|
||||||
*devp = NULL;
|
struct udevice *base = ll_entry_start(struct udevice, udevice);
|
||||||
|
|
||||||
return device_get_device_tail(dev, dev ? 0 : -ENOENT, devp);
|
dev = base + idx;
|
||||||
|
} else {
|
||||||
|
struct driver_rt *drt = gd_dm_driver_rt() + idx;
|
||||||
|
|
||||||
|
dev = drt->dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
*devp = NULL;
|
||||||
|
|
||||||
return device_get_device_tail(dev, dev ? 0 : -ENOENT, devp);
|
return device_get_device_tail(dev, dev ? 0 : -ENOENT, devp);
|
||||||
|
@ -1136,3 +1136,36 @@ int dev_enable_by_path(const char *path)
|
||||||
return lists_bind_fdt(parent, node, NULL, false);
|
return lists_bind_fdt(parent, node, NULL, false);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if CONFIG_IS_ENABLED(OF_PLATDATA_RT)
|
||||||
|
static struct udevice_rt *dev_get_rt(const struct udevice *dev)
|
||||||
|
{
|
||||||
|
struct udevice *base = ll_entry_start(struct udevice, udevice);
|
||||||
|
int idx = dev - base;
|
||||||
|
|
||||||
|
struct udevice_rt *urt = gd_dm_udevice_rt() + idx;
|
||||||
|
|
||||||
|
return urt;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 dev_get_flags(const struct udevice *dev)
|
||||||
|
{
|
||||||
|
const struct udevice_rt *urt = dev_get_rt(dev);
|
||||||
|
|
||||||
|
return urt->flags_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dev_or_flags(const struct udevice *dev, u32 or)
|
||||||
|
{
|
||||||
|
struct udevice_rt *urt = dev_get_rt(dev);
|
||||||
|
|
||||||
|
urt->flags_ |= or;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dev_bic_flags(const struct udevice *dev, u32 bic)
|
||||||
|
{
|
||||||
|
struct udevice_rt *urt = dev_get_rt(dev);
|
||||||
|
|
||||||
|
urt->flags_ &= ~bic;
|
||||||
|
}
|
||||||
|
#endif /* OF_PLATDATA_RT */
|
||||||
|
|
|
@ -372,7 +372,7 @@ int of_get_dma_range(const struct device_node *dev, phys_addr_t *cpu,
|
||||||
bus_node->count_cells(dev, &na, &ns);
|
bus_node->count_cells(dev, &na, &ns);
|
||||||
if (!OF_CHECK_COUNTS(na, ns)) {
|
if (!OF_CHECK_COUNTS(na, ns)) {
|
||||||
printf("Bad cell count for %s\n", of_node_full_name(dev));
|
printf("Bad cell count for %s\n", of_node_full_name(dev));
|
||||||
return -EINVAL;
|
ret = -EINVAL;
|
||||||
goto out_parent;
|
goto out_parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -380,7 +380,7 @@ int of_get_dma_range(const struct device_node *dev, phys_addr_t *cpu,
|
||||||
bus_node->count_cells(parent, &pna, &pns);
|
bus_node->count_cells(parent, &pna, &pns);
|
||||||
if (!OF_CHECK_COUNTS(pna, pns)) {
|
if (!OF_CHECK_COUNTS(pna, pns)) {
|
||||||
printf("Bad cell count for %s\n", of_node_full_name(parent));
|
printf("Bad cell count for %s\n", of_node_full_name(parent));
|
||||||
return -EINVAL;
|
ret = -EINVAL;
|
||||||
goto out_parent;
|
goto out_parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <fdtdec.h>
|
#include <fdtdec.h>
|
||||||
#include <log.h>
|
#include <log.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
|
#include <asm-generic/sections.h>
|
||||||
#include <asm/global_data.h>
|
#include <asm/global_data.h>
|
||||||
#include <linux/libfdt.h>
|
#include <linux/libfdt.h>
|
||||||
#include <dm/acpi.h>
|
#include <dm/acpi.h>
|
||||||
|
@ -129,6 +130,36 @@ void fix_devices(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int dm_setup_inst(void)
|
||||||
|
{
|
||||||
|
DM_ROOT_NON_CONST = DM_DEVICE_GET(root);
|
||||||
|
|
||||||
|
if (CONFIG_IS_ENABLED(OF_PLATDATA_RT)) {
|
||||||
|
struct udevice_rt *urt;
|
||||||
|
void *base;
|
||||||
|
int n_ents;
|
||||||
|
uint size;
|
||||||
|
|
||||||
|
/* Allocate the udevice_rt table */
|
||||||
|
n_ents = ll_entry_count(struct udevice, udevice);
|
||||||
|
urt = calloc(n_ents, sizeof(struct udevice_rt));
|
||||||
|
if (!urt)
|
||||||
|
return log_msg_ret("urt", -ENOMEM);
|
||||||
|
gd_set_dm_udevice_rt(urt);
|
||||||
|
|
||||||
|
/* Now allocate space for the priv/plat data, and copy it in */
|
||||||
|
size = __priv_data_end - __priv_data_start;
|
||||||
|
|
||||||
|
base = calloc(1, size);
|
||||||
|
if (!base)
|
||||||
|
return log_msg_ret("priv", -ENOMEM);
|
||||||
|
memcpy(base, __priv_data_start, size);
|
||||||
|
gd_set_dm_priv_base(base);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int dm_init(bool of_live)
|
int dm_init(bool of_live)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -140,8 +171,12 @@ int dm_init(bool of_live)
|
||||||
dm_warn("Virtual root driver already exists!\n");
|
dm_warn("Virtual root driver already exists!\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
if (CONFIG_IS_ENABLED(OF_PLATDATA_INST)) {
|
||||||
|
gd->uclass_root = &uclass_head;
|
||||||
|
} else {
|
||||||
gd->uclass_root = &DM_UCLASS_ROOT_S_NON_CONST;
|
gd->uclass_root = &DM_UCLASS_ROOT_S_NON_CONST;
|
||||||
INIT_LIST_HEAD(DM_UCLASS_ROOT_NON_CONST);
|
INIT_LIST_HEAD(DM_UCLASS_ROOT_NON_CONST);
|
||||||
|
}
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_NEEDS_MANUAL_RELOC)) {
|
if (IS_ENABLED(CONFIG_NEEDS_MANUAL_RELOC)) {
|
||||||
fix_drivers();
|
fix_drivers();
|
||||||
|
@ -149,7 +184,15 @@ int dm_init(bool of_live)
|
||||||
fix_devices();
|
fix_devices();
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = device_bind_by_name(NULL, false, &root_info, &DM_ROOT_NON_CONST);
|
if (CONFIG_IS_ENABLED(OF_PLATDATA_INST)) {
|
||||||
|
ret = dm_setup_inst();
|
||||||
|
if (ret) {
|
||||||
|
log_debug("dm_setup_inst() failed: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ret = device_bind_by_name(NULL, false, &root_info,
|
||||||
|
&DM_ROOT_NON_CONST);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
if (CONFIG_IS_ENABLED(OF_CONTROL))
|
if (CONFIG_IS_ENABLED(OF_CONTROL))
|
||||||
|
@ -157,6 +200,7 @@ int dm_init(bool of_live)
|
||||||
ret = device_probe(DM_ROOT_NON_CONST);
|
ret = device_probe(DM_ROOT_NON_CONST);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -185,7 +229,7 @@ int dm_scan_plat(bool pre_reloc_only)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (CONFIG_IS_ENABLED(OF_PLATDATA)) {
|
if (CONFIG_IS_ENABLED(OF_PLATDATA_DRIVER_RT)) {
|
||||||
struct driver_rt *dyn;
|
struct driver_rt *dyn;
|
||||||
int n_ents;
|
int n_ents;
|
||||||
|
|
||||||
|
@ -303,6 +347,15 @@ __weak int dm_scan_other(bool pre_reloc_only)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if CONFIG_IS_ENABLED(OF_PLATDATA_INST) && CONFIG_IS_ENABLED(READ_ONLY)
|
||||||
|
void *dm_priv_to_rw(void *priv)
|
||||||
|
{
|
||||||
|
long offset = priv - (void *)__priv_data_start;
|
||||||
|
|
||||||
|
return gd_dm_priv_base() + offset;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* dm_scan() - Scan tables to bind devices
|
* dm_scan() - Scan tables to bind devices
|
||||||
*
|
*
|
||||||
|
@ -347,11 +400,13 @@ int dm_init_and_scan(bool pre_reloc_only)
|
||||||
debug("dm_init() failed: %d\n", ret);
|
debug("dm_init() failed: %d\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
if (!CONFIG_IS_ENABLED(OF_PLATDATA_INST)) {
|
||||||
ret = dm_scan(pre_reloc_only);
|
ret = dm_scan(pre_reloc_only);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
log_debug("dm_scan() failed: %d\n", ret);
|
log_debug("dm_scan() failed: %d\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -148,8 +148,11 @@ int uclass_get(enum uclass_id id, struct uclass **ucp)
|
||||||
|
|
||||||
*ucp = NULL;
|
*ucp = NULL;
|
||||||
uc = uclass_find(id);
|
uc = uclass_find(id);
|
||||||
if (!uc)
|
if (!uc) {
|
||||||
|
if (CONFIG_IS_ENABLED(OF_PLATDATA_INST))
|
||||||
|
return -ENOENT;
|
||||||
return uclass_add(id, ucp);
|
return uclass_add(id, ucp);
|
||||||
|
}
|
||||||
*ucp = uc;
|
*ucp = uc;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -391,7 +394,7 @@ done:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if CONFIG_IS_ENABLED(OF_CONTROL)
|
#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||||
int uclass_find_device_by_phandle(enum uclass_id id, struct udevice *parent,
|
int uclass_find_device_by_phandle(enum uclass_id id, struct udevice *parent,
|
||||||
const char *name, struct udevice **devp)
|
const char *name, struct udevice **devp)
|
||||||
{
|
{
|
||||||
|
|
|
@ -39,9 +39,7 @@ obj-$(CONFIG_SYS_I2C_RCAR_I2C) += rcar_i2c.o
|
||||||
obj-$(CONFIG_SYS_I2C_RCAR_IIC) += rcar_iic.o
|
obj-$(CONFIG_SYS_I2C_RCAR_IIC) += rcar_iic.o
|
||||||
obj-$(CONFIG_SYS_I2C_ROCKCHIP) += rk_i2c.o
|
obj-$(CONFIG_SYS_I2C_ROCKCHIP) += rk_i2c.o
|
||||||
obj-$(CONFIG_SYS_I2C_S3C24X0) += s3c24x0_i2c.o exynos_hs_i2c.o
|
obj-$(CONFIG_SYS_I2C_S3C24X0) += s3c24x0_i2c.o exynos_hs_i2c.o
|
||||||
ifndef CONFIG_SPL_BUILD
|
|
||||||
obj-$(CONFIG_SYS_I2C_SANDBOX) += sandbox_i2c.o i2c-emul-uclass.o
|
obj-$(CONFIG_SYS_I2C_SANDBOX) += sandbox_i2c.o i2c-emul-uclass.o
|
||||||
endif
|
|
||||||
obj-$(CONFIG_SYS_I2C_SH) += sh_i2c.o
|
obj-$(CONFIG_SYS_I2C_SH) += sh_i2c.o
|
||||||
obj-$(CONFIG_SYS_I2C_SOFT) += soft_i2c.o
|
obj-$(CONFIG_SYS_I2C_SOFT) += soft_i2c.o
|
||||||
obj-$(CONFIG_SYS_I2C_STM32F7) += stm32f7_i2c.o
|
obj-$(CONFIG_SYS_I2C_STM32F7) += stm32f7_i2c.o
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <dm.h>
|
#include <dm.h>
|
||||||
#include <i2c.h>
|
#include <i2c.h>
|
||||||
#include <log.h>
|
#include <log.h>
|
||||||
|
#include <asm/i2c.h>
|
||||||
#include <dm/device-internal.h>
|
#include <dm/device-internal.h>
|
||||||
#include <dm/uclass-internal.h>
|
#include <dm/uclass-internal.h>
|
||||||
|
|
||||||
|
@ -23,18 +24,6 @@
|
||||||
* uclass so avoid having strange devices on the I2C bus.
|
* uclass so avoid having strange devices on the I2C bus.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
|
||||||
* struct i2c_emul_uc_plat - information about the emulator for this device
|
|
||||||
*
|
|
||||||
* This is used by devices in UCLASS_I2C_EMUL to record information about the
|
|
||||||
* device being emulated. It is accessible with dev_get_uclass_plat()
|
|
||||||
*
|
|
||||||
* @dev: Device being emulated
|
|
||||||
*/
|
|
||||||
struct i2c_emul_uc_plat {
|
|
||||||
struct udevice *dev;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct udevice *i2c_emul_get_device(struct udevice *emul)
|
struct udevice *i2c_emul_get_device(struct udevice *emul)
|
||||||
{
|
{
|
||||||
struct i2c_emul_uc_plat *uc_plat = dev_get_uclass_plat(emul);
|
struct i2c_emul_uc_plat *uc_plat = dev_get_uclass_plat(emul);
|
||||||
|
@ -42,14 +31,27 @@ struct udevice *i2c_emul_get_device(struct udevice *emul)
|
||||||
return uc_plat->dev;
|
return uc_plat->dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void i2c_emul_set_idx(struct udevice *dev, int emul_idx)
|
||||||
|
{
|
||||||
|
struct dm_i2c_chip *plat = dev_get_parent_plat(dev);
|
||||||
|
|
||||||
|
plat->emul_idx = emul_idx;
|
||||||
|
}
|
||||||
|
|
||||||
int i2c_emul_find(struct udevice *dev, struct udevice **emulp)
|
int i2c_emul_find(struct udevice *dev, struct udevice **emulp)
|
||||||
{
|
{
|
||||||
struct i2c_emul_uc_plat *uc_plat;
|
struct i2c_emul_uc_plat *uc_plat;
|
||||||
struct udevice *emul;
|
struct udevice *emul;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (!CONFIG_IS_ENABLED(OF_PLATDATA)) {
|
||||||
ret = uclass_find_device_by_phandle(UCLASS_I2C_EMUL, dev,
|
ret = uclass_find_device_by_phandle(UCLASS_I2C_EMUL, dev,
|
||||||
"sandbox,emul", &emul);
|
"sandbox,emul", &emul);
|
||||||
|
} else {
|
||||||
|
struct dm_i2c_chip *plat = dev_get_parent_plat(dev);
|
||||||
|
|
||||||
|
ret = device_get_by_ofplat_idx(plat->emul_idx, &emul);
|
||||||
|
}
|
||||||
if (ret) {
|
if (ret) {
|
||||||
log_err("No emulators for device '%s'\n", dev->name);
|
log_err("No emulators for device '%s'\n", dev->name);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -85,8 +87,8 @@ static const struct udevice_id i2c_emul_parent_ids[] = {
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
U_BOOT_DRIVER(i2c_emul_parent_drv) = {
|
U_BOOT_DRIVER(sandbox_i2c_emul_parent) = {
|
||||||
.name = "i2c_emul_parent_drv",
|
.name = "sandbox_i2c_emul_parent",
|
||||||
.id = UCLASS_I2C_EMUL_PARENT,
|
.id = UCLASS_I2C_EMUL_PARENT,
|
||||||
.of_match = i2c_emul_parent_ids,
|
.of_match = i2c_emul_parent_ids,
|
||||||
};
|
};
|
||||||
|
|
|
@ -69,7 +69,7 @@ int irq_get_by_driver_info(struct udevice *dev,
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = device_get_by_driver_info_idx(cells->idx, &irq->dev);
|
ret = device_get_by_ofplat_idx(cells->idx, &irq->dev);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
irq->id = cells->arg[0];
|
irq->id = cells->arg[0];
|
||||||
|
|
|
@ -86,7 +86,7 @@ static const struct udevice_id testbus_ids[] = {
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
U_BOOT_DRIVER(testbus_drv) = {
|
U_BOOT_DRIVER(denx_u_boot_test_bus) = {
|
||||||
.name = "testbus_drv",
|
.name = "testbus_drv",
|
||||||
.of_match = testbus_ids,
|
.of_match = testbus_ids,
|
||||||
.id = UCLASS_TEST_BUS,
|
.id = UCLASS_TEST_BUS,
|
||||||
|
@ -98,6 +98,7 @@ U_BOOT_DRIVER(testbus_drv) = {
|
||||||
.per_child_plat_auto = sizeof(struct dm_test_parent_plat),
|
.per_child_plat_auto = sizeof(struct dm_test_parent_plat),
|
||||||
.child_pre_probe = testbus_child_pre_probe,
|
.child_pre_probe = testbus_child_pre_probe,
|
||||||
.child_post_remove = testbus_child_post_remove,
|
.child_post_remove = testbus_child_post_remove,
|
||||||
|
DM_HEADER(<test.h>)
|
||||||
};
|
};
|
||||||
|
|
||||||
UCLASS_DRIVER(testbus) = {
|
UCLASS_DRIVER(testbus) = {
|
||||||
|
@ -106,6 +107,9 @@ UCLASS_DRIVER(testbus) = {
|
||||||
.flags = DM_UC_FLAG_SEQ_ALIAS,
|
.flags = DM_UC_FLAG_SEQ_ALIAS,
|
||||||
.child_pre_probe = testbus_child_pre_probe_uclass,
|
.child_pre_probe = testbus_child_pre_probe_uclass,
|
||||||
.child_post_probe = testbus_child_post_probe_uclass,
|
.child_post_probe = testbus_child_post_probe_uclass,
|
||||||
|
|
||||||
|
/* This is for dtoc testing only */
|
||||||
|
.per_device_plat_auto = sizeof(struct dm_test_uclass_priv),
|
||||||
};
|
};
|
||||||
|
|
||||||
static int testfdt_drv_ping(struct udevice *dev, int pingval, int *pingret)
|
static int testfdt_drv_ping(struct udevice *dev, int pingval, int *pingret)
|
||||||
|
@ -160,7 +164,9 @@ static const struct udevice_id testfdt_ids[] = {
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
U_BOOT_DRIVER(testfdt_drv) = {
|
DM_DRIVER_ALIAS(denx_u_boot_fdt_test, google_another_fdt_test)
|
||||||
|
|
||||||
|
U_BOOT_DRIVER(denx_u_boot_fdt_test) = {
|
||||||
.name = "testfdt_drv",
|
.name = "testfdt_drv",
|
||||||
.of_match = testfdt_ids,
|
.of_match = testfdt_ids,
|
||||||
.id = UCLASS_TEST_FDT,
|
.id = UCLASS_TEST_FDT,
|
||||||
|
@ -203,6 +209,7 @@ UCLASS_DRIVER(testfdt) = {
|
||||||
.name = "testfdt",
|
.name = "testfdt",
|
||||||
.id = UCLASS_TEST_FDT,
|
.id = UCLASS_TEST_FDT,
|
||||||
.flags = DM_UC_FLAG_SEQ_ALIAS,
|
.flags = DM_UC_FLAG_SEQ_ALIAS,
|
||||||
|
.priv_auto = sizeof(struct dm_test_uc_priv),
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct udevice_id testfdtm_ids[] = {
|
static const struct udevice_id testfdtm_ids[] = {
|
||||||
|
|
|
@ -311,6 +311,7 @@ config MMC_MXS
|
||||||
|
|
||||||
config MMC_PCI
|
config MMC_PCI
|
||||||
bool "Support for MMC controllers on PCI"
|
bool "Support for MMC controllers on PCI"
|
||||||
|
depends on MMC_SDHCI
|
||||||
help
|
help
|
||||||
This selects PCI-based MMC controllers.
|
This selects PCI-based MMC controllers.
|
||||||
If you have an MMC controller on a PCI bus, say Y here.
|
If you have an MMC controller on a PCI bus, say Y here.
|
||||||
|
|
|
@ -1530,8 +1530,7 @@ static int fsl_esdhc_probe(struct udevice *dev)
|
||||||
if (CONFIG_IS_ENABLED(DM_GPIO) && !priv->non_removable) {
|
if (CONFIG_IS_ENABLED(DM_GPIO) && !priv->non_removable) {
|
||||||
struct udevice *gpiodev;
|
struct udevice *gpiodev;
|
||||||
|
|
||||||
ret = device_get_by_driver_info_idx(dtplat->cd_gpios->idx,
|
ret = device_get_by_ofplat_idx(dtplat->cd_gpios->idx, &gpiodev);
|
||||||
&gpiodev);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
|
|
@ -28,25 +28,6 @@
|
||||||
#define debug_buffer(x, ...)
|
#define debug_buffer(x, ...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
|
||||||
* struct sandbox_i2c_rtc_plat_data - platform data for the RTC
|
|
||||||
*
|
|
||||||
* @base_time: Base system time when RTC device was bound
|
|
||||||
* @offset: RTC offset from current system time
|
|
||||||
* @use_system_time: true to use system time, false to use @base_time
|
|
||||||
* @reg: Register values
|
|
||||||
*/
|
|
||||||
struct sandbox_i2c_rtc_plat_data {
|
|
||||||
long base_time;
|
|
||||||
long offset;
|
|
||||||
bool use_system_time;
|
|
||||||
u8 reg[REG_COUNT];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct sandbox_i2c_rtc {
|
|
||||||
unsigned int offset_secs;
|
|
||||||
};
|
|
||||||
|
|
||||||
long sandbox_i2c_rtc_set_offset(struct udevice *dev, bool use_system_time,
|
long sandbox_i2c_rtc_set_offset(struct udevice *dev, bool use_system_time,
|
||||||
int offset)
|
int offset)
|
||||||
{
|
{
|
||||||
|
@ -223,7 +204,7 @@ static int sandbox_i2c_rtc_bind(struct udevice *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct udevice_id sandbox_i2c_rtc_ids[] = {
|
static const struct udevice_id sandbox_i2c_rtc_ids[] = {
|
||||||
{ .compatible = "sandbox,i2c-rtc" },
|
{ .compatible = "sandbox,i2c-rtc-emul" },
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -79,6 +79,18 @@ struct acpi_ops sandbox_rtc_acpi_ops = {
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static int sandbox_rtc_bind(struct udevice *dev)
|
||||||
|
{
|
||||||
|
#if CONFIG_IS_ENABLED(PLATDATA)
|
||||||
|
struct sandbox_i2c_rtc_plat_data *plat = dev_get_plat(dev);
|
||||||
|
|
||||||
|
/* Set up the emul_idx for i2c_emul_find() */
|
||||||
|
i2c_emul_set_idx(dev, plat->dtplat.sandbox_emul->idx);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct rtc_ops sandbox_rtc_ops = {
|
static const struct rtc_ops sandbox_rtc_ops = {
|
||||||
.get = sandbox_rtc_get,
|
.get = sandbox_rtc_get,
|
||||||
.set = sandbox_rtc_set,
|
.set = sandbox_rtc_set,
|
||||||
|
@ -97,5 +109,6 @@ U_BOOT_DRIVER(sandbox_rtc) = {
|
||||||
.id = UCLASS_RTC,
|
.id = UCLASS_RTC,
|
||||||
.of_match = sandbox_rtc_ids,
|
.of_match = sandbox_rtc_ids,
|
||||||
.ops = &sandbox_rtc_ops,
|
.ops = &sandbox_rtc_ops,
|
||||||
|
.bind = sandbox_rtc_bind,
|
||||||
ACPI_OPS_PTR(&sandbox_rtc_acpi_ops)
|
ACPI_OPS_PTR(&sandbox_rtc_acpi_ops)
|
||||||
};
|
};
|
||||||
|
|
83
dts/Kconfig
83
dts/Kconfig
|
@ -338,6 +338,7 @@ config SPL_OF_PLATDATA
|
||||||
bool "Generate platform data for use in SPL"
|
bool "Generate platform data for use in SPL"
|
||||||
depends on SPL_OF_CONTROL
|
depends on SPL_OF_CONTROL
|
||||||
select DTOC
|
select DTOC
|
||||||
|
select SPL_OF_PLATDATA_DRIVER_RT if !SPL_OF_PLATDATA_INST
|
||||||
help
|
help
|
||||||
For very constrained SPL environments the overhead of decoding
|
For very constrained SPL environments the overhead of decoding
|
||||||
device tree nodes and converting their contents into platform data
|
device tree nodes and converting their contents into platform data
|
||||||
|
@ -355,19 +356,58 @@ config SPL_OF_PLATDATA
|
||||||
compatible string, then adding platform data and U_BOOT_DRVINFO
|
compatible string, then adding platform data and U_BOOT_DRVINFO
|
||||||
declarations for each node. See of-plat.txt for more information.
|
declarations for each node. See of-plat.txt for more information.
|
||||||
|
|
||||||
|
if SPL_OF_PLATDATA
|
||||||
|
|
||||||
config SPL_OF_PLATDATA_PARENT
|
config SPL_OF_PLATDATA_PARENT
|
||||||
bool "Support parent information in devices"
|
bool "Support parent information in devices"
|
||||||
depends on SPL_OF_PLATDATA
|
|
||||||
default y
|
default y
|
||||||
help
|
help
|
||||||
Generally it is useful to be able to access the parent of a device
|
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
|
with of-platdata. To save space this can be disabled, but in that
|
||||||
case dev_get_parent() will always return NULL;
|
case dev_get_parent() will always return NULL;
|
||||||
|
|
||||||
|
config SPL_OF_PLATDATA_INST
|
||||||
|
bool "Declare devices at build time"
|
||||||
|
help
|
||||||
|
Declare devices as udevice instances so that they do not need to be
|
||||||
|
bound when U-Boot starts. This can save time and code space.
|
||||||
|
|
||||||
|
config SPL_OF_PLATDATA_NO_BIND
|
||||||
|
bool "Don't allow run-time binding of devices"
|
||||||
|
depends on SPL_OF_PLATDATA_INST
|
||||||
|
default y
|
||||||
|
help
|
||||||
|
This removes the ability to bind devices at run time, thus saving
|
||||||
|
some code space in U-Boot. This can be disabled if binding is needed,
|
||||||
|
at the code of some code size increase.
|
||||||
|
|
||||||
|
config SPL_OF_PLATDATA_RT
|
||||||
|
bool "Use a separate struct for device runtime data"
|
||||||
|
depends on SPL_OF_PLATDATA_INST
|
||||||
|
default y
|
||||||
|
help
|
||||||
|
For systems running SPL from read-only memory it is convenient to
|
||||||
|
separate out the runtime information, so that the devices don't need
|
||||||
|
to be copied before being used. This moves the read-write parts of
|
||||||
|
struct udevice (at present just the flags) into a separate struct,
|
||||||
|
which is allocated at runtime.
|
||||||
|
|
||||||
|
config SPL_OF_PLATDATA_DRIVER_RT
|
||||||
|
bool
|
||||||
|
help
|
||||||
|
Use a separate struct for driver runtime data.
|
||||||
|
|
||||||
|
This enables the driver_rt information, used with of-platdata when
|
||||||
|
of-platdata-inst is not used. It allows finding devices by their
|
||||||
|
driver data.
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
config TPL_OF_PLATDATA
|
config TPL_OF_PLATDATA
|
||||||
bool "Generate platform data for use in TPL"
|
bool "Generate platform data for use in TPL"
|
||||||
depends on TPL_OF_CONTROL
|
depends on TPL_OF_CONTROL
|
||||||
select DTOC
|
select DTOC
|
||||||
|
select TPL_OF_PLATDATA_DRIVER_RT if !TPL_OF_PLATDATA_INST
|
||||||
help
|
help
|
||||||
For very constrained SPL environments the overhead of decoding
|
For very constrained SPL environments the overhead of decoding
|
||||||
device tree nodes and converting their contents into platform data
|
device tree nodes and converting their contents into platform data
|
||||||
|
@ -385,13 +425,52 @@ config TPL_OF_PLATDATA
|
||||||
compatible string, then adding platform data and U_BOOT_DRVINFO
|
compatible string, then adding platform data and U_BOOT_DRVINFO
|
||||||
declarations for each node. See of-plat.txt for more information.
|
declarations for each node. See of-plat.txt for more information.
|
||||||
|
|
||||||
|
if TPL_OF_PLATDATA
|
||||||
|
|
||||||
config TPL_OF_PLATDATA_PARENT
|
config TPL_OF_PLATDATA_PARENT
|
||||||
bool "Support parent information in devices"
|
bool "Support parent information in devices"
|
||||||
depends on TPL_OF_PLATDATA
|
|
||||||
default y
|
default y
|
||||||
help
|
help
|
||||||
Generally it is useful to be able to access the parent of a device
|
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
|
with of-platdata. To save space this can be disabled, but in that
|
||||||
case dev_get_parent() will always return NULL;
|
case dev_get_parent() will always return NULL;
|
||||||
|
|
||||||
|
config TPL_OF_PLATDATA_INST
|
||||||
|
bool "Declare devices at build time"
|
||||||
|
|
||||||
|
help
|
||||||
|
Declare devices as udevice instances so that they do not need to be
|
||||||
|
bound when U-Boot starts. This can save time and code space.
|
||||||
|
|
||||||
|
config TPL_OF_PLATDATA_NO_BIND
|
||||||
|
bool "Don't allow run-time binding of devices"
|
||||||
|
depends on TPL_OF_PLATDATA_INST
|
||||||
|
default y
|
||||||
|
help
|
||||||
|
This removes the ability to bind devices at run time, thus saving
|
||||||
|
some code space in U-Boot. This can be disabled if binding is needed,
|
||||||
|
at the code of some code size increase.
|
||||||
|
|
||||||
|
config TPL_OF_PLATDATA_RT
|
||||||
|
bool "Use a separate struct for device runtime data"
|
||||||
|
depends on TPL_OF_PLATDATA_INST
|
||||||
|
default y
|
||||||
|
help
|
||||||
|
For systems running TPL from read-only memory it is convenient to
|
||||||
|
separate out the runtime information, so that the devices don't need
|
||||||
|
to be copied before being used. This moves the read-write parts of
|
||||||
|
struct udevice (at present just the flags) into a separate struct,
|
||||||
|
which is allocated at runtime.
|
||||||
|
|
||||||
|
config TPL_OF_PLATDATA_DRIVER_RT
|
||||||
|
bool
|
||||||
|
help
|
||||||
|
Use a separate struct for driver runtime data.
|
||||||
|
|
||||||
|
This enables the driver_rt information, used with of-platdata when
|
||||||
|
of-platdata-inst is not used. It allows finding devices by their
|
||||||
|
driver data.
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
|
@ -215,10 +215,20 @@ struct global_data {
|
||||||
* @uclass_root_s.
|
* @uclass_root_s.
|
||||||
*/
|
*/
|
||||||
struct list_head *uclass_root;
|
struct list_head *uclass_root;
|
||||||
# if CONFIG_IS_ENABLED(OF_PLATDATA)
|
# if CONFIG_IS_ENABLED(OF_PLATDATA_DRIVER_RT)
|
||||||
/** @dm_driver_rt: Dynamic info about the driver */
|
/** @dm_driver_rt: Dynamic info about the driver */
|
||||||
struct driver_rt *dm_driver_rt;
|
struct driver_rt *dm_driver_rt;
|
||||||
# endif
|
# endif
|
||||||
|
#if CONFIG_IS_ENABLED(OF_PLATDATA_RT)
|
||||||
|
/** @dm_udevice_rt: Dynamic info about the udevice */
|
||||||
|
struct udevice_rt *dm_udevice_rt;
|
||||||
|
/**
|
||||||
|
* @dm_priv_base: Base address of the priv/plat region used when
|
||||||
|
* udevices and uclasses are in read-only memory. This is NULL if not
|
||||||
|
* used
|
||||||
|
*/
|
||||||
|
void *dm_priv_base;
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_TIMER
|
#ifdef CONFIG_TIMER
|
||||||
/**
|
/**
|
||||||
|
@ -483,7 +493,7 @@ struct global_data {
|
||||||
#define gd_set_of_root(_root)
|
#define gd_set_of_root(_root)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
#if CONFIG_IS_ENABLED(OF_PLATDATA_DRIVER_RT)
|
||||||
#define gd_set_dm_driver_rt(dyn) gd->dm_driver_rt = dyn
|
#define gd_set_dm_driver_rt(dyn) gd->dm_driver_rt = dyn
|
||||||
#define gd_dm_driver_rt() gd->dm_driver_rt
|
#define gd_dm_driver_rt() gd->dm_driver_rt
|
||||||
#else
|
#else
|
||||||
|
@ -491,6 +501,18 @@ struct global_data {
|
||||||
#define gd_dm_driver_rt() NULL
|
#define gd_dm_driver_rt() NULL
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if CONFIG_IS_ENABLED(OF_PLATDATA_RT)
|
||||||
|
#define gd_set_dm_udevice_rt(dyn) gd->dm_udevice_rt = dyn
|
||||||
|
#define gd_dm_udevice_rt() gd->dm_udevice_rt
|
||||||
|
#define gd_set_dm_priv_base(dyn) gd->dm_priv_base = dyn
|
||||||
|
#define gd_dm_priv_base() gd->dm_priv_base
|
||||||
|
#else
|
||||||
|
#define gd_set_dm_udevice_rt(dyn)
|
||||||
|
#define gd_dm_udevice_rt() NULL
|
||||||
|
#define gd_set_dm_priv_base(dyn)
|
||||||
|
#define gd_dm_priv_base() NULL
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_GENERATE_ACPI_TABLE
|
#ifdef CONFIG_GENERATE_ACPI_TABLE
|
||||||
#define gd_acpi_ctx() gd->acpi_ctx
|
#define gd_acpi_ctx() gd->acpi_ctx
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -28,6 +28,9 @@ extern char __efi_helloworld_end[];
|
||||||
extern char __efi_var_file_begin[];
|
extern char __efi_var_file_begin[];
|
||||||
extern char __efi_var_file_end[];
|
extern char __efi_var_file_end[];
|
||||||
|
|
||||||
|
/* Private data used by of-platdata devices/uclasses */
|
||||||
|
extern char __priv_data_start[], __priv_data_end[];
|
||||||
|
|
||||||
/* Start and end of .ctors section - used for constructor calls. */
|
/* Start and end of .ctors section - used for constructor calls. */
|
||||||
extern char __ctors_start[], __ctors_end[];
|
extern char __ctors_start[], __ctors_end[];
|
||||||
|
|
||||||
|
|
|
@ -10,11 +10,86 @@
|
||||||
#ifndef _DM_DEVICE_INTERNAL_H
|
#ifndef _DM_DEVICE_INTERNAL_H
|
||||||
#define _DM_DEVICE_INTERNAL_H
|
#define _DM_DEVICE_INTERNAL_H
|
||||||
|
|
||||||
|
#include <linker_lists.h>
|
||||||
#include <dm/ofnode.h>
|
#include <dm/ofnode.h>
|
||||||
|
|
||||||
struct device_node;
|
struct device_node;
|
||||||
struct udevice;
|
struct udevice;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* These two macros DM_DEVICE_INST and DM_DEVICE_REF are only allowed in code
|
||||||
|
* generated by dtoc, because the ordering is important and if other instances
|
||||||
|
* creep in then they may mess up the ordering expected by dtoc.
|
||||||
|
*
|
||||||
|
* It is OK to use them with 'extern' though, since that does not actually
|
||||||
|
* add a new record to the linker_list.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DM_DEVICE_INST() - Declare a bound device ready for run-time use
|
||||||
|
*
|
||||||
|
* This adds an actual struct udevice to a list which is found by driver model
|
||||||
|
* on start-up.
|
||||||
|
*
|
||||||
|
* For example:
|
||||||
|
*
|
||||||
|
* extern U_BOOT_DRIVER(sandbox_fixed_clock);
|
||||||
|
* extern DM_UCLASS_INST(clk);
|
||||||
|
*
|
||||||
|
* DM_DEVICE_INST(clk_fixed) = {
|
||||||
|
* .driver = DM_DRIVER_REF(sandbox_fixed_clock),
|
||||||
|
* .name = "sandbox_fixed_clock",
|
||||||
|
* .plat_ = &_sandbox_fixed_clock_plat_clk_fixed,
|
||||||
|
* .uclass = DM_UCLASS_REF(clk),
|
||||||
|
* ...
|
||||||
|
* .seq_ = 0,
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* @_name: Name of the udevice. This must be a valid C identifier, used by the
|
||||||
|
* linker_list.
|
||||||
|
*/
|
||||||
|
#define DM_DEVICE_INST(_name) \
|
||||||
|
ll_entry_declare(struct udevice, _name, udevice)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DM_DEVICE_REF() - Get a reference to a device
|
||||||
|
*
|
||||||
|
* This is useful in data structures and code for referencing a udevice at
|
||||||
|
* build time. Before this is used, an extern DM_DEVICE_INST() must have been
|
||||||
|
* declared.
|
||||||
|
*
|
||||||
|
* For example:
|
||||||
|
*
|
||||||
|
* extern DM_DEVICE_INST(clk_fixed);
|
||||||
|
*
|
||||||
|
* struct udevice *devs[] = {
|
||||||
|
* DM_DEVICE_REF(clk_fixed),
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* @_name: Name of the udevice. This must be a valid C identifier, used by the
|
||||||
|
* linker_list
|
||||||
|
* @returns struct udevice * for the device
|
||||||
|
*/
|
||||||
|
#define DM_DEVICE_REF(_name) \
|
||||||
|
ll_entry_ref(struct udevice, _name, udevice)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DM_DEVICE_GET() - Get a pointer to a given device
|
||||||
|
*
|
||||||
|
* This is similar to DM_DEVICE_REF() except that it does not need the extern
|
||||||
|
* declaration before it. However it cannot be used in a data structures, only
|
||||||
|
* in code within a function.
|
||||||
|
*
|
||||||
|
* For example:
|
||||||
|
*
|
||||||
|
* void some_function() {
|
||||||
|
* struct udevice *dev = DM_DEVICE_GET(clk_fixed);
|
||||||
|
* ...
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
#define DM_DEVICE_GET(__name) \
|
||||||
|
ll_entry_get(struct udevice, __name, udevice)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* device_bind() - Create a device and bind it to a driver
|
* device_bind() - Create a device and bind it to a driver
|
||||||
*
|
*
|
||||||
|
@ -209,6 +284,9 @@ static inline int device_chld_remove(struct udevice *dev, struct driver *drv,
|
||||||
* Use this function to override normal operation for special situations, such
|
* Use this function to override normal operation for special situations, such
|
||||||
* as needing to allocate a variable amount of data.
|
* as needing to allocate a variable amount of data.
|
||||||
*
|
*
|
||||||
|
* If OF_PLATDATA_RT is enabled, this function cannot be used out of core driver
|
||||||
|
* model code, since the pointer must be within the gd->dm_priv_base region.
|
||||||
|
*
|
||||||
* @dev Device to check
|
* @dev Device to check
|
||||||
* @priv New private-data pointer
|
* @priv New private-data pointer
|
||||||
*/
|
*/
|
||||||
|
@ -223,6 +301,9 @@ void dev_set_priv(struct udevice *dev, void *priv);
|
||||||
* Use this function to override normal operation for special situations, such
|
* Use this function to override normal operation for special situations, such
|
||||||
* as needing to allocate a variable amount of data.
|
* as needing to allocate a variable amount of data.
|
||||||
*
|
*
|
||||||
|
* If OF_PLATDATA_RT is enabled, this function cannot be used out of core driver
|
||||||
|
* model code, since the pointer must be within the gd->dm_priv_base region.
|
||||||
|
*
|
||||||
* @dev: Device to update
|
* @dev: Device to update
|
||||||
* @parent_priv: New parent-private data
|
* @parent_priv: New parent-private data
|
||||||
*/
|
*/
|
||||||
|
@ -237,6 +318,9 @@ void dev_set_parent_priv(struct udevice *dev, void *parent_priv);
|
||||||
* Use this function to override normal operation for special situations, such
|
* Use this function to override normal operation for special situations, such
|
||||||
* as needing to allocate a variable amount of data.
|
* as needing to allocate a variable amount of data.
|
||||||
*
|
*
|
||||||
|
* If OF_PLATDATA_RT is enabled, this function cannot be used out of core driver
|
||||||
|
* model code, since the pointer must be within the gd->dm_priv_base region.
|
||||||
|
*
|
||||||
* @dev: Device to update
|
* @dev: Device to update
|
||||||
* @uclass_priv: New uclass private data
|
* @uclass_priv: New uclass private data
|
||||||
*/
|
*/
|
||||||
|
@ -251,6 +335,9 @@ void dev_set_uclass_priv(struct udevice *dev, void *uclass_priv);
|
||||||
* Use this function to override normal operation for special situations, such
|
* Use this function to override normal operation for special situations, such
|
||||||
* as needing to allocate a variable amount of data.
|
* as needing to allocate a variable amount of data.
|
||||||
*
|
*
|
||||||
|
* If OF_PLATDATA_RT is enabled, this function cannot be used out of core driver
|
||||||
|
* model code, since the pointer must be within the gd->dm_priv_base region.
|
||||||
|
*
|
||||||
* @dev Device to check
|
* @dev Device to check
|
||||||
* @plat New platform-data pointer
|
* @plat New platform-data pointer
|
||||||
*/
|
*/
|
||||||
|
@ -265,6 +352,9 @@ void dev_set_plat(struct udevice *dev, void *priv);
|
||||||
* Use this function to override normal operation for special situations, such
|
* Use this function to override normal operation for special situations, such
|
||||||
* as needing to allocate a variable amount of data.
|
* as needing to allocate a variable amount of data.
|
||||||
*
|
*
|
||||||
|
* If OF_PLATDATA_RT is enabled, this function cannot be used out of core driver
|
||||||
|
* model code, since the pointer must be within the gd->dm_priv_base region.
|
||||||
|
*
|
||||||
* @dev: Device to update
|
* @dev: Device to update
|
||||||
* @parent_plat: New parent platform data
|
* @parent_plat: New parent platform data
|
||||||
*/
|
*/
|
||||||
|
@ -279,6 +369,9 @@ void dev_set_parent_plat(struct udevice *dev, void *parent_plat);
|
||||||
* Use this function to override normal operation for special situations, such
|
* Use this function to override normal operation for special situations, such
|
||||||
* as needing to allocate a variable amount of data.
|
* as needing to allocate a variable amount of data.
|
||||||
*
|
*
|
||||||
|
* If OF_PLATDATA_RT is enabled, this function cannot be used out of core driver
|
||||||
|
* model code, since the pointer must be within the gd->dm_priv_base region.
|
||||||
|
*
|
||||||
* @dev: Device to update
|
* @dev: Device to update
|
||||||
* @uclass_plat: New uclass platform data
|
* @uclass_plat: New uclass platform data
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -177,7 +177,9 @@ struct udevice {
|
||||||
struct list_head uclass_node;
|
struct list_head uclass_node;
|
||||||
struct list_head child_head;
|
struct list_head child_head;
|
||||||
struct list_head sibling_node;
|
struct list_head sibling_node;
|
||||||
|
#if !CONFIG_IS_ENABLED(OF_PLATDATA_RT)
|
||||||
u32 flags_;
|
u32 flags_;
|
||||||
|
#endif
|
||||||
int seq_;
|
int seq_;
|
||||||
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
|
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||||
ofnode node_;
|
ofnode node_;
|
||||||
|
@ -190,12 +192,32 @@ struct udevice {
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* udevice_rt - runtime information set up by U-Boot
|
||||||
|
*
|
||||||
|
* This is only used with OF_PLATDATA_RT
|
||||||
|
*
|
||||||
|
* There is one of these for every udevice in the linker list, indexed by
|
||||||
|
* the udevice_info idx value.
|
||||||
|
*
|
||||||
|
* @flags_: Flags for this device DM_FLAG_... (do not access outside driver
|
||||||
|
* model)
|
||||||
|
*/
|
||||||
|
struct udevice_rt {
|
||||||
|
u32 flags_;
|
||||||
|
};
|
||||||
|
|
||||||
/* Maximum sequence number supported */
|
/* Maximum sequence number supported */
|
||||||
#define DM_MAX_SEQ 999
|
#define DM_MAX_SEQ 999
|
||||||
|
|
||||||
/* Returns the operations for a device */
|
/* Returns the operations for a device */
|
||||||
#define device_get_ops(dev) (dev->driver->ops)
|
#define device_get_ops(dev) (dev->driver->ops)
|
||||||
|
|
||||||
|
#if CONFIG_IS_ENABLED(OF_PLATDATA_RT)
|
||||||
|
u32 dev_get_flags(const struct udevice *dev);
|
||||||
|
void dev_or_flags(const struct udevice *dev, u32 or);
|
||||||
|
void dev_bic_flags(const struct udevice *dev, u32 bic);
|
||||||
|
#else
|
||||||
static inline u32 dev_get_flags(const struct udevice *dev)
|
static inline u32 dev_get_flags(const struct udevice *dev)
|
||||||
{
|
{
|
||||||
return dev->flags_;
|
return dev->flags_;
|
||||||
|
@ -210,6 +232,7 @@ static inline void dev_bic_flags(struct udevice *dev, u32 bic)
|
||||||
{
|
{
|
||||||
dev->flags_ &= ~bic;
|
dev->flags_ &= ~bic;
|
||||||
}
|
}
|
||||||
|
#endif /* OF_PLATDATA_RT */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* dev_ofnode() - get the DT node reference associated with a udevice
|
* dev_ofnode() - get the DT node reference associated with a udevice
|
||||||
|
@ -362,6 +385,28 @@ struct driver {
|
||||||
#define DM_DRIVER_GET(__name) \
|
#define DM_DRIVER_GET(__name) \
|
||||||
ll_entry_get(struct driver, __name, driver)
|
ll_entry_get(struct driver, __name, driver)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DM_DRIVER_REF() - Get a reference to a driver
|
||||||
|
*
|
||||||
|
* This is useful in data structures and code for referencing a driver at
|
||||||
|
* build time. Before this is used, an extern U_BOOT_DRIVER() must have been
|
||||||
|
* declared.
|
||||||
|
*
|
||||||
|
* For example:
|
||||||
|
*
|
||||||
|
* extern U_BOOT_DRIVER(sandbox_fixed_clock);
|
||||||
|
*
|
||||||
|
* struct driver *drvs[] = {
|
||||||
|
* DM_DRIVER_REF(sandbox_fixed_clock),
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* @_name: Name of the driver. This must be a valid C identifier, used by the
|
||||||
|
* linker_list
|
||||||
|
* @returns struct driver * for the driver
|
||||||
|
*/
|
||||||
|
#define DM_DRIVER_REF(_name) \
|
||||||
|
ll_entry_ref(struct driver, _name, driver)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Declare a macro to state a alias for a driver name. This macro will
|
* Declare a macro to state a alias for a driver name. This macro will
|
||||||
* produce no code but its information will be parsed by tools like
|
* produce no code but its information will be parsed by tools like
|
||||||
|
@ -369,6 +414,40 @@ struct driver {
|
||||||
*/
|
*/
|
||||||
#define DM_DRIVER_ALIAS(__name, __alias)
|
#define DM_DRIVER_ALIAS(__name, __alias)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Declare a macro to indicate which phase of U-Boot this driver is fore.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* This macro produces no code but its information will be parsed by dtoc. The
|
||||||
|
* macro can be only be used once in a driver. Put it within the U_BOOT_DRIVER()
|
||||||
|
* declaration, e.g.:
|
||||||
|
*
|
||||||
|
* U_BOOT_DRIVER(cpu) = {
|
||||||
|
* .name = ...
|
||||||
|
* ...
|
||||||
|
* DM_PHASE(tpl)
|
||||||
|
* };
|
||||||
|
*/
|
||||||
|
#define DM_PHASE(_phase)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Declare a macro to declare a header needed for a driver. Often the correct
|
||||||
|
* header can be found automatically, but only for struct declarations. For
|
||||||
|
* enums and #defines used in the driver declaration and declared in a different
|
||||||
|
* header from the structs, this macro must be used.
|
||||||
|
*
|
||||||
|
* This macro produces no code but its information will be parsed by dtoc. The
|
||||||
|
* macro can be used multiple times with different headers, for the same driver.
|
||||||
|
* Put it within the U_BOOT_DRIVER() declaration, e.g.:
|
||||||
|
*
|
||||||
|
* U_BOOT_DRIVER(cpu) = {
|
||||||
|
* .name = ...
|
||||||
|
* ...
|
||||||
|
* DM_HEADER(<asm/cpu.h>)
|
||||||
|
* };
|
||||||
|
*/
|
||||||
|
#define DM_HEADER(_hdr)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* dev_get_plat() - Get the platform data for a device
|
* dev_get_plat() - Get the platform data for a device
|
||||||
*
|
*
|
||||||
|
@ -611,33 +690,24 @@ int device_find_global_by_ofnode(ofnode node, struct udevice **devp);
|
||||||
int device_get_global_by_ofnode(ofnode node, struct udevice **devp);
|
int device_get_global_by_ofnode(ofnode node, struct udevice **devp);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* device_get_by_driver_info() - Get a device based on driver_info
|
* device_get_by_ofplat_idx() - Get a device based on of-platdata index
|
||||||
*
|
*
|
||||||
* Locates a device by its struct driver_info, by using its reference which
|
* Locates a device by either its struct driver_info index, or its
|
||||||
* is updated during the bind process.
|
* struct udevice index. The latter is used with OF_PLATDATA_INST, since we have
|
||||||
|
* a list of build-time instantiated struct udevice records, The former is used
|
||||||
|
* with !OF_PLATDATA_INST since in that case we have a list of
|
||||||
|
* struct driver_info records.
|
||||||
|
*
|
||||||
|
* The index number is written into the idx field of struct phandle_1_arg, etc.
|
||||||
|
* It is the position of this driver_info/udevice in its linker list.
|
||||||
*
|
*
|
||||||
* The device is probed to activate it ready for use.
|
* The device is probed to activate it ready for use.
|
||||||
*
|
*
|
||||||
* @info: Struct driver_info
|
* @idx: Index number of the driver_info/udevice structure (0=first)
|
||||||
* @devp: Returns pointer to device if found, otherwise this is set to NULL
|
* @devp: Returns pointer to device if found, otherwise this is set to NULL
|
||||||
* @return 0 if OK, -ve on error
|
* @return 0 if OK, -ve on error
|
||||||
*/
|
*/
|
||||||
int device_get_by_driver_info(const struct driver_info *info,
|
int device_get_by_ofplat_idx(uint idx, struct udevice **devp);
|
||||||
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
|
* device_find_first_child() - Find the first child of a device
|
||||||
|
|
|
@ -71,19 +71,4 @@ struct driver_rt {
|
||||||
#define U_BOOT_DRVINFOS(__name) \
|
#define U_BOOT_DRVINFOS(__name) \
|
||||||
ll_entry_declare_list(struct driver_info, __name, driver_info)
|
ll_entry_declare_list(struct driver_info, __name, driver_info)
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a pointer to a given device info given its name
|
|
||||||
*
|
|
||||||
* With the declaration U_BOOT_DRVINFO(name), DM_DRVINFO_GET(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.
|
|
||||||
*
|
|
||||||
* @__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_DRVINFO_GET(__name) \
|
|
||||||
ll_entry_get(struct driver_info, __name, driver_info)
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -11,6 +11,9 @@
|
||||||
|
|
||||||
struct udevice;
|
struct udevice;
|
||||||
|
|
||||||
|
/* Head of the uclass list if CONFIG_OF_PLATDATA_INST is enabled */
|
||||||
|
extern struct list_head uclass_head;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* dm_root() - Return pointer to the top of the driver tree
|
* dm_root() - Return pointer to the top of the driver tree
|
||||||
*
|
*
|
||||||
|
|
|
@ -71,6 +71,11 @@ struct dm_test_priv {
|
||||||
int uclass_postp;
|
int uclass_postp;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* struct dm_test_uc_priv - private data for the testdrv uclass */
|
||||||
|
struct dm_test_uc_priv {
|
||||||
|
int dummy;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct dm_test_perdev_class_priv - private per-device data for test uclass
|
* struct dm_test_perdev_class_priv - private per-device data for test uclass
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -11,6 +11,55 @@
|
||||||
|
|
||||||
#include <dm/ofnode.h>
|
#include <dm/ofnode.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* These next two macros DM_UCLASS_INST() and DM_UCLASS_REF() are only allowed
|
||||||
|
* in code generated by dtoc, because the ordering is important and if other
|
||||||
|
* instances creep in then they may mess up the ordering expected by dtoc.
|
||||||
|
*
|
||||||
|
* It is OK to use them with 'extern' though, since that does not actually
|
||||||
|
* add a new record to the linker_list.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DM_UCLASS_INST() - Declare a uclass ready for run-time use
|
||||||
|
*
|
||||||
|
* This adds an actual struct uclass to a list which is found by driver model
|
||||||
|
* on start-up.
|
||||||
|
*
|
||||||
|
* For example:
|
||||||
|
*
|
||||||
|
* DM_UCLASS_INST(clk) = {
|
||||||
|
* .uc_drv = DM_UCLASS_DRIVER_REF(clk),
|
||||||
|
* ...
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* @_name: Name of the uclass. This must be a valid C identifier, used by the
|
||||||
|
* linker_list.
|
||||||
|
*/
|
||||||
|
#define DM_UCLASS_INST(_name) \
|
||||||
|
ll_entry_declare(struct uclass, _name, uclass)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DM_UCLASS_REF() - Get a reference to a uclass
|
||||||
|
*
|
||||||
|
* This is useful for referencing a uclass at build time. Before this is used,
|
||||||
|
* an extern DM_UCLASS_INST() must have been declared.
|
||||||
|
*
|
||||||
|
* For example:
|
||||||
|
*
|
||||||
|
* extern DM_UCLASS_INST(clk);
|
||||||
|
*
|
||||||
|
* struct uclass *ucs[] = {
|
||||||
|
* DM_UCLASS_REF(clk),
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @_name: Name of the uclass. This must be a valid C identifier, used by the
|
||||||
|
* linker_list
|
||||||
|
* @returns struct uclass * for the device
|
||||||
|
*/
|
||||||
|
#define DM_UCLASS_REF(_name) \
|
||||||
|
ll_entry_ref(struct uclass, _name, uclass)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* uclass_set_priv() - Set the private data for a uclass
|
* uclass_set_priv() - Set the private data for a uclass
|
||||||
*
|
*
|
||||||
|
@ -20,6 +69,9 @@
|
||||||
* Use this function to override normal operation for special situations, such
|
* Use this function to override normal operation for special situations, such
|
||||||
* as needing to allocate a variable amount of data.
|
* as needing to allocate a variable amount of data.
|
||||||
*
|
*
|
||||||
|
* If OF_PLATDATA_RT is enabled, this function cannot be used out of core driver
|
||||||
|
* model code, since the pointer must be within the gd->dm_priv_base region.
|
||||||
|
*
|
||||||
* @uc Uclass to update
|
* @uc Uclass to update
|
||||||
* @priv New private-data pointer
|
* @priv New private-data pointer
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -114,6 +114,37 @@ struct uclass_driver {
|
||||||
#define UCLASS_DRIVER(__name) \
|
#define UCLASS_DRIVER(__name) \
|
||||||
ll_entry_declare(struct uclass_driver, __name, uclass_driver)
|
ll_entry_declare(struct uclass_driver, __name, uclass_driver)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* These two macros DM_UCLASS_DRIVER_REF and DM_UCLASS_DRIVER_REF are only
|
||||||
|
* allowed in code generated by dtoc, because the ordering is important and if
|
||||||
|
* other instances creep in then they may mess up the ordering expected by dtoc.
|
||||||
|
*
|
||||||
|
* It is OK to use them with 'extern' though, since that does not actually
|
||||||
|
* add a new record to the linker_list.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DM_UCLASS_DRIVER_REF() - Get a reference to a uclass driver
|
||||||
|
*
|
||||||
|
* This is useful in data structures and code for referencing a uclass_driver at
|
||||||
|
* build time. Before this is used, an extern UCLASS_DRIVER() must have been
|
||||||
|
* declared.
|
||||||
|
*
|
||||||
|
* For example:
|
||||||
|
*
|
||||||
|
* extern UCLASS_DRIVER(clk);
|
||||||
|
*
|
||||||
|
* struct uclass_driver *drvs[] = {
|
||||||
|
* DM_UCLASS_DRIVER_REF(clk),
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* @_name: Name of the uclass_driver. This must be a valid C identifier, used by
|
||||||
|
* the linker_list.
|
||||||
|
* @returns struct uclass_driver * for the uclass driver
|
||||||
|
*/
|
||||||
|
#define DM_UCLASS_DRIVER_REF(_name) \
|
||||||
|
ll_entry_ref(struct uclass_driver, _name, uclass_driver)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* uclass_get_priv() - Get the private data for a uclass
|
* uclass_get_priv() - Get the private data for a uclass
|
||||||
*
|
*
|
||||||
|
|
|
@ -49,3 +49,12 @@ void dm_dump_driver_compat(void);
|
||||||
void dm_dump_static_driver_info(void);
|
void dm_dump_static_driver_info(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if CONFIG_IS_ENABLED(OF_PLATDATA_INST) && CONFIG_IS_ENABLED(READ_ONLY)
|
||||||
|
void *dm_priv_to_rw(void *priv);
|
||||||
|
#else
|
||||||
|
static inline void *dm_priv_to_rw(void *priv)
|
||||||
|
{
|
||||||
|
return priv;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -24,7 +24,9 @@ struct phandle_2_arg {
|
||||||
uint idx;
|
uint idx;
|
||||||
int arg[2];
|
int arg[2];
|
||||||
};
|
};
|
||||||
|
|
||||||
#include <generated/dt-structs-gen.h>
|
#include <generated/dt-structs-gen.h>
|
||||||
|
#include <generated/dt-decl.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -93,6 +93,8 @@ struct udevice;
|
||||||
* datasheet explains it's usage of this addressing
|
* datasheet explains it's usage of this addressing
|
||||||
* mode.
|
* mode.
|
||||||
* @emul: Emulator for this chip address (only used for emulation)
|
* @emul: Emulator for this chip address (only used for emulation)
|
||||||
|
* @emul_idx: Emulator index, used for of-platdata and set by each i2c chip's
|
||||||
|
* bind() method. This allows i2c_emul_find() to work with of-platdata.
|
||||||
*/
|
*/
|
||||||
struct dm_i2c_chip {
|
struct dm_i2c_chip {
|
||||||
uint chip_addr;
|
uint chip_addr;
|
||||||
|
@ -102,6 +104,7 @@ struct dm_i2c_chip {
|
||||||
#ifdef CONFIG_SANDBOX
|
#ifdef CONFIG_SANDBOX
|
||||||
struct udevice *emul;
|
struct udevice *emul;
|
||||||
bool test_mode;
|
bool test_mode;
|
||||||
|
int emul_idx;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -554,6 +557,18 @@ void i2c_dump_msgs(struct i2c_msg *msg, int nmsgs);
|
||||||
*/
|
*/
|
||||||
int i2c_emul_find(struct udevice *dev, struct udevice **emulp);
|
int i2c_emul_find(struct udevice *dev, struct udevice **emulp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* i2c_emul_set_idx() - Set the emulator index for an i2c sandbox device
|
||||||
|
*
|
||||||
|
* With of-platdata we cannot find the emulator using the device tree, so rely
|
||||||
|
* on the bind() method of each i2c driver calling this function to tell us
|
||||||
|
* the of-platdata idx of the emulator
|
||||||
|
*
|
||||||
|
* @dev: i2c device to set the emulator for
|
||||||
|
* @emul_idx: of-platdata index for that emulator
|
||||||
|
*/
|
||||||
|
void i2c_emul_set_idx(struct udevice *dev, int emul_idx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* i2c_emul_get_device() - Find the device being emulated
|
* i2c_emul_get_device() - Find the device being emulated
|
||||||
*
|
*
|
||||||
|
|
|
@ -211,6 +211,18 @@
|
||||||
_ll_result; \
|
_ll_result; \
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ll_entry_ref() - Get a reference to a linker-generated array entry
|
||||||
|
*
|
||||||
|
* Once an extern ll_entry_declare() has been used to declare the reference,
|
||||||
|
* this macro allows the entry to be accessed.
|
||||||
|
*
|
||||||
|
* This is like ll_entry_get(), but without the extra code, so it is suitable
|
||||||
|
* for putting into data structures.
|
||||||
|
*/
|
||||||
|
#define ll_entry_ref(_type, _name, _list) \
|
||||||
|
((_type *)&_u_boot_list_2_##_list##_2_##_name)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ll_start() - Point to first entry of first linker-generated array
|
* ll_start() - Point to first entry of first linker-generated array
|
||||||
* @_type: Data type of the entry
|
* @_type: Data type of the entry
|
||||||
|
|
|
@ -192,6 +192,8 @@ struct clk_fixed_factor {
|
||||||
unsigned int div;
|
unsigned int div;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern const struct clk_ops clk_fixed_rate_ops;
|
||||||
|
|
||||||
#define to_clk_fixed_factor(_clk) container_of(_clk, struct clk_fixed_factor,\
|
#define to_clk_fixed_factor(_clk) container_of(_clk, struct clk_fixed_factor,\
|
||||||
clk)
|
clk)
|
||||||
|
|
||||||
|
@ -202,6 +204,9 @@ struct clk_fixed_rate {
|
||||||
|
|
||||||
#define to_clk_fixed_rate(dev) ((struct clk_fixed_rate *)dev_get_plat(dev))
|
#define to_clk_fixed_rate(dev) ((struct clk_fixed_rate *)dev_get_plat(dev))
|
||||||
|
|
||||||
|
void clk_fixed_rate_ofdata_to_plat_(struct udevice *dev,
|
||||||
|
struct clk_fixed_rate *plat);
|
||||||
|
|
||||||
struct clk_composite {
|
struct clk_composite {
|
||||||
struct clk clk;
|
struct clk clk;
|
||||||
struct clk_ops ops;
|
struct clk_ops ops;
|
||||||
|
|
|
@ -120,10 +120,25 @@ endif
|
||||||
u-boot-spl-init := $(head-y)
|
u-boot-spl-init := $(head-y)
|
||||||
u-boot-spl-main := $(libs-y)
|
u-boot-spl-main := $(libs-y)
|
||||||
ifdef CONFIG_$(SPL_TPL_)OF_PLATDATA
|
ifdef CONFIG_$(SPL_TPL_)OF_PLATDATA
|
||||||
u-boot-spl-platdata := $(obj)/dts/dt-plat.o
|
platdata-hdr := include/generated/dt-structs-gen.h include/generated/dt-decl.h
|
||||||
u-boot-spl-platdata_c := $(patsubst %.o,%.c,$(u-boot-spl-platdata))
|
platdata-inst := $(obj)/dts/dt-uclass.o $(obj)/dts/dt-device.o
|
||||||
|
platdata-noinst := $(obj)/dts/dt-plat.o
|
||||||
|
|
||||||
|
ifdef CONFIG_$(SPL_TPL_)OF_PLATDATA_INST
|
||||||
|
u-boot-spl-platdata := $(platdata-inst)
|
||||||
|
u-boot-spl-old-platdata := $(platdata-noinst)
|
||||||
|
else
|
||||||
|
u-boot-spl-platdata := $(platdata-noinst)
|
||||||
|
u-boot-spl-old-platdata := $(platdata-inst)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
# Files we need to generate
|
||||||
|
u-boot-spl-platdata_c := $(patsubst %.o,%.c,$(u-boot-spl-platdata))
|
||||||
|
|
||||||
|
# Files we won't generate and should remove
|
||||||
|
u-boot-spl-old-platdata_c := $(patsubst %.o,%.c,$(u-boot-spl-old-platdata))
|
||||||
|
endif # OF_PLATDATA
|
||||||
|
|
||||||
# Linker Script
|
# Linker Script
|
||||||
# First test whether there's a linker-script for the specific stage defined...
|
# First test whether there's a linker-script for the specific stage defined...
|
||||||
ifneq ($(CONFIG_$(SPL_TPL_)LDSCRIPT),)
|
ifneq ($(CONFIG_$(SPL_TPL_)LDSCRIPT),)
|
||||||
|
@ -311,7 +326,11 @@ $(obj)/$(SPL_BIN).dtb: $(obj)/dts/dt-$(SPL_NAME).dtb FORCE
|
||||||
pythonpath = PYTHONPATH=scripts/dtc/pylibfdt
|
pythonpath = PYTHONPATH=scripts/dtc/pylibfdt
|
||||||
|
|
||||||
DTOC_ARGS := $(pythonpath) $(srctree)/tools/dtoc/dtoc \
|
DTOC_ARGS := $(pythonpath) $(srctree)/tools/dtoc/dtoc \
|
||||||
-d $(obj)/$(SPL_BIN).dtb
|
-d $(obj)/$(SPL_BIN).dtb -p $(SPL_NAME)
|
||||||
|
|
||||||
|
ifneq ($(CONFIG_$(SPL_TPL_)OF_PLATDATA_INST),)
|
||||||
|
DTOC_ARGS += -i
|
||||||
|
endif
|
||||||
|
|
||||||
quiet_cmd_dtoc = DTOC $@
|
quiet_cmd_dtoc = DTOC $@
|
||||||
cmd_dtoc = $(DTOC_ARGS) -c $(obj)/dts -C include/generated all
|
cmd_dtoc = $(DTOC_ARGS) -c $(obj)/dts -C include/generated all
|
||||||
|
@ -319,18 +338,17 @@ cmd_dtoc = $(DTOC_ARGS) -c $(obj)/dts -C include/generated all
|
||||||
quiet_cmd_plat = PLAT $@
|
quiet_cmd_plat = PLAT $@
|
||||||
cmd_plat = $(CC) $(c_flags) -c $< -o $(filter-out $(PHONY),$@)
|
cmd_plat = $(CC) $(c_flags) -c $< -o $(filter-out $(PHONY),$@)
|
||||||
|
|
||||||
targets += $(u-boot-spl-platdata)
|
$(obj)/dts/dt-%.o: $(obj)/dts/dt-%.c $(platdata-hdr)
|
||||||
|
|
||||||
$(obj)/dts/dt-%.o: $(obj)/dts/dt-%.c \
|
|
||||||
include/generated/dt-structs-gen.h prepare FORCE
|
|
||||||
$(call if_changed,plat)
|
$(call if_changed,plat)
|
||||||
|
|
||||||
PHONY += dts_dir
|
# Don't use dts_dir here, since it forces running this expensive rule every time
|
||||||
dts_dir:
|
$(platdata-hdr) $(u-boot-spl-platdata_c) &: $(obj)/$(SPL_BIN).dtb
|
||||||
$(shell [ -d $(obj)/dts ] || mkdir -p $(obj)/dts)
|
@[ -d $(obj)/dts ] || mkdir -p $(obj)/dts
|
||||||
|
@# Remove old files since which ones we generate depends on the setting
|
||||||
include/generated/dt-structs-gen.h $(u-boot-spl-platdata_c) &: \
|
@# of OF_PLATDATA_INST and this might change between builds. Leaving old
|
||||||
$(obj)/$(SPL_BIN).dtb dts_dir FORCE
|
@# ones around is confusing and it is possible that switching the
|
||||||
|
@# setting again will use the old one instead of regenerating it.
|
||||||
|
@rm -f $(u-boot-spl-all-platdata_c) $(u-boot-spl-all-platdata)
|
||||||
$(call if_changed,dtoc)
|
$(call if_changed,dtoc)
|
||||||
|
|
||||||
ifdef CONFIG_SAMSUNG
|
ifdef CONFIG_SAMSUNG
|
||||||
|
@ -471,6 +489,10 @@ FORCE:
|
||||||
$(obj)/dts/dt-$(SPL_NAME).dtb: dts/dt.dtb
|
$(obj)/dts/dt-$(SPL_NAME).dtb: dts/dt.dtb
|
||||||
$(Q)$(MAKE) $(build)=$(obj)/dts spl_dtbs
|
$(Q)$(MAKE) $(build)=$(obj)/dts spl_dtbs
|
||||||
|
|
||||||
|
PHONY += dts_dir
|
||||||
|
dts_dir:
|
||||||
|
$(shell [ -d $(obj)/dts ] || mkdir -p $(obj)/dts)
|
||||||
|
|
||||||
# Declare the contents of the .PHONY variable as phony. We keep that
|
# Declare the contents of the .PHONY variable as phony. We keep that
|
||||||
# information in a variable so we can use it in if_changed and friends.
|
# information in a variable so we can use it in if_changed and friends.
|
||||||
.PHONY: $(PHONY)
|
.PHONY: $(PHONY)
|
||||||
|
|
|
@ -23,12 +23,18 @@ quiet_cmd_pymod = PYMOD $@
|
||||||
SWIG_OPTS="-I$(LIBFDT_srcdir) -I$(LIBFDT_srcdir)/.." \
|
SWIG_OPTS="-I$(LIBFDT_srcdir) -I$(LIBFDT_srcdir)/.." \
|
||||||
$(PYTHON3) $< --quiet build_ext --inplace
|
$(PYTHON3) $< --quiet build_ext --inplace
|
||||||
|
|
||||||
$(obj)/_libfdt.so: $(src)/setup.py $(PYLIBFDT_srcs) FORCE
|
rebuild: $(src)/setup.py $(PYLIBFDT_srcs)
|
||||||
@# Remove the library since otherwise Python doesn't seem to regenerate
|
@# Remove the library since otherwise Python doesn't seem to regenerate
|
||||||
@# the libfdt.py file if it is missing.
|
@# the libfdt.py file if it is missing.
|
||||||
rm -f $(obj)/_libfdt*.so
|
@rm -f $(obj)/_libfdt*.so
|
||||||
$(call if_changed,pymod)
|
$(call if_changed,pymod)
|
||||||
|
@# Rename the file to _libfdt.so so this Makefile doesn't run every time
|
||||||
|
@if [ ! -e $(obj)/_libfdt.so ]; then \
|
||||||
|
mv $(obj)/_libfdt*.so $(obj)/_libfdt.so; \
|
||||||
|
fi
|
||||||
|
|
||||||
always += _libfdt.so
|
$(obj)/_libfdt.so $(obj)/libfdt.py &: rebuild
|
||||||
|
|
||||||
|
always += _libfdt.so libfdt.py
|
||||||
|
|
||||||
clean-files += libfdt.i _libfdt.so libfdt.py libfdt_wrap.c
|
clean-files += libfdt.i _libfdt.so libfdt.py libfdt_wrap.c
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
#define BUF_SIZE 0x100
|
#define BUF_SIZE 0x100
|
||||||
|
|
||||||
/* Declare a new mem test */
|
/* Declare a new setexpr test */
|
||||||
#define SETEXPR_TEST(_name, _flags) UNIT_TEST(_name, _flags, setexpr_test)
|
#define SETEXPR_TEST(_name, _flags) UNIT_TEST(_name, _flags, setexpr_test)
|
||||||
|
|
||||||
/* Test 'setexpr' command with simply setting integers */
|
/* Test 'setexpr' command with simply setting integers */
|
||||||
|
|
|
@ -142,12 +142,14 @@ static int find_driver_info(struct unit_test_state *uts, struct udevice *parent,
|
||||||
/* Check that every device is recorded in its driver_info struct */
|
/* Check that every device is recorded in its driver_info struct */
|
||||||
static int dm_test_of_plat_dev(struct unit_test_state *uts)
|
static int dm_test_of_plat_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);
|
const int n_ents = ll_entry_count(struct driver_info, driver_info);
|
||||||
bool found[n_ents];
|
bool found[n_ents];
|
||||||
uint i;
|
uint i;
|
||||||
|
|
||||||
|
/* Skip this test if there is no platform data */
|
||||||
|
if (!CONFIG_IS_ENABLED(OF_PLATDATA_DRIVER_RT))
|
||||||
|
return 0;
|
||||||
|
|
||||||
/* Record the indexes that are found */
|
/* Record the indexes that are found */
|
||||||
memset(found, '\0', sizeof(found));
|
memset(found, '\0', sizeof(found));
|
||||||
ut_assertok(find_driver_info(uts, gd->dm_root, found));
|
ut_assertok(find_driver_info(uts, gd->dm_root, found));
|
||||||
|
@ -155,18 +157,16 @@ static int dm_test_of_plat_dev(struct unit_test_state *uts)
|
||||||
/* Make sure that the driver entries without devices have no ->dev */
|
/* Make sure that the driver entries without devices have no ->dev */
|
||||||
for (i = 0; i < n_ents; i++) {
|
for (i = 0; i < n_ents; i++) {
|
||||||
const struct driver_rt *drt = gd_dm_driver_rt() + i;
|
const struct driver_rt *drt = gd_dm_driver_rt() + i;
|
||||||
const struct driver_info *entry = info + i;
|
|
||||||
struct udevice *dev;
|
struct udevice *dev;
|
||||||
|
|
||||||
if (found[i]) {
|
if (found[i]) {
|
||||||
/* Make sure we can find it */
|
/* Make sure we can find it */
|
||||||
ut_assertnonnull(drt->dev);
|
ut_assertnonnull(drt->dev);
|
||||||
ut_assertok(device_get_by_driver_info(entry, &dev));
|
ut_assertok(device_get_by_ofplat_idx(i, &dev));
|
||||||
ut_asserteq_ptr(dev, drt->dev);
|
ut_asserteq_ptr(dev, drt->dev);
|
||||||
} else {
|
} else {
|
||||||
ut_assertnull(drt->dev);
|
ut_assertnull(drt->dev);
|
||||||
ut_asserteq(-ENOENT,
|
ut_asserteq(-ENOENT, device_get_by_ofplat_idx(i, &dev));
|
||||||
device_get_by_driver_info(entry, &dev));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,22 +184,22 @@ static int dm_test_of_plat_phandle(struct unit_test_state *uts)
|
||||||
ut_asserteq_str("sandbox_clk_test", dev->name);
|
ut_asserteq_str("sandbox_clk_test", dev->name);
|
||||||
plat = dev_get_plat(dev);
|
plat = dev_get_plat(dev);
|
||||||
|
|
||||||
ut_assertok(device_get_by_driver_info_idx(plat->clocks[0].idx, &clk));
|
ut_assertok(device_get_by_ofplat_idx(plat->clocks[0].idx, &clk));
|
||||||
ut_asserteq_str("fixed_clock", clk->name);
|
ut_asserteq_str("sandbox_fixed_clock", clk->name);
|
||||||
|
|
||||||
ut_assertok(device_get_by_driver_info_idx(plat->clocks[1].idx, &clk));
|
ut_assertok(device_get_by_ofplat_idx(plat->clocks[1].idx, &clk));
|
||||||
ut_asserteq_str("sandbox_clk", clk->name);
|
ut_asserteq_str("sandbox_clk", clk->name);
|
||||||
ut_asserteq(1, plat->clocks[1].arg[0]);
|
ut_asserteq(1, plat->clocks[1].arg[0]);
|
||||||
|
|
||||||
ut_assertok(device_get_by_driver_info_idx(plat->clocks[2].idx, &clk));
|
ut_assertok(device_get_by_ofplat_idx(plat->clocks[2].idx, &clk));
|
||||||
ut_asserteq_str("sandbox_clk", clk->name);
|
ut_asserteq_str("sandbox_clk", clk->name);
|
||||||
ut_asserteq(0, plat->clocks[2].arg[0]);
|
ut_asserteq(0, plat->clocks[2].arg[0]);
|
||||||
|
|
||||||
ut_assertok(device_get_by_driver_info_idx(plat->clocks[3].idx, &clk));
|
ut_assertok(device_get_by_ofplat_idx(plat->clocks[3].idx, &clk));
|
||||||
ut_asserteq_str("sandbox_clk", clk->name);
|
ut_asserteq_str("sandbox_clk", clk->name);
|
||||||
ut_asserteq(3, plat->clocks[3].arg[0]);
|
ut_asserteq(3, plat->clocks[3].arg[0]);
|
||||||
|
|
||||||
ut_assertok(device_get_by_driver_info_idx(plat->clocks[4].idx, &clk));
|
ut_assertok(device_get_by_ofplat_idx(plat->clocks[4].idx, &clk));
|
||||||
ut_asserteq_str("sandbox_clk", clk->name);
|
ut_asserteq_str("sandbox_clk", clk->name);
|
||||||
ut_asserteq(2, plat->clocks[4].arg[0]);
|
ut_asserteq(2, plat->clocks[4].arg[0]);
|
||||||
|
|
||||||
|
@ -211,11 +211,11 @@ DM_TEST(dm_test_of_plat_phandle, UT_TESTF_SCAN_PDATA);
|
||||||
/* Test that device parents are correctly set up */
|
/* Test that device parents are correctly set up */
|
||||||
static int dm_test_of_plat_parent(struct unit_test_state *uts)
|
static int dm_test_of_plat_parent(struct unit_test_state *uts)
|
||||||
{
|
{
|
||||||
struct udevice *dev, *bus;
|
struct udevice *rtc, *i2c;
|
||||||
|
|
||||||
ut_assertok(uclass_first_device_err(UCLASS_SIMPLE_BUS, &bus));
|
ut_assertok(uclass_first_device_err(UCLASS_RTC, &rtc));
|
||||||
ut_assertok(device_first_child_err(bus, &dev));
|
ut_assertok(uclass_first_device_err(UCLASS_I2C, &i2c));
|
||||||
ut_asserteq_ptr(bus, dev_get_parent(dev));
|
ut_asserteq_ptr(i2c, dev_get_parent(rtc));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -330,7 +330,7 @@ static int dm_test_fdt_uclass_seq_more(struct unit_test_state *uts)
|
||||||
|
|
||||||
/* Check creating a device with an alias */
|
/* Check creating a device with an alias */
|
||||||
node = ofnode_path("/some-bus/c-test@1");
|
node = ofnode_path("/some-bus/c-test@1");
|
||||||
ut_assertok(device_bind(dm_root(), DM_DRIVER_GET(testfdt_drv),
|
ut_assertok(device_bind(dm_root(), DM_DRIVER_GET(denx_u_boot_fdt_test),
|
||||||
"c-test@1", NULL, node, &dev));
|
"c-test@1", NULL, node, &dev));
|
||||||
ut_asserteq(12, dev_seq(dev));
|
ut_asserteq(12, dev_seq(dev));
|
||||||
ut_assertok(uclass_get_device_by_seq(UCLASS_TEST_FDT, 12, &dev));
|
ut_assertok(uclass_get_device_by_seq(UCLASS_TEST_FDT, 12, &dev));
|
||||||
|
@ -350,11 +350,11 @@ static int dm_test_fdt_uclass_seq_more(struct unit_test_state *uts)
|
||||||
*
|
*
|
||||||
* So next available is 19
|
* So next available is 19
|
||||||
*/
|
*/
|
||||||
ut_assertok(device_bind(dm_root(), DM_DRIVER_GET(testfdt_drv),
|
ut_assertok(device_bind(dm_root(), DM_DRIVER_GET(denx_u_boot_fdt_test),
|
||||||
"fred", NULL, ofnode_null(), &dev));
|
"fred", NULL, ofnode_null(), &dev));
|
||||||
ut_asserteq(19, dev_seq(dev));
|
ut_asserteq(19, dev_seq(dev));
|
||||||
|
|
||||||
ut_assertok(device_bind(dm_root(), DM_DRIVER_GET(testfdt_drv),
|
ut_assertok(device_bind(dm_root(), DM_DRIVER_GET(denx_u_boot_fdt_test),
|
||||||
"fred2", NULL, ofnode_null(), &dev));
|
"fred2", NULL, ofnode_null(), &dev));
|
||||||
ut_asserteq(20, dev_seq(dev));
|
ut_asserteq(20, dev_seq(dev));
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
#define DEBUG
|
#define DEBUG
|
||||||
|
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
#if CONFIG_IS_ENABLED(EFI_LOADER) && !defined(API_BUILD)
|
|
||||||
#include <command.h>
|
#include <command.h>
|
||||||
|
#if CONFIG_IS_ENABLED(EFI_LOADER) && !defined(API_BUILD)
|
||||||
#include <efi_api.h>
|
#include <efi_api.h>
|
||||||
#endif
|
#endif
|
||||||
#include <display_options.h>
|
#include <display_options.h>
|
||||||
|
|
4
test/run
4
test/run
|
@ -30,6 +30,10 @@ fi
|
||||||
run_test "sandbox_spl" ./test/py/test.py --bd sandbox_spl --build \
|
run_test "sandbox_spl" ./test/py/test.py --bd sandbox_spl --build \
|
||||||
-k 'test_ofplatdata or test_handoff or test_spl'
|
-k 'test_ofplatdata or test_handoff or test_spl'
|
||||||
|
|
||||||
|
# Run the sane tests with sandbox_noinst (i.e. without OF_PLATDATA_INST)
|
||||||
|
run_test "sandbox_spl" ./test/py/test.py --bd sandbox_noinst --build \
|
||||||
|
-k 'test_ofplatdata or test_handoff or test_spl'
|
||||||
|
|
||||||
if [ -z "$tools_only" ]; then
|
if [ -z "$tools_only" ]; then
|
||||||
# Run tests for the flat-device-tree version of sandbox. This is a special
|
# Run tests for the flat-device-tree version of sandbox. This is a special
|
||||||
# build which does not enable CONFIG_OF_LIVE for the live device tree, so we can
|
# build which does not enable CONFIG_OF_LIVE for the live device tree, so we can
|
||||||
|
|
|
@ -62,18 +62,26 @@ static int dm_test_post_run(struct unit_test_state *uts)
|
||||||
{
|
{
|
||||||
int id;
|
int id;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* With of-platdata-inst the uclasses are created at build time. If we
|
||||||
|
* destroy them we cannot get them back since uclass_add() is not
|
||||||
|
* supported. So skip this.
|
||||||
|
*/
|
||||||
|
if (!CONFIG_IS_ENABLED(OF_PLATDATA_INST)) {
|
||||||
for (id = 0; id < UCLASS_COUNT; id++) {
|
for (id = 0; id < UCLASS_COUNT; id++) {
|
||||||
struct uclass *uc;
|
struct uclass *uc;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the uclass doesn't exist we don't want to create it. So
|
* If the uclass doesn't exist we don't want to create
|
||||||
* check that here before we call uclass_find_device().
|
* it. So check that here before we call
|
||||||
|
* uclass_find_device().
|
||||||
*/
|
*/
|
||||||
uc = uclass_find(id);
|
uc = uclass_find(id);
|
||||||
if (!uc)
|
if (!uc)
|
||||||
continue;
|
continue;
|
||||||
ut_assertok(uclass_destroy(uc));
|
ut_assertok(uclass_destroy(uc));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
1
tools/binman/README.rst
Symbolic link
1
tools/binman/README.rst
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
binman.rst
|
|
@ -1,47 +1,51 @@
|
||||||
# SPDX-License-Identifier: GPL-2.0+
|
.. SPDX-License-Identifier: GPL-2.0+
|
||||||
# Copyright (c) 2016 Google, Inc
|
.. Copyright (c) 2016 Google, Inc
|
||||||
|
|
||||||
Introduction
|
Introduction
|
||||||
------------
|
============
|
||||||
|
|
||||||
Firmware often consists of several components which must be packaged together.
|
Firmware often consists of several components which must be packaged together.
|
||||||
For example, we may have SPL, U-Boot, a device tree and an environment area
|
For example, we may have SPL, U-Boot, a device tree and an environment area
|
||||||
grouped together and placed in MMC flash. When the system starts, it must be
|
grouped together and placed in MMC flash. When the system starts, it must be
|
||||||
able to find these pieces.
|
able to find these pieces.
|
||||||
|
|
||||||
So far U-Boot has not provided a way to handle creating such images in a
|
Building firmware should be separate from packaging it. Many of the complexities
|
||||||
general way. Each SoC does what it needs to build an image, often packing or
|
of modern firmware build systems come from trying to do both at once. With
|
||||||
concatenating images in the U-Boot build system.
|
binman, you build all the pieces that are needed, using whatever assortment of
|
||||||
|
projects and build systems are needed, then use binman to stitch everything
|
||||||
Binman aims to provide a mechanism for building images, from simple
|
together.
|
||||||
SPL + U-Boot combinations, to more complex arrangements with many parts.
|
|
||||||
|
|
||||||
|
|
||||||
What it does
|
What it does
|
||||||
------------
|
------------
|
||||||
|
|
||||||
Binman reads your board's device tree and finds a node which describes the
|
Binman reads your board's device tree and finds a node which describes the
|
||||||
required image layout. It uses this to work out what to place where. The
|
required image layout. It uses this to work out what to place where.
|
||||||
output file normally contains the device tree, so it is in principle possible
|
|
||||||
to read an image and extract its constituent parts.
|
Binman provides a mechanism for building images, from simple SPL + U-Boot
|
||||||
|
combinations, to more complex arrangements with many parts. It also allows
|
||||||
|
users to inspect images, extract and replace binaries within them, repacking if
|
||||||
|
needed.
|
||||||
|
|
||||||
|
|
||||||
Features
|
Features
|
||||||
--------
|
--------
|
||||||
|
|
||||||
So far binman is pretty simple. It supports binary blobs, such as 'u-boot',
|
Apart from basic padding, alignment and positioning features, Binman supports
|
||||||
'spl' and 'fdt'. It supports empty entries (such as setting to 0xff). It can
|
hierarchical images, compression, hashing and dealing with the binary blobs
|
||||||
place entries at a fixed location in the image, or fit them together with
|
which are a sad trend in open-source firmware at present.
|
||||||
suitable padding and alignment. It provides a way to process binaries before
|
|
||||||
they are included, by adding a Python plug-in. The device tree is available
|
|
||||||
to U-Boot at run-time so that the images can be interpreted.
|
|
||||||
|
|
||||||
Binman can update the device tree with the final location of everything when it
|
Executable binaries can access the location of other binaries in an image by
|
||||||
is done. Entry positions can be provided to U-Boot SPL as run-time symbols,
|
using special linker symbols (zero-overhead but somewhat limited) or by reading
|
||||||
avoiding device-tree code overhead.
|
the devicetree description of the image.
|
||||||
|
|
||||||
Binman can also support incorporating filesystems in the image if required.
|
Binman is designed primarily for use with U-Boot and associated binaries such
|
||||||
For example x86 platforms may use CBFS in some cases.
|
as ARM Trusted Firmware, but it is suitable for use with other projects, such
|
||||||
|
as Zephyr. Binman also provides facilities useful in Chromium OS, such as CBFS,
|
||||||
|
vblocks and and the like.
|
||||||
|
|
||||||
|
Binman provides a way to process binaries before they are included, by adding a
|
||||||
|
Python plug-in.
|
||||||
|
|
||||||
Binman is intended for use with U-Boot but is designed to be general enough
|
Binman is intended for use with U-Boot but is designed to be general enough
|
||||||
to be useful in other image-packaging situations.
|
to be useful in other image-packaging situations.
|
||||||
|
@ -50,11 +54,11 @@ to be useful in other image-packaging situations.
|
||||||
Motivation
|
Motivation
|
||||||
----------
|
----------
|
||||||
|
|
||||||
Packaging of firmware is quite a different task from building the various
|
As mentioned above, packaging of firmware is quite a different task from
|
||||||
parts. In many cases the various binaries which go into the image come from
|
building the various parts. In many cases the various binaries which go into
|
||||||
separate build systems. For example, ARM Trusted Firmware is used on ARMv8
|
the image come from separate build systems. For example, ARM Trusted Firmware
|
||||||
devices but is not built in the U-Boot tree. If a Linux kernel is included
|
is used on ARMv8 devices but is not built in the U-Boot tree. If a Linux kernel
|
||||||
in the firmware image, it is built elsewhere.
|
is included in the firmware image, it is built elsewhere.
|
||||||
|
|
||||||
It is of course possible to add more and more build rules to the U-Boot
|
It is of course possible to add more and more build rules to the U-Boot
|
||||||
build system to cover these cases. It can shell out to other Makefiles and
|
build system to cover these cases. It can shell out to other Makefiles and
|
||||||
|
@ -67,6 +71,7 @@ standard format, we can support making valid images for any board without
|
||||||
manual effort, lots of READMEs, etc.
|
manual effort, lots of READMEs, etc.
|
||||||
|
|
||||||
Benefits:
|
Benefits:
|
||||||
|
|
||||||
- Each binary can have its own build system and tool chain without creating
|
- Each binary can have its own build system and tool chain without creating
|
||||||
any dependencies between them
|
any dependencies between them
|
||||||
- Avoids the need for a single-shot build: individual parts can be updated
|
- Avoids the need for a single-shot build: individual parts can be updated
|
||||||
|
@ -136,6 +141,9 @@ the boundaries between building input files (mkimage) and packaging then
|
||||||
into a final image (binman).
|
into a final image (binman).
|
||||||
|
|
||||||
|
|
||||||
|
Using binman
|
||||||
|
============
|
||||||
|
|
||||||
Example use of binman in U-Boot
|
Example use of binman in U-Boot
|
||||||
-------------------------------
|
-------------------------------
|
||||||
|
|
||||||
|
@ -144,13 +152,13 @@ build system.
|
||||||
|
|
||||||
Consider sunxi. It has the following steps:
|
Consider sunxi. It has the following steps:
|
||||||
|
|
||||||
1. It uses a custom mksunxiboot tool to build an SPL image called
|
#. It uses a custom mksunxiboot tool to build an SPL image called
|
||||||
sunxi-spl.bin. This should probably move into mkimage.
|
sunxi-spl.bin. This should probably move into mkimage.
|
||||||
|
|
||||||
2. It uses mkimage to package U-Boot into a legacy image file (so that it can
|
#. It uses mkimage to package U-Boot into a legacy image file (so that it can
|
||||||
hold the load and execution address) called u-boot.img.
|
hold the load and execution address) called u-boot.img.
|
||||||
|
|
||||||
3. It builds a final output image called u-boot-sunxi-with-spl.bin which
|
#. It builds a final output image called u-boot-sunxi-with-spl.bin which
|
||||||
consists of sunxi-spl.bin, some padding and u-boot.img.
|
consists of sunxi-spl.bin, some padding and u-boot.img.
|
||||||
|
|
||||||
Binman is intended to replace the last step. The U-Boot build system builds
|
Binman is intended to replace the last step. The U-Boot build system builds
|
||||||
|
@ -180,12 +188,12 @@ the configuration of the Intel-format descriptor.
|
||||||
Running binman
|
Running binman
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
First install prerequisites, e.g.
|
First install prerequisites, e.g::
|
||||||
|
|
||||||
sudo apt-get install python-pyelftools python3-pyelftools lzma-alone \
|
sudo apt-get install python-pyelftools python3-pyelftools lzma-alone \
|
||||||
liblz4-tool
|
liblz4-tool
|
||||||
|
|
||||||
Type:
|
Type::
|
||||||
|
|
||||||
binman build -b <board_name>
|
binman build -b <board_name>
|
||||||
|
|
||||||
|
@ -193,7 +201,7 @@ to build an image for a board. The board name is the same name used when
|
||||||
configuring U-Boot (e.g. for sandbox_defconfig the board name is 'sandbox').
|
configuring U-Boot (e.g. for sandbox_defconfig the board name is 'sandbox').
|
||||||
Binman assumes that the input files for the build are in ../b/<board_name>.
|
Binman assumes that the input files for the build are in ../b/<board_name>.
|
||||||
|
|
||||||
Or you can specify this explicitly:
|
Or you can specify this explicitly::
|
||||||
|
|
||||||
binman build -I <build_path>
|
binman build -I <build_path>
|
||||||
|
|
||||||
|
@ -211,17 +219,12 @@ Binman has a few other options which you can see by running 'binman -h'.
|
||||||
Enabling binman for a board
|
Enabling binman for a board
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
At present binman is invoked from a rule in the main Makefile. Typically you
|
At present binman is invoked from a rule in the main Makefile. You should be
|
||||||
will have a rule like:
|
able to enable CONFIG_BINMAN to enable this rule.
|
||||||
|
|
||||||
ifneq ($(CONFIG_ARCH_<something>),)
|
The output file is typically named image.bin and is located in the output
|
||||||
u-boot-<your_suffix>.bin: <input_file_1> <input_file_2> checkbinman FORCE
|
directory. If input files are needed to you add these to INPUTS-y either in the
|
||||||
$(call if_changed,binman)
|
main Makefile or in a config.mk file in your arch subdirectory.
|
||||||
endif
|
|
||||||
|
|
||||||
This assumes that u-boot-<your_suffix>.bin is a target, and is the final file
|
|
||||||
that you need to produce. You can make it a target by adding it to INPUTS-y
|
|
||||||
either in the main Makefile or in a config.mk file in your arch subdirectory.
|
|
||||||
|
|
||||||
Once binman is executed it will pick up its instructions from a device-tree
|
Once binman is executed it will pick up its instructions from a device-tree
|
||||||
file, typically <soc>-u-boot.dtsi, where <soc> is your CONFIG_SYS_SOC value.
|
file, typically <soc>-u-boot.dtsi, where <soc> is your CONFIG_SYS_SOC value.
|
||||||
|
@ -229,11 +232,114 @@ You can use other, more specific CONFIG options - see 'Automatic .dtsi
|
||||||
inclusion' below.
|
inclusion' below.
|
||||||
|
|
||||||
|
|
||||||
|
Access to binman entry offsets at run time (symbols)
|
||||||
|
----------------------------------------------------
|
||||||
|
|
||||||
|
Binman assembles images and determines where each entry is placed in the image.
|
||||||
|
This information may be useful to U-Boot at run time. For example, in SPL it
|
||||||
|
is useful to be able to find the location of U-Boot so that it can be executed
|
||||||
|
when SPL is finished.
|
||||||
|
|
||||||
|
Binman allows you to declare symbols in the SPL image which are filled in
|
||||||
|
with their correct values during the build. For example::
|
||||||
|
|
||||||
|
binman_sym_declare(ulong, u_boot_any, image_pos);
|
||||||
|
|
||||||
|
declares a ulong value which will be assigned to the image-pos of any U-Boot
|
||||||
|
image (u-boot.bin, u-boot.img, u-boot-nodtb.bin) that is present in the image.
|
||||||
|
You can access this value with something like::
|
||||||
|
|
||||||
|
ulong u_boot_offset = binman_sym(ulong, u_boot_any, image_pos);
|
||||||
|
|
||||||
|
Thus u_boot_offset will be set to the image-pos of U-Boot in memory, assuming
|
||||||
|
that the whole image has been loaded, or is available in flash. You can then
|
||||||
|
jump to that address to start U-Boot.
|
||||||
|
|
||||||
|
At present this feature is only supported in SPL and TPL. In principle it is
|
||||||
|
possible to fill in such symbols in U-Boot proper, as well, but a future C
|
||||||
|
library is planned for this instead, to read from the device tree.
|
||||||
|
|
||||||
|
As well as image-pos, it is possible to read the size of an entry and its
|
||||||
|
offset (which is the start position of the entry within its parent).
|
||||||
|
|
||||||
|
A small technical note: Binman automatically adds the base address of the image
|
||||||
|
(i.e. __image_copy_start) to the value of the image-pos symbol, so that when the
|
||||||
|
image is loaded to its linked address, the value will be correct and actually
|
||||||
|
point into the image.
|
||||||
|
|
||||||
|
For example, say SPL is at the start of the image and linked to start at address
|
||||||
|
80108000. If U-Boot's image-pos is 0x8000 then binman will write an image-pos
|
||||||
|
for U-Boot of 80110000 into the SPL binary, since it assumes the image is loaded
|
||||||
|
to 80108000, with SPL at 80108000 and U-Boot at 80110000.
|
||||||
|
|
||||||
|
For x86 devices (with the end-at-4gb property) this base address is not added
|
||||||
|
since it is assumed that images are XIP and the offsets already include the
|
||||||
|
address.
|
||||||
|
|
||||||
|
|
||||||
|
Access to binman entry offsets at run time (fdt)
|
||||||
|
------------------------------------------------
|
||||||
|
|
||||||
|
Binman can update the U-Boot FDT to include the final position and size of
|
||||||
|
each entry in the images it processes. The option to enable this is -u and it
|
||||||
|
causes binman to make sure that the 'offset', 'image-pos' and 'size' properties
|
||||||
|
are set correctly for every entry. Since it is not necessary to specify these in
|
||||||
|
the image definition, binman calculates the final values and writes these to
|
||||||
|
the device tree. These can be used by U-Boot at run-time to find the location
|
||||||
|
of each entry.
|
||||||
|
|
||||||
|
Alternatively, an FDT map entry can be used to add a special FDT containing
|
||||||
|
just the information about the image. This is preceded by a magic string so can
|
||||||
|
be located anywhere in the image. An image header (typically at the start or end
|
||||||
|
of the image) can be used to point to the FDT map. See fdtmap and image-header
|
||||||
|
entries for more information.
|
||||||
|
|
||||||
|
|
||||||
|
Map files
|
||||||
|
---------
|
||||||
|
|
||||||
|
The -m option causes binman to output a .map file for each image that it
|
||||||
|
generates. This shows the offset and size of each entry. For example::
|
||||||
|
|
||||||
|
Offset Size Name
|
||||||
|
00000000 00000028 main-section
|
||||||
|
00000000 00000010 section@0
|
||||||
|
00000000 00000004 u-boot
|
||||||
|
00000010 00000010 section@1
|
||||||
|
00000000 00000004 u-boot
|
||||||
|
|
||||||
|
This shows a hierarchical image with two sections, each with a single entry. The
|
||||||
|
offsets of the sections are absolute hex byte offsets within the image. The
|
||||||
|
offsets of the entries are relative to their respective sections. The size of
|
||||||
|
each entry is also shown, in bytes (hex). The indentation shows the entries
|
||||||
|
nested inside their sections.
|
||||||
|
|
||||||
|
|
||||||
|
Passing command-line arguments to entries
|
||||||
|
-----------------------------------------
|
||||||
|
|
||||||
|
Sometimes it is useful to pass binman the value of an entry property from the
|
||||||
|
command line. For example some entries need access to files and it is not
|
||||||
|
always convenient to put these filenames in the image definition (device tree).
|
||||||
|
|
||||||
|
The-a option supports this::
|
||||||
|
|
||||||
|
-a<prop>=<value>
|
||||||
|
|
||||||
|
where::
|
||||||
|
|
||||||
|
<prop> is the property to set
|
||||||
|
<value> is the value to set it to
|
||||||
|
|
||||||
|
Not all properties can be provided this way. Only some entries support it,
|
||||||
|
typically for filenames.
|
||||||
|
|
||||||
|
|
||||||
Image description format
|
Image description format
|
||||||
------------------------
|
========================
|
||||||
|
|
||||||
The binman node is called 'binman'. An example image description is shown
|
The binman node is called 'binman'. An example image description is shown
|
||||||
below:
|
below::
|
||||||
|
|
||||||
binman {
|
binman {
|
||||||
filename = "u-boot-sunxi-with-spl.bin";
|
filename = "u-boot-sunxi-with-spl.bin";
|
||||||
|
@ -414,7 +520,7 @@ multiple-images:
|
||||||
Normally only a single image is generated. To create more than one
|
Normally only a single image is generated. To create more than one
|
||||||
image, put this property in the binman node. For example, this will
|
image, put this property in the binman node. For example, this will
|
||||||
create image1.bin containing u-boot.bin, and image2.bin containing
|
create image1.bin containing u-boot.bin, and image2.bin containing
|
||||||
both spl/u-boot-spl.bin and u-boot.bin:
|
both spl/u-boot-spl.bin and u-boot.bin::
|
||||||
|
|
||||||
binman {
|
binman {
|
||||||
multiple-images;
|
multiple-images;
|
||||||
|
@ -470,7 +576,7 @@ This feature provides a way of creating hierarchical images. For example here
|
||||||
is an example image with two copies of U-Boot. One is read-only (ro), intended
|
is an example image with two copies of U-Boot. One is read-only (ro), intended
|
||||||
to be written only in the factory. Another is read-write (rw), so that it can be
|
to be written only in the factory. Another is read-write (rw), so that it can be
|
||||||
upgraded in the field. The sizes are fixed so that the ro/rw boundary is known
|
upgraded in the field. The sizes are fixed so that the ro/rw boundary is known
|
||||||
and can be programmed:
|
and can be programmed::
|
||||||
|
|
||||||
binman {
|
binman {
|
||||||
section@0 {
|
section@0 {
|
||||||
|
@ -527,20 +633,179 @@ allow-repack:
|
||||||
image description to be stored in the FDT and fdtmap.
|
image description to be stored in the FDT and fdtmap.
|
||||||
|
|
||||||
|
|
||||||
|
Hashing Entries
|
||||||
|
---------------
|
||||||
|
|
||||||
|
It is possible to ask binman to hash the contents of an entry and write that
|
||||||
|
value back to the device-tree node. For example::
|
||||||
|
|
||||||
|
binman {
|
||||||
|
u-boot {
|
||||||
|
hash {
|
||||||
|
algo = "sha256";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
Here, a new 'value' property will be written to the 'hash' node containing
|
||||||
|
the hash of the 'u-boot' entry. Only SHA256 is supported at present. Whole
|
||||||
|
sections can be hased if desired, by adding the 'hash' node to the section.
|
||||||
|
|
||||||
|
The has value can be chcked at runtime by hashing the data actually read and
|
||||||
|
comparing this has to the value in the device tree.
|
||||||
|
|
||||||
|
|
||||||
|
Expanded entries
|
||||||
|
----------------
|
||||||
|
|
||||||
|
Binman automatically replaces 'u-boot' with an expanded version of that, i.e.
|
||||||
|
'u-boot-expanded'. This means that when you write::
|
||||||
|
|
||||||
|
u-boot {
|
||||||
|
};
|
||||||
|
|
||||||
|
you actually get::
|
||||||
|
|
||||||
|
u-boot {
|
||||||
|
type = "u-boot-expanded';
|
||||||
|
};
|
||||||
|
|
||||||
|
which in turn expands to::
|
||||||
|
|
||||||
|
u-boot {
|
||||||
|
type = "section";
|
||||||
|
|
||||||
|
u-boot-nodtb {
|
||||||
|
};
|
||||||
|
|
||||||
|
u-boot-dtb {
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
U-Boot's various phase binaries actually comprise two or three pieces.
|
||||||
|
For example, u-boot.bin has the executable followed by a devicetree.
|
||||||
|
|
||||||
|
With binman we want to be able to update that devicetree with full image
|
||||||
|
information so that it is accessible to the executable. This is tricky
|
||||||
|
if it is not clear where the devicetree starts.
|
||||||
|
|
||||||
|
The above feature ensures that the devicetree is clearly separated from the
|
||||||
|
U-Boot executable and can be updated separately by binman as needed. It can be
|
||||||
|
disabled with the --no-expanded flag if required.
|
||||||
|
|
||||||
|
The same applies for u-boot-spl and u-boot-spl. In those cases, the expansion
|
||||||
|
includes the BSS padding, so for example::
|
||||||
|
|
||||||
|
spl {
|
||||||
|
type = "u-boot-spl"
|
||||||
|
};
|
||||||
|
|
||||||
|
you actually get::
|
||||||
|
|
||||||
|
spl {
|
||||||
|
type = "u-boot-expanded';
|
||||||
|
};
|
||||||
|
|
||||||
|
which in turn expands to::
|
||||||
|
|
||||||
|
spl {
|
||||||
|
type = "section";
|
||||||
|
|
||||||
|
u-boot-spl-nodtb {
|
||||||
|
};
|
||||||
|
|
||||||
|
u-boot-spl-bss-pad {
|
||||||
|
};
|
||||||
|
|
||||||
|
u-boot-spl-dtb {
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
Of course we should not expand SPL if it has no devicetree. Also if the BSS
|
||||||
|
padding is not needed (because BSS is in RAM as with CONFIG_SPL_SEPARATE_BSS),
|
||||||
|
the 'u-boot-spl-bss-pad' subnode should not be created. The use of the expaned
|
||||||
|
entry type is controlled by the UseExpanded() method. In the SPL case it checks
|
||||||
|
the 'spl-dtb' entry arg, which is 'y' or '1' if SPL has a devicetree.
|
||||||
|
|
||||||
|
For the BSS case, a 'spl-bss-pad' entry arg controls whether it is present. All
|
||||||
|
entry args are provided by the U-Boot Makefile.
|
||||||
|
|
||||||
|
|
||||||
|
Compression
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Binman support compression for 'blob' entries (those of type 'blob' and
|
||||||
|
derivatives). To enable this for an entry, add a 'compress' property::
|
||||||
|
|
||||||
|
blob {
|
||||||
|
filename = "datafile";
|
||||||
|
compress = "lz4";
|
||||||
|
};
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
|
||||||
|
Automatic .dtsi inclusion
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
It is sometimes inconvenient to add a 'binman' node to the .dts file for each
|
||||||
|
board. This can be done by using #include to bring in a common file. Another
|
||||||
|
approach supported by the U-Boot build system is to automatically include
|
||||||
|
a common header. You can then put the binman node (and anything else that is
|
||||||
|
specific to U-Boot, such as u-boot,dm-pre-reloc properies) in that header
|
||||||
|
file.
|
||||||
|
|
||||||
|
Binman will search for the following files in arch/<arch>/dts::
|
||||||
|
|
||||||
|
<dts>-u-boot.dtsi where <dts> is the base name of the .dts file
|
||||||
|
<CONFIG_SYS_SOC>-u-boot.dtsi
|
||||||
|
<CONFIG_SYS_CPU>-u-boot.dtsi
|
||||||
|
<CONFIG_SYS_VENDOR>-u-boot.dtsi
|
||||||
|
u-boot.dtsi
|
||||||
|
|
||||||
|
U-Boot will only use the first one that it finds. If you need to include a
|
||||||
|
more general file you can do that from the more specific file using #include.
|
||||||
|
If you are having trouble figuring out what is going on, you can uncomment
|
||||||
|
the 'warning' line in scripts/Makefile.lib to see what it has found::
|
||||||
|
|
||||||
|
# Uncomment for debugging
|
||||||
|
# This shows all the files that were considered and the one that we chose.
|
||||||
|
# u_boot_dtsi_options_debug = $(u_boot_dtsi_options_raw)
|
||||||
|
|
||||||
|
|
||||||
Entry Documentation
|
Entry Documentation
|
||||||
-------------------
|
===================
|
||||||
|
|
||||||
For details on the various entry types supported by binman and how to use them,
|
For details on the various entry types supported by binman and how to use them,
|
||||||
see README.entries. This is generated from the source code using:
|
see entries.rst which is generated from the source code using:
|
||||||
|
|
||||||
binman entry-docs >tools/binman/README.entries
|
binman entry-docs >tools/binman/entries.rst
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
entries
|
||||||
|
|
||||||
|
|
||||||
|
Managing images
|
||||||
|
===============
|
||||||
|
|
||||||
Listing images
|
Listing images
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
It is possible to list the entries in an existing firmware image created by
|
It is possible to list the entries in an existing firmware image created by
|
||||||
binman, provided that there is an 'fdtmap' entry in the image. For example:
|
binman, provided that there is an 'fdtmap' entry in the image. For example::
|
||||||
|
|
||||||
$ binman ls -i image.bin
|
$ binman ls -i image.bin
|
||||||
Name Image-pos Size Entry-type Offset Uncomp-size
|
Name Image-pos Size Entry-type Offset Uncomp-size
|
||||||
|
@ -559,7 +824,7 @@ This shows the hierarchy of the image, the position, size and type of each
|
||||||
entry, the offset of each entry within its parent and the uncompressed size if
|
entry, the offset of each entry within its parent and the uncompressed size if
|
||||||
the entry is compressed.
|
the entry is compressed.
|
||||||
|
|
||||||
It is also possible to list just some files in an image, e.g.
|
It is also possible to list just some files in an image, e.g.::
|
||||||
|
|
||||||
$ binman ls -i image.bin section/cbfs
|
$ binman ls -i image.bin section/cbfs
|
||||||
Name Image-pos Size Entry-type Offset Uncomp-size
|
Name Image-pos Size Entry-type Offset Uncomp-size
|
||||||
|
@ -568,7 +833,7 @@ It is also possible to list just some files in an image, e.g.
|
||||||
u-boot 138 4 u-boot 38
|
u-boot 138 4 u-boot 38
|
||||||
u-boot-dtb 180 108 u-boot-dtb 80 3b5
|
u-boot-dtb 180 108 u-boot-dtb 80 3b5
|
||||||
|
|
||||||
or with wildcards:
|
or with wildcards::
|
||||||
|
|
||||||
$ binman ls -i image.bin "*cb*" "*head*"
|
$ binman ls -i image.bin "*cb*" "*head*"
|
||||||
Name Image-pos Size Entry-type Offset Uncomp-size
|
Name Image-pos Size Entry-type Offset Uncomp-size
|
||||||
|
@ -583,22 +848,22 @@ Extracting files from images
|
||||||
----------------------------
|
----------------------------
|
||||||
|
|
||||||
You can extract files from an existing firmware image created by binman,
|
You can extract files from an existing firmware image created by binman,
|
||||||
provided that there is an 'fdtmap' entry in the image. For example:
|
provided that there is an 'fdtmap' entry in the image. For example::
|
||||||
|
|
||||||
$ binman extract -i image.bin section/cbfs/u-boot
|
$ binman extract -i image.bin section/cbfs/u-boot
|
||||||
|
|
||||||
which will write the uncompressed contents of that entry to the file 'u-boot' in
|
which will write the uncompressed contents of that entry to the file 'u-boot' in
|
||||||
the current directory. You can also extract to a particular file, in this case
|
the current directory. You can also extract to a particular file, in this case
|
||||||
u-boot.bin:
|
u-boot.bin::
|
||||||
|
|
||||||
$ binman extract -i image.bin section/cbfs/u-boot -f u-boot.bin
|
$ binman extract -i image.bin section/cbfs/u-boot -f u-boot.bin
|
||||||
|
|
||||||
It is possible to extract all files into a destination directory, which will
|
It is possible to extract all files into a destination directory, which will
|
||||||
put files in subdirectories matching the entry hierarchy:
|
put files in subdirectories matching the entry hierarchy::
|
||||||
|
|
||||||
$ binman extract -i image.bin -O outdir
|
$ binman extract -i image.bin -O outdir
|
||||||
|
|
||||||
or just a selection:
|
or just a selection::
|
||||||
|
|
||||||
$ binman extract -i image.bin "*u-boot*" -O outdir
|
$ binman extract -i image.bin "*u-boot*" -O outdir
|
||||||
|
|
||||||
|
@ -616,18 +881,18 @@ to the that entry, compressing if necessary. If the entry size changes, you must
|
||||||
add the 'allow-repack' property to the original image before generating it (see
|
add the 'allow-repack' property to the original image before generating it (see
|
||||||
above), otherwise you will get an error.
|
above), otherwise you will get an error.
|
||||||
|
|
||||||
You can also use a particular file, in this case u-boot.bin:
|
You can also use a particular file, in this case u-boot.bin::
|
||||||
|
|
||||||
$ binman replace -i image.bin section/cbfs/u-boot -f u-boot.bin
|
$ binman replace -i image.bin section/cbfs/u-boot -f u-boot.bin
|
||||||
|
|
||||||
It is possible to replace all files from a source directory which uses the same
|
It is possible to replace all files from a source directory which uses the same
|
||||||
hierarchy as the entries:
|
hierarchy as the entries::
|
||||||
|
|
||||||
$ binman replace -i image.bin -I indir
|
$ binman replace -i image.bin -I indir
|
||||||
|
|
||||||
Files that are missing will generate a warning.
|
Files that are missing will generate a warning.
|
||||||
|
|
||||||
You can also replace just a selection of entries:
|
You can also replace just a selection of entries::
|
||||||
|
|
||||||
$ binman replace -i image.bin "*u-boot*" -I indir
|
$ binman replace -i image.bin "*u-boot*" -I indir
|
||||||
|
|
||||||
|
@ -652,27 +917,9 @@ by increasing the -v/--verbosity from the default of 1:
|
||||||
|
|
||||||
You can use BINMAN_VERBOSE=5 (for example) when building to select this.
|
You can use BINMAN_VERBOSE=5 (for example) when building to select this.
|
||||||
|
|
||||||
Hashing Entries
|
|
||||||
---------------
|
|
||||||
|
|
||||||
It is possible to ask binman to hash the contents of an entry and write that
|
|
||||||
value back to the device-tree node. For example:
|
|
||||||
|
|
||||||
binman {
|
|
||||||
u-boot {
|
|
||||||
hash {
|
|
||||||
algo = "sha256";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
Here, a new 'value' property will be written to the 'hash' node containing
|
|
||||||
the hash of the 'u-boot' entry. Only SHA256 is supported at present. Whole
|
|
||||||
sections can be hased if desired, by adding the 'hash' node to the section.
|
|
||||||
|
|
||||||
The has value can be chcked at runtime by hashing the data actually read and
|
|
||||||
comparing this has to the value in the device tree.
|
|
||||||
|
|
||||||
|
Technical details
|
||||||
|
=================
|
||||||
|
|
||||||
Order of image creation
|
Order of image creation
|
||||||
-----------------------
|
-----------------------
|
||||||
|
@ -749,162 +996,6 @@ what happens in this stage.
|
||||||
final step.
|
final step.
|
||||||
|
|
||||||
|
|
||||||
Automatic .dtsi inclusion
|
|
||||||
-------------------------
|
|
||||||
|
|
||||||
It is sometimes inconvenient to add a 'binman' node to the .dts file for each
|
|
||||||
board. This can be done by using #include to bring in a common file. Another
|
|
||||||
approach supported by the U-Boot build system is to automatically include
|
|
||||||
a common header. You can then put the binman node (and anything else that is
|
|
||||||
specific to U-Boot, such as u-boot,dm-pre-reloc properies) in that header
|
|
||||||
file.
|
|
||||||
|
|
||||||
Binman will search for the following files in arch/<arch>/dts:
|
|
||||||
|
|
||||||
<dts>-u-boot.dtsi where <dts> is the base name of the .dts file
|
|
||||||
<CONFIG_SYS_SOC>-u-boot.dtsi
|
|
||||||
<CONFIG_SYS_CPU>-u-boot.dtsi
|
|
||||||
<CONFIG_SYS_VENDOR>-u-boot.dtsi
|
|
||||||
u-boot.dtsi
|
|
||||||
|
|
||||||
U-Boot will only use the first one that it finds. If you need to include a
|
|
||||||
more general file you can do that from the more specific file using #include.
|
|
||||||
If you are having trouble figuring out what is going on, you can uncomment
|
|
||||||
the 'warning' line in scripts/Makefile.lib to see what it has found:
|
|
||||||
|
|
||||||
# Uncomment for debugging
|
|
||||||
# This shows all the files that were considered and the one that we chose.
|
|
||||||
# u_boot_dtsi_options_debug = $(u_boot_dtsi_options_raw)
|
|
||||||
|
|
||||||
|
|
||||||
Access to binman entry offsets at run time (symbols)
|
|
||||||
----------------------------------------------------
|
|
||||||
|
|
||||||
Binman assembles images and determines where each entry is placed in the image.
|
|
||||||
This information may be useful to U-Boot at run time. For example, in SPL it
|
|
||||||
is useful to be able to find the location of U-Boot so that it can be executed
|
|
||||||
when SPL is finished.
|
|
||||||
|
|
||||||
Binman allows you to declare symbols in the SPL image which are filled in
|
|
||||||
with their correct values during the build. For example:
|
|
||||||
|
|
||||||
binman_sym_declare(ulong, u_boot_any, image_pos);
|
|
||||||
|
|
||||||
declares a ulong value which will be assigned to the image-pos of any U-Boot
|
|
||||||
image (u-boot.bin, u-boot.img, u-boot-nodtb.bin) that is present in the image.
|
|
||||||
You can access this value with something like:
|
|
||||||
|
|
||||||
ulong u_boot_offset = binman_sym(ulong, u_boot_any, image_pos);
|
|
||||||
|
|
||||||
Thus u_boot_offset will be set to the image-pos of U-Boot in memory, assuming
|
|
||||||
that the whole image has been loaded, or is available in flash. You can then
|
|
||||||
jump to that address to start U-Boot.
|
|
||||||
|
|
||||||
At present this feature is only supported in SPL and TPL. In principle it is
|
|
||||||
possible to fill in such symbols in U-Boot proper, as well, but a future C
|
|
||||||
library is planned for this instead, to read from the device tree.
|
|
||||||
|
|
||||||
As well as image-pos, it is possible to read the size of an entry and its
|
|
||||||
offset (which is the start position of the entry within its parent).
|
|
||||||
|
|
||||||
A small technical note: Binman automatically adds the base address of the image
|
|
||||||
(i.e. __image_copy_start) to the value of the image-pos symbol, so that when the
|
|
||||||
image is loaded to its linked address, the value will be correct and actually
|
|
||||||
point into the image.
|
|
||||||
|
|
||||||
For example, say SPL is at the start of the image and linked to start at address
|
|
||||||
80108000. If U-Boot's image-pos is 0x8000 then binman will write an image-pos
|
|
||||||
for U-Boot of 80110000 into the SPL binary, since it assumes the image is loaded
|
|
||||||
to 80108000, with SPL at 80108000 and U-Boot at 80110000.
|
|
||||||
|
|
||||||
For x86 devices (with the end-at-4gb property) this base address is not added
|
|
||||||
since it is assumed that images are XIP and the offsets already include the
|
|
||||||
address.
|
|
||||||
|
|
||||||
|
|
||||||
Access to binman entry offsets at run time (fdt)
|
|
||||||
------------------------------------------------
|
|
||||||
|
|
||||||
Binman can update the U-Boot FDT to include the final position and size of
|
|
||||||
each entry in the images it processes. The option to enable this is -u and it
|
|
||||||
causes binman to make sure that the 'offset', 'image-pos' and 'size' properties
|
|
||||||
are set correctly for every entry. Since it is not necessary to specify these in
|
|
||||||
the image definition, binman calculates the final values and writes these to
|
|
||||||
the device tree. These can be used by U-Boot at run-time to find the location
|
|
||||||
of each entry.
|
|
||||||
|
|
||||||
Alternatively, an FDT map entry can be used to add a special FDT containing
|
|
||||||
just the information about the image. This is preceded by a magic string so can
|
|
||||||
be located anywhere in the image. An image header (typically at the start or end
|
|
||||||
of the image) can be used to point to the FDT map. See fdtmap and image-header
|
|
||||||
entries for more information.
|
|
||||||
|
|
||||||
|
|
||||||
Compression
|
|
||||||
-----------
|
|
||||||
|
|
||||||
Binman support compression for 'blob' entries (those of type 'blob' and
|
|
||||||
derivatives). To enable this for an entry, add a 'compress' property:
|
|
||||||
|
|
||||||
blob {
|
|
||||||
filename = "datafile";
|
|
||||||
compress = "lz4";
|
|
||||||
};
|
|
||||||
|
|
||||||
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
|
|
||||||
---------
|
|
||||||
|
|
||||||
The -m option causes binman to output a .map file for each image that it
|
|
||||||
generates. This shows the offset and size of each entry. For example:
|
|
||||||
|
|
||||||
Offset Size Name
|
|
||||||
00000000 00000028 main-section
|
|
||||||
00000000 00000010 section@0
|
|
||||||
00000000 00000004 u-boot
|
|
||||||
00000010 00000010 section@1
|
|
||||||
00000000 00000004 u-boot
|
|
||||||
|
|
||||||
This shows a hierarchical image with two sections, each with a single entry. The
|
|
||||||
offsets of the sections are absolute hex byte offsets within the image. The
|
|
||||||
offsets of the entries are relative to their respective sections. The size of
|
|
||||||
each entry is also shown, in bytes (hex). The indentation shows the entries
|
|
||||||
nested inside their sections.
|
|
||||||
|
|
||||||
|
|
||||||
Passing command-line arguments to entries
|
|
||||||
-----------------------------------------
|
|
||||||
|
|
||||||
Sometimes it is useful to pass binman the value of an entry property from the
|
|
||||||
command line. For example some entries need access to files and it is not
|
|
||||||
always convenient to put these filenames in the image definition (device tree).
|
|
||||||
|
|
||||||
The-a option supports this:
|
|
||||||
|
|
||||||
-a<prop>=<value>
|
|
||||||
|
|
||||||
where
|
|
||||||
|
|
||||||
<prop> is the property to set
|
|
||||||
<value> is the value to set it to
|
|
||||||
|
|
||||||
Not all properties can be provided this way. Only some entries support it,
|
|
||||||
typically for filenames.
|
|
||||||
|
|
||||||
|
|
||||||
External tools
|
External tools
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
|
@ -927,7 +1018,7 @@ Code coverage
|
||||||
Binman is a critical tool and is designed to be very testable. Entry
|
Binman is a critical tool and is designed to be very testable. Entry
|
||||||
implementations target 100% test coverage. Run 'binman test -T' to check this.
|
implementations target 100% test coverage. Run 'binman test -T' to check this.
|
||||||
|
|
||||||
To enable Python test coverage on Debian-type distributions (e.g. Ubuntu):
|
To enable Python test coverage on Debian-type distributions (e.g. Ubuntu)::
|
||||||
|
|
||||||
$ sudo apt-get install python-coverage python3-coverage python-pytest
|
$ sudo apt-get install python-coverage python3-coverage python-pytest
|
||||||
|
|
||||||
|
@ -938,7 +1029,7 @@ Concurrent tests
|
||||||
Binman tries to run tests concurrently. This means that the tests make use of
|
Binman tries to run tests concurrently. This means that the tests make use of
|
||||||
all available CPUs to run.
|
all available CPUs to run.
|
||||||
|
|
||||||
To enable this:
|
To enable this::
|
||||||
|
|
||||||
$ sudo apt-get install python-subunit python3-subunit
|
$ sudo apt-get install python-subunit python3-subunit
|
||||||
|
|
||||||
|
@ -961,19 +1052,19 @@ Binman's tests have been written under the assumption that they'll be run on a
|
||||||
x86-like host and there hasn't been an attempt to make them portable yet.
|
x86-like host and there hasn't been an attempt to make them portable yet.
|
||||||
However, it's possible to run the tests by cross-compiling to x86.
|
However, it's possible to run the tests by cross-compiling to x86.
|
||||||
|
|
||||||
To install an x86 cross-compiler on Debian-type distributions (e.g. Ubuntu):
|
To install an x86 cross-compiler on Debian-type distributions (e.g. Ubuntu)::
|
||||||
|
|
||||||
$ sudo apt-get install gcc-x86-64-linux-gnu
|
$ sudo apt-get install gcc-x86-64-linux-gnu
|
||||||
|
|
||||||
Then, you can run the tests under cross-compilation:
|
Then, you can run the tests under cross-compilation::
|
||||||
|
|
||||||
$ CROSS_COMPILE=x86_64-linux-gnu- binman test -T
|
$ CROSS_COMPILE=x86_64-linux-gnu- binman test -T
|
||||||
|
|
||||||
You can also use gcc-i686-linux-gnu similar to the above.
|
You can also use gcc-i686-linux-gnu similar to the above.
|
||||||
|
|
||||||
|
|
||||||
Advanced Features / Technical docs
|
Writing new entries and debugging
|
||||||
----------------------------------
|
---------------------------------
|
||||||
|
|
||||||
The behaviour of entries is defined by the Entry class. All other entries are
|
The behaviour of entries is defined by the Entry class. All other entries are
|
||||||
a subclass of this. An important subclass is Entry_blob which takes binary
|
a subclass of this. An important subclass is Entry_blob which takes binary
|
||||||
|
@ -1001,13 +1092,13 @@ the DTC environment variable. This can be useful when the system dtc is too
|
||||||
old.
|
old.
|
||||||
|
|
||||||
To enable a full backtrace and other debugging features in binman, pass
|
To enable a full backtrace and other debugging features in binman, pass
|
||||||
BINMAN_DEBUG=1 to your build:
|
BINMAN_DEBUG=1 to your build::
|
||||||
|
|
||||||
make qemu-x86_defconfig
|
make qemu-x86_defconfig
|
||||||
make BINMAN_DEBUG=1
|
make BINMAN_DEBUG=1
|
||||||
|
|
||||||
To enable verbose logging from binman, base BINMAN_VERBOSE to your build, which
|
To enable verbose logging from binman, base BINMAN_VERBOSE to your build, which
|
||||||
adds a -v<level> option to the call to binman:
|
adds a -v<level> option to the call to binman::
|
||||||
|
|
||||||
make qemu-x86_defconfig
|
make qemu-x86_defconfig
|
||||||
make BINMAN_VERBOSE=5
|
make BINMAN_VERBOSE=5
|
||||||
|
@ -1047,8 +1138,10 @@ To do
|
||||||
-----
|
-----
|
||||||
|
|
||||||
Some ideas:
|
Some ideas:
|
||||||
|
|
||||||
- Use of-platdata to make the information available to code that is unable
|
- Use of-platdata to make the information available to code that is unable
|
||||||
to use device tree (such as a very small SPL image)
|
to use device tree (such as a very small SPL image). For now, limited info is
|
||||||
|
available via linker symbols
|
||||||
- Allow easy building of images by specifying just the board name
|
- Allow easy building of images by specifying just the board name
|
||||||
- Support building an image for a board (-b) more completely, with a
|
- Support building an image for a board (-b) more completely, with a
|
||||||
configurable build directory
|
configurable build directory
|
|
@ -56,6 +56,9 @@ controlled by a description in the board device tree.'''
|
||||||
default=False, help='Output a map file for each image')
|
default=False, help='Output a map file for each image')
|
||||||
build_parser.add_argument('-M', '--allow-missing', action='store_true',
|
build_parser.add_argument('-M', '--allow-missing', action='store_true',
|
||||||
default=False, help='Allow external blobs to be missing')
|
default=False, help='Allow external blobs to be missing')
|
||||||
|
build_parser.add_argument('-n', '--no-expanded', action='store_true',
|
||||||
|
help="Don't use 'expanded' versions of entries where available; "
|
||||||
|
"normally 'u-boot' becomes 'u-boot-expanded', for example")
|
||||||
build_parser.add_argument('-O', '--outdir', type=str,
|
build_parser.add_argument('-O', '--outdir', type=str,
|
||||||
action='store', help='Path to directory to use for intermediate and '
|
action='store', help='Path to directory to use for intermediate and '
|
||||||
'output files')
|
'output files')
|
||||||
|
@ -66,7 +69,7 @@ controlled by a description in the board device tree.'''
|
||||||
default=False, help='Update the binman node with offset/size info')
|
default=False, help='Update the binman node with offset/size info')
|
||||||
|
|
||||||
entry_parser = subparsers.add_parser('entry-docs',
|
entry_parser = subparsers.add_parser('entry-docs',
|
||||||
help='Write out entry documentation (see README.entries)')
|
help='Write out entry documentation (see entries.rst)')
|
||||||
|
|
||||||
list_parser = subparsers.add_parser('ls', help='List files in an image')
|
list_parser = subparsers.add_parser('ls', help='List files in an image')
|
||||||
list_parser.add_argument('-i', '--image', type=str, required=True,
|
list_parser.add_argument('-i', '--image', type=str, required=True,
|
||||||
|
|
|
@ -28,7 +28,7 @@ images = OrderedDict()
|
||||||
# value: Text for the help
|
# value: Text for the help
|
||||||
missing_blob_help = {}
|
missing_blob_help = {}
|
||||||
|
|
||||||
def _ReadImageDesc(binman_node):
|
def _ReadImageDesc(binman_node, use_expanded):
|
||||||
"""Read the image descriptions from the /binman node
|
"""Read the image descriptions from the /binman node
|
||||||
|
|
||||||
This normally produces a single Image object called 'image'. But if
|
This normally produces a single Image object called 'image'. But if
|
||||||
|
@ -36,15 +36,17 @@ def _ReadImageDesc(binman_node):
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
binman_node: Node object of the /binman node
|
binman_node: Node object of the /binman node
|
||||||
|
use_expanded: True if the FDT will be updated with the entry information
|
||||||
Returns:
|
Returns:
|
||||||
OrderedDict of Image objects, each of which describes an image
|
OrderedDict of Image objects, each of which describes an image
|
||||||
"""
|
"""
|
||||||
images = OrderedDict()
|
images = OrderedDict()
|
||||||
if 'multiple-images' in binman_node.props:
|
if 'multiple-images' in binman_node.props:
|
||||||
for node in binman_node.subnodes:
|
for node in binman_node.subnodes:
|
||||||
images[node.name] = Image(node.name, node)
|
images[node.name] = Image(node.name, node,
|
||||||
|
use_expanded=use_expanded)
|
||||||
else:
|
else:
|
||||||
images['image'] = Image('image', binman_node)
|
images['image'] = Image('image', binman_node, use_expanded=use_expanded)
|
||||||
return images
|
return images
|
||||||
|
|
||||||
def _FindBinmanNode(dtb):
|
def _FindBinmanNode(dtb):
|
||||||
|
@ -241,7 +243,7 @@ def ExtractEntries(image_fname, output_fname, outdir, entry_paths,
|
||||||
# If this entry has children, create a directory for it and put its
|
# If this entry has children, create a directory for it and put its
|
||||||
# data in a file called 'root' in that directory
|
# data in a file called 'root' in that directory
|
||||||
if entry.GetEntries():
|
if entry.GetEntries():
|
||||||
if not os.path.exists(fname):
|
if fname and not os.path.exists(fname):
|
||||||
os.makedirs(fname)
|
os.makedirs(fname)
|
||||||
fname = os.path.join(fname, 'root')
|
fname = os.path.join(fname, 'root')
|
||||||
tout.Notice("Write entry '%s' size %x to '%s'" %
|
tout.Notice("Write entry '%s' size %x to '%s'" %
|
||||||
|
@ -399,7 +401,7 @@ def ReplaceEntries(image_fname, input_fname, indir, entry_paths,
|
||||||
return image
|
return image
|
||||||
|
|
||||||
|
|
||||||
def PrepareImagesAndDtbs(dtb_fname, select_images, update_fdt):
|
def PrepareImagesAndDtbs(dtb_fname, select_images, update_fdt, use_expanded):
|
||||||
"""Prepare the images to be processed and select the device tree
|
"""Prepare the images to be processed and select the device tree
|
||||||
|
|
||||||
This function:
|
This function:
|
||||||
|
@ -413,6 +415,9 @@ def PrepareImagesAndDtbs(dtb_fname, select_images, update_fdt):
|
||||||
dtb_fname: Filename of the device tree file to use (.dts or .dtb)
|
dtb_fname: Filename of the device tree file to use (.dts or .dtb)
|
||||||
selected_images: List of images to output, or None for all
|
selected_images: List of images to output, or None for all
|
||||||
update_fdt: True to update the FDT wth entry offsets, etc.
|
update_fdt: True to update the FDT wth entry offsets, etc.
|
||||||
|
use_expanded: True to use expanded versions of entries, if available.
|
||||||
|
So if 'u-boot' is called for, we use 'u-boot-expanded' instead. This
|
||||||
|
is needed if update_fdt is True (although tests may disable it)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
OrderedDict of images:
|
OrderedDict of images:
|
||||||
|
@ -438,7 +443,7 @@ def PrepareImagesAndDtbs(dtb_fname, select_images, update_fdt):
|
||||||
raise ValueError("Device tree '%s' does not have a 'binman' "
|
raise ValueError("Device tree '%s' does not have a 'binman' "
|
||||||
"node" % dtb_fname)
|
"node" % dtb_fname)
|
||||||
|
|
||||||
images = _ReadImageDesc(node)
|
images = _ReadImageDesc(node, use_expanded)
|
||||||
|
|
||||||
if select_images:
|
if select_images:
|
||||||
skip = []
|
skip = []
|
||||||
|
@ -564,7 +569,7 @@ def Binman(args):
|
||||||
if not pager:
|
if not pager:
|
||||||
pager = 'more'
|
pager = 'more'
|
||||||
fname = os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])),
|
fname = os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])),
|
||||||
'README')
|
'README.rst')
|
||||||
command.Run(pager, fname)
|
command.Run(pager, fname)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
@ -611,6 +616,13 @@ def Binman(args):
|
||||||
elf.debug = args.debug
|
elf.debug = args.debug
|
||||||
cbfs_util.VERBOSE = args.verbosity > 2
|
cbfs_util.VERBOSE = args.verbosity > 2
|
||||||
state.use_fake_dtb = args.fake_dtb
|
state.use_fake_dtb = args.fake_dtb
|
||||||
|
|
||||||
|
# Normally we replace the 'u-boot' etype with 'u-boot-expanded', etc.
|
||||||
|
# When running tests this can be disabled using this flag. When not
|
||||||
|
# updating the FDT in image, it is not needed by binman, but we use it
|
||||||
|
# for consistency, so that the images look the same to U-Boot at
|
||||||
|
# runtime.
|
||||||
|
use_expanded = not args.no_expanded
|
||||||
try:
|
try:
|
||||||
tools.SetInputDirs(args.indir)
|
tools.SetInputDirs(args.indir)
|
||||||
tools.PrepareOutputDir(args.outdir, args.preserve)
|
tools.PrepareOutputDir(args.outdir, args.preserve)
|
||||||
|
@ -618,7 +630,7 @@ def Binman(args):
|
||||||
state.SetEntryArgs(args.entry_arg)
|
state.SetEntryArgs(args.entry_arg)
|
||||||
|
|
||||||
images = PrepareImagesAndDtbs(dtb_fname, args.image,
|
images = PrepareImagesAndDtbs(dtb_fname, args.image,
|
||||||
args.update_fdt)
|
args.update_fdt, use_expanded)
|
||||||
missing = False
|
missing = False
|
||||||
for image in images.values():
|
for image in images.values():
|
||||||
missing |= ProcessImage(image, args.update_fdt, args.map,
|
missing |= ProcessImage(image, args.update_fdt, args.map,
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue