Commit | Line | Data |
---|---|---|
606397d6 JS |
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> | |
dfd7f2c1 | 11 | #include <linux/mutex.h> |
606397d6 JS |
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> | |
f369a29b | 17 | #include <linux/gpio/consumer.h> |
606397d6 JS |
18 | |
19 | #include "fsi-master.h" | |
20 | ||
21 | struct fsi_master_aspeed { | |
22 | struct fsi_master master; | |
dfd7f2c1 | 23 | struct mutex lock; /* protect HW access */ |
606397d6 JS |
24 | struct device *dev; |
25 | void __iomem *base; | |
26 | struct clk *clk; | |
4a851d71 | 27 | struct gpio_desc *cfam_reset_gpio; |
606397d6 JS |
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 | ||
913b7373 JS |
84 | #define CREATE_TRACE_POINTS |
85 | #include <trace/events/fsi_master_aspeed.h> | |
86 | ||
606397d6 JS |
87 | #define FSI_LINK_ENABLE_SETUP_TIME 10 /* in mS */ |
88 | ||
4a80c201 JS |
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; | |
add68951 | 93 | module_param_named(bus_div,aspeed_fsi_divisor, ushort, 0); |
4a80c201 | 94 | |
1e2233d4 | 95 | #define OPB_POLL_TIMEOUT 500 |
606397d6 JS |
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 | ||
4134cb91 JS |
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); | |
606397d6 JS |
113 | writel(0x1, 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(base + OPB0_STATUS); | |
120 | ||
913b7373 JS |
121 | trace_fsi_master_aspeed_opb_write(addr, val, transfer_size, status, reg); |
122 | ||
606397d6 JS |
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, (__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, (__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 | ||
4134cb91 JS |
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); | |
606397d6 JS |
164 | writel(0x1, 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(base + OPB0_STATUS); | |
171 | ||
172 | result = readl(base + OPB0_FSI_DATA_R); | |
173 | ||
913b7373 JS |
174 | trace_fsi_master_aspeed_opb_read(addr, transfer_size, result, |
175 | readl(base + OPB0_STATUS), | |
176 | reg); | |
177 | ||
606397d6 JS |
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, (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, (void *)out); | |
219 | } | |
220 | ||
221 | static int check_errors(struct fsi_master_aspeed *aspeed, int err) | |
222 | { | |
223 | int ret; | |
224 | ||
913b7373 JS |
225 | if (trace_fsi_master_aspeed_opb_error_enabled()) { |
226 | __be32 mresp0, mstap0, mesrb0; | |
227 | ||
228 | opb_readl(aspeed, ctrl_base + FSI_MRESP0, &mresp0); | |
229 | opb_readl(aspeed, ctrl_base + FSI_MSTAP0, &mstap0); | |
230 | opb_readl(aspeed, ctrl_base + FSI_MESRB0, &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 | ||
606397d6 JS |
238 | if (err == -EIO) { |
239 | /* Check MAEB (0x70) ? */ | |
240 | ||
241 | /* Then clear errors in master */ | |
242 | ret = opb_writel(aspeed, 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 | ||
6e0ef7d2 | 261 | if (id > 0x3) |
606397d6 JS |
262 | return -EINVAL; |
263 | ||
6e0ef7d2 | 264 | addr |= id << 21; |
606397d6 JS |
265 | addr += link * FSI_HUB_LINK_SIZE; |
266 | ||
dfd7f2c1 EJ |
267 | mutex_lock(&aspeed->lock); |
268 | ||
606397d6 JS |
269 | switch (size) { |
270 | case 1: | |
271 | ret = opb_readb(aspeed, fsi_base + addr, val); | |
272 | break; | |
273 | case 2: | |
274 | ret = opb_readw(aspeed, fsi_base + addr, val); | |
275 | break; | |
276 | case 4: | |
277 | ret = opb_readl(aspeed, fsi_base + addr, val); | |
278 | break; | |
279 | default: | |
dfd7f2c1 EJ |
280 | ret = -EINVAL; |
281 | goto done; | |
606397d6 JS |
282 | } |
283 | ||
284 | ret = check_errors(aspeed, ret); | |
dfd7f2c1 EJ |
285 | done: |
286 | mutex_unlock(&aspeed->lock); | |
287 | return ret; | |
606397d6 JS |
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 | ||
6e0ef7d2 | 296 | if (id > 0x3) |
606397d6 JS |
297 | return -EINVAL; |
298 | ||
6e0ef7d2 | 299 | addr |= id << 21; |
606397d6 JS |
300 | addr += link * FSI_HUB_LINK_SIZE; |
301 | ||
dfd7f2c1 EJ |
302 | mutex_lock(&aspeed->lock); |
303 | ||
606397d6 JS |
304 | switch (size) { |
305 | case 1: | |
306 | ret = opb_writeb(aspeed, fsi_base + addr, *(u8 *)val); | |
307 | break; | |
308 | case 2: | |
309 | ret = opb_writew(aspeed, fsi_base + addr, *(__be16 *)val); | |
310 | break; | |
311 | case 4: | |
312 | ret = opb_writel(aspeed, fsi_base + addr, *(__be32 *)val); | |
313 | break; | |
314 | default: | |
dfd7f2c1 EJ |
315 | ret = -EINVAL; |
316 | goto done; | |
606397d6 JS |
317 | } |
318 | ||
319 | ret = check_errors(aspeed, ret); | |
dfd7f2c1 EJ |
320 | done: |
321 | mutex_unlock(&aspeed->lock); | |
322 | return ret; | |
606397d6 JS |
323 | } |
324 | ||
04635a30 EJ |
325 | static int aspeed_master_link_enable(struct fsi_master *master, int link, |
326 | bool enable) | |
606397d6 JS |
327 | { |
328 | struct fsi_master_aspeed *aspeed = to_fsi_master_aspeed(master); | |
329 | int idx, bit, ret; | |
a1d5ce11 | 330 | __be32 reg; |
606397d6 JS |
331 | |
332 | idx = link / 32; | |
333 | bit = link % 32; | |
334 | ||
335 | reg = cpu_to_be32(0x80000000 >> bit); | |
336 | ||
dfd7f2c1 EJ |
337 | mutex_lock(&aspeed->lock); |
338 | ||
339 | if (!enable) { | |
340 | ret = opb_writel(aspeed, ctrl_base + FSI_MCENP0 + (4 * idx), reg); | |
341 | goto done; | |
342 | } | |
04635a30 | 343 | |
606397d6 JS |
344 | ret = opb_writel(aspeed, ctrl_base + FSI_MSENP0 + (4 * idx), reg); |
345 | if (ret) | |
dfd7f2c1 | 346 | goto done; |
606397d6 JS |
347 | |
348 | mdelay(FSI_LINK_ENABLE_SETUP_TIME); | |
dfd7f2c1 EJ |
349 | done: |
350 | mutex_unlock(&aspeed->lock); | |
351 | return ret; | |
606397d6 JS |
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, &cmd, 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, 0, addr, &cmd, 4); | |
374 | } | |
375 | ||
376 | static void aspeed_master_release(struct device *dev) | |
377 | { | |
378 | struct fsi_master_aspeed *aspeed = | |
d5d8dfb0 | 379 | to_fsi_master_aspeed(to_fsi_master(dev)); |
606397d6 JS |
380 | |
381 | kfree(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, ctrl_base + FSI_MRESP0, 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, ctrl_base + FSI_MRESP0, reg); | |
407 | ||
408 | reg = cpu_to_be32(FSI_MECTRL_EOAE | FSI_MECTRL_P8_AUTO_TERM); | |
409 | opb_writel(aspeed, ctrl_base + FSI_MECTRL, reg); | |
410 | ||
411 | reg = cpu_to_be32(FSI_MMODE_ECRC | FSI_MMODE_EPC | FSI_MMODE_RELA | |
4a80c201 JS |
412 | | fsi_mmode_crs0(aspeed_fsi_divisor) |
413 | | fsi_mmode_crs1(aspeed_fsi_divisor) | |
606397d6 | 414 | | FSI_MMODE_P8_TO_LSB); |
4a80c201 JS |
415 | dev_info(aspeed->dev, "mmode set to %08x (divisor %d)\n", |
416 | be32_to_cpu(reg), aspeed_fsi_divisor); | |
606397d6 JS |
417 | opb_writel(aspeed, ctrl_base + FSI_MMODE, reg); |
418 | ||
419 | reg = cpu_to_be32(0xffff0000); | |
420 | opb_writel(aspeed, ctrl_base + FSI_MDLYR, reg); | |
421 | ||
422 | reg = cpu_to_be32(~0); | |
423 | opb_writel(aspeed, ctrl_base + FSI_MSENP0, 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, ctrl_base + FSI_MCENP0, reg); | |
429 | ||
430 | opb_readl(aspeed, 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, ctrl_base + FSI_MRESP0, reg); | |
434 | ||
435 | opb_readl(aspeed, ctrl_base + FSI_MLEVP0, NULL); | |
436 | ||
437 | /* Reset the master bridge */ | |
438 | reg = cpu_to_be32(FSI_MRESB_RST_GEN); | |
439 | opb_writel(aspeed, ctrl_base + FSI_MRESB0, reg); | |
440 | ||
441 | reg = cpu_to_be32(FSI_MRESB_RST_ERR); | |
442 | opb_writel(aspeed, ctrl_base + FSI_MRESB0, reg); | |
443 | ||
444 | return 0; | |
445 | } | |
446 | ||
4a851d71 JS |
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 | ||
f2af60bb | 452 | trace_fsi_master_aspeed_cfam_reset(true); |
dfd7f2c1 | 453 | mutex_lock(&aspeed->lock); |
4a851d71 JS |
454 | gpiod_set_value(aspeed->cfam_reset_gpio, 1); |
455 | usleep_range(900, 1000); | |
456 | gpiod_set_value(aspeed->cfam_reset_gpio, 0); | |
52300909 EJ |
457 | usleep_range(900, 1000); |
458 | opb_writel(aspeed, ctrl_base + FSI_MRESP0, cpu_to_be32(FSI_MRESP_RST_ALL_MASTER)); | |
dfd7f2c1 | 459 | mutex_unlock(&aspeed->lock); |
f2af60bb | 460 | trace_fsi_master_aspeed_cfam_reset(false); |
4a851d71 JS |
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, "cfam-reset", GPIOD_OUT_LOW); | |
474 | if (IS_ERR(gpio)) | |
475 | return PTR_ERR(gpio); | |
476 | if (!gpio) | |
477 | return 0; | |
478 | ||
479 | aspeed->cfam_reset_gpio = gpio; | |
480 | ||
481 | rc = device_create_file(dev, &dev_attr_cfam_reset); | |
482 | if (rc) { | |
483 | devm_gpiod_put(dev, gpio); | |
484 | return rc; | |
485 | } | |
486 | ||
487 | return 0; | |
488 | } | |
489 | ||
f369a29b JS |
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, "fsi-routing", | |
500 | GPIOD_IN | GPIOD_FLAGS_BIT_NONEXCLUSIVE); | |
501 | if (IS_ERR(routing_gpio)) | |
502 | return PTR_ERR(routing_gpio); | |
503 | if (!routing_gpio) | |
504 | return 0; | |
505 | ||
506 | mux_gpio = devm_gpiod_get_optional(dev, "fsi-mux", GPIOD_ASIS); | |
507 | if (IS_ERR(mux_gpio)) | |
508 | return PTR_ERR(mux_gpio); | |
509 | if (!mux_gpio) | |
510 | return 0; | |
511 | ||
512 | gpio = gpiod_get_value(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) { | |
4a80c201 JS |
518 | /* |
519 | * Cable signal integrity means we should run the bus | |
add68951 JS |
520 | * slightly slower. Do not override if a kernel param |
521 | * has already overridden. | |
4a80c201 | 522 | */ |
add68951 JS |
523 | if (aspeed_fsi_divisor == FSI_DIVISOR_DEFAULT) |
524 | aspeed_fsi_divisor = FSI_DIVISOR_CABLED; | |
525 | ||
f369a29b JS |
526 | gpiod_direction_output(mux_gpio, 0); |
527 | dev_info(dev, "FSI configured for external cable\n"); | |
528 | } else { | |
529 | gpiod_direction_output(mux_gpio, 1); | |
530 | } | |
531 | ||
532 | devm_gpiod_put(dev, routing_gpio); | |
533 | ||
534 | return 0; | |
535 | } | |
536 | ||
606397d6 JS |
537 | static int fsi_master_aspeed_probe(struct platform_device *pdev) |
538 | { | |
539 | struct fsi_master_aspeed *aspeed; | |
606397d6 JS |
540 | int rc, links, reg; |
541 | __be32 raw; | |
542 | ||
f369a29b JS |
543 | rc = tacoma_cabled_fsi_fixup(&pdev->dev); |
544 | if (rc) { | |
545 | dev_err(&pdev->dev, "Tacoma FSI cable fixup failed\n"); | |
546 | return rc; | |
547 | } | |
548 | ||
83ba7e89 | 549 | aspeed = kzalloc(sizeof(*aspeed), GFP_KERNEL); |
606397d6 JS |
550 | if (!aspeed) |
551 | return -ENOMEM; | |
552 | ||
553 | aspeed->dev = &pdev->dev; | |
554 | ||
a3469912 | 555 | aspeed->base = devm_platform_ioremap_resource(pdev, 0); |
83ba7e89 CJ |
556 | if (IS_ERR(aspeed->base)) { |
557 | rc = PTR_ERR(aspeed->base); | |
558 | goto err_free_aspeed; | |
559 | } | |
606397d6 JS |
560 | |
561 | aspeed->clk = devm_clk_get(aspeed->dev, NULL); | |
562 | if (IS_ERR(aspeed->clk)) { | |
563 | dev_err(aspeed->dev, "couldn't get clock\n"); | |
83ba7e89 CJ |
564 | rc = PTR_ERR(aspeed->clk); |
565 | goto err_free_aspeed; | |
606397d6 JS |
566 | } |
567 | rc = clk_prepare_enable(aspeed->clk); | |
568 | if (rc) { | |
569 | dev_err(aspeed->dev, "couldn't enable clock\n"); | |
83ba7e89 | 570 | goto err_free_aspeed; |
606397d6 JS |
571 | } |
572 | ||
4a851d71 JS |
573 | rc = setup_cfam_reset(aspeed); |
574 | if (rc) { | |
575 | dev_err(&pdev->dev, "CFAM reset GPIO setup failed\n"); | |
576 | } | |
577 | ||
606397d6 JS |
578 | writel(0x1, aspeed->base + OPB_CLK_SYNC); |
579 | writel(OPB1_XFER_ACK_EN | OPB0_XFER_ACK_EN, | |
580 | aspeed->base + OPB_IRQ_MASK); | |
581 | ||
582 | /* TODO: determine an appropriate value */ | |
583 | writel(0x10, aspeed->base + OPB_RETRY_COUNTER); | |
584 | ||
585 | writel(ctrl_base, aspeed->base + OPB_CTRL_BASE); | |
586 | writel(fsi_base, aspeed->base + OPB_FSI_BASE); | |
587 | ||
588 | /* Set read data order */ | |
5e502299 | 589 | writel(0x00030b1b, aspeed->base + OPB0_READ_ORDER1); |
606397d6 JS |
590 | |
591 | /* Set write data order */ | |
5e502299 AJ |
592 | writel(0x0011101b, aspeed->base + OPB0_WRITE_ORDER1); |
593 | writel(0x0c330f3f, aspeed->base + OPB0_WRITE_ORDER2); | |
606397d6 JS |
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(0x1, aspeed->base + OPB0_SELECT); | |
601 | ||
602 | rc = opb_readl(aspeed, ctrl_base + FSI_MVER, &raw); | |
603 | if (rc) { | |
604 | dev_err(&pdev->dev, "failed to read hub version\n"); | |
83ba7e89 | 605 | goto err_release; |
606397d6 JS |
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(dev_of_node(&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(&pdev->dev, aspeed); | |
624 | ||
dfd7f2c1 | 625 | mutex_init(&aspeed->lock); |
606397d6 JS |
626 | aspeed_master_init(aspeed); |
627 | ||
628 | rc = fsi_master_register(&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(&aspeed->master.dev); | |
640 | return 0; | |
641 | ||
642 | err_release: | |
643 | clk_disable_unprepare(aspeed->clk); | |
83ba7e89 CJ |
644 | err_free_aspeed: |
645 | kfree(aspeed); | |
606397d6 JS |
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(&aspeed->master); | |
654 | clk_disable_unprepare(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 | }; | |
19a52178 | 663 | MODULE_DEVICE_TABLE(of, fsi_master_aspeed_match); |
606397d6 JS |
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"); |