summaryrefslogtreecommitdiff
path: root/chip/stm32/usb.c
diff options
context:
space:
mode:
Diffstat (limited to 'chip/stm32/usb.c')
-rw-r--r--chip/stm32/usb.c957
1 files changed, 0 insertions, 957 deletions
diff --git a/chip/stm32/usb.c b/chip/stm32/usb.c
deleted file mode 100644
index 0077815a27..0000000000
--- a/chip/stm32/usb.c
+++ /dev/null
@@ -1,957 +0,0 @@
-/* Copyright 2013 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 "system.h"
-#include "task.h"
-#include "timer.h"
-#include "util.h"
-#include "usb_api.h"
-#include "usb_descriptor.h"
-#include "usb_hw.h"
-
-/* Console output macro */
-#define CPRINTF(format, args...) cprintf(CC_USB, format, ## args)
-
-#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
-
-#define USB_RESUME_TIMEOUT_MS 3000
-
-/* 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 = CONFIG_USB_VID,
- .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, /* no of returned bytes, set at runtime */
- .bNumInterfaces = USB_IFACE_COUNT,
- .bConfigurationValue = 1,
- .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 */
-};
-
-/* Endpoint table in USB controller RAM */
-struct stm32_endpoint btable_ep[USB_EP_COUNT] __aligned(8) __usb_btable;
-/* Control endpoint (EP0) buffers */
-static usb_uint ep0_buf_tx[USB_MAX_PACKET_SIZE / 2] __usb_ram;
-static usb_uint ep0_buf_rx[USB_MAX_PACKET_SIZE / 2] __usb_ram;
-
-#define EP0_BUF_TX_SRAM_ADDR ((void *) usb_sram_addr(ep0_buf_tx))
-
-static int set_addr;
-/* remaining size of descriptor data to transfer */
-static int desc_left;
-/* pointer to descriptor data if any */
-static const uint8_t *desc_ptr;
-/* interface that should handle the next tx transaction */
-static uint8_t iface_next = USB_IFACE_COUNT;
-#ifdef CONFIG_USB_REMOTE_WAKEUP
-/* remote wake up feature enabled */
-static int remote_wakeup_enabled;
-#endif
-
-void usb_read_setup_packet(usb_uint *buffer, struct usb_setup_packet *packet)
-{
- packet->bmRequestType = buffer[0] & 0xff;
- packet->bRequest = buffer[0] >> 8;
- packet->wValue = buffer[1];
- packet->wIndex = buffer[2];
- packet->wLength = buffer[3];
-}
-
-struct usb_descriptor_patch {
- const void *address;
- uint16_t data;
-};
-
-static struct usb_descriptor_patch desc_patches[USB_DESC_PATCH_COUNT];
-
-void set_descriptor_patch(enum usb_desc_patch_type type,
- const void *address, uint16_t data)
-{
- desc_patches[type].address = address;
- desc_patches[type].data = data;
-}
-
-void *memcpy_to_usbram_ep0_patch(const void *src, size_t n)
-{
- int i;
- void *ret;
-
- ret = memcpy_to_usbram((void *)usb_sram_addr(ep0_buf_tx), src, n);
-
- for (i = 0; i < USB_DESC_PATCH_COUNT; i++) {
- unsigned int offset = desc_patches[i].address - src;
-
- if (offset >= n)
- continue;
-
- memcpy_to_usbram((void *)(usb_sram_addr(ep0_buf_tx) + offset),
- &desc_patches[i].data, sizeof(desc_patches[i].data));
- }
-
- return ret;
-}
-
-static void ep0_send_descriptor(const uint8_t *desc, int len,
- uint16_t fixup_size)
-{
- /* do not send more than what the host asked for */
- len = MIN(ep0_buf_rx[3], len);
- /*
- * if we cannot transmit everything at once,
- * keep the remainder for the next IN packet
- */
- if (len >= USB_MAX_PACKET_SIZE) {
- desc_left = len - USB_MAX_PACKET_SIZE;
- desc_ptr = desc + USB_MAX_PACKET_SIZE;
- len = USB_MAX_PACKET_SIZE;
- }
- memcpy_to_usbram_ep0_patch(desc, len);
- if (fixup_size) /* set the real descriptor size */
- ep0_buf_tx[1] = fixup_size;
- btable_ep[0].tx_count = len;
- /* send the null OUT transaction if the transfer is complete */
- STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_TX_RX_VALID,
- desc_left ? 0 : EP_STATUS_OUT);
-}
-
-/* Requests on the control endpoint (aka EP0) */
-static void ep0_rx(void)
-{
- uint16_t req = ep0_buf_rx[0]; /* bRequestType | bRequest */
-
- /* reset any incomplete descriptor transfer */
- desc_ptr = NULL;
- iface_next = USB_IFACE_COUNT;
-
- /* interface specific requests */
- if ((req & USB_RECIP_MASK) == USB_RECIP_INTERFACE) {
- uint8_t iface = ep0_buf_rx[2] & 0xff;
- if (iface < USB_IFACE_COUNT) {
- int ret;
-
- ret = usb_iface_request[iface](ep0_buf_rx, ep0_buf_tx);
- if (ret < 0)
- goto unknown_req;
- if (ret == 1)
- iface_next = iface;
- return;
- }
- }
- /* vendor specific request */
- if ((req & USB_TYPE_MASK) == USB_TYPE_VENDOR) {
-#ifdef CONFIG_WEBUSB_URL
- uint8_t b_req = req >> 8; /* bRequest in the transfer */
- uint16_t idx = ep0_buf_rx[2]; /* wIndex in the transfer */
-
- if (b_req == 0x01 && idx == WEBUSB_REQ_GET_URL) {
- int len = *(uint8_t *)webusb_url;
-
- ep0_send_descriptor(webusb_url, len, 0);
- return;
- }
-#endif
- goto unknown_req;
- }
-
- /* TODO check setup bit ? */
- if (req == (USB_DIR_IN | (USB_REQ_GET_DESCRIPTOR << 8))) {
- uint8_t type = ep0_buf_rx[1] >> 8;
- uint8_t idx = ep0_buf_rx[1] & 0xff;
- const uint8_t *desc;
- int len;
-
- switch (type) {
- case USB_DT_DEVICE: /* Setup : Get device descriptor */
- desc = (void *)&dev_desc;
- len = sizeof(dev_desc);
- break;
- case USB_DT_CONFIGURATION: /* Setup : Get configuration desc */
- desc = __usb_desc;
- len = USB_DESC_SIZE;
- break;
-#ifdef CONFIG_USB_BOS
- case USB_DT_BOS: /* Setup : Get BOS descriptor */
- desc = bos_ctx.descp;
- len = bos_ctx.size;
- break;
-#endif
- case USB_DT_STRING: /* Setup : Get string descriptor */
- if (idx >= USB_STR_COUNT)
- /* The string does not exist : STALL */
- goto unknown_req;
-#ifdef CONFIG_USB_SERIALNO
- if (idx == USB_STR_SERIALNO)
- desc = (uint8_t *)usb_serialno_desc;
- else
-#endif
- desc = usb_strings[idx];
- len = desc[0];
- break;
- case USB_DT_DEVICE_QUALIFIER: /* Get device qualifier desc */
- /* Not high speed : STALL next IN used as handshake */
- goto unknown_req;
- default: /* unhandled descriptor */
- goto unknown_req;
- }
- ep0_send_descriptor(desc, len, type == USB_DT_CONFIGURATION ?
- USB_DESC_SIZE : 0);
- } else if (req == (USB_DIR_IN | (USB_REQ_GET_STATUS << 8))) {
- uint16_t data = 0;
- /* Get status */
-#ifdef CONFIG_USB_SELF_POWERED
- data |= USB_REQ_GET_STATUS_SELF_POWERED;
-#endif
-#ifdef CONFIG_USB_REMOTE_WAKEUP
- if (remote_wakeup_enabled)
- data |= USB_REQ_GET_STATUS_REMOTE_WAKEUP;
-#endif
- memcpy_to_usbram(EP0_BUF_TX_SRAM_ADDR, (void *)&data, 2);
- btable_ep[0].tx_count = 2;
- STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_TX_RX_VALID,
- EP_STATUS_OUT /*null OUT transaction */);
- } else if ((req & 0xff) == USB_DIR_OUT) {
- switch (req >> 8) {
- case USB_REQ_SET_FEATURE:
- case USB_REQ_CLEAR_FEATURE:
-#ifdef CONFIG_USB_REMOTE_WAKEUP
- if (ep0_buf_rx[1] ==
- USB_REQ_FEATURE_DEVICE_REMOTE_WAKEUP) {
- remote_wakeup_enabled =
- ((req >> 8) == USB_REQ_SET_FEATURE);
- btable_ep[0].tx_count = 0;
- STM32_TOGGLE_EP(0, EP_TX_RX_MASK,
- EP_TX_RX_VALID, 0);
- break;
- }
-#endif
- goto unknown_req;
- case USB_REQ_SET_ADDRESS:
- /* set the address after we got IN packet handshake */
- set_addr = ep0_buf_rx[1] & 0xff;
- /* need null IN transaction -> TX Valid */
- btable_ep[0].tx_count = 0;
- STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_TX_RX_VALID, 0);
- break;
- case USB_REQ_SET_CONFIGURATION:
- /* uint8_t cfg = ep0_buf_rx[1] & 0xff; */
- /* null IN for handshake */
- btable_ep[0].tx_count = 0;
- STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_TX_RX_VALID, 0);
- break;
- default: /* unhandled request */
- goto unknown_req;
- }
-
- } else {
- goto unknown_req;
- }
-
- return;
-unknown_req:
- STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_RX_VALID | EP_TX_STALL, 0);
-}
-
-static void ep0_tx(void)
-{
- if (set_addr) {
- STM32_USB_DADDR = set_addr | 0x80;
- set_addr = 0;
- CPRINTF("SETAD %02x\n", STM32_USB_DADDR);
- }
- if (desc_ptr) {
- /* we have an on-going descriptor transfer */
- int len = MIN(desc_left, USB_MAX_PACKET_SIZE);
- memcpy_to_usbram(EP0_BUF_TX_SRAM_ADDR, desc_ptr, len);
- btable_ep[0].tx_count = len;
- desc_left -= len;
- desc_ptr += len;
- STM32_TOGGLE_EP(0, EP_TX_MASK, EP_TX_VALID,
- desc_left ? 0 : EP_STATUS_OUT);
- /* send the null OUT transaction if the transfer is complete */
- return;
- }
- if (iface_next < USB_IFACE_COUNT) {
- int ret;
-
- ret = usb_iface_request[iface_next](NULL, ep0_buf_tx);
- if (ret < 0)
- goto error;
- if (ret == 0)
- iface_next = USB_IFACE_COUNT;
- return;
- }
-
-error:
- STM32_TOGGLE_EP(0, EP_TX_MASK, EP_TX_VALID, 0);
-}
-
-static void ep0_event(enum usb_ep_event evt)
-{
- if (evt != USB_EVENT_RESET)
- return;
-
- STM32_USB_EP(0) = BIT(9) /* control EP */ |
- (2 << 4) /* TX NAK */ |
- (3 << 12) /* RX VALID */;
-
- btable_ep[0].tx_addr = usb_sram_addr(ep0_buf_tx);
- btable_ep[0].rx_addr = usb_sram_addr(ep0_buf_rx);
- btable_ep[0].rx_count = 0x8000 | ((USB_MAX_PACKET_SIZE/32-1) << 10);
- btable_ep[0].tx_count = 0;
-}
-USB_DECLARE_EP(0, ep0_tx, ep0_rx, ep0_event);
-
-static void usb_reset(void)
-{
- int ep;
-
- for (ep = 0; ep < USB_EP_COUNT; ep++)
- usb_ep_event[ep](USB_EVENT_RESET);
-
- /*
- * set the default address : 0
- * as we are not configured yet
- */
- STM32_USB_DADDR = 0 | 0x80;
- CPRINTF("RST EP0 %04x\n", STM32_USB_EP(0));
-}
-
-#ifdef CONFIG_USB_SUSPEND
-static void usb_pm_change_notify_hooks(void)
-{
- hook_notify(HOOK_USB_PM_CHANGE);
-}
-DECLARE_DEFERRED(usb_pm_change_notify_hooks);
-
-/* See RM0091 Reference Manual 30.5.5 Suspend/Resume events */
-static void usb_suspend(void)
-{
- CPRINTF("SUS%d\n", remote_wakeup_enabled);
-
- /*
- * usb_suspend can be called from hook task, make sure no interrupt is
- * modifying CNTR at the same time.
- */
- interrupt_disable();
- /* Set FSUSP bit to activate suspend mode */
- STM32_USB_CNTR |= STM32_USB_CNTR_FSUSP;
-
- /* Set USB low power mode */
- STM32_USB_CNTR |= STM32_USB_CNTR_LP_MODE;
- interrupt_enable();
-
- clock_enable_module(MODULE_USB, 0);
-
- /* USB is not in use anymore, we can (hopefully) sleep now. */
- enable_sleep(SLEEP_MASK_USB_DEVICE);
-
- hook_call_deferred(&usb_pm_change_notify_hooks_data, 0);
-}
-
-/*
- * SOF was received (set in interrupt), reset in usb_resume in the
- * unexpected state case.
- */
-static volatile int sof_received;
-
-static void usb_resume_deferred(void)
-{
- uint32_t state = (STM32_USB_FNR & STM32_USB_FNR_RXDP_RXDM_MASK)
- >> STM32_USB_FNR_RXDP_RXDM_SHIFT;
-
- CPRINTF("RSMd %d %04x %d\n", state, STM32_USB_CNTR, sof_received);
- if (sof_received == 0 && (state == 2 || state == 3))
- usb_suspend();
- else
- hook_call_deferred(&usb_pm_change_notify_hooks_data, 0);
-}
-DECLARE_DEFERRED(usb_resume_deferred);
-
-static void usb_resume(void)
-{
- uint32_t state;
-
- clock_enable_module(MODULE_USB, 1);
-
- /* Clear FSUSP bit to exit suspend mode */
- STM32_USB_CNTR &= ~STM32_USB_CNTR_FSUSP;
-
- /* USB is in use again */
- disable_sleep(SLEEP_MASK_USB_DEVICE);
-
- state = (STM32_USB_FNR & STM32_USB_FNR_RXDP_RXDM_MASK)
- >> STM32_USB_FNR_RXDP_RXDM_SHIFT;
-
- CPRINTF("RSM %d %04x\n", state, STM32_USB_CNTR);
-
- /*
- * Reference manual tells we should go back to sleep if state is 10 or
- * 11. However, setting FSUSP and LP_MODE in this interrupt routine
- * seems to lock the USB controller (see b/35775088 and b/71688150).
- * Instead, we do it in a deferred routine. The host must assert the
- * reset condition for 20ms, so reading D+/D- after ~3ms should be safe
- * (there is no chance we end up sampling during a bus transaction).
- */
- if (state == 2 || state == 3) {
- /*
- * This function is already called from interrupt context so
- * there is no risk of race here.
- */
- sof_received = 0;
- STM32_USB_CNTR |= STM32_USB_CNTR_SOFM;
- hook_call_deferred(&usb_resume_deferred_data, 3 * MSEC);
- } else {
- hook_call_deferred(&usb_pm_change_notify_hooks_data, 0);
- }
-}
-
-#ifdef CONFIG_USB_REMOTE_WAKEUP
-/*
- * Makes sure usb_wake is only run once. When 0, wake is in progress.
- */
-static volatile int usb_wake_done = 1;
-
-/*
- * ESOF counter (incremented in interrupt), RESUME bit is cleared when
- * this reaches 0. Also used to detect resume timeout.
- */
-static volatile int esof_count;
-
-__attribute__((weak))
-void board_usb_wake(void)
-{
- /* Side-band USB wake, do nothing by default. */
-}
-
-/* Called 10ms after usb_wake started. */
-static void usb_wake_deferred(void)
-{
- if (esof_count == 3) {
- /*
- * If we reach here, it means that we are not counting ESOF/SOF
- * properly (either of these interrupts should occur every 1ms).
- * This should never happen if we implemented the resume logic
- * correctly.
- *
- * We reset the controller in that case, which recovers the
- * interface.
- */
- CPRINTF("USB stuck\n");
-#if defined(STM32_RCC_APB1RSTR2_USBFSRST)
- STM32_RCC_APB1RSTR2 |= STM32_RCC_APB1RSTR2_USBFSRST;
- STM32_RCC_APB1RSTR2 &= STM32_RCC_APB1RSTR2_USBFSRST;
-#else
- STM32_RCC_APB1RSTR |= STM32_RCC_PB1_USB;
- STM32_RCC_APB1RSTR &= ~STM32_RCC_PB1_USB;
-#endif
- usb_init();
- }
-}
-DECLARE_DEFERRED(usb_wake_deferred);
-
-void usb_wake(void)
-{
- if (!remote_wakeup_enabled ||
- !(STM32_USB_CNTR & STM32_USB_CNTR_FSUSP)) {
- /*
- * USB wake not enabled, or already woken up, or already waking
- * up, nothing to do.
- */
- return;
- }
-
- /* Only allow one caller at a time. */
- if (!atomic_clear((int *)&usb_wake_done))
- return;
-
- CPRINTF("WAKE\n");
-
- /*
- * Sometimes the USB controller gets stuck, and does not count SOF/ESOF
- * frames anymore, detect that.
- */
- hook_call_deferred(&usb_wake_deferred_data, 10 * MSEC);
-
- /*
- * Set RESUME bit for 1 to 15 ms, then clear it. We ask the interrupt
- * routine to count 3 ESOF interrupts, which should take between
- * 2 and 3 ms.
- */
- esof_count = 3;
-
- /* STM32_USB_CNTR can also be updated from interrupt context. */
- interrupt_disable();
- STM32_USB_CNTR |= STM32_USB_CNTR_RESUME |
- STM32_USB_CNTR_ESOFM | STM32_USB_CNTR_SOFM;
- interrupt_enable();
-
- /* Try side-band wake as well. */
- board_usb_wake();
-}
-#endif
-
-int usb_is_suspended(void)
-{
- /* Either hardware block is suspended... */
- if (STM32_USB_CNTR & STM32_USB_CNTR_FSUSP)
- return 1;
-
-#ifdef CONFIG_USB_REMOTE_WAKEUP
- /* ... or we are currently waking up. */
- if (!usb_wake_done)
- return 1;
-#endif
-
- return 0;
-}
-
-int usb_is_remote_wakeup_enabled(void)
-{
-#ifdef CONFIG_USB_REMOTE_WAKEUP
- return remote_wakeup_enabled;
-#else
- return 0;
-#endif
-}
-#endif /* CONFIG_USB_SUSPEND */
-
-#if defined(CONFIG_USB_SUSPEND) && defined(CONFIG_USB_REMOTE_WAKEUP)
-/*
- * Called by usb_interrupt when usb_wake is asking us to count esof_count ESOF
- * interrupts (one per millisecond), then disable RESUME, then wait for resume
- * to complete.
- */
-static void usb_interrupt_handle_wake(uint16_t status)
-{
- int state;
- int good;
-
- esof_count--;
-
- /* Keep counting. */
- if (esof_count > 0)
- return;
-
- /* Clear RESUME bit. */
- if (esof_count == 0)
- STM32_USB_CNTR &= ~STM32_USB_CNTR_RESUME;
-
- /* Then count down until state is resumed. */
- state = (STM32_USB_FNR & STM32_USB_FNR_RXDP_RXDM_MASK)
- >> STM32_USB_FNR_RXDP_RXDM_SHIFT;
-
- /*
- * state 2, or receiving an SOF, means resume
- * completed successfully.
- */
- good = (status & STM32_USB_ISTR_SOF) || (state == 2);
-
- /* Either: state is ready, or we timed out. */
- if (good || state == 3 || esof_count <= -USB_RESUME_TIMEOUT_MS) {
- int ep;
-
- STM32_USB_CNTR &= ~STM32_USB_CNTR_ESOFM;
- usb_wake_done = 1;
- if (!good) {
- CPRINTF("wake error: cnt=%d state=%d\n",
- esof_count, state);
- usb_suspend();
- return;
- }
-
- CPRINTF("RSMOK%d %d\n", -esof_count, state);
-
- for (ep = 1; ep < USB_EP_COUNT; ep++)
- usb_ep_event[ep](USB_EVENT_DEVICE_RESUME);
- }
-}
-#endif /* CONFIG_USB_SUSPEND && CONFIG_USB_REMOTE_WAKEUP */
-
-void usb_interrupt(void)
-{
- uint16_t status = STM32_USB_ISTR;
-
- if (status & STM32_USB_ISTR_RESET)
- usb_reset();
-
-#ifdef CONFIG_USB_SUSPEND
- if (status & STM32_USB_ISTR_SOF) {
- sof_received = 1;
- /*
- * The wake handler also only cares about the _first_ SOF that
- * is received, so we can disable that interrupt.
- */
- STM32_USB_CNTR &= ~STM32_USB_CNTR_SOFM;
- }
-
-#ifdef CONFIG_USB_REMOTE_WAKEUP
- if (status & (STM32_USB_ISTR_ESOF | STM32_USB_ISTR_SOF) &&
- !usb_wake_done)
- usb_interrupt_handle_wake(status);
-#endif
-
- if (status & STM32_USB_ISTR_SUSP)
- usb_suspend();
-
- if (status & STM32_USB_ISTR_WKUP)
- usb_resume();
-#endif
-
- if (status & STM32_USB_ISTR_CTR) {
- int ep = status & STM32_USB_ISTR_EP_ID_MASK;
- if (ep < USB_EP_COUNT) {
- if (status & STM32_USB_ISTR_DIR)
- usb_ep_rx[ep]();
- else
- usb_ep_tx[ep]();
- }
- /* TODO: do it in a USB task */
- /* task_set_event(, 1 << ep_task); */
- }
-
- /* ack only interrupts that we handled */
- STM32_USB_ISTR = ~status;
-}
-DECLARE_IRQ(STM32_IRQ_USB_LP, usb_interrupt, 1);
-
-void usb_init(void)
-{
- /* Enable USB device clock, possibly increasing system clock to 48MHz */
- clock_enable_module(MODULE_USB, 1);
-
- /* configure the pinmux */
- gpio_config_module(MODULE_USB, 1);
-
- /* power on sequence */
-
- /* keep FRES (USB reset) and remove PDWN (power down) */
- STM32_USB_CNTR = STM32_USB_CNTR_FRES;
- udelay(1); /* startup time */
- /* reset FRES and keep interrupts masked */
- STM32_USB_CNTR = 0x00;
- /* clear pending interrupts */
- STM32_USB_ISTR = 0;
-
- /* set descriptors table offset in dedicated SRAM */
- STM32_USB_BTABLE = 0;
-
- /* EXTI18 is USB wake up interrupt */
- /* STM32_EXTI_RTSR |= BIT(18); */
- /* STM32_EXTI_IMR |= BIT(18); */
-
- /* Enable interrupt handlers */
- task_enable_irq(STM32_IRQ_USB_LP);
- /* set interrupts mask : reset/correct transfer/errors */
- STM32_USB_CNTR = STM32_USB_CNTR_CTRM |
- STM32_USB_CNTR_PMAOVRM |
- STM32_USB_CNTR_ERRM |
-#ifdef CONFIG_USB_SUSPEND
- STM32_USB_CNTR_WKUPM |
- STM32_USB_CNTR_SUSPM |
-#endif
- STM32_USB_CNTR_RESETM;
-
-#ifdef CONFIG_USB_SERIALNO
- usb_load_serial();
-#endif
-#ifndef CONFIG_USB_INHIBIT_CONNECT
- usb_connect();
-#endif
-
- CPRINTF("USB init done\n");
-}
-
-#ifndef CONFIG_USB_INHIBIT_INIT
-DECLARE_HOOK(HOOK_INIT, usb_init, HOOK_PRIO_DEFAULT);
-#endif
-
-void usb_release(void)
-{
- /* signal disconnect to host */
- usb_disconnect();
-
- /* power down USB */
- STM32_USB_CNTR = 0;
-
- /* disable interrupt handlers */
- task_disable_irq(STM32_IRQ_USB_LP);
-
- /* unset pinmux */
- gpio_config_module(MODULE_USB, 0);
-
- /* disable USB device clock, possibly slowing down system clock */
- clock_enable_module(MODULE_USB, 0);
-}
-/* ensure the host disconnects and reconnects over a sysjump */
-DECLARE_HOOK(HOOK_SYSJUMP, usb_release, HOOK_PRIO_DEFAULT);
-
-int usb_is_enabled(void)
-{
- return clock_is_module_enabled(MODULE_USB);
-}
-
-void *memcpy_to_usbram(void *dest, const void *src, size_t n)
-{
- int unaligned = (((uintptr_t) dest) & 1);
- usb_uint *d = &__usb_ram_start[((uintptr_t) dest) / 2];
- uint8_t *s = (uint8_t *) src;
- int i;
-
- /*
- * Handle unaligned leading byte via read/modify/write.
- */
- if (unaligned && n) {
- *d = (*d & ~0xff00) | (*s << 8);
- n--;
- s++;
- d++;
- }
-
- for (i = 0; i < n / 2; i++, s += 2)
- *d++ = (s[1] << 8) | s[0];
-
- /*
- * There is a trailing byte to write into a final USB packet memory
- * location, use a read/modify/write to be safe.
- */
- if (n & 1)
- *d = (*d & ~0x00ff) | *s;
-
- return dest;
-}
-
-void *memcpy_from_usbram(void *dest, const void *src, size_t n)
-{
- int unaligned = (((uintptr_t) src) & 1);
- usb_uint const *s = &__usb_ram_start[((uintptr_t) src) / 2];
- uint8_t *d = (uint8_t *) dest;
- int i;
-
- if (unaligned && n) {
- *d = *s >> 8;
- n--;
- s++;
- d++;
- }
-
- for (i = 0; i < n / 2; i++) {
- usb_uint value = *s++;
-
- *d++ = (value >> 0) & 0xff;
- *d++ = (value >> 8) & 0xff;
- }
-
- if (n & 1)
- *d = *s;
-
- return dest;
-}
-
-#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 */
-
-#ifdef CONFIG_MAC_ADDR
-
-/* Save MAC address into pstate region. */
-static int usb_save_mac_addr(const char *mac_addr)
-{
- int rv;
-
- if (!mac_addr) {
- return EC_ERROR_INVAL;
- }
-
- /* Save this new MAC address to flash. */
- rv = board_write_mac_addr(mac_addr);
- if (rv) {
- return rv;
- }
-
- /* Load this new MAC address to memory. */
- if (board_read_mac_addr() != NULL) {
- return EC_SUCCESS;
- } else {
- return EC_ERROR_UNKNOWN;
- }
-}
-
-static int command_macaddr(int argc, char **argv)
-{
- const char* buf;
- int rv = EC_SUCCESS;
-
- if (argc != 1) {
- if ((strcasecmp(argv[1], "set") == 0) &&
- (argc == 3)) {
- ccprintf("Saving MAC address\n");
- rv = usb_save_mac_addr(argv[2]);
- } else if ((strcasecmp(argv[1], "load") == 0) &&
- (argc == 2)) {
- ccprintf("Loading MAC address\n");
- } else {
- return EC_ERROR_INVAL;
- }
- }
-
- buf = board_read_mac_addr();
- if (buf == NULL) {
- buf = DEFAULT_MAC_ADDR;
- }
- ccprintf("MAC address: %s\n", buf);
- return rv;
-}
-
-DECLARE_CONSOLE_COMMAND(macaddr, command_macaddr,
- "load/set [value]",
- "Read and write MAC address");
-
-#endif /* CONFIG_MAC_ADDR */