linux/drivers/soc/renesas/rcar-sysc.c
<<
>>
Prefs
   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
  61struct rcar_sysc_ch {
  62        u16 chan_offs;
  63        u8 chan_bit;
  64        u8 isr_bit;
  65};
  66
  67static void __iomem *rcar_sysc_base;
  68static DEFINE_SPINLOCK(rcar_sysc_lock); /* SMP CPUs + I/O devices */
  69
  70static int rcar_sysc_pwr_on_off(const struct rcar_sysc_ch *sysc_ch, bool on)
  71{
  72        unsigned int sr_bit, reg_offs;
  73        int k;
  74
  75        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
  83        /* Wait until SYSC is ready to accept a power request */
  84        for (k = 0; k < SYSCSR_RETRIES; k++) {
  85                if (ioread32(rcar_sysc_base + SYSCSR) & BIT(sr_bit))
  86                        break;
  87                udelay(SYSCSR_DELAY_US);
  88        }
  89
  90        if (k == SYSCSR_RETRIES)
  91                return -EAGAIN;
  92
  93        /* Submit power shutoff or power resume request */
  94        iowrite32(BIT(sysc_ch->chan_bit),
  95                  rcar_sysc_base + sysc_ch->chan_offs + reg_offs);
  96
  97        return 0;
  98}
  99
 100static int rcar_sysc_power(const struct rcar_sysc_ch *sysc_ch, bool on)
 101{
 102        unsigned int isr_mask = BIT(sysc_ch->isr_bit);
 103        unsigned int chan_mask = BIT(sysc_ch->chan_bit);
 104        unsigned int status;
 105        unsigned long flags;
 106        int ret = 0;
 107        int k;
 108
 109        spin_lock_irqsave(&rcar_sysc_lock, flags);
 110
 111        iowrite32(isr_mask, rcar_sysc_base + SYSCISCR);
 112
 113        /* Submit power shutoff or resume request until it was accepted */
 114        for (k = 0; k < PWRER_RETRIES; k++) {
 115                ret = rcar_sysc_pwr_on_off(sysc_ch, on);
 116                if (ret)
 117                        goto out;
 118
 119                status = ioread32(rcar_sysc_base +
 120                                  sysc_ch->chan_offs + PWRER_OFFS);
 121                if (!(status & chan_mask))
 122                        break;
 123
 124                udelay(PWRER_DELAY_US);
 125        }
 126
 127        if (k == PWRER_RETRIES) {
 128                ret = -EIO;
 129                goto out;
 130        }
 131
 132        /* Wait until the power shutoff or resume request has completed * */
 133        for (k = 0; k < SYSCISR_RETRIES; k++) {
 134                if (ioread32(rcar_sysc_base + SYSCISR) & isr_mask)
 135                        break;
 136                udelay(SYSCISR_DELAY_US);
 137        }
 138
 139        if (k == SYSCISR_RETRIES)
 140                ret = -EIO;
 141
 142        iowrite32(isr_mask, rcar_sysc_base + SYSCISCR);
 143
 144 out:
 145        spin_unlock_irqrestore(&rcar_sysc_lock, flags);
 146
 147        pr_debug("sysc power %s domain %d: %08x -> %d\n", on ? "on" : "off",
 148                 sysc_ch->isr_bit, ioread32(rcar_sysc_base + SYSCISR), ret);
 149        return ret;
 150}
 151
 152static int rcar_sysc_power_down(const struct rcar_sysc_ch *sysc_ch)
 153{
 154        return rcar_sysc_power(sysc_ch, false);
 155}
 156
 157static int rcar_sysc_power_up(const struct rcar_sysc_ch *sysc_ch)
 158{
 159        return rcar_sysc_power(sysc_ch, true);
 160}
 161
 162static bool rcar_sysc_power_is_off(const struct rcar_sysc_ch *sysc_ch)
 163{
 164        unsigned int st;
 165
 166        st = ioread32(rcar_sysc_base + sysc_ch->chan_offs + PWRSR_OFFS);
 167        if (st & BIT(sysc_ch->chan_bit))
 168                return true;
 169
 170        return false;
 171}
 172
 173struct rcar_sysc_pd {
 174        struct generic_pm_domain genpd;
 175        struct rcar_sysc_ch ch;
 176        unsigned int flags;
 177        char name[0];
 178};
 179
 180static inline struct rcar_sysc_pd *to_rcar_pd(struct generic_pm_domain *d)
 181{
 182        return container_of(d, struct rcar_sysc_pd, genpd);
 183}
 184
 185static int rcar_sysc_pd_power_off(struct generic_pm_domain *genpd)
 186{
 187        struct rcar_sysc_pd *pd = to_rcar_pd(genpd);
 188
 189        pr_debug("%s: %s\n", __func__, genpd->name);
 190        return rcar_sysc_power_down(&pd->ch);
 191}
 192
 193static int rcar_sysc_pd_power_on(struct generic_pm_domain *genpd)
 194{
 195        struct rcar_sysc_pd *pd = to_rcar_pd(genpd);
 196
 197        pr_debug("%s: %s\n", __func__, genpd->name);
 198        return rcar_sysc_power_up(&pd->ch);
 199}
 200
 201static bool has_cpg_mstp;
 202
 203static int __init rcar_sysc_pd_setup(struct rcar_sysc_pd *pd)
 204{
 205        struct generic_pm_domain *genpd = &pd->genpd;
 206        const char *name = pd->genpd.name;
 207        struct dev_power_governor *gov = &simple_qos_governor;
 208        int error;
 209
 210        if (pd->flags & PD_CPU) {
 211                /*
 212                 * This domain contains a CPU core and therefore it should
 213                 * only be turned off if the CPU is not in use.
 214                 */
 215                pr_debug("PM domain %s contains %s\n", name, "CPU");
 216                genpd->flags |= GENPD_FLAG_ALWAYS_ON;
 217        } else if (pd->flags & PD_SCU) {
 218                /*
 219                 * This domain contains an SCU and cache-controller, and
 220                 * therefore it should only be turned off if the CPU cores are
 221                 * not in use.
 222                 */
 223                pr_debug("PM domain %s contains %s\n", name, "SCU");
 224                genpd->flags |= GENPD_FLAG_ALWAYS_ON;
 225        } else if (pd->flags & PD_NO_CR) {
 226                /*
 227                 * This domain cannot be turned off.
 228                 */
 229                genpd->flags |= GENPD_FLAG_ALWAYS_ON;
 230        }
 231
 232        if (!(pd->flags & (PD_CPU | PD_SCU))) {
 233                /* Enable Clock Domain for I/O devices */
 234                genpd->flags |= GENPD_FLAG_PM_CLK | GENPD_FLAG_ACTIVE_WAKEUP;
 235                if (has_cpg_mstp) {
 236                        genpd->attach_dev = cpg_mstp_attach_dev;
 237                        genpd->detach_dev = cpg_mstp_detach_dev;
 238                } else {
 239                        genpd->attach_dev = cpg_mssr_attach_dev;
 240                        genpd->detach_dev = cpg_mssr_detach_dev;
 241                }
 242        }
 243
 244        genpd->power_off = rcar_sysc_pd_power_off;
 245        genpd->power_on = rcar_sysc_pd_power_on;
 246
 247        if (pd->flags & (PD_CPU | PD_NO_CR)) {
 248                /* Skip CPUs (handled by SMP code) and areas without control */
 249                pr_debug("%s: Not touching %s\n", __func__, genpd->name);
 250                goto finalize;
 251        }
 252
 253        if (!rcar_sysc_power_is_off(&pd->ch)) {
 254                pr_debug("%s: %s is already powered\n", __func__, genpd->name);
 255                goto finalize;
 256        }
 257
 258        rcar_sysc_power_up(&pd->ch);
 259
 260finalize:
 261        error = pm_genpd_init(genpd, gov, false);
 262        if (error)
 263                pr_err("Failed to init PM domain %s: %d\n", name, error);
 264
 265        return error;
 266}
 267
 268static const struct of_device_id rcar_sysc_matches[] __initconst = {
 269#ifdef CONFIG_SYSC_R8A7743
 270        { .compatible = "renesas,r8a7743-sysc", .data = &r8a7743_sysc_info },
 271#endif
 272#ifdef CONFIG_SYSC_R8A7745
 273        { .compatible = "renesas,r8a7745-sysc", .data = &r8a7745_sysc_info },
 274#endif
 275#ifdef CONFIG_SYSC_R8A77470
 276        { .compatible = "renesas,r8a77470-sysc", .data = &r8a77470_sysc_info },
 277#endif
 278#ifdef CONFIG_SYSC_R8A7779
 279        { .compatible = "renesas,r8a7779-sysc", .data = &r8a7779_sysc_info },
 280#endif
 281#ifdef CONFIG_SYSC_R8A7790
 282        { .compatible = "renesas,r8a7790-sysc", .data = &r8a7790_sysc_info },
 283#endif
 284#ifdef CONFIG_SYSC_R8A7791
 285        { .compatible = "renesas,r8a7791-sysc", .data = &r8a7791_sysc_info },
 286        /* R-Car M2-N is identical to R-Car M2-W w.r.t. power domains. */
 287        { .compatible = "renesas,r8a7793-sysc", .data = &r8a7791_sysc_info },
 288#endif
 289#ifdef CONFIG_SYSC_R8A7792
 290        { .compatible = "renesas,r8a7792-sysc", .data = &r8a7792_sysc_info },
 291#endif
 292#ifdef CONFIG_SYSC_R8A7794
 293        { .compatible = "renesas,r8a7794-sysc", .data = &r8a7794_sysc_info },
 294#endif
 295#ifdef CONFIG_SYSC_R8A7795
 296        { .compatible = "renesas,r8a7795-sysc", .data = &r8a7795_sysc_info },
 297#endif
 298#ifdef CONFIG_SYSC_R8A7796
 299        { .compatible = "renesas,r8a7796-sysc", .data = &r8a7796_sysc_info },
 300#endif
 301#ifdef CONFIG_SYSC_R8A77965
 302        { .compatible = "renesas,r8a77965-sysc", .data = &r8a77965_sysc_info },
 303#endif
 304#ifdef CONFIG_SYSC_R8A77970
 305        { .compatible = "renesas,r8a77970-sysc", .data = &r8a77970_sysc_info },
 306#endif
 307#ifdef CONFIG_SYSC_R8A77980
 308        { .compatible = "renesas,r8a77980-sysc", .data = &r8a77980_sysc_info },
 309#endif
 310#ifdef CONFIG_SYSC_R8A77990
 311        { .compatible = "renesas,r8a77990-sysc", .data = &r8a77990_sysc_info },
 312#endif
 313#ifdef CONFIG_SYSC_R8A77995
 314        { .compatible = "renesas,r8a77995-sysc", .data = &r8a77995_sysc_info },
 315#endif
 316        { /* sentinel */ }
 317};
 318
 319struct rcar_pm_domains {
 320        struct genpd_onecell_data onecell_data;
 321        struct generic_pm_domain *domains[RCAR_PD_ALWAYS_ON + 1];
 322};
 323
 324static struct genpd_onecell_data *rcar_sysc_onecell_data;
 325
 326static int __init rcar_sysc_pd_init(void)
 327{
 328        const struct rcar_sysc_info *info;
 329        const struct of_device_id *match;
 330        struct rcar_pm_domains *domains;
 331        struct device_node *np;
 332        u32 syscier, syscimr;
 333        void __iomem *base;
 334        unsigned int i;
 335        int error;
 336
 337        np = of_find_matching_node_and_match(NULL, rcar_sysc_matches, &match);
 338        if (!np)
 339                return -ENODEV;
 340
 341        info = match->data;
 342
 343        if (info->init) {
 344                error = info->init();
 345                if (error)
 346                        return error;
 347        }
 348
 349        has_cpg_mstp = of_find_compatible_node(NULL, NULL,
 350                                               "renesas,cpg-mstp-clocks");
 351
 352        base = of_iomap(np, 0);
 353        if (!base) {
 354                pr_warn("%pOF: Cannot map regs\n", np);
 355                error = -ENOMEM;
 356                goto out_put;
 357        }
 358
 359        rcar_sysc_base = base;
 360
 361        domains = kzalloc(sizeof(*domains), GFP_KERNEL);
 362        if (!domains) {
 363                error = -ENOMEM;
 364                goto out_put;
 365        }
 366
 367        domains->onecell_data.domains = domains->domains;
 368        domains->onecell_data.num_domains = ARRAY_SIZE(domains->domains);
 369        rcar_sysc_onecell_data = &domains->onecell_data;
 370
 371        for (i = 0, syscier = 0; i < info->num_areas; i++)
 372                syscier |= BIT(info->areas[i].isr_bit);
 373
 374        /*
 375         * Mask all interrupt sources to prevent the CPU from receiving them.
 376         * Make sure not to clear reserved bits that were set before.
 377         */
 378        syscimr = ioread32(base + SYSCIMR);
 379        syscimr |= syscier;
 380        pr_debug("%pOF: syscimr = 0x%08x\n", np, syscimr);
 381        iowrite32(syscimr, base + SYSCIMR);
 382
 383        /*
 384         * SYSC needs all interrupt sources enabled to control power.
 385         */
 386        pr_debug("%pOF: syscier = 0x%08x\n", np, syscier);
 387        iowrite32(syscier, base + SYSCIER);
 388
 389        /*
 390         * First, create all PM domains
 391         */
 392        for (i = 0; i < info->num_areas; i++) {
 393                const struct rcar_sysc_area *area = &info->areas[i];
 394                struct rcar_sysc_pd *pd;
 395
 396                if (!area->name) {
 397                        /* Skip NULLified area */
 398                        continue;
 399                }
 400
 401                pd = kzalloc(sizeof(*pd) + strlen(area->name) + 1, GFP_KERNEL);
 402                if (!pd) {
 403                        error = -ENOMEM;
 404                        goto out_put;
 405                }
 406
 407                strcpy(pd->name, area->name);
 408                pd->genpd.name = pd->name;
 409                pd->ch.chan_offs = area->chan_offs;
 410                pd->ch.chan_bit = area->chan_bit;
 411                pd->ch.isr_bit = area->isr_bit;
 412                pd->flags = area->flags;
 413
 414                error = rcar_sysc_pd_setup(pd);
 415                if (error)
 416                        goto out_put;
 417
 418                domains->domains[area->isr_bit] = &pd->genpd;
 419        }
 420
 421        /*
 422         * Second, link all PM domains to their parents
 423         */
 424        for (i = 0; i < info->num_areas; i++) {
 425                const struct rcar_sysc_area *area = &info->areas[i];
 426
 427                if (!area->name || area->parent < 0)
 428                        continue;
 429
 430                error = pm_genpd_add_subdomain(domains->domains[area->parent],
 431                                               domains->domains[area->isr_bit]);
 432                if (error)
 433                        pr_warn("Failed to add PM subdomain %s to parent %u\n",
 434                                area->name, area->parent);
 435        }
 436
 437        error = of_genpd_add_provider_onecell(np, &domains->onecell_data);
 438
 439out_put:
 440        of_node_put(np);
 441        return error;
 442}
 443early_initcall(rcar_sysc_pd_init);
 444
 445void __init rcar_sysc_nullify(struct rcar_sysc_area *areas,
 446                              unsigned int num_areas, u8 id)
 447{
 448        unsigned int i;
 449
 450        for (i = 0; i < num_areas; i++)
 451                if (areas[i].isr_bit == id) {
 452                        areas[i].name = NULL;
 453                        return;
 454                }
 455}
 456
 457#ifdef CONFIG_ARCH_R8A7779
 458static int rcar_sysc_power_cpu(unsigned int idx, bool on)
 459{
 460        struct generic_pm_domain *genpd;
 461        struct rcar_sysc_pd *pd;
 462        unsigned int i;
 463
 464        if (!rcar_sysc_onecell_data)
 465                return -ENODEV;
 466
 467        for (i = 0; i < rcar_sysc_onecell_data->num_domains; i++) {
 468                genpd = rcar_sysc_onecell_data->domains[i];
 469                if (!genpd)
 470                        continue;
 471
 472                pd = to_rcar_pd(genpd);
 473                if (!(pd->flags & PD_CPU) || pd->ch.chan_bit != idx)
 474                        continue;
 475
 476                return on ? rcar_sysc_power_up(&pd->ch)
 477                          : rcar_sysc_power_down(&pd->ch);
 478        }
 479
 480        return -ENOENT;
 481}
 482
 483int rcar_sysc_power_down_cpu(unsigned int cpu)
 484{
 485        return rcar_sysc_power_cpu(cpu, false);
 486}
 487
 488int rcar_sysc_power_up_cpu(unsigned int cpu)
 489{
 490        return rcar_sysc_power_cpu(cpu, true);
 491}
 492#endif /* CONFIG_ARCH_R8A7779 */
 493