aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2021-01-28 11:37:58 -0500
committerTom Rini <trini@konsulko.com>2021-01-28 11:37:58 -0500
commit07394fb05e4d48fee360ef38c96b3ef0576b7352 (patch)
treeeaf9b03553cbea1907d578a86799aafaf4887504
parent8b195f4b716e4d802768e0e2cd63b417a4690b7f (diff)
parent54f884bb0b1ebc16946890bb8349fe0ca2455bb2 (diff)
downloadu-boot-WIP/28Jan2021.zip
u-boot-WIP/28Jan2021.tar.gz
u-boot-WIP/28Jan2021.tar.bz2
Merge branch '2021-01-27-assorted-fixes-and-improvements'WIP/28Jan2021
- A wide variety of fixes throughout the tree.
-rw-r--r--Makefile6
-rw-r--r--README7
-rw-r--r--cmd/sleep.c2
-rw-r--r--common/Kconfig10
-rw-r--r--common/autoboot.c6
-rw-r--r--common/bloblist.c17
-rw-r--r--common/board_f.c10
-rw-r--r--common/image-fit-sig.c2
-rw-r--r--common/spl/Kconfig9
-rw-r--r--common/spl/spl.c6
-rw-r--r--doc/device-tree-bindings/rtc/abracon,abx80x.txt31
-rw-r--r--drivers/Makefile1
-rw-r--r--drivers/mmc/pci_mmc.c19
-rw-r--r--drivers/pci/pci_auto.c104
-rw-r--r--drivers/pci/pci_auto_old.c18
-rw-r--r--drivers/rtc/Kconfig9
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/abx80x.c553
-rw-r--r--drivers/video/video-uclass.c10
-rw-r--r--include/binman.h14
-rw-r--r--include/bloblist.h10
-rw-r--r--include/bootcount.h6
-rw-r--r--include/linux/arm-smccc.h4
-rw-r--r--include/spl.h53
-rw-r--r--include/uuid.h1
-rw-r--r--include/video.h14
-rw-r--r--lib/Makefile2
-rw-r--r--lib/binman.c61
-rw-r--r--lib/display_options.c9
-rw-r--r--lib/fdtdec.c5
-rw-r--r--lib/rsa/rsa-verify.c4
-rw-r--r--net/eth-uclass.c2
-rw-r--r--scripts/config_whitelist.txt1
-rw-r--r--test/bloblist.c36
34 files changed, 915 insertions, 128 deletions
diff --git a/Makefile b/Makefile
index cef149d..72be573 100644
--- a/Makefile
+++ b/Makefile
@@ -885,7 +885,7 @@ cmd_static_rela = \
tools/relocate-rela $(3) $(4) $$start $$end
else
quiet_cmd_static_rela =
-cmd_static_rela = true
+cmd_static_rela =
endif
# Always append INPUTS so that arch config.mk's can add custom ones
@@ -1312,7 +1312,11 @@ endif
shell_cmd = { $(call echo-cmd,$(1)) $(cmd_$(1)); }
quiet_cmd_objcopy_uboot = OBJCOPY $@
+ifdef cmd_static_rela
cmd_objcopy_uboot = $(cmd_objcopy) && $(call shell_cmd,static_rela,$<,$@,$(CONFIG_SYS_TEXT_BASE)) || { rm -f $@; false; }
+else
+cmd_objcopy_uboot = $(cmd_objcopy)
+endif
u-boot-nodtb.bin: u-boot FORCE
$(call if_changed,objcopy_uboot)
diff --git a/README b/README
index 89606c8..f7f9aa5 100644
--- a/README
+++ b/README
@@ -2770,13 +2770,6 @@ Low Level (hardware related) configuration options:
CONFIG_SYS_OR3_PRELIM, CONFIG_SYS_BR3_PRELIM:
Memory Controller Definitions: BR2/3 and OR2/3 (SDRAM)
-- CONFIG_PCI_ENUM_ONLY
- Only scan through and get the devices on the buses.
- Don't do any setup work, presumably because someone or
- something has already done it, and we don't need to do it
- a second time. Useful for platforms that are pre-booted
- by coreboot or similar.
-
- CONFIG_PCI_INDIRECT_BRIDGE:
Enable support for indirect PCI bridges.
diff --git a/cmd/sleep.c b/cmd/sleep.c
index f0c78a8..1fff400 100644
--- a/cmd/sleep.c
+++ b/cmd/sleep.c
@@ -40,7 +40,7 @@ static int do_sleep(struct cmd_tbl *cmdtp, int flag, int argc,
while (get_timer(start) < delay) {
if (ctrlc())
- return (-1);
+ return CMD_RET_FAILURE;
udelay(100);
}
diff --git a/common/Kconfig b/common/Kconfig
index d8982ba..45535e3 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -697,6 +697,16 @@ config BLOBLIST_ADDR
Sets the address of the bloblist, set up by the first part of U-Boot
which runs. Subsequent U-Boot stages typically use the same address.
+config BLOBLIST_SIZE_RELOC
+ hex "Size of bloblist after relocation"
+ depends on BLOBLIST
+ default BLOBLIST_SIZE
+ help
+ Sets the size of the bloblist in bytes after relocation. Since U-Boot
+ has a lot more memory available then, it is possible to use a larger
+ size than the one set up by SPL. This bloblist is set up during the
+ relocation process.
+
endmenu
source "common/spl/Kconfig"
diff --git a/common/autoboot.c b/common/autoboot.c
index ddb6246..b025fd9 100644
--- a/common/autoboot.c
+++ b/common/autoboot.c
@@ -164,9 +164,9 @@ static int passwd_abort_key(uint64_t etime)
};
char presskey[MAX_DELAY_STOP_STR];
- u_int presskey_len = 0;
- u_int presskey_max = 0;
- u_int i;
+ int presskey_len = 0;
+ int presskey_max = 0;
+ int i;
# ifdef CONFIG_AUTOBOOT_DELAY_STR
if (delaykey[0].str == NULL)
diff --git a/common/bloblist.c b/common/bloblist.c
index 33b5862..0e6448b 100644
--- a/common/bloblist.c
+++ b/common/bloblist.c
@@ -33,6 +33,12 @@ static const char *const tag_name[] = {
[BLOBLISTT_SPL_HANDOFF] = "SPL hand-off",
[BLOBLISTT_VBOOT_CTX] = "Chrome OS vboot context",
[BLOBLISTT_VBOOT_HANDOFF] = "Chrome OS vboot hand-off",
+ [BLOBLISTT_ACPI_GNVS] = "ACPI GNVS",
+ [BLOBLISTT_INTEL_VBT] = "Intel Video-BIOS table",
+ [BLOBLISTT_TPM2_TCG_LOG] = "TPM v2 log space",
+ [BLOBLISTT_TCPA_LOG] = "TPM log space",
+ [BLOBLISTT_ACPI_TABLES] = "ACPI tables for x86",
+ [BLOBLISTT_SMBIOS_TABLES] = "SMBIOS tables for x86",
};
const char *bloblist_tag_name(enum bloblist_tag_t tag)
@@ -317,6 +323,15 @@ void bloblist_show_list(void)
}
}
+void bloblist_reloc(void *to, uint to_size, void *from, uint from_size)
+{
+ struct bloblist_hdr *hdr;
+
+ memcpy(to, from, from_size);
+ hdr = to;
+ hdr->size = to_size;
+}
+
int bloblist_init(void)
{
bool expected;
@@ -327,6 +342,8 @@ int bloblist_init(void)
* that runs
*/
expected = !u_boot_first_phase();
+ if (spl_prev_phase() == PHASE_TPL && !IS_ENABLED(CONFIG_TPL_BLOBLIST))
+ expected = false;
if (expected)
ret = bloblist_check(CONFIG_BLOBLIST_ADDR,
CONFIG_BLOBLIST_SIZE);
diff --git a/common/board_f.c b/common/board_f.c
index ae3001b..4327a43 100644
--- a/common/board_f.c
+++ b/common/board_f.c
@@ -568,9 +568,10 @@ static int reserve_bloblist(void)
{
#ifdef CONFIG_BLOBLIST
/* Align to a 4KB boundary for easier reading of addresses */
- gd->start_addr_sp = ALIGN_DOWN(gd->start_addr_sp - CONFIG_BLOBLIST_SIZE,
- 0x1000);
- gd->new_bloblist = map_sysmem(gd->start_addr_sp, CONFIG_BLOBLIST_SIZE);
+ gd->start_addr_sp = ALIGN_DOWN(gd->start_addr_sp -
+ CONFIG_BLOBLIST_SIZE_RELOC, 0x1000);
+ gd->new_bloblist = map_sysmem(gd->start_addr_sp,
+ CONFIG_BLOBLIST_SIZE_RELOC);
#endif
return 0;
@@ -658,7 +659,8 @@ static int reloc_bloblist(void)
debug("Copying bloblist from %p to %p, size %x\n",
gd->bloblist, gd->new_bloblist, size);
- memcpy(gd->new_bloblist, gd->bloblist, size);
+ bloblist_reloc(gd->new_bloblist, CONFIG_BLOBLIST_SIZE_RELOC,
+ gd->bloblist, size);
gd->bloblist = gd->new_bloblist;
}
#endif
diff --git a/common/image-fit-sig.c b/common/image-fit-sig.c
index d39741e..31cc580 100644
--- a/common/image-fit-sig.c
+++ b/common/image-fit-sig.c
@@ -360,7 +360,7 @@ static int fit_config_verify_sig(const void *fit, int conf_noffset,
const void *sig_blob, int sig_offset)
{
int noffset;
- char *err_msg = "";
+ char *err_msg = "No 'signature' subnode found";
int verified = 0;
int ret;
diff --git a/common/spl/Kconfig b/common/spl/Kconfig
index bdc229f..774541c 100644
--- a/common/spl/Kconfig
+++ b/common/spl/Kconfig
@@ -186,7 +186,7 @@ config SPL_BOOTROM_SUPPORT
config SPL_BOOTCOUNT_LIMIT
bool "Support bootcount in SPL"
- depends on SPL_ENV_SUPPORT
+ depends on SPL_ENV_SUPPORT && !TPL_BOOTCOUNT_LIMIT
help
On some boards, which use 'falcon' mode, it is necessary to check
and increment the number of boot attempts. Such boards do not
@@ -1382,6 +1382,13 @@ config TPL_BOARD_INIT
spl_board_init() from board_init_r(). This function should be
provided by the board.
+config TPL_BOOTCOUNT_LIMIT
+ bool "Support bootcount in TPL"
+ depends on TPL_ENV_SUPPORT
+ help
+ If this option is enabled, the TPL will support bootcount.
+ For example, it may be useful to choose the device to boot.
+
config TPL_LDSCRIPT
string "Linker script for the TPL stage"
depends on TPL
diff --git a/common/spl/spl.c b/common/spl/spl.c
index 835c53d..8cb6f3d 100644
--- a/common/spl/spl.c
+++ b/common/spl/spl.c
@@ -734,7 +734,7 @@ void board_init_r(gd_t *dummy1, ulong dummy2)
debug("Failed to stash bootstage: err=%d\n", ret);
#endif
- debug("loaded - jumping to U-Boot...\n");
+ debug("loaded - jumping to %s...\n", spl_phase_name(spl_next_phase()));
spl_board_prepare_for_boot();
jump_to_image_no_args(&spl_image);
}
@@ -837,7 +837,9 @@ ulong spl_relocate_stack_gd(void)
#endif
}
-#if defined(CONFIG_BOOTCOUNT_LIMIT) && !defined(CONFIG_SPL_BOOTCOUNT_LIMIT)
+#if defined(CONFIG_BOOTCOUNT_LIMIT) && \
+ ((!defined(CONFIG_TPL_BUILD) && !defined(CONFIG_SPL_BOOTCOUNT_LIMIT)) || \
+ (defined(CONFIG_TPL_BUILD) && !defined(CONFIG_TPL_BOOTCOUNT_LIMIT)))
void bootcount_store(ulong a)
{
}
diff --git a/doc/device-tree-bindings/rtc/abracon,abx80x.txt b/doc/device-tree-bindings/rtc/abracon,abx80x.txt
new file mode 100644
index 0000000..2405e35
--- /dev/null
+++ b/doc/device-tree-bindings/rtc/abracon,abx80x.txt
@@ -0,0 +1,31 @@
+Abracon ABX80X I2C ultra low power RTC/Alarm chip
+
+The Abracon ABX80X family consist of the ab0801, ab0803, ab0804, ab0805, ab1801,
+ab1803, ab1804 and ab1805. The ab0805 is the superset of ab080x and the ab1805
+is the superset of ab180x.
+
+Required properties:
+
+ - "compatible": should one of:
+ "abracon,abx80x"
+ "abracon,ab0801"
+ "abracon,ab0803"
+ "abracon,ab0804"
+ "abracon,ab0805"
+ "abracon,ab1801"
+ "abracon,ab1803"
+ "abracon,ab1804"
+ "abracon,ab1805"
+ "microcrystal,rv1805"
+ Using "abracon,abx80x" will enable chip autodetection.
+ - "reg": I2C bus address of the device
+
+Optional properties:
+
+The abx804 and abx805 have a trickle charger that is able to charge the
+connected battery or supercap. Both the following properties have to be defined
+and valid to enable charging:
+
+ - "abracon,tc-diode": should be "standard" (0.6V) or "schottky" (0.3V)
+ - "abracon,tc-resistor": should be <0>, <3>, <6> or <11>. 0 disables the output
+ resistor, the other values are in kOhm.
diff --git a/drivers/Makefile b/drivers/Makefile
index e371bc3..c562a71 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -69,6 +69,7 @@ endif
ifdef CONFIG_TPL_BUILD
+obj-$(CONFIG_TPL_BOOTCOUNT_LIMIT) += bootcount/
obj-$(CONFIG_TPL_MPC8XXX_INIT_DDR_SUPPORT) += ddr/fsl/
endif
diff --git a/drivers/mmc/pci_mmc.c b/drivers/mmc/pci_mmc.c
index b26eb03..fd5dd22 100644
--- a/drivers/mmc/pci_mmc.c
+++ b/drivers/mmc/pci_mmc.c
@@ -10,6 +10,7 @@
#include <log.h>
#include <malloc.h>
#include <mapmem.h>
+#include <mmc.h>
#include <sdhci.h>
#include <acpi/acpigen.h>
#include <acpi/acpi_device.h>
@@ -17,6 +18,12 @@
#include <asm-generic/gpio.h>
#include <dm/acpi.h>
+/* Type of MMC device */
+enum {
+ TYPE_SD,
+ TYPE_EMMC,
+};
+
struct pci_mmc_plat {
struct mmc_config cfg;
struct mmc mmc;
@@ -34,8 +41,15 @@ static int pci_mmc_probe(struct udevice *dev)
struct pci_mmc_plat *plat = dev_get_plat(dev);
struct pci_mmc_priv *priv = dev_get_priv(dev);
struct sdhci_host *host = &priv->host;
+ struct blk_desc *desc;
int ret;
+ ret = mmc_of_parse(dev, &plat->cfg);
+ if (ret)
+ return ret;
+ desc = mmc_get_blk_desc(&plat->mmc);
+ desc->removable = !(plat->cfg.host_caps & MMC_CAP_NONREMOVABLE);
+
host->ioaddr = (void *)dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0,
PCI_REGION_MEM);
host->name = dev->name;
@@ -79,6 +93,8 @@ static int pci_mmc_acpi_fill_ssdt(const struct udevice *dev,
if (!dev_has_ofnode(dev))
return 0;
+ if (dev_get_driver_data(dev) == TYPE_EMMC)
+ return 0;
ret = gpio_get_acpi(&priv->cd_gpio, &gpio);
if (ret)
@@ -122,7 +138,8 @@ struct acpi_ops pci_mmc_acpi_ops = {
};
static const struct udevice_id pci_mmc_match[] = {
- { .compatible = "intel,apl-sd" },
+ { .compatible = "intel,apl-sd", .data = TYPE_SD },
+ { .compatible = "intel,apl-emmc", .data = TYPE_EMMC },
{ }
};
diff --git a/drivers/pci/pci_auto.c b/drivers/pci/pci_auto.c
index b37dd99..da76148 100644
--- a/drivers/pci/pci_auto.c
+++ b/drivers/pci/pci_auto.c
@@ -18,10 +18,10 @@
#define CONFIG_SYS_PCI_CACHE_LINE_SIZE 8
#endif
-void dm_pciauto_setup_device(struct udevice *dev, int bars_num,
- struct pci_region *mem,
- struct pci_region *prefetch, struct pci_region *io,
- bool enum_only)
+static void dm_pciauto_setup_device(struct udevice *dev, int bars_num,
+ struct pci_region *mem,
+ struct pci_region *prefetch,
+ struct pci_region *io)
{
u32 bar_response;
pci_size_t bar_size;
@@ -43,8 +43,7 @@ void dm_pciauto_setup_device(struct udevice *dev, int bars_num,
int ret = 0;
/* Tickle the BAR and get the response */
- if (!enum_only)
- dm_pci_write_config32(dev, bar, 0xffffffff);
+ dm_pci_write_config32(dev, bar, 0xffffffff);
dm_pci_read_config32(dev, bar, &bar_response);
/* If BAR is not implemented (or invalid) go to the next BAR */
@@ -58,8 +57,7 @@ void dm_pciauto_setup_device(struct udevice *dev, int bars_num,
bar_size = bar_response & PCI_BASE_ADDRESS_IO_MASK;
bar_size &= ~(bar_size - 1);
- if (!enum_only)
- bar_res = io;
+ bar_res = io;
debug("PCI Autoconfig: BAR %d, I/O, size=0x%llx, ",
bar_nr, (unsigned long long)bar_size);
@@ -69,10 +67,7 @@ void dm_pciauto_setup_device(struct udevice *dev, int bars_num,
u32 bar_response_upper;
u64 bar64;
- if (!enum_only) {
- dm_pci_write_config32(dev, bar + 4,
- 0xffffffff);
- }
+ dm_pci_write_config32(dev, bar + 4, 0xffffffff);
dm_pci_read_config32(dev, bar + 4,
&bar_response_upper);
@@ -81,33 +76,29 @@ void dm_pciauto_setup_device(struct udevice *dev, int bars_num,
bar_size = ~(bar64 & PCI_BASE_ADDRESS_MEM_MASK)
+ 1;
- if (!enum_only)
- found_mem64 = 1;
+ found_mem64 = 1;
} else {
bar_size = (u32)(~(bar_response &
PCI_BASE_ADDRESS_MEM_MASK) + 1);
}
- if (!enum_only) {
- if (prefetch && (bar_response &
- PCI_BASE_ADDRESS_MEM_PREFETCH)) {
- bar_res = prefetch;
- } else {
- bar_res = mem;
- }
- }
+
+ if (prefetch &&
+ (bar_response & PCI_BASE_ADDRESS_MEM_PREFETCH))
+ bar_res = prefetch;
+ else
+ bar_res = mem;
debug("PCI Autoconfig: BAR %d, %s, size=0x%llx, ",
bar_nr, bar_res == prefetch ? "Prf" : "Mem",
(unsigned long long)bar_size);
}
- if (!enum_only) {
- ret = pciauto_region_allocate(bar_res, bar_size,
- &bar_value, found_mem64);
- if (ret)
- printf("PCI: Failed autoconfig bar %x\n", bar);
- }
- if (!enum_only && !ret) {
+ ret = pciauto_region_allocate(bar_res, bar_size,
+ &bar_value, found_mem64);
+ if (ret)
+ printf("PCI: Failed autoconfig bar %x\n", bar);
+
+ if (!ret) {
/* Write it out and update our limit */
dm_pci_write_config32(dev, bar, (u32)bar_value);
@@ -135,28 +126,24 @@ void dm_pciauto_setup_device(struct udevice *dev, int bars_num,
bar_nr++;
}
- if (!enum_only) {
- /* Configure the expansion ROM address */
- dm_pci_read_config8(dev, PCI_HEADER_TYPE, &header_type);
- header_type &= 0x7f;
- if (header_type != PCI_HEADER_TYPE_CARDBUS) {
- rom_addr = (header_type == PCI_HEADER_TYPE_NORMAL) ?
- PCI_ROM_ADDRESS : PCI_ROM_ADDRESS1;
- dm_pci_write_config32(dev, rom_addr, 0xfffffffe);
- dm_pci_read_config32(dev, rom_addr, &bar_response);
- if (bar_response) {
- bar_size = -(bar_response & ~1);
- debug("PCI Autoconfig: ROM, size=%#x, ",
- (unsigned int)bar_size);
- if (pciauto_region_allocate(mem, bar_size,
- &bar_value,
- false) == 0) {
- dm_pci_write_config32(dev, rom_addr,
- bar_value);
- }
- cmdstat |= PCI_COMMAND_MEMORY;
- debug("\n");
+ /* Configure the expansion ROM address */
+ dm_pci_read_config8(dev, PCI_HEADER_TYPE, &header_type);
+ header_type &= 0x7f;
+ if (header_type != PCI_HEADER_TYPE_CARDBUS) {
+ rom_addr = (header_type == PCI_HEADER_TYPE_NORMAL) ?
+ PCI_ROM_ADDRESS : PCI_ROM_ADDRESS1;
+ dm_pci_write_config32(dev, rom_addr, 0xfffffffe);
+ dm_pci_read_config32(dev, rom_addr, &bar_response);
+ if (bar_response) {
+ bar_size = -(bar_response & ~1);
+ debug("PCI Autoconfig: ROM, size=%#x, ",
+ (unsigned int)bar_size);
+ if (pciauto_region_allocate(mem, bar_size, &bar_value,
+ false) == 0) {
+ dm_pci_write_config32(dev, rom_addr, bar_value);
}
+ cmdstat |= PCI_COMMAND_MEMORY;
+ debug("\n");
}
}
@@ -319,15 +306,10 @@ int dm_pciauto_config_device(struct udevice *dev)
struct pci_region *pci_io;
unsigned int sub_bus = PCI_BUS(dm_pci_get_bdf(dev));
unsigned short class;
- bool enum_only = false;
struct udevice *ctlr = pci_get_controller(dev);
struct pci_controller *ctlr_hose = dev_get_uclass_priv(ctlr);
int ret;
-#ifdef CONFIG_PCI_ENUM_ONLY
- enum_only = true;
-#endif
-
pci_mem = ctlr_hose->pci_mem;
pci_prefetch = ctlr_hose->pci_prefetch;
pci_io = ctlr_hose->pci_io;
@@ -339,8 +321,7 @@ int dm_pciauto_config_device(struct udevice *dev)
debug("PCI Autoconfig: Found P2P bridge, device %d\n",
PCI_DEV(dm_pci_get_bdf(dev)));
- dm_pciauto_setup_device(dev, 2, pci_mem, pci_prefetch, pci_io,
- enum_only);
+ dm_pciauto_setup_device(dev, 2, pci_mem, pci_prefetch, pci_io);
ret = dm_pci_hose_probe_bus(dev);
if (ret < 0)
@@ -353,8 +334,7 @@ int dm_pciauto_config_device(struct udevice *dev)
* just do a minimal setup of the bridge,
* let the OS take care of the rest
*/
- dm_pciauto_setup_device(dev, 0, pci_mem, pci_prefetch, pci_io,
- enum_only);
+ dm_pciauto_setup_device(dev, 0, pci_mem, pci_prefetch, pci_io);
debug("PCI Autoconfig: Found P2CardBus bridge, device %d\n",
PCI_DEV(dm_pci_get_bdf(dev)));
@@ -378,8 +358,7 @@ int dm_pciauto_config_device(struct udevice *dev)
*/
debug("PCI Autoconfig: Broken bridge found, only minimal config\n");
dm_pciauto_setup_device(dev, 0, hose->pci_mem,
- hose->pci_prefetch, hose->pci_io,
- enum_only);
+ hose->pci_prefetch, hose->pci_io);
break;
#endif
@@ -388,8 +367,7 @@ int dm_pciauto_config_device(struct udevice *dev)
/* fall through */
default:
- dm_pciauto_setup_device(dev, 6, pci_mem, pci_prefetch, pci_io,
- enum_only);
+ dm_pciauto_setup_device(dev, 6, pci_mem, pci_prefetch, pci_io);
break;
}
diff --git a/drivers/pci/pci_auto_old.c b/drivers/pci/pci_auto_old.c
index 8b67cfa..c56ff53 100644
--- a/drivers/pci/pci_auto_old.c
+++ b/drivers/pci/pci_auto_old.c
@@ -36,13 +36,11 @@ void pciauto_setup_device(struct pci_controller *hose,
pci_size_t bar_size;
u16 cmdstat = 0;
int bar, bar_nr = 0;
-#ifndef CONFIG_PCI_ENUM_ONLY
u8 header_type;
int rom_addr;
pci_addr_t bar_value;
struct pci_region *bar_res;
int found_mem64 = 0;
-#endif
u16 class;
pci_hose_read_config_word(hose, dev, PCI_COMMAND, &cmdstat);
@@ -51,26 +49,20 @@ void pciauto_setup_device(struct pci_controller *hose,
for (bar = PCI_BASE_ADDRESS_0;
bar < PCI_BASE_ADDRESS_0 + (bars_num * 4); bar += 4) {
/* Tickle the BAR and get the response */
-#ifndef CONFIG_PCI_ENUM_ONLY
pci_hose_write_config_dword(hose, dev, bar, 0xffffffff);
-#endif
pci_hose_read_config_dword(hose, dev, bar, &bar_response);
/* If BAR is not implemented go to the next BAR */
if (!bar_response)
continue;
-#ifndef CONFIG_PCI_ENUM_ONLY
found_mem64 = 0;
-#endif
/* Check the BAR type and set our address mask */
if (bar_response & PCI_BASE_ADDRESS_SPACE) {
bar_size = ((~(bar_response & PCI_BASE_ADDRESS_IO_MASK))
& 0xffff) + 1;
-#ifndef CONFIG_PCI_ENUM_ONLY
bar_res = io;
-#endif
debug("PCI Autoconfig: BAR %d, I/O, size=0x%llx, ",
bar_nr, (unsigned long long)bar_size);
@@ -80,23 +72,18 @@ void pciauto_setup_device(struct pci_controller *hose,
u32 bar_response_upper;
u64 bar64;
-#ifndef CONFIG_PCI_ENUM_ONLY
pci_hose_write_config_dword(hose, dev, bar + 4,
0xffffffff);
-#endif
pci_hose_read_config_dword(hose, dev, bar + 4,
&bar_response_upper);
bar64 = ((u64)bar_response_upper << 32) | bar_response;
bar_size = ~(bar64 & PCI_BASE_ADDRESS_MEM_MASK) + 1;
-#ifndef CONFIG_PCI_ENUM_ONLY
found_mem64 = 1;
-#endif
} else {
bar_size = (u32)(~(bar_response & PCI_BASE_ADDRESS_MEM_MASK) + 1);
}
-#ifndef CONFIG_PCI_ENUM_ONLY
if (prefetch && (bar_response & PCI_BASE_ADDRESS_MEM_PREFETCH))
bar_res = prefetch;
else
@@ -105,10 +92,8 @@ void pciauto_setup_device(struct pci_controller *hose,
debug("PCI Autoconfig: BAR %d, %s, size=0x%llx, ",
bar_nr, bar_res == prefetch ? "Prf" : "Mem",
(unsigned long long)bar_size);
-#endif
}
-#ifndef CONFIG_PCI_ENUM_ONLY
if (pciauto_region_allocate(bar_res, bar_size,
&bar_value, found_mem64) == 0) {
/* Write it out and update our limit */
@@ -129,7 +114,6 @@ void pciauto_setup_device(struct pci_controller *hose,
}
}
-#endif
cmdstat |= (bar_response & PCI_BASE_ADDRESS_SPACE) ?
PCI_COMMAND_IO : PCI_COMMAND_MEMORY;
@@ -138,7 +122,6 @@ void pciauto_setup_device(struct pci_controller *hose,
bar_nr++;
}
-#ifndef CONFIG_PCI_ENUM_ONLY
/* Configure the expansion ROM address */
pci_hose_read_config_byte(hose, dev, PCI_HEADER_TYPE, &header_type);
header_type &= 0x7f;
@@ -160,7 +143,6 @@ void pciauto_setup_device(struct pci_controller *hose,
debug("\n");
}
}
-#endif
/* PCI_COMMAND_IO must be set for VGA device */
pci_hose_read_config_word(hose, dev, PCI_CLASS_DEVICE, &class);
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index cad667a..aa6d901 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -166,4 +166,13 @@ config RTC_STM32
help
Enable STM32 RTC driver. This driver supports the rtc that is present
on some STM32 SoCs.
+
+config RTC_ABX80X
+ bool "Enable Abracon ABx80x RTC driver"
+ depends on DM_RTC
+ help
+ If you say yes here you get support for Abracon AB080X and AB180X
+ families of ultra-low-power battery- and capacitor-backed real-time
+ clock chips.
+
endmenu
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index ef66dc4..6a45a9c 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -55,3 +55,4 @@ obj-$(CONFIG_RTC_S35392A) += s35392a.o
obj-$(CONFIG_RTC_STM32) += stm32_rtc.o
obj-$(CONFIG_SANDBOX) += sandbox_rtc.o
obj-$(CONFIG_RTC_X1205) += x1205.o
+obj-$(CONFIG_RTC_ABX80X) += abx80x.o
diff --git a/drivers/rtc/abx80x.c b/drivers/rtc/abx80x.c
new file mode 100644
index 0000000..528b06c
--- /dev/null
+++ b/drivers/rtc/abx80x.c
@@ -0,0 +1,553 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * A driver for the I2C members of the Abracon AB x8xx RTC family,
+ * and compatible: AB 1805 and AB 0805
+ *
+ * Copyright 2014-2015 Macq S.A.
+ * Copyright 2020 Linaro
+ *
+ * Author: Philippe De Muyter <phdm@macqel.be>
+ * Author: Alexandre Belloni <alexandre.belloni@bootlin.com>
+ * Author: Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>
+ *
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <i2c.h>
+#include <rtc.h>
+#include <log.h>
+
+#define ABX8XX_REG_HTH 0x00
+#define ABX8XX_REG_SC 0x01
+#define ABX8XX_REG_MN 0x02
+#define ABX8XX_REG_HR 0x03
+#define ABX8XX_REG_DA 0x04
+#define ABX8XX_REG_MO 0x05
+#define ABX8XX_REG_YR 0x06
+#define ABX8XX_REG_WD 0x07
+
+#define ABX8XX_REG_AHTH 0x08
+#define ABX8XX_REG_ASC 0x09
+#define ABX8XX_REG_AMN 0x0a
+#define ABX8XX_REG_AHR 0x0b
+#define ABX8XX_REG_ADA 0x0c
+#define ABX8XX_REG_AMO 0x0d
+#define ABX8XX_REG_AWD 0x0e
+
+#define ABX8XX_REG_STATUS 0x0f
+#define ABX8XX_STATUS_AF BIT(2)
+#define ABX8XX_STATUS_BLF BIT(4)
+#define ABX8XX_STATUS_WDT BIT(6)
+
+#define ABX8XX_REG_CTRL1 0x10
+#define ABX8XX_CTRL_WRITE BIT(0)
+#define ABX8XX_CTRL_ARST BIT(2)
+#define ABX8XX_CTRL_12_24 BIT(6)
+
+#define ABX8XX_REG_CTRL2 0x11
+#define ABX8XX_CTRL2_RSVD BIT(5)
+
+#define ABX8XX_REG_IRQ 0x12
+#define ABX8XX_IRQ_AIE BIT(2)
+#define ABX8XX_IRQ_IM_1_4 (0x3 << 5)
+
+#define ABX8XX_REG_CD_TIMER_CTL 0x18
+
+#define ABX8XX_REG_OSC 0x1c
+#define ABX8XX_OSC_FOS BIT(3)
+#define ABX8XX_OSC_BOS BIT(4)
+#define ABX8XX_OSC_ACAL_512 BIT(5)
+#define ABX8XX_OSC_ACAL_1024 BIT(6)
+
+#define ABX8XX_OSC_OSEL BIT(7)
+
+#define ABX8XX_REG_OSS 0x1d
+#define ABX8XX_OSS_OF BIT(1)
+#define ABX8XX_OSS_OMODE BIT(4)
+
+#define ABX8XX_REG_WDT 0x1b
+#define ABX8XX_WDT_WDS BIT(7)
+#define ABX8XX_WDT_BMB_MASK 0x7c
+#define ABX8XX_WDT_BMB_SHIFT 2
+#define ABX8XX_WDT_MAX_TIME (ABX8XX_WDT_BMB_MASK >> ABX8XX_WDT_BMB_SHIFT)
+#define ABX8XX_WDT_WRB_MASK 0x03
+#define ABX8XX_WDT_WRB_1HZ 0x02
+
+#define ABX8XX_REG_CFG_KEY 0x1f
+#define ABX8XX_CFG_KEY_OSC 0xa1
+#define ABX8XX_CFG_KEY_MISC 0x9d
+
+#define ABX8XX_REG_ID0 0x28
+
+#define ABX8XX_REG_OUT_CTRL 0x30
+#define ABX8XX_OUT_CTRL_EXDS BIT(4)
+
+#define ABX8XX_REG_TRICKLE 0x20
+#define ABX8XX_TRICKLE_CHARGE_ENABLE 0xa0
+#define ABX8XX_TRICKLE_STANDARD_DIODE 0x8
+#define ABX8XX_TRICKLE_SCHOTTKY_DIODE 0x4
+
+static u8 trickle_resistors[] = {0, 3, 6, 11};
+
+enum abx80x_chip {AB0801, AB0803, AB0804, AB0805,
+ AB1801, AB1803, AB1804, AB1805, RV1805, ABX80X};
+
+struct abx80x_cap {
+ u16 pn;
+ bool has_tc;
+ bool has_wdog;
+};
+
+static struct abx80x_cap abx80x_caps[] = {
+ [AB0801] = {.pn = 0x0801},
+ [AB0803] = {.pn = 0x0803},
+ [AB0804] = {.pn = 0x0804, .has_tc = true, .has_wdog = true},
+ [AB0805] = {.pn = 0x0805, .has_tc = true, .has_wdog = true},
+ [AB1801] = {.pn = 0x1801},
+ [AB1803] = {.pn = 0x1803},
+ [AB1804] = {.pn = 0x1804, .has_tc = true, .has_wdog = true},
+ [AB1805] = {.pn = 0x1805, .has_tc = true, .has_wdog = true},
+ [RV1805] = {.pn = 0x1805, .has_tc = true, .has_wdog = true},
+ [ABX80X] = {.pn = 0}
+};
+
+static int abx80x_rtc_read8(struct udevice *dev, unsigned int reg)
+{
+ int ret = 0;
+ u8 buf;
+
+ if (reg > 0xff)
+ return -EINVAL;
+
+ ret = dm_i2c_read(dev, reg, &buf, sizeof(buf));
+ if (ret < 0)
+ return ret;
+
+ return buf;
+}
+
+static int abx80x_rtc_write8(struct udevice *dev, unsigned int reg, int val)
+{
+ u8 buf = (u8)val;
+
+ if (reg > 0xff)
+ return -EINVAL;
+
+ return dm_i2c_write(dev, reg, &buf, sizeof(buf));
+}
+
+static int abx80x_is_rc_mode(struct udevice *dev)
+{
+ int flags = 0;
+
+ flags = dm_i2c_reg_read(dev, ABX8XX_REG_OSS);
+ if (flags < 0) {
+ log_err("Failed to read autocalibration attribute\n");
+ return flags;
+ }
+
+ return (flags & ABX8XX_OSS_OMODE) ? 1 : 0;
+}
+
+static int abx80x_enable_trickle_charger(struct udevice *dev, u8 trickle_cfg)
+{
+ int err;
+
+ /*
+ * Write the configuration key register to enable access to the Trickle
+ * register
+ */
+ err = dm_i2c_reg_write(dev, ABX8XX_REG_CFG_KEY, ABX8XX_CFG_KEY_MISC);
+ if (err < 0) {
+ log_err("Unable to write configuration key\n");
+ return -EIO;
+ }
+
+ err = dm_i2c_reg_write(dev, ABX8XX_REG_TRICKLE,
+ ABX8XX_TRICKLE_CHARGE_ENABLE | trickle_cfg);
+ if (err < 0) {
+ log_err("Unable to write trickle register\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int abx80x_rtc_read_time(struct udevice *dev, struct rtc_time *tm)
+{
+ unsigned char buf[8];
+ int err, flags, rc_mode = 0;
+
+ /* Read the Oscillator Failure only in XT mode */
+ rc_mode = abx80x_is_rc_mode(dev);
+ if (rc_mode < 0)
+ return rc_mode;
+
+ if (!rc_mode) {
+ flags = dm_i2c_reg_read(dev, ABX8XX_REG_OSS);
+ if (flags < 0) {
+ log_err("Unable to read oscillator status.\n");
+ return flags;
+ }
+
+ if (flags & ABX8XX_OSS_OF)
+ log_debug("Oscillator fail, data is not accurate.\n");
+ }
+
+ err = dm_i2c_read(dev, ABX8XX_REG_HTH,
+ buf, sizeof(buf));
+ if (err < 0) {
+ log_err("Unable to read date\n");
+ return -EIO;
+ }
+
+ tm->tm_sec = bcd2bin(buf[ABX8XX_REG_SC] & 0x7F);
+ tm->tm_min = bcd2bin(buf[ABX8XX_REG_MN] & 0x7F);
+ tm->tm_hour = bcd2bin(buf[ABX8XX_REG_HR] & 0x3F);
+ tm->tm_wday = buf[ABX8XX_REG_WD] & 0x7;
+ tm->tm_mday = bcd2bin(buf[ABX8XX_REG_DA] & 0x3F);
+ tm->tm_mon = bcd2bin(buf[ABX8XX_REG_MO] & 0x1F);
+ tm->tm_year = bcd2bin(buf[ABX8XX_REG_YR]) + 2000;
+
+ return 0;
+}
+
+static int abx80x_rtc_set_time(struct udevice *dev, const struct rtc_time *tm)
+{
+ unsigned char buf[8];
+ int err, flags;
+
+ if (tm->tm_year < 2000)
+ return -EINVAL;
+
+ buf[ABX8XX_REG_HTH] = 0;
+ buf[ABX8XX_REG_SC] = bin2bcd(tm->tm_sec);
+ buf[ABX8XX_REG_MN] = bin2bcd(tm->tm_min);
+ buf[ABX8XX_REG_HR] = bin2bcd(tm->tm_hour);
+ buf[ABX8XX_REG_DA] = bin2bcd(tm->tm_mday);
+ buf[ABX8XX_REG_MO] = bin2bcd(tm->tm_mon);
+ buf[ABX8XX_REG_YR] = bin2bcd(tm->tm_year - 2000);
+ buf[ABX8XX_REG_WD] = tm->tm_wday;
+
+ err = dm_i2c_write(dev, ABX8XX_REG_HTH,
+ buf, sizeof(buf));
+ if (err < 0) {
+ log_err("Unable to write to date registers\n");
+ return -EIO;
+ }
+
+ /* Clear the OF bit of Oscillator Status Register */
+ flags = dm_i2c_reg_read(dev, ABX8XX_REG_OSS);
+ if (flags < 0) {
+ log_err("Unable to read oscillator status.\n");
+ return flags;
+ }
+
+ err = dm_i2c_reg_write(dev, ABX8XX_REG_OSS,
+ flags & ~ABX8XX_OSS_OF);
+ if (err < 0) {
+ log_err("Unable to write oscillator status register\n");
+ return err;
+ }
+
+ return 0;
+}
+
+static int abx80x_rtc_set_autocalibration(struct udevice *dev,
+ int autocalibration)
+{
+ int retval, flags = 0;
+
+ if (autocalibration != 0 && autocalibration != 1024 &&
+ autocalibration != 512) {
+ log_err("autocalibration value outside permitted range\n");
+ return -EINVAL;
+ }
+
+ flags = dm_i2c_reg_read(dev, ABX8XX_REG_OSC);
+ if (flags < 0)
+ return flags;
+
+ if (autocalibration == 0) {
+ flags &= ~(ABX8XX_OSC_ACAL_512 | ABX8XX_OSC_ACAL_1024);
+ } else if (autocalibration == 1024) {
+ /* 1024 autocalibration is 0x10 */
+ flags |= ABX8XX_OSC_ACAL_1024;
+ flags &= ~(ABX8XX_OSC_ACAL_512);
+ } else {
+ /* 512 autocalibration is 0x11 */
+ flags |= (ABX8XX_OSC_ACAL_1024 | ABX8XX_OSC_ACAL_512);
+ }
+
+ /* Unlock write access to Oscillator Control Register */
+ retval = dm_i2c_reg_write(dev, ABX8XX_REG_CFG_KEY,
+ ABX8XX_CFG_KEY_OSC);
+ if (retval < 0) {
+ log_err("Failed to write CONFIG_KEY register\n");
+ return retval;
+ }
+
+ retval = dm_i2c_reg_write(dev, ABX8XX_REG_OSC, flags);
+
+ return retval;
+}
+
+static int abx80x_rtc_get_autocalibration(struct udevice *dev)
+{
+ int flags = 0, autocalibration;
+
+ flags = dm_i2c_reg_read(dev, ABX8XX_REG_OSC);
+ if (flags < 0)
+ return flags;
+
+ if (flags & ABX8XX_OSC_ACAL_512)
+ autocalibration = 512;
+ else if (flags & ABX8XX_OSC_ACAL_1024)
+ autocalibration = 1024;
+ else
+ autocalibration = 0;
+
+ return autocalibration;
+}
+
+static struct rtc_time default_tm = { 0, 0, 0, 1, 1, 2000, 6, 0, 0 };
+
+static int abx80x_rtc_reset(struct udevice *dev)
+{
+ int ret = 0;
+
+ int autocalib = abx80x_rtc_get_autocalibration(dev);
+
+ if (autocalib != 0)
+ abx80x_rtc_set_autocalibration(dev, 0);
+
+ ret = abx80x_rtc_set_time(dev, &default_tm);
+ if (ret != 0) {
+ log_err("cannot set time to default_tm. error %d\n", ret);
+ return ret;
+ }
+
+ return ret;
+}
+
+static const struct rtc_ops abx80x_rtc_ops = {
+ .get = abx80x_rtc_read_time,
+ .set = abx80x_rtc_set_time,
+ .reset = abx80x_rtc_reset,
+ .read8 = abx80x_rtc_read8,
+ .write8 = abx80x_rtc_write8
+};
+
+static int abx80x_dt_trickle_cfg(struct udevice *dev)
+{
+ const char *diode;
+ int trickle_cfg = 0;
+ int i, ret = 0;
+ u32 tmp;
+
+ diode = ofnode_read_string(dev_ofnode(dev), "abracon,tc-diode");
+ if (!diode)
+ return ret;
+
+ if (!strcmp(diode, "standard")) {
+ trickle_cfg |= ABX8XX_TRICKLE_STANDARD_DIODE;
+ } else if (!strcmp(diode, "schottky")) {
+ trickle_cfg |= ABX8XX_TRICKLE_SCHOTTKY_DIODE;
+ } else {
+ log_err("Invalid tc-diode value: %s\n", diode);
+ return -EINVAL;
+ }
+
+ ret = ofnode_read_u32(dev_ofnode(dev), "abracon,tc-resistor", &tmp);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < sizeof(trickle_resistors); i++)
+ if (trickle_resistors[i] == tmp)
+ break;
+
+ if (i == sizeof(trickle_resistors)) {
+ log_err("Invalid tc-resistor value: %u\n", tmp);
+ return -EINVAL;
+ }
+
+ return (trickle_cfg | i);
+}
+
+static int abx80x_probe(struct udevice *dev)
+{
+ int i, data, err, trickle_cfg = -EINVAL;
+ unsigned char buf[7];
+ unsigned int part = dev->driver_data;
+ unsigned int partnumber;
+ unsigned int majrev, minrev;
+ unsigned int lot;
+ unsigned int wafer;
+ unsigned int uid;
+
+ err = dm_i2c_read(dev, ABX8XX_REG_ID0, buf, sizeof(buf));
+ if (err < 0) {
+ log_err("Unable to read partnumber\n");
+ return -EIO;
+ }
+
+ partnumber = (buf[0] << 8) | buf[1];
+ majrev = buf[2] >> 3;
+ minrev = buf[2] & 0x7;
+ lot = ((buf[4] & 0x80) << 2) | ((buf[6] & 0x80) << 1) | buf[3];
+ uid = ((buf[4] & 0x7f) << 8) | buf[5];
+ wafer = (buf[6] & 0x7c) >> 2;
+ log_debug("model %04x, revision %u.%u, lot %x, wafer %x, uid %x\n",
+ partnumber, majrev, minrev, lot, wafer, uid);
+
+ data = dm_i2c_reg_read(dev, ABX8XX_REG_CTRL1);
+ if (data < 0) {
+ log_err("Unable to read control register\n");
+ return -EIO;
+ }
+
+ err = dm_i2c_reg_write(dev, ABX8XX_REG_CTRL1,
+ ((data & ~(ABX8XX_CTRL_12_24 |
+ ABX8XX_CTRL_ARST)) |
+ ABX8XX_CTRL_WRITE));
+ if (err < 0) {
+ log_err("Unable to write control register\n");
+ return -EIO;
+ }
+
+ /* Configure RV1805 specifics */
+ if (part == RV1805) {
+ /*
+ * Avoid accidentally entering test mode. This can happen
+ * on the RV1805 in case the reserved bit 5 in control2
+ * register is set. RV-1805-C3 datasheet indicates that
+ * the bit should be cleared in section 11h - Control2.
+ */
+ data = dm_i2c_reg_read(dev, ABX8XX_REG_CTRL2);
+ if (data < 0) {
+ log_err("Unable to read control2 register\n");
+ return -EIO;
+ }
+
+ err = dm_i2c_reg_write(dev, ABX8XX_REG_CTRL2,
+ data & ~ABX8XX_CTRL2_RSVD);
+ if (err < 0) {
+ log_err("Unable to write control2 register\n");
+ return -EIO;
+ }
+
+ /*
+ * Avoid extra power leakage. The RV1805 uses smaller
+ * 10pin package and the EXTI input is not present.
+ * Disable it to avoid leakage.
+ */
+ data = dm_i2c_reg_read(dev, ABX8XX_REG_OUT_CTRL);
+ if (data < 0) {
+ log_err("Unable to read output control register\n");
+ return -EIO;
+ }
+
+ /*
+ * Write the configuration key register to enable access to
+ * the config2 register
+ */
+ err = dm_i2c_reg_write(dev, ABX8XX_REG_CFG_KEY,
+ ABX8XX_CFG_KEY_MISC);
+ if (err < 0) {
+ log_err("Unable to write configuration key\n");
+ return -EIO;
+ }
+
+ err = dm_i2c_reg_write(dev, ABX8XX_REG_OUT_CTRL,
+ data | ABX8XX_OUT_CTRL_EXDS);
+ if (err < 0) {
+ log_err("Unable to write output control register\n");
+ return -EIO;
+ }
+ }
+
+ /* part autodetection */
+ if (part == ABX80X) {
+ for (i = 0; abx80x_caps[i].pn; i++)
+ if (partnumber == abx80x_caps[i].pn)
+ break;
+ if (abx80x_caps[i].pn == 0) {
+ log_err("Unknown part: %04x\n", partnumber);
+ return -EINVAL;
+ }
+ part = i;
+ }
+
+ if (partnumber != abx80x_caps[part].pn) {
+ log_err("partnumber mismatch %04x != %04x\n",
+ partnumber, abx80x_caps[part].pn);
+ return -EINVAL;
+ }
+
+ if (abx80x_caps[part].has_tc)
+ trickle_cfg = abx80x_dt_trickle_cfg(dev);
+
+ if (trickle_cfg > 0) {
+ log_debug("Enabling trickle charger: %02x\n", trickle_cfg);
+ abx80x_enable_trickle_charger(dev, trickle_cfg);
+ }
+
+ err = dm_i2c_reg_write(dev, ABX8XX_REG_CD_TIMER_CTL, BIT(2));
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static const struct udevice_id abx80x_of_match[] = {
+ {
+ .compatible = "abracon,abx80x",
+ .data = ABX80X
+ },
+ {
+ .compatible = "abracon,ab0801",
+ .data = AB0801
+ },
+ {
+ .compatible = "abracon,ab0803",
+ .data = AB0803
+ },
+ {
+ .compatible = "abracon,ab0804",
+ .data = AB0804
+ },
+ {
+ .compatible = "abracon,ab0805",
+ .data = AB0805
+ },
+ {
+ .compatible = "abracon,ab1801",
+ .data = AB1801
+ },
+ {
+ .compatible = "abracon,ab1803",
+ .data = AB1803
+ },
+ {
+ .compatible = "abracon,ab1804",
+ .data = AB1804
+ },
+ {
+ .compatible = "abracon,ab1805",
+ .data = AB1805
+ },
+ {
+ .compatible = "microcrystal,rv1805",
+ .data = RV1805
+ },
+ { }
+};
+
+U_BOOT_DRIVER(abx80x_rtc) = {
+ .name = "rtc-abx80x",
+ .id = UCLASS_RTC,
+ .probe = abx80x_probe,
+ .of_match = abx80x_of_match,
+ .ops = &abx80x_rtc_ops,
+};
diff --git a/drivers/video/video-uclass.c b/drivers/video/video-uclass.c
index a1d5275..91d078a 100644
--- a/drivers/video/video-uclass.c
+++ b/drivers/video/video-uclass.c
@@ -290,6 +290,16 @@ int video_sync_copy(struct udevice *dev, void *from, void *to)
return 0;
}
+
+int video_sync_copy_all(struct udevice *dev)
+{
+ struct video_priv *priv = dev_get_uclass_priv(dev);
+
+ video_sync_copy(dev, priv->fb, priv->fb + priv->fb_size);
+
+ return 0;
+}
+
#endif
/* Set up the colour map */
diff --git a/include/binman.h b/include/binman.h
index 8b89a96..5958dfb 100644
--- a/include/binman.h
+++ b/include/binman.h
@@ -71,6 +71,20 @@ int binman_entry_find(const char *name, struct binman_entry *entry);
ofnode binman_section_find_node(const char *name);
/**
+ * binman_select_subnode() - Select a subnode to use to find entries
+ *
+ * Normally binman selects the top-level node for future entry requests, such as
+ * binman_entry_find(). This function allows a subnode to be chosen instead.
+ *
+ * @name: Name of subnode, typically a section. This must be in the top-level
+ * binman node
+ * @return 0 if OK, -EINVAL if there is no /binman node, -ECHILD if multiple
+ * images are being used but the first image is not available, -ENOENT if
+ * the requested subnode cannot be found
+ */
+int binman_select_subnode(const char *name);
+
+/**
* binman_init() - Set up the binman symbol information
*
* This locates the binary symbol information in the device tree ready for use
diff --git a/include/bloblist.h b/include/bloblist.h
index 8cdce61..964b974 100644
--- a/include/bloblist.h
+++ b/include/bloblist.h
@@ -243,6 +243,16 @@ void bloblist_show_list(void);
const char *bloblist_tag_name(enum bloblist_tag_t tag);
/**
+ * bloblist_reloc() - Relocate the bloblist and optionally resize it
+ *
+ * @to: Pointer to new bloblist location (must not overlap old location)
+ * @to:size: New size for bloblist (must be larger than from_size)
+ * @from: Pointer to bloblist to relocate
+ * @from_size: Size of bloblist to relocate
+ */
+void bloblist_reloc(void *to, uint to_size, void *from, uint from_size);
+
+/**
* bloblist_init() - Init the bloblist system with a single bloblist
*
* This uses CONFIG_BLOBLIST_ADDR and CONFIG_BLOBLIST_SIZE to set up a bloblist
diff --git a/include/bootcount.h b/include/bootcount.h
index cd30403..b1d1fe5 100644
--- a/include/bootcount.h
+++ b/include/bootcount.h
@@ -69,7 +69,7 @@ void bootcount_store(ulong);
*/
ulong bootcount_load(void);
-#if defined(CONFIG_SPL_BOOTCOUNT_LIMIT) || defined(CONFIG_BOOTCOUNT_LIMIT)
+#if defined(CONFIG_SPL_BOOTCOUNT_LIMIT) || defined(CONFIG_TPL_BOOTCOUNT_LIMIT) || defined(CONFIG_BOOTCOUNT_LIMIT)
#if !defined(CONFIG_SYS_BOOTCOUNT_LE) && !defined(CONFIG_SYS_BOOTCOUNT_BE)
# if __BYTE_ORDER == __LITTLE_ENDIAN
@@ -130,7 +130,7 @@ static inline void bootcount_inc(void)
#ifndef CONFIG_SPL_BUILD
/* Only increment bootcount when no bootcount support in SPL */
-#ifndef CONFIG_SPL_BOOTCOUNT_LIMIT
+#if !defined(CONFIG_SPL_BOOTCOUNT_LIMIT) && !defined(CONFIG_TPL_BOOTCOUNT_LIMIT)
bootcount_store(++bootcount);
#endif
env_set_ulong("bootcount", bootcount);
@@ -140,5 +140,5 @@ static inline void bootcount_inc(void)
#else
static inline int bootcount_error(void) { return 0; }
static inline void bootcount_inc(void) {}
-#endif /* CONFIG_SPL_BOOTCOUNT_LIMIT || CONFIG_BOOTCOUNT_LIMIT */
+#endif /* CONFIG_SPL_BOOTCOUNT_LIMIT || CONFIG_TPL_BOOTCOUNT_LIMIT || CONFIG_BOOTCOUNT_LIMIT */
#endif /* _BOOTCOUNT_H__ */
diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h
index 2d1e6cc..7f2be23 100644
--- a/include/linux/arm-smccc.h
+++ b/include/linux/arm-smccc.h
@@ -11,8 +11,8 @@
* http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html
*/
-#define ARM_SMCCC_STD_CALL 0
-#define ARM_SMCCC_FAST_CALL 1
+#define ARM_SMCCC_STD_CALL 0UL
+#define ARM_SMCCC_FAST_CALL 1UL
#define ARM_SMCCC_TYPE_SHIFT 31
#define ARM_SMCCC_SMC_32 0
diff --git a/include/spl.h b/include/spl.h
index a764878..faffeb5 100644
--- a/include/spl.h
+++ b/include/spl.h
@@ -58,6 +58,7 @@ static inline bool u_boot_first_phase(void)
}
enum u_boot_phase {
+ PHASE_NONE, /* Invalid phase, signifying before U-Boot */
PHASE_TPL, /* Running in TPL */
PHASE_SPL, /* Running in SPL */
PHASE_BOARD_F, /* Running in U-Boot before relocation */
@@ -123,6 +124,58 @@ static inline enum u_boot_phase spl_phase(void)
#endif
}
+/**
+ * spl_prev_phase() - Figure out the previous U-Boot phase
+ *
+ * @return the previous phase from this one, e.g. if called in SPL this returns
+ * PHASE_TPL, if TPL is enabled
+ */
+static inline enum u_boot_phase spl_prev_phase(void)
+{
+#ifdef CONFIG_TPL_BUILD
+ return PHASE_NONE;
+#elif defined(CONFIG_SPL_BUILD)
+ return IS_ENABLED(CONFIG_TPL) ? PHASE_TPL : PHASE_NONE;
+#else
+ return IS_ENABLED(CONFIG_SPL) ? PHASE_SPL : PHASE_NONE;
+#endif
+}
+
+/**
+ * spl_next_phase() - Figure out the next U-Boot phase
+ *
+ * @return the next phase from this one, e.g. if called in TPL this returns
+ * PHASE_SPL
+ */
+static inline enum u_boot_phase spl_next_phase(void)
+{
+#ifdef CONFIG_TPL_BUILD
+ return PHASE_SPL;
+#else
+ return PHASE_BOARD_F;
+#endif
+}
+
+/**
+ * spl_phase_name() - Get the name of the current phase
+ *
+ * @return phase name
+ */
+static inline const char *spl_phase_name(enum u_boot_phase phase)
+{
+ switch (phase) {
+ case PHASE_TPL:
+ return "TPL";
+ case PHASE_SPL:
+ return "SPL";
+ case PHASE_BOARD_F:
+ case PHASE_BOARD_R:
+ return "U-Boot";
+ default:
+ return "phase?";
+ }
+}
+
/* A string name for SPL or TPL */
#ifdef CONFIG_SPL_BUILD
# ifdef CONFIG_TPL_BUILD
diff --git a/include/uuid.h b/include/uuid.h
index 0c653cb..4a4883d 100644
--- a/include/uuid.h
+++ b/include/uuid.h
@@ -23,6 +23,7 @@ struct uuid {
#define UUID_STR_FORMAT_GUID BIT(0)
#define UUID_STR_UPPER_CASE BIT(1)
+/* Use UUID_STR_LEN + 1 for string space */
#define UUID_STR_LEN 36
#define UUID_BIN_LEN sizeof(struct uuid)
diff --git a/include/video.h b/include/video.h
index 74d822f..8277333 100644
--- a/include/video.h
+++ b/include/video.h
@@ -246,11 +246,25 @@ void video_set_default_colors(struct udevice *dev, bool invert);
* frame buffer start
*/
int video_sync_copy(struct udevice *dev, void *from, void *to);
+
+/**
+ * video_sync_copy_all() - Sync the entire framebuffer to the copy
+ *
+ * @dev: Vidconsole device being updated
+ * @return 0 (always)
+ */
+int video_sync_copy_all(struct udevice *dev);
#else
static inline int video_sync_copy(struct udevice *dev, void *from, void *to)
{
return 0;
}
+
+static inline int video_sync_copy_all(struct udevice *dev)
+{
+ return 0;
+}
+
#endif
#ifndef CONFIG_DM_VIDEO
diff --git a/lib/Makefile b/lib/Makefile
index 851a80e..edc1c3d 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -92,7 +92,9 @@ obj-y += display_options.o
CFLAGS_display_options.o := $(if $(BUILD_TAG),-DBUILD_TAG='"$(BUILD_TAG)"')
obj-$(CONFIG_BCH) += bch.o
obj-$(CONFIG_MMC_SPI) += crc7.o
+#ifndef CONFIG_TPL_BUILD
obj-y += crc32.o
+#endif
obj-$(CONFIG_CRC32C) += crc32c.o
obj-y += ctype.o
obj-y += div64.o
diff --git a/lib/binman.c b/lib/binman.c
index f027d1b..f415df3 100644
--- a/lib/binman.c
+++ b/lib/binman.c
@@ -30,6 +30,34 @@ struct binman_info {
static struct binman_info *binman;
+/**
+ * find_image_node() - Find the top-level binman node
+ *
+ * Finds the binman node which can be used to load entries. The correct node
+ * depends on whether multiple-images is in use.
+ *
+ * @nodep: Returns the node found, on success
+ * @return 0 if OK, , -EINVAL if there is no /binman node, -ECHILD if multiple
+ * images are being used but the first image is not available
+ */
+static int find_image_node(ofnode *nodep)
+{
+ ofnode node;
+
+ node = ofnode_path("/binman");
+ if (!ofnode_valid(node))
+ return log_msg_ret("binman node", -EINVAL);
+ if (ofnode_read_bool(node, "multiple-images")) {
+ node = ofnode_first_subnode(node);
+
+ if (!ofnode_valid(node))
+ return log_msg_ret("first image", -ECHILD);
+ }
+ *nodep = node;
+
+ return 0;
+}
+
static int binman_entry_find_internal(ofnode node, const char *name,
struct binman_entry *entry)
{
@@ -88,21 +116,34 @@ int binman_get_rom_offset(void)
return binman->rom_offset;
}
+int binman_select_subnode(const char *name)
+{
+ ofnode node;
+ int ret;
+
+ ret = find_image_node(&node);
+ if (ret)
+ return log_msg_ret("main", -ENOENT);
+ node = ofnode_find_subnode(node, name);
+ if (!ofnode_valid(node))
+ return log_msg_ret("node", -ENOENT);
+ binman->image = node;
+ log_debug("binman: Selected image subnode '%s'\n",
+ ofnode_get_name(binman->image));
+
+ return 0;
+}
+
int binman_init(void)
{
+ int ret;
+
binman = malloc(sizeof(struct binman_info));
if (!binman)
return log_msg_ret("space for binman", -ENOMEM);
- binman->image = ofnode_path("/binman");
- if (!ofnode_valid(binman->image))
- return log_msg_ret("binman node", -EINVAL);
- if (ofnode_read_bool(binman->image, "multiple-images")) {
- ofnode node = ofnode_first_subnode(binman->image);
-
- if (!ofnode_valid(node))
- return log_msg_ret("first image", -ENOENT);
- binman->image = node;
- }
+ ret = find_image_node(&binman->image);
+ if (ret)
+ return log_msg_ret("node", -ENOENT);
binman_set_rom_offset(ROM_OFFSET_NONE);
return 0;
diff --git a/lib/display_options.c b/lib/display_options.c
index b2025ee..cd48998 100644
--- a/lib/display_options.c
+++ b/lib/display_options.c
@@ -169,11 +169,10 @@ int print_buffer(ulong addr, const void *data, uint width, uint count,
x = lb.us[i] = *(volatile uint16_t *)data;
else
x = lb.uc[i] = *(volatile uint8_t *)data;
-#if defined(CONFIG_SPL_BUILD)
- printf(" %x", (uint)x);
-#else
- printf(" %0*lx", width * 2, x);
-#endif
+ if (CONFIG_IS_ENABLED(USE_TINY_PRINTF))
+ printf(" %x", (uint)x);
+ else
+ printf(" %0*lx", width * 2, x);
data += width;
}
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index 0ab7105..a2d2fb4 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -600,7 +600,8 @@ int fdtdec_prepare_fdt(void)
#ifdef CONFIG_SPL_BUILD
puts("Missing DTB\n");
#else
- puts("No valid device tree binary found - please append one to U-Boot binary, use u-boot-dtb.bin or define CONFIG_OF_EMBED. For sandbox, use -d <file.dtb>\n");
+ printf("No valid device tree binary found at %p\n",
+ gd->fdt_blob);
# ifdef DEBUG
if (gd->fdt_blob) {
printf("fdt_blob=%p\n", gd->fdt_blob);
@@ -1252,7 +1253,7 @@ __weak void *board_fdt_blob_setup(void)
void *fdt_blob = NULL;
#ifdef CONFIG_SPL_BUILD
/* FDT is at end of BSS unless it is in a different memory region */
- if (IS_ENABLED(CONFIG_SPL_SEPARATE_BSS))
+ if (CONFIG_IS_ENABLED(SEPARATE_BSS))
fdt_blob = (ulong *)&_image_binary_end;
else
fdt_blob = (ulong *)&__bss_end;
diff --git a/lib/rsa/rsa-verify.c b/lib/rsa/rsa-verify.c
index 0ab0f62..e34d329 100644
--- a/lib/rsa/rsa-verify.c
+++ b/lib/rsa/rsa-verify.c
@@ -522,10 +522,10 @@ int rsa_verify_hash(struct image_sign_info *info,
return ret;
/* No luck, so try each of the keys in turn */
- for (ndepth = 0, noffset = fdt_next_node(info->fit, sig_node,
+ for (ndepth = 0, noffset = fdt_next_node(blob, sig_node,
&ndepth);
(noffset >= 0) && (ndepth > 0);
- noffset = fdt_next_node(info->fit, noffset, &ndepth)) {
+ noffset = fdt_next_node(blob, noffset, &ndepth)) {
if (ndepth == 1 && noffset != node) {
ret = rsa_verify_with_keynode(info, hash,
sig, sig_len,
diff --git a/net/eth-uclass.c b/net/eth-uclass.c
index 7c2454f..35842f5 100644
--- a/net/eth-uclass.c
+++ b/net/eth-uclass.c
@@ -487,7 +487,7 @@ static int eth_pre_unbind(struct udevice *dev)
static bool eth_dev_get_mac_address(struct udevice *dev, u8 mac[ARP_HLEN])
{
-#if IS_ENABLED(CONFIG_OF_CONTROL)
+#if CONFIG_IS_ENABLED(OF_CONTROL)
const uint8_t *p;
p = dev_read_u8_array_ptr(dev, "mac-address", ARP_HLEN);
diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt
index e2cf205..86e011c 100644
--- a/scripts/config_whitelist.txt
+++ b/scripts/config_whitelist.txt
@@ -1222,7 +1222,6 @@ CONFIG_PCI_CLK_FREQ
CONFIG_PCI_CONFIG_HOST_BRIDGE
CONFIG_PCI_EHCI_DEVICE
CONFIG_PCI_EHCI_DEVNO
-CONFIG_PCI_ENUM_ONLY
CONFIG_PCI_FIXUP_DEV
CONFIG_PCI_GT64120
CONFIG_PCI_INDIRECT_BRIDGE
diff --git a/test/bloblist.c b/test/bloblist.c
index 900299d..85a6c39 100644
--- a/test/bloblist.c
+++ b/test/bloblist.c
@@ -347,6 +347,42 @@ static int bloblist_test_align(struct unit_test_state *uts)
}
BLOBLIST_TEST(bloblist_test_align, 0);
+/* Test relocation of a bloblist */
+static int bloblist_test_reloc(struct unit_test_state *uts)
+{
+ const uint large_size = TEST_BLOBLIST_SIZE;
+ const uint small_size = 0x20;
+ void *old_ptr, *new_ptr;
+ void *blob1, *blob2;
+ ulong new_addr;
+ ulong new_size;
+
+ ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
+ old_ptr = map_sysmem(TEST_ADDR, TEST_BLOBLIST_SIZE);
+
+ /* Add one blob and then one that won't fit */
+ blob1 = bloblist_add(TEST_TAG, small_size, 0);
+ ut_assertnonnull(blob1);
+ blob2 = bloblist_add(TEST_TAG2, large_size, 0);
+ ut_assertnull(blob2);
+
+ /* Relocate the bloblist somewhere else, a bit larger */
+ new_addr = TEST_ADDR + TEST_BLOBLIST_SIZE;
+ new_size = TEST_BLOBLIST_SIZE + 0x100;
+ new_ptr = map_sysmem(new_addr, TEST_BLOBLIST_SIZE);
+ bloblist_reloc(new_ptr, new_size, old_ptr, TEST_BLOBLIST_SIZE);
+ gd->bloblist = new_ptr;
+
+ /* Check the old blob is there and that we can now add the bigger one */
+ ut_assertnonnull(bloblist_find(TEST_TAG, small_size));
+ ut_assertnull(bloblist_find(TEST_TAG2, small_size));
+ blob2 = bloblist_add(TEST_TAG2, large_size, 0);
+ ut_assertnonnull(blob2);
+
+ return 0;
+}
+BLOBLIST_TEST(bloblist_test_reloc, 0);
+
int do_ut_bloblist(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{