1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * IDT CPS Gen.2 Serial RapidIO switch family support |
4 | * |
5 | * Copyright 2010 Integrated Device Technology, Inc. |
6 | * Alexandre Bounine <alexandre.bounine@idt.com> |
7 | */ |
8 | |
9 | #include <linux/stat.h> |
10 | #include <linux/module.h> |
11 | #include <linux/rio.h> |
12 | #include <linux/rio_drv.h> |
13 | #include <linux/rio_ids.h> |
14 | #include <linux/delay.h> |
15 | |
16 | #include <asm/page.h> |
17 | #include "../rio.h" |
18 | |
19 | #define LOCAL_RTE_CONF_DESTID_SEL 0x010070 |
20 | #define LOCAL_RTE_CONF_DESTID_SEL_PSEL 0x0000001f |
21 | |
22 | #define IDT_LT_ERR_REPORT_EN 0x03100c |
23 | |
24 | #define IDT_PORT_ERR_REPORT_EN(n) (0x031044 + (n)*0x40) |
25 | #define IDT_PORT_ERR_REPORT_EN_BC 0x03ff04 |
26 | |
27 | #define IDT_PORT_ISERR_REPORT_EN(n) (0x03104C + (n)*0x40) |
28 | #define IDT_PORT_ISERR_REPORT_EN_BC 0x03ff0c |
29 | #define IDT_PORT_INIT_TX_ACQUIRED 0x00000020 |
30 | |
31 | #define IDT_LANE_ERR_REPORT_EN(n) (0x038010 + (n)*0x100) |
32 | #define IDT_LANE_ERR_REPORT_EN_BC 0x03ff10 |
33 | |
34 | #define IDT_DEV_CTRL_1 0xf2000c |
35 | #define IDT_DEV_CTRL_1_GENPW 0x02000000 |
36 | #define IDT_DEV_CTRL_1_PRSTBEH 0x00000001 |
37 | |
38 | #define IDT_CFGBLK_ERR_CAPTURE_EN 0x020008 |
39 | #define IDT_CFGBLK_ERR_REPORT 0xf20014 |
40 | #define IDT_CFGBLK_ERR_REPORT_GENPW 0x00000002 |
41 | |
42 | #define IDT_AUX_PORT_ERR_CAP_EN 0x020000 |
43 | #define IDT_AUX_ERR_REPORT_EN 0xf20018 |
44 | #define IDT_AUX_PORT_ERR_LOG_I2C 0x00000002 |
45 | #define IDT_AUX_PORT_ERR_LOG_JTAG 0x00000001 |
46 | |
47 | #define IDT_ISLTL_ADDRESS_CAP 0x021014 |
48 | |
49 | #define IDT_RIO_DOMAIN 0xf20020 |
50 | #define IDT_RIO_DOMAIN_MASK 0x000000ff |
51 | |
52 | #define IDT_PW_INFO_CSR 0xf20024 |
53 | |
54 | #define IDT_SOFT_RESET 0xf20040 |
55 | #define IDT_SOFT_RESET_REQ 0x00030097 |
56 | |
57 | #define IDT_I2C_MCTRL 0xf20050 |
58 | #define IDT_I2C_MCTRL_GENPW 0x04000000 |
59 | |
60 | #define IDT_JTAG_CTRL 0xf2005c |
61 | #define IDT_JTAG_CTRL_GENPW 0x00000002 |
62 | |
63 | #define IDT_LANE_CTRL(n) (0xff8000 + (n)*0x100) |
64 | #define IDT_LANE_CTRL_BC 0xffff00 |
65 | #define IDT_LANE_CTRL_GENPW 0x00200000 |
66 | #define IDT_LANE_DFE_1_BC 0xffff18 |
67 | #define IDT_LANE_DFE_2_BC 0xffff1c |
68 | |
69 | #define IDT_PORT_OPS(n) (0xf40004 + (n)*0x100) |
70 | #define IDT_PORT_OPS_GENPW 0x08000000 |
71 | #define IDT_PORT_OPS_PL_ELOG 0x00000040 |
72 | #define IDT_PORT_OPS_LL_ELOG 0x00000020 |
73 | #define IDT_PORT_OPS_LT_ELOG 0x00000010 |
74 | #define IDT_PORT_OPS_BC 0xf4ff04 |
75 | |
76 | #define IDT_PORT_ISERR_DET(n) (0xf40008 + (n)*0x100) |
77 | |
78 | #define IDT_ERR_CAP 0xfd0000 |
79 | #define IDT_ERR_CAP_LOG_OVERWR 0x00000004 |
80 | |
81 | #define IDT_ERR_RD 0xfd0004 |
82 | |
83 | #define IDT_DEFAULT_ROUTE 0xde |
84 | #define IDT_NO_ROUTE 0xdf |
85 | |
86 | static int |
87 | idtg2_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount, |
88 | u16 table, u16 route_destid, u8 route_port) |
89 | { |
90 | /* |
91 | * Select routing table to update |
92 | */ |
93 | if (table == RIO_GLOBAL_TABLE) |
94 | table = 0; |
95 | else |
96 | table++; |
97 | |
98 | if (route_port == RIO_INVALID_ROUTE) |
99 | route_port = IDT_DEFAULT_ROUTE; |
100 | |
101 | rio_mport_write_config_32(port: mport, destid, hopcount, |
102 | LOCAL_RTE_CONF_DESTID_SEL, data: table); |
103 | |
104 | /* |
105 | * Program destination port for the specified destID |
106 | */ |
107 | rio_mport_write_config_32(port: mport, destid, hopcount, |
108 | RIO_STD_RTE_CONF_DESTID_SEL_CSR, |
109 | data: (u32)route_destid); |
110 | |
111 | rio_mport_write_config_32(port: mport, destid, hopcount, |
112 | RIO_STD_RTE_CONF_PORT_SEL_CSR, |
113 | data: (u32)route_port); |
114 | udelay(10); |
115 | |
116 | return 0; |
117 | } |
118 | |
119 | static int |
120 | idtg2_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount, |
121 | u16 table, u16 route_destid, u8 *route_port) |
122 | { |
123 | u32 result; |
124 | |
125 | /* |
126 | * Select routing table to read |
127 | */ |
128 | if (table == RIO_GLOBAL_TABLE) |
129 | table = 0; |
130 | else |
131 | table++; |
132 | |
133 | rio_mport_write_config_32(port: mport, destid, hopcount, |
134 | LOCAL_RTE_CONF_DESTID_SEL, data: table); |
135 | |
136 | rio_mport_write_config_32(port: mport, destid, hopcount, |
137 | RIO_STD_RTE_CONF_DESTID_SEL_CSR, |
138 | data: route_destid); |
139 | |
140 | rio_mport_read_config_32(port: mport, destid, hopcount, |
141 | RIO_STD_RTE_CONF_PORT_SEL_CSR, data: &result); |
142 | |
143 | if (IDT_DEFAULT_ROUTE == (u8)result || IDT_NO_ROUTE == (u8)result) |
144 | *route_port = RIO_INVALID_ROUTE; |
145 | else |
146 | *route_port = (u8)result; |
147 | |
148 | return 0; |
149 | } |
150 | |
151 | static int |
152 | idtg2_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount, |
153 | u16 table) |
154 | { |
155 | u32 i; |
156 | |
157 | /* |
158 | * Select routing table to read |
159 | */ |
160 | if (table == RIO_GLOBAL_TABLE) |
161 | table = 0; |
162 | else |
163 | table++; |
164 | |
165 | rio_mport_write_config_32(port: mport, destid, hopcount, |
166 | LOCAL_RTE_CONF_DESTID_SEL, data: table); |
167 | |
168 | for (i = RIO_STD_RTE_CONF_EXTCFGEN; |
169 | i <= (RIO_STD_RTE_CONF_EXTCFGEN | 0xff);) { |
170 | rio_mport_write_config_32(port: mport, destid, hopcount, |
171 | RIO_STD_RTE_CONF_DESTID_SEL_CSR, data: i); |
172 | rio_mport_write_config_32(port: mport, destid, hopcount, |
173 | RIO_STD_RTE_CONF_PORT_SEL_CSR, |
174 | data: (IDT_DEFAULT_ROUTE << 24) | (IDT_DEFAULT_ROUTE << 16) | |
175 | (IDT_DEFAULT_ROUTE << 8) | IDT_DEFAULT_ROUTE); |
176 | i += 4; |
177 | } |
178 | |
179 | return 0; |
180 | } |
181 | |
182 | |
183 | static int |
184 | idtg2_set_domain(struct rio_mport *mport, u16 destid, u8 hopcount, |
185 | u8 sw_domain) |
186 | { |
187 | /* |
188 | * Switch domain configuration operates only at global level |
189 | */ |
190 | rio_mport_write_config_32(port: mport, destid, hopcount, |
191 | IDT_RIO_DOMAIN, data: (u32)sw_domain); |
192 | return 0; |
193 | } |
194 | |
195 | static int |
196 | idtg2_get_domain(struct rio_mport *mport, u16 destid, u8 hopcount, |
197 | u8 *sw_domain) |
198 | { |
199 | u32 regval; |
200 | |
201 | /* |
202 | * Switch domain configuration operates only at global level |
203 | */ |
204 | rio_mport_read_config_32(port: mport, destid, hopcount, |
205 | IDT_RIO_DOMAIN, data: ®val); |
206 | |
207 | *sw_domain = (u8)(regval & 0xff); |
208 | |
209 | return 0; |
210 | } |
211 | |
212 | static int |
213 | idtg2_em_init(struct rio_dev *rdev) |
214 | { |
215 | u32 regval; |
216 | int i, tmp; |
217 | |
218 | /* |
219 | * This routine performs device-specific initialization only. |
220 | * All standard EM configuration should be performed at upper level. |
221 | */ |
222 | |
223 | pr_debug("RIO: %s [%d:%d]\n" , __func__, rdev->destid, rdev->hopcount); |
224 | |
225 | /* Set Port-Write info CSR: PRIO=3 and CRF=1 */ |
226 | rio_write_config_32(rdev, IDT_PW_INFO_CSR, data: 0x0000e000); |
227 | |
228 | /* |
229 | * Configure LT LAYER error reporting. |
230 | */ |
231 | |
232 | /* Enable standard (RIO.p8) error reporting */ |
233 | rio_write_config_32(rdev, IDT_LT_ERR_REPORT_EN, |
234 | REM_LTL_ERR_ILLTRAN | REM_LTL_ERR_UNSOLR | |
235 | REM_LTL_ERR_UNSUPTR); |
236 | |
237 | /* Use Port-Writes for LT layer error reporting. |
238 | * Enable per-port reset |
239 | */ |
240 | rio_read_config_32(rdev, IDT_DEV_CTRL_1, data: ®val); |
241 | rio_write_config_32(rdev, IDT_DEV_CTRL_1, |
242 | data: regval | IDT_DEV_CTRL_1_GENPW | IDT_DEV_CTRL_1_PRSTBEH); |
243 | |
244 | /* |
245 | * Configure PORT error reporting. |
246 | */ |
247 | |
248 | /* Report all RIO.p8 errors supported by device */ |
249 | rio_write_config_32(rdev, IDT_PORT_ERR_REPORT_EN_BC, data: 0x807e8037); |
250 | |
251 | /* Configure reporting of implementation specific errors/events */ |
252 | rio_write_config_32(rdev, IDT_PORT_ISERR_REPORT_EN_BC, |
253 | IDT_PORT_INIT_TX_ACQUIRED); |
254 | |
255 | /* Use Port-Writes for port error reporting and enable error logging */ |
256 | tmp = RIO_GET_TOTAL_PORTS(rdev->swpinfo); |
257 | for (i = 0; i < tmp; i++) { |
258 | rio_read_config_32(rdev, IDT_PORT_OPS(i), data: ®val); |
259 | rio_write_config_32(rdev, |
260 | IDT_PORT_OPS(i), data: regval | IDT_PORT_OPS_GENPW | |
261 | IDT_PORT_OPS_PL_ELOG | |
262 | IDT_PORT_OPS_LL_ELOG | |
263 | IDT_PORT_OPS_LT_ELOG); |
264 | } |
265 | /* Overwrite error log if full */ |
266 | rio_write_config_32(rdev, IDT_ERR_CAP, IDT_ERR_CAP_LOG_OVERWR); |
267 | |
268 | /* |
269 | * Configure LANE error reporting. |
270 | */ |
271 | |
272 | /* Disable line error reporting */ |
273 | rio_write_config_32(rdev, IDT_LANE_ERR_REPORT_EN_BC, data: 0); |
274 | |
275 | /* Use Port-Writes for lane error reporting (when enabled) |
276 | * (do per-lane update because lanes may have different configuration) |
277 | */ |
278 | tmp = (rdev->did == RIO_DID_IDTCPS1848) ? 48 : 16; |
279 | for (i = 0; i < tmp; i++) { |
280 | rio_read_config_32(rdev, IDT_LANE_CTRL(i), data: ®val); |
281 | rio_write_config_32(rdev, IDT_LANE_CTRL(i), |
282 | data: regval | IDT_LANE_CTRL_GENPW); |
283 | } |
284 | |
285 | /* |
286 | * Configure AUX error reporting. |
287 | */ |
288 | |
289 | /* Disable JTAG and I2C Error capture */ |
290 | rio_write_config_32(rdev, IDT_AUX_PORT_ERR_CAP_EN, data: 0); |
291 | |
292 | /* Disable JTAG and I2C Error reporting/logging */ |
293 | rio_write_config_32(rdev, IDT_AUX_ERR_REPORT_EN, data: 0); |
294 | |
295 | /* Disable Port-Write notification from JTAG */ |
296 | rio_write_config_32(rdev, IDT_JTAG_CTRL, data: 0); |
297 | |
298 | /* Disable Port-Write notification from I2C */ |
299 | rio_read_config_32(rdev, IDT_I2C_MCTRL, data: ®val); |
300 | rio_write_config_32(rdev, IDT_I2C_MCTRL, data: regval & ~IDT_I2C_MCTRL_GENPW); |
301 | |
302 | /* |
303 | * Configure CFG_BLK error reporting. |
304 | */ |
305 | |
306 | /* Disable Configuration Block error capture */ |
307 | rio_write_config_32(rdev, IDT_CFGBLK_ERR_CAPTURE_EN, data: 0); |
308 | |
309 | /* Disable Port-Writes for Configuration Block error reporting */ |
310 | rio_read_config_32(rdev, IDT_CFGBLK_ERR_REPORT, data: ®val); |
311 | rio_write_config_32(rdev, IDT_CFGBLK_ERR_REPORT, |
312 | data: regval & ~IDT_CFGBLK_ERR_REPORT_GENPW); |
313 | |
314 | /* set TVAL = ~50us */ |
315 | rio_write_config_32(rdev, |
316 | offset: rdev->phys_efptr + RIO_PORT_LINKTO_CTL_CSR, data: 0x8e << 8); |
317 | |
318 | return 0; |
319 | } |
320 | |
321 | static int |
322 | idtg2_em_handler(struct rio_dev *rdev, u8 portnum) |
323 | { |
324 | u32 regval, em_perrdet, em_ltlerrdet; |
325 | |
326 | rio_read_config_32(rdev, |
327 | offset: rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, data: &em_ltlerrdet); |
328 | if (em_ltlerrdet) { |
329 | /* Service Logical/Transport Layer Error(s) */ |
330 | if (em_ltlerrdet & REM_LTL_ERR_IMPSPEC) { |
331 | /* Implementation specific error reported */ |
332 | rio_read_config_32(rdev, |
333 | IDT_ISLTL_ADDRESS_CAP, data: ®val); |
334 | |
335 | pr_debug("RIO: %s Implementation Specific LTL errors" \ |
336 | " 0x%x @(0x%x)\n" , |
337 | rio_name(rdev), em_ltlerrdet, regval); |
338 | |
339 | /* Clear implementation specific address capture CSR */ |
340 | rio_write_config_32(rdev, IDT_ISLTL_ADDRESS_CAP, data: 0); |
341 | |
342 | } |
343 | } |
344 | |
345 | rio_read_config_32(rdev, |
346 | offset: rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), data: &em_perrdet); |
347 | if (em_perrdet) { |
348 | /* Service Port-Level Error(s) */ |
349 | if (em_perrdet & REM_PED_IMPL_SPEC) { |
350 | /* Implementation Specific port error reported */ |
351 | |
352 | /* Get IS errors reported */ |
353 | rio_read_config_32(rdev, |
354 | IDT_PORT_ISERR_DET(portnum), data: ®val); |
355 | |
356 | pr_debug("RIO: %s Implementation Specific Port" \ |
357 | " errors 0x%x\n" , rio_name(rdev), regval); |
358 | |
359 | /* Clear all implementation specific events */ |
360 | rio_write_config_32(rdev, |
361 | IDT_PORT_ISERR_DET(portnum), data: 0); |
362 | } |
363 | } |
364 | |
365 | return 0; |
366 | } |
367 | |
368 | static ssize_t |
369 | idtg2_show_errlog(struct device *dev, struct device_attribute *attr, char *buf) |
370 | { |
371 | struct rio_dev *rdev = to_rio_dev(dev); |
372 | ssize_t len = 0; |
373 | u32 regval; |
374 | |
375 | while (!rio_read_config_32(rdev, IDT_ERR_RD, data: ®val)) { |
376 | if (!regval) /* 0 = end of log */ |
377 | break; |
378 | len += snprintf(buf: buf + len, PAGE_SIZE - len, |
379 | fmt: "%08x\n" , regval); |
380 | if (len >= (PAGE_SIZE - 10)) |
381 | break; |
382 | } |
383 | |
384 | return len; |
385 | } |
386 | |
387 | static DEVICE_ATTR(errlog, S_IRUGO, idtg2_show_errlog, NULL); |
388 | |
389 | static int idtg2_sysfs(struct rio_dev *rdev, bool create) |
390 | { |
391 | struct device *dev = &rdev->dev; |
392 | int err = 0; |
393 | |
394 | if (create) { |
395 | /* Initialize sysfs entries */ |
396 | err = device_create_file(device: dev, entry: &dev_attr_errlog); |
397 | if (err) |
398 | dev_err(dev, "Unable create sysfs errlog file\n" ); |
399 | } else |
400 | device_remove_file(dev, attr: &dev_attr_errlog); |
401 | |
402 | return err; |
403 | } |
404 | |
405 | static struct rio_switch_ops idtg2_switch_ops = { |
406 | .owner = THIS_MODULE, |
407 | .add_entry = idtg2_route_add_entry, |
408 | .get_entry = idtg2_route_get_entry, |
409 | .clr_table = idtg2_route_clr_table, |
410 | .set_domain = idtg2_set_domain, |
411 | .get_domain = idtg2_get_domain, |
412 | .em_init = idtg2_em_init, |
413 | .em_handle = idtg2_em_handler, |
414 | }; |
415 | |
416 | static int idtg2_probe(struct rio_dev *rdev, const struct rio_device_id *id) |
417 | { |
418 | pr_debug("RIO: %s for %s\n" , __func__, rio_name(rdev)); |
419 | |
420 | spin_lock(lock: &rdev->rswitch->lock); |
421 | |
422 | if (rdev->rswitch->ops) { |
423 | spin_unlock(lock: &rdev->rswitch->lock); |
424 | return -EINVAL; |
425 | } |
426 | |
427 | rdev->rswitch->ops = &idtg2_switch_ops; |
428 | |
429 | if (rdev->do_enum) { |
430 | /* Ensure that default routing is disabled on startup */ |
431 | rio_write_config_32(rdev, |
432 | RIO_STD_RTE_DEFAULT_PORT, IDT_NO_ROUTE); |
433 | } |
434 | |
435 | spin_unlock(lock: &rdev->rswitch->lock); |
436 | |
437 | /* Create device-specific sysfs attributes */ |
438 | idtg2_sysfs(rdev, create: true); |
439 | |
440 | return 0; |
441 | } |
442 | |
443 | static void idtg2_remove(struct rio_dev *rdev) |
444 | { |
445 | pr_debug("RIO: %s for %s\n" , __func__, rio_name(rdev)); |
446 | spin_lock(lock: &rdev->rswitch->lock); |
447 | if (rdev->rswitch->ops != &idtg2_switch_ops) { |
448 | spin_unlock(lock: &rdev->rswitch->lock); |
449 | return; |
450 | } |
451 | rdev->rswitch->ops = NULL; |
452 | spin_unlock(lock: &rdev->rswitch->lock); |
453 | /* Remove device-specific sysfs attributes */ |
454 | idtg2_sysfs(rdev, create: false); |
455 | } |
456 | |
457 | static const struct rio_device_id idtg2_id_table[] = { |
458 | {RIO_DEVICE(RIO_DID_IDTCPS1848, RIO_VID_IDT)}, |
459 | {RIO_DEVICE(RIO_DID_IDTCPS1616, RIO_VID_IDT)}, |
460 | {RIO_DEVICE(RIO_DID_IDTVPS1616, RIO_VID_IDT)}, |
461 | {RIO_DEVICE(RIO_DID_IDTSPS1616, RIO_VID_IDT)}, |
462 | {RIO_DEVICE(RIO_DID_IDTCPS1432, RIO_VID_IDT)}, |
463 | { 0, } /* terminate list */ |
464 | }; |
465 | |
466 | static struct rio_driver idtg2_driver = { |
467 | .name = "idt_gen2" , |
468 | .id_table = idtg2_id_table, |
469 | .probe = idtg2_probe, |
470 | .remove = idtg2_remove, |
471 | }; |
472 | |
473 | static int __init idtg2_init(void) |
474 | { |
475 | return rio_register_driver(&idtg2_driver); |
476 | } |
477 | |
478 | static void __exit idtg2_exit(void) |
479 | { |
480 | pr_debug("RIO: %s\n" , __func__); |
481 | rio_unregister_driver(&idtg2_driver); |
482 | pr_debug("RIO: %s done\n" , __func__); |
483 | } |
484 | |
485 | device_initcall(idtg2_init); |
486 | module_exit(idtg2_exit); |
487 | |
488 | MODULE_DESCRIPTION("IDT CPS Gen.2 Serial RapidIO switch family driver" ); |
489 | MODULE_AUTHOR("Integrated Device Technology, Inc." ); |
490 | MODULE_LICENSE("GPL" ); |
491 | |