On Wed, Mar 16, 2011 at 2:30 AM, Nath, Arindam <arindam.n...@amd.com> wrote:
> Hi Zhangfei,
>
>
>> -----Original Message-----
>> From: zhangfei gao [mailto:zhangfei....@gmail.com]
>> Sent: Wednesday, March 16, 2011 8:33 AM
>> To: Subhash Jadavani; Nath, Arindam
>> Cc: c...@laptop.org; prak...@marvell.com; linux-mmc@vger.kernel.org; Su,
>> Henry; Lu, Aaron; anath....@gmail.com
>> Subject: Re: [PATCH v2 02/12] mmc: sd: add support for signal voltage
>> switch procedure
>>
>> On Tue, Mar 15, 2011 at 7:58 AM, Subhash Jadavani
>> <subha...@codeaurora.org> wrote:
>> >
>> >
>> >> -----Original Message-----
>> >> From: Nath, Arindam [mailto:arindam.n...@amd.com]
>> >> Sent: Tuesday, March 15, 2011 4:59 PM
>> >> To: Subhash Jadavani; c...@laptop.org
>> >> Cc: zhangfei....@gmail.com; prak...@marvell.com; linux-
>> >> m...@vger.kernel.org; Su, Henry; Lu, Aaron; anath....@gmail.com
>> >> Subject: RE: [PATCH v2 02/12] mmc: sd: add support for signal
>> voltage
>> >> switch procedure
>> >>
>> >> Hi Subhash,
>> >>
>> >>
>> >> > -----Original Message-----
>> >> > From: Subhash Jadavani [mailto:subha...@codeaurora.org]
>> >> > Sent: Tuesday, March 15, 2011 4:49 PM
>> >> > To: Nath, Arindam; c...@laptop.org
>> >> > Cc: zhangfei....@gmail.com; prak...@marvell.com; linux-
>> >> > m...@vger.kernel.org; Su, Henry; Lu, Aaron; anath....@gmail.com
>> >> > Subject: RE: [PATCH v2 02/12] mmc: sd: add support for signal
>> voltage
>> >> > switch procedure
>> >> >
>> >> >
>> >> >
>> >> > > -----Original Message-----
>> >> > > From: linux-mmc-ow...@vger.kernel.org [mailto:linux-mmc-
>> >> > > ow...@vger.kernel.org] On Behalf Of Nath, Arindam
>> >> > > Sent: Tuesday, March 15, 2011 4:03 PM
>> >> > > To: Subhash Jadavani; c...@laptop.org
>> >> > > Cc: zhangfei....@gmail.com; prak...@marvell.com; linux-
>> >> > > m...@vger.kernel.org; Su, Henry; Lu, Aaron; anath....@gmail.com
>> >> > > Subject: RE: [PATCH v2 02/12] mmc: sd: add support for signal
>> >> voltage
>> >> > > switch procedure
>> >> > >
>> >> > > Hi Subhash,
>> >> > >
>> >> > >
>> >> > > > -----Original Message-----
>> >> > > > From: Subhash Jadavani [mailto:subha...@codeaurora.org]
>> >> > > > Sent: Tuesday, March 15, 2011 3:48 PM
>> >> > > > To: Nath, Arindam; c...@laptop.org
>> >> > > > Cc: zhangfei....@gmail.com; prak...@marvell.com; linux-
>> >> > > > m...@vger.kernel.org; Su, Henry; Lu, Aaron; anath....@gmail.com
>> >> > > > Subject: RE: [PATCH v2 02/12] mmc: sd: add support for signal
>> >> > voltage
>> >> > > > switch procedure
>> >> > > >
>> >> > > > Arindam,
>> >> > > >
>> >> > > > During voltage switch, voltage level for CLK, DATA and CMD
>> >> > pads/pins
>> >> > > > should
>> >> > > > be changed from 3.3v to 1.8v. for this SD controller has to
>> >> modify
>> >> > > few
>> >> > > > bits
>> >> > > > in their controller registers and also have to set the voltage
>> >> > level
>> >> > > of
>> >> > > > a
>> >> > > > regulator which is powering those pad/pins.
>> >> > > >
>> >> > > > Now with you current patch, you are calling
>> >> > > start_signal_voltage_switch
>> >> > > > mmc_ops when you want to switch from 3.3v to 1.8v and each
>> >> > controller
>> >> > > > driver
>> >> > > > would then perform above operation in their handler (modifying
>> >> > > relevant
>> >> > > > controller register and setting the voltage level) along with
>> >> SD3.0
>> >> > > > spec
>> >> > > > requirements.
>> >> > > >
>> >> > > > Now let's say after all above initialization and some data
>> >> transfer
>> >> > > > with
>> >> > > > UHS-I card, card is removed from the slot. Now if I insert the
>> >> > > > SDHC/SDSC
>> >> > > > card (with SDv2.0 support) then how will controller undone the
>> >> > above
>> >> > > > voltage
>> >> > > > switch operations (means changing pad/ping voltage level back
>> >> from
>> >> > > 1.8v
>> >> > > > to
>> >> > > > 3.3v)?
>> >> > > >
>> >> > > > To avoid above issue, we can have one new entry in mmc_ios
>> which
>> >> > > > specifies
>> >> > > > the voltage level required for CLK, DATA, CMD pins (0 = 3.3v,
>> 1 =
>> >> > > > 1.8v).
>> >> > > > This entry would be set once start_signal_voltage_switch ops
>> >> > returns
>> >> > > > success. So now when card is removed and new card is inserted,
>> at
>> >> > the
>> >> > > > start
>> >> > > > of initialization we should make sure that set_ios() gets
>> called
>> >> > with
>> >> > > > this
>> >> > > > entry reset (0) which would make sure that CLK, DATA and CMD
>> >> > > pads/pins
>> >> > > > voltage level back to 3.3v.
>> >> > >
>> >> > > Rather than following the procedure mentioned above, can we
>> simply
>> >> > not
>> >> > > reset 1.8V signaling enable in the Host Control2 register when a
>> >> card
>> >> > > is removed? Will that serve the purpose?
>> >> >
>> >> > How will the host controller driver comes to know that card is
>> >> removed
>> >> > (assuming that there is no hardware based card detection
>> available)?
>> >>
>> >> Correct me if wrong, but I think bit 7 of Normal Interrupt Status
>> >> Register can inform regarding the card removal event.
>> >
>> > Sorry. But again I have to make this point clear. It's not necessary
>> that
>> > all host controller implementation would be same as your host
>> controller
>> > implementation. In our host controller we don't have any such status
>> bit for
>> > card removal event.
>> >
>> >>
>> >> > And I
>> >> > don't think host controller driver itself should take decision to
>> >> > revert
>> >> > back from 1.8v to 3.3v until core layer tells it do so.
>> >> >
>> >> > Regarding clearing the bit in Host Control2 register, it's
>> specific
>> >> to
>> >> > your
>> >> > controller. Not all controllers/platform will have same bits
>> >>
>> >> As part of signal voltage switch procedure, we set 1.8V signaling
>> >> enable in the Host Control2 register. So the same bit can be reset
>> to
>> >> set the signaling voltage back to 3.3V.
>> >
>> > Same as my above comment.
>> >
>> >
>> >>
>> >>  and also
>> >> > some
>> >> > controller might have to do something extra than setting few bits
>> in
>> >> > controller registers. In our case for switching from 3.3v to 1.8v,
>> >> > other
>> >> > than setting one of the controller register bit, we also need to
>> set
>> >> > the
>> >> > voltage level of a regulator which is powering these interface
>> pins
>> >> > CMD,
>> >> > DATA, CLK.
>> >>
>> >> In that case I will modify the code to add an entry into mmc_ios as
>> per
>> >> your suggestion.
>> >
>> > What about removing start_signal_voltage_switch ops itself and just
>> adding
>> > one entry in ios for voltage_switch? Whenever you want to switch the
>> voltage
>> > level from 1.8v to 2.7v call set_ios() with this new entry set and
>> when you
>> > want to go back from 1.8v to 2.7v call set_ios() with this new entry
>> reset.
>>
>> Not sure set_ios is a good place to change voltage, which need some
>> time to wait for voltage to be stable, no matter voltage provided by
>> controller or external pmic, while set_ios is protected by spin_lock.
>> Besides, find start_signal_voltage_switch is not protected by
>> spin_lock when accessing register, it would be not safe.
>
> I agree with you. Moreover, as Nicolas mentioned in one of the discussions 
> before, during signal voltage switching, there should not be any concurrent 
> access, so we don't need locking anyways. That's why the current 
> implementation has done away with locking. I am planning to implement using a 
> variable inside mmc_ios and not part of set_ios(). This should be able to 
> cater to the needs of all host controllers.

How about add spin_lock/unlock outside of sleep and protect the
register accessing?
>
> Thanks,
> Arindam
>
>>
>> >
>> >>
>> >> Thanks,
>> >> Arindam
>> >>
>> >> >
>> >> >
>> >> >
>> >> > >
>> >> > > Thanks,
>> >> > > Arindam
>> >> > >
>> >> > > >
>> >> > > > Regards,
>> >> > > > Subhash
>> >> > > >
>> >> > > >
>> >> > > > > -----Original Message-----
>> >> > > > > From: linux-mmc-ow...@vger.kernel.org [mailto:linux-mmc-
>> >> > > > > ow...@vger.kernel.org] On Behalf Of Arindam Nath
>> >> > > > > Sent: Friday, March 04, 2011 5:03 PM
>> >> > > > > To: c...@laptop.org
>> >> > > > > Cc: zhangfei....@gmail.com; prak...@marvell.com;
>> >> > > > > subha...@codeaurora.org; linux-mmc@vger.kernel.org;
>> >> > > henry...@amd.com;
>> >> > > > > aaron...@amd.com; anath....@gmail.com; Arindam Nath
>> >> > > > > Subject: [PATCH v2 02/12] mmc: sd: add support for signal
>> >> voltage
>> >> > > > > switch procedure
>> >> > > > >
>> >> > > > > Host Controller v3.00 adds another Capabilities register.
>> Apart
>> >> > > > > from other things, this new register indicates whether the
>> Host
>> >> > > > > Controller supports SDR50, SDR104, and DDR50 UHS-I modes.
>> The
>> >> > spec
>> >> > > > > doesn't mention about explicit support for SDR12 and SDR25
>> UHS-
>> >> I
>> >> > > > > modes, so the Host Controller v3.00 should support them by
>> >> > default.
>> >> > > > > Also if the controller support SDR104 mode, it will also
>> >> support
>> >> > > > > SDR50 mode as well. So depending on the host support, we set
>> >> the
>> >> > > > > corresponding MMC_CAP_* flags. One more new register. Host
>> >> > Control2
>> >> > > > > is added in v3.00, which is used during Signal Voltage
>> Switch
>> >> > > > > procedure described below.
>> >> > > > >
>> >> > > > > Since as per v3.00 spec, UHS-I supported hosts should set
>> S18R
>> >> > > > > to 1, we set S18R (bit 24) of OCR before sending ACMD41. We
>> >> also
>> >> > > > > need to set XPC (bit 28) of OCR in case the host can supply
>> >> > >150mA.
>> >> > > > > This support is indicated by the Maximum Current
>> Capabilities
>> >> > > > > register of the Host Controller.
>> >> > > > >
>> >> > > > > If the response of ACMD41 has both CCS and S18A set, we
>> start
>> >> the
>> >> > > > > signal voltage switch procedure, which if successfull, will
>> >> > switch
>> >> > > > > the card from 3.3V signalling to 1.8V signalling. Signal
>> >> voltage
>> >> > > > > switch procedure adds support for a new command CMD11 in the
>> >> > > > > Physical Layer Spec v3.01. As part of this procedure, we
>> need
>> >> to
>> >> > > > > set 1.8V Signalling Enable (bit 3) of Host Control2
>> register,
>> >> > which
>> >> > > > > if remains set after 5ms, means the switch to 1.8V
>> signalling
>> >> is
>> >> > > > > successfull. Otherwise, we clear bit 24 of OCR and retry the
>> >> > > > > initialization sequence.
>> >> > > > >
>> >> > > > > Signed-off-by: Arindam Nath <arindam.n...@amd.com>
>> >> > > > > ---
>> >> > > > >  drivers/mmc/core/sd.c     |   37 ++++++++++-
>> >> > > > >  drivers/mmc/core/sd_ops.c |   32 ++++++++++
>> >> > > > >  drivers/mmc/core/sd_ops.h |    1 +
>> >> > > > >  drivers/mmc/host/sdhci.c  |  148
>> >> > > > > +++++++++++++++++++++++++++++++++++++++++----
>> >> > > > >  drivers/mmc/host/sdhci.h  |   18 +++++-
>> >> > > > >  include/linux/mmc/host.h  |   10 +++
>> >> > > > >  include/linux/mmc/sd.h    |    1 +
>> >> > > > >  7 files changed, 229 insertions(+), 18 deletions(-)
>> >> > > > >
>> >> > > > > diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
>> >> > > > > index b3f8a3c..3e82599 100644
>> >> > > > > --- a/drivers/mmc/core/sd.c
>> >> > > > > +++ b/drivers/mmc/core/sd.c
>> >> > > > > @@ -408,6 +408,7 @@ struct device_type sd_type = {
>> >> > > > >  int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32
>> *cid)
>> >> > > > >  {
>> >> > > > >     int err;
>> >> > > > > +   u32 rocr;
>> >> > > > >
>> >> > > > >     /*
>> >> > > > >      * Since we're changing the OCR value, we seem to
>> >> > > > > @@ -427,10 +428,25 @@ int mmc_sd_get_cid(struct mmc_host
>> *host,
>> >> > u32
>> >> > > > > ocr, u32 *cid)
>> >> > > > >     if (!err)
>> >> > > > >             ocr |= 1 << 30;
>> >> > > > >
>> >> > > > > -   err = mmc_send_app_op_cond(host, ocr, NULL);
>> >> > > > > +   /* If the host can supply more than 150mA, XPC should be
>> >> set
>> >> > to
>> >> > > > > 1. */
>> >> > > > > +   if (host->caps & (MMC_CAP_SET_XPC_330 |
>> MMC_CAP_SET_XPC_300
>> >> |
>> >> > > > > +       MMC_CAP_SET_XPC_180))
>> >> > > > > +           ocr |= 1 << 28;
>> >> > > > > +
>> >> > > > > +   err = mmc_send_app_op_cond(host, ocr, &rocr);
>> >> > > > >     if (err)
>> >> > > > >             return err;
>> >> > > > >
>> >> > > > > +   /*
>> >> > > > > +    * In case CCS and S18A in the response is set, start
>> >> Signal
>> >> > > > > Voltage
>> >> > > > > +    * Switch procedure. SPI mode doesn't support CMD11.
>> >> > > > > +    */
>> >> > > > > +   if (!mmc_host_is_spi(host) && (rocr & 0x41000000)) {
>> >> > > > > +           err = mmc_start_voltage_switch(host);
>> >> > > > > +           if (err)
>> >> > > > > +                   return err;
>> >> > > > > +   }
>> >> > > > > +
>> >> > > > >     if (mmc_host_is_spi(host))
>> >> > > > >             err = mmc_send_cid(host, cid);
>> >> > > > >     else
>> >> > > > > @@ -827,11 +843,26 @@ int mmc_attach_sd(struct mmc_host
>> *host)
>> >> > > > >     }
>> >> > > > >
>> >> > > > >     /*
>> >> > > > > +    * If the host supports one of UHS-I modes, request the
>> >> card
>> >> > > > > +    * to switch to 1.8V signaling level.
>> >> > > > > +    */
>> >> > > > > +   if (host->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25
>> |
>> >> > > > > +       MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 |
>> >> > > MMC_CAP_UHS_DDR50))
>> >> > > > > +           host->ocr |= (1 << 24);
>> >> > > > > +
>> >> > > > > +   /*
>> >> > > > >      * Detect and init the card.
>> >> > > > >      */
>> >> > > > >     err = mmc_sd_init_card(host, host->ocr, NULL);
>> >> > > > > -   if (err)
>> >> > > > > -           goto err;
>> >> > > > > +   if (err == -EAGAIN) {
>> >> > > > > +           /*
>> >> > > > > +            * Retry initialization with S18R set to 0.
>> >> > > > > +            */
>> >> > > > > +           host->ocr &= ~(1 << 24);
>> >> > > > > +           err = mmc_sd_init_card(host, host->ocr, NULL);
>> >> > > > > +           if (err)
>> >> > > > > +                   goto err;
>> >> > > > > +   }
>> >> > > > >
>> >> > > > >     mmc_release_host(host);
>> >> > > > >     err = mmc_add_card(host->card);
>> >> > > > > diff --git a/drivers/mmc/core/sd_ops.c
>> >> > b/drivers/mmc/core/sd_ops.c
>> >> > > > > index 797cdb5..8a23e2e 100644
>> >> > > > > --- a/drivers/mmc/core/sd_ops.c
>> >> > > > > +++ b/drivers/mmc/core/sd_ops.c
>> >> > > > > @@ -146,6 +146,38 @@ int mmc_app_set_bus_width(struct
>> mmc_card
>> >> > > *card,
>> >> > > > > int width)
>> >> > > > >     return 0;
>> >> > > > >  }
>> >> > > > >
>> >> > > > > +int mmc_start_voltage_switch(struct mmc_host *host)
>> >> > > > > +{
>> >> > > > > +   struct mmc_command cmd;
>> >> > > > > +   int err;
>> >> > > > > +
>> >> > > > > +   BUG_ON(!host);
>> >> > > > > +
>> >> > > > > +   /*
>> >> > > > > +    * If the host does not provide signal voltage switch
>> >> > > procedure,
>> >> > > > > we
>> >> > > > > +    * set S18R to 0, and then retry initialization
>> sequence.
>> >> > > > > +    */
>> >> > > > > +   if (!host->ops->start_signal_voltage_switch)
>> >> > > > > +           return -EAGAIN;
>> >> > > > > +
>> >> > > > > +   memset(&cmd, 0, sizeof(struct mmc_command));
>> >> > > > > +
>> >> > > > > +   cmd.opcode = SD_SWITCH_VOLTAGE;
>> >> > > > > +   cmd.arg = 0;
>> >> > > > > +   cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
>> >> > > > > +
>> >> > > > > +   err = mmc_wait_for_cmd(host, &cmd, 0);
>> >> > > > > +   if (err)
>> >> > > > > +           return err;
>> >> > > > > +
>> >> > > > > +   if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR))
>> >> > > > > +           return -EIO;
>> >> > > > > +
>> >> > > > > +   err = host->ops->start_signal_voltage_switch(host);
>> >> > > > > +
>> >> > > > > +   return err;
>> >> > > > > +}
>> >> > > > > +
>> >> > > > >  int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr,
>> u32
>> >> > > *rocr)
>> >> > > > >  {
>> >> > > > >     struct mmc_command cmd;
>> >> > > > > diff --git a/drivers/mmc/core/sd_ops.h
>> >> > b/drivers/mmc/core/sd_ops.h
>> >> > > > > index ffc2305..3cfba59 100644
>> >> > > > > --- a/drivers/mmc/core/sd_ops.h
>> >> > > > > +++ b/drivers/mmc/core/sd_ops.h
>> >> > > > > @@ -20,6 +20,7 @@ int mmc_app_send_scr(struct mmc_card
>> *card,
>> >> u32
>> >> > > > > *scr);
>> >> > > > >  int mmc_sd_switch(struct mmc_card *card, int mode, int
>> group,
>> >> > > > >     u8 value, u8 *resp);
>> >> > > > >  int mmc_app_sd_status(struct mmc_card *card, void *ssr);
>> >> > > > > +int mmc_start_voltage_switch(struct mmc_host *host);
>> >> > > > >
>> >> > > > >  #endif
>> >> > > > >
>> >> > > > > diff --git a/drivers/mmc/host/sdhci.c
>> >> b/drivers/mmc/host/sdhci.c
>> >> > > > > index 8914a25..5487a0b 100644
>> >> > > > > --- a/drivers/mmc/host/sdhci.c
>> >> > > > > +++ b/drivers/mmc/host/sdhci.c
>> >> > > > > @@ -85,6 +85,8 @@ static void sdhci_dumpregs(struct
>> sdhci_host
>> >> > > *host)
>> >> > > > >     printk(KERN_DEBUG DRIVER_NAME ": Cmd:      0x%08x | Max
>> >> curr:
>> >> > > > > 0x%08x\n",
>> >> > > > >             sdhci_readw(host, SDHCI_COMMAND),
>> >> > > > >             sdhci_readl(host, SDHCI_MAX_CURRENT));
>> >> > > > > +   printk(KERN_DEBUG DRIVER_NAME ": Host ctl2: 0x%08x\n",
>> >> > > > > +           sdhci_readw(host, SDHCI_HOST_CONTROL2));
>> >> > > > >
>> >> > > > >     if (host->flags & SDHCI_USE_ADMA)
>> >> > > > >             printk(KERN_DEBUG DRIVER_NAME ": ADMA Err:
>> 0x%08x |
>> >> > > ADMA
>> >> > > > > Ptr: 0x%08x\n",
>> >> > > > > @@ -1337,11 +1339,70 @@ out:
>> >> > > > >     spin_unlock_irqrestore(&host->lock, flags);
>> >> > > > >  }
>> >> > > > >
>> >> > > > > +static int sdhci_start_signal_voltage_switch(struct
>> mmc_host
>> >> > *mmc)
>> >> > > > > +{
>> >> > > > > +   struct sdhci_host *host;
>> >> > > > > +   u8 pwr;
>> >> > > > > +   u16 clk, ctrl;
>> >> > > > > +   u32 present_state;
>> >> > > > > +
>> >> > > > > +   host = mmc_priv(mmc);
>> >> > > > > +
>> >> > > > > +   /* Stop SDCLK */
>> >> > > > > +   host = mmc_priv(mmc);
>> >> > > > > +   clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
>> >> > > > > +   clk &= ~SDHCI_CLOCK_CARD_EN;
>> >> > > > > +   sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
>> >> > > > > +
>> >> > > > > +   /* Check whether DAT[3:0] is 0000 */
>> >> > > > > +   present_state = sdhci_readl(host, SDHCI_PRESENT_STATE);
>> >> > > > > +   if (!((present_state & SDHCI_DATA_LVL_MASK) >>
>> >> > > > > SDHCI_DATA_LVL_SHIFT)) {
>> >> > > > > +           /* Enable 1.8V Signal Enable in the Host
>> Control2
>> >> > > register
>> >> > > > > */
>> >> > > > > +           ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
>> >> > > > > +           ctrl |= SDHCI_CTRL_VDD_180;
>> >> > > > > +           sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
>> >> > > > > +
>> >> > > > > +           /* Wait for 5ms */
>> >> > > > > +           usleep_range(5000, 5500);
>> >> > > > > +
>> >> > > > > +           ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
>> >> > > > > +           if (ctrl & SDHCI_CTRL_VDD_180) {
>> >> > > > > +                   /* Provide SDCLK again and wait for
>> 1ms*/
>> >> > > > > +                   clk = sdhci_readw(host,
>> >> SDHCI_CLOCK_CONTROL);
>> >> > > > > +                   clk |= SDHCI_CLOCK_CARD_EN;
>> >> > > > > +                   sdhci_writew(host, clk,
>> >> SDHCI_CLOCK_CONTROL);
>> >> > > > > +                   usleep_range(1000, 1500);
>> >> > > > > +
>> >> > > > > +                   /*
>> >> > > > > +                    * If DAT[3:0] level is 1111b, then the
>> >> card
>> >> > > was
>> >> > > > > +                    * successfully switched to 1.8V
>> signaling.
>> >> > > > > +                    */
>> >> > > > > +                   present_state = sdhci_readl(host,
>> >> > > > > SDHCI_PRESENT_STATE);
>> >> > > > > +                   if ((present_state &
>> SDHCI_DATA_LVL_MASK)
>> >> ==
>> >> > > > > +                        SDHCI_DATA_LVL_MASK) {
>> >> > > > > +                           return 0;
>> >> > > > > +                   }
>> >> > > > > +           }
>> >> > > > > +   }
>> >> > > > > +
>> >> > > > > +   /*
>> >> > > > > +    * If we are here, that means the switch to 1.8V
>> signaling
>> >> > > > > failed. Stop
>> >> > > > > +    * power to the card, and retry initialization sequence
>> by
>> >> > > > > setting S18R
>> >> > > > > +    * to 0.
>> >> > > > > +    */
>> >> > > > > +   pwr = sdhci_readb(host, SDHCI_POWER_CONTROL);
>> >> > > > > +   pwr &= ~SDHCI_POWER_ON;
>> >> > > > > +   sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
>> >> > > > > +
>> >> > > > > +   return -EAGAIN;
>> >> > > > > +}
>> >> > > > > +
>> >> > > > >  static const struct mmc_host_ops sdhci_ops = {
>> >> > > > >     .request        = sdhci_request,
>> >> > > > >     .set_ios        = sdhci_set_ios,
>> >> > > > >     .get_ro         = sdhci_get_ro,
>> >> > > > >     .enable_sdio_irq = sdhci_enable_sdio_irq,
>> >> > > > > +   .start_signal_voltage_switch    =
>> >> > > > > sdhci_start_signal_voltage_switch,
>> >> > > > >  };
>> >> > > > >
>> >> > > > >
>> >> > > > >
>> >> > > >
>> >> > >
>> >> >
>> >>
>> /**********************************************************************
>> >> > > > > *******\
>> >> > > > > @@ -1799,7 +1860,9 @@ EXPORT_SYMBOL_GPL(sdhci_alloc_host);
>> >> > > > >  int sdhci_add_host(struct sdhci_host *host)
>> >> > > > >  {
>> >> > > > >     struct mmc_host *mmc;
>> >> > > > > -   unsigned int caps, ocr_avail;
>> >> > > > > +   u32 caps[2];
>> >> > > > > +   u32 max_current_caps;
>> >> > > > > +   unsigned int ocr_avail;
>> >> > > > >     int ret;
>> >> > > > >
>> >> > > > >     WARN_ON(host == NULL);
>> >> > > > > @@ -1822,12 +1885,15 @@ int sdhci_add_host(struct sdhci_host
>> >> > *host)
>> >> > > > >                     host->version);
>> >> > > > >     }
>> >> > > > >
>> >> > > > > -   caps = (host->quirks & SDHCI_QUIRK_MISSING_CAPS) ? host-
>> >> >caps
>> >> > :
>> >> > > > > +   caps[0] = (host->quirks & SDHCI_QUIRK_MISSING_CAPS) ?
>> host-
>> >> > > >caps
>> >> > > > > :
>> >> > > > >             sdhci_readl(host, SDHCI_CAPABILITIES);
>> >> > > > >
>> >> > > > > +   if (host->version >= SDHCI_SPEC_300)
>> >> > > > > +           caps[1] = sdhci_readl(host,
>> SDHCI_CAPABILITIES_1);
>> >> > > > > +
>> >> > > > >     if (host->quirks & SDHCI_QUIRK_FORCE_DMA)
>> >> > > > >             host->flags |= SDHCI_USE_SDMA;
>> >> > > > > -   else if (!(caps & SDHCI_CAN_DO_SDMA))
>> >> > > > > +   else if (!(caps[0] & SDHCI_CAN_DO_SDMA))
>> >> > > > >             DBG("Controller doesn't have SDMA
>> capability\n");
>> >> > > > >     else
>> >> > > > >             host->flags |= SDHCI_USE_SDMA;
>> >> > > > > @@ -1838,7 +1904,8 @@ int sdhci_add_host(struct sdhci_host
>> >> *host)
>> >> > > > >             host->flags &= ~SDHCI_USE_SDMA;
>> >> > > > >     }
>> >> > > > >
>> >> > > > > -   if ((host->version >= SDHCI_SPEC_200) && (caps &
>> >> > > > > SDHCI_CAN_DO_ADMA2))
>> >> > > > > +   if ((host->version >= SDHCI_SPEC_200) &&
>> >> > > > > +           (caps[0] & SDHCI_CAN_DO_ADMA2))
>> >> > > > >             host->flags |= SDHCI_USE_ADMA;
>> >> > > > >
>> >> > > > >     if ((host->quirks & SDHCI_QUIRK_BROKEN_ADMA) &&
>> >> > > > > @@ -1892,10 +1959,10 @@ int sdhci_add_host(struct sdhci_host
>> >> > *host)
>> >> > > > >     }
>> >> > > > >
>> >> > > > >     if (host->version >= SDHCI_SPEC_300)
>> >> > > > > -           host->max_clk = (caps &
>> SDHCI_CLOCK_V3_BASE_MASK)
>> >> > > > > +           host->max_clk = (caps[0] &
>> >> SDHCI_CLOCK_V3_BASE_MASK)
>> >> > > > >                     >> SDHCI_CLOCK_BASE_SHIFT;
>> >> > > > >     else
>> >> > > > > -           host->max_clk = (caps & SDHCI_CLOCK_BASE_MASK)
>> >> > > > > +           host->max_clk = (caps[0] &
>> SDHCI_CLOCK_BASE_MASK)
>> >> > > > >                     >> SDHCI_CLOCK_BASE_SHIFT;
>> >> > > > >
>> >> > > > >     host->max_clk *= 1000000;
>> >> > > > > @@ -1911,7 +1978,7 @@ int sdhci_add_host(struct sdhci_host
>> >> *host)
>> >> > > > >     }
>> >> > > > >
>> >> > > > >     host->timeout_clk =
>> >> > > > > -           (caps & SDHCI_TIMEOUT_CLK_MASK) >>
>> >> > > SDHCI_TIMEOUT_CLK_SHIFT;
>> >> > > > > +           (caps[0] & SDHCI_TIMEOUT_CLK_MASK) >>
>> >> > > > > SDHCI_TIMEOUT_CLK_SHIFT;
>> >> > > > >     if (host->timeout_clk == 0) {
>> >> > > > >             if (host->ops->get_timeout_clock) {
>> >> > > > >                     host->timeout_clk = host->ops-
>> >> > > > > >get_timeout_clock(host);
>> >> > > > > @@ -1923,7 +1990,7 @@ int sdhci_add_host(struct sdhci_host
>> >> *host)
>> >> > > > >                     return -ENODEV;
>> >> > > > >             }
>> >> > > > >     }
>> >> > > > > -   if (caps & SDHCI_TIMEOUT_CLK_UNIT)
>> >> > > > > +   if (caps[0] & SDHCI_TIMEOUT_CLK_UNIT)
>> >> > > > >             host->timeout_clk *= 1000;
>> >> > > > >
>> >> > > > >     /*
>> >> > > > > @@ -1950,21 +2017,76 @@ int sdhci_add_host(struct sdhci_host
>> >> > *host)
>> >> > > > >     if (!(host->quirks & SDHCI_QUIRK_FORCE_1_BIT_DATA))
>> >> > > > >             mmc->caps |= MMC_CAP_4_BIT_DATA;
>> >> > > > >
>> >> > > > > -   if (caps & SDHCI_CAN_DO_HISPD)
>> >> > > > > +   if (caps[0] & SDHCI_CAN_DO_HISPD)
>> >> > > > >             mmc->caps |= MMC_CAP_SD_HIGHSPEED |
>> >> > > MMC_CAP_MMC_HIGHSPEED;
>> >> > > > >
>> >> > > > >     if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
>> &&
>> >> > > > >         mmc_card_is_removable(mmc))
>> >> > > > >             mmc->caps |= MMC_CAP_NEEDS_POLL;
>> >> > > > >
>> >> > > > > +   /* UHS-I mode(s) supported by the host controller. */
>> >> > > > > +   if (host->version >= SDHCI_SPEC_300)
>> >> > > > > +           mmc->caps |= MMC_CAP_UHS_SDR12 |
>> MMC_CAP_UHS_SDR25;
>> >> > > > > +
>> >> > > > > +   /* SDR104 supports also implies SDR50 support */
>> >> > > > > +   if (caps[1] & SDHCI_SUPPORT_SDR104)
>> >> > > > > +           mmc->caps |= MMC_CAP_UHS_SDR104 |
>> >> MMC_CAP_UHS_SDR50;
>> >> > > > > +   else if (caps[1] & SDHCI_SUPPORT_SDR50)
>> >> > > > > +           mmc->caps |= MMC_CAP_UHS_SDR50;
>> >> > > > > +
>> >> > > > > +   if (caps[1] & SDHCI_SUPPORT_DDR50)
>> >> > > > > +           mmc->caps |= MMC_CAP_UHS_DDR50;
>> >> > > > > +
>> >> > > > >     ocr_avail = 0;
>> >> > > > > -   if (caps & SDHCI_CAN_VDD_330)
>> >> > > > > +   /*
>> >> > > > > +    * According to SD Host Controller spec v3.00, if the
>> Host
>> >> > > System
>> >> > > > > +    * can afford more than 150mA, Host Driver should set
>> XPC
>> >> to
>> >> > 1.
>> >> > > > > Also
>> >> > > > > +    * the value is meaningful only if Voltage Support in
>> the
>> >> > > > > Capabilities
>> >> > > > > +    * register is set. The actual current value is 4 times
>> the
>> >> > > > > register
>> >> > > > > +    * value.
>> >> > > > > +    */
>> >> > > > > +   max_current_caps = sdhci_readl(host, SDHCI_MAX_CURRENT);
>> >> > > > > +
>> >> > > > > +   if (caps[0] & SDHCI_CAN_VDD_330) {
>> >> > > > > +           int max_current_330;
>> >> > > > > +
>> >> > > > >             ocr_avail |= MMC_VDD_32_33 | MMC_VDD_33_34;
>> >> > > > > -   if (caps & SDHCI_CAN_VDD_300)
>> >> > > > > +
>> >> > > > > +           max_current_330 = ((max_current_caps &
>> >> > > > > +                              SDHCI_MAX_CURRENT_330_MASK)
>> >>
>> >> > > > > +                              SDHCI_MAX_CURRENT_330_SHIFT)
>> *
>> >> > > > > +                              SDHCI_MAX_CURRENT_MULTIPLIER;
>> >> > > > > +
>> >> > > > > +           if (max_current_330 > 150)
>> >> > > > > +                   mmc->caps |= MMC_CAP_SET_XPC_330;
>> >> > > > > +   }
>> >> > > > > +   if (caps[0] & SDHCI_CAN_VDD_300) {
>> >> > > > > +           int max_current_300;
>> >> > > > > +
>> >> > > > >             ocr_avail |= MMC_VDD_29_30 | MMC_VDD_30_31;
>> >> > > > > -   if (caps & SDHCI_CAN_VDD_180)
>> >> > > > > +
>> >> > > > > +           max_current_300 = ((max_current_caps &
>> >> > > > > +                              SDHCI_MAX_CURRENT_300_MASK)
>> >>
>> >> > > > > +                              SDHCI_MAX_CURRENT_300_SHIFT)
>> *
>> >> > > > > +                              SDHCI_MAX_CURRENT_MULTIPLIER;
>> >> > > > > +
>> >> > > > > +           if (max_current_300 > 150)
>> >> > > > > +                   mmc->caps |= MMC_CAP_SET_XPC_300;
>> >> > > > > +   }
>> >> > > > > +   if (caps[0] & SDHCI_CAN_VDD_180) {
>> >> > > > > +           int max_current_180;
>> >> > > > > +
>> >> > > > >             ocr_avail |= MMC_VDD_165_195;
>> >> > > > >
>> >> > > > > +           max_current_180 = ((max_current_caps &
>> >> > > > > +                              SDHCI_MAX_CURRENT_180_MASK)
>> >>
>> >> > > > > +                              SDHCI_MAX_CURRENT_180_SHIFT)
>> *
>> >> > > > > +                              SDHCI_MAX_CURRENT_MULTIPLIER;
>> >> > > > > +
>> >> > > > > +           if (max_current_180 > 150)
>> >> > > > > +                   mmc->caps |= MMC_CAP_SET_XPC_180;
>> >> > > > > +   }
>> >> > > > > +
>> >> > > > >     mmc->ocr_avail = ocr_avail;
>> >> > > > >     mmc->ocr_avail_sdio = ocr_avail;
>> >> > > > >     if (host->ocr_avail_sdio)
>> >> > > > > @@ -2024,7 +2146,7 @@ int sdhci_add_host(struct sdhci_host
>> >> *host)
>> >> > > > >     if (host->quirks & SDHCI_QUIRK_FORCE_BLK_SZ_2048) {
>> >> > > > >             mmc->max_blk_size = 2;
>> >> > > > >     } else {
>> >> > > > > -           mmc->max_blk_size = (caps &
>> SDHCI_MAX_BLOCK_MASK)
>> >> >>
>> >> > > > > +           mmc->max_blk_size = (caps[0] &
>> >> SDHCI_MAX_BLOCK_MASK)
>> >> > >>
>> >> > > > >                             SDHCI_MAX_BLOCK_SHIFT;
>> >> > > > >             if (mmc->max_blk_size >= 3) {
>> >> > > > >                     printk(KERN_WARNING "%s: Invalid maximum
>> >> > block
>> >> > > size,
>> >> > > > > "
>> >> > > > > diff --git a/drivers/mmc/host/sdhci.h
>> >> b/drivers/mmc/host/sdhci.h
>> >> > > > > index 223762c..95d70e6 100644
>> >> > > > > --- a/drivers/mmc/host/sdhci.h
>> >> > > > > +++ b/drivers/mmc/host/sdhci.h
>> >> > > > > @@ -69,6 +69,8 @@
>> >> > > > >  #define  SDHCI_DATA_AVAILABLE      0x00000800
>> >> > > > >  #define  SDHCI_CARD_PRESENT        0x00010000
>> >> > > > >  #define  SDHCI_WRITE_PROTECT       0x00080000
>> >> > > > > +#define  SDHCI_DATA_LVL_MASK       0x00F00000
>> >> > > > > +#define   SDHCI_DATA_LVL_SHIFT     20
>> >> > > > >
>> >> > > > >  #define SDHCI_HOST_CONTROL         0x28
>> >> > > > >  #define  SDHCI_CTRL_LED            0x01
>> >> > > > > @@ -147,7 +149,8 @@
>> >> > > > >
>> >> > > > >  #define SDHCI_ACMD12_ERR   0x3C
>> >> > > > >
>> >> > > > > -/* 3E-3F reserved */
>> >> > > > > +#define SDHCI_HOST_CONTROL2                0x3E
>> >> > > > > +#define  SDHCI_CTRL_VDD_180                0x0008
>> >> > > > >
>> >> > > > >  #define SDHCI_CAPABILITIES 0x40
>> >> > > > >  #define  SDHCI_TIMEOUT_CLK_MASK    0x0000003F
>> >> > > > > @@ -168,9 +171,20 @@
>> >> > > > >  #define  SDHCI_CAN_VDD_180 0x04000000
>> >> > > > >  #define  SDHCI_CAN_64BIT   0x10000000
>> >> > > > >
>> >> > > > > +#define  SDHCI_SUPPORT_SDR50       0x00000001
>> >> > > > > +#define  SDHCI_SUPPORT_SDR104      0x00000002
>> >> > > > > +#define  SDHCI_SUPPORT_DDR50       0x00000004
>> >> > > > > +
>> >> > > > >  #define SDHCI_CAPABILITIES_1       0x44
>> >> > > > >
>> >> > > > > -#define SDHCI_MAX_CURRENT  0x48
>> >> > > > > +#define SDHCI_MAX_CURRENT          0x48
>> >> > > > > +#define  SDHCI_MAX_CURRENT_330_MASK        0x0000FF
>> >> > > > > +#define  SDHCI_MAX_CURRENT_330_SHIFT       0
>> >> > > > > +#define  SDHCI_MAX_CURRENT_300_MASK        0x00FF00
>> >> > > > > +#define  SDHCI_MAX_CURRENT_300_SHIFT       8
>> >> > > > > +#define  SDHCI_MAX_CURRENT_180_MASK        0xFF0000
>> >> > > > > +#define  SDHCI_MAX_CURRENT_180_SHIFT       16
>> >> > > > > +#define   SDHCI_MAX_CURRENT_MULTIPLIER     4
>> >> > > > >
>> >> > > > >  /* 4C-4F reserved for more max current */
>> >> > > > >
>> >> > > > > diff --git a/include/linux/mmc/host.h
>> >> b/include/linux/mmc/host.h
>> >> > > > > index bcb793e..ad7daa3 100644
>> >> > > > > --- a/include/linux/mmc/host.h
>> >> > > > > +++ b/include/linux/mmc/host.h
>> >> > > > > @@ -117,6 +117,8 @@ struct mmc_host_ops {
>> >> > > > >
>> >> > > > >     /* optional callback for HC quirks */
>> >> > > > >     void    (*init_card)(struct mmc_host *host, struct
>> mmc_card
>> >> > > *card);
>> >> > > > > +
>> >> > > > > +   int     (*start_signal_voltage_switch)(struct mmc_host
>> >> > *host);
>> >> > > > >  };
>> >> > > > >
>> >> > > > >  struct mmc_card;
>> >> > > > > @@ -173,6 +175,14 @@ struct mmc_host {
>> >> > > > >                                             /* DDR mode at
>> 1.2V
>> >> > */
>> >> > > > >  #define MMC_CAP_POWER_OFF_CARD     (1 << 13)       /* Can
>> >> power
>> >> > > off
>> >> > > > after
>> >> > > > > boot */
>> >> > > > >  #define MMC_CAP_BUS_WIDTH_TEST     (1 << 14)       /*
>> >> > CMD14/CMD19
>> >> > > bus
>> >> > > > > width ok */
>> >> > > > > +#define MMC_CAP_UHS_SDR12  (1 << 15)       /* Host supports
>> >> UHS
>> >> > > SDR12
>> >> > > > > mode */
>> >> > > > > +#define MMC_CAP_UHS_SDR25  (1 << 16)       /* Host supports
>> >> UHS
>> >> > > SDR25
>> >> > > > > mode */
>> >> > > > > +#define MMC_CAP_UHS_SDR50  (1 << 17)       /* Host supports
>> >> UHS
>> >> > > SDR50
>> >> > > > > mode */
>> >> > > > > +#define MMC_CAP_UHS_SDR104 (1 << 18)       /* Host supports
>> >> UHS
>> >> > > SDR104
>> >> > > > > mode */
>> >> > > > > +#define MMC_CAP_UHS_DDR50  (1 << 19)       /* Host supports
>> >> UHS
>> >> > > DDR50
>> >> > > > > mode */
>> >> > > > > +#define MMC_CAP_SET_XPC_330        (1 << 20)       /* Host
>> >> > > supports >150mA
>> >> > > > > current at 3.3V */
>> >> > > > > +#define MMC_CAP_SET_XPC_300        (1 << 21)       /* Host
>> >> > > supports >150mA
>> >> > > > > current at 3.0V */
>> >> > > > > +#define MMC_CAP_SET_XPC_180        (1 << 22)       /* Host
>> >> > > supports >150mA
>> >> > > > > current at 1.8V */
>> >> > > > >
>> >> > > > >     mmc_pm_flag_t           pm_caps;        /* supported pm
>> >> > > features */
>> >> > > > >
>> >> > > > > diff --git a/include/linux/mmc/sd.h b/include/linux/mmc/sd.h
>> >> > > > > index 178363b..3ba5aa6 100644
>> >> > > > > --- a/include/linux/mmc/sd.h
>> >> > > > > +++ b/include/linux/mmc/sd.h
>> >> > > > > @@ -17,6 +17,7 @@
>> >> > > > >  /* This is basically the same command as for MMC with some
>> >> > quirks.
>> >> > > > */
>> >> > > > >  #define SD_SEND_RELATIVE_ADDR     3   /* bcr
>> >> > > R6
>> >> > > > > */
>> >> > > > >  #define SD_SEND_IF_COND           8   /* bcr  [11:0] See
>> below
>> >> > > R7
>> >> > > > > */
>> >> > > > > +#define SD_SWITCH_VOLTAGE         11  /* ac
>> >> > > R1
>> >> > > > > */
>> >> > > > >
>> >> > > > >    /* class 10 */
>> >> > > > >  #define SD_SWITCH                 6   /* adtc [31:0] See
>> below
>> >> > > R1
>> >> > > > > */
>> >> > > > > --
>> >> > > > > 1.7.1
>> >> > > > >
>> >> > > > > --
>> >> > > > > To unsubscribe from this list: send the line "unsubscribe
>> >> linux-
>> >> > > mmc"
>> >> > > > in
>> >> > > > > the body of a message to majord...@vger.kernel.org
>> >> > > > > More majordomo info at  http://vger.kernel.org/majordomo-
>> >> > info.html
>> >> > > >
>> >> > >
>> >> > >
>> >> > > --
>> >> > > To unsubscribe from this list: send the line "unsubscribe linux-
>> >> mmc"
>> >> > in
>> >> > > the body of a message to majord...@vger.kernel.org
>> >> > > More majordomo info at  http://vger.kernel.org/majordomo-
>> info.html
>> >> >
>> >>
>> >
>> >
>> >
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majord...@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to