This is an automated email from Gerrit. Jiri Kastner ([email protected]) just uploaded a new patch set to Gerrit, which you can find at http://openocd.zylin.com/6143
-- gerrit commit fb64faee89a77a76cfbdbd37051cbe012801c92b Author: Jiri Kastner <[email protected]> Date: Tue Apr 6 20:55:56 2021 +0200 target: add mpc5xxx common files Change-Id: Iee16f2a9d970a39c23f18a0538fd850dfdbc8c07 Signed-off-by: Jiri Kastner <[email protected]> diff --git a/src/target/mpc5xxx.c b/src/target/mpc5xxx.c new file mode 100644 index 0000000..7681591 --- /dev/null +++ b/src/target/mpc5xxx.c @@ -0,0 +1,660 @@ +/*************************************************************************** + * Copyright (C) 2017 by James Murray <[email protected] * + * Based on code: * + * Copyright (C) 2010 by Oleksandr Tymoshenko <[email protected]> * + * Based on mips_m4k code: * + * Copyright (C) 2008 by Spencer Oliver <[email protected]> * + * Copyright (C) 2008 by David T.L. Wong * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "jtag/jtag.h" +#include "register.h" +#include "algorithm.h" +#include "target.h" +#include "breakpoints.h" +#include "target_type.h" +#include "mpc5xxx_jtag.h" +#include "mpc5xxx.h" +#include "jtag/interface.h" + +const char * const mpc5xxx_core_reg_list[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", + "r32", "r33", "r34", "r35", "r36", "r37", "r38", "r39", + "r40", "r41", "r42", "r43", "r44", "r45", "r46", "r47", + "r48", "r49", "r50", "r51", "r52", "r53", "r54", "r55", + "r56", "r57", "r58", "r59", "r60", "r61", "r62", "r63", + "pc", "msr", "cnd", "lr", "cnt", "xer", "mq", "r71", +}; + +static const struct mpc5xxx_core_reg + mpc56xx_core_reg_list_arch_info[MPC5XXX_NUMCOREREGS] = { + {0, NULL, NULL}, + {1, NULL, NULL}, + {2, NULL, NULL}, + {3, NULL, NULL}, + {4, NULL, NULL}, + {5, NULL, NULL}, + {6, NULL, NULL}, + {7, NULL, NULL}, + {8, NULL, NULL}, + {9, NULL, NULL}, + {10, NULL, NULL}, + {11, NULL, NULL}, + {12, NULL, NULL}, + {13, NULL, NULL}, + {14, NULL, NULL}, + {15, NULL, NULL}, + {16, NULL, NULL}, + {17, NULL, NULL}, + {18, NULL, NULL}, + {19, NULL, NULL}, + {20, NULL, NULL}, + {21, NULL, NULL}, + {22, NULL, NULL}, + {23, NULL, NULL}, + {24, NULL, NULL}, + {25, NULL, NULL}, + {26, NULL, NULL}, + {27, NULL, NULL}, + {28, NULL, NULL}, + {29, NULL, NULL}, + {30, NULL, NULL}, + {31, NULL, NULL}, + {32, NULL, NULL}, + {33, NULL, NULL}, + {34, NULL, NULL}, + {35, NULL, NULL}, + {36, NULL, NULL}, + {37, NULL, NULL}, + {38, NULL, NULL}, + {39, NULL, NULL}, + {40, NULL, NULL}, + {41, NULL, NULL}, + {42, NULL, NULL}, + {43, NULL, NULL}, + {44, NULL, NULL}, + {45, NULL, NULL}, + {46, NULL, NULL}, + {47, NULL, NULL}, + {48, NULL, NULL}, + {49, NULL, NULL}, + {50, NULL, NULL}, + {51, NULL, NULL}, + {52, NULL, NULL}, + {53, NULL, NULL}, + {54, NULL, NULL}, + {55, NULL, NULL}, + {56, NULL, NULL}, + {57, NULL, NULL}, + {58, NULL, NULL}, + {59, NULL, NULL}, + {60, NULL, NULL}, + {61, NULL, NULL}, + {62, NULL, NULL}, + {63, NULL, NULL}, + {64, NULL, NULL}, + {65, NULL, NULL}, + {66, NULL, NULL}, + {67, NULL, NULL}, + {68, NULL, NULL}, + {69, NULL, NULL}, + {70, NULL, NULL}, + {71, NULL, NULL}, +}; + +int mpc5xxx_read_core_reg(struct target *target, int num) +{ + uint32_t reg_value; + + /* get pointers to arch-specific information */ + struct mpc5xxx_common *mpc56xx = target_to_mpc5xxx(target); + + if ((num < 0) || (num >= MPC5XXX_NUMCOREREGS)) + return ERROR_COMMAND_SYNTAX_ERROR; + + reg_value = mpc56xx->core_regs[num]; + buf_set_u32(mpc56xx->core_cache->reg_list[num].value, 0, 32, reg_value); + mpc56xx->core_cache->reg_list[num].valid = 1; + mpc56xx->core_cache->reg_list[num].dirty = 0; + + return ERROR_OK; +} + +int mpc5xxx_write_core_reg(struct target *target, int num) +{ + uint32_t reg_value; + + /* get pointers to arch-specific information */ + struct mpc5xxx_common *mpc56xx = target_to_mpc5xxx(target); + + if ((num < 0) || (num >= MPC5XXX_NUMCOREREGS)) + return ERROR_COMMAND_SYNTAX_ERROR; + + reg_value = buf_get_u32(mpc56xx->core_cache->reg_list[num].value, 0, 32); + mpc56xx->core_regs[num] = reg_value; + LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", num, reg_value); + mpc56xx->core_cache->reg_list[num].valid = 1; + mpc56xx->core_cache->reg_list[num].dirty = 0; + + return ERROR_OK; +} + +int mpc5xxx_get_core_reg(struct reg *reg) +{ + int retval; + struct mpc5xxx_core_reg *mpc56xx_reg = reg->arch_info; + struct target *target = mpc56xx_reg->target; + + if (target->state != TARGET_HALTED) + return ERROR_TARGET_NOT_HALTED; + + retval = mpc5xxx_read_core_reg(target, mpc56xx_reg->num); + + return retval; +} + +int mpc5xxx_set_core_reg(struct reg *reg, uint8_t *buf) +{ + struct mpc5xxx_core_reg *mpc56xx_reg = reg->arch_info; + struct target *target = mpc56xx_reg->target; + uint32_t value = buf_get_u32(buf, 0, 32); + + if (target->state != TARGET_HALTED) + return ERROR_TARGET_NOT_HALTED; + + buf_set_u32(reg->value, 0, 32, value); + reg->dirty = 1; + reg->valid = 1; + + return ERROR_OK; +} + +const struct reg_arch_type mpc5xxx_reg_type = { + .get = mpc5xxx_get_core_reg, + .set = mpc5xxx_set_core_reg, +}; + +struct reg_cache *mpc5xxx_build_reg_cache(struct target *target) +{ + int num_regs = MPC5XXX_NUMCOREREGS; + struct mpc5xxx_common *mpc56xx = target_to_mpc5xxx(target); + struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache); + struct reg_cache *cache = malloc(sizeof(struct reg_cache)); + struct reg *reg_list = calloc(num_regs, sizeof(struct reg)); + struct mpc5xxx_core_reg *arch_info = + malloc(sizeof(struct mpc5xxx_core_reg) * num_regs); + int i; + + /* Build the process context cache */ + cache->name = "mpc5xxx registers"; + cache->next = NULL; + cache->reg_list = reg_list; + cache->num_regs = num_regs; + (*cache_p) = cache; + mpc56xx->core_cache = cache; + + for (i = 0; i < num_regs; i++) { + arch_info[i] = mpc56xx_core_reg_list_arch_info[i]; + arch_info[i].target = target; + arch_info[i].mpc56xx_common = mpc56xx; + reg_list[i].name = mpc5xxx_core_reg_list[i]; + reg_list[i].size = 32; + reg_list[i].value = calloc(1, 4); + reg_list[i].dirty = 0; + reg_list[i].valid = 0; + reg_list[i].type = &mpc5xxx_reg_type; + reg_list[i].arch_info = &arch_info[i]; + } + + return cache; +} + +int mpc5xxx_assert_reset(struct target *target) +{ + struct mpc5xxx_common *mpc56xx = target_to_mpc5xxx(target); + int retval; + + printf("mpc56xx_assert_reset\n"); + + adapter_assert_reset(); + + /* Init code wants to be talking to JTAGC. */ + retval = mpc5xxx_jtag_access_jtagc(&mpc56xx->jtag); + if (retval) + return retval; + + return ERROR_OK; +} + +int mpc5xxx_read_memory(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, uint8_t *buffer) +{ + struct mpc5xxx_common *mpc56xx = target_to_mpc5xxx(target); + + LOG_DEBUG("address: 0x%8.8" PRIx32 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", + (unsigned int)address, + size, + count); + + /* sanitize arguments */ + if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer)) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) + return ERROR_TARGET_UNALIGNED_ACCESS; + + switch (size) { + case 4: + return mpc5xxx_jtag_read_memory32(&mpc56xx->jtag, address, count, + (uint32_t *)(void *)buffer); + break; + case 2: + return mpc5xxx_jtag_read_memory16(&mpc56xx->jtag, address, count, + (uint16_t *)(void *)buffer); + break; + case 1: + return mpc5xxx_jtag_read_memory8(&mpc56xx->jtag, address, count, buffer); + break; + default: + break; + } + + return ERROR_OK; +} + +int mpc5xxx_write_memory(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, const uint8_t *buffer) +{ + struct mpc5xxx_common *mpc56xx = target_to_mpc5xxx(target); + + LOG_DEBUG("address: 0x%8.8" PRIx32 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", + (unsigned int)address, + size, + count); + + /* sanitize arguments */ + if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer)) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) + return ERROR_TARGET_UNALIGNED_ACCESS; + + switch (size) { + case 4: + return mpc5xxx_jtag_write_memory32(&mpc56xx->jtag, address, count, + (uint32_t *)(void *)buffer); + break; + case 2: + return mpc5xxx_jtag_write_memory16(&mpc56xx->jtag, address, count, + (uint16_t *)(void *)buffer); + break; + case 1: + return mpc5xxx_jtag_write_memory8(&mpc56xx->jtag, address, count, buffer); + break; + default: + break; + } + + return ERROR_OK; +} + +int mpc5xxx_init_target(struct command_context *cmd_ctx, + struct target *target) +{ + struct mpc5xxx_common *mpc56xx = target_to_mpc5xxx(target); + printf("init_target\n"); + mpc56xx->jtag.tap = target->tap; /* why? */ + mpc5xxx_build_reg_cache(target); + /* mpc56xx->num_inst_bpoints_avail = 2; */ + return ERROR_OK; +} + +int mpc5xxx_examine(struct target *target) +{ + uint32_t osr; + struct mpc5xxx_common *mpc56xx = target_to_mpc5xxx(target); + printf("examine\n"); + if (!target_was_examined(target)) { + + target_set_examined(target); + + /* we will configure later */ + mpc56xx->bp_scanned = 0; + mpc56xx->num_inst_bpoints = 0; + mpc56xx->num_data_bpoints = 0; + mpc56xx->num_inst_bpoints_avail = 0; + mpc56xx->num_data_bpoints_avail = 0; + + /* Check if processor halted. */ + mpc5xxx_once_osr_read(&mpc56xx->jtag, &osr); + if (osr & MPC5XXX_OSR_HALT_DEBUG) { /* FIXME say halted if in DEBUG mode */ + LOG_INFO("target is halted/debug"); + target->state = TARGET_HALTED; + } else + target->state = TARGET_RUNNING; + } + + return ERROR_OK; +} + +int mpc5xxx_arch_state(struct target *target) +{ + struct mpc5xxx_common *mpc56xx = target_to_mpc5xxx(target); + + LOG_USER("target halted due to %s, pc: 0x%8.8" PRIx32 "", + debug_reason_name(target), mpc56xx->jtag.dpc); + + return ERROR_OK; +} + +/* This next function derived from mips32.c */ +int mpc5xxx_get_gdb_reg_list(struct target *target, struct reg **reg_list[], + int *reg_list_size, enum target_register_class reg_class) +{ + /* get pointers to arch-specific information */ + struct mpc5xxx_common *mpc56xx = target_to_mpc5xxx(target); + unsigned int i; + + /* include floating point registers */ + *reg_list_size = MPC5XXX_NUMCOREREGS; + *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); + + for (i = 0; i < MPC5XXX_NUMCOREREGS; i++) + (*reg_list)[i] = &mpc56xx->core_cache->reg_list[i]; + + return ERROR_OK; +} + +int mpc5xxx_jtag_read_memory32(struct mpc5xxx_jtag *jtag_info, + uint32_t addr, int count, uint32_t *buffer) +{ + int i, retval; + uint32_t data; + + for (i = 0; i < count; i++) { + retval = mpc5xxx_once_nexus_read(jtag_info, addr + i*4, &data, 32); + + if (retval != ERROR_OK) + return retval; + + /* XXX: Assume PPC32 is BE */ + buffer[i] = be_to_h_u32((uint8_t *)&data); + } + + return ERROR_OK; +} + +int mpc5xxx_jtag_read_memory16(struct mpc5xxx_jtag *jtag_info, + uint32_t addr, int count, uint16_t *buffer) +{ + int i, retval; + uint32_t data; + + i = 0; + + /* any unaligned half-words? */ + if (addr & 3) { + retval = mpc5xxx_once_nexus_read(jtag_info, addr + i*2, &data, 32); + + if (retval != ERROR_OK) + return retval; + + /* XXX: Assume PPC32 is BE */ + data = be_to_h_u32((uint8_t *)&data); + buffer[i] = (data >> 16) & 0xffff; + i++; + } + + /* read all complete words */ + for (; i < (count & ~1); i += 2) { + retval = mpc5xxx_once_nexus_read(jtag_info, addr + i*2, &data, 32); + + if (retval != ERROR_OK) + return retval; + + /* XXX: Assume PPC32 is BE */ + data = be_to_h_u32((uint8_t *)&data); + buffer[i] = data & 0xffff; + buffer[i+1] = (data >> 16) & 0xffff; + } + + /* last halfword */ + if (i < count) { + retval = mpc5xxx_once_nexus_read(jtag_info, addr + i*2, &data, 32); + + if (retval != ERROR_OK) + return retval; + + /* XXX: Assume PPC32 is BE */ + data = be_to_h_u32((uint8_t *)&data); + buffer[i] = data & 0xffff; + } + + return ERROR_OK; +} + +int mpc5xxx_jtag_read_memory8(struct mpc5xxx_jtag *jtag_info, + uint32_t addr, int count, uint8_t *buffer) +{ + int i, j, retval; + uint8_t data[4]; + i = 0; + + /* Do we have non-aligned bytes? */ + if (addr & 3) { + retval = mpc5xxx_once_nexus_read(jtag_info, addr + i, (uint32_t *)(void *)data, 32); + + if (retval != ERROR_OK) + return retval; + + for (j = addr & 3; (j < 4) && (i < count); j++, i++) + buffer[i] = data[3-j]; + } + + /* read all complete words */ + for (; i < (count & ~3); i += 4) { + retval = mpc5xxx_once_nexus_read(jtag_info, addr + i, (uint32_t *)(void *)data, 32); + + if (retval != ERROR_OK) + return retval; + + for (j = 0; j < 4; j++) + buffer[i+j] = data[3-j]; + } + + /* remaining bytes */ + if (i < count) { + retval = mpc5xxx_once_nexus_read(jtag_info, addr + i, (uint32_t *)(void *)data, 32); + + if (retval != ERROR_OK) + return retval; + + for (j = 0; i + j < count; j++) + buffer[i+j] = data[3-j]; + } + + return ERROR_OK; +} + +int mpc5xxx_jtag_write_memory32(struct mpc5xxx_jtag *jtag_info, + uint32_t addr, int count, const uint32_t *buffer) +{ + int i, retval; + uint32_t data; + + for (i = 0; i < count; i++) { + /* XXX: Assume PPC32 is BE */ + h_u32_to_be((uint8_t *)&data, buffer[i]); + retval = mpc5xxx_once_nexus_write(jtag_info, addr + i*4, data, 32); + + if (retval != ERROR_OK) + return retval; + + } + + return ERROR_OK; +} + +int mpc5xxx_jtag_write_memory16(struct mpc5xxx_jtag *jtag_info, + uint32_t addr, int count, const uint16_t *buffer) +{ + int i, retval; + uint32_t data; + uint32_t data_out; + + i = 0; + + /* + * Do we have any non-aligned half-words? + */ + if (addr & 3) { + /* + * _read will read whole world, no need to fiddle + * with address. It will be truncated in set_addr ???? JSM + */ + retval = mpc5xxx_once_nexus_read(jtag_info, addr, &data, 32); + + if (retval != ERROR_OK) + return retval; + + data = be_to_h_u32((uint8_t *)&data); + data = (buffer[i] << 16) | (data & 0xffff); + h_u32_to_be((uint8_t *)&data_out, data); + + retval = mpc5xxx_once_nexus_write(jtag_info, addr, data_out, 32); + + if (retval != ERROR_OK) + return retval; + + i++; + } + + /* write all complete words */ + for (; i < (count & ~1); i += 2) { + /* XXX: Assume PPC32 is BE */ + data = (buffer[i+1] << 16) | buffer[i]; + h_u32_to_be((uint8_t *)&data_out, data); + + retval = mpc5xxx_once_nexus_write(jtag_info, addr + i*2, data_out, 32); + + if (retval != ERROR_OK) + return retval; + } + + /* last halfword */ + if (i < count) { + retval = mpc5xxx_once_nexus_read(jtag_info, addr + i*2, &data, 32); + + if (retval != ERROR_OK) + return retval; + + data = be_to_h_u32((uint8_t *)&data); + data &= ~0xffff; + data |= buffer[i]; + h_u32_to_be((uint8_t *)&data_out, data); + + retval = mpc5xxx_once_nexus_write(jtag_info, addr + i*2, data_out, 32); + + if (retval != ERROR_OK) + return retval; + } + + return ERROR_OK; +} + +int mpc5xxx_jtag_write_memory8(struct mpc5xxx_jtag *jtag_info, + uint32_t addr, int count, const uint8_t *buffer) +{ + int i, j, retval; + uint32_t data; + uint32_t data_out; + + i = 0; + + /* + * Do we have any non-aligned bytes? + */ + if (addr & 3) { + /* + * mwa_read will read whole world, no nead to fiddle + * with address. It will be truncated in set_addr + */ + retval = mpc5xxx_once_nexus_read(jtag_info, addr, &data, 32); + + if (retval != ERROR_OK) + return retval; + + data = be_to_h_u32((uint8_t *)&data); + for (j = addr & 3; (j < 4) && (i < count); j++, i++) { + data &= ~(0xff << j*8); + data |= (buffer[i] << j*8); + } + + h_u32_to_be((uint8_t *)&data_out, data); + retval = mpc5xxx_once_nexus_write(jtag_info, addr, data_out, 32); + + if (retval != ERROR_OK) + return retval; + } + + + /* write all complete words */ + for (; i < (count & ~3); i += 4) { + data = 0; + + for (j = 0; j < 4; j++) + data |= (buffer[j+i] << j*8); + + h_u32_to_be((uint8_t *)&data_out, data); + + retval = mpc5xxx_once_nexus_write(jtag_info, addr + i, data_out, 32); + + if (retval != ERROR_OK) + return retval; + } + + /* + * Write trailing bytes + */ + if (i < count) { + retval = mpc5xxx_once_nexus_read(jtag_info, addr + i, &data, 32); + + if (retval != ERROR_OK) + return retval; + + data = be_to_h_u32((uint8_t *)&data); + for (j = 0; i < count; j++, i++) { + data &= ~(0xff << j*8); + data |= (buffer[j+i] << j*8); + } + + h_u32_to_be((uint8_t *)&data_out, data); + + retval = mpc5xxx_once_nexus_write(jtag_info, addr+i, data_out, 32); + + if (retval != ERROR_OK) + return retval; + } + + return ERROR_OK; +} diff --git a/src/target/mpc5xxx.h b/src/target/mpc5xxx.h new file mode 100644 index 0000000..d9743a7 --- /dev/null +++ b/src/target/mpc5xxx.h @@ -0,0 +1,177 @@ +/*************************************************************************** + * Copyright (C) 2017 by James Murray <[email protected] * + * Based on code: * + * Copyright (C) 2010 by Oleksandr Tymoshenko <[email protected]> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifndef MPC5XXX +#define MPC5XXX + +struct target; + +#define MPC5XXX_NUMCOREREGS 72 /* GDB/Zylin CDT asks for high non-existent regs */ + +enum mpc5xxx_reg_nums { + MPC5XXX_REG_R0 = 0, + MPC5XXX_REG_R1, /* also SP ? */ + MPC5XXX_REG_R2, + MPC5XXX_REG_R3, + MPC5XXX_REG_R4, + MPC5XXX_REG_R5, + MPC5XXX_REG_R6, + MPC5XXX_REG_R7, + MPC5XXX_REG_R8, + MPC5XXX_REG_R9, + MPC5XXX_REG_R10, + MPC5XXX_REG_R11, + MPC5XXX_REG_R12, + MPC5XXX_REG_R13, + MPC5XXX_REG_R14, + MPC5XXX_REG_R15, + MPC5XXX_REG_R16, + MPC5XXX_REG_R17, + MPC5XXX_REG_R18, + MPC5XXX_REG_R19, + MPC5XXX_REG_R20, + MPC5XXX_REG_R21, + MPC5XXX_REG_R22, + MPC5XXX_REG_R23, + MPC5XXX_REG_R24, + MPC5XXX_REG_R25, + MPC5XXX_REG_R26, + MPC5XXX_REG_R27, + MPC5XXX_REG_R28, + MPC5XXX_REG_R29, + MPC5XXX_REG_R30, + MPC5XXX_REG_R31, + MPC5XXX_REG_R32, + MPC5XXX_REG_R33, + MPC5XXX_REG_R34, + MPC5XXX_REG_R35, + MPC5XXX_REG_R36, + MPC5XXX_REG_R37, + MPC5XXX_REG_R38, + MPC5XXX_REG_R39, + MPC5XXX_REG_R40, + MPC5XXX_REG_R41, + MPC5XXX_REG_R42, + MPC5XXX_REG_R43, + MPC5XXX_REG_R44, + MPC5XXX_REG_R45, + MPC5XXX_REG_R46, + MPC5XXX_REG_R47, + MPC5XXX_REG_R48, + MPC5XXX_REG_R49, + MPC5XXX_REG_R50, + MPC5XXX_REG_R51, + MPC5XXX_REG_R52, + MPC5XXX_REG_R53, + MPC5XXX_REG_R54, + MPC5XXX_REG_R55, + MPC5XXX_REG_R56, + MPC5XXX_REG_R57, + MPC5XXX_REG_R58, + MPC5XXX_REG_R59, + MPC5XXX_REG_R60, + MPC5XXX_REG_R61, + MPC5XXX_REG_R62, + MPC5XXX_REG_R63, + MPC5XXX_REG_PC, + MPC5XXX_REG_MSR, + MPC5XXX_REG_CND, + MPC5XXX_REG_LR, + MPC5XXX_REG_CNT, + MPC5XXX_REG_XER, + MPC5XXX_REG_MQ, + MPC5XXX_REG_R71, +}; + +struct mpc5xxx_comparator { + int used; + uint32_t bp_value; + uint32_t reg_address; +}; + +struct mpc5xxx_common { + int common_magic; + struct mpc5xxx_jtag jtag; + struct reg_cache *core_cache; + uint32_t core_regs[MPC5XXX_NUMCOREREGS]; + + int bp_scanned; + int num_inst_bpoints; + int num_data_bpoints; + int num_inst_bpoints_avail; + int num_data_bpoints_avail; + struct mpc5xxx_comparator *inst_break_list; + struct mpc5xxx_comparator *data_break_list; + int jtag_state; + uint32_t saved_ctl ; + uint32_t saved_msr ; + uint32_t ctl_on_entry ; + uint32_t msr_on_entry ; +}; + +static inline struct mpc5xxx_common * +target_to_mpc5xxx(struct target *target) +{ + return (struct mpc5xxx_common *)target->arch_info; +} + +struct mpc5xxx_core_reg { + uint32_t num; + struct target *target; + struct mpc5xxx_common *mpc56xx_common; +}; + +extern const char * const mpc5xxx_core_reg_list[]; +extern const struct mpc5xxx_core_reg + mpc5xxx_core_reg_list_arch_info[]; + +extern const struct reg_arch_type mpc5xxx_reg_type; + +int mpc5xxx_read_core_reg(struct target *target, int num); +int mpc5xxx_write_core_reg(struct target *target, int num); +int mpc5xxx_get_core_reg(struct reg *reg); +int mpc5xxx_set_core_reg(struct reg *reg, uint8_t *buf); +struct reg_cache *mpc5xxx_build_reg_cache(struct target *target); +int mpc5xxx_assert_reset(struct target *target); +int mpc5xxx_read_memory(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, uint8_t *buffer); +int mpc5xxx_write_memory(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, const uint8_t *buffer); +int mpc5xxx_init_target(struct command_context *cmd_ctx, + struct target *target); +int mpc5xxx_examine(struct target *target); +int mpc5xxx_arch_state(struct target *target); +int mpc5xxx_get_gdb_reg_list(struct target *target, struct reg **reg_list[], + int *reg_list_size, enum target_register_class reg_class); + +int mpc5xxx_jtag_read_memory32(struct mpc5xxx_jtag *jtag_info, + uint32_t addr, int count, uint32_t *buffer); +int mpc5xxx_jtag_read_memory16(struct mpc5xxx_jtag *jtag_info, + uint32_t addr, int count, uint16_t *buffer); +int mpc5xxx_jtag_read_memory8(struct mpc5xxx_jtag *jtag_info, + uint32_t addr, int count, uint8_t *buffer); + +int mpc5xxx_jtag_write_memory32(struct mpc5xxx_jtag *jtag_info, + uint32_t addr, int count, const uint32_t *buffer); +int mpc5xxx_jtag_write_memory16(struct mpc5xxx_jtag *jtag_info, + uint32_t addr, int count, const uint16_t *buffer); +int mpc5xxx_jtag_write_memory8(struct mpc5xxx_jtag *jtag_info, + uint32_t addr, int count, const uint8_t *buffer); + +#endif diff --git a/src/target/mpc5xxx_jtag.c b/src/target/mpc5xxx_jtag.c new file mode 100644 index 0000000..ec19bda --- /dev/null +++ b/src/target/mpc5xxx_jtag.c @@ -0,0 +1,624 @@ +/*************************************************************************** + * Copyright (C) 2017 by James Murray <[email protected] * + * Based on code: * + * Copyright (C) 2010 by Oleksandr Tymoshenko <[email protected]> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "target.h" +#include "jtag/jtag.h" +#include "mpc5xxx_jtag.h" +#include "jtag/interface.h" + +#define READ_MAXLOOPS 500 + +int mpc5xxx_jtag_set_instr(struct mpc5xxx_jtag *jtag_info, int new_instr) +{ + struct jtag_tap *tap; + int busy = 0; + + tap = jtag_info->tap; + if (tap == NULL) + return ERROR_FAIL; + + if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != (uint32_t)new_instr) { + do { + struct scan_field field; + uint8_t t[4]; + uint8_t ret[4]; + + field.num_bits = tap->ir_length; + field.out_value = t; + buf_set_u32(t, 0, field.num_bits, new_instr); + field.in_value = ret; + + jtag_add_ir_scan(tap, &field, TAP_IDLE); + if (jtag_execute_queue() != ERROR_OK) { + LOG_ERROR("%s: setting address failed", __func__); + return ERROR_FAIL; + } + busy = buf_get_u32(ret, 2, 1); + } while (busy); /* check for busy bit */ + } + + return ERROR_OK; +} + +int mpc5xxx_jtag_read_data(struct mpc5xxx_jtag *jtag_info, + uint32_t *pdata, uint32_t size) +{ + + struct scan_field field; + uint8_t data_buf[4]; + uint8_t busy_buf[4]; + int busy; + + if (size > 32) + size = 32; + + + do { + int jterr; + memset(data_buf, 0, sizeof(data_buf)); + memset(busy_buf, 0, sizeof(busy_buf)); + + field.num_bits = size; + field.out_value = NULL; + field.in_value = data_buf; + + jtag_add_dr_scan(jtag_info->tap, 1, &field, TAP_IDLE); + + jterr = jtag_execute_queue(); + if (jterr != ERROR_OK) { + LOG_ERROR("%s: reading data failed with error %d", __func__, jterr); + return ERROR_FAIL; + } + + busy = buf_get_u32(busy_buf, 0, 1); + } while (busy); + + *pdata = buf_get_u32(data_buf, 0, 32); + + return ERROR_OK; +} + +int mpc5xxx_jtag_write_data(struct mpc5xxx_jtag *jtag_info, + uint32_t data, uint32_t size) +{ + + struct scan_field field; + uint8_t data_buf[4]; + uint8_t busy_buf[4]; + int busy; + + if (size > 32) + size = 32; + + + do { + int jterr ; + memset(data_buf, 0, sizeof(data_buf)); + memset(busy_buf, 0, sizeof(busy_buf)); + + buf_set_u32(data_buf, 0, size, data); + field.num_bits = size; + field.in_value = NULL; + field.out_value = data_buf; + + jtag_add_dr_scan(jtag_info->tap, 1, &field, TAP_IDLE); + + jterr = jtag_execute_queue(); + if (jterr != ERROR_OK) { + LOG_ERROR("%s: write data failed with error %d", __func__, jterr); + return ERROR_FAIL; + } + + busy = buf_get_u32(busy_buf, 0, 0); + } while (busy); + + + return ERROR_OK; +} + +int mpc5xxx_jtag_access_once(struct mpc5xxx_jtag *jtag_info) +{ + int res; + uint32_t did; + + if (jtag_info->once == MPC5XXX_TAP_INVALID) { + printf("OnCE not yet set.\n"); + return ERROR_FAIL; + } + + if (jtag_info->current_tap == jtag_info->once) + return ERROR_OK; + + if (jtag_info->current_tap != MPC5XXX_TAP_JTAG) { + /* Revert to JTAGC first */ + res = mpc5xxx_jtag_access_jtagc(jtag_info); + if (res) + return res; + } + + printf("Switching to ONCE, (TAP id = 0x%02x)\n", jtag_info->once); + + res = mpc5xxx_jtag_set_instr(jtag_info, jtag_info->once); + if (res) + return res; + + jtag_info->current_tap = jtag_info->once; + /* OnCE uses 10 bits */ + jtag_info->tap->ir_length = 10; + + /* Read the OnCE JTAG ID for info */ + res = mpc5xxx_once_read(jtag_info, MPC5XXX_ONCE_DID, &did, 32); + if (res) + return res; + + if (did != jtag_info->tap->expected_ids[1]) { + printf("Serious JTAG problem! Didn't find OnCE ID (0x%08x), found 0x%08x.\n", + jtag_info->tap->expected_ids[1], did); + printf("Exiting!!!\n"); + exit(2); + return ERROR_FAIL; + } +printf("Switched to ONCE ok.\n"); + return ERROR_OK; +} + +int mpc5xxx_jtag_access_jtagc(struct mpc5xxx_jtag *jtag_info) +{ + int res; + uint32_t did; + +#define JTAG_TAP_ID 0x3e + + if (jtag_info->current_tap == MPC5XXX_TAP_JTAG) + + return ERROR_OK; + + printf("Switching to JTAGC\n"); + (void)interface_jtag_add_reset(0, 0); + + /* Get out of whatever TAP we were in and return to JTAGC */ + res = jtag_add_statemove(TAP_DRPAUSE); + if (res) + return res; + + /* Run-test/idle for JTAGC */ + res = jtag_add_statemove(TAP_IDLE); + if (res) + return res; + + jtag_info->current_tap = MPC5XXX_TAP_JTAG; + jtag_info->tap->ir_length = jtag_info->jtag_irlen; + + /* Validate that the correct IDcode is here */ + res = mpc5xxx_jtagc_read(jtag_info, MPC5XXX_INST_IDCODE, &did, 32); + if (res) + return res; + if (did != jtag_info->tap->expected_ids[0]) { + printf("Serious JTAG problem! Didn't find JTAG ID (0x%08x), found 0x%08x.\n", + jtag_info->tap->expected_ids[0], did); + printf("Exiting!!!\n"); + exit(2); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +int mpc5xxx_jtagc_read(struct mpc5xxx_jtag *jtag_info, + uint32_t addr, uint32_t *value, uint32_t size) +{ + int res; + + res = mpc5xxx_jtag_access_jtagc(jtag_info); + if (res) + return res; + + res = mpc5xxx_jtag_set_instr(jtag_info, addr); + if (res) + return res; + + res = mpc5xxx_jtag_read_data(jtag_info, value, size); + if (res) + return res; + + return ERROR_OK; +} + +int mpc5xxx_jtagc_write(struct mpc5xxx_jtag *jtag_info, + uint32_t addr, uint32_t value, uint32_t size) +{ + int res; + + res = mpc5xxx_jtag_access_jtagc(jtag_info); + if (res) + return res; + + res = mpc5xxx_jtag_set_instr(jtag_info, addr); + if (res) + return res; + + res = mpc5xxx_jtag_write_data(jtag_info, value, size); + if (res) + return res; + + return ERROR_OK; +} + +int mpc5xxx_once_read(struct mpc5xxx_jtag *jtag_info, + uint32_t addr, uint32_t *value, uint32_t size) +{ + int res; + + res = mpc5xxx_jtag_access_once(jtag_info); + if (res) + return res; + + res = mpc5xxx_jtag_set_instr(jtag_info, MPC5XXX_ONCE_READ | addr); + if (res) + return res; + + res = mpc5xxx_jtag_read_data(jtag_info, value, size); + if (res) + return res; + + return ERROR_OK; +} + +int mpc5xxx_once_write(struct mpc5xxx_jtag *jtag_info, + uint32_t addr, uint32_t value, uint32_t size) +{ + int res; + + res = mpc5xxx_jtag_access_once(jtag_info); + if (res) + return res; + + res = mpc5xxx_jtag_set_instr(jtag_info, addr); + if (res) + return res; + + res = mpc5xxx_jtag_write_data(jtag_info, value, size); + if (res) + return res; + + return ERROR_OK; +} + +int mpc5xxx_once_osr_read(struct mpc5xxx_jtag *jtag_info, uint32_t *in) +{ +#define OSR_SIZE 10 + struct scan_field field; + uint8_t data_buf[4]; + uint8_t busy_buf[4]; + uint8_t in_buf[4]; + int busy, res; + + res = mpc5xxx_jtag_access_once(jtag_info); + if (res) + return res; + + do { + memset(data_buf, 0, sizeof(data_buf)); + memset(busy_buf, 0, sizeof(busy_buf)); + memset(in_buf, 0, sizeof(in_buf)); + + buf_set_u32(data_buf, 0, OSR_SIZE, MPC5XXX_ONCE_READ | MPC5XXX_ONCE_NOREG); + field.num_bits = OSR_SIZE; + field.in_value = in_buf; + field.out_value = data_buf; + + jtag_add_ir_scan(jtag_info->tap, &field, TAP_IDLE); + + if (jtag_execute_queue() != ERROR_OK) { + LOG_ERROR("%s: reading data failed", __func__); + return ERROR_FAIL; + } + + busy = buf_get_u32(busy_buf, 0, 0); + } while (busy); + + *in = buf_get_u32(in_buf, 0, OSR_SIZE); + + return ERROR_OK; +} + +int mpc5xxx_once_check_edm(struct mpc5xxx_jtag *jtag_info) +{ + int retval; + uint32_t val; + + retval = mpc5xxx_once_read(jtag_info, MPC5XXX_ONCE_DBCR0, &val, 32); + if (retval != ERROR_OK) + return retval; + printf("Value returned from DBCR0 was 0x%x\n", val); + if ((val & MPC5XXX_ONCE_DBCR0_EDM) == 0) { + printf("EDM bit not set, try to set it\n"); + + retval = mpc5xxx_once_write(jtag_info, MPC5XXX_ONCE_DBCR0, MPC5XXX_ONCE_DBCR0_EDM, 32); + if (retval != ERROR_OK) + return retval; + + /* See if it was actually set */ + retval = mpc5xxx_once_read(jtag_info, MPC5XXX_ONCE_DBCR0, &val, 32); + if (retval != ERROR_OK) + return retval; + + if ((val & MPC5XXX_ONCE_DBCR0_EDM) == 0) { + printf("Seems we are unable to set the EDM bit. Arse!\n"); + exit(1); + } else { + printf("IS OK NOW!\n"); + } + } + return ERROR_OK; +} + +#define CPUSCR_SIZE 192 +/* reads 6 * 32bits from CPUSCR */ +int mpc5xxx_once_cpuscr_read(struct mpc5xxx_jtag *jtag_info, struct mpc5xxx_cpuscr *cpuscr) +{ + struct scan_field field; + uint8_t data_buf[24]; + uint8_t busy_buf[24]; + uint8_t in_buf[24]; + int busy, res; + + res = mpc5xxx_jtag_access_once(jtag_info); + if (res) + return res; + + res = mpc5xxx_jtag_set_instr(jtag_info, MPC5XXX_ONCE_READ | MPC5XXX_ONCE_CPUSCR); + if (res) + return res; + + do { + memset(data_buf, 0, sizeof(data_buf)); + memset(busy_buf, 0, sizeof(busy_buf)); + memset(in_buf, 0, sizeof(in_buf)); + + field.num_bits = CPUSCR_SIZE; + field.in_value = in_buf; + field.out_value = NULL; + + jtag_add_dr_scan(jtag_info->tap, 1, &field, TAP_IDLE); + + if (jtag_execute_queue() != ERROR_OK) { + LOG_ERROR("%s: reading data failed", __func__); + return ERROR_FAIL; + } + + busy = buf_get_u32(busy_buf, 0, 0); + } while (busy); + + cpuscr->wbbrl = buf_get_u32(in_buf, 0, 32); + cpuscr->wbbrh = buf_get_u32(in_buf, 32, 32); + cpuscr->msr = buf_get_u32(in_buf, 64, 32); + cpuscr->pc = buf_get_u32(in_buf, 96, 32); + cpuscr->ir = buf_get_u32(in_buf, 128, 32); + cpuscr->ctl = buf_get_u32(in_buf, 160, 32); + /* printf("CPU MSR=0x%08x\n", cpuscr->msr); */ + + return ERROR_OK; +} + +/* writes 6 * 32bits to CPUSCR */ +int mpc5xxx_once_cpuscr_write(struct mpc5xxx_jtag *jtag_info, struct mpc5xxx_cpuscr *cpuscr) +{ + struct scan_field field; + uint8_t data_buf[24]; + uint8_t busy_buf[24]; + int busy, res; + + res = mpc5xxx_jtag_access_once(jtag_info); + if (res) + return res; + + res = mpc5xxx_jtag_set_instr(jtag_info, MPC5XXX_ONCE_CPUSCR); + if (res) + return res; + + do { + memset(data_buf, 0, sizeof(data_buf)); + memset(busy_buf, 0, sizeof(busy_buf)); + memcpy(data_buf, cpuscr, CPUSCR_SIZE / 8); + + field.num_bits = CPUSCR_SIZE; + field.in_value = NULL; + field.out_value = data_buf; + + jtag_add_dr_scan(jtag_info->tap, 1, &field, TAP_IDLE); + + if (jtag_execute_queue() != ERROR_OK) { + LOG_ERROR("%s: reading data failed", __func__); + return ERROR_FAIL; + } + + busy = buf_get_u32(busy_buf, 0, 0); + } while (busy); + + return ERROR_OK; +} + +int mpc5xxx_once_nexus_read(struct mpc5xxx_jtag *jtag_info, + uint32_t addr, uint32_t *value, uint32_t size) +{ + int res; + uint32_t val, count; + + res = mpc5xxx_jtag_access_once(jtag_info); + if (res) + return res; + + /* Tell ONCE to access NEXUS. + * Note: The code already checks if this is the current instruction, so + * this won't waste JTAG clocks. + */ + res = mpc5xxx_jtag_set_instr(jtag_info, MPC5XXX_ONCE_NEXUS); + if (res) + return res; + + /* Set up RWA with the desired address + * Next is write */ + mpc5xxx_jtag_write_data(jtag_info, MPC5XXX_ONCE_NEXUS_RWA | MPC5XXX_ONCE_NEXUS_WRITE, 8); + mpc5xxx_jtag_write_data(jtag_info, addr, 32); + + /* Now programme the RWCS reg to initiate the read + * Next is write */ + mpc5xxx_jtag_write_data(jtag_info, MPC5XXX_ONCE_NEXUS_RWCS | MPC5XXX_ONCE_NEXUS_WRITE, 8); + if (size == 8) { + val = MPC5XXX_ONCE_NEXUS_RWCS_READ1_8; + } else if (size == 16) { + val = MPC5XXX_ONCE_NEXUS_RWCS_READ1_16; + } else { + val = MPC5XXX_ONCE_NEXUS_RWCS_READ1_32; + size = 32; + } + + mpc5xxx_jtag_write_data(jtag_info, val, 32); + + /* Now poll RWCS until the read completed */ + val = 0; + count = 0; + while (((val & MPC5XXX_ONCE_NEXUS_RWCS_MASK) == 0) && (count < READ_MAXLOOPS)) { + /* next is read */ + mpc5xxx_jtag_write_data(jtag_info, MPC5XXX_ONCE_NEXUS_RWCS, 8); + mpc5xxx_jtag_read_data(jtag_info, &val, 32); + count++; + } + if (((val & MPC5XXX_ONCE_NEXUS_RWCS_MASK) != MPC5XXX_ONCE_NEXUS_RWCS_READOK) + || (count >= READ_MAXLOOPS)) { + LOG_ERROR("Failed to read memory!"); + return ERROR_FAIL; + } + + /* Now read the actual data + * next is read */ + mpc5xxx_jtag_write_data(jtag_info, MPC5XXX_ONCE_NEXUS_RWD, 8); + + mpc5xxx_jtag_read_data(jtag_info, &val, size); + + /* Byte swap for endianism target is BE, but Nexus reads are + * supposed to be LE. Appears that something is converting + * in the middle? + * How do we know that host is LE ? + */ + if (size == 8) { + *value = val; + } else if (size == 16) { + *value = ((val & 0x00ff) << 8) | ((val & 0xff00) >> 8); + } else { + *value = ((val & 0x000000ff) << 24) + | ((val & 0x0000ff00) << 8) + | ((val & 0x00ff0000) >> 8) + | ((val & 0xff000000) >> 24); + } + return ERROR_OK; +} + +int mpc5xxx_once_nexus_write(struct mpc5xxx_jtag *jtag_info, + uint32_t addr, uint32_t value, uint32_t size) +{ + int res; + uint32_t val, count; + + /* Byte swap for endianism target is BE, but Nexus reads are + * supposed to be LE. Appears that something is converting + * in the middle? + * How do we know that host is LE ? + */ + if (size == 8) { + /* no change */ + } else if (size == 16) { + value = ((value & 0x00ff) << 8) | ((value & 0xff00) >> 8); + } else { + value = ((value & 0x000000ff) << 24) + | ((value & 0x0000ff00) << 8) + | ((value & 0x00ff0000) >> 8) + | ((value & 0xff000000) >> 24); + } + + res = mpc5xxx_jtag_access_once(jtag_info); + if (res) + return res; + + /* Tell ONCE to access NEXUS. */ + res = mpc5xxx_jtag_set_instr(jtag_info, MPC5XXX_ONCE_NEXUS); + if (res) + return res; + + /* Set up RWA with the desired address + * Next is write */ + res = mpc5xxx_jtag_write_data(jtag_info, MPC5XXX_ONCE_NEXUS_RWA | MPC5XXX_ONCE_NEXUS_WRITE, 8); + if (res) + return res; + res = mpc5xxx_jtag_write_data(jtag_info, addr, 32); + if (res) + return res; + + /* Now programme the RWCS reg to prepare the write + * Next is write */ + res = mpc5xxx_jtag_write_data(jtag_info, MPC5XXX_ONCE_NEXUS_RWCS | MPC5XXX_ONCE_NEXUS_WRITE, 8); + if (res) + return res; + if (size == 8) { + val = MPC5XXX_ONCE_NEXUS_RWCS_WRITE1_8; + } else if (size == 16) { + val = MPC5XXX_ONCE_NEXUS_RWCS_WRITE1_16; + } else { + val = MPC5XXX_ONCE_NEXUS_RWCS_WRITE1_32; + size = 32; + } + + res = mpc5xxx_jtag_write_data(jtag_info, val, 32); + if (res) + return res; + + /* Now programme the RWD reg to initiate the write + * Next is write */ + res = mpc5xxx_jtag_write_data(jtag_info, MPC5XXX_ONCE_NEXUS_RWD | MPC5XXX_ONCE_NEXUS_WRITE, 8); + if (res) + return res; + res = mpc5xxx_jtag_write_data(jtag_info, value, size); + if (res) + return res; + + /* Now poll RWCS until the read completed */ + val = 0; + count = 0; + while (((val & MPC5XXX_ONCE_NEXUS_RWCS_DVMASK) != 0) && (count < READ_MAXLOOPS)) { + /* next is read */ + res = mpc5xxx_jtag_write_data(jtag_info, MPC5XXX_ONCE_NEXUS_RWCS, 8); + if (res) + return res; + res = mpc5xxx_jtag_read_data(jtag_info, &val, 32); + if (res) + return res; + } + if (((val & MPC5XXX_ONCE_NEXUS_RWCS_MASK) != MPC5XXX_ONCE_NEXUS_RWCS_WRITEOK) + || (count >= READ_MAXLOOPS)) { + LOG_ERROR("Failed to read!"); + return ERROR_FAIL; + } + + return ERROR_OK; +} diff --git a/src/target/mpc5xxx_jtag.h b/src/target/mpc5xxx_jtag.h new file mode 100644 index 0000000..c0e9731 --- /dev/null +++ b/src/target/mpc5xxx_jtag.h @@ -0,0 +1,106 @@ +/*************************************************************************** + * Copyright (C) 2017 by James Murray <[email protected] * + * Based on code: * + * Copyright (C) 2010 by Oleksandr Tymoshenko <[email protected]> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifndef MPC5XXX_JTAG +#define MPC5XXX_JTAG + +#define MPC5XXX_INST_IDCODE 0x01 +#define MPC5XXX_TAP_JTAG 0x01 /* Not TAP number, but used to identify JTAG */ +#define MPC5XXX_TAP_INVALID -1 + +#define MPC5XXX_ONCE_NEXUS_RWCS (0x07 << 1) /* 32bit control reg */ +#define MPC5XXX_ONCE_NEXUS_RWA (0x09 << 1) /* 32bit address reg */ +#define MPC5XXX_ONCE_NEXUS_RWD (0x0a << 1) /* 32bit data reg */ +#define MPC5XXX_ONCE_NEXUS_WRITE 1 /* lsb determines read=0 or write=1 */ +#define MPC5XXX_ONCE_NEXUS_RWCS_READ1_32 0x90000000 /* single 32bit read */ +#define MPC5XXX_ONCE_NEXUS_RWCS_READ1_16 0x88000000 /* single 16bit read */ +#define MPC5XXX_ONCE_NEXUS_RWCS_READ1_8 0x80000000 /* single 8bit read */ +#define MPC5XXX_ONCE_NEXUS_RWCS_WRITE1_32 0xd0000000 /* single 32bit write */ +#define MPC5XXX_ONCE_NEXUS_RWCS_WRITE1_16 0xc8000000 /* single 16bit write */ +#define MPC5XXX_ONCE_NEXUS_RWCS_WRITE1_8 0xc0000000 /* single 8bit write */ +#define MPC5XXX_ONCE_NEXUS_RWCS_MASK 0x00000003 /* ERR, DV mask */ +#define MPC5XXX_ONCE_NEXUS_RWCS_DVMASK 0x00000001 /* DV mask */ +#define MPC5XXX_ONCE_NEXUS_RWCS_READOK 0x00000001 +#define MPC5XXX_ONCE_NEXUS_RWCS_WRITEOK 0x00000000 +#define MPC5XXX_OCR_DEBUG1 0x05 +#define MPC5XXX_OCR_DEBUG2 0x06 +#define MPC5XXX_OCR_DEBUG_OFF 0x04 /* Still leave WKUP bit set */ +#define MPC5XXX_OCR_FDB 0x02 /* Allow SW BPs */ + +/* Some ONCE registers are the same */ +#define MPC5XXX_ONCE_DID 0b0000010 +#define MPC5XXX_ONCE_CPUSCR 0b0010000 +#define MPC5XXX_ONCE_NOREG 0b0010001 +#define MPC5XXX_ONCE_OCR 0b0010010 +#define MPC5XXX_ONCE_DBCR0 0b0110001 +#define MPC5XXX_ONCE_NEXUS 0b1111100 /* access Nexus registers via OnCE, 56xx and 57xx */ + +#define MPC5XXX_ONCE_DBCR0_EDM 0x80000000 /* EDM bit */ + +#define MPC5XXX_ONCE_EX 0b0010000000 /* EX mask. EXit debug */ +#define MPC5XXX_ONCE_GO 0b0100000000 /* GO mask. Execute command */ +#define MPC5XXX_ONCE_READ 0b1000000000 /* READ mask. */ + +#define MPC5XXX_OSR_HALT 0x20 +#define MPC5XXX_OSR_DEBUG 0x08 +#define MPC5XXX_OSR_HALT_DEBUG 0x28 +#define MPC5XXX_OSR_ERR 0x100 + +#define MPC5XXX_MSR_EE 0x8000 +#define MPC5XXX_MSR_CE 0x20000 + +#define MPC5XXX_CPUSCR_CTL_FFRA 0x00000400 +#define MPC5XXX_CPUSCR_CTL_PCOFST4 0x00001000 + +struct mpc5xxx_jtag { + struct jtag_tap *tap; + uint32_t dpc; /* Debug PC value */ + int once; /* Which Once we are talking to */ + int current_tap; /* Which Jtag tap we are talking to */ + int jtag_irlen; /* irlen used for Jtag TAP. Ignores command line option. */ +}; + +struct mpc5xxx_cpuscr { + uint32_t wbbrl, wbbrh, msr, pc, ir, ctl; +}; +int mpc5xxx_jtag_set_instr(struct mpc5xxx_jtag *jtag_info, int new_instr); +int mpc5xxx_jtag_read_data(struct mpc5xxx_jtag *jtag_info, + uint32_t *pdata, uint32_t size); +int mpc5xxx_jtag_write_data(struct mpc5xxx_jtag *jtag_info, + uint32_t data, uint32_t size); +int mpc5xxx_jtag_access_jtagc(struct mpc5xxx_jtag *jtag_info); +int mpc5xxx_jtag_access_once(struct mpc5xxx_jtag *jtag_info); +int mpc5xxx_jtagc_read(struct mpc5xxx_jtag *jtag_info, + uint32_t addr, uint32_t *value, uint32_t size); +int mpc5xxx_jtagc_write(struct mpc5xxx_jtag *jtag_info, + uint32_t addr, uint32_t value, uint32_t size); +int mpc5xxx_once_read(struct mpc5xxx_jtag *jtag_info, + uint32_t addr, uint32_t *value, uint32_t size); +int mpc5xxx_once_write(struct mpc5xxx_jtag *jtag_info, + uint32_t addr, uint32_t value, uint32_t size); +int mpc5xxx_once_nexus_read(struct mpc5xxx_jtag *jtag_info, + uint32_t addr, uint32_t *value, uint32_t size); +int mpc5xxx_once_nexus_write(struct mpc5xxx_jtag *jtag_info, + uint32_t addr, uint32_t value, uint32_t size); +int mpc5xxx_once_osr_read(struct mpc5xxx_jtag *jtag_info, uint32_t *in); +int mpc5xxx_once_cpuscr_read(struct mpc5xxx_jtag *jtag_info, struct mpc5xxx_cpuscr *in); +int mpc5xxx_once_cpuscr_write(struct mpc5xxx_jtag *jtag_info, struct mpc5xxx_cpuscr *in); + + +#endif /* MPC56XX_JTAG */ --
