Commit c710364f authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'mmc-v5.4-2' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc

Pull more MMC updates from Ulf Hansson:
 "A couple more updates/fixes for MMC:

   - sdhci-pci: Add Genesys Logic GL975x support

   - sdhci-tegra: Recover loss in throughput for DMA

   - sdhci-of-esdhc: Fix DMA bug"

* tag 'mmc-v5.4-2' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc:
  mmc: host: sdhci-pci: Add Genesys Logic GL975x support
  mmc: tegra: Implement ->set_dma_mask()
  mmc: sdhci: Let drivers define their DMA mask
  mmc: sdhci-of-esdhc: set DMA snooping based on DMA coherence
  mmc: sdhci: improve ADMA error reporting
parents 97f9a3c4 e51df6ce
...@@ -94,6 +94,7 @@ config MMC_SDHCI_PCI ...@@ -94,6 +94,7 @@ config MMC_SDHCI_PCI
depends on MMC_SDHCI && PCI depends on MMC_SDHCI && PCI
select MMC_CQHCI select MMC_CQHCI
select IOSF_MBI if X86 select IOSF_MBI if X86
select MMC_SDHCI_IO_ACCESSORS
help help
This selects the PCI Secure Digital Host Controller Interface. This selects the PCI Secure Digital Host Controller Interface.
Most controllers found today are PCI devices. Most controllers found today are PCI devices.
......
...@@ -13,7 +13,7 @@ obj-$(CONFIG_MMC_MXS) += mxs-mmc.o ...@@ -13,7 +13,7 @@ obj-$(CONFIG_MMC_MXS) += mxs-mmc.o
obj-$(CONFIG_MMC_SDHCI) += sdhci.o obj-$(CONFIG_MMC_SDHCI) += sdhci.o
obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.o obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.o
sdhci-pci-y += sdhci-pci-core.o sdhci-pci-o2micro.o sdhci-pci-arasan.o \ sdhci-pci-y += sdhci-pci-core.o sdhci-pci-o2micro.o sdhci-pci-arasan.o \
sdhci-pci-dwc-mshc.o sdhci-pci-dwc-mshc.o sdhci-pci-gli.o
obj-$(subst m,y,$(CONFIG_MMC_SDHCI_PCI)) += sdhci-pci-data.o obj-$(subst m,y,$(CONFIG_MMC_SDHCI_PCI)) += sdhci-pci-data.o
obj-$(CONFIG_MMC_SDHCI_ACPI) += sdhci-acpi.o obj-$(CONFIG_MMC_SDHCI_ACPI) += sdhci-acpi.o
obj-$(CONFIG_MMC_SDHCI_PXAV3) += sdhci-pxav3.o obj-$(CONFIG_MMC_SDHCI_PXAV3) += sdhci-pxav3.o
......
...@@ -495,7 +495,12 @@ static int esdhc_of_enable_dma(struct sdhci_host *host) ...@@ -495,7 +495,12 @@ static int esdhc_of_enable_dma(struct sdhci_host *host)
dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40)); dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40));
value = sdhci_readl(host, ESDHC_DMA_SYSCTL); value = sdhci_readl(host, ESDHC_DMA_SYSCTL);
value |= ESDHC_DMA_SNOOP;
if (of_dma_is_coherent(dev->of_node))
value |= ESDHC_DMA_SNOOP;
else
value &= ~ESDHC_DMA_SNOOP;
sdhci_writel(host, value, ESDHC_DMA_SYSCTL); sdhci_writel(host, value, ESDHC_DMA_SYSCTL);
return 0; return 0;
} }
......
...@@ -1685,6 +1685,8 @@ static const struct pci_device_id pci_ids[] = { ...@@ -1685,6 +1685,8 @@ static const struct pci_device_id pci_ids[] = {
SDHCI_PCI_DEVICE(O2, SEABIRD1, o2), SDHCI_PCI_DEVICE(O2, SEABIRD1, o2),
SDHCI_PCI_DEVICE(ARASAN, PHY_EMMC, arasan), SDHCI_PCI_DEVICE(ARASAN, PHY_EMMC, arasan),
SDHCI_PCI_DEVICE(SYNOPSYS, DWC_MSHC, snps), SDHCI_PCI_DEVICE(SYNOPSYS, DWC_MSHC, snps),
SDHCI_PCI_DEVICE(GLI, 9750, gl9750),
SDHCI_PCI_DEVICE(GLI, 9755, gl9755),
SDHCI_PCI_DEVICE_CLASS(AMD, SYSTEM_SDHCI, PCI_CLASS_MASK, amd), SDHCI_PCI_DEVICE_CLASS(AMD, SYSTEM_SDHCI, PCI_CLASS_MASK, amd),
/* Generic SD host controller */ /* Generic SD host controller */
{PCI_DEVICE_CLASS(SYSTEM_SDHCI, PCI_CLASS_MASK)}, {PCI_DEVICE_CLASS(SYSTEM_SDHCI, PCI_CLASS_MASK)},
......
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2019 Genesys Logic, Inc.
*
* Authors: Ben Chuang <ben.chuang@genesyslogic.com.tw>
*
* Version: v0.9.0 (2019-08-08)
*/
#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/pci.h>
#include <linux/mmc/mmc.h>
#include <linux/delay.h>
#include "sdhci.h"
#include "sdhci-pci.h"
/* Genesys Logic extra registers */
#define SDHCI_GLI_9750_WT 0x800
#define SDHCI_GLI_9750_WT_EN BIT(0)
#define GLI_9750_WT_EN_ON 0x1
#define GLI_9750_WT_EN_OFF 0x0
#define SDHCI_GLI_9750_DRIVING 0x860
#define SDHCI_GLI_9750_DRIVING_1 GENMASK(11, 0)
#define SDHCI_GLI_9750_DRIVING_2 GENMASK(27, 26)
#define GLI_9750_DRIVING_1_VALUE 0xFFF
#define GLI_9750_DRIVING_2_VALUE 0x3
#define SDHCI_GLI_9750_PLL 0x864
#define SDHCI_GLI_9750_PLL_TX2_INV BIT(23)
#define SDHCI_GLI_9750_PLL_TX2_DLY GENMASK(22, 20)
#define GLI_9750_PLL_TX2_INV_VALUE 0x1
#define GLI_9750_PLL_TX2_DLY_VALUE 0x0
#define SDHCI_GLI_9750_SW_CTRL 0x874
#define SDHCI_GLI_9750_SW_CTRL_4 GENMASK(7, 6)
#define GLI_9750_SW_CTRL_4_VALUE 0x3
#define SDHCI_GLI_9750_MISC 0x878
#define SDHCI_GLI_9750_MISC_TX1_INV BIT(2)
#define SDHCI_GLI_9750_MISC_RX_INV BIT(3)
#define SDHCI_GLI_9750_MISC_TX1_DLY GENMASK(6, 4)
#define GLI_9750_MISC_TX1_INV_VALUE 0x0
#define GLI_9750_MISC_RX_INV_ON 0x1
#define GLI_9750_MISC_RX_INV_OFF 0x0
#define GLI_9750_MISC_RX_INV_VALUE GLI_9750_MISC_RX_INV_OFF
#define GLI_9750_MISC_TX1_DLY_VALUE 0x5
#define SDHCI_GLI_9750_TUNING_CONTROL 0x540
#define SDHCI_GLI_9750_TUNING_CONTROL_EN BIT(4)
#define GLI_9750_TUNING_CONTROL_EN_ON 0x1
#define GLI_9750_TUNING_CONTROL_EN_OFF 0x0
#define SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_1 BIT(16)
#define SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_2 GENMASK(20, 19)
#define GLI_9750_TUNING_CONTROL_GLITCH_1_VALUE 0x1
#define GLI_9750_TUNING_CONTROL_GLITCH_2_VALUE 0x2
#define SDHCI_GLI_9750_TUNING_PARAMETERS 0x544
#define SDHCI_GLI_9750_TUNING_PARAMETERS_RX_DLY GENMASK(2, 0)
#define GLI_9750_TUNING_PARAMETERS_RX_DLY_VALUE 0x1
#define GLI_MAX_TUNING_LOOP 40
/* Genesys Logic chipset */
static inline void gl9750_wt_on(struct sdhci_host *host)
{
u32 wt_value;
u32 wt_enable;
wt_value = sdhci_readl(host, SDHCI_GLI_9750_WT);
wt_enable = FIELD_GET(SDHCI_GLI_9750_WT_EN, wt_value);
if (wt_enable == GLI_9750_WT_EN_ON)
return;
wt_value &= ~SDHCI_GLI_9750_WT_EN;
wt_value |= FIELD_PREP(SDHCI_GLI_9750_WT_EN, GLI_9750_WT_EN_ON);
sdhci_writel(host, wt_value, SDHCI_GLI_9750_WT);
}
static inline void gl9750_wt_off(struct sdhci_host *host)
{
u32 wt_value;
u32 wt_enable;
wt_value = sdhci_readl(host, SDHCI_GLI_9750_WT);
wt_enable = FIELD_GET(SDHCI_GLI_9750_WT_EN, wt_value);
if (wt_enable == GLI_9750_WT_EN_OFF)
return;
wt_value &= ~SDHCI_GLI_9750_WT_EN;
wt_value |= FIELD_PREP(SDHCI_GLI_9750_WT_EN, GLI_9750_WT_EN_OFF);
sdhci_writel(host, wt_value, SDHCI_GLI_9750_WT);
}
static void gli_set_9750(struct sdhci_host *host)
{
u32 driving_value;
u32 pll_value;
u32 sw_ctrl_value;
u32 misc_value;
u32 parameter_value;
u32 control_value;
u16 ctrl2;
gl9750_wt_on(host);
driving_value = sdhci_readl(host, SDHCI_GLI_9750_DRIVING);
pll_value = sdhci_readl(host, SDHCI_GLI_9750_PLL);
sw_ctrl_value = sdhci_readl(host, SDHCI_GLI_9750_SW_CTRL);
misc_value = sdhci_readl(host, SDHCI_GLI_9750_MISC);
parameter_value = sdhci_readl(host, SDHCI_GLI_9750_TUNING_PARAMETERS);
control_value = sdhci_readl(host, SDHCI_GLI_9750_TUNING_CONTROL);
driving_value &= ~(SDHCI_GLI_9750_DRIVING_1);
driving_value &= ~(SDHCI_GLI_9750_DRIVING_2);
driving_value |= FIELD_PREP(SDHCI_GLI_9750_DRIVING_1,
GLI_9750_DRIVING_1_VALUE);
driving_value |= FIELD_PREP(SDHCI_GLI_9750_DRIVING_2,
GLI_9750_DRIVING_2_VALUE);
sdhci_writel(host, driving_value, SDHCI_GLI_9750_DRIVING);
sw_ctrl_value &= ~SDHCI_GLI_9750_SW_CTRL_4;
sw_ctrl_value |= FIELD_PREP(SDHCI_GLI_9750_SW_CTRL_4,
GLI_9750_SW_CTRL_4_VALUE);
sdhci_writel(host, sw_ctrl_value, SDHCI_GLI_9750_SW_CTRL);
/* reset the tuning flow after reinit and before starting tuning */
pll_value &= ~SDHCI_GLI_9750_PLL_TX2_INV;
pll_value &= ~SDHCI_GLI_9750_PLL_TX2_DLY;
pll_value |= FIELD_PREP(SDHCI_GLI_9750_PLL_TX2_INV,
GLI_9750_PLL_TX2_INV_VALUE);
pll_value |= FIELD_PREP(SDHCI_GLI_9750_PLL_TX2_DLY,
GLI_9750_PLL_TX2_DLY_VALUE);
misc_value &= ~SDHCI_GLI_9750_MISC_TX1_INV;
misc_value &= ~SDHCI_GLI_9750_MISC_RX_INV;
misc_value &= ~SDHCI_GLI_9750_MISC_TX1_DLY;
misc_value |= FIELD_PREP(SDHCI_GLI_9750_MISC_TX1_INV,
GLI_9750_MISC_TX1_INV_VALUE);
misc_value |= FIELD_PREP(SDHCI_GLI_9750_MISC_RX_INV,
GLI_9750_MISC_RX_INV_VALUE);
misc_value |= FIELD_PREP(SDHCI_GLI_9750_MISC_TX1_DLY,
GLI_9750_MISC_TX1_DLY_VALUE);
parameter_value &= ~SDHCI_GLI_9750_TUNING_PARAMETERS_RX_DLY;
parameter_value |= FIELD_PREP(SDHCI_GLI_9750_TUNING_PARAMETERS_RX_DLY,
GLI_9750_TUNING_PARAMETERS_RX_DLY_VALUE);
control_value &= ~SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_1;
control_value &= ~SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_2;
control_value |= FIELD_PREP(SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_1,
GLI_9750_TUNING_CONTROL_GLITCH_1_VALUE);
control_value |= FIELD_PREP(SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_2,
GLI_9750_TUNING_CONTROL_GLITCH_2_VALUE);
sdhci_writel(host, pll_value, SDHCI_GLI_9750_PLL);
sdhci_writel(host, misc_value, SDHCI_GLI_9750_MISC);
/* disable tuned clk */
ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
ctrl2 &= ~SDHCI_CTRL_TUNED_CLK;
sdhci_writew(host, ctrl2, SDHCI_HOST_CONTROL2);
/* enable tuning parameters control */
control_value &= ~SDHCI_GLI_9750_TUNING_CONTROL_EN;
control_value |= FIELD_PREP(SDHCI_GLI_9750_TUNING_CONTROL_EN,
GLI_9750_TUNING_CONTROL_EN_ON);
sdhci_writel(host, control_value, SDHCI_GLI_9750_TUNING_CONTROL);
/* write tuning parameters */
sdhci_writel(host, parameter_value, SDHCI_GLI_9750_TUNING_PARAMETERS);
/* disable tuning parameters control */
control_value &= ~SDHCI_GLI_9750_TUNING_CONTROL_EN;
control_value |= FIELD_PREP(SDHCI_GLI_9750_TUNING_CONTROL_EN,
GLI_9750_TUNING_CONTROL_EN_OFF);
sdhci_writel(host, control_value, SDHCI_GLI_9750_TUNING_CONTROL);
/* clear tuned clk */
ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
ctrl2 &= ~SDHCI_CTRL_TUNED_CLK;
sdhci_writew(host, ctrl2, SDHCI_HOST_CONTROL2);
gl9750_wt_off(host);
}
static void gli_set_9750_rx_inv(struct sdhci_host *host, bool b)
{
u32 misc_value;
gl9750_wt_on(host);
misc_value = sdhci_readl(host, SDHCI_GLI_9750_MISC);
misc_value &= ~SDHCI_GLI_9750_MISC_RX_INV;
if (b) {
misc_value |= FIELD_PREP(SDHCI_GLI_9750_MISC_RX_INV,
GLI_9750_MISC_RX_INV_ON);
} else {
misc_value |= FIELD_PREP(SDHCI_GLI_9750_MISC_RX_INV,
GLI_9750_MISC_RX_INV_OFF);
}
sdhci_writel(host, misc_value, SDHCI_GLI_9750_MISC);
gl9750_wt_off(host);
}
static int __sdhci_execute_tuning_9750(struct sdhci_host *host, u32 opcode)
{
int i;
int rx_inv;
for (rx_inv = 0; rx_inv < 2; rx_inv++) {
gli_set_9750_rx_inv(host, !!rx_inv);
sdhci_start_tuning(host);
for (i = 0; i < GLI_MAX_TUNING_LOOP; i++) {
u16 ctrl;
sdhci_send_tuning(host, opcode);
if (!host->tuning_done) {
sdhci_abort_tuning(host, opcode);
break;
}
ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
if (!(ctrl & SDHCI_CTRL_EXEC_TUNING)) {
if (ctrl & SDHCI_CTRL_TUNED_CLK)
return 0; /* Success! */
break;
}
}
}
if (!host->tuning_done) {
pr_info("%s: Tuning timeout, falling back to fixed sampling clock\n",
mmc_hostname(host->mmc));
return -ETIMEDOUT;
}
pr_info("%s: Tuning failed, falling back to fixed sampling clock\n",
mmc_hostname(host->mmc));
sdhci_reset_tuning(host);
return -EAGAIN;
}
static int gl9750_execute_tuning(struct sdhci_host *host, u32 opcode)
{
host->mmc->retune_period = 0;
if (host->tuning_mode == SDHCI_TUNING_MODE_1)
host->mmc->retune_period = host->tuning_count;
gli_set_9750(host);
host->tuning_err = __sdhci_execute_tuning_9750(host, opcode);
sdhci_end_tuning(host);
return 0;
}
static int gli_probe_slot_gl9750(struct sdhci_pci_slot *slot)
{
struct sdhci_host *host = slot->host;
slot->host->mmc->caps2 |= MMC_CAP2_NO_SDIO;
sdhci_enable_v4_mode(host);
return 0;
}
static int gli_probe_slot_gl9755(struct sdhci_pci_slot *slot)
{
struct sdhci_host *host = slot->host;
slot->host->mmc->caps2 |= MMC_CAP2_NO_SDIO;
sdhci_enable_v4_mode(host);
return 0;
}
static void sdhci_gli_voltage_switch(struct sdhci_host *host)
{
/*
* According to Section 3.6.1 signal voltage switch procedure in
* SD Host Controller Simplified Spec. 4.20, steps 6~8 are as
* follows:
* (6) Set 1.8V Signal Enable in the Host Control 2 register.
* (7) Wait 5ms. 1.8V voltage regulator shall be stable within this
* period.
* (8) If 1.8V Signal Enable is cleared by Host Controller, go to
* step (12).
*
* Wait 5ms after set 1.8V signal enable in Host Control 2 register
* to ensure 1.8V signal enable bit is set by GL9750/GL9755.
*/
usleep_range(5000, 5500);
}
static void sdhci_gl9750_reset(struct sdhci_host *host, u8 mask)
{
sdhci_reset(host, mask);
gli_set_9750(host);
}
static u32 sdhci_gl9750_readl(struct sdhci_host *host, int reg)
{
u32 value;
value = readl(host->ioaddr + reg);
if (unlikely(reg == SDHCI_MAX_CURRENT && !(value & 0xff)))
value |= 0xc8;
return value;
}
static const struct sdhci_ops sdhci_gl9755_ops = {
.set_clock = sdhci_set_clock,
.enable_dma = sdhci_pci_enable_dma,
.set_bus_width = sdhci_set_bus_width,
.reset = sdhci_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
.voltage_switch = sdhci_gli_voltage_switch,
};
const struct sdhci_pci_fixes sdhci_gl9755 = {
.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
.quirks2 = SDHCI_QUIRK2_BROKEN_DDR50,
.probe_slot = gli_probe_slot_gl9755,
.ops = &sdhci_gl9755_ops,
};
static const struct sdhci_ops sdhci_gl9750_ops = {
.read_l = sdhci_gl9750_readl,
.set_clock = sdhci_set_clock,
.enable_dma = sdhci_pci_enable_dma,
.set_bus_width = sdhci_set_bus_width,
.reset = sdhci_gl9750_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
.voltage_switch = sdhci_gli_voltage_switch,
.platform_execute_tuning = gl9750_execute_tuning,
};
const struct sdhci_pci_fixes sdhci_gl9750 = {
.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
.quirks2 = SDHCI_QUIRK2_BROKEN_DDR50,
.probe_slot = gli_probe_slot_gl9750,
.ops = &sdhci_gl9750_ops,
};
...@@ -68,6 +68,9 @@ ...@@ -68,6 +68,9 @@
#define PCI_DEVICE_ID_SYNOPSYS_DWC_MSHC 0xc202 #define PCI_DEVICE_ID_SYNOPSYS_DWC_MSHC 0xc202
#define PCI_DEVICE_ID_GLI_9755 0x9755
#define PCI_DEVICE_ID_GLI_9750 0x9750
/* /*
* PCI device class and mask * PCI device class and mask
*/ */
...@@ -188,5 +191,7 @@ int sdhci_pci_enable_dma(struct sdhci_host *host); ...@@ -188,5 +191,7 @@ int sdhci_pci_enable_dma(struct sdhci_host *host);
extern const struct sdhci_pci_fixes sdhci_arasan; extern const struct sdhci_pci_fixes sdhci_arasan;
extern const struct sdhci_pci_fixes sdhci_snps; extern const struct sdhci_pci_fixes sdhci_snps;
extern const struct sdhci_pci_fixes sdhci_o2; extern const struct sdhci_pci_fixes sdhci_o2;
extern const struct sdhci_pci_fixes sdhci_gl9750;
extern const struct sdhci_pci_fixes sdhci_gl9755;
#endif /* __SDHCI_PCI_H */ #endif /* __SDHCI_PCI_H */
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
*/ */
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
...@@ -104,6 +105,7 @@ ...@@ -104,6 +105,7 @@
struct sdhci_tegra_soc_data { struct sdhci_tegra_soc_data {
const struct sdhci_pltfm_data *pdata; const struct sdhci_pltfm_data *pdata;
u64 dma_mask;
u32 nvquirks; u32 nvquirks;
u8 min_tap_delay; u8 min_tap_delay;
u8 max_tap_delay; u8 max_tap_delay;
...@@ -1233,11 +1235,25 @@ static const struct cqhci_host_ops sdhci_tegra_cqhci_ops = { ...@@ -1233,11 +1235,25 @@ static const struct cqhci_host_ops sdhci_tegra_cqhci_ops = {
.update_dcmd_desc = sdhci_tegra_update_dcmd_desc, .update_dcmd_desc = sdhci_tegra_update_dcmd_desc,
}; };
static int tegra_sdhci_set_dma_mask(struct sdhci_host *host)
{
struct sdhci_pltfm_host *platform = sdhci_priv(host);
struct sdhci_tegra *tegra = sdhci_pltfm_priv(platform);
const struct sdhci_tegra_soc_data *soc = tegra->soc_data;
struct device *dev = mmc_dev(host->mmc);
if (soc->dma_mask)
return dma_set_mask_and_coherent(dev, soc->dma_mask);
return 0;
}
static const struct sdhci_ops tegra_sdhci_ops = { static const struct sdhci_ops tegra_sdhci_ops = {
.get_ro = tegra_sdhci_get_ro, .get_ro = tegra_sdhci_get_ro,
.read_w = tegra_sdhci_readw, .read_w = tegra_sdhci_readw,
.write_l = tegra_sdhci_writel, .write_l = tegra_sdhci_writel,
.set_clock = tegra_sdhci_set_clock, .set_clock = tegra_sdhci_set_clock,
.set_dma_mask = tegra_sdhci_set_dma_mask,
.set_bus_width = sdhci_set_bus_width, .set_bus_width = sdhci_set_bus_width,
.reset = tegra_sdhci_reset, .reset = tegra_sdhci_reset,
.platform_execute_tuning = tegra_sdhci_execute_tuning, .platform_execute_tuning = tegra_sdhci_execute_tuning,
...@@ -1257,6 +1273,7 @@ static const struct sdhci_pltfm_data sdhci_tegra20_pdata = { ...@@ -1257,6 +1273,7 @@ static const struct sdhci_pltfm_data sdhci_tegra20_pdata = {
static const struct sdhci_tegra_soc_data soc_data_tegra20 = { static const struct sdhci_tegra_soc_data soc_data_tegra20 = {
.pdata = &sdhci_tegra20_pdata, .pdata = &sdhci_tegra20_pdata,
.dma_mask = DMA_BIT_MASK(32),
.nvquirks = NVQUIRK_FORCE_SDHCI_SPEC_200 | .nvquirks = NVQUIRK_FORCE_SDHCI_SPEC_200 |
NVQUIRK_ENABLE_BLOCK_GAP_DET, NVQUIRK_ENABLE_BLOCK_GAP_DET,
}; };
...@@ -1283,6 +1300,7 @@ static const struct sdhci_pltfm_data sdhci_tegra30_pdata = { ...@@ -1283,6 +1300,7 @@ static const struct sdhci_pltfm_data sdhci_tegra30_pdata = {
static const struct sdhci_tegra_soc_data soc_data_tegra30 = { static const struct sdhci_tegra_soc_data soc_data_tegra30 = {
.pdata = &sdhci_tegra30_pdata, .pdata = &sdhci_tegra30_pdata,
.dma_mask = DMA_BIT_MASK(32),
.nvquirks = NVQUIRK_ENABLE_SDHCI_SPEC_300 | .nvquirks = NVQUIRK_ENABLE_SDHCI_SPEC_300 |
NVQUIRK_ENABLE_SDR50 | NVQUIRK_ENABLE_SDR50 |
NVQUIRK_ENABLE_SDR104 | NVQUIRK_ENABLE_SDR104 |
...@@ -1295,6 +1313,7 @@ static const struct sdhci_ops tegra114_sdhci_ops = { ...@@ -1295,6 +1313,7 @@ static const struct sdhci_ops tegra114_sdhci_ops = {
.write_w = tegra_sdhci_writew, .write_w = tegra_sdhci_writew,
.write_l = tegra_sdhci_writel, .write_l = tegra_sdhci_writel,
.set_clock = tegra_sdhci_set_clock, .set_clock = tegra_sdhci_set_clock,
.set_dma_mask = tegra_sdhci_set_dma_mask,
.set_bus_width = sdhci_set_bus_width, .set_bus_width = sdhci_set_bus_width,
.reset = tegra_sdhci_reset, .reset = tegra_sdhci_reset,
.platform_execute_tuning = tegra_sdhci_execute_tuning, .platform_execute_tuning = tegra_sdhci_execute_tuning,
...@@ -1316,6 +1335,7 @@ static const struct sdhci_pltfm_data sdhci_tegra114_pdata = { ...@@ -1316,6 +1335,7 @@ static const struct sdhci_pltfm_data sdhci_tegra114_pdata = {
static const struct sdhci_tegra_soc_data soc_data_tegra114 = { static const struct sdhci_tegra_soc_data soc_data_tegra114 = {
.pdata = &sdhci_tegra114_pdata, .pdata = &sdhci_tegra114_pdata,
.dma_mask = DMA_BIT_MASK(32),
}; };
static const struct sdhci_pltfm_data sdhci_tegra124_pdata = { static const struct sdhci_pltfm_data sdhci_tegra124_pdata = {
...@@ -1325,22 +1345,13 @@ static const struct sdhci_pltfm_data sdhci_tegra124_pdata = { ...@@ -1325,22 +1345,13 @@ static const struct sdhci_pltfm_data sdhci_tegra124_pdata = {
SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_NO_HISPD_BIT |
SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
/*
* The TRM states that the SD/MMC controller found on
* Tegra124 can address 34 bits (the maximum supported by
* the Tegra memory controller), but tests show that DMA
* to or from above 4 GiB doesn't work. This is possibly
* caused by missing programming, though it's not obvious
* what sequence is required. Mark 64-bit DMA broken for
* now to fix this for existing users (e.g. Nyan boards).
*/
SDHCI_QUIRK2_BROKEN_64_BIT_DMA,
.ops = &tegra114_sdhci_ops, .ops = &tegra114_sdhci_ops,
}; };
static const struct sdhci_tegra_soc_data soc_data_tegra124 = { static const struct sdhci_tegra_soc_data soc_data_tegra124 = {
.pdata = &sdhci_tegra124_pdata, .pdata = &sdhci_tegra124_pdata,
.dma_mask = DMA_BIT_MASK(34),
}; };
static const struct sdhci_ops tegra210_sdhci_ops = { static const struct sdhci_ops tegra210_sdhci_ops = {
...@@ -1349,6 +1360,7 @@ static const struct sdhci_ops tegra210_sdhci_ops = { ...@@ -1349,6 +1360,7 @@ static const struct sdhci_ops tegra210_sdhci_ops = {
.write_w = tegra210_sdhci_writew, .write_w = tegra210_sdhci_writew,
.write_l = tegra_sdhci_writel, .write_l = tegra_sdhci_writel,
.set_clock = tegra_sdhci_set_clock, .set_clock = tegra_sdhci_set_clock,
.set_dma_mask = tegra_sdhci_set_dma_mask,
.set_bus_width = sdhci_set_bus_width, .set_bus_width = sdhci_set_bus_width,
.reset = tegra_sdhci_reset, .reset = tegra_sdhci_reset,
.set_uhs_signaling = tegra_sdhci_set_uhs_signaling, .set_uhs_signaling = tegra_sdhci_set_uhs_signaling,
...@@ -1369,6 +1381,7 @@ static const struct sdhci_pltfm_data sdhci_tegra210_pdata = { ...@@ -1369,6 +1381,7 @@ static const struct sdhci_pltfm_data sdhci_tegra210_pdata = {
static const struct sdhci_tegra_soc_data soc_data_tegra210 = { static const struct sdhci_tegra_soc_data soc_data_tegra210 = {
.pdata = &sdhci_tegra210_pdata, .pdata = &sdhci_tegra210_pdata,
.dma_mask = DMA_BIT_MASK(34),
.nvquirks = NVQUIRK_NEEDS_PAD_CONTROL | .nvquirks = NVQUIRK_NEEDS_PAD_CONTROL |
NVQUIRK_HAS_PADCALIB | NVQUIRK_HAS_PADCALIB |
NVQUIRK_DIS_CARD_CLK_CONFIG_TAP | NVQUIRK_DIS_CARD_CLK_CONFIG_TAP |
...@@ -1383,6 +1396,7 @@ static const struct sdhci_ops tegra186_sdhci_ops = { ...@@ -1383,6 +1396,7 @@ static const struct sdhci_ops tegra186_sdhci_ops = {
.read_w = tegra_sdhci_readw, .read_w = tegra_sdhci_readw,
.write_l = tegra_sdhci_writel, .write_l = tegra_sdhci_writel,
.set_clock = tegra_sdhci_set_clock, .set_clock = tegra_sdhci_set_clock,
.set_dma_mask = tegra_sdhci_set_dma_mask,
.set_bus_width = sdhci_set_bus_width, .set_bus_width = sdhci_set_bus_width,
.reset = tegra_sdhci_reset, .reset = tegra_sdhci_reset,
.set_uhs_signaling = tegra_sdhci_set_uhs_signaling, .set_uhs_signaling = tegra_sdhci_set_uhs_signaling,
...@@ -1398,20 +1412,13 @@ static const struct sdhci_pltfm_data sdhci_tegra186_pdata = { ...@@ -1398,20 +1412,13 @@ static const struct sdhci_pltfm_data sdhci_tegra186_pdata = {
SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_NO_HISPD_BIT |
SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
/* SDHCI controllers on Tegra186 support 40-bit addressing.
* IOVA addresses are 48-bit wide on Tegra186.
* With 64-bit dma mask used for SDHCI, accesses can
* be broken. Disable 64-bit dma, which would fall back
* to 32-bit dma mask. Ideally 40-bit dma mask would work,
* But it is not supported as of now.
*/
SDHCI_QUIRK2_BROKEN_64_BIT_DMA,
.ops = &tegra186_sdhci_ops, .ops = &tegra186_sdhci_ops,
}; };
static const struct sdhci_tegra_soc_data soc_data_tegra186 = { static const struct sdhci_tegra_soc_data soc_data_tegra186 = {
.pdata = &sdhci_tegra186_pdata, .pdata = &sdhci_tegra186_pdata,
.dma_mask = DMA_BIT_MASK(40),
.nvquirks = NVQUIRK_NEEDS_PAD_CONTROL | .nvquirks = NVQUIRK_NEEDS_PAD_CONTROL |
NVQUIRK_HAS_PADCALIB | NVQUIRK_HAS_PADCALIB |
NVQUIRK_DIS_CARD_CLK_CONFIG_TAP | NVQUIRK_DIS_CARD_CLK_CONFIG_TAP |
...@@ -1424,6 +1431,7 @@ static const struct sdhci_tegra_soc_data soc_data_tegra186 = { ...@@ -1424,6 +1431,7 @@ static const struct sdhci_tegra_soc_data soc_data_tegra186 = {
static const struct sdhci_tegra_soc_data soc_data_tegra194 = { static const struct sdhci_tegra_soc_data soc_data_tegra194 = {
.pdata = &sdhci_tegra186_pdata, .pdata = &sdhci_tegra186_pdata,
.dma_mask = DMA_BIT_MASK(39),
.nvquirks = NVQUIRK_NEEDS_PAD_CONTROL | .nvquirks = NVQUIRK_NEEDS_PAD_CONTROL |
NVQUIRK_HAS_PADCALIB | NVQUIRK_HAS_PADCALIB |
NVQUIRK_DIS_CARD_CLK_CONFIG_TAP | NVQUIRK_DIS_CARD_CLK_CONFIG_TAP |
......
...@@ -2874,6 +2874,7 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *intmask_p) ...@@ -2874,6 +2874,7 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *intmask_p)
static void sdhci_adma_show_error(struct sdhci_host *host) static void sdhci_adma_show_error(struct sdhci_host *host)
{ {
void *desc = host->adma_table; void *desc = host->adma_table;
dma_addr_t dma = host->adma_addr;
sdhci_dumpregs(host); sdhci_dumpregs(host);
...@@ -2881,18 +2882,21 @@ static void sdhci_adma_show_error(struct sdhci_host *host) ...@@ -2881,18 +2882,21 @@ static void sdhci_adma_show_error(struct sdhci_host *host)
struct sdhci_adma2_64_desc *dma_desc = desc; struct sdhci_adma2_64_desc *dma_desc = desc;
if (host->flags & SDHCI_USE_64_BIT_DMA) if (host->flags & SDHCI_USE_64_BIT_DMA)
DBG("%p: DMA 0x%08x%08x, LEN 0x%04x, Attr=0x%02x\n", SDHCI_DUMP("%08llx: DMA 0x%08x%08x, LEN 0x%04x, Attr=0x%02x\n",
desc, le32_to_cpu(dma_desc->addr_hi), (unsigned long long)dma,
le32_to_cpu(dma_desc->addr_hi),
le32_to_cpu(dma_desc->addr_lo), le32_to_cpu(dma_desc->addr_lo),
le16_to_cpu(dma_desc->len), le16_to_cpu(dma_desc->len),
le16_to_cpu(dma_desc->cmd)); le16_to_cpu(dma_desc->cmd));
else else
DBG("%p: DMA 0x%08x, LEN 0x%04x, Attr=0x%02x\n", SDHCI_DUMP("%08llx: DMA 0x%08x, LEN 0x%04x, Attr=0x%02x\n",
desc, le32_to_cpu(dma_desc->addr_lo), (unsigned long long)dma,
le32_to_cpu(dma_desc->addr_lo),
le16_to_cpu(dma_desc->len), le16_to_cpu(dma_desc->len),
le16_to_cpu(dma_desc->cmd)); le16_to_cpu(dma_desc->cmd));
desc += host->desc_sz; desc += host->desc_sz;
dma += host->desc_sz;
if (dma_desc->cmd & cpu_to_le16(ADMA2_END)) if (dma_desc->cmd & cpu_to_le16(ADMA2_END))
break; break;
...@@ -2968,7 +2972,8 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) ...@@ -2968,7 +2972,8 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
!= MMC_BUS_TEST_R) != MMC_BUS_TEST_R)
host->data->error = -EILSEQ; host->data->error = -EILSEQ;
else if (intmask & SDHCI_INT_ADMA_ERROR) { else if (intmask & SDHCI_INT_ADMA_ERROR) {
pr_err("%s: ADMA error\n", mmc_hostname(host->mmc)); pr_err("%s: ADMA error: 0x%08x\n", mmc_hostname(host->mmc),
intmask);
sdhci_adma_show_error(host); sdhci_adma_show_error(host);
host->data->error = -EIO; host->data->error = -EIO;
if (host->ops->adma_workaround) if (host->ops->adma_workaround)
...@@ -3776,18 +3781,14 @@ int sdhci_setup_host(struct sdhci_host *host) ...@@ -3776,18 +3781,14 @@ int sdhci_setup_host(struct sdhci_host *host)
host->flags &= ~SDHCI_USE_ADMA; host->flags &= ~SDHCI_USE_ADMA;
} }
/*
* It is assumed that a 64-bit capable device has set a 64-bit DMA mask
* and *must* do 64-bit DMA. A driver has the opportunity to change
* that during the first call to ->enable_dma(). Similarly
* SDHCI_QUIRK2_BROKEN_64_BIT_DMA must be left to the drivers to
* implement.
*/
if (sdhci_can_64bit_dma(host)) if (sdhci_can_64bit_dma(host))
host->flags |= SDHCI_USE_64_BIT_DMA; host->flags |= SDHCI_USE_64_BIT_DMA;
if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
ret = sdhci_set_dma_mask(host); if (host->ops->set_dma_mask)
ret = host->ops->set_dma_mask(host);
else
ret = sdhci_set_dma_mask(host);
if (!ret && host->ops->enable_dma) if (!ret && host->ops->enable_dma)
ret = host->ops->enable_dma(host); ret = host->ops->enable_dma(host);
......
...@@ -622,6 +622,7 @@ struct sdhci_ops { ...@@ -622,6 +622,7 @@ struct sdhci_ops {
u32 (*irq)(struct sdhci_host *host, u32 intmask); u32 (*irq)(struct sdhci_host *host, u32 intmask);
int (*set_dma_mask)(struct sdhci_host *host);
int (*enable_dma)(struct sdhci_host *host); int (*enable_dma)(struct sdhci_host *host);
unsigned int (*get_max_clock)(struct sdhci_host *host); unsigned int (*get_max_clock)(struct sdhci_host *host);
unsigned int (*get_min_clock)(struct sdhci_host *host); unsigned int (*get_min_clock)(struct sdhci_host *host);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment