cr50: add USB support

Add a USB device driver for the Synopsys DWC USB device controller.

The common USB protocol stack code still need to be de-duplicated with
the STM32 implementation.

Signed-off-by: Vincent Palatin <vpalatin@chromium.org>

BRANCH=none
BUG=chrome-os-partner:33919
TEST=plug Cr50 to a Linux workstation and see USB descriptors using
"lsusb -v -d 18d1:5014"

Change-Id: I4a367241053de2c2d94aa06f82ea4bee51f9f89a
Reviewed-on: https://chromium-review.googlesource.com/231160
Commit-Queue: Vincent Palatin <vpalatin@chromium.org>
Trybot-Ready: Vincent Palatin <vpalatin@chromium.org>
Tested-by: Vincent Palatin <vpalatin@chromium.org>
Reviewed-by: Bill Richardson <wfrichar@chromium.org>
This commit is contained in:
Vincent Palatin
2014-11-19 14:37:10 -08:00
committed by ChromeOS Commit Bot
parent de24d51162
commit 4d0aad8894
9 changed files with 1223 additions and 0 deletions

View File

@@ -5,10 +5,13 @@
#include "common.h"
#include "console.h"
#include "ec_version.h"
#include "gpio.h"
#include "hooks.h"
#include "registers.h"
#include "task.h"
#include "usb.h"
#include "usb_hid.h"
#include "util.h"
/*
@@ -21,6 +24,26 @@
#include "gpio_list.h"
static void send_hid_event(void)
{
uint64_t rpt = 0;
uint8_t *key_ptr = (void *)&rpt + 2;
/* Convert SW_N/SW_S/SW_W/SW_E to A,B,C,D keys */
if (gpio_get_level(GPIO_SW_N))
*key_ptr++ = 0x04; /* A keycode */
if (gpio_get_level(GPIO_SW_S))
*key_ptr++ = 0x05; /* B keycode */
if (gpio_get_level(GPIO_SW_W))
*key_ptr++ = 0x06; /* C keycode */
if (gpio_get_level(GPIO_SW_E))
*key_ptr++ = 0x07; /* D keycode */
/* send the keyboard state over USB HID */
set_keyboard_report(rpt);
/* check release in the future */
hook_call_deferred(send_hid_event, 40);
}
DECLARE_DEFERRED(send_hid_event);
/* Interrupt handler for button pushes */
void button_event(enum gpio_signal signal)
{
@@ -32,6 +55,7 @@ void button_event(enum gpio_signal signal)
signal -= (GPIO_SW_N_ - GPIO_SW_N);
v = gpio_get_level(signal);
send_hid_event();
ccprintf("Button %d = %d\n", signal, v);
gpio_set_level(signal - GPIO_SW_N + GPIO_LED_4, v);
}
@@ -49,3 +73,12 @@ static void board_init(void)
gpio_enable_interrupt(GPIO_SW_E_);
}
DECLARE_HOOK(HOOK_INIT, board_init, HOOK_PRIO_DEFAULT);
const void * const usb_strings[] = {
[USB_STR_DESC] = usb_string_desc,
[USB_STR_VENDOR] = USB_STRING_DESC("Google Inc."),
[USB_STR_PRODUCT] = USB_STRING_DESC("Cr50"),
[USB_STR_VERSION] = USB_STRING_DESC(CROS_EC_VERSION32),
[USB_STR_CONSOLE_NAME] = USB_STRING_DESC("Shell"),
};
BUILD_ASSERT(ARRAY_SIZE(usb_strings) == USB_STR_COUNT);

View File

@@ -15,6 +15,13 @@
#undef CONFIG_HIBERNATE
#undef CONFIG_LID_SWITCH
/* USB configuration */
#define CONFIG_USB
#define CONFIG_USB_CONSOLE
#define CONFIG_USB_HID
#define CONFIG_USB_PID 0x5014
/*
* Allow dangerous commands all the time, since we don't have a write protect
* switch.
@@ -33,6 +40,28 @@
/* user button interrupt handler */
void button_event(enum gpio_signal signal);
/* USB string indexes */
enum usb_strings {
USB_STR_DESC = 0,
USB_STR_VENDOR,
USB_STR_PRODUCT,
USB_STR_VERSION,
USB_STR_CONSOLE_NAME,
USB_STR_COUNT
};
#endif /* !__ASSEMBLER__ */
/* USB interface indexes (use define rather than enum to expand them) */
#define USB_IFACE_CONSOLE 0
#define USB_IFACE_HID 1
#define USB_IFACE_COUNT 2
/* USB endpoint indexes (use define rather than enum to expand them) */
#define USB_EP_CONTROL 0
#define USB_EP_CONSOLE 1
#define USB_EP_HID 2
#define USB_EP_COUNT 3
#endif /* __BOARD_H */

View File

@@ -19,3 +19,7 @@ CPPFLAGS+= -DGC_REVISION="$(ver_str)"
chip-y=clock.o gpio.o hwtimer.o jtag.o system.o uart.o
chip-y+= pmu.o
chip-$(CONFIG_WATCHDOG)+=watchdog.o
chip-$(CONFIG_USB)+=usb.o usb_endpoints.o
chip-$(CONFIG_USB_CONSOLE)+=usb_console.o
chip-$(CONFIG_USB_HID)+=usb_hid.o

View File

@@ -52,4 +52,11 @@
/* Maximum number of deferrable functions */
#define DEFERRABLE_MAX_COUNT 8
/* USB : TODO FIXME */
#define CONFIG_USB_RAM_ACCESS_TYPE uint16_t
/* No dedicated USB RAM */
#define CONFIG_USB_RAM_BASE 0xdead0000
#define CONFIG_USB_RAM_ACCESS_SIZE 0
#define CONFIG_USB_RAM_SIZE 0
#endif /* __CROS_EC_CONFIG_CHIP_H */

View File

@@ -359,4 +359,150 @@ static inline int x_timehs_addr(unsigned int module, unsigned int timer,
#define GR_XO_OSC_SETHOLD REG32(GC_XO0_BASE_ADDR + GC_XO_OSC_SETHOLD_OFFSET)
#define GR_XO_OSC_CLRHOLD REG32(GC_XO0_BASE_ADDR + GC_XO_OSC_CLRHOLD_OFFSET)
/* USB device controller */
#define GR_USB_REG(off) REG32(GC_USB0_BASE_ADDR + (off))
#define GR_USB_GAHBCFG GR_USB_REG(GC_USB_GAHBCFG_OFFSET)
#define GR_USB_GUSBCFG GR_USB_REG(GC_USB_GUSBCFG_OFFSET)
#define GR_USB_GRSTCTL GR_USB_REG(GC_USB_GRSTCTL_OFFSET)
#define GR_USB_GINTSTS GR_USB_REG(GC_USB_GINTSTS_OFFSET)
#define GR_USB_GINTMSK GR_USB_REG(GC_USB_GINTMSK_OFFSET)
#define GR_USB_GRXSTSR GR_USB_REG(GC_USB_GRXSTSR_OFFSET)
#define GR_USB_GRXSTSP GR_USB_REG(GC_USB_GRXSTSP_OFFSET)
#define GR_USB_GRXFSIZ GR_USB_REG(GC_USB_GRXFSIZ_OFFSET)
#define GR_USB_GNPTXFSIZ GR_USB_REG(GC_USB_GNPTXFSIZ_OFFSET)
#define GR_USB_GSNPSID GR_USB_REG(GC_USB_GSNPSID_OFFSET)
#define GR_USB_GHWCFG1 GR_USB_REG(GC_USB_GHWCFG1_OFFSET)
#define GR_USB_GHWCFG2 GR_USB_REG(GC_USB_GHWCFG2_OFFSET)
#define GR_USB_GHWCFG3 GR_USB_REG(GC_USB_GHWCFG3_OFFSET)
#define GR_USB_GHWCFG4 GR_USB_REG(GC_USB_GHWCFG4_OFFSET)
#define GR_USB_GDFIFOCFG GR_USB_REG(GC_USB_GDFIFOCFG_OFFSET)
#define GR_USB_DIEPTXF(n) GR_USB_REG(GC_USB_DIEPTXF1_OFFSET - 4 + (n)*4)
#define GR_USB_DCFG GR_USB_REG(GC_USB_DCFG_OFFSET)
#define GR_USB_DCTL GR_USB_REG(GC_USB_DCTL_OFFSET)
#define GR_USB_DSTS GR_USB_REG(GC_USB_DSTS_OFFSET)
#define GR_USB_DIEPMSK GR_USB_REG(GC_USB_DIEPMSK_OFFSET)
#define GR_USB_DOEPMSK GR_USB_REG(GC_USB_DOEPMSK_OFFSET)
#define GR_USB_DAINT GR_USB_REG(GC_USB_DAINT_OFFSET)
#define GR_USB_DAINTMSK GR_USB_REG(GC_USB_DAINTMSK_OFFSET)
#define GR_USB_DTHRCTL GR_USB_REG(GC_USB_DTHRCTL_OFFSET)
#define GR_USB_DIEPEMPMSK GR_USB_REG(GC_USB_DIEPEMPMSK_OFFSET)
#define GR_USB_EPIREG(off, n) GR_USB_REG(0x900 + (n) * 0x20 + (off))
#define GR_USB_EPOREG(off, n) GR_USB_REG(0xb00 + (n) * 0x20 + (off))
#define GR_USB_DIEPCTL(n) GR_USB_EPIREG(0x00, n)
#define GR_USB_DIEPINT(n) GR_USB_EPIREG(0x08, n)
#define GR_USB_DIEPTSIZ(n) GR_USB_EPIREG(0x10, n)
#define GR_USB_DIEPDMA(n) GR_USB_EPIREG(0x14, n)
#define GR_USB_DTXFSTS(n) GR_USB_EPIREG(0x18, n)
#define GR_USB_DIEPDMAB(n) GR_USB_EPIREG(0x1c, n)
#define GR_USB_DOEPCTL(n) GR_USB_EPOREG(0x00, n)
#define GR_USB_DOEPINT(n) GR_USB_EPOREG(0x08, n)
#define GR_USB_DOEPTSIZ(n) GR_USB_EPOREG(0x10, n)
#define GR_USB_DOEPDMA(n) GR_USB_EPOREG(0x14, n)
#define GR_USB_DOEPDMAB(n) GR_USB_EPOREG(0x1c, n)
#define GAHBCFG_DMA_EN (1 << GC_USB_GAHBCFG_DMAEN_LSB)
#define GAHBCFG_GLB_INTR_EN (1 << GC_USB_GAHBCFG_GLBLINTRMSK_LSB)
#define GAHBCFG_HBSTLEN_INCR4 (3 << GC_USB_GAHBCFG_HBSTLEN_LSB)
#define GAHBCFG_NP_TXF_EMP_LVL (1 << GC_USB_GAHBCFG_NPTXFEMPLVL_LSB)
#define GUSBCFG_TOUTCAL(n) (((n) << GC_USB_GUSBCFG_TOUTCAL_LSB) & GC_USB_GUSBCFG_TOUTCAL_MASK)
#define GUSBCFG_PHYSEL_HS (0 << GC_USB_GUSBCFG_PHYSEL_LSB)
#define GUSBCFG_PHYSEL_FS (1 << GC_USB_GUSBCFG_PHYSEL_LSB)
#define GUSBCFG_FSINTF_6PIN (0 << GC_USB_GUSBCFG_FSINTF_LSB)
#define GUSBCFG_FSINTF_3PIN (1 << GC_USB_GUSBCFG_FSINTF_LSB)
#define GUSBCFG_PHYIF16 (1 << GC_USB_GUSBCFG_PHYIF_LSB)
#define GUSBCFG_PHYIF8 (0 << GC_USB_GUSBCFG_PHYIF_LSB)
#define GUSBCFG_ULPI (1 << GC_USB_GUSBCFG_ULPI_UTMI_SEL_LSB)
#define GUSBCFG_UTMI (0 << GC_USB_GUSBCFG_ULPI_UTMI_SEL_LSB)
#define GRSTCTL_CSFTRST (1 << GC_USB_GRSTCTL_CSFTRST_LSB)
#define GRSTCTL_AHBIDLE (1 << GC_USB_GRSTCTL_AHBIDLE_LSB)
#define GRSTCTL_TXFFLSH (1 << GC_USB_GRSTCTL_TXFFLSH_LSB)
#define GRSTCTL_RXFFLSH (1 << GC_USB_GRSTCTL_RXFFLSH_LSB)
#define GRSTCTL_TXFNUM(n) (((n) << GC_USB_GRSTCTL_TXFNUM_LSB) & GC_USB_GRSTCTL_TXFNUM_MASK)
#define GINTSTS_RXFLVL (1 << GC_USB_GINTSTS_RXFLVL_LSB)
#define GINTSTS_SOF (1 << GC_USB_GINTSTS_SOF_LSB)
#define GINTSTS_GOUTNAKEFF (1 << GC_USB_GINTMSK_GOUTNAKEFFMSK_LSB)
#define GINTSTS_GINNAKEFF (1 << GC_USB_GINTMSK_GINNAKEFFMSK_LSB)
#define GINTSTS_USBRST (1 << GC_USB_GINTMSK_USBRSTMSK_LSB)
#define GINTSTS_ENUMDONE (1 << GC_USB_GINTMSK_ENUMDONEMSK_LSB)
#define GINTSTS_IEPINT (1 << GC_USB_GINTSTS_IEPINT_LSB)
#define GINTSTS_OEPINT (1 << GC_USB_GINTSTS_OEPINT_LSB)
#define DCFG_DEVSPD_FS (1 << GC_USB_DCFG_DEVSPD_LSB)
#define DCFG_DEVSPD_FS48 (3 << GC_USB_DCFG_DEVSPD_LSB)
#define DCFG_DEVADDR(a) (((a) << GC_USB_DCFG_DEVADDR_LSB) & GC_USB_DCFG_DEVADDR_MASK)
#define DCFG_DESCDMA (1 << GC_USB_DCFG_DESCDMA_LSB)
#define DCTL_SFTDISCON (1 << GC_USB_DCTL_SFTDISCON_LSB)
#define DCTL_CGOUTNAK (1 << GC_USB_DCTL_CGOUTNAK_LSB)
#define DCTL_CGNPINNAK (1 << GC_USB_DCTL_CGNPINNAK_LSB)
#define DCTL_PWRONPRGDONE (1 << GC_USB_DCTL_PWRONPRGDONE_LSB)
#define DIEPMSK_TIMEOUTMSK (1 << GC_USB_DIEPMSK_TIMEOUTMSK_LSB)
#define DIEPMSK_AHBERRMSK (1 << GC_USB_DIEPMSK_AHBERRMSK_LSB)
#define DIEPMSK_EPDISBLDMSK (1 << GC_USB_DIEPMSK_EPDISBLDMSK_LSB)
#define DIEPMSK_XFERCOMPLMSK (1 << GC_USB_DIEPMSK_XFERCOMPLMSK_LSB)
#define DIEPMSK_INTKNTXFEMPMSK (1 << GC_USB_DIEPMSK_INTKNTXFEMPMSK_LSB)
#define DIEPMSK_INTKNEPMISMSK (1 << GC_USB_DIEPMSK_INTKNEPMISMSK_LSB)
#define DOEPMSK_SETUPMSK (1 << GC_USB_DOEPMSK_SETUPMSK_LSB)
#define DOEPMSK_AHBERRMSK (1 << GC_USB_DOEPMSK_AHBERRMSK_LSB)
#define DOEPMSK_EPDISBLDMSK (1 << GC_USB_DOEPMSK_EPDISBLDMSK_LSB)
#define DOEPMSK_XFERCOMPLMSK (1 << GC_USB_DOEPMSK_XFERCOMPLMSK_LSB)
#define DXEPCTL_EPTYPE_CTRL (0 << GC_USB_DIEPCTL0_EPTYPE_LSB)
#define DXEPCTL_EPTYPE_ISO (1 << GC_USB_DIEPCTL0_EPTYPE_LSB)
#define DXEPCTL_EPTYPE_BULK (2 << GC_USB_DIEPCTL0_EPTYPE_LSB)
#define DXEPCTL_EPTYPE_INT (3 << GC_USB_DIEPCTL0_EPTYPE_LSB)
#define DXEPCTL_EPTYPE_MASK GC_USB_DIEPCTL0_EPTYPE_MASK
#define DXEPCTL_TXFNUM(n) ((n) << GC_USB_DIEPCTL1_TXFNUM_LSB)
#define DXEPCTL_STALL (1 << GC_USB_DIEPCTL0_STALL_LSB)
#define DXEPCTL_CNAK (1 << GC_USB_DIEPCTL0_CNAK_LSB)
#define DXEPCTL_DPID (1 << GC_USB_DIEPCTL0_DPID_LSB)
#define DXEPCTL_SNAK (1 << GC_USB_DIEPCTL0_SNAK_LSB)
#define DXEPCTL_NAKSTS (1 << GC_USB_DIEPCTL0_NAKSTS_LSB)
#define DXEPCTL_EPENA (1 << GC_USB_DIEPCTL0_EPENA_LSB)
#define DXEPCTL_EPDIS (1 << GC_USB_DIEPCTL0_EPDIS_LSB)
#define DXEPCTL_USBACTEP (1 << GC_USB_DIEPCTL0_USBACTEP_LSB)
#define DXEPCTL_MPS64 (0 << GC_USB_DIEPCTL0_MPS_LSB)
#define DXEPCTL_MPS(cnt) ((cnt) << GC_USB_DIEPCTL1_MPS_LSB)
#define DXEPTSIZ_SUPCNT(n) ((n) << GC_USB_DOEPTSIZ0_SUPCNT_LSB)
#define DXEPTSIZ_PKTCNT(n) ((n) << GC_USB_DIEPTSIZ0_PKTCNT_LSB)
#define DXEPTSIZ_XFERSIZE(n) ((n) << GC_USB_DIEPTSIZ0_XFERSIZE_LSB)
#define DOEPDMA_BS_HOST_RDY (0 << 30)
#define DOEPDMA_BS_DMA_BSY (1 << 30)
#define DOEPDMA_BS_DMA_DONE (2 << 30)
#define DOEPDMA_BS_HOST_BSY (3 << 30)
#define DOEPDMA_BS_MASK (3 << 30)
#define DOEPDMA_RXSTS_MASK (3 << 28)
#define DOEPDMA_LAST (1 << 27)
#define DOEPDMA_SP (1 << 26)
#define DOEPDMA_IOC (1 << 25)
#define DOEPDMA_SR (1 << 24)
#define DOEPDMA_MTRF (1 << 23)
#define DOEPDMA_NAK (1 << 16)
#define DOEPDMA_RXBYTES(n) (((n) & 0xFFFF) << 0)
#define DOEPDMA_RXBYTES_MASK (0xFFFF << 0)
#define DIEPDMA_BS_HOST_RDY (0 << 30)
#define DIEPDMA_BS_DMA_BSY (1 << 30)
#define DIEPDMA_BS_DMA_DONE (2 << 30)
#define DIEPDMA_BS_HOST_BSY (3 << 30)
#define DIEPDMA_BS_MASK (3 << 30)
#define DIEPDMA_TXSTS_MASK (3 << 28)
#define DIEPDMA_LAST (1 << 27)
#define DIEPDMA_SP (1 << 26)
#define DIEPDMA_IOC (1 << 25)
#define DIEPDMA_TXBYTES(n) (((n) & 0xFFFF) << 0)
#define DIEPDMA_TXBYTES_MASK (0xFFFF << 0)
struct g_usb_desc {
uint32_t flags;
void *addr;
};
#endif /* __CROS_EC_REGISTERS_H */

461
chip/g/usb.c Normal file
View File

@@ -0,0 +1,461 @@
/* Copyright (c) 2014 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 "gpio.h"
#include "hooks.h"
#include "link_defs.h"
#include "registers.h"
#include "task.h"
#include "timer.h"
#include "util.h"
#include "usb.h"
/* Rev A1 has a RTL bug in the FIFO */
#if CONCAT2(GC_, GC___MAJOR_REV__) == GC___REVA__
/*
* WORKAROUND: only the first 256 entries are usable as TX FIFO
*
* Use the last 128 entries for EP_INFO (not affected by the bug)
* and 256 entries for RX/TX FIFOs : total 384 entries.
*
* RX FIFO needs more than 64 entries (for reserved space)
* set RX FIFO to 80 entries
* set TX0-TX10 FIFO to 64 bytes = 16 (x 32-bit) entries
* let TX11-TX15 uninitialized for now (WORKAROUND).
*/
#define FIFO_SIZE 0x180
#define TX_FIFO_CNT 11
#else
#define FIFO_SIZE 0x400
#define TX_FIFO_CNT 16
#endif
/* Console output macro */
#define CPRINTF(format, args...) cprintf(CC_USB, format, ## args)
#ifdef CONFIG_USB_BOS
/* v2.01 (vs 2.00) BOS Descriptor provided */
#define USB_DEV_BCDUSB 0x0201
#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
/* 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 = 0,
.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, /* bus powered */
.bMaxPower = 250, /* MaxPower 500 mA */
};
const uint8_t usb_string_desc[] = {
4, /* Descriptor size */
USB_DT_STRING,
0x09, 0x04 /* LangID = 0x0409: U.S. English */
};
/* Descriptors for USB controller S/G DMA */
struct g_usb_desc ep0_out_desc;
struct g_usb_desc ep0_in_desc;
/* 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*/;
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;
/* Requests on the control endpoint (aka EP0) */
static void ep0_rx(void)
{
uint32_t epint = GR_USB_DOEPINT(0);
uint16_t req = ep0_buf_rx[0]; /* bRequestType | bRequest */
GR_USB_DOEPINT(0) = epint; /* clear IT */
/* reset any incomplete descriptor transfer */
desc_ptr = NULL;
/* interface specific requests */
if ((req & USB_RECIP_MASK) == USB_RECIP_INTERFACE) {
uint8_t iface = ep0_buf_rx[2] & 0xff;
if (iface < USB_IFACE_COUNT &&
usb_iface_request[iface](ep0_buf_rx, ep0_buf_tx))
goto unknown_req;
return;
}
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;
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;
}
/* 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_buf_tx, desc, len);
if (type == USB_DT_CONFIGURATION)
/* set the real descriptor size */
ep0_buf_tx[1] = USB_DESC_SIZE;
ep0_in_desc.flags = DIEPDMA_LAST | DIEPDMA_BS_HOST_RDY |
DIEPDMA_IOC | DIEPDMA_TXBYTES(len);
GR_USB_DIEPCTL(0) |= DXEPCTL_CNAK | DXEPCTL_EPENA;
ep0_out_desc.flags = DOEPDMA_RXBYTES(64) | DOEPDMA_LAST
| DOEPDMA_BS_HOST_RDY | DOEPDMA_IOC;
GR_USB_DOEPCTL(0) |= DXEPCTL_CNAK | DXEPCTL_EPENA;
/* send the null OUT transaction if the transfer is complete */
} else if (req == (USB_DIR_IN | (USB_REQ_GET_STATUS << 8))) {
uint16_t zero = 0;
/* Get status */
memcpy_to_usbram(ep0_buf_tx, (void *)&zero, 2);
ep0_in_desc.flags = DIEPDMA_LAST | DIEPDMA_BS_HOST_RDY | DIEPDMA_IOC |
DIEPDMA_TXBYTES(2);
GR_USB_DIEPCTL(0) |= DXEPCTL_CNAK | DXEPCTL_EPENA;
ep0_out_desc.flags = DOEPDMA_RXBYTES(64) | DOEPDMA_LAST
| DOEPDMA_BS_HOST_RDY | DOEPDMA_IOC;
GR_USB_DOEPCTL(0) |= DXEPCTL_CNAK | DXEPCTL_EPENA;
} else if ((req & 0xff) == USB_DIR_OUT) {
switch (req >> 8) {
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 */
ep0_in_desc.flags = DIEPDMA_LAST | DIEPDMA_BS_HOST_RDY | DIEPDMA_IOC |
DIEPDMA_TXBYTES(0) | DIEPDMA_SP;
GR_USB_DIEPCTL(0) |= DXEPCTL_CNAK | DXEPCTL_EPENA;
ep0_out_desc.flags = DOEPDMA_RXBYTES(64) | DOEPDMA_LAST
| DOEPDMA_BS_HOST_RDY | DOEPDMA_IOC;
GR_USB_DOEPCTL(0) |= DXEPCTL_CNAK | DXEPCTL_EPENA;
break;
case USB_REQ_SET_CONFIGURATION:
/* uint8_t cfg = ep0_buf_rx[1] & 0xff; */
/* null IN for handshake */
ep0_in_desc.flags = DIEPDMA_LAST | DIEPDMA_BS_HOST_RDY | DIEPDMA_IOC |
DIEPDMA_TXBYTES(0) | DIEPDMA_SP;
GR_USB_DIEPCTL(0) |= DXEPCTL_CNAK | DXEPCTL_EPENA;
ep0_out_desc.flags = DOEPDMA_RXBYTES(64) | DOEPDMA_LAST
| DOEPDMA_BS_HOST_RDY | DOEPDMA_IOC;
GR_USB_DOEPCTL(0) |= DXEPCTL_CNAK | DXEPCTL_EPENA;
break;
default: /* unhandled request */
goto unknown_req;
}
} else {
goto unknown_req;
}
return;
unknown_req:
ep0_out_desc.flags = DOEPDMA_RXBYTES(64) | DOEPDMA_LAST |
DOEPDMA_BS_HOST_RDY | DOEPDMA_IOC;
GR_USB_DOEPCTL(0) |= DXEPCTL_CNAK | DXEPCTL_EPENA;
GR_USB_DIEPCTL(0) |= DXEPCTL_STALL | DXEPCTL_EPENA;
return;
}
static void ep0_tx(void)
{
uint32_t epint = GR_USB_DIEPINT(0);
GR_USB_DIEPINT(0) = epint; /* clear IT */
if (set_addr) {
GR_USB_DCFG = (GR_USB_DCFG & ~DCFG_DEVADDR(0x7f))
| DCFG_DEVADDR(set_addr);
CPRINTF("SETAD %02x\n", set_addr);
set_addr = 0;
}
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, desc_ptr, len);
ep0_in_desc.flags = DIEPDMA_LAST | DIEPDMA_BS_HOST_RDY |
DIEPDMA_IOC | DIEPDMA_TXBYTES(len);
desc_left -= len;
desc_ptr += len;
/* send the null OUT transaction if the transfer is complete */
GR_USB_DIEPCTL(0) |= DXEPCTL_CNAK | DXEPCTL_EPENA;
/* TODO set Data PID in DIEPCTL */
return;
}
}
static void ep0_reset(void)
{
ep0_out_desc.flags = DOEPDMA_RXBYTES(64) | DOEPDMA_LAST |
DOEPDMA_BS_HOST_RDY | DOEPDMA_IOC;
ep0_out_desc.addr = ep0_buf_rx;
ep0_in_desc.flags = DIEPDMA_TXBYTES(0) | DIEPDMA_LAST |
DIEPDMA_BS_HOST_RDY | DIEPDMA_IOC;
ep0_in_desc.addr = ep0_buf_tx;
GR_USB_DIEPDMA(0) = (uint32_t)&ep0_in_desc;
GR_USB_DOEPDMA(0) = (uint32_t)&ep0_out_desc;
GR_USB_DOEPCTL(0) = DXEPCTL_MPS64 | DXEPCTL_USBACTEP |
DXEPCTL_EPTYPE_CTRL |
DXEPCTL_CNAK | DXEPCTL_EPENA;
GR_USB_DIEPCTL(0) = DXEPCTL_MPS64 | DXEPCTL_USBACTEP |
DXEPCTL_EPTYPE_CTRL;
GR_USB_DAINTMSK = (1<<0) | (1 << (0+16)); /* EPO interrupts */
}
USB_DECLARE_EP(0, ep0_tx, ep0_rx, ep0_reset);
static void usb_reset(void)
{
int ep;
for (ep = 0; ep < USB_EP_COUNT; ep++)
usb_ep_reset[ep]();
/*
* set the default address : 0
* as we are not configured yet
*/
GR_USB_DCFG &= ~DCFG_DEVADDR(0x7f);
}
void usb_interrupt(void)
{
uint32_t status = GR_USB_GINTSTS;
if (status & GINTSTS_USBRST)
usb_reset();
if (status & (GINTSTS_OEPINT | GINTSTS_IEPINT)) {
uint32_t daint = GR_USB_DAINT;
int ep;
for (ep = 0; ep < USB_EP_COUNT && daint; ep++, daint >>= 1) {
if (daint & (1 << 16)) /* OUT packet */
usb_ep_rx[ep]();
if (daint & 1) /* IN packet */
usb_ep_tx[ep]();
}
}
if (status & GINTSTS_GOUTNAKEFF)
GR_USB_DCTL = DCTL_CGOUTNAK;
if (status & GINTSTS_GINNAKEFF)
GR_USB_DCTL = DCTL_CGNPINNAK;
/* ack interrupts */
GR_USB_GINTSTS = status;
}
DECLARE_IRQ(GC_IRQNUM_USB0_USBINTR, usb_interrupt, 1);
static void usb_softreset(void)
{
int timeout;
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;
}
timeout = 10000;
while (!(GR_USB_GRSTCTL & GRSTCTL_AHBIDLE) && timeout-- > 0)
;
if (!timeout) {
CPRINTF("USB: reset timeout\n");
return;
}
}
void usb_connect(void)
{
GR_USB_DCTL &= ~DCTL_SFTDISCON;
}
void usb_disconnect(void)
{
GR_USB_DCTL |= DCTL_SFTDISCON;
}
void usb_init(void)
{
int i;
/* Enable clocks */
clock_enable_module(MODULE_USB, 1);
/* set up pinmux */
gpio_config_module(MODULE_USB, 1);
/* Use the last 128 entries of the FIFO for EP INFO */
GR_USB_GDFIFOCFG = ((FIFO_SIZE - 0x80) << 16) | FIFO_SIZE;
/* PHY configuration */
/* Full-Speed Serial PHY */
GR_USB_GUSBCFG = GUSBCFG_PHYSEL_FS | GUSBCFG_FSINTF_6PIN
| GUSBCFG_TOUTCAL(7) | (9 << 10);
usb_softreset();
/* PHY configuration */
/* Full-Speed Serial PHY */
GR_USB_GUSBCFG = GUSBCFG_PHYSEL_FS | GUSBCFG_FSINTF_6PIN
| GUSBCFG_TOUTCAL(7) | (9 << 10);
/* Global + DMA configuration */
GR_USB_GAHBCFG = GAHBCFG_DMA_EN | GAHBCFG_GLB_INTR_EN |
GAHBCFG_NP_TXF_EMP_LVL;
/* unmask subset of endpoint interrupts */
GR_USB_DIEPMSK = DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK |
DIEPMSK_EPDISBLDMSK | DIEPMSK_XFERCOMPLMSK |
DIEPMSK_INTKNEPMISMSK /*| (1<<9)*//*BNA*/;
GR_USB_DOEPMSK = DOEPMSK_SETUPMSK | DOEPMSK_AHBERRMSK |
DOEPMSK_EPDISBLDMSK | DOEPMSK_XFERCOMPLMSK;
GR_USB_DAINTMSK = 0;
/* Be in disconnected state we are ready */
GR_USB_DCTL |= DCTL_SFTDISCON;
/* Max speed: USB2 FS */
GR_USB_DCFG = DCFG_DEVSPD_FS48 | DCFG_DESCDMA;
/* clear pending interrupts */
GR_USB_GINTSTS = 0xFFFFFFFF;
/*
* Setup FIFOs configuration
* RX FIFO needs more than 64 entries (for reserved space)
* set RX FIFO to 80 entries
* set TX FIFO to 64 bytes = 16 (x 32-bit) entries
*/
GR_USB_GRXFSIZ = 80;
GR_USB_GNPTXFSIZ = 80 | (16 << 16);
for (i = 1; i < TX_FIFO_CNT; i++)
GR_USB_DIEPTXF(i) = (80 + i*16) | (16 << 16);
/* Flush all FIFOs */
GR_USB_GRSTCTL = GRSTCTL_TXFNUM(0x10) | GRSTCTL_TXFFLSH
| GRSTCTL_RXFFLSH;
while (GR_USB_GRSTCTL & (GRSTCTL_TXFFLSH | GRSTCTL_RXFFLSH))
; /* timeout 100ms */
/* Initialize endpoints */
for (i = 0; i < 16; i++) {
GR_USB_DIEPCTL(i) = 0x00/* TODO */;
GR_USB_DOEPCTL(i) = 0x00/* TODO */;
}
/* 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;
/* Enable interrupt handlers */
task_enable_irq(GC_IRQNUM_USB0_USBINTR);
/* set interrupts mask : reset/correct tranfer/errors */
GR_USB_GINTMSK = GINTSTS_GOUTNAKEFF | GINTSTS_GINNAKEFF |
GINTSTS_USBRST | GINTSTS_ENUMDONE |
GINTSTS_OEPINT | GINTSTS_IEPINT;
#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();
/* disable interrupt handlers */
task_disable_irq(GC_IRQNUM_USB0_USBINTR);
/* disable clocks */
clock_enable_module(MODULE_USB, 0);
/* TODO: pin-mux */
}
void *memcpy_to_usbram(void *dest, const void *src, size_t n)
{
return memcpy(dest, src, n);
}

266
chip/g/usb_console.c Normal file
View File

@@ -0,0 +1,266 @@
/* Copyright (c) 2014 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 "common.h"
#include "config.h"
#include "console.h"
#include "link_defs.h"
#include "printf.h"
#include "registers.h"
#include "task.h"
#include "timer.h"
#include "util.h"
#include "usb.h"
/* Console output macro */
#define CPRINTF(format, args...) cprintf(CC_USB, format, ## args)
#define USB_CONSOLE_TIMEOUT_US (30 * MSEC)
#define USB_CONSOLE_RX_BUF_SIZE 16
#define RX_BUF_NEXT(i) (((i) + 1) & (USB_CONSOLE_RX_BUF_SIZE - 1))
static volatile char rx_buf[USB_CONSOLE_RX_BUF_SIZE];
static volatile int rx_buf_head;
static volatile int rx_buf_tail;
static int last_tx_ok = 1;
static int is_reset;
static int is_enabled = 1;
/* USB-Serial descriptors */
const struct usb_interface_descriptor USB_IFACE_DESC(USB_IFACE_CONSOLE) =
{
.bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = USB_IFACE_CONSOLE,
.bAlternateSetting = 0,
.bNumEndpoints = 2,
.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
.bInterfaceSubClass = USB_SUBCLASS_GOOGLE_SERIAL,
.bInterfaceProtocol = USB_PROTOCOL_GOOGLE_SERIAL,
.iInterface = USB_STR_CONSOLE_NAME,
};
const struct usb_endpoint_descriptor USB_EP_DESC(USB_IFACE_CONSOLE, 0) =
{
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = 0x80 | USB_EP_CONSOLE,
.bmAttributes = 0x02 /* Bulk IN */,
.wMaxPacketSize = USB_MAX_PACKET_SIZE,
.bInterval = 10
};
const struct usb_endpoint_descriptor USB_EP_DESC(USB_IFACE_CONSOLE, 1) =
{
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_EP_CONSOLE,
.bmAttributes = 0x02 /* Bulk OUT */,
.wMaxPacketSize = USB_MAX_PACKET_SIZE,
.bInterval = 0
};
static usb_uint ep_buf_tx[USB_MAX_PACKET_SIZE / 2] /*__usb_ram*/;
static usb_uint ep_buf_rx[USB_MAX_PACKET_SIZE / 2] /*__usb_ram*/;
static struct g_usb_desc ep_out_desc;
static struct g_usb_desc ep_in_desc;
static void con_ep_tx(void)
{
/* clear IT */
GR_USB_DIEPINT(USB_EP_CONSOLE) = 0xffffffff;
}
static void con_ep_rx(void)
{
int i;
int rx_size = USB_MAX_PACKET_SIZE
- (ep_out_desc.flags & DOEPDMA_RXBYTES_MASK);
for (i = 0; i < rx_size; i++) {
int rx_buf_next = RX_BUF_NEXT(rx_buf_head);
if (rx_buf_next != rx_buf_tail) {
rx_buf[rx_buf_head] = ((i & 1) ?
(ep_buf_rx[i >> 1] >> 8) :
(ep_buf_rx[i >> 1] & 0xff));
rx_buf_head = rx_buf_next;
}
}
ep_out_desc.flags = DOEPDMA_RXBYTES(USB_MAX_PACKET_SIZE) |
DOEPDMA_LAST | DOEPDMA_BS_HOST_RDY | DOEPDMA_IOC;
GR_USB_DOEPCTL(USB_EP_CONSOLE) |= DXEPCTL_CNAK | DXEPCTL_EPENA;
/* clear IT */
GR_USB_DOEPINT(USB_EP_CONSOLE) = 0xffffffff;
/* wake-up the console task */
console_has_input();
}
static void ep_reset(void)
{
ep_out_desc.flags = DOEPDMA_RXBYTES(USB_MAX_PACKET_SIZE) |
DOEPDMA_LAST | DOEPDMA_BS_HOST_RDY | DOEPDMA_IOC;
ep_out_desc.addr = ep_buf_rx;
GR_USB_DOEPDMA(USB_EP_CONSOLE) = (uint32_t)&ep_out_desc;
ep_in_desc.flags = DIEPDMA_LAST | DIEPDMA_BS_HOST_BSY | DIEPDMA_IOC;
ep_in_desc.addr = ep_buf_tx;
GR_USB_DIEPDMA(USB_EP_CONSOLE) = (uint32_t)&ep_in_desc;
GR_USB_DOEPCTL(USB_EP_CONSOLE) = DXEPCTL_MPS(64) | DXEPCTL_USBACTEP |
DXEPCTL_EPTYPE_BULK |
DXEPCTL_CNAK | DXEPCTL_EPENA;
GR_USB_DIEPCTL(USB_EP_CONSOLE) = DXEPCTL_MPS(64) | DXEPCTL_USBACTEP |
DXEPCTL_EPTYPE_BULK |
DXEPCTL_TXFNUM(USB_EP_CONSOLE);
GR_USB_DAINTMSK |= (1<<USB_EP_CONSOLE) | (1 << (USB_EP_CONSOLE+16));
is_reset = 1;
}
USB_DECLARE_EP(USB_EP_CONSOLE, con_ep_tx, con_ep_rx, ep_reset);
static int __tx_char(void *context, int c)
{
usb_uint *buf = (usb_uint *)ep_buf_tx;
int *tx_idx = context;
/* Do newline to CRLF translation */
if (c == '\n' && __tx_char(context, '\r'))
return 1;
if (*tx_idx > 63)
return 1;
if (!(*tx_idx & 1))
buf[*tx_idx/2] = c;
else
buf[*tx_idx/2] |= c << 8;
(*tx_idx)++;
return 0;
}
static void usb_enable_tx(int len)
{
if (!is_enabled)
return;
ep_in_desc.flags = DIEPDMA_LAST | DIEPDMA_BS_HOST_RDY | DIEPDMA_IOC |
DIEPDMA_TXBYTES(len);
GR_USB_DIEPCTL(USB_EP_CONSOLE) |= DXEPCTL_CNAK | DXEPCTL_EPENA;
}
static inline int usb_console_tx_valid(void)
{
return (ep_in_desc.flags & DIEPDMA_BS_MASK) == DIEPDMA_BS_DMA_DONE;
}
static int usb_wait_console(void)
{
timestamp_t deadline = get_time();
int wait_time_us = 1;
deadline.val += USB_CONSOLE_TIMEOUT_US;
/*
* If the USB console is not used, Tx buffer would never free up.
* In this case, let's drop characters immediately instead of sitting
* for some time just to time out. On the other hand, if the last
* Tx is good, it's likely the host is there to receive data, and
* we should wait so that we don't clobber the buffer.
*/
if (last_tx_ok) {
while (usb_console_tx_valid() || !is_reset) {
if (timestamp_expired(deadline, NULL) ||
in_interrupt_context()) {
last_tx_ok = 0;
return EC_ERROR_TIMEOUT;
}
if (wait_time_us < MSEC)
udelay(wait_time_us);
else
usleep(wait_time_us);
wait_time_us *= 2;
}
return EC_SUCCESS;
} else {
last_tx_ok = !usb_console_tx_valid();
return EC_SUCCESS;
}
}
/*
* Public USB console implementation below.
*/
int usb_getc(void)
{
int c;
if (rx_buf_tail == rx_buf_head)
return -1;
if (!is_enabled)
return -1;
c = rx_buf[rx_buf_tail];
rx_buf_tail = RX_BUF_NEXT(rx_buf_tail);
return c;
}
int usb_putc(int c)
{
int ret;
int tx_idx = 0;
ret = usb_wait_console();
if (ret)
return ret;
ret = __tx_char(&tx_idx, c);
usb_enable_tx(tx_idx);
return ret;
}
int usb_puts(const char *outstr)
{
int ret;
int tx_idx = 0;
ret = usb_wait_console();
if (ret)
return ret;
/* Put all characters in the output buffer */
while (*outstr) {
if (__tx_char(&tx_idx, *outstr++) != 0)
break;
}
usb_enable_tx(tx_idx);
/* Successful if we consumed all output */
return *outstr ? EC_ERROR_OVERFLOW : EC_SUCCESS;
}
int usb_vprintf(const char *format, va_list args)
{
int ret;
int tx_idx = 0;
ret = usb_wait_console();
if (ret)
return ret;
ret = vfnprintf(__tx_char, &tx_idx, format, args);
usb_enable_tx(tx_idx);
return ret;
}
void usb_console_enable(int enabled)
{
is_enabled = enabled;
}

107
chip/g/usb_endpoints.S Normal file
View File

@@ -0,0 +1,107 @@
/* Copyright (c) 2014 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.
*
* USB endpoints/interfaces callbacks declaration
*/
#include "config.h"
.section .rodata.usb_ep
.macro endpoint number suffix
.if \number < USB_EP_COUNT
.long ep_\number\()_\()\suffix
.weak ep_\number\()_\()\suffix
.set ep_\number\()_\()\suffix, ep_undefined
.endif
.endm
.macro interface number
.if \number < USB_IFACE_COUNT
.long iface_\number\()_request
.weak iface_\number\()_request
.set iface_\number\()_request, iface_undefined
.endif
.endm
/* align function pointers on a 32-bit boundary */
.align 2
/* Endpoint callbacks */
.global usb_ep_tx
usb_ep_tx:
endpoint 0 tx
endpoint 1 tx
endpoint 2 tx
endpoint 3 tx
endpoint 4 tx
endpoint 5 tx
endpoint 6 tx
endpoint 7 tx
endpoint 8 tx
endpoint 9 tx
endpoint 10 tx
endpoint 11 tx
endpoint 12 tx
endpoint 13 tx
endpoint 14 tx
endpoint 15 tx
.global usb_ep_rx
usb_ep_rx:
endpoint 0 rx
endpoint 1 rx
endpoint 2 rx
endpoint 3 rx
endpoint 4 rx
endpoint 5 rx
endpoint 6 rx
endpoint 7 rx
endpoint 8 rx
endpoint 9 rx
endpoint 10 rx
endpoint 11 rx
endpoint 12 rx
endpoint 13 rx
endpoint 14 rx
endpoint 15 rx
.global usb_ep_reset
usb_ep_reset:
endpoint 0 rst
endpoint 1 rst
endpoint 2 rst
endpoint 3 rst
endpoint 4 rst
endpoint 5 rst
endpoint 6 rst
endpoint 7 rst
endpoint 8 rst
endpoint 9 rst
endpoint 10 rst
endpoint 11 rst
endpoint 12 rst
endpoint 13 rst
endpoint 14 rst
endpoint 15 rst
.global usb_iface_request
usb_iface_request:
interface 0
interface 1
interface 2
interface 3
interface 4
interface 5
interface 6
interface 7
.text
.code 16
.thumb_func
/* Undefined interface callbacks fail by returning non-zero*/
iface_undefined:
mov r0, #1
ep_undefined:
bx lr

170
chip/g/usb_hid.c Normal file
View File

@@ -0,0 +1,170 @@
/* Copyright (c) 2014 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 "gpio.h"
#include "hooks.h"
#include "link_defs.h"
#include "registers.h"
#include "task.h"
#include "timer.h"
#include "util.h"
#include "usb.h"
#include "usb_hid.h"
/* Console output macro */
#define CPRINTF(format, args...) cprintf(CC_USB, format, ## args)
#define HID_REPORT_SIZE 8
/* HID descriptors */
const struct usb_interface_descriptor USB_IFACE_DESC(USB_IFACE_HID) =
{
.bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = USB_IFACE_HID,
.bAlternateSetting = 0,
.bNumEndpoints = 1,
.bInterfaceClass = USB_CLASS_HID,
.bInterfaceSubClass = USB_HID_SUBCLASS_BOOT,
.bInterfaceProtocol = USB_HID_PROTOCOL_KEYBOARD,
.iInterface = 0,
};
const struct usb_endpoint_descriptor USB_EP_DESC(USB_IFACE_HID, 81) =
{
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = 0x80 | USB_EP_HID,
.bmAttributes = 0x03 /* Interrupt endpoint */,
.wMaxPacketSize = HID_REPORT_SIZE,
.bInterval = 32 /* ms polling interval */
};
const struct usb_hid_descriptor USB_CUSTOM_DESC(USB_IFACE_HID, hid) =
{
.bLength = 9,
.bDescriptorType = USB_HID_DT_HID,
.bcdHID = 0x0100,
.bCountryCode = 0x00, /* Hardware target country */
.bNumDescriptors = 1,
.desc = {
{.bDescriptorType = USB_HID_DT_REPORT,
.wDescriptorLength = 45}
}
};
/* HID : Report Descriptor */
static const uint8_t report_desc[] = {
0x05, 0x01, /* Usage Page (Generic Desktop) */
0x09, 0x06, /* Usage (Keyboard) */
0xA1, 0x01, /* Collection (Application) */
0x05, 0x07, /* Usage Page (Key Codes) */
0x19, 0xE0, /* Usage Minimum (224) */
0x29, 0xE7, /* Usage Maximum (231) */
0x15, 0x00, /* Logical Minimum (0) */
0x25, 0x01, /* Logical Maximum (1) */
0x75, 0x01, /* Report Size (1) */
0x95, 0x08, /* Report Count (8) */
0x81, 0x02, /* Input (Data, Variable, Absolute), ;Modifier byte */
0x95, 0x01, /* Report Count (1) */
0x75, 0x08, /* Report Size (8) */
0x81, 0x01, /* Input (Constant), ;Reserved byte */
0x95, 0x06, /* Report Count (6) */
0x75, 0x08, /* Report Size (8) */
0x15, 0x00, /* Logical Minimum (0) */
0x25, 0x65, /* Logical Maximum(101) */
0x05, 0x07, /* Usage Page (Key Codes) */
0x19, 0x00, /* Usage Minimum (0) */
0x29, 0x65, /* Usage Maximum (101) */
0x81, 0x00, /* Input (Data, Array), ;Key arrays (6 bytes) */
0xC0, /* End Collection */
0x00 /* Padding */
};
static usb_uint hid_ep_buf[HID_REPORT_SIZE / 2] /*__usb_ram*/;
static struct g_usb_desc hid_ep_desc;
void set_keyboard_report(uint64_t rpt)
{
memcpy_to_usbram(hid_ep_buf, (const uint8_t *)&rpt, sizeof(rpt));
hid_ep_desc.flags = DIEPDMA_LAST | DIEPDMA_BS_HOST_RDY | DIEPDMA_IOC |
DIEPDMA_TXBYTES(HID_REPORT_SIZE);
/* enable TX */
GR_USB_DIEPCTL(USB_EP_HID) |= DXEPCTL_CNAK | DXEPCTL_EPENA;
}
static void hid_tx(void)
{
/* clear IT */
GR_USB_DIEPINT(USB_EP_HID) = 0xffffffff;
return;
}
static void hid_reset(void)
{
hid_ep_desc.flags = DIEPDMA_LAST | DIEPDMA_BS_HOST_BSY | DIEPDMA_IOC;
hid_ep_desc.addr = hid_ep_buf;
GR_USB_DIEPDMA(USB_EP_HID) = (uint32_t)&hid_ep_desc;
GR_USB_DIEPCTL(USB_EP_HID) = DXEPCTL_MPS(HID_REPORT_SIZE) |
DXEPCTL_USBACTEP | DXEPCTL_EPTYPE_INT |
DXEPCTL_TXFNUM(USB_EP_HID);
GR_USB_DAINTMSK |= (1<<USB_EP_CONSOLE);
}
USB_DECLARE_EP(USB_EP_HID, hid_tx, hid_tx, hid_reset);
extern struct g_usb_desc ep0_in_desc;
extern struct g_usb_desc ep0_out_desc;
static int hid_iface_request(usb_uint *ep0_buf_rx, usb_uint *ep0_buf_tx)
{
int len;
if ((ep0_buf_rx[0] == (USB_DIR_IN | USB_RECIP_INTERFACE |
(USB_REQ_GET_DESCRIPTOR << 8))) &&
(ep0_buf_rx[1] == (USB_HID_DT_REPORT << 8))) {
/* Setup : HID specific : Get Report descriptor */
memcpy_to_usbram(ep0_buf_tx, report_desc,
sizeof(report_desc));
len = MIN(ep0_buf_rx[3], sizeof(report_desc));
ep0_in_desc.flags = DIEPDMA_LAST | DIEPDMA_BS_HOST_RDY |
DIEPDMA_IOC | DIEPDMA_TXBYTES(len);
GR_USB_DIEPCTL(0) |= DXEPCTL_CNAK | DXEPCTL_EPENA;
ep0_out_desc.flags = DOEPDMA_RXBYTES(64) | DOEPDMA_LAST
| DOEPDMA_BS_HOST_RDY | DOEPDMA_IOC;
GR_USB_DOEPCTL(0) |= DXEPCTL_CNAK | DXEPCTL_EPENA;
return 0;
}
return 1;
}
USB_DECLARE_IFACE(USB_IFACE_HID, hid_iface_request)
static int command_hid(int argc, char **argv)
{
uint8_t keycode = 0x0a; /* 'G' key */
if (argc >= 2) {
char *e;
keycode = strtoi(argv[1], &e, 16);
if (*e)
return EC_ERROR_PARAM1;
}
/* press then release the key */
set_keyboard_report((uint32_t)keycode << 16);
udelay(50000);
set_keyboard_report(0x000000);
return EC_SUCCESS;
}
DECLARE_CONSOLE_COMMAND(hid, command_hid,
"[<HID keycode>]",
"test USB HID driver",
NULL);