1
2
3
4
5
6
7
8
9
10
11
12#include <asm/unaligned.h>
13#include <linux/bitfield.h>
14#include <linux/delay.h>
15#include <linux/kernel.h>
16#include <linux/module.h>
17#include <linux/slab.h>
18#include <linux/sched.h>
19
20#include "nfp_cpp.h"
21#include "nfp6000/nfp6000.h"
22#include "nfp6000/nfp_xpb.h"
23
24
25#define NFP_PL_DEVICE_ID 0x00000004
26#define NFP_PL_DEVICE_ID_MASK GENMASK(7, 0)
27
28#define NFP6000_ARM_GCSR_SOFTMODEL0 0x00400144
29
30
31
32
33
34
35
36
37
38
39int nfp_cpp_readl(struct nfp_cpp *cpp, u32 cpp_id,
40 unsigned long long address, u32 *value)
41{
42 u8 tmp[4];
43 int n;
44
45 n = nfp_cpp_read(cpp, cpp_id, address, tmp, sizeof(tmp));
46 if (n != sizeof(tmp))
47 return n < 0 ? n : -EIO;
48
49 *value = get_unaligned_le32(tmp);
50 return 0;
51}
52
53
54
55
56
57
58
59
60
61
62int nfp_cpp_writel(struct nfp_cpp *cpp, u32 cpp_id,
63 unsigned long long address, u32 value)
64{
65 u8 tmp[4];
66 int n;
67
68 put_unaligned_le32(value, tmp);
69 n = nfp_cpp_write(cpp, cpp_id, address, tmp, sizeof(tmp));
70
71 return n == sizeof(tmp) ? 0 : n < 0 ? n : -EIO;
72}
73
74
75
76
77
78
79
80
81
82
83int nfp_cpp_readq(struct nfp_cpp *cpp, u32 cpp_id,
84 unsigned long long address, u64 *value)
85{
86 u8 tmp[8];
87 int n;
88
89 n = nfp_cpp_read(cpp, cpp_id, address, tmp, sizeof(tmp));
90 if (n != sizeof(tmp))
91 return n < 0 ? n : -EIO;
92
93 *value = get_unaligned_le64(tmp);
94 return 0;
95}
96
97
98
99
100
101
102
103
104
105
106int nfp_cpp_writeq(struct nfp_cpp *cpp, u32 cpp_id,
107 unsigned long long address, u64 value)
108{
109 u8 tmp[8];
110 int n;
111
112 put_unaligned_le64(value, tmp);
113 n = nfp_cpp_write(cpp, cpp_id, address, tmp, sizeof(tmp));
114
115 return n == sizeof(tmp) ? 0 : n < 0 ? n : -EIO;
116}
117
118
119
120
121int nfp_cpp_model_autodetect(struct nfp_cpp *cpp, u32 *model)
122{
123 const u32 arm_id = NFP_CPP_ID(NFP_CPP_TARGET_ARM, 0, 0);
124 u32 reg;
125 int err;
126
127 err = nfp_cpp_readl(cpp, arm_id, NFP6000_ARM_GCSR_SOFTMODEL0, model);
128 if (err < 0)
129 return err;
130
131
132 *model &= ~0xff;
133 err = nfp_xpb_readl(cpp, NFP_XPB_DEVICE(1, 1, 16) + NFP_PL_DEVICE_ID,
134 ®);
135 if (err < 0)
136 return err;
137
138 *model |= (NFP_PL_DEVICE_ID_MASK & reg) - 0x10;
139
140 return 0;
141}
142
143static u8 nfp_bytemask(int width, u64 addr)
144{
145 if (width == 8)
146 return 0xff;
147 else if (width == 4)
148 return 0x0f << (addr & 4);
149 else if (width == 2)
150 return 0x03 << (addr & 6);
151 else if (width == 1)
152 return 0x01 << (addr & 7);
153 else
154 return 0;
155}
156
157int nfp_cpp_explicit_read(struct nfp_cpp *cpp, u32 cpp_id,
158 u64 addr, void *buff, size_t len, int width_read)
159{
160 struct nfp_cpp_explicit *expl;
161 char *tmp = buff;
162 int err, i, incr;
163 u8 byte_mask;
164
165 if (len & (width_read - 1))
166 return -EINVAL;
167
168 expl = nfp_cpp_explicit_acquire(cpp);
169 if (!expl)
170 return -EBUSY;
171
172 incr = min_t(int, 16 * width_read, 128);
173 incr = min_t(int, incr, len);
174
175
176 if (NFP_CPP_ID_ACTION_of(cpp_id) == NFP_CPP_ACTION_RW)
177 cpp_id = NFP_CPP_ID(NFP_CPP_ID_TARGET_of(cpp_id), 0,
178 NFP_CPP_ID_TOKEN_of(cpp_id));
179
180 byte_mask = nfp_bytemask(width_read, addr);
181
182 nfp_cpp_explicit_set_target(expl, cpp_id,
183 incr / width_read - 1, byte_mask);
184 nfp_cpp_explicit_set_posted(expl, 1, 0, NFP_SIGNAL_PUSH,
185 0, NFP_SIGNAL_NONE);
186
187 for (i = 0; i < len; i += incr, addr += incr, tmp += incr) {
188 if (i + incr > len) {
189 incr = len - i;
190 nfp_cpp_explicit_set_target(expl, cpp_id,
191 incr / width_read - 1,
192 0xff);
193 }
194
195 err = nfp_cpp_explicit_do(expl, addr);
196 if (err < 0)
197 goto exit_release;
198
199 err = nfp_cpp_explicit_get(expl, tmp, incr);
200 if (err < 0)
201 goto exit_release;
202 }
203 err = len;
204exit_release:
205 nfp_cpp_explicit_release(expl);
206
207 return err;
208}
209
210int nfp_cpp_explicit_write(struct nfp_cpp *cpp, u32 cpp_id, u64 addr,
211 const void *buff, size_t len, int width_write)
212{
213 struct nfp_cpp_explicit *expl;
214 const char *tmp = buff;
215 int err, i, incr;
216 u8 byte_mask;
217
218 if (len & (width_write - 1))
219 return -EINVAL;
220
221 expl = nfp_cpp_explicit_acquire(cpp);
222 if (!expl)
223 return -EBUSY;
224
225 incr = min_t(int, 16 * width_write, 128);
226 incr = min_t(int, incr, len);
227
228
229 if (NFP_CPP_ID_ACTION_of(cpp_id) == NFP_CPP_ACTION_RW)
230 cpp_id = NFP_CPP_ID(NFP_CPP_ID_TARGET_of(cpp_id), 1,
231 NFP_CPP_ID_TOKEN_of(cpp_id));
232
233 byte_mask = nfp_bytemask(width_write, addr);
234
235 nfp_cpp_explicit_set_target(expl, cpp_id,
236 incr / width_write - 1, byte_mask);
237 nfp_cpp_explicit_set_posted(expl, 1, 0, NFP_SIGNAL_PULL,
238 0, NFP_SIGNAL_NONE);
239
240 for (i = 0; i < len; i += incr, addr += incr, tmp += incr) {
241 if (i + incr > len) {
242 incr = len - i;
243 nfp_cpp_explicit_set_target(expl, cpp_id,
244 incr / width_write - 1,
245 0xff);
246 }
247
248 err = nfp_cpp_explicit_put(expl, tmp, incr);
249 if (err < 0)
250 goto exit_release;
251
252 err = nfp_cpp_explicit_do(expl, addr);
253 if (err < 0)
254 goto exit_release;
255 }
256 err = len;
257exit_release:
258 nfp_cpp_explicit_release(expl);
259
260 return err;
261}
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277u8 __iomem *
278nfp_cpp_map_area(struct nfp_cpp *cpp, const char *name, u32 cpp_id, u64 addr,
279 unsigned long size, struct nfp_cpp_area **area)
280{
281 u8 __iomem *res;
282
283 *area = nfp_cpp_area_alloc_acquire(cpp, name, cpp_id, addr, size);
284 if (!*area)
285 goto err_eio;
286
287 res = nfp_cpp_area_iomem(*area);
288 if (!res)
289 goto err_release_free;
290
291 return res;
292
293err_release_free:
294 nfp_cpp_area_release_free(*area);
295err_eio:
296 return (u8 __iomem *)ERR_PTR(-EIO);
297}
298