1
0
Fork 0

MLK-15149-01 driver: soc: add gpc power domain support on i.mx8mq

Add generic power domain driver support on i.mx8mq. The power
domain on/off operations need to use the SIP service call to
trap into secure monitor to handle it.

Signed-off-by: Bai Ping <ping.bai@nxp.com>
pull/10/head
Bai Ping 2017-06-23 16:22:40 +08:00 committed by Jason Liu
parent 7f5a18458a
commit eda7bfe5f4
2 changed files with 121 additions and 9 deletions

View File

@ -20,50 +20,62 @@
#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/pm_domain.h>
#include <soc/imx/fsl_sip.h>
#define GPC_MAX_IRQS (4 * 32)
struct imx_gpc_pm_domain {
char name[30];
struct generic_pm_domain pd;
u32 gpc_domain_id;
};
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 void imx_gpc_psci_irq_unmask(struct irq_data *d)
{
unsigned long flags;
struct arm_smccc_res res;
spin_lock_irqsave(&gpc_psci_lock, flags);
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_irqrestore(&gpc_psci_lock, flags);
spin_unlock(&gpc_psci_lock);
irq_chip_unmask_parent(d);
}
static void imx_gpc_psci_irq_mask(struct irq_data *d)
{
unsigned long flags;
struct arm_smccc_res res;
spin_lock_irqsave(&gpc_psci_lock, flags);
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_irqrestore(&gpc_psci_lock, flags);
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)
{
unsigned long flags;
struct arm_smccc_res res;
spin_lock_irqsave(&gpc_psci_lock, flags);
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_irqrestore(&gpc_psci_lock, flags);
spin_unlock(&gpc_psci_lock);
return 0;
}
@ -161,3 +173,102 @@ static int __init imx_gpc_psci_init(struct device_node *node,
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;
spin_lock(&gpc_psci_lock);
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);
spin_unlock(&gpc_psci_lock);
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;
spin_lock(&gpc_psci_lock);
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);
spin_unlock(&gpc_psci_lock);
return 0;
};
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;
struct genpd_onecell_data *imx_pd_data;
struct generic_pm_domain **domains;
int ret, num_domains, i;
pr_info("imx8mq pm domain init\n");
if (!np) {
dev_err(dev, "device tree node not found\n");
return -ENODEV;
}
ret = of_property_read_u32(np, "num-domains", &num_domains);
if (ret) {
dev_err(dev, "number of domains not found\n");
return -EINVAL;
};
imx_pm_domain = devm_kcalloc(dev, num_domains, sizeof(*imx_pm_domain), GFP_KERNEL);
if (!imx_pm_domain)
return -ENOMEM;
imx_pd_data = devm_kzalloc(dev, sizeof(*imx_pd_data), GFP_KERNEL);
if (!imx_pd_data)
return -ENOMEM;
domains = devm_kcalloc(dev, num_domains, sizeof(*domains), GFP_KERNEL);
if (!domains)
return -ENOMEM;
for (i = 0; i < num_domains; i++, imx_pm_domain++) {
domains[i] = &imx_pm_domain->pd;
imx_pm_domain->gpc_domain_id = i;
sprintf(imx_pm_domain->name, "%s.%d", np->name, i);
imx_pm_domain->pd.name = imx_pm_domain->name;
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);
}
imx_pd_data->domains = domains;
imx_pd_data->num_domains = num_domains;
of_genpd_add_provider_onecell(np, imx_pd_data);
return 0;
}
static const struct of_device_id imx_gpc_pm_domain_ids[] = {
{.compatible = "fsl,imx8mq-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");

View File

@ -14,5 +14,6 @@
#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
#endif