1 1.17 rin /* $NetBSD: ixp425_npe.c,v 1.17 2023/06/17 11:57:49 rin Exp $ */ 2 1.1 scw 3 1.1 scw /*- 4 1.1 scw * Copyright (c) 2006 Sam Leffler, Errno Consulting 5 1.1 scw * All rights reserved. 6 1.1 scw * 7 1.1 scw * Redistribution and use in source and binary forms, with or without 8 1.1 scw * modification, are permitted provided that the following conditions 9 1.1 scw * are met: 10 1.1 scw * 1. Redistributions of source code must retain the above copyright 11 1.1 scw * notice, this list of conditions and the following disclaimer, 12 1.1 scw * without modification. 13 1.1 scw * 2. Redistributions in binary form must reproduce at minimum a disclaimer 14 1.1 scw * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 15 1.1 scw * redistribution must be conditioned upon including a substantially 16 1.1 scw * similar Disclaimer requirement for further binary redistribution. 17 1.1 scw * 18 1.1 scw * NO WARRANTY 19 1.1 scw * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 1.1 scw * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 1.1 scw * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 22 1.1 scw * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 23 1.1 scw * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 24 1.1 scw * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 scw * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 scw * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 27 1.1 scw * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 scw * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 29 1.1 scw * THE POSSIBILITY OF SUCH DAMAGES. 30 1.1 scw */ 31 1.1 scw 32 1.1 scw /*- 33 1.1 scw * Copyright (c) 2001-2005, Intel Corporation. 34 1.1 scw * All rights reserved. 35 1.1 scw * 36 1.1 scw * Redistribution and use in source and binary forms, with or without 37 1.1 scw * modification, are permitted provided that the following conditions 38 1.1 scw * are met: 39 1.1 scw * 1. Redistributions of source code must retain the above copyright 40 1.1 scw * notice, this list of conditions and the following disclaimer. 41 1.1 scw * 2. Redistributions in binary form must reproduce the above copyright 42 1.1 scw * notice, this list of conditions and the following disclaimer in the 43 1.1 scw * documentation and/or other materials provided with the distribution. 44 1.1 scw * 3. Neither the name of the Intel Corporation nor the names of its contributors 45 1.1 scw * may be used to endorse or promote products derived from this software 46 1.1 scw * without specific prior written permission. 47 1.1 scw * 48 1.1 scw * 49 1.1 scw * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 50 1.1 scw * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 51 1.1 scw * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 52 1.1 scw * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 53 1.1 scw * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 54 1.1 scw * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 55 1.1 scw * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 56 1.1 scw * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 57 1.1 scw * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 58 1.1 scw * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 59 1.1 scw * SUCH DAMAGE. 60 1.1 scw */ 61 1.1 scw #include <sys/cdefs.h> 62 1.1 scw #if 0 63 1.1 scw __FBSDID("$FreeBSD: src/sys/arm/xscale/ixp425/ixp425_npe.c,v 1.1 2006/11/19 23:55:23 sam Exp $"); 64 1.1 scw #endif 65 1.17 rin __KERNEL_RCSID(0, "$NetBSD: ixp425_npe.c,v 1.17 2023/06/17 11:57:49 rin Exp $"); 66 1.1 scw 67 1.1 scw /* 68 1.1 scw * Intel XScale Network Processing Engine (NPE) support. 69 1.1 scw * 70 1.1 scw * Each NPE has an ixpnpeX device associated with it that is 71 1.1 scw * attached at boot. Depending on the microcode loaded into 72 1.1 scw * an NPE there may be an Ethernet interface (npeX) or some 73 1.1 scw * other network interface (e.g. for ATM). This file has support 74 1.1 scw * for loading microcode images and the associated NPE CPU 75 1.1 scw * manipulations (start, stop, reset). 76 1.1 scw * 77 1.1 scw * The code here basically replaces the npeDl and npeMh classes 78 1.1 scw * in the Intel Access Library (IAL). 79 1.1 scw * 80 1.1 scw * NB: Microcode images are loaded with firmware(9). To 81 1.1 scw * include microcode in a static kernel include the 82 1.1 scw * ixpnpe_fw device. Otherwise the firmware will be 83 1.1 scw * automatically loaded from the filesystem. 84 1.1 scw */ 85 1.1 scw #include <sys/param.h> 86 1.1 scw #include <sys/systm.h> 87 1.1 scw #include <sys/kernel.h> 88 1.10 skrll #include <sys/mutex.h> 89 1.1 scw #include <sys/time.h> 90 1.1 scw #include <sys/proc.h> 91 1.1 scw 92 1.1 scw #include <dev/firmload.h> 93 1.1 scw 94 1.8 dyoung #include <sys/bus.h> 95 1.1 scw #include <machine/cpu.h> 96 1.1 scw #include <machine/intr.h> 97 1.1 scw 98 1.1 scw #include <arm/xscale/ixp425reg.h> 99 1.1 scw #include <arm/xscale/ixp425var.h> 100 1.1 scw #include <arm/xscale/ixp425_ixmevar.h> 101 1.1 scw 102 1.1 scw #include <arm/xscale/ixp425_npereg.h> 103 1.1 scw #include <arm/xscale/ixp425_npevar.h> 104 1.4 msaitoh #include <arm/xscale/ixp425_if_npereg.h> 105 1.1 scw 106 1.1 scw #include "locators.h" 107 1.1 scw 108 1.17 rin extern char _binary_IxNpeMicrocode_dat_start[]; 109 1.1 scw 110 1.1 scw #define IX_NPEDL_NPEIMAGE_FIELD_MASK 0xff 111 1.1 scw 112 1.1 scw /* used to read download map from version in microcode image */ 113 1.1 scw #define IX_NPEDL_BLOCK_TYPE_INSTRUCTION 0x00000000 114 1.1 scw #define IX_NPEDL_BLOCK_TYPE_DATA 0x00000001 115 1.1 scw #define IX_NPEDL_BLOCK_TYPE_STATE 0x00000002 116 1.1 scw #define IX_NPEDL_END_OF_DOWNLOAD_MAP 0x0000000F 117 1.1 scw 118 1.1 scw /* 119 1.1 scw * masks used to extract address info from State information context 120 1.1 scw * register addresses as read from microcode image 121 1.1 scw */ 122 1.1 scw #define IX_NPEDL_MASK_STATE_ADDR_CTXT_REG 0x0000000F 123 1.1 scw #define IX_NPEDL_MASK_STATE_ADDR_CTXT_NUM 0x000000F0 124 1.1 scw 125 1.1 scw /* LSB offset of Context Number field in State-Info Context Address */ 126 1.1 scw #define IX_NPEDL_OFFSET_STATE_ADDR_CTXT_NUM 4 127 1.1 scw 128 1.1 scw /* size (in words) of single State Information entry (ctxt reg address|data) */ 129 1.1 scw #define IX_NPEDL_STATE_INFO_ENTRY_SIZE 2 130 1.1 scw 131 1.1 scw typedef struct { 132 1.1 scw uint32_t type; 133 1.1 scw uint32_t offset; 134 1.1 scw } IxNpeDlNpeMgrDownloadMapBlockEntry; 135 1.1 scw 136 1.1 scw typedef union { 137 1.1 scw IxNpeDlNpeMgrDownloadMapBlockEntry block; 138 1.1 scw uint32_t eodmMarker; 139 1.1 scw } IxNpeDlNpeMgrDownloadMapEntry; 140 1.1 scw 141 1.1 scw typedef struct { 142 1.1 scw /* 1st entry in the download map (there may be more than one) */ 143 1.1 scw IxNpeDlNpeMgrDownloadMapEntry entry[1]; 144 1.1 scw } IxNpeDlNpeMgrDownloadMap; 145 1.1 scw 146 1.1 scw /* used to access an instruction or data block in a microcode image */ 147 1.1 scw typedef struct { 148 1.1 scw uint32_t npeMemAddress; 149 1.1 scw uint32_t size; 150 1.1 scw uint32_t data[1]; 151 1.1 scw } IxNpeDlNpeMgrCodeBlock; 152 1.1 scw 153 1.1 scw /* used to access each Context Reg entry state-information block */ 154 1.1 scw typedef struct { 155 1.1 scw uint32_t addressInfo; 156 1.1 scw uint32_t value; 157 1.1 scw } IxNpeDlNpeMgrStateInfoCtxtRegEntry; 158 1.1 scw 159 1.1 scw /* used to access a state-information block in a microcode image */ 160 1.1 scw typedef struct { 161 1.1 scw uint32_t size; 162 1.1 scw IxNpeDlNpeMgrStateInfoCtxtRegEntry ctxtRegEntry[1]; 163 1.1 scw } IxNpeDlNpeMgrStateInfoBlock; 164 1.1 scw 165 1.1 scw static int npe_debug = 0; 166 1.1 scw #define DPRINTF(dev, fmt, ...) do { \ 167 1.1 scw if (npe_debug) printf(fmt, __VA_ARGS__); \ 168 1.1 scw } while (0) 169 1.1 scw #define DPRINTFn(n, dev, fmt, ...) do { \ 170 1.1 scw if (npe_debug >= n) printf(fmt, __VA_ARGS__); \ 171 1.1 scw } while (0) 172 1.1 scw 173 1.1 scw static int npe_checkbits(struct ixpnpe_softc *, uint32_t reg, uint32_t); 174 1.1 scw static int npe_isstopped(struct ixpnpe_softc *); 175 1.1 scw static int npe_load_ins(struct ixpnpe_softc *, 176 1.1 scw const IxNpeDlNpeMgrCodeBlock *bp, int verify); 177 1.1 scw static int npe_load_data(struct ixpnpe_softc *, 178 1.1 scw const IxNpeDlNpeMgrCodeBlock *bp, int verify); 179 1.1 scw static int npe_load_stateinfo(struct ixpnpe_softc *, 180 1.1 scw const IxNpeDlNpeMgrStateInfoBlock *bp, int verify); 181 1.1 scw static int npe_load_image(struct ixpnpe_softc *, 182 1.1 scw const uint32_t *imageCodePtr, int verify); 183 1.1 scw static int npe_cpu_reset(struct ixpnpe_softc *); 184 1.1 scw static int npe_cpu_start(struct ixpnpe_softc *); 185 1.1 scw static int npe_cpu_stop(struct ixpnpe_softc *); 186 1.1 scw static void npe_cmd_issue_write(struct ixpnpe_softc *, 187 1.1 scw uint32_t cmd, uint32_t addr, uint32_t data); 188 1.1 scw static uint32_t npe_cmd_issue_read(struct ixpnpe_softc *, 189 1.1 scw uint32_t cmd, uint32_t addr); 190 1.1 scw static int npe_ins_write(struct ixpnpe_softc *, 191 1.1 scw uint32_t addr, uint32_t data, int verify); 192 1.1 scw static int npe_data_write(struct ixpnpe_softc *, 193 1.1 scw uint32_t addr, uint32_t data, int verify); 194 1.1 scw static void npe_ecs_reg_write(struct ixpnpe_softc *, 195 1.1 scw uint32_t reg, uint32_t data); 196 1.1 scw static uint32_t npe_ecs_reg_read(struct ixpnpe_softc *, uint32_t reg); 197 1.1 scw static void npe_issue_cmd(struct ixpnpe_softc *, uint32_t command); 198 1.1 scw static void npe_cpu_step_save(struct ixpnpe_softc *); 199 1.1 scw static int npe_cpu_step(struct ixpnpe_softc *, uint32_t npeInstruction, 200 1.1 scw uint32_t ctxtNum, uint32_t ldur); 201 1.1 scw static void npe_cpu_step_restore(struct ixpnpe_softc *); 202 1.1 scw static int npe_logical_reg_read(struct ixpnpe_softc *, 203 1.1 scw uint32_t regAddr, uint32_t regSize, 204 1.1 scw uint32_t ctxtNum, uint32_t *regVal); 205 1.1 scw static int npe_logical_reg_write(struct ixpnpe_softc *, 206 1.1 scw uint32_t regAddr, uint32_t regVal, 207 1.1 scw uint32_t regSize, uint32_t ctxtNum, int verify); 208 1.1 scw static int npe_physical_reg_write(struct ixpnpe_softc *, 209 1.1 scw uint32_t regAddr, uint32_t regValue, int verify); 210 1.1 scw static int npe_ctx_reg_write(struct ixpnpe_softc *, uint32_t ctxtNum, 211 1.1 scw uint32_t ctxtReg, uint32_t ctxtRegVal, int verify); 212 1.1 scw 213 1.1 scw static int ixpnpe_intr(void *arg); 214 1.1 scw 215 1.1 scw static uint32_t 216 1.1 scw npe_reg_read(struct ixpnpe_softc *sc, bus_size_t off) 217 1.1 scw { 218 1.1 scw uint32_t v = bus_space_read_4(sc->sc_iot, sc->sc_ioh, off); 219 1.1 scw DPRINTFn(9, sc->sc_dev, "%s(0x%lx) => 0x%x\n", __func__, off, v); 220 1.1 scw return v; 221 1.1 scw } 222 1.1 scw 223 1.1 scw static void 224 1.1 scw npe_reg_write(struct ixpnpe_softc *sc, bus_size_t off, uint32_t val) 225 1.1 scw { 226 1.1 scw DPRINTFn(9, sc->sc_dev, "%s(0x%lx, 0x%x)\n", __func__, off, val); 227 1.1 scw bus_space_write_4(sc->sc_iot, sc->sc_ioh, off, val); 228 1.1 scw } 229 1.1 scw 230 1.9 msaitoh static int ixpnpe_match(device_t, cfdata_t, void *); 231 1.9 msaitoh static void ixpnpe_attach(device_t, device_t, void *); 232 1.1 scw static int ixpnpe_print(void *, const char *); 233 1.9 msaitoh static int ixpnpe_search(device_t, cfdata_t, const int *, void *); 234 1.1 scw 235 1.9 msaitoh CFATTACH_DECL_NEW(ixpnpe, sizeof(struct ixpnpe_softc), 236 1.1 scw ixpnpe_match, ixpnpe_attach, NULL, NULL); 237 1.1 scw 238 1.1 scw static int 239 1.9 msaitoh ixpnpe_match(device_t parent, cfdata_t match, void *arg) 240 1.1 scw { 241 1.1 scw struct ixme_attach_args *ixa = arg; 242 1.1 scw 243 1.1 scw return (ixa->ixa_npe == 1 || ixa->ixa_npe == 2); 244 1.1 scw } 245 1.1 scw 246 1.1 scw static void 247 1.9 msaitoh ixpnpe_attach(device_t parent, device_t self, void *arg) 248 1.1 scw { 249 1.9 msaitoh struct ixpnpe_softc *sc = device_private(self); 250 1.1 scw struct ixme_attach_args *ixa = arg; 251 1.1 scw bus_addr_t base; 252 1.1 scw int irq; 253 1.1 scw 254 1.1 scw aprint_naive("\n"); 255 1.1 scw aprint_normal("\n"); 256 1.1 scw 257 1.9 msaitoh sc->sc_dev = self; 258 1.1 scw sc->sc_iot = ixa->ixa_iot; 259 1.1 scw sc->sc_dt = ixa->ixa_dt; 260 1.1 scw sc->sc_unit = ixa->ixa_npe; 261 1.1 scw 262 1.10 skrll mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_VM); 263 1.1 scw 264 1.1 scw /* XXX: Check features to ensure this NPE is enabled */ 265 1.1 scw 266 1.1 scw switch (ixa->ixa_npe) { 267 1.1 scw default: 268 1.9 msaitoh panic("%s: Invalid NPE!", device_xname(self)); 269 1.1 scw 270 1.1 scw case 1: 271 1.1 scw base = IXP425_NPE_B_HWBASE; 272 1.1 scw sc->sc_size = IXP425_NPE_B_SIZE; 273 1.1 scw irq = IXP425_INT_NPE_B; 274 1.1 scw 275 1.1 scw /* size of instruction memory */ 276 1.1 scw sc->insMemSize = IX_NPEDL_INS_MEMSIZE_WORDS_NPEB; 277 1.1 scw /* size of data memory */ 278 1.1 scw sc->dataMemSize = IX_NPEDL_DATA_MEMSIZE_WORDS_NPEB; 279 1.1 scw break; 280 1.1 scw 281 1.1 scw case 2: 282 1.1 scw base = IXP425_NPE_C_HWBASE; 283 1.1 scw sc->sc_size = IXP425_NPE_C_SIZE; 284 1.1 scw irq = IXP425_INT_NPE_C; 285 1.1 scw 286 1.1 scw /* size of instruction memory */ 287 1.1 scw sc->insMemSize = IX_NPEDL_INS_MEMSIZE_WORDS_NPEC; 288 1.1 scw /* size of data memory */ 289 1.1 scw sc->dataMemSize = IX_NPEDL_DATA_MEMSIZE_WORDS_NPEC; 290 1.1 scw break; 291 1.1 scw } 292 1.1 scw if (bus_space_map(sc->sc_iot, base, sc->sc_size, 0, &sc->sc_ioh)) 293 1.9 msaitoh panic("%s: Cannot map registers", device_xname(self)); 294 1.1 scw 295 1.1 scw /* 296 1.1 scw * Setup IRQ and handler for NPE message support. 297 1.1 scw */ 298 1.1 scw sc->sc_ih = ixp425_intr_establish(irq, IPL_NET, ixpnpe_intr, sc); 299 1.1 scw if (sc->sc_ih == NULL) 300 1.9 msaitoh panic("%s: Unable to establish irq %u", device_xname(self), irq); 301 1.1 scw /* enable output fifo interrupts (NB: must also set OFIFO Write Enable) */ 302 1.1 scw npe_reg_write(sc, IX_NPECTL, 303 1.1 scw npe_reg_read(sc, IX_NPECTL) | (IX_NPECTL_OFE | IX_NPECTL_OFWE)); 304 1.1 scw 305 1.12 thorpej config_search(self, ixa, 306 1.15 thorpej CFARGS(.search = ixpnpe_search)); 307 1.1 scw } 308 1.1 scw 309 1.1 scw static int 310 1.1 scw ixpnpe_print(void *arg, const char *name) 311 1.1 scw { 312 1.1 scw 313 1.1 scw return (UNCONF); 314 1.1 scw } 315 1.1 scw 316 1.1 scw static int 317 1.9 msaitoh ixpnpe_search(device_t parent, cfdata_t cf, const int *ldesc, void *arg) 318 1.1 scw { 319 1.9 msaitoh struct ixpnpe_softc *sc = device_private(parent); 320 1.1 scw struct ixme_attach_args *ixa = arg; 321 1.1 scw struct ixpnpe_attach_args na; 322 1.1 scw 323 1.1 scw na.na_unit = ixa->ixa_npe; 324 1.1 scw na.na_phy = cf->cf_loc[IXPNPECF_PHY]; 325 1.1 scw na.na_npe = sc; 326 1.1 scw na.na_iot = ixa->ixa_iot; 327 1.1 scw na.na_dt = ixa->ixa_dt; 328 1.1 scw 329 1.12 thorpej if (config_probe(parent, cf, &na)) { 330 1.15 thorpej config_attach(parent, cf, &na, ixpnpe_print, CFARGS_NONE); 331 1.1 scw return (1); 332 1.1 scw } 333 1.1 scw 334 1.1 scw return (0); 335 1.1 scw } 336 1.1 scw 337 1.1 scw int 338 1.1 scw ixpnpe_stopandreset(struct ixpnpe_softc *sc) 339 1.1 scw { 340 1.1 scw int error; 341 1.1 scw 342 1.10 skrll mutex_enter(&sc->sc_lock); 343 1.1 scw error = npe_cpu_stop(sc); /* stop NPE */ 344 1.1 scw if (error == 0) 345 1.1 scw error = npe_cpu_reset(sc); /* reset it */ 346 1.1 scw if (error == 0) 347 1.1 scw sc->started = 0; /* mark stopped */ 348 1.10 skrll mutex_exit(&sc->sc_lock); 349 1.1 scw 350 1.1 scw DPRINTF(sc->sc_dev, "%s: error %d\n", __func__, error); 351 1.1 scw return error; 352 1.1 scw } 353 1.1 scw 354 1.1 scw static int 355 1.1 scw ixpnpe_start_locked(struct ixpnpe_softc *sc) 356 1.1 scw { 357 1.1 scw int error; 358 1.1 scw 359 1.1 scw if (!sc->started) { 360 1.1 scw error = npe_cpu_start(sc); 361 1.1 scw if (error == 0) 362 1.1 scw sc->started = 1; 363 1.1 scw } else 364 1.1 scw error = 0; 365 1.1 scw 366 1.1 scw DPRINTF(sc->sc_dev, "%s: error %d\n", __func__, error); 367 1.1 scw return error; 368 1.1 scw } 369 1.1 scw 370 1.1 scw int 371 1.1 scw ixpnpe_start(struct ixpnpe_softc *sc) 372 1.1 scw { 373 1.1 scw int ret; 374 1.1 scw 375 1.10 skrll mutex_enter(&sc->sc_lock); 376 1.1 scw ret = ixpnpe_start_locked(sc); 377 1.10 skrll mutex_exit(&sc->sc_lock); 378 1.1 scw return (ret); 379 1.1 scw } 380 1.1 scw 381 1.1 scw int 382 1.1 scw ixpnpe_stop(struct ixpnpe_softc *sc) 383 1.1 scw { 384 1.1 scw int error; 385 1.1 scw 386 1.10 skrll mutex_enter(&sc->sc_lock); 387 1.1 scw error = npe_cpu_stop(sc); 388 1.1 scw if (error == 0) 389 1.1 scw sc->started = 0; 390 1.10 skrll mutex_exit(&sc->sc_lock); 391 1.1 scw 392 1.1 scw DPRINTF(sc->sc_dev, "%s: error %d\n", __func__, error); 393 1.1 scw return error; 394 1.1 scw } 395 1.1 scw 396 1.1 scw /* 397 1.1 scw * Indicates the start of an NPE Image, in new NPE Image Library format. 398 1.13 andvar * 2 consecutive occurrences indicates the end of the NPE Image Library 399 1.1 scw */ 400 1.1 scw #define NPE_IMAGE_MARKER 0xfeedf00d 401 1.1 scw 402 1.1 scw /* 403 1.1 scw * NPE Image Header definition, used in new NPE Image Library format 404 1.1 scw */ 405 1.1 scw typedef struct { 406 1.1 scw uint32_t marker; 407 1.1 scw uint32_t id; 408 1.1 scw uint32_t size; 409 1.1 scw } IxNpeDlImageMgrImageHeader; 410 1.1 scw 411 1.1 scw static int 412 1.1 scw npe_findimage(struct ixpnpe_softc *sc, 413 1.1 scw const uint32_t *imageLibrary, uint32_t imageId, 414 1.1 scw const uint32_t **imagePtr, uint32_t *imageSize) 415 1.1 scw { 416 1.1 scw const IxNpeDlImageMgrImageHeader *image; 417 1.1 scw uint32_t offset = 0; 418 1.1 scw 419 1.1 scw while (imageLibrary[offset] == NPE_IMAGE_MARKER) { 420 1.1 scw image = (const IxNpeDlImageMgrImageHeader *)&imageLibrary[offset]; 421 1.1 scw offset += sizeof(IxNpeDlImageMgrImageHeader)/sizeof(uint32_t); 422 1.1 scw 423 1.1 scw DPRINTF(sc->sc_dev, "%s: off %u mark 0x%x id 0x%x size %u\n", 424 1.1 scw __func__, offset, image->marker, image->id, image->size); 425 1.1 scw if (image->id == imageId) { 426 1.1 scw *imagePtr = imageLibrary + offset; 427 1.1 scw *imageSize = image->size; 428 1.1 scw return 0; 429 1.1 scw } 430 1.1 scw /* 2 consecutive NPE_IMAGE_MARKER's indicates end of library */ 431 1.1 scw if (image->id == NPE_IMAGE_MARKER) { 432 1.1 scw printf("%s: imageId 0x%08x not found in image library header\n", 433 1.9 msaitoh device_xname(sc->sc_dev), imageId); 434 1.1 scw /* reached end of library, image not found */ 435 1.1 scw return EIO; 436 1.1 scw } 437 1.1 scw offset += image->size; 438 1.1 scw } 439 1.1 scw return EIO; 440 1.1 scw } 441 1.1 scw 442 1.1 scw int 443 1.1 scw ixpnpe_init(struct ixpnpe_softc *sc, const char *imageName, uint32_t imageId) 444 1.1 scw { 445 1.1 scw uint32_t imageSize; 446 1.1 scw const uint32_t *imageCodePtr; 447 1.1 scw void *fw; 448 1.1 scw int error; 449 1.1 scw 450 1.1 scw DPRINTF(sc->sc_dev, "load %s, imageId 0x%08x\n", imageName, imageId); 451 1.1 scw 452 1.1 scw #if 0 453 1.1 scw IxFeatureCtrlDeviceId devid = IX_NPEDL_DEVICEID_FROM_IMAGEID_GET(imageId); 454 1.1 scw /* 455 1.1 scw * Checking if image being loaded is meant for device that is running. 456 1.1 scw * Image is forward compatible. i.e Image built for IXP42X should run 457 1.1 scw * on IXP46X but not vice versa. 458 1.1 scw */ 459 1.1 scw if (devid > (ixFeatureCtrlDeviceRead() & IX_FEATURE_CTRL_DEVICE_TYPE_MASK)) 460 1.1 scw return EINVAL; 461 1.1 scw #endif 462 1.1 scw error = ixpnpe_stopandreset(sc); /* stop and reset the NPE */ 463 1.1 scw if (error != 0) 464 1.1 scw return error; 465 1.1 scw 466 1.1 scw fw = (void *)_binary_IxNpeMicrocode_dat_start; 467 1.1 scw 468 1.1 scw /* Locate desired image in files w/ combined images */ 469 1.1 scw error = npe_findimage(sc, (void *)fw /*fw->data*/, imageId, &imageCodePtr, &imageSize); 470 1.1 scw if (error != 0) 471 1.1 scw goto done; 472 1.1 scw 473 1.1 scw /* 474 1.1 scw * If download was successful, store image Id in list of 475 1.13 andvar * currently loaded images. If a critical error occurred 476 1.1 scw * during download, record that the NPE has an invalid image 477 1.1 scw */ 478 1.10 skrll mutex_enter(&sc->sc_lock); 479 1.1 scw error = npe_load_image(sc, imageCodePtr, 1 /*VERIFY*/); 480 1.1 scw if (error == 0) { 481 1.1 scw sc->validImage = 1; 482 1.1 scw error = ixpnpe_start_locked(sc); 483 1.1 scw } else { 484 1.1 scw sc->validImage = 0; 485 1.1 scw } 486 1.1 scw sc->functionalityId = IX_NPEDL_FUNCTIONID_FROM_IMAGEID_GET(imageId); 487 1.10 skrll mutex_exit(&sc->sc_lock); 488 1.1 scw done: 489 1.1 scw DPRINTF(sc->sc_dev, "%s: error %d\n", __func__, error); 490 1.1 scw return error; 491 1.1 scw } 492 1.1 scw 493 1.1 scw int 494 1.1 scw ixpnpe_getfunctionality(struct ixpnpe_softc *sc) 495 1.1 scw { 496 1.1 scw return (sc->validImage ? sc->functionalityId : 0); 497 1.1 scw } 498 1.1 scw 499 1.1 scw static int 500 1.1 scw npe_checkbits(struct ixpnpe_softc *sc, uint32_t reg, uint32_t expectedBitsSet) 501 1.1 scw { 502 1.1 scw uint32_t val; 503 1.1 scw 504 1.1 scw val = npe_reg_read(sc, reg); 505 1.1 scw DPRINTFn(5, sc->sc_dev, "%s(0x%x, 0x%x) => 0x%x (%u)\n", 506 1.1 scw __func__, reg, expectedBitsSet, val, 507 1.1 scw (val & expectedBitsSet) == expectedBitsSet); 508 1.1 scw return ((val & expectedBitsSet) == expectedBitsSet); 509 1.1 scw } 510 1.1 scw 511 1.1 scw static int 512 1.1 scw npe_isstopped(struct ixpnpe_softc *sc) 513 1.1 scw { 514 1.1 scw return npe_checkbits(sc, 515 1.1 scw IX_NPEDL_REG_OFFSET_EXCTL, IX_NPEDL_EXCTL_STATUS_STOP); 516 1.1 scw } 517 1.1 scw 518 1.1 scw static int 519 1.1 scw npe_load_ins(struct ixpnpe_softc *sc, 520 1.1 scw const IxNpeDlNpeMgrCodeBlock *bp, int verify) 521 1.1 scw { 522 1.1 scw uint32_t npeMemAddress; 523 1.1 scw int i, blockSize; 524 1.1 scw 525 1.1 scw npeMemAddress = bp->npeMemAddress; 526 1.1 scw blockSize = bp->size; /* NB: instruction/data count */ 527 1.1 scw if (npeMemAddress + blockSize > sc->insMemSize) { 528 1.9 msaitoh printf("%s: Block size too big for NPE memory\n", device_xname(sc->sc_dev)); 529 1.1 scw return EINVAL; /* XXX */ 530 1.1 scw } 531 1.1 scw for (i = 0; i < blockSize; i++, npeMemAddress++) { 532 1.1 scw if (npe_ins_write(sc, npeMemAddress, bp->data[i], verify) != 0) { 533 1.9 msaitoh printf("%s: NPE instruction write failed", device_xname(sc->sc_dev)); 534 1.1 scw return EIO; 535 1.1 scw } 536 1.1 scw } 537 1.1 scw return 0; 538 1.1 scw } 539 1.1 scw 540 1.1 scw static int 541 1.1 scw npe_load_data(struct ixpnpe_softc *sc, 542 1.1 scw const IxNpeDlNpeMgrCodeBlock *bp, int verify) 543 1.1 scw { 544 1.1 scw uint32_t npeMemAddress; 545 1.1 scw int i, blockSize; 546 1.1 scw 547 1.1 scw npeMemAddress = bp->npeMemAddress; 548 1.1 scw blockSize = bp->size; /* NB: instruction/data count */ 549 1.1 scw if (npeMemAddress + blockSize > sc->dataMemSize) { 550 1.9 msaitoh printf("%s: Block size too big for NPE memory\n", device_xname(sc->sc_dev)); 551 1.1 scw return EINVAL; 552 1.1 scw } 553 1.1 scw for (i = 0; i < blockSize; i++, npeMemAddress++) { 554 1.1 scw if (npe_data_write(sc, npeMemAddress, bp->data[i], verify) != 0) { 555 1.9 msaitoh printf("%s: NPE data write failed\n", device_xname(sc->sc_dev)); 556 1.1 scw return EIO; 557 1.1 scw } 558 1.1 scw } 559 1.1 scw return 0; 560 1.1 scw } 561 1.1 scw 562 1.1 scw static int 563 1.1 scw npe_load_stateinfo(struct ixpnpe_softc *sc, 564 1.1 scw const IxNpeDlNpeMgrStateInfoBlock *bp, int verify) 565 1.1 scw { 566 1.1 scw int i, nentries, error; 567 1.1 scw 568 1.1 scw npe_cpu_step_save(sc); 569 1.1 scw 570 1.1 scw /* for each state-info context register entry in block */ 571 1.1 scw nentries = bp->size / IX_NPEDL_STATE_INFO_ENTRY_SIZE; 572 1.1 scw error = 0; 573 1.1 scw for (i = 0; i < nentries; i++) { 574 1.1 scw /* each state-info entry is 2 words (address, value) in length */ 575 1.1 scw uint32_t regVal = bp->ctxtRegEntry[i].value; 576 1.1 scw uint32_t addrInfo = bp->ctxtRegEntry[i].addressInfo; 577 1.1 scw 578 1.1 scw uint32_t reg = (addrInfo & IX_NPEDL_MASK_STATE_ADDR_CTXT_REG); 579 1.1 scw uint32_t cNum = (addrInfo & IX_NPEDL_MASK_STATE_ADDR_CTXT_NUM) >> 580 1.1 scw IX_NPEDL_OFFSET_STATE_ADDR_CTXT_NUM; 581 1.1 scw 582 1.1 scw /* error-check Context Register No. and Context Number values */ 583 1.11 joerg if (reg >= IX_NPEDL_CTXT_REG_MAX) { 584 1.9 msaitoh printf("%s: invalid Context Register %u\n", device_xname(sc->sc_dev), 585 1.1 scw reg); 586 1.1 scw error = EINVAL; 587 1.1 scw break; 588 1.1 scw } 589 1.11 joerg if (cNum >= IX_NPEDL_CTXT_NUM_MAX) { 590 1.9 msaitoh printf("%s: invalid Context Number %u\n", device_xname(sc->sc_dev), 591 1.1 scw cNum); 592 1.1 scw error = EINVAL; 593 1.1 scw break; 594 1.1 scw } 595 1.1 scw /* NOTE that there is no STEVT register for Context 0 */ 596 1.1 scw if (cNum == 0 && reg == IX_NPEDL_CTXT_REG_STEVT) { 597 1.9 msaitoh printf("%s: no STEVT for Context 0\n", device_xname(sc->sc_dev)); 598 1.1 scw error = EINVAL; 599 1.1 scw break; 600 1.1 scw } 601 1.1 scw 602 1.1 scw if (npe_ctx_reg_write(sc, cNum, reg, regVal, verify) != 0) { 603 1.1 scw printf("%s: write of state-info to NPE failed\n", 604 1.9 msaitoh device_xname(sc->sc_dev)); 605 1.1 scw error = EIO; 606 1.1 scw break; 607 1.1 scw } 608 1.1 scw } 609 1.1 scw 610 1.1 scw npe_cpu_step_restore(sc); 611 1.1 scw return error; 612 1.1 scw } 613 1.1 scw 614 1.1 scw static int 615 1.1 scw npe_load_image(struct ixpnpe_softc *sc, 616 1.1 scw const uint32_t *imageCodePtr, int verify) 617 1.1 scw { 618 1.1 scw #define EOM(marker) ((marker) == IX_NPEDL_END_OF_DOWNLOAD_MAP) 619 1.1 scw const IxNpeDlNpeMgrDownloadMap *downloadMap; 620 1.1 scw int i, error; 621 1.1 scw 622 1.1 scw if (!npe_isstopped(sc)) { /* verify NPE is stopped */ 623 1.9 msaitoh printf("%s: cannot load image, NPE not stopped\n", device_xname(sc->sc_dev)); 624 1.1 scw return EIO; 625 1.1 scw } 626 1.1 scw 627 1.1 scw /* 628 1.1 scw * Read Download Map, checking each block type and calling 629 1.1 scw * appropriate function to perform download 630 1.1 scw */ 631 1.1 scw error = 0; 632 1.1 scw downloadMap = (const IxNpeDlNpeMgrDownloadMap *) imageCodePtr; 633 1.1 scw for (i = 0; !EOM(downloadMap->entry[i].eodmMarker); i++) { 634 1.1 scw /* calculate pointer to block to be downloaded */ 635 1.1 scw const uint32_t *bp = imageCodePtr + downloadMap->entry[i].block.offset; 636 1.1 scw switch (downloadMap->entry[i].block.type) { 637 1.1 scw case IX_NPEDL_BLOCK_TYPE_INSTRUCTION: 638 1.1 scw error = npe_load_ins(sc, 639 1.1 scw (const IxNpeDlNpeMgrCodeBlock *) bp, verify); 640 1.1 scw DPRINTF(sc->sc_dev, "%s: inst, error %d\n", __func__, error); 641 1.1 scw break; 642 1.1 scw case IX_NPEDL_BLOCK_TYPE_DATA: 643 1.1 scw error = npe_load_data(sc, 644 1.1 scw (const IxNpeDlNpeMgrCodeBlock *) bp, verify); 645 1.1 scw DPRINTF(sc->sc_dev, "%s: data, error %d\n", __func__, error); 646 1.1 scw break; 647 1.1 scw case IX_NPEDL_BLOCK_TYPE_STATE: 648 1.1 scw error = npe_load_stateinfo(sc, 649 1.1 scw (const IxNpeDlNpeMgrStateInfoBlock *) bp, verify); 650 1.1 scw DPRINTF(sc->sc_dev, "%s: state, error %d\n", __func__, error); 651 1.1 scw break; 652 1.1 scw default: 653 1.1 scw printf("%s: unknown block type 0x%x in download map\n", 654 1.9 msaitoh device_xname(sc->sc_dev), downloadMap->entry[i].block.type); 655 1.1 scw error = EIO; /* XXX */ 656 1.1 scw break; 657 1.1 scw } 658 1.1 scw if (error != 0) 659 1.1 scw break; 660 1.1 scw } 661 1.1 scw return error; 662 1.1 scw #undef EOM 663 1.1 scw } 664 1.1 scw 665 1.1 scw /* contains Reset values for Context Store Registers */ 666 1.1 scw static const struct { 667 1.1 scw uint32_t regAddr; 668 1.1 scw uint32_t regResetVal; 669 1.1 scw } ixNpeDlEcsRegResetValues[] = { 670 1.1 scw { IX_NPEDL_ECS_BG_CTXT_REG_0, IX_NPEDL_ECS_BG_CTXT_REG_0_RESET }, 671 1.1 scw { IX_NPEDL_ECS_BG_CTXT_REG_1, IX_NPEDL_ECS_BG_CTXT_REG_1_RESET }, 672 1.1 scw { IX_NPEDL_ECS_BG_CTXT_REG_2, IX_NPEDL_ECS_BG_CTXT_REG_2_RESET }, 673 1.1 scw { IX_NPEDL_ECS_PRI_1_CTXT_REG_0, IX_NPEDL_ECS_PRI_1_CTXT_REG_0_RESET }, 674 1.1 scw { IX_NPEDL_ECS_PRI_1_CTXT_REG_1, IX_NPEDL_ECS_PRI_1_CTXT_REG_1_RESET }, 675 1.1 scw { IX_NPEDL_ECS_PRI_1_CTXT_REG_2, IX_NPEDL_ECS_PRI_1_CTXT_REG_2_RESET }, 676 1.1 scw { IX_NPEDL_ECS_PRI_2_CTXT_REG_0, IX_NPEDL_ECS_PRI_2_CTXT_REG_0_RESET }, 677 1.1 scw { IX_NPEDL_ECS_PRI_2_CTXT_REG_1, IX_NPEDL_ECS_PRI_2_CTXT_REG_1_RESET }, 678 1.1 scw { IX_NPEDL_ECS_PRI_2_CTXT_REG_2, IX_NPEDL_ECS_PRI_2_CTXT_REG_2_RESET }, 679 1.1 scw { IX_NPEDL_ECS_DBG_CTXT_REG_0, IX_NPEDL_ECS_DBG_CTXT_REG_0_RESET }, 680 1.1 scw { IX_NPEDL_ECS_DBG_CTXT_REG_1, IX_NPEDL_ECS_DBG_CTXT_REG_1_RESET }, 681 1.1 scw { IX_NPEDL_ECS_DBG_CTXT_REG_2, IX_NPEDL_ECS_DBG_CTXT_REG_2_RESET }, 682 1.1 scw { IX_NPEDL_ECS_INSTRUCT_REG, IX_NPEDL_ECS_INSTRUCT_REG_RESET } 683 1.1 scw }; 684 1.1 scw 685 1.1 scw /* contains Reset values for Context Store Registers */ 686 1.1 scw static const uint32_t ixNpeDlCtxtRegResetValues[] = { 687 1.1 scw IX_NPEDL_CTXT_REG_RESET_STEVT, 688 1.1 scw IX_NPEDL_CTXT_REG_RESET_STARTPC, 689 1.1 scw IX_NPEDL_CTXT_REG_RESET_REGMAP, 690 1.1 scw IX_NPEDL_CTXT_REG_RESET_CINDEX, 691 1.1 scw }; 692 1.1 scw 693 1.1 scw #define IX_NPEDL_RESET_NPE_PARITY 0x0800 694 1.1 scw #define IX_NPEDL_PARITY_BIT_MASK 0x3F00FFFF 695 1.1 scw #define IX_NPEDL_CONFIG_CTRL_REG_MASK 0x3F3FFFFF 696 1.1 scw 697 1.1 scw static int 698 1.1 scw npe_cpu_reset(struct ixpnpe_softc *sc) 699 1.1 scw { 700 1.1 scw #define N(a) (sizeof(a) / sizeof(a[0])) 701 1.1 scw uint32_t ctxtReg; /* identifies Context Store reg (0-3) */ 702 1.1 scw uint32_t regAddr; 703 1.1 scw uint32_t regVal; 704 1.1 scw uint32_t resetNpeParity; 705 1.1 scw uint32_t ixNpeConfigCtrlRegVal; 706 1.1 scw int i, error = 0; 707 1.1 scw 708 1.1 scw /* pre-store the NPE Config Control Register Value */ 709 1.1 scw ixNpeConfigCtrlRegVal = npe_reg_read(sc, IX_NPEDL_REG_OFFSET_CTL); 710 1.1 scw ixNpeConfigCtrlRegVal |= 0x3F000000; 711 1.1 scw 712 1.1 scw /* disable the parity interrupt */ 713 1.1 scw npe_reg_write(sc, IX_NPEDL_REG_OFFSET_CTL, 714 1.1 scw (ixNpeConfigCtrlRegVal & IX_NPEDL_PARITY_BIT_MASK)); 715 1.1 scw DPRINTFn(2, sc->sc_dev, "%s: dis parity int, CTL => 0x%x\n", 716 1.1 scw __func__, ixNpeConfigCtrlRegVal & IX_NPEDL_PARITY_BIT_MASK); 717 1.1 scw 718 1.1 scw npe_cpu_step_save(sc); 719 1.1 scw 720 1.1 scw /* 721 1.1 scw * Clear the FIFOs. 722 1.1 scw */ 723 1.1 scw while (npe_checkbits(sc, 724 1.1 scw IX_NPEDL_REG_OFFSET_WFIFO, IX_NPEDL_MASK_WFIFO_VALID)) { 725 1.1 scw /* read from the Watch-point FIFO until empty */ 726 1.1 scw (void) npe_reg_read(sc, IX_NPEDL_REG_OFFSET_WFIFO); 727 1.1 scw } 728 1.1 scw 729 1.1 scw while (npe_checkbits(sc, 730 1.1 scw IX_NPEDL_REG_OFFSET_STAT, IX_NPEDL_MASK_STAT_OFNE)) { 731 1.1 scw /* read from the outFIFO until empty */ 732 1.1 scw (void) npe_reg_read(sc, IX_NPEDL_REG_OFFSET_FIFO); 733 1.1 scw } 734 1.1 scw 735 1.1 scw while (npe_checkbits(sc, 736 1.1 scw IX_NPEDL_REG_OFFSET_STAT, IX_NPEDL_MASK_STAT_IFNE)) { 737 1.1 scw /* 738 1.13 andvar * Step execution of the NPE instruction to read inFIFO using 739 1.1 scw * the Debug Executing Context stack. 740 1.1 scw */ 741 1.1 scw error = npe_cpu_step(sc, IX_NPEDL_INSTR_RD_FIFO, 0, 0); 742 1.1 scw if (error != 0) { 743 1.1 scw DPRINTF(sc->sc_dev, "%s: cannot step (1), error %u\n", 744 1.1 scw __func__, error); 745 1.1 scw npe_cpu_step_restore(sc); 746 1.1 scw return error; 747 1.1 scw } 748 1.1 scw } 749 1.1 scw 750 1.1 scw /* 751 1.1 scw * Reset the mailbox reg 752 1.1 scw */ 753 1.1 scw /* ...from XScale side */ 754 1.1 scw npe_reg_write(sc, IX_NPEDL_REG_OFFSET_MBST, IX_NPEDL_REG_RESET_MBST); 755 1.1 scw /* ...from NPE side */ 756 1.1 scw error = npe_cpu_step(sc, IX_NPEDL_INSTR_RESET_MBOX, 0, 0); 757 1.1 scw if (error != 0) { 758 1.1 scw DPRINTF(sc->sc_dev, "%s: cannot step (2), error %u\n", __func__, error); 759 1.1 scw npe_cpu_step_restore(sc); 760 1.1 scw return error; 761 1.1 scw } 762 1.1 scw 763 1.1 scw /* 764 1.1 scw * Reset the physical registers in the NPE register file: 765 1.1 scw * Note: no need to save/restore REGMAP for Context 0 here 766 1.1 scw * since all Context Store regs are reset in subsequent code. 767 1.1 scw */ 768 1.1 scw for (regAddr = 0; 769 1.1 scw regAddr < IX_NPEDL_TOTAL_NUM_PHYS_REG && error == 0; 770 1.1 scw regAddr++) { 771 1.1 scw /* for each physical register in the NPE reg file, write 0 : */ 772 1.2 thorpej error = npe_physical_reg_write(sc, regAddr, 0, true); 773 1.1 scw if (error != 0) { 774 1.1 scw DPRINTF(sc->sc_dev, "%s: cannot write phy reg, error %u\n", 775 1.1 scw __func__, error); 776 1.1 scw npe_cpu_step_restore(sc); 777 1.1 scw return error; /* abort reset */ 778 1.1 scw } 779 1.1 scw } 780 1.1 scw 781 1.1 scw /* 782 1.1 scw * Reset the context store: 783 1.1 scw */ 784 1.1 scw for (i = IX_NPEDL_CTXT_NUM_MIN; i <= IX_NPEDL_CTXT_NUM_MAX; i++) { 785 1.1 scw /* set each context's Context Store registers to reset values: */ 786 1.1 scw for (ctxtReg = 0; ctxtReg < IX_NPEDL_CTXT_REG_MAX; ctxtReg++) { 787 1.1 scw /* NOTE that there is no STEVT register for Context 0 */ 788 1.1 scw if (!(i == 0 && ctxtReg == IX_NPEDL_CTXT_REG_STEVT)) { 789 1.1 scw regVal = ixNpeDlCtxtRegResetValues[ctxtReg]; 790 1.2 thorpej error = npe_ctx_reg_write(sc, i, ctxtReg, regVal, true); 791 1.1 scw if (error != 0) { 792 1.1 scw DPRINTF(sc->sc_dev, "%s: cannot write ctx reg, error %u\n", 793 1.1 scw __func__, error); 794 1.1 scw npe_cpu_step_restore(sc); 795 1.1 scw return error; /* abort reset */ 796 1.1 scw } 797 1.1 scw } 798 1.1 scw } 799 1.1 scw } 800 1.1 scw 801 1.1 scw npe_cpu_step_restore(sc); 802 1.1 scw 803 1.1 scw /* write Reset values to Execution Context Stack registers */ 804 1.1 scw for (i = 0; i < N(ixNpeDlEcsRegResetValues); i++) 805 1.1 scw npe_ecs_reg_write(sc, 806 1.1 scw ixNpeDlEcsRegResetValues[i].regAddr, 807 1.1 scw ixNpeDlEcsRegResetValues[i].regResetVal); 808 1.1 scw 809 1.1 scw /* clear the profile counter */ 810 1.1 scw npe_issue_cmd(sc, IX_NPEDL_EXCTL_CMD_CLR_PROFILE_CNT); 811 1.1 scw 812 1.1 scw /* clear registers EXCT, AP0, AP1, AP2 and AP3 */ 813 1.1 scw for (regAddr = IX_NPEDL_REG_OFFSET_EXCT; 814 1.1 scw regAddr <= IX_NPEDL_REG_OFFSET_AP3; 815 1.1 scw regAddr += sizeof(uint32_t)) 816 1.1 scw npe_reg_write(sc, regAddr, 0); 817 1.1 scw 818 1.1 scw /* Reset the Watch-count register */ 819 1.1 scw npe_reg_write(sc, IX_NPEDL_REG_OFFSET_WC, 0); 820 1.1 scw 821 1.1 scw /* 822 1.1 scw * WR IXA00055043 - Remove IMEM Parity Introduced by NPE Reset Operation 823 1.1 scw */ 824 1.1 scw 825 1.1 scw /* 826 1.1 scw * Reset the NPE and its coprocessor - to reset internal 827 1.1 scw * states and remove parity error. Note this makes no 828 1.1 scw * sense based on the documentation. The feature control 829 1.1 scw * register always reads back as 0 on the ixp425 and further 830 1.1 scw * the bit definition of NPEA/NPEB is off by 1 according to 831 1.13 andvar * the Intel documentation--so we're blindly following the 832 1.1 scw * Intel code w/o any real understanding. 833 1.1 scw */ 834 1.1 scw regVal = EXP_BUS_READ_4(ixp425_softc, EXP_FCTRL_OFFSET); 835 1.1 scw DPRINTFn(2, sc->sc_dev, "%s: FCTRL 0x%x\n", __func__, regVal); 836 1.1 scw resetNpeParity = 837 1.1 scw IX_NPEDL_RESET_NPE_PARITY << (1 + sc->sc_unit); 838 1.1 scw DPRINTFn(2, sc->sc_dev, "%s: FCTRL fuse parity, write 0x%x\n", 839 1.1 scw __func__, regVal | resetNpeParity); 840 1.1 scw EXP_BUS_WRITE_4(ixp425_softc, EXP_FCTRL_OFFSET, regVal | resetNpeParity); 841 1.1 scw 842 1.1 scw /* un-fuse and un-reset the NPE & coprocessor */ 843 1.1 scw DPRINTFn(2, sc->sc_dev, "%s: FCTRL unfuse parity, write 0x%x\n", 844 1.4 msaitoh __func__, regVal & ~resetNpeParity); 845 1.1 scw EXP_BUS_WRITE_4(ixp425_softc, EXP_FCTRL_OFFSET, regVal &~ resetNpeParity); 846 1.1 scw 847 1.1 scw /* 848 1.1 scw * Call NpeMgr function to stop the NPE again after the Feature Control 849 1.1 scw * has unfused and Un-Reset the NPE and its associated Coprocessors. 850 1.1 scw */ 851 1.1 scw error = npe_cpu_stop(sc); 852 1.1 scw 853 1.1 scw /* restore NPE configuration bus Control Register - Parity Settings */ 854 1.1 scw npe_reg_write(sc, IX_NPEDL_REG_OFFSET_CTL, 855 1.1 scw (ixNpeConfigCtrlRegVal & IX_NPEDL_CONFIG_CTRL_REG_MASK)); 856 1.1 scw DPRINTFn(2, sc->sc_dev, "%s: restore CTL => 0x%x\n", 857 1.1 scw __func__, npe_reg_read(sc, IX_NPEDL_REG_OFFSET_CTL)); 858 1.1 scw 859 1.1 scw return error; 860 1.1 scw #undef N 861 1.1 scw } 862 1.1 scw 863 1.1 scw static int 864 1.1 scw npe_cpu_start(struct ixpnpe_softc *sc) 865 1.1 scw { 866 1.1 scw uint32_t ecsRegVal; 867 1.1 scw 868 1.1 scw /* 869 1.1 scw * Ensure only Background Context Stack Level is Active by turning off 870 1.1 scw * the Active bit in each of the other Executing Context Stack levels. 871 1.1 scw */ 872 1.1 scw ecsRegVal = npe_ecs_reg_read(sc, IX_NPEDL_ECS_PRI_1_CTXT_REG_0); 873 1.1 scw ecsRegVal &= ~IX_NPEDL_MASK_ECS_REG_0_ACTIVE; 874 1.1 scw npe_ecs_reg_write(sc, IX_NPEDL_ECS_PRI_1_CTXT_REG_0, ecsRegVal); 875 1.1 scw 876 1.1 scw ecsRegVal = npe_ecs_reg_read(sc, IX_NPEDL_ECS_PRI_2_CTXT_REG_0); 877 1.1 scw ecsRegVal &= ~IX_NPEDL_MASK_ECS_REG_0_ACTIVE; 878 1.1 scw npe_ecs_reg_write(sc, IX_NPEDL_ECS_PRI_2_CTXT_REG_0, ecsRegVal); 879 1.1 scw 880 1.1 scw ecsRegVal = npe_ecs_reg_read(sc, IX_NPEDL_ECS_DBG_CTXT_REG_0); 881 1.1 scw ecsRegVal &= ~IX_NPEDL_MASK_ECS_REG_0_ACTIVE; 882 1.1 scw npe_ecs_reg_write(sc, IX_NPEDL_ECS_DBG_CTXT_REG_0, ecsRegVal); 883 1.1 scw 884 1.1 scw /* clear the pipeline */ 885 1.1 scw npe_issue_cmd(sc, IX_NPEDL_EXCTL_CMD_NPE_CLR_PIPE); 886 1.1 scw 887 1.1 scw /* start NPE execution by issuing command through EXCTL register on NPE */ 888 1.1 scw npe_issue_cmd(sc, IX_NPEDL_EXCTL_CMD_NPE_START); 889 1.1 scw 890 1.1 scw /* 891 1.1 scw * Check execution status of NPE to verify operation was successful. 892 1.1 scw */ 893 1.1 scw return npe_checkbits(sc, 894 1.1 scw IX_NPEDL_REG_OFFSET_EXCTL, IX_NPEDL_EXCTL_STATUS_RUN) ? 0 : EIO; 895 1.1 scw } 896 1.1 scw 897 1.1 scw static int 898 1.1 scw npe_cpu_stop(struct ixpnpe_softc *sc) 899 1.1 scw { 900 1.1 scw /* stop NPE execution by issuing command through EXCTL register on NPE */ 901 1.1 scw npe_issue_cmd(sc, IX_NPEDL_EXCTL_CMD_NPE_STOP); 902 1.1 scw 903 1.1 scw /* verify that NPE Stop was successful */ 904 1.1 scw return npe_checkbits(sc, 905 1.1 scw IX_NPEDL_REG_OFFSET_EXCTL, IX_NPEDL_EXCTL_STATUS_STOP) ? 0 : EIO; 906 1.1 scw } 907 1.1 scw 908 1.1 scw #define IX_NPEDL_REG_SIZE_BYTE 8 909 1.1 scw #define IX_NPEDL_REG_SIZE_SHORT 16 910 1.1 scw #define IX_NPEDL_REG_SIZE_WORD 32 911 1.1 scw 912 1.1 scw /* 913 1.1 scw * Introduce extra read cycles after issuing read command to NPE 914 1.1 scw * so that we read the register after the NPE has updated it 915 1.1 scw * This is to overcome race condition between XScale and NPE 916 1.1 scw */ 917 1.1 scw #define IX_NPEDL_DELAY_READ_CYCLES 2 918 1.1 scw /* 919 1.1 scw * To mask top three MSBs of 32bit word to download into NPE IMEM 920 1.1 scw */ 921 1.1 scw #define IX_NPEDL_MASK_UNUSED_IMEM_BITS 0x1FFFFFFF; 922 1.1 scw 923 1.1 scw static void 924 1.1 scw npe_cmd_issue_write(struct ixpnpe_softc *sc, 925 1.1 scw uint32_t cmd, uint32_t addr, uint32_t data) 926 1.1 scw { 927 1.1 scw npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXDATA, data); 928 1.1 scw npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXAD, addr); 929 1.1 scw npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXCTL, cmd); 930 1.1 scw } 931 1.1 scw 932 1.1 scw static uint32_t 933 1.1 scw npe_cmd_issue_read(struct ixpnpe_softc *sc, uint32_t cmd, uint32_t addr) 934 1.1 scw { 935 1.1 scw uint32_t data; 936 1.1 scw int i; 937 1.1 scw 938 1.1 scw npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXAD, addr); 939 1.1 scw npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXCTL, cmd); 940 1.1 scw for (i = 0; i <= IX_NPEDL_DELAY_READ_CYCLES; i++) 941 1.1 scw data = npe_reg_read(sc, IX_NPEDL_REG_OFFSET_EXDATA); 942 1.1 scw return data; 943 1.1 scw } 944 1.1 scw 945 1.1 scw static int 946 1.1 scw npe_ins_write(struct ixpnpe_softc *sc, uint32_t addr, uint32_t data, int verify) 947 1.1 scw { 948 1.1 scw DPRINTFn(4, sc->sc_dev, "%s(0x%x, 0x%x)\n", __func__, addr, data); 949 1.1 scw npe_cmd_issue_write(sc, IX_NPEDL_EXCTL_CMD_WR_INS_MEM, addr, data); 950 1.1 scw if (verify) { 951 1.1 scw uint32_t rdata; 952 1.1 scw 953 1.1 scw /* 954 1.1 scw * Write invalid data to this reg, so we can see if we're reading 955 1.1 scw * the EXDATA register too early. 956 1.1 scw */ 957 1.1 scw npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXDATA, ~data); 958 1.1 scw 959 1.1 scw /* Disabled since top 3 MSB are not used for Azusa hardware Refer WR:IXA00053900*/ 960 1.1 scw data &= IX_NPEDL_MASK_UNUSED_IMEM_BITS; 961 1.1 scw 962 1.1 scw rdata = npe_cmd_issue_read(sc, IX_NPEDL_EXCTL_CMD_RD_INS_MEM, addr); 963 1.1 scw rdata &= IX_NPEDL_MASK_UNUSED_IMEM_BITS; 964 1.1 scw 965 1.1 scw if (data != rdata) 966 1.1 scw return EIO; 967 1.1 scw } 968 1.1 scw return 0; 969 1.1 scw } 970 1.1 scw 971 1.1 scw static int 972 1.1 scw npe_data_write(struct ixpnpe_softc *sc, uint32_t addr, uint32_t data, int verify) 973 1.1 scw { 974 1.1 scw DPRINTFn(4, sc->sc_dev, "%s(0x%x, 0x%x)\n", __func__, addr, data); 975 1.1 scw npe_cmd_issue_write(sc, IX_NPEDL_EXCTL_CMD_WR_DATA_MEM, addr, data); 976 1.1 scw if (verify) { 977 1.1 scw /* 978 1.1 scw * Write invalid data to this reg, so we can see if we're reading 979 1.1 scw * the EXDATA register too early. 980 1.1 scw */ 981 1.1 scw npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXDATA, ~data); 982 1.1 scw if (data != npe_cmd_issue_read(sc, IX_NPEDL_EXCTL_CMD_RD_DATA_MEM, addr)) 983 1.1 scw return EIO; 984 1.1 scw } 985 1.1 scw return 0; 986 1.1 scw } 987 1.1 scw 988 1.1 scw static void 989 1.1 scw npe_ecs_reg_write(struct ixpnpe_softc *sc, uint32_t reg, uint32_t data) 990 1.1 scw { 991 1.1 scw npe_cmd_issue_write(sc, IX_NPEDL_EXCTL_CMD_WR_ECS_REG, reg, data); 992 1.1 scw } 993 1.1 scw 994 1.1 scw static uint32_t 995 1.1 scw npe_ecs_reg_read(struct ixpnpe_softc *sc, uint32_t reg) 996 1.1 scw { 997 1.1 scw return npe_cmd_issue_read(sc, IX_NPEDL_EXCTL_CMD_RD_ECS_REG, reg); 998 1.1 scw } 999 1.1 scw 1000 1.1 scw static void 1001 1.1 scw npe_issue_cmd(struct ixpnpe_softc *sc, uint32_t command) 1002 1.1 scw { 1003 1.1 scw npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXCTL, command); 1004 1.1 scw } 1005 1.1 scw 1006 1.1 scw static void 1007 1.1 scw npe_cpu_step_save(struct ixpnpe_softc *sc) 1008 1.1 scw { 1009 1.1 scw /* turn off the halt bit by clearing Execution Count register. */ 1010 1.1 scw /* save reg contents 1st and restore later */ 1011 1.1 scw sc->savedExecCount = npe_reg_read(sc, IX_NPEDL_REG_OFFSET_EXCT); 1012 1.1 scw npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXCT, 0); 1013 1.1 scw 1014 1.1 scw /* ensure that IF and IE are on (temporarily), so that we don't end up 1015 1.1 scw * stepping forever */ 1016 1.1 scw sc->savedEcsDbgCtxtReg2 = npe_ecs_reg_read(sc, IX_NPEDL_ECS_DBG_CTXT_REG_2); 1017 1.1 scw 1018 1.1 scw npe_ecs_reg_write(sc, IX_NPEDL_ECS_DBG_CTXT_REG_2, 1019 1.1 scw (sc->savedEcsDbgCtxtReg2 | IX_NPEDL_MASK_ECS_DBG_REG_2_IF | 1020 1.1 scw IX_NPEDL_MASK_ECS_DBG_REG_2_IE)); 1021 1.1 scw } 1022 1.1 scw 1023 1.1 scw static int 1024 1.1 scw npe_cpu_step(struct ixpnpe_softc *sc, uint32_t npeInstruction, 1025 1.1 scw uint32_t ctxtNum, uint32_t ldur) 1026 1.1 scw { 1027 1.1 scw #define IX_NPE_DL_MAX_NUM_OF_RETRIES 1000000 1028 1.1 scw uint32_t ecsDbgRegVal; 1029 1.1 scw uint32_t oldWatchcount, newWatchcount; 1030 1.1 scw int tries; 1031 1.1 scw 1032 1.1 scw /* set the Active bit, and the LDUR, in the debug level */ 1033 1.1 scw ecsDbgRegVal = IX_NPEDL_MASK_ECS_REG_0_ACTIVE | 1034 1.1 scw (ldur << IX_NPEDL_OFFSET_ECS_REG_0_LDUR); 1035 1.1 scw 1036 1.1 scw npe_ecs_reg_write(sc, IX_NPEDL_ECS_DBG_CTXT_REG_0, ecsDbgRegVal); 1037 1.1 scw 1038 1.1 scw /* 1039 1.1 scw * Set CCTXT at ECS DEBUG L3 to specify in which context to execute the 1040 1.1 scw * instruction, and set SELCTXT at ECS DEBUG Level to specify which context 1041 1.1 scw * store to access. 1042 1.1 scw * Debug ECS Level Reg 1 has form 0x000n000n, where n = context number 1043 1.1 scw */ 1044 1.1 scw ecsDbgRegVal = (ctxtNum << IX_NPEDL_OFFSET_ECS_REG_1_CCTXT) | 1045 1.1 scw (ctxtNum << IX_NPEDL_OFFSET_ECS_REG_1_SELCTXT); 1046 1.1 scw 1047 1.1 scw npe_ecs_reg_write(sc, IX_NPEDL_ECS_DBG_CTXT_REG_1, ecsDbgRegVal); 1048 1.1 scw 1049 1.1 scw /* clear the pipeline */ 1050 1.1 scw npe_issue_cmd(sc, IX_NPEDL_EXCTL_CMD_NPE_CLR_PIPE); 1051 1.1 scw 1052 1.1 scw /* load NPE instruction into the instruction register */ 1053 1.1 scw npe_ecs_reg_write(sc, IX_NPEDL_ECS_INSTRUCT_REG, npeInstruction); 1054 1.1 scw 1055 1.1 scw /* we need this value later to wait for completion of NPE execution step */ 1056 1.1 scw oldWatchcount = npe_reg_read(sc, IX_NPEDL_REG_OFFSET_WC); 1057 1.1 scw 1058 1.1 scw /* issue a Step One command via the Execution Control register */ 1059 1.1 scw npe_issue_cmd(sc, IX_NPEDL_EXCTL_CMD_NPE_STEP); 1060 1.1 scw 1061 1.1 scw /* 1062 1.1 scw * Force the XScale to wait until the NPE has finished execution step 1063 1.1 scw * NOTE that this delay will be very small, just long enough to allow a 1064 1.1 scw * single NPE instruction to complete execution; if instruction execution 1065 1.1 scw * is not completed before timeout retries, exit the while loop. 1066 1.1 scw */ 1067 1.1 scw newWatchcount = npe_reg_read(sc, IX_NPEDL_REG_OFFSET_WC); 1068 1.1 scw for (tries = 0; tries < IX_NPE_DL_MAX_NUM_OF_RETRIES && 1069 1.1 scw newWatchcount == oldWatchcount; tries++) { 1070 1.1 scw /* Watch Count register increments when NPE completes an instruction */ 1071 1.1 scw newWatchcount = npe_reg_read(sc, IX_NPEDL_REG_OFFSET_WC); 1072 1.1 scw } 1073 1.1 scw return (tries < IX_NPE_DL_MAX_NUM_OF_RETRIES) ? 0 : EIO; 1074 1.1 scw #undef IX_NPE_DL_MAX_NUM_OF_RETRIES 1075 1.1 scw } 1076 1.1 scw 1077 1.1 scw static void 1078 1.1 scw npe_cpu_step_restore(struct ixpnpe_softc *sc) 1079 1.1 scw { 1080 1.1 scw /* clear active bit in debug level */ 1081 1.1 scw npe_ecs_reg_write(sc, IX_NPEDL_ECS_DBG_CTXT_REG_0, 0); 1082 1.1 scw 1083 1.1 scw /* clear the pipeline */ 1084 1.1 scw npe_issue_cmd(sc, IX_NPEDL_EXCTL_CMD_NPE_CLR_PIPE); 1085 1.1 scw 1086 1.1 scw /* restore Execution Count register contents. */ 1087 1.1 scw npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXCT, sc->savedExecCount); 1088 1.1 scw 1089 1.1 scw /* restore IF and IE bits to original values */ 1090 1.1 scw npe_ecs_reg_write(sc, IX_NPEDL_ECS_DBG_CTXT_REG_2, sc->savedEcsDbgCtxtReg2); 1091 1.1 scw } 1092 1.1 scw 1093 1.1 scw static int 1094 1.1 scw npe_logical_reg_read(struct ixpnpe_softc *sc, 1095 1.1 scw uint32_t regAddr, uint32_t regSize, 1096 1.1 scw uint32_t ctxtNum, uint32_t *regVal) 1097 1.1 scw { 1098 1.1 scw uint32_t npeInstruction, mask; 1099 1.1 scw int error; 1100 1.1 scw 1101 1.1 scw switch (regSize) { 1102 1.1 scw case IX_NPEDL_REG_SIZE_BYTE: 1103 1.1 scw npeInstruction = IX_NPEDL_INSTR_RD_REG_BYTE; 1104 1.1 scw mask = 0xff; 1105 1.1 scw break; 1106 1.1 scw case IX_NPEDL_REG_SIZE_SHORT: 1107 1.1 scw npeInstruction = IX_NPEDL_INSTR_RD_REG_SHORT; 1108 1.1 scw mask = 0xffff; 1109 1.1 scw break; 1110 1.1 scw case IX_NPEDL_REG_SIZE_WORD: 1111 1.1 scw npeInstruction = IX_NPEDL_INSTR_RD_REG_WORD; 1112 1.1 scw mask = 0xffffffff; 1113 1.1 scw break; 1114 1.1 scw default: 1115 1.1 scw return EINVAL; 1116 1.1 scw } 1117 1.1 scw 1118 1.1 scw /* make regAddr be the SRC and DEST operands (e.g. movX d0, d0) */ 1119 1.1 scw npeInstruction |= (regAddr << IX_NPEDL_OFFSET_INSTR_SRC) | 1120 1.1 scw (regAddr << IX_NPEDL_OFFSET_INSTR_DEST); 1121 1.1 scw 1122 1.14 andvar /* step execution of NPE instruction using Debug Executing Context stack */ 1123 1.1 scw error = npe_cpu_step(sc, npeInstruction, ctxtNum, IX_NPEDL_RD_INSTR_LDUR); 1124 1.1 scw if (error != 0) { 1125 1.1 scw DPRINTF(sc->sc_dev, "%s(0x%x, %u, %u), cannot step, error %d\n", 1126 1.1 scw __func__, regAddr, regSize, ctxtNum, error); 1127 1.1 scw return error; 1128 1.1 scw } 1129 1.1 scw /* read value of register from Execution Data register */ 1130 1.1 scw *regVal = npe_reg_read(sc, IX_NPEDL_REG_OFFSET_EXDATA); 1131 1.1 scw 1132 1.1 scw /* align value from left to right */ 1133 1.1 scw *regVal = (*regVal >> (IX_NPEDL_REG_SIZE_WORD - regSize)) & mask; 1134 1.1 scw 1135 1.1 scw return 0; 1136 1.1 scw } 1137 1.1 scw 1138 1.1 scw static int 1139 1.1 scw npe_logical_reg_write(struct ixpnpe_softc *sc, uint32_t regAddr, uint32_t regVal, 1140 1.1 scw uint32_t regSize, uint32_t ctxtNum, int verify) 1141 1.1 scw { 1142 1.1 scw int error; 1143 1.1 scw 1144 1.1 scw DPRINTFn(4, sc->sc_dev, "%s(0x%x, 0x%x, %u, %u)\n", 1145 1.1 scw __func__, regAddr, regVal, regSize, ctxtNum); 1146 1.1 scw if (regSize == IX_NPEDL_REG_SIZE_WORD) { 1147 1.1 scw /* NPE register addressing is left-to-right: e.g. |d0|d1|d2|d3| */ 1148 1.1 scw /* Write upper half-word (short) to |d0|d1| */ 1149 1.1 scw error = npe_logical_reg_write(sc, regAddr, 1150 1.1 scw regVal >> IX_NPEDL_REG_SIZE_SHORT, 1151 1.1 scw IX_NPEDL_REG_SIZE_SHORT, ctxtNum, verify); 1152 1.1 scw if (error != 0) 1153 1.1 scw return error; 1154 1.1 scw 1155 1.1 scw /* Write lower half-word (short) to |d2|d3| */ 1156 1.1 scw error = npe_logical_reg_write(sc, 1157 1.1 scw regAddr + sizeof(uint16_t), 1158 1.1 scw regVal & 0xffff, 1159 1.1 scw IX_NPEDL_REG_SIZE_SHORT, ctxtNum, verify); 1160 1.1 scw } else { 1161 1.1 scw uint32_t npeInstruction; 1162 1.1 scw 1163 1.1 scw switch (regSize) { 1164 1.1 scw case IX_NPEDL_REG_SIZE_BYTE: 1165 1.1 scw npeInstruction = IX_NPEDL_INSTR_WR_REG_BYTE; 1166 1.1 scw regVal &= 0xff; 1167 1.1 scw break; 1168 1.1 scw case IX_NPEDL_REG_SIZE_SHORT: 1169 1.1 scw npeInstruction = IX_NPEDL_INSTR_WR_REG_SHORT; 1170 1.1 scw regVal &= 0xffff; 1171 1.1 scw break; 1172 1.1 scw default: 1173 1.1 scw return EINVAL; 1174 1.1 scw } 1175 1.14 andvar /* fill dest operand field of instruction with destination reg addr */ 1176 1.1 scw npeInstruction |= (regAddr << IX_NPEDL_OFFSET_INSTR_DEST); 1177 1.1 scw 1178 1.1 scw /* fill src operand field of instruction with least-sig 5 bits of val*/ 1179 1.1 scw npeInstruction |= ((regVal & IX_NPEDL_MASK_IMMED_INSTR_SRC_DATA) << 1180 1.1 scw IX_NPEDL_OFFSET_INSTR_SRC); 1181 1.1 scw 1182 1.1 scw /* fill coprocessor field of instruction with most-sig 11 bits of val*/ 1183 1.1 scw npeInstruction |= ((regVal & IX_NPEDL_MASK_IMMED_INSTR_COPROC_DATA) << 1184 1.1 scw IX_NPEDL_DISPLACE_IMMED_INSTR_COPROC_DATA); 1185 1.1 scw 1186 1.14 andvar /* step execution of NPE instruction using Debug ECS */ 1187 1.1 scw error = npe_cpu_step(sc, npeInstruction, 1188 1.1 scw ctxtNum, IX_NPEDL_WR_INSTR_LDUR); 1189 1.1 scw } 1190 1.1 scw if (error != 0) { 1191 1.1 scw DPRINTF(sc->sc_dev, "%s(0x%x, 0x%x, %u, %u), error %u writing reg\n", 1192 1.1 scw __func__, regAddr, regVal, regSize, ctxtNum, error); 1193 1.1 scw return error; 1194 1.1 scw } 1195 1.1 scw if (verify) { 1196 1.1 scw uint32_t retRegVal; 1197 1.1 scw 1198 1.1 scw error = npe_logical_reg_read(sc, regAddr, regSize, ctxtNum, &retRegVal); 1199 1.1 scw if (error == 0 && regVal != retRegVal) 1200 1.1 scw error = EIO; /* XXX ambiguous */ 1201 1.1 scw } 1202 1.1 scw return error; 1203 1.1 scw } 1204 1.1 scw 1205 1.1 scw /* 1206 1.1 scw * There are 32 physical registers used in an NPE. These are 1207 1.1 scw * treated as 16 pairs of 32-bit registers. To write one of the pair, 1208 1.1 scw * write the pair number (0-16) to the REGMAP for Context 0. Then write 1209 1.1 scw * the value to register 0 or 4 in the regfile, depending on which 1210 1.1 scw * register of the pair is to be written 1211 1.1 scw */ 1212 1.1 scw static int 1213 1.1 scw npe_physical_reg_write(struct ixpnpe_softc *sc, 1214 1.1 scw uint32_t regAddr, uint32_t regValue, int verify) 1215 1.1 scw { 1216 1.1 scw int error; 1217 1.1 scw 1218 1.1 scw /* 1219 1.1 scw * Set REGMAP for context 0 to (regAddr >> 1) to choose which pair (0-16) 1220 1.1 scw * of physical registers to write . 1221 1.1 scw */ 1222 1.1 scw error = npe_logical_reg_write(sc, IX_NPEDL_CTXT_REG_ADDR_REGMAP, 1223 1.1 scw (regAddr >> IX_NPEDL_OFFSET_PHYS_REG_ADDR_REGMAP), 1224 1.1 scw IX_NPEDL_REG_SIZE_SHORT, 0, verify); 1225 1.1 scw if (error == 0) { 1226 1.1 scw /* regAddr = 0 or 4 */ 1227 1.1 scw regAddr = (regAddr & IX_NPEDL_MASK_PHYS_REG_ADDR_LOGICAL_ADDR) * 1228 1.1 scw sizeof(uint32_t); 1229 1.1 scw error = npe_logical_reg_write(sc, regAddr, regValue, 1230 1.1 scw IX_NPEDL_REG_SIZE_WORD, 0, verify); 1231 1.1 scw } 1232 1.1 scw return error; 1233 1.1 scw } 1234 1.1 scw 1235 1.1 scw static int 1236 1.1 scw npe_ctx_reg_write(struct ixpnpe_softc *sc, uint32_t ctxtNum, 1237 1.1 scw uint32_t ctxtReg, uint32_t ctxtRegVal, int verify) 1238 1.1 scw { 1239 1.1 scw DPRINTFn(4, sc->sc_dev, "%s(%u, %u, %u)\n", 1240 1.1 scw __func__, ctxtNum, ctxtReg, ctxtRegVal); 1241 1.1 scw /* 1242 1.1 scw * Context 0 has no STARTPC. Instead, this value is used to set 1243 1.1 scw * NextPC for Background ECS, to set where NPE starts executing code 1244 1.1 scw */ 1245 1.1 scw if (ctxtNum == 0 && ctxtReg == IX_NPEDL_CTXT_REG_STARTPC) { 1246 1.1 scw /* read BG_CTXT_REG_0, update NEXTPC bits, and write back to reg */ 1247 1.1 scw uint32_t v = npe_ecs_reg_read(sc, IX_NPEDL_ECS_BG_CTXT_REG_0); 1248 1.1 scw v &= ~IX_NPEDL_MASK_ECS_REG_0_NEXTPC; 1249 1.1 scw v |= (ctxtRegVal << IX_NPEDL_OFFSET_ECS_REG_0_NEXTPC) & 1250 1.1 scw IX_NPEDL_MASK_ECS_REG_0_NEXTPC; 1251 1.1 scw 1252 1.1 scw npe_ecs_reg_write(sc, IX_NPEDL_ECS_BG_CTXT_REG_0, v); 1253 1.1 scw return 0; 1254 1.1 scw } else { 1255 1.1 scw static const struct { 1256 1.1 scw uint32_t regAddress; 1257 1.1 scw uint32_t regSize; 1258 1.1 scw } regAccInfo[IX_NPEDL_CTXT_REG_MAX] = { 1259 1.1 scw { IX_NPEDL_CTXT_REG_ADDR_STEVT, IX_NPEDL_REG_SIZE_BYTE }, 1260 1.1 scw { IX_NPEDL_CTXT_REG_ADDR_STARTPC, IX_NPEDL_REG_SIZE_SHORT }, 1261 1.1 scw { IX_NPEDL_CTXT_REG_ADDR_REGMAP, IX_NPEDL_REG_SIZE_SHORT }, 1262 1.1 scw { IX_NPEDL_CTXT_REG_ADDR_CINDEX, IX_NPEDL_REG_SIZE_BYTE } 1263 1.1 scw }; 1264 1.1 scw return npe_logical_reg_write(sc, regAccInfo[ctxtReg].regAddress, 1265 1.1 scw ctxtRegVal, regAccInfo[ctxtReg].regSize, ctxtNum, verify); 1266 1.1 scw } 1267 1.1 scw } 1268 1.1 scw 1269 1.1 scw /* 1270 1.1 scw * NPE Mailbox support. 1271 1.1 scw */ 1272 1.1 scw #define IX_NPEMH_MAXTRIES 100000 1273 1.1 scw 1274 1.1 scw static int 1275 1.1 scw ixpnpe_ofifo_wait(struct ixpnpe_softc *sc) 1276 1.1 scw { 1277 1.1 scw int i; 1278 1.1 scw 1279 1.1 scw for (i = 0; i < IX_NPEMH_MAXTRIES; i++) { 1280 1.1 scw if (npe_reg_read(sc, IX_NPESTAT) & IX_NPESTAT_OFNE) 1281 1.1 scw return 1; 1282 1.1 scw DELAY(10); 1283 1.1 scw } 1284 1.9 msaitoh printf("%s: %s: timeout, last status 0x%x\n", device_xname(sc->sc_dev), 1285 1.1 scw __func__, npe_reg_read(sc, IX_NPESTAT)); 1286 1.1 scw return 0; 1287 1.1 scw } 1288 1.1 scw 1289 1.1 scw static int 1290 1.1 scw ixpnpe_intr(void *arg) 1291 1.1 scw { 1292 1.1 scw struct ixpnpe_softc *sc = arg; 1293 1.1 scw uint32_t status; 1294 1.1 scw 1295 1.1 scw status = npe_reg_read(sc, IX_NPESTAT); 1296 1.1 scw if ((status & IX_NPESTAT_OFINT) == 0) { 1297 1.1 scw /* NB: should not happen */ 1298 1.9 msaitoh printf("%s: %s: status 0x%x\n", device_xname(sc->sc_dev), __func__, status); 1299 1.1 scw /* XXX must silence interrupt? */ 1300 1.1 scw return(1); 1301 1.1 scw } 1302 1.1 scw /* 1303 1.1 scw * A message is waiting in the output FIFO, copy it so 1304 1.1 scw * the interrupt will be silenced; then signal anyone 1305 1.1 scw * waiting to collect the result. 1306 1.1 scw */ 1307 1.1 scw sc->sc_msgwaiting = -1; /* NB: error indicator */ 1308 1.1 scw if (ixpnpe_ofifo_wait(sc)) { 1309 1.1 scw sc->sc_msg[0] = npe_reg_read(sc, IX_NPEFIFO); 1310 1.1 scw if (ixpnpe_ofifo_wait(sc)) { 1311 1.1 scw sc->sc_msg[1] = npe_reg_read(sc, IX_NPEFIFO); 1312 1.1 scw sc->sc_msgwaiting = 1; /* successful fetch */ 1313 1.1 scw } 1314 1.1 scw } 1315 1.4 msaitoh if (sc->sc_msg[0] == (NPE_MACRECOVERYSTART << NPE_MAC_MSGID_SHL)) { 1316 1.4 msaitoh int s; 1317 1.4 msaitoh 1318 1.4 msaitoh s = splnet(); 1319 1.4 msaitoh delay(100); /* delay 100usec */ 1320 1.4 msaitoh if (sc->macresetcbfunc != NULL) 1321 1.4 msaitoh sc->macresetcbfunc(sc->macresetcbarg); 1322 1.4 msaitoh splx(s); 1323 1.4 msaitoh } 1324 1.4 msaitoh 1325 1.4 msaitoh #if 0 1326 1.4 msaitoh /* XXX Too dangerous! see ixpnpe_recvmsg_locked() */ 1327 1.1 scw wakeup(sc); 1328 1.4 msaitoh #endif 1329 1.1 scw 1330 1.1 scw return (1); 1331 1.1 scw } 1332 1.1 scw 1333 1.1 scw static int 1334 1.1 scw ixpnpe_ififo_wait(struct ixpnpe_softc *sc) 1335 1.1 scw { 1336 1.1 scw int i; 1337 1.1 scw 1338 1.1 scw for (i = 0; i < IX_NPEMH_MAXTRIES; i++) { 1339 1.1 scw if (npe_reg_read(sc, IX_NPESTAT) & IX_NPESTAT_IFNF) 1340 1.1 scw return 1; 1341 1.1 scw DELAY(10); 1342 1.1 scw } 1343 1.1 scw return 0; 1344 1.1 scw } 1345 1.1 scw 1346 1.1 scw static int 1347 1.1 scw ixpnpe_sendmsg_locked(struct ixpnpe_softc *sc, const uint32_t msg[2]) 1348 1.1 scw { 1349 1.1 scw int error = 0; 1350 1.1 scw 1351 1.1 scw sc->sc_msgwaiting = 0; 1352 1.1 scw if (ixpnpe_ififo_wait(sc)) { 1353 1.1 scw npe_reg_write(sc, IX_NPEFIFO, msg[0]); 1354 1.1 scw if (ixpnpe_ififo_wait(sc)) 1355 1.1 scw npe_reg_write(sc, IX_NPEFIFO, msg[1]); 1356 1.1 scw else 1357 1.1 scw error = EIO; 1358 1.1 scw } else 1359 1.1 scw error = EIO; 1360 1.1 scw 1361 1.1 scw if (error) 1362 1.1 scw printf("%s: input FIFO timeout, msg [0x%x,0x%x]\n", 1363 1.9 msaitoh device_xname(sc->sc_dev), msg[0], msg[1]); 1364 1.1 scw return error; 1365 1.1 scw } 1366 1.1 scw 1367 1.1 scw static int 1368 1.1 scw ixpnpe_recvmsg_locked(struct ixpnpe_softc *sc, uint32_t msg[2]) 1369 1.1 scw { 1370 1.1 scw 1371 1.4 msaitoh if (!sc->sc_msgwaiting) { 1372 1.7 rmind /* XXX interrupt context - cannot sleep */ 1373 1.4 msaitoh delay(1000); /* wait 1ms (is it ok?)*/ 1374 1.4 msaitoh } 1375 1.6 cegger memcpy(msg, sc->sc_msg, sizeof(sc->sc_msg)); 1376 1.4 msaitoh /* NB: sc_msgwaiting != 1 means the ack fetch failed */ 1377 1.4 msaitoh return sc->sc_msgwaiting != 1 ? EIO : 0; 1378 1.1 scw } 1379 1.1 scw 1380 1.1 scw /* 1381 1.1 scw * Send a msg to the NPE and wait for a reply. We use the 1382 1.1 scw * private mutex and sleep until an interrupt is received 1383 1.1 scw * signalling the availability of data in the output FIFO 1384 1.1 scw * so the caller cannot be holding a mutex. May be better 1385 1.1 scw * piggyback on the caller's mutex instead but that would 1386 1.1 scw * make other locking confusing. 1387 1.1 scw */ 1388 1.1 scw int 1389 1.1 scw ixpnpe_sendandrecvmsg(struct ixpnpe_softc *sc, 1390 1.1 scw const uint32_t send[2], uint32_t recv[2]) 1391 1.1 scw { 1392 1.1 scw int error; 1393 1.1 scw 1394 1.10 skrll mutex_enter(&sc->sc_lock); 1395 1.1 scw error = ixpnpe_sendmsg_locked(sc, send); 1396 1.1 scw if (error == 0) 1397 1.1 scw error = ixpnpe_recvmsg_locked(sc, recv); 1398 1.10 skrll mutex_exit(&sc->sc_lock); 1399 1.1 scw 1400 1.1 scw return error; 1401 1.1 scw } 1402 1.1 scw 1403 1.1 scw /* XXX temporary, not reliable */ 1404 1.1 scw 1405 1.1 scw int 1406 1.1 scw ixpnpe_sendmsg(struct ixpnpe_softc *sc, const uint32_t msg[2]) 1407 1.1 scw { 1408 1.1 scw int error; 1409 1.1 scw 1410 1.10 skrll mutex_enter(&sc->sc_lock); 1411 1.1 scw error = ixpnpe_sendmsg_locked(sc, msg); 1412 1.10 skrll mutex_exit(&sc->sc_lock); 1413 1.1 scw 1414 1.1 scw return error; 1415 1.1 scw } 1416 1.1 scw 1417 1.1 scw int 1418 1.1 scw ixpnpe_recvmsg(struct ixpnpe_softc *sc, uint32_t msg[2]) 1419 1.1 scw { 1420 1.1 scw int error; 1421 1.1 scw 1422 1.10 skrll mutex_enter(&sc->sc_lock); 1423 1.1 scw if (sc->sc_msgwaiting) 1424 1.6 cegger memcpy(msg, sc->sc_msg, sizeof(sc->sc_msg)); 1425 1.1 scw /* NB: sc_msgwaiting != 1 means the ack fetch failed */ 1426 1.1 scw error = sc->sc_msgwaiting != 1 ? EIO : 0; 1427 1.10 skrll mutex_exit(&sc->sc_lock); 1428 1.1 scw 1429 1.1 scw return error; 1430 1.1 scw } 1431