Re: [PATCH v2 1/1] sdhci support emmc ddr50 mode

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, Dec 8, 2010 at 9:45 AM, Philip Rakity <prakity@xxxxxxxxxxx> wrote:
>
> On Dec 6, 2010, at 8:09 PM, Zhangfei Gao wrote:
>
>> On Mon, Dec 6, 2010 at 10:36 PM, zhangfei gao <zhangfei.gao@xxxxxxxxx> wrote:
>>> On Mon, Dec 6, 2010 at 10:10 PM, Philip Rakity <prakity@xxxxxxxxxxx> wrote:
>>>>
>>>> On Dec 6, 2010, at 4:15 AM, Zhangfei Gao wrote:
>>>>
>>>>> From f2194b46c2c3ded86009d36a4a8b4eebb7d0b9eb Mon Sep 17 00:00:00 2001
>>>>> From: Zhangfei Gao <zhangfei.gao@xxxxxxxxxxx>
>>>>> Date: Fri, 3 Dec 2010 07:21:15 -0500
>>>>> Subject: [PATCH] mmc: sdhci support emmc ddr50 mode
>>>>>
>>>>>       1. spec 3.0 does not claim support 1.2v ddr mode
>>>>>       2. Call back function set_power is added, since some controller count
>>>>> on external pmic to provide power
>>>>>
>>>>> Signed-off-by: Zhangfei Gao <zhangfei.gao@xxxxxxxxxxx>
>>>>> ---
>>>>> drivers/mmc/core/core.c   |    8 ++++++++
>>>>> drivers/mmc/host/sdhci.c  |   36 +++++++++++++++++++++++++++++++++++-
>>>>> drivers/mmc/host/sdhci.h  |   14 ++++++++++++--
>>>>> include/linux/mmc/mmc.h   |    1 +
>>>>> include/linux/mmc/sdhci.h |    2 ++
>>>>> 5 files changed, 58 insertions(+), 3 deletions(-)
>>>>>
>>>>> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
>>>>> index 8bf542c..8f172cd 100644
>>>>> --- a/drivers/mmc/core/core.c
>>>>> +++ b/drivers/mmc/core/core.c
>>>>> @@ -1573,6 +1573,14 @@ void mmc_rescan(struct work_struct *work)
>>>>>                */
>>>>>               err = mmc_send_op_cond(host, 0, &ocr);
>>>>>               if (!err) {
>>>>> +                     if ((ocr & MMC_CARD_1_8V)
>>>>> +                             && (host->ocr_avail & MMC_CARD_1_8V)) {
>>>>> +                             /* switch voltage to 1.8v */
>>>>> +                             mmc_power_off(host);
>>>>> +                             host->ocr = ocr & host->ocr_avail;
>>>>> +                             mmc_power_up(host);
>>>>> +                     }
>>>>> +
>>>>
>>>> is the 1.2v case missing ?
>>> ocr does not support 1.2.
>>>>
>>>> /*
>>>>  * Mask off any voltages we don't support and select
>>>>  * the lowest voltage
>>>>  */
>>>> u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
>>>>
>>>> Doesn't this code already handle the voltage correctly ?
>>> mmc_select_voltage can not meet the requirement, if switch voltage,
>>> power down and power up is needed, time delay is required waiting for
>>> voltage to be stable.
>>>
>>>>
>>>>
>>>>>                       if (mmc_attach_mmc(host, ocr))
>>>>>                               mmc_power_off(host);
>>>>>                       goto out;
>>>>> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
>>>>> index a25db42..b7ad2f6 100644
>>>>> --- a/drivers/mmc/host/sdhci.c
>>>>> +++ b/drivers/mmc/host/sdhci.c
>>>>> @@ -982,6 +982,22 @@ static void sdhci_finish_command(struct sdhci_host *host)
>>>>>       host->cmd = NULL;
>>>>> }
>>>>>
>>>>> +static void sdhci_set_ddr(struct sdhci_host *host, unsigned int ddr)
>>>>> +{
>>>>> +     u16 con;
>>>>> +
>>>>> +     if (ddr == MMC_SDR_MODE)
>>>>> +             return;
>>>>> +
>>>>> +     con = sdhci_readw(host, SDHCI_HOST_CONTROL2);
>>>>> +     if (con & SDHCI_CTRL2_1_8V) {
>>>>> +             con &= ~SDHCI_CTRL2_UHS_MASK;
>>>>> +             if (ddr & MMC_1_8V_DDR_MODE)
>>>>> +                     con |= SDHCI_CTRL2_DDR50;
>>>>> +             sdhci_writew(host, con, SDHCI_HOST_CONTROL2);
>>>>> +     }
>>>>> +}
>>>>> +
>>>>
>>>>
>>>> The host controller should not enable the CAP if 1.8V is not supported.  DDR should not be
>>>> invoked if CAP is not set.  Thus
>>>
>>> set_ddr is called with para ddr, it would not enter here if  CAP is not set.
>>>>
>>>>> +     if (con & SDHCI_CTRL2_1_8V) {
>>>>
>>>> and
>>>>> +             if (ddr & MMC_1_8V_DDR_MODE)
>>>>
>>>> are not needed.
>>>>
>>>> This code should move to driver specific function since tuning may be done on some systems and
>>>> some systems (not mmp2) may need to delay the 5ms for voltage to be stable.  Would prefer a
>>>> host->ops callback.
>>> 5ms is considered in power up, that's the reason not put in set_ios
>>> with call back.
>>>>
>>>>> static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
>>>>> {
>>>>>       int div;
>>>>> @@ -1080,6 +1096,17 @@ static void sdhci_set_power(struct sdhci_host
>>>>> *host, unsigned short power)
>>>>>               return;
>>>>>       }
>>>>>
>>>>> +     if (pwr == SDHCI_POWER_180) {
>>
>> Could add one more condition here
>> if ((host->mmc->caps & MMC_CAP_1_8V_DDR) &&
>>               (pwr == SDHCI_POWER_180)) {
>>
>>>>> +             u16 con;
>>>>> +
>>>>> +             con = sdhci_readw(host, SDHCI_HOST_CONTROL2);
>>>>> +             con |= SDHCI_CTRL2_1_8V;
>>>>> +             sdhci_writew(host, con, SDHCI_HOST_CONTROL2);
>>>>> +
>>>>> +             if (host->ops->set_power)
>>>>> +                     host->ops->set_power(host, pwr);
>>>>> +     }
>>>>> +
>>>>
>>>> This code should be moved to sdhci_set_ddr (aboe).  Not needed if voltage is 1.8v and card
>>>> is not running ddr.
>>> No defect to set SDHCI_CTRL2_1_8V if choose 1.8v.
>>>
>>>>
>>>>>       /*
>>>>>        * Spec says that we should clear the power reg before setting
>>>>>        * a new value. Some controllers don't seem to like this though.
>>>>> @@ -1176,6 +1203,7 @@ static void sdhci_set_ios(struct mmc_host *mmc,
>>>>> struct mmc_ios *ios)
>>>>>       }
>>>>>
>>>>>       sdhci_set_clock(host, ios->clock);
>>>>> +     sdhci_set_ddr(host, ios->ddr);
>>>>>
>>>>>       if (ios->power_mode == MMC_POWER_OFF)
>>>>>               sdhci_set_power(host, -1);
>>>>> @@ -1736,7 +1764,7 @@ EXPORT_SYMBOL_GPL(sdhci_alloc_host);
>>>>> int sdhci_add_host(struct sdhci_host *host)
>>>>> {
>>>>>       struct mmc_host *mmc;
>>>>> -     unsigned int caps;
>>>>> +     unsigned int caps, caps_h;
>>>>>       int ret;
>>>>>
>>>>>       WARN_ON(host == NULL);
>>>>> @@ -1761,6 +1789,12 @@ int sdhci_add_host(struct sdhci_host *host)
>>>>>
>>>>>       caps = (host->quirks & SDHCI_QUIRK_MISSING_CAPS) ? host->caps :
>>>>>               sdhci_readl(host, SDHCI_CAPABILITIES);
>>>>> +     caps_h = sdhci_readl(host, SDHCI_CAPABILITIES_H);
>>>>> +
>>>>> +     if (caps & SDHCI_CAN_VDD_180) {
>>>>> +             if (caps_h & SDHCI_CAN_SDR50)
>>>>> +                     mmc->caps |= (MMC_CAP_1_8V_DDR);
>>>>> +     }
>>>>>
>>>>>       if (host->quirks & SDHCI_QUIRK_FORCE_DMA)
>>>>>               host->flags |= SDHCI_USE_SDMA;
>>>>> diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
>>>>> index b689cc6..28c460a 100644
>>>>> --- a/drivers/mmc/host/sdhci.h
>>>>> +++ b/drivers/mmc/host/sdhci.h
>>>>> @@ -144,7 +144,14 @@
>>>>>
>>>>> #define SDHCI_ACMD12_ERR      0x3C
>>>>>
>>>>> -/* 3E-3F reserved */
>>>>> +#define SDHCI_HOST_CONTROL2  0x3E
>>>>> +#define  SDHCI_CTRL2_UHS_MASK        0x0007
>>>>> +#define   SDHCI_CTRL2_SDR12  0x0000
>>>>> +#define   SDHCI_CTRL2_SDR25  0x0001
>>>>> +#define   SDHCI_CTRL2_SDR50  0x0002
>>>>> +#define   SDHCI_CTRL2_SDR104 0x0003
>>>>> +#define   SDHCI_CTRL2_DDR50  0x0004
>>>>> +#define  SDHCI_CTRL2_1_8V    0x0008
>>>>>
>>>>> #define SDHCI_CAPABILITIES    0x40
>>>>> #define  SDHCI_TIMEOUT_CLK_MASK       0x0000003F
>>>>> @@ -165,7 +172,10 @@
>>>>> #define  SDHCI_CAN_VDD_180    0x04000000
>>>>> #define  SDHCI_CAN_64BIT      0x10000000
>>>>>
>>>>> -/* 44-47 reserved for more caps */
>>>>> +#define SDHCI_CAPABILITIES_H 0x44
>>>>> +#define  SDHCI_CAN_SDR50     0x00000001
>>>>> +#define  SDHCI_CAN_SDR104    0x00000002
>>>>> +#define  SDHCI_CAN_DDR50     0x00000004
>>>>>
>>>>> #define SDHCI_MAX_CURRENT     0x48
>>>>>
>>>>> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
>>>>> index 956fbd8..bd09b19 100644
>>>>> --- a/include/linux/mmc/mmc.h
>>>>> +++ b/include/linux/mmc/mmc.h
>>>>> @@ -202,6 +202,7 @@ struct _mmc_csd {
>>>>>  * OCR bits are mostly in host.h
>>>>>  */
>>>>> #define MMC_CARD_BUSY 0x80000000      /* Card Power up status bit */
>>>>> +#define MMC_CARD_1_8V        0x00000080      /* Card 1.70-1.95V support bit */
>>>>>
>>>>> /*
>>>>>  * Card Command Classes (CCC)
>>>>> diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
>>>>> index 86e8380..57bcda9 100644
>>>>> --- a/include/linux/mmc/sdhci.h
>>>>> +++ b/include/linux/mmc/sdhci.h
>>>>> @@ -163,6 +163,8 @@ struct sdhci_ops {
>>>>>       void (*platform_send_init_74_clocks)(struct sdhci_host *host,
>>>>>                                            u8 power_mode);
>>>>>       unsigned int    (*get_ro)(struct sdhci_host *host);
>>>>> +     unsigned int    (*set_power)(struct sdhci_host *host,
>>>>> +                             unsigned short power);
>>>>> };
>>>>>
>>>>>
>>>>> --
>>>>> 1.7.0.4
>>>>>
>>>>> Update the condition of voltage switch.
>>>>> +                     if ((ocr & MMC_CARD_1_8V)
>>>>> +                             && (host->ocr_avail & MMC_CARD_1_8V)) {
>>>>> +                             /* switch voltage to 1.8v */
>>>>>
>>>>> Any comments are welcome.
>>>>> --
>>>>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
>>>>> the body of a message to majordomo@xxxxxxxxxxxxxxx
>>>>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>>>
>>>>
>>>
>
>
>
> NAK
>
> There are two voltages -- the voltage to the card and the voltage used for signaling.
> The voltage of the card is programmed using mmc_set_voltage.  It can be 3.3, 1.8v etc
> this voltage is controlled via the host control register 0x28.
>
> the voltage used for signaling is controlled via the host control register 2 (0x3e).  moving
> to ddr requires that this voltage be signaled to the card (CMD11) and and changed via
> host control register 2.  The flowchart figure 3.10 -- page 104 shows the sequence that
> is needed.
>
> What is missing in core/ is
> a) support for CMD11
> b) correct implementation for changing  the signaling voltage for uhs modes
>
>
CMD11 only used for sd3.0 card, not mmc card, mmc does not require any
cmd, just change voltage and wait for voltage stable, thanks
>
>
>
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux