diff --git a/firmware/common/cpld_jtag.c b/firmware/common/cpld_jtag.c index 0948858c..478626c3 100644 --- a/firmware/common/cpld_jtag.c +++ b/firmware/common/cpld_jtag.c @@ -29,6 +29,75 @@ static refill_buffer_cb refill_buffer; static uint32_t xsvf_buffer_len, xsvf_pos; static unsigned char* xsvf_buffer; +void cpld_jtag_init(jtag_t* const jtag) { + /* Initialize pin GPIOs in "released" state. */ + cpld_jtag_release(jtag); + + /* TDI and TMS pull-ups are required in all JTAG-compliant devices. + * + * The HackRF CPLD is always present, so let the CPLD pull up its TDI and TMS. + * + * The PortaPack may not be present, so pull up the PortaPack TMS pin from the + * microcontroller. + * + * TCK is recommended to be held low, so use microcontroller pull-down. + * + * TDO is undriven except when in Shift-IR or Shift-DR phases. + * Use the microcontroller to pull down to keep from floating. + * + * LPC43xx pull-up and pull-down resistors are approximately 53K. + */ +#ifdef USER_INTERFACE_PORTAPACK + scu_pinmux(SCU_PINMUX_PP_TMS, SCU_GPIO_PUP | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_PINMUX_PP_TDO, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); +#endif + scu_pinmux(SCU_PINMUX_CPLD_TMS, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_PINMUX_CPLD_TDI, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_PINMUX_CPLD_TDO, SCU_GPIO_PDN | SCU_CONF_FUNCTION4); + scu_pinmux(SCU_PINMUX_CPLD_TCK, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); +} + +void cpld_jtag_take(jtag_t* const jtag) { + const jtag_gpio_t* const gpio = jtag->gpio; + +#ifdef USER_INTERFACE_PORTAPACK + /* Do not drive PortaPack-specific TMS pin initially, just to be cautious. */ + gpio_input(gpio->gpio_pp_tms); + gpio_input(gpio->gpio_pp_tdo); +#endif + gpio_output(gpio->gpio_tms); + gpio_output(gpio->gpio_tdi); + gpio_output(gpio->gpio_tck); + gpio_input(gpio->gpio_tdo); +} + +void cpld_jtag_release(jtag_t* const jtag) { + const jtag_gpio_t* const gpio = jtag->gpio; + + /* Make all pins inputs when JTAG interface not active. + * Let the pull-ups/downs do the work. + */ +#ifdef USER_INTERFACE_PORTAPACK + /* Do not drive PortaPack-specific pins, initially, just to be cautious. */ + gpio_input(gpio->gpio_pp_tms); + gpio_input(gpio->gpio_pp_tdo); +#endif + gpio_input(gpio->gpio_tms); + gpio_input(gpio->gpio_tdi); + gpio_input(gpio->gpio_tck); + gpio_input(gpio->gpio_tdo); + + /* Set initial GPIO state to the voltages of the internal or external pull-ups/downs, + * to avoid any glitches. + */ +#ifdef USER_INTERFACE_PORTAPACK + gpio_set(gpio->gpio_pp_tms); +#endif + gpio_set(gpio->gpio_tms); + gpio_set(gpio->gpio_tdi); + gpio_clear(gpio->gpio_tck); +} + /* return 0 if success else return error code see xsvfExecute() */ int cpld_jtag_program( jtag_t* const jtag, @@ -37,10 +106,12 @@ int cpld_jtag_program( refill_buffer_cb refill ) { int error; + cpld_jtag_take(jtag); xsvf_buffer = buffer; xsvf_buffer_len = buffer_length; refill_buffer = refill; error = xsvfExecute(jtag->gpio); + cpld_jtag_release(jtag); return error; } diff --git a/firmware/common/cpld_jtag.h b/firmware/common/cpld_jtag.h index 04292d22..012b0516 100644 --- a/firmware/common/cpld_jtag.h +++ b/firmware/common/cpld_jtag.h @@ -43,6 +43,10 @@ typedef struct jtag_t { typedef void (*refill_buffer_cb)(void); +void cpld_jtag_init(jtag_t* const jtag); +void cpld_jtag_take(jtag_t* const jtag); +void cpld_jtag_release(jtag_t* const jtag); + /* Return 0 if success else return error code see xsvfExecute() see micro.h. * * We expect the buffer to be initially full of data. After the entire diff --git a/firmware/common/hackrf_core.c b/firmware/common/hackrf_core.c index 74becd01..d363b2ac 100644 --- a/firmware/common/hackrf_core.c +++ b/firmware/common/hackrf_core.c @@ -33,6 +33,7 @@ #include "w25q80bv_target.h" #include "i2c_bus.h" #include "i2c_lpc.h" +#include "cpld_jtag.h" #include #include #include @@ -758,49 +759,11 @@ void ssp1_set_mode_max5864(void) spi_bus_start(max5864.bus, &ssp_config_max5864); } -static void jtag_setup(void) { - /* TDI and TMS pull-ups are required in all JTAG-compliant devices. - * Therefore, do not pull up TDI and TMS on HackRF CPLD, which is always present. - * HackRF TMS and TDI are dedicated, just drive instead of pulling up/down. - * TCK is recommended to be held low. - * TDO is undriven except when in Shift-IR or Shift-DR phases, so pull down to keep from floating. - * Nail down other signals before causing any transitions on TCK, to prevent undesired - * state changes. - */ - /* LPC43xx pull-up and pull-down resistors are approximately 53K. */ -#ifdef USER_INTERFACE_PORTAPACK - gpio_set(jtag_gpio_cpld.gpio_pp_tms); -#endif - gpio_set(jtag_gpio_cpld.gpio_tms); - gpio_set(jtag_gpio_cpld.gpio_tdi); - gpio_clear(jtag_gpio_cpld.gpio_tck); - -#ifdef USER_INTERFACE_PORTAPACK - /* Do not drive PortaPack-specific pins, initially, just to be cautious. */ - gpio_input(jtag_gpio_cpld.gpio_pp_tms); - gpio_input(jtag_gpio_cpld.gpio_pp_tdo); -#endif - gpio_output(jtag_gpio_cpld.gpio_tms); - gpio_output(jtag_gpio_cpld.gpio_tdi); - gpio_output(jtag_gpio_cpld.gpio_tck); - gpio_input(jtag_gpio_cpld.gpio_tdo); - - /* Configure CPLD JTAG pins */ -#ifdef USER_INTERFACE_PORTAPACK - scu_pinmux(SCU_PINMUX_PP_TMS, SCU_GPIO_PUP | SCU_CONF_FUNCTION0); - scu_pinmux(SCU_PINMUX_PP_TDO, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); -#endif - scu_pinmux(SCU_PINMUX_CPLD_TMS, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0); - scu_pinmux(SCU_PINMUX_CPLD_TDI, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0); - scu_pinmux(SCU_PINMUX_CPLD_TDO, SCU_GPIO_PDN | SCU_CONF_FUNCTION4); - scu_pinmux(SCU_PINMUX_CPLD_TCK, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0); -} - void pin_setup(void) { /* Configure all GPIO as Input (safe state) */ gpio_init(); - jtag_setup(); + cpld_jtag_init(&jtag_cpld); /* Configure SCU Pin Mux as GPIO */ scu_pinmux(SCU_PINMUX_LED1, SCU_GPIO_NOPULL); diff --git a/firmware/common/ui_portapack.c b/firmware/common/ui_portapack.c index f5162a40..abee326b 100644 --- a/firmware/common/ui_portapack.c +++ b/firmware/common/ui_portapack.c @@ -503,6 +503,11 @@ static uint32_t jtag_pp_shift(const uint32_t tms_bits, const size_t count) { } static uint32_t jtag_pp_idcode() { + cpld_jtag_take(&jtag_cpld); + + /* TODO: Check if PortaPack TMS is floating or driven by an external device. */ + gpio_output(jtag_cpld.gpio->gpio_pp_tms); + /* Test-Logic/Reset -> Run-Test/Idle -> Select-DR/Scan -> Capture-DR */ jtag_pp_shift(0b11111010, 8); @@ -512,6 +517,8 @@ static uint32_t jtag_pp_idcode() { /* Exit1-DR -> Update-DR -> Run-Test/Idle -> ... -> Test-Logic/Reset */ jtag_pp_shift(0b11011111, 8); + cpld_jtag_release(&jtag_cpld); + return idcode; } @@ -998,9 +1005,6 @@ static const hackrf_ui_t portapack_ui = { }; const hackrf_ui_t* portapack_detect(void) { - /* TODO: Check if PortaPack TMS is floating or driven by an external device. */ - gpio_output(jtag_cpld.gpio->gpio_pp_tms); - if( jtag_pp_idcode() == 0x020A50DD ) { return &portapack_ui; } else {