From e3774f71086b89e3771de5520cfb55cd28e75151 Mon Sep 17 00:00:00 2001 From: Travis Geiselbrecht Date: Mon, 9 Sep 2013 15:01:34 -0700 Subject: [PATCH] [platform][stellaris] start of usb driver for stellaris --- platform/stellaris/include/ti_driverlib.h | 2 + platform/stellaris/init.c | 2 + platform/stellaris/rules.mk | 4 +- platform/stellaris/usbc.c | 252 ++++++++++++++++++++++ target/stellaris-launchpad/init.c | 4 + target/stellaris-launchpad/rules.mk | 3 +- target/stellaris-launchpad/usb.c | 99 +++++++++ 7 files changed, 364 insertions(+), 2 deletions(-) create mode 100644 platform/stellaris/usbc.c create mode 100644 target/stellaris-launchpad/usb.c diff --git a/platform/stellaris/include/ti_driverlib.h b/platform/stellaris/include/ti_driverlib.h index cff00e27..88e492af 100644 --- a/platform/stellaris/include/ti_driverlib.h +++ b/platform/stellaris/include/ti_driverlib.h @@ -13,5 +13,7 @@ __BEGIN_CDECLS #include "driverlib/sysctl.h" #include "driverlib/uart.h" #include "driverlib/timer.h" +#include "driverlib/usb.h" +#include "driverlib/rom.h" __END_CDECLS diff --git a/platform/stellaris/init.c b/platform/stellaris/init.c index 0fd5c408..3f7c601f 100644 --- a/platform/stellaris/init.c +++ b/platform/stellaris/init.c @@ -23,8 +23,10 @@ */ #include +#include #include #include +#include #include "ti_driverlib.h" diff --git a/platform/stellaris/rules.mk b/platform/stellaris/rules.mk index fea76998..ac7e0701 100644 --- a/platform/stellaris/rules.mk +++ b/platform/stellaris/rules.mk @@ -32,6 +32,7 @@ MODULE_SRCS += \ $(LOCAL_DIR)/gpio.c \ $(LOCAL_DIR)/init.c \ $(LOCAL_DIR)/timer.c \ + $(LOCAL_DIR)/usbc.c \ $(LOCAL_DIR)/vectab.c \ @@ -54,7 +55,8 @@ LINKER_SCRIPT += \ $(BUILDDIR)/system-twosegment.ld MODULE_DEPS += \ - lib/cbuf + lib/cbuf \ + dev/usb include $(LOCAL_DIR)/ti/rules.mk diff --git a/platform/stellaris/usbc.c b/platform/stellaris/usbc.c new file mode 100644 index 00000000..d4bbf729 --- /dev/null +++ b/platform/stellaris/usbc.c @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2013 Travis Geiselbrecht + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ti_driverlib.h" +#include "inc/hw_usb.h" + +#define LOCAL_TRACE 0 + +static bool pending_addr_change = false; +static uint8_t addr; + +static void usbc_dump_regs(void) +{ + printf("USB0 reg dump:\n"); +#define DUMPREG8(r) printf("\t" #r ": 0x%hhx\n", *REG8(USB0_BASE + (r))); +#define DUMPREG16(r) printf("\t" #r ": 0x%hx\n", *REG16(USB0_BASE + (r))); +#define DUMPREG32(r) printf("\t" #r ": 0x%x\n", *REG32(USB0_BASE + (r))); + + DUMPREG8(USB_O_FADDR); + DUMPREG8(USB_O_POWER); + DUMPREG16(USB_O_TXIS); + DUMPREG16(USB_O_RXIS); + DUMPREG16(USB_O_TXIE); + DUMPREG16(USB_O_RXIE); + DUMPREG8(USB_O_IS); + DUMPREG8(USB_O_IE); + DUMPREG16(USB_O_FRAME); + DUMPREG8(USB_O_EPIDX); + DUMPREG8(USB_O_TEST); + DUMPREG32(USB_O_FIFO0); + DUMPREG32(USB_O_FIFO1); + DUMPREG32(USB_O_FIFO2); + DUMPREG32(USB_O_FIFO3); + DUMPREG32(USB_O_FIFO4); + DUMPREG32(USB_O_FIFO5); + DUMPREG32(USB_O_FIFO6); + DUMPREG32(USB_O_FIFO7); + DUMPREG32(USB_O_FIFO8); + DUMPREG32(USB_O_FIFO9); + DUMPREG32(USB_O_FIFO10); + DUMPREG32(USB_O_FIFO11); + DUMPREG32(USB_O_FIFO12); + DUMPREG32(USB_O_FIFO13); + DUMPREG32(USB_O_FIFO14); + DUMPREG32(USB_O_FIFO15); + DUMPREG16(USB_O_DEVCTL); + DUMPREG8(USB_O_TXFIFOSZ); + DUMPREG8(USB_O_RXFIFOSZ); + DUMPREG16(USB_O_TXFIFOADD); + DUMPREG16(USB_O_RXFIFOADD); + DUMPREG32(USB_O_PP); + +#undef DUMPREG8 +#undef DUMPREG16 +#undef DUMPREG32 +} + +void stellaris_usbc_early_init(void) +{ + LTRACE_ENTRY; + LTRACE_EXIT; +} + +void stellaris_usbc_init(void) +{ + LTRACE_ENTRY; + + SysCtlPeripheralEnable(SYSCTL_PERIPH_USB0); + SysCtlPeripheralReset(SYSCTL_PERIPH_USB0); + + SysCtlUSBPLLEnable(); + + GPIOPinTypeUSBAnalog(GPIO_PORTD_AHB_BASE, GPIO_PIN_4 | GPIO_PIN_5); + + USBDevMode(USB0_BASE); + USBPHYPowerOn(USB0_BASE); + +#if LOCAL_TRACE + usbc_dump_regs(); + + printf("addr %lu\n", USBDevAddrGet(USB0_BASE)); + printf("ep0 status 0x%lx\n", USBEndpointStatus(USB0_BASE, USB_EP_0)); +#endif + + NVIC_EnableIRQ(INT_USB0 - 16); + USBIntDisableControl(USB0_BASE, USB_INTCTRL_ALL); + + LTRACE_EXIT; +} + +static void ep0_irq(void) +{ + uint status = USBEndpointStatus(USB0_BASE, USB_EP_0); + + LTRACEF("ep0 status 0x%x\n", status); + + /* delay setting the address until the ack as completed */ + if (pending_addr_change) { + LTRACEF("pending addr change\n"); + USBDevAddrSet(USB0_BASE, addr); + pending_addr_change = false; + } + + if (status & USB_DEV_EP0_OUT_PKTRDY) { + LTRACEF("pktrdy\n"); + + uchar buf[sizeof(struct usb_setup)]; + ulong avail = sizeof(buf); + + if (USBEndpointDataGet(USB0_BASE, USB_EP_0, buf, &avail) < 0 || avail != sizeof(buf)) { + LTRACEF("short setup packet, size %lu\n", avail); + } else { + union usb_callback_args args; + args.setup = (void *)buf; + usb_callback(CB_SETUP_MSG, &args); + } + } + if (status & USB_DEV_EP0_SENT_STALL) { + LTRACEF("stall complete\n"); + USBDevEndpointStallClear(USB0_BASE, USB_EP_0, 0); + } +} + +void stellaris_usb0_irq(void) +{ + arm_cm_irq_entry(); + + uint status = USBIntStatusControl(USB0_BASE); + + //LTRACEF("usb irq, status 0x%x\n", status); + + if (status & USB_INTCTRL_RESET) { + // reset + LTRACEF("reset\n"); + pending_addr_change = false; + usb_callback(CB_RESET, NULL); + } + if (status & USB_INTCTRL_CONNECT) { + // reset + LTRACEF("connect\n"); + } + + status = USBIntStatusEndpoint(USB0_BASE); + + if (status & USB_INTEP_0) { + // ep0 + //LTRACEF("ep0\n"); + ep0_irq(); + } + + arm_cm_irq_exit(true); +} + +void usbc_ep0_ack(void) +{ + LTRACE_ENTRY; + + USBDevEndpointDataAck(USB0_BASE, USB_EP_0, true); +} + +void usbc_ep0_stall(void) +{ + LTRACE_ENTRY; + + USBDevEndpointStall(USB0_BASE, USB_EP_0, 0); +} + +void usbc_ep0_send(const void *buf, size_t len, size_t maxlen) +{ + LTRACEF("buf %p, len %zu, maxlen %zu\n", buf, len, maxlen); + + USBEndpointDataPut(USB0_BASE, USB_EP_0, (void *)buf, len); + + USBEndpointDataSend(USB0_BASE, USB_EP_0, USB_TRANS_SETUP); +} + +void usbc_set_address(uint8_t address) +{ + LTRACEF("address 0x%hhx\n", address); + + addr = address; + pending_addr_change = true; +} + +void usbc_ep0_recv(void *buf, size_t len, ep_callback cb) +{ + PANIC_UNIMPLEMENTED; +} + +bool usbc_is_highspeed(void) +{ + return false; +} + +status_t usbc_set_active(bool active) +{ + LTRACEF("active %d\n", active); + if (active) { + USBIntEnableControl(USB0_BASE, USB_INTCTRL_CONNECT | USB_INTCTRL_RESET); + USBIntEnableEndpoint(USB0_BASE, USB_INTEP_0); + USBDevConnect(USB0_BASE); + } else { + USBDevDisconnect(USB0_BASE); + } + + return NO_ERROR; +} + +void usbc_setup_endpoint(ep_t ep, ep_dir_t dir, bool active, ep_callback callback, uint width, uint blocksize) +{ + PANIC_UNIMPLEMENTED; +} + +status_t usbc_queue_rx(ep_t ep, usbc_transfer *transfer) +{ + PANIC_UNIMPLEMENTED; +} + +status_t usbc_queue_tx(ep_t ep, usbc_transfer *transfer) +{ + PANIC_UNIMPLEMENTED; +} + +// vim: set ts=4 sw=4 noexpandtab: diff --git a/target/stellaris-launchpad/init.c b/target/stellaris-launchpad/init.c index f12eb6a0..a1ac9d2a 100644 --- a/target/stellaris-launchpad/init.c +++ b/target/stellaris-launchpad/init.c @@ -29,6 +29,8 @@ #include "ti_driverlib.h" +extern void target_usb_setup(void); + void target_early_init(void) { GPIOPinWrite(GPIO_PORTF_AHB_BASE, GPIO_PIN_1, 0); @@ -45,6 +47,7 @@ void target_early_init(void) void target_init(void) { + target_usb_setup(); } void target_set_debug_led(unsigned int led, bool on) @@ -56,3 +59,4 @@ void target_set_debug_led(unsigned int led, bool on) } } +// vim: set ts=4 sw=4 noexpandtab: diff --git a/target/stellaris-launchpad/rules.mk b/target/stellaris-launchpad/rules.mk index 2dacb023..d7968e5e 100644 --- a/target/stellaris-launchpad/rules.mk +++ b/target/stellaris-launchpad/rules.mk @@ -11,6 +11,7 @@ GLOBAL_DEFINES += \ GLOBAL_INCLUDES += $(LOCAL_DIR)/include MODULE_SRCS += \ - $(LOCAL_DIR)/init.c + $(LOCAL_DIR)/init.c \ + $(LOCAL_DIR)/usb.c \ include make/module.mk diff --git a/target/stellaris-launchpad/usb.c b/target/stellaris-launchpad/usb.c new file mode 100644 index 00000000..031cdb39 --- /dev/null +++ b/target/stellaris-launchpad/usb.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2013 Travis Geiselbrecht + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#include +#include +#include +#include +#include +#include + +#define W(w) (w & 0xff), (w >> 8) +#define W3(w) (w & 0xff), ((w >> 8) & 0xff), ((w >> 16) & 0xff) + +/* top level device descriptor */ +static uint8_t dev_descr[] = { + 0x12, /* descriptor length */ + 0x01, /* Device Descriptor type */ + W(0x0200), /* USB Version */ + 0x00, /* class */ + 0x00, /* subclass */ + 0x00, /* protocol */ + 64, /* max packet size, ept0 */ + W(0x9999), /* vendor */ + W(0x9999), /* product */ + W(0x9999), /* release */ + 0x0, /* manufacturer string */ + 0x0, /* product string */ + 0x0, /* serialno string */ + 0x1, /* num configs */ +}; + +/* high/low speed device qualifier */ +static uint8_t devqual_descr[] = { + 0x0a, /* len */ + 0x06, /* Device Qualifier type */ + W(0x0200), /* USB version */ + 0x00, /* class */ + 0x00, /* subclass */ + 0x00, /* protocol */ + 0x40, /* max packet size, ept0 */ + 0x01, /* num configs */ + 0x00 /* reserved */ +}; + +static uint8_t cfg_descr[] = { + 0x09, /* Length of Cfg Descr */ + 0x02, /* Type of Cfg Descr */ + W(0x09), /* Total Length (incl ifc, ept) */ + 0x00, /* # Interfaces */ + 0x01, /* Cfg Value */ + 0x00, /* Cfg String */ + 0xc0, /* Attributes -- self powered */ + 250, /* Power Consumption - 500mA */ +}; + +static uchar langid[] = { 0x04, 0x03, 0x09, 0x04 }; + +usb_config config = { + .lowspeed = { + .device = USB_DESC_STATIC(dev_descr), + .device_qual = USB_DESC_STATIC(devqual_descr), + .config = USB_DESC_STATIC(cfg_descr), + }, + .highspeed = { + .device = USB_DESC_STATIC(dev_descr), + .device_qual = USB_DESC_STATIC(devqual_descr), + .config = USB_DESC_STATIC(cfg_descr), + }, + + .langid = USB_DESC_STATIC(langid), +}; + +void target_usb_setup(void) +{ + usb_setup(&config); + + usb_start(); +} + +// vim: set ts=4 sw=4 noexpandtab: