From 00491a30b1a4170b6cdd8f563828b6a55cd6e510 Mon Sep 17 00:00:00 2001 From: Heiko Schocher Date: Thu, 23 Feb 2023 07:03:47 +0100 Subject: [PATCH 01/24] powerpc/mpc85xx: disable legacy format booting disable CONFIG_LEGACY_IMAGE_FORMAT so prevent of booting not signed fitimages. Signed-off-by: Heiko Schocher --- configs/socrates_defconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/configs/socrates_defconfig b/configs/socrates_defconfig index 24655131a8a..df8b31b4e7b 100644 --- a/configs/socrates_defconfig +++ b/configs/socrates_defconfig @@ -18,7 +18,6 @@ CONFIG_SYS_MONITOR_LEN=786432 CONFIG_FIT=y CONFIG_FIT_SIGNATURE=y CONFIG_FIT_VERBOSE=y -CONFIG_LEGACY_IMAGE_FORMAT=y CONFIG_OF_BOARD_SETUP=y CONFIG_BOOTDELAY=1 CONFIG_AUTOBOOT_KEYED=y From 771cb4d58b236902c319f037c967fd7a01cbf00a Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 27 Feb 2023 20:56:31 +0100 Subject: [PATCH 02/24] image: Fix potentially uninitialized data variable In case fitImage support is disabled, and image_locate_script() is passed a fitImage, then the 'data' variable is used uninitialized. Drop into the default: branch of the switch-case statement and do not return the uninitialized data, and do not modify the return pointer either, just print an error message. Reported by clang build: " $ make HOSTCC=clang CC=clang KCFLAGS=-Werror sandbox64_defconfig && make HOSTCC=clang CC=clang KCFLAGS=-Werror ... boot/image-board.c:1006:7: error: variable 'data' is used uninitialized whenever switch case is taken [-Werror,-Wsometimes-uninitialized] case IMAGE_FORMAT_LEGACY: ^~~~~~~~~~~~~~~~~~~ include/image.h:608:29: note: expanded from macro 'IMAGE_FORMAT_LEGACY' ^~~~ boot/image-board.c:1128:19: note: uninitialized use occurs here *datap = (char *)data; ^~~~ boot/image-board.c:1001:11: note: initialize the variable 'data' to silence this warning u32 *data; ^ = NULL " Signed-off-by: Marek Vasut Reviewed-by: Tom Rini Reviewed-by: Simon Glass --- boot/image-board.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/boot/image-board.c b/boot/image-board.c index 25b60ec30b3..9bf70824cb7 100644 --- a/boot/image-board.c +++ b/boot/image-board.c @@ -1004,7 +1004,9 @@ int image_locate_script(void *buf, int size, const char *fit_uname, switch (genimg_get_format(buf)) { case IMAGE_FORMAT_LEGACY: - if (IS_ENABLED(CONFIG_LEGACY_IMAGE_FORMAT)) { + if (!IS_ENABLED(CONFIG_LEGACY_IMAGE_FORMAT)) { + goto exit_image_format; + } else { hdr = buf; if (!image_check_magic(hdr)) { @@ -1047,7 +1049,9 @@ int image_locate_script(void *buf, int size, const char *fit_uname, } break; case IMAGE_FORMAT_FIT: - if (IS_ENABLED(CONFIG_FIT)) { + if (!IS_ENABLED(CONFIG_FIT)) { + goto exit_image_format; + } else { fit_hdr = buf; if (fit_check_format(fit_hdr, IMAGE_SIZE_INVAL)) { puts("Bad FIT image format\n"); @@ -1121,12 +1125,15 @@ fallback: } break; default: - puts("Wrong image format for \"source\" command\n"); - return -EPERM; + goto exit_image_format; } *datap = (char *)data; *lenp = len; return 0; + +exit_image_format: + puts("Wrong image format for \"source\" command\n"); + return -EPERM; } From 66e49f047651f6e104d36db12e835b423d456108 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Tue, 28 Feb 2023 07:22:21 +0100 Subject: [PATCH 03/24] Kconfig: Sort the BUILD_TARGET list Sort the defaults list in BUILD_TARGET Kconfig option. No functional change. Signed-off-by: Marek Vasut Reviewed-by: Simon Glass --- Kconfig | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Kconfig b/Kconfig index b8f65589f45..7d04c5ab9f2 100644 --- a/Kconfig +++ b/Kconfig @@ -427,16 +427,16 @@ config REMAKE_ELF config BUILD_TARGET string "Build target special images" + default "u-boot-elf.srec" if RCAR_GEN3 + default "u-boot-with-spl.bin" if ARCH_AT91 && SPL_NAND_SUPPORT + default "u-boot-with-spl.bin" if MPC85xx && !E500MC && !E5500 && !E6500 && SPL + default "u-boot-with-spl.imx" if ARCH_MX6 && SPL + default "u-boot-with-spl.kwb" if ARMADA_32BIT && SPL default "u-boot-with-spl.sfp" if TARGET_SOCFPGA_ARRIA10 default "u-boot-with-spl.sfp" if TARGET_SOCFPGA_GEN5 - default "u-boot-with-spl.kwb" if ARMADA_32BIT && SPL - default "u-boot-elf.srec" if RCAR_GEN3 default "u-boot.itb" if !BINMAN && SPL_LOAD_FIT && (ARCH_ROCKCHIP || \ ARCH_SUNXI || RISCV || ARCH_ZYNQMP) default "u-boot.kwb" if (ARCH_KIRKWOOD || ARMADA_32BIT) && !SPL - default "u-boot-with-spl.bin" if MPC85xx && !E500MC && !E5500 && !E6500 && SPL - default "u-boot-with-spl.bin" if ARCH_AT91 && SPL_NAND_SUPPORT - default "u-boot-with-spl.imx" if ARCH_MX6 && SPL help Some SoCs need special image types (e.g. U-Boot binary with a special header) as build targets. By defining From fef0f1cc38a19f68e215fcc2504b4f60005179a2 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 3 Mar 2023 23:31:22 +0100 Subject: [PATCH 04/24] api: move API related config options into submenu Kconfig settings that are related to the API for standalone applications should be in the API sub-menu and not on the top level. CONFIG_STANDALONE_LOAD_ADDR is only relevant if standalone example applications are built. Signed-off-by: Heinrich Schuchardt --- Kconfig | 8 -------- api/Kconfig | 11 ++++++++++- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/Kconfig b/Kconfig index 7d04c5ab9f2..7a8c190a7bd 100644 --- a/Kconfig +++ b/Kconfig @@ -575,14 +575,6 @@ config MP This provides an option to bringup different processors in multiprocessor cases. -config EXAMPLES - bool "Compile API examples" - depends on !SANDBOX - default y if ARCH_QEMU - help - U-Boot provides an API for standalone applications. Examples are - provided in directory examples/. - endmenu # General setup source "api/Kconfig" diff --git a/api/Kconfig b/api/Kconfig index d9362724e5f..6072288f9bc 100644 --- a/api/Kconfig +++ b/api/Kconfig @@ -10,9 +10,16 @@ config SYS_MMC_MAX_DEVICE depends on API default 1 -endmenu +config EXAMPLES + bool "Compile API examples" + depends on !SANDBOX + default y if ARCH_QEMU + help + U-Boot provides an API for standalone applications. Examples are + provided in directory examples/. config STANDALONE_LOAD_ADDR + depends on EXAMPLES hex "Address in memory to link standalone applications to" default 0xffffffff80200000 if MIPS && 64BIT default 0x8c000000 if SH @@ -30,3 +37,5 @@ config STANDALONE_LOAD_ADDR This option defines a board specific value for the address where standalone program gets loaded, thus overwriting the architecture dependent default settings. + +endmenu From 732b0825475c1a2466a6abf6e223b2a77af011f2 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Mon, 6 Mar 2023 14:27:21 +0100 Subject: [PATCH 05/24] nvedit: simplify do_env_indirect() Instead of calling env_get(from) up to three times, just do it once, computing the value we will put into 'to' and error out if that is NULL (i.e. no 'from' variable and no default provided). No functional change. Signed-off-by: Rasmus Villemoes Reviewed-by: Simon Glass --- cmd/nvedit.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/cmd/nvedit.c b/cmd/nvedit.c index 7cbc3fd573a..12eae0627bb 100644 --- a/cmd/nvedit.c +++ b/cmd/nvedit.c @@ -1025,6 +1025,7 @@ static int do_env_indirect(struct cmd_tbl *cmdtp, int flag, char *from = argv[2]; char *default_value = NULL; int ret = 0; + char *val; if (argc < 3 || argc > 4) { return CMD_RET_USAGE; @@ -1034,18 +1035,14 @@ static int do_env_indirect(struct cmd_tbl *cmdtp, int flag, default_value = argv[3]; } - if (env_get(from) == NULL && default_value == NULL) { + val = env_get(from) ?: default_value; + if (!val) { printf("## env indirect: Environment variable for (%s) does not exist.\n", from); return CMD_RET_FAILURE; } - if (env_get(from) == NULL) { - ret = env_set(to, default_value); - } - else { - ret = env_set(to, env_get(from)); - } + ret = env_set(to, val); if (ret == 0) { return CMD_RET_SUCCESS; From 19213d7a65e9e3f8cfd0852599170636c894169e Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Fri, 10 Mar 2023 11:58:03 +0100 Subject: [PATCH 06/24] sysinfo: gpio: fix loop over DT "revisions" array There can certainly be a lot more elements in the "revisions" (and "names") arrays than there are gpios used to form the trinary number we're searching for; we simply don't know the array size up-front. Nor do we need to, because the loop body already knows to recognize -EOVERFLOW as "not that many elements present" (and we have a test that specifically ensures that dev_read_u32_index() returns exactly that). So just drop the i < priv->gpio_num condition. While in here, fix the weird placement of the default: keyword. Signed-off-by: Rasmus Villemoes Reviewed-by: Simon Glass Reviewed-by: Sean Anderson --- drivers/sysinfo/gpio.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/sysinfo/gpio.c b/drivers/sysinfo/gpio.c index 1d7f050998a..82f90303bb7 100644 --- a/drivers/sysinfo/gpio.c +++ b/drivers/sysinfo/gpio.c @@ -57,7 +57,7 @@ static int sysinfo_gpio_get_str(struct udevice *dev, int id, size_t size, char * int i, ret; u32 revision; - for (i = 0; i < priv->gpio_num; i++) { + for (i = 0; ; i++) { ret = dev_read_u32_index(dev, "revisions", i, &revision); if (ret) { @@ -80,7 +80,8 @@ static int sysinfo_gpio_get_str(struct udevice *dev, int id, size_t size, char * strncpy(val, name, size); val[size - 1] = '\0'; return 0; - } default: + } + default: return -EINVAL; }; } From 59b1c9be01934222cf773b35de7c8d086dabaef6 Mon Sep 17 00:00:00 2001 From: Stephen Carlson Date: Fri, 10 Mar 2023 11:07:13 -0800 Subject: [PATCH 07/24] cmd: pci: Add command to set MPS of all PCIe devices Enable tuning of the PCI Express MPS (Maximum Payload Size) of each device. The Maximum Read Request Size is not altered. The SAFE method uses the largest MPS value supported by all devices in the system for each device. This method is the same algorithm as used by Linux pci=pcie_bus_safe. The PEER2PEER method sets all devices to the minimal (128 byte) MPS, which allows hot plug of devices later that might only support the minimum size, and ensures compatibility of DMA between two devices on the bus. Signed-off-by: Stephen Carlson --- cmd/Kconfig | 10 +++ cmd/Makefile | 1 + cmd/pci_mps.c | 164 ++++++++++++++++++++++++++++++++++++++++++++++++++ include/pci.h | 7 +++ 4 files changed, 182 insertions(+) create mode 100644 cmd/pci_mps.c diff --git a/cmd/Kconfig b/cmd/Kconfig index ba5ec69293f..8138ab98eab 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -1396,6 +1396,16 @@ config CMD_PCI peripherals. Sub-commands allow bus enumeration, displaying and changing configuration space and a few other features. +config CMD_PCI_MPS + bool "pci_mps - Configure PCI device MPS" + depends on PCI + help + Enables PCI Express Maximum Packet Size (MPS) tuning. This + command configures the PCI Express MPS of each endpoint to the + largest value supported by all devices below the root complex. + The Maximum Read Request Size will not be altered. This method is + the same algorithm as used by Linux pci=pcie_bus_safe. + config CMD_PINMUX bool "pinmux - show pins muxing" depends on PINCTRL diff --git a/cmd/Makefile b/cmd/Makefile index d95833b2de0..e032091621d 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -131,6 +131,7 @@ obj-$(CONFIG_CMD_PART) += part.o obj-$(CONFIG_CMD_PCAP) += pcap.o ifdef CONFIG_PCI obj-$(CONFIG_CMD_PCI) += pci.o +obj-$(CONFIG_CMD_PCI_MPS) += pci_mps.o endif obj-$(CONFIG_CMD_PINMUX) += pinmux.o obj-$(CONFIG_CMD_PMC) += pmc.o diff --git a/cmd/pci_mps.c b/cmd/pci_mps.c new file mode 100644 index 00000000000..555a5fdd8e6 --- /dev/null +++ b/cmd/pci_mps.c @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2022 Microsoft Corporation + * Stephen Carlson + * + * PCI Express Maximum Packet Size (MPS) configuration + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PCI_MPS_SAFE 0 +#define PCI_MPS_PEER2PEER 1 + +static int pci_mps_find_safe(struct udevice *bus, unsigned int *min_mps, + unsigned int *n) +{ + struct udevice *dev; + int res = 0, addr; + unsigned int mpss; + u32 regval; + + if (!min_mps || !n) + return -EINVAL; + + for (device_find_first_child(bus, &dev); + dev; + device_find_next_child(&dev)) { + addr = dm_pci_find_capability(dev, PCI_CAP_ID_EXP); + if (addr <= 0) + continue; + + res = dm_pci_read_config32(dev, addr + PCI_EXP_DEVCAP, + ®val); + if (res != 0) + return res; + mpss = (unsigned int)(regval & PCI_EXP_DEVCAP_PAYLOAD); + *n += 1; + if (mpss < *min_mps) + *min_mps = mpss; + } + + return res; +} + +static int pci_mps_set_bus(struct udevice *bus, unsigned int target) +{ + struct udevice *dev; + u32 mpss, target_mps = (u32)(target << 5); + u16 mps; + int res = 0, addr; + + for (device_find_first_child(bus, &dev); + dev && res == 0; + device_find_next_child(&dev)) { + addr = dm_pci_find_capability(dev, PCI_CAP_ID_EXP); + if (addr <= 0) + continue; + + res = dm_pci_read_config32(dev, addr + PCI_EXP_DEVCAP, + &mpss); + if (res != 0) + return res; + + /* Do not set device above its maximum MPSS */ + mpss = (mpss & PCI_EXP_DEVCAP_PAYLOAD) << 5; + if (target_mps < mpss) + mps = (u16)target_mps; + else + mps = (u16)mpss; + res = dm_pci_clrset_config16(dev, addr + PCI_EXP_DEVCTL, + PCI_EXP_DEVCTL_PAYLOAD, mps); + } + + return res; +} + +/* + * Sets the MPS of each PCI Express device to the specified policy. + */ +static int pci_mps_set(int policy) +{ + struct udevice *bus; + int i, res = 0; + /* 0 = 128B, min value for hotplug */ + unsigned int mps = 0; + + if (policy == PCI_MPS_SAFE) { + unsigned int min_mps = PCI_EXP_DEVCAP_PAYLOAD_4096B, n = 0; + + /* Find maximum MPS supported by all devices */ + for (i = 0; + uclass_get_device_by_seq(UCLASS_PCI, i, &bus) == 0 && + res == 0; + i++) + res = pci_mps_find_safe(bus, &min_mps, &n); + + /* If no devices were found, do not reconfigure */ + if (n == 0) + return res; + mps = min_mps; + } + + /* This message is checked by the sandbox test */ + printf("Setting MPS of all devices to %uB\n", 128U << mps); + for (i = 0; + uclass_get_device_by_seq(UCLASS_PCI, i, &bus) == 0 && res == 0; + i++) + res = pci_mps_set_bus(bus, mps); + + return res; +} + +/* + * PCI MPS tuning commands + * + * Syntax: + * pci_mps safe + * pci_mps peer2peer + */ +static int do_pci_mps(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) +{ + char cmd = 'u'; + int ret = 0; + + if (argc > 1) + cmd = argv[1][0]; + + switch (cmd) { + case 's': /* safe */ + ret = pci_mps_set(PCI_MPS_SAFE); + break; + case 'p': /* peer2peer/hotplug */ + ret = pci_mps_set(PCI_MPS_PEER2PEER); + break; + default: /* usage, help */ + goto usage; + } + + return ret; +usage: + return CMD_RET_USAGE; +} + +/***************************************************/ + +#ifdef CONFIG_SYS_LONGHELP +static char pci_mps_help_text[] = + "safe\n" + " - Set PCI Express MPS of all devices to safe values\n" + "pci_mps peer2peer\n" + " - Set PCI Express MPS of all devices to support hotplug and peer-to-peer DMA\n"; +#endif + +U_BOOT_CMD(pci_mps, 2, 0, do_pci_mps, + "configure PCI Express MPS", pci_mps_help_text); diff --git a/include/pci.h b/include/pci.h index c55d6107a49..2f5eb30b83c 100644 --- a/include/pci.h +++ b/include/pci.h @@ -360,6 +360,13 @@ #define PCI_EXP_TYPE_PCIE_BRIDGE 0x8 /* PCI/PCI-X to PCIe Bridge */ #define PCI_EXP_DEVCAP 4 /* Device capabilities */ #define PCI_EXP_DEVCAP_FLR 0x10000000 /* Function Level Reset */ +#define PCI_EXP_DEVCAP_PAYLOAD 0x0007 /* Max payload size supported */ +#define PCI_EXP_DEVCAP_PAYLOAD_128B 0x0000 /* 128 Bytes */ +#define PCI_EXP_DEVCAP_PAYLOAD_256B 0x0001 /* 256 Bytes */ +#define PCI_EXP_DEVCAP_PAYLOAD_512B 0x0002 /* 512 Bytes */ +#define PCI_EXP_DEVCAP_PAYLOAD_1024B 0x0003 /* 1024 Bytes */ +#define PCI_EXP_DEVCAP_PAYLOAD_2048B 0x0004 /* 2048 Bytes */ +#define PCI_EXP_DEVCAP_PAYLOAD_4096B 0x0005 /* 4096 Bytes */ #define PCI_EXP_DEVCTL 8 /* Device Control */ #define PCI_EXP_DEVCTL_PAYLOAD 0x00e0 /* Max_Payload_Size */ #define PCI_EXP_DEVCTL_PAYLOAD_128B 0x0000 /* 128 Bytes */ From 713db6f6d3a3212270fd12ba5c47e986b36dbc39 Mon Sep 17 00:00:00 2001 From: Stephen Carlson Date: Fri, 10 Mar 2023 11:07:14 -0800 Subject: [PATCH 08/24] drivers: pci: sandbox: Add stub sandbox PCI MPS support Reports the sandbox swapcase PCI Express device to support a 256 byte Maximum Payload Size for MPS tuning tests. Signed-off-by: Stephen Carlson Reviewed-by: Simon Glass --- drivers/misc/swap_case.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/misc/swap_case.c b/drivers/misc/swap_case.c index 7093ad1cd4f..ee5c12bd0a4 100644 --- a/drivers/misc/swap_case.c +++ b/drivers/misc/swap_case.c @@ -165,6 +165,9 @@ static int sandbox_swap_case_read_config(const struct udevice *emul, case PCI_CAP_ID_EXP_OFFSET + PCI_CAP_LIST_NEXT: *valuep = PCI_CAP_ID_MSIX_OFFSET; break; + case PCI_CAP_ID_EXP_OFFSET + PCI_EXP_DEVCAP: + *valuep = PCI_EXP_DEVCAP_PAYLOAD_256B; + break; case PCI_CAP_ID_MSIX_OFFSET: if (sandbox_swap_case_use_ea(emul)) *valuep = (PCI_CAP_ID_EA_OFFSET << 8) | PCI_CAP_ID_MSIX; From 447dfbc0638f65accaeba1afa3b33840bdb46b6e Mon Sep 17 00:00:00 2001 From: Stephen Carlson Date: Fri, 10 Mar 2023 11:07:15 -0800 Subject: [PATCH 09/24] test: Add test for new command pci_mps Adds a test for the new pci_mps command to ensure that it can set the Maximum Payload Size (MPS) of all devices to 256 bytes in the sandbox environment. Enables the pci_mps command in the sandbox environment so that this test can be run. Signed-off-by: Stephen Carlson --- MAINTAINERS | 6 ++++++ configs/sandbox_defconfig | 1 + include/test/suites.h | 2 ++ test/cmd/Makefile | 3 +++ test/cmd/pci_mps.c | 42 +++++++++++++++++++++++++++++++++++++++ test/cmd_ut.c | 6 ++++++ 6 files changed, 60 insertions(+) create mode 100644 test/cmd/pci_mps.c diff --git a/MAINTAINERS b/MAINTAINERS index 91d40ea4b6e..d2e245e5e90 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1249,6 +1249,12 @@ M: Heiko Schocher S: Maintained F: drivers/pci/pci_mpc85xx.c +PCI MPS +M: Stephen Carlson +S: Maintained +F: cmd/pci_mps.c +F: test/cmd/pci_mps.c + POWER M: Jaehoon Chung S: Maintained diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index b0f588da32e..2141c3d4698 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -78,6 +78,7 @@ CONFIG_CMD_MMC=y CONFIG_CMD_MUX=y CONFIG_CMD_OSD=y CONFIG_CMD_PCI=y +CONFIG_CMD_PCI_MPS=y CONFIG_CMD_READ=y CONFIG_CMD_REMOTEPROC=y CONFIG_CMD_SPI=y diff --git a/include/test/suites.h b/include/test/suites.h index 7c4960c004d..7349ce5aa60 100644 --- a/include/test/suites.h +++ b/include/test/suites.h @@ -48,6 +48,8 @@ int do_ut_mem(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); int do_ut_optee(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); int do_ut_overlay(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); +int do_ut_pci_mps(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]); int do_ut_print(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); int do_ut_seama(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); int do_ut_setexpr(struct cmd_tbl *cmdtp, int flag, int argc, diff --git a/test/cmd/Makefile b/test/cmd/Makefile index 7848f348bc4..055adc65a25 100644 --- a/test/cmd/Makefile +++ b/test/cmd/Makefile @@ -14,6 +14,9 @@ obj-$(CONFIG_CMD_FDT) += fdt.o obj-$(CONFIG_CONSOLE_TRUETYPE) += font.o obj-$(CONFIG_CMD_LOADM) += loadm.o obj-$(CONFIG_CMD_MEM_SEARCH) += mem_search.o +ifdef CONFIG_CMD_PCI +obj-$(CONFIG_CMD_PCI_MPS) += pci_mps.o +endif obj-$(CONFIG_CMD_PINMUX) += pinmux.o obj-$(CONFIG_CMD_PWM) += pwm.o obj-$(CONFIG_CMD_SEAMA) += seama.o diff --git a/test/cmd/pci_mps.c b/test/cmd/pci_mps.c new file mode 100644 index 00000000000..fd96f4fba6c --- /dev/null +++ b/test/cmd/pci_mps.c @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Tests that the PCI Maximum Payload Size (MPS) command can set the sandbox + * PCI Express device to safe mode and determine the correct payload size. + * + * Copyright 2023 Microsoft + * Written by Stephen Carlson + */ + +#include +#include +#include +#include + +#define PCI_MPS_TEST(_name, _flags) UNIT_TEST(_name, _flags, pci_mps_test) + +/* Test "pci_mps" command in safe "s" mode */ +static int test_pci_mps_safe(struct unit_test_state *uts) +{ + /* Enumerate PCI Express first */ + ut_assertok(run_command("pci e", 0)); + ut_assert_console_end(); + + /* Test pci_mps s */ + ut_assertok(run_command("pci_mps s", 0)); + ut_assert_nextline("Setting MPS of all devices to 256B"); + ut_assert_console_end(); + + return 0; +} + +PCI_MPS_TEST(test_pci_mps_safe, UT_TESTF_CONSOLE_REC); + +int do_ut_pci_mps(struct cmd_tbl *cmdtp, int flag, int argc, + char * const argv[]) +{ + struct unit_test *tests = UNIT_TEST_SUITE_START(pci_mps_test); + const int n = UNIT_TEST_SUITE_COUNT(pci_mps_test); + + return cmd_ut_category("cmd_pci_mps", "pci_mps_test_", tests, n, + argc, argv); +} diff --git a/test/cmd_ut.c b/test/cmd_ut.c index 409c22bfd24..d440da833a9 100644 --- a/test/cmd_ut.c +++ b/test/cmd_ut.c @@ -110,6 +110,9 @@ static struct cmd_tbl cmd_ut_sub[] = { #ifdef CONFIG_CMD_LOADM U_BOOT_CMD_MKENT(loadm, CONFIG_SYS_MAXARGS, 1, do_ut_loadm, "", ""), #endif +#ifdef CONFIG_CMD_PCI_MPS + U_BOOT_CMD_MKENT(pci_mps, CONFIG_SYS_MAXARGS, 1, do_ut_pci_mps, "", ""), +#endif #ifdef CONFIG_CMD_SEAMA U_BOOT_CMD_MKENT(seama, CONFIG_SYS_MAXARGS, 1, do_ut_seama, "", ""), #endif @@ -209,6 +212,9 @@ static char ut_help_text[] = #endif #ifdef CONFIG_UT_OVERLAY "\noverlay - device tree overlays" +#endif +#ifdef CONFIG_CMD_PCI_MPS + "\npci_mps - PCI Express Maximum Payload Size" #endif "\nprint - printing things to the console" "\nsetexpr - setexpr command" From fefd949157430e1dc8569fa39729c63c5eccb454 Mon Sep 17 00:00:00 2001 From: Stefan Herbrechtsmeier Date: Fri, 17 Mar 2023 13:04:13 +0100 Subject: [PATCH 10/24] fs: fat: do not mangle short filenames Do not mangle lower or mixed case filenames which fit into the upper case 8.3 short filename. This ensures FAT standard compatible short filenames (SFN) to support systems without long filename (LFN) support like boot roms (ex. SFN BOOT.BIN instead of BOOT~1.BIN for LFN boot.bin). Signed-off-by: Stefan Herbrechtsmeier --- fs/fat/fat_write.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/fs/fat/fat_write.c b/fs/fat/fat_write.c index 00541ebc3a4..413fc432ebe 100644 --- a/fs/fat/fat_write.c +++ b/fs/fat/fat_write.c @@ -141,6 +141,8 @@ static int set_name(fat_itr *itr, const char *filename, char *shortname) if (!strcmp(buf, filename)) { ret = 1; goto out; + } else if (!strcasecmp(buf, filename)) { + goto out_ret; } /* Construct an indexed short name */ @@ -177,12 +179,13 @@ static int set_name(fat_itr *itr, const char *filename, char *shortname) if (find_directory_entry(itr, buf)) continue; - debug("chosen short name: %s\n", buf); - /* Each long name directory entry takes 13 characters. */ - ret = (strlen(filename) + 25) / 13; - goto out; + goto out_ret; } return -EIO; +out_ret: + debug("chosen short name: %s\n", buf); + /* Each long name directory entry takes 13 characters. */ + ret = (strlen(filename) + 25) / 13; out: memcpy(shortname, &dirent, SHORT_NAME_SIZE); return ret; From 39409fac2c9d9f3cc9cb23b88502b5ff08887339 Mon Sep 17 00:00:00 2001 From: Corentin GUILLEVIC Date: Fri, 17 Mar 2023 13:15:12 +0100 Subject: [PATCH 11/24] fs: ext4: fix files seen as symlink during deletion The deletion process handles special case for symlinks whose target are small enough that it fits in struct ext2_inode.b.symlink. So no block had been allocated. But the check of file type wrongly considered regular files as symlink. So, no block was freed. So, the EXT4 partition could be corrupted because of no free block available. Signed-off-by: Corentin GUILLEVIC --- fs/ext4/ext4_write.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ext4/ext4_write.c b/fs/ext4/ext4_write.c index f22af45d1b9..ea4c5d4157c 100644 --- a/fs/ext4/ext4_write.c +++ b/fs/ext4/ext4_write.c @@ -473,7 +473,7 @@ static int ext4fs_delete_file(int inodeno) * special case for symlinks whose target are small enough that *it fits in struct ext2_inode.b.symlink: no block had been allocated */ - if ((le16_to_cpu(inode.mode) & S_IFLNK) && + if (S_ISLNK(le16_to_cpu(inode.mode)) && le32_to_cpu(inode.size) <= sizeof(inode.b.symlink)) { no_blocks = 0; } From fdef6b982f0a24d4b3a83d107da4f817efa4566f Mon Sep 17 00:00:00 2001 From: Thomas Perrot Date: Fri, 17 Mar 2023 15:22:41 +0100 Subject: [PATCH 12/24] rtc: m41t62: implements read8/write8 operations These operations are required by dm_rtc_read and dm_bootcount_get helpers. Signed-off-by: Thomas Perrot Reviewed-by: Simon Glass --- drivers/rtc/m41t62.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/rtc/m41t62.c b/drivers/rtc/m41t62.c index 66a0faa0ecf..891fe09d311 100644 --- a/drivers/rtc/m41t62.c +++ b/drivers/rtc/m41t62.c @@ -283,6 +283,16 @@ static int m41t62_rtc_reset(struct udevice *dev) return m41t62_sqw_enable(dev, true); } +static int m41t62_rtc_read8(struct udevice *dev, unsigned int reg) +{ + return dm_i2c_reg_read(dev, reg); +} + +static int m41t62_rtc_write8(struct udevice *dev, unsigned int reg, int val) +{ + return dm_i2c_reg_write(dev, reg, val); +} + /* * Make sure HT bit is cleared. This bit is set on entering battery backup * mode, so do this before the first read access. @@ -296,6 +306,8 @@ static const struct rtc_ops m41t62_rtc_ops = { .get = m41t62_rtc_get, .set = m41t62_rtc_set, .reset = m41t62_rtc_reset, + .read8 = m41t62_rtc_read8, + .write8 = m41t62_rtc_write8, }; static const struct udevice_id m41t62_rtc_ids[] = { From e1c97949ee922ccc84c4ef4364c9810aa76f6306 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Fri, 17 Mar 2023 21:12:22 +0100 Subject: [PATCH 13/24] gpio: allow passing NULL to gpio_request_by_line_name() to search all gpio controllers The API is more convenient to use if one doesn't have to know upfront which gpio controller has a line with the name one is searching for, and arrange to look that device up somehow. Or implement this loop oneself. Signed-off-by: Rasmus Villemoes Reviewed-by: Simon Glass --- drivers/gpio/gpio-uclass.c | 7 +++++++ include/asm-generic/gpio.h | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c index dbebf3a53eb..c8be5a4d668 100644 --- a/drivers/gpio/gpio-uclass.c +++ b/drivers/gpio/gpio-uclass.c @@ -1171,6 +1171,13 @@ int gpio_request_by_line_name(struct udevice *dev, const char *line_name, { int ret; + if (!dev) { + uclass_foreach_dev_probe(UCLASS_GPIO, dev) + if (!gpio_request_by_line_name(dev, line_name, desc, flags)) + return 0; + return -ENOENT; + } + ret = dev_read_stringlist_search(dev, "gpio-line-names", line_name); if (ret < 0) return ret; diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index dd0bdf2315e..c4a7fd28439 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -580,7 +580,8 @@ int gpio_request_by_name(struct udevice *dev, const char *list_name, * This allows boards to implement common behaviours using GPIOs while not * requiring specific GPIO offsets be used. * - * @dev: An instance of a GPIO controller udevice + * @dev: An instance of a GPIO controller udevice, or NULL to search + * all GPIO controller devices * @line_name: The name of the GPIO (e.g. "bmc-secure-boot") * @desc: A GPIO descriptor that is populated with the requested GPIO * upon return From c61df34009c3ad46b5798e1d13fd640419bf17e6 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 19 Mar 2023 04:13:02 +0100 Subject: [PATCH 14/24] lib: Fix SYS_TIMER_COUNTS_DOWN description in Kconfig The SYS_TIMER_COUNTS_DOWN description contains a typo, s@rathe@&r@ , fix it. Signed-off-by: Marek Vasut --- lib/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Kconfig b/lib/Kconfig index 4278b240554..202a34ab413 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -16,7 +16,7 @@ config SYS_NUM_ADDR_MAP Sets the number of entries in the virtual-physical mapping table. config SYS_TIMER_COUNTS_DOWN - bool "System timer counts down rathe than up" + bool "System timer counts down rather than up" config PHYSMEM bool "Access to physical memory region (> 4G)" From d87bdb82eae66512c222fd93280acaf4dd1cd4be Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 20 Mar 2023 08:29:57 +1300 Subject: [PATCH 15/24] disk: Use a helper function to reduce duplication Reduce the duplicated code slightly by using a helper function to handle the common code. This reduces the code size very slightly. Signed-off-by: Simon Glass --- disk/disk-uclass.c | 46 +++++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/disk/disk-uclass.c b/disk/disk-uclass.c index d32747e2242..7f1fd80b224 100644 --- a/disk/disk-uclass.c +++ b/disk/disk-uclass.c @@ -65,26 +65,38 @@ int part_create_block_devices(struct udevice *blk_dev) return 0; } +static int blk_part_setup(struct udevice *dev, lbaint_t *startp, + lbaint_t blkcnt) +{ + struct disk_part *part; + + part = dev_get_uclass_plat(dev); + if (*startp >= part->gpt_part_info.size) + return -E2BIG; + + if (*startp + blkcnt > part->gpt_part_info.size) + blkcnt = part->gpt_part_info.size - *startp; + *startp += part->gpt_part_info.start; + + return 0; +} + static ulong part_blk_read(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *buffer) { struct udevice *parent; - struct disk_part *part; const struct blk_ops *ops; + int ret; parent = dev_get_parent(dev); ops = blk_get_ops(parent); if (!ops->read) return -ENOSYS; - part = dev_get_uclass_plat(dev); - if (start >= part->gpt_part_info.size) + ret = blk_part_setup(dev, &start, blkcnt); + if (ret) return 0; - if ((start + blkcnt) > part->gpt_part_info.size) - blkcnt = part->gpt_part_info.size - start; - start += part->gpt_part_info.start; - return ops->read(parent, start, blkcnt, buffer); } @@ -92,22 +104,18 @@ static ulong part_blk_write(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, const void *buffer) { struct udevice *parent; - struct disk_part *part; const struct blk_ops *ops; + int ret; parent = dev_get_parent(dev); ops = blk_get_ops(parent); if (!ops->write) return -ENOSYS; - part = dev_get_uclass_plat(dev); - if (start >= part->gpt_part_info.size) + ret = blk_part_setup(dev, &start, blkcnt); + if (ret) return 0; - if ((start + blkcnt) > part->gpt_part_info.size) - blkcnt = part->gpt_part_info.size - start; - start += part->gpt_part_info.start; - return ops->write(parent, start, blkcnt, buffer); } @@ -115,22 +123,18 @@ static ulong part_blk_erase(struct udevice *dev, lbaint_t start, lbaint_t blkcnt) { struct udevice *parent; - struct disk_part *part; const struct blk_ops *ops; + int ret; parent = dev_get_parent(dev); ops = blk_get_ops(parent); if (!ops->erase) return -ENOSYS; - part = dev_get_uclass_plat(dev); - if (start >= part->gpt_part_info.size) + ret = blk_part_setup(dev, &start, blkcnt); + if (ret) return 0; - if ((start + blkcnt) > part->gpt_part_info.size) - blkcnt = part->gpt_part_info.size - start; - start += part->gpt_part_info.start; - return ops->erase(parent, start, blkcnt); } From b5f045e12fea0a64a3749c4da1bdfd579530b67e Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Mon, 20 Mar 2023 10:23:43 +1300 Subject: [PATCH 16/24] include: kernel.h: port find_closest() from Linux The find_closest() macro can be used to find an element in a sorted array that is closest to an input value. Bring in this macro from Linux v6.3-rc1-2-g8ca09d5fa354. Signed-off-by: Chris Packham Reviewed-by: Simon Glass --- include/linux/kernel.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 3e71d61074b..5cd6c9dc821 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -284,4 +284,28 @@ offsetof(struct structure, member) == (offset), \ "`struct " #structure "` offset for `" #member "` is not " #offset) +#define __find_closest(x, a, as, op) \ +({ \ + typeof(as) __fc_i, __fc_as = (as) - 1; \ + typeof(x) __fc_x = (x); \ + typeof(*a) const *__fc_a = (a); \ + for (__fc_i = 0; __fc_i < __fc_as; __fc_i++) { \ + if (__fc_x op DIV_ROUND_CLOSEST(__fc_a[__fc_i] + \ + __fc_a[__fc_i + 1], 2)) \ + break; \ + } \ + (__fc_i); \ +}) + +/** + * find_closest - locate the closest element in a sorted array + * @x: The reference value. + * @a: The array in which to look for the closest element. Must be sorted + * in ascending order. + * @as: Size of 'a'. + * + * Returns the index of the element closest to 'x'. + */ +#define find_closest(x, a, as) __find_closest(x, a, as, <=) + #endif From 0798a1ce0f6439dfb80d310e11bc8993e09baf08 Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Mon, 20 Mar 2023 10:23:44 +1300 Subject: [PATCH 17/24] drivers: rtc: add max313xx series rtc driver Adding support for Analog Devices MAX313XX series RTCs. This is ported from the Linux driver and adapted for use in u-boot. Notable differences are - handling of tm_year and tm_mon differ - clock source support is omitted - hwmon support for the MAX31328 and MAX31343 is omitted - rtc_ops->reset is added Signed-off-by: Chris Packham Reviewed-by: Simon Glass --- configs/sandbox_defconfig | 1 + drivers/rtc/Kconfig | 13 ++ drivers/rtc/Makefile | 1 + drivers/rtc/max313xx.c | 459 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 474 insertions(+) create mode 100644 drivers/rtc/max313xx.c diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 2141c3d4698..cbace259f80 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -269,6 +269,7 @@ CONFIG_SANDBOX_RESET=y CONFIG_RESET_SYSCON=y CONFIG_RESET_SCMI=y CONFIG_DM_RTC=y +CONFIG_RTC_MAX313XX=y CONFIG_RTC_RV8803=y CONFIG_RTC_HT1380=y CONFIG_SCSI=y diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index fcfda2847c8..23173139e01 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -134,6 +134,19 @@ config RTC_ISL1208 This driver supports reading and writing the RTC/calendar and detects total power failures. +config RTC_MAX313XX + bool "Analog Devices MAX313XX RTC driver" + depends on DM_RTC + depends on DM_I2C + help + If you say yes here you will get support for the + Analog Devices MAX313XX series RTC family. + + Chip features not currently supported: + - Timestamp registers as SRAM + - Temperature sensor + - CLKOUT generation + config RTC_PCF8563 tristate "Philips PCF8563" help diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index b6c9029c8f0..308fab8da9b 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_RTC_HT1380) += ht1380.o obj-$(CONFIG_$(SPL_TPL_)RTC_SANDBOX) += i2c_rtc_emul.o obj-$(CONFIG_RTC_ISL1208) += isl1208.o obj-$(CONFIG_RTC_M41T62) += m41t62.o +obj-$(CONFIG_RTC_MAX313XX) += max313xx.o obj-$(CONFIG_RTC_MC13XXX) += mc13xxx-rtc.o obj-$(CONFIG_RTC_MC146818) += mc146818.o obj-$(CONFIG_MCFRTC) += mcfrtc.o diff --git a/drivers/rtc/max313xx.c b/drivers/rtc/max313xx.c new file mode 100644 index 00000000000..748f3c42c30 --- /dev/null +++ b/drivers/rtc/max313xx.c @@ -0,0 +1,459 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Analog Devices MAX313XX series I2C RTC driver + * + * Copyright 2022 Analog Devices Inc. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* common registers */ +#define MAX313XX_INT_ALARM1 BIT(0) +#define MAX313XX_INT_ALARM2 BIT(1) +#define MAX313XX_HRS_F_12_24 BIT(6) +#define MAX313XX_HRS_F_AM_PM BIT(5) +#define MAX313XX_MONTH_CENTURY BIT(7) + +#define MAX313XX_TMR_CFG_ENABLE BIT(4) +#define MAX313XX_TMR_CFG_FREQ_MASK GENMASK(1, 0) +#define MAX313XX_TMR_CFG_FREQ_16HZ 0x03 + +#define MAX313XX_REG_MINUTE 0x01 +#define MAX313XX_REG_HOUR 0x02 + +#define MAX313XX_TIME_SIZE 0x07 + +/* device specific registers */ +#define MAX3134X_CFG2_REG 0x01 +#define MAX3134X_CFG2_SET_RTC BIT(1) + +#define MAX31341_TRICKLE_RES_MASK GENMASK(1, 0) +#define MAX31341_TRICKLE_DIODE_EN BIT(2) +#define MAX31341_TRICKLE_ENABLE_BIT BIT(3) +#define MAX31341_POWER_MGMT_REG 0x56 +#define MAX31341_POWER_MGMT_TRICKLE_BIT BIT(0) + +#define MAX3133X_TRICKLE_RES_MASK GENMASK(2, 1) +#define MAX3133X_TRICKLE_DIODE_EN BIT(3) +#define MAX3133X_TRICKLE_ENABLE_BIT BIT(0) + +#define MAX31329_TRICKLE_ENABLE_BIT BIT(7) +#define MAX31343_TRICKLE_ENABLE_MASK GENMASK(7, 4) +#define MAX31343_TRICKLE_ENABLE_CODE 5 +#define MAX31329_43_TRICKLE_RES_MASK GENMASK(1, 0) +#define MAX31329_43_TRICKLE_DIODE_EN BIT(2) + +#define MAX31329_CONFIG2_REG 0x04 +#define MAX31329_CONFIG2_CLKIN_EN BIT(2) +#define MAX31329_CONFIG2_CLKIN_FREQ GENMASK(1, 0) + +#define MAX31341_42_CONFIG1_REG 0x00 +#define MAX31341_42_CONFIG1_CLKIN_EN BIT(7) +#define MAX31341_42_CONFIG1_CLKIN_FREQ GENMASK(5, 4) +#define MAX31341_42_CONFIG1_OSC_DISABLE BIT(3) +#define MAX31341_42_CONFIG1_SWRST BIT(0) + +enum max313xx_ids { + ID_MAX31328, + ID_MAX31329, + ID_MAX31331, + ID_MAX31334, + ID_MAX31341, + ID_MAX31342, + ID_MAX31343, + MAX313XX_ID_NR +}; + +/** + * struct chip_desc - descriptor for MAX313xx variants + * @sec_reg: Offset to seconds register. Used to denote the start of the + * current time registers. + * @alarm1_sec_reg: Offset to Alarm1 seconds register. Used to denote the + * start of the alarm registers. + * @int_en_reg: Offset to the interrupt enable register. + * @int_status_reg: Offset to the interrupt status register. + * @ram_reg: Offset to the timestamp RAM (which can be used as SRAM). + * @ram_size: Size of the timestamp RAM. + * @temp_reg: Offset to the temperature register (or 0 if temperature + * sensor is not supported). + * @trickle_reg: Offset to the trickle charger configuration register (or + * 0 if trickle charger is not supported). + * @rst_reg: Offset to the reset register. + * @rst_bit: Bit within the reset register for the software reset. + */ +struct chip_desc { + u8 sec_reg; + u8 alarm1_sec_reg; + + u8 int_en_reg; + u8 int_status_reg; + + u8 ram_reg; + u8 ram_size; + + u8 temp_reg; + + u8 trickle_reg; + + u8 rst_reg; + u8 rst_bit; +}; + +struct max313xx_priv { + enum max313xx_ids id; + const struct chip_desc *chip; +}; + +static const struct chip_desc chip[MAX313XX_ID_NR] = { + [ID_MAX31328] = { + .int_en_reg = 0x0E, + .int_status_reg = 0x0F, + .sec_reg = 0x00, + .alarm1_sec_reg = 0x07, + .temp_reg = 0x11, + }, + [ID_MAX31329] = { + .int_en_reg = 0x01, + .int_status_reg = 0x00, + .sec_reg = 0x06, + .alarm1_sec_reg = 0x0D, + .ram_reg = 0x22, + .ram_size = 64, + .trickle_reg = 0x19, + .rst_reg = 0x02, + .rst_bit = BIT(0), + }, + [ID_MAX31331] = { + .int_en_reg = 0x01, + .int_status_reg = 0x00, + .sec_reg = 0x08, + .alarm1_sec_reg = 0x0F, + .ram_reg = 0x20, + .ram_size = 32, + .trickle_reg = 0x1B, + .rst_reg = 0x02, + .rst_bit = BIT(0), + }, + [ID_MAX31334] = { + .int_en_reg = 0x01, + .int_status_reg = 0x00, + .sec_reg = 0x09, + .alarm1_sec_reg = 0x10, + .ram_reg = 0x30, + .ram_size = 32, + .trickle_reg = 0x1E, + .rst_reg = 0x02, + .rst_bit = BIT(0), + }, + [ID_MAX31341] = { + .int_en_reg = 0x04, + .int_status_reg = 0x05, + .sec_reg = 0x06, + .alarm1_sec_reg = 0x0D, + .ram_reg = 0x16, + .ram_size = 64, + .trickle_reg = 0x57, + .rst_reg = 0x00, + .rst_bit = BIT(0), + }, + [ID_MAX31342] = { + .int_en_reg = 0x04, + .int_status_reg = 0x05, + .sec_reg = 0x06, + .alarm1_sec_reg = 0x0D, + .rst_reg = 0x00, + .rst_bit = BIT(0), + }, + [ID_MAX31343] = { + .int_en_reg = 0x01, + .int_status_reg = 0x00, + .sec_reg = 0x06, + .alarm1_sec_reg = 0x0D, + .ram_reg = 0x22, + .ram_size = 64, + .temp_reg = 0x1A, + .trickle_reg = 0x19, + .rst_reg = 0x02, + .rst_bit = BIT(0), + }, +}; + +static const u32 max313xx_trickle_ohms[] = { 3000, 6000, 11000 }; + +static int max313xx_set_bits(struct udevice *dev, unsigned int reg, unsigned int bits) +{ + int ret; + + ret = dm_i2c_reg_read(dev, reg); + if (ret < 0) + return ret; + + return dm_i2c_reg_write(dev, reg, ret | bits); +} + +static int max313xx_clear_bits(struct udevice *dev, unsigned int reg, unsigned int bits) +{ + int ret; + + ret = dm_i2c_reg_read(dev, reg); + if (ret < 0) + return ret; + + return dm_i2c_reg_write(dev, reg, ret & ~bits); +} + +static int max313xx_get_hour(u8 hour_reg) +{ + int hour; + + /* 24Hr mode */ + if (!FIELD_GET(MAX313XX_HRS_F_12_24, hour_reg)) + return bcd2bin(hour_reg & 0x3f); + + /* 12Hr mode */ + hour = bcd2bin(hour_reg & 0x1f); + if (hour == 12) + hour = 0; + + if (FIELD_GET(MAX313XX_HRS_F_AM_PM, hour_reg)) + hour += 12; + + return hour; +} + +static int max313xx_read_time(struct udevice *dev, struct rtc_time *t) +{ + struct max313xx_priv *rtc = dev_get_priv(dev); + u8 regs[7]; + int ret; + + ret = dm_i2c_read(dev, rtc->chip->sec_reg, regs, 7); + if (ret) + return ret; + + t->tm_sec = bcd2bin(regs[0] & 0x7f); + t->tm_min = bcd2bin(regs[1] & 0x7f); + t->tm_hour = max313xx_get_hour(regs[2]); + t->tm_wday = bcd2bin(regs[3] & 0x07) - 1; + t->tm_mday = bcd2bin(regs[4] & 0x3f); + t->tm_mon = bcd2bin(regs[5] & 0x1f); + t->tm_year = bcd2bin(regs[6]) + 2000; + + if (FIELD_GET(MAX313XX_MONTH_CENTURY, regs[5])) + t->tm_year += 100; + + dev_dbg(dev, "read %4d-%02d-%02d (wday=%d) %2d:%02d:%02d\n", + t->tm_year, t->tm_mon, t->tm_mday, + t->tm_wday, t->tm_hour, t->tm_min, t->tm_sec); + + return 0; +} + +static int max313xx_set_time(struct udevice *dev, const struct rtc_time *t) +{ + struct max313xx_priv *rtc = dev_get_priv(dev); + u8 regs[7]; + int ret; + + dev_dbg(dev, "set %4d-%02d-%02d (wday=%d) %2d:%02d:%02d\n", + t->tm_year, t->tm_mon, t->tm_mday, + t->tm_wday, t->tm_hour, t->tm_min, t->tm_sec); + + if (t->tm_year < 2000) { + dev_err(dev, "year %d (before 2000) not supported\n", + t->tm_year); + return -EINVAL; + } + + if (rtc->chip->rst_bit) { + ret = max313xx_clear_bits(dev, rtc->chip->rst_reg, rtc->chip->rst_bit); + if (ret) + return ret; + } + + regs[0] = bin2bcd(t->tm_sec); + regs[1] = bin2bcd(t->tm_min); + regs[2] = bin2bcd(t->tm_hour); + regs[3] = bin2bcd(t->tm_wday + 1); + regs[4] = bin2bcd(t->tm_mday); + regs[5] = bin2bcd(t->tm_mon); + regs[6] = bin2bcd((t->tm_year - 2000) % 100); + + if ((t->tm_year - 2000) >= 200) + regs[5] |= FIELD_PREP(MAX313XX_MONTH_CENTURY, 1); + + ret = dm_i2c_write(dev, rtc->chip->sec_reg, regs, 7); + if (ret) + return ret; + + switch (rtc->id) { + case ID_MAX31341: + case ID_MAX31342: + ret = max313xx_set_bits(dev, MAX3134X_CFG2_REG, + MAX3134X_CFG2_SET_RTC); + if (ret) + return ret; + + udelay(10000); + + ret = max313xx_clear_bits(dev, MAX3134X_CFG2_REG, + MAX3134X_CFG2_SET_RTC); + if (ret) + return ret; + + break; + default: + break; + } + + return ret; +} + +static int max313xx_reset(struct udevice *dev) +{ + struct max313xx_priv *rtc = dev_get_priv(dev); + int ret = -EINVAL; + + if (rtc->chip->rst_bit) + ret = max313xx_set_bits(dev, rtc->chip->rst_reg, rtc->chip->rst_bit); + + return ret; +} + +static const struct rtc_ops max3133x_rtc_ops = { + .get = max313xx_read_time, + .set = max313xx_set_time, + .reset = max313xx_reset, +}; + +static int max313xx_init(struct udevice *dev) +{ + struct max313xx_priv *rtc = dev_get_priv(dev); + int ret; + + switch (rtc->id) { + case ID_MAX31341: + case ID_MAX31342: + ret = max313xx_clear_bits(dev, MAX31341_42_CONFIG1_REG, + MAX31341_42_CONFIG1_OSC_DISABLE); + if (ret) + return ret; + + return max313xx_set_bits(dev, MAX31341_42_CONFIG1_REG, + MAX31341_42_CONFIG1_SWRST); + default: + return 0; + } +} + +static int max313xx_trickle_charger_setup(struct udevice *dev) +{ + struct max313xx_priv *rtc = dev_get_priv(dev); + bool diode; + int index, reg; + u32 ohms; + u32 chargeable; + int ret; + + if (dev_read_u32(dev, "trickle-resistor-ohms", &ohms) || + dev_read_u32(dev, "aux-voltage-chargeable", &chargeable)) + return 0; + + switch (chargeable) { + case 0: + diode = false; + break; + case 1: + diode = true; + break; + default: + dev_dbg(dev, "unsupported aux-voltage-chargeable value\n"); + return -EINVAL; + } + + if (!rtc->chip->trickle_reg) { + dev_warn(dev, "device does not have trickle charger\n"); + return -ENOTSUPP; + } + + index = find_closest(ohms, max313xx_trickle_ohms, + ARRAY_SIZE(max313xx_trickle_ohms)) + 1; + + switch (rtc->id) { + case ID_MAX31329: + reg = FIELD_PREP(MAX31329_TRICKLE_ENABLE_BIT, 1) | + FIELD_PREP(MAX31329_43_TRICKLE_RES_MASK, index) | + FIELD_PREP(MAX31329_43_TRICKLE_DIODE_EN, diode); + break; + case ID_MAX31331: + case ID_MAX31334: + reg = FIELD_PREP(MAX3133X_TRICKLE_ENABLE_BIT, 1) | + FIELD_PREP(MAX3133X_TRICKLE_DIODE_EN, diode) | + FIELD_PREP(MAX3133X_TRICKLE_RES_MASK, index); + break; + case ID_MAX31341: + if (index == 1) + index = 0; + reg = FIELD_PREP(MAX31341_TRICKLE_ENABLE_BIT, 1) | + FIELD_PREP(MAX31341_TRICKLE_DIODE_EN, diode) | + FIELD_PREP(MAX31341_TRICKLE_RES_MASK, index); + + ret = max313xx_set_bits(dev, MAX31341_POWER_MGMT_REG, + MAX31341_POWER_MGMT_TRICKLE_BIT); + if (ret) + return ret; + + break; + case ID_MAX31343: + reg = FIELD_PREP(MAX31329_43_TRICKLE_RES_MASK, index) | + FIELD_PREP(MAX31329_43_TRICKLE_DIODE_EN, diode) | + FIELD_PREP(MAX31343_TRICKLE_ENABLE_MASK, + MAX31343_TRICKLE_ENABLE_CODE); + break; + default: + return -EOPNOTSUPP; + } + + return dm_i2c_reg_write(dev, rtc->chip->trickle_reg, reg); +} + +static int max313xx_probe(struct udevice *dev) +{ + struct max313xx_priv *max313xx = dev_get_priv(dev); + int ret; + + max313xx->id = dev_get_driver_data(dev); + max313xx->chip = &chip[max313xx->id]; + + ret = max313xx_init(dev); + if (ret) + return ret; + + return max313xx_trickle_charger_setup(dev); +} + +static const struct udevice_id max313xx_of_id[] = { + { .compatible = "adi,max31328", .data = ID_MAX31328 }, + { .compatible = "adi,max31329", .data = ID_MAX31329 }, + { .compatible = "adi,max31331", .data = ID_MAX31331 }, + { .compatible = "adi,max31334", .data = ID_MAX31334 }, + { .compatible = "adi,max31341", .data = ID_MAX31341 }, + { .compatible = "adi,max31342", .data = ID_MAX31342 }, + { .compatible = "adi,max31343", .data = ID_MAX31343 }, + { } +}; + +U_BOOT_DRIVER(rtc_max313xx) = { + .name = "rtc-max313xx", + .id = UCLASS_RTC, + .probe = max313xx_probe, + .of_match = max313xx_of_id, + .priv_auto = sizeof(struct max313xx_priv), + .ops = &max3133x_rtc_ops, +}; From 26f923c7cff1a46d465efcd3b8f2240523c7ab08 Mon Sep 17 00:00:00 2001 From: Evgeny Bachinin Date: Mon, 20 Mar 2023 11:23:11 +0300 Subject: [PATCH 18/24] cli: run_commandf(): small fixups MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * vsnprintf() can truncate cmd, hence it makes no sense to launch such command (it's broken). Moreover, it's better to signalize to the caller about such case (for facilitating debugging or bug hunting). * Fix kernel-doc warnings: include/command.h:264: info: Scanning doc for run_commandf include/command.h:268: warning: contents before sections include/command.h:271: warning: No description found for return value of 'run_commandf' * Add printf-like format attribute to validate at compile-time the format string against parameters's type. * Fix compilation error in case of -Wall, -Werror, -Wextra: error: variable ‘i’ set but not used [-Werror=unused-but-set-variable] * Drop extra ret variable. Signed-off-by: Evgeny Bachinin Reviewed-by: Simon Glass --- common/cli.c | 25 +++++++++++++++++++------ include/command.h | 13 ++++++++++--- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/common/cli.c b/common/cli.c index 9451e6a1426..3916a7b10a7 100644 --- a/common/cli.c +++ b/common/cli.c @@ -8,6 +8,8 @@ * JinHua Luo, GuangDong Linux Center, */ +#define pr_fmt(fmt) "cli: %s: " fmt, __func__ + #include #include #include @@ -20,6 +22,7 @@ #include #include #include +#include #ifdef CONFIG_CMDLINE /* @@ -129,16 +132,26 @@ int run_command_list(const char *cmd, int len, int flag) int run_commandf(const char *fmt, ...) { va_list args; - char cmd[128]; - int i, ret; + int nbytes; va_start(args, fmt); - i = vsnprintf(cmd, sizeof(cmd), fmt, args); + /* + * Limit the console_buffer space being used to CONFIG_SYS_CBSIZE, + * because its last byte is used to fit the replacement of \0 by \n\0 + * in underlying hush parser + */ + nbytes = vsnprintf(console_buffer, CONFIG_SYS_CBSIZE, fmt, args); va_end(args); - ret = run_command(cmd, 0); - - return ret; + if (nbytes < 0) { + pr_debug("I/O internal error occurred.\n"); + return -EIO; + } else if (nbytes >= CONFIG_SYS_CBSIZE) { + pr_debug("'fmt' size:%d exceeds the limit(%d)\n", + nbytes, CONFIG_SYS_CBSIZE); + return -ENOSPC; + } + return run_command(console_buffer, 0); } /****************************************************************************/ diff --git a/include/command.h b/include/command.h index 1b018cb98e7..c4e3170967d 100644 --- a/include/command.h +++ b/include/command.h @@ -13,6 +13,8 @@ #include #include +#include + #ifndef NULL #define NULL 0 #endif @@ -260,12 +262,17 @@ int run_command_repeatable(const char *cmd, int flag); /** * run_commandf() - Run a command created by a format string * - * The command cannot be larger than 127 characters - * * @fmt: printf() format string * @...: Arguments to use (flag is always 0) + * + * The command cannot be larger than (CONFIG_SYS_CBSIZE - 1) characters. + * + * Return: + * Returns 0 on success, -EIO if internal output error occurred, -ENOSPC in + * case of 'fmt' string truncation, or != 0 on error, specific for + * run_command(). */ -int run_commandf(const char *fmt, ...); +int run_commandf(const char *fmt, ...) __printf(1, 2); /** * Run a list of commands separated by ; or even \0 From dd1f34a9b9a0fa7e10fef05641f54955006565e3 Mon Sep 17 00:00:00 2001 From: Evgeny Bachinin Date: Mon, 20 Mar 2023 11:23:12 +0300 Subject: [PATCH 19/24] unit-test: cover run_commandf() by test-cases As run_commandf() is variadic version of run_command() and just a wrapper, hence apply similar run_command's test-cases. Let's avoid warning about empty string passing: warning: zero-length gnu_printf format string [-Wformat-zero-length] assert(run_commandf("") == 0); Signed-off-by: Evgeny Bachinin Reviewed-by: Simon Glass --- test/command_ut.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/test/command_ut.c b/test/command_ut.c index 9837d10eb5c..a74bd109e15 100644 --- a/test/command_ut.c +++ b/test/command_ut.c @@ -9,6 +9,8 @@ #include #include #include +#include +#include static const char test_cmd[] = "setenv list 1\n setenv list ${list}2; " "setenv list ${list}3\0" @@ -17,6 +19,8 @@ static const char test_cmd[] = "setenv list 1\n setenv list ${list}2; " static int do_ut_cmd(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { + char long_str[CONFIG_SYS_CBSIZE + 42]; + printf("%s: Testing commands\n", __func__); run_command("env default -f -a", 0); @@ -60,6 +64,36 @@ static int do_ut_cmd(struct cmd_tbl *cmdtp, int flag, int argc, assert(run_command("'", 0) == 1); + /* Variadic function test-cases */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat-zero-length" + assert(run_commandf("") == 0); +#pragma GCC diagnostic pop + assert(run_commandf(" ") == 0); + assert(run_commandf("'") == 1); + + assert(run_commandf("env %s %s", "delete -f", "list") == 0); + /* Expected: "Error: "list" not defined" */ + assert(run_commandf("printenv list") == 1); + + memset(long_str, 'x', sizeof(long_str)); + assert(run_commandf("Truncation case: %s", long_str) == -ENOSPC); + + if (IS_ENABLED(CONFIG_HUSH_PARSER)) { + assert(run_commandf("env %s %s %s %s", "delete -f", "adder", + "black", "foo") == 0); + assert(run_commandf("setenv foo 'setenv %s 1\nsetenv %s 2'", + "black", "adder") == 0); + run_command("run foo", 0); + assert(env_get("black")); + assert(!strcmp("1", env_get("black"))); + assert(env_get("adder")); + assert(!strcmp("2", env_get("adder"))); + } + + /* Clean up before exit */ + run_command("env default -f -a", 0); + printf("%s: Everything went swimmingly\n", __func__); return 0; } From 0d73c238425bb6218b38d0d35c950b03230e2e5a Mon Sep 17 00:00:00 2001 From: Evgeny Bachinin Date: Mon, 20 Mar 2023 11:23:13 +0300 Subject: [PATCH 20/24] test: fdt: fix run_commandf() warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix warnings both for 32bit and 64bit architecture after adding printf-like attribute format for run_commandf(): warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘ulong {aka long unsigned int}’ [-Wformat=] ret = run_commandf("fdt addr -c %08x", addr); ^ Signed-off-by: Evgeny Bachinin Cc: Marek Vasut Reviewed-by: Simon Glass [trini: Fixup testcases added since patch was posted] Signed-off-by: Tom Rini --- test/cmd/fdt.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/test/cmd/fdt.c b/test/cmd/fdt.c index 22e8c7e3d26..597fecbf62a 100644 --- a/test/cmd/fdt.c +++ b/test/cmd/fdt.c @@ -175,7 +175,7 @@ static int fdt_test_addr(struct unit_test_state *uts) /* Set the working FDT */ set_working_fdt_addr(0); ut_assert_nextline("Working FDT set to 0"); - ut_assertok(run_commandf("fdt addr %08x", addr)); + ut_assertok(run_commandf("fdt addr %08lx", addr)); ut_assert_nextline("Working FDT set to %lx", addr); ut_asserteq(addr, map_to_sysmem(working_fdt)); ut_assertok(ut_check_console_end(uts)); @@ -185,7 +185,7 @@ static int fdt_test_addr(struct unit_test_state *uts) /* Set the control FDT */ fdt_blob = gd->fdt_blob; gd->fdt_blob = NULL; - ret = run_commandf("fdt addr -c %08x", addr); + ret = run_commandf("fdt addr -c %08lx", addr); new_fdt = gd->fdt_blob; gd->fdt_blob = fdt_blob; ut_assertok(ret); @@ -194,7 +194,7 @@ static int fdt_test_addr(struct unit_test_state *uts) /* Test setting an invalid FDT */ fdt[0] = 123; - ut_asserteq(1, run_commandf("fdt addr %08x", addr)); + ut_asserteq(1, run_commandf("fdt addr %08lx", addr)); ut_assert_nextline("libfdt fdt_check_header(): FDT_ERR_BADMAGIC"); ut_assertok(ut_check_console_end(uts)); @@ -223,19 +223,19 @@ static int fdt_test_addr_resize(struct unit_test_state *uts) /* Test setting and resizing the working FDT to a larger size */ ut_assertok(console_record_reset_enable()); - ut_assertok(run_commandf("fdt addr %08x %x", addr, newsize)); + ut_assertok(run_commandf("fdt addr %08lx %x", addr, newsize)); ut_assert_nextline("Working FDT set to %lx", addr); ut_assertok(ut_check_console_end(uts)); /* Try shrinking it */ - ut_assertok(run_commandf("fdt addr %08x %x", addr, sizeof(fdt) / 4)); + ut_assertok(run_commandf("fdt addr %08lx %zx", addr, sizeof(fdt) / 4)); ut_assert_nextline("Working FDT set to %lx", addr); ut_assert_nextline("New length %d < existing length %d, ignoring", (int)sizeof(fdt) / 4, newsize); ut_assertok(ut_check_console_end(uts)); /* ...quietly */ - ut_assertok(run_commandf("fdt addr -q %08x %x", addr, sizeof(fdt) / 4)); + ut_assertok(run_commandf("fdt addr -q %08lx %zx", addr, sizeof(fdt) / 4)); ut_assert_nextline("Working FDT set to %lx", addr); ut_assertok(ut_check_console_end(uts)); @@ -265,13 +265,13 @@ static int fdt_test_move(struct unit_test_state *uts) /* Test moving the working FDT to a new location */ ut_assertok(console_record_reset_enable()); - ut_assertok(run_commandf("fdt move %08x %08x %x", addr, newaddr, ts)); + ut_assertok(run_commandf("fdt move %08lx %08lx %x", addr, newaddr, ts)); ut_assert_nextline("Working FDT set to %lx", newaddr); ut_assertok(ut_check_console_end(uts)); /* Compare the source and destination DTs */ ut_assertok(console_record_reset_enable()); - ut_assertok(run_commandf("cmp.b %08x %08x %x", addr, newaddr, ts)); + ut_assertok(run_commandf("cmp.b %08lx %08lx %x", addr, newaddr, ts)); ut_assert_nextline("Total of %d byte(s) were the same", ts); ut_assertok(ut_check_console_end(uts)); @@ -1406,7 +1406,7 @@ static int fdt_test_apply(struct unit_test_state *uts) /* Test simple DTO application */ ut_assertok(console_record_reset_enable()); - ut_assertok(run_commandf("fdt apply 0x%08x", addro)); + ut_assertok(run_commandf("fdt apply 0x%08lx", addro)); ut_assertok(run_commandf("fdt print /")); ut_assert_nextline("/ {"); ut_assert_nextline("\tnewstring = \"newvalue\";"); @@ -1451,7 +1451,7 @@ static int fdt_test_apply(struct unit_test_state *uts) /* Test complex DTO application */ ut_assertok(console_record_reset_enable()); - ut_assertok(run_commandf("fdt apply 0x%08x", addro)); + ut_assertok(run_commandf("fdt apply 0x%08lx", addro)); ut_assertok(run_commandf("fdt print /")); ut_assert_nextline("/ {"); ut_assert_nextline("\tempty-property;"); @@ -1495,7 +1495,7 @@ static int fdt_test_apply(struct unit_test_state *uts) /* Test complex DTO application */ ut_assertok(console_record_reset_enable()); - ut_assertok(run_commandf("fdt apply 0x%08x", addro)); + ut_assertok(run_commandf("fdt apply 0x%08lx", addro)); ut_assertok(run_commandf("fdt print /")); ut_assert_nextline("/ {"); ut_assert_nextline("\tempty-property;"); From 49b7d69f56d2f0ecb357079708603cf9df0b3699 Mon Sep 17 00:00:00 2001 From: Evgeny Bachinin Date: Mon, 20 Mar 2023 11:23:14 +0300 Subject: [PATCH 21/24] test: exit: fix run_commandf() warnings Fix warnings after adding printf-like attribute format for run_commandf(): warning: too many arguments for format [-Wformat-extra-args] Signed-off-by: Evgeny Bachinin Reviewed-by: Simon Glass Reviewed-by: Simon Glass --- test/cmd/exit.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/test/cmd/exit.c b/test/cmd/exit.c index ca34abef899..7e160f7e4bb 100644 --- a/test/cmd/exit.c +++ b/test/cmd/exit.c @@ -60,20 +60,20 @@ static int cmd_exit_test(struct unit_test_state *uts) /* Validate that 'exit' behaves the same way as 'exit 0' */ ut_assertok(console_record_reset_enable()); - ut_assertok(run_commandf("setenv foo 'echo bar ; exit ; echo baz' ; run foo ; echo $?", i)); + ut_assertok(run_commandf("setenv foo 'echo bar ; exit ; echo baz' ; run foo ; echo $?")); ut_assert_nextline("bar"); ut_assert_nextline("0"); ut_assertok(ut_check_console_end(uts)); ut_assertok(console_record_reset_enable()); - ut_assertok(run_commandf("setenv foo 'echo bar ; exit ; echo baz' ; run foo && echo quux ; echo $?", i)); + ut_assertok(run_commandf("setenv foo 'echo bar ; exit ; echo baz' ; run foo && echo quux ; echo $?")); ut_assert_nextline("bar"); ut_assert_nextline("quux"); ut_assert_nextline("0"); ut_assertok(ut_check_console_end(uts)); ut_assertok(console_record_reset_enable()); - ut_assertok(run_commandf("setenv foo 'echo bar ; exit ; echo baz' ; run foo || echo quux ; echo $?", i)); + ut_assertok(run_commandf("setenv foo 'echo bar ; exit ; echo baz' ; run foo || echo quux ; echo $?")); ut_assert_nextline("bar"); /* Either 'exit' returns 0, or 'echo quux' returns 0 */ ut_assert_nextline("0"); @@ -81,39 +81,39 @@ static int cmd_exit_test(struct unit_test_state *uts) /* Validate that return value still propagates from 'run' command */ ut_assertok(console_record_reset_enable()); - ut_assertok(run_commandf("setenv foo 'echo bar ; true' ; run foo ; echo $?", i)); + ut_assertok(run_commandf("setenv foo 'echo bar ; true' ; run foo ; echo $?")); ut_assert_nextline("bar"); ut_assert_nextline("0"); ut_assertok(ut_check_console_end(uts)); ut_assertok(console_record_reset_enable()); - ut_assertok(run_commandf("setenv foo 'echo bar ; true' ; run foo && echo quux ; echo $?", i)); + ut_assertok(run_commandf("setenv foo 'echo bar ; true' ; run foo && echo quux ; echo $?")); ut_assert_nextline("bar"); ut_assert_nextline("quux"); ut_assert_nextline("0"); ut_assertok(ut_check_console_end(uts)); ut_assertok(console_record_reset_enable()); - ut_assertok(run_commandf("setenv foo 'echo bar ; true' ; run foo || echo quux ; echo $?", i)); + ut_assertok(run_commandf("setenv foo 'echo bar ; true' ; run foo || echo quux ; echo $?")); ut_assert_nextline("bar"); /* The 'true' returns 0 */ ut_assert_nextline("0"); ut_assertok(ut_check_console_end(uts)); ut_assertok(console_record_reset_enable()); - ut_assertok(run_commandf("setenv foo 'echo bar ; false' ; run foo ; echo $?", i)); + ut_assertok(run_commandf("setenv foo 'echo bar ; false' ; run foo ; echo $?")); ut_assert_nextline("bar"); ut_assert_nextline("1"); ut_assertok(ut_check_console_end(uts)); ut_assertok(console_record_reset_enable()); - ut_assertok(run_commandf("setenv foo 'echo bar ; false' ; run foo && echo quux ; echo $?", i)); + ut_assertok(run_commandf("setenv foo 'echo bar ; false' ; run foo && echo quux ; echo $?")); ut_assert_nextline("bar"); ut_assert_nextline("1"); ut_assertok(ut_check_console_end(uts)); ut_assertok(console_record_reset_enable()); - ut_assertok(run_commandf("setenv foo 'echo bar ; false' ; run foo || echo quux ; echo $?", i)); + ut_assertok(run_commandf("setenv foo 'echo bar ; false' ; run foo || echo quux ; echo $?")); ut_assert_nextline("bar"); ut_assert_nextline("quux"); /* The 'echo quux' returns 0 */ From a57adacf50d1bc0b5efd85b484a5c52a4c1ebcf1 Mon Sep 17 00:00:00 2001 From: Svyatoslav Ryhel Date: Mon, 20 Mar 2023 21:01:43 +0200 Subject: [PATCH 22/24] cmd: ums: abort mounting by pressing any key This patch introduses config which allows interrupt run of usb mass storage with any key. This is especially useful on devices with limited input capabilities like tablets and smatphones which have only gpio keys in direct access. Signed-off-by: Svyatoslav Ryhel Reviewed-by: Simon Glass --- cmd/Kconfig | 6 ++++++ cmd/usb_mass_storage.c | 10 ++++++++++ 2 files changed, 16 insertions(+) diff --git a/cmd/Kconfig b/cmd/Kconfig index 8138ab98eab..8c9b430f99f 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -1552,6 +1552,12 @@ config CMD_USB_MASS_STORAGE export a block device: U-Boot, the USB device, acts as a simple external hard drive plugged on the host USB port. +config CMD_UMS_ABORT_KEYED + bool "UMS abort with any key" + depends on CMD_USB_MASS_STORAGE + help + Allow interruption of usb mass storage run with any key pressed. + config CMD_PVBLOCK bool "Xen para-virtualized block device" depends on XEN diff --git a/cmd/usb_mass_storage.c b/cmd/usb_mass_storage.c index b7daaa6e8e8..c3cc1975f9d 100644 --- a/cmd/usb_mass_storage.c +++ b/cmd/usb_mass_storage.c @@ -231,6 +231,16 @@ static int do_usb_mass_storage(struct cmd_tbl *cmdtp, int flag, goto cleanup_register; } + if (IS_ENABLED(CONFIG_CMD_UMS_ABORT_KEYED)) { + /* Abort by pressing any key */ + if (tstc()) { + getchar(); + printf("\rOperation aborted.\n"); + rc = CMD_RET_SUCCESS; + goto cleanup_register; + } + } + schedule(); } From 25df91520e964911dcfa71638834df2854e14024 Mon Sep 17 00:00:00 2001 From: Svyatoslav Ryhel Date: Mon, 20 Mar 2023 21:06:30 +0200 Subject: [PATCH 23/24] input: button_kbd: make driver complementary to gpio buttons Remove need of dts binding for button keyboard since it reuses gpio-keys binding. Select gpio-keys driver if button keyboard is selected since button keyboard can not operate on its own. Tested-by: Svyatoslav Ryhel # HTC One X T30 Signed-off-by: Svyatoslav Ryhel Reviewed-by: Simon Glass --- drivers/input/Kconfig | 2 +- drivers/input/button_kbd.c | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 32360d94c05..c2b365af11d 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -48,8 +48,8 @@ config APPLE_SPI_KEYB config BUTTON_KEYBOARD bool "Buttons as keyboard" - depends on BUTTON_GPIO depends on DM_KEYBOARD + select BUTTON_GPIO help Enable support for mapping buttons to keycode events. Use linux,code button driver dt node to define button-event mapping. diff --git a/drivers/input/button_kbd.c b/drivers/input/button_kbd.c index 99e65f12f01..74fadfca8bb 100644 --- a/drivers/input/button_kbd.c +++ b/drivers/input/button_kbd.c @@ -111,16 +111,14 @@ static int button_kbd_probe(struct udevice *dev) return 0; } -static const struct udevice_id button_kbd_ids[] = { - { .compatible = "button-kbd" }, - { } -}; - U_BOOT_DRIVER(button_kbd) = { .name = "button_kbd", .id = UCLASS_KEYBOARD, - .of_match = button_kbd_ids, .ops = &button_kbd_ops, .priv_auto = sizeof(struct button_kbd_priv), .probe = button_kbd_probe, }; + +U_BOOT_DRVINFO(button_kbd) = { + .name = "button_kbd" +}; From f98b112f9e0516fc9333611d1228d0b634aa353e Mon Sep 17 00:00:00 2001 From: Stefan Herbrechtsmeier Date: Wed, 22 Mar 2023 09:46:02 +0100 Subject: [PATCH 24/24] test: fs: Check fat short file name Ensure that a freshly written fat file with a lower case filename which fits into the upper case 8.3 short filename is not mangeled with a tilde and number. Signed-off-by: Stefan Herbrechtsmeier --- test/py/tests/test_fs/test_ext.py | 36 +++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/test/py/tests/test_fs/test_ext.py b/test/py/tests/test_fs/test_ext.py index dba874fc59c..05fefa53a0e 100644 --- a/test/py/tests/test_fs/test_ext.py +++ b/test/py/tests/test_fs/test_ext.py @@ -8,11 +8,24 @@ This test verifies extended write operation on file system. """ +import os.path import pytest import re +from subprocess import check_output from fstest_defs import * from fstest_helpers import assert_fs_integrity +PLAIN_FILE='abcdefgh.txt' +MANGLE_FILE='abcdefghi.txt' + +def str2fat(long_filename): + splitext = os.path.splitext(long_filename.upper()) + name = splitext[0] + ext = splitext[1][1:] + if len(name) > 8: + name = '%s~1' % name[:6] + return '%-8s %s' % (name, ext) + @pytest.mark.boardspec('sandbox') @pytest.mark.slow class TestFsExt(object): @@ -317,3 +330,26 @@ class TestFsExt(object): assert('FILE0123456789_79' in output) assert_fs_integrity(fs_type, fs_img) + + def test_fs_ext12(self, u_boot_console, fs_obj_ext): + """ + Test Case 12 - write plain and mangle file + """ + fs_type,fs_img,md5val = fs_obj_ext + with u_boot_console.log.section('Test Case 12 - write plain and mangle file'): + # Test Case 12a - Check if command successfully returned + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + '%swrite host 0:0 %x /%s 0' + % (fs_type, ADDR, PLAIN_FILE), + '%swrite host 0:0 %x /%s 0' + % (fs_type, ADDR, MANGLE_FILE)]) + assert('0 bytes written' in ''.join(output)) + # Test Case 12b - Read file system content + output = check_output('mdir -i %s' % fs_img, shell=True).decode() + # Test Case 12c - Check if short filename is not mangled + assert(str2fat(PLAIN_FILE) in ''.join(output)) + # Test Case 12d - Check if long filename is mangled + assert(str2fat(MANGLE_FILE) in ''.join(output)) + + assert_fs_integrity(fs_type, fs_img)