diff options
author | Tom Rini <trini@konsulko.com> | 2023-03-31 10:04:23 -0400 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2023-03-31 10:04:23 -0400 |
commit | b8deed53fe6a55ef76b4f9038bb419a9c853a9fa (patch) | |
tree | 2f0cdb8f35d7c51611417bab680583a65bf21306 | |
parent | f1617e99b933d2c3ecb381954148284d37bf922e (diff) | |
parent | f98b112f9e0516fc9333611d1228d0b634aa353e (diff) | |
download | u-boot-b8deed53fe6a55ef76b4f9038bb419a9c853a9fa.zip u-boot-b8deed53fe6a55ef76b4f9038bb419a9c853a9fa.tar.gz u-boot-b8deed53fe6a55ef76b4f9038bb419a9c853a9fa.tar.bz2 |
Merge branch '2023-03-30-assorted-general-upates' into next
- RTC cleanups / improvements, run_commandf() cleanups, fs bugfixes,
socrates config fix, PCI MPS support, GPIO improvements, other code
cleanups
37 files changed, 971 insertions, 92 deletions
@@ -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 @@ -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/MAINTAINERS b/MAINTAINERS index 91d40ea..d2e245e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1249,6 +1249,12 @@ M: Heiko Schocher <hs@denx.de> S: Maintained F: drivers/pci/pci_mpc85xx.c +PCI MPS +M: Stephen Carlson <stcarlso@linux.microsoft.com> +S: Maintained +F: cmd/pci_mps.c +F: test/cmd/pci_mps.c + POWER M: Jaehoon Chung <jh80.chung@samsung.com> S: Maintained diff --git a/api/Kconfig b/api/Kconfig index d936272..6072288 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 diff --git a/boot/image-board.c b/boot/image-board.c index 25b60ec..9bf7082 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; } diff --git a/cmd/Kconfig b/cmd/Kconfig index ba5ec69..8c9b430 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 @@ -1542,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/Makefile b/cmd/Makefile index d95833b..e032091 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/nvedit.c b/cmd/nvedit.c index 7cbc3fd..12eae06 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 <from> (%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; diff --git a/cmd/pci_mps.c b/cmd/pci_mps.c new file mode 100644 index 0000000..555a5fd --- /dev/null +++ b/cmd/pci_mps.c @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2022 Microsoft Corporation <www.microsoft.com> + * Stephen Carlson <stcarlso@linux.microsoft.com> + * + * PCI Express Maximum Packet Size (MPS) configuration + */ + +#include <common.h> +#include <bootretry.h> +#include <cli.h> +#include <command.h> +#include <console.h> +#include <dm.h> +#include <init.h> +#include <asm/processor.h> +#include <asm/io.h> +#include <pci.h> + +#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/cmd/usb_mass_storage.c b/cmd/usb_mass_storage.c index b7daaa6..c3cc197 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(); } diff --git a/common/cli.c b/common/cli.c index 9451e6a..3916a7b 100644 --- a/common/cli.c +++ b/common/cli.c @@ -8,6 +8,8 @@ * JinHua Luo, GuangDong Linux Center, <luo.jinhua@gd-linux.com> */ +#define pr_fmt(fmt) "cli: %s: " fmt, __func__ + #include <common.h> #include <bootstage.h> #include <cli.h> @@ -20,6 +22,7 @@ #include <malloc.h> #include <asm/global_data.h> #include <dm/ofnode.h> +#include <linux/errno.h> #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/configs/sandbox_defconfig b/configs/sandbox_defconfig index b0f588d..cbace25 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 @@ -268,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/configs/socrates_defconfig b/configs/socrates_defconfig index 2465513..df8b31b 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 diff --git a/disk/disk-uclass.c b/disk/disk-uclass.c index d32747e..7f1fd80 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); } diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c index dbebf3a..c8be5a4 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/drivers/input/Kconfig b/drivers/input/Kconfig index 32360d9..c2b365a 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 99e65f1..74fadfc 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" +}; diff --git a/drivers/misc/swap_case.c b/drivers/misc/swap_case.c index 7093ad1..ee5c12b 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; diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index fcfda28..2317313 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 b6c9029..308fab8 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/m41t62.c b/drivers/rtc/m41t62.c index 66a0faa..891fe09 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[] = { diff --git a/drivers/rtc/max313xx.c b/drivers/rtc/max313xx.c new file mode 100644 index 0000000..748f3c4 --- /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 <bcd.h> +#include <dm.h> +#include <i2c.h> +#include <rtc.h> +#include <dm/device_compat.h> +#include <linux/bitfield.h> +#include <linux/delay.h> +#include <linux/kernel.h> + +/* 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, +}; diff --git a/drivers/sysinfo/gpio.c b/drivers/sysinfo/gpio.c index 1d7f050..82f9030 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; }; } diff --git a/fs/ext4/ext4_write.c b/fs/ext4/ext4_write.c index f22af45..ea4c5d4 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; } diff --git a/fs/fat/fat_write.c b/fs/fat/fat_write.c index 00541eb..413fc43 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; diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index dd0bdf2..c4a7fd2 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 diff --git a/include/command.h b/include/command.h index 1b018cb..c4e3170 100644 --- a/include/command.h +++ b/include/command.h @@ -13,6 +13,8 @@ #include <env.h> #include <linker_lists.h> +#include <linux/compiler_attributes.h> + #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 diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 3e71d61..5cd6c9d 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 diff --git a/include/pci.h b/include/pci.h index c55d610..2f5eb30 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 */ diff --git a/include/test/suites.h b/include/test/suites.h index 7c4960c..7349ce5 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/lib/Kconfig b/lib/Kconfig index 4278b24..202a34a 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)" diff --git a/test/cmd/Makefile b/test/cmd/Makefile index 7848f34..055adc6 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/exit.c b/test/cmd/exit.c index ca34abe..7e160f7 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 */ diff --git a/test/cmd/fdt.c b/test/cmd/fdt.c index 22e8c7e..597fecb 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;"); diff --git a/test/cmd/pci_mps.c b/test/cmd/pci_mps.c new file mode 100644 index 0000000..fd96f4f --- /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 <stcarlso@linux.microsoft.com> + */ + +#include <common.h> +#include <console.h> +#include <test/suites.h> +#include <test/ut.h> + +#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 409c22b..d440da8 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 @@ -210,6 +213,9 @@ static char ut_help_text[] = #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" #ifdef CONFIG_SANDBOX diff --git a/test/command_ut.c b/test/command_ut.c index 9837d10..a74bd10 100644 --- a/test/command_ut.c +++ b/test/command_ut.c @@ -9,6 +9,8 @@ #include <command.h> #include <env.h> #include <log.h> +#include <string.h> +#include <linux/errno.h> 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; } diff --git a/test/py/tests/test_fs/test_ext.py b/test/py/tests/test_fs/test_ext.py index dba874f..05fefa5 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) |