Merge branch '2021-01-27-assorted-fixes-and-improvements'
- A wide variety of fixes throughout the tree.
This commit is contained in:
commit
07394fb05e
6
Makefile
6
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)
|
||||
|
7
README
7
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.
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
31
doc/device-tree-bindings/rtc/abracon,abx80x.txt
Normal file
31
doc/device-tree-bindings/rtc/abracon,abx80x.txt
Normal file
@ -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.
|
@ -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
|
||||
|
@ -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 },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
553
drivers/rtc/abx80x.c
Normal file
553
drivers/rtc/abx80x.c
Normal file
@ -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,
|
||||
};
|
@ -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 */
|
||||
|
@ -70,6 +70,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
|
||||
*
|
||||
|
@ -242,6 +242,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
|
||||
*
|
||||
|
@ -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__ */
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
61
lib/binman.c
61
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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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[])
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user