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
20static int
21idtcps_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(mport, destid, hopcount,
31				RIO_STD_RTE_CONF_DESTID_SEL_CSR, route_destid);
32
33		rio_mport_read_config_32(mport, destid, hopcount,
34				RIO_STD_RTE_CONF_PORT_SEL_CSR, &result);
35
36		result = (0xffffff00 & result) | (u32)route_port;
37		rio_mport_write_config_32(mport, destid, hopcount,
38				RIO_STD_RTE_CONF_PORT_SEL_CSR, result);
39	}
40
41	return 0;
42}
43
44static int
45idtcps_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(mport, destid, hopcount,
52				RIO_STD_RTE_CONF_DESTID_SEL_CSR, route_destid);
53
54		rio_mport_read_config_32(mport, destid, hopcount,
55				RIO_STD_RTE_CONF_PORT_SEL_CSR, &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
67static int
68idtcps_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(mport, destid, hopcount,
76				RIO_STD_RTE_CONF_DESTID_SEL_CSR, i);
77			rio_mport_write_config_32(mport, destid, hopcount,
78				RIO_STD_RTE_CONF_PORT_SEL_CSR,
79				(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
89static int
90idtcps_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(mport, destid, hopcount,
97				  IDTCPS_RIO_DOMAIN, (u32)sw_domain);
98	return 0;
99}
100
101static int
102idtcps_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(mport, destid, hopcount,
111				IDTCPS_RIO_DOMAIN, &regval);
112
113	*sw_domain = (u8)(regval & 0xff);
114
115	return 0;
116}
117
118static 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
129static 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(&rdev->rswitch->lock);
134
135	if (rdev->rswitch->ops) {
136		spin_unlock(&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			rdev->phys_efptr + RIO_PORT_LINKTO_CTL_CSR, 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(&rdev->rswitch->lock);
152	return 0;
153}
154
155static void idtcps_remove(struct rio_dev *rdev)
156{
157	pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
158	spin_lock(&rdev->rswitch->lock);
159	if (rdev->rswitch->ops != &idtcps_switch_ops) {
160		spin_unlock(&rdev->rswitch->lock);
161		return;
162	}
163	rdev->rswitch->ops = NULL;
164	spin_unlock(&rdev->rswitch->lock);
165}
166
167static 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
177static struct rio_driver idtcps_driver = {
178	.name = "idtcps",
179	.id_table = idtcps_id_table,
180	.probe = idtcps_probe,
181	.remove = idtcps_remove,
182};
183
184static int __init idtcps_init(void)
185{
186	return rio_register_driver(&idtcps_driver);
187}
188
189static void __exit idtcps_exit(void)
190{
191	rio_unregister_driver(&idtcps_driver);
192}
193
194device_initcall(idtcps_init);
195module_exit(idtcps_exit);
196
197MODULE_DESCRIPTION("IDT CPS Gen.1 Serial RapidIO switch family driver");
198MODULE_AUTHOR("Integrated Device Technology, Inc.");
199MODULE_LICENSE("GPL");
200