diff -uprN omap3-dev/drivers/serial/usbtty.h omap3-dev-usb/drivers/serial/usbtty.h --- omap3-dev/drivers/serial/usbtty.h 2009-02-01 19:17:13.000000000 +0100 +++ omap3-dev-usb/drivers/serial/usbtty.h 2009-02-01 19:17:43.000000000 +0100 @@ -27,8 +27,10 @@ #include #if defined(CONFIG_PPC) #include -#elif defined(CONFIG_ARM) +#elif defined(CONFIG_OMAP1510) #include +#elif defined(CONFIG_MUSB) +#include #endif #include diff -uprN omap3-dev/drivers/usb/Makefile omap3-dev-usb/drivers/usb/Makefile --- omap3-dev/drivers/usb/Makefile 2009-02-01 19:17:13.000000000 +0100 +++ omap3-dev-usb/drivers/usb/Makefile 2009-02-01 19:17:43.000000000 +0100 @@ -40,6 +40,7 @@ COBJS-$(CONFIG_USB_EHCI_IXP4XX) += usb_e COBJS-$(CONFIG_MUSB_HCD) += musb_hcd.o musb_core.o COBJS-$(CONFIG_USB_DAVINCI) += davinci_usb.o COBJS-$(CONFIG_USB_EHCI_VCT) += usb_ehci_vct.o +COBJS-$(CONFIG_USB_OMAP3530) += omap3530_usb.o # device ifdef CONFIG_USB_DEVICE @@ -47,6 +48,8 @@ COBJS-y += usbdcore_ep0.o COBJS-$(CONFIG_OMAP1510) += usbdcore_omap1510.o COBJS-$(CONFIG_OMAP1610) += usbdcore_omap1510.o COBJS-$(CONFIG_MPC885_FAMILY) += usbdcore_mpc8xx.o +COBJS-$(CONFIG_MUSB) += usbdcore_musb.o +COBJS-$(CONFIG_TWL4030_USB) += twl4030-usb.o endif COBJS := $(COBJS-y) diff -uprN omap3-dev/drivers/usb/omap3530_usb.c omap3-dev-usb/drivers/usb/omap3530_usb.c --- omap3-dev/drivers/usb/omap3530_usb.c 1970-01-01 01:00:00.000000000 +0100 +++ omap3-dev-usb/drivers/usb/omap3530_usb.c 2009-02-01 19:17:43.000000000 +0100 @@ -0,0 +1,66 @@ +/* + * TI's OMAP3530 platform specific USB functions. + * + * Copyright (c) 2008 Texas Instruments + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments + */ + +#include + +#include "omap3530_usb.h" +#include +#include +#include + +/* MUSB platform configuration */ +struct musb_config musb_cfg = { + (struct musb_regs *)MENTOR_USB0_BASE, + OMAP3530_USB_TIMEOUT, + 0 +}; + +/* MUSB module register overlay */ +struct omap3530_usb_regs *regs; + +/* + * This function performs OMAP3530 platform specific initialization for Mentor + * USB OTG controller. + */ +int musb_platform_init(void) +{ + regs = (struct omap3530_usb_regs *)OMAP3530_USB0_BASE; + /* Disable force standby */ + sr32((void *)®s->forcestdby, 0 , 1 , 0); + /* Set configuration for clock and interface clock to be always on */ + writel(0x1008, ®s->sysconfig); + /* Configure the PHY as PHY interface is 12-pin, 8-bit SDR ULPI */ + sr32((void *)®s->interfsel, 0, 1, 1); + return 0; +} + +/* + * This function performs OMAP3530 platform specific deinitialization for + * Mentor USB OTG controller. + */ +void musb_platform_deinit(void) +{ + /* MUSB soft-reset */ + writel(2, ®s->sysconfig); +} + diff -uprN omap3-dev/drivers/usb/omap3530_usb.h omap3-dev-usb/drivers/usb/omap3530_usb.h --- omap3-dev/drivers/usb/omap3530_usb.h 1970-01-01 01:00:00.000000000 +0100 +++ omap3-dev-usb/drivers/usb/omap3530_usb.h 2009-02-01 19:17:43.000000000 +0100 @@ -0,0 +1,49 @@ +/* + * TI's OMAP3530 platform specific USB functions. + * + * Copyright (c) 2008 Texas Instruments + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments + */ + +#ifndef __OMAP3530_MUSB_H__ +#define __OMAP3530_MUSB_H__ + +#include "musb_core.h" + +/* Base address of OMAP3530 usb0 wrapper */ +#define OMAP3530_USB0_BASE 0x480AB400 +/* Base address of OMAP3530 musb core */ +#define MENTOR_USB0_BASE 0x480AB000 +/* Timeout for OMAP3530 USB module */ +#define OMAP3530_USB_TIMEOUT 0x3FFFFFF + +/* + * OMAP3530 platform USB register overlay. + */ +struct omap3530_usb_regs { + u32 revision; + u32 sysconfig; + u32 sysstatus; + u32 interfsel; + u32 simenable; + u32 forcestdby; +}; + +#endif /* __OMAP3530_MUSB_H__ */ + diff -uprN omap3-dev/drivers/usb/twl4030-usb.c omap3-dev-usb/drivers/usb/twl4030-usb.c --- omap3-dev/drivers/usb/twl4030-usb.c 1970-01-01 01:00:00.000000000 +0100 +++ omap3-dev-usb/drivers/usb/twl4030-usb.c 2009-02-01 19:17:43.000000000 +0100 @@ -0,0 +1,169 @@ +/* + * twl4030-usb - TWL4030 USB transceiver, talking to OMAP OTG controller + * + * (C) Copyright 2008 Atin Malaviya (atin.malaviya@gmail.com) + * + * Based on: twl4030-usb.c in linux 2.6 (drivers/i2c/chips/twl4030-usb.c) + * Copyright (C) 2004-2007 Texas Instruments + * Copyright (C) 2008 Nokia Corporation + * Contact: Felipe Balbi + * + * Author: Atin Malaviya (atin.malaviya@gmail.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include + +#define FUNC_CTRL (0x04) +# define OPMODE_MASK (3 << 3) /* bits 3 and 4 */ +# define XCVRSELECT_MASK (3 << 0) /* bits 0 and 1 */ +#define IFC_CTRL (0x07) +# define CARKITMODE (1 << 2) +#define POWER_CTRL (0xAC) +# define OTG_ENAB (1 << 5) +#define PHY_PWR_CTRL (0xFD) +# define PHYPWD (1 << 0) +#define PHY_CLK_CTRL (0xFE) +# define CLOCKGATING_EN (1 << 2) +# define CLK32K_EN (1 << 1) +# define REQ_PHY_DPLL_CLK (1 << 0) +#define PHY_CLK_CTRL_STS (0xFF) +# define PHY_DPLL_CLK (1 << 0) + +static int twl4030_i2c_write(u8 group, u8 reg, u8 data) +{ + int ret = 0; + ret = i2c_write(group, reg, 1, &data, 1); + if (ret != 0) { + serial_printf("TWL4030:I2C:Write[0x%x, 0x%x] Error %d\n", group, reg, ret); + } + return ret; +} + +static int twl4030_i2c_read(u8 group, u8 reg, u8 *data) +{ + int ret = 0; + ret = i2c_read(group, reg, 1, data, 1); + if (ret != 0) { + serial_printf("TWL4030:I2C:Read[0x%x, 0x%x] Error %d\n", group, reg, ret); + } + return ret; +} + +static int twl4030_usb_write(u8 address, u8 data) +{ + int ret = 0; + ret = twl4030_i2c_write(PWRMGT_ADDR_ID1, address, data); + if (ret != 0) { + serial_printf("TWL4030:USB:Write[0x%x] Error %d\n", address, ret); + } + return ret; +} + +static int twl4030_usb_read(u8 address) +{ + u8 data; + int ret = 0; + ret = twl4030_i2c_read(PWRMGT_ADDR_ID1, address, &data); + if (ret == 0) { + ret = data; + } else { + serial_printf("TWL4030:USB:Read[0x%x] Error %d\n", address, ret); + } + return ret; +} + +static int twl4030_usb_set_bits(u8 reg, u8 bits) +{ + return twl4030_usb_write(reg + 1, bits); +} + +static int twl4030_usb_clear_bits(u8 reg, u8 bits) +{ + return twl4030_usb_write(reg + 2, bits); +} + +static void twl4030_usb_ldo_init(void) +{ + /* Enable writing to power configuration registers */ + twl4030_i2c_write(PWRMGT_ADDR_ID4, PROTECT_KEY, 0xC0); + twl4030_i2c_write(PWRMGT_ADDR_ID4, PROTECT_KEY, 0x0C); + + /* put VUSB3V1 LDO in active state */ + twl4030_i2c_write(PWRMGT_ADDR_ID4, VUSB_DEDICATED2, 0); + + /* input to VUSB3V1 LDO is from VBAT, not VBUS */ + twl4030_i2c_write(PWRMGT_ADDR_ID4, VUSB_DEDICATED1, 0x14); + + /* turn on 3.1V regulator */ + twl4030_i2c_write(PWRMGT_ADDR_ID4, VUSB3V1_DEV_GRP, 0x20); + twl4030_i2c_write(PWRMGT_ADDR_ID4, VUSB3V1_TYPE, 0); + + /* turn on 1.5V regulator */ + twl4030_i2c_write(PWRMGT_ADDR_ID4, VUSB1V5_DEV_GRP, 0x20); + twl4030_i2c_write(PWRMGT_ADDR_ID4, VUSB1V5_TYPE, 0); + + /* turn on 1.8V regulator */ + twl4030_i2c_write(PWRMGT_ADDR_ID4, VUSB1V8_DEV_GRP, 0x20); + twl4030_i2c_write(PWRMGT_ADDR_ID4, VUSB1V8_TYPE, 0); + + /* disable access to power configuration registers */ + twl4030_i2c_write(PWRMGT_ADDR_ID4, PROTECT_KEY, 0); +} + +static void twl4030_phy_power(void) +{ + u8 pwr; + + pwr = twl4030_usb_read(PHY_PWR_CTRL); + pwr &= ~PHYPWD; + twl4030_usb_write(PHY_PWR_CTRL, pwr); + twl4030_usb_write(PHY_CLK_CTRL, + twl4030_usb_read(PHY_CLK_CTRL) | + (CLOCKGATING_EN | CLK32K_EN)); +} + +int udc_musb_platform_init(void) +{ + unsigned long timeout; + + /* twl4030 ldo init */ + twl4030_usb_ldo_init(); + + /* Enable the twl4030 phy */ + twl4030_phy_power(); + + /* enable DPLL to access PHY registers over I2C */ + twl4030_usb_write(PHY_CLK_CTRL,twl4030_usb_read(PHY_CLK_CTRL) | REQ_PHY_DPLL_CLK); + timeout = get_timer(0) + CONFIG_SYS_HZ; + while (!(twl4030_usb_read(PHY_CLK_CTRL_STS) & PHY_DPLL_CLK) && get_timer(0) < timeout) { + udelay(10); + } + if (!(twl4030_usb_read(PHY_CLK_CTRL_STS) & PHY_DPLL_CLK)) { + serial_printf("Timeout setting T2 HSUSB PHY DPLL clock\n"); + return -1; + } + + /* Enable ULPI mode */ + twl4030_usb_clear_bits(IFC_CTRL, CARKITMODE); + twl4030_usb_set_bits(POWER_CTRL, OTG_ENAB); + twl4030_usb_clear_bits(FUNC_CTRL,XCVRSELECT_MASK | OPMODE_MASK); + /* let ULPI control the DPLL clock */ + twl4030_usb_write(PHY_CLK_CTRL,twl4030_usb_read(PHY_CLK_CTRL) & ~REQ_PHY_DPLL_CLK); + return 0; +} diff -uprN omap3-dev/drivers/usb/usbdcore_musb.c omap3-dev-usb/drivers/usb/usbdcore_musb.c --- omap3-dev/drivers/usb/usbdcore_musb.c 1970-01-01 01:00:00.000000000 +0100 +++ omap3-dev-usb/drivers/usb/usbdcore_musb.c 2009-02-01 19:17:43.000000000 +0100 @@ -0,0 +1,732 @@ +/* + * (C) Copyright 2008 Texas Instruments Incorporated. + * + * Based on + * u-boot OMAP1510 USB drivers (drivers/usbdcore_omap1510.c) + * twl4030 init based on linux (drivers/i2c/chips/twl4030-usb.c) + * + * Author: Diego Dompe (diego.dompe@ridgerun.com) + * Atin Malaviya (atin.malaviya@gmail.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include + +#include +#include +#include +#include +#include "usbdcore.h" +#include "usbdcore_musb.h" +#include "usbdcore_ep0.h" + +/* Private definitions */ +enum ep0_status { IDLE, DATA_STAGE, DATA_COMPLETE }; + +/* Private variables */ +static struct usb_device_instance *udc_device; +static enum ep0_status ep0status = IDLE; +static unsigned char do_set_address = 0; +static struct urb *ep0_urb = NULL; + +/* Helper functions */ +/** TODO: Should these go in include/usbdcore.h?? */ +static void insl(u32 reg, u32 * data, u32 size) +{ + u32 t; + + for (t = 0; t < size; t++, data++){ + *data = inl(reg); + } +} + +static void outsl(u32 reg, u32 * data, u32 size) +{ + u32 t; + + for (t = 0; t < size; t++, data++) + outl(*data, reg); +} + +static void outsb(u32 reg, u8 * data, u32 size) +{ + u32 t; + + for (t = 0; t < size; t++, data++) + outb(*data, reg); +} + +static void musb_fifo_read(int epnumber, u8 * data, u32 size) +{ + if ((u32)data & 0x3) { /* Not aligned data */ + insb((UDC_FIFO0 + (epnumber << 2)), data, size); + } else { /* 32 bits aligned data */ + int i; + + insl(UDC_FIFO0 + (epnumber << 2),(u32 *)data,size>>2); + data += size & ~0x3; + i = size & 0x3; + while (i--) { + *data = inb(UDC_FIFO0 + (epnumber << 2)); + data++; + } + } +} + +static void musb_fifo_write(int epnumber, u8 * data, u32 size) +{ + if ((u32)data & 0x3) { /* Not aligned data */ + outsb(UDC_FIFO0 + (epnumber << 2), data, size); + } else { /* 32 bits aligned data */ + int i; + + outsl(UDC_FIFO0 + (epnumber << 2), (u32 *)data, size>>2); + data += size & ~0x3; + i = size & 0x3; + while (i--) { + outb(*data, UDC_FIFO0 + (epnumber << 2)); + data++; + } + } +} + +static void musb_fifos_configure(struct usb_device_instance *device) +{ + int ep; + struct usb_bus_instance *bus; + struct usb_endpoint_instance *endpoint; + unsigned short ep_ptr, ep_size, ep_doublebuffer; + int ep_addr, packet_size, buffer_size, attributes; + + bus = device->bus; + + ep_ptr = 0; + + for (ep = 0; ep < bus->max_endpoints; ep++) { + endpoint = bus->endpoint_array + ep; + ep_addr = endpoint->endpoint_address; + if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { + /* IN endpoint */ + packet_size = endpoint->tx_packetSize; + attributes = endpoint->tx_attributes; + } else { + /* OUT endpoint */ + packet_size = endpoint->rcv_packetSize; + attributes = endpoint->rcv_attributes; + } + + switch (packet_size) { + case 0: + ep_size = 0; + break; + case 8: + ep_size = 0; + break; + case 16: + ep_size = 1; + break; + case 32: + ep_size = 2; + break; + case 64: + ep_size = 3; + break; + case 128: + ep_size = 4; + break; + case 256: + ep_size = 5; + break; + case 512: + ep_size = 6; + break; + default: + serial_printf("ep 0x%02x has bad packet size %d", + ep_addr, packet_size); + packet_size = 0; + ep_size = 0; + break; + } + + switch (attributes & USB_ENDPOINT_XFERTYPE_MASK) { + case USB_ENDPOINT_XFER_CONTROL: + case USB_ENDPOINT_XFER_BULK: + case USB_ENDPOINT_XFER_INT: + default: + /* A non-isochronous endpoint may optionally be + * double-buffered. For now we disable + * double-buffering. + */ + ep_doublebuffer = 0; + if (packet_size > 64) + packet_size = 0; + if (!ep || !ep_doublebuffer) + buffer_size = packet_size; + else + buffer_size = packet_size * 2; + break; + case USB_ENDPOINT_XFER_ISOC: + /* Isochronous endpoints are always double- + * buffered + */ + ep_doublebuffer = 1; + buffer_size = packet_size * 2; + break; + } + + /* check to see if our packet buffer RAM is exhausted */ + if ((ep_ptr + buffer_size) > UDC_MAX_FIFO_SIZE) { + serial_printf("out of packet RAM for ep 0x%02x buf size %d", + ep_addr, buffer_size); + buffer_size = packet_size = 0; + } + + /* force a default configuration for endpoint 0 since it is + * always enabled + */ + if (!ep && ((packet_size < 8) || (packet_size > 64))) { + buffer_size = packet_size = 64; + ep_size = 3; + } + + outb(ep & 0xF, UDC_INDEX); + if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { + /* IN endpoint */ + outb((ep_doublebuffer << 4) | (ep_size & 0xf), UDC_TXFIFOSZ); + outw(ep_ptr >> 3, UDC_TXFIFOADDR); + if (!ep) { /* This only apply for ep != 0 */ + outw(packet_size & 0x3FF, UDC_TXMAXP); + } + } else { + /* OUT endpoint */ + outb((ep_doublebuffer << 4) | (ep_size & 0xf), UDC_RXFIFOSZ); + outw(ep_ptr >> 3, UDC_RXFIFOADDR); + if (!ep) { /* This only apply for ep != 0 */ + outw(packet_size & 0x3FF, UDC_RXMAXP); + } + } + ep_ptr += buffer_size; + } +} + +static void musb_ep0_tx(struct usb_endpoint_instance *endpoint) +{ + unsigned int size = 0; + struct urb *urb = endpoint->tx_urb; + + outb(0, UDC_INDEX); + + if (urb) { + + if ((size = + MIN(urb->actual_length - endpoint->sent, + endpoint->tx_packetSize))) { + + musb_fifo_write(0,urb->buffer + endpoint->sent,size); + } + endpoint->last = size; + + if (((endpoint->sent + size) == ep0_urb->device_request.wLength) + || (size != endpoint->tx_packetSize)) { + ep0status = DATA_COMPLETE; + outw(0xA, UDC_CSR0); /* Transmit packet and set dataend */ + } else { + outw(0x2, UDC_CSR0); /* Transmit packet */ + } + } +} + +static void musb_ep0_handler(struct usb_endpoint_instance *endpoint) +{ + u16 csr0; + + outb(0, UDC_INDEX); + + /* Check errors */ + csr0 = inw(UDC_CSR0); + + if (csr0 & 0x4) { /* SENTSTALL */ + outw(csr0 & ~0x4, UDC_CSR0); // Clear stall + serial_printf("%s: stall received on EP0!\n", __FUNCTION__); + } + + if (csr0 & 0x10) { /* SETUPEND */ + outw(0x80, UDC_CSR0); /* Clear setupend */ + serial_printf("%s: setup END early happened! status is %d\n", + __FUNCTION__, ep0status); + ep0status = IDLE; + return; + } + + switch (ep0status) { + case DATA_COMPLETE: + if (do_set_address) { + /* We need to set the address only after + the status stage is complete */ + outb(udc_device->address, UDC_FADDR); + do_set_address = 0; + } + ep0status = IDLE; + /* Fallthrough */ + case IDLE: /* Receiving a setup packet */ + if (csr0 & 0x1) { + insl(UDC_FIFO0, (unsigned int *) &ep0_urb->device_request, + 2); + + /* If we have data, then don't go to IDLE state */ + if (ep0_urb->device_request.wLength) { + ep0status = DATA_STAGE; + + outw(0x40, UDC_CSR0); // Clear RXPKTRDY + if ((ep0_urb->device_request. + bmRequestType & USB_REQ_DIRECTION_MASK) + == USB_REQ_DEVICE2HOST) { + + /* Try to process setup packet */ + if (ep0_recv_setup(ep0_urb)) { + /* Not a setup packet, stall next EP0 transaction */ + outw(0x20, UDC_CSR0); + ep0status = IDLE; + return; + } + /* If we are sending data, do it now, as + ep0_recv_setup should have prepare them + */ + endpoint->tx_urb = ep0_urb; + endpoint->sent = 0; + + musb_ep0_tx(endpoint); + } else { + endpoint->rcv_urb = ep0_urb; + ep0_urb->actual_length = 0; + } + } else { /* Processing zero-length packet */ + /* + * The www.linux-usb.org/usbtest 'test 14' fails with error for zero + * length request. If the SETUP packet requests ZERO length data from + * device-to-host, the TXPKTRDY bit needs to be set in TXCSR otherwise + * the STATUS stage of control transfer will never complete. + * + */ + if ((ep0_urb->device_request. + bmRequestType & USB_REQ_DIRECTION_MASK) + == USB_REQ_DEVICE2HOST) { + outw(0x4A, UDC_CSR0); // Clear RXPKTRDY and DATAEND and TXPKTRDY + } else { + outw(0x48, UDC_CSR0); // Clear RXPKTRDY and DATAEND + } + + /* Try to process setup packet */ + if (ep0_recv_setup(ep0_urb)) { + /* Not a setup packet, stall next EP0 transaction */ + outw(0x20, UDC_CSR0); + ep0status = IDLE; + return; + } + + switch (ep0_urb->device_request.bRequest) { + case USB_REQ_SET_ADDRESS: + usbd_device_event_irq(udc_device, + DEVICE_ADDRESS_ASSIGNED, + 0); + do_set_address = 1; + break; + case USB_REQ_SET_CONFIGURATION: + usbd_device_event_irq(udc_device, + DEVICE_CONFIGURED, 0); + break; + } + + ep0status = DATA_COMPLETE; + } + } + break; + case DATA_STAGE: + if ((ep0_urb->device_request. + bmRequestType & USB_REQ_DIRECTION_MASK) + == USB_REQ_DEVICE2HOST) { + if (!(csr0 & 0x2)) { // There packet was send? + endpoint->sent += endpoint->last; + + /* If we finished sending data we would not be on the DATA_STAGE */ + musb_ep0_tx(endpoint); + } + } else { + /* Receiving data */ + u16 length = inw(UDC_COUNT0); + + if (length) { + if (ep0_urb->actual_length + length > + ep0_urb->device_request.wLength) + length = + ep0_urb->device_request.wLength - + ep0_urb->actual_length; + + endpoint->last = length; + + musb_fifo_read(0,&ep0_urb->buffer[ep0_urb->actual_length],length); + ep0_urb->actual_length += length; + } + + /* We finish if we received the amount of data expected, or less + of the packet size + */ + if ((ep0_urb->actual_length == ep0_urb->device_request.wLength) || + (endpoint->last != endpoint->tx_packetSize)) { + ep0status = DATA_COMPLETE; + outw(0x48, UDC_CSR0); // Clear RXPKTRDY and DATAEND + /* This will process the incoming data */ + if (ep0_recv_setup(ep0_urb)) { + /* Not a setup packet, stall next EP0 transaction */ + outw(0x20, UDC_CSR0); + return; + } + } else + outw(0x40, UDC_CSR0); // Clear RXPKTRDY + } + break; + } +} + +static void musb_ep_tx(struct usb_endpoint_instance *endpoint) +{ + unsigned int size = 0, epnumber = + endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK; + struct urb *urb = endpoint->tx_urb; + + outb(epnumber, UDC_INDEX); + if (urb) { + if ((size = + MIN(urb->actual_length - endpoint->sent, + endpoint->tx_packetSize))) { + musb_fifo_write(epnumber,urb->buffer + endpoint->sent,size); + } + endpoint->last = size; + endpoint->state = 1; /* Transmit hardware is busy */ + + outw(inw(UDC_TXCSR) | 0x1, UDC_TXCSR); // Transmit packet + } +} + + +static void musb_tx_handler(struct usb_endpoint_instance *endpoint) +{ + unsigned int epnumber = + endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK; + u16 txcsr; + + outb(epnumber, UDC_INDEX); + + /* Check errors */ + txcsr = inw(UDC_TXCSR); + + if (txcsr & 0x4) { /* Clear underrun */ + txcsr &= ~0x4; + } + if (txcsr & 0x20) { /* SENTSTALL */ + outw(txcsr & ~0x20, UDC_TXCSR); /* Clear stall */ + return; + } + + if (endpoint->tx_urb && !(txcsr & 0x1)) { // The packet was send? + if ((endpoint->sent+endpoint->last == endpoint->tx_urb->actual_length) /* Send a zero length packet? */ + && (endpoint->last == endpoint->tx_packetSize)) { + /* Prepare to transmit a zero-length packet. */ + endpoint->sent += endpoint->last; + musb_ep_tx(endpoint); + } else if (endpoint->tx_urb->actual_length) { + /* retire the data that was just sent */ + usbd_tx_complete (endpoint); + endpoint->state = 0; /* Transmit hardware is free */ + + /* Check to see if we have more data ready to transmit + * now. + */ + if (endpoint->tx_urb && endpoint->tx_urb->actual_length) { + musb_ep_tx(endpoint); + } + } + } +} + +static void musb_rx_handler(struct usb_endpoint_instance *endpoint) +{ + unsigned int epnumber = + endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK; + u16 rxcsr; + u16 length; + + outb(epnumber, UDC_INDEX); + + /* Check errors */ + rxcsr = inw(UDC_RXCSR); + + if (!(rxcsr & 0x1)) /* There is a package received? */ + return; + + if (rxcsr & 0x40) /* SENTSTALL */ + outw(rxcsr & ~0x40, UDC_RXCSR); /* Clear stall */ + + length = inw(UDC_RXCOUNT); + + if (endpoint->rcv_urb) { + /* Receiving data */ + if (length) { + musb_fifo_read(epnumber,&endpoint->rcv_urb->buffer[endpoint->rcv_urb->actual_length],length); + + outw(rxcsr & ~0x1, UDC_RXCSR); /* Clear RXPKTRDY */ + usbd_rcv_complete(endpoint, length, 0); + } + } else { + serial_printf("%s: no receive URB!\n", __FUNCTION__); + } +} + +static void musb_reset(void) +{ + usbd_device_event_irq(udc_device, DEVICE_HUB_CONFIGURED, 0); + usbd_device_event_irq(udc_device, DEVICE_RESET, 0); + ep0status = IDLE; + do_set_address = 0; +} + +/* Public functions - called by usbdcore, usbtty, etc. */ +void udc_irq(void) +{ + unsigned char int_usb = inb(UDC_INTRUSB); + unsigned short int_tx = inw(UDC_INTRTX); + unsigned short int_rx = inw(UDC_INTRRX); + int ep; + + if (int_usb) { + if (int_usb & 0x4) { /* Reset */ + /* The controller clears FADDR, INDEX, and FIFOs */ + musb_reset(); + } + if (int_usb & 0x20) { /* Disconnected */ + usbd_device_event_irq(udc_device, DEVICE_HUB_RESET, 0); + } + if (int_usb & 0x1) + usbd_device_event_irq (udc_device, DEVICE_BUS_INACTIVE, 0); + if (int_usb & 0x2) + usbd_device_event_irq (udc_device, DEVICE_BUS_ACTIVITY, 0); + } + + /* Note: IRQ values auto clear so read just before processing */ + if (int_rx) { /* OUT endpoints */ + ep = 1; + int_rx >>= 1; + while (int_rx) { + if (int_rx & 1) { + musb_rx_handler(udc_device->bus->endpoint_array + ep); + } + int_rx >>= 1; + ep++; + } + } + if (int_tx) { /* IN endpoints */ + if (int_tx & 1) + musb_ep0_handler(udc_device->bus->endpoint_array); + + ep = 1; + int_tx >>= 1; + while (int_tx) { + if (int_tx & 1) { + musb_tx_handler(udc_device->bus->endpoint_array + ep); + } + int_tx >>= 1; + ep++; + } + } +} + +/* Turn on the USB connection */ +void udc_connect(void) +{ + outb(0x1, UDC_DEVCTL); + + if (!(inb(UDC_DEVCTL) & 0x80)) { + serial_printf("Error, the USB hardware is not on B mode\n"); + outb(0x0, UDC_DEVCTL); + return; + } +} + +/* Turn off the USB connection */ +void udc_disconnect(void) +{ + if (!(inb(UDC_DEVCTL) & 0x80)) { + serial_printf("Error, the USB hardware is not on B mode"); + return; + } + + outb(0x0, UDC_DEVCTL); +} + +int udc_endpoint_write(struct usb_endpoint_instance *endpoint) +{ + /* Transmit only if the hardware is available */ + if (endpoint->tx_urb && endpoint->state == 0) { + musb_ep_tx(endpoint); + } + return 0; +} + +/* + * udc_setup_ep - setup endpoint + * + * Associate a physical endpoint with endpoint_instance + */ +void udc_setup_ep(struct usb_device_instance *device, unsigned int ep, + struct usb_endpoint_instance *endpoint) +{ + int ep_addr; + int attributes; + + /* We dont' have a way to identify if the endpoint definitions changed, + so we have to always reconfigure the FIFOs to avoid problems */ + musb_fifos_configure(device); + + ep_addr = endpoint->endpoint_address; + if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { + /* IN endpoint */ + attributes = endpoint->tx_attributes; + } else { + /* OUT endpoint */ + attributes = endpoint->rcv_attributes; + } + + outb(ep & 0xF, UDC_INDEX); + if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { + /* IN endpoint */ + if (!ep) { /* This only apply for ep != 0 */ + /* Empty fifo twice on case of previous double buffer */ + outw(1<<3,UDC_TXCSR); + outw(1<<3,UDC_TXCSR); + + if (attributes & USB_ENDPOINT_XFER_ISOC) + outw(inw(UDC_TXCSR) | (1 << 13) | (1 << 14) | 0x4, UDC_TXCSR); + else + outw((inw(UDC_TXCSR) | (1 << 13) | 0x4) & ~(1 << 14), UDC_TXCSR); + } + /* Enable interrupt */ + outw(inw(UDC_INTRTXE) | (1 << ep), UDC_INTRTXE); + } else { + /* OUT endpoint */ + if (!ep) { /* This only apply for ep != 0 */ + if (attributes & USB_ENDPOINT_XFER_ISOC) + outw((inw(UDC_RXCSR) | (1 << 14)) & ~(1 << 13), UDC_RXCSR); + else + outw(inw(UDC_RXCSR) & ~(1 << 14) & ~(1 << 13), UDC_RXCSR); + } + /* Enable interrupt */ + outw(inw(UDC_INTRRXE) | (1 << ep), UDC_INTRRXE); + } +} + +/* + * udc_startup_events - allow udc code to do any additional startup + */ +void udc_startup_events(struct usb_device_instance *device) +{ + /* The DEVICE_INIT event puts the USB device in the state STATE_INIT. */ + usbd_device_event_irq(device, DEVICE_INIT, 0); + + /* The DEVICE_CREATE event puts the USB device in the state + * STATE_ATTACHED. + */ + usbd_device_event_irq(device, DEVICE_CREATE, 0); + + /* Some USB controller driver implementations signal + * DEVICE_HUB_CONFIGURED and DEVICE_RESET events here. + * DEVICE_HUB_CONFIGURED causes a transition to the state STATE_POWERED, + * and DEVICE_RESET causes a transition to the state STATE_DEFAULT. + * The MUSB client controller has the capability to detect when the + * USB cable is connected to a powered USB bus, so we will defer the + * DEVICE_HUB_CONFIGURED and DEVICE_RESET events until later. + */ + + /* Save the device structure pointer */ + udc_device = device; + + /* Setup ep0 urb */ + if (!ep0_urb) { + ep0_urb = + usbd_alloc_urb(udc_device, udc_device->bus->endpoint_array); + } else { + serial_printf("udc_enable: ep0_urb already allocated %p\n", + ep0_urb); + } + + /* Enable control interrupts */ + outb(0xf7, UDC_INTRUSBE); +} + +void udc_set_nak(int epid) +{ +/* On MUSB the NAKing is controlled by the USB controller buffers, + so as long as we don't read data from the FIFO, the controller will NAK. + Nothing to see here, move along... +*/ +} + +void udc_unset_nak(int epid) +{ +/* On MUSB the NAKing is controlled by the USB controller buffers, + so as long as we don't read data from the FIFO, the controller will NAK. + Nothing to see here, move along... +*/ +} + +/* Start to initialize h/w stuff */ +int udc_init(void) +{ + /* Clock is initialized on the board code */ + + /* MUSB soft-reset */ + outl(2, UDC_SYSCONFIG); + + if (udc_musb_platform_init()) { + serial_printf("udc_init: platform init failed\n"); + return -1; + } + + outl(inl(UDC_FORCESTDBY) & ~1,UDC_FORCESTDBY); /* disable MSTANDBY */ + outl(inl(UDC_SYSCONFIG) | (2<<12),UDC_SYSCONFIG); /* enable SMARTSTDBY */ + outl(inl(UDC_SYSCONFIG) & ~1,UDC_SYSCONFIG); /* disable AUTOIDLE */ + outl(inl(UDC_SYSCONFIG) | (2<<3),UDC_SYSCONFIG); /* enable SMARTIDLE */ + outl(inl(UDC_SYSCONFIG) | 1,UDC_SYSCONFIG); /* enable AUTOIDLE */ + + /* Configure the PHY as PHY interface is 12-pin, 8-bit SDR ULPI */ + sr32((void *)UDC_INTERFSEL, 0, 1, 1); + + /* Turn off interrupts */ + outw(0x00, UDC_INTRTXE); + outw(0x00, UDC_INTRRXE); + +#if CONFIG_MUSB_FULL_SPEED + /* Use Full speed for debugging proposes, useful so most USB + analyzers can catch the transactions + */ + outb(0, UDC_POWER); + serial_printf("MUSB: using full speed\n"); +#else + serial_printf("MUSB: using high speed\n"); +#endif + + return 0; +} diff -uprN omap3-dev/include/configs/omap3_beagle.h omap3-dev-usb/include/configs/omap3_beagle.h --- omap3-dev/include/configs/omap3_beagle.h 2009-02-01 19:17:15.000000000 +0100 +++ omap3-dev-usb/include/configs/omap3_beagle.h 2009-02-01 19:17:43.000000000 +0100 @@ -92,6 +92,26 @@ #define CONFIG_OMAP3_MMC 1 #define CONFIG_DOS_PARTITION 1 +/* + * I2C configuration + */ +#define CONFIG_HARD_I2C +#define CONFIG_SYS_I2C_SPEED 100000 +#define CONFIG_SYS_I2C_SLAVE 1 +#define CONFIG_DRIVER_OMAP34XX_I2C 1 + +/* + * USB Configuration + */ +#define CONFIG_USB_DEVICE 1 +#define CONFIG_USB_TTY 1 +#define CONFIG_MUSB 1 /* Enable USB driver*/ +#define CONFIG_TWL4030_USB 1 /* Enable TWL4030 USB */ + +/* Allow console in serial and USB at the same time */ +#define CONFIG_CONSOLE_MUX 1 +#define CONFIG_SYS_CONSOLE_IS_IN_ENV 1 + /* commands to include */ #include @@ -178,6 +198,10 @@ "run nandargs; " \ "nand read ${loadaddr} 280000 400000; " \ "bootm ${loadaddr}\0" \ + "usbtty=cdc_acm\0"\ + "stdout=serial,usbtty\0" \ + "stdin=serial,usbtty\0" \ + "stderr=serial,usbtty\0" #define CONFIG_BOOTCOMMAND \ "if mmcinit; then " \ diff -uprN omap3-dev/include/configs/omap3_evm.h omap3-dev-usb/include/configs/omap3_evm.h --- omap3-dev/include/configs/omap3_evm.h 2009-02-01 19:17:15.000000000 +0100 +++ omap3-dev-usb/include/configs/omap3_evm.h 2009-02-01 19:17:43.000000000 +0100 @@ -156,6 +156,26 @@ /* Environment information */ #define CONFIG_BOOTDELAY 10 +/* + * USB MSC and Keyboard support + */ +#define CONFIG_USB_OMAP3530 +#define CONFIG_MUSB_HCD + +#ifdef CONFIG_USB_OMAP3530 +#define CONFIG_CMD_USB +#ifdef CONFIG_MUSB_HCD +#define CONFIG_USB_STORAGE +#define CONGIG_CMD_STORAGE +#define CONFIG_CMD_FAT +#define CONFIG_USB_KEYBOARD +#endif +#ifdef CONFIG_USB_KEYBOARD +#define CONFIG_SYS_USB_EVENT_POLL +#define CONFIG_PREBOOT "usb start" +#endif +#endif + #define CONFIG_EXTRA_ENV_SETTINGS \ "loadaddr=0x82000000\0" \ "console=ttyS2,115200n8\0" \ diff -uprN omap3-dev/include/usbdcore_musb.h omap3-dev-usb/include/usbdcore_musb.h --- omap3-dev/include/usbdcore_musb.h 1970-01-01 01:00:00.000000000 +0100 +++ omap3-dev-usb/include/usbdcore_musb.h 2009-02-01 19:17:44.000000000 +0100 @@ -0,0 +1,120 @@ +/* + * (C) Copyright 2009 + * + * Based on + * u-boot OMAP1510 USB drivers (include/usbdcore_omap1510.h) + * + * Author: Diego Dompe (diego.dompe@ridgerun.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __USBDCORE_MUSB_H__ +#define __USBDCORE_MUSB_H__ + +/* USB Function Module Registers */ + +/* + * UDC_BASE is defined for the specific silicon under soc + * specific cpu.h or related header. + */ + +#define UDC_OFFSET(offset) (UDC_BASE+(offset)) + +#define UDC_INTSRCR UDC_OFFSET(0x0A) /* USB Interrupt src Reg*/ +#define UDC_INTCLRR UDC_OFFSET(0x0A) /* USB Interrupt src clr Reg*/ + +#define UDC_FADDR UDC_OFFSET(0x00) +#define UDC_POWER UDC_OFFSET(0x01) +#define UDC_INTRTX UDC_OFFSET(0x02) +#define UDC_INTRRX UDC_OFFSET(0x04) +#define UDC_INTRTXE UDC_OFFSET(0x06) /* Enable register for INTRTX*/ +#define UDC_INTRRXE UDC_OFFSET(0x08) /* Enable Register for INTRRX*/ +#define UDC_INTRUSB UDC_OFFSET(0x0A) +#define UDC_INTRUSBE UDC_OFFSET(0x0B) +#define UDC_INDEX UDC_OFFSET(0x0E) +#define UDC_TESTMODE UDC_OFFSET(0x0F) +#define UDC_TXMAXP UDC_OFFSET(0x10) +#define UDC_CSR0 UDC_OFFSET(0x12) +#define UDC_TXCSR UDC_OFFSET(0x12) +#define UDC_RXMAXP UDC_OFFSET(0x14) +#define UDC_RXCSR UDC_OFFSET(0x16) +#define UDC_COUNT0 UDC_OFFSET(0x18) +#define UDC_RXCOUNT UDC_OFFSET(0x18) +#define UDC_FIFO0 UDC_OFFSET(0x20) +#define UDC_FIFO1 UDC_OFFSET(0x24) +#define UDC_FIFO2 UDC_OFFSET(0x28) +#define UDC_FIFO3 UDC_OFFSET(0x2C) +#define UDC_FIFO4 UDC_OFFSET(0x30) +#define UDC_FIFO5 UDC_OFFSET(0x34) +#define UDC_FIFO6 UDC_OFFSET(0x38) +#define UDC_FIFO7 UDC_OFFSET(0x3C) +#define UDC_FIFO8 UDC_OFFSET(0x40) +#define UDC_FIFO9 UDC_OFFSET(0x44) +#define UDC_FIFO10 UDC_OFFSET(0x48) +#define UDC_FIFO11 UDC_OFFSET(0x4C) +#define UDC_FIFO12 UDC_OFFSET(0x50) +#define UDC_FIFO13 UDC_OFFSET(0x54) +#define UDC_FIFO14 UDC_OFFSET(0x58) +#define UDC_FIFO15 UDC_OFFSET(0x5C) +#define UDC_DEVCTL UDC_OFFSET(0x60) +#define UDC_TXFIFOSZ UDC_OFFSET(0x62) +#define UDC_RXFIFOSZ UDC_OFFSET(0x63) +#define UDC_TXFIFOADDR UDC_OFFSET(0x64) +#define UDC_RXFIFOADDR UDC_OFFSET(0x66) + +#define UDC_SYSCONFIG UDC_OFFSET(0x404) +#define UDC_INTERFSEL UDC_OFFSET(0x40C) +#define UDC_FORCESTDBY UDC_OFFSET(0x414) + +/* MUSB Endpoint parameters */ +#define EP0_MAX_PACKET_SIZE 64 +#define UDC_OUT_ENDPOINT 3 /* Device RX endpoint */ +#define UDC_OUT_PACKET_SIZE 512 +#define UDC_IN_ENDPOINT 2 /* Device TX endpoint */ +#define UDC_IN_PACKET_SIZE 512 +#define UDC_INT_ENDPOINT 1 /* Device Interrupt/Status endpoint */ +#define UDC_INT_PACKET_SIZE 16 +#define UDC_BULK_PACKET_SIZE 512 + +#define UDC_MAX_FIFO_SIZE 16384 + +#define DEV_CONFIG_VALUE 1 /* Only one i.e. CDC */ + +void udc_irq(void); +/* Flow control */ +void udc_set_nak(int epid); +void udc_unset_nak(int epid); + +/* Higher level functions for abstracting away from specific device */ +int udc_endpoint_write(struct usb_endpoint_instance *endpoint); + +int udc_init(void); + +void udc_enable(struct usb_device_instance *device); +void udc_disable(void); + +void udc_connect(void); +void udc_disconnect(void); + +void udc_startup_events(struct usb_device_instance *device); +void udc_setup_ep(struct usb_device_instance *device, unsigned int ep, + struct usb_endpoint_instance *endpoint); + +/* platform specific initialization */ +int udc_musb_platform_init(void); + +#endif /* __USBDCORE_MUSB_H__ */ diff -uprN omap3-dev/include/usb.h omap3-dev-usb/include/usb.h --- omap3-dev/include/usb.h 2009-02-01 19:17:16.000000000 +0100 +++ omap3-dev-usb/include/usb.h 2009-02-01 19:17:44.000000000 +0100 @@ -183,7 +183,8 @@ struct usb_device { #if defined(CONFIG_USB_UHCI) || defined(CONFIG_USB_OHCI) || \ defined(CONFIG_USB_EHCI) || defined(CONFIG_USB_OHCI_NEW) || \ defined(CONFIG_USB_SL811HS) || defined(CONFIG_USB_ISP116X_HCD) || \ - defined(CONFIG_USB_R8A66597_HCD) || defined(CONFIG_USB_DAVINCI) + defined(CONFIG_USB_R8A66597_HCD) || defined(CONFIG_USB_DAVINCI) || \ + defined(CONFIG_USB_OMAP3530) int usb_lowlevel_init(void); int usb_lowlevel_stop(void);