1 /* 2 * CPU idle for DaVinci SoCs 3 * 4 * Copyright (C) 2009 Texas Instruments Incorporated. http://www.ti.com/ 5 * 6 * Derived from Marvell Kirkwood CPU idle code 7 * (arch/arm/mach-kirkwood/cpuidle.c) 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License version 2 as 11 * published by the Free Software Foundation. 12 */ 13 14 #include <linux/kernel.h> 15 #include <linux/init.h> 16 #include <linux/platform_device.h> 17 #include <linux/cpuidle.h> 18 #include <linux/io.h> 19 #include <linux/export.h> 20 #include <asm/proc-fns.h> 21 #include <asm/cpuidle.h> 22 23 #include <mach/cpuidle.h> 24 #include <mach/ddr2.h> 25 26 #define DAVINCI_CPUIDLE_MAX_STATES 2 27 28 static DEFINE_PER_CPU(struct cpuidle_device, davinci_cpuidle_device); 29 static void __iomem *ddr2_reg_base; 30 static bool ddr2_pdown; 31 32 static void davinci_save_ddr_power(int enter, bool pdown) 33 { 34 u32 val; 35 36 val = __raw_readl(ddr2_reg_base + DDR2_SDRCR_OFFSET); 37 38 if (enter) { 39 if (pdown) 40 val |= DDR2_SRPD_BIT; 41 else 42 val &= ~DDR2_SRPD_BIT; 43 val |= DDR2_LPMODEN_BIT; 44 } else { 45 val &= ~(DDR2_SRPD_BIT | DDR2_LPMODEN_BIT); 46 } 47 48 __raw_writel(val, ddr2_reg_base + DDR2_SDRCR_OFFSET); 49 } 50 51 /* Actual code that puts the SoC in different idle states */ 52 static int davinci_enter_idle(struct cpuidle_device *dev, 53 struct cpuidle_driver *drv, 54 int index) 55 { 56 davinci_save_ddr_power(1, ddr2_pdown); 57 58 index = cpuidle_wrap_enter(dev, drv, index, 59 arm_cpuidle_simple_enter); 60 61 davinci_save_ddr_power(0, ddr2_pdown); 62 63 return index; 64 } 65 66 static struct cpuidle_driver davinci_idle_driver = { 67 .name = "cpuidle-davinci", 68 .owner = THIS_MODULE, 69 .en_core_tk_irqen = 1, 70 .states[0] = ARM_CPUIDLE_WFI_STATE, 71 .states[1] = { 72 .enter = davinci_enter_idle, 73 .exit_latency = 10, 74 .target_residency = 100000, 75 .flags = CPUIDLE_FLAG_TIME_VALID, 76 .name = "DDR SR", 77 .desc = "WFI and DDR Self Refresh", 78 }, 79 .state_count = DAVINCI_CPUIDLE_MAX_STATES, 80 }; 81 82 static int __init davinci_cpuidle_probe(struct platform_device *pdev) 83 { 84 int ret; 85 struct cpuidle_device *device; 86 struct davinci_cpuidle_config *pdata = pdev->dev.platform_data; 87 88 device = &per_cpu(davinci_cpuidle_device, smp_processor_id()); 89 90 if (!pdata) { 91 dev_err(&pdev->dev, "cannot get platform data\n"); 92 return -ENOENT; 93 } 94 95 ddr2_reg_base = pdata->ddr2_ctlr_base; 96 97 ddr2_pdown = pdata->ddr2_pdown; 98 99 ret = cpuidle_register_driver(&davinci_idle_driver); 100 if (ret) { 101 dev_err(&pdev->dev, "failed to register driver\n"); 102 return ret; 103 } 104 105 ret = cpuidle_register_device(device); 106 if (ret) { 107 dev_err(&pdev->dev, "failed to register device\n"); 108 cpuidle_unregister_driver(&davinci_idle_driver); 109 return ret; 110 } 111 112 return 0; 113 } 114 115 static struct platform_driver davinci_cpuidle_driver = { 116 .driver = { 117 .name = "cpuidle-davinci", 118 .owner = THIS_MODULE, 119 }, 120 }; 121 122 static int __init davinci_cpuidle_init(void) 123 { 124 return platform_driver_probe(&davinci_cpuidle_driver, 125 davinci_cpuidle_probe); 126 } 127 device_initcall(davinci_cpuidle_init); 128 129