lkml.org 
[lkml]   [2022]   [Aug]   [20]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v6 16/17] mmc: sdhci-cadence: Add AMD Pensando Elba SoC support
    Date
    From: Brad Larson <blarson@amd.com>

    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>
    ---
    drivers/mmc/host/Kconfig | 1 +
    drivers/mmc/host/sdhci-cadence.c | 132 ++++++++++++++++++++++++++++---
    2 files changed, 123 insertions(+), 10 deletions(-)

    diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
    index 10c563999d3d..9af316d5bca4 100644
    --- a/drivers/mmc/host/Kconfig
    +++ b/drivers/mmc/host/Kconfig
    @@ -244,6 +244,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 708d4297f241..c662c63d49fa 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;
    @@ -77,6 +79,11 @@ struct sdhci_cdns_phy_cfg {
    u8 addr;
    };

    +struct sdhci_cdns_drv_data {
    + int (*init)(struct platform_device *pdev);
    + const struct sdhci_pltfm_data pltfm_data;
    +};
    +
    static const struct sdhci_cdns_phy_cfg sdhci_cdns_phy_cfgs[] = {
    { "cdns,phy-input-delay-sd-highspeed", SDHCI_CDNS_PHY_DLY_SD_HS, },
    { "cdns,phy-input-delay-legacy", SDHCI_CDNS_PHY_DLY_SD_DEFAULT, },
    @@ -316,6 +323,92 @@ 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.
    + */
    +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(ELBA_BYTE_ENABLE_MASK(0xf), 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 byte_enables;
    + unsigned long flags;
    +
    + byte_enables = GENMASK(1, 0) << (reg & 0x3);
    + 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 byte_enables;
    + unsigned long flags;
    +
    + byte_enables = BIT(0) << (reg & 0x3);
    + 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);
    + struct resource *iomem;
    + void __iomem *ioaddr;
    +
    + host->mmc->caps |= (MMC_CAP_1_8V_DDR | MMC_CAP_8_BIT_DATA);
    +
    + iomem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
    + if (!iomem)
    + return -ENOMEM;
    +
    + /* 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;
    + spin_lock_init(&priv->wrlock);
    + 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,
    @@ -325,13 +418,24 @@ static const struct sdhci_ops sdhci_cdns_ops = {
    .set_uhs_signaling = sdhci_cdns_set_uhs_signaling,
    };

    -static const struct sdhci_pltfm_data sdhci_cdns_uniphier_pltfm_data = {
    - .ops = &sdhci_cdns_ops,
    - .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
    +static const struct sdhci_cdns_drv_data sdhci_cdns_uniphier_drv_data = {
    + .pltfm_data = {
    + .ops = &sdhci_cdns_ops,
    + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
    + },
    +};
    +
    +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_pltfm_data sdhci_cdns_pltfm_data = {
    - .ops = &sdhci_cdns_ops,
    +static const struct sdhci_cdns_drv_data sdhci_cdns_drv_data = {
    + .pltfm_data = {
    + .ops = &sdhci_cdns_ops,
    + },
    };

    static void sdhci_cdns_hs400_enhanced_strobe(struct mmc_host *mmc,
    @@ -357,7 +461,7 @@ static void sdhci_cdns_hs400_enhanced_strobe(struct mmc_host *mmc,
    static int sdhci_cdns_probe(struct platform_device *pdev)
    {
    struct sdhci_host *host;
    - const struct sdhci_pltfm_data *data;
    + const struct sdhci_cdns_drv_data *data;
    struct sdhci_pltfm_host *pltfm_host;
    struct sdhci_cdns_priv *priv;
    struct clk *clk;
    @@ -376,10 +480,10 @@ static int sdhci_cdns_probe(struct platform_device *pdev)

    data = of_device_get_match_data(dev);
    if (!data)
    - data = &sdhci_cdns_pltfm_data;
    + data = &sdhci_cdns_drv_data;

    nr_phy_params = sdhci_cdns_phy_param_count(dev->of_node);
    - host = sdhci_pltfm_init(pdev, data,
    + host = sdhci_pltfm_init(pdev, &data->pltfm_data,
    struct_size(priv, phy_params, nr_phy_params));
    if (IS_ERR(host)) {
    ret = PTR_ERR(host);
    @@ -388,7 +492,6 @@ static int sdhci_cdns_probe(struct platform_device *pdev)

    pltfm_host = sdhci_priv(host);
    pltfm_host->clk = clk;
    -
    priv = sdhci_pltfm_priv(pltfm_host);
    priv->nr_phy_params = nr_phy_params;
    priv->hrs_addr = host->ioaddr;
    @@ -397,6 +500,11 @@ static int sdhci_cdns_probe(struct platform_device *pdev)
    host->ioaddr += SDHCI_CDNS_SRS_BASE;
    host->mmc_host_ops.hs400_enhanced_strobe =
    sdhci_cdns_hs400_enhanced_strobe;
    + if (data->init) {
    + ret = data->init(pdev);
    + if (ret)
    + goto free;
    + }
    sdhci_enable_v4_mode(host);
    __sdhci_read_caps(host, &version, NULL, NULL);

    @@ -461,7 +569,11 @@ static const struct dev_pm_ops sdhci_cdns_pm_ops = {
    static const struct of_device_id sdhci_cdns_match[] = {
    {
    .compatible = "socionext,uniphier-sd4hc",
    - .data = &sdhci_cdns_uniphier_pltfm_data,
    + .data = &sdhci_cdns_uniphier_drv_data,
    + },
    + {
    + .compatible = "amd,pensando-elba-sd4hc",
    + .data = &sdhci_elba_drv_data,
    },
    { .compatible = "cdns,sd4hc" },
    { /* sentinel */ }
    --
    2.17.1
    \
     
     \ /
      Last update: 2022-08-20 22:01    [W:4.307 / U:0.524 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site