1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * IDT CPS RapidIO switches support |
4 | * |
5 | * Copyright 2009-2010 Integrated Device Technology, Inc. |
6 | * Alexandre Bounine <alexandre.bounine@idt.com> |
7 | */ |
8 | |
9 | #include <linux/rio.h> |
10 | #include <linux/rio_drv.h> |
11 | #include <linux/rio_ids.h> |
12 | #include <linux/module.h> |
13 | #include "../rio.h" |
14 | |
15 | #define CPS_DEFAULT_ROUTE 0xde |
16 | #define CPS_NO_ROUTE 0xdf |
17 | |
18 | #define IDTCPS_RIO_DOMAIN 0xf20020 |
19 | |
20 | static int |
21 | idtcps_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount, |
22 | u16 table, u16 route_destid, u8 route_port) |
23 | { |
24 | u32 result; |
25 | |
26 | if (route_port == RIO_INVALID_ROUTE) |
27 | route_port = CPS_DEFAULT_ROUTE; |
28 | |
29 | if (table == RIO_GLOBAL_TABLE) { |
30 | rio_mport_write_config_32(port: mport, destid, hopcount, |
31 | RIO_STD_RTE_CONF_DESTID_SEL_CSR, data: route_destid); |
32 | |
33 | rio_mport_read_config_32(port: mport, destid, hopcount, |
34 | RIO_STD_RTE_CONF_PORT_SEL_CSR, data: &result); |
35 | |
36 | result = (0xffffff00 & result) | (u32)route_port; |
37 | rio_mport_write_config_32(port: mport, destid, hopcount, |
38 | RIO_STD_RTE_CONF_PORT_SEL_CSR, data: result); |
39 | } |
40 | |
41 | return 0; |
42 | } |
43 | |
44 | static int |
45 | idtcps_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount, |
46 | u16 table, u16 route_destid, u8 *route_port) |
47 | { |
48 | u32 result; |
49 | |
50 | if (table == RIO_GLOBAL_TABLE) { |
51 | rio_mport_write_config_32(port: mport, destid, hopcount, |
52 | RIO_STD_RTE_CONF_DESTID_SEL_CSR, data: route_destid); |
53 | |
54 | rio_mport_read_config_32(port: mport, destid, hopcount, |
55 | RIO_STD_RTE_CONF_PORT_SEL_CSR, data: &result); |
56 | |
57 | if (CPS_DEFAULT_ROUTE == (u8)result || |
58 | CPS_NO_ROUTE == (u8)result) |
59 | *route_port = RIO_INVALID_ROUTE; |
60 | else |
61 | *route_port = (u8)result; |
62 | } |
63 | |
64 | return 0; |
65 | } |
66 | |
67 | static int |
68 | idtcps_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount, |
69 | u16 table) |
70 | { |
71 | u32 i; |
72 | |
73 | if (table == RIO_GLOBAL_TABLE) { |
74 | for (i = 0x80000000; i <= 0x800000ff;) { |
75 | rio_mport_write_config_32(port: mport, destid, hopcount, |
76 | RIO_STD_RTE_CONF_DESTID_SEL_CSR, data: i); |
77 | rio_mport_write_config_32(port: mport, destid, hopcount, |
78 | RIO_STD_RTE_CONF_PORT_SEL_CSR, |
79 | data: (CPS_DEFAULT_ROUTE << 24) | |
80 | (CPS_DEFAULT_ROUTE << 16) | |
81 | (CPS_DEFAULT_ROUTE << 8) | CPS_DEFAULT_ROUTE); |
82 | i += 4; |
83 | } |
84 | } |
85 | |
86 | return 0; |
87 | } |
88 | |
89 | static int |
90 | idtcps_set_domain(struct rio_mport *mport, u16 destid, u8 hopcount, |
91 | u8 sw_domain) |
92 | { |
93 | /* |
94 | * Switch domain configuration operates only at global level |
95 | */ |
96 | rio_mport_write_config_32(port: mport, destid, hopcount, |
97 | IDTCPS_RIO_DOMAIN, data: (u32)sw_domain); |
98 | return 0; |
99 | } |
100 | |
101 | static int |
102 | idtcps_get_domain(struct rio_mport *mport, u16 destid, u8 hopcount, |
103 | u8 *sw_domain) |
104 | { |
105 | u32 regval; |
106 | |
107 | /* |
108 | * Switch domain configuration operates only at global level |
109 | */ |
110 | rio_mport_read_config_32(port: mport, destid, hopcount, |
111 | IDTCPS_RIO_DOMAIN, data: ®val); |
112 | |
113 | *sw_domain = (u8)(regval & 0xff); |
114 | |
115 | return 0; |
116 | } |
117 | |
118 | static struct rio_switch_ops idtcps_switch_ops = { |
119 | .owner = THIS_MODULE, |
120 | .add_entry = idtcps_route_add_entry, |
121 | .get_entry = idtcps_route_get_entry, |
122 | .clr_table = idtcps_route_clr_table, |
123 | .set_domain = idtcps_set_domain, |
124 | .get_domain = idtcps_get_domain, |
125 | .em_init = NULL, |
126 | .em_handle = NULL, |
127 | }; |
128 | |
129 | static int idtcps_probe(struct rio_dev *rdev, const struct rio_device_id *id) |
130 | { |
131 | pr_debug("RIO: %s for %s\n" , __func__, rio_name(rdev)); |
132 | |
133 | spin_lock(lock: &rdev->rswitch->lock); |
134 | |
135 | if (rdev->rswitch->ops) { |
136 | spin_unlock(lock: &rdev->rswitch->lock); |
137 | return -EINVAL; |
138 | } |
139 | |
140 | rdev->rswitch->ops = &idtcps_switch_ops; |
141 | |
142 | if (rdev->do_enum) { |
143 | /* set TVAL = ~50us */ |
144 | rio_write_config_32(rdev, |
145 | offset: rdev->phys_efptr + RIO_PORT_LINKTO_CTL_CSR, data: 0x8e << 8); |
146 | /* Ensure that default routing is disabled on startup */ |
147 | rio_write_config_32(rdev, |
148 | RIO_STD_RTE_DEFAULT_PORT, CPS_NO_ROUTE); |
149 | } |
150 | |
151 | spin_unlock(lock: &rdev->rswitch->lock); |
152 | return 0; |
153 | } |
154 | |
155 | static void idtcps_remove(struct rio_dev *rdev) |
156 | { |
157 | pr_debug("RIO: %s for %s\n" , __func__, rio_name(rdev)); |
158 | spin_lock(lock: &rdev->rswitch->lock); |
159 | if (rdev->rswitch->ops != &idtcps_switch_ops) { |
160 | spin_unlock(lock: &rdev->rswitch->lock); |
161 | return; |
162 | } |
163 | rdev->rswitch->ops = NULL; |
164 | spin_unlock(lock: &rdev->rswitch->lock); |
165 | } |
166 | |
167 | static const struct rio_device_id idtcps_id_table[] = { |
168 | {RIO_DEVICE(RIO_DID_IDTCPS6Q, RIO_VID_IDT)}, |
169 | {RIO_DEVICE(RIO_DID_IDTCPS8, RIO_VID_IDT)}, |
170 | {RIO_DEVICE(RIO_DID_IDTCPS10Q, RIO_VID_IDT)}, |
171 | {RIO_DEVICE(RIO_DID_IDTCPS12, RIO_VID_IDT)}, |
172 | {RIO_DEVICE(RIO_DID_IDTCPS16, RIO_VID_IDT)}, |
173 | {RIO_DEVICE(RIO_DID_IDT70K200, RIO_VID_IDT)}, |
174 | { 0, } /* terminate list */ |
175 | }; |
176 | |
177 | static struct rio_driver idtcps_driver = { |
178 | .name = "idtcps" , |
179 | .id_table = idtcps_id_table, |
180 | .probe = idtcps_probe, |
181 | .remove = idtcps_remove, |
182 | }; |
183 | |
184 | static int __init idtcps_init(void) |
185 | { |
186 | return rio_register_driver(&idtcps_driver); |
187 | } |
188 | |
189 | static void __exit idtcps_exit(void) |
190 | { |
191 | rio_unregister_driver(&idtcps_driver); |
192 | } |
193 | |
194 | device_initcall(idtcps_init); |
195 | module_exit(idtcps_exit); |
196 | |
197 | MODULE_DESCRIPTION("IDT CPS Gen.1 Serial RapidIO switch family driver" ); |
198 | MODULE_AUTHOR("Integrated Device Technology, Inc." ); |
199 | MODULE_LICENSE("GPL" ); |
200 | |