diff --git a/arch/arm/boot/dts/vexpress-v2p-ca15-tc2.dts b/arch/arm/boot/dts/vexpress-v2p-ca15-tc2.dts index b261bde..7315048 --- a/arch/arm/boot/dts/vexpress-v2p-ca15-tc2.dts +++ b/arch/arm/boot/dts/vexpress-v2p-ca15-tc2.dts @@ -152,6 +152,31 @@ interrupts = <0 95 4>; }; + cpuidle { + #address-cells = <1>; + #size-cells = <0>; + + idlestates { + idlestate0: idlestate@0 { + enter = "simple"; + exit_latency = <1>; + target_residency = <1>; + power_usage = <0xffffffff>; + flags = <0x1>; + state_name = "WFI"; + desc = "ARM WFI"; + }; + idlestate1: idlestate@1 { + enter = "powerdown"; + exit_latency = <300>; + target_residency = <1000>; + flags = <0x1>; + state_name = "C1"; + desc = "ARM power down"; + }; + }; + }; + cci@2c090000 { compatible = "arm,cci"; diff --git a/drivers/cpuidle/arm_big_little.c b/drivers/cpuidle/arm_big_little.c index b97ebe0..857979e --- a/drivers/cpuidle/arm_big_little.c +++ b/drivers/cpuidle/arm_big_little.c @@ -136,6 +136,44 @@ static int bl_enter_powerdown(struct cpuidle_device *dev, return idx; } +int bl_idle_get_dt_states(struct cpuidle_driver *drv) +{ + struct device_node *np = NULL; + int count = 0; + const char *str; + u32 val; + struct cpuidle_state *state = &drv->states[0]; + + while ((np = of_find_node_by_name(np, "idlestate"))) { + count++; + if (count >= CPUIDLE_STATE_MAX) { + pr_err("%s: too many states max=%d\n", __func__, + CPUIDLE_STATE_MAX); + return -EFAULT; + } + + if (of_property_read_u32(np, "exit_latency", &val) == 0) + state->exit_latency = val; + if (of_property_read_u32(np, "target_residency", &val) == 0) + state->target_residency = val; + if (of_property_read_u32(np, "power_usage", &val) == 0) + state->power_usage = val; + if (of_property_read_u32(np, "flags", &val) == 0) + state->flags = val; + if (of_property_read_string(np, "state_name", &str) == 0) + strncpy(state->name, str, CPUIDLE_NAME_LEN); + if (of_property_read_string(np, "desc", &str) == 0) + strncpy(state->desc, str, CPUIDLE_DESC_LEN); + if (of_property_match_string(np, "enter", "powerdown") == 0) + state->enter = bl_enter_powerdown; + else if (of_property_match_string(np, "enter", "simple") == 0) + state->enter = bl_cpuidle_simple_enter; + state++; + } + drv->state_count = count; + return 0; +} + /* * bl_idle_init * @@ -153,12 +191,32 @@ int __init bl_idle_init(void) return -ENODEV; } - drv->state_count = (sizeof(bl_cpuidle_set) / - sizeof(struct cpuidle_state)); + if (bl_idle_get_dt_states(drv) == 0) { + struct cpuidle_state *st = &drv->states[0]; + + pr_err("%s: using DTS state count = %d\n", + __func__, drv->state_count); + for (i = 0; i < drv->state_count; i++) { + st = &drv->states[i]; + pr_err("State[%d] %s (%s) %s\n", + i, st->name, st->desc, + st->enter == bl_enter_powerdown ? "powerdown" : + st->enter == bl_cpuidle_simple_enter ? + "simple" : "NULL"); + pr_err("State[%d] el %u tr %u pu %u fl %u\n", + i, st->exit_latency, st->target_residency, + st->power_usage, st->flags); + } + } else { + drv->state_count = (sizeof(bl_cpuidle_set) / + sizeof(struct cpuidle_state)); - for (i = 0; i < drv->state_count; i++) { - memcpy(&drv->states[i], &bl_cpuidle_set[i], - sizeof(struct cpuidle_state)); + for (i = 0; i < drv->state_count; i++) { + memcpy(&drv->states[i], &bl_cpuidle_set[i], + sizeof(struct cpuidle_state)); + } + pr_err("%s: using built in states count = %d\n", + __func__, drv->state_count); } cpuidle_register_driver(drv); @@ -171,7 +229,7 @@ int __init bl_idle_init(void) dev->state_count = drv->state_count; if (cpuidle_register_device(dev)) { - printk(KERN_ERR "%s: Cpuidle register device failed\n", + pr_err("%s: Cpuidle register device failed\n", __func__); return -EIO; }