blob: cc81fd1141b031ffe476a12f033a7c925aff8f79 [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>
22#include <linux/mm.h>
23#include <linux/interrupt.h>
24#include <linux/bootmem.h>
25#include <linux/module.h>
26#include <linux/delay.h>
27#include <linux/ioport.h>
Timur Tabibc556ba2008-01-08 10:30:58 -060028#include <linux/crc32.h>
Li Yang98658532006-10-03 23:10:46 -050029#include <asm/irq.h>
30#include <asm/page.h>
31#include <asm/pgtable.h>
32#include <asm/immap_qe.h>
33#include <asm/qe.h>
34#include <asm/prom.h>
35#include <asm/rheap.h>
36
37static void qe_snums_init(void);
38static void qe_muram_init(void);
39static int qe_sdma_init(void);
40
41static DEFINE_SPINLOCK(qe_lock);
42
43/* QE snum state */
44enum qe_snum_state {
45 QE_SNUM_STATE_USED,
46 QE_SNUM_STATE_FREE
47};
48
49/* QE snum */
50struct qe_snum {
51 u8 num;
52 enum qe_snum_state state;
53};
54
55/* We allocate this here because it is used almost exclusively for
56 * the communication processor devices.
57 */
58struct qe_immap *qe_immr = NULL;
59EXPORT_SYMBOL(qe_immr);
60
61static struct qe_snum snums[QE_NUM_OF_SNUM]; /* Dynamically allocated SNUMs */
62
63static phys_addr_t qebase = -1;
64
65phys_addr_t get_qe_base(void)
66{
67 struct device_node *qe;
Anton Vorontsova2dd70a2008-01-24 18:39:59 +030068 unsigned int size;
Anton Vorontsovd8985fd2008-02-04 16:46:17 +030069 const u32 *prop;
Li Yang98658532006-10-03 23:10:46 -050070
71 if (qebase != -1)
72 return qebase;
73
Anton Vorontsova2dd70a2008-01-24 18:39:59 +030074 qe = of_find_compatible_node(NULL, NULL, "fsl,qe");
75 if (!qe) {
76 qe = of_find_node_by_type(NULL, "qe");
77 if (!qe)
78 return qebase;
79 }
80
81 prop = of_get_property(qe, "reg", &size);
Anton Vorontsovd8985fd2008-02-04 16:46:17 +030082 if (prop && size >= sizeof(*prop))
83 qebase = of_translate_address(qe, prop);
Anton Vorontsova2dd70a2008-01-24 18:39:59 +030084 of_node_put(qe);
Li Yang98658532006-10-03 23:10:46 -050085
86 return qebase;
87}
88
89EXPORT_SYMBOL(get_qe_base);
90
91void qe_reset(void)
92{
93 if (qe_immr == NULL)
94 qe_immr = ioremap(get_qe_base(), QE_IMMAP_SIZE);
95
96 qe_snums_init();
97
98 qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID,
99 QE_CR_PROTOCOL_UNSPECIFIED, 0);
100
101 /* Reclaim the MURAM memory for our use. */
102 qe_muram_init();
103
104 if (qe_sdma_init())
105 panic("sdma init failed!");
106}
107
108int qe_issue_cmd(u32 cmd, u32 device, u8 mcn_protocol, u32 cmd_input)
109{
110 unsigned long flags;
111 u8 mcn_shift = 0, dev_shift = 0;
112
113 spin_lock_irqsave(&qe_lock, flags);
114 if (cmd == QE_RESET) {
115 out_be32(&qe_immr->cp.cecr, (u32) (cmd | QE_CR_FLG));
116 } else {
117 if (cmd == QE_ASSIGN_PAGE) {
118 /* Here device is the SNUM, not sub-block */
119 dev_shift = QE_CR_SNUM_SHIFT;
120 } else if (cmd == QE_ASSIGN_RISC) {
121 /* Here device is the SNUM, and mcnProtocol is
122 * e_QeCmdRiscAssignment value */
123 dev_shift = QE_CR_SNUM_SHIFT;
124 mcn_shift = QE_CR_MCN_RISC_ASSIGN_SHIFT;
125 } else {
126 if (device == QE_CR_SUBBLOCK_USB)
127 mcn_shift = QE_CR_MCN_USB_SHIFT;
128 else
129 mcn_shift = QE_CR_MCN_NORMAL_SHIFT;
130 }
131
Timur Tabi302439d2006-10-31 17:53:42 +0800132 out_be32(&qe_immr->cp.cecdr, cmd_input);
Li Yang98658532006-10-03 23:10:46 -0500133 out_be32(&qe_immr->cp.cecr,
134 (cmd | QE_CR_FLG | ((u32) device << dev_shift) | (u32)
135 mcn_protocol << mcn_shift));
136 }
137
138 /* wait for the QE_CR_FLG to clear */
139 while(in_be32(&qe_immr->cp.cecr) & QE_CR_FLG)
140 cpu_relax();
141 spin_unlock_irqrestore(&qe_lock, flags);
142
143 return 0;
144}
145EXPORT_SYMBOL(qe_issue_cmd);
146
147/* Set a baud rate generator. This needs lots of work. There are
148 * 16 BRGs, which can be connected to the QE channels or output
149 * as clocks. The BRGs are in two different block of internal
150 * memory mapped space.
Timur Tabi6b0b5942007-10-03 11:34:59 -0500151 * The BRG clock is the QE clock divided by 2.
Li Yang98658532006-10-03 23:10:46 -0500152 * It was set up long ago during the initial boot phase and is
153 * is given to us.
154 * Baud rate clocks are zero-based in the driver code (as that maps
155 * to port numbers). Documentation uses 1-based numbering.
156 */
157static unsigned int brg_clk = 0;
158
159unsigned int get_brg_clk(void)
160{
161 struct device_node *qe;
Anton Vorontsova2dd70a2008-01-24 18:39:59 +0300162 unsigned int size;
163 const u32 *prop;
164
Li Yang98658532006-10-03 23:10:46 -0500165 if (brg_clk)
166 return brg_clk;
167
Anton Vorontsova2dd70a2008-01-24 18:39:59 +0300168 qe = of_find_compatible_node(NULL, NULL, "fsl,qe");
169 if (!qe) {
170 qe = of_find_node_by_type(NULL, "qe");
171 if (!qe)
172 return brg_clk;
173 }
174
175 prop = of_get_property(qe, "brg-frequency", &size);
Anton Vorontsovd8985fd2008-02-04 16:46:17 +0300176 if (prop && size == sizeof(*prop))
177 brg_clk = *prop;
Anton Vorontsova2dd70a2008-01-24 18:39:59 +0300178
Anton Vorontsova2dd70a2008-01-24 18:39:59 +0300179 of_node_put(qe);
180
Li Yang98658532006-10-03 23:10:46 -0500181 return brg_clk;
182}
183
Timur Tabi6b0b5942007-10-03 11:34:59 -0500184/* Program the BRG to the given sampling rate and multiplier
185 *
Timur Tabi7264ec42007-11-29 17:26:30 -0600186 * @brg: the BRG, QE_BRG1 - QE_BRG16
Timur Tabi6b0b5942007-10-03 11:34:59 -0500187 * @rate: the desired sampling rate
188 * @multiplier: corresponds to the value programmed in GUMR_L[RDCR] or
189 * GUMR_L[TDCR]. E.g., if this BRG is the RX clock, and GUMR_L[RDCR]=01,
190 * then 'multiplier' should be 8.
Li Yang98658532006-10-03 23:10:46 -0500191 */
Timur Tabi7264ec42007-11-29 17:26:30 -0600192int qe_setbrg(enum qe_clock brg, unsigned int rate, unsigned int multiplier)
Li Yang98658532006-10-03 23:10:46 -0500193{
Li Yang98658532006-10-03 23:10:46 -0500194 u32 divisor, tempval;
Timur Tabi6b0b5942007-10-03 11:34:59 -0500195 u32 div16 = 0;
Li Yang98658532006-10-03 23:10:46 -0500196
Timur Tabi7264ec42007-11-29 17:26:30 -0600197 if ((brg < QE_BRG1) || (brg > QE_BRG16))
198 return -EINVAL;
199
Timur Tabi6b0b5942007-10-03 11:34:59 -0500200 divisor = get_brg_clk() / (rate * multiplier);
Li Yang98658532006-10-03 23:10:46 -0500201
Li Yang98658532006-10-03 23:10:46 -0500202 if (divisor > QE_BRGC_DIVISOR_MAX + 1) {
Timur Tabi6b0b5942007-10-03 11:34:59 -0500203 div16 = QE_BRGC_DIV16;
Li Yang98658532006-10-03 23:10:46 -0500204 divisor /= 16;
205 }
206
Timur Tabi6b0b5942007-10-03 11:34:59 -0500207 /* Errata QE_General4, which affects some MPC832x and MPC836x SOCs, says
208 that the BRG divisor must be even if you're not using divide-by-16
209 mode. */
210 if (!div16 && (divisor & 1))
211 divisor++;
Li Yang98658532006-10-03 23:10:46 -0500212
Timur Tabi6b0b5942007-10-03 11:34:59 -0500213 tempval = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) |
214 QE_BRGC_ENABLE | div16;
215
Timur Tabi7264ec42007-11-29 17:26:30 -0600216 out_be32(&qe_immr->brg.brgc[brg - QE_BRG1], tempval);
217
218 return 0;
Li Yang98658532006-10-03 23:10:46 -0500219}
Timur Tabi7264ec42007-11-29 17:26:30 -0600220EXPORT_SYMBOL(qe_setbrg);
Li Yang98658532006-10-03 23:10:46 -0500221
Timur Tabi174b0da2007-12-03 15:17:58 -0600222/* Convert a string to a QE clock source enum
223 *
224 * This function takes a string, typically from a property in the device
225 * tree, and returns the corresponding "enum qe_clock" value.
226*/
227enum qe_clock qe_clock_source(const char *source)
228{
229 unsigned int i;
230
231 if (strcasecmp(source, "none") == 0)
232 return QE_CLK_NONE;
233
234 if (strncasecmp(source, "brg", 3) == 0) {
235 i = simple_strtoul(source + 3, NULL, 10);
236 if ((i >= 1) && (i <= 16))
237 return (QE_BRG1 - 1) + i;
238 else
239 return QE_CLK_DUMMY;
240 }
241
242 if (strncasecmp(source, "clk", 3) == 0) {
243 i = simple_strtoul(source + 3, NULL, 10);
244 if ((i >= 1) && (i <= 24))
245 return (QE_CLK1 - 1) + i;
246 else
247 return QE_CLK_DUMMY;
248 }
249
250 return QE_CLK_DUMMY;
251}
252EXPORT_SYMBOL(qe_clock_source);
253
Li Yang98658532006-10-03 23:10:46 -0500254/* Initialize SNUMs (thread serial numbers) according to
255 * QE Module Control chapter, SNUM table
256 */
257static void qe_snums_init(void)
258{
259 int i;
260 static const u8 snum_init[] = {
261 0x04, 0x05, 0x0C, 0x0D, 0x14, 0x15, 0x1C, 0x1D,
262 0x24, 0x25, 0x2C, 0x2D, 0x34, 0x35, 0x88, 0x89,
263 0x98, 0x99, 0xA8, 0xA9, 0xB8, 0xB9, 0xC8, 0xC9,
264 0xD8, 0xD9, 0xE8, 0xE9,
265 };
266
267 for (i = 0; i < QE_NUM_OF_SNUM; i++) {
268 snums[i].num = snum_init[i];
269 snums[i].state = QE_SNUM_STATE_FREE;
270 }
271}
272
273int qe_get_snum(void)
274{
275 unsigned long flags;
276 int snum = -EBUSY;
277 int i;
278
279 spin_lock_irqsave(&qe_lock, flags);
280 for (i = 0; i < QE_NUM_OF_SNUM; i++) {
281 if (snums[i].state == QE_SNUM_STATE_FREE) {
282 snums[i].state = QE_SNUM_STATE_USED;
283 snum = snums[i].num;
284 break;
285 }
286 }
287 spin_unlock_irqrestore(&qe_lock, flags);
288
289 return snum;
290}
291EXPORT_SYMBOL(qe_get_snum);
292
293void qe_put_snum(u8 snum)
294{
295 int i;
296
297 for (i = 0; i < QE_NUM_OF_SNUM; i++) {
298 if (snums[i].num == snum) {
299 snums[i].state = QE_SNUM_STATE_FREE;
300 break;
301 }
302 }
303}
304EXPORT_SYMBOL(qe_put_snum);
305
306static int qe_sdma_init(void)
307{
308 struct sdma *sdma = &qe_immr->sdma;
Timur Tabi4c356302007-05-08 14:46:36 -0500309 unsigned long sdma_buf_offset;
Li Yang98658532006-10-03 23:10:46 -0500310
311 if (!sdma)
312 return -ENODEV;
313
314 /* allocate 2 internal temporary buffers (512 bytes size each) for
315 * the SDMA */
Chuck Meade7f013bc2007-03-27 10:46:10 -0400316 sdma_buf_offset = qe_muram_alloc(512 * 2, 4096);
Timur Tabi4c356302007-05-08 14:46:36 -0500317 if (IS_ERR_VALUE(sdma_buf_offset))
Li Yang98658532006-10-03 23:10:46 -0500318 return -ENOMEM;
319
Timur Tabi4c356302007-05-08 14:46:36 -0500320 out_be32(&sdma->sdebcr, (u32) sdma_buf_offset & QE_SDEBCR_BA_MASK);
Chuck Meade7f013bc2007-03-27 10:46:10 -0400321 out_be32(&sdma->sdmr, (QE_SDMR_GLB_1_MSK |
322 (0x1 << QE_SDMR_CEN_SHIFT)));
Li Yang98658532006-10-03 23:10:46 -0500323
324 return 0;
325}
326
327/*
328 * muram_alloc / muram_free bits.
329 */
330static DEFINE_SPINLOCK(qe_muram_lock);
331
332/* 16 blocks should be enough to satisfy all requests
333 * until the memory subsystem goes up... */
334static rh_block_t qe_boot_muram_rh_block[16];
335static rh_info_t qe_muram_info;
336
337static void qe_muram_init(void)
338{
339 struct device_node *np;
Anton Vorontsova2dd70a2008-01-24 18:39:59 +0300340 const u32 *address;
Li Yang98658532006-10-03 23:10:46 -0500341 u64 size;
342 unsigned int flags;
343
344 /* initialize the info header */
345 rh_init(&qe_muram_info, 1,
346 sizeof(qe_boot_muram_rh_block) /
347 sizeof(qe_boot_muram_rh_block[0]), qe_boot_muram_rh_block);
348
349 /* Attach the usable muram area */
350 /* XXX: This is a subset of the available muram. It
351 * varies with the processor and the microcode patches activated.
352 */
Anton Vorontsova2dd70a2008-01-24 18:39:59 +0300353 np = of_find_compatible_node(NULL, NULL, "fsl,qe-muram-data");
354 if (!np) {
355 np = of_find_node_by_name(NULL, "data-only");
356 if (!np) {
357 WARN_ON(1);
358 return;
359 }
Li Yang98658532006-10-03 23:10:46 -0500360 }
Anton Vorontsova2dd70a2008-01-24 18:39:59 +0300361
362 address = of_get_address(np, 0, &size, &flags);
363 WARN_ON(!address);
364
365 of_node_put(np);
366 if (address)
367 rh_attach_region(&qe_muram_info, *address, (int)size);
Li Yang98658532006-10-03 23:10:46 -0500368}
369
370/* This function returns an index into the MURAM area.
371 */
Timur Tabi4c356302007-05-08 14:46:36 -0500372unsigned long qe_muram_alloc(int size, int align)
Li Yang98658532006-10-03 23:10:46 -0500373{
Timur Tabi4c356302007-05-08 14:46:36 -0500374 unsigned long start;
Li Yang98658532006-10-03 23:10:46 -0500375 unsigned long flags;
376
377 spin_lock_irqsave(&qe_muram_lock, flags);
378 start = rh_alloc_align(&qe_muram_info, size, align, "QE");
379 spin_unlock_irqrestore(&qe_muram_lock, flags);
380
Timur Tabi4c356302007-05-08 14:46:36 -0500381 return start;
Li Yang98658532006-10-03 23:10:46 -0500382}
383EXPORT_SYMBOL(qe_muram_alloc);
384
Timur Tabi4c356302007-05-08 14:46:36 -0500385int qe_muram_free(unsigned long offset)
Li Yang98658532006-10-03 23:10:46 -0500386{
387 int ret;
388 unsigned long flags;
389
390 spin_lock_irqsave(&qe_muram_lock, flags);
Timur Tabi4c356302007-05-08 14:46:36 -0500391 ret = rh_free(&qe_muram_info, offset);
Li Yang98658532006-10-03 23:10:46 -0500392 spin_unlock_irqrestore(&qe_muram_lock, flags);
393
394 return ret;
395}
396EXPORT_SYMBOL(qe_muram_free);
397
398/* not sure if this is ever needed */
Timur Tabi4c356302007-05-08 14:46:36 -0500399unsigned long qe_muram_alloc_fixed(unsigned long offset, int size)
Li Yang98658532006-10-03 23:10:46 -0500400{
Timur Tabi4c356302007-05-08 14:46:36 -0500401 unsigned long start;
Li Yang98658532006-10-03 23:10:46 -0500402 unsigned long flags;
403
404 spin_lock_irqsave(&qe_muram_lock, flags);
Timur Tabi4c356302007-05-08 14:46:36 -0500405 start = rh_alloc_fixed(&qe_muram_info, offset, size, "commproc");
Li Yang98658532006-10-03 23:10:46 -0500406 spin_unlock_irqrestore(&qe_muram_lock, flags);
407
Timur Tabi4c356302007-05-08 14:46:36 -0500408 return start;
Li Yang98658532006-10-03 23:10:46 -0500409}
410EXPORT_SYMBOL(qe_muram_alloc_fixed);
411
412void qe_muram_dump(void)
413{
414 rh_dump(&qe_muram_info);
415}
416EXPORT_SYMBOL(qe_muram_dump);
417
Timur Tabi4c356302007-05-08 14:46:36 -0500418void *qe_muram_addr(unsigned long offset)
Li Yang98658532006-10-03 23:10:46 -0500419{
420 return (void *)&qe_immr->muram[offset];
421}
422EXPORT_SYMBOL(qe_muram_addr);
Timur Tabibc556ba2008-01-08 10:30:58 -0600423
424/* The maximum number of RISCs we support */
425#define MAX_QE_RISC 2
426
427/* Firmware information stored here for qe_get_firmware_info() */
428static struct qe_firmware_info qe_firmware_info;
429
430/*
431 * Set to 1 if QE firmware has been uploaded, and therefore
432 * qe_firmware_info contains valid data.
433 */
434static int qe_firmware_uploaded;
435
436/*
437 * Upload a QE microcode
438 *
439 * This function is a worker function for qe_upload_firmware(). It does
440 * the actual uploading of the microcode.
441 */
442static void qe_upload_microcode(const void *base,
443 const struct qe_microcode *ucode)
444{
445 const __be32 *code = base + be32_to_cpu(ucode->code_offset);
446 unsigned int i;
447
448 if (ucode->major || ucode->minor || ucode->revision)
449 printk(KERN_INFO "qe-firmware: "
450 "uploading microcode '%s' version %u.%u.%u\n",
451 ucode->id, ucode->major, ucode->minor, ucode->revision);
452 else
453 printk(KERN_INFO "qe-firmware: "
454 "uploading microcode '%s'\n", ucode->id);
455
456 /* Use auto-increment */
457 out_be32(&qe_immr->iram.iadd, be32_to_cpu(ucode->iram_offset) |
458 QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR);
459
460 for (i = 0; i < be32_to_cpu(ucode->count); i++)
461 out_be32(&qe_immr->iram.idata, be32_to_cpu(code[i]));
462}
463
464/*
465 * Upload a microcode to the I-RAM at a specific address.
466 *
467 * See Documentation/powerpc/qe-firmware.txt for information on QE microcode
468 * uploading.
469 *
470 * Currently, only version 1 is supported, so the 'version' field must be
471 * set to 1.
472 *
473 * The SOC model and revision are not validated, they are only displayed for
474 * informational purposes.
475 *
476 * 'calc_size' is the calculated size, in bytes, of the firmware structure and
477 * all of the microcode structures, minus the CRC.
478 *
479 * 'length' is the size that the structure says it is, including the CRC.
480 */
481int qe_upload_firmware(const struct qe_firmware *firmware)
482{
483 unsigned int i;
484 unsigned int j;
485 u32 crc;
486 size_t calc_size = sizeof(struct qe_firmware);
487 size_t length;
488 const struct qe_header *hdr;
489
490 if (!firmware) {
491 printk(KERN_ERR "qe-firmware: invalid pointer\n");
492 return -EINVAL;
493 }
494
495 hdr = &firmware->header;
496 length = be32_to_cpu(hdr->length);
497
498 /* Check the magic */
499 if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
500 (hdr->magic[2] != 'F')) {
501 printk(KERN_ERR "qe-firmware: not a microcode\n");
502 return -EPERM;
503 }
504
505 /* Check the version */
506 if (hdr->version != 1) {
507 printk(KERN_ERR "qe-firmware: unsupported version\n");
508 return -EPERM;
509 }
510
511 /* Validate some of the fields */
Timur Tabi6f913162008-03-03 11:11:30 -0600512 if ((firmware->count < 1) || (firmware->count > MAX_QE_RISC)) {
Timur Tabibc556ba2008-01-08 10:30:58 -0600513 printk(KERN_ERR "qe-firmware: invalid data\n");
514 return -EINVAL;
515 }
516
517 /* Validate the length and check if there's a CRC */
518 calc_size += (firmware->count - 1) * sizeof(struct qe_microcode);
519
520 for (i = 0; i < firmware->count; i++)
521 /*
522 * For situations where the second RISC uses the same microcode
523 * as the first, the 'code_offset' and 'count' fields will be
524 * zero, so it's okay to add those.
525 */
526 calc_size += sizeof(__be32) *
527 be32_to_cpu(firmware->microcode[i].count);
528
529 /* Validate the length */
530 if (length != calc_size + sizeof(__be32)) {
531 printk(KERN_ERR "qe-firmware: invalid length\n");
532 return -EPERM;
533 }
534
535 /* Validate the CRC */
536 crc = be32_to_cpu(*(__be32 *)((void *)firmware + calc_size));
537 if (crc != crc32(0, firmware, calc_size)) {
538 printk(KERN_ERR "qe-firmware: firmware CRC is invalid\n");
539 return -EIO;
540 }
541
542 /*
543 * If the microcode calls for it, split the I-RAM.
544 */
545 if (!firmware->split)
546 setbits16(&qe_immr->cp.cercr, QE_CP_CERCR_CIR);
547
548 if (firmware->soc.model)
549 printk(KERN_INFO
550 "qe-firmware: firmware '%s' for %u V%u.%u\n",
551 firmware->id, be16_to_cpu(firmware->soc.model),
552 firmware->soc.major, firmware->soc.minor);
553 else
554 printk(KERN_INFO "qe-firmware: firmware '%s'\n",
555 firmware->id);
556
557 /*
558 * The QE only supports one microcode per RISC, so clear out all the
559 * saved microcode information and put in the new.
560 */
561 memset(&qe_firmware_info, 0, sizeof(qe_firmware_info));
562 strcpy(qe_firmware_info.id, firmware->id);
563 qe_firmware_info.extended_modes = firmware->extended_modes;
564 memcpy(qe_firmware_info.vtraps, firmware->vtraps,
565 sizeof(firmware->vtraps));
566
567 /* Loop through each microcode. */
568 for (i = 0; i < firmware->count; i++) {
569 const struct qe_microcode *ucode = &firmware->microcode[i];
570
571 /* Upload a microcode if it's present */
572 if (ucode->code_offset)
573 qe_upload_microcode(firmware, ucode);
574
575 /* Program the traps for this processor */
576 for (j = 0; j < 16; j++) {
577 u32 trap = be32_to_cpu(ucode->traps[j]);
578
579 if (trap)
580 out_be32(&qe_immr->rsp[i].tibcr[j], trap);
581 }
582
583 /* Enable traps */
584 out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
585 }
586
587 qe_firmware_uploaded = 1;
588
589 return 0;
590}
591EXPORT_SYMBOL(qe_upload_firmware);
592
593/*
594 * Get info on the currently-loaded firmware
595 *
596 * This function also checks the device tree to see if the boot loader has
597 * uploaded a firmware already.
598 */
599struct qe_firmware_info *qe_get_firmware_info(void)
600{
601 static int initialized;
602 struct property *prop;
603 struct device_node *qe;
604 struct device_node *fw = NULL;
605 const char *sprop;
606 unsigned int i;
607
608 /*
609 * If we haven't checked yet, and a driver hasn't uploaded a firmware
610 * yet, then check the device tree for information.
611 */
Ionut Nicu86f4e5d2008-03-07 19:27:59 +0200612 if (qe_firmware_uploaded)
613 return &qe_firmware_info;
614
615 if (initialized)
Timur Tabibc556ba2008-01-08 10:30:58 -0600616 return NULL;
617
618 initialized = 1;
619
620 /*
621 * Newer device trees have an "fsl,qe" compatible property for the QE
622 * node, but we still need to support older device trees.
623 */
624 qe = of_find_compatible_node(NULL, NULL, "fsl,qe");
625 if (!qe) {
626 qe = of_find_node_by_type(NULL, "qe");
627 if (!qe)
628 return NULL;
629 }
630
631 /* Find the 'firmware' child node */
632 for_each_child_of_node(qe, fw) {
633 if (strcmp(fw->name, "firmware") == 0)
634 break;
635 }
636
637 of_node_put(qe);
638
639 /* Did we find the 'firmware' node? */
640 if (!fw)
641 return NULL;
642
643 qe_firmware_uploaded = 1;
644
645 /* Copy the data into qe_firmware_info*/
646 sprop = of_get_property(fw, "id", NULL);
647 if (sprop)
648 strncpy(qe_firmware_info.id, sprop,
649 sizeof(qe_firmware_info.id) - 1);
650
651 prop = of_find_property(fw, "extended-modes", NULL);
652 if (prop && (prop->length == sizeof(u64))) {
653 const u64 *iprop = prop->value;
654
655 qe_firmware_info.extended_modes = *iprop;
656 }
657
658 prop = of_find_property(fw, "virtual-traps", NULL);
659 if (prop && (prop->length == 32)) {
660 const u32 *iprop = prop->value;
661
662 for (i = 0; i < ARRAY_SIZE(qe_firmware_info.vtraps); i++)
663 qe_firmware_info.vtraps[i] = iprop[i];
664 }
665
666 of_node_put(fw);
667
668 return &qe_firmware_info;
669}
670EXPORT_SYMBOL(qe_get_firmware_info);
671