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:
Родитель
e095b78ef2
Коммит
b5dbcf1f1d
|
@ -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 */ }
|
||||
};
|
||||
|
|
Загрузка…
Ссылка в новой задаче