Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.13-rc7 433 lines 11 kB view raw
1/* 2 * R-Car SYSC Power management support 3 * 4 * Copyright (C) 2014 Magnus Damm 5 * Copyright (C) 2015-2017 Glider bvba 6 * 7 * This file is subject to the terms and conditions of the GNU General Public 8 * License. See the file "COPYING" in the main directory of this archive 9 * for more details. 10 */ 11 12#include <linux/clk/renesas.h> 13#include <linux/delay.h> 14#include <linux/err.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/io.h> 21#include <linux/soc/renesas/rcar-sysc.h> 22 23#include "rcar-sysc.h" 24 25/* SYSC Common */ 26#define SYSCSR 0x00 /* SYSC Status Register */ 27#define SYSCISR 0x04 /* Interrupt Status Register */ 28#define SYSCISCR 0x08 /* Interrupt Status Clear Register */ 29#define SYSCIER 0x0c /* Interrupt Enable Register */ 30#define SYSCIMR 0x10 /* Interrupt Mask Register */ 31 32/* SYSC Status Register */ 33#define SYSCSR_PONENB 1 /* Ready for power resume requests */ 34#define SYSCSR_POFFENB 0 /* Ready for power shutoff requests */ 35 36/* 37 * Power Control Register Offsets inside the register block for each domain 38 * Note: The "CR" registers for ARM cores exist on H1 only 39 * Use WFI to power off, CPG/APMU to resume ARM cores on R-Car Gen2 40 * Use PSCI on R-Car Gen3 41 */ 42#define PWRSR_OFFS 0x00 /* Power Status Register */ 43#define PWROFFCR_OFFS 0x04 /* Power Shutoff Control Register */ 44#define PWROFFSR_OFFS 0x08 /* Power Shutoff Status Register */ 45#define PWRONCR_OFFS 0x0c /* Power Resume Control Register */ 46#define PWRONSR_OFFS 0x10 /* Power Resume Status Register */ 47#define PWRER_OFFS 0x14 /* Power Shutoff/Resume Error */ 48 49 50#define SYSCSR_RETRIES 100 51#define SYSCSR_DELAY_US 1 52 53#define PWRER_RETRIES 100 54#define PWRER_DELAY_US 1 55 56#define SYSCISR_RETRIES 1000 57#define SYSCISR_DELAY_US 1 58 59#define RCAR_PD_ALWAYS_ON 32 /* Always-on power area */ 60 61static void __iomem *rcar_sysc_base; 62static DEFINE_SPINLOCK(rcar_sysc_lock); /* SMP CPUs + I/O devices */ 63 64static int rcar_sysc_pwr_on_off(const struct rcar_sysc_ch *sysc_ch, bool on) 65{ 66 unsigned int sr_bit, reg_offs; 67 int k; 68 69 if (on) { 70 sr_bit = SYSCSR_PONENB; 71 reg_offs = PWRONCR_OFFS; 72 } else { 73 sr_bit = SYSCSR_POFFENB; 74 reg_offs = PWROFFCR_OFFS; 75 } 76 77 /* Wait until SYSC is ready to accept a power request */ 78 for (k = 0; k < SYSCSR_RETRIES; k++) { 79 if (ioread32(rcar_sysc_base + SYSCSR) & BIT(sr_bit)) 80 break; 81 udelay(SYSCSR_DELAY_US); 82 } 83 84 if (k == SYSCSR_RETRIES) 85 return -EAGAIN; 86 87 /* Submit power shutoff or power resume request */ 88 iowrite32(BIT(sysc_ch->chan_bit), 89 rcar_sysc_base + sysc_ch->chan_offs + reg_offs); 90 91 return 0; 92} 93 94static int rcar_sysc_power(const struct rcar_sysc_ch *sysc_ch, bool on) 95{ 96 unsigned int isr_mask = BIT(sysc_ch->isr_bit); 97 unsigned int chan_mask = BIT(sysc_ch->chan_bit); 98 unsigned int status; 99 unsigned long flags; 100 int ret = 0; 101 int k; 102 103 spin_lock_irqsave(&rcar_sysc_lock, flags); 104 105 iowrite32(isr_mask, rcar_sysc_base + SYSCISCR); 106 107 /* Submit power shutoff or resume request until it was accepted */ 108 for (k = 0; k < PWRER_RETRIES; k++) { 109 ret = rcar_sysc_pwr_on_off(sysc_ch, on); 110 if (ret) 111 goto out; 112 113 status = ioread32(rcar_sysc_base + 114 sysc_ch->chan_offs + PWRER_OFFS); 115 if (!(status & chan_mask)) 116 break; 117 118 udelay(PWRER_DELAY_US); 119 } 120 121 if (k == PWRER_RETRIES) { 122 ret = -EIO; 123 goto out; 124 } 125 126 /* Wait until the power shutoff or resume request has completed * */ 127 for (k = 0; k < SYSCISR_RETRIES; k++) { 128 if (ioread32(rcar_sysc_base + SYSCISR) & isr_mask) 129 break; 130 udelay(SYSCISR_DELAY_US); 131 } 132 133 if (k == SYSCISR_RETRIES) 134 ret = -EIO; 135 136 iowrite32(isr_mask, rcar_sysc_base + SYSCISCR); 137 138 out: 139 spin_unlock_irqrestore(&rcar_sysc_lock, flags); 140 141 pr_debug("sysc power %s domain %d: %08x -> %d\n", on ? "on" : "off", 142 sysc_ch->isr_bit, ioread32(rcar_sysc_base + SYSCISR), ret); 143 return ret; 144} 145 146int rcar_sysc_power_down(const struct rcar_sysc_ch *sysc_ch) 147{ 148 return rcar_sysc_power(sysc_ch, false); 149} 150 151int rcar_sysc_power_up(const struct rcar_sysc_ch *sysc_ch) 152{ 153 return rcar_sysc_power(sysc_ch, true); 154} 155 156static bool rcar_sysc_power_is_off(const struct rcar_sysc_ch *sysc_ch) 157{ 158 unsigned int st; 159 160 st = ioread32(rcar_sysc_base + sysc_ch->chan_offs + PWRSR_OFFS); 161 if (st & BIT(sysc_ch->chan_bit)) 162 return true; 163 164 return false; 165} 166 167struct rcar_sysc_pd { 168 struct generic_pm_domain genpd; 169 struct rcar_sysc_ch ch; 170 unsigned int flags; 171 char name[0]; 172}; 173 174static inline struct rcar_sysc_pd *to_rcar_pd(struct generic_pm_domain *d) 175{ 176 return container_of(d, struct rcar_sysc_pd, genpd); 177} 178 179static int rcar_sysc_pd_power_off(struct generic_pm_domain *genpd) 180{ 181 struct rcar_sysc_pd *pd = to_rcar_pd(genpd); 182 183 pr_debug("%s: %s\n", __func__, genpd->name); 184 return rcar_sysc_power_down(&pd->ch); 185} 186 187static int rcar_sysc_pd_power_on(struct generic_pm_domain *genpd) 188{ 189 struct rcar_sysc_pd *pd = to_rcar_pd(genpd); 190 191 pr_debug("%s: %s\n", __func__, genpd->name); 192 return rcar_sysc_power_up(&pd->ch); 193} 194 195static bool has_cpg_mstp; 196 197static void __init rcar_sysc_pd_setup(struct rcar_sysc_pd *pd) 198{ 199 struct generic_pm_domain *genpd = &pd->genpd; 200 const char *name = pd->genpd.name; 201 struct dev_power_governor *gov = &simple_qos_governor; 202 203 if (pd->flags & PD_CPU) { 204 /* 205 * This domain contains a CPU core and therefore it should 206 * only be turned off if the CPU is not in use. 207 */ 208 pr_debug("PM domain %s contains %s\n", name, "CPU"); 209 genpd->flags |= GENPD_FLAG_ALWAYS_ON; 210 } else if (pd->flags & PD_SCU) { 211 /* 212 * This domain contains an SCU and cache-controller, and 213 * therefore it should only be turned off if the CPU cores are 214 * not in use. 215 */ 216 pr_debug("PM domain %s contains %s\n", name, "SCU"); 217 genpd->flags |= GENPD_FLAG_ALWAYS_ON; 218 } else if (pd->flags & PD_NO_CR) { 219 /* 220 * This domain cannot be turned off. 221 */ 222 genpd->flags |= GENPD_FLAG_ALWAYS_ON; 223 } 224 225 if (!(pd->flags & (PD_CPU | PD_SCU))) { 226 /* Enable Clock Domain for I/O devices */ 227 genpd->flags |= GENPD_FLAG_PM_CLK; 228 if (has_cpg_mstp) { 229 genpd->attach_dev = cpg_mstp_attach_dev; 230 genpd->detach_dev = cpg_mstp_detach_dev; 231 } else { 232 genpd->attach_dev = cpg_mssr_attach_dev; 233 genpd->detach_dev = cpg_mssr_detach_dev; 234 } 235 } 236 237 genpd->power_off = rcar_sysc_pd_power_off; 238 genpd->power_on = rcar_sysc_pd_power_on; 239 240 if (pd->flags & (PD_CPU | PD_NO_CR)) { 241 /* Skip CPUs (handled by SMP code) and areas without control */ 242 pr_debug("%s: Not touching %s\n", __func__, genpd->name); 243 goto finalize; 244 } 245 246 if (!rcar_sysc_power_is_off(&pd->ch)) { 247 pr_debug("%s: %s is already powered\n", __func__, genpd->name); 248 goto finalize; 249 } 250 251 rcar_sysc_power_up(&pd->ch); 252 253finalize: 254 pm_genpd_init(genpd, gov, false); 255} 256 257static const struct of_device_id rcar_sysc_matches[] = { 258#ifdef CONFIG_SYSC_R8A7743 259 { .compatible = "renesas,r8a7743-sysc", .data = &r8a7743_sysc_info }, 260#endif 261#ifdef CONFIG_SYSC_R8A7745 262 { .compatible = "renesas,r8a7745-sysc", .data = &r8a7745_sysc_info }, 263#endif 264#ifdef CONFIG_SYSC_R8A7779 265 { .compatible = "renesas,r8a7779-sysc", .data = &r8a7779_sysc_info }, 266#endif 267#ifdef CONFIG_SYSC_R8A7790 268 { .compatible = "renesas,r8a7790-sysc", .data = &r8a7790_sysc_info }, 269#endif 270#ifdef CONFIG_SYSC_R8A7791 271 { .compatible = "renesas,r8a7791-sysc", .data = &r8a7791_sysc_info }, 272 /* R-Car M2-N is identical to R-Car M2-W w.r.t. power domains. */ 273 { .compatible = "renesas,r8a7793-sysc", .data = &r8a7791_sysc_info }, 274#endif 275#ifdef CONFIG_SYSC_R8A7792 276 { .compatible = "renesas,r8a7792-sysc", .data = &r8a7792_sysc_info }, 277#endif 278#ifdef CONFIG_SYSC_R8A7794 279 { .compatible = "renesas,r8a7794-sysc", .data = &r8a7794_sysc_info }, 280#endif 281#ifdef CONFIG_SYSC_R8A7795 282 { .compatible = "renesas,r8a7795-sysc", .data = &r8a7795_sysc_info }, 283#endif 284#ifdef CONFIG_SYSC_R8A7796 285 { .compatible = "renesas,r8a7796-sysc", .data = &r8a7796_sysc_info }, 286#endif 287 { /* sentinel */ } 288}; 289 290struct rcar_pm_domains { 291 struct genpd_onecell_data onecell_data; 292 struct generic_pm_domain *domains[RCAR_PD_ALWAYS_ON + 1]; 293}; 294 295static int __init rcar_sysc_pd_init(void) 296{ 297 const struct rcar_sysc_info *info; 298 const struct of_device_id *match; 299 struct rcar_pm_domains *domains; 300 struct device_node *np; 301 u32 syscier, syscimr; 302 void __iomem *base; 303 unsigned int i; 304 int error; 305 306 if (rcar_sysc_base) 307 return 0; 308 309 np = of_find_matching_node_and_match(NULL, rcar_sysc_matches, &match); 310 if (!np) 311 return -ENODEV; 312 313 info = match->data; 314 315 if (info->init) { 316 error = info->init(); 317 if (error) 318 return error; 319 } 320 321 has_cpg_mstp = of_find_compatible_node(NULL, NULL, 322 "renesas,cpg-mstp-clocks"); 323 324 base = of_iomap(np, 0); 325 if (!base) { 326 pr_warn("%s: Cannot map regs\n", np->full_name); 327 error = -ENOMEM; 328 goto out_put; 329 } 330 331 rcar_sysc_base = base; 332 333 domains = kzalloc(sizeof(*domains), GFP_KERNEL); 334 if (!domains) { 335 error = -ENOMEM; 336 goto out_put; 337 } 338 339 domains->onecell_data.domains = domains->domains; 340 domains->onecell_data.num_domains = ARRAY_SIZE(domains->domains); 341 342 for (i = 0, syscier = 0; i < info->num_areas; i++) 343 syscier |= BIT(info->areas[i].isr_bit); 344 345 /* 346 * Mask all interrupt sources to prevent the CPU from receiving them. 347 * Make sure not to clear reserved bits that were set before. 348 */ 349 syscimr = ioread32(base + SYSCIMR); 350 syscimr |= syscier; 351 pr_debug("%s: syscimr = 0x%08x\n", np->full_name, syscimr); 352 iowrite32(syscimr, base + SYSCIMR); 353 354 /* 355 * SYSC needs all interrupt sources enabled to control power. 356 */ 357 pr_debug("%s: syscier = 0x%08x\n", np->full_name, syscier); 358 iowrite32(syscier, base + SYSCIER); 359 360 for (i = 0; i < info->num_areas; i++) { 361 const struct rcar_sysc_area *area = &info->areas[i]; 362 struct rcar_sysc_pd *pd; 363 364 if (!area->name) { 365 /* Skip NULLified area */ 366 continue; 367 } 368 369 pd = kzalloc(sizeof(*pd) + strlen(area->name) + 1, GFP_KERNEL); 370 if (!pd) { 371 error = -ENOMEM; 372 goto out_put; 373 } 374 375 strcpy(pd->name, area->name); 376 pd->genpd.name = pd->name; 377 pd->ch.chan_offs = area->chan_offs; 378 pd->ch.chan_bit = area->chan_bit; 379 pd->ch.isr_bit = area->isr_bit; 380 pd->flags = area->flags; 381 382 rcar_sysc_pd_setup(pd); 383 if (area->parent >= 0) 384 pm_genpd_add_subdomain(domains->domains[area->parent], 385 &pd->genpd); 386 387 domains->domains[area->isr_bit] = &pd->genpd; 388 } 389 390 error = of_genpd_add_provider_onecell(np, &domains->onecell_data); 391 392out_put: 393 of_node_put(np); 394 return error; 395} 396early_initcall(rcar_sysc_pd_init); 397 398void __init rcar_sysc_nullify(struct rcar_sysc_area *areas, 399 unsigned int num_areas, u8 id) 400{ 401 unsigned int i; 402 403 for (i = 0; i < num_areas; i++) 404 if (areas[i].isr_bit == id) { 405 areas[i].name = NULL; 406 return; 407 } 408} 409 410void __init rcar_sysc_init(phys_addr_t base, u32 syscier) 411{ 412 u32 syscimr; 413 414 if (!rcar_sysc_pd_init()) 415 return; 416 417 rcar_sysc_base = ioremap_nocache(base, PAGE_SIZE); 418 419 /* 420 * Mask all interrupt sources to prevent the CPU from receiving them. 421 * Make sure not to clear reserved bits that were set before. 422 */ 423 syscimr = ioread32(rcar_sysc_base + SYSCIMR); 424 syscimr |= syscier; 425 pr_debug("%s: syscimr = 0x%08x\n", __func__, syscimr); 426 iowrite32(syscimr, rcar_sysc_base + SYSCIMR); 427 428 /* 429 * SYSC needs all interrupt sources enabled to control power. 430 */ 431 pr_debug("%s: syscier = 0x%08x\n", __func__, syscier); 432 iowrite32(syscier, rcar_sysc_base + SYSCIER); 433}