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