/* Copyright 2016 The Chromium OS Authors. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "clock.h" #include "common.h" #include "config.h" #include "console.h" #include "flash.h" #include "gpio.h" #include "hooks.h" #include "link_defs.h" #include "registers.h" #include "usb_hw.h" #include "system.h" #include "task.h" #include "timer.h" #include "util.h" #include "usb_descriptor.h" #include "watchdog.h" /****************************************************************************/ /* Debug output */ /* Console output macro */ #define CPRINTS(format, args...) cprints(CC_USB, format, ## args) #define CPRINTF(format, args...) cprintf(CC_USB, format, ## args) /* TODO: Something unexpected happened. Figure out how to report & fix it. */ #define report_error(val) \ CPRINTS("Unhandled USB event at %s line %d: 0x%x", \ __FILE__, __LINE__, val) /****************************************************************************/ /* Standard USB stuff */ #ifdef CONFIG_USB_BOS /* v2.10 (vs 2.00) BOS Descriptor provided */ #define USB_DEV_BCDUSB 0x0210 #else #define USB_DEV_BCDUSB 0x0200 #endif #ifndef USB_DEV_CLASS #define USB_DEV_CLASS USB_CLASS_PER_INTERFACE #endif #ifndef CONFIG_USB_BCD_DEV #define CONFIG_USB_BCD_DEV 0x0100 /* 1.00 */ #endif #ifndef CONFIG_USB_SERIALNO #define USB_STR_SERIALNO 0 #else static int usb_load_serial(void); #endif /* USB Standard Device Descriptor */ static const struct usb_device_descriptor dev_desc = { .bLength = USB_DT_DEVICE_SIZE, .bDescriptorType = USB_DT_DEVICE, .bcdUSB = USB_DEV_BCDUSB, .bDeviceClass = USB_DEV_CLASS, .bDeviceSubClass = 0x00, .bDeviceProtocol = 0x00, .bMaxPacketSize0 = USB_MAX_PACKET_SIZE, .idVendor = USB_VID_GOOGLE, .idProduct = CONFIG_USB_PID, .bcdDevice = CONFIG_USB_BCD_DEV, .iManufacturer = USB_STR_VENDOR, .iProduct = USB_STR_PRODUCT, .iSerialNumber = USB_STR_SERIALNO, .bNumConfigurations = 1 }; /* USB Configuration Descriptor */ const struct usb_config_descriptor USB_CONF_DESC(conf) = { .bLength = USB_DT_CONFIG_SIZE, .bDescriptorType = USB_DT_CONFIGURATION, .wTotalLength = 0x0BAD, /* number of returned bytes, set at runtime */ .bNumInterfaces = USB_IFACE_COUNT, .bConfigurationValue = 1, /* Caution: hard-coded value */ .iConfiguration = USB_STR_VERSION, .bmAttributes = 0x80 /* Reserved bit */ #ifdef CONFIG_USB_SELF_POWERED /* bus or self powered */ | 0x40 #endif #ifdef CONFIG_USB_REMOTE_WAKEUP | 0x20 #endif , .bMaxPower = (CONFIG_USB_MAXPOWER_MA / 2), }; const uint8_t usb_string_desc[] = { 4, /* Descriptor size */ USB_DT_STRING, 0x09, 0x04 /* LangID = 0x0409: U.S. English */ }; /****************************************************************************/ /* Packet-handling stuff, specific to this SoC */ /* Some internal state to keep track of what's going on */ static enum { WAITING_FOR_SETUP_PACKET, DATA_STAGE_IN, NO_DATA_STAGE, } what_am_i_doing; #ifdef DEBUG_ME static const char * const wat[3] = { [WAITING_FOR_SETUP_PACKET] = "wait_for_setup", [DATA_STAGE_IN] = "data_in", [NO_DATA_STAGE] = "no_data", }; #endif /* Programmer's Guide, Table 10-7 */ enum table_case { BAD_0, TABLE_CASE_COMPLETE, TABLE_CASE_SETUP, TABLE_CASE_WTF, TABLE_CASE_D, TABLE_CASE_E, BAD_6, BAD_7, }; static enum table_case decode_table_10_7(uint32_t doepint) { enum table_case val = BAD_0; /* Bits: SI, SPD, IOC */ if (doepint & DOEPINT_XFERCOMPL) val += 1; if (doepint & DOEPINT_SETUP) val += 2; return val; } /* For STATUS/OUT: Use two DMA descriptors, each with one-packet buffers */ #define NUM_OUT_BUFFERS 2 static uint8_t ep0_setup_buf[USB_MAX_PACKET_SIZE]; /* For IN: Several DMA descriptors, all pointing into one large buffer, so that * we can return the configuration descriptor as one big blob. */ #define NUM_IN_PACKETS_AT_ONCE 4 #define IN_BUF_SIZE (NUM_IN_PACKETS_AT_ONCE * USB_MAX_PACKET_SIZE) static uint8_t ep0_in_buf[IN_BUF_SIZE]; struct dwc_usb_ep ep0_ctl = { .max_packet = USB_MAX_PACKET_SIZE, .tx_fifo = 0, .out_pending = 0, .out_expected = 0, .out_data = 0, .out_databuffer = ep0_setup_buf, .out_databuffer_max = sizeof(ep0_setup_buf), .rx_deferred = 0, .in_packets = 0, .in_pending = 0, .in_data = 0, .in_databuffer = ep0_in_buf, .in_databuffer_max = sizeof(ep0_in_buf), .tx_deferred = 0, }; /* Overall device state (USB 2.0 spec, section 9.1.1). * We only need a few, though. */ static enum { DS_DEFAULT, DS_ADDRESS, DS_CONFIGURED, } device_state; static uint8_t configuration_value; /* True if the HW Rx/OUT FIFO is currently listening. */ int rx_ep_is_active(uint32_t ep_num) { return (GR_USB_DOEPCTL(ep_num) & DXEPCTL_EPENA) ? 1 : 0; } /* Number of bytes the HW Rx/OUT FIFO has for us. * * @param ep_num USB endpoint * * @returns number of bytes ready, zero if none. */ int rx_ep_pending(uint32_t ep_num) { struct dwc_usb_ep *ep = usb_ctl.ep[ep_num]; return ep->out_pending; } /* True if the Tx/IN FIFO can take some bytes from us. */ int tx_ep_is_ready(uint32_t ep_num) { struct dwc_usb_ep *ep = usb_ctl.ep[ep_num]; int ready; /* Is the tx hw idle? */ ready = !(GR_USB_DIEPCTL(ep_num) & DXEPCTL_EPENA); /* Is there no pending data? */ ready &= (ep->in_pending == 0); return ready; } /* Write packets of data IN to the host. * * This function uses DMA, so the *data write buffer * must persist until the write completion event. * * @param ep_num USB endpoint to write * @param len number of bytes to write * @param data pointer of data to write * * @return bytes written */ int usb_write_ep(uint32_t ep_num, int len, void *data) { struct dwc_usb_ep *ep = usb_ctl.ep[ep_num]; if (GR_USB_DIEPCTL(ep_num) & DXEPCTL_EPENA) { CPRINTS("usb_write_ep ep%d: FAIL: tx already in progress!"); return 0; } /* We will send as many packets as necessary, including a final * packet of < USB_MAX_PACKET_SIZE (maybe zero length) */ ep->in_packets = (len + USB_MAX_PACKET_SIZE - 1) / USB_MAX_PACKET_SIZE; ep->in_pending = len; ep->in_data = data; GR_USB_DIEPTSIZ(ep_num) = 0; GR_USB_DIEPTSIZ(ep_num) |= DXEPTSIZ_PKTCNT(ep->in_packets); GR_USB_DIEPTSIZ(ep_num) |= DXEPTSIZ_XFERSIZE(len); GR_USB_DIEPDMA(ep_num) = (uint32_t)(ep->in_data); /* We could support longer multi-dma transfers here. */ ep->in_pending -= len; ep->in_packets -= ep->in_packets; ep->in_data += len; /* We are ready to enable this endpoint to start transferring data. */ GR_USB_DIEPCTL(ep_num) |= DXEPCTL_CNAK | DXEPCTL_EPENA; return len; } /* Tx/IN interrupt handler */ void usb_epN_tx(uint32_t ep_num) { struct dwc_usb_ep *ep = usb_ctl.ep[ep_num]; uint32_t dieptsiz = GR_USB_DIEPTSIZ(ep_num); if (GR_USB_DIEPCTL(ep_num) & DXEPCTL_EPENA) { CPRINTS("usb_epN_tx ep%d: tx still active.", ep_num); return; } /* clear the Tx/IN interrupts */ GR_USB_DIEPINT(ep_num) = 0xffffffff; /* * Let's assume this is actually true. * We could support multi-dma transfers here. */ ep->in_packets = 0; ep->in_pending = dieptsiz & GC_USB_DIEPTSIZ1_XFERSIZE_MASK; if (ep->tx_deferred) hook_call_deferred(ep->tx_deferred, 0); } /* Read a packet of data OUT from the host. * * This function uses DMA, so the *data write buffer * must persist until the read completion event. * * @param ep_num USB endpoint to read * @param len number of bytes to read * @param data pointer of data to read * * @return EC_SUCCESS on success */ int usb_read_ep(uint32_t ep_num, int len, void *data) { struct dwc_usb_ep *ep = usb_ctl.ep[ep_num]; int packets = (len + USB_MAX_PACKET_SIZE - 1) / USB_MAX_PACKET_SIZE; ep->out_data = data; ep->out_pending = 0; ep->out_expected = len; GR_USB_DOEPTSIZ(ep_num) = 0; GR_USB_DOEPTSIZ(ep_num) |= DXEPTSIZ_PKTCNT(packets); GR_USB_DOEPTSIZ(ep_num) |= DXEPTSIZ_XFERSIZE(len); GR_USB_DOEPDMA(ep_num) = (uint32_t)ep->out_data; GR_USB_DOEPCTL(ep_num) |= DXEPCTL_CNAK | DXEPCTL_EPENA; return EC_SUCCESS; } /* Rx/OUT endpoint interrupt handler */ void usb_epN_rx(uint32_t ep_num) { struct dwc_usb_ep *ep = usb_ctl.ep[ep_num]; /* Still receiving data. Let's wait. */ if (rx_ep_is_active(ep_num)) return; /* Bytes received decrement DOEPTSIZ XFERSIZE */ if (GR_USB_DOEPINT(ep_num) & DOEPINT_XFERCOMPL) { if (ep->out_expected > 0) { ep->out_pending = ep->out_expected - (GR_USB_DOEPTSIZ(ep_num) & GC_USB_DOEPTSIZ1_XFERSIZE_MASK); } else { CPRINTF("usb_ep%d_rx: unexpected RX DOEPTSIZ %08x\n", ep_num, GR_USB_DOEPTSIZ(ep_num)); ep->out_pending = 0; } ep->out_expected = 0; GR_USB_DOEPTSIZ(ep_num) = 0; } /* clear the RX/OUT interrupts */ GR_USB_DOEPINT(ep_num) = 0xffffffff; if (ep->rx_deferred) hook_call_deferred(ep->rx_deferred, 0); } /* Reset endpoint HW block. */ void epN_reset(uint32_t ep_num) { GR_USB_DOEPCTL(ep_num) = DXEPCTL_MPS(USB_MAX_PACKET_SIZE) | DXEPCTL_USBACTEP | DXEPCTL_EPTYPE_BULK; GR_USB_DIEPCTL(ep_num) = DXEPCTL_MPS(USB_MAX_PACKET_SIZE) | DXEPCTL_USBACTEP | DXEPCTL_EPTYPE_BULK | DXEPCTL_TXFNUM(ep_num); GR_USB_DAINTMSK |= DAINT_INEP(ep_num) | DAINT_OUTEP(ep_num); } /****************************************************************************** * Internal and EP0 functions. */ static void flush_all_fifos(void) { /* Flush all FIFOs according to Section 2.1.1.2 */ GR_USB_GRSTCTL = GRSTCTL_TXFNUM(0x10) | GRSTCTL_TXFFLSH | GRSTCTL_RXFFLSH; while (GR_USB_GRSTCTL & (GRSTCTL_TXFFLSH | GRSTCTL_RXFFLSH)) ; } int send_in_packet(uint32_t ep_num) { struct dwc_usb *usb = &usb_ctl; struct dwc_usb_ep *ep = usb->ep[ep_num]; int len = MIN(USB_MAX_PACKET_SIZE, ep->in_pending); if (ep->in_packets == 0) { report_error(ep_num); return -1; } GR_USB_DIEPTSIZ(ep_num) = 0; GR_USB_DIEPTSIZ(ep_num) |= DXEPTSIZ_PKTCNT(1); GR_USB_DIEPTSIZ(0) |= DXEPTSIZ_XFERSIZE(len); GR_USB_DIEPDMA(0) = (uint32_t)ep->in_data; /* We're sending this much. */ ep->in_pending -= len; ep->in_packets -= 1; ep->in_data += len; /* We are ready to enable this endpoint to start transferring data. */ return len; } /* Load the EP0 IN FIFO buffer with some data (zero-length works too). Returns * len, or negative on error. */ int initialize_in_transfer(const void *source, uint32_t len) { struct dwc_usb *usb = &usb_ctl; struct dwc_usb_ep *ep = usb->ep[0]; #ifdef CONFIG_USB_DWC_FS /* FS OTG port does not support DMA or external phy */ ASSERT(!(usb->dma_en)); ASSERT(usb->phy_type == USB_PHY_INTERNAL); ASSERT(usb->speed == USB_SPEED_FS); ASSERT(usb->irq == STM32_IRQ_OTG_FS); #else /* HS OTG port requires an external phy to support HS */ ASSERT(!((usb->phy_type == USB_PHY_INTERNAL) && (usb->speed == USB_SPEED_HS))); ASSERT(usb->irq == STM32_IRQ_OTG_HS); #endif /* Copy the data into our FIFO buffer */ if (len >= IN_BUF_SIZE) { report_error(len); return -1; } /* Stage data in DMA buffer. */ memcpy(ep->in_databuffer, source, len); ep->in_data = ep->in_databuffer; /* We will send as many packets as necessary, including a final * packet of < USB_MAX_PACKET_SIZE (maybe zero length) */ ep->in_packets = (len + USB_MAX_PACKET_SIZE)/USB_MAX_PACKET_SIZE; ep->in_pending = len; send_in_packet(0); return len; } /* Prepare the EP0 OUT FIFO buffer to accept some data. Returns len, or * negative on error. */ int accept_out_fifo(uint32_t len) { /* TODO: This is not yet implemented */ report_error(len); return -1; } /* The next packet from the host should be a Setup packet. Get ready for it. */ static void expect_setup_packet(void) { struct dwc_usb *usb = &usb_ctl; struct dwc_usb_ep *ep = usb->ep[0]; what_am_i_doing = WAITING_FOR_SETUP_PACKET; ep->out_data = ep->out_databuffer; /* We don't care about IN packets right now, only OUT. */ GR_USB_DAINTMSK |= DAINT_OUTEP(0); GR_USB_DAINTMSK &= ~DAINT_INEP(0); GR_USB_DOEPTSIZ(0) = 0; GR_USB_DOEPTSIZ(0) |= DXEPTSIZ_PKTCNT(1); GR_USB_DOEPTSIZ(0) |= DXEPTSIZ_XFERSIZE(0x18); GR_USB_DOEPTSIZ(0) |= DXEPTSIZ_SUPCNT(1); GR_USB_DOEPCTL(0) = DXEPCTL_USBACTEP | DXEPCTL_EPENA; GR_USB_DOEPDMA(0) = (uint32_t)ep->out_data; } /* We're complaining about something by stalling both IN and OUT packets, * but a SETUP packet will get through anyway, so prepare for it. */ static void stall_both_fifos(void) { what_am_i_doing = WAITING_FOR_SETUP_PACKET; /* We don't care about IN packets right now, only OUT. */ GR_USB_DAINTMSK |= DAINT_OUTEP(0); GR_USB_DAINTMSK &= ~DAINT_INEP(0); GR_USB_DOEPCTL(0) |= DXEPCTL_STALL; GR_USB_DIEPCTL(0) |= DXEPCTL_STALL; expect_setup_packet(); } /* The TX FIFO buffer is loaded. Start the Data phase. */ static void expect_data_phase_in(enum table_case tc) { what_am_i_doing = DATA_STAGE_IN; /* Send the reply (data phase in) */ if (tc == TABLE_CASE_SETUP) GR_USB_DIEPCTL(0) |= DXEPCTL_USBACTEP | DXEPCTL_CNAK | DXEPCTL_EPENA; else GR_USB_DIEPCTL(0) |= DXEPCTL_EPENA; /* We'll receive an empty packet back as a ack, I guess. */ if (tc == TABLE_CASE_SETUP) GR_USB_DOEPCTL(0) |= DXEPCTL_CNAK | DXEPCTL_EPENA; else GR_USB_DOEPCTL(0) |= DXEPCTL_EPENA; /* Get an interrupt when either IN or OUT arrives */ GR_USB_DAINTMSK |= (DAINT_OUTEP(0) | DAINT_INEP(0)); } static void expect_data_phase_out(enum table_case tc) { /* TODO: This is not yet supported */ report_error(tc); expect_setup_packet(); } /* No Data phase, just Status phase (which is IN, since Setup is OUT) */ static void expect_status_phase_in(enum table_case tc) { what_am_i_doing = NO_DATA_STAGE; /* Expect a zero-length IN for the Status phase */ (void) initialize_in_transfer(0, 0); /* Blindly following instructions here, too. */ if (tc == TABLE_CASE_SETUP) GR_USB_DIEPCTL(0) |= DXEPCTL_USBACTEP | DXEPCTL_CNAK | DXEPCTL_EPENA; else GR_USB_DIEPCTL(0) |= DXEPCTL_EPENA; /* Get an interrupt when either IN or OUT arrives */ GR_USB_DAINTMSK |= (DAINT_OUTEP(0) | DAINT_INEP(0)); } /* Handle a Setup packet that expects us to send back data in reply. Return the * length of the data we're returning, or negative to indicate an error. */ static int handle_setup_with_in_stage(enum table_case tc, struct usb_setup_packet *req) { struct dwc_usb *usb = &usb_ctl; struct dwc_usb_ep *ep = usb->ep[0]; const void *data = 0; uint32_t len = 0; int ugly_hack = 0; static const uint16_t zero; /* == 0 */ switch (req->bRequest) { case USB_REQ_GET_DESCRIPTOR: { uint8_t type = req->wValue >> 8; uint8_t idx = req->wValue & 0xff; switch (type) { case USB_DT_DEVICE: data = &dev_desc; len = sizeof(dev_desc); break; case USB_DT_CONFIGURATION: data = __usb_desc; len = USB_DESC_SIZE; ugly_hack = 1; /* see below */ break; #ifdef CONFIG_USB_BOS case USB_DT_BOS: data = bos_ctx.descp; len = bos_ctx.size; break; #endif case USB_DT_STRING: if (idx >= USB_STR_COUNT) return -1; #ifdef CONFIG_USB_SERIALNO if (idx == USB_STR_SERIALNO) data = (uint8_t *)usb_serialno_desc; else #endif data = usb_strings[idx]; len = *(uint8_t *)data; break; case USB_DT_DEVICE_QUALIFIER: /* We're not high speed */ return -1; case USB_DT_DEBUG: /* Not supported */ return -1; default: report_error(type); return -1; } break; } case USB_REQ_GET_STATUS: { /* TODO: Device Status: Remote Wakeup? Self Powered? */ data = &zero; len = sizeof(zero); break; } case USB_REQ_GET_CONFIGURATION: data = &configuration_value; len = sizeof(configuration_value); break; case USB_REQ_SYNCH_FRAME: /* Unimplemented */ return -1; default: report_error(req->bRequest); return -1; } /* Don't send back more than we were asked for. */ len = MIN(req->wLength, len); /* Prepare the TX FIFO. If we haven't preallocated enough room in the * TX FIFO for the largest reply, we'll have to stall. This is a bug in * our code, but detecting it easily at compile time is related to the * ugly_hack directly below. */ if (initialize_in_transfer(data, len) < 0) return -1; if (ugly_hack) { /* * TODO: Somebody figure out how to fix this, please. * * The USB configuration descriptor request is unique in that * it not only returns the configuration descriptor, but also * all the interface descriptors and all their endpoint * descriptors as one enormous blob. We've set up some macros * so we can declare and implement separate interfaces in * separate files just by compiling them, and all the relevant * descriptors are sorted and bundled up by the linker. But the * total length of the entire blob needs to appear in the first * configuration descriptor struct and because we don't know * that value until after linking, it can't be initialized as a * constant. So we have to compute it at run-time and shove it * in here, which also means that we have to copy the whole * blob into our TX FIFO buffer so that it's mutable. Otherwise * we could just point at it (or pretty much any other constant * struct that we wanted to send to the host). Bah. */ struct usb_config_descriptor *cfg = (struct usb_config_descriptor *)ep->in_databuffer; /* set the real descriptor size */ cfg->wTotalLength = USB_DESC_SIZE; } return len; } /* Handle a Setup that comes with additional data for us. */ static int handle_setup_with_out_stage(enum table_case tc, struct usb_setup_packet *req) { /* TODO: We don't support any of these. We should. */ report_error(-1); return -1; } /* Some Setup packets don't have a data stage at all. */ static int handle_setup_with_no_data_stage(enum table_case tc, struct usb_setup_packet *req) { uint8_t set_addr; switch (req->bRequest) { case USB_REQ_SET_ADDRESS: /* * Set the address after the IN packet handshake. * * From the USB 2.0 spec, section 9.4.6: * * As noted elsewhere, requests actually may result in * up to three stages. In the first stage, the Setup * packet is sent to the device. In the optional second * stage, data is transferred between the host and the * device. In the final stage, status is transferred * between the host and the device. The direction of * data and status transfer depends on whether the host * is sending data to the device or the device is * sending data to the host. The Status stage transfer * is always in the opposite direction of the Data * stage. If there is no Data stage, the Status stage * is from the device to the host. * * Stages after the initial Setup packet assume the * same device address as the Setup packet. The USB * device does not change its device address until * after the Status stage of this request is completed * successfully. Note that this is a difference between * this request and all other requests. For all other * requests, the operation indicated must be completed * before the Status stage */ set_addr = req->wValue & 0xff; /* * NOTE: Now that we've said that, we don't do it. The * hardware for this SoC knows that an IN packet will * be following the SET ADDRESS, so it waits until it * sees that happen before the address change takes * effect. If we wait until after the IN packet to * change the register, the hardware gets confused and * doesn't respond to anything. */ GWRITE_FIELD(USB, DCFG, DEVADDR, set_addr); CPRINTS("SETAD 0x%02x (%d)", set_addr, set_addr); device_state = DS_ADDRESS; break; case USB_REQ_SET_CONFIGURATION: switch (req->wValue) { case 0: configuration_value = req->wValue; device_state = DS_ADDRESS; break; case 1: /* Caution: Only one config descriptor TODAY */ /* TODO: All endpoints set to DATA0 toggle state */ configuration_value = req->wValue; device_state = DS_CONFIGURED; break; default: /* Nope. That's a paddlin. */ report_error(-1); return -1; } break; case USB_REQ_CLEAR_FEATURE: case USB_REQ_SET_FEATURE: /* TODO: Handle DEVICE_REMOTE_WAKEUP, ENDPOINT_HALT? */ break; default: /* Anything else is unsupported */ report_error(-1); return -1; } /* No data to transfer, go straight to the Status phase. */ return 0; } /* Dispatch an incoming Setup packet according to its type */ static void handle_setup(enum table_case tc) { struct dwc_usb *usb = &usb_ctl; struct dwc_usb_ep *ep = usb->ep[0]; struct usb_setup_packet *req = (struct usb_setup_packet *)ep->out_databuffer; int data_phase_in = req->bmRequestType & USB_DIR_IN; int data_phase_out = !data_phase_in && req->wLength; int bytes = -1; /* default is to stall */ if (0 == (req->bmRequestType & (USB_TYPE_MASK | USB_RECIP_MASK))) { /* Standard Device requests */ if (data_phase_in) bytes = handle_setup_with_in_stage(tc, req); else if (data_phase_out) bytes = handle_setup_with_out_stage(tc, req); else bytes = handle_setup_with_no_data_stage(tc, req); } else if (USB_RECIP_INTERFACE == (req->bmRequestType & USB_RECIP_MASK)) { /* Interface-specific requests */ uint8_t iface = req->wIndex & 0xff; if (iface < USB_IFACE_COUNT) bytes = usb_iface_request[iface](req); } else { /* Something we need to add support for? */ report_error(-1); } /* We say "no" to unsupported and intentionally unhandled requests by * stalling the Data and/or Status stage. */ if (bytes < 0) { /* Stall both IN and OUT. SETUP will come through anyway. */ stall_both_fifos(); } else { if (data_phase_in) expect_data_phase_in(tc); else if (data_phase_out) expect_data_phase_out(tc); else expect_status_phase_in(tc); } } /* This handles both IN and OUT interrupts for EP0 */ static void ep0_interrupt(uint32_t intr_on_out, uint32_t intr_on_in) { struct dwc_usb *usb = &usb_ctl; struct dwc_usb_ep *ep = usb->ep[0]; uint32_t doepint, diepint; enum table_case tc; int out_complete, out_setup, in_complete; /* Determine the interrupt cause and clear the bits quickly, but only * if they really apply. I don't think they're trustworthy if we didn't * actually get an interrupt. */ doepint = GR_USB_DOEPINT(0) & GR_USB_DOEPMSK; if (intr_on_out) GR_USB_DOEPINT(0) = doepint; diepint = GR_USB_DIEPINT(0) & GR_USB_DIEPMSK; if (intr_on_in) GR_USB_DIEPINT(0) = diepint; out_complete = doepint & DOEPINT_XFERCOMPL; out_setup = doepint & DOEPINT_SETUP; in_complete = diepint & DIEPINT_XFERCOMPL; /* Decode the situation according to Table 10-7 */ tc = decode_table_10_7(doepint); switch (what_am_i_doing) { case WAITING_FOR_SETUP_PACKET: if (out_setup) handle_setup(tc); else report_error(-1); break; case DATA_STAGE_IN: if (intr_on_in && in_complete) { /* A packet is sent. Should we send another? */ if (ep->in_packets > 0) { /* Send another packet. */ send_in_packet(0); expect_data_phase_in(tc); } } /* But we should ignore the OUT endpoint if we didn't actually * get an OUT interrupt. */ if (!intr_on_out) break; if (out_setup) { /* The first IN packet has been seen. Keep going. */ break; } if (out_complete) { /* We've handled the Status phase. All done. */ expect_setup_packet(); break; } /* Anything else should be ignorable. Right? */ break; case NO_DATA_STAGE: if (intr_on_in && in_complete) { /* We are not expecting an empty packet in * return for our empty packet. */ expect_setup_packet(); } /* Done unless we got an OUT interrupt */ if (!intr_on_out) break; if (out_setup) { report_error(-1); break; } /* Anything else means get ready for a Setup packet */ report_error(-1); expect_setup_packet(); break; } } /****************************************************************************/ /* USB device initialization and shutdown routines */ /* * DATA FIFO Setup. There is an internal SPRAM used to buffer the IN/OUT * packets and track related state without hammering the AHB and system RAM * during USB transactions. We have to specify where and how much of that SPRAM * to use for what. * * See Programmer's Guide chapter 2, "Calculating FIFO Size". * We're using Dedicated TxFIFO Operation, without enabling thresholding. * * Section 2.1.1.2, page 30: RXFIFO size is the same as for Shared FIFO, which * is Section 2.1.1.1, page 28. This is also the same as Method 2 on page 45. * * We support up to 3 control EPs, no periodic IN EPs, up to 16 TX EPs. Max * data packet size is 64 bytes. Total SPRAM available is 1024 slots. */ #define MAX_CONTROL_EPS 3 #define MAX_NORMAL_EPS 16 #define FIFO_RAM_DEPTH 1024 /* * Device RX FIFO size is thus: * (4 * 3 + 6) + 2 * ((64 / 4) + 1) + (2 * 16) + 1 == 85 */ #define RXFIFO_SIZE ((4 * MAX_CONTROL_EPS + 6) + \ 2 * ((USB_MAX_PACKET_SIZE / 4) + 1) + \ (2 * MAX_NORMAL_EPS) + 1) /* * Device TX FIFO size is 2 * (64 / 4) == 32 for each IN EP (Page 46). */ #define TXFIFO_SIZE (2 * (USB_MAX_PACKET_SIZE / 4)) /* * We need 4 slots per endpoint direction for endpoint status stuff (Table 2-1, * unconfigurable). */ #define EP_STATUS_SIZE (4 * MAX_NORMAL_EPS * 2) /* * Make sure all that fits. */ BUILD_ASSERT(RXFIFO_SIZE + TXFIFO_SIZE * MAX_NORMAL_EPS + EP_STATUS_SIZE < FIFO_RAM_DEPTH); /* Now put those constants into the correct registers */ static void setup_data_fifos(void) { int i; /* Programmer's Guide, p31 */ GR_USB_GRXFSIZ = RXFIFO_SIZE; /* RXFIFO */ GR_USB_GNPTXFSIZ = (TXFIFO_SIZE << 16) | RXFIFO_SIZE; /* TXFIFO 0 */ /* TXFIFO 1..15 */ for (i = 1; i < MAX_NORMAL_EPS; i++) GR_USB_DIEPTXF(i) = ((TXFIFO_SIZE << 16) | (RXFIFO_SIZE + i * TXFIFO_SIZE)); /* * TODO: The Programmer's Guide is confusing about when or whether to * flush the FIFOs. Section 2.1.1.2 (p31) just says to flush. Section * 2.2.2 (p55) says to stop all the FIFOs first, then flush. Section * 7.5.4 (p162) says that flushing the RXFIFO at reset is not * recommended at all. * * I'm also unclear on whether or not the individual EPs are expected * to be disabled already (DIEPCTLn/DOEPCTLn.EPENA == 0), and if so, * whether by firmware or hardware. */ /* Flush all FIFOs according to Section 2.1.1.2 */ GR_USB_GRSTCTL = GRSTCTL_TXFNUM(0x10) | GRSTCTL_TXFFLSH | GRSTCTL_RXFFLSH; while (GR_USB_GRSTCTL & (GRSTCTL_TXFFLSH | GRSTCTL_RXFFLSH)) ; /* TODO: timeout 100ms */ } static void usb_init_endpoints(void) { int ep; /* Prepare to receive packets on EP0 */ expect_setup_packet(); /* Reset the other endpoints */ for (ep = 1; ep < USB_EP_COUNT; ep++) usb_ep_event[ep](USB_EVENT_RESET); } static void usb_reset(void) { /* Clear our internal state */ device_state = DS_DEFAULT; configuration_value = 0; /* Clear the device address */ GWRITE_FIELD(USB, DCFG, DEVADDR, 0); /* Reinitialize all the endpoints */ usb_init_endpoints(); } static void usb_resetdet(void) { /* TODO: Same as normal reset, right? I think we only get this if we're * suspended (sleeping) and the host resets us. Try it and see. */ usb_reset(); } static void usb_enumdone(void) { /* We can change to HS here. We will not go to HS today */ GR_USB_DCTL |= DCTL_CGOUTNAK; } void usb_interrupt(void) { uint32_t status = GR_USB_GINTSTS & GR_USB_GINTMSK; uint32_t oepint = status & GINTSTS(OEPINT); uint32_t iepint = status & GINTSTS(IEPINT); int ep; if (status & GINTSTS(ENUMDONE)) usb_enumdone(); if (status & GINTSTS(RESETDET)) usb_resetdet(); if (status & GINTSTS(USBRST)) usb_reset(); /* Endpoint interrupts */ if (oepint || iepint) { /* Note: It seems that the DAINT bits are only trustworthy for * identifying interrupts when selected by the corresponding * OEPINT and IEPINT bits from GINTSTS. */ uint32_t daint = GR_USB_DAINT; /* EP0 has a combined IN/OUT handler. Only call it once, but * let it know which direction(s) had an interrupt. */ if (daint & (DAINT_OUTEP(0) | DAINT_INEP(0))) { uint32_t intr_on_out = (oepint && (daint & DAINT_OUTEP(0))); uint32_t intr_on_in = (iepint && (daint & DAINT_INEP(0))); ep0_interrupt(intr_on_out, intr_on_in); } /* Invoke the unidirectional IN and OUT functions for the other * endpoints. Each handler must clear their own bits in * DIEPINTn/DOEPINTn. */ for (ep = 1; ep < USB_EP_COUNT; ep++) { if (oepint && (daint & DAINT_OUTEP(ep))) usb_ep_rx[ep](); if (iepint && (daint & DAINT_INEP(ep))) usb_ep_tx[ep](); } } GR_USB_GINTSTS = status; } DECLARE_IRQ(STM32_IRQ_OTG_FS, usb_interrupt, 1); DECLARE_IRQ(STM32_IRQ_OTG_HS, usb_interrupt, 1); static void usb_softreset(void) { int timeout; CPRINTS("%s", __func__); /* Wait for bus idle */ timeout = 10000; while (!(GR_USB_GRSTCTL & GRSTCTL_AHBIDLE) && timeout-- > 0) ; /* Reset and wait for clear */ GR_USB_GRSTCTL = GRSTCTL_CSFTRST; timeout = 10000; while ((GR_USB_GRSTCTL & GRSTCTL_CSFTRST) && timeout-- > 0) ; if (GR_USB_GRSTCTL & GRSTCTL_CSFTRST) { CPRINTF("USB: reset failed\n"); return; } /* Some more idle? */ timeout = 10000; while (!(GR_USB_GRSTCTL & GRSTCTL_AHBIDLE) && timeout-- > 0) ; if (!timeout) { CPRINTF("USB: reset timeout\n"); return; } /* TODO: Wait 3 PHY clocks before returning */ } void usb_connect(void) { GR_USB_DCTL &= ~DCTL_SFTDISCON; } void usb_disconnect(void) { GR_USB_DCTL |= DCTL_SFTDISCON; device_state = DS_DEFAULT; configuration_value = 0; } void usb_reset_init_phy(void) { struct dwc_usb *usb = &usb_ctl; if (usb->phy_type == USB_PHY_ULPI) { GR_USB_GCCFG &= ~GCCFG_PWRDWN; GR_USB_GUSBCFG &= ~(GUSBCFG_TSDPS | GUSBCFG_ULPIFSLS | GUSBCFG_PHYSEL); GR_USB_GUSBCFG &= ~(GUSBCFG_ULPIEVBUSD | GUSBCFG_ULPIEVBUSI); /* No suspend */ GR_USB_GUSBCFG |= GUSBCFG_ULPICSM | GUSBCFG_ULPIAR; usb_softreset(); } else { GR_USB_GUSBCFG |= GUSBCFG_PHYSEL; usb_softreset(); GR_USB_GCCFG |= GCCFG_PWRDWN; } } void usb_init(void) { int i; struct dwc_usb *usb = &usb_ctl; CPRINTS("%s", __func__); #ifdef CONFIG_USB_SERIALNO usb_load_serial(); #endif /* USB is in use */ disable_sleep(SLEEP_MASK_USB_DEVICE); /* Enable clocks */ clock_enable_module(MODULE_USB, 0); clock_enable_module(MODULE_USB, 1); /* TODO(crbug.com/496888): set up pinmux */ gpio_config_module(MODULE_USB, 1); /* Make sure interrupts are disabled */ GR_USB_GINTMSK = 0; GR_USB_DAINTMSK = 0; GR_USB_DIEPMSK = 0; GR_USB_DOEPMSK = 0; /* Full-Speed Serial PHY */ usb_reset_init_phy(); /* Global + DMA configuration */ GR_USB_GAHBCFG = GAHBCFG_GLB_INTR_EN; GR_USB_GAHBCFG |= GAHBCFG_HBSTLEN_INCR4; if (usb->dma_en) GR_USB_GAHBCFG |= GAHBCFG_DMA_EN; /* Device only, no SRP */ GR_USB_GUSBCFG |= GUSBCFG_FDMOD; GR_USB_GUSBCFG |= GUSBCFG_SRPCAP | GUSBCFG_HNPCAP; GR_USB_GCCFG &= ~GCCFG_VBDEN; GR_USB_GOTGCTL |= GOTGCTL_BVALOEN; GR_USB_GOTGCTL |= GOTGCTL_BVALOVAL; GR_USB_PCGCCTL = 0; if (usb->phy_type == USB_PHY_ULPI) { /* TODO(nsanders): add HS support like so. * GR_USB_DCFG = (GR_USB_DCFG & ~GC_USB_DCFG_DEVSPD_MASK) * | DCFG_DEVSPD_HSULPI; */ GR_USB_DCFG = (GR_USB_DCFG & ~GC_USB_DCFG_DEVSPD_MASK) | DCFG_DEVSPD_FSULPI; } else { GR_USB_DCFG = (GR_USB_DCFG & ~GC_USB_DCFG_DEVSPD_MASK) | DCFG_DEVSPD_FS48; } GR_USB_DCFG |= DCFG_NZLSOHSK; flush_all_fifos(); /* Clear pending interrupts again */ GR_USB_GINTMSK = 0; GR_USB_DIEPMSK = 0; GR_USB_DOEPMSK = 0; GR_USB_DAINT = 0xffffffff; GR_USB_DAINTMSK = 0; /* TODO: What about the AHB Burst Length Field? It's 0 now. */ GR_USB_GAHBCFG |= GAHBCFG_TXFELVL | GAHBCFG_PTXFELVL; /* Device only, no SRP */ GR_USB_GUSBCFG |= GUSBCFG_FDMOD | GUSBCFG_TOUTCAL(7) /* FIXME: Magic number! 14 is for 15MHz! Use 9 for 30MHz */ | GUSBCFG_USBTRDTIM(14); /* Be in disconnected state until we are ready */ usb_disconnect(); /* If we've restored a nonzero device address, update our state. */ if (GR_USB_DCFG & GC_USB_DCFG_DEVADDR_MASK) { /* Caution: We only have one config TODAY, so there's no real * difference between DS_CONFIGURED and DS_ADDRESS. */ device_state = DS_CONFIGURED; configuration_value = 1; } else { device_state = DS_DEFAULT; configuration_value = 0; } /* Now that DCFG.DesDMA is accurate, prepare the FIFOs */ setup_data_fifos(); usb_init_endpoints(); /* Clear any pending interrupts */ for (i = 0; i < 16; i++) { GR_USB_DIEPINT(i) = 0xffffffff; GR_USB_DIEPTSIZ(i) = 0; GR_USB_DOEPINT(i) = 0xffffffff; GR_USB_DOEPTSIZ(i) = 0; } if (usb->dma_en) { GR_USB_DTHRCTL = DTHRCTL_TXTHRLEN_6 | DTHRCTL_RXTHRLEN_6; GR_USB_DTHRCTL |= DTHRCTL_RXTHREN | DTHRCTL_ISOTHREN | DTHRCTL_NONISOTHREN; i = GR_USB_DTHRCTL; } GR_USB_GINTSTS = 0xFFFFFFFF; GR_USB_GAHBCFG |= GAHBCFG_GLB_INTR_EN | GAHBCFG_TXFELVL | GAHBCFG_PTXFELVL; if (!(usb->dma_en)) GR_USB_GINTMSK |= GINTMSK(RXFLVL); /* Unmask some endpoint interrupt causes */ GR_USB_DIEPMSK = DIEPMSK_EPDISBLDMSK | DIEPMSK_XFERCOMPLMSK; GR_USB_DOEPMSK = DOEPMSK_EPDISBLDMSK | DOEPMSK_XFERCOMPLMSK | DOEPMSK_SETUPMSK; /* Enable interrupt handlers */ task_enable_irq(usb->irq); /* Allow USB interrupts to come in */ GR_USB_GINTMSK |= /* NAK bits that must be cleared by the DCTL register */ GINTMSK(GOUTNAKEFF) | GINTMSK(GINNAKEFF) | /* Initialization events */ GINTMSK(USBRST) | GINTMSK(ENUMDONE) | /* Reset detected while suspended. Need to wake up. */ GINTMSK(RESETDET) | /* TODO: Do we need this? */ /* Idle, Suspend detected. Should go to sleep. */ GINTMSK(ERLYSUSP) | GINTMSK(USBSUSP); GR_USB_GINTMSK |= /* Endpoint activity, cleared by the DOEPINT/DIEPINT regs */ GINTMSK(OEPINT) | GINTMSK(IEPINT); /* Device registers have been setup */ GR_USB_DCTL |= DCTL_PWRONPRGDONE; udelay(10); GR_USB_DCTL &= ~DCTL_PWRONPRGDONE; /* Clear global NAKs */ GR_USB_DCTL |= DCTL_CGOUTNAK | DCTL_CGNPINNAK; #ifndef CONFIG_USB_INHIBIT_CONNECT /* Indicate our presence to the USB host */ usb_connect(); #endif } #ifndef CONFIG_USB_INHIBIT_INIT DECLARE_HOOK(HOOK_INIT, usb_init, HOOK_PRIO_DEFAULT); #endif void usb_release(void) { struct dwc_usb *usb = &usb_ctl; /* signal disconnect to host */ usb_disconnect(); /* disable interrupt handlers */ task_disable_irq(usb->irq); /* disable clocks */ clock_enable_module(MODULE_USB, 0); /* TODO: pin-mux */ /* USB is off, so sleep whenever */ enable_sleep(SLEEP_MASK_USB_DEVICE); } /* Print USB info and stats */ static void usb_info(void) { struct dwc_usb *usb = &usb_ctl; int i; CPRINTF("USB settings: %s%s%s\n", usb->speed == USB_SPEED_FS ? "FS " : "HS ", usb->phy_type == USB_PHY_INTERNAL ? "Internal Phy " : "ULPI ", usb->dma_en ? "DMA " : ""); for (i = 0; i < USB_EP_COUNT; i++) { CPRINTF("Endpoint %d activity: %s%s\n", i, rx_ep_is_active(i) ? "RX " : "", tx_ep_is_ready(i) ? "" : "TX "); } } static int command_usb(int argc, char **argv) { if (argc > 1) { if (!strcasecmp("on", argv[1])) usb_init(); else if (!strcasecmp("off", argv[1])) usb_release(); else if (!strcasecmp("info", argv[1])) usb_info(); return EC_SUCCESS; } return EC_ERROR_PARAM1; } DECLARE_CONSOLE_COMMAND(usb, command_usb, "[on|off|info]", "Get/set the USB connection state and PHY selection"); #ifdef CONFIG_USB_SERIALNO /* This will be subbed into USB_STR_SERIALNO. */ struct usb_string_desc *usb_serialno_desc = USB_WR_STRING_DESC(DEFAULT_SERIALNO); /* Update serial number */ static int usb_set_serial(const char *serialno) { struct usb_string_desc *sd = usb_serialno_desc; int i; if (!serialno) return EC_ERROR_INVAL; /* Convert into unicode usb string desc. */ for (i = 0; i < CONFIG_SERIALNO_LEN; i++) { sd->_data[i] = serialno[i]; if (serialno[i] == 0) break; } /* Count wchars (w/o null terminator) plus size & type bytes. */ sd->_len = (i * 2) + 2; sd->_type = USB_DT_STRING; return EC_SUCCESS; } /* Retrieve serial number from pstate flash. */ static int usb_load_serial(void) { const char *serialno; int rv; serialno = board_read_serial(); if (!serialno) return EC_ERROR_ACCESS_DENIED; rv = usb_set_serial(serialno); return rv; } /* Save serial number into pstate region. */ static int usb_save_serial(const char *serialno) { int rv; if (!serialno) return EC_ERROR_INVAL; /* Save this new serial number to flash. */ rv = board_write_serial(serialno); if (rv) return rv; /* Load this new serial number to memory. */ rv = usb_load_serial(); return rv; } static int command_serialno(int argc, char **argv) { struct usb_string_desc *sd = usb_serialno_desc; char buf[CONFIG_SERIALNO_LEN]; int rv = EC_SUCCESS; int i; if (argc != 1) { if ((strcasecmp(argv[1], "set") == 0) && (argc == 3)) { ccprintf("Saving serial number\n"); rv = usb_save_serial(argv[2]); } else if ((strcasecmp(argv[1], "load") == 0) && (argc == 2)) { ccprintf("Loading serial number\n"); rv = usb_load_serial(); } else return EC_ERROR_INVAL; } for (i = 0; i < CONFIG_SERIALNO_LEN; i++) buf[i] = sd->_data[i]; ccprintf("Serial number: %s\n", buf); return rv; } DECLARE_CONSOLE_COMMAND(serialno, command_serialno, "load/set [value]", "Read and write USB serial number"); #endif /* CONFIG_USB_SERIALNO */