Skip to content

Commit 78ab82f

Browse files
alcooperstorulf
authored andcommitted
mmc: sdhci-brcmstb: Add ability to use HS400ES transfer mode
The latest eMMC JEDEC specification version 5.1 added a new transfer mode, HS400 with enhanced strobe (HS400ES). This mode will be selected if both the host controller and eMMC device support it. The latest Arasan 5.1 controller in the 7216a0 supports this mode. The "Host Controller Specification" has not been updated so the controller register bit used to enable this mode is not specified and varies the with controller vendor. The Linux SDHCI driver supplies a callback for enabling HS400ES mode and that callback will be used to supply a routine that will set the proper bit in the Arasan Vendor register. Signed-off-by: Al Cooper <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Ulf Hansson <[email protected]>
1 parent 61696bb commit 78ab82f

File tree

1 file changed

+86
-11
lines changed

1 file changed

+86
-11
lines changed

drivers/mmc/host/sdhci-brcmstb.c

Lines changed: 86 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,41 @@
99
#include <linux/mmc/host.h>
1010
#include <linux/module.h>
1111
#include <linux/of.h>
12+
#include <linux/bitops.h>
1213

1314
#include "sdhci-pltfm.h"
1415

16+
#define SDHCI_VENDOR 0x78
17+
#define SDHCI_VENDOR_ENHANCED_STRB 0x1
18+
19+
#define BRCMSTB_PRIV_FLAGS_NO_64BIT BIT(0)
20+
#define BRCMSTB_PRIV_FLAGS_BROKEN_TIMEOUT BIT(1)
21+
22+
struct sdhci_brcmstb_priv {
23+
void __iomem *cfg_regs;
24+
};
25+
26+
struct brcmstb_match_priv {
27+
void (*hs400es)(struct mmc_host *mmc, struct mmc_ios *ios);
28+
unsigned int flags;
29+
};
30+
31+
static void sdhci_brcmstb_hs400es(struct mmc_host *mmc, struct mmc_ios *ios)
32+
{
33+
struct sdhci_host *host = mmc_priv(mmc);
34+
35+
u32 reg;
36+
37+
dev_dbg(mmc_dev(mmc), "%s(): Setting HS400-Enhanced-Strobe mode\n",
38+
__func__);
39+
reg = readl(host->ioaddr + SDHCI_VENDOR);
40+
if (ios->enhanced_strobe)
41+
reg |= SDHCI_VENDOR_ENHANCED_STRB;
42+
else
43+
reg &= ~SDHCI_VENDOR_ENHANCED_STRB;
44+
writel(reg, host->ioaddr + SDHCI_VENDOR);
45+
}
46+
1547
static const struct sdhci_ops sdhci_brcmstb_ops = {
1648
.set_clock = sdhci_set_clock,
1749
.set_bus_width = sdhci_set_bus_width,
@@ -23,13 +55,40 @@ static const struct sdhci_pltfm_data sdhci_brcmstb_pdata = {
2355
.ops = &sdhci_brcmstb_ops,
2456
};
2557

58+
static const struct brcmstb_match_priv match_priv_7425 = {
59+
.flags = BRCMSTB_PRIV_FLAGS_NO_64BIT |
60+
BRCMSTB_PRIV_FLAGS_BROKEN_TIMEOUT,
61+
};
62+
63+
static const struct brcmstb_match_priv match_priv_7445 = {
64+
.flags = BRCMSTB_PRIV_FLAGS_BROKEN_TIMEOUT,
65+
};
66+
67+
static const struct brcmstb_match_priv match_priv_7216 = {
68+
.hs400es = sdhci_brcmstb_hs400es,
69+
};
70+
71+
static const struct of_device_id sdhci_brcm_of_match[] = {
72+
{ .compatible = "brcm,bcm7425-sdhci", .data = &match_priv_7425 },
73+
{ .compatible = "brcm,bcm7445-sdhci", .data = &match_priv_7445 },
74+
{ .compatible = "brcm,bcm7216-sdhci", .data = &match_priv_7216 },
75+
{},
76+
};
77+
2678
static int sdhci_brcmstb_probe(struct platform_device *pdev)
2779
{
28-
struct sdhci_host *host;
80+
const struct brcmstb_match_priv *match_priv;
2981
struct sdhci_pltfm_host *pltfm_host;
82+
const struct of_device_id *match;
83+
struct sdhci_brcmstb_priv *priv;
84+
struct sdhci_host *host;
85+
struct resource *iomem;
3086
struct clk *clk;
3187
int res;
3288

89+
match = of_match_node(sdhci_brcm_of_match, pdev->dev.of_node);
90+
match_priv = match->data;
91+
3392
clk = devm_clk_get(&pdev->dev, NULL);
3493
if (IS_ERR(clk)) {
3594
dev_err(&pdev->dev, "Clock not found in Device Tree\n");
@@ -39,36 +98,57 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev)
3998
if (res)
4099
return res;
41100

42-
host = sdhci_pltfm_init(pdev, &sdhci_brcmstb_pdata, 0);
101+
host = sdhci_pltfm_init(pdev, &sdhci_brcmstb_pdata,
102+
sizeof(struct sdhci_brcmstb_priv));
43103
if (IS_ERR(host)) {
44104
res = PTR_ERR(host);
45105
goto err_clk;
46106
}
47107

108+
pltfm_host = sdhci_priv(host);
109+
priv = sdhci_pltfm_priv(pltfm_host);
110+
111+
/* Map in the non-standard CFG registers */
112+
iomem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
113+
priv->cfg_regs = devm_ioremap_resource(&pdev->dev, iomem);
114+
if (IS_ERR(priv->cfg_regs)) {
115+
res = PTR_ERR(priv->cfg_regs);
116+
goto err;
117+
}
118+
48119
sdhci_get_of_property(pdev);
49120
res = mmc_of_parse(host->mmc);
50121
if (res)
51122
goto err;
52123

124+
/*
125+
* If the chip has enhanced strobe and it's enabled, add
126+
* callback
127+
*/
128+
if (match_priv->hs400es &&
129+
(host->mmc->caps2 & MMC_CAP2_HS400_ES))
130+
host->mmc_host_ops.hs400_enhanced_strobe = match_priv->hs400es;
131+
53132
/*
54133
* Supply the existing CAPS, but clear the UHS modes. This
55134
* will allow these modes to be specified by device tree
56135
* properties through mmc_of_parse().
57136
*/
58137
host->caps = sdhci_readl(host, SDHCI_CAPABILITIES);
59-
if (of_device_is_compatible(pdev->dev.of_node, "brcm,bcm7425-sdhci"))
138+
if (match_priv->flags & BRCMSTB_PRIV_FLAGS_NO_64BIT)
60139
host->caps &= ~SDHCI_CAN_64BIT;
61140
host->caps1 = sdhci_readl(host, SDHCI_CAPABILITIES_1);
62141
host->caps1 &= ~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_SDR104 |
63142
SDHCI_SUPPORT_DDR50);
64-
host->quirks |= SDHCI_QUIRK_MISSING_CAPS |
65-
SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
143+
host->quirks |= SDHCI_QUIRK_MISSING_CAPS;
144+
145+
if (match_priv->flags & BRCMSTB_PRIV_FLAGS_BROKEN_TIMEOUT)
146+
host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
66147

67148
res = sdhci_add_host(host);
68149
if (res)
69150
goto err;
70151

71-
pltfm_host = sdhci_priv(host);
72152
pltfm_host->clk = clk;
73153
return res;
74154

@@ -79,11 +159,6 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev)
79159
return res;
80160
}
81161

82-
static const struct of_device_id sdhci_brcm_of_match[] = {
83-
{ .compatible = "brcm,bcm7425-sdhci" },
84-
{ .compatible = "brcm,bcm7445-sdhci" },
85-
{},
86-
};
87162
MODULE_DEVICE_TABLE(of, sdhci_brcm_of_match);
88163

89164
static struct platform_driver sdhci_brcmstb_driver = {

0 commit comments

Comments
 (0)