Message ID | 20230410184526.15990-14-blarson@amd.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Support AMD Pensando Elba SoC | expand |
On Mon, 10 Apr 2023 at 20:47, Brad Larson <blarson@amd.com> wrote: > > 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> Applied for next, thanks! Kind regards Uffe > --- > > v13 changes: > - Use GENMASK(7, 3) in elba_priv_writel() to set all byte enables > - Add a variable 'shift' with GENMASK(1, 0) in elba_write_w() and > elba_write_b() to set the byte enable variable. > > v11 changes: > - Remove elba-drv_init() call to platform_get_resource() since that > check is done inside devm_platform_ioremap_resource() > - Move spin_lock_init() before error check > - Remove extra parentheses > > v10 changes: > - Add Elba specific support into this 3rd patch. This builds on the private > writel() enabled in patch 1 followed by platform specific init() in patch 2. > - Specify when first used the reason for the spinlock use to order byte-enable > prior to write data. > > --- > drivers/mmc/host/Kconfig | 1 + > drivers/mmc/host/sdhci-cadence.c | 98 ++++++++++++++++++++++++++++++++ > 2 files changed, 99 insertions(+) > > diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig > index 4745fe217ade..9f793892123c 100644 > --- a/drivers/mmc/host/Kconfig > +++ b/drivers/mmc/host/Kconfig > @@ -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. > > diff --git a/drivers/mmc/host/sdhci-cadence.c b/drivers/mmc/host/sdhci-cadence.c > index c528a25f48b8..5d1e9cef74f5 100644 > --- a/drivers/mmc/host/sdhci-cadence.c > +++ b/drivers/mmc/host/sdhci-cadence.c > @@ -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 */ } > }; > -- > 2.17.1 >
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 4745fe217ade..9f793892123c 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -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. diff --git a/drivers/mmc/host/sdhci-cadence.c b/drivers/mmc/host/sdhci-cadence.c index c528a25f48b8..5d1e9cef74f5 100644 --- a/drivers/mmc/host/sdhci-cadence.c +++ b/drivers/mmc/host/sdhci-cadence.c @@ -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 */ } };