mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 02:50:49 +09:00
Merge tag 'mmc-v6.1' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc
Pull MMC updates from Ulf Hansson:
- dt-bindings: Increase maximum supported frequency to 384MHz
- dw_mmc-rockchip: Add support for the rk3128 variant
- meson-gx: Add support for SDIO interrupts
- mtk-sd: Add support for MT6795 Helio X10 variant
- sdhci: Improve the code by centralizing the CMD/DATA reset handling
- sdhci-msm:
- Add support for the sdm670 variant
- Add support for the sm6115 variant
- sdhci-omap: Make Vignesh replace Kishon as the maintainer
- sdhci-pci-o2micro: Disable fragile support for DDR50 in favor of
SDR50
- sdhci-sprd: Fix clock divider limitation
* tag 'mmc-v6.1' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (31 commits)
mmc: sdhci: Centralize CMD and DATA reset handling
mmc: sdhci: Get rid of SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS
mmc: sdhci: Remove misleading comment about resets
mmc: sdhci: Separate out sdhci_reset_for_all()
MAINTAINERS: Add Vignesh as maintainer of TI SDHCI OMAP DRIVER
mmc: sdhci-msm: add compatible string check for sdm670
dt-bindings: mmc: sdhci-msm: add sdm670 compatible
mmc: wmt-sdmmc: Fix an error handling path in wmt_mci_probe()
mmc: rtsx_usb_sdmmc: Remove the unneeded result variable
mmc: sdhci-of-aspeed: Add dependency on ARCH_ASPEED
mmc: mtk-sd: Add support for MT6795 Helio X10
mmc: mtk-sd: Reorder of_device_id and platform data by name
mmc: sdhci-sprd: Fix the limitation of div
dt-bindings: mmc: sdhci-msm: Add pinctrl-1 property
dt-bindings: mmc: rockchip: add rockchip,rk3128-dw-mshc
dt-bindings: mmc: renesas,sdhi: Add iommus property
mmc: sdhci_am654: Remove the unneeded result variable
mmc: meson-gx: add SDIO interrupt support
mmc: meson-gx: adjust and re-use constant IRQ_EN_MASK
mmc: jz4740_mmc: Fix error check for dma_map_sg
...
This commit is contained in:
@@ -8,7 +8,6 @@ title: Cadence SD/SDIO/eMMC Host Controller (SD4HC)
|
|||||||
|
|
||||||
maintainers:
|
maintainers:
|
||||||
- Masahiro Yamada <yamada.masahiro@socionext.com>
|
- Masahiro Yamada <yamada.masahiro@socionext.com>
|
||||||
- Piotr Sroka <piotrs@cadence.com>
|
|
||||||
|
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: mmc-controller.yaml
|
- $ref: mmc-controller.yaml
|
||||||
|
|||||||
@@ -88,11 +88,18 @@ properties:
|
|||||||
default: 1
|
default: 1
|
||||||
|
|
||||||
max-frequency:
|
max-frequency:
|
||||||
description:
|
description: |
|
||||||
Maximum operating frequency of the bus.
|
Maximum operating frequency of the bus:
|
||||||
|
- for eMMC, the maximum supported frequency is 200MHz,
|
||||||
|
- for SD/SDIO cards the SDR104 mode has a max supported
|
||||||
|
frequency of 208MHz,
|
||||||
|
- some mmc host controllers do support a max frequency upto
|
||||||
|
384MHz.
|
||||||
|
So, lets keep the maximum supported value here.
|
||||||
|
|
||||||
$ref: /schemas/types.yaml#/definitions/uint32
|
$ref: /schemas/types.yaml#/definitions/uint32
|
||||||
minimum: 400000
|
minimum: 400000
|
||||||
maximum: 200000000
|
maximum: 384000000
|
||||||
|
|
||||||
disable-wp:
|
disable-wp:
|
||||||
$ref: /schemas/types.yaml#/definitions/flag
|
$ref: /schemas/types.yaml#/definitions/flag
|
||||||
|
|||||||
@@ -23,8 +23,6 @@ properties:
|
|||||||
reg:
|
reg:
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
|
|
||||||
spi-max-frequency: true
|
|
||||||
|
|
||||||
interrupts:
|
interrupts:
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ properties:
|
|||||||
- mediatek,mt2701-mmc
|
- mediatek,mt2701-mmc
|
||||||
- mediatek,mt2712-mmc
|
- mediatek,mt2712-mmc
|
||||||
- mediatek,mt6779-mmc
|
- mediatek,mt6779-mmc
|
||||||
|
- mediatek,mt6795-mmc
|
||||||
- mediatek,mt7620-mmc
|
- mediatek,mt7620-mmc
|
||||||
- mediatek,mt7622-mmc
|
- mediatek,mt7622-mmc
|
||||||
- mediatek,mt8135-mmc
|
- mediatek,mt8135-mmc
|
||||||
|
|||||||
@@ -89,6 +89,9 @@ properties:
|
|||||||
- tx
|
- tx
|
||||||
- rx
|
- rx
|
||||||
|
|
||||||
|
iommus:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
power-domains:
|
power-domains:
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ properties:
|
|||||||
- rockchip,px30-dw-mshc
|
- rockchip,px30-dw-mshc
|
||||||
- rockchip,rk1808-dw-mshc
|
- rockchip,rk1808-dw-mshc
|
||||||
- rockchip,rk3036-dw-mshc
|
- rockchip,rk3036-dw-mshc
|
||||||
|
- rockchip,rk3128-dw-mshc
|
||||||
- rockchip,rk3228-dw-mshc
|
- rockchip,rk3228-dw-mshc
|
||||||
- rockchip,rk3308-dw-mshc
|
- rockchip,rk3308-dw-mshc
|
||||||
- rockchip,rk3328-dw-mshc
|
- rockchip,rk3328-dw-mshc
|
||||||
|
|||||||
@@ -51,6 +51,9 @@ properties:
|
|||||||
|
|
||||||
sdhci-caps-mask: true
|
sdhci-caps-mask: true
|
||||||
|
|
||||||
|
dma-coherent:
|
||||||
|
type: boolean
|
||||||
|
|
||||||
# PHY output tap delays:
|
# PHY output tap delays:
|
||||||
# Used to delay the data valid window and align it to the sampling clock.
|
# Used to delay the data valid window and align it to the sampling clock.
|
||||||
# Binding needs to be provided for each supported speed mode otherwise the
|
# Binding needs to be provided for each supported speed mode otherwise the
|
||||||
|
|||||||
@@ -38,9 +38,11 @@ properties:
|
|||||||
- qcom,sc7180-sdhci
|
- qcom,sc7180-sdhci
|
||||||
- qcom,sc7280-sdhci
|
- qcom,sc7280-sdhci
|
||||||
- qcom,sdm630-sdhci
|
- qcom,sdm630-sdhci
|
||||||
|
- qcom,sdm670-sdhci
|
||||||
- qcom,sdm845-sdhci
|
- qcom,sdm845-sdhci
|
||||||
- qcom,sdx55-sdhci
|
- qcom,sdx55-sdhci
|
||||||
- qcom,sdx65-sdhci
|
- qcom,sdx65-sdhci
|
||||||
|
- qcom,sm6115-sdhci
|
||||||
- qcom,sm6125-sdhci
|
- qcom,sm6125-sdhci
|
||||||
- qcom,sm6350-sdhci
|
- qcom,sm6350-sdhci
|
||||||
- qcom,sm8150-sdhci
|
- qcom,sm8150-sdhci
|
||||||
@@ -96,6 +98,10 @@ properties:
|
|||||||
description:
|
description:
|
||||||
Should specify pin control groups used for this controller.
|
Should specify pin control groups used for this controller.
|
||||||
|
|
||||||
|
pinctrl-1:
|
||||||
|
description:
|
||||||
|
Should specify sleep pin control groups used for this controller.
|
||||||
|
|
||||||
resets:
|
resets:
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
|
|
||||||
|
|||||||
@@ -7536,7 +7536,7 @@ M: Adrian Hunter <adrian.hunter@intel.com>
|
|||||||
M: Ritesh Harjani <riteshh@codeaurora.org>
|
M: Ritesh Harjani <riteshh@codeaurora.org>
|
||||||
M: Asutosh Das <asutoshd@codeaurora.org>
|
M: Asutosh Das <asutoshd@codeaurora.org>
|
||||||
L: linux-mmc@vger.kernel.org
|
L: linux-mmc@vger.kernel.org
|
||||||
S: Maintained
|
S: Supported
|
||||||
F: drivers/mmc/host/cqhci*
|
F: drivers/mmc/host/cqhci*
|
||||||
|
|
||||||
EMULEX 10Gbps iSCSI - OneConnect DRIVER
|
EMULEX 10Gbps iSCSI - OneConnect DRIVER
|
||||||
@@ -18316,7 +18316,7 @@ F: drivers/mmc/host/sdhci-brcmstb*
|
|||||||
SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) DRIVER
|
SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) DRIVER
|
||||||
M: Adrian Hunter <adrian.hunter@intel.com>
|
M: Adrian Hunter <adrian.hunter@intel.com>
|
||||||
L: linux-mmc@vger.kernel.org
|
L: linux-mmc@vger.kernel.org
|
||||||
S: Maintained
|
S: Supported
|
||||||
F: drivers/mmc/host/sdhci*
|
F: drivers/mmc/host/sdhci*
|
||||||
|
|
||||||
SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) MICROCHIP DRIVER
|
SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) MICROCHIP DRIVER
|
||||||
@@ -18339,7 +18339,7 @@ S: Maintained
|
|||||||
F: drivers/mmc/host/sdhci-spear.c
|
F: drivers/mmc/host/sdhci-spear.c
|
||||||
|
|
||||||
SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) TI OMAP DRIVER
|
SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) TI OMAP DRIVER
|
||||||
M: Kishon Vijay Abraham I <kishon@ti.com>
|
M: Vignesh Raghavendra <vigneshr@ti.com>
|
||||||
L: linux-mmc@vger.kernel.org
|
L: linux-mmc@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: drivers/mmc/host/sdhci-omap.c
|
F: drivers/mmc/host/sdhci-omap.c
|
||||||
|
|||||||
@@ -565,7 +565,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
|
|||||||
spin_lock_init(&host->lock);
|
spin_lock_init(&host->lock);
|
||||||
init_waitqueue_head(&host->wq);
|
init_waitqueue_head(&host->wq);
|
||||||
INIT_DELAYED_WORK(&host->detect, mmc_rescan);
|
INIT_DELAYED_WORK(&host->detect, mmc_rescan);
|
||||||
INIT_DELAYED_WORK(&host->sdio_irq_work, sdio_irq_work);
|
INIT_WORK(&host->sdio_irq_work, sdio_irq_work);
|
||||||
timer_setup(&host->retune_timer, mmc_retune_timer, 0);
|
timer_setup(&host->retune_timer, mmc_retune_timer, 0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -1043,7 +1043,7 @@ static int mmc_sdio_suspend(struct mmc_host *host)
|
|||||||
|
|
||||||
/* Prevent processing of SDIO IRQs in suspended state. */
|
/* Prevent processing of SDIO IRQs in suspended state. */
|
||||||
mmc_card_set_suspended(host->card);
|
mmc_card_set_suspended(host->card);
|
||||||
cancel_delayed_work_sync(&host->sdio_irq_work);
|
cancel_work_sync(&host->sdio_irq_work);
|
||||||
|
|
||||||
mmc_claim_host(host);
|
mmc_claim_host(host);
|
||||||
|
|
||||||
@@ -1103,7 +1103,7 @@ static int mmc_sdio_resume(struct mmc_host *host)
|
|||||||
if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD))
|
if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD))
|
||||||
wake_up_process(host->sdio_irq_thread);
|
wake_up_process(host->sdio_irq_thread);
|
||||||
else if (host->caps & MMC_CAP_SDIO_IRQ)
|
else if (host->caps & MMC_CAP_SDIO_IRQ)
|
||||||
queue_delayed_work(system_wq, &host->sdio_irq_work, 0);
|
schedule_work(&host->sdio_irq_work);
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ static void sdio_run_irqs(struct mmc_host *host)
|
|||||||
void sdio_irq_work(struct work_struct *work)
|
void sdio_irq_work(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct mmc_host *host =
|
struct mmc_host *host =
|
||||||
container_of(work, struct mmc_host, sdio_irq_work.work);
|
container_of(work, struct mmc_host, sdio_irq_work);
|
||||||
|
|
||||||
sdio_run_irqs(host);
|
sdio_run_irqs(host);
|
||||||
}
|
}
|
||||||
@@ -132,7 +132,7 @@ void sdio_irq_work(struct work_struct *work)
|
|||||||
void sdio_signal_irq(struct mmc_host *host)
|
void sdio_signal_irq(struct mmc_host *host)
|
||||||
{
|
{
|
||||||
host->sdio_irq_pending = true;
|
host->sdio_irq_pending = true;
|
||||||
queue_delayed_work(system_wq, &host->sdio_irq_work, 0);
|
schedule_work(&host->sdio_irq_work);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(sdio_signal_irq);
|
EXPORT_SYMBOL_GPL(sdio_signal_irq);
|
||||||
|
|
||||||
|
|||||||
@@ -157,6 +157,7 @@ config MMC_SDHCI_OF_ARASAN
|
|||||||
|
|
||||||
config MMC_SDHCI_OF_ASPEED
|
config MMC_SDHCI_OF_ASPEED
|
||||||
tristate "SDHCI OF support for the ASPEED SDHCI controller"
|
tristate "SDHCI OF support for the ASPEED SDHCI controller"
|
||||||
|
depends on ARCH_ASPEED || COMPILE_TEST
|
||||||
depends on MMC_SDHCI_PLTFM
|
depends on MMC_SDHCI_PLTFM
|
||||||
depends on OF && OF_ADDRESS
|
depends on OF && OF_ADDRESS
|
||||||
select MMC_SDHCI_IO_ACCESSORS
|
select MMC_SDHCI_IO_ACCESSORS
|
||||||
|
|||||||
@@ -1097,8 +1097,9 @@ out5:
|
|||||||
if (host->platdata && host->platdata->cd_setup &&
|
if (host->platdata && host->platdata->cd_setup &&
|
||||||
!(mmc->caps & MMC_CAP_NEEDS_POLL))
|
!(mmc->caps & MMC_CAP_NEEDS_POLL))
|
||||||
host->platdata->cd_setup(mmc, 0);
|
host->platdata->cd_setup(mmc, 0);
|
||||||
out_clk:
|
|
||||||
clk_disable_unprepare(host->clk);
|
clk_disable_unprepare(host->clk);
|
||||||
|
out_clk:
|
||||||
clk_put(host->clk);
|
clk_put(host->clk);
|
||||||
out_irq:
|
out_irq:
|
||||||
free_irq(host->irq, host);
|
free_irq(host->irq, host);
|
||||||
|
|||||||
@@ -298,7 +298,7 @@ static int jz4740_mmc_prepare_dma_data(struct jz4740_mmc_host *host,
|
|||||||
{
|
{
|
||||||
struct dma_chan *chan = jz4740_mmc_get_dma_chan(host, data);
|
struct dma_chan *chan = jz4740_mmc_get_dma_chan(host, data);
|
||||||
enum dma_data_direction dir = mmc_get_dma_dir(data);
|
enum dma_data_direction dir = mmc_get_dma_dir(data);
|
||||||
int sg_count;
|
unsigned int sg_count;
|
||||||
|
|
||||||
if (data->host_cookie == COOKIE_PREMAPPED)
|
if (data->host_cookie == COOKIE_PREMAPPED)
|
||||||
return data->sg_count;
|
return data->sg_count;
|
||||||
@@ -308,7 +308,7 @@ static int jz4740_mmc_prepare_dma_data(struct jz4740_mmc_host *host,
|
|||||||
data->sg_len,
|
data->sg_len,
|
||||||
dir);
|
dir);
|
||||||
|
|
||||||
if (sg_count <= 0) {
|
if (!sg_count) {
|
||||||
dev_err(mmc_dev(host->mmc),
|
dev_err(mmc_dev(host->mmc),
|
||||||
"Failed to map scatterlist for DMA operation\n");
|
"Failed to map scatterlist for DMA operation\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|||||||
@@ -41,14 +41,17 @@
|
|||||||
#define CLK_V2_TX_DELAY_MASK GENMASK(19, 16)
|
#define CLK_V2_TX_DELAY_MASK GENMASK(19, 16)
|
||||||
#define CLK_V2_RX_DELAY_MASK GENMASK(23, 20)
|
#define CLK_V2_RX_DELAY_MASK GENMASK(23, 20)
|
||||||
#define CLK_V2_ALWAYS_ON BIT(24)
|
#define CLK_V2_ALWAYS_ON BIT(24)
|
||||||
|
#define CLK_V2_IRQ_SDIO_SLEEP BIT(25)
|
||||||
|
|
||||||
#define CLK_V3_TX_DELAY_MASK GENMASK(21, 16)
|
#define CLK_V3_TX_DELAY_MASK GENMASK(21, 16)
|
||||||
#define CLK_V3_RX_DELAY_MASK GENMASK(27, 22)
|
#define CLK_V3_RX_DELAY_MASK GENMASK(27, 22)
|
||||||
#define CLK_V3_ALWAYS_ON BIT(28)
|
#define CLK_V3_ALWAYS_ON BIT(28)
|
||||||
|
#define CLK_V3_IRQ_SDIO_SLEEP BIT(29)
|
||||||
|
|
||||||
#define CLK_TX_DELAY_MASK(h) (h->data->tx_delay_mask)
|
#define CLK_TX_DELAY_MASK(h) (h->data->tx_delay_mask)
|
||||||
#define CLK_RX_DELAY_MASK(h) (h->data->rx_delay_mask)
|
#define CLK_RX_DELAY_MASK(h) (h->data->rx_delay_mask)
|
||||||
#define CLK_ALWAYS_ON(h) (h->data->always_on)
|
#define CLK_ALWAYS_ON(h) (h->data->always_on)
|
||||||
|
#define CLK_IRQ_SDIO_SLEEP(h) (h->data->irq_sdio_sleep)
|
||||||
|
|
||||||
#define SD_EMMC_DELAY 0x4
|
#define SD_EMMC_DELAY 0x4
|
||||||
#define SD_EMMC_ADJUST 0x8
|
#define SD_EMMC_ADJUST 0x8
|
||||||
@@ -101,8 +104,7 @@
|
|||||||
#define IRQ_RESP_STATUS BIT(14)
|
#define IRQ_RESP_STATUS BIT(14)
|
||||||
#define IRQ_SDIO BIT(15)
|
#define IRQ_SDIO BIT(15)
|
||||||
#define IRQ_EN_MASK \
|
#define IRQ_EN_MASK \
|
||||||
(IRQ_CRC_ERR | IRQ_TIMEOUTS | IRQ_END_OF_CHAIN | IRQ_RESP_STATUS |\
|
(IRQ_CRC_ERR | IRQ_TIMEOUTS | IRQ_END_OF_CHAIN)
|
||||||
IRQ_SDIO)
|
|
||||||
|
|
||||||
#define SD_EMMC_CMD_CFG 0x50
|
#define SD_EMMC_CMD_CFG 0x50
|
||||||
#define SD_EMMC_CMD_ARG 0x54
|
#define SD_EMMC_CMD_ARG 0x54
|
||||||
@@ -136,6 +138,7 @@ struct meson_mmc_data {
|
|||||||
unsigned int rx_delay_mask;
|
unsigned int rx_delay_mask;
|
||||||
unsigned int always_on;
|
unsigned int always_on;
|
||||||
unsigned int adjust;
|
unsigned int adjust;
|
||||||
|
unsigned int irq_sdio_sleep;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sd_emmc_desc {
|
struct sd_emmc_desc {
|
||||||
@@ -175,6 +178,7 @@ struct meson_host {
|
|||||||
bool vqmmc_enabled;
|
bool vqmmc_enabled;
|
||||||
bool needs_pre_post_req;
|
bool needs_pre_post_req;
|
||||||
|
|
||||||
|
spinlock_t lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define CMD_CFG_LENGTH_MASK GENMASK(8, 0)
|
#define CMD_CFG_LENGTH_MASK GENMASK(8, 0)
|
||||||
@@ -431,6 +435,7 @@ static int meson_mmc_clk_init(struct meson_host *host)
|
|||||||
clk_reg |= FIELD_PREP(CLK_CORE_PHASE_MASK, CLK_PHASE_180);
|
clk_reg |= FIELD_PREP(CLK_CORE_PHASE_MASK, CLK_PHASE_180);
|
||||||
clk_reg |= FIELD_PREP(CLK_TX_PHASE_MASK, CLK_PHASE_0);
|
clk_reg |= FIELD_PREP(CLK_TX_PHASE_MASK, CLK_PHASE_0);
|
||||||
clk_reg |= FIELD_PREP(CLK_RX_PHASE_MASK, CLK_PHASE_0);
|
clk_reg |= FIELD_PREP(CLK_RX_PHASE_MASK, CLK_PHASE_0);
|
||||||
|
clk_reg |= CLK_IRQ_SDIO_SLEEP(host);
|
||||||
writel(clk_reg, host->regs + SD_EMMC_CLOCK);
|
writel(clk_reg, host->regs + SD_EMMC_CLOCK);
|
||||||
|
|
||||||
/* get the mux parents */
|
/* get the mux parents */
|
||||||
@@ -929,33 +934,54 @@ static void meson_mmc_read_resp(struct mmc_host *mmc, struct mmc_command *cmd)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void __meson_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
|
||||||
|
{
|
||||||
|
struct meson_host *host = mmc_priv(mmc);
|
||||||
|
u32 reg_irqen = IRQ_EN_MASK;
|
||||||
|
|
||||||
|
if (enable)
|
||||||
|
reg_irqen |= IRQ_SDIO;
|
||||||
|
writel(reg_irqen, host->regs + SD_EMMC_IRQ_EN);
|
||||||
|
}
|
||||||
|
|
||||||
static irqreturn_t meson_mmc_irq(int irq, void *dev_id)
|
static irqreturn_t meson_mmc_irq(int irq, void *dev_id)
|
||||||
{
|
{
|
||||||
struct meson_host *host = dev_id;
|
struct meson_host *host = dev_id;
|
||||||
struct mmc_command *cmd;
|
struct mmc_command *cmd;
|
||||||
struct mmc_data *data;
|
u32 status, raw_status;
|
||||||
u32 irq_en, status, raw_status;
|
|
||||||
irqreturn_t ret = IRQ_NONE;
|
irqreturn_t ret = IRQ_NONE;
|
||||||
|
|
||||||
irq_en = readl(host->regs + SD_EMMC_IRQ_EN);
|
|
||||||
raw_status = readl(host->regs + SD_EMMC_STATUS);
|
raw_status = readl(host->regs + SD_EMMC_STATUS);
|
||||||
status = raw_status & irq_en;
|
status = raw_status & (IRQ_EN_MASK | IRQ_SDIO);
|
||||||
|
|
||||||
if (!status) {
|
if (!status) {
|
||||||
dev_dbg(host->dev,
|
dev_dbg(host->dev,
|
||||||
"Unexpected IRQ! irq_en 0x%08x - status 0x%08x\n",
|
"Unexpected IRQ! irq_en 0x%08lx - status 0x%08x\n",
|
||||||
irq_en, raw_status);
|
IRQ_EN_MASK | IRQ_SDIO, raw_status);
|
||||||
return IRQ_NONE;
|
return IRQ_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WARN_ON(!host) || WARN_ON(!host->cmd))
|
if (WARN_ON(!host))
|
||||||
return IRQ_NONE;
|
return IRQ_NONE;
|
||||||
|
|
||||||
/* ack all raised interrupts */
|
/* ack all raised interrupts */
|
||||||
writel(status, host->regs + SD_EMMC_STATUS);
|
writel(status, host->regs + SD_EMMC_STATUS);
|
||||||
|
|
||||||
cmd = host->cmd;
|
cmd = host->cmd;
|
||||||
data = cmd->data;
|
|
||||||
|
if (status & IRQ_SDIO) {
|
||||||
|
spin_lock(&host->lock);
|
||||||
|
__meson_mmc_enable_sdio_irq(host->mmc, 0);
|
||||||
|
sdio_signal_irq(host->mmc);
|
||||||
|
spin_unlock(&host->lock);
|
||||||
|
status &= ~IRQ_SDIO;
|
||||||
|
if (!status)
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WARN_ON(!cmd))
|
||||||
|
return IRQ_NONE;
|
||||||
|
|
||||||
cmd->error = 0;
|
cmd->error = 0;
|
||||||
if (status & IRQ_CRC_ERR) {
|
if (status & IRQ_CRC_ERR) {
|
||||||
dev_dbg(host->dev, "CRC Error - status 0x%08x\n", status);
|
dev_dbg(host->dev, "CRC Error - status 0x%08x\n", status);
|
||||||
@@ -973,12 +999,9 @@ static irqreturn_t meson_mmc_irq(int irq, void *dev_id)
|
|||||||
|
|
||||||
meson_mmc_read_resp(host->mmc, cmd);
|
meson_mmc_read_resp(host->mmc, cmd);
|
||||||
|
|
||||||
if (status & IRQ_SDIO) {
|
|
||||||
dev_dbg(host->dev, "IRQ: SDIO TODO.\n");
|
|
||||||
ret = IRQ_HANDLED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status & (IRQ_END_OF_CHAIN | IRQ_RESP_STATUS)) {
|
if (status & (IRQ_END_OF_CHAIN | IRQ_RESP_STATUS)) {
|
||||||
|
struct mmc_data *data = cmd->data;
|
||||||
|
|
||||||
if (data && !cmd->error)
|
if (data && !cmd->error)
|
||||||
data->bytes_xfered = data->blksz * data->blocks;
|
data->bytes_xfered = data->blksz * data->blocks;
|
||||||
if (meson_mmc_bounce_buf_read(data) ||
|
if (meson_mmc_bounce_buf_read(data) ||
|
||||||
@@ -1121,6 +1144,21 @@ static int meson_mmc_voltage_switch(struct mmc_host *mmc, struct mmc_ios *ios)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void meson_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
|
||||||
|
{
|
||||||
|
struct meson_host *host = mmc_priv(mmc);
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&host->lock, flags);
|
||||||
|
__meson_mmc_enable_sdio_irq(mmc, enable);
|
||||||
|
spin_unlock_irqrestore(&host->lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void meson_mmc_ack_sdio_irq(struct mmc_host *mmc)
|
||||||
|
{
|
||||||
|
meson_mmc_enable_sdio_irq(mmc, 1);
|
||||||
|
}
|
||||||
|
|
||||||
static const struct mmc_host_ops meson_mmc_ops = {
|
static const struct mmc_host_ops meson_mmc_ops = {
|
||||||
.request = meson_mmc_request,
|
.request = meson_mmc_request,
|
||||||
.set_ios = meson_mmc_set_ios,
|
.set_ios = meson_mmc_set_ios,
|
||||||
@@ -1130,6 +1168,8 @@ static const struct mmc_host_ops meson_mmc_ops = {
|
|||||||
.execute_tuning = meson_mmc_resampling_tuning,
|
.execute_tuning = meson_mmc_resampling_tuning,
|
||||||
.card_busy = meson_mmc_card_busy,
|
.card_busy = meson_mmc_card_busy,
|
||||||
.start_signal_voltage_switch = meson_mmc_voltage_switch,
|
.start_signal_voltage_switch = meson_mmc_voltage_switch,
|
||||||
|
.enable_sdio_irq = meson_mmc_enable_sdio_irq,
|
||||||
|
.ack_sdio_irq = meson_mmc_ack_sdio_irq,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int meson_mmc_probe(struct platform_device *pdev)
|
static int meson_mmc_probe(struct platform_device *pdev)
|
||||||
@@ -1226,10 +1266,8 @@ static int meson_mmc_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
/* clear, ack and enable interrupts */
|
/* clear, ack and enable interrupts */
|
||||||
writel(0, host->regs + SD_EMMC_IRQ_EN);
|
writel(0, host->regs + SD_EMMC_IRQ_EN);
|
||||||
writel(IRQ_CRC_ERR | IRQ_TIMEOUTS | IRQ_END_OF_CHAIN,
|
writel(IRQ_EN_MASK, host->regs + SD_EMMC_STATUS);
|
||||||
host->regs + SD_EMMC_STATUS);
|
writel(IRQ_EN_MASK, host->regs + SD_EMMC_IRQ_EN);
|
||||||
writel(IRQ_CRC_ERR | IRQ_TIMEOUTS | IRQ_END_OF_CHAIN,
|
|
||||||
host->regs + SD_EMMC_IRQ_EN);
|
|
||||||
|
|
||||||
ret = request_threaded_irq(host->irq, meson_mmc_irq,
|
ret = request_threaded_irq(host->irq, meson_mmc_irq,
|
||||||
meson_mmc_irq_thread, IRQF_ONESHOT,
|
meson_mmc_irq_thread, IRQF_ONESHOT,
|
||||||
@@ -1237,7 +1275,13 @@ static int meson_mmc_probe(struct platform_device *pdev)
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto err_init_clk;
|
goto err_init_clk;
|
||||||
|
|
||||||
|
spin_lock_init(&host->lock);
|
||||||
|
|
||||||
mmc->caps |= MMC_CAP_CMD23;
|
mmc->caps |= MMC_CAP_CMD23;
|
||||||
|
|
||||||
|
if (mmc->caps & MMC_CAP_SDIO_IRQ)
|
||||||
|
mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD;
|
||||||
|
|
||||||
if (host->dram_access_quirk) {
|
if (host->dram_access_quirk) {
|
||||||
/* Limit segments to 1 due to low available sram memory */
|
/* Limit segments to 1 due to low available sram memory */
|
||||||
mmc->max_segs = 1;
|
mmc->max_segs = 1;
|
||||||
@@ -1328,6 +1372,7 @@ static const struct meson_mmc_data meson_gx_data = {
|
|||||||
.rx_delay_mask = CLK_V2_RX_DELAY_MASK,
|
.rx_delay_mask = CLK_V2_RX_DELAY_MASK,
|
||||||
.always_on = CLK_V2_ALWAYS_ON,
|
.always_on = CLK_V2_ALWAYS_ON,
|
||||||
.adjust = SD_EMMC_ADJUST,
|
.adjust = SD_EMMC_ADJUST,
|
||||||
|
.irq_sdio_sleep = CLK_V2_IRQ_SDIO_SLEEP,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct meson_mmc_data meson_axg_data = {
|
static const struct meson_mmc_data meson_axg_data = {
|
||||||
@@ -1335,6 +1380,7 @@ static const struct meson_mmc_data meson_axg_data = {
|
|||||||
.rx_delay_mask = CLK_V3_RX_DELAY_MASK,
|
.rx_delay_mask = CLK_V3_RX_DELAY_MASK,
|
||||||
.always_on = CLK_V3_ALWAYS_ON,
|
.always_on = CLK_V3_ALWAYS_ON,
|
||||||
.adjust = SD_EMMC_V3_ADJUST,
|
.adjust = SD_EMMC_V3_ADJUST,
|
||||||
|
.irq_sdio_sleep = CLK_V3_IRQ_SDIO_SLEEP,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct of_device_id meson_mmc_of_match[] = {
|
static const struct of_device_id meson_mmc_of_match[] = {
|
||||||
|
|||||||
@@ -381,14 +381,14 @@ static void meson_mx_sdhc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
|||||||
static int meson_mx_sdhc_map_dma(struct mmc_host *mmc, struct mmc_request *mrq)
|
static int meson_mx_sdhc_map_dma(struct mmc_host *mmc, struct mmc_request *mrq)
|
||||||
{
|
{
|
||||||
struct mmc_data *data = mrq->data;
|
struct mmc_data *data = mrq->data;
|
||||||
int dma_len;
|
unsigned int dma_len;
|
||||||
|
|
||||||
if (!data)
|
if (!data)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
dma_len = dma_map_sg(mmc_dev(mmc), data->sg, data->sg_len,
|
dma_len = dma_map_sg(mmc_dev(mmc), data->sg, data->sg_len,
|
||||||
mmc_get_dma_dir(data));
|
mmc_get_dma_dir(data));
|
||||||
if (dma_len <= 0) {
|
if (!dma_len) {
|
||||||
dev_err(mmc_dev(mmc), "dma_map_sg failed\n");
|
dev_err(mmc_dev(mmc), "dma_map_sg failed\n");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -474,6 +474,84 @@ struct msdc_host {
|
|||||||
struct cqhci_host *cq_host;
|
struct cqhci_host *cq_host;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct mtk_mmc_compatible mt2701_compat = {
|
||||||
|
.clk_div_bits = 12,
|
||||||
|
.recheck_sdio_irq = true,
|
||||||
|
.hs400_tune = false,
|
||||||
|
.pad_tune_reg = MSDC_PAD_TUNE0,
|
||||||
|
.async_fifo = true,
|
||||||
|
.data_tune = true,
|
||||||
|
.busy_check = false,
|
||||||
|
.stop_clk_fix = false,
|
||||||
|
.enhance_rx = false,
|
||||||
|
.support_64g = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct mtk_mmc_compatible mt2712_compat = {
|
||||||
|
.clk_div_bits = 12,
|
||||||
|
.recheck_sdio_irq = false,
|
||||||
|
.hs400_tune = false,
|
||||||
|
.pad_tune_reg = MSDC_PAD_TUNE0,
|
||||||
|
.async_fifo = true,
|
||||||
|
.data_tune = true,
|
||||||
|
.busy_check = true,
|
||||||
|
.stop_clk_fix = true,
|
||||||
|
.enhance_rx = true,
|
||||||
|
.support_64g = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct mtk_mmc_compatible mt6779_compat = {
|
||||||
|
.clk_div_bits = 12,
|
||||||
|
.recheck_sdio_irq = false,
|
||||||
|
.hs400_tune = false,
|
||||||
|
.pad_tune_reg = MSDC_PAD_TUNE0,
|
||||||
|
.async_fifo = true,
|
||||||
|
.data_tune = true,
|
||||||
|
.busy_check = true,
|
||||||
|
.stop_clk_fix = true,
|
||||||
|
.enhance_rx = true,
|
||||||
|
.support_64g = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct mtk_mmc_compatible mt6795_compat = {
|
||||||
|
.clk_div_bits = 8,
|
||||||
|
.recheck_sdio_irq = false,
|
||||||
|
.hs400_tune = true,
|
||||||
|
.pad_tune_reg = MSDC_PAD_TUNE,
|
||||||
|
.async_fifo = false,
|
||||||
|
.data_tune = false,
|
||||||
|
.busy_check = false,
|
||||||
|
.stop_clk_fix = false,
|
||||||
|
.enhance_rx = false,
|
||||||
|
.support_64g = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct mtk_mmc_compatible mt7620_compat = {
|
||||||
|
.clk_div_bits = 8,
|
||||||
|
.recheck_sdio_irq = true,
|
||||||
|
.hs400_tune = false,
|
||||||
|
.pad_tune_reg = MSDC_PAD_TUNE,
|
||||||
|
.async_fifo = false,
|
||||||
|
.data_tune = false,
|
||||||
|
.busy_check = false,
|
||||||
|
.stop_clk_fix = false,
|
||||||
|
.enhance_rx = false,
|
||||||
|
.use_internal_cd = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct mtk_mmc_compatible mt7622_compat = {
|
||||||
|
.clk_div_bits = 12,
|
||||||
|
.recheck_sdio_irq = true,
|
||||||
|
.hs400_tune = false,
|
||||||
|
.pad_tune_reg = MSDC_PAD_TUNE0,
|
||||||
|
.async_fifo = true,
|
||||||
|
.data_tune = true,
|
||||||
|
.busy_check = true,
|
||||||
|
.stop_clk_fix = true,
|
||||||
|
.enhance_rx = true,
|
||||||
|
.support_64g = false,
|
||||||
|
};
|
||||||
|
|
||||||
static const struct mtk_mmc_compatible mt8135_compat = {
|
static const struct mtk_mmc_compatible mt8135_compat = {
|
||||||
.clk_div_bits = 8,
|
.clk_div_bits = 8,
|
||||||
.recheck_sdio_irq = true,
|
.recheck_sdio_irq = true,
|
||||||
@@ -513,45 +591,6 @@ static const struct mtk_mmc_compatible mt8183_compat = {
|
|||||||
.support_64g = true,
|
.support_64g = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct mtk_mmc_compatible mt2701_compat = {
|
|
||||||
.clk_div_bits = 12,
|
|
||||||
.recheck_sdio_irq = true,
|
|
||||||
.hs400_tune = false,
|
|
||||||
.pad_tune_reg = MSDC_PAD_TUNE0,
|
|
||||||
.async_fifo = true,
|
|
||||||
.data_tune = true,
|
|
||||||
.busy_check = false,
|
|
||||||
.stop_clk_fix = false,
|
|
||||||
.enhance_rx = false,
|
|
||||||
.support_64g = false,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct mtk_mmc_compatible mt2712_compat = {
|
|
||||||
.clk_div_bits = 12,
|
|
||||||
.recheck_sdio_irq = false,
|
|
||||||
.hs400_tune = false,
|
|
||||||
.pad_tune_reg = MSDC_PAD_TUNE0,
|
|
||||||
.async_fifo = true,
|
|
||||||
.data_tune = true,
|
|
||||||
.busy_check = true,
|
|
||||||
.stop_clk_fix = true,
|
|
||||||
.enhance_rx = true,
|
|
||||||
.support_64g = true,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct mtk_mmc_compatible mt7622_compat = {
|
|
||||||
.clk_div_bits = 12,
|
|
||||||
.recheck_sdio_irq = true,
|
|
||||||
.hs400_tune = false,
|
|
||||||
.pad_tune_reg = MSDC_PAD_TUNE0,
|
|
||||||
.async_fifo = true,
|
|
||||||
.data_tune = true,
|
|
||||||
.busy_check = true,
|
|
||||||
.stop_clk_fix = true,
|
|
||||||
.enhance_rx = true,
|
|
||||||
.support_64g = false,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct mtk_mmc_compatible mt8516_compat = {
|
static const struct mtk_mmc_compatible mt8516_compat = {
|
||||||
.clk_div_bits = 12,
|
.clk_div_bits = 12,
|
||||||
.recheck_sdio_irq = true,
|
.recheck_sdio_irq = true,
|
||||||
@@ -563,42 +602,18 @@ static const struct mtk_mmc_compatible mt8516_compat = {
|
|||||||
.stop_clk_fix = true,
|
.stop_clk_fix = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct mtk_mmc_compatible mt7620_compat = {
|
|
||||||
.clk_div_bits = 8,
|
|
||||||
.recheck_sdio_irq = true,
|
|
||||||
.hs400_tune = false,
|
|
||||||
.pad_tune_reg = MSDC_PAD_TUNE,
|
|
||||||
.async_fifo = false,
|
|
||||||
.data_tune = false,
|
|
||||||
.busy_check = false,
|
|
||||||
.stop_clk_fix = false,
|
|
||||||
.enhance_rx = false,
|
|
||||||
.use_internal_cd = true,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct mtk_mmc_compatible mt6779_compat = {
|
|
||||||
.clk_div_bits = 12,
|
|
||||||
.recheck_sdio_irq = false,
|
|
||||||
.hs400_tune = false,
|
|
||||||
.pad_tune_reg = MSDC_PAD_TUNE0,
|
|
||||||
.async_fifo = true,
|
|
||||||
.data_tune = true,
|
|
||||||
.busy_check = true,
|
|
||||||
.stop_clk_fix = true,
|
|
||||||
.enhance_rx = true,
|
|
||||||
.support_64g = true,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct of_device_id msdc_of_ids[] = {
|
static const struct of_device_id msdc_of_ids[] = {
|
||||||
|
{ .compatible = "mediatek,mt2701-mmc", .data = &mt2701_compat},
|
||||||
|
{ .compatible = "mediatek,mt2712-mmc", .data = &mt2712_compat},
|
||||||
|
{ .compatible = "mediatek,mt6779-mmc", .data = &mt6779_compat},
|
||||||
|
{ .compatible = "mediatek,mt6795-mmc", .data = &mt6795_compat},
|
||||||
|
{ .compatible = "mediatek,mt7620-mmc", .data = &mt7620_compat},
|
||||||
|
{ .compatible = "mediatek,mt7622-mmc", .data = &mt7622_compat},
|
||||||
{ .compatible = "mediatek,mt8135-mmc", .data = &mt8135_compat},
|
{ .compatible = "mediatek,mt8135-mmc", .data = &mt8135_compat},
|
||||||
{ .compatible = "mediatek,mt8173-mmc", .data = &mt8173_compat},
|
{ .compatible = "mediatek,mt8173-mmc", .data = &mt8173_compat},
|
||||||
{ .compatible = "mediatek,mt8183-mmc", .data = &mt8183_compat},
|
{ .compatible = "mediatek,mt8183-mmc", .data = &mt8183_compat},
|
||||||
{ .compatible = "mediatek,mt2701-mmc", .data = &mt2701_compat},
|
|
||||||
{ .compatible = "mediatek,mt2712-mmc", .data = &mt2712_compat},
|
|
||||||
{ .compatible = "mediatek,mt7622-mmc", .data = &mt7622_compat},
|
|
||||||
{ .compatible = "mediatek,mt8516-mmc", .data = &mt8516_compat},
|
{ .compatible = "mediatek,mt8516-mmc", .data = &mt8516_compat},
|
||||||
{ .compatible = "mediatek,mt7620-mmc", .data = &mt7620_compat},
|
|
||||||
{ .compatible = "mediatek,mt6779-mmc", .data = &mt6779_compat},
|
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, msdc_of_ids);
|
MODULE_DEVICE_TABLE(of, msdc_of_ids);
|
||||||
|
|||||||
@@ -1042,7 +1042,6 @@ static int sd_set_timing(struct rtsx_usb_sdmmc *host,
|
|||||||
unsigned char timing, bool *ddr_mode)
|
unsigned char timing, bool *ddr_mode)
|
||||||
{
|
{
|
||||||
struct rtsx_ucr *ucr = host->ucr;
|
struct rtsx_ucr *ucr = host->ucr;
|
||||||
int err;
|
|
||||||
|
|
||||||
*ddr_mode = false;
|
*ddr_mode = false;
|
||||||
|
|
||||||
@@ -1097,9 +1096,7 @@ static int sd_set_timing(struct rtsx_usb_sdmmc *host,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = rtsx_usb_send_cmd(ucr, MODE_C, 100);
|
return rtsx_usb_send_cmd(ucr, MODE_C, 100);
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
static void sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
||||||
|
|||||||
@@ -2441,6 +2441,7 @@ static const struct of_device_id sdhci_msm_dt_match[] = {
|
|||||||
*/
|
*/
|
||||||
{.compatible = "qcom,sdhci-msm-v4", .data = &sdhci_msm_mci_var},
|
{.compatible = "qcom,sdhci-msm-v4", .data = &sdhci_msm_mci_var},
|
||||||
{.compatible = "qcom,sdhci-msm-v5", .data = &sdhci_msm_v5_var},
|
{.compatible = "qcom,sdhci-msm-v5", .data = &sdhci_msm_v5_var},
|
||||||
|
{.compatible = "qcom,sdm670-sdhci", .data = &sdm845_sdhci_var},
|
||||||
{.compatible = "qcom,sdm845-sdhci", .data = &sdm845_sdhci_var},
|
{.compatible = "qcom,sdm845-sdhci", .data = &sdm845_sdhci_var},
|
||||||
{.compatible = "qcom,sc7180-sdhci", .data = &sdm845_sdhci_var},
|
{.compatible = "qcom,sc7180-sdhci", .data = &sdm845_sdhci_var},
|
||||||
{},
|
{},
|
||||||
|
|||||||
@@ -297,6 +297,27 @@ static const struct sdhci_pci_fixes sdhci_ricoh_mmc = {
|
|||||||
SDHCI_QUIRK_MISSING_CAPS
|
SDHCI_QUIRK_MISSING_CAPS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void ene_714_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
||||||
|
{
|
||||||
|
struct sdhci_host *host = mmc_priv(mmc);
|
||||||
|
|
||||||
|
sdhci_set_ios(mmc, ios);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some (ENE) controllers misbehave on some ios operations,
|
||||||
|
* signalling timeout and CRC errors even on CMD0. Resetting
|
||||||
|
* it on each ios seems to solve the problem.
|
||||||
|
*/
|
||||||
|
if (!(host->flags & SDHCI_DEVICE_DEAD))
|
||||||
|
sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ene_714_probe_slot(struct sdhci_pci_slot *slot)
|
||||||
|
{
|
||||||
|
slot->host->mmc_host_ops.set_ios = ene_714_set_ios;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct sdhci_pci_fixes sdhci_ene_712 = {
|
static const struct sdhci_pci_fixes sdhci_ene_712 = {
|
||||||
.quirks = SDHCI_QUIRK_SINGLE_POWER_WRITE |
|
.quirks = SDHCI_QUIRK_SINGLE_POWER_WRITE |
|
||||||
SDHCI_QUIRK_BROKEN_DMA,
|
SDHCI_QUIRK_BROKEN_DMA,
|
||||||
@@ -304,8 +325,8 @@ static const struct sdhci_pci_fixes sdhci_ene_712 = {
|
|||||||
|
|
||||||
static const struct sdhci_pci_fixes sdhci_ene_714 = {
|
static const struct sdhci_pci_fixes sdhci_ene_714 = {
|
||||||
.quirks = SDHCI_QUIRK_SINGLE_POWER_WRITE |
|
.quirks = SDHCI_QUIRK_SINGLE_POWER_WRITE |
|
||||||
SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS |
|
|
||||||
SDHCI_QUIRK_BROKEN_DMA,
|
SDHCI_QUIRK_BROKEN_DMA,
|
||||||
|
.probe_slot = ene_714_probe_slot,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct sdhci_pci_fixes sdhci_cafe = {
|
static const struct sdhci_pci_fixes sdhci_cafe = {
|
||||||
|
|||||||
@@ -317,11 +317,12 @@ static int sdhci_o2_execute_tuning(struct mmc_host *mmc, u32 opcode)
|
|||||||
u32 reg_val;
|
u32 reg_val;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This handler only implements the eMMC tuning that is specific to
|
* This handler implements the hardware tuning that is specific to
|
||||||
* this controller. Fall back to the standard method for other TIMING.
|
* this controller. Fall back to the standard method for other TIMING.
|
||||||
*/
|
*/
|
||||||
if ((host->timing != MMC_TIMING_MMC_HS200) &&
|
if ((host->timing != MMC_TIMING_MMC_HS200) &&
|
||||||
(host->timing != MMC_TIMING_UHS_SDR104))
|
(host->timing != MMC_TIMING_UHS_SDR104) &&
|
||||||
|
(host->timing != MMC_TIMING_UHS_SDR50))
|
||||||
return sdhci_execute_tuning(mmc, opcode);
|
return sdhci_execute_tuning(mmc, opcode);
|
||||||
|
|
||||||
if (WARN_ON((opcode != MMC_SEND_TUNING_BLOCK_HS200) &&
|
if (WARN_ON((opcode != MMC_SEND_TUNING_BLOCK_HS200) &&
|
||||||
@@ -631,6 +632,8 @@ static int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot)
|
|||||||
if (reg & 0x1)
|
if (reg & 0x1)
|
||||||
host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12;
|
host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12;
|
||||||
|
|
||||||
|
host->quirks2 |= SDHCI_QUIRK2_BROKEN_DDR50;
|
||||||
|
|
||||||
sdhci_pci_o2_enable_msi(chip, host);
|
sdhci_pci_o2_enable_msi(chip, host);
|
||||||
|
|
||||||
if (chip->pdev->device == PCI_DEVICE_ID_O2_SEABIRD0) {
|
if (chip->pdev->device == PCI_DEVICE_ID_O2_SEABIRD0) {
|
||||||
|
|||||||
@@ -205,14 +205,14 @@ static inline u32 sdhci_sprd_calc_div(u32 base_clk, u32 clk)
|
|||||||
if ((base_clk / div) > (clk * 2))
|
if ((base_clk / div) > (clk * 2))
|
||||||
div++;
|
div++;
|
||||||
|
|
||||||
if (div > SDHCI_SPRD_CLK_MAX_DIV)
|
|
||||||
div = SDHCI_SPRD_CLK_MAX_DIV;
|
|
||||||
|
|
||||||
if (div % 2)
|
if (div % 2)
|
||||||
div = (div + 1) / 2;
|
div = (div + 1) / 2;
|
||||||
else
|
else
|
||||||
div = div / 2;
|
div = div / 2;
|
||||||
|
|
||||||
|
if (div > SDHCI_SPRD_CLK_MAX_DIV)
|
||||||
|
div = SDHCI_SPRD_CLK_MAX_DIV;
|
||||||
|
|
||||||
return div;
|
return div;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -233,28 +233,62 @@ void sdhci_reset(struct sdhci_host *host, u8 mask)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(sdhci_reset);
|
EXPORT_SYMBOL_GPL(sdhci_reset);
|
||||||
|
|
||||||
static void sdhci_do_reset(struct sdhci_host *host, u8 mask)
|
static bool sdhci_do_reset(struct sdhci_host *host, u8 mask)
|
||||||
{
|
{
|
||||||
if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
|
if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
|
||||||
struct mmc_host *mmc = host->mmc;
|
struct mmc_host *mmc = host->mmc;
|
||||||
|
|
||||||
if (!mmc->ops->get_cd(mmc))
|
if (!mmc->ops->get_cd(mmc))
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
host->ops->reset(host, mask);
|
host->ops->reset(host, mask);
|
||||||
|
|
||||||
if (mask & SDHCI_RESET_ALL) {
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sdhci_reset_for_all(struct sdhci_host *host)
|
||||||
|
{
|
||||||
|
if (sdhci_do_reset(host, SDHCI_RESET_ALL)) {
|
||||||
if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
|
if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
|
||||||
if (host->ops->enable_dma)
|
if (host->ops->enable_dma)
|
||||||
host->ops->enable_dma(host);
|
host->ops->enable_dma(host);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Resetting the controller clears many */
|
/* Resetting the controller clears many */
|
||||||
host->preset_enabled = false;
|
host->preset_enabled = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum sdhci_reset_reason {
|
||||||
|
SDHCI_RESET_FOR_INIT,
|
||||||
|
SDHCI_RESET_FOR_REQUEST_ERROR,
|
||||||
|
SDHCI_RESET_FOR_REQUEST_ERROR_DATA_ONLY,
|
||||||
|
SDHCI_RESET_FOR_TUNING_ABORT,
|
||||||
|
SDHCI_RESET_FOR_CARD_REMOVED,
|
||||||
|
SDHCI_RESET_FOR_CQE_RECOVERY,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void sdhci_reset_for_reason(struct sdhci_host *host, enum sdhci_reset_reason reason)
|
||||||
|
{
|
||||||
|
switch (reason) {
|
||||||
|
case SDHCI_RESET_FOR_INIT:
|
||||||
|
sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
|
||||||
|
break;
|
||||||
|
case SDHCI_RESET_FOR_REQUEST_ERROR:
|
||||||
|
case SDHCI_RESET_FOR_TUNING_ABORT:
|
||||||
|
case SDHCI_RESET_FOR_CARD_REMOVED:
|
||||||
|
case SDHCI_RESET_FOR_CQE_RECOVERY:
|
||||||
|
sdhci_do_reset(host, SDHCI_RESET_CMD);
|
||||||
|
sdhci_do_reset(host, SDHCI_RESET_DATA);
|
||||||
|
break;
|
||||||
|
case SDHCI_RESET_FOR_REQUEST_ERROR_DATA_ONLY:
|
||||||
|
sdhci_do_reset(host, SDHCI_RESET_DATA);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define sdhci_reset_for(h, r) sdhci_reset_for_reason((h), SDHCI_RESET_FOR_##r)
|
||||||
|
|
||||||
static void sdhci_set_default_irqs(struct sdhci_host *host)
|
static void sdhci_set_default_irqs(struct sdhci_host *host)
|
||||||
{
|
{
|
||||||
host->ier = SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT |
|
host->ier = SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT |
|
||||||
@@ -323,9 +357,9 @@ static void sdhci_init(struct sdhci_host *host, int soft)
|
|||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
if (soft)
|
if (soft)
|
||||||
sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
|
sdhci_reset_for(host, INIT);
|
||||||
else
|
else
|
||||||
sdhci_do_reset(host, SDHCI_RESET_ALL);
|
sdhci_reset_for_all(host);
|
||||||
|
|
||||||
if (host->v4_mode)
|
if (host->v4_mode)
|
||||||
sdhci_do_enable_v4_mode(host);
|
sdhci_do_enable_v4_mode(host);
|
||||||
@@ -1538,8 +1572,9 @@ static void __sdhci_finish_data(struct sdhci_host *host, bool sw_data_timeout)
|
|||||||
*/
|
*/
|
||||||
if (data->error) {
|
if (data->error) {
|
||||||
if (!host->cmd || host->cmd == data_cmd)
|
if (!host->cmd || host->cmd == data_cmd)
|
||||||
sdhci_do_reset(host, SDHCI_RESET_CMD);
|
sdhci_reset_for(host, REQUEST_ERROR);
|
||||||
sdhci_do_reset(host, SDHCI_RESET_DATA);
|
else
|
||||||
|
sdhci_reset_for(host, REQUEST_ERROR_DATA_ONLY);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((host->flags & (SDHCI_REQ_USE_DMA | SDHCI_USE_ADMA)) ==
|
if ((host->flags & (SDHCI_REQ_USE_DMA | SDHCI_USE_ADMA)) ==
|
||||||
@@ -2403,14 +2438,6 @@ void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
|||||||
host->ops->set_clock(host, host->clock);
|
host->ops->set_clock(host, host->clock);
|
||||||
} else
|
} else
|
||||||
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
|
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
|
||||||
|
|
||||||
/*
|
|
||||||
* Some (ENE) controllers go apeshit on some ios operation,
|
|
||||||
* signalling timeout and CRC errors even on CMD0. Resetting
|
|
||||||
* it on each ios seems to solve the problem.
|
|
||||||
*/
|
|
||||||
if (host->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS)
|
|
||||||
sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(sdhci_set_ios);
|
EXPORT_SYMBOL_GPL(sdhci_set_ios);
|
||||||
|
|
||||||
@@ -2718,8 +2745,7 @@ void sdhci_abort_tuning(struct sdhci_host *host, u32 opcode)
|
|||||||
{
|
{
|
||||||
sdhci_reset_tuning(host);
|
sdhci_reset_tuning(host);
|
||||||
|
|
||||||
sdhci_do_reset(host, SDHCI_RESET_CMD);
|
sdhci_reset_for(host, TUNING_ABORT);
|
||||||
sdhci_do_reset(host, SDHCI_RESET_DATA);
|
|
||||||
|
|
||||||
sdhci_end_tuning(host);
|
sdhci_end_tuning(host);
|
||||||
|
|
||||||
@@ -2987,8 +3013,7 @@ static void sdhci_card_event(struct mmc_host *mmc)
|
|||||||
pr_err("%s: Resetting controller.\n",
|
pr_err("%s: Resetting controller.\n",
|
||||||
mmc_hostname(mmc));
|
mmc_hostname(mmc));
|
||||||
|
|
||||||
sdhci_do_reset(host, SDHCI_RESET_CMD);
|
sdhci_reset_for(host, CARD_REMOVED);
|
||||||
sdhci_do_reset(host, SDHCI_RESET_DATA);
|
|
||||||
|
|
||||||
sdhci_error_out_mrqs(host, -ENOMEDIUM);
|
sdhci_error_out_mrqs(host, -ENOMEDIUM);
|
||||||
}
|
}
|
||||||
@@ -3059,12 +3084,7 @@ static bool sdhci_request_done(struct sdhci_host *host)
|
|||||||
/* This is to force an update */
|
/* This is to force an update */
|
||||||
host->ops->set_clock(host, host->clock);
|
host->ops->set_clock(host, host->clock);
|
||||||
|
|
||||||
/*
|
sdhci_reset_for(host, REQUEST_ERROR);
|
||||||
* Spec says we should do both at the same time, but Ricoh
|
|
||||||
* controllers do not like that.
|
|
||||||
*/
|
|
||||||
sdhci_do_reset(host, SDHCI_RESET_CMD);
|
|
||||||
sdhci_do_reset(host, SDHCI_RESET_DATA);
|
|
||||||
|
|
||||||
host->pending_reset = false;
|
host->pending_reset = false;
|
||||||
}
|
}
|
||||||
@@ -3905,10 +3925,8 @@ void sdhci_cqe_disable(struct mmc_host *mmc, bool recovery)
|
|||||||
|
|
||||||
host->cqe_on = false;
|
host->cqe_on = false;
|
||||||
|
|
||||||
if (recovery) {
|
if (recovery)
|
||||||
sdhci_do_reset(host, SDHCI_RESET_CMD);
|
sdhci_reset_for(host, CQE_RECOVERY);
|
||||||
sdhci_do_reset(host, SDHCI_RESET_DATA);
|
|
||||||
}
|
|
||||||
|
|
||||||
pr_debug("%s: sdhci: CQE off, IRQ mask %#x, IRQ status %#x\n",
|
pr_debug("%s: sdhci: CQE off, IRQ mask %#x, IRQ status %#x\n",
|
||||||
mmc_hostname(mmc), host->ier,
|
mmc_hostname(mmc), host->ier,
|
||||||
@@ -4066,7 +4084,7 @@ void __sdhci_read_caps(struct sdhci_host *host, const u16 *ver,
|
|||||||
if (debug_quirks2)
|
if (debug_quirks2)
|
||||||
host->quirks2 = debug_quirks2;
|
host->quirks2 = debug_quirks2;
|
||||||
|
|
||||||
sdhci_do_reset(host, SDHCI_RESET_ALL);
|
sdhci_reset_for_all(host);
|
||||||
|
|
||||||
if (host->v4_mode)
|
if (host->v4_mode)
|
||||||
sdhci_do_enable_v4_mode(host);
|
sdhci_do_enable_v4_mode(host);
|
||||||
@@ -4807,7 +4825,7 @@ int __sdhci_add_host(struct sdhci_host *host)
|
|||||||
unled:
|
unled:
|
||||||
sdhci_led_unregister(host);
|
sdhci_led_unregister(host);
|
||||||
unirq:
|
unirq:
|
||||||
sdhci_do_reset(host, SDHCI_RESET_ALL);
|
sdhci_reset_for_all(host);
|
||||||
sdhci_writel(host, 0, SDHCI_INT_ENABLE);
|
sdhci_writel(host, 0, SDHCI_INT_ENABLE);
|
||||||
sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
|
sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
|
||||||
free_irq(host->irq, host);
|
free_irq(host->irq, host);
|
||||||
@@ -4865,7 +4883,7 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
|
|||||||
sdhci_led_unregister(host);
|
sdhci_led_unregister(host);
|
||||||
|
|
||||||
if (!dead)
|
if (!dead)
|
||||||
sdhci_do_reset(host, SDHCI_RESET_ALL);
|
sdhci_reset_for_all(host);
|
||||||
|
|
||||||
sdhci_writel(host, 0, SDHCI_INT_ENABLE);
|
sdhci_writel(host, 0, SDHCI_INT_ENABLE);
|
||||||
sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
|
sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
|
||||||
|
|||||||
@@ -379,8 +379,6 @@ struct sdhci_host {
|
|||||||
#define SDHCI_QUIRK_NO_CARD_NO_RESET (1<<2)
|
#define SDHCI_QUIRK_NO_CARD_NO_RESET (1<<2)
|
||||||
/* Controller doesn't like clearing the power reg before a change */
|
/* Controller doesn't like clearing the power reg before a change */
|
||||||
#define SDHCI_QUIRK_SINGLE_POWER_WRITE (1<<3)
|
#define SDHCI_QUIRK_SINGLE_POWER_WRITE (1<<3)
|
||||||
/* Controller has flaky internal state so reset it on each ios change */
|
|
||||||
#define SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS (1<<4)
|
|
||||||
/* Controller has an unusable DMA engine */
|
/* Controller has an unusable DMA engine */
|
||||||
#define SDHCI_QUIRK_BROKEN_DMA (1<<5)
|
#define SDHCI_QUIRK_BROKEN_DMA (1<<5)
|
||||||
/* Controller has an unusable ADMA engine */
|
/* Controller has an unusable ADMA engine */
|
||||||
|
|||||||
@@ -554,7 +554,6 @@ static const struct cqhci_host_ops sdhci_am654_cqhci_ops = {
|
|||||||
static int sdhci_am654_cqe_add_host(struct sdhci_host *host)
|
static int sdhci_am654_cqe_add_host(struct sdhci_host *host)
|
||||||
{
|
{
|
||||||
struct cqhci_host *cq_host;
|
struct cqhci_host *cq_host;
|
||||||
int ret;
|
|
||||||
|
|
||||||
cq_host = devm_kzalloc(mmc_dev(host->mmc), sizeof(struct cqhci_host),
|
cq_host = devm_kzalloc(mmc_dev(host->mmc), sizeof(struct cqhci_host),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
@@ -568,9 +567,7 @@ static int sdhci_am654_cqe_add_host(struct sdhci_host *host)
|
|||||||
|
|
||||||
host->mmc->caps2 |= MMC_CAP2_CQE;
|
host->mmc->caps2 |= MMC_CAP2_CQE;
|
||||||
|
|
||||||
ret = cqhci_init(cq_host, host->mmc, 1);
|
return cqhci_init(cq_host, host->mmc, 1);
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sdhci_am654_get_otap_delay(struct sdhci_host *host,
|
static int sdhci_am654_get_otap_delay(struct sdhci_host *host,
|
||||||
|
|||||||
@@ -846,7 +846,7 @@ static int wmt_mci_probe(struct platform_device *pdev)
|
|||||||
if (IS_ERR(priv->clk_sdmmc)) {
|
if (IS_ERR(priv->clk_sdmmc)) {
|
||||||
dev_err(&pdev->dev, "Error getting clock\n");
|
dev_err(&pdev->dev, "Error getting clock\n");
|
||||||
ret = PTR_ERR(priv->clk_sdmmc);
|
ret = PTR_ERR(priv->clk_sdmmc);
|
||||||
goto fail5;
|
goto fail5_and_a_half;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = clk_prepare_enable(priv->clk_sdmmc);
|
ret = clk_prepare_enable(priv->clk_sdmmc);
|
||||||
@@ -863,6 +863,9 @@ static int wmt_mci_probe(struct platform_device *pdev)
|
|||||||
return 0;
|
return 0;
|
||||||
fail6:
|
fail6:
|
||||||
clk_put(priv->clk_sdmmc);
|
clk_put(priv->clk_sdmmc);
|
||||||
|
fail5_and_a_half:
|
||||||
|
dma_free_coherent(&pdev->dev, mmc->max_blk_count * 16,
|
||||||
|
priv->dma_desc_buffer, priv->dma_desc_device_addr);
|
||||||
fail5:
|
fail5:
|
||||||
free_irq(dma_irq, priv);
|
free_irq(dma_irq, priv);
|
||||||
fail4:
|
fail4:
|
||||||
|
|||||||
@@ -476,7 +476,7 @@ struct mmc_host {
|
|||||||
|
|
||||||
unsigned int sdio_irqs;
|
unsigned int sdio_irqs;
|
||||||
struct task_struct *sdio_irq_thread;
|
struct task_struct *sdio_irq_thread;
|
||||||
struct delayed_work sdio_irq_work;
|
struct work_struct sdio_irq_work;
|
||||||
bool sdio_irq_pending;
|
bool sdio_irq_pending;
|
||||||
atomic_t sdio_irq_thread_abort;
|
atomic_t sdio_irq_thread_abort;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user