diff --git a/cmd/Kconfig b/cmd/Kconfig index 11f299da2b..58864f6448 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -1081,6 +1081,12 @@ config CMD_MTD help MTD commands support. +config CMD_MUX + bool "mux" + depends on MULTIPLEXER + help + List, select, and deselect mux controllers on the fly. + config CMD_NAND bool "nand" default y if NAND_SUNXI diff --git a/cmd/Makefile b/cmd/Makefile index da4e0600b2..0cbee6c2f8 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -105,6 +105,7 @@ obj-$(CONFIG_CMD_CLONE) += clone.o ifneq ($(CONFIG_CMD_NAND)$(CONFIG_CMD_SF),) obj-y += legacy-mtd-utils.o endif +obj-$(CONFIG_CMD_MUX) += mux.o obj-$(CONFIG_CMD_NAND) += nand.o obj-$(CONFIG_CMD_NET) += net.o obj-$(CONFIG_CMD_NVEDIT_EFI) += nvedit_efi.o diff --git a/cmd/mux.c b/cmd/mux.c new file mode 100644 index 0000000000..833266f08b --- /dev/null +++ b/cmd/mux.c @@ -0,0 +1,184 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * List, select, and deselect mux controllers on the fly. + * + * Copyright (c) 2020 Texas Instruments Inc. + * Author: Pratyush Yadav + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define COLUMN_SIZE 16 + +/* + * Print a member of a column. The total size of the text printed, including + * trailing whitespace, will always be COLUMN_SIZE. + */ +#define PRINT_COLUMN(fmt, args...) do { \ + char buf[COLUMN_SIZE + 1]; \ + snprintf(buf, COLUMN_SIZE + 1, fmt, ##args); \ + printf("%-*s", COLUMN_SIZE, buf); \ +} while (0) + +/* + * Find a mux based on its device name in argv[1] and index in the chip in + * argv[2]. + */ +static struct mux_control *cmd_mux_find(char *const argv[]) +{ + struct udevice *dev; + struct mux_chip *chip; + int ret; + unsigned long id; + + ret = strict_strtoul(argv[2], 10, &id); + if (ret) + return ERR_PTR(ret); + + ret = uclass_get_device_by_name(UCLASS_MUX, argv[1], &dev); + if (ret) + return ERR_PTR(ret); + + chip = dev_get_uclass_priv(dev); + if (!chip) + return ERR_PTR(ret); + + if (id >= chip->controllers) + return ERR_PTR(-EINVAL); + + return &chip->mux[id]; +} + +/* + * Print the details of a mux. The columns printed correspond to: "Selected", + * "Current State", "Idle State", and "Num States". + */ +static void print_mux(struct mux_control *mux) +{ + PRINT_COLUMN("%s", mux->in_use ? "yes" : "no"); + + if (mux->cached_state == MUX_IDLE_AS_IS) + PRINT_COLUMN("%s", "unknown"); + else + PRINT_COLUMN("0x%x", mux->cached_state); + + if (mux->idle_state == MUX_IDLE_AS_IS) + PRINT_COLUMN("%s", "as-is"); + else if (mux->idle_state == MUX_IDLE_DISCONNECT) + PRINT_COLUMN("%s", "disconnect"); + else + PRINT_COLUMN("0x%x", mux->idle_state); + + PRINT_COLUMN("0x%x", mux->states); + + printf("\n"); +} + +static int do_mux_list(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct udevice *dev; + struct mux_chip *chip; + int j; + + for (uclass_first_device(UCLASS_MUX, &dev); + dev; + uclass_next_device(&dev)) { + chip = dev_get_uclass_priv(dev); + if (!chip) { + dev_err(dev, "can't find mux chip\n"); + continue; + } + + printf("%s:\n", dev->name); + + printf(" "); + PRINT_COLUMN("ID"); + PRINT_COLUMN("Selected"); + PRINT_COLUMN("Current State"); + PRINT_COLUMN("Idle State"); + PRINT_COLUMN("Num States"); + printf("\n"); + for (j = 0; j < chip->controllers; j++) { + printf(" "); + PRINT_COLUMN("%d", j); + print_mux(&chip->mux[j]); + } + printf("\n"); + } + + return 0; +} + +static int do_mux_select(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct mux_control *mux; + int ret; + unsigned long state; + + if (argc != 4) + return CMD_RET_USAGE; + + mux = cmd_mux_find(argv); + if (IS_ERR_OR_NULL(mux)) { + printf("Failed to find the specified mux\n"); + return CMD_RET_FAILURE; + } + + ret = strict_strtoul(argv[3], 16, &state); + if (ret) { + printf("Invalid state\n"); + return CMD_RET_FAILURE; + } + + ret = mux_control_select(mux, state); + if (ret) { + printf("Failed to select requested state\n"); + return CMD_RET_FAILURE; + } + + return CMD_RET_SUCCESS; +} + +static int do_mux_deselect(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct mux_control *mux; + int ret; + + if (argc != 3) + return CMD_RET_USAGE; + + mux = cmd_mux_find(argv); + if (IS_ERR_OR_NULL(mux)) { + printf("Failed to find the specified mux\n"); + return CMD_RET_FAILURE; + } + + ret = mux_control_deselect(mux); + if (ret) { + printf("Failed to deselect mux\n"); + return CMD_RET_FAILURE; + } + + return CMD_RET_SUCCESS; +} + +static char mux_help_text[] = + "list - List all Muxes and their states\n" + "select - Select the given mux state\n" + "deselect - Deselect the given mux and reset it to its idle state"; + +U_BOOT_CMD_WITH_SUBCMDS(mux, "List, select, and deselect muxes", mux_help_text, + U_BOOT_SUBCMD_MKENT(list, 1, 1, do_mux_list), + U_BOOT_SUBCMD_MKENT(select, 4, 0, do_mux_select), + U_BOOT_SUBCMD_MKENT(deselect, 3, 0, do_mux_deselect));