Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * CPU idle for DaVinci SoCs
0004  *
0005  * Copyright (C) 2009 Texas Instruments Incorporated. https://www.ti.com/
0006  *
0007  * Derived from Marvell Kirkwood CPU idle code
0008  * (arch/arm/mach-kirkwood/cpuidle.c)
0009  */
0010 
0011 #include <linux/kernel.h>
0012 #include <linux/init.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/cpuidle.h>
0015 #include <linux/io.h>
0016 #include <linux/export.h>
0017 #include <asm/cpuidle.h>
0018 
0019 #include "cpuidle.h"
0020 #include "ddr2.h"
0021 
0022 #define DAVINCI_CPUIDLE_MAX_STATES  2
0023 
0024 static void __iomem *ddr2_reg_base;
0025 static bool ddr2_pdown;
0026 
0027 static void davinci_save_ddr_power(int enter, bool pdown)
0028 {
0029     u32 val;
0030 
0031     val = __raw_readl(ddr2_reg_base + DDR2_SDRCR_OFFSET);
0032 
0033     if (enter) {
0034         if (pdown)
0035             val |= DDR2_SRPD_BIT;
0036         else
0037             val &= ~DDR2_SRPD_BIT;
0038         val |= DDR2_LPMODEN_BIT;
0039     } else {
0040         val &= ~(DDR2_SRPD_BIT | DDR2_LPMODEN_BIT);
0041     }
0042 
0043     __raw_writel(val, ddr2_reg_base + DDR2_SDRCR_OFFSET);
0044 }
0045 
0046 /* Actual code that puts the SoC in different idle states */
0047 static int davinci_enter_idle(struct cpuidle_device *dev,
0048                   struct cpuidle_driver *drv, int index)
0049 {
0050     davinci_save_ddr_power(1, ddr2_pdown);
0051     cpu_do_idle();
0052     davinci_save_ddr_power(0, ddr2_pdown);
0053 
0054     return index;
0055 }
0056 
0057 static struct cpuidle_driver davinci_idle_driver = {
0058     .name           = "cpuidle-davinci",
0059     .owner          = THIS_MODULE,
0060     .states[0]      = ARM_CPUIDLE_WFI_STATE,
0061     .states[1]      = {
0062         .enter          = davinci_enter_idle,
0063         .exit_latency       = 10,
0064         .target_residency   = 10000,
0065         .name           = "DDR SR",
0066         .desc           = "WFI and DDR Self Refresh",
0067     },
0068     .state_count = DAVINCI_CPUIDLE_MAX_STATES,
0069 };
0070 
0071 static int __init davinci_cpuidle_probe(struct platform_device *pdev)
0072 {
0073     struct davinci_cpuidle_config *pdata = pdev->dev.platform_data;
0074 
0075     if (!pdata) {
0076         dev_err(&pdev->dev, "cannot get platform data\n");
0077         return -ENOENT;
0078     }
0079 
0080     ddr2_reg_base = pdata->ddr2_ctlr_base;
0081 
0082     ddr2_pdown = pdata->ddr2_pdown;
0083 
0084     return cpuidle_register(&davinci_idle_driver, NULL);
0085 }
0086 
0087 static struct platform_driver davinci_cpuidle_driver = {
0088     .driver = {
0089         .name   = "cpuidle-davinci",
0090     },
0091 };
0092 
0093 static int __init davinci_cpuidle_init(void)
0094 {
0095     return platform_driver_probe(&davinci_cpuidle_driver,
0096                         davinci_cpuidle_probe);
0097 }
0098 device_initcall(davinci_cpuidle_init);
0099