static u32 npe_cmd_read(struct npe *npe, u32 addr, int cmd)
{
__raw_writel(addr, &npe->regs->exec_addr);
__raw_writel(cmd, &npe->regs->exec_status_cmd); /* Iintroduce extra read cycles after issuing read command to NPE sothatwereadtheregisteraftertheNPEhasupdatedit.
This is to overcome race condition between XScale and NPE */
__raw_readl(&npe->regs->exec_data);
__raw_readl(&npe->regs->exec_data); return __raw_readl(&npe->regs->exec_data);
}
staticvoid npe_clear_active(struct npe *npe, u32 reg)
{
u32 val = npe_cmd_read(npe, reg, CMD_RD_ECS_REG);
npe_cmd_write(npe, reg, CMD_WR_ECS_REG, val & ~ECS_REG_0_ACTIVE);
}
staticvoid npe_start(struct npe *npe)
{ /* ensure only Background Context Stack Level is active */
npe_clear_active(npe, ECS_PRI_1_CTXT_REG_0);
npe_clear_active(npe, ECS_PRI_2_CTXT_REG_0);
npe_clear_active(npe, ECS_DBG_CTXT_REG_0);
/* set the Active bit, and the LDUR, in the debug level */
npe_cmd_write(npe, ECS_DBG_CTXT_REG_0, CMD_WR_ECS_REG,
ECS_REG_0_ACTIVE | (ldur << ECS_REG_0_LDUR_BITS));
/* set CCTXT at ECS DEBUG L3 to specify in which context to execute theinstruction,andsetSELCTXTatECSDEBUGLeveltospecify whichcontextstoretoaccess. DebugECSLevelReg1hasform0x000n000n,wheren=contextnumber
*/
npe_cmd_write(npe, ECS_DBG_CTXT_REG_1, CMD_WR_ECS_REG,
(ctx << ECS_REG_1_CCTXT_BITS) |
(ctx << ECS_REG_1_SELCTXT_BITS));
/* clear the pipeline */
__raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd);
/* load NPE instruction into the instruction register */
npe_cmd_write(npe, ECS_INSTRUCT_REG, CMD_WR_ECS_REG, instr);
/* we need this value later to wait for completion of NPE execution
step */
wc = __raw_readl(&npe->regs->watch_count);
/* issue a Step One command via the Execution Control register */
__raw_writel(CMD_NPE_STEP, &npe->regs->exec_status_cmd);
/* Watch Count register increments when NPE completes an instruction */ for (i = 0; i < MAX_RETRIES; i++) { if (wc != __raw_readl(&npe->regs->watch_count)) return0;
udelay(1);
}
staticint __must_check npe_logical_reg_write8(struct npe *npe, u32 addr,
u8 val, u32 ctx)
{ /* here we build the NPE assembler instruction: mov8 d0, #0 */
u32 instr = INSTR_WR_REG_BYTE | /* OpCode */
addr << 9 | /* base Operand */
(val & 0x1F) << 4 | /* lower 5 bits to immediate data */
(val & ~0x1F) << (18 - 5);/* higher 3 bits to CoProc instr. */ return npe_debug_instr(npe, instr, ctx, 1); /* execute it */
}
staticint __must_check npe_logical_reg_write16(struct npe *npe, u32 addr,
u16 val, u32 ctx)
{ /* here we build the NPE assembler instruction: mov16 d0, #0 */
u32 instr = INSTR_WR_REG_SHORT | /* OpCode */
addr << 9 | /* base Operand */
(val & 0x1F) << 4 | /* lower 5 bits to immediate data */
(val & ~0x1F) << (18 - 5);/* higher 11 bits to CoProc instr. */ return npe_debug_instr(npe, instr, ctx, 1); /* execute it */
}
staticint __must_check npe_logical_reg_write32(struct npe *npe, u32 addr,
u32 val, u32 ctx)
{ /* write in 16 bit steps first the high and then the low value */ if (npe_logical_reg_write16(npe, addr, val >> 16, ctx)) return -ETIMEDOUT; return npe_logical_reg_write16(npe, addr + 2, val & 0xFFFF, ctx);
}
/* pre exec - debug instruction */ /* turn off the halt bit by clearing Execution Count register. */
exec_count = __raw_readl(&npe->regs->exec_count);
__raw_writel(0, &npe->regs->exec_count); /* ensure that IF and IE are on (temporarily), so that we don't end up
stepping forever */
ctx_reg2 = npe_cmd_read(npe, ECS_DBG_CTXT_REG_2, CMD_RD_ECS_REG);
npe_cmd_write(npe, ECS_DBG_CTXT_REG_2, CMD_WR_ECS_REG, ctx_reg2 |
ECS_DBG_REG_2_IF | ECS_DBG_REG_2_IE);
/* clear the FIFOs */ while (__raw_readl(&npe->regs->watchpoint_fifo) & WFIFO_VALID)
; while (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_OFNE) /* read from the outFIFO until empty */
print_npe(KERN_DEBUG, npe, "npe_reset: read FIFO = 0x%X\n",
__raw_readl(&npe->regs->in_out_fifo));
while (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNE) /* step execution of the NPE intruction to read inFIFO using
the Debug Executing Context stack */ if (npe_debug_instr(npe, INSTR_RD_FIFO, 0, 0)) return -ETIMEDOUT;
/* reset the mailbox reg from the XScale side */
__raw_writel(RESET_MBOX_STAT, &npe->regs->mailbox_status); /* from NPE side */ if (npe_debug_instr(npe, INSTR_RESET_MBOX, 0, 0)) return -ETIMEDOUT;
/* Reset the physical registers in the NPE register file */ for (val = 0; val < NPE_PHYS_REG; val++) { if (npe_logical_reg_write16(npe, NPE_REGMAP, val >> 1, 0)) return -ETIMEDOUT; /* address is either 0 or 4 */ if (npe_logical_reg_write32(npe, (val & 1) * 4, 0, 0)) return -ETIMEDOUT;
}
/* Reset the context store = each context's Context Store registers */
/* Context 0 has no STARTPC. Instead, this value is used to set NextPC
for Background ECS, to set where NPE starts executing code */
val = npe_cmd_read(npe, ECS_BG_CTXT_REG_0, CMD_RD_ECS_REG);
val &= ~ECS_REG_0_NEXTPC_MASK;
val |= (0/* NextPC */ << 16) & ECS_REG_0_NEXTPC_MASK;
npe_cmd_write(npe, ECS_BG_CTXT_REG_0, CMD_WR_ECS_REG, val);
for (i = 0; i < 16; i++) { if (i) { /* Context 0 has no STEVT nor STARTPC */ /* STEVT = off, 0x80 */ if (npe_logical_reg_write8(npe, NPE_STEVT, 0x80, i)) return -ETIMEDOUT; if (npe_logical_reg_write16(npe, NPE_STARTPC, 0, i)) return -ETIMEDOUT;
} /* REGMAP = d0->p0, d8->p2, d16->p4 */ if (npe_logical_reg_write16(npe, NPE_REGMAP, 0x820, i)) return -ETIMEDOUT; if (npe_logical_reg_write8(npe, NPE_CINDEX, 0, i)) return -ETIMEDOUT;
}
/* post exec */ /* clear active bit in debug level */
npe_cmd_write(npe, ECS_DBG_CTXT_REG_0, CMD_WR_ECS_REG, 0); /* clear the pipeline */
__raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd); /* restore previous values */
__raw_writel(exec_count, &npe->regs->exec_count);
npe_cmd_write(npe, ECS_DBG_CTXT_REG_2, CMD_WR_ECS_REG, ctx_reg2);
/* write reset values to Execution Context Stack registers */ for (val = 0; val < ARRAY_SIZE(ecs_reset); val++)
npe_cmd_write(npe, ecs_reset[val].reg, CMD_WR_ECS_REG,
ecs_reset[val].val);
/* clear the profile counter */
__raw_writel(CMD_CLR_PROFILE_CNT, &npe->regs->exec_status_cmd);
/* *Weneedtoworkoncachedvaluesherebecausetheregister *willreadinvertedbutneedstobewrittennon-inverted.
*/
val = cpu_ixp4xx_features(npe->rmap); /* reset the NPE */
regmap_write(npe->rmap, IXP4XX_EXP_CNFG2, val & ~reset_bit); /* deassert reset */
regmap_write(npe->rmap, IXP4XX_EXP_CNFG2, val | reset_bit);
for (i = 0; i < MAX_RETRIES; i++) {
val = cpu_ixp4xx_features(npe->rmap); if (val & reset_bit) break; /* NPE is back alive */
udelay(1);
} if (i == MAX_RETRIES) return -ETIMEDOUT;
npe_stop(npe);
/* restore NPE configuration bus Control Register - parity settings */
__raw_writel(ctl, &npe->regs->messaging_control); return0;
}
int npe_send_message(struct npe *npe, constvoid *msg, constchar *what)
{ const u32 *send = msg; int cycles = 0;
debug_msg(npe, "Trying to send message %s [%08X:%08X]\n",
what, send[0], send[1]);
if (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNE) {
debug_msg(npe, "NPE input FIFO not empty\n"); return -EIO;
}
staticint ixp4xx_npe_probe(struct platform_device *pdev)
{ int i, found = 0; struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; struct resource *res; struct regmap *rmap;
u32 val;
/* This system has only one syscon, so fetch it */
rmap = syscon_regmap_lookup_by_compatible("syscon"); if (IS_ERR(rmap)) return dev_err_probe(dev, PTR_ERR(rmap), "failed to look up syscon\n");
for (i = 0; i < NPE_COUNT; i++) { struct npe *npe = &npe_tab[i];
res = platform_get_resource(pdev, IORESOURCE_MEM, i); if (!res) return -ENODEV;
val = cpu_ixp4xx_features(rmap);
if (!(val & (IXP4XX_FEATURE_RESET_NPEA << i))) {
dev_info(dev, "NPE%d at %pR not available\n",
i, res); continue; /* NPE already disabled or not present */
}
npe->regs = devm_ioremap_resource(dev, res); if (IS_ERR(npe->regs)) return PTR_ERR(npe->regs);
npe->rmap = rmap;
if (npe_reset(npe)) {
dev_info(dev, "NPE%d at %pR does not reset\n",
i, res); continue;
}
npe->valid = 1;
dev_info(dev, "NPE%d at %pR registered\n", i, res);
found++;
}
if (!found) return -ENODEV;
/* Spawn crypto subdevice if using device tree */ if (IS_ENABLED(CONFIG_OF) && np)
devm_of_platform_populate(dev);
return0;
}
staticvoid ixp4xx_npe_remove(struct platform_device *pdev)
{ int i;
for (i = 0; i < NPE_COUNT; i++) if (npe_tab[i].regs) {
npe_reset(&npe_tab[i]);
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.