summaryrefslogtreecommitdiffstats
path: root/drivers/mci/mci-core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mci/mci-core.c')
-rw-r--r--drivers/mci/mci-core.c86
1 files changed, 70 insertions, 16 deletions
diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c
index 1b0c808559..07eca96a9d 100644
--- a/drivers/mci/mci-core.c
+++ b/drivers/mci/mci-core.c
@@ -494,7 +494,9 @@ int mci_send_ext_csd(struct mci *mci, char *ext_csd)
*/
int mci_switch(struct mci *mci, unsigned index, unsigned value)
{
+ unsigned int status;
struct mci_cmd cmd;
+ int ret;
mci_setup_cmd(&cmd, MMC_CMD_SWITCH,
(MMC_SWITCH_MODE_WRITE_BYTE << 24) |
@@ -502,7 +504,35 @@ int mci_switch(struct mci *mci, unsigned index, unsigned value)
(value << 8),
MMC_RSP_R1b);
- return mci_send_cmd(mci, &cmd, NULL);
+ ret = mci_send_cmd(mci, &cmd, NULL);
+ if (ret)
+ return ret;
+
+ ret = mci_send_status(mci, &status);
+ if (ret)
+ return ret;
+
+ if (status & R1_SWITCH_ERROR)
+ return -EIO;
+
+ return 0;
+}
+
+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;
}
static blkcnt_t mci_calc_blk_cnt(blkcnt_t cap, unsigned shift)
@@ -1193,9 +1223,6 @@ static int mci_mmc_try_bus_width(struct mci *mci, enum mci_bus_width bus_width,
u32 ext_csd_bits;
int err;
- dev_dbg(&mci->dev, "attempting buswidth %u%s\n", 1 << bus_width,
- mci_timing_is_ddr(timing) ? " (DDR)" : "");
-
ext_csd_bits = mci_bus_width_ext_csd_bits(bus_width);
if (mci_timing_is_ddr(timing))
@@ -1203,16 +1230,20 @@ static int mci_mmc_try_bus_width(struct mci *mci, enum mci_bus_width bus_width,
err = mci_switch(mci, EXT_CSD_BUS_WIDTH, ext_csd_bits);
if (err < 0)
- return err;
+ goto out;
mci->host->timing = timing;
mci_set_bus_width(mci, bus_width);
err = mmc_compare_ext_csds(mci, bus_width);
if (err < 0)
- return err;
+ goto out;
+
+out:
+ dev_dbg(&mci->dev, "Tried buswidth %u%s: %s\n", 1 << bus_width,
+ mci_timing_is_ddr(timing) ? " (DDR)" : "", err ? "failed" : "OK");
- return bus_width;
+ return err ?: bus_width;
}
static int mci_mmc_select_bus_width(struct mci *mci)
@@ -1944,6 +1975,22 @@ static int of_broken_cd_fixup(struct device_node *root, void *ctx)
return 0;
}
+static int mci_get_partition_setting_completed(struct mci *mci)
+{
+ u8 *ext_csd;
+ int ret;
+
+ ext_csd = mci_get_ext_csd(mci);
+ if (IS_ERR(ext_csd))
+ return PTR_ERR(ext_csd);
+
+ ret = ext_csd[EXT_CSD_PARTITION_SETTING_COMPLETED];
+
+ free(ext_csd);
+
+ return ret;
+}
+
/**
* Probe an MCI card at the given host interface
* @param mci MCI device instance
@@ -2055,6 +2102,13 @@ static int mci_card_probe(struct mci *mci)
dev_add_param_bool(&mci->dev, "boot_ack",
mci_set_boot_ack, NULL,
&mci->boot_ack_enable, mci);
+
+ ret = mci_get_partition_setting_completed(mci);
+ if (ret < 0)
+ dev_dbg(&mci->dev,
+ "Failed to determine EXT_CSD_PARTITION_SETTING_COMPLETED\n");
+ else
+ dev_add_param_bool_fixed(&mci->dev, "partitioning_completed", ret);
}
dev_dbg(&mci->dev, "SD Card successfully added\n");
@@ -2134,7 +2188,7 @@ int mci_register(struct mci_host *host)
{
struct mci *mci;
struct device *hw_dev;
- struct param_d *param_probe, *param_broken_cd;
+ struct param_d *param;
int ret;
mci = xzalloc(sizeof(*mci));
@@ -2179,20 +2233,20 @@ int mci_register(struct mci_host *host)
dev_info(hw_dev, "registered as %s\n", dev_name(&mci->dev));
- param_probe = dev_add_param_bool(&mci->dev, "probe",
- mci_set_probe, NULL, &mci->probe, mci);
+ param = dev_add_param_bool(&mci->dev, "probe", mci_set_probe, NULL,
+ &mci->probe, mci);
- if (IS_ERR(param_probe) && PTR_ERR(param_probe) != -ENOSYS) {
- ret = PTR_ERR(param_probe);
+ if (IS_ERR(param) && PTR_ERR(param) != -ENOSYS) {
+ ret = PTR_ERR(param);
dev_dbg(&mci->dev, "Failed to add 'probe' parameter to the MCI device\n");
goto err_unregister;
}
- param_broken_cd = dev_add_param_bool(&mci->dev, "broken_cd",
- NULL, NULL, &host->broken_cd, mci);
+ param = dev_add_param_bool(&mci->dev, "broken_cd", NULL, NULL,
+ &host->broken_cd, mci);
- if (IS_ERR(param_broken_cd) && PTR_ERR(param_broken_cd) != -ENOSYS) {
- ret = PTR_ERR(param_broken_cd);
+ if (IS_ERR(param) && PTR_ERR(param) != -ENOSYS) {
+ ret = PTR_ERR(param);
dev_dbg(&mci->dev, "Failed to add 'broken_cd' parameter to the MCI device\n");
goto err_unregister;
}