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