1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright (C) 2006-2010 Freescale Semiconductor, Inc. All rights reserved. |
4 | * |
5 | * Authors: Shlomi Gridish <gridish@freescale.com> |
6 | * Li Yang <leoli@freescale.com> |
7 | * Based on cpm2_common.c from Dan Malek (dmalek@jlc.net) |
8 | * |
9 | * Description: |
10 | * General Purpose functions for the global management of the |
11 | * QUICC Engine (QE). |
12 | */ |
13 | #include <linux/bitmap.h> |
14 | #include <linux/errno.h> |
15 | #include <linux/sched.h> |
16 | #include <linux/kernel.h> |
17 | #include <linux/param.h> |
18 | #include <linux/string.h> |
19 | #include <linux/spinlock.h> |
20 | #include <linux/mm.h> |
21 | #include <linux/interrupt.h> |
22 | #include <linux/module.h> |
23 | #include <linux/delay.h> |
24 | #include <linux/ioport.h> |
25 | #include <linux/iopoll.h> |
26 | #include <linux/crc32.h> |
27 | #include <linux/mod_devicetable.h> |
28 | #include <linux/of.h> |
29 | #include <linux/platform_device.h> |
30 | #include <soc/fsl/qe/immap_qe.h> |
31 | #include <soc/fsl/qe/qe.h> |
32 | |
33 | static void qe_snums_init(void); |
34 | static int qe_sdma_init(void); |
35 | |
36 | static DEFINE_SPINLOCK(qe_lock); |
37 | DEFINE_SPINLOCK(cmxgcr_lock); |
38 | EXPORT_SYMBOL(cmxgcr_lock); |
39 | |
40 | /* We allocate this here because it is used almost exclusively for |
41 | * the communication processor devices. |
42 | */ |
43 | struct qe_immap __iomem *qe_immr; |
44 | EXPORT_SYMBOL(qe_immr); |
45 | |
46 | static u8 snums[QE_NUM_OF_SNUM]; /* Dynamically allocated SNUMs */ |
47 | static DECLARE_BITMAP(snum_state, QE_NUM_OF_SNUM); |
48 | static unsigned int qe_num_of_snum; |
49 | |
50 | static phys_addr_t qebase = -1; |
51 | |
52 | static struct device_node *qe_get_device_node(void) |
53 | { |
54 | struct device_node *qe; |
55 | |
56 | /* |
57 | * Newer device trees have an "fsl,qe" compatible property for the QE |
58 | * node, but we still need to support older device trees. |
59 | */ |
60 | qe = of_find_compatible_node(NULL, NULL, compat: "fsl,qe" ); |
61 | if (qe) |
62 | return qe; |
63 | return of_find_node_by_type(NULL, type: "qe" ); |
64 | } |
65 | |
66 | static phys_addr_t get_qe_base(void) |
67 | { |
68 | struct device_node *qe; |
69 | int ret; |
70 | struct resource res; |
71 | |
72 | if (qebase != -1) |
73 | return qebase; |
74 | |
75 | qe = qe_get_device_node(); |
76 | if (!qe) |
77 | return qebase; |
78 | |
79 | ret = of_address_to_resource(dev: qe, index: 0, r: &res); |
80 | if (!ret) |
81 | qebase = res.start; |
82 | of_node_put(node: qe); |
83 | |
84 | return qebase; |
85 | } |
86 | |
87 | void qe_reset(void) |
88 | { |
89 | if (qe_immr == NULL) |
90 | qe_immr = ioremap(offset: get_qe_base(), QE_IMMAP_SIZE); |
91 | |
92 | qe_snums_init(); |
93 | |
94 | qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID, |
95 | QE_CR_PROTOCOL_UNSPECIFIED, cmd_input: 0); |
96 | |
97 | /* Reclaim the MURAM memory for our use. */ |
98 | qe_muram_init(); |
99 | |
100 | if (qe_sdma_init()) |
101 | panic(fmt: "sdma init failed!" ); |
102 | } |
103 | |
104 | int qe_issue_cmd(u32 cmd, u32 device, u8 mcn_protocol, u32 cmd_input) |
105 | { |
106 | unsigned long flags; |
107 | u8 mcn_shift = 0, dev_shift = 0; |
108 | u32 val; |
109 | int ret; |
110 | |
111 | spin_lock_irqsave(&qe_lock, flags); |
112 | if (cmd == QE_RESET) { |
113 | iowrite32be((u32)(cmd | QE_CR_FLG), &qe_immr->cp.cecr); |
114 | } else { |
115 | if (cmd == QE_ASSIGN_PAGE) { |
116 | /* Here device is the SNUM, not sub-block */ |
117 | dev_shift = QE_CR_SNUM_SHIFT; |
118 | } else if (cmd == QE_ASSIGN_RISC) { |
119 | /* Here device is the SNUM, and mcnProtocol is |
120 | * e_QeCmdRiscAssignment value */ |
121 | dev_shift = QE_CR_SNUM_SHIFT; |
122 | mcn_shift = QE_CR_MCN_RISC_ASSIGN_SHIFT; |
123 | } else { |
124 | if (device == QE_CR_SUBBLOCK_USB) |
125 | mcn_shift = QE_CR_MCN_USB_SHIFT; |
126 | else |
127 | mcn_shift = QE_CR_MCN_NORMAL_SHIFT; |
128 | } |
129 | |
130 | iowrite32be(cmd_input, &qe_immr->cp.cecdr); |
131 | iowrite32be((cmd | QE_CR_FLG | ((u32)device << dev_shift) | (u32)mcn_protocol << mcn_shift), |
132 | &qe_immr->cp.cecr); |
133 | } |
134 | |
135 | /* wait for the QE_CR_FLG to clear */ |
136 | ret = readx_poll_timeout_atomic(ioread32be, &qe_immr->cp.cecr, val, |
137 | (val & QE_CR_FLG) == 0, 0, 100); |
138 | /* On timeout, ret is -ETIMEDOUT, otherwise it will be 0. */ |
139 | spin_unlock_irqrestore(lock: &qe_lock, flags); |
140 | |
141 | return ret == 0; |
142 | } |
143 | EXPORT_SYMBOL(qe_issue_cmd); |
144 | |
145 | /* Set a baud rate generator. This needs lots of work. There are |
146 | * 16 BRGs, which can be connected to the QE channels or output |
147 | * as clocks. The BRGs are in two different block of internal |
148 | * memory mapped space. |
149 | * The BRG clock is the QE clock divided by 2. |
150 | * It was set up long ago during the initial boot phase and is |
151 | * given to us. |
152 | * Baud rate clocks are zero-based in the driver code (as that maps |
153 | * to port numbers). Documentation uses 1-based numbering. |
154 | */ |
155 | static unsigned int brg_clk = 0; |
156 | |
157 | #define CLK_GRAN (1000) |
158 | #define CLK_GRAN_LIMIT (5) |
159 | |
160 | unsigned int qe_get_brg_clk(void) |
161 | { |
162 | struct device_node *qe; |
163 | u32 brg; |
164 | unsigned int mod; |
165 | |
166 | if (brg_clk) |
167 | return brg_clk; |
168 | |
169 | qe = qe_get_device_node(); |
170 | if (!qe) |
171 | return brg_clk; |
172 | |
173 | if (!of_property_read_u32(np: qe, propname: "brg-frequency" , out_value: &brg)) |
174 | brg_clk = brg; |
175 | |
176 | of_node_put(node: qe); |
177 | |
178 | /* round this if near to a multiple of CLK_GRAN */ |
179 | mod = brg_clk % CLK_GRAN; |
180 | if (mod) { |
181 | if (mod < CLK_GRAN_LIMIT) |
182 | brg_clk -= mod; |
183 | else if (mod > (CLK_GRAN - CLK_GRAN_LIMIT)) |
184 | brg_clk += CLK_GRAN - mod; |
185 | } |
186 | |
187 | return brg_clk; |
188 | } |
189 | EXPORT_SYMBOL(qe_get_brg_clk); |
190 | |
191 | #define PVR_VER_836x 0x8083 |
192 | #define PVR_VER_832x 0x8084 |
193 | |
194 | static bool qe_general4_errata(void) |
195 | { |
196 | #ifdef CONFIG_PPC32 |
197 | return pvr_version_is(PVR_VER_836x) || pvr_version_is(PVR_VER_832x); |
198 | #endif |
199 | return false; |
200 | } |
201 | |
202 | /* Program the BRG to the given sampling rate and multiplier |
203 | * |
204 | * @brg: the BRG, QE_BRG1 - QE_BRG16 |
205 | * @rate: the desired sampling rate |
206 | * @multiplier: corresponds to the value programmed in GUMR_L[RDCR] or |
207 | * GUMR_L[TDCR]. E.g., if this BRG is the RX clock, and GUMR_L[RDCR]=01, |
208 | * then 'multiplier' should be 8. |
209 | */ |
210 | int qe_setbrg(enum qe_clock brg, unsigned int rate, unsigned int multiplier) |
211 | { |
212 | u32 divisor, tempval; |
213 | u32 div16 = 0; |
214 | |
215 | if ((brg < QE_BRG1) || (brg > QE_BRG16)) |
216 | return -EINVAL; |
217 | |
218 | divisor = qe_get_brg_clk() / (rate * multiplier); |
219 | |
220 | if (divisor > QE_BRGC_DIVISOR_MAX + 1) { |
221 | div16 = QE_BRGC_DIV16; |
222 | divisor /= 16; |
223 | } |
224 | |
225 | /* Errata QE_General4, which affects some MPC832x and MPC836x SOCs, says |
226 | that the BRG divisor must be even if you're not using divide-by-16 |
227 | mode. */ |
228 | if (qe_general4_errata()) |
229 | if (!div16 && (divisor & 1) && (divisor > 3)) |
230 | divisor++; |
231 | |
232 | tempval = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | |
233 | QE_BRGC_ENABLE | div16; |
234 | |
235 | iowrite32be(tempval, &qe_immr->brg.brgc[brg - QE_BRG1]); |
236 | |
237 | return 0; |
238 | } |
239 | EXPORT_SYMBOL(qe_setbrg); |
240 | |
241 | /* Convert a string to a QE clock source enum |
242 | * |
243 | * This function takes a string, typically from a property in the device |
244 | * tree, and returns the corresponding "enum qe_clock" value. |
245 | */ |
246 | enum qe_clock qe_clock_source(const char *source) |
247 | { |
248 | unsigned int i; |
249 | |
250 | if (strcasecmp(s1: source, s2: "none" ) == 0) |
251 | return QE_CLK_NONE; |
252 | |
253 | if (strcmp(source, "tsync_pin" ) == 0) |
254 | return QE_TSYNC_PIN; |
255 | |
256 | if (strcmp(source, "rsync_pin" ) == 0) |
257 | return QE_RSYNC_PIN; |
258 | |
259 | if (strncasecmp(s1: source, s2: "brg" , n: 3) == 0) { |
260 | i = simple_strtoul(source + 3, NULL, 10); |
261 | if ((i >= 1) && (i <= 16)) |
262 | return (QE_BRG1 - 1) + i; |
263 | else |
264 | return QE_CLK_DUMMY; |
265 | } |
266 | |
267 | if (strncasecmp(s1: source, s2: "clk" , n: 3) == 0) { |
268 | i = simple_strtoul(source + 3, NULL, 10); |
269 | if ((i >= 1) && (i <= 24)) |
270 | return (QE_CLK1 - 1) + i; |
271 | else |
272 | return QE_CLK_DUMMY; |
273 | } |
274 | |
275 | return QE_CLK_DUMMY; |
276 | } |
277 | EXPORT_SYMBOL(qe_clock_source); |
278 | |
279 | /* Initialize SNUMs (thread serial numbers) according to |
280 | * QE Module Control chapter, SNUM table |
281 | */ |
282 | static void qe_snums_init(void) |
283 | { |
284 | static const u8 snum_init_76[] = { |
285 | 0x04, 0x05, 0x0C, 0x0D, 0x14, 0x15, 0x1C, 0x1D, |
286 | 0x24, 0x25, 0x2C, 0x2D, 0x34, 0x35, 0x88, 0x89, |
287 | 0x98, 0x99, 0xA8, 0xA9, 0xB8, 0xB9, 0xC8, 0xC9, |
288 | 0xD8, 0xD9, 0xE8, 0xE9, 0x44, 0x45, 0x4C, 0x4D, |
289 | 0x54, 0x55, 0x5C, 0x5D, 0x64, 0x65, 0x6C, 0x6D, |
290 | 0x74, 0x75, 0x7C, 0x7D, 0x84, 0x85, 0x8C, 0x8D, |
291 | 0x94, 0x95, 0x9C, 0x9D, 0xA4, 0xA5, 0xAC, 0xAD, |
292 | 0xB4, 0xB5, 0xBC, 0xBD, 0xC4, 0xC5, 0xCC, 0xCD, |
293 | 0xD4, 0xD5, 0xDC, 0xDD, 0xE4, 0xE5, 0xEC, 0xED, |
294 | 0xF4, 0xF5, 0xFC, 0xFD, |
295 | }; |
296 | static const u8 snum_init_46[] = { |
297 | 0x04, 0x05, 0x0C, 0x0D, 0x14, 0x15, 0x1C, 0x1D, |
298 | 0x24, 0x25, 0x2C, 0x2D, 0x34, 0x35, 0x88, 0x89, |
299 | 0x98, 0x99, 0xA8, 0xA9, 0xB8, 0xB9, 0xC8, 0xC9, |
300 | 0xD8, 0xD9, 0xE8, 0xE9, 0x08, 0x09, 0x18, 0x19, |
301 | 0x28, 0x29, 0x38, 0x39, 0x48, 0x49, 0x58, 0x59, |
302 | 0x68, 0x69, 0x78, 0x79, 0x80, 0x81, |
303 | }; |
304 | struct device_node *qe; |
305 | const u8 *snum_init; |
306 | int i; |
307 | |
308 | bitmap_zero(dst: snum_state, QE_NUM_OF_SNUM); |
309 | qe_num_of_snum = 28; /* The default number of snum for threads is 28 */ |
310 | qe = qe_get_device_node(); |
311 | if (qe) { |
312 | i = of_property_read_variable_u8_array(np: qe, propname: "fsl,qe-snums" , |
313 | out_values: snums, sz_min: 1, QE_NUM_OF_SNUM); |
314 | if (i > 0) { |
315 | of_node_put(node: qe); |
316 | qe_num_of_snum = i; |
317 | return; |
318 | } |
319 | /* |
320 | * Fall back to legacy binding of using the value of |
321 | * fsl,qe-num-snums to choose one of the static arrays |
322 | * above. |
323 | */ |
324 | of_property_read_u32(np: qe, propname: "fsl,qe-num-snums" , out_value: &qe_num_of_snum); |
325 | of_node_put(node: qe); |
326 | } |
327 | |
328 | if (qe_num_of_snum == 76) { |
329 | snum_init = snum_init_76; |
330 | } else if (qe_num_of_snum == 28 || qe_num_of_snum == 46) { |
331 | snum_init = snum_init_46; |
332 | } else { |
333 | pr_err("QE: unsupported value of fsl,qe-num-snums: %u\n" , qe_num_of_snum); |
334 | return; |
335 | } |
336 | memcpy(snums, snum_init, qe_num_of_snum); |
337 | } |
338 | |
339 | int qe_get_snum(void) |
340 | { |
341 | unsigned long flags; |
342 | int snum = -EBUSY; |
343 | int i; |
344 | |
345 | spin_lock_irqsave(&qe_lock, flags); |
346 | i = find_first_zero_bit(addr: snum_state, size: qe_num_of_snum); |
347 | if (i < qe_num_of_snum) { |
348 | set_bit(nr: i, addr: snum_state); |
349 | snum = snums[i]; |
350 | } |
351 | spin_unlock_irqrestore(lock: &qe_lock, flags); |
352 | |
353 | return snum; |
354 | } |
355 | EXPORT_SYMBOL(qe_get_snum); |
356 | |
357 | void qe_put_snum(u8 snum) |
358 | { |
359 | const u8 *p = memchr(p: snums, c: snum, size: qe_num_of_snum); |
360 | |
361 | if (p) |
362 | clear_bit(nr: p - snums, addr: snum_state); |
363 | } |
364 | EXPORT_SYMBOL(qe_put_snum); |
365 | |
366 | static int qe_sdma_init(void) |
367 | { |
368 | struct sdma __iomem *sdma = &qe_immr->sdma; |
369 | static s32 sdma_buf_offset = -ENOMEM; |
370 | |
371 | /* allocate 2 internal temporary buffers (512 bytes size each) for |
372 | * the SDMA */ |
373 | if (sdma_buf_offset < 0) { |
374 | sdma_buf_offset = qe_muram_alloc(size: 512 * 2, align: 4096); |
375 | if (sdma_buf_offset < 0) |
376 | return -ENOMEM; |
377 | } |
378 | |
379 | iowrite32be((u32)sdma_buf_offset & QE_SDEBCR_BA_MASK, |
380 | &sdma->sdebcr); |
381 | iowrite32be((QE_SDMR_GLB_1_MSK | (0x1 << QE_SDMR_CEN_SHIFT)), |
382 | &sdma->sdmr); |
383 | |
384 | return 0; |
385 | } |
386 | |
387 | /* The maximum number of RISCs we support */ |
388 | #define MAX_QE_RISC 4 |
389 | |
390 | /* Firmware information stored here for qe_get_firmware_info() */ |
391 | static struct qe_firmware_info qe_firmware_info; |
392 | |
393 | /* |
394 | * Set to 1 if QE firmware has been uploaded, and therefore |
395 | * qe_firmware_info contains valid data. |
396 | */ |
397 | static int qe_firmware_uploaded; |
398 | |
399 | /* |
400 | * Upload a QE microcode |
401 | * |
402 | * This function is a worker function for qe_upload_firmware(). It does |
403 | * the actual uploading of the microcode. |
404 | */ |
405 | static void qe_upload_microcode(const void *base, |
406 | const struct qe_microcode *ucode) |
407 | { |
408 | const __be32 *code = base + be32_to_cpu(ucode->code_offset); |
409 | unsigned int i; |
410 | |
411 | if (ucode->major || ucode->minor || ucode->revision) |
412 | printk(KERN_INFO "qe-firmware: " |
413 | "uploading microcode '%s' version %u.%u.%u\n" , |
414 | ucode->id, ucode->major, ucode->minor, ucode->revision); |
415 | else |
416 | printk(KERN_INFO "qe-firmware: " |
417 | "uploading microcode '%s'\n" , ucode->id); |
418 | |
419 | /* Use auto-increment */ |
420 | iowrite32be(be32_to_cpu(ucode->iram_offset) | QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR, |
421 | &qe_immr->iram.iadd); |
422 | |
423 | for (i = 0; i < be32_to_cpu(ucode->count); i++) |
424 | iowrite32be(be32_to_cpu(code[i]), &qe_immr->iram.idata); |
425 | |
426 | /* Set I-RAM Ready Register */ |
427 | iowrite32be(QE_IRAM_READY, &qe_immr->iram.iready); |
428 | } |
429 | |
430 | /* |
431 | * Upload a microcode to the I-RAM at a specific address. |
432 | * |
433 | * See Documentation/arch/powerpc/qe_firmware.rst for information on QE microcode |
434 | * uploading. |
435 | * |
436 | * Currently, only version 1 is supported, so the 'version' field must be |
437 | * set to 1. |
438 | * |
439 | * The SOC model and revision are not validated, they are only displayed for |
440 | * informational purposes. |
441 | * |
442 | * 'calc_size' is the calculated size, in bytes, of the firmware structure and |
443 | * all of the microcode structures, minus the CRC. |
444 | * |
445 | * 'length' is the size that the structure says it is, including the CRC. |
446 | */ |
447 | int qe_upload_firmware(const struct qe_firmware *firmware) |
448 | { |
449 | unsigned int i; |
450 | unsigned int j; |
451 | u32 crc; |
452 | size_t calc_size; |
453 | size_t length; |
454 | const struct qe_header *hdr; |
455 | |
456 | if (!firmware) { |
457 | printk(KERN_ERR "qe-firmware: invalid pointer\n" ); |
458 | return -EINVAL; |
459 | } |
460 | |
461 | hdr = &firmware->header; |
462 | length = be32_to_cpu(hdr->length); |
463 | |
464 | /* Check the magic */ |
465 | if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') || |
466 | (hdr->magic[2] != 'F')) { |
467 | printk(KERN_ERR "qe-firmware: not a microcode\n" ); |
468 | return -EPERM; |
469 | } |
470 | |
471 | /* Check the version */ |
472 | if (hdr->version != 1) { |
473 | printk(KERN_ERR "qe-firmware: unsupported version\n" ); |
474 | return -EPERM; |
475 | } |
476 | |
477 | /* Validate some of the fields */ |
478 | if ((firmware->count < 1) || (firmware->count > MAX_QE_RISC)) { |
479 | printk(KERN_ERR "qe-firmware: invalid data\n" ); |
480 | return -EINVAL; |
481 | } |
482 | |
483 | /* Validate the length and check if there's a CRC */ |
484 | calc_size = struct_size(firmware, microcode, firmware->count); |
485 | |
486 | for (i = 0; i < firmware->count; i++) |
487 | /* |
488 | * For situations where the second RISC uses the same microcode |
489 | * as the first, the 'code_offset' and 'count' fields will be |
490 | * zero, so it's okay to add those. |
491 | */ |
492 | calc_size += sizeof(__be32) * |
493 | be32_to_cpu(firmware->microcode[i].count); |
494 | |
495 | /* Validate the length */ |
496 | if (length != calc_size + sizeof(__be32)) { |
497 | printk(KERN_ERR "qe-firmware: invalid length\n" ); |
498 | return -EPERM; |
499 | } |
500 | |
501 | /* Validate the CRC */ |
502 | crc = be32_to_cpu(*(__be32 *)((void *)firmware + calc_size)); |
503 | if (crc != crc32(0, firmware, calc_size)) { |
504 | printk(KERN_ERR "qe-firmware: firmware CRC is invalid\n" ); |
505 | return -EIO; |
506 | } |
507 | |
508 | /* |
509 | * If the microcode calls for it, split the I-RAM. |
510 | */ |
511 | if (!firmware->split) |
512 | qe_setbits_be16(&qe_immr->cp.cercr, QE_CP_CERCR_CIR); |
513 | |
514 | if (firmware->soc.model) |
515 | printk(KERN_INFO |
516 | "qe-firmware: firmware '%s' for %u V%u.%u\n" , |
517 | firmware->id, be16_to_cpu(firmware->soc.model), |
518 | firmware->soc.major, firmware->soc.minor); |
519 | else |
520 | printk(KERN_INFO "qe-firmware: firmware '%s'\n" , |
521 | firmware->id); |
522 | |
523 | /* |
524 | * The QE only supports one microcode per RISC, so clear out all the |
525 | * saved microcode information and put in the new. |
526 | */ |
527 | memset(&qe_firmware_info, 0, sizeof(qe_firmware_info)); |
528 | strscpy(qe_firmware_info.id, firmware->id, sizeof(qe_firmware_info.id)); |
529 | qe_firmware_info.extended_modes = be64_to_cpu(firmware->extended_modes); |
530 | memcpy(qe_firmware_info.vtraps, firmware->vtraps, |
531 | sizeof(firmware->vtraps)); |
532 | |
533 | /* Loop through each microcode. */ |
534 | for (i = 0; i < firmware->count; i++) { |
535 | const struct qe_microcode *ucode = &firmware->microcode[i]; |
536 | |
537 | /* Upload a microcode if it's present */ |
538 | if (ucode->code_offset) |
539 | qe_upload_microcode(base: firmware, ucode); |
540 | |
541 | /* Program the traps for this processor */ |
542 | for (j = 0; j < 16; j++) { |
543 | u32 trap = be32_to_cpu(ucode->traps[j]); |
544 | |
545 | if (trap) |
546 | iowrite32be(trap, |
547 | &qe_immr->rsp[i].tibcr[j]); |
548 | } |
549 | |
550 | /* Enable traps */ |
551 | iowrite32be(be32_to_cpu(ucode->eccr), |
552 | &qe_immr->rsp[i].eccr); |
553 | } |
554 | |
555 | qe_firmware_uploaded = 1; |
556 | |
557 | return 0; |
558 | } |
559 | EXPORT_SYMBOL(qe_upload_firmware); |
560 | |
561 | /* |
562 | * Get info on the currently-loaded firmware |
563 | * |
564 | * This function also checks the device tree to see if the boot loader has |
565 | * uploaded a firmware already. |
566 | */ |
567 | struct qe_firmware_info *qe_get_firmware_info(void) |
568 | { |
569 | static int initialized; |
570 | struct device_node *qe; |
571 | struct device_node *fw = NULL; |
572 | const char *sprop; |
573 | |
574 | /* |
575 | * If we haven't checked yet, and a driver hasn't uploaded a firmware |
576 | * yet, then check the device tree for information. |
577 | */ |
578 | if (qe_firmware_uploaded) |
579 | return &qe_firmware_info; |
580 | |
581 | if (initialized) |
582 | return NULL; |
583 | |
584 | initialized = 1; |
585 | |
586 | qe = qe_get_device_node(); |
587 | if (!qe) |
588 | return NULL; |
589 | |
590 | /* Find the 'firmware' child node */ |
591 | fw = of_get_child_by_name(node: qe, name: "firmware" ); |
592 | of_node_put(node: qe); |
593 | |
594 | /* Did we find the 'firmware' node? */ |
595 | if (!fw) |
596 | return NULL; |
597 | |
598 | qe_firmware_uploaded = 1; |
599 | |
600 | /* Copy the data into qe_firmware_info*/ |
601 | sprop = of_get_property(node: fw, name: "id" , NULL); |
602 | if (sprop) |
603 | strscpy(qe_firmware_info.id, sprop, |
604 | sizeof(qe_firmware_info.id)); |
605 | |
606 | of_property_read_u64(np: fw, propname: "extended-modes" , |
607 | out_value: &qe_firmware_info.extended_modes); |
608 | |
609 | of_property_read_u32_array(np: fw, propname: "virtual-traps" , out_values: qe_firmware_info.vtraps, |
610 | ARRAY_SIZE(qe_firmware_info.vtraps)); |
611 | |
612 | of_node_put(node: fw); |
613 | |
614 | return &qe_firmware_info; |
615 | } |
616 | EXPORT_SYMBOL(qe_get_firmware_info); |
617 | |
618 | unsigned int qe_get_num_of_risc(void) |
619 | { |
620 | struct device_node *qe; |
621 | unsigned int num_of_risc = 0; |
622 | |
623 | qe = qe_get_device_node(); |
624 | if (!qe) |
625 | return num_of_risc; |
626 | |
627 | of_property_read_u32(np: qe, propname: "fsl,qe-num-riscs" , out_value: &num_of_risc); |
628 | |
629 | of_node_put(node: qe); |
630 | |
631 | return num_of_risc; |
632 | } |
633 | EXPORT_SYMBOL(qe_get_num_of_risc); |
634 | |
635 | unsigned int qe_get_num_of_snums(void) |
636 | { |
637 | return qe_num_of_snum; |
638 | } |
639 | EXPORT_SYMBOL(qe_get_num_of_snums); |
640 | |
641 | static int __init qe_init(void) |
642 | { |
643 | struct device_node *np; |
644 | |
645 | np = of_find_compatible_node(NULL, NULL, compat: "fsl,qe" ); |
646 | if (!np) |
647 | return -ENODEV; |
648 | qe_reset(); |
649 | of_node_put(node: np); |
650 | return 0; |
651 | } |
652 | subsys_initcall(qe_init); |
653 | |
654 | #if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC_85xx) |
655 | static int qe_resume(struct platform_device *ofdev) |
656 | { |
657 | if (!qe_alive_during_sleep()) |
658 | qe_reset(); |
659 | return 0; |
660 | } |
661 | |
662 | static int qe_probe(struct platform_device *ofdev) |
663 | { |
664 | return 0; |
665 | } |
666 | |
667 | static const struct of_device_id qe_ids[] = { |
668 | { .compatible = "fsl,qe" , }, |
669 | { }, |
670 | }; |
671 | |
672 | static struct platform_driver qe_driver = { |
673 | .driver = { |
674 | .name = "fsl-qe" , |
675 | .of_match_table = qe_ids, |
676 | }, |
677 | .probe = qe_probe, |
678 | .resume = qe_resume, |
679 | }; |
680 | |
681 | builtin_platform_driver(qe_driver); |
682 | #endif /* defined(CONFIG_SUSPEND) && defined(CONFIG_PPC_85xx) */ |
683 | |