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