The command structure allows adding more subcommands and is designed to match the Linux program mmc from the mmc-utils. So later more commands can easily be added if need be. Compared to mmc-utils' mmc enh_area set <-y|-n|-c> <start KiB> <length KiB> <device> the command that is implemented here ( mmc enh_area setmax [-c] <device> ) is easier to use (because you don't have to check the maximal allowed size by reading some registers and calculate the available size from them (which then must be calculated back to register values by the mmc command)) but less flexible as it doesn't allow all the crazy possibilities specified in the eMMC standard but just creates an enhanced area with maximal size. Signed-off-by: Uwe Kleine-König <u.kleine-koenig@xxxxxxxxxxxxxx> --- Hello, this is v2 of this patch. I refactored some stuff (but didn't move it out to drivers/mci as suggested, I'd delay that until need arises), changed the options to be easier and added some documentation. Subcommand parsing is now also simpler and doesn't pick up abbreviated commands. Some review comments (e.g. "verbose error reporting") isn't addressed yet as I'm not sure I understand it correctly (see the other mail in this thread). I'm sending out already now as the last round was sent out quite some time to swap this topic in again (in case it was already removed from your mailbox). Best regards Uwe commands/Kconfig | 11 +++ commands/Makefile | 1 + commands/mmc.c | 209 ++++++++++++++++++++++++++++++++++++++++++++++ include/mci.h | 7 ++ 4 files changed, 228 insertions(+) create mode 100644 commands/mmc.c diff --git a/commands/Kconfig b/commands/Kconfig index 675bd1ca76a0..221d65a358e0 100644 --- a/commands/Kconfig +++ b/commands/Kconfig @@ -238,6 +238,17 @@ config CMD_VERSION barebox 2014.05.0-00142-gb289373 #177 Mon May 12 20:35:55 CEST 2014 +config CMD_MMC + tristate + prompt "mmc command allowing to set enhanced area" + depends on MCI + help + Configure mmc cards similar to the userspace mmc utility. Compared to + mmc_extcsd it works on a higher abstraction level. + + Currently only the enh_area subcommand is implemented to configure + the "Enhanced Area" of an mmc device. + config CMD_MMC_EXTCSD tristate prompt "read/write eMMC ext. CSD register" diff --git a/commands/Makefile b/commands/Makefile index eb4796389e6b..27a62240b039 100644 --- a/commands/Makefile +++ b/commands/Makefile @@ -119,6 +119,7 @@ obj-$(CONFIG_CMD_DHCP) += dhcp.o obj-$(CONFIG_CMD_BOOTCHOOSER) += bootchooser.o obj-$(CONFIG_CMD_DHRYSTONE) += dhrystone.o obj-$(CONFIG_CMD_SPD_DECODE) += spd_decode.o +obj-$(CONFIG_CMD_MMC) += mmc.o obj-$(CONFIG_CMD_MMC_EXTCSD) += mmc_extcsd.o obj-$(CONFIG_CMD_NAND_BITFLIP) += nand-bitflip.o obj-$(CONFIG_CMD_SEED) += seed.o diff --git a/commands/mmc.c b/commands/mmc.c new file mode 100644 index 000000000000..ea1c6d6e4f53 --- /dev/null +++ b/commands/mmc.c @@ -0,0 +1,209 @@ +#include <command.h> +#include <mci.h> +#include <stdio.h> +#include <string.h> + +static int mmc_enh_area_setmax(struct mci *mci, u8 *ext_csd) +{ + int ret; + + ret = mci_switch(mci, EXT_CSD_ERASE_GROUP_DEF, 1); + if (ret) { + printf("Failure to write to EXT_CSD_ERASE_GROUP_DEF\n"); + return ret; + } + + ret = mci_switch(mci, EXT_CSD_ENH_START_ADDR, 0); + if (ret) { + printf("Failure to write to EXT_CSD_ENH_START_ADDR[0]\n"); + return ret; + } + + ret = mci_switch(mci, EXT_CSD_ENH_START_ADDR + 1, 0); + if (ret) { + printf("Failure to write to EXT_CSD_ENH_START_ADDR[1]\n"); + return ret; + } + + ret = mci_switch(mci, EXT_CSD_ENH_START_ADDR + 2, 0); + if (ret) { + printf("Failure to write to EXT_CSD_ENH_START_ADDR[2]\n"); + return ret; + } + + ret = mci_switch(mci, EXT_CSD_ENH_START_ADDR + 3, 0); + if (ret) { + printf("Failure to write to EXT_CSD_ENH_START_ADDR[3]\n"); + return ret; + } + + ret = mci_switch(mci, EXT_CSD_ENH_SIZE_MULT, ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT]); + if (ret) { + printf("Failure to write to EXT_CSD_ENH_SIZE_MULT[0]\n"); + return ret; + } + + ret = mci_switch(mci, EXT_CSD_ENH_SIZE_MULT + 1, ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT + 1]); + if (ret) { + printf("Failure to write to EXT_CSD_ENH_SIZE_MULT[1]\n"); + return ret; + } + + ret = mci_switch(mci, EXT_CSD_ENH_SIZE_MULT + 2, ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT + 2]); + if (ret) { + printf("Failure to write to EXT_CSD_ENH_SIZE_MULT[2]\n"); + return ret; + } + + ret = mci_switch(mci, EXT_CSD_PARTITIONS_ATTRIBUTE, ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] | EXT_CSD_ENH_USR_MASK); + if (ret) + printf("Failure to write to EXT_CSD_PARTITIONS_ATTRIBUTE\n"); + + return ret; +} + +static int mmc_partitioning_complete(struct mci *mci) +{ + int ret; + + ret = mci_switch(mci, EXT_CSD_PARTITION_SETTING_COMPLETED, 1); + if (ret) + printf("Failure to write to EXT_CSD_PARTITION_SETTING_COMPLETED\n"); + + return ret; +} + +static u8 *mci_get_ext_csd(struct mci *mci) +{ + u8 *ext_csd; + int ret; + + ext_csd = xmalloc(512); + + ret = mci_send_ext_csd(mci, ext_csd); + if (ret) { + printf("Failure to read EXT_CSD register\n"); + return ERR_PTR(-EIO); + } + + return ext_csd; +} + +/* enh_area setmax [-c] /dev/mmcX */ +static int do_mmc_enh_area(int argc, char *argv[]) +{ + char *devname; + struct mci *mci; + u8 *ext_csd; + int set_completed = 0; + int ret; + + if (argc < 2 || strcmp(argv[1], "setmax") != 0) + goto usage; + + if (argc == 3) { + /* enh_area setmax /dev/mmcX */ + devname = argv[2]; + set_completed = false; + } else if (argc == 4 || strcmp(argv[2], "-c") == 0) { + /* enh_area setmax -c /dev/mmcX */ + devname = argv[3]; + set_completed = true; + } else { +usage: + printf("Usage: mmc enh_area setmax [-c] /dev/mmcX\n"); + return COMMAND_ERROR_USAGE; + } + + if (!strncmp(devname, "/dev/", 5)) + devname += 5; + + mci = mci_get_device_by_name(devname); + if (!mci) { + printf("Failure to open %s as mci device\n", devname); + return COMMAND_ERROR; + } + + ext_csd = mci_get_ext_csd(mci); + if (IS_ERR(ext_csd)) + return COMMAND_ERROR; + + if (!(ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & EXT_CSD_ENH_ATTRIBUTE_EN_MASK)) { + printf("Device doesn't support enhanced area\n"); + goto error; + } + + if (ext_csd[EXT_CSD_PARTITION_SETTING_COMPLETED]) { + printf("Partitioning already finalized\n"); + goto error; + } + + ret = mmc_enh_area_setmax(mci, ext_csd); + if (ret) + goto error; + + free(ext_csd); + + if (set_completed) { + ret = mmc_partitioning_complete(mci); + if (ret) + return COMMAND_ERROR; + printf("Now power cycle the device to let it reconfigure itself.\n"); + } + + return COMMAND_SUCCESS; + +error: + free(ext_csd); + return COMMAND_ERROR; +} + +static struct { + const char *cmd; + int (*func)(int argc, char *argv[]); +} mmc_subcmds[] = { + { + .cmd = "enh_area", + .func = do_mmc_enh_area, + } +}; + +static int do_mmc(int argc, char *argv[]) +{ + size_t i; + int (*func)(int argc, char *argv[]) = NULL; + + if (argc < 2) { + printf("mmc: required subcommand missing\n"); + return 1; + } + + for (i = 0; i < ARRAY_SIZE(mmc_subcmds); ++i) { + if (strcmp(mmc_subcmds[i].cmd, argv[1]) == 0) { + func = mmc_subcmds[i].func; + break; + } + } + + if (func) { + return func(argc - 1, argv + 1); + } else { + printf("mmc: subcommand \"%s\" not found\n", argv[1]); + return COMMAND_ERROR_USAGE; + } +} + +BAREBOX_CMD_HELP_START(mmc) +BAREBOX_CMD_HELP_TEXT("Modifies mmc properties.") +BAREBOX_CMD_HELP_TEXT("") +BAREBOX_CMD_HELP_TEXT("The subcommand enh_area creates an enhanced area of") +BAREBOX_CMD_HELP_TEXT("maximal size.") +BAREBOX_CMD_HELP_TEXT("Note, with -c this is an irreversible action.") +BAREBOX_CMD_HELP_OPT("-c", "complete partitioning") +BAREBOX_CMD_HELP_END + +BAREBOX_CMD_START(mmc) + .cmd = do_mmc, + BAREBOX_CMD_OPTS("enh_area setmax [-c] /dev/mmcX") + BAREBOX_CMD_HELP(cmd_mmc_help) +BAREBOX_CMD_END diff --git a/include/mci.h b/include/mci.h index 072008ef9da7..f70184f3b4ab 100644 --- a/include/mci.h +++ b/include/mci.h @@ -304,6 +304,13 @@ #define EXT_CSD_CARD_TYPE_SDR_1_2V (1<<5) /* Card can run at 200MHz */ /* SDR mode @1.2V I/O */ +/* register PARTITIONS_ATTRIBUTE [156] */ +#define EXT_CSD_ENH_USR_MASK (1 << 0) + +/* register PARTITIONING_SUPPORT [160] */ +#define EXT_CSD_ENH_ATTRIBUTE_EN_MASK (1 << 0) + +/* register BUS_WIDTH [183], field Bus Mode Selection [4:0] */ #define EXT_CSD_BUS_WIDTH_1 0 /* Card is in 1 bit mode */ #define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */ #define EXT_CSD_BUS_WIDTH_8 2 /* Card is in 8 bit mode */ -- 2.19.0 _______________________________________________ barebox mailing list barebox@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/barebox