On 19-01-29 17:09:51, Lucas Stach wrote:
> Am Dienstag, den 29.01.2019, 13:30 +0000 schrieb Abel Vesa:
> > From: Anson Huang <anson.hu...@nxp.com>
> > 
> > Add i.MX8MQ PSCI GPC virtual driver support.
> > 
> > Signed-off-by: Anson Huang <anson.hu...@nxp.com>
> > Signed-off-by: Bai Ping <ping....@nxp.com>
> > Signed-off-by: Abel Vesa <abel.v...@nxp.com>
> 
> NACK, we already have a working driver for the power domains on
> i.MX8MQ, reusing the existing GPCv2 driver. This has been done in
> coordination with Anson Huang. There is no need to involve PSCI in any
> of this.
> 

Hmmm, didn't see that until now. You're right, no point in adding this then.
So I guess the upcomming drivers will have to switch from this old one to the
one already existing when upstreaming.

I'll drop this then. 
Thanks.

> Regards,
> Lucas
> 
> > ---
> >  drivers/soc/imx/Makefile   |   1 +
> >  drivers/soc/imx/gpc-psci.c | 423
> > +++++++++++++++++++++++++++++++++++++++++++++
> >  include/soc/imx/fsl_sip.h  |  31 ++++
> >  3 files changed, 455 insertions(+)
> >  create mode 100644 drivers/soc/imx/gpc-psci.c
> >  create mode 100644 include/soc/imx/fsl_sip.h
> > 
> > diff --git a/drivers/soc/imx/Makefile b/drivers/soc/imx/Makefile
> > index 506a6f3..83a38ac 100644
> > --- a/drivers/soc/imx/Makefile
> > +++ b/drivers/soc/imx/Makefile
> > @@ -1,2 +1,3 @@
> >  obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o
> >  obj-$(CONFIG_IMX_GPCV2_PM_DOMAINS) += gpcv2.o
> > +obj-$(CONFIG_ARCH_MXC) += gpc-psci.o
> > diff --git a/drivers/soc/imx/gpc-psci.c b/drivers/soc/imx/gpc-psci.c
> > new file mode 100644
> > index 0000000..4f8fee9
> > --- /dev/null
> > +++ b/drivers/soc/imx/gpc-psci.c
> > @@ -0,0 +1,423 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * Copyright 2019 NXP.
> > + *
> > + */
> > +
> > +#include <linux/arm-smccc.h>
> > +#include <linux/clk.h>
> > +#include <linux/cpumask.h>
> > +#include <linux/delay.h>
> > +#include <linux/io.h>
> > +#include <linux/irq.h>
> > +#include <linux/irqchip.h>
> > +#include <linux/irqchip/arm-gic.h>
> > +#include <linux/module.h>
> > +#include <linux/of.h>
> > +#include <linux/of_address.h>
> > +#include <linux/of_irq.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/regulator/consumer.h>
> > +#include <linux/pm_domain.h>
> > +#include <soc/imx/fsl_sip.h>
> > +
> > +#define GPC_MAX_IRQS               (4 * 32)
> > +
> > +struct imx_gpc_pm_domain {
> > +   const char name[30];
> > +   struct device *dev;
> > +   struct generic_pm_domain pd;
> > +   u32 gpc_domain_id;
> > +   struct clk **clks;
> > +   unsigned int num_clks;
> > +   struct regulator *reg;
> > +};
> > +
> > +enum imx_gpc_pm_domain_state {
> > +   GPC_PD_STATE_OFF,
> > +   GPC_PD_STATE_ON,
> > +};
> > +
> > +#define to_imx_gpc_pm_domain(_genpd) \
> > +   container_of(_genpd, struct imx_gpc_pm_domain, pd)
> > +
> > +static DEFINE_SPINLOCK(gpc_psci_lock);
> > +static DEFINE_MUTEX(gpc_pd_mutex);
> > +
> > +static void imx_gpc_psci_irq_unmask(struct irq_data *d)
> > +{
> > +   struct arm_smccc_res res;
> > +
> > +   spin_lock(&gpc_psci_lock);
> > +   arm_smccc_smc(FSL_SIP_GPC, FSL_SIP_CONFIG_GPC_UNMASK, d-
> > >hwirq,
> > +                 0, 0, 0, 0, 0, &res);
> > +   spin_unlock(&gpc_psci_lock);
> > +
> > +   irq_chip_unmask_parent(d);
> > +}
> > +
> > +static void imx_gpc_psci_irq_mask(struct irq_data *d)
> > +{
> > +   struct arm_smccc_res res;
> > +
> > +   spin_lock(&gpc_psci_lock);
> > +   arm_smccc_smc(FSL_SIP_GPC, FSL_SIP_CONFIG_GPC_MASK, d-
> > >hwirq,
> > +                 0, 0, 0, 0, 0, &res);
> > +   spin_unlock(&gpc_psci_lock);
> > +
> > +   irq_chip_mask_parent(d);
> > +}
> > +static int imx_gpc_psci_irq_set_wake(struct irq_data *d, unsigned
> > int on)
> > +{
> > +   struct arm_smccc_res res;
> > +
> > +   spin_lock(&gpc_psci_lock);
> > +   arm_smccc_smc(FSL_SIP_GPC, FSL_SIP_CONFIG_GPC_SET_WAKE, d-
> > >hwirq,
> > +                   on, 0, 0, 0, 0, &res);
> > +   spin_unlock(&gpc_psci_lock);
> > +
> > +   return 0;
> > +}
> > +
> > +static int imx_gpc_psci_irq_set_affinity(struct irq_data *d,
> > +                                    const struct cpumask *dest,
> > +                                    bool force)
> > +{
> > +   /* parse the cpu of irq affinity */
> > +   struct arm_smccc_res res;
> > +   int cpu = cpumask_any_and(dest, cpu_online_mask);
> > +
> > +   irq_chip_set_affinity_parent(d, dest, force);
> > +
> > +   spin_lock(&gpc_psci_lock);
> > +   arm_smccc_smc(FSL_SIP_GPC, 0x4, d->hwirq,
> > +                 cpu, 0, 0, 0, 0, &res);
> > +   spin_unlock(&gpc_psci_lock);
> > +
> > +   return 0;
> > +}
> > +
> > +static struct irq_chip imx_gpc_psci_chip = {
> > +   .name                   = "GPC-PSCI",
> > +   .irq_eoi                = irq_chip_eoi_parent,
> > +   .irq_mask               = imx_gpc_psci_irq_mask,
> > +   .irq_unmask             = imx_gpc_psci_irq_unmask,
> > +   .irq_retrigger          =
> > irq_chip_retrigger_hierarchy,
> > +   .irq_set_wake           = imx_gpc_psci_irq_set_wake,
> > +   .irq_set_affinity       = imx_gpc_psci_irq_set_affinity,
> > +};
> > +
> > +static int imx_gpc_psci_domain_translate(struct irq_domain *d,
> > +                               struct irq_fwspec *fwspec,
> > +                               unsigned long *hwirq,
> > +                               unsigned int *type)
> > +{
> > +   if (is_of_node(fwspec->fwnode)) {
> > +           if (fwspec->param_count != 3)
> > +                   return -EINVAL;
> > +
> > +           /* No PPI should point to this domain */
> > +           if (fwspec->param[0] != 0)
> > +                   return -EINVAL;
> > +
> > +           *hwirq = fwspec->param[1];
> > +           *type = fwspec->param[2];
> > +           return 0;
> > +   }
> > +
> > +   return -EINVAL;
> > +}
> > +
> > +static int imx_gpc_psci_domain_alloc(struct irq_domain *domain,
> > +                             unsigned int irq,
> > +                             unsigned int nr_irqs, void *data)
> > +{
> > +   struct irq_fwspec *fwspec = data;
> > +   struct irq_fwspec parent_fwspec;
> > +   irq_hw_number_t hwirq;
> > +   int i;
> > +
> > +   if (fwspec->param_count != 3)
> > +           return -EINVAL; /* Not GIC compliant */
> > +   if (fwspec->param[0] != 0)
> > +           return -EINVAL; /* No PPI should point to
> > this domain */
> > +
> > +   hwirq = fwspec->param[1];
> > +   if (hwirq >= GPC_MAX_IRQS)
> > +           return -EINVAL; /* Can't deal with this */
> > +
> > +   for (i = 0; i < nr_irqs; i++)
> > +           irq_domain_set_hwirq_and_chip(domain, irq + i, hwirq
> > + i,
> > +                                         &imx_gpc_psci_chip,
> > NULL);
> > +
> > +   parent_fwspec = *fwspec;
> > +   parent_fwspec.fwnode = domain->parent->fwnode;
> > +
> > +   return irq_domain_alloc_irqs_parent(domain, irq, nr_irqs,
> > +                                       &parent_fwspec);
> > +}
> > +
> > +static const struct irq_domain_ops imx_gpc_psci_domain_ops = {
> > +   .translate = imx_gpc_psci_domain_translate,
> > +   .alloc  = imx_gpc_psci_domain_alloc,
> > +   .free   = irq_domain_free_irqs_common,
> > +};
> > +
> > +static int __init imx_gpc_psci_init(struct device_node *node,
> > +                          struct device_node *parent)
> > +{
> > +   struct irq_domain *parent_domain, *domain;
> > +
> > +   if (!parent) {
> > +           pr_err("%s: no parent, giving up\n", node-
> > >full_name);
> > +           return -ENODEV;
> > +   }
> > +
> > +   parent_domain = irq_find_host(parent);
> > +   if (!parent_domain) {
> > +           pr_err("%s: unable to obtain parent domain\n",
> > +                   node->full_name);
> > +           return -ENXIO;
> > +   }
> > +
> > +   domain = irq_domain_add_hierarchy(parent_domain, 0,
> > GPC_MAX_IRQS,
> > +                                     node,
> > &imx_gpc_psci_domain_ops,
> > +                                     NULL);
> > +   if (!domain)
> > +           return -ENOMEM;
> > +
> > +   return 0;
> > +}
> > +IRQCHIP_DECLARE(imx_gpc_psci, "fsl,imx8mq-gpc", imx_gpc_psci_init);
> > +
> > +static int imx_gpc_pd_power_on(struct generic_pm_domain *domain)
> > +{
> > +   struct imx_gpc_pm_domain *pd = to_imx_gpc_pm_domain(domain);
> > +   struct arm_smccc_res res;
> > +   int index, ret = 0;
> > +
> > +   /* power on the external supply */
> > +   if (pd->reg) {
> > +           ret = regulator_enable(pd->reg);
> > +           if (ret) {
> > +                   dev_warn(pd->dev, "failed to power up the
> > reg%d\n", ret);
> > +                   return ret;
> > +           }
> > +   }
> > +
> > +   /* enable the necessary clks needed by the power domain */
> > +   if (pd->num_clks) {
> > +           for (index = 0; index < pd->num_clks; index++)
> > +                   clk_prepare_enable(pd->clks[index]);
> > +   }
> > +
> > +   mutex_lock(&gpc_pd_mutex);
> > +   arm_smccc_smc(FSL_SIP_GPC, FSL_SIP_CONFIG_GPC_PM_DOMAIN,
> > +                   pd->gpc_domain_id,
> > +                   GPC_PD_STATE_ON, 0, 0, 0, 0, &res);
> > +   mutex_unlock(&gpc_pd_mutex);
> > +
> > +   return 0;
> > +}
> > +
> > +static int imx_gpc_pd_power_off(struct generic_pm_domain *domain)
> > +{
> > +   struct imx_gpc_pm_domain *pd = to_imx_gpc_pm_domain(domain);
> > +   struct arm_smccc_res res;
> > +   int index, ret = 0;
> > +
> > +   mutex_lock(&gpc_pd_mutex);
> > +   arm_smccc_smc(FSL_SIP_GPC, FSL_SIP_CONFIG_GPC_PM_DOMAIN,
> > +                   pd->gpc_domain_id, GPC_PD_STATE_OFF,
> > +                   0, 0, 0, 0, &res);
> > +   mutex_unlock(&gpc_pd_mutex);
> > +
> > +   /* power off the external supply */
> > +   if (pd->reg) {
> > +           ret = regulator_disable(pd->reg);
> > +           if (ret) {
> > +                   dev_warn(pd->dev, "failed to power off the
> > reg%d\n", ret);
> > +                   return ret;
> > +           }
> > +   }
> > +
> > +   /* disable the necessary clks when power domain on finished
> > */
> > +   if (pd->num_clks) {
> > +           for (index = 0; index < pd->num_clks; index++)
> > +                   clk_disable_unprepare(pd->clks[index]);
> > +   }
> > +
> > +   return ret;
> > +};
> > +
> > +static int imx8m_pd_clk_init(struct device_node *np,
> > +                        struct imx_gpc_pm_domain *domain)
> > +{
> > +   struct property *pp;
> > +   struct clk **clks;
> > +   int index;
> > +
> > +   pp = of_find_property(np, "clocks", NULL);
> > +   if (pp)
> > +           domain->num_clks = pp->length / 8;
> > +   else
> > +           domain->num_clks = 0;
> > +
> > +   if (domain->num_clks) {
> > +           clks = kcalloc(domain->num_clks, sizeof(*clks),
> > GFP_KERNEL);
> > +           if (!clks) {
> > +                   domain->num_clks = 0;
> > +                   domain->clks = NULL;
> > +                   return -ENOMEM;
> > +           }
> > +
> > +           domain->clks = clks;
> > +   }
> > +
> > +   for (index = 0; index < domain->num_clks; index++) {
> > +           clks[index] = of_clk_get(np, index);
> > +           if (IS_ERR(clks[index])) {
> > +                   for (index = 0; index < domain->num_clks;
> > index++) {
> > +                           if (!IS_ERR(clks[index]))
> > +                                   clk_put(clks[index]);
> > +                   }
> > +
> > +                   domain->num_clks = 0;
> > +                   domain->clks = NULL;
> > +                   kfree(clks);
> > +                   pr_warn("imx8m domain clock init failed\n");
> > +                   return -ENODEV;
> > +           }
> > +   }
> > +
> > +   return 0;
> > +}
> > +
> > +static int imx8m_add_subdomain(struct device_node *parent,
> > +                          struct generic_pm_domain *parent_pd)
> > +{
> > +   struct device_node *child_node;
> > +   struct imx_gpc_pm_domain *child_domain;
> > +   int ret = 0;
> > +
> > +   /* add each of the child domain of parent */
> > +   for_each_child_of_node(parent, child_node) {
> > +           if (!of_device_is_available(child_node))
> > +                   continue;
> > +
> > +           child_domain = kzalloc(sizeof(*child_domain),
> > GFP_KERNEL);
> > +           if (!child_domain)
> > +                   return -ENOMEM;
> > +
> > +           ret = of_property_read_string(child_node, "domain-
> > name",
> > +                                         &child_domain-
> > >pd.name);
> > +           if (ret)
> > +                   goto exit;
> > +
> > +           ret = of_property_read_u32(child_node, "domain-id",
> > +                                      &child_domain-
> > >gpc_domain_id);
> > +           if (ret)
> > +                   goto exit;
> > +
> > +           child_domain->pd.power_off = imx_gpc_pd_power_off;
> > +           child_domain->pd.power_on = imx_gpc_pd_power_on;
> > +           /* no reg for subdomains */
> > +           child_domain->reg = NULL;
> > +
> > +           imx8m_pd_clk_init(child_node, child_domain);
> > +
> > +           /* power domains as off at boot */
> > +           pm_genpd_init(&child_domain->pd, NULL, true);
> > +
> > +           /* add subdomain of parent power domain */
> > +           pm_genpd_add_subdomain(parent_pd, &child_domain-
> > >pd);
> > +
> > +           ret = of_genpd_add_provider_simple(child_node,
> > +                                            &child_domain->pd);
> > +           if (ret)
> > +                   pr_err("failed to add subdomain\n");
> > +   }
> > +
> > +   return 0;
> > +exit:
> > +   kfree(child_domain);
> > +   return ret;
> > +};
> > +
> > +static int imx_gpc_pm_domain_probe(struct platform_device *pdev)
> > +{
> > +   struct device *dev = &pdev->dev;
> > +   struct device_node *np = dev->of_node;
> > +   struct imx_gpc_pm_domain *imx_pm_domain;
> > +   int ret = 0;
> > +
> > +   if (!np) {
> > +           dev_err(dev, "power domain device tree node not
> > found\n");
> > +           return -ENODEV;
> > +   }
> > +
> > +   imx_pm_domain = devm_kzalloc(dev, sizeof(*imx_pm_domain),
> > GFP_KERNEL);
> > +   if (!imx_pm_domain)
> > +           return -ENOMEM;
> > +   imx_pm_domain->dev = dev;
> > +
> > +   ret = of_property_read_string(np, "domain-name",
> > +                                   &imx_pm_domain->pd.name);
> > +   if (ret) {
> > +           dev_err(dev, "get domain name failed\n");
> > +           return -EINVAL;
> > +   }
> > +
> > +   ret = of_property_read_u32(np, "domain-id",
> > +                                   &imx_pm_domain-
> > >gpc_domain_id);
> > +   if (ret) {
> > +           dev_err(dev, "get domain id failed\n");
> > +           return -EINVAL;
> > +   }
> > +
> > +   imx_pm_domain->reg = devm_regulator_get_optional(dev,
> > "power");
> > +   if (IS_ERR(imx_pm_domain->reg)) {
> > +           if (PTR_ERR(imx_pm_domain->reg) == -EPROBE_DEFER)
> > +                   return -EPROBE_DEFER;
> > +
> > +           imx_pm_domain->reg = NULL;
> > +   }
> > +
> > +   imx8m_pd_clk_init(np, imx_pm_domain);
> > +
> > +   imx_pm_domain->pd.power_off = imx_gpc_pd_power_off;
> > +   imx_pm_domain->pd.power_on = imx_gpc_pd_power_on;
> > +   /* all power domains as off at boot */
> > +   pm_genpd_init(&imx_pm_domain->pd, NULL, true);
> > +
> > +   ret = of_genpd_add_provider_simple(np,
> > +                            &imx_pm_domain->pd);
> > +
> > +   /* add subdomain */
> > +   ret = imx8m_add_subdomain(np, &imx_pm_domain->pd);
> > +   if (ret)
> > +           dev_warn(dev, "please check the child power domain
> > init\n");
> > +
> > +   return 0;
> > +}
> > +
> > +static const struct of_device_id imx_gpc_pm_domain_ids[] = {
> > +   {.compatible = "fsl,imx8mq-pm-domain"},
> > +   {.compatible = "fsl,imx8mm-pm-domain"},
> > +   {},
> > +};
> > +
> > +static struct platform_driver imx_gpc_pm_domain_driver = {
> > +   .driver = {
> > +           .name   = "imx8m_gpc_pm_domain",
> > +           .owner  = THIS_MODULE,
> > +           .of_match_table = imx_gpc_pm_domain_ids,
> > +   },
> > +   .probe = imx_gpc_pm_domain_probe,
> > +};
> > +
> > +module_platform_driver(imx_gpc_pm_domain_driver);
> > +
> > +MODULE_AUTHOR("NXP");
> > +MODULE_DESCRIPTION("NXP i.MX8M GPC power domain driver");
> > +MODULE_LICENSE("GPL v2");
> > diff --git a/include/soc/imx/fsl_sip.h b/include/soc/imx/fsl_sip.h
> > new file mode 100644
> > index 0000000..c3867a2
> > --- /dev/null
> > +++ b/include/soc/imx/fsl_sip.h
> > @@ -0,0 +1,31 @@
> > +/*
> > + * Copyright (C) 2016 Freescale Semiconductor, Inc.
> > + * Copyright 2017 NXP
> > + *
> > + * This program is free software; you can redistribute it and/or
> > modify
> > + * it under the terms of the GNU General Public License version 2 as
> > + * published by the Free Software Foundation.
> > + */
> > +
> > +#ifndef __SOC_FSL_SIP_H
> > +#define __SOC_FSL_SIP_H
> > +
> > +#define FSL_SIP_GPC                        0xC2000000
> > +#define FSL_SIP_CONFIG_GPC_MASK            0x00
> > +#define FSL_SIP_CONFIG_GPC_UNMASK  0x01
> > +#define FSL_SIP_CONFIG_GPC_SET_WAKE        0x02
> > +#define FSL_SIP_CONFIG_GPC_PM_DOMAIN       0x03
> > +
> > +#define IMX8MQ_PD_MIPI             0
> > +#define IMX8MQ_PD_PCIE1            1
> > +#define IMX8MQ_PD_OTG1             2
> > +#define IMX8MQ_PD_OTG2             3
> > +#define IMX8MQ_PD_GPU              4
> > +#define IMX8MQ_PD_VPU              5
> > +#define IMX8MQ_PD_HDMI             6
> > +#define IMX8MQ_PD_DISP             7
> > +#define IMX8MQ_PD_MIPI_CSI1        8
> > +#define IMX8MQ_PD_MIPI_CSI2        9
> > +#define IMX8MQ_PD_PCIE2            10
> > +
> > +#endif

Reply via email to