1e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury/* 2e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury * CPU idle Marvell Kirkwood SoCs 3e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury * 4e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury * This file is licensed under the terms of the GNU General Public 5e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury * License version 2. This program is licensed "as is" without any 6e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury * warranty of any kind, whether express or implied. 7e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury * 8e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury * The cpu idle uses wait-for-interrupt and DDR self refresh in order 9e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury * to implement two idle states - 10e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury * #1 wait-for-interrupt 11e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury * #2 wait-for-interrupt and DDR self refresh 12a8e39c35b5d09598e129aa9b5e6f35aa3a1915d9Daniel Lezcano * 13a8e39c35b5d09598e129aa9b5e6f35aa3a1915d9Daniel Lezcano * Maintainer: Jason Cooper <jason@lakedaemon.net> 14a8e39c35b5d09598e129aa9b5e6f35aa3a1915d9Daniel Lezcano * Maintainer: Andrew Lunn <andrew@lunn.ch> 15e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury */ 16e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury 17e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury#include <linux/kernel.h> 189cfc94eb0f4843af5d1141a37d7b7ca5d3b27220Andrew Lunn#include <linux/module.h> 19e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury#include <linux/init.h> 20e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury#include <linux/platform_device.h> 21e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury#include <linux/cpuidle.h> 22e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury#include <linux/io.h> 23dc28094b905a872f8884f1f1c48ca86b3b78583aPaul Gortmaker#include <linux/export.h> 24e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury#include <asm/proc-fns.h> 25b334648db0ff2d07b00d81cf033c6eddff277680Robert Lee#include <asm/cpuidle.h> 26e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury 27e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury#define KIRKWOOD_MAX_STATES 2 28e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury 299cfc94eb0f4843af5d1141a37d7b7ca5d3b27220Andrew Lunnstatic void __iomem *ddr_operation_base; 309cfc94eb0f4843af5d1141a37d7b7ca5d3b27220Andrew Lunn 31e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury/* Actual code that puts the SoC in different idle states */ 32e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khourystatic int kirkwood_enter_idle(struct cpuidle_device *dev, 339cfc94eb0f4843af5d1141a37d7b7ca5d3b27220Andrew Lunn struct cpuidle_driver *drv, 34e978aa7d7d57d04eb5f88a7507c4fb98577def77Deepthi Dharwar int index) 35e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury{ 369cfc94eb0f4843af5d1141a37d7b7ca5d3b27220Andrew Lunn writel(0x7, ddr_operation_base); 37b334648db0ff2d07b00d81cf033c6eddff277680Robert Lee cpu_do_idle(); 38e978aa7d7d57d04eb5f88a7507c4fb98577def77Deepthi Dharwar 39e978aa7d7d57d04eb5f88a7507c4fb98577def77Deepthi Dharwar return index; 40e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury} 41e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury 42b334648db0ff2d07b00d81cf033c6eddff277680Robert Leestatic struct cpuidle_driver kirkwood_idle_driver = { 43b334648db0ff2d07b00d81cf033c6eddff277680Robert Lee .name = "kirkwood_idle", 44b334648db0ff2d07b00d81cf033c6eddff277680Robert Lee .owner = THIS_MODULE, 45b334648db0ff2d07b00d81cf033c6eddff277680Robert Lee .states[0] = ARM_CPUIDLE_WFI_STATE, 46b334648db0ff2d07b00d81cf033c6eddff277680Robert Lee .states[1] = { 47b334648db0ff2d07b00d81cf033c6eddff277680Robert Lee .enter = kirkwood_enter_idle, 48b334648db0ff2d07b00d81cf033c6eddff277680Robert Lee .exit_latency = 10, 49b334648db0ff2d07b00d81cf033c6eddff277680Robert Lee .target_residency = 100000, 50b334648db0ff2d07b00d81cf033c6eddff277680Robert Lee .flags = CPUIDLE_FLAG_TIME_VALID, 51b334648db0ff2d07b00d81cf033c6eddff277680Robert Lee .name = "DDR SR", 52b334648db0ff2d07b00d81cf033c6eddff277680Robert Lee .desc = "WFI and DDR Self Refresh", 53b334648db0ff2d07b00d81cf033c6eddff277680Robert Lee }, 54b334648db0ff2d07b00d81cf033c6eddff277680Robert Lee .state_count = KIRKWOOD_MAX_STATES, 55b334648db0ff2d07b00d81cf033c6eddff277680Robert Lee}; 56b334648db0ff2d07b00d81cf033c6eddff277680Robert Lee 57e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury/* Initialize CPU idle by registering the idle states */ 589cfc94eb0f4843af5d1141a37d7b7ca5d3b27220Andrew Lunnstatic int kirkwood_cpuidle_probe(struct platform_device *pdev) 59e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury{ 609cfc94eb0f4843af5d1141a37d7b7ca5d3b27220Andrew Lunn struct resource *res; 619cfc94eb0f4843af5d1141a37d7b7ca5d3b27220Andrew Lunn 629cfc94eb0f4843af5d1141a37d7b7ca5d3b27220Andrew Lunn res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 63488540bf41ce8ccfe8b54c646c3ea67a7196edcdSilviu-Mihai Popescu ddr_operation_base = devm_ioremap_resource(&pdev->dev, res); 64488540bf41ce8ccfe8b54c646c3ea67a7196edcdSilviu-Mihai Popescu if (IS_ERR(ddr_operation_base)) 65488540bf41ce8ccfe8b54c646c3ea67a7196edcdSilviu-Mihai Popescu return PTR_ERR(ddr_operation_base); 66e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury 6730dc72c6fa91c640e98ce5ef5ec33fb2beb41ad2Daniel Lezcano return cpuidle_register(&kirkwood_idle_driver, NULL); 68e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury} 69e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury 7075d6137da195a1e059e1c814cb95635e168f85c0Jingoo Hanstatic int kirkwood_cpuidle_remove(struct platform_device *pdev) 719cfc94eb0f4843af5d1141a37d7b7ca5d3b27220Andrew Lunn{ 7230dc72c6fa91c640e98ce5ef5ec33fb2beb41ad2Daniel Lezcano cpuidle_unregister(&kirkwood_idle_driver); 739cfc94eb0f4843af5d1141a37d7b7ca5d3b27220Andrew Lunn return 0; 749cfc94eb0f4843af5d1141a37d7b7ca5d3b27220Andrew Lunn} 759cfc94eb0f4843af5d1141a37d7b7ca5d3b27220Andrew Lunn 769cfc94eb0f4843af5d1141a37d7b7ca5d3b27220Andrew Lunnstatic struct platform_driver kirkwood_cpuidle_driver = { 779cfc94eb0f4843af5d1141a37d7b7ca5d3b27220Andrew Lunn .probe = kirkwood_cpuidle_probe, 789cfc94eb0f4843af5d1141a37d7b7ca5d3b27220Andrew Lunn .remove = kirkwood_cpuidle_remove, 799cfc94eb0f4843af5d1141a37d7b7ca5d3b27220Andrew Lunn .driver = { 809cfc94eb0f4843af5d1141a37d7b7ca5d3b27220Andrew Lunn .name = "kirkwood_cpuidle", 819cfc94eb0f4843af5d1141a37d7b7ca5d3b27220Andrew Lunn .owner = THIS_MODULE, 829cfc94eb0f4843af5d1141a37d7b7ca5d3b27220Andrew Lunn }, 839cfc94eb0f4843af5d1141a37d7b7ca5d3b27220Andrew Lunn}; 849cfc94eb0f4843af5d1141a37d7b7ca5d3b27220Andrew Lunn 859cfc94eb0f4843af5d1141a37d7b7ca5d3b27220Andrew Lunnmodule_platform_driver(kirkwood_cpuidle_driver); 869cfc94eb0f4843af5d1141a37d7b7ca5d3b27220Andrew Lunn 879cfc94eb0f4843af5d1141a37d7b7ca5d3b27220Andrew LunnMODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch>"); 889cfc94eb0f4843af5d1141a37d7b7ca5d3b27220Andrew LunnMODULE_DESCRIPTION("Kirkwood cpu idle driver"); 899cfc94eb0f4843af5d1141a37d7b7ca5d3b27220Andrew LunnMODULE_LICENSE("GPL v2"); 909cfc94eb0f4843af5d1141a37d7b7ca5d3b27220Andrew LunnMODULE_ALIAS("platform:kirkwood-cpuidle"); 91