]> Git Repo - linux.git/blob - drivers/memory/bt1-l2-ctl.c
nfsd4: a client's own opens needn't prevent delegations
[linux.git] / drivers / memory / bt1-l2-ctl.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2020 BAIKAL ELECTRONICS, JSC
4  *
5  * Authors:
6  *   Serge Semin <[email protected]>
7  *
8  * Baikal-T1 CM2 L2-cache Control Block driver.
9  */
10
11 #include <linux/kernel.h>
12 #include <linux/module.h>
13 #include <linux/bitfield.h>
14 #include <linux/types.h>
15 #include <linux/device.h>
16 #include <linux/platform_device.h>
17 #include <linux/regmap.h>
18 #include <linux/mfd/syscon.h>
19 #include <linux/sysfs.h>
20 #include <linux/of.h>
21
22 #define L2_CTL_REG                      0x028
23 #define L2_CTL_DATA_STALL_FLD           0
24 #define L2_CTL_DATA_STALL_MASK          GENMASK(1, L2_CTL_DATA_STALL_FLD)
25 #define L2_CTL_TAG_STALL_FLD            2
26 #define L2_CTL_TAG_STALL_MASK           GENMASK(3, L2_CTL_TAG_STALL_FLD)
27 #define L2_CTL_WS_STALL_FLD             4
28 #define L2_CTL_WS_STALL_MASK            GENMASK(5, L2_CTL_WS_STALL_FLD)
29 #define L2_CTL_SET_CLKRATIO             BIT(13)
30 #define L2_CTL_CLKRATIO_LOCK            BIT(31)
31
32 #define L2_CTL_STALL_MIN                0
33 #define L2_CTL_STALL_MAX                3
34 #define L2_CTL_STALL_SET_DELAY_US       1
35 #define L2_CTL_STALL_SET_TOUT_US        1000
36
37 /*
38  * struct l2_ctl - Baikal-T1 L2 Control block private data.
39  * @dev: Pointer to the device structure.
40  * @sys_regs: Baikal-T1 System Controller registers map.
41  */
42 struct l2_ctl {
43         struct device *dev;
44
45         struct regmap *sys_regs;
46 };
47
48 /*
49  * enum l2_ctl_stall - Baikal-T1 L2-cache-RAM stall identifier.
50  * @L2_WSSTALL: Way-select latency.
51  * @L2_TAGSTALL: Tag latency.
52  * @L2_DATASTALL: Data latency.
53  */
54 enum l2_ctl_stall {
55         L2_WS_STALL,
56         L2_TAG_STALL,
57         L2_DATA_STALL
58 };
59
60 /*
61  * struct l2_ctl_device_attribute - Baikal-T1 L2-cache device attribute.
62  * @dev_attr: Actual sysfs device attribute.
63  * @id: L2-cache stall field identifier.
64  */
65 struct l2_ctl_device_attribute {
66         struct device_attribute dev_attr;
67         enum l2_ctl_stall id;
68 };
69 #define to_l2_ctl_dev_attr(_dev_attr) \
70         container_of(_dev_attr, struct l2_ctl_device_attribute, dev_attr)
71
72 #define L2_CTL_ATTR_RW(_name, _prefix, _id) \
73         struct l2_ctl_device_attribute l2_ctl_attr_##_name = \
74                 { __ATTR(_name, 0644, _prefix##_show, _prefix##_store), _id }
75
76 static int l2_ctl_get_latency(struct l2_ctl *l2, enum l2_ctl_stall id, u32 *val)
77 {
78         u32 data = 0;
79         int ret;
80
81         ret = regmap_read(l2->sys_regs, L2_CTL_REG, &data);
82         if (ret)
83                 return ret;
84
85         switch (id) {
86         case L2_WS_STALL:
87                 *val = FIELD_GET(L2_CTL_WS_STALL_MASK, data);
88                 break;
89         case L2_TAG_STALL:
90                 *val = FIELD_GET(L2_CTL_TAG_STALL_MASK, data);
91                 break;
92         case L2_DATA_STALL:
93                 *val = FIELD_GET(L2_CTL_DATA_STALL_MASK, data);
94                 break;
95         default:
96                 return -EINVAL;
97         }
98
99         return 0;
100 }
101
102 static int l2_ctl_set_latency(struct l2_ctl *l2, enum l2_ctl_stall id, u32 val)
103 {
104         u32 mask = 0, data = 0;
105         int ret;
106
107         val = clamp_val(val, L2_CTL_STALL_MIN, L2_CTL_STALL_MAX);
108
109         switch (id) {
110         case L2_WS_STALL:
111                 data = FIELD_PREP(L2_CTL_WS_STALL_MASK, val);
112                 mask = L2_CTL_WS_STALL_MASK;
113                 break;
114         case L2_TAG_STALL:
115                 data = FIELD_PREP(L2_CTL_TAG_STALL_MASK, val);
116                 mask = L2_CTL_TAG_STALL_MASK;
117                 break;
118         case L2_DATA_STALL:
119                 data = FIELD_PREP(L2_CTL_DATA_STALL_MASK, val);
120                 mask = L2_CTL_DATA_STALL_MASK;
121                 break;
122         default:
123                 return -EINVAL;
124         }
125
126         data |= L2_CTL_SET_CLKRATIO;
127         mask |= L2_CTL_SET_CLKRATIO;
128
129         ret = regmap_update_bits(l2->sys_regs, L2_CTL_REG, mask, data);
130         if (ret)
131                 return ret;
132
133         return regmap_read_poll_timeout(l2->sys_regs, L2_CTL_REG, data,
134                                         data & L2_CTL_CLKRATIO_LOCK,
135                                         L2_CTL_STALL_SET_DELAY_US,
136                                         L2_CTL_STALL_SET_TOUT_US);
137 }
138
139 static void l2_ctl_clear_data(void *data)
140 {
141         struct l2_ctl *l2 = data;
142         struct platform_device *pdev = to_platform_device(l2->dev);
143
144         platform_set_drvdata(pdev, NULL);
145 }
146
147 static struct l2_ctl *l2_ctl_create_data(struct platform_device *pdev)
148 {
149         struct device *dev = &pdev->dev;
150         struct l2_ctl *l2;
151         int ret;
152
153         l2 = devm_kzalloc(dev, sizeof(*l2), GFP_KERNEL);
154         if (!l2)
155                 return ERR_PTR(-ENOMEM);
156
157         ret = devm_add_action(dev, l2_ctl_clear_data, l2);
158         if (ret) {
159                 dev_err(dev, "Can't add L2 CTL data clear action\n");
160                 return ERR_PTR(ret);
161         }
162
163         l2->dev = dev;
164         platform_set_drvdata(pdev, l2);
165
166         return l2;
167 }
168
169 static int l2_ctl_find_sys_regs(struct l2_ctl *l2)
170 {
171         l2->sys_regs = syscon_node_to_regmap(l2->dev->of_node->parent);
172         if (IS_ERR(l2->sys_regs)) {
173                 dev_err(l2->dev, "Couldn't get L2 CTL register map\n");
174                 return PTR_ERR(l2->sys_regs);
175         }
176
177         return 0;
178 }
179
180 static int l2_ctl_of_parse_property(struct l2_ctl *l2, enum l2_ctl_stall id,
181                                     const char *propname)
182 {
183         int ret = 0;
184         u32 data;
185
186         if (!of_property_read_u32(l2->dev->of_node, propname, &data)) {
187                 ret = l2_ctl_set_latency(l2, id, data);
188                 if (ret)
189                         dev_err(l2->dev, "Invalid value of '%s'\n", propname);
190         }
191
192         return ret;
193 }
194
195 static int l2_ctl_of_parse(struct l2_ctl *l2)
196 {
197         int ret;
198
199         ret = l2_ctl_of_parse_property(l2, L2_WS_STALL, "baikal,l2-ws-latency");
200         if (ret)
201                 return ret;
202
203         ret = l2_ctl_of_parse_property(l2, L2_TAG_STALL, "baikal,l2-tag-latency");
204         if (ret)
205                 return ret;
206
207         return l2_ctl_of_parse_property(l2, L2_DATA_STALL,
208                                         "baikal,l2-data-latency");
209 }
210
211 static ssize_t l2_ctl_latency_show(struct device *dev,
212                                    struct device_attribute *attr,
213                                    char *buf)
214 {
215         struct l2_ctl_device_attribute *devattr = to_l2_ctl_dev_attr(attr);
216         struct l2_ctl *l2 = dev_get_drvdata(dev);
217         u32 data;
218         int ret;
219
220         ret = l2_ctl_get_latency(l2, devattr->id, &data);
221         if (ret)
222                 return ret;
223
224         return scnprintf(buf, PAGE_SIZE, "%u\n", data);
225 }
226
227 static ssize_t l2_ctl_latency_store(struct device *dev,
228                                     struct device_attribute *attr,
229                                     const char *buf, size_t count)
230 {
231         struct l2_ctl_device_attribute *devattr = to_l2_ctl_dev_attr(attr);
232         struct l2_ctl *l2 = dev_get_drvdata(dev);
233         u32 data;
234         int ret;
235
236         if (kstrtouint(buf, 0, &data) < 0)
237                 return -EINVAL;
238
239         ret = l2_ctl_set_latency(l2, devattr->id, data);
240         if (ret)
241                 return ret;
242
243         return count;
244 }
245 static L2_CTL_ATTR_RW(l2_ws_latency, l2_ctl_latency, L2_WS_STALL);
246 static L2_CTL_ATTR_RW(l2_tag_latency, l2_ctl_latency, L2_TAG_STALL);
247 static L2_CTL_ATTR_RW(l2_data_latency, l2_ctl_latency, L2_DATA_STALL);
248
249 static struct attribute *l2_ctl_sysfs_attrs[] = {
250         &l2_ctl_attr_l2_ws_latency.dev_attr.attr,
251         &l2_ctl_attr_l2_tag_latency.dev_attr.attr,
252         &l2_ctl_attr_l2_data_latency.dev_attr.attr,
253         NULL
254 };
255 ATTRIBUTE_GROUPS(l2_ctl_sysfs);
256
257 static void l2_ctl_remove_sysfs(void *data)
258 {
259         struct l2_ctl *l2 = data;
260
261         device_remove_groups(l2->dev, l2_ctl_sysfs_groups);
262 }
263
264 static int l2_ctl_init_sysfs(struct l2_ctl *l2)
265 {
266         int ret;
267
268         ret = device_add_groups(l2->dev, l2_ctl_sysfs_groups);
269         if (ret) {
270                 dev_err(l2->dev, "Failed to create L2 CTL sysfs nodes\n");
271                 return ret;
272         }
273
274         ret = devm_add_action_or_reset(l2->dev, l2_ctl_remove_sysfs, l2);
275         if (ret)
276                 dev_err(l2->dev, "Can't add L2 CTL sysfs remove action\n");
277
278         return ret;
279 }
280
281 static int l2_ctl_probe(struct platform_device *pdev)
282 {
283         struct l2_ctl *l2;
284         int ret;
285
286         l2 = l2_ctl_create_data(pdev);
287         if (IS_ERR(l2))
288                 return PTR_ERR(l2);
289
290         ret = l2_ctl_find_sys_regs(l2);
291         if (ret)
292                 return ret;
293
294         ret = l2_ctl_of_parse(l2);
295         if (ret)
296                 return ret;
297
298         ret = l2_ctl_init_sysfs(l2);
299         if (ret)
300                 return ret;
301
302         return 0;
303 }
304
305 static const struct of_device_id l2_ctl_of_match[] = {
306         { .compatible = "baikal,bt1-l2-ctl" },
307         { }
308 };
309 MODULE_DEVICE_TABLE(of, l2_ctl_of_match);
310
311 static struct platform_driver l2_ctl_driver = {
312         .probe = l2_ctl_probe,
313         .driver = {
314                 .name = "bt1-l2-ctl",
315                 .of_match_table = l2_ctl_of_match
316         }
317 };
318 module_platform_driver(l2_ctl_driver);
319
320 MODULE_AUTHOR("Serge Semin <[email protected]>");
321 MODULE_DESCRIPTION("Baikal-T1 L2-cache driver");
322 MODULE_LICENSE("GPL v2");
This page took 0.045882 seconds and 4 git commands to generate.