109ec1d7ea67f6e23b6ef2178fa2ec48fd65477dcKukjin Kim/* 2e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks * Copyright (c) 2009 Simtec Electronics 3e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks * http://armlinux.simtec.co.uk/ 4e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks * Ben Dooks <ben@simtec.co.uk> 5e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks * 6e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks * S3C24XX CPU Frequency scaling - debugfs status support 7e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks * 8e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks * This program is free software; you can redistribute it and/or modify 9e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks * it under the terms of the GNU General Public License version 2 as 10e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks * published by the Free Software Foundation. 11e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks*/ 12e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks 13e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks#include <linux/init.h> 14a69e4c28b2bddc21b5752b1da8f43ab0a817305cKukjin Kim#include <linux/export.h> 15e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks#include <linux/interrupt.h> 16e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks#include <linux/ioport.h> 17e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks#include <linux/cpufreq.h> 18e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks#include <linux/debugfs.h> 19e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks#include <linux/seq_file.h> 20e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks#include <linux/err.h> 21e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks 22e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks#include <plat/cpu-freq-core.h> 23e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks 24e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooksstatic struct dentry *dbgfs_root; 25e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooksstatic struct dentry *dbgfs_file_io; 26e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooksstatic struct dentry *dbgfs_file_info; 27e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooksstatic struct dentry *dbgfs_file_board; 28e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks 29e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks#define print_ns(x) ((x) / 10), ((x) % 10) 30e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks 31e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooksstatic void show_max(struct seq_file *seq, struct s3c_freq *f) 32e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks{ 33e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks seq_printf(seq, "MAX: F=%lu, H=%lu, P=%lu, A=%lu\n", 34e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks f->fclk, f->hclk, f->pclk, f->armclk); 35e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks} 36e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks 37e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooksstatic int board_show(struct seq_file *seq, void *p) 38e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks{ 39e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks struct s3c_cpufreq_config *cfg; 40e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks struct s3c_cpufreq_board *brd; 41e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks 42e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks cfg = s3c_cpufreq_getconfig(); 43e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks if (!cfg) { 44e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks seq_printf(seq, "no configuration registered\n"); 45e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks return 0; 46e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks } 47e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks 48e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks brd = cfg->board; 49e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks if (!brd) { 50e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks seq_printf(seq, "no board definition set?\n"); 51e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks return 0; 52e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks } 53e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks 54e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks seq_printf(seq, "SDRAM refresh %u ns\n", brd->refresh); 55e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks seq_printf(seq, "auto_io=%u\n", brd->auto_io); 56e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks seq_printf(seq, "need_io=%u\n", brd->need_io); 57e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks 58e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks show_max(seq, &brd->max); 59e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks 60e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks 61e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks return 0; 62e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks} 63e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks 64e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooksstatic int fops_board_open(struct inode *inode, struct file *file) 65e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks{ 66e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks return single_open(file, board_show, NULL); 67e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks} 68e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks 69e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooksstatic const struct file_operations fops_board = { 70e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks .open = fops_board_open, 71e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks .read = seq_read, 72e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks .llseek = seq_lseek, 73e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks .release = single_release, 74e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks .owner = THIS_MODULE, 75e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks}; 76e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks 77e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooksstatic int info_show(struct seq_file *seq, void *p) 78e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks{ 79e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks struct s3c_cpufreq_config *cfg; 80e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks 81e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks cfg = s3c_cpufreq_getconfig(); 82e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks if (!cfg) { 83e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks seq_printf(seq, "no configuration registered\n"); 84e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks return 0; 85e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks } 86e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks 87e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks seq_printf(seq, " FCLK %ld Hz\n", cfg->freq.fclk); 88e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks seq_printf(seq, " HCLK %ld Hz (%lu.%lu ns)\n", 89e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks cfg->freq.hclk, print_ns(cfg->freq.hclk_tns)); 90e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks seq_printf(seq, " PCLK %ld Hz\n", cfg->freq.hclk); 91e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks seq_printf(seq, "ARMCLK %ld Hz\n", cfg->freq.armclk); 92e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks seq_printf(seq, "\n"); 93e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks 94e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks show_max(seq, &cfg->max); 95e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks 96e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks seq_printf(seq, "Divisors: P=%d, H=%d, A=%d, dvs=%s\n", 97e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks cfg->divs.h_divisor, cfg->divs.p_divisor, 98e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks cfg->divs.arm_divisor, cfg->divs.dvs ? "on" : "off"); 99e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks seq_printf(seq, "\n"); 100e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks 101e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks seq_printf(seq, "lock_pll=%u\n", cfg->lock_pll); 102e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks 103e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks return 0; 104e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks} 105e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks 106e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooksstatic int fops_info_open(struct inode *inode, struct file *file) 107e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks{ 108e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks return single_open(file, info_show, NULL); 109e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks} 110e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks 111e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooksstatic const struct file_operations fops_info = { 112e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks .open = fops_info_open, 113e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks .read = seq_read, 114e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks .llseek = seq_lseek, 115e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks .release = single_release, 116e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks .owner = THIS_MODULE, 117e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks}; 118e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks 119e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooksstatic int io_show(struct seq_file *seq, void *p) 120e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks{ 121e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks void (*show_bank)(struct seq_file *, struct s3c_cpufreq_config *, union s3c_iobank *); 122e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks struct s3c_cpufreq_config *cfg; 123e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks struct s3c_iotimings *iot; 124e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks union s3c_iobank *iob; 125e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks int bank; 126e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks 127e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks cfg = s3c_cpufreq_getconfig(); 128e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks if (!cfg) { 129e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks seq_printf(seq, "no configuration registered\n"); 130e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks return 0; 131e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks } 132e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks 133e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks show_bank = cfg->info->debug_io_show; 134e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks if (!show_bank) { 135e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks seq_printf(seq, "no code to show bank timing\n"); 136e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks return 0; 137e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks } 138e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks 139e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks iot = s3c_cpufreq_getiotimings(); 140e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks if (!iot) { 141e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks seq_printf(seq, "no io timings registered\n"); 142e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks return 0; 143e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks } 144e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks 145e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks seq_printf(seq, "hclk period is %lu.%lu ns\n", print_ns(cfg->freq.hclk_tns)); 146e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks 147e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks for (bank = 0; bank < MAX_BANKS; bank++) { 148e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks iob = &iot->bank[bank]; 149e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks 150e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks seq_printf(seq, "bank %d: ", bank); 151e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks 152e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks if (!iob->io_2410) { 153e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks seq_printf(seq, "nothing set\n"); 154e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks continue; 155e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks } 156e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks 157e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks show_bank(seq, cfg, iob); 158e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks } 159e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks 160e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks return 0; 161e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks} 162e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks 163e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooksstatic int fops_io_open(struct inode *inode, struct file *file) 164e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks{ 165e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks return single_open(file, io_show, NULL); 166e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks} 167e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks 168e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooksstatic const struct file_operations fops_io = { 169e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks .open = fops_io_open, 170e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks .read = seq_read, 171e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks .llseek = seq_lseek, 172e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks .release = single_release, 173e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks .owner = THIS_MODULE, 174e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks}; 175e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks 176e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks 177e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooksstatic int __init s3c_freq_debugfs_init(void) 178e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks{ 179e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks dbgfs_root = debugfs_create_dir("s3c-cpufreq", NULL); 180e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks if (IS_ERR(dbgfs_root)) { 181e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks printk(KERN_ERR "%s: error creating debugfs root\n", __func__); 182e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks return PTR_ERR(dbgfs_root); 183e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks } 184e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks 185e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks dbgfs_file_io = debugfs_create_file("io-timing", S_IRUGO, dbgfs_root, 186e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks NULL, &fops_io); 187e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks 188e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks dbgfs_file_info = debugfs_create_file("info", S_IRUGO, dbgfs_root, 189e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks NULL, &fops_info); 190e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks 191e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks dbgfs_file_board = debugfs_create_file("board", S_IRUGO, dbgfs_root, 192e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks NULL, &fops_board); 193e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks 194e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks return 0; 195e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks} 196e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks 197e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dookslate_initcall(s3c_freq_debugfs_init); 198e6d197a6954c8a9ff85727c31ca61fc1da78628aBen Dooks 199