#include <sys/mman.h>
-static uint32_t bcm2835_peri_base = 0x20000000;
+static char *bcm2835_peri_mem_dev;
+static off_t bcm2835_peri_base = 0x20000000;
#define BCM2835_GPIO_BASE (bcm2835_peri_base + 0x200000) /* GPIO controller */
#define BCM2835_PADS_GPIO_0_27 (bcm2835_peri_base + 0x100000)
} initial_gpio_state[ADAPTER_GPIO_IDX_NUM];
static uint32_t initial_drive_strength_etc;
+static inline const char *bcm2835_get_mem_dev(void)
+{
+ if (bcm2835_peri_mem_dev)
+ return bcm2835_peri_mem_dev;
+
+ return "/dev/gpiomem";
+}
+
static inline void bcm2835_gpio_synchronize(void)
{
/* Ensure that previous writes to GPIO registers are flushed out of
static bool is_gpio_config_valid(enum adapter_gpio_config_index idx)
{
/* Only chip 0 is supported, accept unset value (-1) too */
- return adapter_gpio_config[idx].chip_num >= -1
- && adapter_gpio_config[idx].chip_num <= 0
- && adapter_gpio_config[idx].gpio_num >= 0
- && adapter_gpio_config[idx].gpio_num <= 31;
+ return adapter_gpio_config[idx].gpio_num <= 31;
}
static void set_gpio_value(const struct adapter_gpio_config *gpio_config, int value)
}
/* Direction for non push-pull is already set by set_gpio_value() */
- if (adapter_gpio_config[idx].drive == ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL)
+ if (adapter_gpio_config[idx].drive == ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL
+ && adapter_gpio_config[idx].init_state != ADAPTER_GPIO_INIT_STATE_INPUT)
OUT_GPIO(adapter_gpio_config[idx].gpio_num);
bcm2835_gpio_synchronize();
}
if (is_gpio_config_valid(ADAPTER_GPIO_IDX_TRST))
set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_TRST], trst);
- LOG_DEBUG("BCM2835 GPIO: bcm2835gpio_reset(%d, %d), trst_gpio: %d %d, srst_gpio: %d %d",
- trst, srst,
- adapter_gpio_config[ADAPTER_GPIO_IDX_TRST].chip_num, adapter_gpio_config[ADAPTER_GPIO_IDX_TRST].gpio_num,
- adapter_gpio_config[ADAPTER_GPIO_IDX_SRST].chip_num, adapter_gpio_config[ADAPTER_GPIO_IDX_SRST].gpio_num);
+ LOG_DEBUG("trst %d gpio: %d %d, srst %d gpio: %d %d",
+ trst,
+ (int)adapter_gpio_config[ADAPTER_GPIO_IDX_TRST].chip_num,
+ (int)adapter_gpio_config[ADAPTER_GPIO_IDX_TRST].gpio_num,
+ srst,
+ (int)adapter_gpio_config[ADAPTER_GPIO_IDX_SRST].chip_num,
+ (int)adapter_gpio_config[ADAPTER_GPIO_IDX_SRST].gpio_num);
return ERROR_OK;
}
return ERROR_OK;
}
+COMMAND_HANDLER(bcm2835gpio_handle_peripheral_mem_dev)
+{
+ if (CMD_ARGC == 1) {
+ free(bcm2835_peri_mem_dev);
+ bcm2835_peri_mem_dev = strdup(CMD_ARGV[0]);
+ }
+
+ command_print(CMD, "BCM2835 GPIO: peripheral_mem_dev = %s",
+ bcm2835_get_mem_dev());
+ return ERROR_OK;
+}
+
COMMAND_HANDLER(bcm2835gpio_handle_peripheral_base)
{
- if (CMD_ARGC == 1)
- COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], bcm2835_peri_base);
+ uint64_t tmp_base;
+ if (CMD_ARGC == 1) {
+ COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], tmp_base);
+ bcm2835_peri_base = (off_t)tmp_base;
+ }
- command_print(CMD, "BCM2835 GPIO: peripheral_base = 0x%08x",
- bcm2835_peri_base);
+ tmp_base = bcm2835_peri_base;
+ command_print(CMD, "BCM2835 GPIO: peripheral_base = 0x%08" PRIx64,
+ tmp_base);
return ERROR_OK;
}
.help = "SPEED_COEFF and SPEED_OFFSET for delay calculations.",
.usage = "[SPEED_COEFF SPEED_OFFSET]",
},
+ {
+ .name = "peripheral_mem_dev",
+ .handler = &bcm2835gpio_handle_peripheral_mem_dev,
+ .mode = COMMAND_CONFIG,
+ .help = "device to map memory mapped GPIOs from.",
+ .usage = "[device]",
+ },
{
.name = "peripheral_base",
.handler = &bcm2835gpio_handle_peripheral_base,
.mode = COMMAND_CONFIG,
- .help = "peripheral base to access GPIOs (RPi1 0x20000000, RPi2 0x3F000000).",
+ .help = "peripheral base to access GPIOs, not needed with /dev/gpiomem.",
.usage = "[base]",
},
return ERROR_JTAG_INIT_FAILED;
}
- 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);
- }
+ bool is_gpiomem = strcmp(bcm2835_get_mem_dev(), "/dev/gpiomem") == 0;
+ bool pad_mapping_possible = !is_gpiomem;
+
+ dev_mem_fd = open(bcm2835_get_mem_dev(), O_RDWR | O_SYNC);
if (dev_mem_fd < 0) {
- LOG_ERROR("open: %s", strerror(errno));
+ LOG_ERROR("open %s: %s", bcm2835_get_mem_dev(), strerror(errno));
+ /* TODO: add /dev/mem specific doc and refer to it
+ * if (!is_gpiomem && (errno == EACCES || errno == EPERM))
+ * LOG_INFO("Consult the user's guide chapter 4.? how to set permissions and capabilities");
+ */
return ERROR_JTAG_INIT_FAILED;
}
return ERROR_JTAG_INIT_FAILED;
}
- pads_base = mmap(NULL, sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_WRITE,
+ /* TODO: move pads config to a separate utility */
+ if (pad_mapping_possible) {
+ 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) {
- LOG_ERROR("mmap: %s", strerror(errno));
- bcm2835gpio_munmap();
- close(dev_mem_fd);
- return ERROR_JTAG_INIT_FAILED;
+ if (pads_base == MAP_FAILED) {
+ LOG_ERROR("mmap pads: %s", strerror(errno));
+ LOG_WARNING("Continuing with unchanged GPIO pad settings (drive strength and slew rate)");
+ }
+ } else {
+ pads_base = MAP_FAILED;
}
close(dev_mem_fd);
- /* set 4mA drive strength, slew rate limited, hysteresis on */
- initial_drive_strength_etc = pads_base[BCM2835_PADS_GPIO_0_27_OFFSET] & 0x1f;
- pads_base[BCM2835_PADS_GPIO_0_27_OFFSET] = 0x5a000008 + 1;
+ if (pads_base != MAP_FAILED) {
+ /* set 4mA drive strength, slew rate limited, hysteresis on */
+ initial_drive_strength_etc = pads_base[BCM2835_PADS_GPIO_0_27_OFFSET] & 0x1f;
+LOG_INFO("initial pads conf %08x", pads_base[BCM2835_PADS_GPIO_0_27_OFFSET]);
+ pads_base[BCM2835_PADS_GPIO_0_27_OFFSET] = 0x5a000008 + 1;
+LOG_INFO("pads conf set to %08x", pads_base[BCM2835_PADS_GPIO_0_27_OFFSET]);
+ }
/* Configure JTAG/SWD signals. Default directions and initial states are handled
* by adapter.c and "adapter gpio" command.
restore_gpio(ADAPTER_GPIO_IDX_SRST);
restore_gpio(ADAPTER_GPIO_IDX_LED);
- /* Restore drive strength. MSB is password ("5A") */
- pads_base[BCM2835_PADS_GPIO_0_27_OFFSET] = 0x5A000000 | initial_drive_strength_etc;
+ if (pads_base != MAP_FAILED) {
+ /* Restore drive strength. MSB is password ("5A") */
+ pads_base[BCM2835_PADS_GPIO_0_27_OFFSET] = 0x5A000000 | initial_drive_strength_etc;
+ }
bcm2835gpio_munmap();
+ free(bcm2835_peri_mem_dev);
return ERROR_OK;
}