From 86143ecca349c8026eec71e4b4ef3b9df8fb5a60 Mon Sep 17 00:00:00 2001 From: "Jes B. Klinke" Date: Tue, 23 Jan 2024 10:00:30 -0800 Subject: [PATCH] [opentitantool] Allow changing of JTAG pins HyperDebug by default does JTAG on five particular pins. However, as it is all bit-banging with no true hardware support, it is able to use almost any combination of pins. This PR introduces a transport-specific command to "move" the JTAG functionality to a different set of pins. Usage: `opentitantool --interface=hyperdebug transport set-jtag-pins ` Signed-off-by: Jes B. Klinke Change-Id: Ibf61be39949b6330f4dd1ec01c44bbdc5cc2350c --- .../src/transport/hyperdebug/mod.rs | 29 ++++++++++++++- sw/host/opentitanlib/src/transport/mod.rs | 9 +++++ .../opentitantool/src/command/transport.rs | 37 +++++++++++++++++++ 3 files changed, 74 insertions(+), 1 deletion(-) diff --git a/sw/host/opentitanlib/src/transport/hyperdebug/mod.rs b/sw/host/opentitanlib/src/transport/hyperdebug/mod.rs index 763c1f7318c0e..fa6572ba1ca78 100644 --- a/sw/host/opentitanlib/src/transport/hyperdebug/mod.rs +++ b/sw/host/opentitanlib/src/transport/hyperdebug/mod.rs @@ -29,7 +29,8 @@ use crate::transport::chip_whisperer::ChipWhisperer; use crate::transport::common::fpga::{ClearBitstream, FpgaProgram}; use crate::transport::common::uart::{flock_serial, SerialPortExclusiveLock, SerialPortUart}; use crate::transport::{ - Capabilities, Capability, Transport, TransportError, TransportInterfaceType, UpdateFirmware, + Capabilities, Capability, SetJtagPins, Transport, TransportError, TransportInterfaceType, + UpdateFirmware, }; use crate::util::openocd::OpenOcdJtagChain; use crate::util::usb::UsbBackend; @@ -632,6 +633,32 @@ impl Transport for Hyperdebug { update_firmware_action.progress.as_ref(), update_firmware_action.force, ) + } else if let Some(jtag_set_pins) = action.downcast_ref::() { + match ( + &jtag_set_pins.tclk, + &jtag_set_pins.tms, + &jtag_set_pins.tdi, + &jtag_set_pins.tdo, + &jtag_set_pins.trst, + ) { + (Some(tclk), Some(tms), Some(tdi), Some(tdo), Some(trst)) => { + self.inner.cmd_no_output(&format!( + "jtag set-pins {} {} {} {} {}", + tclk.get_internal_pin_name() + .ok_or(TransportError::InvalidOperation)?, + tms.get_internal_pin_name() + .ok_or(TransportError::InvalidOperation)?, + tdi.get_internal_pin_name() + .ok_or(TransportError::InvalidOperation)?, + tdo.get_internal_pin_name() + .ok_or(TransportError::InvalidOperation)?, + trst.get_internal_pin_name() + .ok_or(TransportError::InvalidOperation)?, + ))?; + Ok(None) + } + _ => Err(TransportError::UnsupportedOperation.into()), + } } else if let Some(fpga_program) = action.downcast_ref::() { T::load_bitstream(fpga_program).map(|_| None) } else if let Some(clear) = action.downcast_ref::() { diff --git a/sw/host/opentitanlib/src/transport/mod.rs b/sw/host/opentitanlib/src/transport/mod.rs index 8caf1e887647a..f7455ee51f93f 100644 --- a/sw/host/opentitanlib/src/transport/mod.rs +++ b/sw/host/opentitanlib/src/transport/mod.rs @@ -183,6 +183,15 @@ pub struct Bootstrap { pub image_path: PathBuf, } +/// Some transports allow dynamically changing which pins are used for JTAG. +pub struct SetJtagPins { + pub tclk: Option>, + pub tms: Option>, + pub tdi: Option>, + pub tdo: Option>, + pub trst: Option>, +} + pub trait ProgressIndicator { // Begins a new stage, indicating "size" of this stage in bytes. `name` can be the empty // string, for instance if the operation has only a single stage. diff --git a/sw/host/opentitantool/src/command/transport.rs b/sw/host/opentitantool/src/command/transport.rs index 573a4d6544288..e7a5eb95e3681 100644 --- a/sw/host/opentitantool/src/command/transport.rs +++ b/sw/host/opentitantool/src/command/transport.rs @@ -14,7 +14,10 @@ use std::time::Duration; use opentitanlib::app::command::CommandDispatch; use opentitanlib::app::{StagedProgressBar, TransportWrapper}; +use opentitanlib::io::jtag::JtagParams; use opentitanlib::transport::verilator::transport::Watch; +use opentitanlib::transport::Capability; +use opentitanlib::transport::SetJtagPins; use opentitanlib::transport::UpdateFirmware; /// Initialize state of a transport debugger device to fit the device under test. This @@ -41,6 +44,39 @@ impl CommandDispatch for TransportInit { } } +#[derive(Debug, Args)] +pub struct TransportSetJtagPins { + #[command(flatten)] + pub jtag_params: JtagParams, + + pub tclk: String, + pub tms: String, + pub tdi: String, + pub tdo: String, + pub trst: String, +} + +impl CommandDispatch for TransportSetJtagPins { + fn run( + &self, + _context: &dyn Any, + transport: &TransportWrapper, + ) -> Result>> { + transport + .capabilities()? + .request(Capability::GPIO | Capability::JTAG) + .ok()?; + + transport.dispatch(&SetJtagPins { + tclk: Some(transport.gpio_pin(&self.tclk)?), + tms: Some(transport.gpio_pin(&self.tms)?), + tdi: Some(transport.gpio_pin(&self.tdi)?), + tdo: Some(transport.gpio_pin(&self.tdo)?), + trst: Some(transport.gpio_pin(&self.trst)?), + }) + } +} + /// Updates the firmware of the debugger/transport. If no argument is given, a suitable /// "official" firmware will be used, if one such was compiled into the OpenTitanTool binary. For /// instructions on how to build HyperDebug firmware locally, see @@ -144,6 +180,7 @@ impl CommandDispatch for TransportQueryAll { #[derive(Debug, Subcommand, CommandDispatch)] pub enum TransportCommand { Init(TransportInit), + SetJtagPins(TransportSetJtagPins), VerilatorWatch(VerilatorWatch), UpdateFirmware(TransportUpdateFirmware), Query(TransportQuery),