Merge git://git.denx.de/u-boot-dm
This commit is contained in:
commit
ebe621d5fb
5
Makefile
5
Makefile
@ -802,7 +802,7 @@ quiet_cmd_pad_cat = CAT $@
|
||||
cmd_pad_cat = $(cmd_objcopy) && $(append) || rm -f $@
|
||||
|
||||
all: $(ALL-y)
|
||||
ifeq ($(CONFIG_DM_I2C_COMPAT),y)
|
||||
ifeq ($(CONFIG_DM_I2C_COMPAT)$(CONFIG_SANDBOX),y)
|
||||
@echo "===================== WARNING ======================"
|
||||
@echo "This board uses CONFIG_DM_I2C_COMPAT. Please remove"
|
||||
@echo "(possibly in a subsequent patch in your series)"
|
||||
@ -1319,7 +1319,8 @@ u-boot.lds: $(LDSCRIPT) prepare FORCE
|
||||
|
||||
spl/u-boot-spl.bin: spl/u-boot-spl
|
||||
@:
|
||||
spl/u-boot-spl: tools prepare $(if $(CONFIG_OF_SEPARATE),dts/dt.dtb)
|
||||
spl/u-boot-spl: tools prepare \
|
||||
$(if $(CONFIG_OF_SEPARATE)$(CONFIG_SPL_OF_PLATDATA),dts/dt.dtb)
|
||||
$(Q)$(MAKE) obj=spl -f $(srctree)/scripts/Makefile.spl all
|
||||
|
||||
spl/sunxi-spl.bin: spl/u-boot-spl
|
||||
|
3
README
3
README
@ -3835,9 +3835,6 @@ Configuration Settings:
|
||||
The memory will be freed (or in fact just forgotten) when
|
||||
U-Boot relocates itself.
|
||||
|
||||
Pre-relocation malloc() is only supported on ARM and sandbox
|
||||
at present but is fairly easy to enable for other archs.
|
||||
|
||||
- CONFIG_SYS_MALLOC_SIMPLE
|
||||
Provides a simple and small malloc() and calloc() for those
|
||||
boards which do not use the full malloc in SPL (which is
|
||||
|
@ -30,7 +30,8 @@
|
||||
0x5 0x0>;
|
||||
rockchip,phy-timing = <0x48f9aab4 0xea0910 0x1002c200
|
||||
0xa60 0x40 0x10 0x0>;
|
||||
rockchip,sdram-channel = /bits/ 8 <0x1 0xa 0x3 0x2 0x1 0x0 0xf 0xf>;
|
||||
/* Add a dummy value to cause of-platdata think this is bytes */
|
||||
rockchip,sdram-channel = /bits/ 8 <0x1 0xa 0x3 0x2 0x1 0x0 0xf 0xf 0xff>;
|
||||
rockchip,sdram-params = <0x30B25564 0x627 3 666000000 3 9 1>;
|
||||
};
|
||||
|
||||
|
@ -24,6 +24,12 @@ struct rk3288_sdram_channel {
|
||||
u8 row_3_4;
|
||||
u8 cs0_row;
|
||||
u8 cs1_row;
|
||||
/*
|
||||
* For of-platdata, which would otherwise convert this into two
|
||||
* byte-swapped integers. With a size of 9 bytes, this struct will
|
||||
* appear in of-platdata as a byte array.
|
||||
*/
|
||||
u8 dummy;
|
||||
};
|
||||
|
||||
struct rk3288_sdram_pctl_timing {
|
||||
@ -81,12 +87,4 @@ struct rk3288_base_params {
|
||||
u32 odt;
|
||||
};
|
||||
|
||||
struct rk3288_sdram_params {
|
||||
struct rk3288_sdram_channel ch[2];
|
||||
struct rk3288_sdram_pctl_timing pctl_timing;
|
||||
struct rk3288_sdram_phy_timing phy_timing;
|
||||
struct rk3288_base_params base;
|
||||
int num_channels;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -29,6 +29,7 @@ DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
u32 spl_boot_device(void)
|
||||
{
|
||||
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
const void *blob = gd->fdt_blob;
|
||||
struct udevice *dev;
|
||||
const char *bootdev;
|
||||
@ -63,6 +64,7 @@ u32 spl_boot_device(void)
|
||||
}
|
||||
|
||||
fallback:
|
||||
#endif
|
||||
return BOOT_DEVICE_MMC1;
|
||||
}
|
||||
|
||||
@ -114,7 +116,6 @@ static void configure_l2ctlr(void)
|
||||
#ifdef CONFIG_SPL_MMC_SUPPORT
|
||||
static int configure_emmc(struct udevice *pinctrl)
|
||||
{
|
||||
#if !defined(CONFIG_TARGET_ROCK2) && !defined(CONFIG_TARGET_FIREFLY_RK3288)
|
||||
struct gpio_desc desc;
|
||||
int ret;
|
||||
|
||||
@ -144,7 +145,6 @@ static int configure_emmc(struct udevice *pinctrl)
|
||||
debug("gpio value ret=%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -247,15 +247,18 @@ void spl_board_init(void)
|
||||
goto err;
|
||||
}
|
||||
#ifdef CONFIG_SPL_MMC_SUPPORT
|
||||
ret = pinctrl_request_noflags(pinctrl, PERIPH_ID_SDCARD);
|
||||
if (ret) {
|
||||
debug("%s: Failed to set up SD card\n", __func__);
|
||||
goto err;
|
||||
}
|
||||
ret = configure_emmc(pinctrl);
|
||||
if (ret) {
|
||||
debug("%s: Failed to set up eMMC\n", __func__);
|
||||
goto err;
|
||||
if (!IS_ENABLED(CONFIG_TARGET_ROCK2) &&
|
||||
!IS_ENABLED(CONFIG_TARGET_FIREFLY_RK3288)) {
|
||||
ret = pinctrl_request_noflags(pinctrl, PERIPH_ID_SDCARD);
|
||||
if (ret) {
|
||||
debug("%s: Failed to set up SD card\n", __func__);
|
||||
goto err;
|
||||
}
|
||||
ret = configure_emmc(pinctrl);
|
||||
if (ret) {
|
||||
debug("%s: Failed to set up eMMC\n", __func__);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <common.h>
|
||||
#include <clk.h>
|
||||
#include <dm.h>
|
||||
#include <dt-structs.h>
|
||||
#include <errno.h>
|
||||
#include <ram.h>
|
||||
#include <regmap.h>
|
||||
@ -41,6 +42,19 @@ struct dram_info {
|
||||
struct rk3288_grf *grf;
|
||||
struct rk3288_sgrf *sgrf;
|
||||
struct rk3288_pmu *pmu;
|
||||
bool is_veyron;
|
||||
};
|
||||
|
||||
struct rk3288_sdram_params {
|
||||
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
struct dtd_rockchip_rk3288_dmc of_plat;
|
||||
#endif
|
||||
struct rk3288_sdram_channel ch[2];
|
||||
struct rk3288_sdram_pctl_timing pctl_timing;
|
||||
struct rk3288_sdram_phy_timing phy_timing;
|
||||
struct rk3288_base_params base;
|
||||
int num_channels;
|
||||
struct regmap *map;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SPL_BUILD
|
||||
@ -703,7 +717,7 @@ static int sdram_init(struct dram_info *dram,
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#endif /* CONFIG_SPL_BUILD */
|
||||
|
||||
size_t sdram_size_mb(struct rk3288_pmu *pmu)
|
||||
{
|
||||
@ -779,18 +793,36 @@ static int veyron_init(struct dram_info *priv)
|
||||
static int setup_sdram(struct udevice *dev)
|
||||
{
|
||||
struct dram_info *priv = dev_get_priv(dev);
|
||||
struct rk3288_sdram_params params;
|
||||
struct rk3288_sdram_params *params = dev_get_platdata(dev);
|
||||
|
||||
# ifdef CONFIG_ROCKCHIP_FAST_SPL
|
||||
if (priv->is_veyron) {
|
||||
int ret;
|
||||
|
||||
ret = veyron_init(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
# endif
|
||||
|
||||
return sdram_init(priv, params);
|
||||
}
|
||||
|
||||
static int rk3288_dmc_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
struct rk3288_sdram_params *params = dev_get_platdata(dev);
|
||||
const void *blob = gd->fdt_blob;
|
||||
int node = dev->of_offset;
|
||||
int i, ret;
|
||||
|
||||
params.num_channels = fdtdec_get_int(blob, node,
|
||||
"rockchip,num-channels", 1);
|
||||
for (i = 0; i < params.num_channels; i++) {
|
||||
params->num_channels = fdtdec_get_int(blob, node,
|
||||
"rockchip,num-channels", 1);
|
||||
for (i = 0; i < params->num_channels; i++) {
|
||||
ret = fdtdec_get_byte_array(blob, node,
|
||||
"rockchip,sdram-channel",
|
||||
(u8 *)¶ms.ch[i],
|
||||
sizeof(params.ch[i]));
|
||||
(u8 *)¶ms->ch[i],
|
||||
sizeof(params->ch[i]));
|
||||
if (ret) {
|
||||
debug("%s: Cannot read rockchip,sdram-channel\n",
|
||||
__func__);
|
||||
@ -798,46 +830,82 @@ static int setup_sdram(struct udevice *dev)
|
||||
}
|
||||
}
|
||||
ret = fdtdec_get_int_array(blob, node, "rockchip,pctl-timing",
|
||||
(u32 *)¶ms.pctl_timing,
|
||||
sizeof(params.pctl_timing) / sizeof(u32));
|
||||
(u32 *)¶ms->pctl_timing,
|
||||
sizeof(params->pctl_timing) / sizeof(u32));
|
||||
if (ret) {
|
||||
debug("%s: Cannot read rockchip,pctl-timing\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = fdtdec_get_int_array(blob, node, "rockchip,phy-timing",
|
||||
(u32 *)¶ms.phy_timing,
|
||||
sizeof(params.phy_timing) / sizeof(u32));
|
||||
(u32 *)¶ms->phy_timing,
|
||||
sizeof(params->phy_timing) / sizeof(u32));
|
||||
if (ret) {
|
||||
debug("%s: Cannot read rockchip,phy-timing\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = fdtdec_get_int_array(blob, node, "rockchip,sdram-params",
|
||||
(u32 *)¶ms.base,
|
||||
sizeof(params.base) / sizeof(u32));
|
||||
(u32 *)¶ms->base,
|
||||
sizeof(params->base) / sizeof(u32));
|
||||
if (ret) {
|
||||
debug("%s: Cannot read rockchip,sdram-params\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
#ifdef CONFIG_ROCKCHIP_FAST_SPL
|
||||
struct dram_info *priv = dev_get_priv(dev);
|
||||
|
||||
# ifdef CONFIG_ROCKCHIP_FAST_SPL
|
||||
if (!fdt_node_check_compatible(blob, 0, "google,veyron")) {
|
||||
ret = veyron_init(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
priv->is_veyron = !fdt_node_check_compatible(blob, 0, "google,veyron");
|
||||
#endif
|
||||
ret = regmap_init_mem(dev, ¶ms->map);
|
||||
if (ret)
|
||||
return ret;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_SPL_BUILD */
|
||||
|
||||
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
static int conv_of_platdata(struct udevice *dev)
|
||||
{
|
||||
struct rk3288_sdram_params *plat = dev_get_platdata(dev);
|
||||
struct dtd_rockchip_rk3288_dmc *of_plat = &plat->of_plat;
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
memcpy(&plat->ch[i], of_plat->rockchip_sdram_channel,
|
||||
sizeof(plat->ch[i]));
|
||||
}
|
||||
# endif
|
||||
memcpy(&plat->pctl_timing, of_plat->rockchip_pctl_timing,
|
||||
sizeof(plat->pctl_timing));
|
||||
memcpy(&plat->phy_timing, of_plat->rockchip_phy_timing,
|
||||
sizeof(plat->phy_timing));
|
||||
memcpy(&plat->base, of_plat->rockchip_sdram_params, sizeof(plat->base));
|
||||
plat->num_channels = of_plat->rockchip_num_channels;
|
||||
ret = regmap_init_mem_platdata(dev, of_plat->reg,
|
||||
ARRAY_SIZE(of_plat->reg) / 2,
|
||||
&plat->map);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sdram_init(priv, ¶ms);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int rk3288_dmc_probe(struct udevice *dev)
|
||||
{
|
||||
#ifdef CONFIG_SPL_BUILD
|
||||
struct rk3288_sdram_params *plat = dev_get_platdata(dev);
|
||||
#endif
|
||||
struct dram_info *priv = dev_get_priv(dev);
|
||||
struct regmap *map;
|
||||
int ret;
|
||||
struct udevice *dev_clk;
|
||||
|
||||
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
ret = conv_of_platdata(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
#endif
|
||||
map = syscon_get_regmap_by_driver_data(ROCKCHIP_SYSCON_NOC);
|
||||
if (IS_ERR(map))
|
||||
return PTR_ERR(map);
|
||||
@ -849,14 +917,12 @@ static int rk3288_dmc_probe(struct udevice *dev)
|
||||
priv->sgrf = syscon_get_first_range(ROCKCHIP_SYSCON_SGRF);
|
||||
priv->pmu = syscon_get_first_range(ROCKCHIP_SYSCON_PMU);
|
||||
|
||||
ret = regmap_init_mem(dev, &map);
|
||||
if (ret)
|
||||
return ret;
|
||||
priv->chan[0].pctl = regmap_get_range(map, 0);
|
||||
priv->chan[0].publ = regmap_get_range(map, 1);
|
||||
priv->chan[1].pctl = regmap_get_range(map, 2);
|
||||
priv->chan[1].publ = regmap_get_range(map, 3);
|
||||
|
||||
#ifdef CONFIG_SPL_BUILD
|
||||
priv->chan[0].pctl = regmap_get_range(plat->map, 0);
|
||||
priv->chan[0].publ = regmap_get_range(plat->map, 1);
|
||||
priv->chan[1].pctl = regmap_get_range(plat->map, 2);
|
||||
priv->chan[1].publ = regmap_get_range(plat->map, 3);
|
||||
#endif
|
||||
ret = uclass_get_device(UCLASS_CLK, 0, &dev_clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -898,10 +964,16 @@ static const struct udevice_id rk3288_dmc_ids[] = {
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(dmc_rk3288) = {
|
||||
.name = "rk3288_dmc",
|
||||
.name = "rockchip_rk3288_dmc",
|
||||
.id = UCLASS_RAM,
|
||||
.of_match = rk3288_dmc_ids,
|
||||
.ops = &rk3288_dmc_ops,
|
||||
#ifdef CONFIG_SPL_BUILD
|
||||
.ofdata_to_platdata = rk3288_dmc_ofdata_to_platdata,
|
||||
#endif
|
||||
.probe = rk3288_dmc_probe,
|
||||
.priv_auto_alloc_size = sizeof(struct dram_info),
|
||||
#ifdef CONFIG_SPL_BUILD
|
||||
.platdata_auto_alloc_size = sizeof(struct rk3288_sdram_params),
|
||||
#endif
|
||||
};
|
||||
|
@ -23,3 +23,41 @@ U_BOOT_DRIVER(syscon_rk3288) = {
|
||||
.id = UCLASS_SYSCON,
|
||||
.of_match = rk3288_syscon_ids,
|
||||
};
|
||||
|
||||
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
static int rk3288_syscon_bind_of_platdata(struct udevice *dev)
|
||||
{
|
||||
dev->driver_data = dev->driver->of_match->data;
|
||||
debug("syscon: %s %d\n", dev->name, (uint)dev->driver_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_DRIVER(rockchip_rk3288_noc) = {
|
||||
.name = "rockchip_rk3288_noc",
|
||||
.id = UCLASS_SYSCON,
|
||||
.of_match = rk3288_syscon_ids,
|
||||
.bind = rk3288_syscon_bind_of_platdata,
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(rockchip_rk3288_grf) = {
|
||||
.name = "rockchip_rk3288_grf",
|
||||
.id = UCLASS_SYSCON,
|
||||
.of_match = rk3288_syscon_ids + 1,
|
||||
.bind = rk3288_syscon_bind_of_platdata,
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(rockchip_rk3288_sgrf) = {
|
||||
.name = "rockchip_rk3288_sgrf",
|
||||
.id = UCLASS_SYSCON,
|
||||
.of_match = rk3288_syscon_ids + 2,
|
||||
.bind = rk3288_syscon_bind_of_platdata,
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(rockchip_rk3288_pmu) = {
|
||||
.name = "rockchip_rk3288_pmu",
|
||||
.id = UCLASS_SYSCON,
|
||||
.of_match = rk3288_syscon_ids + 3,
|
||||
.bind = rk3288_syscon_bind_of_platdata,
|
||||
};
|
||||
#endif
|
||||
|
@ -10,8 +10,13 @@ config SYS_BOARD
|
||||
config SYS_CPU
|
||||
default "sandbox"
|
||||
|
||||
config SANDBOX_SPL
|
||||
bool "Enable SPL for sandbox"
|
||||
select SUPPORT_SPL
|
||||
|
||||
config SYS_CONFIG_NAME
|
||||
default "sandbox"
|
||||
default "sandbox_spl" if SANDBOX_SPL
|
||||
default "sandbox" if !SANDBOX_SPL
|
||||
|
||||
config PCI
|
||||
bool "PCI support"
|
||||
|
@ -20,4 +20,9 @@ cmd_u-boot__ = $(CC) -o $@ -Wl,-T u-boot.lds \
|
||||
-Wl,--start-group $(u-boot-main) -Wl,--end-group \
|
||||
$(PLATFORM_LIBS) -Wl,-Map -Wl,u-boot.map
|
||||
|
||||
cmd_u-boot-spl = (cd $(obj) && $(CC) -o $(SPL_BIN) -Wl,-T u-boot-spl.lds \
|
||||
-Wl,--start-group $(patsubst $(obj)/%,%,$(u-boot-spl-main)) \
|
||||
$(patsubst $(obj)/%,%,$(u-boot-spl-platdata)) -Wl,--end-group \
|
||||
$(PLATFORM_LIBS) -Wl,-Map -Wl,u-boot-spl.map -Wl,--gc-sections)
|
||||
|
||||
CONFIG_ARCH_DEVICE_TREE := sandbox
|
||||
|
@ -8,6 +8,7 @@
|
||||
#
|
||||
|
||||
obj-y := cpu.o os.o start.o state.o
|
||||
obj-$(CONFIG_SPL_BUILD) += spl.o
|
||||
obj-$(CONFIG_ETH_SANDBOX_RAW) += eth-raw-os.o
|
||||
obj-$(CONFIG_SANDBOX_SDL) += sdl.o
|
||||
|
||||
|
@ -4,10 +4,12 @@
|
||||
*/
|
||||
#define DEBUG
|
||||
#include <common.h>
|
||||
#include <dm/root.h>
|
||||
#include <errno.h>
|
||||
#include <libfdt.h>
|
||||
#include <os.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/state.h>
|
||||
#include <dm/root.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
@ -55,7 +57,7 @@ int cleanup_before_linux_select(int flags)
|
||||
|
||||
void *map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags)
|
||||
{
|
||||
#ifdef CONFIG_PCI
|
||||
#if defined(CONFIG_PCI) && !defined(CONFIG_SPL_BUILD)
|
||||
unsigned long plen = len;
|
||||
void *ptr;
|
||||
|
||||
|
@ -541,6 +541,57 @@ int os_jump_to_image(const void *dest, int size)
|
||||
return unlink(fname);
|
||||
}
|
||||
|
||||
int os_find_u_boot(char *fname, int maxlen)
|
||||
{
|
||||
struct sandbox_state *state = state_get_current();
|
||||
const char *progname = state->argv[0];
|
||||
int len = strlen(progname);
|
||||
char *p;
|
||||
int fd;
|
||||
|
||||
if (len >= maxlen || len < 4)
|
||||
return -ENOSPC;
|
||||
|
||||
/* Look for 'u-boot' in the same directory as 'u-boot-spl' */
|
||||
strcpy(fname, progname);
|
||||
if (!strcmp(fname + len - 4, "-spl")) {
|
||||
fname[len - 4] = '\0';
|
||||
fd = os_open(fname, O_RDONLY);
|
||||
if (fd >= 0) {
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Look for 'u-boot' in the parent directory of spl/ */
|
||||
p = strstr(fname, "/spl/");
|
||||
if (p) {
|
||||
strcpy(p, p + 4);
|
||||
fd = os_open(fname, O_RDONLY);
|
||||
if (fd >= 0) {
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int os_spl_to_uboot(const char *fname)
|
||||
{
|
||||
struct sandbox_state *state = state_get_current();
|
||||
char *argv[state->argc + 1];
|
||||
int ret;
|
||||
|
||||
memcpy(argv, state->argv, sizeof(char *) * (state->argc + 1));
|
||||
argv[0] = (char *)fname;
|
||||
ret = execv(fname, argv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return unlink(fname);
|
||||
}
|
||||
|
||||
void os_localtime(struct rtc_time *rt)
|
||||
{
|
||||
time_t t = time(NULL);
|
||||
|
68
arch/sandbox/cpu/spl.c
Normal file
68
arch/sandbox/cpu/spl.c
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Google, Inc
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <os.h>
|
||||
#include <spl.h>
|
||||
#include <asm/spl.h>
|
||||
#include <asm/state.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
void board_init_f(ulong flag)
|
||||
{
|
||||
struct sandbox_state *state = state_get_current();
|
||||
|
||||
gd->arch.ram_buf = state->ram_buf;
|
||||
gd->ram_size = state->ram_size;
|
||||
}
|
||||
|
||||
u32 spl_boot_device(void)
|
||||
{
|
||||
return BOOT_DEVICE_BOARD;
|
||||
}
|
||||
|
||||
void spl_board_announce_boot_device(void)
|
||||
{
|
||||
char fname[256];
|
||||
int ret;
|
||||
|
||||
ret = os_find_u_boot(fname, sizeof(fname));
|
||||
if (ret) {
|
||||
printf("(%s not found, error %d)\n", fname, ret);
|
||||
return;
|
||||
}
|
||||
printf("%s\n", fname);
|
||||
}
|
||||
|
||||
int spl_board_load_image(void)
|
||||
{
|
||||
char fname[256];
|
||||
int ret;
|
||||
|
||||
ret = os_find_u_boot(fname, sizeof(fname));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Hopefully this will not return */
|
||||
return os_spl_to_uboot(fname);
|
||||
}
|
||||
|
||||
void spl_board_init(void)
|
||||
{
|
||||
struct udevice *dev;
|
||||
|
||||
preloader_console_init();
|
||||
|
||||
/*
|
||||
* Scan all the devices so that we can output their platform data. See
|
||||
* sandbox_spl_probe().
|
||||
*/
|
||||
for (uclass_first_device(UCLASS_MISC, &dev);
|
||||
dev;
|
||||
uclass_next_device(&dev))
|
||||
;
|
||||
}
|
@ -73,6 +73,7 @@ static int sandbox_cmdline_cb_help(struct sandbox_state *state, const char *arg)
|
||||
}
|
||||
SANDBOX_CMDLINE_OPT_SHORT(help, 'h', 0, "Display help");
|
||||
|
||||
#ifndef CONFIG_SPL_BUILD
|
||||
int sandbox_main_loop_init(void)
|
||||
{
|
||||
struct sandbox_state *state = state_get_current();
|
||||
@ -97,6 +98,7 @@ int sandbox_main_loop_init(void)
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int sandbox_cmdline_cb_boot(struct sandbox_state *state,
|
||||
const char *arg)
|
||||
|
24
arch/sandbox/cpu/u-boot-spl.lds
Normal file
24
arch/sandbox/cpu/u-boot-spl.lds
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 2011-2012 The Chromium OS Authors.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
|
||||
. = ALIGN(4);
|
||||
.u_boot_list : {
|
||||
KEEP(*(SORT(.u_boot_list*)));
|
||||
}
|
||||
|
||||
__u_boot_sandbox_option_start = .;
|
||||
_u_boot_sandbox_getopt : { *(.u_boot_sandbox_getopt) }
|
||||
__u_boot_sandbox_option_end = .;
|
||||
|
||||
__bss_start = .;
|
||||
}
|
||||
|
||||
INSERT BEFORE .data;
|
@ -172,6 +172,37 @@
|
||||
};
|
||||
};
|
||||
|
||||
spl-test {
|
||||
u-boot,dm-pre-reloc;
|
||||
compatible = "sandbox,spl-test";
|
||||
boolval;
|
||||
intval = <1>;
|
||||
intarray = <2 3 4>;
|
||||
byteval = [05];
|
||||
bytearray = [06];
|
||||
longbytearray = [09 0a 0b 0c 0d 0e 0f 10 11];
|
||||
stringval = "message";
|
||||
stringarray = "multi-word", "message";
|
||||
};
|
||||
|
||||
spl-test2 {
|
||||
u-boot,dm-pre-reloc;
|
||||
compatible = "sandbox,spl-test";
|
||||
intval = <3>;
|
||||
intarray = <5>;
|
||||
byteval = [08];
|
||||
bytearray = [01 23 34];
|
||||
longbytearray = [09 0a 0b 0c];
|
||||
stringval = "message2";
|
||||
stringarray = "another", "multi-word", "message";
|
||||
};
|
||||
|
||||
spl-test3 {
|
||||
u-boot,dm-pre-reloc;
|
||||
compatible = "sandbox,spl-test";
|
||||
stringarray = "one";
|
||||
};
|
||||
|
||||
square {
|
||||
compatible = "demo-shape";
|
||||
colour = "blue";
|
||||
|
23
arch/sandbox/include/asm/spl.h
Normal file
23
arch/sandbox/include/asm/spl.h
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Google, Inc
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#ifndef __asm_spl_h
|
||||
#define __asm_spl_h
|
||||
|
||||
#define CONFIG_SPL_BOARD_LOAD_IMAGE
|
||||
|
||||
/**
|
||||
* Board-specific load method for boards that have a special way of loading
|
||||
* U-Boot, which does not fit with the existing SPL code.
|
||||
*
|
||||
* @return 0 on success, negative errno value on failure.
|
||||
*/
|
||||
int spl_board_load_image(void);
|
||||
|
||||
enum {
|
||||
BOOT_DEVICE_BOARD,
|
||||
};
|
||||
|
||||
#endif
|
@ -8,5 +8,7 @@
|
||||
#
|
||||
|
||||
obj-y += interrupts.o
|
||||
ifndef CONFIG_SPL_BUILD
|
||||
obj-$(CONFIG_PCI) += pci_io.o
|
||||
endif
|
||||
obj-$(CONFIG_CMD_BOOTM) += bootm.o
|
||||
|
@ -11,3 +11,10 @@ S: Maintained
|
||||
F: board/sandbox/
|
||||
F: include/configs/sandbox.h
|
||||
F: configs/sandbox_noblk_defconfig
|
||||
|
||||
SANDBOX SPL BOARD
|
||||
M: Simon Glass <sjg@chromium.org>
|
||||
S: Maintained
|
||||
F: board/sandbox/
|
||||
F: include/configs/sandbox_spl.h
|
||||
F: configs/sandbox_spl_defconfig
|
||||
|
@ -13,7 +13,6 @@
|
||||
#include <nand.h>
|
||||
#include <fat.h>
|
||||
#include <version.h>
|
||||
#include <i2c.h>
|
||||
#include <image.h>
|
||||
#include <malloc.h>
|
||||
#include <dm/root.h>
|
||||
@ -203,7 +202,7 @@ int spl_init(void)
|
||||
gd->malloc_limit = CONFIG_SYS_MALLOC_F_LEN;
|
||||
gd->malloc_ptr = 0;
|
||||
#endif
|
||||
if (CONFIG_IS_ENABLED(OF_CONTROL)) {
|
||||
if (CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)) {
|
||||
ret = fdtdec_setup();
|
||||
if (ret) {
|
||||
debug("fdtdec_setup() returned error %d\n", ret);
|
||||
@ -211,7 +210,8 @@ int spl_init(void)
|
||||
}
|
||||
}
|
||||
if (IS_ENABLED(CONFIG_SPL_DM)) {
|
||||
ret = dm_init_and_scan(true);
|
||||
/* With CONFIG_OF_PLATDATA, bring in all devices */
|
||||
ret = dm_init_and_scan(!CONFIG_IS_ENABLED(OF_PLATDATA));
|
||||
if (ret) {
|
||||
debug("dm_init_and_scan() returned error %d\n", ret);
|
||||
return ret;
|
||||
|
@ -69,3 +69,6 @@ CONFIG_USE_PRIVATE_LIBGCC=y
|
||||
CONFIG_USE_TINY_PRINTF=y
|
||||
CONFIG_CMD_DHRYSTONE=y
|
||||
CONFIG_ERRNO_STR=y
|
||||
CONFIG_SPL_OF_PLATDATA=y
|
||||
# CONFIG_SPL_OF_LIBFDT is not set
|
||||
CONFIG_ROCKCHIP_SERIAL=y
|
||||
|
183
configs/sandbox_spl_defconfig
Normal file
183
configs/sandbox_spl_defconfig
Normal file
@ -0,0 +1,183 @@
|
||||
CONFIG_SYS_MALLOC_F_LEN=0x2000
|
||||
CONFIG_MMC=y
|
||||
CONFIG_SANDBOX_SPL=y
|
||||
CONFIG_PCI=y
|
||||
CONFIG_DEFAULT_DEVICE_TREE="sandbox"
|
||||
CONFIG_I8042_KEYB=y
|
||||
CONFIG_SPL=y
|
||||
CONFIG_FIT=y
|
||||
CONFIG_FIT_VERBOSE=y
|
||||
CONFIG_FIT_SIGNATURE=y
|
||||
CONFIG_SPL_LOAD_FIT=y
|
||||
CONFIG_BOOTSTAGE=y
|
||||
CONFIG_BOOTSTAGE_REPORT=y
|
||||
CONFIG_BOOTSTAGE_USER_COUNT=0x20
|
||||
CONFIG_BOOTSTAGE_FDT=y
|
||||
CONFIG_BOOTSTAGE_STASH=y
|
||||
CONFIG_BOOTSTAGE_STASH_ADDR=0x0
|
||||
CONFIG_BOOTSTAGE_STASH_SIZE=0x4096
|
||||
CONFIG_CONSOLE_RECORD=y
|
||||
CONFIG_CONSOLE_RECORD_OUT_SIZE=0x1000
|
||||
CONFIG_HUSH_PARSER=y
|
||||
CONFIG_CMD_CPU=y
|
||||
CONFIG_CMD_LICENSE=y
|
||||
CONFIG_CMD_BOOTZ=y
|
||||
# CONFIG_CMD_ELF is not set
|
||||
# CONFIG_CMD_IMLS is not set
|
||||
CONFIG_CMD_ASKENV=y
|
||||
CONFIG_CMD_GREPENV=y
|
||||
CONFIG_LOOPW=y
|
||||
CONFIG_CMD_MEMTEST=y
|
||||
CONFIG_CMD_MX_CYCLIC=y
|
||||
CONFIG_CMD_MEMINFO=y
|
||||
CONFIG_CMD_DEMO=y
|
||||
CONFIG_CMD_SF=y
|
||||
CONFIG_CMD_SPI=y
|
||||
CONFIG_CMD_I2C=y
|
||||
CONFIG_CMD_USB=y
|
||||
CONFIG_CMD_REMOTEPROC=y
|
||||
CONFIG_CMD_GPIO=y
|
||||
CONFIG_CMD_TFTPPUT=y
|
||||
CONFIG_CMD_TFTPSRV=y
|
||||
CONFIG_CMD_RARP=y
|
||||
CONFIG_CMD_DHCP=y
|
||||
CONFIG_CMD_MII=y
|
||||
CONFIG_CMD_PING=y
|
||||
CONFIG_CMD_CDP=y
|
||||
CONFIG_CMD_SNTP=y
|
||||
CONFIG_CMD_DNS=y
|
||||
CONFIG_CMD_LINK_LOCAL=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_EXT2=y
|
||||
CONFIG_CMD_EXT4=y
|
||||
CONFIG_CMD_EXT4_WRITE=y
|
||||
CONFIG_CMD_FAT=y
|
||||
CONFIG_CMD_FS_GENERIC=y
|
||||
CONFIG_OF_CONTROL=y
|
||||
CONFIG_SPL_OF_CONTROL=y
|
||||
CONFIG_OF_HOSTFILE=y
|
||||
CONFIG_SPL_OF_PLATDATA=y
|
||||
CONFIG_NETCONSOLE=y
|
||||
CONFIG_SPL_DM=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_BLK=y
|
||||
CONFIG_CLK=y
|
||||
CONFIG_CPU=y
|
||||
CONFIG_DM_DEMO=y
|
||||
CONFIG_DM_DEMO_SIMPLE=y
|
||||
CONFIG_DM_DEMO_SHAPE=y
|
||||
CONFIG_PM8916_GPIO=y
|
||||
CONFIG_SANDBOX_GPIO=y
|
||||
CONFIG_DM_I2C_COMPAT=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_SPL_I2C_MUX=y
|
||||
CONFIG_I2C_ARB_GPIO_CHALLENGE=y
|
||||
CONFIG_CROS_EC_KEYB=y
|
||||
CONFIG_LED=y
|
||||
CONFIG_LED_GPIO=y
|
||||
CONFIG_DM_MAILBOX=y
|
||||
CONFIG_SANDBOX_MBOX=y
|
||||
CONFIG_MISC=y
|
||||
CONFIG_CMD_CROS_EC=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_PWRSEQ=y
|
||||
CONFIG_SPL_PWRSEQ=y
|
||||
CONFIG_SYSRESET=y
|
||||
CONFIG_DM_MMC_OPS=y
|
||||
CONFIG_SANDBOX_MMC=y
|
||||
CONFIG_SPI_FLASH_SANDBOX=y
|
||||
CONFIG_SPI_FLASH=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_DM_PCI=y
|
||||
CONFIG_DM_PCI_COMPAT=y
|
||||
CONFIG_PCI_SANDBOX=y
|
||||
CONFIG_PINCTRL=y
|
||||
CONFIG_PINCONF=y
|
||||
CONFIG_ROCKCHIP_PINCTRL=y
|
||||
CONFIG_ROCKCHIP_3036_PINCTRL=y
|
||||
CONFIG_PINCTRL_SANDBOX=y
|
||||
CONFIG_DM_PMIC=y
|
||||
CONFIG_PMIC_ACT8846=y
|
||||
CONFIG_DM_PMIC_PFUZE100=y
|
||||
CONFIG_DM_PMIC_MAX77686=y
|
||||
CONFIG_PMIC_PM8916=y
|
||||
CONFIG_PMIC_RK808=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_RK808=y
|
||||
CONFIG_REGULATOR_S5M8767=y
|
||||
CONFIG_DM_REGULATOR_SANDBOX=y
|
||||
CONFIG_REGULATOR_TPS65090=y
|
||||
CONFIG_RAM=y
|
||||
CONFIG_REMOTEPROC_SANDBOX=y
|
||||
CONFIG_DM_RESET=y
|
||||
CONFIG_SANDBOX_RESET=y
|
||||
CONFIG_DM_RTC=y
|
||||
CONFIG_SANDBOX_SERIAL=y
|
||||
CONFIG_SOUND=y
|
||||
CONFIG_SOUND_SANDBOX=y
|
||||
CONFIG_SANDBOX_SPI=y
|
||||
CONFIG_SPMI=y
|
||||
CONFIG_SPMI_SANDBOX=y
|
||||
CONFIG_TIMER=y
|
||||
CONFIG_TIMER_EARLY=y
|
||||
CONFIG_SANDBOX_TIMER=y
|
||||
CONFIG_TPM_TIS_SANDBOX=y
|
||||
CONFIG_USB=y
|
||||
CONFIG_DM_USB=y
|
||||
CONFIG_USB_EMUL=y
|
||||
CONFIG_USB_STORAGE=y
|
||||
CONFIG_USB_KEYBOARD=y
|
||||
CONFIG_SYS_USB_EVENT_POLL=y
|
||||
CONFIG_DM_VIDEO=y
|
||||
CONFIG_CONSOLE_ROTATION=y
|
||||
CONFIG_CONSOLE_TRUETYPE=y
|
||||
CONFIG_CONSOLE_TRUETYPE_CANTORAONE=y
|
||||
CONFIG_VIDEO_SANDBOX_SDL=y
|
||||
CONFIG_CMD_DHRYSTONE=y
|
||||
CONFIG_TPM=y
|
||||
CONFIG_LZ4=y
|
||||
CONFIG_ERRNO_STR=y
|
||||
CONFIG_UNIT_TEST=y
|
||||
CONFIG_UT_TIME=y
|
||||
CONFIG_UT_DM=y
|
||||
CONFIG_UT_ENV=y
|
310
doc/driver-model/of-plat.txt
Normal file
310
doc/driver-model/of-plat.txt
Normal file
@ -0,0 +1,310 @@
|
||||
Driver Model 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_DEVICE() 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 SPL_OF_PLATDATA. This is only available
|
||||
in SPL and should be tested with:
|
||||
|
||||
#if CONFIG_IS_ENABLED(SPL_OF_PLATDATA)
|
||||
|
||||
A new tool called 'dtoc' converts a device tree file either into a set of
|
||||
struct declarations, one for each compatible node, or a set of
|
||||
U_BOOT_DEVICE() declarations along with the actual platform data for each
|
||||
device. As an example, consider this MMC node:
|
||||
|
||||
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:
|
||||
|
||||
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_2_cell 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 declaration:
|
||||
|
||||
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 = {{&dtv_clock_controller_at_ff760000, 456},
|
||||
{&dtv_clock_controller_at_ff760000, 68},
|
||||
{&dtv_clock_controller_at_ff760000, 114},
|
||||
{&dtv_clock_controller_at_ff760000, 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_DEVICE(dwmmc_at_ff0c0000) = {
|
||||
.name = "rockchip_rk3288_dw_mshc",
|
||||
.platdata = &dtv_dwmmc_at_ff0c0000,
|
||||
.platdata_size = sizeof(dtv_dwmmc_at_ff0c0000),
|
||||
};
|
||||
|
||||
The device is then instantiated at run-time and the platform data can be
|
||||
accessed using:
|
||||
|
||||
struct udevice *dev;
|
||||
struct dtd_rockchip_rk3288_dw_mshc *plat = dev_get_platdata(dev);
|
||||
|
||||
This avoids the code overhead of converting the device tree data to
|
||||
platform data in the driver. The ofdata_to_platdata() method should
|
||||
therefore do nothing in such a driver.
|
||||
|
||||
|
||||
Converting of-platdata to a useful form
|
||||
---------------------------------------
|
||||
|
||||
Of course it would be possible use the of-platdata directly in your driver
|
||||
whenever configuration information is required. However this meands 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
|
||||
ofdata_to_platdata() 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 platdata struct in its probe() method. The
|
||||
existing device tree decoding logic should be kept in the
|
||||
ofdata_to_platdata() method and wrapped with #if.
|
||||
|
||||
For example:
|
||||
|
||||
#include <dt-structs.h>
|
||||
|
||||
struct mmc_platdata {
|
||||
#if CONFIG_IS_ENABLED(SPL_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_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
#if !CONFIG_IS_ENABLED(SPL_OF_PLATDATA)
|
||||
/* Decode the device tree data */
|
||||
struct mmc_platdata *plat = dev_get_platdata(dev);
|
||||
const void *blob = gd->fdt_blob;
|
||||
int node = dev->of_offset;
|
||||
|
||||
plat->fifo_depth = fdtdec_get_int(blob, node, "fifo-depth", 0);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mmc_probe(struct udevice *dev)
|
||||
{
|
||||
struct mmc_platdata *plat = dev_get_platdata(dev);
|
||||
|
||||
#if CONFIG_IS_ENABLED(SPL_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",
|
||||
.id = UCLASS_MMC,
|
||||
.of_match = mmc_ids,
|
||||
.ofdata_to_platdata = mmc_ofdata_to_platdata,
|
||||
.probe = mmc_probe,
|
||||
.priv_auto_alloc_size = sizeof(struct mmc_priv),
|
||||
.platdata_auto_alloc_size = sizeof(struct mmc_platdata),
|
||||
};
|
||||
|
||||
|
||||
In the case where SPL_OF_PLATDATA is enabled, platdata_auto_alloc_size 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 platdata_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
|
||||
ofdata_to_platdata() 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(SPL_OF_PLATDATA).
|
||||
|
||||
The dt-platdata.c file contains the device declarations and is is built in
|
||||
spl/dt-platdata.c.
|
||||
|
||||
Some phandles (thsoe that are recognised as such) are converted into
|
||||
points to platform data. This pointer can potentially be used to access the
|
||||
referenced device (by searching for the pointer value). This feature is not
|
||||
yet implemented, however.
|
||||
|
||||
The beginnings of a libfdt Python module are provided. So far this only
|
||||
implements a subset of the features.
|
||||
|
||||
The 'swig' tool is needed to build the libfdt Python module. If this is not
|
||||
found then the Python model is not used and a fallback is used instead, which
|
||||
makes use of fdtget.
|
||||
|
||||
|
||||
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
|
||||
- Complete the phandle feature
|
||||
- Move to using a full Python libfdt module
|
||||
|
||||
--
|
||||
Simon Glass <sjg@chromium.org>
|
||||
Google, Inc
|
||||
6/6/16
|
||||
Updated Independence Day 2016
|
@ -10,6 +10,7 @@
|
||||
#include <clk.h>
|
||||
#include <clk-uclass.h>
|
||||
#include <dm.h>
|
||||
#include <dt-structs.h>
|
||||
#include <errno.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
@ -21,6 +22,22 @@ static inline struct clk_ops *clk_dev_ops(struct udevice *dev)
|
||||
|
||||
#if CONFIG_IS_ENABLED(OF_CONTROL)
|
||||
#ifdef CONFIG_SPL_BUILD
|
||||
# if CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
int clk_get_by_index_platdata(struct udevice *dev, int index,
|
||||
struct phandle_2_cell *cells, struct clk *clk)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (index != 0)
|
||||
return -ENOSYS;
|
||||
ret = uclass_get_device(UCLASS_CLK, 0, &clk->dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
clk->id = cells[0].id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
# else
|
||||
int clk_get_by_index(struct udevice *dev, int index, struct clk *clk)
|
||||
{
|
||||
int ret;
|
||||
@ -39,6 +56,7 @@ int clk_get_by_index(struct udevice *dev, int index, struct clk *clk)
|
||||
clk->id = cell[1];
|
||||
return 0;
|
||||
}
|
||||
# endif /* OF_PLATDATA */
|
||||
|
||||
int clk_get_by_name(struct udevice *dev, const char *name, struct clk *clk)
|
||||
{
|
||||
@ -117,8 +135,8 @@ int clk_get_by_name(struct udevice *dev, const char *name, struct clk *clk)
|
||||
|
||||
return clk_get_by_index(dev, index, clk);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif /* CONFIG_SPL_BUILD */
|
||||
#endif /* OF_CONTROL */
|
||||
|
||||
int clk_request(struct udevice *dev, struct clk *clk)
|
||||
{
|
||||
|
@ -30,9 +30,11 @@ const struct clk_ops clk_fixed_rate_ops = {
|
||||
|
||||
static int clk_fixed_rate_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
to_clk_fixed_rate(dev)->fixed_rate =
|
||||
fdtdec_get_int(gd->fdt_blob, dev->of_offset,
|
||||
"clock-frequency", 0);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -7,7 +7,9 @@
|
||||
#include <common.h>
|
||||
#include <clk-uclass.h>
|
||||
#include <dm.h>
|
||||
#include <dt-structs.h>
|
||||
#include <errno.h>
|
||||
#include <mapmem.h>
|
||||
#include <syscon.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/clock.h>
|
||||
@ -21,6 +23,12 @@
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
struct rk3288_clk_plat {
|
||||
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
struct dtd_rockchip_rk3288_cru dtd;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct rk3288_clk_priv {
|
||||
struct rk3288_grf *grf;
|
||||
struct rk3288_cru *cru;
|
||||
@ -783,13 +791,30 @@ static struct clk_ops rk3288_clk_ops = {
|
||||
.set_rate = rk3288_clk_set_rate,
|
||||
};
|
||||
|
||||
static int rk3288_clk_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
struct rk3288_clk_priv *priv = dev_get_priv(dev);
|
||||
|
||||
priv->cru = (struct rk3288_cru *)dev_get_addr(dev);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk3288_clk_probe(struct udevice *dev)
|
||||
{
|
||||
struct rk3288_clk_priv *priv = dev_get_priv(dev);
|
||||
|
||||
priv->cru = (struct rk3288_cru *)dev_get_addr(dev);
|
||||
priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
|
||||
if (IS_ERR(priv->grf))
|
||||
return PTR_ERR(priv->grf);
|
||||
#ifdef CONFIG_SPL_BUILD
|
||||
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
struct rk3288_clk_plat *plat = dev_get_platdata(dev);
|
||||
|
||||
priv->cru = map_sysmem(plat->dtd.reg[0], plat->dtd.reg[1]);
|
||||
#endif
|
||||
rkclk_init(priv->cru, priv->grf);
|
||||
#endif
|
||||
|
||||
@ -813,12 +838,14 @@ static const struct udevice_id rk3288_clk_ids[] = {
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(clk_rk3288) = {
|
||||
.name = "clk_rk3288",
|
||||
U_BOOT_DRIVER(rockchip_rk3288_cru) = {
|
||||
.name = "rockchip_rk3288_cru",
|
||||
.id = UCLASS_CLK,
|
||||
.of_match = rk3288_clk_ids,
|
||||
.priv_auto_alloc_size = sizeof(struct rk3288_clk_priv),
|
||||
.platdata_auto_alloc_size = sizeof(struct rk3288_clk_plat),
|
||||
.ops = &rk3288_clk_ops,
|
||||
.bind = rk3288_clk_bind,
|
||||
.ofdata_to_platdata = rk3288_clk_ofdata_to_platdata,
|
||||
.probe = rk3288_clk_probe,
|
||||
};
|
||||
|
@ -112,7 +112,7 @@ int device_unbind(struct udevice *dev)
|
||||
|
||||
devres_release_all(dev);
|
||||
|
||||
if (dev->flags & DM_NAME_ALLOCED)
|
||||
if (dev->flags & DM_FLAG_NAME_ALLOCED)
|
||||
free((char *)dev->name);
|
||||
free(dev);
|
||||
|
||||
|
@ -30,7 +30,7 @@ DECLARE_GLOBAL_DATA_PTR;
|
||||
static int device_bind_common(struct udevice *parent, const struct driver *drv,
|
||||
const char *name, void *platdata,
|
||||
ulong driver_data, int of_offset,
|
||||
struct udevice **devp)
|
||||
uint of_platdata_size, struct udevice **devp)
|
||||
{
|
||||
struct udevice *dev;
|
||||
struct uclass *uc;
|
||||
@ -84,12 +84,29 @@ static int device_bind_common(struct udevice *parent, const struct driver *drv,
|
||||
}
|
||||
}
|
||||
|
||||
if (!dev->platdata && drv->platdata_auto_alloc_size) {
|
||||
dev->flags |= DM_FLAG_ALLOC_PDATA;
|
||||
dev->platdata = calloc(1, drv->platdata_auto_alloc_size);
|
||||
if (!dev->platdata) {
|
||||
ret = -ENOMEM;
|
||||
goto fail_alloc1;
|
||||
if (drv->platdata_auto_alloc_size) {
|
||||
bool alloc = !platdata;
|
||||
|
||||
if (CONFIG_IS_ENABLED(OF_PLATDATA)) {
|
||||
if (of_platdata_size) {
|
||||
dev->flags |= DM_FLAG_OF_PLATDATA;
|
||||
if (of_platdata_size <
|
||||
drv->platdata_auto_alloc_size)
|
||||
alloc = true;
|
||||
}
|
||||
}
|
||||
if (alloc) {
|
||||
dev->flags |= DM_FLAG_ALLOC_PDATA;
|
||||
dev->platdata = calloc(1,
|
||||
drv->platdata_auto_alloc_size);
|
||||
if (!dev->platdata) {
|
||||
ret = -ENOMEM;
|
||||
goto fail_alloc1;
|
||||
}
|
||||
if (CONFIG_IS_ENABLED(OF_PLATDATA) && platdata) {
|
||||
memcpy(dev->platdata, platdata,
|
||||
of_platdata_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -202,14 +219,14 @@ int device_bind_with_driver_data(struct udevice *parent,
|
||||
struct udevice **devp)
|
||||
{
|
||||
return device_bind_common(parent, drv, name, NULL, driver_data,
|
||||
of_offset, devp);
|
||||
of_offset, 0, devp);
|
||||
}
|
||||
|
||||
int device_bind(struct udevice *parent, const struct driver *drv,
|
||||
const char *name, void *platdata, int of_offset,
|
||||
struct udevice **devp)
|
||||
{
|
||||
return device_bind_common(parent, drv, name, platdata, 0, of_offset,
|
||||
return device_bind_common(parent, drv, name, platdata, 0, of_offset, 0,
|
||||
devp);
|
||||
}
|
||||
|
||||
@ -217,6 +234,7 @@ int device_bind_by_name(struct udevice *parent, bool pre_reloc_only,
|
||||
const struct driver_info *info, struct udevice **devp)
|
||||
{
|
||||
struct driver *drv;
|
||||
uint platdata_size = 0;
|
||||
|
||||
drv = lists_driver_lookup_name(info->name);
|
||||
if (!drv)
|
||||
@ -224,8 +242,11 @@ int device_bind_by_name(struct udevice *parent, bool pre_reloc_only,
|
||||
if (pre_reloc_only && !(drv->flags & DM_FLAG_PRE_RELOC))
|
||||
return -EPERM;
|
||||
|
||||
return device_bind(parent, drv, info->name, (void *)info->platdata,
|
||||
-1, devp);
|
||||
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
platdata_size = info->platdata_size;
|
||||
#endif
|
||||
return device_bind_common(parent, drv, info->name,
|
||||
(void *)info->platdata, 0, -1, platdata_size, devp);
|
||||
}
|
||||
|
||||
static void *alloc_priv(int size, uint flags)
|
||||
@ -608,7 +629,7 @@ const char *dev_get_uclass_name(struct udevice *dev)
|
||||
|
||||
fdt_addr_t dev_get_addr_index(struct udevice *dev, int index)
|
||||
{
|
||||
#if CONFIG_IS_ENABLED(OF_CONTROL)
|
||||
#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
fdt_addr_t addr;
|
||||
|
||||
if (CONFIG_IS_ENABLED(OF_TRANSLATE)) {
|
||||
@ -738,7 +759,7 @@ bool device_is_last_sibling(struct udevice *dev)
|
||||
|
||||
void device_set_name_alloced(struct udevice *dev)
|
||||
{
|
||||
dev->flags |= DM_NAME_ALLOCED;
|
||||
dev->flags |= DM_FLAG_NAME_ALLOCED;
|
||||
}
|
||||
|
||||
int device_set_name(struct udevice *dev, const char *name)
|
||||
|
@ -99,7 +99,7 @@ int device_bind_driver_to_node(struct udevice *parent, const char *drv_name,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if CONFIG_IS_ENABLED(OF_CONTROL)
|
||||
#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
/**
|
||||
* driver_check_compatible() - Check if a driver is compatible with this node
|
||||
*
|
||||
|
@ -15,6 +15,49 @@
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
static struct regmap *regmap_alloc_count(int count)
|
||||
{
|
||||
struct regmap *map;
|
||||
|
||||
map = malloc(sizeof(struct regmap));
|
||||
if (!map)
|
||||
return NULL;
|
||||
if (count <= 1) {
|
||||
map->range = &map->base_range;
|
||||
} else {
|
||||
map->range = malloc(count * sizeof(struct regmap_range));
|
||||
if (!map->range) {
|
||||
free(map);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
map->range_count = count;
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
int regmap_init_mem_platdata(struct udevice *dev, u32 *reg, int count,
|
||||
struct regmap **mapp)
|
||||
{
|
||||
struct regmap_range *range;
|
||||
struct regmap *map;
|
||||
|
||||
map = regmap_alloc_count(count);
|
||||
if (!map)
|
||||
return -ENOMEM;
|
||||
|
||||
map->base = *reg;
|
||||
for (range = map->range; count > 0; reg += 2, range++, count--) {
|
||||
range->start = *reg;
|
||||
range->size = reg[1];
|
||||
}
|
||||
|
||||
*mapp = map;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
int regmap_init_mem(struct udevice *dev, struct regmap **mapp)
|
||||
{
|
||||
const void *blob = gd->fdt_blob;
|
||||
@ -37,22 +80,11 @@ int regmap_init_mem(struct udevice *dev, struct regmap **mapp)
|
||||
if (!cell || !count)
|
||||
return -EINVAL;
|
||||
|
||||
map = malloc(sizeof(struct regmap));
|
||||
map = regmap_alloc_count(count);
|
||||
if (!map)
|
||||
return -ENOMEM;
|
||||
|
||||
if (count <= 1) {
|
||||
map->range = &map->base_range;
|
||||
} else {
|
||||
map->range = malloc(count * sizeof(struct regmap_range));
|
||||
if (!map->range) {
|
||||
free(map);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
map->base = fdtdec_get_number(cell, addr_len);
|
||||
map->range_count = count;
|
||||
|
||||
for (range = map->range; count > 0;
|
||||
count--, cell += both_len, range++) {
|
||||
@ -64,6 +96,7 @@ int regmap_init_mem(struct udevice *dev, struct regmap **mapp)
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void *regmap_get_range(struct regmap *map, unsigned int range_num)
|
||||
{
|
||||
|
@ -188,7 +188,7 @@ int dm_scan_platdata(bool pre_reloc_only)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if CONFIG_IS_ENABLED(OF_CONTROL)
|
||||
#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
int dm_scan_fdt_node(struct udevice *parent, const void *blob, int offset,
|
||||
bool pre_reloc_only)
|
||||
{
|
||||
@ -244,7 +244,7 @@ int dm_init_and_scan(bool pre_reloc_only)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (CONFIG_IS_ENABLED(OF_CONTROL)) {
|
||||
if (CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)) {
|
||||
ret = dm_scan_fdt(gd->fdt_blob, pre_reloc_only);
|
||||
if (ret) {
|
||||
debug("dm_scan_fdt() failed: %d\n", ret);
|
||||
|
@ -29,7 +29,20 @@ static int syscon_pre_probe(struct udevice *dev)
|
||||
{
|
||||
struct syscon_uc_info *priv = dev_get_uclass_priv(dev);
|
||||
|
||||
/*
|
||||
* With OF_PLATDATA we really have no way of knowing the format of
|
||||
* the device-specific platform data. So we assume that it starts with
|
||||
* a 'reg' member, and this holds a single address and size. Drivers
|
||||
* using OF_PLATDATA will need to ensure that this is true.
|
||||
*/
|
||||
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
struct syscon_base_platdata *plat = dev_get_platdata(dev);
|
||||
|
||||
return regmap_init_mem_platdata(dev, plat->reg, ARRAY_SIZE(plat->reg),
|
||||
&priv->regmap);
|
||||
#else
|
||||
return regmap_init_mem(dev, &priv->regmap);
|
||||
#endif
|
||||
}
|
||||
|
||||
int syscon_get_by_driver_data(ulong driver_data, struct udevice **devp)
|
||||
|
@ -29,12 +29,19 @@ obj-$(CONFIG_PDSP188x) += pdsp188x.o
|
||||
obj-$(CONFIG_$(SPL_)PWRSEQ) += pwrseq-uclass.o
|
||||
obj-$(CONFIG_SANDBOX) += sysreset_sandbox.o
|
||||
ifdef CONFIG_DM_I2C
|
||||
ifndef CONFIG_SPL_BUILD
|
||||
obj-$(CONFIG_SANDBOX) += i2c_eeprom_emul.o
|
||||
endif
|
||||
endif
|
||||
obj-$(CONFIG_SMSC_LPC47M) += smsc_lpc47m.o
|
||||
obj-$(CONFIG_SMSC_SIO1007) += smsc_sio1007.o
|
||||
obj-$(CONFIG_STATUS_LED) += status_led.o
|
||||
obj-$(CONFIG_SANDBOX) += swap_case.o
|
||||
ifdef CONFIG_SPL_OF_PLATDATA
|
||||
ifdef CONFIG_SPL_BUILD
|
||||
obj-$(CONFIG_SANDBOX) += spltest_sandbox.o
|
||||
endif
|
||||
endif
|
||||
obj-$(CONFIG_SANDBOX) += syscon_sandbox.o
|
||||
obj-$(CONFIG_TWL4030_LED) += twl4030_led.o
|
||||
obj-$(CONFIG_FSL_IFC) += fsl_ifc.o
|
||||
|
53
drivers/misc/spltest_sandbox.c
Normal file
53
drivers/misc/spltest_sandbox.c
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Google, Inc
|
||||
* Written by Simon Glass <sjg@chromium.org>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <dt-structs.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
static int sandbox_spl_probe(struct udevice *dev)
|
||||
{
|
||||
struct dtd_sandbox_spl_test *plat = dev_get_platdata(dev);
|
||||
int i;
|
||||
|
||||
printf("of-platdata probe:\n");
|
||||
printf("bool %d\n", plat->boolval);
|
||||
|
||||
printf("byte %02x\n", plat->byteval);
|
||||
printf("bytearray");
|
||||
for (i = 0; i < sizeof(plat->bytearray); i++)
|
||||
printf(" %02x", plat->bytearray[i]);
|
||||
printf("\n");
|
||||
|
||||
printf("int %d\n", plat->intval);
|
||||
printf("intarray");
|
||||
for (i = 0; i < ARRAY_SIZE(plat->intarray); i++)
|
||||
printf(" %d", plat->intarray[i]);
|
||||
printf("\n");
|
||||
|
||||
printf("longbytearray");
|
||||
for (i = 0; i < sizeof(plat->longbytearray); i++)
|
||||
printf(" %02x", plat->longbytearray[i]);
|
||||
printf("\n");
|
||||
|
||||
printf("string %s\n", plat->stringval);
|
||||
printf("stringarray");
|
||||
for (i = 0; i < ARRAY_SIZE(plat->stringarray); i++)
|
||||
printf(" \"%s\"", plat->stringarray[i]);
|
||||
printf("\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_DRIVER(sandbox_spl_test) = {
|
||||
.name = "sandbox_spl_test",
|
||||
.id = UCLASS_MISC,
|
||||
.flags = DM_FLAG_PRE_RELOC,
|
||||
.probe = sandbox_spl_probe,
|
||||
};
|
@ -7,8 +7,10 @@
|
||||
#include <common.h>
|
||||
#include <clk.h>
|
||||
#include <dm.h>
|
||||
#include <dt-structs.h>
|
||||
#include <dwmmc.h>
|
||||
#include <errno.h>
|
||||
#include <mapmem.h>
|
||||
#include <pwrseq.h>
|
||||
#include <syscon.h>
|
||||
#include <asm/gpio.h>
|
||||
@ -19,6 +21,9 @@
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
struct rockchip_mmc_plat {
|
||||
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
struct dtd_rockchip_rk3288_dw_mshc dtplat;
|
||||
#endif
|
||||
struct mmc_config cfg;
|
||||
struct mmc mmc;
|
||||
};
|
||||
@ -26,6 +31,9 @@ struct rockchip_mmc_plat {
|
||||
struct rockchip_dwmmc_priv {
|
||||
struct clk clk;
|
||||
struct dwmci_host host;
|
||||
int fifo_depth;
|
||||
bool fifo_mode;
|
||||
u32 minmax[2];
|
||||
};
|
||||
|
||||
static uint rockchip_dwmmc_get_mmc_clk(struct dwmci_host *host, uint freq)
|
||||
@ -45,6 +53,7 @@ static uint rockchip_dwmmc_get_mmc_clk(struct dwmci_host *host, uint freq)
|
||||
|
||||
static int rockchip_dwmmc_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
struct rockchip_dwmmc_priv *priv = dev_get_priv(dev);
|
||||
struct dwmci_host *host = &priv->host;
|
||||
|
||||
@ -61,6 +70,16 @@ static int rockchip_dwmmc_ofdata_to_platdata(struct udevice *dev)
|
||||
else
|
||||
host->dev_index = 1;
|
||||
|
||||
priv->fifo_depth = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
|
||||
"fifo-depth", 0);
|
||||
if (priv->fifo_depth < 0)
|
||||
return -EINVAL;
|
||||
priv->fifo_mode = fdtdec_get_bool(gd->fdt_blob, dev->of_offset,
|
||||
"fifo-mode");
|
||||
if (fdtdec_get_int_array(gd->fdt_blob, dev->of_offset,
|
||||
"clock-freq-min-max", priv->minmax, 2))
|
||||
return -EINVAL;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -71,28 +90,34 @@ static int rockchip_dwmmc_probe(struct udevice *dev)
|
||||
struct rockchip_dwmmc_priv *priv = dev_get_priv(dev);
|
||||
struct dwmci_host *host = &priv->host;
|
||||
struct udevice *pwr_dev __maybe_unused;
|
||||
u32 minmax[2];
|
||||
int ret;
|
||||
int fifo_depth;
|
||||
|
||||
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
struct dtd_rockchip_rk3288_dw_mshc *dtplat = &plat->dtplat;
|
||||
|
||||
host->name = dev->name;
|
||||
host->ioaddr = map_sysmem(dtplat->reg[0], dtplat->reg[1]);
|
||||
host->buswidth = dtplat->bus_width;
|
||||
host->get_mmc_clk = rockchip_dwmmc_get_mmc_clk;
|
||||
host->priv = dev;
|
||||
host->dev_index = 0;
|
||||
priv->fifo_depth = dtplat->fifo_depth;
|
||||
priv->fifo_mode = 0;
|
||||
memcpy(priv->minmax, dtplat->clock_freq_min_max, sizeof(priv->minmax));
|
||||
|
||||
ret = clk_get_by_index_platdata(dev, 0, dtplat->clocks, &priv->clk);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
#else
|
||||
ret = clk_get_by_index(dev, 0, &priv->clk);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (fdtdec_get_int_array(gd->fdt_blob, dev->of_offset,
|
||||
"clock-freq-min-max", minmax, 2))
|
||||
return -EINVAL;
|
||||
|
||||
fifo_depth = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
|
||||
"fifo-depth", 0);
|
||||
if (fifo_depth < 0)
|
||||
return -EINVAL;
|
||||
|
||||
#endif
|
||||
host->fifoth_val = MSIZE(0x2) |
|
||||
RX_WMARK(fifo_depth / 2 - 1) | TX_WMARK(fifo_depth / 2);
|
||||
RX_WMARK(priv->fifo_depth / 2 - 1) |
|
||||
TX_WMARK(priv->fifo_depth / 2);
|
||||
|
||||
if (fdtdec_get_bool(gd->fdt_blob, dev->of_offset, "fifo-mode"))
|
||||
host->fifo_mode = true;
|
||||
host->fifo_mode = priv->fifo_mode;
|
||||
|
||||
#ifdef CONFIG_PWRSEQ
|
||||
/* Enable power if needed */
|
||||
@ -105,7 +130,7 @@ static int rockchip_dwmmc_probe(struct udevice *dev)
|
||||
}
|
||||
#endif
|
||||
dwmci_setup_cfg(&plat->cfg, dev->name, host->buswidth, host->caps,
|
||||
minmax[1], minmax[0]);
|
||||
priv->minmax[1], priv->minmax[0]);
|
||||
host->mmc = &plat->mmc;
|
||||
host->mmc->priv = &priv->host;
|
||||
host->mmc->dev = dev;
|
||||
@ -132,7 +157,7 @@ static const struct udevice_id rockchip_dwmmc_ids[] = {
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(rockchip_dwmmc_drv) = {
|
||||
.name = "rockchip_dwmmc",
|
||||
.name = "rockchip_rk3288_dw_mshc",
|
||||
.id = UCLASS_MMC,
|
||||
.of_match = rockchip_dwmmc_ids,
|
||||
.ofdata_to_platdata = rockchip_dwmmc_ofdata_to_platdata,
|
||||
|
@ -476,6 +476,7 @@ static int rk3288_pinctrl_request(struct udevice *dev, int func, int flags)
|
||||
static int rk3288_pinctrl_get_periph_id(struct udevice *dev,
|
||||
struct udevice *periph)
|
||||
{
|
||||
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
u32 cell[3];
|
||||
int ret;
|
||||
|
||||
@ -506,6 +507,7 @@ static int rk3288_pinctrl_get_periph_id(struct udevice *dev,
|
||||
case 103:
|
||||
return PERIPH_ID_HDMI;
|
||||
}
|
||||
#endif
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
@ -664,8 +666,12 @@ static struct pinctrl_ops rk3288_pinctrl_ops = {
|
||||
|
||||
static int rk3288_pinctrl_bind(struct udevice *dev)
|
||||
{
|
||||
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
return 0;
|
||||
#else
|
||||
/* scan child GPIO banks */
|
||||
return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef CONFIG_SPL_BUILD
|
||||
@ -719,7 +725,7 @@ static const struct udevice_id rk3288_pinctrl_ids[] = {
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(pinctrl_rk3288) = {
|
||||
.name = "pinctrl_rk3288",
|
||||
.name = "rockchip_rk3288_pinctrl",
|
||||
.id = UCLASS_PINCTRL,
|
||||
.of_match = rk3288_pinctrl_ids,
|
||||
.priv_auto_alloc_size = sizeof(struct rk3288_pinctrl_priv),
|
||||
|
@ -312,6 +312,15 @@ config SYS_NS16550
|
||||
be used. It can be a constant or a function to get clock, eg,
|
||||
get_serial_clock().
|
||||
|
||||
config ROCKCHIP_SERIAL
|
||||
bool "Rockchip on-chip UART support"
|
||||
depends on DM_SERIAL && SPL_OF_PLATDATA
|
||||
help
|
||||
Select this to enable a debug UART for Rockchip devices when using
|
||||
CONFIG_OF_PLATDATA (i.e. a compiled-in device tree replacemenmt).
|
||||
This uses the ns16550 driver, converting the platdata from of-platdata
|
||||
to the ns16550 format.
|
||||
|
||||
config SANDBOX_SERIAL
|
||||
bool "Sandbox UART support"
|
||||
depends on SANDBOX
|
||||
|
@ -28,6 +28,9 @@ obj-$(CONFIG_S5P) += serial_s5p.o
|
||||
obj-$(CONFIG_MXC_UART) += serial_mxc.o
|
||||
obj-$(CONFIG_PXA_SERIAL) += serial_pxa.o
|
||||
obj-$(CONFIG_MESON_SERIAL) += serial_meson.o
|
||||
ifdef CONFIG_SPL_BUILD
|
||||
obj-$(CONFIG_ROCKCHIP_SERIAL) += serial_rockchip.o
|
||||
endif
|
||||
obj-$(CONFIG_S3C24X0_SERIAL) += serial_s3c24x0.o
|
||||
obj-$(CONFIG_XILINX_UARTLITE) += serial_xuartlite.o
|
||||
obj-$(CONFIG_SANDBOX_SERIAL) += sandbox.o
|
||||
|
@ -347,7 +347,7 @@ int ns16550_serial_probe(struct udevice *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if CONFIG_IS_ENABLED(OF_CONTROL)
|
||||
#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
int ns16550_serial_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct ns16550_platdata *plat = dev->platdata;
|
||||
@ -416,6 +416,7 @@ const struct dm_serial_ops ns16550_serial_ops = {
|
||||
.setbrg = ns16550_serial_setbrg,
|
||||
};
|
||||
|
||||
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
#if CONFIG_IS_ENABLED(OF_CONTROL)
|
||||
/*
|
||||
* Please consider existing compatible strings before adding a new
|
||||
@ -452,4 +453,5 @@ U_BOOT_DRIVER(ns16550_serial) = {
|
||||
.flags = DM_FLAG_PRE_RELOC,
|
||||
};
|
||||
#endif
|
||||
#endif /* !OF_PLATDATA */
|
||||
#endif /* CONFIG_DM_SERIAL */
|
||||
|
@ -115,7 +115,9 @@ static int sandbox_serial_pending(struct udevice *dev, bool input)
|
||||
return 0;
|
||||
|
||||
os_usleep(100);
|
||||
#ifndef CONFIG_SPL_BUILD
|
||||
video_sync_all();
|
||||
#endif
|
||||
if (next_index == serial_buf_read)
|
||||
return 1; /* buffer full */
|
||||
|
||||
|
@ -33,7 +33,13 @@ static void serial_find_console_or_panic(void)
|
||||
struct udevice *dev;
|
||||
int node;
|
||||
|
||||
if (CONFIG_IS_ENABLED(OF_CONTROL) && blob) {
|
||||
if (CONFIG_IS_ENABLED(OF_PLATDATA)) {
|
||||
uclass_first_device(UCLASS_SERIAL, &dev);
|
||||
if (dev) {
|
||||
gd->cur_serial_dev = dev;
|
||||
return;
|
||||
}
|
||||
} else if (CONFIG_IS_ENABLED(OF_CONTROL) && blob) {
|
||||
/* Check for a chosen console */
|
||||
node = fdtdec_get_chosen_node(blob, "stdout-path");
|
||||
if (node < 0) {
|
||||
|
43
drivers/serial/serial_rockchip.c
Normal file
43
drivers/serial/serial_rockchip.c
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Google, Inc
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <debug_uart.h>
|
||||
#include <dm.h>
|
||||
#include <dt-structs.h>
|
||||
#include <ns16550.h>
|
||||
#include <serial.h>
|
||||
#include <asm/arch/clock.h>
|
||||
|
||||
struct rockchip_uart_platdata {
|
||||
struct dtd_rockchip_rk3288_uart dtplat;
|
||||
struct ns16550_platdata plat;
|
||||
};
|
||||
|
||||
struct dtd_rockchip_rk3288_uart *dtplat, s_dtplat;
|
||||
|
||||
static int rockchip_serial_probe(struct udevice *dev)
|
||||
{
|
||||
struct rockchip_uart_platdata *plat = dev_get_platdata(dev);
|
||||
|
||||
/* Create some new platform data for the standard driver */
|
||||
plat->plat.base = plat->dtplat.reg[0];
|
||||
plat->plat.reg_shift = plat->dtplat.reg_shift;
|
||||
plat->plat.clock = plat->dtplat.clock_frequency;
|
||||
dev->platdata = &plat->plat;
|
||||
|
||||
return ns16550_serial_probe(dev);
|
||||
}
|
||||
|
||||
U_BOOT_DRIVER(rockchip_rk3288_uart) = {
|
||||
.name = "rockchip_rk3288_uart",
|
||||
.id = UCLASS_SERIAL,
|
||||
.priv_auto_alloc_size = sizeof(struct NS16550),
|
||||
.platdata_auto_alloc_size = sizeof(struct rockchip_uart_platdata),
|
||||
.probe = rockchip_serial_probe,
|
||||
.ops = &ns16550_serial_ops,
|
||||
.flags = DM_FLAG_PRE_RELOC,
|
||||
};
|
21
dts/Kconfig
21
dts/Kconfig
@ -85,4 +85,25 @@ config OF_SPL_REMOVE_PROPS
|
||||
can be discarded. This option defines the list of properties to
|
||||
discard.
|
||||
|
||||
config SPL_OF_PLATDATA
|
||||
bool "Generate platform data for use in SPL"
|
||||
depends on SPL_OF_CONTROL
|
||||
help
|
||||
For very constrained SPL environments the overhead of decoding
|
||||
device tree nodes and converting their contents into platform data
|
||||
is too large. This overhead includes libfdt code as well as the
|
||||
device tree contents itself. The latter is fairly compact, but the
|
||||
former can add 3KB or more to a Thumb 2 Image.
|
||||
|
||||
This option enables generation of platform data from the device
|
||||
tree as C code. This code creates devices using U_BOOT_DEVICE()
|
||||
declarations. The benefit is that it allows driver code to access
|
||||
the platform data directly in C structures, avoidin the libfdt
|
||||
overhead.
|
||||
|
||||
This option works by generating C structure declarations for each
|
||||
compatible string, then adding platform data and U_BOOT_DEVICE
|
||||
declarations for each node. See README.platdata for more
|
||||
information.
|
||||
|
||||
endmenu
|
||||
|
@ -60,6 +60,10 @@ struct clk {
|
||||
};
|
||||
|
||||
#if CONFIG_IS_ENABLED(OF_CONTROL)
|
||||
struct phandle_2_cell;
|
||||
int clk_get_by_index_platdata(struct udevice *dev, int index,
|
||||
struct phandle_2_cell *cells, struct clk *clk);
|
||||
|
||||
/**
|
||||
* clock_get_by_index - Get/request a clock by integer index.
|
||||
*
|
||||
|
@ -16,8 +16,10 @@
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SPL_BUILD
|
||||
#define CONFIG_IO_TRACE
|
||||
#define CONFIG_CMD_IOTRACE
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_TIMER
|
||||
#define CONFIG_SYS_TIMER_RATE 1000000
|
||||
@ -192,6 +194,7 @@
|
||||
#define CONFIG_CMD_LZMADEC
|
||||
#define CONFIG_CMD_DATE
|
||||
|
||||
#ifndef CONFIG_SPL_BUILD
|
||||
#define CONFIG_CMD_IDE
|
||||
#define CONFIG_SYS_IDE_MAXBUS 1
|
||||
#define CONFIG_SYS_ATA_IDE0_OFFSET 0
|
||||
@ -201,6 +204,7 @@
|
||||
#define CONFIG_SYS_ATA_REG_OFFSET 1
|
||||
#define CONFIG_SYS_ATA_ALT_OFFSET 2
|
||||
#define CONFIG_SYS_ATA_STRIDE 4
|
||||
#endif
|
||||
|
||||
#define CONFIG_SCSI
|
||||
#define CONFIG_SCSI_AHCI_PLAT
|
||||
|
20
include/configs/sandbox_spl.h
Normal file
20
include/configs/sandbox_spl.h
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Google, Inc
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#ifndef __SANDBOX_SPL_CONFIG_H
|
||||
#define __SANDBOX_SPL_CONFIG_H
|
||||
|
||||
#include <configs/sandbox.h>
|
||||
|
||||
#define CONFIG_SPL_BOARD_INIT
|
||||
|
||||
#define CONFIG_SPL_DRIVERS_MISC_SUPPORT
|
||||
#define CONFIG_SPL_ENV_SUPPORT
|
||||
#define CONFIG_SPL_FRAMEWORK
|
||||
#define CONFIG_SPL_LIBCOMMON_SUPPORT
|
||||
#define CONFIG_SPL_LIBGENERIC_SUPPORT
|
||||
#define CONFIG_SPL_SERIAL_SUPPORT
|
||||
|
||||
#endif
|
@ -42,7 +42,9 @@ struct driver_info;
|
||||
#define DM_FLAG_BOUND (1 << 6)
|
||||
|
||||
/* Device name is allocated and should be freed on unbind() */
|
||||
#define DM_NAME_ALLOCED (1 << 7)
|
||||
#define DM_FLAG_NAME_ALLOCED (1 << 7)
|
||||
|
||||
#define DM_FLAG_OF_PLATDATA (1 << 8)
|
||||
|
||||
/**
|
||||
* struct udevice - An instance of a driver
|
||||
@ -553,7 +555,7 @@ int device_set_name(struct udevice *dev, const char *name);
|
||||
/**
|
||||
* device_set_name_alloced() - note that a device name is allocated
|
||||
*
|
||||
* This sets the DM_NAME_ALLOCED flag for the device, so that when it is
|
||||
* This sets the DM_FLAG_NAME_ALLOCED flag for the device, so that when it is
|
||||
* unbound the name will be freed. This avoids memory leaks.
|
||||
*
|
||||
* @dev: Device to update
|
||||
|
@ -22,10 +22,15 @@
|
||||
*
|
||||
* @name: Driver name
|
||||
* @platdata: Driver-specific platform data
|
||||
* @platdata_size: Size of platform data structure
|
||||
* @flags: Platform data flags (DM_FLAG_...)
|
||||
*/
|
||||
struct driver_info {
|
||||
const char *name;
|
||||
const void *platdata;
|
||||
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
uint platdata_size;
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
|
19
include/dt-structs.h
Normal file
19
include/dt-structs.h
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Google, Inc
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#ifndef __DT_STTUCTS
|
||||
#define __DT_STTUCTS
|
||||
|
||||
/* These structures may only be used in SPL */
|
||||
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
struct phandle_2_cell {
|
||||
const void *node;
|
||||
int id;
|
||||
};
|
||||
#include <generated/dt-structs.h>
|
||||
#endif
|
||||
|
||||
#endif
|
25
include/os.h
25
include/os.h
@ -286,6 +286,31 @@ int os_read_ram_buf(const char *fname);
|
||||
*/
|
||||
int os_jump_to_image(const void *dest, int size);
|
||||
|
||||
/**
|
||||
* os_find_u_boot() - Determine the path to U-Boot proper
|
||||
*
|
||||
* This function is intended to be called from within sandbox SPL. It uses
|
||||
* a few heuristics to find U-Boot proper. Normally it is either in the same
|
||||
* directory, or the directory above (since u-boot-spl is normally in an
|
||||
* spl/ subdirectory when built).
|
||||
*
|
||||
* @fname: Place to put full path to U-Boot
|
||||
* @maxlen: Maximum size of @fname
|
||||
* @return 0 if OK, -NOSPC if the filename is too large, -ENOENT if not found
|
||||
*/
|
||||
int os_find_u_boot(char *fname, int maxlen);
|
||||
|
||||
/**
|
||||
* os_spl_to_uboot() - Run U-Boot proper
|
||||
*
|
||||
* When called from SPL, this runs U-Boot proper. The filename is obtained by
|
||||
* calling os_find_u_boot().
|
||||
*
|
||||
* @fname: Full pathname to U-Boot executable
|
||||
* @return 0 if OK, -ve on error
|
||||
*/
|
||||
int os_spl_to_uboot(const char *fname);
|
||||
|
||||
/**
|
||||
* Read the current system time
|
||||
*
|
||||
|
@ -56,6 +56,22 @@ int regmap_read(struct regmap *map, uint offset, uint *valp);
|
||||
*/
|
||||
int regmap_init_mem(struct udevice *dev, struct regmap **mapp);
|
||||
|
||||
/**
|
||||
* regmap_init_mem_platdata() - Set up a new memory register map for of-platdata
|
||||
*
|
||||
* This creates a new regmap with a list of regions passed in, rather than
|
||||
* using the device tree. It only supports 32-bit machines.
|
||||
*
|
||||
* Use regmap_uninit() to free it.
|
||||
*
|
||||
* @dev: Device that uses this map
|
||||
* @reg: List of address, size pairs
|
||||
* @count: Number of pairs (e.g. 1 if the regmap has a single entry)
|
||||
* @mapp: Returns allocated map
|
||||
*/
|
||||
int regmap_init_mem_platdata(struct udevice *dev, u32 *reg, int count,
|
||||
struct regmap **mapp);
|
||||
|
||||
/**
|
||||
* regmap_get_range() - Obtain the base memory address of a regmap range
|
||||
*
|
||||
|
@ -23,6 +23,17 @@ struct syscon_ops {
|
||||
|
||||
#define syscon_get_ops(dev) ((struct syscon_ops *)(dev)->driver->ops)
|
||||
|
||||
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
/*
|
||||
* We don't support 64-bit machines. If they are so resource-contrained that
|
||||
* they need to use OF_PLATDATA, something is horribly wrong with the
|
||||
* education of our hardware engineers.
|
||||
*/
|
||||
struct syscon_base_platdata {
|
||||
u32 reg[2];
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* syscon_get_regmap() - Get access to a register map
|
||||
*
|
||||
|
@ -48,11 +48,10 @@ obj-$(CONFIG_$(SPL_)SHA1) += sha1.o
|
||||
obj-$(CONFIG_$(SPL_)SHA256) += sha256.o
|
||||
|
||||
obj-$(CONFIG_$(SPL_)OF_LIBFDT) += libfdt/
|
||||
ifdef CONFIG_SPL_OF_CONTROL
|
||||
obj-$(CONFIG_OF_LIBFDT) += libfdt/
|
||||
endif
|
||||
ifneq ($(CONFIG_SPL_BUILD)$(CONFIG_SPL_OF_PLATDATA),yy)
|
||||
obj-$(CONFIG_$(SPL_)OF_CONTROL) += fdtdec_common.o
|
||||
obj-$(CONFIG_$(SPL_)OF_CONTROL) += fdtdec.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_SPL_BUILD
|
||||
obj-$(CONFIG_SPL_YMODEM_SUPPORT) += crc16.o
|
||||
|
89
lib/libfdt/libfdt.swig
Normal file
89
lib/libfdt/libfdt.swig
Normal file
@ -0,0 +1,89 @@
|
||||
/* File: libfdt.i */
|
||||
%module libfdt
|
||||
|
||||
%{
|
||||
#define SWIG_FILE_WITH_INIT
|
||||
#include "libfdt.h"
|
||||
%}
|
||||
|
||||
%pythoncode %{
|
||||
def Raise(errnum):
|
||||
raise ValueError('Error %s' % fdt_strerror(errnum))
|
||||
|
||||
def Name(fdt, offset):
|
||||
name, len = fdt_get_name(fdt, offset)
|
||||
return name
|
||||
|
||||
def String(fdt, offset):
|
||||
offset = fdt32_to_cpu(offset)
|
||||
name = fdt_string(fdt, offset)
|
||||
return name
|
||||
|
||||
def swap32(x):
|
||||
return (((x << 24) & 0xFF000000) |
|
||||
((x << 8) & 0x00FF0000) |
|
||||
((x >> 8) & 0x0000FF00) |
|
||||
((x >> 24) & 0x000000FF))
|
||||
|
||||
def fdt32_to_cpu(x):
|
||||
return swap32(x)
|
||||
|
||||
def Data(prop):
|
||||
set_prop(prop)
|
||||
return get_prop_data()
|
||||
%}
|
||||
|
||||
%include "typemaps.i"
|
||||
%include "cstring.i"
|
||||
|
||||
%typemap(in) void* = char*;
|
||||
|
||||
typedef int fdt32_t;
|
||||
|
||||
struct fdt_property {
|
||||
fdt32_t tag;
|
||||
fdt32_t len;
|
||||
fdt32_t nameoff;
|
||||
char data[0];
|
||||
};
|
||||
|
||||
/*
|
||||
* This is a work-around since I'm not sure of a better way to copy out the
|
||||
* contents of a string. This is used in dtoc/GetProps(). The intent is to
|
||||
* pass in a pointer to a property and access the data field at the end of
|
||||
* it. Ideally the Data() function above would be able to do this directly,
|
||||
* but I'm not sure how to do that.
|
||||
*/
|
||||
#pragma SWIG nowarn=454
|
||||
%inline %{
|
||||
static struct fdt_property *cur_prop;
|
||||
|
||||
void set_prop(struct fdt_property *prop) {
|
||||
cur_prop = prop;
|
||||
}
|
||||
%}
|
||||
|
||||
%cstring_output_allocate_size(char **s, int *sz, free(*$1));
|
||||
%inline %{
|
||||
void get_prop_data(char **s, int *sz) {
|
||||
*sz = fdt32_to_cpu(cur_prop->len);
|
||||
*s = (char *)malloc(*sz);
|
||||
if (!*s)
|
||||
*sz = 0;
|
||||
else
|
||||
memcpy(*s, cur_prop + 1, *sz);
|
||||
}
|
||||
%}
|
||||
|
||||
const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int checklen);
|
||||
int fdt_path_offset(const void *fdt, const char *path);
|
||||
int fdt_first_property_offset(const void *fdt, int nodeoffset);
|
||||
int fdt_next_property_offset(const void *fdt, int offset);
|
||||
const char *fdt_strerror(int errval);
|
||||
const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
|
||||
int offset,
|
||||
int *OUTPUT);
|
||||
const char *fdt_get_name(const void *fdt, int nodeoffset, int *OUTPUT);
|
||||
const char *fdt_string(const void *fdt, int stroffset);
|
||||
int fdt_first_subnode(const void *fdt, int offset);
|
||||
int fdt_next_subnode(const void *fdt, int offset);
|
38
lib/libfdt/setup.py
Normal file
38
lib/libfdt/setup.py
Normal file
@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
setup.py file for SWIG libfdt
|
||||
"""
|
||||
|
||||
from distutils.core import setup, Extension
|
||||
import os
|
||||
import sys
|
||||
|
||||
# Don't cross-compile - always use the host compiler.
|
||||
del os.environ['CROSS_COMPILE']
|
||||
del os.environ['CC']
|
||||
|
||||
progname = sys.argv[0]
|
||||
cflags = sys.argv[1]
|
||||
files = sys.argv[2:]
|
||||
|
||||
if cflags:
|
||||
cflags = [flag for flag in cflags.split(' ') if flag]
|
||||
else:
|
||||
cflags = None
|
||||
|
||||
libfdt_module = Extension(
|
||||
'_libfdt',
|
||||
sources = files,
|
||||
extra_compile_args = cflags
|
||||
)
|
||||
|
||||
sys.argv = [progname, '--quiet', 'build_ext', '--inplace']
|
||||
|
||||
setup (name = 'libfdt',
|
||||
version = '0.1',
|
||||
author = "SWIG Docs",
|
||||
description = """Simple swig libfdt from docs""",
|
||||
ext_modules = [libfdt_module],
|
||||
py_modules = ["libfdt"],
|
||||
)
|
14
lib/libfdt/test_libfdt.py
Normal file
14
lib/libfdt/test_libfdt.py
Normal file
@ -0,0 +1,14 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
our_path = os.path.dirname(os.path.realpath(__file__))
|
||||
sys.path.append(os.path.join(our_path, '../../b/sandbox_spl/tools'))
|
||||
|
||||
import libfdt
|
||||
|
||||
with open('b/sandbox_spl/u-boot.dtb') as fd:
|
||||
fdt = fd.read()
|
||||
|
||||
print libfdt.fdt_path_offset(fdt, "/aliases")
|
@ -185,3 +185,12 @@ int snprintf(char *buf, size_t size, const char *fmt, ...)
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void __assert_fail(const char *assertion, const char *file, unsigned line,
|
||||
const char *function)
|
||||
{
|
||||
/* This will not return */
|
||||
printf("%s:%u: %s: Assertion `%s' failed.", file, line, function,
|
||||
assertion);
|
||||
hang();
|
||||
}
|
||||
|
@ -28,12 +28,16 @@ __hostprogs := $(sort $(hostprogs-y) $(hostprogs-m))
|
||||
# C code
|
||||
# Executables compiled from a single .c file
|
||||
host-csingle := $(foreach m,$(__hostprogs), \
|
||||
$(if $($(m)-objs)$($(m)-cxxobjs),,$(m)))
|
||||
$(if $($(m)-objs)$($(m)-cxxobjs)$($(m)-sharedobjs),,$(m)))
|
||||
|
||||
# C executables linked based on several .o files
|
||||
host-cmulti := $(foreach m,$(__hostprogs),\
|
||||
$(if $($(m)-cxxobjs),,$(if $($(m)-objs),$(m))))
|
||||
|
||||
# Shared object libraries
|
||||
host-shared := $(foreach m,$(__hostprogs),\
|
||||
$(if $($(m)-sharedobjs),$(m))))
|
||||
|
||||
# Object (.o) files compiled from .c files
|
||||
host-cobjs := $(sort $(foreach m,$(__hostprogs),$($(m)-objs)))
|
||||
|
||||
@ -59,6 +63,7 @@ host-cmulti := $(addprefix $(obj)/,$(host-cmulti))
|
||||
host-cobjs := $(addprefix $(obj)/,$(host-cobjs))
|
||||
host-cxxmulti := $(addprefix $(obj)/,$(host-cxxmulti))
|
||||
host-cxxobjs := $(addprefix $(obj)/,$(host-cxxobjs))
|
||||
host-shared := $(addprefix $(obj)/,$(host-shared))
|
||||
host-objdirs := $(addprefix $(obj)/,$(host-objdirs))
|
||||
|
||||
obj-dirs += $(host-objdirs)
|
||||
@ -128,4 +133,4 @@ $(host-cxxobjs): $(obj)/%.o: $(src)/%.cc FORCE
|
||||
$(call if_changed_dep,host-cxxobjs)
|
||||
|
||||
targets += $(host-csingle) $(host-cmulti) $(host-cobjs)\
|
||||
$(host-cxxmulti) $(host-cxxobjs)
|
||||
$(host-cxxmulti) $(host-cxxobjs) $(host-shared)
|
||||
|
@ -45,6 +45,7 @@ LDFLAGS_FINAL += --gc-sections
|
||||
# FIX ME
|
||||
cpp_flags := $(KBUILD_CPPFLAGS) $(PLATFORM_CPPFLAGS) $(UBOOTINCLUDE) \
|
||||
$(NOSTDINC_FLAGS)
|
||||
c_flags := $(KBUILD_CFLAGS) $(cpp_flags)
|
||||
|
||||
HAVE_VENDOR_COMMON_LIB = $(if $(wildcard $(srctree)/board/$(VENDOR)/common/Makefile),y,n)
|
||||
|
||||
@ -76,6 +77,9 @@ endif
|
||||
|
||||
u-boot-spl-init := $(head-y)
|
||||
u-boot-spl-main := $(libs-y)
|
||||
ifdef CONFIG_SPL_OF_PLATDATA
|
||||
u-boot-spl-platdata := $(obj)/dts/dt-platdata.o
|
||||
endif
|
||||
|
||||
# Linker Script
|
||||
ifdef CONFIG_SPL_LDSCRIPT
|
||||
@ -169,7 +173,7 @@ cmd_cat = cat $(filter-out $(PHONY), $^) > $@
|
||||
quiet_cmd_copy = COPY $@
|
||||
cmd_copy = cp $< $@
|
||||
|
||||
ifeq ($(CONFIG_SPL_OF_CONTROL)$(CONFIG_OF_SEPARATE),yy)
|
||||
ifeq ($(CONFIG_SPL_OF_CONTROL)$(CONFIG_OF_SEPARATE)$(CONFIG_SPL_OF_PLATDATA),yy)
|
||||
$(obj)/$(SPL_BIN)-dtb.bin: $(obj)/$(SPL_BIN)-nodtb.bin $(obj)/$(SPL_BIN)-pad.bin \
|
||||
$(obj)/$(SPL_BIN).dtb FORCE
|
||||
$(call if_changed,cat)
|
||||
@ -207,6 +211,32 @@ cmd_cpp_cfg = $(CPP) -Wp,-MD,$(depfile) $(cpp_flags) $(LDPPFLAGS) -ansi \
|
||||
$(obj)/$(SPL_BIN).cfg: include/config.h FORCE
|
||||
$(call if_changed,cpp_cfg)
|
||||
|
||||
pythonpath = PYTHONPATH=tools
|
||||
|
||||
quiet_cmd_dtocc = DTOC C $@
|
||||
cmd_dtocc = $(pythonpath) $(srctree)/tools/dtoc/dtoc -d $(obj)/$(SPL_BIN).dtb -o $@ platdata
|
||||
|
||||
quiet_cmd_dtoch = DTOC H $@
|
||||
cmd_dtoch = $(pythonpath) $(srctree)/tools/dtoc/dtoc -d $(obj)/$(SPL_BIN).dtb -o $@ struct
|
||||
|
||||
quiet_cmd_plat = PLAT $@
|
||||
cmd_plat = $(CC) $(c_flags) -c $< -o $@
|
||||
|
||||
$(obj)/dts/dt-platdata.o: $(obj)/dts/dt-platdata.c include/generated/dt-structs.h
|
||||
$(call if_changed,plat)
|
||||
|
||||
PHONY += dts_dir
|
||||
dts_dir:
|
||||
$(shell [ -d $(obj)/dts ] || mkdir -p $(obj)/dts)
|
||||
|
||||
include/generated/dt-structs.h: $(obj)/$(SPL_BIN).dtb dts_dir dtoc
|
||||
$(call if_changed,dtoch)
|
||||
|
||||
$(obj)/dts/dt-platdata.c: $(obj)/$(SPL_BIN).dtb dts_dir dtoc
|
||||
$(call if_changed,dtocc)
|
||||
|
||||
dtoc: #$(objtree)/tools/_libfdt.so
|
||||
|
||||
ifdef CONFIG_SAMSUNG
|
||||
ifdef CONFIG_VAR_SIZE_SPL
|
||||
VAR_SIZE_PARAM = --vs
|
||||
@ -241,19 +271,24 @@ cmd_mksunxiboot = $(objtree)/tools/mksunxiboot $< $@
|
||||
$(obj)/sunxi-spl.bin: $(obj)/$(SPL_BIN).bin FORCE
|
||||
$(call if_changed,mksunxiboot)
|
||||
|
||||
quiet_cmd_u-boot-spl = LD $@
|
||||
cmd_u-boot-spl = (cd $(obj) && $(LD) $(LDFLAGS) $(LDFLAGS_$(@F)) \
|
||||
# Rule to link u-boot-spl
|
||||
# May be overridden by arch/$(ARCH)/config.mk
|
||||
quiet_cmd_u-boot-spl ?= LD $@
|
||||
cmd_u-boot-spl ?= (cd $(obj) && $(LD) $(LDFLAGS) $(LDFLAGS_$(@F)) \
|
||||
$(patsubst $(obj)/%,%,$(u-boot-spl-init)) --start-group \
|
||||
$(patsubst $(obj)/%,%,$(u-boot-spl-main)) --end-group \
|
||||
$(patsubst $(obj)/%,%,$(u-boot-spl-main)) \
|
||||
$(patsubst $(obj)/%,%,$(u-boot-spl-platdata)) \
|
||||
--end-group \
|
||||
$(PLATFORM_LIBS) -Map $(SPL_BIN).map -o $(SPL_BIN))
|
||||
|
||||
$(obj)/$(SPL_BIN): $(u-boot-spl-init) $(u-boot-spl-main) $(obj)/u-boot-spl.lds FORCE
|
||||
$(obj)/$(SPL_BIN): $(u-boot-spl-platdata) $(u-boot-spl-init) \
|
||||
$(u-boot-spl-main) $(obj)/u-boot-spl.lds FORCE
|
||||
$(call if_changed,u-boot-spl)
|
||||
|
||||
$(sort $(u-boot-spl-init) $(u-boot-spl-main)): $(u-boot-spl-dirs) ;
|
||||
|
||||
PHONY += $(u-boot-spl-dirs)
|
||||
$(u-boot-spl-dirs):
|
||||
$(u-boot-spl-dirs): $(u-boot-spl-platdata)
|
||||
$(Q)$(MAKE) $(build)=$@
|
||||
|
||||
quiet_cmd_cpp_lds = LDS $@
|
||||
|
@ -193,7 +193,7 @@ def pytest_configure(config):
|
||||
for v in env_vars:
|
||||
os.environ['U_BOOT_' + v.upper()] = getattr(ubconfig, v)
|
||||
|
||||
if board_type == 'sandbox':
|
||||
if board_type.startswith('sandbox'):
|
||||
import u_boot_console_sandbox
|
||||
console = u_boot_console_sandbox.ConsoleSandbox(log, ubconfig)
|
||||
else:
|
||||
|
42
test/py/tests/test_ofplatdata.py
Normal file
42
test/py/tests/test_ofplatdata.py
Normal file
@ -0,0 +1,42 @@
|
||||
# Copyright (c) 2016 Google, Inc
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
import pytest
|
||||
|
||||
OF_PLATDATA_OUTPUT = '''
|
||||
of-platdata probe:
|
||||
bool 1
|
||||
byte 05
|
||||
bytearray 06 00 00
|
||||
int 1
|
||||
intarray 2 3 4 0
|
||||
longbytearray 09 0a 0b 0c 0d 0e 0f 10 11
|
||||
string message
|
||||
stringarray "multi-word" "message" ""
|
||||
of-platdata probe:
|
||||
bool 0
|
||||
byte 08
|
||||
bytearray 01 23 34
|
||||
int 3
|
||||
intarray 5 0 0 0
|
||||
longbytearray 09 00 00 00 00 00 00 00 00
|
||||
string message2
|
||||
stringarray "another" "multi-word" "message"
|
||||
of-platdata probe:
|
||||
bool 0
|
||||
byte 00
|
||||
bytearray 00 00 00
|
||||
int 0
|
||||
intarray 0 0 0 0
|
||||
longbytearray 00 00 00 00 00 00 00 00 00
|
||||
string <NULL>
|
||||
stringarray "one" "" ""
|
||||
'''
|
||||
|
||||
@pytest.mark.buildconfigspec('spl')
|
||||
def test_ofplatdata(u_boot_console):
|
||||
"""Test that of-platdata can be generated and used in sandbox"""
|
||||
cons = u_boot_console
|
||||
output = cons.get_spawn_output().replace('\r', '')
|
||||
assert OF_PLATDATA_OUTPUT in output
|
@ -345,7 +345,7 @@ class ConsoleBase(object):
|
||||
m = self.p.expect([pattern_u_boot_spl_signon] +
|
||||
self.bad_patterns)
|
||||
if m != 0:
|
||||
raise Exception('Bad pattern found on console: ' +
|
||||
raise Exception('Bad pattern found on SPL console: ' +
|
||||
self.bad_pattern_ids[m - 1])
|
||||
m = self.p.expect([pattern_u_boot_main_signon] + self.bad_patterns)
|
||||
if m != 0:
|
||||
@ -393,6 +393,16 @@ class ConsoleBase(object):
|
||||
pass
|
||||
self.p = None
|
||||
|
||||
def get_spawn_output(self):
|
||||
"""Return the start-up output from U-Boot
|
||||
|
||||
Returns:
|
||||
The output produced by ensure_spawed(), as a string.
|
||||
"""
|
||||
if self.p:
|
||||
return self.p.get_expect_output()
|
||||
return None
|
||||
|
||||
def validate_version_string_in_text(self, text):
|
||||
"""Assert that a command's output includes the U-Boot signon message.
|
||||
|
||||
|
@ -39,11 +39,15 @@ class ConsoleSandbox(ConsoleBase):
|
||||
A u_boot_spawn.Spawn object that is attached to U-Boot.
|
||||
"""
|
||||
|
||||
bcfg = self.config.buildconfig
|
||||
config_spl = bcfg.get('config_spl', 'n') == 'y'
|
||||
fname = '/spl/u-boot-spl' if config_spl else '/u-boot'
|
||||
print fname
|
||||
cmd = []
|
||||
if self.config.gdbserver:
|
||||
cmd += ['gdbserver', self.config.gdbserver]
|
||||
cmd += [
|
||||
self.config.build_dir + '/u-boot',
|
||||
self.config.build_dir + fname,
|
||||
'-v',
|
||||
'-d',
|
||||
self.config.dtb
|
||||
|
@ -18,6 +18,9 @@ class Timeout(Exception):
|
||||
class Spawn(object):
|
||||
"""Represents the stdio of a freshly created sub-process. Commands may be
|
||||
sent to the process, and responses waited for.
|
||||
|
||||
Members:
|
||||
output: accumulated output from expect()
|
||||
"""
|
||||
|
||||
def __init__(self, args, cwd=None):
|
||||
@ -34,6 +37,7 @@ class Spawn(object):
|
||||
|
||||
self.waited = False
|
||||
self.buf = ''
|
||||
self.output = ''
|
||||
self.logfile_read = None
|
||||
self.before = ''
|
||||
self.after = ''
|
||||
@ -154,6 +158,7 @@ class Spawn(object):
|
||||
posafter = earliest_m.end()
|
||||
self.before = self.buf[:pos]
|
||||
self.after = self.buf[pos:posafter]
|
||||
self.output += self.buf[:posafter]
|
||||
self.buf = self.buf[posafter:]
|
||||
return earliest_pi
|
||||
tnow_s = time.time()
|
||||
@ -198,3 +203,11 @@ class Spawn(object):
|
||||
if not self.isalive():
|
||||
break
|
||||
time.sleep(0.1)
|
||||
|
||||
def get_expect_output(self):
|
||||
"""Return the output read by expect()
|
||||
|
||||
Returns:
|
||||
The output processed by expect(), as a string.
|
||||
"""
|
||||
return self.output
|
||||
|
@ -107,6 +107,20 @@ mkimage-objs := $(dumpimage-mkimage-objs) mkimage.o
|
||||
fit_info-objs := $(dumpimage-mkimage-objs) fit_info.o
|
||||
fit_check_sign-objs := $(dumpimage-mkimage-objs) fit_check_sign.o
|
||||
|
||||
# Build a libfdt Python module if swig is available
|
||||
# Use 'sudo apt-get install swig libpython-dev' to enable this
|
||||
hostprogs-$(CONFIG_SPL_OF_PLATDATA) += \
|
||||
$(if $(shell which swig),_libfdt.so)
|
||||
_libfdt.so-sharedobjs += $(LIBFDT_OBJS)
|
||||
libfdt:
|
||||
|
||||
tools/_libfdt.so: $(patsubst %.o,%.c,$(LIBFDT_OBJS)) tools/libfdt_wrap.c
|
||||
python $(srctree)/lib/libfdt/setup.py "$(_hostc_flags)" $^
|
||||
mv _libfdt.so $@
|
||||
|
||||
tools/libfdt_wrap.c: $(srctree)/lib/libfdt/libfdt.swig
|
||||
swig -python -o $@ $<
|
||||
|
||||
# TODO(sjg@chromium.org): Is this correct on Mac OS?
|
||||
|
||||
ifneq ($(CONFIG_MX23)$(CONFIG_MX28),)
|
||||
|
1
tools/dtoc/.gitignore
vendored
Normal file
1
tools/dtoc/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
*.pyc
|
1
tools/dtoc/dtoc
Symbolic link
1
tools/dtoc/dtoc
Symbolic link
@ -0,0 +1 @@
|
||||
dtoc.py
|
394
tools/dtoc/dtoc.py
Executable file
394
tools/dtoc/dtoc.py
Executable file
@ -0,0 +1,394 @@
|
||||
#!/usr/bin/python
|
||||
#
|
||||
# Copyright (C) 2016 Google, Inc
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
import copy
|
||||
from optparse import OptionError, OptionParser
|
||||
import os
|
||||
import sys
|
||||
|
||||
import fdt_util
|
||||
|
||||
# Bring in the patman libraries
|
||||
our_path = os.path.dirname(os.path.realpath(__file__))
|
||||
sys.path.append(os.path.join(our_path, '../patman'))
|
||||
|
||||
# Bring in either the normal fdt library (which relies on libfdt) or the
|
||||
# fallback one (which uses fdtget and is slower). Both provide the same
|
||||
# interfface for this file to use.
|
||||
try:
|
||||
from fdt import Fdt
|
||||
import fdt
|
||||
have_libfdt = True
|
||||
except ImportError:
|
||||
have_libfdt = False
|
||||
from fdt_fallback import Fdt
|
||||
import fdt_fallback as fdt
|
||||
|
||||
import struct
|
||||
|
||||
# When we see these properties we ignore them - i.e. do not create a structure member
|
||||
PROP_IGNORE_LIST = [
|
||||
'#address-cells',
|
||||
'#gpio-cells',
|
||||
'#size-cells',
|
||||
'compatible',
|
||||
'linux,phandle',
|
||||
"status",
|
||||
'phandle',
|
||||
'u-boot,dm-pre-reloc',
|
||||
]
|
||||
|
||||
# C type declarations for the tyues we support
|
||||
TYPE_NAMES = {
|
||||
fdt_util.TYPE_INT: 'fdt32_t',
|
||||
fdt_util.TYPE_BYTE: 'unsigned char',
|
||||
fdt_util.TYPE_STRING: 'const char *',
|
||||
fdt_util.TYPE_BOOL: 'bool',
|
||||
};
|
||||
|
||||
STRUCT_PREFIX = 'dtd_'
|
||||
VAL_PREFIX = 'dtv_'
|
||||
|
||||
def Conv_name_to_c(name):
|
||||
"""Convert a device-tree name to a C identifier
|
||||
|
||||
Args:
|
||||
name: Name to convert
|
||||
Return:
|
||||
String containing the C version of this name
|
||||
"""
|
||||
str = name.replace('@', '_at_')
|
||||
str = str.replace('-', '_')
|
||||
str = str.replace(',', '_')
|
||||
str = str.replace('/', '__')
|
||||
return str
|
||||
|
||||
def TabTo(num_tabs, str):
|
||||
if len(str) >= num_tabs * 8:
|
||||
return str + ' '
|
||||
return str + '\t' * (num_tabs - len(str) / 8)
|
||||
|
||||
class DtbPlatdata:
|
||||
"""Provide a means to convert device tree binary data to platform data
|
||||
|
||||
The output of this process is C structures which can be used in space-
|
||||
constrained encvironments where the ~3KB code overhead of device tree
|
||||
code is not affordable.
|
||||
|
||||
Properties:
|
||||
fdt: Fdt object, referencing the device tree
|
||||
_dtb_fname: Filename of the input device tree binary file
|
||||
_valid_nodes: A list of Node object with compatible strings
|
||||
_options: Command-line options
|
||||
_phandle_node: A dict of nodes indexed by phandle number (1, 2...)
|
||||
_outfile: The current output file (sys.stdout or a real file)
|
||||
_lines: Stashed list of output lines for outputting in the future
|
||||
_phandle_node: A dict of Nodes indexed by phandle (an integer)
|
||||
"""
|
||||
def __init__(self, dtb_fname, options):
|
||||
self._dtb_fname = dtb_fname
|
||||
self._valid_nodes = None
|
||||
self._options = options
|
||||
self._phandle_node = {}
|
||||
self._outfile = None
|
||||
self._lines = []
|
||||
|
||||
def SetupOutput(self, fname):
|
||||
"""Set up the output destination
|
||||
|
||||
Once this is done, future calls to self.Out() will output to this
|
||||
file.
|
||||
|
||||
Args:
|
||||
fname: Filename to send output to, or '-' for stdout
|
||||
"""
|
||||
if fname == '-':
|
||||
self._outfile = sys.stdout
|
||||
else:
|
||||
self._outfile = open(fname, 'w')
|
||||
|
||||
def Out(self, str):
|
||||
"""Output a string to the output file
|
||||
|
||||
Args:
|
||||
str: String to output
|
||||
"""
|
||||
self._outfile.write(str)
|
||||
|
||||
def Buf(self, str):
|
||||
"""Buffer up a string to send later
|
||||
|
||||
Args:
|
||||
str: String to add to our 'buffer' list
|
||||
"""
|
||||
self._lines.append(str)
|
||||
|
||||
def GetBuf(self):
|
||||
"""Get the contents of the output buffer, and clear it
|
||||
|
||||
Returns:
|
||||
The output buffer, which is then cleared for future use
|
||||
"""
|
||||
lines = self._lines
|
||||
self._lines = []
|
||||
return lines
|
||||
|
||||
def GetValue(self, type, value):
|
||||
"""Get a value as a C expression
|
||||
|
||||
For integers this returns a byte-swapped (little-endian) hex string
|
||||
For bytes this returns a hex string, e.g. 0x12
|
||||
For strings this returns a literal string enclosed in quotes
|
||||
For booleans this return 'true'
|
||||
|
||||
Args:
|
||||
type: Data type (fdt_util)
|
||||
value: Data value, as a string of bytes
|
||||
"""
|
||||
if type == fdt_util.TYPE_INT:
|
||||
return '%#x' % fdt_util.fdt32_to_cpu(value)
|
||||
elif type == fdt_util.TYPE_BYTE:
|
||||
return '%#x' % ord(value[0])
|
||||
elif type == fdt_util.TYPE_STRING:
|
||||
return '"%s"' % value
|
||||
elif type == fdt_util.TYPE_BOOL:
|
||||
return 'true'
|
||||
|
||||
def GetCompatName(self, node):
|
||||
"""Get a node's first compatible string as a C identifier
|
||||
|
||||
Args:
|
||||
node: Node object to check
|
||||
Return:
|
||||
C identifier for the first compatible string
|
||||
"""
|
||||
compat = node.props['compatible'].value
|
||||
if type(compat) == list:
|
||||
compat = compat[0]
|
||||
return Conv_name_to_c(compat)
|
||||
|
||||
def ScanDtb(self):
|
||||
"""Scan the device tree to obtain a tree of notes and properties
|
||||
|
||||
Once this is done, self.fdt.GetRoot() can be called to obtain the
|
||||
device tree root node, and progress from there.
|
||||
"""
|
||||
self.fdt = Fdt(self._dtb_fname)
|
||||
self.fdt.Scan()
|
||||
|
||||
def ScanTree(self):
|
||||
"""Scan the device tree for useful information
|
||||
|
||||
This fills in the following properties:
|
||||
_phandle_node: A dict of Nodes indexed by phandle (an integer)
|
||||
_valid_nodes: A list of nodes we wish to consider include in the
|
||||
platform data
|
||||
"""
|
||||
node_list = []
|
||||
self._phandle_node = {}
|
||||
for node in self.fdt.GetRoot().subnodes:
|
||||
if 'compatible' in node.props:
|
||||
status = node.props.get('status')
|
||||
if (not options.include_disabled and not status or
|
||||
status.value != 'disabled'):
|
||||
node_list.append(node)
|
||||
phandle_prop = node.props.get('phandle')
|
||||
if phandle_prop:
|
||||
phandle = phandle_prop.GetPhandle()
|
||||
self._phandle_node[phandle] = node
|
||||
|
||||
self._valid_nodes = node_list
|
||||
|
||||
def IsPhandle(self, prop):
|
||||
"""Check if a node contains phandles
|
||||
|
||||
We have no reliable way of detecting whether a node uses a phandle
|
||||
or not. As an interim measure, use a list of known property names.
|
||||
|
||||
Args:
|
||||
prop: Prop object to check
|
||||
Return:
|
||||
True if the object value contains phandles, else False
|
||||
"""
|
||||
if prop.name in ['clocks']:
|
||||
return True
|
||||
return False
|
||||
|
||||
def ScanStructs(self):
|
||||
"""Scan the device tree building up the C structures we will use.
|
||||
|
||||
Build a dict keyed by C struct name containing a dict of Prop
|
||||
object for each struct field (keyed by property name). Where the
|
||||
same struct appears multiple times, try to use the 'widest'
|
||||
property, i.e. the one with a type which can express all others.
|
||||
|
||||
Once the widest property is determined, all other properties are
|
||||
updated to match that width.
|
||||
"""
|
||||
structs = {}
|
||||
for node in self._valid_nodes:
|
||||
node_name = self.GetCompatName(node)
|
||||
fields = {}
|
||||
|
||||
# Get a list of all the valid properties in this node.
|
||||
for name, prop in node.props.iteritems():
|
||||
if name not in PROP_IGNORE_LIST and name[0] != '#':
|
||||
fields[name] = copy.deepcopy(prop)
|
||||
|
||||
# If we've seen this node_name before, update the existing struct.
|
||||
if node_name in structs:
|
||||
struct = structs[node_name]
|
||||
for name, prop in fields.iteritems():
|
||||
oldprop = struct.get(name)
|
||||
if oldprop:
|
||||
oldprop.Widen(prop)
|
||||
else:
|
||||
struct[name] = prop
|
||||
|
||||
# Otherwise store this as a new struct.
|
||||
else:
|
||||
structs[node_name] = fields
|
||||
|
||||
upto = 0
|
||||
for node in self._valid_nodes:
|
||||
node_name = self.GetCompatName(node)
|
||||
struct = structs[node_name]
|
||||
for name, prop in node.props.iteritems():
|
||||
if name not in PROP_IGNORE_LIST and name[0] != '#':
|
||||
prop.Widen(struct[name])
|
||||
upto += 1
|
||||
return structs
|
||||
|
||||
def GenerateStructs(self, structs):
|
||||
"""Generate struct defintions for the platform data
|
||||
|
||||
This writes out the body of a header file consisting of structure
|
||||
definitions for node in self._valid_nodes. See the documentation in
|
||||
README.of-plat for more information.
|
||||
"""
|
||||
self.Out('#include <stdbool.h>\n')
|
||||
self.Out('#include <libfdt.h>\n')
|
||||
|
||||
# Output the struct definition
|
||||
for name in sorted(structs):
|
||||
self.Out('struct %s%s {\n' % (STRUCT_PREFIX, name));
|
||||
for pname in sorted(structs[name]):
|
||||
prop = structs[name][pname]
|
||||
if self.IsPhandle(prop):
|
||||
# For phandles, include a reference to the target
|
||||
self.Out('\t%s%s[%d]' % (TabTo(2, 'struct phandle_2_cell'),
|
||||
Conv_name_to_c(prop.name),
|
||||
len(prop.value) / 2))
|
||||
else:
|
||||
ptype = TYPE_NAMES[prop.type]
|
||||
self.Out('\t%s%s' % (TabTo(2, ptype),
|
||||
Conv_name_to_c(prop.name)))
|
||||
if type(prop.value) == list:
|
||||
self.Out('[%d]' % len(prop.value))
|
||||
self.Out(';\n')
|
||||
self.Out('};\n')
|
||||
|
||||
def GenerateTables(self):
|
||||
"""Generate device defintions for the platform data
|
||||
|
||||
This writes out C platform data initialisation data and
|
||||
U_BOOT_DEVICE() declarations for each valid node. See the
|
||||
documentation in README.of-plat for more information.
|
||||
"""
|
||||
self.Out('#include <common.h>\n')
|
||||
self.Out('#include <dm.h>\n')
|
||||
self.Out('#include <dt-structs.h>\n')
|
||||
self.Out('\n')
|
||||
node_txt_list = []
|
||||
for node in self._valid_nodes:
|
||||
struct_name = self.GetCompatName(node)
|
||||
var_name = Conv_name_to_c(node.name)
|
||||
self.Buf('static struct %s%s %s%s = {\n' %
|
||||
(STRUCT_PREFIX, struct_name, VAL_PREFIX, var_name))
|
||||
for pname, prop in node.props.iteritems():
|
||||
if pname in PROP_IGNORE_LIST or pname[0] == '#':
|
||||
continue
|
||||
ptype = TYPE_NAMES[prop.type]
|
||||
member_name = Conv_name_to_c(prop.name)
|
||||
self.Buf('\t%s= ' % TabTo(3, '.' + member_name))
|
||||
|
||||
# Special handling for lists
|
||||
if type(prop.value) == list:
|
||||
self.Buf('{')
|
||||
vals = []
|
||||
# For phandles, output a reference to the platform data
|
||||
# of the target node.
|
||||
if self.IsPhandle(prop):
|
||||
# Process the list as pairs of (phandle, id)
|
||||
it = iter(prop.value)
|
||||
for phandle_cell, id_cell in zip(it, it):
|
||||
phandle = fdt_util.fdt32_to_cpu(phandle_cell)
|
||||
id = fdt_util.fdt32_to_cpu(id_cell)
|
||||
target_node = self._phandle_node[phandle]
|
||||
name = Conv_name_to_c(target_node.name)
|
||||
vals.append('{&%s%s, %d}' % (VAL_PREFIX, name, id))
|
||||
else:
|
||||
for val in prop.value:
|
||||
vals.append(self.GetValue(prop.type, val))
|
||||
self.Buf(', '.join(vals))
|
||||
self.Buf('}')
|
||||
else:
|
||||
self.Buf(self.GetValue(prop.type, prop.value))
|
||||
self.Buf(',\n')
|
||||
self.Buf('};\n')
|
||||
|
||||
# Add a device declaration
|
||||
self.Buf('U_BOOT_DEVICE(%s) = {\n' % var_name)
|
||||
self.Buf('\t.name\t\t= "%s",\n' % struct_name)
|
||||
self.Buf('\t.platdata\t= &%s%s,\n' % (VAL_PREFIX, var_name))
|
||||
self.Buf('\t.platdata_size\t= sizeof(%s%s),\n' %
|
||||
(VAL_PREFIX, var_name))
|
||||
self.Buf('};\n')
|
||||
self.Buf('\n')
|
||||
|
||||
# Output phandle target nodes first, since they may be referenced
|
||||
# by others
|
||||
if 'phandle' in node.props:
|
||||
self.Out(''.join(self.GetBuf()))
|
||||
else:
|
||||
node_txt_list.append(self.GetBuf())
|
||||
|
||||
# Output all the nodes which are not phandle targets themselves, but
|
||||
# may reference them. This avoids the need for forward declarations.
|
||||
for node_txt in node_txt_list:
|
||||
self.Out(''.join(node_txt))
|
||||
|
||||
|
||||
if __name__ != "__main__":
|
||||
pass
|
||||
|
||||
parser = OptionParser()
|
||||
parser.add_option('-d', '--dtb-file', action='store',
|
||||
help='Specify the .dtb input file')
|
||||
parser.add_option('--include-disabled', action='store_true',
|
||||
help='Include disabled nodes')
|
||||
parser.add_option('-o', '--output', action='store', default='-',
|
||||
help='Select output filename')
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
if not args:
|
||||
raise ValueError('Please specify a command: struct, platdata')
|
||||
|
||||
plat = DtbPlatdata(options.dtb_file, options)
|
||||
plat.ScanDtb()
|
||||
plat.ScanTree()
|
||||
plat.SetupOutput(options.output)
|
||||
structs = plat.ScanStructs()
|
||||
|
||||
for cmd in args[0].split(','):
|
||||
if cmd == 'struct':
|
||||
plat.GenerateStructs(structs)
|
||||
elif cmd == 'platdata':
|
||||
plat.GenerateTables()
|
||||
else:
|
||||
raise ValueError("Unknown command '%s': (use: struct, platdata)" % cmd)
|
180
tools/dtoc/fdt.py
Normal file
180
tools/dtoc/fdt.py
Normal file
@ -0,0 +1,180 @@
|
||||
#!/usr/bin/python
|
||||
#
|
||||
# Copyright (C) 2016 Google, Inc
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
import fdt_util
|
||||
import libfdt
|
||||
import sys
|
||||
|
||||
# This deals with a device tree, presenting it as a list of Node and Prop
|
||||
# objects, representing nodes and properties, respectively.
|
||||
#
|
||||
# This implementation uses a libfdt Python library to access the device tree,
|
||||
# so it is fairly efficient.
|
||||
|
||||
class Prop:
|
||||
"""A device tree property
|
||||
|
||||
Properties:
|
||||
name: Property name (as per the device tree)
|
||||
value: Property value as a string of bytes, or a list of strings of
|
||||
bytes
|
||||
type: Value type
|
||||
"""
|
||||
def __init__(self, name, bytes):
|
||||
self.name = name
|
||||
self.value = None
|
||||
if not bytes:
|
||||
self.type = fdt_util.TYPE_BOOL
|
||||
self.value = True
|
||||
return
|
||||
self.type, self.value = fdt_util.BytesToValue(bytes)
|
||||
|
||||
def GetPhandle(self):
|
||||
"""Get a (single) phandle value from a property
|
||||
|
||||
Gets the phandle valuie from a property and returns it as an integer
|
||||
"""
|
||||
return fdt_util.fdt32_to_cpu(self.value[:4])
|
||||
|
||||
def Widen(self, newprop):
|
||||
"""Figure out which property type is more general
|
||||
|
||||
Given a current property and a new property, this function returns the
|
||||
one that is less specific as to type. The less specific property will
|
||||
be ble to represent the data in the more specific property. This is
|
||||
used for things like:
|
||||
|
||||
node1 {
|
||||
compatible = "fred";
|
||||
value = <1>;
|
||||
};
|
||||
node1 {
|
||||
compatible = "fred";
|
||||
value = <1 2>;
|
||||
};
|
||||
|
||||
He we want to use an int array for 'value'. The first property
|
||||
suggests that a single int is enough, but the second one shows that
|
||||
it is not. Calling this function with these two propertes would
|
||||
update the current property to be like the second, since it is less
|
||||
specific.
|
||||
"""
|
||||
if newprop.type < self.type:
|
||||
self.type = newprop.type
|
||||
|
||||
if type(newprop.value) == list and type(self.value) != list:
|
||||
self.value = [self.value]
|
||||
|
||||
if type(self.value) == list and len(newprop.value) > len(self.value):
|
||||
val = fdt_util.GetEmpty(self.type)
|
||||
while len(self.value) < len(newprop.value):
|
||||
self.value.append(val)
|
||||
|
||||
|
||||
class Node:
|
||||
"""A device tree node
|
||||
|
||||
Properties:
|
||||
offset: Integer offset in the device tree
|
||||
name: Device tree node tname
|
||||
path: Full path to node, along with the node name itself
|
||||
_fdt: Device tree object
|
||||
subnodes: A list of subnodes for this node, each a Node object
|
||||
props: A dict of properties for this node, each a Prop object.
|
||||
Keyed by property name
|
||||
"""
|
||||
def __init__(self, fdt, offset, name, path):
|
||||
self.offset = offset
|
||||
self.name = name
|
||||
self.path = path
|
||||
self._fdt = fdt
|
||||
self.subnodes = []
|
||||
self.props = {}
|
||||
|
||||
def Scan(self):
|
||||
"""Scan a node's properties and subnodes
|
||||
|
||||
This fills in the props and subnodes properties, recursively
|
||||
searching into subnodes so that the entire tree is built.
|
||||
"""
|
||||
self.props = self._fdt.GetProps(self.path)
|
||||
|
||||
offset = libfdt.fdt_first_subnode(self._fdt.GetFdt(), self.offset)
|
||||
while offset >= 0:
|
||||
sep = '' if self.path[-1] == '/' else '/'
|
||||
name = libfdt.Name(self._fdt.GetFdt(), offset)
|
||||
path = self.path + sep + name
|
||||
node = Node(self._fdt, offset, name, path)
|
||||
self.subnodes.append(node)
|
||||
|
||||
node.Scan()
|
||||
offset = libfdt.fdt_next_subnode(self._fdt.GetFdt(), offset)
|
||||
|
||||
|
||||
class Fdt:
|
||||
"""Provides simple access to a flat device tree blob.
|
||||
|
||||
Properties:
|
||||
fname: Filename of fdt
|
||||
_root: Root of device tree (a Node object)
|
||||
"""
|
||||
|
||||
def __init__(self, fname):
|
||||
self.fname = fname
|
||||
with open(fname) as fd:
|
||||
self._fdt = fd.read()
|
||||
|
||||
def GetFdt(self):
|
||||
"""Get the contents of the FDT
|
||||
|
||||
Returns:
|
||||
The FDT contents as a string of bytes
|
||||
"""
|
||||
return self._fdt
|
||||
|
||||
def Scan(self):
|
||||
"""Scan a device tree, building up a tree of Node objects
|
||||
|
||||
This fills in the self._root property
|
||||
"""
|
||||
self._root = Node(self, 0, '/', '/')
|
||||
self._root.Scan()
|
||||
|
||||
def GetRoot(self):
|
||||
"""Get the root Node of the device tree
|
||||
|
||||
Returns:
|
||||
The root Node object
|
||||
"""
|
||||
return self._root
|
||||
|
||||
def GetProps(self, node):
|
||||
"""Get all properties from a node.
|
||||
|
||||
Args:
|
||||
node: Full path to node name to look in.
|
||||
|
||||
Returns:
|
||||
A dictionary containing all the properties, indexed by node name.
|
||||
The entries are Prop objects.
|
||||
|
||||
Raises:
|
||||
ValueError: if the node does not exist.
|
||||
"""
|
||||
offset = libfdt.fdt_path_offset(self._fdt, node)
|
||||
if offset < 0:
|
||||
libfdt.Raise(offset)
|
||||
props_dict = {}
|
||||
poffset = libfdt.fdt_first_property_offset(self._fdt, offset)
|
||||
while poffset >= 0:
|
||||
dprop, plen = libfdt.fdt_get_property_by_offset(self._fdt, poffset)
|
||||
prop = Prop(libfdt.String(self._fdt, dprop.nameoff), libfdt.Data(dprop))
|
||||
props_dict[prop.name] = prop
|
||||
|
||||
poffset = libfdt.fdt_next_property_offset(self._fdt, poffset)
|
||||
return props_dict
|
207
tools/dtoc/fdt_fallback.py
Normal file
207
tools/dtoc/fdt_fallback.py
Normal file
@ -0,0 +1,207 @@
|
||||
#!/usr/bin/python
|
||||
#
|
||||
# Copyright (C) 2016 Google, Inc
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
import command
|
||||
import fdt_util
|
||||
import sys
|
||||
|
||||
# This deals with a device tree, presenting it as a list of Node and Prop
|
||||
# objects, representing nodes and properties, respectively.
|
||||
#
|
||||
# This implementation uses the fdtget tool to access the device tree, so it
|
||||
# is not very efficient for larger trees. The tool is called once for each
|
||||
# node and property in the tree.
|
||||
|
||||
class Prop:
|
||||
"""A device tree property
|
||||
|
||||
Properties:
|
||||
name: Property name (as per the device tree)
|
||||
value: Property value as a string of bytes, or a list of strings of
|
||||
bytes
|
||||
type: Value type
|
||||
"""
|
||||
def __init__(self, name, byte_list_str):
|
||||
self.name = name
|
||||
self.value = None
|
||||
if not byte_list_str.strip():
|
||||
self.type = fdt_util.TYPE_BOOL
|
||||
return
|
||||
bytes = [chr(int(byte, 16)) for byte in byte_list_str.strip().split(' ')]
|
||||
self.type, self.value = fdt_util.BytesToValue(''.join(bytes))
|
||||
|
||||
def GetPhandle(self):
|
||||
"""Get a (single) phandle value from a property
|
||||
|
||||
Gets the phandle valuie from a property and returns it as an integer
|
||||
"""
|
||||
return fdt_util.fdt32_to_cpu(self.value[:4])
|
||||
|
||||
def Widen(self, newprop):
|
||||
"""Figure out which property type is more general
|
||||
|
||||
Given a current property and a new property, this function returns the
|
||||
one that is less specific as to type. The less specific property will
|
||||
be ble to represent the data in the more specific property. This is
|
||||
used for things like:
|
||||
|
||||
node1 {
|
||||
compatible = "fred";
|
||||
value = <1>;
|
||||
};
|
||||
node1 {
|
||||
compatible = "fred";
|
||||
value = <1 2>;
|
||||
};
|
||||
|
||||
He we want to use an int array for 'value'. The first property
|
||||
suggests that a single int is enough, but the second one shows that
|
||||
it is not. Calling this function with these two propertes would
|
||||
update the current property to be like the second, since it is less
|
||||
specific.
|
||||
"""
|
||||
if newprop.type < self.type:
|
||||
self.type = newprop.type
|
||||
|
||||
if type(newprop.value) == list and type(self.value) != list:
|
||||
self.value = newprop.value
|
||||
|
||||
class Node:
|
||||
"""A device tree node
|
||||
|
||||
Properties:
|
||||
name: Device tree node tname
|
||||
path: Full path to node, along with the node name itself
|
||||
_fdt: Device tree object
|
||||
subnodes: A list of subnodes for this node, each a Node object
|
||||
props: A dict of properties for this node, each a Prop object.
|
||||
Keyed by property name
|
||||
"""
|
||||
def __init__(self, fdt, name, path):
|
||||
self.name = name
|
||||
self.path = path
|
||||
self._fdt = fdt
|
||||
self.subnodes = []
|
||||
self.props = {}
|
||||
|
||||
def Scan(self):
|
||||
"""Scan a node's properties and subnodes
|
||||
|
||||
This fills in the props and subnodes properties, recursively
|
||||
searching into subnodes so that the entire tree is built.
|
||||
"""
|
||||
for name, byte_list_str in self._fdt.GetProps(self.path).iteritems():
|
||||
prop = Prop(name, byte_list_str)
|
||||
self.props[name] = prop
|
||||
|
||||
for name in self._fdt.GetSubNodes(self.path):
|
||||
sep = '' if self.path[-1] == '/' else '/'
|
||||
path = self.path + sep + name
|
||||
node = Node(self._fdt, name, path)
|
||||
self.subnodes.append(node)
|
||||
|
||||
node.Scan()
|
||||
|
||||
|
||||
class Fdt:
|
||||
"""Provides simple access to a flat device tree blob.
|
||||
|
||||
Properties:
|
||||
fname: Filename of fdt
|
||||
_root: Root of device tree (a Node object)
|
||||
"""
|
||||
|
||||
def __init__(self, fname):
|
||||
self.fname = fname
|
||||
|
||||
def Scan(self):
|
||||
"""Scan a device tree, building up a tree of Node objects
|
||||
|
||||
This fills in the self._root property
|
||||
"""
|
||||
self._root = Node(self, '/', '/')
|
||||
self._root.Scan()
|
||||
|
||||
def GetRoot(self):
|
||||
"""Get the root Node of the device tree
|
||||
|
||||
Returns:
|
||||
The root Node object
|
||||
"""
|
||||
return self._root
|
||||
|
||||
def GetSubNodes(self, node):
|
||||
"""Returns a list of sub-nodes of a given node
|
||||
|
||||
Args:
|
||||
node: Node name to return children from
|
||||
|
||||
Returns:
|
||||
List of children in the node (each a string node name)
|
||||
|
||||
Raises:
|
||||
CmdError: if the node does not exist.
|
||||
"""
|
||||
out = command.Output('fdtget', self.fname, '-l', node)
|
||||
return out.strip().splitlines()
|
||||
|
||||
def GetProps(self, node, convert_dashes=False):
|
||||
"""Get all properties from a node
|
||||
|
||||
Args:
|
||||
node: full path to node name to look in
|
||||
convert_dashes: True to convert - to _ in node names
|
||||
|
||||
Returns:
|
||||
A dictionary containing all the properties, indexed by node name.
|
||||
The entries are simply strings - no decoding of lists or numbers
|
||||
is done.
|
||||
|
||||
Raises:
|
||||
CmdError: if the node does not exist.
|
||||
"""
|
||||
out = command.Output('fdtget', self.fname, node, '-p')
|
||||
props = out.strip().splitlines()
|
||||
props_dict = {}
|
||||
for prop in props:
|
||||
name = prop
|
||||
if convert_dashes:
|
||||
prop = re.sub('-', '_', prop)
|
||||
props_dict[prop] = self.GetProp(node, name)
|
||||
return props_dict
|
||||
|
||||
def GetProp(self, node, prop, default=None, typespec=None):
|
||||
"""Get a property from a device tree.
|
||||
|
||||
This looks up the given node and property, and returns the value as a
|
||||
string,
|
||||
|
||||
If the node or property does not exist, this will return the default
|
||||
value.
|
||||
|
||||
Args:
|
||||
node: Full path to node to look up.
|
||||
prop: Property name to look up.
|
||||
default: Default value to return if nothing is present in the fdt,
|
||||
or None to raise in this case. This will be converted to a
|
||||
string.
|
||||
typespec: Type character to use (None for default, 's' for string)
|
||||
|
||||
Returns:
|
||||
string containing the property value.
|
||||
|
||||
Raises:
|
||||
CmdError: if the property does not exist and no default is provided.
|
||||
"""
|
||||
args = [self.fname, node, prop, '-t', 'bx']
|
||||
if default is not None:
|
||||
args += ['-d', str(default)]
|
||||
if typespec is not None:
|
||||
args += ['-t%s' % typespec]
|
||||
out = command.Output('fdtget', *args)
|
||||
return out.strip()
|
86
tools/dtoc/fdt_util.py
Normal file
86
tools/dtoc/fdt_util.py
Normal file
@ -0,0 +1,86 @@
|
||||
#!/usr/bin/python
|
||||
#
|
||||
# Copyright (C) 2016 Google, Inc
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
import struct
|
||||
|
||||
# A list of types we support
|
||||
(TYPE_BYTE, TYPE_INT, TYPE_STRING, TYPE_BOOL) = range(4)
|
||||
|
||||
def BytesToValue(bytes):
|
||||
"""Converts a string of bytes into a type and value
|
||||
|
||||
Args:
|
||||
A string containing bytes
|
||||
|
||||
Return:
|
||||
A tuple:
|
||||
Type of data
|
||||
Data, either a single element or a list of elements. Each element
|
||||
is one of:
|
||||
TYPE_STRING: string value from the property
|
||||
TYPE_INT: a byte-swapped integer stored as a 4-byte string
|
||||
TYPE_BYTE: a byte stored as a single-byte string
|
||||
"""
|
||||
size = len(bytes)
|
||||
strings = bytes.split('\0')
|
||||
is_string = True
|
||||
count = len(strings) - 1
|
||||
if count > 0 and not strings[-1]:
|
||||
for string in strings[:-1]:
|
||||
if not string:
|
||||
is_string = False
|
||||
break
|
||||
for ch in string:
|
||||
if ch < ' ' or ch > '~':
|
||||
is_string = False
|
||||
break
|
||||
else:
|
||||
is_string = False
|
||||
if is_string:
|
||||
if count == 1:
|
||||
return TYPE_STRING, strings[0]
|
||||
else:
|
||||
return TYPE_STRING, strings[:-1]
|
||||
if size % 4:
|
||||
if size == 1:
|
||||
return TYPE_BYTE, bytes[0]
|
||||
else:
|
||||
return TYPE_BYTE, list(bytes)
|
||||
val = []
|
||||
for i in range(0, size, 4):
|
||||
val.append(bytes[i:i + 4])
|
||||
if size == 4:
|
||||
return TYPE_INT, val[0]
|
||||
else:
|
||||
return TYPE_INT, val
|
||||
|
||||
def GetEmpty(type):
|
||||
"""Get an empty / zero value of the given type
|
||||
|
||||
Returns:
|
||||
A single value of the given type
|
||||
"""
|
||||
if type == TYPE_BYTE:
|
||||
return chr(0)
|
||||
elif type == TYPE_INT:
|
||||
return struct.pack('<I', 0);
|
||||
elif type == TYPE_STRING:
|
||||
return ''
|
||||
else:
|
||||
return True
|
||||
|
||||
def fdt32_to_cpu(val):
|
||||
"""Convert a device tree cell to an integer
|
||||
|
||||
Args:
|
||||
Value to convert (4-character string representing the cell value)
|
||||
|
||||
Return:
|
||||
A native-endian integer value
|
||||
"""
|
||||
return struct.unpack(">I", val)[0]
|
Loading…
Reference in New Issue
Block a user