mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-27 14:43:58 +08:00
fb2c599f05
Enabling off mode was only reachable deeply hidden in the debugfs. As powersaving is an important feature, move the option out of its shady place. The debugfs file can still be used to override the default. Use the presence of a device compatible to ti,twl4030-idle or ti,twl4030-idle-osc-off as an indicator that the board is wired correctly for off mode. Signed-off-by: Andreas Kemnade <andreas@kemnade.info> [tony@atomide.com: updated to fix a checkpatch warning] Signed-off-by: Tony Lindgren <tony@atomide.com>
245 lines
5.0 KiB
C
245 lines
5.0 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* OMAP Power Management debug routines
|
|
*
|
|
* Copyright (C) 2005 Texas Instruments, Inc.
|
|
* Copyright (C) 2006-2008 Nokia Corporation
|
|
*
|
|
* Written by:
|
|
* Richard Woodruff <r-woodruff2@ti.com>
|
|
* Tony Lindgren
|
|
* Juha Yrjola
|
|
* Amit Kucheria <amit.kucheria@nokia.com>
|
|
* Igor Stoppa <igor.stoppa@nokia.com>
|
|
* Jouni Hogander
|
|
*
|
|
* Based on pm.c for omap2
|
|
*/
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/sched/clock.h>
|
|
#include <linux/clk.h>
|
|
#include <linux/err.h>
|
|
#include <linux/io.h>
|
|
#include <linux/module.h>
|
|
#include <linux/slab.h>
|
|
|
|
#include "clock.h"
|
|
#include "powerdomain.h"
|
|
#include "clockdomain.h"
|
|
|
|
#include "soc.h"
|
|
#include "cm2xxx_3xxx.h"
|
|
#include "prm2xxx_3xxx.h"
|
|
#include "pm.h"
|
|
|
|
#ifdef CONFIG_DEBUG_FS
|
|
#include <linux/debugfs.h>
|
|
#include <linux/seq_file.h>
|
|
|
|
static int pm_dbg_init_done;
|
|
|
|
static int pm_dbg_init(void);
|
|
|
|
static const char pwrdm_state_names[][PWRDM_MAX_PWRSTS] = {
|
|
"OFF",
|
|
"RET",
|
|
"INA",
|
|
"ON"
|
|
};
|
|
|
|
void pm_dbg_update_time(struct powerdomain *pwrdm, int prev)
|
|
{
|
|
s64 t;
|
|
|
|
if (!pm_dbg_init_done)
|
|
return ;
|
|
|
|
/* Update timer for previous state */
|
|
t = sched_clock();
|
|
|
|
pwrdm->state_timer[prev] += t - pwrdm->timer;
|
|
|
|
pwrdm->timer = t;
|
|
}
|
|
|
|
static int clkdm_dbg_show_counter(struct clockdomain *clkdm, void *user)
|
|
{
|
|
struct seq_file *s = (struct seq_file *)user;
|
|
|
|
if (strcmp(clkdm->name, "emu_clkdm") == 0 ||
|
|
strcmp(clkdm->name, "wkup_clkdm") == 0 ||
|
|
strncmp(clkdm->name, "dpll", 4) == 0)
|
|
return 0;
|
|
|
|
seq_printf(s, "%s->%s (%d)\n", clkdm->name, clkdm->pwrdm.ptr->name,
|
|
clkdm->usecount);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int pwrdm_dbg_show_counter(struct powerdomain *pwrdm, void *user)
|
|
{
|
|
struct seq_file *s = (struct seq_file *)user;
|
|
int i;
|
|
|
|
if (strcmp(pwrdm->name, "emu_pwrdm") == 0 ||
|
|
strcmp(pwrdm->name, "wkup_pwrdm") == 0 ||
|
|
strncmp(pwrdm->name, "dpll", 4) == 0)
|
|
return 0;
|
|
|
|
if (pwrdm->state != pwrdm_read_pwrst(pwrdm))
|
|
printk(KERN_ERR "pwrdm state mismatch(%s) %d != %d\n",
|
|
pwrdm->name, pwrdm->state, pwrdm_read_pwrst(pwrdm));
|
|
|
|
seq_printf(s, "%s (%s)", pwrdm->name,
|
|
pwrdm_state_names[pwrdm->state]);
|
|
for (i = 0; i < PWRDM_MAX_PWRSTS; i++)
|
|
seq_printf(s, ",%s:%d", pwrdm_state_names[i],
|
|
pwrdm->state_counter[i]);
|
|
|
|
seq_printf(s, ",RET-LOGIC-OFF:%d", pwrdm->ret_logic_off_counter);
|
|
for (i = 0; i < pwrdm->banks; i++)
|
|
seq_printf(s, ",RET-MEMBANK%d-OFF:%d", i + 1,
|
|
pwrdm->ret_mem_off_counter[i]);
|
|
|
|
seq_putc(s, '\n');
|
|
return 0;
|
|
}
|
|
|
|
static int pwrdm_dbg_show_timer(struct powerdomain *pwrdm, void *user)
|
|
{
|
|
struct seq_file *s = (struct seq_file *)user;
|
|
int i;
|
|
|
|
if (strcmp(pwrdm->name, "emu_pwrdm") == 0 ||
|
|
strcmp(pwrdm->name, "wkup_pwrdm") == 0 ||
|
|
strncmp(pwrdm->name, "dpll", 4) == 0)
|
|
return 0;
|
|
|
|
pwrdm_state_switch(pwrdm);
|
|
|
|
seq_printf(s, "%s (%s)", pwrdm->name,
|
|
pwrdm_state_names[pwrdm->state]);
|
|
|
|
for (i = 0; i < 4; i++)
|
|
seq_printf(s, ",%s:%lld", pwrdm_state_names[i],
|
|
pwrdm->state_timer[i]);
|
|
|
|
seq_putc(s, '\n');
|
|
return 0;
|
|
}
|
|
|
|
static int pm_dbg_counters_show(struct seq_file *s, void *unused)
|
|
{
|
|
pwrdm_for_each(pwrdm_dbg_show_counter, s);
|
|
clkdm_for_each(clkdm_dbg_show_counter, s);
|
|
|
|
return 0;
|
|
}
|
|
DEFINE_SHOW_ATTRIBUTE(pm_dbg_counters);
|
|
|
|
static int pm_dbg_timers_show(struct seq_file *s, void *unused)
|
|
{
|
|
pwrdm_for_each(pwrdm_dbg_show_timer, s);
|
|
return 0;
|
|
}
|
|
DEFINE_SHOW_ATTRIBUTE(pm_dbg_timers);
|
|
|
|
static int pwrdm_suspend_get(void *data, u64 *val)
|
|
{
|
|
int ret = -EINVAL;
|
|
|
|
if (cpu_is_omap34xx())
|
|
ret = omap3_pm_get_suspend_state((struct powerdomain *)data);
|
|
*val = ret;
|
|
|
|
if (ret >= 0)
|
|
return 0;
|
|
return *val;
|
|
}
|
|
|
|
static int pwrdm_suspend_set(void *data, u64 val)
|
|
{
|
|
if (cpu_is_omap34xx())
|
|
return omap3_pm_set_suspend_state(
|
|
(struct powerdomain *)data, (int)val);
|
|
return -EINVAL;
|
|
}
|
|
|
|
DEFINE_SIMPLE_ATTRIBUTE(pwrdm_suspend_fops, pwrdm_suspend_get,
|
|
pwrdm_suspend_set, "%llu\n");
|
|
|
|
static int __init pwrdms_setup(struct powerdomain *pwrdm, void *dir)
|
|
{
|
|
int i;
|
|
s64 t;
|
|
struct dentry *d;
|
|
|
|
t = sched_clock();
|
|
|
|
for (i = 0; i < 4; i++)
|
|
pwrdm->state_timer[i] = 0;
|
|
|
|
pwrdm->timer = t;
|
|
|
|
if (strncmp(pwrdm->name, "dpll", 4) == 0)
|
|
return 0;
|
|
|
|
d = debugfs_create_dir(pwrdm->name, (struct dentry *)dir);
|
|
debugfs_create_file("suspend", S_IRUGO|S_IWUSR, d, pwrdm,
|
|
&pwrdm_suspend_fops);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int option_get(void *data, u64 *val)
|
|
{
|
|
u32 *option = data;
|
|
|
|
*val = *option;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int option_set(void *data, u64 val)
|
|
{
|
|
u32 *option = data;
|
|
|
|
*option = val;
|
|
|
|
if (option == &enable_off_mode) {
|
|
if (cpu_is_omap34xx())
|
|
omap3_pm_off_mode_enable(val);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
DEFINE_SIMPLE_ATTRIBUTE(pm_dbg_option_fops, option_get, option_set, "%llu\n");
|
|
|
|
static int __init pm_dbg_init(void)
|
|
{
|
|
struct dentry *d;
|
|
|
|
if (pm_dbg_init_done)
|
|
return 0;
|
|
|
|
d = debugfs_create_dir("pm_debug", NULL);
|
|
|
|
debugfs_create_file("count", 0444, d, NULL, &pm_dbg_counters_fops);
|
|
debugfs_create_file("time", 0444, d, NULL, &pm_dbg_timers_fops);
|
|
|
|
pwrdm_for_each(pwrdms_setup, (void *)d);
|
|
|
|
debugfs_create_file("enable_off_mode", S_IRUGO | S_IWUSR, d,
|
|
&enable_off_mode, &pm_dbg_option_fops);
|
|
pm_dbg_init_done = 1;
|
|
|
|
return 0;
|
|
}
|
|
omap_arch_initcall(pm_dbg_init);
|
|
|
|
#endif
|