aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/host/sdhci-brcmstb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/host/sdhci-brcmstb.c')
-rw-r--r--drivers/mmc/host/sdhci-brcmstb.c276
1 files changed, 264 insertions, 12 deletions
diff --git a/drivers/mmc/host/sdhci-brcmstb.c b/drivers/mmc/host/sdhci-brcmstb.c
index 15705e85417f..0b1823ec06c1 100644
--- a/drivers/mmc/host/sdhci-brcmstb.c
+++ b/drivers/mmc/host/sdhci-brcmstb.c
@@ -12,6 +12,8 @@
#include <linux/of.h>
#include <linux/bitops.h>
#include <linux/delay.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/regulator/consumer.h>
#include "sdhci-cqhci.h"
#include "sdhci-pltfm.h"
@@ -28,29 +30,38 @@
#define BRCMSTB_PRIV_FLAGS_HAS_CQE BIT(0)
#define BRCMSTB_PRIV_FLAGS_GATE_CLOCK BIT(1)
+#define BRCMSTB_PRIV_FLAGS_HAS_SD_EXPRESS BIT(2)
#define SDHCI_ARASAN_CQE_BASE_ADDR 0x200
#define SDIO_CFG_CQ_CAPABILITY 0x4c
-#define SDIO_CFG_CQ_CAPABILITY_FMUL GENMASK(13, 12)
+#define SDIO_CFG_CQ_CAPABILITY_FMUL_SHIFT 12
#define SDIO_CFG_CTRL 0x0
#define SDIO_CFG_CTRL_SDCD_N_TEST_EN BIT(31)
#define SDIO_CFG_CTRL_SDCD_N_TEST_LEV BIT(30)
+#define SDIO_CFG_SD_PIN_SEL 0x44
+#define SDIO_CFG_SD_PIN_SEL_MASK 0x3
+#define SDIO_CFG_SD_PIN_SEL_SD BIT(1)
+#define SDIO_CFG_SD_PIN_SEL_MMC BIT(0)
+
#define SDIO_CFG_MAX_50MHZ_MODE 0x1ac
#define SDIO_CFG_MAX_50MHZ_MODE_STRAP_OVERRIDE BIT(31)
#define SDIO_CFG_MAX_50MHZ_MODE_ENABLE BIT(0)
-#define MMC_CAP_HSE_MASK (MMC_CAP2_HSX00_1_2V | MMC_CAP2_HSX00_1_8V)
-/* Select all SD UHS type I SDR speed above 50MB/s */
-#define MMC_CAP_UHS_I_SDR_MASK (MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104)
-
struct sdhci_brcmstb_priv {
void __iomem *cfg_regs;
unsigned int flags;
struct clk *base_clk;
u32 base_freq_hz;
+ struct regulator *sde_1v8;
+ struct device_node *sde_pcie;
+ void *__iomem sde_ioaddr;
+ void *__iomem sde_ioaddr2;
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *pins_default;
+ struct pinctrl_state *pins_sdex;
};
struct brcmstb_match_priv {
@@ -141,6 +152,42 @@ static void sdhci_brcmstb_hs400es(struct mmc_host *mmc, struct mmc_ios *ios)
writel(reg, host->ioaddr + SDHCI_VENDOR);
}
+static void sdhci_bcm2712_set_clock(struct sdhci_host *host, unsigned int clock)
+{
+ u16 clk;
+ u32 reg;
+ bool is_emmc_rate = false;
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_brcmstb_priv *brcmstb_priv = sdhci_pltfm_priv(pltfm_host);
+
+ host->mmc->actual_clock = 0;
+
+ sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
+
+ switch (host->mmc->ios.timing) {
+ case MMC_TIMING_MMC_HS400:
+ case MMC_TIMING_MMC_HS200:
+ case MMC_TIMING_MMC_DDR52:
+ case MMC_TIMING_MMC_HS:
+ is_emmc_rate = true;
+ break;
+ }
+
+ reg = readl(brcmstb_priv->cfg_regs + SDIO_CFG_SD_PIN_SEL);
+ reg &= ~SDIO_CFG_SD_PIN_SEL_MASK;
+ if (is_emmc_rate)
+ reg |= SDIO_CFG_SD_PIN_SEL_MMC;
+ else
+ reg |= SDIO_CFG_SD_PIN_SEL_SD;
+ writel(reg, brcmstb_priv->cfg_regs + SDIO_CFG_SD_PIN_SEL);
+
+ if (clock == 0)
+ return;
+
+ clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock);
+ sdhci_enable_clk(host, clk);
+}
+
static void sdhci_brcmstb_set_clock(struct sdhci_host *host, unsigned int clock)
{
u16 clk;
@@ -156,6 +203,17 @@ static void sdhci_brcmstb_set_clock(struct sdhci_host *host, unsigned int clock)
sdhci_enable_clk(host, clk);
}
+static void sdhci_brcmstb_set_power(struct sdhci_host *host, unsigned char mode,
+ unsigned short vdd)
+{
+ if (!IS_ERR(host->mmc->supply.vmmc)) {
+ struct mmc_host *mmc = host->mmc;
+
+ mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
+ }
+ sdhci_set_power_noreg(host, mode, vdd);
+}
+
static void sdhci_brcmstb_set_uhs_signaling(struct sdhci_host *host,
unsigned int timing)
{
@@ -185,21 +243,41 @@ static void sdhci_brcmstb_set_uhs_signaling(struct sdhci_host *host,
sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
}
+static void sdhci_bcm2712_hs400_downgrade(struct mmc_host *mmc)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ /*
+ * The eMMC PHY and its internal controller parses and validates
+ * the uhs_mode, divisor, pin_sel, and sampling clock select
+ * output from the SD controller. It will refuse to update its
+ * config if HS timings are selected while the clock is >52MHz.
+ * so bump the clock down now before card/controller setup is
+ * performed.
+ */
+ sdhci_bcm2712_set_clock(host, 52000000);
+}
+
static void sdhci_brcmstb_cfginit_2712(struct sdhci_host *host)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_brcmstb_priv *brcmstb_priv = sdhci_pltfm_priv(pltfm_host);
u32 reg;
+ u32 uhs_mask = (MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104);
+ u32 hsemmc_mask = (MMC_CAP2_HS200_1_8V_SDR | MMC_CAP2_HS200_1_2V_SDR |
+ MMC_CAP2_HS400_1_8V | MMC_CAP2_HS400_1_2V);
+ u32 base_clk_mhz;
/*
* If we support a speed that requires tuning,
* then select the delay line PHY as the clock source.
*/
- if ((host->mmc->caps & MMC_CAP_UHS_I_SDR_MASK) || (host->mmc->caps2 & MMC_CAP_HSE_MASK)) {
+ if ((host->mmc->caps & uhs_mask) || (host->mmc->caps2 & hsemmc_mask)) {
reg = readl(brcmstb_priv->cfg_regs + SDIO_CFG_MAX_50MHZ_MODE);
reg &= ~SDIO_CFG_MAX_50MHZ_MODE_ENABLE;
reg |= SDIO_CFG_MAX_50MHZ_MODE_STRAP_OVERRIDE;
writel(reg, brcmstb_priv->cfg_regs + SDIO_CFG_MAX_50MHZ_MODE);
+
+ host->mmc_host_ops.hs400_downgrade = sdhci_bcm2712_hs400_downgrade;
}
if ((host->mmc->caps & MMC_CAP_NONREMOVABLE) ||
@@ -210,6 +288,109 @@ static void sdhci_brcmstb_cfginit_2712(struct sdhci_host *host)
reg |= SDIO_CFG_CTRL_SDCD_N_TEST_EN;
writel(reg, brcmstb_priv->cfg_regs + SDIO_CFG_CTRL);
}
+
+ /* Guesstimate the timer frequency (controller base clock) */
+ base_clk_mhz = max_t(u32, clk_get_rate(pltfm_host->clk) / (1000 * 1000), 1);
+ reg = (3 << SDIO_CFG_CQ_CAPABILITY_FMUL_SHIFT) | base_clk_mhz;
+ writel(reg, brcmstb_priv->cfg_regs + SDIO_CFG_CQ_CAPABILITY);
+}
+
+static int bcm2712_init_sd_express(struct sdhci_host *host, struct mmc_ios *ios)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_brcmstb_priv *brcmstb_priv = sdhci_pltfm_priv(pltfm_host);
+ struct device *dev = host->mmc->parent;
+ u32 ctrl_val;
+ u32 present_state;
+ int ret;
+
+ if (!brcmstb_priv->sde_ioaddr || !brcmstb_priv->sde_ioaddr2)
+ return -EINVAL;
+
+ if (!brcmstb_priv->pinctrl)
+ return -EINVAL;
+
+ /* Turn off the SD clock first */
+ sdhci_set_clock(host, 0);
+
+ /* Disable SD DAT0-3 pulls */
+ pinctrl_select_state(brcmstb_priv->pinctrl, brcmstb_priv->pins_sdex);
+
+ ctrl_val = readl(brcmstb_priv->sde_ioaddr);
+ dev_dbg(dev, "ctrl_val 1 %08x\n", ctrl_val);
+
+ /* Tri-state the SD pins */
+ ctrl_val |= 0x1ff8;
+ writel(ctrl_val, brcmstb_priv->sde_ioaddr);
+ dev_dbg(dev, "ctrl_val 1->%08x (%08x)\n", ctrl_val, readl(brcmstb_priv->sde_ioaddr));
+ /* Let voltages settle */
+ udelay(100);
+
+ /* Enable the PCIe sideband pins */
+ ctrl_val &= ~0x6000;
+ writel(ctrl_val, brcmstb_priv->sde_ioaddr);
+ dev_dbg(dev, "ctrl_val 1->%08x (%08x)\n", ctrl_val, readl(brcmstb_priv->sde_ioaddr));
+ /* Let voltages settle */
+ udelay(100);
+
+ /* Turn on the 1v8 VDD2 regulator */
+ ret = regulator_enable(brcmstb_priv->sde_1v8);
+ if (ret)
+ return ret;
+
+ /* Wait for Tpvcrl */
+ msleep(1);
+
+ /* Sample DAT2 (CLKREQ#) - if low, card is in PCIe mode */
+ present_state = sdhci_readl(host, SDHCI_PRESENT_STATE);
+ present_state = (present_state & SDHCI_DATA_LVL_MASK) >> SDHCI_DATA_LVL_SHIFT;
+ dev_dbg(dev, "state = 0x%08x\n", present_state);
+
+ if (present_state & BIT(2)) {
+ dev_err(dev, "DAT2 still high, abandoning SDex switch\n");
+ return -ENODEV;
+ }
+
+ /* Turn on the LCPLL PTEST mux */
+ ctrl_val = readl(brcmstb_priv->sde_ioaddr2 + 20); // misc5
+ ctrl_val &= ~(0x7 << 7);
+ ctrl_val |= 3 << 7;
+ writel(ctrl_val, brcmstb_priv->sde_ioaddr2 + 20);
+ dev_dbg(dev, "misc 5->%08x (%08x)\n", ctrl_val, readl(brcmstb_priv->sde_ioaddr2 + 20));
+
+ /* PTEST diff driver enable */
+ ctrl_val = readl(brcmstb_priv->sde_ioaddr2);
+ ctrl_val |= BIT(21);
+ writel(ctrl_val, brcmstb_priv->sde_ioaddr2);
+
+ dev_dbg(dev, "misc 0->%08x (%08x)\n", ctrl_val, readl(brcmstb_priv->sde_ioaddr2));
+
+ /* Wait for more than the minimum Tpvpgl time */
+ msleep(100);
+
+ if (brcmstb_priv->sde_pcie) {
+ struct of_changeset changeset;
+ static struct property okay_property = {
+ .name = "status",
+ .value = "okay",
+ .length = 5,
+ };
+
+ /* Enable the pcie controller */
+ of_changeset_init(&changeset);
+ ret = of_changeset_update_property(&changeset,
+ brcmstb_priv->sde_pcie,
+ &okay_property);
+ if (ret) {
+ dev_err(dev, "%s: failed to update property - %d\n", __func__,
+ ret);
+ return -ENODEV;
+ }
+ ret = of_changeset_apply(&changeset);
+ }
+
+ dev_dbg(dev, "%s -> %d\n", __func__, ret);
+ return ret;
}
static void sdhci_brcmstb_dumpregs(struct mmc_host *mmc)
@@ -220,6 +401,7 @@ static void sdhci_brcmstb_dumpregs(struct mmc_host *mmc)
static void sdhci_brcmstb_cqe_enable(struct mmc_host *mmc)
{
struct sdhci_host *host = mmc_priv(mmc);
+ struct cqhci_host *cq_host = mmc->cqe_private;
u32 reg;
reg = sdhci_readl(host, SDHCI_PRESENT_STATE);
@@ -229,6 +411,22 @@ static void sdhci_brcmstb_cqe_enable(struct mmc_host *mmc)
}
sdhci_cqe_enable(mmc);
+
+ /*
+ * The controller resets this register to a very short default interval
+ * whenever CQHCI is disabled.
+ *
+ * For removable cards CBC needs to be clear or card removal can hang
+ * the CQE. In polling mode, a CIT of 0x4000 "cycles" seems to produce the best
+ * throughput.
+ *
+ * For nonremovable cards, the specification default of CBC=1 CIT=0x1000
+ * suffices.
+ */
+ if (mmc->caps & MMC_CAP_NONREMOVABLE)
+ cqhci_writel(cq_host, 0x00011000, CQHCI_SSC1);
+ else
+ cqhci_writel(cq_host, 0x00004000, CQHCI_SSC1);
}
static const struct cqhci_host_ops sdhci_brcmstb_cqhci_ops = {
@@ -245,11 +443,12 @@ static struct sdhci_ops sdhci_brcmstb_ops = {
};
static struct sdhci_ops sdhci_brcmstb_ops_2712 = {
- .set_clock = sdhci_set_clock,
- .set_power = sdhci_set_power_and_bus_voltage,
+ .set_clock = sdhci_bcm2712_set_clock,
+ .set_power = sdhci_brcmstb_set_power,
.set_bus_width = sdhci_set_bus_width,
- .reset = sdhci_reset,
+ .reset = brcmstb_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
+ .init_sd_express = bcm2712_init_sd_express,
};
static struct sdhci_ops sdhci_brcmstb_ops_7216 = {
@@ -267,6 +466,8 @@ static struct sdhci_ops sdhci_brcmstb_ops_74165b0 = {
};
static const struct brcmstb_match_priv match_priv_2712 = {
+ .flags = BRCMSTB_MATCH_FLAGS_USE_CARD_BUSY,
+ .hs400es = sdhci_brcmstb_hs400es,
.cfginit = sdhci_brcmstb_cfginit_2712,
.ops = &sdhci_brcmstb_ops_2712,
};
@@ -370,8 +571,10 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev)
struct sdhci_pltfm_host *pltfm_host;
const struct of_device_id *match;
struct sdhci_brcmstb_priv *priv;
- u32 actual_clock_mhz;
+ u32 actual_clock_mhz, cqe;
struct sdhci_host *host;
+ struct resource *iomem;
+ bool no_pinctrl = false;
struct clk *clk;
struct clk *base_clk = NULL;
int res;
@@ -394,12 +597,21 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev)
return PTR_ERR(host);
pltfm_host = sdhci_priv(host);
+ pltfm_host->clk = clk;
+
priv = sdhci_pltfm_priv(pltfm_host);
- if (device_property_read_bool(&pdev->dev, "supports-cqe")) {
+ cqe = 0;
+ device_property_read_u32(&pdev->dev, "supports-cqe", &cqe);
+ if (cqe > 0) {
priv->flags |= BRCMSTB_PRIV_FLAGS_HAS_CQE;
match_priv->ops->irq = sdhci_brcmstb_cqhci_irq;
}
+ priv->sde_pcie = of_parse_phandle(pdev->dev.of_node,
+ "sde-pcie", 0);
+ if (priv->sde_pcie)
+ priv->flags |= BRCMSTB_PRIV_FLAGS_HAS_SD_EXPRESS;
+
/* Map in the non-standard CFG registers */
priv->cfg_regs = devm_platform_get_and_ioremap_resource(pdev, 1, NULL);
if (IS_ERR(priv->cfg_regs)) {
@@ -412,6 +624,43 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev)
if (res)
goto err;
+ priv->sde_1v8 = devm_regulator_get_optional(&pdev->dev, "sde-1v8");
+ if (IS_ERR(priv->sde_1v8))
+ priv->flags &= ~BRCMSTB_PRIV_FLAGS_HAS_SD_EXPRESS;
+
+ iomem = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+ if (iomem) {
+ priv->sde_ioaddr = devm_ioremap_resource(&pdev->dev, iomem);
+ if (IS_ERR(priv->sde_ioaddr))
+ priv->sde_ioaddr = NULL;
+ }
+
+ iomem = platform_get_resource(pdev, IORESOURCE_MEM, 3);
+ if (iomem) {
+ priv->sde_ioaddr2 = devm_ioremap_resource(&pdev->dev, iomem);
+ if (IS_ERR(priv->sde_ioaddr2))
+ priv->sde_ioaddr = NULL;
+ }
+
+ priv->pinctrl = devm_pinctrl_get(&pdev->dev);
+ if (IS_ERR(priv->pinctrl)) {
+ no_pinctrl = true;
+ }
+ priv->pins_default = pinctrl_lookup_state(priv->pinctrl, "default");
+ if (IS_ERR(priv->pins_default)) {
+ dev_dbg(&pdev->dev, "No pinctrl default state\n");
+ no_pinctrl = true;
+ }
+ priv->pins_sdex = pinctrl_lookup_state(priv->pinctrl, "sd-express");
+ if (IS_ERR(priv->pins_sdex)) {
+ dev_dbg(&pdev->dev, "No pinctrl sd-express state\n");
+ no_pinctrl = true;
+ }
+ if (no_pinctrl || !priv->sde_ioaddr || !priv->sde_ioaddr2) {
+ priv->pinctrl = NULL;
+ priv->flags &= ~BRCMSTB_PRIV_FLAGS_HAS_SD_EXPRESS;
+ }
+
/*
* Automatic clock gating does not work for SD cards that may
* voltage switch so only enable it for non-removable devices.
@@ -428,6 +677,10 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev)
(host->mmc->caps2 & MMC_CAP2_HS400_ES))
host->mmc_host_ops.hs400_enhanced_strobe = match_priv->hs400es;
+ if (host->ops->init_sd_express &&
+ (priv->flags & BRCMSTB_PRIV_FLAGS_HAS_SD_EXPRESS))
+ host->mmc->caps2 |= MMC_CAP2_SD_EXP;
+
if (match_priv->cfginit)
match_priv->cfginit(host);
@@ -481,7 +734,6 @@ add_host:
if (res)
goto err;
- pltfm_host->clk = clk;
return res;
err: