129f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill/*
229f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill * This file is subject to the terms and conditions of the GNU General Public
329f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill * License.  See the file "COPYING" in the main directory of this archive
429f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill * for more details.
529f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill *
629f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill * Copyright (C) 2013 Imagination Technologies Ltd.
729f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill */
829f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill
929f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill#include <linux/kernel.h>
1029f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill#include <linux/debugfs.h>
1129f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill#include <linux/seq_file.h>
1229f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill#include <asm/cpu.h>
1329f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill#include <asm/mipsregs.h>
1429f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill
1529f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hillstatic void build_segment_config(char *str, unsigned int cfg)
1629f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill{
1729f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	unsigned int am;
1829f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	static const char * const am_str[] = {
1929f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill		"UK", "MK", "MSK", "MUSK", "MUSUK", "USK",
2029f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill		"RSRVD", "UUSK"};
2129f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill
2229f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	/* Segment access mode. */
2329f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	am = (cfg & MIPS_SEGCFG_AM) >> MIPS_SEGCFG_AM_SHIFT;
2429f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	str += sprintf(str, "%-5s", am_str[am]);
2529f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill
2629f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	/*
2729f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	 * Access modes MK, MSK and MUSK are mapped segments. Therefore
2829f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	 * there is no direct physical address mapping.
2929f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	 */
3029f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	if ((am == 0) || (am > 3)) {
3129f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill		str += sprintf(str, "         %03lx",
3229f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill			((cfg & MIPS_SEGCFG_PA) >> MIPS_SEGCFG_PA_SHIFT));
3329f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill		str += sprintf(str, "         %01ld",
3429f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill			((cfg & MIPS_SEGCFG_C) >> MIPS_SEGCFG_C_SHIFT));
3529f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	} else {
3629f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill		str += sprintf(str, "         UND");
3729f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill		str += sprintf(str, "         U");
3829f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	}
3929f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill
4029f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	/* Exception configuration. */
4129f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	str += sprintf(str, "       %01ld\n",
4229f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill		((cfg & MIPS_SEGCFG_EU) >> MIPS_SEGCFG_EU_SHIFT));
4329f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill}
4429f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill
4529f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hillstatic int show_segments(struct seq_file *m, void *v)
4629f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill{
4729f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	unsigned int segcfg;
4829f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	char str[42];
4929f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill
5029f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	seq_puts(m, "Segment   Virtual    Size   Access Mode   Physical   Caching   EU\n");
5129f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	seq_puts(m, "-------   -------    ----   -----------   --------   -------   --\n");
5229f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill
5329f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	segcfg = read_c0_segctl0();
5429f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	build_segment_config(str, segcfg);
5529f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	seq_printf(m, "   0      e0000000   512M      %s", str);
5629f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill
5729f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	segcfg >>= 16;
5829f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	build_segment_config(str, segcfg);
5929f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	seq_printf(m, "   1      c0000000   512M      %s", str);
6029f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill
6129f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	segcfg = read_c0_segctl1();
6229f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	build_segment_config(str, segcfg);
6329f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	seq_printf(m, "   2      a0000000   512M      %s", str);
6429f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill
6529f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	segcfg >>= 16;
6629f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	build_segment_config(str, segcfg);
6729f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	seq_printf(m, "   3      80000000   512M      %s", str);
6829f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill
6929f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	segcfg = read_c0_segctl2();
7029f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	build_segment_config(str, segcfg);
7129f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	seq_printf(m, "   4      40000000    1G       %s", str);
7229f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill
7329f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	segcfg >>= 16;
7429f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	build_segment_config(str, segcfg);
7529f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	seq_printf(m, "   5      00000000    1G       %s\n", str);
7629f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill
7729f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	return 0;
7829f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill}
7929f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill
8029f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hillstatic int segments_open(struct inode *inode, struct file *file)
8129f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill{
8229f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	return single_open(file, show_segments, NULL);
8329f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill}
8429f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill
8529f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hillstatic const struct file_operations segments_fops = {
8629f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	.open		= segments_open,
8729f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	.read		= seq_read,
8829f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	.llseek		= seq_lseek,
8929f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	.release	= single_release,
9029f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill};
9129f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill
9229f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hillstatic int __init segments_info(void)
9329f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill{
9429f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	extern struct dentry *mips_debugfs_dir;
9529f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	struct dentry *segments;
9629f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill
9729f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	if (cpu_has_segments) {
9829f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill		if (!mips_debugfs_dir)
9929f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill			return -ENODEV;
10029f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill
10129f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill		segments = debugfs_create_file("segments", S_IRUGO,
10229f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill					       mips_debugfs_dir, NULL,
10329f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill					       &segments_fops);
10429f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill		if (!segments)
10529f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill			return -ENOMEM;
10629f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	}
10729f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill	return 0;
10829f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill}
10929f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hill
11029f9087c52d19067a1eccfd5c0a4a0045cf3ea04Steven J. Hilldevice_initcall(segments_info);
111