Merge branch 'master' of git://git.denx.de/u-boot-usb

This commit is contained in:
Tom Rini 2015-01-20 10:20:13 -05:00
commit b44a414959
17 changed files with 601 additions and 94 deletions

View file

@ -441,6 +441,26 @@ static int do_usb_stop_keyboard(int force)
return 0;
}
static void do_usb_start(void)
{
bootstage_mark_name(BOOTSTAGE_ID_USB_START, "usb_start");
if (usb_init() < 0)
return;
#ifdef CONFIG_USB_STORAGE
/* try to recognize storage devices immediately */
usb_stor_curr_dev = usb_stor_scan(1);
#endif
#ifdef CONFIG_USB_HOST_ETHER
/* try to recognize ethernet devices immediately */
usb_ether_curr_dev = usb_host_eth_scan(1);
#endif
#ifdef CONFIG_USB_KEYBOARD
drv_usb_kbd_init();
#endif
}
/******************************************************************************
* usb command intepreter
*/
@ -457,26 +477,20 @@ static int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
if (argc < 2)
return CMD_RET_USAGE;
if ((strncmp(argv[1], "reset", 5) == 0) ||
(strncmp(argv[1], "start", 5) == 0)) {
bootstage_mark_name(BOOTSTAGE_ID_USB_START, "usb_start");
if (strncmp(argv[1], "start", 5) == 0) {
if (usb_started)
return 0; /* Already started */
printf("starting USB...\n");
do_usb_start();
return 0;
}
if (strncmp(argv[1], "reset", 5) == 0) {
printf("resetting USB...\n");
if (do_usb_stop_keyboard(1) != 0)
return 1;
usb_stop();
printf("(Re)start USB...\n");
if (usb_init() >= 0) {
#ifdef CONFIG_USB_STORAGE
/* try to recognize storage devices immediately */
usb_stor_curr_dev = usb_stor_scan(1);
#endif
#ifdef CONFIG_USB_HOST_ETHER
/* try to recognize ethernet devices immediately */
usb_ether_curr_dev = usb_host_eth_scan(1);
#endif
#ifdef CONFIG_USB_KEYBOARD
drv_usb_kbd_init();
#endif
}
do_usb_start();
return 0;
}
if (strncmp(argv[1], "stop", 4) == 0) {

View file

@ -59,6 +59,7 @@ int usb_init(void)
void *ctrl;
struct usb_device *dev;
int i, start_index = 0;
int controllers_initialized = 0;
int ret;
dev_index = 0;
@ -78,6 +79,7 @@ int usb_init(void)
ret = usb_lowlevel_init(i, USB_INIT_HOST, &ctrl);
if (ret == -ENODEV) { /* No such device. */
puts("Port not available.\n");
controllers_initialized++;
continue;
}
@ -89,6 +91,7 @@ int usb_init(void)
* lowlevel init is OK, now scan the bus for devices
* i.e. search HUBs and configure them
*/
controllers_initialized++;
start_index = dev_index;
printf("scanning bus %d for devices... ", i);
dev = usb_alloc_new_device(ctrl);
@ -110,12 +113,10 @@ int usb_init(void)
debug("scan end\n");
/* if we were not able to find at least one working bus, bail out */
if (!usb_started) {
if (controllers_initialized == 0)
puts("USB error: all controllers failed lowlevel init\n");
return -1;
}
return 0;
return usb_started ? 0 : -1;
}
/******************************************************************************
@ -969,6 +970,8 @@ int usb_new_device(struct usb_device *dev)
printf("\n Couldn't reset port %i\n", dev->portnr);
return 1;
}
} else {
usb_reset_root_port();
}
#endif

View file

@ -332,7 +332,8 @@ static inline void usb_kbd_poll_for_event(struct usb_device *dev)
/* We've consumed all queued int packets, create new */
destroy_int_queue(dev, data->intq);
data->intq = create_int_queue(dev, data->intpipe, 1,
USB_KBD_BOOT_REPORT_SIZE, data->new);
USB_KBD_BOOT_REPORT_SIZE, data->new,
data->intinterval);
}
#endif
}
@ -453,7 +454,8 @@ static int usb_kbd_probe(struct usb_device *dev, unsigned int ifnum)
debug("USB KBD: enable interrupt pipe...\n");
#ifdef CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE
data->intq = create_int_queue(dev, data->intpipe, 1,
USB_KBD_BOOT_REPORT_SIZE, data->new);
USB_KBD_BOOT_REPORT_SIZE, data->new,
data->intinterval);
if (!data->intq) {
#else
if (usb_submit_int_msg(dev, data->intpipe, data->new, data->intpktsize,
@ -542,6 +544,10 @@ int usb_kbd_deregister(int force)
data = usb_kbd_dev->privptr;
if (stdio_deregister_dev(dev, force) != 0)
return 1;
#ifdef CONFIG_CONSOLE_MUX
if (iomux_doenv(stdin, getenv("stdin")) != 0)
return 1;
#endif
#ifdef CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE
destroy_int_queue(usb_kbd_dev, data->intq);
#endif

View file

@ -271,6 +271,19 @@ static int asix_read_mac(struct eth_device *eth)
return 0;
}
static int asix_write_mac(struct eth_device *eth)
{
struct ueth_data *dev = (struct ueth_data *)eth->priv;
int ret;
ret = asix_write_cmd(dev, AX_ACCESS_MAC, AX_NODE_ID, ETH_ALEN,
ETH_ALEN, eth->enetaddr);
if (ret < 0)
debug("Failed to set MAC address: %02x\n", ret);
return ret;
}
static int asix_basic_reset(struct ueth_data *dev)
{
struct asix_private *dev_priv = (struct asix_private *)dev->dev_priv;
@ -686,6 +699,7 @@ int ax88179_eth_get_info(struct usb_device *dev, struct ueth_data *ss,
eth->send = asix_send;
eth->recv = asix_recv;
eth->halt = asix_halt;
eth->write_hwaddr = asix_write_mac;
eth->priv = ss;
if (asix_basic_reset(ss))

View file

@ -761,6 +761,14 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
if (value >= 0)
value = min(w_length, (u16) value);
break;
case USB_DT_BOS:
/*
* The USB compliance test (USB 2.0 Command Verifier)
* issues this request. We should not run into the
* default path here. But return for now until
* the superspeed support is added.
*/
break;
default:
goto unknown;
}

View file

@ -780,6 +780,13 @@ static int dfu_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
return 0;
}
static int __dfu_get_alt(struct usb_function *f, unsigned intf)
{
struct f_dfu *f_dfu = func_to_dfu(f);
return f_dfu->altsetting;
}
/* TODO: is this really what we need here? */
static void dfu_disable(struct usb_function *f)
{
@ -806,6 +813,7 @@ static int dfu_bind_config(struct usb_configuration *c)
f_dfu->usb_function.bind = dfu_bind;
f_dfu->usb_function.unbind = dfu_unbind;
f_dfu->usb_function.set_alt = dfu_set_alt;
f_dfu->usb_function.get_alt = __dfu_get_alt;
f_dfu->usb_function.disable = dfu_disable;
f_dfu->usb_function.strings = dfu_generic_strings;
f_dfu->usb_function.setup = dfu_handle;

View file

@ -1950,11 +1950,11 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
dev->watchdog.period = 5000 * CONFIG_SYS_HZ / 1000000; /* 5 ms */
dev->watchdog.function = udc_watchdog;
dev->mach = &mach_info;
udc_disable(dev);
udc_reinit(dev);
dev->mach = &mach_info;
dev->gadget.name = "pxa2xx_udc";
retval = driver->bind(&dev->gadget);
if (retval) {

View file

@ -1148,7 +1148,7 @@ disable_periodic(struct ehci_ctrl *ctrl)
struct int_queue *
create_int_queue(struct usb_device *dev, unsigned long pipe, int queuesize,
int elementsize, void *buffer)
int elementsize, void *buffer, int interval)
{
struct ehci_ctrl *ctrl = dev->controller;
struct int_queue *result = NULL;
@ -1398,7 +1398,7 @@ submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
debug("dev=%p, pipe=%lu, buffer=%p, length=%d, interval=%d",
dev, pipe, buffer, length, interval);
queue = create_int_queue(dev, pipe, 1, length, buffer);
queue = create_int_queue(dev, pipe, 1, length, buffer, interval);
if (!queue)
return -1;

View file

@ -8,6 +8,7 @@ obj-$(CONFIG_MUSB_HOST) += musb_host.o musb_core.o musb_uboot.o
obj-$(CONFIG_USB_MUSB_DSPS) += musb_dsps.o
obj-$(CONFIG_USB_MUSB_AM35X) += am35x.o
obj-$(CONFIG_USB_MUSB_OMAP2PLUS) += omap2430.o
obj-$(CONFIG_USB_MUSB_SUNXI) += sunxi.o
ccflags-y := $(call cc-option,-Wno-unused-variable) \
$(call cc-option,-Wno-unused-but-set-variable) \

View file

@ -2130,8 +2130,6 @@ done:
return ret;
}
#ifndef __UBOOT__
/*
* abort a transfer that's at the head of a hardware queue.
* called with controller locked, irqs blocked
@ -2195,7 +2193,14 @@ static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh)
return status;
}
static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
#ifndef __UBOOT__
static int musb_urb_dequeue(
#else
int musb_urb_dequeue(
#endif
struct usb_hcd *hcd,
struct urb *urb,
int status)
{
struct musb *musb = hcd_to_musb(hcd);
struct musb_qh *qh;
@ -2253,6 +2258,7 @@ done:
return ret;
}
#ifndef __UBOOT__
/* disable an endpoint */
static void
musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep)

View file

@ -110,5 +110,6 @@ static inline struct urb *next_urb(struct musb_qh *qh)
#ifdef __UBOOT__
int musb_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags);
int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status);
#endif
#endif /* _MUSB_HOST_H */

View file

@ -216,6 +216,9 @@
#ifndef CONFIG_BLACKFIN
/* SUNXI has different reg addresses, but identical r/w functions */
#ifndef CONFIG_ARCH_SUNXI
/*
* Common USB registers
*/
@ -318,6 +321,85 @@
#define MUSB_BUSCTL_OFFSET(_epnum, _offset) \
(0x80 + (8*(_epnum)) + (_offset))
#else /* CONFIG_ARCH_SUNXI */
/*
* Common USB registers
*/
#define MUSB_FADDR 0x0098
#define MUSB_POWER 0x0040
#define MUSB_INTRTX 0x0044
#define MUSB_INTRRX 0x0046
#define MUSB_INTRTXE 0x0048
#define MUSB_INTRRXE 0x004A
#define MUSB_INTRUSB 0x004C
#define MUSB_INTRUSBE 0x0050
#define MUSB_FRAME 0x0054
#define MUSB_INDEX 0x0042
#define MUSB_TESTMODE 0x007C
/* Get offset for a given FIFO from musb->mregs */
#define MUSB_FIFO_OFFSET(epnum) (0x00 + ((epnum) * 4))
/*
* Additional Control Registers
*/
#define MUSB_DEVCTL 0x0041
/* These are always controlled through the INDEX register */
#define MUSB_TXFIFOSZ 0x0090
#define MUSB_RXFIFOSZ 0x0094
#define MUSB_TXFIFOADD 0x0092
#define MUSB_RXFIFOADD 0x0096
#define MUSB_EPINFO 0x0078
#define MUSB_RAMINFO 0x0079
#define MUSB_LINKINFO 0x007A
#define MUSB_VPLEN 0x007B
#define MUSB_HS_EOF1 0x007C
#define MUSB_FS_EOF1 0x007D
#define MUSB_LS_EOF1 0x007E
/* Offsets to endpoint registers */
#define MUSB_TXMAXP 0x0080
#define MUSB_TXCSR 0x0082
#define MUSB_CSR0 0x0082
#define MUSB_RXMAXP 0x0084
#define MUSB_RXCSR 0x0086
#define MUSB_RXCOUNT 0x0088
#define MUSB_COUNT0 0x0088
#define MUSB_TXTYPE 0x008C
#define MUSB_TYPE0 0x008C
#define MUSB_TXINTERVAL 0x008D
#define MUSB_NAKLIMIT0 0x008D
#define MUSB_RXTYPE 0x008E
#define MUSB_RXINTERVAL 0x008F
#define MUSB_CONFIGDATA 0x00b0 /* musb_read_configdata adds 0x10 ! */
#define MUSB_FIFOSIZE 0x0090
/* Offsets to endpoint registers in indexed model (using INDEX register) */
#define MUSB_INDEXED_OFFSET(_epnum, _offset) (_offset)
#define MUSB_TXCSR_MODE 0x2000
/* "bus control"/target registers, for host side multipoint (external hubs) */
#define MUSB_TXFUNCADDR 0x0098
#define MUSB_TXHUBADDR 0x009A
#define MUSB_TXHUBPORT 0x009B
#define MUSB_RXFUNCADDR 0x009C
#define MUSB_RXHUBADDR 0x009E
#define MUSB_RXHUBPORT 0x009F
/* Endpoint is selected with MUSB_INDEX. */
#define MUSB_BUSCTL_OFFSET(_epnum, _offset) (_offset)
#endif /* CONFIG_ARCH_SUNXI */
static inline void musb_write_txfifosz(void __iomem *mbase, u8 c_size)
{
musb_writeb(mbase, MUSB_TXFIFOSZ, c_size);
@ -340,7 +422,9 @@ static inline void musb_write_rxfifoadd(void __iomem *mbase, u16 c_off)
static inline void musb_write_ulpi_buscontrol(void __iomem *mbase, u8 val)
{
#ifndef CONFIG_ARCH_SUNXI /* No ulpi on sunxi */
musb_writeb(mbase, MUSB_ULPI_BUSCONTROL, val);
#endif
}
static inline u8 musb_read_txfifosz(void __iomem *mbase)
@ -365,7 +449,11 @@ static inline u16 musb_read_rxfifoadd(void __iomem *mbase)
static inline u8 musb_read_ulpi_buscontrol(void __iomem *mbase)
{
#ifdef CONFIG_ARCH_SUNXI /* No ulpi on sunxi */
return 0;
#else
return musb_readb(mbase, MUSB_ULPI_BUSCONTROL);
#endif
}
static inline u8 musb_read_configdata(void __iomem *mbase)
@ -376,7 +464,11 @@ static inline u8 musb_read_configdata(void __iomem *mbase)
static inline u16 musb_read_hwvers(void __iomem *mbase)
{
#ifdef CONFIG_ARCH_SUNXI
return 0; /* Unknown version */
#else
return musb_readw(mbase, MUSB_HWVERS);
#endif
}
static inline void __iomem *musb_read_target_reg_base(u8 i, void __iomem *mbase)

View file

@ -12,6 +12,11 @@
#include "musb_gadget.h"
#ifdef CONFIG_MUSB_HOST
struct int_queue {
struct usb_host_endpoint hep;
struct urb urb;
};
static struct musb *host;
static struct usb_hcd hcd;
static enum usb_device_speed host_speed;
@ -25,45 +30,42 @@ static void musb_host_complete_urb(struct urb *urb)
static struct usb_host_endpoint hep;
static struct urb urb;
static struct urb *construct_urb(struct usb_device *dev, int endpoint_type,
unsigned long pipe, void *buffer, int len,
struct devrequest *setup, int interval)
static void construct_urb(struct urb *urb, struct usb_host_endpoint *hep,
struct usb_device *dev, int endpoint_type,
unsigned long pipe, void *buffer, int len,
struct devrequest *setup, int interval)
{
int epnum = usb_pipeendpoint(pipe);
int is_in = usb_pipein(pipe);
memset(&urb, 0, sizeof(struct urb));
memset(&hep, 0, sizeof(struct usb_host_endpoint));
INIT_LIST_HEAD(&hep.urb_list);
INIT_LIST_HEAD(&urb.urb_list);
urb.ep = &hep;
urb.complete = musb_host_complete_urb;
urb.status = -EINPROGRESS;
urb.dev = dev;
urb.pipe = pipe;
urb.transfer_buffer = buffer;
urb.transfer_dma = (unsigned long)buffer;
urb.transfer_buffer_length = len;
urb.setup_packet = (unsigned char *)setup;
memset(urb, 0, sizeof(struct urb));
memset(hep, 0, sizeof(struct usb_host_endpoint));
INIT_LIST_HEAD(&hep->urb_list);
INIT_LIST_HEAD(&urb->urb_list);
urb->ep = hep;
urb->complete = musb_host_complete_urb;
urb->status = -EINPROGRESS;
urb->dev = dev;
urb->pipe = pipe;
urb->transfer_buffer = buffer;
urb->transfer_dma = (unsigned long)buffer;
urb->transfer_buffer_length = len;
urb->setup_packet = (unsigned char *)setup;
urb.ep->desc.wMaxPacketSize =
urb->ep->desc.wMaxPacketSize =
__cpu_to_le16(is_in ? dev->epmaxpacketin[epnum] :
dev->epmaxpacketout[epnum]);
urb.ep->desc.bmAttributes = endpoint_type;
urb.ep->desc.bEndpointAddress =
urb->ep->desc.bmAttributes = endpoint_type;
urb->ep->desc.bEndpointAddress =
(is_in ? USB_DIR_IN : USB_DIR_OUT) | epnum;
urb.ep->desc.bInterval = interval;
return &urb;
urb->ep->desc.bInterval = interval;
}
#define MUSB_HOST_TIMEOUT 0x3ffffff
static int submit_urb(struct usb_hcd *hcd, struct urb *urb)
{
struct musb *host = hcd->hcd_priv;
int ret;
int timeout;
unsigned long timeout;
ret = musb_urb_enqueue(hcd, urb, 0);
if (ret < 0) {
@ -71,12 +73,16 @@ static int submit_urb(struct usb_hcd *hcd, struct urb *urb)
return ret;
}
timeout = MUSB_HOST_TIMEOUT;
timeout = get_timer(0) + USB_TIMEOUT_MS(urb->pipe);
do {
if (ctrlc())
return -EIO;
host->isr(0, host);
} while ((urb->dev->status & USB_ST_NOT_PROC) && --timeout);
} while (urb->status == -EINPROGRESS &&
get_timer(0) < timeout);
if (urb->status == -EINPROGRESS)
musb_urb_dequeue(hcd, urb, -ETIME);
return urb->status;
}
@ -84,38 +90,117 @@ static int submit_urb(struct usb_hcd *hcd, struct urb *urb)
int submit_control_msg(struct usb_device *dev, unsigned long pipe,
void *buffer, int len, struct devrequest *setup)
{
struct urb *urb = construct_urb(dev, USB_ENDPOINT_XFER_CONTROL, pipe,
buffer, len, setup, 0);
construct_urb(&urb, &hep, dev, USB_ENDPOINT_XFER_CONTROL, pipe,
buffer, len, setup, 0);
/* Fix speed for non hub-attached devices */
if (!dev->parent)
dev->speed = host_speed;
return submit_urb(&hcd, urb);
return submit_urb(&hcd, &urb);
}
int submit_bulk_msg(struct usb_device *dev, unsigned long pipe,
void *buffer, int len)
{
struct urb *urb = construct_urb(dev, USB_ENDPOINT_XFER_BULK, pipe,
buffer, len, NULL, 0);
return submit_urb(&hcd, urb);
construct_urb(&urb, &hep, dev, USB_ENDPOINT_XFER_BULK, pipe,
buffer, len, NULL, 0);
return submit_urb(&hcd, &urb);
}
int submit_int_msg(struct usb_device *dev, unsigned long pipe,
void *buffer, int len, int interval)
{
struct urb *urb = construct_urb(dev, USB_ENDPOINT_XFER_INT, pipe,
buffer, len, NULL, interval);
return submit_urb(&hcd, urb);
construct_urb(&urb, &hep, dev, USB_ENDPOINT_XFER_INT, pipe,
buffer, len, NULL, interval);
return submit_urb(&hcd, &urb);
}
struct int_queue *create_int_queue(struct usb_device *dev, unsigned long pipe,
int queuesize, int elementsize, void *buffer, int interval)
{
struct int_queue *queue;
int ret, index = usb_pipein(pipe) * 16 + usb_pipeendpoint(pipe);
if (queuesize != 1) {
printf("ERROR musb int-queues only support queuesize 1\n");
return NULL;
}
if (dev->int_pending & (1 << index)) {
printf("ERROR int-urb is already pending on pipe %lx\n", pipe);
return NULL;
}
queue = malloc(sizeof(*queue));
if (!queue)
return NULL;
construct_urb(&queue->urb, &queue->hep, dev, USB_ENDPOINT_XFER_INT,
pipe, buffer, elementsize, NULL, interval);
ret = musb_urb_enqueue(&hcd, &queue->urb, 0);
if (ret < 0) {
printf("Failed to enqueue URB to controller\n");
free(queue);
return NULL;
}
dev->int_pending |= 1 << index;
return queue;
}
int destroy_int_queue(struct usb_device *dev, struct int_queue *queue)
{
int index = usb_pipein(queue->urb.pipe) * 16 +
usb_pipeendpoint(queue->urb.pipe);
if (queue->urb.status == -EINPROGRESS)
musb_urb_dequeue(&hcd, &queue->urb, -ETIME);
dev->int_pending &= ~(1 << index);
free(queue);
return 0;
}
void *poll_int_queue(struct usb_device *dev, struct int_queue *queue)
{
if (queue->urb.status != -EINPROGRESS)
return NULL; /* URB has already completed in a prev. poll */
host->isr(0, host);
if (queue->urb.status != -EINPROGRESS)
return queue->urb.transfer_buffer; /* Done */
return NULL; /* URB still pending */
}
void usb_reset_root_port(void)
{
void *mbase = host->mregs;
u8 power;
power = musb_readb(mbase, MUSB_POWER);
power &= 0xf0;
musb_writeb(mbase, MUSB_POWER, MUSB_POWER_RESET | power);
mdelay(50);
power = musb_readb(mbase, MUSB_POWER);
musb_writeb(mbase, MUSB_POWER, ~MUSB_POWER_RESET & power);
host->isr(0, host);
host_speed = (musb_readb(mbase, MUSB_POWER) & MUSB_POWER_HSMODE) ?
USB_SPEED_HIGH :
(musb_readb(mbase, MUSB_DEVCTL) & MUSB_DEVCTL_FSDEV) ?
USB_SPEED_FULL : USB_SPEED_LOW;
mdelay((host_speed == USB_SPEED_LOW) ? 200 : 50);
}
int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
{
u8 power;
void *mbase;
int timeout = MUSB_HOST_TIMEOUT;
/* USB spec says it may take up to 1 second for a device to connect */
unsigned long timeout = get_timer(0) + 1000;
if (!host) {
printf("MUSB host is not registered\n");
@ -127,20 +212,11 @@ int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
do {
if (musb_readb(mbase, MUSB_DEVCTL) & MUSB_DEVCTL_HM)
break;
} while (--timeout);
if (!timeout)
} while (get_timer(0) < timeout);
if (get_timer(0) >= timeout)
return -ENODEV;
power = musb_readb(mbase, MUSB_POWER);
musb_writeb(mbase, MUSB_POWER, MUSB_POWER_RESET | power);
udelay(30000);
power = musb_readb(mbase, MUSB_POWER);
musb_writeb(mbase, MUSB_POWER, ~MUSB_POWER_RESET & power);
host->isr(0, host);
host_speed = (musb_readb(mbase, MUSB_POWER) & MUSB_POWER_HSMODE) ?
USB_SPEED_HIGH :
(musb_readb(mbase, MUSB_DEVCTL) & MUSB_DEVCTL_FSDEV) ?
USB_SPEED_FULL : USB_SPEED_LOW;
usb_reset_root_port();
host->is_active = 1;
hcd.hcd_priv = host;

View file

@ -0,0 +1,279 @@
/*
* Allwinner SUNXI "glue layer"
*
* Copyright © 2015 Hans de Goede <hdegoede@redhat.com>
* Copyright © 2013 Jussi Kivilinna <jussi.kivilinna@iki.fi>
*
* Based on the sw_usb "Allwinner OTG Dual Role Controller" code.
* Copyright 2007-2012 (C) Allwinner Technology Co., Ltd.
* javen <javen@allwinnertech.com>
*
* Based on the DA8xx "glue layer" code.
* Copyright (c) 2008-2009 MontaVista Software, Inc. <source@mvista.com>
* Copyright (C) 2005-2006 by Texas Instruments
*
* This file is part of the Inventra Controller Driver for Linux.
*
* The Inventra Controller Driver for Linux is free software; you
* can redistribute it and/or modify it under the terms of the GNU
* General Public License version 2 as published by the Free Software
* Foundation.
*
*/
#include <common.h>
#include <asm/arch/cpu.h>
#include <asm/arch/usbc.h>
#include "linux-compat.h"
#include "musb_core.h"
/******************************************************************************
******************************************************************************
* From the Allwinner driver
******************************************************************************
******************************************************************************/
/******************************************************************************
* From include/sunxi_usb_bsp.h
******************************************************************************/
/* reg offsets */
#define USBC_REG_o_ISCR 0x0400
#define USBC_REG_o_PHYCTL 0x0404
#define USBC_REG_o_PHYBIST 0x0408
#define USBC_REG_o_PHYTUNE 0x040c
#define USBC_REG_o_VEND0 0x0043
/* Interface Status and Control */
#define USBC_BP_ISCR_VBUS_VALID_FROM_DATA 30
#define USBC_BP_ISCR_VBUS_VALID_FROM_VBUS 29
#define USBC_BP_ISCR_EXT_ID_STATUS 28
#define USBC_BP_ISCR_EXT_DM_STATUS 27
#define USBC_BP_ISCR_EXT_DP_STATUS 26
#define USBC_BP_ISCR_MERGED_VBUS_STATUS 25
#define USBC_BP_ISCR_MERGED_ID_STATUS 24
#define USBC_BP_ISCR_ID_PULLUP_EN 17
#define USBC_BP_ISCR_DPDM_PULLUP_EN 16
#define USBC_BP_ISCR_FORCE_ID 14
#define USBC_BP_ISCR_FORCE_VBUS_VALID 12
#define USBC_BP_ISCR_VBUS_VALID_SRC 10
#define USBC_BP_ISCR_HOSC_EN 7
#define USBC_BP_ISCR_VBUS_CHANGE_DETECT 6
#define USBC_BP_ISCR_ID_CHANGE_DETECT 5
#define USBC_BP_ISCR_DPDM_CHANGE_DETECT 4
#define USBC_BP_ISCR_IRQ_ENABLE 3
#define USBC_BP_ISCR_VBUS_CHANGE_DETECT_EN 2
#define USBC_BP_ISCR_ID_CHANGE_DETECT_EN 1
#define USBC_BP_ISCR_DPDM_CHANGE_DETECT_EN 0
/******************************************************************************
* From usbc/usbc.c
******************************************************************************/
static u32 USBC_WakeUp_ClearChangeDetect(u32 reg_val)
{
u32 temp = reg_val;
temp &= ~(1 << USBC_BP_ISCR_VBUS_CHANGE_DETECT);
temp &= ~(1 << USBC_BP_ISCR_ID_CHANGE_DETECT);
temp &= ~(1 << USBC_BP_ISCR_DPDM_CHANGE_DETECT);
return temp;
}
static void USBC_EnableIdPullUp(__iomem void *base)
{
u32 reg_val;
reg_val = musb_readl(base, USBC_REG_o_ISCR);
reg_val |= (1 << USBC_BP_ISCR_ID_PULLUP_EN);
reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
musb_writel(base, USBC_REG_o_ISCR, reg_val);
}
static void USBC_DisableIdPullUp(__iomem void *base)
{
u32 reg_val;
reg_val = musb_readl(base, USBC_REG_o_ISCR);
reg_val &= ~(1 << USBC_BP_ISCR_ID_PULLUP_EN);
reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
musb_writel(base, USBC_REG_o_ISCR, reg_val);
}
static void USBC_EnableDpDmPullUp(__iomem void *base)
{
u32 reg_val;
reg_val = musb_readl(base, USBC_REG_o_ISCR);
reg_val |= (1 << USBC_BP_ISCR_DPDM_PULLUP_EN);
reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
musb_writel(base, USBC_REG_o_ISCR, reg_val);
}
static void USBC_DisableDpDmPullUp(__iomem void *base)
{
u32 reg_val;
reg_val = musb_readl(base, USBC_REG_o_ISCR);
reg_val &= ~(1 << USBC_BP_ISCR_DPDM_PULLUP_EN);
reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
musb_writel(base, USBC_REG_o_ISCR, reg_val);
}
static void USBC_ForceIdToLow(__iomem void *base)
{
u32 reg_val;
reg_val = musb_readl(base, USBC_REG_o_ISCR);
reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_ID);
reg_val |= (0x02 << USBC_BP_ISCR_FORCE_ID);
reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
musb_writel(base, USBC_REG_o_ISCR, reg_val);
}
static void USBC_ForceIdToHigh(__iomem void *base)
{
u32 reg_val;
reg_val = musb_readl(base, USBC_REG_o_ISCR);
reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_ID);
reg_val |= (0x03 << USBC_BP_ISCR_FORCE_ID);
reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
musb_writel(base, USBC_REG_o_ISCR, reg_val);
}
static void USBC_ForceVbusValidDisable(__iomem void *base)
{
u32 reg_val;
reg_val = musb_readl(base, USBC_REG_o_ISCR);
reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_VBUS_VALID);
reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
musb_writel(base, USBC_REG_o_ISCR, reg_val);
}
static void USBC_ForceVbusValidToHigh(__iomem void *base)
{
u32 reg_val;
reg_val = musb_readl(base, USBC_REG_o_ISCR);
reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_VBUS_VALID);
reg_val |= (0x03 << USBC_BP_ISCR_FORCE_VBUS_VALID);
reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
musb_writel(base, USBC_REG_o_ISCR, reg_val);
}
static void USBC_ConfigFIFO_Base(void)
{
u32 reg_value;
/* config usb fifo, 8kb mode */
reg_value = readl(SUNXI_SRAMC_BASE + 0x04);
reg_value &= ~(0x03 << 0);
reg_value |= (1 << 0);
writel(reg_value, SUNXI_SRAMC_BASE + 0x04);
}
/******************************************************************************
* MUSB Glue code
******************************************************************************/
static irqreturn_t sunxi_musb_interrupt(int irq, void *__hci)
{
struct musb *musb = __hci;
irqreturn_t retval = IRQ_NONE;
/* read and flush interrupts */
musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB);
if (musb->int_usb)
musb_writeb(musb->mregs, MUSB_INTRUSB, musb->int_usb);
musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX);
if (musb->int_tx)
musb_writew(musb->mregs, MUSB_INTRTX, musb->int_tx);
musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX);
if (musb->int_rx)
musb_writew(musb->mregs, MUSB_INTRRX, musb->int_rx);
if (musb->int_usb || musb->int_tx || musb->int_rx)
retval |= musb_interrupt(musb);
return retval;
}
static void sunxi_musb_enable(struct musb *musb)
{
pr_debug("%s():\n", __func__);
/* select PIO mode */
musb_writeb(musb->mregs, USBC_REG_o_VEND0, 0);
if (is_host_enabled(musb)) {
/* port power on */
sunxi_usbc_vbus_enable(0);
}
}
static void sunxi_musb_disable(struct musb *musb)
{
pr_debug("%s():\n", __func__);
/* Put the controller back in a pristane state for "usb reset" */
if (musb->is_active) {
sunxi_usbc_disable(0);
sunxi_usbc_enable(0);
musb->is_active = 0;
}
}
static int sunxi_musb_init(struct musb *musb)
{
int err;
pr_debug("%s():\n", __func__);
err = sunxi_usbc_request_resources(0);
if (err)
return err;
musb->isr = sunxi_musb_interrupt;
sunxi_usbc_enable(0);
USBC_ConfigFIFO_Base();
USBC_EnableDpDmPullUp(musb->mregs);
USBC_EnableIdPullUp(musb->mregs);
if (is_host_enabled(musb)) {
/* Host mode */
USBC_ForceIdToLow(musb->mregs);
USBC_ForceVbusValidToHigh(musb->mregs);
} else {
/* Peripheral mode */
USBC_ForceIdToHigh(musb->mregs);
USBC_ForceVbusValidDisable(musb->mregs);
}
return 0;
}
static int sunxi_musb_exit(struct musb *musb)
{
pr_debug("%s():\n", __func__);
USBC_DisableDpDmPullUp(musb->mregs);
USBC_DisableIdPullUp(musb->mregs);
sunxi_usbc_vbus_disable(0);
sunxi_usbc_disable(0);
return sunxi_usbc_free_resources(0);
}
const struct musb_platform_ops sunxi_musb_ops = {
.init = sunxi_musb_init,
.exit = sunxi_musb_exit,
.enable = sunxi_musb_enable,
.disable = sunxi_musb_disable,
};

View file

@ -48,6 +48,7 @@ struct urb {
list_add_tail(&urb->urb_list, &urb->ep->urb_list); \
ret; })
#define usb_hcd_unlink_urb_from_ep(hcd, urb) list_del_init(&urb->urb_list)
#define usb_hcd_check_unlink_urb(hdc, urb, status) 0
static inline void usb_hcd_giveback_urb(struct usb_hcd *hcd,
struct urb *urb,

View file

@ -90,15 +90,8 @@
#endif
#ifdef CONFIG_CMD_USB
#define BOOTENV_RUN_USB_INIT "run usb_init; "
#define BOOTENV_SET_USB_NEED_INIT "setenv usb_need_init; "
#define BOOTENV_RUN_USB_INIT "usb start; "
#define BOOTENV_SHARED_USB \
"usb_init=" \
"if ${usb_need_init}; then " \
"setenv usb_need_init false; " \
"usb start 0; " \
"fi\0" \
\
"usb_boot=" \
BOOTENV_RUN_USB_INIT \
BOOTENV_SHARED_BLKDEV_BODY(usb)
@ -106,7 +99,6 @@
#define BOOTENV_DEV_NAME_USB BOOTENV_DEV_NAME_BLKDEV
#else
#define BOOTENV_RUN_USB_INIT
#define BOOTENV_SET_USB_NEED_INIT
#define BOOTENV_SHARED_USB
#define BOOTENV_DEV_USB \
BOOT_TARGET_DEVICES_references_USB_without_CONFIG_CMD_USB
@ -202,7 +194,7 @@
\
BOOT_TARGET_DEVICES(BOOTENV_DEV) \
\
"bootcmd=" BOOTENV_SET_USB_NEED_INIT BOOTENV_SET_SCSI_NEED_INIT \
"bootcmd=" BOOTENV_SET_SCSI_NEED_INIT \
"for target in ${boot_targets}; do " \
"run bootcmd_${target}; " \
"done\0"

View file

@ -120,6 +120,7 @@ struct usb_device {
* Each instance needs its own set of data structures.
*/
unsigned long status;
unsigned long int_pending; /* 1 bit per ep, used by int_queue */
int act_len; /* transfered bytes */
int maxchild; /* Number of ports if hub */
int portnr;
@ -154,11 +155,16 @@ enum usb_init_type {
defined(CONFIG_USB_OMAP3) || defined(CONFIG_USB_DA8XX) || \
defined(CONFIG_USB_BLACKFIN) || defined(CONFIG_USB_AM35X) || \
defined(CONFIG_USB_MUSB_DSPS) || defined(CONFIG_USB_MUSB_AM35X) || \
defined(CONFIG_USB_MUSB_OMAP2PLUS) || defined(CONFIG_USB_XHCI) || \
defined(CONFIG_USB_DWC2)
defined(CONFIG_USB_MUSB_OMAP2PLUS) || defined(CONFIG_USB_MUSB_SUNXI) || \
defined(CONFIG_USB_XHCI) || defined(CONFIG_USB_DWC2)
int usb_lowlevel_init(int index, enum usb_init_type init, void **controller);
int usb_lowlevel_stop(int index);
#ifdef CONFIG_MUSB_HOST
void usb_reset_root_port(void);
#else
#define usb_reset_root_port()
#endif
int submit_bulk_msg(struct usb_device *dev, unsigned long pipe,
void *buffer, int transfer_len);
@ -167,9 +173,9 @@ int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
int transfer_len, int interval);
#ifdef CONFIG_USB_EHCI /* Only the ehci code has pollable int support */
#if defined CONFIG_USB_EHCI || defined CONFIG_MUSB_HOST
struct int_queue *create_int_queue(struct usb_device *dev, unsigned long pipe,
int queuesize, int elementsize, void *buffer);
int queuesize, int elementsize, void *buffer, int interval);
int destroy_int_queue(struct usb_device *dev, struct int_queue *queue);
void *poll_int_queue(struct usb_device *dev, struct int_queue *queue);
#endif