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>
This commit is contained in:
Brad Larson 2023-04-10 11:45:24 -07:00 коммит произвёл Ulf Hansson
Родитель e095b78ef2
Коммит b5dbcf1f1d
2 изменённых файлов: 99 добавлений и 0 удалений

Просмотреть файл

@ -255,6 +255,7 @@ config MMC_SDHCI_CADENCE
tristate "SDHCI support for the Cadence SD/SDIO/eMMC controller"
depends on MMC_SDHCI_PLTFM
depends on OF
select MMC_SDHCI_IO_ACCESSORS
help
This selects the Cadence SD/SDIO/eMMC driver.

Просмотреть файл

@ -66,6 +66,8 @@ struct sdhci_cdns_phy_param {
struct sdhci_cdns_priv {
void __iomem *hrs_addr;
void __iomem *ctl_addr; /* write control */
spinlock_t wrlock; /* write lock */
bool enhanced_strobe;
void (*priv_writel)(struct sdhci_cdns_priv *priv, u32 val, void __iomem *reg);
unsigned int nr_phy_params;
@ -321,6 +323,91 @@ static void sdhci_cdns_set_uhs_signaling(struct sdhci_host *host,
sdhci_set_uhs_signaling(host, timing);
}
/* Elba control register bits [6:3] are byte-lane enables */
#define ELBA_BYTE_ENABLE_MASK(x) ((x) << 3)
/*
* The Pensando Elba SoC explicitly controls byte-lane enabling on writes
* which includes writes to the HRS registers. The write lock (wrlock)
* is used to ensure byte-lane enable, using write control (ctl_addr),
* occurs before the data write.
*/
static void elba_priv_writel(struct sdhci_cdns_priv *priv, u32 val,
void __iomem *reg)
{
unsigned long flags;
spin_lock_irqsave(&priv->wrlock, flags);
writel(GENMASK(7, 3), priv->ctl_addr);
writel(val, reg);
spin_unlock_irqrestore(&priv->wrlock, flags);
}
static void elba_write_l(struct sdhci_host *host, u32 val, int reg)
{
elba_priv_writel(sdhci_cdns_priv(host), val, host->ioaddr + reg);
}
static void elba_write_w(struct sdhci_host *host, u16 val, int reg)
{
struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
u32 shift = reg & GENMASK(1, 0);
unsigned long flags;
u32 byte_enables;
byte_enables = GENMASK(1, 0) << shift;
spin_lock_irqsave(&priv->wrlock, flags);
writel(ELBA_BYTE_ENABLE_MASK(byte_enables), priv->ctl_addr);
writew(val, host->ioaddr + reg);
spin_unlock_irqrestore(&priv->wrlock, flags);
}
static void elba_write_b(struct sdhci_host *host, u8 val, int reg)
{
struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
u32 shift = reg & GENMASK(1, 0);
unsigned long flags;
u32 byte_enables;
byte_enables = BIT(0) << shift;
spin_lock_irqsave(&priv->wrlock, flags);
writel(ELBA_BYTE_ENABLE_MASK(byte_enables), priv->ctl_addr);
writeb(val, host->ioaddr + reg);
spin_unlock_irqrestore(&priv->wrlock, flags);
}
static const struct sdhci_ops sdhci_elba_ops = {
.write_l = elba_write_l,
.write_w = elba_write_w,
.write_b = elba_write_b,
.set_clock = sdhci_set_clock,
.get_timeout_clock = sdhci_cdns_get_timeout_clock,
.set_bus_width = sdhci_set_bus_width,
.reset = sdhci_reset,
.set_uhs_signaling = sdhci_cdns_set_uhs_signaling,
};
static int elba_drv_init(struct platform_device *pdev)
{
struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
void __iomem *ioaddr;
host->mmc->caps |= MMC_CAP_1_8V_DDR | MMC_CAP_8_BIT_DATA;
spin_lock_init(&priv->wrlock);
/* Byte-lane control register */
ioaddr = devm_platform_ioremap_resource(pdev, 1);
if (IS_ERR(ioaddr))
return PTR_ERR(ioaddr);
priv->ctl_addr = ioaddr;
priv->priv_writel = elba_priv_writel;
writel(ELBA_BYTE_ENABLE_MASK(0xf), priv->ctl_addr);
return 0;
}
static const struct sdhci_ops sdhci_cdns_ops = {
.set_clock = sdhci_set_clock,
.get_timeout_clock = sdhci_cdns_get_timeout_clock,
@ -337,6 +424,13 @@ static const struct sdhci_cdns_drv_data sdhci_cdns_uniphier_drv_data = {
},
};
static const struct sdhci_cdns_drv_data sdhci_elba_drv_data = {
.init = elba_drv_init,
.pltfm_data = {
.ops = &sdhci_elba_ops,
},
};
static const struct sdhci_cdns_drv_data sdhci_cdns_drv_data = {
.pltfm_data = {
.ops = &sdhci_cdns_ops,
@ -477,6 +571,10 @@ static const struct of_device_id sdhci_cdns_match[] = {
.compatible = "socionext,uniphier-sd4hc",
.data = &sdhci_cdns_uniphier_drv_data,
},
{
.compatible = "amd,pensando-elba-sd4hc",
.data = &sdhci_elba_drv_data,
},
{ .compatible = "cdns,sd4hc" },
{ /* sentinel */ }
};