mirror of
https://github.com/u-boot/u-boot.git
synced 2024-12-04 10:03:41 +08: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
@ -148,7 +148,7 @@ jobs:
|
||||
export UBOOT_TRAVIS_BUILD_DIR=/tmp/sandbox_spl
|
||||
export PYTHONPATH=${UBOOT_TRAVIS_BUILD_DIR}/scripts/dtc/pylibfdt
|
||||
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/buildman/buildman -t
|
||||
./tools/dtoc/dtoc -t
|
||||
@ -187,6 +187,9 @@ jobs:
|
||||
sandbox_spl:
|
||||
TEST_PY_BD: "sandbox_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:
|
||||
TEST_PY_BD: "sandbox_flattree"
|
||||
evb_ast2500:
|
||||
|
@ -168,7 +168,8 @@ Run binman, buildman, dtoc, Kconfig and patman testsuites:
|
||||
export UBOOT_TRAVIS_BUILD_DIR=/tmp/sandbox_spl;
|
||||
export PYTHONPATH="${UBOOT_TRAVIS_BUILD_DIR}/scripts/dtc/pylibfdt";
|
||||
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/buildman/buildman -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"
|
||||
<<: *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:
|
||||
tags: [ 'all' ]
|
||||
variables:
|
||||
|
18
Makefile
18
Makefile
@ -17,9 +17,13 @@ NAME =
|
||||
# o Look for make include files relative to root of kernel src
|
||||
MAKEFLAGS += -rR --include-dir=$(CURDIR)
|
||||
|
||||
# Determine host architecture
|
||||
# Determine target architecture for the sandbox
|
||||
include include/host_arch.h
|
||||
MK_ARCH="${shell uname -m}"
|
||||
ifeq ("", "$(CROSS_COMPILE)")
|
||||
MK_ARCH="${shell uname -m}"
|
||||
else
|
||||
MK_ARCH="${shell echo $(CROSS_COMPILE) | sed -n 's/^\s*\([^\/]*\/\)*\([^-]*\)-\S*/\2/p'}"
|
||||
endif
|
||||
unexport HOST_ARCH
|
||||
ifeq ("x86_64", $(MK_ARCH))
|
||||
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)
|
||||
else ifneq (,$(findstring $(MK_ARCH), "aarch64" "armv8l"))
|
||||
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)
|
||||
else ifeq ("riscv32", $(MK_ARCH))
|
||||
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_VERBOSE=3' to set vebosity level
|
||||
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 $@
|
||||
cmd_binman = $(srctree)/tools/binman/binman $(if $(BINMAN_DEBUG),-D) \
|
||||
--toolpath $(objtree)/tools \
|
||||
@ -1338,6 +1347,9 @@ cmd_binman = $(srctree)/tools/binman/binman $(if $(BINMAN_DEBUG),-D) \
|
||||
-a atf-bl31-path=${BL31} \
|
||||
-a default-dt=$(default_dt) \
|
||||
-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))
|
||||
|
||||
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();
|
||||
|
||||
printf("%s\n", __func__);
|
||||
/* U-Boot will delete ram buffer after read: "--rm_memory"*/
|
||||
state->ram_buf_rm = true;
|
||||
return os_jump_to_file(fname);
|
||||
|
@ -13,6 +13,14 @@ SECTIONS
|
||||
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_getopt : { KEEP(*(.u_boot_sandbox_getopt)) }
|
||||
__u_boot_sandbox_option_end = .;
|
||||
|
@ -31,7 +31,7 @@
|
||||
|
||||
clk_fixed: clk-fixed {
|
||||
u-boot,dm-pre-reloc;
|
||||
compatible = "fixed-clock";
|
||||
compatible = "sandbox,fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <1234>;
|
||||
};
|
||||
@ -101,15 +101,19 @@
|
||||
};
|
||||
|
||||
i2c_emul: emul {
|
||||
u-boot,dm-pre-reloc;
|
||||
reg = <0xff>;
|
||||
compatible = "sandbox,i2c-emul-parent";
|
||||
emul_eeprom: emul-eeprom {
|
||||
compatible = "sandbox,i2c-eeprom";
|
||||
sandbox,filename = "i2c.bin";
|
||||
sandbox,size = <256>;
|
||||
#emul-cells = <0>;
|
||||
};
|
||||
emul0: emul0 {
|
||||
compatible = "sandbox,i2c-rtc";
|
||||
u-boot,dm-pre-reloc;
|
||||
compatible = "sandbox,i2c-rtc-emul";
|
||||
#emul-cells = <0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
@ -260,14 +264,10 @@
|
||||
stringarray = "pre-proper";
|
||||
};
|
||||
|
||||
test-bus {
|
||||
compatible = "simple-bus";
|
||||
spl-test7 {
|
||||
u-boot,dm-spl;
|
||||
spl-test7 {
|
||||
u-boot,dm-spl;
|
||||
compatible = "sandbox,spl-test";
|
||||
stringarray = "spl";
|
||||
};
|
||||
compatible = "sandbox,spl-test";
|
||||
stringarray = "spl";
|
||||
};
|
||||
|
||||
square {
|
||||
|
@ -604,10 +604,10 @@
|
||||
sandbox,size = <256>;
|
||||
};
|
||||
emul0: emul0 {
|
||||
compatible = "sandbox,i2c-rtc";
|
||||
compatible = "sandbox,i2c-rtc-emul";
|
||||
};
|
||||
emul1: emull {
|
||||
compatible = "sandbox,i2c-rtc";
|
||||
compatible = "sandbox,i2c-rtc-emul";
|
||||
};
|
||||
};
|
||||
|
||||
@ -1402,3 +1402,4 @@
|
||||
};
|
||||
|
||||
#include "sandbox_pmic.dtsi"
|
||||
#include "cros-ec-keyboard.dtsi"
|
||||
|
@ -7,6 +7,9 @@
|
||||
#define __SANDBOX_CLK_H
|
||||
|
||||
#include <common.h>
|
||||
#include <clk.h>
|
||||
#include <dt-structs.h>
|
||||
#include <linux/clk-provider.h>
|
||||
|
||||
struct udevice;
|
||||
|
||||
@ -45,6 +48,27 @@ enum sandbox_clk_test_id {
|
||||
|
||||
#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.
|
||||
*
|
||||
|
@ -11,4 +11,19 @@ struct sandbox_i2c_priv {
|
||||
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 */
|
||||
|
@ -9,6 +9,8 @@
|
||||
#ifndef __asm_rtc_h
|
||||
#define __asm_rtc_h
|
||||
|
||||
#include <dt-structs.h>
|
||||
|
||||
/* Register numbers in the sandbox RTC */
|
||||
enum {
|
||||
REG_SEC = 5,
|
||||
@ -29,4 +31,26 @@ enum {
|
||||
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
|
||||
|
@ -21,6 +21,8 @@ config INTEL_APOLLOLAKE
|
||||
select INTEL_GMA_SWSMISCI
|
||||
select ACPI_GNVS_EXTERNAL
|
||||
select TPL_OF_PLATDATA_PARENT
|
||||
select TPL_OF_PLATDATA_INST
|
||||
select TPL_READ_ONLY
|
||||
imply ENABLE_MRC_CACHE
|
||||
imply AHCI_PCI
|
||||
imply SCSI
|
||||
|
@ -9,8 +9,8 @@
|
||||
#define LOG_CATEGORY UCLASS_ACPI_PMC
|
||||
|
||||
#include <common.h>
|
||||
#include <dt-structs.h>
|
||||
#include <dm.h>
|
||||
#include <dt-structs.h>
|
||||
#include <log.h>
|
||||
#include <spl.h>
|
||||
#include <acpi/acpi_s3.h>
|
||||
|
@ -93,4 +93,5 @@ U_BOOT_DRIVER(intel_apl_punit) = {
|
||||
.id = UCLASS_SYSCON,
|
||||
.of_match = apl_syscon_ids,
|
||||
.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)
|
||||
{
|
||||
/* This is not set with of-platdata, so set it manually */
|
||||
if (CONFIG_IS_ENABLED(OF_PLATDATA))
|
||||
/* This is not set with basic of-platdata, so set it manually */
|
||||
if (CONFIG_IS_ENABLED(OF_PLATDATA) &&
|
||||
!CONFIG_IS_ENABLED(OF_PLATDATA_INST))
|
||||
dev->driver_data = X86_IRQT_ITSS;
|
||||
|
||||
return 0;
|
||||
|
@ -32,6 +32,14 @@ SECTIONS
|
||||
. = ALIGN(4);
|
||||
.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);
|
||||
.data : { *(.data*) }
|
||||
|
||||
|
@ -100,7 +100,7 @@
|
||||
clk: clock {
|
||||
compatible = "intel,apl-clk";
|
||||
#clock-cells = <1>;
|
||||
u-boot,dm-pre-reloc;
|
||||
u-boot,dm-pre-proper;
|
||||
};
|
||||
|
||||
cpus {
|
||||
@ -141,7 +141,7 @@
|
||||
};
|
||||
|
||||
acpi_gpe: general-purpose-events {
|
||||
u-boot,dm-pre-reloc;
|
||||
u-boot,dm-pre-proper;
|
||||
reg = <IOMAP_ACPI_BASE IOMAP_ACPI_SIZE>;
|
||||
compatible = "intel,acpi-gpe";
|
||||
interrupt-controller;
|
||||
@ -423,7 +423,7 @@
|
||||
compatible = "intel,apl-i2c", "snps,designware-i2c-pci";
|
||||
reg = <0x0200b210 0 0 0 0>;
|
||||
early-regs = <IOMAP_I2C2_BASE 0x1000>;
|
||||
u-boot,dm-pre-reloc;
|
||||
u-boot,dm-pre-proper;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
clock-frequency = <400000>;
|
||||
@ -434,7 +434,7 @@
|
||||
tpm: tpm@50 {
|
||||
reg = <0x50>;
|
||||
compatible = "google,cr50";
|
||||
u-boot,dm-pre-reloc;
|
||||
u-boot,dm-pre-proper;
|
||||
u-boot,i2c-offset-len = <0>;
|
||||
ready-gpios = <&gpio_n 28 GPIO_ACTIVE_LOW>;
|
||||
interrupts-extended = <&acpi_gpe GPIO_28_IRQ
|
||||
@ -1233,5 +1233,5 @@
|
||||
&rtc {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
u-boot,dm-pre-reloc;
|
||||
u-boot,dm-pre-proper;
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
/ {
|
||||
reset: reset {
|
||||
compatible = "x86,reset";
|
||||
u-boot,dm-pre-reloc;
|
||||
u-boot,dm-pre-proper;
|
||||
};
|
||||
};
|
||||
|
@ -38,20 +38,11 @@
|
||||
};
|
||||
#endif
|
||||
spl {
|
||||
type = "section";
|
||||
type = "u-boot-spl";
|
||||
offset = <CONFIG_X86_OFFSET_SPL>;
|
||||
u-boot-spl {
|
||||
};
|
||||
u-boot-spl-dtb {
|
||||
};
|
||||
};
|
||||
u-boot {
|
||||
type = "section";
|
||||
offset = <CONFIG_X86_OFFSET_U_BOOT>;
|
||||
u-boot-nodtb {
|
||||
};
|
||||
u-boot-dtb {
|
||||
};
|
||||
};
|
||||
#elif defined(CONFIG_SPL)
|
||||
u-boot-spl-with-ucode-ptr {
|
||||
@ -64,11 +55,7 @@
|
||||
offset = <CONFIG_X86_OFFSET_U_BOOT>;
|
||||
};
|
||||
#else
|
||||
# ifdef CONFIG_SPL
|
||||
u-boot {
|
||||
offset = <CONFIG_SYS_TEXT_BASE>;
|
||||
};
|
||||
# elif defined(CONFIG_HAVE_MICROCODE)
|
||||
# ifdef CONFIG_HAVE_MICROCODE
|
||||
/* If there is no SPL then we need to put microcode in U-Boot */
|
||||
u-boot-with-ucode-ptr {
|
||||
offset = <CONFIG_X86_OFFSET_U_BOOT>;
|
||||
|
@ -150,5 +150,6 @@ U_BOOT_DRIVER(pci_x86) = {
|
||||
.name = "pci_x86",
|
||||
.id = UCLASS_SIMPLE_BUS,
|
||||
.of_match = of_match_ptr(tpl_fake_pci_ids),
|
||||
DM_PHASE(tpl)
|
||||
};
|
||||
#endif
|
||||
|
@ -20,6 +20,13 @@ F: board/sandbox/
|
||||
F: include/configs/sandbox_spl.h
|
||||
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
|
||||
M: Simon Glass <sjg@chromium.org>
|
||||
S: Maintained
|
||||
|
@ -48,6 +48,7 @@ unsigned long timer_read_counter(void)
|
||||
static enum env_location env_locations[] = {
|
||||
ENVL_NOWHERE,
|
||||
ENVL_EXT4,
|
||||
ENVL_FAT,
|
||||
};
|
||||
|
||||
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
|
||||
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
|
||||
bool "Enable output of the SPL banner 'U-Boot SPL ...'"
|
||||
default y
|
||||
@ -1440,6 +1453,17 @@ config TPL_STACK
|
||||
The address of the initial stack-pointer for the TPL stage.
|
||||
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
|
||||
bool "Support returning to the BOOTROM (from TPL)"
|
||||
help
|
||||
|
@ -73,6 +73,7 @@ CONFIG_MAC_PARTITION=y
|
||||
CONFIG_ISO_PARTITION=y
|
||||
CONFIG_EFI_PARTITION=y
|
||||
# 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_REGMAP=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_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"
|
||||
@ -87,6 +88,7 @@ CONFIG_OF_CONTROL=y
|
||||
CONFIG_SPL_OF_CONTROL=y
|
||||
CONFIG_OF_HOSTFILE=y
|
||||
CONFIG_SPL_OF_PLATDATA=y
|
||||
CONFIG_SPL_OF_PLATDATA_INST=y
|
||||
CONFIG_ENV_IS_NOWHERE=y
|
||||
CONFIG_ENV_IS_IN_EXT4=y
|
||||
CONFIG_ENV_EXT4_INTERFACE="host"
|
||||
@ -102,6 +104,7 @@ 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
|
||||
|
@ -709,8 +709,8 @@ to load a 'u-boot-payload.efi', see below test logs on QEMU.
|
||||
No controllers found
|
||||
Hit any key to stop autoboot: 0
|
||||
|
||||
See :doc:`../uefi/u-boot_on_efi` and :doc:`../uefi/uefi` for details of
|
||||
EFI support in U-Boot.
|
||||
See :doc:`../develop/uefi/u-boot_on_efi` and :doc:`../develop/uefi/uefi` for
|
||||
details of EFI support in U-Boot.
|
||||
|
||||
Chain-loading
|
||||
-------------
|
||||
|
@ -3,6 +3,10 @@
|
||||
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::
|
||||
: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";
|
||||
emul_1f: emul@1f,0 {
|
||||
compatible = "sandbox,swap-case";
|
||||
#emul-cells = <0>;
|
||||
};
|
||||
};
|
||||
|
@ -10,9 +10,11 @@ Implementation
|
||||
:maxdepth: 1
|
||||
|
||||
commands
|
||||
driver-model/index
|
||||
global_data
|
||||
logging
|
||||
menus
|
||||
uefi/index
|
||||
version
|
||||
|
||||
Debugging
|
||||
@ -24,6 +26,14 @@ Debugging
|
||||
crash_dumps
|
||||
trace
|
||||
|
||||
Packaging
|
||||
---------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
package/index
|
||||
|
||||
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)
|
||||
==================================
|
||||
|
||||
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
|
||||
|
@ -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
|
||||
|
||||
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
|
||||
------------------------
|
||||
|
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
|
||||
|
||||
fdt_overlays
|
||||
fit
|
||||
netconsole
|
||||
partitions
|
||||
|
||||
|
@ -148,12 +148,6 @@ clocks_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) = {
|
||||
.name = "ti_sysc",
|
||||
.id = UCLASS_SIMPLE_BUS,
|
||||
|
@ -39,7 +39,7 @@ int clk_get_by_driver_info(struct udevice *dev, struct phandle_1_arg *cells,
|
||||
{
|
||||
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)
|
||||
return ret;
|
||||
clk->id = cells->arg[0];
|
||||
|
@ -25,18 +25,24 @@ const struct clk_ops clk_fixed_rate_ops = {
|
||||
.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)
|
||||
to_clk_fixed_rate(dev)->fixed_rate =
|
||||
dev_read_u32_default(dev, "clock-frequency", 0);
|
||||
plat->fixed_rate = dev_read_u32_default(dev, "clock-frequency", 0);
|
||||
#endif
|
||||
/* Make fixed rate clock accessible from higher level struct clk */
|
||||
/* FIXME: This is not allowed */
|
||||
dev_set_uclass_priv(dev, clk);
|
||||
|
||||
clk->dev = dev;
|
||||
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;
|
||||
}
|
||||
|
@ -9,13 +9,7 @@
|
||||
#include <errno.h>
|
||||
#include <malloc.h>
|
||||
#include <asm/clk.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];
|
||||
};
|
||||
#include <linux/clk-provider.h>
|
||||
|
||||
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 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 <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[] = {
|
||||
[SANDBOX_CLK_TEST_ID_FIXED] = "fixed",
|
||||
[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;
|
||||
void *ptr;
|
||||
|
||||
if (CONFIG_IS_ENABLED(OF_PLATDATA_NO_BIND))
|
||||
return -ENOSYS;
|
||||
|
||||
if (devp)
|
||||
*devp = NULL;
|
||||
if (!name)
|
||||
@ -395,26 +398,31 @@ int device_of_to_plat(struct udevice *dev)
|
||||
if (dev_get_flags(dev) & DM_FLAG_PLATDATA_VALID)
|
||||
return 0;
|
||||
|
||||
/* Ensure all parents have ofdata */
|
||||
if (dev->parent) {
|
||||
ret = device_of_to_plat(dev->parent);
|
||||
/*
|
||||
* 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 */
|
||||
if (dev->parent) {
|
||||
ret = device_of_to_plat(dev->parent);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
/*
|
||||
* The device might have already been probed during
|
||||
* the call to device_probe() on its parent device
|
||||
* (e.g. PCI bridge devices). Test the flags again
|
||||
* so that we don't mess up the device.
|
||||
*/
|
||||
if (dev_get_flags(dev) & DM_FLAG_PLATDATA_VALID)
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = device_alloc_priv(dev);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
/*
|
||||
* The device might have already been probed during
|
||||
* the call to device_probe() on its parent device
|
||||
* (e.g. PCI bridge devices). Test the flags again
|
||||
* so that we don't mess up the device.
|
||||
*/
|
||||
if (dev_get_flags(dev) & DM_FLAG_PLATDATA_VALID)
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = device_alloc_priv(dev);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
drv = dev->driver;
|
||||
assert(drv);
|
||||
|
||||
@ -592,7 +600,7 @@ void *dev_get_plat(const struct udevice *dev)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return dev->plat_;
|
||||
return dm_priv_to_rw(dev->plat_);
|
||||
}
|
||||
|
||||
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 dev->parent_plat_;
|
||||
return dm_priv_to_rw(dev->parent_plat_);
|
||||
}
|
||||
|
||||
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 dev->uclass_plat_;
|
||||
return dm_priv_to_rw(dev->uclass_plat_);
|
||||
}
|
||||
|
||||
void *dev_get_priv(const struct udevice *dev)
|
||||
@ -622,7 +630,7 @@ void *dev_get_priv(const struct udevice *dev)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return dev->priv_;
|
||||
return dm_priv_to_rw(dev->priv_);
|
||||
}
|
||||
|
||||
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 dev->uclass_priv_;
|
||||
return dm_priv_to_rw(dev->uclass_priv_);
|
||||
}
|
||||
|
||||
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 dev->parent_priv_;
|
||||
return dm_priv_to_rw(dev->parent_priv_);
|
||||
}
|
||||
|
||||
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)
|
||||
int device_get_by_driver_info(const struct driver_info *info,
|
||||
struct udevice **devp)
|
||||
int device_get_by_ofplat_idx(uint idx, struct udevice **devp)
|
||||
{
|
||||
struct driver_info *info_base =
|
||||
ll_entry_start(struct driver_info, driver_info);
|
||||
int idx = info - info_base;
|
||||
struct driver_rt *drt = gd_dm_driver_rt() + idx;
|
||||
struct udevice *dev;
|
||||
|
||||
dev = drt->dev;
|
||||
*devp = NULL;
|
||||
if (CONFIG_IS_ENABLED(OF_PLATDATA_INST)) {
|
||||
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;
|
||||
|
||||
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;
|
||||
dev = drt->dev;
|
||||
}
|
||||
*devp = NULL;
|
||||
|
||||
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);
|
||||
}
|
||||
#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);
|
||||
if (!OF_CHECK_COUNTS(na, ns)) {
|
||||
printf("Bad cell count for %s\n", of_node_full_name(dev));
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
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);
|
||||
if (!OF_CHECK_COUNTS(pna, pns)) {
|
||||
printf("Bad cell count for %s\n", of_node_full_name(parent));
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto out_parent;
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <fdtdec.h>
|
||||
#include <log.h>
|
||||
#include <malloc.h>
|
||||
#include <asm-generic/sections.h>
|
||||
#include <asm/global_data.h>
|
||||
#include <linux/libfdt.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 ret;
|
||||
@ -140,8 +171,12 @@ int dm_init(bool of_live)
|
||||
dm_warn("Virtual root driver already exists!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
gd->uclass_root = &DM_UCLASS_ROOT_S_NON_CONST;
|
||||
INIT_LIST_HEAD(DM_UCLASS_ROOT_NON_CONST);
|
||||
if (CONFIG_IS_ENABLED(OF_PLATDATA_INST)) {
|
||||
gd->uclass_root = &uclass_head;
|
||||
} else {
|
||||
gd->uclass_root = &DM_UCLASS_ROOT_S_NON_CONST;
|
||||
INIT_LIST_HEAD(DM_UCLASS_ROOT_NON_CONST);
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_NEEDS_MANUAL_RELOC)) {
|
||||
fix_drivers();
|
||||
@ -149,14 +184,23 @@ int dm_init(bool of_live)
|
||||
fix_devices();
|
||||
}
|
||||
|
||||
ret = device_bind_by_name(NULL, false, &root_info, &DM_ROOT_NON_CONST);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (CONFIG_IS_ENABLED(OF_CONTROL))
|
||||
dev_set_ofnode(DM_ROOT_NON_CONST, ofnode_root());
|
||||
ret = device_probe(DM_ROOT_NON_CONST);
|
||||
if (ret)
|
||||
return ret;
|
||||
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)
|
||||
return ret;
|
||||
if (CONFIG_IS_ENABLED(OF_CONTROL))
|
||||
dev_set_ofnode(DM_ROOT_NON_CONST, ofnode_root());
|
||||
ret = device_probe(DM_ROOT_NON_CONST);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -185,7 +229,7 @@ int dm_scan_plat(bool pre_reloc_only)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (CONFIG_IS_ENABLED(OF_PLATDATA)) {
|
||||
if (CONFIG_IS_ENABLED(OF_PLATDATA_DRIVER_RT)) {
|
||||
struct driver_rt *dyn;
|
||||
int n_ents;
|
||||
|
||||
@ -303,6 +347,15 @@ __weak int dm_scan_other(bool pre_reloc_only)
|
||||
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
|
||||
*
|
||||
@ -347,10 +400,12 @@ int dm_init_and_scan(bool pre_reloc_only)
|
||||
debug("dm_init() failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
ret = dm_scan(pre_reloc_only);
|
||||
if (ret) {
|
||||
log_debug("dm_scan() failed: %d\n", ret);
|
||||
return ret;
|
||||
if (!CONFIG_IS_ENABLED(OF_PLATDATA_INST)) {
|
||||
ret = dm_scan(pre_reloc_only);
|
||||
if (ret) {
|
||||
log_debug("dm_scan() failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -148,8 +148,11 @@ int uclass_get(enum uclass_id id, struct uclass **ucp)
|
||||
|
||||
*ucp = NULL;
|
||||
uc = uclass_find(id);
|
||||
if (!uc)
|
||||
if (!uc) {
|
||||
if (CONFIG_IS_ENABLED(OF_PLATDATA_INST))
|
||||
return -ENOENT;
|
||||
return uclass_add(id, ucp);
|
||||
}
|
||||
*ucp = uc;
|
||||
|
||||
return 0;
|
||||
@ -391,7 +394,7 @@ done:
|
||||
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,
|
||||
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_ROCKCHIP) += rk_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
|
||||
endif
|
||||
obj-$(CONFIG_SYS_I2C_SH) += sh_i2c.o
|
||||
obj-$(CONFIG_SYS_I2C_SOFT) += soft_i2c.o
|
||||
obj-$(CONFIG_SYS_I2C_STM32F7) += stm32f7_i2c.o
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <dm.h>
|
||||
#include <i2c.h>
|
||||
#include <log.h>
|
||||
#include <asm/i2c.h>
|
||||
#include <dm/device-internal.h>
|
||||
#include <dm/uclass-internal.h>
|
||||
|
||||
@ -23,18 +24,6 @@
|
||||
* 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 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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct i2c_emul_uc_plat *uc_plat;
|
||||
struct udevice *emul;
|
||||
int ret;
|
||||
|
||||
ret = uclass_find_device_by_phandle(UCLASS_I2C_EMUL, dev,
|
||||
"sandbox,emul", &emul);
|
||||
if (!CONFIG_IS_ENABLED(OF_PLATDATA)) {
|
||||
ret = uclass_find_device_by_phandle(UCLASS_I2C_EMUL, dev,
|
||||
"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) {
|
||||
log_err("No emulators for device '%s'\n", dev->name);
|
||||
return ret;
|
||||
@ -85,8 +87,8 @@ static const struct udevice_id i2c_emul_parent_ids[] = {
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(i2c_emul_parent_drv) = {
|
||||
.name = "i2c_emul_parent_drv",
|
||||
U_BOOT_DRIVER(sandbox_i2c_emul_parent) = {
|
||||
.name = "sandbox_i2c_emul_parent",
|
||||
.id = UCLASS_I2C_EMUL_PARENT,
|
||||
.of_match = i2c_emul_parent_ids,
|
||||
};
|
||||
|
@ -69,7 +69,7 @@ int irq_get_by_driver_info(struct udevice *dev,
|
||||
{
|
||||
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)
|
||||
return ret;
|
||||
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",
|
||||
.of_match = testbus_ids,
|
||||
.id = UCLASS_TEST_BUS,
|
||||
@ -98,6 +98,7 @@ U_BOOT_DRIVER(testbus_drv) = {
|
||||
.per_child_plat_auto = sizeof(struct dm_test_parent_plat),
|
||||
.child_pre_probe = testbus_child_pre_probe,
|
||||
.child_post_remove = testbus_child_post_remove,
|
||||
DM_HEADER(<test.h>)
|
||||
};
|
||||
|
||||
UCLASS_DRIVER(testbus) = {
|
||||
@ -106,6 +107,9 @@ UCLASS_DRIVER(testbus) = {
|
||||
.flags = DM_UC_FLAG_SEQ_ALIAS,
|
||||
.child_pre_probe = testbus_child_pre_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)
|
||||
@ -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",
|
||||
.of_match = testfdt_ids,
|
||||
.id = UCLASS_TEST_FDT,
|
||||
@ -203,6 +209,7 @@ UCLASS_DRIVER(testfdt) = {
|
||||
.name = "testfdt",
|
||||
.id = UCLASS_TEST_FDT,
|
||||
.flags = DM_UC_FLAG_SEQ_ALIAS,
|
||||
.priv_auto = sizeof(struct dm_test_uc_priv),
|
||||
};
|
||||
|
||||
static const struct udevice_id testfdtm_ids[] = {
|
||||
|
@ -311,6 +311,7 @@ config MMC_MXS
|
||||
|
||||
config MMC_PCI
|
||||
bool "Support for MMC controllers on PCI"
|
||||
depends on MMC_SDHCI
|
||||
help
|
||||
This selects PCI-based MMC controllers.
|
||||
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) {
|
||||
struct udevice *gpiodev;
|
||||
|
||||
ret = device_get_by_driver_info_idx(dtplat->cd_gpios->idx,
|
||||
&gpiodev);
|
||||
ret = device_get_by_ofplat_idx(dtplat->cd_gpios->idx, &gpiodev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -28,25 +28,6 @@
|
||||
#define debug_buffer(x, ...)
|
||||
#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,
|
||||
int offset)
|
||||
{
|
||||
@ -223,7 +204,7 @@ static int sandbox_i2c_rtc_bind(struct udevice *dev)
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
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 = {
|
||||
.get = sandbox_rtc_get,
|
||||
.set = sandbox_rtc_set,
|
||||
@ -97,5 +109,6 @@ U_BOOT_DRIVER(sandbox_rtc) = {
|
||||
.id = UCLASS_RTC,
|
||||
.of_match = sandbox_rtc_ids,
|
||||
.ops = &sandbox_rtc_ops,
|
||||
.bind = sandbox_rtc_bind,
|
||||
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"
|
||||
depends on SPL_OF_CONTROL
|
||||
select DTOC
|
||||
select SPL_OF_PLATDATA_DRIVER_RT if !SPL_OF_PLATDATA_INST
|
||||
help
|
||||
For very constrained SPL environments the overhead of decoding
|
||||
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
|
||||
declarations for each node. See of-plat.txt for more information.
|
||||
|
||||
if SPL_OF_PLATDATA
|
||||
|
||||
config SPL_OF_PLATDATA_PARENT
|
||||
bool "Support parent information in devices"
|
||||
depends on SPL_OF_PLATDATA
|
||||
default y
|
||||
help
|
||||
Generally it is useful to be able to access the parent of a device
|
||||
with of-platdata. To save space this can be disabled, but in that
|
||||
case dev_get_parent() will always return NULL;
|
||||
|
||||
config 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
|
||||
bool "Generate platform data for use in TPL"
|
||||
depends on TPL_OF_CONTROL
|
||||
select DTOC
|
||||
select TPL_OF_PLATDATA_DRIVER_RT if !TPL_OF_PLATDATA_INST
|
||||
help
|
||||
For very constrained SPL environments the overhead of decoding
|
||||
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
|
||||
declarations for each node. See of-plat.txt for more information.
|
||||
|
||||
if TPL_OF_PLATDATA
|
||||
|
||||
config TPL_OF_PLATDATA_PARENT
|
||||
bool "Support parent information in devices"
|
||||
depends on TPL_OF_PLATDATA
|
||||
default y
|
||||
help
|
||||
Generally it is useful to be able to access the parent of a device
|
||||
with of-platdata. To save space this can be disabled, but in that
|
||||
case dev_get_parent() will always return NULL;
|
||||
|
||||
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
|
||||
|
@ -215,10 +215,20 @@ struct global_data {
|
||||
* @uclass_root_s.
|
||||
*/
|
||||
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 */
|
||||
struct driver_rt *dm_driver_rt;
|
||||
# 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
|
||||
#ifdef CONFIG_TIMER
|
||||
/**
|
||||
@ -483,7 +493,7 @@ struct global_data {
|
||||
#define gd_set_of_root(_root)
|
||||
#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_dm_driver_rt() gd->dm_driver_rt
|
||||
#else
|
||||
@ -491,6 +501,18 @@ struct global_data {
|
||||
#define gd_dm_driver_rt() NULL
|
||||
#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
|
||||
#define gd_acpi_ctx() gd->acpi_ctx
|
||||
#else
|
||||
|
@ -28,6 +28,9 @@ extern char __efi_helloworld_end[];
|
||||
extern char __efi_var_file_begin[];
|
||||
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. */
|
||||
extern char __ctors_start[], __ctors_end[];
|
||||
|
||||
|
@ -10,11 +10,86 @@
|
||||
#ifndef _DM_DEVICE_INTERNAL_H
|
||||
#define _DM_DEVICE_INTERNAL_H
|
||||
|
||||
#include <linker_lists.h>
|
||||
#include <dm/ofnode.h>
|
||||
|
||||
struct device_node;
|
||||
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
|
||||
*
|
||||
@ -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
|
||||
* 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
|
||||
* @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
|
||||
* 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
|
||||
* @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
|
||||
* 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
|
||||
* @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
|
||||
* 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
|
||||
* @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
|
||||
* 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
|
||||
* @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
|
||||
* 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
|
||||
* @uclass_plat: New uclass platform data
|
||||
*/
|
||||
|
@ -177,7 +177,9 @@ struct udevice {
|
||||
struct list_head uclass_node;
|
||||
struct list_head child_head;
|
||||
struct list_head sibling_node;
|
||||
#if !CONFIG_IS_ENABLED(OF_PLATDATA_RT)
|
||||
u32 flags_;
|
||||
#endif
|
||||
int seq_;
|
||||
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
ofnode node_;
|
||||
@ -190,12 +192,32 @@ struct udevice {
|
||||
#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 */
|
||||
#define DM_MAX_SEQ 999
|
||||
|
||||
/* Returns the operations for a device */
|
||||
#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)
|
||||
{
|
||||
return dev->flags_;
|
||||
@ -210,6 +232,7 @@ static inline void dev_bic_flags(struct udevice *dev, u32 bic)
|
||||
{
|
||||
dev->flags_ &= ~bic;
|
||||
}
|
||||
#endif /* OF_PLATDATA_RT */
|
||||
|
||||
/**
|
||||
* dev_ofnode() - get the DT node reference associated with a udevice
|
||||
@ -362,6 +385,28 @@ struct driver {
|
||||
#define DM_DRIVER_GET(__name) \
|
||||
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
|
||||
* produce no code but its information will be parsed by tools like
|
||||
@ -369,6 +414,40 @@ struct driver {
|
||||
*/
|
||||
#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
|
||||
*
|
||||
@ -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);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* is updated during the bind process.
|
||||
* Locates a device by either its struct driver_info index, or its
|
||||
* 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.
|
||||
*
|
||||
* @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
|
||||
* @return 0 if OK, -ve on error
|
||||
*/
|
||||
int device_get_by_driver_info(const struct driver_info *info,
|
||||
struct udevice **devp);
|
||||
|
||||
/**
|
||||
* device_get_by_driver_info_idx() - Get a device based on driver_info index
|
||||
*
|
||||
* Locates a device by its struct driver_info, by using its index number which
|
||||
* is written into the idx field of struct phandle_1_arg, etc.
|
||||
*
|
||||
* The device is probed to activate it ready for use.
|
||||
*
|
||||
* @idx: Index number of the driver_info structure (0=first)
|
||||
* @devp: Returns pointer to device if found, otherwise this is set to NULL
|
||||
* @return 0 if OK, -ve on error
|
||||
*/
|
||||
int device_get_by_driver_info_idx(uint idx, struct udevice **devp);
|
||||
int device_get_by_ofplat_idx(uint idx, struct udevice **devp);
|
||||
|
||||
/**
|
||||
* device_find_first_child() - Find the first child of a device
|
||||
|
@ -71,19 +71,4 @@ struct driver_rt {
|
||||
#define U_BOOT_DRVINFOS(__name) \
|
||||
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
|
||||
|
@ -11,6 +11,9 @@
|
||||
|
||||
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
|
||||
*
|
||||
|
@ -71,6 +71,11 @@ struct dm_test_priv {
|
||||
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
|
||||
*/
|
||||
|
@ -11,6 +11,55 @@
|
||||
|
||||
#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
|
||||
*
|
||||
@ -20,6 +69,9 @@
|
||||
* Use this function to override normal operation for special situations, such
|
||||
* 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
|
||||
* @priv New private-data pointer
|
||||
*/
|
||||
|
@ -114,6 +114,37 @@ struct uclass_driver {
|
||||
#define UCLASS_DRIVER(__name) \
|
||||
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
|
||||
*
|
||||
|
@ -49,3 +49,12 @@ void dm_dump_driver_compat(void);
|
||||
void dm_dump_static_driver_info(void);
|
||||
|
||||
#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;
|
||||
int arg[2];
|
||||
};
|
||||
|
||||
#include <generated/dt-structs-gen.h>
|
||||
#include <generated/dt-decl.h>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -93,6 +93,8 @@ struct udevice;
|
||||
* datasheet explains it's usage of this addressing
|
||||
* mode.
|
||||
* @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 {
|
||||
uint chip_addr;
|
||||
@ -102,6 +104,7 @@ struct dm_i2c_chip {
|
||||
#ifdef CONFIG_SANDBOX
|
||||
struct udevice *emul;
|
||||
bool test_mode;
|
||||
int emul_idx;
|
||||
#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);
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
|
@ -211,6 +211,18 @@
|
||||
_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
|
||||
* @_type: Data type of the entry
|
||||
|
@ -192,6 +192,8 @@ struct clk_fixed_factor {
|
||||
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,\
|
||||
clk)
|
||||
|
||||
@ -202,6 +204,9 @@ struct clk_fixed_rate {
|
||||
|
||||
#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 clk;
|
||||
struct clk_ops ops;
|
||||
|
@ -120,10 +120,25 @@ endif
|
||||
u-boot-spl-init := $(head-y)
|
||||
u-boot-spl-main := $(libs-y)
|
||||
ifdef CONFIG_$(SPL_TPL_)OF_PLATDATA
|
||||
u-boot-spl-platdata := $(obj)/dts/dt-plat.o
|
||||
u-boot-spl-platdata_c := $(patsubst %.o,%.c,$(u-boot-spl-platdata))
|
||||
platdata-hdr := include/generated/dt-structs-gen.h include/generated/dt-decl.h
|
||||
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
|
||||
|
||||
# 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
|
||||
# First test whether there's a linker-script for the specific stage defined...
|
||||
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
|
||||
|
||||
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 $@
|
||||
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 $@
|
||||
cmd_plat = $(CC) $(c_flags) -c $< -o $(filter-out $(PHONY),$@)
|
||||
|
||||
targets += $(u-boot-spl-platdata)
|
||||
|
||||
$(obj)/dts/dt-%.o: $(obj)/dts/dt-%.c \
|
||||
include/generated/dt-structs-gen.h prepare FORCE
|
||||
$(obj)/dts/dt-%.o: $(obj)/dts/dt-%.c $(platdata-hdr)
|
||||
$(call if_changed,plat)
|
||||
|
||||
PHONY += dts_dir
|
||||
dts_dir:
|
||||
$(shell [ -d $(obj)/dts ] || mkdir -p $(obj)/dts)
|
||||
|
||||
include/generated/dt-structs-gen.h $(u-boot-spl-platdata_c) &: \
|
||||
$(obj)/$(SPL_BIN).dtb dts_dir FORCE
|
||||
# Don't use dts_dir here, since it forces running this expensive rule every time
|
||||
$(platdata-hdr) $(u-boot-spl-platdata_c) &: $(obj)/$(SPL_BIN).dtb
|
||||
@[ -d $(obj)/dts ] || mkdir -p $(obj)/dts
|
||||
@# Remove old files since which ones we generate depends on the setting
|
||||
@# of OF_PLATDATA_INST and this might change between builds. Leaving old
|
||||
@# 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)
|
||||
|
||||
ifdef CONFIG_SAMSUNG
|
||||
@ -471,6 +489,10 @@ FORCE:
|
||||
$(obj)/dts/dt-$(SPL_NAME).dtb: dts/dt.dtb
|
||||
$(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
|
||||
# information in a variable so we can use it in if_changed and friends.
|
||||
.PHONY: $(PHONY)
|
||||
|
@ -23,12 +23,18 @@ quiet_cmd_pymod = PYMOD $@
|
||||
SWIG_OPTS="-I$(LIBFDT_srcdir) -I$(LIBFDT_srcdir)/.." \
|
||||
$(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
|
||||
@# the libfdt.py file if it is missing.
|
||||
rm -f $(obj)/_libfdt*.so
|
||||
@rm -f $(obj)/_libfdt*.so
|
||||
$(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
|
||||
|
@ -15,7 +15,7 @@
|
||||
|
||||
#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)
|
||||
|
||||
/* 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 */
|
||||
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);
|
||||
bool found[n_ents];
|
||||
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 */
|
||||
memset(found, '\0', sizeof(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 */
|
||||
for (i = 0; i < n_ents; i++) {
|
||||
const struct driver_rt *drt = gd_dm_driver_rt() + i;
|
||||
const struct driver_info *entry = info + i;
|
||||
struct udevice *dev;
|
||||
|
||||
if (found[i]) {
|
||||
/* Make sure we can find it */
|
||||
ut_assertnonnull(drt->dev);
|
||||
ut_assertok(device_get_by_driver_info(entry, &dev));
|
||||
ut_assertok(device_get_by_ofplat_idx(i, &dev));
|
||||
ut_asserteq_ptr(dev, drt->dev);
|
||||
} else {
|
||||
ut_assertnull(drt->dev);
|
||||
ut_asserteq(-ENOENT,
|
||||
device_get_by_driver_info(entry, &dev));
|
||||
ut_asserteq(-ENOENT, device_get_by_ofplat_idx(i, &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);
|
||||
plat = dev_get_plat(dev);
|
||||
|
||||
ut_assertok(device_get_by_driver_info_idx(plat->clocks[0].idx, &clk));
|
||||
ut_asserteq_str("fixed_clock", clk->name);
|
||||
ut_assertok(device_get_by_ofplat_idx(plat->clocks[0].idx, &clk));
|
||||
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(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(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(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(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 */
|
||||
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(device_first_child_err(bus, &dev));
|
||||
ut_asserteq_ptr(bus, dev_get_parent(dev));
|
||||
ut_assertok(uclass_first_device_err(UCLASS_RTC, &rtc));
|
||||
ut_assertok(uclass_first_device_err(UCLASS_I2C, &i2c));
|
||||
ut_asserteq_ptr(i2c, dev_get_parent(rtc));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -330,7 +330,7 @@ static int dm_test_fdt_uclass_seq_more(struct unit_test_state *uts)
|
||||
|
||||
/* Check creating a device with an alias */
|
||||
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));
|
||||
ut_asserteq(12, dev_seq(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
|
||||
*/
|
||||
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));
|
||||
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));
|
||||
ut_asserteq(20, dev_seq(dev));
|
||||
|
||||
|
@ -6,8 +6,8 @@
|
||||
#define DEBUG
|
||||
|
||||
#include <common.h>
|
||||
#if CONFIG_IS_ENABLED(EFI_LOADER) && !defined(API_BUILD)
|
||||
#include <command.h>
|
||||
#if CONFIG_IS_ENABLED(EFI_LOADER) && !defined(API_BUILD)
|
||||
#include <efi_api.h>
|
||||
#endif
|
||||
#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 \
|
||||
-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
|
||||
# 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
|
||||
|
@ -62,17 +62,25 @@ static int dm_test_post_run(struct unit_test_state *uts)
|
||||
{
|
||||
int id;
|
||||
|
||||
for (id = 0; id < UCLASS_COUNT; id++) {
|
||||
struct uclass *uc;
|
||||
/*
|
||||
* 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++) {
|
||||
struct uclass *uc;
|
||||
|
||||
/*
|
||||
* If the uclass doesn't exist we don't want to create it. So
|
||||
* check that here before we call uclass_find_device().
|
||||
*/
|
||||
uc = uclass_find(id);
|
||||
if (!uc)
|
||||
continue;
|
||||
ut_assertok(uclass_destroy(uc));
|
||||
/*
|
||||
* If the uclass doesn't exist we don't want to create
|
||||
* it. So check that here before we call
|
||||
* uclass_find_device().
|
||||
*/
|
||||
uc = uclass_find(id);
|
||||
if (!uc)
|
||||
continue;
|
||||
ut_assertok(uclass_destroy(uc));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
1
tools/binman/README.rst
Symbolic link
1
tools/binman/README.rst
Symbolic link
@ -0,0 +1 @@
|
||||
binman.rst
|
File diff suppressed because it is too large
Load Diff
@ -56,6 +56,9 @@ controlled by a description in the board device tree.'''
|
||||
default=False, help='Output a map file for each image')
|
||||
build_parser.add_argument('-M', '--allow-missing', action='store_true',
|
||||
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,
|
||||
action='store', help='Path to directory to use for intermediate and '
|
||||
'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')
|
||||
|
||||
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.add_argument('-i', '--image', type=str, required=True,
|
||||
|
@ -28,7 +28,7 @@ images = OrderedDict()
|
||||
# value: Text for the help
|
||||
missing_blob_help = {}
|
||||
|
||||
def _ReadImageDesc(binman_node):
|
||||
def _ReadImageDesc(binman_node, use_expanded):
|
||||
"""Read the image descriptions from the /binman node
|
||||
|
||||
This normally produces a single Image object called 'image'. But if
|
||||
@ -36,15 +36,17 @@ def _ReadImageDesc(binman_node):
|
||||
|
||||
Args:
|
||||
binman_node: Node object of the /binman node
|
||||
use_expanded: True if the FDT will be updated with the entry information
|
||||
Returns:
|
||||
OrderedDict of Image objects, each of which describes an image
|
||||
"""
|
||||
images = OrderedDict()
|
||||
if 'multiple-images' in binman_node.props:
|
||||
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:
|
||||
images['image'] = Image('image', binman_node)
|
||||
images['image'] = Image('image', binman_node, use_expanded=use_expanded)
|
||||
return images
|
||||
|
||||
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
|
||||
# data in a file called 'root' in that directory
|
||||
if entry.GetEntries():
|
||||
if not os.path.exists(fname):
|
||||
if fname and not os.path.exists(fname):
|
||||
os.makedirs(fname)
|
||||
fname = os.path.join(fname, 'root')
|
||||
tout.Notice("Write entry '%s' size %x to '%s'" %
|
||||
@ -399,7 +401,7 @@ def ReplaceEntries(image_fname, input_fname, indir, entry_paths,
|
||||
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
|
||||
|
||||
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)
|
||||
selected_images: List of images to output, or None for all
|
||||
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:
|
||||
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' "
|
||||
"node" % dtb_fname)
|
||||
|
||||
images = _ReadImageDesc(node)
|
||||
images = _ReadImageDesc(node, use_expanded)
|
||||
|
||||
if select_images:
|
||||
skip = []
|
||||
@ -564,7 +569,7 @@ def Binman(args):
|
||||
if not pager:
|
||||
pager = 'more'
|
||||
fname = os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])),
|
||||
'README')
|
||||
'README.rst')
|
||||
command.Run(pager, fname)
|
||||
return 0
|
||||
|
||||
@ -611,6 +616,13 @@ def Binman(args):
|
||||
elf.debug = args.debug
|
||||
cbfs_util.VERBOSE = args.verbosity > 2
|
||||
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:
|
||||
tools.SetInputDirs(args.indir)
|
||||
tools.PrepareOutputDir(args.outdir, args.preserve)
|
||||
@ -618,7 +630,7 @@ def Binman(args):
|
||||
state.SetEntryArgs(args.entry_arg)
|
||||
|
||||
images = PrepareImagesAndDtbs(dtb_fname, args.image,
|
||||
args.update_fdt)
|
||||
args.update_fdt, use_expanded)
|
||||
missing = False
|
||||
for image in images.values():
|
||||
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…
Reference in New Issue
Block a user