1f50ee824SGregory CLEMENT /* 2c16788b4SThomas Petazzoni * Marvell Armada 370, 38x and XP SoC cpuidle driver 3f50ee824SGregory CLEMENT * 4f50ee824SGregory CLEMENT * Copyright (C) 2014 Marvell 5f50ee824SGregory CLEMENT * 6f50ee824SGregory CLEMENT * Nadav Haklai <nadavh@marvell.com> 7f50ee824SGregory CLEMENT * Gregory CLEMENT <gregory.clement@free-electrons.com> 8f50ee824SGregory CLEMENT * 9f50ee824SGregory CLEMENT * This file is licensed under the terms of the GNU General Public 10f50ee824SGregory CLEMENT * License version 2. This program is licensed "as is" without any 11f50ee824SGregory CLEMENT * warranty of any kind, whether express or implied. 12f50ee824SGregory CLEMENT * 13f50ee824SGregory CLEMENT * Maintainer: Gregory CLEMENT <gregory.clement@free-electrons.com> 14f50ee824SGregory CLEMENT */ 15f50ee824SGregory CLEMENT 16f50ee824SGregory CLEMENT #include <linux/cpu_pm.h> 17f50ee824SGregory CLEMENT #include <linux/cpuidle.h> 18f50ee824SGregory CLEMENT #include <linux/module.h> 19f50ee824SGregory CLEMENT #include <linux/of.h> 20f50ee824SGregory CLEMENT #include <linux/suspend.h> 21f50ee824SGregory CLEMENT #include <linux/platform_device.h> 22f50ee824SGregory CLEMENT #include <asm/cpuidle.h> 23f50ee824SGregory CLEMENT 24f50ee824SGregory CLEMENT #define MVEBU_V7_FLAG_DEEP_IDLE 0x10000 25f50ee824SGregory CLEMENT 26f50ee824SGregory CLEMENT static int (*mvebu_v7_cpu_suspend)(int); 27f50ee824SGregory CLEMENT 28f50ee824SGregory CLEMENT static int mvebu_v7_enter_idle(struct cpuidle_device *dev, 29f50ee824SGregory CLEMENT struct cpuidle_driver *drv, 30f50ee824SGregory CLEMENT int index) 31f50ee824SGregory CLEMENT { 32f50ee824SGregory CLEMENT int ret; 33f50ee824SGregory CLEMENT bool deepidle = false; 34f50ee824SGregory CLEMENT cpu_pm_enter(); 35f50ee824SGregory CLEMENT 36f50ee824SGregory CLEMENT if (drv->states[index].flags & MVEBU_V7_FLAG_DEEP_IDLE) 37f50ee824SGregory CLEMENT deepidle = true; 38f50ee824SGregory CLEMENT 39*4ce40e9dSPeter Zijlstra ct_idle_enter(); 40f50ee824SGregory CLEMENT ret = mvebu_v7_cpu_suspend(deepidle); 41*4ce40e9dSPeter Zijlstra ct_idle_exit(); 42*4ce40e9dSPeter Zijlstra 4343b68879SGregory CLEMENT cpu_pm_exit(); 4443b68879SGregory CLEMENT 45f50ee824SGregory CLEMENT if (ret) 46f50ee824SGregory CLEMENT return ret; 47f50ee824SGregory CLEMENT 48f50ee824SGregory CLEMENT return index; 49f50ee824SGregory CLEMENT } 50f50ee824SGregory CLEMENT 51f50ee824SGregory CLEMENT static struct cpuidle_driver armadaxp_idle_driver = { 52f50ee824SGregory CLEMENT .name = "armada_xp_idle", 53f50ee824SGregory CLEMENT .states[0] = ARM_CPUIDLE_WFI_STATE, 54f50ee824SGregory CLEMENT .states[1] = { 55*4ce40e9dSPeter Zijlstra .flags = CPUIDLE_FLAG_RCU_IDLE, 56f50ee824SGregory CLEMENT .enter = mvebu_v7_enter_idle, 57ce6031c8SSebastien Rannou .exit_latency = 100, 58f50ee824SGregory CLEMENT .power_usage = 50, 59ce6031c8SSebastien Rannou .target_residency = 1000, 60f50ee824SGregory CLEMENT .name = "MV CPU IDLE", 61f50ee824SGregory CLEMENT .desc = "CPU power down", 62f50ee824SGregory CLEMENT }, 63f50ee824SGregory CLEMENT .states[2] = { 64*4ce40e9dSPeter Zijlstra .flags = CPUIDLE_FLAG_RCU_IDLE, 65f50ee824SGregory CLEMENT .enter = mvebu_v7_enter_idle, 66ce6031c8SSebastien Rannou .exit_latency = 1000, 67f50ee824SGregory CLEMENT .power_usage = 5, 68ce6031c8SSebastien Rannou .target_residency = 10000, 69b82b6ccaSDaniel Lezcano .flags = MVEBU_V7_FLAG_DEEP_IDLE, 70f50ee824SGregory CLEMENT .name = "MV CPU DEEP IDLE", 71f50ee824SGregory CLEMENT .desc = "CPU and L2 Fabric power down", 72f50ee824SGregory CLEMENT }, 73f50ee824SGregory CLEMENT .state_count = 3, 74f50ee824SGregory CLEMENT }; 75f50ee824SGregory CLEMENT 76c3c7fe7cSThomas Petazzoni static struct cpuidle_driver armada370_idle_driver = { 77c3c7fe7cSThomas Petazzoni .name = "armada_370_idle", 78c3c7fe7cSThomas Petazzoni .states[0] = ARM_CPUIDLE_WFI_STATE, 79c3c7fe7cSThomas Petazzoni .states[1] = { 80*4ce40e9dSPeter Zijlstra .flags = CPUIDLE_FLAG_RCU_IDLE, 81c3c7fe7cSThomas Petazzoni .enter = mvebu_v7_enter_idle, 82c3c7fe7cSThomas Petazzoni .exit_latency = 100, 83c3c7fe7cSThomas Petazzoni .power_usage = 5, 84c3c7fe7cSThomas Petazzoni .target_residency = 1000, 85b82b6ccaSDaniel Lezcano .flags = MVEBU_V7_FLAG_DEEP_IDLE, 86c3c7fe7cSThomas Petazzoni .name = "Deep Idle", 87c3c7fe7cSThomas Petazzoni .desc = "CPU and L2 Fabric power down", 88c3c7fe7cSThomas Petazzoni }, 89c3c7fe7cSThomas Petazzoni .state_count = 2, 90c3c7fe7cSThomas Petazzoni }; 91c3c7fe7cSThomas Petazzoni 92c16788b4SThomas Petazzoni static struct cpuidle_driver armada38x_idle_driver = { 93c16788b4SThomas Petazzoni .name = "armada_38x_idle", 94c16788b4SThomas Petazzoni .states[0] = ARM_CPUIDLE_WFI_STATE, 95c16788b4SThomas Petazzoni .states[1] = { 96*4ce40e9dSPeter Zijlstra .flags = CPUIDLE_FLAG_RCU_IDLE, 97c16788b4SThomas Petazzoni .enter = mvebu_v7_enter_idle, 98c16788b4SThomas Petazzoni .exit_latency = 10, 99c16788b4SThomas Petazzoni .power_usage = 5, 100c16788b4SThomas Petazzoni .target_residency = 100, 101c16788b4SThomas Petazzoni .name = "Idle", 102c16788b4SThomas Petazzoni .desc = "CPU and SCU power down", 103c16788b4SThomas Petazzoni }, 104c16788b4SThomas Petazzoni .state_count = 2, 105c16788b4SThomas Petazzoni }; 106c16788b4SThomas Petazzoni 107f50ee824SGregory CLEMENT static int mvebu_v7_cpuidle_probe(struct platform_device *pdev) 108f50ee824SGregory CLEMENT { 109da1a64f8SRussell King const struct platform_device_id *id = pdev->id_entry; 110da1a64f8SRussell King 111da1a64f8SRussell King if (!id) 112da1a64f8SRussell King return -EINVAL; 113da1a64f8SRussell King 114f50ee824SGregory CLEMENT mvebu_v7_cpu_suspend = pdev->dev.platform_data; 115c3c7fe7cSThomas Petazzoni 116da1a64f8SRussell King return cpuidle_register((struct cpuidle_driver *)id->driver_data, NULL); 117f50ee824SGregory CLEMENT } 118f50ee824SGregory CLEMENT 119da1a64f8SRussell King static const struct platform_device_id mvebu_cpuidle_ids[] = { 120da1a64f8SRussell King { 121f50ee824SGregory CLEMENT .name = "cpuidle-armada-xp", 122da1a64f8SRussell King .driver_data = (unsigned long)&armadaxp_idle_driver, 123da1a64f8SRussell King }, { 124c3c7fe7cSThomas Petazzoni .name = "cpuidle-armada-370", 125da1a64f8SRussell King .driver_data = (unsigned long)&armada370_idle_driver, 126da1a64f8SRussell King }, { 127c16788b4SThomas Petazzoni .name = "cpuidle-armada-38x", 128da1a64f8SRussell King .driver_data = (unsigned long)&armada38x_idle_driver, 129c16788b4SThomas Petazzoni }, 130da1a64f8SRussell King {} 131c16788b4SThomas Petazzoni }; 132c16788b4SThomas Petazzoni 133da1a64f8SRussell King static struct platform_driver mvebu_cpuidle_driver = { 134da1a64f8SRussell King .probe = mvebu_v7_cpuidle_probe, 135da1a64f8SRussell King .driver = { 136da1a64f8SRussell King .name = "cpuidle-mbevu", 137ab319939SRussell King .suppress_bind_attrs = true, 138da1a64f8SRussell King }, 139da1a64f8SRussell King .id_table = mvebu_cpuidle_ids, 140da1a64f8SRussell King }; 141da1a64f8SRussell King 142ab319939SRussell King builtin_platform_driver(mvebu_cpuidle_driver); 143c16788b4SThomas Petazzoni 144f50ee824SGregory CLEMENT MODULE_AUTHOR("Gregory CLEMENT <gregory.clement@free-electrons.com>"); 145f50ee824SGregory CLEMENT MODULE_DESCRIPTION("Marvell EBU v7 cpuidle driver"); 146f50ee824SGregory CLEMENT MODULE_LICENSE("GPL"); 147