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