linux/arch/arm/mach-exynos/suspend.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd.
   3 *              http://www.samsung.com
   4 *
   5 * EXYNOS - Suspend support
   6 *
   7 * Based on arch/arm/mach-s3c2410/pm.c
   8 * Copyright (c) 2006 Simtec Electronics
   9 *      Ben Dooks <ben@simtec.co.uk>
  10 *
  11 * This program is free software; you can redistribute it and/or modify
  12 * it under the terms of the GNU General Public License version 2 as
  13 * published by the Free Software Foundation.
  14 */
  15
  16#include <linux/init.h>
  17#include <linux/suspend.h>
  18#include <linux/syscore_ops.h>
  19#include <linux/cpu_pm.h>
  20#include <linux/io.h>
  21#include <linux/irq.h>
  22#include <linux/irqchip.h>
  23#include <linux/irqdomain.h>
  24#include <linux/of_address.h>
  25#include <linux/err.h>
  26#include <linux/regulator/machine.h>
  27#include <linux/soc/samsung/exynos-pmu.h>
  28#include <linux/soc/samsung/exynos-regs-pmu.h>
  29
  30#include <asm/cacheflush.h>
  31#include <asm/hardware/cache-l2x0.h>
  32#include <asm/firmware.h>
  33#include <asm/mcpm.h>
  34#include <asm/smp_scu.h>
  35#include <asm/suspend.h>
  36
  37#include <mach/map.h>
  38
  39#include <plat/pm-common.h>
  40
  41#include "common.h"
  42
  43#define REG_TABLE_END (-1U)
  44
  45#define EXYNOS5420_CPU_STATE    0x28
  46
  47/**
  48 * struct exynos_wkup_irq - PMU IRQ to mask mapping
  49 * @hwirq: Hardware IRQ signal of the PMU
  50 * @mask: Mask in PMU wake-up mask register
  51 */
  52struct exynos_wkup_irq {
  53        unsigned int hwirq;
  54        u32 mask;
  55};
  56
  57struct exynos_pm_data {
  58        const struct exynos_wkup_irq *wkup_irq;
  59        unsigned int wake_disable_mask;
  60
  61        void (*pm_prepare)(void);
  62        void (*pm_resume_prepare)(void);
  63        void (*pm_resume)(void);
  64        int (*pm_suspend)(void);
  65        int (*cpu_suspend)(unsigned long);
  66};
  67
  68static const struct exynos_pm_data *pm_data __ro_after_init;
  69
  70static int exynos5420_cpu_state;
  71static unsigned int exynos_pmu_spare3;
  72
  73/*
  74 * GIC wake-up support
  75 */
  76
  77static u32 exynos_irqwake_intmask = 0xffffffff;
  78
  79static const struct exynos_wkup_irq exynos3250_wkup_irq[] = {
  80        { 73, BIT(1) }, /* RTC alarm */
  81        { 74, BIT(2) }, /* RTC tick */
  82        { /* sentinel */ },
  83};
  84
  85static const struct exynos_wkup_irq exynos4_wkup_irq[] = {
  86        { 44, BIT(1) }, /* RTC alarm */
  87        { 45, BIT(2) }, /* RTC tick */
  88        { /* sentinel */ },
  89};
  90
  91static const struct exynos_wkup_irq exynos5250_wkup_irq[] = {
  92        { 43, BIT(1) }, /* RTC alarm */
  93        { 44, BIT(2) }, /* RTC tick */
  94        { /* sentinel */ },
  95};
  96
  97static int exynos_irq_set_wake(struct irq_data *data, unsigned int state)
  98{
  99        const struct exynos_wkup_irq *wkup_irq;
 100
 101        if (!pm_data->wkup_irq)
 102                return -ENOENT;
 103        wkup_irq = pm_data->wkup_irq;
 104
 105        while (wkup_irq->mask) {
 106                if (wkup_irq->hwirq == data->hwirq) {
 107                        if (!state)
 108                                exynos_irqwake_intmask |= wkup_irq->mask;
 109                        else
 110                                exynos_irqwake_intmask &= ~wkup_irq->mask;
 111                        return 0;
 112                }
 113                ++wkup_irq;
 114        }
 115
 116        return -ENOENT;
 117}
 118
 119static struct irq_chip exynos_pmu_chip = {
 120        .name                   = "PMU",
 121        .irq_eoi                = irq_chip_eoi_parent,
 122        .irq_mask               = irq_chip_mask_parent,
 123        .irq_unmask             = irq_chip_unmask_parent,
 124        .irq_retrigger          = irq_chip_retrigger_hierarchy,
 125        .irq_set_wake           = exynos_irq_set_wake,
 126#ifdef CONFIG_SMP
 127        .irq_set_affinity       = irq_chip_set_affinity_parent,
 128#endif
 129};
 130
 131static int exynos_pmu_domain_translate(struct irq_domain *d,
 132                                       struct irq_fwspec *fwspec,
 133                                       unsigned long *hwirq,
 134                                       unsigned int *type)
 135{
 136        if (is_of_node(fwspec->fwnode)) {
 137                if (fwspec->param_count != 3)
 138                        return -EINVAL;
 139
 140                /* No PPI should point to this domain */
 141                if (fwspec->param[0] != 0)
 142                        return -EINVAL;
 143
 144                *hwirq = fwspec->param[1];
 145                *type = fwspec->param[2];
 146                return 0;
 147        }
 148
 149        return -EINVAL;
 150}
 151
 152static int exynos_pmu_domain_alloc(struct irq_domain *domain,
 153                                   unsigned int virq,
 154                                   unsigned int nr_irqs, void *data)
 155{
 156        struct irq_fwspec *fwspec = data;
 157        struct irq_fwspec parent_fwspec;
 158        irq_hw_number_t hwirq;
 159        int i;
 160
 161        if (fwspec->param_count != 3)
 162                return -EINVAL; /* Not GIC compliant */
 163        if (fwspec->param[0] != 0)
 164                return -EINVAL; /* No PPI should point to this domain */
 165
 166        hwirq = fwspec->param[1];
 167
 168        for (i = 0; i < nr_irqs; i++)
 169                irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
 170                                              &exynos_pmu_chip, NULL);
 171
 172        parent_fwspec = *fwspec;
 173        parent_fwspec.fwnode = domain->parent->fwnode;
 174        return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs,
 175                                            &parent_fwspec);
 176}
 177
 178static const struct irq_domain_ops exynos_pmu_domain_ops = {
 179        .translate      = exynos_pmu_domain_translate,
 180        .alloc          = exynos_pmu_domain_alloc,
 181        .free           = irq_domain_free_irqs_common,
 182};
 183
 184static int __init exynos_pmu_irq_init(struct device_node *node,
 185                                      struct device_node *parent)
 186{
 187        struct irq_domain *parent_domain, *domain;
 188
 189        if (!parent) {
 190                pr_err("%pOF: no parent, giving up\n", node);
 191                return -ENODEV;
 192        }
 193
 194        parent_domain = irq_find_host(parent);
 195        if (!parent_domain) {
 196                pr_err("%pOF: unable to obtain parent domain\n", node);
 197                return -ENXIO;
 198        }
 199
 200        pmu_base_addr = of_iomap(node, 0);
 201
 202        if (!pmu_base_addr) {
 203                pr_err("%pOF: failed to find exynos pmu register\n", node);
 204                return -ENOMEM;
 205        }
 206
 207        domain = irq_domain_add_hierarchy(parent_domain, 0, 0,
 208                                          node, &exynos_pmu_domain_ops,
 209                                          NULL);
 210        if (!domain) {
 211                iounmap(pmu_base_addr);
 212                return -ENOMEM;
 213        }
 214
 215        /*
 216         * Clear the OF_POPULATED flag set in of_irq_init so that
 217         * later the Exynos PMU platform device won't be skipped.
 218         */
 219        of_node_clear_flag(node, OF_POPULATED);
 220
 221        return 0;
 222}
 223
 224#define EXYNOS_PMU_IRQ(symbol, name)    IRQCHIP_DECLARE(symbol, name, exynos_pmu_irq_init)
 225
 226EXYNOS_PMU_IRQ(exynos3250_pmu_irq, "samsung,exynos3250-pmu");
 227EXYNOS_PMU_IRQ(exynos4210_pmu_irq, "samsung,exynos4210-pmu");
 228EXYNOS_PMU_IRQ(exynos4212_pmu_irq, "samsung,exynos4212-pmu");
 229EXYNOS_PMU_IRQ(exynos4412_pmu_irq, "samsung,exynos4412-pmu");
 230EXYNOS_PMU_IRQ(exynos5250_pmu_irq, "samsung,exynos5250-pmu");
 231EXYNOS_PMU_IRQ(exynos5420_pmu_irq, "samsung,exynos5420-pmu");
 232
 233static int exynos_cpu_do_idle(void)
 234{
 235        /* issue the standby signal into the pm unit. */
 236        cpu_do_idle();
 237
 238        pr_info("Failed to suspend the system\n");
 239        return 1; /* Aborting suspend */
 240}
 241static void exynos_flush_cache_all(void)
 242{
 243        flush_cache_all();
 244        outer_flush_all();
 245}
 246
 247static int exynos_cpu_suspend(unsigned long arg)
 248{
 249        exynos_flush_cache_all();
 250        return exynos_cpu_do_idle();
 251}
 252
 253static int exynos3250_cpu_suspend(unsigned long arg)
 254{
 255        flush_cache_all();
 256        return exynos_cpu_do_idle();
 257}
 258
 259static int exynos5420_cpu_suspend(unsigned long arg)
 260{
 261        /* MCPM works with HW CPU identifiers */
 262        unsigned int mpidr = read_cpuid_mpidr();
 263        unsigned int cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
 264        unsigned int cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
 265
 266        writel_relaxed(0x0, sysram_base_addr + EXYNOS5420_CPU_STATE);
 267
 268        if (IS_ENABLED(CONFIG_EXYNOS5420_MCPM)) {
 269                mcpm_set_entry_vector(cpu, cluster, exynos_cpu_resume);
 270                mcpm_cpu_suspend();
 271        }
 272
 273        pr_info("Failed to suspend the system\n");
 274
 275        /* return value != 0 means failure */
 276        return 1;
 277}
 278
 279static void exynos_pm_set_wakeup_mask(void)
 280{
 281        /* Set wake-up mask registers */
 282        pmu_raw_writel(exynos_get_eint_wake_mask(), S5P_EINT_WAKEUP_MASK);
 283        pmu_raw_writel(exynos_irqwake_intmask & ~(1 << 31), S5P_WAKEUP_MASK);
 284}
 285
 286static void exynos_pm_enter_sleep_mode(void)
 287{
 288        /* Set value of power down register for sleep mode */
 289        exynos_sys_powerdown_conf(SYS_SLEEP);
 290        pmu_raw_writel(EXYNOS_SLEEP_MAGIC, S5P_INFORM1);
 291}
 292
 293static void exynos_pm_prepare(void)
 294{
 295        exynos_set_delayed_reset_assertion(false);
 296
 297        /* Set wake-up mask registers */
 298        exynos_pm_set_wakeup_mask();
 299
 300        exynos_pm_enter_sleep_mode();
 301
 302        /* ensure at least INFORM0 has the resume address */
 303        pmu_raw_writel(__pa_symbol(exynos_cpu_resume), S5P_INFORM0);
 304}
 305
 306static void exynos3250_pm_prepare(void)
 307{
 308        unsigned int tmp;
 309
 310        /* Set wake-up mask registers */
 311        exynos_pm_set_wakeup_mask();
 312
 313        tmp = pmu_raw_readl(EXYNOS3_ARM_L2_OPTION);
 314        tmp &= ~EXYNOS5_OPTION_USE_RETENTION;
 315        pmu_raw_writel(tmp, EXYNOS3_ARM_L2_OPTION);
 316
 317        exynos_pm_enter_sleep_mode();
 318
 319        /* ensure at least INFORM0 has the resume address */
 320        pmu_raw_writel(__pa_symbol(exynos_cpu_resume), S5P_INFORM0);
 321}
 322
 323static void exynos5420_pm_prepare(void)
 324{
 325        unsigned int tmp;
 326
 327        /* Set wake-up mask registers */
 328        exynos_pm_set_wakeup_mask();
 329
 330        exynos_pmu_spare3 = pmu_raw_readl(S5P_PMU_SPARE3);
 331        /*
 332         * The cpu state needs to be saved and restored so that the
 333         * secondary CPUs will enter low power start. Though the U-Boot
 334         * is setting the cpu state with low power flag, the kernel
 335         * needs to restore it back in case, the primary cpu fails to
 336         * suspend for any reason.
 337         */
 338        exynos5420_cpu_state = readl_relaxed(sysram_base_addr +
 339                                             EXYNOS5420_CPU_STATE);
 340
 341        exynos_pm_enter_sleep_mode();
 342
 343        /* ensure at least INFORM0 has the resume address */
 344        if (IS_ENABLED(CONFIG_EXYNOS5420_MCPM))
 345                pmu_raw_writel(__pa_symbol(mcpm_entry_point), S5P_INFORM0);
 346
 347        tmp = pmu_raw_readl(EXYNOS_L2_OPTION(0));
 348        tmp &= ~EXYNOS_L2_USE_RETENTION;
 349        pmu_raw_writel(tmp, EXYNOS_L2_OPTION(0));
 350
 351        tmp = pmu_raw_readl(EXYNOS5420_SFR_AXI_CGDIS1);
 352        tmp |= EXYNOS5420_UFS;
 353        pmu_raw_writel(tmp, EXYNOS5420_SFR_AXI_CGDIS1);
 354
 355        tmp = pmu_raw_readl(EXYNOS5420_ARM_COMMON_OPTION);
 356        tmp &= ~EXYNOS5420_L2RSTDISABLE_VALUE;
 357        pmu_raw_writel(tmp, EXYNOS5420_ARM_COMMON_OPTION);
 358
 359        tmp = pmu_raw_readl(EXYNOS5420_FSYS2_OPTION);
 360        tmp |= EXYNOS5420_EMULATION;
 361        pmu_raw_writel(tmp, EXYNOS5420_FSYS2_OPTION);
 362
 363        tmp = pmu_raw_readl(EXYNOS5420_PSGEN_OPTION);
 364        tmp |= EXYNOS5420_EMULATION;
 365        pmu_raw_writel(tmp, EXYNOS5420_PSGEN_OPTION);
 366}
 367
 368
 369static int exynos_pm_suspend(void)
 370{
 371        exynos_pm_central_suspend();
 372
 373        /* Setting SEQ_OPTION register */
 374        pmu_raw_writel(S5P_USE_STANDBY_WFI0 | S5P_USE_STANDBY_WFE0,
 375                       S5P_CENTRAL_SEQ_OPTION);
 376
 377        if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9)
 378                exynos_cpu_save_register();
 379
 380        return 0;
 381}
 382
 383static int exynos5420_pm_suspend(void)
 384{
 385        u32 this_cluster;
 386
 387        exynos_pm_central_suspend();
 388
 389        /* Setting SEQ_OPTION register */
 390
 391        this_cluster = MPIDR_AFFINITY_LEVEL(read_cpuid_mpidr(), 1);
 392        if (!this_cluster)
 393                pmu_raw_writel(EXYNOS5420_ARM_USE_STANDBY_WFI0,
 394                                S5P_CENTRAL_SEQ_OPTION);
 395        else
 396                pmu_raw_writel(EXYNOS5420_KFC_USE_STANDBY_WFI0,
 397                                S5P_CENTRAL_SEQ_OPTION);
 398        return 0;
 399}
 400
 401static void exynos_pm_resume(void)
 402{
 403        u32 cpuid = read_cpuid_part();
 404
 405        if (exynos_pm_central_resume())
 406                goto early_wakeup;
 407
 408        if (cpuid == ARM_CPU_PART_CORTEX_A9)
 409                scu_enable(S5P_VA_SCU);
 410
 411        if (call_firmware_op(resume) == -ENOSYS
 412            && cpuid == ARM_CPU_PART_CORTEX_A9)
 413                exynos_cpu_restore_register();
 414
 415early_wakeup:
 416
 417        /* Clear SLEEP mode set in INFORM1 */
 418        pmu_raw_writel(0x0, S5P_INFORM1);
 419        exynos_set_delayed_reset_assertion(true);
 420}
 421
 422static void exynos3250_pm_resume(void)
 423{
 424        u32 cpuid = read_cpuid_part();
 425
 426        if (exynos_pm_central_resume())
 427                goto early_wakeup;
 428
 429        pmu_raw_writel(S5P_USE_STANDBY_WFI_ALL, S5P_CENTRAL_SEQ_OPTION);
 430
 431        if (call_firmware_op(resume) == -ENOSYS
 432            && cpuid == ARM_CPU_PART_CORTEX_A9)
 433                exynos_cpu_restore_register();
 434
 435early_wakeup:
 436
 437        /* Clear SLEEP mode set in INFORM1 */
 438        pmu_raw_writel(0x0, S5P_INFORM1);
 439}
 440
 441static void exynos5420_prepare_pm_resume(void)
 442{
 443        if (IS_ENABLED(CONFIG_EXYNOS5420_MCPM))
 444                WARN_ON(mcpm_cpu_powered_up());
 445}
 446
 447static void exynos5420_pm_resume(void)
 448{
 449        unsigned long tmp;
 450
 451        /* Restore the CPU0 low power state register */
 452        tmp = pmu_raw_readl(EXYNOS5_ARM_CORE0_SYS_PWR_REG);
 453        pmu_raw_writel(tmp | S5P_CORE_LOCAL_PWR_EN,
 454                       EXYNOS5_ARM_CORE0_SYS_PWR_REG);
 455
 456        /* Restore the sysram cpu state register */
 457        writel_relaxed(exynos5420_cpu_state,
 458                       sysram_base_addr + EXYNOS5420_CPU_STATE);
 459
 460        pmu_raw_writel(EXYNOS5420_USE_STANDBY_WFI_ALL,
 461                        S5P_CENTRAL_SEQ_OPTION);
 462
 463        if (exynos_pm_central_resume())
 464                goto early_wakeup;
 465
 466        pmu_raw_writel(exynos_pmu_spare3, S5P_PMU_SPARE3);
 467
 468early_wakeup:
 469
 470        tmp = pmu_raw_readl(EXYNOS5420_SFR_AXI_CGDIS1);
 471        tmp &= ~EXYNOS5420_UFS;
 472        pmu_raw_writel(tmp, EXYNOS5420_SFR_AXI_CGDIS1);
 473
 474        tmp = pmu_raw_readl(EXYNOS5420_FSYS2_OPTION);
 475        tmp &= ~EXYNOS5420_EMULATION;
 476        pmu_raw_writel(tmp, EXYNOS5420_FSYS2_OPTION);
 477
 478        tmp = pmu_raw_readl(EXYNOS5420_PSGEN_OPTION);
 479        tmp &= ~EXYNOS5420_EMULATION;
 480        pmu_raw_writel(tmp, EXYNOS5420_PSGEN_OPTION);
 481
 482        /* Clear SLEEP mode set in INFORM1 */
 483        pmu_raw_writel(0x0, S5P_INFORM1);
 484}
 485
 486/*
 487 * Suspend Ops
 488 */
 489
 490static int exynos_suspend_enter(suspend_state_t state)
 491{
 492        int ret;
 493
 494        s3c_pm_debug_init();
 495
 496        S3C_PMDBG("%s: suspending the system...\n", __func__);
 497
 498        S3C_PMDBG("%s: wakeup masks: %08x,%08x\n", __func__,
 499                        exynos_irqwake_intmask, exynos_get_eint_wake_mask());
 500
 501        if (exynos_irqwake_intmask == -1U
 502            && exynos_get_eint_wake_mask() == -1U) {
 503                pr_err("%s: No wake-up sources!\n", __func__);
 504                pr_err("%s: Aborting sleep\n", __func__);
 505                return -EINVAL;
 506        }
 507
 508        s3c_pm_save_uarts();
 509        if (pm_data->pm_prepare)
 510                pm_data->pm_prepare();
 511        flush_cache_all();
 512        s3c_pm_check_store();
 513
 514        ret = call_firmware_op(suspend);
 515        if (ret == -ENOSYS)
 516                ret = cpu_suspend(0, pm_data->cpu_suspend);
 517        if (ret)
 518                return ret;
 519
 520        if (pm_data->pm_resume_prepare)
 521                pm_data->pm_resume_prepare();
 522        s3c_pm_restore_uarts();
 523
 524        S3C_PMDBG("%s: wakeup stat: %08x\n", __func__,
 525                        pmu_raw_readl(S5P_WAKEUP_STAT));
 526
 527        s3c_pm_check_restore();
 528
 529        S3C_PMDBG("%s: resuming the system...\n", __func__);
 530
 531        return 0;
 532}
 533
 534static int exynos_suspend_prepare(void)
 535{
 536        int ret;
 537
 538        /*
 539         * REVISIT: It would be better if struct platform_suspend_ops
 540         * .prepare handler get the suspend_state_t as a parameter to
 541         * avoid hard-coding the suspend to mem state. It's safe to do
 542         * it now only because the suspend_valid_only_mem function is
 543         * used as the .valid callback used to check if a given state
 544         * is supported by the platform anyways.
 545         */
 546        ret = regulator_suspend_prepare(PM_SUSPEND_MEM);
 547        if (ret) {
 548                pr_err("Failed to prepare regulators for suspend (%d)\n", ret);
 549                return ret;
 550        }
 551
 552        s3c_pm_check_prepare();
 553
 554        return 0;
 555}
 556
 557static void exynos_suspend_finish(void)
 558{
 559        int ret;
 560
 561        s3c_pm_check_cleanup();
 562
 563        ret = regulator_suspend_finish();
 564        if (ret)
 565                pr_warn("Failed to resume regulators from suspend (%d)\n", ret);
 566}
 567
 568static const struct platform_suspend_ops exynos_suspend_ops = {
 569        .enter          = exynos_suspend_enter,
 570        .prepare        = exynos_suspend_prepare,
 571        .finish         = exynos_suspend_finish,
 572        .valid          = suspend_valid_only_mem,
 573};
 574
 575static const struct exynos_pm_data exynos3250_pm_data = {
 576        .wkup_irq       = exynos3250_wkup_irq,
 577        .wake_disable_mask = ((0xFF << 8) | (0x1F << 1)),
 578        .pm_suspend     = exynos_pm_suspend,
 579        .pm_resume      = exynos3250_pm_resume,
 580        .pm_prepare     = exynos3250_pm_prepare,
 581        .cpu_suspend    = exynos3250_cpu_suspend,
 582};
 583
 584static const struct exynos_pm_data exynos4_pm_data = {
 585        .wkup_irq       = exynos4_wkup_irq,
 586        .wake_disable_mask = ((0xFF << 8) | (0x1F << 1)),
 587        .pm_suspend     = exynos_pm_suspend,
 588        .pm_resume      = exynos_pm_resume,
 589        .pm_prepare     = exynos_pm_prepare,
 590        .cpu_suspend    = exynos_cpu_suspend,
 591};
 592
 593static const struct exynos_pm_data exynos5250_pm_data = {
 594        .wkup_irq       = exynos5250_wkup_irq,
 595        .wake_disable_mask = ((0xFF << 8) | (0x1F << 1)),
 596        .pm_suspend     = exynos_pm_suspend,
 597        .pm_resume      = exynos_pm_resume,
 598        .pm_prepare     = exynos_pm_prepare,
 599        .cpu_suspend    = exynos_cpu_suspend,
 600};
 601
 602static const struct exynos_pm_data exynos5420_pm_data = {
 603        .wkup_irq       = exynos5250_wkup_irq,
 604        .wake_disable_mask = (0x7F << 7) | (0x1F << 1),
 605        .pm_resume_prepare = exynos5420_prepare_pm_resume,
 606        .pm_resume      = exynos5420_pm_resume,
 607        .pm_suspend     = exynos5420_pm_suspend,
 608        .pm_prepare     = exynos5420_pm_prepare,
 609        .cpu_suspend    = exynos5420_cpu_suspend,
 610};
 611
 612static const struct of_device_id exynos_pmu_of_device_ids[] __initconst = {
 613        {
 614                .compatible = "samsung,exynos3250-pmu",
 615                .data = &exynos3250_pm_data,
 616        }, {
 617                .compatible = "samsung,exynos4210-pmu",
 618                .data = &exynos4_pm_data,
 619        }, {
 620                .compatible = "samsung,exynos4212-pmu",
 621                .data = &exynos4_pm_data,
 622        }, {
 623                .compatible = "samsung,exynos4412-pmu",
 624                .data = &exynos4_pm_data,
 625        }, {
 626                .compatible = "samsung,exynos5250-pmu",
 627                .data = &exynos5250_pm_data,
 628        }, {
 629                .compatible = "samsung,exynos5420-pmu",
 630                .data = &exynos5420_pm_data,
 631        },
 632        { /*sentinel*/ },
 633};
 634
 635static struct syscore_ops exynos_pm_syscore_ops;
 636
 637void __init exynos_pm_init(void)
 638{
 639        const struct of_device_id *match;
 640        struct device_node *np;
 641        u32 tmp;
 642
 643        np = of_find_matching_node_and_match(NULL, exynos_pmu_of_device_ids, &match);
 644        if (!np) {
 645                pr_err("Failed to find PMU node\n");
 646                return;
 647        }
 648
 649        if (WARN_ON(!of_find_property(np, "interrupt-controller", NULL))) {
 650                pr_warn("Outdated DT detected, suspend/resume will NOT work\n");
 651                return;
 652        }
 653
 654        pm_data = (const struct exynos_pm_data *) match->data;
 655
 656        /* All wakeup disable */
 657        tmp = pmu_raw_readl(S5P_WAKEUP_MASK);
 658        tmp |= pm_data->wake_disable_mask;
 659        pmu_raw_writel(tmp, S5P_WAKEUP_MASK);
 660
 661        exynos_pm_syscore_ops.suspend   = pm_data->pm_suspend;
 662        exynos_pm_syscore_ops.resume    = pm_data->pm_resume;
 663
 664        register_syscore_ops(&exynos_pm_syscore_ops);
 665        suspend_set_ops(&exynos_suspend_ops);
 666}
 667