Hi Zhangfei, > -----Original Message----- > From: zhangfei gao [mailto:zhangfei.gao@xxxxxxxxx] > Sent: Wednesday, March 16, 2011 8:33 AM > To: Subhash Jadavani; Nath, Arindam > Cc: cjb@xxxxxxxxxx; prakity@xxxxxxxxxxx; linux-mmc@xxxxxxxxxxxxxxx; Su, > Henry; Lu, Aaron; anath.amd@xxxxxxxxx > 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 > <subhashj@xxxxxxxxxxxxxx> wrote: > > > > > >> -----Original Message----- > >> From: Nath, Arindam [mailto:Arindam.Nath@xxxxxxx] > >> Sent: Tuesday, March 15, 2011 4:59 PM > >> To: Subhash Jadavani; cjb@xxxxxxxxxx > >> Cc: zhangfei.gao@xxxxxxxxx; prakity@xxxxxxxxxxx; linux- > >> mmc@xxxxxxxxxxxxxxx; Su, Henry; Lu, Aaron; anath.amd@xxxxxxxxx > >> Subject: RE: [PATCH v2 02/12] mmc: sd: add support for signal > voltage > >> switch procedure > >> > >> Hi Subhash, > >> > >> > >> > -----Original Message----- > >> > From: Subhash Jadavani [mailto:subhashj@xxxxxxxxxxxxxx] > >> > Sent: Tuesday, March 15, 2011 4:49 PM > >> > To: Nath, Arindam; cjb@xxxxxxxxxx > >> > Cc: zhangfei.gao@xxxxxxxxx; prakity@xxxxxxxxxxx; linux- > >> > mmc@xxxxxxxxxxxxxxx; Su, Henry; Lu, Aaron; anath.amd@xxxxxxxxx > >> > Subject: RE: [PATCH v2 02/12] mmc: sd: add support for signal > voltage > >> > switch procedure > >> > > >> > > >> > > >> > > -----Original Message----- > >> > > From: linux-mmc-owner@xxxxxxxxxxxxxxx [mailto:linux-mmc- > >> > > owner@xxxxxxxxxxxxxxx] On Behalf Of Nath, Arindam > >> > > Sent: Tuesday, March 15, 2011 4:03 PM > >> > > To: Subhash Jadavani; cjb@xxxxxxxxxx > >> > > Cc: zhangfei.gao@xxxxxxxxx; prakity@xxxxxxxxxxx; linux- > >> > > mmc@xxxxxxxxxxxxxxx; Su, Henry; Lu, Aaron; anath.amd@xxxxxxxxx > >> > > Subject: RE: [PATCH v2 02/12] mmc: sd: add support for signal > >> voltage > >> > > switch procedure > >> > > > >> > > Hi Subhash, > >> > > > >> > > > >> > > > -----Original Message----- > >> > > > From: Subhash Jadavani [mailto:subhashj@xxxxxxxxxxxxxx] > >> > > > Sent: Tuesday, March 15, 2011 3:48 PM > >> > > > To: Nath, Arindam; cjb@xxxxxxxxxx > >> > > > Cc: zhangfei.gao@xxxxxxxxx; prakity@xxxxxxxxxxx; linux- > >> > > > mmc@xxxxxxxxxxxxxxx; Su, Henry; Lu, Aaron; anath.amd@xxxxxxxxx > >> > > > 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. Thanks, Arindam > > > > >> > >> Thanks, > >> Arindam > >> > >> > > >> > > >> > > >> > > > >> > > Thanks, > >> > > Arindam > >> > > > >> > > > > >> > > > Regards, > >> > > > Subhash > >> > > > > >> > > > > >> > > > > -----Original Message----- > >> > > > > From: linux-mmc-owner@xxxxxxxxxxxxxxx [mailto:linux-mmc- > >> > > > > owner@xxxxxxxxxxxxxxx] On Behalf Of Arindam Nath > >> > > > > Sent: Friday, March 04, 2011 5:03 PM > >> > > > > To: cjb@xxxxxxxxxx > >> > > > > Cc: zhangfei.gao@xxxxxxxxx; prakity@xxxxxxxxxxx; > >> > > > > subhashj@xxxxxxxxxxxxxx; linux-mmc@xxxxxxxxxxxxxxx; > >> > > henry.su@xxxxxxx; > >> > > > > aaron.lu@xxxxxxx; anath.amd@xxxxxxxxx; 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.nath@xxxxxxx> > >> > > > > --- > >> > > > > 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 majordomo@xxxxxxxxxxxxxxx > >> > > > > 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 majordomo@xxxxxxxxxxxxxxx > >> > > 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 majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html