initial push
This commit is contained in:
946
m68k/driver/bdm-cpu32.c
Normal file
946
m68k/driver/bdm-cpu32.c
Normal file
@@ -0,0 +1,946 @@
|
||||
/*
|
||||
* Motorola Background Debug Mode Driver
|
||||
* Copyright (C) 1995 W. Eric Norum
|
||||
* Copyright (C) 1998-2008 Chris Johns
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* W. Eric Norum
|
||||
* Saskatchewan Accelerator Laboratory
|
||||
* University of Saskatchewan
|
||||
* 107 North Road
|
||||
* Saskatoon, Saskatchewan, CANADA
|
||||
* S7N 5C6
|
||||
*
|
||||
* eric@skatter.usask.ca
|
||||
*
|
||||
* Coldfire support by:
|
||||
* Chris Johns
|
||||
* chris@contemporary.net.au
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* PD (Eric's) CPU32 Interface
|
||||
*
|
||||
* Parallel port bit assignments
|
||||
*
|
||||
* Status register (bits 0-2 not used):
|
||||
* +---+---+---+---+---+---+---+---+
|
||||
* | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||||
* +---+---+---+---+---+---+---+---+
|
||||
* | | | | |
|
||||
* | | | | +--- Target FREEZE line
|
||||
* | | | | 1 - Target is in background mode
|
||||
* | | | | 0 - Target is not background mode
|
||||
* | | | |
|
||||
* | | | +------- Not used
|
||||
* | | |
|
||||
* | | +----------- Serial data from target
|
||||
* | | 1 - `0' from target
|
||||
* | | 0 - `1' from target
|
||||
* | |
|
||||
* | +--------------- Target power
|
||||
* | 1 - Target power is ON
|
||||
* | 0 - Target power is OFF
|
||||
* |
|
||||
* +------------------- Target connected
|
||||
* 1 - Target is connected
|
||||
* 0 - Target is not connected
|
||||
*
|
||||
* Control register (bits 4-7 not used):
|
||||
* +---+---+---+---+
|
||||
* | 3 | 2 | 1 | 0 |
|
||||
* +---+---+---+---+
|
||||
* | | | |
|
||||
* | | | +--- Target BKPT* /DSCLK line
|
||||
* | | | Write 1 - Drive BKPT* /DSCLK line LOW
|
||||
* | | | Write 0 - Allow BKPT* /DSCLK line to go HIGH
|
||||
* | | | Allow flip-flop to control BKPT* /DSCLK line
|
||||
* | | |
|
||||
* | | +------- Target RESET* line
|
||||
* | | Write 1 - Force RESET* LOW
|
||||
* | | Write 0 - Allow monitoring of RESET*
|
||||
* | | Read 1 - RESET* is LOW
|
||||
* | | Read 0 - RESET* is HIGH
|
||||
* | |
|
||||
* | +----------- Serial data to target
|
||||
* | Write 0 - Send `0' to target
|
||||
* | Write 1 - Send `1' to target
|
||||
* |
|
||||
* +--------------- Control single-step flip-flop
|
||||
* Write 1 - Clear flip-flop
|
||||
* BKPT* /DSCLK is controlled by bit 0.
|
||||
* Write 0 - Allow flip-flop operation
|
||||
* Falling edge of IFETCH* /DSI clocks a `1'
|
||||
* into the flip-flop and drive BKPT* /DSCLK
|
||||
* LOW, causing a breakpoint.
|
||||
*/
|
||||
#define CPU32_PD_SR_CONNECTED (0x80)
|
||||
#define CPU32_PD_SR_POWERED (0x40)
|
||||
#define CPU32_PD_SR_DATA_BAR (0x20)
|
||||
#define CPU32_PD_SR_FROZEN (0x08)
|
||||
|
||||
#define CPU32_PD_CR_NOT_SINGLESTEP (0x08)
|
||||
#define CPU32_PD_CR_DATA (0x04)
|
||||
#define CPU32_PD_CR_FORCE_RESET (0x02)
|
||||
#define CPU32_PD_CR_RESET_STATUS (0x02)
|
||||
#define CPU32_PD_CR_CLOCKBAR_BKPT (0x01)
|
||||
|
||||
/*
|
||||
* ICD interface.
|
||||
*
|
||||
* Parallel port bit assignments
|
||||
*
|
||||
* Status register
|
||||
* +---+---+---+---+---+---+---+---+
|
||||
* | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||||
* +---+---+---+---+---+---+---+---+
|
||||
* | | | | |
|
||||
* | | | | +--- Not used
|
||||
* | | | +------- Not used
|
||||
* | | +----------- Not used
|
||||
* | |
|
||||
* | +--------------- Target FREEZE line
|
||||
* | 1 - Target is in background mode
|
||||
* | 0 - Target is not background mode
|
||||
* |
|
||||
* +------------------- Serial data from target
|
||||
* 1 - `0' from target
|
||||
* 0 - `1' from target
|
||||
*
|
||||
* Data register
|
||||
* +---+---+---+---+---+---+---+---+
|
||||
* | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||||
* +---+---+---+---+---+---+---+---+
|
||||
* | | | | | | | |
|
||||
* | | | | | | | +--- Serial data to target
|
||||
* | | | | | | | Write 1: Send 1 to target
|
||||
* | | | | | | | Write 0: Send 0 to target
|
||||
* | | | | | | | Signal gets to target, if OE is 1
|
||||
* | | | | | | | and target is in FREEZE mode
|
||||
* | | | | | | |
|
||||
* | | | | | | +------- Clock
|
||||
* | | | | | | if target in freeze mode, then:
|
||||
* | | | | | | Write 1: drive BKPT* /DSCLK 1
|
||||
* | | | | | | Write 0: drive BKPT* /DSCLK 0
|
||||
* | | | | | |
|
||||
* | | | | | +----------- BREAK
|
||||
* | | | | | if target not in freeze mode, then:
|
||||
* | | | | | Write 0: drive BKPT* /DSCLK 0
|
||||
* | | | | | line determines single stepping
|
||||
* | | | | | on leaving BGND mode:
|
||||
* | | | | | Write 0: do single step
|
||||
* | | | | | Write 1: continue normally
|
||||
* | | | | |
|
||||
* | | | | +--------------- RESET
|
||||
* | | | | Write 0: pull reset low
|
||||
* | | | | Write 1: release reset line
|
||||
* | | | |
|
||||
* | | | +--- OE
|
||||
* | | | Write 0 - DSI is tristated
|
||||
* | | | Write 1 - DSI pin is forced to level of serial data
|
||||
* | | |
|
||||
* | | +------- LED
|
||||
* | | Write 1 - turn on LED
|
||||
* | | Write 0 - turn off LED
|
||||
* | |
|
||||
* | +----------- ERROR
|
||||
* | Write 0 - BERR output is tristated
|
||||
* | Write 1 - BERR is pulled low
|
||||
* |
|
||||
* +--------------- spare
|
||||
*/
|
||||
|
||||
#define CPU32_ICD_DSI (1 << 0) /* data shift input Host->MCU */
|
||||
#define CPU32_ICD_DSCLK (1 << 1) /* data shift clock / breakpoint pin */
|
||||
#define CPU32_ICD_STEP_OUT (1 << 2) /* set low to force breakpoint */
|
||||
#define CPU32_ICD_RST_OUT (1 << 3) /* set low to force reset on MCU */
|
||||
#define CPU32_ICD_OE (1 << 4) /* set to a 1 to enable DSI */
|
||||
#define CPU32_ICD_FORCE_BERR (1 << 6) /* set to a 1 to force BERR on target */
|
||||
#define CPU32_ICD_FREEZE (1 << 6) /* */
|
||||
#define CPU32_ICD_DSO (1 << 7) /* */
|
||||
|
||||
/*
|
||||
************************************************************************
|
||||
* CPU32 for PD/ICD interface support routines *
|
||||
************************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
* CPU32 system register mapping. See bdm.h for the user values.
|
||||
*/
|
||||
|
||||
static int cpu32_sysreg_map[BDM_REG_VBR + 1] =
|
||||
{ 0x0, /* BDM_REG_RPC */
|
||||
0x1, /* BDM_REG_PCC */
|
||||
0xb, /* BDM_REG_SR */
|
||||
0xc, /* BDM_REG_USP */
|
||||
0xd, /* BDM_REG_SSP */
|
||||
0xe, /* BDM_REG_SFC */
|
||||
0xf, /* BDM_REG_DFC */
|
||||
0x8, /* BDM_REG_ATEMP */
|
||||
0x9, /* BDM_REG_FAR */
|
||||
0xa /* BDM_REG_VBR */
|
||||
};
|
||||
|
||||
/* need by cpu32_read_sysreg() */
|
||||
static int cpu32_write_sysreg (struct BDM *self, struct BDMioctl *ioc, int mode);
|
||||
static int cpu32_icd_stop_chip (struct BDM *self);
|
||||
|
||||
/*
|
||||
* Clock a word to/from the target
|
||||
*/
|
||||
|
||||
static int
|
||||
cpu32_serial_clock (struct BDM *self, unsigned short wval, int holdback)
|
||||
{
|
||||
return (self->serial_clock) (self, wval, holdback);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get target status
|
||||
*/
|
||||
static int
|
||||
cpu32_pd_get_status (struct BDM *self)
|
||||
{
|
||||
unsigned char sr = inb (self->statusPort);
|
||||
int ret;
|
||||
|
||||
if (!(sr & CPU32_PD_SR_CONNECTED))
|
||||
ret = BDM_TARGETNC;
|
||||
else if (!(sr & CPU32_PD_SR_POWERED))
|
||||
ret = BDM_TARGETPOWER;
|
||||
else
|
||||
ret = (sr & CPU32_PD_SR_FROZEN ? BDM_TARGETSTOPPED : 0) |
|
||||
(inb (self->controlPort) & CPU32_PD_CR_RESET_STATUS ? BDM_TARGETRESET : 0);
|
||||
if (self->debugFlag > 1)
|
||||
PRINTF (" cpu32_pd_get_status -- Status Port:0x%02x Status:0x%04x\n",
|
||||
sr, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Hardware initialization
|
||||
*/
|
||||
static int
|
||||
cpu32_pd_init_hardware (struct BDM *self)
|
||||
{
|
||||
int status;
|
||||
|
||||
/*
|
||||
* Force breakpoint
|
||||
*/
|
||||
outb (CPU32_PD_CR_NOT_SINGLESTEP | CPU32_PD_CR_CLOCKBAR_BKPT, self->controlPort);
|
||||
udelay (100);
|
||||
outb (CPU32_PD_CR_FORCE_RESET | CPU32_PD_CR_CLOCKBAR_BKPT, self->controlPort);
|
||||
bdm_sleep (HZ / 100);
|
||||
outb (CPU32_PD_CR_CLOCKBAR_BKPT, self->controlPort);
|
||||
udelay (10);
|
||||
outb (CPU32_PD_CR_NOT_SINGLESTEP | CPU32_PD_CR_CLOCKBAR_BKPT, self->controlPort);
|
||||
udelay (100);
|
||||
status = cpu32_pd_get_status (self);
|
||||
if (self->debugFlag)
|
||||
PRINTF (" cpu32_pd_init_hardware: status:0x%02x control port:0x%02x\n",
|
||||
status, inb (self->controlPort));
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clock a word to/from the target
|
||||
*/
|
||||
static int
|
||||
cpu32_pd_serial_clock (struct BDM *self, unsigned short wval, int holdback)
|
||||
{
|
||||
unsigned long shiftRegister;
|
||||
unsigned char dataBit;
|
||||
unsigned int counter;
|
||||
unsigned int status = cpu32_pd_get_status (self);
|
||||
|
||||
if (status & BDM_TARGETRESET)
|
||||
return BDM_FAULT_RESET;
|
||||
if (status & BDM_TARGETNC)
|
||||
return BDM_FAULT_CABLE;
|
||||
if (status & BDM_TARGETPOWER)
|
||||
return BDM_FAULT_POWER;
|
||||
shiftRegister = wval;
|
||||
counter = 17 - holdback;
|
||||
while (counter--) {
|
||||
dataBit = ((shiftRegister & 0x10000) ? CPU32_PD_CR_DATA : 0);
|
||||
shiftRegister <<= 1;
|
||||
outb (dataBit | CPU32_PD_CR_NOT_SINGLESTEP | CPU32_PD_CR_CLOCKBAR_BKPT,
|
||||
self->controlPort);
|
||||
bdm_delay (self->delayTimer + 1);
|
||||
if ((inb (self->statusPort) & CPU32_PD_SR_DATA_BAR) == 0)
|
||||
shiftRegister |= 1;
|
||||
outb (dataBit | CPU32_PD_CR_NOT_SINGLESTEP, self->controlPort);
|
||||
bdm_delay ((self->delayTimer >> 1) + 1);
|
||||
}
|
||||
self->readValue = shiftRegister & 0x1FFFF;
|
||||
if (self->debugFlag)
|
||||
PRINTF (" cpu32_pd_serial_clock -- send 0x%05x receive 0x%05x\n",
|
||||
wval, self->readValue);
|
||||
if (self->readValue & 0x10000) {
|
||||
if (self->readValue == 0x10001)
|
||||
return BDM_FAULT_BERR;
|
||||
else if (self->readValue != 0x10000)
|
||||
return BDM_FAULT_NVC;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Restart chip and stop on first instruction fetch
|
||||
*/
|
||||
static int
|
||||
cpu32_pd_restart_chip (struct BDM *self)
|
||||
{
|
||||
int check;
|
||||
|
||||
if (self->debugFlag)
|
||||
PRINTF (" cpu32_pd_restart_chip\n");
|
||||
outb (CPU32_PD_CR_FORCE_RESET | CPU32_PD_CR_CLOCKBAR_BKPT, self->controlPort);
|
||||
udelay (10);
|
||||
outb (CPU32_PD_CR_CLOCKBAR_BKPT, self->controlPort);
|
||||
udelay (10);
|
||||
outb (CPU32_PD_CR_NOT_SINGLESTEP | CPU32_PD_CR_CLOCKBAR_BKPT, self->controlPort);
|
||||
for (check = 0 ; check < 1000 ; check++) {
|
||||
if (inb (self->statusPort) & CPU32_PD_SR_FROZEN)
|
||||
return 0;
|
||||
}
|
||||
return BDM_FAULT_RESPONSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Restart chip and disable background debugging mode
|
||||
*/
|
||||
static int
|
||||
cpu32_pd_release_chip (struct BDM *self)
|
||||
{
|
||||
if (self->debugFlag)
|
||||
PRINTF (" cpu32_pd_release_chip\n");
|
||||
outb (CPU32_PD_CR_NOT_SINGLESTEP | CPU32_PD_CR_FORCE_RESET, self->controlPort);
|
||||
udelay (10);
|
||||
outb (CPU32_PD_CR_NOT_SINGLESTEP, self->controlPort);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Restart chip, enable background debugging mode, halt on first fetch
|
||||
*
|
||||
* The software from the Motorola BBS tries to have the target
|
||||
* chip begin execution, but that doesn't work very reliably.
|
||||
* The RESETH* line rises rather slowly, so sometimes the BKPT* / DSCLK
|
||||
* would be seen low, and sometimes it wouldn't.
|
||||
*/
|
||||
static int
|
||||
cpu32_pd_reset_chip (struct BDM *self)
|
||||
{
|
||||
if (self->debugFlag)
|
||||
PRINTF (" cpu32_pd_reset_chip\n");
|
||||
outb (CPU32_PD_CR_CLOCKBAR_BKPT | CPU32_PD_CR_FORCE_RESET,
|
||||
self->controlPort);
|
||||
udelay (10);
|
||||
outb (CPU32_PD_CR_CLOCKBAR_BKPT, self->controlPort);
|
||||
udelay (10);
|
||||
outb (CPU32_PD_CR_CLOCKBAR_BKPT | CPU32_PD_CR_NOT_SINGLESTEP,
|
||||
self->controlPort);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Force the target into background debugging mode
|
||||
*/
|
||||
static int
|
||||
cpu32_pd_stop_chip (struct BDM *self)
|
||||
{
|
||||
int check;
|
||||
|
||||
if (self->debugFlag)
|
||||
PRINTF (" cpu32_pd_stop_chip\n");
|
||||
if (inb (self->statusPort) & CPU32_PD_SR_FROZEN)
|
||||
return 0;
|
||||
outb (CPU32_PD_CR_NOT_SINGLESTEP | CPU32_PD_CR_CLOCKBAR_BKPT,
|
||||
self->controlPort);
|
||||
for (check = 0 ; check < 1000 ; check++) {
|
||||
if (inb (self->statusPort) & CPU32_PD_SR_FROZEN)
|
||||
return 0;
|
||||
}
|
||||
return BDM_FAULT_RESPONSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make the target execute a single instruction and
|
||||
* reenter background debugging mode
|
||||
*/
|
||||
static int
|
||||
cpu32_pd_step_chip (struct BDM *self)
|
||||
{
|
||||
int check;
|
||||
unsigned char dataBit;
|
||||
int err;
|
||||
|
||||
if (self->debugFlag)
|
||||
PRINTF (" cpu32_pd_step_chip\n");
|
||||
err = cpu32_serial_clock (self, BDM_GO_CMD, 1);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/*
|
||||
* Send the last bit of the command
|
||||
*/
|
||||
dataBit = (BDM_GO_CMD & 0x1) ? CPU32_PD_CR_DATA : 0;
|
||||
outb (dataBit | CPU32_PD_CR_NOT_SINGLESTEP | CPU32_PD_CR_CLOCKBAR_BKPT,
|
||||
self->controlPort);
|
||||
bdm_delay (self->delayTimer + 1);
|
||||
|
||||
/*
|
||||
* Enable single-step
|
||||
*/
|
||||
outb (dataBit | CPU32_PD_CR_CLOCKBAR_BKPT, self->controlPort);
|
||||
bdm_delay (1);
|
||||
outb (dataBit, self->controlPort);
|
||||
|
||||
/*
|
||||
* Wait for step to complete
|
||||
* The software from the Motorola BBS doesn't do this, but
|
||||
* omitting the `outb' operation leaves a race condition the
|
||||
* next time cpu32_serial_clock is called.
|
||||
*
|
||||
* The first output operation in bdmSerialClock sends
|
||||
* `dataBit | CPU32_CR_NOT_SINGLESTEP | CPU32_CR_CLOCKBAR_BKPT' to the
|
||||
* control port. If the flip flop in the external circuit
|
||||
* clears before the `CPU32_CR_CLOCKBAR_BKPT' pin of the '132 goes
|
||||
* low, there is a narrow glitch on the BKPT* / DSCLK pin, which
|
||||
* clocks a garbage bit into the target chip.
|
||||
*/
|
||||
for (check = 0 ; check < 1000 ; check++) {
|
||||
if (inb (self->statusPort) & CPU32_PD_SR_FROZEN) {
|
||||
outb (CPU32_PD_CR_CLOCKBAR_BKPT, self->controlPort);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return BDM_FAULT_RESPONSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get target status
|
||||
*/
|
||||
static int
|
||||
cpu32_icd_get_status (struct BDM *self)
|
||||
{
|
||||
unsigned char sr = inb (self->statusPort);
|
||||
int ret;
|
||||
|
||||
ret = sr & CPU32_ICD_FREEZE ? BDM_TARGETSTOPPED : 0;
|
||||
if (self->debugFlag > 1)
|
||||
PRINTF (" cpu32_icd_get_status -- Status Port:0x%02x Status:0x%04x\n",
|
||||
sr, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Hardware initialization
|
||||
*/
|
||||
static int
|
||||
cpu32_icd_init_hardware (struct BDM *self)
|
||||
{
|
||||
int status;
|
||||
|
||||
/*
|
||||
* Force breakpoint
|
||||
*/
|
||||
outb (CPU32_ICD_STEP_OUT | CPU32_ICD_DSCLK | CPU32_ICD_RST_OUT, self->dataPort);
|
||||
udelay (10);
|
||||
status = cpu32_icd_get_status (self);
|
||||
if (self->debugFlag)
|
||||
PRINTF (" cpu32_icd_init_hardware: status:0x%02x, data port:0x%02x\n",
|
||||
status, inb (self->dataPort));
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clock a word to/from the target
|
||||
*/
|
||||
static int
|
||||
cpu32_icd_serial_clock (struct BDM *self, unsigned short wval, int holdback)
|
||||
{
|
||||
unsigned long shiftRegister;
|
||||
unsigned char dataBit;
|
||||
unsigned int counter;
|
||||
unsigned int status = cpu32_icd_get_status (self);
|
||||
|
||||
if (status & BDM_TARGETRESET)
|
||||
return BDM_FAULT_RESET;
|
||||
if (status & BDM_TARGETNC)
|
||||
return BDM_FAULT_CABLE;
|
||||
if (status & BDM_TARGETPOWER)
|
||||
return BDM_FAULT_POWER;
|
||||
if(!(status & BDM_TARGETSTOPPED)) {
|
||||
if (self->debugFlag)
|
||||
PRINTF (" cpu32_icd_serial_clock -- stop target first\n");
|
||||
if (cpu32_icd_stop_chip (self) == BDM_FAULT_RESPONSE) {
|
||||
if (self->debugFlag)
|
||||
PRINTF (" cpu32_icd_serial_clock -- can\'t stop it\n");
|
||||
return BDM_FAULT_RESPONSE;
|
||||
}
|
||||
}
|
||||
shiftRegister = wval;
|
||||
counter = 17 - holdback;
|
||||
while (counter--) {
|
||||
dataBit = ((shiftRegister & 0x10000) ? CPU32_ICD_DSI : 0);
|
||||
shiftRegister <<= 1;
|
||||
outb (dataBit | CPU32_ICD_RST_OUT | CPU32_ICD_OE | CPU32_ICD_STEP_OUT,
|
||||
self->dataPort);
|
||||
bdm_delay (self->delayTimer + 1);
|
||||
if ((inb (self->statusPort) & CPU32_ICD_DSO) == 0)
|
||||
shiftRegister |= 1;
|
||||
outb (dataBit | CPU32_ICD_RST_OUT | CPU32_ICD_OE | CPU32_ICD_STEP_OUT | CPU32_ICD_DSCLK,
|
||||
self->dataPort);
|
||||
bdm_delay ((self->delayTimer >> 1) + 1);
|
||||
}
|
||||
if (holdback == 0) {
|
||||
outb (CPU32_ICD_RST_OUT | CPU32_ICD_STEP_OUT | CPU32_ICD_DSCLK,
|
||||
self->dataPort);
|
||||
bdm_delay (self->delayTimer + 1);
|
||||
}
|
||||
outb (CPU32_ICD_RST_OUT | CPU32_ICD_STEP_OUT | CPU32_ICD_DSCLK,
|
||||
self->dataPort);
|
||||
self->readValue = shiftRegister & 0x1FFFF;
|
||||
if (self->debugFlag)
|
||||
PRINTF (" cpu32_icd_serial_clock -- send 0x%05x, receive 0x%05x\n",
|
||||
wval, self->readValue);
|
||||
if (self->readValue & 0x10000) {
|
||||
if (self->readValue == 0x10001)
|
||||
return BDM_FAULT_BERR;
|
||||
else if (self->readValue != 0x10000)
|
||||
return BDM_FAULT_NVC;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Force the target into background debugging mode
|
||||
*/
|
||||
static int
|
||||
cpu32_icd_stop_chip (struct BDM *self)
|
||||
{
|
||||
int check;
|
||||
int pass;
|
||||
|
||||
if (self->debugFlag)
|
||||
PRINTF (" cpu32_icd_stop_chip: ");
|
||||
/* if FREEZE is already high, we're stopped and we're done here */
|
||||
if (inb (self->statusPort) & CPU32_ICD_FREEZE) {
|
||||
if (self->debugFlag)
|
||||
PRINTF ("already stopped\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* try multiple times... */
|
||||
for (pass = 0; pass < 14; pass++) {
|
||||
|
||||
/* even times, simply assert DSCLK and RESET */
|
||||
if (pass%2 == 0) {
|
||||
outb (CPU32_ICD_DSCLK | CPU32_ICD_RST_OUT, self->dataPort);
|
||||
}
|
||||
/* odd times, yank BERR as well, in case the target is wedged */
|
||||
else {
|
||||
outb (CPU32_ICD_DSCLK | CPU32_ICD_RST_OUT | CPU32_ICD_FORCE_BERR,
|
||||
self->dataPort);
|
||||
}
|
||||
|
||||
/* now hang around and wait for the freeze line to come up
|
||||
* XXX we're depending on a nop loop for timing? arrrgh!
|
||||
*/
|
||||
for (check = 0 ; check < (1000 + ((pass+1)%2) * 9000) ; check++) {
|
||||
if (inb (self->statusPort) & CPU32_ICD_FREEZE) {
|
||||
/* if freeze line is high we're OK
|
||||
* XXX let reset go too?
|
||||
*/
|
||||
if (self->debugFlag)
|
||||
PRINTF("stopped after %d bdm_delays\n", check);
|
||||
outb (CPU32_ICD_RST_OUT, self->dataPort);
|
||||
return 0;
|
||||
}
|
||||
bdm_delay (10);
|
||||
}
|
||||
|
||||
}
|
||||
/* we've failed... */
|
||||
outb (CPU32_ICD_RST_OUT, self->dataPort);
|
||||
if (self->debugFlag)
|
||||
PRINTF("failed!\n");
|
||||
return BDM_FAULT_RESPONSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Restart chip and stop on first instruction fetch
|
||||
*/
|
||||
static int
|
||||
cpu32_icd_restart_chip (struct BDM *self)
|
||||
{
|
||||
if (self->debugFlag)
|
||||
PRINTF (" cpu32_icd_restart_chip\n");
|
||||
outb (CPU32_ICD_DSCLK, self->dataPort);
|
||||
udelay (1);
|
||||
return cpu32_icd_stop_chip (self);
|
||||
}
|
||||
|
||||
/*
|
||||
* Restart chip and disable background debugging mode
|
||||
*/
|
||||
static int
|
||||
cpu32_icd_release_chip (struct BDM *self)
|
||||
{
|
||||
if (self->debugFlag)
|
||||
PRINTF (" cpu32_icd_release_chip\n");
|
||||
outb (CPU32_ICD_DSCLK | CPU32_ICD_STEP_OUT, self->dataPort);
|
||||
udelay (10);
|
||||
outb (CPU32_ICD_DSCLK | CPU32_ICD_RST_OUT | CPU32_ICD_STEP_OUT, self->dataPort);
|
||||
udelay (10);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Restart chip, enable background debugging mode, halt on first fetch
|
||||
*
|
||||
* The software from the Motorola BBS tries to have the target
|
||||
* chip begin execution, but that doesn't work very reliably.
|
||||
* The RESETH* line rises rather slowly, so sometimes the BKPT* / DSCLK
|
||||
* would be seen low, and sometimes it wouldn't.
|
||||
*/
|
||||
static int
|
||||
cpu32_icd_reset_chip (struct BDM *self)
|
||||
{
|
||||
if (self->debugFlag)
|
||||
PRINTF (" cpu32_icd_reset_chip\n");
|
||||
|
||||
/*
|
||||
* Assert RESET*, BKPT*, and BREAK*
|
||||
*/
|
||||
outb (0, self->dataPort);
|
||||
udelay (100);
|
||||
|
||||
/*
|
||||
* Deassert RESET (CPU must see BKPT* asserted at rising edge of RESET*)
|
||||
* Leaving BKPT* and BREAK* asserted gets us ready for first data txfer
|
||||
* as per Figure 7-8 in CPU32RM/AD
|
||||
*/
|
||||
outb (CPU32_ICD_RST_OUT, self->dataPort);
|
||||
udelay (100);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Make the target execute a single instruction and
|
||||
* reenter background debugging mode
|
||||
*/
|
||||
static int
|
||||
cpu32_icd_step_chip (struct BDM *self)
|
||||
{
|
||||
unsigned char dataBit;
|
||||
int err;
|
||||
|
||||
if (self->debugFlag)
|
||||
PRINTF (" cpu32_step_chip\n");
|
||||
err = cpu32_serial_clock (self, BDM_GO_CMD, 1);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/*
|
||||
* Send the last bit of the command
|
||||
*/
|
||||
dataBit = (BDM_GO_CMD & 0x1) ? CPU32_ICD_DSI : 0;
|
||||
outb (dataBit | CPU32_ICD_OE | CPU32_ICD_STEP_OUT | CPU32_ICD_RST_OUT,
|
||||
self->dataPort);
|
||||
bdm_delay (self->delayTimer + 1);
|
||||
outb (dataBit | CPU32_ICD_OE | CPU32_ICD_RST_OUT, self->dataPort);
|
||||
bdm_delay (1);
|
||||
/* Raise CPU32_ICD_DSCLK before dropping CPU32_ICD_OEA */
|
||||
outb (CPU32_ICD_DSCLK | CPU32_ICD_OE | CPU32_ICD_RST_OUT, self->dataPort);
|
||||
bdm_delay (1);
|
||||
outb (CPU32_ICD_DSCLK | CPU32_ICD_RST_OUT, self->dataPort);
|
||||
|
||||
return cpu32_icd_stop_chip (self);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read system register
|
||||
*/
|
||||
|
||||
static int
|
||||
cpu32_read_sysreg (struct BDM *self, struct BDMioctl *ioc, int mode)
|
||||
{
|
||||
int err, cmd;
|
||||
unsigned short msw, lsw;
|
||||
|
||||
/*
|
||||
* CPU32 MBAR require sfc support, make it look like
|
||||
* a register.
|
||||
*/
|
||||
if (ioc->address == BDM_REG_MBAR) {
|
||||
struct BDMioctl mbar_ioc;
|
||||
unsigned long sfc;
|
||||
|
||||
mbar_ioc.address = BDM_REG_SFC;
|
||||
if ((err = cpu32_read_sysreg (self, &mbar_ioc,
|
||||
BDM_SYS_REG_MODE_MAPPED)) < 0)
|
||||
return err;
|
||||
sfc = mbar_ioc.value;
|
||||
mbar_ioc.address = BDM_REG_SFC;
|
||||
mbar_ioc.value = 7;
|
||||
if ((err = cpu32_write_sysreg (self, &mbar_ioc,
|
||||
BDM_SYS_REG_MODE_MAPPED)) < 0)
|
||||
return err;
|
||||
mbar_ioc.address = 0x3FF00;
|
||||
if ((err = bdmDrvReadLongWord (self, &mbar_ioc)) < 0)
|
||||
return err;
|
||||
ioc->value = mbar_ioc.value;
|
||||
mbar_ioc.address = BDM_REG_SFC;
|
||||
mbar_ioc.value = sfc;
|
||||
if ((err = cpu32_write_sysreg (self, &mbar_ioc,
|
||||
BDM_SYS_REG_MODE_MAPPED)) < 0)
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ioc->address > BDM_REG_VBR)
|
||||
return BDM_FAULT_NVC;
|
||||
|
||||
if (mode != BDM_SYS_REG_MODE_MAPPED)
|
||||
cmd = ioc->address & 0xffff;
|
||||
else
|
||||
cmd = cpu32_sysreg_map[ioc->address];
|
||||
|
||||
if (cmd == -1) {
|
||||
ioc->value = 0;
|
||||
if (self->debugFlag)
|
||||
PRINTF (" cpu32_read_sysreg - Reg(%d):0x%x is not mapped; ignored\n",
|
||||
mode, ioc->address);
|
||||
return 0;
|
||||
}
|
||||
|
||||
cmd |= BDM_RSREG_CMD;
|
||||
|
||||
if (((err = cpu32_serial_clock (self, cmd, 0)) != 0) ||
|
||||
((err = bdmBitBashFetchWord (self, &msw)) != 0) ||
|
||||
((err = bdmBitBashFetchWord (self, &lsw)) != 0))
|
||||
return err;
|
||||
ioc->value = (msw << 16) | lsw;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write system register
|
||||
*/
|
||||
static int
|
||||
cpu32_write_sysreg (struct BDM *self, struct BDMioctl *ioc, int mode)
|
||||
{
|
||||
int err, cmd;
|
||||
|
||||
/*
|
||||
* CPU32 MBAR require dfc support, make it look like
|
||||
* a register.
|
||||
*/
|
||||
if (ioc->address == BDM_REG_MBAR) {
|
||||
struct BDMioctl mbar_ioc;
|
||||
unsigned long dfc;
|
||||
|
||||
mbar_ioc.address = BDM_REG_DFC;
|
||||
if ((err = cpu32_read_sysreg (self, &mbar_ioc,
|
||||
BDM_SYS_REG_MODE_MAPPED)) < 0)
|
||||
return err;
|
||||
dfc = mbar_ioc.value;
|
||||
mbar_ioc.address = BDM_REG_DFC;
|
||||
mbar_ioc.value = 7;
|
||||
if ((err = cpu32_write_sysreg (self, &mbar_ioc,
|
||||
BDM_SYS_REG_MODE_MAPPED)) < 0)
|
||||
return err;
|
||||
mbar_ioc.address = 0x3FF00;
|
||||
mbar_ioc.value = ioc->value;
|
||||
if ((err = bdmDrvWriteLongWord (self, &mbar_ioc)) < 0)
|
||||
return err;
|
||||
mbar_ioc.address = BDM_REG_DFC;
|
||||
mbar_ioc.value = dfc;
|
||||
if ((err = cpu32_write_sysreg (self, &mbar_ioc,
|
||||
BDM_SYS_REG_MODE_MAPPED)) < 0)
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ioc->address > BDM_REG_VBR)
|
||||
return BDM_FAULT_NVC;
|
||||
|
||||
if (mode != BDM_SYS_REG_MODE_MAPPED)
|
||||
cmd = ioc->address & 0xffff;
|
||||
else
|
||||
cmd = cpu32_sysreg_map[ioc->address];
|
||||
|
||||
cmd = BDM_WSREG_CMD;
|
||||
|
||||
if (((err = cpu32_serial_clock (self, cmd, 0)) != 0) ||
|
||||
((err = cpu32_serial_clock (self, ioc->value >> 16, 0)) != 0) ||
|
||||
((err = cpu32_serial_clock (self, ioc->value, 0)) != 0))
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate a bus error for the ICD interface
|
||||
*/
|
||||
|
||||
static int
|
||||
cpu32_icd_gen_bus_error (struct BDM *self)
|
||||
{
|
||||
if (self->debugFlag)
|
||||
PRINTF(" cpu32_icd_gen_bus_error\n");
|
||||
|
||||
outb (CPU32_ICD_FORCE_BERR | CPU32_ICD_RST_OUT, self->dataPort);
|
||||
udelay (400);
|
||||
outb (CPU32_ICD_RST_OUT, self->dataPort);
|
||||
|
||||
return BDM_FAULT_BERR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate a bus error as the access has failed. This is
|
||||
* not supported on the CPU32 with PD interface.
|
||||
* (the 7-chip PD interface generates it automatically in hardware
|
||||
*/
|
||||
static int
|
||||
cpu32_gen_bus_error (struct BDM *self)
|
||||
{
|
||||
if (self->debugFlag > 1)
|
||||
PRINTF(" cpu32_gen_bus_error\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Restart target execution
|
||||
*/
|
||||
static int
|
||||
cpu32_run_chip (struct BDM *self)
|
||||
{
|
||||
return cpu32_serial_clock (self, BDM_GO_CMD, 0);
|
||||
}
|
||||
|
||||
#ifdef BDM_BIT_BASH_PORT
|
||||
|
||||
/*
|
||||
* Bit Bash the BDM port. No status checks. I assume you know what is happening at
|
||||
* a low level with the BDM hardware if you are using this interface.
|
||||
*/
|
||||
static int
|
||||
cpu32_bit_bash (struct BDM *self, unsigned short mask, unsigned short bits)
|
||||
{
|
||||
unsigned char ctrl_port = 0;
|
||||
|
||||
if (self->debugFlag)
|
||||
PRINTF (" cpu32_bit_bash: mask=%04x, bits=%04x\n", mask, bits);
|
||||
|
||||
self->bit_bash_bits &= ~mask;
|
||||
self->bit_bash_bits |= bits;
|
||||
|
||||
if (self->bit_bash_bits & BDM_BB_RESET)
|
||||
ctrl_port |= CPU32_CR_FORCE_RESET;
|
||||
|
||||
if ((self->bit_bash_bits & BDM_BB_BKPT) == 0)
|
||||
ctrl_port |= CPU32_CR_CLOCKBAR_BKPT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Initialise the BDM structure for a CPU32
|
||||
*/
|
||||
static int
|
||||
cpu32_pd_init_self (struct BDM *self)
|
||||
{
|
||||
int reg;
|
||||
|
||||
self->processor = BDM_CPU32;
|
||||
self->interface = BDM_CPU32_ERIC;
|
||||
|
||||
self->get_status = cpu32_pd_get_status;
|
||||
self->init_hardware = cpu32_pd_init_hardware;
|
||||
self->serial_clock = cpu32_pd_serial_clock;
|
||||
self->gen_bus_error = cpu32_gen_bus_error;
|
||||
self->read_sysreg = cpu32_read_sysreg;
|
||||
self->write_sysreg = cpu32_write_sysreg;
|
||||
self->restart_chip = cpu32_pd_restart_chip;
|
||||
self->release_chip = cpu32_pd_release_chip;
|
||||
self->reset_chip = cpu32_pd_reset_chip;
|
||||
self->stop_chip = cpu32_pd_stop_chip;
|
||||
self->run_chip = cpu32_run_chip;
|
||||
self->step_chip = cpu32_pd_step_chip;
|
||||
|
||||
#ifdef BDM_BIT_BASH_PORT
|
||||
self->bit_bash = cpu32_bit_bash;
|
||||
self->bit_bash_bits = 0;
|
||||
#endif
|
||||
|
||||
for (reg = 0; reg < BDM_MAX_SYSREG; reg++)
|
||||
self->shadow_sysreg[reg] = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
cpu32_icd_init_self (struct BDM *self)
|
||||
{
|
||||
int reg;
|
||||
|
||||
self->processor = BDM_CPU32;
|
||||
self->interface = BDM_CPU32_ICD;
|
||||
|
||||
self->get_status = cpu32_icd_get_status;
|
||||
self->init_hardware = cpu32_icd_init_hardware;
|
||||
self->serial_clock = cpu32_icd_serial_clock;
|
||||
self->gen_bus_error = cpu32_icd_gen_bus_error;
|
||||
self->restart_chip = cpu32_icd_restart_chip;
|
||||
self->release_chip = cpu32_icd_release_chip;
|
||||
self->reset_chip = cpu32_icd_reset_chip;
|
||||
self->stop_chip = cpu32_icd_stop_chip;
|
||||
self->run_chip = cpu32_run_chip;
|
||||
self->step_chip = cpu32_icd_step_chip;
|
||||
self->fill_buf = bdmBitBashFillBuf;
|
||||
self->send_buf = bdmBitBashSendBuf;
|
||||
self->read_sysreg = cpu32_read_sysreg;
|
||||
self->read_proreg = bdmBitBashReadProcessorRegister;
|
||||
self->read_long_word = bdmBitBashReadLongWord;
|
||||
self->read_word = bdmBitBashReadWord;
|
||||
self->read_byte = bdmBitBashReadByte;
|
||||
self->write_sysreg = cpu32_write_sysreg;
|
||||
self->write_proreg = bdmBitBashWriteProcessorRegister;
|
||||
self->write_long_word = bdmBitBashWriteLongWord;
|
||||
self->write_word = bdmBitBashWriteWord;
|
||||
self->write_byte = bdmBitBashWriteByte;
|
||||
|
||||
#ifdef BDM_BIT_BASH_PORT
|
||||
self->bit_bash = cpu32_bit_bash;
|
||||
self->bit_bash_bits = 0;
|
||||
#endif
|
||||
|
||||
for (reg = 0; reg < BDM_MAX_SYSREG; reg++)
|
||||
self->shadow_sysreg[reg] = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user