On 1 December 2011 16:27, Subhash Jadavani <subhashj@xxxxxxxxxxxxxx> wrote: > > >> -----Original Message----- >> From: linux-mmc-owner@xxxxxxxxxxxxxxx [mailto:linux-mmc- >> owner@xxxxxxxxxxxxxxx] On Behalf Of Girish K S >> Sent: Thursday, December 01, 2011 3:58 PM >> To: Subhash Jadavani >> Cc: linux-mmc@xxxxxxxxxxxxxxx; patches@xxxxxxxxxx; linux-samsung- >> soc@xxxxxxxxxxxxxxx; Chris Ball >> Subject: Re: [PATCH V5] mmc: core: HS200 mode support for eMMC 4.5 >> >> On 1 December 2011 15:33, Subhash Jadavani <subhashj@xxxxxxxxxxxxxx> >> wrote: >> > Hi Girish, >> > >> >> -----Original Message----- >> >> From: linux-mmc-owner@xxxxxxxxxxxxxxx [mailto:linux-mmc- >> >> owner@xxxxxxxxxxxxxxx] On Behalf Of Girish K S >> >> Sent: Wednesday, November 30, 2011 2:24 PM >> >> To: linux-mmc@xxxxxxxxxxxxxxx >> >> Cc: patches@xxxxxxxxxx; linux-samsung-soc@xxxxxxxxxxxxxxx; >> >> subhashj@xxxxxxxxxxxxxx; 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 <cjb@xxxxxxxxxx> >> >> Signed-off-by: Girish K S <girish.shivananjappa@xxxxxxxxxx> >> >> --- >> >> 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. 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 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 > -- 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