forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-05-10 cde9070d9970eef1f7ec2360586c802a16230ad8
kernel/arch/powerpc/platforms/powernv/opal-xscom.c
....@@ -1,12 +1,11 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
2
- * PowerNV LPC bus handling.
3
+ * PowerNV SCOM bus debugfs interface
34 *
5
+ * Copyright 2010 Benjamin Herrenschmidt, IBM Corp
6
+ * <benh@kernel.crashing.org>
7
+ * and David Gibson, IBM Corporation.
48 * Copyright 2013 IBM Corp.
5
- *
6
- * This program is free software; you can redistribute it and/or
7
- * modify it under the terms of the GNU General Public License
8
- * as published by the Free Software Foundation; either version
9
- * 2 of the License, or (at your option) any later version.
109 */
1110
1211 #include <linux/kernel.h>
....@@ -14,62 +13,13 @@
1413 #include <linux/bug.h>
1514 #include <linux/gfp.h>
1615 #include <linux/slab.h>
16
+#include <linux/uaccess.h>
1717
1818 #include <asm/machdep.h>
1919 #include <asm/firmware.h>
2020 #include <asm/opal.h>
21
-#include <asm/scom.h>
22
-
23
-/*
24
- * We could probably fit that inside the scom_map_t
25
- * which is a void* after all but it's really too ugly
26
- * so let's kmalloc it for now
27
- */
28
-struct opal_scom_map {
29
- uint32_t chip;
30
- uint64_t addr;
31
-};
32
-
33
-static scom_map_t opal_scom_map(struct device_node *dev, u64 reg, u64 count)
34
-{
35
- struct opal_scom_map *m;
36
- const __be32 *gcid;
37
-
38
- if (!of_get_property(dev, "scom-controller", NULL)) {
39
- pr_err("%s: device %pOF is not a SCOM controller\n",
40
- __func__, dev);
41
- return SCOM_MAP_INVALID;
42
- }
43
- gcid = of_get_property(dev, "ibm,chip-id", NULL);
44
- if (!gcid) {
45
- pr_err("%s: device %pOF has no ibm,chip-id\n",
46
- __func__, dev);
47
- return SCOM_MAP_INVALID;
48
- }
49
- m = kmalloc(sizeof(*m), GFP_KERNEL);
50
- if (!m)
51
- return NULL;
52
- m->chip = be32_to_cpup(gcid);
53
- m->addr = reg;
54
-
55
- return (scom_map_t)m;
56
-}
57
-
58
-static void opal_scom_unmap(scom_map_t map)
59
-{
60
- kfree(map);
61
-}
62
-
63
-static int opal_xscom_err_xlate(int64_t rc)
64
-{
65
- switch(rc) {
66
- case 0:
67
- return 0;
68
- /* Add more translations if necessary */
69
- default:
70
- return -EIO;
71
- }
72
-}
21
+#include <asm/debugfs.h>
22
+#include <asm/prom.h>
7323
7424 static u64 opal_scom_unmangle(u64 addr)
7525 {
....@@ -102,39 +52,154 @@
10252 return addr;
10353 }
10454
105
-static int opal_scom_read(scom_map_t map, u64 reg, u64 *value)
55
+static int opal_scom_read(uint32_t chip, uint64_t addr, u64 reg, u64 *value)
10656 {
107
- struct opal_scom_map *m = map;
10857 int64_t rc;
10958 __be64 v;
11059
111
- reg = opal_scom_unmangle(m->addr + reg);
112
- rc = opal_xscom_read(m->chip, reg, (__be64 *)__pa(&v));
60
+ reg = opal_scom_unmangle(addr + reg);
61
+ rc = opal_xscom_read(chip, reg, (__be64 *)__pa(&v));
62
+ if (rc) {
63
+ *value = 0xfffffffffffffffful;
64
+ return -EIO;
65
+ }
11366 *value = be64_to_cpu(v);
114
- return opal_xscom_err_xlate(rc);
115
-}
116
-
117
-static int opal_scom_write(scom_map_t map, u64 reg, u64 value)
118
-{
119
- struct opal_scom_map *m = map;
120
- int64_t rc;
121
-
122
- reg = opal_scom_unmangle(m->addr + reg);
123
- rc = opal_xscom_write(m->chip, reg, value);
124
- return opal_xscom_err_xlate(rc);
125
-}
126
-
127
-static const struct scom_controller opal_scom_controller = {
128
- .map = opal_scom_map,
129
- .unmap = opal_scom_unmap,
130
- .read = opal_scom_read,
131
- .write = opal_scom_write
132
-};
133
-
134
-static int opal_xscom_init(void)
135
-{
136
- if (firmware_has_feature(FW_FEATURE_OPAL))
137
- scom_init(&opal_scom_controller);
13867 return 0;
13968 }
140
-machine_arch_initcall(powernv, opal_xscom_init);
69
+
70
+static int opal_scom_write(uint32_t chip, uint64_t addr, u64 reg, u64 value)
71
+{
72
+ int64_t rc;
73
+
74
+ reg = opal_scom_unmangle(addr + reg);
75
+ rc = opal_xscom_write(chip, reg, value);
76
+ if (rc)
77
+ return -EIO;
78
+ return 0;
79
+}
80
+
81
+struct scom_debug_entry {
82
+ u32 chip;
83
+ struct debugfs_blob_wrapper path;
84
+ char name[16];
85
+};
86
+
87
+static ssize_t scom_debug_read(struct file *filp, char __user *ubuf,
88
+ size_t count, loff_t *ppos)
89
+{
90
+ struct scom_debug_entry *ent = filp->private_data;
91
+ u64 __user *ubuf64 = (u64 __user *)ubuf;
92
+ loff_t off = *ppos;
93
+ ssize_t done = 0;
94
+ u64 reg, reg_base, reg_cnt, val;
95
+ int rc;
96
+
97
+ if (off < 0 || (off & 7) || (count & 7))
98
+ return -EINVAL;
99
+ reg_base = off >> 3;
100
+ reg_cnt = count >> 3;
101
+
102
+ for (reg = 0; reg < reg_cnt; reg++) {
103
+ rc = opal_scom_read(ent->chip, reg_base, reg, &val);
104
+ if (!rc)
105
+ rc = put_user(val, ubuf64);
106
+ if (rc) {
107
+ if (!done)
108
+ done = rc;
109
+ break;
110
+ }
111
+ ubuf64++;
112
+ *ppos += 8;
113
+ done += 8;
114
+ }
115
+ return done;
116
+}
117
+
118
+static ssize_t scom_debug_write(struct file *filp, const char __user *ubuf,
119
+ size_t count, loff_t *ppos)
120
+{
121
+ struct scom_debug_entry *ent = filp->private_data;
122
+ u64 __user *ubuf64 = (u64 __user *)ubuf;
123
+ loff_t off = *ppos;
124
+ ssize_t done = 0;
125
+ u64 reg, reg_base, reg_cnt, val;
126
+ int rc;
127
+
128
+ if (off < 0 || (off & 7) || (count & 7))
129
+ return -EINVAL;
130
+ reg_base = off >> 3;
131
+ reg_cnt = count >> 3;
132
+
133
+ for (reg = 0; reg < reg_cnt; reg++) {
134
+ rc = get_user(val, ubuf64);
135
+ if (!rc)
136
+ rc = opal_scom_write(ent->chip, reg_base, reg, val);
137
+ if (rc) {
138
+ if (!done)
139
+ done = rc;
140
+ break;
141
+ }
142
+ ubuf64++;
143
+ done += 8;
144
+ }
145
+ return done;
146
+}
147
+
148
+static const struct file_operations scom_debug_fops = {
149
+ .read = scom_debug_read,
150
+ .write = scom_debug_write,
151
+ .open = simple_open,
152
+ .llseek = default_llseek,
153
+};
154
+
155
+static int scom_debug_init_one(struct dentry *root, struct device_node *dn,
156
+ int chip)
157
+{
158
+ struct scom_debug_entry *ent;
159
+ struct dentry *dir;
160
+
161
+ ent = kzalloc(sizeof(*ent), GFP_KERNEL);
162
+ if (!ent)
163
+ return -ENOMEM;
164
+
165
+ ent->chip = chip;
166
+ snprintf(ent->name, 16, "%08x", chip);
167
+ ent->path.data = (void *)kasprintf(GFP_KERNEL, "%pOF", dn);
168
+ ent->path.size = strlen((char *)ent->path.data);
169
+
170
+ dir = debugfs_create_dir(ent->name, root);
171
+ if (!dir) {
172
+ kfree(ent->path.data);
173
+ kfree(ent);
174
+ return -1;
175
+ }
176
+
177
+ debugfs_create_blob("devspec", 0400, dir, &ent->path);
178
+ debugfs_create_file("access", 0600, dir, ent, &scom_debug_fops);
179
+
180
+ return 0;
181
+}
182
+
183
+static int scom_debug_init(void)
184
+{
185
+ struct device_node *dn;
186
+ struct dentry *root;
187
+ int chip, rc;
188
+
189
+ if (!firmware_has_feature(FW_FEATURE_OPAL))
190
+ return 0;
191
+
192
+ root = debugfs_create_dir("scom", powerpc_debugfs_root);
193
+ if (!root)
194
+ return -1;
195
+
196
+ rc = 0;
197
+ for_each_node_with_property(dn, "scom-controller") {
198
+ chip = of_get_ibm_chip_id(dn);
199
+ WARN_ON(chip == -1);
200
+ rc |= scom_debug_init_one(root, dn, chip);
201
+ }
202
+
203
+ return rc;
204
+}
205
+device_initcall(scom_debug_init);