diff --git a/jetson-nano-gpio.patch b/jetson-nano-gpio.patch deleted file mode 100644 index cf27638..0000000 --- a/jetson-nano-gpio.patch +++ /dev/null @@ -1,472 +0,0 @@ -diff --git a/CMakeLists.txt b/CMakeLists.txt -index b309fe0..7c6fbe7 100644 ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -216,9 +216,16 @@ if (ENABLE_LIBGPIOD) - message("libgpiod support enabled") - endif(ENABLE_LIBGPIOD) - --if (ENABLE_UDEV OR ENABLE_LIBGPIOD) -+if (ENABLE_JETSONNANOGPIO) -+ add_definitions(-DENABLE_JETSONNANOGPIO=1) -+ target_sources(openFPGALoader PRIVATE src/jetsonNanoJtagBitbang.cpp) -+ list (APPEND OPENFPGALOADER_HEADERS src/jetsonNanoJtagBitbang.hpp) -+ message("Jetson Nano GPIO support enabled") -+endif(ENABLE_JETSONNANOGPIO) -+ -+if (ENABLE_UDEV OR ENABLE_LIBGPIOD OR ENABLE_JETSONNANOGPIO) - add_definitions(-DUSE_DEVICE_ARG) --endif(ENABLE_UDEV OR ENABLE_LIBGPIOD) -+endif(ENABLE_UDEV OR ENABLE_LIBGPIOD OR ENABLE_JETSONNANOGPIO) - - if (BUILD_STATIC) - set_target_properties(openFPGALoader PROPERTIES LINK_SEARCH_END_STATIC 1) -diff --git a/doc/cable.yml b/doc/cable.yml -index 4f62953..019d1c8 100644 ---- a/doc/cable.yml -+++ b/doc/cable.yml -@@ -257,3 +257,9 @@ libgpiod: - - Name: Bitbang GPIO - Description: Bitbang GPIO pins on Linux host. - URL: https://github.com/brgl/libgpiod -+ -+jetson-nano-gpio: -+ -+ - Name: Bitbang GPIO -+ Description: Bitbang GPIO pins on Jetson Nano Linux host. Use /dev/mem to have a faster clock. -+ URL: https://github.com/jwatte/jetson-gpio-example -\ No newline at end of file -diff --git a/src/cable.hpp b/src/cable.hpp -index c383bda..878cba2 100644 ---- a/src/cable.hpp -+++ b/src/cable.hpp -@@ -26,6 +26,7 @@ enum communication_type { - MODE_DFU, /*! DFU based probe */ - MODE_XVC_CLIENT, /*! Xilinx Virtual Cable client */ - MODE_LIBGPIOD_BITBANG, /*! Bitbang gpio pins */ -+ MODE_JETSONNANO_BITBANG, /*! Bitbang gpio pins */ - }; - - typedef struct { -@@ -75,6 +76,9 @@ static std::map cable_list = { - #ifdef ENABLE_LIBGPIOD - {"libgpiod", {MODE_LIBGPIOD_BITBANG, {}}}, - #endif -+#ifdef ENABLE_JETSONNANOGPIO -+ {"jetson-nano-gpio", {MODE_JETSONNANO_BITBANG, {}}}, -+#endif - }; - - #endif -diff --git a/src/jetsonNanoJtagBitbang.cpp b/src/jetsonNanoJtagBitbang.cpp -new file mode 100644 -index 0000000..f16d8de ---- /dev/null -+++ b/src/jetsonNanoJtagBitbang.cpp -@@ -0,0 +1,269 @@ -+// SPDX-License-Identifier: Apache-2.0 -+/* -+ * Copyright (C) 2020-2022 Gwenhael Goavec-Merou -+ * Copyright (C) 2022 Jean Biemar -+ * -+ * Jetson nano bitbang driver added by Jean Biemar in 2022 -+ */ -+ -+#include "jetsonNanoJtagBitbang.hpp" -+ -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include "display.hpp" -+ -+#define DEBUG 1 -+ -+#ifdef DEBUG -+#define display(...) \ -+ do { \ -+ if (_verbose) fprintf(stdout, __VA_ARGS__); \ -+ }while(0) -+#else -+#define display(...) do {}while(0) -+#endif -+ -+/* Tegra X1 SoC Technical Reference Manual, version 1.3 -+ * -+ * See Chapter 9 "Multi-Purpose I/O Pins", section 9.13 "GPIO Registers" -+ * (table 32: GPIO Register Address Map) -+ * -+ * The GPIO hardware shares PinMux with up to 4 Special Function I/O per -+ * pin, and only one of those five functions (SFIO plus GPIO) can be routed to -+ * a pin at a time, using the PixMux. -+ * -+ * In turn, the PinMux outputs signals to Pads using Pad Control Groups. Pad -+ * control groups control things like "drive strength" and "slew rate," and -+ * need to be reset after deep sleep. Also, different pads have different -+ * voltage tolerance. Pads marked "CZ" can be configured to be 3.3V tolerant -+ * and driving; and pads marked "DD" can be 3.3V tolerant when in open-drain -+ * mode (only.) -+ * -+ * The CNF register selects GPIO or SFIO, so setting it to 1 forces the GPIO -+ * function. This is convenient for those who have a different pinmux at boot. -+ */ -+ -+#define GPIO_SET_BIT(REG, BIT) REG |= 1UL << BIT -+#define GPIO_CLEAR_BIT(REG, BIT) REG &= ~(1UL << BIT) -+ -+JetsonNanoJtagBitbang::JetsonNanoJtagBitbang( -+ const jtag_pins_conf_t *pin_conf, -+ const std::string &dev, __attribute__((unused)) uint32_t clkHZ, -+ uint8_t verbose) -+{ -+ uint32_t tms_port_reg, tck_port_reg, tdi_port_reg, tdo_port_reg; -+ -+ _verbose = verbose; -+ -+ _tck_pin = pin_conf->tck_pin; -+ _tms_pin = pin_conf->tms_pin; -+ _tdi_pin = pin_conf->tdi_pin; -+ _tdo_pin = pin_conf->tdo_pin; -+ -+ display("Jetson Nano jtag bitbang driver, tck_pin=%d, tms_pin=%d, tdi_pin=%d, tdo_pin=%d\n", -+ _tck_pin, _tms_pin, _tdi_pin, _tdo_pin); -+ -+ /* Validate pins */ -+ int pins[] = {_tck_pin, _tms_pin, _tdi_pin, _tdo_pin}; -+ for (uint32_t i = 0; i < sizeof(pins) / sizeof(pins[0]); i++) { -+ if (pins[i] < 0 || pins[i] >= 1000) { -+ display("Pin %d is outside of valid range\n", pins[i]); -+ throw std::runtime_error("A pin is outside of valid range\n"); -+ } -+ -+ for (uint32_t j = i + 1; j < sizeof(pins) / sizeof(pins[0]); j++) { -+ if (pins[i] == pins[j]) { -+ display("Two or more pins are assigned to the same pin number %d\n", pins[i]); -+ throw std::runtime_error("Two or more pins are assigned to the same pin number\n"); -+ } -+ } -+ } -+ -+ /* Get ports */ -+ tms_port_reg = GPIO_PORT_BASE + ((_tms_pin/8)/GPIO_PORT_SHORT_OFFSET_SIZE*GPIO_PORT_LARGE_OFFSET) + ((_tms_pin/8)%GPIO_PORT_SHORT_OFFSET_SIZE*GPIO_PORT_SHORT_OFFSET); -+ tck_port_reg = GPIO_PORT_BASE + ((_tck_pin/8)/GPIO_PORT_SHORT_OFFSET_SIZE*GPIO_PORT_LARGE_OFFSET) + ((_tck_pin/8)%GPIO_PORT_SHORT_OFFSET_SIZE*GPIO_PORT_SHORT_OFFSET); -+ tdi_port_reg = GPIO_PORT_BASE + ((_tdi_pin/8)/GPIO_PORT_SHORT_OFFSET_SIZE*GPIO_PORT_LARGE_OFFSET) + ((_tdi_pin/8)%GPIO_PORT_SHORT_OFFSET_SIZE*GPIO_PORT_SHORT_OFFSET); -+ tdo_port_reg = GPIO_PORT_BASE + ((_tdo_pin/8)/GPIO_PORT_SHORT_OFFSET_SIZE*GPIO_PORT_LARGE_OFFSET) + ((_tdo_pin/8)%GPIO_PORT_SHORT_OFFSET_SIZE*GPIO_PORT_SHORT_OFFSET); -+ -+ /* Get pin */ -+ _tms_pin %= 8; -+ _tck_pin %= 8; -+ _tdi_pin %= 8; -+ _tdo_pin %= 8; -+ -+ display("reg:pin details: TMS %x:%i, TCK %x:%i, TDI %x:%i, TDO %x:%i\n", tms_port_reg, _tms_pin, tck_port_reg, _tck_pin, tdi_port_reg, _tdi_pin, tdo_port_reg, _tdo_pin); -+ -+ _curr_tdi = 0; -+ _curr_tck = 0; -+ _curr_tms = 1; -+ -+ // FIXME: I'm unsure how this value should be set. -+ // Maybe experiment, or think through what it should be. -+ _clkHZ = 5000000; -+ -+ // read physical memory (needs root) -+ int fd = open("/dev/mem", O_RDWR | O_SYNC); -+ if (fd < 0) { -+ display("Can't open /dev/mem. Error %x\n", errno); -+ throw std::runtime_error("No access to /dev/mem\n"); -+ } -+ // map a particular physical address into our address space -+ int pagesize = getpagesize(); -+ int pagemask = pagesize-1; -+ -+ // This page will actually contain all the GPIO controllers, because they are co-located -+ void *base = mmap(0, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, ((tms_port_reg | tck_port_reg | tdi_port_reg | tdo_port_reg) & ~pagemask)); -+ if (base == NULL) { -+ display("mmap return error\n"); -+ throw std::runtime_error("mmap error\n"); -+ } -+ -+ _tms_port = (gpio_t volatile *)((char *)base + (tms_port_reg & pagemask)); -+ _tck_port = (gpio_t volatile *)((char *)base + (tck_port_reg & pagemask)); -+ _tdi_port = (gpio_t volatile *)((char *)base + (tdi_port_reg & pagemask)); -+ _tdo_port = (gpio_t volatile *)((char *)base + (tdo_port_reg & pagemask)); -+ -+ // for _tms_port : GPIO OUT -+ GPIO_SET_BIT(_tms_port->CNF, _tms_pin); -+ GPIO_SET_BIT(_tms_port->OE, _tms_pin); -+ GPIO_SET_BIT(_tms_port->OUT, _tms_pin); -+ -+ // for _tck_port : GPIO OUT -+ GPIO_SET_BIT(_tck_port->CNF, _tck_pin); -+ GPIO_SET_BIT(_tck_port->OE, _tck_pin); -+ GPIO_CLEAR_BIT(_tck_port->OUT, _tck_pin); -+ -+ // for _tdi_port : GPIO OUT -+ GPIO_SET_BIT(_tdi_port->CNF, _tdi_pin); -+ GPIO_SET_BIT(_tdi_port->OE, _tdi_pin); -+ GPIO_CLEAR_BIT(_tdi_port->OUT, _tdi_pin); -+ -+ // for _tdo_port : GPIO IN -+ GPIO_SET_BIT(_tdo_port->CNF, _tdo_pin); -+ GPIO_CLEAR_BIT(_tdo_port->OE , _tdo_pin); -+ GPIO_CLEAR_BIT(_tdo_port->IN, _tdo_pin); -+} -+ -+JetsonNanoJtagBitbang::~JetsonNanoJtagBitbang() -+{ -+ GPIO_CLEAR_BIT(_tms_port->OE, _tms_pin); -+ GPIO_CLEAR_BIT(_tck_port->OE, _tck_pin); -+ GPIO_CLEAR_BIT(_tdi_port->OE, _tdi_pin); -+ -+ GPIO_CLEAR_BIT(_tms_port->CNF, _tms_pin); -+ GPIO_CLEAR_BIT(_tck_port->CNF, _tck_pin); -+ GPIO_CLEAR_BIT(_tdi_port->CNF, _tdi_pin); -+ GPIO_CLEAR_BIT(_tdo_port->CNF, _tdo_pin); -+} -+ -+int JetsonNanoJtagBitbang::update_pins(int tck, int tms, int tdi) -+{ -+ if (tdi != _curr_tdi) { -+ if(tdi) -+ GPIO_SET_BIT(_tdi_port->OUT, _tdi_pin); -+ else -+ GPIO_CLEAR_BIT(_tdi_port->OUT, _tdi_pin); -+ } -+ -+ if (tms != _curr_tms) { -+ if(tms) -+ GPIO_SET_BIT(_tms_port->OUT, _tms_pin); -+ else -+ GPIO_CLEAR_BIT(_tms_port->OUT, _tms_pin); -+ } -+ -+ if (tck != _curr_tck) { -+ if(tck) -+ GPIO_SET_BIT(_tck_port->OUT, _tck_pin); -+ else -+ GPIO_CLEAR_BIT(_tck_port->OUT, _tck_pin); -+ } -+ -+ _curr_tdi = tdi; -+ _curr_tms = tms; -+ _curr_tck = tck; -+ -+ return 0; -+} -+ -+int JetsonNanoJtagBitbang::read_tdo() -+{ -+ return (_tdo_port->IN>>_tdo_pin) & 0x01; -+} -+ -+int JetsonNanoJtagBitbang::setClkFreq(__attribute__((unused)) uint32_t clkHZ) -+{ -+ // FIXME: The assumption is that calling the gpiod_line_set_value -+ // routine will limit the clock frequency to lower than what is specified. -+ // This needs to be verified, and possibly artificial delays should be added. -+ return 0; -+} -+ -+int JetsonNanoJtagBitbang::writeTMS(uint8_t *tms_buf, uint32_t len, -+ __attribute__((unused)) bool flush_buffer) -+{ -+ int tms; -+ -+ for (uint32_t i = 0; i < len; i++) { -+ tms = ((tms_buf[i >> 3] & (1 << (i & 7))) ? 1 : 0); -+ -+ update_pins(0, tms, 0); -+ update_pins(1, tms, 0); -+ } -+ -+ update_pins(0, tms, 0); -+ -+ return len; -+} -+ -+int JetsonNanoJtagBitbang::writeTDI(uint8_t *tx, uint8_t *rx, uint32_t len, bool end) -+{ -+ int tms = _curr_tms; -+ int tdi = _curr_tdi; -+ -+ if (rx) -+ memset(rx, 0, len / 8); -+ -+ for (uint32_t i = 0; i < len; i++) { -+ if (end && (i == len - 1)) -+ tms = 1; -+ -+ if (tx) -+ tdi = (tx[i >> 3] & (1 << (i & 7))) ? 1 : 0; -+ -+ update_pins(0, tms, tdi); -+ update_pins(1, tms, tdi); -+ -+ if (rx) { -+ if (read_tdo() > 0) -+ rx[i >> 3] |= 1 << (i & 7); -+ } -+ } -+ -+ update_pins(0, tms, tdi); -+ -+ return len; -+} -+ -+int JetsonNanoJtagBitbang::toggleClk(uint8_t tms, uint8_t tdi, uint32_t clk_len) -+{ -+ for (uint32_t i = 0; i < clk_len; i++) { -+ update_pins(0, tms, tdi); -+ update_pins(1, tms, tdi); -+ } -+ -+ update_pins(0, tms, tdi); -+ -+ return clk_len; -+} -diff --git a/src/jetsonNanoJtagBitbang.hpp b/src/jetsonNanoJtagBitbang.hpp -new file mode 100644 -index 0000000..8c1f443 ---- /dev/null -+++ b/src/jetsonNanoJtagBitbang.hpp -@@ -0,0 +1,105 @@ -+// SPDX-License-Identifier: Apache-2.0 -+/* -+ * Copyright (C) 2020-2022 Gwenhael Goavec-Merou -+ * Copyright (C) 2022 Jean Biemar -+ * -+ * Jetson nano bitbang driver added by Jean Biemar in 2022 -+ */ -+ -+#ifndef JETSONNANOBITBANG_H -+#define JETSONNANOBITBANG_H -+ -+#include -+ -+#include "board.hpp" -+#include "jtagInterface.hpp" -+ -+/* Tegra X1 SoC Technical Reference Manual, version 1.3 -+ * -+ * See Chapter 9 "Multi-Purpose I/O Pins", section 9.13 "GPIO Registers" -+ * (table 32: GPIO Register Address Map) -+ * -+ * The GPIO hardware shares PinMux with up to 4 Special Function I/O per -+ * pin, and only one of those five functions (SFIO plus GPIO) can be routed to -+ * a pin at a time, using the PixMux. -+ * -+ * In turn, the PinMux outputs signals to Pads using Pad Control Groups. Pad -+ * control groups control things like "drive strength" and "slew rate," and -+ * need to be reset after deep sleep. Also, different pads have different -+ * voltage tolerance. Pads marked "CZ" can be configured to be 3.3V tolerant -+ * and driving; and pads marked "DD" can be 3.3V tolerant when in open-drain -+ * mode (only.) -+ * -+ * The CNF register selects GPIO or SFIO, so setting it to 1 forces the GPIO -+ * function. This is convenient for those who have a different pinmux at boot. -+ */ -+#define GPIO_PORT_BASE 0x6000d000 // Port A -+#define GPIO_PORT_MAX 0x6000d708 // Port EE -+#define GPIO_PORT_SHORT_OFFSET_SIZE 4 -+#define GPIO_PORT_SHORT_OFFSET 0x00000004 -+#define GPIO_PORT_LARGE_OFFSET 0x00000100 -+ -+/*! -+ * \file JetsonNanoJtagBitbang.hpp -+ * \class JetsonNanoJtagBitbang -+ * \brief concrete class between jtag implementation and gpio bitbang -+ * \author Jean Biemar -+ */ -+ -+class JetsonNanoJtagBitbang : public JtagInterface { -+ public: -+ JetsonNanoJtagBitbang(const jtag_pins_conf_t *pin_conf, -+ const std::string &dev, uint32_t clkHZ, uint8_t verbose); -+ virtual ~JetsonNanoJtagBitbang(); -+ -+ int setClkFreq(uint32_t clkHZ) override; -+ int writeTMS(uint8_t *tms_buf, uint32_t len, bool flush_buffer) override; -+ int writeTDI(uint8_t *tx, uint8_t *rx, uint32_t len, bool end) override; -+ int toggleClk(uint8_t tms, uint8_t tdo, uint32_t clk_len) override; -+ -+ int get_buffer_size() override { return 0; } -+ bool isFull() override { return false; } -+ int flush() override { return 0; } -+ -+ private: -+ // layout based on the definitions above -+ // Each GPIO controller has four ports, each port controls 8 pins, each -+ // register is interleaved for the four ports, so -+ // REGX: port0, port1, port2, port3 -+ // REGY: port0, port1, port2, port3 -+ typedef struct { -+ uint32_t CNF; -+ uint32_t _padding1[3]; -+ uint32_t OE; -+ uint32_t _padding2[3]; -+ uint32_t OUT; -+ uint32_t _padding3[3]; -+ uint32_t IN; -+ uint32_t _padding4[3]; -+ uint32_t INT_STA; -+ uint32_t _padding5[3]; -+ uint32_t INT_ENB; -+ uint32_t _padding6[3]; -+ uint32_t INT_LVL; -+ uint32_t _padding7[3]; -+ uint32_t INT_CLR; -+ uint32_t _padding8[3]; -+ } gpio_t; -+ -+ int update_pins(int tck, int tms, int tdi); -+ int read_tdo(); -+ -+ bool _verbose; -+ -+ int _tck_pin; -+ int _tms_pin; -+ int _tdo_pin; -+ int _tdi_pin; -+ -+ gpio_t volatile *_tms_port, *_tck_port, *_tdo_port, *_tdi_port; -+ -+ int _curr_tms; -+ int _curr_tdi; -+ int _curr_tck; -+}; -+#endif -diff --git a/src/jtag.cpp b/src/jtag.cpp -index 4bd6f72..6e23ee6 100644 ---- a/src/jtag.cpp -+++ b/src/jtag.cpp -@@ -24,6 +24,9 @@ - #ifdef ENABLE_LIBGPIOD - #include "libgpiodJtagBitbang.hpp" - #endif -+#ifdef ENABLE_JETSONNANOGPIO -+#include "jetsonNanoJtagBitbang.hpp" -+#endif - #include "jlink.hpp" - #ifdef ENABLE_CMSISDAP - #include "cmsisDAP.hpp" -@@ -139,6 +142,11 @@ void Jtag::init_internal(cable_t &cable, const string &dev, const string &serial - case MODE_LIBGPIOD_BITBANG: - _jtag = new LibgpiodJtagBitbang(pin_conf, dev, clkHZ, _verbose); - break; -+#endif -+#ifdef ENABLE_JETSONNANOGPIO -+ case MODE_JETSONNANO_BITBANG: -+ _jtag = new JetsonNanoJtagBitbang(pin_conf, dev, clkHZ, _verbose); -+ break; - #endif - default: - std::cerr << "Jtag: unknown cable type" << std::endl;