sd: g12a: optimize sd & wifi TDMA

PD#166884: optimize sd inval irq error,
when sd insert wifi running. wifi is data1.

Change-Id: I6de4f519d3bacec7d9ab4eec4fc9b0cfc6b5d07d
Signed-off-by: Nan Li <nan.li@amlogic.com>
This commit is contained in:
Nan Li
2018-05-22 16:16:31 +08:00
committed by Yixun Lan
parent 11573cdb34
commit 59bc6ce4ed
5 changed files with 193 additions and 81 deletions

View File

@@ -1425,7 +1425,7 @@
status = "disabled";
compatible = "amlogic, meson-mmc-g12a";
reg = <0x0 0xffe05000 0x0 0x800>;
interrupts = <0 190 1>;
interrupts = <0 190 4>;
pinctrl-names = "sd_all_pins",
"sd_clk_cmd_pins",
@@ -2058,11 +2058,15 @@
"GPIOC_1",
"GPIOC_2",
"GPIOC_3",
"GPIOC_4",
"GPIOC_5";
function = "gpio_periphs";
output-high;
};
mux1 {
groups = "GPIOC_4";
function = "gpio_periphs";
output-low;
};
};
sd_clr_noall_pins:sd_clr_noall_pins {
@@ -2165,7 +2169,12 @@
groups = "GPIOV_0";
function = "gpio_periphs";
bias-pull-up;
output-high;
output-low;
};
mux1 {
groups = "GPIOX_4";
function = "gpio_periphs";
output-low;
};
};

View File

@@ -513,6 +513,7 @@ _cali_retry:
ret = aml_cali_auto(mmc, &c_data);
else
ret = aml_cali_index(mmc, &c_data);
host->is_tunning = 0;
if (ret) {
/* Do not get a valid line delay index value! */
if (cali_retry < MAX_CALI_RETRY) {
@@ -526,7 +527,6 @@ _cali_retry:
return -1;
}
}
host->is_tunning = 0;
ret = aml_cali_find(mmc, &c_data);
/* retry cali here! */
@@ -731,6 +731,7 @@ tunning:
host->is_tunning = 1;
ret = aml_tuning_adj(mmc, opcode,
tuning_data, &best_win_start, &best_win_size);
host->is_tunning = 0;
if (ret)
return -ENOMEM;
if (best_win_size <= 0) {
@@ -787,7 +788,6 @@ tunning:
gadjust->cali_enable = 0;
gadjust->cali_rise = 0;
writel(adjust, host->base + SD_EMMC_ADJUST);
host->is_tunning = 0;
/* fixme, yyh for retry flow. */
emmc_adj->adj_win_start = best_win_start;
@@ -1140,13 +1140,14 @@ void aml_sd_emmc_set_clkc(struct amlsd_platform *pdata)
void aml_sd_emmc_save_host_val(struct mmc_host *mmc)
{
u32 adj, dly1, dly2, intf3;
u32 vconf = 0;
u32 vconf = 0, vclkc = 0;
struct sd_emmc_config *pconf = (struct sd_emmc_config *)&vconf;
struct amlsd_platform *pdata = mmc_priv(mmc);
struct amlsd_host *host = pdata->host;
unsigned long clk_ios;
clk_ios = clk_get_rate(host->cfg_div_clk);
vclkc = readl(host->base + SD_EMMC_CLOCK_V3);
vconf = readl(host->base + SD_EMMC_CFG);
adj = readl(host->base + SD_EMMC_ADJUST_V3);
dly1 = readl(host->base + SD_EMMC_DELAY1_V3);
@@ -1157,6 +1158,7 @@ void aml_sd_emmc_save_host_val(struct mmc_host *mmc)
&& (pconf->bl_len == pdata->bl_len)
&& (pconf->stop_clk == pdata->stop_clk)
&& (mmc->actual_clock == clk_ios)
&& (vclkc == pdata->clkc)
&& (adj == pdata->adj)
&& (dly1 == pdata->dly1)
&& (dly2 == pdata->dly2)
@@ -1169,6 +1171,7 @@ void aml_sd_emmc_save_host_val(struct mmc_host *mmc)
pconf->bus_width = pdata->bus_width;
pconf->bl_len = pdata->bl_len;
pconf->stop_clk = pdata->stop_clk;
vclkc = pdata->clkc;
adj = pdata->adj;
dly1 = pdata->dly1;
dly2 = pdata->dly2;
@@ -1176,7 +1179,9 @@ void aml_sd_emmc_save_host_val(struct mmc_host *mmc)
if (aml_card_type_non_sdio(pdata))
pconf->stop_clk = 0;
writel(vclkc, host->base + SD_EMMC_CLOCK_V3);
clk_set_rate(host->cfg_div_clk, clk_ios);
pdata->clkc = readl(host->base + SD_EMMC_CLOCK_V3);
writel(vconf, host->base + SD_EMMC_CFG);
writel(adj, host->base + SD_EMMC_ADJUST_V3);
writel(dly1, host->base + SD_EMMC_DELAY1_V3);
@@ -1858,11 +1863,72 @@ static void aml_sd_emmc_check_sdio_irq(struct amlsd_host *host)
}
}
}
static void aml_sd_emmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
{
struct amlsd_platform *pdata = mmc_priv(mmc);
struct amlsd_host *host = pdata->host;
unsigned long flags;
/* u32 vstat = 0; */
u32 vclkc = 0;
struct sd_emmc_clock *pclock = NULL;
struct sd_emmc_clock_v3 *pclock_v3 = NULL;
u32 vconf = 0;
struct sd_emmc_config *pconf = (struct sd_emmc_config *)&vconf;
u32 virqc = 0;
struct sd_emmc_irq_en *irqc = (struct sd_emmc_irq_en *)&virqc;
host->sdio_irqen = enable;
if (host->xfer_step == XFER_START)
return;
if (enable)
spin_lock_irqsave(&host->mrq_lock, flags);
vconf = readl(host->base + SD_EMMC_CFG);
virqc = readl(host->base + SD_EMMC_IRQ_EN);
pconf->irq_ds = 0;
/* vstat = sd_emmc_regs->gstatus&SD_EMMC_IRQ_ALL; */
if (enable)
irqc->irq_sdio = 1;
else
irqc->irq_sdio = 0;
writel(virqc, host->base + SD_EMMC_IRQ_EN);
writel(vconf, host->base + SD_EMMC_CFG);
if (host->ctrl_ver >= 3) {
pclock_v3 = (struct sd_emmc_clock_v3 *)&vclkc;
vclkc = readl(host->base + SD_EMMC_CLOCK_V3);
pclock_v3->irq_sdio_sleep = 1;
pclock_v3->irq_sdio_sleep_ds = 0;
writel(vclkc, host->base + SD_EMMC_CLOCK_V3);
} else {
pclock = (struct sd_emmc_clock *)&vclkc;
vclkc = readl(host->base + SD_EMMC_CLOCK);
pclock->irq_sdio_sleep = 1;
pclock->irq_sdio_sleep_ds = 0;
writel(vclkc, host->base + SD_EMMC_CLOCK);
}
pdata->clkc = vclkc;
if (enable)
spin_unlock_irqrestore(&host->mrq_lock, flags);
/* check if irq already occurred */
aml_sd_emmc_check_sdio_irq(host);
}
int meson_mmc_request_done(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct amlsd_platform *pdata = NULL;
struct amlsd_host *host = NULL;
unsigned long flags;
#ifdef AML_MMC_TDMA
u32 virqc = 0;
struct sd_emmc_irq_en *irqc = (struct sd_emmc_irq_en *)&virqc;
#endif
pdata = mmc_priv(mmc);
host = pdata->host;
@@ -1878,11 +1944,26 @@ int meson_mmc_request_done(struct mmc_host *mmc, struct mmc_request *mrq)
if (pdata->xfer_post)
pdata->xfer_post(pdata);
#ifdef AML_MMC_TDMA
if ((host->mem->start == host->data->port_b_base)
&& (host->data->chip_type == MMC_CHIP_G12A)
&& strcmp(host->pinctrl_name, "sdio_")) {
if (sdio_host) {
if (pdata->xfer_pre)
pdata->xfer_pre(mmc_priv(sdio_host));
virqc = readl(host->base + SD_EMMC_IRQ_EN);
if (irqc->irq_sdio != host->sdio_irqen)
aml_sd_emmc_enable_sdio_irq(sdio_host,
host->sdio_irqen);
}
}
#endif
aml_sd_emmc_check_sdio_irq(host);
mmc_request_done(host->mmc, mrq);
#ifdef AML_MMC_TDMA
if ((host->mem->start == host->data->port_b_base)
&& (host->data->chip_type == MMC_CHIP_G12A)
&& (host->init_volt == 0)
&& (host->is_tunning == 0))
complete(&host->drv_completion);
#endif
@@ -1982,6 +2063,11 @@ static void meson_mmc_start_cmd(struct mmc_host *mmc, struct mmc_request *mrq)
conf_flag |= 1 << 0;
pconf->auto_clk = 0;
host->sd_sdio_switch_volat_done = 0;
#ifdef AML_MMC_TDMA
if ((host->mem->start == host->data->port_b_base)
&& (host->data->chip_type == MMC_CHIP_G12A))
host->init_volt = 1;
#endif
}
if ((pconf->auto_clk) && (pdata->auto_clk_close)) {
conf_flag |= 1 << 1;
@@ -2254,10 +2340,9 @@ static void meson_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
pdata->xfer_pre(pdata);
#ifdef AML_MMC_TDMA
if ((host->mem->start == host->data->port_b_base)
&& (host->data->chip_type == MMC_CHIP_G12A)) {
aml_sd_emmc_save_host_val(mmc);
}
if ((host->mem->start == host->data->port_b_base)
&& (host->data->chip_type == MMC_CHIP_G12A))
aml_sd_emmc_save_host_val(mmc);
#endif
spin_lock_irqsave(&host->mrq_lock, flags);
@@ -2391,6 +2476,9 @@ static irqreturn_t meson_mmc_irq(int irq, void *dev_id)
if (WARN_ON(!host))
return IRQ_NONE;
#ifdef AML_MMC_TDMA
spin_lock_irqsave(&host->mrq_lock, flags);
#endif
virqc = readl(host->base + SD_EMMC_IRQ_EN) & 0xffff;
vstat = readl(host->base + SD_EMMC_STATUS) & 0xffffffff;
host->ista = vstat;
@@ -2399,16 +2487,46 @@ static irqreturn_t meson_mmc_irq(int irq, void *dev_id)
__func__, __LINE__, vstat);
if (irqc->irq_sdio && ista->irq_sdio) {
if ((host->mmc->sdio_irq_thread)
&& (!atomic_read(&host->mmc->sdio_irq_thread_abort))) {
mmc_signal_sdio_irq(host->mmc);
if (!(vstat & 0x3fff))
return IRQ_HANDLED;
#ifdef AML_MMC_TDMA
if (strcmp(mmc_hostname(host->mmc), "sdio")
&& sdio_host) {
if ((sdio_host->sdio_irq_thread)
&& (!atomic_read(
&sdio_host->sdio_irq_thread_abort))) {
mmc_signal_sdio_irq(sdio_host);
if (!(vstat & 0x3fff)) {
spin_unlock_irqrestore(&host->mrq_lock,
flags);
return IRQ_HANDLED;
}
}
} else {
#endif
if ((host->mmc->sdio_irq_thread)
&& (!atomic_read(
&host->mmc->sdio_irq_thread_abort))) {
mmc_signal_sdio_irq(host->mmc);
if (!(vstat & 0x3fff)) {
#ifdef AML_MMC_TDMA
spin_unlock_irqrestore(&host->mrq_lock,
flags);
#endif
return IRQ_HANDLED;
}
}
#ifdef AML_MMC_TDMA
}
} else if (!(vstat & 0x3fff))
#endif
} else if (!(vstat & 0x3fff)) {
#ifdef AML_MMC_TDMA
spin_unlock_irqrestore(&host->mrq_lock, flags);
#endif
return IRQ_HANDLED;
}
#ifndef AML_MMC_TDMA
spin_lock_irqsave(&host->mrq_lock, flags);
#endif
mrq = host->mrq;
mmc = host->mmc;
pdata = mmc_priv(mmc);
@@ -2816,56 +2934,6 @@ static irqreturn_t meson_mmc_irq_thread(int irq, void *dev_id)
return IRQ_HANDLED;
}
static void aml_sd_emmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
{
struct amlsd_platform *pdata = mmc_priv(mmc);
struct amlsd_host *host = pdata->host;
unsigned long flags;
/* u32 vstat = 0; */
u32 vclkc = 0;
struct sd_emmc_clock *pclock = NULL;
struct sd_emmc_clock_v3 *pclock_v3 = NULL;
u32 vconf = 0;
struct sd_emmc_config *pconf = (struct sd_emmc_config *)&vconf;
u32 virqc = 0;
struct sd_emmc_irq_en *irqc = (struct sd_emmc_irq_en *)&virqc;
host->sdio_irqen = enable;
spin_lock_irqsave(&host->mrq_lock, flags);
vconf = readl(host->base + SD_EMMC_CFG);
virqc = readl(host->base + SD_EMMC_IRQ_EN);
pconf->irq_ds = 0;
/* vstat = sd_emmc_regs->gstatus&SD_EMMC_IRQ_ALL; */
if (enable)
irqc->irq_sdio = 1;
else
irqc->irq_sdio = 0;
writel(virqc, host->base + SD_EMMC_IRQ_EN);
writel(vconf, host->base + SD_EMMC_CFG);
if (host->ctrl_ver >= 3) {
pclock_v3 = (struct sd_emmc_clock_v3 *)&vclkc;
vclkc = readl(host->base + SD_EMMC_CLOCK_V3);
pclock_v3->irq_sdio_sleep = 1;
pclock_v3->irq_sdio_sleep_ds = 0;
writel(vclkc, host->base + SD_EMMC_CLOCK_V3);
} else {
pclock = (struct sd_emmc_clock *)&vclkc;
vclkc = readl(host->base + SD_EMMC_CLOCK);
pclock->irq_sdio_sleep = 1;
pclock->irq_sdio_sleep_ds = 0;
writel(vclkc, host->base + SD_EMMC_CLOCK);
}
pdata->clkc = vclkc;
spin_unlock_irqrestore(&host->mrq_lock, flags);
/* check if irq already occurred */
aml_sd_emmc_check_sdio_irq(host);
}
/*get readonly: 0 for rw, 1 for ro*/
static int aml_sd_emmc_get_ro(struct mmc_host *mmc)
{
@@ -2905,6 +2973,12 @@ static int aml_sd_emmc_card_busy(struct mmc_host *mmc)
u32 vconf;
struct sd_emmc_config *pconf = (struct sd_emmc_config *)&vconf;
#ifdef AML_MMC_TDMA
if ((host->mem->start == host->data->port_b_base)
&& (host->data->chip_type == MMC_CHIP_G12A)
&& (host->init_volt == 0))
wait_for_completion(&host->drv_completion);
#endif
vstat = readl(host->base + SD_EMMC_STATUS);
status = ista->dat_i & 0xf;
@@ -2914,7 +2988,18 @@ static int aml_sd_emmc_card_busy(struct mmc_host *mmc)
vconf = readl(host->base + SD_EMMC_CFG);
pconf->auto_clk = 1;
writel(vconf, host->base + SD_EMMC_CFG);
#ifdef AML_MMC_TDMA
if ((host->mem->start == host->data->port_b_base)
&& (host->data->chip_type == MMC_CHIP_G12A))
host->init_volt = 0;
#endif
}
#ifdef AML_MMC_TDMA
if ((host->mem->start == host->data->port_b_base)
&& (host->data->chip_type == MMC_CHIP_G12A)
&& (host->init_volt == 0))
complete(&host->drv_completion);
#endif
return !status;
}
@@ -3021,12 +3106,14 @@ static int meson_mmc_probe(struct platform_device *pdev)
}
if (host->ctrl_ver >= 3) {
#ifdef AML_MMC_TDMA
if ((host->mem->start == host->data->port_b_base)
&& (host->data->chip_type == MMC_CHIP_G12A))
ret = devm_request_threaded_irq(&pdev->dev, host->irq,
meson_mmc_irq, meson_mmc_irq_thread_v3,
IRQF_ONESHOT, "meson-aml-mmc", host);
else
#endif
ret = devm_request_threaded_irq(&pdev->dev, host->irq,
meson_mmc_irq, meson_mmc_irq_thread_v3,
IRQF_SHARED, "meson-aml-mmc", host);

View File

@@ -62,6 +62,9 @@ int meson_mmc_clk_init_v3(struct amlsd_host *host)
pclkc->div = 60; /* 400KHz */
pclkc->src = 0; /* 0: Crystal 24MHz */
pclkc->core_phase = init->core_phase; /* 2: 180 phase */
if ((host->mem->start == host->data->port_b_base)
&& (host->data->chip_type == MMC_CHIP_G12A))
pclkc->core_phase = 2;
pclkc->rx_phase = init->rx_phase;
pclkc->tx_phase = init->tx_phase;
pclkc->always_on = 1; /* Keep clock always on */
@@ -307,17 +310,19 @@ void meson_mmc_set_ios_v3(struct mmc_host *mmc,
struct mmc_ios *ios)
{
struct amlsd_platform *pdata = mmc_priv(mmc);
#ifdef AML_MMC_TDMA
struct amlsd_host *host = pdata->host;
#ifdef AML_MMC_TDMA
if ((host->mem->start == host->data->port_b_base)
&& (host->data->chip_type == MMC_CHIP_G12A))
&& (host->data->chip_type == MMC_CHIP_G12A)
&& (host->init_volt == 0))
wait_for_completion(&host->drv_completion);
#endif
if (!pdata->is_in) {
#ifdef AML_MMC_TDMA
if ((host->mem->start == host->data->port_b_base)
&& (host->data->chip_type == MMC_CHIP_G12A))
&& (host->data->chip_type == MMC_CHIP_G12A)
&& (host->init_volt == 0))
complete(&host->drv_completion);
#endif
return;
@@ -341,7 +346,8 @@ void meson_mmc_set_ios_v3(struct mmc_host *mmc,
aml_cs_dont_care(mmc);
#ifdef AML_MMC_TDMA
if ((host->mem->start == host->data->port_b_base)
&& (host->data->chip_type == MMC_CHIP_G12A))
&& (host->data->chip_type == MMC_CHIP_G12A)
&& (host->init_volt == 0))
complete(&host->drv_completion);
#endif
}
@@ -581,7 +587,6 @@ static int emmc_eyetest_log(struct mmc_host *mmc, u32 line_x)
u64 tmp = 0;
u32 blksz = 512;
host->is_tunning = 1;
pr_debug("delay1: 0x%x , delay2: 0x%x, line_x: %d\n",
readl(host->base + SD_EMMC_DELAY1_V3),
readl(host->base + SD_EMMC_DELAY2_V3), line_x);
@@ -601,12 +606,14 @@ RETRY:
/*****test start*************/
udelay(5);
host->is_tunning = 1;
if (line_x < 9)
aml_sd_emmc_cali_v3(mmc,
MMC_READ_MULTIPLE_BLOCK,
host->blk_test, blksz, 40);
else
aml_sd_emmc_cmd_v3(mmc);
host->is_tunning = 0;
udelay(1);
eyetest_log = readl(host->base + SD_EMMC_EYETEST_LOG);
@@ -635,7 +642,6 @@ RETRY:
readl(host->base + SD_EMMC_DELAY1_V3),
readl(host->base + SD_EMMC_DELAY2_V3),
pdata->align[line_x], line_x);
host->is_tunning = 0;
return 0;
}
@@ -1075,12 +1081,12 @@ tunning:
|| (clkc->div >= 10)) {
pr_info("%s: final result of tuning failed\n",
mmc_hostname(host->mmc));
host->is_tunning = 0;
#ifdef AML_MMC_TDMA
if ((host->mem->start == host->data->port_b_base)
&& (host->data->chip_type == MMC_CHIP_G12A))
complete(&host->drv_completion);
#endif
return -1;
}
clkc->div += 1;
@@ -1093,6 +1099,12 @@ tunning:
if (++tuning_num > MAX_TUNING_RETRY) {
pr_err("%s: tuning failed\n",
mmc_hostname(host->mmc));
host->is_tunning = 0;
#ifdef AML_MMC_TDMA
if ((host->mem->start == host->data->port_b_base)
&& (host->data->chip_type == MMC_CHIP_G12A))
complete(&host->drv_completion);
#endif
return -1;
}
pr_warn("wave is not sharp, again\n");
@@ -1116,6 +1128,11 @@ tunning:
gadjust->cali_rise = 0;
writel(adjust, host->base + SD_EMMC_ADJUST_V3);
pdata->adj = adjust;
pr_info("%s: sd_emmc_regs->gclock=0x%x,sd_emmc_regs->gadjust=0x%x\n",
mmc_hostname(host->mmc),
readl(host->base + SD_EMMC_CLOCK_V3),
readl(host->base + SD_EMMC_ADJUST_V3));
host->is_tunning = 0;
#ifdef AML_MMC_TDMA
if ((host->mem->start == host->data->port_b_base)
@@ -1123,10 +1140,6 @@ tunning:
complete(&host->drv_completion);
#endif
pr_info("%s: sd_emmc_regs->gclock=0x%x,sd_emmc_regs->gadjust=0x%x\n",
mmc_hostname(host->mmc),
readl(host->base + SD_EMMC_CLOCK_V3),
readl(host->base + SD_EMMC_ADJUST_V3));
return ret;
#endif
return 0;
@@ -1253,7 +1266,6 @@ static int sdio_eyetest_log(struct mmc_host *mmc, u32 line_x, u32 opcode,
const u8 *blk_pattern = tuning_data->blk_pattern;
unsigned int blksz = tuning_data->blksz;
host->is_tunning = 1;
/****** calculate line_x ***************************/
/******* init eyetest register ************************/
pr_debug("delay1: 0x%x , delay2: 0x%x, line_x: %d\n",
@@ -1271,9 +1283,11 @@ RETRY:
pdata->intf3 = intf3;
udelay(5);
host->is_tunning = 1;
for (i = 0; i < 40; i++)
aml_sd_emmc_tuning_transfer(mmc, opcode,
blk_pattern, host->blk_test, blksz);
host->is_tunning = 0;
udelay(1);
eyetest_log = readl(host->base + SD_EMMC_EYETEST_LOG);
eyetest_out0 = readl(host->base + SD_EMMC_EYETEST_OUT0);
@@ -1302,7 +1316,6 @@ RETRY:
pdata->intf3 = intf3;
pdata->align[line_x] = ((tmp | eyetest_out1) << 32) | eyetest_out0;
pr_debug("u64 eyetestout 0x%llx\n", pdata->align[line_x]);
host->is_tunning = 0;
return 0;
}
@@ -1315,7 +1328,6 @@ static int aml_sdio_timing(struct mmc_host *mmc, u32 opcode,
u32 line_x = 0, delay1 = 0, retry = 1, temp;
int ret;
host->is_tunning = 1;
delay1 = 0;
for (line_x = 0; line_x < 4; line_x++) {
writel(0, host->base + SD_EMMC_DELAY1_V3);
@@ -1356,7 +1368,6 @@ RETRY:
writel(delay1, host->base + SD_EMMC_DELAY1_V3);
pdata->dly1 = delay1;
host->is_tunning = 0;
pr_info("%s: gadjust=0x%x, gdelay1=0x%x, gclock=0x%x\n",
mmc_hostname(host->mmc),
readl(host->base + SD_EMMC_ADJUST_V3),

View File

@@ -867,6 +867,8 @@ int aml_sd_uart_detect(struct amlsd_platform *pdata)
pr_info("normal card in\n");
aml_uart_switch(pdata, 0);
aml_jtag_switch_ao(pdata);
if (host->data->chip_type == MMC_CHIP_G12A)
host->is_sduart = 0;
if (pdata->caps & MMC_CAP_4_BIT_DATA)
mmc->caps |= MMC_CAP_4_BIT_DATA;
}
@@ -882,6 +884,8 @@ int aml_sd_uart_detect(struct amlsd_platform *pdata)
pr_info("card out\n");
pdata->is_tuned = false;
if (host->data->chip_type == MMC_CHIP_G12A)
host->is_sduart = 0;
if (mmc && mmc->card)
mmc_card_set_removed(mmc->card);
aml_uart_switch(pdata, 0);

View File

@@ -470,6 +470,7 @@ struct amlsd_host {
int status; /* host status: xx_error/ok */
int init_flag;
int init_volt;
char *msg_buf;
#define MESSAGE_BUF_SIZE 512