From d1d0fb1e963a4a0f6c004dafc785393b1132de64 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 29 Oct 2020 09:57:16 +0800 Subject: [PATCH] mmc: brcmstb: add support for BCM2712 BCM2712 has an SD Express capable SDHCI implementation and uses the SDIO CFG register block present on other STB chips. Add plumbing for SD Express handover and BCM2712-specific functions. Due to the common bus infrastructure between BCM2711 and BCM2712, the driver also needs to implement 32-bit IO accessors. mmc: brcmstb: override card presence if broken-cd is set Not just if the card is declared as nonremovable. sdhci: brcmstb: align SD express switchover with SD spec v8.00 Part 1 of the Physical specification, figure 3-24, details the switch sequence for cards initially probed as SD. Add a missing check for DAT2 level after switching VDD2 on. sdhci: brcmstb: clean up SD Express probe and error handling Refactor to avoid spurious error messages in dmesg if the requisite SD Express DT nodes aren't present. Signed-off-by: Jonathan Bell mmc: sdhci-brcmstb: only use the delay line PHY for tuneable speeds The MMC core has a 200MHz core clock which allows the use of DDR50 and below without incremental phase tuning. SDR50/SDR104 and the EMMC HS200 speeds require tuning. Signed-off-by: Jonathan Bell --- drivers/mmc/host/Kconfig | 2 + drivers/mmc/host/sdhci-brcmstb.c | 357 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 359 insertions(+) diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index d71dc5c..0613d46 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -1039,7 +1039,9 @@ config MMC_SDHCI_BRCMSTB tristate "Broadcom SDIO/SD/MMC support" depends on ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST depends on MMC_SDHCI_PLTFM + select MMC_SDHCI_IO_ACCESSORS select MMC_CQHCI + select OF_DYNAMIC default ARCH_BRCMSTB || BMIPS_GENERIC help This selects support for the SDIO/SD/MMC Host Controller on diff --git a/drivers/mmc/host/sdhci-brcmstb.c b/drivers/mmc/host/sdhci-brcmstb.c index c23251b..6024125 100644 --- a/drivers/mmc/host/sdhci-brcmstb.c +++ b/drivers/mmc/host/sdhci-brcmstb.c @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include "sdhci-cqhci.h" #include "sdhci-pltfm.h" @@ -26,18 +28,43 @@ #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_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_CARD BIT(1) + +#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) + struct sdhci_brcmstb_priv { void __iomem *cfg_regs; unsigned int flags; struct clk *base_clk; u32 base_freq_hz; + u32 shadow_cmd; + u32 shadow_blk; + bool is_cmd_shadowed; + bool is_blk_shadowed; + 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 { void (*hs400es)(struct mmc_host *mmc, struct mmc_ios *ios); + void (*cfginit)(struct sdhci_host *host); struct sdhci_ops *ops; const unsigned int flags; }; @@ -94,6 +121,124 @@ static void sdhci_brcmstb_set_clock(struct sdhci_host *host, unsigned int clock) sdhci_enable_clk(host, clk); } +#define REG_OFFSET_IN_BITS(reg) ((reg) << 3 & 0x18) + +static inline u32 sdhci_brcmstb_32only_readl(struct sdhci_host *host, int reg) +{ + u32 val = readl(host->ioaddr + reg); + + pr_debug("%s: readl [0x%02x] 0x%08x\n", + mmc_hostname(host->mmc), reg, val); + return val; +} + +static u16 sdhci_brcmstb_32only_readw(struct sdhci_host *host, int reg) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_brcmstb_priv *brcmstb_priv = sdhci_pltfm_priv(pltfm_host); + u32 val; + u16 word; + + if ((reg == SDHCI_TRANSFER_MODE) && brcmstb_priv->is_cmd_shadowed) { + /* Get the saved transfer mode */ + val = brcmstb_priv->shadow_cmd; + } else if ((reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) && + brcmstb_priv->is_blk_shadowed) { + /* Get the saved block info */ + val = brcmstb_priv->shadow_blk; + } else { + val = sdhci_brcmstb_32only_readl(host, (reg & ~3)); + } + word = val >> REG_OFFSET_IN_BITS(reg) & 0xffff; + return word; +} + +static u8 sdhci_brcmstb_32only_readb(struct sdhci_host *host, int reg) +{ + u32 val = sdhci_brcmstb_32only_readl(host, (reg & ~3)); + u8 byte = val >> REG_OFFSET_IN_BITS(reg) & 0xff; + return byte; +} + +static inline void sdhci_brcmstb_32only_writel(struct sdhci_host *host, u32 val, int reg) +{ + pr_debug("%s: writel [0x%02x] 0x%08x\n", + mmc_hostname(host->mmc), reg, val); + + writel(val, host->ioaddr + reg); +} + +/* + * BCM2712 unfortunately carries with it a perennial bug with the SD controller + * register interface present on previous chips (2711/2709/2708). Accesses must + * be dword-sized and a read-modify-write cycle to the 32-bit registers + * containing the COMMAND, TRANSFER_MODE, BLOCK_SIZE and BLOCK_COUNT registers + * tramples the upper/lower 16 bits of data written. BCM2712 does not seem to + * need the extreme delay between each write as on previous chips, just the + * serialisation of writes to these registers in a single 32-bit operation. + */ +static void sdhci_brcmstb_32only_writew(struct sdhci_host *host, u16 val, int reg) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_brcmstb_priv *brcmstb_priv = sdhci_pltfm_priv(pltfm_host); + u32 word_shift = REG_OFFSET_IN_BITS(reg); + u32 mask = 0xffff << word_shift; + u32 oldval, newval; + + if (reg == SDHCI_COMMAND) { + /* Write the block now as we are issuing a command */ + if (brcmstb_priv->is_blk_shadowed) { + sdhci_brcmstb_32only_writel(host, brcmstb_priv->shadow_blk, + SDHCI_BLOCK_SIZE); + brcmstb_priv->is_blk_shadowed = false; + } + oldval = brcmstb_priv->shadow_cmd; + brcmstb_priv->is_cmd_shadowed = false; + } else if ((reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) && + brcmstb_priv->is_blk_shadowed) { + /* Block size and count are stored in shadow reg */ + oldval = brcmstb_priv->shadow_blk; + } else { + /* Read reg, all other registers are not shadowed */ + oldval = sdhci_brcmstb_32only_readl(host, (reg & ~3)); + } + newval = (oldval & ~mask) | (val << word_shift); + + if (reg == SDHCI_TRANSFER_MODE) { + /* Save the transfer mode until the command is issued */ + brcmstb_priv->shadow_cmd = newval; + brcmstb_priv->is_cmd_shadowed = true; + } else if (reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) { + /* Save the block info until the command is issued */ + brcmstb_priv->shadow_blk = newval; + brcmstb_priv->is_blk_shadowed = true; + } else { + /* Command or other regular 32-bit write */ + sdhci_brcmstb_32only_writel(host, newval, reg & ~3); + } +} + +static void sdhci_brcmstb_32only_writeb(struct sdhci_host *host, u8 val, int reg) +{ + u32 oldval = sdhci_brcmstb_32only_readl(host, (reg & ~3)); + u32 byte_shift = REG_OFFSET_IN_BITS(reg); + u32 mask = 0xff << byte_shift; + u32 newval = (oldval & ~mask) | (val << byte_shift); + + sdhci_brcmstb_32only_writel(host, newval, reg & ~3); +} + +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) { @@ -123,6 +268,146 @@ static void sdhci_brcmstb_set_uhs_signaling(struct sdhci_host *host, sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); } +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); + bool want_dll = false; + 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 reg; + + if (!(host->quirks2 & SDHCI_QUIRK2_NO_1_8_V)) { + if((host->mmc->caps & uhs_mask) || (host->mmc->caps2 & hsemmc_mask)) + want_dll = true; + } + + /* + * If we want a speed that requires tuning, + * then select the delay line PHY as the clock source. + */ + if (want_dll) { + 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); + } + + if ((host->mmc->caps & MMC_CAP_NONREMOVABLE) || + (host->mmc->caps & MMC_CAP_NEEDS_POLL)) { + /* Force presence */ + reg = readl(brcmstb_priv->cfg_regs + SDIO_CFG_CTRL); + reg &= ~SDIO_CFG_CTRL_SDCD_N_TEST_LEV; + reg |= SDIO_CFG_CTRL_SDCD_N_TEST_EN; + writel(reg, brcmstb_priv->cfg_regs + SDIO_CFG_CTRL); + } else { + /* Enable card detection line */ + reg = readl(brcmstb_priv->cfg_regs + SDIO_CFG_SD_PIN_SEL); + reg &= ~SDIO_CFG_SD_PIN_SEL_MASK; + reg |= SDIO_CFG_SD_PIN_SEL_CARD; + writel(reg, brcmstb_priv->cfg_regs + SDIO_CFG_SD_PIN_SEL); + } +} + +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) { sdhci_dumpregs(mmc_priv(mmc)); @@ -155,6 +440,21 @@ static struct sdhci_ops sdhci_brcmstb_ops = { .set_uhs_signaling = sdhci_set_uhs_signaling, }; +static struct sdhci_ops sdhci_brcmstb_ops_2712 = { + .read_l = sdhci_brcmstb_32only_readl, + .read_w = sdhci_brcmstb_32only_readw, + .read_b = sdhci_brcmstb_32only_readb, + .write_l = sdhci_brcmstb_32only_writel, + .write_w = sdhci_brcmstb_32only_writew, + .write_b = sdhci_brcmstb_32only_writeb, + .set_clock = sdhci_set_clock, + .set_power = sdhci_brcmstb_set_power, + .set_bus_width = sdhci_set_bus_width, + .reset = sdhci_reset, + .set_uhs_signaling = sdhci_set_uhs_signaling, + .init_sd_express = bcm2712_init_sd_express, +}; + static struct sdhci_ops sdhci_brcmstb_ops_7216 = { .set_clock = sdhci_brcmstb_set_clock, .set_bus_width = sdhci_set_bus_width, @@ -179,10 +479,16 @@ static const struct brcmstb_match_priv match_priv_7216 = { .ops = &sdhci_brcmstb_ops_7216, }; +static const struct brcmstb_match_priv match_priv_2712 = { + .cfginit = sdhci_brcmstb_cfginit_2712, + .ops = &sdhci_brcmstb_ops_2712, +}; + static const struct of_device_id __maybe_unused sdhci_brcm_of_match[] = { { .compatible = "brcm,bcm7425-sdhci", .data = &match_priv_7425 }, { .compatible = "brcm,bcm7445-sdhci", .data = &match_priv_7445 }, { .compatible = "brcm,bcm7216-sdhci", .data = &match_priv_7216 }, + { .compatible = "brcm,bcm2712-sdhci", .data = &match_priv_2712 }, {}, }; @@ -255,6 +561,8 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev) struct sdhci_brcmstb_priv *priv; u32 actual_clock_mhz; struct sdhci_host *host; + struct resource *iomem; + bool no_pinctrl = false; struct clk *clk; struct clk *base_clk = NULL; int res; @@ -283,6 +591,11 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev) 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)) { @@ -295,6 +608,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. @@ -311,6 +661,13 @@ 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); + /* * Supply the existing CAPS, but clear the UHS modes. This * will allow these modes to be specified by device tree -- 2.7.4