1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Renesas R-Car V3U System Controller 4 * 5 * Copyright (C) 2020 Renesas Electronics Corp. 6 */ 7 8#include <linux/bits.h> 9#include <linux/clk/renesas.h> 10#include <linux/delay.h> 11#include <linux/err.h> 12#include <linux/io.h> 13#include <linux/iopoll.h> 14#include <linux/kernel.h> 15#include <linux/mm.h> 16#include <linux/of_address.h> 17#include <linux/pm_domain.h> 18#include <linux/slab.h> 19#include <linux/spinlock.h> 20#include <linux/types.h> 21 22#include <dt-bindings/power/r8a779a0-sysc.h> 23 24/* 25 * Power Domain flags 26 */ 27#define PD_CPU BIT(0) /* Area contains main CPU core */ 28#define PD_SCU BIT(1) /* Area contains SCU and L2 cache */ 29#define PD_NO_CR BIT(2) /* Area lacks PWR{ON,OFF}CR registers */ 30 31#define PD_CPU_NOCR PD_CPU | PD_NO_CR /* CPU area lacks CR */ 32#define PD_ALWAYS_ON PD_NO_CR /* Always-on area */ 33 34/* 35 * Description of a Power Area 36 */ 37struct r8a779a0_sysc_area { 38 const char *name; 39 u8 pdr; /* PDRn */ 40 int parent; /* -1 if none */ 41 unsigned int flags; /* See PD_* */ 42}; 43 44/* 45 * SoC-specific Power Area Description 46 */ 47struct r8a779a0_sysc_info { 48 const struct r8a779a0_sysc_area *areas; 49 unsigned int num_areas; 50}; 51 52static struct r8a779a0_sysc_area r8a779a0_areas[] __initdata = { 53 { "always-on", R8A779A0_PD_ALWAYS_ON, -1, PD_ALWAYS_ON }, 54 { "a3e0", R8A779A0_PD_A3E0, R8A779A0_PD_ALWAYS_ON, PD_SCU }, 55 { "a3e1", R8A779A0_PD_A3E1, R8A779A0_PD_ALWAYS_ON, PD_SCU }, 56 { "a2e0d0", R8A779A0_PD_A2E0D0, R8A779A0_PD_A3E0, PD_SCU }, 57 { "a2e0d1", R8A779A0_PD_A2E0D1, R8A779A0_PD_A3E0, PD_SCU }, 58 { "a2e1d0", R8A779A0_PD_A2E1D0, R8A779A0_PD_A3E1, PD_SCU }, 59 { "a2e1d1", R8A779A0_PD_A2E1D1, R8A779A0_PD_A3E1, PD_SCU }, 60 { "a1e0d0c0", R8A779A0_PD_A1E0D0C0, R8A779A0_PD_A2E0D0, PD_CPU_NOCR }, 61 { "a1e0d0c1", R8A779A0_PD_A1E0D0C1, R8A779A0_PD_A2E0D0, PD_CPU_NOCR }, 62 { "a1e0d1c0", R8A779A0_PD_A1E0D1C0, R8A779A0_PD_A2E0D1, PD_CPU_NOCR }, 63 { "a1e0d1c1", R8A779A0_PD_A1E0D1C1, R8A779A0_PD_A2E0D1, PD_CPU_NOCR }, 64 { "a1e1d0c0", R8A779A0_PD_A1E1D0C0, R8A779A0_PD_A2E1D0, PD_CPU_NOCR }, 65 { "a1e1d0c1", R8A779A0_PD_A1E1D0C1, R8A779A0_PD_A2E1D0, PD_CPU_NOCR }, 66 { "a1e1d1c0", R8A779A0_PD_A1E1D1C0, R8A779A0_PD_A2E1D1, PD_CPU_NOCR }, 67 { "a1e1d1c1", R8A779A0_PD_A1E1D1C1, R8A779A0_PD_A2E1D1, PD_CPU_NOCR }, 68 { "3dg-a", R8A779A0_PD_3DG_A, R8A779A0_PD_ALWAYS_ON }, 69 { "3dg-b", R8A779A0_PD_3DG_B, R8A779A0_PD_3DG_A }, 70 { "a3vip0", R8A779A0_PD_A3VIP0, R8A779A0_PD_ALWAYS_ON }, 71 { "a3vip1", R8A779A0_PD_A3VIP1, R8A779A0_PD_ALWAYS_ON }, 72 { "a3vip3", R8A779A0_PD_A3VIP3, R8A779A0_PD_ALWAYS_ON }, 73 { "a3vip2", R8A779A0_PD_A3VIP2, R8A779A0_PD_ALWAYS_ON }, 74 { "a3isp01", R8A779A0_PD_A3ISP01, R8A779A0_PD_ALWAYS_ON }, 75 { "a3isp23", R8A779A0_PD_A3ISP23, R8A779A0_PD_ALWAYS_ON }, 76 { "a3ir", R8A779A0_PD_A3IR, R8A779A0_PD_ALWAYS_ON }, 77 { "a2cn0", R8A779A0_PD_A2CN0, R8A779A0_PD_A3IR }, 78 { "a2imp01", R8A779A0_PD_A2IMP01, R8A779A0_PD_A3IR }, 79 { "a2dp0", R8A779A0_PD_A2DP0, R8A779A0_PD_A3IR }, 80 { "a2cv0", R8A779A0_PD_A2CV0, R8A779A0_PD_A3IR }, 81 { "a2cv1", R8A779A0_PD_A2CV1, R8A779A0_PD_A3IR }, 82 { "a2cv4", R8A779A0_PD_A2CV4, R8A779A0_PD_A3IR }, 83 { "a2cv6", R8A779A0_PD_A2CV6, R8A779A0_PD_A3IR }, 84 { "a2cn2", R8A779A0_PD_A2CN2, R8A779A0_PD_A3IR }, 85 { "a2imp23", R8A779A0_PD_A2IMP23, R8A779A0_PD_A3IR }, 86 { "a2dp1", R8A779A0_PD_A2DP1, R8A779A0_PD_A3IR }, 87 { "a2cv2", R8A779A0_PD_A2CV2, R8A779A0_PD_A3IR }, 88 { "a2cv3", R8A779A0_PD_A2CV3, R8A779A0_PD_A3IR }, 89 { "a2cv5", R8A779A0_PD_A2CV5, R8A779A0_PD_A3IR }, 90 { "a2cv7", R8A779A0_PD_A2CV7, R8A779A0_PD_A3IR }, 91 { "a2cn1", R8A779A0_PD_A2CN1, R8A779A0_PD_A3IR }, 92 { "a1cnn0", R8A779A0_PD_A1CNN0, R8A779A0_PD_A2CN0 }, 93 { "a1cnn2", R8A779A0_PD_A1CNN2, R8A779A0_PD_A2CN2 }, 94 { "a1dsp0", R8A779A0_PD_A1DSP0, R8A779A0_PD_A2CN2 }, 95 { "a1cnn1", R8A779A0_PD_A1CNN1, R8A779A0_PD_A2CN1 }, 96 { "a1dsp1", R8A779A0_PD_A1DSP1, R8A779A0_PD_A2CN1 }, 97}; 98 99static const struct r8a779a0_sysc_info r8a779a0_sysc_info __initconst = { 100 .areas = r8a779a0_areas, 101 .num_areas = ARRAY_SIZE(r8a779a0_areas), 102}; 103 104/* SYSC Common */ 105#define SYSCSR 0x000 /* SYSC Status Register */ 106#define SYSCPONSR(x) (0x800 + ((x) * 0x4)) /* Power-ON Status Register 0 */ 107#define SYSCPOFFSR(x) (0x808 + ((x) * 0x4)) /* Power-OFF Status Register */ 108#define SYSCISCR(x) (0x810 + ((x) * 0x4)) /* Interrupt Status/Clear Register */ 109#define SYSCIER(x) (0x820 + ((x) * 0x4)) /* Interrupt Enable Register */ 110#define SYSCIMR(x) (0x830 + ((x) * 0x4)) /* Interrupt Mask Register */ 111 112/* Power Domain Registers */ 113#define PDRSR(n) (0x1000 + ((n) * 0x40)) 114#define PDRONCR(n) (0x1004 + ((n) * 0x40)) 115#define PDROFFCR(n) (0x1008 + ((n) * 0x40)) 116#define PDRESR(n) (0x100C + ((n) * 0x40)) 117 118/* PWRON/PWROFF */ 119#define PWRON_PWROFF BIT(0) /* Power-ON/OFF request */ 120 121/* PDRESR */ 122#define PDRESR_ERR BIT(0) 123 124/* PDRSR */ 125#define PDRSR_OFF BIT(0) /* Power-OFF state */ 126#define PDRSR_ON BIT(4) /* Power-ON state */ 127#define PDRSR_OFF_STATE BIT(8) /* Processing Power-OFF sequence */ 128#define PDRSR_ON_STATE BIT(12) /* Processing Power-ON sequence */ 129 130#define SYSCSR_BUSY GENMASK(1, 0) /* All bit sets is not busy */ 131 132#define SYSCSR_TIMEOUT 10000 133#define SYSCSR_DELAY_US 10 134 135#define PDRESR_RETRIES 1000 136#define PDRESR_DELAY_US 10 137 138#define SYSCISR_TIMEOUT 10000 139#define SYSCISR_DELAY_US 10 140 141#define NUM_DOMAINS_EACH_REG BITS_PER_TYPE(u32) 142 143static void __iomem *r8a779a0_sysc_base; 144static DEFINE_SPINLOCK(r8a779a0_sysc_lock); /* SMP CPUs + I/O devices */ 145 146static int r8a779a0_sysc_pwr_on_off(u8 pdr, bool on) 147{ 148 unsigned int reg_offs; 149 u32 val; 150 int ret; 151 152 if (on) 153 reg_offs = PDRONCR(pdr); 154 else 155 reg_offs = PDROFFCR(pdr); 156 157 /* Wait until SYSC is ready to accept a power request */ 158 ret = readl_poll_timeout_atomic(r8a779a0_sysc_base + SYSCSR, val, 159 (val & SYSCSR_BUSY) == SYSCSR_BUSY, 160 SYSCSR_DELAY_US, SYSCSR_TIMEOUT); 161 if (ret < 0) 162 return -EAGAIN; 163 164 /* Submit power shutoff or power resume request */ 165 iowrite32(PWRON_PWROFF, r8a779a0_sysc_base + reg_offs); 166 167 return 0; 168} 169 170static int clear_irq_flags(unsigned int reg_idx, unsigned int isr_mask) 171{ 172 u32 val; 173 int ret; 174 175 iowrite32(isr_mask, r8a779a0_sysc_base + SYSCISCR(reg_idx)); 176 177 ret = readl_poll_timeout_atomic(r8a779a0_sysc_base + SYSCISCR(reg_idx), 178 val, !(val & isr_mask), 179 SYSCISR_DELAY_US, SYSCISR_TIMEOUT); 180 if (ret < 0) { 181 pr_err("\n %s : Can not clear IRQ flags in SYSCISCR", __func__); 182 return -EIO; 183 } 184 185 return 0; 186} 187 188static int r8a779a0_sysc_power(u8 pdr, bool on) 189{ 190 unsigned int isr_mask; 191 unsigned int reg_idx, bit_idx; 192 unsigned int status; 193 unsigned long flags; 194 int ret = 0; 195 u32 val; 196 int k; 197 198 spin_lock_irqsave(&r8a779a0_sysc_lock, flags); 199 200 reg_idx = pdr / NUM_DOMAINS_EACH_REG; 201 bit_idx = pdr % NUM_DOMAINS_EACH_REG; 202 203 isr_mask = BIT(bit_idx); 204 205 /* 206 * The interrupt source needs to be enabled, but masked, to prevent the 207 * CPU from receiving it. 208 */ 209 iowrite32(ioread32(r8a779a0_sysc_base + SYSCIER(reg_idx)) | isr_mask, 210 r8a779a0_sysc_base + SYSCIER(reg_idx)); 211 iowrite32(ioread32(r8a779a0_sysc_base + SYSCIMR(reg_idx)) | isr_mask, 212 r8a779a0_sysc_base + SYSCIMR(reg_idx)); 213 214 ret = clear_irq_flags(reg_idx, isr_mask); 215 if (ret) 216 goto out; 217 218 /* Submit power shutoff or resume request until it was accepted */ 219 for (k = 0; k < PDRESR_RETRIES; k++) { 220 ret = r8a779a0_sysc_pwr_on_off(pdr, on); 221 if (ret) 222 goto out; 223 224 status = ioread32(r8a779a0_sysc_base + PDRESR(pdr)); 225 if (!(status & PDRESR_ERR)) 226 break; 227 228 udelay(PDRESR_DELAY_US); 229 } 230 231 if (k == PDRESR_RETRIES) { 232 ret = -EIO; 233 goto out; 234 } 235 236 /* Wait until the power shutoff or resume request has completed * */ 237 ret = readl_poll_timeout_atomic(r8a779a0_sysc_base + SYSCISCR(reg_idx), 238 val, (val & isr_mask), 239 SYSCISR_DELAY_US, SYSCISR_TIMEOUT); 240 if (ret < 0) { 241 ret = -EIO; 242 goto out; 243 } 244 245 /* Clear interrupt flags */ 246 ret = clear_irq_flags(reg_idx, isr_mask); 247 if (ret) 248 goto out; 249 250 out: 251 spin_unlock_irqrestore(&r8a779a0_sysc_lock, flags); 252 253 pr_debug("sysc power %s domain %d: %08x -> %d\n", on ? "on" : "off", 254 pdr, ioread32(r8a779a0_sysc_base + SYSCISCR(reg_idx)), ret); 255 return ret; 256} 257 258static bool r8a779a0_sysc_power_is_off(u8 pdr) 259{ 260 unsigned int st; 261 262 st = ioread32(r8a779a0_sysc_base + PDRSR(pdr)); 263 264 if (st & PDRSR_OFF) 265 return true; 266 267 return false; 268} 269 270struct r8a779a0_sysc_pd { 271 struct generic_pm_domain genpd; 272 u8 pdr; 273 unsigned int flags; 274 char name[]; 275}; 276 277static inline struct r8a779a0_sysc_pd *to_r8a779a0_pd(struct generic_pm_domain *d) 278{ 279 return container_of(d, struct r8a779a0_sysc_pd, genpd); 280} 281 282static int r8a779a0_sysc_pd_power_off(struct generic_pm_domain *genpd) 283{ 284 struct r8a779a0_sysc_pd *pd = to_r8a779a0_pd(genpd); 285 286 pr_debug("%s: %s\n", __func__, genpd->name); 287 return r8a779a0_sysc_power(pd->pdr, false); 288} 289 290static int r8a779a0_sysc_pd_power_on(struct generic_pm_domain *genpd) 291{ 292 struct r8a779a0_sysc_pd *pd = to_r8a779a0_pd(genpd); 293 294 pr_debug("%s: %s\n", __func__, genpd->name); 295 return r8a779a0_sysc_power(pd->pdr, true); 296} 297 298static int __init r8a779a0_sysc_pd_setup(struct r8a779a0_sysc_pd *pd) 299{ 300 struct generic_pm_domain *genpd = &pd->genpd; 301 const char *name = pd->genpd.name; 302 int error; 303 304 if (pd->flags & PD_CPU) { 305 /* 306 * This domain contains a CPU core and therefore it should 307 * only be turned off if the CPU is not in use. 308 */ 309 pr_debug("PM domain %s contains %s\n", name, "CPU"); 310 genpd->flags |= GENPD_FLAG_ALWAYS_ON; 311 } else if (pd->flags & PD_SCU) { 312 /* 313 * This domain contains an SCU and cache-controller, and 314 * therefore it should only be turned off if the CPU cores are 315 * not in use. 316 */ 317 pr_debug("PM domain %s contains %s\n", name, "SCU"); 318 genpd->flags |= GENPD_FLAG_ALWAYS_ON; 319 } else if (pd->flags & PD_NO_CR) { 320 /* 321 * This domain cannot be turned off. 322 */ 323 genpd->flags |= GENPD_FLAG_ALWAYS_ON; 324 } 325 326 if (!(pd->flags & (PD_CPU | PD_SCU))) { 327 /* Enable Clock Domain for I/O devices */ 328 genpd->flags |= GENPD_FLAG_PM_CLK | GENPD_FLAG_ACTIVE_WAKEUP; 329 genpd->attach_dev = cpg_mssr_attach_dev; 330 genpd->detach_dev = cpg_mssr_detach_dev; 331 } 332 333 genpd->power_off = r8a779a0_sysc_pd_power_off; 334 genpd->power_on = r8a779a0_sysc_pd_power_on; 335 336 if (pd->flags & (PD_CPU | PD_NO_CR)) { 337 /* Skip CPUs (handled by SMP code) and areas without control */ 338 pr_debug("%s: Not touching %s\n", __func__, genpd->name); 339 goto finalize; 340 } 341 342 if (!r8a779a0_sysc_power_is_off(pd->pdr)) { 343 pr_debug("%s: %s is already powered\n", __func__, genpd->name); 344 goto finalize; 345 } 346 347 r8a779a0_sysc_power(pd->pdr, true); 348 349finalize: 350 error = pm_genpd_init(genpd, &simple_qos_governor, false); 351 if (error) 352 pr_err("Failed to init PM domain %s: %d\n", name, error); 353 354 return error; 355} 356 357static const struct of_device_id r8a779a0_sysc_matches[] __initconst = { 358 { .compatible = "renesas,r8a779a0-sysc", .data = &r8a779a0_sysc_info }, 359 { /* sentinel */ } 360}; 361 362struct r8a779a0_pm_domains { 363 struct genpd_onecell_data onecell_data; 364 struct generic_pm_domain *domains[R8A779A0_PD_ALWAYS_ON + 1]; 365}; 366 367static struct genpd_onecell_data *r8a779a0_sysc_onecell_data; 368 369static int __init r8a779a0_sysc_pd_init(void) 370{ 371 const struct r8a779a0_sysc_info *info; 372 const struct of_device_id *match; 373 struct r8a779a0_pm_domains *domains; 374 struct device_node *np; 375 void __iomem *base; 376 unsigned int i; 377 int error; 378 379 np = of_find_matching_node_and_match(NULL, r8a779a0_sysc_matches, &match); 380 if (!np) 381 return -ENODEV; 382 383 info = match->data; 384 385 base = of_iomap(np, 0); 386 if (!base) { 387 pr_warn("%pOF: Cannot map regs\n", np); 388 error = -ENOMEM; 389 goto out_put; 390 } 391 392 r8a779a0_sysc_base = base; 393 394 domains = kzalloc(sizeof(*domains), GFP_KERNEL); 395 if (!domains) { 396 error = -ENOMEM; 397 goto out_put; 398 } 399 400 domains->onecell_data.domains = domains->domains; 401 domains->onecell_data.num_domains = ARRAY_SIZE(domains->domains); 402 r8a779a0_sysc_onecell_data = &domains->onecell_data; 403 404 for (i = 0; i < info->num_areas; i++) { 405 const struct r8a779a0_sysc_area *area = &info->areas[i]; 406 struct r8a779a0_sysc_pd *pd; 407 408 if (!area->name) { 409 /* Skip NULLified area */ 410 continue; 411 } 412 413 pd = kzalloc(sizeof(*pd) + strlen(area->name) + 1, GFP_KERNEL); 414 if (!pd) { 415 error = -ENOMEM; 416 goto out_put; 417 } 418 419 strcpy(pd->name, area->name); 420 pd->genpd.name = pd->name; 421 pd->pdr = area->pdr; 422 pd->flags = area->flags; 423 424 error = r8a779a0_sysc_pd_setup(pd); 425 if (error) 426 goto out_put; 427 428 domains->domains[area->pdr] = &pd->genpd; 429 430 if (area->parent < 0) 431 continue; 432 433 error = pm_genpd_add_subdomain(domains->domains[area->parent], 434 &pd->genpd); 435 if (error) { 436 pr_warn("Failed to add PM subdomain %s to parent %u\n", 437 area->name, area->parent); 438 goto out_put; 439 } 440 } 441 442 error = of_genpd_add_provider_onecell(np, &domains->onecell_data); 443 444out_put: 445 of_node_put(np); 446 return error; 447} 448early_initcall(r8a779a0_sysc_pd_init); 449