Skip to content

Commit b5dbcf1

Browse files
blarson866Ulf Hansson
authored andcommitted
mmc: sdhci-cadence: Add AMD Pensando Elba SoC support
Add support for AMD Pensando Elba SoC which explicitly controls byte-lane enables on writes. Select MMC_SDHCI_IO_ACCESSORS for MMC_SDHCI_CADENCE which allows Elba SoC sdhci_elba_ops to overwrite the SDHCI IO memory accessors Signed-off-by: Brad Larson <blarson@amd.com> Acked-by: Adrian Hunter <adrian.hunter@intel.com> Link: https://lore.kernel.org/r/20230410184526.15990-14-blarson@amd.com Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
1 parent e095b78 commit b5dbcf1

2 files changed

Lines changed: 99 additions & 0 deletions

File tree

drivers/mmc/host/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ config MMC_SDHCI_CADENCE
255255
tristate "SDHCI support for the Cadence SD/SDIO/eMMC controller"
256256
depends on MMC_SDHCI_PLTFM
257257
depends on OF
258+
select MMC_SDHCI_IO_ACCESSORS
258259
help
259260
This selects the Cadence SD/SDIO/eMMC driver.
260261

drivers/mmc/host/sdhci-cadence.c

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ struct sdhci_cdns_phy_param {
6666

6767
struct sdhci_cdns_priv {
6868
void __iomem *hrs_addr;
69+
void __iomem *ctl_addr; /* write control */
70+
spinlock_t wrlock; /* write lock */
6971
bool enhanced_strobe;
7072
void (*priv_writel)(struct sdhci_cdns_priv *priv, u32 val, void __iomem *reg);
7173
unsigned int nr_phy_params;
@@ -321,6 +323,91 @@ static void sdhci_cdns_set_uhs_signaling(struct sdhci_host *host,
321323
sdhci_set_uhs_signaling(host, timing);
322324
}
323325

326+
/* Elba control register bits [6:3] are byte-lane enables */
327+
#define ELBA_BYTE_ENABLE_MASK(x) ((x) << 3)
328+
329+
/*
330+
* The Pensando Elba SoC explicitly controls byte-lane enabling on writes
331+
* which includes writes to the HRS registers. The write lock (wrlock)
332+
* is used to ensure byte-lane enable, using write control (ctl_addr),
333+
* occurs before the data write.
334+
*/
335+
static void elba_priv_writel(struct sdhci_cdns_priv *priv, u32 val,
336+
void __iomem *reg)
337+
{
338+
unsigned long flags;
339+
340+
spin_lock_irqsave(&priv->wrlock, flags);
341+
writel(GENMASK(7, 3), priv->ctl_addr);
342+
writel(val, reg);
343+
spin_unlock_irqrestore(&priv->wrlock, flags);
344+
}
345+
346+
static void elba_write_l(struct sdhci_host *host, u32 val, int reg)
347+
{
348+
elba_priv_writel(sdhci_cdns_priv(host), val, host->ioaddr + reg);
349+
}
350+
351+
static void elba_write_w(struct sdhci_host *host, u16 val, int reg)
352+
{
353+
struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
354+
u32 shift = reg & GENMASK(1, 0);
355+
unsigned long flags;
356+
u32 byte_enables;
357+
358+
byte_enables = GENMASK(1, 0) << shift;
359+
spin_lock_irqsave(&priv->wrlock, flags);
360+
writel(ELBA_BYTE_ENABLE_MASK(byte_enables), priv->ctl_addr);
361+
writew(val, host->ioaddr + reg);
362+
spin_unlock_irqrestore(&priv->wrlock, flags);
363+
}
364+
365+
static void elba_write_b(struct sdhci_host *host, u8 val, int reg)
366+
{
367+
struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
368+
u32 shift = reg & GENMASK(1, 0);
369+
unsigned long flags;
370+
u32 byte_enables;
371+
372+
byte_enables = BIT(0) << shift;
373+
spin_lock_irqsave(&priv->wrlock, flags);
374+
writel(ELBA_BYTE_ENABLE_MASK(byte_enables), priv->ctl_addr);
375+
writeb(val, host->ioaddr + reg);
376+
spin_unlock_irqrestore(&priv->wrlock, flags);
377+
}
378+
379+
static const struct sdhci_ops sdhci_elba_ops = {
380+
.write_l = elba_write_l,
381+
.write_w = elba_write_w,
382+
.write_b = elba_write_b,
383+
.set_clock = sdhci_set_clock,
384+
.get_timeout_clock = sdhci_cdns_get_timeout_clock,
385+
.set_bus_width = sdhci_set_bus_width,
386+
.reset = sdhci_reset,
387+
.set_uhs_signaling = sdhci_cdns_set_uhs_signaling,
388+
};
389+
390+
static int elba_drv_init(struct platform_device *pdev)
391+
{
392+
struct sdhci_host *host = platform_get_drvdata(pdev);
393+
struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
394+
void __iomem *ioaddr;
395+
396+
host->mmc->caps |= MMC_CAP_1_8V_DDR | MMC_CAP_8_BIT_DATA;
397+
spin_lock_init(&priv->wrlock);
398+
399+
/* Byte-lane control register */
400+
ioaddr = devm_platform_ioremap_resource(pdev, 1);
401+
if (IS_ERR(ioaddr))
402+
return PTR_ERR(ioaddr);
403+
404+
priv->ctl_addr = ioaddr;
405+
priv->priv_writel = elba_priv_writel;
406+
writel(ELBA_BYTE_ENABLE_MASK(0xf), priv->ctl_addr);
407+
408+
return 0;
409+
}
410+
324411
static const struct sdhci_ops sdhci_cdns_ops = {
325412
.set_clock = sdhci_set_clock,
326413
.get_timeout_clock = sdhci_cdns_get_timeout_clock,
@@ -337,6 +424,13 @@ static const struct sdhci_cdns_drv_data sdhci_cdns_uniphier_drv_data = {
337424
},
338425
};
339426

427+
static const struct sdhci_cdns_drv_data sdhci_elba_drv_data = {
428+
.init = elba_drv_init,
429+
.pltfm_data = {
430+
.ops = &sdhci_elba_ops,
431+
},
432+
};
433+
340434
static const struct sdhci_cdns_drv_data sdhci_cdns_drv_data = {
341435
.pltfm_data = {
342436
.ops = &sdhci_cdns_ops,
@@ -477,6 +571,10 @@ static const struct of_device_id sdhci_cdns_match[] = {
477571
.compatible = "socionext,uniphier-sd4hc",
478572
.data = &sdhci_cdns_uniphier_drv_data,
479573
},
574+
{
575+
.compatible = "amd,pensando-elba-sd4hc",
576+
.data = &sdhci_elba_drv_data,
577+
},
480578
{ .compatible = "cdns,sd4hc" },
481579
{ /* sentinel */ }
482580
};

0 commit comments

Comments
 (0)