diff options
author | Tom Rini <trini@konsulko.com> | 2017-12-14 15:46:07 -0500 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2017-12-14 15:46:07 -0500 |
commit | 15616a0aa58173bce1efe47569bf2e10d023ae9c (patch) | |
tree | 57a9d4613a8534360816344cd0a331fd15649e80 | |
parent | 7ef548e6008d4225e0ae7c9af35cb76558756a62 (diff) | |
parent | 854dfbf99b89c114ba100905e1500b8ace60e0f9 (diff) | |
download | u-boot-15616a0aa58173bce1efe47569bf2e10d023ae9c.zip u-boot-15616a0aa58173bce1efe47569bf2e10d023ae9c.tar.gz u-boot-15616a0aa58173bce1efe47569bf2e10d023ae9c.tar.bz2 |
Merge git://git.denx.de/u-boot-dm
61 files changed, 1638 insertions, 62 deletions
@@ -1149,6 +1149,11 @@ u-boot-sunxi-with-spl.bin: spl/sunxi-spl.bin u-boot.img u-boot.dtb FORCE endif ifneq ($(CONFIG_TEGRA),) +ifneq ($(CONFIG_BINMAN),) +u-boot-dtb-tegra.bin u-boot-tegra.bin u-boot-nodtb-tegra.bin: \ + spl/u-boot-spl u-boot.bin FORCE + $(call if_changed,binman) +else OBJCOPYFLAGS_u-boot-nodtb-tegra.bin = -O binary --pad-to=$(CONFIG_SYS_TEXT_BASE) u-boot-nodtb-tegra.bin: spl/u-boot-spl u-boot-nodtb.bin FORCE $(call if_changed,pad_cat) @@ -1159,6 +1164,7 @@ u-boot-tegra.bin: spl/u-boot-spl u-boot.bin FORCE u-boot-dtb-tegra.bin: u-boot-tegra.bin FORCE $(call if_changed,copy) +endif # binman endif OBJCOPYFLAGS_u-boot-app.efi := $(OBJCOPYFLAGS_EFI) diff --git a/arch/arm/config.mk b/arch/arm/config.mk index 02f61fc..9c213b8 100644 --- a/arch/arm/config.mk +++ b/arch/arm/config.mk @@ -136,10 +136,12 @@ endif # limit ourselves to the sections we want in the .bin. ifdef CONFIG_ARM64 OBJCOPYFLAGS += -j .text -j .secure_text -j .secure_data -j .rodata -j .data \ - -j .u_boot_list -j .rela.dyn -j .got -j .got.plt + -j .u_boot_list -j .rela.dyn -j .got -j .got.plt \ + -j .binman_sym_table else OBJCOPYFLAGS += -j .text -j .secure_text -j .secure_data -j .rodata -j .hash \ - -j .data -j .got -j .got.plt -j .u_boot_list -j .rel.dyn + -j .data -j .got -j .got.plt -j .u_boot_list -j .rel.dyn \ + -j .binman_sym_table endif # if a dtb section exists we always have to include it diff --git a/arch/arm/cpu/u-boot-spl.lds b/arch/arm/cpu/u-boot-spl.lds index 068163b..65f7b68 100644 --- a/arch/arm/cpu/u-boot-spl.lds +++ b/arch/arm/cpu/u-boot-spl.lds @@ -37,6 +37,13 @@ SECTIONS } . = ALIGN(4); + .binman_sym_table : { + __binman_sym_start = .; + KEEP(*(SORT(.binman_sym*))); + __binman_sym_end = .; + } + + . = ALIGN(4); __image_copy_end = .; diff --git a/arch/arm/dts/tegra-u-boot.dtsi b/arch/arm/dts/tegra-u-boot.dtsi new file mode 100644 index 0000000..cde591c --- /dev/null +++ b/arch/arm/dts/tegra-u-boot.dtsi @@ -0,0 +1,40 @@ +#include <config.h> + +/ { + binman { + multiple-images; + image1 { + filename = "u-boot-tegra.bin"; + pad-byte = <0xff>; + u-boot-spl { + }; + u-boot { + pos = <(CONFIG_SYS_TEXT_BASE - + CONFIG_SPL_TEXT_BASE)>; + }; + }; + + /* Same as image1 - some tools still expect the -dtb suffix */ + image2 { + filename = "u-boot-dtb-tegra.bin"; + pad-byte = <0xff>; + u-boot-spl { + }; + u-boot { + pos = <(CONFIG_SYS_TEXT_BASE - + CONFIG_SPL_TEXT_BASE)>; + }; + }; + + image3 { + filename = "u-boot-nodtb-tegra.bin"; + pad-byte = <0xff>; + u-boot-spl { + }; + u-boot-nodtb { + pos = <(CONFIG_SYS_TEXT_BASE - + CONFIG_SPL_TEXT_BASE)>; + }; + }; + }; +}; diff --git a/arch/arm/dts/tegra114-u-boot.dtsi b/arch/arm/dts/tegra114-u-boot.dtsi new file mode 100644 index 0000000..7c11972 --- /dev/null +++ b/arch/arm/dts/tegra114-u-boot.dtsi @@ -0,0 +1,3 @@ +#include <config.h> + +#include "tegra-u-boot.dtsi" diff --git a/arch/arm/dts/tegra124-nyan-big-u-boot.dtsi b/arch/arm/dts/tegra124-nyan-big-u-boot.dtsi index 65c3851..44e6499 100644 --- a/arch/arm/dts/tegra124-nyan-big-u-boot.dtsi +++ b/arch/arm/dts/tegra124-nyan-big-u-boot.dtsi @@ -5,6 +5,8 @@ * SPDX-License-Identifier: GPL-2.0+ */ +#include "tegra-u-boot.dtsi" + / { host1x@50000000 { u-boot,dm-pre-reloc; diff --git a/arch/arm/dts/tegra124-u-boot.dtsi b/arch/arm/dts/tegra124-u-boot.dtsi new file mode 100644 index 0000000..7c11972 --- /dev/null +++ b/arch/arm/dts/tegra124-u-boot.dtsi @@ -0,0 +1,3 @@ +#include <config.h> + +#include "tegra-u-boot.dtsi" diff --git a/arch/arm/dts/tegra20-u-boot.dtsi b/arch/arm/dts/tegra20-u-boot.dtsi index 9b9835d..7c11972 100644 --- a/arch/arm/dts/tegra20-u-boot.dtsi +++ b/arch/arm/dts/tegra20-u-boot.dtsi @@ -1,8 +1,3 @@ -/ { - host1x@50000000 { - u-boot,dm-pre-reloc; - dc@54200000 { - u-boot,dm-pre-reloc; - }; - }; -}; +#include <config.h> + +#include "tegra-u-boot.dtsi" diff --git a/arch/arm/dts/tegra210-u-boot.dtsi b/arch/arm/dts/tegra210-u-boot.dtsi new file mode 100644 index 0000000..7c11972 --- /dev/null +++ b/arch/arm/dts/tegra210-u-boot.dtsi @@ -0,0 +1,3 @@ +#include <config.h> + +#include "tegra-u-boot.dtsi" diff --git a/arch/arm/dts/tegra30-u-boot.dtsi b/arch/arm/dts/tegra30-u-boot.dtsi new file mode 100644 index 0000000..7c11972 --- /dev/null +++ b/arch/arm/dts/tegra30-u-boot.dtsi @@ -0,0 +1,3 @@ +#include <config.h> + +#include "tegra-u-boot.dtsi" diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index 51e5090..51d1436 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -38,6 +38,7 @@ config TEGRA_COMMON select OF_CONTROL select VIDCONSOLE_AS_LCD if DM_VIDEO select BOARD_EARLY_INIT_F + select BINMAN imply CRC32_VERIFY config TEGRA_NO_BPMP diff --git a/arch/sandbox/dts/sandbox_pmic.dtsi b/arch/sandbox/dts/sandbox_pmic.dtsi index ce261b9..acb4799 100644 --- a/arch/sandbox/dts/sandbox_pmic.dtsi +++ b/arch/sandbox/dts/sandbox_pmic.dtsi @@ -75,4 +75,10 @@ regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; }; + + no_match_by_nodename { + regulator-name = "buck_SUPPLY_1.5V"; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <1500000>; + }; }; diff --git a/common/spl/spl.c b/common/spl/spl.c index 3bb20c7..76c1963 100644 --- a/common/spl/spl.c +++ b/common/spl/spl.c @@ -8,6 +8,7 @@ */ #include <common.h> +#include <binman_sym.h> #include <dm.h> #include <spl.h> #include <asm/u-boot.h> @@ -32,6 +33,9 @@ DECLARE_GLOBAL_DATA_PTR; u32 *boot_params_ptr = NULL; +/* See spl.h for information about this */ +binman_sym_declare(ulong, u_boot_any, pos); + /* Define board data structure */ static bd_t bdata __attribute__ ((section(".data"))); @@ -120,9 +124,17 @@ __weak void spl_board_prepare_for_boot(void) void spl_set_header_raw_uboot(struct spl_image_info *spl_image) { + ulong u_boot_pos = binman_sym(ulong, u_boot_any, pos); + spl_image->size = CONFIG_SYS_MONITOR_LEN; - spl_image->entry_point = CONFIG_SYS_UBOOT_START; - spl_image->load_addr = CONFIG_SYS_TEXT_BASE; + if (u_boot_pos != BINMAN_SYM_MISSING) { + /* biman does not support separate entry addresses at present */ + spl_image->entry_point = u_boot_pos; + spl_image->load_addr = u_boot_pos; + } else { + spl_image->entry_point = CONFIG_SYS_UBOOT_START; + spl_image->load_addr = CONFIG_SYS_TEXT_BASE; + } spl_image->os = IH_OS_U_BOOT; spl_image->name = "U-Boot"; } diff --git a/common/spl/spl_ram.c b/common/spl/spl_ram.c index b2645a1..fa8c768 100644 --- a/common/spl/spl_ram.c +++ b/common/spl/spl_ram.c @@ -11,6 +11,8 @@ * SPDX-License-Identifier: GPL-2.0+ */ #include <common.h> +#include <binman_sym.h> +#include <mapmem.h> #include <spl.h> #include <libfdt.h> @@ -48,15 +50,24 @@ static int spl_ram_load_image(struct spl_image_info *spl_image, load.read = spl_ram_load_read; spl_load_simple_fit(spl_image, &load, 0, header); } else { + ulong u_boot_pos = binman_sym(ulong, u_boot_any, pos); + debug("Legacy image\n"); /* * Get the header. It will point to an address defined by * handoff which will tell where the image located inside - * the flash. For now, it will temporary fixed to address - * pointed by U-Boot. + * the flash. */ - header = (struct image_header *) - (CONFIG_SYS_TEXT_BASE - sizeof(struct image_header)); + debug("u_boot_pos = %lx\n", u_boot_pos); + if (u_boot_pos == BINMAN_SYM_MISSING) { + /* + * No binman support or no information. For now, fix it + * to the address pointed to by U-Boot. + */ + u_boot_pos = CONFIG_SYS_TEXT_BASE - + sizeof(struct image_header); + } + header = (struct image_header *)map_sysmem(u_boot_pos, 0); spl_parse_image_header(spl_image, header); } diff --git a/doc/device-tree-bindings/regulator/regulator.txt b/doc/device-tree-bindings/regulator/regulator.txt index 918711e..65b69c4 100644 --- a/doc/device-tree-bindings/regulator/regulator.txt +++ b/doc/device-tree-bindings/regulator/regulator.txt @@ -2,7 +2,8 @@ Voltage/Current regulator Binding: The regulator devices don't use the "compatible" property. The binding is done -by the prefix of regulator node's name. Usually the pmic I/O driver will provide +by the prefix of regulator node's name, or, if this fails, by the prefix of the +regulator's "regulator-name" property. Usually the pmic I/O driver will provide the array of 'struct pmic_child_info' with the prefixes and compatible drivers. The bind is done by calling function: pmic_bind_childs(). Example drivers: @@ -15,8 +16,19 @@ For the node name e.g.: "prefix[:alpha:]num { ... }": Example the prefix "ldo" will pass for: "ldo1", "ldo@1", "ldoreg@1, ... +Binding by means of the node's name is preferred. However if the node names +would produce ambiguous prefixes (like "regulator@1" and "regualtor@11") and you +can't or do not want to change them then binding against the "regulator-name" +property is possible. The syntax for the prefix of the "regulator-name" property +is the same as the one for the regulator's node name. +Use case: a regulator named "regulator@1" to be bound to a driver named +"LDO_DRV" and a regulator named "regualator@11" to be bound to an other driver +named "BOOST_DRV". Using prefix "regualtor@1" for driver matching would load +the same driver for both regulators, hence the prefix is ambiguous. + Optional properties: -- regulator-name: a string, required by the regulator uclass +- regulator-name: a string, required by the regulator uclass, used for driver + binding if binding by node's name prefix fails - regulator-min-microvolt: a minimum allowed Voltage value - regulator-max-microvolt: a maximum allowed Voltage value - regulator-min-microamp: a minimum allowed Current value diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c index 537cf5f..010ed32 100644 --- a/drivers/block/blk-uclass.c +++ b/drivers/block/blk-uclass.c @@ -10,6 +10,7 @@ #include <dm.h> #include <dm/device-internal.h> #include <dm/lists.h> +#include <dm/uclass-internal.h> static const char *if_typename_str[IF_TYPE_COUNT] = { [IF_TYPE_IDE] = "ide", @@ -331,7 +332,7 @@ int blk_first_device(int if_type, struct udevice **devp) struct blk_desc *desc; int ret; - ret = uclass_first_device(UCLASS_BLK, devp); + ret = uclass_find_first_device(UCLASS_BLK, devp); if (ret) return ret; if (!*devp) @@ -340,7 +341,7 @@ int blk_first_device(int if_type, struct udevice **devp) desc = dev_get_uclass_platdata(*devp); if (desc->if_type == if_type) return 0; - ret = uclass_next_device(devp); + ret = uclass_find_next_device(devp); if (ret) return ret; } while (*devp); @@ -356,7 +357,7 @@ int blk_next_device(struct udevice **devp) desc = dev_get_uclass_platdata(*devp); if_type = desc->if_type; do { - ret = uclass_next_device(devp); + ret = uclass_find_next_device(devp); if (ret) return ret; if (!*devp) diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig index e3f9e4d..5d49c93 100644 --- a/drivers/power/pmic/Kconfig +++ b/drivers/power/pmic/Kconfig @@ -201,3 +201,11 @@ config POWER_MC34VR500 The MC34VR500 is used in conjunction with the FSL T1 and LS1 series SoC. It provides 4 buck DC-DC convertors and 5 LDOs, and it is accessed via an I2C interface. + +config DM_PMIC_TPS65910 + bool "Enable driver for Texas Instruments TPS65910 PMIC" + depends on DM_PMIC + ---help--- + The TPS65910 is a PMIC containing 3 buck DC-DC converters, one boost + DC-DC converter, 8 LDOs and a RTC. This driver binds the SMPS and LDO + pmic children. diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile index f7bdfa5..7d6c583 100644 --- a/drivers/power/pmic/Makefile +++ b/drivers/power/pmic/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_PMIC_RK8XX) += rk8xx.o obj-$(CONFIG_PMIC_RN5T567) += rn5t567.o obj-$(CONFIG_PMIC_TPS65090) += tps65090.o obj-$(CONFIG_PMIC_S5M8767) += s5m8767.o +obj-$(CONFIG_DM_PMIC_TPS65910) += pmic_tps65910_dm.o obj-$(CONFIG_$(SPL_)PMIC_PALMAS) += palmas.o obj-$(CONFIG_$(SPL_)PMIC_LP873X) += lp873x.o obj-$(CONFIG_$(SPL_)PMIC_LP87565) += lp87565.o diff --git a/drivers/power/pmic/pmic-uclass.c b/drivers/power/pmic/pmic-uclass.c index 64964e4..9347b40 100644 --- a/drivers/power/pmic/pmic-uclass.c +++ b/drivers/power/pmic/pmic-uclass.c @@ -26,6 +26,7 @@ int pmic_bind_children(struct udevice *pmic, ofnode parent, struct driver *drv; struct udevice *child; const char *node_name; + const char *reg_name; int bind_count = 0; ofnode node; int prefix_len; @@ -44,8 +45,14 @@ int pmic_bind_children(struct udevice *pmic, ofnode parent, debug(" - compatible prefix: '%s'\n", info->prefix); prefix_len = strlen(info->prefix); - if (strncmp(info->prefix, node_name, prefix_len)) - continue; + if (strncmp(info->prefix, node_name, prefix_len)) { + reg_name = ofnode_read_string(node, + "regulator-name"); + if (!reg_name) + continue; + if (strncmp(info->prefix, reg_name, prefix_len)) + continue; + } drv = lists_driver_lookup_name(info->driver); if (!drv) { diff --git a/drivers/power/pmic/pmic_tps65910_dm.c b/drivers/power/pmic/pmic_tps65910_dm.c new file mode 100644 index 0000000..0127ce3 --- /dev/null +++ b/drivers/power/pmic/pmic_tps65910_dm.c @@ -0,0 +1,98 @@ +/* + * Copyright (C) EETS GmbH, 2017, Felix Brack <f.brack@eets.ch> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <i2c.h> +#include <power/pmic.h> +#include <power/regulator.h> +#include <power/tps65910_pmic.h> + +DECLARE_GLOBAL_DATA_PTR; + +static const struct pmic_child_info pmic_children_info[] = { + { .prefix = "ldo_", .driver = TPS65910_LDO_DRIVER }, + { .prefix = "buck_", .driver = TPS65910_BUCK_DRIVER }, + { .prefix = "boost_", .driver = TPS65910_BOOST_DRIVER }, + { }, +}; + +static int pmic_tps65910_reg_count(struct udevice *dev) +{ + return TPS65910_NUM_REGS; +} + +static int pmic_tps65910_write(struct udevice *dev, uint reg, const u8 *buffer, + int len) +{ + int ret; + + ret = dm_i2c_write(dev, reg, buffer, len); + if (ret) + error("%s write error on register %02x\n", dev->name, reg); + + return ret; +} + +static int pmic_tps65910_read(struct udevice *dev, uint reg, u8 *buffer, + int len) +{ + int ret; + + ret = dm_i2c_read(dev, reg, buffer, len); + if (ret) + error("%s read error on register %02x\n", dev->name, reg); + + return ret; +} + +static int pmic_tps65910_bind(struct udevice *dev) +{ + ofnode regulators_node; + int children; + + regulators_node = dev_read_subnode(dev, "regulators"); + if (!ofnode_valid(regulators_node)) { + debug("%s regulators subnode not found\n", dev->name); + return -EINVAL; + } + + children = pmic_bind_children(dev, regulators_node, pmic_children_info); + if (!children) + debug("%s has no children (regulators)\n", dev->name); + + return 0; +} + +static int pmic_tps65910_probe(struct udevice *dev) +{ + /* use I2C control interface instead of I2C smartreflex interface to + * access smartrefelex registers VDD1_OP_REG, VDD1_SR_REG, VDD2_OP_REG + * and VDD2_SR_REG + */ + return pmic_clrsetbits(dev, TPS65910_REG_DEVICE_CTRL, 0, + TPS65910_I2C_SEL_MASK); +} + +static struct dm_pmic_ops pmic_tps65910_ops = { + .reg_count = pmic_tps65910_reg_count, + .read = pmic_tps65910_read, + .write = pmic_tps65910_write, +}; + +static const struct udevice_id pmic_tps65910_match[] = { + { .compatible = "ti,tps65910" }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(pmic_tps65910) = { + .name = "pmic_tps65910", + .id = UCLASS_PMIC, + .of_match = pmic_tps65910_match, + .bind = pmic_tps65910_bind, + .probe = pmic_tps65910_probe, + .ops = &pmic_tps65910_ops, +}; diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig index 8892fa1..26fb936 100644 --- a/drivers/power/regulator/Kconfig +++ b/drivers/power/regulator/Kconfig @@ -188,3 +188,11 @@ config DM_REGULATOR_LP87565 LP87565 series of PMICs have 4 single phase BUCKs that can also be configured in multi phase modes. The driver implements get/set api for value and enable. + +config DM_REGULATOR_TPS65910 + bool "Enable driver for TPS65910 PMIC regulators" + depends on DM_PMIC_TPS65910 + ---help--- + The TPS65910 PMIC provides 4 SMPSs and 8 LDOs. This driver supports all + regulator types of the TPS65910 (BUCK, BOOST and LDO). It implements + the get/set api for value and enable. diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile index 6c149a9..7a2e76d 100644 --- a/drivers/power/regulator/Makefile +++ b/drivers/power/regulator/Makefile @@ -21,3 +21,4 @@ obj-$(CONFIG_$(SPL_)DM_REGULATOR_PALMAS) += palmas_regulator.o obj-$(CONFIG_$(SPL_)DM_REGULATOR_PBIAS) += pbias_regulator.o obj-$(CONFIG_$(SPL_)DM_REGULATOR_LP873X) += lp873x_regulator.o obj-$(CONFIG_$(SPL_)DM_REGULATOR_LP87565) += lp87565_regulator.o +obj-$(CONFIG_DM_REGULATOR_TPS65910) += tps65910_regulator.o diff --git a/drivers/power/regulator/tps65910_regulator.c b/drivers/power/regulator/tps65910_regulator.c new file mode 100644 index 0000000..5e2ec8f --- /dev/null +++ b/drivers/power/regulator/tps65910_regulator.c @@ -0,0 +1,459 @@ +/* + * Copyright (C) EETS GmbH, 2017, Felix Brack <f.brack@eets.ch> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <power/pmic.h> +#include <power/regulator.h> +#include <power/tps65910_pmic.h> + +#define VOUT_CHOICE_COUNT 4 + +/* + * struct regulator_props - Properties of a LDO and VIO SMPS regulator + * + * All of these regulators allow setting one out of four output voltages. + * These output voltages are only achievable when supplying the regulator + * with a minimum input voltage. + * + * @vin_min[]: minimum supply input voltage in uV required to achieve the + * corresponding vout[] voltage + * @vout[]: regulator output voltage in uV + * @reg: I2C register used to set regulator voltage + */ +struct regulator_props { + int vin_min[VOUT_CHOICE_COUNT]; + int vout[VOUT_CHOICE_COUNT]; + int reg; +}; + +static const struct regulator_props ldo_props_vdig1 = { + .vin_min = { 1700000, 2100000, 2700000, 3200000 }, + .vout = { 1200000, 1500000, 1800000, 2700000 }, + .reg = TPS65910_REG_VDIG1 +}; + +static const struct regulator_props ldo_props_vdig2 = { + .vin_min = { 1700000, 1700000, 1700000, 2700000 }, + .vout = { 1000000, 1100000, 1200000, 1800000 }, + .reg = TPS65910_REG_VDIG2 +}; + +static const struct regulator_props ldo_props_vpll = { + .vin_min = { 2700000, 2700000, 2700000, 3000000 }, + .vout = { 1000000, 1100000, 1800000, 2500000 }, + .reg = TPS65910_REG_VPLL +}; + +static const struct regulator_props ldo_props_vdac = { + .vin_min = { 2700000, 3000000, 3200000, 3200000 }, + .vout = { 1800000, 2600000, 2800000, 2850000 }, + .reg = TPS65910_REG_VDAC +}; + +static const struct regulator_props ldo_props_vaux1 = { + .vin_min = { 2700000, 3200000, 3200000, 3200000 }, + .vout = { 1800000, 2500000, 2800000, 2850000 }, + .reg = TPS65910_REG_VAUX1 +}; + +static const struct regulator_props ldo_props_vaux2 = { + .vin_min = { 2700000, 3200000, 3200000, 3600000 }, + .vout = { 1800000, 2800000, 2900000, 3300000 }, + .reg = TPS65910_REG_VAUX2 +}; + +static const struct regulator_props ldo_props_vaux33 = { + .vin_min = { 2700000, 2700000, 3200000, 3600000 }, + .vout = { 1800000, 2000000, 2800000, 3300000 }, + .reg = TPS65910_REG_VAUX33 +}; + +static const struct regulator_props ldo_props_vmmc = { + .vin_min = { 2700000, 3200000, 3200000, 3600000 }, + .vout = { 1800000, 2800000, 3000000, 3300000 }, + .reg = TPS65910_REG_VMMC +}; + +static const struct regulator_props smps_props_vio = { + .vin_min = { 3200000, 3200000, 4000000, 4400000 }, + .vout = { 1500000, 1800000, 2500000, 3300000 }, + .reg = TPS65910_REG_VIO +}; + +/* lookup table of control registers indexed by regulator unit number */ +static const int ctrl_regs[] = { + TPS65910_REG_VRTC, + TPS65910_REG_VIO, + TPS65910_REG_VDD1, + TPS65910_REG_VDD2, + TPS65910_REG_VDD3, + TPS65910_REG_VDIG1, + TPS65910_REG_VDIG2, + TPS65910_REG_VPLL, + TPS65910_REG_VDAC, + TPS65910_REG_VAUX1, + TPS65910_REG_VAUX2, + TPS65910_REG_VAUX33, + TPS65910_REG_VMMC +}; + +/* supply names as used in DT */ +static const char * const supply_names[] = { + "vccio-supply", + "vcc1-supply", + "vcc2-supply", + "vcc3-supply", + "vcc4-supply", + "vcc5-supply", + "vcc6-supply", + "vcc7-supply" +}; + +/* lookup table of regulator supplies indexed by regulator unit number */ +static const int regulator_supplies[] = { + TPS65910_SUPPLY_VCC7, + TPS65910_SUPPLY_VCCIO, + TPS65910_SUPPLY_VCC1, + TPS65910_SUPPLY_VCC2, + TPS65910_SUPPLY_VCC7, + TPS65910_SUPPLY_VCC6, + TPS65910_SUPPLY_VCC6, + TPS65910_SUPPLY_VCC5, + TPS65910_SUPPLY_VCC5, + TPS65910_SUPPLY_VCC4, + TPS65910_SUPPLY_VCC4, + TPS65910_SUPPLY_VCC3, + TPS65910_SUPPLY_VCC3 +}; + +static int get_ctrl_reg_from_unit_addr(const uint unit_addr) +{ + if (unit_addr < ARRAY_SIZE(ctrl_regs)) + return ctrl_regs[unit_addr]; + return -ENXIO; +} + +static int tps65910_regulator_get_value(struct udevice *dev, + const struct regulator_props *rgp) +{ + int sel, val, vout; + struct tps65910_regulator_pdata *pdata = dev_get_platdata(dev); + int vin = pdata->supply; + + val = pmic_reg_read(dev->parent, rgp->reg); + if (val < 0) + return val; + sel = (val & TPS65910_SEL_MASK) >> 2; + vout = (vin >= *(rgp->vin_min + sel)) ? *(rgp->vout + sel) : 0; + vout = ((val & TPS65910_SUPPLY_STATE_MASK) == 1) ? vout : 0; + + return vout; +} + +static int tps65910_ldo_get_value(struct udevice *dev) +{ + struct tps65910_regulator_pdata *pdata = dev_get_platdata(dev); + int vin; + + if (!pdata) + return 0; + vin = pdata->supply; + + switch (pdata->unit) { + case TPS65910_UNIT_VRTC: + /* VRTC is fixed and can't be turned off */ + return (vin >= 2500000) ? 1830000 : 0; + case TPS65910_UNIT_VDIG1: + return tps65910_regulator_get_value(dev, &ldo_props_vdig1); + case TPS65910_UNIT_VDIG2: + return tps65910_regulator_get_value(dev, &ldo_props_vdig2); + case TPS65910_UNIT_VPLL: + return tps65910_regulator_get_value(dev, &ldo_props_vpll); + case TPS65910_UNIT_VDAC: + return tps65910_regulator_get_value(dev, &ldo_props_vdac); + case TPS65910_UNIT_VAUX1: + return tps65910_regulator_get_value(dev, &ldo_props_vaux1); + case TPS65910_UNIT_VAUX2: + return tps65910_regulator_get_value(dev, &ldo_props_vaux2); + case TPS65910_UNIT_VAUX33: + return tps65910_regulator_get_value(dev, &ldo_props_vaux33); + case TPS65910_UNIT_VMMC: + return tps65910_regulator_get_value(dev, &ldo_props_vmmc); + default: + return 0; + } +} + +static int tps65910_regulator_set_value(struct udevice *dev, + const struct regulator_props *ldo, + int uV) +{ + int val; + int sel = 0; + struct tps65910_regulator_pdata *pdata = dev_get_platdata(dev); + + do { + /* we only allow exact voltage matches */ + if (uV == *(ldo->vout + sel)) + break; + } while (++sel < VOUT_CHOICE_COUNT); + if (sel == VOUT_CHOICE_COUNT) + return -EINVAL; + if (pdata->supply < *(ldo->vin_min + sel)) + return -EINVAL; + + val = pmic_reg_read(dev->parent, ldo->reg); + if (val < 0) + return val; + val &= ~TPS65910_SEL_MASK; + val |= sel << 2; + return pmic_reg_write(dev->parent, ldo->reg, val); +} + +static int tps65910_ldo_set_value(struct udevice *dev, int uV) +{ + struct tps65910_regulator_pdata *pdata = dev_get_platdata(dev); + int vin = pdata->supply; + + switch (pdata->unit) { + case TPS65910_UNIT_VRTC: + /* VRTC is fixed to 1.83V and can't be turned off */ + if (vin < 2500000) + return -EINVAL; + return 0; + case TPS65910_UNIT_VDIG1: + return tps65910_regulator_set_value(dev, &ldo_props_vdig1, uV); + case TPS65910_UNIT_VDIG2: + return tps65910_regulator_set_value(dev, &ldo_props_vdig2, uV); + case TPS65910_UNIT_VPLL: + return tps65910_regulator_set_value(dev, &ldo_props_vpll, uV); + case TPS65910_UNIT_VDAC: + return tps65910_regulator_set_value(dev, &ldo_props_vdac, uV); + case TPS65910_UNIT_VAUX1: + return tps65910_regulator_set_value(dev, &ldo_props_vaux1, uV); + case TPS65910_UNIT_VAUX2: + return tps65910_regulator_set_value(dev, &ldo_props_vaux2, uV); + case TPS65910_UNIT_VAUX33: + return tps65910_regulator_set_value(dev, &ldo_props_vaux33, uV); + case TPS65910_UNIT_VMMC: + return tps65910_regulator_set_value(dev, &ldo_props_vmmc, uV); + default: + return 0; + } +} + +static int tps65910_get_enable(struct udevice *dev) +{ + int reg, val; + struct tps65910_regulator_pdata *pdata = dev_get_platdata(dev); + + reg = get_ctrl_reg_from_unit_addr(pdata->unit); + if (reg < 0) + return reg; + + val = pmic_reg_read(dev->parent, reg); + if (val < 0) + return val; + + /* bits 1:0 of regulator control register define state */ + return ((val & TPS65910_SUPPLY_STATE_MASK) == 1); +} + +static int tps65910_set_enable(struct udevice *dev, bool enable) +{ + int reg; + uint clr, set; + struct tps65910_regulator_pdata *pdata = dev_get_platdata(dev); + + reg = get_ctrl_reg_from_unit_addr(pdata->unit); + if (reg < 0) + return reg; + + if (enable) { + clr = TPS65910_SUPPLY_STATE_MASK & ~TPS65910_SUPPLY_STATE_ON; + set = TPS65910_SUPPLY_STATE_MASK & TPS65910_SUPPLY_STATE_ON; + } else { + clr = TPS65910_SUPPLY_STATE_MASK & ~TPS65910_SUPPLY_STATE_OFF; + set = TPS65910_SUPPLY_STATE_MASK & TPS65910_SUPPLY_STATE_OFF; + } + return pmic_clrsetbits(dev->parent, reg, clr, set); +} + +static int buck_get_vdd1_vdd2_value(struct udevice *dev, int reg_vdd) +{ + int gain; + int val = pmic_reg_read(dev, reg_vdd); + + if (val < 0) + return val; + gain = (val & TPS65910_GAIN_SEL_MASK) >> 6; + gain = (gain == 0) ? 1 : gain; + val = pmic_reg_read(dev, reg_vdd + 1); + if (val < 0) + return val; + if (val & TPS65910_VDD_SR_MASK) + /* use smart reflex value instead */ + val = pmic_reg_read(dev, reg_vdd + 2); + if (val < 0) + return val; + return (562500 + (val & TPS65910_VDD_SEL_MASK) * 12500) * gain; +} + +static int tps65910_buck_get_value(struct udevice *dev) +{ + struct tps65910_regulator_pdata *pdata = dev_get_platdata(dev); + + switch (pdata->unit) { + case TPS65910_UNIT_VIO: + return tps65910_regulator_get_value(dev, &smps_props_vio); + case TPS65910_UNIT_VDD1: + return buck_get_vdd1_vdd2_value(dev->parent, TPS65910_REG_VDD1); + case TPS65910_UNIT_VDD2: + return buck_get_vdd1_vdd2_value(dev->parent, TPS65910_REG_VDD2); + default: + return 0; + } +} + +static int buck_set_vdd1_vdd2_value(struct udevice *dev, int uV) +{ + int ret, reg_vdd, gain; + int val; + struct dm_regulator_uclass_platdata *uc_pdata; + struct tps65910_regulator_pdata *pdata = dev_get_platdata(dev); + + switch (pdata->unit) { + case TPS65910_UNIT_VDD1: + reg_vdd = TPS65910_REG_VDD1; + break; + case TPS65910_UNIT_VDD2: + reg_vdd = TPS65910_REG_VDD2; + break; + default: + return -EINVAL; + } + uc_pdata = dev_get_uclass_platdata(dev); + + /* check setpoint is within limits */ + if (uV < uc_pdata->min_uV) { + error("voltage %duV for %s too low\n", uV, dev->name); + return -EINVAL; + } + if (uV > uc_pdata->max_uV) { + error("voltage %duV for %s too high\n", uV, dev->name); + return -EINVAL; + } + + val = pmic_reg_read(dev->parent, reg_vdd); + if (val < 0) + return val; + gain = (val & TPS65910_GAIN_SEL_MASK) >> 6; + gain = (gain == 0) ? 1 : gain; + val = ((uV / gain) - 562500) / 12500; + if (val < TPS65910_VDD_SEL_MIN || val > TPS65910_VDD_SEL_MAX) + /* + * Neither do we change the gain, nor do we allow shutdown or + * any approximate value (for now) + */ + return -EPERM; + val &= TPS65910_VDD_SEL_MASK; + ret = pmic_reg_write(dev->parent, reg_vdd + 1, val); + if (ret) + return ret; + return 0; +} + +static int tps65910_buck_set_value(struct udevice *dev, int uV) +{ + struct tps65910_regulator_pdata *pdata = dev_get_platdata(dev); + + if (pdata->unit == TPS65910_UNIT_VIO) + return tps65910_regulator_set_value(dev, &smps_props_vio, uV); + + return buck_set_vdd1_vdd2_value(dev, uV); +} + +static int tps65910_boost_get_value(struct udevice *dev) +{ + int vout; + struct tps65910_regulator_pdata *pdata = dev_get_platdata(dev); + + vout = (pdata->supply >= 3000000) ? 5000000 : 0; + return vout; +} + +static int tps65910_regulator_ofdata_to_platdata(struct udevice *dev) +{ + struct udevice *supply; + int ret; + const char *supply_name; + struct tps65910_regulator_pdata *pdata = dev_get_platdata(dev); + + pdata->unit = dev_get_driver_data(dev); + if (pdata->unit > TPS65910_UNIT_VMMC) + return -EINVAL; + supply_name = supply_names[regulator_supplies[pdata->unit]]; + + debug("Looking up supply power %s\n", supply_name); + ret = device_get_supply_regulator(dev->parent, supply_name, &supply); + if (ret) { + debug(" missing supply power %s\n", supply_name); + return ret; + } + pdata->supply = regulator_get_value(supply); + if (pdata->supply < 0) { + debug(" invalid supply voltage for regulator %s\n", + supply->name); + return -EINVAL; + } + + return 0; +} + +static const struct dm_regulator_ops tps65910_boost_ops = { + .get_value = tps65910_boost_get_value, + .get_enable = tps65910_get_enable, + .set_enable = tps65910_set_enable, +}; + +U_BOOT_DRIVER(tps65910_boost) = { + .name = TPS65910_BOOST_DRIVER, + .id = UCLASS_REGULATOR, + .ops = &tps65910_boost_ops, + .platdata_auto_alloc_size = sizeof(struct tps65910_regulator_pdata), + .ofdata_to_platdata = tps65910_regulator_ofdata_to_platdata, +}; + +static const struct dm_regulator_ops tps65910_buck_ops = { + .get_value = tps65910_buck_get_value, + .set_value = tps65910_buck_set_value, + .get_enable = tps65910_get_enable, + .set_enable = tps65910_set_enable, +}; + +U_BOOT_DRIVER(tps65910_buck) = { + .name = TPS65910_BUCK_DRIVER, + .id = UCLASS_REGULATOR, + .ops = &tps65910_buck_ops, + .platdata_auto_alloc_size = sizeof(struct tps65910_regulator_pdata), + .ofdata_to_platdata = tps65910_regulator_ofdata_to_platdata, +}; + +static const struct dm_regulator_ops tps65910_ldo_ops = { + .get_value = tps65910_ldo_get_value, + .set_value = tps65910_ldo_set_value, + .get_enable = tps65910_get_enable, + .set_enable = tps65910_set_enable, +}; + +U_BOOT_DRIVER(tps65910_ldo) = { + .name = TPS65910_LDO_DRIVER, + .id = UCLASS_REGULATOR, + .ops = &tps65910_ldo_ops, + .platdata_auto_alloc_size = sizeof(struct tps65910_regulator_pdata), + .ofdata_to_platdata = tps65910_regulator_ofdata_to_platdata, +}; diff --git a/drivers/sysreset/sysreset-uclass.c b/drivers/sysreset/sysreset-uclass.c index 3566d17..0747c52 100644 --- a/drivers/sysreset/sysreset-uclass.c +++ b/drivers/sysreset/sysreset-uclass.c @@ -70,7 +70,7 @@ void reset_cpu(ulong addr) int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { - sysreset_walk_halt(SYSRESET_WARM); + sysreset_walk_halt(SYSRESET_COLD); return 0; } diff --git a/include/binman_sym.h b/include/binman_sym.h new file mode 100644 index 0000000..87d03d5 --- /dev/null +++ b/include/binman_sym.h @@ -0,0 +1,93 @@ +/* + * Symbol access for symbols set up by binman as part of the build. + * + * This allows C code to access the position of a particular part of the image + * assembled by binman. + * + * Copyright (c) 2017 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __BINMAN_SYM_H +#define __BINMAN_SYM_H + +#define BINMAN_SYM_MISSING (-1UL) + +#ifdef CONFIG_BINMAN + +/** + * binman_symname() - Internal fnuction to get a binman symbol name + * + * @entry_name: Name of the entry to look for (e.g. 'u_boot_spl') + * @_prop_name: Property value to get from that entry (e.g. 'pos') + * @returns name of the symbol for that entry and property + */ +#define binman_symname(_entry_name, _prop_name) \ + _binman_ ## _entry_name ## _prop_ ## _prop_name + +/** + * binman_sym_declare() - Declare a symbol that will be used at run-time + * + * @_type: Type f the symbol (e.g. unsigned long) + * @entry_name: Name of the entry to look for (e.g. 'u_boot_spl') + * @_prop_name: Property value to get from that entry (e.g. 'pos') + */ +#define binman_sym_declare(_type, _entry_name, _prop_name) \ + _type binman_symname(_entry_name, _prop_name) \ + __attribute__((aligned(4), unused, section(".binman_sym"))) + +/** + * binman_sym_extern() - Declare a extern symbol that will be used at run-time + * + * @_type: Type f the symbol (e.g. unsigned long) + * @entry_name: Name of the entry to look for (e.g. 'u_boot_spl') + * @_prop_name: Property value to get from that entry (e.g. 'pos') + */ +#define binman_sym_extern(_type, _entry_name, _prop_name) \ + extern _type binman_symname(_entry_name, _prop_name) \ + __attribute__((aligned(4), unused, section(".binman_sym"))) + +/** + * binman_sym_declare_optional() - Declare an optional symbol + * + * If this symbol cannot be provided by binman, an error will not be generated. + * Instead the image will be assigned the value BINMAN_SYM_MISSING. + * + * @_type: Type f the symbol (e.g. unsigned long) + * @entry_name: Name of the entry to look for (e.g. 'u_boot_spl') + * @_prop_name: Property value to get from that entry (e.g. 'pos') + */ +#define binman_sym_declare_optional(_type, _entry_name, _prop_name) \ + _type binman_symname(_entry_name, _prop_name) \ + __attribute__((aligned(4), weak, unused, \ + section(".binman_sym"))) + +/** + * binman_sym() - Access a previously declared symbol + * + * This is used to get the value of a symbol. E.g.: + * + * ulong address = binman_sym(ulong, u_boot_spl, pos); + * + * @_type: Type f the symbol (e.g. unsigned long) + * @entry_name: Name of the entry to look for (e.g. 'u_boot_spl') + * @_prop_name: Property value to get from that entry (e.g. 'pos') + * @returns value of that property (filled in by binman) + */ +#define binman_sym(_type, _entry_name, _prop_name) \ + (*(_type *)&binman_symname(_entry_name, _prop_name)) + +#else /* !BINMAN */ + +#define binman_sym_declare(_type, _entry_name, _prop_name) + +#define binman_sym_declare_optional(_type, _entry_name, _prop_name) + +#define binman_sym_extern(_type, _entry_name, _prop_name) + +#define binman_sym(_type, _entry_name, _prop_name) BINMAN_SYM_MISSING + +#endif /* BINMAN */ + +#endif diff --git a/include/power/sandbox_pmic.h b/include/power/sandbox_pmic.h index 7fdbfb9..c5e6fda 100644 --- a/include/power/sandbox_pmic.h +++ b/include/power/sandbox_pmic.h @@ -13,7 +13,7 @@ #define SANDBOX_BUCK_DRIVER "sandbox_buck" #define SANDBOX_OF_BUCK_PREFIX "buck" -#define SANDBOX_BUCK_COUNT 2 +#define SANDBOX_BUCK_COUNT 3 #define SANDBOX_LDO_COUNT 2 /* * Sandbox PMIC registers: @@ -109,6 +109,9 @@ enum { #define SANDBOX_BUCK1_PLATNAME "SUPPLY_1.2V" #define SANDBOX_BUCK2_DEVNAME "buck2" #define SANDBOX_BUCK2_PLATNAME "SUPPLY_3.3V" +/* BUCK3: for testing fallback regulator prefix matching during bind */ +#define SANDBOX_BUCK3_DEVNAME "no_match_by_nodename" +#define SANDBOX_BUCK3_PLATNAME "buck_SUPPLY_1.5V" /* LDO names */ #define SANDBOX_LDO1_DEVNAME "ldo1" #define SANDBOX_LDO1_PLATNAME "VDD_EMMC_1.8V" diff --git a/include/power/tps65910_pmic.h b/include/power/tps65910_pmic.h new file mode 100644 index 0000000..e8d9ffa --- /dev/null +++ b/include/power/tps65910_pmic.h @@ -0,0 +1,130 @@ +/* + * Copyright (C) EETS GmbH, 2017, Felix Brack <f.brack@eets.ch> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __TPS65910_PMIC_H_ +#define __TPS65910_PMIC_H_ + +#define TPS65910_I2C_SEL_MASK (0x1 << 4) +#define TPS65910_VDD_SR_MASK (0x1 << 7) +#define TPS65910_GAIN_SEL_MASK (0x3 << 6) +#define TPS65910_VDD_SEL_MASK 0x7f +#define TPS65910_VDD_SEL_MIN 3 +#define TPS65910_VDD_SEL_MAX 75 +#define TPS65910_SEL_MASK (0x3 << 2) +#define TPS65910_SUPPLY_STATE_MASK 0x3 +#define TPS65910_SUPPLY_STATE_OFF 0x0 +#define TPS65910_SUPPLY_STATE_ON 0x1 + +/* i2c registers */ +enum { + TPS65910_REG_RTC_SEC = 0x00, + TPS65910_REG_RTC_MIN, + TPS65910_REG_RTC_HOUR, + TPS65910_REG_RTC_DAY, + TPS65910_REG_RTC_MONTH, + TPS65910_REG_RTC_YEAR, + TPS65910_REG_RTC_WEEK, + TPS65910_REG_RTC_ALARM_SEC = 0x08, + TPS65910_REG_RTC_ALARM_MIN, + TPS65910_REG_RTC_ALARM_HOUR, + TPS65910_REG_RTC_ALARM_DAY, + TPS65910_REG_RTC_ALARM_MONTH, + TPS65910_REG_RTC_ALARM_YEAR, + TPS65910_REG_RTC_CTRL = 0x10, + TPS65910_REG_RTC_STAT, + TPS65910_REG_RTC_INT, + TPS65910_REG_RTC_COMP_LSB, + TPS65910_REG_RTC_COMP_MSB, + TPS65910_REG_RTC_RESISTOR_PRG, + TPS65910_REG_RTC_RESET_STAT, + TPS65910_REG_BACKUP1, + TPS65910_REG_BACKUP2, + TPS65910_REG_BACKUP3, + TPS65910_REG_BACKUP4, + TPS65910_REG_BACKUP5, + TPS65910_REG_PUADEN, + TPS65910_REG_REF, + TPS65910_REG_VRTC, + TPS65910_REG_VIO = 0x20, + TPS65910_REG_VDD1, + TPS65910_REG_VDD1_VAL, + TPS65910_REG_VDD1_VAL_SR, + TPS65910_REG_VDD2, + TPS65910_REG_VDD2_VAL, + TPS65910_REG_VDD2_VAL_SR, + TPS65910_REG_VDD3, + TPS65910_REG_VDIG1 = 0x30, + TPS65910_REG_VDIG2, + TPS65910_REG_VAUX1, + TPS65910_REG_VAUX2, + TPS65910_REG_VAUX33, + TPS65910_REG_VMMC, + TPS65910_REG_VPLL, + TPS65910_REG_VDAC, + TPS65910_REG_THERM, + TPS65910_REG_BATTERY_BACKUP_CHARGE, + TPS65910_REG_DCDC_CTRL = 0x3e, + TPS65910_REG_DEVICE_CTRL, + TPS65910_REG_DEVICE_CTRL2, + TPS65910_REG_SLEEP_KEEP_LDO_ON, + TPS65910_REG_SLEEP_KEEP_RES_ON, + TPS65910_REG_SLEEP_SET_LDO_OFF, + TPS65910_REG_SLEEP_SET_RES_OFF, + TPS65910_REG_EN1_LDO_ASS, + TPS65910_REG_EM1_SMPS_ASS, + TPS65910_REG_EN2_LDO_ASS, + TPS65910_REG_EM2_SMPS_ASS, + TPS65910_REG_INT_STAT = 0x50, + TPS65910_REG_INT_MASK, + TPS65910_REG_INT_STAT2, + TPS65910_REG_INT_MASK2, + TPS65910_REG_GPIO = 0x60, + TPS65910_REG_JTAGREVNUM = 0x80, + TPS65910_NUM_REGS +}; + +/* chip supplies */ +enum { + TPS65910_SUPPLY_VCCIO = 0x00, + TPS65910_SUPPLY_VCC1, + TPS65910_SUPPLY_VCC2, + TPS65910_SUPPLY_VCC3, + TPS65910_SUPPLY_VCC4, + TPS65910_SUPPLY_VCC5, + TPS65910_SUPPLY_VCC6, + TPS65910_SUPPLY_VCC7, + TPS65910_NUM_SUPPLIES +}; + +/* regulator unit numbers */ +enum { + TPS65910_UNIT_VRTC = 0x00, + TPS65910_UNIT_VIO, + TPS65910_UNIT_VDD1, + TPS65910_UNIT_VDD2, + TPS65910_UNIT_VDD3, + TPS65910_UNIT_VDIG1, + TPS65910_UNIT_VDIG2, + TPS65910_UNIT_VPLL, + TPS65910_UNIT_VDAC, + TPS65910_UNIT_VAUX1, + TPS65910_UNIT_VAUX2, + TPS65910_UNIT_VAUX33, + TPS65910_UNIT_VMMC, +}; + +/* platform data */ +struct tps65910_regulator_pdata { + u32 supply; /* regulator supply voltage in uV */ + uint unit; /* unit-address according to DT */ +}; + +/* driver names */ +#define TPS65910_BUCK_DRIVER "tps65910_buck" +#define TPS65910_BOOST_DRIVER "tps65910_boost" +#define TPS65910_LDO_DRIVER "tps65910_ldo" + +#endif /* __TPS65910_PMIC_H_ */ diff --git a/include/spl.h b/include/spl.h index 308ce7b..c14448b 100644 --- a/include/spl.h +++ b/include/spl.h @@ -7,6 +7,8 @@ #ifndef _SPL_H_ #define _SPL_H_ +#include <binman_sym.h> + /* Platform-specific defines */ #include <linux/compiler.h> #include <asm/spl.h> @@ -51,6 +53,15 @@ struct spl_load_info { void *buf); }; +/* + * We need to know the position of U-Boot in memory so we can jump to it. We + * allow any U-Boot binary to be used (u-boot.bin, u-boot-nodtb.bin, + * u-boot.img), hence the '_any'. These is no checking here that the correct + * image is found. For * example if u-boot.img is used we don't check that + * spl_parse_image_header() can parse a valid header. + */ +binman_sym_extern(ulong, u_boot_any, pos); + /** * spl_load_simple_fit() - Loads a fit image from a device. * @spl_image: Image description to set up diff --git a/test/dm/regulator.c b/test/dm/regulator.c index 3d0056f..395381d 100644 --- a/test/dm/regulator.c +++ b/test/dm/regulator.c @@ -27,6 +27,7 @@ DECLARE_GLOBAL_DATA_PTR; enum { BUCK1, BUCK2, + BUCK3, LDO1, LDO2, OUTPUT_COUNT, @@ -42,6 +43,7 @@ static const char *regulator_names[OUTPUT_COUNT][OUTPUT_NAME_COUNT] = { /* devname, platname */ { SANDBOX_BUCK1_DEVNAME, SANDBOX_BUCK1_PLATNAME }, { SANDBOX_BUCK2_DEVNAME, SANDBOX_BUCK2_PLATNAME }, + { SANDBOX_BUCK3_DEVNAME, SANDBOX_BUCK3_PLATNAME }, { SANDBOX_LDO1_DEVNAME, SANDBOX_LDO1_PLATNAME}, { SANDBOX_LDO2_DEVNAME, SANDBOX_LDO2_PLATNAME}, }; diff --git a/tools/binman/README b/tools/binman/README index 4ef76c8..08c3e56 100644 --- a/tools/binman/README +++ b/tools/binman/README @@ -439,6 +439,8 @@ contents of an entry in some way. For example, it would be possible to create an entry containing a hash of the contents of some other entries. At this stage the position and size of entries should not be adjusted. +6. WriteEntryInfo() + 7. BuildImage() - builds the image and writes it to a file. This is the final step. @@ -471,6 +473,33 @@ the 'warning' line in scripts/Makefile.lib to see what it has found: # u_boot_dtsi_options_debug = $(u_boot_dtsi_options_raw) +Access to binman entry positions at run time +-------------------------------------------- + +Binman assembles images and determines where each entry is placed in the image. +This information may be useful to U-Boot at run time. For example, in SPL it +is useful to be able to find the location of U-Boot so that it can be executed +when SPL is finished. + +Binman allows you to declare symbols in the SPL image which are filled in +with their correct values during the build. For example: + + binman_sym_declare(ulong, u_boot_any, pos); + +declares a ulong value which will be assigned to the position of any U-Boot +image (u-boot.bin, u-boot.img, u-boot-nodtb.bin) that is present in the image. +You can access this value with something like: + + ulong u_boot_pos = binman_sym(ulong, u_boot_any, pos); + +Thus u_boot_pos will be set to the position of U-Boot in memory, assuming that +the whole image has been loaded, or is available in flash. You can then jump to +that address to start U-Boot. + +At present this feature is only supported in SPL. In principle it is possible +to fill in such symbols in U-Boot proper, as well. + + Code coverage ------------- @@ -543,7 +572,8 @@ To do Some ideas: - Fill out the device tree to include the final position and size of each - entry (since the input file may not always specify these) + entry (since the input file may not always specify these). See also + 'Access to binman entry positions at run time' above - Use of-platdata to make the information available to code that is unable to use device tree (such as a very small SPL image) - Write an image map to a text file diff --git a/tools/binman/binman.py b/tools/binman/binman.py index 3ccf25f..1c8e8db 100755 --- a/tools/binman/binman.py +++ b/tools/binman/binman.py @@ -31,11 +31,13 @@ import cmdline import command import control -def RunTests(): +def RunTests(debug): """Run the functional tests and any embedded doctests""" + import elf_test import entry_test import fdt_test import ftest + import image_test import test import doctest @@ -45,12 +47,15 @@ def RunTests(): suite.run(result) sys.argv = [sys.argv[0]] + if debug: + sys.argv.append('-D') # Run the entry tests first ,since these need to be the first to import the # 'entry' module. suite = unittest.TestLoader().loadTestsFromTestCase(entry_test.TestEntry) suite.run(result) - for module in (ftest.TestFunctional, fdt_test.TestFdt): + for module in (ftest.TestFunctional, fdt_test.TestFdt, elf_test.TestElf, + image_test.TestImage): suite = unittest.TestLoader().loadTestsFromTestCase(module) suite.run(result) @@ -110,7 +115,7 @@ def RunBinman(options, args): sys.tracebacklimit = 0 if options.test: - ret_code = RunTests() + ret_code = RunTests(options.debug) elif options.test_coverage: RunTestCoverage() diff --git a/tools/binman/control.py b/tools/binman/control.py index e9d48df..ffa2bbd 100644 --- a/tools/binman/control.py +++ b/tools/binman/control.py @@ -12,6 +12,7 @@ import sys import tools import command +import elf import fdt import fdt_util from image import Image @@ -89,6 +90,7 @@ def Binman(options, args): try: tout.Init(options.verbosity) + elf.debug = options.debug try: tools.SetInputDirs(options.indir) tools.PrepareOutputDir(options.outdir, options.preserve) @@ -109,6 +111,7 @@ def Binman(options, args): image.CheckSize() image.CheckEntries() image.ProcessEntryContents() + image.WriteSymbols() image.BuildImage() finally: tools.FinaliseOutputDir() diff --git a/tools/binman/elf.py b/tools/binman/elf.py new file mode 100644 index 0000000..80ff225 --- /dev/null +++ b/tools/binman/elf.py @@ -0,0 +1,129 @@ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Handle various things related to ELF images +# + +from collections import namedtuple, OrderedDict +import command +import os +import re +import struct + +import tools + +# This is enabled from control.py +debug = False + +Symbol = namedtuple('Symbol', ['section', 'address', 'size', 'weak']) + + +def GetSymbols(fname, patterns): + """Get the symbols from an ELF file + + Args: + fname: Filename of the ELF file to read + patterns: List of regex patterns to search for, each a string + + Returns: + None, if the file does not exist, or Dict: + key: Name of symbol + value: Hex value of symbol + """ + stdout = command.Output('objdump', '-t', fname, raise_on_error=False) + lines = stdout.splitlines() + if patterns: + re_syms = re.compile('|'.join(patterns)) + else: + re_syms = None + syms = {} + syms_started = False + for line in lines: + if not line or not syms_started: + if 'SYMBOL TABLE' in line: + syms_started = True + line = None # Otherwise code coverage complains about 'continue' + continue + if re_syms and not re_syms.search(line): + continue + + space_pos = line.find(' ') + value, rest = line[:space_pos], line[space_pos + 1:] + flags = rest[:7] + parts = rest[7:].split() + section, size = parts[:2] + if len(parts) > 2: + name = parts[2] + syms[name] = Symbol(section, int(value, 16), int(size,16), + flags[1] == 'w') + return syms + +def GetSymbolAddress(fname, sym_name): + """Get a value of a symbol from an ELF file + + Args: + fname: Filename of the ELF file to read + patterns: List of regex patterns to search for, each a string + + Returns: + Symbol value (as an integer) or None if not found + """ + syms = GetSymbols(fname, [sym_name]) + sym = syms.get(sym_name) + if not sym: + return None + return sym.address + +def LookupAndWriteSymbols(elf_fname, entry, image): + """Replace all symbols in an entry with their correct values + + The entry contents is updated so that values for referenced symbols will be + visible at run time. This is done by finding out the symbols positions in + the entry (using the ELF file) and replacing them with values from binman's + data structures. + + Args: + elf_fname: Filename of ELF image containing the symbol information for + entry + entry: Entry to process + image: Image which can be used to lookup symbol values + """ + fname = tools.GetInputFilename(elf_fname) + syms = GetSymbols(fname, ['image', 'binman']) + if not syms: + return + base = syms.get('__image_copy_start') + if not base: + return + for name, sym in syms.iteritems(): + if name.startswith('_binman'): + msg = ("Image '%s': Symbol '%s'\n in entry '%s'" % + (image.GetPath(), name, entry.GetPath())) + offset = sym.address - base.address + if offset < 0 or offset + sym.size > entry.contents_size: + raise ValueError('%s has offset %x (size %x) but the contents ' + 'size is %x' % (entry.GetPath(), offset, + sym.size, entry.contents_size)) + if sym.size == 4: + pack_string = '<I' + elif sym.size == 8: + pack_string = '<Q' + else: + raise ValueError('%s has size %d: only 4 and 8 are supported' % + (msg, sym.size)) + + # Look up the symbol in our entry tables. + value = image.LookupSymbol(name, sym.weak, msg) + if value is not None: + value += base.address + else: + value = -1 + pack_string = pack_string.lower() + value_bytes = struct.pack(pack_string, value) + if debug: + print('%s:\n insert %s, offset %x, value %x, length %d' % + (msg, name, offset, value, len(value_bytes))) + entry.data = (entry.data[:offset] + value_bytes + + entry.data[offset + sym.size:]) diff --git a/tools/binman/elf_test.py b/tools/binman/elf_test.py new file mode 100644 index 0000000..e5fc282 --- /dev/null +++ b/tools/binman/elf_test.py @@ -0,0 +1,122 @@ +# +# Copyright (c) 2017 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Test for the elf module + +from contextlib import contextmanager +import os +import sys +import unittest + +try: + from StringIO import StringIO +except ImportError: + from io import StringIO + +import elf + +binman_dir = os.path.dirname(os.path.realpath(sys.argv[0])) + +# Use this to suppress stdout/stderr output: +# with capture_sys_output() as (stdout, stderr) +# ...do something... +@contextmanager +def capture_sys_output(): + capture_out, capture_err = StringIO(), StringIO() + old_out, old_err = sys.stdout, sys.stderr + try: + sys.stdout, sys.stderr = capture_out, capture_err + yield capture_out, capture_err + finally: + sys.stdout, sys.stderr = old_out, old_err + + +class FakeEntry: + def __init__(self, contents_size): + self.contents_size = contents_size + self.data = 'a' * contents_size + + def GetPath(self): + return 'entry_path' + +class FakeImage: + def __init__(self, sym_value=1): + self.sym_value = sym_value + + def GetPath(self): + return 'image_path' + + def LookupSymbol(self, name, weak, msg): + return self.sym_value + +class TestElf(unittest.TestCase): + def testAllSymbols(self): + fname = os.path.join(binman_dir, 'test', 'u_boot_ucode_ptr') + syms = elf.GetSymbols(fname, []) + self.assertIn('.ucode', syms) + + def testRegexSymbols(self): + fname = os.path.join(binman_dir, 'test', 'u_boot_ucode_ptr') + syms = elf.GetSymbols(fname, ['ucode']) + self.assertIn('.ucode', syms) + syms = elf.GetSymbols(fname, ['missing']) + self.assertNotIn('.ucode', syms) + syms = elf.GetSymbols(fname, ['missing', 'ucode']) + self.assertIn('.ucode', syms) + + def testMissingFile(self): + entry = FakeEntry(10) + image = FakeImage() + with self.assertRaises(ValueError) as e: + syms = elf.LookupAndWriteSymbols('missing-file', entry, image) + self.assertIn("Filename 'missing-file' not found in input path", + str(e.exception)) + + def testOutsideFile(self): + entry = FakeEntry(10) + image = FakeImage() + elf_fname = os.path.join(binman_dir, 'test', 'u_boot_binman_syms') + with self.assertRaises(ValueError) as e: + syms = elf.LookupAndWriteSymbols(elf_fname, entry, image) + self.assertIn('entry_path has offset 4 (size 8) but the contents size ' + 'is a', str(e.exception)) + + def testMissingImageStart(self): + entry = FakeEntry(10) + image = FakeImage() + elf_fname = os.path.join(binman_dir, 'test', 'u_boot_binman_syms_bad') + self.assertEqual(elf.LookupAndWriteSymbols(elf_fname, entry, image), + None) + + def testBadSymbolSize(self): + entry = FakeEntry(10) + image = FakeImage() + elf_fname = os.path.join(binman_dir, 'test', 'u_boot_binman_syms_size') + with self.assertRaises(ValueError) as e: + syms = elf.LookupAndWriteSymbols(elf_fname, entry, image) + self.assertIn('has size 1: only 4 and 8 are supported', + str(e.exception)) + + def testNoValue(self): + entry = FakeEntry(20) + image = FakeImage(sym_value=None) + elf_fname = os.path.join(binman_dir, 'test', 'u_boot_binman_syms') + syms = elf.LookupAndWriteSymbols(elf_fname, entry, image) + self.assertEqual(chr(255) * 16 + 'a' * 4, entry.data) + + def testDebug(self): + elf.debug = True + entry = FakeEntry(20) + image = FakeImage() + elf_fname = os.path.join(binman_dir, 'test', 'u_boot_binman_syms') + with capture_sys_output() as (stdout, stderr): + syms = elf.LookupAndWriteSymbols(elf_fname, entry, image) + elf.debug = False + self.assertTrue(len(stdout.getvalue()) > 0) + + +if __name__ == '__main__': + unittest.main() diff --git a/tools/binman/etype/entry.py b/tools/binman/etype/entry.py index 67c5734..5541887 100644 --- a/tools/binman/etype/entry.py +++ b/tools/binman/etype/entry.py @@ -198,3 +198,11 @@ class Entry(object): def ProcessContents(self): pass + + def WriteSymbols(self, image): + """Write symbol values into binary files for access at run time + + Args: + image: Image containing the entry + """ + pass diff --git a/tools/binman/etype/u_boot_spl.py b/tools/binman/etype/u_boot_spl.py index 68b0148..3720b47 100644 --- a/tools/binman/etype/u_boot_spl.py +++ b/tools/binman/etype/u_boot_spl.py @@ -6,12 +6,18 @@ # Entry-type module for spl/u-boot-spl.bin # +import elf + from entry import Entry from blob import Entry_blob class Entry_u_boot_spl(Entry_blob): def __init__(self, image, etype, node): Entry_blob.__init__(self, image, etype, node) + self.elf_fname = 'spl/u-boot-spl' def GetDefaultFilename(self): return 'spl/u-boot-spl.bin' + + def WriteSymbols(self, image): + elf.LookupAndWriteSymbols(self.elf_fname, self, image) diff --git a/tools/binman/etype/u_boot_spl_bss_pad.py b/tools/binman/etype/u_boot_spl_bss_pad.py index c005f28..c37f61d 100644 --- a/tools/binman/etype/u_boot_spl_bss_pad.py +++ b/tools/binman/etype/u_boot_spl_bss_pad.py @@ -9,6 +9,7 @@ # import command +import elf from entry import Entry from blob import Entry_blob import tools @@ -19,8 +20,8 @@ class Entry_u_boot_spl_bss_pad(Entry_blob): def ObtainContents(self): fname = tools.GetInputFilename('spl/u-boot-spl') - args = [['nm', fname], ['grep', '__bss_size']] - out = command.RunPipe(args, capture=True).stdout.splitlines() - bss_size = int(out[0].split()[0], 16) + bss_size = elf.GetSymbolAddress(fname, '__bss_size') + if not bss_size: + self.Raise('Expected __bss_size symbol in spl/u-boot-spl') self.data = chr(0) * bss_size self.contents_size = bss_size diff --git a/tools/binman/etype/u_boot_spl_dtb.py b/tools/binman/etype/u_boot_spl_dtb.py new file mode 100644 index 0000000..6c5ce1e --- /dev/null +++ b/tools/binman/etype/u_boot_spl_dtb.py @@ -0,0 +1,17 @@ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Entry-type module for U-Boot device tree +# + +from entry import Entry +from blob import Entry_blob + +class Entry_u_boot_spl_dtb(Entry_blob): + def __init__(self, image, etype, node): + Entry_blob.__init__(self, image, etype, node) + + def GetDefaultFilename(self): + return 'spl/u-boot-spl.dtb' diff --git a/tools/binman/etype/u_boot_spl_nodtb.py b/tools/binman/etype/u_boot_spl_nodtb.py new file mode 100644 index 0000000..880e0c7 --- /dev/null +++ b/tools/binman/etype/u_boot_spl_nodtb.py @@ -0,0 +1,17 @@ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Entry-type module for 'u-boot-nodtb.bin' +# + +from entry import Entry +from blob import Entry_blob + +class Entry_u_boot_spl_nodtb(Entry_blob): + def __init__(self, image, etype, node): + Entry_blob.__init__(self, image, etype, node) + + def GetDefaultFilename(self): + return 'spl/u-boot-spl-nodtb.bin' diff --git a/tools/binman/etype/u_boot_with_ucode_ptr.py b/tools/binman/etype/u_boot_with_ucode_ptr.py index 6f01adb..99b4371 100644 --- a/tools/binman/etype/u_boot_with_ucode_ptr.py +++ b/tools/binman/etype/u_boot_with_ucode_ptr.py @@ -9,6 +9,7 @@ import struct import command +import elf from entry import Entry from blob import Entry_blob import fdt_util @@ -31,11 +32,9 @@ class Entry_u_boot_with_ucode_ptr(Entry_blob): def ObtainContents(self): # Figure out where to put the microcode pointer fname = tools.GetInputFilename(self.elf_fname) - args = [['nm', fname], ['grep', '-w', '_dt_ucode_base_size']] - out = (command.RunPipe(args, capture=True, raise_on_error=False). - stdout.splitlines()) - if len(out) == 1: - self.target_pos = int(out[0].split()[0], 16) + sym = elf.GetSymbolAddress(fname, '_dt_ucode_base_size') + if sym: + self.target_pos = sym elif not fdt_util.GetBool(self._node, 'optional-ucode'): self.Raise('Cannot locate _dt_ucode_base_size symbol in u-boot') diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index 9083143..5812ab3 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -20,6 +20,7 @@ import binman import cmdline import command import control +import elf import fdt import fdt_util import tools @@ -28,11 +29,12 @@ import tout # Contents of test files, corresponding to different entry types U_BOOT_DATA = '1234' U_BOOT_IMG_DATA = 'img' -U_BOOT_SPL_DATA = '567' +U_BOOT_SPL_DATA = '56780123456789abcde' BLOB_DATA = '89' ME_DATA = '0abcd' VGA_DATA = 'vga' U_BOOT_DTB_DATA = 'udtb' +U_BOOT_SPL_DTB_DATA = 'spldtb' X86_START16_DATA = 'start16' X86_START16_SPL_DATA = 'start16spl' U_BOOT_NODTB_DATA = 'nodtb with microcode pointer somewhere in here' @@ -76,6 +78,7 @@ class TestFunctional(unittest.TestCase): TestFunctional._MakeInputFile('me.bin', ME_DATA) TestFunctional._MakeInputFile('vga.bin', VGA_DATA) TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA) + TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA) TestFunctional._MakeInputFile('u-boot-x86-16bit.bin', X86_START16_DATA) TestFunctional._MakeInputFile('spl/u-boot-x86-16bit-spl.bin', X86_START16_SPL_DATA) @@ -134,7 +137,10 @@ class TestFunctional(unittest.TestCase): Returns: Return value (0 for success) """ - (options, args) = cmdline.ParseArgs(list(args)) + args = list(args) + if '-D' in sys.argv: + args = args + ['-D'] + (options, args) = cmdline.ParseArgs(args) options.pager = 'binman-invalid-pager' options.build_dir = self._indir @@ -142,14 +148,16 @@ class TestFunctional(unittest.TestCase): # options.verbosity = tout.DEBUG return control.Binman(options, args) - def _DoTestFile(self, fname): + def _DoTestFile(self, fname, debug=False): """Run binman with a given test file Args: fname: Device tree source filename to use (e.g. 05_simple.dts) """ - return self._DoBinman('-p', '-I', self._indir, - '-d', self.TestFile(fname)) + args = ['-p', '-I', self._indir, '-d', self.TestFile(fname)] + if debug: + args.append('-D') + return self._DoBinman(*args) def _SetupDtb(self, fname, outfile='u-boot.dtb'): """Set up a new test device-tree file @@ -302,7 +310,6 @@ class TestFunctional(unittest.TestCase): self.assertEqual(0, len(result.stderr)) self.assertEqual(0, result.return_code) - # Not yet available. def testBoard(self): """Test that we can run it with a specific board""" self._SetupDtb('05_simple.dts', 'sandbox/u-boot.dtb') @@ -362,6 +369,10 @@ class TestFunctional(unittest.TestCase): data = self._DoReadFile('05_simple.dts') self.assertEqual(U_BOOT_DATA, data) + def testSimpleDebug(self): + """Test a simple binman run with debugging enabled""" + data = self._DoTestFile('05_simple.dts', debug=True) + def testDual(self): """Test that we can handle creating two images @@ -563,8 +574,10 @@ class TestFunctional(unittest.TestCase): def testImagePadByte(self): """Test that the image pad byte can be specified""" + with open(self.TestFile('bss_data')) as fd: + TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read()) data = self._DoReadFile('21_image_pad.dts') - self.assertEqual(U_BOOT_SPL_DATA + (chr(0xff) * 9) + U_BOOT_DATA, data) + self.assertEqual(U_BOOT_SPL_DATA + (chr(0xff) * 1) + U_BOOT_DATA, data) def testImageName(self): """Test that image files can be named""" @@ -586,7 +599,7 @@ class TestFunctional(unittest.TestCase): def testPackSorted(self): """Test that entries can be sorted""" data = self._DoReadFile('24_sorted.dts') - self.assertEqual(chr(0) * 5 + U_BOOT_SPL_DATA + chr(0) * 2 + + self.assertEqual(chr(0) * 1 + U_BOOT_SPL_DATA + chr(0) * 2 + U_BOOT_DATA, data) def testPackZeroPosition(self): @@ -614,14 +627,14 @@ class TestFunctional(unittest.TestCase): with self.assertRaises(ValueError) as e: self._DoTestFile('28_pack_4gb_outside.dts') self.assertIn("Node '/binman/u-boot': Position 0x0 (0) is outside " - "the image starting at 0xfffffff0 (4294967280)", + "the image starting at 0xffffffe0 (4294967264)", str(e.exception)) def testPackX86Rom(self): """Test that a basic x86 ROM can be created""" data = self._DoReadFile('29_x86-rom.dts') - self.assertEqual(U_BOOT_DATA + chr(0) * 3 + U_BOOT_SPL_DATA + - chr(0) * 6, data) + self.assertEqual(U_BOOT_DATA + chr(0) * 7 + U_BOOT_SPL_DATA + + chr(0) * 2, data) def testPackX86RomMeNoDesc(self): """Test that an invalid Intel descriptor entry is detected""" @@ -835,6 +848,13 @@ class TestFunctional(unittest.TestCase): data = self._DoReadFile('47_spl_bss_pad.dts') self.assertEqual(U_BOOT_SPL_DATA + (chr(0) * 10) + U_BOOT_DATA, data) + with open(self.TestFile('u_boot_ucode_ptr')) as fd: + TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read()) + with self.assertRaises(ValueError) as e: + data = self._DoReadFile('47_spl_bss_pad.dts') + self.assertIn('Expected __bss_size symbol in spl/u-boot-spl', + str(e.exception)) + def testPackStart16Spl(self): """Test that an image with an x86 start16 region can be created""" data = self._DoReadFile('48_x86-start16-spl.dts') @@ -862,6 +882,32 @@ class TestFunctional(unittest.TestCase): data = self._DoReadFile('50_intel_mrc.dts') self.assertEqual(MRC_DATA, data[:len(MRC_DATA)]) + def testSplDtb(self): + """Test that an image with spl/u-boot-spl.dtb can be created""" + data = self._DoReadFile('51_u_boot_spl_dtb.dts') + self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)]) + + def testSplNoDtb(self): + """Test that an image with spl/u-boot-spl-nodtb.bin can be created""" + data = self._DoReadFile('52_u_boot_spl_nodtb.dts') + self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)]) + + def testSymbols(self): + """Test binman can assign symbols embedded in U-Boot""" + elf_fname = self.TestFile('u_boot_binman_syms') + syms = elf.GetSymbols(elf_fname, ['binman', 'image']) + addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start') + self.assertEqual(syms['_binman_u_boot_spl_prop_pos'].address, addr) + + with open(self.TestFile('u_boot_binman_syms')) as fd: + TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read()) + data = self._DoReadFile('53_symbols.dts') + sym_values = struct.pack('<LQL', 0x24 + 0, 0x24 + 24, 0x24 + 20) + expected = (sym_values + U_BOOT_SPL_DATA[16:] + chr(0xff) + + U_BOOT_DATA + + sym_values + U_BOOT_SPL_DATA[16:]) + self.assertEqual(expected, data) + if __name__ == "__main__": unittest.main() diff --git a/tools/binman/image.py b/tools/binman/image.py index 24c4f6f..741630f 100644 --- a/tools/binman/image.py +++ b/tools/binman/image.py @@ -6,8 +6,12 @@ # Class for an image, the output of binman # +from __future__ import print_function + from collections import OrderedDict from operator import attrgetter +import re +import sys import fdt_util import tools @@ -45,7 +49,7 @@ class Image: address. _entries: OrderedDict() of entries """ - def __init__(self, name, node): + def __init__(self, name, node, test=False): global entry global Entry import entry @@ -64,8 +68,9 @@ class Image: self._end_4gb = False self._entries = OrderedDict() - self._ReadNode() - self._ReadEntries() + if not test: + self._ReadNode() + self._ReadEntries() def _ReadNode(self): """Read properties from the image node""" @@ -119,6 +124,14 @@ class Image: """ raise ValueError("Image '%s': %s" % (self._node.path, msg)) + def GetPath(self): + """Get the path of an image (in the FDT) + + Returns: + Full path of the node for this image + """ + return self._node.path + def _ReadEntries(self): for node in self._node.subnodes: self._entries[node.name] = Entry.Create(self, node) @@ -220,6 +233,11 @@ class Image: for entry in self._entries.values(): entry.ProcessContents() + def WriteSymbols(self): + """Write symbol values into binary files for access at run time""" + for entry in self._entries.values(): + entry.WriteSymbols(self) + def BuildImage(self): """Write the image to a file""" fname = tools.GetOutputFilename(self._filename) @@ -230,3 +248,58 @@ class Image: data = entry.GetData() fd.seek(self._pad_before + entry.pos - self._skip_at_start) fd.write(data) + + def LookupSymbol(self, sym_name, optional, msg): + """Look up a symbol in an ELF file + + Looks up a symbol in an ELF file. Only entry types which come from an + ELF image can be used by this function. + + At present the only entry property supported is pos. + + Args: + sym_name: Symbol name in the ELF file to look up in the format + _binman_<entry>_prop_<property> where <entry> is the name of + the entry and <property> is the property to find (e.g. + _binman_u_boot_prop_pos). As a special case, you can append + _any to <entry> to have it search for any matching entry. E.g. + _binman_u_boot_any_prop_pos will match entries called u-boot, + u-boot-img and u-boot-nodtb) + optional: True if the symbol is optional. If False this function + will raise if the symbol is not found + msg: Message to display if an error occurs + + Returns: + Value that should be assigned to that symbol, or None if it was + optional and not found + + Raises: + ValueError if the symbol is invalid or not found, or references a + property which is not supported + """ + m = re.match(r'^_binman_(\w+)_prop_(\w+)$', sym_name) + if not m: + raise ValueError("%s: Symbol '%s' has invalid format" % + (msg, sym_name)) + entry_name, prop_name = m.groups() + entry_name = entry_name.replace('_', '-') + entry = self._entries.get(entry_name) + if not entry: + if entry_name.endswith('-any'): + root = entry_name[:-4] + for name in self._entries: + if name.startswith(root): + rest = name[len(root):] + if rest in ['', '-img', '-nodtb']: + entry = self._entries[name] + if not entry: + err = ("%s: Entry '%s' not found in list (%s)" % + (msg, entry_name, ','.join(self._entries.keys()))) + if optional: + print('Warning: %s' % err, file=sys.stderr) + return None + raise ValueError(err) + if prop_name == 'pos': + return entry.pos + else: + raise ValueError("%s: No such property '%s'" % (msg, prop_name)) diff --git a/tools/binman/image_test.py b/tools/binman/image_test.py new file mode 100644 index 0000000..1b50dda --- /dev/null +++ b/tools/binman/image_test.py @@ -0,0 +1,46 @@ +# +# Copyright (c) 2017 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Test for the image module + +import unittest + +from image import Image +from elf_test import capture_sys_output + +class TestImage(unittest.TestCase): + def testInvalidFormat(self): + image = Image('name', 'node', test=True) + with self.assertRaises(ValueError) as e: + image.LookupSymbol('_binman_something_prop_', False, 'msg') + self.assertIn( + "msg: Symbol '_binman_something_prop_' has invalid format", + str(e.exception)) + + def testMissingSymbol(self): + image = Image('name', 'node', test=True) + image._entries = {} + with self.assertRaises(ValueError) as e: + image.LookupSymbol('_binman_type_prop_pname', False, 'msg') + self.assertIn("msg: Entry 'type' not found in list ()", + str(e.exception)) + + def testMissingSymbolOptional(self): + image = Image('name', 'node', test=True) + image._entries = {} + with capture_sys_output() as (stdout, stderr): + val = image.LookupSymbol('_binman_type_prop_pname', True, 'msg') + self.assertEqual(val, None) + self.assertEqual("Warning: msg: Entry 'type' not found in list ()\n", + stderr.getvalue()) + self.assertEqual('', stdout.getvalue()) + + def testBadProperty(self): + image = Image('name', 'node', test=True) + image._entries = {'u-boot': 1} + with self.assertRaises(ValueError) as e: + image.LookupSymbol('_binman_u_boot_prop_bad', False, 'msg') + self.assertIn("msg: No such property 'bad", str(e.exception)) diff --git a/tools/binman/test/21_image_pad.dts b/tools/binman/test/21_image_pad.dts index daf8385f..bf39dc1 100644 --- a/tools/binman/test/21_image_pad.dts +++ b/tools/binman/test/21_image_pad.dts @@ -10,7 +10,7 @@ }; u-boot { - pos = <12>; + pos = <20>; }; }; }; diff --git a/tools/binman/test/24_sorted.dts b/tools/binman/test/24_sorted.dts index 9f4151c..43a7831 100644 --- a/tools/binman/test/24_sorted.dts +++ b/tools/binman/test/24_sorted.dts @@ -7,11 +7,11 @@ binman { sort-by-pos; u-boot { - pos = <10>; + pos = <22>; }; u-boot-spl { - pos = <5>; + pos = <1>; }; }; }; diff --git a/tools/binman/test/28_pack_4gb_outside.dts b/tools/binman/test/28_pack_4gb_outside.dts index ff468c7..18d6bb5 100644 --- a/tools/binman/test/28_pack_4gb_outside.dts +++ b/tools/binman/test/28_pack_4gb_outside.dts @@ -7,13 +7,13 @@ binman { sort-by-pos; end-at-4gb; - size = <16>; + size = <32>; u-boot { pos = <0>; }; u-boot-spl { - pos = <0xfffffff7>; + pos = <0xffffffeb>; }; }; }; diff --git a/tools/binman/test/29_x86-rom.dts b/tools/binman/test/29_x86-rom.dts index 075ede3..d49078e 100644 --- a/tools/binman/test/29_x86-rom.dts +++ b/tools/binman/test/29_x86-rom.dts @@ -7,13 +7,13 @@ binman { sort-by-pos; end-at-4gb; - size = <16>; + size = <32>; u-boot { - pos = <0xfffffff0>; + pos = <0xffffffe0>; }; u-boot-spl { - pos = <0xfffffff7>; + pos = <0xffffffeb>; }; }; }; diff --git a/tools/binman/test/51_u_boot_spl_dtb.dts b/tools/binman/test/51_u_boot_spl_dtb.dts new file mode 100644 index 0000000..3912f86 --- /dev/null +++ b/tools/binman/test/51_u_boot_spl_dtb.dts @@ -0,0 +1,13 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + size = <16>; + + u-boot-spl-dtb { + }; + }; +}; diff --git a/tools/binman/test/52_u_boot_spl_nodtb.dts b/tools/binman/test/52_u_boot_spl_nodtb.dts new file mode 100644 index 0000000..7f4e277 --- /dev/null +++ b/tools/binman/test/52_u_boot_spl_nodtb.dts @@ -0,0 +1,11 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + u-boot-spl-nodtb { + }; + }; +}; diff --git a/tools/binman/test/53_symbols.dts b/tools/binman/test/53_symbols.dts new file mode 100644 index 0000000..980b066 --- /dev/null +++ b/tools/binman/test/53_symbols.dts @@ -0,0 +1,20 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + pad-byte = <0xff>; + u-boot-spl { + }; + + u-boot { + pos = <20>; + }; + + u-boot-spl2 { + type = "u-boot-spl"; + }; + }; +}; diff --git a/tools/binman/test/Makefile b/tools/binman/test/Makefile index 217d13c..e58fc80 100644 --- a/tools/binman/test/Makefile +++ b/tools/binman/test/Makefile @@ -10,8 +10,12 @@ CFLAGS := -march=i386 -m32 -nostdlib -I ../../../include LDS_UCODE := -T u_boot_ucode_ptr.lds +LDS_BINMAN := -T u_boot_binman_syms.lds +LDS_BINMAN_BAD := -T u_boot_binman_syms_bad.lds -TARGETS = u_boot_ucode_ptr u_boot_no_ucode_ptr bss_data +TARGETS = u_boot_ucode_ptr u_boot_no_ucode_ptr bss_data \ + u_boot_binman_syms u_boot_binman_syms.bin u_boot_binman_syms_bad \ + u_boot_binman_syms_size all: $(TARGETS) @@ -24,6 +28,18 @@ u_boot_ucode_ptr: u_boot_ucode_ptr.c bss_data: CFLAGS += bss_data.lds bss_data: bss_data.c +u_boot_binman_syms.bin: u_boot_binman_syms + objcopy -O binary $< -R .note.gnu.build-id $@ + +u_boot_binman_syms: CFLAGS += $(LDS_BINMAN) +u_boot_binman_syms: u_boot_binman_syms.c + +u_boot_binman_syms_bad: CFLAGS += $(LDS_BINMAN_BAD) +u_boot_binman_syms_bad: u_boot_binman_syms_bad.c + +u_boot_binman_syms_size: CFLAGS += $(LDS_BINMAN) +u_boot_binman_syms_size: u_boot_binman_syms_size.c + clean: rm -f $(TARGETS) diff --git a/tools/binman/test/bss_data.c b/tools/binman/test/bss_data.c index f865a9d..e0305c3 100644 --- a/tools/binman/test/bss_data.c +++ b/tools/binman/test/bss_data.c @@ -4,7 +4,7 @@ * SPDX-License-Identifier: GPL-2.0+ * * Simple program to create a _dt_ucode_base_size symbol which can be read - * by 'nm'. This is used by binman tests. + * by binutils. This is used by binman tests. */ int bss_data[10]; diff --git a/tools/binman/test/u_boot_binman_syms b/tools/binman/test/u_boot_binman_syms Binary files differnew file mode 100755 index 0000000..2e02dc0 --- /dev/null +++ b/tools/binman/test/u_boot_binman_syms diff --git a/tools/binman/test/u_boot_binman_syms.c b/tools/binman/test/u_boot_binman_syms.c new file mode 100644 index 0000000..a975476 --- /dev/null +++ b/tools/binman/test/u_boot_binman_syms.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2017 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + * + * Simple program to create some binman symbols. This is used by binman tests. + */ + +#define CONFIG_BINMAN +#include <binman_sym.h> + +binman_sym_declare(unsigned long, u_boot_spl, pos); +binman_sym_declare(unsigned long long, u_boot_spl2, pos); +binman_sym_declare(unsigned long, u_boot_any, pos); diff --git a/tools/binman/test/u_boot_binman_syms.lds b/tools/binman/test/u_boot_binman_syms.lds new file mode 100644 index 0000000..d3130cd --- /dev/null +++ b/tools/binman/test/u_boot_binman_syms.lds @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2016 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(_start) + +SECTIONS +{ + . = 0x00000000; + _start = .; + + . = ALIGN(4); + .text : + { + __image_copy_start = .; + *(.text*) + } + + . = ALIGN(4); + .binman_sym_table : { + __binman_sym_start = .; + KEEP(*(SORT(.binman_sym*))); + __binman_sym_end = .; + } + +} diff --git a/tools/binman/test/u_boot_binman_syms_bad b/tools/binman/test/u_boot_binman_syms_bad Binary files differnew file mode 100755 index 0000000..8da3d9d --- /dev/null +++ b/tools/binman/test/u_boot_binman_syms_bad diff --git a/tools/binman/test/u_boot_binman_syms_bad.c b/tools/binman/test/u_boot_binman_syms_bad.c new file mode 120000 index 0000000..939b2e9 --- /dev/null +++ b/tools/binman/test/u_boot_binman_syms_bad.c @@ -0,0 +1 @@ +u_boot_binman_syms.c
\ No newline at end of file diff --git a/tools/binman/test/u_boot_binman_syms_bad.lds b/tools/binman/test/u_boot_binman_syms_bad.lds new file mode 100644 index 0000000..0b474b5 --- /dev/null +++ b/tools/binman/test/u_boot_binman_syms_bad.lds @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2016 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(_start) + +SECTIONS +{ + . = 0x00000000; + _start = .; + + . = ALIGN(4); + .text : + { + *(.text*) + } + + . = ALIGN(4); + .binman_sym_table : { + __binman_sym_start = .; + KEEP(*(SORT(.binman_sym*))); + __binman_sym_end = .; + } + +} diff --git a/tools/binman/test/u_boot_binman_syms_size b/tools/binman/test/u_boot_binman_syms_size Binary files differnew file mode 100755 index 0000000..d691e89 --- /dev/null +++ b/tools/binman/test/u_boot_binman_syms_size diff --git a/tools/binman/test/u_boot_binman_syms_size.c b/tools/binman/test/u_boot_binman_syms_size.c new file mode 100644 index 0000000..ee4c048 --- /dev/null +++ b/tools/binman/test/u_boot_binman_syms_size.c @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2017 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + * + * Simple program to create some binman symbols. This is used by binman tests. + */ + +#define CONFIG_BINMAN +#include <binman_sym.h> + +binman_sym_declare(char, u_boot_spl, pos); diff --git a/tools/binman/test/u_boot_ucode_ptr.c b/tools/binman/test/u_boot_ucode_ptr.c index 24f349f..734d54f 100644 --- a/tools/binman/test/u_boot_ucode_ptr.c +++ b/tools/binman/test/u_boot_ucode_ptr.c @@ -4,7 +4,7 @@ * SPDX-License-Identifier: GPL-2.0+ * * Simple program to create a _dt_ucode_base_size symbol which can be read - * by 'nm'. This is used by binman tests. + * by binutils. This is used by binman tests. */ static unsigned long _dt_ucode_base_size[2] |