From 5f7b294a42194bc3656a6647fe1a14bee7d9e7bf Mon Sep 17 00:00:00 2001 From: Maximilian Deubel Date: Mon, 24 Jun 2024 16:50:42 +0200 Subject: [PATCH 1/4] [nrf fromtree] drivers: dp: swdp_bitbang: power optimization This patch changes GPIO initialization to be in PORT_OFF state by default. Also, if no transceiver is attached to the signals, the GPIOs are configured to be disconnected to preserve power. I tested this on a prototype board where we are going to have a debugger in a low-power context. Signed-off-by: Maximilian Deubel (cherry picked from commit b0936ae35331c3218ed4d51477d95b06afe53ecd) --- drivers/dp/swdp_bitbang.c | 118 ++++++++++++++++++++++---------------- 1 file changed, 68 insertions(+), 50 deletions(-) diff --git a/drivers/dp/swdp_bitbang.c b/drivers/dp/swdp_bitbang.c index ba46c629604a..dabf6d34a024 100644 --- a/drivers/dp/swdp_bitbang.c +++ b/drivers/dp/swdp_bitbang.c @@ -562,107 +562,125 @@ static int sw_configure(const struct device *dev, static int sw_port_on(const struct device *dev) { const struct sw_config *config = dev->config; - - gpio_pin_set_dt(&config->clk, 1); + int ret; if (config->dnoe.port) { - gpio_pin_set_dt(&config->dnoe, 1); + ret = gpio_pin_configure_dt(&config->dnoe, GPIO_OUTPUT_ACTIVE); + if (ret) { + return ret; + } } if (config->dout.port) { - gpio_pin_set_dt(&config->dout, 1); - } else { - int ret; - - ret = gpio_pin_configure_dt(&config->dio, GPIO_OUTPUT_ACTIVE); + ret = gpio_pin_configure_dt(&config->dout, 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; -} - -static int sw_port_off(const struct device *dev) -{ - const struct sw_config *config = dev->config; - - if (config->dnoe.port) { - gpio_pin_set_dt(&config->dnoe, 0); + ret = gpio_pin_configure_dt(&config->dio, GPIO_INPUT); + if (ret) { + return ret; } - if (config->dout.port) { - gpio_pin_set_dt(&config->dout, 0); - } else { - int ret; - - ret = gpio_pin_configure_dt(&config->dio, GPIO_INPUT); + if (config->noe.port) { + ret = gpio_pin_configure_dt(&config->noe, GPIO_OUTPUT_ACTIVE); if (ret) { return ret; } } - if (config->noe.port) { - gpio_pin_set_dt(&config->noe, 0); + ret = gpio_pin_configure_dt(&config->clk, GPIO_OUTPUT_ACTIVE); + if (ret) { + return ret; } - if (config->reset.port) { - gpio_pin_set_dt(&config->reset, 1); + + ret = gpio_pin_configure_dt(&config->reset, GPIO_OUTPUT_ACTIVE); + if (ret) { + return ret; } return 0; } -static int sw_gpio_init(const struct device *dev) +static int sw_port_off(const struct device *dev) { const struct sw_config *config = dev->config; - struct sw_cfg_data *sw_data = dev->data; int ret; - ret = gpio_pin_configure_dt(&config->clk, GPIO_OUTPUT_ACTIVE); - if (ret) { - return ret; - } + /* If there is a transceiver connected to IO, pins should always be driven. */ + if (config->dnoe.port) { + ret = gpio_pin_configure_dt(&config->dnoe, GPIO_OUTPUT_INACTIVE); + if (ret) { + return ret; + } - ret = gpio_pin_configure_dt(&config->dio, GPIO_INPUT); - if (ret) { - return ret; - } + if (config->dout.port) { + ret = gpio_pin_configure_dt(&config->dout, GPIO_OUTPUT_ACTIVE); + if (ret) { + return ret; + } + } - if (config->dout.port) { - ret = gpio_pin_configure_dt(&config->dout, GPIO_OUTPUT_ACTIVE); + ret = gpio_pin_configure_dt(&config->dio, GPIO_INPUT); if (ret) { return ret; } - } + } else { + if (config->dout.port) { + ret = gpio_pin_configure_dt(&config->dout, GPIO_DISCONNECTED); + if (ret) { + return ret; + } + } - if (config->dnoe.port) { - ret = gpio_pin_configure_dt(&config->dnoe, GPIO_OUTPUT_INACTIVE); + ret = gpio_pin_configure_dt(&config->dio, GPIO_DISCONNECTED); if (ret) { return ret; } } + /* If there is a transceiver connected to CLK, pins should always be driven. */ if (config->noe.port) { ret = gpio_pin_configure_dt(&config->noe, GPIO_OUTPUT_INACTIVE); if (ret) { return ret; } + + ret = gpio_pin_configure_dt(&config->clk, GPIO_OUTPUT_ACTIVE); + if (ret) { + return ret; + } + + } else { + ret = gpio_pin_configure_dt(&config->clk, GPIO_DISCONNECTED); + if (ret) { + return ret; + } } if (config->reset.port) { - ret = gpio_pin_configure_dt(&config->reset, GPIO_OUTPUT_ACTIVE); + ret = gpio_pin_configure_dt(&config->reset, GPIO_DISCONNECTED); if (ret) { return ret; } } + return 0; +} + +static int sw_gpio_init(const struct device *dev) +{ + const struct sw_config *config = dev->config; + struct sw_cfg_data *sw_data = dev->data; + int ret; + + /* start with the port turned off */ + ret = sw_port_off(dev); + if (ret) { + return ret; + } + sw_data->turnaround = 1U; sw_data->data_phase = false; sw_data->fast_clock = false; From 5330222de38dfad026c0112fba0299501926ada2 Mon Sep 17 00:00:00 2001 From: Maximilian Deubel Date: Wed, 2 Oct 2024 13:52:33 +0200 Subject: [PATCH 2/4] [nrf fromtree] drivers: dp: swdp_bitbang: hardcode nRF53 SYSCLK Since CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC is tied to the slow RTC clock for the nRF53, use the default SYSCLK of 64MHz instead. Signed-off-by: Maximilian Deubel (cherry picked from commit 621a6000d578aa7d52c8d9e7e4403d2e851c15d0) --- drivers/dp/swdp_ll_pin.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/dp/swdp_ll_pin.h b/drivers/dp/swdp_ll_pin.h index 3044931a228a..48b4ea14cb3e 100644 --- a/drivers/dp/swdp_ll_pin.h +++ b/drivers/dp/swdp_ll_pin.h @@ -6,8 +6,9 @@ #include #include +#include -#if defined(CONFIG_SOC_SERIES_NRF52X) +#if defined(CONFIG_SOC_SERIES_NRF52X) || defined(CONFIG_SOC_SERIES_NRF53X) #define CPU_CLOCK 64000000U #else #define CPU_CLOCK CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC From b4e6d2244f2bf6c301a8946353566b8f56090136 Mon Sep 17 00:00:00 2001 From: Maximilian Deubel Date: Wed, 2 Oct 2024 13:53:31 +0200 Subject: [PATCH 3/4] [nrf fromtree] drivers: dp: swdp_bitbang: Update SWD clock calculation This patch updates the SWD clock calculation to the latest behavior of DAPLink. Signed-off-by: Maximilian Deubel (cherry picked from commit fd686a25b3aa2d2671d628fca1717ae43fb49b55) --- drivers/dp/swdp_bitbang.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/drivers/dp/swdp_bitbang.c b/drivers/dp/swdp_bitbang.c index dabf6d34a024..a1d28386209f 100644 --- a/drivers/dp/swdp_bitbang.c +++ b/drivers/dp/swdp_bitbang.c @@ -26,8 +26,8 @@ #include LOG_MODULE_REGISTER(swdp, CONFIG_DP_DRIVER_LOG_LEVEL); -#define CLOCK_DELAY(swclk_freq, port_write_cycles) \ - ((CPU_CLOCK / 2 / swclk_freq) - port_write_cycles) +#define MAX_SWJ_CLOCK(delay_cycles, port_write_cycles) \ + ((CPU_CLOCK / 2U) / (port_write_cycles + delay_cycles)) /* * Default SWCLK frequency in Hz. @@ -35,6 +35,7 @@ LOG_MODULE_REGISTER(swdp, CONFIG_DP_DRIVER_LOG_LEVEL); */ #define SWDP_DEFAULT_SWCLK_FREQUENCY 1000000U +#define DELAY_FAST_CYCLES 2U #define DELAY_SLOW_CYCLES 3U struct sw_config { @@ -528,14 +529,19 @@ static int sw_set_clock(const struct device *dev, const uint32_t clock) struct sw_cfg_data *sw_data = dev->data; uint32_t delay; - sw_data->fast_clock = false; - delay = ((CPU_CLOCK / 2U) + (clock - 1U)) / clock; - - if (delay > config->port_write_cycles) { - delay -= config->port_write_cycles; - delay = (delay + (DELAY_SLOW_CYCLES - 1U)) / DELAY_SLOW_CYCLES; - } else { + if (clock >= MAX_SWJ_CLOCK(DELAY_FAST_CYCLES, config->port_write_cycles)) { + sw_data->fast_clock = true; delay = 1U; + } else { + sw_data->fast_clock = false; + + delay = ((CPU_CLOCK / 2U) + (clock - 1U)) / clock; + if (delay > config->port_write_cycles) { + delay -= config->port_write_cycles; + delay = (delay + (DELAY_SLOW_CYCLES - 1U)) / DELAY_SLOW_CYCLES; + } else { + delay = 1U; + } } sw_data->clock_delay = delay; @@ -684,8 +690,7 @@ static int sw_gpio_init(const struct device *dev) sw_data->turnaround = 1U; sw_data->data_phase = false; sw_data->fast_clock = false; - sw_data->clock_delay = CLOCK_DELAY(SWDP_DEFAULT_SWCLK_FREQUENCY, - config->port_write_cycles); + sw_set_clock(dev, SWDP_DEFAULT_SWCLK_FREQUENCY); return 0; } From edba7b8864f1ccc77b07212d9696741bf1715382 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Fri, 11 Oct 2024 13:11:30 -0700 Subject: [PATCH 4/4] [nrf fromtree] dp: swdp_bitbang: fix unused variable build error The variable config in sw_port_off() is not used, and it's causing CI build error about unused variable. So remove it. Signed-off-by: Daniel Leung (cherry picked from commit 1ec5ce05f9f84b18cb8056d01917480a6ec39e52) --- drivers/dp/swdp_bitbang.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/dp/swdp_bitbang.c b/drivers/dp/swdp_bitbang.c index a1d28386209f..7822315ab8e1 100644 --- a/drivers/dp/swdp_bitbang.c +++ b/drivers/dp/swdp_bitbang.c @@ -677,7 +677,6 @@ static int sw_port_off(const struct device *dev) static int sw_gpio_init(const struct device *dev) { - const struct sw_config *config = dev->config; struct sw_cfg_data *sw_data = dev->data; int ret;