/* Set (to enable) or clear (to disable stepping) the SSt bit (bit 8) in Cp0 Debug reg (reg 23, sel 0) */ int mips_ejtag_config_step(struct mips_ejtag *ejtag_info, int enable_step) { struct pracc_queue_info ctx = {.max_code = 7}; pracc_queue_init(&ctx); if (ctx.retval != ERROR_OK) goto exit; pracc_add(&ctx, 0, MIPS32_MFC0(8, 23, 0)); /* move COP0 Debug to $8 */ pracc_add(&ctx, 0, MIPS32_ORI(8, 8, 0x0100)); /* set SSt bit in debug reg */ if (!enable_step) pracc_add(&ctx, 0, MIPS32_XORI(8, 8, 0x0100)); /* clear SSt bit in debug reg */ pracc_add(&ctx, 0, MIPS32_MTC0(8, 23, 0)); /* move $8 to COP0 Debug */ pracc_add(&ctx, 0, MIPS32_LUI(8, UPPER16(ejtag_info->reg8))); /* restore upper 16 bits of $8 */ pracc_add(&ctx, 0, MIPS32_B(NEG16((ctx.code_count + 1)))); /* jump to start */ pracc_add(&ctx, 0, MIPS32_ORI(8, 8, LOWER16(ejtag_info->reg8))); /* restore lower 16 bits of $8 */ ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL); exit: pracc_queue_free(&ctx); return ctx.retval; } /* * Disable memory protection for 0xFF20.0000–0xFF3F.FFFF * It is needed by EJTAG 1.5-2.0, especially for BMIPS CPUs * For example bcm7401 and others. At leas on some * CPUs, DebugMode wont start if this bit is not removed. */ static int disable_dcr_mp(struct mips_ejtag *ejtag_info) { uint32_t dcr; int retval; retval = mips32_dmaacc_read_mem(ejtag_info, EJTAG_DCR, 4, 1, &dcr); if (retval != ERROR_OK) goto error; dcr &= ~EJTAG_DCR_MP; retval = mips32_dmaacc_write_mem(ejtag_info, EJTAG_DCR, 4, 1, &dcr); if (retval != ERROR_OK) goto error; return ERROR_OK; error: LOG_ERROR("Failed to remove DCR MPbit!"); return retval; }
static int ath79_spi_bitbang_codegen(struct ath79_flash_bank *ath79_info, struct pracc_queue_info *ctx, uint8_t *data, int len, int partial_xfer) { uint32_t cs_high = ATH79_SPI_CS_ALLHI; uint32_t cs_low = ath79_chipselects[ath79_info->chipselect]; uint32_t clock_high = cs_low | ATH79_SPI_CE_HI; uint32_t clock_low = cs_low; uint32_t pracc_out = 0; uint32_t io_base = ath79_info->io_base; const uint32_t preamble1[] = { /* $15 = MIPS32_PRACC_BASE_ADDR */ MIPS32_LUI(0, 15, PRACC_UPPER_BASE_ADDR), /* $1 = io_base */ MIPS32_LUI(0, 1, UPPER16(io_base)), }; ath79_pracc_addn(ctx, preamble1, ARRAY_SIZE(preamble1)); if (ath79_info->spi.pre_deselect) { /* Clear deselect flag so we don't deselect again if * this is a partial xfer. */ ath79_info->spi.pre_deselect = 0; const uint32_t pre_deselect[] = { /* [$1 + FS] = 1 (enable flash io register access) */ MIPS32_LUI(0, 2, UPPER16(1)), MIPS32_ORI(0, 2, 2, LOWER16(1)), MIPS32_SW(0, 2, ATH79_REG_FS, 1), /* deselect flash just in case */ /* $2 = SPI_CS_DIS */ MIPS32_LUI(0, 2, UPPER16(cs_high)), MIPS32_ORI(0, 2, 2, LOWER16(cs_high)), /* [$1 + WRITE] = $2 */ MIPS32_SW(0, 2, ATH79_REG_WRITE, 1), }; ath79_pracc_addn(ctx, pre_deselect, ARRAY_SIZE(pre_deselect)); } const uint32_t preamble2[] = { /* t0 = CLOCK_LOW + 0-bit */ MIPS32_LUI(0, 8, UPPER16((clock_low + 0))), MIPS32_ORI(0, 8, 8, LOWER16((clock_low + 0))), /* t1 = CLOCK_LOW + 1-bit */ MIPS32_LUI(0, 9, UPPER16((clock_low + 1))), MIPS32_ORI(0, 9, 9, LOWER16((clock_low + 1))), /* t2 = CLOCK_HIGH + 0-bit */ MIPS32_LUI(0, 10, UPPER16((clock_high + 0))), MIPS32_ORI(0, 10, 10, LOWER16((clock_high + 0))), /* t3 = CLOCK_HIGH + 1-bit */ MIPS32_LUI(0, 11, UPPER16((clock_high + 1))), MIPS32_ORI(0, 11, 11, LOWER16((clock_high + 1))), }; ath79_pracc_addn(ctx, preamble2, ARRAY_SIZE(preamble2)); for (int i = 0; i < len; i++) { uint8_t x = data[i]; /* Generate bitbang code for one byte, highest bit first .*/ for (int j = BITS_PER_BYTE - 1; j >= 0; j--) { int bit = ((x >> j) & 1); if (bit) { /* [$1 + WRITE] = t1 */ pracc_add(ctx, 0, MIPS32_SW(0, 9, ATH79_REG_WRITE, 1)); /* [$1 + WRITE] = t3 */ pracc_add(ctx, 0, MIPS32_SW(0, 11, ATH79_REG_WRITE, 1)); } else { /* [$1 + WRITE] = t0 */ pracc_add(ctx, 0, MIPS32_SW(0, 8, ATH79_REG_WRITE, 1)); /* [$1 + WRITE] = t2 */ pracc_add(ctx, 0, MIPS32_SW(0, 10, ATH79_REG_WRITE, 1)); } } if (i % 4 == 3) { /* $3 = [$1 + DATA] */ pracc_add(ctx, 0, MIPS32_LW(0, 3, ATH79_REG_DATA, 1)); /* [OUTi] = $3 */ pracc_add(ctx, MIPS32_PRACC_PARAM_OUT + pracc_out, MIPS32_SW(0, 3, PRACC_OUT_OFFSET + pracc_out, 15)); pracc_out += 4; } } if (len & 3) { /* not a multiple of 4 bytes */ /* $3 = [$1 + DATA] */ pracc_add(ctx, 0, MIPS32_LW(0, 3, ATH79_REG_DATA, 1)); /* [OUTi] = $3 */ pracc_add(ctx, MIPS32_PRACC_PARAM_OUT + pracc_out, MIPS32_SW(0, 3, PRACC_OUT_OFFSET + pracc_out, 15)); pracc_out += 4; } if (ath79_info->spi.post_deselect && !partial_xfer) { const uint32_t post_deselect[] = { /* $2 = SPI_CS_DIS */ MIPS32_LUI(0, 2, UPPER16(cs_high)), MIPS32_ORI(0, 2, 2, LOWER16(cs_high)), /* [$1 + WRITE] = $2 */ MIPS32_SW(0, 2, ATH79_REG_WRITE, 1), /* [$1 + FS] = 0 (disable flash io register access) */ MIPS32_XORI(0, 2, 2, 0), MIPS32_SW(0, 2, ATH79_REG_FS, 1), }; ath79_pracc_addn(ctx, post_deselect, ARRAY_SIZE(post_deselect)); } /* common pracc epilogue */ /* jump to start */ pracc_add(ctx, 0, MIPS32_B(0, NEG16(ctx->code_count + 1))); /* restore $15 from DeSave */ pracc_add(ctx, 0, MIPS32_MFC0(0, 15, 31, 0)); return pracc_out / 4; }