linux/arch/arm/mach-davinci/cpuidle.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * CPU idle for DaVinci SoCs
   4 *
   5 * Copyright (C) 2009 Texas Instruments Incorporated. https://www.ti.com/
   6 *
   7 * Derived from Marvell Kirkwood CPU idle code
   8 * (arch/arm/mach-kirkwood/cpuidle.c)
   9 */
  10
  11#include <linux/kernel.h>
  12#include <linux/init.h>
  13#include <linux/platform_device.h>
  14#include <linux/cpuidle.h>
  15#include <linux/io.h>
  16#include <linux/export.h>
  17#include <asm/cpuidle.h>
  18
  19#include "cpuidle.h"
  20#include "ddr2.h"
  21
  22#define DAVINCI_CPUIDLE_MAX_STATES      2
  23
  24static void __iomem *ddr2_reg_base;
  25static bool ddr2_pdown;
  26
  27static void davinci_save_ddr_power(int enter, bool pdown)
  28{
  29        u32 val;
  30
  31        val = __raw_readl(ddr2_reg_base + DDR2_SDRCR_OFFSET);
  32
  33        if (enter) {
  34                if (pdown)
  35                        val |= DDR2_SRPD_BIT;
  36                else
  37                        val &= ~DDR2_SRPD_BIT;
  38                val |= DDR2_LPMODEN_BIT;
  39        } else {
  40                val &= ~(DDR2_SRPD_BIT | DDR2_LPMODEN_BIT);
  41        }
  42
  43        __raw_writel(val, ddr2_reg_base + DDR2_SDRCR_OFFSET);
  44}
  45
  46/* Actual code that puts the SoC in different idle states */
  47static int davinci_enter_idle(struct cpuidle_device *dev,
  48                              struct cpuidle_driver *drv, int index)
  49{
  50        davinci_save_ddr_power(1, ddr2_pdown);
  51        cpu_do_idle();
  52        davinci_save_ddr_power(0, ddr2_pdown);
  53
  54        return index;
  55}
  56
  57static struct cpuidle_driver davinci_idle_driver = {
  58        .name                   = "cpuidle-davinci",
  59        .owner                  = THIS_MODULE,
  60        .states[0]              = ARM_CPUIDLE_WFI_STATE,
  61        .states[1]              = {
  62                .enter                  = davinci_enter_idle,
  63                .exit_latency           = 10,
  64                .target_residency       = 10000,
  65                .name                   = "DDR SR",
  66                .desc                   = "WFI and DDR Self Refresh",
  67        },
  68        .state_count = DAVINCI_CPUIDLE_MAX_STATES,
  69};
  70
  71static int __init davinci_cpuidle_probe(struct platform_device *pdev)
  72{
  73        struct davinci_cpuidle_config *pdata = pdev->dev.platform_data;
  74
  75        if (!pdata) {
  76                dev_err(&pdev->dev, "cannot get platform data\n");
  77                return -ENOENT;
  78        }
  79
  80        ddr2_reg_base = pdata->ddr2_ctlr_base;
  81
  82        ddr2_pdown = pdata->ddr2_pdown;
  83
  84        return cpuidle_register(&davinci_idle_driver, NULL);
  85}
  86
  87static struct platform_driver davinci_cpuidle_driver = {
  88        .driver = {
  89                .name   = "cpuidle-davinci",
  90        },
  91};
  92
  93static int __init davinci_cpuidle_init(void)
  94{
  95        return platform_driver_probe(&davinci_cpuidle_driver,
  96                                                davinci_cpuidle_probe);
  97}
  98device_initcall(davinci_cpuidle_init);
  99
 100