Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * OMAP Power Management debug routines
0004  *
0005  * Copyright (C) 2005 Texas Instruments, Inc.
0006  * Copyright (C) 2006-2008 Nokia Corporation
0007  *
0008  * Written by:
0009  * Richard Woodruff <r-woodruff2@ti.com>
0010  * Tony Lindgren
0011  * Juha Yrjola
0012  * Amit Kucheria <amit.kucheria@nokia.com>
0013  * Igor Stoppa <igor.stoppa@nokia.com>
0014  * Jouni Hogander
0015  *
0016  * Based on pm.c for omap2
0017  */
0018 
0019 #include <linux/kernel.h>
0020 #include <linux/sched.h>
0021 #include <linux/sched/clock.h>
0022 #include <linux/clk.h>
0023 #include <linux/err.h>
0024 #include <linux/io.h>
0025 #include <linux/module.h>
0026 #include <linux/slab.h>
0027 
0028 #include "clock.h"
0029 #include "powerdomain.h"
0030 #include "clockdomain.h"
0031 
0032 #include "soc.h"
0033 #include "cm2xxx_3xxx.h"
0034 #include "prm2xxx_3xxx.h"
0035 #include "pm.h"
0036 
0037 #ifdef CONFIG_DEBUG_FS
0038 #include <linux/debugfs.h>
0039 #include <linux/seq_file.h>
0040 
0041 static int pm_dbg_init_done;
0042 
0043 static int pm_dbg_init(void);
0044 
0045 static const char pwrdm_state_names[][PWRDM_MAX_PWRSTS] = {
0046     "OFF",
0047     "RET",
0048     "INA",
0049     "ON"
0050 };
0051 
0052 void pm_dbg_update_time(struct powerdomain *pwrdm, int prev)
0053 {
0054     s64 t;
0055 
0056     if (!pm_dbg_init_done)
0057         return ;
0058 
0059     /* Update timer for previous state */
0060     t = sched_clock();
0061 
0062     pwrdm->state_timer[prev] += t - pwrdm->timer;
0063 
0064     pwrdm->timer = t;
0065 }
0066 
0067 static int clkdm_dbg_show_counter(struct clockdomain *clkdm, void *user)
0068 {
0069     struct seq_file *s = (struct seq_file *)user;
0070 
0071     if (strcmp(clkdm->name, "emu_clkdm") == 0 ||
0072         strcmp(clkdm->name, "wkup_clkdm") == 0 ||
0073         strncmp(clkdm->name, "dpll", 4) == 0)
0074         return 0;
0075 
0076     seq_printf(s, "%s->%s (%d)\n", clkdm->name, clkdm->pwrdm.ptr->name,
0077            clkdm->usecount);
0078 
0079     return 0;
0080 }
0081 
0082 static int pwrdm_dbg_show_counter(struct powerdomain *pwrdm, void *user)
0083 {
0084     struct seq_file *s = (struct seq_file *)user;
0085     int i;
0086 
0087     if (strcmp(pwrdm->name, "emu_pwrdm") == 0 ||
0088         strcmp(pwrdm->name, "wkup_pwrdm") == 0 ||
0089         strncmp(pwrdm->name, "dpll", 4) == 0)
0090         return 0;
0091 
0092     if (pwrdm->state != pwrdm_read_pwrst(pwrdm))
0093         printk(KERN_ERR "pwrdm state mismatch(%s) %d != %d\n",
0094             pwrdm->name, pwrdm->state, pwrdm_read_pwrst(pwrdm));
0095 
0096     seq_printf(s, "%s (%s)", pwrdm->name,
0097             pwrdm_state_names[pwrdm->state]);
0098     for (i = 0; i < PWRDM_MAX_PWRSTS; i++)
0099         seq_printf(s, ",%s:%d", pwrdm_state_names[i],
0100             pwrdm->state_counter[i]);
0101 
0102     seq_printf(s, ",RET-LOGIC-OFF:%d", pwrdm->ret_logic_off_counter);
0103     for (i = 0; i < pwrdm->banks; i++)
0104         seq_printf(s, ",RET-MEMBANK%d-OFF:%d", i + 1,
0105                 pwrdm->ret_mem_off_counter[i]);
0106 
0107     seq_putc(s, '\n');
0108     return 0;
0109 }
0110 
0111 static int pwrdm_dbg_show_timer(struct powerdomain *pwrdm, void *user)
0112 {
0113     struct seq_file *s = (struct seq_file *)user;
0114     int i;
0115 
0116     if (strcmp(pwrdm->name, "emu_pwrdm") == 0 ||
0117         strcmp(pwrdm->name, "wkup_pwrdm") == 0 ||
0118         strncmp(pwrdm->name, "dpll", 4) == 0)
0119         return 0;
0120 
0121     pwrdm_state_switch(pwrdm);
0122 
0123     seq_printf(s, "%s (%s)", pwrdm->name,
0124         pwrdm_state_names[pwrdm->state]);
0125 
0126     for (i = 0; i < 4; i++)
0127         seq_printf(s, ",%s:%lld", pwrdm_state_names[i],
0128             pwrdm->state_timer[i]);
0129 
0130     seq_putc(s, '\n');
0131     return 0;
0132 }
0133 
0134 static int pm_dbg_counters_show(struct seq_file *s, void *unused)
0135 {
0136     pwrdm_for_each(pwrdm_dbg_show_counter, s);
0137     clkdm_for_each(clkdm_dbg_show_counter, s);
0138 
0139     return 0;
0140 }
0141 DEFINE_SHOW_ATTRIBUTE(pm_dbg_counters);
0142 
0143 static int pm_dbg_timers_show(struct seq_file *s, void *unused)
0144 {
0145     pwrdm_for_each(pwrdm_dbg_show_timer, s);
0146     return 0;
0147 }
0148 DEFINE_SHOW_ATTRIBUTE(pm_dbg_timers);
0149 
0150 static int pwrdm_suspend_get(void *data, u64 *val)
0151 {
0152     int ret = -EINVAL;
0153 
0154     if (cpu_is_omap34xx())
0155         ret = omap3_pm_get_suspend_state((struct powerdomain *)data);
0156     *val = ret;
0157 
0158     if (ret >= 0)
0159         return 0;
0160     return *val;
0161 }
0162 
0163 static int pwrdm_suspend_set(void *data, u64 val)
0164 {
0165     if (cpu_is_omap34xx())
0166         return omap3_pm_set_suspend_state(
0167             (struct powerdomain *)data, (int)val);
0168     return -EINVAL;
0169 }
0170 
0171 DEFINE_DEBUGFS_ATTRIBUTE(pwrdm_suspend_fops, pwrdm_suspend_get,
0172               pwrdm_suspend_set, "%llu\n");
0173 
0174 static int __init pwrdms_setup(struct powerdomain *pwrdm, void *dir)
0175 {
0176     int i;
0177     s64 t;
0178     struct dentry *d;
0179 
0180     t = sched_clock();
0181 
0182     for (i = 0; i < 4; i++)
0183         pwrdm->state_timer[i] = 0;
0184 
0185     pwrdm->timer = t;
0186 
0187     if (strncmp(pwrdm->name, "dpll", 4) == 0)
0188         return 0;
0189 
0190     d = debugfs_create_dir(pwrdm->name, (struct dentry *)dir);
0191     debugfs_create_file("suspend", S_IRUGO|S_IWUSR, d, pwrdm,
0192                 &pwrdm_suspend_fops);
0193 
0194     return 0;
0195 }
0196 
0197 static int option_get(void *data, u64 *val)
0198 {
0199     u32 *option = data;
0200 
0201     *val = *option;
0202 
0203     return 0;
0204 }
0205 
0206 static int option_set(void *data, u64 val)
0207 {
0208     u32 *option = data;
0209 
0210     *option = val;
0211 
0212     if (option == &enable_off_mode) {
0213         if (cpu_is_omap34xx())
0214             omap3_pm_off_mode_enable(val);
0215     }
0216 
0217     return 0;
0218 }
0219 
0220 DEFINE_SIMPLE_ATTRIBUTE(pm_dbg_option_fops, option_get, option_set, "%llu\n");
0221 
0222 static int __init pm_dbg_init(void)
0223 {
0224     struct dentry *d;
0225 
0226     if (pm_dbg_init_done)
0227         return 0;
0228 
0229     d = debugfs_create_dir("pm_debug", NULL);
0230 
0231     debugfs_create_file("count", 0444, d, NULL, &pm_dbg_counters_fops);
0232     debugfs_create_file("time", 0444, d, NULL, &pm_dbg_timers_fops);
0233 
0234     pwrdm_for_each(pwrdms_setup, (void *)d);
0235 
0236     debugfs_create_file("enable_off_mode", S_IRUGO | S_IWUSR, d,
0237                 &enable_off_mode, &pm_dbg_option_fops);
0238     pm_dbg_init_done = 1;
0239 
0240     return 0;
0241 }
0242 omap_arch_initcall(pm_dbg_init);
0243 
0244 #endif