Files
m68k-bdm/m68k/driver/bdm.c
Bernd Mueller adfd70813f initial push
2026-06-17 13:44:30 +02:00

1393 lines
34 KiB
C

/*
* Motorola Background Debug Mode Driver
* Copyright (C) 1995 W. Eric Norum
* Copyright (C) 1998-2007 Chris Johns
*
* Based on:
* 1. `A Background Debug Mode Driver Package for Motorola's
* 16- and 32-Bit Microcontrollers', Scott Howard, Motorola
* Canada, 1993.
* 2. `Linux device driver for public domain BDM Interface',
* M. Schraut, Technische Universitaet Muenchen, Lehrstuhl
* fuer Prozessrechner, 1995.
*
* Extended to support the ColdFire BDM interface using the P&E
* module which comes with the EVB. Currently only tested with the
* 5206 (5V) device.
*
* 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@users.sourceforge.net
*
* ccj@acm.org
*
* 19/1/1999 -- Greg Ungerer (gerg@moreton.com.au)
* Added support for more recent LINUX kernels 2.2.0+
*
* 22/10/1999 -- CCJ (ccj@acm.org)
* Remove the OS specific parts to allow for easier support for
* different OS's. This is based on the work done by
* David McCullough (davidm@stallion.oz.au) for the SCO port.
*
* 31/05/2000 - CCJ (ccj@acm.org)
* Merged in the ICD interface, and renamed the Eric interface
* to the PD interface.
*
* 01/09/2000 - ASA (aaganichev@hypercom.com)
* Fixed ICD and PD support basing on original driver code, fix ICD name
* misspelling.
*
* 14/11/2000 - James Housley <jim@thehousleys.net>
* Greg Tunnock (gtunnock@redfernnetworks.com)
* Port to FreeBSD.
*
* 02/02/2001 - KJO (vac4050@cae597.rsc.raytheon.com)
* Reduced time delays in some cpu32_icd_xxx() functions to improve
* performance of cpu32 ICD driver and speed up downloads.
*
* 12/12/2001 - Thomas Andrew (tandrews@mindspring.co.za)
* Change to stop getting "Invalid instruction (0x1FFFF) back from the
* ICD interface.
*/
/*
* Declarations common to kernel and user code
*/
#include "bdm.h"
/*
************************************************************************
* BDM driver control structure *
************************************************************************
*/
struct BDM {
/*
* Device name, processor and interface type
*/
char name[20];
int processor;
int interface;
/*
* Device I/O ports
*/
int exists;
int portsAreMine;
int portBase;
int dataPort;
int statusPort;
int controlPort;
int usbDev;
/*
* Control debugging messages
*/
int debugFlag;
/*
* Device is exclusive-use
*/
int isOpen;
/*
* Serial I/O delay timer
*/
int delayTimer;
/*
* I/O buffer
*/
char ioBuffer[512];
unsigned int readValue;
/*
* Interface specific handlers
*/
int (*get_status)(struct BDM *self);
int (*init_hardware) (struct BDM *self);
int (*serial_clock) (struct BDM *self, unsigned short wval, int holdback);
int (*gen_bus_error) (struct BDM *self);
int (*restart_chip) (struct BDM *self);
int (*release_chip) (struct BDM *self);
int (*reset_chip) (struct BDM *self);
int (*stop_chip) (struct BDM *self);
int (*run_chip) (struct BDM *self);
int (*step_chip) (struct BDM *self);
int (*fill_buf) (struct BDM *self, int count);
int (*send_buf) (struct BDM *self, int count);
int (*read_sysreg) (struct BDM *self, struct BDMioctl *ioc, int mode);
int (*read_proreg) (struct BDM *self, struct BDMioctl *ioc);
int (*read_long_word) (struct BDM *self, struct BDMioctl *ioc);
int (*read_word) (struct BDM *self, struct BDMioctl *ioc);
int (*read_byte) (struct BDM *self, struct BDMioctl *ioc);
int (*write_sysreg) (struct BDM *self, struct BDMioctl *ioc, int mode);
int (*write_proreg) (struct BDM *self, struct BDMioctl *ioc);
int (*write_long_word) (struct BDM *self, struct BDMioctl *ioc);
int (*write_word) (struct BDM *self, struct BDMioctl *ioc);
int (*write_byte) (struct BDM *self, struct BDMioctl *ioc);
/*
* Some system registers are write only so we need to shadow them
*/
unsigned long shadow_sysreg[BDM_MAX_SYSREG];
/*
* Coldfire processors have different versions of the debug module.
* These also require special operations to occur.
*/
int cf_debug_ver;
int cf_use_pst;
/*
* Need to get the status from the csr, how-ever the status bits are a
* once read then clear so we need logic to store this state to know
* the status.
*/
int cf_running;
unsigned long cf_csr;
/*
* Revision D BDM hardware does not have a bit to mask interrupts so
* we must save the SR when we step and then restore when we go.
*/
unsigned long cf_sr_mask_cache;
int cf_sr_masked;
/*
* Address for the current transfer. The TBLCF pod always
* takes the address rather than streaming. This should be changed.
*/
unsigned long address;
#ifdef BDM_BIT_BASH_PORT
int (*bit_bash) (struct BDM *self, unsigned short mask, unsigned short value);
/*
* The current state of the bit bash bits. Easier than figuring out
* if the bit should be on or off by reading the PC port. I am sure
* this could be done, but I am not a PC parallel port expert.
*/
unsigned short bit_bash_bits;
#endif
};
/*
************************************************************************
* System Register Modes *
************************************************************************
*/
#define BDM_SYS_REG_MODE_MAPPED (0)
#define BDM_SYS_REG_MODE_CONTROL (1)
#define BDM_SYS_REG_MODE_DEBUG (2)
/*
************************************************************************
* Common Functions *
************************************************************************
*/
static int bdmDrvGetStatus (struct BDM *self);
static int bdmDrvInitHardware (struct BDM *self);
static int bdmDrvRestartChip (struct BDM *self);
static int bdmDrvReleaseChip (struct BDM *self);
static int bdmDrvResetChip (struct BDM *self);
static int bdmDrvStopChip (struct BDM *self);
static int bdmDrvSerialClock (struct BDM *self, unsigned short wval, int holdback);
static int bdmDrvGenerateBusError (struct BDM *self);
static int bdmDrvStepChip (struct BDM *self);
static int bdmDrvSendCommandTillTargetReady (struct BDM *self,
unsigned short command);
static int bdmDrvFillBuf (struct BDM *self, int count);
static int bdmDrvSendBuf (struct BDM *self, int count);
static int bdmDrvGo (struct BDM *self);
static int bdmDrvReadSystemRegister (struct BDM *self, struct BDMioctl *ioc, int mode);
static int bdmDrvReadProcessorRegister (struct BDM *self, struct BDMioctl *ioc);
static int bdmDrvReadLongWord (struct BDM *self, struct BDMioctl *ioc);
static int bdmDrvReadWord (struct BDM *self, struct BDMioctl *ioc);
static int bdmDrvReadByte (struct BDM *self, struct BDMioctl *ioc);
static int bdmDrvWriteSystemRegister (struct BDM *self, struct BDMioctl *ioc, int mode);
static int bdmDrvWriteProcessorRegister (struct BDM *self, struct BDMioctl *ioc);
static int bdmDrvWriteLongWord (struct BDM *self, struct BDMioctl *ioc);
static int bdmDrvWriteWord (struct BDM *self, struct BDMioctl *ioc);
static int bdmDrvWriteByte (struct BDM *self, struct BDMioctl *ioc);
/*
* Common processor defines.
*/
/*
* CPU Generated Messages.
*/
#define CGM_FAILURE 1 /* bit 16, s/c bit */
#define CGM_CMD_OK 0xffff
#define CGM_NOT_READY 0x0000
#define CGM_BUS_ERROR 0x0001
#define CGM_ILLEGAL_CMD 0xffff
/*
* Command codes for BDM interface
*/
#define BDM_RREG_CMD 0x2180 /* CPU32, Coldfire */
#define BDM_WREG_CMD 0x2080 /* CPU32, Coldfire */
#define BDM_RSREG_CMD 0x2580 /* CPU32, Coldfire */
#define BDM_WSREG_CMD 0x2480 /* CPU32, Coldfire */
#define BDM_READ_CMD 0x1900 /* CPU32, Coldfire */
#define BDM_WRITE_CMD 0x1800 /* CPU32, Coldfire */
#define BDM_DUMP_CMD 0x1d00 /* CPU32, Coldfire */
#define BDM_FILL_CMD 0x1c00 /* CPU32, Coldfire */
#define BDM_GO_CMD 0x0c00 /* CPU32, Coldfire */
#define BDM_CALL_CMD 0x0800 /* CPU32 */
#define BDM_RST_CMD 0x0400 /* CPU32, Coldfire */
#define BDM_NOP_CMD 0x0000 /* CPU32, Coldfire */
#define BDM_RCREG_CMD 0x2980 /* Coldfire */
#define BDM_WCREG_CMD 0x2880 /* Coldfire */
#define BDM_RDMREG_CMD 0x2d80 /* Coldfire */
#define BDM_WDMREG_CMD 0x2c80 /* Coldfire */
#define BDM_FORCED_TA_CMD 0x0002 /* Coldfire version D and higher */
/*
* Operand size for BDM_READ_CMD/BDM_WRITE_CMD
*/
#define BDM_SIZE_BYTE 0x0000
#define BDM_SIZE_WORD 0x0040
#define BDM_SIZE_LONG 0x0080
/*
* Address/Data field
*/
#define BDM_ADDR_NOT_DATA 0x0004
/*
* Per-device data.
* Allocate a struct for each port for each interface.
*/
static struct BDM bdm_device_info[BDM_NUM_OF_MINORS];
/*
* Does this host require swapping.
*/
static int mustSwap;
/*
************************************************************************
* Genric Bit Bash Functions Decls *
************************************************************************
*/
static int bdmBitBashSendCommandTillTargetReady (struct BDM *self,
unsigned short command);
static int bdmBitBashFillBuf (struct BDM *self, int count);
static int bdmBitBashSendBuf (struct BDM *self, int count);
static int bdmbitBashFetchWord (struct BDM *self, unsigned short *sp);
static int bdmBitBashReadProcessorRegister (struct BDM *self,
struct BDMioctl *ioc);
static int bdmBitBashReadLongWord (struct BDM *self, struct BDMioctl *ioc);
static int bdmBitBashReadWord (struct BDM *self, struct BDMioctl *ioc);
static int bdmBitBashReadByte (struct BDM *self, struct BDMioctl *ioc);
static int bdmBitBashWriteProcessorRegister (struct BDM *self,
struct BDMioctl *ioc);
static int bdmBitBashWriteLongWord (struct BDM *self,
struct BDMioctl *ioc);
static int bdmBitBashWriteWord (struct BDM *self, struct BDMioctl *ioc);
static int bdmBitBashWriteByte (struct BDM *self, struct BDMioctl *ioc);
/*
************************************************************************
* CPU32 for PD/ICD interface support routines *
************************************************************************
*/
#include "bdm-cpu32.c"
/*
************************************************************************
* Coldfire P&E support routines *
************************************************************************
*/
#include "bdm-cf-pe.c"
/*
************************************************************************
* Coldfire P&E support routines *
************************************************************************
*/
#if BDM_TBLCF_USB
#include "bdm-tblcf.c"
#endif
/*
************************************************************************
* Genric Bit Bash Functions *
************************************************************************
*/
/*
* Loop till target I/O operation completes
*/
static int
bdmBitBashSendCommandTillTargetReady (struct BDM *self, unsigned short command)
{
int err;
int timeout = 0;
/*
* If no response is returned hit the bus error line and
* then wait for the bus error response.
*/
for (;;) {
err = bdmDrvSerialClock (self, command, 0);
if (err)
return err;
if ((self->readValue & 0x10000) == 0)
return 0;
++timeout;
if (timeout == 5) {
/*
* Should get a bus error response back.
*/
bdmDrvGenerateBusError (self);
}
if (timeout > 6) {
return BDM_FAULT_RESPONSE;
}
}
}
/*
* Fill I/O buffer with data from target
*/
static int
bdmBitBashFillBuf (struct BDM *self, int count)
{
unsigned short *sp = (unsigned short *)self->ioBuffer;
int cmd;
int err;
if (self->debugFlag)
PRINTF ("bdmBitBashFillBuf - count:%d\n", count);
if (count == 0)
return 0;
if (count >= 4)
cmd = BDM_DUMP_CMD | BDM_SIZE_LONG;
else if (count >= 2)
cmd = BDM_DUMP_CMD | BDM_SIZE_WORD;
else
cmd = BDM_DUMP_CMD | BDM_SIZE_BYTE;
err = bdmDrvSerialClock (self, cmd, 0);
if (err)
return err;
for (;;) {
switch (count) {
case 1:
err = bdmBitBashSendCommandTillTargetReady (self, BDM_NOP_CMD);
if (err)
return err;
*(unsigned char *)sp = self->readValue;
return 0;
case 2:
err = bdmBitBashSendCommandTillTargetReady (self, BDM_NOP_CMD);
if (err)
return err;
*sp = self->readValue;
return 0;
case 3:
err = bdmBitBashSendCommandTillTargetReady (self, BDM_DUMP_CMD | BDM_SIZE_BYTE);
if (err)
return err;
*sp++ = self->readValue;
count -= 2;
break;
case 4:
err = bdmBitBashSendCommandTillTargetReady (self, BDM_NOP_CMD);
if (err)
return err;
*sp++ = self->readValue;
err = bdmDrvSerialClock (self, BDM_NOP_CMD, 0);
if (err)
return err;
*sp = self->readValue;
return 0;
case 5:
err = bdmBitBashSendCommandTillTargetReady (self, BDM_NOP_CMD);
if (err)
return err;
*sp++ = self->readValue;
err = bdmBitBashSendCommandTillTargetReady (self, BDM_DUMP_CMD | BDM_SIZE_BYTE);
if (err)
return err;
*sp++ = self->readValue;
count -= 4;
break;
case 6:
case 7:
err = bdmBitBashSendCommandTillTargetReady (self, BDM_NOP_CMD);
if (err)
return err;
*sp++ = self->readValue;
err = bdmBitBashSendCommandTillTargetReady (self, BDM_DUMP_CMD | BDM_SIZE_WORD);
if (err)
return err;
*sp++ = self->readValue;
count -= 4;
break;
default:
err = bdmBitBashSendCommandTillTargetReady (self, BDM_NOP_CMD);
if (err)
return err;
*sp++ = self->readValue;
err = bdmBitBashSendCommandTillTargetReady (self, BDM_DUMP_CMD | BDM_SIZE_LONG);
if (err)
return err;
*sp++ = self->readValue;
count -= 4;
break;
}
}
}
/*
* Send contents of I/O buffer to target
*/
static int
bdmBitBashSendBuf (struct BDM *self, int count)
{
unsigned short *sp = (unsigned short *)self->ioBuffer;
int cmd;
int err;
if (self->debugFlag)
PRINTF ("bdmBitBashSendBuf - count:%d\n", count);
if (count == 0)
return 0;
for (;;) {
if (count >= 4)
cmd = BDM_FILL_CMD | BDM_SIZE_LONG;
else if (count >= 2)
cmd = BDM_FILL_CMD | BDM_SIZE_WORD;
else if (count >= 1)
cmd = BDM_FILL_CMD | BDM_SIZE_BYTE;
else
cmd = BDM_NOP_CMD;
err = bdmBitBashSendCommandTillTargetReady (self, cmd);
if (err)
return err;
if (count >= 4) {
err = bdmDrvSerialClock (self, *sp++, 0);
if (err)
return err;
err = bdmDrvSerialClock (self, *sp++, 0);
if (err)
return err;
count -= 4;
}
else if (count >= 2) {
err = bdmDrvSerialClock (self, *sp++, 0);
if (err)
return err;
count -= 2;
}
else if (count >= 1) {
err = bdmDrvSerialClock (self, *(unsigned char *)sp, 0);
if (err)
return err;
count -= 1;
}
else {
return 0;
}
}
}
/*
* Get a word from the target
*/
int
bdmBitBashFetchWord (struct BDM *self, unsigned short *sp)
{
int err;
err = bdmBitBashSendCommandTillTargetReady (self, BDM_NOP_CMD);
if (err)
return err;
*sp = self->readValue;
return 0;
}
/*
* Read processor register
*/
static int
bdmBitBashReadProcessorRegister (struct BDM *self, struct BDMioctl *ioc)
{
int err;
unsigned short msw, lsw;
if (((err = bdmDrvSerialClock (self, BDM_RREG_CMD | (ioc->address & 0xF), 0)) != 0) ||
((err = bdmBitBashFetchWord (self, &msw)) != 0) ||
((err = bdmBitBashFetchWord (self, &lsw)) != 0)) {
if (self->debugFlag)
PRINTF ("bdmBitBashReadProcessorRegister - reg:0x%02x, failed err=%d\n",
ioc->address & 0xF, err);
return err;
}
ioc->value = (msw << 16) | lsw;
if (self->debugFlag)
PRINTF ("bdmBitBashReadProcessorRegister - reg:0x%02x = 0x%08x\n",
ioc->address & 0xF, ioc->value);
return 0;
}
/*
* Read a long word from memory
*/
static int
bdmBitBashReadLongWord (struct BDM *self, struct BDMioctl *ioc)
{
int err;
unsigned short msw, lsw;
if (((err = bdmDrvSerialClock (self, BDM_READ_CMD | BDM_SIZE_LONG, 0)) != 0) ||
((err = bdmDrvSerialClock (self, ioc->address >> 16, 0)) != 0) ||
((err = bdmDrvSerialClock (self, ioc->address, 0)) != 0) ||
((err = bdmBitBashFetchWord (self, &msw)) != 0) ||
((err = bdmBitBashFetchWord (self, &lsw)) != 0)) {
if (self->debugFlag)
PRINTF ("bdmBitBashReadLongWord : *0x%08x failed, err=%d\n", ioc->address, err);
return err;
}
ioc->value = (msw << 16) | lsw;
if (self->debugFlag)
PRINTF ("bdmBitBashReadLongWord : *0x%08x = 0x%08x\n", ioc->address, ioc->value);
return 0;
}
/*
* Read a word from memory
*/
static int
bdmBitBashReadWord (struct BDM *self, struct BDMioctl *ioc)
{
int err;
unsigned short w;
if (((err = bdmDrvSerialClock (self, BDM_READ_CMD | BDM_SIZE_WORD, 0)) != 0) ||
((err = bdmDrvSerialClock (self, ioc->address >> 16, 0)) != 0) ||
((err = bdmDrvSerialClock (self, ioc->address, 0)) != 0) ||
((err = bdmBitBashFetchWord (self, &w)) != 0)) {
if (self->debugFlag)
PRINTF ("bdmBitBashReadWord : *0x%08x failed, err=%d\n", ioc->address, err);
return err;
}
ioc->value = w;
if (self->debugFlag)
PRINTF ("bdmBitBashReadWord : *0x%08x = 0x%04x\n", ioc->address, (ioc->value & 0xffff));
return 0;
}
/*
* Read a byte from memory
*/
static int
bdmBitBashReadByte (struct BDM *self, struct BDMioctl *ioc)
{
int err;
unsigned short w;
if (((err = bdmDrvSerialClock (self, BDM_READ_CMD | BDM_SIZE_BYTE, 0)) != 0) ||
((err = bdmDrvSerialClock (self, ioc->address >> 16, 0)) != 0) ||
((err = bdmDrvSerialClock (self, ioc->address, 0)) != 0) ||
((err = bdmBitBashFetchWord (self, &w)) != 0)){
if (self->debugFlag)
PRINTF ("bdmBitBashReadByte : *0x%08x failed, err=%d\n", ioc->address, err);
return err;
}
ioc->value = w;
if (self->debugFlag)
PRINTF ("bdmBitBashReadByte : *0x%08x = 0x%02x\n", ioc->address, (ioc->value & 0xff));
return 0;
}
/*
* Write processor register
*/
static int
bdmBitBashWriteProcessorRegister (struct BDM *self, struct BDMioctl *ioc)
{
int err;
if (self->debugFlag)
PRINTF ("bdmBitBashWriteProcessorRegister - reg:%d, val:0x%08x\n",
ioc->address & 0xF, ioc->value);
if (((err = bdmDrvSerialClock (self, BDM_WREG_CMD | (ioc->address & 0xF), 0)) != 0) ||
((err = bdmDrvSerialClock (self, ioc->value >> 16, 0)) != 0) ||
((err = bdmDrvSerialClock (self, ioc->value, 0)) != 0))
return err;
return 0;
}
/*
* Write a long word to memory
*/
static int
bdmBitBashWriteLongWord (struct BDM *self, struct BDMioctl *ioc)
{
int err;
unsigned short w;
if (self->debugFlag)
PRINTF ("bdmBitBashWriteLongWord : 0x%08x = 0x%08x\n", ioc->address, ioc->value);
if (((err = bdmDrvSerialClock (self, BDM_WRITE_CMD | BDM_SIZE_LONG, 0)) != 0) ||
((err = bdmDrvSerialClock (self, ioc->address >> 16, 0)) != 0) ||
((err = bdmDrvSerialClock (self, ioc->address, 0)) != 0) ||
((err = bdmDrvSerialClock (self, ioc->value >> 16, 0)) != 0) ||
((err = bdmDrvSerialClock (self, ioc->value, 0)) != 0) ||
((err = bdmBitBashFetchWord (self, &w)) != 0))
return err;
return 0;
}
/*
* Write a word to memory
*/
static int
bdmBitBashWriteWord (struct BDM *self, struct BDMioctl *ioc)
{
int err;
unsigned short w;
if (self->debugFlag)
PRINTF ("bdmBitBashWriteWord : 0x%08x = 0x%04x\n", ioc->address, (ioc->value & 0xffff));
if (((err = bdmDrvSerialClock (self, BDM_WRITE_CMD | BDM_SIZE_WORD, 0)) != 0) ||
((err = bdmDrvSerialClock (self, ioc->address >> 16, 0)) != 0) ||
((err = bdmDrvSerialClock (self, ioc->address, 0)) != 0) ||
((err = bdmDrvSerialClock (self, ioc->value, 0)) != 0) ||
((err = bdmBitBashFetchWord (self, &w)) != 0))
return err;
return 0;
}
/*
* Write a byte to memory
*/
static int
bdmBitBashWriteByte (struct BDM *self, struct BDMioctl *ioc)
{
int err;
unsigned short w;
if (self->debugFlag)
PRINTF ("bdmBitBashWriteByte : 0x%08x = 0x%02x\n", ioc->address, (ioc->value & 0xff));
if (((err = bdmDrvSerialClock (self, BDM_WRITE_CMD | BDM_SIZE_BYTE, 0)) != 0) ||
((err = bdmDrvSerialClock (self, ioc->address >> 16, 0)) != 0) ||
((err = bdmDrvSerialClock (self, ioc->address, 0)) != 0) ||
((err = bdmDrvSerialClock (self, ioc->value, 0)) != 0) ||
((err = bdmBitBashFetchWord (self, &w)) != 0))
return err;
return 0;
}
/*
************************************************************************
* Common Functions *
************************************************************************
*/
/*
* Get target status
*/
static int
bdmDrvGetStatus (struct BDM *self)
{
return (self->get_status) (self);
}
/*
* Hardware initialization
*/
static int
bdmDrvInitHardware (struct BDM *self)
{
return (self->init_hardware) (self);
}
/*
* Clock a word to/from the target
*/
static int
bdmDrvSerialClock (struct BDM *self, unsigned short wval, int holdback)
{
return (self->serial_clock) (self, wval, holdback);
}
/*
* Generate a bus error on the target.
*/
static int
bdmDrvGenerateBusError (struct BDM *self)
{
return (self->gen_bus_error) (self);
}
/*
* Restart chip and stop on the first instruction fetch
*/
static int
bdmDrvRestartChip (struct BDM *self)
{
return (self->restart_chip) (self);
}
/*
* Restart chip and disable background debugging mode
*/
static int
bdmDrvReleaseChip (struct BDM *self)
{
return (self->release_chip) (self);
}
/*
* Reset chip, enable background debugging mode, halt on first fetch.
*
*/
static int
bdmDrvResetChip (struct BDM *self)
{
return (self->reset_chip) (self);
}
/*
* Force the target into background debugging mode
*/
static int
bdmDrvStopChip (struct BDM *self)
{
return (self->stop_chip) (self);
}
/*
* Restart target execution
*/
static int
bdmDrvGo (struct BDM *self)
{
return (self->run_chip) (self);
}
/*
* Make the target execute a single instruction and
* reenter background debugging mode
*/
static int
bdmDrvStepChip (struct BDM *self)
{
return (self->step_chip) (self);
}
/*
* Fill I/O buffer with data from target
*/
static int
bdmDrvFillBuf (struct BDM *self, int count)
{
int err = (self->fill_buf) (self, count);
if (mustSwap)
{
char *p = self->ioBuffer;
int i;
char c;
for (i = 0; i < (count - 1); i += 2)
{
c = *p;
*p = *(p + 1);
p++;
*p = c;
p++;
}
}
return err;
}
/*
* Send contents of I/O buffer to target
*/
static int
bdmDrvSendBuf (struct BDM *self, int count)
{
if (mustSwap)
{
char *p = self->ioBuffer;
int i;
char c;
for (i = 0; i < (count - 1); i += 2)
{
c = *p;
*p = *(p + 1);
p++;
*p = c;
p++;
}
}
return (self->send_buf) (self, count);
}
/*
* Read system register
*/
static int
bdmDrvReadSystemRegister (struct BDM *self, struct BDMioctl *ioc, int mode)
{
return (self->read_sysreg) (self, ioc, mode);
}
/*
* Read processor register
*/
static int
bdmDrvReadProcessorRegister (struct BDM *self, struct BDMioctl *ioc)
{
return (self->read_proreg) (self, ioc);
}
/*
* Read a long word from memory
*/
static int
bdmDrvReadLongWord (struct BDM *self, struct BDMioctl *ioc)
{
return (self->read_long_word) (self, ioc);
}
/*
* Read a word from memory
*/
static int
bdmDrvReadWord (struct BDM *self, struct BDMioctl *ioc)
{
return (self->read_word) (self, ioc);
}
/*
* Read a byte from memory
*/
static int
bdmDrvReadByte (struct BDM *self, struct BDMioctl *ioc)
{
return (self->read_byte) (self, ioc);
}
/*
* Write system register
*/
static int
bdmDrvWriteSystemRegister (struct BDM *self, struct BDMioctl *ioc, int mode)
{
return (self->write_sysreg) (self, ioc, mode);
}
/*
* Write processor register
*/
static int
bdmDrvWriteProcessorRegister (struct BDM *self, struct BDMioctl *ioc)
{
return (self->write_proreg) (self, ioc);
}
/*
* Write a long word to memory
*/
static int
bdmDrvWriteLongWord (struct BDM *self, struct BDMioctl *ioc)
{
return (self->write_long_word) (self, ioc);
}
/*
* Write a word to memory
*/
static int
bdmDrvWriteWord (struct BDM *self, struct BDMioctl *ioc)
{
return (self->write_word) (self, ioc);
}
/*
* Write a byte to memory
*/
static int
bdmDrvWriteByte (struct BDM *self, struct BDMioctl *ioc)
{
return (self->write_byte) (self, ioc);
}
#ifdef BDM_BIT_BASH_PORT
/*
* Bit Bash the BDM signals. This is provided to allow low level
* bit bashing support for getting new BDM or target hardware
* working.
*/
static int
bdmDrvBitBash (struct BDM *self, struct BDMioctl *ioc)
{
if (self->bit_bash)
return (self->bit_bash) (self, ioc->value >> 16, ioc->value & 0xffff);
return -1;
}
#endif
/*
************************************************************************
* Driver Functions which are common to the different OS's *
************************************************************************
*/
/*
* Requires the OS to define `os_claim_io_ports' and
* `os_release_io_ports'. If your OS does not support this,
* do nothing and return an error code of 0.
*/
static int
bdm_open (unsigned int minor)
{
struct BDM *self;
int status, err = 0;
union {
char c[4];
uint32_t l;
} un;
if (minor >= (sizeof bdm_device_info / sizeof bdm_device_info[0]))
return ENODEV;
/*
* Determine what byte-swapping we'll need to do
*/
if (sizeof un.l != sizeof un.c) {
PRINTF ("bdm_open -- host machine sizeof (uint32_t) != sizeof (char[4])");
return ENODEV;
}
if ((sizeof (uint32_t) != 4) ||
(sizeof (short) != 2) ||
(sizeof (char) != 1)) {
PRINTF ("bdm_open -- host machine sizeof not appropriate");
return ENODEV;
}
un.c[0] = 0x01;
un.c[1] = 0x02;
un.c[2] = 0x03;
un.c[3] = 0x04;
if (un.l == 0x01020304) {
mustSwap = 0;
}
else if (un.l == 0x04030201) {
mustSwap = 1;
}
else {
PRINTF ("bdm_open -- host machine has peculiar byte ordering");
return ENODEV;
}
self = &bdm_device_info[minor];
if (self->debugFlag > 0)
PRINTF ("bdm_open -- minor %d\n", minor);
if (!self->exists)
return ENODEV;
if (self->isOpen)
return EBUSY;
/*
* Ask the OS to try and claim the port.
*/
err = os_claim_io_ports (self->name, self->portBase, 4);
if (err)
return err;
self->portsAreMine = 1;
if (self->debugFlag)
PRINTF ("bdm_open -- %s using port 0x%x.\n", self->name, self->portBase);
/*
* Set up the driver.
*/
status = bdmDrvInitHardware (self);
if (status & BDM_TARGETNC)
err = BDM_FAULT_CABLE;
else if (status & BDM_TARGETPOWER)
err = BDM_FAULT_POWER;
if (err) {
os_release_io_ports (self->portBase, 4);
self->portsAreMine = 0;
}
else {
os_lock_module ();
self->isOpen = 1;
}
if (self->debugFlag)
PRINTF ("BDMopen return %d, delayTimer %d\n", err, self->delayTimer);
return err;
}
/*
* The old Linux driver set the control port back to the value it
* had when the device was opened. This is good when the port is
* being shared between the BDM interface and a printer, but has
* the unfortunate side effect of freezing the target. This makes
* it inconvenient to use the debugger, or a downloader program,
* since the target freezes as soon as the debugger, or downloader,
* exits.
*/
static int
bdm_close (unsigned int minor)
{
struct BDM *self = &bdm_device_info[minor];
if (self->isOpen) {
bdmDrvReleaseChip (self);
if (self->exists && self->portsAreMine)
os_release_io_ports (self->portBase, 4);
self->portsAreMine = 0;
self->isOpen = 0;
os_unlock_module ();
}
if (self->debugFlag)
PRINTF ("BDM released\n");
return 0;
}
static int
bdm_ioctl (unsigned int minor, unsigned int cmd, unsigned long arg)
{
struct BDM *self = &bdm_device_info[minor];
struct BDMioctl ioc;
int iarg;
int err = 0;
/*
* Pick up the argument
*/
if (self->debugFlag > 3)
PRINTF ("BDMioctl cmd:0x%x\n", cmd);
switch (cmd) {
case BDM_READ_REG:
case BDM_READ_CTLREG:
case BDM_READ_DBREG:
case BDM_READ_SYSREG:
case BDM_READ_LONGWORD:
case BDM_READ_WORD:
case BDM_READ_BYTE:
case BDM_WRITE_REG:
case BDM_WRITE_CTLREG:
case BDM_WRITE_DBREG:
case BDM_WRITE_SYSREG:
case BDM_WRITE_LONGWORD:
case BDM_WRITE_WORD:
case BDM_WRITE_BYTE:
err = os_copy_in ((void*) &ioc, (void*) arg, sizeof ioc);
break;
case BDM_SPEED:
case BDM_DEBUG:
case BDM_SET_CF_PST:
err = os_copy_in ((void*) &iarg, (void*) arg, sizeof iarg);
if (self->debugFlag > 3)
PRINTF ("BDMioctl cmd->iarg:0x%x\n", iarg);
break;
}
if (err)
return err;
/*
* Handle the request
*/
switch (cmd) {
case BDM_INIT:
iarg = bdmDrvInitHardware (self);
if (iarg & BDM_TARGETNC)
err = BDM_FAULT_CABLE;
else if (iarg & BDM_TARGETPOWER)
err = BDM_FAULT_POWER;
break;
case BDM_RESET_CHIP:
err = bdmDrvResetChip (self);
break;
case BDM_RESTART_CHIP:
err = bdmDrvRestartChip (self);
break;
case BDM_STOP_CHIP:
err = bdmDrvStopChip (self);
break;
case BDM_STEP_CHIP:
err = bdmDrvStepChip (self);
break;
case BDM_GO:
err = bdmDrvGo (self);
break;
case BDM_GET_STATUS:
iarg = bdmDrvGetStatus (self);
break;
case BDM_SPEED:
self->delayTimer = iarg;
if (self->debugFlag)
PRINTF ("delayTimer now %d\n", self->delayTimer);
break;
case BDM_DEBUG:
self->debugFlag = iarg;
if (self->debugFlag)
PRINTF ("debugFlag now %d\n", self->debugFlag);
break;
case BDM_RELEASE_CHIP:
err = bdmDrvReleaseChip (self);
break;
case BDM_READ_CTLREG:
err = bdmDrvReadSystemRegister (self, &ioc, BDM_SYS_REG_MODE_CONTROL);
break;
case BDM_READ_DBREG:
err = bdmDrvReadSystemRegister (self, &ioc, BDM_SYS_REG_MODE_DEBUG);
break;
case BDM_READ_REG:
err = bdmDrvReadProcessorRegister (self, &ioc);
break;
case BDM_READ_SYSREG:
err = bdmDrvReadSystemRegister (self, &ioc, BDM_SYS_REG_MODE_MAPPED);
break;
case BDM_READ_LONGWORD:
err = bdmDrvReadLongWord (self, &ioc);
break;
case BDM_READ_WORD:
err = bdmDrvReadWord (self, &ioc);
break;
case BDM_READ_BYTE:
err = bdmDrvReadByte (self, &ioc);
break;
case BDM_WRITE_CTLREG:
err = bdmDrvWriteSystemRegister (self, &ioc, BDM_SYS_REG_MODE_CONTROL);
break;
case BDM_WRITE_DBREG:
err = bdmDrvWriteSystemRegister (self, &ioc, BDM_SYS_REG_MODE_DEBUG);
break;
case BDM_WRITE_SYSREG:
err = bdmDrvWriteSystemRegister (self, &ioc, BDM_SYS_REG_MODE_MAPPED);
break;
case BDM_WRITE_REG:
err = bdmDrvWriteProcessorRegister (self, &ioc);
break;
case BDM_WRITE_LONGWORD:
err = bdmDrvWriteLongWord (self, &ioc);
break;
case BDM_WRITE_WORD:
err = bdmDrvWriteWord (self, &ioc);
break;
case BDM_WRITE_BYTE:
err = bdmDrvWriteByte (self, &ioc);
break;
case BDM_GET_CPU_TYPE:
iarg = self->processor;
break;
case BDM_GET_IF_TYPE:
iarg = self->interface;
break;
case BDM_GET_DRV_VER:
iarg = BDM_DRV_VERSION;
break;
case BDM_GET_CF_PST:
iarg = self->cf_use_pst;
break;
case BDM_SET_CF_PST:
self->cf_use_pst = iarg;
break;
default:
err = EINVAL;
break;
}
if (err)
return err;
/*
* Return the result if no error was found.
*/
switch (cmd) {
case BDM_READ_REG:
case BDM_READ_CTLREG:
case BDM_READ_DBREG:
case BDM_READ_SYSREG:
case BDM_READ_LONGWORD:
case BDM_READ_WORD:
case BDM_READ_BYTE:
err = os_copy_out ((void*) arg, (void*) &ioc, sizeof ioc);
break;
case BDM_GET_STATUS:
case BDM_GET_CPU_TYPE:
case BDM_GET_IF_TYPE:
case BDM_GET_DRV_VER:
case BDM_GET_CF_PST:
err = os_copy_out ((void*) arg, (void*) &iarg, sizeof iarg);
}
return err;
}
static int
bdm_read (unsigned int minor, char *buf, int count)
{
struct BDM *self = &bdm_device_info[minor];
int nleft, ncopy;
int err;
nleft = count;
while (nleft) {
if (nleft > sizeof self->ioBuffer)
ncopy = sizeof self->ioBuffer;
else
ncopy = nleft;
err = bdmDrvFillBuf (self, ncopy);
if (err)
return err;
err = os_move_out (buf, self->ioBuffer, ncopy);
if (err)
return err;
nleft -= ncopy;
#ifndef BUF_INCREMENTED_BY_MOVE_OUT
buf += ncopy;
#endif
}
return 0;
}
static int
bdm_write (unsigned int minor, char *buf, int count)
{
struct BDM *self = &bdm_device_info[minor];
int nleft, ncopy;
int err;
nleft = count;
while (nleft) {
if (nleft > sizeof self->ioBuffer)
ncopy = sizeof self->ioBuffer;
else
ncopy = nleft;
err = os_move_in (self->ioBuffer, (void*) buf, ncopy);
if (err)
return err;
err = bdmDrvSendBuf (self, ncopy);
if (err)
return err;
nleft -= ncopy;
#ifndef BUF_INCREMENTED_BY_MOVE_IN
buf += ncopy;
#endif
}
return 0;
}