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