Re: [PATCH v3 2/9] mmc: mmci: add support for not-amba, but still compatible, variants

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



+ Russell

On 16 January 2017 at 08:37, Andrea Merello <andrea.merello@xxxxxxxxx> wrote:
> The STM32F4xx family contain a SDIO IP that looks like a variant of
> the PL180, however, inspite it's actually attached to a APB bus, it
> cannot be handled by the AMBA bus code, because it lacks of the ID
> registers that AMBA primecell IPs have.
>
> This patch prepares for supporting the STM32 variant by letting the
> driver register also as a platform driver, that can be matched from
> the OF with specific "compatible" strings

NAK!

Too much code are depending on the amba bus in the driver. I sincerely
hope you haven't tried this approach for other amba drivers, because
it will screw them up and they will become a nightmare to maintain!

Moreover, there is a way to override the use of the AMBA IDs
registers. I think you can use that instead! No?

Kind regards
Uffe

>
> Signed-off-by: Andrea Merello <andrea.merello@xxxxxxxxx>
> ---
>  drivers/mmc/host/Kconfig |   8 +-
>  drivers/mmc/host/mmci.c  | 297 ++++++++++++++++++++++++++++++++++++-----------
>  2 files changed, 236 insertions(+), 69 deletions(-)
>
> diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
> index 2eb9701..f8f7f289 100644
> --- a/drivers/mmc/host/Kconfig
> +++ b/drivers/mmc/host/Kconfig
> @@ -5,12 +5,12 @@
>  comment "MMC/SD/SDIO Host Controller Drivers"
>
>  config MMC_ARMMMCI
> -       tristate "ARM AMBA Multimedia Card Interface support"
> -       depends on ARM_AMBA
> +       tristate "ARM AMBA Multimedia Card Interface and compatible support"
>         help
>           This selects the ARM(R) AMBA(R) PrimeCell Multimedia Card
> -         Interface (PL180 and PL181) support.  If you have an ARM(R)
> -         platform with a Multimedia Card slot, say Y or M here.
> +         Interface (PL180, PL181 and compatible) support.
> +         If you have an ARM(R) platform with a Multimedia Card slot,
> +         say Y or M here.
>
>           If unsure, say N.
>
> diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
> index 597fab8..54c2fc3 100644
> --- a/drivers/mmc/host/mmci.c
> +++ b/drivers/mmc/host/mmci.c
> @@ -1,5 +1,6 @@
>  /*
> - *  linux/drivers/mmc/host/mmci.c - ARM PrimeCell MMCI PL180/1 driver
> + *  linux/drivers/mmc/host/mmci.c - ARM PrimeCell MMCI PL180/1 and
> + *  comaptible driver
>   *
>   *  Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
>   *  Copyright (C) 2010 ST-Ericsson SA
> @@ -37,6 +38,8 @@
>  #include <linux/pm_runtime.h>
>  #include <linux/types.h>
>  #include <linux/pinctrl/consumer.h>
> +#include <linux/platform_device.h>
> +#include <linux/of_device.h>
>
>  #include <asm/div64.h>
>  #include <asm/io.h>
> @@ -113,7 +116,7 @@ struct variant_data {
>         bool                    reversed_irq_handling;
>  };
>
> -static struct variant_data variant_arm = {
> +static __maybe_unused struct variant_data variant_arm = {
>         .fifosize               = 16 * 4,
>         .fifohalfsize           = 8 * 4,
>         .datalength_bits        = 16,
> @@ -122,7 +125,7 @@ static struct variant_data variant_arm = {
>         .reversed_irq_handling  = true,
>  };
>
> -static struct variant_data variant_arm_extended_fifo = {
> +static __maybe_unused struct variant_data variant_arm_extended_fifo = {
>         .fifosize               = 128 * 4,
>         .fifohalfsize           = 64 * 4,
>         .datalength_bits        = 16,
> @@ -130,7 +133,7 @@ static struct variant_data variant_arm_extended_fifo = {
>         .f_max                  = 100000000,
>  };
>
> -static struct variant_data variant_arm_extended_fifo_hwfc = {
> +static __maybe_unused struct variant_data variant_arm_extended_fifo_hwfc = {
>         .fifosize               = 128 * 4,
>         .fifohalfsize           = 64 * 4,
>         .clkreg_enable          = MCI_ARM_HWFCEN,
> @@ -139,7 +142,7 @@ static struct variant_data variant_arm_extended_fifo_hwfc = {
>         .f_max                  = 100000000,
>  };
>
> -static struct variant_data variant_u300 = {
> +static __maybe_unused struct variant_data variant_u300 = {
>         .fifosize               = 16 * 4,
>         .fifohalfsize           = 8 * 4,
>         .clkreg_enable          = MCI_ST_U300_HWFCEN,
> @@ -154,7 +157,7 @@ static struct variant_data variant_u300 = {
>         .pwrreg_nopower         = true,
>  };
>
> -static struct variant_data variant_nomadik = {
> +static __maybe_unused struct variant_data variant_nomadik = {
>         .fifosize               = 16 * 4,
>         .fifohalfsize           = 8 * 4,
>         .clkreg                 = MCI_CLK_ENABLE,
> @@ -170,7 +173,7 @@ static struct variant_data variant_nomadik = {
>         .pwrreg_nopower         = true,
>  };
>
> -static struct variant_data variant_ux500 = {
> +static __maybe_unused struct variant_data variant_ux500 = {
>         .fifosize               = 30 * 4,
>         .fifohalfsize           = 8 * 4,
>         .clkreg                 = MCI_CLK_ENABLE,
> @@ -192,7 +195,7 @@ static struct variant_data variant_ux500 = {
>         .pwrreg_nopower         = true,
>  };
>
> -static struct variant_data variant_ux500v2 = {
> +static __maybe_unused struct variant_data variant_ux500v2 = {
>         .fifosize               = 30 * 4,
>         .fifohalfsize           = 8 * 4,
>         .clkreg                 = MCI_CLK_ENABLE,
> @@ -216,7 +219,7 @@ static struct variant_data variant_ux500v2 = {
>         .pwrreg_nopower         = true,
>  };
>
> -static struct variant_data variant_qcom = {
> +static __maybe_unused struct variant_data variant_qcom = {
>         .fifosize               = 16 * 4,
>         .fifohalfsize           = 8 * 4,
>         .clkreg                 = MCI_CLK_ENABLE,
> @@ -1528,31 +1531,32 @@ static int mmci_of_parse(struct device_node *np, struct mmc_host *mmc)
>         return 0;
>  }
>
> -static int mmci_probe(struct amba_device *dev,
> -       const struct amba_id *id)
> +static struct mmci_host *mmci_probe(struct device *dev,
> +                                   struct variant_data *variant,
> +                                   struct resource *res,
> +                                   unsigned int irq0, unsigned int irq1)
>  {
> -       struct mmci_platform_data *plat = dev->dev.platform_data;
> -       struct device_node *np = dev->dev.of_node;
> -       struct variant_data *variant = id->data;
> -       struct mmci_host *host;
> +       struct device_node *np = dev->of_node;
> +       struct mmci_platform_data *plat = dev->platform_data;
>         struct mmc_host *mmc;
> +       struct mmci_host *host;
>         int ret;
>
>         /* Must have platform data or Device Tree. */
>         if (!plat && !np) {
> -               dev_err(&dev->dev, "No plat data or DT found\n");
> -               return -EINVAL;
> +               dev_err(dev, "No plat data or DT found\n");
> +               return ERR_PTR(-EINVAL);
>         }
>
>         if (!plat) {
> -               plat = devm_kzalloc(&dev->dev, sizeof(*plat), GFP_KERNEL);
> +               plat = devm_kzalloc(dev, sizeof(*plat), GFP_KERNEL);
>                 if (!plat)
> -                       return -ENOMEM;
> +                       return ERR_PTR(-ENOMEM);
>         }
>
> -       mmc = mmc_alloc_host(sizeof(struct mmci_host), &dev->dev);
> +       mmc = mmc_alloc_host(sizeof(struct mmci_host), dev);
>         if (!mmc)
> -               return -ENOMEM;
> +               return ERR_PTR(-ENOMEM);
>
>         ret = mmci_of_parse(np, mmc);
>         if (ret)
> @@ -1561,12 +1565,7 @@ static int mmci_probe(struct amba_device *dev,
>         host = mmc_priv(mmc);
>         host->mmc = mmc;
>
> -       host->hw_designer = amba_manf(dev);
> -       host->hw_revision = amba_rev(dev);
> -       dev_dbg(mmc_dev(mmc), "designer ID = 0x%02x\n", host->hw_designer);
> -       dev_dbg(mmc_dev(mmc), "revision = 0x%01x\n", host->hw_revision);
> -
> -       host->clk = devm_clk_get(&dev->dev, NULL);
> +       host->clk = devm_clk_get(dev, NULL);
>         if (IS_ERR(host->clk)) {
>                 ret = PTR_ERR(host->clk);
>                 goto host_free;
> @@ -1598,8 +1597,8 @@ static int mmci_probe(struct amba_device *dev,
>                         host->mclk);
>         }
>
> -       host->phybase = dev->res.start;
> -       host->base = devm_ioremap_resource(&dev->dev, &dev->res);
> +       host->phybase = res->start;
> +       host->base = devm_ioremap_resource(dev, res);
>         if (IS_ERR(host->base)) {
>                 ret = PTR_ERR(host->base);
>                 goto clk_disable;
> @@ -1742,49 +1741,41 @@ static int mmci_probe(struct amba_device *dev,
>                 }
>         }
>
> -       ret = devm_request_irq(&dev->dev, dev->irq[0], mmci_irq, IRQF_SHARED,
> -                       DRIVER_NAME " (cmd)", host);
> +       ret = devm_request_irq(dev, irq0, mmci_irq, IRQF_SHARED,
> +                              DRIVER_NAME " (cmd)", host);
>         if (ret)
>                 goto clk_disable;
>
> -       if (!dev->irq[1])
> +       if (!irq1) {
>                 host->singleirq = true;
> -       else {
> -               ret = devm_request_irq(&dev->dev, dev->irq[1], mmci_pio_irq,
> -                               IRQF_SHARED, DRIVER_NAME " (pio)", host);
> +       } else {
> +               ret = devm_request_irq(dev, irq1, mmci_pio_irq,
> +                                      IRQF_SHARED, DRIVER_NAME " (pio)", host);
>                 if (ret)
>                         goto clk_disable;
>         }
>
>         writel(MCI_IRQENABLE, host->base + MMCIMASK0);
>
> -       amba_set_drvdata(dev, mmc);
> -
> -       dev_info(&dev->dev, "%s: PL%03x manf %x rev%u at 0x%08llx irq %d,%d (pio)\n",
> -                mmc_hostname(mmc), amba_part(dev), amba_manf(dev),
> -                amba_rev(dev), (unsigned long long)dev->res.start,
> -                dev->irq[0], dev->irq[1]);
> -
>         mmci_dma_setup(host);
>
> -       pm_runtime_set_autosuspend_delay(&dev->dev, 50);
> -       pm_runtime_use_autosuspend(&dev->dev);
> +       pm_runtime_set_autosuspend_delay(dev, 50);
> +       pm_runtime_use_autosuspend(dev);
>
>         mmc_add_host(mmc);
>
> -       pm_runtime_put(&dev->dev);
> -       return 0;
> +       pm_runtime_put(dev);
> +       return host;
>
>   clk_disable:
>         clk_disable_unprepare(host->clk);
>   host_free:
>         mmc_free_host(mmc);
> -       return ret;
> +       return ERR_PTR(ret);
>  }
>
> -static int mmci_remove(struct amba_device *dev)
> +static int mmc_remove(struct mmc_host *mmc)
>  {
> -       struct mmc_host *mmc = amba_get_drvdata(dev);
>
>         if (mmc) {
>                 struct mmci_host *host = mmc_priv(mmc);
> @@ -1793,7 +1784,7 @@ static int mmci_remove(struct amba_device *dev)
>                  * Undo pm_runtime_put() in probe.  We use the _sync
>                  * version here so that we can access the primecell.
>                  */
> -               pm_runtime_get_sync(&dev->dev);
> +               pm_runtime_get_sync(mmc->parent);
>
>                 mmc_remove_host(mmc);
>
> @@ -1847,14 +1838,11 @@ static void mmci_restore(struct mmci_host *host)
>         spin_unlock_irqrestore(&host->lock, flags);
>  }
>
> -static int mmci_runtime_suspend(struct device *dev)
> +static int mmci_runtime_suspend(struct mmc_host *mmc)
>  {
> -       struct amba_device *adev = to_amba_device(dev);
> -       struct mmc_host *mmc = amba_get_drvdata(adev);
> -
>         if (mmc) {
>                 struct mmci_host *host = mmc_priv(mmc);
> -               pinctrl_pm_select_sleep_state(dev);
> +               pinctrl_pm_select_sleep_state(mmc->parent);
>                 mmci_save(host);
>                 clk_disable_unprepare(host->clk);
>         }
> @@ -1862,28 +1850,77 @@ static int mmci_runtime_suspend(struct device *dev)
>         return 0;
>  }
>
> -static int mmci_runtime_resume(struct device *dev)
> +static int mmci_runtime_resume(struct mmc_host *mmc)
>  {
> -       struct amba_device *adev = to_amba_device(dev);
> -       struct mmc_host *mmc = amba_get_drvdata(adev);
>
>         if (mmc) {
>                 struct mmci_host *host = mmc_priv(mmc);
>                 clk_prepare_enable(host->clk);
>                 mmci_restore(host);
> -               pinctrl_pm_select_default_state(dev);
> +               pinctrl_pm_select_default_state(mmc->parent);
>         }
>
>         return 0;
>  }
>  #endif
>
> -static const struct dev_pm_ops mmci_dev_pm_ops = {
> +#ifdef CONFIG_ARM_AMBA
> +static int mmci_remove_amba(struct amba_device *dev)
> +{
> +       struct mmc_host *mmc = amba_get_drvdata(dev);
> +
> +       return mmc_remove(mmc);
> +}
> +
> +static int mmci_runtime_resume_amba(struct device *dev)
> +{
> +       struct amba_device *adev = to_amba_device(dev);
> +       struct mmc_host *mmc = amba_get_drvdata(adev);
> +
> +       return mmci_runtime_resume(mmc);
> +}
> +
> +static int mmci_runtime_suspend_amba(struct device *dev)
> +{
> +       struct amba_device *adev = to_amba_device(dev);
> +       struct mmc_host *mmc = amba_get_drvdata(adev);
> +
> +       return mmci_runtime_suspend(mmc);
> +}
> +
> +static const struct dev_pm_ops mmci_dev_pm_ops_amba = {
>         SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
>                                 pm_runtime_force_resume)
> -       SET_RUNTIME_PM_OPS(mmci_runtime_suspend, mmci_runtime_resume, NULL)
> +       SET_RUNTIME_PM_OPS(mmci_runtime_suspend_amba, mmci_runtime_resume_amba,
> +                          NULL)
>  };
>
> +static int mmci_probe_amba(struct amba_device *dev, const struct amba_id *id)
> +{
> +       struct mmci_host *host;
> +       struct variant_data *variant = id->data;
> +
> +       host = mmci_probe(&dev->dev, variant, &dev->res,
> +                         dev->irq[0], dev->irq[1]);
> +       if (IS_ERR(host))
> +               return PTR_ERR(host);
> +
> +       host->hw_designer = amba_manf(dev);
> +       host->hw_revision = amba_rev(dev);
> +       dev_dbg(mmc_dev(host->mmc), "designer ID = 0x%02x\n",
> +               host->hw_designer);
> +       dev_dbg(mmc_dev(host->mmc), "revision = 0x%01x\n", host->hw_revision);
> +
> +       amba_set_drvdata(dev, host->mmc);
> +
> +       dev_info(&dev->dev, "%s: PL%03x manf %x rev%u at 0x%08llx irq %d,%d (pio)\n",
> +                mmc_hostname(host->mmc), amba_part(dev), amba_manf(dev),
> +                amba_rev(dev), (unsigned long long)dev->res.start,
> +                dev->irq[0], dev->irq[1]);
> +
> +       return 0;
> +}
> +
>  static struct amba_id mmci_ids[] = {
>         {
>                 .id     = 0x00041180,
> @@ -1945,14 +1982,144 @@ MODULE_DEVICE_TABLE(amba, mmci_ids);
>  static struct amba_driver mmci_driver = {
>         .drv            = {
>                 .name   = DRIVER_NAME,
> -               .pm     = &mmci_dev_pm_ops,
> +               .pm     = &mmci_dev_pm_ops_amba,
>         },
> -       .probe          = mmci_probe,
> -       .remove         = mmci_remove,
> +       .probe          = mmci_probe_amba,
> +       .remove         = mmci_remove_amba,
>         .id_table       = mmci_ids,
>  };
> +#endif
> +
> +static const struct of_device_id mmci_pltfm_match[] = {
> +       {},
> +};
> +
> +static int mmci_probe_pltfm(struct platform_device *pdev)
> +{
> +       struct mmci_host *host;
> +       struct variant_data *variant;
> +       const struct of_device_id *match;
> +       int irq0, irq1;
> +       struct resource *res;
> +
> +       irq0 = platform_get_irq(pdev, 0);
> +       if (irq0 < 0) {
> +               dev_err(&pdev->dev, "Can't get IRQ");
> +               return -EINVAL;
> +       }
> +
> +       irq1 = platform_get_irq(pdev, 1);
> +       /* optional. set to 0 to be compatible with original amba probe code */
> +       if (irq1 < 0)
> +               irq1 = 0;
> +
> +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +       if (!res) {
> +               dev_err(&pdev->dev, "Can't get MMIO range");
> +               return -EINVAL;
> +       }
> +
> +       match = of_match_device(mmci_pltfm_match, &pdev->dev);
> +       if (!match) {
> +               dev_err(&pdev->dev, "Can't get variant data\n");
> +               return -EINVAL;
> +       }
> +       variant = (struct variant_data *)match->data;
> +
> +       host = mmci_probe(&pdev->dev, variant, res,
> +                         irq0, irq1);
> +       if (IS_ERR(host))
> +               return PTR_ERR(host);
> +
> +       platform_set_drvdata(pdev, host->mmc);
> +       dev_info(&pdev->dev, "%s: PL81x compatible SDIO at 0x%08llx irq %d,%d (pio)\n",
> +                mmc_hostname(host->mmc),
> +                (unsigned long long)res->start, irq0, irq1);
> +
> +       return 0;
> +}
> +
> +static int mmci_remove_pltfm(struct platform_device *pdev)
> +{
> +       struct mmc_host *mmc = platform_get_drvdata(pdev);
> +
> +       return mmc_remove(mmc);
> +}
> +
> +static int mmci_runtime_resume_pltfm(struct device *dev)
> +{
> +       struct platform_device *pdev = to_platform_device(dev);
> +       struct mmc_host *mmc = platform_get_drvdata(pdev);
> +
> +       return mmci_runtime_resume(mmc);
> +}
> +
> +static int mmci_runtime_suspend_pltfm(struct device *dev)
> +{
> +       struct platform_device *pdev = to_platform_device(dev);
> +       struct mmc_host *mmc = platform_get_drvdata(pdev);
> +
> +       return mmci_runtime_suspend(mmc);
> +}
> +
> +MODULE_DEVICE_TABLE(of, mmci_pltfm_match);
> +
> +static const struct dev_pm_ops mmci_dev_pm_ops_pltfm = {
> +       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
> +                               pm_runtime_force_resume)
> +       SET_RUNTIME_PM_OPS(mmci_runtime_suspend_pltfm,
> +                          mmci_runtime_resume_pltfm, NULL)
> +};
> +
> +static struct platform_driver mmci_pltfm_driver = {
> +       .probe          = mmci_probe_pltfm,
> +       .remove         = mmci_remove_pltfm,
> +       .driver         = {
> +               .name           = DRIVER_NAME,
> +               .of_match_table = mmci_pltfm_match,
> +               .pm             = &mmci_dev_pm_ops_pltfm,
> +       },
> +};
> +
> +static int __init mmci_init(void)
> +{
> +       int ret;
> +       __maybe_unused int ret_amba;
> +
> +       ret = platform_driver_register(&mmci_pltfm_driver);
> +
> +#ifdef CONFIG_ARM_AMBA
> +       ret_amba = amba_driver_register(&mmci_driver);
> +
> +       /* if both plaform and amba failed. Just fail. */
> +       if (ret && ret_amba)
> +               return ret;
> +
> +       /*
> +        * If only one of the two succeeded, don't fail here, because the
> +        * other one is probably usable, but spit a warning..
> +        */
> +       if (ret_amba)
> +               pr_warn("could not register MMCI amba driver");
> +
> +       if (ret)
> +               pr_warn("could not register MMCI platform driver");
> +
> +       return 0;
> +#endif
> +       return ret;
> +}
> +
> +static void __exit mmci_exit(void)
> +{
> +       platform_driver_unregister(&mmci_pltfm_driver);
> +#ifdef CONFIG_ARM_AMBA
> +       amba_driver_unregister(&mmci_driver);
> +#endif
> +}
>
> -module_amba_driver(mmci_driver);
> +module_init(mmci_init);
> +module_exit(mmci_exit);
>
>  module_param(fmax, uint, 0444);
>
> --
> 2.7.4
>
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux