X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=src%2Fjtag%2Fdrivers%2Fbcm2835gpio.c;h=0bbbc6fced2f5d75f80d0f9b12697a4f92d3e0b9;hb=e643a494d46c571711ccba361ad20faaf6f6503c;hp=38ef163fab53fdf0da378491bce801769b89d1a2;hpb=64f1f7b1c179dcce4e008bef6bf9515c47ae4100;p=fw%2Fopenocd diff --git a/src/jtag/drivers/bcm2835gpio.c b/src/jtag/drivers/bcm2835gpio.c index 38ef163fa..0bbbc6fce 100644 --- a/src/jtag/drivers/bcm2835gpio.c +++ b/src/jtag/drivers/bcm2835gpio.c @@ -1,22 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2013 by Paul Fertser, fercerpav@gmail.com * * * * Copyright (C) 2012 by Creative Product Design, marc @ cpdesign.com.au * * Based on at91rm9200.c (c) Anders Larsen * * 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 . * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -24,6 +13,7 @@ #endif #include +#include #include "bitbang.h" #include @@ -47,14 +37,15 @@ uint32_t bcm2835_peri_base = 0x20000000; #define GPIO_LEV (*(pio_base+13)) /* current level of the pin */ static int dev_mem_fd; -static volatile uint32_t *pio_base; +static volatile uint32_t *pio_base = MAP_FAILED; +static volatile uint32_t *pads_base = MAP_FAILED; static bb_value_t bcm2835gpio_read(void); static int bcm2835gpio_write(int tck, int tms, int tdi); -static int bcm2835gpio_reset(int trst, int srst); static int bcm2835_swdio_read(void); static void bcm2835_swdio_drive(bool is_output); +static int bcm2835gpio_swd_write(int swclk, int swdio); static int bcm2835gpio_init(void); static int bcm2835gpio_quit(void); @@ -62,9 +53,9 @@ static int bcm2835gpio_quit(void); static struct bitbang_interface bcm2835gpio_bitbang = { .read = bcm2835gpio_read, .write = bcm2835gpio_write, - .reset = bcm2835gpio_reset, .swdio_read = bcm2835_swdio_read, .swdio_drive = bcm2835_swdio_drive, + .swd_write = bcm2835gpio_swd_write, .blink = NULL }; @@ -85,12 +76,19 @@ static int swclk_gpio = -1; static int swclk_gpio_mode; static int swdio_gpio = -1; static int swdio_gpio_mode; +static int swdio_dir_gpio = -1; +static int swdio_dir_gpio_mode; /* Transition delay coefficients */ static int speed_coeff = 113714; static int speed_offset = 28; static unsigned int jtag_delay; +static int is_gpio_valid(int gpio) +{ + return gpio >= 0 && gpio <= 31; +} + static bb_value_t bcm2835gpio_read(void) { return (GPIO_LEV & 1< 0) { + if (is_gpio_valid(trst_gpio)) { set |= !trst< 0) { + if (is_gpio_valid(srst_gpio)) { set |= !srst<= 0 && gpio <= 53; -} - COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionums) { if (CMD_ARGC == 4) { @@ -199,7 +202,7 @@ COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionums) return ERROR_COMMAND_SYNTAX_ERROR; } - command_print(CMD_CTX, + command_print(CMD, "BCM2835 GPIO config: tck = %d, tms = %d, tdi = %d, tdo = %d", tck_gpio, tms_gpio, tdi_gpio, tdo_gpio); @@ -211,7 +214,7 @@ COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_tck) if (CMD_ARGC == 1) COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tck_gpio); - command_print(CMD_CTX, "BCM2835 GPIO config: tck = %d", tck_gpio); + command_print(CMD, "BCM2835 GPIO config: tck = %d", tck_gpio); return ERROR_OK; } @@ -220,7 +223,7 @@ COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_tms) if (CMD_ARGC == 1) COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tms_gpio); - command_print(CMD_CTX, "BCM2835 GPIO config: tms = %d", tms_gpio); + command_print(CMD, "BCM2835 GPIO config: tms = %d", tms_gpio); return ERROR_OK; } @@ -229,7 +232,7 @@ COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_tdo) if (CMD_ARGC == 1) COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tdo_gpio); - command_print(CMD_CTX, "BCM2835 GPIO config: tdo = %d", tdo_gpio); + command_print(CMD, "BCM2835 GPIO config: tdo = %d", tdo_gpio); return ERROR_OK; } @@ -238,7 +241,7 @@ COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_tdi) if (CMD_ARGC == 1) COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tdi_gpio); - command_print(CMD_CTX, "BCM2835 GPIO config: tdi = %d", tdi_gpio); + command_print(CMD, "BCM2835 GPIO config: tdi = %d", tdi_gpio); return ERROR_OK; } @@ -247,7 +250,7 @@ COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_srst) if (CMD_ARGC == 1) COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], srst_gpio); - command_print(CMD_CTX, "BCM2835 GPIO config: srst = %d", srst_gpio); + command_print(CMD, "BCM2835 GPIO config: srst = %d", srst_gpio); return ERROR_OK; } @@ -256,7 +259,7 @@ COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_trst) if (CMD_ARGC == 1) COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], trst_gpio); - command_print(CMD_CTX, "BCM2835 GPIO config: trst = %d", trst_gpio); + command_print(CMD, "BCM2835 GPIO config: trst = %d", trst_gpio); return ERROR_OK; } @@ -269,7 +272,7 @@ COMMAND_HANDLER(bcm2835gpio_handle_swd_gpionums) return ERROR_COMMAND_SYNTAX_ERROR; } - command_print(CMD_CTX, + command_print(CMD, "BCM2835 GPIO nums: swclk = %d, swdio = %d", swclk_gpio, swdio_gpio); @@ -281,7 +284,7 @@ COMMAND_HANDLER(bcm2835gpio_handle_swd_gpionum_swclk) if (CMD_ARGC == 1) COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swclk_gpio); - command_print(CMD_CTX, "BCM2835 num: swclk = %d", swclk_gpio); + command_print(CMD, "BCM2835 num: swclk = %d", swclk_gpio); return ERROR_OK; } @@ -290,7 +293,16 @@ COMMAND_HANDLER(bcm2835gpio_handle_swd_gpionum_swdio) if (CMD_ARGC == 1) COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swdio_gpio); - command_print(CMD_CTX, "BCM2835 num: swdio = %d", swdio_gpio); + command_print(CMD, "BCM2835 num: swdio = %d", swdio_gpio); + return ERROR_OK; +} + +COMMAND_HANDLER(bcm2835gpio_handle_swd_dir_gpionum_swdio) +{ + if (CMD_ARGC == 1) + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swdio_dir_gpio); + + command_print(CMD, "BCM2835 num: swdio_dir = %d", swdio_dir_gpio); return ERROR_OK; } @@ -300,6 +312,9 @@ COMMAND_HANDLER(bcm2835gpio_handle_speed_coeffs) COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], speed_coeff); COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], speed_offset); } + + command_print(CMD, "BCM2835 GPIO: speed_coeffs = %d, speed_offset = %d", + speed_coeff, speed_offset); return ERROR_OK; } @@ -307,102 +322,140 @@ COMMAND_HANDLER(bcm2835gpio_handle_peripheral_base) { if (CMD_ARGC == 1) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], bcm2835_peri_base); + + command_print(CMD, "BCM2835 GPIO: peripheral_base = 0x%08x", + bcm2835_peri_base); return ERROR_OK; } -static const struct command_registration bcm2835gpio_command_handlers[] = { +static const struct command_registration bcm2835gpio_subcommand_handlers[] = { { - .name = "bcm2835gpio_jtag_nums", + .name = "jtag_nums", .handler = &bcm2835gpio_handle_jtag_gpionums, .mode = COMMAND_CONFIG, .help = "gpio numbers for tck, tms, tdi, tdo. (in that order)", - .usage = "(tck tms tdi tdo)* ", + .usage = "[tck tms tdi tdo]", }, { - .name = "bcm2835gpio_tck_num", + .name = "tck_num", .handler = &bcm2835gpio_handle_jtag_gpionum_tck, .mode = COMMAND_CONFIG, .help = "gpio number for tck.", + .usage = "[tck]", }, { - .name = "bcm2835gpio_tms_num", + .name = "tms_num", .handler = &bcm2835gpio_handle_jtag_gpionum_tms, .mode = COMMAND_CONFIG, .help = "gpio number for tms.", + .usage = "[tms]", }, { - .name = "bcm2835gpio_tdo_num", + .name = "tdo_num", .handler = &bcm2835gpio_handle_jtag_gpionum_tdo, .mode = COMMAND_CONFIG, .help = "gpio number for tdo.", + .usage = "[tdo]", }, { - .name = "bcm2835gpio_tdi_num", + .name = "tdi_num", .handler = &bcm2835gpio_handle_jtag_gpionum_tdi, .mode = COMMAND_CONFIG, .help = "gpio number for tdi.", + .usage = "[tdi]", }, { - .name = "bcm2835gpio_swd_nums", + .name = "swd_nums", .handler = &bcm2835gpio_handle_swd_gpionums, .mode = COMMAND_CONFIG, .help = "gpio numbers for swclk, swdio. (in that order)", - .usage = "(swclk swdio)* ", + .usage = "[swclk swdio]", }, { - .name = "bcm2835gpio_swclk_num", + .name = "swclk_num", .handler = &bcm2835gpio_handle_swd_gpionum_swclk, .mode = COMMAND_CONFIG, .help = "gpio number for swclk.", + .usage = "[swclk]", }, { - .name = "bcm2835gpio_swdio_num", + .name = "swdio_num", .handler = &bcm2835gpio_handle_swd_gpionum_swdio, .mode = COMMAND_CONFIG, .help = "gpio number for swdio.", + .usage = "[swdio]", }, { - .name = "bcm2835gpio_srst_num", + .name = "swdio_dir_num", + .handler = &bcm2835gpio_handle_swd_dir_gpionum_swdio, + .mode = COMMAND_CONFIG, + .help = "gpio number for swdio direction control pin (set=output mode, clear=input mode)", + .usage = "[swdio_dir]", + }, + { + .name = "srst_num", .handler = &bcm2835gpio_handle_jtag_gpionum_srst, .mode = COMMAND_CONFIG, .help = "gpio number for srst.", + .usage = "[srst]", }, { - .name = "bcm2835gpio_trst_num", + .name = "trst_num", .handler = &bcm2835gpio_handle_jtag_gpionum_trst, .mode = COMMAND_CONFIG, .help = "gpio number for trst.", + .usage = "[trst]", }, { - .name = "bcm2835gpio_speed_coeffs", + .name = "speed_coeffs", .handler = &bcm2835gpio_handle_speed_coeffs, .mode = COMMAND_CONFIG, .help = "SPEED_COEFF and SPEED_OFFSET for delay calculations.", + .usage = "[SPEED_COEFF SPEED_OFFSET]", }, { - .name = "bcm2835gpio_peripheral_base", + .name = "peripheral_base", .handler = &bcm2835gpio_handle_peripheral_base, .mode = COMMAND_CONFIG, .help = "peripheral base to access GPIOs (RPi1 0x20000000, RPi2 0x3F000000).", + .usage = "[base]", }, COMMAND_REGISTRATION_DONE }; +static const struct command_registration bcm2835gpio_command_handlers[] = { + { + .name = "bcm2835gpio", + .mode = COMMAND_ANY, + .help = "perform bcm2835gpio management", + .chain = bcm2835gpio_subcommand_handlers, + .usage = "", + }, + COMMAND_REGISTRATION_DONE +}; + static const char * const bcm2835_transports[] = { "jtag", "swd", NULL }; -struct jtag_interface bcm2835gpio_interface = { - .name = "bcm2835gpio", +static struct jtag_interface bcm2835gpio_interface = { .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = bitbang_execute_queue, +}; + +struct adapter_driver bcm2835gpio_adapter_driver = { + .name = "bcm2835gpio", .transports = bcm2835_transports, - .swd = &bitbang_swd, - .speed = bcm2835gpio_speed, - .khz = bcm2835gpio_khz, - .speed_div = bcm2835gpio_speed_div, .commands = bcm2835gpio_command_handlers, + .init = bcm2835gpio_init, .quit = bcm2835gpio_quit, + .reset = bcm2835gpio_reset, + .speed = bcm2835gpio_speed, + .khz = bcm2835gpio_khz, + .speed_div = bcm2835gpio_speed_div, + + .jtag_ops = &bcm2835gpio_interface, + .swd_ops = &bitbang_swd, }; static bool bcm2835gpio_jtag_mode_possible(void) @@ -427,27 +480,42 @@ static bool bcm2835gpio_swd_mode_possible(void) return 1; } +static void bcm2835gpio_munmap(void) +{ + if (pio_base != MAP_FAILED) { + munmap((void *)pio_base, sysconf(_SC_PAGE_SIZE)); + pio_base = MAP_FAILED; + } + + if (pads_base != MAP_FAILED) { + munmap((void *)pads_base, sysconf(_SC_PAGE_SIZE)); + pads_base = MAP_FAILED; + } +} + static int bcm2835gpio_init(void) { bitbang_interface = &bcm2835gpio_bitbang; LOG_INFO("BCM2835 GPIO JTAG/SWD bitbang driver"); - if (bcm2835gpio_jtag_mode_possible()) { - if (bcm2835gpio_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)"); - } else if (bcm2835gpio_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"); + if (transport_is_jtag() && !bcm2835gpio_jtag_mode_possible()) { + LOG_ERROR("Require tck, tms, tdi and tdo gpios for JTAG mode"); + return ERROR_JTAG_INIT_FAILED; + } + + if (transport_is_swd() && !bcm2835gpio_swd_mode_possible()) { + LOG_ERROR("Require swclk and swdio gpio for SWD mode"); return ERROR_JTAG_INIT_FAILED; } - dev_mem_fd = open("/dev/mem", O_RDWR | O_SYNC); + dev_mem_fd = open("/dev/gpiomem", O_RDWR | O_SYNC); + if (dev_mem_fd < 0) { + LOG_DEBUG("Cannot open /dev/gpiomem, fallback to /dev/mem"); + dev_mem_fd = open("/dev/mem", O_RDWR | O_SYNC); + } if (dev_mem_fd < 0) { - perror("open"); + LOG_ERROR("open: %s", strerror(errno)); return ERROR_JTAG_INIT_FAILED; } @@ -455,50 +523,70 @@ static int bcm2835gpio_init(void) MAP_SHARED, dev_mem_fd, BCM2835_GPIO_BASE); if (pio_base == MAP_FAILED) { - perror("mmap"); + LOG_ERROR("mmap: %s", strerror(errno)); close(dev_mem_fd); return ERROR_JTAG_INIT_FAILED; } - static volatile uint32_t *pads_base; pads_base = mmap(NULL, sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_WRITE, MAP_SHARED, dev_mem_fd, BCM2835_PADS_GPIO_0_27); if (pads_base == MAP_FAILED) { - perror("mmap"); + LOG_ERROR("mmap: %s", strerror(errno)); + bcm2835gpio_munmap(); close(dev_mem_fd); return ERROR_JTAG_INIT_FAILED; } + close(dev_mem_fd); + /* set 4mA drive strength, slew rate limited, hysteresis on */ pads_base[BCM2835_PADS_GPIO_0_27_OFFSET] = 0x5a000008 + 1; - tdo_gpio_mode = MODE_GPIO(tdo_gpio); - tdi_gpio_mode = MODE_GPIO(tdi_gpio); - tck_gpio_mode = MODE_GPIO(tck_gpio); - tms_gpio_mode = MODE_GPIO(tms_gpio); - swclk_gpio_mode = MODE_GPIO(swclk_gpio); - swdio_gpio_mode = MODE_GPIO(swdio_gpio); /* * Configure TDO as an input, and TDI, TCK, TMS, TRST, SRST * as outputs. Drive TDI and TCK low, and TMS/TRST/SRST high. */ - INP_GPIO(tdo_gpio); - - GPIO_CLR = 1<