driver: swdp_bitbang: rework pin configurations
Move low-level GPIO functions to a separate file and use GPIO driver API if low-level GPIO support is not available for the platform. Allows alternative pin configuration using only two pins, clk and dio. Improve binding description. Signed-off-by: Maximilian Deubel <maximilian.deubel@nordicsemi.no> Signed-off-by: Johann Fischer <johann.fischer@nordicsemi.no>
This commit is contained in:
parent
f5ccc3c82c
commit
3ef2c66a8a
@ -24,6 +24,7 @@ config SWDP_BITBANG_DRIVER
|
||||
bool "Serial Wire Debug Port bit-bang driver"
|
||||
default y
|
||||
depends on DT_HAS_ZEPHYR_SWDP_GPIO_ENABLED
|
||||
depends on GPIO
|
||||
help
|
||||
Serial Wire Debug Port bit-bang driver.
|
||||
|
||||
|
||||
@ -21,15 +21,11 @@
|
||||
#include <zephyr/drivers/gpio.h>
|
||||
#include <zephyr/drivers/swdp.h>
|
||||
|
||||
#include "swdp_ll_pin.h"
|
||||
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_REGISTER(swdp, CONFIG_DP_DRIVER_LOG_LEVEL);
|
||||
|
||||
#if defined(CONFIG_SOC_SERIES_NRF52X)
|
||||
#define CPU_CLOCK 64000000U
|
||||
#else
|
||||
#define CPU_CLOCK CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC
|
||||
#endif
|
||||
|
||||
#define CLOCK_DELAY(swclk_freq, port_write_cycles) \
|
||||
((CPU_CLOCK / 2 / swclk_freq) - port_write_cycles)
|
||||
|
||||
@ -44,15 +40,15 @@ LOG_MODULE_REGISTER(swdp, CONFIG_DP_DRIVER_LOG_LEVEL);
|
||||
struct sw_config {
|
||||
struct gpio_dt_spec clk;
|
||||
struct gpio_dt_spec dout;
|
||||
struct gpio_dt_spec din;
|
||||
struct gpio_dt_spec dio;
|
||||
struct gpio_dt_spec dnoe;
|
||||
void *dout_reg;
|
||||
void *dio_reg;
|
||||
void *dnoe_reg;
|
||||
struct gpio_dt_spec noe;
|
||||
struct gpio_dt_spec reset;
|
||||
uint32_t port_write_cycles;
|
||||
void *clk_reg;
|
||||
void *dout_reg;
|
||||
void *din_reg;
|
||||
void *dnoe_reg;
|
||||
};
|
||||
|
||||
struct sw_cfg_data {
|
||||
@ -98,102 +94,78 @@ static ALWAYS_INLINE uint32_t sw_get32bit_parity(uint32_t data)
|
||||
return data & 1U;
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE void pin_delay_asm(uint32_t delay)
|
||||
{
|
||||
#if defined(CONFIG_SOC_SERIES_NRF52X)
|
||||
__asm volatile ("movs r3, %[p]\n"
|
||||
".start_%=:\n"
|
||||
"subs r3, #1\n"
|
||||
"bne .start_%=\n"
|
||||
:
|
||||
: [p] "r" (delay)
|
||||
: "r3", "cc"
|
||||
);
|
||||
#else
|
||||
#error "Not defined for this SoC family"
|
||||
#endif
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE void pin_platform_set(void *base, uint8_t pin)
|
||||
{
|
||||
#if defined(CONFIG_SOC_SERIES_NRF52X)
|
||||
NRF_GPIO_Type * reg = base;
|
||||
|
||||
reg->OUTSET = BIT(pin);
|
||||
#else
|
||||
#error "Not defined for this SoC family"
|
||||
#endif
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE void pin_platform_clr(void *base, uint8_t pin)
|
||||
{
|
||||
#if defined(CONFIG_SOC_SERIES_NRF52X)
|
||||
NRF_GPIO_Type * reg = base;
|
||||
|
||||
reg->OUTCLR = BIT(pin);
|
||||
#else
|
||||
#error "Not defined for this SoC family"
|
||||
#endif
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE uint32_t pin_platform_get(void *base, uint8_t pin)
|
||||
{
|
||||
#if defined(CONFIG_SOC_SERIES_NRF52X)
|
||||
NRF_GPIO_Type * reg = base;
|
||||
|
||||
return ((reg->IN >> pin) & 1);
|
||||
#else
|
||||
#error "Not defined for this SoC family"
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Set SWCLK DAP hardware output pin to high level */
|
||||
static ALWAYS_INLINE void pin_swclk_set(const struct device *dev)
|
||||
{
|
||||
const struct sw_config *config = dev->config;
|
||||
const struct gpio_dt_spec *dt_spec = &config->clk;
|
||||
|
||||
pin_platform_set(config->clk_reg, dt_spec->pin);
|
||||
if (FAST_BITBANG_HW_SUPPORT) {
|
||||
swdp_ll_pin_set(config->clk_reg, config->clk.pin);
|
||||
} else {
|
||||
gpio_pin_set_dt(&config->clk, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set SWCLK DAP hardware output pin to low level */
|
||||
static ALWAYS_INLINE void pin_swclk_clr(const struct device *dev)
|
||||
{
|
||||
const struct sw_config *config = dev->config;
|
||||
const struct gpio_dt_spec *dt_spec = &config->clk;
|
||||
|
||||
pin_platform_clr(config->clk_reg, dt_spec->pin);
|
||||
if (FAST_BITBANG_HW_SUPPORT) {
|
||||
swdp_ll_pin_clr(config->clk_reg, config->clk.pin);
|
||||
} else {
|
||||
gpio_pin_set_dt(&config->clk, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the SWDIO DAP hardware output pin to high level */
|
||||
static ALWAYS_INLINE void pin_swdio_set(const struct device *dev)
|
||||
{
|
||||
const struct sw_config *config = dev->config;
|
||||
const struct gpio_dt_spec *dt_spec = &config->dout;
|
||||
|
||||
pin_platform_set(config->dout_reg, dt_spec->pin);
|
||||
if (config->dout.port) {
|
||||
if (FAST_BITBANG_HW_SUPPORT) {
|
||||
swdp_ll_pin_set(config->dout_reg, config->dout.pin);
|
||||
} else {
|
||||
gpio_pin_set_dt(&config->dout, 1);
|
||||
}
|
||||
} else {
|
||||
if (FAST_BITBANG_HW_SUPPORT) {
|
||||
swdp_ll_pin_set(config->dio_reg, config->dio.pin);
|
||||
} else {
|
||||
gpio_pin_set_dt(&config->dio, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the SWDIO DAP hardware output pin to low level */
|
||||
static ALWAYS_INLINE void pin_swdio_clr(const struct device *dev)
|
||||
{
|
||||
const struct sw_config *config = dev->config;
|
||||
const struct gpio_dt_spec *dt_spec = &config->dout;
|
||||
|
||||
pin_platform_clr(config->dout_reg, dt_spec->pin);
|
||||
if (config->dout.port) {
|
||||
if (FAST_BITBANG_HW_SUPPORT) {
|
||||
swdp_ll_pin_clr(config->dout_reg, config->dout.pin);
|
||||
} else {
|
||||
gpio_pin_set_dt(&config->dout, 0);
|
||||
}
|
||||
} else {
|
||||
if (FAST_BITBANG_HW_SUPPORT) {
|
||||
swdp_ll_pin_clr(config->dio_reg, config->dio.pin);
|
||||
} else {
|
||||
gpio_pin_set_dt(&config->dio, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the SWDIO DAP hardware output pin to bit level */
|
||||
static ALWAYS_INLINE void pin_swdio_out(const struct device *dev,
|
||||
const uint32_t bit)
|
||||
{
|
||||
const struct sw_config *config = dev->config;
|
||||
const struct gpio_dt_spec *dt_spec = &config->dout;
|
||||
|
||||
if (bit & 1U) {
|
||||
pin_platform_set(config->dout_reg, dt_spec->pin);
|
||||
pin_swdio_set(dev);
|
||||
} else {
|
||||
pin_platform_clr(config->dout_reg, dt_spec->pin);
|
||||
pin_swdio_clr(dev);
|
||||
}
|
||||
}
|
||||
|
||||
@ -201,9 +173,12 @@ static ALWAYS_INLINE void pin_swdio_out(const struct device *dev,
|
||||
static ALWAYS_INLINE uint32_t pin_swdio_in(const struct device *dev)
|
||||
{
|
||||
const struct sw_config *config = dev->config;
|
||||
const struct gpio_dt_spec *dt_spec = &config->din;
|
||||
|
||||
return pin_platform_get(config->din_reg, dt_spec->pin);
|
||||
if (FAST_BITBANG_HW_SUPPORT) {
|
||||
return swdp_ll_pin_get(config->dio_reg, config->dio.pin);
|
||||
} else {
|
||||
return gpio_pin_get_dt(&config->dio);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -213,9 +188,20 @@ static ALWAYS_INLINE uint32_t pin_swdio_in(const struct device *dev)
|
||||
static ALWAYS_INLINE void pin_swdio_out_enable(const struct device *dev)
|
||||
{
|
||||
const struct sw_config *config = dev->config;
|
||||
const struct gpio_dt_spec *dt_spec = &config->dnoe;
|
||||
|
||||
pin_platform_set(config->dnoe_reg, dt_spec->pin);
|
||||
if (config->dnoe.port) {
|
||||
if (FAST_BITBANG_HW_SUPPORT) {
|
||||
swdp_ll_pin_set(config->dnoe_reg, config->dnoe.pin);
|
||||
} else {
|
||||
gpio_pin_set_dt(&config->dnoe, 1);
|
||||
}
|
||||
} else {
|
||||
if (FAST_BITBANG_HW_SUPPORT) {
|
||||
swdp_ll_pin_output(config->dio_reg, config->dio.pin);
|
||||
} else {
|
||||
gpio_pin_configure_dt(&config->dio, GPIO_OUTPUT_ACTIVE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -224,9 +210,20 @@ static ALWAYS_INLINE void pin_swdio_out_enable(const struct device *dev)
|
||||
static ALWAYS_INLINE void pin_swdio_out_disable(const struct device *dev)
|
||||
{
|
||||
const struct sw_config *config = dev->config;
|
||||
const struct gpio_dt_spec *dt_spec = &config->dnoe;
|
||||
|
||||
pin_platform_clr(config->dnoe_reg, dt_spec->pin);
|
||||
if (config->dnoe.port) {
|
||||
if (FAST_BITBANG_HW_SUPPORT) {
|
||||
swdp_ll_pin_clr(config->dnoe_reg, config->dnoe.pin);
|
||||
} else {
|
||||
gpio_pin_set_dt(&config->dnoe, 0);
|
||||
}
|
||||
} else {
|
||||
if (FAST_BITBANG_HW_SUPPORT) {
|
||||
swdp_ll_pin_input(config->dio_reg, config->dio.pin);
|
||||
} else {
|
||||
gpio_pin_configure_dt(&config->dio, GPIO_INPUT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define SW_CLOCK_CYCLE(dev, delay) \
|
||||
@ -260,13 +257,14 @@ static int sw_sequence(const struct device *dev, uint32_t count,
|
||||
{
|
||||
struct sw_cfg_data *sw_data = dev->data;
|
||||
unsigned int key;
|
||||
uint32_t val = 0;
|
||||
uint32_t n = 0;
|
||||
uint32_t val = 0; /* current byte */
|
||||
uint32_t n = 0; /* bit counter */
|
||||
|
||||
LOG_DBG("count %u", count);
|
||||
LOG_DBG("writing %u bits", count);
|
||||
LOG_HEXDUMP_DBG(data, count, "sequence bit data");
|
||||
key = irq_lock();
|
||||
|
||||
pin_swdio_out_enable(dev);
|
||||
while (count--) {
|
||||
if (n == 0U) {
|
||||
val = *data++;
|
||||
@ -309,6 +307,8 @@ static int sw_transfer(const struct device *dev,
|
||||
uint32_t parity = 0;
|
||||
uint32_t n;
|
||||
|
||||
pin_swdio_out_enable(dev);
|
||||
|
||||
LOG_DBG("request 0x%02x idle %u", request, idle_cycles);
|
||||
if (!(request & SWDP_REQUEST_RnW)) {
|
||||
LOG_DBG("write data 0x%08x", *data);
|
||||
@ -449,19 +449,31 @@ static int sw_set_pins(const struct device *dev,
|
||||
}
|
||||
}
|
||||
|
||||
if (pins & BIT(SWDP_SWDIO_PIN)) {
|
||||
if (value & BIT(SWDP_SWDIO_PIN)) {
|
||||
gpio_pin_set_dt(&config->dout, 1);
|
||||
} else {
|
||||
gpio_pin_set_dt(&config->dout, 0);
|
||||
if (config->dout_reg != NULL) {
|
||||
if (pins & BIT(SWDP_SWDIO_PIN)) {
|
||||
if (value & BIT(SWDP_SWDIO_PIN)) {
|
||||
gpio_pin_set_dt(&config->dout, 1);
|
||||
} else {
|
||||
gpio_pin_set_dt(&config->dout, 0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (pins & BIT(SWDP_SWDIO_PIN)) {
|
||||
if (value & BIT(SWDP_SWDIO_PIN)) {
|
||||
gpio_pin_set_dt(&config->dio, 1);
|
||||
} else {
|
||||
gpio_pin_set_dt(&config->dio, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pins & BIT(SWDP_nRESET_PIN)) {
|
||||
if (value & BIT(SWDP_nRESET_PIN)) {
|
||||
gpio_pin_set_dt(&config->reset, 1);
|
||||
} else {
|
||||
gpio_pin_set_dt(&config->reset, 0);
|
||||
if (config->reset.port) {
|
||||
if (pins & BIT(SWDP_nRESET_PIN)) {
|
||||
if (value & BIT(SWDP_nRESET_PIN)) {
|
||||
gpio_pin_set_dt(&config->reset, 1);
|
||||
} else {
|
||||
gpio_pin_set_dt(&config->reset, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -473,10 +485,12 @@ static int sw_get_pins(const struct device *dev, uint8_t *const state)
|
||||
const struct sw_config *config = dev->config;
|
||||
uint32_t val;
|
||||
|
||||
val = gpio_pin_get_dt(&config->reset);
|
||||
*state = val ? BIT(SWDP_nRESET_PIN) : 0;
|
||||
if (config->reset.port) {
|
||||
val = gpio_pin_get_dt(&config->reset);
|
||||
*state = val ? BIT(SWDP_nRESET_PIN) : 0;
|
||||
}
|
||||
|
||||
val = gpio_pin_get_dt(&config->din);
|
||||
val = gpio_pin_get_dt(&config->dio);
|
||||
*state |= val ? BIT(SWDP_SWDIO_PIN) : 0;
|
||||
|
||||
val = gpio_pin_get_dt(&config->clk);
|
||||
@ -529,10 +543,28 @@ static int sw_port_on(const struct device *dev)
|
||||
const struct sw_config *config = dev->config;
|
||||
|
||||
gpio_pin_set_dt(&config->clk, 1);
|
||||
gpio_pin_set_dt(&config->dout, 1);
|
||||
gpio_pin_set_dt(&config->dnoe, 1);
|
||||
gpio_pin_set_dt(&config->noe, 1);
|
||||
gpio_pin_set_dt(&config->reset, 1);
|
||||
|
||||
if (config->dnoe.port) {
|
||||
gpio_pin_set_dt(&config->dnoe, 1);
|
||||
}
|
||||
|
||||
if (config->dout.port) {
|
||||
gpio_pin_set_dt(&config->dout, 1);
|
||||
} else {
|
||||
int ret;
|
||||
|
||||
ret = gpio_pin_configure_dt(&config->dio, GPIO_OUTPUT_ACTIVE);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (config->noe.port) {
|
||||
gpio_pin_set_dt(&config->noe, 1);
|
||||
}
|
||||
if (config->reset.port) {
|
||||
gpio_pin_set_dt(&config->reset, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -541,9 +573,27 @@ static int sw_port_off(const struct device *dev)
|
||||
{
|
||||
const struct sw_config *config = dev->config;
|
||||
|
||||
gpio_pin_set_dt(&config->dnoe, 0);
|
||||
gpio_pin_set_dt(&config->noe, 0);
|
||||
gpio_pin_set_dt(&config->reset, 1);
|
||||
if (config->dnoe.port) {
|
||||
gpio_pin_set_dt(&config->dnoe, 0);
|
||||
}
|
||||
|
||||
if (config->dout.port) {
|
||||
gpio_pin_set_dt(&config->dout, 0);
|
||||
} else {
|
||||
int ret;
|
||||
|
||||
ret = gpio_pin_configure_dt(&config->dio, GPIO_INPUT);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (config->noe.port) {
|
||||
gpio_pin_set_dt(&config->noe, 0);
|
||||
}
|
||||
if (config->reset.port) {
|
||||
gpio_pin_set_dt(&config->reset, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -559,29 +609,37 @@ static int sw_gpio_init(const struct device *dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = gpio_pin_configure_dt(&config->dout, GPIO_OUTPUT_ACTIVE);
|
||||
ret = gpio_pin_configure_dt(&config->dio, GPIO_INPUT);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = gpio_pin_configure_dt(&config->din, GPIO_INPUT);
|
||||
if (ret) {
|
||||
return ret;
|
||||
if (config->dout.port) {
|
||||
ret = gpio_pin_configure_dt(&config->dout, GPIO_OUTPUT_ACTIVE);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = gpio_pin_configure_dt(&config->dnoe, GPIO_OUTPUT_INACTIVE);
|
||||
if (ret) {
|
||||
return ret;
|
||||
if (config->dnoe.port) {
|
||||
ret = gpio_pin_configure_dt(&config->dnoe, GPIO_OUTPUT_INACTIVE);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = gpio_pin_configure_dt(&config->noe, GPIO_OUTPUT_INACTIVE);
|
||||
if (ret) {
|
||||
return ret;
|
||||
if (config->noe.port) {
|
||||
ret = gpio_pin_configure_dt(&config->noe, GPIO_OUTPUT_INACTIVE);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = gpio_pin_configure_dt(&config->reset, GPIO_OUTPUT_INACTIVE);
|
||||
if (ret) {
|
||||
return ret;
|
||||
if (config->reset.port) {
|
||||
ret = gpio_pin_configure_dt(&config->reset, GPIO_OUTPUT_ACTIVE);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
sw_data->turnaround = 1U;
|
||||
@ -605,29 +663,35 @@ static struct swdp_api swdp_bitbang_api = {
|
||||
.swdp_port_off = sw_port_off,
|
||||
};
|
||||
|
||||
#define SW_GPIOS_GET_REG(n, gpios) \
|
||||
INT_TO_POINTER(DT_REG_ADDR(DT_PHANDLE(DT_DRV_INST(n), gpios)))
|
||||
#define SW_GPIOS_GET_REG(n, gpios) \
|
||||
COND_CODE_1(DT_INST_NODE_HAS_PROP(n, gpios), \
|
||||
(INT_TO_POINTER(DT_REG_ADDR(DT_PHANDLE(DT_DRV_INST(n), gpios)))), \
|
||||
(NULL))
|
||||
|
||||
#define SW_DEVICE_DEFINE(n) \
|
||||
static const struct sw_config sw_cfg_##n = { \
|
||||
.clk = GPIO_DT_SPEC_INST_GET(n, clk_gpios), \
|
||||
.dout = GPIO_DT_SPEC_INST_GET(n, dout_gpios), \
|
||||
.din = GPIO_DT_SPEC_INST_GET(n, din_gpios), \
|
||||
.dnoe = GPIO_DT_SPEC_INST_GET(n, dnoe_gpios), \
|
||||
.noe = GPIO_DT_SPEC_INST_GET(n, noe_gpios), \
|
||||
.reset = GPIO_DT_SPEC_INST_GET(n, reset_gpios), \
|
||||
.port_write_cycles = DT_INST_PROP(n, port_write_cycles), \
|
||||
.clk_reg = SW_GPIOS_GET_REG(n, clk_gpios), \
|
||||
.dout_reg = SW_GPIOS_GET_REG(n, dout_gpios), \
|
||||
.din_reg = SW_GPIOS_GET_REG(n, din_gpios), \
|
||||
.dnoe_reg = SW_GPIOS_GET_REG(n, dnoe_gpios), \
|
||||
}; \
|
||||
\
|
||||
static struct sw_cfg_data sw_data_##n; \
|
||||
\
|
||||
DEVICE_DT_INST_DEFINE(n, sw_gpio_init, NULL, \
|
||||
&sw_data_##n, &sw_cfg_##n, \
|
||||
POST_KERNEL, CONFIG_DP_DRIVER_INIT_PRIO, \
|
||||
&swdp_bitbang_api); \
|
||||
#define SW_DEVICE_DEFINE(n) \
|
||||
BUILD_ASSERT((DT_INST_NODE_HAS_PROP(n, dout_gpios)) == \
|
||||
(DT_INST_NODE_HAS_PROP(n, dnoe_gpios)), \
|
||||
"Either the dout-gpios or dnoe-gpios property is missing."); \
|
||||
\
|
||||
static const struct sw_config sw_cfg_##n = { \
|
||||
.clk = GPIO_DT_SPEC_INST_GET(n, clk_gpios), \
|
||||
.clk_reg = SW_GPIOS_GET_REG(n, clk_gpios), \
|
||||
.dio = GPIO_DT_SPEC_INST_GET(n, dio_gpios), \
|
||||
.dio_reg = SW_GPIOS_GET_REG(n, dio_gpios), \
|
||||
.dout = GPIO_DT_SPEC_INST_GET_OR(n, dout_gpios, {0}), \
|
||||
.dout_reg = SW_GPIOS_GET_REG(n, dout_gpios), \
|
||||
.dnoe = GPIO_DT_SPEC_INST_GET_OR(n, dnoe_gpios, {0}), \
|
||||
.dnoe_reg = SW_GPIOS_GET_REG(n, dnoe_gpios), \
|
||||
.noe = GPIO_DT_SPEC_INST_GET_OR(n, noe_gpios, {0}), \
|
||||
.reset = GPIO_DT_SPEC_INST_GET_OR(n, reset_gpios, {0}), \
|
||||
.port_write_cycles = DT_INST_PROP(n, port_write_cycles), \
|
||||
}; \
|
||||
\
|
||||
static struct sw_cfg_data sw_data_##n; \
|
||||
\
|
||||
DEVICE_DT_INST_DEFINE(n, sw_gpio_init, NULL, \
|
||||
&sw_data_##n, &sw_cfg_##n, \
|
||||
POST_KERNEL, CONFIG_DP_DRIVER_INIT_PRIO, \
|
||||
&swdp_bitbang_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(SW_DEVICE_DEFINE)
|
||||
|
||||
84
drivers/dp/swdp_ll_pin.h
Normal file
84
drivers/dp/swdp_ll_pin.h
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/drivers/gpio.h>
|
||||
|
||||
#if defined(CONFIG_SOC_SERIES_NRF52X)
|
||||
#define CPU_CLOCK 64000000U
|
||||
#else
|
||||
#define CPU_CLOCK CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SOC_SERIES_NRF52X) || defined(CONFIG_SOC_SERIES_NRF53X)
|
||||
#define FAST_BITBANG_HW_SUPPORT 1
|
||||
#else
|
||||
#define FAST_BITBANG_HW_SUPPORT 0
|
||||
#endif
|
||||
|
||||
static ALWAYS_INLINE void pin_delay_asm(uint32_t delay)
|
||||
{
|
||||
#if defined(CONFIG_CPU_CORTEX_M)
|
||||
__asm volatile ("movs r3, %[p]\n"
|
||||
".start_%=:\n"
|
||||
"subs r3, #1\n"
|
||||
"bne .start_%=\n"
|
||||
:
|
||||
: [p] "r" (delay)
|
||||
: "r3", "cc"
|
||||
);
|
||||
#else
|
||||
#warning "Pin delay is not defined"
|
||||
#endif
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE void swdp_ll_pin_input(void *const base, uint8_t pin)
|
||||
{
|
||||
#if defined(CONFIG_SOC_SERIES_NRF52X) || defined(CONFIG_SOC_SERIES_NRF53X)
|
||||
NRF_GPIO_Type * reg = base;
|
||||
|
||||
reg->PIN_CNF[pin] = 0b0000;
|
||||
#endif
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE void swdp_ll_pin_output(void *const base, uint8_t pin)
|
||||
{
|
||||
#if defined(CONFIG_SOC_SERIES_NRF52X) || defined(CONFIG_SOC_SERIES_NRF53X)
|
||||
NRF_GPIO_Type * reg = base;
|
||||
|
||||
reg->PIN_CNF[pin] = 0b0001;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static ALWAYS_INLINE void swdp_ll_pin_set(void *const base, uint8_t pin)
|
||||
{
|
||||
#if defined(CONFIG_SOC_SERIES_NRF52X) || defined(CONFIG_SOC_SERIES_NRF53X)
|
||||
NRF_GPIO_Type * reg = base;
|
||||
|
||||
reg->OUTSET = BIT(pin);
|
||||
#endif
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE void swdp_ll_pin_clr(void *const base, uint8_t pin)
|
||||
{
|
||||
#if defined(CONFIG_SOC_SERIES_NRF52X) || defined(CONFIG_SOC_SERIES_NRF53X)
|
||||
NRF_GPIO_Type * reg = base;
|
||||
|
||||
reg->OUTCLR = BIT(pin);
|
||||
#endif
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE uint32_t swdp_ll_pin_get(void *const base, uint8_t pin)
|
||||
{
|
||||
#if defined(CONFIG_SOC_SERIES_NRF52X) || defined(CONFIG_SOC_SERIES_NRF53X)
|
||||
NRF_GPIO_Type * reg = base;
|
||||
|
||||
return ((reg->IN >> pin) & 1);
|
||||
#else
|
||||
return 0UL;
|
||||
#endif
|
||||
}
|
||||
@ -1,10 +1,60 @@
|
||||
# Copyright (c) 2019, Phytec Messtechnik GmbH
|
||||
# Copyright (c) 2019 Phytec Messtechnik GmbH
|
||||
# Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
description: >
|
||||
description: |
|
||||
This is a representation of the Serial Wire Debug Port interface
|
||||
implementation by GPIO bit-banging.
|
||||
|
||||
Schematic using dual-supply bus transceiver and separate dout and dnoe pins
|
||||
|
||||
VCC_3V3 VCC_REF
|
||||
^ ^
|
||||
| +-------------+ |
|
||||
+-------|vcca vccb|-----+
|
||||
| |
|
||||
clk-gpios -------|a b|-------------- SWD CLK
|
||||
| |
|
||||
noe-gpios -------|dir gnd|-----+
|
||||
+-------------+ |
|
||||
74LVC1T45 v
|
||||
GND
|
||||
|
||||
|
||||
VCC_3V3 VCC_REF
|
||||
^ ^
|
||||
| +-------------+ |
|
||||
+-------|vcca vccb|-----+
|
||||
| |
|
||||
dio-gpios -------|a b|------------*- SWD DIO
|
||||
| | |
|
||||
+-------|dir gnd|-----+ |
|
||||
| +-------------+ | |
|
||||
v 74LVC1T45 v |
|
||||
GND GND |
|
||||
|
|
||||
|
|
||||
VCC_3V3 VCC_REF |
|
||||
^ ^ |
|
||||
| +-------------+ | |
|
||||
+-------|vcca vccb|-----+ |
|
||||
| | |
|
||||
dout-gpios -------|a b|------------+
|
||||
| |
|
||||
dnoe-gpios -------|dir gnd|-----+
|
||||
+-------------+ |
|
||||
74LVC1T45 v
|
||||
GND
|
||||
|
||||
Direct connection using only dio pin for SWD DIO.
|
||||
|
||||
clk-gpios ------------------------------------ SWD CLK
|
||||
|
||||
dio-gpios ------------------------------------ SWD DIO
|
||||
|
||||
Of course, bidirectional bus transceiver between dio and SWD DIO can also be
|
||||
used together with noe pin to enable/disable transceivers.
|
||||
|
||||
compatible: "zephyr,swdp-gpio"
|
||||
|
||||
include: base.yaml
|
||||
@ -15,32 +65,38 @@ properties:
|
||||
required: true
|
||||
description: GPIO pin used for SWCLK output
|
||||
|
||||
dio-gpios:
|
||||
type: phandle-array
|
||||
required: true
|
||||
description: |
|
||||
GPIO pin used for SWDIO input. This pin is also used for the SWDIO output
|
||||
if separate output pin is not defined.
|
||||
|
||||
dout-gpios:
|
||||
type: phandle-array
|
||||
required: true
|
||||
description: GPIO pin used for SWDIO output
|
||||
|
||||
din-gpios:
|
||||
type: phandle-array
|
||||
required: true
|
||||
description: GPIO pin used for SWDIO input
|
||||
description: |
|
||||
Optional GPIO pin used for SWDIO output.
|
||||
|
||||
dnoe-gpios:
|
||||
type: phandle-array
|
||||
required: true
|
||||
description: GPIO pin used for SWDIO NOE output
|
||||
description: |
|
||||
GPIO pin used to disable the SWDIO output buffer behind optional
|
||||
pin dout-gpios.
|
||||
|
||||
noe-gpios:
|
||||
type: phandle-array
|
||||
required: true
|
||||
description: GPIO pin used for SWD NOE output
|
||||
description: |
|
||||
Optional pin to disable all bus transceivers if any are present.
|
||||
|
||||
reset-gpios:
|
||||
type: phandle-array
|
||||
required: true
|
||||
description: GPIO pin used for RESET output
|
||||
description: |
|
||||
Optional GPIO pin used for RESET output.
|
||||
|
||||
port-write-cycles:
|
||||
type: int
|
||||
required: true
|
||||
description: Number of processor cycles for I/O Port write operations
|
||||
description: |
|
||||
Number of processor cycles for I/O Port write operations.For example, the
|
||||
GPIO clock may be different from the CPU clock. This can usually be
|
||||
found in the SoC documentation.
|
||||
|
||||
Loading…
Reference in New Issue
Block a user