162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2006-2010 Freescale Semiconductor, Inc. All rights reserved.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Authors: 	Shlomi Gridish <gridish@freescale.com>
662306a36Sopenharmony_ci * 		Li Yang <leoli@freescale.com>
762306a36Sopenharmony_ci * Based on cpm2_common.c from Dan Malek (dmalek@jlc.net)
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * Description:
1062306a36Sopenharmony_ci * General Purpose functions for the global management of the
1162306a36Sopenharmony_ci * QUICC Engine (QE).
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ci#include <linux/bitmap.h>
1462306a36Sopenharmony_ci#include <linux/errno.h>
1562306a36Sopenharmony_ci#include <linux/sched.h>
1662306a36Sopenharmony_ci#include <linux/kernel.h>
1762306a36Sopenharmony_ci#include <linux/param.h>
1862306a36Sopenharmony_ci#include <linux/string.h>
1962306a36Sopenharmony_ci#include <linux/spinlock.h>
2062306a36Sopenharmony_ci#include <linux/mm.h>
2162306a36Sopenharmony_ci#include <linux/interrupt.h>
2262306a36Sopenharmony_ci#include <linux/module.h>
2362306a36Sopenharmony_ci#include <linux/delay.h>
2462306a36Sopenharmony_ci#include <linux/ioport.h>
2562306a36Sopenharmony_ci#include <linux/iopoll.h>
2662306a36Sopenharmony_ci#include <linux/crc32.h>
2762306a36Sopenharmony_ci#include <linux/mod_devicetable.h>
2862306a36Sopenharmony_ci#include <linux/of.h>
2962306a36Sopenharmony_ci#include <linux/platform_device.h>
3062306a36Sopenharmony_ci#include <soc/fsl/qe/immap_qe.h>
3162306a36Sopenharmony_ci#include <soc/fsl/qe/qe.h>
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_cistatic void qe_snums_init(void);
3462306a36Sopenharmony_cistatic int qe_sdma_init(void);
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistatic DEFINE_SPINLOCK(qe_lock);
3762306a36Sopenharmony_ciDEFINE_SPINLOCK(cmxgcr_lock);
3862306a36Sopenharmony_ciEXPORT_SYMBOL(cmxgcr_lock);
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci/* We allocate this here because it is used almost exclusively for
4162306a36Sopenharmony_ci * the communication processor devices.
4262306a36Sopenharmony_ci */
4362306a36Sopenharmony_cistruct qe_immap __iomem *qe_immr;
4462306a36Sopenharmony_ciEXPORT_SYMBOL(qe_immr);
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cistatic u8 snums[QE_NUM_OF_SNUM];	/* Dynamically allocated SNUMs */
4762306a36Sopenharmony_cistatic DECLARE_BITMAP(snum_state, QE_NUM_OF_SNUM);
4862306a36Sopenharmony_cistatic unsigned int qe_num_of_snum;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_cistatic phys_addr_t qebase = -1;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistatic struct device_node *qe_get_device_node(void)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	struct device_node *qe;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	/*
5762306a36Sopenharmony_ci	 * Newer device trees have an "fsl,qe" compatible property for the QE
5862306a36Sopenharmony_ci	 * node, but we still need to support older device trees.
5962306a36Sopenharmony_ci	 */
6062306a36Sopenharmony_ci	qe = of_find_compatible_node(NULL, NULL, "fsl,qe");
6162306a36Sopenharmony_ci	if (qe)
6262306a36Sopenharmony_ci		return qe;
6362306a36Sopenharmony_ci	return of_find_node_by_type(NULL, "qe");
6462306a36Sopenharmony_ci}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_cistatic phys_addr_t get_qe_base(void)
6762306a36Sopenharmony_ci{
6862306a36Sopenharmony_ci	struct device_node *qe;
6962306a36Sopenharmony_ci	int ret;
7062306a36Sopenharmony_ci	struct resource res;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	if (qebase != -1)
7362306a36Sopenharmony_ci		return qebase;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	qe = qe_get_device_node();
7662306a36Sopenharmony_ci	if (!qe)
7762306a36Sopenharmony_ci		return qebase;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	ret = of_address_to_resource(qe, 0, &res);
8062306a36Sopenharmony_ci	if (!ret)
8162306a36Sopenharmony_ci		qebase = res.start;
8262306a36Sopenharmony_ci	of_node_put(qe);
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	return qebase;
8562306a36Sopenharmony_ci}
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_civoid qe_reset(void)
8862306a36Sopenharmony_ci{
8962306a36Sopenharmony_ci	if (qe_immr == NULL)
9062306a36Sopenharmony_ci		qe_immr = ioremap(get_qe_base(), QE_IMMAP_SIZE);
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	qe_snums_init();
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID,
9562306a36Sopenharmony_ci		     QE_CR_PROTOCOL_UNSPECIFIED, 0);
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	/* Reclaim the MURAM memory for our use. */
9862306a36Sopenharmony_ci	qe_muram_init();
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	if (qe_sdma_init())
10162306a36Sopenharmony_ci		panic("sdma init failed!");
10262306a36Sopenharmony_ci}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ciint qe_issue_cmd(u32 cmd, u32 device, u8 mcn_protocol, u32 cmd_input)
10562306a36Sopenharmony_ci{
10662306a36Sopenharmony_ci	unsigned long flags;
10762306a36Sopenharmony_ci	u8 mcn_shift = 0, dev_shift = 0;
10862306a36Sopenharmony_ci	u32 val;
10962306a36Sopenharmony_ci	int ret;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	spin_lock_irqsave(&qe_lock, flags);
11262306a36Sopenharmony_ci	if (cmd == QE_RESET) {
11362306a36Sopenharmony_ci		iowrite32be((u32)(cmd | QE_CR_FLG), &qe_immr->cp.cecr);
11462306a36Sopenharmony_ci	} else {
11562306a36Sopenharmony_ci		if (cmd == QE_ASSIGN_PAGE) {
11662306a36Sopenharmony_ci			/* Here device is the SNUM, not sub-block */
11762306a36Sopenharmony_ci			dev_shift = QE_CR_SNUM_SHIFT;
11862306a36Sopenharmony_ci		} else if (cmd == QE_ASSIGN_RISC) {
11962306a36Sopenharmony_ci			/* Here device is the SNUM, and mcnProtocol is
12062306a36Sopenharmony_ci			 * e_QeCmdRiscAssignment value */
12162306a36Sopenharmony_ci			dev_shift = QE_CR_SNUM_SHIFT;
12262306a36Sopenharmony_ci			mcn_shift = QE_CR_MCN_RISC_ASSIGN_SHIFT;
12362306a36Sopenharmony_ci		} else {
12462306a36Sopenharmony_ci			if (device == QE_CR_SUBBLOCK_USB)
12562306a36Sopenharmony_ci				mcn_shift = QE_CR_MCN_USB_SHIFT;
12662306a36Sopenharmony_ci			else
12762306a36Sopenharmony_ci				mcn_shift = QE_CR_MCN_NORMAL_SHIFT;
12862306a36Sopenharmony_ci		}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci		iowrite32be(cmd_input, &qe_immr->cp.cecdr);
13162306a36Sopenharmony_ci		iowrite32be((cmd | QE_CR_FLG | ((u32)device << dev_shift) | (u32)mcn_protocol << mcn_shift),
13262306a36Sopenharmony_ci			       &qe_immr->cp.cecr);
13362306a36Sopenharmony_ci	}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	/* wait for the QE_CR_FLG to clear */
13662306a36Sopenharmony_ci	ret = readx_poll_timeout_atomic(ioread32be, &qe_immr->cp.cecr, val,
13762306a36Sopenharmony_ci					(val & QE_CR_FLG) == 0, 0, 100);
13862306a36Sopenharmony_ci	/* On timeout, ret is -ETIMEDOUT, otherwise it will be 0. */
13962306a36Sopenharmony_ci	spin_unlock_irqrestore(&qe_lock, flags);
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	return ret == 0;
14262306a36Sopenharmony_ci}
14362306a36Sopenharmony_ciEXPORT_SYMBOL(qe_issue_cmd);
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci/* Set a baud rate generator. This needs lots of work. There are
14662306a36Sopenharmony_ci * 16 BRGs, which can be connected to the QE channels or output
14762306a36Sopenharmony_ci * as clocks. The BRGs are in two different block of internal
14862306a36Sopenharmony_ci * memory mapped space.
14962306a36Sopenharmony_ci * The BRG clock is the QE clock divided by 2.
15062306a36Sopenharmony_ci * It was set up long ago during the initial boot phase and is
15162306a36Sopenharmony_ci * given to us.
15262306a36Sopenharmony_ci * Baud rate clocks are zero-based in the driver code (as that maps
15362306a36Sopenharmony_ci * to port numbers). Documentation uses 1-based numbering.
15462306a36Sopenharmony_ci */
15562306a36Sopenharmony_cistatic unsigned int brg_clk = 0;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci#define CLK_GRAN	(1000)
15862306a36Sopenharmony_ci#define CLK_GRAN_LIMIT	(5)
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ciunsigned int qe_get_brg_clk(void)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	struct device_node *qe;
16362306a36Sopenharmony_ci	u32 brg;
16462306a36Sopenharmony_ci	unsigned int mod;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	if (brg_clk)
16762306a36Sopenharmony_ci		return brg_clk;
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	qe = qe_get_device_node();
17062306a36Sopenharmony_ci	if (!qe)
17162306a36Sopenharmony_ci		return brg_clk;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	if (!of_property_read_u32(qe, "brg-frequency", &brg))
17462306a36Sopenharmony_ci		brg_clk = brg;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	of_node_put(qe);
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	/* round this if near to a multiple of CLK_GRAN */
17962306a36Sopenharmony_ci	mod = brg_clk % CLK_GRAN;
18062306a36Sopenharmony_ci	if (mod) {
18162306a36Sopenharmony_ci		if (mod < CLK_GRAN_LIMIT)
18262306a36Sopenharmony_ci			brg_clk -= mod;
18362306a36Sopenharmony_ci		else if (mod > (CLK_GRAN - CLK_GRAN_LIMIT))
18462306a36Sopenharmony_ci			brg_clk += CLK_GRAN - mod;
18562306a36Sopenharmony_ci	}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	return brg_clk;
18862306a36Sopenharmony_ci}
18962306a36Sopenharmony_ciEXPORT_SYMBOL(qe_get_brg_clk);
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci#define PVR_VER_836x	0x8083
19262306a36Sopenharmony_ci#define PVR_VER_832x	0x8084
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_cistatic bool qe_general4_errata(void)
19562306a36Sopenharmony_ci{
19662306a36Sopenharmony_ci#ifdef CONFIG_PPC32
19762306a36Sopenharmony_ci	return pvr_version_is(PVR_VER_836x) || pvr_version_is(PVR_VER_832x);
19862306a36Sopenharmony_ci#endif
19962306a36Sopenharmony_ci	return false;
20062306a36Sopenharmony_ci}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci/* Program the BRG to the given sampling rate and multiplier
20362306a36Sopenharmony_ci *
20462306a36Sopenharmony_ci * @brg: the BRG, QE_BRG1 - QE_BRG16
20562306a36Sopenharmony_ci * @rate: the desired sampling rate
20662306a36Sopenharmony_ci * @multiplier: corresponds to the value programmed in GUMR_L[RDCR] or
20762306a36Sopenharmony_ci * GUMR_L[TDCR].  E.g., if this BRG is the RX clock, and GUMR_L[RDCR]=01,
20862306a36Sopenharmony_ci * then 'multiplier' should be 8.
20962306a36Sopenharmony_ci */
21062306a36Sopenharmony_ciint qe_setbrg(enum qe_clock brg, unsigned int rate, unsigned int multiplier)
21162306a36Sopenharmony_ci{
21262306a36Sopenharmony_ci	u32 divisor, tempval;
21362306a36Sopenharmony_ci	u32 div16 = 0;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	if ((brg < QE_BRG1) || (brg > QE_BRG16))
21662306a36Sopenharmony_ci		return -EINVAL;
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	divisor = qe_get_brg_clk() / (rate * multiplier);
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	if (divisor > QE_BRGC_DIVISOR_MAX + 1) {
22162306a36Sopenharmony_ci		div16 = QE_BRGC_DIV16;
22262306a36Sopenharmony_ci		divisor /= 16;
22362306a36Sopenharmony_ci	}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	/* Errata QE_General4, which affects some MPC832x and MPC836x SOCs, says
22662306a36Sopenharmony_ci	   that the BRG divisor must be even if you're not using divide-by-16
22762306a36Sopenharmony_ci	   mode. */
22862306a36Sopenharmony_ci	if (qe_general4_errata())
22962306a36Sopenharmony_ci		if (!div16 && (divisor & 1) && (divisor > 3))
23062306a36Sopenharmony_ci			divisor++;
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	tempval = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) |
23362306a36Sopenharmony_ci		QE_BRGC_ENABLE | div16;
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	iowrite32be(tempval, &qe_immr->brg.brgc[brg - QE_BRG1]);
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	return 0;
23862306a36Sopenharmony_ci}
23962306a36Sopenharmony_ciEXPORT_SYMBOL(qe_setbrg);
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci/* Convert a string to a QE clock source enum
24262306a36Sopenharmony_ci *
24362306a36Sopenharmony_ci * This function takes a string, typically from a property in the device
24462306a36Sopenharmony_ci * tree, and returns the corresponding "enum qe_clock" value.
24562306a36Sopenharmony_ci*/
24662306a36Sopenharmony_cienum qe_clock qe_clock_source(const char *source)
24762306a36Sopenharmony_ci{
24862306a36Sopenharmony_ci	unsigned int i;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	if (strcasecmp(source, "none") == 0)
25162306a36Sopenharmony_ci		return QE_CLK_NONE;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	if (strcmp(source, "tsync_pin") == 0)
25462306a36Sopenharmony_ci		return QE_TSYNC_PIN;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	if (strcmp(source, "rsync_pin") == 0)
25762306a36Sopenharmony_ci		return QE_RSYNC_PIN;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	if (strncasecmp(source, "brg", 3) == 0) {
26062306a36Sopenharmony_ci		i = simple_strtoul(source + 3, NULL, 10);
26162306a36Sopenharmony_ci		if ((i >= 1) && (i <= 16))
26262306a36Sopenharmony_ci			return (QE_BRG1 - 1) + i;
26362306a36Sopenharmony_ci		else
26462306a36Sopenharmony_ci			return QE_CLK_DUMMY;
26562306a36Sopenharmony_ci	}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	if (strncasecmp(source, "clk", 3) == 0) {
26862306a36Sopenharmony_ci		i = simple_strtoul(source + 3, NULL, 10);
26962306a36Sopenharmony_ci		if ((i >= 1) && (i <= 24))
27062306a36Sopenharmony_ci			return (QE_CLK1 - 1) + i;
27162306a36Sopenharmony_ci		else
27262306a36Sopenharmony_ci			return QE_CLK_DUMMY;
27362306a36Sopenharmony_ci	}
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	return QE_CLK_DUMMY;
27662306a36Sopenharmony_ci}
27762306a36Sopenharmony_ciEXPORT_SYMBOL(qe_clock_source);
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci/* Initialize SNUMs (thread serial numbers) according to
28062306a36Sopenharmony_ci * QE Module Control chapter, SNUM table
28162306a36Sopenharmony_ci */
28262306a36Sopenharmony_cistatic void qe_snums_init(void)
28362306a36Sopenharmony_ci{
28462306a36Sopenharmony_ci	static const u8 snum_init_76[] = {
28562306a36Sopenharmony_ci		0x04, 0x05, 0x0C, 0x0D, 0x14, 0x15, 0x1C, 0x1D,
28662306a36Sopenharmony_ci		0x24, 0x25, 0x2C, 0x2D, 0x34, 0x35, 0x88, 0x89,
28762306a36Sopenharmony_ci		0x98, 0x99, 0xA8, 0xA9, 0xB8, 0xB9, 0xC8, 0xC9,
28862306a36Sopenharmony_ci		0xD8, 0xD9, 0xE8, 0xE9, 0x44, 0x45, 0x4C, 0x4D,
28962306a36Sopenharmony_ci		0x54, 0x55, 0x5C, 0x5D, 0x64, 0x65, 0x6C, 0x6D,
29062306a36Sopenharmony_ci		0x74, 0x75, 0x7C, 0x7D, 0x84, 0x85, 0x8C, 0x8D,
29162306a36Sopenharmony_ci		0x94, 0x95, 0x9C, 0x9D, 0xA4, 0xA5, 0xAC, 0xAD,
29262306a36Sopenharmony_ci		0xB4, 0xB5, 0xBC, 0xBD, 0xC4, 0xC5, 0xCC, 0xCD,
29362306a36Sopenharmony_ci		0xD4, 0xD5, 0xDC, 0xDD, 0xE4, 0xE5, 0xEC, 0xED,
29462306a36Sopenharmony_ci		0xF4, 0xF5, 0xFC, 0xFD,
29562306a36Sopenharmony_ci	};
29662306a36Sopenharmony_ci	static const u8 snum_init_46[] = {
29762306a36Sopenharmony_ci		0x04, 0x05, 0x0C, 0x0D, 0x14, 0x15, 0x1C, 0x1D,
29862306a36Sopenharmony_ci		0x24, 0x25, 0x2C, 0x2D, 0x34, 0x35, 0x88, 0x89,
29962306a36Sopenharmony_ci		0x98, 0x99, 0xA8, 0xA9, 0xB8, 0xB9, 0xC8, 0xC9,
30062306a36Sopenharmony_ci		0xD8, 0xD9, 0xE8, 0xE9, 0x08, 0x09, 0x18, 0x19,
30162306a36Sopenharmony_ci		0x28, 0x29, 0x38, 0x39, 0x48, 0x49, 0x58, 0x59,
30262306a36Sopenharmony_ci		0x68, 0x69, 0x78, 0x79, 0x80, 0x81,
30362306a36Sopenharmony_ci	};
30462306a36Sopenharmony_ci	struct device_node *qe;
30562306a36Sopenharmony_ci	const u8 *snum_init;
30662306a36Sopenharmony_ci	int i;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	bitmap_zero(snum_state, QE_NUM_OF_SNUM);
30962306a36Sopenharmony_ci	qe_num_of_snum = 28; /* The default number of snum for threads is 28 */
31062306a36Sopenharmony_ci	qe = qe_get_device_node();
31162306a36Sopenharmony_ci	if (qe) {
31262306a36Sopenharmony_ci		i = of_property_read_variable_u8_array(qe, "fsl,qe-snums",
31362306a36Sopenharmony_ci						       snums, 1, QE_NUM_OF_SNUM);
31462306a36Sopenharmony_ci		if (i > 0) {
31562306a36Sopenharmony_ci			of_node_put(qe);
31662306a36Sopenharmony_ci			qe_num_of_snum = i;
31762306a36Sopenharmony_ci			return;
31862306a36Sopenharmony_ci		}
31962306a36Sopenharmony_ci		/*
32062306a36Sopenharmony_ci		 * Fall back to legacy binding of using the value of
32162306a36Sopenharmony_ci		 * fsl,qe-num-snums to choose one of the static arrays
32262306a36Sopenharmony_ci		 * above.
32362306a36Sopenharmony_ci		 */
32462306a36Sopenharmony_ci		of_property_read_u32(qe, "fsl,qe-num-snums", &qe_num_of_snum);
32562306a36Sopenharmony_ci		of_node_put(qe);
32662306a36Sopenharmony_ci	}
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	if (qe_num_of_snum == 76) {
32962306a36Sopenharmony_ci		snum_init = snum_init_76;
33062306a36Sopenharmony_ci	} else if (qe_num_of_snum == 28 || qe_num_of_snum == 46) {
33162306a36Sopenharmony_ci		snum_init = snum_init_46;
33262306a36Sopenharmony_ci	} else {
33362306a36Sopenharmony_ci		pr_err("QE: unsupported value of fsl,qe-num-snums: %u\n", qe_num_of_snum);
33462306a36Sopenharmony_ci		return;
33562306a36Sopenharmony_ci	}
33662306a36Sopenharmony_ci	memcpy(snums, snum_init, qe_num_of_snum);
33762306a36Sopenharmony_ci}
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ciint qe_get_snum(void)
34062306a36Sopenharmony_ci{
34162306a36Sopenharmony_ci	unsigned long flags;
34262306a36Sopenharmony_ci	int snum = -EBUSY;
34362306a36Sopenharmony_ci	int i;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	spin_lock_irqsave(&qe_lock, flags);
34662306a36Sopenharmony_ci	i = find_first_zero_bit(snum_state, qe_num_of_snum);
34762306a36Sopenharmony_ci	if (i < qe_num_of_snum) {
34862306a36Sopenharmony_ci		set_bit(i, snum_state);
34962306a36Sopenharmony_ci		snum = snums[i];
35062306a36Sopenharmony_ci	}
35162306a36Sopenharmony_ci	spin_unlock_irqrestore(&qe_lock, flags);
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	return snum;
35462306a36Sopenharmony_ci}
35562306a36Sopenharmony_ciEXPORT_SYMBOL(qe_get_snum);
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_civoid qe_put_snum(u8 snum)
35862306a36Sopenharmony_ci{
35962306a36Sopenharmony_ci	const u8 *p = memchr(snums, snum, qe_num_of_snum);
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	if (p)
36262306a36Sopenharmony_ci		clear_bit(p - snums, snum_state);
36362306a36Sopenharmony_ci}
36462306a36Sopenharmony_ciEXPORT_SYMBOL(qe_put_snum);
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_cistatic int qe_sdma_init(void)
36762306a36Sopenharmony_ci{
36862306a36Sopenharmony_ci	struct sdma __iomem *sdma = &qe_immr->sdma;
36962306a36Sopenharmony_ci	static s32 sdma_buf_offset = -ENOMEM;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	/* allocate 2 internal temporary buffers (512 bytes size each) for
37262306a36Sopenharmony_ci	 * the SDMA */
37362306a36Sopenharmony_ci	if (sdma_buf_offset < 0) {
37462306a36Sopenharmony_ci		sdma_buf_offset = qe_muram_alloc(512 * 2, 4096);
37562306a36Sopenharmony_ci		if (sdma_buf_offset < 0)
37662306a36Sopenharmony_ci			return -ENOMEM;
37762306a36Sopenharmony_ci	}
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	iowrite32be((u32)sdma_buf_offset & QE_SDEBCR_BA_MASK,
38062306a36Sopenharmony_ci		       &sdma->sdebcr);
38162306a36Sopenharmony_ci	iowrite32be((QE_SDMR_GLB_1_MSK | (0x1 << QE_SDMR_CEN_SHIFT)),
38262306a36Sopenharmony_ci		       &sdma->sdmr);
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	return 0;
38562306a36Sopenharmony_ci}
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci/* The maximum number of RISCs we support */
38862306a36Sopenharmony_ci#define MAX_QE_RISC     4
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci/* Firmware information stored here for qe_get_firmware_info() */
39162306a36Sopenharmony_cistatic struct qe_firmware_info qe_firmware_info;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci/*
39462306a36Sopenharmony_ci * Set to 1 if QE firmware has been uploaded, and therefore
39562306a36Sopenharmony_ci * qe_firmware_info contains valid data.
39662306a36Sopenharmony_ci */
39762306a36Sopenharmony_cistatic int qe_firmware_uploaded;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci/*
40062306a36Sopenharmony_ci * Upload a QE microcode
40162306a36Sopenharmony_ci *
40262306a36Sopenharmony_ci * This function is a worker function for qe_upload_firmware().  It does
40362306a36Sopenharmony_ci * the actual uploading of the microcode.
40462306a36Sopenharmony_ci */
40562306a36Sopenharmony_cistatic void qe_upload_microcode(const void *base,
40662306a36Sopenharmony_ci	const struct qe_microcode *ucode)
40762306a36Sopenharmony_ci{
40862306a36Sopenharmony_ci	const __be32 *code = base + be32_to_cpu(ucode->code_offset);
40962306a36Sopenharmony_ci	unsigned int i;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	if (ucode->major || ucode->minor || ucode->revision)
41262306a36Sopenharmony_ci		printk(KERN_INFO "qe-firmware: "
41362306a36Sopenharmony_ci			"uploading microcode '%s' version %u.%u.%u\n",
41462306a36Sopenharmony_ci			ucode->id, ucode->major, ucode->minor, ucode->revision);
41562306a36Sopenharmony_ci	else
41662306a36Sopenharmony_ci		printk(KERN_INFO "qe-firmware: "
41762306a36Sopenharmony_ci			"uploading microcode '%s'\n", ucode->id);
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	/* Use auto-increment */
42062306a36Sopenharmony_ci	iowrite32be(be32_to_cpu(ucode->iram_offset) | QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR,
42162306a36Sopenharmony_ci		       &qe_immr->iram.iadd);
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	for (i = 0; i < be32_to_cpu(ucode->count); i++)
42462306a36Sopenharmony_ci		iowrite32be(be32_to_cpu(code[i]), &qe_immr->iram.idata);
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	/* Set I-RAM Ready Register */
42762306a36Sopenharmony_ci	iowrite32be(QE_IRAM_READY, &qe_immr->iram.iready);
42862306a36Sopenharmony_ci}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci/*
43162306a36Sopenharmony_ci * Upload a microcode to the I-RAM at a specific address.
43262306a36Sopenharmony_ci *
43362306a36Sopenharmony_ci * See Documentation/powerpc/qe_firmware.rst for information on QE microcode
43462306a36Sopenharmony_ci * uploading.
43562306a36Sopenharmony_ci *
43662306a36Sopenharmony_ci * Currently, only version 1 is supported, so the 'version' field must be
43762306a36Sopenharmony_ci * set to 1.
43862306a36Sopenharmony_ci *
43962306a36Sopenharmony_ci * The SOC model and revision are not validated, they are only displayed for
44062306a36Sopenharmony_ci * informational purposes.
44162306a36Sopenharmony_ci *
44262306a36Sopenharmony_ci * 'calc_size' is the calculated size, in bytes, of the firmware structure and
44362306a36Sopenharmony_ci * all of the microcode structures, minus the CRC.
44462306a36Sopenharmony_ci *
44562306a36Sopenharmony_ci * 'length' is the size that the structure says it is, including the CRC.
44662306a36Sopenharmony_ci */
44762306a36Sopenharmony_ciint qe_upload_firmware(const struct qe_firmware *firmware)
44862306a36Sopenharmony_ci{
44962306a36Sopenharmony_ci	unsigned int i;
45062306a36Sopenharmony_ci	unsigned int j;
45162306a36Sopenharmony_ci	u32 crc;
45262306a36Sopenharmony_ci	size_t calc_size;
45362306a36Sopenharmony_ci	size_t length;
45462306a36Sopenharmony_ci	const struct qe_header *hdr;
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	if (!firmware) {
45762306a36Sopenharmony_ci		printk(KERN_ERR "qe-firmware: invalid pointer\n");
45862306a36Sopenharmony_ci		return -EINVAL;
45962306a36Sopenharmony_ci	}
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	hdr = &firmware->header;
46262306a36Sopenharmony_ci	length = be32_to_cpu(hdr->length);
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	/* Check the magic */
46562306a36Sopenharmony_ci	if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
46662306a36Sopenharmony_ci	    (hdr->magic[2] != 'F')) {
46762306a36Sopenharmony_ci		printk(KERN_ERR "qe-firmware: not a microcode\n");
46862306a36Sopenharmony_ci		return -EPERM;
46962306a36Sopenharmony_ci	}
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	/* Check the version */
47262306a36Sopenharmony_ci	if (hdr->version != 1) {
47362306a36Sopenharmony_ci		printk(KERN_ERR "qe-firmware: unsupported version\n");
47462306a36Sopenharmony_ci		return -EPERM;
47562306a36Sopenharmony_ci	}
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	/* Validate some of the fields */
47862306a36Sopenharmony_ci	if ((firmware->count < 1) || (firmware->count > MAX_QE_RISC)) {
47962306a36Sopenharmony_ci		printk(KERN_ERR "qe-firmware: invalid data\n");
48062306a36Sopenharmony_ci		return -EINVAL;
48162306a36Sopenharmony_ci	}
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	/* Validate the length and check if there's a CRC */
48462306a36Sopenharmony_ci	calc_size = struct_size(firmware, microcode, firmware->count);
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	for (i = 0; i < firmware->count; i++)
48762306a36Sopenharmony_ci		/*
48862306a36Sopenharmony_ci		 * For situations where the second RISC uses the same microcode
48962306a36Sopenharmony_ci		 * as the first, the 'code_offset' and 'count' fields will be
49062306a36Sopenharmony_ci		 * zero, so it's okay to add those.
49162306a36Sopenharmony_ci		 */
49262306a36Sopenharmony_ci		calc_size += sizeof(__be32) *
49362306a36Sopenharmony_ci			be32_to_cpu(firmware->microcode[i].count);
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	/* Validate the length */
49662306a36Sopenharmony_ci	if (length != calc_size + sizeof(__be32)) {
49762306a36Sopenharmony_ci		printk(KERN_ERR "qe-firmware: invalid length\n");
49862306a36Sopenharmony_ci		return -EPERM;
49962306a36Sopenharmony_ci	}
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	/* Validate the CRC */
50262306a36Sopenharmony_ci	crc = be32_to_cpu(*(__be32 *)((void *)firmware + calc_size));
50362306a36Sopenharmony_ci	if (crc != crc32(0, firmware, calc_size)) {
50462306a36Sopenharmony_ci		printk(KERN_ERR "qe-firmware: firmware CRC is invalid\n");
50562306a36Sopenharmony_ci		return -EIO;
50662306a36Sopenharmony_ci	}
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	/*
50962306a36Sopenharmony_ci	 * If the microcode calls for it, split the I-RAM.
51062306a36Sopenharmony_ci	 */
51162306a36Sopenharmony_ci	if (!firmware->split)
51262306a36Sopenharmony_ci		qe_setbits_be16(&qe_immr->cp.cercr, QE_CP_CERCR_CIR);
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	if (firmware->soc.model)
51562306a36Sopenharmony_ci		printk(KERN_INFO
51662306a36Sopenharmony_ci			"qe-firmware: firmware '%s' for %u V%u.%u\n",
51762306a36Sopenharmony_ci			firmware->id, be16_to_cpu(firmware->soc.model),
51862306a36Sopenharmony_ci			firmware->soc.major, firmware->soc.minor);
51962306a36Sopenharmony_ci	else
52062306a36Sopenharmony_ci		printk(KERN_INFO "qe-firmware: firmware '%s'\n",
52162306a36Sopenharmony_ci			firmware->id);
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	/*
52462306a36Sopenharmony_ci	 * The QE only supports one microcode per RISC, so clear out all the
52562306a36Sopenharmony_ci	 * saved microcode information and put in the new.
52662306a36Sopenharmony_ci	 */
52762306a36Sopenharmony_ci	memset(&qe_firmware_info, 0, sizeof(qe_firmware_info));
52862306a36Sopenharmony_ci	strscpy(qe_firmware_info.id, firmware->id, sizeof(qe_firmware_info.id));
52962306a36Sopenharmony_ci	qe_firmware_info.extended_modes = be64_to_cpu(firmware->extended_modes);
53062306a36Sopenharmony_ci	memcpy(qe_firmware_info.vtraps, firmware->vtraps,
53162306a36Sopenharmony_ci		sizeof(firmware->vtraps));
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	/* Loop through each microcode. */
53462306a36Sopenharmony_ci	for (i = 0; i < firmware->count; i++) {
53562306a36Sopenharmony_ci		const struct qe_microcode *ucode = &firmware->microcode[i];
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci		/* Upload a microcode if it's present */
53862306a36Sopenharmony_ci		if (ucode->code_offset)
53962306a36Sopenharmony_ci			qe_upload_microcode(firmware, ucode);
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci		/* Program the traps for this processor */
54262306a36Sopenharmony_ci		for (j = 0; j < 16; j++) {
54362306a36Sopenharmony_ci			u32 trap = be32_to_cpu(ucode->traps[j]);
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci			if (trap)
54662306a36Sopenharmony_ci				iowrite32be(trap,
54762306a36Sopenharmony_ci					       &qe_immr->rsp[i].tibcr[j]);
54862306a36Sopenharmony_ci		}
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci		/* Enable traps */
55162306a36Sopenharmony_ci		iowrite32be(be32_to_cpu(ucode->eccr),
55262306a36Sopenharmony_ci			       &qe_immr->rsp[i].eccr);
55362306a36Sopenharmony_ci	}
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	qe_firmware_uploaded = 1;
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	return 0;
55862306a36Sopenharmony_ci}
55962306a36Sopenharmony_ciEXPORT_SYMBOL(qe_upload_firmware);
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci/*
56262306a36Sopenharmony_ci * Get info on the currently-loaded firmware
56362306a36Sopenharmony_ci *
56462306a36Sopenharmony_ci * This function also checks the device tree to see if the boot loader has
56562306a36Sopenharmony_ci * uploaded a firmware already.
56662306a36Sopenharmony_ci */
56762306a36Sopenharmony_cistruct qe_firmware_info *qe_get_firmware_info(void)
56862306a36Sopenharmony_ci{
56962306a36Sopenharmony_ci	static int initialized;
57062306a36Sopenharmony_ci	struct device_node *qe;
57162306a36Sopenharmony_ci	struct device_node *fw = NULL;
57262306a36Sopenharmony_ci	const char *sprop;
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	/*
57562306a36Sopenharmony_ci	 * If we haven't checked yet, and a driver hasn't uploaded a firmware
57662306a36Sopenharmony_ci	 * yet, then check the device tree for information.
57762306a36Sopenharmony_ci	 */
57862306a36Sopenharmony_ci	if (qe_firmware_uploaded)
57962306a36Sopenharmony_ci		return &qe_firmware_info;
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	if (initialized)
58262306a36Sopenharmony_ci		return NULL;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	initialized = 1;
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	qe = qe_get_device_node();
58762306a36Sopenharmony_ci	if (!qe)
58862306a36Sopenharmony_ci		return NULL;
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	/* Find the 'firmware' child node */
59162306a36Sopenharmony_ci	fw = of_get_child_by_name(qe, "firmware");
59262306a36Sopenharmony_ci	of_node_put(qe);
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	/* Did we find the 'firmware' node? */
59562306a36Sopenharmony_ci	if (!fw)
59662306a36Sopenharmony_ci		return NULL;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	qe_firmware_uploaded = 1;
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	/* Copy the data into qe_firmware_info*/
60162306a36Sopenharmony_ci	sprop = of_get_property(fw, "id", NULL);
60262306a36Sopenharmony_ci	if (sprop)
60362306a36Sopenharmony_ci		strscpy(qe_firmware_info.id, sprop,
60462306a36Sopenharmony_ci			sizeof(qe_firmware_info.id));
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	of_property_read_u64(fw, "extended-modes",
60762306a36Sopenharmony_ci			     &qe_firmware_info.extended_modes);
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	of_property_read_u32_array(fw, "virtual-traps", qe_firmware_info.vtraps,
61062306a36Sopenharmony_ci				   ARRAY_SIZE(qe_firmware_info.vtraps));
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	of_node_put(fw);
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	return &qe_firmware_info;
61562306a36Sopenharmony_ci}
61662306a36Sopenharmony_ciEXPORT_SYMBOL(qe_get_firmware_info);
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ciunsigned int qe_get_num_of_risc(void)
61962306a36Sopenharmony_ci{
62062306a36Sopenharmony_ci	struct device_node *qe;
62162306a36Sopenharmony_ci	unsigned int num_of_risc = 0;
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	qe = qe_get_device_node();
62462306a36Sopenharmony_ci	if (!qe)
62562306a36Sopenharmony_ci		return num_of_risc;
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	of_property_read_u32(qe, "fsl,qe-num-riscs", &num_of_risc);
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	of_node_put(qe);
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	return num_of_risc;
63262306a36Sopenharmony_ci}
63362306a36Sopenharmony_ciEXPORT_SYMBOL(qe_get_num_of_risc);
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ciunsigned int qe_get_num_of_snums(void)
63662306a36Sopenharmony_ci{
63762306a36Sopenharmony_ci	return qe_num_of_snum;
63862306a36Sopenharmony_ci}
63962306a36Sopenharmony_ciEXPORT_SYMBOL(qe_get_num_of_snums);
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_cistatic int __init qe_init(void)
64262306a36Sopenharmony_ci{
64362306a36Sopenharmony_ci	struct device_node *np;
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	np = of_find_compatible_node(NULL, NULL, "fsl,qe");
64662306a36Sopenharmony_ci	if (!np)
64762306a36Sopenharmony_ci		return -ENODEV;
64862306a36Sopenharmony_ci	qe_reset();
64962306a36Sopenharmony_ci	of_node_put(np);
65062306a36Sopenharmony_ci	return 0;
65162306a36Sopenharmony_ci}
65262306a36Sopenharmony_cisubsys_initcall(qe_init);
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci#if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC_85xx)
65562306a36Sopenharmony_cistatic int qe_resume(struct platform_device *ofdev)
65662306a36Sopenharmony_ci{
65762306a36Sopenharmony_ci	if (!qe_alive_during_sleep())
65862306a36Sopenharmony_ci		qe_reset();
65962306a36Sopenharmony_ci	return 0;
66062306a36Sopenharmony_ci}
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_cistatic int qe_probe(struct platform_device *ofdev)
66362306a36Sopenharmony_ci{
66462306a36Sopenharmony_ci	return 0;
66562306a36Sopenharmony_ci}
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_cistatic const struct of_device_id qe_ids[] = {
66862306a36Sopenharmony_ci	{ .compatible = "fsl,qe", },
66962306a36Sopenharmony_ci	{ },
67062306a36Sopenharmony_ci};
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_cistatic struct platform_driver qe_driver = {
67362306a36Sopenharmony_ci	.driver = {
67462306a36Sopenharmony_ci		.name = "fsl-qe",
67562306a36Sopenharmony_ci		.of_match_table = qe_ids,
67662306a36Sopenharmony_ci	},
67762306a36Sopenharmony_ci	.probe = qe_probe,
67862306a36Sopenharmony_ci	.resume = qe_resume,
67962306a36Sopenharmony_ci};
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_cibuiltin_platform_driver(qe_driver);
68262306a36Sopenharmony_ci#endif /* defined(CONFIG_SUSPEND) && defined(CONFIG_PPC_85xx) */
683