1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | // Copyright (C) IBM Corporation 2018 |
3 | // FSI master driver for AST2600 |
4 | |
5 | #include <linux/clk.h> |
6 | #include <linux/delay.h> |
7 | #include <linux/fsi.h> |
8 | #include <linux/io.h> |
9 | #include <linux/mfd/syscon.h> |
10 | #include <linux/module.h> |
11 | #include <linux/mutex.h> |
12 | #include <linux/of.h> |
13 | #include <linux/platform_device.h> |
14 | #include <linux/regmap.h> |
15 | #include <linux/slab.h> |
16 | #include <linux/iopoll.h> |
17 | #include <linux/gpio/consumer.h> |
18 | |
19 | #include "fsi-master.h" |
20 | |
21 | struct fsi_master_aspeed { |
22 | struct fsi_master master; |
23 | struct mutex lock; /* protect HW access */ |
24 | struct device *dev; |
25 | void __iomem *base; |
26 | struct clk *clk; |
27 | struct gpio_desc *cfam_reset_gpio; |
28 | }; |
29 | |
30 | #define to_fsi_master_aspeed(m) \ |
31 | container_of(m, struct fsi_master_aspeed, master) |
32 | |
33 | /* Control register (size 0x400) */ |
34 | static const u32 ctrl_base = 0x80000000; |
35 | |
36 | static const u32 fsi_base = 0xa0000000; |
37 | |
38 | #define OPB_FSI_VER 0x00 |
39 | #define OPB_TRIGGER 0x04 |
40 | #define OPB_CTRL_BASE 0x08 |
41 | #define OPB_FSI_BASE 0x0c |
42 | #define OPB_CLK_SYNC 0x3c |
43 | #define OPB_IRQ_CLEAR 0x40 |
44 | #define OPB_IRQ_MASK 0x44 |
45 | #define OPB_IRQ_STATUS 0x48 |
46 | |
47 | #define OPB0_SELECT 0x10 |
48 | #define OPB0_RW 0x14 |
49 | #define OPB0_XFER_SIZE 0x18 |
50 | #define OPB0_FSI_ADDR 0x1c |
51 | #define OPB0_FSI_DATA_W 0x20 |
52 | #define OPB0_STATUS 0x80 |
53 | #define OPB0_FSI_DATA_R 0x84 |
54 | |
55 | #define OPB0_WRITE_ORDER1 0x4c |
56 | #define OPB0_WRITE_ORDER2 0x50 |
57 | #define OPB1_WRITE_ORDER1 0x54 |
58 | #define OPB1_WRITE_ORDER2 0x58 |
59 | #define OPB0_READ_ORDER1 0x5c |
60 | #define OPB1_READ_ORDER2 0x60 |
61 | |
62 | #define OPB_RETRY_COUNTER 0x64 |
63 | |
64 | /* OPBn_STATUS */ |
65 | #define STATUS_HALFWORD_ACK BIT(0) |
66 | #define STATUS_FULLWORD_ACK BIT(1) |
67 | #define STATUS_ERR_ACK BIT(2) |
68 | #define STATUS_RETRY BIT(3) |
69 | #define STATUS_TIMEOUT BIT(4) |
70 | |
71 | /* OPB_IRQ_MASK */ |
72 | #define OPB1_XFER_ACK_EN BIT(17) |
73 | #define OPB0_XFER_ACK_EN BIT(16) |
74 | |
75 | /* OPB_RW */ |
76 | #define CMD_READ BIT(0) |
77 | #define CMD_WRITE 0 |
78 | |
79 | /* OPBx_XFER_SIZE */ |
80 | #define XFER_FULLWORD (BIT(1) | BIT(0)) |
81 | #define XFER_HALFWORD (BIT(0)) |
82 | #define XFER_BYTE (0) |
83 | |
84 | #define CREATE_TRACE_POINTS |
85 | #include <trace/events/fsi_master_aspeed.h> |
86 | |
87 | #define FSI_LINK_ENABLE_SETUP_TIME 10 /* in mS */ |
88 | |
89 | /* Run the bus at maximum speed by default */ |
90 | #define FSI_DIVISOR_DEFAULT 1 |
91 | #define FSI_DIVISOR_CABLED 2 |
92 | static u16 aspeed_fsi_divisor = FSI_DIVISOR_DEFAULT; |
93 | module_param_named(bus_div,aspeed_fsi_divisor, ushort, 0); |
94 | |
95 | #define OPB_POLL_TIMEOUT 500 |
96 | |
97 | static int __opb_write(struct fsi_master_aspeed *aspeed, u32 addr, |
98 | u32 val, u32 transfer_size) |
99 | { |
100 | void __iomem *base = aspeed->base; |
101 | u32 reg, status; |
102 | int ret; |
103 | |
104 | /* |
105 | * The ordering of these writes up until the trigger |
106 | * write does not matter, so use writel_relaxed. |
107 | */ |
108 | writel_relaxed(CMD_WRITE, base + OPB0_RW); |
109 | writel_relaxed(transfer_size, base + OPB0_XFER_SIZE); |
110 | writel_relaxed(addr, base + OPB0_FSI_ADDR); |
111 | writel_relaxed(val, base + OPB0_FSI_DATA_W); |
112 | writel_relaxed(0x1, base + OPB_IRQ_CLEAR); |
113 | writel(val: 0x1, addr: base + OPB_TRIGGER); |
114 | |
115 | ret = readl_poll_timeout(base + OPB_IRQ_STATUS, reg, |
116 | (reg & OPB0_XFER_ACK_EN) != 0, |
117 | 0, OPB_POLL_TIMEOUT); |
118 | |
119 | status = readl(addr: base + OPB0_STATUS); |
120 | |
121 | trace_fsi_master_aspeed_opb_write(addr, val, size: transfer_size, status, irq_status: reg); |
122 | |
123 | /* Return error when poll timed out */ |
124 | if (ret) |
125 | return ret; |
126 | |
127 | /* Command failed, master will reset */ |
128 | if (status & STATUS_ERR_ACK) |
129 | return -EIO; |
130 | |
131 | return 0; |
132 | } |
133 | |
134 | static int opb_writeb(struct fsi_master_aspeed *aspeed, u32 addr, u8 val) |
135 | { |
136 | return __opb_write(aspeed, addr, val, XFER_BYTE); |
137 | } |
138 | |
139 | static int opb_writew(struct fsi_master_aspeed *aspeed, u32 addr, __be16 val) |
140 | { |
141 | return __opb_write(aspeed, addr, val: (__force u16)val, XFER_HALFWORD); |
142 | } |
143 | |
144 | static int opb_writel(struct fsi_master_aspeed *aspeed, u32 addr, __be32 val) |
145 | { |
146 | return __opb_write(aspeed, addr, val: (__force u32)val, XFER_FULLWORD); |
147 | } |
148 | |
149 | static int __opb_read(struct fsi_master_aspeed *aspeed, uint32_t addr, |
150 | u32 transfer_size, void *out) |
151 | { |
152 | void __iomem *base = aspeed->base; |
153 | u32 result, reg; |
154 | int status, ret; |
155 | |
156 | /* |
157 | * The ordering of these writes up until the trigger |
158 | * write does not matter, so use writel_relaxed. |
159 | */ |
160 | writel_relaxed(CMD_READ, base + OPB0_RW); |
161 | writel_relaxed(transfer_size, base + OPB0_XFER_SIZE); |
162 | writel_relaxed(addr, base + OPB0_FSI_ADDR); |
163 | writel_relaxed(0x1, base + OPB_IRQ_CLEAR); |
164 | writel(val: 0x1, addr: base + OPB_TRIGGER); |
165 | |
166 | ret = readl_poll_timeout(base + OPB_IRQ_STATUS, reg, |
167 | (reg & OPB0_XFER_ACK_EN) != 0, |
168 | 0, OPB_POLL_TIMEOUT); |
169 | |
170 | status = readl(addr: base + OPB0_STATUS); |
171 | |
172 | result = readl(addr: base + OPB0_FSI_DATA_R); |
173 | |
174 | trace_fsi_master_aspeed_opb_read(addr, size: transfer_size, result, |
175 | readl(addr: base + OPB0_STATUS), |
176 | irq_status: reg); |
177 | |
178 | /* Return error when poll timed out */ |
179 | if (ret) |
180 | return ret; |
181 | |
182 | /* Command failed, master will reset */ |
183 | if (status & STATUS_ERR_ACK) |
184 | return -EIO; |
185 | |
186 | if (out) { |
187 | switch (transfer_size) { |
188 | case XFER_BYTE: |
189 | *(u8 *)out = result; |
190 | break; |
191 | case XFER_HALFWORD: |
192 | *(u16 *)out = result; |
193 | break; |
194 | case XFER_FULLWORD: |
195 | *(u32 *)out = result; |
196 | break; |
197 | default: |
198 | return -EINVAL; |
199 | } |
200 | |
201 | } |
202 | |
203 | return 0; |
204 | } |
205 | |
206 | static int opb_readl(struct fsi_master_aspeed *aspeed, uint32_t addr, __be32 *out) |
207 | { |
208 | return __opb_read(aspeed, addr, XFER_FULLWORD, out); |
209 | } |
210 | |
211 | static int opb_readw(struct fsi_master_aspeed *aspeed, uint32_t addr, __be16 *out) |
212 | { |
213 | return __opb_read(aspeed, addr, XFER_HALFWORD, out: (void *)out); |
214 | } |
215 | |
216 | static int opb_readb(struct fsi_master_aspeed *aspeed, uint32_t addr, u8 *out) |
217 | { |
218 | return __opb_read(aspeed, addr, XFER_BYTE, out: (void *)out); |
219 | } |
220 | |
221 | static int check_errors(struct fsi_master_aspeed *aspeed, int err) |
222 | { |
223 | int ret; |
224 | |
225 | if (trace_fsi_master_aspeed_opb_error_enabled()) { |
226 | __be32 mresp0, mstap0, mesrb0; |
227 | |
228 | opb_readl(aspeed, addr: ctrl_base + FSI_MRESP0, out: &mresp0); |
229 | opb_readl(aspeed, addr: ctrl_base + FSI_MSTAP0, out: &mstap0); |
230 | opb_readl(aspeed, addr: ctrl_base + FSI_MESRB0, out: &mesrb0); |
231 | |
232 | trace_fsi_master_aspeed_opb_error( |
233 | be32_to_cpu(mresp0), |
234 | be32_to_cpu(mstap0), |
235 | be32_to_cpu(mesrb0)); |
236 | } |
237 | |
238 | if (err == -EIO) { |
239 | /* Check MAEB (0x70) ? */ |
240 | |
241 | /* Then clear errors in master */ |
242 | ret = opb_writel(aspeed, addr: ctrl_base + FSI_MRESP0, |
243 | cpu_to_be32(FSI_MRESP_RST_ALL_MASTER)); |
244 | if (ret) { |
245 | /* TODO: log? return different code? */ |
246 | return ret; |
247 | } |
248 | /* TODO: confirm that 0x70 was okay */ |
249 | } |
250 | |
251 | /* This will pass through timeout errors */ |
252 | return err; |
253 | } |
254 | |
255 | static int aspeed_master_read(struct fsi_master *master, int link, |
256 | uint8_t id, uint32_t addr, void *val, size_t size) |
257 | { |
258 | struct fsi_master_aspeed *aspeed = to_fsi_master_aspeed(master); |
259 | int ret; |
260 | |
261 | if (id > 0x3) |
262 | return -EINVAL; |
263 | |
264 | addr |= id << 21; |
265 | addr += link * FSI_HUB_LINK_SIZE; |
266 | |
267 | mutex_lock(&aspeed->lock); |
268 | |
269 | switch (size) { |
270 | case 1: |
271 | ret = opb_readb(aspeed, addr: fsi_base + addr, out: val); |
272 | break; |
273 | case 2: |
274 | ret = opb_readw(aspeed, addr: fsi_base + addr, out: val); |
275 | break; |
276 | case 4: |
277 | ret = opb_readl(aspeed, addr: fsi_base + addr, out: val); |
278 | break; |
279 | default: |
280 | ret = -EINVAL; |
281 | goto done; |
282 | } |
283 | |
284 | ret = check_errors(aspeed, err: ret); |
285 | done: |
286 | mutex_unlock(lock: &aspeed->lock); |
287 | return ret; |
288 | } |
289 | |
290 | static int aspeed_master_write(struct fsi_master *master, int link, |
291 | uint8_t id, uint32_t addr, const void *val, size_t size) |
292 | { |
293 | struct fsi_master_aspeed *aspeed = to_fsi_master_aspeed(master); |
294 | int ret; |
295 | |
296 | if (id > 0x3) |
297 | return -EINVAL; |
298 | |
299 | addr |= id << 21; |
300 | addr += link * FSI_HUB_LINK_SIZE; |
301 | |
302 | mutex_lock(&aspeed->lock); |
303 | |
304 | switch (size) { |
305 | case 1: |
306 | ret = opb_writeb(aspeed, addr: fsi_base + addr, val: *(u8 *)val); |
307 | break; |
308 | case 2: |
309 | ret = opb_writew(aspeed, addr: fsi_base + addr, val: *(__be16 *)val); |
310 | break; |
311 | case 4: |
312 | ret = opb_writel(aspeed, addr: fsi_base + addr, val: *(__be32 *)val); |
313 | break; |
314 | default: |
315 | ret = -EINVAL; |
316 | goto done; |
317 | } |
318 | |
319 | ret = check_errors(aspeed, err: ret); |
320 | done: |
321 | mutex_unlock(lock: &aspeed->lock); |
322 | return ret; |
323 | } |
324 | |
325 | static int aspeed_master_link_enable(struct fsi_master *master, int link, |
326 | bool enable) |
327 | { |
328 | struct fsi_master_aspeed *aspeed = to_fsi_master_aspeed(master); |
329 | int idx, bit, ret; |
330 | __be32 reg; |
331 | |
332 | idx = link / 32; |
333 | bit = link % 32; |
334 | |
335 | reg = cpu_to_be32(0x80000000 >> bit); |
336 | |
337 | mutex_lock(&aspeed->lock); |
338 | |
339 | if (!enable) { |
340 | ret = opb_writel(aspeed, addr: ctrl_base + FSI_MCENP0 + (4 * idx), val: reg); |
341 | goto done; |
342 | } |
343 | |
344 | ret = opb_writel(aspeed, addr: ctrl_base + FSI_MSENP0 + (4 * idx), val: reg); |
345 | if (ret) |
346 | goto done; |
347 | |
348 | mdelay(FSI_LINK_ENABLE_SETUP_TIME); |
349 | done: |
350 | mutex_unlock(lock: &aspeed->lock); |
351 | return ret; |
352 | } |
353 | |
354 | static int aspeed_master_term(struct fsi_master *master, int link, uint8_t id) |
355 | { |
356 | uint32_t addr; |
357 | __be32 cmd; |
358 | |
359 | addr = 0x4; |
360 | cmd = cpu_to_be32(0xecc00000); |
361 | |
362 | return aspeed_master_write(master, link, id, addr, val: &cmd, size: 4); |
363 | } |
364 | |
365 | static int aspeed_master_break(struct fsi_master *master, int link) |
366 | { |
367 | uint32_t addr; |
368 | __be32 cmd; |
369 | |
370 | addr = 0x0; |
371 | cmd = cpu_to_be32(0xc0de0000); |
372 | |
373 | return aspeed_master_write(master, link, id: 0, addr, val: &cmd, size: 4); |
374 | } |
375 | |
376 | static void aspeed_master_release(struct device *dev) |
377 | { |
378 | struct fsi_master_aspeed *aspeed = |
379 | to_fsi_master_aspeed(to_fsi_master(dev)); |
380 | |
381 | kfree(objp: aspeed); |
382 | } |
383 | |
384 | /* mmode encoders */ |
385 | static inline u32 fsi_mmode_crs0(u32 x) |
386 | { |
387 | return (x & FSI_MMODE_CRS0MASK) << FSI_MMODE_CRS0SHFT; |
388 | } |
389 | |
390 | static inline u32 fsi_mmode_crs1(u32 x) |
391 | { |
392 | return (x & FSI_MMODE_CRS1MASK) << FSI_MMODE_CRS1SHFT; |
393 | } |
394 | |
395 | static int aspeed_master_init(struct fsi_master_aspeed *aspeed) |
396 | { |
397 | __be32 reg; |
398 | |
399 | reg = cpu_to_be32(FSI_MRESP_RST_ALL_MASTER | FSI_MRESP_RST_ALL_LINK |
400 | | FSI_MRESP_RST_MCR | FSI_MRESP_RST_PYE); |
401 | opb_writel(aspeed, addr: ctrl_base + FSI_MRESP0, val: reg); |
402 | |
403 | /* Initialize the MFSI (hub master) engine */ |
404 | reg = cpu_to_be32(FSI_MRESP_RST_ALL_MASTER | FSI_MRESP_RST_ALL_LINK |
405 | | FSI_MRESP_RST_MCR | FSI_MRESP_RST_PYE); |
406 | opb_writel(aspeed, addr: ctrl_base + FSI_MRESP0, val: reg); |
407 | |
408 | reg = cpu_to_be32(FSI_MECTRL_EOAE | FSI_MECTRL_P8_AUTO_TERM); |
409 | opb_writel(aspeed, addr: ctrl_base + FSI_MECTRL, val: reg); |
410 | |
411 | reg = cpu_to_be32(FSI_MMODE_ECRC | FSI_MMODE_EPC | FSI_MMODE_RELA |
412 | | fsi_mmode_crs0(aspeed_fsi_divisor) |
413 | | fsi_mmode_crs1(aspeed_fsi_divisor) |
414 | | FSI_MMODE_P8_TO_LSB); |
415 | dev_info(aspeed->dev, "mmode set to %08x (divisor %d)\n" , |
416 | be32_to_cpu(reg), aspeed_fsi_divisor); |
417 | opb_writel(aspeed, addr: ctrl_base + FSI_MMODE, val: reg); |
418 | |
419 | reg = cpu_to_be32(0xffff0000); |
420 | opb_writel(aspeed, addr: ctrl_base + FSI_MDLYR, val: reg); |
421 | |
422 | reg = cpu_to_be32(~0); |
423 | opb_writel(aspeed, addr: ctrl_base + FSI_MSENP0, val: reg); |
424 | |
425 | /* Leave enabled long enough for master logic to set up */ |
426 | mdelay(FSI_LINK_ENABLE_SETUP_TIME); |
427 | |
428 | opb_writel(aspeed, addr: ctrl_base + FSI_MCENP0, val: reg); |
429 | |
430 | opb_readl(aspeed, addr: ctrl_base + FSI_MAEB, NULL); |
431 | |
432 | reg = cpu_to_be32(FSI_MRESP_RST_ALL_MASTER | FSI_MRESP_RST_ALL_LINK); |
433 | opb_writel(aspeed, addr: ctrl_base + FSI_MRESP0, val: reg); |
434 | |
435 | opb_readl(aspeed, addr: ctrl_base + FSI_MLEVP0, NULL); |
436 | |
437 | /* Reset the master bridge */ |
438 | reg = cpu_to_be32(FSI_MRESB_RST_GEN); |
439 | opb_writel(aspeed, addr: ctrl_base + FSI_MRESB0, val: reg); |
440 | |
441 | reg = cpu_to_be32(FSI_MRESB_RST_ERR); |
442 | opb_writel(aspeed, addr: ctrl_base + FSI_MRESB0, val: reg); |
443 | |
444 | return 0; |
445 | } |
446 | |
447 | static ssize_t cfam_reset_store(struct device *dev, struct device_attribute *attr, |
448 | const char *buf, size_t count) |
449 | { |
450 | struct fsi_master_aspeed *aspeed = dev_get_drvdata(dev); |
451 | |
452 | trace_fsi_master_aspeed_cfam_reset(start: true); |
453 | mutex_lock(&aspeed->lock); |
454 | gpiod_set_value(desc: aspeed->cfam_reset_gpio, value: 1); |
455 | usleep_range(min: 900, max: 1000); |
456 | gpiod_set_value(desc: aspeed->cfam_reset_gpio, value: 0); |
457 | usleep_range(min: 900, max: 1000); |
458 | opb_writel(aspeed, addr: ctrl_base + FSI_MRESP0, cpu_to_be32(FSI_MRESP_RST_ALL_MASTER)); |
459 | mutex_unlock(lock: &aspeed->lock); |
460 | trace_fsi_master_aspeed_cfam_reset(start: false); |
461 | |
462 | return count; |
463 | } |
464 | |
465 | static DEVICE_ATTR(cfam_reset, 0200, NULL, cfam_reset_store); |
466 | |
467 | static int setup_cfam_reset(struct fsi_master_aspeed *aspeed) |
468 | { |
469 | struct device *dev = aspeed->dev; |
470 | struct gpio_desc *gpio; |
471 | int rc; |
472 | |
473 | gpio = devm_gpiod_get_optional(dev, con_id: "cfam-reset" , flags: GPIOD_OUT_LOW); |
474 | if (IS_ERR(ptr: gpio)) |
475 | return PTR_ERR(ptr: gpio); |
476 | if (!gpio) |
477 | return 0; |
478 | |
479 | aspeed->cfam_reset_gpio = gpio; |
480 | |
481 | rc = device_create_file(device: dev, entry: &dev_attr_cfam_reset); |
482 | if (rc) { |
483 | devm_gpiod_put(dev, desc: gpio); |
484 | return rc; |
485 | } |
486 | |
487 | return 0; |
488 | } |
489 | |
490 | static int tacoma_cabled_fsi_fixup(struct device *dev) |
491 | { |
492 | struct gpio_desc *routing_gpio, *mux_gpio; |
493 | int gpio; |
494 | |
495 | /* |
496 | * The routing GPIO is a jumper indicating we should mux for the |
497 | * externally connected FSI cable. |
498 | */ |
499 | routing_gpio = devm_gpiod_get_optional(dev, con_id: "fsi-routing" , |
500 | flags: GPIOD_IN | GPIOD_FLAGS_BIT_NONEXCLUSIVE); |
501 | if (IS_ERR(ptr: routing_gpio)) |
502 | return PTR_ERR(ptr: routing_gpio); |
503 | if (!routing_gpio) |
504 | return 0; |
505 | |
506 | mux_gpio = devm_gpiod_get_optional(dev, con_id: "fsi-mux" , flags: GPIOD_ASIS); |
507 | if (IS_ERR(ptr: mux_gpio)) |
508 | return PTR_ERR(ptr: mux_gpio); |
509 | if (!mux_gpio) |
510 | return 0; |
511 | |
512 | gpio = gpiod_get_value(desc: routing_gpio); |
513 | if (gpio < 0) |
514 | return gpio; |
515 | |
516 | /* If the routing GPIO is high we should set the mux to low. */ |
517 | if (gpio) { |
518 | /* |
519 | * Cable signal integrity means we should run the bus |
520 | * slightly slower. Do not override if a kernel param |
521 | * has already overridden. |
522 | */ |
523 | if (aspeed_fsi_divisor == FSI_DIVISOR_DEFAULT) |
524 | aspeed_fsi_divisor = FSI_DIVISOR_CABLED; |
525 | |
526 | gpiod_direction_output(desc: mux_gpio, value: 0); |
527 | dev_info(dev, "FSI configured for external cable\n" ); |
528 | } else { |
529 | gpiod_direction_output(desc: mux_gpio, value: 1); |
530 | } |
531 | |
532 | devm_gpiod_put(dev, desc: routing_gpio); |
533 | |
534 | return 0; |
535 | } |
536 | |
537 | static int fsi_master_aspeed_probe(struct platform_device *pdev) |
538 | { |
539 | struct fsi_master_aspeed *aspeed; |
540 | int rc, links, reg; |
541 | __be32 raw; |
542 | |
543 | rc = tacoma_cabled_fsi_fixup(dev: &pdev->dev); |
544 | if (rc) { |
545 | dev_err(&pdev->dev, "Tacoma FSI cable fixup failed\n" ); |
546 | return rc; |
547 | } |
548 | |
549 | aspeed = kzalloc(size: sizeof(*aspeed), GFP_KERNEL); |
550 | if (!aspeed) |
551 | return -ENOMEM; |
552 | |
553 | aspeed->dev = &pdev->dev; |
554 | |
555 | aspeed->base = devm_platform_ioremap_resource(pdev, index: 0); |
556 | if (IS_ERR(ptr: aspeed->base)) { |
557 | rc = PTR_ERR(ptr: aspeed->base); |
558 | goto err_free_aspeed; |
559 | } |
560 | |
561 | aspeed->clk = devm_clk_get(dev: aspeed->dev, NULL); |
562 | if (IS_ERR(ptr: aspeed->clk)) { |
563 | dev_err(aspeed->dev, "couldn't get clock\n" ); |
564 | rc = PTR_ERR(ptr: aspeed->clk); |
565 | goto err_free_aspeed; |
566 | } |
567 | rc = clk_prepare_enable(clk: aspeed->clk); |
568 | if (rc) { |
569 | dev_err(aspeed->dev, "couldn't enable clock\n" ); |
570 | goto err_free_aspeed; |
571 | } |
572 | |
573 | rc = setup_cfam_reset(aspeed); |
574 | if (rc) { |
575 | dev_err(&pdev->dev, "CFAM reset GPIO setup failed\n" ); |
576 | } |
577 | |
578 | writel(val: 0x1, addr: aspeed->base + OPB_CLK_SYNC); |
579 | writel(OPB1_XFER_ACK_EN | OPB0_XFER_ACK_EN, |
580 | addr: aspeed->base + OPB_IRQ_MASK); |
581 | |
582 | /* TODO: determine an appropriate value */ |
583 | writel(val: 0x10, addr: aspeed->base + OPB_RETRY_COUNTER); |
584 | |
585 | writel(val: ctrl_base, addr: aspeed->base + OPB_CTRL_BASE); |
586 | writel(val: fsi_base, addr: aspeed->base + OPB_FSI_BASE); |
587 | |
588 | /* Set read data order */ |
589 | writel(val: 0x00030b1b, addr: aspeed->base + OPB0_READ_ORDER1); |
590 | |
591 | /* Set write data order */ |
592 | writel(val: 0x0011101b, addr: aspeed->base + OPB0_WRITE_ORDER1); |
593 | writel(val: 0x0c330f3f, addr: aspeed->base + OPB0_WRITE_ORDER2); |
594 | |
595 | /* |
596 | * Select OPB0 for all operations. |
597 | * Will need to be reworked when enabling DMA or anything that uses |
598 | * OPB1. |
599 | */ |
600 | writel(val: 0x1, addr: aspeed->base + OPB0_SELECT); |
601 | |
602 | rc = opb_readl(aspeed, addr: ctrl_base + FSI_MVER, out: &raw); |
603 | if (rc) { |
604 | dev_err(&pdev->dev, "failed to read hub version\n" ); |
605 | goto err_release; |
606 | } |
607 | |
608 | reg = be32_to_cpu(raw); |
609 | links = (reg >> 8) & 0xff; |
610 | dev_info(&pdev->dev, "hub version %08x (%d links)\n" , reg, links); |
611 | |
612 | aspeed->master.dev.parent = &pdev->dev; |
613 | aspeed->master.dev.release = aspeed_master_release; |
614 | aspeed->master.dev.of_node = of_node_get(node: dev_of_node(dev: &pdev->dev)); |
615 | |
616 | aspeed->master.n_links = links; |
617 | aspeed->master.read = aspeed_master_read; |
618 | aspeed->master.write = aspeed_master_write; |
619 | aspeed->master.send_break = aspeed_master_break; |
620 | aspeed->master.term = aspeed_master_term; |
621 | aspeed->master.link_enable = aspeed_master_link_enable; |
622 | |
623 | dev_set_drvdata(dev: &pdev->dev, data: aspeed); |
624 | |
625 | mutex_init(&aspeed->lock); |
626 | aspeed_master_init(aspeed); |
627 | |
628 | rc = fsi_master_register(master: &aspeed->master); |
629 | if (rc) |
630 | goto err_release; |
631 | |
632 | /* At this point, fsi_master_register performs the device_initialize(), |
633 | * and holds the sole reference on master.dev. This means the device |
634 | * will be freed (via ->release) during any subsequent call to |
635 | * fsi_master_unregister. We add our own reference to it here, so we |
636 | * can perform cleanup (in _remove()) without it being freed before |
637 | * we're ready. |
638 | */ |
639 | get_device(dev: &aspeed->master.dev); |
640 | return 0; |
641 | |
642 | err_release: |
643 | clk_disable_unprepare(clk: aspeed->clk); |
644 | err_free_aspeed: |
645 | kfree(objp: aspeed); |
646 | return rc; |
647 | } |
648 | |
649 | static int fsi_master_aspeed_remove(struct platform_device *pdev) |
650 | { |
651 | struct fsi_master_aspeed *aspeed = platform_get_drvdata(pdev); |
652 | |
653 | fsi_master_unregister(master: &aspeed->master); |
654 | clk_disable_unprepare(clk: aspeed->clk); |
655 | |
656 | return 0; |
657 | } |
658 | |
659 | static const struct of_device_id fsi_master_aspeed_match[] = { |
660 | { .compatible = "aspeed,ast2600-fsi-master" }, |
661 | { }, |
662 | }; |
663 | MODULE_DEVICE_TABLE(of, fsi_master_aspeed_match); |
664 | |
665 | static struct platform_driver fsi_master_aspeed_driver = { |
666 | .driver = { |
667 | .name = "fsi-master-aspeed" , |
668 | .of_match_table = fsi_master_aspeed_match, |
669 | }, |
670 | .probe = fsi_master_aspeed_probe, |
671 | .remove = fsi_master_aspeed_remove, |
672 | }; |
673 | |
674 | module_platform_driver(fsi_master_aspeed_driver); |
675 | MODULE_LICENSE("GPL" ); |
676 | |