ARM: S3C: CPUFREQ: Add debugfs support for cpufreq
Add debugfs support for the cpufreq driver to allow information about the system state to be exported to the user. Signed-off-by: Ben Dooks <ben@simtec.co.uk> Signed-off-by: Ben Dooks <ben-linux@fluff.org>
This commit is contained in:
parent
dfff4e95d7
commit
e6d197a695
10 changed files with 317 additions and 0 deletions
|
@ -1329,6 +1329,12 @@ config CPU_FREQ_S3C24XX_IODEBUG
|
|||
help
|
||||
Enable s3c_freq_iodbg for the Samsung S3C CPUfreq core
|
||||
|
||||
config CPU_FREQ_S3C24XX_DEBUGFS
|
||||
bool "Export debugfs for CPUFreq"
|
||||
depends on CPU_FREQ_S3C24XX && DEBUG_FS
|
||||
help
|
||||
Export status information via debugfs.
|
||||
|
||||
endif
|
||||
|
||||
source "drivers/cpuidle/Kconfig"
|
||||
|
|
|
@ -111,6 +111,8 @@ static struct s3c_cpufreq_info s3c2410_cpufreq_info = {
|
|||
.set_refresh = s3c2410_cpufreq_setrefresh,
|
||||
.set_divs = s3c2410_cpufreq_setdivs,
|
||||
.calc_divs = s3c2410_cpufreq_calcdivs,
|
||||
|
||||
.debug_io_show = s3c_cpufreq_debugfs_call(s3c2410_iotiming_debugfs),
|
||||
};
|
||||
|
||||
static int s3c2410_cpufreq_add(struct sys_device *sysdev)
|
||||
|
|
|
@ -190,6 +190,8 @@ static struct s3c_cpufreq_info s3c2412_cpufreq_info = {
|
|||
.get_iotiming = s3c2412_iotiming_get,
|
||||
|
||||
.resume_clocks = s3c2412_setup_clocks,
|
||||
|
||||
.debug_io_show = s3c_cpufreq_debugfs_call(s3c2412_iotiming_debugfs),
|
||||
};
|
||||
|
||||
static int s3c2412_cpufreq_add(struct sys_device *sysdev)
|
||||
|
|
|
@ -21,6 +21,7 @@ obj-y += clock.o
|
|||
obj-$(CONFIG_S3C24XX_DCLK) += clock-dclk.o
|
||||
|
||||
obj-$(CONFIG_CPU_FREQ_S3C24XX) += cpu-freq.o
|
||||
obj-$(CONFIG_CPU_FREQ_S3C24XX_DEBUGFS) += cpu-freq-debugfs.o
|
||||
|
||||
# Architecture dependant builds
|
||||
|
||||
|
|
199
arch/arm/plat-s3c24xx/cpu-freq-debugfs.c
Normal file
199
arch/arm/plat-s3c24xx/cpu-freq-debugfs.c
Normal file
|
@ -0,0 +1,199 @@
|
|||
/* linux/arch/arm/plat-s3c24xx/cpu-freq-debugfs.c
|
||||
*
|
||||
* Copyright (c) 2009 Simtec Electronics
|
||||
* http://armlinux.simtec.co.uk/
|
||||
* Ben Dooks <ben@simtec.co.uk>
|
||||
*
|
||||
* S3C24XX CPU Frequency scaling - debugfs status support
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include <plat/cpu-freq-core.h>
|
||||
|
||||
static struct dentry *dbgfs_root;
|
||||
static struct dentry *dbgfs_file_io;
|
||||
static struct dentry *dbgfs_file_info;
|
||||
static struct dentry *dbgfs_file_board;
|
||||
|
||||
#define print_ns(x) ((x) / 10), ((x) % 10)
|
||||
|
||||
static void show_max(struct seq_file *seq, struct s3c_freq *f)
|
||||
{
|
||||
seq_printf(seq, "MAX: F=%lu, H=%lu, P=%lu, A=%lu\n",
|
||||
f->fclk, f->hclk, f->pclk, f->armclk);
|
||||
}
|
||||
|
||||
static int board_show(struct seq_file *seq, void *p)
|
||||
{
|
||||
struct s3c_cpufreq_config *cfg;
|
||||
struct s3c_cpufreq_board *brd;
|
||||
|
||||
cfg = s3c_cpufreq_getconfig();
|
||||
if (!cfg) {
|
||||
seq_printf(seq, "no configuration registered\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
brd = cfg->board;
|
||||
if (!brd) {
|
||||
seq_printf(seq, "no board definition set?\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
seq_printf(seq, "SDRAM refresh %u ns\n", brd->refresh);
|
||||
seq_printf(seq, "auto_io=%u\n", brd->auto_io);
|
||||
seq_printf(seq, "need_io=%u\n", brd->need_io);
|
||||
|
||||
show_max(seq, &brd->max);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fops_board_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, board_show, NULL);
|
||||
}
|
||||
|
||||
static const struct file_operations fops_board = {
|
||||
.open = fops_board_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int info_show(struct seq_file *seq, void *p)
|
||||
{
|
||||
struct s3c_cpufreq_config *cfg;
|
||||
|
||||
cfg = s3c_cpufreq_getconfig();
|
||||
if (!cfg) {
|
||||
seq_printf(seq, "no configuration registered\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
seq_printf(seq, " FCLK %ld Hz\n", cfg->freq.fclk);
|
||||
seq_printf(seq, " HCLK %ld Hz (%lu.%lu ns)\n",
|
||||
cfg->freq.hclk, print_ns(cfg->freq.hclk_tns));
|
||||
seq_printf(seq, " PCLK %ld Hz\n", cfg->freq.hclk);
|
||||
seq_printf(seq, "ARMCLK %ld Hz\n", cfg->freq.armclk);
|
||||
seq_printf(seq, "\n");
|
||||
|
||||
show_max(seq, &cfg->max);
|
||||
|
||||
seq_printf(seq, "Divisors: P=%d, H=%d, A=%d, dvs=%s\n",
|
||||
cfg->divs.h_divisor, cfg->divs.p_divisor,
|
||||
cfg->divs.arm_divisor, cfg->divs.dvs ? "on" : "off");
|
||||
seq_printf(seq, "\n");
|
||||
|
||||
seq_printf(seq, "lock_pll=%u\n", cfg->lock_pll);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fops_info_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, info_show, NULL);
|
||||
}
|
||||
|
||||
static const struct file_operations fops_info = {
|
||||
.open = fops_info_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int io_show(struct seq_file *seq, void *p)
|
||||
{
|
||||
void (*show_bank)(struct seq_file *, struct s3c_cpufreq_config *, union s3c_iobank *);
|
||||
struct s3c_cpufreq_config *cfg;
|
||||
struct s3c_iotimings *iot;
|
||||
union s3c_iobank *iob;
|
||||
int bank;
|
||||
|
||||
cfg = s3c_cpufreq_getconfig();
|
||||
if (!cfg) {
|
||||
seq_printf(seq, "no configuration registered\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
show_bank = cfg->info->debug_io_show;
|
||||
if (!show_bank) {
|
||||
seq_printf(seq, "no code to show bank timing\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
iot = s3c_cpufreq_getiotimings();
|
||||
if (!iot) {
|
||||
seq_printf(seq, "no io timings registered\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
seq_printf(seq, "hclk period is %lu.%lu ns\n", print_ns(cfg->freq.hclk_tns));
|
||||
|
||||
for (bank = 0; bank < MAX_BANKS; bank++) {
|
||||
iob = &iot->bank[bank];
|
||||
|
||||
seq_printf(seq, "bank %d: ", bank);
|
||||
|
||||
if (!iob->io_2410) {
|
||||
seq_printf(seq, "nothing set\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
show_bank(seq, cfg, iob);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fops_io_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, io_show, NULL);
|
||||
}
|
||||
|
||||
static const struct file_operations fops_io = {
|
||||
.open = fops_io_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
||||
static int __init s3c_freq_debugfs_init(void)
|
||||
{
|
||||
dbgfs_root = debugfs_create_dir("s3c-cpufreq", NULL);
|
||||
if (IS_ERR(dbgfs_root)) {
|
||||
printk(KERN_ERR "%s: error creating debugfs root\n", __func__);
|
||||
return PTR_ERR(dbgfs_root);
|
||||
}
|
||||
|
||||
dbgfs_file_io = debugfs_create_file("io-timing", S_IRUGO, dbgfs_root,
|
||||
NULL, &fops_io);
|
||||
|
||||
dbgfs_file_info = debugfs_create_file("info", S_IRUGO, dbgfs_root,
|
||||
NULL, &fops_info);
|
||||
|
||||
dbgfs_file_board = debugfs_create_file("board", S_IRUGO, dbgfs_root,
|
||||
NULL, &fops_board);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
late_initcall(s3c_freq_debugfs_init);
|
||||
|
|
@ -50,6 +50,18 @@ static struct clk *clk_hclk;
|
|||
static struct clk *clk_pclk;
|
||||
static struct clk *clk_arm;
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ_S3C24XX_DEBUGFS
|
||||
struct s3c_cpufreq_config *s3c_cpufreq_getconfig(void)
|
||||
{
|
||||
return &cpu_cur;
|
||||
}
|
||||
|
||||
struct s3c_iotimings *s3c_cpufreq_getiotimings(void)
|
||||
{
|
||||
return &s3c24xx_iotiming;
|
||||
}
|
||||
#endif /* CONFIG_CPU_FREQ_S3C24XX_DEBUGFS */
|
||||
|
||||
static void s3c_cpufreq_getcur(struct s3c_cpufreq_config *cfg)
|
||||
{
|
||||
unsigned long fclk, pclk, hclk, armclk;
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
|
||||
#include <plat/cpu-freq.h>
|
||||
|
||||
struct seq_file;
|
||||
|
||||
#define MAX_BANKS (8)
|
||||
#define S3C2412_MAX_IO (8)
|
||||
|
||||
|
@ -181,6 +183,10 @@ struct s3c_cpufreq_info {
|
|||
struct cpufreq_frequency_table *t,
|
||||
size_t table_size);
|
||||
|
||||
void (*debug_io_show)(struct seq_file *seq,
|
||||
struct s3c_cpufreq_config *cfg,
|
||||
union s3c_iobank *iob);
|
||||
|
||||
void (*set_refresh)(struct s3c_cpufreq_config *cfg);
|
||||
void (*set_fvco)(struct s3c_cpufreq_config *cfg);
|
||||
void (*set_divs)(struct s3c_cpufreq_config *cfg);
|
||||
|
@ -191,6 +197,24 @@ extern int s3c_cpufreq_register(struct s3c_cpufreq_info *info);
|
|||
|
||||
extern int s3c_plltab_register(struct cpufreq_frequency_table *plls, unsigned int plls_no);
|
||||
|
||||
/* exports and utilities for debugfs */
|
||||
extern struct s3c_cpufreq_config *s3c_cpufreq_getconfig(void);
|
||||
extern struct s3c_iotimings *s3c_cpufreq_getiotimings(void);
|
||||
|
||||
extern void s3c2410_iotiming_debugfs(struct seq_file *seq,
|
||||
struct s3c_cpufreq_config *cfg,
|
||||
union s3c_iobank *iob);
|
||||
|
||||
extern void s3c2412_iotiming_debugfs(struct seq_file *seq,
|
||||
struct s3c_cpufreq_config *cfg,
|
||||
union s3c_iobank *iob);
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ_S3C24XX_DEBUGFS
|
||||
#define s3c_cpufreq_debugfs_call(x) x
|
||||
#else
|
||||
#define s3c_cpufreq_debugfs_call(x) NULL
|
||||
#endif
|
||||
|
||||
/* Useful utility functions. */
|
||||
|
||||
extern struct clk *s3c_cpufreq_clk_get(struct device *, const char *);
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <mach/map.h>
|
||||
|
@ -303,6 +304,50 @@ void s3c2410_iotiming_getbank(struct s3c_cpufreq_config *cfg,
|
|||
bt->tacc = get_tacc(hclk, bankcon >> S3C2410_BANKCON_Tacc_SHIFT);
|
||||
}
|
||||
|
||||
/**
|
||||
* s3c2410_iotiming_debugfs - debugfs show io bank timing information
|
||||
* @seq: The seq_file to write output to using seq_printf().
|
||||
* @cfg: The current configuration.
|
||||
* @iob: The IO bank information to decode.
|
||||
*/
|
||||
void s3c2410_iotiming_debugfs(struct seq_file *seq,
|
||||
struct s3c_cpufreq_config *cfg,
|
||||
union s3c_iobank *iob)
|
||||
{
|
||||
struct s3c2410_iobank_timing *bt = iob->io_2410;
|
||||
unsigned long bankcon = bt->bankcon;
|
||||
unsigned long hclk = cfg->freq.hclk_tns;
|
||||
unsigned int tacs;
|
||||
unsigned int tcos;
|
||||
unsigned int tacc;
|
||||
unsigned int tcoh;
|
||||
unsigned int tcah;
|
||||
|
||||
seq_printf(seq, "BANKCON=0x%08lx\n", bankcon);
|
||||
|
||||
tcah = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tcah_SHIFT);
|
||||
tcoh = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tcoh_SHIFT);
|
||||
tcos = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tcos_SHIFT);
|
||||
tacs = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tacs_SHIFT);
|
||||
tacc = get_tacc(hclk, bankcon >> S3C2410_BANKCON_Tacc_SHIFT);
|
||||
|
||||
seq_printf(seq,
|
||||
"\tRead: Tacs=%d.%d, Tcos=%d.%d, Tacc=%d.%d, Tcoh=%d.%d, Tcah=%d.%d\n",
|
||||
print_ns(bt->tacs),
|
||||
print_ns(bt->tcos),
|
||||
print_ns(bt->tacc),
|
||||
print_ns(bt->tcoh),
|
||||
print_ns(bt->tcah));
|
||||
|
||||
seq_printf(seq,
|
||||
"\t Set: Tacs=%d.%d, Tcos=%d.%d, Tacc=%d.%d, Tcoh=%d.%d, Tcah=%d.%d\n",
|
||||
print_ns(tacs),
|
||||
print_ns(tcos),
|
||||
print_ns(tacc),
|
||||
print_ns(tcoh),
|
||||
print_ns(tcah));
|
||||
}
|
||||
|
||||
/**
|
||||
* s3c2410_iotiming_calc - Calculate bank timing for frequency change.
|
||||
* @cfg: The frequency configuration
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/sysdev.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/clk.h>
|
||||
|
@ -108,6 +109,29 @@ static int s3c2412_calc_bank(struct s3c_cpufreq_config *cfg,
|
|||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* s3c2412_iotiming_debugfs - debugfs show io bank timing information
|
||||
* @seq: The seq_file to write output to using seq_printf().
|
||||
* @cfg: The current configuration.
|
||||
* @iob: The IO bank information to decode.
|
||||
*/
|
||||
void s3c2412_iotiming_debugfs(struct seq_file *seq,
|
||||
struct s3c_cpufreq_config *cfg,
|
||||
union s3c_iobank *iob)
|
||||
{
|
||||
struct s3c2412_iobank_timing *bt = iob->io_2412;
|
||||
|
||||
seq_printf(seq,
|
||||
"\tRead: idcy=%d.%d wstrd=%d.%d wstwr=%d,%d"
|
||||
"wstoen=%d.%d wstwen=%d.%d wstbrd=%d.%d\n",
|
||||
print_ns(bt->idcy),
|
||||
print_ns(bt->wstrd),
|
||||
print_ns(bt->wstwr),
|
||||
print_ns(bt->wstoen),
|
||||
print_ns(bt->wstwen),
|
||||
print_ns(bt->wstbrd));
|
||||
}
|
||||
|
||||
/**
|
||||
* s3c2412_iotiming_calc - calculate all the bank divisor settings.
|
||||
* @cfg: The current frequency configuration.
|
||||
|
|
|
@ -266,6 +266,8 @@ struct s3c_cpufreq_info s3c2440_cpufreq_info = {
|
|||
.calc_freqtable = s3c2440_cpufreq_calctable,
|
||||
|
||||
.resume_clocks = s3c244x_setup_clocks,
|
||||
|
||||
.debug_io_show = s3c_cpufreq_debugfs_call(s3c2410_iotiming_debugfs),
|
||||
};
|
||||
|
||||
static int s3c2440_cpufreq_add(struct sys_device *sysdev)
|
||||
|
|
Loading…
Reference in a new issue