1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * RapidIO Tsi57x switch family support
5 * Copyright 2009-2010 Integrated Device Technology, Inc.
6 * Alexandre Bounine <alexandre.bounine@idt.com>
8 * - Modified switch operations initialization.
10 * Copyright 2005 MontaVista Software, Inc.
11 * Matt Porter <mporter@kernel.crashing.org>
14 #include <linux/rio.h>
15 #include <linux/rio_drv.h>
16 #include <linux/rio_ids.h>
17 #include <linux/delay.h>
18 #include <linux/module.h>
21 /* Global (broadcast) route registers */
22 #define SPBC_ROUTE_CFG_DESTID 0x10070
23 #define SPBC_ROUTE_CFG_PORT 0x10074
25 /* Per port route registers */
26 #define SPP_ROUTE_CFG_DESTID(n) (0x11070 + 0x100*n)
27 #define SPP_ROUTE_CFG_PORT(n) (0x11074 + 0x100*n)
29 #define TSI578_SP_MODE(n) (0x11004 + n*0x100)
30 #define TSI578_SP_MODE_GLBL 0x10004
31 #define TSI578_SP_MODE_PW_DIS 0x08000000
32 #define TSI578_SP_MODE_LUT_512 0x01000000
34 #define TSI578_SP_CTL_INDEP(n) (0x13004 + n*0x100)
35 #define TSI578_SP_LUT_PEINF(n) (0x13010 + n*0x100)
36 #define TSI578_SP_CS_TX(n) (0x13014 + n*0x100)
37 #define TSI578_SP_INT_STATUS(n) (0x13018 + n*0x100)
39 #define TSI578_GLBL_ROUTE_BASE 0x10078
42 tsi57x_route_add_entry(struct rio_mport
*mport
, u16 destid
, u8 hopcount
,
43 u16 table
, u16 route_destid
, u8 route_port
)
45 if (table
== RIO_GLOBAL_TABLE
) {
46 rio_mport_write_config_32(mport
, destid
, hopcount
,
47 SPBC_ROUTE_CFG_DESTID
, route_destid
);
48 rio_mport_write_config_32(mport
, destid
, hopcount
,
49 SPBC_ROUTE_CFG_PORT
, route_port
);
51 rio_mport_write_config_32(mport
, destid
, hopcount
,
52 SPP_ROUTE_CFG_DESTID(table
), route_destid
);
53 rio_mport_write_config_32(mport
, destid
, hopcount
,
54 SPP_ROUTE_CFG_PORT(table
), route_port
);
63 tsi57x_route_get_entry(struct rio_mport
*mport
, u16 destid
, u8 hopcount
,
64 u16 table
, u16 route_destid
, u8
*route_port
)
69 if (table
== RIO_GLOBAL_TABLE
) {
70 /* Use local RT of the ingress port to avoid possible
72 rio_mport_read_config_32(mport
, destid
, hopcount
,
73 RIO_SWP_INFO_CAR
, &result
);
74 table
= (result
& RIO_SWP_INFO_PORT_NUM_MASK
);
77 rio_mport_write_config_32(mport
, destid
, hopcount
,
78 SPP_ROUTE_CFG_DESTID(table
), route_destid
);
79 rio_mport_read_config_32(mport
, destid
, hopcount
,
80 SPP_ROUTE_CFG_PORT(table
), &result
);
82 *route_port
= (u8
)result
;
90 tsi57x_route_clr_table(struct rio_mport
*mport
, u16 destid
, u8 hopcount
,
96 lut_size
= (mport
->sys_size
) ? 0x1ff : 0xff;
98 if (table
== RIO_GLOBAL_TABLE
) {
99 rio_mport_write_config_32(mport
, destid
, hopcount
,
100 SPBC_ROUTE_CFG_DESTID
, 0x80000000);
101 for (route_idx
= 0; route_idx
<= lut_size
; route_idx
++)
102 rio_mport_write_config_32(mport
, destid
, hopcount
,
106 rio_mport_write_config_32(mport
, destid
, hopcount
,
107 SPP_ROUTE_CFG_DESTID(table
), 0x80000000);
108 for (route_idx
= 0; route_idx
<= lut_size
; route_idx
++)
109 rio_mport_write_config_32(mport
, destid
, hopcount
,
110 SPP_ROUTE_CFG_PORT(table
) , RIO_INVALID_ROUTE
);
117 tsi57x_set_domain(struct rio_mport
*mport
, u16 destid
, u8 hopcount
,
123 * Switch domain configuration operates only at global level
126 /* Turn off flat (LUT_512) mode */
127 rio_mport_read_config_32(mport
, destid
, hopcount
,
128 TSI578_SP_MODE_GLBL
, ®val
);
129 rio_mport_write_config_32(mport
, destid
, hopcount
, TSI578_SP_MODE_GLBL
,
130 regval
& ~TSI578_SP_MODE_LUT_512
);
131 /* Set switch domain base */
132 rio_mport_write_config_32(mport
, destid
, hopcount
,
133 TSI578_GLBL_ROUTE_BASE
,
134 (u32
)(sw_domain
<< 24));
139 tsi57x_get_domain(struct rio_mport
*mport
, u16 destid
, u8 hopcount
,
145 * Switch domain configuration operates only at global level
147 rio_mport_read_config_32(mport
, destid
, hopcount
,
148 TSI578_GLBL_ROUTE_BASE
, ®val
);
150 *sw_domain
= (u8
)(regval
>> 24);
156 tsi57x_em_init(struct rio_dev
*rdev
)
161 pr_debug("TSI578 %s [%d:%d]\n", __func__
, rdev
->destid
, rdev
->hopcount
);
164 portnum
< RIO_GET_TOTAL_PORTS(rdev
->swpinfo
); portnum
++) {
165 /* Make sure that Port-Writes are enabled (for all ports) */
166 rio_read_config_32(rdev
,
167 TSI578_SP_MODE(portnum
), ®val
);
168 rio_write_config_32(rdev
,
169 TSI578_SP_MODE(portnum
),
170 regval
& ~TSI578_SP_MODE_PW_DIS
);
172 /* Clear all pending interrupts */
173 rio_read_config_32(rdev
,
174 RIO_DEV_PORT_N_ERR_STS_CSR(rdev
, portnum
),
176 rio_write_config_32(rdev
,
177 RIO_DEV_PORT_N_ERR_STS_CSR(rdev
, portnum
),
178 regval
& 0x07120214);
180 rio_read_config_32(rdev
,
181 TSI578_SP_INT_STATUS(portnum
), ®val
);
182 rio_write_config_32(rdev
,
183 TSI578_SP_INT_STATUS(portnum
),
184 regval
& 0x000700bd);
186 /* Enable all interrupts to allow ports to send a port-write */
187 rio_read_config_32(rdev
,
188 TSI578_SP_CTL_INDEP(portnum
), ®val
);
189 rio_write_config_32(rdev
,
190 TSI578_SP_CTL_INDEP(portnum
),
191 regval
| 0x000b0000);
193 /* Skip next (odd) port if the current port is in x4 mode */
194 rio_read_config_32(rdev
,
195 RIO_DEV_PORT_N_CTL_CSR(rdev
, portnum
),
197 if ((regval
& RIO_PORT_N_CTL_PWIDTH
) == RIO_PORT_N_CTL_PWIDTH_4
)
201 /* set TVAL = ~50us */
202 rio_write_config_32(rdev
,
203 rdev
->phys_efptr
+ RIO_PORT_LINKTO_CTL_CSR
, 0x9a << 8);
209 tsi57x_em_handler(struct rio_dev
*rdev
, u8 portnum
)
211 struct rio_mport
*mport
= rdev
->net
->hport
;
212 u32 intstat
, err_status
;
213 int sendcount
, checkcount
;
217 rio_read_config_32(rdev
,
218 RIO_DEV_PORT_N_ERR_STS_CSR(rdev
, portnum
),
221 if ((err_status
& RIO_PORT_N_ERR_STS_PORT_OK
) &&
222 (err_status
& (RIO_PORT_N_ERR_STS_OUT_ES
|
223 RIO_PORT_N_ERR_STS_INP_ES
))) {
224 /* Remove any queued packets by locking/unlocking port */
225 rio_read_config_32(rdev
,
226 RIO_DEV_PORT_N_CTL_CSR(rdev
, portnum
),
228 if (!(regval
& RIO_PORT_N_CTL_LOCKOUT
)) {
229 rio_write_config_32(rdev
,
230 RIO_DEV_PORT_N_CTL_CSR(rdev
, portnum
),
231 regval
| RIO_PORT_N_CTL_LOCKOUT
);
233 rio_write_config_32(rdev
,
234 RIO_DEV_PORT_N_CTL_CSR(rdev
, portnum
),
238 /* Read from link maintenance response register to clear
241 rio_read_config_32(rdev
,
242 RIO_DEV_PORT_N_MNT_RSP_CSR(rdev
, portnum
),
245 /* Send a Packet-Not-Accepted/Link-Request-Input-Status control
246 * symbol to recover from IES/OES
250 rio_write_config_32(rdev
,
251 TSI578_SP_CS_TX(portnum
), 0x40fc8000);
253 while (checkcount
--) {
255 rio_read_config_32(rdev
,
256 RIO_DEV_PORT_N_MNT_RSP_CSR(rdev
,
259 if (regval
& RIO_PORT_N_MNT_RSP_RVAL
)
268 /* Clear implementation specific error status bits */
269 rio_read_config_32(rdev
, TSI578_SP_INT_STATUS(portnum
), &intstat
);
270 pr_debug("TSI578[%x:%x] SP%d_INT_STATUS=0x%08x\n",
271 rdev
->destid
, rdev
->hopcount
, portnum
, intstat
);
273 if (intstat
& 0x10000) {
274 rio_read_config_32(rdev
,
275 TSI578_SP_LUT_PEINF(portnum
), ®val
);
276 regval
= (mport
->sys_size
) ? (regval
>> 16) : (regval
>> 24);
277 route_port
= rdev
->rswitch
->route_table
[regval
];
278 pr_debug("RIO: TSI578[%s] P%d LUT Parity Error (destID=%d)\n",
279 rio_name(rdev
), portnum
, regval
);
280 tsi57x_route_add_entry(mport
, rdev
->destid
, rdev
->hopcount
,
281 RIO_GLOBAL_TABLE
, regval
, route_port
);
284 rio_write_config_32(rdev
, TSI578_SP_INT_STATUS(portnum
),
285 intstat
& 0x000700bd);
290 static struct rio_switch_ops tsi57x_switch_ops
= {
291 .owner
= THIS_MODULE
,
292 .add_entry
= tsi57x_route_add_entry
,
293 .get_entry
= tsi57x_route_get_entry
,
294 .clr_table
= tsi57x_route_clr_table
,
295 .set_domain
= tsi57x_set_domain
,
296 .get_domain
= tsi57x_get_domain
,
297 .em_init
= tsi57x_em_init
,
298 .em_handle
= tsi57x_em_handler
,
301 static int tsi57x_probe(struct rio_dev
*rdev
, const struct rio_device_id
*id
)
303 pr_debug("RIO: %s for %s\n", __func__
, rio_name(rdev
));
305 spin_lock(&rdev
->rswitch
->lock
);
307 if (rdev
->rswitch
->ops
) {
308 spin_unlock(&rdev
->rswitch
->lock
);
311 rdev
->rswitch
->ops
= &tsi57x_switch_ops
;
314 /* Ensure that default routing is disabled on startup */
315 rio_write_config_32(rdev
, RIO_STD_RTE_DEFAULT_PORT
,
319 spin_unlock(&rdev
->rswitch
->lock
);
323 static void tsi57x_remove(struct rio_dev
*rdev
)
325 pr_debug("RIO: %s for %s\n", __func__
, rio_name(rdev
));
326 spin_lock(&rdev
->rswitch
->lock
);
327 if (rdev
->rswitch
->ops
!= &tsi57x_switch_ops
) {
328 spin_unlock(&rdev
->rswitch
->lock
);
331 rdev
->rswitch
->ops
= NULL
;
332 spin_unlock(&rdev
->rswitch
->lock
);
335 static const struct rio_device_id tsi57x_id_table
[] = {
336 {RIO_DEVICE(RIO_DID_TSI572
, RIO_VID_TUNDRA
)},
337 {RIO_DEVICE(RIO_DID_TSI574
, RIO_VID_TUNDRA
)},
338 {RIO_DEVICE(RIO_DID_TSI577
, RIO_VID_TUNDRA
)},
339 {RIO_DEVICE(RIO_DID_TSI578
, RIO_VID_TUNDRA
)},
340 { 0, } /* terminate list */
343 static struct rio_driver tsi57x_driver
= {
345 .id_table
= tsi57x_id_table
,
346 .probe
= tsi57x_probe
,
347 .remove
= tsi57x_remove
,
350 static int __init
tsi57x_init(void)
352 return rio_register_driver(&tsi57x_driver
);
355 static void __exit
tsi57x_exit(void)
357 rio_unregister_driver(&tsi57x_driver
);
360 device_initcall(tsi57x_init
);
361 module_exit(tsi57x_exit
);
363 MODULE_DESCRIPTION("IDT Tsi57x Serial RapidIO switch family driver");
364 MODULE_AUTHOR("Integrated Device Technology, Inc.");
365 MODULE_LICENSE("GPL");