blob: c2518cdb7ddb6e94822138e7c702d9242b444f86 [file] [log] [blame]
Li Yang98658532006-10-03 23:10:46 -05001/*
Yang Li8a56e1e2012-11-01 18:53:42 +00002 * Copyright (C) 2006-2010 Freescale Semiconductor, Inc. All rights reserved.
Li Yang98658532006-10-03 23:10:46 -05003 *
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>
Li Yang98658532006-10-03 23:10:46 -050025#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>
Anton Vorontsovfdfde242009-09-16 01:43:55 +040029#include <linux/mod_devicetable.h>
30#include <linux/of_platform.h>
Li Yang98658532006-10-03 23:10:46 -050031#include <asm/irq.h>
32#include <asm/page.h>
33#include <asm/pgtable.h>
34#include <asm/immap_qe.h>
35#include <asm/qe.h>
36#include <asm/prom.h>
37#include <asm/rheap.h>
38
39static void qe_snums_init(void);
Li Yang98658532006-10-03 23:10:46 -050040static int qe_sdma_init(void);
41
42static DEFINE_SPINLOCK(qe_lock);
Anton Vorontsov09a3fba2008-11-11 18:31:39 +030043DEFINE_SPINLOCK(cmxgcr_lock);
44EXPORT_SYMBOL(cmxgcr_lock);
Li Yang98658532006-10-03 23:10:46 -050045
46/* QE snum state */
47enum qe_snum_state {
48 QE_SNUM_STATE_USED,
49 QE_SNUM_STATE_FREE
50};
51
52/* QE snum */
53struct qe_snum {
54 u8 num;
55 enum qe_snum_state state;
56};
57
58/* We allocate this here because it is used almost exclusively for
59 * the communication processor devices.
60 */
Anton Vorontsov0b51b022008-03-11 20:24:13 +030061struct qe_immap __iomem *qe_immr;
Li Yang98658532006-10-03 23:10:46 -050062EXPORT_SYMBOL(qe_immr);
63
64static struct qe_snum snums[QE_NUM_OF_SNUM]; /* Dynamically allocated SNUMs */
Haiying Wang98ca77a2009-05-01 15:40:48 -040065static unsigned int qe_num_of_snum;
Li Yang98658532006-10-03 23:10:46 -050066
67static phys_addr_t qebase = -1;
68
69phys_addr_t get_qe_base(void)
70{
71 struct device_node *qe;
Andy Fleming7e1cc9c2008-05-07 13:19:44 -050072 int size;
Anton Vorontsovd8985fd2008-02-04 16:46:17 +030073 const u32 *prop;
Li Yang98658532006-10-03 23:10:46 -050074
75 if (qebase != -1)
76 return qebase;
77
Anton Vorontsova2dd70a2008-01-24 18:39:59 +030078 qe = of_find_compatible_node(NULL, NULL, "fsl,qe");
79 if (!qe) {
80 qe = of_find_node_by_type(NULL, "qe");
81 if (!qe)
82 return qebase;
83 }
84
85 prop = of_get_property(qe, "reg", &size);
Anton Vorontsovd8985fd2008-02-04 16:46:17 +030086 if (prop && size >= sizeof(*prop))
87 qebase = of_translate_address(qe, prop);
Anton Vorontsova2dd70a2008-01-24 18:39:59 +030088 of_node_put(qe);
Li Yang98658532006-10-03 23:10:46 -050089
90 return qebase;
91}
92
93EXPORT_SYMBOL(get_qe_base);
94
Anton Vorontsov0c7b87b2009-09-16 01:43:52 +040095void qe_reset(void)
Li Yang98658532006-10-03 23:10:46 -050096{
97 if (qe_immr == NULL)
98 qe_immr = ioremap(get_qe_base(), QE_IMMAP_SIZE);
99
100 qe_snums_init();
101
102 qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID,
103 QE_CR_PROTOCOL_UNSPECIFIED, 0);
104
105 /* Reclaim the MURAM memory for our use. */
106 qe_muram_init();
107
108 if (qe_sdma_init())
109 panic("sdma init failed!");
110}
111
112int qe_issue_cmd(u32 cmd, u32 device, u8 mcn_protocol, u32 cmd_input)
113{
114 unsigned long flags;
115 u8 mcn_shift = 0, dev_shift = 0;
Timur Tabif49156ea2009-05-26 10:21:42 -0500116 u32 ret;
Li Yang98658532006-10-03 23:10:46 -0500117
118 spin_lock_irqsave(&qe_lock, flags);
119 if (cmd == QE_RESET) {
120 out_be32(&qe_immr->cp.cecr, (u32) (cmd | QE_CR_FLG));
121 } else {
122 if (cmd == QE_ASSIGN_PAGE) {
123 /* Here device is the SNUM, not sub-block */
124 dev_shift = QE_CR_SNUM_SHIFT;
125 } else if (cmd == QE_ASSIGN_RISC) {
126 /* Here device is the SNUM, and mcnProtocol is
127 * e_QeCmdRiscAssignment value */
128 dev_shift = QE_CR_SNUM_SHIFT;
129 mcn_shift = QE_CR_MCN_RISC_ASSIGN_SHIFT;
130 } else {
131 if (device == QE_CR_SUBBLOCK_USB)
132 mcn_shift = QE_CR_MCN_USB_SHIFT;
133 else
134 mcn_shift = QE_CR_MCN_NORMAL_SHIFT;
135 }
136
Timur Tabi302439d2006-10-31 17:53:42 +0800137 out_be32(&qe_immr->cp.cecdr, cmd_input);
Li Yang98658532006-10-03 23:10:46 -0500138 out_be32(&qe_immr->cp.cecr,
139 (cmd | QE_CR_FLG | ((u32) device << dev_shift) | (u32)
140 mcn_protocol << mcn_shift));
141 }
142
143 /* wait for the QE_CR_FLG to clear */
Timur Tabif49156ea2009-05-26 10:21:42 -0500144 ret = spin_event_timeout((in_be32(&qe_immr->cp.cecr) & QE_CR_FLG) == 0,
145 100, 0);
146 /* On timeout (e.g. failure), the expression will be false (ret == 0),
147 otherwise it will be true (ret == 1). */
Li Yang98658532006-10-03 23:10:46 -0500148 spin_unlock_irqrestore(&qe_lock, flags);
149
Timur Tabif49156ea2009-05-26 10:21:42 -0500150 return ret == 1;
Li Yang98658532006-10-03 23:10:46 -0500151}
152EXPORT_SYMBOL(qe_issue_cmd);
153
154/* Set a baud rate generator. This needs lots of work. There are
155 * 16 BRGs, which can be connected to the QE channels or output
156 * as clocks. The BRGs are in two different block of internal
157 * memory mapped space.
Timur Tabi6b0b5942007-10-03 11:34:59 -0500158 * The BRG clock is the QE clock divided by 2.
Li Yang98658532006-10-03 23:10:46 -0500159 * It was set up long ago during the initial boot phase and is
160 * is given to us.
161 * Baud rate clocks are zero-based in the driver code (as that maps
162 * to port numbers). Documentation uses 1-based numbering.
163 */
164static unsigned int brg_clk = 0;
165
Anton Vorontsov7f0a6fc2008-03-11 20:24:24 +0300166unsigned int qe_get_brg_clk(void)
Li Yang98658532006-10-03 23:10:46 -0500167{
168 struct device_node *qe;
Andy Fleming7e1cc9c2008-05-07 13:19:44 -0500169 int size;
Anton Vorontsova2dd70a2008-01-24 18:39:59 +0300170 const u32 *prop;
171
Li Yang98658532006-10-03 23:10:46 -0500172 if (brg_clk)
173 return brg_clk;
174
Anton Vorontsova2dd70a2008-01-24 18:39:59 +0300175 qe = of_find_compatible_node(NULL, NULL, "fsl,qe");
176 if (!qe) {
177 qe = of_find_node_by_type(NULL, "qe");
178 if (!qe)
179 return brg_clk;
180 }
181
182 prop = of_get_property(qe, "brg-frequency", &size);
Anton Vorontsovd8985fd2008-02-04 16:46:17 +0300183 if (prop && size == sizeof(*prop))
184 brg_clk = *prop;
Anton Vorontsova2dd70a2008-01-24 18:39:59 +0300185
Anton Vorontsova2dd70a2008-01-24 18:39:59 +0300186 of_node_put(qe);
187
Li Yang98658532006-10-03 23:10:46 -0500188 return brg_clk;
189}
Anton Vorontsov7f0a6fc2008-03-11 20:24:24 +0300190EXPORT_SYMBOL(qe_get_brg_clk);
Li Yang98658532006-10-03 23:10:46 -0500191
Timur Tabi6b0b5942007-10-03 11:34:59 -0500192/* Program the BRG to the given sampling rate and multiplier
193 *
Timur Tabi7264ec42007-11-29 17:26:30 -0600194 * @brg: the BRG, QE_BRG1 - QE_BRG16
Timur Tabi6b0b5942007-10-03 11:34:59 -0500195 * @rate: the desired sampling rate
196 * @multiplier: corresponds to the value programmed in GUMR_L[RDCR] or
197 * GUMR_L[TDCR]. E.g., if this BRG is the RX clock, and GUMR_L[RDCR]=01,
198 * then 'multiplier' should be 8.
Li Yang98658532006-10-03 23:10:46 -0500199 */
Timur Tabi7264ec42007-11-29 17:26:30 -0600200int qe_setbrg(enum qe_clock brg, unsigned int rate, unsigned int multiplier)
Li Yang98658532006-10-03 23:10:46 -0500201{
Li Yang98658532006-10-03 23:10:46 -0500202 u32 divisor, tempval;
Timur Tabi6b0b5942007-10-03 11:34:59 -0500203 u32 div16 = 0;
Li Yang98658532006-10-03 23:10:46 -0500204
Timur Tabi7264ec42007-11-29 17:26:30 -0600205 if ((brg < QE_BRG1) || (brg > QE_BRG16))
206 return -EINVAL;
207
Anton Vorontsov7f0a6fc2008-03-11 20:24:24 +0300208 divisor = qe_get_brg_clk() / (rate * multiplier);
Li Yang98658532006-10-03 23:10:46 -0500209
Li Yang98658532006-10-03 23:10:46 -0500210 if (divisor > QE_BRGC_DIVISOR_MAX + 1) {
Timur Tabi6b0b5942007-10-03 11:34:59 -0500211 div16 = QE_BRGC_DIV16;
Li Yang98658532006-10-03 23:10:46 -0500212 divisor /= 16;
213 }
214
Timur Tabi6b0b5942007-10-03 11:34:59 -0500215 /* Errata QE_General4, which affects some MPC832x and MPC836x SOCs, says
216 that the BRG divisor must be even if you're not using divide-by-16
217 mode. */
Joakim Tjernlundae5f8c12011-08-23 14:30:05 +0200218 if (!div16 && (divisor & 1) && (divisor > 3))
Timur Tabi6b0b5942007-10-03 11:34:59 -0500219 divisor++;
Li Yang98658532006-10-03 23:10:46 -0500220
Timur Tabi6b0b5942007-10-03 11:34:59 -0500221 tempval = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) |
222 QE_BRGC_ENABLE | div16;
223
Timur Tabi7264ec42007-11-29 17:26:30 -0600224 out_be32(&qe_immr->brg.brgc[brg - QE_BRG1], tempval);
225
226 return 0;
Li Yang98658532006-10-03 23:10:46 -0500227}
Timur Tabi7264ec42007-11-29 17:26:30 -0600228EXPORT_SYMBOL(qe_setbrg);
Li Yang98658532006-10-03 23:10:46 -0500229
Timur Tabi174b0da2007-12-03 15:17:58 -0600230/* Convert a string to a QE clock source enum
231 *
232 * This function takes a string, typically from a property in the device
233 * tree, and returns the corresponding "enum qe_clock" value.
234*/
235enum qe_clock qe_clock_source(const char *source)
236{
237 unsigned int i;
238
239 if (strcasecmp(source, "none") == 0)
240 return QE_CLK_NONE;
241
242 if (strncasecmp(source, "brg", 3) == 0) {
243 i = simple_strtoul(source + 3, NULL, 10);
244 if ((i >= 1) && (i <= 16))
245 return (QE_BRG1 - 1) + i;
246 else
247 return QE_CLK_DUMMY;
248 }
249
250 if (strncasecmp(source, "clk", 3) == 0) {
251 i = simple_strtoul(source + 3, NULL, 10);
252 if ((i >= 1) && (i <= 24))
253 return (QE_CLK1 - 1) + i;
254 else
255 return QE_CLK_DUMMY;
256 }
257
258 return QE_CLK_DUMMY;
259}
260EXPORT_SYMBOL(qe_clock_source);
261
Li Yang98658532006-10-03 23:10:46 -0500262/* Initialize SNUMs (thread serial numbers) according to
263 * QE Module Control chapter, SNUM table
264 */
265static void qe_snums_init(void)
266{
267 int i;
Dave Liufa1b42b2010-01-12 00:04:03 +0000268 static const u8 snum_init_76[] = {
269 0x04, 0x05, 0x0C, 0x0D, 0x14, 0x15, 0x1C, 0x1D,
270 0x24, 0x25, 0x2C, 0x2D, 0x34, 0x35, 0x88, 0x89,
271 0x98, 0x99, 0xA8, 0xA9, 0xB8, 0xB9, 0xC8, 0xC9,
272 0xD8, 0xD9, 0xE8, 0xE9, 0x44, 0x45, 0x4C, 0x4D,
273 0x54, 0x55, 0x5C, 0x5D, 0x64, 0x65, 0x6C, 0x6D,
274 0x74, 0x75, 0x7C, 0x7D, 0x84, 0x85, 0x8C, 0x8D,
275 0x94, 0x95, 0x9C, 0x9D, 0xA4, 0xA5, 0xAC, 0xAD,
276 0xB4, 0xB5, 0xBC, 0xBD, 0xC4, 0xC5, 0xCC, 0xCD,
277 0xD4, 0xD5, 0xDC, 0xDD, 0xE4, 0xE5, 0xEC, 0xED,
278 0xF4, 0xF5, 0xFC, 0xFD,
279 };
280 static const u8 snum_init_46[] = {
Li Yang98658532006-10-03 23:10:46 -0500281 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 };
Dave Liufa1b42b2010-01-12 00:04:03 +0000288 static const u8 *snum_init;
Li Yang98658532006-10-03 23:10:46 -0500289
Haiying Wang98ca77a2009-05-01 15:40:48 -0400290 qe_num_of_snum = qe_get_num_of_snums();
291
Dave Liufa1b42b2010-01-12 00:04:03 +0000292 if (qe_num_of_snum == 76)
293 snum_init = snum_init_76;
294 else
295 snum_init = snum_init_46;
296
Haiying Wang98ca77a2009-05-01 15:40:48 -0400297 for (i = 0; i < qe_num_of_snum; i++) {
Li Yang98658532006-10-03 23:10:46 -0500298 snums[i].num = snum_init[i];
299 snums[i].state = QE_SNUM_STATE_FREE;
300 }
301}
302
303int qe_get_snum(void)
304{
305 unsigned long flags;
306 int snum = -EBUSY;
307 int i;
308
309 spin_lock_irqsave(&qe_lock, flags);
Haiying Wang98ca77a2009-05-01 15:40:48 -0400310 for (i = 0; i < qe_num_of_snum; i++) {
Li Yang98658532006-10-03 23:10:46 -0500311 if (snums[i].state == QE_SNUM_STATE_FREE) {
312 snums[i].state = QE_SNUM_STATE_USED;
313 snum = snums[i].num;
314 break;
315 }
316 }
317 spin_unlock_irqrestore(&qe_lock, flags);
318
319 return snum;
320}
321EXPORT_SYMBOL(qe_get_snum);
322
323void qe_put_snum(u8 snum)
324{
325 int i;
326
Haiying Wang98ca77a2009-05-01 15:40:48 -0400327 for (i = 0; i < qe_num_of_snum; i++) {
Li Yang98658532006-10-03 23:10:46 -0500328 if (snums[i].num == snum) {
329 snums[i].state = QE_SNUM_STATE_FREE;
330 break;
331 }
332 }
333}
334EXPORT_SYMBOL(qe_put_snum);
335
336static int qe_sdma_init(void)
337{
Andy Fleming7e1cc9c2008-05-07 13:19:44 -0500338 struct sdma __iomem *sdma = &qe_immr->sdma;
Anton Vorontsov0c7b87b2009-09-16 01:43:52 +0400339 static unsigned long sdma_buf_offset = (unsigned long)-ENOMEM;
Li Yang98658532006-10-03 23:10:46 -0500340
341 if (!sdma)
342 return -ENODEV;
343
344 /* allocate 2 internal temporary buffers (512 bytes size each) for
345 * the SDMA */
Anton Vorontsov0c7b87b2009-09-16 01:43:52 +0400346 if (IS_ERR_VALUE(sdma_buf_offset)) {
347 sdma_buf_offset = qe_muram_alloc(512 * 2, 4096);
348 if (IS_ERR_VALUE(sdma_buf_offset))
349 return -ENOMEM;
350 }
Li Yang98658532006-10-03 23:10:46 -0500351
Timur Tabi4c356302007-05-08 14:46:36 -0500352 out_be32(&sdma->sdebcr, (u32) sdma_buf_offset & QE_SDEBCR_BA_MASK);
Chuck Meade7f013bc2007-03-27 10:46:10 -0400353 out_be32(&sdma->sdmr, (QE_SDMR_GLB_1_MSK |
354 (0x1 << QE_SDMR_CEN_SHIFT)));
Li Yang98658532006-10-03 23:10:46 -0500355
356 return 0;
357}
358
Timur Tabibc556ba2008-01-08 10:30:58 -0600359/* The maximum number of RISCs we support */
Anton Vorontsov98eaa092009-08-27 21:30:11 +0400360#define MAX_QE_RISC 4
Timur Tabibc556ba2008-01-08 10:30:58 -0600361
362/* Firmware information stored here for qe_get_firmware_info() */
363static struct qe_firmware_info qe_firmware_info;
364
365/*
366 * Set to 1 if QE firmware has been uploaded, and therefore
367 * qe_firmware_info contains valid data.
368 */
369static int qe_firmware_uploaded;
370
371/*
372 * Upload a QE microcode
373 *
374 * This function is a worker function for qe_upload_firmware(). It does
375 * the actual uploading of the microcode.
376 */
377static void qe_upload_microcode(const void *base,
378 const struct qe_microcode *ucode)
379{
380 const __be32 *code = base + be32_to_cpu(ucode->code_offset);
381 unsigned int i;
382
383 if (ucode->major || ucode->minor || ucode->revision)
384 printk(KERN_INFO "qe-firmware: "
385 "uploading microcode '%s' version %u.%u.%u\n",
386 ucode->id, ucode->major, ucode->minor, ucode->revision);
387 else
388 printk(KERN_INFO "qe-firmware: "
389 "uploading microcode '%s'\n", ucode->id);
390
391 /* Use auto-increment */
392 out_be32(&qe_immr->iram.iadd, be32_to_cpu(ucode->iram_offset) |
393 QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR);
394
395 for (i = 0; i < be32_to_cpu(ucode->count); i++)
396 out_be32(&qe_immr->iram.idata, be32_to_cpu(code[i]));
Kokoris, Ioannise65650e2011-11-11 17:05:11 +0100397
398 /* Set I-RAM Ready Register */
399 out_be32(&qe_immr->iram.iready, be32_to_cpu(QE_IRAM_READY));
Timur Tabibc556ba2008-01-08 10:30:58 -0600400}
401
402/*
403 * Upload a microcode to the I-RAM at a specific address.
404 *
Paul Bolle395cf962011-08-15 02:02:26 +0200405 * See Documentation/powerpc/qe_firmware.txt for information on QE microcode
Timur Tabibc556ba2008-01-08 10:30:58 -0600406 * uploading.
407 *
408 * Currently, only version 1 is supported, so the 'version' field must be
409 * set to 1.
410 *
411 * The SOC model and revision are not validated, they are only displayed for
412 * informational purposes.
413 *
414 * 'calc_size' is the calculated size, in bytes, of the firmware structure and
415 * all of the microcode structures, minus the CRC.
416 *
417 * 'length' is the size that the structure says it is, including the CRC.
418 */
419int qe_upload_firmware(const struct qe_firmware *firmware)
420{
421 unsigned int i;
422 unsigned int j;
423 u32 crc;
424 size_t calc_size = sizeof(struct qe_firmware);
425 size_t length;
426 const struct qe_header *hdr;
427
428 if (!firmware) {
429 printk(KERN_ERR "qe-firmware: invalid pointer\n");
430 return -EINVAL;
431 }
432
433 hdr = &firmware->header;
434 length = be32_to_cpu(hdr->length);
435
436 /* Check the magic */
437 if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
438 (hdr->magic[2] != 'F')) {
439 printk(KERN_ERR "qe-firmware: not a microcode\n");
440 return -EPERM;
441 }
442
443 /* Check the version */
444 if (hdr->version != 1) {
445 printk(KERN_ERR "qe-firmware: unsupported version\n");
446 return -EPERM;
447 }
448
449 /* Validate some of the fields */
Timur Tabi6f913162008-03-03 11:11:30 -0600450 if ((firmware->count < 1) || (firmware->count > MAX_QE_RISC)) {
Timur Tabibc556ba2008-01-08 10:30:58 -0600451 printk(KERN_ERR "qe-firmware: invalid data\n");
452 return -EINVAL;
453 }
454
455 /* Validate the length and check if there's a CRC */
456 calc_size += (firmware->count - 1) * sizeof(struct qe_microcode);
457
458 for (i = 0; i < firmware->count; i++)
459 /*
460 * For situations where the second RISC uses the same microcode
461 * as the first, the 'code_offset' and 'count' fields will be
462 * zero, so it's okay to add those.
463 */
464 calc_size += sizeof(__be32) *
465 be32_to_cpu(firmware->microcode[i].count);
466
467 /* Validate the length */
468 if (length != calc_size + sizeof(__be32)) {
469 printk(KERN_ERR "qe-firmware: invalid length\n");
470 return -EPERM;
471 }
472
473 /* Validate the CRC */
474 crc = be32_to_cpu(*(__be32 *)((void *)firmware + calc_size));
475 if (crc != crc32(0, firmware, calc_size)) {
476 printk(KERN_ERR "qe-firmware: firmware CRC is invalid\n");
477 return -EIO;
478 }
479
480 /*
481 * If the microcode calls for it, split the I-RAM.
482 */
483 if (!firmware->split)
484 setbits16(&qe_immr->cp.cercr, QE_CP_CERCR_CIR);
485
486 if (firmware->soc.model)
487 printk(KERN_INFO
488 "qe-firmware: firmware '%s' for %u V%u.%u\n",
489 firmware->id, be16_to_cpu(firmware->soc.model),
490 firmware->soc.major, firmware->soc.minor);
491 else
492 printk(KERN_INFO "qe-firmware: firmware '%s'\n",
493 firmware->id);
494
495 /*
496 * The QE only supports one microcode per RISC, so clear out all the
497 * saved microcode information and put in the new.
498 */
499 memset(&qe_firmware_info, 0, sizeof(qe_firmware_info));
Rickard Strandqvist5db43122014-07-26 23:26:51 +0200500 strlcpy(qe_firmware_info.id, firmware->id, sizeof(qe_firmware_info.id));
Timur Tabibc556ba2008-01-08 10:30:58 -0600501 qe_firmware_info.extended_modes = firmware->extended_modes;
502 memcpy(qe_firmware_info.vtraps, firmware->vtraps,
503 sizeof(firmware->vtraps));
504
505 /* Loop through each microcode. */
506 for (i = 0; i < firmware->count; i++) {
507 const struct qe_microcode *ucode = &firmware->microcode[i];
508
509 /* Upload a microcode if it's present */
510 if (ucode->code_offset)
511 qe_upload_microcode(firmware, ucode);
512
513 /* Program the traps for this processor */
514 for (j = 0; j < 16; j++) {
515 u32 trap = be32_to_cpu(ucode->traps[j]);
516
517 if (trap)
518 out_be32(&qe_immr->rsp[i].tibcr[j], trap);
519 }
520
521 /* Enable traps */
522 out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
523 }
524
525 qe_firmware_uploaded = 1;
526
527 return 0;
528}
529EXPORT_SYMBOL(qe_upload_firmware);
530
531/*
532 * Get info on the currently-loaded firmware
533 *
534 * This function also checks the device tree to see if the boot loader has
535 * uploaded a firmware already.
536 */
537struct qe_firmware_info *qe_get_firmware_info(void)
538{
539 static int initialized;
540 struct property *prop;
541 struct device_node *qe;
542 struct device_node *fw = NULL;
543 const char *sprop;
544 unsigned int i;
545
546 /*
547 * If we haven't checked yet, and a driver hasn't uploaded a firmware
548 * yet, then check the device tree for information.
549 */
Ionut Nicu86f4e5d2008-03-07 19:27:59 +0200550 if (qe_firmware_uploaded)
551 return &qe_firmware_info;
552
553 if (initialized)
Timur Tabibc556ba2008-01-08 10:30:58 -0600554 return NULL;
555
556 initialized = 1;
557
558 /*
559 * Newer device trees have an "fsl,qe" compatible property for the QE
560 * node, but we still need to support older device trees.
561 */
562 qe = of_find_compatible_node(NULL, NULL, "fsl,qe");
563 if (!qe) {
564 qe = of_find_node_by_type(NULL, "qe");
565 if (!qe)
566 return NULL;
567 }
568
569 /* Find the 'firmware' child node */
570 for_each_child_of_node(qe, fw) {
571 if (strcmp(fw->name, "firmware") == 0)
572 break;
573 }
574
575 of_node_put(qe);
576
577 /* Did we find the 'firmware' node? */
578 if (!fw)
579 return NULL;
580
581 qe_firmware_uploaded = 1;
582
583 /* Copy the data into qe_firmware_info*/
584 sprop = of_get_property(fw, "id", NULL);
585 if (sprop)
Rickard Strandqvist5db43122014-07-26 23:26:51 +0200586 strlcpy(qe_firmware_info.id, sprop,
587 sizeof(qe_firmware_info.id));
Timur Tabibc556ba2008-01-08 10:30:58 -0600588
589 prop = of_find_property(fw, "extended-modes", NULL);
590 if (prop && (prop->length == sizeof(u64))) {
591 const u64 *iprop = prop->value;
592
593 qe_firmware_info.extended_modes = *iprop;
594 }
595
596 prop = of_find_property(fw, "virtual-traps", NULL);
597 if (prop && (prop->length == 32)) {
598 const u32 *iprop = prop->value;
599
600 for (i = 0; i < ARRAY_SIZE(qe_firmware_info.vtraps); i++)
601 qe_firmware_info.vtraps[i] = iprop[i];
602 }
603
604 of_node_put(fw);
605
606 return &qe_firmware_info;
607}
608EXPORT_SYMBOL(qe_get_firmware_info);
609
Haiying Wang06c44352009-05-01 15:40:47 -0400610unsigned int qe_get_num_of_risc(void)
611{
612 struct device_node *qe;
613 int size;
614 unsigned int num_of_risc = 0;
615 const u32 *prop;
616
617 qe = of_find_compatible_node(NULL, NULL, "fsl,qe");
618 if (!qe) {
619 /* Older devices trees did not have an "fsl,qe"
620 * compatible property, so we need to look for
621 * the QE node by name.
622 */
623 qe = of_find_node_by_type(NULL, "qe");
624 if (!qe)
625 return num_of_risc;
626 }
627
628 prop = of_get_property(qe, "fsl,qe-num-riscs", &size);
629 if (prop && size == sizeof(*prop))
630 num_of_risc = *prop;
631
632 of_node_put(qe);
633
634 return num_of_risc;
635}
636EXPORT_SYMBOL(qe_get_num_of_risc);
637
Haiying Wang98ca77a2009-05-01 15:40:48 -0400638unsigned int qe_get_num_of_snums(void)
639{
640 struct device_node *qe;
641 int size;
642 unsigned int num_of_snums;
643 const u32 *prop;
644
645 num_of_snums = 28; /* The default number of snum for threads is 28 */
646 qe = of_find_compatible_node(NULL, NULL, "fsl,qe");
647 if (!qe) {
648 /* Older devices trees did not have an "fsl,qe"
649 * compatible property, so we need to look for
650 * the QE node by name.
651 */
652 qe = of_find_node_by_type(NULL, "qe");
653 if (!qe)
654 return num_of_snums;
655 }
656
657 prop = of_get_property(qe, "fsl,qe-num-snums", &size);
658 if (prop && size == sizeof(*prop)) {
659 num_of_snums = *prop;
660 if ((num_of_snums < 28) || (num_of_snums > QE_NUM_OF_SNUM)) {
661 /* No QE ever has fewer than 28 SNUMs */
662 pr_err("QE: number of snum is invalid\n");
Julia Lawall5aac4d72010-08-29 11:52:44 +0200663 of_node_put(qe);
Haiying Wang98ca77a2009-05-01 15:40:48 -0400664 return -EINVAL;
665 }
666 }
667
668 of_node_put(qe);
669
670 return num_of_snums;
671}
672EXPORT_SYMBOL(qe_get_num_of_snums);
Anton Vorontsovfdfde242009-09-16 01:43:55 +0400673
674#if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC_85xx)
Grant Likelya454dc52010-07-22 15:52:34 -0600675static int qe_resume(struct platform_device *ofdev)
Anton Vorontsovfdfde242009-09-16 01:43:55 +0400676{
677 if (!qe_alive_during_sleep())
678 qe_reset();
679 return 0;
680}
681
Grant Likely00006122011-02-22 19:59:54 -0700682static int qe_probe(struct platform_device *ofdev)
Anton Vorontsovfdfde242009-09-16 01:43:55 +0400683{
684 return 0;
685}
686
687static const struct of_device_id qe_ids[] = {
688 { .compatible = "fsl,qe", },
689 { },
690};
691
Grant Likely00006122011-02-22 19:59:54 -0700692static struct platform_driver qe_driver = {
Grant Likely40182942010-04-13 16:13:02 -0700693 .driver = {
694 .name = "fsl-qe",
Grant Likely40182942010-04-13 16:13:02 -0700695 .of_match_table = qe_ids,
696 },
Anton Vorontsovfdfde242009-09-16 01:43:55 +0400697 .probe = qe_probe,
698 .resume = qe_resume,
699};
700
701static int __init qe_drv_init(void)
702{
Grant Likely00006122011-02-22 19:59:54 -0700703 return platform_driver_register(&qe_driver);
Anton Vorontsovfdfde242009-09-16 01:43:55 +0400704}
705device_initcall(qe_drv_init);
706#endif /* defined(CONFIG_SUSPEND) && defined(CONFIG_PPC_85xx) */