Commit | Line | Data |
---|---|---|
96f60e37 RK |
1 | /* |
2 | * Copyright (C) 2012 Russell King | |
3 | * Rewritten from the dovefb driver, and Armada510 manuals. | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License version 2 as | |
7 | * published by the Free Software Foundation. | |
8 | */ | |
9 | #include <linux/ctype.h> | |
10 | #include <linux/debugfs.h> | |
11 | #include <linux/module.h> | |
12 | #include <linux/seq_file.h> | |
13 | #include <drm/drmP.h> | |
14 | #include "armada_crtc.h" | |
15 | #include "armada_drm.h" | |
16 | ||
17 | static int armada_debugfs_gem_linear_show(struct seq_file *m, void *data) | |
18 | { | |
19 | struct drm_info_node *node = m->private; | |
20 | struct drm_device *dev = node->minor->dev; | |
21 | struct armada_private *priv = dev->dev_private; | |
22 | int ret; | |
23 | ||
0b8ebeac | 24 | mutex_lock(&priv->linear_lock); |
96f60e37 | 25 | ret = drm_mm_dump_table(m, &priv->linear); |
0b8ebeac | 26 | mutex_unlock(&priv->linear_lock); |
96f60e37 RK |
27 | |
28 | return ret; | |
29 | } | |
30 | ||
31 | static int armada_debugfs_reg_show(struct seq_file *m, void *data) | |
32 | { | |
33 | struct drm_device *dev = m->private; | |
34 | struct armada_private *priv = dev->dev_private; | |
35 | int n, i; | |
36 | ||
37 | if (priv) { | |
38 | for (n = 0; n < ARRAY_SIZE(priv->dcrtc); n++) { | |
39 | struct armada_crtc *dcrtc = priv->dcrtc[n]; | |
40 | if (!dcrtc) | |
41 | continue; | |
42 | ||
43 | for (i = 0x84; i <= 0x1c4; i += 4) { | |
44 | uint32_t v = readl_relaxed(dcrtc->base + i); | |
45 | seq_printf(m, "%u: 0x%04x: 0x%08x\n", n, i, v); | |
46 | } | |
47 | } | |
48 | } | |
49 | ||
50 | return 0; | |
51 | } | |
52 | ||
53 | static int armada_debugfs_reg_r_open(struct inode *inode, struct file *file) | |
54 | { | |
55 | return single_open(file, armada_debugfs_reg_show, inode->i_private); | |
56 | } | |
57 | ||
58 | static const struct file_operations fops_reg_r = { | |
59 | .owner = THIS_MODULE, | |
60 | .open = armada_debugfs_reg_r_open, | |
61 | .read = seq_read, | |
62 | .llseek = seq_lseek, | |
63 | .release = single_release, | |
64 | }; | |
65 | ||
66 | static int armada_debugfs_write(struct file *file, const char __user *ptr, | |
67 | size_t len, loff_t *off) | |
68 | { | |
69 | struct drm_device *dev = file->private_data; | |
70 | struct armada_private *priv = dev->dev_private; | |
71 | struct armada_crtc *dcrtc = priv->dcrtc[0]; | |
72 | char buf[32], *p; | |
73 | uint32_t reg, val; | |
74 | int ret; | |
75 | ||
76 | if (*off != 0) | |
77 | return 0; | |
78 | ||
79 | if (len > sizeof(buf) - 1) | |
80 | len = sizeof(buf) - 1; | |
81 | ||
82 | ret = strncpy_from_user(buf, ptr, len); | |
83 | if (ret < 0) | |
84 | return ret; | |
85 | buf[len] = '\0'; | |
86 | ||
87 | reg = simple_strtoul(buf, &p, 16); | |
88 | if (!isspace(*p)) | |
89 | return -EINVAL; | |
90 | val = simple_strtoul(p + 1, NULL, 16); | |
91 | ||
92 | if (reg >= 0x84 && reg <= 0x1c4) | |
93 | writel(val, dcrtc->base + reg); | |
94 | ||
95 | return len; | |
96 | } | |
97 | ||
96f60e37 RK |
98 | static const struct file_operations fops_reg_w = { |
99 | .owner = THIS_MODULE, | |
a276d6ce | 100 | .open = simple_open, |
96f60e37 RK |
101 | .write = armada_debugfs_write, |
102 | .llseek = noop_llseek, | |
103 | }; | |
104 | ||
105 | static struct drm_info_list armada_debugfs_list[] = { | |
106 | { "gem_linear", armada_debugfs_gem_linear_show, 0 }, | |
107 | }; | |
108 | #define ARMADA_DEBUGFS_ENTRIES ARRAY_SIZE(armada_debugfs_list) | |
109 | ||
110 | static int drm_add_fake_info_node(struct drm_minor *minor, struct dentry *ent, | |
111 | const void *key) | |
112 | { | |
113 | struct drm_info_node *node; | |
114 | ||
115 | node = kmalloc(sizeof(struct drm_info_node), GFP_KERNEL); | |
e8e11817 | 116 | if (!node) { |
96f60e37 RK |
117 | debugfs_remove(ent); |
118 | return -ENOMEM; | |
119 | } | |
120 | ||
121 | node->minor = minor; | |
122 | node->dent = ent; | |
123 | node->info_ent = (void *) key; | |
124 | ||
125 | mutex_lock(&minor->debugfs_lock); | |
126 | list_add(&node->list, &minor->debugfs_list); | |
127 | mutex_unlock(&minor->debugfs_lock); | |
128 | ||
129 | return 0; | |
130 | } | |
131 | ||
132 | static int armada_debugfs_create(struct dentry *root, struct drm_minor *minor, | |
133 | const char *name, umode_t mode, const struct file_operations *fops) | |
134 | { | |
135 | struct dentry *de; | |
136 | ||
137 | de = debugfs_create_file(name, mode, root, minor->dev, fops); | |
138 | ||
139 | return drm_add_fake_info_node(minor, de, fops); | |
140 | } | |
141 | ||
142 | int armada_drm_debugfs_init(struct drm_minor *minor) | |
143 | { | |
144 | int ret; | |
145 | ||
146 | ret = drm_debugfs_create_files(armada_debugfs_list, | |
147 | ARMADA_DEBUGFS_ENTRIES, | |
148 | minor->debugfs_root, minor); | |
149 | if (ret) | |
150 | return ret; | |
151 | ||
152 | ret = armada_debugfs_create(minor->debugfs_root, minor, | |
153 | "reg", S_IFREG | S_IRUSR, &fops_reg_r); | |
154 | if (ret) | |
155 | goto err_1; | |
156 | ||
157 | ret = armada_debugfs_create(minor->debugfs_root, minor, | |
158 | "reg_wr", S_IFREG | S_IWUSR, &fops_reg_w); | |
159 | if (ret) | |
160 | goto err_2; | |
161 | return ret; | |
162 | ||
163 | err_2: | |
164 | drm_debugfs_remove_files((struct drm_info_list *)&fops_reg_r, 1, minor); | |
165 | err_1: | |
166 | drm_debugfs_remove_files(armada_debugfs_list, ARMADA_DEBUGFS_ENTRIES, | |
167 | minor); | |
168 | return ret; | |
169 | } | |
170 | ||
171 | void armada_drm_debugfs_cleanup(struct drm_minor *minor) | |
172 | { | |
173 | drm_debugfs_remove_files((struct drm_info_list *)&fops_reg_w, 1, minor); | |
174 | drm_debugfs_remove_files((struct drm_info_list *)&fops_reg_r, 1, minor); | |
175 | drm_debugfs_remove_files(armada_debugfs_list, ARMADA_DEBUGFS_ENTRIES, | |
176 | minor); | |
177 | } |