diff options
Diffstat (limited to 'target/linux/bcm27xx/patches-6.1/950-0859-mmc-brcmstb-add-support-for-BCM2712.patch')
-rw-r--r-- | target/linux/bcm27xx/patches-6.1/950-0859-mmc-brcmstb-add-support-for-BCM2712.patch | 498 |
1 files changed, 0 insertions, 498 deletions
diff --git a/target/linux/bcm27xx/patches-6.1/950-0859-mmc-brcmstb-add-support-for-BCM2712.patch b/target/linux/bcm27xx/patches-6.1/950-0859-mmc-brcmstb-add-support-for-BCM2712.patch deleted file mode 100644 index 05d403a63e..0000000000 --- a/target/linux/bcm27xx/patches-6.1/950-0859-mmc-brcmstb-add-support-for-BCM2712.patch +++ /dev/null @@ -1,498 +0,0 @@ -From b627647c4500d39cb026924b608841fdf4d4d7e9 Mon Sep 17 00:00:00 2001 -From: Ulf Hansson <ulf.hansson@linaro.org> -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 <jonathan@raspberrypi.com> - -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 <jonathan@raspberrypi.com> ---- - drivers/mmc/host/Kconfig | 2 + - drivers/mmc/host/sdhci-brcmstb.c | 356 +++++++++++++++++++++++++++++++ - 2 files changed, 358 insertions(+) - ---- a/drivers/mmc/host/Kconfig -+++ b/drivers/mmc/host/Kconfig -@@ -1082,7 +1082,9 @@ config MMC_SDHCI_BRCMSTB - tristate "Broadcom SDIO/SD/MMC support" - depends on ARCH_BRCMSTB || BMIPS_GENERIC - depends on MMC_SDHCI_PLTFM -+ select MMC_SDHCI_IO_ACCESSORS - select MMC_CQHCI -+ select OF_DYNAMIC - default y - help - This selects support for the SDIO/SD/MMC Host Controller on ---- a/drivers/mmc/host/sdhci-brcmstb.c -+++ b/drivers/mmc/host/sdhci-brcmstb.c -@@ -11,6 +11,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" -@@ -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(stru - 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_signal - 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_op - .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 m - .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 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 }, - {}, - }; - -@@ -256,6 +562,7 @@ static int sdhci_brcmstb_probe(struct pl - 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; -@@ -290,6 +597,11 @@ static int sdhci_brcmstb_probe(struct pl - 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 */ - iomem = platform_get_resource(pdev, IORESOURCE_MEM, 1); - priv->cfg_regs = devm_ioremap_resource(&pdev->dev, iomem); -@@ -303,6 +615,43 @@ static int sdhci_brcmstb_probe(struct pl - 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. -@@ -319,6 +668,13 @@ static int sdhci_brcmstb_probe(struct pl - (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 |