Skip to content

Commit

Permalink
ARM: S3C: CPUFREQ: Add debugfs support for cpufreq
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Ben Dooks authored and Ben Dooks committed Jul 30, 2009
1 parent dfff4e9 commit e6d197a
Show file tree
Hide file tree
Showing 10 changed files with 317 additions and 0 deletions.
6 changes: 6 additions & 0 deletions arch/arm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
2 changes: 2 additions & 0 deletions arch/arm/mach-s3c2410/cpu-freq.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions arch/arm/mach-s3c2412/cpu-freq.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions arch/arm/plat-s3c24xx/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
199 changes: 199 additions & 0 deletions arch/arm/plat-s3c24xx/cpu-freq-debugfs.c
Original file line number Diff line number Diff line change
@@ -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);

12 changes: 12 additions & 0 deletions arch/arm/plat-s3c24xx/cpu-freq.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
24 changes: 24 additions & 0 deletions arch/arm/plat-s3c24xx/include/plat/cpu-freq-core.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

#include <plat/cpu-freq.h>

struct seq_file;

#define MAX_BANKS (8)
#define S3C2412_MAX_IO (8)

Expand Down Expand Up @@ -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);
Expand All @@ -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 *);
Expand Down
45 changes: 45 additions & 0 deletions arch/arm/plat-s3c24xx/s3c2410-iotiming.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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
Expand Down
24 changes: 24 additions & 0 deletions arch/arm/plat-s3c24xx/s3c2412-iotiming.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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.
Expand Down
Loading

0 comments on commit e6d197a

Please sign in to comment.