This is an automated email from Gerrit.

Icenowy Zheng ([email protected]) just uploaded a new patch set to Gerrit, which 
you can find at http://openocd.zylin.com/4336

-- gerrit

commit 210bce86d4ac770a26b72697d24c8c1ac99f56ef
Author: Icenowy Zheng <[email protected]>
Date:   Sun Jan 14 02:42:33 2018 +0800

    sunxigpio: add new driver
    
    Multiple Allwinner ARM SoCs are cheap and popular, and have all similar
    design at GPIOs.
    
    Add a driver for the GPIO of it. A interface config file for Orange Pi
    PC board is also added as an example.
    
    Change-Id: Ia3044d6b5f51f227b23877202be5f3f2fd234840
    Signed-off-by: Icenowy Zheng <[email protected]>

diff --git a/configure.ac b/configure.ac
index 562ec5a..b8d5220 100644
--- a/configure.ac
+++ b/configure.ac
@@ -301,12 +301,16 @@ AS_CASE(["${host_cpu}"],
     AC_ARG_ENABLE([imx_gpio],
       AS_HELP_STRING([--enable-imx_gpio], [Enable building support for 
bitbanging on NXP IMX processors]),
       [build_imx_gpio=$enableval], [build_imx_gpio=no])
+    AC_ARG_ENABLE([sunxigpio],
+      AS_HELP_STRING([--enable-sunxigpio], [Enable building support for 
bitbanging on Allwinner SoCs.]),
+      [build_sunxigpio=$enableval], [build_sunxigpio=no])
   ],
   [
     build_ep93xx=no
     build_at91rm9200=no
     build_bcm2835gpio=no
     build_imx_gpio=no
+    build_sunxigpio=no
 ])
 
 AC_ARG_ENABLE([gw16012],
@@ -513,6 +517,13 @@ AS_IF([test "x$build_at91rm9200" = "xyes"], [
   AC_DEFINE([BUILD_AT91RM9200], [0], [0 if you don't want at91rm9200.])
 ])
 
+AS_IF([test "x$build_sunxigpio" = "xyes"], [
+  build_bitbang=yes
+  AC_DEFINE([BUILD_SUNXIGPIO], [1], [1 if you want sunxigpio.])
+], [
+  AC_DEFINE([BUILD_SUNXIGPIO], [0], [0 if you don't want sunxigpio.])
+])
+
 AS_IF([test "x$build_bcm2835gpio" = "xyes"], [
   build_bitbang=yes
   AC_DEFINE([BUILD_BCM2835GPIO], [1], [1 if you want bcm2835gpio.])
@@ -698,6 +709,7 @@ AM_CONDITIONAL([IOUTIL], [test "x$build_ioutil" = "xyes"])
 AM_CONDITIONAL([AT91RM9200], [test "x$build_at91rm9200" = "xyes"])
 AM_CONDITIONAL([BCM2835GPIO], [test "x$build_bcm2835gpio" = "xyes"])
 AM_CONDITIONAL([IMX_GPIO], [test "x$build_imx_gpio" = "xyes"])
+AM_CONDITIONAL([SUNXIGPIO], [test "x$build_sunxigpio" = "xyes"])
 AM_CONDITIONAL([BITBANG], [test "x$build_bitbang" = "xyes"])
 AM_CONDITIONAL([JTAG_VPI], [test "x$build_jtag_vpi" = "xyes" -o 
"x$build_jtag_vpi" = "xyes"])
 AM_CONDITIONAL([USB_BLASTER_DRIVER], [test "x$enable_usb_blaster" != "xno" -o 
"x$enable_usb_blaster_2" != "xno"])
diff --git a/src/jtag/drivers/Makefile.am b/src/jtag/drivers/Makefile.am
index 3e5974d..d019f75 100644
--- a/src/jtag/drivers/Makefile.am
+++ b/src/jtag/drivers/Makefile.am
@@ -158,6 +158,10 @@ if KITPROG
 DRIVERFILES += %D%/kitprog.c
 endif
 
+if SUNXIGPIO
+DRIVERFILES += %D%/sunxigpio.c
+endif
+
 DRIVERHEADERS = \
        %D%/bitbang.h \
        %D%/bitq.h \
diff --git a/src/jtag/drivers/sunxigpio.c b/src/jtag/drivers/sunxigpio.c
new file mode 100644
index 0000000..c84a1bc
--- /dev/null
+++ b/src/jtag/drivers/sunxigpio.c
@@ -0,0 +1,600 @@
+/***************************************************************************
+ *   Copyright (C) 2017 Icenowy Zheng <[email protected]>                    *
+ *                                                                         *
+ *   Based on bcm2835gpio.c (c) Creative Product Design and Paul Fertser   *
+ *   and RPi GPIO examples by Gert van Loo & Dom                           *
+ *                                                                         *
+ *   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, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <jtag/interface.h>
+#include "bitbang.h"
+
+#include <unistd.h>
+#include <sys/mman.h>
+
+static int sunxigpio_read(void);
+static void sunxigpio_write(int tck, int tms, int tdi);
+static void sunxigpio_reset(int trst, int srst);
+
+static int sunxi_swdio_read(void);
+static void sunxi_swdio_drive(bool is_output);
+
+static int sunxigpio_init(void);
+static int sunxigpio_quit(void);
+
+static struct bitbang_interface sunxigpio_bitbang = {
+       .read = sunxigpio_read,
+       .write = sunxigpio_write,
+       .reset = sunxigpio_reset,
+       .swdio_read = sunxi_swdio_read,
+       .swdio_drive = sunxi_swdio_drive,
+       .blink = NULL
+};
+
+static uint32_t pio_base = 0x01c20800;
+
+struct sunxi_gpio {
+       int num;
+       uint32_t function_offset;
+       uint32_t value_offset;
+       uint8_t function_bit;
+       uint8_t value_bit;
+};
+
+#define BIT(x)                 (1 << (x))
+#define GPIO_DIRECTION_INPUT   0
+#define GPIO_DIRECTION_OUTPUT  1
+
+/* GPIO structs for each signal. bit32 is valid (MSB is bit31) */
+static struct sunxi_gpio tck_gpio = { -1, 0, 0, 32, 32 };
+static struct sunxi_gpio tms_gpio = { -1, 0, 0, 32, 32 };
+static struct sunxi_gpio tdi_gpio = { -1, 0, 0, 32, 32 };
+static struct sunxi_gpio tdo_gpio = { -1, 0, 0, 32, 32 };
+static struct sunxi_gpio trst_gpio = { -1, 0, 0, 32, 32 };
+static struct sunxi_gpio srst_gpio = { -1, 0, 0, 32, 32 };
+static struct sunxi_gpio swclk_gpio = { -1, 0, 0, 32, 32 };
+static struct sunxi_gpio swdio_gpio = { -1, 0, 0, 32, 32 };
+
+static uint32_t (*gpio_readl)(uint32_t addr);
+static void (*gpio_writel)(uint32_t val, uint32_t addr);
+
+static bool sunxi_is_gpio_num_valid(int gpio_num)
+{
+       return gpio_num >= 0 && gpio_num <= 287; /* from PA0 to PI31 */
+}
+
+static void sunxi_num_to_gpio(int gpio_num, struct sunxi_gpio *gpio)
+{
+       int bank = gpio_num / 32, pin = gpio_num % 32;
+
+       gpio->num = gpio_num;
+       gpio->value_offset = 0x24 * bank + 0x10;
+       gpio->value_bit = pin;
+       gpio->function_offset = 0x24 * bank;
+       while (pin >= 8) {
+               gpio->function_offset += 4;
+               pin -= 8;
+       }
+       gpio->function_bit = pin * 4;
+}
+
+#define SUNXI_GPIO_PIN_NAME_LEN 5 /* PXxx\0 */
+static void sunxi_gpio_num_get_name(int gpio_num, char *name)
+{
+       int bank = gpio_num / 32, pin = gpio_num % 32;
+       name[0] = 'P';
+       name[1] = 'A' + bank;
+       name[2] = '0' + pin / 10;
+       name[3] = '0' + pin % 10;
+       name[4] = '\0';
+}
+
+static void sunxi_gpio_get_name(struct sunxi_gpio *gpio, char *name)
+{
+       sunxi_gpio_num_get_name(gpio->num, name);
+}
+
+static bool sunxi_gpio_is_valid(struct sunxi_gpio *gpio)
+{
+       return !(gpio->value_bit == 32 || gpio->function_bit == 32);
+}
+
+static int sunxi_read_gpio(struct sunxi_gpio *gpio)
+{
+       return !!(gpio_readl(gpio->value_offset) & BIT(gpio->value_bit));
+}
+
+static void sunxi_write_gpio(struct sunxi_gpio *gpio, int val)
+{
+       uint32_t reg = gpio_readl(gpio->value_offset);
+
+       if (val)
+               reg |= BIT(gpio->value_bit);
+       else
+               reg &= ~BIT(gpio->value_bit);
+
+       gpio_writel(reg, gpio->value_offset);
+}
+
+static void sunxi_gpio_direction(struct sunxi_gpio *gpio, int dir)
+{
+       if (dir != GPIO_DIRECTION_INPUT && dir != GPIO_DIRECTION_OUTPUT)
+               return;
+
+       uint32_t val = gpio_readl(gpio->function_offset);
+       val &= ~(0xf << gpio->function_bit);
+       val |= (dir << gpio->function_bit);
+       gpio_writel(val, gpio->function_offset);
+}
+
+static int dev_mem_fd;
+static volatile uint32_t *pio_mmap_base;
+
+static uint32_t sunxi_gpio_readl(uint32_t addr)
+{
+       uint32_t val = *(pio_mmap_base + addr / sizeof(*pio_mmap_base));
+       return val;
+}
+
+static void sunxi_gpio_writel(uint32_t val, uint32_t addr)
+{
+       *(pio_mmap_base + addr / sizeof(*pio_mmap_base)) = val;
+}
+
+static int sunxigpio_read(void)
+{
+       return sunxi_read_gpio(&tdo_gpio);
+}
+
+static void sunxigpio_write(int tck, int tms, int tdi)
+{
+       sunxi_write_gpio(&tck_gpio, tck);
+       sunxi_write_gpio(&tms_gpio, tms);
+       sunxi_write_gpio(&tdi_gpio, tdi);
+}
+
+static void sunxigpio_swd_write(int tck, int tms, int tdi)
+{
+       sunxi_write_gpio(&swclk_gpio, tck);
+       sunxi_write_gpio(&swdio_gpio, tdi);
+}
+
+/* (1) assert or (0) deassert reset lines */
+static void sunxigpio_reset(int trst, int srst)
+{
+       if (sunxi_gpio_is_valid(&trst_gpio))
+               sunxi_write_gpio(&trst_gpio, trst);
+
+       if (sunxi_gpio_is_valid(&srst_gpio))
+               sunxi_write_gpio(&srst_gpio, srst);
+}
+
+static void sunxi_swdio_drive(bool is_output)
+{
+       if (is_output)
+               sunxi_gpio_direction(&swdio_gpio, GPIO_DIRECTION_OUTPUT);
+       else
+               sunxi_gpio_direction(&swdio_gpio, GPIO_DIRECTION_INPUT);
+}
+
+static int sunxi_swdio_read(void)
+{
+       return sunxi_read_gpio(&swdio_gpio);
+}
+
+COMMAND_HANDLER(sunxigpio_handle_jtag_gpionums)
+{
+       int num;
+       char name[SUNXI_GPIO_PIN_NAME_LEN];
+       if (CMD_ARGC == 4) {
+               COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], num);
+               if (sunxi_is_gpio_num_valid(num))
+                       sunxi_num_to_gpio(num, &tck_gpio);
+               COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], num);
+               if (sunxi_is_gpio_num_valid(num))
+                       sunxi_num_to_gpio(num, &tms_gpio);
+               COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], num);
+               if (sunxi_is_gpio_num_valid(num))
+                       sunxi_num_to_gpio(num, &tdi_gpio);
+               COMMAND_PARSE_NUMBER(int, CMD_ARGV[3], num);
+               if (sunxi_is_gpio_num_valid(num))
+                       sunxi_num_to_gpio(num, &tdo_gpio);
+       } else if (CMD_ARGC != 0) {
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       command_print(CMD_CTX, "Allwinner GPIO config: ");
+       sunxi_gpio_get_name(&tck_gpio, name);
+       command_print(CMD_CTX, "tck = %s, ", name);
+       sunxi_gpio_get_name(&tms_gpio, name);
+       command_print(CMD_CTX, "tms = %s, ", name);
+       sunxi_gpio_get_name(&tdi_gpio, name);
+       command_print(CMD_CTX, "tdi = %s, ", name);
+       sunxi_gpio_get_name(&tdo_gpio, name);
+       command_print(CMD_CTX, "tdo = %s", name);
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(sunxigpio_handle_jtag_gpionum_tck)
+{
+       int num;
+       char name[SUNXI_GPIO_PIN_NAME_LEN];
+
+       if (CMD_ARGC == 1) {
+               COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], num);
+               if (sunxi_is_gpio_num_valid(num))
+                       sunxi_num_to_gpio(num, &tck_gpio);
+       }
+
+       command_print(CMD_CTX, "Allwinner GPIO config: ");
+       sunxi_gpio_get_name(&tck_gpio, name);
+       command_print(CMD_CTX, "tck = %s", name);
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(sunxigpio_handle_jtag_gpionum_tms)
+{
+       int num;
+       char name[SUNXI_GPIO_PIN_NAME_LEN];
+
+       if (CMD_ARGC == 1) {
+               COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], num);
+               if (sunxi_is_gpio_num_valid(num))
+                       sunxi_num_to_gpio(num, &tms_gpio);
+       }
+
+       command_print(CMD_CTX, "Allwinner GPIO config: ");
+       sunxi_gpio_get_name(&tms_gpio, name);
+       command_print(CMD_CTX, "tms = %s", name);
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(sunxigpio_handle_jtag_gpionum_tdo)
+{
+       int num;
+       char name[SUNXI_GPIO_PIN_NAME_LEN];
+
+       if (CMD_ARGC == 1) {
+               COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], num);
+               if (sunxi_is_gpio_num_valid(num))
+                       sunxi_num_to_gpio(num, &tdo_gpio);
+       }
+
+       command_print(CMD_CTX, "Allwinner GPIO config: ");
+       sunxi_gpio_get_name(&tdo_gpio, name);
+       command_print(CMD_CTX, "tdo = %s", name);
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(sunxigpio_handle_jtag_gpionum_tdi)
+{
+       int num;
+       char name[SUNXI_GPIO_PIN_NAME_LEN];
+
+       if (CMD_ARGC == 1) {
+               COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], num);
+               if (sunxi_is_gpio_num_valid(num))
+                       sunxi_num_to_gpio(num, &tdi_gpio);
+       }
+
+       command_print(CMD_CTX, "Allwinner GPIO config: ");
+       sunxi_gpio_get_name(&tdi_gpio, name);
+       command_print(CMD_CTX, "tdi = %s", name);
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(sunxigpio_handle_jtag_gpionum_srst)
+{
+       int num;
+       char name[SUNXI_GPIO_PIN_NAME_LEN];
+
+       if (CMD_ARGC == 1) {
+               COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], num);
+               if (sunxi_is_gpio_num_valid(num))
+                       sunxi_num_to_gpio(num, &srst_gpio);
+       }
+
+       command_print(CMD_CTX, "Allwinner GPIO config: ");
+       sunxi_gpio_get_name(&srst_gpio, name);
+       command_print(CMD_CTX, "srst = %s", name);
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(sunxigpio_handle_jtag_gpionum_trst)
+{
+       int num;
+       char name[SUNXI_GPIO_PIN_NAME_LEN];
+
+       if (CMD_ARGC == 1) {
+               COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], num);
+               if (sunxi_is_gpio_num_valid(num))
+                       sunxi_num_to_gpio(num, &trst_gpio);
+       }
+
+       command_print(CMD_CTX, "Allwinner GPIO config: ");
+       sunxi_gpio_get_name(&trst_gpio, name);
+       command_print(CMD_CTX, "trst = %s", name);
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(sunxigpio_handle_swd_gpionums)
+{
+       int num;
+       char name[SUNXI_GPIO_PIN_NAME_LEN];
+       if (CMD_ARGC == 2) {
+               COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], num);
+               if (sunxi_is_gpio_num_valid(num))
+                       sunxi_num_to_gpio(num, &swclk_gpio);
+               COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], num);
+               if (sunxi_is_gpio_num_valid(num))
+                       sunxi_num_to_gpio(num, &swdio_gpio);
+       } else if (CMD_ARGC != 0) {
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       command_print(CMD_CTX, "Allwinner GPIO config: ");
+       sunxi_gpio_get_name(&swclk_gpio, name);
+       command_print(CMD_CTX, "swclk = %s, ", name);
+       sunxi_gpio_get_name(&swdio_gpio, name);
+       command_print(CMD_CTX, "swdio = %s", name);
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(sunxigpio_handle_swd_gpionum_swclk)
+{
+       int num;
+       char name[SUNXI_GPIO_PIN_NAME_LEN];
+
+       if (CMD_ARGC == 1) {
+               COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], num);
+               if (sunxi_is_gpio_num_valid(num))
+                       sunxi_num_to_gpio(num, &swclk_gpio);
+       }
+
+       command_print(CMD_CTX, "Allwinner GPIO config: ");
+       sunxi_gpio_get_name(&swclk_gpio, name);
+       command_print(CMD_CTX, "swclk = %s", name);
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(sunxigpio_handle_swd_gpionum_swdio)
+{
+       int num;
+       char name[SUNXI_GPIO_PIN_NAME_LEN];
+
+       if (CMD_ARGC == 1) {
+               COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], num);
+               if (sunxi_is_gpio_num_valid(num))
+                       sunxi_num_to_gpio(num, &swdio_gpio);
+       }
+
+       command_print(CMD_CTX, "Allwinner GPIO config: ");
+       sunxi_gpio_get_name(&swdio_gpio, name);
+       command_print(CMD_CTX, "swdio = %s", name);
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(sunxigpio_handle_pio_base)
+{
+       if (CMD_ARGC == 1)
+               COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], pio_base);
+       return ERROR_OK;
+}
+
+static const struct command_registration sunxigpio_command_handlers[] = {
+       {
+               .name = "sunxigpio_jtag_nums",
+               .handler = &sunxigpio_handle_jtag_gpionums,
+               .mode = COMMAND_CONFIG,
+               .help = "gpio numbers for tck, tms, tdi, tdo. (in that order)",
+               .usage = "(tck tms tdi tdo)* ",
+       },
+       {
+               .name = "sunxigpio_tck_num",
+               .handler = &sunxigpio_handle_jtag_gpionum_tck,
+               .mode = COMMAND_CONFIG,
+               .help = "gpio number for tck.",
+       },
+       {
+               .name = "sunxigpio_tms_num",
+               .handler = &sunxigpio_handle_jtag_gpionum_tms,
+               .mode = COMMAND_CONFIG,
+               .help = "gpio number for tms.",
+       },
+       {
+               .name = "sunxigpio_tdo_num",
+               .handler = &sunxigpio_handle_jtag_gpionum_tdo,
+               .mode = COMMAND_CONFIG,
+               .help = "gpio number for tdo.",
+       },
+       {
+               .name = "sunxigpio_tdi_num",
+               .handler = &sunxigpio_handle_jtag_gpionum_tdi,
+               .mode = COMMAND_CONFIG,
+               .help = "gpio number for tdi.",
+       },
+       {
+               .name = "sunxigpio_swd_nums",
+               .handler = &sunxigpio_handle_swd_gpionums,
+               .mode = COMMAND_CONFIG,
+               .help = "gpio numbers for swclk, swdio. (in that order)",
+               .usage = "(swclk swdio)* ",
+       },
+       {
+               .name = "sunxigpio_swclk_num",
+               .handler = &sunxigpio_handle_swd_gpionum_swclk,
+               .mode = COMMAND_CONFIG,
+               .help = "gpio number for swclk.",
+       },
+       {
+               .name = "sunxigpio_swdio_num",
+               .handler = &sunxigpio_handle_swd_gpionum_swdio,
+               .mode = COMMAND_CONFIG,
+               .help = "gpio number for swdio.",
+       },
+       {
+               .name = "sunxigpio_srst_num",
+               .handler = &sunxigpio_handle_jtag_gpionum_srst,
+               .mode = COMMAND_CONFIG,
+               .help = "gpio number for srst.",
+       },
+       {
+               .name = "sunxigpio_trst_num",
+               .handler = &sunxigpio_handle_jtag_gpionum_trst,
+               .mode = COMMAND_CONFIG,
+               .help = "gpio number for trst.",
+       },
+       {
+               .name = "sunxigpio_pio_base",
+               .handler = &sunxigpio_handle_pio_base,
+               .mode = COMMAND_CONFIG,
+               .help = "Pin controller base (0x01c28000 except A80 and H6).",
+       },
+
+       COMMAND_REGISTRATION_DONE
+};
+
+static const char * const sunxi_transports[] = { "jtag", "swd", NULL };
+
+struct jtag_interface sunxigpio_interface = {
+       .name = "sunxigpio",
+       .supported = DEBUG_CAP_TMS_SEQ,
+       .execute_queue = bitbang_execute_queue,
+       .transports = sunxi_transports,
+       .swd = &bitbang_swd,
+       .commands = sunxigpio_command_handlers,
+       .init = sunxigpio_init,
+       .quit = sunxigpio_quit,
+};
+
+static bool sunxigpio_jtag_mode_possible(void)
+{
+       if (!sunxi_gpio_is_valid(&tck_gpio))
+               return 0;
+       if (!sunxi_gpio_is_valid(&tms_gpio))
+               return 0;
+       if (!sunxi_gpio_is_valid(&tdi_gpio))
+               return 0;
+       if (!sunxi_gpio_is_valid(&tdo_gpio))
+               return 0;
+       return 1;
+}
+
+static bool sunxigpio_swd_mode_possible(void)
+{
+       if (!sunxi_gpio_is_valid(&swclk_gpio))
+               return 0;
+       if (!sunxi_gpio_is_valid(&swdio_gpio))
+               return 0;
+       return 1;
+}
+
+static int sunxigpio_init(void)
+{
+       bitbang_interface = &sunxigpio_bitbang;
+       gpio_readl = sunxi_gpio_readl;
+       gpio_writel = sunxi_gpio_writel;
+
+       LOG_INFO("Allwinner GPIO JTAG/SWD bitbang driver via /dev/mem");
+
+       if (sunxigpio_jtag_mode_possible()) {
+               if (sunxigpio_swd_mode_possible())
+                       LOG_INFO("JTAG and SWD modes enabled");
+               else
+                       LOG_INFO("JTAG only mode enabled (specify swclk and 
swdio gpio to add SWD mode)");
+               if (!sunxi_gpio_is_valid(&trst_gpio) && 
!sunxi_gpio_is_valid(&srst_gpio)) {
+                       LOG_ERROR("Require at least one of trst or srst gpios 
to be specified");
+                       return ERROR_JTAG_INIT_FAILED;
+               }
+       } else if (sunxigpio_swd_mode_possible()) {
+               LOG_INFO("SWD only mode enabled (specify tck, tms, tdi and tdo 
gpios to add JTAG mode)");
+       } else {
+               LOG_ERROR("Require tck, tms, tdi and tdo gpios for JTAG mode 
and/or swclk and swdio gpio for SWD mode");
+               return ERROR_JTAG_INIT_FAILED;
+       }
+
+       dev_mem_fd = open("/dev/mem", O_RDWR | O_SYNC);
+       if (dev_mem_fd < 0) {
+               perror("open");
+               return ERROR_JTAG_INIT_FAILED;
+       }
+
+       size_t pagesize = getpagesize();
+       uint32_t pio_page = pio_base & (~(pagesize-1));
+       uint32_t pio_offset_inpage = pio_base - pio_page;
+
+       uint32_t *pio_page_mmap_base;
+       pio_page_mmap_base = mmap(NULL, sysconf(_SC_PAGE_SIZE),
+                                 PROT_READ | PROT_WRITE,
+                                 MAP_SHARED, dev_mem_fd, pio_page);
+
+       if (pio_page_mmap_base == MAP_FAILED) {
+               perror("mmap");
+               close(dev_mem_fd);
+               return ERROR_JTAG_INIT_FAILED;
+       }
+
+       pio_mmap_base = pio_page_mmap_base +
+                       pio_offset_inpage / sizeof(*pio_page_mmap_base);
+
+       /*
+        * Configure TDO as an input, and TDI, TCK, TMS, TRST, SRST
+        * as outputs.  Drive TDI and TCK low, and TMS/TRST/SRST high.
+        */
+       if (sunxigpio_jtag_mode_possible()) {
+               sunxi_gpio_direction(&tdo_gpio, GPIO_DIRECTION_INPUT);
+               sunxi_gpio_direction(&tdi_gpio, GPIO_DIRECTION_OUTPUT);
+               sunxi_write_gpio(&tdi_gpio, 0);
+               sunxi_gpio_direction(&tck_gpio, GPIO_DIRECTION_OUTPUT);
+               sunxi_write_gpio(&tck_gpio, 0);
+               sunxi_gpio_direction(&tms_gpio, GPIO_DIRECTION_OUTPUT);
+               sunxi_write_gpio(&tms_gpio, 1);
+       }
+
+       if (sunxigpio_swd_mode_possible()) {
+               sunxi_gpio_direction(&swclk_gpio, GPIO_DIRECTION_OUTPUT);
+               sunxi_write_gpio(&swclk_gpio, 0);
+               sunxi_gpio_direction(&swdio_gpio, GPIO_DIRECTION_OUTPUT);
+               sunxi_write_gpio(&swdio_gpio, 0);
+       }
+
+       if (sunxi_gpio_is_valid(&trst_gpio)) {
+               sunxi_gpio_direction(&trst_gpio, GPIO_DIRECTION_OUTPUT);
+               sunxi_write_gpio(&trst_gpio, 1);
+       }
+
+       if (sunxi_gpio_is_valid(&srst_gpio)) {
+               sunxi_gpio_direction(&srst_gpio, GPIO_DIRECTION_OUTPUT);
+               sunxi_write_gpio(&srst_gpio, 1);
+       }
+
+       if (swd_mode) {
+               sunxigpio_bitbang.write = sunxigpio_swd_write;
+               bitbang_switch_to_swd();
+       }
+
+       return ERROR_OK;
+}
+
+static int sunxigpio_quit(void)
+{
+       return ERROR_OK;
+}
diff --git a/src/jtag/interfaces.c b/src/jtag/interfaces.c
index 174c63a..729151a 100644
--- a/src/jtag/interfaces.c
+++ b/src/jtag/interfaces.c
@@ -120,6 +120,9 @@ extern struct jtag_interface aice_interface;
 #if BUILD_BCM2835GPIO == 1
 extern struct jtag_interface bcm2835gpio_interface;
 #endif
+#if BUILD_SUNXIGPIO == 1
+extern struct jtag_interface sunxigpio_interface;
+#endif
 #if BUILD_CMSIS_DAP == 1
 extern struct jtag_interface cmsis_dap_interface;
 #endif
@@ -219,6 +222,9 @@ struct jtag_interface *jtag_interfaces[] = {
 #if BUILD_BCM2835GPIO == 1
                &bcm2835gpio_interface,
 #endif
+#if BUILD_SUNXIGPIO == 1
+               &sunxigpio_interface,
+#endif
 #if BUILD_CMSIS_DAP == 1
                &cmsis_dap_interface,
 #endif
diff --git a/tcl/interface/sunxigpio-opipc.cfg 
b/tcl/interface/sunxigpio-opipc.cfg
new file mode 100644
index 0000000..202fb56
--- /dev/null
+++ b/tcl/interface/sunxigpio-opipc.cfg
@@ -0,0 +1,29 @@
+#
+# Config for using Orange Pi PC's expansion header
+#
+# This is best used with a fast enough buffer but also
+# is suitable for direct connection if the target voltage
+# matches RPi's 3.3V and the cable is short enough.
+#
+# Do not forget the GND connection, pin 6 of the expansion header.
+#
+
+interface sunxigpio
+
+sunxigpio_pio_base 0x01c20800
+
+# Each of the JTAG lines need a gpio number set: tck tms tdi tdo
+# Header pin numbers: 29 35 31 33
+sunxigpio_jtag_nums 7 10 8 9
+
+# If you define trst or srst, use appropriate reset_config
+# Header pin numbers: TRST - 37, SRST - 27
+
+sunxigpio_trst_num 20
+reset_config trst_only
+
+# sunxigpio_srst_num 19
+# reset_config srst_only srst_push_pull
+
+# or if you have both connected,
+# reset_config trst_and_srst srst_push_pull

-- 

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
OpenOCD-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/openocd-devel

Reply via email to