> -----Original Message-----
> From: [email protected] [mailto:linux-mmc-
> [email protected]] On Behalf Of Girish K S
> Sent: Thursday, December 01, 2011 7:48 PM
> To: Subhash Jadavani
> Cc: [email protected]; [email protected]; linux-samsung-
> [email protected]; Chris Ball
> Subject: Re: [PATCH V5] mmc: core: HS200 mode support for eMMC 4.5
>
> On 1 December 2011 16:27, Subhash Jadavani <[email protected]>
> wrote:
> >
> >
> >> -----Original Message-----
> >> From: [email protected] [mailto:linux-mmc-
> >> [email protected]] On Behalf Of Girish K S
> >> Sent: Thursday, December 01, 2011 3:58 PM
> >> To: Subhash Jadavani
> >> Cc: [email protected]; [email protected]; linux-samsung-
> >> [email protected]; Chris Ball
> >> Subject: Re: [PATCH V5] mmc: core: HS200 mode support for eMMC 4.5
> >>
> >> On 1 December 2011 15:33, Subhash Jadavani <[email protected]>
> >> wrote:
> >> > Hi Girish,
> >> >
> >> >> -----Original Message-----
> >> >> From: [email protected] [mailto:linux-mmc-
> >> >> [email protected]] On Behalf Of Girish K S
> >> >> Sent: Wednesday, November 30, 2011 2:24 PM
> >> >> To: [email protected]
> >> >> Cc: [email protected]; [email protected];
> >> >> [email protected]; Girish K S; Chris Ball
> >> >> Subject: [PATCH V5] mmc: core: HS200 mode support for eMMC 4.5
> >> >>
> >> >> This patch adds the support of the HS200 bus speed for eMMC 4.5
> >> >> devices.
> >> >> The eMMC 4.5 devices have support for 200MHz bus speed.The mmc
> core
> >> and
> >> >> host modules have been touched to add support for this module.
> >> >>
> >> >> It is necessary to know the card type in the sdhci.c file to add
> >> >> support
> >> >> for eMMC tuning function. So card.h file is included to import
> the
> >> card
> >> >> data structure.
> >> >>
> >> >> cc: Chris Ball <[email protected]>
> >> >> Signed-off-by: Girish K S <[email protected]>
> >> >> ---
> >> >> Changes in v5:
> >> >> Reduced the case statements for better code readability.
> >> Removed
> >> >> unused macro definitions. Modified the tuning function
> >> prototype
> >> >> and definition to support tuning for both SD and eMMC
> cards.
> >> >> Changes in v4:
> >> >> Rebased onto chris-mmc/mmc-next branch. This patch is
> >> >> successfully
> >> >> applied on commit with id
> >> >> de022ed3fdc14808299b2fa66dbb1ed5ab921912.
> >> >> Changes in v3:
> >> >> In the previous commits of chris-mmc/mmc-next branch, the
> >> patch
> >> >> with
> >> >> commit id (c0f22a2c92e357e7cb3988b0b13034d70b7461f9)
> defines
> >> >> caps2 for
> >> >> more capabilities. This patch version deletes the member
> >> >> ext_caps(created
> >> >> in my earlier patch) from struct mmc_host and reuses
> already
> >> >> accepted
> >> >> caps2 member.
> >> >> Changes in v2:
> >> >> Rebased to latest chris-mmc/mmc-next branch. Resolved
> >> indentation
> >> >> problems identified in review. This patch has to be applied
> >> >> before
> >> >> the patch released for modifying the printk messages.
> >> >> Changes in v1:
> >> >> Case statements in switch that produce same result have
> >> >> been combined to reduce repeated assignments.
> >> >> patch recreated after rebase to chris balls mmc-next
> branch.
> >> >>
> >> >> drivers/mmc/core/bus.c | 3 +-
> >> >> drivers/mmc/core/mmc.c | 77
> >> >> ++++++++++++++++++++++++++++++++++++++++----
> >> >> drivers/mmc/core/sd.c | 3 +-
> >> >> drivers/mmc/core/sdio.c | 4 ++-
> >> >> drivers/mmc/host/sdhci.c | 38 +++++++++++++++++-----
> >> >> include/linux/mmc/card.h | 3 ++
> >> >> include/linux/mmc/host.h | 11 ++++++-
> >> >> include/linux/mmc/mmc.h | 66
> >> >> ++++++++++++++++++++++++++++++++++++++-
> >> >> include/linux/mmc/sdhci.h | 1 +
> >> >> 9 files changed, 185 insertions(+), 21 deletions(-)
> >> >>
> >> >> diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
> >> >> index 5639fdf..83c9f8d 100644
> >> >> --- a/drivers/mmc/core/bus.c
> >> >> +++ b/drivers/mmc/core/bus.c
> >> >> @@ -301,10 +301,11 @@ int mmc_add_card(struct mmc_card *card)
> >> >> mmc_card_ddr_mode(card) ? "DDR " : "",
> >> >> type);
> >> >> } else {
> >> >> - printk(KERN_INFO "%s: new %s%s%s card at address
> >> %04x\n",
> >> >> + pr_info("%s: new %s%s%s%s card at address %04x\n",
> >> >> mmc_hostname(card->host),
> >> >> mmc_card_uhs(card) ? "ultra high speed " :
> >> >> (mmc_card_highspeed(card) ? "high speed " :
> >> ""),
> >> >> + (mmc_card_hs200(card) ? "HS200 " : ""),
> >> >> mmc_card_ddr_mode(card) ? "DDR " : "",
> >> >> type, card->rca);
> >> >> }
> >> >> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> >> >> index a1223bd..f4124d6 100644
> >> >> --- a/drivers/mmc/core/mmc.c
> >> >> +++ b/drivers/mmc/core/mmc.c
> >> >> @@ -285,6 +285,27 @@ static int mmc_read_ext_csd(struct mmc_card
> >> *card,
> >> >> u8 *ext_csd)
> >> >> }
> >> >> card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
> >> >> switch (ext_csd[EXT_CSD_CARD_TYPE] &
> EXT_CSD_CARD_TYPE_MASK) {
> >> >> + case EXT_CSD_CARD_TYPE_SDR_ALL:
> >> >> + case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V:
> >> >> + case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V:
> >> >> + case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52:
> >> >> + card->ext_csd.hs_max_dtr = 200000000;
> >> >> + card->ext_csd.card_type =
> EXT_CSD_CARD_TYPE_SDR_200;
> >> >> + break;
> >> >> + case EXT_CSD_CARD_TYPE_SDR_1_2V_ALL:
> >> >> + case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V:
> >> >> + case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V:
> >> >> + case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52:
> >> >> + card->ext_csd.hs_max_dtr = 200000000;
> >> >> + card->ext_csd.card_type =
> EXT_CSD_CARD_TYPE_SDR_1_2V;
> >> >> + break;
> >> >> + case EXT_CSD_CARD_TYPE_SDR_1_8V_ALL:
> >> >> + case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V:
> >> >> + case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V:
> >> >> + case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52:
> >> >> + card->ext_csd.hs_max_dtr = 200000000;
> >> >> + card->ext_csd.card_type =
> EXT_CSD_CARD_TYPE_SDR_1_8V;
> >> >> + break;
> >> >> case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52 |
> >> >> EXT_CSD_CARD_TYPE_26:
> >> >> card->ext_csd.hs_max_dtr = 52000000;
> >> >> @@ -699,6 +720,7 @@ static int mmc_init_card(struct mmc_host
> *host,
> >> u32
> >> >> ocr,
> >> >> {
> >> >> struct mmc_card *card;
> >> >> int err, ddr = 0;
> >> >> + int hs_sdr = 0;
> >> >> u32 cid[4];
> >> >> unsigned int max_dtr;
> >> >> u32 rocr;
> >> >> @@ -894,11 +916,16 @@ static int mmc_init_card(struct mmc_host
> >> *host,
> >> >> u32 ocr,
> >> >> /*
> >> >> * Activate high speed (if supported)
> >> >> */
> >> >> - if ((card->ext_csd.hs_max_dtr != 0) &&
> >> >> - (host->caps & MMC_CAP_MMC_HIGHSPEED)) {
> >> >> - err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> >> >> - EXT_CSD_HS_TIMING, 1,
> >> >> - card->ext_csd.generic_cmd6_time);
> >> >> + if (card->ext_csd.hs_max_dtr != 0) {
> >> >> + err = 0;
> >> >> + if ((card->ext_csd.hs_max_dtr > 52000000) &&
> >> >> + (host->caps2 & MMC_CAP2_HS200))
> >> >> + err = mmc_switch(card,
> EXT_CSD_CMD_SET_NORMAL,
> >> >> + EXT_CSD_HS_TIMING, 2, 0);
> >> >> + else if (host->caps & MMC_CAP_MMC_HIGHSPEED)
> >> >> + err = mmc_switch(card,
> EXT_CSD_CMD_SET_NORMAL,
> >> >> + EXT_CSD_HS_TIMING, 1, 0);
> >> >> +
> >> >> if (err && err != -EBADMSG)
> >> >> goto free_card;
> >> >>
> >> >> @@ -907,7 +934,11 @@ static int mmc_init_card(struct mmc_host
> *host,
> >> >> u32 ocr,
> >> >> mmc_hostname(card->host));
> >> >> err = 0;
> >> >> } else {
> >> >> - mmc_card_set_highspeed(card);
> >> >> + if ((card->ext_csd.hs_max_dtr > 52000000)
> &&
> >> >> + (host->caps2 & MMC_CAP2_HS200))
> >> >> + mmc_card_set_hs200(card);
> >> >> + else
> >> >> + mmc_card_set_highspeed(card);
> >> >> mmc_set_timing(card->host,
> MMC_TIMING_MMC_HS);
> >> >
> >> > MMC_TIMING_MMC_HS200 is defined but still not used.
> >> >
> >> > So I guess it should be like this ::
> >> > + if ((card->ext_csd.hs_max_dtr > 52000000)
> &&
> >> > + (host->caps2 & MMC_CAP2_HS200)) {
> >> > + mmc_card_set_hs200(card);
> >> > + mmc_set_timing(card->host,
> >> MMC_TIMING_MMC_HS200)
> >> > + } else {
> >> > + mmc_card_set_highspeed(card);
> >> > + mmc_set_timing(card->host,
> >> > MMC_TIMING_MMC_HS)
> >> > + }
> >> >
> >> >
> >> >
> >> >
> >> >
> >> >
> >> >
> >> >
> >> >
> >> >
> >> >
> >> >
> >> >
> >> >
> >> >> }
> >> >> }
> >> >> @@ -933,7 +964,7 @@ static int mmc_init_card(struct mmc_host
> *host,
> >> u32
> >> >> ocr,
> >> >> */
> >> >> max_dtr = (unsigned int)-1;
> >> >>
> >> >> - if (mmc_card_highspeed(card)) {
> >> >> + if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
> >> >> if (max_dtr > card->ext_csd.hs_max_dtr)
> >> >> max_dtr = card->ext_csd.hs_max_dtr;
> >> >> } else if (max_dtr > card->csd.max_dtr) {
> >> >> @@ -959,6 +990,18 @@ static int mmc_init_card(struct mmc_host
> *host,
> >> >> u32 ocr,
> >> >> }
> >> >>
> >> >> /*
> >> >> + * Indicate HS200 SDR mode (if supported).
> >> >> + */
> >> >> + if (mmc_card_hs200(card)) {
> >> >> + if ((card->ext_csd.card_type &
> >> EXT_CSD_CARD_TYPE_SDR_1_8V)
> >> >> + && (host->caps2 & MMC_CAP2_HS200_1_8V_SDR))
> >> >> + hs_sdr = MMC_1_8V_SDR_MODE;
> >> >> + else if ((card->ext_csd.card_type &
> >> >> EXT_CSD_CARD_TYPE_SDR_1_2V)
> >> >> + && (host->caps2 & MMC_CAP2_HS200_1_2V_SDR))
> >> >> + hs_sdr = MMC_1_2V_SDR_MODE;
> >> >> + }
> >> >> +
> >> >> + /*
> >> >> * Activate wide bus and DDR (if supported).
> >> >> */
> >> >> if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
> >> >> @@ -998,6 +1041,17 @@ static int mmc_init_card(struct mmc_host
> >> *host,
> >> >> u32 ocr,
> >> >> if (!err) {
> >> >> mmc_set_bus_width(card->host,
> >> bus_width);
> >> >>
> >> >> + if ((host->caps2 & MMC_CAP2_HS200)
> &&
> >> >> + card->host->ops-
> >execute_tuning)
> >> >> + err = card->host->ops-> \
> >> >> + execute_tuning(card-
> >> >host,
> >> >> +
> >> > MMC_SEND_TUNING_BLOCK_HS200);
> >> >
> >> >
> >> > execute_tuning should be done right after the timing is changed to
> >> HS200 and
> >> > clock rate is changed to 200Mhz. This is not the correct sequence
> to
> >> call
> >> > the execute_tuning().
> >> > As told earlier, It is mentioned in the spec that tuning should be
> >> executed after change of buswidth (mandatory). Also it mentions that
> >> "The host may invoke the HS200 tuning sequence, by sending CMD21 to
> the
> >> device". It means that
> >> after setting the HS200 mode, Changing to freq > 52Mhz and changing
> >> the bus width tuning can be executed anytime to identify the
> sampling
> >> point to read.(By anytime i mean before actual block read
> Operation).
> >> Can you please point me to the place in the spec where it specifies
> >> tuning should be done immediately after freq change (may be i missed
> >> to read it).
> >
> >
> > Ok. let me ask you this. Why do we run the execute_tuning()? It's to
> tune
> > the sampling clock generator of host controller before you start any
> read
> > operation (on command line or data line) from card. If you don't tune
> the
> > sampling clock generator before the read operation (after changing
> the
> > timing to HS200 and clock rate to 200mhz), you can't be sure that
> read
> > operation from card will be completed without errors. You may get the
> data /
> > cmd response CRC errors. At least this will surely fail on our MSM
> SDCC host
> > controller. That's what we had faced with SD3.0 UHS-I tuning as well
> as
> > mentioned in http://www.spinics.net/lists/linux-arm-
> msm/msg03867.html.
> > this tuning is done before any read opration for the best bus width
> supported.
Agreed. But can we be sure that "command response" for bus width change via
CMD6, will not have any command CRC failures if tuning is not done?
> ps:Chris need your comment on this
> >
> >> >> +
> >> >> + if (err) {
> >> >> + pr_warning("tuning
> execution
> >> > failed\n");
> >> >> + continue;
> >> >> + }
> >> >> +
> >> >> /*
> >> >> * If controller can't handle bus
> >> width
> >> > test,
> >> >> * compare ext_csd previously read
> in
> >> 1 bit
> >> >> mode
> >> >> @@ -1056,6 +1110,15 @@ static int mmc_init_card(struct mmc_host
> >> *host,
> >> >> u32 ocr,
> >> >> mmc_card_set_ddr_mode(card);
> >> >> mmc_set_timing(card->host,
> >> MMC_TIMING_UHS_DDR50);
> >> >> mmc_set_bus_width(card->host, bus_width);
> >> >> + } else if (hs_sdr) {
> >> >> + if (hs_sdr == EXT_CSD_CARD_TYPE_SDR_1_2V) {
> >> >> + err = mmc_set_signal_voltage(host,
> >> >> + MMC_SIGNAL_VOLTAGE_120, 0);
> >> >> + if (err)
> >> >> + goto err;
> >> >> + }
> >> >> + mmc_set_timing(card->host,
> MMC_TIMING_MMC_HS);
> >> >> + mmc_set_bus_width(card->host, bus_width);
> >> >> }
> >> >> }
> >> >>
> >> >> diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
> >> >> index 1d5a3bd..c1d3ee3 100644
> >> >> --- a/drivers/mmc/core/sd.c
> >> >> +++ b/drivers/mmc/core/sd.c
> >> >> @@ -660,7 +660,8 @@ static int mmc_sd_init_uhs_card(struct
> mmc_card
> >> >> *card)
> >> >>
> >> >> /* SPI mode doesn't define CMD19 */
> >> >> if (!mmc_host_is_spi(card->host) && card->host->ops-
> >> >> >execute_tuning)
> >> >> - err = card->host->ops->execute_tuning(card->host);
> >> >> + err = card->host->ops->execute_tuning(card->host,
> >> \
> >> >> +
> >> > MMC_SEND_TUNING_BLOCK);
> >> >>
> >> >> out:
> >> >> kfree(status);
> >> >> diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
> >> >> index 8c04f7f..8ef8817 100644
> >> >> --- a/drivers/mmc/core/sdio.c
> >> >> +++ b/drivers/mmc/core/sdio.c
> >> >> @@ -14,6 +14,7 @@
> >> >>
> >> >> #include <linux/mmc/host.h>
> >> >> #include <linux/mmc/card.h>
> >> >> +#include <linux/mmc/mmc.h>
> >> >> #include <linux/mmc/sdio.h>
> >> >> #include <linux/mmc/sdio_func.h>
> >> >> #include <linux/mmc/sdio_ids.h>
> >> >> @@ -556,7 +557,8 @@ static int mmc_sdio_init_uhs_card(struct
> >> mmc_card
> >> >> *card)
> >> >>
> >> >> /* Initialize and start re-tuning timer */
> >> >> if (!mmc_host_is_spi(card->host) && card->host->ops-
> >> >> >execute_tuning)
> >> >> - err = card->host->ops->execute_tuning(card->host);
> >> >> + err = card->host->ops->execute_tuning(card->host,
> >> >> +
> >> > MMC_SEND_TUNING_BLOCK);
> >> >>
> >> >> out:
> >> >>
> >> >> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> >> >> index a7c2311..13d74bb 100644
> >> >> --- a/drivers/mmc/host/sdhci.c
> >> >> +++ b/drivers/mmc/host/sdhci.c
> >> >> @@ -49,7 +49,7 @@ static void sdhci_finish_data(struct sdhci_host
> >> *);
> >> >>
> >> >> static void sdhci_send_command(struct sdhci_host *, struct
> >> mmc_command
> >> >> *);
> >> >> static void sdhci_finish_command(struct sdhci_host *);
> >> >> -static int sdhci_execute_tuning(struct mmc_host *mmc);
> >> >> +static int sdhci_execute_tuning(struct mmc_host *mmc, u32
> opcode);
> >> >> static void sdhci_tuning_timer(unsigned long data);
> >> >>
> >> >> #ifdef CONFIG_PM_RUNTIME
> >> >> @@ -1016,7 +1016,8 @@ static void sdhci_send_command(struct
> >> sdhci_host
> >> >> *host, struct mmc_command *cmd)
> >> >> flags |= SDHCI_CMD_INDEX;
> >> >>
> >> >> /* CMD19 is special in that the Data Present Select should
> be
> >> set
> >> >> */
> >> >> - if (cmd->data || (cmd->opcode == MMC_SEND_TUNING_BLOCK))
> >> >> + if (cmd->data || (cmd->opcode == MMC_SEND_TUNING_BLOCK) ||
> >> >> + (cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200))
> >> >> flags |= SDHCI_CMD_DATA;
> >> >>
> >> >> sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags),
> >> >> SDHCI_COMMAND);
> >> >> @@ -1287,7 +1288,7 @@ static void sdhci_request(struct mmc_host
> >> *mmc,
> >> >> struct mmc_request *mrq)
> >> >> if ((host->flags & SDHCI_NEEDS_RETUNING) &&
> >> >> !(present_state & (SDHCI_DOING_WRITE |
> >> >> SDHCI_DOING_READ))) {
> >> >> spin_unlock_irqrestore(&host->lock, flags);
> >> >> - sdhci_execute_tuning(mmc);
> >> >> + sdhci_execute_tuning(mmc, mrq->cmd-
> >opcode);
> >> >> spin_lock_irqsave(&host->lock, flags);
> >> >>
> >> >> /* Restore original mmc_request structure
> */
> >> >> @@ -1673,7 +1674,7 @@ static int
> >> >> sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
> >> >> return err;
> >> >> }
> >> >>
> >> >> -static int sdhci_execute_tuning(struct mmc_host *mmc)
> >> >> +static int sdhci_execute_tuning(struct mmc_host *mmc, u32
> opcode)
> >> >> {
> >> >> struct sdhci_host *host;
> >> >> u16 ctrl;
> >> >> @@ -1694,10 +1695,13 @@ static int sdhci_execute_tuning(struct
> >> mmc_host
> >> >> *mmc)
> >> >> * Host Controller needs tuning only in case of SDR104 mode
> >> >> * and for SDR50 mode when Use Tuning for SDR50 is set in
> >> >> * Capabilities register.
> >> >> + * If the Host Controller supports the HS200 mode then
> tuning
> >> >> + * function has to be executed.
> >> >> */
> >> >> if (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR104)
> ||
> >> >> (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR50)
> &&
> >> >> - (host->flags & SDHCI_SDR50_NEEDS_TUNING)))
> >> >> + (host->flags & SDHCI_SDR50_NEEDS_TUNING)) ||
> >> >> + (host->flags & SDHCI_HS200_NEEDS_TUNING))
> >> >> ctrl |= SDHCI_CTRL_EXEC_TUNING;
> >> >> else {
> >> >> spin_unlock(&host->lock);
> >> >> @@ -1733,7 +1737,7 @@ static int sdhci_execute_tuning(struct
> >> mmc_host
> >> >> *mmc)
> >> >> if (!tuning_loop_counter && !timeout)
> >> >> break;
> >> >>
> >> >> - cmd.opcode = MMC_SEND_TUNING_BLOCK;
> >> >> + cmd.opcode = opcode;
> >> >> cmd.arg = 0;
> >> >> cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
> >> >> cmd.retries = 0;
> >> >> @@ -1748,7 +1752,17 @@ static int sdhci_execute_tuning(struct
> >> mmc_host
> >> >> *mmc)
> >> >> * block to the Host Controller. So we set the
> block
> >> size
> >> >> * to 64 here.
> >> >> */
> >> >> - sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64),
> >> >> SDHCI_BLOCK_SIZE);
> >> >> + if (cmd.opcode == MMC_SEND_TUNING_BLOCK_HS200) {
> >> >> + if (mmc->ios.bus_width == MMC_BUS_WIDTH_8)
> >> >> + sdhci_writew(host,
> SDHCI_MAKE_BLKSZ(7,
> >> 128),
> >> >> + SDHCI_BLOCK_SIZE);
> >> >> + else if (mmc->ios.bus_width ==
> >> MMC_BUS_WIDTH_4)
> >> >> + sdhci_writew(host,
> SDHCI_MAKE_BLKSZ(7,
> >> 64),
> >> >> + SDHCI_BLOCK_SIZE);
> >> >> + } else {
> >> >> + sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64),
> >> >> + SDHCI_BLOCK_SIZE);
> >> >> + }
> >> >>
> >> >> /*
> >> >> * The tuning block is sent by the card to the host
> >> >> controller.
> >> >> @@ -2131,12 +2145,14 @@ static void sdhci_show_adma_error(struct
> >> >> sdhci_host *host) { }
> >> >>
> >> >> static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
> >> >> {
> >> >> + u32 command;
> >> >> BUG_ON(intmask == 0);
> >> >>
> >> >> /* CMD19 generates _only_ Buffer Read Ready interrupt */
> >> >> if (intmask & SDHCI_INT_DATA_AVAIL) {
> >> >> - if (SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))
> ==
> >> >> - MMC_SEND_TUNING_BLOCK) {
> >> >> + command = SDHCI_GET_CMD(sdhci_readw(host,
> >> SDHCI_COMMAND));
> >> >> + if ((command == MMC_SEND_TUNING_BLOCK) ||
> >> >> + (command == MMC_SEND_TUNING_BLOCK_HS200)) {
> >> >> host->tuning_done = 1;
> >> >> wake_up(&host->buf_ready_int);
> >> >> return;
> >> >> @@ -2741,6 +2757,10 @@ int sdhci_add_host(struct sdhci_host
> *host)
> >> >> if (caps[1] & SDHCI_USE_SDR50_TUNING)
> >> >> host->flags |= SDHCI_SDR50_NEEDS_TUNING;
> >> >>
> >> >> + /* Does the host needs tuning for HS200? */
> >> >> + if (mmc->caps2 & MMC_CAP2_HS200)
> >> >> + host->flags |= SDHCI_HS200_NEEDS_TUNING;
> >> >> +
> >> >> /* Driver Type(s) (A, C, D) supported by the host */
> >> >> if (caps[1] & SDHCI_DRIVER_TYPE_A)
> >> >> mmc->caps |= MMC_CAP_DRIVER_TYPE_A;
> >> >> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> >> >> index 534974c..e76f649 100644
> >> >> --- a/include/linux/mmc/card.h
> >> >> +++ b/include/linux/mmc/card.h
> >> >> @@ -209,6 +209,7 @@ struct mmc_card {
> >> >> #define MMC_STATE_HIGHSPEED_DDR (1<<4) /* card is
> in
> >> high
> >> >> speed mode */
> >> >> #define MMC_STATE_ULTRAHIGHSPEED (1<<5) /* card is
> in
> >> ultra
> >> >> high speed mode */
> >> >> #define MMC_CARD_SDXC (1<<6) /* card is
> >> SDXC */
> >> >> +#define MMC_STATE_HIGHSPEED_200 (1<<7) /* card is in HS200
> >> >> mode */
> >> >> unsigned int quirks; /* card quirks */
> >> >> #define MMC_QUIRK_LENIENT_FN0 (1<<0) /* allow
> SDIO
> >> FN0
> >> >> writes outside of the VS CCCR range */
> >> >> #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1) /* use func-
> >> >> >cur_blksize */
> >> >> @@ -365,6 +366,7 @@ static inline void __maybe_unused
> >> >> remove_quirk(struct mmc_card *card, int data)
> >> >> #define mmc_card_present(c) ((c)->state & MMC_STATE_PRESENT)
> >> >> #define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY)
> >> >> #define mmc_card_highspeed(c) ((c)->state &
> >> MMC_STATE_HIGHSPEED)
> >> >> +#define mmc_card_hs200(c) ((c)->state &
> MMC_STATE_HIGHSPEED_200)
> >> >> #define mmc_card_blockaddr(c) ((c)->state &
> >> MMC_STATE_BLOCKADDR)
> >> >> #define mmc_card_ddr_mode(c) ((c)->state &
> MMC_STATE_HIGHSPEED_DDR)
> >> >> #define mmc_card_uhs(c) ((c)->state &
> >> >> MMC_STATE_ULTRAHIGHSPEED)
> >> >> @@ -374,6 +376,7 @@ static inline void __maybe_unused
> >> >> remove_quirk(struct mmc_card *card, int data)
> >> >> #define mmc_card_set_present(c) ((c)->state |=
> >> MMC_STATE_PRESENT)
> >> >> #define mmc_card_set_readonly(c) ((c)->state |=
> MMC_STATE_READONLY)
> >> >> #define mmc_card_set_highspeed(c) ((c)->state |=
> >> MMC_STATE_HIGHSPEED)
> >> >> +#define mmc_card_set_hs200(c) ((c)->state |=
> >> >> MMC_STATE_HIGHSPEED_200)
> >> >> #define mmc_card_set_blockaddr(c) ((c)->state |=
> >> MMC_STATE_BLOCKADDR)
> >> >> #define mmc_card_set_ddr_mode(c) ((c)->state |=
> >> >> MMC_STATE_HIGHSPEED_DDR)
> >> >> #define mmc_card_set_uhs(c) ((c)->state |=
> >> MMC_STATE_ULTRAHIGHSPEED)
> >> >> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> >> >> index 706f722..5eac57a 100644
> >> >> --- a/include/linux/mmc/host.h
> >> >> +++ b/include/linux/mmc/host.h
> >> >> @@ -50,6 +50,7 @@ struct mmc_ios {
> >> >>
> >> >> #define MMC_TIMING_LEGACY 0
> >> >> #define MMC_TIMING_MMC_HS 1
> >> >> +#define MMC_TIMING_MMC_HS200 2
> >> >> #define MMC_TIMING_SD_HS 2
> >> >> #define MMC_TIMING_UHS_SDR12 MMC_TIMING_LEGACY
> >> >> #define MMC_TIMING_UHS_SDR25 MMC_TIMING_SD_HS
> >> >> @@ -60,6 +61,8 @@ struct mmc_ios {
> >> >> #define MMC_SDR_MODE 0
> >> >> #define MMC_1_2V_DDR_MODE 1
> >> >> #define MMC_1_8V_DDR_MODE 2
> >> >> +#define MMC_1_2V_SDR_MODE 3
> >> >> +#define MMC_1_8V_SDR_MODE 4
> >> >>
> >> >> unsigned char signal_voltage; /* signalling
> voltage
> >> >> (1.8V or 3.3V) */
> >> >>
> >> >> @@ -148,7 +151,9 @@ struct mmc_host_ops {
> >> >> void (*init_card)(struct mmc_host *host, struct mmc_card
> >> *card);
> >> >>
> >> >> int (*start_signal_voltage_switch)(struct mmc_host
> *host,
> >> >> struct mmc_ios *ios);
> >> >> - int (*execute_tuning)(struct mmc_host *host);
> >> >> +
> >> >> + /* The tuning command opcode value is different for SD and
> >> eMMC
> >> >> cards */
> >> >> + int (*execute_tuning)(struct mmc_host *host, u32
> opcode);
> >> >> void (*enable_preset_value)(struct mmc_host *host, bool
> >> enable);
> >> >> int (*select_drive_strength)(unsigned int max_dtr, int
> >> >> host_drv, int card_drv);
> >> >> void (*hw_reset)(struct mmc_host *host);
> >> >> @@ -242,6 +247,10 @@ struct mmc_host {
> >> >> #define MMC_CAP2_CACHE_CTRL (1 << 1) /* Allow cache
> control
> >> */
> >> >> #define MMC_CAP2_POWEROFF_NOTIFY (1 << 2) /* Notify poweroff
> >> >> supported */
> >> >> #define MMC_CAP2_NO_MULTI_READ (1 << 3) /*
> Multiblock
> >> reads
> >> >> don't work */
> >> >> +#define MMC_CAP2_HS200_1_8V_SDR (1 << 4) /* can
> support
> >> */
> >> >> +#define MMC_CAP2_HS200_1_2V_SDR (1 << 5) /* can
> support
> >> */
> >> >> +#define MMC_CAP2_HS200 (MMC_CAP2_HS200_1_8V_SDR |
> \
> >> >> + MMC_CAP2_HS200_1_2V_SDR)
> >> >>
> >> >> mmc_pm_flag_t pm_caps; /* supported pm
> >> features */
> >> >> unsigned int power_notify_type;
> >> >> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
> >> >> index 0e71356..7996272 100644
> >> >> --- a/include/linux/mmc/mmc.h
> >> >> +++ b/include/linux/mmc/mmc.h
> >> >> @@ -51,6 +51,7 @@
> >> >> #define MMC_READ_SINGLE_BLOCK 17 /* adtc [31:0] data addr
> R1
> >> >> */
> >> >> #define MMC_READ_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr
> R1
> >> >> */
> >> >> #define MMC_SEND_TUNING_BLOCK 19 /* adtc
> R1
> >> >> */
> >> >> +#define MMC_SEND_TUNING_BLOCK_HS200 21 /* adtc R1 */
> >> >>
> >> >> /* class 3 */
> >> >> #define MMC_WRITE_DAT_UNTIL_STOP 20 /* adtc [31:0] data addr
> R1
> >> >> */
> >> >> @@ -333,13 +334,76 @@ struct _mmc_csd {
> >> >>
> >> >> #define EXT_CSD_CARD_TYPE_26 (1<<0) /* Card can run at 26MHz */
> >> >> #define EXT_CSD_CARD_TYPE_52 (1<<1) /* Card can run at 52MHz */
> >> >> -#define EXT_CSD_CARD_TYPE_MASK 0xF /* Mask out
> reserved
> >> bits */
> >> >> +#define EXT_CSD_CARD_TYPE_MASK 0x3F /* Mask out
> reserved
> >> bits */
> >> >> #define EXT_CSD_CARD_TYPE_DDR_1_8V (1<<2) /* Card can run at
> >> 52MHz
> >> >> */
> >> >> /* DDR mode @1.8V or
> 3V
> >> I/O */
> >> >> #define EXT_CSD_CARD_TYPE_DDR_1_2V (1<<3) /* Card can run at
> >> 52MHz
> >> >> */
> >> >> /* DDR mode @1.2V I/O
> */
> >> >> #define EXT_CSD_CARD_TYPE_DDR_52
> (EXT_CSD_CARD_TYPE_DDR_1_8V
> >> \
> >> >> |
> EXT_CSD_CARD_TYPE_DDR_1_2V)
> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_8V (1<<4) /* Card can run at
> >> >> 200MHz */
> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_2V (1<<5) /* Card can run at
> >> >> 200MHz */
> >> >> + /* SDR mode @1.2V
> I/O
> >> */
> >> >> +
> >> >> +#define EXT_CSD_CARD_TYPE_SDR_200 (EXT_CSD_CARD_TYPE_SDR_1_8V
> >> \
> >> >> + |
> EXT_CSD_CARD_TYPE_SDR_1_2V)
> >> >> +
> >> >> +#define EXT_CSD_CARD_TYPE_SDR_ALL (EXT_CSD_CARD_TYPE_SDR_200
> >> \
> >> >> + | EXT_CSD_CARD_TYPE_52
> >> \
> >> >> + | EXT_CSD_CARD_TYPE_26)
> >> >> +
> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_ALL
> >> >> (EXT_CSD_CARD_TYPE_SDR_1_2V \
> >> >> + | EXT_CSD_CARD_TYPE_52
> >> \
> >> >> + | EXT_CSD_CARD_TYPE_26)
> >> >> +
> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_ALL
> >> >> (EXT_CSD_CARD_TYPE_SDR_1_8V \
> >> >> + | EXT_CSD_CARD_TYPE_52
> >> \
> >> >> + | EXT_CSD_CARD_TYPE_26)
> >> >> +
> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V
> >> >> (EXT_CSD_CARD_TYPE_SDR_1_2V \
> >> >> + |
> >> EXT_CSD_CARD_TYPE_DDR_1_8V
> >> > \
> >> >> + |
> EXT_CSD_CARD_TYPE_52
> >> > \
> >> >> + |
> >> EXT_CSD_CARD_TYPE_26)
> >> >> +
> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V
> >> >> (EXT_CSD_CARD_TYPE_SDR_1_8V \
> >> >> + |
> >> EXT_CSD_CARD_TYPE_DDR_1_8V
> >> > \
> >> >> + |
> EXT_CSD_CARD_TYPE_52
> >> > \
> >> >> + |
> >> EXT_CSD_CARD_TYPE_26)
> >> >> +
> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V
> >> >> (EXT_CSD_CARD_TYPE_SDR_1_2V \
> >> >> + |
> >> EXT_CSD_CARD_TYPE_DDR_1_2V
> >> > \
> >> >> + |
> EXT_CSD_CARD_TYPE_52
> >> > \
> >> >> + |
> >> EXT_CSD_CARD_TYPE_26)
> >> >> +
> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V
> >> >> (EXT_CSD_CARD_TYPE_SDR_1_8V \
> >> >> + |
> >> EXT_CSD_CARD_TYPE_DDR_1_2V
> >> > \
> >> >> + |
> EXT_CSD_CARD_TYPE_52
> >> > \
> >> >> + |
> >> EXT_CSD_CARD_TYPE_26)
> >> >> +
> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52
> >> >> (EXT_CSD_CARD_TYPE_SDR_1_2V \
> >> >> + |
> >> EXT_CSD_CARD_TYPE_DDR_52
> >> > \
> >> >> + |
> EXT_CSD_CARD_TYPE_52
> >> > \
> >> >> + |
> >> EXT_CSD_CARD_TYPE_26)
> >> >> +
> >> >> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52
> >> >> (EXT_CSD_CARD_TYPE_SDR_1_8V \
> >> >> + |
> >> EXT_CSD_CARD_TYPE_DDR_52
> >> > \
> >> >> + |
> EXT_CSD_CARD_TYPE_52
> >> > \
> >> >> + |
> >> EXT_CSD_CARD_TYPE_26)
> >> >> +
> >> >> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V
> >> >> (EXT_CSD_CARD_TYPE_SDR_200 \
> >> >> + |
> >> EXT_CSD_CARD_TYPE_DDR_1_8V
> >> > \
> >> >> + |
> EXT_CSD_CARD_TYPE_52
> >> > \
> >> >> + |
> >> EXT_CSD_CARD_TYPE_26)
> >> >> +
> >> >> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V
> >> >> (EXT_CSD_CARD_TYPE_SDR_200 \
> >> >> + |
> >> EXT_CSD_CARD_TYPE_DDR_1_2V
> >> > \
> >> >> + |
> EXT_CSD_CARD_TYPE_52
> >> > \
> >> >> + |
> >> EXT_CSD_CARD_TYPE_26)
> >> >> +
> >> >> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52
> >> (EXT_CSD_CARD_TYPE_SDR_200
> >> >> \
> >> >> + |
> >> EXT_CSD_CARD_TYPE_DDR_52
> >> > \
> >> >> + |
> EXT_CSD_CARD_TYPE_52
> >> > \
> >> >> + |
> >> EXT_CSD_CARD_TYPE_26)
> >> >>
> >> >> #define EXT_CSD_BUS_WIDTH_1 0 /* Card is in 1 bit mode */
> >> >> #define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */
> >> >> diff --git a/include/linux/mmc/sdhci.h
> b/include/linux/mmc/sdhci.h
> >> >> index e4b6935..d9a2222 100644
> >> >> --- a/include/linux/mmc/sdhci.h
> >> >> +++ b/include/linux/mmc/sdhci.h
> >> >> @@ -121,6 +121,7 @@ struct sdhci_host {
> >> >> #define SDHCI_AUTO_CMD23 (1<<7) /* Auto CMD23 support */
> >> >> #define SDHCI_PV_ENABLED (1<<8) /* Preset value enabled */
> >> >> #define SDHCI_SDIO_IRQ_ENABLED (1<<9) /* SDIO irq enabled
> */
> >> >> +#define SDHCI_HS200_NEEDS_TUNING (1<<10) /* HS200 needs
> tuning
> >> */
> >> >>
> >> >> unsigned int version; /* SDHCI spec. version */
> >> >>
> >> >> --
> >> >> 1.7.1
> >> >>
> >> >> --
> >> >> To unsubscribe from this list: send the line "unsubscribe linux-
> mmc"
> >> in
> >> >> the body of a message to [email protected]
> >> >> 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 [email protected]
> >> > 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 [email protected]
> >> 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 [email protected]
> 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 [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html