mirror of
https://github.com/revyos/th1520-vendor-uboot.git
synced 2026-09-17 21:02:04 +02:00
Linux_SDK_V0.9.5
This commit is contained in:
6
cmd/.gitignore
vendored
Normal file
6
cmd/.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
config_data.gz
|
||||
config_data_gz.h
|
||||
config_data_size.h
|
||||
license_data.gz
|
||||
license_data_gz.h
|
||||
license_data_size.h
|
||||
2163
cmd/Kconfig
Normal file
2163
cmd/Kconfig
Normal file
File diff suppressed because it is too large
Load Diff
231
cmd/Makefile
Normal file
231
cmd/Makefile
Normal file
@@ -0,0 +1,231 @@
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# (C) Copyright 2004-2006
|
||||
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
|
||||
ifndef CONFIG_SPL_BUILD
|
||||
# core command
|
||||
obj-y += boot.o
|
||||
obj-$(CONFIG_CMD_BOOTM) += bootm.o
|
||||
obj-y += help.o
|
||||
obj-y += version.o
|
||||
|
||||
# command
|
||||
obj-$(CONFIG_CMD_AES) += aes.o
|
||||
obj-$(CONFIG_CMD_AB_SELECT) += ab_select.o
|
||||
obj-$(CONFIG_CMD_ADC) += adc.o
|
||||
obj-$(CONFIG_CMD_ARMFLASH) += armflash.o
|
||||
obj-$(CONFIG_HAVE_BLOCK_DEVICE) += blk_common.o
|
||||
obj-$(CONFIG_CMD_SOURCE) += source.o
|
||||
obj-$(CONFIG_CMD_BCB) += bcb.o
|
||||
obj-$(CONFIG_CMD_BDI) += bdinfo.o
|
||||
obj-$(CONFIG_CMD_BEDBUG) += bedbug.o
|
||||
obj-$(CONFIG_CMD_BIND) += bind.o
|
||||
obj-$(CONFIG_CMD_BINOP) += binop.o
|
||||
obj-$(CONFIG_CMD_BLOCK_CACHE) += blkcache.o
|
||||
obj-$(CONFIG_CMD_BMP) += bmp.o
|
||||
obj-$(CONFIG_CMD_BOOTCOUNT) += bootcount.o
|
||||
obj-$(CONFIG_CMD_BOOTEFI) += bootefi.o
|
||||
obj-$(CONFIG_CMD_BOOTMENU) += bootmenu.o
|
||||
obj-$(CONFIG_CMD_BOOTSTAGE) += bootstage.o
|
||||
obj-$(CONFIG_CMD_BOOTZ) += bootz.o
|
||||
obj-$(CONFIG_CMD_BOOTI) += booti.o
|
||||
obj-$(CONFIG_CMD_BTRFS) += btrfs.o
|
||||
obj-$(CONFIG_CMD_CACHE) += cache.o
|
||||
obj-$(CONFIG_CMD_CBFS) += cbfs.o
|
||||
obj-$(CONFIG_CMD_CLK) += clk.o
|
||||
obj-$(CONFIG_CMD_CLS) += cls.o
|
||||
obj-$(CONFIG_CMD_CONFIG) += config.o
|
||||
obj-$(CONFIG_CMD_CONITRACE) += conitrace.o
|
||||
obj-$(CONFIG_CMD_CONSOLE) += console.o
|
||||
obj-$(CONFIG_CMD_CPU) += cpu.o
|
||||
obj-$(CONFIG_DATAFLASH_MMC_SELECT) += dataflash_mmc_mux.o
|
||||
obj-$(CONFIG_CMD_DATE) += date.o
|
||||
obj-$(CONFIG_CMD_DEMO) += demo.o
|
||||
obj-$(CONFIG_CMD_DM) += dm.o
|
||||
obj-$(CONFIG_CMD_SOUND) += sound.o
|
||||
ifdef CONFIG_POST
|
||||
obj-$(CONFIG_CMD_DIAG) += diag.o
|
||||
endif
|
||||
obj-$(CONFIG_CMD_DTIMG) += dtimg.o
|
||||
obj-$(CONFIG_CMD_ECHO) += echo.o
|
||||
obj-$(CONFIG_ENV_IS_IN_EEPROM) += eeprom.o
|
||||
obj-$(CONFIG_CMD_EEPROM) += eeprom.o
|
||||
obj-$(CONFIG_EFI_STUB) += efi.o
|
||||
obj-$(CONFIG_CMD_EFIDEBUG) += efidebug.o
|
||||
obj-$(CONFIG_CMD_ELF) += elf.o
|
||||
obj-$(CONFIG_HUSH_PARSER) += exit.o
|
||||
obj-$(CONFIG_CMD_EXT4) += ext4.o
|
||||
obj-$(CONFIG_CMD_EXT2) += ext2.o
|
||||
obj-$(CONFIG_CMD_FAT) += fat.o
|
||||
obj-$(CONFIG_CMD_FDC) += fdc.o
|
||||
obj-$(CONFIG_CMD_FDT) += fdt.o
|
||||
obj-$(CONFIG_CMD_FITUPD) += fitupd.o
|
||||
obj-$(CONFIG_CMD_FLASH) += flash.o
|
||||
obj-$(CONFIG_CMD_FPGA) += fpga.o
|
||||
obj-$(CONFIG_CMD_FPGAD) += fpgad.o
|
||||
obj-$(CONFIG_CMD_FS_GENERIC) += fs.o
|
||||
obj-$(CONFIG_CMD_FUSE) += fuse.o
|
||||
obj-$(CONFIG_CMD_GETTIME) += gettime.o
|
||||
obj-$(CONFIG_CMD_GPIO) += gpio.o
|
||||
obj-$(CONFIG_CMD_HVC) += smccc.o
|
||||
obj-$(CONFIG_CMD_I2C) += i2c.o
|
||||
obj-$(CONFIG_CMD_IOTRACE) += iotrace.o
|
||||
obj-$(CONFIG_CMD_HASH) += hash.o
|
||||
obj-$(CONFIG_CMD_IDE) += ide.o disk.o
|
||||
obj-$(CONFIG_CMD_INI) += ini.o
|
||||
obj-$(CONFIG_CMD_IRQ) += irq.o
|
||||
obj-$(CONFIG_CMD_ITEST) += itest.o
|
||||
obj-$(CONFIG_CMD_JFFS2) += jffs2.o
|
||||
obj-$(CONFIG_CMD_CRAMFS) += cramfs.o
|
||||
obj-$(CONFIG_LED_STATUS_CMD) += legacy_led.o
|
||||
obj-$(CONFIG_CMD_LED) += led.o
|
||||
obj-$(CONFIG_CMD_LICENSE) += license.o
|
||||
obj-y += load.o
|
||||
obj-$(CONFIG_CMD_LOG) += log.o
|
||||
obj-$(CONFIG_ID_EEPROM) += mac.o
|
||||
obj-$(CONFIG_CMD_MD5SUM) += md5sum.o
|
||||
obj-$(CONFIG_CMD_MEMORY) += mem.o
|
||||
obj-$(CONFIG_CMD_IO) += io.o
|
||||
obj-$(CONFIG_CMD_MFSL) += mfsl.o
|
||||
obj-$(CONFIG_CMD_MII) += mii.o
|
||||
obj-$(CONFIG_CMD_MDIO) += mdio.o
|
||||
obj-$(CONFIG_CMD_MISC) += misc.o
|
||||
obj-$(CONFIG_CMD_MMC) += mmc.o
|
||||
obj-$(CONFIG_MP) += mp.o
|
||||
obj-$(CONFIG_CMD_MTD) += mtd.o
|
||||
obj-$(CONFIG_CMD_MTDPARTS) += mtdparts.o
|
||||
ifneq ($(CONFIG_CMD_NAND)$(CONFIG_CMD_SF),)
|
||||
obj-y += legacy-mtd-utils.o
|
||||
endif
|
||||
obj-$(CONFIG_CMD_NAND) += nand.o
|
||||
obj-$(CONFIG_CMD_NET) += net.o
|
||||
obj-$(CONFIG_CMD_NVEDIT_EFI) += nvedit_efi.o
|
||||
obj-$(CONFIG_CMD_ONENAND) += onenand.o
|
||||
obj-$(CONFIG_CMD_OSD) += osd.o
|
||||
obj-$(CONFIG_CMD_PART) += part.o
|
||||
obj-$(CONFIG_CMD_PCAP) += pcap.o
|
||||
ifdef CONFIG_PCI
|
||||
obj-$(CONFIG_CMD_PCI) += pci.o
|
||||
endif
|
||||
obj-$(CONFIG_CMD_PINMUX) += pinmux.o
|
||||
obj-$(CONFIG_CMD_PXE) += pxe.o pxe_utils.o
|
||||
obj-$(CONFIG_CMD_WOL) += wol.o
|
||||
obj-$(CONFIG_CMD_QFW) += qfw.o
|
||||
obj-$(CONFIG_CMD_READ) += read.o
|
||||
obj-$(CONFIG_CMD_REGINFO) += reginfo.o
|
||||
obj-$(CONFIG_CMD_REISER) += reiser.o
|
||||
obj-$(CONFIG_CMD_REMOTEPROC) += remoteproc.o
|
||||
obj-$(CONFIG_CMD_ROCKUSB) += rockusb.o
|
||||
obj-$(CONFIG_SANDBOX) += host.o
|
||||
obj-$(CONFIG_CMD_SATA) += sata.o
|
||||
obj-$(CONFIG_CMD_NVME) += nvme.o
|
||||
obj-$(CONFIG_SANDBOX) += sb.o
|
||||
obj-$(CONFIG_CMD_SF) += sf.o
|
||||
obj-$(CONFIG_CMD_SCSI) += scsi.o disk.o
|
||||
obj-$(CONFIG_CMD_SHA1SUM) += sha1sum.o
|
||||
obj-$(CONFIG_CMD_SETEXPR) += setexpr.o
|
||||
obj-$(CONFIG_CMD_SPI) += spi.o
|
||||
obj-$(CONFIG_CMD_STRINGS) += strings.o
|
||||
obj-$(CONFIG_CMD_SMC) += smccc.o
|
||||
obj-$(CONFIG_CMD_SYSBOOT) += sysboot.o pxe_utils.o
|
||||
obj-$(CONFIG_CMD_TERMINAL) += terminal.o
|
||||
obj-$(CONFIG_CMD_TIME) += time.o
|
||||
obj-$(CONFIG_CMD_TRACE) += trace.o
|
||||
obj-$(CONFIG_HUSH_PARSER) += test.o
|
||||
obj-$(CONFIG_CMD_TPM) += tpm-common.o
|
||||
obj-$(CONFIG_CMD_TPM_V1) += tpm-v1.o
|
||||
obj-$(CONFIG_CMD_TPM_TEST) += tpm_test.o
|
||||
obj-$(CONFIG_CMD_TPM_V2) += tpm-v2.o
|
||||
obj-$(CONFIG_CMD_CROS_EC) += cros_ec.o
|
||||
obj-$(CONFIG_CMD_TSI148) += tsi148.o
|
||||
obj-$(CONFIG_CMD_UBI) += ubi.o
|
||||
obj-$(CONFIG_CMD_UBIFS) += ubifs.o
|
||||
obj-$(CONFIG_CMD_UNIVERSE) += universe.o
|
||||
obj-$(CONFIG_CMD_UNZIP) += unzip.o
|
||||
obj-$(CONFIG_CMD_VIRTIO) += virtio.o
|
||||
obj-$(CONFIG_CMD_WDT) += wdt.o
|
||||
obj-$(CONFIG_CMD_LZMADEC) += lzmadec.o
|
||||
obj-$(CONFIG_CMD_UFS) += ufs.o
|
||||
obj-$(CONFIG_CMD_USB) += usb.o disk.o
|
||||
obj-$(CONFIG_CMD_FASTBOOT) += fastboot.o
|
||||
obj-$(CONFIG_CMD_FS_UUID) += fs_uuid.o
|
||||
|
||||
obj-$(CONFIG_CMD_USB_MASS_STORAGE) += usb_mass_storage.o
|
||||
obj-$(CONFIG_CMD_USB_SDP) += usb_gadget_sdp.o
|
||||
obj-$(CONFIG_CMD_THOR_DOWNLOAD) += thordown.o
|
||||
obj-$(CONFIG_CMD_XIMG) += ximg.o
|
||||
obj-$(CONFIG_CMD_YAFFS2) += yaffs2.o
|
||||
obj-$(CONFIG_CMD_SPL) += spl.o
|
||||
obj-$(CONFIG_CMD_W1) += w1.o
|
||||
obj-$(CONFIG_CMD_ZIP) += zip.o
|
||||
obj-$(CONFIG_CMD_ZFS) += zfs.o
|
||||
|
||||
obj-$(CONFIG_CMD_DFU) += dfu.o
|
||||
obj-$(CONFIG_CMD_GPT) += gpt.o
|
||||
obj-$(CONFIG_CMD_ETHSW) += ethsw.o
|
||||
obj-$(CONFIG_CMD_AXI) += axi.o
|
||||
|
||||
obj-$(CONFIG_TARGET_LIGHT_FM_C910_VAL_SV) += trng_cmd.o
|
||||
|
||||
# Power
|
||||
obj-$(CONFIG_CMD_PMIC) += pmic.o
|
||||
obj-$(CONFIG_CMD_REGULATOR) += regulator.o
|
||||
|
||||
obj-$(CONFIG_CMD_BLOB) += blob.o
|
||||
|
||||
# Android Verified Boot 2.0
|
||||
obj-$(CONFIG_CMD_AVB) += avb.o
|
||||
|
||||
obj-$(CONFIG_DDR_SCAN) += ddrscan.o
|
||||
obj-$(CONFIG_DDR_PRBS_TEST) += prbs.o queue.o
|
||||
|
||||
obj-$(CONFIG_ARM) += arm/
|
||||
obj-$(CONFIG_RISCV) += riscv/
|
||||
obj-$(CONFIG_X86) += x86/
|
||||
|
||||
obj-$(CONFIG_ARCH_MVEBU) += mvebu/
|
||||
endif # !CONFIG_SPL_BUILD
|
||||
|
||||
# core command
|
||||
obj-y += nvedit.o
|
||||
|
||||
obj-$(CONFIG_TI_COMMON_CMD_OPTIONS) += ti/
|
||||
|
||||
filechk_data_gz = (echo "static const char data_gz[] ="; cat $< | scripts/bin2c; echo ";")
|
||||
|
||||
filechk_data_size = \
|
||||
(echo "static const size_t data_size = "; \
|
||||
cat $< | wc -c; echo ";")
|
||||
|
||||
# "config" command
|
||||
$(obj)/config.o: $(obj)/config_data_gz.h $(obj)/config_data_size.h
|
||||
|
||||
targets += config_data.gz
|
||||
$(obj)/config_data.gz: $(KCONFIG_CONFIG) FORCE
|
||||
$(call if_changed,gzip)
|
||||
|
||||
targets += config_data_gz.h
|
||||
$(obj)/config_data_gz.h: $(obj)/config_data.gz FORCE
|
||||
$(call filechk,data_gz)
|
||||
|
||||
targets += config_data_size.h
|
||||
$(obj)/config_data_size.h: $(KCONFIG_CONFIG) FORCE
|
||||
$(call filechk,data_size)
|
||||
|
||||
# "license" command
|
||||
$(obj)/license.o: $(obj)/license_data_gz.h $(obj)/license_data_size.h
|
||||
|
||||
targets += license_data.gz
|
||||
$(obj)/license_data.gz: $(srctree)/Licenses/gpl-2.0.txt FORCE
|
||||
$(call if_changed,gzip)
|
||||
|
||||
targets += license_data_gz.h
|
||||
$(obj)/license_data_gz.h: $(obj)/license_data.gz FORCE
|
||||
$(call filechk,data_gz)
|
||||
|
||||
targets += license_data_size.h
|
||||
$(obj)/license_data_size.h: $(srctree)/Licenses/gpl-2.0.txt FORCE
|
||||
$(call filechk,data_size)
|
||||
|
||||
CFLAGS_ethsw.o := -Wno-enum-conversion
|
||||
52
cmd/ab_select.c
Normal file
52
cmd/ab_select.c
Normal file
@@ -0,0 +1,52 @@
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*/
|
||||
|
||||
#include <android_ab.h>
|
||||
#include <command.h>
|
||||
|
||||
static int do_ab_select(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
int ret;
|
||||
struct blk_desc *dev_desc;
|
||||
disk_partition_t part_info;
|
||||
char slot[2];
|
||||
|
||||
if (argc != 4)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
/* Lookup the "misc" partition from argv[2] and argv[3] */
|
||||
if (part_get_info_by_dev_and_name_or_num(argv[2], argv[3],
|
||||
&dev_desc, &part_info) < 0) {
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
ret = ab_select_slot(dev_desc, &part_info);
|
||||
if (ret < 0) {
|
||||
printf("Android boot failed, error %d.\n", ret);
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
/* Android standard slot names are 'a', 'b', ... */
|
||||
slot[0] = BOOT_SLOT_NAME(ret);
|
||||
slot[1] = '\0';
|
||||
env_set(argv[1], slot);
|
||||
printf("ANDROID: Booting slot: %s\n", slot);
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(ab_select, 4, 0, do_ab_select,
|
||||
"Select the slot used to boot from and register the boot attempt.",
|
||||
"<slot_var_name> <interface> <dev[:part|#part_name]>\n"
|
||||
" - Load the slot metadata from the partition 'part' on\n"
|
||||
" device type 'interface' instance 'dev' and store the active\n"
|
||||
" slot in the 'slot_var_name' variable. This also updates the\n"
|
||||
" Android slot metadata with a boot attempt, which can cause\n"
|
||||
" successive calls to this function to return a different result\n"
|
||||
" if the returned slot runs out of boot attempts.\n"
|
||||
" - If 'part_name' is passed, preceded with a # instead of :, the\n"
|
||||
" partition name whose label is 'part_name' will be looked up in\n"
|
||||
" the partition table. This is commonly the \"misc\" partition.\n"
|
||||
);
|
||||
159
cmd/adc.c
Normal file
159
cmd/adc.c
Normal file
@@ -0,0 +1,159 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2018 BayLibre, SAS
|
||||
* Author: Neil Armstrong <narmstrong@baylibre.com>
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <dm.h>
|
||||
#include <adc.h>
|
||||
|
||||
static int do_adc_list(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char *const argv[])
|
||||
{
|
||||
struct udevice *dev;
|
||||
int ret;
|
||||
|
||||
ret = uclass_first_device_err(UCLASS_ADC, &dev);
|
||||
if (ret) {
|
||||
printf("No available ADC device\n");
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
do {
|
||||
printf("- %s\n", dev->name);
|
||||
|
||||
ret = uclass_next_device(&dev);
|
||||
if (ret)
|
||||
return CMD_RET_FAILURE;
|
||||
} while (dev);
|
||||
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
static int do_adc_info(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char *const argv[])
|
||||
{
|
||||
struct udevice *dev;
|
||||
unsigned int data_mask, ch_mask;
|
||||
int ret, vss, vdd;
|
||||
|
||||
if (argc < 2)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
ret = uclass_get_device_by_name(UCLASS_ADC, argv[1], &dev);
|
||||
if (ret) {
|
||||
printf("Unknown ADC device %s\n", argv[1]);
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
printf("ADC Device '%s' :\n", argv[1]);
|
||||
|
||||
ret = adc_channel_mask(dev, &ch_mask);
|
||||
if (!ret)
|
||||
printf("channel mask: %x\n", ch_mask);
|
||||
|
||||
ret = adc_data_mask(dev, &data_mask);
|
||||
if (!ret)
|
||||
printf("data mask: %x\n", data_mask);
|
||||
|
||||
ret = adc_vdd_value(dev, &vdd);
|
||||
if (!ret)
|
||||
printf("vdd: %duV\n", vdd);
|
||||
|
||||
ret = adc_vss_value(dev, &vss);
|
||||
if (!ret)
|
||||
printf("vss: %duV\n", vss);
|
||||
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
static int do_adc_single(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char *const argv[])
|
||||
{
|
||||
struct udevice *dev;
|
||||
unsigned int data;
|
||||
int ret, uV;
|
||||
|
||||
if (argc < 3)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
ret = adc_channel_single_shot(argv[1], simple_strtol(argv[2], NULL, 0),
|
||||
&data);
|
||||
if (ret) {
|
||||
printf("Error getting single shot for device %s channel %s\n",
|
||||
argv[1], argv[2]);
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
ret = uclass_get_device_by_name(UCLASS_ADC, argv[1], &dev);
|
||||
if (!ret && !adc_raw_to_uV(dev, data, &uV))
|
||||
printf("%u, %d uV\n", data, uV);
|
||||
else
|
||||
printf("%u\n", data);
|
||||
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
static int do_adc_scan(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char *const argv[])
|
||||
{
|
||||
struct adc_channel ch[ADC_MAX_CHANNEL];
|
||||
struct udevice *dev;
|
||||
unsigned int ch_mask;
|
||||
int i, chan, ret, uV;
|
||||
|
||||
if (argc < 2)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
ret = uclass_get_device_by_name(UCLASS_ADC, argv[1], &dev);
|
||||
if (ret) {
|
||||
pr_err("Can't get the ADC %s: %d\n", argv[1], ret);
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
switch (argc) {
|
||||
case 3:
|
||||
ch_mask = simple_strtoul(argv[2], NULL, 0);
|
||||
if (ch_mask)
|
||||
break;
|
||||
case 2:
|
||||
ret = adc_channel_mask(dev, &ch_mask);
|
||||
if (ret) {
|
||||
pr_err("Can't get mask for %s: %d\n", dev->name, ret);
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ret = adc_channels_single_shot(dev->name, ch_mask, ch);
|
||||
if (ret) {
|
||||
pr_err("Can't get single shot for %s (chans mask: 0x%x): %d\n",
|
||||
dev->name, ch_mask, ret);
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
for (chan = 0, i = 0; chan < ADC_MAX_CHANNEL; chan++) {
|
||||
if (!(ch_mask & ADC_CHANNEL(chan)))
|
||||
continue;
|
||||
if (!adc_raw_to_uV(dev, ch[i].data, &uV))
|
||||
printf("[%02d]: %u, %d uV\n", ch[i].id, ch[i].data, uV);
|
||||
else
|
||||
printf("[%02d]: %u\n", ch[i].id, ch[i].data);
|
||||
i++;
|
||||
}
|
||||
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
static char adc_help_text[] =
|
||||
"list - list ADC devices\n"
|
||||
"adc info <name> - Get ADC device info\n"
|
||||
"adc single <name> <channel> - Get Single data of ADC device channel\n"
|
||||
"adc scan <name> [channel mask] - Scan all [or masked] ADC channels";
|
||||
|
||||
U_BOOT_CMD_WITH_SUBCMDS(adc, "ADC sub-system", adc_help_text,
|
||||
U_BOOT_SUBCMD_MKENT(list, 1, 1, do_adc_list),
|
||||
U_BOOT_SUBCMD_MKENT(info, 2, 1, do_adc_info),
|
||||
U_BOOT_SUBCMD_MKENT(single, 3, 1, do_adc_single),
|
||||
U_BOOT_SUBCMD_MKENT(scan, 3, 1, do_adc_scan));
|
||||
97
cmd/aes.c
Normal file
97
cmd/aes.c
Normal file
@@ -0,0 +1,97 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2014 Marek Vasut <marex@denx.de>
|
||||
*
|
||||
* Command for en/de-crypting block of memory with AES-128-CBC cipher.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <uboot_aes.h>
|
||||
#include <malloc.h>
|
||||
#include <asm/byteorder.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <mapmem.h>
|
||||
|
||||
/**
|
||||
* do_aes() - Handle the "aes" command-line command
|
||||
* @cmdtp: Command data struct pointer
|
||||
* @flag: Command flag
|
||||
* @argc: Command-line argument count
|
||||
* @argv: Array of command-line arguments
|
||||
*
|
||||
* Returns zero on success, CMD_RET_USAGE in case of misuse and negative
|
||||
* on error.
|
||||
*/
|
||||
static int do_aes(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
|
||||
{
|
||||
uint32_t key_addr, iv_addr, src_addr, dst_addr, len;
|
||||
uint8_t *key_ptr, *iv_ptr, *src_ptr, *dst_ptr;
|
||||
uint8_t key_exp[AES_EXPAND_KEY_LENGTH];
|
||||
uint32_t aes_blocks;
|
||||
int enc;
|
||||
|
||||
if (argc != 7)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
if (!strncmp(argv[1], "enc", 3))
|
||||
enc = 1;
|
||||
else if (!strncmp(argv[1], "dec", 3))
|
||||
enc = 0;
|
||||
else
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
key_addr = simple_strtoul(argv[2], NULL, 16);
|
||||
iv_addr = simple_strtoul(argv[3], NULL, 16);
|
||||
src_addr = simple_strtoul(argv[4], NULL, 16);
|
||||
dst_addr = simple_strtoul(argv[5], NULL, 16);
|
||||
len = simple_strtoul(argv[6], NULL, 16);
|
||||
|
||||
key_ptr = (uint8_t *)map_sysmem(key_addr, 128 / 8);
|
||||
iv_ptr = (uint8_t *)map_sysmem(iv_addr, 128 / 8);
|
||||
src_ptr = (uint8_t *)map_sysmem(src_addr, len);
|
||||
dst_ptr = (uint8_t *)map_sysmem(dst_addr, len);
|
||||
|
||||
/* First we expand the key. */
|
||||
aes_expand_key(key_ptr, key_exp);
|
||||
|
||||
/* Calculate the number of AES blocks to encrypt. */
|
||||
aes_blocks = DIV_ROUND_UP(len, AES_KEY_LENGTH);
|
||||
|
||||
if (enc)
|
||||
aes_cbc_encrypt_blocks(key_exp, iv_ptr, src_ptr, dst_ptr,
|
||||
aes_blocks);
|
||||
else
|
||||
aes_cbc_decrypt_blocks(key_exp, iv_ptr, src_ptr, dst_ptr,
|
||||
aes_blocks);
|
||||
|
||||
unmap_sysmem(key_ptr);
|
||||
unmap_sysmem(iv_ptr);
|
||||
unmap_sysmem(src_ptr);
|
||||
unmap_sysmem(dst_ptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***************************************************/
|
||||
#ifdef CONFIG_SYS_LONGHELP
|
||||
static char aes_help_text[] =
|
||||
"enc key iv src dst len - Encrypt block of data $len bytes long\n"
|
||||
" at address $src using a key at address\n"
|
||||
" $key with initialization vector at address\n"
|
||||
" $iv. Store the result at address $dst.\n"
|
||||
" The $len size must be multiple of 16 bytes.\n"
|
||||
" The $key and $iv must be 16 bytes long.\n"
|
||||
"aes dec key iv src dst len - Decrypt block of data $len bytes long\n"
|
||||
" at address $src using a key at address\n"
|
||||
" $key with initialization vector at address\n"
|
||||
" $iv. Store the result at address $dst.\n"
|
||||
" The $len size must be multiple of 16 bytes.\n"
|
||||
" The $key and $iv must be 16 bytes long.";
|
||||
#endif
|
||||
|
||||
U_BOOT_CMD(
|
||||
aes, 7, 1, do_aes,
|
||||
"AES 128 CBC encryption",
|
||||
aes_help_text
|
||||
);
|
||||
7
cmd/arm/Makefile
Normal file
7
cmd/arm/Makefile
Normal file
@@ -0,0 +1,7 @@
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
ifdef CONFIG_ARM64
|
||||
obj-$(CONFIG_CMD_EXCEPTION) += exception64.o
|
||||
else
|
||||
obj-$(CONFIG_CMD_EXCEPTION) += exception.o
|
||||
endif
|
||||
61
cmd/arm/exception.c
Normal file
61
cmd/arm/exception.c
Normal file
@@ -0,0 +1,61 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* The 'exception' command can be used for testing exception handling.
|
||||
*
|
||||
* Copyright (c) 2018, Heinrich Schuchardt <xypron.glpk@gmx.de>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
|
||||
static int do_unaligned(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
/*
|
||||
* The LDRD instruction requires the data source to be four byte aligned
|
||||
* even if strict alignment fault checking is disabled in the system
|
||||
* control register.
|
||||
*/
|
||||
asm volatile (
|
||||
"MOV r5, sp\n"
|
||||
"ADD r5, #1\n"
|
||||
"LDRD r6, r7, [r5]\n");
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
static int do_breakpoint(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
asm volatile ("BKPT #123\n");
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
static int do_undefined(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
/*
|
||||
* 0xe7f...f. is undefined in ARM mode
|
||||
* 0xde.. is undefined in Thumb mode
|
||||
*/
|
||||
asm volatile (".word 0xe7f7defb\n");
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
static cmd_tbl_t cmd_sub[] = {
|
||||
U_BOOT_CMD_MKENT(breakpoint, CONFIG_SYS_MAXARGS, 1, do_breakpoint,
|
||||
"", ""),
|
||||
U_BOOT_CMD_MKENT(unaligned, CONFIG_SYS_MAXARGS, 1, do_unaligned,
|
||||
"", ""),
|
||||
U_BOOT_CMD_MKENT(undefined, CONFIG_SYS_MAXARGS, 1, do_undefined,
|
||||
"", ""),
|
||||
};
|
||||
|
||||
static char exception_help_text[] =
|
||||
"<ex>\n"
|
||||
" The following exceptions are available:\n"
|
||||
" breakpoint - prefetch abort\n"
|
||||
" unaligned - data abort\n"
|
||||
" undefined - undefined instruction\n"
|
||||
;
|
||||
|
||||
#include <exception.h>
|
||||
33
cmd/arm/exception64.c
Normal file
33
cmd/arm/exception64.c
Normal file
@@ -0,0 +1,33 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* The 'exception' command can be used for testing exception handling.
|
||||
*
|
||||
* Copyright (c) 2018, Heinrich Schuchardt <xypron.glpk@gmx.de>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
|
||||
static int do_undefined(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
/*
|
||||
* 0xe7f...f. is undefined in ARM mode
|
||||
* 0xde.. is undefined in Thumb mode
|
||||
*/
|
||||
asm volatile (".word 0xe7f7defb\n");
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
static cmd_tbl_t cmd_sub[] = {
|
||||
U_BOOT_CMD_MKENT(undefined, CONFIG_SYS_MAXARGS, 1, do_undefined,
|
||||
"", ""),
|
||||
};
|
||||
|
||||
static char exception_help_text[] =
|
||||
"<ex>\n"
|
||||
" The following exceptions are available:\n"
|
||||
" undefined - undefined instruction\n"
|
||||
;
|
||||
|
||||
#include <exception.h>
|
||||
299
cmd/armflash.c
Normal file
299
cmd/armflash.c
Normal file
@@ -0,0 +1,299 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2015
|
||||
* Linus Walleij, Linaro
|
||||
*
|
||||
* Support for ARM Flash Partitions
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <console.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#define MAX_REGIONS 4
|
||||
#define MAX_IMAGES 32
|
||||
|
||||
struct afs_region {
|
||||
u32 load_address;
|
||||
u32 size;
|
||||
u32 offset;
|
||||
};
|
||||
|
||||
struct afs_image {
|
||||
flash_info_t *flinfo;
|
||||
const char *name;
|
||||
u32 version;
|
||||
u32 entrypoint;
|
||||
u32 attributes;
|
||||
u32 region_count;
|
||||
struct afs_region regions[MAX_REGIONS];
|
||||
ulong flash_mem_start;
|
||||
ulong flash_mem_end;
|
||||
};
|
||||
|
||||
static struct afs_image afs_images[MAX_IMAGES];
|
||||
static int num_afs_images;
|
||||
|
||||
static u32 compute_crc(ulong start, u32 len)
|
||||
{
|
||||
u32 sum = 0;
|
||||
int i;
|
||||
|
||||
if (len % 4 != 0) {
|
||||
printf("bad checksumming\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < len; i += 4) {
|
||||
u32 val;
|
||||
|
||||
val = readl((void *)start + i);
|
||||
if (val > ~sum)
|
||||
sum++;
|
||||
sum += val;
|
||||
}
|
||||
return ~sum;
|
||||
}
|
||||
|
||||
static void parse_bank(ulong bank)
|
||||
{
|
||||
int i;
|
||||
ulong flstart, flend;
|
||||
flash_info_t *info;
|
||||
|
||||
info = &flash_info[bank];
|
||||
if (info->flash_id != FLASH_MAN_CFI) {
|
||||
printf("Bank %lu: missing or unknown FLASH type\n", bank);
|
||||
return;
|
||||
}
|
||||
if (!info->sector_count) {
|
||||
printf("Bank %lu: no FLASH sectors\n", bank);
|
||||
return;
|
||||
}
|
||||
|
||||
flstart = info->start[0];
|
||||
flend = flstart + info->size;
|
||||
|
||||
for (i = 0; i < info->sector_count; ++i) {
|
||||
ulong secend;
|
||||
u32 foot1, foot2;
|
||||
|
||||
if (ctrlc())
|
||||
break;
|
||||
|
||||
if (i == info->sector_count-1)
|
||||
secend = flend;
|
||||
else
|
||||
secend = info->start[i+1];
|
||||
|
||||
/* Check for v1 header */
|
||||
foot1 = readl((void *)secend - 0x0c);
|
||||
if (foot1 == 0xA0FFFF9FU) {
|
||||
struct afs_image *afi = &afs_images[num_afs_images];
|
||||
ulong imginfo;
|
||||
|
||||
afi->flinfo = info;
|
||||
afi->version = 1;
|
||||
afi->flash_mem_start = readl((void *)secend - 0x10);
|
||||
afi->flash_mem_end = readl((void *)secend - 0x14);
|
||||
afi->attributes = readl((void *)secend - 0x08);
|
||||
/* Adjust to even address */
|
||||
imginfo = afi->flash_mem_end + afi->flash_mem_end % 4;
|
||||
/* Record as a single region */
|
||||
afi->region_count = 1;
|
||||
afi->regions[0].offset = readl((void *)imginfo + 0x04);
|
||||
afi->regions[0].load_address =
|
||||
readl((void *)imginfo + 0x08);
|
||||
afi->regions[0].size = readl((void *)imginfo + 0x0C);
|
||||
afi->entrypoint = readl((void *)imginfo + 0x10);
|
||||
afi->name = (const char *)imginfo + 0x14;
|
||||
num_afs_images++;
|
||||
}
|
||||
|
||||
/* Check for v2 header */
|
||||
foot1 = readl((void *)secend - 0x04);
|
||||
foot2 = readl((void *)secend - 0x08);
|
||||
/* This makes up the string "HSLFTOOF" flash footer */
|
||||
if (foot1 == 0x464F4F54U && foot2 == 0x464C5348U) {
|
||||
struct afs_image *afi = &afs_images[num_afs_images];
|
||||
ulong imginfo;
|
||||
u32 block_start, block_end;
|
||||
int j;
|
||||
|
||||
afi->flinfo = info;
|
||||
afi->version = readl((void *)secend - 0x0c);
|
||||
imginfo = secend - 0x30 - readl((void *)secend - 0x10);
|
||||
afi->name = (const char *)secend - 0x30;
|
||||
|
||||
afi->entrypoint = readl((void *)imginfo+0x08);
|
||||
afi->attributes = readl((void *)imginfo+0x0c);
|
||||
afi->region_count = readl((void *)imginfo+0x10);
|
||||
block_start = readl((void *)imginfo+0x54);
|
||||
block_end = readl((void *)imginfo+0x58);
|
||||
afi->flash_mem_start = afi->flinfo->start[block_start];
|
||||
afi->flash_mem_end = afi->flinfo->start[block_end];
|
||||
|
||||
/*
|
||||
* Check footer CRC, the algorithm saves the inverse
|
||||
* checksum as part of the summed words, and thus
|
||||
* the result should be zero.
|
||||
*/
|
||||
if (compute_crc(imginfo + 8, 0x88) != 0) {
|
||||
printf("BAD CRC on ARM image info\n");
|
||||
printf("(continuing anyway)\n");
|
||||
}
|
||||
|
||||
/* Parse regions */
|
||||
for (j = 0; j < afi->region_count; j++) {
|
||||
afi->regions[j].load_address =
|
||||
readl((void *)imginfo+0x14 + j*0x10);
|
||||
afi->regions[j].size =
|
||||
readl((void *)imginfo+0x18 + j*0x10);
|
||||
afi->regions[j].offset =
|
||||
readl((void *)imginfo+0x1c + j*0x10);
|
||||
/*
|
||||
* At offset 0x20 + j*0x10 there is a region
|
||||
* checksum which seems to be the running
|
||||
* sum + 3, however since we anyway checksum
|
||||
* the entire footer this is skipped over for
|
||||
* checking here.
|
||||
*/
|
||||
}
|
||||
num_afs_images++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_flash(void)
|
||||
{
|
||||
ulong bank;
|
||||
|
||||
/* We have already parsed the images in flash */
|
||||
if (num_afs_images > 0)
|
||||
return;
|
||||
for (bank = 0; bank < CONFIG_SYS_MAX_FLASH_BANKS; ++bank)
|
||||
parse_bank(bank);
|
||||
}
|
||||
|
||||
static int load_image(const char * const name, const ulong address)
|
||||
{
|
||||
struct afs_image *afi = NULL;
|
||||
int i;
|
||||
|
||||
parse_flash();
|
||||
for (i = 0; i < num_afs_images; i++) {
|
||||
struct afs_image *tmp = &afs_images[i];
|
||||
|
||||
if (!strcmp(tmp->name, name)) {
|
||||
afi = tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!afi) {
|
||||
printf("image \"%s\" not found in flash\n", name);
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
for (i = 0; i < afi->region_count; i++) {
|
||||
ulong from, to;
|
||||
|
||||
from = afi->flash_mem_start + afi->regions[i].offset;
|
||||
if (address) {
|
||||
to = address;
|
||||
} else if (afi->regions[i].load_address) {
|
||||
to = afi->regions[i].load_address;
|
||||
} else {
|
||||
printf("no valid load address\n");
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
memcpy((void *)to, (void *)from, afi->regions[i].size);
|
||||
|
||||
printf("loaded region %d from %08lX to %08lX, %08X bytes\n",
|
||||
i,
|
||||
from,
|
||||
to,
|
||||
afi->regions[i].size);
|
||||
}
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
static void print_images(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
parse_flash();
|
||||
for (i = 0; i < num_afs_images; i++) {
|
||||
struct afs_image *afi = &afs_images[i];
|
||||
int j;
|
||||
|
||||
printf("Image: \"%s\" (v%d):\n", afi->name, afi->version);
|
||||
printf(" Entry point: 0x%08X\n", afi->entrypoint);
|
||||
printf(" Attributes: 0x%08X: ", afi->attributes);
|
||||
if (afi->attributes == 0x01)
|
||||
printf("ARM executable");
|
||||
if (afi->attributes == 0x08)
|
||||
printf("ARM backup");
|
||||
printf("\n");
|
||||
printf(" Flash mem start: 0x%08lX\n",
|
||||
afi->flash_mem_start);
|
||||
printf(" Flash mem end: 0x%08lX\n",
|
||||
afi->flash_mem_end);
|
||||
for (j = 0; j < afi->region_count; j++) {
|
||||
printf(" region %d\n"
|
||||
" load address: %08X\n"
|
||||
" size: %08X\n"
|
||||
" offset: %08X\n",
|
||||
j,
|
||||
afi->regions[j].load_address,
|
||||
afi->regions[j].size,
|
||||
afi->regions[j].offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int exists(const char * const name)
|
||||
{
|
||||
int i;
|
||||
|
||||
parse_flash();
|
||||
for (i = 0; i < num_afs_images; i++) {
|
||||
struct afs_image *afi = &afs_images[i];
|
||||
|
||||
if (strcmp(afi->name, name) == 0)
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
static int do_afs(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
int ret = CMD_RET_SUCCESS;
|
||||
|
||||
if (argc == 1) {
|
||||
print_images();
|
||||
} else if (argc == 3 && !strcmp(argv[1], "exists")) {
|
||||
ret = exists(argv[2]);
|
||||
} else if (argc == 3 && !strcmp(argv[1], "load")) {
|
||||
ret = load_image(argv[2], 0x0);
|
||||
} else if (argc == 4 && !strcmp(argv[1], "load")) {
|
||||
ulong load_addr;
|
||||
|
||||
load_addr = simple_strtoul(argv[3], NULL, 16);
|
||||
ret = load_image(argv[2], load_addr);
|
||||
} else {
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(afs, 4, 0, do_afs, "show AFS partitions",
|
||||
"no arguments\n"
|
||||
" - list images in flash\n"
|
||||
"exists <image>\n"
|
||||
" - returns 1 if an image exists, else 0\n"
|
||||
"load <image>\n"
|
||||
" - load an image to the location indicated in the header\n"
|
||||
"load <image> 0x<address>\n"
|
||||
" - load an image to the location specified\n");
|
||||
469
cmd/avb.c
Normal file
469
cmd/avb.c
Normal file
@@ -0,0 +1,469 @@
|
||||
|
||||
/*
|
||||
* (C) Copyright 2018, Linaro Limited
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <avb_verify.h>
|
||||
#include <command.h>
|
||||
#include <env.h>
|
||||
#include <image.h>
|
||||
#include <malloc.h>
|
||||
#include <mmc.h>
|
||||
|
||||
#define AVB_BOOTARGS "avb_bootargs"
|
||||
static struct AvbOps *avb_ops;
|
||||
|
||||
int do_avb_init(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
unsigned long mmc_dev;
|
||||
|
||||
if (argc != 2)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
mmc_dev = simple_strtoul(argv[1], NULL, 16);
|
||||
|
||||
if (avb_ops)
|
||||
avb_ops_free(avb_ops);
|
||||
|
||||
avb_ops = avb_ops_alloc(mmc_dev);
|
||||
if (avb_ops)
|
||||
return CMD_RET_SUCCESS;
|
||||
|
||||
printf("Failed to initialize avb2\n");
|
||||
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
int do_avb_read_part(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
const char *part;
|
||||
s64 offset;
|
||||
size_t bytes, bytes_read = 0;
|
||||
void *buffer;
|
||||
|
||||
if (!avb_ops) {
|
||||
printf("AVB 2.0 is not initialized, please run 'avb init'\n");
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
if (argc != 5)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
part = argv[1];
|
||||
offset = simple_strtoul(argv[2], NULL, 16);
|
||||
bytes = simple_strtoul(argv[3], NULL, 16);
|
||||
buffer = (void *)simple_strtoul(argv[4], NULL, 16);
|
||||
|
||||
if (avb_ops->read_from_partition(avb_ops, part, offset, bytes,
|
||||
buffer, &bytes_read) ==
|
||||
AVB_IO_RESULT_OK) {
|
||||
printf("Read %zu bytes\n", bytes_read);
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
printf("Failed to read from partition\n");
|
||||
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
int do_avb_read_part_hex(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char *const argv[])
|
||||
{
|
||||
const char *part;
|
||||
s64 offset;
|
||||
size_t bytes, bytes_read = 0;
|
||||
char *buffer;
|
||||
|
||||
if (!avb_ops) {
|
||||
printf("AVB 2.0 is not initialized, please run 'avb init'\n");
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
if (argc != 4)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
part = argv[1];
|
||||
offset = simple_strtoul(argv[2], NULL, 16);
|
||||
bytes = simple_strtoul(argv[3], NULL, 16);
|
||||
|
||||
buffer = malloc(bytes);
|
||||
if (!buffer) {
|
||||
printf("Failed to tlb_allocate buffer for data\n");
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
memset(buffer, 0, bytes);
|
||||
|
||||
if (avb_ops->read_from_partition(avb_ops, part, offset, bytes, buffer,
|
||||
&bytes_read) == AVB_IO_RESULT_OK) {
|
||||
printf("Requested %zu, read %zu bytes\n", bytes, bytes_read);
|
||||
printf("Data: ");
|
||||
for (int i = 0; i < bytes_read; i++)
|
||||
printf("%02X", buffer[i]);
|
||||
|
||||
printf("\n");
|
||||
|
||||
free(buffer);
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
printf("Failed to read from partition\n");
|
||||
|
||||
free(buffer);
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
int do_avb_write_part(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
const char *part;
|
||||
s64 offset;
|
||||
size_t bytes;
|
||||
void *buffer;
|
||||
|
||||
if (!avb_ops) {
|
||||
printf("AVB 2.0 is not initialized, run 'avb init' first\n");
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
if (argc != 5)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
part = argv[1];
|
||||
offset = simple_strtoul(argv[2], NULL, 16);
|
||||
bytes = simple_strtoul(argv[3], NULL, 16);
|
||||
buffer = (void *)simple_strtoul(argv[4], NULL, 16);
|
||||
|
||||
if (avb_ops->write_to_partition(avb_ops, part, offset, bytes, buffer) ==
|
||||
AVB_IO_RESULT_OK) {
|
||||
printf("Wrote %zu bytes\n", bytes);
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
printf("Failed to write in partition\n");
|
||||
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
int do_avb_read_rb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
size_t index;
|
||||
u64 rb_idx;
|
||||
|
||||
if (!avb_ops) {
|
||||
printf("AVB 2.0 is not initialized, run 'avb init' first\n");
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
if (argc != 2)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
index = (size_t)simple_strtoul(argv[1], NULL, 16);
|
||||
|
||||
if (avb_ops->read_rollback_index(avb_ops, index, &rb_idx) ==
|
||||
AVB_IO_RESULT_OK) {
|
||||
printf("Rollback index: %llx\n", rb_idx);
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
printf("Failed to read rollback index\n");
|
||||
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
int do_avb_write_rb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
size_t index;
|
||||
u64 rb_idx;
|
||||
|
||||
if (!avb_ops) {
|
||||
printf("AVB 2.0 is not initialized, run 'avb init' first\n");
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
if (argc != 3)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
index = (size_t)simple_strtoul(argv[1], NULL, 16);
|
||||
rb_idx = simple_strtoul(argv[2], NULL, 16);
|
||||
|
||||
if (avb_ops->write_rollback_index(avb_ops, index, rb_idx) ==
|
||||
AVB_IO_RESULT_OK)
|
||||
return CMD_RET_SUCCESS;
|
||||
|
||||
printf("Failed to write rollback index\n");
|
||||
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
int do_avb_get_uuid(cmd_tbl_t *cmdtp, int flag,
|
||||
int argc, char * const argv[])
|
||||
{
|
||||
const char *part;
|
||||
char buffer[UUID_STR_LEN + 1];
|
||||
|
||||
if (!avb_ops) {
|
||||
printf("AVB 2.0 is not initialized, run 'avb init' first\n");
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
if (argc != 2)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
part = argv[1];
|
||||
|
||||
if (avb_ops->get_unique_guid_for_partition(avb_ops, part, buffer,
|
||||
UUID_STR_LEN + 1) ==
|
||||
AVB_IO_RESULT_OK) {
|
||||
printf("'%s' UUID: %s\n", part, buffer);
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
printf("Failed to read UUID\n");
|
||||
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
int do_avb_verify_part(cmd_tbl_t *cmdtp, int flag,
|
||||
int argc, char *const argv[])
|
||||
{
|
||||
const char * const requested_partitions[] = {"boot", NULL};
|
||||
AvbSlotVerifyResult slot_result;
|
||||
AvbSlotVerifyData *out_data;
|
||||
char *cmdline;
|
||||
char *extra_args;
|
||||
char *slot_suffix = "";
|
||||
|
||||
bool unlocked = false;
|
||||
int res = CMD_RET_FAILURE;
|
||||
|
||||
if (!avb_ops) {
|
||||
printf("AVB 2.0 is not initialized, run 'avb init' first\n");
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
if (argc < 1 || argc > 2)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
if (argc == 2)
|
||||
slot_suffix = argv[1];
|
||||
|
||||
printf("## Android Verified Boot 2.0 version %s\n",
|
||||
avb_version_string());
|
||||
|
||||
if (avb_ops->read_is_device_unlocked(avb_ops, &unlocked) !=
|
||||
AVB_IO_RESULT_OK) {
|
||||
printf("Can't determine device lock state.\n");
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
slot_result =
|
||||
avb_slot_verify(avb_ops,
|
||||
requested_partitions,
|
||||
slot_suffix,
|
||||
unlocked,
|
||||
AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE,
|
||||
&out_data);
|
||||
|
||||
switch (slot_result) {
|
||||
case AVB_SLOT_VERIFY_RESULT_OK:
|
||||
/* Until we don't have support of changing unlock states, we
|
||||
* assume that we are by default in locked state.
|
||||
* So in this case we can boot only when verification is
|
||||
* successful; we also supply in cmdline GREEN boot state
|
||||
*/
|
||||
printf("Verification passed successfully\n");
|
||||
|
||||
/* export additional bootargs to AVB_BOOTARGS env var */
|
||||
|
||||
extra_args = avb_set_state(avb_ops, AVB_GREEN);
|
||||
if (extra_args)
|
||||
cmdline = append_cmd_line(out_data->cmdline,
|
||||
extra_args);
|
||||
else
|
||||
cmdline = out_data->cmdline;
|
||||
|
||||
env_set(AVB_BOOTARGS, cmdline);
|
||||
|
||||
res = CMD_RET_SUCCESS;
|
||||
break;
|
||||
case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION:
|
||||
printf("Verification failed\n");
|
||||
break;
|
||||
case AVB_SLOT_VERIFY_RESULT_ERROR_IO:
|
||||
printf("I/O error occurred during verification\n");
|
||||
break;
|
||||
case AVB_SLOT_VERIFY_RESULT_ERROR_OOM:
|
||||
printf("OOM error occurred during verification\n");
|
||||
break;
|
||||
case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA:
|
||||
printf("Corrupted dm-verity metadata detected\n");
|
||||
break;
|
||||
case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION:
|
||||
printf("Unsupported version avbtool was used\n");
|
||||
break;
|
||||
case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX:
|
||||
printf("Checking rollback index failed\n");
|
||||
break;
|
||||
case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED:
|
||||
printf("Public key was rejected\n");
|
||||
break;
|
||||
default:
|
||||
printf("Unknown error occurred\n");
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int do_avb_is_unlocked(cmd_tbl_t *cmdtp, int flag,
|
||||
int argc, char * const argv[])
|
||||
{
|
||||
bool unlock;
|
||||
|
||||
if (!avb_ops) {
|
||||
printf("AVB not initialized, run 'avb init' first\n");
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
if (argc != 1) {
|
||||
printf("--%s(-1)\n", __func__);
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
if (avb_ops->read_is_device_unlocked(avb_ops, &unlock) ==
|
||||
AVB_IO_RESULT_OK) {
|
||||
printf("Unlocked = %d\n", unlock);
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
printf("Can't determine device lock state.\n");
|
||||
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
int do_avb_read_pvalue(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
const char *name;
|
||||
size_t bytes;
|
||||
size_t bytes_read;
|
||||
void *buffer;
|
||||
char *endp;
|
||||
|
||||
if (!avb_ops) {
|
||||
printf("AVB 2.0 is not initialized, run 'avb init' first\n");
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
if (argc != 3)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
name = argv[1];
|
||||
bytes = simple_strtoul(argv[2], &endp, 10);
|
||||
if (*endp && *endp != '\n')
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
buffer = malloc(bytes);
|
||||
if (!buffer)
|
||||
return CMD_RET_FAILURE;
|
||||
|
||||
if (avb_ops->read_persistent_value(avb_ops, name, bytes, buffer,
|
||||
&bytes_read) == AVB_IO_RESULT_OK) {
|
||||
printf("Read %zu bytes, value = %s\n", bytes_read,
|
||||
(char *)buffer);
|
||||
free(buffer);
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
printf("Failed to read persistent value\n");
|
||||
|
||||
free(buffer);
|
||||
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
int do_avb_write_pvalue(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
const char *name;
|
||||
const char *value;
|
||||
|
||||
if (!avb_ops) {
|
||||
printf("AVB 2.0 is not initialized, run 'avb init' first\n");
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
if (argc != 3)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
name = argv[1];
|
||||
value = argv[2];
|
||||
|
||||
if (avb_ops->write_persistent_value(avb_ops, name, strlen(value) + 1,
|
||||
(const uint8_t *)value) ==
|
||||
AVB_IO_RESULT_OK) {
|
||||
printf("Wrote %zu bytes\n", strlen(value) + 1);
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
printf("Failed to write persistent value\n");
|
||||
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
static cmd_tbl_t cmd_avb[] = {
|
||||
U_BOOT_CMD_MKENT(init, 2, 0, do_avb_init, "", ""),
|
||||
U_BOOT_CMD_MKENT(read_rb, 2, 0, do_avb_read_rb, "", ""),
|
||||
U_BOOT_CMD_MKENT(write_rb, 3, 0, do_avb_write_rb, "", ""),
|
||||
U_BOOT_CMD_MKENT(is_unlocked, 1, 0, do_avb_is_unlocked, "", ""),
|
||||
U_BOOT_CMD_MKENT(get_uuid, 2, 0, do_avb_get_uuid, "", ""),
|
||||
U_BOOT_CMD_MKENT(read_part, 5, 0, do_avb_read_part, "", ""),
|
||||
U_BOOT_CMD_MKENT(read_part_hex, 4, 0, do_avb_read_part_hex, "", ""),
|
||||
U_BOOT_CMD_MKENT(write_part, 5, 0, do_avb_write_part, "", ""),
|
||||
U_BOOT_CMD_MKENT(verify, 2, 0, do_avb_verify_part, "", ""),
|
||||
#ifdef CONFIG_OPTEE_TA_AVB
|
||||
U_BOOT_CMD_MKENT(read_pvalue, 3, 0, do_avb_read_pvalue, "", ""),
|
||||
U_BOOT_CMD_MKENT(write_pvalue, 3, 0, do_avb_write_pvalue, "", ""),
|
||||
#endif
|
||||
};
|
||||
|
||||
static int do_avb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
cmd_tbl_t *cp;
|
||||
|
||||
cp = find_cmd_tbl(argv[1], cmd_avb, ARRAY_SIZE(cmd_avb));
|
||||
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
if (!cp || argc > cp->maxargs)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
if (flag == CMD_FLAG_REPEAT)
|
||||
return CMD_RET_FAILURE;
|
||||
|
||||
return cp->cmd(cmdtp, flag, argc, argv);
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
avb, 29, 0, do_avb,
|
||||
"Provides commands for testing Android Verified Boot 2.0 functionality",
|
||||
"init <dev> - initialize avb2 for <dev>\n"
|
||||
"avb read_rb <num> - read rollback index at location <num>\n"
|
||||
"avb write_rb <num> <rb> - write rollback index <rb> to <num>\n"
|
||||
"avb is_unlocked - returns unlock status of the device\n"
|
||||
"avb get_uuid <partname> - read and print uuid of partition <part>\n"
|
||||
"avb read_part <partname> <offset> <num> <addr> - read <num> bytes from\n"
|
||||
" partition <partname> to buffer <addr>\n"
|
||||
"avb read_part_hex <partname> <offset> <num> - read <num> bytes from\n"
|
||||
" partition <partname> and print to stdout\n"
|
||||
"avb write_part <partname> <offset> <num> <addr> - write <num> bytes to\n"
|
||||
" <partname> by <offset> using data from <addr>\n"
|
||||
#ifdef CONFIG_OPTEE_TA_AVB
|
||||
"avb read_pvalue <name> <bytes> - read a persistent value <name>\n"
|
||||
"avb write_pvalue <name> <value> - write a persistent value <name>\n"
|
||||
#endif
|
||||
"avb verify [slot_suffix] - run verification process using hash data\n"
|
||||
" from vbmeta structure\n"
|
||||
" [slot_suffix] - _a, _b, etc (if vbmeta partition is slotted)\n"
|
||||
);
|
||||
352
cmd/axi.c
Normal file
352
cmd/axi.c
Normal file
@@ -0,0 +1,352 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2016
|
||||
* Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc
|
||||
*
|
||||
* (C) Copyright 2017, 2018
|
||||
* Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <axi.h>
|
||||
#include <command.h>
|
||||
#include <console.h>
|
||||
#include <dm.h>
|
||||
|
||||
/* Currently selected AXI bus device */
|
||||
static struct udevice *axi_cur_bus;
|
||||
/* Transmission size from last command */
|
||||
static uint dp_last_size;
|
||||
/* Address from last command */
|
||||
static uint dp_last_addr;
|
||||
/* Number of bytes to display from last command; default = 64 */
|
||||
static uint dp_last_length = 0x40;
|
||||
|
||||
/**
|
||||
* show_bus() - Show devices on a single AXI bus
|
||||
* @bus: The AXI bus device to printt information for
|
||||
*/
|
||||
static void show_bus(struct udevice *bus)
|
||||
{
|
||||
struct udevice *dev;
|
||||
|
||||
printf("Bus %d:\t%s", bus->req_seq, bus->name);
|
||||
if (device_active(bus))
|
||||
printf(" (active %d)", bus->seq);
|
||||
printf("\n");
|
||||
for (device_find_first_child(bus, &dev);
|
||||
dev;
|
||||
device_find_next_child(&dev))
|
||||
printf(" %s\n", dev->name);
|
||||
}
|
||||
|
||||
/**
|
||||
* axi_set_cur_bus() - Set the currently active AXI bus
|
||||
* @busnum: The number of the bus (i.e. its sequence number) that should be
|
||||
* made active
|
||||
*
|
||||
* The operations supplied by this command operate only on the currently active
|
||||
* bus.
|
||||
*
|
||||
* Return: 0 if OK, -ve on error
|
||||
*/
|
||||
static int axi_set_cur_bus(unsigned int busnum)
|
||||
{
|
||||
struct udevice *bus;
|
||||
struct udevice *dummy;
|
||||
int ret;
|
||||
|
||||
/* Make sure that all sequence numbers are initialized */
|
||||
for (uclass_first_device(UCLASS_AXI, &dummy);
|
||||
dummy;
|
||||
uclass_next_device(&dummy))
|
||||
;
|
||||
|
||||
ret = uclass_get_device_by_seq(UCLASS_AXI, busnum, &bus);
|
||||
if (ret) {
|
||||
debug("%s: No bus %d\n", __func__, busnum);
|
||||
return ret;
|
||||
}
|
||||
axi_cur_bus = bus;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* axi_get_cur_bus() - Retrieve the currently active AXI bus device
|
||||
* @busp: Pointer to a struct udevice that receives the currently active bus
|
||||
* device
|
||||
*
|
||||
* Return: 0 if OK, -ve on error
|
||||
*/
|
||||
static int axi_get_cur_bus(struct udevice **busp)
|
||||
{
|
||||
if (!axi_cur_bus) {
|
||||
puts("No AXI bus selected\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
*busp = axi_cur_bus;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Command handlers
|
||||
*/
|
||||
|
||||
static int do_axi_show_bus(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
struct udevice *dummy;
|
||||
|
||||
/* Make sure that all sequence numbers are initialized */
|
||||
for (uclass_first_device(UCLASS_AXI, &dummy);
|
||||
dummy;
|
||||
uclass_next_device(&dummy))
|
||||
;
|
||||
|
||||
if (argc == 1) {
|
||||
/* show all busses */
|
||||
struct udevice *bus;
|
||||
|
||||
for (uclass_first_device(UCLASS_AXI, &bus);
|
||||
bus;
|
||||
uclass_next_device(&bus))
|
||||
show_bus(bus);
|
||||
} else {
|
||||
int i;
|
||||
|
||||
/* show specific bus */
|
||||
i = simple_strtoul(argv[1], NULL, 10);
|
||||
|
||||
struct udevice *bus;
|
||||
int ret;
|
||||
|
||||
ret = uclass_get_device_by_seq(UCLASS_AXI, i, &bus);
|
||||
if (ret) {
|
||||
printf("Invalid bus %d: err=%d\n", i, ret);
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
show_bus(bus);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_axi_bus_num(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
int ret = 0;
|
||||
int bus_no;
|
||||
|
||||
if (argc == 1) {
|
||||
/* querying current setting */
|
||||
struct udevice *bus;
|
||||
|
||||
if (!axi_get_cur_bus(&bus))
|
||||
bus_no = bus->seq;
|
||||
else
|
||||
bus_no = -1;
|
||||
|
||||
printf("Current bus is %d\n", bus_no);
|
||||
} else {
|
||||
bus_no = simple_strtoul(argv[1], NULL, 10);
|
||||
printf("Setting bus to %d\n", bus_no);
|
||||
|
||||
ret = axi_set_cur_bus(bus_no);
|
||||
if (ret)
|
||||
printf("Failure changing bus number (%d)\n", ret);
|
||||
}
|
||||
|
||||
return ret ? CMD_RET_FAILURE : 0;
|
||||
}
|
||||
|
||||
static int do_axi_md(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
/* Print that many bytes per line */
|
||||
const uint DISP_LINE_LEN = 16;
|
||||
u8 linebuf[DISP_LINE_LEN];
|
||||
unsigned int k;
|
||||
ulong addr, length, size;
|
||||
ulong nbytes;
|
||||
enum axi_size_t axisize;
|
||||
int unitsize;
|
||||
|
||||
/*
|
||||
* We use the last specified parameters, unless new ones are
|
||||
* entered.
|
||||
*/
|
||||
size = dp_last_size;
|
||||
addr = dp_last_addr;
|
||||
length = dp_last_length;
|
||||
|
||||
if (argc < 3)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
if (!axi_cur_bus) {
|
||||
puts("No AXI bus selected\n");
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
if ((flag & CMD_FLAG_REPEAT) == 0) {
|
||||
size = simple_strtoul(argv[1], NULL, 10);
|
||||
|
||||
/*
|
||||
* Address is specified since argc >= 3
|
||||
*/
|
||||
addr = simple_strtoul(argv[2], NULL, 16);
|
||||
|
||||
/*
|
||||
* If there's another parameter, it is the length to display;
|
||||
* length is the number of objects, not number of bytes
|
||||
*/
|
||||
if (argc > 3)
|
||||
length = simple_strtoul(argv[3], NULL, 16);
|
||||
}
|
||||
|
||||
switch (size) {
|
||||
case 8:
|
||||
axisize = AXI_SIZE_8;
|
||||
unitsize = 1;
|
||||
break;
|
||||
case 16:
|
||||
axisize = AXI_SIZE_16;
|
||||
unitsize = 2;
|
||||
break;
|
||||
case 32:
|
||||
axisize = AXI_SIZE_32;
|
||||
unitsize = 4;
|
||||
break;
|
||||
default:
|
||||
printf("Unknown read size '%lu'\n", size);
|
||||
return CMD_RET_USAGE;
|
||||
};
|
||||
|
||||
nbytes = length * unitsize;
|
||||
do {
|
||||
ulong linebytes = (nbytes > DISP_LINE_LEN) ?
|
||||
DISP_LINE_LEN : nbytes;
|
||||
|
||||
for (k = 0; k < linebytes / unitsize; ++k) {
|
||||
int ret = axi_read(axi_cur_bus, addr + k * unitsize,
|
||||
linebuf + k * unitsize, axisize);
|
||||
|
||||
if (!ret) /* Continue if axi_read was successful */
|
||||
continue;
|
||||
|
||||
if (ret == -ENOSYS)
|
||||
printf("axi_read failed; read size not supported?\n");
|
||||
else
|
||||
printf("axi_read failed: err = %d\n", ret);
|
||||
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
print_buffer(addr, (void *)linebuf, unitsize,
|
||||
linebytes / unitsize,
|
||||
DISP_LINE_LEN / unitsize);
|
||||
|
||||
nbytes -= max(linebytes, 1UL);
|
||||
addr += linebytes;
|
||||
|
||||
if (ctrlc())
|
||||
break;
|
||||
} while (nbytes > 0);
|
||||
|
||||
dp_last_size = size;
|
||||
dp_last_addr = addr;
|
||||
dp_last_length = length;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_axi_mw(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
u32 writeval;
|
||||
ulong addr, count, size;
|
||||
enum axi_size_t axisize;
|
||||
|
||||
if (argc <= 3 || argc >= 6)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
size = simple_strtoul(argv[1], NULL, 10);
|
||||
|
||||
switch (size) {
|
||||
case 8:
|
||||
axisize = AXI_SIZE_8;
|
||||
break;
|
||||
case 16:
|
||||
axisize = AXI_SIZE_16;
|
||||
break;
|
||||
case 32:
|
||||
axisize = AXI_SIZE_32;
|
||||
break;
|
||||
default:
|
||||
printf("Unknown write size '%lu'\n", size);
|
||||
return CMD_RET_USAGE;
|
||||
};
|
||||
|
||||
/* Address is specified since argc > 4 */
|
||||
addr = simple_strtoul(argv[2], NULL, 16);
|
||||
|
||||
/* Get the value to write */
|
||||
writeval = simple_strtoul(argv[3], NULL, 16);
|
||||
|
||||
/* Count ? */
|
||||
if (argc == 5)
|
||||
count = simple_strtoul(argv[4], NULL, 16);
|
||||
else
|
||||
count = 1;
|
||||
|
||||
while (count-- > 0) {
|
||||
int ret = axi_write(axi_cur_bus, addr + count * sizeof(u32),
|
||||
&writeval, axisize);
|
||||
|
||||
if (ret) {
|
||||
printf("axi_write failed: err = %d\n", ret);
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static cmd_tbl_t cmd_axi_sub[] = {
|
||||
U_BOOT_CMD_MKENT(bus, 1, 1, do_axi_show_bus, "", ""),
|
||||
U_BOOT_CMD_MKENT(dev, 1, 1, do_axi_bus_num, "", ""),
|
||||
U_BOOT_CMD_MKENT(md, 4, 1, do_axi_md, "", ""),
|
||||
U_BOOT_CMD_MKENT(mw, 5, 1, do_axi_mw, "", ""),
|
||||
};
|
||||
|
||||
static int do_ihs_axi(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
cmd_tbl_t *c;
|
||||
|
||||
if (argc < 2)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
/* Strip off leading 'axi' command argument */
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
/* Hand off rest of command line to sub-commands */
|
||||
c = find_cmd_tbl(argv[0], &cmd_axi_sub[0], ARRAY_SIZE(cmd_axi_sub));
|
||||
|
||||
if (c)
|
||||
return c->cmd(cmdtp, flag, argc, argv);
|
||||
else
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
static char axi_help_text[] =
|
||||
"bus - show AXI bus info\n"
|
||||
"axi dev [bus] - show or set current AXI bus to bus number [bus]\n"
|
||||
"axi md size addr [# of objects] - read from AXI device at address [addr] and data width [size] (one of 8, 16, 32)\n"
|
||||
"axi mw size addr value [count] - write data [value] to AXI device at address [addr] and data width [size] (one of 8, 16, 32)\n";
|
||||
|
||||
U_BOOT_CMD(axi, 7, 1, do_ihs_axi,
|
||||
"AXI sub-system",
|
||||
axi_help_text
|
||||
);
|
||||
338
cmd/bcb.c
Normal file
338
cmd/bcb.c
Normal file
@@ -0,0 +1,338 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2019 Eugeniu Rosca <rosca.eugeniu@gmail.com>
|
||||
*
|
||||
* Command to read/modify/write Android BCB fields
|
||||
*/
|
||||
|
||||
#include <android_bootloader_message.h>
|
||||
#include <command.h>
|
||||
#include <common.h>
|
||||
|
||||
enum bcb_cmd {
|
||||
BCB_CMD_LOAD,
|
||||
BCB_CMD_FIELD_SET,
|
||||
BCB_CMD_FIELD_CLEAR,
|
||||
BCB_CMD_FIELD_TEST,
|
||||
BCB_CMD_FIELD_DUMP,
|
||||
BCB_CMD_STORE,
|
||||
};
|
||||
|
||||
static int bcb_dev = -1;
|
||||
static int bcb_part = -1;
|
||||
static struct bootloader_message bcb = { { 0 } };
|
||||
|
||||
static int bcb_cmd_get(char *cmd)
|
||||
{
|
||||
if (!strcmp(cmd, "load"))
|
||||
return BCB_CMD_LOAD;
|
||||
if (!strcmp(cmd, "set"))
|
||||
return BCB_CMD_FIELD_SET;
|
||||
if (!strcmp(cmd, "clear"))
|
||||
return BCB_CMD_FIELD_CLEAR;
|
||||
if (!strcmp(cmd, "test"))
|
||||
return BCB_CMD_FIELD_TEST;
|
||||
if (!strcmp(cmd, "store"))
|
||||
return BCB_CMD_STORE;
|
||||
if (!strcmp(cmd, "dump"))
|
||||
return BCB_CMD_FIELD_DUMP;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int bcb_is_misused(int argc, char *const argv[])
|
||||
{
|
||||
int cmd = bcb_cmd_get(argv[0]);
|
||||
|
||||
switch (cmd) {
|
||||
case BCB_CMD_LOAD:
|
||||
case BCB_CMD_FIELD_SET:
|
||||
if (argc != 3)
|
||||
goto err;
|
||||
break;
|
||||
case BCB_CMD_FIELD_TEST:
|
||||
if (argc != 4)
|
||||
goto err;
|
||||
break;
|
||||
case BCB_CMD_FIELD_CLEAR:
|
||||
if (argc != 1 && argc != 2)
|
||||
goto err;
|
||||
break;
|
||||
case BCB_CMD_STORE:
|
||||
if (argc != 1)
|
||||
goto err;
|
||||
break;
|
||||
case BCB_CMD_FIELD_DUMP:
|
||||
if (argc != 2)
|
||||
goto err;
|
||||
break;
|
||||
default:
|
||||
printf("Error: 'bcb %s' not supported\n", argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (cmd != BCB_CMD_LOAD && (bcb_dev < 0 || bcb_part < 0)) {
|
||||
printf("Error: Please, load BCB first!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err:
|
||||
printf("Error: Bad usage of 'bcb %s'\n", argv[0]);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int bcb_field_get(char *name, char **fieldp, int *sizep)
|
||||
{
|
||||
if (!strcmp(name, "command")) {
|
||||
*fieldp = bcb.command;
|
||||
*sizep = sizeof(bcb.command);
|
||||
} else if (!strcmp(name, "status")) {
|
||||
*fieldp = bcb.status;
|
||||
*sizep = sizeof(bcb.status);
|
||||
} else if (!strcmp(name, "recovery")) {
|
||||
*fieldp = bcb.recovery;
|
||||
*sizep = sizeof(bcb.recovery);
|
||||
} else if (!strcmp(name, "stage")) {
|
||||
*fieldp = bcb.stage;
|
||||
*sizep = sizeof(bcb.stage);
|
||||
} else if (!strcmp(name, "reserved")) {
|
||||
*fieldp = bcb.reserved;
|
||||
*sizep = sizeof(bcb.reserved);
|
||||
} else {
|
||||
printf("Error: Unknown bcb field '%s'\n", name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_bcb_load(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
struct blk_desc *desc;
|
||||
disk_partition_t info;
|
||||
u64 cnt;
|
||||
char *endp;
|
||||
int part, ret;
|
||||
|
||||
ret = blk_get_device_by_str("mmc", argv[1], &desc);
|
||||
if (ret < 0)
|
||||
goto err_read_fail;
|
||||
|
||||
part = simple_strtoul(argv[2], &endp, 0);
|
||||
if (*endp == '\0') {
|
||||
ret = part_get_info(desc, part, &info);
|
||||
if (ret)
|
||||
goto err_read_fail;
|
||||
} else {
|
||||
part = part_get_info_by_name(desc, argv[2], &info);
|
||||
if (part < 0) {
|
||||
ret = part;
|
||||
goto err_read_fail;
|
||||
}
|
||||
}
|
||||
|
||||
cnt = DIV_ROUND_UP(sizeof(struct bootloader_message), info.blksz);
|
||||
if (cnt > info.size)
|
||||
goto err_too_small;
|
||||
|
||||
if (blk_dread(desc, info.start, cnt, &bcb) != cnt) {
|
||||
ret = -EIO;
|
||||
goto err_read_fail;
|
||||
}
|
||||
|
||||
bcb_dev = desc->devnum;
|
||||
bcb_part = part;
|
||||
debug("%s: Loaded from mmc %d:%d\n", __func__, bcb_dev, bcb_part);
|
||||
|
||||
return CMD_RET_SUCCESS;
|
||||
err_read_fail:
|
||||
printf("Error: mmc %s:%s read failed (%d)\n", argv[1], argv[2], ret);
|
||||
goto err;
|
||||
err_too_small:
|
||||
printf("Error: mmc %s:%s too small!", argv[1], argv[2]);
|
||||
goto err;
|
||||
err:
|
||||
bcb_dev = -1;
|
||||
bcb_part = -1;
|
||||
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
static int do_bcb_set(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
int size, len;
|
||||
char *field, *str, *found;
|
||||
|
||||
if (bcb_field_get(argv[1], &field, &size))
|
||||
return CMD_RET_FAILURE;
|
||||
|
||||
len = strlen(argv[2]);
|
||||
if (len >= size) {
|
||||
printf("Error: sizeof('%s') = %d >= %d = sizeof(bcb.%s)\n",
|
||||
argv[2], len, size, argv[1]);
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
str = argv[2];
|
||||
|
||||
field[0] = '\0';
|
||||
while ((found = strsep(&str, ":"))) {
|
||||
if (field[0] != '\0')
|
||||
strcat(field, "\n");
|
||||
strcat(field, found);
|
||||
}
|
||||
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
static int do_bcb_clear(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
int size;
|
||||
char *field;
|
||||
|
||||
if (argc == 1) {
|
||||
memset(&bcb, 0, sizeof(bcb));
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
if (bcb_field_get(argv[1], &field, &size))
|
||||
return CMD_RET_FAILURE;
|
||||
|
||||
memset(field, 0, size);
|
||||
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
static int do_bcb_test(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
int size;
|
||||
char *field;
|
||||
char *op = argv[2];
|
||||
|
||||
if (bcb_field_get(argv[1], &field, &size))
|
||||
return CMD_RET_FAILURE;
|
||||
|
||||
if (*op == '=' && *(op + 1) == '\0') {
|
||||
if (!strncmp(argv[3], field, size))
|
||||
return CMD_RET_SUCCESS;
|
||||
else
|
||||
return CMD_RET_FAILURE;
|
||||
} else if (*op == '~' && *(op + 1) == '\0') {
|
||||
if (!strstr(field, argv[3]))
|
||||
return CMD_RET_FAILURE;
|
||||
else
|
||||
return CMD_RET_SUCCESS;
|
||||
} else {
|
||||
printf("Error: Unknown operator '%s'\n", op);
|
||||
}
|
||||
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
static int do_bcb_dump(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
int size;
|
||||
char *field;
|
||||
|
||||
if (bcb_field_get(argv[1], &field, &size))
|
||||
return CMD_RET_FAILURE;
|
||||
|
||||
print_buffer((ulong)field - (ulong)&bcb, (void *)field, 1, size, 16);
|
||||
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
static int do_bcb_store(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
struct blk_desc *desc;
|
||||
disk_partition_t info;
|
||||
u64 cnt;
|
||||
int ret;
|
||||
|
||||
desc = blk_get_devnum_by_type(IF_TYPE_MMC, bcb_dev);
|
||||
if (!desc) {
|
||||
ret = -ENODEV;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = part_get_info(desc, bcb_part, &info);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
cnt = DIV_ROUND_UP(sizeof(struct bootloader_message), info.blksz);
|
||||
|
||||
if (blk_dwrite(desc, info.start, cnt, &bcb) != cnt) {
|
||||
ret = -EIO;
|
||||
goto err;
|
||||
}
|
||||
|
||||
return CMD_RET_SUCCESS;
|
||||
err:
|
||||
printf("Error: mmc %d:%d write failed (%d)\n", bcb_dev, bcb_part, ret);
|
||||
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
static cmd_tbl_t cmd_bcb_sub[] = {
|
||||
U_BOOT_CMD_MKENT(load, CONFIG_SYS_MAXARGS, 1, do_bcb_load, "", ""),
|
||||
U_BOOT_CMD_MKENT(set, CONFIG_SYS_MAXARGS, 1, do_bcb_set, "", ""),
|
||||
U_BOOT_CMD_MKENT(clear, CONFIG_SYS_MAXARGS, 1, do_bcb_clear, "", ""),
|
||||
U_BOOT_CMD_MKENT(test, CONFIG_SYS_MAXARGS, 1, do_bcb_test, "", ""),
|
||||
U_BOOT_CMD_MKENT(dump, CONFIG_SYS_MAXARGS, 1, do_bcb_dump, "", ""),
|
||||
U_BOOT_CMD_MKENT(store, CONFIG_SYS_MAXARGS, 1, do_bcb_store, "", ""),
|
||||
};
|
||||
|
||||
static int do_bcb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
|
||||
{
|
||||
cmd_tbl_t *c;
|
||||
|
||||
if (argc < 2)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
c = find_cmd_tbl(argv[0], cmd_bcb_sub, ARRAY_SIZE(cmd_bcb_sub));
|
||||
if (!c)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
if (bcb_is_misused(argc, argv)) {
|
||||
/*
|
||||
* We try to improve the user experience by reporting the
|
||||
* root-cause of misusage, so don't return CMD_RET_USAGE,
|
||||
* since the latter prints out the full-blown help text
|
||||
*/
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
return c->cmd(cmdtp, flag, argc, argv);
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
bcb, CONFIG_SYS_MAXARGS, 1, do_bcb,
|
||||
"Load/set/clear/test/dump/store Android BCB fields",
|
||||
"load <dev> <part> - load BCB from mmc <dev>:<part>\n"
|
||||
"bcb set <field> <val> - set BCB <field> to <val>\n"
|
||||
"bcb clear [<field>] - clear BCB <field> or all fields\n"
|
||||
"bcb test <field> <op> <val> - test BCB <field> against <val>\n"
|
||||
"bcb dump <field> - dump BCB <field>\n"
|
||||
"bcb store - store BCB back to mmc\n"
|
||||
"\n"
|
||||
"Legend:\n"
|
||||
"<dev> - MMC device index containing the BCB partition\n"
|
||||
"<part> - MMC partition index or name containing the BCB\n"
|
||||
"<field> - one of {command,status,recovery,stage,reserved}\n"
|
||||
"<op> - the binary operator used in 'bcb test':\n"
|
||||
" '=' returns true if <val> matches the string stored in <field>\n"
|
||||
" '~' returns true if <val> matches a subset of <field>'s string\n"
|
||||
"<val> - string/text provided as input to bcb {set,test}\n"
|
||||
" NOTE: any ':' character in <val> will be replaced by line feed\n"
|
||||
" during 'bcb set' and used as separator by upper layers\n"
|
||||
);
|
||||
478
cmd/bdinfo.c
Normal file
478
cmd/bdinfo.c
Normal file
@@ -0,0 +1,478 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2003
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Boot support
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <env.h>
|
||||
#include <vsprintf.h>
|
||||
#include <linux/compiler.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
__maybe_unused
|
||||
static void print_num(const char *name, ulong value)
|
||||
{
|
||||
printf("%-12s= 0x%0*lx\n", name, 2 * (int)sizeof(value), value);
|
||||
}
|
||||
|
||||
__maybe_unused
|
||||
static void print_eth(int idx)
|
||||
{
|
||||
char name[10], *val;
|
||||
if (idx)
|
||||
sprintf(name, "eth%iaddr", idx);
|
||||
else
|
||||
strcpy(name, "ethaddr");
|
||||
val = env_get(name);
|
||||
if (!val)
|
||||
val = "(not set)";
|
||||
printf("%-12s= %s\n", name, val);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_DM_ETH
|
||||
__maybe_unused
|
||||
static void print_eths(void)
|
||||
{
|
||||
struct eth_device *dev;
|
||||
int i = 0;
|
||||
|
||||
do {
|
||||
dev = eth_get_dev_by_index(i);
|
||||
if (dev) {
|
||||
printf("eth%dname = %s\n", i, dev->name);
|
||||
print_eth(i);
|
||||
i++;
|
||||
}
|
||||
} while (dev);
|
||||
|
||||
printf("current eth = %s\n", eth_get_name());
|
||||
printf("ip_addr = %s\n", env_get("ipaddr"));
|
||||
}
|
||||
#endif
|
||||
|
||||
__maybe_unused
|
||||
static void print_lnum(const char *name, unsigned long long value)
|
||||
{
|
||||
printf("%-12s= 0x%.8llX\n", name, value);
|
||||
}
|
||||
|
||||
__maybe_unused
|
||||
static void print_mhz(const char *name, unsigned long hz)
|
||||
{
|
||||
char buf[32];
|
||||
|
||||
printf("%-12s= %6s MHz\n", name, strmhz(buf, hz));
|
||||
}
|
||||
|
||||
|
||||
static inline void print_bi_boot_params(const bd_t *bd)
|
||||
{
|
||||
print_num("boot_params", (ulong)bd->bi_boot_params);
|
||||
}
|
||||
|
||||
static inline void print_bi_mem(const bd_t *bd)
|
||||
{
|
||||
#if defined(CONFIG_SH)
|
||||
print_num("mem start ", (ulong)bd->bi_memstart);
|
||||
print_lnum("mem size ", (u64)bd->bi_memsize);
|
||||
#elif defined(CONFIG_ARC)
|
||||
print_num("mem start", (ulong)bd->bi_memstart);
|
||||
print_lnum("mem size", (u64)bd->bi_memsize);
|
||||
#else
|
||||
print_num("memstart", (ulong)bd->bi_memstart);
|
||||
print_lnum("memsize", (u64)bd->bi_memsize);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void print_bi_dram(const bd_t *bd)
|
||||
{
|
||||
#ifdef CONFIG_NR_DRAM_BANKS
|
||||
int i;
|
||||
|
||||
for (i = 0; i < CONFIG_NR_DRAM_BANKS; ++i) {
|
||||
if (bd->bi_dram[i].size) {
|
||||
print_num("DRAM bank", i);
|
||||
print_num("-> start", bd->bi_dram[i].start);
|
||||
print_num("-> size", bd->bi_dram[i].size);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void print_bi_flash(const bd_t *bd)
|
||||
{
|
||||
#if defined(CONFIG_MICROBLAZE) || defined(CONFIG_SH)
|
||||
print_num("flash start ", (ulong)bd->bi_flashstart);
|
||||
print_num("flash size ", (ulong)bd->bi_flashsize);
|
||||
print_num("flash offset ", (ulong)bd->bi_flashoffset);
|
||||
|
||||
#elif defined(CONFIG_NIOS2)
|
||||
print_num("flash start", (ulong)bd->bi_flashstart);
|
||||
print_num("flash size", (ulong)bd->bi_flashsize);
|
||||
print_num("flash offset", (ulong)bd->bi_flashoffset);
|
||||
#else
|
||||
print_num("flashstart", (ulong)bd->bi_flashstart);
|
||||
print_num("flashsize", (ulong)bd->bi_flashsize);
|
||||
print_num("flashoffset", (ulong)bd->bi_flashoffset);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void print_eth_ip_addr(void)
|
||||
{
|
||||
#if defined(CONFIG_CMD_NET)
|
||||
print_eth(0);
|
||||
#if defined(CONFIG_HAS_ETH1)
|
||||
print_eth(1);
|
||||
#endif
|
||||
#if defined(CONFIG_HAS_ETH2)
|
||||
print_eth(2);
|
||||
#endif
|
||||
#if defined(CONFIG_HAS_ETH3)
|
||||
print_eth(3);
|
||||
#endif
|
||||
#if defined(CONFIG_HAS_ETH4)
|
||||
print_eth(4);
|
||||
#endif
|
||||
#if defined(CONFIG_HAS_ETH5)
|
||||
print_eth(5);
|
||||
#endif
|
||||
printf("IP addr = %s\n", env_get("ipaddr"));
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void print_baudrate(void)
|
||||
{
|
||||
#if defined(CONFIG_PPC)
|
||||
printf("baudrate = %6u bps\n", gd->baudrate);
|
||||
#else
|
||||
printf("baudrate = %u bps\n", gd->baudrate);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __maybe_unused print_std_bdinfo(const bd_t *bd)
|
||||
{
|
||||
print_bi_boot_params(bd);
|
||||
print_bi_mem(bd);
|
||||
print_bi_flash(bd);
|
||||
print_eth_ip_addr();
|
||||
print_baudrate();
|
||||
}
|
||||
|
||||
#if defined(CONFIG_PPC)
|
||||
void __weak board_detail(void)
|
||||
{
|
||||
/* Please define board_detail() for your platform */
|
||||
}
|
||||
|
||||
int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
bd_t *bd = gd->bd;
|
||||
|
||||
#ifdef DEBUG
|
||||
print_num("bd address", (ulong)bd);
|
||||
#endif
|
||||
print_bi_mem(bd);
|
||||
print_bi_flash(bd);
|
||||
print_num("sramstart", bd->bi_sramstart);
|
||||
print_num("sramsize", bd->bi_sramsize);
|
||||
#if defined(CONFIG_MPC8xx) || defined(CONFIG_E500)
|
||||
print_num("immr_base", bd->bi_immr_base);
|
||||
#endif
|
||||
print_num("bootflags", bd->bi_bootflags);
|
||||
#if defined(CONFIG_CPM2)
|
||||
print_mhz("vco", bd->bi_vco);
|
||||
print_mhz("sccfreq", bd->bi_sccfreq);
|
||||
print_mhz("brgfreq", bd->bi_brgfreq);
|
||||
#endif
|
||||
print_mhz("intfreq", bd->bi_intfreq);
|
||||
#if defined(CONFIG_CPM2)
|
||||
print_mhz("cpmfreq", bd->bi_cpmfreq);
|
||||
#endif
|
||||
print_mhz("busfreq", bd->bi_busfreq);
|
||||
|
||||
#ifdef CONFIG_ENABLE_36BIT_PHYS
|
||||
#ifdef CONFIG_PHYS_64BIT
|
||||
puts("addressing = 36-bit\n");
|
||||
#else
|
||||
puts("addressing = 32-bit\n");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
print_eth_ip_addr();
|
||||
print_baudrate();
|
||||
print_num("relocaddr", gd->relocaddr);
|
||||
board_detail();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined(CONFIG_NIOS2)
|
||||
|
||||
int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
bd_t *bd = gd->bd;
|
||||
|
||||
print_bi_dram(bd);
|
||||
print_bi_flash(bd);
|
||||
|
||||
#if defined(CONFIG_SYS_SRAM_BASE)
|
||||
print_num ("sram start", (ulong)bd->bi_sramstart);
|
||||
print_num ("sram size", (ulong)bd->bi_sramsize);
|
||||
#endif
|
||||
|
||||
print_eth_ip_addr();
|
||||
print_baudrate();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined(CONFIG_MICROBLAZE)
|
||||
|
||||
int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
bd_t *bd = gd->bd;
|
||||
|
||||
print_bi_dram(bd);
|
||||
print_bi_flash(bd);
|
||||
#if defined(CONFIG_SYS_SRAM_BASE)
|
||||
print_num("sram start ", (ulong)bd->bi_sramstart);
|
||||
print_num("sram size ", (ulong)bd->bi_sramsize);
|
||||
#endif
|
||||
#if defined(CONFIG_CMD_NET) && !defined(CONFIG_DM_ETH)
|
||||
print_eths();
|
||||
#endif
|
||||
print_baudrate();
|
||||
print_num("relocaddr", gd->relocaddr);
|
||||
print_num("reloc off", gd->reloc_off);
|
||||
print_num("fdt_blob", (ulong)gd->fdt_blob);
|
||||
print_num("new_fdt", (ulong)gd->new_fdt);
|
||||
print_num("fdt_size", (ulong)gd->fdt_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined(CONFIG_M68K)
|
||||
|
||||
int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
bd_t *bd = gd->bd;
|
||||
|
||||
print_bi_mem(bd);
|
||||
print_bi_flash(bd);
|
||||
#if defined(CONFIG_SYS_INIT_RAM_ADDR)
|
||||
print_num("sramstart", (ulong)bd->bi_sramstart);
|
||||
print_num("sramsize", (ulong)bd->bi_sramsize);
|
||||
#endif
|
||||
#if defined(CONFIG_SYS_MBAR)
|
||||
print_num("mbar", bd->bi_mbar_base);
|
||||
#endif
|
||||
print_mhz("cpufreq", bd->bi_intfreq);
|
||||
print_mhz("busfreq", bd->bi_busfreq);
|
||||
#ifdef CONFIG_PCI
|
||||
print_mhz("pcifreq", bd->bi_pcifreq);
|
||||
#endif
|
||||
#ifdef CONFIG_EXTRA_CLOCK
|
||||
print_mhz("flbfreq", bd->bi_flbfreq);
|
||||
print_mhz("inpfreq", bd->bi_inpfreq);
|
||||
print_mhz("vcofreq", bd->bi_vcofreq);
|
||||
#endif
|
||||
print_eth_ip_addr();
|
||||
print_baudrate();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined(CONFIG_MIPS)
|
||||
|
||||
int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
print_std_bdinfo(gd->bd);
|
||||
print_num("relocaddr", gd->relocaddr);
|
||||
print_num("reloc off", gd->reloc_off);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined(CONFIG_ARM)
|
||||
|
||||
static int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
bd_t *bd = gd->bd;
|
||||
|
||||
print_num("arch_number", bd->bi_arch_number);
|
||||
print_bi_boot_params(bd);
|
||||
print_bi_dram(bd);
|
||||
|
||||
#ifdef CONFIG_SYS_MEM_RESERVE_SECURE
|
||||
if (gd->arch.secure_ram & MEM_RESERVE_SECURE_SECURED) {
|
||||
print_num("Secure ram",
|
||||
gd->arch.secure_ram & MEM_RESERVE_SECURE_ADDR_MASK);
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_RESV_RAM
|
||||
if (gd->arch.resv_ram)
|
||||
print_num("Reserved ram", gd->arch.resv_ram);
|
||||
#endif
|
||||
#if defined(CONFIG_CMD_NET) && !defined(CONFIG_DM_ETH)
|
||||
print_eths();
|
||||
#endif
|
||||
print_baudrate();
|
||||
#if !(CONFIG_IS_ENABLED(SYS_ICACHE_OFF) && CONFIG_IS_ENABLED(SYS_DCACHE_OFF))
|
||||
print_num("TLB addr", gd->arch.tlb_addr);
|
||||
#endif
|
||||
print_num("relocaddr", gd->relocaddr);
|
||||
print_num("reloc off", gd->reloc_off);
|
||||
print_num("irq_sp", gd->irq_sp); /* irq stack pointer */
|
||||
print_num("sp start ", gd->start_addr_sp);
|
||||
#if defined(CONFIG_LCD) || defined(CONFIG_VIDEO) || defined(CONFIG_DM_VIDEO)
|
||||
print_num("FB base ", gd->fb_base);
|
||||
#endif
|
||||
/*
|
||||
* TODO: Currently only support for davinci SOC's is added.
|
||||
* Remove this check once all the board implement this.
|
||||
*/
|
||||
#ifdef CONFIG_CLOCKS
|
||||
printf("ARM frequency = %ld MHz\n", gd->bd->bi_arm_freq);
|
||||
printf("DSP frequency = %ld MHz\n", gd->bd->bi_dsp_freq);
|
||||
printf("DDR frequency = %ld MHz\n", gd->bd->bi_ddr_freq);
|
||||
#endif
|
||||
#ifdef CONFIG_BOARD_TYPES
|
||||
printf("Board Type = %ld\n", gd->board_type);
|
||||
#endif
|
||||
#if CONFIG_VAL(SYS_MALLOC_F_LEN)
|
||||
printf("Early malloc usage: %lx / %x\n", gd->malloc_ptr,
|
||||
CONFIG_VAL(SYS_MALLOC_F_LEN));
|
||||
#endif
|
||||
if (gd->fdt_blob)
|
||||
print_num("fdt_blob", (ulong)gd->fdt_blob);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined(CONFIG_SH)
|
||||
|
||||
int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
bd_t *bd = gd->bd;
|
||||
|
||||
print_bi_mem(bd);
|
||||
print_bi_flash(bd);
|
||||
print_eth_ip_addr();
|
||||
print_baudrate();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined(CONFIG_X86)
|
||||
|
||||
int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
bd_t *bd = gd->bd;
|
||||
|
||||
print_bi_boot_params(bd);
|
||||
|
||||
print_bi_dram(bd);
|
||||
|
||||
print_num("relocaddr", gd->relocaddr);
|
||||
print_num("reloc off", gd->reloc_off);
|
||||
#if defined(CONFIG_CMD_NET)
|
||||
print_eth_ip_addr();
|
||||
print_mhz("ethspeed", bd->bi_ethspeed);
|
||||
#endif
|
||||
print_baudrate();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined(CONFIG_SANDBOX)
|
||||
|
||||
int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
bd_t *bd = gd->bd;
|
||||
|
||||
print_bi_boot_params(bd);
|
||||
print_bi_dram(bd);
|
||||
print_eth_ip_addr();
|
||||
|
||||
#if defined(CONFIG_LCD) || defined(CONFIG_VIDEO)
|
||||
print_num("FB base ", gd->fb_base);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined(CONFIG_NDS32)
|
||||
|
||||
int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
bd_t *bd = gd->bd;
|
||||
|
||||
print_num("arch_number", bd->bi_arch_number);
|
||||
print_bi_boot_params(bd);
|
||||
print_bi_dram(bd);
|
||||
print_eth_ip_addr();
|
||||
print_baudrate();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined(CONFIG_RISCV)
|
||||
|
||||
int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
bd_t *bd = gd->bd;
|
||||
|
||||
print_bi_boot_params(bd);
|
||||
print_bi_dram(bd);
|
||||
print_num("relocaddr", gd->relocaddr);
|
||||
print_num("reloc off", gd->reloc_off);
|
||||
print_eth_ip_addr();
|
||||
print_baudrate();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined(CONFIG_ARC)
|
||||
|
||||
int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
bd_t *bd = gd->bd;
|
||||
|
||||
print_bi_mem(bd);
|
||||
print_eth_ip_addr();
|
||||
print_baudrate();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined(CONFIG_XTENSA)
|
||||
|
||||
int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
print_std_bdinfo(gd->bd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined(CONFIG_CSKY)
|
||||
|
||||
int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
print_std_bdinfo(gd->bd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
#error "a case for this architecture does not exist!"
|
||||
#endif
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
U_BOOT_CMD(
|
||||
bdinfo, 1, 1, do_bdinfo,
|
||||
"print Board Info structure",
|
||||
""
|
||||
);
|
||||
404
cmd/bedbug.c
Normal file
404
cmd/bedbug.c
Normal file
@@ -0,0 +1,404 @@
|
||||
/*
|
||||
* BedBug Functions
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <cli.h>
|
||||
#include <command.h>
|
||||
#include <console.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <net.h>
|
||||
#include <bedbug/type.h>
|
||||
#include <bedbug/bedbug.h>
|
||||
#include <bedbug/regs.h>
|
||||
#include <bedbug/ppc.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
extern void show_regs __P ((struct pt_regs *));
|
||||
extern int run_command __P ((const char *, int));
|
||||
|
||||
ulong dis_last_addr = 0; /* Last address disassembled */
|
||||
ulong dis_last_len = 20; /* Default disassembler length */
|
||||
CPU_DEBUG_CTX bug_ctx; /* Bedbug context structure */
|
||||
|
||||
|
||||
/* ======================================================================
|
||||
* U-Boot's puts function does not append a newline, so the bedbug stuff
|
||||
* will use this for the output of the dis/assembler.
|
||||
* ====================================================================== */
|
||||
|
||||
int bedbug_puts (const char *str)
|
||||
{
|
||||
/* -------------------------------------------------- */
|
||||
|
||||
printf ("%s\r\n", str);
|
||||
return 0;
|
||||
} /* bedbug_puts */
|
||||
|
||||
|
||||
|
||||
/* ======================================================================
|
||||
* Initialize the bug_ctx structure used by the bedbug debugger. This is
|
||||
* specific to the CPU since each has different debug registers and
|
||||
* settings.
|
||||
* ====================================================================== */
|
||||
|
||||
void bedbug_init (void)
|
||||
{
|
||||
/* -------------------------------------------------- */
|
||||
return;
|
||||
} /* bedbug_init */
|
||||
|
||||
|
||||
|
||||
/* ======================================================================
|
||||
* Entry point from the interpreter to the disassembler. Repeated calls
|
||||
* will resume from the last disassembled address.
|
||||
* ====================================================================== */
|
||||
int do_bedbug_dis (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
ulong addr; /* Address to start disassembly from */
|
||||
ulong len; /* # of instructions to disassemble */
|
||||
|
||||
/* -------------------------------------------------- */
|
||||
|
||||
/* Setup to go from the last address if none is given */
|
||||
addr = dis_last_addr;
|
||||
len = dis_last_len;
|
||||
|
||||
if (argc < 2)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
if ((flag & CMD_FLAG_REPEAT) == 0) {
|
||||
/* New command */
|
||||
addr = simple_strtoul (argv[1], NULL, 16);
|
||||
|
||||
/* If an extra param is given then it is the length */
|
||||
if (argc > 2)
|
||||
len = simple_strtoul (argv[2], NULL, 16);
|
||||
}
|
||||
|
||||
/* Run the disassembler */
|
||||
disppc ((unsigned char *) addr, 0, len, bedbug_puts, F_RADHEX);
|
||||
|
||||
dis_last_addr = addr + (len * 4);
|
||||
dis_last_len = len;
|
||||
return 0;
|
||||
} /* do_bedbug_dis */
|
||||
|
||||
U_BOOT_CMD (ds, 3, 1, do_bedbug_dis,
|
||||
"disassemble memory",
|
||||
"ds <address> [# instructions]");
|
||||
|
||||
/* ======================================================================
|
||||
* Entry point from the interpreter to the assembler. Assembles
|
||||
* instructions in consecutive memory locations until a '.' (period) is
|
||||
* entered on a line by itself.
|
||||
* ====================================================================== */
|
||||
int do_bedbug_asm (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
long mem_addr; /* Address to assemble into */
|
||||
unsigned long instr; /* Machine code for text */
|
||||
char prompt[15]; /* Prompt string for user input */
|
||||
int asm_err; /* Error code from the assembler */
|
||||
|
||||
/* -------------------------------------------------- */
|
||||
int rcode = 0;
|
||||
|
||||
if (argc < 2)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
printf ("\nEnter '.' when done\n");
|
||||
mem_addr = simple_strtoul (argv[1], NULL, 16);
|
||||
|
||||
while (1) {
|
||||
putc ('\n');
|
||||
disppc ((unsigned char *) mem_addr, 0, 1, bedbug_puts,
|
||||
F_RADHEX);
|
||||
|
||||
sprintf (prompt, "%08lx: ", mem_addr);
|
||||
cli_readline(prompt);
|
||||
|
||||
if (console_buffer[0] && strcmp (console_buffer, ".")) {
|
||||
if ((instr =
|
||||
asmppc (mem_addr, console_buffer,
|
||||
&asm_err)) != 0) {
|
||||
*(unsigned long *) mem_addr = instr;
|
||||
mem_addr += 4;
|
||||
} else {
|
||||
printf ("*** Error: %s ***\n",
|
||||
asm_error_str (asm_err));
|
||||
rcode = 1;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return rcode;
|
||||
} /* do_bedbug_asm */
|
||||
|
||||
U_BOOT_CMD (as, 2, 0, do_bedbug_asm,
|
||||
"assemble memory", "as <address>");
|
||||
|
||||
/* ======================================================================
|
||||
* Used to set a break point from the interpreter. Simply calls into the
|
||||
* CPU-specific break point set routine.
|
||||
* ====================================================================== */
|
||||
|
||||
int do_bedbug_break (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
/* -------------------------------------------------- */
|
||||
if (bug_ctx.do_break)
|
||||
(*bug_ctx.do_break) (cmdtp, flag, argc, argv);
|
||||
return 0;
|
||||
|
||||
} /* do_bedbug_break */
|
||||
|
||||
U_BOOT_CMD (break, 3, 0, do_bedbug_break,
|
||||
"set or clear a breakpoint",
|
||||
" - Set or clear a breakpoint\n"
|
||||
"break <address> - Break at an address\n"
|
||||
"break off <bp#> - Disable breakpoint.\n"
|
||||
"break show - List breakpoints.");
|
||||
|
||||
/* ======================================================================
|
||||
* Called from the debug interrupt routine. Simply calls the CPU-specific
|
||||
* breakpoint handling routine.
|
||||
* ====================================================================== */
|
||||
|
||||
void do_bedbug_breakpoint (struct pt_regs *regs)
|
||||
{
|
||||
/* -------------------------------------------------- */
|
||||
|
||||
if (bug_ctx.break_isr)
|
||||
(*bug_ctx.break_isr) (regs);
|
||||
|
||||
return;
|
||||
} /* do_bedbug_breakpoint */
|
||||
|
||||
|
||||
|
||||
/* ======================================================================
|
||||
* Called from the CPU-specific breakpoint handling routine. Enter a
|
||||
* mini main loop until the stopped flag is cleared from the breakpoint
|
||||
* context.
|
||||
*
|
||||
* This handles the parts of the debugger that are common to all CPU's.
|
||||
* ====================================================================== */
|
||||
|
||||
void bedbug_main_loop (unsigned long addr, struct pt_regs *regs)
|
||||
{
|
||||
int len; /* Length of command line */
|
||||
int flag; /* Command flags */
|
||||
int rc = 0; /* Result from run_command */
|
||||
char prompt_str[20]; /* Prompt string */
|
||||
static char lastcommand[CONFIG_SYS_CBSIZE] = { 0 }; /* previous command */
|
||||
/* -------------------------------------------------- */
|
||||
|
||||
if (bug_ctx.clear)
|
||||
(*bug_ctx.clear) (bug_ctx.current_bp);
|
||||
|
||||
printf ("Breakpoint %d: ", bug_ctx.current_bp);
|
||||
disppc ((unsigned char *) addr, 0, 1, bedbug_puts, F_RADHEX);
|
||||
|
||||
bug_ctx.stopped = 1;
|
||||
bug_ctx.regs = regs;
|
||||
|
||||
sprintf (prompt_str, "BEDBUG.%d =>", bug_ctx.current_bp);
|
||||
|
||||
/* A miniature main loop */
|
||||
while (bug_ctx.stopped) {
|
||||
len = cli_readline(prompt_str);
|
||||
|
||||
flag = 0; /* assume no special flags for now */
|
||||
|
||||
if (len > 0)
|
||||
strcpy (lastcommand, console_buffer);
|
||||
else if (len == 0)
|
||||
flag |= CMD_FLAG_REPEAT;
|
||||
|
||||
if (len == -1)
|
||||
printf ("<INTERRUPT>\n");
|
||||
else
|
||||
rc = run_command_repeatable(lastcommand, flag);
|
||||
|
||||
if (rc <= 0) {
|
||||
/* invalid command or not repeatable, forget it */
|
||||
lastcommand[0] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bug_ctx.regs = NULL;
|
||||
bug_ctx.current_bp = 0;
|
||||
|
||||
return;
|
||||
} /* bedbug_main_loop */
|
||||
|
||||
|
||||
|
||||
/* ======================================================================
|
||||
* Interpreter command to continue from a breakpoint. Just clears the
|
||||
* stopped flag in the context so that the breakpoint routine will
|
||||
* return.
|
||||
* ====================================================================== */
|
||||
int do_bedbug_continue (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
/* -------------------------------------------------- */
|
||||
|
||||
if (!bug_ctx.stopped) {
|
||||
printf ("Not at a breakpoint\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
bug_ctx.stopped = 0;
|
||||
return 0;
|
||||
} /* do_bedbug_continue */
|
||||
|
||||
U_BOOT_CMD (continue, 1, 0, do_bedbug_continue,
|
||||
"continue from a breakpoint",
|
||||
"");
|
||||
|
||||
/* ======================================================================
|
||||
* Interpreter command to continue to the next instruction, stepping into
|
||||
* subroutines. Works by calling the find_next_addr() routine to compute
|
||||
* the address passes control to the CPU-specific set breakpoint routine
|
||||
* for the current breakpoint number.
|
||||
* ====================================================================== */
|
||||
int do_bedbug_step (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
unsigned long addr; /* Address to stop at */
|
||||
|
||||
/* -------------------------------------------------- */
|
||||
|
||||
if (!bug_ctx.stopped) {
|
||||
printf ("Not at a breakpoint\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!find_next_address((unsigned char *) &addr, false, bug_ctx.regs))
|
||||
return 1;
|
||||
|
||||
if (bug_ctx.set)
|
||||
(*bug_ctx.set) (bug_ctx.current_bp, addr);
|
||||
|
||||
bug_ctx.stopped = 0;
|
||||
return 0;
|
||||
} /* do_bedbug_step */
|
||||
|
||||
U_BOOT_CMD (step, 1, 1, do_bedbug_step,
|
||||
"single step execution.",
|
||||
"");
|
||||
|
||||
/* ======================================================================
|
||||
* Interpreter command to continue to the next instruction, stepping over
|
||||
* subroutines. Works by calling the find_next_addr() routine to compute
|
||||
* the address passes control to the CPU-specific set breakpoint routine
|
||||
* for the current breakpoint number.
|
||||
* ====================================================================== */
|
||||
int do_bedbug_next (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
unsigned long addr; /* Address to stop at */
|
||||
|
||||
/* -------------------------------------------------- */
|
||||
|
||||
if (!bug_ctx.stopped) {
|
||||
printf ("Not at a breakpoint\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!find_next_address((unsigned char *) &addr, true, bug_ctx.regs))
|
||||
return 1;
|
||||
|
||||
if (bug_ctx.set)
|
||||
(*bug_ctx.set) (bug_ctx.current_bp, addr);
|
||||
|
||||
bug_ctx.stopped = 0;
|
||||
return 0;
|
||||
} /* do_bedbug_next */
|
||||
|
||||
U_BOOT_CMD (next, 1, 1, do_bedbug_next,
|
||||
"single step execution, stepping over subroutines.",
|
||||
"");
|
||||
|
||||
/* ======================================================================
|
||||
* Interpreter command to print the current stack. This assumes an EABI
|
||||
* architecture, so it starts with GPR R1 and works back up the stack.
|
||||
* ====================================================================== */
|
||||
int do_bedbug_stack (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
unsigned long sp; /* Stack pointer */
|
||||
unsigned long func; /* LR from stack */
|
||||
int depth; /* Stack iteration level */
|
||||
int skip = 1; /* Flag to skip the first entry */
|
||||
unsigned long top; /* Top of memory address */
|
||||
|
||||
/* -------------------------------------------------- */
|
||||
|
||||
if (!bug_ctx.stopped) {
|
||||
printf ("Not at a breakpoint\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
top = gd->bd->bi_memstart + gd->bd->bi_memsize;
|
||||
depth = 0;
|
||||
|
||||
printf ("Depth PC\n");
|
||||
printf ("----- --------\n");
|
||||
printf ("%5d %08lx\n", depth++, bug_ctx.regs->nip);
|
||||
|
||||
sp = bug_ctx.regs->gpr[1];
|
||||
func = *(unsigned long *) (sp + 4);
|
||||
|
||||
while ((func < top) && (sp < top)) {
|
||||
if (!skip)
|
||||
printf ("%5d %08lx\n", depth++, func);
|
||||
else
|
||||
--skip;
|
||||
|
||||
sp = *(unsigned long *) sp;
|
||||
func = *(unsigned long *) (sp + 4);
|
||||
}
|
||||
return 0;
|
||||
} /* do_bedbug_stack */
|
||||
|
||||
U_BOOT_CMD (where, 1, 1, do_bedbug_stack,
|
||||
"Print the running stack.",
|
||||
"");
|
||||
|
||||
/* ======================================================================
|
||||
* Interpreter command to dump the registers. Calls the CPU-specific
|
||||
* show registers routine.
|
||||
* ====================================================================== */
|
||||
int do_bedbug_rdump (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
/* -------------------------------------------------- */
|
||||
|
||||
if (!bug_ctx.stopped) {
|
||||
printf ("Not at a breakpoint\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
show_regs (bug_ctx.regs);
|
||||
return 0;
|
||||
} /* do_bedbug_rdump */
|
||||
|
||||
U_BOOT_CMD (rdump, 1, 1, do_bedbug_rdump,
|
||||
"Show registers.", "");
|
||||
/* ====================================================================== */
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001 William L. Pitts
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms are freely
|
||||
* permitted provided that the above copyright notice and this
|
||||
* paragraph and the following disclaimer are duplicated in all
|
||||
* such forms.
|
||||
*
|
||||
* This software is provided "AS IS" and without any express or
|
||||
* implied warranties, including, without limitation, the implied
|
||||
* warranties of merchantability and fitness for a particular
|
||||
* purpose.
|
||||
*/
|
||||
255
cmd/bind.c
Normal file
255
cmd/bind.c
Normal file
@@ -0,0 +1,255 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2018 JJ Hiblot <jjhiblot@ti.com>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <dm/device-internal.h>
|
||||
#include <dm/lists.h>
|
||||
#include <dm/uclass-internal.h>
|
||||
|
||||
static int bind_by_class_index(const char *uclass, int index,
|
||||
const char *drv_name)
|
||||
{
|
||||
static enum uclass_id uclass_id;
|
||||
struct udevice *dev;
|
||||
struct udevice *parent;
|
||||
int ret;
|
||||
struct driver *drv;
|
||||
|
||||
drv = lists_driver_lookup_name(drv_name);
|
||||
if (!drv) {
|
||||
printf("Cannot find driver '%s'\n", drv_name);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
uclass_id = uclass_get_by_name(uclass);
|
||||
if (uclass_id == UCLASS_INVALID) {
|
||||
printf("%s is not a valid uclass\n", uclass);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = uclass_find_device(uclass_id, index, &parent);
|
||||
if (!parent || ret) {
|
||||
printf("Cannot find device %d of class %s\n", index, uclass);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = device_bind_with_driver_data(parent, drv, drv->name, 0,
|
||||
ofnode_null(), &dev);
|
||||
if (!dev || ret) {
|
||||
printf("Unable to bind. err:%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int find_dev(const char *uclass, int index, struct udevice **devp)
|
||||
{
|
||||
static enum uclass_id uclass_id;
|
||||
int rc;
|
||||
|
||||
uclass_id = uclass_get_by_name(uclass);
|
||||
if (uclass_id == UCLASS_INVALID) {
|
||||
printf("%s is not a valid uclass\n", uclass);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = uclass_find_device(uclass_id, index, devp);
|
||||
if (!*devp || rc) {
|
||||
printf("Cannot find device %d of class %s\n", index, uclass);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unbind_by_class_index(const char *uclass, int index)
|
||||
{
|
||||
int ret;
|
||||
struct udevice *dev;
|
||||
|
||||
ret = find_dev(uclass, index, &dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = device_remove(dev, DM_REMOVE_NORMAL);
|
||||
if (ret) {
|
||||
printf("Unable to remove. err:%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = device_unbind(dev);
|
||||
if (ret) {
|
||||
printf("Unable to unbind. err:%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unbind_child_by_class_index(const char *uclass, int index,
|
||||
const char *drv_name)
|
||||
{
|
||||
struct udevice *parent;
|
||||
int ret;
|
||||
struct driver *drv;
|
||||
|
||||
drv = lists_driver_lookup_name(drv_name);
|
||||
if (!drv) {
|
||||
printf("Cannot find driver '%s'\n", drv_name);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
ret = find_dev(uclass, index, &parent);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = device_chld_remove(parent, drv, DM_REMOVE_NORMAL);
|
||||
if (ret)
|
||||
printf("Unable to remove all. err:%d\n", ret);
|
||||
|
||||
ret = device_chld_unbind(parent, drv);
|
||||
if (ret)
|
||||
printf("Unable to unbind all. err:%d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bind_by_node_path(const char *path, const char *drv_name)
|
||||
{
|
||||
struct udevice *dev;
|
||||
struct udevice *parent = NULL;
|
||||
int ret;
|
||||
ofnode ofnode;
|
||||
struct driver *drv;
|
||||
|
||||
drv = lists_driver_lookup_name(drv_name);
|
||||
if (!drv) {
|
||||
printf("%s is not a valid driver name\n", drv_name);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
ofnode = ofnode_path(path);
|
||||
if (!ofnode_valid(ofnode)) {
|
||||
printf("%s is not a valid node path\n", path);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
while (ofnode_valid(ofnode)) {
|
||||
if (!device_find_global_by_ofnode(ofnode, &parent))
|
||||
break;
|
||||
ofnode = ofnode_get_parent(ofnode);
|
||||
}
|
||||
|
||||
if (!parent) {
|
||||
printf("Cannot find a parent device for node path %s\n", path);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ofnode = ofnode_path(path);
|
||||
ret = device_bind_with_driver_data(parent, drv, ofnode_get_name(ofnode),
|
||||
0, ofnode, &dev);
|
||||
if (!dev || ret) {
|
||||
printf("Unable to bind. err:%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unbind_by_node_path(const char *path)
|
||||
{
|
||||
struct udevice *dev;
|
||||
int ret;
|
||||
ofnode ofnode;
|
||||
|
||||
ofnode = ofnode_path(path);
|
||||
if (!ofnode_valid(ofnode)) {
|
||||
printf("%s is not a valid node path\n", path);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = device_find_global_by_ofnode(ofnode, &dev);
|
||||
|
||||
if (!dev || ret) {
|
||||
printf("Cannot find a device with path %s\n", path);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = device_remove(dev, DM_REMOVE_NORMAL);
|
||||
if (ret) {
|
||||
printf("Unable to remove. err:%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = device_unbind(dev);
|
||||
if (ret) {
|
||||
printf("Unable to unbind. err:%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_bind_unbind(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
int ret = 0;
|
||||
bool bind;
|
||||
bool by_node;
|
||||
|
||||
if (argc < 2)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
bind = (argv[0][0] == 'b');
|
||||
by_node = (argv[1][0] == '/');
|
||||
|
||||
if (by_node && bind) {
|
||||
if (argc != 3)
|
||||
return CMD_RET_USAGE;
|
||||
ret = bind_by_node_path(argv[1], argv[2]);
|
||||
} else if (by_node && !bind) {
|
||||
if (argc != 2)
|
||||
return CMD_RET_USAGE;
|
||||
ret = unbind_by_node_path(argv[1]);
|
||||
} else if (!by_node && bind) {
|
||||
int index = (argc > 2) ? simple_strtoul(argv[2], NULL, 10) : 0;
|
||||
|
||||
if (argc != 4)
|
||||
return CMD_RET_USAGE;
|
||||
ret = bind_by_class_index(argv[1], index, argv[3]);
|
||||
} else if (!by_node && !bind) {
|
||||
int index = (argc > 2) ? simple_strtoul(argv[2], NULL, 10) : 0;
|
||||
|
||||
if (argc == 3)
|
||||
ret = unbind_by_class_index(argv[1], index);
|
||||
else if (argc == 4)
|
||||
ret = unbind_child_by_class_index(argv[1], index,
|
||||
argv[3]);
|
||||
else
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
return CMD_RET_FAILURE;
|
||||
else
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
bind, 4, 0, do_bind_unbind,
|
||||
"Bind a device to a driver",
|
||||
"<node path> <driver>\n"
|
||||
"bind <class> <index> <driver>\n"
|
||||
);
|
||||
|
||||
U_BOOT_CMD(
|
||||
unbind, 4, 0, do_bind_unbind,
|
||||
"Unbind a device from a driver",
|
||||
"<node path>\n"
|
||||
"unbind <class> <index>\n"
|
||||
"unbind <class> <index> <driver>\n"
|
||||
);
|
||||
153
cmd/binop.c
Normal file
153
cmd/binop.c
Normal file
@@ -0,0 +1,153 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <env.h>
|
||||
#include <hexdump.h>
|
||||
#include <malloc.h>
|
||||
#include <mapmem.h>
|
||||
#include <linux/ctype.h>
|
||||
|
||||
enum {
|
||||
OP_ID_XOR,
|
||||
OP_ID_AND,
|
||||
OP_ID_OR,
|
||||
};
|
||||
|
||||
void write_to_env_var(char *varname, u8 *result, ulong len)
|
||||
{
|
||||
char *str_output;
|
||||
char *str_ptr;
|
||||
int i;
|
||||
|
||||
str_output = malloc(len * 2 + 1);
|
||||
str_ptr = str_output;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
sprintf(str_ptr, "%02x", result[i]);
|
||||
str_ptr += 2;
|
||||
}
|
||||
*str_ptr = '\0';
|
||||
env_set(varname, str_output);
|
||||
|
||||
free(str_output);
|
||||
}
|
||||
|
||||
void read_from_env_var(char *varname, u8 *result)
|
||||
{
|
||||
char *str_value;
|
||||
|
||||
str_value = env_get(varname);
|
||||
if (str_value)
|
||||
hex2bin(result, str_value, strlen(str_value) / 2);
|
||||
else
|
||||
hex2bin(result, varname, strlen(varname) / 2);
|
||||
}
|
||||
|
||||
void read_from_mem(ulong addr, u8 *result, ulong len)
|
||||
{
|
||||
u8 *src;
|
||||
|
||||
src = map_sysmem(addr, len);
|
||||
memcpy(result, src, len);
|
||||
unmap_sysmem(src);
|
||||
}
|
||||
|
||||
void write_to_mem(char *varname, u8 *result, ulong len)
|
||||
{
|
||||
ulong addr;
|
||||
u8 *buf;
|
||||
|
||||
addr = simple_strtoul(varname, NULL, 16);
|
||||
buf = map_sysmem(addr, len);
|
||||
memcpy(buf, result, len);
|
||||
unmap_sysmem(buf);
|
||||
}
|
||||
|
||||
static int do_binop(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
ulong len;
|
||||
u8 *result, *src1, *src2;
|
||||
char *oparg, *lenarg, *src1arg, *src2arg, *destarg;
|
||||
int i, op;
|
||||
|
||||
if (argc < 5)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
oparg = argv[1];
|
||||
lenarg = argv[2];
|
||||
src1arg = argv[3];
|
||||
src2arg = argv[4];
|
||||
|
||||
if (!strcmp(oparg, "xor"))
|
||||
op = OP_ID_XOR;
|
||||
else if (!strcmp(oparg, "or"))
|
||||
op = OP_ID_OR;
|
||||
else if (!strcmp(oparg, "and"))
|
||||
op = OP_ID_AND;
|
||||
else
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
len = simple_strtoul(lenarg, NULL, 10);
|
||||
|
||||
src1 = malloc(len);
|
||||
src2 = malloc(len);
|
||||
|
||||
if (*src1arg == '*')
|
||||
read_from_mem(simple_strtoul(src1arg + 1, NULL, 16), src1, len);
|
||||
else
|
||||
read_from_env_var(src1arg, src1);
|
||||
|
||||
if (*src2arg == '*')
|
||||
read_from_mem(simple_strtoul(src2arg + 1, NULL, 16), src2, len);
|
||||
else
|
||||
read_from_env_var(src2arg, src2);
|
||||
|
||||
result = malloc(len);
|
||||
|
||||
switch (op) {
|
||||
case OP_ID_XOR:
|
||||
for (i = 0; i < len; i++)
|
||||
result[i] = src1[i] ^ src2[i];
|
||||
break;
|
||||
case OP_ID_OR:
|
||||
for (i = 0; i < len; i++)
|
||||
result[i] = src1[i] | src2[i];
|
||||
break;
|
||||
case OP_ID_AND:
|
||||
for (i = 0; i < len; i++)
|
||||
result[i] = src1[i] & src2[i];
|
||||
break;
|
||||
}
|
||||
|
||||
if (argc == 5) {
|
||||
for (i = 0; i < len; i++) {
|
||||
printf("%02x ", result[i]);
|
||||
if (i % 16 == 15)
|
||||
puts("\n");
|
||||
}
|
||||
puts("\n");
|
||||
|
||||
goto exit;
|
||||
}
|
||||
|
||||
destarg = argv[5];
|
||||
|
||||
if (*destarg == '*')
|
||||
write_to_mem(destarg + 1, result, len); /* Skip asterisk */
|
||||
else
|
||||
write_to_env_var(destarg, result, len);
|
||||
exit:
|
||||
free(result);
|
||||
free(src2);
|
||||
free(src1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
binop, 6, 1, do_binop,
|
||||
"compute binary operation",
|
||||
"op count [*]src1 [*]src2 [[*]dest]\n"
|
||||
" - compute binary operation of data at/in src1 and\n src2 (either *memaddr, env var name or hex string)\n and store result in/at dest, where op is one of\n xor, or, and."
|
||||
);
|
||||
97
cmd/blk_common.c
Normal file
97
cmd/blk_common.c
Normal file
@@ -0,0 +1,97 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Handling of common block commands
|
||||
*
|
||||
* Copyright (c) 2017 Google, Inc
|
||||
*
|
||||
* (C) Copyright 2000-2011
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <blk.h>
|
||||
|
||||
int blk_common_cmd(int argc, char * const argv[], enum if_type if_type,
|
||||
int *cur_devnump)
|
||||
{
|
||||
const char *if_name = blk_get_if_type_name(if_type);
|
||||
|
||||
switch (argc) {
|
||||
case 0:
|
||||
case 1:
|
||||
return CMD_RET_USAGE;
|
||||
case 2:
|
||||
if (strncmp(argv[1], "inf", 3) == 0) {
|
||||
blk_list_devices(if_type);
|
||||
return 0;
|
||||
} else if (strncmp(argv[1], "dev", 3) == 0) {
|
||||
if (blk_print_device_num(if_type, *cur_devnump)) {
|
||||
printf("\nno %s devices available\n", if_name);
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
return 0;
|
||||
} else if (strncmp(argv[1], "part", 4) == 0) {
|
||||
if (blk_list_part(if_type))
|
||||
printf("\nno %s devices available\n", if_name);
|
||||
return 0;
|
||||
}
|
||||
return CMD_RET_USAGE;
|
||||
case 3:
|
||||
if (strncmp(argv[1], "dev", 3) == 0) {
|
||||
int dev = (int)simple_strtoul(argv[2], NULL, 10);
|
||||
|
||||
if (!blk_show_device(if_type, dev)) {
|
||||
*cur_devnump = dev;
|
||||
printf("... is now current device\n");
|
||||
} else {
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
return 0;
|
||||
} else if (strncmp(argv[1], "part", 4) == 0) {
|
||||
int dev = (int)simple_strtoul(argv[2], NULL, 10);
|
||||
|
||||
if (blk_print_part_devnum(if_type, dev)) {
|
||||
printf("\n%s device %d not available\n",
|
||||
if_name, dev);
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
default: /* at least 4 args */
|
||||
if (strcmp(argv[1], "read") == 0) {
|
||||
ulong addr = simple_strtoul(argv[2], NULL, 16);
|
||||
lbaint_t blk = simple_strtoul(argv[3], NULL, 16);
|
||||
ulong cnt = simple_strtoul(argv[4], NULL, 16);
|
||||
ulong n;
|
||||
|
||||
printf("\n%s read: device %d block # "LBAFU", count %lu ... ",
|
||||
if_name, *cur_devnump, blk, cnt);
|
||||
|
||||
n = blk_read_devnum(if_type, *cur_devnump, blk, cnt,
|
||||
(ulong *)addr);
|
||||
|
||||
printf("%ld blocks read: %s\n", n,
|
||||
n == cnt ? "OK" : "ERROR");
|
||||
return n == cnt ? 0 : 1;
|
||||
} else if (strcmp(argv[1], "write") == 0) {
|
||||
ulong addr = simple_strtoul(argv[2], NULL, 16);
|
||||
lbaint_t blk = simple_strtoul(argv[3], NULL, 16);
|
||||
ulong cnt = simple_strtoul(argv[4], NULL, 16);
|
||||
ulong n;
|
||||
|
||||
printf("\n%s write: device %d block # "LBAFU", count %lu ... ",
|
||||
if_name, *cur_devnump, blk, cnt);
|
||||
|
||||
n = blk_write_devnum(if_type, *cur_devnump, blk, cnt,
|
||||
(ulong *)addr);
|
||||
|
||||
printf("%ld blocks written: %s\n", n,
|
||||
n == cnt ? "OK" : "ERROR");
|
||||
return n == cnt ? 0 : 1;
|
||||
} else {
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
}
|
||||
}
|
||||
86
cmd/blkcache.c
Normal file
86
cmd/blkcache.c
Normal file
@@ -0,0 +1,86 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) Nelson Integration, LLC 2016
|
||||
* Author: Eric Nelson<eric@nelint.com>
|
||||
*
|
||||
*/
|
||||
#include <config.h>
|
||||
#include <common.h>
|
||||
#include <malloc.h>
|
||||
#include <part.h>
|
||||
|
||||
static int blkc_show(cmd_tbl_t *cmdtp, int flag,
|
||||
int argc, char * const argv[])
|
||||
{
|
||||
struct block_cache_stats stats;
|
||||
blkcache_stats(&stats);
|
||||
|
||||
printf("hits: %u\n"
|
||||
"misses: %u\n"
|
||||
"entries: %u\n"
|
||||
"max blocks/entry: %u\n"
|
||||
"max cache entries: %u\n",
|
||||
stats.hits, stats.misses, stats.entries,
|
||||
stats.max_blocks_per_entry, stats.max_entries);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int blkc_configure(cmd_tbl_t *cmdtp, int flag,
|
||||
int argc, char * const argv[])
|
||||
{
|
||||
unsigned blocks_per_entry, max_entries;
|
||||
if (argc != 3)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
blocks_per_entry = simple_strtoul(argv[1], 0, 0);
|
||||
max_entries = simple_strtoul(argv[2], 0, 0);
|
||||
blkcache_configure(blocks_per_entry, max_entries);
|
||||
printf("changed to max of %u entries of %u blocks each\n",
|
||||
max_entries, blocks_per_entry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static cmd_tbl_t cmd_blkc_sub[] = {
|
||||
U_BOOT_CMD_MKENT(show, 0, 0, blkc_show, "", ""),
|
||||
U_BOOT_CMD_MKENT(configure, 3, 0, blkc_configure, "", ""),
|
||||
};
|
||||
|
||||
static __maybe_unused void blkc_reloc(void)
|
||||
{
|
||||
static int relocated;
|
||||
|
||||
if (!relocated) {
|
||||
fixup_cmdtable(cmd_blkc_sub, ARRAY_SIZE(cmd_blkc_sub));
|
||||
relocated = 1;
|
||||
};
|
||||
}
|
||||
|
||||
static int do_blkcache(cmd_tbl_t *cmdtp, int flag,
|
||||
int argc, char * const argv[])
|
||||
{
|
||||
cmd_tbl_t *c;
|
||||
|
||||
#ifdef CONFIG_NEEDS_MANUAL_RELOC
|
||||
blkc_reloc();
|
||||
#endif
|
||||
if (argc < 2)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
/* Strip off leading argument */
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
c = find_cmd_tbl(argv[0], &cmd_blkc_sub[0], ARRAY_SIZE(cmd_blkc_sub));
|
||||
|
||||
if (!c)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
return c->cmd(cmdtp, flag, argc, argv);
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
blkcache, 4, 0, do_blkcache,
|
||||
"block cache diagnostics and control",
|
||||
"show - show and reset statistics\n"
|
||||
"blkcache configure blocks entries\n"
|
||||
);
|
||||
107
cmd/blob.c
Normal file
107
cmd/blob.c
Normal file
@@ -0,0 +1,107 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
*
|
||||
* Command for encapsulating/decapsulating blob of memory.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <malloc.h>
|
||||
#include <asm/byteorder.h>
|
||||
#include <linux/compiler.h>
|
||||
|
||||
/**
|
||||
* blob_decap() - Decapsulate the data as a blob
|
||||
* @key_mod: - Pointer to key modifier/key
|
||||
* @src: - Address of data to be decapsulated
|
||||
* @dst: - Address of data to be decapsulated
|
||||
* @len: - Size of data to be decapsulated
|
||||
*
|
||||
* Returns zero on success,and negative on error.
|
||||
*/
|
||||
__weak int blob_decap(u8 *key_mod, u8 *src, u8 *dst, u32 len)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* blob_encap() - Encapsulate the data as a blob
|
||||
* @key_mod: - Pointer to key modifier/key
|
||||
* @src: - Address of data to be encapsulated
|
||||
* @dst: - Address of data to be encapsulated
|
||||
* @len: - Size of data to be encapsulated
|
||||
*
|
||||
* Returns zero on success,and negative on error.
|
||||
*/
|
||||
__weak int blob_encap(u8 *key_mod, u8 *src, u8 *dst, u32 len)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* do_blob() - Handle the "blob" command-line command
|
||||
* @cmdtp: Command data struct pointer
|
||||
* @flag: Command flag
|
||||
* @argc: Command-line argument count
|
||||
* @argv: Array of command-line arguments
|
||||
*
|
||||
* Returns zero on success, CMD_RET_USAGE in case of misuse and negative
|
||||
* on error.
|
||||
*/
|
||||
static int do_blob(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
|
||||
{
|
||||
ulong key_addr, src_addr, dst_addr, len;
|
||||
uint8_t *km_ptr, *src_ptr, *dst_ptr;
|
||||
int enc, ret = 0;
|
||||
|
||||
if (argc != 6)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
if (!strncmp(argv[1], "enc", 3))
|
||||
enc = 1;
|
||||
else if (!strncmp(argv[1], "dec", 3))
|
||||
enc = 0;
|
||||
else
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
src_addr = simple_strtoul(argv[2], NULL, 16);
|
||||
dst_addr = simple_strtoul(argv[3], NULL, 16);
|
||||
len = simple_strtoul(argv[4], NULL, 16);
|
||||
key_addr = simple_strtoul(argv[5], NULL, 16);
|
||||
|
||||
km_ptr = (uint8_t *)(uintptr_t)key_addr;
|
||||
src_ptr = (uint8_t *)(uintptr_t)src_addr;
|
||||
dst_ptr = (uint8_t *)(uintptr_t)dst_addr;
|
||||
|
||||
if (enc)
|
||||
ret = blob_encap(km_ptr, src_ptr, dst_ptr, len);
|
||||
else
|
||||
ret = blob_decap(km_ptr, src_ptr, dst_ptr, len);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/***************************************************/
|
||||
static char blob_help_text[] =
|
||||
"enc src dst len km - Encapsulate and create blob of data\n"
|
||||
" $len bytes long at address $src and\n"
|
||||
" store the result at address $dst.\n"
|
||||
" $km is the address where the key\n"
|
||||
" modifier is stored.\n"
|
||||
" The modifier is required for generation\n"
|
||||
" /use as key for cryptographic operation.\n"
|
||||
" Key modifier should be 16 byte long.\n"
|
||||
"blob dec src dst len km - Decapsulate the blob of data at address\n"
|
||||
" $src and store result of $len byte at\n"
|
||||
" addr $dst.\n"
|
||||
" $km is the address where the key\n"
|
||||
" modifier is stored.\n"
|
||||
" The modifier is required for generation\n"
|
||||
" /use as key for cryptographic operation.\n"
|
||||
" Key modifier should be 16 byte long.\n";
|
||||
|
||||
U_BOOT_CMD(
|
||||
blob, 6, 1, do_blob,
|
||||
"Blob encapsulation/decryption",
|
||||
blob_help_text
|
||||
);
|
||||
277
cmd/bmp.c
Normal file
277
cmd/bmp.c
Normal file
@@ -0,0 +1,277 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2002
|
||||
* Detlev Zundel, DENX Software Engineering, dzu@denx.de.
|
||||
*/
|
||||
|
||||
/*
|
||||
* BMP handling routines
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <bmp_layout.h>
|
||||
#include <command.h>
|
||||
#include <dm.h>
|
||||
#include <gzip.h>
|
||||
#include <lcd.h>
|
||||
#include <malloc.h>
|
||||
#include <mapmem.h>
|
||||
#include <splash.h>
|
||||
#include <video.h>
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
static int bmp_info (ulong addr);
|
||||
|
||||
/*
|
||||
* Allocate and decompress a BMP image using gunzip().
|
||||
*
|
||||
* Returns a pointer to the decompressed image data. This pointer is
|
||||
* aligned to 32-bit-aligned-address + 2.
|
||||
* See doc/README.displaying-bmps for explanation.
|
||||
*
|
||||
* The allocation address is passed to 'alloc_addr' and must be freed
|
||||
* by the caller after use.
|
||||
*
|
||||
* Returns NULL if decompression failed, or if the decompressed data
|
||||
* didn't contain a valid BMP signature.
|
||||
*/
|
||||
#ifdef CONFIG_VIDEO_BMP_GZIP
|
||||
struct bmp_image *gunzip_bmp(unsigned long addr, unsigned long *lenp,
|
||||
void **alloc_addr)
|
||||
{
|
||||
void *dst;
|
||||
unsigned long len;
|
||||
struct bmp_image *bmp;
|
||||
|
||||
/*
|
||||
* Decompress bmp image
|
||||
*/
|
||||
len = CONFIG_SYS_VIDEO_LOGO_MAX_SIZE;
|
||||
/* allocate extra 3 bytes for 32-bit-aligned-address + 2 alignment */
|
||||
dst = malloc(CONFIG_SYS_VIDEO_LOGO_MAX_SIZE + 3);
|
||||
if (dst == NULL) {
|
||||
puts("Error: malloc in gunzip failed!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bmp = dst;
|
||||
|
||||
/* align to 32-bit-aligned-address + 2 */
|
||||
bmp = (struct bmp_image *)((((uintptr_t)dst + 1) & ~3) + 2);
|
||||
|
||||
if (gunzip(bmp, CONFIG_SYS_VIDEO_LOGO_MAX_SIZE, map_sysmem(addr, 0),
|
||||
&len) != 0) {
|
||||
free(dst);
|
||||
return NULL;
|
||||
}
|
||||
if (len == CONFIG_SYS_VIDEO_LOGO_MAX_SIZE)
|
||||
puts("Image could be truncated"
|
||||
" (increase CONFIG_SYS_VIDEO_LOGO_MAX_SIZE)!\n");
|
||||
|
||||
/*
|
||||
* Check for bmp mark 'BM'
|
||||
*/
|
||||
if (!((bmp->header.signature[0] == 'B') &&
|
||||
(bmp->header.signature[1] == 'M'))) {
|
||||
free(dst);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
debug("Gzipped BMP image detected!\n");
|
||||
|
||||
*alloc_addr = dst;
|
||||
return bmp;
|
||||
}
|
||||
#else
|
||||
struct bmp_image *gunzip_bmp(unsigned long addr, unsigned long *lenp,
|
||||
void **alloc_addr)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int do_bmp_info(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
ulong addr;
|
||||
|
||||
switch (argc) {
|
||||
case 1: /* use load_addr as default address */
|
||||
addr = load_addr;
|
||||
break;
|
||||
case 2: /* use argument */
|
||||
addr = simple_strtoul(argv[1], NULL, 16);
|
||||
break;
|
||||
default:
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
return (bmp_info(addr));
|
||||
}
|
||||
|
||||
static int do_bmp_display(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
ulong addr;
|
||||
int x = 0, y = 0;
|
||||
|
||||
splash_get_pos(&x, &y);
|
||||
|
||||
switch (argc) {
|
||||
case 1: /* use load_addr as default address */
|
||||
addr = load_addr;
|
||||
break;
|
||||
case 2: /* use argument */
|
||||
addr = simple_strtoul(argv[1], NULL, 16);
|
||||
break;
|
||||
case 4:
|
||||
addr = simple_strtoul(argv[1], NULL, 16);
|
||||
if (!strcmp(argv[2], "m"))
|
||||
x = BMP_ALIGN_CENTER;
|
||||
else
|
||||
x = simple_strtoul(argv[2], NULL, 10);
|
||||
if (!strcmp(argv[3], "m"))
|
||||
y = BMP_ALIGN_CENTER;
|
||||
else
|
||||
y = simple_strtoul(argv[3], NULL, 10);
|
||||
break;
|
||||
default:
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
return (bmp_display(addr, x, y));
|
||||
}
|
||||
|
||||
static cmd_tbl_t cmd_bmp_sub[] = {
|
||||
U_BOOT_CMD_MKENT(info, 3, 0, do_bmp_info, "", ""),
|
||||
U_BOOT_CMD_MKENT(display, 5, 0, do_bmp_display, "", ""),
|
||||
};
|
||||
|
||||
#ifdef CONFIG_NEEDS_MANUAL_RELOC
|
||||
void bmp_reloc(void) {
|
||||
fixup_cmdtable(cmd_bmp_sub, ARRAY_SIZE(cmd_bmp_sub));
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Subroutine: do_bmp
|
||||
*
|
||||
* Description: Handler for 'bmp' command..
|
||||
*
|
||||
* Inputs: argv[1] contains the subcommand
|
||||
*
|
||||
* Return: None
|
||||
*
|
||||
*/
|
||||
static int do_bmp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
cmd_tbl_t *c;
|
||||
|
||||
/* Strip off leading 'bmp' command argument */
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
c = find_cmd_tbl(argv[0], &cmd_bmp_sub[0], ARRAY_SIZE(cmd_bmp_sub));
|
||||
|
||||
if (c)
|
||||
return c->cmd(cmdtp, flag, argc, argv);
|
||||
else
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
bmp, 5, 1, do_bmp,
|
||||
"manipulate BMP image data",
|
||||
"info <imageAddr> - display image info\n"
|
||||
"bmp display <imageAddr> [x y] - display image at x,y"
|
||||
);
|
||||
|
||||
/*
|
||||
* Subroutine: bmp_info
|
||||
*
|
||||
* Description: Show information about bmp file in memory
|
||||
*
|
||||
* Inputs: addr address of the bmp file
|
||||
*
|
||||
* Return: None
|
||||
*
|
||||
*/
|
||||
static int bmp_info(ulong addr)
|
||||
{
|
||||
struct bmp_image *bmp = (struct bmp_image *)map_sysmem(addr, 0);
|
||||
void *bmp_alloc_addr = NULL;
|
||||
unsigned long len;
|
||||
|
||||
if (!((bmp->header.signature[0]=='B') &&
|
||||
(bmp->header.signature[1]=='M')))
|
||||
bmp = gunzip_bmp(addr, &len, &bmp_alloc_addr);
|
||||
|
||||
if (bmp == NULL) {
|
||||
printf("There is no valid bmp file at the given address\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("Image size : %d x %d\n", le32_to_cpu(bmp->header.width),
|
||||
le32_to_cpu(bmp->header.height));
|
||||
printf("Bits per pixel: %d\n", le16_to_cpu(bmp->header.bit_count));
|
||||
printf("Compression : %d\n", le32_to_cpu(bmp->header.compression));
|
||||
|
||||
if (bmp_alloc_addr)
|
||||
free(bmp_alloc_addr);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Subroutine: bmp_display
|
||||
*
|
||||
* Description: Display bmp file located in memory
|
||||
*
|
||||
* Inputs: addr address of the bmp file
|
||||
*
|
||||
* Return: None
|
||||
*
|
||||
*/
|
||||
int bmp_display(ulong addr, int x, int y)
|
||||
{
|
||||
#ifdef CONFIG_DM_VIDEO
|
||||
struct udevice *dev;
|
||||
#endif
|
||||
int ret;
|
||||
struct bmp_image *bmp = map_sysmem(addr, 0);
|
||||
void *bmp_alloc_addr = NULL;
|
||||
unsigned long len;
|
||||
|
||||
if (!((bmp->header.signature[0]=='B') &&
|
||||
(bmp->header.signature[1]=='M')))
|
||||
bmp = gunzip_bmp(addr, &len, &bmp_alloc_addr);
|
||||
|
||||
if (!bmp) {
|
||||
printf("There is no valid bmp file at the given address\n");
|
||||
return 1;
|
||||
}
|
||||
addr = map_to_sysmem(bmp);
|
||||
|
||||
#ifdef CONFIG_DM_VIDEO
|
||||
ret = uclass_first_device_err(UCLASS_VIDEO, &dev);
|
||||
if (!ret) {
|
||||
bool align = false;
|
||||
|
||||
if (CONFIG_IS_ENABLED(SPLASH_SCREEN_ALIGN) ||
|
||||
x == BMP_ALIGN_CENTER ||
|
||||
y == BMP_ALIGN_CENTER)
|
||||
align = true;
|
||||
|
||||
ret = video_bmp_display(dev, addr, x, y, align);
|
||||
}
|
||||
#elif defined(CONFIG_LCD)
|
||||
ret = lcd_display_bitmap(addr, x, y);
|
||||
#elif defined(CONFIG_VIDEO)
|
||||
ret = video_display_bitmap(addr, x, y);
|
||||
#else
|
||||
# error bmp_display() requires CONFIG_LCD or CONFIG_VIDEO
|
||||
#endif
|
||||
|
||||
if (bmp_alloc_addr)
|
||||
free(bmp_alloc_addr);
|
||||
|
||||
return ret ? CMD_RET_FAILURE : 0;
|
||||
}
|
||||
78
cmd/boot.c
Normal file
78
cmd/boot.c
Normal file
@@ -0,0 +1,78 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2000-2003
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Misc boot support
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <net.h>
|
||||
|
||||
#ifdef CONFIG_CMD_GO
|
||||
|
||||
/* Allow ports to override the default behavior */
|
||||
__attribute__((weak))
|
||||
unsigned long do_go_exec(ulong (*entry)(int, char * const []), int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
return entry (argc, argv);
|
||||
}
|
||||
|
||||
static int do_go(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
ulong addr, rc;
|
||||
int rcode = 0;
|
||||
|
||||
if (argc < 2)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
addr = simple_strtoul(argv[1], NULL, 16);
|
||||
|
||||
printf ("## Starting application at 0x%08lX ...\n", addr);
|
||||
|
||||
/*
|
||||
* pass address parameter as argv[0] (aka command name),
|
||||
* and all remaining args
|
||||
*/
|
||||
rc = do_go_exec ((void *)addr, argc - 1, argv + 1);
|
||||
if (rc != 0) rcode = 1;
|
||||
|
||||
printf ("## Application terminated, rc = 0x%lX\n", rc);
|
||||
return rcode;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
U_BOOT_CMD(
|
||||
go, CONFIG_SYS_MAXARGS, 1, do_go,
|
||||
"start application at address 'addr'",
|
||||
"addr [arg ...]\n - start application at address 'addr'\n"
|
||||
" passing 'arg' as arguments"
|
||||
);
|
||||
|
||||
#endif
|
||||
|
||||
U_BOOT_CMD(
|
||||
reset, 1, 0, do_reset,
|
||||
"Perform RESET of the CPU",
|
||||
""
|
||||
);
|
||||
|
||||
#ifdef CONFIG_CMD_POWEROFF
|
||||
U_BOOT_CMD(
|
||||
poweroff, 1, 0, do_poweroff,
|
||||
"Perform POWEROFF of the device",
|
||||
""
|
||||
);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CMD_BOOT_SLAVE
|
||||
U_BOOT_CMD(
|
||||
bootslave, CONFIG_SYS_MAXARGS, 0, do_bootslave,
|
||||
"Boot application from memory on the SLAVE CPU",
|
||||
"addr - address of the application"
|
||||
);
|
||||
#endif
|
||||
61
cmd/bootcount.c
Normal file
61
cmd/bootcount.c
Normal file
@@ -0,0 +1,61 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <bootcount.h>
|
||||
|
||||
static int do_bootcount_print(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
printf("%lu\n", bootcount_load());
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
static int do_bootcount_reset(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
/*
|
||||
* note that we're explicitly not resetting the environment
|
||||
* variable, so you still have the old bootcounter available
|
||||
*/
|
||||
bootcount_store(0);
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
static cmd_tbl_t bootcount_sub[] = {
|
||||
U_BOOT_CMD_MKENT(print, 1, 1, do_bootcount_print, "", ""),
|
||||
U_BOOT_CMD_MKENT(reset, 1, 1, do_bootcount_reset, "", ""),
|
||||
};
|
||||
|
||||
static int do_bootcount(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
cmd_tbl_t *cp;
|
||||
|
||||
if (argc < 2)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
/* drop initial "bootcount" arg */
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
cp = find_cmd_tbl(argv[0], bootcount_sub, ARRAY_SIZE(bootcount_sub));
|
||||
if (cp)
|
||||
return cp->cmd(cmdtp, flag, argc, argv);
|
||||
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
#if CONFIG_IS_ENABLED(SYS_LONGHELP)
|
||||
static char bootcount_help_text[] =
|
||||
"print - print current bootcounter\n"
|
||||
"reset - reset the bootcounter"
|
||||
;
|
||||
#endif
|
||||
|
||||
U_BOOT_CMD(bootcount, 2, 1, do_bootcount,
|
||||
"bootcount",
|
||||
#if CONFIG_IS_ENABLED(SYS_LONGHELP)
|
||||
bootcount_help_text
|
||||
#endif
|
||||
);
|
||||
650
cmd/bootefi.c
Normal file
650
cmd/bootefi.c
Normal file
@@ -0,0 +1,650 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* EFI application loader
|
||||
*
|
||||
* Copyright (c) 2016 Alexander Graf
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <charset.h>
|
||||
#include <command.h>
|
||||
#include <dm.h>
|
||||
#include <efi_loader.h>
|
||||
#include <efi_selftest.h>
|
||||
#include <env.h>
|
||||
#include <errno.h>
|
||||
#include <linux/libfdt.h>
|
||||
#include <linux/libfdt_env.h>
|
||||
#include <mapmem.h>
|
||||
#include <memalign.h>
|
||||
#include <asm-generic/sections.h>
|
||||
#include <linux/linkage.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
static struct efi_device_path *bootefi_image_path;
|
||||
static struct efi_device_path *bootefi_device_path;
|
||||
|
||||
/**
|
||||
* Set the load options of an image from an environment variable.
|
||||
*
|
||||
* @handle: the image handle
|
||||
* @env_var: name of the environment variable
|
||||
* Return: status code
|
||||
*/
|
||||
static efi_status_t set_load_options(efi_handle_t handle, const char *env_var)
|
||||
{
|
||||
struct efi_loaded_image *loaded_image_info;
|
||||
size_t size;
|
||||
const char *env = env_get(env_var);
|
||||
u16 *pos;
|
||||
efi_status_t ret;
|
||||
|
||||
ret = EFI_CALL(systab.boottime->open_protocol(
|
||||
handle,
|
||||
&efi_guid_loaded_image,
|
||||
(void **)&loaded_image_info,
|
||||
efi_root, NULL,
|
||||
EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL));
|
||||
if (ret != EFI_SUCCESS)
|
||||
return EFI_INVALID_PARAMETER;
|
||||
|
||||
loaded_image_info->load_options = NULL;
|
||||
loaded_image_info->load_options_size = 0;
|
||||
if (!env)
|
||||
goto out;
|
||||
|
||||
size = utf8_utf16_strlen(env) + 1;
|
||||
loaded_image_info->load_options = calloc(size, sizeof(u16));
|
||||
if (!loaded_image_info->load_options) {
|
||||
printf("ERROR: Out of memory\n");
|
||||
EFI_CALL(systab.boottime->close_protocol(handle,
|
||||
&efi_guid_loaded_image,
|
||||
efi_root, NULL));
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
pos = loaded_image_info->load_options;
|
||||
utf8_utf16_strcpy(&pos, env);
|
||||
loaded_image_info->load_options_size = size * 2;
|
||||
|
||||
out:
|
||||
return EFI_CALL(systab.boottime->close_protocol(handle,
|
||||
&efi_guid_loaded_image,
|
||||
efi_root, NULL));
|
||||
}
|
||||
|
||||
#if !CONFIG_IS_ENABLED(GENERATE_ACPI_TABLE)
|
||||
|
||||
/**
|
||||
* copy_fdt() - Copy the device tree to a new location available to EFI
|
||||
*
|
||||
* The FDT is copied to a suitable location within the EFI memory map.
|
||||
* Additional 12 KiB are added to the space in case the device tree needs to be
|
||||
* expanded later with fdt_open_into().
|
||||
*
|
||||
* @fdtp: On entry a pointer to the flattened device tree.
|
||||
* On exit a pointer to the copy of the flattened device tree.
|
||||
* FDT start
|
||||
* Return: status code
|
||||
*/
|
||||
static efi_status_t copy_fdt(void **fdtp)
|
||||
{
|
||||
unsigned long fdt_ram_start = -1L, fdt_pages;
|
||||
efi_status_t ret = 0;
|
||||
void *fdt, *new_fdt;
|
||||
u64 new_fdt_addr;
|
||||
uint fdt_size;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
|
||||
u64 ram_start = gd->bd->bi_dram[i].start;
|
||||
u64 ram_size = gd->bd->bi_dram[i].size;
|
||||
|
||||
if (!ram_size)
|
||||
continue;
|
||||
|
||||
if (ram_start < fdt_ram_start)
|
||||
fdt_ram_start = ram_start;
|
||||
}
|
||||
|
||||
/*
|
||||
* Give us at least 12 KiB of breathing room in case the device tree
|
||||
* needs to be expanded later.
|
||||
*/
|
||||
fdt = *fdtp;
|
||||
fdt_pages = efi_size_in_pages(fdt_totalsize(fdt) + 0x3000);
|
||||
fdt_size = fdt_pages << EFI_PAGE_SHIFT;
|
||||
|
||||
/*
|
||||
* Safe fdt location is at 127 MiB.
|
||||
* On the sandbox convert from the sandbox address space.
|
||||
*/
|
||||
new_fdt_addr = (uintptr_t)map_sysmem(fdt_ram_start + 0x7f00000 +
|
||||
fdt_size, 0);
|
||||
ret = efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS,
|
||||
EFI_BOOT_SERVICES_DATA, fdt_pages,
|
||||
&new_fdt_addr);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
/* If we can't put it there, put it somewhere */
|
||||
new_fdt_addr = (ulong)memalign(EFI_PAGE_SIZE, fdt_size);
|
||||
ret = efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS,
|
||||
EFI_BOOT_SERVICES_DATA, fdt_pages,
|
||||
&new_fdt_addr);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
printf("ERROR: Failed to reserve space for FDT\n");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
new_fdt = (void *)(uintptr_t)new_fdt_addr;
|
||||
memcpy(new_fdt, fdt, fdt_totalsize(fdt));
|
||||
fdt_set_totalsize(new_fdt, fdt_size);
|
||||
|
||||
*fdtp = (void *)(uintptr_t)new_fdt_addr;
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_carve_out_dt_rsv() - Carve out DT reserved memory ranges
|
||||
*
|
||||
* The mem_rsv entries of the FDT are added to the memory map. Any failures are
|
||||
* ignored because this is not critical and we would rather continue to try to
|
||||
* boot.
|
||||
*
|
||||
* @fdt: Pointer to device tree
|
||||
*/
|
||||
static void efi_carve_out_dt_rsv(void *fdt)
|
||||
{
|
||||
int nr_rsv, i;
|
||||
uint64_t addr, size, pages;
|
||||
|
||||
nr_rsv = fdt_num_mem_rsv(fdt);
|
||||
|
||||
/* Look for an existing entry and add it to the efi mem map. */
|
||||
for (i = 0; i < nr_rsv; i++) {
|
||||
if (fdt_get_mem_rsv(fdt, i, &addr, &size) != 0)
|
||||
continue;
|
||||
|
||||
/* Convert from sandbox address space. */
|
||||
addr = (uintptr_t)map_sysmem(addr, 0);
|
||||
|
||||
pages = efi_size_in_pages(size + (addr & EFI_PAGE_MASK));
|
||||
addr &= ~EFI_PAGE_MASK;
|
||||
if (efi_add_memory_map(addr, pages, EFI_RESERVED_MEMORY_TYPE,
|
||||
false) != EFI_SUCCESS)
|
||||
printf("FDT memrsv map %d: Failed to add to map\n", i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get_config_table() - get configuration table
|
||||
*
|
||||
* @guid: GUID of the configuration table
|
||||
* Return: pointer to configuration table or NULL
|
||||
*/
|
||||
static void *get_config_table(const efi_guid_t *guid)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < systab.nr_tables; i++) {
|
||||
if (!guidcmp(guid, &systab.tables[i].guid))
|
||||
return systab.tables[i].table;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* !CONFIG_IS_ENABLED(GENERATE_ACPI_TABLE) */
|
||||
|
||||
/**
|
||||
* efi_install_fdt() - install fdt passed by a command argument
|
||||
*
|
||||
* If fdt_opt is available, the device tree located at that memory address will
|
||||
* will be installed as configuration table, otherwise the device tree located
|
||||
* at the address indicated by environment variable fdtcontroladdr will be used.
|
||||
*
|
||||
* On architectures (x86) using ACPI tables device trees shall not be installed
|
||||
* as configuration table.
|
||||
*
|
||||
* @fdt_opt: pointer to argument
|
||||
* Return: status code
|
||||
*/
|
||||
static efi_status_t efi_install_fdt(const char *fdt_opt)
|
||||
{
|
||||
/*
|
||||
* The EBBR spec requires that we have either an FDT or an ACPI table
|
||||
* but not both.
|
||||
*/
|
||||
#if CONFIG_IS_ENABLED(GENERATE_ACPI_TABLE)
|
||||
if (fdt_opt) {
|
||||
printf("ERROR: can't have ACPI table and device tree.\n");
|
||||
return EFI_LOAD_ERROR;
|
||||
}
|
||||
#else
|
||||
unsigned long fdt_addr;
|
||||
void *fdt;
|
||||
bootm_headers_t img = { 0 };
|
||||
efi_status_t ret;
|
||||
|
||||
if (fdt_opt) {
|
||||
fdt_addr = simple_strtoul(fdt_opt, NULL, 16);
|
||||
if (!fdt_addr)
|
||||
return EFI_INVALID_PARAMETER;
|
||||
} else {
|
||||
/* Look for device tree that is already installed */
|
||||
if (get_config_table(&efi_guid_fdt))
|
||||
return EFI_SUCCESS;
|
||||
/* Use our own device tree as default */
|
||||
fdt_opt = env_get("fdtcontroladdr");
|
||||
if (!fdt_opt) {
|
||||
printf("ERROR: need device tree\n");
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
fdt_addr = simple_strtoul(fdt_opt, NULL, 16);
|
||||
if (!fdt_addr) {
|
||||
printf("ERROR: invalid $fdtcontroladdr\n");
|
||||
return EFI_LOAD_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* Install device tree */
|
||||
fdt = map_sysmem(fdt_addr, 0);
|
||||
if (fdt_check_header(fdt)) {
|
||||
printf("ERROR: invalid device tree\n");
|
||||
return EFI_LOAD_ERROR;
|
||||
}
|
||||
|
||||
/* Create memory reservations as indicated by the device tree */
|
||||
efi_carve_out_dt_rsv(fdt);
|
||||
|
||||
/* Prepare device tree for payload */
|
||||
ret = copy_fdt(&fdt);
|
||||
if (ret) {
|
||||
printf("ERROR: out of memory\n");
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
if (image_setup_libfdt(&img, fdt, 0, NULL)) {
|
||||
printf("ERROR: failed to process device tree\n");
|
||||
return EFI_LOAD_ERROR;
|
||||
}
|
||||
|
||||
/* Install device tree as UEFI table */
|
||||
ret = efi_install_configuration_table(&efi_guid_fdt, fdt);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
printf("ERROR: failed to install device tree\n");
|
||||
return ret;
|
||||
}
|
||||
#endif /* GENERATE_ACPI_TABLE */
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* do_bootefi_exec() - execute EFI binary
|
||||
*
|
||||
* @handle: handle of loaded image
|
||||
* Return: status code
|
||||
*
|
||||
* Load the EFI binary into a newly assigned memory unwinding the relocation
|
||||
* information, install the loaded image protocol, and call the binary.
|
||||
*/
|
||||
static efi_status_t do_bootefi_exec(efi_handle_t handle)
|
||||
{
|
||||
efi_status_t ret;
|
||||
efi_uintn_t exit_data_size = 0;
|
||||
u16 *exit_data = NULL;
|
||||
|
||||
/* Transfer environment variable as load options */
|
||||
ret = set_load_options(handle, "bootargs");
|
||||
if (ret != EFI_SUCCESS)
|
||||
return ret;
|
||||
|
||||
/* Call our payload! */
|
||||
ret = EFI_CALL(efi_start_image(handle, &exit_data_size, &exit_data));
|
||||
printf("## Application terminated, r = %lu\n", ret & ~EFI_ERROR_MASK);
|
||||
if (ret && exit_data) {
|
||||
printf("## %ls\n", exit_data);
|
||||
efi_free_pool(exit_data);
|
||||
}
|
||||
|
||||
efi_restore_gd();
|
||||
|
||||
/*
|
||||
* FIXME: Who is responsible for
|
||||
* free(loaded_image_info->load_options);
|
||||
* Once efi_exit() is implemented correctly,
|
||||
* handle itself doesn't exist here.
|
||||
*/
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* do_efibootmgr() - execute EFI boot manager
|
||||
*
|
||||
* Return: status code
|
||||
*/
|
||||
static int do_efibootmgr(void)
|
||||
{
|
||||
efi_handle_t handle;
|
||||
efi_status_t ret;
|
||||
|
||||
ret = efi_bootmgr_load(&handle);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
printf("EFI boot manager: Cannot load any image\n");
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
ret = do_bootefi_exec(handle);
|
||||
|
||||
if (ret != EFI_SUCCESS)
|
||||
return CMD_RET_FAILURE;
|
||||
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* do_bootefi_image() - execute EFI binary
|
||||
*
|
||||
* Set up memory image for the binary to be loaded, prepare device path, and
|
||||
* then call do_bootefi_exec() to execute it.
|
||||
*
|
||||
* @image_opt: string of image start address
|
||||
* Return: status code
|
||||
*/
|
||||
static int do_bootefi_image(const char *image_opt)
|
||||
{
|
||||
void *image_buf;
|
||||
struct efi_device_path *device_path, *image_path;
|
||||
struct efi_device_path *file_path = NULL;
|
||||
unsigned long addr, size;
|
||||
const char *size_str;
|
||||
efi_handle_t mem_handle = NULL, handle;
|
||||
efi_status_t ret;
|
||||
|
||||
#ifdef CONFIG_CMD_BOOTEFI_HELLO
|
||||
if (!strcmp(image_opt, "hello")) {
|
||||
char *saddr;
|
||||
|
||||
saddr = env_get("loadaddr");
|
||||
size = __efi_helloworld_end - __efi_helloworld_begin;
|
||||
|
||||
if (saddr)
|
||||
addr = simple_strtoul(saddr, NULL, 16);
|
||||
else
|
||||
addr = CONFIG_SYS_LOAD_ADDR;
|
||||
|
||||
image_buf = map_sysmem(addr, size);
|
||||
memcpy(image_buf, __efi_helloworld_begin, size);
|
||||
|
||||
device_path = NULL;
|
||||
image_path = NULL;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
size_str = env_get("filesize");
|
||||
if (size_str)
|
||||
size = simple_strtoul(size_str, NULL, 16);
|
||||
else
|
||||
size = 0;
|
||||
|
||||
addr = simple_strtoul(image_opt, NULL, 16);
|
||||
/* Check that a numeric value was passed */
|
||||
if (!addr && *image_opt != '0')
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
image_buf = map_sysmem(addr, size);
|
||||
|
||||
device_path = bootefi_device_path;
|
||||
image_path = bootefi_image_path;
|
||||
}
|
||||
|
||||
if (!device_path && !image_path) {
|
||||
/*
|
||||
* Special case for efi payload not loaded from disk,
|
||||
* such as 'bootefi hello' or for example payload
|
||||
* loaded directly into memory via JTAG, etc:
|
||||
*/
|
||||
file_path = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE,
|
||||
(uintptr_t)image_buf, size);
|
||||
/*
|
||||
* Make sure that device for device_path exist
|
||||
* in load_image(). Otherwise, shell and grub will fail.
|
||||
*/
|
||||
ret = efi_create_handle(&mem_handle);
|
||||
if (ret != EFI_SUCCESS)
|
||||
goto out;
|
||||
|
||||
ret = efi_add_protocol(mem_handle, &efi_guid_device_path,
|
||||
file_path);
|
||||
if (ret != EFI_SUCCESS)
|
||||
goto out;
|
||||
} else {
|
||||
assert(device_path && image_path);
|
||||
file_path = efi_dp_append(device_path, image_path);
|
||||
}
|
||||
|
||||
ret = EFI_CALL(efi_load_image(false, efi_root,
|
||||
file_path, image_buf, size, &handle));
|
||||
if (ret != EFI_SUCCESS)
|
||||
goto out;
|
||||
|
||||
ret = do_bootefi_exec(handle);
|
||||
|
||||
out:
|
||||
if (mem_handle)
|
||||
efi_delete_handle(mem_handle);
|
||||
if (file_path)
|
||||
efi_free_pool(file_path);
|
||||
|
||||
if (ret != EFI_SUCCESS)
|
||||
return CMD_RET_FAILURE;
|
||||
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CMD_BOOTEFI_SELFTEST
|
||||
static efi_status_t bootefi_run_prepare(const char *load_options_path,
|
||||
struct efi_device_path *device_path,
|
||||
struct efi_device_path *image_path,
|
||||
struct efi_loaded_image_obj **image_objp,
|
||||
struct efi_loaded_image **loaded_image_infop)
|
||||
{
|
||||
efi_status_t ret;
|
||||
|
||||
ret = efi_setup_loaded_image(device_path, image_path, image_objp,
|
||||
loaded_image_infop);
|
||||
if (ret != EFI_SUCCESS)
|
||||
return ret;
|
||||
|
||||
/* Transfer environment variable as load options */
|
||||
return set_load_options((efi_handle_t)*image_objp, load_options_path);
|
||||
}
|
||||
|
||||
/**
|
||||
* bootefi_test_prepare() - prepare to run an EFI test
|
||||
*
|
||||
* Prepare to run a test as if it were provided by a loaded image.
|
||||
*
|
||||
* @image_objp: pointer to be set to the loaded image handle
|
||||
* @loaded_image_infop: pointer to be set to the loaded image protocol
|
||||
* @path: dummy file path used to construct the device path
|
||||
* set in the loaded image protocol
|
||||
* @load_options_path: name of a U-Boot environment variable. Its value is
|
||||
* set as load options in the loaded image protocol.
|
||||
* Return: status code
|
||||
*/
|
||||
static efi_status_t bootefi_test_prepare
|
||||
(struct efi_loaded_image_obj **image_objp,
|
||||
struct efi_loaded_image **loaded_image_infop, const char *path,
|
||||
const char *load_options_path)
|
||||
{
|
||||
efi_status_t ret;
|
||||
|
||||
/* Construct a dummy device path */
|
||||
bootefi_device_path = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE, 0, 0);
|
||||
if (!bootefi_device_path)
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
|
||||
bootefi_image_path = efi_dp_from_file(NULL, 0, path);
|
||||
if (!bootefi_image_path) {
|
||||
ret = EFI_OUT_OF_RESOURCES;
|
||||
goto failure;
|
||||
}
|
||||
|
||||
ret = bootefi_run_prepare(load_options_path, bootefi_device_path,
|
||||
bootefi_image_path, image_objp,
|
||||
loaded_image_infop);
|
||||
if (ret == EFI_SUCCESS)
|
||||
return ret;
|
||||
|
||||
efi_free_pool(bootefi_image_path);
|
||||
bootefi_image_path = NULL;
|
||||
failure:
|
||||
efi_free_pool(bootefi_device_path);
|
||||
bootefi_device_path = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* bootefi_run_finish() - finish up after running an EFI test
|
||||
*
|
||||
* @loaded_image_info: Pointer to a struct which holds the loaded image info
|
||||
* @image_obj: Pointer to a struct which holds the loaded image object
|
||||
*/
|
||||
static void bootefi_run_finish(struct efi_loaded_image_obj *image_obj,
|
||||
struct efi_loaded_image *loaded_image_info)
|
||||
{
|
||||
efi_restore_gd();
|
||||
free(loaded_image_info->load_options);
|
||||
efi_delete_handle(&image_obj->header);
|
||||
}
|
||||
|
||||
/**
|
||||
* do_efi_selftest() - execute EFI selftest
|
||||
*
|
||||
* Return: status code
|
||||
*/
|
||||
static int do_efi_selftest(void)
|
||||
{
|
||||
struct efi_loaded_image_obj *image_obj;
|
||||
struct efi_loaded_image *loaded_image_info;
|
||||
efi_status_t ret;
|
||||
|
||||
ret = bootefi_test_prepare(&image_obj, &loaded_image_info,
|
||||
"\\selftest", "efi_selftest");
|
||||
if (ret != EFI_SUCCESS)
|
||||
return CMD_RET_FAILURE;
|
||||
|
||||
/* Execute the test */
|
||||
ret = EFI_CALL(efi_selftest(&image_obj->header, &systab));
|
||||
bootefi_run_finish(image_obj, loaded_image_info);
|
||||
|
||||
return ret != EFI_SUCCESS;
|
||||
}
|
||||
#endif /* CONFIG_CMD_BOOTEFI_SELFTEST */
|
||||
|
||||
/**
|
||||
* do_bootefi() - execute `bootefi` command
|
||||
*
|
||||
* @cmdtp: table entry describing command
|
||||
* @flag: bitmap indicating how the command was invoked
|
||||
* @argc: number of arguments
|
||||
* @argv: command line arguments
|
||||
* Return: status code
|
||||
*/
|
||||
static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
efi_status_t ret;
|
||||
|
||||
if (argc < 2)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
/* Initialize EFI drivers */
|
||||
ret = efi_init_obj_list();
|
||||
if (ret != EFI_SUCCESS) {
|
||||
printf("Error: Cannot initialize UEFI sub-system, r = %lu\n",
|
||||
ret & ~EFI_ERROR_MASK);
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
ret = efi_install_fdt(argc > 2 ? argv[2] : NULL);
|
||||
if (ret == EFI_INVALID_PARAMETER)
|
||||
return CMD_RET_USAGE;
|
||||
else if (ret != EFI_SUCCESS)
|
||||
return CMD_RET_FAILURE;
|
||||
|
||||
if (!strcmp(argv[1], "bootmgr"))
|
||||
return do_efibootmgr();
|
||||
#ifdef CONFIG_CMD_BOOTEFI_SELFTEST
|
||||
else if (!strcmp(argv[1], "selftest"))
|
||||
return do_efi_selftest();
|
||||
#endif
|
||||
|
||||
return do_bootefi_image(argv[1]);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SYS_LONGHELP
|
||||
static char bootefi_help_text[] =
|
||||
"<image address> [fdt address]\n"
|
||||
" - boot EFI payload stored at address <image address>.\n"
|
||||
" If specified, the device tree located at <fdt address> gets\n"
|
||||
" exposed as EFI configuration table.\n"
|
||||
#ifdef CONFIG_CMD_BOOTEFI_HELLO
|
||||
"bootefi hello\n"
|
||||
" - boot a sample Hello World application stored within U-Boot\n"
|
||||
#endif
|
||||
#ifdef CONFIG_CMD_BOOTEFI_SELFTEST
|
||||
"bootefi selftest [fdt address]\n"
|
||||
" - boot an EFI selftest application stored within U-Boot\n"
|
||||
" Use environment variable efi_selftest to select a single test.\n"
|
||||
" Use 'setenv efi_selftest list' to enumerate all tests.\n"
|
||||
#endif
|
||||
"bootefi bootmgr [fdt address]\n"
|
||||
" - load and boot EFI payload based on BootOrder/BootXXXX variables.\n"
|
||||
"\n"
|
||||
" If specified, the device tree located at <fdt address> gets\n"
|
||||
" exposed as EFI configuration table.\n";
|
||||
#endif
|
||||
|
||||
U_BOOT_CMD(
|
||||
bootefi, 3, 0, do_bootefi,
|
||||
"Boots an EFI payload from memory",
|
||||
bootefi_help_text
|
||||
);
|
||||
|
||||
/**
|
||||
* efi_set_bootdev() - set boot device
|
||||
*
|
||||
* This function is called when a file is loaded, e.g. via the 'load' command.
|
||||
* We use the path to this file to inform the UEFI binary about the boot device.
|
||||
*
|
||||
* @dev: device, e.g. "MMC"
|
||||
* @devnr: number of the device, e.g. "1:2"
|
||||
* @path: path to file loaded
|
||||
*/
|
||||
void efi_set_bootdev(const char *dev, const char *devnr, const char *path)
|
||||
{
|
||||
struct efi_device_path *device, *image;
|
||||
efi_status_t ret;
|
||||
|
||||
/* efi_set_bootdev is typically called repeatedly, recover memory */
|
||||
efi_free_pool(bootefi_device_path);
|
||||
efi_free_pool(bootefi_image_path);
|
||||
|
||||
ret = efi_dp_from_name(dev, devnr, path, &device, &image);
|
||||
if (ret == EFI_SUCCESS) {
|
||||
bootefi_device_path = device;
|
||||
if (image) {
|
||||
/* FIXME: image should not contain device */
|
||||
struct efi_device_path *image_tmp = image;
|
||||
|
||||
efi_dp_split_file_path(image, &device, &image);
|
||||
efi_free_pool(image_tmp);
|
||||
}
|
||||
bootefi_image_path = image;
|
||||
} else {
|
||||
bootefi_device_path = NULL;
|
||||
bootefi_image_path = NULL;
|
||||
}
|
||||
}
|
||||
160
cmd/booti.c
Normal file
160
cmd/booti.c
Normal file
@@ -0,0 +1,160 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2000-2009
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <bootm.h>
|
||||
#include <command.h>
|
||||
#include <image.h>
|
||||
#include <irq_func.h>
|
||||
#include <lmb.h>
|
||||
#include <mapmem.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sizes.h>
|
||||
|
||||
/*
|
||||
* Image booting support
|
||||
*/
|
||||
static int booti_start(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[], bootm_headers_t *images)
|
||||
{
|
||||
int ret;
|
||||
ulong ld;
|
||||
ulong relocated_addr;
|
||||
ulong image_size;
|
||||
|
||||
ret = do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_START,
|
||||
images, 1);
|
||||
|
||||
/* Setup Linux kernel Image entry point */
|
||||
if (!argc) {
|
||||
ld = load_addr;
|
||||
debug("* kernel: default image load address = 0x%08lx\n",
|
||||
load_addr);
|
||||
} else {
|
||||
ld = simple_strtoul(argv[0], NULL, 16);
|
||||
debug("* kernel: cmdline image address = 0x%08lx\n", ld);
|
||||
}
|
||||
|
||||
ret = booti_setup(ld, &relocated_addr, &image_size, false);
|
||||
if (ret != 0)
|
||||
return 1;
|
||||
|
||||
/* Handle BOOTM_STATE_LOADOS */
|
||||
if (relocated_addr != ld) {
|
||||
debug("Moving Image from 0x%lx to 0x%lx\n", ld, relocated_addr);
|
||||
memmove((void *)relocated_addr, (void *)ld, image_size);
|
||||
}
|
||||
|
||||
images->ep = relocated_addr;
|
||||
images->os.start = relocated_addr;
|
||||
images->os.end = relocated_addr + image_size;
|
||||
|
||||
lmb_reserve(&images->lmb, images->ep, le32_to_cpu(image_size));
|
||||
|
||||
/*
|
||||
* Handle the BOOTM_STATE_FINDOTHER state ourselves as we do not
|
||||
* have a header that provide this informaiton.
|
||||
*/
|
||||
if (bootm_find_images(flag, argc, argv))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int do_booti(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Consume 'booti' */
|
||||
argc--; argv++;
|
||||
|
||||
if (booti_start(cmdtp, flag, argc, argv, &images))
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* We are doing the BOOTM_STATE_LOADOS state ourselves, so must
|
||||
* disable interrupts ourselves
|
||||
*/
|
||||
bootm_disable_interrupts();
|
||||
|
||||
images.os.os = IH_OS_LINUX;
|
||||
#ifdef CONFIG_RISCV_SMODE
|
||||
images.os.arch = IH_ARCH_RISCV;
|
||||
#elif CONFIG_ARM64
|
||||
images.os.arch = IH_ARCH_ARM64;
|
||||
#endif
|
||||
ret = do_bootm_states(cmdtp, flag, argc, argv,
|
||||
#ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH
|
||||
BOOTM_STATE_RAMDISK |
|
||||
#endif
|
||||
BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO |
|
||||
BOOTM_STATE_OS_GO,
|
||||
&images, 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*******************************************************************/
|
||||
/* sboot - boot security image */
|
||||
/*******************************************************************/
|
||||
#ifdef CONFIG_TARGET_LIGHT_C910
|
||||
|
||||
#if CONFIG_IS_ENABLED(LIGHT_SEC_UPGRADE)
|
||||
extern int light_vimage(int argc, char *const argv[]);
|
||||
int do_vimage(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
if (light_vimage(argc, argv) != 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
vimage, CONFIG_SYS_MAXARGS, 1, do_vimage,
|
||||
"verify image file with known pubkey which reside in father image or itself!",
|
||||
"vimage addr imgname[[tee/tf] - verify specifed image resides in addr\n"
|
||||
);
|
||||
|
||||
#endif
|
||||
|
||||
#if CONFIG_IS_ENABLED(LIGHT_SEC_BOOT_WITH_VERIFY_VAL_A) || CONFIG_IS_ENABLED(LIGHT_SEC_BOOT_WITH_VERIFY_VAL_B) || CONFIG_IS_ENABLED(LIGHT_SEC_BOOT_WITH_VERIFY_ANT_EVT)
|
||||
extern int light_secboot(int argc, char * const argv[]);
|
||||
int do_secboot(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
if (light_secboot(argc, argv) != 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
U_BOOT_CMD(
|
||||
secboot, CONFIG_SYS_MAXARGS, 1, do_secboot,
|
||||
"verify image file with known pubkey which reside in father image or itself!",
|
||||
"vimage addr imgname[[tee/tf] - verify specifed image resides in addr\n"
|
||||
);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SYS_LONGHELP
|
||||
static char booti_help_text[] =
|
||||
"[addr [initrd[:size]] [fdt]]\n"
|
||||
" - boot Linux 'Image' stored at 'addr'\n"
|
||||
"\tThe argument 'initrd' is optional and specifies the address\n"
|
||||
"\tof an initrd in memory. The optional parameter ':size' allows\n"
|
||||
"\tspecifying the size of a RAW initrd.\n"
|
||||
#if defined(CONFIG_OF_LIBFDT)
|
||||
"\tSince booting a Linux kernel requires a flat device-tree, a\n"
|
||||
"\tthird argument providing the address of the device-tree blob\n"
|
||||
"\tis required. To boot a kernel with a device-tree blob but\n"
|
||||
"\twithout an initrd image, use a '-' for the initrd argument.\n"
|
||||
#endif
|
||||
"";
|
||||
#endif
|
||||
|
||||
U_BOOT_CMD(
|
||||
booti, CONFIG_SYS_MAXARGS, 1, do_booti,
|
||||
"boot Linux kernel 'Image' format from memory", booti_help_text
|
||||
);
|
||||
548
cmd/bootm.c
Normal file
548
cmd/bootm.c
Normal file
@@ -0,0 +1,548 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2000-2009
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Boot support
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <bootm.h>
|
||||
#include <command.h>
|
||||
#include <env.h>
|
||||
#include <errno.h>
|
||||
#include <image.h>
|
||||
#include <malloc.h>
|
||||
#include <nand.h>
|
||||
#include <asm/byteorder.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/err.h>
|
||||
#include <u-boot/zlib.h>
|
||||
#include <mapmem.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#if defined(CONFIG_CMD_IMI)
|
||||
static int image_info(unsigned long addr);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_CMD_IMLS)
|
||||
#include <flash.h>
|
||||
#include <mtd/cfi_flash.h>
|
||||
extern flash_info_t flash_info[]; /* info for FLASH chips */
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_CMD_IMLS) || defined(CONFIG_CMD_IMLS_NAND)
|
||||
static int do_imls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
|
||||
#endif
|
||||
|
||||
/* we overload the cmd field with our state machine info instead of a
|
||||
* function pointer */
|
||||
static cmd_tbl_t cmd_bootm_sub[] = {
|
||||
U_BOOT_CMD_MKENT(start, 0, 1, (void *)BOOTM_STATE_START, "", ""),
|
||||
U_BOOT_CMD_MKENT(loados, 0, 1, (void *)BOOTM_STATE_LOADOS, "", ""),
|
||||
#ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH
|
||||
U_BOOT_CMD_MKENT(ramdisk, 0, 1, (void *)BOOTM_STATE_RAMDISK, "", ""),
|
||||
#endif
|
||||
#ifdef CONFIG_OF_LIBFDT
|
||||
U_BOOT_CMD_MKENT(fdt, 0, 1, (void *)BOOTM_STATE_FDT, "", ""),
|
||||
#endif
|
||||
U_BOOT_CMD_MKENT(cmdline, 0, 1, (void *)BOOTM_STATE_OS_CMDLINE, "", ""),
|
||||
U_BOOT_CMD_MKENT(bdt, 0, 1, (void *)BOOTM_STATE_OS_BD_T, "", ""),
|
||||
U_BOOT_CMD_MKENT(prep, 0, 1, (void *)BOOTM_STATE_OS_PREP, "", ""),
|
||||
U_BOOT_CMD_MKENT(fake, 0, 1, (void *)BOOTM_STATE_OS_FAKE_GO, "", ""),
|
||||
U_BOOT_CMD_MKENT(go, 0, 1, (void *)BOOTM_STATE_OS_GO, "", ""),
|
||||
};
|
||||
|
||||
static int do_bootm_subcommand(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
int ret = 0;
|
||||
long state;
|
||||
cmd_tbl_t *c;
|
||||
|
||||
c = find_cmd_tbl(argv[0], &cmd_bootm_sub[0], ARRAY_SIZE(cmd_bootm_sub));
|
||||
argc--; argv++;
|
||||
|
||||
if (c) {
|
||||
state = (long)c->cmd;
|
||||
if (state == BOOTM_STATE_START)
|
||||
state |= BOOTM_STATE_FINDOS | BOOTM_STATE_FINDOTHER;
|
||||
} else {
|
||||
/* Unrecognized command */
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
if (((state & BOOTM_STATE_START) != BOOTM_STATE_START) &&
|
||||
images.state >= state) {
|
||||
printf("Trying to execute a command out of order\n");
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
ret = do_bootm_states(cmdtp, flag, argc, argv, state, &images, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*******************************************************************/
|
||||
/* bootm - boot application image from image in memory */
|
||||
/*******************************************************************/
|
||||
int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
#ifdef CONFIG_NEEDS_MANUAL_RELOC
|
||||
static int relocated = 0;
|
||||
|
||||
if (!relocated) {
|
||||
int i;
|
||||
|
||||
/* relocate names of sub-command table */
|
||||
for (i = 0; i < ARRAY_SIZE(cmd_bootm_sub); i++)
|
||||
cmd_bootm_sub[i].name += gd->reloc_off;
|
||||
|
||||
relocated = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* determine if we have a sub command */
|
||||
argc--; argv++;
|
||||
if (argc > 0) {
|
||||
char *endp;
|
||||
|
||||
simple_strtoul(argv[0], &endp, 16);
|
||||
/* endp pointing to NULL means that argv[0] was just a
|
||||
* valid number, pass it along to the normal bootm processing
|
||||
*
|
||||
* If endp is ':' or '#' assume a FIT identifier so pass
|
||||
* along for normal processing.
|
||||
*
|
||||
* Right now we assume the first arg should never be '-'
|
||||
*/
|
||||
if ((*endp != 0) && (*endp != ':') && (*endp != '#'))
|
||||
return do_bootm_subcommand(cmdtp, flag, argc, argv);
|
||||
}
|
||||
|
||||
return do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_START |
|
||||
BOOTM_STATE_FINDOS | BOOTM_STATE_FINDOTHER |
|
||||
BOOTM_STATE_LOADOS |
|
||||
#ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH
|
||||
BOOTM_STATE_RAMDISK |
|
||||
#endif
|
||||
#if defined(CONFIG_PPC) || defined(CONFIG_MIPS)
|
||||
BOOTM_STATE_OS_CMDLINE |
|
||||
#endif
|
||||
BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO |
|
||||
BOOTM_STATE_OS_GO, &images, 1);
|
||||
}
|
||||
|
||||
int bootm_maybe_autostart(cmd_tbl_t *cmdtp, const char *cmd)
|
||||
{
|
||||
const char *ep = env_get("autostart");
|
||||
|
||||
if (ep && !strcmp(ep, "yes")) {
|
||||
char *local_args[2];
|
||||
local_args[0] = (char *)cmd;
|
||||
local_args[1] = NULL;
|
||||
printf("Automatic boot of image at addr 0x%08lX ...\n", load_addr);
|
||||
return do_bootm(cmdtp, 0, 1, local_args);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SYS_LONGHELP
|
||||
static char bootm_help_text[] =
|
||||
"[addr [arg ...]]\n - boot application image stored in memory\n"
|
||||
"\tpassing arguments 'arg ...'; when booting a Linux kernel,\n"
|
||||
"\t'arg' can be the address of an initrd image\n"
|
||||
#if defined(CONFIG_OF_LIBFDT)
|
||||
"\tWhen booting a Linux kernel which requires a flat device-tree\n"
|
||||
"\ta third argument is required which is the address of the\n"
|
||||
"\tdevice-tree blob. To boot that kernel without an initrd image,\n"
|
||||
"\tuse a '-' for the second argument. If you do not pass a third\n"
|
||||
"\ta bd_info struct will be passed instead\n"
|
||||
#endif
|
||||
#if defined(CONFIG_FIT)
|
||||
"\t\nFor the new multi component uImage format (FIT) addresses\n"
|
||||
"\tmust be extended to include component or configuration unit name:\n"
|
||||
"\taddr:<subimg_uname> - direct component image specification\n"
|
||||
"\taddr#<conf_uname> - configuration specification\n"
|
||||
"\tUse iminfo command to get the list of existing component\n"
|
||||
"\timages and configurations.\n"
|
||||
#endif
|
||||
"\nSub-commands to do part of the bootm sequence. The sub-commands "
|
||||
"must be\n"
|
||||
"issued in the order below (it's ok to not issue all sub-commands):\n"
|
||||
"\tstart [addr [arg ...]]\n"
|
||||
"\tloados - load OS image\n"
|
||||
#if defined(CONFIG_SYS_BOOT_RAMDISK_HIGH)
|
||||
"\tramdisk - relocate initrd, set env initrd_start/initrd_end\n"
|
||||
#endif
|
||||
#if defined(CONFIG_OF_LIBFDT)
|
||||
"\tfdt - relocate flat device tree\n"
|
||||
#endif
|
||||
"\tcmdline - OS specific command line processing/setup\n"
|
||||
"\tbdt - OS specific bd_t processing\n"
|
||||
"\tprep - OS specific prep before relocation or go\n"
|
||||
#if defined(CONFIG_TRACE)
|
||||
"\tfake - OS specific fake start without go\n"
|
||||
#endif
|
||||
"\tgo - start OS";
|
||||
#endif
|
||||
|
||||
U_BOOT_CMD(
|
||||
bootm, CONFIG_SYS_MAXARGS, 1, do_bootm,
|
||||
"boot application image from memory", bootm_help_text
|
||||
);
|
||||
|
||||
/*******************************************************************/
|
||||
/* bootd - boot default image */
|
||||
/*******************************************************************/
|
||||
#if defined(CONFIG_CMD_BOOTD)
|
||||
int do_bootd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
return run_command(env_get("bootcmd"), flag);
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
boot, 1, 1, do_bootd,
|
||||
"boot default, i.e., run 'bootcmd'",
|
||||
""
|
||||
);
|
||||
|
||||
/* keep old command name "bootd" for backward compatibility */
|
||||
U_BOOT_CMD(
|
||||
bootd, 1, 1, do_bootd,
|
||||
"boot default, i.e., run 'bootcmd'",
|
||||
""
|
||||
);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*******************************************************************/
|
||||
/* iminfo - print header info for a requested image */
|
||||
/*******************************************************************/
|
||||
#if defined(CONFIG_CMD_IMI)
|
||||
static int do_iminfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
int arg;
|
||||
ulong addr;
|
||||
int rcode = 0;
|
||||
|
||||
if (argc < 2) {
|
||||
return image_info(load_addr);
|
||||
}
|
||||
|
||||
for (arg = 1; arg < argc; ++arg) {
|
||||
addr = simple_strtoul(argv[arg], NULL, 16);
|
||||
if (image_info(addr) != 0)
|
||||
rcode = 1;
|
||||
}
|
||||
return rcode;
|
||||
}
|
||||
|
||||
static int image_info(ulong addr)
|
||||
{
|
||||
void *hdr = (void *)map_sysmem(addr, 0);
|
||||
|
||||
printf("\n## Checking Image at %08lx ...\n", addr);
|
||||
|
||||
switch (genimg_get_format(hdr)) {
|
||||
#if defined(CONFIG_LEGACY_IMAGE_FORMAT)
|
||||
case IMAGE_FORMAT_LEGACY:
|
||||
puts(" Legacy image found\n");
|
||||
if (!image_check_magic(hdr)) {
|
||||
puts(" Bad Magic Number\n");
|
||||
unmap_sysmem(hdr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!image_check_hcrc(hdr)) {
|
||||
puts(" Bad Header Checksum\n");
|
||||
unmap_sysmem(hdr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
image_print_contents(hdr);
|
||||
|
||||
puts(" Verifying Checksum ... ");
|
||||
if (!image_check_dcrc(hdr)) {
|
||||
puts(" Bad Data CRC\n");
|
||||
unmap_sysmem(hdr);
|
||||
return 1;
|
||||
}
|
||||
puts("OK\n");
|
||||
unmap_sysmem(hdr);
|
||||
return 0;
|
||||
#endif
|
||||
#if defined(CONFIG_ANDROID_BOOT_IMAGE)
|
||||
case IMAGE_FORMAT_ANDROID:
|
||||
puts(" Android image found\n");
|
||||
android_print_contents(hdr);
|
||||
unmap_sysmem(hdr);
|
||||
return 0;
|
||||
#endif
|
||||
#if defined(CONFIG_FIT)
|
||||
case IMAGE_FORMAT_FIT:
|
||||
puts(" FIT image found\n");
|
||||
|
||||
if (!fit_check_format(hdr)) {
|
||||
puts("Bad FIT image format!\n");
|
||||
unmap_sysmem(hdr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fit_print_contents(hdr);
|
||||
|
||||
if (!fit_all_image_verify(hdr)) {
|
||||
puts("Bad hash in FIT image!\n");
|
||||
unmap_sysmem(hdr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
unmap_sysmem(hdr);
|
||||
return 0;
|
||||
#endif
|
||||
default:
|
||||
puts("Unknown image format!\n");
|
||||
break;
|
||||
}
|
||||
|
||||
unmap_sysmem(hdr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
iminfo, CONFIG_SYS_MAXARGS, 1, do_iminfo,
|
||||
"print header information for application image",
|
||||
"addr [addr ...]\n"
|
||||
" - print header information for application image starting at\n"
|
||||
" address 'addr' in memory; this includes verification of the\n"
|
||||
" image contents (magic number, header and payload checksums)"
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/*******************************************************************/
|
||||
/* imls - list all images found in flash */
|
||||
/*******************************************************************/
|
||||
#if defined(CONFIG_CMD_IMLS)
|
||||
static int do_imls_nor(void)
|
||||
{
|
||||
flash_info_t *info;
|
||||
int i, j;
|
||||
void *hdr;
|
||||
|
||||
for (i = 0, info = &flash_info[0];
|
||||
i < CONFIG_SYS_MAX_FLASH_BANKS; ++i, ++info) {
|
||||
|
||||
if (info->flash_id == FLASH_UNKNOWN)
|
||||
goto next_bank;
|
||||
for (j = 0; j < info->sector_count; ++j) {
|
||||
|
||||
hdr = (void *)info->start[j];
|
||||
if (!hdr)
|
||||
goto next_sector;
|
||||
|
||||
switch (genimg_get_format(hdr)) {
|
||||
#if defined(CONFIG_LEGACY_IMAGE_FORMAT)
|
||||
case IMAGE_FORMAT_LEGACY:
|
||||
if (!image_check_hcrc(hdr))
|
||||
goto next_sector;
|
||||
|
||||
printf("Legacy Image at %08lX:\n", (ulong)hdr);
|
||||
image_print_contents(hdr);
|
||||
|
||||
puts(" Verifying Checksum ... ");
|
||||
if (!image_check_dcrc(hdr)) {
|
||||
puts("Bad Data CRC\n");
|
||||
} else {
|
||||
puts("OK\n");
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#if defined(CONFIG_FIT)
|
||||
case IMAGE_FORMAT_FIT:
|
||||
if (!fit_check_format(hdr))
|
||||
goto next_sector;
|
||||
|
||||
printf("FIT Image at %08lX:\n", (ulong)hdr);
|
||||
fit_print_contents(hdr);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
goto next_sector;
|
||||
}
|
||||
|
||||
next_sector: ;
|
||||
}
|
||||
next_bank: ;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_CMD_IMLS_NAND)
|
||||
static int nand_imls_legacyimage(struct mtd_info *mtd, int nand_dev,
|
||||
loff_t off, size_t len)
|
||||
{
|
||||
void *imgdata;
|
||||
int ret;
|
||||
|
||||
imgdata = malloc(len);
|
||||
if (!imgdata) {
|
||||
printf("May be a Legacy Image at NAND device %d offset %08llX:\n",
|
||||
nand_dev, off);
|
||||
printf(" Low memory(cannot allocate memory for image)\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = nand_read_skip_bad(mtd, off, &len, NULL, mtd->size, imgdata);
|
||||
if (ret < 0 && ret != -EUCLEAN) {
|
||||
free(imgdata);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!image_check_hcrc(imgdata)) {
|
||||
free(imgdata);
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("Legacy Image at NAND device %d offset %08llX:\n",
|
||||
nand_dev, off);
|
||||
image_print_contents(imgdata);
|
||||
|
||||
puts(" Verifying Checksum ... ");
|
||||
if (!image_check_dcrc(imgdata))
|
||||
puts("Bad Data CRC\n");
|
||||
else
|
||||
puts("OK\n");
|
||||
|
||||
free(imgdata);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nand_imls_fitimage(struct mtd_info *mtd, int nand_dev, loff_t off,
|
||||
size_t len)
|
||||
{
|
||||
void *imgdata;
|
||||
int ret;
|
||||
|
||||
imgdata = malloc(len);
|
||||
if (!imgdata) {
|
||||
printf("May be a FIT Image at NAND device %d offset %08llX:\n",
|
||||
nand_dev, off);
|
||||
printf(" Low memory(cannot allocate memory for image)\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = nand_read_skip_bad(mtd, off, &len, NULL, mtd->size, imgdata);
|
||||
if (ret < 0 && ret != -EUCLEAN) {
|
||||
free(imgdata);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!fit_check_format(imgdata)) {
|
||||
free(imgdata);
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("FIT Image at NAND device %d offset %08llX:\n", nand_dev, off);
|
||||
|
||||
fit_print_contents(imgdata);
|
||||
free(imgdata);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_imls_nand(void)
|
||||
{
|
||||
struct mtd_info *mtd;
|
||||
int nand_dev = nand_curr_device;
|
||||
size_t len;
|
||||
loff_t off;
|
||||
u32 buffer[16];
|
||||
|
||||
if (nand_dev < 0 || nand_dev >= CONFIG_SYS_MAX_NAND_DEVICE) {
|
||||
puts("\nNo NAND devices available\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
for (nand_dev = 0; nand_dev < CONFIG_SYS_MAX_NAND_DEVICE; nand_dev++) {
|
||||
mtd = get_nand_dev_by_index(nand_dev);
|
||||
if (!mtd->name || !mtd->size)
|
||||
continue;
|
||||
|
||||
for (off = 0; off < mtd->size; off += mtd->erasesize) {
|
||||
const image_header_t *header;
|
||||
int ret;
|
||||
|
||||
if (nand_block_isbad(mtd, off))
|
||||
continue;
|
||||
|
||||
len = sizeof(buffer);
|
||||
|
||||
ret = nand_read(mtd, off, &len, (u8 *)buffer);
|
||||
if (ret < 0 && ret != -EUCLEAN) {
|
||||
printf("NAND read error %d at offset %08llX\n",
|
||||
ret, off);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (genimg_get_format(buffer)) {
|
||||
#if defined(CONFIG_LEGACY_IMAGE_FORMAT)
|
||||
case IMAGE_FORMAT_LEGACY:
|
||||
header = (const image_header_t *)buffer;
|
||||
|
||||
len = image_get_image_size(header);
|
||||
nand_imls_legacyimage(mtd, nand_dev, off, len);
|
||||
break;
|
||||
#endif
|
||||
#if defined(CONFIG_FIT)
|
||||
case IMAGE_FORMAT_FIT:
|
||||
len = fit_get_size(buffer);
|
||||
nand_imls_fitimage(mtd, nand_dev, off, len);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_CMD_IMLS) || defined(CONFIG_CMD_IMLS_NAND)
|
||||
static int do_imls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
int ret_nor = 0, ret_nand = 0;
|
||||
|
||||
#if defined(CONFIG_CMD_IMLS)
|
||||
ret_nor = do_imls_nor();
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_CMD_IMLS_NAND)
|
||||
ret_nand = do_imls_nand();
|
||||
#endif
|
||||
|
||||
if (ret_nor)
|
||||
return ret_nor;
|
||||
|
||||
if (ret_nand)
|
||||
return ret_nand;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
imls, 1, 1, do_imls,
|
||||
"list all images found in flash",
|
||||
"\n"
|
||||
" - Prints information about all images found at sector/block\n"
|
||||
" boundaries in nor/nand flash."
|
||||
);
|
||||
#endif
|
||||
511
cmd/bootmenu.c
Normal file
511
cmd/bootmenu.c
Normal file
@@ -0,0 +1,511 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2011-2013 Pali Rohár <pali.rohar@gmail.com>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <ansi.h>
|
||||
#include <env.h>
|
||||
#include <menu.h>
|
||||
#include <watchdog.h>
|
||||
#include <malloc.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
/* maximum bootmenu entries */
|
||||
#define MAX_COUNT 99
|
||||
|
||||
/* maximal size of bootmenu env
|
||||
* 9 = strlen("bootmenu_")
|
||||
* 2 = strlen(MAX_COUNT)
|
||||
* 1 = NULL term
|
||||
*/
|
||||
#define MAX_ENV_SIZE (9 + 2 + 1)
|
||||
|
||||
struct bootmenu_entry {
|
||||
unsigned short int num; /* unique number 0 .. MAX_COUNT */
|
||||
char key[3]; /* key identifier of number */
|
||||
char *title; /* title of entry */
|
||||
char *command; /* hush command of entry */
|
||||
struct bootmenu_data *menu; /* this bootmenu */
|
||||
struct bootmenu_entry *next; /* next menu entry (num+1) */
|
||||
};
|
||||
|
||||
struct bootmenu_data {
|
||||
int delay; /* delay for autoboot */
|
||||
int active; /* active menu entry */
|
||||
int count; /* total count of menu entries */
|
||||
struct bootmenu_entry *first; /* first menu entry */
|
||||
};
|
||||
|
||||
enum bootmenu_key {
|
||||
KEY_NONE = 0,
|
||||
KEY_UP,
|
||||
KEY_DOWN,
|
||||
KEY_SELECT,
|
||||
};
|
||||
|
||||
static char *bootmenu_getoption(unsigned short int n)
|
||||
{
|
||||
char name[MAX_ENV_SIZE];
|
||||
|
||||
if (n > MAX_COUNT)
|
||||
return NULL;
|
||||
|
||||
sprintf(name, "bootmenu_%d", n);
|
||||
return env_get(name);
|
||||
}
|
||||
|
||||
static void bootmenu_print_entry(void *data)
|
||||
{
|
||||
struct bootmenu_entry *entry = data;
|
||||
int reverse = (entry->menu->active == entry->num);
|
||||
|
||||
/*
|
||||
* Move cursor to line where the entry will be drown (entry->num)
|
||||
* First 3 lines contain bootmenu header + 1 empty line
|
||||
*/
|
||||
printf(ANSI_CURSOR_POSITION, entry->num + 4, 1);
|
||||
|
||||
puts(" ");
|
||||
|
||||
if (reverse)
|
||||
puts(ANSI_COLOR_REVERSE);
|
||||
|
||||
puts(entry->title);
|
||||
|
||||
if (reverse)
|
||||
puts(ANSI_COLOR_RESET);
|
||||
}
|
||||
|
||||
static void bootmenu_autoboot_loop(struct bootmenu_data *menu,
|
||||
enum bootmenu_key *key, int *esc)
|
||||
{
|
||||
int i, c;
|
||||
|
||||
if (menu->delay > 0) {
|
||||
printf(ANSI_CURSOR_POSITION, menu->count + 5, 1);
|
||||
printf(" Hit any key to stop autoboot: %2d ", menu->delay);
|
||||
}
|
||||
|
||||
while (menu->delay > 0) {
|
||||
for (i = 0; i < 100; ++i) {
|
||||
if (!tstc()) {
|
||||
WATCHDOG_RESET();
|
||||
mdelay(10);
|
||||
continue;
|
||||
}
|
||||
|
||||
menu->delay = -1;
|
||||
c = getc();
|
||||
|
||||
switch (c) {
|
||||
case '\e':
|
||||
*esc = 1;
|
||||
*key = KEY_NONE;
|
||||
break;
|
||||
case '\r':
|
||||
*key = KEY_SELECT;
|
||||
break;
|
||||
default:
|
||||
*key = KEY_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (menu->delay < 0)
|
||||
break;
|
||||
|
||||
--menu->delay;
|
||||
printf("\b\b\b%2d ", menu->delay);
|
||||
}
|
||||
|
||||
printf(ANSI_CURSOR_POSITION, menu->count + 5, 1);
|
||||
puts(ANSI_CLEAR_LINE);
|
||||
|
||||
if (menu->delay == 0)
|
||||
*key = KEY_SELECT;
|
||||
}
|
||||
|
||||
static void bootmenu_loop(struct bootmenu_data *menu,
|
||||
enum bootmenu_key *key, int *esc)
|
||||
{
|
||||
int c;
|
||||
|
||||
while (!tstc()) {
|
||||
WATCHDOG_RESET();
|
||||
mdelay(10);
|
||||
}
|
||||
|
||||
c = getc();
|
||||
|
||||
switch (*esc) {
|
||||
case 0:
|
||||
/* First char of ANSI escape sequence '\e' */
|
||||
if (c == '\e') {
|
||||
*esc = 1;
|
||||
*key = KEY_NONE;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
/* Second char of ANSI '[' */
|
||||
if (c == '[') {
|
||||
*esc = 2;
|
||||
*key = KEY_NONE;
|
||||
} else {
|
||||
*esc = 0;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
/* Third char of ANSI (number '1') - optional */
|
||||
if (*esc == 2 && c == '1') {
|
||||
*esc = 3;
|
||||
*key = KEY_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
*esc = 0;
|
||||
|
||||
/* ANSI 'A' - key up was pressed */
|
||||
if (c == 'A')
|
||||
*key = KEY_UP;
|
||||
/* ANSI 'B' - key down was pressed */
|
||||
else if (c == 'B')
|
||||
*key = KEY_DOWN;
|
||||
/* other key was pressed */
|
||||
else
|
||||
*key = KEY_NONE;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* enter key was pressed */
|
||||
if (c == '\r')
|
||||
*key = KEY_SELECT;
|
||||
}
|
||||
|
||||
static char *bootmenu_choice_entry(void *data)
|
||||
{
|
||||
struct bootmenu_data *menu = data;
|
||||
struct bootmenu_entry *iter;
|
||||
enum bootmenu_key key = KEY_NONE;
|
||||
int esc = 0;
|
||||
int i;
|
||||
|
||||
while (1) {
|
||||
if (menu->delay >= 0) {
|
||||
/* Autoboot was not stopped */
|
||||
bootmenu_autoboot_loop(menu, &key, &esc);
|
||||
} else {
|
||||
/* Some key was pressed, so autoboot was stopped */
|
||||
bootmenu_loop(menu, &key, &esc);
|
||||
}
|
||||
|
||||
switch (key) {
|
||||
case KEY_UP:
|
||||
if (menu->active > 0)
|
||||
--menu->active;
|
||||
/* no menu key selected, regenerate menu */
|
||||
return NULL;
|
||||
case KEY_DOWN:
|
||||
if (menu->active < menu->count - 1)
|
||||
++menu->active;
|
||||
/* no menu key selected, regenerate menu */
|
||||
return NULL;
|
||||
case KEY_SELECT:
|
||||
iter = menu->first;
|
||||
for (i = 0; i < menu->active; ++i)
|
||||
iter = iter->next;
|
||||
return iter->key;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* never happens */
|
||||
debug("bootmenu: this should not happen");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void bootmenu_destroy(struct bootmenu_data *menu)
|
||||
{
|
||||
struct bootmenu_entry *iter = menu->first;
|
||||
struct bootmenu_entry *next;
|
||||
|
||||
while (iter) {
|
||||
next = iter->next;
|
||||
free(iter->title);
|
||||
free(iter->command);
|
||||
free(iter);
|
||||
iter = next;
|
||||
}
|
||||
free(menu);
|
||||
}
|
||||
|
||||
static struct bootmenu_data *bootmenu_create(int delay)
|
||||
{
|
||||
unsigned short int i = 0;
|
||||
const char *option;
|
||||
struct bootmenu_data *menu;
|
||||
struct bootmenu_entry *iter = NULL;
|
||||
|
||||
int len;
|
||||
char *sep;
|
||||
char *default_str;
|
||||
struct bootmenu_entry *entry;
|
||||
|
||||
menu = malloc(sizeof(struct bootmenu_data));
|
||||
if (!menu)
|
||||
return NULL;
|
||||
|
||||
menu->delay = delay;
|
||||
menu->active = 0;
|
||||
menu->first = NULL;
|
||||
|
||||
default_str = env_get("bootmenu_default");
|
||||
if (default_str)
|
||||
menu->active = (int)simple_strtol(default_str, NULL, 10);
|
||||
|
||||
while ((option = bootmenu_getoption(i))) {
|
||||
sep = strchr(option, '=');
|
||||
if (!sep) {
|
||||
printf("Invalid bootmenu entry: %s\n", option);
|
||||
break;
|
||||
}
|
||||
|
||||
entry = malloc(sizeof(struct bootmenu_entry));
|
||||
if (!entry)
|
||||
goto cleanup;
|
||||
|
||||
len = sep-option;
|
||||
entry->title = malloc(len + 1);
|
||||
if (!entry->title) {
|
||||
free(entry);
|
||||
goto cleanup;
|
||||
}
|
||||
memcpy(entry->title, option, len);
|
||||
entry->title[len] = 0;
|
||||
|
||||
len = strlen(sep + 1);
|
||||
entry->command = malloc(len + 1);
|
||||
if (!entry->command) {
|
||||
free(entry->title);
|
||||
free(entry);
|
||||
goto cleanup;
|
||||
}
|
||||
memcpy(entry->command, sep + 1, len);
|
||||
entry->command[len] = 0;
|
||||
|
||||
sprintf(entry->key, "%d", i);
|
||||
|
||||
entry->num = i;
|
||||
entry->menu = menu;
|
||||
entry->next = NULL;
|
||||
|
||||
if (!iter)
|
||||
menu->first = entry;
|
||||
else
|
||||
iter->next = entry;
|
||||
|
||||
iter = entry;
|
||||
++i;
|
||||
|
||||
if (i == MAX_COUNT - 1)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Add U-Boot console entry at the end */
|
||||
if (i <= MAX_COUNT - 1) {
|
||||
entry = malloc(sizeof(struct bootmenu_entry));
|
||||
if (!entry)
|
||||
goto cleanup;
|
||||
|
||||
entry->title = strdup("U-Boot console");
|
||||
if (!entry->title) {
|
||||
free(entry);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
entry->command = strdup("");
|
||||
if (!entry->command) {
|
||||
free(entry->title);
|
||||
free(entry);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
sprintf(entry->key, "%d", i);
|
||||
|
||||
entry->num = i;
|
||||
entry->menu = menu;
|
||||
entry->next = NULL;
|
||||
|
||||
if (!iter)
|
||||
menu->first = entry;
|
||||
else
|
||||
iter->next = entry;
|
||||
|
||||
iter = entry;
|
||||
++i;
|
||||
}
|
||||
|
||||
menu->count = i;
|
||||
|
||||
if ((menu->active >= menu->count)||(menu->active < 0)) { //ensure active menuitem is inside menu
|
||||
printf("active menuitem (%d) is outside menu (0..%d)\n",menu->active,menu->count-1);
|
||||
menu->active=0;
|
||||
}
|
||||
|
||||
return menu;
|
||||
|
||||
cleanup:
|
||||
bootmenu_destroy(menu);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void bootmenu_show(int delay)
|
||||
{
|
||||
int init = 0;
|
||||
void *choice = NULL;
|
||||
char *title = NULL;
|
||||
char *command = NULL;
|
||||
struct menu *menu;
|
||||
struct bootmenu_data *bootmenu;
|
||||
struct bootmenu_entry *iter;
|
||||
char *option, *sep;
|
||||
|
||||
/* If delay is 0 do not create menu, just run first entry */
|
||||
if (delay == 0) {
|
||||
option = bootmenu_getoption(0);
|
||||
if (!option) {
|
||||
puts("bootmenu option 0 was not found\n");
|
||||
return;
|
||||
}
|
||||
sep = strchr(option, '=');
|
||||
if (!sep) {
|
||||
puts("bootmenu option 0 is invalid\n");
|
||||
return;
|
||||
}
|
||||
run_command(sep+1, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
bootmenu = bootmenu_create(delay);
|
||||
if (!bootmenu)
|
||||
return;
|
||||
|
||||
menu = menu_create(NULL, bootmenu->delay, 1, bootmenu_print_entry,
|
||||
bootmenu_choice_entry, bootmenu);
|
||||
if (!menu) {
|
||||
bootmenu_destroy(bootmenu);
|
||||
return;
|
||||
}
|
||||
|
||||
for (iter = bootmenu->first; iter; iter = iter->next) {
|
||||
if (!menu_item_add(menu, iter->key, iter))
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Default menu entry is always first */
|
||||
menu_default_set(menu, "0");
|
||||
|
||||
puts(ANSI_CURSOR_HIDE);
|
||||
puts(ANSI_CLEAR_CONSOLE);
|
||||
printf(ANSI_CURSOR_POSITION, 1, 1);
|
||||
|
||||
init = 1;
|
||||
|
||||
if (menu_get_choice(menu, &choice)) {
|
||||
iter = choice;
|
||||
title = strdup(iter->title);
|
||||
command = strdup(iter->command);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
menu_destroy(menu);
|
||||
bootmenu_destroy(bootmenu);
|
||||
|
||||
if (init) {
|
||||
puts(ANSI_CURSOR_SHOW);
|
||||
puts(ANSI_CLEAR_CONSOLE);
|
||||
printf(ANSI_CURSOR_POSITION, 1, 1);
|
||||
}
|
||||
|
||||
if (title && command) {
|
||||
debug("Starting entry '%s'\n", title);
|
||||
free(title);
|
||||
run_command(command, 0);
|
||||
free(command);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_POSTBOOTMENU
|
||||
run_command(CONFIG_POSTBOOTMENU, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void menu_display_statusline(struct menu *m)
|
||||
{
|
||||
struct bootmenu_entry *entry;
|
||||
struct bootmenu_data *menu;
|
||||
|
||||
if (menu_default_choice(m, (void *)&entry) < 0)
|
||||
return;
|
||||
|
||||
menu = entry->menu;
|
||||
|
||||
printf(ANSI_CURSOR_POSITION, 1, 1);
|
||||
puts(ANSI_CLEAR_LINE);
|
||||
printf(ANSI_CURSOR_POSITION, 2, 1);
|
||||
puts(" *** U-Boot Boot Menu ***");
|
||||
puts(ANSI_CLEAR_LINE_TO_END);
|
||||
printf(ANSI_CURSOR_POSITION, 3, 1);
|
||||
puts(ANSI_CLEAR_LINE);
|
||||
|
||||
/* First 3 lines are bootmenu header + 2 empty lines between entries */
|
||||
printf(ANSI_CURSOR_POSITION, menu->count + 5, 1);
|
||||
puts(ANSI_CLEAR_LINE);
|
||||
printf(ANSI_CURSOR_POSITION, menu->count + 6, 1);
|
||||
puts(" Press UP/DOWN to move, ENTER to select");
|
||||
puts(ANSI_CLEAR_LINE_TO_END);
|
||||
printf(ANSI_CURSOR_POSITION, menu->count + 7, 1);
|
||||
puts(ANSI_CLEAR_LINE);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_AUTOBOOT_MENU_SHOW
|
||||
int menu_show(int bootdelay)
|
||||
{
|
||||
bootmenu_show(bootdelay);
|
||||
return -1; /* -1 - abort boot and run monitor code */
|
||||
}
|
||||
#endif
|
||||
|
||||
int do_bootmenu(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
|
||||
{
|
||||
char *delay_str = NULL;
|
||||
int delay = 10;
|
||||
|
||||
#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
|
||||
delay = CONFIG_BOOTDELAY;
|
||||
#endif
|
||||
|
||||
if (argc >= 2)
|
||||
delay_str = argv[1];
|
||||
|
||||
if (!delay_str)
|
||||
delay_str = env_get("bootmenu_delay");
|
||||
|
||||
if (delay_str)
|
||||
delay = (int)simple_strtol(delay_str, NULL, 10);
|
||||
|
||||
bootmenu_show(delay);
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
bootmenu, 2, 1, do_bootmenu,
|
||||
"ANSI terminal bootmenu",
|
||||
"[delay]\n"
|
||||
" - show ANSI terminal bootmenu with autoboot delay"
|
||||
);
|
||||
94
cmd/bootstage.c
Normal file
94
cmd/bootstage.c
Normal file
@@ -0,0 +1,94 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2012, Google Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
|
||||
static int do_bootstage_report(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
bootstage_report();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_base_size(int argc, char * const argv[], ulong *basep,
|
||||
ulong *sizep)
|
||||
{
|
||||
char *endp;
|
||||
|
||||
*basep = CONFIG_BOOTSTAGE_STASH_ADDR;
|
||||
*sizep = CONFIG_BOOTSTAGE_STASH_SIZE;
|
||||
if (argc < 2)
|
||||
return 0;
|
||||
*basep = simple_strtoul(argv[1], &endp, 16);
|
||||
if (*argv[1] == 0 || *endp != 0)
|
||||
return -1;
|
||||
if (argc == 2)
|
||||
return 0;
|
||||
*sizep = simple_strtoul(argv[2], &endp, 16);
|
||||
if (*argv[2] == 0 || *endp != 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_bootstage_stash(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
ulong base, size;
|
||||
int ret;
|
||||
|
||||
if (get_base_size(argc, argv, &base, &size))
|
||||
return CMD_RET_USAGE;
|
||||
if (base == -1UL) {
|
||||
printf("No bootstage stash area defined\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (0 == strcmp(argv[0], "stash"))
|
||||
ret = bootstage_stash((void *)base, size);
|
||||
else
|
||||
ret = bootstage_unstash((void *)base, size);
|
||||
if (ret)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static cmd_tbl_t cmd_bootstage_sub[] = {
|
||||
U_BOOT_CMD_MKENT(report, 2, 1, do_bootstage_report, "", ""),
|
||||
U_BOOT_CMD_MKENT(stash, 4, 0, do_bootstage_stash, "", ""),
|
||||
U_BOOT_CMD_MKENT(unstash, 4, 0, do_bootstage_stash, "", ""),
|
||||
};
|
||||
|
||||
/*
|
||||
* Process a bootstage sub-command
|
||||
*/
|
||||
static int do_boostage(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
cmd_tbl_t *c;
|
||||
|
||||
/* Strip off leading 'bootstage' command argument */
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
c = find_cmd_tbl(argv[0], cmd_bootstage_sub,
|
||||
ARRAY_SIZE(cmd_bootstage_sub));
|
||||
|
||||
if (c)
|
||||
return c->cmd(cmdtp, flag, argc, argv);
|
||||
else
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
|
||||
U_BOOT_CMD(bootstage, 4, 1, do_boostage,
|
||||
"Boot stage command",
|
||||
" - check boot progress and timing\n"
|
||||
"report - Print a report\n"
|
||||
"stash [<start> [<size>]] - Stash data into memory\n"
|
||||
"unstash [<start> [<size>]] - Unstash data from memory"
|
||||
);
|
||||
109
cmd/bootz.c
Normal file
109
cmd/bootz.c
Normal file
@@ -0,0 +1,109 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2000-2009
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <bootm.h>
|
||||
#include <command.h>
|
||||
#include <irq_func.h>
|
||||
#include <lmb.h>
|
||||
#include <linux/compiler.h>
|
||||
|
||||
int __weak bootz_setup(ulong image, ulong *start, ulong *end)
|
||||
{
|
||||
/* Please define bootz_setup() for your platform */
|
||||
|
||||
puts("Your platform's zImage format isn't supported yet!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* zImage booting support
|
||||
*/
|
||||
static int bootz_start(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[], bootm_headers_t *images)
|
||||
{
|
||||
int ret;
|
||||
ulong zi_start, zi_end;
|
||||
|
||||
ret = do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_START,
|
||||
images, 1);
|
||||
|
||||
/* Setup Linux kernel zImage entry point */
|
||||
if (!argc) {
|
||||
images->ep = load_addr;
|
||||
debug("* kernel: default image load address = 0x%08lx\n",
|
||||
load_addr);
|
||||
} else {
|
||||
images->ep = simple_strtoul(argv[0], NULL, 16);
|
||||
debug("* kernel: cmdline image address = 0x%08lx\n",
|
||||
images->ep);
|
||||
}
|
||||
|
||||
ret = bootz_setup(images->ep, &zi_start, &zi_end);
|
||||
if (ret != 0)
|
||||
return 1;
|
||||
|
||||
lmb_reserve(&images->lmb, images->ep, zi_end - zi_start);
|
||||
|
||||
/*
|
||||
* Handle the BOOTM_STATE_FINDOTHER state ourselves as we do not
|
||||
* have a header that provide this informaiton.
|
||||
*/
|
||||
if (bootm_find_images(flag, argc, argv))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int do_bootz(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Consume 'bootz' */
|
||||
argc--; argv++;
|
||||
|
||||
if (bootz_start(cmdtp, flag, argc, argv, &images))
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* We are doing the BOOTM_STATE_LOADOS state ourselves, so must
|
||||
* disable interrupts ourselves
|
||||
*/
|
||||
bootm_disable_interrupts();
|
||||
|
||||
images.os.os = IH_OS_LINUX;
|
||||
ret = do_bootm_states(cmdtp, flag, argc, argv,
|
||||
#ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH
|
||||
BOOTM_STATE_RAMDISK |
|
||||
#endif
|
||||
BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO |
|
||||
BOOTM_STATE_OS_GO,
|
||||
&images, 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SYS_LONGHELP
|
||||
static char bootz_help_text[] =
|
||||
"[addr [initrd[:size]] [fdt]]\n"
|
||||
" - boot Linux zImage stored in memory\n"
|
||||
"\tThe argument 'initrd' is optional and specifies the address\n"
|
||||
"\tof the initrd in memory. The optional argument ':size' allows\n"
|
||||
"\tspecifying the size of RAW initrd.\n"
|
||||
#if defined(CONFIG_OF_LIBFDT)
|
||||
"\tWhen booting a Linux kernel which requires a flat device-tree\n"
|
||||
"\ta third argument is required which is the address of the\n"
|
||||
"\tdevice-tree blob. To boot that kernel without an initrd image,\n"
|
||||
"\tuse a '-' for the second argument. If you do not pass a third\n"
|
||||
"\ta bd_info struct will be passed instead\n"
|
||||
#endif
|
||||
"";
|
||||
#endif
|
||||
|
||||
U_BOOT_CMD(
|
||||
bootz, CONFIG_SYS_MAXARGS, 1, do_bootz,
|
||||
"boot Linux zImage image from memory", bootz_help_text
|
||||
);
|
||||
27
cmd/btrfs.c
Normal file
27
cmd/btrfs.c
Normal file
@@ -0,0 +1,27 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* 2017 by Marek Behun <marek.behun@nic.cz>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <btrfs.h>
|
||||
#include <fs.h>
|
||||
|
||||
int do_btrsubvol(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
|
||||
{
|
||||
if (argc != 3)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
if (fs_set_blk_dev(argv[1], argv[2], FS_TYPE_BTRFS))
|
||||
return 1;
|
||||
|
||||
btrfs_list_subvols();
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(btrsubvol, 3, 1, do_btrsubvol,
|
||||
"list subvolumes of a BTRFS filesystem",
|
||||
"<interface> <dev[:part]>\n"
|
||||
" - List subvolumes of a BTRFS filesystem."
|
||||
)
|
||||
110
cmd/cache.c
Normal file
110
cmd/cache.c
Normal file
@@ -0,0 +1,110 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2000
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Cache support: switch on or off, get status
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <cpu_func.h>
|
||||
#include <linux/compiler.h>
|
||||
|
||||
static int parse_argv(const char *);
|
||||
|
||||
void __weak invalidate_icache_all(void)
|
||||
{
|
||||
/* please define arch specific invalidate_icache_all */
|
||||
puts("No arch specific invalidate_icache_all available!\n");
|
||||
}
|
||||
|
||||
static int do_icache(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
switch (argc) {
|
||||
case 2: /* on / off / flush */
|
||||
switch (parse_argv(argv[1])) {
|
||||
case 0:
|
||||
icache_disable();
|
||||
break;
|
||||
case 1:
|
||||
icache_enable();
|
||||
break;
|
||||
case 2:
|
||||
invalidate_icache_all();
|
||||
break;
|
||||
default:
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
break;
|
||||
case 1: /* get status */
|
||||
printf("Instruction Cache is %s\n",
|
||||
icache_status() ? "ON" : "OFF");
|
||||
return 0;
|
||||
default:
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __weak flush_dcache_all(void)
|
||||
{
|
||||
puts("No arch specific flush_dcache_all available!\n");
|
||||
/* please define arch specific flush_dcache_all */
|
||||
}
|
||||
|
||||
static int do_dcache(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
switch (argc) {
|
||||
case 2: /* on / off / flush */
|
||||
switch (parse_argv(argv[1])) {
|
||||
case 0:
|
||||
dcache_disable();
|
||||
break;
|
||||
case 1:
|
||||
dcache_enable();
|
||||
break;
|
||||
case 2:
|
||||
flush_dcache_all();
|
||||
break;
|
||||
default:
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
break;
|
||||
case 1: /* get status */
|
||||
printf("Data (writethrough) Cache is %s\n",
|
||||
dcache_status() ? "ON" : "OFF");
|
||||
return 0;
|
||||
default:
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_argv(const char *s)
|
||||
{
|
||||
if (strcmp(s, "flush") == 0)
|
||||
return 2;
|
||||
else if (strcmp(s, "on") == 0)
|
||||
return 1;
|
||||
else if (strcmp(s, "off") == 0)
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
U_BOOT_CMD(
|
||||
icache, 2, 1, do_icache,
|
||||
"enable or disable instruction cache",
|
||||
"[on, off, flush]\n"
|
||||
" - enable, disable, or flush instruction cache"
|
||||
);
|
||||
|
||||
U_BOOT_CMD(
|
||||
dcache, 2, 1, do_dcache,
|
||||
"enable or disable data cache",
|
||||
"[on, off, flush]\n"
|
||||
" - enable, disable, or flush data (writethrough) cache"
|
||||
);
|
||||
231
cmd/cbfs.c
Normal file
231
cmd/cbfs.c
Normal file
@@ -0,0 +1,231 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* CBFS commands
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <env.h>
|
||||
#include <cbfs.h>
|
||||
|
||||
static int do_cbfs_init(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char *const argv[])
|
||||
{
|
||||
uintptr_t end_of_rom = 0xffffffff;
|
||||
char *ep;
|
||||
|
||||
if (argc > 2) {
|
||||
printf("usage: cbfsls [end of rom]>\n");
|
||||
return 0;
|
||||
}
|
||||
if (argc == 2) {
|
||||
end_of_rom = simple_strtoul(argv[1], &ep, 16);
|
||||
if (*ep) {
|
||||
puts("\n** Invalid end of ROM **\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
file_cbfs_init(end_of_rom);
|
||||
if (cbfs_get_result() != CBFS_SUCCESS) {
|
||||
printf("%s.\n", file_cbfs_error());
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
cbfsinit, 2, 0, do_cbfs_init,
|
||||
"initialize the cbfs driver",
|
||||
"[end of rom]\n"
|
||||
" - Initialize the cbfs driver. The optional 'end of rom'\n"
|
||||
" parameter specifies where the end of the ROM is that the\n"
|
||||
" CBFS is in. It defaults to 0xFFFFFFFF\n"
|
||||
);
|
||||
|
||||
static int do_cbfs_fsload(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char *const argv[])
|
||||
{
|
||||
const struct cbfs_cachenode *file;
|
||||
unsigned long offset;
|
||||
unsigned long count;
|
||||
long size;
|
||||
|
||||
if (argc < 3) {
|
||||
printf("usage: cbfsload <addr> <filename> [bytes]\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* parse offset and count */
|
||||
offset = simple_strtoul(argv[1], NULL, 16);
|
||||
if (argc == 4)
|
||||
count = simple_strtoul(argv[3], NULL, 16);
|
||||
else
|
||||
count = 0;
|
||||
|
||||
file = file_cbfs_find(argv[2]);
|
||||
if (!file) {
|
||||
if (cbfs_get_result() == CBFS_FILE_NOT_FOUND)
|
||||
printf("%s: %s\n", file_cbfs_error(), argv[2]);
|
||||
else
|
||||
printf("%s.\n", file_cbfs_error());
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("reading %s\n", file_cbfs_name(file));
|
||||
|
||||
size = file_cbfs_read(file, (void *)offset, count);
|
||||
|
||||
printf("\n%ld bytes read\n", size);
|
||||
|
||||
env_set_hex("filesize", size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
cbfsload, 4, 0, do_cbfs_fsload,
|
||||
"load binary file from a cbfs filesystem",
|
||||
"<addr> <filename> [bytes]\n"
|
||||
" - load binary file 'filename' from the cbfs to address 'addr'\n"
|
||||
);
|
||||
|
||||
static int do_cbfs_ls(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char *const argv[])
|
||||
{
|
||||
const struct cbfs_cachenode *file = file_cbfs_get_first();
|
||||
int files = 0;
|
||||
|
||||
if (!file) {
|
||||
printf("%s.\n", file_cbfs_error());
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf(" size type name\n");
|
||||
printf("------------------------------------------\n");
|
||||
while (file) {
|
||||
int type = file_cbfs_type(file);
|
||||
char *type_name = NULL;
|
||||
const char *filename = file_cbfs_name(file);
|
||||
|
||||
printf(" %8d", file_cbfs_size(file));
|
||||
|
||||
switch (type) {
|
||||
case CBFS_TYPE_BOOTBLOCK:
|
||||
type_name = "bootblock";
|
||||
break;
|
||||
case CBFS_TYPE_CBFSHEADER:
|
||||
type_name = "cbfs header";
|
||||
break;
|
||||
case CBFS_TYPE_STAGE:
|
||||
type_name = "stage";
|
||||
break;
|
||||
case CBFS_TYPE_PAYLOAD:
|
||||
type_name = "payload";
|
||||
break;
|
||||
case CBFS_TYPE_FIT:
|
||||
type_name = "fit";
|
||||
break;
|
||||
case CBFS_TYPE_OPTIONROM:
|
||||
type_name = "option rom";
|
||||
break;
|
||||
case CBFS_TYPE_BOOTSPLASH:
|
||||
type_name = "boot splash";
|
||||
break;
|
||||
case CBFS_TYPE_RAW:
|
||||
type_name = "raw";
|
||||
break;
|
||||
case CBFS_TYPE_VSA:
|
||||
type_name = "vsa";
|
||||
break;
|
||||
case CBFS_TYPE_MBI:
|
||||
type_name = "mbi";
|
||||
break;
|
||||
case CBFS_TYPE_MICROCODE:
|
||||
type_name = "microcode";
|
||||
break;
|
||||
case CBFS_TYPE_FSP:
|
||||
type_name = "fsp";
|
||||
break;
|
||||
case CBFS_TYPE_MRC:
|
||||
type_name = "mrc";
|
||||
break;
|
||||
case CBFS_TYPE_MMA:
|
||||
type_name = "mma";
|
||||
break;
|
||||
case CBFS_TYPE_EFI:
|
||||
type_name = "efi";
|
||||
break;
|
||||
case CBFS_TYPE_STRUCT:
|
||||
type_name = "struct";
|
||||
break;
|
||||
case CBFS_TYPE_CMOS_DEFAULT:
|
||||
type_name = "cmos default";
|
||||
break;
|
||||
case CBFS_TYPE_SPD:
|
||||
type_name = "spd";
|
||||
break;
|
||||
case CBFS_TYPE_MRC_CACHE:
|
||||
type_name = "mrc cache";
|
||||
break;
|
||||
case CBFS_TYPE_CMOS_LAYOUT:
|
||||
type_name = "cmos layout";
|
||||
break;
|
||||
case -1:
|
||||
case 0:
|
||||
type_name = "null";
|
||||
break;
|
||||
}
|
||||
if (type_name)
|
||||
printf(" %16s", type_name);
|
||||
else
|
||||
printf(" %16d", type);
|
||||
|
||||
if (filename[0])
|
||||
printf(" %s\n", filename);
|
||||
else
|
||||
printf(" %s\n", "(empty)");
|
||||
file_cbfs_get_next(&file);
|
||||
files++;
|
||||
}
|
||||
|
||||
printf("\n%d file(s)\n\n", files);
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
cbfsls, 1, 1, do_cbfs_ls,
|
||||
"list files",
|
||||
" - list the files in the cbfs\n"
|
||||
);
|
||||
|
||||
static int do_cbfs_fsinfo(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char *const argv[])
|
||||
{
|
||||
const struct cbfs_header *header = file_cbfs_get_header();
|
||||
|
||||
if (!header) {
|
||||
printf("%s.\n", file_cbfs_error());
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
printf("CBFS version: %#x\n", header->version);
|
||||
printf("ROM size: %#x\n", header->rom_size);
|
||||
printf("Boot block size: %#x\n", header->boot_block_size);
|
||||
printf("CBFS size: %#x\n",
|
||||
header->rom_size - header->boot_block_size - header->offset);
|
||||
printf("Alignment: %d\n", header->align);
|
||||
printf("Offset: %#x\n", header->offset);
|
||||
printf("\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
cbfsinfo, 1, 1, do_cbfs_fsinfo,
|
||||
"print information about filesystem",
|
||||
" - print information about the cbfs filesystem\n"
|
||||
);
|
||||
118
cmd/clk.c
Normal file
118
cmd/clk.c
Normal file
@@ -0,0 +1,118 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2013 Xilinx, Inc.
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <clk.h>
|
||||
#if defined(CONFIG_DM) && defined(CONFIG_CLK)
|
||||
#include <dm.h>
|
||||
#include <dm/device.h>
|
||||
#include <dm/root.h>
|
||||
#include <dm/device-internal.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_DM) && defined(CONFIG_CLK)
|
||||
static void show_clks(struct udevice *dev, int depth, int last_flag)
|
||||
{
|
||||
int i, is_last;
|
||||
struct udevice *child;
|
||||
struct clk *clkp;
|
||||
u32 rate;
|
||||
|
||||
clkp = dev_get_clk_ptr(dev);
|
||||
if (device_get_uclass_id(dev) == UCLASS_CLK && clkp) {
|
||||
rate = clk_get_rate(clkp);
|
||||
|
||||
printf(" %-12u %8d ", rate, clkp->enable_count);
|
||||
|
||||
for (i = depth; i >= 0; i--) {
|
||||
is_last = (last_flag >> i) & 1;
|
||||
if (i) {
|
||||
if (is_last)
|
||||
printf(" ");
|
||||
else
|
||||
printf("| ");
|
||||
} else {
|
||||
if (is_last)
|
||||
printf("`-- ");
|
||||
else
|
||||
printf("|-- ");
|
||||
}
|
||||
}
|
||||
|
||||
printf("%s\n", dev->name);
|
||||
}
|
||||
|
||||
list_for_each_entry(child, &dev->child_head, sibling_node) {
|
||||
is_last = list_is_last(&child->sibling_node, &dev->child_head);
|
||||
show_clks(child, depth + 1, (last_flag << 1) | is_last);
|
||||
}
|
||||
}
|
||||
|
||||
int __weak soc_clk_dump(void)
|
||||
{
|
||||
struct udevice *root;
|
||||
|
||||
root = dm_root();
|
||||
if (root) {
|
||||
printf(" Rate Usecnt Name\n");
|
||||
printf("------------------------------------------\n");
|
||||
show_clks(root, -1, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
int __weak soc_clk_dump(void)
|
||||
{
|
||||
puts("Not implemented\n");
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int do_clk_dump(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char *const argv[])
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = soc_clk_dump();
|
||||
if (ret < 0) {
|
||||
printf("Clock dump error %d\n", ret);
|
||||
ret = CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static cmd_tbl_t cmd_clk_sub[] = {
|
||||
U_BOOT_CMD_MKENT(dump, 1, 1, do_clk_dump, "", ""),
|
||||
};
|
||||
|
||||
static int do_clk(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char *const argv[])
|
||||
{
|
||||
cmd_tbl_t *c;
|
||||
|
||||
if (argc < 2)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
/* Strip off leading 'clk' command argument */
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
c = find_cmd_tbl(argv[0], &cmd_clk_sub[0], ARRAY_SIZE(cmd_clk_sub));
|
||||
|
||||
if (c)
|
||||
return c->cmd(cmdtp, flag, argc, argv);
|
||||
else
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SYS_LONGHELP
|
||||
static char clk_help_text[] =
|
||||
"dump - Print clock frequencies";
|
||||
#endif
|
||||
|
||||
U_BOOT_CMD(clk, 2, 1, do_clk, "CLK sub-system", clk_help_text);
|
||||
35
cmd/cls.c
Normal file
35
cmd/cls.c
Normal file
@@ -0,0 +1,35 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2018
|
||||
* DENX Software Engineering, Anatolij Gustschin <agust@denx.de>
|
||||
*
|
||||
* cls - clear screen command
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <dm.h>
|
||||
#include <lcd.h>
|
||||
#include <video.h>
|
||||
|
||||
static int do_video_clear(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char *const argv[])
|
||||
{
|
||||
#if defined(CONFIG_DM_VIDEO)
|
||||
struct udevice *dev;
|
||||
|
||||
if (uclass_first_device_err(UCLASS_VIDEO, &dev))
|
||||
return CMD_RET_FAILURE;
|
||||
|
||||
if (video_clear(dev))
|
||||
return CMD_RET_FAILURE;
|
||||
#elif defined(CONFIG_CFB_CONSOLE)
|
||||
video_clear();
|
||||
#elif defined(CONFIG_LCD)
|
||||
lcd_clear();
|
||||
#else
|
||||
return CMD_RET_FAILURE;
|
||||
#endif
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(cls, 1, 1, do_video_clear, "clear screen", "");
|
||||
44
cmd/config.c
Normal file
44
cmd/config.c
Normal file
@@ -0,0 +1,44 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2017 Masahiro Yamada <yamada.masahiro@socionext.com>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <gzip.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#include "config_data_gz.h"
|
||||
#include "config_data_size.h"
|
||||
|
||||
static int do_config(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
char *dst;
|
||||
unsigned long len = data_size;
|
||||
int ret = CMD_RET_SUCCESS;
|
||||
|
||||
dst = malloc(data_size + 1);
|
||||
if (!dst)
|
||||
return CMD_RET_FAILURE;
|
||||
|
||||
ret = gunzip(dst, data_size, (unsigned char *)data_gz, &len);
|
||||
if (ret) {
|
||||
printf("failed to uncompress .config data\n");
|
||||
ret = CMD_RET_FAILURE;
|
||||
goto free;
|
||||
}
|
||||
|
||||
dst[data_size] = 0;
|
||||
puts(dst);
|
||||
|
||||
free:
|
||||
free(dst);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
config, 1, 1, do_config,
|
||||
"print .config",
|
||||
""
|
||||
);
|
||||
51
cmd/conitrace.c
Normal file
51
cmd/conitrace.c
Normal file
@@ -0,0 +1,51 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* The 'conitrace' command prints the codes received from the console input as
|
||||
* hexadecimal numbers.
|
||||
*
|
||||
* Copyright (c) 2018, Heinrich Schuchardt <xypron.glpk@gmx.de>
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
|
||||
static int do_conitrace(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
bool first = true;
|
||||
|
||||
printf("Waiting for your input\n");
|
||||
printf("To terminate type 'x'\n");
|
||||
|
||||
/* Empty input buffer */
|
||||
while (tstc())
|
||||
getc();
|
||||
|
||||
for (;;) {
|
||||
int c = getc();
|
||||
|
||||
if (first && (c == 'x' || c == 'X'))
|
||||
break;
|
||||
|
||||
printf("%02x ", c);
|
||||
first = false;
|
||||
|
||||
/* 1 ms delay - serves to detect separate keystrokes */
|
||||
udelay(1000);
|
||||
if (!tstc()) {
|
||||
printf("\n");
|
||||
first = true;
|
||||
}
|
||||
}
|
||||
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SYS_LONGHELP
|
||||
static char conitrace_help_text[] = "";
|
||||
#endif
|
||||
|
||||
U_BOOT_CMD_COMPLETE(
|
||||
conitrace, 2, 0, do_conitrace,
|
||||
"trace console input",
|
||||
conitrace_help_text, NULL
|
||||
);
|
||||
52
cmd/console.c
Normal file
52
cmd/console.c
Normal file
@@ -0,0 +1,52 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2000
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Boot support
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <stdio_dev.h>
|
||||
|
||||
extern void _do_coninfo (void);
|
||||
static int do_coninfo(cmd_tbl_t *cmd, int flag, int argc, char * const argv[])
|
||||
{
|
||||
int l;
|
||||
struct list_head *list = stdio_get_list();
|
||||
struct list_head *pos;
|
||||
struct stdio_dev *dev;
|
||||
|
||||
/* Scan for valid output and input devices */
|
||||
|
||||
puts ("List of available devices:\n");
|
||||
|
||||
list_for_each(pos, list) {
|
||||
dev = list_entry(pos, struct stdio_dev, list);
|
||||
|
||||
printf ("%-8s %08x %c%c ",
|
||||
dev->name,
|
||||
dev->flags,
|
||||
(dev->flags & DEV_FLAGS_INPUT) ? 'I' : '.',
|
||||
(dev->flags & DEV_FLAGS_OUTPUT) ? 'O' : '.');
|
||||
|
||||
for (l = 0; l < MAX_FILES; l++) {
|
||||
if (stdio_devices[l] == dev) {
|
||||
printf ("%s ", stdio_names[l]);
|
||||
}
|
||||
}
|
||||
putc ('\n');
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************/
|
||||
|
||||
U_BOOT_CMD(
|
||||
coninfo, 3, 1, do_coninfo,
|
||||
"print console devices and information",
|
||||
""
|
||||
);
|
||||
117
cmd/cpu.c
Normal file
117
cmd/cpu.c
Normal file
@@ -0,0 +1,117 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2015 Google, Inc
|
||||
* Written by Simon Glass <sjg@chromium.org>
|
||||
* Copyright (c) 2017 Álvaro Fernández Rojas <noltari@gmail.com>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <cpu.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
|
||||
static const char *cpu_feature_name[CPU_FEAT_COUNT] = {
|
||||
"L1 cache",
|
||||
"MMU",
|
||||
"Microcode",
|
||||
"Device ID",
|
||||
};
|
||||
|
||||
static int print_cpu_list(bool detail)
|
||||
{
|
||||
struct udevice *dev;
|
||||
char buf[100];
|
||||
|
||||
for (uclass_first_device(UCLASS_CPU, &dev);
|
||||
dev;
|
||||
uclass_next_device(&dev)) {
|
||||
struct cpu_platdata *plat = dev_get_parent_platdata(dev);
|
||||
struct cpu_info info;
|
||||
bool first = true;
|
||||
int ret, i;
|
||||
|
||||
ret = cpu_get_desc(dev, buf, sizeof(buf));
|
||||
printf("%3d: %-10s %s\n", dev->seq, dev->name,
|
||||
ret ? "<no description>" : buf);
|
||||
if (!detail)
|
||||
continue;
|
||||
ret = cpu_get_info(dev, &info);
|
||||
if (ret) {
|
||||
printf("\t(no detail available");
|
||||
if (ret != -ENOSYS)
|
||||
printf(": err=%d", ret);
|
||||
printf(")\n");
|
||||
continue;
|
||||
}
|
||||
printf("\tID = %d, freq = ", plat->cpu_id);
|
||||
print_freq(info.cpu_freq, "");
|
||||
for (i = 0; i < CPU_FEAT_COUNT; i++) {
|
||||
if (info.features & (1 << i)) {
|
||||
printf("%s%s", first ? ": " : ", ",
|
||||
cpu_feature_name[i]);
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
if (info.features & (1 << CPU_FEAT_UCODE))
|
||||
printf("\tMicrocode version %#x\n",
|
||||
plat->ucode_version);
|
||||
if (info.features & (1 << CPU_FEAT_DEVICE_ID))
|
||||
printf("\tDevice ID %#lx\n", plat->device_id);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_cpu_list(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char *const argv[])
|
||||
{
|
||||
if (print_cpu_list(false))
|
||||
return CMD_RET_FAILURE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_cpu_detail(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char *const argv[])
|
||||
{
|
||||
if (print_cpu_list(true))
|
||||
return CMD_RET_FAILURE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static cmd_tbl_t cmd_cpu_sub[] = {
|
||||
U_BOOT_CMD_MKENT(list, 2, 1, do_cpu_list, "", ""),
|
||||
U_BOOT_CMD_MKENT(detail, 4, 0, do_cpu_detail, "", ""),
|
||||
};
|
||||
|
||||
/*
|
||||
* Process a cpu sub-command
|
||||
*/
|
||||
static int do_cpu(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
cmd_tbl_t *c = NULL;
|
||||
|
||||
/* Strip off leading 'cpu' command argument */
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
if (argc)
|
||||
c = find_cmd_tbl(argv[0], cmd_cpu_sub,
|
||||
ARRAY_SIZE(cmd_cpu_sub));
|
||||
|
||||
if (c)
|
||||
return c->cmd(cmdtp, flag, argc, argv);
|
||||
else
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
cpu, 2, 1, do_cpu,
|
||||
"display information about CPUs",
|
||||
"list - list available CPUs\n"
|
||||
"cpu detail - show CPU detail"
|
||||
);
|
||||
211
cmd/cramfs.c
Normal file
211
cmd/cramfs.c
Normal file
@@ -0,0 +1,211 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
*
|
||||
* based on: cmd_jffs2.c
|
||||
*
|
||||
* Add support for a CRAMFS located in RAM
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* CRAMFS support
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <env.h>
|
||||
#include <malloc.h>
|
||||
#include <mapmem.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <jffs2/jffs2.h>
|
||||
#include <jffs2/load_kernel.h>
|
||||
#include <cramfs/cramfs_fs.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
/* enable/disable debugging messages */
|
||||
#define DEBUG_CRAMFS
|
||||
#undef DEBUG_CRAMFS
|
||||
|
||||
#ifdef DEBUG_CRAMFS
|
||||
# define DEBUGF(fmt, args...) printf(fmt ,##args)
|
||||
#else
|
||||
# define DEBUGF(fmt, args...)
|
||||
#endif
|
||||
|
||||
#include <flash.h>
|
||||
|
||||
#ifndef CONFIG_MTD_NOR_FLASH
|
||||
# define OFFSET_ADJUSTMENT 0
|
||||
#else
|
||||
# define OFFSET_ADJUSTMENT (flash_info[id.num].start[0])
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_FS_JFFS2
|
||||
#include <linux/stat.h>
|
||||
char *mkmodestr(unsigned long mode, char *str)
|
||||
{
|
||||
static const char *l = "xwr";
|
||||
int mask = 1, i;
|
||||
char c;
|
||||
|
||||
switch (mode & S_IFMT) {
|
||||
case S_IFDIR: str[0] = 'd'; break;
|
||||
case S_IFBLK: str[0] = 'b'; break;
|
||||
case S_IFCHR: str[0] = 'c'; break;
|
||||
case S_IFIFO: str[0] = 'f'; break;
|
||||
case S_IFLNK: str[0] = 'l'; break;
|
||||
case S_IFSOCK: str[0] = 's'; break;
|
||||
case S_IFREG: str[0] = '-'; break;
|
||||
default: str[0] = '?';
|
||||
}
|
||||
|
||||
for(i = 0; i < 9; i++) {
|
||||
c = l[i%3];
|
||||
str[9-i] = (mode & mask)?c:'-';
|
||||
mask = mask<<1;
|
||||
}
|
||||
|
||||
if(mode & S_ISUID) str[3] = (mode & S_IXUSR)?'s':'S';
|
||||
if(mode & S_ISGID) str[6] = (mode & S_IXGRP)?'s':'S';
|
||||
if(mode & S_ISVTX) str[9] = (mode & S_IXOTH)?'t':'T';
|
||||
str[10] = '\0';
|
||||
return str;
|
||||
}
|
||||
#endif /* CONFIG_FS_JFFS2 */
|
||||
|
||||
extern int cramfs_check (struct part_info *info);
|
||||
extern int cramfs_load (char *loadoffset, struct part_info *info, char *filename);
|
||||
extern int cramfs_ls (struct part_info *info, char *filename);
|
||||
extern int cramfs_info (struct part_info *info);
|
||||
|
||||
/***************************************************/
|
||||
/* U-Boot commands */
|
||||
/***************************************************/
|
||||
|
||||
/**
|
||||
* Routine implementing fsload u-boot command. This routine tries to load
|
||||
* a requested file from cramfs filesystem at location 'cramfsaddr'.
|
||||
* cramfsaddr is an evironment variable.
|
||||
*
|
||||
* @param cmdtp command internal data
|
||||
* @param flag command flag
|
||||
* @param argc number of arguments supplied to the command
|
||||
* @param argv arguments list
|
||||
* @return 0 on success, 1 otherwise
|
||||
*/
|
||||
int do_cramfs_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
char *filename;
|
||||
int size;
|
||||
ulong offset = load_addr;
|
||||
char *offset_virt;
|
||||
|
||||
struct part_info part;
|
||||
struct mtd_device dev;
|
||||
struct mtdids id;
|
||||
|
||||
ulong addr;
|
||||
addr = simple_strtoul(env_get("cramfsaddr"), NULL, 16);
|
||||
|
||||
/* hack! */
|
||||
/* cramfs_* only supports NOR flash chips */
|
||||
/* fake the device type */
|
||||
id.type = MTD_DEV_TYPE_NOR;
|
||||
id.num = 0;
|
||||
dev.id = &id;
|
||||
part.dev = &dev;
|
||||
/* fake the address offset */
|
||||
part.offset = (u64)(uintptr_t) map_sysmem(addr - OFFSET_ADJUSTMENT, 0);
|
||||
|
||||
/* pre-set Boot file name */
|
||||
filename = env_get("bootfile");
|
||||
if (!filename)
|
||||
filename = "uImage";
|
||||
|
||||
if (argc == 2) {
|
||||
filename = argv[1];
|
||||
}
|
||||
if (argc == 3) {
|
||||
offset = simple_strtoul(argv[1], NULL, 0);
|
||||
load_addr = offset;
|
||||
filename = argv[2];
|
||||
}
|
||||
|
||||
offset_virt = map_sysmem(offset, 0);
|
||||
size = 0;
|
||||
if (cramfs_check(&part))
|
||||
size = cramfs_load (offset_virt, &part, filename);
|
||||
|
||||
if (size > 0) {
|
||||
printf("### CRAMFS load complete: %d bytes loaded to 0x%lx\n",
|
||||
size, offset);
|
||||
env_set_hex("filesize", size);
|
||||
} else {
|
||||
printf("### CRAMFS LOAD ERROR<%x> for %s!\n", size, filename);
|
||||
}
|
||||
|
||||
unmap_sysmem(offset_virt);
|
||||
unmap_sysmem((void *)(uintptr_t)part.offset);
|
||||
|
||||
return !(size > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Routine implementing u-boot ls command which lists content of a given
|
||||
* directory at location 'cramfsaddr'.
|
||||
* cramfsaddr is an evironment variable.
|
||||
*
|
||||
* @param cmdtp command internal data
|
||||
* @param flag command flag
|
||||
* @param argc number of arguments supplied to the command
|
||||
* @param argv arguments list
|
||||
* @return 0 on success, 1 otherwise
|
||||
*/
|
||||
int do_cramfs_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
char *filename = "/";
|
||||
int ret;
|
||||
struct part_info part;
|
||||
struct mtd_device dev;
|
||||
struct mtdids id;
|
||||
|
||||
ulong addr;
|
||||
addr = simple_strtoul(env_get("cramfsaddr"), NULL, 16);
|
||||
|
||||
/* hack! */
|
||||
/* cramfs_* only supports NOR flash chips */
|
||||
/* fake the device type */
|
||||
id.type = MTD_DEV_TYPE_NOR;
|
||||
id.num = 0;
|
||||
dev.id = &id;
|
||||
part.dev = &dev;
|
||||
/* fake the address offset */
|
||||
part.offset = (u64)(uintptr_t) map_sysmem(addr - OFFSET_ADJUSTMENT, 0);
|
||||
|
||||
if (argc == 2)
|
||||
filename = argv[1];
|
||||
|
||||
ret = 0;
|
||||
if (cramfs_check(&part))
|
||||
ret = cramfs_ls (&part, filename);
|
||||
unmap_sysmem((void *)(uintptr_t)part.offset);
|
||||
|
||||
return ret ? 0 : 1;
|
||||
}
|
||||
|
||||
/* command line only */
|
||||
|
||||
/***************************************************/
|
||||
U_BOOT_CMD(
|
||||
cramfsload, 3, 0, do_cramfs_load,
|
||||
"load binary file from a filesystem image",
|
||||
"[ off ] [ filename ]\n"
|
||||
" - load binary file from address 'cramfsaddr'\n"
|
||||
" with offset 'off'\n"
|
||||
);
|
||||
U_BOOT_CMD(
|
||||
cramfsls, 2, 1, do_cramfs_ls,
|
||||
"list files in a directory (default /)",
|
||||
"[ directory ]\n"
|
||||
" - list files in a directory.\n"
|
||||
);
|
||||
384
cmd/cros_ec.c
Normal file
384
cmd/cros_ec.c
Normal file
@@ -0,0 +1,384 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Chromium OS cros_ec driver
|
||||
*
|
||||
* Copyright (c) 2016 The Chromium OS Authors.
|
||||
* Copyright (c) 2016 National Instruments Corp
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <cros_ec.h>
|
||||
#include <dm.h>
|
||||
#include <dm/device-internal.h>
|
||||
#include <dm/uclass-internal.h>
|
||||
|
||||
/* Note: depends on enum ec_current_image */
|
||||
static const char * const ec_current_image_name[] = {"unknown", "RO", "RW"};
|
||||
|
||||
/**
|
||||
* Decode a flash region parameter
|
||||
*
|
||||
* @param argc Number of params remaining
|
||||
* @param argv List of remaining parameters
|
||||
* @return flash region (EC_FLASH_REGION_...) or -1 on error
|
||||
*/
|
||||
static int cros_ec_decode_region(int argc, char * const argv[])
|
||||
{
|
||||
if (argc > 0) {
|
||||
if (0 == strcmp(*argv, "rw"))
|
||||
return EC_FLASH_REGION_ACTIVE;
|
||||
else if (0 == strcmp(*argv, "ro"))
|
||||
return EC_FLASH_REGION_RO;
|
||||
|
||||
debug("%s: Invalid region '%s'\n", __func__, *argv);
|
||||
} else {
|
||||
debug("%s: Missing region parameter\n", __func__);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a flash read or write command
|
||||
*
|
||||
* @param dev CROS-EC device to read/write
|
||||
* @param is_write 1 do to a write, 0 to do a read
|
||||
* @param argc Number of arguments
|
||||
* @param argv Arguments (2 is region, 3 is address)
|
||||
* @return 0 for ok, 1 for a usage error or -ve for ec command error
|
||||
* (negative EC_RES_...)
|
||||
*/
|
||||
static int do_read_write(struct udevice *dev, int is_write, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
uint32_t offset, size = -1U, region_size;
|
||||
unsigned long addr;
|
||||
char *endp;
|
||||
int region;
|
||||
int ret;
|
||||
|
||||
region = cros_ec_decode_region(argc - 2, argv + 2);
|
||||
if (region == -1)
|
||||
return 1;
|
||||
if (argc < 4)
|
||||
return 1;
|
||||
addr = simple_strtoul(argv[3], &endp, 16);
|
||||
if (*argv[3] == 0 || *endp != 0)
|
||||
return 1;
|
||||
if (argc > 4) {
|
||||
size = simple_strtoul(argv[4], &endp, 16);
|
||||
if (*argv[4] == 0 || *endp != 0)
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = cros_ec_flash_offset(dev, region, &offset, ®ion_size);
|
||||
if (ret) {
|
||||
debug("%s: Could not read region info\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
if (size == -1U)
|
||||
size = region_size;
|
||||
|
||||
ret = is_write ?
|
||||
cros_ec_flash_write(dev, (uint8_t *)addr, offset, size) :
|
||||
cros_ec_flash_read(dev, (uint8_t *)addr, offset, size);
|
||||
if (ret) {
|
||||
debug("%s: Could not %s region\n", __func__,
|
||||
is_write ? "write" : "read");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_cros_ec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
struct udevice *dev;
|
||||
const char *cmd;
|
||||
int ret = 0;
|
||||
|
||||
if (argc < 2)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
cmd = argv[1];
|
||||
if (0 == strcmp("init", cmd)) {
|
||||
/* Remove any existing device */
|
||||
ret = uclass_find_device(UCLASS_CROS_EC, 0, &dev);
|
||||
if (!ret)
|
||||
device_remove(dev, DM_REMOVE_NORMAL);
|
||||
ret = uclass_get_device(UCLASS_CROS_EC, 0, &dev);
|
||||
if (ret) {
|
||||
printf("Could not init cros_ec device (err %d)\n", ret);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = uclass_get_device(UCLASS_CROS_EC, 0, &dev);
|
||||
if (ret) {
|
||||
printf("Cannot get cros-ec device (err=%d)\n", ret);
|
||||
return 1;
|
||||
}
|
||||
if (0 == strcmp("id", cmd)) {
|
||||
char id[MSG_BYTES];
|
||||
|
||||
if (cros_ec_read_id(dev, id, sizeof(id))) {
|
||||
debug("%s: Could not read KBC ID\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
printf("%s\n", id);
|
||||
} else if (0 == strcmp("info", cmd)) {
|
||||
struct ec_response_mkbp_info info;
|
||||
|
||||
if (cros_ec_info(dev, &info)) {
|
||||
debug("%s: Could not read KBC info\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
printf("rows = %u\n", info.rows);
|
||||
printf("cols = %u\n", info.cols);
|
||||
} else if (0 == strcmp("curimage", cmd)) {
|
||||
enum ec_current_image image;
|
||||
|
||||
if (cros_ec_read_current_image(dev, &image)) {
|
||||
debug("%s: Could not read KBC image\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
printf("%d\n", image);
|
||||
} else if (0 == strcmp("hash", cmd)) {
|
||||
struct ec_response_vboot_hash hash;
|
||||
int i;
|
||||
|
||||
if (cros_ec_read_hash(dev, EC_VBOOT_HASH_OFFSET_ACTIVE, &hash)) {
|
||||
debug("%s: Could not read KBC hash\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (hash.hash_type == EC_VBOOT_HASH_TYPE_SHA256)
|
||||
printf("type: SHA-256\n");
|
||||
else
|
||||
printf("type: %d\n", hash.hash_type);
|
||||
|
||||
printf("offset: 0x%08x\n", hash.offset);
|
||||
printf("size: 0x%08x\n", hash.size);
|
||||
|
||||
printf("digest: ");
|
||||
for (i = 0; i < hash.digest_size; i++)
|
||||
printf("%02x", hash.hash_digest[i]);
|
||||
printf("\n");
|
||||
} else if (0 == strcmp("reboot", cmd)) {
|
||||
int region;
|
||||
enum ec_reboot_cmd cmd;
|
||||
|
||||
if (argc >= 3 && !strcmp(argv[2], "cold")) {
|
||||
cmd = EC_REBOOT_COLD;
|
||||
} else {
|
||||
region = cros_ec_decode_region(argc - 2, argv + 2);
|
||||
if (region == EC_FLASH_REGION_RO)
|
||||
cmd = EC_REBOOT_JUMP_RO;
|
||||
else if (region == EC_FLASH_REGION_ACTIVE)
|
||||
cmd = EC_REBOOT_JUMP_RW;
|
||||
else
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
if (cros_ec_reboot(dev, cmd, 0)) {
|
||||
debug("%s: Could not reboot KBC\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
} else if (0 == strcmp("events", cmd)) {
|
||||
uint32_t events;
|
||||
|
||||
if (cros_ec_get_host_events(dev, &events)) {
|
||||
debug("%s: Could not read host events\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
printf("0x%08x\n", events);
|
||||
} else if (0 == strcmp("clrevents", cmd)) {
|
||||
uint32_t events = 0x7fffffff;
|
||||
|
||||
if (argc >= 3)
|
||||
events = simple_strtol(argv[2], NULL, 0);
|
||||
|
||||
if (cros_ec_clear_host_events(dev, events)) {
|
||||
debug("%s: Could not clear host events\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
} else if (0 == strcmp("read", cmd)) {
|
||||
ret = do_read_write(dev, 0, argc, argv);
|
||||
if (ret > 0)
|
||||
return CMD_RET_USAGE;
|
||||
} else if (0 == strcmp("write", cmd)) {
|
||||
ret = do_read_write(dev, 1, argc, argv);
|
||||
if (ret > 0)
|
||||
return CMD_RET_USAGE;
|
||||
} else if (0 == strcmp("erase", cmd)) {
|
||||
int region = cros_ec_decode_region(argc - 2, argv + 2);
|
||||
uint32_t offset, size;
|
||||
|
||||
if (region == -1)
|
||||
return CMD_RET_USAGE;
|
||||
if (cros_ec_flash_offset(dev, region, &offset, &size)) {
|
||||
debug("%s: Could not read region info\n", __func__);
|
||||
ret = -1;
|
||||
} else {
|
||||
ret = cros_ec_flash_erase(dev, offset, size);
|
||||
if (ret) {
|
||||
debug("%s: Could not erase region\n",
|
||||
__func__);
|
||||
}
|
||||
}
|
||||
} else if (0 == strcmp("regioninfo", cmd)) {
|
||||
int region = cros_ec_decode_region(argc - 2, argv + 2);
|
||||
uint32_t offset, size;
|
||||
|
||||
if (region == -1)
|
||||
return CMD_RET_USAGE;
|
||||
ret = cros_ec_flash_offset(dev, region, &offset, &size);
|
||||
if (ret) {
|
||||
debug("%s: Could not read region info\n", __func__);
|
||||
} else {
|
||||
printf("Region: %s\n", region == EC_FLASH_REGION_RO ?
|
||||
"RO" : "RW");
|
||||
printf("Offset: %x\n", offset);
|
||||
printf("Size: %x\n", size);
|
||||
}
|
||||
} else if (0 == strcmp("flashinfo", cmd)) {
|
||||
struct ec_response_flash_info p;
|
||||
|
||||
ret = cros_ec_read_flashinfo(dev, &p);
|
||||
if (!ret) {
|
||||
printf("Flash size: %u\n", p.flash_size);
|
||||
printf("Write block size: %u\n", p.write_block_size);
|
||||
printf("Erase block size: %u\n", p.erase_block_size);
|
||||
}
|
||||
} else if (0 == strcmp("vbnvcontext", cmd)) {
|
||||
uint8_t block[EC_VBNV_BLOCK_SIZE];
|
||||
char buf[3];
|
||||
int i, len;
|
||||
unsigned long result;
|
||||
|
||||
if (argc <= 2) {
|
||||
ret = cros_ec_read_nvdata(dev, block,
|
||||
EC_VBNV_BLOCK_SIZE);
|
||||
if (!ret) {
|
||||
printf("vbnv_block: ");
|
||||
for (i = 0; i < EC_VBNV_BLOCK_SIZE; i++)
|
||||
printf("%02x", block[i]);
|
||||
putc('\n');
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* TODO(clchiou): Move this to a utility function as
|
||||
* cmd_spi might want to call it.
|
||||
*/
|
||||
memset(block, 0, EC_VBNV_BLOCK_SIZE);
|
||||
len = strlen(argv[2]);
|
||||
buf[2] = '\0';
|
||||
for (i = 0; i < EC_VBNV_BLOCK_SIZE; i++) {
|
||||
if (i * 2 >= len)
|
||||
break;
|
||||
buf[0] = argv[2][i * 2];
|
||||
if (i * 2 + 1 >= len)
|
||||
buf[1] = '0';
|
||||
else
|
||||
buf[1] = argv[2][i * 2 + 1];
|
||||
strict_strtoul(buf, 16, &result);
|
||||
block[i] = result;
|
||||
}
|
||||
ret = cros_ec_write_nvdata(dev, block,
|
||||
EC_VBNV_BLOCK_SIZE);
|
||||
}
|
||||
if (ret) {
|
||||
debug("%s: Could not %s VbNvContext\n", __func__,
|
||||
argc <= 2 ? "read" : "write");
|
||||
}
|
||||
} else if (0 == strcmp("test", cmd)) {
|
||||
int result = cros_ec_test(dev);
|
||||
|
||||
if (result)
|
||||
printf("Test failed with error %d\n", result);
|
||||
else
|
||||
puts("Test passed\n");
|
||||
} else if (0 == strcmp("version", cmd)) {
|
||||
struct ec_response_get_version *p;
|
||||
char *build_string;
|
||||
|
||||
ret = cros_ec_read_version(dev, &p);
|
||||
if (!ret) {
|
||||
/* Print versions */
|
||||
printf("RO version: %1.*s\n",
|
||||
(int)sizeof(p->version_string_ro),
|
||||
p->version_string_ro);
|
||||
printf("RW version: %1.*s\n",
|
||||
(int)sizeof(p->version_string_rw),
|
||||
p->version_string_rw);
|
||||
printf("Firmware copy: %s\n",
|
||||
(p->current_image <
|
||||
ARRAY_SIZE(ec_current_image_name) ?
|
||||
ec_current_image_name[p->current_image] :
|
||||
"?"));
|
||||
ret = cros_ec_read_build_info(dev, &build_string);
|
||||
if (!ret)
|
||||
printf("Build info: %s\n", build_string);
|
||||
}
|
||||
} else if (0 == strcmp("ldo", cmd)) {
|
||||
uint8_t index, state;
|
||||
char *endp;
|
||||
|
||||
if (argc < 3)
|
||||
return CMD_RET_USAGE;
|
||||
index = simple_strtoul(argv[2], &endp, 10);
|
||||
if (*argv[2] == 0 || *endp != 0)
|
||||
return CMD_RET_USAGE;
|
||||
if (argc > 3) {
|
||||
state = simple_strtoul(argv[3], &endp, 10);
|
||||
if (*argv[3] == 0 || *endp != 0)
|
||||
return CMD_RET_USAGE;
|
||||
ret = cros_ec_set_ldo(dev, index, state);
|
||||
} else {
|
||||
ret = cros_ec_get_ldo(dev, index, &state);
|
||||
if (!ret) {
|
||||
printf("LDO%d: %s\n", index,
|
||||
state == EC_LDO_STATE_ON ?
|
||||
"on" : "off");
|
||||
}
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
debug("%s: Could not access LDO%d\n", __func__, index);
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
printf("Error: CROS-EC command failed (error %d)\n", ret);
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
crosec, 6, 1, do_cros_ec,
|
||||
"CROS-EC utility command",
|
||||
"init Re-init CROS-EC (done on startup automatically)\n"
|
||||
"crosec id Read CROS-EC ID\n"
|
||||
"crosec info Read CROS-EC info\n"
|
||||
"crosec curimage Read CROS-EC current image\n"
|
||||
"crosec hash Read CROS-EC hash\n"
|
||||
"crosec reboot [rw | ro | cold] Reboot CROS-EC\n"
|
||||
"crosec events Read CROS-EC host events\n"
|
||||
"crosec clrevents [mask] Clear CROS-EC host events\n"
|
||||
"crosec regioninfo <ro|rw> Read image info\n"
|
||||
"crosec flashinfo Read flash info\n"
|
||||
"crosec erase <ro|rw> Erase EC image\n"
|
||||
"crosec read <ro|rw> <addr> [<size>] Read EC image\n"
|
||||
"crosec write <ro|rw> <addr> [<size>] Write EC image\n"
|
||||
"crosec vbnvcontext [hexstring] Read [write] VbNvContext from EC\n"
|
||||
"crosec ldo <idx> [<state>] Switch/Read LDO state\n"
|
||||
"crosec test run tests on cros_ec\n"
|
||||
"crosec version Read CROS-EC version"
|
||||
);
|
||||
47
cmd/dataflash_mmc_mux.c
Normal file
47
cmd/dataflash_mmc_mux.c
Normal file
@@ -0,0 +1,47 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2000
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
|
||||
static int mmc_nspi (const char *);
|
||||
|
||||
int do_dataflash_mmc_mux (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
switch (argc) {
|
||||
case 2: /* on / off */
|
||||
switch (mmc_nspi (argv[1])) {
|
||||
case 0: AT91F_SelectSPI ();
|
||||
break;
|
||||
case 1: AT91F_SelectMMC ();
|
||||
break;
|
||||
}
|
||||
case 1: /* get status */
|
||||
printf ("Mux is configured to be %s\n",
|
||||
AT91F_GetMuxStatus () ? "MMC" : "SPI");
|
||||
return 0;
|
||||
default:
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mmc_nspi (const char *s)
|
||||
{
|
||||
if (strcmp (s, "mmc") == 0) {
|
||||
return 1;
|
||||
} else if (strcmp (s, "spi") == 0) {
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
dataflash_mmc_mux, 2, 1, do_dataflash_mmc_mux,
|
||||
"enable or disable MMC or SPI\n",
|
||||
"[mmc, spi]\n"
|
||||
" - enable or disable MMC or SPI"
|
||||
);
|
||||
249
cmd/date.c
Normal file
249
cmd/date.c
Normal file
@@ -0,0 +1,249 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2001
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*/
|
||||
|
||||
/*
|
||||
* RTC, Date & Time support: get and set date & time
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <dm.h>
|
||||
#include <rtc.h>
|
||||
#include <i2c.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
static const char * const weekdays[] = {
|
||||
"Sun", "Mon", "Tues", "Wednes", "Thurs", "Fri", "Satur",
|
||||
};
|
||||
|
||||
#ifdef CONFIG_NEEDS_MANUAL_RELOC
|
||||
#define RELOC(a) ((typeof(a))((unsigned long)(a) + gd->reloc_off))
|
||||
#else
|
||||
#define RELOC(a) a
|
||||
#endif
|
||||
|
||||
int mk_date (const char *, struct rtc_time *);
|
||||
|
||||
static struct rtc_time default_tm = { 0, 0, 0, 1, 1, 2000, 6, 0, 0 };
|
||||
|
||||
static int do_date(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
struct rtc_time tm;
|
||||
int rcode = 0;
|
||||
int old_bus __maybe_unused;
|
||||
|
||||
/* switch to correct I2C bus */
|
||||
#ifdef CONFIG_DM_RTC
|
||||
struct udevice *dev;
|
||||
|
||||
rcode = uclass_get_device(UCLASS_RTC, 0, &dev);
|
||||
if (rcode) {
|
||||
printf("Cannot find RTC: err=%d\n", rcode);
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
#elif defined(CONFIG_SYS_I2C)
|
||||
old_bus = i2c_get_bus_num();
|
||||
i2c_set_bus_num(CONFIG_SYS_RTC_BUS_NUM);
|
||||
#else
|
||||
old_bus = I2C_GET_BUS();
|
||||
I2C_SET_BUS(CONFIG_SYS_RTC_BUS_NUM);
|
||||
#endif
|
||||
|
||||
switch (argc) {
|
||||
case 2: /* set date & time */
|
||||
if (strcmp(argv[1],"reset") == 0) {
|
||||
puts ("Reset RTC...\n");
|
||||
#ifdef CONFIG_DM_RTC
|
||||
rcode = dm_rtc_reset(dev);
|
||||
if (!rcode)
|
||||
rcode = dm_rtc_set(dev, &default_tm);
|
||||
#else
|
||||
rtc_reset();
|
||||
rcode = rtc_set(&default_tm);
|
||||
#endif
|
||||
if (rcode)
|
||||
puts("## Failed to set date after RTC reset\n");
|
||||
} else {
|
||||
/* initialize tm with current time */
|
||||
#ifdef CONFIG_DM_RTC
|
||||
rcode = dm_rtc_get(dev, &tm);
|
||||
#else
|
||||
rcode = rtc_get(&tm);
|
||||
#endif
|
||||
if (!rcode) {
|
||||
/* insert new date & time */
|
||||
if (mk_date(argv[1], &tm) != 0) {
|
||||
puts ("## Bad date format\n");
|
||||
break;
|
||||
}
|
||||
/* and write to RTC */
|
||||
#ifdef CONFIG_DM_RTC
|
||||
rcode = dm_rtc_set(dev, &tm);
|
||||
#else
|
||||
rcode = rtc_set(&tm);
|
||||
#endif
|
||||
if (rcode) {
|
||||
printf("## Set date failed: err=%d\n",
|
||||
rcode);
|
||||
}
|
||||
} else {
|
||||
puts("## Get date failed\n");
|
||||
}
|
||||
}
|
||||
/* FALL TROUGH */
|
||||
case 1: /* get date & time */
|
||||
#ifdef CONFIG_DM_RTC
|
||||
rcode = dm_rtc_get(dev, &tm);
|
||||
#else
|
||||
rcode = rtc_get(&tm);
|
||||
#endif
|
||||
if (rcode) {
|
||||
puts("## Get date failed\n");
|
||||
break;
|
||||
}
|
||||
|
||||
printf ("Date: %4d-%02d-%02d (%sday) Time: %2d:%02d:%02d\n",
|
||||
tm.tm_year, tm.tm_mon, tm.tm_mday,
|
||||
(tm.tm_wday<0 || tm.tm_wday>6) ?
|
||||
"unknown " : RELOC(weekdays[tm.tm_wday]),
|
||||
tm.tm_hour, tm.tm_min, tm.tm_sec);
|
||||
|
||||
break;
|
||||
default:
|
||||
rcode = CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
/* switch back to original I2C bus */
|
||||
#ifdef CONFIG_SYS_I2C
|
||||
i2c_set_bus_num(old_bus);
|
||||
#elif !defined(CONFIG_DM_RTC)
|
||||
I2C_SET_BUS(old_bus);
|
||||
#endif
|
||||
|
||||
return rcode ? CMD_RET_FAILURE : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* simple conversion of two-digit string with error checking
|
||||
*/
|
||||
static int cnvrt2 (const char *str, int *valp)
|
||||
{
|
||||
int val;
|
||||
|
||||
if ((*str < '0') || (*str > '9'))
|
||||
return (-1);
|
||||
|
||||
val = *str - '0';
|
||||
|
||||
++str;
|
||||
|
||||
if ((*str < '0') || (*str > '9'))
|
||||
return (-1);
|
||||
|
||||
*valp = 10 * val + (*str - '0');
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert date string: MMDDhhmm[[CC]YY][.ss]
|
||||
*
|
||||
* Some basic checking for valid values is done, but this will not catch
|
||||
* all possible error conditions.
|
||||
*/
|
||||
int mk_date (const char *datestr, struct rtc_time *tmp)
|
||||
{
|
||||
int len, val;
|
||||
char *ptr;
|
||||
|
||||
ptr = strchr(datestr, '.');
|
||||
len = strlen(datestr);
|
||||
|
||||
/* Set seconds */
|
||||
if (ptr) {
|
||||
int sec;
|
||||
|
||||
ptr++;
|
||||
if ((len - (ptr - datestr)) != 2)
|
||||
return (-1);
|
||||
|
||||
len -= 3;
|
||||
|
||||
if (cnvrt2 (ptr, &sec))
|
||||
return (-1);
|
||||
|
||||
tmp->tm_sec = sec;
|
||||
} else {
|
||||
tmp->tm_sec = 0;
|
||||
}
|
||||
|
||||
if (len == 12) { /* MMDDhhmmCCYY */
|
||||
int year, century;
|
||||
|
||||
if (cnvrt2 (datestr+ 8, ¢ury) ||
|
||||
cnvrt2 (datestr+10, &year) ) {
|
||||
return (-1);
|
||||
}
|
||||
tmp->tm_year = 100 * century + year;
|
||||
} else if (len == 10) { /* MMDDhhmmYY */
|
||||
int year, century;
|
||||
|
||||
century = tmp->tm_year / 100;
|
||||
if (cnvrt2 (datestr+ 8, &year))
|
||||
return (-1);
|
||||
tmp->tm_year = 100 * century + year;
|
||||
}
|
||||
|
||||
switch (len) {
|
||||
case 8: /* MMDDhhmm */
|
||||
/* fall thru */
|
||||
case 10: /* MMDDhhmmYY */
|
||||
/* fall thru */
|
||||
case 12: /* MMDDhhmmCCYY */
|
||||
if (cnvrt2 (datestr+0, &val) ||
|
||||
val > 12) {
|
||||
break;
|
||||
}
|
||||
tmp->tm_mon = val;
|
||||
if (cnvrt2 (datestr+2, &val) ||
|
||||
val > ((tmp->tm_mon==2) ? 29 : 31)) {
|
||||
break;
|
||||
}
|
||||
tmp->tm_mday = val;
|
||||
|
||||
if (cnvrt2 (datestr+4, &val) ||
|
||||
val > 23) {
|
||||
break;
|
||||
}
|
||||
tmp->tm_hour = val;
|
||||
|
||||
if (cnvrt2 (datestr+6, &val) ||
|
||||
val > 59) {
|
||||
break;
|
||||
}
|
||||
tmp->tm_min = val;
|
||||
|
||||
/* calculate day of week */
|
||||
rtc_calc_weekday(tmp);
|
||||
|
||||
return (0);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/***************************************************/
|
||||
|
||||
U_BOOT_CMD(
|
||||
date, 2, 1, do_date,
|
||||
"get/set/reset date & time",
|
||||
"[MMDDhhmm[[CC]YY][.ss]]\ndate reset\n"
|
||||
" - without arguments: print date & time\n"
|
||||
" - with numeric argument: set the system date & time\n"
|
||||
" - with 'reset' argument: reset the RTC"
|
||||
);
|
||||
1195
cmd/ddrscan.c
Normal file
1195
cmd/ddrscan.c
Normal file
File diff suppressed because it is too large
Load Diff
131
cmd/demo.c
Normal file
131
cmd/demo.c
Normal file
@@ -0,0 +1,131 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2013 Google, Inc
|
||||
*
|
||||
* (C) Copyright 2012
|
||||
* Pavel Herrmann <morpheus.ibis@gmail.com>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm-demo.h>
|
||||
#include <mapmem.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
struct udevice *demo_dev;
|
||||
|
||||
static int do_demo_hello(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
int ch = 0;
|
||||
|
||||
if (argc)
|
||||
ch = *argv[0];
|
||||
|
||||
return demo_hello(demo_dev, ch);
|
||||
}
|
||||
|
||||
static int do_demo_status(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
int status;
|
||||
int ret;
|
||||
|
||||
ret = demo_status(demo_dev, &status);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
printf("Status: %d\n", status);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_demo_light(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
int light;
|
||||
int ret;
|
||||
|
||||
if (argc) {
|
||||
light = simple_strtoul(argv[0], NULL, 16);
|
||||
ret = demo_set_light(demo_dev, light);
|
||||
} else {
|
||||
ret = demo_get_light(demo_dev);
|
||||
if (ret >= 0) {
|
||||
printf("Light: %x\n", ret);
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int do_demo_list(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
struct udevice *dev;
|
||||
int i, ret;
|
||||
|
||||
puts("Demo uclass entries:\n");
|
||||
|
||||
for (i = 0, ret = uclass_first_device(UCLASS_DEMO, &dev);
|
||||
dev;
|
||||
ret = uclass_next_device(&dev)) {
|
||||
printf("entry %d - instance %08x, ops %08x, platdata %08x\n",
|
||||
i++, (uint)map_to_sysmem(dev),
|
||||
(uint)map_to_sysmem(dev->driver->ops),
|
||||
(uint)map_to_sysmem(dev_get_platdata(dev)));
|
||||
}
|
||||
|
||||
return cmd_process_error(cmdtp, ret);
|
||||
}
|
||||
|
||||
static cmd_tbl_t demo_commands[] = {
|
||||
U_BOOT_CMD_MKENT(list, 0, 1, do_demo_list, "", ""),
|
||||
U_BOOT_CMD_MKENT(hello, 2, 1, do_demo_hello, "", ""),
|
||||
U_BOOT_CMD_MKENT(light, 2, 1, do_demo_light, "", ""),
|
||||
U_BOOT_CMD_MKENT(status, 1, 1, do_demo_status, "", ""),
|
||||
};
|
||||
|
||||
static int do_demo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
cmd_tbl_t *demo_cmd;
|
||||
int devnum = 0;
|
||||
int ret;
|
||||
|
||||
if (argc < 2)
|
||||
return CMD_RET_USAGE;
|
||||
demo_cmd = find_cmd_tbl(argv[1], demo_commands,
|
||||
ARRAY_SIZE(demo_commands));
|
||||
argc -= 2;
|
||||
argv += 2;
|
||||
|
||||
if ((!demo_cmd || argc > demo_cmd->maxargs) ||
|
||||
((demo_cmd->name[0] != 'l') && (argc < 1)))
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
if (argc) {
|
||||
devnum = simple_strtoul(argv[0], NULL, 10);
|
||||
ret = uclass_get_device(UCLASS_DEMO, devnum, &demo_dev);
|
||||
if (ret)
|
||||
return cmd_process_error(cmdtp, ret);
|
||||
argc--;
|
||||
argv++;
|
||||
} else {
|
||||
demo_dev = NULL;
|
||||
if (demo_cmd->cmd != do_demo_list)
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
ret = demo_cmd->cmd(demo_cmd, flag, argc, argv);
|
||||
|
||||
return cmd_process_error(demo_cmd, ret);
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
demo, 4, 1, do_demo,
|
||||
"Driver model (dm) demo operations",
|
||||
"list List available demo devices\n"
|
||||
"demo hello <num> [<char>] Say hello\n"
|
||||
"demo light [<num>] Set or get the lights\n"
|
||||
"demo status <num> Get demo device status\n"
|
||||
"demo list List available demo devices"
|
||||
);
|
||||
91
cmd/dfu.c
Normal file
91
cmd/dfu.c
Normal file
@@ -0,0 +1,91 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* cmd_dfu.c -- dfu command
|
||||
*
|
||||
* Copyright (C) 2015
|
||||
* Lukasz Majewski <l.majewski@majess.pl>
|
||||
*
|
||||
* Copyright (C) 2012 Samsung Electronics
|
||||
* authors: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
|
||||
* Lukasz Majewski <l.majewski@samsung.com>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <watchdog.h>
|
||||
#include <dfu.h>
|
||||
#include <console.h>
|
||||
#include <g_dnl.h>
|
||||
#include <usb.h>
|
||||
#include <net.h>
|
||||
|
||||
static int do_dfu(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
|
||||
if (argc < 2)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
#ifdef CONFIG_DFU_OVER_USB
|
||||
char *usb_controller = argv[1];
|
||||
#endif
|
||||
#if defined(CONFIG_DFU_OVER_USB) || defined(CONFIG_DFU_OVER_TFTP)
|
||||
char *interface = NULL;
|
||||
char *devstring = NULL;
|
||||
|
||||
if (argc >= 4) {
|
||||
interface = argv[2];
|
||||
devstring = argv[3];
|
||||
}
|
||||
#endif
|
||||
|
||||
int ret = 0;
|
||||
#ifdef CONFIG_DFU_OVER_TFTP
|
||||
unsigned long addr = 0;
|
||||
if (!strcmp(argv[1], "tftp")) {
|
||||
if (argc == 5 || argc == 3)
|
||||
addr = simple_strtoul(argv[argc - 1], NULL, 0);
|
||||
|
||||
return update_tftp(addr, interface, devstring);
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_DFU_OVER_USB
|
||||
ret = dfu_init_env_entities(interface, devstring);
|
||||
if (ret)
|
||||
goto done;
|
||||
|
||||
ret = CMD_RET_SUCCESS;
|
||||
if (strcmp(argv[argc - 1], "list") == 0) {
|
||||
dfu_show_entities();
|
||||
goto done;
|
||||
}
|
||||
|
||||
int controller_index = simple_strtoul(usb_controller, NULL, 0);
|
||||
|
||||
run_usb_dnl_gadget(controller_index, "usb_dnl_dfu");
|
||||
|
||||
done:
|
||||
dfu_free_entities();
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(dfu, CONFIG_SYS_MAXARGS, 1, do_dfu,
|
||||
"Device Firmware Upgrade",
|
||||
""
|
||||
#ifdef CONFIG_DFU_OVER_USB
|
||||
"<USB_controller> [<interface> <dev>] [list]\n"
|
||||
" - device firmware upgrade via <USB_controller>\n"
|
||||
" on device <dev>, attached to interface\n"
|
||||
" <interface>\n"
|
||||
" [list] - list available alt settings\n"
|
||||
#endif
|
||||
#ifdef CONFIG_DFU_OVER_TFTP
|
||||
#ifdef CONFIG_DFU_OVER_USB
|
||||
"dfu "
|
||||
#endif
|
||||
"tftp [<interface> <dev>] [<addr>]\n"
|
||||
" - device firmware upgrade via TFTP\n"
|
||||
" on device <dev>, attached to interface\n"
|
||||
" <interface>\n"
|
||||
" [<addr>] - address where FIT image has been stored\n"
|
||||
#endif
|
||||
);
|
||||
59
cmd/diag.c
Normal file
59
cmd/diag.c
Normal file
@@ -0,0 +1,59 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2002
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Diagnostics support
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <post.h>
|
||||
|
||||
int do_diag (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if (argc == 1 || strcmp (argv[1], "run") != 0) {
|
||||
/* List test info */
|
||||
if (argc == 1) {
|
||||
puts ("Available hardware tests:\n");
|
||||
post_info (NULL);
|
||||
puts ("Use 'diag [<test1> [<test2> ...]]'"
|
||||
" to get more info.\n");
|
||||
puts ("Use 'diag run [<test1> [<test2> ...]]'"
|
||||
" to run tests.\n");
|
||||
} else {
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (post_info (argv[i]) != 0)
|
||||
printf ("%s - no such test\n", argv[i]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Run tests */
|
||||
if (argc == 2) {
|
||||
post_run (NULL, POST_RAM | POST_MANUAL);
|
||||
} else {
|
||||
for (i = 2; i < argc; i++) {
|
||||
if (post_run (argv[i], POST_RAM | POST_MANUAL) != 0)
|
||||
printf ("%s - unable to execute the test\n",
|
||||
argv[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
/***************************************************/
|
||||
|
||||
U_BOOT_CMD(
|
||||
diag, CONFIG_SYS_MAXARGS, 0, do_diag,
|
||||
"perform board diagnostics",
|
||||
" - print list of available tests\n"
|
||||
"diag [test1 [test2]]\n"
|
||||
" - print information about specified tests\n"
|
||||
"diag run - run all available tests\n"
|
||||
"diag run [test1 [test2]]\n"
|
||||
" - run specified tests"
|
||||
);
|
||||
130
cmd/disk.c
Normal file
130
cmd/disk.c
Normal file
@@ -0,0 +1,130 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2000-2011
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <cpu_func.h>
|
||||
#include <part.h>
|
||||
|
||||
int common_diskboot(cmd_tbl_t *cmdtp, const char *intf, int argc,
|
||||
char *const argv[])
|
||||
{
|
||||
__maybe_unused int dev;
|
||||
int part;
|
||||
ulong addr = CONFIG_SYS_LOAD_ADDR;
|
||||
ulong cnt;
|
||||
disk_partition_t info;
|
||||
#if defined(CONFIG_LEGACY_IMAGE_FORMAT)
|
||||
image_header_t *hdr;
|
||||
#endif
|
||||
struct blk_desc *dev_desc;
|
||||
|
||||
#if CONFIG_IS_ENABLED(FIT)
|
||||
const void *fit_hdr = NULL;
|
||||
#endif
|
||||
|
||||
bootstage_mark(BOOTSTAGE_ID_IDE_START);
|
||||
if (argc > 3) {
|
||||
bootstage_error(BOOTSTAGE_ID_IDE_ADDR);
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
bootstage_mark(BOOTSTAGE_ID_IDE_ADDR);
|
||||
|
||||
if (argc > 1)
|
||||
addr = simple_strtoul(argv[1], NULL, 16);
|
||||
|
||||
bootstage_mark(BOOTSTAGE_ID_IDE_BOOT_DEVICE);
|
||||
|
||||
part = blk_get_device_part_str(intf, (argc == 3) ? argv[2] : NULL,
|
||||
&dev_desc, &info, 1);
|
||||
if (part < 0) {
|
||||
bootstage_error(BOOTSTAGE_ID_IDE_TYPE);
|
||||
return 1;
|
||||
}
|
||||
|
||||
dev = dev_desc->devnum;
|
||||
bootstage_mark(BOOTSTAGE_ID_IDE_TYPE);
|
||||
|
||||
printf("\nLoading from %s device %d, partition %d: "
|
||||
"Name: %.32s Type: %.32s\n", intf, dev, part, info.name,
|
||||
info.type);
|
||||
|
||||
debug("First Block: " LBAFU ", # of blocks: " LBAFU
|
||||
", Block Size: %ld\n",
|
||||
info.start, info.size, info.blksz);
|
||||
|
||||
if (blk_dread(dev_desc, info.start, 1, (ulong *)addr) != 1) {
|
||||
printf("** Read error on %d:%d\n", dev, part);
|
||||
bootstage_error(BOOTSTAGE_ID_IDE_PART_READ);
|
||||
return 1;
|
||||
}
|
||||
bootstage_mark(BOOTSTAGE_ID_IDE_PART_READ);
|
||||
|
||||
switch (genimg_get_format((void *) addr)) {
|
||||
#if defined(CONFIG_LEGACY_IMAGE_FORMAT)
|
||||
case IMAGE_FORMAT_LEGACY:
|
||||
hdr = (image_header_t *) addr;
|
||||
|
||||
bootstage_mark(BOOTSTAGE_ID_IDE_FORMAT);
|
||||
|
||||
if (!image_check_hcrc(hdr)) {
|
||||
puts("\n** Bad Header Checksum **\n");
|
||||
bootstage_error(BOOTSTAGE_ID_IDE_CHECKSUM);
|
||||
return 1;
|
||||
}
|
||||
bootstage_mark(BOOTSTAGE_ID_IDE_CHECKSUM);
|
||||
|
||||
image_print_contents(hdr);
|
||||
|
||||
cnt = image_get_image_size(hdr);
|
||||
break;
|
||||
#endif
|
||||
#if CONFIG_IS_ENABLED(FIT)
|
||||
case IMAGE_FORMAT_FIT:
|
||||
fit_hdr = (const void *) addr;
|
||||
puts("Fit image detected...\n");
|
||||
|
||||
cnt = fit_get_size(fit_hdr);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
bootstage_error(BOOTSTAGE_ID_IDE_FORMAT);
|
||||
puts("** Unknown image type\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
cnt += info.blksz - 1;
|
||||
cnt /= info.blksz;
|
||||
cnt -= 1;
|
||||
|
||||
if (blk_dread(dev_desc, info.start + 1, cnt,
|
||||
(ulong *)(addr + info.blksz)) != cnt) {
|
||||
printf("** Read error on %d:%d\n", dev, part);
|
||||
bootstage_error(BOOTSTAGE_ID_IDE_READ);
|
||||
return 1;
|
||||
}
|
||||
bootstage_mark(BOOTSTAGE_ID_IDE_READ);
|
||||
|
||||
#if CONFIG_IS_ENABLED(FIT)
|
||||
/* This cannot be done earlier,
|
||||
* we need complete FIT image in RAM first */
|
||||
if (genimg_get_format((void *) addr) == IMAGE_FORMAT_FIT) {
|
||||
if (!fit_check_format(fit_hdr)) {
|
||||
bootstage_error(BOOTSTAGE_ID_IDE_FIT_READ);
|
||||
puts("** Bad FIT image format\n");
|
||||
return 1;
|
||||
}
|
||||
bootstage_mark(BOOTSTAGE_ID_IDE_FIT_READ_OK);
|
||||
fit_print_contents(fit_hdr);
|
||||
}
|
||||
#endif
|
||||
|
||||
flush_cache(addr, (cnt+1)*info.blksz);
|
||||
|
||||
/* Loading ok, update default load address */
|
||||
load_addr = addr;
|
||||
|
||||
return bootm_maybe_autostart(cmdtp, argv[0]);
|
||||
}
|
||||
88
cmd/dm.c
Normal file
88
cmd/dm.c
Normal file
@@ -0,0 +1,88 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2013 Google, Inc
|
||||
*
|
||||
* (C) Copyright 2012
|
||||
* Marek Vasut <marex@denx.de>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <dm.h>
|
||||
#include <malloc.h>
|
||||
#include <mapmem.h>
|
||||
#include <errno.h>
|
||||
#include <asm/io.h>
|
||||
#include <dm/root.h>
|
||||
#include <dm/util.h>
|
||||
|
||||
static int do_dm_dump_all(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
dm_dump_all();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_dm_dump_uclass(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
dm_dump_uclass();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_dm_dump_devres(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
dm_dump_devres();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static cmd_tbl_t test_commands[] = {
|
||||
U_BOOT_CMD_MKENT(tree, 0, 1, do_dm_dump_all, "", ""),
|
||||
U_BOOT_CMD_MKENT(uclass, 1, 1, do_dm_dump_uclass, "", ""),
|
||||
U_BOOT_CMD_MKENT(devres, 1, 1, do_dm_dump_devres, "", ""),
|
||||
};
|
||||
|
||||
static __maybe_unused void dm_reloc(void)
|
||||
{
|
||||
static int relocated;
|
||||
|
||||
if (!relocated) {
|
||||
fixup_cmdtable(test_commands, ARRAY_SIZE(test_commands));
|
||||
relocated = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int do_dm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
cmd_tbl_t *test_cmd;
|
||||
int ret;
|
||||
|
||||
#ifdef CONFIG_NEEDS_MANUAL_RELOC
|
||||
dm_reloc();
|
||||
#endif
|
||||
|
||||
if (argc < 2)
|
||||
return CMD_RET_USAGE;
|
||||
test_cmd = find_cmd_tbl(argv[1], test_commands,
|
||||
ARRAY_SIZE(test_commands));
|
||||
argc -= 2;
|
||||
argv += 2;
|
||||
if (!test_cmd || argc > test_cmd->maxargs)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
ret = test_cmd->cmd(test_cmd, flag, argc, argv);
|
||||
|
||||
return cmd_process_error(test_cmd, ret);
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
dm, 3, 1, do_dm,
|
||||
"Driver model low level access",
|
||||
"tree Dump driver model tree ('*' = activated)\n"
|
||||
"dm uclass Dump list of instances for each uclass\n"
|
||||
"dm devres Dump list of device resources for each device"
|
||||
);
|
||||
142
cmd/dtimg.c
Normal file
142
cmd/dtimg.c
Normal file
@@ -0,0 +1,142 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2018 Linaro Ltd.
|
||||
* Sam Protsenko <semen.protsenko@linaro.org>
|
||||
*/
|
||||
|
||||
#include <env.h>
|
||||
#include <image-android-dt.h>
|
||||
#include <common.h>
|
||||
|
||||
enum cmd_dtimg_info {
|
||||
CMD_DTIMG_START = 0,
|
||||
CMD_DTIMG_SIZE,
|
||||
};
|
||||
|
||||
static int do_dtimg_dump(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
char *endp;
|
||||
ulong hdr_addr;
|
||||
|
||||
if (argc != 2)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
hdr_addr = simple_strtoul(argv[1], &endp, 16);
|
||||
if (*endp != '\0') {
|
||||
printf("Error: Wrong image address\n");
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
if (!android_dt_check_header(hdr_addr)) {
|
||||
printf("Error: DT image header is incorrect\n");
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
android_dt_print_contents(hdr_addr);
|
||||
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
static int dtimg_get_fdt(int argc, char * const argv[], enum cmd_dtimg_info cmd)
|
||||
{
|
||||
ulong hdr_addr;
|
||||
u32 index;
|
||||
char *endp;
|
||||
ulong fdt_addr;
|
||||
u32 fdt_size;
|
||||
char buf[65];
|
||||
|
||||
if (argc != 4)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
hdr_addr = simple_strtoul(argv[1], &endp, 16);
|
||||
if (*endp != '\0') {
|
||||
printf("Error: Wrong image address\n");
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
if (!android_dt_check_header(hdr_addr)) {
|
||||
printf("Error: DT image header is incorrect\n");
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
index = simple_strtoul(argv[2], &endp, 0);
|
||||
if (*endp != '\0') {
|
||||
printf("Error: Wrong index\n");
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
if (!android_dt_get_fdt_by_index(hdr_addr, index, &fdt_addr, &fdt_size))
|
||||
return CMD_RET_FAILURE;
|
||||
|
||||
switch (cmd) {
|
||||
case CMD_DTIMG_START:
|
||||
snprintf(buf, sizeof(buf), "%lx", fdt_addr);
|
||||
break;
|
||||
case CMD_DTIMG_SIZE:
|
||||
snprintf(buf, sizeof(buf), "%x", fdt_size);
|
||||
break;
|
||||
default:
|
||||
printf("Error: Unknown cmd_dtimg_info value: %d\n", cmd);
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
env_set(argv[3], buf);
|
||||
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
static int do_dtimg_start(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
return dtimg_get_fdt(argc, argv, CMD_DTIMG_START);
|
||||
}
|
||||
|
||||
static int do_dtimg_size(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
return dtimg_get_fdt(argc, argv, CMD_DTIMG_SIZE);
|
||||
}
|
||||
|
||||
static cmd_tbl_t cmd_dtimg_sub[] = {
|
||||
U_BOOT_CMD_MKENT(dump, 2, 0, do_dtimg_dump, "", ""),
|
||||
U_BOOT_CMD_MKENT(start, 4, 0, do_dtimg_start, "", ""),
|
||||
U_BOOT_CMD_MKENT(size, 4, 0, do_dtimg_size, "", ""),
|
||||
};
|
||||
|
||||
static int do_dtimg(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
cmd_tbl_t *cp;
|
||||
|
||||
cp = find_cmd_tbl(argv[1], cmd_dtimg_sub, ARRAY_SIZE(cmd_dtimg_sub));
|
||||
|
||||
/* Strip off leading 'dtimg' command argument */
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
if (!cp || argc > cp->maxargs)
|
||||
return CMD_RET_USAGE;
|
||||
if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp))
|
||||
return CMD_RET_SUCCESS;
|
||||
|
||||
return cp->cmd(cmdtp, flag, argc, argv);
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
dtimg, CONFIG_SYS_MAXARGS, 0, do_dtimg,
|
||||
"manipulate dtb/dtbo Android image",
|
||||
"dump <addr>\n"
|
||||
" - parse specified image and print its structure info\n"
|
||||
" <addr>: image address in RAM, in hex\n"
|
||||
"dtimg start <addr> <index> <varname>\n"
|
||||
" - get address (hex) of FDT in the image, by index\n"
|
||||
" <addr>: image address in RAM, in hex\n"
|
||||
" <index>: index of desired FDT in the image\n"
|
||||
" <varname>: name of variable where to store address of FDT\n"
|
||||
"dtimg size <addr> <index> <varname>\n"
|
||||
" - get size (hex, bytes) of FDT in the image, by index\n"
|
||||
" <addr>: image address in RAM, in hex\n"
|
||||
" <index>: index of desired FDT in the image\n"
|
||||
" <varname>: name of variable where to store size of FDT"
|
||||
);
|
||||
55
cmd/echo.c
Normal file
55
cmd/echo.c
Normal file
@@ -0,0 +1,55 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2000-2009
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
|
||||
static int do_echo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
int i;
|
||||
int putnl = 1;
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
char *p = argv[i];
|
||||
char *nls; /* new-line suppression */
|
||||
|
||||
if (i > 1)
|
||||
putc(' ');
|
||||
|
||||
nls = strstr(p, "\\c");
|
||||
if (nls) {
|
||||
char *prenls = p;
|
||||
|
||||
putnl = 0;
|
||||
/*
|
||||
* be paranoid and guess that someone might
|
||||
* say \c more than once
|
||||
*/
|
||||
while (nls) {
|
||||
*nls = '\0';
|
||||
puts(prenls);
|
||||
*nls = '\\';
|
||||
prenls = nls + 2;
|
||||
nls = strstr(prenls, "\\c");
|
||||
}
|
||||
puts(prenls);
|
||||
} else {
|
||||
puts(p);
|
||||
}
|
||||
}
|
||||
|
||||
if (putnl)
|
||||
putc('\n');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
echo, CONFIG_SYS_MAXARGS, 1, do_echo,
|
||||
"echo args to console",
|
||||
"[args..]\n"
|
||||
" - echo args to console; \\c suppresses newline"
|
||||
);
|
||||
455
cmd/eeprom.c
Normal file
455
cmd/eeprom.c
Normal file
@@ -0,0 +1,455 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2000, 2001
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Support for read and write access to EEPROM like memory devices. This
|
||||
* includes regular EEPROM as well as FRAM (ferroelectic nonvolaile RAM).
|
||||
* FRAM devices read and write data at bus speed. In particular, there is no
|
||||
* write delay. Also, there is no limit imposed on the number of bytes that can
|
||||
* be transferred with a single read or write.
|
||||
*
|
||||
* Use the following configuration options to ensure no unneeded performance
|
||||
* degradation (typical for EEPROM) is incured for FRAM memory:
|
||||
*
|
||||
* #define CONFIG_SYS_I2C_FRAM
|
||||
* #undef CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS
|
||||
*
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <config.h>
|
||||
#include <command.h>
|
||||
#include <eeprom.h>
|
||||
#include <i2c.h>
|
||||
#include <eeprom_layout.h>
|
||||
|
||||
#ifndef CONFIG_SYS_I2C_SPEED
|
||||
#define CONFIG_SYS_I2C_SPEED 50000
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS
|
||||
#define CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS 0
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SYS_EEPROM_PAGE_WRITE_BITS
|
||||
#define CONFIG_SYS_EEPROM_PAGE_WRITE_BITS 8
|
||||
#endif
|
||||
|
||||
#ifndef I2C_RXTX_LEN
|
||||
#define I2C_RXTX_LEN 128
|
||||
#endif
|
||||
|
||||
#define EEPROM_PAGE_SIZE (1 << CONFIG_SYS_EEPROM_PAGE_WRITE_BITS)
|
||||
#define EEPROM_PAGE_OFFSET(x) ((x) & (EEPROM_PAGE_SIZE - 1))
|
||||
|
||||
/*
|
||||
* for CONFIG_SYS_I2C_EEPROM_ADDR_LEN == 2 (16-bit EEPROM address) offset is
|
||||
* 0x000nxxxx for EEPROM address selectors at n, offset xxxx in EEPROM.
|
||||
*
|
||||
* for CONFIG_SYS_I2C_EEPROM_ADDR_LEN == 1 (8-bit EEPROM page address) offset is
|
||||
* 0x00000nxx for EEPROM address selectors and page number at n.
|
||||
*/
|
||||
#if !defined(CONFIG_SPI) || defined(CONFIG_ENV_EEPROM_IS_ON_I2C)
|
||||
#if !defined(CONFIG_SYS_I2C_EEPROM_ADDR_LEN) || \
|
||||
(CONFIG_SYS_I2C_EEPROM_ADDR_LEN < 1) || \
|
||||
(CONFIG_SYS_I2C_EEPROM_ADDR_LEN > 2)
|
||||
#error CONFIG_SYS_I2C_EEPROM_ADDR_LEN must be 1 or 2
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_DM_I2C)
|
||||
int eeprom_i2c_bus;
|
||||
#endif
|
||||
|
||||
__weak int eeprom_write_enable(unsigned dev_addr, int state)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void eeprom_init(int bus)
|
||||
{
|
||||
/* I2C EEPROM */
|
||||
#if defined(CONFIG_DM_I2C)
|
||||
eeprom_i2c_bus = bus;
|
||||
#elif defined(CONFIG_SYS_I2C)
|
||||
if (bus >= 0)
|
||||
i2c_set_bus_num(bus);
|
||||
i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int eeprom_addr(unsigned dev_addr, unsigned offset, uchar *addr)
|
||||
{
|
||||
unsigned blk_off;
|
||||
int alen;
|
||||
|
||||
blk_off = offset & 0xff; /* block offset */
|
||||
#if CONFIG_SYS_I2C_EEPROM_ADDR_LEN == 1
|
||||
addr[0] = offset >> 8; /* block number */
|
||||
addr[1] = blk_off; /* block offset */
|
||||
alen = 2;
|
||||
#else
|
||||
addr[0] = offset >> 16; /* block number */
|
||||
addr[1] = offset >> 8; /* upper address octet */
|
||||
addr[2] = blk_off; /* lower address octet */
|
||||
alen = 3;
|
||||
#endif /* CONFIG_SYS_I2C_EEPROM_ADDR_LEN */
|
||||
|
||||
addr[0] |= dev_addr; /* insert device address */
|
||||
|
||||
return alen;
|
||||
}
|
||||
|
||||
static int eeprom_len(unsigned offset, unsigned end)
|
||||
{
|
||||
unsigned len = end - offset;
|
||||
|
||||
/*
|
||||
* For a FRAM device there is no limit on the number of the
|
||||
* bytes that can be accessed with the single read or write
|
||||
* operation.
|
||||
*/
|
||||
#if !defined(CONFIG_SYS_I2C_FRAM)
|
||||
unsigned blk_off = offset & 0xff;
|
||||
unsigned maxlen = EEPROM_PAGE_SIZE - EEPROM_PAGE_OFFSET(blk_off);
|
||||
|
||||
if (maxlen > I2C_RXTX_LEN)
|
||||
maxlen = I2C_RXTX_LEN;
|
||||
|
||||
if (len > maxlen)
|
||||
len = maxlen;
|
||||
#endif
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int eeprom_rw_block(unsigned offset, uchar *addr, unsigned alen,
|
||||
uchar *buffer, unsigned len, bool read)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
#if defined(CONFIG_DM_I2C)
|
||||
struct udevice *dev;
|
||||
|
||||
ret = i2c_get_chip_for_busnum(eeprom_i2c_bus, addr[0],
|
||||
alen - 1, &dev);
|
||||
if (ret) {
|
||||
printf("%s: Cannot find udev for a bus %d\n", __func__,
|
||||
eeprom_i2c_bus);
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
if (read)
|
||||
ret = dm_i2c_read(dev, offset, buffer, len);
|
||||
else
|
||||
ret = dm_i2c_write(dev, offset, buffer, len);
|
||||
|
||||
#else /* Non DM I2C support - will be removed */
|
||||
|
||||
if (read)
|
||||
ret = i2c_read(addr[0], offset, alen - 1, buffer, len);
|
||||
else
|
||||
ret = i2c_write(addr[0], offset, alen - 1, buffer, len);
|
||||
#endif /* CONFIG_DM_I2C */
|
||||
if (ret)
|
||||
ret = CMD_RET_FAILURE;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int eeprom_rw(unsigned dev_addr, unsigned offset, uchar *buffer,
|
||||
unsigned cnt, bool read)
|
||||
{
|
||||
unsigned end = offset + cnt;
|
||||
unsigned alen, len;
|
||||
int rcode = 0;
|
||||
uchar addr[3];
|
||||
|
||||
#if defined(CONFIG_SYS_I2C_EEPROM_BUS)
|
||||
eeprom_init(CONFIG_SYS_I2C_EEPROM_BUS);
|
||||
#endif
|
||||
|
||||
while (offset < end) {
|
||||
alen = eeprom_addr(dev_addr, offset, addr);
|
||||
|
||||
len = eeprom_len(offset, end);
|
||||
|
||||
rcode = eeprom_rw_block(offset, addr, alen, buffer, len, read);
|
||||
|
||||
buffer += len;
|
||||
offset += len;
|
||||
|
||||
if (!read)
|
||||
udelay(CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS * 1000);
|
||||
}
|
||||
|
||||
return rcode;
|
||||
}
|
||||
|
||||
int eeprom_read(unsigned dev_addr, unsigned offset, uchar *buffer, unsigned cnt)
|
||||
{
|
||||
/*
|
||||
* Read data until done or would cross a page boundary.
|
||||
* We must write the address again when changing pages
|
||||
* because the next page may be in a different device.
|
||||
*/
|
||||
return eeprom_rw(dev_addr, offset, buffer, cnt, 1);
|
||||
}
|
||||
|
||||
int eeprom_write(unsigned dev_addr, unsigned offset,
|
||||
uchar *buffer, unsigned cnt)
|
||||
{
|
||||
int ret;
|
||||
|
||||
eeprom_write_enable(dev_addr, 1);
|
||||
|
||||
/*
|
||||
* Write data until done or would cross a write page boundary.
|
||||
* We must write the address again when changing pages
|
||||
* because the address counter only increments within a page.
|
||||
*/
|
||||
ret = eeprom_rw(dev_addr, offset, buffer, cnt, 0);
|
||||
|
||||
eeprom_write_enable(dev_addr, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int parse_numeric_param(char *str)
|
||||
{
|
||||
char *endptr;
|
||||
int value = simple_strtol(str, &endptr, 16);
|
||||
|
||||
return (*endptr != '\0') ? -1 : value;
|
||||
}
|
||||
|
||||
/**
|
||||
* parse_i2c_bus_addr - parse the i2c bus and i2c devaddr parameters
|
||||
*
|
||||
* @i2c_bus: address to store the i2c bus
|
||||
* @i2c_addr: address to store the device i2c address
|
||||
* @argc: count of command line arguments left to parse
|
||||
* @argv: command line arguments left to parse
|
||||
* @argc_no_bus_addr: argc value we expect to see when bus & addr aren't given
|
||||
*
|
||||
* @returns: number of arguments parsed or CMD_RET_USAGE if error
|
||||
*/
|
||||
static int parse_i2c_bus_addr(int *i2c_bus, ulong *i2c_addr, int argc,
|
||||
char * const argv[], int argc_no_bus_addr)
|
||||
{
|
||||
int argc_no_bus = argc_no_bus_addr + 1;
|
||||
int argc_bus_addr = argc_no_bus_addr + 2;
|
||||
|
||||
#ifdef CONFIG_SYS_DEF_EEPROM_ADDR
|
||||
if (argc == argc_no_bus_addr) {
|
||||
*i2c_bus = -1;
|
||||
*i2c_addr = CONFIG_SYS_DEF_EEPROM_ADDR;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if (argc == argc_no_bus) {
|
||||
*i2c_bus = -1;
|
||||
*i2c_addr = parse_numeric_param(argv[0]);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (argc == argc_bus_addr) {
|
||||
*i2c_bus = parse_numeric_param(argv[0]);
|
||||
*i2c_addr = parse_numeric_param(argv[1]);
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CMD_EEPROM_LAYOUT
|
||||
|
||||
__weak int eeprom_parse_layout_version(char *str)
|
||||
{
|
||||
return LAYOUT_VERSION_UNRECOGNIZED;
|
||||
}
|
||||
|
||||
static unsigned char eeprom_buf[CONFIG_SYS_EEPROM_SIZE];
|
||||
|
||||
#endif
|
||||
|
||||
enum eeprom_action {
|
||||
EEPROM_READ,
|
||||
EEPROM_WRITE,
|
||||
EEPROM_PRINT,
|
||||
EEPROM_UPDATE,
|
||||
EEPROM_ACTION_INVALID,
|
||||
};
|
||||
|
||||
static enum eeprom_action parse_action(char *cmd)
|
||||
{
|
||||
if (!strncmp(cmd, "read", 4))
|
||||
return EEPROM_READ;
|
||||
if (!strncmp(cmd, "write", 5))
|
||||
return EEPROM_WRITE;
|
||||
#ifdef CONFIG_CMD_EEPROM_LAYOUT
|
||||
if (!strncmp(cmd, "print", 5))
|
||||
return EEPROM_PRINT;
|
||||
if (!strncmp(cmd, "update", 6))
|
||||
return EEPROM_UPDATE;
|
||||
#endif
|
||||
|
||||
return EEPROM_ACTION_INVALID;
|
||||
}
|
||||
|
||||
static int eeprom_execute_command(enum eeprom_action action, int i2c_bus,
|
||||
ulong i2c_addr, int layout_ver, char *key,
|
||||
char *value, ulong addr, ulong off, ulong cnt)
|
||||
{
|
||||
int rcode = 0;
|
||||
const char *const fmt =
|
||||
"\nEEPROM @0x%lX %s: addr %08lx off %04lx count %ld ... ";
|
||||
#ifdef CONFIG_CMD_EEPROM_LAYOUT
|
||||
struct eeprom_layout layout;
|
||||
#endif
|
||||
|
||||
if (action == EEPROM_ACTION_INVALID)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
eeprom_init(i2c_bus);
|
||||
if (action == EEPROM_READ) {
|
||||
printf(fmt, i2c_addr, "read", addr, off, cnt);
|
||||
|
||||
rcode = eeprom_read(i2c_addr, off, (uchar *)addr, cnt);
|
||||
|
||||
puts("done\n");
|
||||
return rcode;
|
||||
} else if (action == EEPROM_WRITE) {
|
||||
printf(fmt, i2c_addr, "write", addr, off, cnt);
|
||||
|
||||
rcode = eeprom_write(i2c_addr, off, (uchar *)addr, cnt);
|
||||
|
||||
puts("done\n");
|
||||
return rcode;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CMD_EEPROM_LAYOUT
|
||||
rcode = eeprom_read(i2c_addr, 0, eeprom_buf, CONFIG_SYS_EEPROM_SIZE);
|
||||
if (rcode < 0)
|
||||
return rcode;
|
||||
|
||||
eeprom_layout_setup(&layout, eeprom_buf, CONFIG_SYS_EEPROM_SIZE,
|
||||
layout_ver);
|
||||
|
||||
if (action == EEPROM_PRINT) {
|
||||
layout.print(&layout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
layout.update(&layout, key, value);
|
||||
|
||||
rcode = eeprom_write(i2c_addr, 0, layout.data, CONFIG_SYS_EEPROM_SIZE);
|
||||
#endif
|
||||
|
||||
return rcode;
|
||||
}
|
||||
|
||||
#define NEXT_PARAM(argc, index) { (argc)--; (index)++; }
|
||||
int do_eeprom(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
int layout_ver = LAYOUT_VERSION_AUTODETECT;
|
||||
enum eeprom_action action = EEPROM_ACTION_INVALID;
|
||||
int i2c_bus = -1, index = 0;
|
||||
ulong i2c_addr = -1, addr = 0, cnt = 0, off = 0;
|
||||
int ret;
|
||||
char *field_name = "";
|
||||
char *field_value = "";
|
||||
|
||||
if (argc <= 1)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
NEXT_PARAM(argc, index); /* Skip program name */
|
||||
|
||||
action = parse_action(argv[index]);
|
||||
NEXT_PARAM(argc, index);
|
||||
|
||||
if (action == EEPROM_ACTION_INVALID)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
#ifdef CONFIG_CMD_EEPROM_LAYOUT
|
||||
if (action == EEPROM_PRINT || action == EEPROM_UPDATE) {
|
||||
if (!strcmp(argv[index], "-l")) {
|
||||
NEXT_PARAM(argc, index);
|
||||
layout_ver = eeprom_parse_layout_version(argv[index]);
|
||||
NEXT_PARAM(argc, index);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (action) {
|
||||
case EEPROM_READ:
|
||||
case EEPROM_WRITE:
|
||||
ret = parse_i2c_bus_addr(&i2c_bus, &i2c_addr, argc,
|
||||
argv + index, 3);
|
||||
break;
|
||||
case EEPROM_PRINT:
|
||||
ret = parse_i2c_bus_addr(&i2c_bus, &i2c_addr, argc,
|
||||
argv + index, 0);
|
||||
break;
|
||||
case EEPROM_UPDATE:
|
||||
ret = parse_i2c_bus_addr(&i2c_bus, &i2c_addr, argc,
|
||||
argv + index, 2);
|
||||
break;
|
||||
default:
|
||||
/* Get compiler to stop whining */
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
if (ret == CMD_RET_USAGE)
|
||||
return ret;
|
||||
|
||||
while (ret--)
|
||||
NEXT_PARAM(argc, index);
|
||||
|
||||
if (action == EEPROM_READ || action == EEPROM_WRITE) {
|
||||
addr = parse_numeric_param(argv[index]);
|
||||
NEXT_PARAM(argc, index);
|
||||
off = parse_numeric_param(argv[index]);
|
||||
NEXT_PARAM(argc, index);
|
||||
cnt = parse_numeric_param(argv[index]);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CMD_EEPROM_LAYOUT
|
||||
if (action == EEPROM_UPDATE) {
|
||||
field_name = argv[index];
|
||||
NEXT_PARAM(argc, index);
|
||||
field_value = argv[index];
|
||||
NEXT_PARAM(argc, index);
|
||||
}
|
||||
#endif
|
||||
|
||||
return eeprom_execute_command(action, i2c_bus, i2c_addr, layout_ver,
|
||||
field_name, field_value, addr, off, cnt);
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
eeprom, 8, 1, do_eeprom,
|
||||
"EEPROM sub-system",
|
||||
"read <bus> <devaddr> addr off cnt\n"
|
||||
"eeprom write <bus> <devaddr> addr off cnt\n"
|
||||
" - read/write `cnt' bytes from `devaddr` EEPROM at offset `off'"
|
||||
#ifdef CONFIG_CMD_EEPROM_LAYOUT
|
||||
"\n"
|
||||
"eeprom print [-l <layout_version>] <bus> <devaddr>\n"
|
||||
" - Print layout fields and their data in human readable format\n"
|
||||
"eeprom update [-l <layout_version>] <bus> <devaddr> field_name field_value\n"
|
||||
" - Update a specific eeprom field with new data.\n"
|
||||
" The new data must be written in the same human readable format as shown by the print command.\n"
|
||||
"\n"
|
||||
"LAYOUT VERSIONS\n"
|
||||
"The -l option can be used to force the command to interpret the EEPROM data using the chosen layout.\n"
|
||||
"If the -l option is omitted, the command will auto detect the layout based on the data in the EEPROM.\n"
|
||||
"The values which can be provided with the -l option are:\n"
|
||||
CONFIG_EEPROM_LAYOUT_HELP_STRING"\n"
|
||||
#endif
|
||||
)
|
||||
260
cmd/efi.c
Normal file
260
cmd/efi.c
Normal file
@@ -0,0 +1,260 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2015 Google, Inc
|
||||
* Written by Simon Glass <sjg@chromium.org>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <efi.h>
|
||||
#include <errno.h>
|
||||
#include <malloc.h>
|
||||
#include <sort.h>
|
||||
|
||||
static const char *const type_name[] = {
|
||||
"reserved",
|
||||
"loader_code",
|
||||
"loader_data",
|
||||
"bs_code",
|
||||
"bs_data",
|
||||
"rt_code",
|
||||
"rt_data",
|
||||
"conv",
|
||||
"unusable",
|
||||
"acpi_reclaim",
|
||||
"acpi_nvs",
|
||||
"io",
|
||||
"io_port",
|
||||
"pal_code",
|
||||
};
|
||||
|
||||
static struct attr_info {
|
||||
u64 val;
|
||||
const char *name;
|
||||
} mem_attr[] = {
|
||||
{ EFI_MEMORY_UC, "uncached" },
|
||||
{ EFI_MEMORY_WC, "write-coalescing" },
|
||||
{ EFI_MEMORY_WT, "write-through" },
|
||||
{ EFI_MEMORY_WB, "write-back" },
|
||||
{ EFI_MEMORY_UCE, "uncached & exported" },
|
||||
{ EFI_MEMORY_WP, "write-protect" },
|
||||
{ EFI_MEMORY_RP, "read-protect" },
|
||||
{ EFI_MEMORY_XP, "execute-protect" },
|
||||
{ EFI_MEMORY_NV, "non-volatile" },
|
||||
{ EFI_MEMORY_MORE_RELIABLE, "higher reliability" },
|
||||
{ EFI_MEMORY_RO, "read-only" },
|
||||
{ EFI_MEMORY_RUNTIME, "needs runtime mapping" }
|
||||
};
|
||||
|
||||
/* Maximum different attribute values we can track */
|
||||
#define ATTR_SEEN_MAX 30
|
||||
|
||||
static inline bool is_boot_services(int type)
|
||||
{
|
||||
return type == EFI_LOADER_CODE || type == EFI_LOADER_DATA ||
|
||||
type == EFI_BOOT_SERVICES_CODE ||
|
||||
type == EFI_BOOT_SERVICES_DATA;
|
||||
}
|
||||
|
||||
static int h_cmp_entry(const void *v1, const void *v2)
|
||||
{
|
||||
const struct efi_mem_desc *desc1 = v1;
|
||||
const struct efi_mem_desc *desc2 = v2;
|
||||
int64_t diff = desc1->physical_start - desc2->physical_start;
|
||||
|
||||
/*
|
||||
* Manually calculate the difference to avoid sign loss in the 64-bit
|
||||
* to 32-bit conversion
|
||||
*/
|
||||
return diff < 0 ? -1 : diff > 0 ? 1 : 0;
|
||||
}
|
||||
|
||||
void *efi_build_mem_table(struct efi_entry_memmap *map, int size, bool skip_bs)
|
||||
{
|
||||
struct efi_mem_desc *desc, *end, *base, *dest, *prev;
|
||||
int count;
|
||||
u64 addr;
|
||||
|
||||
base = malloc(size + sizeof(*desc));
|
||||
if (!base) {
|
||||
debug("%s: Cannot allocate %#x bytes\n", __func__, size);
|
||||
return NULL;
|
||||
}
|
||||
end = (struct efi_mem_desc *)((ulong)map + size);
|
||||
count = ((ulong)end - (ulong)map->desc) / map->desc_size;
|
||||
memcpy(base, map->desc, (ulong)end - (ulong)map->desc);
|
||||
qsort(base, count, map->desc_size, h_cmp_entry);
|
||||
prev = NULL;
|
||||
addr = 0;
|
||||
dest = base;
|
||||
end = (struct efi_mem_desc *)((ulong)base + count * map->desc_size);
|
||||
for (desc = base; desc < end; desc = efi_get_next_mem_desc(map, desc)) {
|
||||
bool merge = true;
|
||||
int type = desc->type;
|
||||
|
||||
if (skip_bs && is_boot_services(desc->type))
|
||||
type = EFI_CONVENTIONAL_MEMORY;
|
||||
|
||||
memcpy(dest, desc, map->desc_size);
|
||||
dest->type = type;
|
||||
if (!skip_bs || !prev)
|
||||
merge = false;
|
||||
else if (desc->physical_start != addr)
|
||||
merge = false;
|
||||
else if (type != EFI_CONVENTIONAL_MEMORY)
|
||||
merge = false;
|
||||
else if (prev->type != EFI_CONVENTIONAL_MEMORY)
|
||||
merge = false;
|
||||
|
||||
if (merge) {
|
||||
prev->num_pages += desc->num_pages;
|
||||
} else {
|
||||
prev = dest;
|
||||
dest = efi_get_next_mem_desc(map, dest);
|
||||
}
|
||||
addr = desc->physical_start + (desc->num_pages <<
|
||||
EFI_PAGE_SHIFT);
|
||||
}
|
||||
|
||||
/* Mark the end */
|
||||
dest->type = EFI_TABLE_END;
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
static void efi_print_mem_table(struct efi_entry_memmap *map,
|
||||
struct efi_mem_desc *desc, bool skip_bs)
|
||||
{
|
||||
u64 attr_seen[ATTR_SEEN_MAX];
|
||||
int attr_seen_count;
|
||||
int upto, i;
|
||||
u64 addr;
|
||||
|
||||
printf(" # %-14s %10s %10s %10s %s\n", "Type", "Physical",
|
||||
"Virtual", "Size", "Attributes");
|
||||
|
||||
/* Keep track of all the different attributes we have seen */
|
||||
attr_seen_count = 0;
|
||||
addr = 0;
|
||||
for (upto = 0; desc->type != EFI_TABLE_END;
|
||||
upto++, desc = efi_get_next_mem_desc(map, desc)) {
|
||||
const char *name;
|
||||
u64 size;
|
||||
|
||||
if (skip_bs && is_boot_services(desc->type))
|
||||
continue;
|
||||
if (desc->physical_start != addr) {
|
||||
printf(" %-14s %010llx %10s %010llx\n", "<gap>",
|
||||
addr, "", desc->physical_start - addr);
|
||||
}
|
||||
size = desc->num_pages << EFI_PAGE_SHIFT;
|
||||
|
||||
name = desc->type < ARRAY_SIZE(type_name) ?
|
||||
type_name[desc->type] : "<invalid>";
|
||||
printf("%2d %x:%-12s %010llx %010llx %010llx ", upto,
|
||||
desc->type, name, desc->physical_start,
|
||||
desc->virtual_start, size);
|
||||
if (desc->attribute & EFI_MEMORY_RUNTIME)
|
||||
putc('r');
|
||||
printf("%llx", desc->attribute & ~EFI_MEMORY_RUNTIME);
|
||||
putc('\n');
|
||||
|
||||
for (i = 0; i < attr_seen_count; i++) {
|
||||
if (attr_seen[i] == desc->attribute)
|
||||
break;
|
||||
}
|
||||
if (i == attr_seen_count && i < ATTR_SEEN_MAX)
|
||||
attr_seen[attr_seen_count++] = desc->attribute;
|
||||
addr = desc->physical_start + size;
|
||||
}
|
||||
|
||||
printf("\nAttributes key:\n");
|
||||
for (i = 0; i < attr_seen_count; i++) {
|
||||
u64 attr = attr_seen[i];
|
||||
bool first;
|
||||
int j;
|
||||
|
||||
printf("%c%llx: ", (attr & EFI_MEMORY_RUNTIME) ? 'r' : ' ',
|
||||
attr & ~EFI_MEMORY_RUNTIME);
|
||||
for (j = 0, first = true; j < ARRAY_SIZE(mem_attr); j++) {
|
||||
if (attr & mem_attr[j].val) {
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
printf(", ");
|
||||
printf("%s", mem_attr[j].name);
|
||||
}
|
||||
}
|
||||
putc('\n');
|
||||
}
|
||||
if (skip_bs)
|
||||
printf("*Some areas are merged (use 'all' to see)\n");
|
||||
}
|
||||
|
||||
static int do_efi_mem(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
struct efi_mem_desc *desc;
|
||||
struct efi_entry_memmap *map;
|
||||
int size, ret;
|
||||
bool skip_bs;
|
||||
|
||||
skip_bs = !argc || *argv[0] != 'a';
|
||||
ret = efi_info_get(EFIET_MEMORY_MAP, (void **)&map, &size);
|
||||
switch (ret) {
|
||||
case -ENOENT:
|
||||
printf("No EFI table available\n");
|
||||
goto done;
|
||||
case -EPROTONOSUPPORT:
|
||||
printf("Incorrect EFI table version\n");
|
||||
goto done;
|
||||
}
|
||||
printf("EFI table at %lx, memory map %p, size %x, version %x, descr. size %#x\n",
|
||||
gd->arch.table, map, size, map->version, map->desc_size);
|
||||
if (map->version != EFI_MEM_DESC_VERSION) {
|
||||
printf("Incorrect memory map version\n");
|
||||
ret = -EPROTONOSUPPORT;
|
||||
goto done;
|
||||
}
|
||||
|
||||
desc = efi_build_mem_table(map, size, skip_bs);
|
||||
if (!desc) {
|
||||
ret = -ENOMEM;
|
||||
goto done;
|
||||
}
|
||||
|
||||
efi_print_mem_table(map, desc, skip_bs);
|
||||
free(desc);
|
||||
done:
|
||||
if (ret)
|
||||
printf("Error: %d\n", ret);
|
||||
|
||||
return ret ? CMD_RET_FAILURE : 0;
|
||||
}
|
||||
|
||||
static cmd_tbl_t efi_commands[] = {
|
||||
U_BOOT_CMD_MKENT(mem, 1, 1, do_efi_mem, "", ""),
|
||||
};
|
||||
|
||||
static int do_efi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
cmd_tbl_t *efi_cmd;
|
||||
int ret;
|
||||
|
||||
if (argc < 2)
|
||||
return CMD_RET_USAGE;
|
||||
efi_cmd = find_cmd_tbl(argv[1], efi_commands, ARRAY_SIZE(efi_commands));
|
||||
argc -= 2;
|
||||
argv += 2;
|
||||
if (!efi_cmd || argc > efi_cmd->maxargs)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
ret = efi_cmd->cmd(efi_cmd, flag, argc, argv);
|
||||
|
||||
return cmd_process_error(efi_cmd, ret);
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
efi, 3, 1, do_efi,
|
||||
"EFI access",
|
||||
"mem [all] Dump memory information [include boot services]"
|
||||
);
|
||||
1121
cmd/efidebug.c
Normal file
1121
cmd/efidebug.c
Normal file
File diff suppressed because it is too large
Load Diff
544
cmd/elf.c
Normal file
544
cmd/elf.c
Normal file
@@ -0,0 +1,544 @@
|
||||
/*
|
||||
* Copyright (c) 2001 William L. Pitts
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms are freely
|
||||
* permitted provided that the above copyright notice and this
|
||||
* paragraph and the following disclaimer are duplicated in all
|
||||
* such forms.
|
||||
*
|
||||
* This software is provided "AS IS" and without any express or
|
||||
* implied warranties, including, without limitation, the implied
|
||||
* warranties of merchantability and fitness for a particular
|
||||
* purpose.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <cpu_func.h>
|
||||
#include <elf.h>
|
||||
#include <env.h>
|
||||
#include <net.h>
|
||||
#include <vxworks.h>
|
||||
#ifdef CONFIG_X86
|
||||
#include <vbe.h>
|
||||
#include <asm/e820.h>
|
||||
#include <linux/linkage.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* A very simple ELF64 loader, assumes the image is valid, returns the
|
||||
* entry point address.
|
||||
*
|
||||
* Note if U-Boot is 32-bit, the loader assumes the to segment's
|
||||
* physical address and size is within the lower 32-bit address space.
|
||||
*/
|
||||
static unsigned long load_elf64_image_phdr(unsigned long addr)
|
||||
{
|
||||
Elf64_Ehdr *ehdr; /* Elf header structure pointer */
|
||||
Elf64_Phdr *phdr; /* Program header structure pointer */
|
||||
int i;
|
||||
|
||||
ehdr = (Elf64_Ehdr *)addr;
|
||||
phdr = (Elf64_Phdr *)(addr + (ulong)ehdr->e_phoff);
|
||||
|
||||
/* Load each program header */
|
||||
for (i = 0; i < ehdr->e_phnum; ++i) {
|
||||
void *dst = (void *)(ulong)phdr->p_paddr;
|
||||
void *src = (void *)addr + phdr->p_offset;
|
||||
|
||||
debug("Loading phdr %i to 0x%p (%lu bytes)\n",
|
||||
i, dst, (ulong)phdr->p_filesz);
|
||||
if (phdr->p_filesz)
|
||||
memcpy(dst, src, phdr->p_filesz);
|
||||
if (phdr->p_filesz != phdr->p_memsz)
|
||||
memset(dst + phdr->p_filesz, 0x00,
|
||||
phdr->p_memsz - phdr->p_filesz);
|
||||
flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN),
|
||||
roundup(phdr->p_memsz, ARCH_DMA_MINALIGN));
|
||||
++phdr;
|
||||
}
|
||||
|
||||
if (ehdr->e_machine == EM_PPC64 && (ehdr->e_flags &
|
||||
EF_PPC64_ELFV1_ABI)) {
|
||||
/*
|
||||
* For the 64-bit PowerPC ELF V1 ABI, e_entry is a function
|
||||
* descriptor pointer with the first double word being the
|
||||
* address of the entry point of the function.
|
||||
*/
|
||||
uintptr_t addr = ehdr->e_entry;
|
||||
|
||||
return *(Elf64_Addr *)addr;
|
||||
}
|
||||
|
||||
return ehdr->e_entry;
|
||||
}
|
||||
|
||||
static unsigned long load_elf64_image_shdr(unsigned long addr)
|
||||
{
|
||||
Elf64_Ehdr *ehdr; /* Elf header structure pointer */
|
||||
Elf64_Shdr *shdr; /* Section header structure pointer */
|
||||
unsigned char *strtab = 0; /* String table pointer */
|
||||
unsigned char *image; /* Binary image pointer */
|
||||
int i; /* Loop counter */
|
||||
|
||||
ehdr = (Elf64_Ehdr *)addr;
|
||||
|
||||
/* Find the section header string table for output info */
|
||||
shdr = (Elf64_Shdr *)(addr + (ulong)ehdr->e_shoff +
|
||||
(ehdr->e_shstrndx * sizeof(Elf64_Shdr)));
|
||||
|
||||
if (shdr->sh_type == SHT_STRTAB)
|
||||
strtab = (unsigned char *)(addr + (ulong)shdr->sh_offset);
|
||||
|
||||
/* Load each appropriate section */
|
||||
for (i = 0; i < ehdr->e_shnum; ++i) {
|
||||
shdr = (Elf64_Shdr *)(addr + (ulong)ehdr->e_shoff +
|
||||
(i * sizeof(Elf64_Shdr)));
|
||||
|
||||
if (!(shdr->sh_flags & SHF_ALLOC) ||
|
||||
shdr->sh_addr == 0 || shdr->sh_size == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strtab) {
|
||||
debug("%sing %s @ 0x%08lx (%ld bytes)\n",
|
||||
(shdr->sh_type == SHT_NOBITS) ? "Clear" : "Load",
|
||||
&strtab[shdr->sh_name],
|
||||
(unsigned long)shdr->sh_addr,
|
||||
(long)shdr->sh_size);
|
||||
}
|
||||
|
||||
if (shdr->sh_type == SHT_NOBITS) {
|
||||
memset((void *)(uintptr_t)shdr->sh_addr, 0,
|
||||
shdr->sh_size);
|
||||
} else {
|
||||
image = (unsigned char *)addr + (ulong)shdr->sh_offset;
|
||||
memcpy((void *)(uintptr_t)shdr->sh_addr,
|
||||
(const void *)image, shdr->sh_size);
|
||||
}
|
||||
flush_cache(rounddown(shdr->sh_addr, ARCH_DMA_MINALIGN),
|
||||
roundup((shdr->sh_addr + shdr->sh_size),
|
||||
ARCH_DMA_MINALIGN) -
|
||||
rounddown(shdr->sh_addr, ARCH_DMA_MINALIGN));
|
||||
}
|
||||
|
||||
if (ehdr->e_machine == EM_PPC64 && (ehdr->e_flags &
|
||||
EF_PPC64_ELFV1_ABI)) {
|
||||
/*
|
||||
* For the 64-bit PowerPC ELF V1 ABI, e_entry is a function
|
||||
* descriptor pointer with the first double word being the
|
||||
* address of the entry point of the function.
|
||||
*/
|
||||
uintptr_t addr = ehdr->e_entry;
|
||||
|
||||
return *(Elf64_Addr *)addr;
|
||||
}
|
||||
|
||||
return ehdr->e_entry;
|
||||
}
|
||||
|
||||
/*
|
||||
* A very simple ELF loader, assumes the image is valid, returns the
|
||||
* entry point address.
|
||||
*
|
||||
* The loader firstly reads the EFI class to see if it's a 64-bit image.
|
||||
* If yes, call the ELF64 loader. Otherwise continue with the ELF32 loader.
|
||||
*/
|
||||
static unsigned long load_elf_image_phdr(unsigned long addr)
|
||||
{
|
||||
Elf32_Ehdr *ehdr; /* Elf header structure pointer */
|
||||
Elf32_Phdr *phdr; /* Program header structure pointer */
|
||||
int i;
|
||||
|
||||
ehdr = (Elf32_Ehdr *)addr;
|
||||
if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
|
||||
return load_elf64_image_phdr(addr);
|
||||
|
||||
phdr = (Elf32_Phdr *)(addr + ehdr->e_phoff);
|
||||
|
||||
/* Load each program header */
|
||||
for (i = 0; i < ehdr->e_phnum; ++i) {
|
||||
void *dst = (void *)(uintptr_t)phdr->p_paddr;
|
||||
void *src = (void *)addr + phdr->p_offset;
|
||||
|
||||
debug("Loading phdr %i to 0x%p (%i bytes)\n",
|
||||
i, dst, phdr->p_filesz);
|
||||
if (phdr->p_filesz)
|
||||
memcpy(dst, src, phdr->p_filesz);
|
||||
if (phdr->p_filesz != phdr->p_memsz)
|
||||
memset(dst + phdr->p_filesz, 0x00,
|
||||
phdr->p_memsz - phdr->p_filesz);
|
||||
flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN),
|
||||
roundup(phdr->p_memsz, ARCH_DMA_MINALIGN));
|
||||
++phdr;
|
||||
}
|
||||
|
||||
return ehdr->e_entry;
|
||||
}
|
||||
|
||||
static unsigned long load_elf_image_shdr(unsigned long addr)
|
||||
{
|
||||
Elf32_Ehdr *ehdr; /* Elf header structure pointer */
|
||||
Elf32_Shdr *shdr; /* Section header structure pointer */
|
||||
unsigned char *strtab = 0; /* String table pointer */
|
||||
unsigned char *image; /* Binary image pointer */
|
||||
int i; /* Loop counter */
|
||||
|
||||
ehdr = (Elf32_Ehdr *)addr;
|
||||
if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
|
||||
return load_elf64_image_shdr(addr);
|
||||
|
||||
/* Find the section header string table for output info */
|
||||
shdr = (Elf32_Shdr *)(addr + ehdr->e_shoff +
|
||||
(ehdr->e_shstrndx * sizeof(Elf32_Shdr)));
|
||||
|
||||
if (shdr->sh_type == SHT_STRTAB)
|
||||
strtab = (unsigned char *)(addr + shdr->sh_offset);
|
||||
|
||||
/* Load each appropriate section */
|
||||
for (i = 0; i < ehdr->e_shnum; ++i) {
|
||||
shdr = (Elf32_Shdr *)(addr + ehdr->e_shoff +
|
||||
(i * sizeof(Elf32_Shdr)));
|
||||
|
||||
if (!(shdr->sh_flags & SHF_ALLOC) ||
|
||||
shdr->sh_addr == 0 || shdr->sh_size == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strtab) {
|
||||
debug("%sing %s @ 0x%08lx (%ld bytes)\n",
|
||||
(shdr->sh_type == SHT_NOBITS) ? "Clear" : "Load",
|
||||
&strtab[shdr->sh_name],
|
||||
(unsigned long)shdr->sh_addr,
|
||||
(long)shdr->sh_size);
|
||||
}
|
||||
|
||||
if (shdr->sh_type == SHT_NOBITS) {
|
||||
memset((void *)(uintptr_t)shdr->sh_addr, 0,
|
||||
shdr->sh_size);
|
||||
} else {
|
||||
image = (unsigned char *)addr + shdr->sh_offset;
|
||||
memcpy((void *)(uintptr_t)shdr->sh_addr,
|
||||
(const void *)image, shdr->sh_size);
|
||||
}
|
||||
flush_cache(rounddown(shdr->sh_addr, ARCH_DMA_MINALIGN),
|
||||
roundup((shdr->sh_addr + shdr->sh_size),
|
||||
ARCH_DMA_MINALIGN) -
|
||||
rounddown(shdr->sh_addr, ARCH_DMA_MINALIGN));
|
||||
}
|
||||
|
||||
return ehdr->e_entry;
|
||||
}
|
||||
|
||||
/* Allow ports to override the default behavior */
|
||||
static unsigned long do_bootelf_exec(ulong (*entry)(int, char * const[]),
|
||||
int argc, char * const argv[])
|
||||
{
|
||||
unsigned long ret;
|
||||
|
||||
/*
|
||||
* pass address parameter as argv[0] (aka command name),
|
||||
* and all remaining args
|
||||
*/
|
||||
ret = entry(argc, argv);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine if a valid ELF image exists at the given memory location.
|
||||
* First look at the ELF header magic field, then make sure that it is
|
||||
* executable.
|
||||
*/
|
||||
int valid_elf_image(unsigned long addr)
|
||||
{
|
||||
Elf32_Ehdr *ehdr; /* Elf header structure pointer */
|
||||
|
||||
ehdr = (Elf32_Ehdr *)addr;
|
||||
|
||||
if (!IS_ELF(*ehdr)) {
|
||||
printf("## No elf image at address 0x%08lx\n", addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ehdr->e_type != ET_EXEC) {
|
||||
printf("## Not a 32-bit elf image at address 0x%08lx\n", addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Interpreter command to boot an arbitrary ELF image from memory */
|
||||
int do_bootelf(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
unsigned long addr; /* Address of the ELF image */
|
||||
unsigned long rc; /* Return value from user code */
|
||||
char *sload = NULL;
|
||||
const char *ep = env_get("autostart");
|
||||
int rcode = 0;
|
||||
|
||||
/* Consume 'bootelf' */
|
||||
argc--; argv++;
|
||||
|
||||
/* Check for flag. */
|
||||
if (argc >= 1 && (argv[0][0] == '-' && \
|
||||
(argv[0][1] == 'p' || argv[0][1] == 's'))) {
|
||||
sload = argv[0];
|
||||
/* Consume flag. */
|
||||
argc--; argv++;
|
||||
}
|
||||
/* Check for address. */
|
||||
if (argc >= 1 && strict_strtoul(argv[0], 16, &addr) != -EINVAL) {
|
||||
/* Consume address */
|
||||
argc--; argv++;
|
||||
} else
|
||||
addr = load_addr;
|
||||
|
||||
if (!valid_elf_image(addr))
|
||||
return 1;
|
||||
|
||||
if (sload && sload[1] == 'p')
|
||||
addr = load_elf_image_phdr(addr);
|
||||
else
|
||||
addr = load_elf_image_shdr(addr);
|
||||
|
||||
if (ep && !strcmp(ep, "no"))
|
||||
return rcode;
|
||||
|
||||
printf("## Starting application at 0x%08lx ...\n", addr);
|
||||
|
||||
/*
|
||||
* pass address parameter as argv[0] (aka command name),
|
||||
* and all remaining args
|
||||
*/
|
||||
rc = do_bootelf_exec((void *)addr, argc, argv);
|
||||
if (rc != 0)
|
||||
rcode = 1;
|
||||
|
||||
printf("## Application terminated, rc = 0x%lx\n", rc);
|
||||
|
||||
return rcode;
|
||||
}
|
||||
|
||||
/*
|
||||
* Interpreter command to boot VxWorks from a memory image. The image can
|
||||
* be either an ELF image or a raw binary. Will attempt to setup the
|
||||
* bootline and other parameters correctly.
|
||||
*/
|
||||
int do_bootvx(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
unsigned long addr; /* Address of image */
|
||||
unsigned long bootaddr = 0; /* Address to put the bootline */
|
||||
char *bootline; /* Text of the bootline */
|
||||
char *tmp; /* Temporary char pointer */
|
||||
char build_buf[128]; /* Buffer for building the bootline */
|
||||
int ptr = 0;
|
||||
#ifdef CONFIG_X86
|
||||
ulong base;
|
||||
struct e820_info *info;
|
||||
struct e820_entry *data;
|
||||
struct efi_gop_info *gop;
|
||||
struct vesa_mode_info *vesa = &mode_info.vesa;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Check the loadaddr variable.
|
||||
* If we don't know where the image is then we're done.
|
||||
*/
|
||||
if (argc < 2)
|
||||
addr = load_addr;
|
||||
else
|
||||
addr = simple_strtoul(argv[1], NULL, 16);
|
||||
|
||||
#if defined(CONFIG_CMD_NET)
|
||||
/*
|
||||
* Check to see if we need to tftp the image ourselves
|
||||
* before starting
|
||||
*/
|
||||
if ((argc == 2) && (strcmp(argv[1], "tftp") == 0)) {
|
||||
if (net_loop(TFTPGET) <= 0)
|
||||
return 1;
|
||||
printf("Automatic boot of VxWorks image at address 0x%08lx ...\n",
|
||||
addr);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This should equate to
|
||||
* NV_RAM_ADRS + NV_BOOT_OFFSET + NV_ENET_OFFSET
|
||||
* from the VxWorks BSP header files.
|
||||
* This will vary from board to board
|
||||
*/
|
||||
#if defined(CONFIG_SYS_VXWORKS_MAC_PTR)
|
||||
tmp = (char *)CONFIG_SYS_VXWORKS_MAC_PTR;
|
||||
eth_env_get_enetaddr("ethaddr", (uchar *)build_buf);
|
||||
memcpy(tmp, build_buf, 6);
|
||||
#else
|
||||
puts("## Ethernet MAC address not copied to NV RAM\n");
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_X86
|
||||
/*
|
||||
* Get VxWorks's physical memory base address from environment,
|
||||
* if we don't specify it in the environment, use a default one.
|
||||
*/
|
||||
base = env_get_hex("vx_phys_mem_base", VXWORKS_PHYS_MEM_BASE);
|
||||
data = (struct e820_entry *)(base + E820_DATA_OFFSET);
|
||||
info = (struct e820_info *)(base + E820_INFO_OFFSET);
|
||||
|
||||
memset(info, 0, sizeof(struct e820_info));
|
||||
info->sign = E820_SIGNATURE;
|
||||
info->entries = install_e820_map(E820MAX, data);
|
||||
info->addr = (info->entries - 1) * sizeof(struct e820_entry) +
|
||||
E820_DATA_OFFSET;
|
||||
|
||||
/*
|
||||
* Explicitly clear the bootloader image size otherwise if memory
|
||||
* at this offset happens to contain some garbage data, the final
|
||||
* available memory size for the kernel is insane.
|
||||
*/
|
||||
*(u32 *)(base + BOOT_IMAGE_SIZE_OFFSET) = 0;
|
||||
|
||||
/*
|
||||
* Prepare compatible framebuffer information block.
|
||||
* The VESA mode has to be 32-bit RGBA.
|
||||
*/
|
||||
if (vesa->x_resolution && vesa->y_resolution) {
|
||||
gop = (struct efi_gop_info *)(base + EFI_GOP_INFO_OFFSET);
|
||||
gop->magic = EFI_GOP_INFO_MAGIC;
|
||||
gop->info.version = 0;
|
||||
gop->info.width = vesa->x_resolution;
|
||||
gop->info.height = vesa->y_resolution;
|
||||
gop->info.pixel_format = EFI_GOT_RGBA8;
|
||||
gop->info.pixels_per_scanline = vesa->bytes_per_scanline / 4;
|
||||
gop->fb_base = vesa->phys_base_ptr;
|
||||
gop->fb_size = vesa->bytes_per_scanline * vesa->y_resolution;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Use bootaddr to find the location in memory that VxWorks
|
||||
* will look for the bootline string. The default value is
|
||||
* (LOCAL_MEM_LOCAL_ADRS + BOOT_LINE_OFFSET) as defined by
|
||||
* VxWorks BSP. For example, on PowerPC it defaults to 0x4200.
|
||||
*/
|
||||
tmp = env_get("bootaddr");
|
||||
if (!tmp) {
|
||||
#ifdef CONFIG_X86
|
||||
bootaddr = base + X86_BOOT_LINE_OFFSET;
|
||||
#else
|
||||
printf("## VxWorks bootline address not specified\n");
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!bootaddr)
|
||||
bootaddr = simple_strtoul(tmp, NULL, 16);
|
||||
|
||||
/*
|
||||
* Check to see if the bootline is defined in the 'bootargs' parameter.
|
||||
* If it is not defined, we may be able to construct the info.
|
||||
*/
|
||||
bootline = env_get("bootargs");
|
||||
if (!bootline) {
|
||||
tmp = env_get("bootdev");
|
||||
if (tmp) {
|
||||
strcpy(build_buf, tmp);
|
||||
ptr = strlen(tmp);
|
||||
} else {
|
||||
printf("## VxWorks boot device not specified\n");
|
||||
}
|
||||
|
||||
tmp = env_get("bootfile");
|
||||
if (tmp)
|
||||
ptr += sprintf(build_buf + ptr, "host:%s ", tmp);
|
||||
else
|
||||
ptr += sprintf(build_buf + ptr, "host:vxWorks ");
|
||||
|
||||
/*
|
||||
* The following parameters are only needed if 'bootdev'
|
||||
* is an ethernet device, otherwise they are optional.
|
||||
*/
|
||||
tmp = env_get("ipaddr");
|
||||
if (tmp) {
|
||||
ptr += sprintf(build_buf + ptr, "e=%s", tmp);
|
||||
tmp = env_get("netmask");
|
||||
if (tmp) {
|
||||
u32 mask = env_get_ip("netmask").s_addr;
|
||||
ptr += sprintf(build_buf + ptr,
|
||||
":%08x ", ntohl(mask));
|
||||
} else {
|
||||
ptr += sprintf(build_buf + ptr, " ");
|
||||
}
|
||||
}
|
||||
|
||||
tmp = env_get("serverip");
|
||||
if (tmp)
|
||||
ptr += sprintf(build_buf + ptr, "h=%s ", tmp);
|
||||
|
||||
tmp = env_get("gatewayip");
|
||||
if (tmp)
|
||||
ptr += sprintf(build_buf + ptr, "g=%s ", tmp);
|
||||
|
||||
tmp = env_get("hostname");
|
||||
if (tmp)
|
||||
ptr += sprintf(build_buf + ptr, "tn=%s ", tmp);
|
||||
|
||||
tmp = env_get("othbootargs");
|
||||
if (tmp) {
|
||||
strcpy(build_buf + ptr, tmp);
|
||||
ptr += strlen(tmp);
|
||||
}
|
||||
|
||||
bootline = build_buf;
|
||||
}
|
||||
|
||||
memcpy((void *)bootaddr, bootline, max(strlen(bootline), (size_t)255));
|
||||
flush_cache(bootaddr, max(strlen(bootline), (size_t)255));
|
||||
printf("## Using bootline (@ 0x%lx): %s\n", bootaddr, (char *)bootaddr);
|
||||
|
||||
/*
|
||||
* If the data at the load address is an elf image, then
|
||||
* treat it like an elf image. Otherwise, assume that it is a
|
||||
* binary image.
|
||||
*/
|
||||
if (valid_elf_image(addr))
|
||||
addr = load_elf_image_phdr(addr);
|
||||
else
|
||||
puts("## Not an ELF image, assuming binary\n");
|
||||
|
||||
printf("## Starting vxWorks at 0x%08lx ...\n", addr);
|
||||
|
||||
dcache_disable();
|
||||
#if defined(CONFIG_ARM64) && defined(CONFIG_ARMV8_PSCI)
|
||||
armv8_setup_psci();
|
||||
smp_kick_all_cpus();
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_X86
|
||||
/* VxWorks on x86 uses stack to pass parameters */
|
||||
((asmlinkage void (*)(int))addr)(0);
|
||||
#else
|
||||
((void (*)(int))addr)(0);
|
||||
#endif
|
||||
|
||||
puts("## vxWorks terminated\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
bootelf, CONFIG_SYS_MAXARGS, 0, do_bootelf,
|
||||
"Boot from an ELF image in memory",
|
||||
"[-p|-s] [address]\n"
|
||||
"\t- load ELF image at [address] via program headers (-p)\n"
|
||||
"\t or via section headers (-s)"
|
||||
);
|
||||
|
||||
U_BOOT_CMD(
|
||||
bootvx, 2, 0, do_bootvx,
|
||||
"Boot vxWorks from an ELF image",
|
||||
" [address] - load address of vxWorks ELF image."
|
||||
);
|
||||
1101
cmd/ethsw.c
Normal file
1101
cmd/ethsw.c
Normal file
File diff suppressed because it is too large
Load Diff
25
cmd/exit.c
Normal file
25
cmd/exit.c
Normal file
@@ -0,0 +1,25 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2000-2009
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
|
||||
static int do_exit(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
int r;
|
||||
|
||||
r = 0;
|
||||
if (argc > 1)
|
||||
r = simple_strtoul(argv[1], NULL, 10);
|
||||
|
||||
return -r - 2;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
exit, 2, 1, do_exit,
|
||||
"exit script",
|
||||
""
|
||||
);
|
||||
50
cmd/ext2.c
Normal file
50
cmd/ext2.c
Normal file
@@ -0,0 +1,50 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2011 - 2012 Samsung Electronics
|
||||
* EXT4 filesystem implementation in Uboot by
|
||||
* Uma Shankar <uma.shankar@samsung.com>
|
||||
* Manjunatha C Achar <a.manjunatha@samsung.com>
|
||||
|
||||
* (C) Copyright 2004
|
||||
* esd gmbh <www.esd-electronics.com>
|
||||
* Reinhard Arlt <reinhard.arlt@esd-electronics.com>
|
||||
*
|
||||
* made from cmd_reiserfs by
|
||||
*
|
||||
* (C) Copyright 2003 - 2004
|
||||
* Sysgo Real-Time Solutions, AG <www.elinos.com>
|
||||
* Pavel Bartusek <pba@sysgo.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Ext2fs support
|
||||
*/
|
||||
#include <fs.h>
|
||||
|
||||
static int do_ext2ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
return do_ls(cmdtp, flag, argc, argv, FS_TYPE_EXT);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Ext2fs boot command intepreter. Derived from diskboot
|
||||
*/
|
||||
int do_ext2load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
return do_load(cmdtp, flag, argc, argv, FS_TYPE_EXT);
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
ext2ls, 4, 1, do_ext2ls,
|
||||
"list files in a directory (default /)",
|
||||
"<interface> <dev[:part]> [directory]\n"
|
||||
" - list files from 'dev' on 'interface' in a 'directory'"
|
||||
)
|
||||
|
||||
U_BOOT_CMD(
|
||||
ext2load, 6, 0, do_ext2load,
|
||||
"load binary file from a Ext2 filesystem",
|
||||
"<interface> [<dev[:part]> [addr [filename [bytes [pos]]]]]\n"
|
||||
" - load binary file 'filename' from 'dev' on 'interface'\n"
|
||||
" to address 'addr' from ext2 filesystem."
|
||||
)
|
||||
93
cmd/ext4.c
Normal file
93
cmd/ext4.c
Normal file
@@ -0,0 +1,93 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2011 - 2012 Samsung Electronics
|
||||
* EXT4 filesystem implementation in Uboot by
|
||||
* Uma Shankar <uma.shankar@samsung.com>
|
||||
* Manjunatha C Achar <a.manjunatha@samsung.com>
|
||||
*
|
||||
* Ext4fs support
|
||||
* made from existing cmd_ext2.c file of Uboot
|
||||
*
|
||||
* (C) Copyright 2004
|
||||
* esd gmbh <www.esd-electronics.com>
|
||||
* Reinhard Arlt <reinhard.arlt@esd-electronics.com>
|
||||
*
|
||||
* made from cmd_reiserfs by
|
||||
*
|
||||
* (C) Copyright 2003 - 2004
|
||||
* Sysgo Real-Time Solutions, AG <www.elinos.com>
|
||||
* Pavel Bartusek <pba@sysgo.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changelog:
|
||||
* 0.1 - Newly created file for ext4fs support. Taken from cmd_ext2.c
|
||||
* file in uboot. Added ext4fs ls load and write support.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <part.h>
|
||||
#include <config.h>
|
||||
#include <command.h>
|
||||
#include <image.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <asm/byteorder.h>
|
||||
#include <ext4fs.h>
|
||||
#include <linux/stat.h>
|
||||
#include <malloc.h>
|
||||
#include <fs.h>
|
||||
|
||||
#if defined(CONFIG_CMD_USB) && defined(CONFIG_USB_STORAGE)
|
||||
#include <usb.h>
|
||||
#endif
|
||||
|
||||
int do_ext4_size(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char *const argv[])
|
||||
{
|
||||
return do_size(cmdtp, flag, argc, argv, FS_TYPE_EXT);
|
||||
}
|
||||
|
||||
int do_ext4_load(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char *const argv[])
|
||||
{
|
||||
return do_load(cmdtp, flag, argc, argv, FS_TYPE_EXT);
|
||||
}
|
||||
|
||||
int do_ext4_ls(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
|
||||
{
|
||||
return do_ls(cmdtp, flag, argc, argv, FS_TYPE_EXT);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_CMD_EXT4_WRITE)
|
||||
int do_ext4_write(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char *const argv[])
|
||||
{
|
||||
return do_save(cmdtp, flag, argc, argv, FS_TYPE_EXT);
|
||||
}
|
||||
|
||||
U_BOOT_CMD(ext4write, 7, 1, do_ext4_write,
|
||||
"create a file in the root directory",
|
||||
"<interface> <dev[:part]> <addr> <absolute filename path>\n"
|
||||
" [sizebytes] [file offset]\n"
|
||||
" - create a file in / directory");
|
||||
|
||||
#endif
|
||||
|
||||
U_BOOT_CMD(
|
||||
ext4size, 4, 0, do_ext4_size,
|
||||
"determine a file's size",
|
||||
"<interface> <dev[:part]> <filename>\n"
|
||||
" - Find file 'filename' from 'dev' on 'interface'\n"
|
||||
" and determine its size."
|
||||
);
|
||||
|
||||
U_BOOT_CMD(ext4ls, 4, 1, do_ext4_ls,
|
||||
"list files in a directory (default /)",
|
||||
"<interface> <dev[:part]> [directory]\n"
|
||||
" - list files from 'dev' on 'interface' in a 'directory'");
|
||||
|
||||
U_BOOT_CMD(ext4load, 7, 0, do_ext4_load,
|
||||
"load binary file from a Ext4 filesystem",
|
||||
"<interface> [<dev[:part]> [addr [filename [bytes [pos]]]]]\n"
|
||||
" - load binary file 'filename' from 'dev' on 'interface'\n"
|
||||
" to address 'addr' from ext4 filesystem");
|
||||
162
cmd/fastboot.c
Normal file
162
cmd/fastboot.c
Normal file
@@ -0,0 +1,162 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2008 - 2009 Windriver, <www.windriver.com>
|
||||
* Author: Tom Rix <Tom.Rix@windriver.com>
|
||||
*
|
||||
* (C) Copyright 2014 Linaro, Ltd.
|
||||
* Rob Herring <robh@kernel.org>
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <console.h>
|
||||
#include <g_dnl.h>
|
||||
#include <fastboot.h>
|
||||
#include <net.h>
|
||||
#include <usb.h>
|
||||
#include <watchdog.h>
|
||||
|
||||
static int do_fastboot_udp(int argc, char *const argv[],
|
||||
uintptr_t buf_addr, size_t buf_size)
|
||||
{
|
||||
#if CONFIG_IS_ENABLED(UDP_FUNCTION_FASTBOOT)
|
||||
int err = net_loop(FASTBOOT);
|
||||
|
||||
if (err < 0) {
|
||||
printf("fastboot udp error: %d\n", err);
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
return CMD_RET_SUCCESS;
|
||||
#else
|
||||
pr_err("Fastboot UDP not enabled\n");
|
||||
return CMD_RET_FAILURE;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int do_fastboot_usb(int argc, char *const argv[],
|
||||
uintptr_t buf_addr, size_t buf_size)
|
||||
{
|
||||
#if CONFIG_IS_ENABLED(USB_FUNCTION_FASTBOOT)
|
||||
int controller_index;
|
||||
char *usb_controller;
|
||||
char *endp;
|
||||
int ret;
|
||||
|
||||
if (argc < 2)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
usb_controller = argv[1];
|
||||
controller_index = simple_strtoul(usb_controller, &endp, 0);
|
||||
if (*endp != '\0') {
|
||||
pr_err("Error: Wrong USB controller index format\n");
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
ret = usb_gadget_initialize(controller_index);
|
||||
if (ret) {
|
||||
pr_err("USB init failed: %d\n", ret);
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
g_dnl_clear_detach();
|
||||
ret = g_dnl_register("usb_dnl_fastboot");
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!g_dnl_board_usb_cable_connected()) {
|
||||
puts("\rUSB cable not detected.\n" \
|
||||
"Command exit.\n");
|
||||
ret = CMD_RET_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if (g_dnl_detach())
|
||||
break;
|
||||
if (ctrlc())
|
||||
break;
|
||||
WATCHDOG_RESET();
|
||||
usb_gadget_handle_interrupts(controller_index);
|
||||
}
|
||||
|
||||
ret = CMD_RET_SUCCESS;
|
||||
|
||||
exit:
|
||||
g_dnl_unregister();
|
||||
g_dnl_clear_detach();
|
||||
usb_gadget_release(controller_index);
|
||||
|
||||
return ret;
|
||||
#else
|
||||
pr_err("Fastboot USB not enabled\n");
|
||||
return CMD_RET_FAILURE;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int do_fastboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
|
||||
{
|
||||
uintptr_t buf_addr = (uintptr_t)NULL;
|
||||
size_t buf_size = 0;
|
||||
|
||||
if (argc < 2)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
while (argc > 1 && **(argv + 1) == '-') {
|
||||
char *arg = *++argv;
|
||||
|
||||
--argc;
|
||||
while (*++arg) {
|
||||
switch (*arg) {
|
||||
case 'l':
|
||||
if (--argc <= 0)
|
||||
return CMD_RET_USAGE;
|
||||
buf_addr = simple_strtoul(*++argv, NULL, 16);
|
||||
goto NXTARG;
|
||||
|
||||
case 's':
|
||||
if (--argc <= 0)
|
||||
return CMD_RET_USAGE;
|
||||
buf_size = simple_strtoul(*++argv, NULL, 16);
|
||||
goto NXTARG;
|
||||
|
||||
default:
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
}
|
||||
NXTARG:
|
||||
;
|
||||
}
|
||||
|
||||
/* Handle case when USB controller param is just '-' */
|
||||
if (argc == 1) {
|
||||
pr_err("Error: Incorrect USB controller index\n");
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
fastboot_init((void *)buf_addr, buf_size);
|
||||
|
||||
if (!strcmp(argv[1], "udp"))
|
||||
return do_fastboot_udp(argc, argv, buf_addr, buf_size);
|
||||
|
||||
if (!strcmp(argv[1], "usb")) {
|
||||
argv++;
|
||||
argc--;
|
||||
}
|
||||
|
||||
return do_fastboot_usb(argc, argv, buf_addr, buf_size);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SYS_LONGHELP
|
||||
static char fastboot_help_text[] =
|
||||
"[-l addr] [-s size] usb <controller> | udp\n"
|
||||
"\taddr - address of buffer used during data transfers ("
|
||||
__stringify(CONFIG_FASTBOOT_BUF_ADDR) ")\n"
|
||||
"\tsize - size of buffer used during data transfers ("
|
||||
__stringify(CONFIG_FASTBOOT_BUF_SIZE) ")"
|
||||
;
|
||||
#endif
|
||||
|
||||
U_BOOT_CMD(
|
||||
fastboot, CONFIG_SYS_MAXARGS, 1, do_fastboot,
|
||||
"run as a fastboot usb or udp device", fastboot_help_text
|
||||
);
|
||||
179
cmd/fat.c
Normal file
179
cmd/fat.c
Normal file
@@ -0,0 +1,179 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2002
|
||||
* Richard Jones, rjones@nexus-tech.net
|
||||
*/
|
||||
|
||||
/*
|
||||
* Boot support
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <s_record.h>
|
||||
#include <net.h>
|
||||
#include <ata.h>
|
||||
#include <asm/io.h>
|
||||
#include <mapmem.h>
|
||||
#include <part.h>
|
||||
#include <fat.h>
|
||||
#include <fs.h>
|
||||
|
||||
int do_fat_size(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
return do_size(cmdtp, flag, argc, argv, FS_TYPE_FAT);
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
fatsize, 4, 0, do_fat_size,
|
||||
"determine a file's size",
|
||||
"<interface> <dev[:part]> <filename>\n"
|
||||
" - Find file 'filename' from 'dev' on 'interface'\n"
|
||||
" and determine its size."
|
||||
);
|
||||
|
||||
int do_fat_fsload (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
return do_load(cmdtp, flag, argc, argv, FS_TYPE_FAT);
|
||||
}
|
||||
|
||||
|
||||
U_BOOT_CMD(
|
||||
fatload, 7, 0, do_fat_fsload,
|
||||
"load binary file from a dos filesystem",
|
||||
"<interface> [<dev[:part]> [<addr> [<filename> [bytes [pos]]]]]\n"
|
||||
" - Load binary file 'filename' from 'dev' on 'interface'\n"
|
||||
" to address 'addr' from dos filesystem.\n"
|
||||
" 'pos' gives the file position to start loading from.\n"
|
||||
" If 'pos' is omitted, 0 is used. 'pos' requires 'bytes'.\n"
|
||||
" 'bytes' gives the size to load. If 'bytes' is 0 or omitted,\n"
|
||||
" the load stops on end of file.\n"
|
||||
" If either 'pos' or 'bytes' are not aligned to\n"
|
||||
" ARCH_DMA_MINALIGN then a misaligned buffer warning will\n"
|
||||
" be printed and performance will suffer for the load."
|
||||
);
|
||||
|
||||
static int do_fat_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
return do_ls(cmdtp, flag, argc, argv, FS_TYPE_FAT);
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
fatls, 4, 1, do_fat_ls,
|
||||
"list files in a directory (default /)",
|
||||
"<interface> [<dev[:part]>] [directory]\n"
|
||||
" - list files from 'dev' on 'interface' in a 'directory'"
|
||||
);
|
||||
|
||||
static int do_fat_fsinfo(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
int dev, part;
|
||||
struct blk_desc *dev_desc;
|
||||
disk_partition_t info;
|
||||
|
||||
if (argc < 2) {
|
||||
printf("usage: fatinfo <interface> [<dev[:part]>]\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
part = blk_get_device_part_str(argv[1], argv[2], &dev_desc, &info, 1);
|
||||
if (part < 0)
|
||||
return 1;
|
||||
|
||||
dev = dev_desc->devnum;
|
||||
if (fat_set_blk_dev(dev_desc, &info) != 0) {
|
||||
printf("\n** Unable to use %s %d:%d for fatinfo **\n",
|
||||
argv[1], dev, part);
|
||||
return 1;
|
||||
}
|
||||
return file_fat_detectfs();
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
fatinfo, 3, 1, do_fat_fsinfo,
|
||||
"print information about filesystem",
|
||||
"<interface> [<dev[:part]>]\n"
|
||||
" - print information about filesystem from 'dev' on 'interface'"
|
||||
);
|
||||
|
||||
#ifdef CONFIG_FAT_WRITE
|
||||
static int do_fat_fswrite(cmd_tbl_t *cmdtp, int flag,
|
||||
int argc, char * const argv[])
|
||||
{
|
||||
loff_t size;
|
||||
int ret;
|
||||
unsigned long addr;
|
||||
unsigned long count;
|
||||
long offset;
|
||||
struct blk_desc *dev_desc = NULL;
|
||||
disk_partition_t info;
|
||||
int dev = 0;
|
||||
int part = 1;
|
||||
void *buf;
|
||||
|
||||
if (argc < 5)
|
||||
return cmd_usage(cmdtp);
|
||||
|
||||
part = blk_get_device_part_str(argv[1], argv[2], &dev_desc, &info, 1);
|
||||
if (part < 0)
|
||||
return 1;
|
||||
|
||||
dev = dev_desc->devnum;
|
||||
|
||||
if (fat_set_blk_dev(dev_desc, &info) != 0) {
|
||||
printf("\n** Unable to use %s %d:%d for fatwrite **\n",
|
||||
argv[1], dev, part);
|
||||
return 1;
|
||||
}
|
||||
addr = simple_strtoul(argv[3], NULL, 16);
|
||||
count = (argc <= 5) ? 0 : simple_strtoul(argv[5], NULL, 16);
|
||||
/* offset should be a hex, but "-1" is allowed */
|
||||
offset = (argc <= 6) ? 0 : simple_strtol(argv[6], NULL, 16);
|
||||
|
||||
buf = map_sysmem(addr, count);
|
||||
ret = file_fat_write(argv[4], buf, offset, count, &size);
|
||||
unmap_sysmem(buf);
|
||||
if (ret < 0) {
|
||||
printf("\n** Unable to write \"%s\" from %s %d:%d **\n",
|
||||
argv[4], argv[1], dev, part);
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("%llu bytes written\n", size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
fatwrite, 7, 0, do_fat_fswrite,
|
||||
"write file into a dos filesystem",
|
||||
"<interface> <dev[:part]> <addr> <filename> [<bytes> [<offset>]]\n"
|
||||
" - write file 'filename' from the address 'addr' in RAM\n"
|
||||
" to 'dev' on 'interface'"
|
||||
);
|
||||
|
||||
static int do_fat_rm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
return do_rm(cmdtp, flag, argc, argv, FS_TYPE_FAT);
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
fatrm, 4, 1, do_fat_rm,
|
||||
"delete a file",
|
||||
"<interface> [<dev[:part]>] <filename>\n"
|
||||
" - delete a file from 'dev' on 'interface'"
|
||||
);
|
||||
|
||||
static int do_fat_mkdir(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
return do_mkdir(cmdtp, flag, argc, argv, FS_TYPE_FAT);
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
fatmkdir, 4, 1, do_fat_mkdir,
|
||||
"create a directory",
|
||||
"<interface> [<dev[:part]>] <directory>\n"
|
||||
" - create a directory in 'dev' on 'interface'"
|
||||
);
|
||||
#endif
|
||||
752
cmd/fdc.c
Normal file
752
cmd/fdc.c
Normal file
@@ -0,0 +1,752 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2001
|
||||
* Denis Peter, MPL AG, d.peter@mpl.ch.
|
||||
*/
|
||||
/*
|
||||
* Floppy Disk support
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <config.h>
|
||||
#include <command.h>
|
||||
#include <image.h>
|
||||
#include <irq_func.h>
|
||||
|
||||
|
||||
#undef FDC_DEBUG
|
||||
|
||||
#ifdef FDC_DEBUG
|
||||
#define PRINTF(fmt,args...) printf (fmt ,##args)
|
||||
#else
|
||||
#define PRINTF(fmt,args...)
|
||||
#endif
|
||||
|
||||
/*#if defined(CONFIG_CMD_DATE) */
|
||||
/*#include <rtc.h> */
|
||||
/*#endif */
|
||||
|
||||
typedef struct {
|
||||
int flags; /* connected drives ect */
|
||||
unsigned long blnr; /* Logical block nr */
|
||||
uchar drive; /* drive no */
|
||||
uchar cmdlen; /* cmd length */
|
||||
uchar cmd[16]; /* cmd desc */
|
||||
uchar dma; /* if > 0 dma enabled */
|
||||
uchar result[11]; /* status information */
|
||||
uchar resultlen; /* lenght of result */
|
||||
} FDC_COMMAND_STRUCT;
|
||||
|
||||
/* flags: only the lower 8bit used:
|
||||
* bit 0 if set drive 0 is present
|
||||
* bit 1 if set drive 1 is present
|
||||
* bit 2 if set drive 2 is present
|
||||
* bit 3 if set drive 3 is present
|
||||
* bit 4 if set disk in drive 0 is inserted
|
||||
* bit 5 if set disk in drive 1 is inserted
|
||||
* bit 6 if set disk in drive 2 is inserted
|
||||
* bit 7 if set disk in drive 4 is inserted
|
||||
*/
|
||||
|
||||
/* cmd indexes */
|
||||
#define COMMAND 0
|
||||
#define DRIVE 1
|
||||
#define CONFIG0 1
|
||||
#define SPEC_HUTSRT 1
|
||||
#define TRACK 2
|
||||
#define CONFIG1 2
|
||||
#define SPEC_HLT 2
|
||||
#define HEAD 3
|
||||
#define CONFIG2 3
|
||||
#define SECTOR 4
|
||||
#define SECTOR_SIZE 5
|
||||
#define LAST_TRACK 6
|
||||
#define GAP 7
|
||||
#define DTL 8
|
||||
/* result indexes */
|
||||
#define STATUS_0 0
|
||||
#define STATUS_PCN 1
|
||||
#define STATUS_1 1
|
||||
#define STATUS_2 2
|
||||
#define STATUS_TRACK 3
|
||||
#define STATUS_HEAD 4
|
||||
#define STATUS_SECT 5
|
||||
#define STATUS_SECT_SIZE 6
|
||||
|
||||
|
||||
/* Register addresses */
|
||||
#define FDC_BASE 0x3F0
|
||||
#define FDC_SRA FDC_BASE + 0 /* Status Register A */
|
||||
#define FDC_SRB FDC_BASE + 1 /* Status Register B */
|
||||
#define FDC_DOR FDC_BASE + 2 /* Digital Output Register */
|
||||
#define FDC_TDR FDC_BASE + 3 /* Tape Drive Register */
|
||||
#define FDC_DSR FDC_BASE + 4 /* Data rate Register */
|
||||
#define FDC_MSR FDC_BASE + 4 /* Main Status Register */
|
||||
#define FDC_FIFO FDC_BASE + 5 /* FIFO */
|
||||
#define FDC_DIR FDC_BASE + 6 /* Digital Input Register */
|
||||
#define FDC_CCR FDC_BASE + 7 /* Configuration Control */
|
||||
/* Commands */
|
||||
#define FDC_CMD_SENSE_INT 0x08
|
||||
#define FDC_CMD_CONFIGURE 0x13
|
||||
#define FDC_CMD_SPECIFY 0x03
|
||||
#define FDC_CMD_RECALIBRATE 0x07
|
||||
#define FDC_CMD_READ 0x06
|
||||
#define FDC_CMD_READ_TRACK 0x02
|
||||
#define FDC_CMD_READ_ID 0x0A
|
||||
#define FDC_CMD_DUMP_REG 0x0E
|
||||
#define FDC_CMD_SEEK 0x0F
|
||||
|
||||
#define FDC_CMD_SENSE_INT_LEN 0x01
|
||||
#define FDC_CMD_CONFIGURE_LEN 0x04
|
||||
#define FDC_CMD_SPECIFY_LEN 0x03
|
||||
#define FDC_CMD_RECALIBRATE_LEN 0x02
|
||||
#define FDC_CMD_READ_LEN 0x09
|
||||
#define FDC_CMD_READ_TRACK_LEN 0x09
|
||||
#define FDC_CMD_READ_ID_LEN 0x02
|
||||
#define FDC_CMD_DUMP_REG_LEN 0x01
|
||||
#define FDC_CMD_SEEK_LEN 0x03
|
||||
|
||||
#define FDC_FIFO_THR 0x0C
|
||||
#define FDC_FIFO_DIS 0x00
|
||||
#define FDC_IMPLIED_SEEK 0x01
|
||||
#define FDC_POLL_DIS 0x00
|
||||
#define FDC_PRE_TRK 0x00
|
||||
#define FDC_CONFIGURE FDC_FIFO_THR | (FDC_POLL_DIS<<4) | (FDC_FIFO_DIS<<5) | (FDC_IMPLIED_SEEK << 6)
|
||||
#define FDC_MFM_MODE 0x01 /* MFM enable */
|
||||
#define FDC_SKIP_MODE 0x00 /* skip enable */
|
||||
|
||||
#define FDC_TIME_OUT 100000 /* time out */
|
||||
#define FDC_RW_RETRIES 3 /* read write retries */
|
||||
#define FDC_CAL_RETRIES 3 /* calibration and seek retries */
|
||||
|
||||
|
||||
/* Disk structure */
|
||||
typedef struct {
|
||||
unsigned int size; /* nr of sectors total */
|
||||
unsigned int sect; /* sectors per track */
|
||||
unsigned int head; /* nr of heads */
|
||||
unsigned int track; /* nr of tracks */
|
||||
unsigned int stretch; /* !=0 means double track steps */
|
||||
unsigned char gap; /* gap1 size */
|
||||
unsigned char rate; /* data rate. |= 0x40 for perpendicular */
|
||||
unsigned char spec1; /* stepping rate, head unload time */
|
||||
unsigned char fmt_gap;/* gap2 size */
|
||||
unsigned char hlt; /* head load time */
|
||||
unsigned char sect_code;/* Sector Size code */
|
||||
const char * name; /* used only for predefined formats */
|
||||
} FD_GEO_STRUCT;
|
||||
|
||||
|
||||
/* supported Floppy types (currently only one) */
|
||||
const static FD_GEO_STRUCT floppy_type[2] = {
|
||||
{ 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,16,2,"H1440" }, /* 7 1.44MB 3.5" */
|
||||
{ 0, 0,0, 0,0,0x00,0x00,0x00,0x00, 0,0,NULL }, /* end of table */
|
||||
};
|
||||
|
||||
static FDC_COMMAND_STRUCT cmd; /* global command struct */
|
||||
|
||||
/* If the boot drive number is undefined, we assume it's drive 0 */
|
||||
#ifndef CONFIG_SYS_FDC_DRIVE_NUMBER
|
||||
#define CONFIG_SYS_FDC_DRIVE_NUMBER 0
|
||||
#endif
|
||||
|
||||
/* Hardware access */
|
||||
#ifndef CONFIG_SYS_ISA_IO_STRIDE
|
||||
#define CONFIG_SYS_ISA_IO_STRIDE 1
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SYS_ISA_IO_OFFSET
|
||||
#define CONFIG_SYS_ISA_IO_OFFSET 0
|
||||
#endif
|
||||
|
||||
/* Supporting Functions */
|
||||
/* reads a Register of the FDC */
|
||||
unsigned char read_fdc_reg(unsigned int addr)
|
||||
{
|
||||
volatile unsigned char *val =
|
||||
(volatile unsigned char *)(CONFIG_SYS_ISA_IO_BASE_ADDRESS +
|
||||
(addr * CONFIG_SYS_ISA_IO_STRIDE) +
|
||||
CONFIG_SYS_ISA_IO_OFFSET);
|
||||
|
||||
return val [0];
|
||||
}
|
||||
|
||||
/* writes a Register of the FDC */
|
||||
void write_fdc_reg(unsigned int addr, unsigned char val)
|
||||
{
|
||||
volatile unsigned char *tmp =
|
||||
(volatile unsigned char *)(CONFIG_SYS_ISA_IO_BASE_ADDRESS +
|
||||
(addr * CONFIG_SYS_ISA_IO_STRIDE) +
|
||||
CONFIG_SYS_ISA_IO_OFFSET);
|
||||
tmp[0]=val;
|
||||
}
|
||||
|
||||
/* waits for an interrupt (polling) */
|
||||
int wait_for_fdc_int(void)
|
||||
{
|
||||
unsigned long timeout;
|
||||
timeout = FDC_TIME_OUT;
|
||||
while((read_fdc_reg(FDC_SRA)&0x80)==0) {
|
||||
timeout--;
|
||||
udelay(10);
|
||||
if(timeout==0) /* timeout occurred */
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* reads a byte from the FIFO of the FDC and checks direction and RQM bit
|
||||
of the MSR. returns -1 if timeout, or byte if ok */
|
||||
int read_fdc_byte(void)
|
||||
{
|
||||
unsigned long timeout;
|
||||
timeout = FDC_TIME_OUT;
|
||||
while((read_fdc_reg(FDC_MSR)&0xC0)!=0xC0) {
|
||||
/* direction out and ready */
|
||||
udelay(10);
|
||||
timeout--;
|
||||
if(timeout==0) /* timeout occurred */
|
||||
return -1;
|
||||
}
|
||||
return read_fdc_reg(FDC_FIFO);
|
||||
}
|
||||
|
||||
/* if the direction of the FIFO is wrong, this routine is used to
|
||||
empty the FIFO. Should _not_ be used */
|
||||
int fdc_need_more_output(void)
|
||||
{
|
||||
unsigned char c;
|
||||
while((read_fdc_reg(FDC_MSR)&0xC0)==0xC0) {
|
||||
c=(unsigned char)read_fdc_byte();
|
||||
printf("Error: more output: %x\n",c);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/* writes a byte to the FIFO of the FDC and checks direction and RQM bit
|
||||
of the MSR */
|
||||
int write_fdc_byte(unsigned char val)
|
||||
{
|
||||
unsigned long timeout;
|
||||
timeout = FDC_TIME_OUT;
|
||||
while((read_fdc_reg(FDC_MSR)&0xC0)!=0x80) {
|
||||
/* direction in and ready for byte */
|
||||
timeout--;
|
||||
udelay(10);
|
||||
fdc_need_more_output();
|
||||
if(timeout==0) /* timeout occurred */
|
||||
return false;
|
||||
}
|
||||
write_fdc_reg(FDC_FIFO,val);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* sets up all FDC commands and issues it to the FDC. If
|
||||
the command causes direct results (no Execution Phase)
|
||||
the result is be read as well. */
|
||||
|
||||
int fdc_issue_cmd(FDC_COMMAND_STRUCT *pCMD,FD_GEO_STRUCT *pFG)
|
||||
{
|
||||
int i;
|
||||
unsigned long head,track,sect,timeout;
|
||||
track = pCMD->blnr / (pFG->sect * pFG->head); /* track nr */
|
||||
sect = pCMD->blnr % (pFG->sect * pFG->head); /* remaining blocks */
|
||||
head = sect / pFG->sect; /* head nr */
|
||||
sect = sect % pFG->sect; /* remaining blocks */
|
||||
sect++; /* sectors are 1 based */
|
||||
PRINTF("Cmd 0x%02x Track %ld, Head %ld, Sector %ld, Drive %d (blnr %ld)\n",
|
||||
pCMD->cmd[0],track,head,sect,pCMD->drive,pCMD->blnr);
|
||||
|
||||
if(head|=0) { /* max heads = 2 */
|
||||
pCMD->cmd[DRIVE]=pCMD->drive | 0x04; /* head 1 */
|
||||
pCMD->cmd[HEAD]=(unsigned char) head; /* head register */
|
||||
}
|
||||
else {
|
||||
pCMD->cmd[DRIVE]=pCMD->drive; /* head 0 */
|
||||
pCMD->cmd[HEAD]=(unsigned char) head; /* head register */
|
||||
}
|
||||
pCMD->cmd[TRACK]=(unsigned char) track; /* track */
|
||||
switch (pCMD->cmd[COMMAND]) {
|
||||
case FDC_CMD_READ:
|
||||
pCMD->cmd[SECTOR]=(unsigned char) sect; /* sector */
|
||||
pCMD->cmd[SECTOR_SIZE]=pFG->sect_code; /* sector size code */
|
||||
pCMD->cmd[LAST_TRACK]=pFG->sect; /* End of track */
|
||||
pCMD->cmd[GAP]=pFG->gap; /* gap */
|
||||
pCMD->cmd[DTL]=0xFF; /* DTL */
|
||||
pCMD->cmdlen=FDC_CMD_READ_LEN;
|
||||
pCMD->cmd[COMMAND]|=(FDC_MFM_MODE<<6); /* set MFM bit */
|
||||
pCMD->cmd[COMMAND]|=(FDC_SKIP_MODE<<5); /* set Skip bit */
|
||||
pCMD->resultlen=0; /* result only after execution */
|
||||
break;
|
||||
case FDC_CMD_SEEK:
|
||||
pCMD->cmdlen=FDC_CMD_SEEK_LEN;
|
||||
pCMD->resultlen=0; /* no result */
|
||||
break;
|
||||
case FDC_CMD_CONFIGURE:
|
||||
pCMD->cmd[CONFIG0]=0;
|
||||
pCMD->cmd[CONFIG1]=FDC_CONFIGURE; /* FIFO Threshold, Poll, Enable FIFO */
|
||||
pCMD->cmd[CONFIG2]=FDC_PRE_TRK; /* Precompensation Track */
|
||||
pCMD->cmdlen=FDC_CMD_CONFIGURE_LEN;
|
||||
pCMD->resultlen=0; /* no result */
|
||||
break;
|
||||
case FDC_CMD_SPECIFY:
|
||||
pCMD->cmd[SPEC_HUTSRT]=pFG->spec1;
|
||||
pCMD->cmd[SPEC_HLT]=(pFG->hlt)<<1; /* head load time */
|
||||
if(pCMD->dma==0)
|
||||
pCMD->cmd[SPEC_HLT]|=0x1; /* no dma */
|
||||
pCMD->cmdlen=FDC_CMD_SPECIFY_LEN;
|
||||
pCMD->resultlen=0; /* no result */
|
||||
break;
|
||||
case FDC_CMD_DUMP_REG:
|
||||
pCMD->cmdlen=FDC_CMD_DUMP_REG_LEN;
|
||||
pCMD->resultlen=10; /* 10 byte result */
|
||||
break;
|
||||
case FDC_CMD_READ_ID:
|
||||
pCMD->cmd[COMMAND]|=(FDC_MFM_MODE<<6); /* set MFM bit */
|
||||
pCMD->cmdlen=FDC_CMD_READ_ID_LEN;
|
||||
pCMD->resultlen=7; /* 7 byte result */
|
||||
break;
|
||||
case FDC_CMD_RECALIBRATE:
|
||||
pCMD->cmd[DRIVE]&=0x03; /* don't set the head bit */
|
||||
pCMD->cmdlen=FDC_CMD_RECALIBRATE_LEN;
|
||||
pCMD->resultlen=0; /* no result */
|
||||
break;
|
||||
break;
|
||||
case FDC_CMD_SENSE_INT:
|
||||
pCMD->cmdlen=FDC_CMD_SENSE_INT_LEN;
|
||||
pCMD->resultlen=2;
|
||||
break;
|
||||
}
|
||||
for(i=0;i<pCMD->cmdlen;i++) {
|
||||
/* PRINTF("write cmd%d = 0x%02X\n",i,pCMD->cmd[i]); */
|
||||
if (write_fdc_byte(pCMD->cmd[i]) == false) {
|
||||
PRINTF("Error: timeout while issue cmd%d\n",i);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
timeout=FDC_TIME_OUT;
|
||||
for(i=0;i<pCMD->resultlen;i++) {
|
||||
while((read_fdc_reg(FDC_MSR)&0xC0)!=0xC0) {
|
||||
timeout--;
|
||||
if(timeout==0) {
|
||||
PRINTF(" timeout while reading result%d MSR=0x%02X\n",i,read_fdc_reg(FDC_MSR));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
pCMD->result[i]=(unsigned char)read_fdc_byte();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* selects the drive assigned in the cmd structur and
|
||||
switches on the Motor */
|
||||
void select_fdc_drive(FDC_COMMAND_STRUCT *pCMD)
|
||||
{
|
||||
unsigned char val;
|
||||
|
||||
val=(1<<(4+pCMD->drive))|pCMD->drive|0xC; /* set reset, dma gate and motor bits */
|
||||
if((read_fdc_reg(FDC_DOR)&val)!=val) {
|
||||
write_fdc_reg(FDC_DOR,val);
|
||||
for(val=0;val<255;val++)
|
||||
udelay(500); /* wait some time to start motor */
|
||||
}
|
||||
}
|
||||
|
||||
/* switches off the Motor of the specified drive */
|
||||
void stop_fdc_drive(FDC_COMMAND_STRUCT *pCMD)
|
||||
{
|
||||
unsigned char val;
|
||||
|
||||
val=(1<<(4+pCMD->drive))|pCMD->drive; /* sets motor bits */
|
||||
write_fdc_reg(FDC_DOR,(read_fdc_reg(FDC_DOR)&~val));
|
||||
}
|
||||
|
||||
/* issues a recalibrate command, waits for interrupt and
|
||||
* issues a sense_interrupt */
|
||||
int fdc_recalibrate(FDC_COMMAND_STRUCT *pCMD,FD_GEO_STRUCT *pFG)
|
||||
{
|
||||
pCMD->cmd[COMMAND]=FDC_CMD_RECALIBRATE;
|
||||
if (fdc_issue_cmd(pCMD, pFG) == false)
|
||||
return false;
|
||||
while (wait_for_fdc_int() != true);
|
||||
|
||||
pCMD->cmd[COMMAND]=FDC_CMD_SENSE_INT;
|
||||
return(fdc_issue_cmd(pCMD,pFG));
|
||||
}
|
||||
|
||||
/* issues a recalibrate command, waits for interrupt and
|
||||
* issues a sense_interrupt */
|
||||
int fdc_seek(FDC_COMMAND_STRUCT *pCMD,FD_GEO_STRUCT *pFG)
|
||||
{
|
||||
pCMD->cmd[COMMAND]=FDC_CMD_SEEK;
|
||||
if (fdc_issue_cmd(pCMD, pFG) == false)
|
||||
return false;
|
||||
while (wait_for_fdc_int() != true);
|
||||
|
||||
pCMD->cmd[COMMAND]=FDC_CMD_SENSE_INT;
|
||||
return(fdc_issue_cmd(pCMD,pFG));
|
||||
}
|
||||
|
||||
/* terminates current command, by not servicing the FIFO
|
||||
* waits for interrupt and fills in the result bytes */
|
||||
int fdc_terminate(FDC_COMMAND_STRUCT *pCMD)
|
||||
{
|
||||
int i;
|
||||
for(i=0;i<100;i++)
|
||||
udelay(500); /* wait 500usec for fifo overrun */
|
||||
while((read_fdc_reg(FDC_SRA)&0x80)==0x00); /* wait as long as no int has occurred */
|
||||
for(i=0;i<7;i++) {
|
||||
pCMD->result[i]=(unsigned char)read_fdc_byte();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* reads data from FDC, seek commands are issued automatic */
|
||||
int fdc_read_data(unsigned char *buffer, unsigned long blocks,FDC_COMMAND_STRUCT *pCMD, FD_GEO_STRUCT *pFG)
|
||||
{
|
||||
/* first seek to start address */
|
||||
unsigned long len,readblk,i,timeout,ii,offset;
|
||||
unsigned char c,retriesrw,retriescal;
|
||||
unsigned char *bufferw; /* working buffer */
|
||||
int sect_size;
|
||||
int flags;
|
||||
|
||||
flags=disable_interrupts(); /* switch off all Interrupts */
|
||||
select_fdc_drive(pCMD); /* switch on drive */
|
||||
sect_size=0x080<<pFG->sect_code;
|
||||
retriesrw=0;
|
||||
retriescal=0;
|
||||
offset=0;
|
||||
if (fdc_seek(pCMD, pFG) == false) {
|
||||
stop_fdc_drive(pCMD);
|
||||
if (flags)
|
||||
enable_interrupts();
|
||||
return false;
|
||||
}
|
||||
if((pCMD->result[STATUS_0]&0x20)!=0x20) {
|
||||
printf("Seek error Status: %02X\n",pCMD->result[STATUS_0]);
|
||||
stop_fdc_drive(pCMD);
|
||||
if (flags)
|
||||
enable_interrupts();
|
||||
return false;
|
||||
}
|
||||
/* now determine the next seek point */
|
||||
/* lastblk=pCMD->blnr + blocks; */
|
||||
/* readblk=(pFG->head*pFG->sect)-(pCMD->blnr%(pFG->head*pFG->sect)); */
|
||||
readblk=pFG->sect-(pCMD->blnr%pFG->sect);
|
||||
PRINTF("1st nr of block possible read %ld start %ld\n",readblk,pCMD->blnr);
|
||||
if(readblk>blocks) /* is end within 1st track */
|
||||
readblk=blocks; /* yes, correct it */
|
||||
PRINTF("we read %ld blocks start %ld\n",readblk,pCMD->blnr);
|
||||
bufferw = &buffer[0]; /* setup working buffer */
|
||||
do {
|
||||
retryrw:
|
||||
len=sect_size * readblk;
|
||||
pCMD->cmd[COMMAND]=FDC_CMD_READ;
|
||||
if (fdc_issue_cmd(pCMD, pFG) == false) {
|
||||
stop_fdc_drive(pCMD);
|
||||
if (flags)
|
||||
enable_interrupts();
|
||||
return false;
|
||||
}
|
||||
for (i=0;i<len;i++) {
|
||||
timeout=FDC_TIME_OUT;
|
||||
do {
|
||||
c=read_fdc_reg(FDC_MSR);
|
||||
if((c&0xC0)==0xC0) {
|
||||
bufferw[i]=read_fdc_reg(FDC_FIFO);
|
||||
break;
|
||||
}
|
||||
if((c&0xC0)==0x80) { /* output */
|
||||
PRINTF("Transfer error transferred: at %ld, MSR=%02X\n",i,c);
|
||||
if(i>6) {
|
||||
for(ii=0;ii<7;ii++) {
|
||||
pCMD->result[ii]=bufferw[(i-7+ii)];
|
||||
} /* for */
|
||||
}
|
||||
if(retriesrw++>FDC_RW_RETRIES) {
|
||||
if (retriescal++>FDC_CAL_RETRIES) {
|
||||
stop_fdc_drive(pCMD);
|
||||
if (flags)
|
||||
enable_interrupts();
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
PRINTF(" trying to recalibrate Try %d\n",retriescal);
|
||||
if (fdc_recalibrate(pCMD, pFG) == false) {
|
||||
stop_fdc_drive(pCMD);
|
||||
if (flags)
|
||||
enable_interrupts();
|
||||
return false;
|
||||
}
|
||||
retriesrw=0;
|
||||
goto retrycal;
|
||||
} /* else >FDC_CAL_RETRIES */
|
||||
}
|
||||
else {
|
||||
PRINTF("Read retry %d\n",retriesrw);
|
||||
goto retryrw;
|
||||
} /* else >FDC_RW_RETRIES */
|
||||
}/* if output */
|
||||
timeout--;
|
||||
} while (true);
|
||||
} /* for len */
|
||||
/* the last sector of a track or all data has been read,
|
||||
* we need to get the results */
|
||||
fdc_terminate(pCMD);
|
||||
offset+=(sect_size*readblk); /* set up buffer pointer */
|
||||
bufferw = &buffer[offset];
|
||||
pCMD->blnr+=readblk; /* update current block nr */
|
||||
blocks-=readblk; /* update blocks */
|
||||
if(blocks==0)
|
||||
break; /* we are finish */
|
||||
/* setup new read blocks */
|
||||
/* readblk=pFG->head*pFG->sect; */
|
||||
readblk=pFG->sect;
|
||||
if(readblk>blocks)
|
||||
readblk=blocks;
|
||||
retrycal:
|
||||
/* a seek is necessary */
|
||||
if (fdc_seek(pCMD, pFG) == false) {
|
||||
stop_fdc_drive(pCMD);
|
||||
if (flags)
|
||||
enable_interrupts();
|
||||
return false;
|
||||
}
|
||||
if((pCMD->result[STATUS_0]&0x20)!=0x20) {
|
||||
PRINTF("Seek error Status: %02X\n",pCMD->result[STATUS_0]);
|
||||
stop_fdc_drive(pCMD);
|
||||
return false;
|
||||
}
|
||||
} while (true); /* start over */
|
||||
stop_fdc_drive(pCMD); /* switch off drive */
|
||||
if (flags)
|
||||
enable_interrupts();
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Scan all drives and check if drive is present and disk is inserted */
|
||||
int fdc_check_drive(FDC_COMMAND_STRUCT *pCMD, FD_GEO_STRUCT *pFG)
|
||||
{
|
||||
int i,drives,state;
|
||||
/* OK procedure of data book is satisfied.
|
||||
* trying to get some information over the drives */
|
||||
state=0; /* no drives, no disks */
|
||||
for(drives=0;drives<4;drives++) {
|
||||
pCMD->drive=drives;
|
||||
select_fdc_drive(pCMD);
|
||||
pCMD->blnr=0; /* set to the 1st block */
|
||||
if (fdc_recalibrate(pCMD, pFG) == false)
|
||||
continue;
|
||||
if((pCMD->result[STATUS_0]&0x10)==0x10)
|
||||
continue;
|
||||
/* ok drive connected check for disk */
|
||||
state|=(1<<drives);
|
||||
pCMD->blnr=pFG->size; /* set to the last block */
|
||||
if (fdc_seek(pCMD, pFG) == false)
|
||||
continue;
|
||||
pCMD->blnr=0; /* set to the 1st block */
|
||||
if (fdc_recalibrate(pCMD, pFG) == false)
|
||||
continue;
|
||||
pCMD->cmd[COMMAND]=FDC_CMD_READ_ID;
|
||||
if (fdc_issue_cmd(pCMD, pFG) == false)
|
||||
continue;
|
||||
state|=(0x10<<drives);
|
||||
}
|
||||
stop_fdc_drive(pCMD);
|
||||
for(i=0;i<4;i++) {
|
||||
PRINTF("Floppy Drive %d %sconnected %sDisk inserted %s\n",i,
|
||||
((state&(1<<i))==(1<<i)) ? "":"not ",
|
||||
((state&(0x10<<i))==(0x10<<i)) ? "":"no ",
|
||||
((state&(0x10<<i))==(0x10<<i)) ? pFG->name : "");
|
||||
}
|
||||
pCMD->flags=state;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* int fdc_setup
|
||||
* setup the fdc according the datasheet
|
||||
* assuming in PS2 Mode
|
||||
*/
|
||||
int fdc_setup(int drive, FDC_COMMAND_STRUCT *pCMD, FD_GEO_STRUCT *pFG)
|
||||
{
|
||||
int i;
|
||||
|
||||
#ifdef CONFIG_SYS_FDC_HW_INIT
|
||||
fdc_hw_init ();
|
||||
#endif
|
||||
/* first, we reset the FDC via the DOR */
|
||||
write_fdc_reg(FDC_DOR,0x00);
|
||||
for(i=0; i<255; i++) /* then we wait some time */
|
||||
udelay(500);
|
||||
/* then, we clear the reset in the DOR */
|
||||
pCMD->drive=drive;
|
||||
select_fdc_drive(pCMD);
|
||||
/* initialize the CCR */
|
||||
write_fdc_reg(FDC_CCR,pFG->rate);
|
||||
/* then initialize the DSR */
|
||||
write_fdc_reg(FDC_DSR,pFG->rate);
|
||||
if (wait_for_fdc_int() == false) {
|
||||
PRINTF("Time Out after writing CCR\n");
|
||||
return false;
|
||||
}
|
||||
/* now issue sense Interrupt and status command
|
||||
* assuming only one drive present (drive 0) */
|
||||
pCMD->dma=0; /* we don't use any dma at all */
|
||||
for(i=0;i<4;i++) {
|
||||
/* issue sense interrupt for all 4 possible drives */
|
||||
pCMD->cmd[COMMAND]=FDC_CMD_SENSE_INT;
|
||||
if (fdc_issue_cmd(pCMD, pFG) == false) {
|
||||
PRINTF("Sense Interrupt for drive %d failed\n",i);
|
||||
}
|
||||
}
|
||||
/* issue the configure command */
|
||||
pCMD->drive=drive;
|
||||
select_fdc_drive(pCMD);
|
||||
pCMD->cmd[COMMAND]=FDC_CMD_CONFIGURE;
|
||||
if (fdc_issue_cmd(pCMD, pFG) == false) {
|
||||
PRINTF(" configure timeout\n");
|
||||
stop_fdc_drive(pCMD);
|
||||
return false;
|
||||
}
|
||||
/* issue specify command */
|
||||
pCMD->cmd[COMMAND]=FDC_CMD_SPECIFY;
|
||||
if (fdc_issue_cmd(pCMD, pFG) == false) {
|
||||
PRINTF(" specify timeout\n");
|
||||
stop_fdc_drive(pCMD);
|
||||
return false;
|
||||
|
||||
}
|
||||
/* then, we clear the reset in the DOR */
|
||||
/* fdc_check_drive(pCMD,pFG); */
|
||||
/* write_fdc_reg(FDC_DOR,0x04); */
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* main routine do_fdcboot
|
||||
*/
|
||||
int do_fdcboot (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
FD_GEO_STRUCT *pFG = (FD_GEO_STRUCT *)floppy_type;
|
||||
FDC_COMMAND_STRUCT *pCMD = &cmd;
|
||||
unsigned long addr,imsize;
|
||||
#if defined(CONFIG_LEGACY_IMAGE_FORMAT)
|
||||
image_header_t *hdr; /* used for fdc boot */
|
||||
#endif
|
||||
unsigned char boot_drive;
|
||||
int i,nrofblk;
|
||||
#if defined(CONFIG_FIT)
|
||||
const void *fit_hdr = NULL;
|
||||
#endif
|
||||
|
||||
switch (argc) {
|
||||
case 1:
|
||||
addr = CONFIG_SYS_LOAD_ADDR;
|
||||
boot_drive=CONFIG_SYS_FDC_DRIVE_NUMBER;
|
||||
break;
|
||||
case 2:
|
||||
addr = simple_strtoul(argv[1], NULL, 16);
|
||||
boot_drive=CONFIG_SYS_FDC_DRIVE_NUMBER;
|
||||
break;
|
||||
case 3:
|
||||
addr = simple_strtoul(argv[1], NULL, 16);
|
||||
boot_drive=simple_strtoul(argv[2], NULL, 10);
|
||||
break;
|
||||
default:
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
/* setup FDC and scan for drives */
|
||||
if (fdc_setup(boot_drive, pCMD, pFG) == false) {
|
||||
printf("\n** Error in setup FDC **\n");
|
||||
return 1;
|
||||
}
|
||||
if (fdc_check_drive(pCMD, pFG) == false) {
|
||||
printf("\n** Error in check_drives **\n");
|
||||
return 1;
|
||||
}
|
||||
if((pCMD->flags&(1<<boot_drive))==0) {
|
||||
/* drive not available */
|
||||
printf("\n** Drive %d not availabe **\n",boot_drive);
|
||||
return 1;
|
||||
}
|
||||
if((pCMD->flags&(0x10<<boot_drive))==0) {
|
||||
/* no disk inserted */
|
||||
printf("\n** No disk inserted in drive %d **\n",boot_drive);
|
||||
return 1;
|
||||
}
|
||||
/* ok, we have a valid source */
|
||||
pCMD->drive=boot_drive;
|
||||
/* read first block */
|
||||
pCMD->blnr=0;
|
||||
if (fdc_read_data((unsigned char *)addr, 1, pCMD, pFG) == false) {
|
||||
printf("\nRead error:");
|
||||
for(i=0;i<7;i++)
|
||||
printf("result%d: 0x%02X\n",i,pCMD->result[i]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
switch (genimg_get_format ((void *)addr)) {
|
||||
#if defined(CONFIG_LEGACY_IMAGE_FORMAT)
|
||||
case IMAGE_FORMAT_LEGACY:
|
||||
hdr = (image_header_t *)addr;
|
||||
image_print_contents (hdr);
|
||||
|
||||
imsize = image_get_image_size (hdr);
|
||||
break;
|
||||
#endif
|
||||
#if defined(CONFIG_FIT)
|
||||
case IMAGE_FORMAT_FIT:
|
||||
fit_hdr = (const void *)addr;
|
||||
puts ("Fit image detected...\n");
|
||||
|
||||
imsize = fit_get_size (fit_hdr);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
puts ("** Unknown image type\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
nrofblk=imsize/512;
|
||||
if((imsize%512)>0)
|
||||
nrofblk++;
|
||||
printf("Loading %ld Bytes (%d blocks) at 0x%08lx..\n",imsize,nrofblk,addr);
|
||||
pCMD->blnr=0;
|
||||
if (fdc_read_data((unsigned char *)addr, nrofblk, pCMD, pFG) == false) {
|
||||
/* read image block */
|
||||
printf("\nRead error:");
|
||||
for(i=0;i<7;i++)
|
||||
printf("result%d: 0x%02X\n",i,pCMD->result[i]);
|
||||
return 1;
|
||||
}
|
||||
printf("OK %ld Bytes loaded.\n",imsize);
|
||||
|
||||
flush_cache (addr, imsize);
|
||||
|
||||
#if defined(CONFIG_FIT)
|
||||
/* This cannot be done earlier, we need complete FIT image in RAM first */
|
||||
if (genimg_get_format ((void *)addr) == IMAGE_FORMAT_FIT) {
|
||||
if (!fit_check_format (fit_hdr)) {
|
||||
puts ("** Bad FIT image format\n");
|
||||
return 1;
|
||||
}
|
||||
fit_print_contents (fit_hdr);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Loading ok, update default load address */
|
||||
load_addr = addr;
|
||||
|
||||
return bootm_maybe_autostart(cmdtp, argv[0]);
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
fdcboot, 3, 1, do_fdcboot,
|
||||
"boot from floppy device",
|
||||
"loadAddr drive"
|
||||
);
|
||||
33
cmd/fitupd.c
Normal file
33
cmd/fitupd.c
Normal file
@@ -0,0 +1,33 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2011
|
||||
* Andreas Pretzsch, carpe noctem engineering, apr@cn-eng.de
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <net.h>
|
||||
|
||||
#if !defined(CONFIG_UPDATE_TFTP)
|
||||
#error "CONFIG_UPDATE_TFTP required"
|
||||
#endif
|
||||
|
||||
static int do_fitupd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
ulong addr = 0UL;
|
||||
|
||||
if (argc > 2)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
if (argc == 2)
|
||||
addr = simple_strtoul(argv[1], NULL, 16);
|
||||
|
||||
return update_tftp(addr, NULL, NULL);
|
||||
}
|
||||
|
||||
U_BOOT_CMD(fitupd, 2, 0, do_fitupd,
|
||||
"update from FIT image",
|
||||
"[addr]\n"
|
||||
"\t- run update from FIT image at addr\n"
|
||||
"\t or from tftp 'updatefile'"
|
||||
);
|
||||
699
cmd/flash.c
Normal file
699
cmd/flash.c
Normal file
@@ -0,0 +1,699 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2000
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*/
|
||||
|
||||
/*
|
||||
* FLASH support
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
|
||||
#if defined(CONFIG_CMD_MTDPARTS)
|
||||
#include <jffs2/jffs2.h>
|
||||
|
||||
/* partition handling routines */
|
||||
int mtdparts_init(void);
|
||||
int mtd_id_parse(const char *id, const char **ret_id, u8 *dev_type, u8 *dev_num);
|
||||
int find_dev_and_part(const char *id, struct mtd_device **dev,
|
||||
u8 *part_num, struct part_info **part);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MTD_NOR_FLASH
|
||||
#include <flash.h>
|
||||
#include <mtd/cfi_flash.h>
|
||||
extern flash_info_t flash_info[]; /* info for FLASH chips */
|
||||
|
||||
/*
|
||||
* The user interface starts numbering for Flash banks with 1
|
||||
* for historical reasons.
|
||||
*/
|
||||
|
||||
/*
|
||||
* this routine looks for an abbreviated flash range specification.
|
||||
* the syntax is B:SF[-SL], where B is the bank number, SF is the first
|
||||
* sector to erase, and SL is the last sector to erase (defaults to SF).
|
||||
* bank numbers start at 1 to be consistent with other specs, sector numbers
|
||||
* start at zero.
|
||||
*
|
||||
* returns: 1 - correct spec; *pinfo, *psf and *psl are
|
||||
* set appropriately
|
||||
* 0 - doesn't look like an abbreviated spec
|
||||
* -1 - looks like an abbreviated spec, but got
|
||||
* a parsing error, a number out of range,
|
||||
* or an invalid flash bank.
|
||||
*/
|
||||
static int
|
||||
abbrev_spec (char *str, flash_info_t ** pinfo, int *psf, int *psl)
|
||||
{
|
||||
flash_info_t *fp;
|
||||
int bank, first, last;
|
||||
char *p, *ep;
|
||||
|
||||
if ((p = strchr (str, ':')) == NULL)
|
||||
return 0;
|
||||
*p++ = '\0';
|
||||
|
||||
bank = simple_strtoul (str, &ep, 10);
|
||||
if (ep == str || *ep != '\0' ||
|
||||
bank < 1 || bank > CONFIG_SYS_MAX_FLASH_BANKS ||
|
||||
(fp = &flash_info[bank - 1])->flash_id == FLASH_UNKNOWN)
|
||||
return -1;
|
||||
|
||||
str = p;
|
||||
if ((p = strchr (str, '-')) != NULL)
|
||||
*p++ = '\0';
|
||||
|
||||
first = simple_strtoul (str, &ep, 10);
|
||||
if (ep == str || *ep != '\0' || first >= fp->sector_count)
|
||||
return -1;
|
||||
|
||||
if (p != NULL) {
|
||||
last = simple_strtoul (p, &ep, 10);
|
||||
if (ep == p || *ep != '\0' ||
|
||||
last < first || last >= fp->sector_count)
|
||||
return -1;
|
||||
} else {
|
||||
last = first;
|
||||
}
|
||||
|
||||
*pinfo = fp;
|
||||
*psf = first;
|
||||
*psl = last;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Take *addr in Flash and adjust it to fall on the end of its sector
|
||||
*/
|
||||
int flash_sect_roundb (ulong *addr)
|
||||
{
|
||||
flash_info_t *info;
|
||||
ulong bank, sector_end_addr;
|
||||
char found;
|
||||
int i;
|
||||
|
||||
/* find the end addr of the sector where the *addr is */
|
||||
found = 0;
|
||||
for (bank = 0; bank < CONFIG_SYS_MAX_FLASH_BANKS && !found; ++bank) {
|
||||
info = &flash_info[bank];
|
||||
for (i = 0; i < info->sector_count && !found; ++i) {
|
||||
/* get the end address of the sector */
|
||||
if (i == info->sector_count - 1) {
|
||||
sector_end_addr = info->start[0] +
|
||||
info->size - 1;
|
||||
} else {
|
||||
sector_end_addr = info->start[i+1] - 1;
|
||||
}
|
||||
|
||||
if (*addr <= sector_end_addr &&
|
||||
*addr >= info->start[i]) {
|
||||
found = 1;
|
||||
/* adjust *addr if necessary */
|
||||
if (*addr < sector_end_addr)
|
||||
*addr = sector_end_addr;
|
||||
} /* sector */
|
||||
} /* bank */
|
||||
}
|
||||
if (!found) {
|
||||
/* error, address not in flash */
|
||||
printf("Error: end address (0x%08lx) not in flash!\n", *addr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function computes the start and end addresses for both
|
||||
* erase and protect commands. The range of the addresses on which
|
||||
* either of the commands is to operate can be given in two forms:
|
||||
* 1. <cmd> start end - operate on <'start', 'end')
|
||||
* 2. <cmd> start +length - operate on <'start', start + length)
|
||||
* If the second form is used and the end address doesn't fall on the
|
||||
* sector boundary, than it will be adjusted to the next sector boundary.
|
||||
* If it isn't in the flash, the function will fail (return -1).
|
||||
* Input:
|
||||
* arg1, arg2: address specification (i.e. both command arguments)
|
||||
* Output:
|
||||
* addr_first, addr_last: computed address range
|
||||
* Return:
|
||||
* 1: success
|
||||
* -1: failure (bad format, bad address).
|
||||
*/
|
||||
static int
|
||||
addr_spec(char *arg1, char *arg2, ulong *addr_first, ulong *addr_last)
|
||||
{
|
||||
char *ep;
|
||||
char len_used; /* indicates if the "start +length" form used */
|
||||
|
||||
*addr_first = simple_strtoul(arg1, &ep, 16);
|
||||
if (ep == arg1 || *ep != '\0')
|
||||
return -1;
|
||||
|
||||
len_used = 0;
|
||||
if (arg2 && *arg2 == '+'){
|
||||
len_used = 1;
|
||||
++arg2;
|
||||
}
|
||||
|
||||
*addr_last = simple_strtoul(arg2, &ep, 16);
|
||||
if (ep == arg2 || *ep != '\0')
|
||||
return -1;
|
||||
|
||||
if (len_used){
|
||||
/*
|
||||
* *addr_last has the length, compute correct *addr_last
|
||||
* XXX watch out for the integer overflow! Right now it is
|
||||
* checked for in both the callers.
|
||||
*/
|
||||
*addr_last = *addr_first + *addr_last - 1;
|
||||
|
||||
/*
|
||||
* It may happen that *addr_last doesn't fall on the sector
|
||||
* boundary. We want to round such an address to the next
|
||||
* sector boundary, so that the commands don't fail later on.
|
||||
*/
|
||||
|
||||
if (flash_sect_roundb(addr_last) > 0)
|
||||
return -1;
|
||||
} /* "start +length" from used */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
flash_fill_sect_ranges (ulong addr_first, ulong addr_last,
|
||||
int *s_first, int *s_last,
|
||||
int *s_count )
|
||||
{
|
||||
flash_info_t *info;
|
||||
ulong bank;
|
||||
int rcode = 0;
|
||||
|
||||
*s_count = 0;
|
||||
|
||||
for (bank=0; bank < CONFIG_SYS_MAX_FLASH_BANKS; ++bank) {
|
||||
s_first[bank] = -1; /* first sector to erase */
|
||||
s_last [bank] = -1; /* last sector to erase */
|
||||
}
|
||||
|
||||
for (bank=0,info = &flash_info[0];
|
||||
(bank < CONFIG_SYS_MAX_FLASH_BANKS) && (addr_first <= addr_last);
|
||||
++bank, ++info) {
|
||||
ulong b_end;
|
||||
int sect;
|
||||
short s_end;
|
||||
|
||||
if (info->flash_id == FLASH_UNKNOWN) {
|
||||
continue;
|
||||
}
|
||||
|
||||
b_end = info->start[0] + info->size - 1; /* bank end addr */
|
||||
s_end = info->sector_count - 1; /* last sector */
|
||||
|
||||
|
||||
for (sect=0; sect < info->sector_count; ++sect) {
|
||||
ulong end; /* last address in current sect */
|
||||
|
||||
end = (sect == s_end) ? b_end : info->start[sect + 1] - 1;
|
||||
|
||||
if (addr_first > end)
|
||||
continue;
|
||||
if (addr_last < info->start[sect])
|
||||
continue;
|
||||
|
||||
if (addr_first == info->start[sect]) {
|
||||
s_first[bank] = sect;
|
||||
}
|
||||
if (addr_last == end) {
|
||||
s_last[bank] = sect;
|
||||
}
|
||||
}
|
||||
if (s_first[bank] >= 0) {
|
||||
if (s_last[bank] < 0) {
|
||||
if (addr_last > b_end) {
|
||||
s_last[bank] = s_end;
|
||||
} else {
|
||||
puts ("Error: end address"
|
||||
" not on sector boundary\n");
|
||||
rcode = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (s_last[bank] < s_first[bank]) {
|
||||
puts ("Error: end sector"
|
||||
" precedes start sector\n");
|
||||
rcode = 1;
|
||||
break;
|
||||
}
|
||||
sect = s_last[bank];
|
||||
addr_first = (sect == s_end) ? b_end + 1: info->start[sect + 1];
|
||||
(*s_count) += s_last[bank] - s_first[bank] + 1;
|
||||
} else if (addr_first >= info->start[0] && addr_first < b_end) {
|
||||
puts ("Error: start address not on sector boundary\n");
|
||||
rcode = 1;
|
||||
break;
|
||||
} else if (s_last[bank] >= 0) {
|
||||
puts ("Error: cannot span across banks when they are"
|
||||
" mapped in reverse order\n");
|
||||
rcode = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return rcode;
|
||||
}
|
||||
#endif /* CONFIG_MTD_NOR_FLASH */
|
||||
|
||||
static int do_flinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
#ifdef CONFIG_MTD_NOR_FLASH
|
||||
ulong bank;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MTD_NOR_FLASH
|
||||
if (argc == 1) { /* print info for all FLASH banks */
|
||||
for (bank=0; bank <CONFIG_SYS_MAX_FLASH_BANKS; ++bank) {
|
||||
printf ("\nBank # %ld: ", bank+1);
|
||||
|
||||
flash_print_info (&flash_info[bank]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bank = simple_strtoul(argv[1], NULL, 16);
|
||||
if ((bank < 1) || (bank > CONFIG_SYS_MAX_FLASH_BANKS)) {
|
||||
printf ("Only FLASH Banks # 1 ... # %d supported\n",
|
||||
CONFIG_SYS_MAX_FLASH_BANKS);
|
||||
return 1;
|
||||
}
|
||||
printf ("\nBank # %ld: ", bank);
|
||||
flash_print_info (&flash_info[bank-1]);
|
||||
#endif /* CONFIG_MTD_NOR_FLASH */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_flerase(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
#ifdef CONFIG_MTD_NOR_FLASH
|
||||
flash_info_t *info = NULL;
|
||||
ulong bank, addr_first, addr_last;
|
||||
int n, sect_first = 0, sect_last = 0;
|
||||
#if defined(CONFIG_CMD_MTDPARTS)
|
||||
struct mtd_device *dev;
|
||||
struct part_info *part;
|
||||
u8 dev_type, dev_num, pnum;
|
||||
#endif
|
||||
int rcode = 0;
|
||||
|
||||
if (argc < 2)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
if (strcmp(argv[1], "all") == 0) {
|
||||
for (bank=1; bank<=CONFIG_SYS_MAX_FLASH_BANKS; ++bank) {
|
||||
printf ("Erase Flash Bank # %ld ", bank);
|
||||
info = &flash_info[bank-1];
|
||||
rcode = flash_erase (info, 0, info->sector_count-1);
|
||||
}
|
||||
return rcode;
|
||||
}
|
||||
|
||||
if ((n = abbrev_spec(argv[1], &info, §_first, §_last)) != 0) {
|
||||
if (n < 0) {
|
||||
puts ("Bad sector specification\n");
|
||||
return 1;
|
||||
}
|
||||
printf ("Erase Flash Sectors %d-%d in Bank # %zu ",
|
||||
sect_first, sect_last, (info-flash_info)+1);
|
||||
rcode = flash_erase(info, sect_first, sect_last);
|
||||
return rcode;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_CMD_MTDPARTS)
|
||||
/* erase <part-id> - erase partition */
|
||||
if ((argc == 2) && (mtd_id_parse(argv[1], NULL, &dev_type, &dev_num) == 0)) {
|
||||
mtdparts_init();
|
||||
if (find_dev_and_part(argv[1], &dev, &pnum, &part) == 0) {
|
||||
if (dev->id->type == MTD_DEV_TYPE_NOR) {
|
||||
bank = dev->id->num;
|
||||
info = &flash_info[bank];
|
||||
addr_first = part->offset + info->start[0];
|
||||
addr_last = addr_first + part->size - 1;
|
||||
|
||||
printf ("Erase Flash Partition %s, "
|
||||
"bank %ld, 0x%08lx - 0x%08lx ",
|
||||
argv[1], bank, addr_first,
|
||||
addr_last);
|
||||
|
||||
rcode = flash_sect_erase(addr_first, addr_last);
|
||||
return rcode;
|
||||
}
|
||||
|
||||
printf("cannot erase, not a NOR device\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (argc != 3)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
if (strcmp(argv[1], "bank") == 0) {
|
||||
bank = simple_strtoul(argv[2], NULL, 16);
|
||||
if ((bank < 1) || (bank > CONFIG_SYS_MAX_FLASH_BANKS)) {
|
||||
printf ("Only FLASH Banks # 1 ... # %d supported\n",
|
||||
CONFIG_SYS_MAX_FLASH_BANKS);
|
||||
return 1;
|
||||
}
|
||||
printf ("Erase Flash Bank # %ld ", bank);
|
||||
info = &flash_info[bank-1];
|
||||
rcode = flash_erase (info, 0, info->sector_count-1);
|
||||
return rcode;
|
||||
}
|
||||
|
||||
if (addr_spec(argv[1], argv[2], &addr_first, &addr_last) < 0){
|
||||
printf ("Bad address format\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (addr_first >= addr_last)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
rcode = flash_sect_erase(addr_first, addr_last);
|
||||
return rcode;
|
||||
#else
|
||||
return 0;
|
||||
#endif /* CONFIG_MTD_NOR_FLASH */
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MTD_NOR_FLASH
|
||||
int flash_sect_erase (ulong addr_first, ulong addr_last)
|
||||
{
|
||||
flash_info_t *info;
|
||||
ulong bank;
|
||||
int s_first[CONFIG_SYS_MAX_FLASH_BANKS], s_last[CONFIG_SYS_MAX_FLASH_BANKS];
|
||||
int erased = 0;
|
||||
int planned;
|
||||
int rcode = 0;
|
||||
|
||||
rcode = flash_fill_sect_ranges (addr_first, addr_last,
|
||||
s_first, s_last, &planned );
|
||||
|
||||
if (planned && (rcode == 0)) {
|
||||
for (bank=0,info = &flash_info[0];
|
||||
(bank < CONFIG_SYS_MAX_FLASH_BANKS) && (rcode == 0);
|
||||
++bank, ++info) {
|
||||
if (s_first[bank]>=0) {
|
||||
erased += s_last[bank] - s_first[bank] + 1;
|
||||
debug ("Erase Flash from 0x%08lx to 0x%08lx "
|
||||
"in Bank # %ld ",
|
||||
info->start[s_first[bank]],
|
||||
(s_last[bank] == info->sector_count) ?
|
||||
info->start[0] + info->size - 1:
|
||||
info->start[s_last[bank]+1] - 1,
|
||||
bank+1);
|
||||
rcode = flash_erase (info, s_first[bank], s_last[bank]);
|
||||
}
|
||||
}
|
||||
if (rcode == 0)
|
||||
printf("Erased %d sectors\n", erased);
|
||||
} else if (rcode == 0) {
|
||||
puts ("Error: start and/or end address"
|
||||
" not on sector boundary\n");
|
||||
rcode = 1;
|
||||
}
|
||||
return rcode;
|
||||
}
|
||||
#endif /* CONFIG_MTD_NOR_FLASH */
|
||||
|
||||
static int do_protect(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
int rcode = 0;
|
||||
#ifdef CONFIG_MTD_NOR_FLASH
|
||||
flash_info_t *info = NULL;
|
||||
ulong bank;
|
||||
int i, n, sect_first = 0, sect_last = 0;
|
||||
#if defined(CONFIG_CMD_MTDPARTS)
|
||||
struct mtd_device *dev;
|
||||
struct part_info *part;
|
||||
u8 dev_type, dev_num, pnum;
|
||||
#endif
|
||||
#endif /* CONFIG_MTD_NOR_FLASH */
|
||||
#if defined(CONFIG_MTD_NOR_FLASH)
|
||||
int p;
|
||||
ulong addr_first, addr_last;
|
||||
#endif
|
||||
|
||||
if (argc < 3)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
#if defined(CONFIG_MTD_NOR_FLASH)
|
||||
if (strcmp(argv[1], "off") == 0)
|
||||
p = 0;
|
||||
else if (strcmp(argv[1], "on") == 0)
|
||||
p = 1;
|
||||
else
|
||||
return CMD_RET_USAGE;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MTD_NOR_FLASH
|
||||
if (strcmp(argv[2], "all") == 0) {
|
||||
for (bank=1; bank<=CONFIG_SYS_MAX_FLASH_BANKS; ++bank) {
|
||||
info = &flash_info[bank-1];
|
||||
if (info->flash_id == FLASH_UNKNOWN) {
|
||||
continue;
|
||||
}
|
||||
printf ("%sProtect Flash Bank # %ld\n",
|
||||
p ? "" : "Un-", bank);
|
||||
|
||||
for (i=0; i<info->sector_count; ++i) {
|
||||
#if defined(CONFIG_SYS_FLASH_PROTECTION)
|
||||
if (flash_real_protect(info, i, p))
|
||||
rcode = 1;
|
||||
putc ('.');
|
||||
#else
|
||||
info->protect[i] = p;
|
||||
#endif /* CONFIG_SYS_FLASH_PROTECTION */
|
||||
}
|
||||
#if defined(CONFIG_SYS_FLASH_PROTECTION)
|
||||
if (!rcode) puts (" done\n");
|
||||
#endif /* CONFIG_SYS_FLASH_PROTECTION */
|
||||
}
|
||||
return rcode;
|
||||
}
|
||||
|
||||
if ((n = abbrev_spec(argv[2], &info, §_first, §_last)) != 0) {
|
||||
if (n < 0) {
|
||||
puts ("Bad sector specification\n");
|
||||
return 1;
|
||||
}
|
||||
printf("%sProtect Flash Sectors %d-%d in Bank # %zu\n",
|
||||
p ? "" : "Un-", sect_first, sect_last,
|
||||
(info-flash_info)+1);
|
||||
for (i = sect_first; i <= sect_last; i++) {
|
||||
#if defined(CONFIG_SYS_FLASH_PROTECTION)
|
||||
if (flash_real_protect(info, i, p))
|
||||
rcode = 1;
|
||||
putc ('.');
|
||||
#else
|
||||
info->protect[i] = p;
|
||||
#endif /* CONFIG_SYS_FLASH_PROTECTION */
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SYS_FLASH_PROTECTION)
|
||||
if (!rcode) puts (" done\n");
|
||||
#endif /* CONFIG_SYS_FLASH_PROTECTION */
|
||||
|
||||
return rcode;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_CMD_MTDPARTS)
|
||||
/* protect on/off <part-id> */
|
||||
if ((argc == 3) && (mtd_id_parse(argv[2], NULL, &dev_type, &dev_num) == 0)) {
|
||||
mtdparts_init();
|
||||
if (find_dev_and_part(argv[2], &dev, &pnum, &part) == 0) {
|
||||
if (dev->id->type == MTD_DEV_TYPE_NOR) {
|
||||
bank = dev->id->num;
|
||||
info = &flash_info[bank];
|
||||
addr_first = part->offset + info->start[0];
|
||||
addr_last = addr_first + part->size - 1;
|
||||
|
||||
printf ("%sProtect Flash Partition %s, "
|
||||
"bank %ld, 0x%08lx - 0x%08lx\n",
|
||||
p ? "" : "Un", argv[1],
|
||||
bank, addr_first, addr_last);
|
||||
|
||||
rcode = flash_sect_protect (p, addr_first, addr_last);
|
||||
return rcode;
|
||||
}
|
||||
|
||||
printf("cannot %sprotect, not a NOR device\n",
|
||||
p ? "" : "un");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (argc != 4)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
if (strcmp(argv[2], "bank") == 0) {
|
||||
bank = simple_strtoul(argv[3], NULL, 16);
|
||||
if ((bank < 1) || (bank > CONFIG_SYS_MAX_FLASH_BANKS)) {
|
||||
printf ("Only FLASH Banks # 1 ... # %d supported\n",
|
||||
CONFIG_SYS_MAX_FLASH_BANKS);
|
||||
return 1;
|
||||
}
|
||||
printf ("%sProtect Flash Bank # %ld\n",
|
||||
p ? "" : "Un-", bank);
|
||||
info = &flash_info[bank-1];
|
||||
|
||||
if (info->flash_id == FLASH_UNKNOWN) {
|
||||
puts ("missing or unknown FLASH type\n");
|
||||
return 1;
|
||||
}
|
||||
for (i=0; i<info->sector_count; ++i) {
|
||||
#if defined(CONFIG_SYS_FLASH_PROTECTION)
|
||||
if (flash_real_protect(info, i, p))
|
||||
rcode = 1;
|
||||
putc ('.');
|
||||
#else
|
||||
info->protect[i] = p;
|
||||
#endif /* CONFIG_SYS_FLASH_PROTECTION */
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SYS_FLASH_PROTECTION)
|
||||
if (!rcode) puts (" done\n");
|
||||
#endif /* CONFIG_SYS_FLASH_PROTECTION */
|
||||
|
||||
return rcode;
|
||||
}
|
||||
|
||||
if (addr_spec(argv[2], argv[3], &addr_first, &addr_last) < 0){
|
||||
printf("Bad address format\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (addr_first >= addr_last)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
rcode = flash_sect_protect (p, addr_first, addr_last);
|
||||
#endif /* CONFIG_MTD_NOR_FLASH */
|
||||
return rcode;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MTD_NOR_FLASH
|
||||
int flash_sect_protect (int p, ulong addr_first, ulong addr_last)
|
||||
{
|
||||
flash_info_t *info;
|
||||
ulong bank;
|
||||
int s_first[CONFIG_SYS_MAX_FLASH_BANKS], s_last[CONFIG_SYS_MAX_FLASH_BANKS];
|
||||
int protected, i;
|
||||
int planned;
|
||||
int rcode;
|
||||
|
||||
rcode = flash_fill_sect_ranges( addr_first, addr_last, s_first, s_last, &planned );
|
||||
|
||||
protected = 0;
|
||||
|
||||
if (planned && (rcode == 0)) {
|
||||
for (bank=0,info = &flash_info[0]; bank < CONFIG_SYS_MAX_FLASH_BANKS; ++bank, ++info) {
|
||||
if (info->flash_id == FLASH_UNKNOWN) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (s_first[bank]>=0 && s_first[bank]<=s_last[bank]) {
|
||||
debug ("%sProtecting sectors %d..%d in bank %ld\n",
|
||||
p ? "" : "Un-",
|
||||
s_first[bank], s_last[bank], bank+1);
|
||||
protected += s_last[bank] - s_first[bank] + 1;
|
||||
for (i=s_first[bank]; i<=s_last[bank]; ++i) {
|
||||
#if defined(CONFIG_SYS_FLASH_PROTECTION)
|
||||
if (flash_real_protect(info, i, p))
|
||||
rcode = 1;
|
||||
putc ('.');
|
||||
#else
|
||||
info->protect[i] = p;
|
||||
#endif /* CONFIG_SYS_FLASH_PROTECTION */
|
||||
}
|
||||
}
|
||||
}
|
||||
#if defined(CONFIG_SYS_FLASH_PROTECTION)
|
||||
puts (" done\n");
|
||||
#endif /* CONFIG_SYS_FLASH_PROTECTION */
|
||||
|
||||
printf ("%sProtected %d sectors\n",
|
||||
p ? "" : "Un-", protected);
|
||||
} else if (rcode == 0) {
|
||||
puts ("Error: start and/or end address"
|
||||
" not on sector boundary\n");
|
||||
rcode = 1;
|
||||
}
|
||||
return rcode;
|
||||
}
|
||||
#endif /* CONFIG_MTD_NOR_FLASH */
|
||||
|
||||
|
||||
/**************************************************/
|
||||
#if defined(CONFIG_CMD_MTDPARTS)
|
||||
# define TMP_ERASE "erase <part-id>\n - erase partition\n"
|
||||
# define TMP_PROT_ON "protect on <part-id>\n - protect partition\n"
|
||||
# define TMP_PROT_OFF "protect off <part-id>\n - make partition writable\n"
|
||||
#else
|
||||
# define TMP_ERASE /* empty */
|
||||
# define TMP_PROT_ON /* empty */
|
||||
# define TMP_PROT_OFF /* empty */
|
||||
#endif
|
||||
|
||||
U_BOOT_CMD(
|
||||
flinfo, 2, 1, do_flinfo,
|
||||
"print FLASH memory information",
|
||||
"\n - print information for all FLASH memory banks\n"
|
||||
"flinfo N\n - print information for FLASH memory bank # N"
|
||||
);
|
||||
|
||||
U_BOOT_CMD(
|
||||
erase, 3, 0, do_flerase,
|
||||
"erase FLASH memory",
|
||||
"start end\n"
|
||||
" - erase FLASH from addr 'start' to addr 'end'\n"
|
||||
"erase start +len\n"
|
||||
" - erase FLASH from addr 'start' to the end of sect "
|
||||
"w/addr 'start'+'len'-1\n"
|
||||
"erase N:SF[-SL]\n - erase sectors SF-SL in FLASH bank # N\n"
|
||||
"erase bank N\n - erase FLASH bank # N\n"
|
||||
TMP_ERASE
|
||||
"erase all\n - erase all FLASH banks"
|
||||
);
|
||||
|
||||
U_BOOT_CMD(
|
||||
protect, 4, 0, do_protect,
|
||||
"enable or disable FLASH write protection",
|
||||
"on start end\n"
|
||||
" - protect FLASH from addr 'start' to addr 'end'\n"
|
||||
"protect on start +len\n"
|
||||
" - protect FLASH from addr 'start' to end of sect "
|
||||
"w/addr 'start'+'len'-1\n"
|
||||
"protect on N:SF[-SL]\n"
|
||||
" - protect sectors SF-SL in FLASH bank # N\n"
|
||||
"protect on bank N\n - protect FLASH bank # N\n"
|
||||
TMP_PROT_ON
|
||||
"protect on all\n - protect all FLASH banks\n"
|
||||
"protect off start end\n"
|
||||
" - make FLASH from addr 'start' to addr 'end' writable\n"
|
||||
"protect off start +len\n"
|
||||
" - make FLASH from addr 'start' to end of sect "
|
||||
"w/addr 'start'+'len'-1 wrtable\n"
|
||||
"protect off N:SF[-SL]\n"
|
||||
" - make sectors SF-SL writable in FLASH bank # N\n"
|
||||
"protect off bank N\n - make FLASH bank # N writable\n"
|
||||
TMP_PROT_OFF
|
||||
"protect off all\n - make all FLASH banks writable"
|
||||
);
|
||||
|
||||
#undef TMP_ERASE
|
||||
#undef TMP_PROT_ON
|
||||
#undef TMP_PROT_OFF
|
||||
466
cmd/fpga.c
Normal file
466
cmd/fpga.c
Normal file
@@ -0,0 +1,466 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2000, 2001
|
||||
* Rich Ireland, Enterasys Networks, rireland@enterasys.com.
|
||||
*/
|
||||
|
||||
/*
|
||||
* FPGA support
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <env.h>
|
||||
#include <fpga.h>
|
||||
#include <fs.h>
|
||||
#include <gzip.h>
|
||||
#include <malloc.h>
|
||||
|
||||
static long do_fpga_get_device(char *arg)
|
||||
{
|
||||
long dev = FPGA_INVALID_DEVICE;
|
||||
char *devstr = env_get("fpga");
|
||||
|
||||
if (devstr)
|
||||
/* Should be strtol to handle -1 cases */
|
||||
dev = simple_strtol(devstr, NULL, 16);
|
||||
|
||||
if (dev == FPGA_INVALID_DEVICE && arg)
|
||||
dev = simple_strtol(arg, NULL, 16);
|
||||
|
||||
debug("%s: device = %ld\n", __func__, dev);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
static int do_fpga_check_params(long *dev, long *fpga_data, size_t *data_size,
|
||||
cmd_tbl_t *cmdtp, int argc, char *const argv[])
|
||||
{
|
||||
size_t local_data_size;
|
||||
long local_fpga_data;
|
||||
|
||||
debug("%s %d, %d\n", __func__, argc, cmdtp->maxargs);
|
||||
|
||||
if (argc != cmdtp->maxargs) {
|
||||
debug("fpga: incorrect parameters passed\n");
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
*dev = do_fpga_get_device(argv[0]);
|
||||
|
||||
local_fpga_data = simple_strtol(argv[1], NULL, 16);
|
||||
if (!local_fpga_data) {
|
||||
debug("fpga: zero fpga_data address\n");
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
*fpga_data = local_fpga_data;
|
||||
|
||||
local_data_size = simple_strtoul(argv[2], NULL, 16);
|
||||
if (!local_data_size) {
|
||||
debug("fpga: zero size\n");
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
*data_size = local_data_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_CMD_FPGA_LOAD_SECURE)
|
||||
int do_fpga_loads(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
|
||||
{
|
||||
size_t data_size = 0;
|
||||
long fpga_data, dev;
|
||||
int ret;
|
||||
struct fpga_secure_info fpga_sec_info;
|
||||
|
||||
memset(&fpga_sec_info, 0, sizeof(fpga_sec_info));
|
||||
|
||||
if (argc < 5) {
|
||||
debug("fpga: incorrect parameters passed\n");
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
if (argc == 6)
|
||||
fpga_sec_info.userkey_addr = (u8 *)(uintptr_t)
|
||||
simple_strtoull(argv[5],
|
||||
NULL, 16);
|
||||
else
|
||||
/*
|
||||
* If 6th parameter is not passed then do_fpga_check_params
|
||||
* will get 5 instead of expected 6 which means that function
|
||||
* return CMD_RET_USAGE. Increase number of params +1 to pass
|
||||
* this.
|
||||
*/
|
||||
argc++;
|
||||
|
||||
fpga_sec_info.encflag = (u8)simple_strtoul(argv[4], NULL, 16);
|
||||
fpga_sec_info.authflag = (u8)simple_strtoul(argv[3], NULL, 16);
|
||||
|
||||
if (fpga_sec_info.authflag >= FPGA_NO_ENC_OR_NO_AUTH &&
|
||||
fpga_sec_info.encflag >= FPGA_NO_ENC_OR_NO_AUTH) {
|
||||
debug("fpga: Use <fpga load> for NonSecure bitstream\n");
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
if (fpga_sec_info.encflag == FPGA_ENC_USR_KEY &&
|
||||
!fpga_sec_info.userkey_addr) {
|
||||
debug("fpga: User key not provided\n");
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
ret = do_fpga_check_params(&dev, &fpga_data, &data_size,
|
||||
cmdtp, argc, argv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return fpga_loads(dev, (void *)fpga_data, data_size, &fpga_sec_info);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_CMD_FPGA_LOADFS)
|
||||
static int do_fpga_loadfs(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char *const argv[])
|
||||
{
|
||||
size_t data_size = 0;
|
||||
long fpga_data, dev;
|
||||
int ret;
|
||||
fpga_fs_info fpga_fsinfo;
|
||||
|
||||
ret = do_fpga_check_params(&dev, &fpga_data, &data_size,
|
||||
cmdtp, argc, argv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
fpga_fsinfo.fstype = FS_TYPE_ANY;
|
||||
fpga_fsinfo.blocksize = (unsigned int)simple_strtoul(argv[3], NULL, 16);
|
||||
fpga_fsinfo.interface = argv[4];
|
||||
fpga_fsinfo.dev_part = argv[5];
|
||||
fpga_fsinfo.filename = argv[6];
|
||||
|
||||
return fpga_fsload(dev, (void *)fpga_data, data_size, &fpga_fsinfo);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int do_fpga_info(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
long dev = do_fpga_get_device(argv[0]);
|
||||
|
||||
return fpga_info(dev);
|
||||
}
|
||||
|
||||
static int do_fpga_dump(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
size_t data_size = 0;
|
||||
long fpga_data, dev;
|
||||
int ret;
|
||||
|
||||
ret = do_fpga_check_params(&dev, &fpga_data, &data_size,
|
||||
cmdtp, argc, argv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return fpga_dump(dev, (void *)fpga_data, data_size);
|
||||
}
|
||||
|
||||
static int do_fpga_load(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
size_t data_size = 0;
|
||||
long fpga_data, dev;
|
||||
int ret;
|
||||
|
||||
ret = do_fpga_check_params(&dev, &fpga_data, &data_size,
|
||||
cmdtp, argc, argv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return fpga_load(dev, (void *)fpga_data, data_size, BIT_FULL);
|
||||
}
|
||||
|
||||
static int do_fpga_loadb(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
size_t data_size = 0;
|
||||
long fpga_data, dev;
|
||||
int ret;
|
||||
|
||||
ret = do_fpga_check_params(&dev, &fpga_data, &data_size,
|
||||
cmdtp, argc, argv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return fpga_loadbitstream(dev, (void *)fpga_data, data_size, BIT_FULL);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_CMD_FPGA_LOADP)
|
||||
static int do_fpga_loadp(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
size_t data_size = 0;
|
||||
long fpga_data, dev;
|
||||
int ret;
|
||||
|
||||
ret = do_fpga_check_params(&dev, &fpga_data, &data_size,
|
||||
cmdtp, argc, argv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return fpga_load(dev, (void *)fpga_data, data_size, BIT_PARTIAL);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_CMD_FPGA_LOADBP)
|
||||
static int do_fpga_loadbp(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
size_t data_size = 0;
|
||||
long fpga_data, dev;
|
||||
int ret;
|
||||
|
||||
ret = do_fpga_check_params(&dev, &fpga_data, &data_size,
|
||||
cmdtp, argc, argv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return fpga_loadbitstream(dev, (void *)fpga_data, data_size,
|
||||
BIT_PARTIAL);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_CMD_FPGA_LOADMK)
|
||||
static int do_fpga_loadmk(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
size_t data_size = 0;
|
||||
void *fpga_data = NULL;
|
||||
#if defined(CONFIG_FIT)
|
||||
const char *fit_uname = NULL;
|
||||
ulong fit_addr;
|
||||
#endif
|
||||
ulong dev = do_fpga_get_device(argv[0]);
|
||||
char *datastr = env_get("fpgadata");
|
||||
|
||||
debug("fpga: argc %x, dev %lx, datastr %s\n", argc, dev, datastr);
|
||||
|
||||
if (dev == FPGA_INVALID_DEVICE) {
|
||||
debug("fpga: Invalid fpga device\n");
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
if (argc == 0 && !datastr) {
|
||||
debug("fpga: No datastr passed\n");
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
if (argc == 2) {
|
||||
datastr = argv[1];
|
||||
debug("fpga: Full command with two args\n");
|
||||
} else if (argc == 1 && !datastr) {
|
||||
debug("fpga: Dev is setup - fpgadata passed\n");
|
||||
datastr = argv[0];
|
||||
}
|
||||
|
||||
#if defined(CONFIG_FIT)
|
||||
if (fit_parse_subimage(datastr, (ulong)fpga_data,
|
||||
&fit_addr, &fit_uname)) {
|
||||
fpga_data = (void *)fit_addr;
|
||||
debug("* fpga: subimage '%s' from FIT image ",
|
||||
fit_uname);
|
||||
debug("at 0x%08lx\n", fit_addr);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
fpga_data = (void *)simple_strtoul(datastr, NULL, 16);
|
||||
debug("* fpga: cmdline image address = 0x%08lx\n",
|
||||
(ulong)fpga_data);
|
||||
}
|
||||
debug("%s: fpga_data = 0x%lx\n", __func__, (ulong)fpga_data);
|
||||
if (!fpga_data) {
|
||||
puts("Zero fpga_data address\n");
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
switch (genimg_get_format(fpga_data)) {
|
||||
#if defined(CONFIG_LEGACY_IMAGE_FORMAT)
|
||||
case IMAGE_FORMAT_LEGACY:
|
||||
{
|
||||
image_header_t *hdr = (image_header_t *)fpga_data;
|
||||
ulong data;
|
||||
u8 comp;
|
||||
|
||||
comp = image_get_comp(hdr);
|
||||
if (comp == IH_COMP_GZIP) {
|
||||
#if defined(CONFIG_GZIP)
|
||||
ulong image_buf = image_get_data(hdr);
|
||||
ulong image_size = ~0UL;
|
||||
|
||||
data = image_get_load(hdr);
|
||||
|
||||
if (gunzip((void *)data, ~0UL, (void *)image_buf,
|
||||
&image_size) != 0) {
|
||||
puts("GUNZIP: error\n");
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
data_size = image_size;
|
||||
#else
|
||||
puts("Gunzip image is not supported\n");
|
||||
return 1;
|
||||
#endif
|
||||
} else {
|
||||
data = (ulong)image_get_data(hdr);
|
||||
data_size = image_get_data_size(hdr);
|
||||
}
|
||||
return fpga_load(dev, (void *)data, data_size,
|
||||
BIT_FULL);
|
||||
}
|
||||
#endif
|
||||
#if defined(CONFIG_FIT)
|
||||
case IMAGE_FORMAT_FIT:
|
||||
{
|
||||
const void *fit_hdr = (const void *)fpga_data;
|
||||
int noffset;
|
||||
const void *fit_data;
|
||||
|
||||
if (!fit_uname) {
|
||||
puts("No FIT subimage unit name\n");
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
if (!fit_check_format(fit_hdr)) {
|
||||
puts("Bad FIT image format\n");
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
/* get fpga component image node offset */
|
||||
noffset = fit_image_get_node(fit_hdr, fit_uname);
|
||||
if (noffset < 0) {
|
||||
printf("Can't find '%s' FIT subimage\n", fit_uname);
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
/* verify integrity */
|
||||
if (!fit_image_verify(fit_hdr, noffset)) {
|
||||
puts("Bad Data Hash\n");
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
/* get fpga subimage/external data address and length */
|
||||
if (fit_image_get_data_and_size(fit_hdr, noffset,
|
||||
&fit_data, &data_size)) {
|
||||
puts("Fpga subimage data not found\n");
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
return fpga_load(dev, fit_data, data_size, BIT_FULL);
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
puts("** Unknown image type\n");
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static cmd_tbl_t fpga_commands[] = {
|
||||
U_BOOT_CMD_MKENT(info, 1, 1, do_fpga_info, "", ""),
|
||||
U_BOOT_CMD_MKENT(dump, 3, 1, do_fpga_dump, "", ""),
|
||||
U_BOOT_CMD_MKENT(load, 3, 1, do_fpga_load, "", ""),
|
||||
U_BOOT_CMD_MKENT(loadb, 3, 1, do_fpga_loadb, "", ""),
|
||||
#if defined(CONFIG_CMD_FPGA_LOADP)
|
||||
U_BOOT_CMD_MKENT(loadp, 3, 1, do_fpga_loadp, "", ""),
|
||||
#endif
|
||||
#if defined(CONFIG_CMD_FPGA_LOADBP)
|
||||
U_BOOT_CMD_MKENT(loadbp, 3, 1, do_fpga_loadbp, "", ""),
|
||||
#endif
|
||||
#if defined(CONFIG_CMD_FPGA_LOADFS)
|
||||
U_BOOT_CMD_MKENT(loadfs, 7, 1, do_fpga_loadfs, "", ""),
|
||||
#endif
|
||||
#if defined(CONFIG_CMD_FPGA_LOADMK)
|
||||
U_BOOT_CMD_MKENT(loadmk, 2, 1, do_fpga_loadmk, "", ""),
|
||||
#endif
|
||||
#if defined(CONFIG_CMD_FPGA_LOAD_SECURE)
|
||||
U_BOOT_CMD_MKENT(loads, 6, 1, do_fpga_loads, "", ""),
|
||||
#endif
|
||||
};
|
||||
|
||||
static int do_fpga_wrapper(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char *const argv[])
|
||||
{
|
||||
cmd_tbl_t *fpga_cmd;
|
||||
int ret;
|
||||
|
||||
if (argc < 2)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
fpga_cmd = find_cmd_tbl(argv[1], fpga_commands,
|
||||
ARRAY_SIZE(fpga_commands));
|
||||
if (!fpga_cmd) {
|
||||
debug("fpga: non existing command\n");
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
argc -= 2;
|
||||
argv += 2;
|
||||
|
||||
if (argc > fpga_cmd->maxargs) {
|
||||
debug("fpga: more parameters passed\n");
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
ret = fpga_cmd->cmd(fpga_cmd, flag, argc, argv);
|
||||
|
||||
return cmd_process_error(fpga_cmd, ret);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_CMD_FPGA_LOADFS) || defined(CONFIG_CMD_FPGA_LOAD_SECURE)
|
||||
U_BOOT_CMD(fpga, 9, 1, do_fpga_wrapper,
|
||||
#else
|
||||
U_BOOT_CMD(fpga, 6, 1, do_fpga_wrapper,
|
||||
#endif
|
||||
"loadable FPGA image support",
|
||||
"[operation type] [device number] [image address] [image size]\n"
|
||||
"fpga operations:\n"
|
||||
" dump\t[dev] [address] [size]\tLoad device to memory buffer\n"
|
||||
" info\t[dev]\t\t\tlist known device information\n"
|
||||
" load\t[dev] [address] [size]\tLoad device from memory buffer\n"
|
||||
#if defined(CONFIG_CMD_FPGA_LOADP)
|
||||
" loadp\t[dev] [address] [size]\t"
|
||||
"Load device from memory buffer with partial bitstream\n"
|
||||
#endif
|
||||
" loadb\t[dev] [address] [size]\t"
|
||||
"Load device from bitstream buffer (Xilinx only)\n"
|
||||
#if defined(CONFIG_CMD_FPGA_LOADBP)
|
||||
" loadbp\t[dev] [address] [size]\t"
|
||||
"Load device from bitstream buffer with partial bitstream"
|
||||
"(Xilinx only)\n"
|
||||
#endif
|
||||
#if defined(CONFIG_CMD_FPGA_LOADFS)
|
||||
"Load device from filesystem (FAT by default) (Xilinx only)\n"
|
||||
" loadfs [dev] [address] [image size] [blocksize] <interface>\n"
|
||||
" [<dev[:part]>] <filename>\n"
|
||||
#endif
|
||||
#if defined(CONFIG_CMD_FPGA_LOADMK)
|
||||
" loadmk [dev] [address]\tLoad device generated with mkimage"
|
||||
#if defined(CONFIG_FIT)
|
||||
"\n"
|
||||
"\tFor loadmk operating on FIT format uImage address must include\n"
|
||||
"\tsubimage unit name in the form of addr:<subimg_uname>"
|
||||
#endif
|
||||
#endif
|
||||
#if defined(CONFIG_CMD_FPGA_LOAD_SECURE)
|
||||
"Load encrypted bitstream (Xilinx only)\n"
|
||||
" loads [dev] [address] [size] [auth-OCM-0/DDR-1/noauth-2]\n"
|
||||
" [enc-devkey(0)/userkey(1)/nenc(2) [Userkey address]\n"
|
||||
"Loads the secure bistreams(authenticated/encrypted/both\n"
|
||||
"authenticated and encrypted) of [size] from [address].\n"
|
||||
"The auth-OCM/DDR flag specifies to perform authentication\n"
|
||||
"in OCM or in DDR. 0 for OCM, 1 for DDR, 2 for no authentication.\n"
|
||||
"The enc flag specifies which key to be used for decryption\n"
|
||||
"0-device key, 1-user key, 2-no encryption.\n"
|
||||
"The optional Userkey address specifies from which address key\n"
|
||||
"has to be used for decryption if user key is selected.\n"
|
||||
"NOTE: the secure bitstream has to be created using Xilinx\n"
|
||||
"bootgen tool only.\n"
|
||||
#endif
|
||||
);
|
||||
100
cmd/fpgad.c
Normal file
100
cmd/fpgad.c
Normal file
@@ -0,0 +1,100 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2013
|
||||
* Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc
|
||||
*
|
||||
* based on cmd_mem.c
|
||||
* (C) Copyright 2000
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <console.h>
|
||||
|
||||
#include <gdsys_fpga.h>
|
||||
|
||||
static uint dp_last_fpga;
|
||||
static uint dp_last_addr;
|
||||
static uint dp_last_length = 0x40;
|
||||
|
||||
/*
|
||||
* FPGA Memory Display
|
||||
*
|
||||
* Syntax:
|
||||
* fpgad {fpga} {addr} {len}
|
||||
*/
|
||||
#define DISP_LINE_LEN 16
|
||||
int do_fpga_md(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
unsigned int k;
|
||||
unsigned int fpga;
|
||||
ulong addr, length;
|
||||
int rc = 0;
|
||||
u16 linebuf[DISP_LINE_LEN/sizeof(u16)];
|
||||
ulong nbytes;
|
||||
|
||||
/*
|
||||
* We use the last specified parameters, unless new ones are
|
||||
* entered.
|
||||
*/
|
||||
fpga = dp_last_fpga;
|
||||
addr = dp_last_addr;
|
||||
length = dp_last_length;
|
||||
|
||||
if (argc < 3)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
if ((flag & CMD_FLAG_REPEAT) == 0) {
|
||||
/*
|
||||
* FPGA is specified since argc > 2
|
||||
*/
|
||||
fpga = simple_strtoul(argv[1], NULL, 16);
|
||||
|
||||
/*
|
||||
* Address is specified since argc > 2
|
||||
*/
|
||||
addr = simple_strtoul(argv[2], NULL, 16);
|
||||
|
||||
/*
|
||||
* If another parameter, it is the length to display.
|
||||
* Length is the number of objects, not number of bytes.
|
||||
*/
|
||||
if (argc > 3)
|
||||
length = simple_strtoul(argv[3], NULL, 16);
|
||||
}
|
||||
|
||||
nbytes = length * sizeof(u16);
|
||||
do {
|
||||
ulong linebytes = (nbytes > DISP_LINE_LEN) ?
|
||||
DISP_LINE_LEN : nbytes;
|
||||
|
||||
for (k = 0; k < linebytes / sizeof(u16); ++k)
|
||||
fpga_get_reg(fpga,
|
||||
(u16 *)fpga_ptr[fpga] + addr
|
||||
/ sizeof(u16) + k,
|
||||
addr + k * sizeof(u16),
|
||||
&linebuf[k]);
|
||||
print_buffer(addr, (void *)linebuf, sizeof(u16),
|
||||
linebytes / sizeof(u16),
|
||||
DISP_LINE_LEN / sizeof(u16));
|
||||
|
||||
nbytes -= linebytes;
|
||||
addr += linebytes;
|
||||
if (ctrlc()) {
|
||||
rc = 1;
|
||||
break;
|
||||
}
|
||||
} while (nbytes > 0);
|
||||
|
||||
dp_last_fpga = fpga;
|
||||
dp_last_addr = addr;
|
||||
dp_last_length = length;
|
||||
return rc;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
fpgad, 4, 1, do_fpga_md,
|
||||
"fpga register display",
|
||||
"fpga address [# of objects]"
|
||||
);
|
||||
101
cmd/fs.c
Normal file
101
cmd/fs.c
Normal file
@@ -0,0 +1,101 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Inspired by cmd_ext_common.c, cmd_fat.c.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <fs.h>
|
||||
|
||||
static int do_size_wrapper(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
return do_size(cmdtp, flag, argc, argv, FS_TYPE_ANY);
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
size, 4, 0, do_size_wrapper,
|
||||
"determine a file's size",
|
||||
"<interface> <dev[:part]> <filename>\n"
|
||||
" - Find file 'filename' from 'dev' on 'interface'\n"
|
||||
" and determine its size."
|
||||
);
|
||||
|
||||
static int do_load_wrapper(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
return do_load(cmdtp, flag, argc, argv, FS_TYPE_ANY);
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
load, 7, 0, do_load_wrapper,
|
||||
"load binary file from a filesystem",
|
||||
"<interface> [<dev[:part]> [<addr> [<filename> [bytes [pos]]]]]\n"
|
||||
" - Load binary file 'filename' from partition 'part' on device\n"
|
||||
" type 'interface' instance 'dev' to address 'addr' in memory.\n"
|
||||
" 'bytes' gives the size to load in bytes.\n"
|
||||
" If 'bytes' is 0 or omitted, the file is read until the end.\n"
|
||||
" 'pos' gives the file byte position to start reading from.\n"
|
||||
" If 'pos' is 0 or omitted, the file is read from the start."
|
||||
)
|
||||
|
||||
static int do_save_wrapper(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
return do_save(cmdtp, flag, argc, argv, FS_TYPE_ANY);
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
save, 7, 0, do_save_wrapper,
|
||||
"save file to a filesystem",
|
||||
"<interface> <dev[:part]> <addr> <filename> bytes [pos]\n"
|
||||
" - Save binary file 'filename' to partition 'part' on device\n"
|
||||
" type 'interface' instance 'dev' from addr 'addr' in memory.\n"
|
||||
" 'bytes' gives the size to save in bytes and is mandatory.\n"
|
||||
" 'pos' gives the file byte position to start writing to.\n"
|
||||
" If 'pos' is 0 or omitted, the file is written from the start."
|
||||
)
|
||||
|
||||
static int do_ls_wrapper(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
return do_ls(cmdtp, flag, argc, argv, FS_TYPE_ANY);
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
ls, 4, 1, do_ls_wrapper,
|
||||
"list files in a directory (default /)",
|
||||
"<interface> [<dev[:part]> [directory]]\n"
|
||||
" - List files in directory 'directory' of partition 'part' on\n"
|
||||
" device type 'interface' instance 'dev'."
|
||||
)
|
||||
|
||||
static int do_ln_wrapper(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
return do_ln(cmdtp, flag, argc, argv, FS_TYPE_ANY);
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
ln, 5, 1, do_ln_wrapper,
|
||||
"Create a symbolic link",
|
||||
"<interface> <dev[:part]> target linkname\n"
|
||||
" - create a symbolic link to 'target' with the name 'linkname' on\n"
|
||||
" device type 'interface' instance 'dev'."
|
||||
)
|
||||
|
||||
static int do_fstype_wrapper(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
return do_fs_type(cmdtp, flag, argc, argv);
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
fstype, 4, 1, do_fstype_wrapper,
|
||||
"Look up a filesystem type",
|
||||
"<interface> <dev>:<part>\n"
|
||||
"- print filesystem type\n"
|
||||
"fstype <interface> <dev>:<part> <varname>\n"
|
||||
"- set environment variable to filesystem type\n"
|
||||
);
|
||||
25
cmd/fs_uuid.c
Normal file
25
cmd/fs_uuid.c
Normal file
@@ -0,0 +1,25 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* cmd_fs_uuid.c -- fsuuid command
|
||||
*
|
||||
* Copyright (C) 2014, Bachmann electronic GmbH
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <fs.h>
|
||||
|
||||
static int do_fs_uuid_wrapper(cmd_tbl_t *cmdtp, int flag,
|
||||
int argc, char * const argv[])
|
||||
{
|
||||
return do_fs_uuid(cmdtp, flag, argc, argv, FS_TYPE_ANY);
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
fsuuid, 4, 1, do_fs_uuid_wrapper,
|
||||
"Look up a filesystem UUID",
|
||||
"<interface> <dev>:<part>\n"
|
||||
" - print filesystem UUID\n"
|
||||
"fsuuid <interface> <dev>:<part> <varname>\n"
|
||||
" - set environment variable to filesystem UUID\n"
|
||||
);
|
||||
145
cmd/fuse.c
Normal file
145
cmd/fuse.c
Normal file
@@ -0,0 +1,145 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2009-2013 ADVANSEE
|
||||
* Benoît Thébaudeau <benoit.thebaudeau@advansee.com>
|
||||
*
|
||||
* Based on the mpc512x iim code:
|
||||
* Copyright 2008 Silicon Turnkey Express, Inc.
|
||||
* Martha Marx <mmarx@silicontkx.com>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <console.h>
|
||||
#include <fuse.h>
|
||||
#include <linux/errno.h>
|
||||
|
||||
static int strtou32(const char *str, unsigned int base, u32 *result)
|
||||
{
|
||||
char *ep;
|
||||
|
||||
*result = simple_strtoul(str, &ep, base);
|
||||
if (ep == str || *ep != '\0')
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int confirm_prog(void)
|
||||
{
|
||||
puts("Warning: Programming fuses is an irreversible operation!\n"
|
||||
" This may brick your system.\n"
|
||||
" Use this command only if you are sure of "
|
||||
"what you are doing!\n"
|
||||
"\nReally perform this fuse programming? <y/N>\n");
|
||||
|
||||
if (confirm_yesno())
|
||||
return 1;
|
||||
|
||||
puts("Fuse programming aborted\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_fuse(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
|
||||
{
|
||||
const char *op = argc >= 2 ? argv[1] : NULL;
|
||||
int confirmed = argc >= 3 && !strcmp(argv[2], "-y");
|
||||
u32 bank, word, cnt, val;
|
||||
int ret, i;
|
||||
|
||||
argc -= 2 + confirmed;
|
||||
argv += 2 + confirmed;
|
||||
|
||||
if (argc < 2 || strtou32(argv[0], 0, &bank) ||
|
||||
strtou32(argv[1], 0, &word))
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
if (!strcmp(op, "read")) {
|
||||
if (argc == 2)
|
||||
cnt = 1;
|
||||
else if (argc != 3 || strtou32(argv[2], 0, &cnt))
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
printf("Reading bank %u:\n", bank);
|
||||
for (i = 0; i < cnt; i++, word++) {
|
||||
if (!(i % 4))
|
||||
printf("\nWord 0x%.8x:", word);
|
||||
|
||||
ret = fuse_read(bank, word, &val);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
printf(" %.8x", val);
|
||||
}
|
||||
putc('\n');
|
||||
} else if (!strcmp(op, "sense")) {
|
||||
if (argc == 2)
|
||||
cnt = 1;
|
||||
else if (argc != 3 || strtou32(argv[2], 0, &cnt))
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
printf("Sensing bank %u:\n", bank);
|
||||
for (i = 0; i < cnt; i++, word++) {
|
||||
if (!(i % 4))
|
||||
printf("\nWord 0x%.8x:", word);
|
||||
|
||||
ret = fuse_sense(bank, word, &val);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
printf(" %.8x", val);
|
||||
}
|
||||
putc('\n');
|
||||
} else if (!strcmp(op, "prog")) {
|
||||
if (argc < 3)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
for (i = 2; i < argc; i++, word++) {
|
||||
if (strtou32(argv[i], 16, &val))
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
printf("Programming bank %u word 0x%.8x to 0x%.8x...\n",
|
||||
bank, word, val);
|
||||
if (!confirmed && !confirm_prog())
|
||||
return CMD_RET_FAILURE;
|
||||
ret = fuse_prog(bank, word, val);
|
||||
if (ret)
|
||||
goto err;
|
||||
}
|
||||
} else if (!strcmp(op, "override")) {
|
||||
if (argc < 3)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
for (i = 2; i < argc; i++, word++) {
|
||||
if (strtou32(argv[i], 16, &val))
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
printf("Overriding bank %u word 0x%.8x with "
|
||||
"0x%.8x...\n", bank, word, val);
|
||||
ret = fuse_override(bank, word, val);
|
||||
if (ret)
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
puts("ERROR\n");
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
fuse, CONFIG_SYS_MAXARGS, 0, do_fuse,
|
||||
"Fuse sub-system",
|
||||
"read <bank> <word> [<cnt>] - read 1 or 'cnt' fuse words,\n"
|
||||
" starting at 'word'\n"
|
||||
"fuse sense <bank> <word> [<cnt>] - sense 1 or 'cnt' fuse words,\n"
|
||||
" starting at 'word'\n"
|
||||
"fuse prog [-y] <bank> <word> <hexval> [<hexval>...] - program 1 or\n"
|
||||
" several fuse words, starting at 'word' (PERMANENT)\n"
|
||||
"fuse override <bank> <word> <hexval> [<hexval>...] - override 1 or\n"
|
||||
" several fuse words, starting at 'word'"
|
||||
);
|
||||
39
cmd/gettime.c
Normal file
39
cmd/gettime.c
Normal file
@@ -0,0 +1,39 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
|
||||
*
|
||||
* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
|
||||
*
|
||||
* (C) Copyright 2001
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Get Timer overflows after 2^32 / CONFIG_SYS_HZ (32Khz) = 131072 sec
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
|
||||
static int do_gettime(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
unsigned long int val = get_timer(0);
|
||||
|
||||
#ifdef CONFIG_SYS_HZ
|
||||
printf("Timer val: %lu\n", val);
|
||||
printf("Seconds : %lu\n", val / CONFIG_SYS_HZ);
|
||||
printf("Remainder : %lu\n", val % CONFIG_SYS_HZ);
|
||||
printf("sys_hz = %lu\n", (unsigned long int)CONFIG_SYS_HZ);
|
||||
#else
|
||||
printf("CONFIG_SYS_HZ not defined");
|
||||
printf("Timer Val %lu", val);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
gettime, 1, 1, do_gettime,
|
||||
"get timer val elapsed",
|
||||
"get time elapsed from uboot start"
|
||||
);
|
||||
249
cmd/gpio.c
Normal file
249
cmd/gpio.c
Normal file
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
* Control GPIO pins on the fly
|
||||
*
|
||||
* Copyright (c) 2008-2011 Analog Devices Inc.
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <errno.h>
|
||||
#include <dm.h>
|
||||
#include <asm/gpio.h>
|
||||
|
||||
__weak int name_to_gpio(const char *name)
|
||||
{
|
||||
return simple_strtoul(name, NULL, 10);
|
||||
}
|
||||
|
||||
enum gpio_cmd {
|
||||
GPIOC_INPUT,
|
||||
GPIOC_SET,
|
||||
GPIOC_CLEAR,
|
||||
GPIOC_TOGGLE,
|
||||
};
|
||||
|
||||
#if defined(CONFIG_DM_GPIO) && !defined(gpio_status)
|
||||
|
||||
/* A few flags used by show_gpio() */
|
||||
enum {
|
||||
FLAG_SHOW_ALL = 1 << 0,
|
||||
FLAG_SHOW_BANK = 1 << 1,
|
||||
FLAG_SHOW_NEWLINE = 1 << 2,
|
||||
};
|
||||
|
||||
static void gpio_get_description(struct udevice *dev, const char *bank_name,
|
||||
int offset, int *flagsp, bool show_all)
|
||||
{
|
||||
char buf[80];
|
||||
int ret;
|
||||
|
||||
ret = gpio_get_function(dev, offset, NULL);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
if (!show_all && !(*flagsp & FLAG_SHOW_ALL) && ret == GPIOF_UNUSED)
|
||||
return;
|
||||
if ((*flagsp & FLAG_SHOW_BANK) && bank_name) {
|
||||
if (*flagsp & FLAG_SHOW_NEWLINE) {
|
||||
putc('\n');
|
||||
*flagsp &= ~FLAG_SHOW_NEWLINE;
|
||||
}
|
||||
printf("Bank %s:\n", bank_name);
|
||||
*flagsp &= ~FLAG_SHOW_BANK;
|
||||
}
|
||||
|
||||
ret = gpio_get_status(dev, offset, buf, sizeof(buf));
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
printf("%s\n", buf);
|
||||
return;
|
||||
err:
|
||||
printf("Error %d\n", ret);
|
||||
}
|
||||
|
||||
static int do_gpio_status(bool all, const char *gpio_name)
|
||||
{
|
||||
struct udevice *dev;
|
||||
int banklen;
|
||||
int flags;
|
||||
int ret;
|
||||
|
||||
flags = 0;
|
||||
if (gpio_name && !*gpio_name)
|
||||
gpio_name = NULL;
|
||||
for (ret = uclass_first_device(UCLASS_GPIO, &dev);
|
||||
dev;
|
||||
ret = uclass_next_device(&dev)) {
|
||||
const char *bank_name;
|
||||
int num_bits;
|
||||
|
||||
flags |= FLAG_SHOW_BANK;
|
||||
if (all)
|
||||
flags |= FLAG_SHOW_ALL;
|
||||
bank_name = gpio_get_bank_info(dev, &num_bits);
|
||||
if (!num_bits) {
|
||||
debug("GPIO device %s has no bits\n", dev->name);
|
||||
continue;
|
||||
}
|
||||
banklen = bank_name ? strlen(bank_name) : 0;
|
||||
|
||||
if (!gpio_name || !bank_name ||
|
||||
!strncasecmp(gpio_name, bank_name, banklen)) {
|
||||
const char *p;
|
||||
int offset;
|
||||
|
||||
p = gpio_name + banklen;
|
||||
if (gpio_name && *p) {
|
||||
offset = simple_strtoul(p, NULL, 10);
|
||||
gpio_get_description(dev, bank_name, offset,
|
||||
&flags, true);
|
||||
} else {
|
||||
for (offset = 0; offset < num_bits; offset++) {
|
||||
gpio_get_description(dev, bank_name,
|
||||
offset, &flags, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Add a newline between bank names */
|
||||
if (!(flags & FLAG_SHOW_BANK))
|
||||
flags |= FLAG_SHOW_NEWLINE;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int do_gpio(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
unsigned int gpio;
|
||||
enum gpio_cmd sub_cmd;
|
||||
int value;
|
||||
const char *str_cmd, *str_gpio = NULL;
|
||||
int ret;
|
||||
#ifdef CONFIG_DM_GPIO
|
||||
bool all = false;
|
||||
#endif
|
||||
|
||||
if (argc < 2)
|
||||
show_usage:
|
||||
return CMD_RET_USAGE;
|
||||
str_cmd = argv[1];
|
||||
argc -= 2;
|
||||
argv += 2;
|
||||
#ifdef CONFIG_DM_GPIO
|
||||
if (argc > 0 && !strcmp(*argv, "-a")) {
|
||||
all = true;
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
#endif
|
||||
if (argc > 0)
|
||||
str_gpio = *argv;
|
||||
if (!strncmp(str_cmd, "status", 2)) {
|
||||
/* Support deprecated gpio_status() */
|
||||
#ifdef gpio_status
|
||||
gpio_status();
|
||||
return 0;
|
||||
#elif defined(CONFIG_DM_GPIO)
|
||||
return cmd_process_error(cmdtp, do_gpio_status(all, str_gpio));
|
||||
#else
|
||||
goto show_usage;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!str_gpio)
|
||||
goto show_usage;
|
||||
|
||||
/* parse the behavior */
|
||||
switch (*str_cmd) {
|
||||
case 'i':
|
||||
sub_cmd = GPIOC_INPUT;
|
||||
break;
|
||||
case 's':
|
||||
sub_cmd = GPIOC_SET;
|
||||
break;
|
||||
case 'c':
|
||||
sub_cmd = GPIOC_CLEAR;
|
||||
break;
|
||||
case 't':
|
||||
sub_cmd = GPIOC_TOGGLE;
|
||||
break;
|
||||
default:
|
||||
goto show_usage;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_DM_GPIO)
|
||||
/*
|
||||
* TODO(sjg@chromium.org): For now we must fit into the existing GPIO
|
||||
* framework, so we look up the name here and convert it to a GPIO number.
|
||||
* Once all GPIO drivers are converted to driver model, we can change the
|
||||
* code here to use the GPIO uclass interface instead of the numbered
|
||||
* GPIO compatibility layer.
|
||||
*/
|
||||
ret = gpio_lookup_name(str_gpio, NULL, NULL, &gpio);
|
||||
if (ret) {
|
||||
printf("GPIO: '%s' not found\n", str_gpio);
|
||||
return cmd_process_error(cmdtp, ret);
|
||||
}
|
||||
#else
|
||||
/* turn the gpio name into a gpio number */
|
||||
gpio = name_to_gpio(str_gpio);
|
||||
if (gpio < 0)
|
||||
goto show_usage;
|
||||
#endif
|
||||
/* grab the pin before we tweak it */
|
||||
ret = gpio_request(gpio, "cmd_gpio");
|
||||
if (ret && ret != -EBUSY) {
|
||||
printf("gpio: requesting pin %u failed\n", gpio);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* finally, let's do it: set direction and exec command */
|
||||
if (sub_cmd == GPIOC_INPUT) {
|
||||
gpio_direction_input(gpio);
|
||||
value = gpio_get_value(gpio);
|
||||
} else {
|
||||
switch (sub_cmd) {
|
||||
case GPIOC_SET:
|
||||
value = 1;
|
||||
break;
|
||||
case GPIOC_CLEAR:
|
||||
value = 0;
|
||||
break;
|
||||
case GPIOC_TOGGLE:
|
||||
value = gpio_get_value(gpio);
|
||||
if (!IS_ERR_VALUE(value))
|
||||
value = !value;
|
||||
break;
|
||||
default:
|
||||
goto show_usage;
|
||||
}
|
||||
gpio_direction_output(gpio, value);
|
||||
}
|
||||
printf("gpio: pin %s (gpio %u) value is ", str_gpio, gpio);
|
||||
if (IS_ERR_VALUE(value))
|
||||
printf("unknown (ret=%d)\n", value);
|
||||
else
|
||||
printf("%d\n", value);
|
||||
if (sub_cmd != GPIOC_INPUT && !IS_ERR_VALUE(value)) {
|
||||
int nval = gpio_get_value(gpio);
|
||||
|
||||
if (IS_ERR_VALUE(nval))
|
||||
printf(" Warning: no access to GPIO output value\n");
|
||||
else if (nval != value)
|
||||
printf(" Warning: value of pin is still %d\n", nval);
|
||||
}
|
||||
|
||||
if (ret != -EBUSY)
|
||||
gpio_free(gpio);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(gpio, 4, 0, do_gpio,
|
||||
"query and control gpio pins",
|
||||
"<input|set|clear|toggle> <pin>\n"
|
||||
" - input/set/clear/toggle the specified pin\n"
|
||||
"gpio status [-a] [<bank> | <pin>] - show [all/claimed] GPIOs");
|
||||
900
cmd/gpt.c
Normal file
900
cmd/gpt.c
Normal file
@@ -0,0 +1,900 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* cmd_gpt.c -- GPT (GUID Partition Table) handling command
|
||||
*
|
||||
* Copyright (C) 2015
|
||||
* Lukasz Majewski <l.majewski@majess.pl>
|
||||
*
|
||||
* Copyright (C) 2012 Samsung Electronics
|
||||
* author: Lukasz Majewski <l.majewski@samsung.com>
|
||||
* author: Piotr Wilczek <p.wilczek@samsung.com>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <env.h>
|
||||
#include <malloc.h>
|
||||
#include <command.h>
|
||||
#include <part_efi.h>
|
||||
#include <exports.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <div64.h>
|
||||
#include <memalign.h>
|
||||
#include <linux/compat.h>
|
||||
#include <linux/sizes.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static LIST_HEAD(disk_partitions);
|
||||
|
||||
/**
|
||||
* extract_env(): Expand env name from string format '&{env_name}'
|
||||
* and return pointer to the env (if the env is set)
|
||||
*
|
||||
* @param str - pointer to string
|
||||
* @param env - pointer to pointer to extracted env
|
||||
*
|
||||
* @return - zero on successful expand and env is set
|
||||
*/
|
||||
static int extract_env(const char *str, char **env)
|
||||
{
|
||||
int ret = -1;
|
||||
char *e, *s;
|
||||
#ifdef CONFIG_RANDOM_UUID
|
||||
char uuid_str[UUID_STR_LEN + 1];
|
||||
#endif
|
||||
|
||||
if (!str || strlen(str) < 4)
|
||||
return -1;
|
||||
|
||||
if (!((strncmp(str, "${", 2) == 0) && (str[strlen(str) - 1] == '}')))
|
||||
return -1;
|
||||
|
||||
s = strdup(str);
|
||||
if (s == NULL)
|
||||
return -1;
|
||||
|
||||
memset(s + strlen(s) - 1, '\0', 1);
|
||||
memmove(s, s + 2, strlen(s) - 1);
|
||||
|
||||
e = env_get(s);
|
||||
if (e == NULL) {
|
||||
#ifdef CONFIG_RANDOM_UUID
|
||||
debug("%s unset. ", str);
|
||||
gen_rand_uuid_str(uuid_str, UUID_STR_FORMAT_GUID);
|
||||
env_set(s, uuid_str);
|
||||
|
||||
e = env_get(s);
|
||||
if (e) {
|
||||
debug("Set to random.\n");
|
||||
ret = 0;
|
||||
} else {
|
||||
debug("Can't get random UUID.\n");
|
||||
}
|
||||
#else
|
||||
debug("%s unset.\n", str);
|
||||
#endif
|
||||
} else {
|
||||
debug("%s get from environment.\n", str);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
*env = e;
|
||||
free(s);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* extract_val(): Extract value from a key=value pair list (comma separated).
|
||||
* Only value for the given key is returend.
|
||||
* Function allocates memory for the value, remember to free!
|
||||
*
|
||||
* @param str - pointer to string with key=values pairs
|
||||
* @param key - pointer to the key to search for
|
||||
*
|
||||
* @return - pointer to allocated string with the value
|
||||
*/
|
||||
static char *extract_val(const char *str, const char *key)
|
||||
{
|
||||
char *v, *k;
|
||||
char *s, *strcopy;
|
||||
char *new = NULL;
|
||||
|
||||
strcopy = strdup(str);
|
||||
if (strcopy == NULL)
|
||||
return NULL;
|
||||
|
||||
s = strcopy;
|
||||
while (s) {
|
||||
v = strsep(&s, ",");
|
||||
if (!v)
|
||||
break;
|
||||
k = strsep(&v, "=");
|
||||
if (!k)
|
||||
break;
|
||||
if (strcmp(k, key) == 0) {
|
||||
new = strdup(v);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(strcopy);
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
/**
|
||||
* found_key(): Found key without value in parameter list (comma separated).
|
||||
*
|
||||
* @param str - pointer to string with key
|
||||
* @param key - pointer to the key to search for
|
||||
*
|
||||
* @return - true on found key
|
||||
*/
|
||||
static bool found_key(const char *str, const char *key)
|
||||
{
|
||||
char *k;
|
||||
char *s, *strcopy;
|
||||
bool result = false;
|
||||
|
||||
strcopy = strdup(str);
|
||||
if (!strcopy)
|
||||
return NULL;
|
||||
|
||||
s = strcopy;
|
||||
while (s) {
|
||||
k = strsep(&s, ",");
|
||||
if (!k)
|
||||
break;
|
||||
if (strcmp(k, key) == 0) {
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(strcopy);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int calc_parts_list_len(int numparts)
|
||||
{
|
||||
int partlistlen = UUID_STR_LEN + 1 + strlen("uuid_disk=");
|
||||
/* for the comma */
|
||||
partlistlen++;
|
||||
|
||||
/* per-partition additions; numparts starts at 1, so this should be correct */
|
||||
partlistlen += numparts * (strlen("name=,") + PART_NAME_LEN + 1);
|
||||
/* see part.h for definition of struct disk_partition */
|
||||
partlistlen += numparts * (strlen("start=MiB,") + sizeof(lbaint_t) + 1);
|
||||
partlistlen += numparts * (strlen("size=MiB,") + sizeof(lbaint_t) + 1);
|
||||
partlistlen += numparts * (strlen("uuid=;") + UUID_STR_LEN + 1);
|
||||
/* for the terminating null */
|
||||
partlistlen++;
|
||||
debug("Length of partitions_list is %d for %d partitions\n", partlistlen,
|
||||
numparts);
|
||||
return partlistlen;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CMD_GPT_RENAME
|
||||
static void del_gpt_info(void)
|
||||
{
|
||||
struct list_head *pos = &disk_partitions;
|
||||
struct disk_part *curr;
|
||||
while (!list_empty(pos)) {
|
||||
curr = list_entry(pos->next, struct disk_part, list);
|
||||
list_del(pos->next);
|
||||
free(curr);
|
||||
}
|
||||
}
|
||||
|
||||
static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
|
||||
{
|
||||
struct disk_part *newpart;
|
||||
newpart = calloc(1, sizeof(struct disk_part));
|
||||
if (!newpart)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
newpart->gpt_part_info.start = info->start;
|
||||
newpart->gpt_part_info.size = info->size;
|
||||
newpart->gpt_part_info.blksz = info->blksz;
|
||||
strncpy((char *)newpart->gpt_part_info.name, (const char *)info->name,
|
||||
PART_NAME_LEN);
|
||||
newpart->gpt_part_info.name[PART_NAME_LEN - 1] = '\0';
|
||||
strncpy((char *)newpart->gpt_part_info.type, (const char *)info->type,
|
||||
PART_TYPE_LEN);
|
||||
newpart->gpt_part_info.type[PART_TYPE_LEN - 1] = '\0';
|
||||
newpart->gpt_part_info.bootable = info->bootable;
|
||||
#ifdef CONFIG_PARTITION_UUIDS
|
||||
strncpy(newpart->gpt_part_info.uuid, (const char *)info->uuid,
|
||||
UUID_STR_LEN);
|
||||
/* UUID_STR_LEN is correct, as uuid[]'s length is UUID_STR_LEN+1 chars */
|
||||
newpart->gpt_part_info.uuid[UUID_STR_LEN] = '\0';
|
||||
#endif
|
||||
newpart->partnum = partnum;
|
||||
|
||||
return newpart;
|
||||
}
|
||||
|
||||
static void prettyprint_part_size(char *sizestr, lbaint_t partsize,
|
||||
lbaint_t blksize)
|
||||
{
|
||||
unsigned long long partbytes, partmegabytes;
|
||||
|
||||
partbytes = partsize * blksize;
|
||||
partmegabytes = lldiv(partbytes, SZ_1M);
|
||||
snprintf(sizestr, 16, "%lluMiB", partmegabytes);
|
||||
}
|
||||
|
||||
static void print_gpt_info(void)
|
||||
{
|
||||
struct list_head *pos;
|
||||
struct disk_part *curr;
|
||||
char partstartstr[16];
|
||||
char partsizestr[16];
|
||||
|
||||
list_for_each(pos, &disk_partitions) {
|
||||
curr = list_entry(pos, struct disk_part, list);
|
||||
prettyprint_part_size(partstartstr, curr->gpt_part_info.start,
|
||||
curr->gpt_part_info.blksz);
|
||||
prettyprint_part_size(partsizestr, curr->gpt_part_info.size,
|
||||
curr->gpt_part_info.blksz);
|
||||
|
||||
printf("Partition %d:\n", curr->partnum);
|
||||
printf("Start %s, size %s\n", partstartstr, partsizestr);
|
||||
printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
|
||||
curr->gpt_part_info.name);
|
||||
printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
|
||||
curr->gpt_part_info.bootable);
|
||||
#ifdef CONFIG_PARTITION_UUIDS
|
||||
printf("UUID %s\n", curr->gpt_part_info.uuid);
|
||||
#endif
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* create the string that upstream 'gpt write' command will accept as an
|
||||
* argument
|
||||
*
|
||||
* From doc/README.gpt, Format of partitions layout:
|
||||
* "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
|
||||
* name=kernel,size=60MiB,uuid=...;"
|
||||
* The fields 'name' and 'size' are mandatory for every partition.
|
||||
* The field 'start' is optional. The fields 'uuid' and 'uuid_disk'
|
||||
* are optional if CONFIG_RANDOM_UUID is enabled.
|
||||
*/
|
||||
static int create_gpt_partitions_list(int numparts, const char *guid,
|
||||
char *partitions_list)
|
||||
{
|
||||
struct list_head *pos;
|
||||
struct disk_part *curr;
|
||||
char partstr[PART_NAME_LEN + 1];
|
||||
|
||||
if (!partitions_list)
|
||||
return -EINVAL;
|
||||
|
||||
strcpy(partitions_list, "uuid_disk=");
|
||||
strncat(partitions_list, guid, UUID_STR_LEN + 1);
|
||||
strcat(partitions_list, ";");
|
||||
|
||||
list_for_each(pos, &disk_partitions) {
|
||||
curr = list_entry(pos, struct disk_part, list);
|
||||
strcat(partitions_list, "name=");
|
||||
strncat(partitions_list, (const char *)curr->gpt_part_info.name,
|
||||
PART_NAME_LEN + 1);
|
||||
sprintf(partstr, ",start=0x%llx",
|
||||
(unsigned long long)curr->gpt_part_info.start *
|
||||
curr->gpt_part_info.blksz);
|
||||
/* one extra byte for NULL */
|
||||
strncat(partitions_list, partstr, PART_NAME_LEN + 1);
|
||||
sprintf(partstr, ",size=0x%llx",
|
||||
(unsigned long long)curr->gpt_part_info.size *
|
||||
curr->gpt_part_info.blksz);
|
||||
strncat(partitions_list, partstr, PART_NAME_LEN + 1);
|
||||
|
||||
strcat(partitions_list, ",uuid=");
|
||||
strncat(partitions_list, curr->gpt_part_info.uuid,
|
||||
UUID_STR_LEN + 1);
|
||||
strcat(partitions_list, ";");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* read partition info into disk_partitions list where
|
||||
* it can be printed or modified
|
||||
*/
|
||||
static int get_gpt_info(struct blk_desc *dev_desc)
|
||||
{
|
||||
/* start partition numbering at 1, as U-Boot does */
|
||||
int valid_parts = 0, p, ret;
|
||||
disk_partition_t info;
|
||||
struct disk_part *new_disk_part;
|
||||
|
||||
/*
|
||||
* Always re-read partition info from device, in case
|
||||
* it has changed
|
||||
*/
|
||||
INIT_LIST_HEAD(&disk_partitions);
|
||||
|
||||
for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
|
||||
ret = part_get_info(dev_desc, p, &info);
|
||||
if (ret)
|
||||
continue;
|
||||
|
||||
/* Add 1 here because counter is zero-based but p1 is
|
||||
the first partition */
|
||||
new_disk_part = allocate_disk_part(&info, valid_parts+1);
|
||||
if (IS_ERR(new_disk_part))
|
||||
goto out;
|
||||
|
||||
list_add_tail(&new_disk_part->list, &disk_partitions);
|
||||
valid_parts++;
|
||||
}
|
||||
if (valid_parts == 0) {
|
||||
printf("** No valid partitions found **\n");
|
||||
goto out;
|
||||
}
|
||||
return valid_parts;
|
||||
out:
|
||||
if (valid_parts >= 1)
|
||||
del_gpt_info();
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* a wrapper to test get_gpt_info */
|
||||
static int do_get_gpt_info(struct blk_desc *dev_desc)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = get_gpt_info(dev_desc);
|
||||
if (ret > 0) {
|
||||
print_gpt_info();
|
||||
del_gpt_info();
|
||||
return 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* set_gpt_info(): Fill partition information from string
|
||||
* function allocates memory, remember to free!
|
||||
*
|
||||
* @param dev_desc - pointer block device descriptor
|
||||
* @param str_part - pointer to string with partition information
|
||||
* @param str_disk_guid - pointer to pointer to allocated string with disk guid
|
||||
* @param partitions - pointer to pointer to allocated partitions array
|
||||
* @param parts_count - number of partitions
|
||||
*
|
||||
* @return - zero on success, otherwise error
|
||||
*
|
||||
*/
|
||||
static int set_gpt_info(struct blk_desc *dev_desc,
|
||||
const char *str_part,
|
||||
char **str_disk_guid,
|
||||
disk_partition_t **partitions,
|
||||
u8 *parts_count)
|
||||
{
|
||||
char *tok, *str, *s;
|
||||
int i;
|
||||
char *val, *p;
|
||||
int p_count;
|
||||
disk_partition_t *parts;
|
||||
int errno = 0;
|
||||
uint64_t size_ll, start_ll;
|
||||
lbaint_t offset = 0;
|
||||
int max_str_part = calc_parts_list_len(MAX_SEARCH_PARTITIONS);
|
||||
|
||||
debug("%s: lba num: 0x%x %d\n", __func__,
|
||||
(unsigned int)dev_desc->lba, (unsigned int)dev_desc->lba);
|
||||
|
||||
if (str_part == NULL)
|
||||
return -1;
|
||||
|
||||
str = strdup(str_part);
|
||||
if (str == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
/* extract disk guid */
|
||||
s = str;
|
||||
val = extract_val(str, "uuid_disk");
|
||||
if (!val) {
|
||||
#ifdef CONFIG_RANDOM_UUID
|
||||
*str_disk_guid = malloc(UUID_STR_LEN + 1);
|
||||
if (*str_disk_guid == NULL)
|
||||
return -ENOMEM;
|
||||
gen_rand_uuid_str(*str_disk_guid, UUID_STR_FORMAT_STD);
|
||||
#else
|
||||
free(str);
|
||||
return -2;
|
||||
#endif
|
||||
} else {
|
||||
val = strsep(&val, ";");
|
||||
if (extract_env(val, &p))
|
||||
p = val;
|
||||
*str_disk_guid = strdup(p);
|
||||
free(val);
|
||||
/* Move s to first partition */
|
||||
strsep(&s, ";");
|
||||
}
|
||||
if (s == NULL) {
|
||||
printf("Error: is the partitions string NULL-terminated?\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (strnlen(s, max_str_part) == 0)
|
||||
return -3;
|
||||
|
||||
i = strnlen(s, max_str_part) - 1;
|
||||
if (s[i] == ';')
|
||||
s[i] = '\0';
|
||||
|
||||
/* calculate expected number of partitions */
|
||||
p_count = 1;
|
||||
p = s;
|
||||
while (*p) {
|
||||
if (*p++ == ';')
|
||||
p_count++;
|
||||
}
|
||||
|
||||
/* allocate memory for partitions */
|
||||
parts = calloc(sizeof(disk_partition_t), p_count);
|
||||
if (parts == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
/* retrieve partitions data from string */
|
||||
for (i = 0; i < p_count; i++) {
|
||||
tok = strsep(&s, ";");
|
||||
|
||||
if (tok == NULL)
|
||||
break;
|
||||
|
||||
/* uuid */
|
||||
val = extract_val(tok, "uuid");
|
||||
if (!val) {
|
||||
/* 'uuid' is optional if random uuid's are enabled */
|
||||
#ifdef CONFIG_RANDOM_UUID
|
||||
gen_rand_uuid_str(parts[i].uuid, UUID_STR_FORMAT_STD);
|
||||
#else
|
||||
errno = -4;
|
||||
goto err;
|
||||
#endif
|
||||
} else {
|
||||
if (extract_env(val, &p))
|
||||
p = val;
|
||||
if (strnlen(p, max_str_part) >= sizeof(parts[i].uuid)) {
|
||||
printf("Wrong uuid format for partition %d\n", i);
|
||||
errno = -4;
|
||||
goto err;
|
||||
}
|
||||
strncpy((char *)parts[i].uuid, p, max_str_part);
|
||||
free(val);
|
||||
}
|
||||
#ifdef CONFIG_PARTITION_TYPE_GUID
|
||||
/* guid */
|
||||
val = extract_val(tok, "type");
|
||||
if (val) {
|
||||
/* 'type' is optional */
|
||||
if (extract_env(val, &p))
|
||||
p = val;
|
||||
if (strnlen(p, max_str_part) >= sizeof(parts[i].type_guid)) {
|
||||
printf("Wrong type guid format for partition %d\n",
|
||||
i);
|
||||
errno = -4;
|
||||
goto err;
|
||||
}
|
||||
strncpy((char *)parts[i].type_guid, p, max_str_part);
|
||||
free(val);
|
||||
}
|
||||
#endif
|
||||
/* name */
|
||||
val = extract_val(tok, "name");
|
||||
if (!val) { /* name is mandatory */
|
||||
errno = -4;
|
||||
goto err;
|
||||
}
|
||||
if (extract_env(val, &p))
|
||||
p = val;
|
||||
if (strnlen(p, max_str_part) >= sizeof(parts[i].name)) {
|
||||
errno = -4;
|
||||
goto err;
|
||||
}
|
||||
strncpy((char *)parts[i].name, p, max_str_part);
|
||||
free(val);
|
||||
|
||||
/* size */
|
||||
val = extract_val(tok, "size");
|
||||
if (!val) { /* 'size' is mandatory */
|
||||
errno = -4;
|
||||
goto err;
|
||||
}
|
||||
if (extract_env(val, &p))
|
||||
p = val;
|
||||
if ((strcmp(p, "-") == 0)) {
|
||||
/* Let part efi module to auto extend the size */
|
||||
parts[i].size = 0;
|
||||
} else {
|
||||
size_ll = ustrtoull(p, &p, 0);
|
||||
parts[i].size = lldiv(size_ll, dev_desc->blksz);
|
||||
}
|
||||
|
||||
free(val);
|
||||
|
||||
/* start address */
|
||||
val = extract_val(tok, "start");
|
||||
if (val) { /* start address is optional */
|
||||
if (extract_env(val, &p))
|
||||
p = val;
|
||||
start_ll = ustrtoull(p, &p, 0);
|
||||
parts[i].start = lldiv(start_ll, dev_desc->blksz);
|
||||
free(val);
|
||||
}
|
||||
|
||||
offset += parts[i].size + parts[i].start;
|
||||
|
||||
/* bootable */
|
||||
if (found_key(tok, "bootable"))
|
||||
parts[i].bootable = 1;
|
||||
}
|
||||
|
||||
*parts_count = p_count;
|
||||
*partitions = parts;
|
||||
free(str);
|
||||
|
||||
return 0;
|
||||
err:
|
||||
free(str);
|
||||
free(*str_disk_guid);
|
||||
free(parts);
|
||||
|
||||
return errno;
|
||||
}
|
||||
|
||||
static int gpt_default(struct blk_desc *blk_dev_desc, const char *str_part)
|
||||
{
|
||||
int ret;
|
||||
char *str_disk_guid;
|
||||
u8 part_count = 0;
|
||||
disk_partition_t *partitions = NULL;
|
||||
|
||||
/* fill partitions */
|
||||
ret = set_gpt_info(blk_dev_desc, str_part,
|
||||
&str_disk_guid, &partitions, &part_count);
|
||||
if (ret) {
|
||||
if (ret == -1)
|
||||
printf("No partition list provided\n");
|
||||
if (ret == -2)
|
||||
printf("Missing disk guid\n");
|
||||
if ((ret == -3) || (ret == -4))
|
||||
printf("Partition list incomplete\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* save partitions layout to disk */
|
||||
ret = gpt_restore(blk_dev_desc, str_disk_guid, partitions, part_count);
|
||||
free(str_disk_guid);
|
||||
free(partitions);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int gpt_verify(struct blk_desc *blk_dev_desc, const char *str_part)
|
||||
{
|
||||
ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1,
|
||||
blk_dev_desc->blksz);
|
||||
disk_partition_t *partitions = NULL;
|
||||
gpt_entry *gpt_pte = NULL;
|
||||
char *str_disk_guid;
|
||||
u8 part_count = 0;
|
||||
int ret = 0;
|
||||
|
||||
/* fill partitions */
|
||||
ret = set_gpt_info(blk_dev_desc, str_part,
|
||||
&str_disk_guid, &partitions, &part_count);
|
||||
if (ret) {
|
||||
if (ret == -1) {
|
||||
printf("No partition list provided - only basic check\n");
|
||||
ret = gpt_verify_headers(blk_dev_desc, gpt_head,
|
||||
&gpt_pte);
|
||||
goto out;
|
||||
}
|
||||
if (ret == -2)
|
||||
printf("Missing disk guid\n");
|
||||
if ((ret == -3) || (ret == -4))
|
||||
printf("Partition list incomplete\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check partition layout with provided pattern */
|
||||
ret = gpt_verify_partitions(blk_dev_desc, partitions, part_count,
|
||||
gpt_head, &gpt_pte);
|
||||
free(str_disk_guid);
|
||||
free(partitions);
|
||||
out:
|
||||
free(gpt_pte);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)
|
||||
{
|
||||
int ret;
|
||||
char disk_guid[UUID_STR_LEN + 1];
|
||||
|
||||
ret = get_disk_guid(dev_desc, disk_guid);
|
||||
if (ret < 0)
|
||||
return CMD_RET_FAILURE;
|
||||
|
||||
if (namestr)
|
||||
env_set(namestr, disk_guid);
|
||||
else
|
||||
printf("%s\n", disk_guid);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CMD_GPT_RENAME
|
||||
/*
|
||||
* There are 3 malloc() calls in set_gpt_info() and there is no info about which
|
||||
* failed.
|
||||
*/
|
||||
static void set_gpt_cleanup(char **str_disk_guid,
|
||||
disk_partition_t **partitions)
|
||||
{
|
||||
#ifdef CONFIG_RANDOM_UUID
|
||||
if (str_disk_guid)
|
||||
free(str_disk_guid);
|
||||
#endif
|
||||
if (partitions)
|
||||
free(partitions);
|
||||
}
|
||||
|
||||
static int do_rename_gpt_parts(struct blk_desc *dev_desc, char *subcomm,
|
||||
char *name1, char *name2)
|
||||
{
|
||||
struct list_head *pos;
|
||||
struct disk_part *curr;
|
||||
disk_partition_t *new_partitions = NULL;
|
||||
char disk_guid[UUID_STR_LEN + 1];
|
||||
char *partitions_list, *str_disk_guid;
|
||||
u8 part_count = 0;
|
||||
int partlistlen, ret, numparts = 0, partnum, i = 1, ctr1 = 0, ctr2 = 0;
|
||||
|
||||
if ((subcomm == NULL) || (name1 == NULL) || (name2 == NULL) ||
|
||||
(strcmp(subcomm, "swap") && (strcmp(subcomm, "rename"))))
|
||||
return -EINVAL;
|
||||
|
||||
ret = get_disk_guid(dev_desc, disk_guid);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
/*
|
||||
* Allocates disk_partitions, requiring matching call to del_gpt_info()
|
||||
* if successful.
|
||||
*/
|
||||
numparts = get_gpt_info(dev_desc);
|
||||
if (numparts <= 0)
|
||||
return numparts ? numparts : -ENODEV;
|
||||
|
||||
partlistlen = calc_parts_list_len(numparts);
|
||||
partitions_list = malloc(partlistlen);
|
||||
if (!partitions_list) {
|
||||
del_gpt_info();
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(partitions_list, '\0', partlistlen);
|
||||
|
||||
ret = create_gpt_partitions_list(numparts, disk_guid, partitions_list);
|
||||
if (ret < 0) {
|
||||
free(partitions_list);
|
||||
return ret;
|
||||
}
|
||||
/*
|
||||
* Uncomment the following line to print a string that 'gpt write'
|
||||
* or 'gpt verify' will accept as input.
|
||||
*/
|
||||
debug("OLD partitions_list is %s with %u chars\n", partitions_list,
|
||||
(unsigned)strlen(partitions_list));
|
||||
|
||||
/* set_gpt_info allocates new_partitions and str_disk_guid */
|
||||
ret = set_gpt_info(dev_desc, partitions_list, &str_disk_guid,
|
||||
&new_partitions, &part_count);
|
||||
if (ret < 0) {
|
||||
del_gpt_info();
|
||||
free(partitions_list);
|
||||
if (ret == -ENOMEM)
|
||||
set_gpt_cleanup(&str_disk_guid, &new_partitions);
|
||||
else
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!strcmp(subcomm, "swap")) {
|
||||
if ((strlen(name1) > PART_NAME_LEN) || (strlen(name2) > PART_NAME_LEN)) {
|
||||
printf("Names longer than %d characters are truncated.\n", PART_NAME_LEN);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
list_for_each(pos, &disk_partitions) {
|
||||
curr = list_entry(pos, struct disk_part, list);
|
||||
if (!strcmp((char *)curr->gpt_part_info.name, name1)) {
|
||||
strcpy((char *)curr->gpt_part_info.name, name2);
|
||||
ctr1++;
|
||||
} else if (!strcmp((char *)curr->gpt_part_info.name, name2)) {
|
||||
strcpy((char *)curr->gpt_part_info.name, name1);
|
||||
ctr2++;
|
||||
}
|
||||
}
|
||||
if ((ctr1 + ctr2 < 2) || (ctr1 != ctr2)) {
|
||||
printf("Cannot swap partition names except in pairs.\n");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
} else { /* rename */
|
||||
if (strlen(name2) > PART_NAME_LEN) {
|
||||
printf("Names longer than %d characters are truncated.\n", PART_NAME_LEN);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
partnum = (int)simple_strtol(name1, NULL, 10);
|
||||
if ((partnum < 0) || (partnum > numparts)) {
|
||||
printf("Illegal partition number %s\n", name1);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
ret = part_get_info(dev_desc, partnum, new_partitions);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
/* U-Boot partition numbering starts at 1 */
|
||||
list_for_each(pos, &disk_partitions) {
|
||||
curr = list_entry(pos, struct disk_part, list);
|
||||
if (i == partnum) {
|
||||
strcpy((char *)curr->gpt_part_info.name, name2);
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
ret = create_gpt_partitions_list(numparts, disk_guid, partitions_list);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
debug("NEW partitions_list is %s with %u chars\n", partitions_list,
|
||||
(unsigned)strlen(partitions_list));
|
||||
|
||||
ret = set_gpt_info(dev_desc, partitions_list, &str_disk_guid,
|
||||
&new_partitions, &part_count);
|
||||
/*
|
||||
* Even though valid pointers are here passed into set_gpt_info(),
|
||||
* it mallocs again, and there's no way to tell which failed.
|
||||
*/
|
||||
if (ret < 0) {
|
||||
del_gpt_info();
|
||||
free(partitions_list);
|
||||
if (ret == -ENOMEM)
|
||||
set_gpt_cleanup(&str_disk_guid, &new_partitions);
|
||||
else
|
||||
goto out;
|
||||
}
|
||||
|
||||
debug("Writing new partition table\n");
|
||||
ret = gpt_restore(dev_desc, disk_guid, new_partitions, numparts);
|
||||
if (ret < 0) {
|
||||
printf("Writing new partition table failed\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
debug("Reading back new partition table\n");
|
||||
/*
|
||||
* Empty the existing disk_partitions list, as otherwise the memory in
|
||||
* the original list is unreachable.
|
||||
*/
|
||||
del_gpt_info();
|
||||
numparts = get_gpt_info(dev_desc);
|
||||
if (numparts <= 0) {
|
||||
ret = numparts ? numparts : -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
printf("new partition table with %d partitions is:\n", numparts);
|
||||
print_gpt_info();
|
||||
del_gpt_info();
|
||||
out:
|
||||
free(new_partitions);
|
||||
free(str_disk_guid);
|
||||
free(partitions_list);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* do_gpt(): Perform GPT operations
|
||||
*
|
||||
* @param cmdtp - command name
|
||||
* @param flag
|
||||
* @param argc
|
||||
* @param argv
|
||||
*
|
||||
* @return zero on success; otherwise error
|
||||
*/
|
||||
static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
int ret = CMD_RET_SUCCESS;
|
||||
int dev = 0;
|
||||
char *ep;
|
||||
struct blk_desc *blk_dev_desc = NULL;
|
||||
|
||||
#ifndef CONFIG_CMD_GPT_RENAME
|
||||
if (argc < 4 || argc > 5)
|
||||
#else
|
||||
if (argc < 4 || argc > 6)
|
||||
#endif
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
dev = (int)simple_strtoul(argv[3], &ep, 10);
|
||||
if (!ep || ep[0] != '\0') {
|
||||
printf("'%s' is not a number\n", argv[3]);
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
blk_dev_desc = blk_get_dev(argv[2], dev);
|
||||
if (!blk_dev_desc) {
|
||||
printf("%s: %s dev %d NOT available\n",
|
||||
__func__, argv[2], dev);
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
if ((strcmp(argv[1], "write") == 0) && (argc == 5)) {
|
||||
printf("Writing GPT: ");
|
||||
ret = gpt_default(blk_dev_desc, argv[4]);
|
||||
} else if ((strcmp(argv[1], "verify") == 0)) {
|
||||
ret = gpt_verify(blk_dev_desc, argv[4]);
|
||||
printf("Verify GPT: ");
|
||||
} else if (strcmp(argv[1], "guid") == 0) {
|
||||
ret = do_disk_guid(blk_dev_desc, argv[4]);
|
||||
#ifdef CONFIG_CMD_GPT_RENAME
|
||||
} else if (strcmp(argv[1], "read") == 0) {
|
||||
ret = do_get_gpt_info(blk_dev_desc);
|
||||
} else if ((strcmp(argv[1], "swap") == 0) ||
|
||||
(strcmp(argv[1], "rename") == 0)) {
|
||||
ret = do_rename_gpt_parts(blk_dev_desc, argv[1], argv[4], argv[5]);
|
||||
#endif
|
||||
} else {
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
printf("error!\n");
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
printf("success!\n");
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
|
||||
"GUID Partition Table",
|
||||
"<command> <interface> <dev> <partitions_list>\n"
|
||||
" - GUID partition table restoration and validity check\n"
|
||||
" Restore or verify GPT information on a device connected\n"
|
||||
" to interface\n"
|
||||
" Example usage:\n"
|
||||
" gpt write mmc 0 $partitions\n"
|
||||
" gpt verify mmc 0 $partitions\n"
|
||||
" gpt guid <interface> <dev>\n"
|
||||
" - print disk GUID\n"
|
||||
" gpt guid <interface> <dev> <varname>\n"
|
||||
" - set environment variable to disk GUID\n"
|
||||
" Example usage:\n"
|
||||
" gpt guid mmc 0\n"
|
||||
" gpt guid mmc 0 varname\n"
|
||||
#ifdef CONFIG_CMD_GPT_RENAME
|
||||
"gpt partition renaming commands:\n"
|
||||
" gpt read <interface> <dev>\n"
|
||||
" - read GPT into a data structure for manipulation\n"
|
||||
" gpt swap <interface> <dev> <name1> <name2>\n"
|
||||
" - change all partitions named name1 to name2\n"
|
||||
" and vice-versa\n"
|
||||
" gpt rename <interface> <dev> <part> <name>\n"
|
||||
" - rename the specified partition\n"
|
||||
" Example usage:\n"
|
||||
" gpt swap mmc 0 foo bar\n"
|
||||
" gpt rename mmc 0 3 foo\n"
|
||||
#endif
|
||||
);
|
||||
55
cmd/hash.c
Normal file
55
cmd/hash.c
Normal file
@@ -0,0 +1,55 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2012 The Chromium OS Authors.
|
||||
*
|
||||
* (C) Copyright 2011
|
||||
* Joe Hershberger, National Instruments, joe.hershberger@ni.com
|
||||
*
|
||||
* (C) Copyright 2000
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <hash.h>
|
||||
#include <linux/ctype.h>
|
||||
|
||||
static int do_hash(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
char *s;
|
||||
int flags = HASH_FLAG_ENV;
|
||||
|
||||
#ifdef CONFIG_HASH_VERIFY
|
||||
if (argc < 4)
|
||||
return CMD_RET_USAGE;
|
||||
if (!strcmp(argv[1], "-v")) {
|
||||
flags |= HASH_FLAG_VERIFY;
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
#endif
|
||||
/* Move forward to 'algorithm' parameter */
|
||||
argc--;
|
||||
argv++;
|
||||
for (s = *argv; *s; s++)
|
||||
*s = tolower(*s);
|
||||
return hash_command(*argv, flags, cmdtp, flag, argc - 1, argv + 1);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HASH_VERIFY
|
||||
#define HARGS 6
|
||||
#else
|
||||
#define HARGS 5
|
||||
#endif
|
||||
|
||||
U_BOOT_CMD(
|
||||
hash, HARGS, 1, do_hash,
|
||||
"compute hash message digest",
|
||||
"algorithm address count [[*]hash_dest]\n"
|
||||
" - compute message digest [save to env var / *address]"
|
||||
#ifdef CONFIG_HASH_VERIFY
|
||||
"\nhash -v algorithm address count [*]hash\n"
|
||||
" - verify message digest of memory area to immediate value, \n"
|
||||
" env var or *address"
|
||||
#endif
|
||||
);
|
||||
39
cmd/help.c
Normal file
39
cmd/help.c
Normal file
@@ -0,0 +1,39 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2000-2009
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
|
||||
static int do_help(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
#ifdef CONFIG_CMDLINE
|
||||
cmd_tbl_t *start = ll_entry_start(cmd_tbl_t, cmd);
|
||||
const int len = ll_entry_count(cmd_tbl_t, cmd);
|
||||
return _do_help(start, len, cmdtp, flag, argc, argv);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
help, CONFIG_SYS_MAXARGS, 1, do_help,
|
||||
"print command description/usage",
|
||||
"\n"
|
||||
" - print brief description of all commands\n"
|
||||
"help command ...\n"
|
||||
" - print detailed usage of 'command'"
|
||||
);
|
||||
|
||||
#ifdef CONFIG_CMDLINE
|
||||
/* This does not use the U_BOOT_CMD macro as ? can't be used in symbol names */
|
||||
ll_entry_declare(cmd_tbl_t, question_mark, cmd) = {
|
||||
"?", CONFIG_SYS_MAXARGS, cmd_always_repeatable, do_help,
|
||||
"alias for 'help'",
|
||||
#ifdef CONFIG_SYS_LONGHELP
|
||||
""
|
||||
#endif /* CONFIG_SYS_LONGHELP */
|
||||
};
|
||||
#endif
|
||||
184
cmd/host.c
Normal file
184
cmd/host.c
Normal file
@@ -0,0 +1,184 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2012, Google Inc.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <fs.h>
|
||||
#include <part.h>
|
||||
#include <sandboxblockdev.h>
|
||||
#include <linux/errno.h>
|
||||
|
||||
static int host_curr_device = -1;
|
||||
|
||||
static int do_host_load(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
return do_load(cmdtp, flag, argc, argv, FS_TYPE_SANDBOX);
|
||||
}
|
||||
|
||||
static int do_host_ls(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
return do_ls(cmdtp, flag, argc, argv, FS_TYPE_SANDBOX);
|
||||
}
|
||||
|
||||
static int do_host_size(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
return do_size(cmdtp, flag, argc, argv, FS_TYPE_SANDBOX);
|
||||
}
|
||||
|
||||
static int do_host_save(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
return do_save(cmdtp, flag, argc, argv, FS_TYPE_SANDBOX);
|
||||
}
|
||||
|
||||
static int do_host_bind(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
if (argc < 2 || argc > 3)
|
||||
return CMD_RET_USAGE;
|
||||
char *ep;
|
||||
char *dev_str = argv[1];
|
||||
char *file = argc >= 3 ? argv[2] : NULL;
|
||||
int dev = simple_strtoul(dev_str, &ep, 16);
|
||||
if (*ep) {
|
||||
printf("** Bad device specification %s **\n", dev_str);
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
return host_dev_bind(dev, file);
|
||||
}
|
||||
|
||||
static int do_host_info(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
if (argc < 1 || argc > 2)
|
||||
return CMD_RET_USAGE;
|
||||
int min_dev = 0;
|
||||
int max_dev = CONFIG_HOST_MAX_DEVICES - 1;
|
||||
if (argc >= 2) {
|
||||
char *ep;
|
||||
char *dev_str = argv[1];
|
||||
int dev = simple_strtoul(dev_str, &ep, 16);
|
||||
if (*ep) {
|
||||
printf("** Bad device specification %s **\n", dev_str);
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
min_dev = dev;
|
||||
max_dev = dev;
|
||||
}
|
||||
int dev;
|
||||
printf("%3s %12s %s\n", "dev", "blocks", "path");
|
||||
for (dev = min_dev; dev <= max_dev; dev++) {
|
||||
struct blk_desc *blk_dev;
|
||||
int ret;
|
||||
|
||||
printf("%3d ", dev);
|
||||
ret = host_get_dev_err(dev, &blk_dev);
|
||||
if (ret) {
|
||||
if (ret == -ENOENT)
|
||||
puts("Not bound to a backing file\n");
|
||||
else if (ret == -ENODEV)
|
||||
puts("Invalid host device number\n");
|
||||
|
||||
continue;
|
||||
}
|
||||
struct host_block_dev *host_dev;
|
||||
|
||||
#ifdef CONFIG_BLK
|
||||
host_dev = dev_get_platdata(blk_dev->bdev);
|
||||
#else
|
||||
host_dev = blk_dev->priv;
|
||||
#endif
|
||||
printf("%12lu %s\n", (unsigned long)blk_dev->lba,
|
||||
host_dev->filename);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_host_dev(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
int dev;
|
||||
char *ep;
|
||||
struct blk_desc *blk_dev;
|
||||
int ret;
|
||||
|
||||
if (argc < 1 || argc > 3)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
if (argc == 1) {
|
||||
if (host_curr_device < 0) {
|
||||
printf("No current host device\n");
|
||||
return 1;
|
||||
}
|
||||
printf("Current host device %d\n", host_curr_device);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev = simple_strtoul(argv[1], &ep, 16);
|
||||
if (*ep) {
|
||||
printf("** Bad device specification %s **\n", argv[2]);
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
ret = host_get_dev_err(dev, &blk_dev);
|
||||
if (ret) {
|
||||
if (ret == -ENOENT)
|
||||
puts("Not bound to a backing file\n");
|
||||
else if (ret == -ENODEV)
|
||||
puts("Invalid host device number\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
host_curr_device = dev;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static cmd_tbl_t cmd_host_sub[] = {
|
||||
U_BOOT_CMD_MKENT(load, 7, 0, do_host_load, "", ""),
|
||||
U_BOOT_CMD_MKENT(ls, 3, 0, do_host_ls, "", ""),
|
||||
U_BOOT_CMD_MKENT(save, 6, 0, do_host_save, "", ""),
|
||||
U_BOOT_CMD_MKENT(size, 3, 0, do_host_size, "", ""),
|
||||
U_BOOT_CMD_MKENT(bind, 3, 0, do_host_bind, "", ""),
|
||||
U_BOOT_CMD_MKENT(info, 3, 0, do_host_info, "", ""),
|
||||
U_BOOT_CMD_MKENT(dev, 0, 1, do_host_dev, "", ""),
|
||||
};
|
||||
|
||||
static int do_host(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
cmd_tbl_t *c;
|
||||
|
||||
/* Skip past 'host' */
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
c = find_cmd_tbl(argv[0], cmd_host_sub,
|
||||
ARRAY_SIZE(cmd_host_sub));
|
||||
|
||||
if (c)
|
||||
return c->cmd(cmdtp, flag, argc, argv);
|
||||
else
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
host, 8, 1, do_host,
|
||||
"Miscellaneous host commands",
|
||||
"load hostfs - <addr> <filename> [<bytes> <offset>] - "
|
||||
"load a file from host\n"
|
||||
"host ls hostfs - <filename> - list files on host\n"
|
||||
"host save hostfs - <addr> <filename> <bytes> [<offset>] - "
|
||||
"save a file to host\n"
|
||||
"host size hostfs - <filename> - determine size of file on host\n"
|
||||
"host bind <dev> [<filename>] - bind \"host\" device to file\n"
|
||||
"host info [<dev>] - show device binding & info\n"
|
||||
"host dev [<dev>] - Set or retrieve the current host device\n"
|
||||
"host commands use the \"hostfs\" device. The \"host\" device is used\n"
|
||||
"with standard IO commands such as fatls or ext2load"
|
||||
);
|
||||
60
cmd/ide.c
Normal file
60
cmd/ide.c
Normal file
@@ -0,0 +1,60 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2000-2011
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*/
|
||||
|
||||
/*
|
||||
* IDE support
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <blk.h>
|
||||
#include <config.h>
|
||||
#include <watchdog.h>
|
||||
#include <command.h>
|
||||
#include <image.h>
|
||||
#include <asm/byteorder.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include <ide.h>
|
||||
#include <ata.h>
|
||||
|
||||
#ifdef CONFIG_LED_STATUS
|
||||
# include <status_led.h>
|
||||
#endif
|
||||
|
||||
/* Current I/O Device */
|
||||
static int curr_device;
|
||||
|
||||
int do_ide(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
|
||||
{
|
||||
if (argc == 2) {
|
||||
if (strncmp(argv[1], "res", 3) == 0) {
|
||||
puts("\nReset IDE: ");
|
||||
ide_init();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return blk_common_cmd(argc, argv, IF_TYPE_IDE, &curr_device);
|
||||
}
|
||||
|
||||
int do_diskboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
|
||||
{
|
||||
return common_diskboot(cmdtp, "ide", argc, argv);
|
||||
}
|
||||
|
||||
U_BOOT_CMD(ide, 5, 1, do_ide,
|
||||
"IDE sub-system",
|
||||
"reset - reset IDE controller\n"
|
||||
"ide info - show available IDE devices\n"
|
||||
"ide device [dev] - show or set current device\n"
|
||||
"ide part [dev] - print partition table of one or all IDE devices\n"
|
||||
"ide read addr blk# cnt\n"
|
||||
"ide write addr blk# cnt - read/write `cnt'"
|
||||
" blocks starting at block `blk#'\n"
|
||||
" to/from memory address `addr'");
|
||||
|
||||
U_BOOT_CMD(diskboot, 3, 1, do_diskboot,
|
||||
"boot from IDE device", "loadAddr dev:part");
|
||||
251
cmd/ini.c
Normal file
251
cmd/ini.c
Normal file
@@ -0,0 +1,251 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
/*
|
||||
* inih -- simple .INI file parser
|
||||
*
|
||||
* Copyright (c) 2009, Brush Technology
|
||||
* Copyright (c) 2012:
|
||||
* Joe Hershberger, National Instruments, joe.hershberger@ni.com
|
||||
* All rights reserved.
|
||||
*
|
||||
* Go to the project home page for more info:
|
||||
* http://code.google.com/p/inih/
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <env.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#ifdef CONFIG_INI_MAX_LINE
|
||||
#define MAX_LINE CONFIG_INI_MAX_LINE
|
||||
#else
|
||||
#define MAX_LINE 200
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_INI_MAX_SECTION
|
||||
#define MAX_SECTION CONFIG_INI_MAX_SECTION
|
||||
#else
|
||||
#define MAX_SECTION 50
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_INI_MAX_NAME
|
||||
#define MAX_NAME CONFIG_INI_MAX_NAME
|
||||
#else
|
||||
#define MAX_NAME 50
|
||||
#endif
|
||||
|
||||
/* Strip whitespace chars off end of given string, in place. Return s. */
|
||||
static char *rstrip(char *s)
|
||||
{
|
||||
char *p = s + strlen(s);
|
||||
|
||||
while (p > s && isspace(*--p))
|
||||
*p = '\0';
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Return pointer to first non-whitespace char in given string. */
|
||||
static char *lskip(const char *s)
|
||||
{
|
||||
while (*s && isspace(*s))
|
||||
s++;
|
||||
return (char *)s;
|
||||
}
|
||||
|
||||
/* Return pointer to first char c or ';' comment in given string, or pointer to
|
||||
null at end of string if neither found. ';' must be prefixed by a whitespace
|
||||
character to register as a comment. */
|
||||
static char *find_char_or_comment(const char *s, char c)
|
||||
{
|
||||
int was_whitespace = 0;
|
||||
|
||||
while (*s && *s != c && !(was_whitespace && *s == ';')) {
|
||||
was_whitespace = isspace(*s);
|
||||
s++;
|
||||
}
|
||||
return (char *)s;
|
||||
}
|
||||
|
||||
/* Version of strncpy that ensures dest (size bytes) is null-terminated. */
|
||||
static char *strncpy0(char *dest, const char *src, size_t size)
|
||||
{
|
||||
strncpy(dest, src, size);
|
||||
dest[size - 1] = '\0';
|
||||
return dest;
|
||||
}
|
||||
|
||||
/* Emulate the behavior of fgets but on memory */
|
||||
static char *memgets(char *str, int num, char **mem, size_t *memsize)
|
||||
{
|
||||
char *end;
|
||||
int len;
|
||||
int newline = 1;
|
||||
|
||||
end = memchr(*mem, '\n', *memsize);
|
||||
if (end == NULL) {
|
||||
if (*memsize == 0)
|
||||
return NULL;
|
||||
end = *mem + *memsize;
|
||||
newline = 0;
|
||||
}
|
||||
len = min((end - *mem) + newline, num);
|
||||
memcpy(str, *mem, len);
|
||||
if (len < num)
|
||||
str[len] = '\0';
|
||||
|
||||
/* prepare the mem vars for the next call */
|
||||
*memsize -= (end - *mem) + newline;
|
||||
*mem += (end - *mem) + newline;
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/* Parse given INI-style file. May have [section]s, name=value pairs
|
||||
(whitespace stripped), and comments starting with ';' (semicolon). Section
|
||||
is "" if name=value pair parsed before any section heading. name:value
|
||||
pairs are also supported as a concession to Python's ConfigParser.
|
||||
|
||||
For each name=value pair parsed, call handler function with given user
|
||||
pointer as well as section, name, and value (data only valid for duration
|
||||
of handler call). Handler should return nonzero on success, zero on error.
|
||||
|
||||
Returns 0 on success, line number of first error on parse error (doesn't
|
||||
stop on first error).
|
||||
*/
|
||||
static int ini_parse(char *filestart, size_t filelen,
|
||||
int (*handler)(void *, char *, char *, char *), void *user)
|
||||
{
|
||||
/* Uses a fair bit of stack (use heap instead if you need to) */
|
||||
char line[MAX_LINE];
|
||||
char section[MAX_SECTION] = "";
|
||||
char prev_name[MAX_NAME] = "";
|
||||
|
||||
char *curmem = filestart;
|
||||
char *start;
|
||||
char *end;
|
||||
char *name;
|
||||
char *value;
|
||||
size_t memleft = filelen;
|
||||
int lineno = 0;
|
||||
int error = 0;
|
||||
|
||||
/* Scan through file line by line */
|
||||
while (memgets(line, sizeof(line), &curmem, &memleft) != NULL) {
|
||||
lineno++;
|
||||
start = lskip(rstrip(line));
|
||||
|
||||
if (*start == ';' || *start == '#') {
|
||||
/*
|
||||
* Per Python ConfigParser, allow '#' comments at start
|
||||
* of line
|
||||
*/
|
||||
}
|
||||
#if CONFIG_INI_ALLOW_MULTILINE
|
||||
else if (*prev_name && *start && start > line) {
|
||||
/*
|
||||
* Non-blank line with leading whitespace, treat as
|
||||
* continuation of previous name's value (as per Python
|
||||
* ConfigParser).
|
||||
*/
|
||||
if (!handler(user, section, prev_name, start) && !error)
|
||||
error = lineno;
|
||||
}
|
||||
#endif
|
||||
else if (*start == '[') {
|
||||
/* A "[section]" line */
|
||||
end = find_char_or_comment(start + 1, ']');
|
||||
if (*end == ']') {
|
||||
*end = '\0';
|
||||
strncpy0(section, start + 1, sizeof(section));
|
||||
*prev_name = '\0';
|
||||
} else if (!error) {
|
||||
/* No ']' found on section line */
|
||||
error = lineno;
|
||||
}
|
||||
} else if (*start && *start != ';') {
|
||||
/* Not a comment, must be a name[=:]value pair */
|
||||
end = find_char_or_comment(start, '=');
|
||||
if (*end != '=')
|
||||
end = find_char_or_comment(start, ':');
|
||||
if (*end == '=' || *end == ':') {
|
||||
*end = '\0';
|
||||
name = rstrip(start);
|
||||
value = lskip(end + 1);
|
||||
end = find_char_or_comment(value, '\0');
|
||||
if (*end == ';')
|
||||
*end = '\0';
|
||||
rstrip(value);
|
||||
/* Strip double-quotes */
|
||||
if (value[0] == '"' &&
|
||||
value[strlen(value)-1] == '"') {
|
||||
value[strlen(value)-1] = '\0';
|
||||
value += 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Valid name[=:]value pair found, call handler
|
||||
*/
|
||||
strncpy0(prev_name, name, sizeof(prev_name));
|
||||
if (!handler(user, section, name, value) &&
|
||||
!error)
|
||||
error = lineno;
|
||||
} else if (!error)
|
||||
/* No '=' or ':' found on name[=:]value line */
|
||||
error = lineno;
|
||||
}
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int ini_handler(void *user, char *section, char *name, char *value)
|
||||
{
|
||||
char *requested_section = (char *)user;
|
||||
#ifdef CONFIG_INI_CASE_INSENSITIVE
|
||||
int i;
|
||||
|
||||
for (i = 0; i < strlen(requested_section); i++)
|
||||
requested_section[i] = tolower(requested_section[i]);
|
||||
for (i = 0; i < strlen(section); i++)
|
||||
section[i] = tolower(section[i]);
|
||||
#endif
|
||||
|
||||
if (!strcmp(section, requested_section)) {
|
||||
#ifdef CONFIG_INI_CASE_INSENSITIVE
|
||||
for (i = 0; i < strlen(name); i++)
|
||||
name[i] = tolower(name[i]);
|
||||
for (i = 0; i < strlen(value); i++)
|
||||
value[i] = tolower(value[i]);
|
||||
#endif
|
||||
env_set(name, value);
|
||||
printf("ini: Imported %s as %s\n", name, value);
|
||||
}
|
||||
|
||||
/* success */
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int do_ini(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
const char *section;
|
||||
char *file_address;
|
||||
size_t file_size;
|
||||
|
||||
if (argc == 1)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
section = argv[1];
|
||||
file_address = (char *)simple_strtoul(
|
||||
argc < 3 ? env_get("loadaddr") : argv[2], NULL, 16);
|
||||
file_size = (size_t)simple_strtoul(
|
||||
argc < 4 ? env_get("filesize") : argv[3], NULL, 16);
|
||||
|
||||
return ini_parse(file_address, file_size, ini_handler, (void *)section);
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
ini, 4, 0, do_ini,
|
||||
"parse an ini file in memory and merge the specified section into the env",
|
||||
"section [[file-address] file-size]"
|
||||
);
|
||||
124
cmd/io.c
Normal file
124
cmd/io.c
Normal file
@@ -0,0 +1,124 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2012 The Chromium OS Authors.
|
||||
*/
|
||||
|
||||
/*
|
||||
* IO space access commands.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
/* Display values from last command */
|
||||
static ulong last_addr, last_size;
|
||||
static ulong last_length = 0x40;
|
||||
static ulong base_address;
|
||||
|
||||
#define DISP_LINE_LEN 16
|
||||
|
||||
/*
|
||||
* IO Display
|
||||
*
|
||||
* Syntax:
|
||||
* iod{.b, .w, .l} {addr}
|
||||
*/
|
||||
int do_io_iod(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
|
||||
{
|
||||
ulong addr, length, bytes;
|
||||
u8 buf[DISP_LINE_LEN];
|
||||
int size, todo;
|
||||
|
||||
/*
|
||||
* We use the last specified parameters, unless new ones are
|
||||
* entered.
|
||||
*/
|
||||
addr = last_addr;
|
||||
size = last_size;
|
||||
length = last_length;
|
||||
|
||||
if (argc < 2)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
if ((flag & CMD_FLAG_REPEAT) == 0) {
|
||||
/*
|
||||
* New command specified. Check for a size specification.
|
||||
* Defaults to long if no or incorrect specification.
|
||||
*/
|
||||
size = cmd_get_data_size(argv[0], 4);
|
||||
if (size < 0)
|
||||
return 1;
|
||||
|
||||
/* Address is specified since argc > 1 */
|
||||
addr = simple_strtoul(argv[1], NULL, 16);
|
||||
addr += base_address;
|
||||
|
||||
/*
|
||||
* If another parameter, it is the length to display.
|
||||
* Length is the number of objects, not number of bytes.
|
||||
*/
|
||||
if (argc > 2)
|
||||
length = simple_strtoul(argv[2], NULL, 16);
|
||||
}
|
||||
|
||||
bytes = size * length;
|
||||
|
||||
/* Print the lines */
|
||||
for (; bytes > 0; addr += todo) {
|
||||
u8 *ptr = buf;
|
||||
int i;
|
||||
|
||||
todo = min(bytes, (ulong)DISP_LINE_LEN);
|
||||
for (i = 0; i < todo; i += size, ptr += size) {
|
||||
if (size == 4)
|
||||
*(u32 *)ptr = inl(addr + i);
|
||||
else if (size == 2)
|
||||
*(u16 *)ptr = inw(addr + i);
|
||||
else
|
||||
*ptr = inb(addr + i);
|
||||
}
|
||||
print_buffer(addr, buf, size, todo / size,
|
||||
DISP_LINE_LEN / size);
|
||||
bytes -= todo;
|
||||
}
|
||||
|
||||
last_addr = addr;
|
||||
last_length = length;
|
||||
last_size = size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int do_io_iow(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
|
||||
{
|
||||
ulong addr, val;
|
||||
int size;
|
||||
|
||||
if (argc != 3)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
size = cmd_get_data_size(argv[0], 4);
|
||||
if (size < 0)
|
||||
return 1;
|
||||
|
||||
addr = simple_strtoul(argv[1], NULL, 16);
|
||||
val = simple_strtoul(argv[2], NULL, 16);
|
||||
|
||||
if (size == 4)
|
||||
outl((u32) val, addr);
|
||||
else if (size == 2)
|
||||
outw((u16) val, addr);
|
||||
else
|
||||
outb((u8) val, addr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**************************************************/
|
||||
U_BOOT_CMD(iod, 3, 1, do_io_iod,
|
||||
"IO space display", "[.b, .w, .l] address");
|
||||
|
||||
U_BOOT_CMD(iow, 3, 0, do_io_iow,
|
||||
"IO space modify",
|
||||
"[.b, .w, .l] address value");
|
||||
129
cmd/iotrace.c
Normal file
129
cmd/iotrace.c
Normal file
@@ -0,0 +1,129 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2014 Google, Inc
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <iotrace.h>
|
||||
|
||||
static void do_print_stats(void)
|
||||
{
|
||||
ulong start, size, needed_size, offset, count;
|
||||
|
||||
printf("iotrace is %sabled\n", iotrace_get_enabled() ? "en" : "dis");
|
||||
iotrace_get_buffer(&start, &size, &needed_size, &offset, &count);
|
||||
printf("Start: %08lx\n", start);
|
||||
printf("Actual Size: %08lx\n", size);
|
||||
printf("Needed Size: %08lx\n", needed_size);
|
||||
iotrace_get_region(&start, &size);
|
||||
printf("Region: %08lx\n", start);
|
||||
printf("Size: %08lx\n", size);
|
||||
printf("Offset: %08lx\n", offset);
|
||||
printf("Output: %08lx\n", start + offset);
|
||||
printf("Count: %08lx\n", count);
|
||||
printf("CRC32: %08lx\n", (ulong)iotrace_get_checksum());
|
||||
}
|
||||
|
||||
static void do_print_trace(void)
|
||||
{
|
||||
ulong start, size, needed_size, offset, count;
|
||||
|
||||
struct iotrace_record *cur_record;
|
||||
|
||||
iotrace_get_buffer(&start, &size, &needed_size, &offset, &count);
|
||||
|
||||
if (!start || !size || !count)
|
||||
return;
|
||||
|
||||
printf("Timestamp Value Address\n");
|
||||
|
||||
cur_record = (struct iotrace_record *)start;
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (cur_record->flags & IOT_WRITE)
|
||||
printf("%08llu: 0x%08lx --> 0x%08llx\n",
|
||||
cur_record->timestamp,
|
||||
cur_record->value,
|
||||
(unsigned long long)cur_record->addr);
|
||||
else
|
||||
printf("%08llu: 0x%08lx <-- 0x%08llx\n",
|
||||
cur_record->timestamp,
|
||||
cur_record->value,
|
||||
(unsigned long long)cur_record->addr);
|
||||
|
||||
cur_record++;
|
||||
}
|
||||
}
|
||||
|
||||
static int do_set_buffer(int argc, char * const argv[])
|
||||
{
|
||||
ulong addr = 0, size = 0;
|
||||
|
||||
if (argc == 2) {
|
||||
addr = simple_strtoul(*argv++, NULL, 16);
|
||||
size = simple_strtoul(*argv++, NULL, 16);
|
||||
} else if (argc != 0) {
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
iotrace_set_buffer(addr, size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_set_region(int argc, char * const argv[])
|
||||
{
|
||||
ulong addr = 0, size = 0;
|
||||
|
||||
if (argc == 2) {
|
||||
addr = simple_strtoul(*argv++, NULL, 16);
|
||||
size = simple_strtoul(*argv++, NULL, 16);
|
||||
} else if (argc != 0) {
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
iotrace_set_region(addr, size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int do_iotrace(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
const char *cmd = argc < 2 ? NULL : argv[1];
|
||||
|
||||
if (!cmd)
|
||||
return cmd_usage(cmdtp);
|
||||
switch (*cmd) {
|
||||
case 'b':
|
||||
return do_set_buffer(argc - 2, argv + 2);
|
||||
case 'l':
|
||||
return do_set_region(argc - 2, argv + 2);
|
||||
case 'p':
|
||||
iotrace_set_enabled(0);
|
||||
break;
|
||||
case 'r':
|
||||
iotrace_set_enabled(1);
|
||||
break;
|
||||
case 's':
|
||||
do_print_stats();
|
||||
break;
|
||||
case 'd':
|
||||
do_print_trace();
|
||||
break;
|
||||
default:
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
iotrace, 4, 1, do_iotrace,
|
||||
"iotrace utility commands",
|
||||
"stats - display iotrace stats\n"
|
||||
"iotrace buffer <address> <size> - set iotrace buffer\n"
|
||||
"iotrace limit <address> <size> - set iotrace region limit\n"
|
||||
"iotrace pause - pause tracing\n"
|
||||
"iotrace resume - resume tracing\n"
|
||||
"iotrace dump - dump iotrace buffer"
|
||||
);
|
||||
40
cmd/irq.c
Normal file
40
cmd/irq.c
Normal file
@@ -0,0 +1,40 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2008 Freescale Semiconductor, Inc.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <config.h>
|
||||
#include <command.h>
|
||||
#include <irq_func.h>
|
||||
|
||||
static int do_interrupts(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
|
||||
if (argc != 2)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
/* on */
|
||||
if (strncmp(argv[1], "on", 2) == 0)
|
||||
enable_interrupts();
|
||||
else
|
||||
disable_interrupts();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
interrupts, 5, 0, do_interrupts,
|
||||
"enable or disable interrupts",
|
||||
"[on, off]"
|
||||
);
|
||||
|
||||
/* Implemented in $(CPU)/interrupts.c */
|
||||
int do_irqinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
|
||||
|
||||
U_BOOT_CMD(
|
||||
irqinfo, 1, 1, do_irqinfo,
|
||||
"print information about IRQs",
|
||||
""
|
||||
);
|
||||
220
cmd/itest.c
Normal file
220
cmd/itest.c
Normal file
@@ -0,0 +1,220 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2003
|
||||
* Tait Electronics Limited, Christchurch, New Zealand
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file provides a shell like 'test' function to return
|
||||
* true/false from an integer or string compare of two memory
|
||||
* locations or a location and a scalar/literal.
|
||||
* A few parts were lifted from bash 'test' command
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <config.h>
|
||||
#include <command.h>
|
||||
#include <env.h>
|
||||
#include <mapmem.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
#define EQ 0
|
||||
#define NE 1
|
||||
#define LT 2
|
||||
#define GT 3
|
||||
#define LE 4
|
||||
#define GE 5
|
||||
|
||||
struct op_tbl_s {
|
||||
char *op; /* operator string */
|
||||
int opcode; /* internal representation of opcode */
|
||||
};
|
||||
|
||||
typedef struct op_tbl_s op_tbl_t;
|
||||
|
||||
static const op_tbl_t op_table [] = {
|
||||
{ "-lt", LT },
|
||||
{ "<" , LT },
|
||||
{ "-gt", GT },
|
||||
{ ">" , GT },
|
||||
{ "-eq", EQ },
|
||||
{ "==" , EQ },
|
||||
{ "-ne", NE },
|
||||
{ "!=" , NE },
|
||||
{ "<>" , NE },
|
||||
{ "-ge", GE },
|
||||
{ ">=" , GE },
|
||||
{ "-le", LE },
|
||||
{ "<=" , LE },
|
||||
};
|
||||
|
||||
static long evalexp(char *s, int w)
|
||||
{
|
||||
long l = 0;
|
||||
unsigned long addr;
|
||||
void *buf;
|
||||
|
||||
/* if the parameter starts with a * then assume is a pointer to the value we want */
|
||||
if (s[0] == '*') {
|
||||
addr = simple_strtoul(&s[1], NULL, 16);
|
||||
buf = map_physmem(addr, w, MAP_WRBACK);
|
||||
if (!buf && addr) {
|
||||
puts("Failed to map physical memory\n");
|
||||
return 0;
|
||||
}
|
||||
switch (w) {
|
||||
case 1:
|
||||
l = (long)(*(u8 *)buf);
|
||||
break;
|
||||
case 2:
|
||||
l = (long)(*(u16 *)buf);
|
||||
break;
|
||||
case 4:
|
||||
l = (long)(*(u32 *)buf);
|
||||
break;
|
||||
#ifdef CONFIG_PHYS_64BIT
|
||||
case 8:
|
||||
l = (long)(*(unsigned long *)buf);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
unmap_physmem(buf, w);
|
||||
return l;
|
||||
} else {
|
||||
l = simple_strtoul(s, NULL, 16);
|
||||
}
|
||||
|
||||
/* avoid overflow on mask calculus */
|
||||
return (w >= sizeof(long)) ? l : (l & ((1UL << (w * 8)) - 1));
|
||||
}
|
||||
|
||||
static char * evalstr(char *s)
|
||||
{
|
||||
/* if the parameter starts with a * then assume a string pointer else its a literal */
|
||||
if (s[0] == '*') {
|
||||
return (char *)simple_strtoul(&s[1], NULL, 16);
|
||||
} else if (s[0] == '$') {
|
||||
int i = 2;
|
||||
|
||||
if (s[1] != '{')
|
||||
return NULL;
|
||||
|
||||
while (s[i] != '}') {
|
||||
if (s[i] == 0)
|
||||
return NULL;
|
||||
i++;
|
||||
}
|
||||
s[i] = 0;
|
||||
return env_get((const char *)&s[2]);
|
||||
} else {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
static int stringcomp(char *s, char *t, int op)
|
||||
{
|
||||
int p;
|
||||
char *l, *r;
|
||||
|
||||
l = evalstr(s);
|
||||
r = evalstr(t);
|
||||
|
||||
p = strcmp(l, r);
|
||||
switch (op) {
|
||||
case EQ: return (p == 0);
|
||||
case NE: return (p != 0);
|
||||
case LT: return (p < 0);
|
||||
case GT: return (p > 0);
|
||||
case LE: return (p <= 0);
|
||||
case GE: return (p >= 0);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int arithcomp (char *s, char *t, int op, int w)
|
||||
{
|
||||
long l, r;
|
||||
|
||||
l = evalexp (s, w);
|
||||
r = evalexp (t, w);
|
||||
|
||||
switch (op) {
|
||||
case EQ: return (l == r);
|
||||
case NE: return (l != r);
|
||||
case LT: return (l < r);
|
||||
case GT: return (l > r);
|
||||
case LE: return (l <= r);
|
||||
case GE: return (l >= r);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int binary_test(char *op, char *arg1, char *arg2, int w)
|
||||
{
|
||||
int len, i;
|
||||
const op_tbl_t *optp;
|
||||
|
||||
len = strlen(op);
|
||||
|
||||
for (optp = (op_tbl_t *)&op_table, i = 0;
|
||||
i < ARRAY_SIZE(op_table);
|
||||
optp++, i++) {
|
||||
|
||||
if ((strncmp (op, optp->op, len) == 0) && (len == strlen (optp->op))) {
|
||||
if (w == 0) {
|
||||
return (stringcomp(arg1, arg2, optp->opcode));
|
||||
} else {
|
||||
return (arithcomp (arg1, arg2, optp->opcode, w));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf("Unknown operator '%s'\n", op);
|
||||
return 0; /* op code not found */
|
||||
}
|
||||
|
||||
/* command line interface to the shell test */
|
||||
static int do_itest(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
int value, w;
|
||||
|
||||
/* Validate arguments */
|
||||
if ((argc != 4))
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
/* Check for a data width specification.
|
||||
* Defaults to long (4) if no specification.
|
||||
* Uses -2 as 'width' for .s (string) so as not to upset existing code
|
||||
*/
|
||||
switch (w = cmd_get_data_size(argv[0], 4)) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
#ifdef CONFIG_PHYS_64BIT
|
||||
case 8:
|
||||
#endif
|
||||
value = binary_test (argv[2], argv[1], argv[3], w);
|
||||
break;
|
||||
case -2:
|
||||
value = binary_test (argv[2], argv[1], argv[3], 0);
|
||||
break;
|
||||
case -1:
|
||||
default:
|
||||
puts("Invalid data width specifier\n");
|
||||
value = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return !value;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
itest, 4, 0, do_itest,
|
||||
"return true/false on integer compare",
|
||||
#ifdef CONFIG_PHYS_64BIT
|
||||
"[.b, .w, .l, .q, .s] [*]value1 <op> [*]value2"
|
||||
#else
|
||||
"[.b, .w, .l, .s] [*]value1 <op> [*]value2"
|
||||
#endif
|
||||
);
|
||||
620
cmd/jffs2.c
Normal file
620
cmd/jffs2.c
Normal file
@@ -0,0 +1,620 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2002
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Robert Schwebel, Pengutronix, <r.schwebel@pengutronix.de>
|
||||
*
|
||||
* (C) Copyright 2003
|
||||
* Kai-Uwe Bloem, Auerswald GmbH & Co KG, <linux-development@auerswald.de>
|
||||
*
|
||||
* (C) Copyright 2005
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*
|
||||
* Added support for reading flash partition table from environment.
|
||||
* Parsing routines are based on driver/mtd/cmdline.c from the linux 2.4
|
||||
* kernel tree.
|
||||
*
|
||||
* $Id: cmdlinepart.c,v 1.17 2004/11/26 11:18:47 lavinen Exp $
|
||||
* Copyright 2002 SYSGO Real-Time Solutions GmbH
|
||||
*/
|
||||
|
||||
/*
|
||||
* Three environment variables are used by the parsing routines:
|
||||
*
|
||||
* 'partition' - keeps current partition identifier
|
||||
*
|
||||
* partition := <part-id>
|
||||
* <part-id> := <dev-id>,part_num
|
||||
*
|
||||
*
|
||||
* 'mtdids' - linux kernel mtd device id <-> u-boot device id mapping
|
||||
*
|
||||
* mtdids=<idmap>[,<idmap>,...]
|
||||
*
|
||||
* <idmap> := <dev-id>=<mtd-id>
|
||||
* <dev-id> := 'nand'|'nor'|'onenand'<dev-num>
|
||||
* <dev-num> := mtd device number, 0...
|
||||
* <mtd-id> := unique device tag used by linux kernel to find mtd device (mtd->name)
|
||||
*
|
||||
*
|
||||
* 'mtdparts' - partition list
|
||||
*
|
||||
* mtdparts=mtdparts=<mtd-def>[;<mtd-def>...]
|
||||
*
|
||||
* <mtd-def> := <mtd-id>:<part-def>[,<part-def>...]
|
||||
* <mtd-id> := unique device tag used by linux kernel to find mtd device (mtd->name)
|
||||
* <part-def> := <size>[@<offset>][<name>][<ro-flag>]
|
||||
* <size> := standard linux memsize OR '-' to denote all remaining space
|
||||
* <offset> := partition start offset within the device
|
||||
* <name> := '(' NAME ')'
|
||||
* <ro-flag> := when set to 'ro' makes partition read-only (not used, passed to kernel)
|
||||
*
|
||||
* Notes:
|
||||
* - each <mtd-id> used in mtdparts must albo exist in 'mtddis' mapping
|
||||
* - if the above variables are not set defaults for a given target are used
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* 1 NOR Flash, with 1 single writable partition:
|
||||
* mtdids=nor0=edb7312-nor
|
||||
* mtdparts=mtdparts=edb7312-nor:-
|
||||
*
|
||||
* 1 NOR Flash with 2 partitions, 1 NAND with one
|
||||
* mtdids=nor0=edb7312-nor,nand0=edb7312-nand
|
||||
* mtdparts=mtdparts=edb7312-nor:256k(ARMboot)ro,-(root);edb7312-nand:-(home)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* JFFS2/CRAMFS support
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <env.h>
|
||||
#include <malloc.h>
|
||||
#include <jffs2/jffs2.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <cramfs/cramfs_fs.h>
|
||||
|
||||
#if defined(CONFIG_CMD_NAND)
|
||||
#include <linux/mtd/rawnand.h>
|
||||
#include <nand.h>
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_CMD_ONENAND)
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/onenand.h>
|
||||
#include <onenand_uboot.h>
|
||||
#endif
|
||||
|
||||
/* enable/disable debugging messages */
|
||||
#define DEBUG_JFFS
|
||||
#undef DEBUG_JFFS
|
||||
|
||||
#ifdef DEBUG_JFFS
|
||||
# define DEBUGF(fmt, args...) printf(fmt ,##args)
|
||||
#else
|
||||
# define DEBUGF(fmt, args...)
|
||||
#endif
|
||||
|
||||
/* special size referring to all the remaining space in a partition */
|
||||
#define SIZE_REMAINING 0xFFFFFFFF
|
||||
|
||||
/* special offset value, it is used when not provided by user
|
||||
*
|
||||
* this value is used temporarily during parsing, later such offests
|
||||
* are recalculated */
|
||||
#define OFFSET_NOT_SPECIFIED 0xFFFFFFFF
|
||||
|
||||
/* minimum partition size */
|
||||
#define MIN_PART_SIZE 4096
|
||||
|
||||
/* this flag needs to be set in part_info struct mask_flags
|
||||
* field for read-only partitions */
|
||||
#define MTD_WRITEABLE_CMD 1
|
||||
|
||||
/* current active device and partition number */
|
||||
#ifdef CONFIG_CMD_MTDPARTS
|
||||
/* Use the ones declared in cmd_mtdparts.c */
|
||||
extern struct mtd_device *current_mtd_dev;
|
||||
extern u8 current_mtd_partnum;
|
||||
#else
|
||||
/* Use local ones */
|
||||
struct mtd_device *current_mtd_dev = NULL;
|
||||
u8 current_mtd_partnum = 0;
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_CMD_CRAMFS)
|
||||
extern int cramfs_check (struct part_info *info);
|
||||
extern int cramfs_load (char *loadoffset, struct part_info *info, char *filename);
|
||||
extern int cramfs_ls (struct part_info *info, char *filename);
|
||||
extern int cramfs_info (struct part_info *info);
|
||||
#else
|
||||
/* defining empty macros for function names is ugly but avoids ifdef clutter
|
||||
* all over the code */
|
||||
#define cramfs_check(x) (0)
|
||||
#define cramfs_load(x,y,z) (-1)
|
||||
#define cramfs_ls(x,y) (0)
|
||||
#define cramfs_info(x) (0)
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_CMD_MTDPARTS
|
||||
/**
|
||||
* Check device number to be within valid range for given device type.
|
||||
*
|
||||
* @param dev device to validate
|
||||
* @return 0 if device is valid, 1 otherwise
|
||||
*/
|
||||
static int mtd_device_validate(u8 type, u8 num, u32 *size)
|
||||
{
|
||||
if (type == MTD_DEV_TYPE_NOR) {
|
||||
#if defined(CONFIG_CMD_FLASH)
|
||||
if (num < CONFIG_SYS_MAX_FLASH_BANKS) {
|
||||
extern flash_info_t flash_info[];
|
||||
*size = flash_info[num].size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("no such FLASH device: %s%d (valid range 0 ... %d\n",
|
||||
MTD_DEV_TYPE(type), num, CONFIG_SYS_MAX_FLASH_BANKS - 1);
|
||||
#else
|
||||
printf("support for FLASH devices not present\n");
|
||||
#endif
|
||||
} else if (type == MTD_DEV_TYPE_NAND) {
|
||||
#if defined(CONFIG_JFFS2_NAND) && defined(CONFIG_CMD_NAND)
|
||||
struct mtd_info *mtd = get_nand_dev_by_index(num);
|
||||
if (mtd) {
|
||||
*size = mtd->size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("no such NAND device: %s%d (valid range 0 ... %d)\n",
|
||||
MTD_DEV_TYPE(type), num, CONFIG_SYS_MAX_NAND_DEVICE - 1);
|
||||
#else
|
||||
printf("support for NAND devices not present\n");
|
||||
#endif
|
||||
} else if (type == MTD_DEV_TYPE_ONENAND) {
|
||||
#if defined(CONFIG_CMD_ONENAND)
|
||||
*size = onenand_mtd.size;
|
||||
return 0;
|
||||
#else
|
||||
printf("support for OneNAND devices not present\n");
|
||||
#endif
|
||||
} else
|
||||
printf("Unknown defice type %d\n", type);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse device id string <dev-id> := 'nand'|'nor'|'onenand'<dev-num>,
|
||||
* return device type and number.
|
||||
*
|
||||
* @param id string describing device id
|
||||
* @param ret_id output pointer to next char after parse completes (output)
|
||||
* @param dev_type parsed device type (output)
|
||||
* @param dev_num parsed device number (output)
|
||||
* @return 0 on success, 1 otherwise
|
||||
*/
|
||||
static int mtd_id_parse(const char *id, const char **ret_id, u8 *dev_type, u8 *dev_num)
|
||||
{
|
||||
const char *p = id;
|
||||
|
||||
*dev_type = 0;
|
||||
if (strncmp(p, "nand", 4) == 0) {
|
||||
*dev_type = MTD_DEV_TYPE_NAND;
|
||||
p += 4;
|
||||
} else if (strncmp(p, "nor", 3) == 0) {
|
||||
*dev_type = MTD_DEV_TYPE_NOR;
|
||||
p += 3;
|
||||
} else if (strncmp(p, "onenand", 7) == 0) {
|
||||
*dev_type = MTD_DEV_TYPE_ONENAND;
|
||||
p += 7;
|
||||
} else {
|
||||
printf("incorrect device type in %s\n", id);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!isdigit(*p)) {
|
||||
printf("incorrect device number in %s\n", id);
|
||||
return 1;
|
||||
}
|
||||
|
||||
*dev_num = simple_strtoul(p, (char **)&p, 0);
|
||||
if (ret_id)
|
||||
*ret_id = p;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 'Static' version of command line mtdparts_init() routine. Single partition on
|
||||
* a single device configuration.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Calculate sector size.
|
||||
*
|
||||
* @return sector size
|
||||
*/
|
||||
static inline u32 get_part_sector_size_nand(struct mtdids *id)
|
||||
{
|
||||
#if defined(CONFIG_JFFS2_NAND) && defined(CONFIG_CMD_NAND)
|
||||
struct mtd_info *mtd;
|
||||
|
||||
mtd = get_nand_dev_by_index(id->num);
|
||||
|
||||
return mtd->erasesize;
|
||||
#else
|
||||
BUG();
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline u32 get_part_sector_size_nor(struct mtdids *id, struct part_info *part)
|
||||
{
|
||||
#if defined(CONFIG_CMD_FLASH)
|
||||
extern flash_info_t flash_info[];
|
||||
|
||||
u32 end_phys, start_phys, sector_size = 0, size = 0;
|
||||
int i;
|
||||
flash_info_t *flash;
|
||||
|
||||
flash = &flash_info[id->num];
|
||||
|
||||
start_phys = flash->start[0] + part->offset;
|
||||
end_phys = start_phys + part->size - 1;
|
||||
|
||||
for (i = 0; i < flash->sector_count; i++) {
|
||||
if (flash->start[i] >= end_phys)
|
||||
break;
|
||||
|
||||
if (flash->start[i] >= start_phys) {
|
||||
if (i == flash->sector_count - 1) {
|
||||
size = flash->start[0] + flash->size - flash->start[i];
|
||||
} else {
|
||||
size = flash->start[i+1] - flash->start[i];
|
||||
}
|
||||
|
||||
if (sector_size < size)
|
||||
sector_size = size;
|
||||
}
|
||||
}
|
||||
|
||||
return sector_size;
|
||||
#else
|
||||
BUG();
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline u32 get_part_sector_size_onenand(void)
|
||||
{
|
||||
#if defined(CONFIG_CMD_ONENAND)
|
||||
struct mtd_info *mtd;
|
||||
|
||||
mtd = &onenand_mtd;
|
||||
|
||||
return mtd->erasesize;
|
||||
#else
|
||||
BUG();
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline u32 get_part_sector_size(struct mtdids *id, struct part_info *part)
|
||||
{
|
||||
if (id->type == MTD_DEV_TYPE_NAND)
|
||||
return get_part_sector_size_nand(id);
|
||||
else if (id->type == MTD_DEV_TYPE_NOR)
|
||||
return get_part_sector_size_nor(id, part);
|
||||
else if (id->type == MTD_DEV_TYPE_ONENAND)
|
||||
return get_part_sector_size_onenand();
|
||||
else
|
||||
DEBUGF("Error: Unknown device type.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse and initialize global mtdids mapping and create global
|
||||
* device/partition list.
|
||||
*
|
||||
* 'Static' version of command line mtdparts_init() routine. Single partition on
|
||||
* a single device configuration.
|
||||
*
|
||||
* @return 0 on success, 1 otherwise
|
||||
*/
|
||||
int mtdparts_init(void)
|
||||
{
|
||||
static int initialized = 0;
|
||||
u32 size;
|
||||
char *dev_name;
|
||||
|
||||
DEBUGF("\n---mtdparts_init---\n");
|
||||
if (!initialized) {
|
||||
struct mtdids *id;
|
||||
struct part_info *part;
|
||||
|
||||
initialized = 1;
|
||||
current_mtd_dev = (struct mtd_device *)
|
||||
malloc(sizeof(struct mtd_device) +
|
||||
sizeof(struct part_info) +
|
||||
sizeof(struct mtdids));
|
||||
if (!current_mtd_dev) {
|
||||
printf("out of memory\n");
|
||||
return 1;
|
||||
}
|
||||
memset(current_mtd_dev, 0, sizeof(struct mtd_device) +
|
||||
sizeof(struct part_info) + sizeof(struct mtdids));
|
||||
|
||||
id = (struct mtdids *)(current_mtd_dev + 1);
|
||||
part = (struct part_info *)(id + 1);
|
||||
|
||||
/* id */
|
||||
id->mtd_id = "single part";
|
||||
|
||||
#if defined(CONFIG_JFFS2_DEV)
|
||||
dev_name = CONFIG_JFFS2_DEV;
|
||||
#else
|
||||
dev_name = "nor0";
|
||||
#endif
|
||||
|
||||
if ((mtd_id_parse(dev_name, NULL, &id->type, &id->num) != 0) ||
|
||||
(mtd_device_validate(id->type, id->num, &size) != 0)) {
|
||||
printf("incorrect device: %s%d\n", MTD_DEV_TYPE(id->type), id->num);
|
||||
free(current_mtd_dev);
|
||||
return 1;
|
||||
}
|
||||
id->size = size;
|
||||
INIT_LIST_HEAD(&id->link);
|
||||
|
||||
DEBUGF("dev id: type = %d, num = %d, size = 0x%08lx, mtd_id = %s\n",
|
||||
id->type, id->num, id->size, id->mtd_id);
|
||||
|
||||
/* partition */
|
||||
part->name = "static";
|
||||
part->auto_name = 0;
|
||||
|
||||
#if defined(CONFIG_JFFS2_PART_SIZE)
|
||||
part->size = CONFIG_JFFS2_PART_SIZE;
|
||||
#else
|
||||
part->size = SIZE_REMAINING;
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_JFFS2_PART_OFFSET)
|
||||
part->offset = CONFIG_JFFS2_PART_OFFSET;
|
||||
#else
|
||||
part->offset = 0x00000000;
|
||||
#endif
|
||||
|
||||
part->dev = current_mtd_dev;
|
||||
INIT_LIST_HEAD(&part->link);
|
||||
|
||||
/* recalculate size if needed */
|
||||
if (part->size == SIZE_REMAINING)
|
||||
part->size = id->size - part->offset;
|
||||
|
||||
part->sector_size = get_part_sector_size(id, part);
|
||||
|
||||
DEBUGF("part : name = %s, size = 0x%08lx, offset = 0x%08lx\n",
|
||||
part->name, part->size, part->offset);
|
||||
|
||||
/* device */
|
||||
current_mtd_dev->id = id;
|
||||
INIT_LIST_HEAD(¤t_mtd_dev->link);
|
||||
current_mtd_dev->num_parts = 1;
|
||||
INIT_LIST_HEAD(¤t_mtd_dev->parts);
|
||||
list_add(&part->link, ¤t_mtd_dev->parts);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* #ifndef CONFIG_CMD_MTDPARTS */
|
||||
|
||||
/**
|
||||
* Return pointer to the partition of a requested number from a requested
|
||||
* device.
|
||||
*
|
||||
* @param dev device that is to be searched for a partition
|
||||
* @param part_num requested partition number
|
||||
* @return pointer to the part_info, NULL otherwise
|
||||
*/
|
||||
static struct part_info* jffs2_part_info(struct mtd_device *dev, unsigned int part_num)
|
||||
{
|
||||
struct list_head *entry;
|
||||
struct part_info *part;
|
||||
int num;
|
||||
|
||||
if (!dev)
|
||||
return NULL;
|
||||
|
||||
DEBUGF("\n--- jffs2_part_info: partition number %d for device %s%d (%s)\n",
|
||||
part_num, MTD_DEV_TYPE(dev->id->type),
|
||||
dev->id->num, dev->id->mtd_id);
|
||||
|
||||
if (part_num >= dev->num_parts) {
|
||||
printf("invalid partition number %d for device %s%d (%s)\n",
|
||||
part_num, MTD_DEV_TYPE(dev->id->type),
|
||||
dev->id->num, dev->id->mtd_id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* locate partition number, return it */
|
||||
num = 0;
|
||||
list_for_each(entry, &dev->parts) {
|
||||
part = list_entry(entry, struct part_info, link);
|
||||
|
||||
if (part_num == num++) {
|
||||
return part;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/***************************************************/
|
||||
/* U-Boot commands */
|
||||
/***************************************************/
|
||||
|
||||
/**
|
||||
* Routine implementing fsload u-boot command. This routine tries to load
|
||||
* a requested file from jffs2/cramfs filesystem on a current partition.
|
||||
*
|
||||
* @param cmdtp command internal data
|
||||
* @param flag command flag
|
||||
* @param argc number of arguments supplied to the command
|
||||
* @param argv arguments list
|
||||
* @return 0 on success, 1 otherwise
|
||||
*/
|
||||
int do_jffs2_fsload(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
char *fsname;
|
||||
char *filename;
|
||||
int size;
|
||||
struct part_info *part;
|
||||
ulong offset = load_addr;
|
||||
|
||||
/* pre-set Boot file name */
|
||||
filename = env_get("bootfile");
|
||||
if (!filename)
|
||||
filename = "uImage";
|
||||
|
||||
if (argc == 2) {
|
||||
filename = argv[1];
|
||||
}
|
||||
if (argc == 3) {
|
||||
offset = simple_strtoul(argv[1], NULL, 16);
|
||||
load_addr = offset;
|
||||
filename = argv[2];
|
||||
}
|
||||
|
||||
/* make sure we are in sync with env variables */
|
||||
if (mtdparts_init() !=0)
|
||||
return 1;
|
||||
|
||||
if ((part = jffs2_part_info(current_mtd_dev, current_mtd_partnum))){
|
||||
|
||||
/* check partition type for cramfs */
|
||||
fsname = (cramfs_check(part) ? "CRAMFS" : "JFFS2");
|
||||
printf("### %s loading '%s' to 0x%lx\n", fsname, filename, offset);
|
||||
|
||||
if (cramfs_check(part)) {
|
||||
size = cramfs_load ((char *) offset, part, filename);
|
||||
} else {
|
||||
/* if this is not cramfs assume jffs2 */
|
||||
size = jffs2_1pass_load((char *)offset, part, filename);
|
||||
}
|
||||
|
||||
if (size > 0) {
|
||||
printf("### %s load complete: %d bytes loaded to 0x%lx\n",
|
||||
fsname, size, offset);
|
||||
env_set_hex("filesize", size);
|
||||
} else {
|
||||
printf("### %s LOAD ERROR<%x> for %s!\n", fsname, size, filename);
|
||||
}
|
||||
|
||||
return !(size > 0);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Routine implementing u-boot ls command which lists content of a given
|
||||
* directory on a current partition.
|
||||
*
|
||||
* @param cmdtp command internal data
|
||||
* @param flag command flag
|
||||
* @param argc number of arguments supplied to the command
|
||||
* @param argv arguments list
|
||||
* @return 0 on success, 1 otherwise
|
||||
*/
|
||||
int do_jffs2_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
char *filename = "/";
|
||||
int ret;
|
||||
struct part_info *part;
|
||||
|
||||
if (argc == 2)
|
||||
filename = argv[1];
|
||||
|
||||
/* make sure we are in sync with env variables */
|
||||
if (mtdparts_init() !=0)
|
||||
return 1;
|
||||
|
||||
if ((part = jffs2_part_info(current_mtd_dev, current_mtd_partnum))){
|
||||
|
||||
/* check partition type for cramfs */
|
||||
if (cramfs_check(part)) {
|
||||
ret = cramfs_ls (part, filename);
|
||||
} else {
|
||||
/* if this is not cramfs assume jffs2 */
|
||||
ret = jffs2_1pass_ls(part, filename);
|
||||
}
|
||||
|
||||
return ret ? 0 : 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Routine implementing u-boot fsinfo command. This routine prints out
|
||||
* miscellaneous filesystem informations/statistics.
|
||||
*
|
||||
* @param cmdtp command internal data
|
||||
* @param flag command flag
|
||||
* @param argc number of arguments supplied to the command
|
||||
* @param argv arguments list
|
||||
* @return 0 on success, 1 otherwise
|
||||
*/
|
||||
int do_jffs2_fsinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
struct part_info *part;
|
||||
char *fsname;
|
||||
int ret;
|
||||
|
||||
/* make sure we are in sync with env variables */
|
||||
if (mtdparts_init() !=0)
|
||||
return 1;
|
||||
|
||||
if ((part = jffs2_part_info(current_mtd_dev, current_mtd_partnum))){
|
||||
|
||||
/* check partition type for cramfs */
|
||||
fsname = (cramfs_check(part) ? "CRAMFS" : "JFFS2");
|
||||
printf("### filesystem type is %s\n", fsname);
|
||||
|
||||
if (cramfs_check(part)) {
|
||||
ret = cramfs_info (part);
|
||||
} else {
|
||||
/* if this is not cramfs assume jffs2 */
|
||||
ret = jffs2_1pass_info(part);
|
||||
}
|
||||
|
||||
return ret ? 0 : 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/***************************************************/
|
||||
U_BOOT_CMD(
|
||||
fsload, 3, 0, do_jffs2_fsload,
|
||||
"load binary file from a filesystem image",
|
||||
"[ off ] [ filename ]\n"
|
||||
" - load binary file from flash bank\n"
|
||||
" with offset 'off'"
|
||||
);
|
||||
U_BOOT_CMD(
|
||||
fsls, 2, 1, do_jffs2_ls,
|
||||
"list files in a directory (default /)",
|
||||
"[ directory ]"
|
||||
);
|
||||
|
||||
U_BOOT_CMD(
|
||||
fsinfo, 1, 1, do_jffs2_fsinfo,
|
||||
"print information about filesystems",
|
||||
""
|
||||
);
|
||||
/***************************************************/
|
||||
142
cmd/led.c
Normal file
142
cmd/led.c
Normal file
@@ -0,0 +1,142 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2017 Google, Inc
|
||||
* Written by Simon Glass <sjg@chromium.org>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <dm.h>
|
||||
#include <led.h>
|
||||
#include <dm/uclass-internal.h>
|
||||
|
||||
#define LED_TOGGLE LEDST_COUNT
|
||||
|
||||
static const char *const state_label[] = {
|
||||
[LEDST_OFF] = "off",
|
||||
[LEDST_ON] = "on",
|
||||
[LEDST_TOGGLE] = "toggle",
|
||||
#ifdef CONFIG_LED_BLINK
|
||||
[LEDST_BLINK] = "blink",
|
||||
#endif
|
||||
};
|
||||
|
||||
enum led_state_t get_led_cmd(char *var)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < LEDST_COUNT; i++) {
|
||||
if (!strncmp(var, state_label[i], strlen(var)))
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int show_led_state(struct udevice *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = led_get_state(dev);
|
||||
if (ret >= LEDST_COUNT)
|
||||
ret = -EINVAL;
|
||||
if (ret >= 0)
|
||||
printf("%s\n", state_label[ret]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int list_leds(void)
|
||||
{
|
||||
struct udevice *dev;
|
||||
int ret;
|
||||
|
||||
for (uclass_find_first_device(UCLASS_LED, &dev);
|
||||
dev;
|
||||
uclass_find_next_device(&dev)) {
|
||||
struct led_uc_plat *plat = dev_get_uclass_platdata(dev);
|
||||
|
||||
if (!plat->label)
|
||||
continue;
|
||||
printf("%-15s ", plat->label);
|
||||
if (device_active(dev)) {
|
||||
ret = show_led_state(dev);
|
||||
if (ret < 0)
|
||||
printf("Error %d\n", ret);
|
||||
} else {
|
||||
printf("<inactive>\n");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int do_led(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
enum led_state_t cmd;
|
||||
const char *led_label;
|
||||
struct udevice *dev;
|
||||
#ifdef CONFIG_LED_BLINK
|
||||
int freq_ms = 0;
|
||||
#endif
|
||||
int ret;
|
||||
|
||||
/* Validate arguments */
|
||||
if (argc < 2)
|
||||
return CMD_RET_USAGE;
|
||||
led_label = argv[1];
|
||||
if (strncmp(led_label, "list", 4) == 0)
|
||||
return list_leds();
|
||||
|
||||
cmd = argc > 2 ? get_led_cmd(argv[2]) : LEDST_COUNT;
|
||||
#ifdef CONFIG_LED_BLINK
|
||||
if (cmd == LEDST_BLINK) {
|
||||
if (argc < 4)
|
||||
return CMD_RET_USAGE;
|
||||
freq_ms = simple_strtoul(argv[3], NULL, 10);
|
||||
}
|
||||
#endif
|
||||
ret = led_get_by_label(led_label, &dev);
|
||||
if (ret) {
|
||||
printf("LED '%s' not found (err=%d)\n", led_label, ret);
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
switch (cmd) {
|
||||
case LEDST_OFF:
|
||||
case LEDST_ON:
|
||||
case LEDST_TOGGLE:
|
||||
ret = led_set_state(dev, cmd);
|
||||
break;
|
||||
#ifdef CONFIG_LED_BLINK
|
||||
case LEDST_BLINK:
|
||||
ret = led_set_period(dev, freq_ms);
|
||||
if (!ret)
|
||||
ret = led_set_state(dev, LEDST_BLINK);
|
||||
break;
|
||||
#endif
|
||||
case LEDST_COUNT:
|
||||
printf("LED '%s': ", led_label);
|
||||
ret = show_led_state(dev);
|
||||
break;
|
||||
}
|
||||
if (ret < 0) {
|
||||
printf("LED '%s' operation failed (err=%d)\n", led_label, ret);
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_LED_BLINK
|
||||
#define BLINK "|blink [blink-freq in ms]"
|
||||
#else
|
||||
#define BLINK ""
|
||||
#endif
|
||||
|
||||
U_BOOT_CMD(
|
||||
led, 4, 1, do_led,
|
||||
"manage LEDs",
|
||||
"<led_label> on|off|toggle" BLINK "\tChange LED state\n"
|
||||
"led <led_label>\tGet LED state\n"
|
||||
"led list\t\tshow a list of LEDs"
|
||||
);
|
||||
99
cmd/legacy-mtd-utils.c
Normal file
99
cmd/legacy-mtd-utils.c
Normal file
@@ -0,0 +1,99 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
#include <common.h>
|
||||
#include <jffs2/jffs2.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/string.h>
|
||||
#include <mtd.h>
|
||||
|
||||
static int get_part(const char *partname, int *idx, loff_t *off, loff_t *size,
|
||||
loff_t *maxsize, int devtype)
|
||||
{
|
||||
#ifdef CONFIG_CMD_MTDPARTS
|
||||
struct mtd_device *dev;
|
||||
struct part_info *part;
|
||||
u8 pnum;
|
||||
int ret;
|
||||
|
||||
ret = mtdparts_init();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = find_dev_and_part(partname, &dev, &pnum, &part);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (dev->id->type != devtype) {
|
||||
printf("not same typ %d != %d\n", dev->id->type, devtype);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*off = part->offset;
|
||||
*size = part->size;
|
||||
*maxsize = part->size;
|
||||
*idx = dev->id->num;
|
||||
|
||||
return 0;
|
||||
#else
|
||||
puts("mtdparts support missing.\n");
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int mtd_arg_off(const char *arg, int *idx, loff_t *off, loff_t *size,
|
||||
loff_t *maxsize, int devtype, uint64_t chipsize)
|
||||
{
|
||||
if (!str2off(arg, off))
|
||||
return get_part(arg, idx, off, size, maxsize, devtype);
|
||||
|
||||
if (*off >= chipsize) {
|
||||
puts("Offset exceeds device limit\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
*maxsize = chipsize - *off;
|
||||
*size = *maxsize;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mtd_arg_off_size(int argc, char *const argv[], int *idx, loff_t *off,
|
||||
loff_t *size, loff_t *maxsize, int devtype,
|
||||
uint64_t chipsize)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (argc == 0) {
|
||||
*off = 0;
|
||||
*size = chipsize;
|
||||
*maxsize = *size;
|
||||
goto print;
|
||||
}
|
||||
|
||||
ret = mtd_arg_off(argv[0], idx, off, size, maxsize, devtype,
|
||||
chipsize);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (argc == 1)
|
||||
goto print;
|
||||
|
||||
if (!str2off(argv[1], size)) {
|
||||
printf("'%s' is not a number\n", argv[1]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (*size > *maxsize) {
|
||||
puts("Size exceeds partition or device limit\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
print:
|
||||
printf("device %d ", *idx);
|
||||
if (*size == chipsize)
|
||||
puts("whole chip\n");
|
||||
else
|
||||
printf("offset 0x%llx, size 0x%llx\n",
|
||||
(unsigned long long)*off, (unsigned long long)*size);
|
||||
return 0;
|
||||
}
|
||||
12
cmd/legacy-mtd-utils.h
Normal file
12
cmd/legacy-mtd-utils.h
Normal file
@@ -0,0 +1,12 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
|
||||
#ifndef __LEGACY_MTD_UTILS_H
|
||||
#define __LEGACY_MTD_UTILS_H
|
||||
|
||||
int mtd_arg_off(const char *arg, int *idx, loff_t *off, loff_t *size,
|
||||
loff_t *maxsize, int devtype, uint64_t chipsize);
|
||||
int mtd_arg_off_size(int argc, char *const argv[], int *idx, loff_t *off,
|
||||
loff_t *size, loff_t *maxsize, int devtype,
|
||||
uint64_t chipsize);
|
||||
|
||||
#endif /* LEGACY_MTD_UTILS_H */
|
||||
186
cmd/legacy_led.c
Normal file
186
cmd/legacy_led.c
Normal file
@@ -0,0 +1,186 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2010
|
||||
* Jason Kridner <jkridner@beagleboard.org>
|
||||
*
|
||||
* Based on cmd_led.c patch from:
|
||||
* http://www.mail-archive.com/u-boot@lists.denx.de/msg06873.html
|
||||
* (C) Copyright 2008
|
||||
* Ulf Samuelsson <ulf.samuelsson@atmel.com>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <config.h>
|
||||
#include <command.h>
|
||||
#include <status_led.h>
|
||||
|
||||
struct led_tbl_s {
|
||||
char *string; /* String for use in the command */
|
||||
led_id_t mask; /* Mask used for calling __led_set() */
|
||||
void (*off)(void); /* Optional function for turning LED off */
|
||||
void (*on)(void); /* Optional function for turning LED on */
|
||||
void (*toggle)(void);/* Optional function for toggling LED */
|
||||
};
|
||||
|
||||
typedef struct led_tbl_s led_tbl_t;
|
||||
|
||||
static const led_tbl_t led_commands[] = {
|
||||
#ifdef CONFIG_LED_STATUS_BOARD_SPECIFIC
|
||||
#ifdef CONFIG_LED_STATUS0
|
||||
{ "0", CONFIG_LED_STATUS_BIT, NULL, NULL, NULL },
|
||||
#endif
|
||||
#ifdef CONFIG_LED_STATUS1
|
||||
{ "1", CONFIG_LED_STATUS_BIT1, NULL, NULL, NULL },
|
||||
#endif
|
||||
#ifdef CONFIG_LED_STATUS2
|
||||
{ "2", CONFIG_LED_STATUS_BIT2, NULL, NULL, NULL },
|
||||
#endif
|
||||
#ifdef CONFIG_LED_STATUS3
|
||||
{ "3", CONFIG_LED_STATUS_BIT3, NULL, NULL, NULL },
|
||||
#endif
|
||||
#ifdef CONFIG_LED_STATUS4
|
||||
{ "4", CONFIG_LED_STATUS_BIT4, NULL, NULL, NULL },
|
||||
#endif
|
||||
#ifdef CONFIG_LED_STATUS5
|
||||
{ "5", CONFIG_LED_STATUS_BIT5, NULL, NULL, NULL },
|
||||
#endif
|
||||
#endif
|
||||
#ifdef CONFIG_LED_STATUS_GREEN
|
||||
{ "green", CONFIG_LED_STATUS_GREEN, green_led_off, green_led_on, NULL },
|
||||
#endif
|
||||
#ifdef CONFIG_LED_STATUS_YELLOW
|
||||
{ "yellow", CONFIG_LED_STATUS_YELLOW, yellow_led_off, yellow_led_on,
|
||||
NULL },
|
||||
#endif
|
||||
#ifdef CONFIG_LED_STATUS_RED
|
||||
{ "red", CONFIG_LED_STATUS_RED, red_led_off, red_led_on, NULL },
|
||||
#endif
|
||||
#ifdef CONFIG_LED_STATUS_BLUE
|
||||
{ "blue", CONFIG_LED_STATUS_BLUE, blue_led_off, blue_led_on, NULL },
|
||||
#endif
|
||||
{ NULL, 0, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
enum led_cmd { LED_ON, LED_OFF, LED_TOGGLE, LED_BLINK };
|
||||
|
||||
enum led_cmd get_led_cmd(char *var)
|
||||
{
|
||||
if (strcmp(var, "off") == 0)
|
||||
return LED_OFF;
|
||||
if (strcmp(var, "on") == 0)
|
||||
return LED_ON;
|
||||
if (strcmp(var, "toggle") == 0)
|
||||
return LED_TOGGLE;
|
||||
if (strcmp(var, "blink") == 0)
|
||||
return LED_BLINK;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* LED drivers providing a blinking LED functionality, like the
|
||||
* PCA9551, can override this empty weak function
|
||||
*/
|
||||
void __weak __led_blink(led_id_t mask, int freq)
|
||||
{
|
||||
}
|
||||
|
||||
int do_legacy_led(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
int i, match = 0;
|
||||
enum led_cmd cmd;
|
||||
int freq;
|
||||
|
||||
/* Validate arguments */
|
||||
if ((argc < 3) || (argc > 4))
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
cmd = get_led_cmd(argv[2]);
|
||||
if (cmd < 0) {
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
for (i = 0; led_commands[i].string; i++) {
|
||||
if ((strcmp("all", argv[1]) == 0) ||
|
||||
(strcmp(led_commands[i].string, argv[1]) == 0)) {
|
||||
match = 1;
|
||||
switch (cmd) {
|
||||
case LED_ON:
|
||||
if (led_commands[i].on)
|
||||
led_commands[i].on();
|
||||
else
|
||||
__led_set(led_commands[i].mask,
|
||||
CONFIG_LED_STATUS_ON);
|
||||
break;
|
||||
case LED_OFF:
|
||||
if (led_commands[i].off)
|
||||
led_commands[i].off();
|
||||
else
|
||||
__led_set(led_commands[i].mask,
|
||||
CONFIG_LED_STATUS_OFF);
|
||||
break;
|
||||
case LED_TOGGLE:
|
||||
if (led_commands[i].toggle)
|
||||
led_commands[i].toggle();
|
||||
else
|
||||
__led_toggle(led_commands[i].mask);
|
||||
break;
|
||||
case LED_BLINK:
|
||||
if (argc != 4)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
freq = simple_strtoul(argv[3], NULL, 10);
|
||||
__led_blink(led_commands[i].mask, freq);
|
||||
}
|
||||
/* Need to set only 1 led if led_name wasn't 'all' */
|
||||
if (strcmp("all", argv[1]) != 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we ran out of matches, print Usage */
|
||||
if (!match) {
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
led, 4, 1, do_legacy_led,
|
||||
"["
|
||||
#ifdef CONFIG_LED_STATUS_BOARD_SPECIFIC
|
||||
#ifdef CONFIG_LED_STATUS0
|
||||
"0|"
|
||||
#endif
|
||||
#ifdef CONFIG_LED_STATUS1
|
||||
"1|"
|
||||
#endif
|
||||
#ifdef CONFIG_LED_STATUS2
|
||||
"2|"
|
||||
#endif
|
||||
#ifdef CONFIG_LED_STATUS3
|
||||
"3|"
|
||||
#endif
|
||||
#ifdef CONFIG_LED_STATUS4
|
||||
"4|"
|
||||
#endif
|
||||
#ifdef CONFIG_LED_STATUS5
|
||||
"5|"
|
||||
#endif
|
||||
#endif
|
||||
#ifdef CONFIG_LED_STATUS_GREEN
|
||||
"green|"
|
||||
#endif
|
||||
#ifdef CONFIG_LED_STATUS_YELLOW
|
||||
"yellow|"
|
||||
#endif
|
||||
#ifdef CONFIG_LED_STATUS_RED
|
||||
"red|"
|
||||
#endif
|
||||
#ifdef CONFIG_LED_STATUS_BLUE
|
||||
"blue|"
|
||||
#endif
|
||||
"all] [on|off|toggle|blink] [blink-freq in ms]",
|
||||
"[led_name] [on|off|toggle|blink] sets or clears led(s)"
|
||||
);
|
||||
45
cmd/license.c
Normal file
45
cmd/license.c
Normal file
@@ -0,0 +1,45 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2007 by OpenMoko, Inc.
|
||||
* Author: Harald Welte <laforge@openmoko.org>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <gzip.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#include "license_data_gz.h"
|
||||
#include "license_data_size.h"
|
||||
|
||||
static int do_license(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
char *dst;
|
||||
unsigned long len = data_size;
|
||||
int ret = CMD_RET_SUCCESS;
|
||||
|
||||
dst = malloc(data_size + 1);
|
||||
if (!dst)
|
||||
return CMD_RET_FAILURE;
|
||||
|
||||
ret = gunzip(dst, data_size, (unsigned char *)data_gz, &len);
|
||||
if (ret) {
|
||||
printf("Error uncompressing license text\n");
|
||||
ret = CMD_RET_FAILURE;
|
||||
goto free;
|
||||
}
|
||||
|
||||
dst[data_size] = 0;
|
||||
puts(dst);
|
||||
|
||||
free:
|
||||
free(dst);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
license, 1, 1, do_license,
|
||||
"print GPL license text",
|
||||
""
|
||||
);
|
||||
1085
cmd/load.c
Normal file
1085
cmd/load.c
Normal file
File diff suppressed because it is too large
Load Diff
142
cmd/log.c
Normal file
142
cmd/log.c
Normal file
@@ -0,0 +1,142 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2017 Google, Inc
|
||||
* Written by Simon Glass <sjg@chromium.org>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <dm.h>
|
||||
#include <log.h>
|
||||
|
||||
static char log_fmt_chars[LOGF_COUNT] = "clFLfm";
|
||||
|
||||
static int do_log_level(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
if (argc > 1)
|
||||
gd->default_log_level = simple_strtol(argv[1], NULL, 10);
|
||||
else
|
||||
printf("Default log level: %d\n", gd->default_log_level);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_log_format(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
int i;
|
||||
|
||||
if (argc > 1) {
|
||||
const char *str = argv[1];
|
||||
|
||||
if (!strcmp(str, "default")) {
|
||||
gd->log_fmt = LOGF_DEFAULT;
|
||||
} else if (!strcmp(str, "all")) {
|
||||
gd->log_fmt = LOGF_ALL;
|
||||
} else {
|
||||
gd->log_fmt = 0;
|
||||
for (; *str; str++) {
|
||||
char *ptr = strchr(log_fmt_chars, *str);
|
||||
|
||||
if (!ptr) {
|
||||
printf("Invalid log char '%c'\n", *str);
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
gd->log_fmt |= 1 << (ptr - log_fmt_chars);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
printf("Log format: ");
|
||||
for (i = 0; i < LOGF_COUNT; i++) {
|
||||
if (gd->log_fmt & (1 << i))
|
||||
printf("%c", log_fmt_chars[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_log_rec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
enum log_category_t cat;
|
||||
enum log_level_t level;
|
||||
const char *file;
|
||||
uint line;
|
||||
const char *func;
|
||||
const char *msg;
|
||||
char *end;
|
||||
|
||||
if (argc < 7)
|
||||
return CMD_RET_USAGE;
|
||||
cat = log_get_cat_by_name(argv[1]);
|
||||
level = simple_strtoul(argv[2], &end, 10);
|
||||
if (end == argv[2]) {
|
||||
level = log_get_level_by_name(argv[2]);
|
||||
|
||||
if (level == LOGL_NONE) {
|
||||
printf("Invalid log level '%s'\n", argv[2]);
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
}
|
||||
if (level >= LOGL_MAX) {
|
||||
printf("Invalid log level %u\n", level);
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
file = argv[3];
|
||||
line = simple_strtoul(argv[4], NULL, 10);
|
||||
func = argv[5];
|
||||
msg = argv[6];
|
||||
if (_log(cat, level, file, line, func, "%s\n", msg))
|
||||
return CMD_RET_FAILURE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static cmd_tbl_t log_sub[] = {
|
||||
U_BOOT_CMD_MKENT(level, CONFIG_SYS_MAXARGS, 1, do_log_level, "", ""),
|
||||
#ifdef CONFIG_LOG_TEST
|
||||
U_BOOT_CMD_MKENT(test, 2, 1, do_log_test, "", ""),
|
||||
#endif
|
||||
U_BOOT_CMD_MKENT(format, CONFIG_SYS_MAXARGS, 1, do_log_format, "", ""),
|
||||
U_BOOT_CMD_MKENT(rec, CONFIG_SYS_MAXARGS, 1, do_log_rec, "", ""),
|
||||
};
|
||||
|
||||
static int do_log(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
cmd_tbl_t *cp;
|
||||
|
||||
if (argc < 2)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
/* drop initial "log" arg */
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
cp = find_cmd_tbl(argv[0], log_sub, ARRAY_SIZE(log_sub));
|
||||
if (cp)
|
||||
return cp->cmd(cmdtp, flag, argc, argv);
|
||||
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SYS_LONGHELP
|
||||
static char log_help_text[] =
|
||||
"level - get/set log level\n"
|
||||
#ifdef CONFIG_LOG_TEST
|
||||
"log test - run log tests\n"
|
||||
#endif
|
||||
"log format <fmt> - set log output format. <fmt> is a string where\n"
|
||||
"\teach letter indicates something that should be displayed:\n"
|
||||
"\tc=category, l=level, F=file, L=line number, f=function, m=msg\n"
|
||||
"\tor 'default', equivalent to 'fm', or 'all' for all\n"
|
||||
"log rec <category> <level> <file> <line> <func> <message> - "
|
||||
"output a log record"
|
||||
;
|
||||
#endif
|
||||
|
||||
U_BOOT_CMD(
|
||||
log, CONFIG_SYS_MAXARGS, 1, do_log,
|
||||
"log system", log_help_text
|
||||
);
|
||||
54
cmd/lzmadec.c
Normal file
54
cmd/lzmadec.c
Normal file
@@ -0,0 +1,54 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2013 Patrice Bouchand <pbfwdlist_gmail_com>
|
||||
* lzma uncompress command in Uboot
|
||||
*
|
||||
* made from existing cmd_unzip.c file of Uboot
|
||||
*
|
||||
* (C) Copyright 2000
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <env.h>
|
||||
#include <mapmem.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include <lzma/LzmaTools.h>
|
||||
|
||||
static int do_lzmadec(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
|
||||
{
|
||||
unsigned long src, dst;
|
||||
SizeT src_len = ~0UL, dst_len = ~0UL;
|
||||
int ret;
|
||||
|
||||
switch (argc) {
|
||||
case 4:
|
||||
dst_len = simple_strtoul(argv[3], NULL, 16);
|
||||
/* fall through */
|
||||
case 3:
|
||||
src = simple_strtoul(argv[1], NULL, 16);
|
||||
dst = simple_strtoul(argv[2], NULL, 16);
|
||||
break;
|
||||
default:
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
ret = lzmaBuffToBuffDecompress(map_sysmem(dst, dst_len), &src_len,
|
||||
map_sysmem(src, 0), dst_len);
|
||||
|
||||
if (ret != SZ_OK)
|
||||
return 1;
|
||||
printf("Uncompressed size: %ld = %#lX\n", (ulong)src_len,
|
||||
(ulong)src_len);
|
||||
env_set_hex("filesize", src_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
lzmadec, 4, 1, do_lzmadec,
|
||||
"lzma uncompress a memory region",
|
||||
"srcaddr dstaddr [dstsize]"
|
||||
);
|
||||
32
cmd/mac.c
Normal file
32
cmd/mac.c
Normal file
@@ -0,0 +1,32 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2006 Freescale Semiconductor
|
||||
* York Sun (yorksun@freescale.com)
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
|
||||
extern int do_mac(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
|
||||
|
||||
U_BOOT_CMD(
|
||||
mac, 3, 1, do_mac,
|
||||
"display and program the system ID and MAC addresses in EEPROM",
|
||||
"[read|save|id|num|errata|date|ports|port_number]\n"
|
||||
"mac read\n"
|
||||
" - read EEPROM content into memory data structure\n"
|
||||
"mac save\n"
|
||||
" - save memory data structure to the EEPROM\n"
|
||||
"mac id\n"
|
||||
" - program system id per hard coded value\n"
|
||||
"mac num string\n"
|
||||
" - program system serial number to value string\n"
|
||||
"mac errata string\n"
|
||||
" - program errata data to value string\n"
|
||||
"mac date YYMMDDhhmmss\n"
|
||||
" - program date to string value YYMMDDhhmmss\n"
|
||||
"mac ports N\n"
|
||||
" - program the number of network ports to integer N\n"
|
||||
"mac X string\n"
|
||||
" - program MAC addr for port X [X=0,1..] to colon separated string"
|
||||
);
|
||||
183
cmd/md5sum.c
Normal file
183
cmd/md5sum.c
Normal file
@@ -0,0 +1,183 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2011
|
||||
* Joe Hershberger, National Instruments, joe.hershberger@ni.com
|
||||
*
|
||||
* (C) Copyright 2000
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <env.h>
|
||||
#include <mapmem.h>
|
||||
#include <u-boot/md5.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
/*
|
||||
* Store the resulting sum to an address or variable
|
||||
*/
|
||||
static void store_result(const u8 *sum, const char *dest)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if (*dest == '*') {
|
||||
u8 *ptr;
|
||||
|
||||
ptr = (u8 *)simple_strtoul(dest + 1, NULL, 16);
|
||||
for (i = 0; i < 16; i++)
|
||||
*ptr++ = sum[i];
|
||||
} else {
|
||||
char str_output[33];
|
||||
char *str_ptr = str_output;
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
sprintf(str_ptr, "%02x", sum[i]);
|
||||
str_ptr += 2;
|
||||
}
|
||||
env_set(dest, str_output);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MD5SUM_VERIFY
|
||||
static int parse_verify_sum(char *verify_str, u8 *vsum)
|
||||
{
|
||||
if (*verify_str == '*') {
|
||||
u8 *ptr;
|
||||
|
||||
ptr = (u8 *)simple_strtoul(verify_str + 1, NULL, 16);
|
||||
memcpy(vsum, ptr, 16);
|
||||
} else {
|
||||
unsigned int i;
|
||||
char *vsum_str;
|
||||
|
||||
if (strlen(verify_str) == 32)
|
||||
vsum_str = verify_str;
|
||||
else {
|
||||
vsum_str = env_get(verify_str);
|
||||
if (vsum_str == NULL || strlen(vsum_str) != 32)
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
char *nullp = vsum_str + (i + 1) * 2;
|
||||
char end = *nullp;
|
||||
|
||||
*nullp = '\0';
|
||||
*(u8 *)(vsum + i) =
|
||||
simple_strtoul(vsum_str + (i * 2), NULL, 16);
|
||||
*nullp = end;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int do_md5sum(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
ulong addr, len;
|
||||
unsigned int i;
|
||||
u8 output[16];
|
||||
u8 vsum[16];
|
||||
int verify = 0;
|
||||
int ac;
|
||||
char * const *av;
|
||||
void *buf;
|
||||
|
||||
if (argc < 3)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
av = argv + 1;
|
||||
ac = argc - 1;
|
||||
if (strcmp(*av, "-v") == 0) {
|
||||
verify = 1;
|
||||
av++;
|
||||
ac--;
|
||||
if (ac < 3)
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
addr = simple_strtoul(*av++, NULL, 16);
|
||||
len = simple_strtoul(*av++, NULL, 16);
|
||||
|
||||
buf = map_sysmem(addr, len);
|
||||
md5_wd(buf, len, output, CHUNKSZ_MD5);
|
||||
unmap_sysmem(buf);
|
||||
|
||||
if (!verify) {
|
||||
printf("md5 for %08lx ... %08lx ==> ", addr, addr + len - 1);
|
||||
for (i = 0; i < 16; i++)
|
||||
printf("%02x", output[i]);
|
||||
printf("\n");
|
||||
|
||||
if (ac > 2)
|
||||
store_result(output, *av);
|
||||
} else {
|
||||
char *verify_str = *av++;
|
||||
|
||||
if (parse_verify_sum(verify_str, vsum)) {
|
||||
printf("ERROR: %s does not contain a valid md5 sum\n",
|
||||
verify_str);
|
||||
return 1;
|
||||
}
|
||||
if (memcmp(output, vsum, 16) != 0) {
|
||||
printf("md5 for %08lx ... %08lx ==> ", addr,
|
||||
addr + len - 1);
|
||||
for (i = 0; i < 16; i++)
|
||||
printf("%02x", output[i]);
|
||||
printf(" != ");
|
||||
for (i = 0; i < 16; i++)
|
||||
printf("%02x", vsum[i]);
|
||||
printf(" ** ERROR **\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int do_md5sum(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
unsigned long addr, len;
|
||||
unsigned int i;
|
||||
u8 output[16];
|
||||
void *buf;
|
||||
|
||||
if (argc < 3)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
addr = simple_strtoul(argv[1], NULL, 16);
|
||||
len = simple_strtoul(argv[2], NULL, 16);
|
||||
|
||||
buf = map_sysmem(addr, len);
|
||||
md5_wd(buf, len, output, CHUNKSZ_MD5);
|
||||
unmap_sysmem(buf);
|
||||
|
||||
printf("md5 for %08lx ... %08lx ==> ", addr, addr + len - 1);
|
||||
for (i = 0; i < 16; i++)
|
||||
printf("%02x", output[i]);
|
||||
printf("\n");
|
||||
|
||||
if (argc > 3)
|
||||
store_result(output, argv[3]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MD5SUM_VERIFY
|
||||
U_BOOT_CMD(
|
||||
md5sum, 5, 1, do_md5sum,
|
||||
"compute MD5 message digest",
|
||||
"address count [[*]sum]\n"
|
||||
" - compute MD5 message digest [save to sum]\n"
|
||||
"md5sum -v address count [*]sum\n"
|
||||
" - verify md5sum of memory area"
|
||||
);
|
||||
#else
|
||||
U_BOOT_CMD(
|
||||
md5sum, 4, 1, do_md5sum,
|
||||
"compute MD5 message digest",
|
||||
"address count [[*]sum]\n"
|
||||
" - compute MD5 message digest [save to sum]"
|
||||
);
|
||||
#endif
|
||||
332
cmd/mdio.c
Normal file
332
cmd/mdio.c
Normal file
@@ -0,0 +1,332 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2011 Freescale Semiconductor, Inc
|
||||
* Andy Fleming
|
||||
*/
|
||||
|
||||
/*
|
||||
* MDIO Commands
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <miiphy.h>
|
||||
#include <phy.h>
|
||||
|
||||
static char last_op[2];
|
||||
static uint last_data;
|
||||
static uint last_addr_lo;
|
||||
static uint last_addr_hi;
|
||||
static uint last_devad_lo;
|
||||
static uint last_devad_hi;
|
||||
static uint last_reg_lo;
|
||||
static uint last_reg_hi;
|
||||
|
||||
static int extract_range(char *input, int *plo, int *phi)
|
||||
{
|
||||
char *end;
|
||||
*plo = simple_strtol(input, &end, 16);
|
||||
if (end == input)
|
||||
return -1;
|
||||
|
||||
if ((*end == '-') && *(++end))
|
||||
*phi = simple_strtol(end, NULL, 16);
|
||||
else if (*end == '\0')
|
||||
*phi = *plo;
|
||||
else
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mdio_write_ranges(struct mii_dev *bus,
|
||||
int addrlo,
|
||||
int addrhi, int devadlo, int devadhi,
|
||||
int reglo, int reghi, unsigned short data,
|
||||
int extended)
|
||||
{
|
||||
struct phy_device *phydev;
|
||||
int addr, devad, reg;
|
||||
int err = 0;
|
||||
|
||||
for (addr = addrlo; addr <= addrhi; addr++) {
|
||||
phydev = bus->phymap[addr];
|
||||
|
||||
for (devad = devadlo; devad <= devadhi; devad++) {
|
||||
for (reg = reglo; reg <= reghi; reg++) {
|
||||
if (!phydev)
|
||||
err = bus->write(bus, addr, devad,
|
||||
reg, data);
|
||||
else if (!extended)
|
||||
err = phy_write_mmd(phydev, devad,
|
||||
reg, data);
|
||||
else
|
||||
err = phydev->drv->writeext(phydev,
|
||||
addr, devad, reg, data);
|
||||
|
||||
if (err)
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err_out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int mdio_read_ranges(struct mii_dev *bus,
|
||||
int addrlo,
|
||||
int addrhi, int devadlo, int devadhi,
|
||||
int reglo, int reghi, int extended)
|
||||
{
|
||||
int addr, devad, reg;
|
||||
struct phy_device *phydev;
|
||||
|
||||
printf("Reading from bus %s\n", bus->name);
|
||||
for (addr = addrlo; addr <= addrhi; addr++) {
|
||||
phydev = bus->phymap[addr];
|
||||
printf("PHY at address %x:\n", addr);
|
||||
|
||||
for (devad = devadlo; devad <= devadhi; devad++) {
|
||||
for (reg = reglo; reg <= reghi; reg++) {
|
||||
int val;
|
||||
|
||||
if (!phydev)
|
||||
val = bus->read(bus, addr, devad, reg);
|
||||
else if (!extended)
|
||||
val = phy_read_mmd(phydev, devad, reg);
|
||||
else
|
||||
val = phydev->drv->readext(phydev, addr,
|
||||
devad, reg);
|
||||
|
||||
if (val < 0) {
|
||||
printf("Error\n");
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
if (devad >= 0)
|
||||
printf("%d.", devad);
|
||||
|
||||
printf("%d - 0x%x\n", reg, val & 0xffff);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The register will be in the form [a[-b].]x[-y] */
|
||||
static int extract_reg_range(char *input, int *devadlo, int *devadhi,
|
||||
int *reglo, int *reghi)
|
||||
{
|
||||
char *regstr;
|
||||
|
||||
/* use strrchr to find the last string after a '.' */
|
||||
regstr = strrchr(input, '.');
|
||||
|
||||
/* If it exists, extract the devad(s) */
|
||||
if (regstr) {
|
||||
char devadstr[32];
|
||||
|
||||
strncpy(devadstr, input, regstr - input);
|
||||
devadstr[regstr - input] = '\0';
|
||||
|
||||
if (extract_range(devadstr, devadlo, devadhi))
|
||||
return -1;
|
||||
|
||||
regstr++;
|
||||
} else {
|
||||
/* Otherwise, we have no devad, and we just got regs */
|
||||
*devadlo = *devadhi = MDIO_DEVAD_NONE;
|
||||
|
||||
regstr = input;
|
||||
}
|
||||
|
||||
return extract_range(regstr, reglo, reghi);
|
||||
}
|
||||
|
||||
static int extract_phy_range(char *const argv[], int argc, struct mii_dev **bus,
|
||||
struct phy_device **phydev,
|
||||
int *addrlo, int *addrhi)
|
||||
{
|
||||
struct phy_device *dev = *phydev;
|
||||
|
||||
if ((argc < 1) || (argc > 2))
|
||||
return -1;
|
||||
|
||||
/* If there are two arguments, it's busname addr */
|
||||
if (argc == 2) {
|
||||
*bus = miiphy_get_dev_by_name(argv[0]);
|
||||
|
||||
if (!*bus)
|
||||
return -1;
|
||||
|
||||
return extract_range(argv[1], addrlo, addrhi);
|
||||
}
|
||||
|
||||
/* It must be one argument, here */
|
||||
|
||||
/*
|
||||
* This argument can be one of two things:
|
||||
* 1) Ethernet device name
|
||||
* 2) Just an address (use the previously-used bus)
|
||||
*
|
||||
* We check all buses for a PHY which is connected to an ethernet
|
||||
* device by the given name. If none are found, we call
|
||||
* extract_range() on the string, and see if it's an address range.
|
||||
*/
|
||||
dev = mdio_phydev_for_ethname(argv[0]);
|
||||
|
||||
if (dev) {
|
||||
*addrlo = *addrhi = dev->addr;
|
||||
*bus = dev->bus;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* It's an address or nothing useful */
|
||||
return extract_range(argv[0], addrlo, addrhi);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
static int do_mdio(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
char op[2];
|
||||
int addrlo, addrhi, reglo, reghi, devadlo, devadhi;
|
||||
unsigned short data;
|
||||
int pos = argc - 1;
|
||||
struct mii_dev *bus;
|
||||
struct phy_device *phydev = NULL;
|
||||
int extended = 0;
|
||||
|
||||
if (argc < 2)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
#ifdef CONFIG_DM_MDIO
|
||||
/* probe DM MII device before any operation so they are all accesible */
|
||||
dm_mdio_probe_devices();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We use the last specified parameters, unless new ones are
|
||||
* entered.
|
||||
*/
|
||||
op[0] = argv[1][0];
|
||||
addrlo = last_addr_lo;
|
||||
addrhi = last_addr_hi;
|
||||
devadlo = last_devad_lo;
|
||||
devadhi = last_devad_hi;
|
||||
reglo = last_reg_lo;
|
||||
reghi = last_reg_hi;
|
||||
data = last_data;
|
||||
|
||||
bus = mdio_get_current_dev();
|
||||
|
||||
if (flag & CMD_FLAG_REPEAT)
|
||||
op[0] = last_op[0];
|
||||
|
||||
if (strlen(argv[1]) > 1) {
|
||||
op[1] = argv[1][1];
|
||||
if (op[1] == 'x') {
|
||||
phydev = mdio_phydev_for_ethname(argv[2]);
|
||||
|
||||
if (phydev) {
|
||||
addrlo = phydev->addr;
|
||||
addrhi = addrlo;
|
||||
bus = phydev->bus;
|
||||
extended = 1;
|
||||
} else {
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
if (!phydev->drv ||
|
||||
(!phydev->drv->writeext && (op[0] == 'w')) ||
|
||||
(!phydev->drv->readext && (op[0] == 'r'))) {
|
||||
puts("PHY does not have extended functions\n");
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (op[0]) {
|
||||
case 'w':
|
||||
if (pos > 1)
|
||||
data = simple_strtoul(argv[pos--], NULL, 16);
|
||||
/* Intentional fall-through - Get reg for read and write */
|
||||
case 'r':
|
||||
if (pos > 1)
|
||||
if (extract_reg_range(argv[pos--], &devadlo, &devadhi,
|
||||
®lo, ®hi))
|
||||
return CMD_RET_FAILURE;
|
||||
/* Intentional fall-through - Get phy for all commands */
|
||||
default:
|
||||
if (pos > 1)
|
||||
if (extract_phy_range(&argv[2], pos - 1, &bus,
|
||||
&phydev, &addrlo, &addrhi))
|
||||
return CMD_RET_FAILURE;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (!bus) {
|
||||
puts("No MDIO bus found\n");
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
if (op[0] == 'l') {
|
||||
mdio_list_devices();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Save the chosen bus */
|
||||
miiphy_set_current_dev(bus->name);
|
||||
|
||||
switch (op[0]) {
|
||||
case 'w':
|
||||
mdio_write_ranges(bus, addrlo, addrhi, devadlo, devadhi,
|
||||
reglo, reghi, data, extended);
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
mdio_read_ranges(bus, addrlo, addrhi, devadlo, devadhi,
|
||||
reglo, reghi, extended);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Save the parameters for repeats.
|
||||
*/
|
||||
last_op[0] = op[0];
|
||||
last_addr_lo = addrlo;
|
||||
last_addr_hi = addrhi;
|
||||
last_devad_lo = devadlo;
|
||||
last_devad_hi = devadhi;
|
||||
last_reg_lo = reglo;
|
||||
last_reg_hi = reghi;
|
||||
last_data = data;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***************************************************/
|
||||
|
||||
U_BOOT_CMD(
|
||||
mdio, 6, 1, do_mdio,
|
||||
"MDIO utility commands",
|
||||
"list - List MDIO buses\n"
|
||||
"mdio read <phydev> [<devad>.]<reg> - "
|
||||
"read PHY's register at <devad>.<reg>\n"
|
||||
"mdio write <phydev> [<devad>.]<reg> <data> - "
|
||||
"write PHY's register at <devad>.<reg>\n"
|
||||
"mdio rx <phydev> [<devad>.]<reg> - "
|
||||
"read PHY's extended register at <devad>.<reg>\n"
|
||||
"mdio wx <phydev> [<devad>.]<reg> <data> - "
|
||||
"write PHY's extended register at <devad>.<reg>\n"
|
||||
"<phydev> may be:\n"
|
||||
" <busname> <addr>\n"
|
||||
" <addr>\n"
|
||||
" <eth name>\n"
|
||||
"<addr> <devad>, and <reg> may be ranges, e.g. 1-5.4-0x1f.\n"
|
||||
);
|
||||
387
cmd/mfsl.c
Normal file
387
cmd/mfsl.c
Normal file
@@ -0,0 +1,387 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2007 Michal Simek
|
||||
*
|
||||
* Michal SIMEK <monstr@monstr.eu>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Microblaze FSL support
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <config.h>
|
||||
#include <command.h>
|
||||
#include <asm/asm.h>
|
||||
|
||||
int do_frd (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
unsigned int fslnum;
|
||||
unsigned int num;
|
||||
unsigned int blocking;
|
||||
|
||||
if (argc < 2)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
fslnum = (unsigned int)simple_strtoul (argv[1], NULL, 16);
|
||||
blocking = (unsigned int)simple_strtoul (argv[2], NULL, 16);
|
||||
if (fslnum < 0 || fslnum >= XILINX_FSL_NUMBER) {
|
||||
puts ("Bad number of FSL\n");
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
switch (fslnum) {
|
||||
#if (XILINX_FSL_NUMBER > 0)
|
||||
case 0:
|
||||
switch (blocking) {
|
||||
case 0: NGET (num, 0);
|
||||
break;
|
||||
case 1: NCGET (num, 0);
|
||||
break;
|
||||
case 2: GET (num, 0);
|
||||
break;
|
||||
case 3: CGET (num, 0);
|
||||
break;
|
||||
default:
|
||||
return 2;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#if (XILINX_FSL_NUMBER > 1)
|
||||
case 1:
|
||||
switch (blocking) {
|
||||
case 0: NGET (num, 1);
|
||||
break;
|
||||
case 1: NCGET (num, 1);
|
||||
break;
|
||||
case 2: GET (num, 1);
|
||||
break;
|
||||
case 3: CGET (num, 1);
|
||||
break;
|
||||
default:
|
||||
return 2;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#if (XILINX_FSL_NUMBER > 2)
|
||||
case 2:
|
||||
switch (blocking) {
|
||||
case 0: NGET (num, 2);
|
||||
break;
|
||||
case 1: NCGET (num, 2);
|
||||
break;
|
||||
case 2: GET (num, 2);
|
||||
break;
|
||||
case 3: CGET (num, 2);
|
||||
break;
|
||||
default:
|
||||
return 2;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#if (XILINX_FSL_NUMBER > 3)
|
||||
case 3:
|
||||
switch (blocking) {
|
||||
case 0: NGET (num, 3);
|
||||
break;
|
||||
case 1: NCGET (num, 3);
|
||||
break;
|
||||
case 2: GET (num, 3);
|
||||
break;
|
||||
case 3: CGET (num, 3);
|
||||
break;
|
||||
default:
|
||||
return 2;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#if (XILINX_FSL_NUMBER > 4)
|
||||
case 4:
|
||||
switch (blocking) {
|
||||
case 0: NGET (num, 4);
|
||||
break;
|
||||
case 1: NCGET (num, 4);
|
||||
break;
|
||||
case 2: GET (num, 4);
|
||||
break;
|
||||
case 3: CGET (num, 4);
|
||||
break;
|
||||
default:
|
||||
return 2;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#if (XILINX_FSL_NUMBER > 5)
|
||||
case 5:
|
||||
switch (blocking) {
|
||||
case 0: NGET (num, 5);
|
||||
break;
|
||||
case 1: NCGET (num, 5);
|
||||
break;
|
||||
case 2: GET (num, 5);
|
||||
break;
|
||||
case 3: CGET (num, 5);
|
||||
break;
|
||||
default:
|
||||
return 2;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#if (XILINX_FSL_NUMBER > 6)
|
||||
case 6:
|
||||
switch (blocking) {
|
||||
case 0: NGET (num, 6);
|
||||
break;
|
||||
case 1: NCGET (num, 6);
|
||||
break;
|
||||
case 2: GET (num, 6);
|
||||
break;
|
||||
case 3: CGET (num, 6);
|
||||
break;
|
||||
default:
|
||||
return 2;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#if (XILINX_FSL_NUMBER > 7)
|
||||
case 7:
|
||||
switch (blocking) {
|
||||
case 0: NGET (num, 7);
|
||||
break;
|
||||
case 1: NCGET (num, 7);
|
||||
break;
|
||||
case 2: GET (num, 7);
|
||||
break;
|
||||
case 3: CGET (num, 7);
|
||||
break;
|
||||
default:
|
||||
return 2;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf ("%01x: 0x%08x - %s %s read\n", fslnum, num,
|
||||
blocking < 2 ? "non blocking" : "blocking",
|
||||
((blocking == 1) || (blocking == 3)) ? "control" : "data" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
int do_fwr (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
unsigned int fslnum;
|
||||
unsigned int num;
|
||||
unsigned int blocking;
|
||||
|
||||
if (argc < 3)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
fslnum = (unsigned int)simple_strtoul (argv[1], NULL, 16);
|
||||
num = (unsigned int)simple_strtoul (argv[2], NULL, 16);
|
||||
blocking = (unsigned int)simple_strtoul (argv[3], NULL, 16);
|
||||
if (fslnum < 0 || fslnum >= XILINX_FSL_NUMBER)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
switch (fslnum) {
|
||||
#if (XILINX_FSL_NUMBER > 0)
|
||||
case 0:
|
||||
switch (blocking) {
|
||||
case 0: NPUT (num, 0);
|
||||
break;
|
||||
case 1: NCPUT (num, 0);
|
||||
break;
|
||||
case 2: PUT (num, 0);
|
||||
break;
|
||||
case 3: CPUT (num, 0);
|
||||
break;
|
||||
default:
|
||||
return 2;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#if (XILINX_FSL_NUMBER > 1)
|
||||
case 1:
|
||||
switch (blocking) {
|
||||
case 0: NPUT (num, 1);
|
||||
break;
|
||||
case 1: NCPUT (num, 1);
|
||||
break;
|
||||
case 2: PUT (num, 1);
|
||||
break;
|
||||
case 3: CPUT (num, 1);
|
||||
break;
|
||||
default:
|
||||
return 2;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#if (XILINX_FSL_NUMBER > 2)
|
||||
case 2:
|
||||
switch (blocking) {
|
||||
case 0: NPUT (num, 2);
|
||||
break;
|
||||
case 1: NCPUT (num, 2);
|
||||
break;
|
||||
case 2: PUT (num, 2);
|
||||
break;
|
||||
case 3: CPUT (num, 2);
|
||||
break;
|
||||
default:
|
||||
return 2;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#if (XILINX_FSL_NUMBER > 3)
|
||||
case 3:
|
||||
switch (blocking) {
|
||||
case 0: NPUT (num, 3);
|
||||
break;
|
||||
case 1: NCPUT (num, 3);
|
||||
break;
|
||||
case 2: PUT (num, 3);
|
||||
break;
|
||||
case 3: CPUT (num, 3);
|
||||
break;
|
||||
default:
|
||||
return 2;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#if (XILINX_FSL_NUMBER > 4)
|
||||
case 4:
|
||||
switch (blocking) {
|
||||
case 0: NPUT (num, 4);
|
||||
break;
|
||||
case 1: NCPUT (num, 4);
|
||||
break;
|
||||
case 2: PUT (num, 4);
|
||||
break;
|
||||
case 3: CPUT (num, 4);
|
||||
break;
|
||||
default:
|
||||
return 2;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#if (XILINX_FSL_NUMBER > 5)
|
||||
case 5:
|
||||
switch (blocking) {
|
||||
case 0: NPUT (num, 5);
|
||||
break;
|
||||
case 1: NCPUT (num, 5);
|
||||
break;
|
||||
case 2: PUT (num, 5);
|
||||
break;
|
||||
case 3: CPUT (num, 5);
|
||||
break;
|
||||
default:
|
||||
return 2;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#if (XILINX_FSL_NUMBER > 6)
|
||||
case 6:
|
||||
switch (blocking) {
|
||||
case 0: NPUT (num, 6);
|
||||
break;
|
||||
case 1: NCPUT (num, 6);
|
||||
break;
|
||||
case 2: PUT (num, 6);
|
||||
break;
|
||||
case 3: CPUT (num, 6);
|
||||
break;
|
||||
default:
|
||||
return 2;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#if (XILINX_FSL_NUMBER > 7)
|
||||
case 7:
|
||||
switch (blocking) {
|
||||
case 0: NPUT (num, 7);
|
||||
break;
|
||||
case 1: NCPUT (num, 7);
|
||||
break;
|
||||
case 2: PUT (num, 7);
|
||||
break;
|
||||
case 3: CPUT (num, 7);
|
||||
break;
|
||||
default:
|
||||
return 2;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf ("%01x: 0x%08x - %s %s write\n", fslnum, num,
|
||||
blocking < 2 ? "non blocking" : "blocking",
|
||||
((blocking == 1) || (blocking == 3)) ? "control" : "data" );
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int do_rspr (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
unsigned int reg = 0;
|
||||
unsigned int val = 0;
|
||||
|
||||
if (argc < 2)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
reg = (unsigned int)simple_strtoul (argv[1], NULL, 16);
|
||||
val = (unsigned int)simple_strtoul (argv[2], NULL, 16);
|
||||
switch (reg) {
|
||||
case 0x1:
|
||||
if (argc > 2) {
|
||||
MTS (val, rmsr);
|
||||
NOP;
|
||||
MFS (val, rmsr);
|
||||
} else {
|
||||
MFS (val, rmsr);
|
||||
}
|
||||
puts ("MSR");
|
||||
break;
|
||||
case 0x3:
|
||||
MFS (val, rear);
|
||||
puts ("EAR");
|
||||
break;
|
||||
case 0x5:
|
||||
MFS (val, resr);
|
||||
puts ("ESR");
|
||||
break;
|
||||
default:
|
||||
puts ("Unsupported register\n");
|
||||
return 1;
|
||||
}
|
||||
printf (": 0x%08x\n", val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***************************************************/
|
||||
|
||||
U_BOOT_CMD (frd, 3, 1, do_frd,
|
||||
"read data from FSL",
|
||||
"- [fslnum [0|1|2|3]]\n"
|
||||
" 0 - non blocking data read\n"
|
||||
" 1 - non blocking control read\n"
|
||||
" 2 - blocking data read\n"
|
||||
" 3 - blocking control read");
|
||||
|
||||
U_BOOT_CMD (fwr, 4, 1, do_fwr,
|
||||
"write data to FSL",
|
||||
"- [fslnum [0|1|2|3]]\n"
|
||||
" 0 - non blocking data write\n"
|
||||
" 1 - non blocking control write\n"
|
||||
" 2 - blocking data write\n"
|
||||
" 3 - blocking control write");
|
||||
|
||||
U_BOOT_CMD (rspr, 3, 1, do_rspr,
|
||||
"read/write special purpose register",
|
||||
"- reg_num [write value] read/write special purpose register\n"
|
||||
" 1 - MSR - Machine status register\n"
|
||||
" 3 - EAR - Exception address register\n"
|
||||
" 5 - ESR - Exception status register");
|
||||
478
cmd/mii.c
Normal file
478
cmd/mii.c
Normal file
@@ -0,0 +1,478 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2001
|
||||
* Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com
|
||||
*/
|
||||
|
||||
/*
|
||||
* MII Utilities
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <miiphy.h>
|
||||
|
||||
typedef struct _MII_field_desc_t {
|
||||
ushort hi;
|
||||
ushort lo;
|
||||
ushort mask;
|
||||
const char *name;
|
||||
} MII_field_desc_t;
|
||||
|
||||
static const MII_field_desc_t reg_0_desc_tbl[] = {
|
||||
{ 15, 15, 0x01, "reset" },
|
||||
{ 14, 14, 0x01, "loopback" },
|
||||
{ 13, 6, 0x81, "speed selection" }, /* special */
|
||||
{ 12, 12, 0x01, "A/N enable" },
|
||||
{ 11, 11, 0x01, "power-down" },
|
||||
{ 10, 10, 0x01, "isolate" },
|
||||
{ 9, 9, 0x01, "restart A/N" },
|
||||
{ 8, 8, 0x01, "duplex" }, /* special */
|
||||
{ 7, 7, 0x01, "collision test enable" },
|
||||
{ 5, 0, 0x3f, "(reserved)" }
|
||||
};
|
||||
|
||||
static const MII_field_desc_t reg_1_desc_tbl[] = {
|
||||
{ 15, 15, 0x01, "100BASE-T4 able" },
|
||||
{ 14, 14, 0x01, "100BASE-X full duplex able" },
|
||||
{ 13, 13, 0x01, "100BASE-X half duplex able" },
|
||||
{ 12, 12, 0x01, "10 Mbps full duplex able" },
|
||||
{ 11, 11, 0x01, "10 Mbps half duplex able" },
|
||||
{ 10, 10, 0x01, "100BASE-T2 full duplex able" },
|
||||
{ 9, 9, 0x01, "100BASE-T2 half duplex able" },
|
||||
{ 8, 8, 0x01, "extended status" },
|
||||
{ 7, 7, 0x01, "(reserved)" },
|
||||
{ 6, 6, 0x01, "MF preamble suppression" },
|
||||
{ 5, 5, 0x01, "A/N complete" },
|
||||
{ 4, 4, 0x01, "remote fault" },
|
||||
{ 3, 3, 0x01, "A/N able" },
|
||||
{ 2, 2, 0x01, "link status" },
|
||||
{ 1, 1, 0x01, "jabber detect" },
|
||||
{ 0, 0, 0x01, "extended capabilities" },
|
||||
};
|
||||
|
||||
static const MII_field_desc_t reg_2_desc_tbl[] = {
|
||||
{ 15, 0, 0xffff, "OUI portion" },
|
||||
};
|
||||
|
||||
static const MII_field_desc_t reg_3_desc_tbl[] = {
|
||||
{ 15, 10, 0x3f, "OUI portion" },
|
||||
{ 9, 4, 0x3f, "manufacturer part number" },
|
||||
{ 3, 0, 0x0f, "manufacturer rev. number" },
|
||||
};
|
||||
|
||||
static const MII_field_desc_t reg_4_desc_tbl[] = {
|
||||
{ 15, 15, 0x01, "next page able" },
|
||||
{ 14, 14, 0x01, "(reserved)" },
|
||||
{ 13, 13, 0x01, "remote fault" },
|
||||
{ 12, 12, 0x01, "(reserved)" },
|
||||
{ 11, 11, 0x01, "asymmetric pause" },
|
||||
{ 10, 10, 0x01, "pause enable" },
|
||||
{ 9, 9, 0x01, "100BASE-T4 able" },
|
||||
{ 8, 8, 0x01, "100BASE-TX full duplex able" },
|
||||
{ 7, 7, 0x01, "100BASE-TX able" },
|
||||
{ 6, 6, 0x01, "10BASE-T full duplex able" },
|
||||
{ 5, 5, 0x01, "10BASE-T able" },
|
||||
{ 4, 0, 0x1f, "selector" },
|
||||
};
|
||||
|
||||
static const MII_field_desc_t reg_5_desc_tbl[] = {
|
||||
{ 15, 15, 0x01, "next page able" },
|
||||
{ 14, 14, 0x01, "acknowledge" },
|
||||
{ 13, 13, 0x01, "remote fault" },
|
||||
{ 12, 12, 0x01, "(reserved)" },
|
||||
{ 11, 11, 0x01, "asymmetric pause able" },
|
||||
{ 10, 10, 0x01, "pause able" },
|
||||
{ 9, 9, 0x01, "100BASE-T4 able" },
|
||||
{ 8, 8, 0x01, "100BASE-X full duplex able" },
|
||||
{ 7, 7, 0x01, "100BASE-TX able" },
|
||||
{ 6, 6, 0x01, "10BASE-T full duplex able" },
|
||||
{ 5, 5, 0x01, "10BASE-T able" },
|
||||
{ 4, 0, 0x1f, "partner selector" },
|
||||
};
|
||||
|
||||
static const MII_field_desc_t reg_9_desc_tbl[] = {
|
||||
{ 15, 13, 0x07, "test mode" },
|
||||
{ 12, 12, 0x01, "manual master/slave enable" },
|
||||
{ 11, 11, 0x01, "manual master/slave value" },
|
||||
{ 10, 10, 0x01, "multi/single port" },
|
||||
{ 9, 9, 0x01, "1000BASE-T full duplex able" },
|
||||
{ 8, 8, 0x01, "1000BASE-T half duplex able" },
|
||||
{ 7, 7, 0x01, "automatic TDR on link down" },
|
||||
{ 6, 6, 0x7f, "(reserved)" },
|
||||
};
|
||||
|
||||
static const MII_field_desc_t reg_10_desc_tbl[] = {
|
||||
{ 15, 15, 0x01, "master/slave config fault" },
|
||||
{ 14, 14, 0x01, "master/slave config result" },
|
||||
{ 13, 13, 0x01, "local receiver status OK" },
|
||||
{ 12, 12, 0x01, "remote receiver status OK" },
|
||||
{ 11, 11, 0x01, "1000BASE-T full duplex able" },
|
||||
{ 10, 10, 0x01, "1000BASE-T half duplex able" },
|
||||
{ 9, 8, 0x03, "(reserved)" },
|
||||
{ 7, 0, 0xff, "1000BASE-T idle error counter"},
|
||||
};
|
||||
|
||||
typedef struct _MII_reg_desc_t {
|
||||
ushort regno;
|
||||
const MII_field_desc_t *pdesc;
|
||||
ushort len;
|
||||
const char *name;
|
||||
} MII_reg_desc_t;
|
||||
|
||||
static const MII_reg_desc_t mii_reg_desc_tbl[] = {
|
||||
{ MII_BMCR, reg_0_desc_tbl, ARRAY_SIZE(reg_0_desc_tbl),
|
||||
"PHY control register" },
|
||||
{ MII_BMSR, reg_1_desc_tbl, ARRAY_SIZE(reg_1_desc_tbl),
|
||||
"PHY status register" },
|
||||
{ MII_PHYSID1, reg_2_desc_tbl, ARRAY_SIZE(reg_2_desc_tbl),
|
||||
"PHY ID 1 register" },
|
||||
{ MII_PHYSID2, reg_3_desc_tbl, ARRAY_SIZE(reg_3_desc_tbl),
|
||||
"PHY ID 2 register" },
|
||||
{ MII_ADVERTISE, reg_4_desc_tbl, ARRAY_SIZE(reg_4_desc_tbl),
|
||||
"Autonegotiation advertisement register" },
|
||||
{ MII_LPA, reg_5_desc_tbl, ARRAY_SIZE(reg_5_desc_tbl),
|
||||
"Autonegotiation partner abilities register" },
|
||||
{ MII_CTRL1000, reg_9_desc_tbl, ARRAY_SIZE(reg_9_desc_tbl),
|
||||
"1000BASE-T control register" },
|
||||
{ MII_STAT1000, reg_10_desc_tbl, ARRAY_SIZE(reg_10_desc_tbl),
|
||||
"1000BASE-T status register" },
|
||||
};
|
||||
|
||||
static void dump_reg(
|
||||
ushort regval,
|
||||
const MII_reg_desc_t *prd);
|
||||
|
||||
static bool special_field(ushort regno, const MII_field_desc_t *pdesc,
|
||||
ushort regval);
|
||||
|
||||
static void MII_dump(const ushort *regvals, uchar reglo, uchar reghi)
|
||||
{
|
||||
ulong i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(mii_reg_desc_tbl); i++) {
|
||||
const uchar reg = mii_reg_desc_tbl[i].regno;
|
||||
|
||||
if (reg >= reglo && reg <= reghi)
|
||||
dump_reg(regvals[reg - reglo], &mii_reg_desc_tbl[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Print out field position, value, name */
|
||||
static void dump_field(const MII_field_desc_t *pdesc, ushort regval)
|
||||
{
|
||||
if (pdesc->hi == pdesc->lo)
|
||||
printf("%2u ", pdesc->lo);
|
||||
else
|
||||
printf("%2u-%2u", pdesc->hi, pdesc->lo);
|
||||
|
||||
printf(" = %5u %s", (regval >> pdesc->lo) & pdesc->mask,
|
||||
pdesc->name);
|
||||
}
|
||||
|
||||
static void dump_reg(
|
||||
ushort regval,
|
||||
const MII_reg_desc_t *prd)
|
||||
{
|
||||
ulong i;
|
||||
ushort mask_in_place;
|
||||
const MII_field_desc_t *pdesc;
|
||||
|
||||
printf("%u. (%04hx) -- %s --\n",
|
||||
prd->regno, regval, prd->name);
|
||||
|
||||
for (i = 0; i < prd->len; i++) {
|
||||
pdesc = &prd->pdesc[i];
|
||||
|
||||
mask_in_place = pdesc->mask << pdesc->lo;
|
||||
|
||||
printf(" (%04hx:%04x) %u.",
|
||||
mask_in_place,
|
||||
regval & mask_in_place,
|
||||
prd->regno);
|
||||
|
||||
if (!special_field(prd->regno, pdesc, regval))
|
||||
dump_field(pdesc, regval);
|
||||
printf("\n");
|
||||
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/* Special fields:
|
||||
** 0.6,13
|
||||
** 0.8
|
||||
** 2.15-0
|
||||
** 3.15-0
|
||||
** 4.4-0
|
||||
** 5.4-0
|
||||
*/
|
||||
|
||||
static bool special_field(ushort regno, const MII_field_desc_t *pdesc,
|
||||
ushort regval)
|
||||
{
|
||||
const ushort sel_bits = (regval >> pdesc->lo) & pdesc->mask;
|
||||
|
||||
if ((regno == MII_BMCR) && (pdesc->lo == 6)) {
|
||||
ushort speed_bits = regval & (BMCR_SPEED1000 | BMCR_SPEED100);
|
||||
printf("%2u,%2u = b%u%u speed selection = %s Mbps",
|
||||
6, 13,
|
||||
(regval >> 6) & 1,
|
||||
(regval >> 13) & 1,
|
||||
speed_bits == BMCR_SPEED1000 ? "1000" :
|
||||
speed_bits == BMCR_SPEED100 ? "100" :
|
||||
"10");
|
||||
return 1;
|
||||
}
|
||||
|
||||
else if ((regno == MII_BMCR) && (pdesc->lo == 8)) {
|
||||
dump_field(pdesc, regval);
|
||||
printf(" = %s", ((regval >> pdesc->lo) & 1) ? "full" : "half");
|
||||
return 1;
|
||||
}
|
||||
|
||||
else if ((regno == MII_ADVERTISE) && (pdesc->lo == 0)) {
|
||||
dump_field(pdesc, regval);
|
||||
printf(" = %s",
|
||||
sel_bits == PHY_ANLPAR_PSB_802_3 ? "IEEE 802.3 CSMA/CD" :
|
||||
sel_bits == PHY_ANLPAR_PSB_802_9 ?
|
||||
"IEEE 802.9 ISLAN-16T" : "???");
|
||||
return 1;
|
||||
}
|
||||
|
||||
else if ((regno == MII_LPA) && (pdesc->lo == 0)) {
|
||||
dump_field(pdesc, regval);
|
||||
printf(" = %s",
|
||||
sel_bits == PHY_ANLPAR_PSB_802_3 ? "IEEE 802.3 CSMA/CD" :
|
||||
sel_bits == PHY_ANLPAR_PSB_802_9 ?
|
||||
"IEEE 802.9 ISLAN-16T" : "???");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char last_op[2];
|
||||
static uint last_data;
|
||||
static uint last_addr_lo;
|
||||
static uint last_addr_hi;
|
||||
static uint last_reg_lo;
|
||||
static uint last_reg_hi;
|
||||
static uint last_mask;
|
||||
|
||||
static void extract_range(
|
||||
char * input,
|
||||
unsigned char * plo,
|
||||
unsigned char * phi)
|
||||
{
|
||||
char * end;
|
||||
*plo = simple_strtoul(input, &end, 16);
|
||||
if (*end == '-') {
|
||||
end++;
|
||||
*phi = simple_strtoul(end, NULL, 16);
|
||||
}
|
||||
else {
|
||||
*phi = *plo;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
static int do_mii(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
char op[2];
|
||||
unsigned char addrlo, addrhi, reglo, reghi;
|
||||
unsigned char addr, reg;
|
||||
unsigned short data, mask;
|
||||
int rcode = 0;
|
||||
const char *devname;
|
||||
|
||||
if (argc < 2)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
#if defined(CONFIG_MII_INIT)
|
||||
mii_init ();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We use the last specified parameters, unless new ones are
|
||||
* entered.
|
||||
*/
|
||||
op[0] = last_op[0];
|
||||
op[1] = last_op[1];
|
||||
addrlo = last_addr_lo;
|
||||
addrhi = last_addr_hi;
|
||||
reglo = last_reg_lo;
|
||||
reghi = last_reg_hi;
|
||||
data = last_data;
|
||||
mask = last_mask;
|
||||
|
||||
if ((flag & CMD_FLAG_REPEAT) == 0) {
|
||||
op[0] = argv[1][0];
|
||||
if (strlen(argv[1]) > 1)
|
||||
op[1] = argv[1][1];
|
||||
else
|
||||
op[1] = '\0';
|
||||
|
||||
if (argc >= 3)
|
||||
extract_range(argv[2], &addrlo, &addrhi);
|
||||
if (argc >= 4)
|
||||
extract_range(argv[3], ®lo, ®hi);
|
||||
if (argc >= 5)
|
||||
data = simple_strtoul(argv[4], NULL, 16);
|
||||
if (argc >= 6)
|
||||
mask = simple_strtoul(argv[5], NULL, 16);
|
||||
}
|
||||
|
||||
if (addrhi > 31 && strncmp(op, "de", 2)) {
|
||||
printf("Incorrect PHY address. Range should be 0-31\n");
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
/* use current device */
|
||||
devname = miiphy_get_current_dev();
|
||||
|
||||
/*
|
||||
* check info/read/write.
|
||||
*/
|
||||
if (op[0] == 'i') {
|
||||
unsigned char j, start, end;
|
||||
unsigned int oui;
|
||||
unsigned char model;
|
||||
unsigned char rev;
|
||||
|
||||
/*
|
||||
* Look for any and all PHYs. Valid addresses are 0..31.
|
||||
*/
|
||||
if (argc >= 3) {
|
||||
start = addrlo; end = addrhi;
|
||||
} else {
|
||||
start = 0; end = 31;
|
||||
}
|
||||
|
||||
for (j = start; j <= end; j++) {
|
||||
if (miiphy_info (devname, j, &oui, &model, &rev) == 0) {
|
||||
printf("PHY 0x%02X: "
|
||||
"OUI = 0x%04X, "
|
||||
"Model = 0x%02X, "
|
||||
"Rev = 0x%02X, "
|
||||
"%3dbase%s, %s\n",
|
||||
j, oui, model, rev,
|
||||
miiphy_speed (devname, j),
|
||||
miiphy_is_1000base_x (devname, j)
|
||||
? "X" : "T",
|
||||
(miiphy_duplex (devname, j) == FULL)
|
||||
? "FDX" : "HDX");
|
||||
}
|
||||
}
|
||||
} else if (op[0] == 'r') {
|
||||
for (addr = addrlo; addr <= addrhi; addr++) {
|
||||
for (reg = reglo; reg <= reghi; reg++) {
|
||||
data = 0xffff;
|
||||
if (miiphy_read (devname, addr, reg, &data) != 0) {
|
||||
printf(
|
||||
"Error reading from the PHY addr=%02x reg=%02x\n",
|
||||
addr, reg);
|
||||
rcode = 1;
|
||||
} else {
|
||||
if ((addrlo != addrhi) || (reglo != reghi))
|
||||
printf("addr=%02x reg=%02x data=",
|
||||
(uint)addr, (uint)reg);
|
||||
printf("%04X\n", data & 0x0000FFFF);
|
||||
}
|
||||
}
|
||||
if ((addrlo != addrhi) && (reglo != reghi))
|
||||
printf("\n");
|
||||
}
|
||||
} else if (op[0] == 'w') {
|
||||
for (addr = addrlo; addr <= addrhi; addr++) {
|
||||
for (reg = reglo; reg <= reghi; reg++) {
|
||||
if (miiphy_write (devname, addr, reg, data) != 0) {
|
||||
printf("Error writing to the PHY addr=%02x reg=%02x\n",
|
||||
addr, reg);
|
||||
rcode = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (op[0] == 'm') {
|
||||
for (addr = addrlo; addr <= addrhi; addr++) {
|
||||
for (reg = reglo; reg <= reghi; reg++) {
|
||||
unsigned short val = 0;
|
||||
if (miiphy_read(devname, addr,
|
||||
reg, &val)) {
|
||||
printf("Error reading from the PHY");
|
||||
printf(" addr=%02x", addr);
|
||||
printf(" reg=%02x\n", reg);
|
||||
rcode = 1;
|
||||
} else {
|
||||
val = (val & ~mask) | (data & mask);
|
||||
if (miiphy_write(devname, addr,
|
||||
reg, val)) {
|
||||
printf("Error writing to the PHY");
|
||||
printf(" addr=%02x", addr);
|
||||
printf(" reg=%02x\n", reg);
|
||||
rcode = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (strncmp(op, "du", 2) == 0) {
|
||||
ushort regs[MII_STAT1000 + 1]; /* Last reg is 0x0a */
|
||||
int ok = 1;
|
||||
if (reglo > MII_STAT1000 || reghi > MII_STAT1000) {
|
||||
printf("The MII dump command only formats the standard MII registers, 0-5, 9-a.\n");
|
||||
return 1;
|
||||
}
|
||||
for (addr = addrlo; addr <= addrhi; addr++) {
|
||||
for (reg = reglo; reg <= reghi; reg++) {
|
||||
if (miiphy_read(devname, addr, reg,
|
||||
®s[reg - reglo]) != 0) {
|
||||
ok = 0;
|
||||
printf(
|
||||
"Error reading from the PHY addr=%02x reg=%02x\n",
|
||||
addr, reg);
|
||||
rcode = 1;
|
||||
}
|
||||
}
|
||||
if (ok)
|
||||
MII_dump(regs, reglo, reghi);
|
||||
printf("\n");
|
||||
}
|
||||
} else if (strncmp(op, "de", 2) == 0) {
|
||||
if (argc == 2)
|
||||
miiphy_listdev ();
|
||||
else
|
||||
miiphy_set_current_dev (argv[2]);
|
||||
} else {
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Save the parameters for repeats.
|
||||
*/
|
||||
last_op[0] = op[0];
|
||||
last_op[1] = op[1];
|
||||
last_addr_lo = addrlo;
|
||||
last_addr_hi = addrhi;
|
||||
last_reg_lo = reglo;
|
||||
last_reg_hi = reghi;
|
||||
last_data = data;
|
||||
last_mask = mask;
|
||||
|
||||
return rcode;
|
||||
}
|
||||
|
||||
/***************************************************/
|
||||
|
||||
U_BOOT_CMD(
|
||||
mii, 6, 1, do_mii,
|
||||
"MII utility commands",
|
||||
"device - list available devices\n"
|
||||
"mii device <devname> - set current device\n"
|
||||
"mii info <addr> - display MII PHY info\n"
|
||||
"mii read <addr> <reg> - read MII PHY <addr> register <reg>\n"
|
||||
"mii write <addr> <reg> <data> - write MII PHY <addr> register <reg>\n"
|
||||
"mii modify <addr> <reg> <data> <mask> - modify MII PHY <addr> register <reg>\n"
|
||||
" updating bits identified in <mask>\n"
|
||||
"mii dump <addr> <reg> - pretty-print <addr> <reg> (0-5 only)\n"
|
||||
"Addr and/or reg may be ranges, e.g. 2-7."
|
||||
);
|
||||
85
cmd/misc.c
Normal file
85
cmd/misc.c
Normal file
@@ -0,0 +1,85 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2001
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Misc functions
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <console.h>
|
||||
|
||||
static int do_sleep(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
ulong start = get_timer(0);
|
||||
ulong mdelay = 0;
|
||||
ulong delay;
|
||||
char *frpart;
|
||||
|
||||
if (argc != 2)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
delay = simple_strtoul(argv[1], NULL, 10) * CONFIG_SYS_HZ;
|
||||
|
||||
frpart = strchr(argv[1], '.');
|
||||
|
||||
if (frpart) {
|
||||
uint mult = CONFIG_SYS_HZ / 10;
|
||||
for (frpart++; *frpart != '\0' && mult > 0; frpart++) {
|
||||
if (*frpart < '0' || *frpart > '9') {
|
||||
mdelay = 0;
|
||||
break;
|
||||
}
|
||||
mdelay += (*frpart - '0') * mult;
|
||||
mult /= 10;
|
||||
}
|
||||
}
|
||||
|
||||
delay += mdelay;
|
||||
|
||||
while (get_timer(start) < delay) {
|
||||
if (ctrlc())
|
||||
return (-1);
|
||||
|
||||
udelay(100);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
sleep , 2, 1, do_sleep,
|
||||
"delay execution for some time",
|
||||
"N\n"
|
||||
" - delay execution for N seconds (N is _decimal_ and can be\n"
|
||||
" fractional)"
|
||||
);
|
||||
|
||||
#ifdef CONFIG_CMD_TIMER
|
||||
static int do_timer(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
static ulong start;
|
||||
|
||||
if (argc != 2)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
if (!strcmp(argv[1], "start"))
|
||||
start = get_timer(0);
|
||||
|
||||
if (!strcmp(argv[1], "get")) {
|
||||
ulong msecs = get_timer(start) * 1000 / CONFIG_SYS_HZ;
|
||||
printf("%ld.%03d\n", msecs / 1000, (int)(msecs % 1000));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
timer, 2, 1, do_timer,
|
||||
"access the system timer",
|
||||
"start - Reset the timer reference.\n"
|
||||
"timer get - Print the time since 'start'."
|
||||
);
|
||||
#endif
|
||||
95
cmd/mp.c
Normal file
95
cmd/mp.c
Normal file
@@ -0,0 +1,95 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2008-2009 Freescale Semiconductor, Inc.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <cpu_func.h>
|
||||
|
||||
static int cpu_status_all(void)
|
||||
{
|
||||
unsigned long cpuid;
|
||||
|
||||
for (cpuid = 0; ; cpuid++) {
|
||||
if (!is_core_valid(cpuid)) {
|
||||
if (cpuid == 0) {
|
||||
printf("Core num: %lu is not valid\n", cpuid);
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
cpu_status(cpuid);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
cpu_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
unsigned long cpuid;
|
||||
|
||||
if (argc == 2 && strncmp(argv[1], "status", 6) == 0)
|
||||
return cpu_status_all();
|
||||
|
||||
if (argc < 3)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
cpuid = simple_strtoul(argv[1], NULL, 10);
|
||||
if (!is_core_valid(cpuid)) {
|
||||
printf ("Core num: %lu is not valid\n", cpuid);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
if (argc == 3) {
|
||||
if (strncmp(argv[2], "reset", 5) == 0)
|
||||
cpu_reset(cpuid);
|
||||
else if (strncmp(argv[2], "status", 6) == 0)
|
||||
cpu_status(cpuid);
|
||||
else if (strncmp(argv[2], "disable", 7) == 0)
|
||||
return cpu_disable(cpuid);
|
||||
else
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 4 or greater, make sure its release */
|
||||
if (strncmp(argv[2], "release", 7) != 0)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
if (cpu_release(cpuid, argc - 3, argv + 3))
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SYS_LONGHELP
|
||||
static char cpu_help_text[] =
|
||||
"<num> reset - Reset cpu <num>\n"
|
||||
"cpu status - Status of all cpus\n"
|
||||
"cpu <num> status - Status of cpu <num>\n"
|
||||
"cpu <num> disable - Disable cpu <num>\n"
|
||||
"cpu <num> release <addr> [args] - Release cpu <num> at <addr> with [args]"
|
||||
#ifdef CONFIG_PPC
|
||||
"\n"
|
||||
" [args] : <pir> <r3> <r6>\n" \
|
||||
" pir - processor id (if writeable)\n" \
|
||||
" r3 - value for gpr 3\n" \
|
||||
" r6 - value for gpr 6\n" \
|
||||
"\n" \
|
||||
" Use '-' for any arg if you want the default value.\n" \
|
||||
" Default for r3 is <num> and r6 is 0\n" \
|
||||
"\n" \
|
||||
" When cpu <num> is released r4 and r5 = 0.\n" \
|
||||
" r7 will contain the size of the initial mapped area"
|
||||
#endif
|
||||
"";
|
||||
#endif
|
||||
|
||||
U_BOOT_CMD(
|
||||
cpu, CONFIG_SYS_MAXARGS, 1, cpu_cmd,
|
||||
"Multiprocessor CPU boot manipulation and release", cpu_help_text
|
||||
);
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user