mirror of https://gitee.com/openkylin/linux.git
mmc: mmci: add busy_complete callback
This patch adds busy_completion callback at mmci_host_ops to allow to define a specific busy completion by variant. The legacy code corresponding to busy completion used by ux500 variants is moved to ux500_busy_complete function. Signed-off-by: Ludovic Barre <ludovic.barre@st.com> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
This commit is contained in:
parent
8266c585f4
commit
cb0335b778
|
@ -44,6 +44,7 @@
|
|||
#define DRIVER_NAME "mmci-pl18x"
|
||||
|
||||
static void mmci_variant_init(struct mmci_host *host);
|
||||
static void ux500_variant_init(struct mmci_host *host);
|
||||
static void ux500v2_variant_init(struct mmci_host *host);
|
||||
|
||||
static unsigned int fmax = 515633;
|
||||
|
@ -184,7 +185,7 @@ static struct variant_data variant_ux500 = {
|
|||
.irq_pio_mask = MCI_IRQ_PIO_MASK,
|
||||
.start_err = MCI_STARTBITERR,
|
||||
.opendrain = MCI_OD,
|
||||
.init = mmci_variant_init,
|
||||
.init = ux500_variant_init,
|
||||
};
|
||||
|
||||
static struct variant_data variant_ux500v2 = {
|
||||
|
@ -610,6 +611,67 @@ static u32 ux500v2_get_dctrl_cfg(struct mmci_host *host)
|
|||
return MCI_DPSM_ENABLE | (host->data->blksz << 16);
|
||||
}
|
||||
|
||||
static bool ux500_busy_complete(struct mmci_host *host, u32 status, u32 err_msk)
|
||||
{
|
||||
void __iomem *base = host->base;
|
||||
|
||||
/*
|
||||
* Before unmasking for the busy end IRQ, confirm that the
|
||||
* command was sent successfully. To keep track of having a
|
||||
* command in-progress, waiting for busy signaling to end,
|
||||
* store the status in host->busy_status.
|
||||
*
|
||||
* Note that, the card may need a couple of clock cycles before
|
||||
* it starts signaling busy on DAT0, hence re-read the
|
||||
* MMCISTATUS register here, to allow the busy bit to be set.
|
||||
* Potentially we may even need to poll the register for a
|
||||
* while, to allow it to be set, but tests indicates that it
|
||||
* isn't needed.
|
||||
*/
|
||||
if (!host->busy_status && !(status & err_msk) &&
|
||||
(readl(base + MMCISTATUS) & host->variant->busy_detect_flag)) {
|
||||
writel(readl(base + MMCIMASK0) |
|
||||
host->variant->busy_detect_mask,
|
||||
base + MMCIMASK0);
|
||||
|
||||
host->busy_status = status & (MCI_CMDSENT | MCI_CMDRESPEND);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* If there is a command in-progress that has been successfully
|
||||
* sent, then bail out if busy status is set and wait for the
|
||||
* busy end IRQ.
|
||||
*
|
||||
* Note that, the HW triggers an IRQ on both edges while
|
||||
* monitoring DAT0 for busy completion, but there is only one
|
||||
* status bit in MMCISTATUS for the busy state. Therefore
|
||||
* both the start and the end interrupts needs to be cleared,
|
||||
* one after the other. So, clear the busy start IRQ here.
|
||||
*/
|
||||
if (host->busy_status &&
|
||||
(status & host->variant->busy_detect_flag)) {
|
||||
writel(host->variant->busy_detect_mask, base + MMCICLEAR);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* If there is a command in-progress that has been successfully
|
||||
* sent and the busy bit isn't set, it means we have received
|
||||
* the busy end IRQ. Clear and mask the IRQ, then continue to
|
||||
* process the command.
|
||||
*/
|
||||
if (host->busy_status) {
|
||||
writel(host->variant->busy_detect_mask, base + MMCICLEAR);
|
||||
|
||||
writel(readl(base + MMCIMASK0) &
|
||||
~host->variant->busy_detect_mask, base + MMCIMASK0);
|
||||
host->busy_status = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* All the DMA operation mode stuff goes inside this ifdef.
|
||||
* This assumes that you have a generic DMA device interface,
|
||||
|
@ -953,9 +1015,16 @@ static void mmci_variant_init(struct mmci_host *host)
|
|||
host->ops = &mmci_variant_ops;
|
||||
}
|
||||
|
||||
static void ux500_variant_init(struct mmci_host *host)
|
||||
{
|
||||
host->ops = &mmci_variant_ops;
|
||||
host->ops->busy_complete = ux500_busy_complete;
|
||||
}
|
||||
|
||||
static void ux500v2_variant_init(struct mmci_host *host)
|
||||
{
|
||||
host->ops = &mmci_variant_ops;
|
||||
host->ops->busy_complete = ux500_busy_complete;
|
||||
host->ops->get_datactrl_cfg = ux500v2_get_dctrl_cfg;
|
||||
}
|
||||
|
||||
|
@ -1235,68 +1304,9 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
|
|||
return;
|
||||
|
||||
/* Handle busy detection on DAT0 if the variant supports it. */
|
||||
if (busy_resp && host->variant->busy_detect) {
|
||||
|
||||
/*
|
||||
* Before unmasking for the busy end IRQ, confirm that the
|
||||
* command was sent successfully. To keep track of having a
|
||||
* command in-progress, waiting for busy signaling to end,
|
||||
* store the status in host->busy_status.
|
||||
*
|
||||
* Note that, the card may need a couple of clock cycles before
|
||||
* it starts signaling busy on DAT0, hence re-read the
|
||||
* MMCISTATUS register here, to allow the busy bit to be set.
|
||||
* Potentially we may even need to poll the register for a
|
||||
* while, to allow it to be set, but tests indicates that it
|
||||
* isn't needed.
|
||||
*/
|
||||
if (!host->busy_status && !(status & err_msk) &&
|
||||
(readl(base + MMCISTATUS) & host->variant->busy_detect_flag)) {
|
||||
|
||||
writel(readl(base + MMCIMASK0) |
|
||||
host->variant->busy_detect_mask,
|
||||
base + MMCIMASK0);
|
||||
|
||||
host->busy_status =
|
||||
status & (MCI_CMDSENT|MCI_CMDRESPEND);
|
||||
if (busy_resp && host->variant->busy_detect)
|
||||
if (!host->ops->busy_complete(host, status, err_msk))
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If there is a command in-progress that has been successfully
|
||||
* sent, then bail out if busy status is set and wait for the
|
||||
* busy end IRQ.
|
||||
*
|
||||
* Note that, the HW triggers an IRQ on both edges while
|
||||
* monitoring DAT0 for busy completion, but there is only one
|
||||
* status bit in MMCISTATUS for the busy state. Therefore
|
||||
* both the start and the end interrupts needs to be cleared,
|
||||
* one after the other. So, clear the busy start IRQ here.
|
||||
*/
|
||||
if (host->busy_status &&
|
||||
(status & host->variant->busy_detect_flag)) {
|
||||
writel(host->variant->busy_detect_mask,
|
||||
host->base + MMCICLEAR);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If there is a command in-progress that has been successfully
|
||||
* sent and the busy bit isn't set, it means we have received
|
||||
* the busy end IRQ. Clear and mask the IRQ, then continue to
|
||||
* process the command.
|
||||
*/
|
||||
if (host->busy_status) {
|
||||
|
||||
writel(host->variant->busy_detect_mask,
|
||||
host->base + MMCICLEAR);
|
||||
|
||||
writel(readl(base + MMCIMASK0) &
|
||||
~host->variant->busy_detect_mask,
|
||||
base + MMCIMASK0);
|
||||
host->busy_status = 0;
|
||||
}
|
||||
}
|
||||
|
||||
host->cmd = NULL;
|
||||
|
||||
|
|
|
@ -369,6 +369,7 @@ struct mmci_host_ops {
|
|||
void (*dma_error)(struct mmci_host *host);
|
||||
void (*set_clkreg)(struct mmci_host *host, unsigned int desired);
|
||||
void (*set_pwrreg)(struct mmci_host *host, unsigned int pwr);
|
||||
bool (*busy_complete)(struct mmci_host *host, u32 status, u32 err_msk);
|
||||
};
|
||||
|
||||
struct mmci_host {
|
||||
|
|
Loading…
Reference in New Issue