Merge git://git.denx.de/u-boot-dm

This commit is contained in:
Tom Rini 2016-07-15 08:06:22 -04:00
commit ebe621d5fb
71 changed files with 2495 additions and 130 deletions

View File

@ -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
View File

@ -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

View File

@ -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>;
};

View File

@ -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

View File

@ -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

View File

@ -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 *)&params.ch[i],
sizeof(params.ch[i]));
(u8 *)&params->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 *)&params.pctl_timing,
sizeof(params.pctl_timing) / sizeof(u32));
(u32 *)&params->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 *)&params.phy_timing,
sizeof(params.phy_timing) / sizeof(u32));
(u32 *)&params->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 *)&params.base,
sizeof(params.base) / sizeof(u32));
(u32 *)&params->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, &params->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, &params);
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
};

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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
View 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))
;
}

View File

@ -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)

View 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;

View File

@ -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";

View 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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

View 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

View 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

View File

@ -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)
{

View File

@ -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;
}

View File

@ -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,
};

View File

@ -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);

View File

@ -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)

View File

@ -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
*

View File

@ -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)
{

View File

@ -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);

View File

@ -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)

View File

@ -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

View 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,
};

View File

@ -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,

View File

@ -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),

View File

@ -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

View File

@ -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

View File

@ -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 */

View File

@ -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 */

View File

@ -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) {

View 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,
};

View File

@ -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

View File

@ -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.
*

View File

@ -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

View 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

View File

@ -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

View File

@ -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
View 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

View File

@ -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
*

View File

@ -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
*

View File

@ -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
*

View File

@ -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
View 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
View 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
View 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")

View File

@ -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();
}

View File

@ -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)

View File

@ -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 $@

View File

@ -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:

View 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

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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
View File

@ -0,0 +1 @@
*.pyc

1
tools/dtoc/dtoc Symbolic link
View File

@ -0,0 +1 @@
dtoc.py

394
tools/dtoc/dtoc.py Executable file
View 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
View 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
View 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
View 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]