summaryrefslogtreecommitdiffstats
path: root/commands/mmc.c
diff options
context:
space:
mode:
Diffstat (limited to 'commands/mmc.c')
-rw-r--r--commands/mmc.c196
1 files changed, 196 insertions, 0 deletions
diff --git a/commands/mmc.c b/commands/mmc.c
new file mode 100644
index 0000000000..c696e7b881
--- /dev/null
+++ b/commands/mmc.c
@@ -0,0 +1,196 @@
+#include <command.h>
+#include <mci.h>
+#include <stdio.h>
+#include <string.h>
+#include <getopt.h>
+
+static int mmc_enh_area_setmax(struct mci *mci, u8 *ext_csd)
+{
+ unsigned i;
+ struct {
+ unsigned index;
+ unsigned value;
+ } regval[] = {
+ {
+ .index = EXT_CSD_ERASE_GROUP_DEF,
+ .value = 1,
+ }, {
+ .index = EXT_CSD_ENH_START_ADDR,
+ .value = 0,
+ }, {
+ .index = EXT_CSD_ENH_START_ADDR + 1,
+ .value = 0,
+ }, {
+ .index = EXT_CSD_ENH_START_ADDR + 2,
+ .value = 0,
+ }, {
+ .index = EXT_CSD_ENH_START_ADDR + 3,
+ .value = 0,
+ }, {
+ .index = EXT_CSD_ENH_SIZE_MULT,
+ .value = ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT],
+ }, {
+ .index = EXT_CSD_ENH_SIZE_MULT + 1,
+ .value = ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT + 1],
+ }, {
+ .index = EXT_CSD_ENH_SIZE_MULT + 2,
+ .value = ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT + 2],
+ }, {
+ .index = EXT_CSD_PARTITIONS_ATTRIBUTE,
+ .value = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] | EXT_CSD_ENH_USR_MASK,
+ }
+ };
+
+ for (i = 0; i < ARRAY_SIZE(regval); ++i) {
+ int ret = mci_switch(mci, regval[i].index, regval[i].value);
+ if (ret) {
+ printf("Failure to write to register %u", regval[i].index);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+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");
+ free(ext_csd);
+ return ERR_PTR(-EIO);
+ }
+
+ return ext_csd;
+}
+
+/* enh_area [-c] /dev/mmcX */
+static int do_mmc_enh_area(int argc, char *argv[])
+{
+ const char *devpath;
+ struct mci *mci;
+ u8 *ext_csd;
+ int set_completed = 0;
+ int opt;
+ int ret;
+
+ while ((opt = getopt(argc, argv, "c")) > 0) {
+ switch (opt) {
+ case 'c':
+ set_completed = 1;
+ break;
+ }
+ }
+
+ if (argc - optind != 1) {
+ printf("Usage: mmc enh_area [-c] /dev/mmcX\n");
+ return COMMAND_ERROR_USAGE;
+ }
+
+ devpath = argv[optind];
+
+ mci = mci_get_device_by_devpath(devpath);
+ if (!mci) {
+ printf("Failure to open %s as mci device\n", devpath);
+ 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 [-c] /dev/mmcX")
+ BAREBOX_CMD_HELP(cmd_mmc_help)
+BAREBOX_CMD_END