summaryrefslogtreecommitdiff
path: root/cmd
diff options
context:
space:
mode:
Diffstat (limited to 'cmd')
-rw-r--r--cmd/Kconfig15
-rw-r--r--cmd/Makefile2
-rw-r--r--cmd/bootefi.c247
-rw-r--r--cmd/bootmenu.c42
-rw-r--r--cmd/conitrace.c4
-rw-r--r--cmd/disk.c1
-rw-r--r--cmd/efidebug.c13
-rw-r--r--cmd/gpt.c161
-rw-r--r--cmd/mbr.c314
-rw-r--r--cmd/pwm.c117
10 files changed, 754 insertions, 162 deletions
diff --git a/cmd/Kconfig b/cmd/Kconfig
index da86a940ce1..0625ee4050f 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -122,6 +122,7 @@ config CMD_CONSOLE
config CMD_CPU
bool "cpu"
+ depends on CPU
help
Print information about available CPUs. This normally shows the
number of CPUs, type (e.g. manufacturer, architecture, product or
@@ -927,6 +928,12 @@ config CMD_GPIO
help
GPIO support.
+config CMD_PWM
+ bool "pwm"
+ depends on DM_PWM
+ help
+ Control PWM channels, this allows invert/config/enable/disable PWM channels.
+
config CMD_GPT
bool "GPT (GUID Partition Table) command"
select EFI_PARTITION
@@ -1034,6 +1041,14 @@ config CMD_LSBLK
Print list of available block device drivers, and for each, the list
of known block devices.
+config CMD_MBR
+ bool "MBR (Master Boot Record) command"
+ select DOS_PARTITION
+ select HAVE_BLOCK_DEVICE
+ help
+ Enable the 'mbr' command to ready and write MBR (Master Boot Record)
+ style partition tables.
+
config CMD_MISC
bool "misc"
depends on MISC
diff --git a/cmd/Makefile b/cmd/Makefile
index 5b3400a8403..176bf925fdc 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -120,6 +120,7 @@ endif
obj-$(CONFIG_CMD_PINMUX) += pinmux.o
obj-$(CONFIG_CMD_PMC) += pmc.o
obj-$(CONFIG_CMD_PSTORE) += pstore.o
+obj-$(CONFIG_CMD_PWM) += pwm.o
obj-$(CONFIG_CMD_PXE) += pxe.o pxe_utils.o
obj-$(CONFIG_CMD_WOL) += wol.o
obj-$(CONFIG_CMD_QFW) += qfw.o
@@ -178,6 +179,7 @@ obj-$(CONFIG_CMD_ZFS) += zfs.o
obj-$(CONFIG_CMD_DFU) += dfu.o
obj-$(CONFIG_CMD_GPT) += gpt.o
+obj-$(CONFIG_CMD_MBR) += mbr.o
obj-$(CONFIG_CMD_ETHSW) += ethsw.o
obj-$(CONFIG_CMD_AXI) += axi.o
obj-$(CONFIG_CMD_PVBLOCK) += pvblock.o
diff --git a/cmd/bootefi.c b/cmd/bootefi.c
index fdf909f8da2..c8eb5c32b07 100644
--- a/cmd/bootefi.c
+++ b/cmd/bootefi.c
@@ -29,6 +29,82 @@ DECLARE_GLOBAL_DATA_PTR;
static struct efi_device_path *bootefi_image_path;
static struct efi_device_path *bootefi_device_path;
+static void *image_addr;
+static size_t image_size;
+
+/**
+ * efi_clear_bootdev() - clear boot device
+ */
+static void efi_clear_bootdev(void)
+{
+ efi_free_pool(bootefi_device_path);
+ efi_free_pool(bootefi_image_path);
+ bootefi_device_path = NULL;
+ bootefi_image_path = NULL;
+ image_addr = NULL;
+ image_size = 0;
+}
+
+/**
+ * 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
+ * @buffer: buffer with file loaded
+ * @buffer_size: size of file loaded
+ */
+void efi_set_bootdev(const char *dev, const char *devnr, const char *path,
+ void *buffer, size_t buffer_size)
+{
+ struct efi_device_path *device, *image;
+ efi_status_t ret;
+
+ /* Forget overwritten image */
+ if (buffer + buffer_size >= image_addr &&
+ image_addr + image_size >= buffer)
+ efi_clear_bootdev();
+
+ /* Remember only PE-COFF and FIT images */
+ if (efi_check_pe(buffer, buffer_size, NULL) != EFI_SUCCESS) {
+#ifdef CONFIG_FIT
+ if (!fit_check_format(buffer))
+ return;
+ /*
+ * FIT images of type EFI_OS are started via command bootm.
+ * We should not use their boot device with the bootefi command.
+ */
+ buffer = 0;
+ buffer_size = 0;
+#else
+ return;
+#endif
+ }
+
+ /* efi_set_bootdev() is typically called repeatedly, recover memory */
+ efi_clear_bootdev();
+
+ image_addr = buffer;
+ image_size = buffer_size;
+
+ 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 {
+ efi_clear_bootdev();
+ }
+}
/**
* efi_env_set_load_options() - set load options from environment variable
@@ -136,86 +212,6 @@ done:
}
/**
- * efi_reserve_memory() - add reserved memory to memory map
- *
- * @addr: start address of the reserved memory range
- * @size: size of the reserved memory range
- * @nomap: indicates that the memory range shall not be accessed by the
- * UEFI payload
- */
-static void efi_reserve_memory(u64 addr, u64 size, bool nomap)
-{
- int type;
- efi_uintn_t ret;
-
- /* Convert from sandbox address space. */
- addr = (uintptr_t)map_sysmem(addr, 0);
-
- if (nomap)
- type = EFI_RESERVED_MEMORY_TYPE;
- else
- type = EFI_BOOT_SERVICES_DATA;
-
- ret = efi_add_memory_map(addr, size, type);
- if (ret != EFI_SUCCESS)
- log_err("Reserved memory mapping failed addr %llx size %llx\n",
- addr, size);
-}
-
-/**
- * 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;
- u64 addr, size;
- int nodeoffset, subnode;
-
- 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;
- efi_reserve_memory(addr, size, false);
- }
-
- /* process reserved-memory */
- nodeoffset = fdt_subnode_offset(fdt, 0, "reserved-memory");
- if (nodeoffset >= 0) {
- subnode = fdt_first_subnode(fdt, nodeoffset);
- while (subnode >= 0) {
- fdt_addr_t fdt_addr;
- fdt_size_t fdt_size;
-
- /* check if this subnode has a reg property */
- fdt_addr = fdtdec_get_addr_size_auto_parent(
- fdt, nodeoffset, subnode,
- "reg", 0, &fdt_size, false);
- /*
- * The /reserved-memory node may have children with
- * a size instead of a reg property.
- */
- if (fdt_addr != FDT_ADDR_T_NONE &&
- fdtdec_get_is_enabled(fdt, subnode)) {
- bool nomap;
-
- nomap = !!fdt_getprop(fdt, subnode, "no-map",
- NULL);
- efi_reserve_memory(fdt_addr, fdt_size, nomap);
- }
- subnode = fdt_next_subnode(fdt, subnode);
- }
- }
-}
-
-/**
* get_config_table() - get configuration table
*
* @guid: GUID of the configuration table
@@ -398,43 +394,28 @@ static int do_bootefi_image(const char *image_opt)
{
void *image_buf;
unsigned long addr, size;
- const char *size_str;
efi_status_t ret;
#ifdef CONFIG_CMD_BOOTEFI_HELLO
if (!strcmp(image_opt, "hello")) {
- char *saddr;
-
- saddr = env_get("loadaddr");
+ image_buf = __efi_helloworld_begin;
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);
-
- efi_free_pool(bootefi_device_path);
- efi_free_pool(bootefi_image_path);
- bootefi_device_path = NULL;
- bootefi_image_path = NULL;
+ efi_clear_bootdev();
} 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);
+ addr = strtoul(image_opt, NULL, 16);
/* Check that a numeric value was passed */
- if (!addr && *image_opt != '0')
+ if (!addr)
return CMD_RET_USAGE;
- image_buf = map_sysmem(addr, size);
+ image_buf = map_sysmem(addr, 0);
+
+ if (image_buf != image_addr) {
+ log_err("No UEFI binary known at %s\n", image_opt);
+ return CMD_RET_FAILURE;
+ }
+ size = image_size;
}
ret = efi_run_image(image_buf, size);
@@ -567,11 +548,8 @@ static efi_status_t bootefi_test_prepare
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;
+ efi_clear_bootdev();
return ret;
}
@@ -653,10 +631,12 @@ static int do_bootefi(struct cmd_tbl *cmdtp, int flag, int argc,
else if (ret != EFI_SUCCESS)
return CMD_RET_FAILURE;
- if (!strcmp(argv[1], "bootmgr"))
- return do_efibootmgr();
+ if (IS_ENABLED(CONFIG_CMD_BOOTEFI_BOOTMGR)) {
+ if (!strcmp(argv[1], "bootmgr"))
+ return do_efibootmgr();
+ }
#ifdef CONFIG_CMD_BOOTEFI_SELFTEST
- else if (!strcmp(argv[1], "selftest"))
+ if (!strcmp(argv[1], "selftest"))
return do_efi_selftest();
#endif
@@ -679,11 +659,14 @@ static char bootefi_help_text[] =
" Use environment variable efi_selftest to select a single test.\n"
" Use 'setenv efi_selftest list' to enumerate all tests.\n"
#endif
+#ifdef CONFIG_CMD_BOOTEFI_BOOTMGR
"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";
+ " exposed as EFI configuration table.\n"
+#endif
+ ;
#endif
U_BOOT_CMD(
@@ -691,39 +674,3 @@ U_BOOT_CMD(
"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;
- }
-}
diff --git a/cmd/bootmenu.c b/cmd/bootmenu.c
index 1ba7b622e50..409ef9a8480 100644
--- a/cmd/bootmenu.c
+++ b/cmd/bootmenu.c
@@ -45,6 +45,7 @@ enum bootmenu_key {
KEY_UP,
KEY_DOWN,
KEY_SELECT,
+ KEY_QUIT,
};
static char *bootmenu_getoption(unsigned short int n)
@@ -109,6 +110,9 @@ static void bootmenu_autoboot_loop(struct bootmenu_data *menu,
case '\r':
*key = KEY_SELECT;
break;
+ case 0x3: /* ^C */
+ *key = KEY_QUIT;
+ break;
default:
*key = KEY_NONE;
break;
@@ -136,13 +140,25 @@ static void bootmenu_loop(struct bootmenu_data *menu,
{
int c;
- while (!tstc()) {
- WATCHDOG_RESET();
- mdelay(10);
+ if (*esc == 1) {
+ if (tstc()) {
+ c = getchar();
+ } else {
+ WATCHDOG_RESET();
+ mdelay(10);
+ if (tstc())
+ c = getchar();
+ else
+ c = '\e';
+ }
+ } else {
+ while (!tstc()) {
+ WATCHDOG_RESET();
+ mdelay(10);
+ }
+ c = getchar();
}
- c = getchar();
-
switch (*esc) {
case 0:
/* First char of ANSI escape sequence '\e' */
@@ -157,7 +173,9 @@ static void bootmenu_loop(struct bootmenu_data *menu,
*esc = 2;
*key = KEY_NONE;
} else {
- *esc = 0;
+ /* Alone ESC key was pressed */
+ *key = KEY_QUIT;
+ *esc = (c == '\e') ? 1 : 0;
}
break;
case 2:
@@ -187,6 +205,10 @@ static void bootmenu_loop(struct bootmenu_data *menu,
/* enter key was pressed */
if (c == '\r')
*key = KEY_SELECT;
+
+ /* ^C was pressed */
+ if (c == 0x3)
+ *key = KEY_QUIT;
}
static char *bootmenu_choice_entry(void *data)
@@ -222,6 +244,12 @@ static char *bootmenu_choice_entry(void *data)
for (i = 0; i < menu->active; ++i)
iter = iter->next;
return iter->key;
+ case KEY_QUIT:
+ /* Quit by choosing the last entry - U-Boot console */
+ iter = menu->first;
+ while (iter->next)
+ iter = iter->next;
+ return iter->key;
default:
break;
}
@@ -389,7 +417,7 @@ static void menu_display_statusline(struct menu *m)
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(" Press UP/DOWN to move, ENTER to select, ESC/CTRL+C to quit");
puts(ANSI_CLEAR_LINE_TO_END);
printf(ANSI_CURSOR_POSITION, menu->count + 7, 1);
puts(ANSI_CLEAR_LINE);
diff --git a/cmd/conitrace.c b/cmd/conitrace.c
index 811f5c68a9c..d50f3bf3ccb 100644
--- a/cmd/conitrace.c
+++ b/cmd/conitrace.c
@@ -30,8 +30,8 @@ static int do_conitrace(struct cmd_tbl *cmdtp, int flag, int argc,
printf("%02x ", c);
first = false;
- /* 1 ms delay - serves to detect separate keystrokes */
- udelay(1000);
+ /* 10 ms delay - serves to detect separate keystrokes */
+ udelay(10000);
if (!tstc()) {
printf("\n");
first = true;
diff --git a/cmd/disk.c b/cmd/disk.c
index 8060e753ebd..0bc3808dfe2 100644
--- a/cmd/disk.c
+++ b/cmd/disk.c
@@ -120,7 +120,6 @@ int common_diskboot(struct cmd_tbl *cmdtp, const char *intf, int argc,
return 1;
}
bootstage_mark(BOOTSTAGE_ID_IDE_FIT_READ_OK);
- fit_print_contents(fit_hdr);
}
#endif
diff --git a/cmd/efidebug.c b/cmd/efidebug.c
index 5fb7b1e3c6a..9a2d4ddd5ef 100644
--- a/cmd/efidebug.c
+++ b/cmd/efidebug.c
@@ -8,6 +8,7 @@
#include <charset.h>
#include <common.h>
#include <command.h>
+#include <efi_dt_fixup.h>
#include <efi_loader.h>
#include <efi_rng.h>
#include <exports.h>
@@ -495,6 +496,10 @@ static const struct {
"PXE Base Code",
EFI_PXE_BASE_CODE_PROTOCOL_GUID,
},
+ {
+ "Device-Tree Fixup",
+ EFI_DT_FIXUP_PROTOCOL_GUID,
+ },
/* Configuration table GUIDs */
{
"ACPI table",
@@ -1362,8 +1367,8 @@ static int do_efi_boot_opt(struct cmd_tbl *cmdtp, int flag,
*
* efidebug test bootmgr
*/
-static int do_efi_test_bootmgr(struct cmd_tbl *cmdtp, int flag,
- int argc, char * const argv[])
+static __maybe_unused int do_efi_test_bootmgr(struct cmd_tbl *cmdtp, int flag,
+ int argc, char * const argv[])
{
efi_handle_t image;
efi_uintn_t exit_data_size = 0;
@@ -1387,8 +1392,10 @@ static int do_efi_test_bootmgr(struct cmd_tbl *cmdtp, int flag,
}
static struct cmd_tbl cmd_efidebug_test_sub[] = {
+#ifdef CONFIG_CMD_BOOTEFI_BOOTMGR
U_BOOT_CMD_MKENT(bootmgr, CONFIG_SYS_MAXARGS, 1, do_efi_test_bootmgr,
"", ""),
+#endif
};
/**
@@ -1576,8 +1583,10 @@ static char efidebug_help_text[] =
" - show UEFI memory map\n"
"efidebug tables\n"
" - show UEFI configuration tables\n"
+#ifdef CONFIG_CMD_BOOTEFI_BOOTMGR
"efidebug test bootmgr\n"
" - run simple bootmgr for test\n"
+#endif
"efidebug query [-nv][-bs][-rt][-at]\n"
" - show size of UEFI variables store\n";
#endif
diff --git a/cmd/gpt.c b/cmd/gpt.c
index df759416c88..76a95ade6c2 100644
--- a/cmd/gpt.c
+++ b/cmd/gpt.c
@@ -18,6 +18,7 @@
#include <command.h>
#include <part.h>
#include <part_efi.h>
+#include <part.h>
#include <exports.h>
#include <uuid.h>
#include <linux/ctype.h>
@@ -621,6 +622,152 @@ static int gpt_verify(struct blk_desc *blk_dev_desc, const char *str_part)
return ret;
}
+/**
+ * gpt_enumerate() - Enumerate partition names into environment variable.
+ *
+ * Enumerate partition names. Partition names are stored in gpt_partition_list
+ * environment variable. Each partition name is delimited by space.
+ *
+ * @desc: block device descriptor
+ *
+ * @Return: '0' on success and -ve error on failure
+ */
+static int gpt_enumerate(struct blk_desc *desc)
+{
+ struct part_driver *first_drv, *part_drv;
+ int str_len = 0, tmp_len;
+ char part_list[2048];
+ int n_drvs;
+ char *ptr;
+
+ part_list[0] = 0;
+ n_drvs = part_driver_get_count();
+ if (!n_drvs) {
+ printf("Failed to get partition driver count\n");
+ return -ENOENT;
+ }
+
+ first_drv = part_driver_get_first();
+ for (part_drv = first_drv; part_drv != first_drv + n_drvs; part_drv++) {
+ struct disk_partition pinfo;
+ int ret;
+ int i;
+
+ for (i = 1; i < part_drv->max_entries; i++) {
+ ret = part_drv->get_info(desc, i, &pinfo);
+ if (ret) {
+ /* no more entries in table */
+ break;
+ }
+
+ ptr = &part_list[str_len];
+ tmp_len = strlen((const char *)pinfo.name);
+ str_len += tmp_len;
+ /* +1 for space */
+ str_len++;
+ if (str_len > sizeof(part_list)) {
+ printf("Error insufficient memory\n");
+ return -ENOMEM;
+ }
+ strcpy(ptr, (const char *)pinfo.name);
+ /* One byte for space(" ") delimiter */
+ ptr[tmp_len] = ' ';
+ }
+ }
+ if (*part_list)
+ part_list[strlen(part_list) - 1] = 0;
+ debug("setenv gpt_partition_list %s\n", part_list);
+
+ return env_set("gpt_partition_list", part_list);
+}
+
+/**
+ * gpt_setenv_part_variables() - setup partition environmental variables
+ *
+ * Setup the gpt_partition_name, gpt_partition_entry, gpt_partition_addr
+ * and gpt_partition_size environment variables.
+ *
+ * @pinfo: pointer to disk partition
+ * @i: partition entry
+ *
+ * @Return: '0' on success and -ENOENT on failure
+ */
+static int gpt_setenv_part_variables(struct disk_partition *pinfo, int i)
+{
+ int ret;
+
+ ret = env_set_hex("gpt_partition_addr", pinfo->start);
+ if (ret)
+ goto fail;
+
+ ret = env_set_hex("gpt_partition_size", pinfo->size);
+ if (ret)
+ goto fail;
+
+ ret = env_set_ulong("gpt_partition_entry", i);
+ if (ret)
+ goto fail;
+
+ ret = env_set("gpt_partition_name", (const char *)pinfo->name);
+ if (ret)
+ goto fail;
+
+ return 0;
+
+fail:
+ return -ENOENT;
+}
+
+/**
+ * gpt_setenv() - Dynamically setup environment variables.
+ *
+ * Dynamically setup environment variables for name, index, offset and size
+ * for partition in GPT table after running "gpt setenv" for a partition name.
+ *
+ * @desc: block device descriptor
+ * @name: partition name
+ *
+ * @Return: '0' on success and -ve err on failure
+ */
+static int gpt_setenv(struct blk_desc *desc, const char *name)
+{
+ struct part_driver *first_drv, *part_drv;
+ int n_drvs;
+ int ret = -1;
+
+ n_drvs = part_driver_get_count();
+ if (!n_drvs) {
+ printf("Failed to get partition driver count\n");
+ goto fail;
+ }
+
+ first_drv = part_driver_get_first();
+ for (part_drv = first_drv; part_drv != first_drv + n_drvs; part_drv++) {
+ struct disk_partition pinfo;
+ int i;
+
+ for (i = 1; i < part_drv->max_entries; i++) {
+ ret = part_drv->get_info(desc, i, &pinfo);
+ if (ret) {
+ /* no more entries in table */
+ break;
+ }
+
+ if (!strcmp(name, (const char *)pinfo.name)) {
+ /* match found, setup environment variables */
+ ret = gpt_setenv_part_variables(&pinfo, i);
+ if (ret)
+ goto fail;
+
+ return 0;
+ }
+ }
+ }
+
+fail:
+ return ret;
+}
+
static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)
{
int ret;
@@ -827,6 +974,10 @@ static int do_gpt(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
} else if ((strcmp(argv[1], "verify") == 0)) {
ret = gpt_verify(blk_dev_desc, argv[4]);
printf("Verify GPT: ");
+ } else if ((strcmp(argv[1], "setenv") == 0)) {
+ ret = gpt_setenv(blk_dev_desc, argv[4]);
+ } else if ((strcmp(argv[1], "enumerate") == 0)) {
+ ret = gpt_enumerate(blk_dev_desc);
} else if (strcmp(argv[1], "guid") == 0) {
ret = do_disk_guid(blk_dev_desc, argv[4]);
#ifdef CONFIG_CMD_GPT_RENAME
@@ -857,7 +1008,17 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
" to interface\n"
" Example usage:\n"
" gpt write mmc 0 $partitions\n"
+ " - write the GPT to device\n"
" gpt verify mmc 0 $partitions\n"
+ " - verify the GPT on device against $partitions\n"
+ " gpt setenv mmc 0 $name\n"
+ " - setup environment variables for partition $name:\n"
+ " gpt_partition_addr, gpt_partition_size,\n"
+ " gpt_partition_name, gpt_partition_entry\n"
+ " gpt enumerate mmc 0\n"
+ " - store list of partitions to gpt_partition_list environment variable\n"
+ " read <interface> <dev>\n"
+ " - read GPT into a data structure for manipulation\n"
" gpt guid <interface> <dev>\n"
" - print disk GUID\n"
" gpt guid <interface> <dev> <varname>\n"
diff --git a/cmd/mbr.c b/cmd/mbr.c
new file mode 100644
index 00000000000..da2e3a4722b
--- /dev/null
+++ b/cmd/mbr.c
@@ -0,0 +1,314 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * cmd_mbr.c -- MBR (Master Boot Record) handling command
+ *
+ * Copyright (C) 2020 Samsung Electronics
+ * author: Marek Szyprowski <m.szyprowski@samsung.com>
+ *
+ * based on the gpt command.
+ */
+
+#include <common.h>
+#include <blk.h>
+#include <command.h>
+#include <malloc.h>
+#include <part.h>
+
+/**
+ * extract_val() - Extract a value from the key=value pair list
+ * @str: pointer to string with key=values pairs
+ * @key: pointer to the key to search for
+ *
+ * The list of parameters is come separated, only a value for
+ * the given key is returend.
+ *
+ * Function allocates memory for the value, remember to free!
+ *
+ * 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() - Search for a key without a value in the parameter list
+ * @str: pointer to string with key
+ * @key: pointer to the key to search for
+ *
+ * The list of parameters is come separated.
+ *
+ * Return: True if key has been found.
+ */
+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 str_to_partitions(const char *str_part, int blksz,
+ unsigned long *disk_uuid, struct disk_partition **partitions,
+ int *parts_count)
+{
+ char *tok, *str, *s;
+ int i;
+ char *val, *p;
+ int p_count;
+ struct disk_partition *parts;
+ int errno = 0;
+ uint64_t size_ll, start_ll;
+
+ 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) {
+ val = strsep(&val, ";");
+ p = val;
+ *disk_uuid = ustrtoull(p, &p, 0);
+ free(val);
+ /* Move s to first partition */
+ strsep(&s, ";");
+ }
+ if (s == NULL) {
+ printf("Error: is the partitions string NULL-terminated?\n");
+ return -EINVAL;
+ }
+
+ /* remove the optional semicolon at the end of the string */
+ i = strlen(s) - 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(struct disk_partition), 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;
+
+ /* size */
+ val = extract_val(tok, "size");
+ if (!val) { /* 'size' is mandatory */
+ errno = -4;
+ goto err;
+ }
+ p = val;
+ if ((strcmp(p, "-") == 0)) {
+ /* auto extend the size */
+ parts[i].size = 0;
+ } else {
+ size_ll = ustrtoull(p, &p, 0);
+ parts[i].size = size_ll / blksz;
+ }
+ free(val);
+
+ /* start address */
+ val = extract_val(tok, "start");
+ if (val) { /* start address is optional */
+ p = val;
+ start_ll = ustrtoull(p, &p, 0);
+ parts[i].start = start_ll / blksz;
+ free(val);
+ }
+
+ /* system id */
+ val = extract_val(tok, "id");
+ if (!val) { /* '' is mandatory */
+ errno = -4;
+ goto err;
+ }
+ p = val;
+ parts[i].sys_ind = ustrtoul(p, &p, 0);
+ free(val);
+
+ /* bootable */
+ if (found_key(tok, "bootable"))
+ parts[i].bootable = PART_BOOTABLE;
+ }
+
+ *parts_count = p_count;
+ *partitions = parts;
+ free(str);
+
+ return 0;
+err:
+ free(str);
+ free(parts);
+
+ return errno;
+}
+
+static int do_write_mbr(struct blk_desc *dev, const char *str)
+{
+ unsigned long disk_uuid = 0;
+ struct disk_partition *partitions;
+ int blksz = dev->blksz;
+ int count;
+
+ if (str_to_partitions(str, blksz, &disk_uuid, &partitions, &count)) {
+ printf("MBR: failed to setup partitions from \"%s\"\n", str);
+ return -1;
+ }
+
+ if (layout_mbr_partitions(partitions, count, dev->lba)) {
+ printf("MBR: failed to layout partitions on the device\n");
+ free(partitions);
+ return -1;
+ }
+
+ if (write_mbr_partitions(dev, partitions, count, disk_uuid)) {
+ printf("MBR: failed to write partitions to the device\n");
+ free(partitions);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int do_verify_mbr(struct blk_desc *dev, const char *str)
+{
+ unsigned long disk_uuid = 0;
+ struct disk_partition *partitions;
+ int blksz = dev->blksz;
+ int count, i, ret = 1;
+
+ if (str_to_partitions(str, blksz, &disk_uuid, &partitions, &count)) {
+ printf("MBR: failed to setup partitions from \"%s\"\n", str);
+ return -1;
+ }
+
+ for (i = 0; i < count; i++) {
+ struct disk_partition p;
+
+ if (part_get_info(dev, i+1, &p))
+ goto fail;
+
+ if ((partitions[i].size && p.size < partitions[i].size) ||
+ (partitions[i].start && p.start < partitions[i].start) ||
+ (p.sys_ind != partitions[i].sys_ind))
+ goto fail;
+ }
+ ret = 0;
+fail:
+ free(partitions);
+ return ret;
+}
+
+static int do_mbr(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
+{
+ const char *parts = NULL;
+ int ret = CMD_RET_SUCCESS;
+ int dev = 0;
+ char *ep;
+ struct blk_desc *blk_dev_desc = NULL;
+
+ if (argc != 4 && argc != 5)
+ 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)) {
+ parts = (argc == 5) ? argv[4] : env_get("mbr_parts");
+ printf("MBR: write ");
+ ret = do_write_mbr(blk_dev_desc, parts);
+ } else if ((strcmp(argv[1], "verify") == 0)) {
+ printf("MBR: verify ");
+ parts = (argc == 5) ? argv[4] : env_get("mbr_parts");
+ ret = do_verify_mbr(blk_dev_desc, parts);
+ } else {
+ return CMD_RET_USAGE;
+ }
+
+ if (ret) {
+ printf("error!\n");
+ return CMD_RET_FAILURE;
+ }
+
+ printf("success!\n");
+ return CMD_RET_SUCCESS;
+}
+
+U_BOOT_CMD(mbr, CONFIG_SYS_MAXARGS, 1, do_mbr,
+ "MBR (Master Boot Record)",
+ "<command> <interface> <dev> <partitions_list>\n"
+ " - MBR partition table restoration utility\n"
+ " Restore or check partition information on a device connected\n"
+ " to the given block interface\n"
+ " Example usage:\n"
+ " mbr write mmc 0 [\"${mbr_parts}\"]\n"
+ " mbr verify mmc 0 [\"${partitions}\"]\n"
+);
diff --git a/cmd/pwm.c b/cmd/pwm.c
new file mode 100644
index 00000000000..5849fc57b66
--- /dev/null
+++ b/cmd/pwm.c
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Control PWM channels
+ *
+ * Copyright (c) 2020 SiFive, Inc
+ * author: Pragnesh Patel <pragnesh.patel@sifive.com>
+ */
+
+#include <command.h>
+#include <dm.h>
+#include <pwm.h>
+
+enum pwm_cmd {
+ PWM_SET_INVERT,
+ PWM_SET_CONFIG,
+ PWM_SET_ENABLE,
+ PWM_SET_DISABLE,
+};
+
+static int do_pwm(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ const char *str_cmd, *str_channel = NULL, *str_enable = NULL;
+ const char *str_pwm = NULL, *str_period = NULL, *str_duty = NULL;
+ enum pwm_cmd sub_cmd;
+ struct udevice *dev;
+ u32 channel, pwm_enable, pwm_dev, period_ns = 0, duty_ns = 0;
+ int ret;
+
+ if (argc < 4)
+ return CMD_RET_USAGE;
+
+ str_cmd = argv[1];
+ argc -= 2;
+ argv += 2;
+
+ if (argc > 0) {
+ str_pwm = *argv;
+ argc--;
+ argv++;
+ }
+
+ if (!str_pwm)
+ return CMD_RET_USAGE;
+
+ switch (*str_cmd) {
+ case 'i':
+ sub_cmd = PWM_SET_INVERT;
+ break;
+ case 'c':
+ sub_cmd = PWM_SET_CONFIG;
+ break;
+ case 'e':
+ sub_cmd = PWM_SET_ENABLE;
+ break;
+ case 'd':
+ sub_cmd = PWM_SET_DISABLE;
+ break;
+ default:
+ return CMD_RET_USAGE;
+ }
+
+ pwm_dev = simple_strtoul(str_pwm, NULL, 10);
+ ret = uclass_get_device(UCLASS_PWM, pwm_dev, &dev);
+ if (ret) {
+ printf("pwm: '%s' not found\n", str_pwm);
+ return cmd_process_error(cmdtp, ret);
+ }
+
+ if (argc > 0) {
+ str_channel = *argv;
+ channel = simple_strtoul(str_channel, NULL, 10);
+ argc--;
+ argv++;
+ } else {
+ return CMD_RET_USAGE;
+ }
+
+ if (sub_cmd == PWM_SET_INVERT && argc > 0) {
+ str_enable = *argv;
+ pwm_enable = simple_strtoul(str_enable, NULL, 10);
+ ret = pwm_set_invert(dev, channel, pwm_enable);
+ } else if (sub_cmd == PWM_SET_CONFIG && argc == 2) {
+ str_period = *argv;
+ argc--;
+ argv++;
+ period_ns = simple_strtoul(str_period, NULL, 10);
+
+ if (argc > 0) {
+ str_duty = *argv;
+ duty_ns = simple_strtoul(str_duty, NULL, 10);
+ }
+
+ ret = pwm_set_config(dev, channel, period_ns, duty_ns);
+ } else if (sub_cmd == PWM_SET_ENABLE) {
+ ret = pwm_set_enable(dev, channel, 1);
+ } else if (sub_cmd == PWM_SET_DISABLE) {
+ ret = pwm_set_enable(dev, channel, 0);
+ } else {
+ printf("PWM arguments missing\n");
+ return CMD_RET_FAILURE;
+ }
+
+ if (ret) {
+ printf("error(%d)\n", ret);
+ return CMD_RET_FAILURE;
+ }
+
+ return CMD_RET_SUCCESS;
+}
+
+U_BOOT_CMD(pwm, 6, 0, do_pwm,
+ "control pwm channels",
+ "pwm <invert> <pwm_dev_num> <channel> <polarity>\n"
+ "pwm <config> <pwm_dev_num> <channel> <period_ns> <duty_ns>\n"
+ "pwm <enable/disable> <pwm_dev_num> <channel>\n"
+ "Note: All input values are in decimal");