blob: 1ed1a9fd9bcf689b49b11881503556c6054c1b65 [file] [log] [blame]
Li Yang98658532006-10-03 23:10:46 -05001/*
2 * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
3 *
4 * Authors: Shlomi Gridish <gridish@freescale.com>
5 * Li Yang <leoli@freescale.com>
6 * Based on cpm2_common.c from Dan Malek (dmalek@jlc.net)
7 *
8 * Description:
9 * General Purpose functions for the global management of the
10 * QUICC Engine (QE).
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version.
16 */
17#include <linux/errno.h>
18#include <linux/sched.h>
19#include <linux/kernel.h>
20#include <linux/param.h>
21#include <linux/string.h>
Anton Vorontsov09a3fba2008-11-11 18:31:39 +030022#include <linux/spinlock.h>
Li Yang98658532006-10-03 23:10:46 -050023#include <linux/mm.h>
24#include <linux/interrupt.h>
25#include <linux/bootmem.h>
26#include <linux/module.h>
27#include <linux/delay.h>
28#include <linux/ioport.h>
Timur Tabibc556ba2008-01-08 10:30:58 -060029#include <linux/crc32.h>
Li Yang98658532006-10-03 23:10:46 -050030#include <asm/irq.h>
31#include <asm/page.h>
32#include <asm/pgtable.h>
33#include <asm/immap_qe.h>
34#include <asm/qe.h>
35#include <asm/prom.h>
36#include <asm/rheap.h>
37
38static void qe_snums_init(void);
Li Yang98658532006-10-03 23:10:46 -050039static int qe_sdma_init(void);
40
41static DEFINE_SPINLOCK(qe_lock);
Anton Vorontsov09a3fba2008-11-11 18:31:39 +030042DEFINE_SPINLOCK(cmxgcr_lock);
43EXPORT_SYMBOL(cmxgcr_lock);
Li Yang98658532006-10-03 23:10:46 -050044
45/* QE snum state */
46enum qe_snum_state {
47 QE_SNUM_STATE_USED,
48 QE_SNUM_STATE_FREE
49};
50
51/* QE snum */
52struct qe_snum {
53 u8 num;
54 enum qe_snum_state state;
55};
56
57/* We allocate this here because it is used almost exclusively for
58 * the communication processor devices.
59 */
Anton Vorontsov0b51b022008-03-11 20:24:13 +030060struct qe_immap __iomem *qe_immr;
Li Yang98658532006-10-03 23:10:46 -050061EXPORT_SYMBOL(qe_immr);
62
63static struct qe_snum snums[QE_NUM_OF_SNUM]; /* Dynamically allocated SNUMs */
Haiying Wang98ca77a2009-05-01 15:40:48 -040064static unsigned int qe_num_of_snum;
Li Yang98658532006-10-03 23:10:46 -050065
66static phys_addr_t qebase = -1;
67
Anton Vorontsoved241572009-08-27 07:35:50 +000068int qe_alive_during_sleep(void)
69{
70 static int ret = -1;
71
72 if (ret != -1)
73 return ret;
74
75 ret = !of_find_compatible_node(NULL, NULL, "fsl,mpc8569-pmc");
76
77 return ret;
78}
79EXPORT_SYMBOL(qe_alive_during_sleep);
80
Li Yang98658532006-10-03 23:10:46 -050081phys_addr_t get_qe_base(void)
82{
83 struct device_node *qe;
Andy Fleming7e1cc9c2008-05-07 13:19:44 -050084 int size;
Anton Vorontsovd8985fd2008-02-04 16:46:17 +030085 const u32 *prop;
Li Yang98658532006-10-03 23:10:46 -050086
87 if (qebase != -1)
88 return qebase;
89
Anton Vorontsova2dd70a2008-01-24 18:39:59 +030090 qe = of_find_compatible_node(NULL, NULL, "fsl,qe");
91 if (!qe) {
92 qe = of_find_node_by_type(NULL, "qe");
93 if (!qe)
94 return qebase;
95 }
96
97 prop = of_get_property(qe, "reg", &size);
Anton Vorontsovd8985fd2008-02-04 16:46:17 +030098 if (prop && size >= sizeof(*prop))
99 qebase = of_translate_address(qe, prop);
Anton Vorontsova2dd70a2008-01-24 18:39:59 +0300100 of_node_put(qe);
Li Yang98658532006-10-03 23:10:46 -0500101
102 return qebase;
103}
104
105EXPORT_SYMBOL(get_qe_base);
106
Anton Vorontsov0c7b87b2009-09-16 01:43:52 +0400107void qe_reset(void)
Li Yang98658532006-10-03 23:10:46 -0500108{
109 if (qe_immr == NULL)
110 qe_immr = ioremap(get_qe_base(), QE_IMMAP_SIZE);
111
112 qe_snums_init();
113
114 qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID,
115 QE_CR_PROTOCOL_UNSPECIFIED, 0);
116
117 /* Reclaim the MURAM memory for our use. */
118 qe_muram_init();
119
120 if (qe_sdma_init())
121 panic("sdma init failed!");
122}
123
124int qe_issue_cmd(u32 cmd, u32 device, u8 mcn_protocol, u32 cmd_input)
125{
126 unsigned long flags;
127 u8 mcn_shift = 0, dev_shift = 0;
Timur Tabif49156e2009-05-26 10:21:42 -0500128 u32 ret;
Li Yang98658532006-10-03 23:10:46 -0500129
130 spin_lock_irqsave(&qe_lock, flags);
131 if (cmd == QE_RESET) {
132 out_be32(&qe_immr->cp.cecr, (u32) (cmd | QE_CR_FLG));
133 } else {
134 if (cmd == QE_ASSIGN_PAGE) {
135 /* Here device is the SNUM, not sub-block */
136 dev_shift = QE_CR_SNUM_SHIFT;
137 } else if (cmd == QE_ASSIGN_RISC) {
138 /* Here device is the SNUM, and mcnProtocol is
139 * e_QeCmdRiscAssignment value */
140 dev_shift = QE_CR_SNUM_SHIFT;
141 mcn_shift = QE_CR_MCN_RISC_ASSIGN_SHIFT;
142 } else {
143 if (device == QE_CR_SUBBLOCK_USB)
144 mcn_shift = QE_CR_MCN_USB_SHIFT;
145 else
146 mcn_shift = QE_CR_MCN_NORMAL_SHIFT;
147 }
148
Timur Tabi302439d2006-10-31 17:53:42 +0800149 out_be32(&qe_immr->cp.cecdr, cmd_input);
Li Yang98658532006-10-03 23:10:46 -0500150 out_be32(&qe_immr->cp.cecr,
151 (cmd | QE_CR_FLG | ((u32) device << dev_shift) | (u32)
152 mcn_protocol << mcn_shift));
153 }
154
155 /* wait for the QE_CR_FLG to clear */
Timur Tabif49156e2009-05-26 10:21:42 -0500156 ret = spin_event_timeout((in_be32(&qe_immr->cp.cecr) & QE_CR_FLG) == 0,
157 100, 0);
158 /* On timeout (e.g. failure), the expression will be false (ret == 0),
159 otherwise it will be true (ret == 1). */
Li Yang98658532006-10-03 23:10:46 -0500160 spin_unlock_irqrestore(&qe_lock, flags);
161
Timur Tabif49156e2009-05-26 10:21:42 -0500162 return ret == 1;
Li Yang98658532006-10-03 23:10:46 -0500163}
164EXPORT_SYMBOL(qe_issue_cmd);
165
166/* Set a baud rate generator. This needs lots of work. There are
167 * 16 BRGs, which can be connected to the QE channels or output
168 * as clocks. The BRGs are in two different block of internal
169 * memory mapped space.
Timur Tabi6b0b5942007-10-03 11:34:59 -0500170 * The BRG clock is the QE clock divided by 2.
Li Yang98658532006-10-03 23:10:46 -0500171 * It was set up long ago during the initial boot phase and is
172 * is given to us.
173 * Baud rate clocks are zero-based in the driver code (as that maps
174 * to port numbers). Documentation uses 1-based numbering.
175 */
176static unsigned int brg_clk = 0;
177
Anton Vorontsov7f0a6fc2008-03-11 20:24:24 +0300178unsigned int qe_get_brg_clk(void)
Li Yang98658532006-10-03 23:10:46 -0500179{
180 struct device_node *qe;
Andy Fleming7e1cc9c2008-05-07 13:19:44 -0500181 int size;
Anton Vorontsova2dd70a2008-01-24 18:39:59 +0300182 const u32 *prop;
183
Li Yang98658532006-10-03 23:10:46 -0500184 if (brg_clk)
185 return brg_clk;
186
Anton Vorontsova2dd70a2008-01-24 18:39:59 +0300187 qe = of_find_compatible_node(NULL, NULL, "fsl,qe");
188 if (!qe) {
189 qe = of_find_node_by_type(NULL, "qe");
190 if (!qe)
191 return brg_clk;
192 }
193
194 prop = of_get_property(qe, "brg-frequency", &size);
Anton Vorontsovd8985fd2008-02-04 16:46:17 +0300195 if (prop && size == sizeof(*prop))
196 brg_clk = *prop;
Anton Vorontsova2dd70a2008-01-24 18:39:59 +0300197
Anton Vorontsova2dd70a2008-01-24 18:39:59 +0300198 of_node_put(qe);
199
Li Yang98658532006-10-03 23:10:46 -0500200 return brg_clk;
201}
Anton Vorontsov7f0a6fc2008-03-11 20:24:24 +0300202EXPORT_SYMBOL(qe_get_brg_clk);
Li Yang98658532006-10-03 23:10:46 -0500203
Timur Tabi6b0b5942007-10-03 11:34:59 -0500204/* Program the BRG to the given sampling rate and multiplier
205 *
Timur Tabi7264ec42007-11-29 17:26:30 -0600206 * @brg: the BRG, QE_BRG1 - QE_BRG16
Timur Tabi6b0b5942007-10-03 11:34:59 -0500207 * @rate: the desired sampling rate
208 * @multiplier: corresponds to the value programmed in GUMR_L[RDCR] or
209 * GUMR_L[TDCR]. E.g., if this BRG is the RX clock, and GUMR_L[RDCR]=01,
210 * then 'multiplier' should be 8.
Li Yang98658532006-10-03 23:10:46 -0500211 */
Timur Tabi7264ec42007-11-29 17:26:30 -0600212int qe_setbrg(enum qe_clock brg, unsigned int rate, unsigned int multiplier)
Li Yang98658532006-10-03 23:10:46 -0500213{
Li Yang98658532006-10-03 23:10:46 -0500214 u32 divisor, tempval;
Timur Tabi6b0b5942007-10-03 11:34:59 -0500215 u32 div16 = 0;
Li Yang98658532006-10-03 23:10:46 -0500216
Timur Tabi7264ec42007-11-29 17:26:30 -0600217 if ((brg < QE_BRG1) || (brg > QE_BRG16))
218 return -EINVAL;
219
Anton Vorontsov7f0a6fc2008-03-11 20:24:24 +0300220 divisor = qe_get_brg_clk() / (rate * multiplier);
Li Yang98658532006-10-03 23:10:46 -0500221
Li Yang98658532006-10-03 23:10:46 -0500222 if (divisor > QE_BRGC_DIVISOR_MAX + 1) {
Timur Tabi6b0b5942007-10-03 11:34:59 -0500223 div16 = QE_BRGC_DIV16;
Li Yang98658532006-10-03 23:10:46 -0500224 divisor /= 16;
225 }
226
Timur Tabi6b0b5942007-10-03 11:34:59 -0500227 /* Errata QE_General4, which affects some MPC832x and MPC836x SOCs, says
228 that the BRG divisor must be even if you're not using divide-by-16
229 mode. */
230 if (!div16 && (divisor & 1))
231 divisor++;
Li Yang98658532006-10-03 23:10:46 -0500232
Timur Tabi6b0b5942007-10-03 11:34:59 -0500233 tempval = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) |
234 QE_BRGC_ENABLE | div16;
235
Timur Tabi7264ec42007-11-29 17:26:30 -0600236 out_be32(&qe_immr->brg.brgc[brg - QE_BRG1], tempval);
237
238 return 0;
Li Yang98658532006-10-03 23:10:46 -0500239}
Timur Tabi7264ec42007-11-29 17:26:30 -0600240EXPORT_SYMBOL(qe_setbrg);
Li Yang98658532006-10-03 23:10:46 -0500241
Timur Tabi174b0da2007-12-03 15:17:58 -0600242/* Convert a string to a QE clock source enum
243 *
244 * This function takes a string, typically from a property in the device
245 * tree, and returns the corresponding "enum qe_clock" value.
246*/
247enum qe_clock qe_clock_source(const char *source)
248{
249 unsigned int i;
250
251 if (strcasecmp(source, "none") == 0)
252 return QE_CLK_NONE;
253
254 if (strncasecmp(source, "brg", 3) == 0) {
255 i = simple_strtoul(source + 3, NULL, 10);
256 if ((i >= 1) && (i <= 16))
257 return (QE_BRG1 - 1) + i;
258 else
259 return QE_CLK_DUMMY;
260 }
261
262 if (strncasecmp(source, "clk", 3) == 0) {
263 i = simple_strtoul(source + 3, NULL, 10);
264 if ((i >= 1) && (i <= 24))
265 return (QE_CLK1 - 1) + i;
266 else
267 return QE_CLK_DUMMY;
268 }
269
270 return QE_CLK_DUMMY;
271}
272EXPORT_SYMBOL(qe_clock_source);
273
Li Yang98658532006-10-03 23:10:46 -0500274/* Initialize SNUMs (thread serial numbers) according to
275 * QE Module Control chapter, SNUM table
276 */
277static void qe_snums_init(void)
278{
279 int i;
280 static const u8 snum_init[] = {
281 0x04, 0x05, 0x0C, 0x0D, 0x14, 0x15, 0x1C, 0x1D,
282 0x24, 0x25, 0x2C, 0x2D, 0x34, 0x35, 0x88, 0x89,
283 0x98, 0x99, 0xA8, 0xA9, 0xB8, 0xB9, 0xC8, 0xC9,
Haiying Wang98ca77a2009-05-01 15:40:48 -0400284 0xD8, 0xD9, 0xE8, 0xE9, 0x08, 0x09, 0x18, 0x19,
285 0x28, 0x29, 0x38, 0x39, 0x48, 0x49, 0x58, 0x59,
286 0x68, 0x69, 0x78, 0x79, 0x80, 0x81,
Li Yang98658532006-10-03 23:10:46 -0500287 };
288
Haiying Wang98ca77a2009-05-01 15:40:48 -0400289 qe_num_of_snum = qe_get_num_of_snums();
290
291 for (i = 0; i < qe_num_of_snum; i++) {
Li Yang98658532006-10-03 23:10:46 -0500292 snums[i].num = snum_init[i];
293 snums[i].state = QE_SNUM_STATE_FREE;
294 }
295}
296
297int qe_get_snum(void)
298{
299 unsigned long flags;
300 int snum = -EBUSY;
301 int i;
302
303 spin_lock_irqsave(&qe_lock, flags);
Haiying Wang98ca77a2009-05-01 15:40:48 -0400304 for (i = 0; i < qe_num_of_snum; i++) {
Li Yang98658532006-10-03 23:10:46 -0500305 if (snums[i].state == QE_SNUM_STATE_FREE) {
306 snums[i].state = QE_SNUM_STATE_USED;
307 snum = snums[i].num;
308 break;
309 }
310 }
311 spin_unlock_irqrestore(&qe_lock, flags);
312
313 return snum;
314}
315EXPORT_SYMBOL(qe_get_snum);
316
317void qe_put_snum(u8 snum)
318{
319 int i;
320
Haiying Wang98ca77a2009-05-01 15:40:48 -0400321 for (i = 0; i < qe_num_of_snum; i++) {
Li Yang98658532006-10-03 23:10:46 -0500322 if (snums[i].num == snum) {
323 snums[i].state = QE_SNUM_STATE_FREE;
324 break;
325 }
326 }
327}
328EXPORT_SYMBOL(qe_put_snum);
329
330static int qe_sdma_init(void)
331{
Andy Fleming7e1cc9c2008-05-07 13:19:44 -0500332 struct sdma __iomem *sdma = &qe_immr->sdma;
Anton Vorontsov0c7b87b2009-09-16 01:43:52 +0400333 static unsigned long sdma_buf_offset = (unsigned long)-ENOMEM;
Li Yang98658532006-10-03 23:10:46 -0500334
335 if (!sdma)
336 return -ENODEV;
337
338 /* allocate 2 internal temporary buffers (512 bytes size each) for
339 * the SDMA */
Anton Vorontsov0c7b87b2009-09-16 01:43:52 +0400340 if (IS_ERR_VALUE(sdma_buf_offset)) {
341 sdma_buf_offset = qe_muram_alloc(512 * 2, 4096);
342 if (IS_ERR_VALUE(sdma_buf_offset))
343 return -ENOMEM;
344 }
Li Yang98658532006-10-03 23:10:46 -0500345
Timur Tabi4c356302007-05-08 14:46:36 -0500346 out_be32(&sdma->sdebcr, (u32) sdma_buf_offset & QE_SDEBCR_BA_MASK);
Chuck Meade7f013bc2007-03-27 10:46:10 -0400347 out_be32(&sdma->sdmr, (QE_SDMR_GLB_1_MSK |
348 (0x1 << QE_SDMR_CEN_SHIFT)));
Li Yang98658532006-10-03 23:10:46 -0500349
350 return 0;
351}
352
Timur Tabibc556ba2008-01-08 10:30:58 -0600353/* The maximum number of RISCs we support */
Anton Vorontsov98eaa092009-08-27 21:30:11 +0400354#define MAX_QE_RISC 4
Timur Tabibc556ba2008-01-08 10:30:58 -0600355
356/* Firmware information stored here for qe_get_firmware_info() */
357static struct qe_firmware_info qe_firmware_info;
358
359/*
360 * Set to 1 if QE firmware has been uploaded, and therefore
361 * qe_firmware_info contains valid data.
362 */
363static int qe_firmware_uploaded;
364
365/*
366 * Upload a QE microcode
367 *
368 * This function is a worker function for qe_upload_firmware(). It does
369 * the actual uploading of the microcode.
370 */
371static void qe_upload_microcode(const void *base,
372 const struct qe_microcode *ucode)
373{
374 const __be32 *code = base + be32_to_cpu(ucode->code_offset);
375 unsigned int i;
376
377 if (ucode->major || ucode->minor || ucode->revision)
378 printk(KERN_INFO "qe-firmware: "
379 "uploading microcode '%s' version %u.%u.%u\n",
380 ucode->id, ucode->major, ucode->minor, ucode->revision);
381 else
382 printk(KERN_INFO "qe-firmware: "
383 "uploading microcode '%s'\n", ucode->id);
384
385 /* Use auto-increment */
386 out_be32(&qe_immr->iram.iadd, be32_to_cpu(ucode->iram_offset) |
387 QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR);
388
389 for (i = 0; i < be32_to_cpu(ucode->count); i++)
390 out_be32(&qe_immr->iram.idata, be32_to_cpu(code[i]));
391}
392
393/*
394 * Upload a microcode to the I-RAM at a specific address.
395 *
396 * See Documentation/powerpc/qe-firmware.txt for information on QE microcode
397 * uploading.
398 *
399 * Currently, only version 1 is supported, so the 'version' field must be
400 * set to 1.
401 *
402 * The SOC model and revision are not validated, they are only displayed for
403 * informational purposes.
404 *
405 * 'calc_size' is the calculated size, in bytes, of the firmware structure and
406 * all of the microcode structures, minus the CRC.
407 *
408 * 'length' is the size that the structure says it is, including the CRC.
409 */
410int qe_upload_firmware(const struct qe_firmware *firmware)
411{
412 unsigned int i;
413 unsigned int j;
414 u32 crc;
415 size_t calc_size = sizeof(struct qe_firmware);
416 size_t length;
417 const struct qe_header *hdr;
418
419 if (!firmware) {
420 printk(KERN_ERR "qe-firmware: invalid pointer\n");
421 return -EINVAL;
422 }
423
424 hdr = &firmware->header;
425 length = be32_to_cpu(hdr->length);
426
427 /* Check the magic */
428 if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
429 (hdr->magic[2] != 'F')) {
430 printk(KERN_ERR "qe-firmware: not a microcode\n");
431 return -EPERM;
432 }
433
434 /* Check the version */
435 if (hdr->version != 1) {
436 printk(KERN_ERR "qe-firmware: unsupported version\n");
437 return -EPERM;
438 }
439
440 /* Validate some of the fields */
Timur Tabi6f913162008-03-03 11:11:30 -0600441 if ((firmware->count < 1) || (firmware->count > MAX_QE_RISC)) {
Timur Tabibc556ba2008-01-08 10:30:58 -0600442 printk(KERN_ERR "qe-firmware: invalid data\n");
443 return -EINVAL;
444 }
445
446 /* Validate the length and check if there's a CRC */
447 calc_size += (firmware->count - 1) * sizeof(struct qe_microcode);
448
449 for (i = 0; i < firmware->count; i++)
450 /*
451 * For situations where the second RISC uses the same microcode
452 * as the first, the 'code_offset' and 'count' fields will be
453 * zero, so it's okay to add those.
454 */
455 calc_size += sizeof(__be32) *
456 be32_to_cpu(firmware->microcode[i].count);
457
458 /* Validate the length */
459 if (length != calc_size + sizeof(__be32)) {
460 printk(KERN_ERR "qe-firmware: invalid length\n");
461 return -EPERM;
462 }
463
464 /* Validate the CRC */
465 crc = be32_to_cpu(*(__be32 *)((void *)firmware + calc_size));
466 if (crc != crc32(0, firmware, calc_size)) {
467 printk(KERN_ERR "qe-firmware: firmware CRC is invalid\n");
468 return -EIO;
469 }
470
471 /*
472 * If the microcode calls for it, split the I-RAM.
473 */
474 if (!firmware->split)
475 setbits16(&qe_immr->cp.cercr, QE_CP_CERCR_CIR);
476
477 if (firmware->soc.model)
478 printk(KERN_INFO
479 "qe-firmware: firmware '%s' for %u V%u.%u\n",
480 firmware->id, be16_to_cpu(firmware->soc.model),
481 firmware->soc.major, firmware->soc.minor);
482 else
483 printk(KERN_INFO "qe-firmware: firmware '%s'\n",
484 firmware->id);
485
486 /*
487 * The QE only supports one microcode per RISC, so clear out all the
488 * saved microcode information and put in the new.
489 */
490 memset(&qe_firmware_info, 0, sizeof(qe_firmware_info));
491 strcpy(qe_firmware_info.id, firmware->id);
492 qe_firmware_info.extended_modes = firmware->extended_modes;
493 memcpy(qe_firmware_info.vtraps, firmware->vtraps,
494 sizeof(firmware->vtraps));
495
496 /* Loop through each microcode. */
497 for (i = 0; i < firmware->count; i++) {
498 const struct qe_microcode *ucode = &firmware->microcode[i];
499
500 /* Upload a microcode if it's present */
501 if (ucode->code_offset)
502 qe_upload_microcode(firmware, ucode);
503
504 /* Program the traps for this processor */
505 for (j = 0; j < 16; j++) {
506 u32 trap = be32_to_cpu(ucode->traps[j]);
507
508 if (trap)
509 out_be32(&qe_immr->rsp[i].tibcr[j], trap);
510 }
511
512 /* Enable traps */
513 out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
514 }
515
516 qe_firmware_uploaded = 1;
517
518 return 0;
519}
520EXPORT_SYMBOL(qe_upload_firmware);
521
522/*
523 * Get info on the currently-loaded firmware
524 *
525 * This function also checks the device tree to see if the boot loader has
526 * uploaded a firmware already.
527 */
528struct qe_firmware_info *qe_get_firmware_info(void)
529{
530 static int initialized;
531 struct property *prop;
532 struct device_node *qe;
533 struct device_node *fw = NULL;
534 const char *sprop;
535 unsigned int i;
536
537 /*
538 * If we haven't checked yet, and a driver hasn't uploaded a firmware
539 * yet, then check the device tree for information.
540 */
Ionut Nicu86f4e5d2008-03-07 19:27:59 +0200541 if (qe_firmware_uploaded)
542 return &qe_firmware_info;
543
544 if (initialized)
Timur Tabibc556ba2008-01-08 10:30:58 -0600545 return NULL;
546
547 initialized = 1;
548
549 /*
550 * Newer device trees have an "fsl,qe" compatible property for the QE
551 * node, but we still need to support older device trees.
552 */
553 qe = of_find_compatible_node(NULL, NULL, "fsl,qe");
554 if (!qe) {
555 qe = of_find_node_by_type(NULL, "qe");
556 if (!qe)
557 return NULL;
558 }
559
560 /* Find the 'firmware' child node */
561 for_each_child_of_node(qe, fw) {
562 if (strcmp(fw->name, "firmware") == 0)
563 break;
564 }
565
566 of_node_put(qe);
567
568 /* Did we find the 'firmware' node? */
569 if (!fw)
570 return NULL;
571
572 qe_firmware_uploaded = 1;
573
574 /* Copy the data into qe_firmware_info*/
575 sprop = of_get_property(fw, "id", NULL);
576 if (sprop)
577 strncpy(qe_firmware_info.id, sprop,
578 sizeof(qe_firmware_info.id) - 1);
579
580 prop = of_find_property(fw, "extended-modes", NULL);
581 if (prop && (prop->length == sizeof(u64))) {
582 const u64 *iprop = prop->value;
583
584 qe_firmware_info.extended_modes = *iprop;
585 }
586
587 prop = of_find_property(fw, "virtual-traps", NULL);
588 if (prop && (prop->length == 32)) {
589 const u32 *iprop = prop->value;
590
591 for (i = 0; i < ARRAY_SIZE(qe_firmware_info.vtraps); i++)
592 qe_firmware_info.vtraps[i] = iprop[i];
593 }
594
595 of_node_put(fw);
596
597 return &qe_firmware_info;
598}
599EXPORT_SYMBOL(qe_get_firmware_info);
600
Haiying Wang06c44352009-05-01 15:40:47 -0400601unsigned int qe_get_num_of_risc(void)
602{
603 struct device_node *qe;
604 int size;
605 unsigned int num_of_risc = 0;
606 const u32 *prop;
607
608 qe = of_find_compatible_node(NULL, NULL, "fsl,qe");
609 if (!qe) {
610 /* Older devices trees did not have an "fsl,qe"
611 * compatible property, so we need to look for
612 * the QE node by name.
613 */
614 qe = of_find_node_by_type(NULL, "qe");
615 if (!qe)
616 return num_of_risc;
617 }
618
619 prop = of_get_property(qe, "fsl,qe-num-riscs", &size);
620 if (prop && size == sizeof(*prop))
621 num_of_risc = *prop;
622
623 of_node_put(qe);
624
625 return num_of_risc;
626}
627EXPORT_SYMBOL(qe_get_num_of_risc);
628
Haiying Wang98ca77a2009-05-01 15:40:48 -0400629unsigned int qe_get_num_of_snums(void)
630{
631 struct device_node *qe;
632 int size;
633 unsigned int num_of_snums;
634 const u32 *prop;
635
636 num_of_snums = 28; /* The default number of snum for threads is 28 */
637 qe = of_find_compatible_node(NULL, NULL, "fsl,qe");
638 if (!qe) {
639 /* Older devices trees did not have an "fsl,qe"
640 * compatible property, so we need to look for
641 * the QE node by name.
642 */
643 qe = of_find_node_by_type(NULL, "qe");
644 if (!qe)
645 return num_of_snums;
646 }
647
648 prop = of_get_property(qe, "fsl,qe-num-snums", &size);
649 if (prop && size == sizeof(*prop)) {
650 num_of_snums = *prop;
651 if ((num_of_snums < 28) || (num_of_snums > QE_NUM_OF_SNUM)) {
652 /* No QE ever has fewer than 28 SNUMs */
653 pr_err("QE: number of snum is invalid\n");
654 return -EINVAL;
655 }
656 }
657
658 of_node_put(qe);
659
660 return num_of_snums;
661}
662EXPORT_SYMBOL(qe_get_num_of_snums);