Merge "mmc: msm_sdcc: Add new soft reset mechanism for SDCCv4" into msm-3.4

This commit is contained in:
Linux Build Service Account 2012-07-05 05:22:37 -07:00 committed by QuIC Gerrit Code Review
commit 01786ed978
2 changed files with 147 additions and 61 deletions

View File

@ -162,7 +162,7 @@ static inline unsigned short msmsdcc_get_nr_sg(struct msmsdcc_host *host)
{
unsigned short ret = NR_SG;
if (host->is_sps_mode) {
if (is_sps_mode(host)) {
ret = SPS_MAX_DESCS;
} else { /* DMA or PIO mode */
if (NR_SG > MAX_NR_SG_DMA_PIO)
@ -263,41 +263,89 @@ static void msmsdcc_sps_pipes_reset_and_restore(struct msmsdcc_host *host)
static void msmsdcc_soft_reset(struct msmsdcc_host *host)
{
/*
* Reset SDCC controller's DPSM (data path state machine
* and CPSM (command path state machine).
* Reset controller state machines without resetting
* configuration registers (MCI_POWER, MCI_CLK, MCI_INT_MASKn).
*/
writel_relaxed(0, host->base + MMCICOMMAND);
msmsdcc_sync_reg_wr(host);
writel_relaxed(0, host->base + MMCIDATACTRL);
msmsdcc_sync_reg_wr(host);
if (is_sw_reset_save_config(host)) {
ktime_t start;
writel_relaxed(readl_relaxed(host->base + MMCIPOWER)
| MCI_SW_RST_CFG, host->base + MMCIPOWER);
msmsdcc_sync_reg_wr(host);
start = ktime_get();
while (readl_relaxed(host->base + MMCIPOWER) & MCI_SW_RST_CFG) {
/*
* SW reset can take upto 10HCLK + 15MCLK cycles.
* Calculating based on min clk rates (hclk = 27MHz,
* mclk = 400KHz) it comes to ~40us. Let's poll for
* max. 1ms for reset completion.
*/
if (ktime_to_us(ktime_sub(ktime_get(), start)) > 1000) {
pr_err("%s: %s failed\n",
mmc_hostname(host->mmc), __func__);
BUG();
}
}
} else {
writel_relaxed(0, host->base + MMCICOMMAND);
msmsdcc_sync_reg_wr(host);
writel_relaxed(0, host->base + MMCIDATACTRL);
msmsdcc_sync_reg_wr(host);
}
}
static void msmsdcc_hard_reset(struct msmsdcc_host *host)
{
int ret;
/* Reset the controller */
ret = clk_reset(host->clk, CLK_RESET_ASSERT);
if (ret)
pr_err("%s: Clock assert failed at %u Hz"
" with err %d\n", mmc_hostname(host->mmc),
/*
* Reset SDCC controller to power on default state.
* Don't issue a reset request to clock control block if
* SDCC controller itself can support hard reset.
*/
if (is_sw_hard_reset(host)) {
ktime_t start;
writel_relaxed(readl_relaxed(host->base + MMCIPOWER)
| MCI_SW_RST, host->base + MMCIPOWER);
msmsdcc_sync_reg_wr(host);
start = ktime_get();
while (readl_relaxed(host->base + MMCIPOWER) & MCI_SW_RST) {
/*
* See comment in msmsdcc_soft_reset() on choosing 1ms
* poll timeout.
*/
if (ktime_to_us(ktime_sub(ktime_get(), start)) > 1000) {
pr_err("%s: %s failed\n",
mmc_hostname(host->mmc), __func__);
BUG();
}
}
} else {
ret = clk_reset(host->clk, CLK_RESET_ASSERT);
if (ret)
pr_err("%s: Clock assert failed at %u Hz" \
" with err %d\n", mmc_hostname(host->mmc),
host->clk_rate, ret);
ret = clk_reset(host->clk, CLK_RESET_DEASSERT);
if (ret)
pr_err("%s: Clock deassert failed at %u Hz"
" with err %d\n", mmc_hostname(host->mmc),
host->clk_rate, ret);
ret = clk_reset(host->clk, CLK_RESET_DEASSERT);
if (ret)
pr_err("%s: Clock deassert failed at %u Hz" \
" with err %d\n", mmc_hostname(host->mmc),
host->clk_rate, ret);
mb();
/* Give some delay for clock reset to propogate to controller */
msmsdcc_delay(host);
mb();
/* Give some delay for clock reset to propogate to controller */
msmsdcc_delay(host);
}
}
static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
{
if (host->sdcc_version) {
if (host->is_sps_mode) {
if (is_soft_reset(host)) {
if (is_sps_mode(host)) {
/* Reset DML first */
msmsdcc_dml_reset(host);
/*
@ -313,7 +361,7 @@ static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
pr_debug("%s: Applied soft reset to Controller\n",
mmc_hostname(host->mmc));
if (host->is_sps_mode)
if (is_sps_mode(host))
msmsdcc_dml_init(host);
} else {
/* Give Clock reset (hard reset) to controller */
@ -393,7 +441,7 @@ static inline unsigned int msmsdcc_get_min_sup_clk_rate(
static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host)
{
mb();
if (!host->sdcc_version)
if (!is_wait_for_reg_write(host))
udelay(host->reg_write_delay);
else if (readl_relaxed(host->base + MCI_STATUS2) &
MCI_MCLK_REG_WR_ACTIVE) {
@ -773,14 +821,14 @@ static bool msmsdcc_is_dma_possible(struct msmsdcc_host *host,
bool ret = true;
u32 xfer_size = data->blksz * data->blocks;
if (host->is_sps_mode) {
if (is_sps_mode(host)) {
/*
* BAM Mode: Fall back on PIO if size is less
* than or equal to SPS_MIN_XFER_SIZE bytes.
*/
if (xfer_size <= SPS_MIN_XFER_SIZE)
ret = false;
} else if (host->is_dma_mode) {
} else if (is_dma_mode(host)) {
/*
* ADM Mode: Fall back on PIO if size is less than FIFO size
* or not integer multiple of FIFO size
@ -1125,9 +1173,9 @@ msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
datactrl |= MCI_AUTO_PROG_DONE;
if (msmsdcc_is_dma_possible(host, data)) {
if (host->is_dma_mode && !msmsdcc_config_dma(host, data)) {
if (is_dma_mode(host) && !msmsdcc_config_dma(host, data)) {
datactrl |= MCI_DPSM_DMAENABLE;
} else if (host->is_sps_mode) {
} else if (is_sps_mode(host)) {
if (!msmsdcc_is_dml_busy(host)) {
if (!msmsdcc_sps_start_xfer(host, data)) {
/* Now kick start DML transfer */
@ -1176,7 +1224,7 @@ msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
"%s: data timeout is zero. timeout_ns=0x%x, timeout_clks=0x%x\n",
mmc_hostname(host->mmc), data->timeout_ns, data->timeout_clks);
if (host->is_dma_mode && (datactrl & MCI_DPSM_DMAENABLE)) {
if (is_dma_mode(host) && (datactrl & MCI_DPSM_DMAENABLE)) {
/* Use ADM (Application Data Mover) HW for Data transfer */
/* Save parameters for the dma exec function */
host->cmd_timeout = timeout;
@ -1626,10 +1674,10 @@ static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
if (!cmd->data || cmd->error) {
if (host->curr.data && host->dma.sg &&
host->is_dma_mode)
is_dma_mode(host))
msm_dmov_flush(host->dma.channel, 0);
else if (host->curr.data && host->sps.sg &&
host->is_sps_mode){
is_sps_mode(host)) {
/* Stop current SPS transfer */
msmsdcc_sps_exit_curr_xfer(host);
}
@ -1782,9 +1830,9 @@ msmsdcc_irq(int irq, void *dev_id)
MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
msmsdcc_data_err(host, data, status);
host->curr.data_xfered = 0;
if (host->dma.sg && host->is_dma_mode)
if (host->dma.sg && is_dma_mode(host))
msm_dmov_flush(host->dma.channel, 0);
else if (host->sps.sg && host->is_sps_mode) {
else if (host->sps.sg && is_sps_mode(host)) {
/* Stop current SPS transfer */
msmsdcc_sps_exit_curr_xfer(host);
} else {
@ -1969,7 +2017,7 @@ msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
msmsdcc_sdio_al_lpm(mmc, false);
/* check if sps pipe reset is pending? */
if (host->is_sps_mode && host->sps.pipe_reset_pending) {
if (is_sps_mode(host) && host->sps.pipe_reset_pending) {
msmsdcc_sps_pipes_reset_and_restore(host);
host->sps.pipe_reset_pending = false;
}
@ -2035,7 +2083,7 @@ msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
}
if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
if (host->sdcc_version) {
if (is_auto_prog_done(host)) {
if (!mrq->stop)
host->curr.wait_for_auto_prog_done = true;
} else {
@ -4523,11 +4571,11 @@ static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
if (host->curr.data) {
if (!msmsdcc_is_dma_possible(host, host->curr.data))
pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
else if (host->is_dma_mode)
else if (is_dma_mode(host))
pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
mmc_hostname(host->mmc), host->dma.busy,
host->dma.channel, host->dma.crci);
else if (host->is_sps_mode) {
else if (is_sps_mode(host)) {
if (host->sps.busy && atomic_read(&host->clks_on))
msmsdcc_print_regs("SDCC-DML", host->dml_base,
host->dml_memres->start,
@ -4577,9 +4625,9 @@ static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
if (mrq->data && !mrq->data->error)
mrq->data->error = -ETIMEDOUT;
host->curr.data_xfered = 0;
if (host->dma.sg && host->is_dma_mode) {
if (host->dma.sg && is_dma_mode(host)) {
msm_dmov_flush(host->dma.channel, 0);
} else if (host->sps.sg && host->is_sps_mode) {
} else if (host->sps.sg && is_sps_mode(host)) {
/* Stop current SPS transfer */
msmsdcc_sps_exit_curr_xfer(host);
} else {
@ -4951,9 +4999,9 @@ msmsdcc_probe(struct platform_device *pdev)
host->curr.cmd = NULL;
if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
host->is_sps_mode = 1;
set_hw_caps(host, MSMSDCC_SPS_BAM_SUP);
else if (dmares)
host->is_dma_mode = 1;
set_hw_caps(host, MSMSDCC_DMA_SUP);
host->base = ioremap(core_memres->start,
resource_size(core_memres));
@ -4986,7 +5034,7 @@ msmsdcc_probe(struct platform_device *pdev)
tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
(unsigned long)host);
if (host->is_dma_mode) {
if (is_dma_mode(host)) {
/* Setup DMA */
ret = msmsdcc_init_dma(host);
if (ret)
@ -5045,13 +5093,8 @@ msmsdcc_probe(struct platform_device *pdev)
if (!host->clk_rate)
dev_err(&pdev->dev, "Failed to read MCLK\n");
/*
* Lookup the Controller Version, to identify the supported features
* Version number read as 0 would indicate SDCC3 or earlier versions
*/
host->sdcc_version = readl_relaxed(host->base + MCI_VERSION);
pr_info("%s: mci-version: %x\n", mmc_hostname(host->mmc),
host->sdcc_version);
set_default_hw_caps(host);
/*
* Set the register write delay according to min. clock frequency
* supported and update later when the host->clk_rate changes.
@ -5089,7 +5132,7 @@ msmsdcc_probe(struct platform_device *pdev)
/* Clocks has to be running before accessing SPS/DML HW blocks */
if (host->is_sps_mode) {
if (is_sps_mode(host)) {
/* Initialize SPS */
ret = msmsdcc_sps_init(host);
if (ret)
@ -5122,7 +5165,7 @@ msmsdcc_probe(struct platform_device *pdev)
* status is to use the AUTO_PROG_DONE status provided by SDCC4
* controller. So let's enable the CMD23 for SDCC4 only.
*/
if (!plat->disable_cmd23 && host->sdcc_version)
if (!plat->disable_cmd23 && is_auto_prog_done(host))
mmc->caps |= MMC_CAP_CMD23;
mmc->caps |= plat->uhs_caps;
@ -5297,6 +5340,8 @@ msmsdcc_probe(struct platform_device *pdev)
(unsigned int) plat->status_irq, host->dma.channel,
host->dma.crci);
pr_info("%s: Controller capabilities: 0x%.8x\n",
mmc_hostname(mmc), host->hw_caps);
pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
(mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
@ -5311,14 +5356,14 @@ msmsdcc_probe(struct platform_device *pdev)
pr_info("%s: Power save feature enable = %d\n",
mmc_hostname(mmc), msmsdcc_pwrsave);
if (host->is_dma_mode && host->dma.channel != -1
if (is_dma_mode(host) && host->dma.channel != -1
&& host->dma.crci != -1) {
pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
mmc_hostname(mmc), host->dma.cmd_busaddr,
host->dma.cmdptr_busaddr);
} else if (host->is_sps_mode) {
} else if (is_sps_mode(host)) {
pr_info("%s: SPS-BAM data transfer mode available\n",
mmc_hostname(mmc));
} else
@ -5369,10 +5414,10 @@ msmsdcc_probe(struct platform_device *pdev)
irq_free:
free_irq(core_irqres->start, host);
dml_exit:
if (host->is_sps_mode)
if (is_sps_mode(host))
msmsdcc_dml_exit(host);
sps_exit:
if (host->is_sps_mode)
if (is_sps_mode(host))
msmsdcc_sps_exit(host);
vreg_deinit:
msmsdcc_vreg_init(host, false);
@ -5395,7 +5440,7 @@ msmsdcc_probe(struct platform_device *pdev)
bus_clk_put:
if (!IS_ERR_OR_NULL(host->bus_clk))
clk_put(host->bus_clk);
if (host->is_dma_mode) {
if (is_dma_mode(host)) {
if (host->dmares)
dma_free_coherent(NULL,
sizeof(struct msmsdcc_nc_dmadata),
@ -5464,14 +5509,14 @@ static int msmsdcc_remove(struct platform_device *pdev)
msmsdcc_vreg_init(host, false);
if (host->is_dma_mode) {
if (is_dma_mode(host)) {
if (host->dmares)
dma_free_coherent(NULL,
sizeof(struct msmsdcc_nc_dmadata),
host->dma.nc, host->dma.nc_busaddr);
}
if (host->is_sps_mode) {
if (is_sps_mode(host)) {
msmsdcc_dml_exit(host);
msmsdcc_sps_exit(host);
}

View File

@ -38,6 +38,8 @@
#define MCI_PWR_UP 0x02
#define MCI_PWR_ON 0x03
#define MCI_OD (1 << 6)
#define MCI_SW_RST (1 << 7)
#define MCI_SW_RST_CFG (1 << 8)
#define MMCICLOCK 0x004
#define MCI_CLK_ENABLE (1 << 8)
@ -363,14 +365,12 @@ struct msmsdcc_host {
u32 pwr;
struct mmc_platform_data *plat;
u32 sdcc_version;
unsigned int hw_caps;
unsigned int oldstat;
struct msmsdcc_dma_data dma;
struct msmsdcc_sps_data sps;
bool is_dma_mode;
bool is_sps_mode;
struct msmsdcc_pio_data pio;
#ifdef CONFIG_HAS_EARLYSUSPEND
@ -415,6 +415,47 @@ struct msmsdcc_host {
struct device_attribute polling;
};
#define MSMSDCC_VERSION_MASK 0xFFFF
#define MSMSDCC_DMA_SUP (1 << 0)
#define MSMSDCC_SPS_BAM_SUP (1 << 1)
#define MSMSDCC_SOFT_RESET (1 << 2)
#define MSMSDCC_AUTO_PROG_DONE (1 << 3)
#define MSMSDCC_REG_WR_ACTIVE (1 << 4)
#define MSMSDCC_SW_RST (1 << 5)
#define MSMSDCC_SW_RST_CFG (1 << 6)
#define set_hw_caps(h, val) ((h)->hw_caps |= val)
#define is_sps_mode(h) ((h)->hw_caps & MSMSDCC_SPS_BAM_SUP)
#define is_dma_mode(h) ((h)->hw_caps & MSMSDCC_DMA_SUP)
#define is_soft_reset(h) ((h)->hw_caps & MSMSDCC_SOFT_RESET)
#define is_auto_prog_done(h) ((h)->hw_caps & MSMSDCC_AUTO_PROG_DONE)
#define is_wait_for_reg_write(h) ((h)->hw_caps & MSMSDCC_REG_WR_ACTIVE)
#define is_sw_hard_reset(h) ((h)->hw_caps & MSMSDCC_SW_RST)
#define is_sw_reset_save_config(h) ((h)->hw_caps & MSMSDCC_SW_RST_CFG)
/* Set controller capabilities based on version */
static inline void set_default_hw_caps(struct msmsdcc_host *host)
{
u32 version;
/*
* Lookup the Controller Version, to identify the supported features
* Version number read as 0 would indicate SDCC3 or earlier versions.
*/
version = readl_relaxed(host->base + MCI_VERSION);
pr_info("%s: SDCC Version: 0x%.8x\n", mmc_hostname(host->mmc), version);
if (!version)
return;
version &= MSMSDCC_VERSION_MASK;
if (version) /* SDCC v4 and greater */
host->hw_caps |= MSMSDCC_AUTO_PROG_DONE |
MSMSDCC_SOFT_RESET | MSMSDCC_REG_WR_ACTIVE;
if (version >= 0x2D) /* SDCC v4 2.1.0 and greater */
host->hw_caps |= MSMSDCC_SW_RST | MSMSDCC_SW_RST_CFG;
}
int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave);
int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable);