ixp425_npe.c revision 186420
1255570Strasz/*-
2255570Strasz * Copyright (c) 2006-2008 Sam Leffler, Errno Consulting
3255570Strasz * All rights reserved.
4255570Strasz *
5255570Strasz * Redistribution and use in source and binary forms, with or without
6255570Strasz * modification, are permitted provided that the following conditions
7255570Strasz * are met:
8255570Strasz * 1. Redistributions of source code must retain the above copyright
9255570Strasz *    notice, this list of conditions and the following disclaimer,
10255570Strasz *    without modification.
11255570Strasz * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12255570Strasz *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13255570Strasz *    redistribution must be conditioned upon including a substantially
14255570Strasz *    similar Disclaimer requirement for further binary redistribution.
15255570Strasz *
16255570Strasz * NO WARRANTY
17255570Strasz * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18255570Strasz * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19255570Strasz * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20255570Strasz * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21255570Strasz * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22255570Strasz * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23255570Strasz * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24255570Strasz * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25255570Strasz * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26255570Strasz * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27255570Strasz * THE POSSIBILITY OF SUCH DAMAGES.
28255570Strasz */
29255570Strasz
30255570Strasz/*-
31255570Strasz * Copyright (c) 2001-2005, Intel Corporation.
32255570Strasz * All rights reserved.
33255570Strasz *
34255570Strasz * Redistribution and use in source and binary forms, with or without
35255570Strasz * modification, are permitted provided that the following conditions
36255570Strasz * are met:
37255570Strasz * 1. Redistributions of source code must retain the above copyright
38255570Strasz *    notice, this list of conditions and the following disclaimer.
39255570Strasz * 2. Redistributions in binary form must reproduce the above copyright
40255570Strasz *    notice, this list of conditions and the following disclaimer in the
41255570Strasz *    documentation and/or other materials provided with the distribution.
42255570Strasz * 3. Neither the name of the Intel Corporation nor the names of its contributors
43255570Strasz *    may be used to endorse or promote products derived from this software
44255570Strasz *    without specific prior written permission.
45255570Strasz *
46255570Strasz *
47255570Strasz * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
48255570Strasz * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49255570Strasz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50255570Strasz * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
51255570Strasz * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52255570Strasz * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53255570Strasz * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54255570Strasz * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55255570Strasz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56255570Strasz * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57255570Strasz * SUCH DAMAGE.
58255570Strasz*/
59255570Strasz#include <sys/cdefs.h>
60263724Strasz__FBSDID("$FreeBSD: head/sys/arm/xscale/ixp425/ixp425_npe.c 186420 2008-12-23 04:51:46Z sam $");
61275244Strasz
62275247Strasz/*
63275247Strasz * Intel XScale Network Processing Engine (NPE) support.
64275642Strasz *
65275642Strasz * Each NPE has an ixpnpeX device associated with it that is
66255570Strasz * attached at boot.  Depending on the microcode loaded into
67255570Strasz * an NPE there may be an Ethernet interface (npeX) or some
68255570Strasz * other network interface (e.g. for ATM).  This file has support
69255570Strasz * for loading microcode images and the associated NPE CPU
70255570Strasz * manipulations (start, stop, reset).
71255570Strasz *
72255570Strasz * The code here basically replaces the npeDl and npeMh classes
73255570Strasz * in the Intel Access Library (IAL).
74255570Strasz *
75255570Strasz * NB: Microcode images are loaded with firmware(9).  To
76255570Strasz *     include microcode in a static kernel include the
77255570Strasz *     ixpnpe_fw device.  Otherwise the firmware will be
78255570Strasz *     automatically loaded from the filesystem.
79275246Strasz */
80275246Strasz#include <sys/param.h>
81255570Strasz#include <sys/systm.h>
82255570Strasz#include <sys/kernel.h>
83255570Strasz#include <sys/malloc.h>
84263722Strasz#include <sys/module.h>
85255570Strasz#include <sys/time.h>
86263722Strasz#include <sys/bus.h>
87255570Strasz#include <sys/resource.h>
88263722Strasz#include <sys/rman.h>
89255570Strasz#include <sys/sysctl.h>
90263722Strasz
91255570Strasz#include <sys/linker.h>
92274939Smav#include <sys/firmware.h>
93274939Smav
94274939Smav#include <machine/bus.h>
95274939Smav#include <machine/cpu.h>
96274939Smav#include <machine/cpufunc.h>
97274939Smav#include <machine/resource.h>
98263722Strasz#include <machine/intr.h>
99255570Strasz#include <arm/xscale/ixp425/ixp425reg.h>
100263722Strasz#include <arm/xscale/ixp425/ixp425var.h>
101255570Strasz
102279002Smav#include <arm/xscale/ixp425/ixp425_npereg.h>
103279002Smav#include <arm/xscale/ixp425/ixp425_npevar.h>
104263722Strasz
105255570Straszstruct ixpnpe_softc {
106255570Strasz	device_t	sc_dev;
107275186Strasz	bus_space_tag_t	sc_iot;
108255570Strasz	bus_space_handle_t sc_ioh;
109275186Strasz	bus_size_t	sc_size;	/* size of mapped register window */
110275186Strasz	struct resource	*sc_irq;	/* IRQ resource */
111275186Strasz	void		*sc_ih;		/* interrupt handler */
112275187Strasz	struct mtx	sc_mtx;		/* mailbox lock */
113275186Strasz	uint32_t	sc_msg[2];	/* reply msg collected in ixpnpe_intr */
114275186Strasz	int		sc_msgwaiting;	/* sc_msg holds valid data */
115275186Strasz	int		sc_npeid;
116275186Strasz	int		sc_nrefs;	/* # of references */
117275186Strasz
118255570Strasz	int		validImage;	/* valid ucode image loaded */
119255570Strasz	int		started;	/* NPE is started */
120255570Strasz	uint8_t		functionalityId;/* ucode functionality ID */
121275186Strasz	int		insMemSize;	/* size of instruction memory */
122255570Strasz	int		dataMemSize;	/* size of data memory */
123275186Strasz	uint32_t	savedExecCount;
124275186Strasz	uint32_t	savedEcsDbgCtxtReg2;
125275186Strasz};
126275187Straszstatic struct ixpnpe_softc *npes[NPE_MAX];
127275186Strasz
128275186Strasz#define	IX_NPEDL_NPEIMAGE_FIELD_MASK	0xff
129275186Strasz
130275186Strasz/* used to read download map from version in microcode image */
131275186Strasz#define IX_NPEDL_BLOCK_TYPE_INSTRUCTION	0x00000000
132255570Strasz#define IX_NPEDL_BLOCK_TYPE_DATA	0x00000001
133255570Strasz#define IX_NPEDL_BLOCK_TYPE_STATE	0x00000002
134255570Strasz#define IX_NPEDL_END_OF_DOWNLOAD_MAP	0x0000000F
135275186Strasz
136255570Strasz/*
137275186Strasz * masks used to extract address info from State information context
138275186Strasz * register addresses as read from microcode image
139275186Strasz */
140275187Strasz#define IX_NPEDL_MASK_STATE_ADDR_CTXT_REG         0x0000000F
141275186Strasz#define IX_NPEDL_MASK_STATE_ADDR_CTXT_NUM         0x000000F0
142275186Strasz
143275186Strasz/* LSB offset of Context Number field in State-Info Context Address */
144275186Strasz#define IX_NPEDL_OFFSET_STATE_ADDR_CTXT_NUM       4
145275186Strasz
146255570Strasz/* size (in words) of single State Information entry (ctxt reg address|data) */
147255570Strasz#define IX_NPEDL_STATE_INFO_ENTRY_SIZE	2
148255570Strasz
149263722Strasztypedef struct {
150255570Strasz	uint32_t type;
151255570Strasz	uint32_t offset;
152255570Strasz} IxNpeDlNpeMgrDownloadMapBlockEntry;
153255570Strasz
154255570Strasztypedef union {
155255570Strasz	IxNpeDlNpeMgrDownloadMapBlockEntry block;
156255570Strasz	uint32_t eodmMarker;
157255570Strasz} IxNpeDlNpeMgrDownloadMapEntry;
158255570Strasz
159255570Strasztypedef struct {
160274939Smav	/* 1st entry in the download map (there may be more than one) */
161274939Smav	IxNpeDlNpeMgrDownloadMapEntry entry[1];
162274939Smav} IxNpeDlNpeMgrDownloadMap;
163274939Smav
164274939Smav/* used to access an instruction or data block in a microcode image */
165274939Smavtypedef struct {
166274939Smav	uint32_t npeMemAddress;
167274939Smav	uint32_t size;
168274939Smav	uint32_t data[1];
169274939Smav} IxNpeDlNpeMgrCodeBlock;
170274939Smav
171275187Strasz/* used to access each Context Reg entry state-information block */
172274939Smavtypedef struct {
173275187Strasz	uint32_t addressInfo;
174275187Strasz	uint32_t value;
175275187Strasz} IxNpeDlNpeMgrStateInfoCtxtRegEntry;
176275187Strasz
177275187Strasz/* used to access a state-information block in a microcode image */
178275187Strasztypedef struct {
179275187Strasz	uint32_t size;
180275187Strasz	IxNpeDlNpeMgrStateInfoCtxtRegEntry ctxtRegEntry[1];
181275187Strasz} IxNpeDlNpeMgrStateInfoBlock;
182274939Smav
183274939Smavstatic int npe_debug = 0;
184274939SmavSYSCTL_INT(_debug, OID_AUTO, ixp425npe, CTLFLAG_RW, &npe_debug,
185275187Strasz	   0, "IXP4XX NPE debug msgs");
186274939SmavTUNABLE_INT("debug.ixp425npe", &npe_debug);
187275187Strasz#define	DPRINTF(dev, fmt, ...) do {					\
188275187Strasz	if (npe_debug) device_printf(dev, fmt, __VA_ARGS__);		\
189275187Strasz} while (0)
190275187Strasz#define	DPRINTFn(n, dev, fmt, ...) do {					\
191275187Strasz	if (npe_debug >= n) printf(fmt, __VA_ARGS__);			\
192275187Strasz} while (0)
193275187Strasz
194275187Straszstatic int npe_checkbits(struct ixpnpe_softc *, uint32_t reg, uint32_t);
195275187Straszstatic int npe_isstopped(struct ixpnpe_softc *);
196274939Smavstatic int npe_load_ins(struct ixpnpe_softc *,
197274939Smav		const IxNpeDlNpeMgrCodeBlock *bp, int verify);
198274939Smavstatic int npe_load_data(struct ixpnpe_softc *,
199263722Strasz		const IxNpeDlNpeMgrCodeBlock *bp, int verify);
200255570Straszstatic int npe_load_stateinfo(struct ixpnpe_softc *,
201255570Strasz		const IxNpeDlNpeMgrStateInfoBlock *bp, int verify);
202255570Straszstatic int npe_load_image(struct ixpnpe_softc *,
203255570Strasz		const uint32_t *imageCodePtr, int verify);
204255570Straszstatic int npe_cpu_reset(struct ixpnpe_softc *);
205255570Straszstatic int npe_cpu_start(struct ixpnpe_softc *);
206255570Straszstatic int npe_cpu_stop(struct ixpnpe_softc *);
207255570Straszstatic void npe_cmd_issue_write(struct ixpnpe_softc *,
208263726Strasz		uint32_t cmd, uint32_t addr, uint32_t data);
209263726Straszstatic uint32_t npe_cmd_issue_read(struct ixpnpe_softc *,
210263726Strasz		uint32_t cmd, uint32_t addr);
211263726Straszstatic int npe_ins_write(struct ixpnpe_softc *,
212263726Strasz		uint32_t addr, uint32_t data, int verify);
213263726Straszstatic int npe_data_write(struct ixpnpe_softc *,
214263726Strasz		uint32_t addr, uint32_t data, int verify);
215263726Straszstatic void npe_ecs_reg_write(struct ixpnpe_softc *,
216263726Strasz		uint32_t reg, uint32_t data);
217263726Straszstatic uint32_t npe_ecs_reg_read(struct ixpnpe_softc *, uint32_t reg);
218263726Straszstatic void npe_issue_cmd(struct ixpnpe_softc *, uint32_t command);
219255570Straszstatic void npe_cpu_step_save(struct ixpnpe_softc *);
220255570Straszstatic int npe_cpu_step(struct ixpnpe_softc *, uint32_t npeInstruction,
221255570Strasz		uint32_t ctxtNum, uint32_t ldur);
222255570Straszstatic void npe_cpu_step_restore(struct ixpnpe_softc *);
223255570Straszstatic int npe_logical_reg_read(struct ixpnpe_softc *,
224255570Strasz		uint32_t regAddr, uint32_t regSize,
225255570Strasz		uint32_t ctxtNum, uint32_t *regVal);
226255570Straszstatic int npe_logical_reg_write(struct ixpnpe_softc *,
227255570Strasz		uint32_t regAddr, uint32_t regVal,
228275246Strasz		uint32_t regSize, uint32_t ctxtNum, int verify);
229275246Straszstatic int npe_physical_reg_write(struct ixpnpe_softc *,
230255570Strasz		uint32_t regAddr, uint32_t regValue, int verify);
231255570Straszstatic int npe_ctx_reg_write(struct ixpnpe_softc *, uint32_t ctxtNum,
232255570Strasz		uint32_t ctxtReg, uint32_t ctxtRegVal, int verify);
233263724Strasz
234263724Straszstatic void ixpnpe_intr(void *arg);
235255570Strasz
236255570Straszstatic uint32_t
237255570Strasznpe_reg_read(struct ixpnpe_softc *sc, bus_size_t off)
238263720Strasz{
239263720Strasz	uint32_t v = bus_space_read_4(sc->sc_iot, sc->sc_ioh, off);
240263720Strasz	DPRINTFn(9, sc->sc_dev, "%s(0x%lx) => 0x%x\n", __func__, off, v);
241263720Strasz	return v;
242255570Strasz}
243255570Strasz
244263724Straszstatic void
245263724Strasznpe_reg_write(struct ixpnpe_softc *sc, bus_size_t off, uint32_t val)
246263724Strasz{
247263724Strasz	DPRINTFn(9, sc->sc_dev, "%s(0x%lx, 0x%x)\n", __func__, off, val);
248275245Strasz	bus_space_write_4(sc->sc_iot, sc->sc_ioh, off, val);
249263724Strasz}
250263724Strasz
251263724Straszstruct ixpnpe_softc *
252263724Straszixpnpe_attach(device_t dev, int npeid)
253263724Strasz{
254263724Strasz	struct npeconfig {
255255570Strasz		uint32_t	base;
256255570Strasz		uint32_t	size;
257255570Strasz		int		irq;
258255570Strasz		uint32_t	ins_memsize;
259255570Strasz		uint32_t	data_memsize;
260255570Strasz	};
261255570Strasz	static const struct npeconfig npeconfigs[NPE_MAX] = {
262255570Strasz		[NPE_A] = {
263255570Strasz		    .base = IXP425_NPE_A_HWBASE,
264255570Strasz		    .size = IXP425_NPE_A_SIZE,
265255570Strasz		    .irq = IXP425_INT_NPE_A,
266255570Strasz		    .ins_memsize = IX_NPEDL_INS_MEMSIZE_WORDS_NPEA,
267255570Strasz		    .data_memsize = IX_NPEDL_DATA_MEMSIZE_WORDS_NPEA
268255570Strasz		},
269255570Strasz		[NPE_B] = {
270255570Strasz		    .base = IXP425_NPE_B_HWBASE,
271255570Strasz		    .size = IXP425_NPE_B_SIZE,
272255570Strasz		    .irq = IXP425_INT_NPE_B,
273255570Strasz		    .ins_memsize = IX_NPEDL_INS_MEMSIZE_WORDS_NPEB,
274255570Strasz		    .data_memsize = IX_NPEDL_DATA_MEMSIZE_WORDS_NPEB
275255570Strasz		},
276255570Strasz		[NPE_C] = {
277255570Strasz		    .base = IXP425_NPE_C_HWBASE,
278255570Strasz		    .size = IXP425_NPE_C_SIZE,
279255570Strasz		    .irq = IXP425_INT_NPE_C,
280255570Strasz		    .ins_memsize = IX_NPEDL_INS_MEMSIZE_WORDS_NPEC,
281263720Strasz		    .data_memsize = IX_NPEDL_DATA_MEMSIZE_WORDS_NPEC
282263720Strasz		},
283263720Strasz	};
284263720Strasz	struct ixp425_softc *sa = device_get_softc(device_get_parent(dev));
285263720Strasz	struct ixpnpe_softc *sc;
286263720Strasz	const struct npeconfig *config;
287263720Strasz	int rid;
288263720Strasz
289263720Strasz	if (npeid >= NPE_MAX) {
290263720Strasz		device_printf(dev, "%s: bad npeid %d\n", __func__, npeid);
291263720Strasz		return NULL;
292263720Strasz	}
293263720Strasz	sc = npes[npeid];
294263720Strasz	if (sc != NULL) {
295263720Strasz		sc->sc_nrefs++;
296263720Strasz		return sc;
297263720Strasz	}
298263720Strasz	config = &npeconfigs[npeid];
299263720Strasz
300263720Strasz	/* XXX M_BUS */
301263720Strasz	sc = malloc(sizeof(struct ixpnpe_softc), M_TEMP, M_WAITOK | M_ZERO);
302263720Strasz	sc->sc_dev = dev;
303263722Strasz	sc->sc_iot = sa->sc_iot;
304255570Strasz	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), "npe driver", MTX_DEF);
305255570Strasz	sc->sc_npeid = npeid;
306255570Strasz	sc->sc_nrefs = 1;
307255570Strasz
308255570Strasz	sc->sc_size = config->size;
309255570Strasz	sc->insMemSize = config->ins_memsize;	/* size of instruction memory */
310255570Strasz	sc->dataMemSize = config->data_memsize;	/* size of data memory */
311255570Strasz
312263725Strasz	if (bus_space_map(sc->sc_iot, config->base, sc->sc_size, 0, &sc->sc_ioh))
313263725Strasz		panic("%s: Cannot map registers", device_get_name(dev));
314263725Strasz
315263725Strasz	/*
316263725Strasz	 * Setup IRQ and handler for NPE message support.
317263725Strasz	 */
318263725Strasz	rid = 0;
319263725Strasz	sc->sc_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
320263725Strasz	    config->irq, config->irq, 1, RF_ACTIVE);
321263725Strasz	if (sc->sc_irq == NULL)
322263725Strasz		panic("%s: Unable to allocate irq %u", device_get_name(dev),
323255570Strasz		    config->irq);
324255570Strasz	/* XXX could be a source of entropy */
325255570Strasz	bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_NET | INTR_MPSAFE,
326255570Strasz	    NULL, ixpnpe_intr, sc, &sc->sc_ih);
327255570Strasz	/*
328255570Strasz	 * Enable output fifo interrupts (NB: must also set OFIFO Write Enable)
329255570Strasz	 */
330255570Strasz	npe_reg_write(sc, IX_NPECTL,
331255570Strasz	    npe_reg_read(sc, IX_NPECTL) | (IX_NPECTL_OFE | IX_NPECTL_OFWE));
332275246Strasz
333275246Strasz	npes[npeid] = sc;
334255570Strasz
335255570Strasz	return sc;
336255570Strasz}
337255570Strasz
338255570Straszvoid
339275244Straszixpnpe_detach(struct ixpnpe_softc *sc)
340275244Strasz{
341255570Strasz	if (--sc->sc_nrefs == 0) {
342255570Strasz		npes[sc->sc_npeid] = NULL;
343255570Strasz
344275642Strasz		/* disable output fifo interrupts */
345275642Strasz		npe_reg_write(sc, IX_NPECTL,
346255570Strasz		    npe_reg_read(sc, IX_NPECTL) &~ (IX_NPECTL_OFE | IX_NPECTL_OFWE));
347255570Strasz
348255570Strasz		bus_teardown_intr(sc->sc_dev, sc->sc_irq, sc->sc_ih);
349255570Strasz		bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_size);
350255570Strasz		mtx_destroy(&sc->sc_mtx);
351255570Strasz		free(sc, M_TEMP);
352255570Strasz	}
353255570Strasz}
354255570Strasz
355255570Straszint
356255570Straszixpnpe_stopandreset(struct ixpnpe_softc *sc)
357255570Strasz{
358255570Strasz	int error;
359255570Strasz
360255570Strasz	mtx_lock(&sc->sc_mtx);
361255570Strasz	error = npe_cpu_stop(sc);		/* stop NPE */
362255570Strasz	if (error == 0)
363255570Strasz		error = npe_cpu_reset(sc);	/* reset it */
364255570Strasz	if (error == 0)
365255570Strasz		sc->started = 0;		/* mark stopped */
366255570Strasz	mtx_unlock(&sc->sc_mtx);
367255570Strasz
368275244Strasz	DPRINTF(sc->sc_dev, "%s: error %d\n", __func__, error);
369275244Strasz	return error;
370275244Strasz}
371275244Strasz
372275245Straszstatic int
373275244Straszixpnpe_start_locked(struct ixpnpe_softc *sc)
374275244Strasz{
375275244Strasz	int error;
376275244Strasz
377275244Strasz	if (!sc->started) {
378275244Strasz		error = npe_cpu_start(sc);
379255570Strasz		if (error == 0)
380255570Strasz			sc->started = 1;
381255570Strasz	} else
382255570Strasz		error = 0;
383255570Strasz
384255570Strasz	DPRINTF(sc->sc_dev, "%s: error %d\n", __func__, error);
385255570Strasz	return error;
386255570Strasz}
387255570Strasz
388255570Straszint
389255570Straszixpnpe_start(struct ixpnpe_softc *sc)
390255570Strasz{
391255570Strasz	int ret;
392255570Strasz
393255570Strasz	mtx_lock(&sc->sc_mtx);
394255570Strasz	ret = ixpnpe_start_locked(sc);
395255570Strasz	mtx_unlock(&sc->sc_mtx);
396255570Strasz	return (ret);
397255570Strasz}
398255570Strasz
399255570Straszint
400255570Straszixpnpe_stop(struct ixpnpe_softc *sc)
401275642Strasz{
402275642Strasz	int error;
403275642Strasz
404275642Strasz	mtx_lock(&sc->sc_mtx);
405275642Strasz	error = npe_cpu_stop(sc);
406275642Strasz	if (error == 0)
407275642Strasz		sc->started = 0;
408275642Strasz	mtx_unlock(&sc->sc_mtx);
409275642Strasz
410275642Strasz	DPRINTF(sc->sc_dev, "%s: error %d\n", __func__, error);
411275642Strasz	return error;
412279002Smav}
413279002Smav
414279002Smav/*
415279002Smav * Indicates the start of an NPE Image, in new NPE Image Library format.
416279002Smav * 2 consecutive occurances indicates the end of the NPE Image Library
417279002Smav */
418279002Smav#define NPE_IMAGE_MARKER 0xfeedf00d
419279002Smav
420279002Smav/*
421279002Smav * NPE Image Header definition, used in new NPE Image Library format
422279002Smav */
423279002Smavtypedef struct {
424279002Smav	uint32_t marker;
425279002Smav	uint32_t id;
426279002Smav	uint32_t size;
427279002Smav} IxNpeDlImageMgrImageHeader;
428263722Strasz
429255570Straszstatic int
430255570Strasznpe_findimage(struct ixpnpe_softc *sc,
431255570Strasz    const uint32_t *imageLibrary, uint32_t imageId,
432255570Strasz    const uint32_t **imagePtr, uint32_t *imageSize)
433255570Strasz{
434255570Strasz	const IxNpeDlImageMgrImageHeader *image;
435263722Strasz	uint32_t offset = 0;
436255570Strasz
437255570Strasz	while (imageLibrary[offset] == NPE_IMAGE_MARKER) {
438255570Strasz		image = (const IxNpeDlImageMgrImageHeader *)
439255570Strasz		    &imageLibrary[offset];
440255570Strasz		offset += sizeof(IxNpeDlImageMgrImageHeader)/sizeof(uint32_t);
441255570Strasz
442255570Strasz		DPRINTF(sc->sc_dev, "%s: off %u mark 0x%x id 0x%x size %u\n",
443255570Strasz		    __func__, offset, image->marker, image->id, image->size);
444255570Strasz		if (image->id == imageId) {
445255570Strasz			*imagePtr = imageLibrary + offset;
446255570Strasz			*imageSize = image->size;
447275246Strasz			return 0;
448275246Strasz		}
449255570Strasz		/* 2 consecutive NPE_IMAGE_MARKER's indicates end of library */
450255570Strasz		if (image->id == NPE_IMAGE_MARKER) {
451255570Strasz			DPRINTF(sc->sc_dev, "imageId 0x%08x not found in "
452263722Strasz			    "image library header\n", imageId);
453255570Strasz			/* reached end of library, image not found */
454263722Strasz			return ESRCH;
455255570Strasz		}
456263724Strasz		offset += image->size;
457263724Strasz	}
458263722Strasz	return ESRCH;
459255570Strasz}
460263722Strasz
461255570Straszstatic int
462263722Straszixpnpe_load_firmware(struct ixpnpe_softc *sc, const char *imageName,
463263720Strasz    uint32_t imageId)
464263722Strasz{
465263720Strasz	static const char *devname[4] =
466263722Strasz	     { "IXP425", "IXP435/IXP465", "DeviceID#2", "DeviceID#3" };
467255570Strasz	uint32_t imageSize;
468275642Strasz	const uint32_t *imageCodePtr;
469275642Strasz	const struct firmware *fw;
470263722Strasz	int error;
471279002Smav
472279002Smav	DPRINTF(sc->sc_dev, "load %s, imageId 0x%08x\n", imageName, imageId);
473255570Strasz
474255570Strasz#if 0
475263722Strasz	IxFeatureCtrlDeviceId devid = IX_NPEDL_DEVICEID_FROM_IMAGEID_GET(imageId);
476255570Strasz	/*
477255570Strasz	 * Checking if image being loaded is meant for device that is running.
478255570Strasz	 * Image is forward compatible. i.e Image built for IXP42X should run
479263723Strasz	 * on IXP46X but not vice versa.
480255570Strasz	 */
481255570Strasz	if (devid > (ixFeatureCtrlDeviceRead() & IX_FEATURE_CTRL_DEVICE_TYPE_MASK))
482255570Strasz	    return EINVAL;
483255570Strasz#endif
484255570Strasz	error = ixpnpe_stopandreset(sc);		/* stop and reset the NPE */
485255570Strasz	if (error != 0)
486263722Strasz		return error;
487255570Strasz
488255570Strasz	fw = firmware_get(imageName);
489255570Strasz	if (fw == NULL)
490255570Strasz		return ENOENT;
491263723Strasz
492255570Strasz	/* Locate desired image in files w/ combined images */
493263724Strasz	error = npe_findimage(sc, fw->data, imageId, &imageCodePtr, &imageSize);
494255570Strasz	if (error != 0)
495263723Strasz		goto done;
496255570Strasz
497255570Strasz	device_printf(sc->sc_dev,
498255570Strasz	    "load fw image %s.NPE-%c Func 0x%x Rev %u.%u\n",
499255570Strasz	    devname[NPEIMAGE_DEVID(imageId)], 'A' + NPEIMAGE_NPEID(imageId),
500255570Strasz	    NPEIMAGE_FUNCID(imageId), NPEIMAGE_MAJOR(imageId),
501263723Strasz	    NPEIMAGE_MINOR(imageId));
502255570Strasz
503255570Strasz	/*
504255570Strasz	 * If download was successful, store image Id in list of
505255570Strasz	 * currently loaded images. If a critical error occured
506255570Strasz	 * during download, record that the NPE has an invalid image
507255570Strasz	 */
508263724Strasz	mtx_lock(&sc->sc_mtx);
509263724Strasz	error = npe_load_image(sc, imageCodePtr, 1 /*VERIFY*/);
510263724Strasz	if (error == 0) {
511263724Strasz		sc->validImage = 1;
512263724Strasz		error = ixpnpe_start_locked(sc);
513263724Strasz	} else {
514263724Strasz		sc->validImage = 0;
515263724Strasz	}
516263724Strasz	sc->functionalityId = IX_NPEDL_FUNCTIONID_FROM_IMAGEID_GET(imageId);
517263724Strasz	mtx_unlock(&sc->sc_mtx);
518263724Straszdone:
519263724Strasz	firmware_put(fw, FIRMWARE_UNLOAD);
520263724Strasz	DPRINTF(sc->sc_dev, "%s: error %d\n", __func__, error);
521263724Strasz	return error;
522263724Strasz}
523263724Strasz
524263724Straszstatic int
525263724Straszoverride_imageid(device_t dev, const char *resname, uint32_t *val)
526263724Strasz{
527275245Strasz	int unit = device_get_unit(dev);
528263724Strasz	int resval;
529263724Strasz
530263724Strasz	if (resource_int_value("npe", unit, resname, &resval) != 0)
531263724Strasz		return 0;
532263724Strasz	/* XXX validate */
533263724Strasz	if (bootverbose)
534263722Strasz		device_printf(dev, "using npe.%d.%s=0x%x override\n",
535255570Strasz		    unit, resname, resval);
536255570Strasz	*val = resval;
537255570Strasz	return 1;
538255570Strasz}
539255570Strasz
540263724Straszint
541263724Straszixpnpe_init(struct ixpnpe_softc *sc)
542263723Strasz{
543255570Strasz	static const uint32_t npeconfig[NPE_MAX] = {
544255570Strasz		[NPE_A] = IXP425_NPE_A_IMAGEID,
545255570Strasz		[NPE_B] = IXP425_NPE_B_IMAGEID,
546255570Strasz		[NPE_C] = IXP425_NPE_C_IMAGEID,
547255570Strasz	};
548255570Strasz	uint32_t imageid, msg[2];
549255570Strasz	int error;
550255570Strasz
551255570Strasz	if (sc->started)
552255570Strasz		return 0;
553255570Strasz	/*
554255570Strasz	 * Load NPE firmware and start it running.  We assume
555255570Strasz	 * that minor version bumps remain compatible so probe
556255570Strasz	 * the firmware image starting with the expected version
557255570Strasz	 * and then bump the minor version up to the max.
558255570Strasz	 */
559255570Strasz	if (!override_imageid(sc->sc_dev, "imageid", &imageid))
560255570Strasz		imageid = npeconfig[sc->sc_npeid];
561255570Strasz	for (;;) {
562255570Strasz		error = ixpnpe_load_firmware(sc, "npe_fw", imageid);
563255570Strasz		if (error == 0)
564263722Strasz			break;
565255570Strasz		/*
566255570Strasz		 * ESRCH is returned when the requested image
567255570Strasz		 * is not present
568255570Strasz		 */
569255570Strasz		if (error != ESRCH) {
570263724Strasz			device_printf(sc->sc_dev,
571263724Strasz			    "cannot init NPE (error %d)\n", error);
572263723Strasz			return error;
573255570Strasz		}
574255570Strasz		/* bump the minor version up to the max possible */
575255570Strasz		if (NPEIMAGE_MINOR(imageid) == 0xff) {
576255570Strasz			device_printf(sc->sc_dev, "cannot locate firmware "
577255570Strasz			    "(imageid 0x%08x)\n", imageid);
578255570Strasz			return error;
579255570Strasz		}
580255570Strasz		imageid++;
581255570Strasz	}
582255570Strasz	/* NB: firmware should respond with a status msg */
583255570Strasz	if (ixpnpe_recvmsg_sync(sc, msg) != 0) {
584255570Strasz		device_printf(sc->sc_dev,
585255570Strasz		    "firmware did not respond as expected\n");
586255570Strasz		return EIO;
587255570Strasz	}
588255570Strasz	return 0;
589255570Strasz}
590255570Strasz
591255570Straszint
592255570Straszixpnpe_getfunctionality(struct ixpnpe_softc *sc)
593255570Strasz{
594255570Strasz	return (sc->validImage ? sc->functionalityId : 0);
595255570Strasz}
596255570Strasz
597255570Straszstatic int
598255570Strasznpe_checkbits(struct ixpnpe_softc *sc, uint32_t reg, uint32_t expectedBitsSet)
599255570Strasz{
600255570Strasz	uint32_t val;
601263722Strasz
602263720Strasz	val = npe_reg_read(sc, reg);
603263720Strasz	DPRINTFn(5, sc->sc_dev, "%s(0x%x, 0x%x) => 0x%x (%u)\n",
604263720Strasz	    __func__, reg, expectedBitsSet, val,
605263720Strasz	    (val & expectedBitsSet) == expectedBitsSet);
606263720Strasz	return ((val & expectedBitsSet) == expectedBitsSet);
607263724Strasz}
608263720Strasz
609263723Straszstatic int
610263720Strasznpe_isstopped(struct ixpnpe_softc *sc)
611263720Strasz{
612263720Strasz	return npe_checkbits(sc,
613263720Strasz	    IX_NPEDL_REG_OFFSET_EXCTL, IX_NPEDL_EXCTL_STATUS_STOP);
614263720Strasz}
615263720Strasz
616263720Straszstatic int
617263720Strasznpe_load_ins(struct ixpnpe_softc *sc,
618263720Strasz    const IxNpeDlNpeMgrCodeBlock *bp, int verify)
619263720Strasz{
620263720Strasz	uint32_t npeMemAddress;
621263720Strasz	int i, blockSize;
622263720Strasz
623263720Strasz	npeMemAddress = bp->npeMemAddress;
624263720Strasz	blockSize = bp->size;		/* NB: instruction/data count */
625263720Strasz	if (npeMemAddress + blockSize > sc->insMemSize) {
626263720Strasz		device_printf(sc->sc_dev,
627263720Strasz		    "Block size %u too big for NPE memory\n", blockSize);
628263722Strasz		return EINVAL;	/* XXX */
629263720Strasz	}
630263720Strasz	for (i = 0; i < blockSize; i++, npeMemAddress++) {
631263720Strasz		if (npe_ins_write(sc, npeMemAddress, bp->data[i], verify) != 0) {
632263720Strasz			device_printf(sc->sc_dev,
633263720Strasz			    "NPE instruction write failed");
634263724Strasz			return EIO;
635263720Strasz		}
636263723Strasz	}
637263720Strasz	return 0;
638263720Strasz}
639263720Strasz
640263720Straszstatic int
641263720Strasznpe_load_data(struct ixpnpe_softc *sc,
642263720Strasz    const IxNpeDlNpeMgrCodeBlock *bp, int verify)
643263720Strasz{
644263720Strasz	uint32_t npeMemAddress;
645263720Strasz	int i, blockSize;
646263720Strasz
647263720Strasz	npeMemAddress = bp->npeMemAddress;
648263720Strasz	blockSize = bp->size;		/* NB: instruction/data count */
649263720Strasz	if (npeMemAddress + blockSize > sc->dataMemSize) {
650263720Strasz		device_printf(sc->sc_dev,
651263720Strasz		    "Block size %u too big for NPE memory\n", blockSize);
652263720Strasz		return EINVAL;
653263720Strasz	}
654263720Strasz	for (i = 0; i < blockSize; i++, npeMemAddress++) {
655263722Strasz		if (npe_data_write(sc, npeMemAddress, bp->data[i], verify) != 0) {
656255570Strasz			device_printf(sc->sc_dev, "NPE data write failed\n");
657255570Strasz			return EIO;
658255570Strasz		}
659263723Strasz	}
660255570Strasz	return 0;
661255570Strasz}
662255570Strasz
663255570Straszstatic int
664255570Strasznpe_load_stateinfo(struct ixpnpe_softc *sc,
665255570Strasz    const IxNpeDlNpeMgrStateInfoBlock *bp, int verify)
666263723Strasz{
667255570Strasz	int i, nentries, error;
668255570Strasz
669255570Strasz	npe_cpu_step_save(sc);
670255570Strasz
671255570Strasz	/* for each state-info context register entry in block */
672255570Strasz	nentries = bp->size / IX_NPEDL_STATE_INFO_ENTRY_SIZE;
673255570Strasz	error = 0;
674275642Strasz	for (i = 0; i < nentries; i++) {
675275642Strasz		/* each state-info entry is 2 words (address, value) */
676275642Strasz		uint32_t regVal = bp->ctxtRegEntry[i].value;
677275642Strasz		uint32_t addrInfo = bp->ctxtRegEntry[i].addressInfo;
678275642Strasz
679275642Strasz		uint32_t reg = (addrInfo & IX_NPEDL_MASK_STATE_ADDR_CTXT_REG);
680275642Strasz		uint32_t cNum = (addrInfo & IX_NPEDL_MASK_STATE_ADDR_CTXT_NUM) >>
681275642Strasz		    IX_NPEDL_OFFSET_STATE_ADDR_CTXT_NUM;
682275642Strasz
683275642Strasz		/* error-check Context Register No. and Context Number values */
684275642Strasz		if (!(0 <= reg && reg < IX_NPEDL_CTXT_REG_MAX)) {
685263722Strasz			device_printf(sc->sc_dev,
686263722Strasz			    "invalid Context Register %u\n", reg);
687255570Strasz			error = EINVAL;
688255570Strasz			break;
689255570Strasz		}
690255570Strasz		if (!(0 <= cNum && cNum < IX_NPEDL_CTXT_NUM_MAX)) {
691255570Strasz			device_printf(sc->sc_dev,
692275186Strasz			    "invalid Context Number %u\n", cNum);
693255570Strasz			error = EINVAL;
694275186Strasz			break;
695279002Smav		}
696275186Strasz		/* NOTE that there is no STEVT register for Context 0 */
697275186Strasz		if (cNum == 0 && reg == IX_NPEDL_CTXT_REG_STEVT) {
698275187Strasz			device_printf(sc->sc_dev,
699275186Strasz			    "no STEVT for Context 0\n");
700275186Strasz			error = EINVAL;
701275186Strasz			break;
702275186Strasz		}
703279002Smav
704279002Smav		if (npe_ctx_reg_write(sc, cNum, reg, regVal, verify) != 0) {
705255570Strasz			device_printf(sc->sc_dev,
706255570Strasz			    "write of state-info to NPE failed\n");
707279002Smav			error = EIO;
708279002Smav			break;
709279002Smav		}
710255570Strasz	}
711255570Strasz
712255570Strasz	npe_cpu_step_restore(sc);
713279002Smav	return error;
714279002Smav}
715279002Smav
716279002Smavstatic int
717279002Smavnpe_load_image(struct ixpnpe_softc *sc,
718279002Smav    const uint32_t *imageCodePtr, int verify)
719279002Smav{
720279002Smav#define	EOM(marker)	((marker) == IX_NPEDL_END_OF_DOWNLOAD_MAP)
721279002Smav	const IxNpeDlNpeMgrDownloadMap *downloadMap;
722279002Smav	int i, error;
723279002Smav
724279002Smav	if (!npe_isstopped(sc)) {		/* verify NPE is stopped */
725279002Smav		device_printf(sc->sc_dev,
726279002Smav		    "cannot load image, NPE not stopped\n");
727279002Smav		return EIO;
728279002Smav	}
729279002Smav
730279002Smav	/*
731279002Smav	 * Read Download Map, checking each block type and calling
732279002Smav	 * appropriate function to perform download
733279002Smav	 */
734263722Strasz	error = 0;
735255570Strasz	downloadMap = (const IxNpeDlNpeMgrDownloadMap *) imageCodePtr;
736263722Strasz	for (i = 0; !EOM(downloadMap->entry[i].eodmMarker); i++) {
737275246Strasz		/* calculate pointer to block to be downloaded */
738275246Strasz		const uint32_t *bp = imageCodePtr +
739255570Strasz		    downloadMap->entry[i].block.offset;
740255570Strasz		switch (downloadMap->entry[i].block.type) {
741263722Strasz		case IX_NPEDL_BLOCK_TYPE_INSTRUCTION:
742263722Strasz			error = npe_load_ins(sc,
743255570Strasz			    (const IxNpeDlNpeMgrCodeBlock *) bp, verify);
744263722Strasz			DPRINTF(sc->sc_dev, "%s: inst, error %d\n",
745255570Strasz			    __func__, error);
746263722Strasz			break;
747255570Strasz		case IX_NPEDL_BLOCK_TYPE_DATA:
748263722Strasz			error = npe_load_data(sc,
749255570Strasz			    (const IxNpeDlNpeMgrCodeBlock *) bp, verify);
750263722Strasz			DPRINTF(sc->sc_dev, "%s: data, error %d\n",
751255570Strasz			    __func__, error);
752263722Strasz			break;
753255570Strasz		case IX_NPEDL_BLOCK_TYPE_STATE:
754263722Strasz		    error = npe_load_stateinfo(sc,
755255570Strasz			(const IxNpeDlNpeMgrStateInfoBlock *) bp, verify);
756255570Strasz			DPRINTF(sc->sc_dev, "%s: state, error %d\n",
757263722Strasz			    __func__, error);
758255570Strasz			break;
759255570Strasz		default:
760279002Smav			device_printf(sc->sc_dev,
761255570Strasz			    "unknown block type 0x%x in download map\n",
762279002Smav			    downloadMap->entry[i].block.type);
763255570Strasz			error = EIO;		/* XXX */
764255570Strasz			break;
765255570Strasz		}
766255570Strasz		if (error != 0)
767255570Strasz			break;
768255570Strasz	}
769255570Strasz	return error;
770255570Strasz#undef EOM
771275186Strasz}
772255570Strasz
773275186Strasz/* contains Reset values for Context Store Registers  */
774275186Straszstatic const struct {
775275186Strasz	uint32_t regAddr;
776275187Strasz	uint32_t regResetVal;
777275186Strasz} ixNpeDlEcsRegResetValues[] = {
778275186Strasz	{ IX_NPEDL_ECS_BG_CTXT_REG_0,    IX_NPEDL_ECS_BG_CTXT_REG_0_RESET },
779275186Strasz	{ IX_NPEDL_ECS_BG_CTXT_REG_1,    IX_NPEDL_ECS_BG_CTXT_REG_1_RESET },
780275186Strasz	{ IX_NPEDL_ECS_BG_CTXT_REG_2,    IX_NPEDL_ECS_BG_CTXT_REG_2_RESET },
781255570Strasz	{ IX_NPEDL_ECS_PRI_1_CTXT_REG_0, IX_NPEDL_ECS_PRI_1_CTXT_REG_0_RESET },
782279002Smav	{ IX_NPEDL_ECS_PRI_1_CTXT_REG_1, IX_NPEDL_ECS_PRI_1_CTXT_REG_1_RESET },
783255570Strasz	{ IX_NPEDL_ECS_PRI_1_CTXT_REG_2, IX_NPEDL_ECS_PRI_1_CTXT_REG_2_RESET },
784279002Smav	{ IX_NPEDL_ECS_PRI_2_CTXT_REG_0, IX_NPEDL_ECS_PRI_2_CTXT_REG_0_RESET },
785255570Strasz	{ IX_NPEDL_ECS_PRI_2_CTXT_REG_1, IX_NPEDL_ECS_PRI_2_CTXT_REG_1_RESET },
786255570Strasz	{ IX_NPEDL_ECS_PRI_2_CTXT_REG_2, IX_NPEDL_ECS_PRI_2_CTXT_REG_2_RESET },
787275186Strasz	{ IX_NPEDL_ECS_DBG_CTXT_REG_0,   IX_NPEDL_ECS_DBG_CTXT_REG_0_RESET },
788255570Strasz	{ IX_NPEDL_ECS_DBG_CTXT_REG_1,   IX_NPEDL_ECS_DBG_CTXT_REG_1_RESET },
789255570Strasz	{ IX_NPEDL_ECS_DBG_CTXT_REG_2,   IX_NPEDL_ECS_DBG_CTXT_REG_2_RESET },
790255570Strasz	{ IX_NPEDL_ECS_INSTRUCT_REG,     IX_NPEDL_ECS_INSTRUCT_REG_RESET }
791263722Strasz};
792255570Strasz
793255570Strasz/* contains Reset values for Context Store Registers  */
794279002Smavstatic const uint32_t ixNpeDlCtxtRegResetValues[] = {
795255570Strasz	IX_NPEDL_CTXT_REG_RESET_STEVT,
796279002Smav	IX_NPEDL_CTXT_REG_RESET_STARTPC,
797255570Strasz	IX_NPEDL_CTXT_REG_RESET_REGMAP,
798255570Strasz	IX_NPEDL_CTXT_REG_RESET_CINDEX,
799255570Strasz};
800255570Strasz
801255570Strasz#define	IX_NPEDL_RESET_NPE_PARITY	0x0800
802255570Strasz#define	IX_NPEDL_PARITY_BIT_MASK	0x3F00FFFF
803255570Strasz#define	IX_NPEDL_CONFIG_CTRL_REG_MASK	0x3F3FFFFF
804255570Strasz
805263722Straszstatic int
806255570Strasznpe_cpu_reset(struct ixpnpe_softc *sc)
807255570Strasz{
808274870Strasz#define	N(a)	(sizeof(a) / sizeof(a[0]))
809255570Strasz	struct ixp425_softc *sa =
810255570Strasz	    device_get_softc(device_get_parent(sc->sc_dev));
811255570Strasz	uint32_t ctxtReg; /* identifies Context Store reg (0-3) */
812255570Strasz	uint32_t regAddr;
813255570Strasz	uint32_t regVal;
814255570Strasz	uint32_t resetNpeParity;
815255570Strasz	uint32_t ixNpeConfigCtrlRegVal;
816255570Strasz	int i, error = 0;
817263722Strasz
818255570Strasz	/* pre-store the NPE Config Control Register Value */
819255570Strasz	ixNpeConfigCtrlRegVal = npe_reg_read(sc, IX_NPEDL_REG_OFFSET_CTL);
820279002Smav	ixNpeConfigCtrlRegVal |= 0x3F000000;
821255570Strasz
822279002Smav	/* disable the parity interrupt */
823255570Strasz	npe_reg_write(sc, IX_NPEDL_REG_OFFSET_CTL,
824255570Strasz	    (ixNpeConfigCtrlRegVal & IX_NPEDL_PARITY_BIT_MASK));
825255570Strasz	DPRINTFn(2, sc->sc_dev, "%s: dis parity int, CTL => 0x%x\n",
826255570Strasz	    __func__, ixNpeConfigCtrlRegVal & IX_NPEDL_PARITY_BIT_MASK);
827255570Strasz
828255570Strasz	npe_cpu_step_save(sc);
829255570Strasz
830255570Strasz	/*
831263722Strasz	 * Clear the FIFOs.
832255570Strasz	 */
833255570Strasz	while (npe_checkbits(sc,
834279002Smav	      IX_NPEDL_REG_OFFSET_WFIFO, IX_NPEDL_MASK_WFIFO_VALID)) {
835255570Strasz		/* read from the Watch-point FIFO until empty */
836279002Smav		(void) npe_reg_read(sc, IX_NPEDL_REG_OFFSET_WFIFO);
837255570Strasz	}
838255570Strasz
839255570Strasz	while (npe_checkbits(sc,
840255570Strasz	      IX_NPEDL_REG_OFFSET_STAT, IX_NPEDL_MASK_STAT_OFNE)) {
841255570Strasz		/* read from the outFIFO until empty */
842275186Strasz		(void) npe_reg_read(sc, IX_NPEDL_REG_OFFSET_FIFO);
843275186Strasz	}
844275186Strasz
845275186Strasz	while (npe_checkbits(sc,
846267962Sjpaetzel	      IX_NPEDL_REG_OFFSET_STAT, IX_NPEDL_MASK_STAT_IFNE)) {
847275186Strasz		/*
848267962Sjpaetzel		 * Step execution of the NPE intruction to read inFIFO using
849275186Strasz		 * the Debug Executing Context stack.
850275187Strasz		 */
851275186Strasz		error = npe_cpu_step(sc, IX_NPEDL_INSTR_RD_FIFO, 0, 0);
852267962Sjpaetzel		if (error != 0) {
853267962Sjpaetzel			DPRINTF(sc->sc_dev, "%s: cannot step (1), error %u\n",
854255570Strasz			    __func__, error);
855255570Strasz			npe_cpu_step_restore(sc);
856279002Smav			return error;
857255570Strasz		}
858279002Smav	}
859255570Strasz
860255570Strasz	/*
861275186Strasz	 * Reset the mailbox reg
862255570Strasz	 */
863255570Strasz	/* ...from XScale side */
864255570Strasz	npe_reg_write(sc, IX_NPEDL_REG_OFFSET_MBST, IX_NPEDL_REG_RESET_MBST);
865255570Strasz	/* ...from NPE side */
866255570Strasz	error = npe_cpu_step(sc, IX_NPEDL_INSTR_RESET_MBOX, 0, 0);
867255570Strasz	if (error != 0) {
868255570Strasz		DPRINTF(sc->sc_dev, "%s: cannot step (2), error %u\n",
869255570Strasz		    __func__, error);
870255570Strasz		npe_cpu_step_restore(sc);
871255570Strasz		return error;
872255570Strasz	}
873255570Strasz
874255570Strasz	/*
875255570Strasz	 * Reset the physical registers in the NPE register file:
876255570Strasz	 * Note: no need to save/restore REGMAP for Context 0 here
877255570Strasz	 * since all Context Store regs are reset in subsequent code.
878255570Strasz	 */
879255570Strasz	for (regAddr = 0;
880255570Strasz	     regAddr < IX_NPEDL_TOTAL_NUM_PHYS_REG && error == 0;
881255570Strasz	     regAddr++) {
882255570Strasz		/* for each physical register in the NPE reg file, write 0 : */
883255570Strasz		error = npe_physical_reg_write(sc, regAddr, 0, TRUE);
884255570Strasz		if (error != 0) {
885255570Strasz			DPRINTF(sc->sc_dev, "%s: cannot write phy reg,"
886255570Strasz			    "error %u\n", __func__, error);
887255570Strasz			npe_cpu_step_restore(sc);
888255570Strasz			return error;		/* abort reset */
889255570Strasz		}
890255570Strasz	}
891255570Strasz
892255570Strasz	/*
893255570Strasz	 * Reset the context store:
894255570Strasz	 */
895255570Strasz	for (i = IX_NPEDL_CTXT_NUM_MIN; i <= IX_NPEDL_CTXT_NUM_MAX; i++) {
896255570Strasz		/* set each context's Context Store registers to reset values */
897255570Strasz		for (ctxtReg = 0; ctxtReg < IX_NPEDL_CTXT_REG_MAX; ctxtReg++) {
898255570Strasz			/* NOTE that there is no STEVT register for Context 0 */
899255570Strasz			if (i == 0 && ctxtReg == IX_NPEDL_CTXT_REG_STEVT)
900255570Strasz				continue;
901255570Strasz			regVal = ixNpeDlCtxtRegResetValues[ctxtReg];
902255570Strasz			error = npe_ctx_reg_write(sc, i, ctxtReg,
903255570Strasz			    regVal, TRUE);
904255570Strasz			if (error != 0) {
905255570Strasz				DPRINTF(sc->sc_dev, "%s: cannot write ctx reg,"
906255570Strasz				    "error %u\n", __func__, error);
907255570Strasz				npe_cpu_step_restore(sc);
908255570Strasz				return error;	 /* abort reset */
909255570Strasz			}
910255570Strasz		}
911255570Strasz	}
912255570Strasz
913263726Strasz	npe_cpu_step_restore(sc);
914263726Strasz
915263726Strasz	/* write Reset values to Execution Context Stack registers */
916255570Strasz	for (i = 0; i < N(ixNpeDlEcsRegResetValues); i++)
917263725Strasz		npe_ecs_reg_write(sc,
918255570Strasz		    ixNpeDlEcsRegResetValues[i].regAddr,
919255570Strasz		    ixNpeDlEcsRegResetValues[i].regResetVal);
920255570Strasz
921263725Strasz	/* clear the profile counter */
922263729Strasz	npe_issue_cmd(sc, IX_NPEDL_EXCTL_CMD_CLR_PROFILE_CNT);
923255570Strasz
924255570Strasz	/* clear registers EXCT, AP0, AP1, AP2 and AP3 */
925263725Strasz	for (regAddr = IX_NPEDL_REG_OFFSET_EXCT;
926255570Strasz	     regAddr <= IX_NPEDL_REG_OFFSET_AP3;
927255570Strasz	     regAddr += sizeof(uint32_t))
928255570Strasz		npe_reg_write(sc, regAddr, 0);
929255570Strasz
930255570Strasz	/* Reset the Watch-count register */
931255570Strasz	npe_reg_write(sc, IX_NPEDL_REG_OFFSET_WC, 0);
932255570Strasz
933255570Strasz	/*
934263715Strasz	 * WR IXA00055043 - Remove IMEM Parity Introduced by NPE Reset Operation
935255570Strasz	 */
936255570Strasz
937255570Strasz	/*
938255570Strasz	 * Reset the NPE and its coprocessor - to reset internal
939255570Strasz	 * states and remove parity error.  Note this makes no
940255570Strasz	 * sense based on the documentation.  The feature control
941255570Strasz	 * register always reads back as 0 on the ixp425 and further
942255570Strasz	 * the bit definition of NPEA/NPEB is off by 1 according to
943255570Strasz	 * the Intel documention--so we're blindly following the
944255570Strasz	 * Intel code w/o any real understanding.
945255570Strasz	 */
946255570Strasz	regVal = EXP_BUS_READ_4(sa, EXP_FCTRL_OFFSET);
947263726Strasz	DPRINTFn(2, sc->sc_dev, "%s: FCTRL 0x%x\n", __func__, regVal);
948263726Strasz	resetNpeParity =
949263726Strasz	    IX_NPEDL_RESET_NPE_PARITY << (1 + device_get_unit(sc->sc_dev));
950263726Strasz	DPRINTFn(2, sc->sc_dev, "%s: FCTRL fuse parity, write 0x%x\n",
951263726Strasz	    __func__, regVal | resetNpeParity);
952263729Strasz	EXP_BUS_WRITE_4(sa, EXP_FCTRL_OFFSET, regVal | resetNpeParity);
953263726Strasz
954263726Strasz	/* un-fuse and un-reset the NPE & coprocessor */
955263725Strasz	DPRINTFn(2, sc->sc_dev, "%s: FCTRL unfuse parity, write 0x%x\n",
956263725Strasz	    __func__, regVal & resetNpeParity);
957263725Strasz	EXP_BUS_WRITE_4(sa, EXP_FCTRL_OFFSET, regVal &~ resetNpeParity);
958263725Strasz
959263725Strasz	/*
960263725Strasz	 * Call NpeMgr function to stop the NPE again after the Feature Control
961263725Strasz	 * has unfused and Un-Reset the NPE and its associated Coprocessors.
962263725Strasz	 */
963263725Strasz	error = npe_cpu_stop(sc);
964265511Strasz
965265511Strasz	/* restore NPE configuration bus Control Register - Parity Settings  */
966255570Strasz	npe_reg_write(sc, IX_NPEDL_REG_OFFSET_CTL,
967255570Strasz	    (ixNpeConfigCtrlRegVal & IX_NPEDL_CONFIG_CTRL_REG_MASK));
968255570Strasz	DPRINTFn(2, sc->sc_dev, "%s: restore CTL => 0x%x\n",
969255570Strasz	    __func__, npe_reg_read(sc, IX_NPEDL_REG_OFFSET_CTL));
970255570Strasz
971255570Strasz	return error;
972255570Strasz#undef N
973255570Strasz}
974
975static int
976npe_cpu_start(struct ixpnpe_softc *sc)
977{
978	uint32_t ecsRegVal;
979
980	/*
981	 * Ensure only Background Context Stack Level is Active by turning off
982	 * the Active bit in each of the other Executing Context Stack levels.
983	 */
984	ecsRegVal = npe_ecs_reg_read(sc, IX_NPEDL_ECS_PRI_1_CTXT_REG_0);
985	ecsRegVal &= ~IX_NPEDL_MASK_ECS_REG_0_ACTIVE;
986	npe_ecs_reg_write(sc, IX_NPEDL_ECS_PRI_1_CTXT_REG_0, ecsRegVal);
987
988	ecsRegVal = npe_ecs_reg_read(sc, IX_NPEDL_ECS_PRI_2_CTXT_REG_0);
989	ecsRegVal &= ~IX_NPEDL_MASK_ECS_REG_0_ACTIVE;
990	npe_ecs_reg_write(sc, IX_NPEDL_ECS_PRI_2_CTXT_REG_0, ecsRegVal);
991
992	ecsRegVal = npe_ecs_reg_read(sc, IX_NPEDL_ECS_DBG_CTXT_REG_0);
993	ecsRegVal &= ~IX_NPEDL_MASK_ECS_REG_0_ACTIVE;
994	npe_ecs_reg_write(sc, IX_NPEDL_ECS_DBG_CTXT_REG_0, ecsRegVal);
995
996	/* clear the pipeline */
997	npe_issue_cmd(sc, IX_NPEDL_EXCTL_CMD_NPE_CLR_PIPE);
998
999	/* start NPE execution by issuing cmd through EXCTL register on NPE */
1000	npe_issue_cmd(sc, IX_NPEDL_EXCTL_CMD_NPE_START);
1001
1002	/*
1003	 * Check execution status of NPE to verify operation was successful.
1004	 */
1005	return npe_checkbits(sc,
1006	    IX_NPEDL_REG_OFFSET_EXCTL, IX_NPEDL_EXCTL_STATUS_RUN) ? 0 : EIO;
1007}
1008
1009static int
1010npe_cpu_stop(struct ixpnpe_softc *sc)
1011{
1012	/* stop NPE execution by issuing cmd through EXCTL register on NPE */
1013	npe_issue_cmd(sc, IX_NPEDL_EXCTL_CMD_NPE_STOP);
1014
1015	/* verify that NPE Stop was successful */
1016	return npe_checkbits(sc,
1017	    IX_NPEDL_REG_OFFSET_EXCTL, IX_NPEDL_EXCTL_STATUS_STOP) ? 0 : EIO;
1018}
1019
1020#define IX_NPEDL_REG_SIZE_BYTE            8
1021#define IX_NPEDL_REG_SIZE_SHORT           16
1022#define IX_NPEDL_REG_SIZE_WORD            32
1023
1024/*
1025 * Introduce extra read cycles after issuing read command to NPE
1026 * so that we read the register after the NPE has updated it
1027 * This is to overcome race condition between XScale and NPE
1028 */
1029#define IX_NPEDL_DELAY_READ_CYCLES        2
1030/*
1031 * To mask top three MSBs of 32bit word to download into NPE IMEM
1032 */
1033#define IX_NPEDL_MASK_UNUSED_IMEM_BITS    0x1FFFFFFF;
1034
1035static void
1036npe_cmd_issue_write(struct ixpnpe_softc *sc,
1037    uint32_t cmd, uint32_t addr, uint32_t data)
1038{
1039	npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXDATA, data);
1040	npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXAD, addr);
1041	npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXCTL, cmd);
1042}
1043
1044static uint32_t
1045npe_cmd_issue_read(struct ixpnpe_softc *sc, uint32_t cmd, uint32_t addr)
1046{
1047	uint32_t data;
1048	int i;
1049
1050	npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXAD, addr);
1051	npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXCTL, cmd);
1052	for (i = 0; i <= IX_NPEDL_DELAY_READ_CYCLES; i++)
1053		data = npe_reg_read(sc, IX_NPEDL_REG_OFFSET_EXDATA);
1054	return data;
1055}
1056
1057static int
1058npe_ins_write(struct ixpnpe_softc *sc, uint32_t addr, uint32_t data, int verify)
1059{
1060	DPRINTFn(4, sc->sc_dev, "%s(0x%x, 0x%x)\n", __func__, addr, data);
1061	npe_cmd_issue_write(sc, IX_NPEDL_EXCTL_CMD_WR_INS_MEM, addr, data);
1062	if (verify) {
1063		uint32_t rdata;
1064
1065		/*
1066		 * Write invalid data to this reg, so we can see if we're
1067		 * reading the EXDATA register too early.
1068		 */
1069		npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXDATA, ~data);
1070
1071		/*
1072		 * Disabled since top 3 MSB are not used for Azusa
1073		 * hardware Refer WR:IXA00053900
1074		 */
1075		data &= IX_NPEDL_MASK_UNUSED_IMEM_BITS;
1076
1077		rdata = npe_cmd_issue_read(sc, IX_NPEDL_EXCTL_CMD_RD_INS_MEM,
1078		    addr);
1079		rdata &= IX_NPEDL_MASK_UNUSED_IMEM_BITS;
1080
1081		if (data != rdata)
1082			return EIO;
1083	}
1084	return 0;
1085}
1086
1087static int
1088npe_data_write(struct ixpnpe_softc *sc, uint32_t addr, uint32_t data, int verify)
1089{
1090	DPRINTFn(4, sc->sc_dev, "%s(0x%x, 0x%x)\n", __func__, addr, data);
1091	npe_cmd_issue_write(sc, IX_NPEDL_EXCTL_CMD_WR_DATA_MEM, addr, data);
1092	if (verify) {
1093		/*
1094		 * Write invalid data to this reg, so we can see if we're
1095		 * reading the EXDATA register too early.
1096		 */
1097		npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXDATA, ~data);
1098		if (data != npe_cmd_issue_read(sc, IX_NPEDL_EXCTL_CMD_RD_DATA_MEM, addr))
1099			return EIO;
1100	}
1101	return 0;
1102}
1103
1104static void
1105npe_ecs_reg_write(struct ixpnpe_softc *sc, uint32_t reg, uint32_t data)
1106{
1107	npe_cmd_issue_write(sc, IX_NPEDL_EXCTL_CMD_WR_ECS_REG, reg, data);
1108}
1109
1110static uint32_t
1111npe_ecs_reg_read(struct ixpnpe_softc *sc, uint32_t reg)
1112{
1113	return npe_cmd_issue_read(sc, IX_NPEDL_EXCTL_CMD_RD_ECS_REG, reg);
1114}
1115
1116static void
1117npe_issue_cmd(struct ixpnpe_softc *sc, uint32_t command)
1118{
1119	npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXCTL, command);
1120}
1121
1122static void
1123npe_cpu_step_save(struct ixpnpe_softc *sc)
1124{
1125	/* turn off the halt bit by clearing Execution Count register. */
1126	/* save reg contents 1st and restore later */
1127	sc->savedExecCount = npe_reg_read(sc, IX_NPEDL_REG_OFFSET_EXCT);
1128	npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXCT, 0);
1129
1130	/* ensure that IF and IE are on (temporarily), so that we don't end up
1131	 * stepping forever */
1132	sc->savedEcsDbgCtxtReg2 = npe_ecs_reg_read(sc,
1133	    IX_NPEDL_ECS_DBG_CTXT_REG_2);
1134
1135	npe_ecs_reg_write(sc, IX_NPEDL_ECS_DBG_CTXT_REG_2,
1136	    (sc->savedEcsDbgCtxtReg2 | IX_NPEDL_MASK_ECS_DBG_REG_2_IF |
1137	     IX_NPEDL_MASK_ECS_DBG_REG_2_IE));
1138}
1139
1140static int
1141npe_cpu_step(struct ixpnpe_softc *sc, uint32_t npeInstruction,
1142    uint32_t ctxtNum, uint32_t ldur)
1143{
1144#define	IX_NPE_DL_MAX_NUM_OF_RETRIES	1000000
1145	uint32_t ecsDbgRegVal;
1146	uint32_t oldWatchcount, newWatchcount;
1147	int tries;
1148
1149	/* set the Active bit, and the LDUR, in the debug level */
1150	ecsDbgRegVal = IX_NPEDL_MASK_ECS_REG_0_ACTIVE |
1151	    (ldur << IX_NPEDL_OFFSET_ECS_REG_0_LDUR);
1152
1153	npe_ecs_reg_write(sc, IX_NPEDL_ECS_DBG_CTXT_REG_0, ecsDbgRegVal);
1154
1155	/*
1156	 * Set CCTXT at ECS DEBUG L3 to specify in which context to execute the
1157	 * instruction, and set SELCTXT at ECS DEBUG Level to specify which
1158	 * context store to access.
1159	 * Debug ECS Level Reg 1 has form  0x000n000n, where n = context number
1160	 */
1161	ecsDbgRegVal = (ctxtNum << IX_NPEDL_OFFSET_ECS_REG_1_CCTXT) |
1162	    (ctxtNum << IX_NPEDL_OFFSET_ECS_REG_1_SELCTXT);
1163
1164	npe_ecs_reg_write(sc, IX_NPEDL_ECS_DBG_CTXT_REG_1, ecsDbgRegVal);
1165
1166	/* clear the pipeline */
1167	npe_issue_cmd(sc, IX_NPEDL_EXCTL_CMD_NPE_CLR_PIPE);
1168
1169	/* load NPE instruction into the instruction register */
1170	npe_ecs_reg_write(sc, IX_NPEDL_ECS_INSTRUCT_REG, npeInstruction);
1171
1172	/* need this value later to wait for completion of NPE execution step */
1173	oldWatchcount = npe_reg_read(sc, IX_NPEDL_REG_OFFSET_WC);
1174
1175	/* issue a Step One command via the Execution Control register */
1176	npe_issue_cmd(sc, IX_NPEDL_EXCTL_CMD_NPE_STEP);
1177
1178	/*
1179	 * Force the XScale to wait until the NPE has finished execution step
1180	 * NOTE that this delay will be very small, just long enough to allow a
1181	 * single NPE instruction to complete execution; if instruction
1182	 * execution is not completed before timeout retries, exit the while
1183	 * loop.
1184	 */
1185	newWatchcount = npe_reg_read(sc, IX_NPEDL_REG_OFFSET_WC);
1186	for (tries = 0; tries < IX_NPE_DL_MAX_NUM_OF_RETRIES &&
1187	    newWatchcount == oldWatchcount; tries++) {
1188		/* Watch Count register incr's when NPE completes an inst */
1189		newWatchcount = npe_reg_read(sc, IX_NPEDL_REG_OFFSET_WC);
1190	}
1191	return (tries < IX_NPE_DL_MAX_NUM_OF_RETRIES) ? 0 : EIO;
1192#undef IX_NPE_DL_MAX_NUM_OF_RETRIES
1193}
1194
1195static void
1196npe_cpu_step_restore(struct ixpnpe_softc *sc)
1197{
1198	/* clear active bit in debug level */
1199	npe_ecs_reg_write(sc, IX_NPEDL_ECS_DBG_CTXT_REG_0, 0);
1200
1201	/* clear the pipeline */
1202	npe_issue_cmd(sc, IX_NPEDL_EXCTL_CMD_NPE_CLR_PIPE);
1203
1204	/* restore Execution Count register contents. */
1205	npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXCT, sc->savedExecCount);
1206
1207	/* restore IF and IE bits to original values */
1208	npe_ecs_reg_write(sc, IX_NPEDL_ECS_DBG_CTXT_REG_2, sc->savedEcsDbgCtxtReg2);
1209}
1210
1211static int
1212npe_logical_reg_read(struct ixpnpe_softc *sc,
1213    uint32_t regAddr, uint32_t regSize,
1214    uint32_t ctxtNum, uint32_t *regVal)
1215{
1216	uint32_t npeInstruction, mask;
1217	int error;
1218
1219	switch (regSize) {
1220	case IX_NPEDL_REG_SIZE_BYTE:
1221		npeInstruction = IX_NPEDL_INSTR_RD_REG_BYTE;
1222		mask = 0xff;
1223		break;
1224	case IX_NPEDL_REG_SIZE_SHORT:
1225		npeInstruction = IX_NPEDL_INSTR_RD_REG_SHORT;
1226		mask = 0xffff;
1227		break;
1228	case IX_NPEDL_REG_SIZE_WORD:
1229		npeInstruction = IX_NPEDL_INSTR_RD_REG_WORD;
1230		mask = 0xffffffff;
1231		break;
1232	default:
1233		return EINVAL;
1234	}
1235
1236	/* make regAddr be the SRC and DEST operands (e.g. movX d0, d0) */
1237	npeInstruction |= (regAddr << IX_NPEDL_OFFSET_INSTR_SRC) |
1238	    (regAddr << IX_NPEDL_OFFSET_INSTR_DEST);
1239
1240	/* step execution of NPE inst using Debug Executing Context stack */
1241	error = npe_cpu_step(sc, npeInstruction, ctxtNum,
1242	    IX_NPEDL_RD_INSTR_LDUR);
1243	if (error != 0) {
1244		DPRINTF(sc->sc_dev, "%s(0x%x, %u, %u), cannot step, error %d\n",
1245		    __func__, regAddr, regSize, ctxtNum, error);
1246		return error;
1247	}
1248	/* read value of register from Execution Data register */
1249	*regVal = npe_reg_read(sc, IX_NPEDL_REG_OFFSET_EXDATA);
1250
1251	/* align value from left to right */
1252	*regVal = (*regVal >> (IX_NPEDL_REG_SIZE_WORD - regSize)) & mask;
1253
1254	return 0;
1255}
1256
1257static int
1258npe_logical_reg_write(struct ixpnpe_softc *sc, uint32_t regAddr, uint32_t regVal,
1259    uint32_t regSize, uint32_t ctxtNum, int verify)
1260{
1261	int error;
1262
1263	DPRINTFn(4, sc->sc_dev, "%s(0x%x, 0x%x, %u, %u)\n",
1264	    __func__, regAddr, regVal, regSize, ctxtNum);
1265	if (regSize == IX_NPEDL_REG_SIZE_WORD) {
1266		/*
1267		 * NPE register addressing is left-to-right: e.g. |d0|d1|d2|d3|
1268		 * Write upper half-word (short) to |d0|d1|
1269		 */
1270		error = npe_logical_reg_write(sc, regAddr,
1271			     regVal >> IX_NPEDL_REG_SIZE_SHORT,
1272			     IX_NPEDL_REG_SIZE_SHORT, ctxtNum, verify);
1273		if (error != 0)
1274		    return error;
1275
1276		/* Write lower half-word (short) to |d2|d3| */
1277		error = npe_logical_reg_write(sc,
1278			     regAddr + sizeof(uint16_t),
1279			     regVal & 0xffff,
1280			     IX_NPEDL_REG_SIZE_SHORT, ctxtNum, verify);
1281	} else {
1282		uint32_t npeInstruction;
1283
1284		switch (regSize) {
1285		case IX_NPEDL_REG_SIZE_BYTE:
1286			npeInstruction = IX_NPEDL_INSTR_WR_REG_BYTE;
1287			regVal &= 0xff;
1288			break;
1289		case IX_NPEDL_REG_SIZE_SHORT:
1290			npeInstruction = IX_NPEDL_INSTR_WR_REG_SHORT;
1291			regVal &= 0xffff;
1292			break;
1293		default:
1294			return EINVAL;
1295		}
1296		/* fill dest operand field of inst with dest reg addr */
1297		npeInstruction |= (regAddr << IX_NPEDL_OFFSET_INSTR_DEST);
1298
1299		/* fill src operand field of inst with least-sig 5 bits of val*/
1300		npeInstruction |=
1301		    ((regVal & IX_NPEDL_MASK_IMMED_INSTR_SRC_DATA) <<
1302		     IX_NPEDL_OFFSET_INSTR_SRC);
1303
1304		/* fill coprocessor field of inst with most-sig 11 bits of val*/
1305		npeInstruction |=
1306		    ((regVal & IX_NPEDL_MASK_IMMED_INSTR_COPROC_DATA) <<
1307		     IX_NPEDL_DISPLACE_IMMED_INSTR_COPROC_DATA);
1308
1309		/* step execution of NPE intruction using Debug ECS */
1310		error = npe_cpu_step(sc, npeInstruction,
1311		    ctxtNum, IX_NPEDL_WR_INSTR_LDUR);
1312	}
1313	if (error != 0) {
1314		DPRINTF(sc->sc_dev, "%s(0x%x, 0x%x, %u, %u), error %u "
1315		    "writing reg\n", __func__, regAddr, regVal, regSize,
1316		    ctxtNum, error);
1317		return error;
1318	}
1319	if (verify) {
1320		uint32_t retRegVal;
1321
1322		error = npe_logical_reg_read(sc, regAddr, regSize, ctxtNum,
1323		    &retRegVal);
1324		if (error == 0 && regVal != retRegVal)
1325			error = EIO;	/* XXX ambiguous */
1326	}
1327	return error;
1328}
1329
1330/*
1331 * There are 32 physical registers used in an NPE.  These are
1332 * treated as 16 pairs of 32-bit registers.  To write one of the pair,
1333 * write the pair number (0-16) to the REGMAP for Context 0.  Then write
1334 * the value to register  0 or 4 in the regfile, depending on which
1335 * register of the pair is to be written
1336 */
1337static int
1338npe_physical_reg_write(struct ixpnpe_softc *sc,
1339    uint32_t regAddr, uint32_t regValue, int verify)
1340{
1341	int error;
1342
1343	/*
1344	 * Set REGMAP for context 0 to (regAddr >> 1) to choose which pair
1345	 * (0-16) of physical registers to write .
1346	 */
1347	error = npe_logical_reg_write(sc, IX_NPEDL_CTXT_REG_ADDR_REGMAP,
1348		   (regAddr >> IX_NPEDL_OFFSET_PHYS_REG_ADDR_REGMAP),
1349		   IX_NPEDL_REG_SIZE_SHORT, 0, verify);
1350	if (error == 0) {
1351	    /* regAddr = 0 or 4  */
1352	    regAddr = (regAddr & IX_NPEDL_MASK_PHYS_REG_ADDR_LOGICAL_ADDR) *
1353		sizeof(uint32_t);
1354	    error = npe_logical_reg_write(sc, regAddr, regValue,
1355		IX_NPEDL_REG_SIZE_WORD, 0, verify);
1356	}
1357	return error;
1358}
1359
1360static int
1361npe_ctx_reg_write(struct ixpnpe_softc *sc, uint32_t ctxtNum,
1362    uint32_t ctxtReg, uint32_t ctxtRegVal, int verify)
1363{
1364	DPRINTFn(4, sc->sc_dev, "%s(%u, %u, %u)\n",
1365	    __func__, ctxtNum, ctxtReg, ctxtRegVal);
1366	/*
1367	 * Context 0 has no STARTPC. Instead, this value is used to set
1368	 * NextPC for Background ECS, to set where NPE starts executing code
1369	 */
1370	if (ctxtNum == 0 && ctxtReg == IX_NPEDL_CTXT_REG_STARTPC) {
1371		/* read BG_CTXT_REG_0, update NEXTPC bits, & write back to reg*/
1372		uint32_t v = npe_ecs_reg_read(sc, IX_NPEDL_ECS_BG_CTXT_REG_0);
1373		v &= ~IX_NPEDL_MASK_ECS_REG_0_NEXTPC;
1374		v |= (ctxtRegVal << IX_NPEDL_OFFSET_ECS_REG_0_NEXTPC) &
1375		    IX_NPEDL_MASK_ECS_REG_0_NEXTPC;
1376
1377		npe_ecs_reg_write(sc, IX_NPEDL_ECS_BG_CTXT_REG_0, v);
1378		return 0;
1379	} else {
1380		static const struct {
1381			uint32_t regAddress;
1382			uint32_t regSize;
1383		} regAccInfo[IX_NPEDL_CTXT_REG_MAX] = {
1384			{ IX_NPEDL_CTXT_REG_ADDR_STEVT,
1385			  IX_NPEDL_REG_SIZE_BYTE },
1386			{ IX_NPEDL_CTXT_REG_ADDR_STARTPC,
1387			  IX_NPEDL_REG_SIZE_SHORT },
1388			{ IX_NPEDL_CTXT_REG_ADDR_REGMAP,
1389			  IX_NPEDL_REG_SIZE_SHORT },
1390			{ IX_NPEDL_CTXT_REG_ADDR_CINDEX,
1391			  IX_NPEDL_REG_SIZE_BYTE }
1392		};
1393		return npe_logical_reg_write(sc, regAccInfo[ctxtReg].regAddress,
1394			ctxtRegVal, regAccInfo[ctxtReg].regSize, ctxtNum, verify);
1395	}
1396}
1397
1398/*
1399 * NPE Mailbox support.
1400 */
1401#define	IX_NPEMH_MAXTRIES	100000
1402
1403static int
1404ofifo_wait(struct ixpnpe_softc *sc)
1405{
1406	int i;
1407
1408	for (i = 0; i < IX_NPEMH_MAXTRIES; i++) {
1409		if (npe_reg_read(sc, IX_NPESTAT) & IX_NPESTAT_OFNE)
1410			return 1;
1411		DELAY(10);
1412	}
1413	device_printf(sc->sc_dev, "%s: timeout, last status 0x%x\n",
1414	    __func__, npe_reg_read(sc, IX_NPESTAT));
1415	return 0;
1416}
1417
1418static int
1419getmsg(struct ixpnpe_softc *sc, uint32_t msg[2])
1420{
1421	mtx_assert(&sc->sc_mtx, MA_OWNED);
1422
1423	if (!ofifo_wait(sc))
1424		return EAGAIN;
1425	msg[0] = npe_reg_read(sc, IX_NPEFIFO);
1426	DPRINTF(sc->sc_dev, "%s: msg0 0x%x\n", __func__, msg[0]);
1427	if (!ofifo_wait(sc))
1428		return EAGAIN;
1429	msg[1] = npe_reg_read(sc, IX_NPEFIFO);
1430	DPRINTF(sc->sc_dev, "%s: msg1 0x%x\n", __func__, msg[1]);
1431	return 0;
1432}
1433
1434static void
1435ixpnpe_intr(void *arg)
1436{
1437	struct ixpnpe_softc *sc = arg;
1438	uint32_t status;
1439
1440	mtx_lock(&sc->sc_mtx);
1441	status = npe_reg_read(sc, IX_NPESTAT);
1442	DPRINTF(sc->sc_dev, "%s: status 0x%x\n", __func__, status);
1443	if ((status & IX_NPESTAT_OFINT) == 0) {
1444		/* NB: should not happen */
1445		device_printf(sc->sc_dev, "%s: status 0x%x\n",
1446		    __func__, status);
1447		/* XXX must silence interrupt? */
1448		mtx_unlock(&sc->sc_mtx);
1449		return;
1450	}
1451	/*
1452	 * A message is waiting in the output FIFO, copy it so
1453	 * the interrupt will be silenced.
1454	 */
1455	if (getmsg(sc, sc->sc_msg) == 0)
1456		sc->sc_msgwaiting = 1;
1457	mtx_unlock(&sc->sc_mtx);
1458}
1459
1460static int
1461ififo_wait(struct ixpnpe_softc *sc)
1462{
1463	int i;
1464
1465	for (i = 0; i < IX_NPEMH_MAXTRIES; i++) {
1466		if (npe_reg_read(sc, IX_NPESTAT) & IX_NPESTAT_IFNF)
1467			return 1;
1468		DELAY(10);
1469	}
1470	device_printf(sc->sc_dev, "%s: timeout, last status 0x%x\n",
1471	    __func__, npe_reg_read(sc, IX_NPESTAT));
1472	return 0;
1473}
1474
1475static int
1476putmsg(struct ixpnpe_softc *sc, const uint32_t msg[2])
1477{
1478	mtx_assert(&sc->sc_mtx, MA_OWNED);
1479
1480	DPRINTF(sc->sc_dev, "%s: msg 0x%x:0x%x\n", __func__, msg[0], msg[1]);
1481	if (!ififo_wait(sc))
1482		return EIO;
1483	npe_reg_write(sc, IX_NPEFIFO, msg[0]);
1484	if (!ififo_wait(sc))
1485		return EIO;
1486	npe_reg_write(sc, IX_NPEFIFO, msg[1]);
1487
1488	return 0;
1489}
1490
1491/*
1492 * Send a msg to the NPE and wait for a reply.  We spin as
1493 * we may be called early with interrupts not properly setup.
1494 */
1495int
1496ixpnpe_sendandrecvmsg_sync(struct ixpnpe_softc *sc,
1497	const uint32_t send[2], uint32_t recv[2])
1498{
1499	int error;
1500
1501	mtx_lock(&sc->sc_mtx);
1502	error = putmsg(sc, send);
1503	if (error == 0)
1504		error = getmsg(sc, recv);
1505	mtx_unlock(&sc->sc_mtx);
1506
1507	return error;
1508}
1509
1510/*
1511 * Send a msg to the NPE w/o waiting for a reply.
1512 */
1513int
1514ixpnpe_sendmsg_async(struct ixpnpe_softc *sc, const uint32_t msg[2])
1515{
1516	int error;
1517
1518	mtx_lock(&sc->sc_mtx);
1519	error = putmsg(sc, msg);
1520	mtx_unlock(&sc->sc_mtx);
1521
1522	return error;
1523}
1524
1525static int
1526recvmsg_locked(struct ixpnpe_softc *sc, uint32_t msg[2])
1527{
1528	mtx_assert(&sc->sc_mtx, MA_OWNED);
1529
1530	DPRINTF(sc->sc_dev, "%s: msgwaiting %d\n", __func__, sc->sc_msgwaiting);
1531	if (sc->sc_msgwaiting) {
1532		msg[0] = sc->sc_msg[0];
1533		msg[1] = sc->sc_msg[1];
1534		sc->sc_msgwaiting = 0;
1535		return 0;
1536	}
1537	return EAGAIN;
1538}
1539
1540/*
1541 * Receive any msg previously received from the NPE. If nothing
1542 * is available we return EAGAIN and the caller is required to
1543 * do a synchronous receive or try again later.
1544 */
1545int
1546ixpnpe_recvmsg_async(struct ixpnpe_softc *sc, uint32_t msg[2])
1547{
1548	int error;
1549
1550	mtx_lock(&sc->sc_mtx);
1551	error = recvmsg_locked(sc, msg);
1552	mtx_unlock(&sc->sc_mtx);
1553
1554	return error;
1555}
1556
1557/*
1558 * Receive a msg from the NPE.  If one was received asynchronously
1559 * then it's returned; otherwise we poll synchronously.
1560 */
1561int
1562ixpnpe_recvmsg_sync(struct ixpnpe_softc *sc, uint32_t msg[2])
1563{
1564	int error;
1565
1566	mtx_lock(&sc->sc_mtx);
1567	error = recvmsg_locked(sc, msg);
1568	if (error == EAGAIN)
1569		error = getmsg(sc, msg);
1570	mtx_unlock(&sc->sc_mtx);
1571
1572	return error;
1573}
1574