From 3456a59663eb92450472620edf576964160e2f10 Mon Sep 17 00:00:00 2001 From: Adrian Negreanu Date: Tue, 7 Dec 2021 22:54:16 +0200 Subject: [PATCH] [rfc] lpc4322: swd using sgpio Signed-off-by: Adrian Negreanu --- records/hic_hal/lpc4322.yaml | 1 + source/hic_hal/nxp/lpc4322/DAP_config.h | 16 + source/hic_hal/nxp/lpc4322/gpio.c | 5 + source/hic_hal/nxp/lpc4322/swdp_sgpio.c | 1111 +++++++++++++++++++++++ 4 files changed, 1133 insertions(+) create mode 100644 source/hic_hal/nxp/lpc4322/swdp_sgpio.c diff --git a/records/hic_hal/lpc4322.yaml b/records/hic_hal/lpc4322.yaml index 11fa4ee1a6..a265bfd2d1 100644 --- a/records/hic_hal/lpc4322.yaml +++ b/records/hic_hal/lpc4322.yaml @@ -9,6 +9,7 @@ common: - INTERNAL_FLASH - DAPLINK_HIC_ID=0x97969905 # DAPLINK_HIC_ID_LPC4322 - OS_CLOCK=120000000 + - SWDP_SGPIO includes: - source/hic_hal/nxp/lpc4322 - source/hic_hal/nxp/lpc4322/RTE_Driver diff --git a/source/hic_hal/nxp/lpc4322/DAP_config.h b/source/hic_hal/nxp/lpc4322/DAP_config.h index d031bdbda6..4a8f00a920 100644 --- a/source/hic_hal/nxp/lpc4322/DAP_config.h +++ b/source/hic_hal/nxp/lpc4322/DAP_config.h @@ -300,11 +300,13 @@ __STATIC_FORCEINLINE uint32_t PIN_SWDIO_IN(void) */ __STATIC_FORCEINLINE void PIN_SWDIO_OUT(uint32_t bit) { +#ifndef SWDP_SGPIO if (bit & 0x1) { X_SET(SWDIO); } else { X_CLR(SWDIO); } +#endif } /** SWDIO I/O pin: Switch to Output mode (used in SWD mode only). @@ -313,8 +315,10 @@ called prior \ref PIN_SWDIO_OUT function calls. */ __STATIC_FORCEINLINE void PIN_SWDIO_OUT_ENABLE(void) { +#ifndef SWDP_SGPIO X_SET(SWDIO_TXE); X_DIR_OUT(SWDIO); +#endif } /** SWDIO I/O pin: Switch to Input mode (used in SWD mode only). @@ -323,8 +327,10 @@ called prior \ref PIN_SWDIO_IN function calls. */ __STATIC_FORCEINLINE void PIN_SWDIO_OUT_DISABLE(void) { +#ifndef SWDP_SGPIO X_DIR_IN(SWDIO); X_CLR(SWDIO_TXE); +#endif } @@ -506,11 +512,21 @@ __STATIC_INLINE void DAP_SETUP(void) while (!(LPC_CCU1->CLK_M4_GPIO_STAT & CCU_CLK_STAT_RUN)); +#ifdef SWDP_SGPIO + /* Table 186. Pin multiplexing. */ + /* SWCLK/TCK: PIN(P1_17) FUNC6(SGPIO11). TCK_SWCLK. Table 189. */ + scu_pinmux(1, 17, CLK_OUT, FUNC6); + /* SWDIO/TMS: PIN(P1_6) FUNC6(SGPIO14). TMS_SWDIO. Table 188. */ + scu_pinmux(1, 6, INBUF_ENABLE | PUP_DISABLE | SLEWRATE_FAST, FUNC6); + /* SWDIO/TXEN: PIN(P1_5) FUNC6(SGPIO15). TMS_SWDIO_TXEN. */ + scu_pinmux(1, 5, PUP_DISABLE | SLEWRATE_FAST, FUNC6); +#else /* Configure I/O pins: function number, input buffer enabled, */ /* no pull-up/down */ scu_pinmux(1, 17, GPIO_NOPULL, FUNC0); /* SWCLK/TCK: GPIO0[12] */ scu_pinmux(1, 6, GPIO_NOPULL, FUNC0); /* SWDIO/TMS: GPIO1[9] */ scu_pinmux(1, 5, GPIO_NOPULL, FUNC0); /* SWDIO_OE: GPIO1[8] */ +#endif } /** Reset Target Device with custom specific I/O pin or command sequence. diff --git a/source/hic_hal/nxp/lpc4322/gpio.c b/source/hic_hal/nxp/lpc4322/gpio.c index 7a32166b4a..fcbf46b2d8 100644 --- a/source/hic_hal/nxp/lpc4322/gpio.c +++ b/source/hic_hal/nxp/lpc4322/gpio.c @@ -89,6 +89,11 @@ void gpio_init(void) X_DIR_IN(SWO); #endif +#ifdef SWDP_SGPIO + extern void sgpio_init(void); + sgpio_init(); +#endif + busy_wait(10000); } diff --git a/source/hic_hal/nxp/lpc4322/swdp_sgpio.c b/source/hic_hal/nxp/lpc4322/swdp_sgpio.c new file mode 100644 index 0000000000..1173a2673b --- /dev/null +++ b/source/hic_hal/nxp/lpc4322/swdp_sgpio.c @@ -0,0 +1,1111 @@ +/** + * @file swdp_sgpio.c + * @brief SWD implemented using LPC4322's SGPIOs. + * + * DAPLink Interface Firmware + * Copyright (c) 2009-2021, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "LPC43xx.h" +#include "DAP_config.h" +#include "DAP.h" + +// Referenced documents: +// ID072320: Arm Debug Interface Architecture Specification ARM IHI 0031F. +// UM10503: LPC43xx ARM Cortex-M4/M0 multi-core microcontroller User Manual, Rev. 1.7 — 17 October 2013. +// +// Q: Why SGPIO14 SWDIO ? +// A: it uses the same P1_6 pin as the bit-banged SWDIO. +// +// Q: Why SGPIO15 for SWDIO_TXEN ? +// A: it uses the same P1_5 pin. +// +// Q: Why SGPIO11 for clock ? +// A: Only SGPIO 8, 9, 10, 11 can be CLK_SOURCE_PIN_MODE. +// +// Which SGPIO is the GPIO is being hooked to ? +// +// If CONCAT_ENABLE is NOT set, then the pin is External Data pin. +// +// Can I have two SGPIOs connected to the same GPIO? +// +// Q:How can I find which GPIO coresponds to which SGPIO? +// See Table 185. +// P1_17 TCK/SWCLK: GPIO0[12] - SGPIO11 +// P1_6 TMS/SWDIO: GPIO1[9] - SGPIO14 +// PLL1 (SGPIO_CLK) is set to 204MHz in CGU_Init (lpc43xx_cgu.c) +// The local clock is made from a 12-bit down counter, COUNT, +// running at the SGPIO_CLOCK. +// +// The COUNT duration can be preset with register PRESET. +// +// When COUNT reaches zero, it is loaded with PRESET. +// +// Each time COUNT reaches zero the register shifts right; +// loading bit REG[31] with data captured from DIN and +// loading DOUT with bit REG[0]. +// Thus COUNT controls the serial data rate. +// +// The POS counter consists of an 8-bit counter that is decremented when COUNT equals zero. +// When POS reaches zero it is loaded with the PRESET_POS value. +// +// Slice data is exchanged using a double buffering scheme. +// When POS reaches zero the slice register REG content is +// swapped with the slice buffer REG_SS content. + +#define SLICE_D 3 +#define SLICE_F 5 +#define SLICE_G 6 +#define SLICE_H 7 +#define SLICE_M 12 +#define SLICE_N 13 +#define SLICE_O 14 +#define SLICE_P 15 + +// Table 269 UM10503. +// P_OUT_CFG +#define OUT_MUX_CFG_CLK_OUT 0x08 +#define OUT_MUX_CFG_DOUT_DOUTM2C 0x03 +#define OUT_MUX_CFG_DOUT_DOUTM8B 0x0A +// P_OE_CFG +#define OUT_MUX_CFG_GPIO_OE 0x00 +#define OUT_MUX_CFG_DOUT_OEM1 0x40 +#define OUT_MUX_CFG_DOUT_OEM2 0x50 + +// Table 272 UM10503. +#define SGPIO_MUX_CFG_EXT_CLK_ENABLE_INTERNAL (0b00 << 0) +#define SGPIO_MUX_CFG_EXT_CLK_ENABLE_EXTERNAL (0b01 << 0) + +#define SGPIO_MUX_CFG_CLK_SOURCE_PIN_MODE_8 (0b00 << 1) +#define SGPIO_MUX_CFG_CLK_SOURCE_PIN_MODE_9 (0b01 << 1) +#define SGPIO_MUX_CFG_CLK_SOURCE_PIN_MODE_10 (0b10 << 1) +#define SGPIO_MUX_CFG_CLK_SOURCE_PIN_MODE_11 (0b11 << 1) + +#define SGPIO_MUX_CFG_CLK_SOURCE_SLICE_MODE_D (0b00 << 3) +#define SGPIO_MUX_CFG_CLK_SOURCE_SLICE_MODE_H (0b01 << 3) +#define SGPIO_MUX_CFG_CLK_SOURCE_SLICE_MODE_O (0b10 << 3) +#define SGPIO_MUX_CFG_CLK_SOURCE_SLICE_MODE_P (0b11 << 3) + +#define SGPIO_MUX_CFG_QUALIFIER_MODE_DEFAULT (0b00 << 5) +#define SGPIO_MUX_CFG_QUALIFIER_MODE_DISABLE (0b01 << 5) +#define SGPIO_MUX_CFG_QUALIFIER_MODE_SLICE (0b10 << 5) +#define SGPIO_MUX_CFG_QUALIFIER_MODE_PIN (0b11 << 5) + +#define SGPIO_MUX_CFG_QUALIFIER_PIN_MODE_8 (0b00 << 7) +#define SGPIO_MUX_CFG_QUALIFIER_PIN_MODE_9 (0b01 << 7) +#define SGPIO_MUX_CFG_QUALIFIER_PIN_MODE_10 (0b10 << 7) +#define SGPIO_MUX_CFG_QUALIFIER_PIN_MODE_11 (0b11 << 7) + +#define SGPIO_MUX_CFG_QUALIFIER_SLICE_MODE_A (0b00 << 9) +#define SGPIO_MUX_CFG_QUALIFIER_SLICE_MODE_H (0b01 << 9) +#define SGPIO_MUX_CFG_QUALIFIER_SLICE_MODE_I (0b10 << 9) +#define SGPIO_MUX_CFG_QUALIFIER_SLICE_MODE_P (0b11 << 9) + +#define SGPIO_MUX_CFG_CONCAT_EXT_PIN (0b00 << 11) +#define SGPIO_MUX_CFG_CONCAT_DISABLE (0b00 << 11) +#define SGPIO_MUX_CFG_CONCAT_ENABLE (0b01 << 11) + +#define SGPIO_MUX_CFG_CONCAT_ORDER_LOOP (0b00 << 12) +#define SGPIO_MUX_CFG_CONCAT_ORDER_2SLC (0b01 << 12) +#define SGPIO_MUX_CFG_CONCAT_ORDER_4SLC (0b10 << 12) +#define SGPIO_MUX_CFG_CONCAT_ORDER_8SLC (0b11 << 12) + + +//////////////////////////////////////////////////////////// +// Table 274 UM10503. +#define SLICE_MUX_CFG_MATCH_MODE_DISABLED (0b00 << 0) +#define SLICE_MUX_CFG_MATCH_MODE_ENABLED (0b01 << 0) + +#define SLICE_MUX_CFG_CLK_CAPTURE_MODE_RISING (0b00 << 1) +#define SLICE_MUX_CFG_CLK_CAPTURE_MODE_FALLING (0b01 << 1) + +#define SLICE_MUX_CFG_CLKGEN_MODE_INTERNAL (0b00 << 2) +#define SLICE_MUX_CFG_CLKGEN_MODE_EXTERNAL (0b01 << 2) +#define SLICE_MUX_CFG_INV_OUT_CLK_NORMAL (0b00 << 3) +#define SLICE_MUX_CFG_INV_OUT_CLK_INVERTED (0b01 << 3) + +#define SLICE_MUX_CFG_DATA_CAPTURE_MODE_RISING (0b00 << 4) +#define SLICE_MUX_CFG_DATA_CAPTURE_MODE_FALLING (0b01 << 4) +#define SLICE_MUX_CFG_DATA_CAPTURE_MODE_LOW (0b10 << 4) +#define SLICE_MUX_CFG_DATA_CAPTURE_MODE_HIGH (0b11 << 4) + +#define SLICE_MUX_CFG_PARALLEL_MODE_1BPCLK (0b00 << 6) +#define SLICE_MUX_CFG_PARALLEL_MODE_2BPCLK (0b01 << 6) +#define SLICE_MUX_CFG_PARALLEL_MODE_4BPCLK (0b10 << 6) +#define SLICE_MUX_CFG_PARALLEL_MODE_8BPCLK (0b11 << 6) + +#define SLICE_MUX_CFG_INV_QUALIFIER_NORMAL (0b00 << 8) +#define SLICE_MUX_CFG_INV_QUALIFIER_INVERTED (0b01 << 8) + +#define POS_POS(n) (n? ((n-1)&0xFF)<<0 : 0) // value at start +#define POS_PRESET(n) (n? ((n-1)&0xFF)<<8 : 0) // PRESET_POS can be used to indicate word boundaries for words that are not a multiple of 32 bit + + + + +// SWCLK/TCK. +// SLICE_N SWCLK +// [31....0] -> SGPIO11/P1_17/GPIO0[12]. +#define SGPIO_SWCLK_TCK 11 +// Slice N can act as Clock on SGPIO11. Table 270. Output pin multiplexing +#define SLICE_SWCLK_TCK SLICE_N +#define SLICE_SWCLK_TCK_MASK (1 << SLICE_SWCLK_TCK) + + +// SWDIO/TMS. +// Input slices. +// Table 316 (Slice I/O Multiplexing), pg501 UM10503. +// Table 276 UM10503. +// +// SGPIO14 is connected to H31 (bit 31 of slice H). +// Since SLICE_H is an input slice, it means it should be configured as External Data (CONCAT_ENABLE=0). +// +// SWDIO SLICE_H SLICE_P +// External Data(SGPIO14/P1_6/GPIO1[9]) -> [31....0] -> [31....0] +#define SGPIO_SWDIO_TMS 14 +#define SLICE_SWDIO_TMS_DIN1 SLICE_P +#define SLICE_SWDIO_TMS_DIN1_MASK (1 << SLICE_SWDIO_TMS_DIN1) +#define SLICE_SWDIO_TMS_DIN0 SLICE_H +#define SLICE_SWDIO_TMS_DIN0_MASK (1 << SLICE_SWDIO_TMS_DIN0) + +// SWDIO/TMS. +// Output slices. +// Table 273 (Output pin multiplexing), pg481. +// +// SLICE_D SLICE_O SWDIO. +// [31....0] -> [31....0] -> External Data(SGPIO14/P1_6/GPIO1[9]). +#define SLICE_SWDIO_TMS_DOUT1 SLICE_D +#define SLICE_SWDIO_TMS_DOUT1_MASK (1 << SLICE_SWDIO_TMS_DOUT1) +#define SLICE_SWDIO_TMS_DOUT0 SLICE_O +#define SLICE_SWDIO_TMS_DOUT0_MASK (1 << SLICE_SWDIO_TMS_DOUT0) + +// SWDIO/TMS. +// OutputEnable control slice. Table 271. Output enable control +// +// SLICE_F +// [31....0] -> SGPIO14_P_OE_CFG. +#define SLICE_SWDIO_TMS_OE SLICE_F +#define SLICE_SWDIO_TMS_OE_MASK (1 << SLICE_SWDIO_TMS_OE) + + + +// SWDIO/TXEN. +// [31....0] -> SGPIO15/P1_5/GPIO1[8]. +#define SGPIO_SWDIO_TXEN 15 +#define SLICE_SWDIO_TXEN SLICE_M +#define SLICE_SWDIO_TXEN_MASK (1 << SLICE_SWDIO_TXEN) + + +#define SLICE_POS(s) LPC_SGPIO->POS[SLICE_##s] +#define SLICE_CNT(s) LPC_SGPIO->COUNT[SLICE_##s] +#define SLICE_REG(s) LPC_SGPIO->REG[SLICE_##s] +#define SLICE_SHD(s) LPC_SGPIO->REG_SS[SLICE_##s] + +#define REQUEST_READ(request) (request & DAP_TRANSFER_RnW) +#define REQUEST_TIMESTAMP(request) (request & DAP_TRANSFER_TIMESTAMP) +#define REQUEST_WRITE(request) ((request & DAP_TRANSFER_RnW) == 0U) + + + +__STATIC_FORCEINLINE uint8_t PARITY_U32(uint32_t v) +{ + v ^= v >> 16; + v ^= v >> 8; + v ^= v >> 4; + v &= 0xF; + return (0x6996 >> v) & 1; +} + + + +__STATIC_FORCEINLINE void putU32(uint32_t src_sz, const uint8_t *src, volatile uint32_t *dst) +{ + uint32_t rv = 0; + + for (unsigned i = 0; i < src_sz; ++i) + { + rv |= *src++<<(i*8); + } + *dst = rv; +} + + + +__STATIC_FORCEINLINE void getU32(uint32_t src_sz, uint32_t src, uint8_t *dst) +{ + for (unsigned i=0; i< src_sz; ++i) + { + *dst++ = src & 0xFF; + } +} + + + +// Enable the Output SGPIO pin. +// 19.6.15 UM10503. +__STATIC_FORCEINLINE void sgpio_pin_oenable(uint32_t pin) +{ + uint32_t cur_oenreg; + cur_oenreg = LPC_SGPIO->GPIO_OENREG; + LPC_SGPIO->GPIO_OENREG = cur_oenreg | (1 << pin); +} + + + +// Disable the Output SGPIO pin. +// 19.6.15 UM10503. +__STATIC_FORCEINLINE void sgpio_pin_odisable(uint32_t pin) +{ + uint32_t cur_oenreg; + cur_oenreg = LPC_SGPIO->GPIO_OENREG; + LPC_SGPIO->GPIO_OENREG = cur_oenreg & ~(1 << pin); +} + + + +// Exchange clock interrupt clear mask register. +// 19.6.24 UM10503. +// Set the CLR_EN_1 register bit to clear +// the corresponding bit in the ENABLE_1 register. +__STATIC_FORCEINLINE void exchg_clk_int_off(uint32_t mask) +{ + LPC_SGPIO->CLR_EN_1 = mask; +} + + + +// Exchange clock interrupt clear status register. +// 19.6.28 UM10503. +__STATIC_FORCEINLINE void exchg_clk_cleanup(uint32_t slice_mask) +{ + LPC_SGPIO->CLR_STATUS_1 = slice_mask; +} + + + +// Exchange clock interrupt status register. +// 19.6.27 UM10503. +// The STATUS_1 register bits are set when +// the shadow and data registers are exchanged. +__STATIC_FORCEINLINE void exchg_clk_wait_on(uint32_t slice_mask) +{ + while ((LPC_SGPIO->STATUS_1 & slice_mask) != slice_mask) { } +} + + + +// Enable the slices' COUNT counter. +// 1 = Starts COUNTn or external shift clock. +// 0 = Disables slice shift clock. +__STATIC_FORCEINLINE void shift_clk_kickoff(uint32_t slice_mask) +{ + LPC_SGPIO->CTRL_ENABLE |= slice_mask; +} + + + +__STATIC_FORCEINLINE void shift_clk_int_off(uint32_t mask) +{ + LPC_SGPIO->CLR_EN_0 = mask; +} + + + +__STATIC_FORCEINLINE void shift_clk_disable(uint32_t slice_mask) +{ + LPC_SGPIO->CTRL_ENABLE &= ~slice_mask; +} + + + +// The shift_clock frequency is therefore equal to: +// +// frequency(shift_clock) = frequency(SGPIO_CLK) / (PRESET+1). +// PRESET = frequency(SGPIO_CLK)/frequency(shift_clk) - 1. +// +// sgpio_clk = SystemCoreClock +// shift_clock = HZ_FROM_CLOCK_DELAY(DAP.clock_delay) +// PRESET = frequency(SGPIO_CLK)/frequency(shift_clk) - 1. +static uint32_t shift_clk_preset() +{ +// hz_from_clock_delay = SystemCoreClock/(2U*(DAP.clock_delay + IO_PORT_WRITE_CYCLES)); +// SystemCoreClock/hz_from_clock_delay - 1; + return (2*DAP_Data.clock_delay) - 1; + //uint32_t clk = CGU_GetPCLKFrequency(CGU_PERIPHERAL_M4CORE); + //return clk/DAP_Data.clock - 1;//PRESET = SGPIO_CLK/shift_clk - 1 +} + + + +static void shift_clk_preset_init(void) +{ + uint32_t sc = shift_clk_preset(); + + LPC_SGPIO->PRESET[SLICE_SWCLK_TCK] = sc; + + // These use SGPIO11 as external clock. + LPC_SGPIO->PRESET[SLICE_SWDIO_TXEN] = 0; + LPC_SGPIO->PRESET[SLICE_SWDIO_TMS_OE] = 0; + LPC_SGPIO->PRESET[SLICE_SWDIO_TMS_DIN1] = 0; + LPC_SGPIO->PRESET[SLICE_SWDIO_TMS_DIN0] = 0; + LPC_SGPIO->PRESET[SLICE_SWDIO_TMS_DOUT0] = 0; + LPC_SGPIO->PRESET[SLICE_SWDIO_TMS_DOUT1] = 0; +} + + + +// 0 = Enables COUNT and POS counters. +// The counters start counting when the +// CTRL_EN bit or bits are set in the +// CTRL_ENABLED register. +// 1 = Disable the POSi counter of slice i +// when the POSi counter reaches a zero +// count. +// Once a slice is enabled, it's POS register should not be modified. +// +// If only one POSi countdown is needed +// (when only one slice should be processed), +// then this should be called after COUNTi +// is started with shift_clk_kickoff(). +__STATIC_FORCEINLINE void slice_pos_oneshot(uint32_t slice_mask) +{ + LPC_SGPIO->CTRL_DISABLE |= slice_mask; +} + + + +__STATIC_FORCEINLINE void slice_pos_disable(uint32_t slice_mask) +{ + LPC_SGPIO->CTRL_DISABLE &= ~slice_mask; +} + + + +// Line turnaround B4.1.3, ID072320. +// To prevent contention, a turnaround period +// is required when the device driving the wire +// changes. For the turnaround period, neither +// the host nor the target drives the wire, and +// the state of the wire is undefined. +static void line_turnaround(uint32_t period) +{ + // drive SWCLK_TCK for: period * shift_clock cycles. + SLICE_POS(SWCLK_TCK) = POS_POS(period) | POS_PRESET(0); + SLICE_CNT(SWCLK_TCK) = 0; + SLICE_POS(SWDIO_TXEN) = POS_POS(period) | POS_PRESET(0); + SLICE_REG(SWDIO_TXEN) = 0b00000000000000000000000000000000; + SLICE_SHD(SWDIO_TXEN) = 0; + SLICE_CNT(SWDIO_TXEN) = 0; + + SLICE_POS(SWDIO_TMS_OE) = POS_POS(period) | POS_PRESET(0); + SLICE_REG(SWDIO_TMS_OE) = 0b00000000000000000000000000000000; + SLICE_SHD(SWDIO_TMS_OE) = 0; + SLICE_CNT(SWDIO_TMS_OE) = 0; + SLICE_REG(SWDIO_TMS_DOUT0) = 0; + SLICE_SHD(SWDIO_TMS_DOUT0) = 0; + exchg_clk_cleanup(SLICE_SWCLK_TCK_MASK); + slice_pos_oneshot(SLICE_SWCLK_TCK_MASK); + shift_clk_kickoff(SLICE_SWCLK_TCK_MASK); + exchg_clk_wait_on(SLICE_SWCLK_TCK_MASK); + shift_clk_disable(SLICE_SWCLK_TCK_MASK); + slice_pos_disable(SLICE_SWCLK_TCK_MASK); +} + +// B4.1.4 Idle cycles, ID072320. +// The host clocks the SWD interface with the line LOW to insert idle cycles. +static void idle_cycles(uint32_t period) +{ + // drive SWCLK_TCK for: period * shift_clock cycles. + SLICE_POS(SWCLK_TCK) = POS_POS(period) | POS_PRESET(0); + SLICE_CNT(SWCLK_TCK) = 0; + SLICE_POS(SWDIO_TXEN) = POS_POS(period) | POS_PRESET(0); + SLICE_REG(SWDIO_TXEN) = 0b00000000000000000000000000000000; + SLICE_SHD(SWDIO_TXEN) = 0; + SLICE_CNT(SWDIO_TXEN) = 0; + + SLICE_POS(SWDIO_TMS_OE) = POS_POS(period) | POS_PRESET(0); + SLICE_REG(SWDIO_TMS_OE) = 0b00000000000000000000000000000000; + SLICE_SHD(SWDIO_TMS_OE) = 0; + SLICE_CNT(SWDIO_TMS_OE) = 0; + SLICE_REG(SWDIO_TMS_DOUT0) = 0; + SLICE_SHD(SWDIO_TMS_DOUT0) = 0; + exchg_clk_cleanup(SLICE_SWCLK_TCK_MASK); + slice_pos_oneshot(SLICE_SWCLK_TCK_MASK); + shift_clk_kickoff(SLICE_SWCLK_TCK_MASK); + exchg_clk_wait_on(SLICE_SWCLK_TCK_MASK); + shift_clk_disable(SLICE_SWCLK_TCK_MASK); + slice_pos_disable(SLICE_SWCLK_TCK_MASK); +} + +struct reg_descript { + volatile uint32_t* reg_addr; + uint32_t slice_mask; +}; + + +// bits_sz bits SLICE_D -> SLICE_O -> out +// Use one slice for 1..32bits +// Use two slices for 33..64bits +// Use Slicedata Shadow registers for more than 64bits. +static void sequence_send(uint32_t bits_sz, const uint8_t *data) +{ + uint32_t bits_it = 0; + uint32_t data_it = 0; + uint32_t slices_started = 0; + size_t regs_len = 4; + + struct reg_descript regs[] = { + {&SLICE_REG(SWDIO_TMS_DOUT0), SLICE_SWDIO_TMS_DOUT0_MASK}, + {&SLICE_REG(SWDIO_TMS_DOUT1), SLICE_SWDIO_TMS_DOUT1_MASK}, + {&SLICE_SHD(SWDIO_TMS_DOUT0), SLICE_SWDIO_TMS_DOUT0_MASK}, + {&SLICE_SHD(SWDIO_TMS_DOUT1), SLICE_SWDIO_TMS_DOUT1_MASK}, + }; + + shift_clk_preset_init(); + uint32_t chunk_size = bits_sz<=64 ? bits_sz : 64; + + SLICE_POS(SWCLK_TCK) = POS_POS(bits_sz) | POS_PRESET(0); + SLICE_CNT(SWCLK_TCK) = 0; + SLICE_REG(SWCLK_TCK) = 0x0; + SLICE_SHD(SWCLK_TCK) = 0x0; + + // Drive the SGPIO14 OutputEnable. + SLICE_POS(SWDIO_TMS_OE) = POS_POS(bits_sz) | POS_PRESET(0); + SLICE_CNT(SWDIO_TMS_OE) = 0; + SLICE_REG(SWDIO_TMS_OE) = 0xFFFFFFFF; + SLICE_SHD(SWDIO_TMS_OE) = 0xFFFFFFFF; + + SLICE_POS(SWDIO_TXEN) = POS_POS(bits_sz) | POS_PRESET(0); + SLICE_CNT(SWDIO_TXEN) = 0; + SLICE_REG(SWDIO_TXEN) = 0xFFFFFFFF; + SLICE_SHD(SWDIO_TXEN) = 0xFFFFFFFF; + + SLICE_POS(SWDIO_TMS_DOUT0) = POS_POS(chunk_size) | POS_PRESET(chunk_size); + SLICE_POS(SWDIO_TMS_DOUT1) = POS_POS(chunk_size) | POS_PRESET(chunk_size); + + while (bits_it < bits_sz) + { + uint32_t bits_remaining = bits_sz - bits_it; + uint32_t bytes_remaining = (bits_remaining + 7) / 8; + uint32_t bytes_it = 0; + uint32_t slices_used = 0; + + while ((bytes_it < bytes_remaining/4) && (bytes_it < regs_len)) + { + // 1 + putU32(4, data + data_it, regs[bytes_it].reg_addr); + slices_used |= regs[bytes_it].slice_mask; + bits_it += 4*8; + data_it += 4; + bytes_it += 1; + } + + SLICE_SHD(SWDIO_TMS_OE) = 0xFFFFFFFF; + SLICE_SHD(SWDIO_TXEN) = 0xFFFFFFFF; + + if (bytes_remaining > 16) + { + if (!slices_started) + { + exchg_clk_cleanup(SLICE_SWCLK_TCK_MASK | SLICE_SWDIO_TXEN_MASK | slices_used); + slice_pos_oneshot(SLICE_SWCLK_TCK_MASK);// | SLICE_SWDIO_TXEN_MASK); + shift_clk_kickoff(SLICE_SWCLK_TCK_MASK | SLICE_SWDIO_TXEN_MASK | slices_used); + slices_started = 1; + } + exchg_clk_wait_on(slices_used); + exchg_clk_cleanup(slices_used); + + regs[0].reg_addr = &SLICE_SHD(SWDIO_TMS_DOUT0); + regs[0].slice_mask = SLICE_SWDIO_TMS_DOUT0_MASK; + + regs[1].reg_addr = &SLICE_SHD(SWDIO_TMS_DOUT1); + regs[1].slice_mask = SLICE_SWDIO_TMS_DOUT1_MASK; + regs_len = 2; + continue; + } + + if (bytes_remaining - 4*bytes_it && bytes_it < regs_len) + { + // 2 + putU32(bytes_remaining - 4*bytes_it, data + data_it, regs[bytes_it].reg_addr); + slices_used |= regs[bytes_it].slice_mask; + bits_it = bits_sz; + data_it += bytes_remaining - 4*bytes_it; + } + if (!slices_started) + { + exchg_clk_cleanup(SLICE_SWCLK_TCK_MASK | SLICE_SWDIO_TXEN_MASK | slices_used); + slice_pos_oneshot(SLICE_SWCLK_TCK_MASK);// | SLICE_SWDIO_TXEN_MASK); + shift_clk_kickoff(SLICE_SWCLK_TCK_MASK | SLICE_SWDIO_TXEN_MASK | slices_used); + slices_started = 1; + } + exchg_clk_wait_on(slices_used); + exchg_clk_cleanup(slices_used); + SLICE_SHD(SWDIO_TMS_DOUT0) = 1; + SLICE_SHD(SWDIO_TMS_DOUT1) = 1; + exchg_clk_wait_on(SLICE_SWCLK_TCK_MASK); + } + + shift_clk_disable(SLICE_SWDIO_TMS_DOUT0_MASK | SLICE_SWDIO_TMS_DOUT1_MASK | SLICE_SWCLK_TCK_MASK | SLICE_SWDIO_TXEN_MASK | SLICE_SWDIO_TMS_OE_MASK); + slice_pos_disable(SLICE_SWDIO_TMS_DOUT0_MASK | SLICE_SWDIO_TMS_DOUT1_MASK | SLICE_SWCLK_TCK_MASK | SLICE_SWDIO_TXEN_MASK | SLICE_SWDIO_TMS_OE_MASK); +} + + + +// bits IN -> SLICE_H -> SLICE_P +static void sequence_read(uint32_t bits_sz, uint8_t *data) +{ +#if 0 + + uint8_t bits_it = 0; + uint8_t data_it = 0; + uint32_t slices_used; + + // drive the Clock + SLICE_POS(SWCLK_TCK) = POS_POS(bits_sz) | POS_PRESET(0); + SLICE_CNT(SWCLK_TCK) = 0; + + // Disable Output. + SLICE_POS(SWDIO_TMS_OE) = POS_POS(0) | POS_PRESET(0); + SLICE_CNT(SWDIO_TMS_OE) = 0; + SLICE_REG(SWDIO_TMS_OE) = 0; + SLICE_SHD(SWDIO_TMS_OE) = 0; + + // Disable TXEN. + SLICE_POS(SWDIO_TXEN) = POS_POS(0) | POS_PRESET(0); + SLICE_CNT(SWDIO_TXEN) = 0; + SLICE_SHD(SWDIO_TXEN) = 0; + + SLICE_POS(SWDIO_TMS_DIN1) = POS_POS(64) | POS_PRESET(64); + SLICE_POS(SWDIO_TMS_DIN0) = POS_POS(64) | POS_PRESET(64); + + slice_pos_oneshot(SLICE_SWCLK_TCK_MASK); + shift_clk_kickoff(SLICE_SWDIO_TMS_DIN0_MASK | SLICE_SWDIO_TMS_DIN1_MASK | SLICE_SWCLK_TCK_MASK); + + exchg_clk_wait_on(SLICE_SWCLK_TCK_MASK); + shift_clk_disable(SLICE_SWDIO_TMS_DIN0_MASK | SLICE_SWDIO_TMS_DIN1_MASK | SLICE_SWCLK_TCK_MASK); + slice_pos_disable(SLICE_SWDIO_TMS_DIN0_MASK | SLICE_SWDIO_TMS_DIN1_MASK | SLICE_SWCLK_TCK_MASK); +#endif +#if 0 + volatile uint32_t* regs[] = { + &SLICE_REG(SWDIO_TMS_DIN1), + &SLICE_REG(SWDIO_TMS_DIN0), + &SLICE_SHD(SWDIO_TMS_DIN1), + &SLICE_SHD(SWDIO_TMS_DIN0) + }; + uint32_t slices_started = 0; + size_t regs_len = 4; + + while (bits_it < bits_sz) + { + uint32_t bits_remaining = bits_sz - bits_it; + uint32_t bytes_remaining = (bits_remaining + 7) / 8; + uint32_t i = 0; + + while ((i < bytes_remaining/4) && (i < regs_len)) + { + getU32(4, *regs[i], data + data_it); + bits_it += 4*8; + data_it += 4; + i += 1; + } + + if (bytes_remaining > 16) + { + if (!slices_started) + { + slice_pos_oneshot(SLICE_SWCLK_TCK_MASK); + shift_clk_kickoff(SLICE_SWDIO_TMS_DIN1_MASK | SLICE_SWDIO_TMS_DIN0_MASK | SLICE_SWCLK_TCK_MASK | SLICE_SWDIO_TXEN_MASK); + slices_started = 1; + } + exchg_clk_wait_on(SLICE_SWDIO_TMS_DIN1_MASK | SLICE_SWDIO_TMS_DIN0_MASK); + exchg_clk_cleanup(SLICE_SWDIO_TMS_DIN1_MASK | SLICE_SWDIO_TMS_DIN0_MASK); + regs[0] = &SLICE_SHD(SWDIO_TMS_DIN1); + regs[1] = &SLICE_SHD(SWDIO_TMS_DIN0); + regs_len = 2; + continue; + } + + if (bytes_remaining - 4*i && i < regs_len) + { + getU32(bytes_remaining - 4*i, *regs[i], data + data_it); + bits_it = bits_sz; + data_it += bytes_remaining - 4*i; + } + if (!slices_started) + { + slice_pos_oneshot(SLICE_SWCLK_TCK_MASK); + shift_clk_kickoff(SLICE_SWDIO_TMS_DIN1_MASK | SLICE_SWDIO_TMS_DIN0_MASK | SLICE_SWCLK_TCK_MASK | SLICE_SWDIO_TXEN_MASK); + slices_started = 1; + } + exchg_clk_wait_on(SLICE_SWDIO_TMS_DIN1_MASK | SLICE_SWDIO_TMS_DIN0_MASK); + exchg_clk_cleanup(SLICE_SWDIO_TMS_DIN1_MASK | SLICE_SWDIO_TMS_DIN0_MASK); + if (bits_it >= bits_sz) + { + SLICE_SHD(SWDIO_TMS_DIN1) = 0; + SLICE_SHD(SWDIO_TMS_DIN0) = 0; + //After completing a transaction, the host must either insert idle cycles. + //If the host is driving the SWD clock, continue to clock. + //the SWD interface with at least eight idle cycles. + //After completing this sequence, the host can stop the clock. + //wait for the last SS regs to be sent. + slice_pos_oneshot(SLICE_SWDIO_TMS_DIN1_MASK | SLICE_SWDIO_TMS_DIN0_MASK); + exchg_clk_wait_on(SLICE_SWCLK_TCK_MASK); + //exchg_clk_cleanup(SLICE_SWCLK_TCK_MASK | SLICE_SWDIO_TMS_DIN1_MASK | SLICE_SWDIO_TMS_DIN0_MASK); + } + } + shift_clk_disable(SLICE_SWDIO_TMS_DIN1_MASK | SLICE_SWDIO_TMS_DIN0_MASK | SLICE_SWCLK_TCK_MASK | SLICE_SWDIO_TXEN_MASK); + slice_pos_disable(SLICE_SWDIO_TMS_DIN1_MASK | SLICE_SWDIO_TMS_DIN0_MASK | SLICE_SWCLK_TCK_MASK | SLICE_SWDIO_TXEN_MASK); +#endif +} + + + +// Figure B4-1 SWD successful write operation, pg112 +// Read HDR T ACK Data T +// Send HDR T ACK T Data +// Wait HDR T ACK T +static uint8_t transfer_send(uint32_t hdr, uint32_t *data) +{ + uint32_t ack = DAP_TRANSFER_FAULT; + uint32_t pkt[2]; + uint32_t bit, parity = 0; + + SLICE_POS(SWDIO_TXEN) = POS_POS(8) | POS_PRESET(0); + SLICE_REG(SWDIO_TXEN) = 0b00000000000000001111111111111111; + SLICE_SHD(SWDIO_TXEN) = 0; + SLICE_CNT(SWDIO_TXEN) = 0; + + SLICE_POS(SWDIO_TMS_OE) = POS_POS(8) | POS_PRESET(0); + SLICE_REG(SWDIO_TMS_OE) = 0b00000000000000000000000011111111; + SLICE_SHD(SWDIO_TMS_OE) = 0; + SLICE_CNT(SWDIO_TMS_OE) = 0; + + // header:8 + SLICE_POS(SWDIO_TMS_DOUT0) = POS_POS(8) | POS_PRESET(0); + SLICE_REG(SWDIO_TMS_DOUT0) = hdr; + SLICE_SHD(SWDIO_TMS_DOUT0) = 0; + SLICE_CNT(SWDIO_TMS_DOUT0) = 0; + + // header:8 turnaround:1 ack:3 + SLICE_POS(SWDIO_TMS_DIN0) = POS_POS(8 + DAP_Data.swd_conf.turnaround + 3) | POS_PRESET(0); + SLICE_CNT(SWDIO_TMS_DIN0) = 0; + + // header:8 turnaround:1 ack:3 turnaround:1 + SLICE_POS(SWCLK_TCK) = POS_POS(8 + DAP_Data.swd_conf.turnaround + 3 + DAP_Data.swd_conf.turnaround) | POS_PRESET(0); + SLICE_CNT(SWCLK_TCK) = 0; + + exchg_clk_cleanup(SLICE_SWDIO_TMS_DOUT0_MASK | SLICE_SWDIO_TMS_DIN0_MASK | SLICE_SWCLK_TCK_MASK | SLICE_SWDIO_TXEN_MASK | SLICE_SWDIO_TMS_OE_MASK); + slice_pos_oneshot(SLICE_SWDIO_TMS_DOUT0_MASK | SLICE_SWDIO_TMS_DIN0_MASK | SLICE_SWCLK_TCK_MASK | SLICE_SWDIO_TXEN_MASK | SLICE_SWDIO_TMS_OE_MASK); + shift_clk_kickoff(SLICE_SWDIO_TMS_DOUT0_MASK | SLICE_SWDIO_TMS_DIN0_MASK | SLICE_SWCLK_TCK_MASK | SLICE_SWDIO_TXEN_MASK | SLICE_SWDIO_TMS_OE_MASK); + + exchg_clk_wait_on(SLICE_SWCLK_TCK_MASK); + + shift_clk_disable(SLICE_SWDIO_TMS_DOUT0_MASK | SLICE_SWDIO_TMS_DIN0_MASK | SLICE_SWCLK_TCK_MASK | SLICE_SWDIO_TXEN_MASK | SLICE_SWDIO_TMS_OE_MASK); + slice_pos_disable(SLICE_SWDIO_TMS_DOUT0_MASK | SLICE_SWDIO_TMS_DIN0_MASK | SLICE_SWCLK_TCK_MASK | SLICE_SWDIO_TXEN_MASK | SLICE_SWDIO_TMS_OE_MASK); + + pkt[0] = SLICE_SHD(SWDIO_TMS_DIN0); + ack = (pkt[0] >> 28) & 0b111; + if (ack == DAP_TRANSFER_WAIT || ack == DAP_TRANSFER_FAULT) + { + if (DAP_Data.swd_conf.data_phase == 0) + return ack; + } + else if (ack != DAP_TRANSFER_OK) + { + line_turnaround(DAP_Data.swd_conf.turnaround + 32U + 1U); + return ack; + } + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + // handle DAP_TRANSFER_FAULT + // check parity + + if (data) + parity = PARITY_U32(*data); + + SLICE_POS(SWDIO_TMS_DOUT0) = POS_POS(32 + 1) | POS_PRESET(0); + SLICE_REG(SWDIO_TMS_DOUT0) = *data; + SLICE_CNT(SWDIO_TMS_DOUT0) = 0; + + SLICE_POS(SWDIO_TMS_DOUT1) = POS_POS(32 + 1) | POS_PRESET(0); + SLICE_REG(SWDIO_TMS_DOUT1) = 0xFFFFFFFF & parity; + SLICE_CNT(SWDIO_TMS_DOUT1) = 0; + + SLICE_POS(SWDIO_TXEN) = POS_POS(32) | POS_PRESET(32); + SLICE_REG(SWDIO_TXEN) = 0xFFFFFFFF; + SLICE_SHD(SWDIO_TXEN) = 0xFFFFFFFF; + SLICE_CNT(SWDIO_TXEN) = 0; + + SLICE_POS(SWDIO_TMS_OE) = POS_POS(32) | POS_PRESET(32); + SLICE_REG(SWDIO_TMS_OE) = 0xFFFFFFFF; + SLICE_SHD(SWDIO_TMS_OE) = 0xFFFFFFFF; + SLICE_CNT(SWDIO_TMS_OE) = 0; + + // data:32 parity:1 + SLICE_POS(SWCLK_TCK) = POS_POS(32 + 1) | POS_PRESET(0); + SLICE_CNT(SWCLK_TCK) = 0; + + exchg_clk_cleanup(SLICE_SWDIO_TMS_DOUT0_MASK | SLICE_SWDIO_TMS_DOUT1_MASK | SLICE_SWCLK_TCK_MASK | SLICE_SWDIO_TXEN_MASK | SLICE_SWDIO_TMS_OE_MASK); + slice_pos_oneshot(SLICE_SWDIO_TMS_DOUT0_MASK | SLICE_SWDIO_TMS_DOUT1_MASK | SLICE_SWCLK_TCK_MASK); + shift_clk_kickoff(SLICE_SWDIO_TMS_DOUT0_MASK | SLICE_SWDIO_TMS_DOUT1_MASK | SLICE_SWCLK_TCK_MASK | SLICE_SWDIO_TXEN_MASK | SLICE_SWDIO_TMS_OE_MASK); + + exchg_clk_wait_on(SLICE_SWCLK_TCK_MASK); + + shift_clk_disable(SLICE_SWDIO_TMS_DOUT0_MASK | SLICE_SWDIO_TMS_DOUT1_MASK | SLICE_SWCLK_TCK_MASK | SLICE_SWDIO_TXEN_MASK | SLICE_SWDIO_TMS_OE_MASK); + slice_pos_disable(SLICE_SWDIO_TMS_DOUT0_MASK | SLICE_SWDIO_TMS_DOUT1_MASK | SLICE_SWCLK_TCK_MASK | SLICE_SWDIO_TXEN_MASK | SLICE_SWDIO_TMS_OE_MASK); + + SLICE_REG(SWDIO_TMS_DOUT0) = 1; + SLICE_REG(SWDIO_TMS_DOUT1) = 1; + SLICE_REG(SWDIO_TMS_OE) = 1; + SLICE_REG(SWDIO_TXEN) = 1; + + //if (DAP_Data.transfer.idle_cycles) { + // idle_cycles(DAP_Data.transfer.idle_cycles); + //} + + return ack; +} + +// 3c e7 +// 0011110011100111 + +// Figure B4-2 SWD successful read operation, pg112 +static uint8_t transfer_read(uint32_t hdr, uint32_t *data) +{ + uint32_t ack = DAP_TRANSFER_FAULT; + uint32_t pkt[2]; + uint32_t bit; + + SLICE_POS(SWDIO_TXEN) = POS_POS(8) | POS_PRESET(0); + SLICE_REG(SWDIO_TXEN) = 0b00000000000000001111111111111111; + SLICE_SHD(SWDIO_TXEN) = 0; + SLICE_CNT(SWDIO_TXEN) = 0; + + SLICE_POS(SWDIO_TMS_OE) = POS_POS(8) | POS_PRESET(0); + SLICE_REG(SWDIO_TMS_OE) = 0b00000000000000000000000011111111; + SLICE_SHD(SWDIO_TMS_OE) = 0; + SLICE_CNT(SWDIO_TMS_OE) = 0; + + // header:8 + SLICE_POS(SWDIO_TMS_DOUT0) = POS_POS(8) | POS_PRESET(0); + SLICE_REG(SWDIO_TMS_DOUT0) = hdr; + SLICE_SHD(SWDIO_TMS_DOUT0) = 0; + SLICE_CNT(SWDIO_TMS_DOUT0) = 0; + + // header:8 turnaround:1 ack:3 + SLICE_POS(SWDIO_TMS_DIN0) = POS_POS(8 + DAP_Data.swd_conf.turnaround + 3) | POS_PRESET(0); + SLICE_CNT(SWDIO_TMS_DIN0) = 0; + + // header:8 turnaround:1 ack:3 + SLICE_POS(SWCLK_TCK) = POS_POS(8 + DAP_Data.swd_conf.turnaround + 3) | POS_PRESET(0); + SLICE_CNT(SWCLK_TCK) = 0; + + exchg_clk_cleanup(SLICE_SWDIO_TMS_DOUT0_MASK | SLICE_SWDIO_TMS_DIN0_MASK | SLICE_SWCLK_TCK_MASK | SLICE_SWDIO_TXEN_MASK | SLICE_SWDIO_TMS_OE_MASK); + slice_pos_oneshot(SLICE_SWDIO_TMS_DOUT0_MASK | SLICE_SWDIO_TMS_DIN0_MASK | SLICE_SWCLK_TCK_MASK | SLICE_SWDIO_TXEN_MASK | SLICE_SWDIO_TMS_OE_MASK); + shift_clk_kickoff(SLICE_SWDIO_TMS_DOUT0_MASK | SLICE_SWDIO_TMS_DIN0_MASK | SLICE_SWCLK_TCK_MASK | SLICE_SWDIO_TXEN_MASK | SLICE_SWDIO_TMS_OE_MASK); + + exchg_clk_wait_on(SLICE_SWCLK_TCK_MASK); + + shift_clk_disable(SLICE_SWDIO_TMS_DOUT0_MASK | SLICE_SWDIO_TMS_DIN0_MASK | SLICE_SWCLK_TCK_MASK | SLICE_SWDIO_TXEN_MASK | SLICE_SWDIO_TMS_OE_MASK); + slice_pos_disable(SLICE_SWDIO_TMS_DOUT0_MASK | SLICE_SWDIO_TMS_DIN0_MASK | SLICE_SWCLK_TCK_MASK | SLICE_SWDIO_TXEN_MASK | SLICE_SWDIO_TMS_OE_MASK); + + pkt[0] = SLICE_SHD(SWDIO_TMS_DIN0); + ack = (pkt[0] >> 28) & 0b111; + if (ack == DAP_TRANSFER_WAIT || ack == DAP_TRANSFER_FAULT) + { + line_turnaround(DAP_Data.swd_conf.turnaround); + if (DAP_Data.swd_conf.data_phase == 0) + return ack; + } + else if (ack != DAP_TRANSFER_OK) + { + line_turnaround(DAP_Data.swd_conf.turnaround + 32U + 2U); + return ack; + } + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + // handle DAP_TRANSFER_FAULT + // check parity + + if (data) + *data = pkt[0]>>31; + + SLICE_REG(SWDIO_TMS_DOUT0) = 0; + SLICE_REG(SWDIO_TMS_DOUT1) = 0; + SLICE_REG(SWDIO_TMS_OE) = 0; + SLICE_REG(SWDIO_TXEN) = 0; + + pkt[0] = 0; + pkt[1] = 0; + + // data:32 parity:1 + SLICE_POS(SWDIO_TMS_DIN0) = POS_POS(32 + 1) | POS_PRESET(0); + SLICE_REG(SWDIO_TMS_DIN0) = 0; + SLICE_SHD(SWDIO_TMS_DIN0) = 0; + SLICE_CNT(SWDIO_TMS_DIN0) = 0; + SLICE_POS(SWDIO_TMS_DIN1) = POS_POS(32 + 1) | POS_PRESET(0); + SLICE_REG(SWDIO_TMS_DIN1) = 0; + SLICE_SHD(SWDIO_TMS_DIN1) = 0; + SLICE_CNT(SWDIO_TMS_DIN1) = 0; + + // data:32 parity:1 turnaround:1 + SLICE_POS(SWCLK_TCK) = POS_POS(32 + 1 + DAP_Data.swd_conf.turnaround) | POS_PRESET(0); + + exchg_clk_cleanup(SLICE_SWDIO_TMS_DIN0_MASK | SLICE_SWDIO_TMS_DIN1_MASK | SLICE_SWCLK_TCK_MASK | SLICE_SWDIO_TXEN_MASK | SLICE_SWDIO_TMS_OE_MASK); + slice_pos_oneshot(SLICE_SWDIO_TMS_DIN0_MASK | SLICE_SWDIO_TMS_DIN1_MASK | SLICE_SWCLK_TCK_MASK); + shift_clk_kickoff(SLICE_SWDIO_TMS_DIN0_MASK | SLICE_SWDIO_TMS_DIN1_MASK | SLICE_SWCLK_TCK_MASK | SLICE_SWDIO_TXEN_MASK | SLICE_SWDIO_TMS_OE_MASK); + + exchg_clk_wait_on(SLICE_SWCLK_TCK_MASK); + + shift_clk_disable(SLICE_SWDIO_TMS_DIN0_MASK | SLICE_SWDIO_TMS_DIN1_MASK | SLICE_SWCLK_TCK_MASK | SLICE_SWDIO_TXEN_MASK | SLICE_SWDIO_TMS_OE_MASK); + slice_pos_disable(SLICE_SWDIO_TMS_DIN0_MASK | SLICE_SWDIO_TMS_DIN1_MASK | SLICE_SWCLK_TCK_MASK | SLICE_SWDIO_TXEN_MASK | SLICE_SWDIO_TMS_OE_MASK); + + pkt[0] = SLICE_SHD(SWDIO_TMS_DIN0); + pkt[1] = SLICE_SHD(SWDIO_TMS_DIN1); + + if (data) + *data |= (pkt[0] << 2) | (pkt[1]>>30); + + return ack; +} + + + +// Configures all slices, muxes, etc. +// Ensures that outputs are enabled and SWDIO and SWCLK are high +// Slice concatenation is set by register SGPIO_MUX_CFG (Table 275 and Table 276). +// The field CONCAT_ENABLE enables this feature. +// When multiple slices are concatenated, this field +// should be set the same for all involved slices. +// The field CONCAT_ORDER sets the concatenation size. +void sgpio_init(void) +{ + shift_clk_int_off(0xFFFF); + exchg_clk_int_off(0xFFFF); + slice_pos_disable(0xFFFF); + shift_clk_disable(0xFFFF); + + LPC_SGPIO->OUT_MUX_CFG[SGPIO_SWCLK_TCK] = OUT_MUX_CFG_CLK_OUT + | OUT_MUX_CFG_GPIO_OE; + LPC_SGPIO->SGPIO_MUX_CFG[SLICE_SWCLK_TCK] = SGPIO_MUX_CFG_EXT_CLK_ENABLE_INTERNAL + | SGPIO_MUX_CFG_CLK_SOURCE_PIN_MODE_8 + | SGPIO_MUX_CFG_CLK_SOURCE_SLICE_MODE_D + | SGPIO_MUX_CFG_QUALIFIER_MODE_DEFAULT + | SGPIO_MUX_CFG_QUALIFIER_PIN_MODE_8 + | SGPIO_MUX_CFG_QUALIFIER_SLICE_MODE_A + | SGPIO_MUX_CFG_CONCAT_DISABLE + | SGPIO_MUX_CFG_CONCAT_ORDER_LOOP + ; + + LPC_SGPIO->SLICE_MUX_CFG[SLICE_SWCLK_TCK] = SLICE_MUX_CFG_MATCH_MODE_DISABLED + | SLICE_MUX_CFG_CLK_CAPTURE_MODE_RISING + | SLICE_MUX_CFG_CLKGEN_MODE_INTERNAL + | SLICE_MUX_CFG_INV_OUT_CLK_INVERTED + | SLICE_MUX_CFG_DATA_CAPTURE_MODE_RISING + | SLICE_MUX_CFG_PARALLEL_MODE_1BPCLK + | SLICE_MUX_CFG_INV_QUALIFIER_NORMAL + ; + + // SWDIO/TXEN (SGPIO15). + LPC_SGPIO->OUT_MUX_CFG[SGPIO_SWDIO_TXEN] = OUT_MUX_CFG_DOUT_DOUTM8B + | OUT_MUX_CFG_GPIO_OE; + LPC_SGPIO->SGPIO_MUX_CFG[SLICE_SWDIO_TXEN] = SGPIO_MUX_CFG_EXT_CLK_ENABLE_EXTERNAL + | SGPIO_MUX_CFG_CLK_SOURCE_PIN_MODE_11 + | SGPIO_MUX_CFG_CLK_SOURCE_SLICE_MODE_D + | SGPIO_MUX_CFG_QUALIFIER_MODE_DEFAULT + | SGPIO_MUX_CFG_QUALIFIER_PIN_MODE_8 + | SGPIO_MUX_CFG_QUALIFIER_SLICE_MODE_A + | SGPIO_MUX_CFG_CONCAT_ENABLE + | SGPIO_MUX_CFG_CONCAT_ORDER_LOOP + ; + + LPC_SGPIO->SLICE_MUX_CFG[SLICE_SWDIO_TXEN] = SLICE_MUX_CFG_MATCH_MODE_DISABLED + | SLICE_MUX_CFG_CLK_CAPTURE_MODE_RISING + | SLICE_MUX_CFG_CLKGEN_MODE_EXTERNAL + | SLICE_MUX_CFG_INV_OUT_CLK_INVERTED + | SLICE_MUX_CFG_DATA_CAPTURE_MODE_RISING + | SLICE_MUX_CFG_PARALLEL_MODE_1BPCLK + | SLICE_MUX_CFG_INV_QUALIFIER_NORMAL + ; + + // output-enable slice configuration. + LPC_SGPIO->SGPIO_MUX_CFG[SLICE_SWDIO_TMS_OE] = SGPIO_MUX_CFG_EXT_CLK_ENABLE_EXTERNAL + | SGPIO_MUX_CFG_CLK_SOURCE_PIN_MODE_11 + | SGPIO_MUX_CFG_CLK_SOURCE_SLICE_MODE_D + | SGPIO_MUX_CFG_QUALIFIER_MODE_DEFAULT + | SGPIO_MUX_CFG_QUALIFIER_PIN_MODE_8 + | SGPIO_MUX_CFG_QUALIFIER_SLICE_MODE_A + | SGPIO_MUX_CFG_CONCAT_ENABLE + | SGPIO_MUX_CFG_CONCAT_ORDER_LOOP + ; + + LPC_SGPIO->SLICE_MUX_CFG[SLICE_SWDIO_TMS_OE] = SLICE_MUX_CFG_MATCH_MODE_DISABLED + | SLICE_MUX_CFG_CLK_CAPTURE_MODE_RISING + | SLICE_MUX_CFG_CLKGEN_MODE_EXTERNAL + | SLICE_MUX_CFG_INV_OUT_CLK_INVERTED + | SLICE_MUX_CFG_DATA_CAPTURE_MODE_RISING + | SLICE_MUX_CFG_PARALLEL_MODE_1BPCLK + | SLICE_MUX_CFG_INV_QUALIFIER_NORMAL + ; + + // SWDIO/TMS (SGPIO14). Table 276. + LPC_SGPIO->OUT_MUX_CFG[SGPIO_SWDIO_TMS] = OUT_MUX_CFG_DOUT_DOUTM2C + | OUT_MUX_CFG_DOUT_OEM1; + // input slice configuration. + LPC_SGPIO->SGPIO_MUX_CFG[SLICE_SWDIO_TMS_DIN0] = SGPIO_MUX_CFG_EXT_CLK_ENABLE_EXTERNAL + | SGPIO_MUX_CFG_CLK_SOURCE_PIN_MODE_11 + | SGPIO_MUX_CFG_CLK_SOURCE_SLICE_MODE_D + | SGPIO_MUX_CFG_QUALIFIER_MODE_DEFAULT + | SGPIO_MUX_CFG_QUALIFIER_PIN_MODE_8 + | SGPIO_MUX_CFG_QUALIFIER_SLICE_MODE_A + | SGPIO_MUX_CFG_CONCAT_EXT_PIN + | SGPIO_MUX_CFG_CONCAT_ORDER_LOOP + ; + LPC_SGPIO->SGPIO_MUX_CFG[SLICE_SWDIO_TMS_DIN1] = SGPIO_MUX_CFG_EXT_CLK_ENABLE_EXTERNAL + | SGPIO_MUX_CFG_CLK_SOURCE_PIN_MODE_11 + | SGPIO_MUX_CFG_CLK_SOURCE_SLICE_MODE_D + | SGPIO_MUX_CFG_QUALIFIER_MODE_DEFAULT + | SGPIO_MUX_CFG_QUALIFIER_PIN_MODE_8 + | SGPIO_MUX_CFG_QUALIFIER_SLICE_MODE_A + | SGPIO_MUX_CFG_CONCAT_ENABLE + | SGPIO_MUX_CFG_CONCAT_ORDER_2SLC + ; + LPC_SGPIO->SLICE_MUX_CFG[SLICE_SWDIO_TMS_DIN0] = SLICE_MUX_CFG_MATCH_MODE_DISABLED + | SLICE_MUX_CFG_CLK_CAPTURE_MODE_RISING + | SLICE_MUX_CFG_CLKGEN_MODE_EXTERNAL + | SLICE_MUX_CFG_INV_OUT_CLK_INVERTED + | SLICE_MUX_CFG_DATA_CAPTURE_MODE_RISING + | SLICE_MUX_CFG_PARALLEL_MODE_1BPCLK + | SLICE_MUX_CFG_INV_QUALIFIER_NORMAL + ; + LPC_SGPIO->SLICE_MUX_CFG[SLICE_SWDIO_TMS_DIN1] = SLICE_MUX_CFG_MATCH_MODE_DISABLED + | SLICE_MUX_CFG_CLK_CAPTURE_MODE_RISING + | SLICE_MUX_CFG_CLKGEN_MODE_EXTERNAL + | SLICE_MUX_CFG_INV_OUT_CLK_INVERTED + | SLICE_MUX_CFG_DATA_CAPTURE_MODE_RISING + | SLICE_MUX_CFG_PARALLEL_MODE_1BPCLK + | SLICE_MUX_CFG_INV_QUALIFIER_NORMAL + ; + // output slice configuration. + LPC_SGPIO->SGPIO_MUX_CFG[SLICE_SWDIO_TMS_DOUT1] = SGPIO_MUX_CFG_EXT_CLK_ENABLE_EXTERNAL + | SGPIO_MUX_CFG_CLK_SOURCE_PIN_MODE_11 + | SGPIO_MUX_CFG_CLK_SOURCE_SLICE_MODE_D + | SGPIO_MUX_CFG_QUALIFIER_MODE_DEFAULT + | SGPIO_MUX_CFG_QUALIFIER_PIN_MODE_8 + | SGPIO_MUX_CFG_QUALIFIER_SLICE_MODE_A + | SGPIO_MUX_CFG_CONCAT_ENABLE + | SGPIO_MUX_CFG_CONCAT_ORDER_LOOP + ; + LPC_SGPIO->SGPIO_MUX_CFG[SLICE_SWDIO_TMS_DOUT0] = SGPIO_MUX_CFG_EXT_CLK_ENABLE_EXTERNAL + | SGPIO_MUX_CFG_CLK_SOURCE_PIN_MODE_11 + | SGPIO_MUX_CFG_CLK_SOURCE_SLICE_MODE_D + | SGPIO_MUX_CFG_QUALIFIER_MODE_DEFAULT + | SGPIO_MUX_CFG_QUALIFIER_PIN_MODE_8 + | SGPIO_MUX_CFG_QUALIFIER_SLICE_MODE_A + | SGPIO_MUX_CFG_CONCAT_ENABLE + | SGPIO_MUX_CFG_CONCAT_ORDER_2SLC + ; + LPC_SGPIO->SLICE_MUX_CFG[SLICE_SWDIO_TMS_DOUT1] = SLICE_MUX_CFG_MATCH_MODE_DISABLED + | SLICE_MUX_CFG_CLK_CAPTURE_MODE_RISING + | SLICE_MUX_CFG_CLKGEN_MODE_EXTERNAL + | SLICE_MUX_CFG_INV_OUT_CLK_INVERTED + | SLICE_MUX_CFG_DATA_CAPTURE_MODE_RISING + | SLICE_MUX_CFG_PARALLEL_MODE_1BPCLK + | SLICE_MUX_CFG_INV_QUALIFIER_NORMAL + ; + LPC_SGPIO->SLICE_MUX_CFG[SLICE_SWDIO_TMS_DOUT0] = SLICE_MUX_CFG_MATCH_MODE_DISABLED + | SLICE_MUX_CFG_CLK_CAPTURE_MODE_RISING + | SLICE_MUX_CFG_CLKGEN_MODE_EXTERNAL + | SLICE_MUX_CFG_INV_OUT_CLK_INVERTED + | SLICE_MUX_CFG_DATA_CAPTURE_MODE_RISING + | SLICE_MUX_CFG_PARALLEL_MODE_1BPCLK + | SLICE_MUX_CFG_INV_QUALIFIER_NORMAL + ; + + // Enable SGPIO pins. + sgpio_pin_oenable(SGPIO_SWCLK_TCK); + sgpio_pin_oenable(SGPIO_SWDIO_TXEN); +} + + + +#if ((DAP_SWD != 0) || (DAP_JTAG != 0)) +// Generate SWJ Sequence +// count: Number of bits in sequence: 1..256 (256 encoded as 0) +// data: Sequence generated on SWDIO/TMS (with clock @SWCLK/TCK); LSB is transmitted first. +// return: none +void SWJ_Sequence (uint32_t count, const uint8_t *request) +{ + sequence_send(count, request); +} +#endif + + + +#if (DAP_SWD != 0) +// Generate SWD Sequence +// info: sequence information +// swdo: pointer to SWDIO generated data +// swdi: pointer to SWDIO captured data +// return: none +void SWD_Sequence (uint32_t info, const uint8_t *swdo, uint8_t *swdi) +{ + uint32_t bytes_nb; + bytes_nb = info & SWD_SEQUENCE_CLK; + if (bytes_nb == 0U) { + bytes_nb = 64U; + } + if (info & SWD_SEQUENCE_DIN) { + sequence_read(bytes_nb*8, swdi); + } else { + sequence_send(bytes_nb*8, swdo); + } +} + +// SWD Transfer I/O +// request: A[3:2] RnW APnDP +// data: DATA[31:0] +// return: ACK[2:0] +uint8_t SWD_Transfer(uint32_t request, uint32_t *data) +{ + uint32_t ack = DAP_TRANSFER_OK; + uint32_t parity = PARITY_U32(request & 0xF); + + uint32_t hdr = 1 /* Start Bit */ + | ((request & 0xF) << 1) /* APnDP, RnW, A2, A3 Bits */ + | (parity << 5) /* Parity Bit */ + | (0 << 6) /* Stop Bit */ + | (1 << 7) /* Park Bit */ + ; + + + if (REQUEST_READ(request)) { + ack = transfer_read(hdr, data); + } + if (REQUEST_WRITE(request)) { + ack = transfer_send(hdr, data); + } + if (REQUEST_TIMESTAMP(request)) { + DAP_Data.timestamp = TIMESTAMP_GET(); + } + + return (uint8_t)ack; +} +#endif /* (DAP_SWD != 0) */