blob: fdba66c1be0d8db8c2daf6e627b3b6eaf2cc7908 [file] [log] [blame]
#ifndef __ASRDCSTAT_H
#define __ASRDCSTAT_H
#include <linux/debugfs.h>
#include <linux/uaccess.h>
//TODO #include <linux/clk/dvfs-dvc.h>
#include <linux/fs.h>
#include <linux/time.h>
//TODO #include <asm/cputime.h>
#include <asm/div64.h>
#include <linux/kernel_stat.h>
#include <linux/tick.h>
enum lowpower_mode {
LPM_C1,
LPM_C2,
#ifdef CONFIG_ARM64
LPM_MP2,
#endif
LPM_D1P,
LPM_D1,
LPM_D2,
LPM_D2_UDR,
MAX_LPM_INDEX = 15,
};
#define MAX_BREAKDOWN_TIME 11
/* use the largest possible number is 10 */
#define MAX_LPM_INDEX_DC 10
struct op_dcstat_info {
unsigned int ppindex;
unsigned long pprate;
struct timespec64 prev_ts;
u64 clk_idle_time; /* ns */
u64 clk_busy_time; /* ns */
u64 pwr_off_time; /* ns */
/* used for ddr ticks ratio */
long ddr_glob_ratio;
long ddr_idle_ratio;
long ddr_busy_ratio;
long ddr_data_ratio;
long ddr_util_ratio;
};
struct clk_dc_stat_info {
bool stat_start;
struct op_dcstat_info *ops_dcstat;
u32 power_mode;
unsigned int ops_stat_size;
unsigned int curopindex;
unsigned int idle_flag;
unsigned int online;
u64 C1_idle_start;
u64 C1_idle_end;
u64 C1_op_total[MAX_LPM_INDEX_DC];
int C1_op_index;
u64 C1_count[MAX_LPM_INDEX_DC];
u64 C2_idle_start;
u64 C2_idle_end;
u64 C2_op_total[MAX_LPM_INDEX_DC];
int C2_op_index;
u64 C2_count[MAX_LPM_INDEX_DC];
u64 breakdown_start;
u64 breakdown_end;
u64 breakdown_time_total[MAX_BREAKDOWN_TIME+1];
u64 breakdown_time_count[MAX_BREAKDOWN_TIME+1];
u64 runtime_start;
u64 runtime_end;
u64 runtime_op_total[MAX_LPM_INDEX_DC];
u64 idle_op_total[MAX_LPM_INDEX_DC];
int runtime_op_index;
};
struct clk_dcstat {
struct clk *clk;
struct clk_dc_stat_info clk_dcstat;
struct list_head node;
struct notifier_block nb;
};
struct core_dcstat {
struct clk *clk;
int cpu_num;
int *cpu_id;
struct list_head node;
};
enum clk_stat_msg {
CLK_STAT_START = 0,
CLK_STAT_STOP,
CLK_STATE_ON,
CLK_STATE_OFF,
CLK_RATE_CHANGE,
PWR_ON,
PWR_OFF,
CLK_DYNVOL_CHANGE,
CPU_IDLE_ENTER,
CPU_IDLE_EXIT,
CPU_M2_OR_DEEPER_ENTER,
};
struct idle_dcstat_info {
u64 all_idle_start;
u64 all_idle_end;
u64 total_all_idle;
u64 total_all_idle_count;
u64 all_active_start;
u64 all_active_end;
u64 total_all_active;
u64 total_all_active_count;
u64 M2_idle_start;
u64 M2_idle_total;
u64 M2_count;
u64 D1P_idle_start;
u64 D1P_idle_total;
u64 D1p_count;
u64 D1_idle_start;
u64 D1_idle_total;
u64 D1_count;
u64 D2_idle_start;
u64 D2_idle_total;
u64 D2_count;
u64 cal_duration;
u64 all_idle_op_total[MAX_LPM_INDEX_DC];
int all_idle_op_index;
u64 all_idle_count[MAX_LPM_INDEX_DC];
};
#define CLK_DCSTAT_OPS(clk, name) \
static int name##_dc_show(struct seq_file *seq, void *data) \
{ \
if (!clk) \
return -ENODEV; \
\
show_dc_stat_info(clk, seq, data); \
if (seq->count == PAGE_SIZE) \
pr_warn("%s The dump buf is larger than one page!\n", \
__func__); \
return 0; \
} \
static ssize_t name##_dc_write(struct file *filp, \
const char __user *buffer, size_t count, loff_t *ppos) \
{ \
unsigned int start; \
char buf[10] = { 0 }; \
size_t ret = 0; \
\
if (!clk) \
return -ENODEV; \
\
if (copy_from_user(buf, buffer, count)) \
return -EFAULT; \
sscanf(buf, "%d", &start); \
ret = start_stop_dc_stat(clk, start); \
if (ret < 0) \
return ret; \
return count; \
} \
static int name##_dc_open(struct inode *inode, struct file *file) \
{ \
return single_open(file, name##_dc_show, NULL); \
} \
static const struct file_operations name##_dc_ops = { \
.owner = THIS_MODULE, \
.open = name##_dc_open, \
.read = seq_read, \
.write = name##_dc_write, \
.llseek = seq_lseek, \
.release = single_release, \
}; \
/* function used for clk duty cycle stat */
static inline u64 ts2ns(struct timespec64 cur, struct timespec64 prev)
{
u64 time_ns = 0;
if ((cur.tv_sec > prev.tv_sec) ||
((cur.tv_sec == prev.tv_sec) && (cur.tv_nsec > prev.tv_nsec))) {
time_ns = (u64)(cur.tv_sec - prev.tv_sec);
time_ns *= NSEC_PER_SEC;
time_ns += (u64)(cur.tv_nsec - prev.tv_nsec);
}
return time_ns;
}
static inline u32 calculate_dc(u32 busy, u32 total, u32 *fraction)
{
u32 result, remainder;
u64 busy64, remainder64;
busy64 = (u64)busy;
result = div_u64_rem(busy64 * 100, total, &remainder);
remainder64 = (u64)remainder;
*fraction = div_u64(remainder64 * 100, total);
return result;
}
int show_dc_stat_info(struct clk *clk, struct seq_file *seq, void *data);
int start_stop_dc_stat(struct clk *clk, unsigned int start);
int clk_register_dcstat(struct clk *clk,
unsigned long *opt, unsigned int opt_size);
#ifdef CONFIG_ARM_PSCI
extern void asr_cpuidle_enter_dcstat(int index);
extern void asr_cpuidle_exit_dcstat(void);
#else
static inline void asr_cpuidle_enter_dcstat(int index)
{
}
static inline void asr_cpuidle_exit_dcstat(void)
{
}
#endif
typedef int (*powermode)(u32);
#ifdef CONFIG_DEBUG_FS
extern void cpu_dcstat_event(struct clk *clk, unsigned int cpuid,
enum clk_stat_msg msg, unsigned int tgtop);
extern void clk_dcstat_event(struct clk *clk,
enum clk_stat_msg msg, unsigned int tgtstate);
extern void clk_dcstat_event_check(struct clk *clk,
enum clk_stat_msg msg, unsigned int tgtstate);
extern int register_cpu_dcstat(struct clk *clk, unsigned int cpunum,
unsigned int *op_table, unsigned int opt_size, powermode func);
extern struct dentry *cpu_dcstat_file_create(const char *file_name,
struct dentry *parent);
extern struct dentry *clk_dcstat_file_create(const char *file_name,
struct dentry *parent, const struct file_operations *fops);
extern struct clk *cpu_dcstat_clk;
extern void vol_dcstat_event(u32);
extern void vol_ledstatus_event(u32);
#else
static inline void cpu_dcstat_event(struct clk *clk, unsigned int cpuid,
enum clk_stat_msg msg, unsigned int tgtop)
{
}
static inline void clk_dcstat_event(struct clk *clk,
enum clk_stat_msg msg, unsigned int tgtstate)
{
}
static inline void clk_dcstat_event_check(struct clk *clk,
enum clk_stat_msg msg, unsigned int tgtstate)
{
}
static int register_cpu_dcstat(struct clk *clk, unsigned int cpunum,
unsigned int *op_table, unsigned int opt_size, powermode func);
{
}
static struct dentry *cpu_dcstat_file_create(const char *file_name,
struct dentry *parent);
{
}
static struct dentry *clk_dcstat_file_create(const char *file_name,
struct dentry *parent, const struct file_operations *fops);
{
}
void vol_dcstat_event(u32) {}
void vol_ledstatus_event(u32) {}
#endif
extern int ddr_profiling_show(struct clk_dc_stat_info *dc_stat_info);
extern int ddr_profiling_store(int start);
extern u64 suspended_time;
#endif /* __ASRDCSTAT_H */