From dc2cdf84516ee0bbde854cf9fca2ed7b637739d6 Mon Sep 17 00:00:00 2001 From: Kolja Waschk Date: Thu, 8 Nov 2007 07:11:41 +0000 Subject: [PATCH] [ 1429825 ] EJTAG driver (partial patch - only the bus driver for now) git-svn-id: https://urjtag.svn.sourceforge.net/svnroot/urjtag/trunk@737 b68d4a1b-bc3d-0410-92ed-d4ac073336b7 --- jtag/src/bus/Makefile.am | 1 + jtag/src/bus/buses.c | 1 + jtag/src/bus/buses.h | 1 + jtag/src/bus/ejtag.c | 493 +++++++++++++++++++++++++++++++++++ jtag/src/tap/parport/ppdev.c | 2 +- 5 files changed, 497 insertions(+), 1 deletion(-) create mode 100644 jtag/src/bus/ejtag.c diff --git a/jtag/src/bus/Makefile.am b/jtag/src/bus/Makefile.am index 7d56a44f..d8ae0d56 100644 --- a/jtag/src/bus/Makefile.am +++ b/jtag/src/bus/Makefile.am @@ -30,6 +30,7 @@ libbus_a_SOURCES = \ buses.h \ au1500.c \ bcm1250.c \ + ejtag.c \ bf533_stamp.c \ bf533_ezkit.c \ ixp425.c \ diff --git a/jtag/src/bus/buses.c b/jtag/src/bus/buses.c index f50fa657..1b1247f7 100644 --- a/jtag/src/bus/buses.c +++ b/jtag/src/bus/buses.c @@ -32,6 +32,7 @@ const bus_driver_t *bus_drivers[] = { &au1500_bus, &bcm1250_bus, + &ejtag_bus, &bf533_stamp_bus, &bf533_ezkit_bus, &ixp425_bus, diff --git a/jtag/src/bus/buses.h b/jtag/src/bus/buses.h index 18087e67..c8095346 100644 --- a/jtag/src/bus/buses.h +++ b/jtag/src/bus/buses.h @@ -27,6 +27,7 @@ extern const bus_driver_t au1500_bus; extern const bus_driver_t bcm1250_bus; +extern const bus_driver_t ejtag_bus; extern const bus_driver_t bf533_stamp_bus; extern const bus_driver_t bf533_ezkit_bus; extern const bus_driver_t ixp425_bus; diff --git a/jtag/src/bus/ejtag.c b/jtag/src/bus/ejtag.c new file mode 100644 index 00000000..1f33e813 --- /dev/null +++ b/jtag/src/bus/ejtag.c @@ -0,0 +1,493 @@ +/* + * $Id$ + * + * EJTAG compatible bus driver via PrAcc + * Copyright (C) 2005, Marek Michalkiewicz + * + * 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., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by Marek Michalkiewicz , 2005. + * + * Documentation: + * [1] MIPS Licensees, "MIPS EJTAG Debug Solution", 980818 Rev. 2.0.0 + * [2] MIPS Technologies, Inc. "EJTAG Specification", 2001-02-15, Rev. 2.60 + * + */ + +#include "sysdep.h" + +#include +#include +#include + +#include "part.h" +#include "bus.h" +#include "chain.h" +#include "bssignal.h" +#include "jtag.h" +#include "buses.h" + +typedef struct { + chain_t *chain; + part_t *part; + int initialized; + uint32_t impcode; /* EJTAG Implementation Register */ + uint16_t adr_hi; /* cached high bits of $3 */ +} bus_params_t; + +#define BP ((bus_params_t *) bus->params) + +#define CHAIN (BP->chain) +#define PART (BP->part) + +#define EJTAG_VER ((BP->impcode >> 29) & 7) + +#define EJTAG_20 0 +#define EJTAG_25 1 +#define EJTAG_26 2 + +static int ejtag_bus_area( bus_t *bus, uint32_t adr, bus_area_t *area ); + +static void +ejtag_bus_printinfo( bus_t *bus ) +{ + int i; + + for (i = 0; i < CHAIN->parts->len; i++) + if (PART == CHAIN->parts->parts[i]) + break; + printf( _("EJTAG compatible bus driver via PrAcc (JTAG part No. %d)\n"), i ); +} + +/* EJTAG control register bits */ +#define PerRst 20 +#define PRnW 19 +#define PrAcc 18 +#define PrRst 16 +#define ProbEn 15 +#define JtagBrk 12 +#define BrkSt 3 + +/* EJTAG 2.6 */ +#define Rocc 31 +#define ProbTrap 14 + +static uint32_t +reg_value( tap_register *reg ) +{ + uint32_t retval = 0; + int i; + + for (i = 0; i < reg->len; i++) { + if (reg->data[i]) + retval |= (1 << i); + } + return retval; +} + +static uint32_t +ejtag_run_pracc( bus_t *bus, const uint32_t *code, unsigned int len ) +{ + data_register *ejaddr, *ejdata, *ejctrl; + int i, pass; + uint32_t addr, data, retval; + + ejaddr = part_find_data_register( PART, "EJADDRESS" ); + ejdata = part_find_data_register( PART, "EJDATA" ); + ejctrl = part_find_data_register( PART, "EJCONTROL" ); + if (!(ejaddr && ejdata && ejctrl)) { + printf( _("%s(%d) EJADDRESS, EJDATA or EJCONTROL register not found\n"), + __FILE__, __LINE__ ); + return 0; + } + + part_set_instruction( PART, "EJTAG_CONTROL" ); + chain_shift_instructions( CHAIN ); + + pass = 0; + retval = 0; + + for (;;) { + ejctrl->in->data[PrAcc] = 1; + chain_shift_data_registers( CHAIN, 0 ); + chain_shift_data_registers( CHAIN, 1 ); + + // printf( "ctrl=%s\n", register_get_string( ejctrl->out ) ); + + if (ejctrl->out->data[Rocc]) { + printf( _("%s(%d) Reset occurred, ctrl=%s\n"), + __FILE__, __LINE__, + register_get_string( ejctrl->out ) ); + BP->initialized = 0; + break; + } + if (! ejctrl->out->data[PrAcc]) { + printf( _("%s(%d) No processor access, ctrl=%s\n"), + __FILE__, __LINE__, + register_get_string( ejctrl->out ) ); + BP->initialized = 0; + break; + } + + part_set_instruction( PART, "EJTAG_ADDRESS" ); + chain_shift_instructions( CHAIN ); + + chain_shift_data_registers( CHAIN, 1 ); + addr = reg_value( ejaddr->out ); + if (addr & 3) { + printf( _("%s(%d) PrAcc bad alignment: addr=0x%08x\n"), + __FILE__, __LINE__, addr ); + addr &= ~3; + } + + part_set_instruction( PART, "EJTAG_DATA" ); + chain_shift_instructions( CHAIN ); + + register_fill( ejdata->in, 0 ); + + if (ejctrl->out->data[PRnW]) { + chain_shift_data_registers( CHAIN, 1 ); + data = reg_value( ejdata->out ); +#if 0 + printf( _("%s(%d) PrAcc write: addr=0x%08x data=0x%08x\n"), + __FILE__, __LINE__, addr, data ); +#endif + if (addr == UINT32_C(0xff200000)) { + /* Return value from the target CPU. */ + retval = data; + } else { + printf( _("%s(%d) Unknown write addr=0x%08x data=0x%08x\n"), + __FILE__, __LINE__, addr, data ); + } + } else { + if (addr == UINT32_C(0xff200200) && pass++) + break; + + data = 0; + if (addr >= 0xff200200 && addr < 0xff200200 + (len << 2)) { + data = code[(addr - 0xff200200) >> 2]; + + for (i = 0; i < 32; i++) + ejdata->in->data[i] = (data >> i) & 1; + } +#if 0 + printf( "%s(%d) PrAcc read: addr=0x%08x data=0x%08x\n", + __FILE__, __LINE__, addr, data ); +#endif + chain_shift_data_registers( CHAIN, 0 ); + } + + part_set_instruction( PART, "EJTAG_CONTROL" ); + chain_shift_instructions( CHAIN ); + + ejctrl->in->data[PrAcc] = 0; + chain_shift_data_registers( CHAIN, 0 ); + } + return retval; +} + +static void +ejtag_bus_init( bus_t *bus ) +{ + data_register *ejctrl, *ejimpl; + uint32_t code[4] = { + 0x3c04ff20, // lui $4,0xff20 + 0x349f0200, // ori $31,$4,0x0200 + 0x03e00008, // jr $31 + 0x3c030000 // lui $3,0 + }; + + ejctrl = part_find_data_register( PART, "EJCONTROL" ); + ejimpl = part_find_data_register( PART, "EJIMPCODE" ); + if (!(ejctrl && ejimpl)) { + printf( _("%s(%d) EJCONTROL or EJIMPCODE register not found\n"), + __FILE__, __LINE__ ); + return; + } + + part_set_instruction( PART, "EJTAG_IMPCODE" ); + chain_shift_instructions( CHAIN ); + chain_shift_data_registers( CHAIN, 0 ); + chain_shift_data_registers( CHAIN, 1 ); + printf( "ImpCode=%s\n", register_get_string( ejimpl->out ) ); + BP->impcode = reg_value( ejimpl->out ); + + switch (EJTAG_VER) { + case EJTAG_20: printf( "EJTAG version: <= 2.0\n"); break; + case EJTAG_25: printf( "EJTAG version: 2.5\n"); break; + case EJTAG_26: printf( "EJTAG version: 2.6\n"); break; + default: + printf( "EJTAG version: unknown (%d)\n", EJTAG_VER ); + } + printf( "EJTAG Implementation flags:%s%s%s%s%s%s%s\n", + (BP->impcode & (1 << 28)) ? " R3k" : " R4k", + (BP->impcode & (1 << 24)) ? " DINTsup" : "", + (BP->impcode & (1 << 22)) ? " ASID_8" : "", + (BP->impcode & (1 << 21)) ? " ASID_6" : "", + (BP->impcode & (1 << 16)) ? " MIPS16" : "", + (BP->impcode & (1 << 14)) ? " NoDMA" : "", + (BP->impcode & (1 )) ? " MIPS64" : " MIPS32" ); + + if (EJTAG_VER >= EJTAG_25) { + part_set_instruction( PART, "EJTAGBOOT" ); + chain_shift_instructions( CHAIN ); + } + + part_set_instruction( PART, "EJTAG_CONTROL" ); + chain_shift_instructions( CHAIN ); + + register_fill( ejctrl->in, 0 ); + + ejctrl->in->data[PrRst] = 1; + ejctrl->in->data[PerRst] = 1; + chain_shift_data_registers( CHAIN, 0 ); + + ejctrl->in->data[PrRst] = 0; + ejctrl->in->data[PerRst] = 0; + chain_shift_data_registers( CHAIN, 0 ); + + ejctrl->in->data[PrAcc] = 1; + ejctrl->in->data[ProbEn] = 1; + if (EJTAG_VER >= EJTAG_25) { + ejctrl->in->data[ProbTrap] = 1; + ejctrl->in->data[Rocc] = 1; + } + chain_shift_data_registers( CHAIN, 0 ); + + ejctrl->in->data[JtagBrk] = 1; + chain_shift_data_registers( CHAIN, 0 ); + + ejctrl->in->data[JtagBrk] = 0; + chain_shift_data_registers( CHAIN, 1 ); + + if (! ejctrl->out->data[BrkSt]) { + printf( _("%s(%d) Failed to enter debug mode, ctrl=%s\n"), + __FILE__, __LINE__, + register_get_string( ejctrl->out ) ); + return; + } + + if (ejctrl->out->data[Rocc]) { + ejctrl->in->data[Rocc] = 0; + chain_shift_data_registers( CHAIN, 0 ); + ejctrl->in->data[Rocc] = 1; + chain_shift_data_registers( CHAIN, 1 ); + } + + ejtag_run_pracc( bus, code, 4 ); + BP->adr_hi = 0; + BP->initialized = 1; +} + +static void +ejtag_bus_prepare( bus_t *bus ) +{ + if (BP->initialized) + return; + + ejtag_bus_init( bus ); +} + +static int +ejtag_gen_read( uint32_t *code, uint32_t adr ) +{ + uint16_t adr_hi, adr_lo; + uint32_t *p = code; + + /* 16-bit signed offset, phys -> kseg1 */ + adr_lo = adr & 0xffff; + adr_hi = ((adr >> 16) & 0x1fff) + (adr_lo >> 15) + 0xa000; + + if (BP->adr_hi != adr_hi) { + BP->adr_hi = adr_hi; + *p++ = 0x3c030000 | adr_hi; // lui $3,adr_hi + } + switch (adr >> 29) { + case 0: + *p++ = 0x90620000 | adr_lo; // lbu $2,adr_lo($3) + break; + case 1: + *p++ = 0x94620000 | (adr_lo & ~1); // lhu $2,adr_lo($3) + break; + case 2: + *p++ = 0x8c620000 | (adr_lo & ~3); // lw $2,adr_lo($3) + break; + default: /* unknown bus width */ + *p++ = 0x00001025; // move $2,$0 + break; + } + *p++ = 0x03e00008; // jr $31 + return p - code; +} + +static void +ejtag_bus_read_start( bus_t *bus, uint32_t adr ) +{ + uint32_t code[3]; + + ejtag_run_pracc( bus, code, ejtag_gen_read( code, adr )); + // printf("bus_read_start: adr=0x%08x\n", adr); +} + +static uint32_t +ejtag_bus_read_next( bus_t *bus, uint32_t adr ) +{ + uint32_t d; + uint32_t code[4], *p = code; + + *p++ = 0xac820000; // sw $2,0($4) + p += ejtag_gen_read( p, adr ); + + d = ejtag_run_pracc( bus, code, p - code ); + + // printf("bus_read_next: adr=0x%08x data=0x%08x\n", adr, d); + return d; +} + +static uint32_t +ejtag_bus_read_end( bus_t *bus ) +{ + uint32_t d; + static const uint32_t code[2] = { + 0xac820000, // sw $2,0($4) + 0x03e00008 // jr $31 + }; + + d = ejtag_run_pracc( bus, code, 2 ); + + // printf("bus_read_end: data=0x%08x\n", d); + return d; +} + +static uint32_t +ejtag_bus_read( bus_t *bus, uint32_t adr ) +{ + ejtag_bus_read_start( bus, adr ); + return ejtag_bus_read_end( bus ); +} + +static void +ejtag_bus_write( bus_t *bus, uint32_t adr, uint32_t data ) +{ + uint16_t adr_hi, adr_lo; + uint32_t code[5], *p = code; + + /* 16-bit signed offset, phys -> kseg1 */ + adr_lo = adr & 0xffff; + adr_hi = ((adr >> 16) & 0x1fff) + (adr_lo >> 15) + 0xa000; + + if (BP->adr_hi != adr_hi) { + BP->adr_hi = adr_hi; + *p++ = 0x3c030000 | adr_hi; // lui $3,adr_hi + } + switch (adr >> 29) { + case 0: + *p++ = 0x34020000 | (data & 0xff); // li $2,data + *p++ = 0xa0620000 | adr_lo; // sb $2,adr_lo($3) + break; + case 1: + *p++ = 0x34020000 | (data & 0xffff); // li $2,data + *p++ = 0xa4620000 | (adr_lo & ~1); // sh $2,adr_lo($3) + break; + case 2: + *p++ = 0x3c020000 | (data >> 16); // lui $2,data_hi + *p++ = 0x34420000 | (data & 0xffff); // ori $2,data_lo + *p++ = 0xac620000 | (adr_lo & ~3); // sw $2,adr_lo($3) + break; + } + *p++ = 0x03e00008; // jr $31 + + ejtag_run_pracc( bus, code, p - code ); + + // printf("bus_write: adr=0x%08x data=0x%08x\n", adr, data); +} + +static int +ejtag_bus_area( bus_t *bus, uint32_t adr, bus_area_t *area ) +{ + if (adr < UINT32_C(0x20000000)) { + area->description = NULL; + area->start = UINT32_C(0x00000000); + area->length = UINT64_C(0x20000000); + area->width = 8; + } else if (adr < UINT32_C(0x40000000)) { + area->description = NULL; + area->start = UINT32_C(0x20000000); + area->length = UINT64_C(0x20000000); + area->width = 16; + } else if (adr < UINT32_C(0x60000000)) { + area->description = NULL; + area->start = UINT32_C(0x40000000); + area->length = UINT64_C(0x20000000); + area->width = 32; + } else { + area->description = NULL; + area->start = UINT32_C(0x60000000); + area->length = UINT64_C(0xa0000000); + area->width = 0; + } + return 0; +} + +static void +ejtag_bus_free( bus_t *bus ) +{ + free( bus->params ); + free( bus ); +} + +static bus_t *ejtag_bus_new( void ); + +const bus_driver_t ejtag_bus = { + "ejtag", + N_("EJTAG compatible bus driver via PrAcc"), + ejtag_bus_new, + ejtag_bus_free, + ejtag_bus_printinfo, + ejtag_bus_prepare, + ejtag_bus_area, + ejtag_bus_read_start, + ejtag_bus_read_next, + ejtag_bus_read_end, + ejtag_bus_read, + ejtag_bus_write +}; + +static bus_t * +ejtag_bus_new( void ) +{ + bus_t *bus; + + if (!chain || !chain->parts || chain->parts->len <= chain->active_part || chain->active_part < 0) + return NULL; + + bus = malloc( sizeof (bus_t) ); + if (!bus) + return NULL; + + bus->driver = &ejtag_bus; + bus->params = malloc( sizeof (bus_params_t) ); + if (!bus->params) { + free( bus ); + return NULL; + } + + CHAIN = chain; + PART = chain->parts->parts[chain->active_part]; + BP->initialized = 0; + + return bus; +} diff --git a/jtag/src/tap/parport/ppdev.c b/jtag/src/tap/parport/ppdev.c index 3eb91f76..5909c7f4 100644 --- a/jtag/src/tap/parport/ppdev.c +++ b/jtag/src/tap/parport/ppdev.c @@ -167,7 +167,7 @@ ppdev_open( parport_t *parport ) return -1; } - if ((ioctl( p->fd, PPEXCL ) == -1) || (ioctl( p->fd, PPCLAIM ) == -1)) { + if (/*(ioctl( p->fd, PPEXCL ) == -1) ||*/ (ioctl( p->fd, PPCLAIM ) == -1)) { printf( _("Could not claim ppdev device: %s\n"), strerror(errno) ); close( p->fd ); p->fd = -1;