blob: b0a80de34c98851f670c97aa1d19dc61ead62814 [file] [log] [blame]
Kuninori Morimoto41c45672018-09-07 02:04:19 +00001// SPDX-License-Identifier: GPL-2.0
Magnus Damma6557eb2014-01-15 16:43:08 +09002/*
3 * R-Car SYSC Power management support
4 *
5 * Copyright (C) 2014 Magnus Damm
Geert Uytterhoevenafa6f532017-03-31 11:01:55 +02006 * Copyright (C) 2015-2017 Glider bvba
Magnus Damma6557eb2014-01-15 16:43:08 +09007 */
8
Geert Uytterhoeven1c8c77f2016-04-20 14:02:40 +02009#include <linux/clk/renesas.h>
Magnus Damma6557eb2014-01-15 16:43:08 +090010#include <linux/delay.h>
11#include <linux/err.h>
12#include <linux/mm.h>
Geert Uytterhoevendcc09fd2016-04-20 14:02:38 +020013#include <linux/of_address.h>
14#include <linux/pm_domain.h>
15#include <linux/slab.h>
Magnus Damma6557eb2014-01-15 16:43:08 +090016#include <linux/spinlock.h>
Dan Williams2584cf82015-08-10 23:07:05 -040017#include <linux/io.h>
Geert Uytterhoeven56d6fb12021-01-25 15:26:06 +010018#include <linux/iopoll.h>
Geert Uytterhoevenbe32bcb2016-04-20 14:02:36 +020019#include <linux/soc/renesas/rcar-sysc.h>
Magnus Damma6557eb2014-01-15 16:43:08 +090020
Geert Uytterhoevendcc09fd2016-04-20 14:02:38 +020021#include "rcar-sysc.h"
22
Geert Uytterhoeven577d1042015-06-04 20:22:27 +020023/* SYSC Common */
24#define SYSCSR 0x00 /* SYSC Status Register */
25#define SYSCISR 0x04 /* Interrupt Status Register */
26#define SYSCISCR 0x08 /* Interrupt Status Clear Register */
27#define SYSCIER 0x0c /* Interrupt Enable Register */
28#define SYSCIMR 0x10 /* Interrupt Mask Register */
Magnus Damma6557eb2014-01-15 16:43:08 +090029
Geert Uytterhoeven577d1042015-06-04 20:22:27 +020030/* SYSC Status Register */
31#define SYSCSR_PONENB 1 /* Ready for power resume requests */
32#define SYSCSR_POFFENB 0 /* Ready for power shutoff requests */
Magnus Damma6557eb2014-01-15 16:43:08 +090033
Geert Uytterhoeven577d1042015-06-04 20:22:27 +020034/*
35 * Power Control Register Offsets inside the register block for each domain
36 * Note: The "CR" registers for ARM cores exist on H1 only
Geert Uytterhoevendcc09fd2016-04-20 14:02:38 +020037 * Use WFI to power off, CPG/APMU to resume ARM cores on R-Car Gen2
38 * Use PSCI on R-Car Gen3
Geert Uytterhoeven577d1042015-06-04 20:22:27 +020039 */
40#define PWRSR_OFFS 0x00 /* Power Status Register */
41#define PWROFFCR_OFFS 0x04 /* Power Shutoff Control Register */
42#define PWROFFSR_OFFS 0x08 /* Power Shutoff Status Register */
43#define PWRONCR_OFFS 0x0c /* Power Resume Control Register */
44#define PWRONSR_OFFS 0x10 /* Power Resume Status Register */
45#define PWRER_OFFS 0x14 /* Power Shutoff/Resume Error */
Magnus Damma6557eb2014-01-15 16:43:08 +090046
Geert Uytterhoeven577d1042015-06-04 20:22:27 +020047
Geert Uytterhoeven56d6fb12021-01-25 15:26:06 +010048#define SYSCSR_TIMEOUT 100
Geert Uytterhoeven577d1042015-06-04 20:22:27 +020049#define SYSCSR_DELAY_US 1
50
Geert Uytterhoeven2f575fc2015-06-04 20:22:29 +020051#define PWRER_RETRIES 100
52#define PWRER_DELAY_US 1
53
Geert Uytterhoeven56d6fb12021-01-25 15:26:06 +010054#define SYSCISR_TIMEOUT 1000
Geert Uytterhoeven577d1042015-06-04 20:22:27 +020055#define SYSCISR_DELAY_US 1
Magnus Damma6557eb2014-01-15 16:43:08 +090056
Geert Uytterhoevendcc09fd2016-04-20 14:02:38 +020057#define RCAR_PD_ALWAYS_ON 32 /* Always-on power area */
58
Geert Uytterhoeven7e8a50d2018-05-30 17:25:16 +020059struct rcar_sysc_ch {
60 u16 chan_offs;
61 u8 chan_bit;
62 u8 isr_bit;
63};
64
Magnus Dammc4ca5d82014-02-24 14:52:12 +090065static void __iomem *rcar_sysc_base;
Magnus Damma6557eb2014-01-15 16:43:08 +090066static DEFINE_SPINLOCK(rcar_sysc_lock); /* SMP CPUs + I/O devices */
Geert Uytterhoeven44b51002019-08-28 13:36:12 +020067static u32 rcar_sysc_extmask_offs, rcar_sysc_extmask_val;
Magnus Damma6557eb2014-01-15 16:43:08 +090068
Geert Uytterhoevenbcb82432015-06-04 20:22:32 +020069static int rcar_sysc_pwr_on_off(const struct rcar_sysc_ch *sysc_ch, bool on)
Magnus Damma6557eb2014-01-15 16:43:08 +090070{
Geert Uytterhoevenbcb82432015-06-04 20:22:32 +020071 unsigned int sr_bit, reg_offs;
Geert Uytterhoeven56d6fb12021-01-25 15:26:06 +010072 u32 val;
73 int ret;
Magnus Damma6557eb2014-01-15 16:43:08 +090074
Geert Uytterhoevenbcb82432015-06-04 20:22:32 +020075 if (on) {
76 sr_bit = SYSCSR_PONENB;
77 reg_offs = PWRONCR_OFFS;
78 } else {
79 sr_bit = SYSCSR_POFFENB;
80 reg_offs = PWROFFCR_OFFS;
81 }
82
Geert Uytterhoeven577d1042015-06-04 20:22:27 +020083 /* Wait until SYSC is ready to accept a power request */
Geert Uytterhoeven56d6fb12021-01-25 15:26:06 +010084 ret = readl_poll_timeout_atomic(rcar_sysc_base + SYSCSR, val,
85 val & BIT(sr_bit), SYSCSR_DELAY_US,
86 SYSCSR_TIMEOUT);
87 if (ret)
Magnus Damma6557eb2014-01-15 16:43:08 +090088 return -EAGAIN;
89
Geert Uytterhoeven577d1042015-06-04 20:22:27 +020090 /* Submit power shutoff or power resume request */
Geert Uytterhoeven21437c52015-06-04 20:22:31 +020091 iowrite32(BIT(sysc_ch->chan_bit),
Magnus Damma6557eb2014-01-15 16:43:08 +090092 rcar_sysc_base + sysc_ch->chan_offs + reg_offs);
93
94 return 0;
95}
96
Geert Uytterhoevenbcb82432015-06-04 20:22:32 +020097static int rcar_sysc_power(const struct rcar_sysc_ch *sysc_ch, bool on)
Magnus Damma6557eb2014-01-15 16:43:08 +090098{
Geert Uytterhoeven21437c52015-06-04 20:22:31 +020099 unsigned int isr_mask = BIT(sysc_ch->isr_bit);
100 unsigned int chan_mask = BIT(sysc_ch->chan_bit);
Geert Uytterhoeven56d6fb12021-01-25 15:26:06 +0100101 unsigned int status, k;
Magnus Damma6557eb2014-01-15 16:43:08 +0900102 unsigned long flags;
Geert Uytterhoeven56d6fb12021-01-25 15:26:06 +0100103 int ret;
Magnus Damma6557eb2014-01-15 16:43:08 +0900104
105 spin_lock_irqsave(&rcar_sysc_lock, flags);
106
Geert Uytterhoeven7fc46502018-12-05 16:39:45 +0100107 /*
Geert Uytterhoeven44b51002019-08-28 13:36:12 +0200108 * Mask external power requests for CPU or 3DG domains
109 */
110 if (rcar_sysc_extmask_val) {
111 iowrite32(rcar_sysc_extmask_val,
112 rcar_sysc_base + rcar_sysc_extmask_offs);
113 }
114
115 /*
Geert Uytterhoeven7fc46502018-12-05 16:39:45 +0100116 * The interrupt source needs to be enabled, but masked, to prevent the
117 * CPU from receiving it.
118 */
119 iowrite32(ioread32(rcar_sysc_base + SYSCIMR) | isr_mask,
120 rcar_sysc_base + SYSCIMR);
121 iowrite32(ioread32(rcar_sysc_base + SYSCIER) | isr_mask,
122 rcar_sysc_base + SYSCIER);
123
Magnus Damma6557eb2014-01-15 16:43:08 +0900124 iowrite32(isr_mask, rcar_sysc_base + SYSCISCR);
125
Geert Uytterhoeven577d1042015-06-04 20:22:27 +0200126 /* Submit power shutoff or resume request until it was accepted */
Geert Uytterhoeven2f575fc2015-06-04 20:22:29 +0200127 for (k = 0; k < PWRER_RETRIES; k++) {
Geert Uytterhoevenbcb82432015-06-04 20:22:32 +0200128 ret = rcar_sysc_pwr_on_off(sysc_ch, on);
Magnus Damma6557eb2014-01-15 16:43:08 +0900129 if (ret)
130 goto out;
131
132 status = ioread32(rcar_sysc_base +
133 sysc_ch->chan_offs + PWRER_OFFS);
Geert Uytterhoeven2f575fc2015-06-04 20:22:29 +0200134 if (!(status & chan_mask))
135 break;
136
137 udelay(PWRER_DELAY_US);
138 }
139
140 if (k == PWRER_RETRIES) {
141 ret = -EIO;
142 goto out;
143 }
Magnus Damma6557eb2014-01-15 16:43:08 +0900144
Geert Uytterhoeven577d1042015-06-04 20:22:27 +0200145 /* Wait until the power shutoff or resume request has completed * */
Geert Uytterhoeven56d6fb12021-01-25 15:26:06 +0100146 ret = readl_poll_timeout_atomic(rcar_sysc_base + SYSCISR, status,
147 status & isr_mask, SYSCISR_DELAY_US,
148 SYSCISR_TIMEOUT);
149 if (ret)
Magnus Damma6557eb2014-01-15 16:43:08 +0900150 ret = -EIO;
151
152 iowrite32(isr_mask, rcar_sysc_base + SYSCISCR);
153
154 out:
Geert Uytterhoeven44b51002019-08-28 13:36:12 +0200155 if (rcar_sysc_extmask_val)
156 iowrite32(0, rcar_sysc_base + rcar_sysc_extmask_offs);
157
Magnus Damma6557eb2014-01-15 16:43:08 +0900158 spin_unlock_irqrestore(&rcar_sysc_lock, flags);
159
Geert Uytterhoeven68667ce2016-04-20 14:02:37 +0200160 pr_debug("sysc power %s domain %d: %08x -> %d\n", on ? "on" : "off",
Magnus Damma6557eb2014-01-15 16:43:08 +0900161 sysc_ch->isr_bit, ioread32(rcar_sysc_base + SYSCISR), ret);
162 return ret;
163}
164
Geert Uytterhoeven2f024ce2016-04-20 14:02:39 +0200165static bool rcar_sysc_power_is_off(const struct rcar_sysc_ch *sysc_ch)
Magnus Damma6557eb2014-01-15 16:43:08 +0900166{
167 unsigned int st;
168
169 st = ioread32(rcar_sysc_base + sysc_ch->chan_offs + PWRSR_OFFS);
Geert Uytterhoeven21437c52015-06-04 20:22:31 +0200170 if (st & BIT(sysc_ch->chan_bit))
Magnus Damma6557eb2014-01-15 16:43:08 +0900171 return true;
172
173 return false;
174}
175
Geert Uytterhoevendcc09fd2016-04-20 14:02:38 +0200176struct rcar_sysc_pd {
177 struct generic_pm_domain genpd;
178 struct rcar_sysc_ch ch;
179 unsigned int flags;
Geert Uytterhoeven0ed0eb02019-06-17 14:00:56 +0200180 char name[];
Geert Uytterhoevendcc09fd2016-04-20 14:02:38 +0200181};
182
183static inline struct rcar_sysc_pd *to_rcar_pd(struct generic_pm_domain *d)
184{
185 return container_of(d, struct rcar_sysc_pd, genpd);
186}
187
188static int rcar_sysc_pd_power_off(struct generic_pm_domain *genpd)
189{
190 struct rcar_sysc_pd *pd = to_rcar_pd(genpd);
191
192 pr_debug("%s: %s\n", __func__, genpd->name);
Geert Uytterhoeven319c8402018-12-05 16:39:43 +0100193 return rcar_sysc_power(&pd->ch, false);
Geert Uytterhoevendcc09fd2016-04-20 14:02:38 +0200194}
195
196static int rcar_sysc_pd_power_on(struct generic_pm_domain *genpd)
197{
198 struct rcar_sysc_pd *pd = to_rcar_pd(genpd);
199
200 pr_debug("%s: %s\n", __func__, genpd->name);
Geert Uytterhoeven319c8402018-12-05 16:39:43 +0100201 return rcar_sysc_power(&pd->ch, true);
Geert Uytterhoevendcc09fd2016-04-20 14:02:38 +0200202}
203
Geert Uytterhoeven1c8c77f2016-04-20 14:02:40 +0200204static bool has_cpg_mstp;
205
Geert Uytterhoeven977d5ba2018-06-05 17:05:15 +0200206static int __init rcar_sysc_pd_setup(struct rcar_sysc_pd *pd)
Geert Uytterhoevendcc09fd2016-04-20 14:02:38 +0200207{
208 struct generic_pm_domain *genpd = &pd->genpd;
209 const char *name = pd->genpd.name;
Geert Uytterhoeven977d5ba2018-06-05 17:05:15 +0200210 int error;
Geert Uytterhoevendcc09fd2016-04-20 14:02:38 +0200211
212 if (pd->flags & PD_CPU) {
213 /*
214 * This domain contains a CPU core and therefore it should
215 * only be turned off if the CPU is not in use.
216 */
217 pr_debug("PM domain %s contains %s\n", name, "CPU");
Geert Uytterhoeven980532a2017-06-12 11:23:45 +0200218 genpd->flags |= GENPD_FLAG_ALWAYS_ON;
Geert Uytterhoevendcc09fd2016-04-20 14:02:38 +0200219 } else if (pd->flags & PD_SCU) {
220 /*
221 * This domain contains an SCU and cache-controller, and
222 * therefore it should only be turned off if the CPU cores are
223 * not in use.
224 */
225 pr_debug("PM domain %s contains %s\n", name, "SCU");
Geert Uytterhoeven980532a2017-06-12 11:23:45 +0200226 genpd->flags |= GENPD_FLAG_ALWAYS_ON;
Geert Uytterhoevendcc09fd2016-04-20 14:02:38 +0200227 } else if (pd->flags & PD_NO_CR) {
228 /*
229 * This domain cannot be turned off.
230 */
Geert Uytterhoeven980532a2017-06-12 11:23:45 +0200231 genpd->flags |= GENPD_FLAG_ALWAYS_ON;
Geert Uytterhoevendcc09fd2016-04-20 14:02:38 +0200232 }
233
Geert Uytterhoeven1c8c77f2016-04-20 14:02:40 +0200234 if (!(pd->flags & (PD_CPU | PD_SCU))) {
235 /* Enable Clock Domain for I/O devices */
Geert Uytterhoeven91c719f2017-11-09 14:27:02 +0100236 genpd->flags |= GENPD_FLAG_PM_CLK | GENPD_FLAG_ACTIVE_WAKEUP;
Geert Uytterhoeven1c8c77f2016-04-20 14:02:40 +0200237 if (has_cpg_mstp) {
238 genpd->attach_dev = cpg_mstp_attach_dev;
239 genpd->detach_dev = cpg_mstp_detach_dev;
240 } else {
241 genpd->attach_dev = cpg_mssr_attach_dev;
242 genpd->detach_dev = cpg_mssr_detach_dev;
243 }
244 }
245
Geert Uytterhoevendcc09fd2016-04-20 14:02:38 +0200246 genpd->power_off = rcar_sysc_pd_power_off;
247 genpd->power_on = rcar_sysc_pd_power_on;
248
249 if (pd->flags & (PD_CPU | PD_NO_CR)) {
250 /* Skip CPUs (handled by SMP code) and areas without control */
251 pr_debug("%s: Not touching %s\n", __func__, genpd->name);
252 goto finalize;
253 }
254
255 if (!rcar_sysc_power_is_off(&pd->ch)) {
256 pr_debug("%s: %s is already powered\n", __func__, genpd->name);
257 goto finalize;
258 }
259
Geert Uytterhoeven319c8402018-12-05 16:39:43 +0100260 rcar_sysc_power(&pd->ch, true);
Geert Uytterhoevendcc09fd2016-04-20 14:02:38 +0200261
262finalize:
Geert Uytterhoevene0e1df62019-08-09 16:14:32 +0200263 error = pm_genpd_init(genpd, &simple_qos_governor, false);
Geert Uytterhoeven977d5ba2018-06-05 17:05:15 +0200264 if (error)
265 pr_err("Failed to init PM domain %s: %d\n", name, error);
266
267 return error;
Geert Uytterhoevendcc09fd2016-04-20 14:02:38 +0200268}
269
Geert Uytterhoeven707aa452017-12-19 16:54:44 +0100270static const struct of_device_id rcar_sysc_matches[] __initconst = {
Lad Prabhakar5b9fa9c2020-04-23 22:40:43 +0100271#ifdef CONFIG_SYSC_R8A7742
272 { .compatible = "renesas,r8a7742-sysc", .data = &r8a7742_sysc_info },
273#endif
Geert Uytterhoeven8be381a2017-05-19 10:35:10 +0200274#ifdef CONFIG_SYSC_R8A7743
Sergei Shtylyov603311b2016-10-05 14:35:01 -0700275 { .compatible = "renesas,r8a7743-sysc", .data = &r8a7743_sysc_info },
Biju Dasc3299eb2018-09-11 11:12:44 +0100276 /* RZ/G1N is identical to RZ/G2M w.r.t. power domains. */
277 { .compatible = "renesas,r8a7744-sysc", .data = &r8a7743_sysc_info },
Sergei Shtylyov603311b2016-10-05 14:35:01 -0700278#endif
Geert Uytterhoeven8be381a2017-05-19 10:35:10 +0200279#ifdef CONFIG_SYSC_R8A7745
Sergei Shtylyov141723e2016-11-05 00:46:13 +0300280 { .compatible = "renesas,r8a7745-sysc", .data = &r8a7745_sysc_info },
281#endif
Biju Das964f7c02018-03-28 20:26:09 +0100282#ifdef CONFIG_SYSC_R8A77470
283 { .compatible = "renesas,r8a77470-sysc", .data = &r8a77470_sysc_info },
284#endif
Biju Das7f0e99c2018-08-02 15:53:19 +0100285#ifdef CONFIG_SYSC_R8A774A1
286 { .compatible = "renesas,r8a774a1-sysc", .data = &r8a774a1_sysc_info },
287#endif
Biju Das6655c562019-09-23 08:29:40 +0100288#ifdef CONFIG_SYSC_R8A774B1
289 { .compatible = "renesas,r8a774b1-sysc", .data = &r8a774b1_sysc_info },
290#endif
Fabrizio Castrof37d2112018-09-10 15:41:27 +0100291#ifdef CONFIG_SYSC_R8A774C0
292 { .compatible = "renesas,r8a774c0-sysc", .data = &r8a774c0_sysc_info },
293#endif
Marian-Cristian Rotariuf446ade2020-07-07 17:18:05 +0100294#ifdef CONFIG_SYSC_R8A774E1
295 { .compatible = "renesas,r8a774e1-sysc", .data = &r8a774e1_sysc_info },
296#endif
Geert Uytterhoeven8be381a2017-05-19 10:35:10 +0200297#ifdef CONFIG_SYSC_R8A7779
Geert Uytterhoeven9b83ea12016-04-20 14:02:41 +0200298 { .compatible = "renesas,r8a7779-sysc", .data = &r8a7779_sysc_info },
299#endif
Geert Uytterhoeven8be381a2017-05-19 10:35:10 +0200300#ifdef CONFIG_SYSC_R8A7790
Geert Uytterhoevenad7c9db2016-04-20 14:02:42 +0200301 { .compatible = "renesas,r8a7790-sysc", .data = &r8a7790_sysc_info },
302#endif
Geert Uytterhoeven8be381a2017-05-19 10:35:10 +0200303#ifdef CONFIG_SYSC_R8A7791
Geert Uytterhoevenc5fbb3c2016-04-20 14:02:43 +0200304 { .compatible = "renesas,r8a7791-sysc", .data = &r8a7791_sysc_info },
Geert Uytterhoevena247eb92016-04-20 14:02:44 +0200305 /* R-Car M2-N is identical to R-Car M2-W w.r.t. power domains. */
306 { .compatible = "renesas,r8a7793-sysc", .data = &r8a7791_sysc_info },
307#endif
Geert Uytterhoeven8be381a2017-05-19 10:35:10 +0200308#ifdef CONFIG_SYSC_R8A7792
309 { .compatible = "renesas,r8a7792-sysc", .data = &r8a7792_sysc_info },
310#endif
311#ifdef CONFIG_SYSC_R8A7794
Geert Uytterhoeven9af1dbc2016-04-20 14:02:45 +0200312 { .compatible = "renesas,r8a7794-sysc", .data = &r8a7794_sysc_info },
313#endif
Geert Uytterhoeven8be381a2017-05-19 10:35:10 +0200314#ifdef CONFIG_SYSC_R8A7795
Geert Uytterhoeven23f1e2e2016-04-20 14:02:46 +0200315 { .compatible = "renesas,r8a7795-sysc", .data = &r8a7795_sysc_info },
316#endif
Geert Uytterhoevenf79edb12019-10-23 14:33:32 +0200317#ifdef CONFIG_SYSC_R8A77960
318 { .compatible = "renesas,r8a7796-sysc", .data = &r8a77960_sysc_info },
Geert Uytterhoevene0c98b92016-05-30 19:05:11 +0200319#endif
Geert Uytterhoevenbdde3d32019-10-23 14:33:37 +0200320#ifdef CONFIG_SYSC_R8A77961
321 { .compatible = "renesas,r8a77961-sysc", .data = &r8a77961_sysc_info },
322#endif
Jacopo Mondia5277092018-02-20 16:12:06 +0100323#ifdef CONFIG_SYSC_R8A77965
324 { .compatible = "renesas,r8a77965-sysc", .data = &r8a77965_sysc_info },
325#endif
Sergei Shtylyovbab9b2a2017-09-12 23:37:20 +0300326#ifdef CONFIG_SYSC_R8A77970
327 { .compatible = "renesas,r8a77970-sysc", .data = &r8a77970_sysc_info },
328#endif
Sergei Shtylyov41d6d8b2018-02-16 21:28:02 +0300329#ifdef CONFIG_SYSC_R8A77980
330 { .compatible = "renesas,r8a77980-sysc", .data = &r8a77980_sysc_info },
331#endif
Takeshi Kihara44b12d42018-05-15 21:07:38 +0900332#ifdef CONFIG_SYSC_R8A77990
333 { .compatible = "renesas,r8a77990-sysc", .data = &r8a77990_sysc_info },
334#endif
Geert Uytterhoeveneed17c42017-07-20 14:34:53 +0200335#ifdef CONFIG_SYSC_R8A77995
336 { .compatible = "renesas,r8a77995-sysc", .data = &r8a77995_sysc_info },
337#endif
Geert Uytterhoevendcc09fd2016-04-20 14:02:38 +0200338 { /* sentinel */ }
339};
340
341struct rcar_pm_domains {
342 struct genpd_onecell_data onecell_data;
343 struct generic_pm_domain *domains[RCAR_PD_ALWAYS_ON + 1];
344};
345
Geert Uytterhoevenf2b1d2f2018-05-30 17:25:13 +0200346static struct genpd_onecell_data *rcar_sysc_onecell_data;
347
Geert Uytterhoevendcc09fd2016-04-20 14:02:38 +0200348static int __init rcar_sysc_pd_init(void)
349{
350 const struct rcar_sysc_info *info;
351 const struct of_device_id *match;
352 struct rcar_pm_domains *domains;
353 struct device_node *np;
Geert Uytterhoevendcc09fd2016-04-20 14:02:38 +0200354 void __iomem *base;
355 unsigned int i;
356 int error;
357
358 np = of_find_matching_node_and_match(NULL, rcar_sysc_matches, &match);
359 if (!np)
360 return -ENODEV;
361
362 info = match->data;
363
Geert Uytterhoevenafa6f532017-03-31 11:01:55 +0200364 if (info->init) {
365 error = info->init();
366 if (error)
Nishka Dasguptada51ced2019-08-15 11:43:54 +0530367 goto out_put;
Geert Uytterhoevenafa6f532017-03-31 11:01:55 +0200368 }
369
Geert Uytterhoeven1c8c77f2016-04-20 14:02:40 +0200370 has_cpg_mstp = of_find_compatible_node(NULL, NULL,
371 "renesas,cpg-mstp-clocks");
372
Geert Uytterhoevendcc09fd2016-04-20 14:02:38 +0200373 base = of_iomap(np, 0);
374 if (!base) {
Rob Herring37c342c2017-07-18 16:43:29 -0500375 pr_warn("%pOF: Cannot map regs\n", np);
Geert Uytterhoevendcc09fd2016-04-20 14:02:38 +0200376 error = -ENOMEM;
377 goto out_put;
378 }
379
380 rcar_sysc_base = base;
381
Geert Uytterhoeven44b51002019-08-28 13:36:12 +0200382 /* Optional External Request Mask Register */
383 rcar_sysc_extmask_offs = info->extmask_offs;
384 rcar_sysc_extmask_val = info->extmask_val;
385
Geert Uytterhoevendcc09fd2016-04-20 14:02:38 +0200386 domains = kzalloc(sizeof(*domains), GFP_KERNEL);
387 if (!domains) {
388 error = -ENOMEM;
389 goto out_put;
390 }
391
392 domains->onecell_data.domains = domains->domains;
393 domains->onecell_data.num_domains = ARRAY_SIZE(domains->domains);
Geert Uytterhoevenf2b1d2f2018-05-30 17:25:13 +0200394 rcar_sysc_onecell_data = &domains->onecell_data;
Geert Uytterhoevendcc09fd2016-04-20 14:02:38 +0200395
Geert Uytterhoevendcc09fd2016-04-20 14:02:38 +0200396 for (i = 0; i < info->num_areas; i++) {
397 const struct rcar_sysc_area *area = &info->areas[i];
398 struct rcar_sysc_pd *pd;
Len Baker148bcca2021-08-08 14:50:11 +0200399 size_t n;
Geert Uytterhoevendcc09fd2016-04-20 14:02:38 +0200400
Geert Uytterhoevenafa6f532017-03-31 11:01:55 +0200401 if (!area->name) {
402 /* Skip NULLified area */
403 continue;
404 }
405
Len Baker148bcca2021-08-08 14:50:11 +0200406 n = strlen(area->name) + 1;
407 pd = kzalloc(sizeof(*pd) + n, GFP_KERNEL);
Geert Uytterhoevendcc09fd2016-04-20 14:02:38 +0200408 if (!pd) {
409 error = -ENOMEM;
410 goto out_put;
411 }
412
Len Baker148bcca2021-08-08 14:50:11 +0200413 memcpy(pd->name, area->name, n);
Geert Uytterhoevendcc09fd2016-04-20 14:02:38 +0200414 pd->genpd.name = pd->name;
415 pd->ch.chan_offs = area->chan_offs;
416 pd->ch.chan_bit = area->chan_bit;
417 pd->ch.isr_bit = area->isr_bit;
418 pd->flags = area->flags;
419
Geert Uytterhoeven977d5ba2018-06-05 17:05:15 +0200420 error = rcar_sysc_pd_setup(pd);
421 if (error)
422 goto out_put;
Geert Uytterhoevendcc09fd2016-04-20 14:02:38 +0200423
424 domains->domains[area->isr_bit] = &pd->genpd;
Geert Uytterhoevendcc09fd2016-04-20 14:02:38 +0200425
Geert Uytterhoeven15851242018-12-05 16:39:44 +0100426 if (area->parent < 0)
Geert Uytterhoeven977d5ba2018-06-05 17:05:15 +0200427 continue;
428
429 error = pm_genpd_add_subdomain(domains->domains[area->parent],
Geert Uytterhoeven15851242018-12-05 16:39:44 +0100430 &pd->genpd);
431 if (error) {
Geert Uytterhoeven977d5ba2018-06-05 17:05:15 +0200432 pr_warn("Failed to add PM subdomain %s to parent %u\n",
433 area->name, area->parent);
Geert Uytterhoeven15851242018-12-05 16:39:44 +0100434 goto out_put;
435 }
Geert Uytterhoeven977d5ba2018-06-05 17:05:15 +0200436 }
437
Geert Uytterhoeven10235782016-06-28 16:10:31 +0200438 error = of_genpd_add_provider_onecell(np, &domains->onecell_data);
Geert Uytterhoeven2dfc5642021-01-28 09:28:47 +0100439 if (!error)
440 of_node_set_flag(np, OF_POPULATED);
Geert Uytterhoevendcc09fd2016-04-20 14:02:38 +0200441
442out_put:
443 of_node_put(np);
444 return error;
445}
446early_initcall(rcar_sysc_pd_init);
Geert Uytterhoevenb1e52282016-06-28 16:10:32 +0200447
Geert Uytterhoevenafa6f532017-03-31 11:01:55 +0200448void __init rcar_sysc_nullify(struct rcar_sysc_area *areas,
449 unsigned int num_areas, u8 id)
450{
451 unsigned int i;
452
453 for (i = 0; i < num_areas; i++)
454 if (areas[i].isr_bit == id) {
455 areas[i].name = NULL;
456 return;
457 }
458}
459
Geert Uytterhoevenf2b1d2f2018-05-30 17:25:13 +0200460#ifdef CONFIG_ARCH_R8A7779
461static int rcar_sysc_power_cpu(unsigned int idx, bool on)
Geert Uytterhoevenb1e52282016-06-28 16:10:32 +0200462{
Geert Uytterhoevenf2b1d2f2018-05-30 17:25:13 +0200463 struct generic_pm_domain *genpd;
464 struct rcar_sysc_pd *pd;
465 unsigned int i;
Geert Uytterhoevenced42732016-06-28 16:10:34 +0200466
Geert Uytterhoevenf2b1d2f2018-05-30 17:25:13 +0200467 if (!rcar_sysc_onecell_data)
468 return -ENODEV;
Geert Uytterhoevenb1e52282016-06-28 16:10:32 +0200469
Geert Uytterhoevenf2b1d2f2018-05-30 17:25:13 +0200470 for (i = 0; i < rcar_sysc_onecell_data->num_domains; i++) {
471 genpd = rcar_sysc_onecell_data->domains[i];
472 if (!genpd)
473 continue;
Geert Uytterhoeven05323992016-06-28 16:10:33 +0200474
Geert Uytterhoevenf2b1d2f2018-05-30 17:25:13 +0200475 pd = to_rcar_pd(genpd);
476 if (!(pd->flags & PD_CPU) || pd->ch.chan_bit != idx)
477 continue;
Geert Uytterhoevenced42732016-06-28 16:10:34 +0200478
Geert Uytterhoeven319c8402018-12-05 16:39:43 +0100479 return rcar_sysc_power(&pd->ch, on);
Geert Uytterhoevenf2b1d2f2018-05-30 17:25:13 +0200480 }
481
482 return -ENOENT;
Geert Uytterhoevenb1e52282016-06-28 16:10:32 +0200483}
Geert Uytterhoevenf2b1d2f2018-05-30 17:25:13 +0200484
485int rcar_sysc_power_down_cpu(unsigned int cpu)
486{
487 return rcar_sysc_power_cpu(cpu, false);
488}
489
490int rcar_sysc_power_up_cpu(unsigned int cpu)
491{
492 return rcar_sysc_power_cpu(cpu, true);
493}
494#endif /* CONFIG_ARCH_R8A7779 */