xref: /OK3568_Linux_fs/kernel/drivers/soc/ixp4xx/ixp4xx-npe.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Intel IXP4xx Network Processor Engine driver for Linux
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl>
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * The code is based on publicly available information:
8*4882a593Smuzhiyun  * - Intel IXP4xx Developer's Manual and other e-papers
9*4882a593Smuzhiyun  * - Intel IXP400 Access Library Software (BSD license)
10*4882a593Smuzhiyun  * - previous works by Christian Hohnstaedt <chohnstaedt@innominate.com>
11*4882a593Smuzhiyun  *   Thanks, Christian.
12*4882a593Smuzhiyun  */
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun #include <linux/delay.h>
15*4882a593Smuzhiyun #include <linux/dma-mapping.h>
16*4882a593Smuzhiyun #include <linux/firmware.h>
17*4882a593Smuzhiyun #include <linux/io.h>
18*4882a593Smuzhiyun #include <linux/kernel.h>
19*4882a593Smuzhiyun #include <linux/module.h>
20*4882a593Smuzhiyun #include <linux/of.h>
21*4882a593Smuzhiyun #include <linux/platform_device.h>
22*4882a593Smuzhiyun #include <linux/soc/ixp4xx/npe.h>
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun #define DEBUG_MSG			0
25*4882a593Smuzhiyun #define DEBUG_FW			0
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun #define NPE_COUNT			3
28*4882a593Smuzhiyun #define MAX_RETRIES			1000	/* microseconds */
29*4882a593Smuzhiyun #define NPE_42X_DATA_SIZE		0x800	/* in dwords */
30*4882a593Smuzhiyun #define NPE_46X_DATA_SIZE		0x1000
31*4882a593Smuzhiyun #define NPE_A_42X_INSTR_SIZE		0x1000
32*4882a593Smuzhiyun #define NPE_B_AND_C_42X_INSTR_SIZE	0x800
33*4882a593Smuzhiyun #define NPE_46X_INSTR_SIZE		0x1000
34*4882a593Smuzhiyun #define REGS_SIZE			0x1000
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun #define NPE_PHYS_REG			32
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun #define FW_MAGIC			0xFEEDF00D
39*4882a593Smuzhiyun #define FW_BLOCK_TYPE_INSTR		0x0
40*4882a593Smuzhiyun #define FW_BLOCK_TYPE_DATA		0x1
41*4882a593Smuzhiyun #define FW_BLOCK_TYPE_EOF		0xF
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun /* NPE exec status (read) and command (write) */
44*4882a593Smuzhiyun #define CMD_NPE_STEP			0x01
45*4882a593Smuzhiyun #define CMD_NPE_START			0x02
46*4882a593Smuzhiyun #define CMD_NPE_STOP			0x03
47*4882a593Smuzhiyun #define CMD_NPE_CLR_PIPE		0x04
48*4882a593Smuzhiyun #define CMD_CLR_PROFILE_CNT		0x0C
49*4882a593Smuzhiyun #define CMD_RD_INS_MEM			0x10 /* instruction memory */
50*4882a593Smuzhiyun #define CMD_WR_INS_MEM			0x11
51*4882a593Smuzhiyun #define CMD_RD_DATA_MEM			0x12 /* data memory */
52*4882a593Smuzhiyun #define CMD_WR_DATA_MEM			0x13
53*4882a593Smuzhiyun #define CMD_RD_ECS_REG			0x14 /* exec access register */
54*4882a593Smuzhiyun #define CMD_WR_ECS_REG			0x15
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun #define STAT_RUN			0x80000000
57*4882a593Smuzhiyun #define STAT_STOP			0x40000000
58*4882a593Smuzhiyun #define STAT_CLEAR			0x20000000
59*4882a593Smuzhiyun #define STAT_ECS_K			0x00800000 /* pipeline clean */
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun #define NPE_STEVT			0x1B
62*4882a593Smuzhiyun #define NPE_STARTPC			0x1C
63*4882a593Smuzhiyun #define NPE_REGMAP			0x1E
64*4882a593Smuzhiyun #define NPE_CINDEX			0x1F
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun #define INSTR_WR_REG_SHORT		0x0000C000
67*4882a593Smuzhiyun #define INSTR_WR_REG_BYTE		0x00004000
68*4882a593Smuzhiyun #define INSTR_RD_FIFO			0x0F888220
69*4882a593Smuzhiyun #define INSTR_RESET_MBOX		0x0FAC8210
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun #define ECS_BG_CTXT_REG_0		0x00 /* Background Executing Context */
72*4882a593Smuzhiyun #define ECS_BG_CTXT_REG_1		0x01 /*		Stack level */
73*4882a593Smuzhiyun #define ECS_BG_CTXT_REG_2		0x02
74*4882a593Smuzhiyun #define ECS_PRI_1_CTXT_REG_0		0x04 /* Priority 1 Executing Context */
75*4882a593Smuzhiyun #define ECS_PRI_1_CTXT_REG_1		0x05 /*		Stack level */
76*4882a593Smuzhiyun #define ECS_PRI_1_CTXT_REG_2		0x06
77*4882a593Smuzhiyun #define ECS_PRI_2_CTXT_REG_0		0x08 /* Priority 2 Executing Context */
78*4882a593Smuzhiyun #define ECS_PRI_2_CTXT_REG_1		0x09 /*		Stack level */
79*4882a593Smuzhiyun #define ECS_PRI_2_CTXT_REG_2		0x0A
80*4882a593Smuzhiyun #define ECS_DBG_CTXT_REG_0		0x0C /* Debug Executing Context */
81*4882a593Smuzhiyun #define ECS_DBG_CTXT_REG_1		0x0D /*		Stack level */
82*4882a593Smuzhiyun #define ECS_DBG_CTXT_REG_2		0x0E
83*4882a593Smuzhiyun #define ECS_INSTRUCT_REG		0x11 /* NPE Instruction Register */
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun #define ECS_REG_0_ACTIVE		0x80000000 /* all levels */
86*4882a593Smuzhiyun #define ECS_REG_0_NEXTPC_MASK		0x1FFF0000 /* BG/PRI1/PRI2 levels */
87*4882a593Smuzhiyun #define ECS_REG_0_LDUR_BITS		8
88*4882a593Smuzhiyun #define ECS_REG_0_LDUR_MASK		0x00000700 /* all levels */
89*4882a593Smuzhiyun #define ECS_REG_1_CCTXT_BITS		16
90*4882a593Smuzhiyun #define ECS_REG_1_CCTXT_MASK		0x000F0000 /* all levels */
91*4882a593Smuzhiyun #define ECS_REG_1_SELCTXT_BITS		0
92*4882a593Smuzhiyun #define ECS_REG_1_SELCTXT_MASK		0x0000000F /* all levels */
93*4882a593Smuzhiyun #define ECS_DBG_REG_2_IF		0x00100000 /* debug level */
94*4882a593Smuzhiyun #define ECS_DBG_REG_2_IE		0x00080000 /* debug level */
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun /* NPE watchpoint_fifo register bit */
97*4882a593Smuzhiyun #define WFIFO_VALID			0x80000000
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun /* NPE messaging_status register bit definitions */
100*4882a593Smuzhiyun #define MSGSTAT_OFNE	0x00010000 /* OutFifoNotEmpty */
101*4882a593Smuzhiyun #define MSGSTAT_IFNF	0x00020000 /* InFifoNotFull */
102*4882a593Smuzhiyun #define MSGSTAT_OFNF	0x00040000 /* OutFifoNotFull */
103*4882a593Smuzhiyun #define MSGSTAT_IFNE	0x00080000 /* InFifoNotEmpty */
104*4882a593Smuzhiyun #define MSGSTAT_MBINT	0x00100000 /* Mailbox interrupt */
105*4882a593Smuzhiyun #define MSGSTAT_IFINT	0x00200000 /* InFifo interrupt */
106*4882a593Smuzhiyun #define MSGSTAT_OFINT	0x00400000 /* OutFifo interrupt */
107*4882a593Smuzhiyun #define MSGSTAT_WFINT	0x00800000 /* WatchFifo interrupt */
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun /* NPE messaging_control register bit definitions */
110*4882a593Smuzhiyun #define MSGCTL_OUT_FIFO			0x00010000 /* enable output FIFO */
111*4882a593Smuzhiyun #define MSGCTL_IN_FIFO			0x00020000 /* enable input FIFO */
112*4882a593Smuzhiyun #define MSGCTL_OUT_FIFO_WRITE		0x01000000 /* enable FIFO + WRITE */
113*4882a593Smuzhiyun #define MSGCTL_IN_FIFO_WRITE		0x02000000
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun /* NPE mailbox_status value for reset */
116*4882a593Smuzhiyun #define RESET_MBOX_STAT			0x0000F0F0
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun #define NPE_A_FIRMWARE "NPE-A"
119*4882a593Smuzhiyun #define NPE_B_FIRMWARE "NPE-B"
120*4882a593Smuzhiyun #define NPE_C_FIRMWARE "NPE-C"
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun const char *npe_names[] = { NPE_A_FIRMWARE, NPE_B_FIRMWARE, NPE_C_FIRMWARE };
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun #define print_npe(pri, npe, fmt, ...)					\
125*4882a593Smuzhiyun 	printk(pri "%s: " fmt, npe_name(npe), ## __VA_ARGS__)
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun #if DEBUG_MSG
128*4882a593Smuzhiyun #define debug_msg(npe, fmt, ...)					\
129*4882a593Smuzhiyun 	print_npe(KERN_DEBUG, npe, fmt, ## __VA_ARGS__)
130*4882a593Smuzhiyun #else
131*4882a593Smuzhiyun #define debug_msg(npe, fmt, ...)
132*4882a593Smuzhiyun #endif
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun static struct {
135*4882a593Smuzhiyun 	u32 reg, val;
136*4882a593Smuzhiyun } ecs_reset[] = {
137*4882a593Smuzhiyun 	{ ECS_BG_CTXT_REG_0,	0xA0000000 },
138*4882a593Smuzhiyun 	{ ECS_BG_CTXT_REG_1,	0x01000000 },
139*4882a593Smuzhiyun 	{ ECS_BG_CTXT_REG_2,	0x00008000 },
140*4882a593Smuzhiyun 	{ ECS_PRI_1_CTXT_REG_0,	0x20000080 },
141*4882a593Smuzhiyun 	{ ECS_PRI_1_CTXT_REG_1,	0x01000000 },
142*4882a593Smuzhiyun 	{ ECS_PRI_1_CTXT_REG_2,	0x00008000 },
143*4882a593Smuzhiyun 	{ ECS_PRI_2_CTXT_REG_0,	0x20000080 },
144*4882a593Smuzhiyun 	{ ECS_PRI_2_CTXT_REG_1,	0x01000000 },
145*4882a593Smuzhiyun 	{ ECS_PRI_2_CTXT_REG_2,	0x00008000 },
146*4882a593Smuzhiyun 	{ ECS_DBG_CTXT_REG_0,	0x20000000 },
147*4882a593Smuzhiyun 	{ ECS_DBG_CTXT_REG_1,	0x00000000 },
148*4882a593Smuzhiyun 	{ ECS_DBG_CTXT_REG_2,	0x001E0000 },
149*4882a593Smuzhiyun 	{ ECS_INSTRUCT_REG,	0x1003C00F },
150*4882a593Smuzhiyun };
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun static struct npe npe_tab[NPE_COUNT] = {
153*4882a593Smuzhiyun 	{
154*4882a593Smuzhiyun 		.id	= 0,
155*4882a593Smuzhiyun 	}, {
156*4882a593Smuzhiyun 		.id	= 1,
157*4882a593Smuzhiyun 	}, {
158*4882a593Smuzhiyun 		.id	= 2,
159*4882a593Smuzhiyun 	}
160*4882a593Smuzhiyun };
161*4882a593Smuzhiyun 
npe_running(struct npe * npe)162*4882a593Smuzhiyun int npe_running(struct npe *npe)
163*4882a593Smuzhiyun {
164*4882a593Smuzhiyun 	return (__raw_readl(&npe->regs->exec_status_cmd) & STAT_RUN) != 0;
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun 
npe_cmd_write(struct npe * npe,u32 addr,int cmd,u32 data)167*4882a593Smuzhiyun static void npe_cmd_write(struct npe *npe, u32 addr, int cmd, u32 data)
168*4882a593Smuzhiyun {
169*4882a593Smuzhiyun 	__raw_writel(data, &npe->regs->exec_data);
170*4882a593Smuzhiyun 	__raw_writel(addr, &npe->regs->exec_addr);
171*4882a593Smuzhiyun 	__raw_writel(cmd, &npe->regs->exec_status_cmd);
172*4882a593Smuzhiyun }
173*4882a593Smuzhiyun 
npe_cmd_read(struct npe * npe,u32 addr,int cmd)174*4882a593Smuzhiyun static u32 npe_cmd_read(struct npe *npe, u32 addr, int cmd)
175*4882a593Smuzhiyun {
176*4882a593Smuzhiyun 	__raw_writel(addr, &npe->regs->exec_addr);
177*4882a593Smuzhiyun 	__raw_writel(cmd, &npe->regs->exec_status_cmd);
178*4882a593Smuzhiyun 	/* Iintroduce extra read cycles after issuing read command to NPE
179*4882a593Smuzhiyun 	   so that we read the register after the NPE has updated it.
180*4882a593Smuzhiyun 	   This is to overcome race condition between XScale and NPE */
181*4882a593Smuzhiyun 	__raw_readl(&npe->regs->exec_data);
182*4882a593Smuzhiyun 	__raw_readl(&npe->regs->exec_data);
183*4882a593Smuzhiyun 	return __raw_readl(&npe->regs->exec_data);
184*4882a593Smuzhiyun }
185*4882a593Smuzhiyun 
npe_clear_active(struct npe * npe,u32 reg)186*4882a593Smuzhiyun static void npe_clear_active(struct npe *npe, u32 reg)
187*4882a593Smuzhiyun {
188*4882a593Smuzhiyun 	u32 val = npe_cmd_read(npe, reg, CMD_RD_ECS_REG);
189*4882a593Smuzhiyun 	npe_cmd_write(npe, reg, CMD_WR_ECS_REG, val & ~ECS_REG_0_ACTIVE);
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun 
npe_start(struct npe * npe)192*4882a593Smuzhiyun static void npe_start(struct npe *npe)
193*4882a593Smuzhiyun {
194*4882a593Smuzhiyun 	/* ensure only Background Context Stack Level is active */
195*4882a593Smuzhiyun 	npe_clear_active(npe, ECS_PRI_1_CTXT_REG_0);
196*4882a593Smuzhiyun 	npe_clear_active(npe, ECS_PRI_2_CTXT_REG_0);
197*4882a593Smuzhiyun 	npe_clear_active(npe, ECS_DBG_CTXT_REG_0);
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	__raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd);
200*4882a593Smuzhiyun 	__raw_writel(CMD_NPE_START, &npe->regs->exec_status_cmd);
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun 
npe_stop(struct npe * npe)203*4882a593Smuzhiyun static void npe_stop(struct npe *npe)
204*4882a593Smuzhiyun {
205*4882a593Smuzhiyun 	__raw_writel(CMD_NPE_STOP, &npe->regs->exec_status_cmd);
206*4882a593Smuzhiyun 	__raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd); /*FIXME?*/
207*4882a593Smuzhiyun }
208*4882a593Smuzhiyun 
npe_debug_instr(struct npe * npe,u32 instr,u32 ctx,u32 ldur)209*4882a593Smuzhiyun static int __must_check npe_debug_instr(struct npe *npe, u32 instr, u32 ctx,
210*4882a593Smuzhiyun 					u32 ldur)
211*4882a593Smuzhiyun {
212*4882a593Smuzhiyun 	u32 wc;
213*4882a593Smuzhiyun 	int i;
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	/* set the Active bit, and the LDUR, in the debug level */
216*4882a593Smuzhiyun 	npe_cmd_write(npe, ECS_DBG_CTXT_REG_0, CMD_WR_ECS_REG,
217*4882a593Smuzhiyun 		      ECS_REG_0_ACTIVE | (ldur << ECS_REG_0_LDUR_BITS));
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun 	/* set CCTXT at ECS DEBUG L3 to specify in which context to execute
220*4882a593Smuzhiyun 	   the instruction, and set SELCTXT at ECS DEBUG Level to specify
221*4882a593Smuzhiyun 	   which context store to access.
222*4882a593Smuzhiyun 	   Debug ECS Level Reg 1 has form 0x000n000n, where n = context number
223*4882a593Smuzhiyun 	*/
224*4882a593Smuzhiyun 	npe_cmd_write(npe, ECS_DBG_CTXT_REG_1, CMD_WR_ECS_REG,
225*4882a593Smuzhiyun 		      (ctx << ECS_REG_1_CCTXT_BITS) |
226*4882a593Smuzhiyun 		      (ctx << ECS_REG_1_SELCTXT_BITS));
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun 	/* clear the pipeline */
229*4882a593Smuzhiyun 	__raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd);
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 	/* load NPE instruction into the instruction register */
232*4882a593Smuzhiyun 	npe_cmd_write(npe, ECS_INSTRUCT_REG, CMD_WR_ECS_REG, instr);
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 	/* we need this value later to wait for completion of NPE execution
235*4882a593Smuzhiyun 	   step */
236*4882a593Smuzhiyun 	wc = __raw_readl(&npe->regs->watch_count);
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun 	/* issue a Step One command via the Execution Control register */
239*4882a593Smuzhiyun 	__raw_writel(CMD_NPE_STEP, &npe->regs->exec_status_cmd);
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 	/* Watch Count register increments when NPE completes an instruction */
242*4882a593Smuzhiyun 	for (i = 0; i < MAX_RETRIES; i++) {
243*4882a593Smuzhiyun 		if (wc != __raw_readl(&npe->regs->watch_count))
244*4882a593Smuzhiyun 			return 0;
245*4882a593Smuzhiyun 		udelay(1);
246*4882a593Smuzhiyun 	}
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 	print_npe(KERN_ERR, npe, "reset: npe_debug_instr(): timeout\n");
249*4882a593Smuzhiyun 	return -ETIMEDOUT;
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun 
npe_logical_reg_write8(struct npe * npe,u32 addr,u8 val,u32 ctx)252*4882a593Smuzhiyun static int __must_check npe_logical_reg_write8(struct npe *npe, u32 addr,
253*4882a593Smuzhiyun 					       u8 val, u32 ctx)
254*4882a593Smuzhiyun {
255*4882a593Smuzhiyun 	/* here we build the NPE assembler instruction: mov8 d0, #0 */
256*4882a593Smuzhiyun 	u32 instr = INSTR_WR_REG_BYTE |	/* OpCode */
257*4882a593Smuzhiyun 		addr << 9 |		/* base Operand */
258*4882a593Smuzhiyun 		(val & 0x1F) << 4 |	/* lower 5 bits to immediate data */
259*4882a593Smuzhiyun 		(val & ~0x1F) << (18 - 5);/* higher 3 bits to CoProc instr. */
260*4882a593Smuzhiyun 	return npe_debug_instr(npe, instr, ctx, 1); /* execute it */
261*4882a593Smuzhiyun }
262*4882a593Smuzhiyun 
npe_logical_reg_write16(struct npe * npe,u32 addr,u16 val,u32 ctx)263*4882a593Smuzhiyun static int __must_check npe_logical_reg_write16(struct npe *npe, u32 addr,
264*4882a593Smuzhiyun 						u16 val, u32 ctx)
265*4882a593Smuzhiyun {
266*4882a593Smuzhiyun 	/* here we build the NPE assembler instruction: mov16 d0, #0 */
267*4882a593Smuzhiyun 	u32 instr = INSTR_WR_REG_SHORT | /* OpCode */
268*4882a593Smuzhiyun 		addr << 9 |		/* base Operand */
269*4882a593Smuzhiyun 		(val & 0x1F) << 4 |	/* lower 5 bits to immediate data */
270*4882a593Smuzhiyun 		(val & ~0x1F) << (18 - 5);/* higher 11 bits to CoProc instr. */
271*4882a593Smuzhiyun 	return npe_debug_instr(npe, instr, ctx, 1); /* execute it */
272*4882a593Smuzhiyun }
273*4882a593Smuzhiyun 
npe_logical_reg_write32(struct npe * npe,u32 addr,u32 val,u32 ctx)274*4882a593Smuzhiyun static int __must_check npe_logical_reg_write32(struct npe *npe, u32 addr,
275*4882a593Smuzhiyun 						u32 val, u32 ctx)
276*4882a593Smuzhiyun {
277*4882a593Smuzhiyun 	/* write in 16 bit steps first the high and then the low value */
278*4882a593Smuzhiyun 	if (npe_logical_reg_write16(npe, addr, val >> 16, ctx))
279*4882a593Smuzhiyun 		return -ETIMEDOUT;
280*4882a593Smuzhiyun 	return npe_logical_reg_write16(npe, addr + 2, val & 0xFFFF, ctx);
281*4882a593Smuzhiyun }
282*4882a593Smuzhiyun 
npe_reset(struct npe * npe)283*4882a593Smuzhiyun static int npe_reset(struct npe *npe)
284*4882a593Smuzhiyun {
285*4882a593Smuzhiyun 	u32 val, ctl, exec_count, ctx_reg2;
286*4882a593Smuzhiyun 	int i;
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 	ctl = (__raw_readl(&npe->regs->messaging_control) | 0x3F000000) &
289*4882a593Smuzhiyun 		0x3F3FFFFF;
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 	/* disable parity interrupt */
292*4882a593Smuzhiyun 	__raw_writel(ctl & 0x3F00FFFF, &npe->regs->messaging_control);
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 	/* pre exec - debug instruction */
295*4882a593Smuzhiyun 	/* turn off the halt bit by clearing Execution Count register. */
296*4882a593Smuzhiyun 	exec_count = __raw_readl(&npe->regs->exec_count);
297*4882a593Smuzhiyun 	__raw_writel(0, &npe->regs->exec_count);
298*4882a593Smuzhiyun 	/* ensure that IF and IE are on (temporarily), so that we don't end up
299*4882a593Smuzhiyun 	   stepping forever */
300*4882a593Smuzhiyun 	ctx_reg2 = npe_cmd_read(npe, ECS_DBG_CTXT_REG_2, CMD_RD_ECS_REG);
301*4882a593Smuzhiyun 	npe_cmd_write(npe, ECS_DBG_CTXT_REG_2, CMD_WR_ECS_REG, ctx_reg2 |
302*4882a593Smuzhiyun 		      ECS_DBG_REG_2_IF | ECS_DBG_REG_2_IE);
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 	/* clear the FIFOs */
305*4882a593Smuzhiyun 	while (__raw_readl(&npe->regs->watchpoint_fifo) & WFIFO_VALID)
306*4882a593Smuzhiyun 		;
307*4882a593Smuzhiyun 	while (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_OFNE)
308*4882a593Smuzhiyun 		/* read from the outFIFO until empty */
309*4882a593Smuzhiyun 		print_npe(KERN_DEBUG, npe, "npe_reset: read FIFO = 0x%X\n",
310*4882a593Smuzhiyun 			  __raw_readl(&npe->regs->in_out_fifo));
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun 	while (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNE)
313*4882a593Smuzhiyun 		/* step execution of the NPE intruction to read inFIFO using
314*4882a593Smuzhiyun 		   the Debug Executing Context stack */
315*4882a593Smuzhiyun 		if (npe_debug_instr(npe, INSTR_RD_FIFO, 0, 0))
316*4882a593Smuzhiyun 			return -ETIMEDOUT;
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun 	/* reset the mailbox reg from the XScale side */
319*4882a593Smuzhiyun 	__raw_writel(RESET_MBOX_STAT, &npe->regs->mailbox_status);
320*4882a593Smuzhiyun 	/* from NPE side */
321*4882a593Smuzhiyun 	if (npe_debug_instr(npe, INSTR_RESET_MBOX, 0, 0))
322*4882a593Smuzhiyun 		return -ETIMEDOUT;
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun 	/* Reset the physical registers in the NPE register file */
325*4882a593Smuzhiyun 	for (val = 0; val < NPE_PHYS_REG; val++) {
326*4882a593Smuzhiyun 		if (npe_logical_reg_write16(npe, NPE_REGMAP, val >> 1, 0))
327*4882a593Smuzhiyun 			return -ETIMEDOUT;
328*4882a593Smuzhiyun 		/* address is either 0 or 4 */
329*4882a593Smuzhiyun 		if (npe_logical_reg_write32(npe, (val & 1) * 4, 0, 0))
330*4882a593Smuzhiyun 			return -ETIMEDOUT;
331*4882a593Smuzhiyun 	}
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun 	/* Reset the context store = each context's Context Store registers */
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	/* Context 0 has no STARTPC. Instead, this value is used to set NextPC
336*4882a593Smuzhiyun 	   for Background ECS, to set where NPE starts executing code */
337*4882a593Smuzhiyun 	val = npe_cmd_read(npe, ECS_BG_CTXT_REG_0, CMD_RD_ECS_REG);
338*4882a593Smuzhiyun 	val &= ~ECS_REG_0_NEXTPC_MASK;
339*4882a593Smuzhiyun 	val |= (0 /* NextPC */ << 16) & ECS_REG_0_NEXTPC_MASK;
340*4882a593Smuzhiyun 	npe_cmd_write(npe, ECS_BG_CTXT_REG_0, CMD_WR_ECS_REG, val);
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun 	for (i = 0; i < 16; i++) {
343*4882a593Smuzhiyun 		if (i) {	/* Context 0 has no STEVT nor STARTPC */
344*4882a593Smuzhiyun 			/* STEVT = off, 0x80 */
345*4882a593Smuzhiyun 			if (npe_logical_reg_write8(npe, NPE_STEVT, 0x80, i))
346*4882a593Smuzhiyun 				return -ETIMEDOUT;
347*4882a593Smuzhiyun 			if (npe_logical_reg_write16(npe, NPE_STARTPC, 0, i))
348*4882a593Smuzhiyun 				return -ETIMEDOUT;
349*4882a593Smuzhiyun 		}
350*4882a593Smuzhiyun 		/* REGMAP = d0->p0, d8->p2, d16->p4 */
351*4882a593Smuzhiyun 		if (npe_logical_reg_write16(npe, NPE_REGMAP, 0x820, i))
352*4882a593Smuzhiyun 			return -ETIMEDOUT;
353*4882a593Smuzhiyun 		if (npe_logical_reg_write8(npe, NPE_CINDEX, 0, i))
354*4882a593Smuzhiyun 			return -ETIMEDOUT;
355*4882a593Smuzhiyun 	}
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun 	/* post exec */
358*4882a593Smuzhiyun 	/* clear active bit in debug level */
359*4882a593Smuzhiyun 	npe_cmd_write(npe, ECS_DBG_CTXT_REG_0, CMD_WR_ECS_REG, 0);
360*4882a593Smuzhiyun 	/* clear the pipeline */
361*4882a593Smuzhiyun 	__raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd);
362*4882a593Smuzhiyun 	/* restore previous values */
363*4882a593Smuzhiyun 	__raw_writel(exec_count, &npe->regs->exec_count);
364*4882a593Smuzhiyun 	npe_cmd_write(npe, ECS_DBG_CTXT_REG_2, CMD_WR_ECS_REG, ctx_reg2);
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 	/* write reset values to Execution Context Stack registers */
367*4882a593Smuzhiyun 	for (val = 0; val < ARRAY_SIZE(ecs_reset); val++)
368*4882a593Smuzhiyun 		npe_cmd_write(npe, ecs_reset[val].reg, CMD_WR_ECS_REG,
369*4882a593Smuzhiyun 			      ecs_reset[val].val);
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun 	/* clear the profile counter */
372*4882a593Smuzhiyun 	__raw_writel(CMD_CLR_PROFILE_CNT, &npe->regs->exec_status_cmd);
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun 	__raw_writel(0, &npe->regs->exec_count);
375*4882a593Smuzhiyun 	__raw_writel(0, &npe->regs->action_points[0]);
376*4882a593Smuzhiyun 	__raw_writel(0, &npe->regs->action_points[1]);
377*4882a593Smuzhiyun 	__raw_writel(0, &npe->regs->action_points[2]);
378*4882a593Smuzhiyun 	__raw_writel(0, &npe->regs->action_points[3]);
379*4882a593Smuzhiyun 	__raw_writel(0, &npe->regs->watch_count);
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 	val = ixp4xx_read_feature_bits();
382*4882a593Smuzhiyun 	/* reset the NPE */
383*4882a593Smuzhiyun 	ixp4xx_write_feature_bits(val &
384*4882a593Smuzhiyun 				  ~(IXP4XX_FEATURE_RESET_NPEA << npe->id));
385*4882a593Smuzhiyun 	/* deassert reset */
386*4882a593Smuzhiyun 	ixp4xx_write_feature_bits(val |
387*4882a593Smuzhiyun 				  (IXP4XX_FEATURE_RESET_NPEA << npe->id));
388*4882a593Smuzhiyun 	for (i = 0; i < MAX_RETRIES; i++) {
389*4882a593Smuzhiyun 		if (ixp4xx_read_feature_bits() &
390*4882a593Smuzhiyun 		    (IXP4XX_FEATURE_RESET_NPEA << npe->id))
391*4882a593Smuzhiyun 			break;	/* NPE is back alive */
392*4882a593Smuzhiyun 		udelay(1);
393*4882a593Smuzhiyun 	}
394*4882a593Smuzhiyun 	if (i == MAX_RETRIES)
395*4882a593Smuzhiyun 		return -ETIMEDOUT;
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun 	npe_stop(npe);
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun 	/* restore NPE configuration bus Control Register - parity settings */
400*4882a593Smuzhiyun 	__raw_writel(ctl, &npe->regs->messaging_control);
401*4882a593Smuzhiyun 	return 0;
402*4882a593Smuzhiyun }
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 
npe_send_message(struct npe * npe,const void * msg,const char * what)405*4882a593Smuzhiyun int npe_send_message(struct npe *npe, const void *msg, const char *what)
406*4882a593Smuzhiyun {
407*4882a593Smuzhiyun 	const u32 *send = msg;
408*4882a593Smuzhiyun 	int cycles = 0;
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun 	debug_msg(npe, "Trying to send message %s [%08X:%08X]\n",
411*4882a593Smuzhiyun 		  what, send[0], send[1]);
412*4882a593Smuzhiyun 
413*4882a593Smuzhiyun 	if (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNE) {
414*4882a593Smuzhiyun 		debug_msg(npe, "NPE input FIFO not empty\n");
415*4882a593Smuzhiyun 		return -EIO;
416*4882a593Smuzhiyun 	}
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun 	__raw_writel(send[0], &npe->regs->in_out_fifo);
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun 	if (!(__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNF)) {
421*4882a593Smuzhiyun 		debug_msg(npe, "NPE input FIFO full\n");
422*4882a593Smuzhiyun 		return -EIO;
423*4882a593Smuzhiyun 	}
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun 	__raw_writel(send[1], &npe->regs->in_out_fifo);
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun 	while ((cycles < MAX_RETRIES) &&
428*4882a593Smuzhiyun 	       (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNE)) {
429*4882a593Smuzhiyun 		udelay(1);
430*4882a593Smuzhiyun 		cycles++;
431*4882a593Smuzhiyun 	}
432*4882a593Smuzhiyun 
433*4882a593Smuzhiyun 	if (cycles == MAX_RETRIES) {
434*4882a593Smuzhiyun 		debug_msg(npe, "Timeout sending message\n");
435*4882a593Smuzhiyun 		return -ETIMEDOUT;
436*4882a593Smuzhiyun 	}
437*4882a593Smuzhiyun 
438*4882a593Smuzhiyun #if DEBUG_MSG > 1
439*4882a593Smuzhiyun 	debug_msg(npe, "Sending a message took %i cycles\n", cycles);
440*4882a593Smuzhiyun #endif
441*4882a593Smuzhiyun 	return 0;
442*4882a593Smuzhiyun }
443*4882a593Smuzhiyun 
npe_recv_message(struct npe * npe,void * msg,const char * what)444*4882a593Smuzhiyun int npe_recv_message(struct npe *npe, void *msg, const char *what)
445*4882a593Smuzhiyun {
446*4882a593Smuzhiyun 	u32 *recv = msg;
447*4882a593Smuzhiyun 	int cycles = 0, cnt = 0;
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun 	debug_msg(npe, "Trying to receive message %s\n", what);
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 	while (cycles < MAX_RETRIES) {
452*4882a593Smuzhiyun 		if (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_OFNE) {
453*4882a593Smuzhiyun 			recv[cnt++] = __raw_readl(&npe->regs->in_out_fifo);
454*4882a593Smuzhiyun 			if (cnt == 2)
455*4882a593Smuzhiyun 				break;
456*4882a593Smuzhiyun 		} else {
457*4882a593Smuzhiyun 			udelay(1);
458*4882a593Smuzhiyun 			cycles++;
459*4882a593Smuzhiyun 		}
460*4882a593Smuzhiyun 	}
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun 	switch(cnt) {
463*4882a593Smuzhiyun 	case 1:
464*4882a593Smuzhiyun 		debug_msg(npe, "Received [%08X]\n", recv[0]);
465*4882a593Smuzhiyun 		break;
466*4882a593Smuzhiyun 	case 2:
467*4882a593Smuzhiyun 		debug_msg(npe, "Received [%08X:%08X]\n", recv[0], recv[1]);
468*4882a593Smuzhiyun 		break;
469*4882a593Smuzhiyun 	}
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun 	if (cycles == MAX_RETRIES) {
472*4882a593Smuzhiyun 		debug_msg(npe, "Timeout waiting for message\n");
473*4882a593Smuzhiyun 		return -ETIMEDOUT;
474*4882a593Smuzhiyun 	}
475*4882a593Smuzhiyun 
476*4882a593Smuzhiyun #if DEBUG_MSG > 1
477*4882a593Smuzhiyun 	debug_msg(npe, "Receiving a message took %i cycles\n", cycles);
478*4882a593Smuzhiyun #endif
479*4882a593Smuzhiyun 	return 0;
480*4882a593Smuzhiyun }
481*4882a593Smuzhiyun 
npe_send_recv_message(struct npe * npe,void * msg,const char * what)482*4882a593Smuzhiyun int npe_send_recv_message(struct npe *npe, void *msg, const char *what)
483*4882a593Smuzhiyun {
484*4882a593Smuzhiyun 	int result;
485*4882a593Smuzhiyun 	u32 *send = msg, recv[2];
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun 	if ((result = npe_send_message(npe, msg, what)) != 0)
488*4882a593Smuzhiyun 		return result;
489*4882a593Smuzhiyun 	if ((result = npe_recv_message(npe, recv, what)) != 0)
490*4882a593Smuzhiyun 		return result;
491*4882a593Smuzhiyun 
492*4882a593Smuzhiyun 	if ((recv[0] != send[0]) || (recv[1] != send[1])) {
493*4882a593Smuzhiyun 		debug_msg(npe, "Message %s: unexpected message received\n",
494*4882a593Smuzhiyun 			  what);
495*4882a593Smuzhiyun 		return -EIO;
496*4882a593Smuzhiyun 	}
497*4882a593Smuzhiyun 	return 0;
498*4882a593Smuzhiyun }
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun 
npe_load_firmware(struct npe * npe,const char * name,struct device * dev)501*4882a593Smuzhiyun int npe_load_firmware(struct npe *npe, const char *name, struct device *dev)
502*4882a593Smuzhiyun {
503*4882a593Smuzhiyun 	const struct firmware *fw_entry;
504*4882a593Smuzhiyun 
505*4882a593Smuzhiyun 	struct dl_block {
506*4882a593Smuzhiyun 		u32 type;
507*4882a593Smuzhiyun 		u32 offset;
508*4882a593Smuzhiyun 	} *blk;
509*4882a593Smuzhiyun 
510*4882a593Smuzhiyun 	struct dl_image {
511*4882a593Smuzhiyun 		u32 magic;
512*4882a593Smuzhiyun 		u32 id;
513*4882a593Smuzhiyun 		u32 size;
514*4882a593Smuzhiyun 		union {
515*4882a593Smuzhiyun 			u32 data[0];
516*4882a593Smuzhiyun 			struct dl_block blocks[0];
517*4882a593Smuzhiyun 		};
518*4882a593Smuzhiyun 	} *image;
519*4882a593Smuzhiyun 
520*4882a593Smuzhiyun 	struct dl_codeblock {
521*4882a593Smuzhiyun 		u32 npe_addr;
522*4882a593Smuzhiyun 		u32 size;
523*4882a593Smuzhiyun 		u32 data[0];
524*4882a593Smuzhiyun 	} *cb;
525*4882a593Smuzhiyun 
526*4882a593Smuzhiyun 	int i, j, err, data_size, instr_size, blocks, table_end;
527*4882a593Smuzhiyun 	u32 cmd;
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun 	if ((err = request_firmware(&fw_entry, name, dev)) != 0)
530*4882a593Smuzhiyun 		return err;
531*4882a593Smuzhiyun 
532*4882a593Smuzhiyun 	err = -EINVAL;
533*4882a593Smuzhiyun 	if (fw_entry->size < sizeof(struct dl_image)) {
534*4882a593Smuzhiyun 		print_npe(KERN_ERR, npe, "incomplete firmware file\n");
535*4882a593Smuzhiyun 		goto err;
536*4882a593Smuzhiyun 	}
537*4882a593Smuzhiyun 	image = (struct dl_image*)fw_entry->data;
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun #if DEBUG_FW
540*4882a593Smuzhiyun 	print_npe(KERN_DEBUG, npe, "firmware: %08X %08X %08X (0x%X bytes)\n",
541*4882a593Smuzhiyun 		  image->magic, image->id, image->size, image->size * 4);
542*4882a593Smuzhiyun #endif
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun 	if (image->magic == swab32(FW_MAGIC)) { /* swapped file */
545*4882a593Smuzhiyun 		image->id = swab32(image->id);
546*4882a593Smuzhiyun 		image->size = swab32(image->size);
547*4882a593Smuzhiyun 	} else if (image->magic != FW_MAGIC) {
548*4882a593Smuzhiyun 		print_npe(KERN_ERR, npe, "bad firmware file magic: 0x%X\n",
549*4882a593Smuzhiyun 			  image->magic);
550*4882a593Smuzhiyun 		goto err;
551*4882a593Smuzhiyun 	}
552*4882a593Smuzhiyun 	if ((image->size * 4 + sizeof(struct dl_image)) != fw_entry->size) {
553*4882a593Smuzhiyun 		print_npe(KERN_ERR, npe,
554*4882a593Smuzhiyun 			  "inconsistent size of firmware file\n");
555*4882a593Smuzhiyun 		goto err;
556*4882a593Smuzhiyun 	}
557*4882a593Smuzhiyun 	if (((image->id >> 24) & 0xF /* NPE ID */) != npe->id) {
558*4882a593Smuzhiyun 		print_npe(KERN_ERR, npe, "firmware file NPE ID mismatch\n");
559*4882a593Smuzhiyun 		goto err;
560*4882a593Smuzhiyun 	}
561*4882a593Smuzhiyun 	if (image->magic == swab32(FW_MAGIC))
562*4882a593Smuzhiyun 		for (i = 0; i < image->size; i++)
563*4882a593Smuzhiyun 			image->data[i] = swab32(image->data[i]);
564*4882a593Smuzhiyun 
565*4882a593Smuzhiyun 	if (cpu_is_ixp42x() && ((image->id >> 28) & 0xF /* device ID */)) {
566*4882a593Smuzhiyun 		print_npe(KERN_INFO, npe, "IXP43x/IXP46x firmware ignored on "
567*4882a593Smuzhiyun 			  "IXP42x\n");
568*4882a593Smuzhiyun 		goto err;
569*4882a593Smuzhiyun 	}
570*4882a593Smuzhiyun 
571*4882a593Smuzhiyun 	if (npe_running(npe)) {
572*4882a593Smuzhiyun 		print_npe(KERN_INFO, npe, "unable to load firmware, NPE is "
573*4882a593Smuzhiyun 			  "already running\n");
574*4882a593Smuzhiyun 		err = -EBUSY;
575*4882a593Smuzhiyun 		goto err;
576*4882a593Smuzhiyun 	}
577*4882a593Smuzhiyun #if 0
578*4882a593Smuzhiyun 	npe_stop(npe);
579*4882a593Smuzhiyun 	npe_reset(npe);
580*4882a593Smuzhiyun #endif
581*4882a593Smuzhiyun 
582*4882a593Smuzhiyun 	print_npe(KERN_INFO, npe, "firmware functionality 0x%X, "
583*4882a593Smuzhiyun 		  "revision 0x%X:%X\n", (image->id >> 16) & 0xFF,
584*4882a593Smuzhiyun 		  (image->id >> 8) & 0xFF, image->id & 0xFF);
585*4882a593Smuzhiyun 
586*4882a593Smuzhiyun 	if (cpu_is_ixp42x()) {
587*4882a593Smuzhiyun 		if (!npe->id)
588*4882a593Smuzhiyun 			instr_size = NPE_A_42X_INSTR_SIZE;
589*4882a593Smuzhiyun 		else
590*4882a593Smuzhiyun 			instr_size = NPE_B_AND_C_42X_INSTR_SIZE;
591*4882a593Smuzhiyun 		data_size = NPE_42X_DATA_SIZE;
592*4882a593Smuzhiyun 	} else {
593*4882a593Smuzhiyun 		instr_size = NPE_46X_INSTR_SIZE;
594*4882a593Smuzhiyun 		data_size = NPE_46X_DATA_SIZE;
595*4882a593Smuzhiyun 	}
596*4882a593Smuzhiyun 
597*4882a593Smuzhiyun 	for (blocks = 0; blocks * sizeof(struct dl_block) / 4 < image->size;
598*4882a593Smuzhiyun 	     blocks++)
599*4882a593Smuzhiyun 		if (image->blocks[blocks].type == FW_BLOCK_TYPE_EOF)
600*4882a593Smuzhiyun 			break;
601*4882a593Smuzhiyun 	if (blocks * sizeof(struct dl_block) / 4 >= image->size) {
602*4882a593Smuzhiyun 		print_npe(KERN_INFO, npe, "firmware EOF block marker not "
603*4882a593Smuzhiyun 			  "found\n");
604*4882a593Smuzhiyun 		goto err;
605*4882a593Smuzhiyun 	}
606*4882a593Smuzhiyun 
607*4882a593Smuzhiyun #if DEBUG_FW
608*4882a593Smuzhiyun 	print_npe(KERN_DEBUG, npe, "%i firmware blocks found\n", blocks);
609*4882a593Smuzhiyun #endif
610*4882a593Smuzhiyun 
611*4882a593Smuzhiyun 	table_end = blocks * sizeof(struct dl_block) / 4 + 1 /* EOF marker */;
612*4882a593Smuzhiyun 	for (i = 0, blk = image->blocks; i < blocks; i++, blk++) {
613*4882a593Smuzhiyun 		if (blk->offset > image->size - sizeof(struct dl_codeblock) / 4
614*4882a593Smuzhiyun 		    || blk->offset < table_end) {
615*4882a593Smuzhiyun 			print_npe(KERN_INFO, npe, "invalid offset 0x%X of "
616*4882a593Smuzhiyun 				  "firmware block #%i\n", blk->offset, i);
617*4882a593Smuzhiyun 			goto err;
618*4882a593Smuzhiyun 		}
619*4882a593Smuzhiyun 
620*4882a593Smuzhiyun 		cb = (struct dl_codeblock*)&image->data[blk->offset];
621*4882a593Smuzhiyun 		if (blk->type == FW_BLOCK_TYPE_INSTR) {
622*4882a593Smuzhiyun 			if (cb->npe_addr + cb->size > instr_size)
623*4882a593Smuzhiyun 				goto too_big;
624*4882a593Smuzhiyun 			cmd = CMD_WR_INS_MEM;
625*4882a593Smuzhiyun 		} else if (blk->type == FW_BLOCK_TYPE_DATA) {
626*4882a593Smuzhiyun 			if (cb->npe_addr + cb->size > data_size)
627*4882a593Smuzhiyun 				goto too_big;
628*4882a593Smuzhiyun 			cmd = CMD_WR_DATA_MEM;
629*4882a593Smuzhiyun 		} else {
630*4882a593Smuzhiyun 			print_npe(KERN_INFO, npe, "invalid firmware block #%i "
631*4882a593Smuzhiyun 				  "type 0x%X\n", i, blk->type);
632*4882a593Smuzhiyun 			goto err;
633*4882a593Smuzhiyun 		}
634*4882a593Smuzhiyun 		if (blk->offset + sizeof(*cb) / 4 + cb->size > image->size) {
635*4882a593Smuzhiyun 			print_npe(KERN_INFO, npe, "firmware block #%i doesn't "
636*4882a593Smuzhiyun 				  "fit in firmware image: type %c, start 0x%X,"
637*4882a593Smuzhiyun 				  " length 0x%X\n", i,
638*4882a593Smuzhiyun 				  blk->type == FW_BLOCK_TYPE_INSTR ? 'I' : 'D',
639*4882a593Smuzhiyun 				  cb->npe_addr, cb->size);
640*4882a593Smuzhiyun 			goto err;
641*4882a593Smuzhiyun 		}
642*4882a593Smuzhiyun 
643*4882a593Smuzhiyun 		for (j = 0; j < cb->size; j++)
644*4882a593Smuzhiyun 			npe_cmd_write(npe, cb->npe_addr + j, cmd, cb->data[j]);
645*4882a593Smuzhiyun 	}
646*4882a593Smuzhiyun 
647*4882a593Smuzhiyun 	npe_start(npe);
648*4882a593Smuzhiyun 	if (!npe_running(npe))
649*4882a593Smuzhiyun 		print_npe(KERN_ERR, npe, "unable to start\n");
650*4882a593Smuzhiyun 	release_firmware(fw_entry);
651*4882a593Smuzhiyun 	return 0;
652*4882a593Smuzhiyun 
653*4882a593Smuzhiyun too_big:
654*4882a593Smuzhiyun 	print_npe(KERN_INFO, npe, "firmware block #%i doesn't fit in NPE "
655*4882a593Smuzhiyun 		  "memory: type %c, start 0x%X, length 0x%X\n", i,
656*4882a593Smuzhiyun 		  blk->type == FW_BLOCK_TYPE_INSTR ? 'I' : 'D',
657*4882a593Smuzhiyun 		  cb->npe_addr, cb->size);
658*4882a593Smuzhiyun err:
659*4882a593Smuzhiyun 	release_firmware(fw_entry);
660*4882a593Smuzhiyun 	return err;
661*4882a593Smuzhiyun }
662*4882a593Smuzhiyun 
663*4882a593Smuzhiyun 
npe_request(unsigned id)664*4882a593Smuzhiyun struct npe *npe_request(unsigned id)
665*4882a593Smuzhiyun {
666*4882a593Smuzhiyun 	if (id < NPE_COUNT)
667*4882a593Smuzhiyun 		if (npe_tab[id].valid)
668*4882a593Smuzhiyun 			if (try_module_get(THIS_MODULE))
669*4882a593Smuzhiyun 				return &npe_tab[id];
670*4882a593Smuzhiyun 	return NULL;
671*4882a593Smuzhiyun }
672*4882a593Smuzhiyun 
npe_release(struct npe * npe)673*4882a593Smuzhiyun void npe_release(struct npe *npe)
674*4882a593Smuzhiyun {
675*4882a593Smuzhiyun 	module_put(THIS_MODULE);
676*4882a593Smuzhiyun }
677*4882a593Smuzhiyun 
ixp4xx_npe_probe(struct platform_device * pdev)678*4882a593Smuzhiyun static int ixp4xx_npe_probe(struct platform_device *pdev)
679*4882a593Smuzhiyun {
680*4882a593Smuzhiyun 	int i, found = 0;
681*4882a593Smuzhiyun 	struct device *dev = &pdev->dev;
682*4882a593Smuzhiyun 	struct resource *res;
683*4882a593Smuzhiyun 
684*4882a593Smuzhiyun 	for (i = 0; i < NPE_COUNT; i++) {
685*4882a593Smuzhiyun 		struct npe *npe = &npe_tab[i];
686*4882a593Smuzhiyun 
687*4882a593Smuzhiyun 		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
688*4882a593Smuzhiyun 		if (!res)
689*4882a593Smuzhiyun 			return -ENODEV;
690*4882a593Smuzhiyun 
691*4882a593Smuzhiyun 		if (!(ixp4xx_read_feature_bits() &
692*4882a593Smuzhiyun 		      (IXP4XX_FEATURE_RESET_NPEA << i))) {
693*4882a593Smuzhiyun 			dev_info(dev, "NPE%d at %pR not available\n",
694*4882a593Smuzhiyun 				 i, res);
695*4882a593Smuzhiyun 			continue; /* NPE already disabled or not present */
696*4882a593Smuzhiyun 		}
697*4882a593Smuzhiyun 		npe->regs = devm_ioremap_resource(dev, res);
698*4882a593Smuzhiyun 		if (IS_ERR(npe->regs))
699*4882a593Smuzhiyun 			return PTR_ERR(npe->regs);
700*4882a593Smuzhiyun 
701*4882a593Smuzhiyun 		if (npe_reset(npe)) {
702*4882a593Smuzhiyun 			dev_info(dev, "NPE%d at %pR does not reset\n",
703*4882a593Smuzhiyun 				 i, res);
704*4882a593Smuzhiyun 			continue;
705*4882a593Smuzhiyun 		}
706*4882a593Smuzhiyun 		npe->valid = 1;
707*4882a593Smuzhiyun 		dev_info(dev, "NPE%d at %pR registered\n", i, res);
708*4882a593Smuzhiyun 		found++;
709*4882a593Smuzhiyun 	}
710*4882a593Smuzhiyun 
711*4882a593Smuzhiyun 	if (!found)
712*4882a593Smuzhiyun 		return -ENODEV;
713*4882a593Smuzhiyun 	return 0;
714*4882a593Smuzhiyun }
715*4882a593Smuzhiyun 
ixp4xx_npe_remove(struct platform_device * pdev)716*4882a593Smuzhiyun static int ixp4xx_npe_remove(struct platform_device *pdev)
717*4882a593Smuzhiyun {
718*4882a593Smuzhiyun 	int i;
719*4882a593Smuzhiyun 
720*4882a593Smuzhiyun 	for (i = 0; i < NPE_COUNT; i++)
721*4882a593Smuzhiyun 		if (npe_tab[i].regs) {
722*4882a593Smuzhiyun 			npe_reset(&npe_tab[i]);
723*4882a593Smuzhiyun 		}
724*4882a593Smuzhiyun 
725*4882a593Smuzhiyun 	return 0;
726*4882a593Smuzhiyun }
727*4882a593Smuzhiyun 
728*4882a593Smuzhiyun static const struct of_device_id ixp4xx_npe_of_match[] = {
729*4882a593Smuzhiyun 	{
730*4882a593Smuzhiyun 		.compatible = "intel,ixp4xx-network-processing-engine",
731*4882a593Smuzhiyun         },
732*4882a593Smuzhiyun 	{},
733*4882a593Smuzhiyun };
734*4882a593Smuzhiyun 
735*4882a593Smuzhiyun static struct platform_driver ixp4xx_npe_driver = {
736*4882a593Smuzhiyun 	.driver = {
737*4882a593Smuzhiyun 		.name           = "ixp4xx-npe",
738*4882a593Smuzhiyun 		.of_match_table = ixp4xx_npe_of_match,
739*4882a593Smuzhiyun 	},
740*4882a593Smuzhiyun 	.probe = ixp4xx_npe_probe,
741*4882a593Smuzhiyun 	.remove = ixp4xx_npe_remove,
742*4882a593Smuzhiyun };
743*4882a593Smuzhiyun module_platform_driver(ixp4xx_npe_driver);
744*4882a593Smuzhiyun 
745*4882a593Smuzhiyun MODULE_AUTHOR("Krzysztof Halasa");
746*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
747*4882a593Smuzhiyun MODULE_FIRMWARE(NPE_A_FIRMWARE);
748*4882a593Smuzhiyun MODULE_FIRMWARE(NPE_B_FIRMWARE);
749*4882a593Smuzhiyun MODULE_FIRMWARE(NPE_C_FIRMWARE);
750*4882a593Smuzhiyun 
751*4882a593Smuzhiyun EXPORT_SYMBOL(npe_names);
752*4882a593Smuzhiyun EXPORT_SYMBOL(npe_running);
753*4882a593Smuzhiyun EXPORT_SYMBOL(npe_request);
754*4882a593Smuzhiyun EXPORT_SYMBOL(npe_release);
755*4882a593Smuzhiyun EXPORT_SYMBOL(npe_load_firmware);
756*4882a593Smuzhiyun EXPORT_SYMBOL(npe_send_message);
757*4882a593Smuzhiyun EXPORT_SYMBOL(npe_recv_message);
758*4882a593Smuzhiyun EXPORT_SYMBOL(npe_send_recv_message);
759