blob: 62c6ba17991ad614d787d0ff57d9f39f53341982 [file] [log] [blame]
Thomas Gleixner2874c5f2019-05-27 08:55:01 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Li Yang98658532006-10-03 23:10:46 -05002/*
Yang Li8a56e1e2012-11-01 18:53:42 +00003 * Copyright (C) 2006-2010 Freescale Semiconductor, Inc. All rights reserved.
Li Yang98658532006-10-03 23:10:46 -05004 *
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).
Li Yang98658532006-10-03 23:10:46 -050012 */
13#include <linux/errno.h>
14#include <linux/sched.h>
15#include <linux/kernel.h>
16#include <linux/param.h>
17#include <linux/string.h>
Anton Vorontsov09a3fba2008-11-11 18:31:39 +030018#include <linux/spinlock.h>
Li Yang98658532006-10-03 23:10:46 -050019#include <linux/mm.h>
20#include <linux/interrupt.h>
Li Yang98658532006-10-03 23:10:46 -050021#include <linux/module.h>
22#include <linux/delay.h>
23#include <linux/ioport.h>
Timur Tabibc556ba2008-01-08 10:30:58 -060024#include <linux/crc32.h>
Anton Vorontsovfdfde242009-09-16 01:43:55 +040025#include <linux/mod_devicetable.h>
26#include <linux/of_platform.h>
Li Yang98658532006-10-03 23:10:46 -050027#include <asm/irq.h>
28#include <asm/page.h>
29#include <asm/pgtable.h>
Zhao Qiang7aa1aa62015-11-30 10:48:57 +080030#include <soc/fsl/qe/immap_qe.h>
31#include <soc/fsl/qe/qe.h>
Li Yang98658532006-10-03 23:10:46 -050032#include <asm/prom.h>
33#include <asm/rheap.h>
34
35static void qe_snums_init(void);
Li Yang98658532006-10-03 23:10:46 -050036static int qe_sdma_init(void);
37
38static DEFINE_SPINLOCK(qe_lock);
Anton Vorontsov09a3fba2008-11-11 18:31:39 +030039DEFINE_SPINLOCK(cmxgcr_lock);
40EXPORT_SYMBOL(cmxgcr_lock);
Li Yang98658532006-10-03 23:10:46 -050041
42/* QE snum state */
43enum qe_snum_state {
44 QE_SNUM_STATE_USED,
45 QE_SNUM_STATE_FREE
46};
47
48/* QE snum */
49struct qe_snum {
50 u8 num;
51 enum qe_snum_state state;
52};
53
54/* We allocate this here because it is used almost exclusively for
55 * the communication processor devices.
56 */
Anton Vorontsov0b51b022008-03-11 20:24:13 +030057struct qe_immap __iomem *qe_immr;
Li Yang98658532006-10-03 23:10:46 -050058EXPORT_SYMBOL(qe_immr);
59
60static struct qe_snum snums[QE_NUM_OF_SNUM]; /* Dynamically allocated SNUMs */
Haiying Wang98ca77a2009-05-01 15:40:48 -040061static unsigned int qe_num_of_snum;
Li Yang98658532006-10-03 23:10:46 -050062
63static phys_addr_t qebase = -1;
64
Christophe Leroyb54ea822017-02-07 10:05:11 +010065static phys_addr_t get_qe_base(void)
Li Yang98658532006-10-03 23:10:46 -050066{
67 struct device_node *qe;
Zhao Qiang50669432016-09-23 10:20:31 +080068 int ret;
69 struct resource res;
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
Zhao Qiang50669432016-09-23 10:20:31 +080081 ret = of_address_to_resource(qe, 0, &res);
82 if (!ret)
83 qebase = res.start;
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
Anton Vorontsov0c7b87b2009-09-16 01:43:52 +040089void qe_reset(void)
Li Yang98658532006-10-03 23:10:46 -050090{
91 if (qe_immr == NULL)
92 qe_immr = ioremap(get_qe_base(), QE_IMMAP_SIZE);
93
94 qe_snums_init();
95
96 qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID,
97 QE_CR_PROTOCOL_UNSPECIFIED, 0);
98
99 /* Reclaim the MURAM memory for our use. */
100 qe_muram_init();
101
102 if (qe_sdma_init())
103 panic("sdma init failed!");
104}
105
106int qe_issue_cmd(u32 cmd, u32 device, u8 mcn_protocol, u32 cmd_input)
107{
108 unsigned long flags;
109 u8 mcn_shift = 0, dev_shift = 0;
Timur Tabif49156ea2009-05-26 10:21:42 -0500110 u32 ret;
Li Yang98658532006-10-03 23:10:46 -0500111
112 spin_lock_irqsave(&qe_lock, flags);
113 if (cmd == QE_RESET) {
114 out_be32(&qe_immr->cp.cecr, (u32) (cmd | QE_CR_FLG));
115 } else {
116 if (cmd == QE_ASSIGN_PAGE) {
117 /* Here device is the SNUM, not sub-block */
118 dev_shift = QE_CR_SNUM_SHIFT;
119 } else if (cmd == QE_ASSIGN_RISC) {
120 /* Here device is the SNUM, and mcnProtocol is
121 * e_QeCmdRiscAssignment value */
122 dev_shift = QE_CR_SNUM_SHIFT;
123 mcn_shift = QE_CR_MCN_RISC_ASSIGN_SHIFT;
124 } else {
125 if (device == QE_CR_SUBBLOCK_USB)
126 mcn_shift = QE_CR_MCN_USB_SHIFT;
127 else
128 mcn_shift = QE_CR_MCN_NORMAL_SHIFT;
129 }
130
Timur Tabi302439d2006-10-31 17:53:42 +0800131 out_be32(&qe_immr->cp.cecdr, cmd_input);
Li Yang98658532006-10-03 23:10:46 -0500132 out_be32(&qe_immr->cp.cecr,
133 (cmd | QE_CR_FLG | ((u32) device << dev_shift) | (u32)
134 mcn_protocol << mcn_shift));
135 }
136
137 /* wait for the QE_CR_FLG to clear */
Timur Tabif49156ea2009-05-26 10:21:42 -0500138 ret = spin_event_timeout((in_be32(&qe_immr->cp.cecr) & QE_CR_FLG) == 0,
139 100, 0);
140 /* On timeout (e.g. failure), the expression will be false (ret == 0),
141 otherwise it will be true (ret == 1). */
Li Yang98658532006-10-03 23:10:46 -0500142 spin_unlock_irqrestore(&qe_lock, flags);
143
Timur Tabif49156ea2009-05-26 10:21:42 -0500144 return ret == 1;
Li Yang98658532006-10-03 23:10:46 -0500145}
146EXPORT_SYMBOL(qe_issue_cmd);
147
148/* Set a baud rate generator. This needs lots of work. There are
149 * 16 BRGs, which can be connected to the QE channels or output
150 * as clocks. The BRGs are in two different block of internal
151 * memory mapped space.
Timur Tabi6b0b5942007-10-03 11:34:59 -0500152 * The BRG clock is the QE clock divided by 2.
Li Yang98658532006-10-03 23:10:46 -0500153 * It was set up long ago during the initial boot phase and is
154 * is given to us.
155 * Baud rate clocks are zero-based in the driver code (as that maps
156 * to port numbers). Documentation uses 1-based numbering.
157 */
158static unsigned int brg_clk = 0;
159
Valentin Longchamp2ccf80b2017-02-17 11:29:45 +0100160#define CLK_GRAN (1000)
161#define CLK_GRAN_LIMIT (5)
162
Anton Vorontsov7f0a6fc2008-03-11 20:24:24 +0300163unsigned int qe_get_brg_clk(void)
Li Yang98658532006-10-03 23:10:46 -0500164{
165 struct device_node *qe;
Andy Fleming7e1cc9c2008-05-07 13:19:44 -0500166 int size;
Anton Vorontsova2dd70a2008-01-24 18:39:59 +0300167 const u32 *prop;
Valentin Longchamp2ccf80b2017-02-17 11:29:45 +0100168 unsigned int mod;
Anton Vorontsova2dd70a2008-01-24 18:39:59 +0300169
Li Yang98658532006-10-03 23:10:46 -0500170 if (brg_clk)
171 return brg_clk;
172
Anton Vorontsova2dd70a2008-01-24 18:39:59 +0300173 qe = of_find_compatible_node(NULL, NULL, "fsl,qe");
174 if (!qe) {
175 qe = of_find_node_by_type(NULL, "qe");
176 if (!qe)
177 return brg_clk;
178 }
179
180 prop = of_get_property(qe, "brg-frequency", &size);
Anton Vorontsovd8985fd2008-02-04 16:46:17 +0300181 if (prop && size == sizeof(*prop))
182 brg_clk = *prop;
Anton Vorontsova2dd70a2008-01-24 18:39:59 +0300183
Anton Vorontsova2dd70a2008-01-24 18:39:59 +0300184 of_node_put(qe);
185
Valentin Longchamp2ccf80b2017-02-17 11:29:45 +0100186 /* round this if near to a multiple of CLK_GRAN */
187 mod = brg_clk % CLK_GRAN;
188 if (mod) {
189 if (mod < CLK_GRAN_LIMIT)
190 brg_clk -= mod;
191 else if (mod > (CLK_GRAN - CLK_GRAN_LIMIT))
192 brg_clk += CLK_GRAN - mod;
193 }
194
Li Yang98658532006-10-03 23:10:46 -0500195 return brg_clk;
196}
Anton Vorontsov7f0a6fc2008-03-11 20:24:24 +0300197EXPORT_SYMBOL(qe_get_brg_clk);
Li Yang98658532006-10-03 23:10:46 -0500198
Valentin Longchampe5c5c8d2017-02-17 11:29:46 +0100199#define PVR_VER_836x 0x8083
200#define PVR_VER_832x 0x8084
201
Timur Tabi6b0b5942007-10-03 11:34:59 -0500202/* Program the BRG to the given sampling rate and multiplier
203 *
Timur Tabi7264ec42007-11-29 17:26:30 -0600204 * @brg: the BRG, QE_BRG1 - QE_BRG16
Timur Tabi6b0b5942007-10-03 11:34:59 -0500205 * @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.
Li Yang98658532006-10-03 23:10:46 -0500209 */
Timur Tabi7264ec42007-11-29 17:26:30 -0600210int qe_setbrg(enum qe_clock brg, unsigned int rate, unsigned int multiplier)
Li Yang98658532006-10-03 23:10:46 -0500211{
Li Yang98658532006-10-03 23:10:46 -0500212 u32 divisor, tempval;
Timur Tabi6b0b5942007-10-03 11:34:59 -0500213 u32 div16 = 0;
Li Yang98658532006-10-03 23:10:46 -0500214
Timur Tabi7264ec42007-11-29 17:26:30 -0600215 if ((brg < QE_BRG1) || (brg > QE_BRG16))
216 return -EINVAL;
217
Anton Vorontsov7f0a6fc2008-03-11 20:24:24 +0300218 divisor = qe_get_brg_clk() / (rate * multiplier);
Li Yang98658532006-10-03 23:10:46 -0500219
Li Yang98658532006-10-03 23:10:46 -0500220 if (divisor > QE_BRGC_DIVISOR_MAX + 1) {
Timur Tabi6b0b5942007-10-03 11:34:59 -0500221 div16 = QE_BRGC_DIV16;
Li Yang98658532006-10-03 23:10:46 -0500222 divisor /= 16;
223 }
224
Timur Tabi6b0b5942007-10-03 11:34:59 -0500225 /* 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. */
Valentin Longchampe5c5c8d2017-02-17 11:29:46 +0100228 if (pvr_version_is(PVR_VER_836x) || pvr_version_is(PVR_VER_832x))
229 if (!div16 && (divisor & 1) && (divisor > 3))
230 divisor++;
Li Yang98658532006-10-03 23:10:46 -0500231
Timur Tabi6b0b5942007-10-03 11:34:59 -0500232 tempval = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) |
233 QE_BRGC_ENABLE | div16;
234
Timur Tabi7264ec42007-11-29 17:26:30 -0600235 out_be32(&qe_immr->brg.brgc[brg - QE_BRG1], tempval);
236
237 return 0;
Li Yang98658532006-10-03 23:10:46 -0500238}
Timur Tabi7264ec42007-11-29 17:26:30 -0600239EXPORT_SYMBOL(qe_setbrg);
Li Yang98658532006-10-03 23:10:46 -0500240
Timur Tabi174b0da2007-12-03 15:17:58 -0600241/* 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*/
246enum qe_clock qe_clock_source(const char *source)
247{
248 unsigned int i;
249
250 if (strcasecmp(source, "none") == 0)
251 return QE_CLK_NONE;
252
Zhao Qiang68f047e2016-06-06 14:29:58 +0800253 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
Timur Tabi174b0da2007-12-03 15:17:58 -0600259 if (strncasecmp(source, "brg", 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(source, "clk", 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}
277EXPORT_SYMBOL(qe_clock_source);
278
Li Yang98658532006-10-03 23:10:46 -0500279/* Initialize SNUMs (thread serial numbers) according to
280 * QE Module Control chapter, SNUM table
281 */
282static void qe_snums_init(void)
283{
284 int i;
Dave Liufa1b42b2010-01-12 00:04:03 +0000285 static const u8 snum_init_76[] = {
286 0x04, 0x05, 0x0C, 0x0D, 0x14, 0x15, 0x1C, 0x1D,
287 0x24, 0x25, 0x2C, 0x2D, 0x34, 0x35, 0x88, 0x89,
288 0x98, 0x99, 0xA8, 0xA9, 0xB8, 0xB9, 0xC8, 0xC9,
289 0xD8, 0xD9, 0xE8, 0xE9, 0x44, 0x45, 0x4C, 0x4D,
290 0x54, 0x55, 0x5C, 0x5D, 0x64, 0x65, 0x6C, 0x6D,
291 0x74, 0x75, 0x7C, 0x7D, 0x84, 0x85, 0x8C, 0x8D,
292 0x94, 0x95, 0x9C, 0x9D, 0xA4, 0xA5, 0xAC, 0xAD,
293 0xB4, 0xB5, 0xBC, 0xBD, 0xC4, 0xC5, 0xCC, 0xCD,
294 0xD4, 0xD5, 0xDC, 0xDD, 0xE4, 0xE5, 0xEC, 0xED,
295 0xF4, 0xF5, 0xFC, 0xFD,
296 };
297 static const u8 snum_init_46[] = {
Li Yang98658532006-10-03 23:10:46 -0500298 0x04, 0x05, 0x0C, 0x0D, 0x14, 0x15, 0x1C, 0x1D,
299 0x24, 0x25, 0x2C, 0x2D, 0x34, 0x35, 0x88, 0x89,
300 0x98, 0x99, 0xA8, 0xA9, 0xB8, 0xB9, 0xC8, 0xC9,
Haiying Wang98ca77a2009-05-01 15:40:48 -0400301 0xD8, 0xD9, 0xE8, 0xE9, 0x08, 0x09, 0x18, 0x19,
302 0x28, 0x29, 0x38, 0x39, 0x48, 0x49, 0x58, 0x59,
303 0x68, 0x69, 0x78, 0x79, 0x80, 0x81,
Li Yang98658532006-10-03 23:10:46 -0500304 };
Dave Liufa1b42b2010-01-12 00:04:03 +0000305 static const u8 *snum_init;
Li Yang98658532006-10-03 23:10:46 -0500306
Haiying Wang98ca77a2009-05-01 15:40:48 -0400307 qe_num_of_snum = qe_get_num_of_snums();
308
Dave Liufa1b42b2010-01-12 00:04:03 +0000309 if (qe_num_of_snum == 76)
310 snum_init = snum_init_76;
311 else
312 snum_init = snum_init_46;
313
Haiying Wang98ca77a2009-05-01 15:40:48 -0400314 for (i = 0; i < qe_num_of_snum; i++) {
Li Yang98658532006-10-03 23:10:46 -0500315 snums[i].num = snum_init[i];
316 snums[i].state = QE_SNUM_STATE_FREE;
317 }
318}
319
320int qe_get_snum(void)
321{
322 unsigned long flags;
323 int snum = -EBUSY;
324 int i;
325
326 spin_lock_irqsave(&qe_lock, flags);
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].state == QE_SNUM_STATE_FREE) {
329 snums[i].state = QE_SNUM_STATE_USED;
330 snum = snums[i].num;
331 break;
332 }
333 }
334 spin_unlock_irqrestore(&qe_lock, flags);
335
336 return snum;
337}
338EXPORT_SYMBOL(qe_get_snum);
339
340void qe_put_snum(u8 snum)
341{
342 int i;
343
Haiying Wang98ca77a2009-05-01 15:40:48 -0400344 for (i = 0; i < qe_num_of_snum; i++) {
Li Yang98658532006-10-03 23:10:46 -0500345 if (snums[i].num == snum) {
346 snums[i].state = QE_SNUM_STATE_FREE;
347 break;
348 }
349 }
350}
351EXPORT_SYMBOL(qe_put_snum);
352
353static int qe_sdma_init(void)
354{
Andy Fleming7e1cc9c2008-05-07 13:19:44 -0500355 struct sdma __iomem *sdma = &qe_immr->sdma;
Anton Vorontsov0c7b87b2009-09-16 01:43:52 +0400356 static unsigned long sdma_buf_offset = (unsigned long)-ENOMEM;
Li Yang98658532006-10-03 23:10:46 -0500357
358 if (!sdma)
359 return -ENODEV;
360
361 /* allocate 2 internal temporary buffers (512 bytes size each) for
362 * the SDMA */
Anton Vorontsov0c7b87b2009-09-16 01:43:52 +0400363 if (IS_ERR_VALUE(sdma_buf_offset)) {
364 sdma_buf_offset = qe_muram_alloc(512 * 2, 4096);
365 if (IS_ERR_VALUE(sdma_buf_offset))
366 return -ENOMEM;
367 }
Li Yang98658532006-10-03 23:10:46 -0500368
Timur Tabi4c356302007-05-08 14:46:36 -0500369 out_be32(&sdma->sdebcr, (u32) sdma_buf_offset & QE_SDEBCR_BA_MASK);
Chuck Meade7f013bc2007-03-27 10:46:10 -0400370 out_be32(&sdma->sdmr, (QE_SDMR_GLB_1_MSK |
371 (0x1 << QE_SDMR_CEN_SHIFT)));
Li Yang98658532006-10-03 23:10:46 -0500372
373 return 0;
374}
375
Timur Tabibc556ba2008-01-08 10:30:58 -0600376/* The maximum number of RISCs we support */
Anton Vorontsov98eaa092009-08-27 21:30:11 +0400377#define MAX_QE_RISC 4
Timur Tabibc556ba2008-01-08 10:30:58 -0600378
379/* Firmware information stored here for qe_get_firmware_info() */
380static struct qe_firmware_info qe_firmware_info;
381
382/*
383 * Set to 1 if QE firmware has been uploaded, and therefore
384 * qe_firmware_info contains valid data.
385 */
386static int qe_firmware_uploaded;
387
388/*
389 * Upload a QE microcode
390 *
391 * This function is a worker function for qe_upload_firmware(). It does
392 * the actual uploading of the microcode.
393 */
394static void qe_upload_microcode(const void *base,
395 const struct qe_microcode *ucode)
396{
397 const __be32 *code = base + be32_to_cpu(ucode->code_offset);
398 unsigned int i;
399
400 if (ucode->major || ucode->minor || ucode->revision)
401 printk(KERN_INFO "qe-firmware: "
402 "uploading microcode '%s' version %u.%u.%u\n",
403 ucode->id, ucode->major, ucode->minor, ucode->revision);
404 else
405 printk(KERN_INFO "qe-firmware: "
406 "uploading microcode '%s'\n", ucode->id);
407
408 /* Use auto-increment */
409 out_be32(&qe_immr->iram.iadd, be32_to_cpu(ucode->iram_offset) |
410 QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR);
411
412 for (i = 0; i < be32_to_cpu(ucode->count); i++)
413 out_be32(&qe_immr->iram.idata, be32_to_cpu(code[i]));
Kokoris, Ioannise65650e2011-11-11 17:05:11 +0100414
415 /* Set I-RAM Ready Register */
416 out_be32(&qe_immr->iram.iready, be32_to_cpu(QE_IRAM_READY));
Timur Tabibc556ba2008-01-08 10:30:58 -0600417}
418
419/*
420 * Upload a microcode to the I-RAM at a specific address.
421 *
Paul Bolle395cf962011-08-15 02:02:26 +0200422 * See Documentation/powerpc/qe_firmware.txt for information on QE microcode
Timur Tabibc556ba2008-01-08 10:30:58 -0600423 * uploading.
424 *
425 * Currently, only version 1 is supported, so the 'version' field must be
426 * set to 1.
427 *
428 * The SOC model and revision are not validated, they are only displayed for
429 * informational purposes.
430 *
431 * 'calc_size' is the calculated size, in bytes, of the firmware structure and
432 * all of the microcode structures, minus the CRC.
433 *
434 * 'length' is the size that the structure says it is, including the CRC.
435 */
436int qe_upload_firmware(const struct qe_firmware *firmware)
437{
438 unsigned int i;
439 unsigned int j;
440 u32 crc;
441 size_t calc_size = sizeof(struct qe_firmware);
442 size_t length;
443 const struct qe_header *hdr;
444
445 if (!firmware) {
446 printk(KERN_ERR "qe-firmware: invalid pointer\n");
447 return -EINVAL;
448 }
449
450 hdr = &firmware->header;
451 length = be32_to_cpu(hdr->length);
452
453 /* Check the magic */
454 if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
455 (hdr->magic[2] != 'F')) {
456 printk(KERN_ERR "qe-firmware: not a microcode\n");
457 return -EPERM;
458 }
459
460 /* Check the version */
461 if (hdr->version != 1) {
462 printk(KERN_ERR "qe-firmware: unsupported version\n");
463 return -EPERM;
464 }
465
466 /* Validate some of the fields */
Timur Tabi6f913162008-03-03 11:11:30 -0600467 if ((firmware->count < 1) || (firmware->count > MAX_QE_RISC)) {
Timur Tabibc556ba2008-01-08 10:30:58 -0600468 printk(KERN_ERR "qe-firmware: invalid data\n");
469 return -EINVAL;
470 }
471
472 /* Validate the length and check if there's a CRC */
473 calc_size += (firmware->count - 1) * sizeof(struct qe_microcode);
474
475 for (i = 0; i < firmware->count; i++)
476 /*
477 * For situations where the second RISC uses the same microcode
478 * as the first, the 'code_offset' and 'count' fields will be
479 * zero, so it's okay to add those.
480 */
481 calc_size += sizeof(__be32) *
482 be32_to_cpu(firmware->microcode[i].count);
483
484 /* Validate the length */
485 if (length != calc_size + sizeof(__be32)) {
486 printk(KERN_ERR "qe-firmware: invalid length\n");
487 return -EPERM;
488 }
489
490 /* Validate the CRC */
491 crc = be32_to_cpu(*(__be32 *)((void *)firmware + calc_size));
492 if (crc != crc32(0, firmware, calc_size)) {
493 printk(KERN_ERR "qe-firmware: firmware CRC is invalid\n");
494 return -EIO;
495 }
496
497 /*
498 * If the microcode calls for it, split the I-RAM.
499 */
500 if (!firmware->split)
501 setbits16(&qe_immr->cp.cercr, QE_CP_CERCR_CIR);
502
503 if (firmware->soc.model)
504 printk(KERN_INFO
505 "qe-firmware: firmware '%s' for %u V%u.%u\n",
506 firmware->id, be16_to_cpu(firmware->soc.model),
507 firmware->soc.major, firmware->soc.minor);
508 else
509 printk(KERN_INFO "qe-firmware: firmware '%s'\n",
510 firmware->id);
511
512 /*
513 * The QE only supports one microcode per RISC, so clear out all the
514 * saved microcode information and put in the new.
515 */
516 memset(&qe_firmware_info, 0, sizeof(qe_firmware_info));
Rickard Strandqvist5db43122014-07-26 23:26:51 +0200517 strlcpy(qe_firmware_info.id, firmware->id, sizeof(qe_firmware_info.id));
Timur Tabibc556ba2008-01-08 10:30:58 -0600518 qe_firmware_info.extended_modes = firmware->extended_modes;
519 memcpy(qe_firmware_info.vtraps, firmware->vtraps,
520 sizeof(firmware->vtraps));
521
522 /* Loop through each microcode. */
523 for (i = 0; i < firmware->count; i++) {
524 const struct qe_microcode *ucode = &firmware->microcode[i];
525
526 /* Upload a microcode if it's present */
527 if (ucode->code_offset)
528 qe_upload_microcode(firmware, ucode);
529
530 /* Program the traps for this processor */
531 for (j = 0; j < 16; j++) {
532 u32 trap = be32_to_cpu(ucode->traps[j]);
533
534 if (trap)
535 out_be32(&qe_immr->rsp[i].tibcr[j], trap);
536 }
537
538 /* Enable traps */
539 out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
540 }
541
542 qe_firmware_uploaded = 1;
543
544 return 0;
545}
546EXPORT_SYMBOL(qe_upload_firmware);
547
548/*
549 * Get info on the currently-loaded firmware
550 *
551 * This function also checks the device tree to see if the boot loader has
552 * uploaded a firmware already.
553 */
554struct qe_firmware_info *qe_get_firmware_info(void)
555{
556 static int initialized;
557 struct property *prop;
558 struct device_node *qe;
559 struct device_node *fw = NULL;
560 const char *sprop;
561 unsigned int i;
562
563 /*
564 * If we haven't checked yet, and a driver hasn't uploaded a firmware
565 * yet, then check the device tree for information.
566 */
Ionut Nicu86f4e5d2008-03-07 19:27:59 +0200567 if (qe_firmware_uploaded)
568 return &qe_firmware_info;
569
570 if (initialized)
Timur Tabibc556ba2008-01-08 10:30:58 -0600571 return NULL;
572
573 initialized = 1;
574
575 /*
576 * Newer device trees have an "fsl,qe" compatible property for the QE
577 * node, but we still need to support older device trees.
578 */
579 qe = of_find_compatible_node(NULL, NULL, "fsl,qe");
580 if (!qe) {
581 qe = of_find_node_by_type(NULL, "qe");
582 if (!qe)
583 return NULL;
584 }
585
586 /* Find the 'firmware' child node */
Rob Herringf55f6122018-08-29 15:04:25 -0500587 fw = of_get_child_by_name(qe, "firmware");
Timur Tabibc556ba2008-01-08 10:30:58 -0600588 of_node_put(qe);
589
590 /* Did we find the 'firmware' node? */
591 if (!fw)
592 return NULL;
593
594 qe_firmware_uploaded = 1;
595
596 /* Copy the data into qe_firmware_info*/
597 sprop = of_get_property(fw, "id", NULL);
598 if (sprop)
Rickard Strandqvist5db43122014-07-26 23:26:51 +0200599 strlcpy(qe_firmware_info.id, sprop,
600 sizeof(qe_firmware_info.id));
Timur Tabibc556ba2008-01-08 10:30:58 -0600601
602 prop = of_find_property(fw, "extended-modes", NULL);
603 if (prop && (prop->length == sizeof(u64))) {
604 const u64 *iprop = prop->value;
605
606 qe_firmware_info.extended_modes = *iprop;
607 }
608
609 prop = of_find_property(fw, "virtual-traps", NULL);
610 if (prop && (prop->length == 32)) {
611 const u32 *iprop = prop->value;
612
613 for (i = 0; i < ARRAY_SIZE(qe_firmware_info.vtraps); i++)
614 qe_firmware_info.vtraps[i] = iprop[i];
615 }
616
617 of_node_put(fw);
618
619 return &qe_firmware_info;
620}
621EXPORT_SYMBOL(qe_get_firmware_info);
622
Haiying Wang06c44352009-05-01 15:40:47 -0400623unsigned int qe_get_num_of_risc(void)
624{
625 struct device_node *qe;
626 int size;
627 unsigned int num_of_risc = 0;
628 const u32 *prop;
629
630 qe = of_find_compatible_node(NULL, NULL, "fsl,qe");
631 if (!qe) {
632 /* Older devices trees did not have an "fsl,qe"
633 * compatible property, so we need to look for
634 * the QE node by name.
635 */
636 qe = of_find_node_by_type(NULL, "qe");
637 if (!qe)
638 return num_of_risc;
639 }
640
641 prop = of_get_property(qe, "fsl,qe-num-riscs", &size);
642 if (prop && size == sizeof(*prop))
643 num_of_risc = *prop;
644
645 of_node_put(qe);
646
647 return num_of_risc;
648}
649EXPORT_SYMBOL(qe_get_num_of_risc);
650
Haiying Wang98ca77a2009-05-01 15:40:48 -0400651unsigned int qe_get_num_of_snums(void)
652{
653 struct device_node *qe;
654 int size;
655 unsigned int num_of_snums;
656 const u32 *prop;
657
658 num_of_snums = 28; /* The default number of snum for threads is 28 */
659 qe = of_find_compatible_node(NULL, NULL, "fsl,qe");
660 if (!qe) {
661 /* Older devices trees did not have an "fsl,qe"
662 * compatible property, so we need to look for
663 * the QE node by name.
664 */
665 qe = of_find_node_by_type(NULL, "qe");
666 if (!qe)
667 return num_of_snums;
668 }
669
670 prop = of_get_property(qe, "fsl,qe-num-snums", &size);
671 if (prop && size == sizeof(*prop)) {
672 num_of_snums = *prop;
673 if ((num_of_snums < 28) || (num_of_snums > QE_NUM_OF_SNUM)) {
674 /* No QE ever has fewer than 28 SNUMs */
675 pr_err("QE: number of snum is invalid\n");
Julia Lawall5aac4d72010-08-29 11:52:44 +0200676 of_node_put(qe);
Haiying Wang98ca77a2009-05-01 15:40:48 -0400677 return -EINVAL;
678 }
679 }
680
681 of_node_put(qe);
682
683 return num_of_snums;
684}
685EXPORT_SYMBOL(qe_get_num_of_snums);
Anton Vorontsovfdfde242009-09-16 01:43:55 +0400686
Zhao Qiang302c0592015-11-30 10:48:56 +0800687static int __init qe_init(void)
688{
689 struct device_node *np;
690
691 np = of_find_compatible_node(NULL, NULL, "fsl,qe");
692 if (!np)
693 return -ENODEV;
694 qe_reset();
695 of_node_put(np);
696 return 0;
697}
698subsys_initcall(qe_init);
699
Anton Vorontsovfdfde242009-09-16 01:43:55 +0400700#if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC_85xx)
Grant Likelya454dc52010-07-22 15:52:34 -0600701static int qe_resume(struct platform_device *ofdev)
Anton Vorontsovfdfde242009-09-16 01:43:55 +0400702{
703 if (!qe_alive_during_sleep())
704 qe_reset();
705 return 0;
706}
707
Grant Likely00006122011-02-22 19:59:54 -0700708static int qe_probe(struct platform_device *ofdev)
Anton Vorontsovfdfde242009-09-16 01:43:55 +0400709{
710 return 0;
711}
712
713static const struct of_device_id qe_ids[] = {
714 { .compatible = "fsl,qe", },
715 { },
716};
717
Grant Likely00006122011-02-22 19:59:54 -0700718static struct platform_driver qe_driver = {
Grant Likely40182942010-04-13 16:13:02 -0700719 .driver = {
720 .name = "fsl-qe",
Grant Likely40182942010-04-13 16:13:02 -0700721 .of_match_table = qe_ids,
722 },
Anton Vorontsovfdfde242009-09-16 01:43:55 +0400723 .probe = qe_probe,
724 .resume = qe_resume,
725};
726
Geliang Tangc9492b42016-11-23 23:04:21 +0800727builtin_platform_driver(qe_driver);
Anton Vorontsovfdfde242009-09-16 01:43:55 +0400728#endif /* defined(CONFIG_SUSPEND) && defined(CONFIG_PPC_85xx) */