Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/fsi/fsi-master-hub.c
26278 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* FSI hub master driver
4
*
5
* Copyright (C) IBM Corporation 2016
6
*/
7
8
#include <linux/delay.h>
9
#include <linux/fsi.h>
10
#include <linux/module.h>
11
#include <linux/of.h>
12
#include <linux/slab.h>
13
14
#include "fsi-master.h"
15
16
#define FSI_ENGID_HUB_MASTER 0x1c
17
18
#define FSI_LINK_ENABLE_SETUP_TIME 10 /* in mS */
19
20
/*
21
* FSI hub master support
22
*
23
* A hub master increases the number of potential target devices that the
24
* primary FSI master can access. For each link a primary master supports,
25
* each of those links can in turn be chained to a hub master with multiple
26
* links of its own.
27
*
28
* The hub is controlled by a set of control registers exposed as a regular fsi
29
* device (the hub->upstream device), and provides access to the downstream FSI
30
* bus as through an address range on the slave itself (->addr and ->size).
31
*
32
* [This differs from "cascaded" masters, which expose the entire downstream
33
* bus entirely through the fsi device address range, and so have a smaller
34
* accessible address space.]
35
*/
36
struct fsi_master_hub {
37
struct fsi_master master;
38
struct fsi_device *upstream;
39
uint32_t addr, size; /* slave-relative addr of */
40
/* master address space */
41
};
42
43
#define to_fsi_master_hub(m) container_of(m, struct fsi_master_hub, master)
44
45
static int hub_master_read(struct fsi_master *master, int link,
46
uint8_t id, uint32_t addr, void *val, size_t size)
47
{
48
struct fsi_master_hub *hub = to_fsi_master_hub(master);
49
50
if (id != 0)
51
return -EINVAL;
52
53
addr += hub->addr + (link * FSI_HUB_LINK_SIZE);
54
return fsi_slave_read(hub->upstream->slave, addr, val, size);
55
}
56
57
static int hub_master_write(struct fsi_master *master, int link,
58
uint8_t id, uint32_t addr, const void *val, size_t size)
59
{
60
struct fsi_master_hub *hub = to_fsi_master_hub(master);
61
62
if (id != 0)
63
return -EINVAL;
64
65
addr += hub->addr + (link * FSI_HUB_LINK_SIZE);
66
return fsi_slave_write(hub->upstream->slave, addr, val, size);
67
}
68
69
static int hub_master_break(struct fsi_master *master, int link)
70
{
71
uint32_t addr;
72
__be32 cmd;
73
74
addr = 0x4;
75
cmd = cpu_to_be32(0xc0de0000);
76
77
return hub_master_write(master, link, 0, addr, &cmd, sizeof(cmd));
78
}
79
80
static int hub_master_link_enable(struct fsi_master *master, int link,
81
bool enable)
82
{
83
struct fsi_master_hub *hub = to_fsi_master_hub(master);
84
int idx, bit;
85
__be32 reg;
86
int rc;
87
88
idx = link / 32;
89
bit = link % 32;
90
91
reg = cpu_to_be32(0x80000000 >> bit);
92
93
if (!enable)
94
return fsi_device_write(hub->upstream, FSI_MCENP0 + (4 * idx),
95
&reg, 4);
96
97
rc = fsi_device_write(hub->upstream, FSI_MSENP0 + (4 * idx), &reg, 4);
98
if (rc)
99
return rc;
100
101
mdelay(FSI_LINK_ENABLE_SETUP_TIME);
102
103
return 0;
104
}
105
106
static void hub_master_release(struct device *dev)
107
{
108
struct fsi_master_hub *hub = to_fsi_master_hub(to_fsi_master(dev));
109
110
kfree(hub);
111
}
112
113
/* mmode encoders */
114
static inline u32 fsi_mmode_crs0(u32 x)
115
{
116
return (x & FSI_MMODE_CRS0MASK) << FSI_MMODE_CRS0SHFT;
117
}
118
119
static inline u32 fsi_mmode_crs1(u32 x)
120
{
121
return (x & FSI_MMODE_CRS1MASK) << FSI_MMODE_CRS1SHFT;
122
}
123
124
static int hub_master_init(struct fsi_master_hub *hub)
125
{
126
struct fsi_device *dev = hub->upstream;
127
__be32 reg;
128
int rc;
129
130
reg = cpu_to_be32(FSI_MRESP_RST_ALL_MASTER | FSI_MRESP_RST_ALL_LINK
131
| FSI_MRESP_RST_MCR | FSI_MRESP_RST_PYE);
132
rc = fsi_device_write(dev, FSI_MRESP0, &reg, sizeof(reg));
133
if (rc)
134
return rc;
135
136
/* Initialize the MFSI (hub master) engine */
137
reg = cpu_to_be32(FSI_MRESP_RST_ALL_MASTER | FSI_MRESP_RST_ALL_LINK
138
| FSI_MRESP_RST_MCR | FSI_MRESP_RST_PYE);
139
rc = fsi_device_write(dev, FSI_MRESP0, &reg, sizeof(reg));
140
if (rc)
141
return rc;
142
143
reg = cpu_to_be32(FSI_MECTRL_EOAE | FSI_MECTRL_P8_AUTO_TERM);
144
rc = fsi_device_write(dev, FSI_MECTRL, &reg, sizeof(reg));
145
if (rc)
146
return rc;
147
148
reg = cpu_to_be32(FSI_MMODE_EIP | FSI_MMODE_ECRC | FSI_MMODE_EPC
149
| fsi_mmode_crs0(1) | fsi_mmode_crs1(1)
150
| FSI_MMODE_P8_TO_LSB);
151
rc = fsi_device_write(dev, FSI_MMODE, &reg, sizeof(reg));
152
if (rc)
153
return rc;
154
155
reg = cpu_to_be32(0xffff0000);
156
rc = fsi_device_write(dev, FSI_MDLYR, &reg, sizeof(reg));
157
if (rc)
158
return rc;
159
160
reg = cpu_to_be32(~0);
161
rc = fsi_device_write(dev, FSI_MSENP0, &reg, sizeof(reg));
162
if (rc)
163
return rc;
164
165
/* Leave enabled long enough for master logic to set up */
166
mdelay(FSI_LINK_ENABLE_SETUP_TIME);
167
168
rc = fsi_device_write(dev, FSI_MCENP0, &reg, sizeof(reg));
169
if (rc)
170
return rc;
171
172
rc = fsi_device_read(dev, FSI_MAEB, &reg, sizeof(reg));
173
if (rc)
174
return rc;
175
176
reg = cpu_to_be32(FSI_MRESP_RST_ALL_MASTER | FSI_MRESP_RST_ALL_LINK);
177
rc = fsi_device_write(dev, FSI_MRESP0, &reg, sizeof(reg));
178
if (rc)
179
return rc;
180
181
rc = fsi_device_read(dev, FSI_MLEVP0, &reg, sizeof(reg));
182
if (rc)
183
return rc;
184
185
/* Reset the master bridge */
186
reg = cpu_to_be32(FSI_MRESB_RST_GEN);
187
rc = fsi_device_write(dev, FSI_MRESB0, &reg, sizeof(reg));
188
if (rc)
189
return rc;
190
191
reg = cpu_to_be32(FSI_MRESB_RST_ERR);
192
return fsi_device_write(dev, FSI_MRESB0, &reg, sizeof(reg));
193
}
194
195
static int hub_master_probe(struct device *dev)
196
{
197
struct fsi_device *fsi_dev = to_fsi_dev(dev);
198
struct fsi_master_hub *hub;
199
uint32_t reg, links;
200
__be32 __reg;
201
int rc;
202
203
rc = fsi_device_read(fsi_dev, FSI_MVER, &__reg, sizeof(__reg));
204
if (rc)
205
return rc;
206
207
reg = be32_to_cpu(__reg);
208
links = (reg >> 8) & 0xff;
209
dev_dbg(dev, "hub version %08x (%d links)\n", reg, links);
210
211
rc = fsi_slave_claim_range(fsi_dev->slave, FSI_HUB_LINK_OFFSET,
212
FSI_HUB_LINK_SIZE * links);
213
if (rc) {
214
dev_err(dev, "can't claim slave address range for links");
215
return rc;
216
}
217
218
hub = kzalloc(sizeof(*hub), GFP_KERNEL);
219
if (!hub) {
220
rc = -ENOMEM;
221
goto err_release;
222
}
223
224
hub->addr = FSI_HUB_LINK_OFFSET;
225
hub->size = FSI_HUB_LINK_SIZE * links;
226
hub->upstream = fsi_dev;
227
228
hub->master.dev.parent = dev;
229
hub->master.dev.release = hub_master_release;
230
hub->master.dev.of_node = of_node_get(dev_of_node(dev));
231
232
hub->master.n_links = links;
233
hub->master.read = hub_master_read;
234
hub->master.write = hub_master_write;
235
hub->master.send_break = hub_master_break;
236
hub->master.link_enable = hub_master_link_enable;
237
238
dev_set_drvdata(dev, hub);
239
240
hub_master_init(hub);
241
242
rc = fsi_master_register(&hub->master);
243
if (rc)
244
goto err_release;
245
246
/* At this point, fsi_master_register performs the device_initialize(),
247
* and holds the sole reference on master.dev. This means the device
248
* will be freed (via ->release) during any subsequent call to
249
* fsi_master_unregister. We add our own reference to it here, so we
250
* can perform cleanup (in _remove()) without it being freed before
251
* we're ready.
252
*/
253
get_device(&hub->master.dev);
254
return 0;
255
256
err_release:
257
fsi_slave_release_range(fsi_dev->slave, FSI_HUB_LINK_OFFSET,
258
FSI_HUB_LINK_SIZE * links);
259
return rc;
260
}
261
262
static int hub_master_remove(struct device *dev)
263
{
264
struct fsi_master_hub *hub = dev_get_drvdata(dev);
265
266
fsi_master_unregister(&hub->master);
267
fsi_slave_release_range(hub->upstream->slave, hub->addr, hub->size);
268
of_node_put(hub->master.dev.of_node);
269
270
/*
271
* master.dev will likely be ->release()ed after this, which free()s
272
* the hub
273
*/
274
put_device(&hub->master.dev);
275
276
return 0;
277
}
278
279
static const struct fsi_device_id hub_master_ids[] = {
280
{
281
.engine_type = FSI_ENGID_HUB_MASTER,
282
.version = FSI_VERSION_ANY,
283
},
284
{ 0 }
285
};
286
287
static struct fsi_driver hub_master_driver = {
288
.id_table = hub_master_ids,
289
.drv = {
290
.name = "fsi-master-hub",
291
.bus = &fsi_bus_type,
292
.probe = hub_master_probe,
293
.remove = hub_master_remove,
294
}
295
};
296
297
module_fsi_driver(hub_master_driver);
298
MODULE_DESCRIPTION("FSI hub master driver");
299
MODULE_LICENSE("GPL");
300
301