162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * R-Car Gen4 SYSC Power management support 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2021 Renesas Electronics Corp. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/bits.h> 962306a36Sopenharmony_ci#include <linux/clk/renesas.h> 1062306a36Sopenharmony_ci#include <linux/delay.h> 1162306a36Sopenharmony_ci#include <linux/err.h> 1262306a36Sopenharmony_ci#include <linux/io.h> 1362306a36Sopenharmony_ci#include <linux/iopoll.h> 1462306a36Sopenharmony_ci#include <linux/kernel.h> 1562306a36Sopenharmony_ci#include <linux/mm.h> 1662306a36Sopenharmony_ci#include <linux/of_address.h> 1762306a36Sopenharmony_ci#include <linux/pm_domain.h> 1862306a36Sopenharmony_ci#include <linux/slab.h> 1962306a36Sopenharmony_ci#include <linux/spinlock.h> 2062306a36Sopenharmony_ci#include <linux/types.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include "rcar-gen4-sysc.h" 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/* SYSC Common */ 2562306a36Sopenharmony_ci#define SYSCSR 0x000 /* SYSC Status Register */ 2662306a36Sopenharmony_ci#define SYSCPONSR(x) (0x800 + ((x) * 0x4)) /* Power-ON Status Register 0 */ 2762306a36Sopenharmony_ci#define SYSCPOFFSR(x) (0x808 + ((x) * 0x4)) /* Power-OFF Status Register */ 2862306a36Sopenharmony_ci#define SYSCISCR(x) (0x810 + ((x) * 0x4)) /* Interrupt Status/Clear Register */ 2962306a36Sopenharmony_ci#define SYSCIER(x) (0x820 + ((x) * 0x4)) /* Interrupt Enable Register */ 3062306a36Sopenharmony_ci#define SYSCIMR(x) (0x830 + ((x) * 0x4)) /* Interrupt Mask Register */ 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci/* Power Domain Registers */ 3362306a36Sopenharmony_ci#define PDRSR(n) (0x1000 + ((n) * 0x40)) 3462306a36Sopenharmony_ci#define PDRONCR(n) (0x1004 + ((n) * 0x40)) 3562306a36Sopenharmony_ci#define PDROFFCR(n) (0x1008 + ((n) * 0x40)) 3662306a36Sopenharmony_ci#define PDRESR(n) (0x100C + ((n) * 0x40)) 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci/* PWRON/PWROFF */ 3962306a36Sopenharmony_ci#define PWRON_PWROFF BIT(0) /* Power-ON/OFF request */ 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci/* PDRESR */ 4262306a36Sopenharmony_ci#define PDRESR_ERR BIT(0) 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci/* PDRSR */ 4562306a36Sopenharmony_ci#define PDRSR_OFF BIT(0) /* Power-OFF state */ 4662306a36Sopenharmony_ci#define PDRSR_ON BIT(4) /* Power-ON state */ 4762306a36Sopenharmony_ci#define PDRSR_OFF_STATE BIT(8) /* Processing Power-OFF sequence */ 4862306a36Sopenharmony_ci#define PDRSR_ON_STATE BIT(12) /* Processing Power-ON sequence */ 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci#define SYSCSR_BUSY GENMASK(1, 0) /* All bit sets is not busy */ 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci#define SYSCSR_TIMEOUT 10000 5362306a36Sopenharmony_ci#define SYSCSR_DELAY_US 10 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci#define PDRESR_RETRIES 1000 5662306a36Sopenharmony_ci#define PDRESR_DELAY_US 10 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci#define SYSCISR_TIMEOUT 10000 5962306a36Sopenharmony_ci#define SYSCISR_DELAY_US 10 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci#define RCAR_GEN4_PD_ALWAYS_ON 64 6262306a36Sopenharmony_ci#define NUM_DOMAINS_EACH_REG BITS_PER_TYPE(u32) 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic void __iomem *rcar_gen4_sysc_base; 6562306a36Sopenharmony_cistatic DEFINE_SPINLOCK(rcar_gen4_sysc_lock); /* SMP CPUs + I/O devices */ 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic int rcar_gen4_sysc_pwr_on_off(u8 pdr, bool on) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci unsigned int reg_offs; 7062306a36Sopenharmony_ci u32 val; 7162306a36Sopenharmony_ci int ret; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci if (on) 7462306a36Sopenharmony_ci reg_offs = PDRONCR(pdr); 7562306a36Sopenharmony_ci else 7662306a36Sopenharmony_ci reg_offs = PDROFFCR(pdr); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci /* Wait until SYSC is ready to accept a power request */ 7962306a36Sopenharmony_ci ret = readl_poll_timeout_atomic(rcar_gen4_sysc_base + SYSCSR, val, 8062306a36Sopenharmony_ci (val & SYSCSR_BUSY) == SYSCSR_BUSY, 8162306a36Sopenharmony_ci SYSCSR_DELAY_US, SYSCSR_TIMEOUT); 8262306a36Sopenharmony_ci if (ret < 0) 8362306a36Sopenharmony_ci return -EAGAIN; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci /* Submit power shutoff or power resume request */ 8662306a36Sopenharmony_ci iowrite32(PWRON_PWROFF, rcar_gen4_sysc_base + reg_offs); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci return 0; 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic int clear_irq_flags(unsigned int reg_idx, unsigned int isr_mask) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci u32 val; 9462306a36Sopenharmony_ci int ret; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci iowrite32(isr_mask, rcar_gen4_sysc_base + SYSCISCR(reg_idx)); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci ret = readl_poll_timeout_atomic(rcar_gen4_sysc_base + SYSCISCR(reg_idx), 9962306a36Sopenharmony_ci val, !(val & isr_mask), 10062306a36Sopenharmony_ci SYSCISR_DELAY_US, SYSCISR_TIMEOUT); 10162306a36Sopenharmony_ci if (ret < 0) { 10262306a36Sopenharmony_ci pr_err("\n %s : Can not clear IRQ flags in SYSCISCR", __func__); 10362306a36Sopenharmony_ci return -EIO; 10462306a36Sopenharmony_ci } 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci return 0; 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic int rcar_gen4_sysc_power(u8 pdr, bool on) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci unsigned int isr_mask; 11262306a36Sopenharmony_ci unsigned int reg_idx, bit_idx; 11362306a36Sopenharmony_ci unsigned int status; 11462306a36Sopenharmony_ci unsigned long flags; 11562306a36Sopenharmony_ci int ret = 0; 11662306a36Sopenharmony_ci u32 val; 11762306a36Sopenharmony_ci int k; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci spin_lock_irqsave(&rcar_gen4_sysc_lock, flags); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci reg_idx = pdr / NUM_DOMAINS_EACH_REG; 12262306a36Sopenharmony_ci bit_idx = pdr % NUM_DOMAINS_EACH_REG; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci isr_mask = BIT(bit_idx); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci /* 12762306a36Sopenharmony_ci * The interrupt source needs to be enabled, but masked, to prevent the 12862306a36Sopenharmony_ci * CPU from receiving it. 12962306a36Sopenharmony_ci */ 13062306a36Sopenharmony_ci iowrite32(ioread32(rcar_gen4_sysc_base + SYSCIER(reg_idx)) | isr_mask, 13162306a36Sopenharmony_ci rcar_gen4_sysc_base + SYSCIER(reg_idx)); 13262306a36Sopenharmony_ci iowrite32(ioread32(rcar_gen4_sysc_base + SYSCIMR(reg_idx)) | isr_mask, 13362306a36Sopenharmony_ci rcar_gen4_sysc_base + SYSCIMR(reg_idx)); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci ret = clear_irq_flags(reg_idx, isr_mask); 13662306a36Sopenharmony_ci if (ret) 13762306a36Sopenharmony_ci goto out; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci /* Submit power shutoff or resume request until it was accepted */ 14062306a36Sopenharmony_ci for (k = 0; k < PDRESR_RETRIES; k++) { 14162306a36Sopenharmony_ci ret = rcar_gen4_sysc_pwr_on_off(pdr, on); 14262306a36Sopenharmony_ci if (ret) 14362306a36Sopenharmony_ci goto out; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci status = ioread32(rcar_gen4_sysc_base + PDRESR(pdr)); 14662306a36Sopenharmony_ci if (!(status & PDRESR_ERR)) 14762306a36Sopenharmony_ci break; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci udelay(PDRESR_DELAY_US); 15062306a36Sopenharmony_ci } 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci if (k == PDRESR_RETRIES) { 15362306a36Sopenharmony_ci ret = -EIO; 15462306a36Sopenharmony_ci goto out; 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci /* Wait until the power shutoff or resume request has completed * */ 15862306a36Sopenharmony_ci ret = readl_poll_timeout_atomic(rcar_gen4_sysc_base + SYSCISCR(reg_idx), 15962306a36Sopenharmony_ci val, (val & isr_mask), 16062306a36Sopenharmony_ci SYSCISR_DELAY_US, SYSCISR_TIMEOUT); 16162306a36Sopenharmony_ci if (ret < 0) { 16262306a36Sopenharmony_ci ret = -EIO; 16362306a36Sopenharmony_ci goto out; 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci /* Clear interrupt flags */ 16762306a36Sopenharmony_ci ret = clear_irq_flags(reg_idx, isr_mask); 16862306a36Sopenharmony_ci if (ret) 16962306a36Sopenharmony_ci goto out; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci out: 17262306a36Sopenharmony_ci spin_unlock_irqrestore(&rcar_gen4_sysc_lock, flags); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci pr_debug("sysc power %s domain %d: %08x -> %d\n", on ? "on" : "off", 17562306a36Sopenharmony_ci pdr, ioread32(rcar_gen4_sysc_base + SYSCISCR(reg_idx)), ret); 17662306a36Sopenharmony_ci return ret; 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_cistatic bool rcar_gen4_sysc_power_is_off(u8 pdr) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci unsigned int st; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci st = ioread32(rcar_gen4_sysc_base + PDRSR(pdr)); 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci if (st & PDRSR_OFF) 18662306a36Sopenharmony_ci return true; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci return false; 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_cistruct rcar_gen4_sysc_pd { 19262306a36Sopenharmony_ci struct generic_pm_domain genpd; 19362306a36Sopenharmony_ci u8 pdr; 19462306a36Sopenharmony_ci unsigned int flags; 19562306a36Sopenharmony_ci char name[]; 19662306a36Sopenharmony_ci}; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_cistatic inline struct rcar_gen4_sysc_pd *to_rcar_gen4_pd(struct generic_pm_domain *d) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci return container_of(d, struct rcar_gen4_sysc_pd, genpd); 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic int rcar_gen4_sysc_pd_power_off(struct generic_pm_domain *genpd) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci struct rcar_gen4_sysc_pd *pd = to_rcar_gen4_pd(genpd); 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci pr_debug("%s: %s\n", __func__, genpd->name); 20862306a36Sopenharmony_ci return rcar_gen4_sysc_power(pd->pdr, false); 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic int rcar_gen4_sysc_pd_power_on(struct generic_pm_domain *genpd) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci struct rcar_gen4_sysc_pd *pd = to_rcar_gen4_pd(genpd); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci pr_debug("%s: %s\n", __func__, genpd->name); 21662306a36Sopenharmony_ci return rcar_gen4_sysc_power(pd->pdr, true); 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistatic int __init rcar_gen4_sysc_pd_setup(struct rcar_gen4_sysc_pd *pd) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci struct generic_pm_domain *genpd = &pd->genpd; 22262306a36Sopenharmony_ci const char *name = pd->genpd.name; 22362306a36Sopenharmony_ci int error; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci if (pd->flags & PD_CPU) { 22662306a36Sopenharmony_ci /* 22762306a36Sopenharmony_ci * This domain contains a CPU core and therefore it should 22862306a36Sopenharmony_ci * only be turned off if the CPU is not in use. 22962306a36Sopenharmony_ci */ 23062306a36Sopenharmony_ci pr_debug("PM domain %s contains %s\n", name, "CPU"); 23162306a36Sopenharmony_ci genpd->flags |= GENPD_FLAG_ALWAYS_ON; 23262306a36Sopenharmony_ci } else if (pd->flags & PD_SCU) { 23362306a36Sopenharmony_ci /* 23462306a36Sopenharmony_ci * This domain contains an SCU and cache-controller, and 23562306a36Sopenharmony_ci * therefore it should only be turned off if the CPU cores are 23662306a36Sopenharmony_ci * not in use. 23762306a36Sopenharmony_ci */ 23862306a36Sopenharmony_ci pr_debug("PM domain %s contains %s\n", name, "SCU"); 23962306a36Sopenharmony_ci genpd->flags |= GENPD_FLAG_ALWAYS_ON; 24062306a36Sopenharmony_ci } else if (pd->flags & PD_NO_CR) { 24162306a36Sopenharmony_ci /* 24262306a36Sopenharmony_ci * This domain cannot be turned off. 24362306a36Sopenharmony_ci */ 24462306a36Sopenharmony_ci genpd->flags |= GENPD_FLAG_ALWAYS_ON; 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci if (!(pd->flags & (PD_CPU | PD_SCU))) { 24862306a36Sopenharmony_ci /* Enable Clock Domain for I/O devices */ 24962306a36Sopenharmony_ci genpd->flags |= GENPD_FLAG_PM_CLK | GENPD_FLAG_ACTIVE_WAKEUP; 25062306a36Sopenharmony_ci genpd->attach_dev = cpg_mssr_attach_dev; 25162306a36Sopenharmony_ci genpd->detach_dev = cpg_mssr_detach_dev; 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci genpd->power_off = rcar_gen4_sysc_pd_power_off; 25562306a36Sopenharmony_ci genpd->power_on = rcar_gen4_sysc_pd_power_on; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci if (pd->flags & (PD_CPU | PD_NO_CR)) { 25862306a36Sopenharmony_ci /* Skip CPUs (handled by SMP code) and areas without control */ 25962306a36Sopenharmony_ci pr_debug("%s: Not touching %s\n", __func__, genpd->name); 26062306a36Sopenharmony_ci goto finalize; 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci if (!rcar_gen4_sysc_power_is_off(pd->pdr)) { 26462306a36Sopenharmony_ci pr_debug("%s: %s is already powered\n", __func__, genpd->name); 26562306a36Sopenharmony_ci goto finalize; 26662306a36Sopenharmony_ci } 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci rcar_gen4_sysc_power(pd->pdr, true); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_cifinalize: 27162306a36Sopenharmony_ci error = pm_genpd_init(genpd, &simple_qos_governor, false); 27262306a36Sopenharmony_ci if (error) 27362306a36Sopenharmony_ci pr_err("Failed to init PM domain %s: %d\n", name, error); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci return error; 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_cistatic const struct of_device_id rcar_gen4_sysc_matches[] __initconst = { 27962306a36Sopenharmony_ci#ifdef CONFIG_SYSC_R8A779A0 28062306a36Sopenharmony_ci { .compatible = "renesas,r8a779a0-sysc", .data = &r8a779a0_sysc_info }, 28162306a36Sopenharmony_ci#endif 28262306a36Sopenharmony_ci#ifdef CONFIG_SYSC_R8A779F0 28362306a36Sopenharmony_ci { .compatible = "renesas,r8a779f0-sysc", .data = &r8a779f0_sysc_info }, 28462306a36Sopenharmony_ci#endif 28562306a36Sopenharmony_ci#ifdef CONFIG_SYSC_R8A779G0 28662306a36Sopenharmony_ci { .compatible = "renesas,r8a779g0-sysc", .data = &r8a779g0_sysc_info }, 28762306a36Sopenharmony_ci#endif 28862306a36Sopenharmony_ci { /* sentinel */ } 28962306a36Sopenharmony_ci}; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_cistruct rcar_gen4_pm_domains { 29262306a36Sopenharmony_ci struct genpd_onecell_data onecell_data; 29362306a36Sopenharmony_ci struct generic_pm_domain *domains[RCAR_GEN4_PD_ALWAYS_ON + 1]; 29462306a36Sopenharmony_ci}; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_cistatic struct genpd_onecell_data *rcar_gen4_sysc_onecell_data; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_cistatic int __init rcar_gen4_sysc_pd_init(void) 29962306a36Sopenharmony_ci{ 30062306a36Sopenharmony_ci const struct rcar_gen4_sysc_info *info; 30162306a36Sopenharmony_ci const struct of_device_id *match; 30262306a36Sopenharmony_ci struct rcar_gen4_pm_domains *domains; 30362306a36Sopenharmony_ci struct device_node *np; 30462306a36Sopenharmony_ci void __iomem *base; 30562306a36Sopenharmony_ci unsigned int i; 30662306a36Sopenharmony_ci int error; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci np = of_find_matching_node_and_match(NULL, rcar_gen4_sysc_matches, &match); 30962306a36Sopenharmony_ci if (!np) 31062306a36Sopenharmony_ci return -ENODEV; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci info = match->data; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci base = of_iomap(np, 0); 31562306a36Sopenharmony_ci if (!base) { 31662306a36Sopenharmony_ci pr_warn("%pOF: Cannot map regs\n", np); 31762306a36Sopenharmony_ci error = -ENOMEM; 31862306a36Sopenharmony_ci goto out_put; 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci rcar_gen4_sysc_base = base; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci domains = kzalloc(sizeof(*domains), GFP_KERNEL); 32462306a36Sopenharmony_ci if (!domains) { 32562306a36Sopenharmony_ci error = -ENOMEM; 32662306a36Sopenharmony_ci goto out_put; 32762306a36Sopenharmony_ci } 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci domains->onecell_data.domains = domains->domains; 33062306a36Sopenharmony_ci domains->onecell_data.num_domains = ARRAY_SIZE(domains->domains); 33162306a36Sopenharmony_ci rcar_gen4_sysc_onecell_data = &domains->onecell_data; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci for (i = 0; i < info->num_areas; i++) { 33462306a36Sopenharmony_ci const struct rcar_gen4_sysc_area *area = &info->areas[i]; 33562306a36Sopenharmony_ci struct rcar_gen4_sysc_pd *pd; 33662306a36Sopenharmony_ci size_t n; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci if (!area->name) { 33962306a36Sopenharmony_ci /* Skip NULLified area */ 34062306a36Sopenharmony_ci continue; 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci n = strlen(area->name) + 1; 34462306a36Sopenharmony_ci pd = kzalloc(sizeof(*pd) + n, GFP_KERNEL); 34562306a36Sopenharmony_ci if (!pd) { 34662306a36Sopenharmony_ci error = -ENOMEM; 34762306a36Sopenharmony_ci goto out_put; 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci memcpy(pd->name, area->name, n); 35162306a36Sopenharmony_ci pd->genpd.name = pd->name; 35262306a36Sopenharmony_ci pd->pdr = area->pdr; 35362306a36Sopenharmony_ci pd->flags = area->flags; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci error = rcar_gen4_sysc_pd_setup(pd); 35662306a36Sopenharmony_ci if (error) 35762306a36Sopenharmony_ci goto out_put; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci domains->domains[area->pdr] = &pd->genpd; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci if (area->parent < 0) 36262306a36Sopenharmony_ci continue; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci error = pm_genpd_add_subdomain(domains->domains[area->parent], 36562306a36Sopenharmony_ci &pd->genpd); 36662306a36Sopenharmony_ci if (error) { 36762306a36Sopenharmony_ci pr_warn("Failed to add PM subdomain %s to parent %u\n", 36862306a36Sopenharmony_ci area->name, area->parent); 36962306a36Sopenharmony_ci goto out_put; 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci } 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci error = of_genpd_add_provider_onecell(np, &domains->onecell_data); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ciout_put: 37662306a36Sopenharmony_ci of_node_put(np); 37762306a36Sopenharmony_ci return error; 37862306a36Sopenharmony_ci} 37962306a36Sopenharmony_ciearly_initcall(rcar_gen4_sysc_pd_init); 380