Merge "ARM: dts: msm: enable SDR104 workaround for MSM8998"
This commit is contained in:
commit
bbc2d362eb
12 changed files with 92 additions and 3 deletions
|
@ -75,6 +75,11 @@ Optional Properties:
|
|||
during clock scaling. If this property is not
|
||||
defined, then it falls back to the default HS
|
||||
bus speed mode to maintain backward compatibility.
|
||||
- qcom,sdr104-wa: On Certain chipsets, SDR104 mode might be unstable causing CRC errors
|
||||
on the interface. So there is a workaround implemented to skip printing
|
||||
register dumps on CRC errors and also downgrade bus speed mode to
|
||||
SDR50/DDR50 in case of continuous CRC errors. Set this flag to enable
|
||||
this workaround.
|
||||
|
||||
In the following, <supply> can be vdd (flash core voltage) or vdd-io (I/O voltage).
|
||||
- qcom,<supply>-always-on - specifies whether supply should be kept "on" always.
|
||||
|
|
|
@ -1575,6 +1575,8 @@
|
|||
qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000
|
||||
100000000 200000000 4294967295>;
|
||||
|
||||
qcom,sdr104-wa;
|
||||
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
|
|
@ -2189,6 +2189,17 @@ static int mmc_blk_err_check(struct mmc_card *card,
|
|||
int need_retune = card->host->need_retune;
|
||||
int ecc_err = 0, gen_err = 0;
|
||||
|
||||
if (card->host->sdr104_wa && mmc_card_sd(card) &&
|
||||
(card->host->ios.timing == MMC_TIMING_UHS_SDR104) &&
|
||||
!card->sdr104_blocked &&
|
||||
(brq->data.error == -EILSEQ ||
|
||||
brq->data.error == -EIO ||
|
||||
brq->data.error == -ETIMEDOUT ||
|
||||
brq->cmd.error == -EILSEQ ||
|
||||
brq->cmd.error == -EIO ||
|
||||
brq->cmd.error == -ETIMEDOUT))
|
||||
card->err_in_sdr104 = true;
|
||||
|
||||
/*
|
||||
* sbc.error indicates a problem with the set block count
|
||||
* command. No data will have been transferred.
|
||||
|
@ -3645,6 +3656,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
|
|||
struct mmc_async_req *areq;
|
||||
const u8 packed_nr = 2;
|
||||
u8 reqs = 0;
|
||||
bool reset = false;
|
||||
#ifdef CONFIG_MMC_SIMULATE_MAX_SPEED
|
||||
unsigned long waitfor = jiffies;
|
||||
#endif
|
||||
|
@ -3690,6 +3702,26 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
|
|||
type = rq_data_dir(req) == READ ? MMC_BLK_READ : MMC_BLK_WRITE;
|
||||
mmc_queue_bounce_post(mq_rq);
|
||||
|
||||
if (card->err_in_sdr104) {
|
||||
/*
|
||||
* Data CRC/timeout errors will manifest as CMD/DATA
|
||||
* ERR. But we'd like to retry these too.
|
||||
* Moreover, no harm done if this fails too for multiple
|
||||
* times, we anyway reduce the bus-speed and retry the
|
||||
* same request.
|
||||
* If that fails too, we don't override this status.
|
||||
*/
|
||||
if (status == MMC_BLK_ABORT ||
|
||||
status == MMC_BLK_CMD_ERR ||
|
||||
status == MMC_BLK_DATA_ERR ||
|
||||
status == MMC_BLK_RETRY)
|
||||
/* reset on all of these errors and retry */
|
||||
reset = true;
|
||||
|
||||
status = MMC_BLK_RETRY;
|
||||
card->err_in_sdr104 = false;
|
||||
}
|
||||
|
||||
switch (status) {
|
||||
case MMC_BLK_SUCCESS:
|
||||
case MMC_BLK_PARTIAL:
|
||||
|
@ -3730,8 +3762,32 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
|
|||
break;
|
||||
case MMC_BLK_RETRY:
|
||||
retune_retry_done = brq->retune_retry_done;
|
||||
if (retry++ < MMC_BLK_MAX_RETRIES)
|
||||
if (retry++ < MMC_BLK_MAX_RETRIES) {
|
||||
break;
|
||||
} else if (reset) {
|
||||
reset = false;
|
||||
/*
|
||||
* If we exhaust all the retries due to
|
||||
* CRC/timeout errors in SDR140 mode with UHS SD
|
||||
* cards, re-configure the card in SDR50
|
||||
* bus-speed mode.
|
||||
* All subsequent re-init of this card will be
|
||||
* in SDR50 mode, unless it is removed and
|
||||
* re-inserted. When new UHS SD cards are
|
||||
* inserted, it may start at SDR104 mode if
|
||||
* supported by the card.
|
||||
*/
|
||||
pr_err("%s: blocked SDR104, lower the bus-speed (SDR50 / DDR50)\n",
|
||||
req->rq_disk->disk_name);
|
||||
mmc_host_clear_sdr104(card->host);
|
||||
mmc_suspend_clk_scaling(card->host);
|
||||
mmc_blk_reset(md, card->host, type);
|
||||
/* SDR104 mode is blocked from now on */
|
||||
card->sdr104_blocked = true;
|
||||
/* retry 5 times again */
|
||||
retry = 0;
|
||||
break;
|
||||
}
|
||||
/* Fall through */
|
||||
case MMC_BLK_ABORT:
|
||||
if (!mmc_blk_reset(md, card->host, type) &&
|
||||
|
|
|
@ -4040,6 +4040,10 @@ int _mmc_detect_card_removed(struct mmc_host *host)
|
|||
|
||||
if (ret) {
|
||||
mmc_card_set_removed(host->card);
|
||||
if (host->card->sdr104_blocked) {
|
||||
mmc_host_set_sdr104(host);
|
||||
host->card->sdr104_blocked = false;
|
||||
}
|
||||
pr_debug("%s: card remove detected\n", mmc_hostname(host));
|
||||
}
|
||||
|
||||
|
|
|
@ -80,7 +80,6 @@ void mmc_init_context_info(struct mmc_host *host);
|
|||
|
||||
extern bool mmc_can_scale_clk(struct mmc_host *host);
|
||||
extern int mmc_init_clk_scaling(struct mmc_host *host);
|
||||
extern int mmc_suspend_clk_scaling(struct mmc_host *host);
|
||||
extern int mmc_resume_clk_scaling(struct mmc_host *host);
|
||||
extern int mmc_exit_clk_scaling(struct mmc_host *host);
|
||||
extern unsigned long mmc_get_max_frequency(struct mmc_host *host);
|
||||
|
|
|
@ -1285,6 +1285,8 @@ static int _mmc_sd_resume(struct mmc_host *host)
|
|||
#endif
|
||||
mmc_card_clr_suspended(host->card);
|
||||
|
||||
if (host->card->sdr104_blocked)
|
||||
goto out;
|
||||
err = mmc_resume_clk_scaling(host);
|
||||
if (err) {
|
||||
pr_err("%s: %s: fail to resume clock scaling (%d)\n",
|
||||
|
|
|
@ -1960,6 +1960,8 @@ struct sdhci_msm_pltfm_data *sdhci_msm_populate_pdata(struct device *dev,
|
|||
if (of_get_property(np, "qcom,core_3_0v_support", NULL))
|
||||
pdata->core_3_0v_support = true;
|
||||
|
||||
pdata->sdr104_wa = of_property_read_bool(np, "qcom,sdr104-wa");
|
||||
|
||||
return pdata;
|
||||
out:
|
||||
return NULL;
|
||||
|
@ -4579,6 +4581,7 @@ static int sdhci_msm_probe(struct platform_device *pdev)
|
|||
if (msm_host->pdata->nonhotplug)
|
||||
msm_host->mmc->caps2 |= MMC_CAP2_NONHOTPLUG;
|
||||
|
||||
msm_host->mmc->sdr104_wa = msm_host->pdata->sdr104_wa;
|
||||
|
||||
/* Initialize ICE if present */
|
||||
if (msm_host->ice.pdev) {
|
||||
|
|
|
@ -153,6 +153,7 @@ struct sdhci_msm_pltfm_data {
|
|||
u32 ice_clk_min;
|
||||
struct sdhci_msm_pm_qos_data pm_qos_data;
|
||||
bool core_3_0v_support;
|
||||
bool sdr104_wa;
|
||||
};
|
||||
|
||||
struct sdhci_msm_bus_vote {
|
||||
|
|
|
@ -3083,7 +3083,10 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
|
|||
mmc_hostname(host->mmc), intmask,
|
||||
host->data->error, ktime_to_ms(ktime_sub(
|
||||
ktime_get(), host->data_start_time)));
|
||||
sdhci_dumpregs(host);
|
||||
|
||||
if (!host->mmc->sdr104_wa ||
|
||||
(host->mmc->ios.timing != MMC_TIMING_UHS_SDR104))
|
||||
sdhci_dumpregs(host);
|
||||
}
|
||||
sdhci_finish_data(host);
|
||||
} else {
|
||||
|
|
|
@ -434,6 +434,8 @@ struct mmc_card {
|
|||
enum mmc_pon_type pon_type;
|
||||
bool cmdq_init;
|
||||
struct mmc_bkops_info bkops;
|
||||
bool err_in_sdr104;
|
||||
bool sdr104_blocked;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -169,6 +169,7 @@ extern int __mmc_switch_cmdq_mode(struct mmc_command *cmd, u8 set, u8 index,
|
|||
extern int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error);
|
||||
extern int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd);
|
||||
extern int mmc_set_auto_bkops(struct mmc_card *card, bool enable);
|
||||
extern int mmc_suspend_clk_scaling(struct mmc_host *host);
|
||||
|
||||
#define MMC_ERASE_ARG 0x00000000
|
||||
#define MMC_SECURE_ERASE_ARG 0x80000000
|
||||
|
|
|
@ -595,6 +595,7 @@ struct mmc_host {
|
|||
struct io_latency_state io_lat_s;
|
||||
#endif
|
||||
|
||||
bool sdr104_wa;
|
||||
unsigned long private[0] ____cacheline_aligned;
|
||||
};
|
||||
|
||||
|
@ -728,6 +729,16 @@ static inline int mmc_host_uhs(struct mmc_host *host)
|
|||
MMC_CAP_UHS_DDR50);
|
||||
}
|
||||
|
||||
static inline void mmc_host_clear_sdr104(struct mmc_host *host)
|
||||
{
|
||||
host->caps &= ~MMC_CAP_UHS_SDR104;
|
||||
}
|
||||
|
||||
static inline void mmc_host_set_sdr104(struct mmc_host *host)
|
||||
{
|
||||
host->caps |= MMC_CAP_UHS_SDR104;
|
||||
}
|
||||
|
||||
static inline int mmc_host_packed_wr(struct mmc_host *host)
|
||||
{
|
||||
return host->caps2 & MMC_CAP2_PACKED_WR;
|
||||
|
|
Loading…
Add table
Reference in a new issue