root/drivers/cpuidle/cpuidle-exynos.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. exynos_enter_coupled_lowpower
  2. exynos_enter_lowpower
  3. exynos_cpuidle_probe

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd.
   4  *              http://www.samsung.com
   5  *
   6  * Coupled cpuidle support based on the work of:
   7  *      Colin Cross <ccross@android.com>
   8  *      Daniel Lezcano <daniel.lezcano@linaro.org>
   9 */
  10 
  11 #include <linux/cpuidle.h>
  12 #include <linux/cpu_pm.h>
  13 #include <linux/export.h>
  14 #include <linux/init.h>
  15 #include <linux/platform_device.h>
  16 #include <linux/of.h>
  17 #include <linux/platform_data/cpuidle-exynos.h>
  18 
  19 #include <asm/suspend.h>
  20 #include <asm/cpuidle.h>
  21 
  22 static atomic_t exynos_idle_barrier;
  23 
  24 static struct cpuidle_exynos_data *exynos_cpuidle_pdata;
  25 static void (*exynos_enter_aftr)(void);
  26 
  27 static int exynos_enter_coupled_lowpower(struct cpuidle_device *dev,
  28                                          struct cpuidle_driver *drv,
  29                                          int index)
  30 {
  31         int ret;
  32 
  33         exynos_cpuidle_pdata->pre_enter_aftr();
  34 
  35         /*
  36          * Waiting all cpus to reach this point at the same moment
  37          */
  38         cpuidle_coupled_parallel_barrier(dev, &exynos_idle_barrier);
  39 
  40         /*
  41          * Both cpus will reach this point at the same time
  42          */
  43         ret = dev->cpu ? exynos_cpuidle_pdata->cpu1_powerdown()
  44                        : exynos_cpuidle_pdata->cpu0_enter_aftr();
  45         if (ret)
  46                 index = ret;
  47 
  48         /*
  49          * Waiting all cpus to finish the power sequence before going further
  50          */
  51         cpuidle_coupled_parallel_barrier(dev, &exynos_idle_barrier);
  52 
  53         exynos_cpuidle_pdata->post_enter_aftr();
  54 
  55         return index;
  56 }
  57 
  58 static int exynos_enter_lowpower(struct cpuidle_device *dev,
  59                                 struct cpuidle_driver *drv,
  60                                 int index)
  61 {
  62         int new_index = index;
  63 
  64         /* AFTR can only be entered when cores other than CPU0 are offline */
  65         if (num_online_cpus() > 1 || dev->cpu != 0)
  66                 new_index = drv->safe_state_index;
  67 
  68         if (new_index == 0)
  69                 return arm_cpuidle_simple_enter(dev, drv, new_index);
  70 
  71         exynos_enter_aftr();
  72 
  73         return new_index;
  74 }
  75 
  76 static struct cpuidle_driver exynos_idle_driver = {
  77         .name                   = "exynos_idle",
  78         .owner                  = THIS_MODULE,
  79         .states = {
  80                 [0] = ARM_CPUIDLE_WFI_STATE,
  81                 [1] = {
  82                         .enter                  = exynos_enter_lowpower,
  83                         .exit_latency           = 300,
  84                         .target_residency       = 10000,
  85                         .name                   = "C1",
  86                         .desc                   = "ARM power down",
  87                 },
  88         },
  89         .state_count = 2,
  90         .safe_state_index = 0,
  91 };
  92 
  93 static struct cpuidle_driver exynos_coupled_idle_driver = {
  94         .name                   = "exynos_coupled_idle",
  95         .owner                  = THIS_MODULE,
  96         .states = {
  97                 [0] = ARM_CPUIDLE_WFI_STATE,
  98                 [1] = {
  99                         .enter                  = exynos_enter_coupled_lowpower,
 100                         .exit_latency           = 5000,
 101                         .target_residency       = 10000,
 102                         .flags                  = CPUIDLE_FLAG_COUPLED |
 103                                                   CPUIDLE_FLAG_TIMER_STOP,
 104                         .name                   = "C1",
 105                         .desc                   = "ARM power down",
 106                 },
 107         },
 108         .state_count = 2,
 109         .safe_state_index = 0,
 110 };
 111 
 112 static int exynos_cpuidle_probe(struct platform_device *pdev)
 113 {
 114         int ret;
 115 
 116         if (IS_ENABLED(CONFIG_SMP) &&
 117             (of_machine_is_compatible("samsung,exynos4210") ||
 118              of_machine_is_compatible("samsung,exynos3250"))) {
 119                 exynos_cpuidle_pdata = pdev->dev.platform_data;
 120 
 121                 ret = cpuidle_register(&exynos_coupled_idle_driver,
 122                                        cpu_possible_mask);
 123         } else {
 124                 exynos_enter_aftr = (void *)(pdev->dev.platform_data);
 125 
 126                 ret = cpuidle_register(&exynos_idle_driver, NULL);
 127         }
 128 
 129         if (ret) {
 130                 dev_err(&pdev->dev, "failed to register cpuidle driver\n");
 131                 return ret;
 132         }
 133 
 134         return 0;
 135 }
 136 
 137 static struct platform_driver exynos_cpuidle_driver = {
 138         .probe  = exynos_cpuidle_probe,
 139         .driver = {
 140                 .name = "exynos_cpuidle",
 141         },
 142 };
 143 builtin_platform_driver(exynos_cpuidle_driver);

/* [<][>][^][v][top][bottom][index][help] */