r-link-uboot/cpu/omap3/fastboot.c

1219 lines
29 KiB
C

/*
* Copyright 2008 - 2009 (C) Wind River Systems, Inc.
* Tom Rix <Tom.Rix@windriver.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 <common.h>
#include <asm/arch/cpu.h>
#include <asm/io.h>
#include <asm/types.h>
#include <asm/arch/bits.h>
#include <asm/arch/mem.h>
#include <asm/arch/sys_proto.h>
#include <asm/arch/sys_info.h>
#include <asm/arch/usb34xx.h>
#include <asm/arch/led.h>
#include <environment.h>
#include <command.h>
#include <usbdcore.h>
#include <fastboot.h>
#include <twl4030.h>
#if defined(CONFIG_FASTBOOT)
#include "usb_debug_macros.h"
#define CONFUSED() printf ("How did we get here %s %d ? \n", __FILE__, __LINE__)
/* memory mapped registers */
static volatile u8 *pwr = (volatile u8 *) OMAP34XX_USB_POWER;
static volatile u16 *csr0 = (volatile u16 *) OMAP34XX_USB_CSR0;
static volatile u8 *index = (volatile u8 *) OMAP34XX_USB_INDEX;
static volatile u8 *txfifosz = (volatile u8 *) OMAP34XX_USB_TXFIFOSZ;
static volatile u8 *rxfifosz = (volatile u8 *) OMAP34XX_USB_RXFIFOSZ;
static volatile u16 *txfifoadd = (volatile u16 *) OMAP34XX_USB_TXFIFOADD;
static volatile u16 *rxfifoadd = (volatile u16 *) OMAP34XX_USB_RXFIFOADD;
#define BULK_ENDPOINT 1
static volatile u16 *peri_rxcsr = (volatile u16 *) OMAP34XX_USB_RXCSR(BULK_ENDPOINT);
static volatile u16 *rxmaxp = (volatile u16 *) OMAP34XX_USB_RXMAXP(BULK_ENDPOINT);
static volatile u16 *rxcount = (volatile u16 *) OMAP34XX_USB_RXCOUNT(BULK_ENDPOINT);
static volatile u16 *peri_txcsr = (volatile u16 *) OMAP34XX_USB_TXCSR(BULK_ENDPOINT);
static volatile u16 *txmaxp = (volatile u16 *) OMAP34XX_USB_TXMAXP(BULK_ENDPOINT);
static volatile u8 *bulk_fifo = (volatile u8 *) OMAP34XX_USB_FIFO(BULK_ENDPOINT);
#define DMA_CHANNEL 1
static volatile u8 *peri_dma_intr = (volatile u8 *) OMAP34XX_USB_DMA_INTR;
static volatile u16 *peri_dma_cntl = (volatile u16 *) OMAP34XX_USB_DMA_CNTL_CH(DMA_CHANNEL);
static volatile u32 *peri_dma_addr = (volatile u32 *) OMAP34XX_USB_DMA_ADDR_CH(DMA_CHANNEL);
static volatile u32 *peri_dma_count = (volatile u32 *) OMAP34XX_USB_DMA_COUNT_CH(DMA_CHANNEL);
static volatile u32 *otg_sysconfig = (volatile u32 *) OMAP34XX_OTG_SYSCONFIG;
static volatile u32 *otg_interfsel = (volatile u32 *) OMAP34XX_OTG_INTERFSEL;
static volatile u32 *otg_forcestdby = (volatile u32 *) OMAP34XX_OTG_FORCESTDBY;
/* This is the TI USB vendor id */
#define DEVICE_VENDOR_ID 0x0451
/* This is just made up.. */
#define DEVICE_PRODUCT_ID 0xCAFE
/* This is just made up.. */
#define DEVICE_BCD 0x0311;
/* String 0 is the language id */
#define DEVICE_STRING_PRODUCT_INDEX 1
#define DEVICE_STRING_SERIAL_NUMBER_INDEX 2
#define DEVICE_STRING_CONFIG_INDEX 3
#define DEVICE_STRING_INTERFACE_INDEX 4
#define DEVICE_STRING_MANUFACTURER_INDEX 5
#define DEVICE_STRING_MAX_INDEX DEVICE_STRING_MANUFACTURER_INDEX
#define DEVICE_STRING_LANGUAGE_ID 0x0409 /* English (United States) */
/* Define this to use 1.1 / fullspeed */
/* #define CONFIG_USB_1_1_DEVICE */
/* In high speed mode packets are 512
In full speed mode packets are 64 */
#define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_2_0 (0x0200)
#define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_1_1 (0x0040)
#define TX_ENDPOINT_MAXIMUM_PACKET_SIZE_2_0 (0x0200)
#define TX_ENDPOINT_MAXIMUM_PACKET_SIZE_1_1 (0x0040)
/* Same, just repackaged as
2^(m+3), 64 = 2^6, m = 3 */
#define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_BITS_2_0 (6)
#define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_BITS_1_1 (3)
#define TX_ENDPOINT_MAXIMUM_PACKET_SIZE_BITS_2_0 (6)
#define TX_ENDPOINT_MAXIMUM_PACKET_SIZE_BITS_1_1 (3)
#define CONFIGURATION_NORMAL 1
#define TX_LAST() \
*csr0 |= (MUSB_CSR0_TXPKTRDY | MUSB_CSR0_P_DATAEND); \
while (*csr0 & MUSB_CSR0_RXPKTRDY) \
udelay(1);
#define NAK_REQ() *csr0 |= MUSB_CSR0_P_SENDSTALL
#define ACK_REQ() *csr0 |= MUSB_CSR0_P_DATAEND
#define ACK_RX() *peri_rxcsr |= (MUSB_CSR0_P_SVDRXPKTRDY | MUSB_CSR0_P_DATAEND)
static u8 fastboot_fifo[MUSB_EP0_FIFOSIZE];
static u16 fastboot_fifo_used = 0;
static unsigned int set_address = 0;
static u8 faddr = 0xff;
static unsigned int high_speed = 0;
static unsigned int deferred_rx = 0;
static struct usb_device_request req;
/* The packet size is dependend of the speed mode
In high speed mode packets are 512
In full speed mode packets are 64
Set to maximum of 512 */
/* Note: The start address (written to the MUSB_DMA_ADDR_CH(n) register)
must be word aligned */
static u8 fastboot_bulk_fifo[0x0200] __attribute__ ((aligned(0x4)));
static char *device_strings[DEVICE_STRING_MANUFACTURER_INDEX+1];
static struct cmd_fastboot_interface *fastboot_interface = NULL;
#ifdef DEBUG_FASTBOOT
static void fastboot_db_regs(void)
{
printf("fastboot_db_regs\n");
u8 b;
u16 s;
/* */
b = inb (OMAP34XX_USB_FADDR);
printf ("\tfaddr 0x%2.2x\n", b);
b = inb (OMAP34XX_USB_POWER);
PRINT_PWR(b);
s = inw (OMAP34XX_USB_CSR0);
PRINT_CSR0(s);
b = inb (OMAP34XX_USB_DEVCTL);
PRINT_DEVCTL(b);
b = inb (OMAP34XX_USB_CONFIGDATA);
PRINT_CONFIG(b);
s = inw (OMAP34XX_USB_FRAME);
printf ("\tframe 0x%4.4x\n", s);
b = inb (OMAP34XX_USB_INDEX);
printf ("\tindex 0x%2.2x\n", b);
s = *rxmaxp;
PRINT_RXMAXP(s);
s = *peri_rxcsr;
PRINT_RXCSR(s);
s = *txmaxp;
PRINT_TXMAXP(s);
s = *peri_txcsr;
PRINT_TXCSR(s);
}
static void fastboot_db_otg_regs(void)
{
u32 v;
v = __raw_readl(OMAP34XX_OTG_REVISION);
printf("OTG_REVISION 0x%x\n", v);
v = __raw_readl(OMAP34XX_OTG_SYSCONFIG);
printf("OTG_SYSCONFIG 0x%x\n", v);
v = __raw_readl(OMAP34XX_OTG_SYSSTATUS);
printf("OTG_SYSSTATUS 0x%x\n", v);
v = __raw_readl(OMAP34XX_OTG_INTERFSEL);
printf("OTG_INTERFSEL 0x%x\n", v);
v = __raw_readl(OMAP34XX_OTG_FORCESTDBY);
printf("OTG_FORCESTDBY 0x%x\n", v);
}
#endif
static void fastboot_bulk_endpoint_reset (void)
{
u8 old_index;
/* save old index */
old_index = *index;
/* set index to tx/rx endpoint */
*index = BULK_ENDPOINT;
/* Address starts at the end of EP0 fifo, shifted right 3 (8 bytes) */
*txfifoadd = MUSB_EP0_FIFOSIZE >> 3;
/* Size depends on the mode. Do not double buffer */
if (high_speed) {
*txfifosz = TX_ENDPOINT_MAXIMUM_PACKET_SIZE_BITS_2_0;
} else {
*txfifosz = TX_ENDPOINT_MAXIMUM_PACKET_SIZE_BITS_1_1;
}
/*
* Double buffer the rx fifo because it handles the large transfers
* The extent is now double and must be considered if another fifo is
* added to the end of this one.
*/
if (high_speed) {
*rxfifosz =
RX_ENDPOINT_MAXIMUM_PACKET_SIZE_BITS_2_0 |
MUSB_RXFIFOSZ_DPB;
*rxfifoadd = (MUSB_EP0_FIFOSIZE + TX_ENDPOINT_MAXIMUM_PACKET_SIZE_2_0) >> 3;
} else {
*rxfifosz =
RX_ENDPOINT_MAXIMUM_PACKET_SIZE_BITS_1_1 |
MUSB_RXFIFOSZ_DPB;
*rxfifoadd = (MUSB_EP0_FIFOSIZE + TX_ENDPOINT_MAXIMUM_PACKET_SIZE_1_1) >> 3;
}
/* restore index */
*index = old_index;
/* Setup Rx endpoint for Bulk OUT */
*rxmaxp = fastboot_fifo_size();
/* Flush anything on fifo */
while (*peri_rxcsr & MUSB_RXCSR_RXPKTRDY)
{
*peri_rxcsr |= MUSB_RXCSR_FLUSHFIFO;
udelay(1);
}
/* No dma, enable bulkout, */
*peri_rxcsr &= ~(MUSB_RXCSR_DMAENAB | MUSB_RXCSR_P_ISO);
/* reset endpoint data */
*peri_rxcsr |= MUSB_RXCSR_CLRDATATOG;
/* Setup Tx endpoint for Bulk IN */
/* Set max packet size per usb 1.1 / 2.0 */
*txmaxp = fastboot_fifo_size();
/* Flush anything on fifo */
while (*peri_txcsr & MUSB_TXCSR_FIFONOTEMPTY)
{
*peri_txcsr |= MUSB_TXCSR_FLUSHFIFO;
udelay(1);
}
/* No dma, enable bulkout, no underflow */
*peri_txcsr &= ~(MUSB_TXCSR_DMAENAB | MUSB_TXCSR_P_ISO | MUSB_TXCSR_P_UNDERRUN);
/* reset endpoint data, shared fifo with rx */
*peri_txcsr |= (MUSB_TXCSR_CLRDATATOG | MUSB_TXCSR_MODE);
}
static void fastboot_reset (void)
{
OMAP3_LED_ERROR_ON ();
/* Reset OTG */
/* Set OTG to always be on */
*otg_sysconfig = (OMAP34XX_OTG_SYSCONFIG_NO_STANDBY_MODE |
OMAP34XX_OTG_SYSCONFIG_NO_IDLE_MODE);
/* Set the interface */
*otg_interfsel = OMAP34XX_OTG_INTERFSEL_OMAP;
/* Clear force standby */
*otg_forcestdby &= ~OMAP34XX_OTG_FORCESTDBY_STANDBY;
/* Reset MUSB */
*pwr &= ~MUSB_POWER_SOFTCONN;
udelay(2 * 500000); /* 1 sec */
OMAP3_LED_ERROR_OFF ();
/* Reset address */
faddr = 0xff;
/* Reset */
#ifdef CONFIG_USB_1_1_DEVICE
*pwr &= ~MUSB_POWER_HSENAB;
*pwr |= MUSB_POWER_SOFTCONN;
#else
*pwr |= (MUSB_POWER_SOFTCONN | MUSB_POWER_HSENAB);
#endif
/* Bulk endpoint fifo */
fastboot_bulk_endpoint_reset ();
OMAP3_LED_ERROR_ON ();
}
static u8 read_fifo_8(void)
{
u8 val;
val = inb (OMAP34XX_USB_FIFO_0);
return val;
}
static u8 read_bulk_fifo_8(void)
{
u8 val;
val = *bulk_fifo;
return val;
}
static int read_bulk_fifo_dma(u8 *buf, u32 size)
{
int ret = 0;
/* Set the address */
*peri_dma_addr = (u32) buf;
/* Set the transfer size */
*peri_dma_count = size;
/*
* Set the control parts,
* The size is either going to be 64 or 512 which
* is ok for burst mode 3 which does increment by 16.
*/
*peri_dma_cntl =
MUSB_DMA_CNTL_BUSRT_MODE_3 |
MUSB_DMA_CNTL_END_POINT(BULK_ENDPOINT) |
MUSB_DMA_CNTL_MODE_1 |
MUSB_DMA_CNTL_WRITE |
MUSB_DMA_CNTL_ENABLE;
while (1) {
if (MUSB_DMA_CNTL_ERR & *peri_dma_cntl) {
ret = 1;
break;
}
if (0 == *peri_dma_count)
break;
}
return ret;
}
static void write_fifo_8(u8 val)
{
outb (val, OMAP34XX_USB_FIFO_0);
}
static void write_bulk_fifo_8(u8 val)
{
*bulk_fifo = val;
}
static void read_request(void)
{
int i;
for (i = 0; i < 8; i++)
fastboot_fifo[i] = read_fifo_8 ();
memcpy (&req, &fastboot_fifo[0], 8);
fastboot_fifo_used = 0;
*csr0 |= MUSB_CSR0_P_SVDRXPKTRDY;
while (*csr0 & MUSB_CSR0_RXPKTRDY)
udelay(1);
}
static int do_usb_req_set_interface(void)
{
int ret = FASTBOOT_OK;
/* Only support interface 0, alternate 0 */
if ((0 == req.wIndex) &&
(0 == req.wValue))
{
fastboot_bulk_endpoint_reset ();
ACK_REQ();
}
else
{
NAK_REQ();
}
return ret;
}
static int do_usb_req_set_address(void)
{
int ret = FASTBOOT_OK;
if (0xff == faddr)
{
faddr = (u8) (req.wValue & 0x7f);
set_address = 1;
/* Check if we are in high speed mode */
if (*pwr & MUSB_POWER_HSMODE)
high_speed = 1;
else
high_speed = 0;
ACK_REQ();
}
else
{
NAK_REQ();
}
return ret;
}
static int do_usb_req_set_configuration(void)
{
int ret = FASTBOOT_OK;
if (0xff == faddr) {
NAK_REQ();
} else {
if (0 == req.wValue) {
/* spec says to go to address state.. */
faddr = 0xff;
ACK_REQ();
} else if (CONFIGURATION_NORMAL == req.wValue) {
/* This is the one! */
/* Bulk endpoint fifo */
fastboot_bulk_endpoint_reset();
ACK_REQ();
} else {
/* Only support 1 configuration so nak anything else */
NAK_REQ();
}
}
return ret;
}
static int do_usb_req_set_feature(void)
{
int ret = FASTBOOT_OK;
NAK_REQ();
return ret;
}
static int do_usb_req_get_descriptor(void)
{
int ret = FASTBOOT_OK;
if (0 == req.wLength)
{
ACK_REQ();
}
else
{
unsigned int byteLoop;
if (USB_DT_DEVICE == (req.wValue >> 8))
{
struct usb_device_descriptor d;
d.bLength = MIN(req.wLength, sizeof (d));
d.bDescriptorType = USB_DT_DEVICE;
#ifdef CONFIG_USB_1_1_DEVICE
d.bcdUSB = 0x110;
#else
d.bcdUSB = 0x200;
#endif
d.bDeviceClass = 0xff;
d.bDeviceSubClass = 0xff;
d.bDeviceProtocol = 0xff;
d.bMaxPacketSize0 = 0x40;
d.idVendor = DEVICE_VENDOR_ID;
d.idProduct = DEVICE_PRODUCT_ID;
d.bcdDevice = DEVICE_BCD;
d.iManufacturer = DEVICE_STRING_MANUFACTURER_INDEX;
d.iProduct = DEVICE_STRING_PRODUCT_INDEX;
d.iSerialNumber = DEVICE_STRING_SERIAL_NUMBER_INDEX;
d.bNumConfigurations = 1;
memcpy (&fastboot_fifo, &d, d.bLength);
for (byteLoop = 0; byteLoop < d.bLength; byteLoop++)
write_fifo_8 (fastboot_fifo[byteLoop]);
TX_LAST();
}
else if (USB_DT_CONFIG == (req.wValue >> 8))
{
struct usb_configuration_descriptor c;
struct usb_interface_descriptor i;
struct usb_endpoint_descriptor e1, e2;
unsigned char bytes_remaining = req.wLength;
unsigned char bytes_total = 0;
c.bLength = MIN(bytes_remaining, sizeof (c));
c.bDescriptorType = USB_DT_CONFIG;
/* Set this to the total we want */
c.wTotalLength = sizeof (c) + sizeof (i) + sizeof (e1) + sizeof (e2);
c.bNumInterfaces = 1;
c.bConfigurationValue = CONFIGURATION_NORMAL;
c.iConfiguration = DEVICE_STRING_CONFIG_INDEX;
c.bmAttributes = 0xc0;
c.bMaxPower = 0x32;
bytes_remaining -= c.bLength;
memcpy (&fastboot_fifo[0], &c, c.bLength);
bytes_total += c.bLength;
i.bLength = MIN (bytes_remaining, sizeof(i));
i.bDescriptorType = USB_DT_INTERFACE;
i.bInterfaceNumber = 0x00;
i.bAlternateSetting = 0x00;
i.bNumEndpoints = 0x02;
i.bInterfaceClass = FASTBOOT_INTERFACE_CLASS;
i.bInterfaceSubClass = FASTBOOT_INTERFACE_SUB_CLASS;
i.bInterfaceProtocol = FASTBOOT_INTERFACE_PROTOCOL;
i.iInterface = DEVICE_STRING_INTERFACE_INDEX;
bytes_remaining -= i.bLength;
memcpy (&fastboot_fifo[bytes_total], &i, i.bLength);
bytes_total += i.bLength;
e1.bLength = MIN (bytes_remaining, sizeof (e1));
e1.bDescriptorType = USB_DT_ENDPOINT;
e1.bEndpointAddress = 0x80 | BULK_ENDPOINT; /* IN */
e1.bmAttributes = USB_ENDPOINT_XFER_BULK;
if (high_speed)
e1.wMaxPacketSize = TX_ENDPOINT_MAXIMUM_PACKET_SIZE_2_0;
else
e1.wMaxPacketSize = TX_ENDPOINT_MAXIMUM_PACKET_SIZE_1_1;
e1.bInterval = 0x00;
bytes_remaining -= e1.bLength;
memcpy (&fastboot_fifo[bytes_total], &e1, e1.bLength);
bytes_total += e1.bLength;
e2.bLength = MIN (bytes_remaining, sizeof (e2));
e2.bDescriptorType = USB_DT_ENDPOINT;
e2.bEndpointAddress = BULK_ENDPOINT; /* OUT */
e2.bmAttributes = USB_ENDPOINT_XFER_BULK;
if (high_speed)
e2.wMaxPacketSize = RX_ENDPOINT_MAXIMUM_PACKET_SIZE_2_0;
else
e2.wMaxPacketSize = RX_ENDPOINT_MAXIMUM_PACKET_SIZE_1_1;
e2.bInterval = 0x00;
bytes_remaining -= e2.bLength;
memcpy (&fastboot_fifo[bytes_total], &e2, e2.bLength);
bytes_total += e2.bLength;
for (byteLoop = 0; byteLoop < bytes_total; byteLoop++)
write_fifo_8 (fastboot_fifo[byteLoop]);
TX_LAST();
}
else if (USB_DT_STRING == (req.wValue >> 8))
{
unsigned char bLength;
unsigned char string_index = req.wValue & 0xff;
if (string_index > DEVICE_STRING_MAX_INDEX)
{
/* Windows XP asks for an invalid string index.
Fail silently instead of doing
NAK_REQ();
*/
}
else if (0 == string_index)
{
/* Language ID */
bLength = MIN(4, req.wLength);
fastboot_fifo[0] = bLength; /* length */
fastboot_fifo[1] = USB_DT_STRING; /* descriptor = string */
fastboot_fifo[2] = DEVICE_STRING_LANGUAGE_ID & 0xff;
fastboot_fifo[3] = DEVICE_STRING_LANGUAGE_ID >> 8;
for (byteLoop = 0; byteLoop < bLength; byteLoop++)
write_fifo_8 (fastboot_fifo[byteLoop]);
TX_LAST();
}
else
{
/* Size of string in chars */
unsigned char s;
unsigned char sl = strlen (&device_strings[string_index][0]);
/* Size of descriptor
1 : header
2 : type
2*sl : string */
unsigned char bLength = 2 + (2 * sl);
bLength = MIN(bLength, req.wLength);
fastboot_fifo[0] = bLength; /* length */
fastboot_fifo[1] = USB_DT_STRING; /* descriptor = string */
/* Copy device string to fifo, expand to simple unicode */
for (s = 0; s < sl; s++)
{
fastboot_fifo[2+ 2*s + 0] = device_strings[string_index][s];
fastboot_fifo[2+ 2*s + 1] = 0;
}
for (byteLoop = 0; byteLoop < bLength; byteLoop++)
write_fifo_8 (fastboot_fifo[byteLoop]);
TX_LAST();
}
} else if (USB_DT_DEVICE_QUALIFIER == (req.wValue >> 8)) {
#ifdef CONFIG_USB_1_1_DEVICE
/* This is an invalid request for usb 1.1, nak it */
NAK_REQ();
#else
struct usb_qualifier_descriptor d;
d.bLength = MIN(req.wLength, sizeof(d));
d.bDescriptorType = USB_DT_DEVICE_QUALIFIER;
d.bcdUSB = 0x200;
d.bDeviceClass = 0xff;
d.bDeviceSubClass = 0xff;
d.bDeviceProtocol = 0xff;
d.bMaxPacketSize0 = 0x40;
d.bNumConfigurations = 1;
d.bRESERVED = 0;
memcpy(&fastboot_fifo, &d, d.bLength);
for (byteLoop = 0; byteLoop < d.bLength; byteLoop++)
write_fifo_8(fastboot_fifo[byteLoop]);
TX_LAST();
#endif
}
else
{
NAK_REQ();
}
}
return ret;
}
static int do_usb_req_get_status(void)
{
int ret = FASTBOOT_OK;
if (0 == req.wLength)
{
ACK_REQ();
}
else
{
/* See 9.4.5 */
unsigned int byteLoop;
unsigned char bLength;
bLength = MIN (req.wValue, 2);
fastboot_fifo[0] = USB_STATUS_SELFPOWERED;
fastboot_fifo[1] = 0;
for (byteLoop = 0; byteLoop < bLength; byteLoop++)
write_fifo_8 (fastboot_fifo[byteLoop]);
TX_LAST();
}
return ret;
}
static int fastboot_poll_h (void)
{
int ret = FASTBOOT_INACTIVE;
u16 count0;
if (*csr0 & MUSB_CSR0_RXPKTRDY)
{
count0 = inw (OMAP34XX_USB_COUNT0);
ret = FASTBOOT_OK;
if (count0 != 8)
{
OMAP3_LED_ERROR_ON ();
CONFUSED();
ret = FASTBOOT_ERROR;
}
else
{
read_request();
/* Check data */
if (USB_REQ_TYPE_STANDARD == (req.bmRequestType & USB_REQ_TYPE_MASK))
{
/* standard */
if (0 == (req.bmRequestType & USB_REQ_DIRECTION_MASK))
{
/* host-to-device */
if (USB_RECIP_DEVICE == (req.bmRequestType & USB_REQ_RECIPIENT_MASK))
{
/* device */
switch (req.bRequest)
{
case USB_REQ_SET_ADDRESS:
ret = do_usb_req_set_address();
break;
case USB_REQ_SET_FEATURE:
ret = do_usb_req_set_feature();
break;
case USB_REQ_SET_CONFIGURATION:
ret = do_usb_req_set_configuration();
break;
default:
NAK_REQ();
ret = FASTBOOT_ERROR;
break;
}
}
else if (USB_RECIP_INTERFACE == (req.bmRequestType & USB_REQ_RECIPIENT_MASK))
{
switch (req.bRequest)
{
case USB_REQ_SET_INTERFACE:
ret = do_usb_req_set_interface();
break;
default:
NAK_REQ();
ret = FASTBOOT_ERROR;
break;
}
}
else
{
NAK_REQ();
ret = FASTBOOT_ERROR;
}
}
else
{
/* device-to-host */
if (USB_RECIP_DEVICE == (req.bmRequestType & USB_REQ_RECIPIENT_MASK))
{
switch (req.bRequest)
{
case USB_REQ_GET_DESCRIPTOR:
ret = do_usb_req_get_descriptor();
break;
case USB_REQ_GET_STATUS:
ret = do_usb_req_get_status();
break;
default:
NAK_REQ();
ret = FASTBOOT_ERROR;
break;
}
}
else
{
NAK_REQ();
ret = FASTBOOT_ERROR;
}
}
}
else
{
/* Non-Standard Req */
NAK_REQ();
ret = FASTBOOT_ERROR;
}
}
if (FASTBOOT_OK > ret)
{
printf ("Unhandled req\n");
PRINT_REQ (req);
}
}
return ret;
}
static int fastboot_resume (void)
{
/* Here because of stall was sent */
if (*csr0 & MUSB_CSR0_P_SENTSTALL)
{
*csr0 &= ~MUSB_CSR0_P_SENTSTALL;
return FASTBOOT_OK;
}
/* Host stopped last transaction */
if (*csr0 & MUSB_CSR0_P_SETUPEND)
{
/* This should be enough .. */
*csr0 |= MUSB_CSR0_P_SVDSETUPEND;
#if 0
if (0xff != faddr)
fastboot_reset ();
/* Let the cmd layer to reset */
if (fastboot_interface &&
fastboot_interface->reset_handler)
{
fastboot_interface->reset_handler();
}
/* If we were not resetting, dropping through and handling the
poll would be fine. As it is returning now is the
right thing to do here. */
return 0;
#endif
}
/* Should we change the address ? */
if (set_address)
{
outb (faddr, OMAP34XX_USB_FADDR);
set_address = 0;
/* If you have gotten here you are mostly ok */
OMAP3_LED_OK_ON();
}
return fastboot_poll_h();
}
static void fastboot_rx_error(void)
{
/* Clear the RXPKTRDY bit */
*peri_rxcsr &= ~MUSB_RXCSR_RXPKTRDY;
/* Send stall */
*peri_rxcsr |= MUSB_RXCSR_P_SENDSTALL;
/* Wait till stall is sent.. */
while (!(*peri_rxcsr & MUSB_RXCSR_P_SENTSTALL))
udelay(1);
/* Clear stall */
*peri_rxcsr &= ~MUSB_RXCSR_P_SENTSTALL;
}
static int fastboot_rx (void)
{
int ret = FASTBOOT_INACTIVE;
if (*peri_rxcsr & MUSB_RXCSR_RXPKTRDY)
{
u16 count = *rxcount;
int fifo_size = fastboot_fifo_size();
ret = FASTBOOT_OK;
if (0 == *rxcount) {
/* Clear the RXPKTRDY bit */
*peri_rxcsr &= ~MUSB_RXCSR_RXPKTRDY;
} else if (fifo_size < count) {
fastboot_rx_error();
} else {
int i = 0;
int err = 1;
/*
* If the fifo is full, it is likely we are going to
* do a multiple packet transfere. To speed this up
* do a DMA for full packets. To keep the handling
* of the end packet simple, just do it by manually
* reading the fifo
*/
if (fifo_size == count) {
/* Mode 1
*
* The setup is not as simple as
* *peri_rxcsr |=
* (MUSB_RXCSR_DMAENAB | MUSB_RXCSR_DMAMODE)
*
* There is a special sequence needed to
* enable mode 1. This was take from
* musb_gadget.c in the 2.6.27 kernel
*/
*peri_rxcsr &= ~MUSB_RXCSR_AUTOCLEAR;
*peri_rxcsr |= MUSB_RXCSR_DMAENAB;
*peri_rxcsr |= MUSB_RXCSR_DMAMODE;
*peri_rxcsr |= MUSB_RXCSR_DMAENAB;
if (read_bulk_fifo_dma
(fastboot_bulk_fifo, fifo_size)) {
/* Failure */
fastboot_rx_error();
}
/* Disable DMA in peri_rxcsr */
*peri_rxcsr &= ~(MUSB_RXCSR_DMAENAB |
MUSB_RXCSR_DMAMODE);
} else {
for (i = 0; i < count; i++)
fastboot_bulk_fifo[i] =
read_bulk_fifo_8();
}
/* Clear the RXPKTRDY bit */
*peri_rxcsr &= ~MUSB_RXCSR_RXPKTRDY;
/* Pass this up to the interface's handler */
if (fastboot_interface &&
fastboot_interface->rx_handler) {
if (!fastboot_interface->rx_handler
(&fastboot_bulk_fifo[0], count))
err = 0;
}
/* Since the buffer is not null terminated,
* poison the buffer */
memset(&fastboot_bulk_fifo[0], 0, fifo_size);
/* If the interface did not handle the command */
if (err) {
OMAP3_LED_ERROR_ON ();
CONFUSED();
ret = FASTBOOT_ERROR;
}
}
}
return ret;
}
static int fastboot_suspend (void)
{
/* No suspending going on here!
We are polling for all its worth */
return FASTBOOT_OK;
}
int fastboot_poll(void)
{
/* No activity */
int ret = FASTBOOT_INACTIVE;
u8 intrusb;
u16 intrtx;
u16 intrrx;
if (deferred_rx)
ret = FASTBOOT_OK;
/* Look at the interrupt registers */
intrusb = inb (OMAP34XX_USB_INTRUSB);
/* A disconnect happended, this signals that the cable
has been disconnected, return immediately */
if (intrusb & OMAP34XX_USB_INTRUSB_DISCON)
return FASTBOOT_DISCONNECT;
if (intrusb & OMAP34XX_USB_INTRUSB_RESUME)
{
ret = fastboot_resume ();
if (FASTBOOT_OK > ret)
return ret;
}
else
{
if (intrusb & OMAP34XX_USB_INTRUSB_SOF)
{
ret = fastboot_resume ();
if (FASTBOOT_OK > ret)
return ret;
/* The fastboot client blocks of read and
intrrx is not reliable.
Really poll */
if (deferred_rx)
ret = fastboot_rx ();
deferred_rx = 0;
if (FASTBOOT_OK > ret)
return ret;
}
if (intrusb & OMAP34XX_USB_INTRUSB_SUSPEND)
{
ret = fastboot_suspend ();
if (FASTBOOT_OK > ret)
return ret;
}
intrtx = inw (OMAP34XX_USB_INTRTX);
if (intrtx)
{
/* TX interrupts happen when a packet has been sent
We already poll the csr register for this when
something is sent, so do not do it twice
*/
}
intrrx = inw (OMAP34XX_USB_INTRRX);
if (intrrx)
{
/* Defer this to SOF */
deferred_rx = 1;
}
}
return ret;
}
void fastboot_shutdown(void)
{
/* Let the cmd layer know that we are shutting down */
if (fastboot_interface &&
fastboot_interface->reset_handler) {
fastboot_interface->reset_handler();
}
/* Clear the SOFTCONN bit to disconnect */
*pwr &= ~MUSB_POWER_SOFTCONN;
/* Reset some globals */
faddr = 0xff;
fastboot_interface = NULL;
high_speed = 0;
deferred_rx = 0;
OMAP3_LED_ERROR_ON ();
}
int fastboot_is_highspeed(void)
{
int ret = 0;
if (*pwr & MUSB_POWER_HSMODE)
ret = 1;
return ret;
}
int fastboot_fifo_size(void)
{
return high_speed ? RX_ENDPOINT_MAXIMUM_PACKET_SIZE_2_0 : RX_ENDPOINT_MAXIMUM_PACKET_SIZE_1_1;
}
int fastboot_tx_status(const char *buffer, unsigned int buffer_size)
{
int ret = 1;
unsigned int i;
/* fastboot client only reads back at most 64 */
unsigned int transfer_size = MIN(64, buffer_size);
while (*peri_txcsr & MUSB_TXCSR_TXPKTRDY)
udelay(1);
for (i = 0; i < transfer_size; i++)
write_bulk_fifo_8 (buffer[i]);
*peri_txcsr |= MUSB_TXCSR_TXPKTRDY;
while (*peri_txcsr & MUSB_TXCSR_TXPKTRDY)
udelay(1);
/* Send an empty packet to signal that we are done */
TX_LAST();
ret = 0;
return ret;
}
int fastboot_tx(unsigned char *buffer, unsigned int buffer_size)
{
int ret = 0;
if (*peri_txcsr & MUSB_TXCSR_TXPKTRDY) {
/* Small delay if fifo is in use */
udelay(1);
} else {
unsigned int i;
/* fastboot client only reads back at most 64 */
unsigned int transfer_size =
MIN(fastboot_fifo_size(), buffer_size);
for (i = 0; i < transfer_size; i++)
write_bulk_fifo_8(buffer[i]);
*peri_txcsr |= MUSB_TXCSR_TXPKTRDY;
ret = transfer_size;
/* Send an empty packet to signal that we are done */
TX_LAST();
}
return ret;
}
int fastboot_getvar(const char *rx_buffer, char *tx_buffer)
{
/* Place board specific variables here */
return 0;
}
int fastboot_preboot(void)
{
#if (defined(CONFIG_TWL4030_KEYPAD) && (CONFIG_TWL4030_KEYPAD))
int i;
unsigned char key1, key2;
int keys;
udelay(CFG_FASTBOOT_PREBOOT_INITIAL_WAIT);
for (i = 0; i < CFG_FASTBOOT_PREBOOT_LOOP_MAXIMUM; i++) {
key1 = key2 = 0;
keys = twl4030_keypad_keys_pressed(&key1, &key2);
if ((1 == CFG_FASTBOOT_PREBOOT_KEYS) &&
(1 == keys)) {
if (CFG_FASTBOOT_PREBOOT_KEY1 == key1)
return 1;
} else if ((2 == CFG_FASTBOOT_PREBOOT_KEYS) &&
(2 == keys)) {
if ((CFG_FASTBOOT_PREBOOT_KEY1 == key1) &&
(CFG_FASTBOOT_PREBOOT_KEY2 == key2))
return 1;
}
udelay(CFG_FASTBOOT_PREBOOT_LOOP_WAIT);
}
#endif
return 0;
}
static void set_serial_number(void)
{
char *dieid = getenv("dieid#");
if (dieid == NULL) {
device_strings[DEVICE_STRING_SERIAL_NUMBER_INDEX] = "00123";
} else {
static char serial_number[32];
int len;
memset(&serial_number[0], 0, 32);
len = strlen(dieid);
if (len > 30)
len = 30;
strncpy(&serial_number[0], dieid, len);
device_strings[DEVICE_STRING_SERIAL_NUMBER_INDEX] =
&serial_number[0];
}
}
int fastboot_init(struct cmd_fastboot_interface *interface)
{
int ret = 1;
u8 devctl;
device_strings[DEVICE_STRING_MANUFACTURER_INDEX] = "Texas Instruments";
#if defined(CONFIG_3630SDP)
device_strings[DEVICE_STRING_PRODUCT_INDEX] = "SDP3630";
#elif defined(CONFIG_3430ZOOM2)
device_strings[DEVICE_STRING_PRODUCT_INDEX] = "Zoom2";
#elif defined (CONFIG_3430LABRADOR)
device_strings[DEVICE_STRING_PRODUCT_INDEX] = "Zoom";
#elif defined (CONFIG_3530OVERO)
device_strings[DEVICE_STRING_PRODUCT_INDEX] = "Overo";
#else
/* Default, An error message to prompt user */
#error "Need a product name for fastboot"
#endif
set_serial_number();
/* These are just made up */
device_strings[DEVICE_STRING_CONFIG_INDEX] = "Android Fastboot";
device_strings[DEVICE_STRING_INTERFACE_INDEX] = "Android Fastboot";
/* The interface structure */
fastboot_interface = interface;
fastboot_interface->product_name = device_strings[DEVICE_STRING_PRODUCT_INDEX];
fastboot_interface->serial_no = device_strings[DEVICE_STRING_SERIAL_NUMBER_INDEX];
fastboot_interface->nand_block_size = 2048;
fastboot_interface->nand_oob_size = 64;
fastboot_interface->transfer_buffer = (unsigned char *) CFG_FASTBOOT_TRANSFER_BUFFER;
fastboot_interface->transfer_buffer_size = CFG_FASTBOOT_TRANSFER_BUFFER_SIZE;
fastboot_reset();
/* Check if device is in b-peripheral mode */
devctl = inb (OMAP34XX_USB_DEVCTL);
if (!(devctl & MUSB_DEVCTL_BDEVICE) ||
(devctl & MUSB_DEVCTL_HM))
{
printf ("ERROR : Unsupport USB mode\n");
printf ("Check that mini-B USB cable is attached to the device\n");
}
else
{
ret = 0;
}
return ret;
}
#endif /* CONFIG_FASTBOOT */