diff --git a/src/lmi.c b/src/lmi.c index cb620c0..a08819e 100644 --- a/src/lmi.c +++ b/src/lmi.c @@ -38,7 +38,7 @@ static int lmi_flash_erase(struct target_s *target, uint32_t addr, int len); static int lmi_flash_write(struct target_s *target, uint32_t dest, const uint8_t *src, int len); -static const char lmi_driver_str[] = "LuminaryMicro Stellaris"; +static const char lmi_driver_str[] = "TI Stellaris/Tiva"; static const char lmi_xml_memory_map[] = "" /* "" " " ""; +static const char tm4c123gh6pm_xml_memory_map[] = "" +/* ""*/ + "" + " " + " 0x400" + " " + " " + ""; + uint16_t lmi_flash_write_stub[] = { // _start: @@ -100,6 +111,13 @@ bool lmi_probe(struct target_s *target) target->flash_erase = lmi_flash_erase; target->flash_write = lmi_flash_write; return true; + + case 0x10A1: /* TM4C123GH6PM */ + target->driver = lmi_driver_str; + target->xml_mem_map = tm4c123gh6pm_xml_memory_map; + target->flash_erase = lmi_flash_erase; + target->flash_write = lmi_flash_write; + return true; } return false; } diff --git a/src/platforms/launchpad-icdi/Makefile.inc b/src/platforms/launchpad-icdi/Makefile.inc new file mode 100644 index 0000000..8a0f9a3 --- /dev/null +++ b/src/platforms/launchpad-icdi/Makefile.inc @@ -0,0 +1,23 @@ +CROSS_COMPILE ?= arm-none-eabi- +CC = $(CROSS_COMPILE)gcc +OBJCOPY = $(CROSS_COMPILE)objcopy + +INCLUDES = -I../libopencm3/include + +CPU_FLAGS = -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard +CFLAGS += $(INCLUDES) $(CPU_FLAGS) -DTARGET_IS_BLIZZARD_RB1 -DLM4F -DPART_TM4C123GH6PM + +LINKER_SCRIPT="platforms/tm4c/tm4c.ld" +LDFLAGS = -nostartfiles -lc $(CPU_FLAGS) -nodefaultlibs -T$(LINKER_SCRIPT) -Wl,--gc-sections \ + -L../libopencm3/lib -lopencm3_lm4f -lnosys -lm -lgcc + +VPATH += platforms/tm4c + +SRC += cdcacm.c \ + usbuart.c \ + traceswo.o + +all: blackmagic.bin + +blackmagic.bin: blackmagic + $(OBJCOPY) -O binary $^ $@ diff --git a/src/platforms/launchpad-icdi/platform.c b/src/platforms/launchpad-icdi/platform.c new file mode 100644 index 0000000..848271e --- /dev/null +++ b/src/platforms/launchpad-icdi/platform.c @@ -0,0 +1,86 @@ +#include "platform.h" +#include "gdb_if.h" +#include "usbuart.h" + +#include +#include +#include +#include + +#define SYSTICKHZ 100 +#define SYSTICKMS (1000 / SYSTICKHZ) + +#define PLL_DIV_80MHZ 5 +#define PLL_DIV_25MHZ 16 + +extern void trace_tick(void); + +jmp_buf fatal_error_jmpbuf; +uint8_t running_status; +volatile uint32_t timeout_counter; + +const char *morse_msg; + +void morse(const char *msg, char repeat) +{ + (void) msg; + (void) repeat; +} + +void sys_tick_handler(void) +{ + if(timeout_counter) + timeout_counter--; + trace_tick(); +} + +int +platform_init(void) +{ + int i; + for(i=0; i<1000000; i++); + + rcc_sysclk_config(OSCSRC_MOSC, XTAL_16M, PLL_DIV_80MHZ); + + // Enable all JTAG ports and set pins to output + periph_clock_enable(RCC_GPIOA); + periph_clock_enable(RCC_GPIOB); + + gpio_enable_ahb_aperture(); + + gpio_mode_setup(TMS_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, TMS_PIN); + gpio_mode_setup(TCK_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, TCK_PIN); + gpio_mode_setup(TDI_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, TDI_PIN); + gpio_mode_setup(TDO_PORT, GPIO_MODE_INPUT, GPIO_PUPD_NONE, TDO_PIN); + gpio_mode_setup(SRST_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, SRST_PIN); + gpio_set_output_config(SRST_PORT, GPIO_OTYPE_OD, GPIO_DRIVE_2MA, SRST_PIN); + gpio_set(SRST_PORT, SRST_PIN); + + systick_set_clocksource(STK_CSR_CLKSOURCE_AHB_DIV8); + systick_set_reload(rcc_get_system_clock_frequency() / (SYSTICKHZ * 8)); + + systick_interrupt_enable(); + systick_counter_enable(); + + nvic_enable_irq(NVIC_SYSTICK_IRQ); + nvic_enable_irq(NVIC_UART0_IRQ); + + usbuart_init(); + cdcacm_init(); + + //jtag_scan(NULL); + + return 0; +} + +void platform_delay(uint32_t delay) +{ + timeout_counter = delay * 10; + while(timeout_counter); +} + +const char *platform_target_voltage(void) +{ + return "not supported"; +} + diff --git a/src/platforms/launchpad-icdi/platform.h b/src/platforms/launchpad-icdi/platform.h new file mode 100644 index 0000000..7f5d55f --- /dev/null +++ b/src/platforms/launchpad-icdi/platform.h @@ -0,0 +1,137 @@ +#ifndef __PLATFORM_H +#define __PLATFORM_H + +#include + +#include +#include + +#include +#include + +#include "gdb_packet.h" + +#define CDCACM_PACKET_SIZE 64 +#define BOARD_IDENT "Black Magic Probe (Launchpad ICDI), (Firmware 1.5" VERSION_SUFFIX ", build " BUILDDATE ")" +#define BOARD_IDENT_DFU "Black Magic (Upgrade) for Launchpad, (Firmware 1.5" VERSION_SUFFIX ", build " BUILDDATE ")" +#define DFU_IDENT "Black Magic Firmware Upgrade (Launchpad)" +#define DFU_IFACE_STRING "lolwut" + +extern usbd_device *usbdev; +#define CDCACM_GDB_ENDPOINT 1 +#define CDCACM_UART_ENDPOINT 3 + +extern jmp_buf fatal_error_jmpbuf; +extern uint8_t running_status; +extern const char *morse_msg; +extern volatile uint32_t timeout_counter; + +#define TMS_PORT GPIOA_BASE +#define TMS_PIN GPIO3 + +#define TCK_PORT GPIOA_BASE +#define TCK_PIN GPIO2 + +#define TDI_PORT GPIOA_BASE +#define TDI_PIN GPIO5 + +#define TDO_PORT GPIOA_BASE +#define TDO_PIN GPIO4 + +#define SWO_PORT GPIOD_BASE +#define SWO_PIN GPIO6 + +#define SWDIO_PORT TMS_PORT +#define SWDIO_PIN TMS_PIN + +#define SWCLK_PORT TCK_PORT +#define SWCLK_PIN TCK_PIN + +#define SRST_PORT GPIOA_BASE +#define SRST_PIN GPIO6 + +#define TMS_SET_MODE() { \ + gpio_mode_setup(TMS_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, TMS_PIN); \ + gpio_set_output_config(TMS_PORT, GPIO_OTYPE_PP, GPIO_DRIVE_2MA, TMS_PIN); \ +} + +#define SWDIO_MODE_FLOAT() { \ + gpio_mode_setup(SWDIO_PORT, GPIO_MODE_INPUT, GPIO_PUPD_NONE, SWDIO_PIN); \ +} + +#define SWDIO_MODE_DRIVE() { \ + gpio_mode_setup(SWDIO_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, SWDIO_PIN); \ + gpio_set_output_config(SWDIO_PORT, GPIO_OTYPE_PP, GPIO_DRIVE_2MA, SWDIO_PIN); \ +} + +extern usbd_driver lm4f_usb_driver; +#define USB_DRIVER lm4f_usb_driver +#define USB_IRQ NVIC_USB0_IRQ +#define USB_ISR usb0_isr + +#define IRQ_PRI_USB (2 << 4) + +#define USBUART UART0 +#define USBUART_CLK RCC_UART0 +#define USBUART_IRQ NVIC_UART0_IRQ +#define USBUART_ISR uart0_isr +#define UART_PIN_SETUP() do { \ + periph_clock_enable(RCC_GPIOA); \ + __asm__("nop"); __asm__("nop"); __asm__("nop"); \ + gpio_set_af(GPIOA_BASE, 0x1, GPIO0 | GPIO1); \ + gpio_mode_setup(GPIOA_BASE, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO0); \ + gpio_mode_setup(GPIOA_BASE, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO1); \ + } while (0) + +#define TRACEUART UART2 +#define TRACEUART_CLK RCC_UART2 +#define TRACEUART_IRQ NVIC_UART2_IRQ +#define TRACEUART_ISR uart2_isr + +/* Use newlib provided integer only stdio functions */ +#define sscanf siscanf +#define sprintf siprintf +#define vasprintf vasiprintf + +#define DEBUG(...) + +#define SET_RUN_STATE(state) {running_status = (state);} +#define SET_IDLE_STATE(state) {} +#define SET_ERROR_STATE(state) SET_IDLE_STATE(state) + +#define PLATFORM_SET_FATAL_ERROR_RECOVERY() {setjmp(fatal_error_jmpbuf);} +#define PLATFORM_FATAL_ERROR(error) { \ + if( running_status ) gdb_putpacketz("X1D"); \ + else gdb_putpacketz("EFF"); \ + running_status = 0; \ + target_list_free(); \ + morse("TARGET LOST.", 1); \ + longjmp(fatal_error_jmpbuf, (error)); \ +} + +#define PLATFORM_HAS_TRACESWO + +int platform_init(void); +void morse(const char *msg, char repeat); + +inline static void gpio_set_val(uint32_t port, uint8_t pin, uint8_t val) { + gpio_write(port, pin, val == 0 ? 0 : 0xff); +} + +inline static uint8_t gpio_get(uint32_t port, uint8_t pin) { + return !(gpio_read(port, pin) == 0); +} + +void platform_delay(uint32_t delay); +const char *platform_target_voltage(void); + +/* */ +void cdcacm_init(void); +/* Returns current usb configuration, or 0 if not configured. */ +int cdcacm_get_config(void); +int cdcacm_get_dtr(void); + +#define disconnect_usb() do { usbd_disconnect(usbdev,1); nvic_disable_irq(USB_IRQ);} while(0) +#define setup_vbus_irq() + +#endif diff --git a/src/platforms/tm4c/cdcacm.c b/src/platforms/tm4c/cdcacm.c new file mode 100644 index 0000000..041d85b --- /dev/null +++ b/src/platforms/tm4c/cdcacm.c @@ -0,0 +1,577 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2011 Black Sphere Technologies Ltd. + * Written by Gareth McMullin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* This file implements a the USB Communications Device Class - Abstract + * Control Model (CDC-ACM) as defined in CDC PSTN subclass 1.2. + * A Device Firmware Upgrade (DFU 1.1) class interface is provided for + * field firmware upgrade. + * + * The device's unique id is used as the USB serial number string. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "platform.h" +#include "gdb_if.h" +#if defined(PLATFORM_HAS_TRACESWO) +#include +#endif +#include + +#define DFU_IF_NO 4 + +usbd_device * usbdev; + +static char *get_dev_unique_id(char *serial_no); + +static int configured; +static int cdcacm_gdb_dtr = 1; + + +static const struct usb_device_descriptor dev = { + .bLength = USB_DT_DEVICE_SIZE, + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = 0x0200, + .bDeviceClass = 0xEF, /* Miscellaneous Device */ + .bDeviceSubClass = 2, /* Common Class */ + .bDeviceProtocol = 1, /* Interface Association */ + .bMaxPacketSize0 = 64, + .idVendor = 0x1D50, + .idProduct = 0x6018, + .bcdDevice = 0x0100, + .iManufacturer = 1, + .iProduct = 2, + .iSerialNumber = 3, + .bNumConfigurations = 1, +}; + +/* This notification endpoint isn't implemented. According to CDC spec its + * optional, but its absence causes a NULL pointer dereference in Linux cdc_acm + * driver. */ +static const struct usb_endpoint_descriptor gdb_comm_endp[] = {{ + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x82, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 16, + .bInterval = 255, +}}; + +static const struct usb_endpoint_descriptor gdb_data_endp[] = {{ + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x01, + .bmAttributes = USB_ENDPOINT_ATTR_BULK, + .wMaxPacketSize = CDCACM_PACKET_SIZE, + .bInterval = 1, +}, { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x81, + .bmAttributes = USB_ENDPOINT_ATTR_BULK, + .wMaxPacketSize = CDCACM_PACKET_SIZE, + .bInterval = 1, +}}; + +static const struct { + struct usb_cdc_header_descriptor header; + struct usb_cdc_call_management_descriptor call_mgmt; + struct usb_cdc_acm_descriptor acm; + struct usb_cdc_union_descriptor cdc_union; +} __attribute__((packed)) gdb_cdcacm_functional_descriptors = { + .header = { + .bFunctionLength = sizeof(struct usb_cdc_header_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_CDC_TYPE_HEADER, + .bcdCDC = 0x0110, + }, + .call_mgmt = { + .bFunctionLength = + sizeof(struct usb_cdc_call_management_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT, + .bmCapabilities = 0, + .bDataInterface = 1, + }, + .acm = { + .bFunctionLength = sizeof(struct usb_cdc_acm_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_CDC_TYPE_ACM, + .bmCapabilities = 2, /* SET_LINE_CODING supported */ + }, + .cdc_union = { + .bFunctionLength = sizeof(struct usb_cdc_union_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_CDC_TYPE_UNION, + .bControlInterface = 0, + .bSubordinateInterface0 = 1, + } +}; + +static const struct usb_interface_descriptor gdb_comm_iface[] = {{ + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_CDC, + .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM, + .bInterfaceProtocol = USB_CDC_PROTOCOL_AT, + .iInterface = 4, + + .endpoint = gdb_comm_endp, + + .extra = &gdb_cdcacm_functional_descriptors, + .extralen = sizeof(gdb_cdcacm_functional_descriptors) +}}; + +static const struct usb_interface_descriptor gdb_data_iface[] = {{ + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 1, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_DATA, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, + .iInterface = 0, + + .endpoint = gdb_data_endp, +}}; + +static const struct usb_iface_assoc_descriptor gdb_assoc = { + .bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE, + .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, + .bFirstInterface = 0, + .bInterfaceCount = 2, + .bFunctionClass = USB_CLASS_CDC, + .bFunctionSubClass = USB_CDC_SUBCLASS_ACM, + .bFunctionProtocol = USB_CDC_PROTOCOL_AT, + .iFunction = 0, +}; + +/* Serial ACM interface */ +static const struct usb_endpoint_descriptor uart_comm_endp[] = {{ + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x84, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 16, + .bInterval = 255, +}}; + +static const struct usb_endpoint_descriptor uart_data_endp[] = {{ + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x03, + .bmAttributes = USB_ENDPOINT_ATTR_BULK, + .wMaxPacketSize = CDCACM_PACKET_SIZE, + .bInterval = 1, +}, { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x83, + .bmAttributes = USB_ENDPOINT_ATTR_BULK, + .wMaxPacketSize = CDCACM_PACKET_SIZE, + .bInterval = 1, +}}; + +static const struct { + struct usb_cdc_header_descriptor header; + struct usb_cdc_call_management_descriptor call_mgmt; + struct usb_cdc_acm_descriptor acm; + struct usb_cdc_union_descriptor cdc_union; +} __attribute__((packed)) uart_cdcacm_functional_descriptors = { + .header = { + .bFunctionLength = sizeof(struct usb_cdc_header_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_CDC_TYPE_HEADER, + .bcdCDC = 0x0110, + }, + .call_mgmt = { + .bFunctionLength = + sizeof(struct usb_cdc_call_management_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT, + .bmCapabilities = 0, + .bDataInterface = 3, + }, + .acm = { + .bFunctionLength = sizeof(struct usb_cdc_acm_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_CDC_TYPE_ACM, + .bmCapabilities = 2, /* SET_LINE_CODING supported*/ + }, + .cdc_union = { + .bFunctionLength = sizeof(struct usb_cdc_union_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_CDC_TYPE_UNION, + .bControlInterface = 2, + .bSubordinateInterface0 = 3, + } +}; + +static const struct usb_interface_descriptor uart_comm_iface[] = {{ + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 2, + .bAlternateSetting = 0, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_CDC, + .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM, + .bInterfaceProtocol = USB_CDC_PROTOCOL_AT, + .iInterface = 5, + + .endpoint = uart_comm_endp, + + .extra = &uart_cdcacm_functional_descriptors, + .extralen = sizeof(uart_cdcacm_functional_descriptors) +}}; + +static const struct usb_interface_descriptor uart_data_iface[] = {{ + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 3, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_DATA, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, + .iInterface = 0, + + .endpoint = uart_data_endp, +}}; + +static const struct usb_iface_assoc_descriptor uart_assoc = { + .bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE, + .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, + .bFirstInterface = 2, + .bInterfaceCount = 2, + .bFunctionClass = USB_CLASS_CDC, + .bFunctionSubClass = USB_CDC_SUBCLASS_ACM, + .bFunctionProtocol = USB_CDC_PROTOCOL_AT, + .iFunction = 0, +}; + +const struct usb_dfu_descriptor dfu_function = { + .bLength = sizeof(struct usb_dfu_descriptor), + .bDescriptorType = DFU_FUNCTIONAL, + .bmAttributes = USB_DFU_CAN_DOWNLOAD | USB_DFU_WILL_DETACH, + .wDetachTimeout = 255, + .wTransferSize = 1024, + .bcdDFUVersion = 0x011A, +}; + +const struct usb_interface_descriptor dfu_iface = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = DFU_IF_NO, + .bAlternateSetting = 0, + .bNumEndpoints = 0, + .bInterfaceClass = 0xFE, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 1, + .iInterface = 6, + + .extra = &dfu_function, + .extralen = sizeof(dfu_function), +}; + +static const struct usb_iface_assoc_descriptor dfu_assoc = { + .bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE, + .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, + .bFirstInterface = 4, + .bInterfaceCount = 1, + .bFunctionClass = 0xFE, + .bFunctionSubClass = 1, + .bFunctionProtocol = 1, + .iFunction = 6, +}; + +#if defined(PLATFORM_HAS_TRACESWO) +static const struct usb_endpoint_descriptor trace_endp[] = {{ + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x85, + .bmAttributes = USB_ENDPOINT_ATTR_BULK, + .wMaxPacketSize = 64, + .bInterval = 0, +}}; + +const struct usb_interface_descriptor trace_iface = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 5, + .bAlternateSetting = 0, + .bNumEndpoints = 1, + .bInterfaceClass = 0xFF, + .bInterfaceSubClass = 0xFF, + .bInterfaceProtocol = 0xFF, + .iInterface = 7, + + .endpoint = trace_endp, +}; + +static const struct usb_iface_assoc_descriptor trace_assoc = { + .bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE, + .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, + .bFirstInterface = 5, + .bInterfaceCount = 1, + .bFunctionClass = 0xFF, + .bFunctionSubClass = 0xFF, + .bFunctionProtocol = 0xFF, + .iFunction = 7, +}; +#endif + +static const struct usb_interface ifaces[] = {{ + .num_altsetting = 1, + .iface_assoc = &gdb_assoc, + .altsetting = gdb_comm_iface, +}, { + .num_altsetting = 1, + .altsetting = gdb_data_iface, +}, { + .num_altsetting = 1, + .iface_assoc = &uart_assoc, + .altsetting = uart_comm_iface, +}, { + .num_altsetting = 1, + .altsetting = uart_data_iface, +}, { + .num_altsetting = 1, + .iface_assoc = &dfu_assoc, + .altsetting = &dfu_iface, +#if defined(PLATFORM_HAS_TRACESWO) +}, { + .num_altsetting = 1, + .iface_assoc = &trace_assoc, + .altsetting = &trace_iface, +#endif +}}; + +static const struct usb_config_descriptor config = { + .bLength = USB_DT_CONFIGURATION_SIZE, + .bDescriptorType = USB_DT_CONFIGURATION, + .wTotalLength = 0, +#if defined(PLATFORM_HAS_TRACESWO) + .bNumInterfaces = 6, +#else + .bNumInterfaces = 5, +#endif + .bConfigurationValue = 1, + .iConfiguration = 0, + .bmAttributes = 0x80, + .bMaxPower = 0x32, + + .interface = ifaces, +}; + +char serial_no[9]; + +static const char *usb_strings[] = { + "Black Sphere Technologies", + BOARD_IDENT, + serial_no, + "Black Magic GDB Server", + "Black Magic UART Port", + DFU_IDENT, +#if defined(PLATFORM_HAS_TRACESWO) + "Black Magic Trace Capture", +#endif +}; + +static void dfu_detach_complete(usbd_device *dev, struct usb_setup_data *req) +{ + (void)dev; + (void)req; + + /* Disconnect USB cable */ + disconnect_usb(); + + /* Assert boot-request pin */ + //assert_boot_pin(); + + /* Reset core to enter bootloader */ + scb_reset_core(); +} + +static int cdcacm_control_request(usbd_device *dev, + struct usb_setup_data *req, uint8_t **buf, uint16_t *len, + void (**complete)(usbd_device *dev, struct usb_setup_data *req)) +{ + (void)dev; + (void)complete; + (void)buf; + (void)len; + + switch(req->bRequest) { + case USB_CDC_REQ_SET_CONTROL_LINE_STATE: + /* Ignore if not for GDB interface */ + if(req->wIndex != 0) + return 1; + + cdcacm_gdb_dtr = req->wValue & 1; + + return 1; + case USB_CDC_REQ_SET_LINE_CODING: + if(*len < sizeof(struct usb_cdc_line_coding)) + return 0; + + switch(req->wIndex) { + case 2: + usbuart_set_line_coding((struct usb_cdc_line_coding*)*buf); + case 0: + return 1; /* Ignore on GDB Port */ + default: + return 0; + } + case DFU_GETSTATUS: + if(req->wIndex == DFU_IF_NO) { + (*buf)[0] = DFU_STATUS_OK; + (*buf)[1] = 0; + (*buf)[2] = 0; + (*buf)[3] = 0; + (*buf)[4] = STATE_APP_IDLE; + (*buf)[5] = 0; /* iString not used here */ + *len = 6; + + return 1; + } + case DFU_DETACH: + if(req->wIndex == DFU_IF_NO) { + *complete = dfu_detach_complete; + return 1; + } + return 0; + } + return 0; +} + +int cdcacm_get_config(void) +{ + return configured; +} + +int cdcacm_get_dtr(void) +{ + return cdcacm_gdb_dtr; +} + +static void cdcacm_set_config(usbd_device *dev, uint16_t wValue) +{ + configured = wValue; + + /* GDB interface */ + usbd_ep_setup(dev, 0x01, USB_ENDPOINT_ATTR_BULK, + CDCACM_PACKET_SIZE, gdb_usb_out_cb); + usbd_ep_setup(dev, 0x81, USB_ENDPOINT_ATTR_BULK, + CDCACM_PACKET_SIZE, NULL); + usbd_ep_setup(dev, 0x82, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL); + + /* Serial interface */ + usbd_ep_setup(dev, 0x03, USB_ENDPOINT_ATTR_BULK, + CDCACM_PACKET_SIZE, usbuart_usb_out_cb); + usbd_ep_setup(dev, 0x83, USB_ENDPOINT_ATTR_BULK, + CDCACM_PACKET_SIZE, usbuart_usb_in_cb); + usbd_ep_setup(dev, 0x84, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL); + +#if defined(PLATFORM_HAS_TRACESWO) + /* Trace interface */ + usbd_ep_setup(dev, 0x85, USB_ENDPOINT_ATTR_BULK, + 64, trace_buf_drain); +#endif + + usbd_register_control_callback(dev, + USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE, + USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, + cdcacm_control_request); + + /* Notify the host that DCD is asserted. + * Allows the use of /dev/tty* devices on *BSD/MacOS + */ + char buf[10]; + struct usb_cdc_notification *notif = (void*)buf; + /* We echo signals back to host as notification */ + notif->bmRequestType = 0xA1; + notif->bNotification = USB_CDC_NOTIFY_SERIAL_STATE; + notif->wValue = 0; + notif->wIndex = 0; + notif->wLength = 2; + buf[8] = 3; /* DCD | DSR */ + buf[9] = 0; + usbd_ep_write_packet(dev, 0x82, buf, 10); + notif->wIndex = 2; + usbd_ep_write_packet(dev, 0x84, buf, 10); +} + +/* We need a special large control buffer for this device: */ +uint8_t usbd_control_buffer[256]; + +void cdcacm_init(void) +{ + get_dev_unique_id(serial_no); + + periph_clock_enable(RCC_GPIOD); + __asm__("nop"); __asm__("nop"); __asm__("nop"); + gpio_mode_setup(GPIOD_BASE, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO4|GPIO5); + + usbdev = usbd_init(&USB_DRIVER, &dev, &config, usb_strings, + sizeof(usb_strings)/sizeof(char *), + usbd_control_buffer, sizeof(usbd_control_buffer)); + + usbd_register_set_config_callback(usbdev, cdcacm_set_config); + + usb_enable_interrupts(USB_INT_RESET|USB_INT_DISCON|USB_INT_RESUME|USB_INT_SUSPEND, + 0xff, 0xff); + nvic_set_priority(USB_IRQ, IRQ_PRI_USB); + nvic_enable_irq(USB_IRQ); + setup_vbus_irq(); +} + +void USB_ISR(void) +{ + usbd_poll(usbdev); +} + +static char *get_dev_unique_id(char *s) +{ + /* FIXME: Store a unique serial number somewhere and retreive here */ + uint32_t unique_id = 1; + int i; + + /* Fetch serial number from chip's unique ID */ + for(i = 0; i < 8; i++) { + s[7-i] = ((unique_id >> (4*i)) & 0xF) + '0'; + } + for(i = 0; i < 8; i++) + if(s[i] > '9') + s[i] += 'A' - '9' - 1; + s[8] = 0; + + return s; +} diff --git a/src/platforms/tm4c/gdb_if.c b/src/platforms/tm4c/gdb_if.c new file mode 100644 index 0000000..b14bbd3 --- /dev/null +++ b/src/platforms/tm4c/gdb_if.c @@ -0,0 +1,100 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2011 Black Sphere Technologies Ltd. + * Written by Gareth McMullin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* This file implements a transparent channel over which the GDB Remote + * Serial Debugging protocol is implemented. This implementation for STM32 + * uses the USB CDC-ACM device bulk endpoints to implement the channel. + */ +#include "platform.h" +#include + +#include "gdb_if.h" + +static volatile uint32_t head_out, tail_out; +static volatile uint32_t count_in; +static volatile uint8_t buffer_out[16*CDCACM_PACKET_SIZE]; +static volatile uint8_t buffer_in[CDCACM_PACKET_SIZE]; + +void gdb_if_putchar(unsigned char c, int flush) +{ + buffer_in[count_in++] = c; + if(flush || (count_in == CDCACM_PACKET_SIZE)) { + /* Refuse to send if USB isn't configured, and + * don't bother if nobody's listening */ + if((cdcacm_get_config() != 1) || !cdcacm_get_dtr()) { + count_in = 0; + return; + } + while(usbd_ep_write_packet(usbdev, CDCACM_GDB_ENDPOINT, + (uint8_t *)buffer_in, count_in) <= 0); + count_in = 0; + } +} + +void gdb_usb_out_cb(usbd_device *dev, uint8_t ep) +{ + (void)ep; + static uint8_t buf[CDCACM_PACKET_SIZE]; + + usbd_ep_nak_set(dev, CDCACM_GDB_ENDPOINT, 1); + uint32_t count = usbd_ep_read_packet(dev, CDCACM_GDB_ENDPOINT, + (uint8_t *)buf, CDCACM_PACKET_SIZE); + + + uint32_t idx; + for (idx=0; idx ":"\n<- "); + + /* Don't turnaround if direction not changing */ + if(dir == olddir) return; + olddir = dir; + + if(dir) + SWDIO_MODE_FLOAT(); + gpio_set(SWCLK_PORT, SWCLK_PIN); + gpio_clear(SWCLK_PORT, SWCLK_PIN); + if(!dir) + SWDIO_MODE_DRIVE(); +} + +static uint8_t swdptap_bit_in(void) +{ + uint16_t ret; + + ret = gpio_get(SWDIO_PORT, SWDIO_PIN); + gpio_set(SWCLK_PORT, SWCLK_PIN); + gpio_clear(SWCLK_PORT, SWCLK_PIN); + + DEBUG("%d", ret?1:0); + + return ret != 0; +} + +static void swdptap_bit_out(uint8_t val) +{ + DEBUG("%d", val); + + gpio_set_val(SWDIO_PORT, SWDIO_PIN, val); + gpio_set(SWCLK_PORT, SWCLK_PIN); + gpio_clear(SWCLK_PORT, SWCLK_PIN); +} + +int +swdptap_init(void) +{ + swdptap_reset(); + swdptap_seq_out(0xE79E, 16); /* 0b0111100111100111 */ + swdptap_reset(); + swdptap_seq_out(0, 16); + + return 0; +} + +void +swdptap_reset(void) +{ + swdptap_turnaround(0); + /* 50 clocks with TMS high */ + for(int i = 0; i < 50; i++) swdptap_bit_out(1); +} + +uint32_t +swdptap_seq_in(int ticks) +{ + uint32_t index = 1; + uint32_t ret = 0; + + swdptap_turnaround(1); + + while(ticks--) { + if(swdptap_bit_in()) ret |= index; + index <<= 1; + } + + return ret; +} + +uint8_t +swdptap_seq_in_parity(uint32_t *ret, int ticks) +{ + uint32_t index = 1; + uint8_t parity = 0; + *ret = 0; + + swdptap_turnaround(1); + + while(ticks--) { + if(swdptap_bit_in()) { + *ret |= index; + parity ^= 1; + } + index <<= 1; + } + if(swdptap_bit_in()) parity ^= 1; + + return parity; +} + +void +swdptap_seq_out(uint32_t MS, int ticks) +{ + swdptap_turnaround(0); + + while(ticks--) { + swdptap_bit_out(MS & 1); + MS >>= 1; + } +} + +void +swdptap_seq_out_parity(uint32_t MS, int ticks) +{ + uint8_t parity = 0; + + swdptap_turnaround(0); + + while(ticks--) { + swdptap_bit_out(MS & 1); + parity ^= MS; + MS >>= 1; + } + swdptap_bit_out(parity & 1); +} diff --git a/src/platforms/tm4c/tm4c.ld b/src/platforms/tm4c/tm4c.ld new file mode 100644 index 0000000..8fe93a4 --- /dev/null +++ b/src/platforms/tm4c/tm4c.ld @@ -0,0 +1,29 @@ +/* + * This file is part of the libopenstm32 project. + * + * Copyright (C) 2010 Thomas Otto + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* Define memory regions. */ +MEMORY +{ + rom (rx) : ORIGIN = 0x00000000, LENGTH = 256K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 32K +} + +/* Include the common ld script from libopenstm32. */ +INCLUDE libopencm3_lm4f.ld + diff --git a/src/platforms/tm4c/traceswo.c b/src/platforms/tm4c/traceswo.c new file mode 100644 index 0000000..eb63139 --- /dev/null +++ b/src/platforms/tm4c/traceswo.c @@ -0,0 +1,165 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2012 Black Sphere Technologies Ltd. + * Written by Gareth McMullin + * + * Copyright (C) 2014 Fredrik Ahlberg + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* This file implements capture of the TRACESWO output. + * + * ARM DDI 0403D - ARMv7M Architecture Reference Manual + * ARM DDI 0337I - Cortex-M3 Technical Reference Manual + * ARM DDI 0314H - CoreSight Components Technical Reference Manual + */ + +#include "general.h" + +#include +#include +#include + +#include + +#include + +#include +#include "platform.h" + +void traceswo_init(void) +{ + periph_clock_enable(RCC_GPIOD); + periph_clock_enable(TRACEUART_CLK); + __asm__("nop"); __asm__("nop"); __asm__("nop"); + + gpio_mode_setup(SWO_PORT, GPIO_MODE_INPUT, GPIO_PUPD_NONE, SWO_PIN); + gpio_set_af(SWO_PORT, 1, SWO_PIN); /* U2RX */ + + uart_disable(TRACEUART); + + /* Setup UART parameters. */ + uart_clock_from_sysclk(TRACEUART); + uart_set_baudrate(TRACEUART, 800000); + uart_set_databits(TRACEUART, 8); + uart_set_stopbits(TRACEUART, 1); + uart_set_parity(TRACEUART, UART_PARITY_NONE); + + // Enable FIFO + uart_enable_fifo(TRACEUART); + + // Set FIFO interrupt trigger levels to 4/8 full for RX buffer and + // 7/8 empty (1/8 full) for TX buffer + uart_set_fifo_trigger_levels(TRACEUART, UART_FIFO_RX_TRIG_1_2, UART_FIFO_TX_TRIG_7_8); + + uart_clear_interrupt_flag(TRACEUART, UART_INT_RX | UART_INT_RT); + + /* Enable interrupts */ + uart_enable_interrupts(TRACEUART, UART_INT_RX | UART_INT_RT); + + /* Finally enable the USART. */ + uart_enable(TRACEUART); + + nvic_set_priority(TRACEUART_IRQ, 0); + nvic_enable_irq(TRACEUART_IRQ); + + /* Un-stall USB endpoint */ + usbd_ep_stall_set(usbdev, 0x85, 0); + + gpio_mode_setup(GPIOD, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO3); +} + +void traceswo_baud(unsigned int baud) +{ + uart_set_baudrate(TRACEUART, baud); + uart_set_databits(TRACEUART, 8); +} + +#define FIFO_SIZE 256 + +/* RX Fifo buffer */ +static volatile uint8_t buf_rx[FIFO_SIZE]; +/* Fifo in pointer, writes assumed to be atomic, should be only incremented within RX ISR */ +static volatile uint32_t buf_rx_in = 0; +/* Fifo out pointer, writes assumed to be atomic, should be only incremented outside RX ISR */ +static volatile uint32_t buf_rx_out = 0; + +void trace_buf_push(void) +{ + size_t len; + + if (buf_rx_in == buf_rx_out) { + return; + } else if (buf_rx_in > buf_rx_out) { + len = buf_rx_in - buf_rx_out; + } else { + len = FIFO_SIZE - buf_rx_out; + } + + if (len > 64) { + len = 64; + } + + if (usbd_ep_write_packet(usbdev, 0x85, (uint8_t *)&buf_rx[buf_rx_out], len) == len) { + buf_rx_out += len; + buf_rx_out %= FIFO_SIZE; + } +} + +void trace_buf_drain(usbd_device *dev, uint8_t ep) +{ + (void) dev; + (void) ep; + trace_buf_push(); +} + +void trace_tick(void) +{ + trace_buf_push(); +} + +void TRACEUART_ISR(void) +{ + uint32_t flush = uart_is_interrupt_source(TRACEUART, UART_INT_RT); + + while (!uart_is_rx_fifo_empty(TRACEUART)) { + uint32_t c = uart_recv(TRACEUART); + + /* If the next increment of rx_in would put it at the same point + * as rx_out, the FIFO is considered full. + */ + if (((buf_rx_in + 1) % FIFO_SIZE) != buf_rx_out) + { + /* insert into FIFO */ + buf_rx[buf_rx_in++] = c; + + /* wrap out pointer */ + if (buf_rx_in >= FIFO_SIZE) + { + buf_rx_in = 0; + } + } else { + flush = 1; + break; + } + } + + if (flush) { + /* advance fifo out pointer by amount written */ + trace_buf_push(); + } +} + diff --git a/src/platforms/tm4c/usbuart.c b/src/platforms/tm4c/usbuart.c new file mode 100644 index 0000000..bb769f0 --- /dev/null +++ b/src/platforms/tm4c/usbuart.c @@ -0,0 +1,182 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2012 Black Sphere Technologies Ltd. + * Written by Gareth McMullin + * + * Copyright (C) 2014 Fredrik Ahlberg + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include + +#define FIFO_SIZE 128 + +/* RX Fifo buffer */ +static uint8_t buf_rx[FIFO_SIZE]; +/* Fifo in pointer, writes assumed to be atomic, should be only incremented within RX ISR */ +static uint8_t buf_rx_in; +/* Fifo out pointer, writes assumed to be atomic, should be only incremented outside RX ISR */ +static uint8_t buf_rx_out; + +void usbuart_init(void) +{ + UART_PIN_SETUP(); + + periph_clock_enable(USBUART_CLK); + __asm__("nop"); __asm__("nop"); __asm__("nop"); + + uart_disable(USBUART); + + /* Setup UART parameters. */ + uart_clock_from_sysclk(USBUART); + uart_set_baudrate(USBUART, 38400); + uart_set_databits(USBUART, 8); + uart_set_stopbits(USBUART, 1); + uart_set_parity(USBUART, UART_PARITY_NONE); + + // Enable FIFO + uart_enable_fifo(USBUART); + + // Set FIFO interrupt trigger levels to 1/8 full for RX buffer and + // 7/8 empty (1/8 full) for TX buffer + uart_set_fifo_trigger_levels(USBUART, UART_FIFO_RX_TRIG_1_8, UART_FIFO_TX_TRIG_7_8); + + uart_clear_interrupt_flag(USBUART, UART_INT_RX | UART_INT_RT); + + /* Enable interrupts */ + uart_enable_interrupts(UART0, UART_INT_RX| UART_INT_RT); + + /* Finally enable the USART. */ + uart_enable(USBUART); + + //nvic_set_priority(USBUSART_IRQ, IRQ_PRI_USBUSART); + nvic_enable_irq(USBUART_IRQ); +} + +void usbuart_set_line_coding(struct usb_cdc_line_coding *coding) +{ + uart_set_baudrate(USBUART, coding->dwDTERate); + uart_set_databits(USBUART, coding->bDataBits); + switch(coding->bCharFormat) { + case 0: + case 1: + uart_set_stopbits(USBUART, 1); + break; + case 2: + uart_set_stopbits(USBUART, 2); + break; + } + switch(coding->bParityType) { + case 0: + uart_set_parity(USBUART, UART_PARITY_NONE); + break; + case 1: + uart_set_parity(USBUART, UART_PARITY_ODD); + break; + case 2: + uart_set_parity(USBUART, UART_PARITY_EVEN); + break; + } +} + +void usbuart_usb_out_cb(usbd_device *dev, uint8_t ep) +{ + (void)ep; + + char buf[CDCACM_PACKET_SIZE]; + int len = usbd_ep_read_packet(dev, CDCACM_UART_ENDPOINT, + buf, CDCACM_PACKET_SIZE); + + for(int i = 0; i < len; i++) + uart_send_blocking(USBUART, buf[i]); +} + + +void usbuart_usb_in_cb(usbd_device *dev, uint8_t ep) +{ + (void) dev; + (void) ep; +} + +/* + * Read a character from the UART RX and stuff it in a software FIFO. + * Allowed to read from FIFO out pointer, but not write to it. + * Allowed to write to FIFO in pointer. + */ +void USBUART_ISR(void) +{ + int flush = uart_is_interrupt_source(USBUART, UART_INT_RT); + + while (!uart_is_rx_fifo_empty(USBUART)) { + char c = uart_recv(USBUART); + + /* If the next increment of rx_in would put it at the same point + * as rx_out, the FIFO is considered full. + */ + if (((buf_rx_in + 1) % FIFO_SIZE) != buf_rx_out) + { + /* insert into FIFO */ + buf_rx[buf_rx_in++] = c; + + /* wrap out pointer */ + if (buf_rx_in >= FIFO_SIZE) + { + buf_rx_in = 0; + } + } else { + flush = 1; + } + } + + if (flush) { + /* forcibly empty fifo if no USB endpoint */ + if (cdcacm_get_config() != 1) + { + buf_rx_out = buf_rx_in; + return; + } + + uint8_t packet_buf[CDCACM_PACKET_SIZE]; + uint8_t packet_size = 0; + uint8_t buf_out = buf_rx_out; + + /* copy from uart FIFO into local usb packet buffer */ + while (buf_rx_in != buf_out && packet_size < CDCACM_PACKET_SIZE) + { + packet_buf[packet_size++] = buf_rx[buf_out++]; + + /* wrap out pointer */ + if (buf_out >= FIFO_SIZE) + { + buf_out = 0; + } + + } + + /* advance fifo out pointer by amount written */ + buf_rx_out += usbd_ep_write_packet(usbdev, + CDCACM_UART_ENDPOINT, packet_buf, packet_size); + buf_rx_out %= FIFO_SIZE; + } +} +