summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2020-09-25 08:06:22 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2020-09-25 08:06:22 +0200
commit1ab2e649dc0ccef7ee990b999e1d8f8c32e7cd24 (patch)
tree66f02471e811228f4da2580109b7d26c68ebe90a
parent39bdcdfb814a22c8143c04938268378e9994b7dd (diff)
parent94c0b6c798f619bd45aa1411a2ffedba86cad063 (diff)
downloadbarebox-1ab2e649dc0ccef7ee990b999e1d8f8c32e7cd24.tar.gz
barebox-1ab2e649dc0ccef7ee990b999e1d8f8c32e7cd24.tar.xz
Merge branch 'for-next/mmc' into master
-rw-r--r--commands/mmc_extcsd.c25
-rw-r--r--common/blspec.c11
-rw-r--r--common/fastboot.c2
-rw-r--r--common/globalvar.c5
-rw-r--r--drivers/mci/Kconfig20
-rw-r--r--drivers/mci/mci-core.c96
-rw-r--r--include/globalvar.h1
-rw-r--r--include/mci.h3
8 files changed, 136 insertions, 27 deletions
diff --git a/commands/mmc_extcsd.c b/commands/mmc_extcsd.c
index c9a28fb1fe..7ae068348d 100644
--- a/commands/mmc_extcsd.c
+++ b/commands/mmc_extcsd.c
@@ -11,6 +11,7 @@
#include <mci.h>
#include <getopt.h>
#include <fs.h>
+#include <linux/sizes.h>
#define EXT_CSD_BLOCKSIZE 512
@@ -1142,7 +1143,7 @@ static int print_field(u8 *reg, int index)
return 1;
case EXT_CSD_SEC_COUNT:
- tmp64 = val * 512;
+ tmp64 *= 512;
printf("\tDevice density: %llu B\n", tmp64);
return 1;
@@ -1232,7 +1233,7 @@ static int print_field(u8 *reg, int index)
case EXT_CSD_HC_ERASE_GRP_SIZE:
val = get_field_val(EXT_CSD_HC_ERASE_GRP_SIZE, 0, 0xFF);
- val = val * 524288;
+ val = val * SZ_512K;
if (val)
str = basprintf("Erase-unit size: %u", val);
else
@@ -1342,7 +1343,8 @@ static int print_field(u8 *reg, int index)
case EXT_CSD_ENH_SIZE_MULT:
tmp = get_field_val(EXT_CSD_HC_WP_GRP_SIZE, 0, 0xFF);
tmp = tmp + get_field_val(EXT_CSD_HC_ERASE_GRP_SIZE, 0, 0xFF);
- tmp64 = val * tmp * 524288;
+ tmp64 *= tmp;
+ tmp64 *= SZ_512K;
printf("\tEnhanced User Data Area %i Size: %llu B\n",
index - EXT_CSD_ENH_SIZE_MULT, tmp64);
return 1;
@@ -1350,28 +1352,32 @@ static int print_field(u8 *reg, int index)
case EXT_CSD_GP_SIZE_MULT3:
tmp = get_field_val(EXT_CSD_HC_WP_GRP_SIZE, 0, 0xFF);
tmp = tmp + get_field_val(EXT_CSD_HC_ERASE_GRP_SIZE, 0, 0xFF);
- tmp64 = val * tmp * 524288;
+ tmp64 *= tmp;
+ tmp64 *= SZ_512K;
printf("\tGeneral_Purpose_Partition_3 Size: %llu B\n", tmp64);
return 1;
case EXT_CSD_GP_SIZE_MULT2:
tmp = get_field_val(EXT_CSD_HC_WP_GRP_SIZE, 0, 0xFF);
tmp = tmp + get_field_val(EXT_CSD_HC_ERASE_GRP_SIZE, 0, 0xFF);
- tmp64 = val * tmp * 524288;
+ tmp64 *= tmp;
+ tmp64 *= SZ_512K;
printf("\tGeneral_Purpose_Partition_2 Size: %llu B\n", tmp64);
return 1;
case EXT_CSD_GP_SIZE_MULT1:
tmp = get_field_val(EXT_CSD_HC_WP_GRP_SIZE, 0, 0xFF);
tmp = tmp + get_field_val(EXT_CSD_HC_ERASE_GRP_SIZE, 0, 0xFF);
- tmp64 = val * tmp * 524288;
+ tmp64 *= tmp;
+ tmp64 *= SZ_512K;
printf("\tGeneral_Purpose_Partition_1 Size: %llu B\n", tmp64);
return 1;
case EXT_CSD_GP_SIZE_MULT0:
tmp = get_field_val(EXT_CSD_HC_WP_GRP_SIZE, 0, 0xFF);
tmp = tmp + get_field_val(EXT_CSD_HC_ERASE_GRP_SIZE, 0, 0xFF);
- tmp64 = val * tmp * 524288;
+ tmp64 *= tmp;
+ tmp64 *= SZ_512K;
printf("\tGeneral_Purpose_Partition_0 Size: %llu B\n", tmp64);
return 1;
@@ -1422,7 +1428,8 @@ static int print_field(u8 *reg, int index)
case EXT_CSD_MAX_ENH_SIZE_MULT:
tmp = get_field_val(EXT_CSD_HC_WP_GRP_SIZE, 0, 0xFF);
tmp = tmp + get_field_val(EXT_CSD_HC_ERASE_GRP_SIZE, 0, 0xFF);
- tmp64 = val * tmp * 524288;
+ tmp64 *= tmp;
+ tmp64 *= SZ_512K;
printf("\tMax Enhanced Area: %llu B\n", tmp64);
return 1;
@@ -2156,7 +2163,7 @@ static int print_field(u8 *reg, int index)
str = "FIFO policy for cache";
else
str = "not provided";
- printf("\t[0] Device flushing: %s", str);
+ printf("\t[0] Device flushing: %s\n", str);
return 1;
case EXT_CSD_OPTIMAL_READ_SIZE:
diff --git a/common/blspec.c b/common/blspec.c
index ed66352d11..9499d32477 100644
--- a/common/blspec.c
+++ b/common/blspec.c
@@ -133,19 +133,18 @@ static int blspec_boot(struct bootentry *be, int verbose, int dryrun)
const char *overlays;
const char *appendroot;
struct bootm_data data = {
- .initrd_address = UIMAGE_INVALID_ADDRESS,
- .os_address = UIMAGE_SOME_ADDRESS,
- .verbose = verbose,
.dryrun = dryrun,
};
globalvar_set_match("linux.bootargs.dyn.", "");
- globalvar_set_match("bootm.image", "");
- globalvar_set_match("bootm.oftree", "");
- globalvar_set_match("bootm.initrd", "");
+ globalvar_set("bootm.image", "");
+ globalvar_set("bootm.oftree", "");
+ globalvar_set("bootm.initrd", "");
bootm_data_init_defaults(&data);
+ data.verbose = verbose || data.verbose;
+
devicetree = blspec_entry_var_get(entry, "devicetree");
initrd = blspec_entry_var_get(entry, "initrd");
options = blspec_entry_var_get(entry, "options");
diff --git a/common/fastboot.c b/common/fastboot.c
index 302720c43d..86e7997a0b 100644
--- a/common/fastboot.c
+++ b/common/fastboot.c
@@ -383,7 +383,7 @@ static void __maybe_unused cb_boot(struct fastboot *fb, const char *opt)
fastboot_tx_print(fb, FASTBOOT_MSG_INFO, "Booting kernel..\n");
globalvar_set_match("linux.bootargs.dyn.", "");
- globalvar_set_match("bootm.image", "");
+ globalvar_set("bootm.image", "");
data.os_file = fb->tempname;
diff --git a/common/globalvar.c b/common/globalvar.c
index 6ab4c1f68e..eefee73e7a 100644
--- a/common/globalvar.c
+++ b/common/globalvar.c
@@ -399,6 +399,11 @@ void globalvar_set_match(const char *match, const char *val)
}
}
+void globalvar_set(const char *name, const char *val)
+{
+ dev_set_param(&global_device, name, val);
+}
+
static int globalvar_simple_set(struct device_d *dev, struct param_d *p, const char *val)
{
struct device_d *rdev;
diff --git a/drivers/mci/Kconfig b/drivers/mci/Kconfig
index 09c0569286..b4c4072596 100644
--- a/drivers/mci/Kconfig
+++ b/drivers/mci/Kconfig
@@ -34,6 +34,26 @@ config MCI_WRITE
config MCI_MMC_BOOT_PARTITIONS
bool "support MMC boot partitions"
+ help
+ Provide access to the 'boot partitions' of devices of type 'MMC'.
+ These so called 'hardware partitions' act like an independent memory
+ device and thus, need special handling.
+
+ Note: only 'MMC' have 'boot partitions'. So, if you don't use an
+ 'MMC' device, you don't need this support.
+
+config MCI_MMC_GPP_PARTITIONS
+ bool "support MMC general purpose partitions (GPP)"
+ help
+ Provide access to the 'general purpose partitions' of devices of type
+ 'MMC'. These so called 'hardware partitions' act like an independent
+ memory device and thus, need special handling.
+
+ Note: only 'MMC' devices have 'general purpose partitions'. So, if
+ you don't use an 'MMC' device, you don't need this support.
+
+ Note: by default, 'MMC' devices have no 'general purpose partitions',
+ it requires a special one-time configuration step to enable them.
comment "--- MCI host drivers ---"
diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c
index a58dedc1cd..2261fd1c1b 100644
--- a/drivers/mci/mci-core.c
+++ b/drivers/mci/mci-core.c
@@ -33,6 +33,7 @@
#include <disks.h>
#include <of.h>
#include <linux/err.h>
+#include <linux/sizes.h>
#define MAX_BUFFER_NUMBER 0xffffffff
@@ -361,9 +362,9 @@ static int mmc_send_op_cond(struct mci *mci)
}
/**
- * FIXME
- * @param mci MCI instance
- * @param ext_csd Buffer for a 512 byte sized extended CSD
+ * Read-in the card's whole extended CSD configuration area
+ * @param[in] mci MCI instance
+ * @param[out] ext_csd Buffer for an #EXT_CSD_BLOCKSIZE byte sized extended CSD
* @return Transaction status (0 on success)
*
* Note: Only cards newer than Version 1.1 (Physical Layer Spec) support
@@ -386,12 +387,16 @@ int mci_send_ext_csd(struct mci *mci, char *ext_csd)
}
/**
- * FIXME
- * @param mci MCI instance
- * @param set FIXME
- * @param index FIXME
- * @param value FIXME
+ * Write a byte into the card's extended CSD configuration area
+ * @param[in] mci MCI instance
+ * @param[in] index Byte index in the extended CSD configuration area
+ * @param[in] value Byte to write at index into the extended CSD configuration area
* @return Transaction status (0 on success)
+ *
+ * This sends a CMD6 (aka SWITCH) to the card and writes @b value at extended CSD @b index.
+ *
+ * @note It always writes a full byte, the alternatives 'bit set' and
+ * 'bit clear' aren't supported.
*/
int mci_switch(struct mci *mci, unsigned index, unsigned value)
{
@@ -441,6 +446,69 @@ static void mci_part_add(struct mci *mci, uint64_t size,
}
/**
+ * Read a value spread to three consecutive bytes in the ECSD information
+ * @param[in] ecsd_info Information from the eMMC
+ * @param[in] idx The index where to start to read
+ * @return The GPP size in units of 'write protect group' size
+ *
+ * The value in the ECSD information block is meant in little endian
+ */
+static __maybe_unused unsigned mmc_extract_gpp_units(const char *ecsd_info, unsigned idx)
+{
+ unsigned val;
+
+ val = ecsd_info[idx];
+ val |= ecsd_info[idx + 1] << 8;
+ val |= ecsd_info[idx + 2] << 16;
+
+ return val;
+}
+
+/**
+ * Create and enable access to 'general purpose hardware partitions' on demand
+ * @param mci[in,out] MCI instance
+ *
+ * General Purpose hardware Partitions (aka GPPs) aren't enabled by default. Its
+ * up to the application to (one-time) setup the eMMC to provide GPPs. Since
+ * they aren't wildly used, enable access to them on demand only.
+ */
+static __maybe_unused void mmc_extract_gpp_partitions(struct mci *mci)
+{
+ uint64_t wpgs, part_size;
+ size_t idx;
+ char *name, *partname;
+ static const unsigned gpp_offsets[MMC_NUM_GP_PARTITION] = {
+ EXT_CSD_GP_SIZE_MULT0, EXT_CSD_GP_SIZE_MULT1,
+ EXT_CSD_GP_SIZE_MULT2, EXT_CSD_GP_SIZE_MULT3, };
+
+ if (!(mci->ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & 0x01))
+ return; /* no partitioning support */
+ /*
+ * The size of GPPs is defined in units of 'write protect group' size.
+ * The 'write protect group' size is defined to:
+ * CSD_HC_ERASE_GRP_SIZE * CSD_HC_WP_GRP_SIZE * 512 kiB
+ */
+ wpgs = mci->ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
+ wpgs *= mci->ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
+ wpgs *= SZ_512K;
+
+ /* up to four GPPs can be enabled. */
+ for (idx = 0; idx < ARRAY_SIZE(gpp_offsets); idx++) {
+ part_size = mmc_extract_gpp_units(mci->ext_csd, gpp_offsets[idx]);
+ if (part_size == 0)
+ continue;
+ /* Convert to bytes */
+ part_size *= wpgs;
+
+ partname = xasprintf("gpp%zu", idx);
+ name = xasprintf("%s.%s", mci->cdevname, partname);
+ /* TODO read-only flag */
+ mci_part_add(mci, part_size, EXT_CSD_PART_CONFIG_ACC_GPP0 + idx,
+ name, partname, idx, false, MMC_BLK_DATA_AREA_GP);
+ }
+}
+
+/**
* Change transfer frequency for an MMC card
* @param mci MCI instance
* @return Transaction status (0 on success)
@@ -515,6 +583,9 @@ static int mmc_change_freq(struct mci *mci)
mci->bootpart = (mci->ext_csd_part_config >> 3) & 0x7;
}
+ if (IS_ENABLED(CONFIG_MCI_MMC_GPP_PARTITIONS))
+ mmc_extract_gpp_partitions(mci);
+
return 0;
}
@@ -1239,13 +1310,16 @@ static int sd_send_if_cond(struct mci *mci)
return 0;
}
+/**
+ * Switch between hardware MMC partitions on demand
+ */
static int mci_blk_part_switch(struct mci_part *part)
{
struct mci *mci = part->mci;
int ret;
- if (!IS_ENABLED(CONFIG_MCI_MMC_BOOT_PARTITIONS))
- return 0;
+ if (!IS_ENABLED(CONFIG_MCI_MMC_BOOT_PARTITIONS) && !IS_ENABLED(CONFIG_MCI_MMC_GPP_PARTITIONS))
+ return 0; /* no need */
if (mci->part_curr == part)
return 0;
@@ -1637,6 +1711,8 @@ static int mci_register_partition(struct mci_part *part)
break;
case MMC_BLK_DATA_AREA_MAIN:
break;
+ case MMC_BLK_DATA_AREA_GP:
+ break;
default:
return 0;
}
diff --git a/include/globalvar.h b/include/globalvar.h
index 6f2c6db746..face53d33f 100644
--- a/include/globalvar.h
+++ b/include/globalvar.h
@@ -15,6 +15,7 @@ int globalvar_add_simple(const char *name, const char *value);
void globalvar_remove(const char *name);
char *globalvar_get_match(const char *match, const char *separator);
void globalvar_set_match(const char *match, const char *val);
+void globalvar_set(const char *name, const char *val);
int globalvar_add_simple_string(const char *name, char **value);
int globalvar_add_simple_int(const char *name, int *value,
diff --git a/include/mci.h b/include/mci.h
index 96547fb396..5e6805e8dc 100644
--- a/include/mci.h
+++ b/include/mci.h
@@ -277,6 +277,7 @@
*/
#define EXT_CSD_PART_CONFIG_ACC_MASK (0x7)
#define EXT_CSD_PART_CONFIG_ACC_BOOT0 (0x1)
+#define EXT_CSD_PART_CONFIG_ACC_GPP0 (0x4)
#define EXT_CSD_CMD_SET_NORMAL (1<<0)
#define EXT_CSD_CMD_SET_SECURE (1<<1)
@@ -456,7 +457,7 @@ struct mci {
uint64_t capacity; /**< Card's data capacity in bytes */
int ready_for_use; /** true if already probed */
int dsr_imp; /**< DSR implementation state from CSD */
- char *ext_csd;
+ u8 *ext_csd;
int probe;
struct param_d *param_boot;
int bootpart;