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(slave: 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(slave: 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, id: 0, addr, val: &cmd, size: 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(dev: hub->upstream, FSI_MCENP0 + (4 * idx), |
95 | val: ®, size: 4); |
96 | |
97 | rc = fsi_device_write(dev: hub->upstream, FSI_MSENP0 + (4 * idx), val: ®, size: 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(objp: 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, val: ®, size: 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, val: ®, size: 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, val: ®, size: 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, val: ®, size: sizeof(reg)); |
152 | if (rc) |
153 | return rc; |
154 | |
155 | reg = cpu_to_be32(0xffff0000); |
156 | rc = fsi_device_write(dev, FSI_MDLYR, val: ®, size: sizeof(reg)); |
157 | if (rc) |
158 | return rc; |
159 | |
160 | reg = cpu_to_be32(~0); |
161 | rc = fsi_device_write(dev, FSI_MSENP0, val: ®, size: 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, val: ®, size: sizeof(reg)); |
169 | if (rc) |
170 | return rc; |
171 | |
172 | rc = fsi_device_read(dev, FSI_MAEB, val: ®, size: 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, val: ®, size: sizeof(reg)); |
178 | if (rc) |
179 | return rc; |
180 | |
181 | rc = fsi_device_read(dev, FSI_MLEVP0, val: ®, size: 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, val: ®, size: 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, val: ®, size: 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(dev: fsi_dev, FSI_MVER, val: &__reg, size: 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(slave: 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(size: 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(node: 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, data: hub); |
239 | |
240 | hub_master_init(hub); |
241 | |
242 | rc = fsi_master_register(master: &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(dev: &hub->master.dev); |
254 | return 0; |
255 | |
256 | err_release: |
257 | fsi_slave_release_range(slave: 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(master: &hub->master); |
267 | fsi_slave_release_range(slave: hub->upstream->slave, addr: hub->addr, size: hub->size); |
268 | of_node_put(node: 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(dev: &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_LICENSE("GPL" ); |
299 | |