[U-Boot] [PATCH v2 24/26] mmc: use the right voltage level for MMC DDR and HS200 modes
Jaehoon Chung
jh80.chung at samsung.com
Fri Sep 22 13:54:40 UTC 2017
On 09/21/2017 11:30 PM, Jean-Jacques Hiblot wrote:
> HS200 only supports 1.2v and 1.8v signal voltages. DDR52 supports 3.3v/1.8v
> or 1.2v signal voltages.
> Select the lowest voltage available when using those modes.
>
> Signed-off-by: Jean-Jacques Hiblot <jjhiblot at ti.com>
> ---
> drivers/mmc/mmc.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
> include/mmc.h | 20 +++++++++++++---
> 2 files changed, 84 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
> index 6d1bf94..2d447dd 100644
> --- a/drivers/mmc/mmc.c
> +++ b/drivers/mmc/mmc.c
> @@ -767,6 +767,7 @@ static int mmc_get_capabilities(struct mmc *mmc)
> mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
>
> cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0x3f;
> + mmc->cardtype = cardtype;
>
> if (cardtype & (EXT_CSD_CARD_TYPE_HS200_1_2V |
> EXT_CSD_CARD_TYPE_HS200_1_8V)) {
> @@ -1441,10 +1442,30 @@ struct mode_width_tuning {
> uint tuning;
> };
>
> +int mmc_voltage_to_mv(enum mmc_voltage voltage)
> +{
> + switch (voltage) {
> + case MMC_SIGNAL_VOLTAGE_000: return 0;
> + case MMC_SIGNAL_VOLTAGE_330: return 3300;
> + case MMC_SIGNAL_VOLTAGE_180: return 1800;
> + case MMC_SIGNAL_VOLTAGE_120: return 1200;
Plz, change line.
case xxx:
return xxx;
> + }
> + return -EINVAL;
> +}
> +
> static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage)
> {
> + int err;
Initialized err = 0
> +
> + if (mmc->signal_voltage == signal_voltage)
> + return 0;
return err; or use return ret?
> +
> mmc->signal_voltage = signal_voltage;
> - return mmc_set_ios(mmc);
> + err = mmc_set_ios(mmc);
> + if (err)
> + debug("unable to set voltage (err %d)\n", err);
> +
> + return err;
> }
>
> static const struct mode_width_tuning sd_modes_by_pref[] = {
> @@ -1584,6 +1605,43 @@ static int mmc_read_and_compare_ext_csd(struct mmc *mmc)
> return -EBADMSG;
> }
>
> +static int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode,
> + uint32_t allowed_mask)
> +{
> + u32 card_mask = 0;
> +
> + switch (mode) {
> + case MMC_HS_200:
> + if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_8V)
> + card_mask |= MMC_SIGNAL_VOLTAGE_180;
> + if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_2V)
> + card_mask |= MMC_SIGNAL_VOLTAGE_120;
> + break;
> + case MMC_DDR_52:
> + if (mmc->cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V)
> + card_mask |= MMC_SIGNAL_VOLTAGE_330 |
> + MMC_SIGNAL_VOLTAGE_180;
> + if (mmc->cardtype & EXT_CSD_CARD_TYPE_DDR_1_2V)
> + card_mask |= MMC_SIGNAL_VOLTAGE_120;
> + break;
> + default:
> + card_mask |= MMC_SIGNAL_VOLTAGE_330;
> + break;
> + }
> +
> + while (card_mask & allowed_mask) {
> + enum mmc_voltage best_match;
> +
> + best_match = 1 << (ffs(card_mask & allowed_mask) - 1);
> + if (!mmc_set_signal_voltage(mmc, best_match))
> + return 0;
Just return 0?
> +
> + allowed_mask &= ~best_match;
> + }
> +
> + return -ENOTSUPP;
> +}
> +
> static const struct mode_width_tuning mmc_modes_by_pref[] = {
> {
> .mode = MMC_HS_200,
> @@ -1655,10 +1713,17 @@ static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps)
> for_each_mmc_mode_by_pref(card_caps, mwt) {
> for_each_supported_width(card_caps & mwt->widths,
> mmc_is_mode_ddr(mwt->mode), ecbw) {
> + enum mmc_voltage old_voltage;
> debug("trying mode %s width %d (at %d MHz)\n",
> mmc_mode_name(mwt->mode),
> bus_width(ecbw->cap),
> mmc_mode2freq(mmc, mwt->mode) / 1000000);
> + old_voltage = mmc->signal_voltage;
> + err = mmc_set_lowest_voltage(mmc, mwt->mode,
> + MMC_ALL_SIGNAL_VOLTAGE);
> + if (err)
> + continue;
> +
> /* configure the bus width (card + host) */
> err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
> EXT_CSD_BUS_WIDTH,
> @@ -1702,6 +1767,7 @@ static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps)
> if (!err)
> return 0;
> error:
> + mmc_set_signal_voltage(mmc, old_voltage);
doesn't need to check the return value?
> /* if an error occured, revert to a safer bus mode */
> mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
> EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_1);
> diff --git a/include/mmc.h b/include/mmc.h
> index a9ebc88..c11f698 100644
> --- a/include/mmc.h
> +++ b/include/mmc.h
> @@ -311,11 +311,15 @@ static inline bool mmc_is_tuning_cmd(uint cmdidx)
>
> enum mmc_voltage {
> MMC_SIGNAL_VOLTAGE_000 = 0,
> - MMC_SIGNAL_VOLTAGE_120,
> - MMC_SIGNAL_VOLTAGE_180,
> - MMC_SIGNAL_VOLTAGE_330
> + MMC_SIGNAL_VOLTAGE_120 = 1,
> + MMC_SIGNAL_VOLTAGE_180 = 2,
> + MMC_SIGNAL_VOLTAGE_330 = 4,
> };
>
> +#define MMC_ALL_SIGNAL_VOLTAGE (MMC_SIGNAL_VOLTAGE_120 |\
> + MMC_SIGNAL_VOLTAGE_180 |\
> + MMC_SIGNAL_VOLTAGE_330)
> +
> /* Maximum block size for MMC */
> #define MMC_MAX_BLOCK_LEN 512
>
> @@ -588,6 +592,8 @@ struct mmc {
> #endif
> #endif
> u8 *ext_csd;
> + u32 cardtype; /* cardtype read from the MMC */
> + enum mmc_voltage current_voltage;
> enum bus_mode selected_mode; /* mode currently used */
> enum bus_mode best_mode; /* best mode is the supported mode with the
> * highest bandwidth. It may not always be the
> @@ -647,6 +653,14 @@ int mmc_init(struct mmc *mmc);
> int mmc_read(struct mmc *mmc, u64 src, uchar *dst, int size);
>
> /**
> + * mmc_voltage_to_mv() - Convert a mmc_voltage in mV
> + *
> + * @voltage: The mmc_voltage to convert
> + * @return the value in mV if OK, -EINVAL on error (invalid mmc_voltage value)
> + */
> +int mmc_voltage_to_mv(enum mmc_voltage voltage);
> +
> +/**
> * mmc_set_clock() - change the bus clock
> * @mmc: MMC struct
> * @clock: bus frequency in Hz
>
More information about the U-Boot
mailing list