Commit | Line | Data |
---|---|---|
2874c5fd | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2b0c28d7 | 2 | /* |
d02443a6 | 3 | * Freescale MPC85xx/MPC86xx RapidIO support |
2b0c28d7 | 4 | * |
bd4fb654 TM |
5 | * Copyright 2009 Sysgo AG |
6 | * Thomas Moll <thomas.moll@sysgo.com> | |
7 | * - fixed maintenance access routines, check for aligned access | |
8 | * | |
5b2074ae AB |
9 | * Copyright 2009 Integrated Device Technology, Inc. |
10 | * Alex Bounine <alexandre.bounine@idt.com> | |
11 | * - Added Port-Write message handling | |
12 | * - Added Machine Check exception handling | |
13 | * | |
6ec4bedb | 14 | * Copyright (C) 2007, 2008, 2010, 2011 Freescale Semiconductor, Inc. |
ad1e9380 ZW |
15 | * Zhang Wei <wei.zhang@freescale.com> |
16 | * | |
2b0c28d7 MP |
17 | * Copyright 2005 MontaVista Software, Inc. |
18 | * Matt Porter <mporter@kernel.crashing.org> | |
2b0c28d7 MP |
19 | */ |
20 | ||
2b0c28d7 | 21 | #include <linux/init.h> |
8a39b05f | 22 | #include <linux/extable.h> |
2b0c28d7 MP |
23 | #include <linux/types.h> |
24 | #include <linux/dma-mapping.h> | |
25 | #include <linux/interrupt.h> | |
81d7cac4 | 26 | #include <linux/of.h> |
26a2056e RH |
27 | #include <linux/of_address.h> |
28 | #include <linux/of_irq.h> | |
81d7cac4 | 29 | #include <linux/platform_device.h> |
61b26917 | 30 | #include <linux/delay.h> |
5a0e3ad6 | 31 | #include <linux/slab.h> |
2b0c28d7 | 32 | |
6ec4bedb LG |
33 | #include <linux/io.h> |
34 | #include <linux/uaccess.h> | |
a52c8f52 | 35 | #include <asm/machdep.h> |
c265735f | 36 | #include <asm/rio.h> |
2b0c28d7 | 37 | |
6ec4bedb | 38 | #include "fsl_rio.h" |
5b2074ae | 39 | |
6ec4bedb | 40 | #undef DEBUG_PW /* Port-Write debugging */ |
6ff31453 SX |
41 | |
42 | #define RIO_PORT1_EDCSR 0x0640 | |
43 | #define RIO_PORT2_EDCSR 0x0680 | |
44 | #define RIO_PORT1_IECSR 0x10130 | |
45 | #define RIO_PORT2_IECSR 0x101B0 | |
6ff31453 | 46 | |
af84ca38 | 47 | #define RIO_GCCSR 0x13c |
61b26917 | 48 | #define RIO_ESCSR 0x158 |
6ec4bedb | 49 | #define ESCSR_CLEAR 0x07120204 |
6ff31453 | 50 | #define RIO_PORT2_ESCSR 0x178 |
61b26917 | 51 | #define RIO_CCSR 0x15c |
6ff31453 SX |
52 | #define RIO_LTLEDCSR_IER 0x80000000 |
53 | #define RIO_LTLEDCSR_PRT 0x01000000 | |
6ec4bedb | 54 | #define IECSR_CLEAR 0x80000000 |
61b26917 ZW |
55 | #define RIO_ISR_AACR 0x10120 |
56 | #define RIO_ISR_AACR_AA 0x1 /* Accept All ID */ | |
2b0c28d7 | 57 | |
e6a546fd MG |
58 | #define RIWTAR_TRAD_VAL_SHIFT 12 |
59 | #define RIWTAR_TRAD_MASK 0x00FFFFFF | |
60 | #define RIWBAR_BADD_VAL_SHIFT 12 | |
61 | #define RIWBAR_BADD_MASK 0x003FFFFF | |
62 | #define RIWAR_ENABLE 0x80000000 | |
63 | #define RIWAR_TGINT_LOCAL 0x00F00000 | |
64 | #define RIWAR_RDTYP_NO_SNOOP 0x00040000 | |
65 | #define RIWAR_RDTYP_SNOOP 0x00050000 | |
66 | #define RIWAR_WRTYP_NO_SNOOP 0x00004000 | |
67 | #define RIWAR_WRTYP_SNOOP 0x00005000 | |
68 | #define RIWAR_WRTYP_ALLOC 0x00006000 | |
69 | #define RIWAR_SIZE_MASK 0x0000003F | |
70 | ||
31d1e130 IN |
71 | static DEFINE_SPINLOCK(fsl_rio_config_lock); |
72 | ||
2255411d | 73 | #define ___fsl_read_rio_config(x, addr, err, op, barrier) \ |
a52c8f52 AB |
74 | __asm__ __volatile__( \ |
75 | "1: "op" %1,0(%2)\n" \ | |
2255411d | 76 | " "barrier"\n" \ |
a52c8f52 AB |
77 | "2:\n" \ |
78 | ".section .fixup,\"ax\"\n" \ | |
79 | "3: li %1,-1\n" \ | |
80 | " li %0,%3\n" \ | |
81 | " b 2b\n" \ | |
24bfa6a9 NP |
82 | ".previous\n" \ |
83 | EX_TABLE(1b, 3b) \ | |
a52c8f52 AB |
84 | : "=r" (err), "=r" (x) \ |
85 | : "b" (addr), "i" (-EFAULT), "0" (err)) | |
86 | ||
2255411d CL |
87 | #ifdef CONFIG_BOOKE |
88 | #define __fsl_read_rio_config(x, addr, err, op) \ | |
89 | ___fsl_read_rio_config(x, addr, err, op, "mbar") | |
90 | #else | |
91 | #define __fsl_read_rio_config(x, addr, err, op) \ | |
92 | ___fsl_read_rio_config(x, addr, err, op, "eieio") | |
93 | #endif | |
94 | ||
6ec4bedb | 95 | void __iomem *rio_regs_win; |
abc3aeae LG |
96 | void __iomem *rmu_regs_win; |
97 | resource_size_t rio_law_start; | |
98 | ||
99 | struct fsl_rio_dbell *dbell; | |
100 | struct fsl_rio_pw *pw; | |
a52c8f52 | 101 | |
688de017 | 102 | #ifdef CONFIG_PPC_E500 |
cce1f106 | 103 | int fsl_rio_mcheck_exception(struct pt_regs *regs) |
a52c8f52 | 104 | { |
82a9a480 SW |
105 | const struct exception_table_entry *entry; |
106 | unsigned long reason; | |
a52c8f52 | 107 | |
82a9a480 SW |
108 | if (!rio_regs_win) |
109 | return 0; | |
110 | ||
111 | reason = in_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR)); | |
112 | if (reason & (RIO_LTLEDCSR_IER | RIO_LTLEDCSR_PRT)) { | |
113 | /* Check if we are prepared to handle this fault */ | |
114 | entry = search_exception_tables(regs->nip); | |
115 | if (entry) { | |
116 | pr_debug("RIO: %s - MC Exception handled\n", | |
117 | __func__); | |
118 | out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR), | |
119 | 0); | |
806c0e6e | 120 | regs_set_recoverable(regs); |
59dc5bfc | 121 | regs_set_return_ip(regs, extable_fixup(entry)); |
82a9a480 | 122 | return 1; |
a52c8f52 AB |
123 | } |
124 | } | |
125 | ||
cce1f106 | 126 | return 0; |
a52c8f52 | 127 | } |
cce1f106 | 128 | EXPORT_SYMBOL_GPL(fsl_rio_mcheck_exception); |
ff33f182 | 129 | #endif |
a52c8f52 | 130 | |
2b0c28d7 | 131 | /** |
d02443a6 | 132 | * fsl_local_config_read - Generate a MPC85xx local config space read |
9941d945 | 133 | * @mport: RapidIO master port info |
2b0c28d7 MP |
134 | * @index: ID of RapdiIO interface |
135 | * @offset: Offset into configuration space | |
136 | * @len: Length (in bytes) of the maintenance transaction | |
137 | * @data: Value to be read into | |
138 | * | |
139 | * Generates a MPC85xx local configuration space read. Returns %0 on | |
140 | * success or %-EINVAL on failure. | |
141 | */ | |
ad1e9380 ZW |
142 | static int fsl_local_config_read(struct rio_mport *mport, |
143 | int index, u32 offset, int len, u32 *data) | |
2b0c28d7 | 144 | { |
ad1e9380 | 145 | struct rio_priv *priv = mport->priv; |
d02443a6 | 146 | pr_debug("fsl_local_config_read: index %d offset %8.8x\n", index, |
abc3aeae | 147 | offset); |
ad1e9380 | 148 | *data = in_be32(priv->regs_win + offset); |
2b0c28d7 MP |
149 | |
150 | return 0; | |
151 | } | |
152 | ||
153 | /** | |
d02443a6 | 154 | * fsl_local_config_write - Generate a MPC85xx local config space write |
9941d945 | 155 | * @mport: RapidIO master port info |
2b0c28d7 MP |
156 | * @index: ID of RapdiIO interface |
157 | * @offset: Offset into configuration space | |
158 | * @len: Length (in bytes) of the maintenance transaction | |
159 | * @data: Value to be written | |
160 | * | |
161 | * Generates a MPC85xx local configuration space write. Returns %0 on | |
162 | * success or %-EINVAL on failure. | |
163 | */ | |
ad1e9380 ZW |
164 | static int fsl_local_config_write(struct rio_mport *mport, |
165 | int index, u32 offset, int len, u32 data) | |
2b0c28d7 | 166 | { |
ad1e9380 | 167 | struct rio_priv *priv = mport->priv; |
2b0c28d7 | 168 | pr_debug |
6ec4bedb LG |
169 | ("fsl_local_config_write: index %d offset %8.8x data %8.8x\n", |
170 | index, offset, data); | |
ad1e9380 | 171 | out_be32(priv->regs_win + offset, data); |
2b0c28d7 MP |
172 | |
173 | return 0; | |
174 | } | |
175 | ||
176 | /** | |
d02443a6 | 177 | * fsl_rio_config_read - Generate a MPC85xx read maintenance transaction |
9941d945 | 178 | * @mport: RapidIO master port info |
2b0c28d7 MP |
179 | * @index: ID of RapdiIO interface |
180 | * @destid: Destination ID of transaction | |
181 | * @hopcount: Number of hops to target device | |
182 | * @offset: Offset into configuration space | |
183 | * @len: Length (in bytes) of the maintenance transaction | |
184 | * @val: Location to be read into | |
185 | * | |
186 | * Generates a MPC85xx read maintenance transaction. Returns %0 on | |
187 | * success or %-EINVAL on failure. | |
188 | */ | |
189 | static int | |
ad1e9380 ZW |
190 | fsl_rio_config_read(struct rio_mport *mport, int index, u16 destid, |
191 | u8 hopcount, u32 offset, int len, u32 *val) | |
2b0c28d7 | 192 | { |
ad1e9380 | 193 | struct rio_priv *priv = mport->priv; |
31d1e130 | 194 | unsigned long flags; |
2b0c28d7 | 195 | u8 *data; |
a52c8f52 | 196 | u32 rval, err = 0; |
2b0c28d7 MP |
197 | |
198 | pr_debug | |
6ec4bedb LG |
199 | ("fsl_rio_config_read:" |
200 | " index %d destid %d hopcount %d offset %8.8x len %d\n", | |
abc3aeae | 201 | index, destid, hopcount, offset, len); |
bd4fb654 TM |
202 | |
203 | /* 16MB maintenance window possible */ | |
204 | /* allow only aligned access to maintenance registers */ | |
205 | if (offset > (0x1000000 - len) || !IS_ALIGNED(offset, len)) | |
206 | return -EINVAL; | |
207 | ||
31d1e130 IN |
208 | spin_lock_irqsave(&fsl_rio_config_lock, flags); |
209 | ||
ad1e9380 | 210 | out_be32(&priv->maint_atmu_regs->rowtar, |
bd4fb654 | 211 | (destid << 22) | (hopcount << 12) | (offset >> 12)); |
6ec4bedb | 212 | out_be32(&priv->maint_atmu_regs->rowtear, (destid >> 10)); |
2b0c28d7 | 213 | |
bd4fb654 | 214 | data = (u8 *) priv->maint_win + (offset & (RIO_MAINT_WIN_SIZE - 1)); |
2b0c28d7 MP |
215 | switch (len) { |
216 | case 1: | |
a52c8f52 | 217 | __fsl_read_rio_config(rval, data, err, "lbz"); |
2b0c28d7 MP |
218 | break; |
219 | case 2: | |
a52c8f52 | 220 | __fsl_read_rio_config(rval, data, err, "lhz"); |
2b0c28d7 | 221 | break; |
bd4fb654 | 222 | case 4: |
a52c8f52 | 223 | __fsl_read_rio_config(rval, data, err, "lwz"); |
2b0c28d7 | 224 | break; |
bd4fb654 | 225 | default: |
31d1e130 | 226 | spin_unlock_irqrestore(&fsl_rio_config_lock, flags); |
bd4fb654 | 227 | return -EINVAL; |
2b0c28d7 MP |
228 | } |
229 | ||
a52c8f52 AB |
230 | if (err) { |
231 | pr_debug("RIO: cfg_read error %d for %x:%x:%x\n", | |
232 | err, destid, hopcount, offset); | |
233 | } | |
234 | ||
31d1e130 | 235 | spin_unlock_irqrestore(&fsl_rio_config_lock, flags); |
a52c8f52 AB |
236 | *val = rval; |
237 | ||
238 | return err; | |
2b0c28d7 MP |
239 | } |
240 | ||
241 | /** | |
d02443a6 | 242 | * fsl_rio_config_write - Generate a MPC85xx write maintenance transaction |
9941d945 | 243 | * @mport: RapidIO master port info |
2b0c28d7 MP |
244 | * @index: ID of RapdiIO interface |
245 | * @destid: Destination ID of transaction | |
246 | * @hopcount: Number of hops to target device | |
247 | * @offset: Offset into configuration space | |
248 | * @len: Length (in bytes) of the maintenance transaction | |
249 | * @val: Value to be written | |
250 | * | |
251 | * Generates an MPC85xx write maintenance transaction. Returns %0 on | |
252 | * success or %-EINVAL on failure. | |
253 | */ | |
254 | static int | |
ad1e9380 ZW |
255 | fsl_rio_config_write(struct rio_mport *mport, int index, u16 destid, |
256 | u8 hopcount, u32 offset, int len, u32 val) | |
2b0c28d7 | 257 | { |
ad1e9380 | 258 | struct rio_priv *priv = mport->priv; |
31d1e130 | 259 | unsigned long flags; |
2b0c28d7 | 260 | u8 *data; |
31d1e130 IN |
261 | int ret = 0; |
262 | ||
2b0c28d7 | 263 | pr_debug |
6ec4bedb | 264 | ("fsl_rio_config_write:" |
abc3aeae LG |
265 | " index %d destid %d hopcount %d offset %8.8x len %d val %8.8x\n", |
266 | index, destid, hopcount, offset, len, val); | |
bd4fb654 TM |
267 | |
268 | /* 16MB maintenance windows possible */ | |
269 | /* allow only aligned access to maintenance registers */ | |
270 | if (offset > (0x1000000 - len) || !IS_ALIGNED(offset, len)) | |
271 | return -EINVAL; | |
272 | ||
31d1e130 IN |
273 | spin_lock_irqsave(&fsl_rio_config_lock, flags); |
274 | ||
ad1e9380 | 275 | out_be32(&priv->maint_atmu_regs->rowtar, |
bd4fb654 | 276 | (destid << 22) | (hopcount << 12) | (offset >> 12)); |
6ec4bedb | 277 | out_be32(&priv->maint_atmu_regs->rowtear, (destid >> 10)); |
2b0c28d7 | 278 | |
bd4fb654 | 279 | data = (u8 *) priv->maint_win + (offset & (RIO_MAINT_WIN_SIZE - 1)); |
2b0c28d7 MP |
280 | switch (len) { |
281 | case 1: | |
282 | out_8((u8 *) data, val); | |
283 | break; | |
284 | case 2: | |
285 | out_be16((u16 *) data, val); | |
286 | break; | |
bd4fb654 | 287 | case 4: |
2b0c28d7 MP |
288 | out_be32((u32 *) data, val); |
289 | break; | |
bd4fb654 | 290 | default: |
31d1e130 | 291 | ret = -EINVAL; |
2b0c28d7 | 292 | } |
31d1e130 | 293 | spin_unlock_irqrestore(&fsl_rio_config_lock, flags); |
2b0c28d7 | 294 | |
31d1e130 | 295 | return ret; |
2b0c28d7 MP |
296 | } |
297 | ||
e6a546fd MG |
298 | static void fsl_rio_inbound_mem_init(struct rio_priv *priv) |
299 | { | |
300 | int i; | |
301 | ||
302 | /* close inbound windows */ | |
303 | for (i = 0; i < RIO_INB_ATMU_COUNT; i++) | |
304 | out_be32(&priv->inb_atmu_regs[i].riwar, 0); | |
305 | } | |
306 | ||
c265735f CL |
307 | static int fsl_map_inb_mem(struct rio_mport *mport, dma_addr_t lstart, |
308 | u64 rstart, u64 size, u32 flags) | |
e6a546fd MG |
309 | { |
310 | struct rio_priv *priv = mport->priv; | |
311 | u32 base_size; | |
312 | unsigned int base_size_log; | |
313 | u64 win_start, win_end; | |
314 | u32 riwar; | |
315 | int i; | |
316 | ||
a057a52e | 317 | if ((size & (size - 1)) != 0 || size > 0x400000000ULL) |
e6a546fd MG |
318 | return -EINVAL; |
319 | ||
320 | base_size_log = ilog2(size); | |
321 | base_size = 1 << base_size_log; | |
322 | ||
323 | /* check if addresses are aligned with the window size */ | |
324 | if (lstart & (base_size - 1)) | |
325 | return -EINVAL; | |
326 | if (rstart & (base_size - 1)) | |
327 | return -EINVAL; | |
328 | ||
329 | /* check for conflicting ranges */ | |
330 | for (i = 0; i < RIO_INB_ATMU_COUNT; i++) { | |
331 | riwar = in_be32(&priv->inb_atmu_regs[i].riwar); | |
332 | if ((riwar & RIWAR_ENABLE) == 0) | |
333 | continue; | |
334 | win_start = ((u64)(in_be32(&priv->inb_atmu_regs[i].riwbar) & RIWBAR_BADD_MASK)) | |
335 | << RIWBAR_BADD_VAL_SHIFT; | |
336 | win_end = win_start + ((1 << ((riwar & RIWAR_SIZE_MASK) + 1)) - 1); | |
337 | if (rstart < win_end && (rstart + size) > win_start) | |
338 | return -EINVAL; | |
339 | } | |
340 | ||
341 | /* find unused atmu */ | |
342 | for (i = 0; i < RIO_INB_ATMU_COUNT; i++) { | |
343 | riwar = in_be32(&priv->inb_atmu_regs[i].riwar); | |
344 | if ((riwar & RIWAR_ENABLE) == 0) | |
345 | break; | |
346 | } | |
347 | if (i >= RIO_INB_ATMU_COUNT) | |
348 | return -ENOMEM; | |
349 | ||
350 | out_be32(&priv->inb_atmu_regs[i].riwtar, lstart >> RIWTAR_TRAD_VAL_SHIFT); | |
351 | out_be32(&priv->inb_atmu_regs[i].riwbar, rstart >> RIWBAR_BADD_VAL_SHIFT); | |
352 | out_be32(&priv->inb_atmu_regs[i].riwar, RIWAR_ENABLE | RIWAR_TGINT_LOCAL | | |
353 | RIWAR_RDTYP_SNOOP | RIWAR_WRTYP_SNOOP | (base_size_log - 1)); | |
354 | ||
355 | return 0; | |
356 | } | |
357 | ||
c265735f | 358 | static void fsl_unmap_inb_mem(struct rio_mport *mport, dma_addr_t lstart) |
e6a546fd MG |
359 | { |
360 | u32 win_start_shift, base_start_shift; | |
361 | struct rio_priv *priv = mport->priv; | |
362 | u32 riwar, riwtar; | |
363 | int i; | |
364 | ||
365 | /* skip default window */ | |
366 | base_start_shift = lstart >> RIWTAR_TRAD_VAL_SHIFT; | |
367 | for (i = 0; i < RIO_INB_ATMU_COUNT; i++) { | |
368 | riwar = in_be32(&priv->inb_atmu_regs[i].riwar); | |
369 | if ((riwar & RIWAR_ENABLE) == 0) | |
370 | continue; | |
371 | ||
372 | riwtar = in_be32(&priv->inb_atmu_regs[i].riwtar); | |
373 | win_start_shift = riwtar & RIWTAR_TRAD_MASK; | |
374 | if (win_start_shift == base_start_shift) { | |
375 | out_be32(&priv->inb_atmu_regs[i].riwar, riwar & ~RIWAR_ENABLE); | |
376 | return; | |
377 | } | |
378 | } | |
379 | } | |
380 | ||
abc3aeae | 381 | void fsl_rio_port_error_handler(int offset) |
6ff31453 SX |
382 | { |
383 | /*XXX: Error recovery is not implemented, we just clear errors */ | |
384 | out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR), 0); | |
385 | ||
386 | if (offset == 0) { | |
387 | out_be32((u32 *)(rio_regs_win + RIO_PORT1_EDCSR), 0); | |
671ee7f0 | 388 | out_be32((u32 *)(rio_regs_win + RIO_PORT1_IECSR), IECSR_CLEAR); |
6ff31453 SX |
389 | out_be32((u32 *)(rio_regs_win + RIO_ESCSR), ESCSR_CLEAR); |
390 | } else { | |
391 | out_be32((u32 *)(rio_regs_win + RIO_PORT2_EDCSR), 0); | |
671ee7f0 | 392 | out_be32((u32 *)(rio_regs_win + RIO_PORT2_IECSR), IECSR_CLEAR); |
6ff31453 SX |
393 | out_be32((u32 *)(rio_regs_win + RIO_PORT2_ESCSR), ESCSR_CLEAR); |
394 | } | |
395 | } | |
7f620df8 ZW |
396 | static inline void fsl_rio_info(struct device *dev, u32 ccsr) |
397 | { | |
398 | const char *str; | |
399 | if (ccsr & 1) { | |
400 | /* Serial phy */ | |
401 | switch (ccsr >> 30) { | |
402 | case 0: | |
403 | str = "1"; | |
404 | break; | |
405 | case 1: | |
406 | str = "4"; | |
407 | break; | |
408 | default: | |
409 | str = "Unknown"; | |
d258e64e | 410 | break; |
7f620df8 ZW |
411 | } |
412 | dev_info(dev, "Hardware port width: %s\n", str); | |
413 | ||
414 | switch ((ccsr >> 27) & 7) { | |
415 | case 0: | |
416 | str = "Single-lane 0"; | |
417 | break; | |
418 | case 1: | |
419 | str = "Single-lane 2"; | |
420 | break; | |
421 | case 2: | |
422 | str = "Four-lane"; | |
423 | break; | |
424 | default: | |
425 | str = "Unknown"; | |
426 | break; | |
427 | } | |
428 | dev_info(dev, "Training connection status: %s\n", str); | |
429 | } else { | |
430 | /* Parallel phy */ | |
431 | if (!(ccsr & 0x80000000)) | |
432 | dev_info(dev, "Output port operating in 8-bit mode\n"); | |
433 | if (!(ccsr & 0x08000000)) | |
434 | dev_info(dev, "Input port operating in 8-bit mode\n"); | |
435 | } | |
436 | } | |
437 | ||
2b0c28d7 | 438 | /** |
9941d945 | 439 | * fsl_rio_setup - Setup Freescale PowerPC RapidIO interface |
2dc11581 | 440 | * @dev: platform_device pointer |
2b0c28d7 MP |
441 | * |
442 | * Initializes MPC85xx RapidIO hardware interface, configures | |
443 | * master port with system-specific info, and registers the | |
444 | * master port with the RapidIO subsystem. | |
445 | */ | |
c265735f | 446 | static int fsl_rio_setup(struct platform_device *dev) |
2b0c28d7 MP |
447 | { |
448 | struct rio_ops *ops; | |
449 | struct rio_mport *port; | |
cc2bb696 ZW |
450 | struct rio_priv *priv; |
451 | int rc = 0; | |
f892ac77 | 452 | const u32 *port_index; |
abc3aeae | 453 | u32 active_ports = 0; |
abc3aeae | 454 | struct device_node *np, *rmu_node; |
61b26917 | 455 | u32 ccsr; |
c4ae1799 | 456 | u64 range_start; |
abc3aeae LG |
457 | u32 i; |
458 | static int tmp; | |
459 | struct device_node *rmu_np[MAX_MSG_UNIT_NUM] = {NULL}; | |
cc2bb696 | 460 | |
61c7a080 | 461 | if (!dev->dev.of_node) { |
cc2bb696 | 462 | dev_err(&dev->dev, "Device OF-Node is NULL"); |
abc3aeae | 463 | return -ENODEV; |
cc2bb696 ZW |
464 | } |
465 | ||
de8d11bc | 466 | rio_regs_win = of_iomap(dev->dev.of_node, 0); |
abc3aeae LG |
467 | if (!rio_regs_win) { |
468 | dev_err(&dev->dev, "Unable to map rio register window\n"); | |
469 | rc = -ENOMEM; | |
470 | goto err_rio_regs; | |
cc2bb696 ZW |
471 | } |
472 | ||
e5cabeb3 | 473 | ops = kzalloc(sizeof(struct rio_ops), GFP_KERNEL); |
6c75933c JL |
474 | if (!ops) { |
475 | rc = -ENOMEM; | |
476 | goto err_ops; | |
477 | } | |
d02443a6 ZW |
478 | ops->lcread = fsl_local_config_read; |
479 | ops->lcwrite = fsl_local_config_write; | |
480 | ops->cread = fsl_rio_config_read; | |
481 | ops->cwrite = fsl_rio_config_write; | |
abc3aeae | 482 | ops->dsend = fsl_rio_doorbell_send; |
5b2074ae | 483 | ops->pwenable = fsl_rio_pw_enable; |
abc3aeae LG |
484 | ops->open_outb_mbox = fsl_open_outb_mbox; |
485 | ops->open_inb_mbox = fsl_open_inb_mbox; | |
486 | ops->close_outb_mbox = fsl_close_outb_mbox; | |
487 | ops->close_inb_mbox = fsl_close_inb_mbox; | |
488 | ops->add_outb_message = fsl_add_outb_message; | |
489 | ops->add_inb_buffer = fsl_add_inb_buffer; | |
490 | ops->get_inb_message = fsl_get_inb_message; | |
e6a546fd MG |
491 | ops->map_inb = fsl_map_inb_mem; |
492 | ops->unmap_inb = fsl_unmap_inb_mem; | |
abc3aeae LG |
493 | |
494 | rmu_node = of_parse_phandle(dev->dev.of_node, "fsl,srio-rmu-handle", 0); | |
a614db9a SW |
495 | if (!rmu_node) { |
496 | dev_err(&dev->dev, "No valid fsl,srio-rmu-handle property\n"); | |
380afa36 | 497 | rc = -ENOENT; |
abc3aeae | 498 | goto err_rmu; |
a614db9a | 499 | } |
de8d11bc RH |
500 | rmu_regs_win = of_iomap(rmu_node, 0); |
501 | ||
fcee9692 | 502 | of_node_put(rmu_node); |
abc3aeae LG |
503 | if (!rmu_regs_win) { |
504 | dev_err(&dev->dev, "Unable to map rmu register window\n"); | |
6c75933c | 505 | rc = -ENOMEM; |
abc3aeae LG |
506 | goto err_rmu; |
507 | } | |
508 | for_each_compatible_node(np, NULL, "fsl,srio-msg-unit") { | |
509 | rmu_np[tmp] = np; | |
510 | tmp++; | |
6c75933c | 511 | } |
ad1e9380 | 512 | |
abc3aeae LG |
513 | /*set up doobell node*/ |
514 | np = of_find_compatible_node(NULL, NULL, "fsl,srio-dbell-unit"); | |
515 | if (!np) { | |
a614db9a | 516 | dev_err(&dev->dev, "No fsl,srio-dbell-unit node\n"); |
abc3aeae LG |
517 | rc = -ENODEV; |
518 | goto err_dbell; | |
519 | } | |
520 | dbell = kzalloc(sizeof(struct fsl_rio_dbell), GFP_KERNEL); | |
521 | if (!(dbell)) { | |
522 | dev_err(&dev->dev, "Can't alloc memory for 'fsl_rio_dbell'\n"); | |
ad1e9380 | 523 | rc = -ENOMEM; |
abc3aeae | 524 | goto err_dbell; |
ad1e9380 | 525 | } |
abc3aeae LG |
526 | dbell->dev = &dev->dev; |
527 | dbell->bellirq = irq_of_parse_and_map(np, 1); | |
528 | dev_info(&dev->dev, "bellirq: %d\n", dbell->bellirq); | |
ad1e9380 | 529 | |
f892ac77 | 530 | if (of_property_read_reg(np, 0, &range_start, NULL)) { |
b7c670d6 RH |
531 | pr_err("%pOF: unable to find 'reg' property\n", |
532 | np); | |
abc3aeae LG |
533 | rc = -ENOMEM; |
534 | goto err_pw; | |
535 | } | |
abc3aeae LG |
536 | dbell->dbell_regs = (struct rio_dbell_regs *)(rmu_regs_win + |
537 | (u32)range_start); | |
538 | ||
539 | /*set up port write node*/ | |
540 | np = of_find_compatible_node(NULL, NULL, "fsl,srio-port-write-unit"); | |
541 | if (!np) { | |
a614db9a | 542 | dev_err(&dev->dev, "No fsl,srio-port-write-unit node\n"); |
abc3aeae LG |
543 | rc = -ENODEV; |
544 | goto err_pw; | |
545 | } | |
546 | pw = kzalloc(sizeof(struct fsl_rio_pw), GFP_KERNEL); | |
547 | if (!(pw)) { | |
548 | dev_err(&dev->dev, "Can't alloc memory for 'fsl_rio_pw'\n"); | |
549 | rc = -ENOMEM; | |
550 | goto err_pw; | |
551 | } | |
552 | pw->dev = &dev->dev; | |
553 | pw->pwirq = irq_of_parse_and_map(np, 0); | |
554 | dev_info(&dev->dev, "pwirq: %d\n", pw->pwirq); | |
f892ac77 | 555 | if (of_property_read_reg(np, 0, &range_start, NULL)) { |
b7c670d6 RH |
556 | pr_err("%pOF: unable to find 'reg' property\n", |
557 | np); | |
abc3aeae LG |
558 | rc = -ENOMEM; |
559 | goto err; | |
c1256ebe | 560 | } |
abc3aeae LG |
561 | pw->pw_regs = (struct rio_pw_regs *)(rmu_regs_win + (u32)range_start); |
562 | ||
563 | /*set up ports node*/ | |
564 | for_each_child_of_node(dev->dev.of_node, np) { | |
c4ae1799 RH |
565 | struct resource res; |
566 | ||
abc3aeae LG |
567 | port_index = of_get_property(np, "cell-index", NULL); |
568 | if (!port_index) { | |
b7c670d6 RH |
569 | dev_err(&dev->dev, "Can't get %pOF property 'cell-index'\n", |
570 | np); | |
abc3aeae LG |
571 | continue; |
572 | } | |
573 | ||
c4ae1799 | 574 | if (of_range_to_resource(np, 0, &res)) { |
b7c670d6 RH |
575 | dev_err(&dev->dev, "Can't get %pOF property 'ranges'\n", |
576 | np); | |
abc3aeae LG |
577 | continue; |
578 | } | |
c1256ebe | 579 | |
c4ae1799 RH |
580 | dev_info(&dev->dev, "%pOF: LAW %pR\n", |
581 | np, &res); | |
abc3aeae LG |
582 | |
583 | port = kzalloc(sizeof(struct rio_mport), GFP_KERNEL); | |
584 | if (!port) | |
585 | continue; | |
586 | ||
dd64f4fe AB |
587 | rc = rio_mport_initialize(port); |
588 | if (rc) { | |
589 | kfree(port); | |
590 | continue; | |
591 | } | |
592 | ||
abc3aeae LG |
593 | i = *port_index - 1; |
594 | port->index = (unsigned char)i; | |
595 | ||
596 | priv = kzalloc(sizeof(struct rio_priv), GFP_KERNEL); | |
597 | if (!priv) { | |
598 | dev_err(&dev->dev, "Can't alloc memory for 'priv'\n"); | |
599 | kfree(port); | |
600 | continue; | |
601 | } | |
602 | ||
603 | INIT_LIST_HEAD(&port->dbells); | |
c4ae1799 | 604 | port->iores = res; /* struct copy */ |
abc3aeae LG |
605 | port->iores.name = "rio_io_win"; |
606 | ||
607 | if (request_resource(&iomem_resource, &port->iores) < 0) { | |
608 | dev_err(&dev->dev, "RIO: Error requesting master port region" | |
609 | " 0x%016llx-0x%016llx\n", | |
610 | (u64)port->iores.start, (u64)port->iores.end); | |
611 | kfree(priv); | |
612 | kfree(port); | |
613 | continue; | |
614 | } | |
615 | sprintf(port->name, "RIO mport %d", i); | |
616 | ||
617 | priv->dev = &dev->dev; | |
2aaf308b | 618 | port->dev.parent = &dev->dev; |
abc3aeae LG |
619 | port->ops = ops; |
620 | port->priv = priv; | |
621 | port->phys_efptr = 0x100; | |
adff1649 | 622 | port->phys_rmap = 1; |
abc3aeae LG |
623 | priv->regs_win = rio_regs_win; |
624 | ||
abc3aeae | 625 | ccsr = in_be32(priv->regs_win + RIO_CCSR + i*0x20); |
adff1649 | 626 | |
abc3aeae LG |
627 | /* Checking the port training status */ |
628 | if (in_be32((priv->regs_win + RIO_ESCSR + i*0x20)) & 1) { | |
629 | dev_err(&dev->dev, "Port %d is not ready. " | |
630 | "Try to restart connection...\n", i); | |
7f620df8 | 631 | /* Disable ports */ |
abc3aeae LG |
632 | out_be32(priv->regs_win |
633 | + RIO_CCSR + i*0x20, 0); | |
7f620df8 | 634 | /* Set 1x lane */ |
abc3aeae LG |
635 | setbits32(priv->regs_win |
636 | + RIO_CCSR + i*0x20, 0x02000000); | |
7f620df8 | 637 | /* Enable ports */ |
abc3aeae LG |
638 | setbits32(priv->regs_win |
639 | + RIO_CCSR + i*0x20, 0x00600000); | |
640 | msleep(100); | |
641 | if (in_be32((priv->regs_win | |
642 | + RIO_ESCSR + i*0x20)) & 1) { | |
643 | dev_err(&dev->dev, | |
644 | "Port %d restart failed.\n", i); | |
645 | release_resource(&port->iores); | |
646 | kfree(priv); | |
647 | kfree(port); | |
648 | continue; | |
649 | } | |
650 | dev_info(&dev->dev, "Port %d restart success!\n", i); | |
7f620df8 | 651 | } |
abc3aeae | 652 | fsl_rio_info(&dev->dev, ccsr); |
61b26917 | 653 | |
abc3aeae | 654 | port->sys_size = (in_be32((priv->regs_win + RIO_PEF_CAR)) |
e0423236 | 655 | & RIO_PEF_CTLS) >> 4; |
abc3aeae LG |
656 | dev_info(&dev->dev, "RapidIO Common Transport System size: %d\n", |
657 | port->sys_size ? 65536 : 256); | |
658 | ||
abc3aeae LG |
659 | if (port->host_deviceid >= 0) |
660 | out_be32(priv->regs_win + RIO_GCCSR, RIO_PORT_GEN_HOST | | |
661 | RIO_PORT_GEN_MASTER | RIO_PORT_GEN_DISCOVERED); | |
662 | else | |
663 | out_be32(priv->regs_win + RIO_GCCSR, | |
664 | RIO_PORT_GEN_MASTER); | |
e0423236 | 665 | |
abc3aeae LG |
666 | priv->atmu_regs = (struct rio_atmu_regs *)(priv->regs_win |
667 | + ((i == 0) ? RIO_ATMU_REGS_PORT1_OFFSET : | |
668 | RIO_ATMU_REGS_PORT2_OFFSET)); | |
669 | ||
670 | priv->maint_atmu_regs = priv->atmu_regs + 1; | |
e6a546fd MG |
671 | priv->inb_atmu_regs = (struct rio_inb_atmu_regs __iomem *) |
672 | (priv->regs_win + | |
673 | ((i == 0) ? RIO_INB_ATMU_REGS_PORT1_OFFSET : | |
674 | RIO_INB_ATMU_REGS_PORT2_OFFSET)); | |
675 | ||
adff1649 AB |
676 | /* Set to receive packets with any dest ID */ |
677 | out_be32((priv->regs_win + RIO_ISR_AACR + i*0x80), | |
678 | RIO_ISR_AACR_AA); | |
af84ca38 | 679 | |
abc3aeae LG |
680 | /* Configure maintenance transaction window */ |
681 | out_be32(&priv->maint_atmu_regs->rowbar, | |
682 | port->iores.start >> 12); | |
683 | out_be32(&priv->maint_atmu_regs->rowar, | |
684 | 0x80077000 | (ilog2(RIO_MAINT_WIN_SIZE) - 1)); | |
61b26917 | 685 | |
abc3aeae LG |
686 | priv->maint_win = ioremap(port->iores.start, |
687 | RIO_MAINT_WIN_SIZE); | |
2b0c28d7 | 688 | |
abc3aeae | 689 | rio_law_start = range_start; |
2b0c28d7 | 690 | |
abc3aeae | 691 | fsl_rio_setup_rmu(port, rmu_np[i]); |
e6a546fd | 692 | fsl_rio_inbound_mem_init(priv); |
2b0c28d7 | 693 | |
abc3aeae | 694 | dbell->mport[i] = port; |
9a0b0627 | 695 | pw->mport[i] = port; |
abc3aeae | 696 | |
dd64f4fe AB |
697 | if (rio_register_mport(port)) { |
698 | release_resource(&port->iores); | |
699 | kfree(priv); | |
700 | kfree(port); | |
701 | continue; | |
702 | } | |
abc3aeae LG |
703 | active_ports++; |
704 | } | |
705 | ||
706 | if (!active_ports) { | |
707 | rc = -ENOLINK; | |
708 | goto err; | |
709 | } | |
6ec4bedb | 710 | |
abc3aeae LG |
711 | fsl_rio_doorbell_init(dbell); |
712 | fsl_rio_port_write_init(pw); | |
ad1e9380 | 713 | |
cc2bb696 | 714 | return 0; |
ad1e9380 | 715 | err: |
abc3aeae | 716 | kfree(pw); |
a614db9a | 717 | pw = NULL; |
abc3aeae LG |
718 | err_pw: |
719 | kfree(dbell); | |
a614db9a | 720 | dbell = NULL; |
abc3aeae LG |
721 | err_dbell: |
722 | iounmap(rmu_regs_win); | |
a614db9a | 723 | rmu_regs_win = NULL; |
abc3aeae | 724 | err_rmu: |
6c75933c JL |
725 | kfree(ops); |
726 | err_ops: | |
abc3aeae | 727 | iounmap(rio_regs_win); |
a614db9a | 728 | rio_regs_win = NULL; |
abc3aeae | 729 | err_rio_regs: |
cc2bb696 | 730 | return rc; |
2b0c28d7 | 731 | } |
cc2bb696 ZW |
732 | |
733 | /* The probe function for RapidIO peer-to-peer network. | |
734 | */ | |
cad5cef6 | 735 | static int fsl_of_rio_rpn_probe(struct platform_device *dev) |
cc2bb696 | 736 | { |
b7c670d6 RH |
737 | printk(KERN_INFO "Setting up RapidIO peer-to-peer network %pOF\n", |
738 | dev->dev.of_node); | |
cc2bb696 | 739 | |
2f809985 | 740 | return fsl_rio_setup(dev); |
cc2bb696 ZW |
741 | }; |
742 | ||
743 | static const struct of_device_id fsl_of_rio_rpn_ids[] = { | |
744 | { | |
abc3aeae | 745 | .compatible = "fsl,srio", |
cc2bb696 ZW |
746 | }, |
747 | {}, | |
748 | }; | |
749 | ||
00006124 | 750 | static struct platform_driver fsl_of_rio_rpn_driver = { |
4018294b GL |
751 | .driver = { |
752 | .name = "fsl-of-rio", | |
4018294b GL |
753 | .of_match_table = fsl_of_rio_rpn_ids, |
754 | }, | |
cc2bb696 ZW |
755 | .probe = fsl_of_rio_rpn_probe, |
756 | }; | |
757 | ||
758 | static __init int fsl_of_rio_rpn_init(void) | |
759 | { | |
00006124 | 760 | return platform_driver_register(&fsl_of_rio_rpn_driver); |
cc2bb696 ZW |
761 | } |
762 | ||
763 | subsys_initcall(fsl_of_rio_rpn_init); |