drivers/usb: regorganisation
move to linux usb driver organisation as following drivers/usb/gadget drivers/usb/host drivers/usb/musb Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> Signed-off-by: Remy Bohmer <linux@bohmer.net>
This commit is contained in:
committed by
Remy Bohmer
parent
712ac6a1a6
commit
2731b9a866
59
drivers/usb/host/Makefile
Normal file
59
drivers/usb/host/Makefile
Normal file
@@ -0,0 +1,59 @@
|
||||
#
|
||||
# (C) Copyright 2000-2007
|
||||
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
#
|
||||
# See file CREDITS for list of people who contributed to this
|
||||
# project.
|
||||
#
|
||||
# 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 $(TOPDIR)/config.mk
|
||||
|
||||
LIB := $(obj)libusb_host.a
|
||||
|
||||
# ohci
|
||||
COBJS-$(CONFIG_USB_OHCI_NEW) += ohci-hcd.o
|
||||
COBJS-$(CONFIG_USB_ATMEL) += ohci-at91.o
|
||||
COBJS-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o
|
||||
COBJS-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o
|
||||
COBJS-$(CONFIG_USB_S3C64XX) += s3c64xx-hcd.o
|
||||
COBJS-$(CONFIG_USB_SL811HS) += sl811-hcd.o
|
||||
|
||||
# echi
|
||||
COBJS-$(CONFIG_USB_EHCI) += ehci-hcd.o
|
||||
COBJS-$(CONFIG_USB_EHCI_FSL) += ehci-fsl.o
|
||||
COBJS-$(CONFIG_USB_EHCI_IXP4XX) += ehci-ixp.o
|
||||
COBJS-$(CONFIG_USB_EHCI_PCI) += ehci-pci.o
|
||||
COBJS-$(CONFIG_USB_EHCI_VCT) += ehci-vct.o
|
||||
|
||||
COBJS := $(COBJS-y)
|
||||
SRCS := $(COBJS:.o=.c)
|
||||
OBJS := $(addprefix $(obj),$(COBJS))
|
||||
|
||||
all: $(LIB)
|
||||
|
||||
$(LIB): $(obj).depend $(OBJS)
|
||||
$(AR) $(ARFLAGS) $@ $(OBJS)
|
||||
|
||||
#########################################################################
|
||||
|
||||
# defines $(obj).depend target
|
||||
include $(SRCTREE)/rules.mk
|
||||
|
||||
sinclude $(obj).depend
|
||||
|
||||
#########################################################################
|
||||
29
drivers/usb/host/ehci-core.h
Normal file
29
drivers/usb/host/ehci-core.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/*-
|
||||
* Copyright (c) 2007-2008, Juniper Networks, Inc.
|
||||
* Copyright (c) 2008, Excito Elektronik i Skåne AB
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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 version 2 of
|
||||
* the License.
|
||||
*
|
||||
* 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 USB_EHCI_CORE_H
|
||||
#define USB_EHCI_CORE_H
|
||||
|
||||
extern int rootdev;
|
||||
extern struct ehci_hccr *hccr;
|
||||
extern volatile struct ehci_hcor *hcor;
|
||||
|
||||
#endif
|
||||
100
drivers/usb/host/ehci-fsl.c
Normal file
100
drivers/usb/host/ehci-fsl.c
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* (C) Copyright 2008, Excito Elektronik i Sk=E5ne AB
|
||||
*
|
||||
* Author: Tor Krill tor@excito.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 <pci.h>
|
||||
#include <usb.h>
|
||||
#include <mpc83xx.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/bitops.h>
|
||||
|
||||
#include "ehci.h"
|
||||
#include "ehci-fsl.h"
|
||||
#include "ehci-core.h"
|
||||
|
||||
/*
|
||||
* Create the appropriate control structures to manage
|
||||
* a new EHCI host controller.
|
||||
*
|
||||
* Excerpts from linux ehci fsl driver.
|
||||
*/
|
||||
int ehci_hcd_init(void)
|
||||
{
|
||||
volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
|
||||
uint32_t addr, temp;
|
||||
|
||||
addr = (uint32_t)&(im->usb[0]);
|
||||
hccr = (struct ehci_hccr *)(addr + FSL_SKIP_PCI);
|
||||
hcor = (struct ehci_hcor *)((uint32_t) hccr +
|
||||
HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
|
||||
|
||||
/* Configure clock */
|
||||
clrsetbits_be32(&(im->clk.sccr), MPC83XX_SCCR_USB_MASK,
|
||||
MPC83XX_SCCR_USB_DRCM_11);
|
||||
|
||||
/* Confgure interface. */
|
||||
temp = in_be32((void *)(addr + FSL_SOC_USB_CTRL));
|
||||
out_be32((void *)(addr + FSL_SOC_USB_CTRL), temp
|
||||
| REFSEL_16MHZ | UTMI_PHY_EN);
|
||||
|
||||
/* Wait for clock to stabilize */
|
||||
do {
|
||||
temp = in_be32((void *)(addr + FSL_SOC_USB_CTRL));
|
||||
udelay(1000);
|
||||
} while (!(temp & PHY_CLK_VALID));
|
||||
|
||||
/* Set to Host mode */
|
||||
temp = in_le32((void *)(addr + FSL_SOC_USB_USBMODE));
|
||||
out_le32((void *)(addr + FSL_SOC_USB_USBMODE), temp | CM_HOST);
|
||||
|
||||
out_be32((void *)(addr + FSL_SOC_USB_SNOOP1), SNOOP_SIZE_2GB);
|
||||
out_be32((void *)(addr + FSL_SOC_USB_SNOOP2),
|
||||
0x80000000 | SNOOP_SIZE_2GB);
|
||||
|
||||
/* Init phy */
|
||||
/* TODO: handle different phys? */
|
||||
out_le32(&(hcor->or_portsc[0]), PORT_PTS_UTMI);
|
||||
|
||||
/* Enable interface. */
|
||||
temp = in_be32((void *)(addr + FSL_SOC_USB_CTRL));
|
||||
out_be32((void *)(addr + FSL_SOC_USB_CTRL), temp | USB_EN);
|
||||
|
||||
out_be32((void *)(addr + FSL_SOC_USB_PRICTRL), 0x0000000c);
|
||||
out_be32((void *)(addr + FSL_SOC_USB_AGECNTTHRSH), 0x00000040);
|
||||
out_be32((void *)(addr + FSL_SOC_USB_SICTRL), 0x00000001);
|
||||
|
||||
/* Enable interface. */
|
||||
temp = in_be32((void *)(addr + FSL_SOC_USB_CTRL));
|
||||
out_be32((void *)(addr + FSL_SOC_USB_CTRL), temp | USB_EN);
|
||||
|
||||
temp = in_le32((void *)(addr + FSL_SOC_USB_USBMODE));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy the appropriate control structures corresponding
|
||||
* the the EHCI host controller.
|
||||
*/
|
||||
int ehci_hcd_stop(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
86
drivers/usb/host/ehci-fsl.h
Normal file
86
drivers/usb/host/ehci-fsl.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (c) 2005 freescale semiconductor
|
||||
* Copyright (c) 2005 MontaVista Software
|
||||
* Copyright (c) 2008 Excito Elektronik i Sk=E5ne AB
|
||||
*
|
||||
* 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 _EHCI_FSL_H
|
||||
#define _EHCI_FSL_H
|
||||
|
||||
/* Global offsets */
|
||||
#define FSL_SKIP_PCI 0x100
|
||||
|
||||
/* offsets for the non-ehci registers in the FSL SOC USB controller */
|
||||
#define FSL_SOC_USB_ULPIVP 0x170
|
||||
#define FSL_SOC_USB_PORTSC1 0x184
|
||||
#define PORT_PTS_MSK (3 << 30)
|
||||
#define PORT_PTS_UTMI (0 << 30)
|
||||
#define PORT_PTS_ULPI (2 << 30)
|
||||
#define PORT_PTS_SERIAL (3 << 30)
|
||||
#define PORT_PTS_PTW (1 << 28)
|
||||
|
||||
/* USBMODE Register bits */
|
||||
#define CM_IDLE (0 << 0)
|
||||
#define CM_RESERVED (1 << 0)
|
||||
#define CM_DEVICE (2 << 0)
|
||||
#define CM_HOST (3 << 0)
|
||||
#define USBMODE_RESERVED_2 (0 << 2)
|
||||
#define SLOM (1 << 3)
|
||||
#define SDIS (1 << 4)
|
||||
|
||||
/* CONTROL Register bits */
|
||||
#define ULPI_INT_EN (1 << 0)
|
||||
#define WU_INT_EN (1 << 1)
|
||||
#define USB_EN (1 << 2)
|
||||
#define LSF_EN (1 << 3)
|
||||
#define KEEP_OTG_ON (1 << 4)
|
||||
#define OTG_PORT (1 << 5)
|
||||
#define REFSEL_12MHZ (0 << 6)
|
||||
#define REFSEL_16MHZ (1 << 6)
|
||||
#define REFSEL_48MHZ (2 << 6)
|
||||
#define PLL_RESET (1 << 8)
|
||||
#define UTMI_PHY_EN (1 << 9)
|
||||
#define PHY_CLK_SEL_UTMI (0 << 10)
|
||||
#define PHY_CLK_SEL_ULPI (1 << 10)
|
||||
#define CLKIN_SEL_USB_CLK (0 << 11)
|
||||
#define CLKIN_SEL_USB_CLK2 (1 << 11)
|
||||
#define CLKIN_SEL_SYS_CLK (2 << 11)
|
||||
#define CLKIN_SEL_SYS_CLK2 (3 << 11)
|
||||
#define RESERVED_18 (0 << 13)
|
||||
#define RESERVED_17 (0 << 14)
|
||||
#define RESERVED_16 (0 << 15)
|
||||
#define WU_INT (1 << 16)
|
||||
#define PHY_CLK_VALID (1 << 17)
|
||||
|
||||
#define FSL_SOC_USB_PORTSC2 0x188
|
||||
#define FSL_SOC_USB_USBMODE 0x1a8
|
||||
#define FSL_SOC_USB_SNOOP1 0x400 /* NOTE: big-endian */
|
||||
#define FSL_SOC_USB_SNOOP2 0x404 /* NOTE: big-endian */
|
||||
#define FSL_SOC_USB_AGECNTTHRSH 0x408 /* NOTE: big-endian */
|
||||
#define FSL_SOC_USB_PRICTRL 0x40c /* NOTE: big-endian */
|
||||
#define FSL_SOC_USB_SICTRL 0x410 /* NOTE: big-endian */
|
||||
#define FSL_SOC_USB_CTRL 0x500 /* NOTE: big-endian */
|
||||
#define SNOOP_SIZE_2GB 0x1e
|
||||
|
||||
/* System Clock Control Register */
|
||||
#define MPC83XX_SCCR_USB_MASK 0x00f00000
|
||||
#define MPC83XX_SCCR_USB_DRCM_11 0x00300000
|
||||
#define MPC83XX_SCCR_USB_DRCM_01 0x00100000
|
||||
#define MPC83XX_SCCR_USB_DRCM_10 0x00200000
|
||||
|
||||
#endif /* _EHCI_FSL_H */
|
||||
883
drivers/usb/host/ehci-hcd.c
Normal file
883
drivers/usb/host/ehci-hcd.c
Normal file
@@ -0,0 +1,883 @@
|
||||
/*-
|
||||
* Copyright (c) 2007-2008, Juniper Networks, Inc.
|
||||
* Copyright (c) 2008, Excito Elektronik i Skåne AB
|
||||
* Copyright (c) 2008, Michael Trimarchi <trimarchimichael@yahoo.it>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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 version 2 of
|
||||
* the License.
|
||||
*
|
||||
* 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/byteorder.h>
|
||||
#include <usb.h>
|
||||
#include <asm/io.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#include "ehci.h"
|
||||
|
||||
int rootdev;
|
||||
struct ehci_hccr *hccr; /* R/O registers, not need for volatile */
|
||||
volatile struct ehci_hcor *hcor;
|
||||
|
||||
static uint16_t portreset;
|
||||
static struct QH qh_list __attribute__((aligned(32)));
|
||||
|
||||
static struct descriptor {
|
||||
struct usb_hub_descriptor hub;
|
||||
struct usb_device_descriptor device;
|
||||
struct usb_linux_config_descriptor config;
|
||||
struct usb_linux_interface_descriptor interface;
|
||||
struct usb_endpoint_descriptor endpoint;
|
||||
} __attribute__ ((packed)) descriptor = {
|
||||
{
|
||||
0x8, /* bDescLength */
|
||||
0x29, /* bDescriptorType: hub descriptor */
|
||||
2, /* bNrPorts -- runtime modified */
|
||||
0, /* wHubCharacteristics */
|
||||
0xff, /* bPwrOn2PwrGood */
|
||||
0, /* bHubCntrCurrent */
|
||||
{}, /* Device removable */
|
||||
{} /* at most 7 ports! XXX */
|
||||
},
|
||||
{
|
||||
0x12, /* bLength */
|
||||
1, /* bDescriptorType: UDESC_DEVICE */
|
||||
0x0002, /* bcdUSB: v2.0 */
|
||||
9, /* bDeviceClass: UDCLASS_HUB */
|
||||
0, /* bDeviceSubClass: UDSUBCLASS_HUB */
|
||||
1, /* bDeviceProtocol: UDPROTO_HSHUBSTT */
|
||||
64, /* bMaxPacketSize: 64 bytes */
|
||||
0x0000, /* idVendor */
|
||||
0x0000, /* idProduct */
|
||||
0x0001, /* bcdDevice */
|
||||
1, /* iManufacturer */
|
||||
2, /* iProduct */
|
||||
0, /* iSerialNumber */
|
||||
1 /* bNumConfigurations: 1 */
|
||||
},
|
||||
{
|
||||
0x9,
|
||||
2, /* bDescriptorType: UDESC_CONFIG */
|
||||
cpu_to_le16(0x19),
|
||||
1, /* bNumInterface */
|
||||
1, /* bConfigurationValue */
|
||||
0, /* iConfiguration */
|
||||
0x40, /* bmAttributes: UC_SELF_POWER */
|
||||
0 /* bMaxPower */
|
||||
},
|
||||
{
|
||||
0x9, /* bLength */
|
||||
4, /* bDescriptorType: UDESC_INTERFACE */
|
||||
0, /* bInterfaceNumber */
|
||||
0, /* bAlternateSetting */
|
||||
1, /* bNumEndpoints */
|
||||
9, /* bInterfaceClass: UICLASS_HUB */
|
||||
0, /* bInterfaceSubClass: UISUBCLASS_HUB */
|
||||
0, /* bInterfaceProtocol: UIPROTO_HSHUBSTT */
|
||||
0 /* iInterface */
|
||||
},
|
||||
{
|
||||
0x7, /* bLength */
|
||||
5, /* bDescriptorType: UDESC_ENDPOINT */
|
||||
0x81, /* bEndpointAddress:
|
||||
* UE_DIR_IN | EHCI_INTR_ENDPT
|
||||
*/
|
||||
3, /* bmAttributes: UE_INTERRUPT */
|
||||
8, 0, /* wMaxPacketSize */
|
||||
255 /* bInterval */
|
||||
},
|
||||
};
|
||||
|
||||
#if defined(CONFIG_EHCI_IS_TDI)
|
||||
#define ehci_is_TDI() (1)
|
||||
#else
|
||||
#define ehci_is_TDI() (0)
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_EHCI_DCACHE)
|
||||
/*
|
||||
* Routines to handle (flush/invalidate) the dcache for the QH and qTD
|
||||
* structures and data buffers. This is needed on platforms using this
|
||||
* EHCI support with dcache enabled.
|
||||
*/
|
||||
static void flush_invalidate(u32 addr, int size, int flush)
|
||||
{
|
||||
if (flush)
|
||||
flush_dcache_range(addr, addr + size);
|
||||
else
|
||||
invalidate_dcache_range(addr, addr + size);
|
||||
}
|
||||
|
||||
static void cache_qtd(struct qTD *qtd, int flush)
|
||||
{
|
||||
u32 *ptr = (u32 *)qtd->qt_buffer[0];
|
||||
int len = (qtd->qt_token & 0x7fff0000) >> 16;
|
||||
|
||||
flush_invalidate((u32)qtd, sizeof(struct qTD), flush);
|
||||
if (ptr && len)
|
||||
flush_invalidate((u32)ptr, len, flush);
|
||||
}
|
||||
|
||||
|
||||
static inline struct QH *qh_addr(struct QH *qh)
|
||||
{
|
||||
return (struct QH *)((u32)qh & 0xffffffe0);
|
||||
}
|
||||
|
||||
static void cache_qh(struct QH *qh, int flush)
|
||||
{
|
||||
struct qTD *qtd;
|
||||
struct qTD *next;
|
||||
static struct qTD *first_qtd;
|
||||
|
||||
/*
|
||||
* Walk the QH list and flush/invalidate all entries
|
||||
*/
|
||||
while (1) {
|
||||
flush_invalidate((u32)qh_addr(qh), sizeof(struct QH), flush);
|
||||
if ((u32)qh & QH_LINK_TYPE_QH)
|
||||
break;
|
||||
qh = qh_addr(qh);
|
||||
qh = (struct QH *)qh->qh_link;
|
||||
}
|
||||
qh = qh_addr(qh);
|
||||
|
||||
/*
|
||||
* Save first qTD pointer, needed for invalidating pass on this QH
|
||||
*/
|
||||
if (flush)
|
||||
first_qtd = qtd = (struct qTD *)(*(u32 *)&qh->qh_overlay &
|
||||
0xffffffe0);
|
||||
else
|
||||
qtd = first_qtd;
|
||||
|
||||
/*
|
||||
* Walk the qTD list and flush/invalidate all entries
|
||||
*/
|
||||
while (1) {
|
||||
if (qtd == NULL)
|
||||
break;
|
||||
cache_qtd(qtd, flush);
|
||||
next = (struct qTD *)((u32)qtd->qt_next & 0xffffffe0);
|
||||
if (next == qtd)
|
||||
break;
|
||||
qtd = next;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void ehci_flush_dcache(struct QH *qh)
|
||||
{
|
||||
cache_qh(qh, 1);
|
||||
}
|
||||
|
||||
static inline void ehci_invalidate_dcache(struct QH *qh)
|
||||
{
|
||||
cache_qh(qh, 0);
|
||||
}
|
||||
#else /* CONFIG_EHCI_DCACHE */
|
||||
/*
|
||||
*
|
||||
*/
|
||||
static inline void ehci_flush_dcache(struct QH *qh)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void ehci_invalidate_dcache(struct QH *qh)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_EHCI_DCACHE */
|
||||
|
||||
static int handshake(uint32_t *ptr, uint32_t mask, uint32_t done, int usec)
|
||||
{
|
||||
uint32_t result;
|
||||
do {
|
||||
result = ehci_readl(ptr);
|
||||
if (result == ~(uint32_t)0)
|
||||
return -1;
|
||||
result &= mask;
|
||||
if (result == done)
|
||||
return 0;
|
||||
udelay(1);
|
||||
usec--;
|
||||
} while (usec > 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void ehci_free(void *p, size_t sz)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static int ehci_reset(void)
|
||||
{
|
||||
uint32_t cmd;
|
||||
uint32_t tmp;
|
||||
uint32_t *reg_ptr;
|
||||
int ret = 0;
|
||||
|
||||
cmd = ehci_readl(&hcor->or_usbcmd);
|
||||
cmd |= CMD_RESET;
|
||||
ehci_writel(&hcor->or_usbcmd, cmd);
|
||||
ret = handshake((uint32_t *)&hcor->or_usbcmd, CMD_RESET, 0, 250 * 1000);
|
||||
if (ret < 0) {
|
||||
printf("EHCI fail to reset\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ehci_is_TDI()) {
|
||||
reg_ptr = (uint32_t *)((u8 *)hcor + USBMODE);
|
||||
tmp = ehci_readl(reg_ptr);
|
||||
tmp |= USBMODE_CM_HC;
|
||||
#if defined(CONFIG_EHCI_MMIO_BIG_ENDIAN)
|
||||
tmp |= USBMODE_BE;
|
||||
#endif
|
||||
ehci_writel(reg_ptr, tmp);
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void *ehci_alloc(size_t sz, size_t align)
|
||||
{
|
||||
static struct QH qh __attribute__((aligned(32)));
|
||||
static struct qTD td[3] __attribute__((aligned (32)));
|
||||
static int ntds;
|
||||
void *p;
|
||||
|
||||
switch (sz) {
|
||||
case sizeof(struct QH):
|
||||
p = &qh;
|
||||
ntds = 0;
|
||||
break;
|
||||
case sizeof(struct qTD):
|
||||
if (ntds == 3) {
|
||||
debug("out of TDs\n");
|
||||
return NULL;
|
||||
}
|
||||
p = &td[ntds];
|
||||
ntds++;
|
||||
break;
|
||||
default:
|
||||
debug("unknown allocation size\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(p, sz, 0);
|
||||
return p;
|
||||
}
|
||||
|
||||
static int ehci_td_buffer(struct qTD *td, void *buf, size_t sz)
|
||||
{
|
||||
uint32_t addr, delta, next;
|
||||
int idx;
|
||||
|
||||
addr = (uint32_t) buf;
|
||||
idx = 0;
|
||||
while (idx < 5) {
|
||||
td->qt_buffer[idx] = cpu_to_hc32(addr);
|
||||
next = (addr + 4096) & ~4095;
|
||||
delta = next - addr;
|
||||
if (delta >= sz)
|
||||
break;
|
||||
sz -= delta;
|
||||
addr = next;
|
||||
idx++;
|
||||
}
|
||||
|
||||
if (idx == 5) {
|
||||
debug("out of buffer pointers (%u bytes left)\n", sz);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
|
||||
int length, struct devrequest *req)
|
||||
{
|
||||
struct QH *qh;
|
||||
struct qTD *td;
|
||||
volatile struct qTD *vtd;
|
||||
unsigned long ts;
|
||||
uint32_t *tdp;
|
||||
uint32_t endpt, token, usbsts;
|
||||
uint32_t c, toggle;
|
||||
uint32_t cmd;
|
||||
int ret = 0;
|
||||
|
||||
debug("dev=%p, pipe=%lx, buffer=%p, length=%d, req=%p\n", dev, pipe,
|
||||
buffer, length, req);
|
||||
if (req != NULL)
|
||||
debug("req=%u (%#x), type=%u (%#x), value=%u (%#x), index=%u\n",
|
||||
req->request, req->request,
|
||||
req->requesttype, req->requesttype,
|
||||
le16_to_cpu(req->value), le16_to_cpu(req->value),
|
||||
le16_to_cpu(req->index));
|
||||
|
||||
qh = ehci_alloc(sizeof(struct QH), 32);
|
||||
if (qh == NULL) {
|
||||
debug("unable to allocate QH\n");
|
||||
return -1;
|
||||
}
|
||||
qh->qh_link = cpu_to_hc32((uint32_t)&qh_list | QH_LINK_TYPE_QH);
|
||||
c = (usb_pipespeed(pipe) != USB_SPEED_HIGH &&
|
||||
usb_pipeendpoint(pipe) == 0) ? 1 : 0;
|
||||
endpt = (8 << 28) |
|
||||
(c << 27) |
|
||||
(usb_maxpacket(dev, pipe) << 16) |
|
||||
(0 << 15) |
|
||||
(1 << 14) |
|
||||
(usb_pipespeed(pipe) << 12) |
|
||||
(usb_pipeendpoint(pipe) << 8) |
|
||||
(0 << 7) | (usb_pipedevice(pipe) << 0);
|
||||
qh->qh_endpt1 = cpu_to_hc32(endpt);
|
||||
endpt = (1 << 30) |
|
||||
(dev->portnr << 23) |
|
||||
(dev->parent->devnum << 16) | (0 << 8) | (0 << 0);
|
||||
qh->qh_endpt2 = cpu_to_hc32(endpt);
|
||||
qh->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
|
||||
qh->qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
|
||||
|
||||
td = NULL;
|
||||
tdp = &qh->qh_overlay.qt_next;
|
||||
|
||||
toggle =
|
||||
usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
|
||||
|
||||
if (req != NULL) {
|
||||
td = ehci_alloc(sizeof(struct qTD), 32);
|
||||
if (td == NULL) {
|
||||
debug("unable to allocate SETUP td\n");
|
||||
goto fail;
|
||||
}
|
||||
td->qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
|
||||
td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
|
||||
token = (0 << 31) |
|
||||
(sizeof(*req) << 16) |
|
||||
(0 << 15) | (0 << 12) | (3 << 10) | (2 << 8) | (0x80 << 0);
|
||||
td->qt_token = cpu_to_hc32(token);
|
||||
if (ehci_td_buffer(td, req, sizeof(*req)) != 0) {
|
||||
debug("unable construct SETUP td\n");
|
||||
ehci_free(td, sizeof(*td));
|
||||
goto fail;
|
||||
}
|
||||
*tdp = cpu_to_hc32((uint32_t) td);
|
||||
tdp = &td->qt_next;
|
||||
toggle = 1;
|
||||
}
|
||||
|
||||
if (length > 0 || req == NULL) {
|
||||
td = ehci_alloc(sizeof(struct qTD), 32);
|
||||
if (td == NULL) {
|
||||
debug("unable to allocate DATA td\n");
|
||||
goto fail;
|
||||
}
|
||||
td->qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
|
||||
td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
|
||||
token = (toggle << 31) |
|
||||
(length << 16) |
|
||||
((req == NULL ? 1 : 0) << 15) |
|
||||
(0 << 12) |
|
||||
(3 << 10) |
|
||||
((usb_pipein(pipe) ? 1 : 0) << 8) | (0x80 << 0);
|
||||
td->qt_token = cpu_to_hc32(token);
|
||||
if (ehci_td_buffer(td, buffer, length) != 0) {
|
||||
debug("unable construct DATA td\n");
|
||||
ehci_free(td, sizeof(*td));
|
||||
goto fail;
|
||||
}
|
||||
*tdp = cpu_to_hc32((uint32_t) td);
|
||||
tdp = &td->qt_next;
|
||||
}
|
||||
|
||||
if (req != NULL) {
|
||||
td = ehci_alloc(sizeof(struct qTD), 32);
|
||||
if (td == NULL) {
|
||||
debug("unable to allocate ACK td\n");
|
||||
goto fail;
|
||||
}
|
||||
td->qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
|
||||
td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
|
||||
token = (toggle << 31) |
|
||||
(0 << 16) |
|
||||
(1 << 15) |
|
||||
(0 << 12) |
|
||||
(3 << 10) |
|
||||
((usb_pipein(pipe) ? 0 : 1) << 8) | (0x80 << 0);
|
||||
td->qt_token = cpu_to_hc32(token);
|
||||
*tdp = cpu_to_hc32((uint32_t) td);
|
||||
tdp = &td->qt_next;
|
||||
}
|
||||
|
||||
qh_list.qh_link = cpu_to_hc32((uint32_t) qh | QH_LINK_TYPE_QH);
|
||||
|
||||
/* Flush dcache */
|
||||
ehci_flush_dcache(&qh_list);
|
||||
|
||||
usbsts = ehci_readl(&hcor->or_usbsts);
|
||||
ehci_writel(&hcor->or_usbsts, (usbsts & 0x3f));
|
||||
|
||||
/* Enable async. schedule. */
|
||||
cmd = ehci_readl(&hcor->or_usbcmd);
|
||||
cmd |= CMD_ASE;
|
||||
ehci_writel(&hcor->or_usbcmd, cmd);
|
||||
|
||||
ret = handshake((uint32_t *)&hcor->or_usbsts, STD_ASS, STD_ASS,
|
||||
100 * 1000);
|
||||
if (ret < 0) {
|
||||
printf("EHCI fail timeout STD_ASS set\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Wait for TDs to be processed. */
|
||||
ts = get_timer(0);
|
||||
vtd = td;
|
||||
do {
|
||||
/* Invalidate dcache */
|
||||
ehci_invalidate_dcache(&qh_list);
|
||||
token = hc32_to_cpu(vtd->qt_token);
|
||||
if (!(token & 0x80))
|
||||
break;
|
||||
} while (get_timer(ts) < CONFIG_SYS_HZ);
|
||||
|
||||
/* Disable async schedule. */
|
||||
cmd = ehci_readl(&hcor->or_usbcmd);
|
||||
cmd &= ~CMD_ASE;
|
||||
ehci_writel(&hcor->or_usbcmd, cmd);
|
||||
|
||||
ret = handshake((uint32_t *)&hcor->or_usbsts, STD_ASS, 0,
|
||||
100 * 1000);
|
||||
if (ret < 0) {
|
||||
printf("EHCI fail timeout STD_ASS reset\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
qh_list.qh_link = cpu_to_hc32((uint32_t)&qh_list | QH_LINK_TYPE_QH);
|
||||
|
||||
token = hc32_to_cpu(qh->qh_overlay.qt_token);
|
||||
if (!(token & 0x80)) {
|
||||
debug("TOKEN=%#x\n", token);
|
||||
switch (token & 0xfc) {
|
||||
case 0:
|
||||
toggle = token >> 31;
|
||||
usb_settoggle(dev, usb_pipeendpoint(pipe),
|
||||
usb_pipeout(pipe), toggle);
|
||||
dev->status = 0;
|
||||
break;
|
||||
case 0x40:
|
||||
dev->status = USB_ST_STALLED;
|
||||
break;
|
||||
case 0xa0:
|
||||
case 0x20:
|
||||
dev->status = USB_ST_BUF_ERR;
|
||||
break;
|
||||
case 0x50:
|
||||
case 0x10:
|
||||
dev->status = USB_ST_BABBLE_DET;
|
||||
break;
|
||||
default:
|
||||
dev->status = USB_ST_CRC_ERR;
|
||||
break;
|
||||
}
|
||||
dev->act_len = length - ((token >> 16) & 0x7fff);
|
||||
} else {
|
||||
dev->act_len = 0;
|
||||
debug("dev=%u, usbsts=%#x, p[1]=%#x, p[2]=%#x\n",
|
||||
dev->devnum, ehci_readl(&hcor->or_usbsts),
|
||||
ehci_readl(&hcor->or_portsc[0]),
|
||||
ehci_readl(&hcor->or_portsc[1]));
|
||||
}
|
||||
|
||||
return (dev->status != USB_ST_NOT_PROC) ? 0 : -1;
|
||||
|
||||
fail:
|
||||
td = (void *)hc32_to_cpu(qh->qh_overlay.qt_next);
|
||||
while (td != (void *)QT_NEXT_TERMINATE) {
|
||||
qh->qh_overlay.qt_next = td->qt_next;
|
||||
ehci_free(td, sizeof(*td));
|
||||
td = (void *)hc32_to_cpu(qh->qh_overlay.qt_next);
|
||||
}
|
||||
ehci_free(qh, sizeof(*qh));
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int min3(int a, int b, int c)
|
||||
{
|
||||
|
||||
if (b < a)
|
||||
a = b;
|
||||
if (c < a)
|
||||
a = c;
|
||||
return a;
|
||||
}
|
||||
|
||||
int
|
||||
ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
|
||||
int length, struct devrequest *req)
|
||||
{
|
||||
uint8_t tmpbuf[4];
|
||||
u16 typeReq;
|
||||
void *srcptr = NULL;
|
||||
int len, srclen;
|
||||
uint32_t reg;
|
||||
uint32_t *status_reg;
|
||||
|
||||
if (le16_to_cpu(req->index) >= CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
|
||||
printf("The request port(%d) is not configured\n",
|
||||
le16_to_cpu(req->index) - 1);
|
||||
return -1;
|
||||
}
|
||||
status_reg = (uint32_t *)&hcor->or_portsc[
|
||||
le16_to_cpu(req->index) - 1];
|
||||
srclen = 0;
|
||||
|
||||
debug("req=%u (%#x), type=%u (%#x), value=%u, index=%u\n",
|
||||
req->request, req->request,
|
||||
req->requesttype, req->requesttype,
|
||||
le16_to_cpu(req->value), le16_to_cpu(req->index));
|
||||
|
||||
typeReq = req->request << 8 | req->requesttype;
|
||||
|
||||
switch (le16_to_cpu(typeReq)) {
|
||||
case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
|
||||
switch (le16_to_cpu(req->value) >> 8) {
|
||||
case USB_DT_DEVICE:
|
||||
debug("USB_DT_DEVICE request\n");
|
||||
srcptr = &descriptor.device;
|
||||
srclen = 0x12;
|
||||
break;
|
||||
case USB_DT_CONFIG:
|
||||
debug("USB_DT_CONFIG config\n");
|
||||
srcptr = &descriptor.config;
|
||||
srclen = 0x19;
|
||||
break;
|
||||
case USB_DT_STRING:
|
||||
debug("USB_DT_STRING config\n");
|
||||
switch (le16_to_cpu(req->value) & 0xff) {
|
||||
case 0: /* Language */
|
||||
srcptr = "\4\3\1\0";
|
||||
srclen = 4;
|
||||
break;
|
||||
case 1: /* Vendor */
|
||||
srcptr = "\16\3u\0-\0b\0o\0o\0t\0";
|
||||
srclen = 14;
|
||||
break;
|
||||
case 2: /* Product */
|
||||
srcptr = "\52\3E\0H\0C\0I\0 "
|
||||
"\0H\0o\0s\0t\0 "
|
||||
"\0C\0o\0n\0t\0r\0o\0l\0l\0e\0r\0";
|
||||
srclen = 42;
|
||||
break;
|
||||
default:
|
||||
debug("unknown value DT_STRING %x\n",
|
||||
le16_to_cpu(req->value));
|
||||
goto unknown;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
debug("unknown value %x\n", le16_to_cpu(req->value));
|
||||
goto unknown;
|
||||
}
|
||||
break;
|
||||
case USB_REQ_GET_DESCRIPTOR | ((USB_DIR_IN | USB_RT_HUB) << 8):
|
||||
switch (le16_to_cpu(req->value) >> 8) {
|
||||
case USB_DT_HUB:
|
||||
debug("USB_DT_HUB config\n");
|
||||
srcptr = &descriptor.hub;
|
||||
srclen = 0x8;
|
||||
break;
|
||||
default:
|
||||
debug("unknown value %x\n", le16_to_cpu(req->value));
|
||||
goto unknown;
|
||||
}
|
||||
break;
|
||||
case USB_REQ_SET_ADDRESS | (USB_RECIP_DEVICE << 8):
|
||||
debug("USB_REQ_SET_ADDRESS\n");
|
||||
rootdev = le16_to_cpu(req->value);
|
||||
break;
|
||||
case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
|
||||
debug("USB_REQ_SET_CONFIGURATION\n");
|
||||
/* Nothing to do */
|
||||
break;
|
||||
case USB_REQ_GET_STATUS | ((USB_DIR_IN | USB_RT_HUB) << 8):
|
||||
tmpbuf[0] = 1; /* USB_STATUS_SELFPOWERED */
|
||||
tmpbuf[1] = 0;
|
||||
srcptr = tmpbuf;
|
||||
srclen = 2;
|
||||
break;
|
||||
case USB_REQ_GET_STATUS | ((USB_RT_PORT | USB_DIR_IN) << 8):
|
||||
memset(tmpbuf, 0, 4);
|
||||
reg = ehci_readl(status_reg);
|
||||
if (reg & EHCI_PS_CS)
|
||||
tmpbuf[0] |= USB_PORT_STAT_CONNECTION;
|
||||
if (reg & EHCI_PS_PE)
|
||||
tmpbuf[0] |= USB_PORT_STAT_ENABLE;
|
||||
if (reg & EHCI_PS_SUSP)
|
||||
tmpbuf[0] |= USB_PORT_STAT_SUSPEND;
|
||||
if (reg & EHCI_PS_OCA)
|
||||
tmpbuf[0] |= USB_PORT_STAT_OVERCURRENT;
|
||||
if (reg & EHCI_PS_PR &&
|
||||
(portreset & (1 << le16_to_cpu(req->index)))) {
|
||||
int ret;
|
||||
/* force reset to complete */
|
||||
reg = reg & ~(EHCI_PS_PR | EHCI_PS_CLEAR);
|
||||
ehci_writel(status_reg, reg);
|
||||
ret = handshake(status_reg, EHCI_PS_PR, 0, 2 * 1000);
|
||||
if (!ret)
|
||||
tmpbuf[0] |= USB_PORT_STAT_RESET;
|
||||
else
|
||||
printf("port(%d) reset error\n",
|
||||
le16_to_cpu(req->index) - 1);
|
||||
}
|
||||
if (reg & EHCI_PS_PP)
|
||||
tmpbuf[1] |= USB_PORT_STAT_POWER >> 8;
|
||||
|
||||
if (ehci_is_TDI()) {
|
||||
switch ((reg >> 26) & 3) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
tmpbuf[1] |= USB_PORT_STAT_LOW_SPEED >> 8;
|
||||
break;
|
||||
case 2:
|
||||
default:
|
||||
tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8;
|
||||
}
|
||||
|
||||
if (reg & EHCI_PS_CSC)
|
||||
tmpbuf[2] |= USB_PORT_STAT_C_CONNECTION;
|
||||
if (reg & EHCI_PS_PEC)
|
||||
tmpbuf[2] |= USB_PORT_STAT_C_ENABLE;
|
||||
if (reg & EHCI_PS_OCC)
|
||||
tmpbuf[2] |= USB_PORT_STAT_C_OVERCURRENT;
|
||||
if (portreset & (1 << le16_to_cpu(req->index)))
|
||||
tmpbuf[2] |= USB_PORT_STAT_C_RESET;
|
||||
|
||||
srcptr = tmpbuf;
|
||||
srclen = 4;
|
||||
break;
|
||||
case USB_REQ_SET_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8):
|
||||
reg = ehci_readl(status_reg);
|
||||
reg &= ~EHCI_PS_CLEAR;
|
||||
switch (le16_to_cpu(req->value)) {
|
||||
case USB_PORT_FEAT_ENABLE:
|
||||
reg |= EHCI_PS_PE;
|
||||
ehci_writel(status_reg, reg);
|
||||
break;
|
||||
case USB_PORT_FEAT_POWER:
|
||||
if (HCS_PPC(ehci_readl(&hccr->cr_hcsparams))) {
|
||||
reg |= EHCI_PS_PP;
|
||||
ehci_writel(status_reg, reg);
|
||||
}
|
||||
break;
|
||||
case USB_PORT_FEAT_RESET:
|
||||
if ((reg & (EHCI_PS_PE | EHCI_PS_CS)) == EHCI_PS_CS &&
|
||||
!ehci_is_TDI() &&
|
||||
EHCI_PS_IS_LOWSPEED(reg)) {
|
||||
/* Low speed device, give up ownership. */
|
||||
debug("port %d low speed --> companion\n",
|
||||
req->index - 1);
|
||||
reg |= EHCI_PS_PO;
|
||||
ehci_writel(status_reg, reg);
|
||||
break;
|
||||
} else {
|
||||
reg |= EHCI_PS_PR;
|
||||
reg &= ~EHCI_PS_PE;
|
||||
ehci_writel(status_reg, reg);
|
||||
/*
|
||||
* caller must wait, then call GetPortStatus
|
||||
* usb 2.0 specification say 50 ms resets on
|
||||
* root
|
||||
*/
|
||||
wait_ms(50);
|
||||
portreset |= 1 << le16_to_cpu(req->index);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
debug("unknown feature %x\n", le16_to_cpu(req->value));
|
||||
goto unknown;
|
||||
}
|
||||
/* unblock posted writes */
|
||||
ehci_readl(&hcor->or_usbcmd);
|
||||
break;
|
||||
case USB_REQ_CLEAR_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8):
|
||||
reg = ehci_readl(status_reg);
|
||||
switch (le16_to_cpu(req->value)) {
|
||||
case USB_PORT_FEAT_ENABLE:
|
||||
reg &= ~EHCI_PS_PE;
|
||||
break;
|
||||
case USB_PORT_FEAT_C_ENABLE:
|
||||
reg = (reg & ~EHCI_PS_CLEAR) | EHCI_PS_PE;
|
||||
break;
|
||||
case USB_PORT_FEAT_POWER:
|
||||
if (HCS_PPC(ehci_readl(&hccr->cr_hcsparams)))
|
||||
reg = reg & ~(EHCI_PS_CLEAR | EHCI_PS_PP);
|
||||
case USB_PORT_FEAT_C_CONNECTION:
|
||||
reg = (reg & ~EHCI_PS_CLEAR) | EHCI_PS_CSC;
|
||||
break;
|
||||
case USB_PORT_FEAT_OVER_CURRENT:
|
||||
reg = (reg & ~EHCI_PS_CLEAR) | EHCI_PS_OCC;
|
||||
break;
|
||||
case USB_PORT_FEAT_C_RESET:
|
||||
portreset &= ~(1 << le16_to_cpu(req->index));
|
||||
break;
|
||||
default:
|
||||
debug("unknown feature %x\n", le16_to_cpu(req->value));
|
||||
goto unknown;
|
||||
}
|
||||
ehci_writel(status_reg, reg);
|
||||
/* unblock posted write */
|
||||
ehci_readl(&hcor->or_usbcmd);
|
||||
break;
|
||||
default:
|
||||
debug("Unknown request\n");
|
||||
goto unknown;
|
||||
}
|
||||
|
||||
wait_ms(1);
|
||||
len = min3(srclen, le16_to_cpu(req->length), length);
|
||||
if (srcptr != NULL && len > 0)
|
||||
memcpy(buffer, srcptr, len);
|
||||
else
|
||||
debug("Len is 0\n");
|
||||
|
||||
dev->act_len = len;
|
||||
dev->status = 0;
|
||||
return 0;
|
||||
|
||||
unknown:
|
||||
debug("requesttype=%x, request=%x, value=%x, index=%x, length=%x\n",
|
||||
req->requesttype, req->request, le16_to_cpu(req->value),
|
||||
le16_to_cpu(req->index), le16_to_cpu(req->length));
|
||||
|
||||
dev->act_len = 0;
|
||||
dev->status = USB_ST_STALLED;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int usb_lowlevel_stop(void)
|
||||
{
|
||||
return ehci_hcd_stop();
|
||||
}
|
||||
|
||||
int usb_lowlevel_init(void)
|
||||
{
|
||||
uint32_t reg;
|
||||
uint32_t cmd;
|
||||
|
||||
if (ehci_hcd_init() != 0)
|
||||
return -1;
|
||||
|
||||
/* EHCI spec section 4.1 */
|
||||
if (ehci_reset() != 0)
|
||||
return -1;
|
||||
|
||||
#if defined(CONFIG_EHCI_HCD_INIT_AFTER_RESET)
|
||||
if (ehci_hcd_init() != 0)
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
/* Set head of reclaim list */
|
||||
memset(&qh_list, 0, sizeof(qh_list));
|
||||
qh_list.qh_link = cpu_to_hc32((uint32_t)&qh_list | QH_LINK_TYPE_QH);
|
||||
qh_list.qh_endpt1 = cpu_to_hc32((1 << 15) | (USB_SPEED_HIGH << 12));
|
||||
qh_list.qh_curtd = cpu_to_hc32(QT_NEXT_TERMINATE);
|
||||
qh_list.qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
|
||||
qh_list.qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
|
||||
qh_list.qh_overlay.qt_token = cpu_to_hc32(0x40);
|
||||
|
||||
/* Set async. queue head pointer. */
|
||||
ehci_writel(&hcor->or_asynclistaddr, (uint32_t)&qh_list);
|
||||
|
||||
reg = ehci_readl(&hccr->cr_hcsparams);
|
||||
descriptor.hub.bNbrPorts = HCS_N_PORTS(reg);
|
||||
printf("Register %x NbrPorts %d\n", reg, descriptor.hub.bNbrPorts);
|
||||
/* Port Indicators */
|
||||
if (HCS_INDICATOR(reg))
|
||||
descriptor.hub.wHubCharacteristics |= 0x80;
|
||||
/* Port Power Control */
|
||||
if (HCS_PPC(reg))
|
||||
descriptor.hub.wHubCharacteristics |= 0x01;
|
||||
|
||||
/* Start the host controller. */
|
||||
cmd = ehci_readl(&hcor->or_usbcmd);
|
||||
/*
|
||||
* Philips, Intel, and maybe others need CMD_RUN before the
|
||||
* root hub will detect new devices (why?); NEC doesn't
|
||||
*/
|
||||
cmd &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET);
|
||||
cmd |= CMD_RUN;
|
||||
ehci_writel(&hcor->or_usbcmd, cmd);
|
||||
|
||||
/* take control over the ports */
|
||||
cmd = ehci_readl(&hcor->or_configflag);
|
||||
cmd |= FLAG_CF;
|
||||
ehci_writel(&hcor->or_configflag, cmd);
|
||||
/* unblock posted write */
|
||||
cmd = ehci_readl(&hcor->or_usbcmd);
|
||||
wait_ms(5);
|
||||
reg = HC_VERSION(ehci_readl(&hccr->cr_capbase));
|
||||
printf("USB EHCI %x.%02x\n", reg >> 8, reg & 0xff);
|
||||
|
||||
rootdev = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
|
||||
int length)
|
||||
{
|
||||
|
||||
if (usb_pipetype(pipe) != PIPE_BULK) {
|
||||
debug("non-bulk pipe (type=%lu)", usb_pipetype(pipe));
|
||||
return -1;
|
||||
}
|
||||
return ehci_submit_async(dev, pipe, buffer, length, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
|
||||
int length, struct devrequest *setup)
|
||||
{
|
||||
|
||||
if (usb_pipetype(pipe) != PIPE_CONTROL) {
|
||||
debug("non-control pipe (type=%lu)", usb_pipetype(pipe));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (usb_pipedevice(pipe) == rootdev) {
|
||||
if (rootdev == 0)
|
||||
dev->speed = USB_SPEED_HIGH;
|
||||
return ehci_submit_root(dev, pipe, buffer, length, setup);
|
||||
}
|
||||
return ehci_submit_async(dev, pipe, buffer, length, setup);
|
||||
}
|
||||
|
||||
int
|
||||
submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
|
||||
int length, int interval)
|
||||
{
|
||||
|
||||
debug("dev=%p, pipe=%lu, buffer=%p, length=%d, interval=%d",
|
||||
dev, pipe, buffer, length, interval);
|
||||
return -1;
|
||||
}
|
||||
50
drivers/usb/host/ehci-ixp4xx.c
Normal file
50
drivers/usb/host/ehci-ixp4xx.c
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* (C) Copyright 2008, Michael Trimarchi <trimarchimichael@yahoo.it>
|
||||
*
|
||||
* Author: Michael Trimarchi <trimarchimichael@yahoo.it>
|
||||
* This code is based on ehci freescale driver
|
||||
*
|
||||
* 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 <usb.h>
|
||||
|
||||
#include "ehci.h"
|
||||
#include "ehci-core.h"
|
||||
/*
|
||||
* Create the appropriate control structures to manage
|
||||
* a new EHCI host controller.
|
||||
*/
|
||||
int ehci_hcd_init(void)
|
||||
{
|
||||
hccr = (struct ehci_hccr *)(0xcd000100);
|
||||
hcor = (struct ehci_hcor *)((uint32_t) hccr
|
||||
+ HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
|
||||
|
||||
printf("IXP4XX init hccr %x and hcor %x hc_length %d\n",
|
||||
(uint32_t)hccr, (uint32_t)hcor,
|
||||
(uint32_t)HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy the appropriate control structures corresponding
|
||||
* the the EHCI host controller.
|
||||
*/
|
||||
int ehci_hcd_stop(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
65
drivers/usb/host/ehci-pci.c
Normal file
65
drivers/usb/host/ehci-pci.c
Normal file
@@ -0,0 +1,65 @@
|
||||
/*-
|
||||
* Copyright (c) 2007-2008, Juniper Networks, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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 version 2 of
|
||||
* the License.
|
||||
*
|
||||
* 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 <pci.h>
|
||||
#include <usb.h>
|
||||
|
||||
#include "ehci.h"
|
||||
#include "ehci-core.h"
|
||||
|
||||
#ifdef CONFIG_PCI_EHCI_DEVICE
|
||||
static struct pci_device_id ehci_pci_ids[] = {
|
||||
/* Please add supported PCI EHCI controller ids here */
|
||||
{0, 0}
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Create the appropriate control structures to manage
|
||||
* a new EHCI host controller.
|
||||
*/
|
||||
int ehci_hcd_init(void)
|
||||
{
|
||||
pci_dev_t pdev;
|
||||
uint32_t addr;
|
||||
|
||||
pdev = pci_find_devices(ehci_pci_ids, CONFIG_PCI_EHCI_DEVICE);
|
||||
if (pdev == -1) {
|
||||
printf("EHCI host controller not found\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &addr);
|
||||
hccr = (struct ehci_hccr *)addr;
|
||||
hcor = (struct ehci_hcor *)((uint32_t) hccr +
|
||||
HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy the appropriate control structures corresponding
|
||||
* the the EHCI host controller.
|
||||
*/
|
||||
int ehci_hcd_stop(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
58
drivers/usb/host/ehci-vct.c
Normal file
58
drivers/usb/host/ehci-vct.c
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* (C) Copyright 2009 Stefan Roese <sr@denx.de>, DENX Software Engineering
|
||||
*
|
||||
* 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 <usb.h>
|
||||
|
||||
#include "ehci.h"
|
||||
#include "ehci-core.h"
|
||||
|
||||
int vct_ehci_hcd_init(u32 *hccr, u32 *hcor);
|
||||
|
||||
/*
|
||||
* Create the appropriate control structures to manage
|
||||
* a new EHCI host controller.
|
||||
*/
|
||||
int ehci_hcd_init(void)
|
||||
{
|
||||
int ret;
|
||||
u32 vct_hccr;
|
||||
u32 vct_hcor;
|
||||
|
||||
/*
|
||||
* Init VCT specific stuff
|
||||
*/
|
||||
ret = vct_ehci_hcd_init(&vct_hccr, &vct_hcor);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
hccr = (struct ehci_hccr *)vct_hccr;
|
||||
hcor = (struct ehci_hcor *)vct_hcor;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy the appropriate control structures corresponding
|
||||
* the the EHCI host controller.
|
||||
*/
|
||||
int ehci_hcd_stop(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
194
drivers/usb/host/ehci.h
Normal file
194
drivers/usb/host/ehci.h
Normal file
@@ -0,0 +1,194 @@
|
||||
/*-
|
||||
* Copyright (c) 2007-2008, Juniper Networks, Inc.
|
||||
* Copyright (c) 2008, Michael Trimarchi <trimarchimichael@yahoo.it>
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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 version 2 of
|
||||
* the License.
|
||||
*
|
||||
* 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 USB_EHCI_H
|
||||
#define USB_EHCI_H
|
||||
|
||||
#if !defined(CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS)
|
||||
#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 2
|
||||
#endif
|
||||
|
||||
/* (shifted) direction/type/recipient from the USB 2.0 spec, table 9.2 */
|
||||
#define DeviceRequest \
|
||||
((USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE) << 8)
|
||||
|
||||
#define DeviceOutRequest \
|
||||
((USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE) << 8)
|
||||
|
||||
#define InterfaceRequest \
|
||||
((USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_INTERFACE) << 8)
|
||||
|
||||
#define EndpointRequest \
|
||||
((USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_INTERFACE) << 8)
|
||||
|
||||
#define EndpointOutRequest \
|
||||
((USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_INTERFACE) << 8)
|
||||
|
||||
/*
|
||||
* Register Space.
|
||||
*/
|
||||
struct ehci_hccr {
|
||||
uint32_t cr_capbase;
|
||||
#define HC_LENGTH(p) (((p) >> 0) & 0x00ff)
|
||||
#define HC_VERSION(p) (((p) >> 16) & 0xffff)
|
||||
uint32_t cr_hcsparams;
|
||||
#define HCS_PPC(p) ((p) & (1 << 4))
|
||||
#define HCS_INDICATOR(p) ((p) & (1 << 16)) /* Port indicators */
|
||||
#define HCS_N_PORTS(p) (((p) >> 0) & 0xf)
|
||||
uint32_t cr_hccparams;
|
||||
uint8_t cr_hcsp_portrt[8];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ehci_hcor {
|
||||
uint32_t or_usbcmd;
|
||||
#define CMD_PARK (1 << 11) /* enable "park" */
|
||||
#define CMD_PARK_CNT(c) (((c) >> 8) & 3) /* how many transfers to park */
|
||||
#define CMD_ASE (1 << 5) /* async schedule enable */
|
||||
#define CMD_LRESET (1 << 7) /* partial reset */
|
||||
#define CMD_IAAD (1 << 5) /* "doorbell" interrupt */
|
||||
#define CMD_PSE (1 << 4) /* periodic schedule enable */
|
||||
#define CMD_RESET (1 << 1) /* reset HC not bus */
|
||||
#define CMD_RUN (1 << 0) /* start/stop HC */
|
||||
uint32_t or_usbsts;
|
||||
#define STD_ASS (1 << 15)
|
||||
#define STS_HALT (1 << 12)
|
||||
uint32_t or_usbintr;
|
||||
uint32_t or_frindex;
|
||||
uint32_t or_ctrldssegment;
|
||||
uint32_t or_periodiclistbase;
|
||||
uint32_t or_asynclistaddr;
|
||||
uint32_t _reserved_[9];
|
||||
uint32_t or_configflag;
|
||||
#define FLAG_CF (1 << 0) /* true: we'll support "high speed" */
|
||||
uint32_t or_portsc[CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS];
|
||||
uint32_t or_systune;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define USBMODE 0x68 /* USB Device mode */
|
||||
#define USBMODE_SDIS (1 << 3) /* Stream disable */
|
||||
#define USBMODE_BE (1 << 2) /* BE/LE endiannes select */
|
||||
#define USBMODE_CM_HC (3 << 0) /* host controller mode */
|
||||
#define USBMODE_CM_IDLE (0 << 0) /* idle state */
|
||||
|
||||
/* Interface descriptor */
|
||||
struct usb_linux_interface_descriptor {
|
||||
unsigned char bLength;
|
||||
unsigned char bDescriptorType;
|
||||
unsigned char bInterfaceNumber;
|
||||
unsigned char bAlternateSetting;
|
||||
unsigned char bNumEndpoints;
|
||||
unsigned char bInterfaceClass;
|
||||
unsigned char bInterfaceSubClass;
|
||||
unsigned char bInterfaceProtocol;
|
||||
unsigned char iInterface;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Configuration descriptor information.. */
|
||||
struct usb_linux_config_descriptor {
|
||||
unsigned char bLength;
|
||||
unsigned char bDescriptorType;
|
||||
unsigned short wTotalLength;
|
||||
unsigned char bNumInterfaces;
|
||||
unsigned char bConfigurationValue;
|
||||
unsigned char iConfiguration;
|
||||
unsigned char bmAttributes;
|
||||
unsigned char MaxPower;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#if defined CONFIG_EHCI_DESC_BIG_ENDIAN
|
||||
#define ehci_readl(x) (*((volatile u32 *)(x)))
|
||||
#define ehci_writel(a, b) (*((volatile u32 *)(a)) = ((volatile u32)b))
|
||||
#else
|
||||
#define ehci_readl(x) cpu_to_le32((*((volatile u32 *)(x))))
|
||||
#define ehci_writel(a, b) (*((volatile u32 *)(a)) = \
|
||||
cpu_to_le32(((volatile u32)b)))
|
||||
#endif
|
||||
|
||||
#if defined CONFIG_EHCI_MMIO_BIG_ENDIAN
|
||||
#define hc32_to_cpu(x) be32_to_cpu((x))
|
||||
#define cpu_to_hc32(x) cpu_to_be32((x))
|
||||
#else
|
||||
#define hc32_to_cpu(x) le32_to_cpu((x))
|
||||
#define cpu_to_hc32(x) cpu_to_le32((x))
|
||||
#endif
|
||||
|
||||
#define EHCI_PS_WKOC_E (1 << 22) /* RW wake on over current */
|
||||
#define EHCI_PS_WKDSCNNT_E (1 << 21) /* RW wake on disconnect */
|
||||
#define EHCI_PS_WKCNNT_E (1 << 20) /* RW wake on connect */
|
||||
#define EHCI_PS_PO (1 << 13) /* RW port owner */
|
||||
#define EHCI_PS_PP (1 << 12) /* RW,RO port power */
|
||||
#define EHCI_PS_LS (3 << 10) /* RO line status */
|
||||
#define EHCI_PS_PR (1 << 8) /* RW port reset */
|
||||
#define EHCI_PS_SUSP (1 << 7) /* RW suspend */
|
||||
#define EHCI_PS_FPR (1 << 6) /* RW force port resume */
|
||||
#define EHCI_PS_OCC (1 << 5) /* RWC over current change */
|
||||
#define EHCI_PS_OCA (1 << 4) /* RO over current active */
|
||||
#define EHCI_PS_PEC (1 << 3) /* RWC port enable change */
|
||||
#define EHCI_PS_PE (1 << 2) /* RW port enable */
|
||||
#define EHCI_PS_CSC (1 << 1) /* RWC connect status change */
|
||||
#define EHCI_PS_CS (1 << 0) /* RO connect status */
|
||||
#define EHCI_PS_CLEAR (EHCI_PS_OCC | EHCI_PS_PEC | EHCI_PS_CSC)
|
||||
|
||||
#define EHCI_PS_IS_LOWSPEED(x) (((x) & EHCI_PS_LS) == (1 << 10))
|
||||
|
||||
/*
|
||||
* Schedule Interface Space.
|
||||
*
|
||||
* IMPORTANT: Software must ensure that no interface data structure
|
||||
* reachable by the EHCI host controller spans a 4K page boundary!
|
||||
*
|
||||
* Periodic transfers (i.e. isochronous and interrupt transfers) are
|
||||
* not supported.
|
||||
*/
|
||||
|
||||
/* Queue Element Transfer Descriptor (qTD). */
|
||||
struct qTD {
|
||||
uint32_t qt_next;
|
||||
#define QT_NEXT_TERMINATE 1
|
||||
uint32_t qt_altnext;
|
||||
uint32_t qt_token;
|
||||
uint32_t qt_buffer[5];
|
||||
};
|
||||
|
||||
/* Queue Head (QH). */
|
||||
struct QH {
|
||||
uint32_t qh_link;
|
||||
#define QH_LINK_TERMINATE 1
|
||||
#define QH_LINK_TYPE_ITD 0
|
||||
#define QH_LINK_TYPE_QH 2
|
||||
#define QH_LINK_TYPE_SITD 4
|
||||
#define QH_LINK_TYPE_FSTN 6
|
||||
uint32_t qh_endpt1;
|
||||
uint32_t qh_endpt2;
|
||||
uint32_t qh_curtd;
|
||||
struct qTD qh_overlay;
|
||||
/*
|
||||
* Add dummy fill value to make the size of this struct
|
||||
* aligned to 32 bytes
|
||||
*/
|
||||
uint8_t fill[16];
|
||||
};
|
||||
|
||||
/* Low level init functions */
|
||||
int ehci_hcd_init(void);
|
||||
int ehci_hcd_stop(void);
|
||||
|
||||
#endif /* USB_EHCI_H */
|
||||
1441
drivers/usb/host/isp116x-hcd.c
Normal file
1441
drivers/usb/host/isp116x-hcd.c
Normal file
File diff suppressed because it is too large
Load Diff
489
drivers/usb/host/isp116x.h
Normal file
489
drivers/usb/host/isp116x.h
Normal file
@@ -0,0 +1,489 @@
|
||||
/*
|
||||
* ISP116x register declarations and HCD data structures
|
||||
*
|
||||
* Copyright (C) 2007 Rodolfo Giometti <giometti@linux.it>
|
||||
* Copyright (C) 2007 Eurotech S.p.A. <info@eurotech.it>
|
||||
* Copyright (C) 2005 Olav Kongas <ok@artecdesign.ee>
|
||||
* Portions:
|
||||
* Copyright (C) 2004 Lothar Wassmann
|
||||
* Copyright (C) 2004 Psion Teklogix
|
||||
* Copyright (C) 2004 David Brownell
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DBG(fmt, args...) \
|
||||
printf("isp116x: %s: " fmt "\n" , __FUNCTION__ , ## args)
|
||||
#else
|
||||
#define DBG(fmt, args...) do {} while (0)
|
||||
#endif
|
||||
|
||||
#ifdef VERBOSE
|
||||
# define VDBG DBG
|
||||
#else
|
||||
# define VDBG(fmt, args...) do {} while (0)
|
||||
#endif
|
||||
|
||||
#define ERR(fmt, args...) \
|
||||
printf("isp116x: %s: " fmt "\n" , __FUNCTION__ , ## args)
|
||||
#define WARN(fmt, args...) \
|
||||
printf("isp116x: %s: " fmt "\n" , __FUNCTION__ , ## args)
|
||||
#define INFO(fmt, args...) \
|
||||
printf("isp116x: " fmt "\n" , ## args)
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/* us of 1ms frame */
|
||||
#define MAX_LOAD_LIMIT 850
|
||||
|
||||
/* Full speed: max # of bytes to transfer for a single urb
|
||||
at a time must be < 1024 && must be multiple of 64.
|
||||
832 allows transfering 4kiB within 5 frames. */
|
||||
#define MAX_TRANSFER_SIZE_FULLSPEED 832
|
||||
|
||||
/* Low speed: there is no reason to schedule in very big
|
||||
chunks; often the requested long transfers are for
|
||||
string descriptors containing short strings. */
|
||||
#define MAX_TRANSFER_SIZE_LOWSPEED 64
|
||||
|
||||
/* Bytetime (us), a rough indication of how much time it
|
||||
would take to transfer a byte of useful data over USB */
|
||||
#define BYTE_TIME_FULLSPEED 1
|
||||
#define BYTE_TIME_LOWSPEED 20
|
||||
|
||||
/* Buffer sizes */
|
||||
#define ISP116x_BUF_SIZE 4096
|
||||
#define ISP116x_ITL_BUFSIZE 0
|
||||
#define ISP116x_ATL_BUFSIZE ((ISP116x_BUF_SIZE) - 2*(ISP116x_ITL_BUFSIZE))
|
||||
|
||||
#define ISP116x_WRITE_OFFSET 0x80
|
||||
|
||||
/* --- ISP116x registers/bits ---------------------------------------------- */
|
||||
|
||||
#define HCREVISION 0x00
|
||||
#define HCCONTROL 0x01
|
||||
#define HCCONTROL_HCFS (3 << 6) /* host controller
|
||||
functional state */
|
||||
#define HCCONTROL_USB_RESET (0 << 6)
|
||||
#define HCCONTROL_USB_RESUME (1 << 6)
|
||||
#define HCCONTROL_USB_OPER (2 << 6)
|
||||
#define HCCONTROL_USB_SUSPEND (3 << 6)
|
||||
#define HCCONTROL_RWC (1 << 9) /* remote wakeup connected */
|
||||
#define HCCONTROL_RWE (1 << 10) /* remote wakeup enable */
|
||||
#define HCCMDSTAT 0x02
|
||||
#define HCCMDSTAT_HCR (1 << 0) /* host controller reset */
|
||||
#define HCCMDSTAT_SOC (3 << 16) /* scheduling overrun count */
|
||||
#define HCINTSTAT 0x03
|
||||
#define HCINT_SO (1 << 0) /* scheduling overrun */
|
||||
#define HCINT_WDH (1 << 1) /* writeback of done_head */
|
||||
#define HCINT_SF (1 << 2) /* start frame */
|
||||
#define HCINT_RD (1 << 3) /* resume detect */
|
||||
#define HCINT_UE (1 << 4) /* unrecoverable error */
|
||||
#define HCINT_FNO (1 << 5) /* frame number overflow */
|
||||
#define HCINT_RHSC (1 << 6) /* root hub status change */
|
||||
#define HCINT_OC (1 << 30) /* ownership change */
|
||||
#define HCINT_MIE (1 << 31) /* master interrupt enable */
|
||||
#define HCINTENB 0x04
|
||||
#define HCINTDIS 0x05
|
||||
#define HCFMINTVL 0x0d
|
||||
#define HCFMREM 0x0e
|
||||
#define HCFMNUM 0x0f
|
||||
#define HCLSTHRESH 0x11
|
||||
#define HCRHDESCA 0x12
|
||||
#define RH_A_NDP (0x3 << 0) /* # downstream ports */
|
||||
#define RH_A_PSM (1 << 8) /* power switching mode */
|
||||
#define RH_A_NPS (1 << 9) /* no power switching */
|
||||
#define RH_A_DT (1 << 10) /* device type (mbz) */
|
||||
#define RH_A_OCPM (1 << 11) /* overcurrent protection
|
||||
mode */
|
||||
#define RH_A_NOCP (1 << 12) /* no overcurrent protection */
|
||||
#define RH_A_POTPGT (0xff << 24) /* power on -> power good
|
||||
time */
|
||||
#define HCRHDESCB 0x13
|
||||
#define RH_B_DR (0xffff << 0) /* device removable flags */
|
||||
#define RH_B_PPCM (0xffff << 16) /* port power control mask */
|
||||
#define HCRHSTATUS 0x14
|
||||
#define RH_HS_LPS (1 << 0) /* local power status */
|
||||
#define RH_HS_OCI (1 << 1) /* over current indicator */
|
||||
#define RH_HS_DRWE (1 << 15) /* device remote wakeup
|
||||
enable */
|
||||
#define RH_HS_LPSC (1 << 16) /* local power status change */
|
||||
#define RH_HS_OCIC (1 << 17) /* over current indicator
|
||||
change */
|
||||
#define RH_HS_CRWE (1 << 31) /* clear remote wakeup
|
||||
enable */
|
||||
#define HCRHPORT1 0x15
|
||||
#define RH_PS_CCS (1 << 0) /* current connect status */
|
||||
#define RH_PS_PES (1 << 1) /* port enable status */
|
||||
#define RH_PS_PSS (1 << 2) /* port suspend status */
|
||||
#define RH_PS_POCI (1 << 3) /* port over current
|
||||
indicator */
|
||||
#define RH_PS_PRS (1 << 4) /* port reset status */
|
||||
#define RH_PS_PPS (1 << 8) /* port power status */
|
||||
#define RH_PS_LSDA (1 << 9) /* low speed device attached */
|
||||
#define RH_PS_CSC (1 << 16) /* connect status change */
|
||||
#define RH_PS_PESC (1 << 17) /* port enable status change */
|
||||
#define RH_PS_PSSC (1 << 18) /* port suspend status
|
||||
change */
|
||||
#define RH_PS_OCIC (1 << 19) /* over current indicator
|
||||
change */
|
||||
#define RH_PS_PRSC (1 << 20) /* port reset status change */
|
||||
#define HCRHPORT_CLRMASK (0x1f << 16)
|
||||
#define HCRHPORT2 0x16
|
||||
#define HCHWCFG 0x20
|
||||
#define HCHWCFG_15KRSEL (1 << 12)
|
||||
#define HCHWCFG_CLKNOTSTOP (1 << 11)
|
||||
#define HCHWCFG_ANALOG_OC (1 << 10)
|
||||
#define HCHWCFG_DACK_MODE (1 << 8)
|
||||
#define HCHWCFG_EOT_POL (1 << 7)
|
||||
#define HCHWCFG_DACK_POL (1 << 6)
|
||||
#define HCHWCFG_DREQ_POL (1 << 5)
|
||||
#define HCHWCFG_DBWIDTH_MASK (0x03 << 3)
|
||||
#define HCHWCFG_DBWIDTH(n) (((n) << 3) & HCHWCFG_DBWIDTH_MASK)
|
||||
#define HCHWCFG_INT_POL (1 << 2)
|
||||
#define HCHWCFG_INT_TRIGGER (1 << 1)
|
||||
#define HCHWCFG_INT_ENABLE (1 << 0)
|
||||
#define HCDMACFG 0x21
|
||||
#define HCDMACFG_BURST_LEN_MASK (0x03 << 5)
|
||||
#define HCDMACFG_BURST_LEN(n) (((n) << 5) & HCDMACFG_BURST_LEN_MASK)
|
||||
#define HCDMACFG_BURST_LEN_1 HCDMACFG_BURST_LEN(0)
|
||||
#define HCDMACFG_BURST_LEN_4 HCDMACFG_BURST_LEN(1)
|
||||
#define HCDMACFG_BURST_LEN_8 HCDMACFG_BURST_LEN(2)
|
||||
#define HCDMACFG_DMA_ENABLE (1 << 4)
|
||||
#define HCDMACFG_BUF_TYPE_MASK (0x07 << 1)
|
||||
#define HCDMACFG_CTR_SEL (1 << 2)
|
||||
#define HCDMACFG_ITLATL_SEL (1 << 1)
|
||||
#define HCDMACFG_DMA_RW_SELECT (1 << 0)
|
||||
#define HCXFERCTR 0x22
|
||||
#define HCuPINT 0x24
|
||||
#define HCuPINT_SOF (1 << 0)
|
||||
#define HCuPINT_ATL (1 << 1)
|
||||
#define HCuPINT_AIIEOT (1 << 2)
|
||||
#define HCuPINT_OPR (1 << 4)
|
||||
#define HCuPINT_SUSP (1 << 5)
|
||||
#define HCuPINT_CLKRDY (1 << 6)
|
||||
#define HCuPINTENB 0x25
|
||||
#define HCCHIPID 0x27
|
||||
#define HCCHIPID_MASK 0xff00
|
||||
#define HCCHIPID_MAGIC 0x6100
|
||||
#define HCSCRATCH 0x28
|
||||
#define HCSWRES 0x29
|
||||
#define HCSWRES_MAGIC 0x00f6
|
||||
#define HCITLBUFLEN 0x2a
|
||||
#define HCATLBUFLEN 0x2b
|
||||
#define HCBUFSTAT 0x2c
|
||||
#define HCBUFSTAT_ITL0_FULL (1 << 0)
|
||||
#define HCBUFSTAT_ITL1_FULL (1 << 1)
|
||||
#define HCBUFSTAT_ATL_FULL (1 << 2)
|
||||
#define HCBUFSTAT_ITL0_DONE (1 << 3)
|
||||
#define HCBUFSTAT_ITL1_DONE (1 << 4)
|
||||
#define HCBUFSTAT_ATL_DONE (1 << 5)
|
||||
#define HCRDITL0LEN 0x2d
|
||||
#define HCRDITL1LEN 0x2e
|
||||
#define HCITLPORT 0x40
|
||||
#define HCATLPORT 0x41
|
||||
|
||||
/* PTD accessor macros. */
|
||||
#define PTD_GET_COUNT(p) (((p)->count & PTD_COUNT_MSK) >> 0)
|
||||
#define PTD_COUNT(v) (((v) << 0) & PTD_COUNT_MSK)
|
||||
#define PTD_GET_TOGGLE(p) (((p)->count & PTD_TOGGLE_MSK) >> 10)
|
||||
#define PTD_TOGGLE(v) (((v) << 10) & PTD_TOGGLE_MSK)
|
||||
#define PTD_GET_ACTIVE(p) (((p)->count & PTD_ACTIVE_MSK) >> 11)
|
||||
#define PTD_ACTIVE(v) (((v) << 11) & PTD_ACTIVE_MSK)
|
||||
#define PTD_GET_CC(p) (((p)->count & PTD_CC_MSK) >> 12)
|
||||
#define PTD_CC(v) (((v) << 12) & PTD_CC_MSK)
|
||||
#define PTD_GET_MPS(p) (((p)->mps & PTD_MPS_MSK) >> 0)
|
||||
#define PTD_MPS(v) (((v) << 0) & PTD_MPS_MSK)
|
||||
#define PTD_GET_SPD(p) (((p)->mps & PTD_SPD_MSK) >> 10)
|
||||
#define PTD_SPD(v) (((v) << 10) & PTD_SPD_MSK)
|
||||
#define PTD_GET_LAST(p) (((p)->mps & PTD_LAST_MSK) >> 11)
|
||||
#define PTD_LAST(v) (((v) << 11) & PTD_LAST_MSK)
|
||||
#define PTD_GET_EP(p) (((p)->mps & PTD_EP_MSK) >> 12)
|
||||
#define PTD_EP(v) (((v) << 12) & PTD_EP_MSK)
|
||||
#define PTD_GET_LEN(p) (((p)->len & PTD_LEN_MSK) >> 0)
|
||||
#define PTD_LEN(v) (((v) << 0) & PTD_LEN_MSK)
|
||||
#define PTD_GET_DIR(p) (((p)->len & PTD_DIR_MSK) >> 10)
|
||||
#define PTD_DIR(v) (((v) << 10) & PTD_DIR_MSK)
|
||||
#define PTD_GET_B5_5(p) (((p)->len & PTD_B5_5_MSK) >> 13)
|
||||
#define PTD_B5_5(v) (((v) << 13) & PTD_B5_5_MSK)
|
||||
#define PTD_GET_FA(p) (((p)->faddr & PTD_FA_MSK) >> 0)
|
||||
#define PTD_FA(v) (((v) << 0) & PTD_FA_MSK)
|
||||
#define PTD_GET_FMT(p) (((p)->faddr & PTD_FMT_MSK) >> 7)
|
||||
#define PTD_FMT(v) (((v) << 7) & PTD_FMT_MSK)
|
||||
|
||||
/* Hardware transfer status codes -- CC from ptd->count */
|
||||
#define TD_CC_NOERROR 0x00
|
||||
#define TD_CC_CRC 0x01
|
||||
#define TD_CC_BITSTUFFING 0x02
|
||||
#define TD_CC_DATATOGGLEM 0x03
|
||||
#define TD_CC_STALL 0x04
|
||||
#define TD_DEVNOTRESP 0x05
|
||||
#define TD_PIDCHECKFAIL 0x06
|
||||
#define TD_UNEXPECTEDPID 0x07
|
||||
#define TD_DATAOVERRUN 0x08
|
||||
#define TD_DATAUNDERRUN 0x09
|
||||
/* 0x0A, 0x0B reserved for hardware */
|
||||
#define TD_BUFFEROVERRUN 0x0C
|
||||
#define TD_BUFFERUNDERRUN 0x0D
|
||||
/* 0x0E, 0x0F reserved for HCD */
|
||||
#define TD_NOTACCESSED 0x0F
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#define LOG2_PERIODIC_SIZE 5 /* arbitrary; this matches OHCI */
|
||||
#define PERIODIC_SIZE (1 << LOG2_PERIODIC_SIZE)
|
||||
|
||||
/* Philips transfer descriptor */
|
||||
struct ptd {
|
||||
u16 count;
|
||||
#define PTD_COUNT_MSK (0x3ff << 0)
|
||||
#define PTD_TOGGLE_MSK (1 << 10)
|
||||
#define PTD_ACTIVE_MSK (1 << 11)
|
||||
#define PTD_CC_MSK (0xf << 12)
|
||||
u16 mps;
|
||||
#define PTD_MPS_MSK (0x3ff << 0)
|
||||
#define PTD_SPD_MSK (1 << 10)
|
||||
#define PTD_LAST_MSK (1 << 11)
|
||||
#define PTD_EP_MSK (0xf << 12)
|
||||
u16 len;
|
||||
#define PTD_LEN_MSK (0x3ff << 0)
|
||||
#define PTD_DIR_MSK (3 << 10)
|
||||
#define PTD_DIR_SETUP (0)
|
||||
#define PTD_DIR_OUT (1)
|
||||
#define PTD_DIR_IN (2)
|
||||
#define PTD_B5_5_MSK (1 << 13)
|
||||
u16 faddr;
|
||||
#define PTD_FA_MSK (0x7f << 0)
|
||||
#define PTD_FMT_MSK (1 << 7)
|
||||
} __attribute__ ((packed, aligned(2)));
|
||||
|
||||
struct isp116x_ep {
|
||||
struct usb_device *udev;
|
||||
struct ptd ptd;
|
||||
|
||||
u8 maxpacket;
|
||||
u8 epnum;
|
||||
u8 nextpid;
|
||||
|
||||
u16 length; /* of current packet */
|
||||
unsigned char *data; /* to databuf */
|
||||
|
||||
u16 error_count;
|
||||
};
|
||||
|
||||
/* URB struct */
|
||||
#define N_URB_TD 48
|
||||
#define URB_DEL 1
|
||||
typedef struct {
|
||||
struct isp116x_ep *ed;
|
||||
void *transfer_buffer; /* (in) associated data buffer */
|
||||
int actual_length; /* (return) actual transfer length */
|
||||
unsigned long pipe; /* (in) pipe information */
|
||||
#if 0
|
||||
int state;
|
||||
#endif
|
||||
} urb_priv_t;
|
||||
|
||||
struct isp116x_platform_data {
|
||||
/* Enable internal resistors on downstream ports */
|
||||
unsigned sel15Kres:1;
|
||||
/* On-chip overcurrent detection */
|
||||
unsigned oc_enable:1;
|
||||
/* Enable wakeup by devices on usb bus (e.g. wakeup
|
||||
by attachment/detachment or by device activity
|
||||
such as moving a mouse). When chosen, this option
|
||||
prevents stopping internal clock, increasing
|
||||
thereby power consumption in suspended state. */
|
||||
unsigned remote_wakeup_enable:1;
|
||||
};
|
||||
|
||||
struct isp116x {
|
||||
u16 *addr_reg;
|
||||
u16 *data_reg;
|
||||
|
||||
struct isp116x_platform_data *board;
|
||||
|
||||
struct dentry *dentry;
|
||||
unsigned long stat1, stat2, stat4, stat8, stat16;
|
||||
|
||||
/* Status flags */
|
||||
unsigned disabled:1;
|
||||
unsigned sleeping:1;
|
||||
|
||||
/* Root hub registers */
|
||||
u32 rhdesca;
|
||||
u32 rhdescb;
|
||||
u32 rhstatus;
|
||||
u32 rhport[2];
|
||||
|
||||
/* Schedule for the current frame */
|
||||
struct isp116x_ep *atl_active;
|
||||
int atl_buflen;
|
||||
int atl_bufshrt;
|
||||
int atl_last_dir;
|
||||
int atl_finishing;
|
||||
};
|
||||
|
||||
/* ------------------------------------------------- */
|
||||
|
||||
/* Inter-io delay (ns). The chip is picky about access timings; it
|
||||
* expects at least:
|
||||
* 150ns delay between consecutive accesses to DATA_REG,
|
||||
* 300ns delay between access to ADDR_REG and DATA_REG
|
||||
* OE, WE MUST NOT be changed during these intervals
|
||||
*/
|
||||
#if defined(UDELAY)
|
||||
#define isp116x_delay(h,d) udelay(d)
|
||||
#else
|
||||
#define isp116x_delay(h,d) do {} while (0)
|
||||
#endif
|
||||
|
||||
static inline void isp116x_write_addr(struct isp116x *isp116x, unsigned reg)
|
||||
{
|
||||
writew(reg & 0xff, isp116x->addr_reg);
|
||||
isp116x_delay(isp116x, UDELAY);
|
||||
}
|
||||
|
||||
static inline void isp116x_write_data16(struct isp116x *isp116x, u16 val)
|
||||
{
|
||||
writew(val, isp116x->data_reg);
|
||||
isp116x_delay(isp116x, UDELAY);
|
||||
}
|
||||
|
||||
static inline void isp116x_raw_write_data16(struct isp116x *isp116x, u16 val)
|
||||
{
|
||||
__raw_writew(val, isp116x->data_reg);
|
||||
isp116x_delay(isp116x, UDELAY);
|
||||
}
|
||||
|
||||
static inline u16 isp116x_read_data16(struct isp116x *isp116x)
|
||||
{
|
||||
u16 val;
|
||||
|
||||
val = readw(isp116x->data_reg);
|
||||
isp116x_delay(isp116x, UDELAY);
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline u16 isp116x_raw_read_data16(struct isp116x *isp116x)
|
||||
{
|
||||
u16 val;
|
||||
|
||||
val = __raw_readw(isp116x->data_reg);
|
||||
isp116x_delay(isp116x, UDELAY);
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline void isp116x_write_data32(struct isp116x *isp116x, u32 val)
|
||||
{
|
||||
writew(val & 0xffff, isp116x->data_reg);
|
||||
isp116x_delay(isp116x, UDELAY);
|
||||
writew(val >> 16, isp116x->data_reg);
|
||||
isp116x_delay(isp116x, UDELAY);
|
||||
}
|
||||
|
||||
static inline u32 isp116x_read_data32(struct isp116x *isp116x)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = (u32) readw(isp116x->data_reg);
|
||||
isp116x_delay(isp116x, UDELAY);
|
||||
val |= ((u32) readw(isp116x->data_reg)) << 16;
|
||||
isp116x_delay(isp116x, UDELAY);
|
||||
return val;
|
||||
}
|
||||
|
||||
/* Let's keep register access functions out of line. Hint:
|
||||
we wait at least 150 ns at every access.
|
||||
*/
|
||||
static u16 isp116x_read_reg16(struct isp116x *isp116x, unsigned reg)
|
||||
{
|
||||
isp116x_write_addr(isp116x, reg);
|
||||
return isp116x_read_data16(isp116x);
|
||||
}
|
||||
|
||||
static u32 isp116x_read_reg32(struct isp116x *isp116x, unsigned reg)
|
||||
{
|
||||
isp116x_write_addr(isp116x, reg);
|
||||
return isp116x_read_data32(isp116x);
|
||||
}
|
||||
|
||||
static void isp116x_write_reg16(struct isp116x *isp116x, unsigned reg,
|
||||
unsigned val)
|
||||
{
|
||||
isp116x_write_addr(isp116x, reg | ISP116x_WRITE_OFFSET);
|
||||
isp116x_write_data16(isp116x, (u16) (val & 0xffff));
|
||||
}
|
||||
|
||||
static void isp116x_write_reg32(struct isp116x *isp116x, unsigned reg,
|
||||
unsigned val)
|
||||
{
|
||||
isp116x_write_addr(isp116x, reg | ISP116x_WRITE_OFFSET);
|
||||
isp116x_write_data32(isp116x, (u32) val);
|
||||
}
|
||||
|
||||
/* --- USB HUB constants (not OHCI-specific; see hub.h) -------------------- */
|
||||
|
||||
/* destination of request */
|
||||
#define RH_INTERFACE 0x01
|
||||
#define RH_ENDPOINT 0x02
|
||||
#define RH_OTHER 0x03
|
||||
|
||||
#define RH_CLASS 0x20
|
||||
#define RH_VENDOR 0x40
|
||||
|
||||
/* Requests: bRequest << 8 | bmRequestType */
|
||||
#define RH_GET_STATUS 0x0080
|
||||
#define RH_CLEAR_FEATURE 0x0100
|
||||
#define RH_SET_FEATURE 0x0300
|
||||
#define RH_SET_ADDRESS 0x0500
|
||||
#define RH_GET_DESCRIPTOR 0x0680
|
||||
#define RH_SET_DESCRIPTOR 0x0700
|
||||
#define RH_GET_CONFIGURATION 0x0880
|
||||
#define RH_SET_CONFIGURATION 0x0900
|
||||
#define RH_GET_STATE 0x0280
|
||||
#define RH_GET_INTERFACE 0x0A80
|
||||
#define RH_SET_INTERFACE 0x0B00
|
||||
#define RH_SYNC_FRAME 0x0C80
|
||||
/* Our Vendor Specific Request */
|
||||
#define RH_SET_EP 0x2000
|
||||
|
||||
/* Hub port features */
|
||||
#define RH_PORT_CONNECTION 0x00
|
||||
#define RH_PORT_ENABLE 0x01
|
||||
#define RH_PORT_SUSPEND 0x02
|
||||
#define RH_PORT_OVER_CURRENT 0x03
|
||||
#define RH_PORT_RESET 0x04
|
||||
#define RH_PORT_POWER 0x08
|
||||
#define RH_PORT_LOW_SPEED 0x09
|
||||
|
||||
#define RH_C_PORT_CONNECTION 0x10
|
||||
#define RH_C_PORT_ENABLE 0x11
|
||||
#define RH_C_PORT_SUSPEND 0x12
|
||||
#define RH_C_PORT_OVER_CURRENT 0x13
|
||||
#define RH_C_PORT_RESET 0x14
|
||||
|
||||
/* Hub features */
|
||||
#define RH_C_HUB_LOCAL_POWER 0x00
|
||||
#define RH_C_HUB_OVER_CURRENT 0x01
|
||||
|
||||
#define RH_DEVICE_REMOTE_WAKEUP 0x00
|
||||
#define RH_ENDPOINT_STALL 0x01
|
||||
|
||||
#define RH_ACK 0x01
|
||||
#define RH_REQ_ERR -1
|
||||
#define RH_NACK 0x00
|
||||
80
drivers/usb/host/ohci-at91.c
Normal file
80
drivers/usb/host/ohci-at91.c
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* (C) Copyright 2006
|
||||
* DENX Software Engineering <mk@denx.de>
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* 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>
|
||||
|
||||
#if defined(CONFIG_USB_OHCI_NEW) && defined(CONFIG_SYS_USB_OHCI_CPU_INIT)
|
||||
|
||||
#include <asm/arch/hardware.h>
|
||||
#include <asm/arch/io.h>
|
||||
#include <asm/arch/at91_pmc.h>
|
||||
|
||||
int usb_cpu_init(void)
|
||||
{
|
||||
|
||||
#if defined(CONFIG_AT91CAP9) || defined(CONFIG_AT91SAM9260) || \
|
||||
defined(CONFIG_AT91SAM9263) || defined(CONFIG_AT91SAM9G20)
|
||||
/* Enable PLLB */
|
||||
at91_sys_write(AT91_CKGR_PLLBR, CONFIG_SYS_AT91_PLLB);
|
||||
while ((at91_sys_read(AT91_PMC_SR) & AT91_PMC_LOCKB) != AT91_PMC_LOCKB)
|
||||
;
|
||||
#endif
|
||||
|
||||
/* Enable USB host clock. */
|
||||
at91_sys_write(AT91_PMC_PCER, 1 << AT91_ID_UHP);
|
||||
#ifdef CONFIG_AT91SAM9261
|
||||
at91_sys_write(AT91_PMC_SCER, AT91_PMC_UHP | AT91_PMC_HCK0);
|
||||
#else
|
||||
at91_sys_write(AT91_PMC_SCER, AT91_PMC_UHP);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_cpu_stop(void)
|
||||
{
|
||||
/* Disable USB host clock. */
|
||||
at91_sys_write(AT91_PMC_PCDR, 1 << AT91_ID_UHP);
|
||||
#ifdef CONFIG_AT91SAM9261
|
||||
at91_sys_write(AT91_PMC_SCDR, AT91_PMC_UHP | AT91_PMC_HCK0);
|
||||
#else
|
||||
at91_sys_write(AT91_PMC_SCDR, AT91_PMC_UHP);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_AT91CAP9) || defined(CONFIG_AT91SAM9260) || \
|
||||
defined(CONFIG_AT91SAM9263) || defined(CONFIG_AT91SAM9G20)
|
||||
/* Disable PLLB */
|
||||
at91_sys_write(AT91_CKGR_PLLBR, 0);
|
||||
while ((at91_sys_read(AT91_PMC_SR) & AT91_PMC_LOCKB) != 0)
|
||||
;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_cpu_init_fail(void)
|
||||
{
|
||||
return usb_cpu_stop();
|
||||
}
|
||||
|
||||
#endif /* defined(CONFIG_USB_OHCI) && defined(CONFIG_SYS_USB_OHCI_CPU_INIT) */
|
||||
2016
drivers/usb/host/ohci-hcd.c
Normal file
2016
drivers/usb/host/ohci-hcd.c
Normal file
File diff suppressed because it is too large
Load Diff
483
drivers/usb/host/ohci.h
Normal file
483
drivers/usb/host/ohci.h
Normal file
@@ -0,0 +1,483 @@
|
||||
/*
|
||||
* URB OHCI HCD (Host Controller Driver) for USB.
|
||||
*
|
||||
* (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
|
||||
* (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
|
||||
*
|
||||
* usb-ohci.h
|
||||
*/
|
||||
|
||||
/* functions for doing board or CPU specific setup/cleanup */
|
||||
extern int usb_board_init(void);
|
||||
extern int usb_board_stop(void);
|
||||
extern int usb_board_init_fail(void);
|
||||
|
||||
extern int usb_cpu_init(void);
|
||||
extern int usb_cpu_stop(void);
|
||||
extern int usb_cpu_init_fail(void);
|
||||
|
||||
|
||||
static int cc_to_error[16] = {
|
||||
|
||||
/* mapping of the OHCI CC status to error codes */
|
||||
/* No Error */ 0,
|
||||
/* CRC Error */ USB_ST_CRC_ERR,
|
||||
/* Bit Stuff */ USB_ST_BIT_ERR,
|
||||
/* Data Togg */ USB_ST_CRC_ERR,
|
||||
/* Stall */ USB_ST_STALLED,
|
||||
/* DevNotResp */ -1,
|
||||
/* PIDCheck */ USB_ST_BIT_ERR,
|
||||
/* UnExpPID */ USB_ST_BIT_ERR,
|
||||
/* DataOver */ USB_ST_BUF_ERR,
|
||||
/* DataUnder */ USB_ST_BUF_ERR,
|
||||
/* reservd */ -1,
|
||||
/* reservd */ -1,
|
||||
/* BufferOver */ USB_ST_BUF_ERR,
|
||||
/* BuffUnder */ USB_ST_BUF_ERR,
|
||||
/* Not Access */ -1,
|
||||
/* Not Access */ -1
|
||||
};
|
||||
|
||||
static const char *cc_to_string[16] = {
|
||||
"No Error",
|
||||
"CRC: Last data packet from endpoint contained a CRC error.",
|
||||
"BITSTUFFING: Last data packet from endpoint contained a bit " \
|
||||
"stuffing violation",
|
||||
"DATATOGGLEMISMATCH: Last packet from endpoint had data toggle PID\n" \
|
||||
"that did not match the expected value.",
|
||||
"STALL: TD was moved to the Done Queue because the endpoint returned" \
|
||||
" a STALL PID",
|
||||
"DEVICENOTRESPONDING: Device did not respond to token (IN) or did\n" \
|
||||
"not provide a handshake (OUT)",
|
||||
"PIDCHECKFAILURE: Check bits on PID from endpoint failed on data PID\n"\
|
||||
"(IN) or handshake (OUT)",
|
||||
"UNEXPECTEDPID: Receive PID was not valid when encountered or PID\n" \
|
||||
"value is not defined.",
|
||||
"DATAOVERRUN: The amount of data returned by the endpoint exceeded\n" \
|
||||
"either the size of the maximum data packet allowed\n" \
|
||||
"from the endpoint (found in MaximumPacketSize field\n" \
|
||||
"of ED) or the remaining buffer size.",
|
||||
"DATAUNDERRUN: The endpoint returned less than MaximumPacketSize\n" \
|
||||
"and that amount was not sufficient to fill the\n" \
|
||||
"specified buffer",
|
||||
"reserved1",
|
||||
"reserved2",
|
||||
"BUFFEROVERRUN: During an IN, HC received data from endpoint faster\n" \
|
||||
"than it could be written to system memory",
|
||||
"BUFFERUNDERRUN: During an OUT, HC could not retrieve data from\n" \
|
||||
"system memory fast enough to keep up with data USB " \
|
||||
"data rate.",
|
||||
"NOT ACCESSED: This code is set by software before the TD is placed" \
|
||||
"on a list to be processed by the HC.(1)",
|
||||
"NOT ACCESSED: This code is set by software before the TD is placed" \
|
||||
"on a list to be processed by the HC.(2)",
|
||||
};
|
||||
|
||||
/* ED States */
|
||||
|
||||
#define ED_NEW 0x00
|
||||
#define ED_UNLINK 0x01
|
||||
#define ED_OPER 0x02
|
||||
#define ED_DEL 0x04
|
||||
#define ED_URB_DEL 0x08
|
||||
|
||||
/* usb_ohci_ed */
|
||||
struct ed {
|
||||
__u32 hwINFO;
|
||||
__u32 hwTailP;
|
||||
__u32 hwHeadP;
|
||||
__u32 hwNextED;
|
||||
|
||||
struct ed *ed_prev;
|
||||
__u8 int_period;
|
||||
__u8 int_branch;
|
||||
__u8 int_load;
|
||||
__u8 int_interval;
|
||||
__u8 state;
|
||||
__u8 type;
|
||||
__u16 last_iso;
|
||||
struct ed *ed_rm_list;
|
||||
|
||||
struct usb_device *usb_dev;
|
||||
void *purb;
|
||||
__u32 unused[2];
|
||||
} __attribute((aligned(16)));
|
||||
typedef struct ed ed_t;
|
||||
|
||||
|
||||
/* TD info field */
|
||||
#define TD_CC 0xf0000000
|
||||
#define TD_CC_GET(td_p) ((td_p >>28) & 0x0f)
|
||||
#define TD_CC_SET(td_p, cc) (td_p) = ((td_p) & 0x0fffffff) | (((cc) & 0x0f) << 28)
|
||||
#define TD_EC 0x0C000000
|
||||
#define TD_T 0x03000000
|
||||
#define TD_T_DATA0 0x02000000
|
||||
#define TD_T_DATA1 0x03000000
|
||||
#define TD_T_TOGGLE 0x00000000
|
||||
#define TD_R 0x00040000
|
||||
#define TD_DI 0x00E00000
|
||||
#define TD_DI_SET(X) (((X) & 0x07)<< 21)
|
||||
#define TD_DP 0x00180000
|
||||
#define TD_DP_SETUP 0x00000000
|
||||
#define TD_DP_IN 0x00100000
|
||||
#define TD_DP_OUT 0x00080000
|
||||
|
||||
#define TD_ISO 0x00010000
|
||||
#define TD_DEL 0x00020000
|
||||
|
||||
/* CC Codes */
|
||||
#define TD_CC_NOERROR 0x00
|
||||
#define TD_CC_CRC 0x01
|
||||
#define TD_CC_BITSTUFFING 0x02
|
||||
#define TD_CC_DATATOGGLEM 0x03
|
||||
#define TD_CC_STALL 0x04
|
||||
#define TD_DEVNOTRESP 0x05
|
||||
#define TD_PIDCHECKFAIL 0x06
|
||||
#define TD_UNEXPECTEDPID 0x07
|
||||
#define TD_DATAOVERRUN 0x08
|
||||
#define TD_DATAUNDERRUN 0x09
|
||||
#define TD_BUFFEROVERRUN 0x0C
|
||||
#define TD_BUFFERUNDERRUN 0x0D
|
||||
#define TD_NOTACCESSED 0x0F
|
||||
|
||||
|
||||
#define MAXPSW 1
|
||||
|
||||
struct td {
|
||||
__u32 hwINFO;
|
||||
__u32 hwCBP; /* Current Buffer Pointer */
|
||||
__u32 hwNextTD; /* Next TD Pointer */
|
||||
__u32 hwBE; /* Memory Buffer End Pointer */
|
||||
|
||||
/* #ifndef CONFIG_MPC5200 /\* this seems wrong *\/ */
|
||||
__u16 hwPSW[MAXPSW];
|
||||
/* #endif */
|
||||
__u8 unused;
|
||||
__u8 index;
|
||||
struct ed *ed;
|
||||
struct td *next_dl_td;
|
||||
struct usb_device *usb_dev;
|
||||
int transfer_len;
|
||||
__u32 data;
|
||||
|
||||
__u32 unused2[2];
|
||||
} __attribute((aligned(32)));
|
||||
typedef struct td td_t;
|
||||
|
||||
#define OHCI_ED_SKIP (1 << 14)
|
||||
|
||||
/*
|
||||
* The HCCA (Host Controller Communications Area) is a 256 byte
|
||||
* structure defined in the OHCI spec. that the host controller is
|
||||
* told the base address of. It must be 256-byte aligned.
|
||||
*/
|
||||
|
||||
#define NUM_INTS 32 /* part of the OHCI standard */
|
||||
struct ohci_hcca {
|
||||
__u32 int_table[NUM_INTS]; /* Interrupt ED table */
|
||||
#if defined(CONFIG_MPC5200)
|
||||
__u16 pad1; /* set to 0 on each frame_no change */
|
||||
__u16 frame_no; /* current frame number */
|
||||
#else
|
||||
__u16 frame_no; /* current frame number */
|
||||
__u16 pad1; /* set to 0 on each frame_no change */
|
||||
#endif
|
||||
__u32 done_head; /* info returned for an interrupt */
|
||||
u8 reserved_for_hc[116];
|
||||
} __attribute((aligned(256)));
|
||||
|
||||
|
||||
/*
|
||||
* Maximum number of root hub ports.
|
||||
*/
|
||||
#ifndef CONFIG_SYS_USB_OHCI_MAX_ROOT_PORTS
|
||||
# error "CONFIG_SYS_USB_OHCI_MAX_ROOT_PORTS undefined!"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This is the structure of the OHCI controller's memory mapped I/O
|
||||
* region. This is Memory Mapped I/O. You must use the readl() and
|
||||
* writel() macros defined in asm/io.h to access these!!
|
||||
*/
|
||||
struct ohci_regs {
|
||||
/* control and status registers */
|
||||
__u32 revision;
|
||||
__u32 control;
|
||||
__u32 cmdstatus;
|
||||
__u32 intrstatus;
|
||||
__u32 intrenable;
|
||||
__u32 intrdisable;
|
||||
/* memory pointers */
|
||||
__u32 hcca;
|
||||
__u32 ed_periodcurrent;
|
||||
__u32 ed_controlhead;
|
||||
__u32 ed_controlcurrent;
|
||||
__u32 ed_bulkhead;
|
||||
__u32 ed_bulkcurrent;
|
||||
__u32 donehead;
|
||||
/* frame counters */
|
||||
__u32 fminterval;
|
||||
__u32 fmremaining;
|
||||
__u32 fmnumber;
|
||||
__u32 periodicstart;
|
||||
__u32 lsthresh;
|
||||
/* Root hub ports */
|
||||
struct ohci_roothub_regs {
|
||||
__u32 a;
|
||||
__u32 b;
|
||||
__u32 status;
|
||||
__u32 portstatus[CONFIG_SYS_USB_OHCI_MAX_ROOT_PORTS];
|
||||
} roothub;
|
||||
} __attribute((aligned(32)));
|
||||
|
||||
/* Some EHCI controls */
|
||||
#define EHCI_USBCMD_OFF 0x20
|
||||
#define EHCI_USBCMD_HCRESET (1 << 1)
|
||||
|
||||
/* OHCI CONTROL AND STATUS REGISTER MASKS */
|
||||
|
||||
/*
|
||||
* HcControl (control) register masks
|
||||
*/
|
||||
#define OHCI_CTRL_CBSR (3 << 0) /* control/bulk service ratio */
|
||||
#define OHCI_CTRL_PLE (1 << 2) /* periodic list enable */
|
||||
#define OHCI_CTRL_IE (1 << 3) /* isochronous enable */
|
||||
#define OHCI_CTRL_CLE (1 << 4) /* control list enable */
|
||||
#define OHCI_CTRL_BLE (1 << 5) /* bulk list enable */
|
||||
#define OHCI_CTRL_HCFS (3 << 6) /* host controller functional state */
|
||||
#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */
|
||||
#define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */
|
||||
#define OHCI_CTRL_RWE (1 << 10) /* remote wakeup enable */
|
||||
|
||||
/* pre-shifted values for HCFS */
|
||||
# define OHCI_USB_RESET (0 << 6)
|
||||
# define OHCI_USB_RESUME (1 << 6)
|
||||
# define OHCI_USB_OPER (2 << 6)
|
||||
# define OHCI_USB_SUSPEND (3 << 6)
|
||||
|
||||
/*
|
||||
* HcCommandStatus (cmdstatus) register masks
|
||||
*/
|
||||
#define OHCI_HCR (1 << 0) /* host controller reset */
|
||||
#define OHCI_CLF (1 << 1) /* control list filled */
|
||||
#define OHCI_BLF (1 << 2) /* bulk list filled */
|
||||
#define OHCI_OCR (1 << 3) /* ownership change request */
|
||||
#define OHCI_SOC (3 << 16) /* scheduling overrun count */
|
||||
|
||||
/*
|
||||
* masks used with interrupt registers:
|
||||
* HcInterruptStatus (intrstatus)
|
||||
* HcInterruptEnable (intrenable)
|
||||
* HcInterruptDisable (intrdisable)
|
||||
*/
|
||||
#define OHCI_INTR_SO (1 << 0) /* scheduling overrun */
|
||||
#define OHCI_INTR_WDH (1 << 1) /* writeback of done_head */
|
||||
#define OHCI_INTR_SF (1 << 2) /* start frame */
|
||||
#define OHCI_INTR_RD (1 << 3) /* resume detect */
|
||||
#define OHCI_INTR_UE (1 << 4) /* unrecoverable error */
|
||||
#define OHCI_INTR_FNO (1 << 5) /* frame number overflow */
|
||||
#define OHCI_INTR_RHSC (1 << 6) /* root hub status change */
|
||||
#define OHCI_INTR_OC (1 << 30) /* ownership change */
|
||||
#define OHCI_INTR_MIE (1 << 31) /* master interrupt enable */
|
||||
|
||||
|
||||
/* Virtual Root HUB */
|
||||
struct virt_root_hub {
|
||||
int devnum; /* Address of Root Hub endpoint */
|
||||
void *dev; /* was urb */
|
||||
void *int_addr;
|
||||
int send;
|
||||
int interval;
|
||||
};
|
||||
|
||||
/* USB HUB CONSTANTS (not OHCI-specific; see hub.h) */
|
||||
|
||||
/* destination of request */
|
||||
#define RH_INTERFACE 0x01
|
||||
#define RH_ENDPOINT 0x02
|
||||
#define RH_OTHER 0x03
|
||||
|
||||
#define RH_CLASS 0x20
|
||||
#define RH_VENDOR 0x40
|
||||
|
||||
/* Requests: bRequest << 8 | bmRequestType */
|
||||
#define RH_GET_STATUS 0x0080
|
||||
#define RH_CLEAR_FEATURE 0x0100
|
||||
#define RH_SET_FEATURE 0x0300
|
||||
#define RH_SET_ADDRESS 0x0500
|
||||
#define RH_GET_DESCRIPTOR 0x0680
|
||||
#define RH_SET_DESCRIPTOR 0x0700
|
||||
#define RH_GET_CONFIGURATION 0x0880
|
||||
#define RH_SET_CONFIGURATION 0x0900
|
||||
#define RH_GET_STATE 0x0280
|
||||
#define RH_GET_INTERFACE 0x0A80
|
||||
#define RH_SET_INTERFACE 0x0B00
|
||||
#define RH_SYNC_FRAME 0x0C80
|
||||
/* Our Vendor Specific Request */
|
||||
#define RH_SET_EP 0x2000
|
||||
|
||||
|
||||
/* Hub port features */
|
||||
#define RH_PORT_CONNECTION 0x00
|
||||
#define RH_PORT_ENABLE 0x01
|
||||
#define RH_PORT_SUSPEND 0x02
|
||||
#define RH_PORT_OVER_CURRENT 0x03
|
||||
#define RH_PORT_RESET 0x04
|
||||
#define RH_PORT_POWER 0x08
|
||||
#define RH_PORT_LOW_SPEED 0x09
|
||||
|
||||
#define RH_C_PORT_CONNECTION 0x10
|
||||
#define RH_C_PORT_ENABLE 0x11
|
||||
#define RH_C_PORT_SUSPEND 0x12
|
||||
#define RH_C_PORT_OVER_CURRENT 0x13
|
||||
#define RH_C_PORT_RESET 0x14
|
||||
|
||||
/* Hub features */
|
||||
#define RH_C_HUB_LOCAL_POWER 0x00
|
||||
#define RH_C_HUB_OVER_CURRENT 0x01
|
||||
|
||||
#define RH_DEVICE_REMOTE_WAKEUP 0x00
|
||||
#define RH_ENDPOINT_STALL 0x01
|
||||
|
||||
#define RH_ACK 0x01
|
||||
#define RH_REQ_ERR -1
|
||||
#define RH_NACK 0x00
|
||||
|
||||
|
||||
/* OHCI ROOT HUB REGISTER MASKS */
|
||||
|
||||
/* roothub.portstatus [i] bits */
|
||||
#define RH_PS_CCS 0x00000001 /* current connect status */
|
||||
#define RH_PS_PES 0x00000002 /* port enable status*/
|
||||
#define RH_PS_PSS 0x00000004 /* port suspend status */
|
||||
#define RH_PS_POCI 0x00000008 /* port over current indicator */
|
||||
#define RH_PS_PRS 0x00000010 /* port reset status */
|
||||
#define RH_PS_PPS 0x00000100 /* port power status */
|
||||
#define RH_PS_LSDA 0x00000200 /* low speed device attached */
|
||||
#define RH_PS_CSC 0x00010000 /* connect status change */
|
||||
#define RH_PS_PESC 0x00020000 /* port enable status change */
|
||||
#define RH_PS_PSSC 0x00040000 /* port suspend status change */
|
||||
#define RH_PS_OCIC 0x00080000 /* over current indicator change */
|
||||
#define RH_PS_PRSC 0x00100000 /* port reset status change */
|
||||
|
||||
/* roothub.status bits */
|
||||
#define RH_HS_LPS 0x00000001 /* local power status */
|
||||
#define RH_HS_OCI 0x00000002 /* over current indicator */
|
||||
#define RH_HS_DRWE 0x00008000 /* device remote wakeup enable */
|
||||
#define RH_HS_LPSC 0x00010000 /* local power status change */
|
||||
#define RH_HS_OCIC 0x00020000 /* over current indicator change */
|
||||
#define RH_HS_CRWE 0x80000000 /* clear remote wakeup enable */
|
||||
|
||||
/* roothub.b masks */
|
||||
#define RH_B_DR 0x0000ffff /* device removable flags */
|
||||
#define RH_B_PPCM 0xffff0000 /* port power control mask */
|
||||
|
||||
/* roothub.a masks */
|
||||
#define RH_A_NDP (0xff << 0) /* number of downstream ports */
|
||||
#define RH_A_PSM (1 << 8) /* power switching mode */
|
||||
#define RH_A_NPS (1 << 9) /* no power switching */
|
||||
#define RH_A_DT (1 << 10) /* device type (mbz) */
|
||||
#define RH_A_OCPM (1 << 11) /* over current protection mode */
|
||||
#define RH_A_NOCP (1 << 12) /* no over current protection */
|
||||
#define RH_A_POTPGT (0xff << 24) /* power on to power good time */
|
||||
|
||||
/* urb */
|
||||
#define N_URB_TD 48
|
||||
typedef struct
|
||||
{
|
||||
ed_t *ed;
|
||||
__u16 length; /* number of tds associated with this request */
|
||||
__u16 td_cnt; /* number of tds already serviced */
|
||||
struct usb_device *dev;
|
||||
int state;
|
||||
unsigned long pipe;
|
||||
void *transfer_buffer;
|
||||
int transfer_buffer_length;
|
||||
int interval;
|
||||
int actual_length;
|
||||
int finished;
|
||||
td_t *td[N_URB_TD]; /* list pointer to all corresponding TDs associated with this request */
|
||||
} urb_priv_t;
|
||||
#define URB_DEL 1
|
||||
|
||||
/*
|
||||
* This is the full ohci controller description
|
||||
*
|
||||
* Note how the "proper" USB information is just
|
||||
* a subset of what the full implementation needs. (Linus)
|
||||
*/
|
||||
|
||||
|
||||
typedef struct ohci {
|
||||
struct ohci_hcca *hcca; /* hcca */
|
||||
/*dma_addr_t hcca_dma;*/
|
||||
|
||||
int irq;
|
||||
int disabled; /* e.g. got a UE, we're hung */
|
||||
int sleeping;
|
||||
unsigned long flags; /* for HC bugs */
|
||||
|
||||
struct ohci_regs *regs; /* OHCI controller's memory */
|
||||
|
||||
int ohci_int_load[32]; /* load of the 32 Interrupt Chains (for load balancing)*/
|
||||
ed_t *ed_rm_list[2]; /* lists of all endpoints to be removed */
|
||||
ed_t *ed_bulktail; /* last endpoint of bulk list */
|
||||
ed_t *ed_controltail; /* last endpoint of control list */
|
||||
int intrstatus;
|
||||
__u32 hc_control; /* copy of the hc control reg */
|
||||
struct usb_device *dev[32];
|
||||
struct virt_root_hub rh;
|
||||
|
||||
const char *slot_name;
|
||||
} ohci_t;
|
||||
|
||||
#define NUM_EDS 8 /* num of preallocated endpoint descriptors */
|
||||
|
||||
struct ohci_device {
|
||||
ed_t ed[NUM_EDS];
|
||||
int ed_cnt;
|
||||
};
|
||||
|
||||
/* hcd */
|
||||
/* endpoint */
|
||||
static int ep_link(ohci_t * ohci, ed_t * ed);
|
||||
static int ep_unlink(ohci_t * ohci, ed_t * ed);
|
||||
static ed_t * ep_add_ed(struct usb_device * usb_dev, unsigned long pipe,
|
||||
int interval, int load);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* we need more TDs than EDs */
|
||||
#define NUM_TD 64
|
||||
|
||||
/* +1 so we can align the storage */
|
||||
td_t gtd[NUM_TD+1];
|
||||
/* pointers to aligned storage */
|
||||
td_t *ptd;
|
||||
|
||||
/* TDs ... */
|
||||
static inline struct td *
|
||||
td_alloc (struct usb_device *usb_dev)
|
||||
{
|
||||
int i;
|
||||
struct td *td;
|
||||
|
||||
td = NULL;
|
||||
for (i = 0; i < NUM_TD; i++)
|
||||
{
|
||||
if (ptd[i].usb_dev == NULL)
|
||||
{
|
||||
td = &ptd[i];
|
||||
td->usb_dev = usb_dev;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return td;
|
||||
}
|
||||
|
||||
static inline void
|
||||
ed_free (struct ed *ed)
|
||||
{
|
||||
ed->usb_dev = NULL;
|
||||
}
|
||||
945
drivers/usb/host/r8a66597-hcd.c
Normal file
945
drivers/usb/host/r8a66597-hcd.c
Normal file
@@ -0,0 +1,945 @@
|
||||
/*
|
||||
* R8A66597 HCD (Host Controller Driver) for u-boot
|
||||
*
|
||||
* Copyright (C) 2008 Yoshihiro Shimoda <shimoda.yoshihiro@renesas.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; version 2 of the License.
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <usb.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include "r8a66597.h"
|
||||
|
||||
#ifdef R8A66597_DEBUG
|
||||
#define R8A66597_DPRINT printf
|
||||
#else
|
||||
#define R8A66597_DPRINT(...)
|
||||
#endif
|
||||
|
||||
static const char hcd_name[] = "r8a66597_hcd";
|
||||
static unsigned short clock = CONFIG_R8A66597_XTAL;
|
||||
static unsigned short vif = CONFIG_R8A66597_LDRV;
|
||||
static unsigned short endian = CONFIG_R8A66597_ENDIAN;
|
||||
static struct r8a66597 gr8a66597;
|
||||
|
||||
static void get_hub_data(struct usb_device *dev, u16 *hub_devnum, u16 *hubport)
|
||||
{
|
||||
int i;
|
||||
|
||||
*hub_devnum = 0;
|
||||
*hubport = 0;
|
||||
|
||||
/* check a device connected to root_hub */
|
||||
if ((dev->parent && dev->parent->devnum == 1) ||
|
||||
(dev->devnum == 1))
|
||||
return;
|
||||
|
||||
for (i = 0; i < USB_MAXCHILDREN; i++) {
|
||||
if (dev->parent->children[i] == dev) {
|
||||
*hub_devnum = (u8)dev->parent->devnum;
|
||||
*hubport = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
printf("get_hub_data error.\n");
|
||||
}
|
||||
|
||||
static void set_devadd(struct r8a66597 *r8a66597, u8 r8a66597_address,
|
||||
struct usb_device *dev, int port)
|
||||
{
|
||||
u16 val, usbspd, upphub, hubport;
|
||||
unsigned long devadd_reg = get_devadd_addr(r8a66597_address);
|
||||
|
||||
get_hub_data(dev, &upphub, &hubport);
|
||||
usbspd = r8a66597->speed;
|
||||
val = (upphub << 11) | (hubport << 8) | (usbspd << 6) | (port & 0x0001);
|
||||
r8a66597_write(r8a66597, val, devadd_reg);
|
||||
}
|
||||
|
||||
static int r8a66597_clock_enable(struct r8a66597 *r8a66597)
|
||||
{
|
||||
u16 tmp;
|
||||
int i = 0;
|
||||
|
||||
#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
|
||||
do {
|
||||
r8a66597_write(r8a66597, SCKE, SYSCFG0);
|
||||
tmp = r8a66597_read(r8a66597, SYSCFG0);
|
||||
if (i++ > 1000) {
|
||||
printf("register access fail.\n");
|
||||
return -1;
|
||||
}
|
||||
} while ((tmp & SCKE) != SCKE);
|
||||
r8a66597_write(r8a66597, 0x04, 0x02);
|
||||
#else
|
||||
do {
|
||||
r8a66597_write(r8a66597, USBE, SYSCFG0);
|
||||
tmp = r8a66597_read(r8a66597, SYSCFG0);
|
||||
if (i++ > 1000) {
|
||||
printf("register access fail.\n");
|
||||
return -1;
|
||||
}
|
||||
} while ((tmp & USBE) != USBE);
|
||||
r8a66597_bclr(r8a66597, USBE, SYSCFG0);
|
||||
r8a66597_mdfy(r8a66597, clock, XTAL, SYSCFG0);
|
||||
|
||||
i = 0;
|
||||
r8a66597_bset(r8a66597, XCKE, SYSCFG0);
|
||||
do {
|
||||
udelay(1000);
|
||||
tmp = r8a66597_read(r8a66597, SYSCFG0);
|
||||
if (i++ > 500) {
|
||||
printf("register access fail.\n");
|
||||
return -1;
|
||||
}
|
||||
} while ((tmp & SCKE) != SCKE);
|
||||
#endif /* #if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void r8a66597_clock_disable(struct r8a66597 *r8a66597)
|
||||
{
|
||||
r8a66597_bclr(r8a66597, SCKE, SYSCFG0);
|
||||
udelay(1);
|
||||
#if !defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
|
||||
r8a66597_bclr(r8a66597, PLLC, SYSCFG0);
|
||||
r8a66597_bclr(r8a66597, XCKE, SYSCFG0);
|
||||
r8a66597_bclr(r8a66597, USBE, SYSCFG0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void r8a66597_enable_port(struct r8a66597 *r8a66597, int port)
|
||||
{
|
||||
u16 val;
|
||||
|
||||
val = port ? DRPD : DCFM | DRPD;
|
||||
r8a66597_bset(r8a66597, val, get_syscfg_reg(port));
|
||||
r8a66597_bset(r8a66597, HSE, get_syscfg_reg(port));
|
||||
|
||||
r8a66597_write(r8a66597, BURST | CPU_ADR_RD_WR, get_dmacfg_reg(port));
|
||||
}
|
||||
|
||||
static void r8a66597_disable_port(struct r8a66597 *r8a66597, int port)
|
||||
{
|
||||
u16 val, tmp;
|
||||
|
||||
r8a66597_write(r8a66597, 0, get_intenb_reg(port));
|
||||
r8a66597_write(r8a66597, 0, get_intsts_reg(port));
|
||||
|
||||
r8a66597_port_power(r8a66597, port, 0);
|
||||
|
||||
do {
|
||||
tmp = r8a66597_read(r8a66597, SOFCFG) & EDGESTS;
|
||||
udelay(640);
|
||||
} while (tmp == EDGESTS);
|
||||
|
||||
val = port ? DRPD : DCFM | DRPD;
|
||||
r8a66597_bclr(r8a66597, val, get_syscfg_reg(port));
|
||||
r8a66597_bclr(r8a66597, HSE, get_syscfg_reg(port));
|
||||
}
|
||||
|
||||
static int enable_controller(struct r8a66597 *r8a66597)
|
||||
{
|
||||
int ret, port;
|
||||
|
||||
ret = r8a66597_clock_enable(r8a66597);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
r8a66597_bset(r8a66597, vif & LDRV, PINCFG);
|
||||
r8a66597_bset(r8a66597, USBE, SYSCFG0);
|
||||
|
||||
r8a66597_bset(r8a66597, INTL, SOFCFG);
|
||||
r8a66597_write(r8a66597, 0, INTENB0);
|
||||
r8a66597_write(r8a66597, 0, INTENB1);
|
||||
r8a66597_write(r8a66597, 0, INTENB2);
|
||||
|
||||
r8a66597_bset(r8a66597, endian & BIGEND, CFIFOSEL);
|
||||
r8a66597_bset(r8a66597, endian & BIGEND, D0FIFOSEL);
|
||||
r8a66597_bset(r8a66597, endian & BIGEND, D1FIFOSEL);
|
||||
r8a66597_bset(r8a66597, TRNENSEL, SOFCFG);
|
||||
|
||||
for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++)
|
||||
r8a66597_enable_port(r8a66597, port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void disable_controller(struct r8a66597 *r8a66597)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!(r8a66597_read(r8a66597, SYSCFG0) & USBE))
|
||||
return;
|
||||
|
||||
r8a66597_write(r8a66597, 0, INTENB0);
|
||||
r8a66597_write(r8a66597, 0, INTSTS0);
|
||||
|
||||
r8a66597_write(r8a66597, 0, D0FIFOSEL);
|
||||
r8a66597_write(r8a66597, 0, D1FIFOSEL);
|
||||
r8a66597_write(r8a66597, 0, DCPCFG);
|
||||
r8a66597_write(r8a66597, 0x40, DCPMAXP);
|
||||
r8a66597_write(r8a66597, 0, DCPCTR);
|
||||
|
||||
for (i = 0; i <= 10; i++)
|
||||
r8a66597_write(r8a66597, 0, get_devadd_addr(i));
|
||||
for (i = 1; i <= 5; i++) {
|
||||
r8a66597_write(r8a66597, 0, get_pipetre_addr(i));
|
||||
r8a66597_write(r8a66597, 0, get_pipetrn_addr(i));
|
||||
}
|
||||
for (i = 1; i < R8A66597_MAX_NUM_PIPE; i++) {
|
||||
r8a66597_write(r8a66597, 0, get_pipectr_addr(i));
|
||||
r8a66597_write(r8a66597, i, PIPESEL);
|
||||
r8a66597_write(r8a66597, 0, PIPECFG);
|
||||
r8a66597_write(r8a66597, 0, PIPEBUF);
|
||||
r8a66597_write(r8a66597, 0, PIPEMAXP);
|
||||
r8a66597_write(r8a66597, 0, PIPEPERI);
|
||||
}
|
||||
|
||||
for (i = 0; i < R8A66597_MAX_ROOT_HUB; i++)
|
||||
r8a66597_disable_port(r8a66597, i);
|
||||
|
||||
r8a66597_clock_disable(r8a66597);
|
||||
}
|
||||
|
||||
static void r8a66597_reg_wait(struct r8a66597 *r8a66597, unsigned long reg,
|
||||
u16 mask, u16 loop)
|
||||
{
|
||||
u16 tmp;
|
||||
int i = 0;
|
||||
|
||||
do {
|
||||
tmp = r8a66597_read(r8a66597, reg);
|
||||
if (i++ > 1000000) {
|
||||
printf("register%lx, loop %x is timeout\n", reg, loop);
|
||||
break;
|
||||
}
|
||||
} while ((tmp & mask) != loop);
|
||||
}
|
||||
|
||||
static void pipe_buffer_setting(struct r8a66597 *r8a66597,
|
||||
struct usb_device *dev, unsigned long pipe)
|
||||
{
|
||||
u16 val = 0;
|
||||
u16 pipenum, bufnum, maxpacket;
|
||||
|
||||
if (usb_pipein(pipe)) {
|
||||
pipenum = BULK_IN_PIPENUM;
|
||||
bufnum = BULK_IN_BUFNUM;
|
||||
maxpacket = dev->epmaxpacketin[usb_pipeendpoint(pipe)];
|
||||
} else {
|
||||
pipenum = BULK_OUT_PIPENUM;
|
||||
bufnum = BULK_OUT_BUFNUM;
|
||||
maxpacket = dev->epmaxpacketout[usb_pipeendpoint(pipe)];
|
||||
}
|
||||
|
||||
if (r8a66597->pipe_config & (1 << pipenum))
|
||||
return;
|
||||
r8a66597->pipe_config |= (1 << pipenum);
|
||||
|
||||
r8a66597_bset(r8a66597, ACLRM, get_pipectr_addr(pipenum));
|
||||
r8a66597_bclr(r8a66597, ACLRM, get_pipectr_addr(pipenum));
|
||||
r8a66597_write(r8a66597, pipenum, PIPESEL);
|
||||
|
||||
/* FIXME: This driver support bulk transfer only. */
|
||||
if (!usb_pipein(pipe))
|
||||
val |= R8A66597_DIR;
|
||||
else
|
||||
val |= R8A66597_SHTNAK;
|
||||
val |= R8A66597_BULK | R8A66597_DBLB | usb_pipeendpoint(pipe);
|
||||
r8a66597_write(r8a66597, val, PIPECFG);
|
||||
|
||||
r8a66597_write(r8a66597, (8 << 10) | bufnum, PIPEBUF);
|
||||
r8a66597_write(r8a66597, make_devsel(usb_pipedevice(pipe)) |
|
||||
maxpacket, PIPEMAXP);
|
||||
r8a66597_write(r8a66597, 0, PIPEPERI);
|
||||
r8a66597_write(r8a66597, SQCLR, get_pipectr_addr(pipenum));
|
||||
}
|
||||
|
||||
static int send_setup_packet(struct r8a66597 *r8a66597, struct usb_device *dev,
|
||||
struct devrequest *setup)
|
||||
{
|
||||
int i;
|
||||
unsigned short *p = (unsigned short *)setup;
|
||||
unsigned long setup_addr = USBREQ;
|
||||
u16 intsts1;
|
||||
int timeout = 3000;
|
||||
u16 devsel = setup->request == USB_REQ_SET_ADDRESS ? 0 : dev->devnum;
|
||||
|
||||
r8a66597_write(r8a66597, make_devsel(devsel) |
|
||||
(8 << dev->maxpacketsize), DCPMAXP);
|
||||
r8a66597_write(r8a66597, ~(SIGN | SACK), INTSTS1);
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
r8a66597_write(r8a66597, le16_to_cpu(p[i]), setup_addr);
|
||||
setup_addr += 2;
|
||||
}
|
||||
r8a66597_write(r8a66597, ~0x0001, BRDYSTS);
|
||||
r8a66597_write(r8a66597, SUREQ, DCPCTR);
|
||||
|
||||
while (1) {
|
||||
intsts1 = r8a66597_read(r8a66597, INTSTS1);
|
||||
if (intsts1 & SACK)
|
||||
break;
|
||||
if (intsts1 & SIGN) {
|
||||
printf("setup packet send error\n");
|
||||
return -1;
|
||||
}
|
||||
if (timeout-- < 0) {
|
||||
printf("setup packet timeout\n");
|
||||
return -1;
|
||||
}
|
||||
udelay(500);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int send_bulk_packet(struct r8a66597 *r8a66597, struct usb_device *dev,
|
||||
unsigned long pipe, void *buffer, int transfer_len)
|
||||
{
|
||||
u16 tmp, bufsize;
|
||||
u16 *buf;
|
||||
size_t size;
|
||||
|
||||
R8A66597_DPRINT("%s\n", __func__);
|
||||
|
||||
r8a66597_mdfy(r8a66597, MBW | BULK_OUT_PIPENUM,
|
||||
MBW | CURPIPE, CFIFOSEL);
|
||||
r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, BULK_OUT_PIPENUM);
|
||||
tmp = r8a66597_read(r8a66597, CFIFOCTR);
|
||||
if ((tmp & FRDY) == 0) {
|
||||
printf("%s FRDY is not set (%x)\n", __func__, tmp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* prepare parameters */
|
||||
bufsize = dev->epmaxpacketout[usb_pipeendpoint(pipe)];
|
||||
buf = (u16 *)(buffer + dev->act_len);
|
||||
size = min((int)bufsize, transfer_len - dev->act_len);
|
||||
|
||||
/* write fifo */
|
||||
r8a66597_write(r8a66597, ~(1 << BULK_OUT_PIPENUM), BEMPSTS);
|
||||
if (buffer) {
|
||||
r8a66597_write_fifo(r8a66597, CFIFO, buf, size);
|
||||
r8a66597_write(r8a66597, BVAL, CFIFOCTR);
|
||||
}
|
||||
|
||||
/* update parameters */
|
||||
dev->act_len += size;
|
||||
|
||||
r8a66597_mdfy(r8a66597, PID_BUF, PID,
|
||||
get_pipectr_addr(BULK_OUT_PIPENUM));
|
||||
|
||||
while (!(r8a66597_read(r8a66597, BEMPSTS) & (1 << BULK_OUT_PIPENUM)))
|
||||
if (ctrlc())
|
||||
return -1;
|
||||
r8a66597_write(r8a66597, ~(1 << BULK_OUT_PIPENUM), BEMPSTS);
|
||||
|
||||
if (dev->act_len >= transfer_len)
|
||||
r8a66597_mdfy(r8a66597, PID_NAK, PID,
|
||||
get_pipectr_addr(BULK_OUT_PIPENUM));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int receive_bulk_packet(struct r8a66597 *r8a66597,
|
||||
struct usb_device *dev,
|
||||
unsigned long pipe,
|
||||
void *buffer, int transfer_len)
|
||||
{
|
||||
u16 tmp;
|
||||
u16 *buf;
|
||||
const u16 pipenum = BULK_IN_PIPENUM;
|
||||
int rcv_len;
|
||||
int maxpacket = dev->epmaxpacketin[usb_pipeendpoint(pipe)];
|
||||
|
||||
R8A66597_DPRINT("%s\n", __func__);
|
||||
|
||||
/* prepare */
|
||||
if (dev->act_len == 0) {
|
||||
r8a66597_mdfy(r8a66597, PID_NAK, PID,
|
||||
get_pipectr_addr(pipenum));
|
||||
r8a66597_write(r8a66597, ~(1 << pipenum), BRDYSTS);
|
||||
|
||||
r8a66597_write(r8a66597, TRCLR, get_pipetre_addr(pipenum));
|
||||
r8a66597_write(r8a66597,
|
||||
(transfer_len + maxpacket - 1) / maxpacket,
|
||||
get_pipetrn_addr(pipenum));
|
||||
r8a66597_bset(r8a66597, TRENB, get_pipetre_addr(pipenum));
|
||||
|
||||
r8a66597_mdfy(r8a66597, PID_BUF, PID,
|
||||
get_pipectr_addr(pipenum));
|
||||
}
|
||||
|
||||
r8a66597_mdfy(r8a66597, MBW | pipenum, MBW | CURPIPE, CFIFOSEL);
|
||||
r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, pipenum);
|
||||
|
||||
while (!(r8a66597_read(r8a66597, BRDYSTS) & (1 << pipenum)))
|
||||
if (ctrlc())
|
||||
return -1;
|
||||
r8a66597_write(r8a66597, ~(1 << pipenum), BRDYSTS);
|
||||
|
||||
tmp = r8a66597_read(r8a66597, CFIFOCTR);
|
||||
if ((tmp & FRDY) == 0) {
|
||||
printf("%s FRDY is not set. (%x)\n", __func__, tmp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
buf = (u16 *)(buffer + dev->act_len);
|
||||
rcv_len = tmp & DTLN;
|
||||
dev->act_len += rcv_len;
|
||||
|
||||
if (buffer) {
|
||||
if (rcv_len == 0)
|
||||
r8a66597_write(r8a66597, BCLR, CFIFOCTR);
|
||||
else
|
||||
r8a66597_read_fifo(r8a66597, CFIFO, buf, rcv_len);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int receive_control_packet(struct r8a66597 *r8a66597,
|
||||
struct usb_device *dev,
|
||||
void *buffer, int transfer_len)
|
||||
{
|
||||
u16 tmp;
|
||||
int rcv_len;
|
||||
|
||||
/* FIXME: limit transfer size : 64byte or less */
|
||||
|
||||
r8a66597_bclr(r8a66597, R8A66597_DIR, DCPCFG);
|
||||
r8a66597_mdfy(r8a66597, 0, ISEL | CURPIPE, CFIFOSEL);
|
||||
r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
|
||||
r8a66597_bset(r8a66597, SQSET, DCPCTR);
|
||||
r8a66597_write(r8a66597, BCLR, CFIFOCTR);
|
||||
r8a66597_mdfy(r8a66597, PID_BUF, PID, DCPCTR);
|
||||
|
||||
while (!(r8a66597_read(r8a66597, BRDYSTS) & 0x0001))
|
||||
if (ctrlc())
|
||||
return -1;
|
||||
r8a66597_write(r8a66597, ~0x0001, BRDYSTS);
|
||||
|
||||
r8a66597_mdfy(r8a66597, MBW, MBW | CURPIPE, CFIFOSEL);
|
||||
r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
|
||||
|
||||
tmp = r8a66597_read(r8a66597, CFIFOCTR);
|
||||
if ((tmp & FRDY) == 0) {
|
||||
printf("%s FRDY is not set. (%x)\n", __func__, tmp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rcv_len = tmp & DTLN;
|
||||
dev->act_len += rcv_len;
|
||||
|
||||
r8a66597_mdfy(r8a66597, PID_NAK, PID, DCPCTR);
|
||||
|
||||
if (buffer) {
|
||||
if (rcv_len == 0)
|
||||
r8a66597_write(r8a66597, BCLR, DCPCTR);
|
||||
else
|
||||
r8a66597_read_fifo(r8a66597, CFIFO, buffer, rcv_len);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int send_status_packet(struct r8a66597 *r8a66597,
|
||||
unsigned long pipe)
|
||||
{
|
||||
r8a66597_bset(r8a66597, SQSET, DCPCTR);
|
||||
r8a66597_mdfy(r8a66597, PID_NAK, PID, DCPCTR);
|
||||
|
||||
if (usb_pipein(pipe)) {
|
||||
r8a66597_bset(r8a66597, R8A66597_DIR, DCPCFG);
|
||||
r8a66597_mdfy(r8a66597, ISEL, ISEL | CURPIPE, CFIFOSEL);
|
||||
r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
|
||||
r8a66597_write(r8a66597, ~BEMP0, BEMPSTS);
|
||||
r8a66597_write(r8a66597, BCLR | BVAL, CFIFOCTR);
|
||||
} else {
|
||||
r8a66597_bclr(r8a66597, R8A66597_DIR, DCPCFG);
|
||||
r8a66597_mdfy(r8a66597, 0, ISEL | CURPIPE, CFIFOSEL);
|
||||
r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
|
||||
r8a66597_write(r8a66597, BCLR, CFIFOCTR);
|
||||
}
|
||||
r8a66597_mdfy(r8a66597, PID_BUF, PID, DCPCTR);
|
||||
|
||||
while (!(r8a66597_read(r8a66597, BEMPSTS) & 0x0001))
|
||||
if (ctrlc())
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void r8a66597_check_syssts(struct r8a66597 *r8a66597, int port)
|
||||
{
|
||||
int count = R8A66597_MAX_SAMPLING;
|
||||
unsigned short syssts, old_syssts;
|
||||
|
||||
R8A66597_DPRINT("%s\n", __func__);
|
||||
|
||||
old_syssts = r8a66597_read(r8a66597, get_syssts_reg(port) & LNST);
|
||||
while (count > 0) {
|
||||
wait_ms(R8A66597_RH_POLL_TIME);
|
||||
|
||||
syssts = r8a66597_read(r8a66597, get_syssts_reg(port) & LNST);
|
||||
if (syssts == old_syssts) {
|
||||
count--;
|
||||
} else {
|
||||
count = R8A66597_MAX_SAMPLING;
|
||||
old_syssts = syssts;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void r8a66597_bus_reset(struct r8a66597 *r8a66597, int port)
|
||||
{
|
||||
wait_ms(10);
|
||||
r8a66597_mdfy(r8a66597, USBRST, USBRST | UACT, get_dvstctr_reg(port));
|
||||
wait_ms(50);
|
||||
r8a66597_mdfy(r8a66597, UACT, USBRST | UACT, get_dvstctr_reg(port));
|
||||
wait_ms(50);
|
||||
}
|
||||
|
||||
static int check_usb_device_connecting(struct r8a66597 *r8a66597)
|
||||
{
|
||||
int timeout = 10000; /* 100usec * 10000 = 1sec */
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 5; i++) {
|
||||
/* check a usb cable connect */
|
||||
while (!(r8a66597_read(r8a66597, INTSTS1) & ATTCH)) {
|
||||
if (timeout-- < 0) {
|
||||
printf("%s timeout.\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
udelay(100);
|
||||
}
|
||||
|
||||
/* check a data line */
|
||||
r8a66597_check_syssts(r8a66597, 0);
|
||||
|
||||
r8a66597_bus_reset(r8a66597, 0);
|
||||
r8a66597->speed = get_rh_usb_speed(r8a66597, 0);
|
||||
|
||||
if (!(r8a66597_read(r8a66597, INTSTS1) & DTCH)) {
|
||||
r8a66597->port_change = USB_PORT_STAT_C_CONNECTION;
|
||||
r8a66597->port_status = USB_PORT_STAT_CONNECTION |
|
||||
USB_PORT_STAT_ENABLE;
|
||||
return 0; /* success */
|
||||
}
|
||||
|
||||
R8A66597_DPRINT("USB device has detached. retry = %d\n", i);
|
||||
r8a66597_write(r8a66597, ~DTCH, INTSTS1);
|
||||
}
|
||||
|
||||
return -1; /* fail */
|
||||
}
|
||||
|
||||
/* based on usb_ohci.c */
|
||||
#define min_t(type, x, y) \
|
||||
({ type __x = (x); type __y = (y); __x < __y ? __x : __y; })
|
||||
/*-------------------------------------------------------------------------*
|
||||
* Virtual Root Hub
|
||||
*-------------------------------------------------------------------------*/
|
||||
|
||||
/* Device descriptor */
|
||||
static __u8 root_hub_dev_des[] =
|
||||
{
|
||||
0x12, /* __u8 bLength; */
|
||||
0x01, /* __u8 bDescriptorType; Device */
|
||||
0x10, /* __u16 bcdUSB; v1.1 */
|
||||
0x01,
|
||||
0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
|
||||
0x00, /* __u8 bDeviceSubClass; */
|
||||
0x00, /* __u8 bDeviceProtocol; */
|
||||
0x08, /* __u8 bMaxPacketSize0; 8 Bytes */
|
||||
0x00, /* __u16 idVendor; */
|
||||
0x00,
|
||||
0x00, /* __u16 idProduct; */
|
||||
0x00,
|
||||
0x00, /* __u16 bcdDevice; */
|
||||
0x00,
|
||||
0x00, /* __u8 iManufacturer; */
|
||||
0x01, /* __u8 iProduct; */
|
||||
0x00, /* __u8 iSerialNumber; */
|
||||
0x01 /* __u8 bNumConfigurations; */
|
||||
};
|
||||
|
||||
/* Configuration descriptor */
|
||||
static __u8 root_hub_config_des[] =
|
||||
{
|
||||
0x09, /* __u8 bLength; */
|
||||
0x02, /* __u8 bDescriptorType; Configuration */
|
||||
0x19, /* __u16 wTotalLength; */
|
||||
0x00,
|
||||
0x01, /* __u8 bNumInterfaces; */
|
||||
0x01, /* __u8 bConfigurationValue; */
|
||||
0x00, /* __u8 iConfiguration; */
|
||||
0x40, /* __u8 bmAttributes; */
|
||||
|
||||
0x00, /* __u8 MaxPower; */
|
||||
|
||||
/* interface */
|
||||
0x09, /* __u8 if_bLength; */
|
||||
0x04, /* __u8 if_bDescriptorType; Interface */
|
||||
0x00, /* __u8 if_bInterfaceNumber; */
|
||||
0x00, /* __u8 if_bAlternateSetting; */
|
||||
0x01, /* __u8 if_bNumEndpoints; */
|
||||
0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */
|
||||
0x00, /* __u8 if_bInterfaceSubClass; */
|
||||
0x00, /* __u8 if_bInterfaceProtocol; */
|
||||
0x00, /* __u8 if_iInterface; */
|
||||
|
||||
/* endpoint */
|
||||
0x07, /* __u8 ep_bLength; */
|
||||
0x05, /* __u8 ep_bDescriptorType; Endpoint */
|
||||
0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
|
||||
0x03, /* __u8 ep_bmAttributes; Interrupt */
|
||||
0x02, /* __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */
|
||||
0x00,
|
||||
0xff /* __u8 ep_bInterval; 255 ms */
|
||||
};
|
||||
|
||||
static unsigned char root_hub_str_index0[] =
|
||||
{
|
||||
0x04, /* __u8 bLength; */
|
||||
0x03, /* __u8 bDescriptorType; String-descriptor */
|
||||
0x09, /* __u8 lang ID */
|
||||
0x04, /* __u8 lang ID */
|
||||
};
|
||||
|
||||
static unsigned char root_hub_str_index1[] =
|
||||
{
|
||||
34, /* __u8 bLength; */
|
||||
0x03, /* __u8 bDescriptorType; String-descriptor */
|
||||
'R', /* __u8 Unicode */
|
||||
0, /* __u8 Unicode */
|
||||
'8', /* __u8 Unicode */
|
||||
0, /* __u8 Unicode */
|
||||
'A', /* __u8 Unicode */
|
||||
0, /* __u8 Unicode */
|
||||
'6', /* __u8 Unicode */
|
||||
0, /* __u8 Unicode */
|
||||
'6', /* __u8 Unicode */
|
||||
0, /* __u8 Unicode */
|
||||
'5', /* __u8 Unicode */
|
||||
0, /* __u8 Unicode */
|
||||
'9', /* __u8 Unicode */
|
||||
0, /* __u8 Unicode */
|
||||
'7', /* __u8 Unicode */
|
||||
0, /* __u8 Unicode */
|
||||
' ', /* __u8 Unicode */
|
||||
0, /* __u8 Unicode */
|
||||
'R', /* __u8 Unicode */
|
||||
0, /* __u8 Unicode */
|
||||
'o', /* __u8 Unicode */
|
||||
0, /* __u8 Unicode */
|
||||
'o', /* __u8 Unicode */
|
||||
0, /* __u8 Unicode */
|
||||
't', /* __u8 Unicode */
|
||||
0, /* __u8 Unicode */
|
||||
'H', /* __u8 Unicode */
|
||||
0, /* __u8 Unicode */
|
||||
'u', /* __u8 Unicode */
|
||||
0, /* __u8 Unicode */
|
||||
'b', /* __u8 Unicode */
|
||||
0, /* __u8 Unicode */
|
||||
};
|
||||
|
||||
static int r8a66597_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
|
||||
void *buffer, int transfer_len, struct devrequest *cmd)
|
||||
{
|
||||
struct r8a66597 *r8a66597 = &gr8a66597;
|
||||
int leni = transfer_len;
|
||||
int len = 0;
|
||||
int stat = 0;
|
||||
__u16 bmRType_bReq;
|
||||
__u16 wValue;
|
||||
__u16 wIndex;
|
||||
__u16 wLength;
|
||||
unsigned char data[32];
|
||||
|
||||
R8A66597_DPRINT("%s\n", __func__);
|
||||
|
||||
if (usb_pipeint(pipe)) {
|
||||
printf("Root-Hub submit IRQ: NOT implemented");
|
||||
return 0;
|
||||
}
|
||||
|
||||
bmRType_bReq = cmd->requesttype | (cmd->request << 8);
|
||||
wValue = cpu_to_le16 (cmd->value);
|
||||
wIndex = cpu_to_le16 (cmd->index);
|
||||
wLength = cpu_to_le16 (cmd->length);
|
||||
|
||||
switch (bmRType_bReq) {
|
||||
case RH_GET_STATUS:
|
||||
*(__u16 *)buffer = cpu_to_le16(1);
|
||||
len = 2;
|
||||
break;
|
||||
case RH_GET_STATUS | RH_INTERFACE:
|
||||
*(__u16 *)buffer = cpu_to_le16(0);
|
||||
len = 2;
|
||||
break;
|
||||
case RH_GET_STATUS | RH_ENDPOINT:
|
||||
*(__u16 *)buffer = cpu_to_le16(0);
|
||||
len = 2;
|
||||
break;
|
||||
case RH_GET_STATUS | RH_CLASS:
|
||||
*(__u32 *)buffer = cpu_to_le32(0);
|
||||
len = 4;
|
||||
break;
|
||||
case RH_GET_STATUS | RH_OTHER | RH_CLASS:
|
||||
*(__u32 *)buffer = cpu_to_le32(r8a66597->port_status |
|
||||
(r8a66597->port_change << 16));
|
||||
len = 4;
|
||||
break;
|
||||
case RH_CLEAR_FEATURE | RH_ENDPOINT:
|
||||
case RH_CLEAR_FEATURE | RH_CLASS:
|
||||
break;
|
||||
|
||||
case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
|
||||
switch (wValue) {
|
||||
case RH_C_PORT_CONNECTION:
|
||||
r8a66597->port_change &= ~USB_PORT_STAT_C_CONNECTION;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
|
||||
switch (wValue) {
|
||||
case (RH_PORT_SUSPEND):
|
||||
break;
|
||||
case (RH_PORT_RESET):
|
||||
r8a66597_bus_reset(r8a66597, 0);
|
||||
break;
|
||||
case (RH_PORT_POWER):
|
||||
break;
|
||||
case (RH_PORT_ENABLE):
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case RH_SET_ADDRESS:
|
||||
gr8a66597.rh_devnum = wValue;
|
||||
break;
|
||||
case RH_GET_DESCRIPTOR:
|
||||
switch ((wValue & 0xff00) >> 8) {
|
||||
case (0x01): /* device descriptor */
|
||||
len = min_t(unsigned int,
|
||||
leni,
|
||||
min_t(unsigned int,
|
||||
sizeof(root_hub_dev_des),
|
||||
wLength));
|
||||
memcpy(buffer, root_hub_dev_des, len);
|
||||
break;
|
||||
case (0x02): /* configuration descriptor */
|
||||
len = min_t(unsigned int,
|
||||
leni,
|
||||
min_t(unsigned int,
|
||||
sizeof(root_hub_config_des),
|
||||
wLength));
|
||||
memcpy(buffer, root_hub_config_des, len);
|
||||
break;
|
||||
case (0x03): /* string descriptors */
|
||||
if (wValue == 0x0300) {
|
||||
len = min_t(unsigned int,
|
||||
leni,
|
||||
min_t(unsigned int,
|
||||
sizeof(root_hub_str_index0),
|
||||
wLength));
|
||||
memcpy(buffer, root_hub_str_index0, len);
|
||||
}
|
||||
if (wValue == 0x0301) {
|
||||
len = min_t(unsigned int,
|
||||
leni,
|
||||
min_t(unsigned int,
|
||||
sizeof(root_hub_str_index1),
|
||||
wLength));
|
||||
memcpy(buffer, root_hub_str_index1, len);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
stat = USB_ST_STALLED;
|
||||
}
|
||||
break;
|
||||
|
||||
case RH_GET_DESCRIPTOR | RH_CLASS:
|
||||
{
|
||||
__u32 temp = 0x00000001;
|
||||
|
||||
data[0] = 9; /* min length; */
|
||||
data[1] = 0x29;
|
||||
data[2] = temp & RH_A_NDP;
|
||||
data[3] = 0;
|
||||
if (temp & RH_A_PSM)
|
||||
data[3] |= 0x1;
|
||||
if (temp & RH_A_NOCP)
|
||||
data[3] |= 0x10;
|
||||
else if (temp & RH_A_OCPM)
|
||||
data[3] |= 0x8;
|
||||
|
||||
/* corresponds to data[4-7] */
|
||||
data[5] = (temp & RH_A_POTPGT) >> 24;
|
||||
data[7] = temp & RH_B_DR;
|
||||
if (data[2] < 7) {
|
||||
data[8] = 0xff;
|
||||
} else {
|
||||
data[0] += 2;
|
||||
data[8] = (temp & RH_B_DR) >> 8;
|
||||
data[10] = data[9] = 0xff;
|
||||
}
|
||||
|
||||
len = min_t(unsigned int, leni,
|
||||
min_t(unsigned int, data[0], wLength));
|
||||
memcpy(buffer, data, len);
|
||||
break;
|
||||
}
|
||||
|
||||
case RH_GET_CONFIGURATION:
|
||||
*(__u8 *) buffer = 0x01;
|
||||
len = 1;
|
||||
break;
|
||||
case RH_SET_CONFIGURATION:
|
||||
break;
|
||||
default:
|
||||
R8A66597_DPRINT("unsupported root hub command");
|
||||
stat = USB_ST_STALLED;
|
||||
}
|
||||
|
||||
wait_ms(1);
|
||||
|
||||
len = min_t(int, len, leni);
|
||||
|
||||
dev->act_len = len;
|
||||
dev->status = stat;
|
||||
|
||||
return stat;
|
||||
}
|
||||
|
||||
int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
|
||||
int transfer_len)
|
||||
{
|
||||
struct r8a66597 *r8a66597 = &gr8a66597;
|
||||
int ret = 0;
|
||||
|
||||
R8A66597_DPRINT("%s\n", __func__);
|
||||
R8A66597_DPRINT("pipe = %08x, buffer = %p, len = %d, devnum = %d\n",
|
||||
pipe, buffer, transfer_len, dev->devnum);
|
||||
|
||||
set_devadd(r8a66597, dev->devnum, dev, 0);
|
||||
|
||||
pipe_buffer_setting(r8a66597, dev, pipe);
|
||||
|
||||
dev->act_len = 0;
|
||||
while (dev->act_len < transfer_len && ret == 0) {
|
||||
if (ctrlc())
|
||||
return -1;
|
||||
|
||||
if (usb_pipein(pipe))
|
||||
ret = receive_bulk_packet(r8a66597, dev, pipe, buffer,
|
||||
transfer_len);
|
||||
else
|
||||
ret = send_bulk_packet(r8a66597, dev, pipe, buffer,
|
||||
transfer_len);
|
||||
}
|
||||
|
||||
if (ret == 0)
|
||||
dev->status = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int submit_control_msg(struct usb_device *dev, unsigned long pipe,
|
||||
void *buffer, int transfer_len, struct devrequest *setup)
|
||||
{
|
||||
struct r8a66597 *r8a66597 = &gr8a66597;
|
||||
u16 r8a66597_address = setup->request == USB_REQ_SET_ADDRESS ?
|
||||
0 : dev->devnum;
|
||||
|
||||
R8A66597_DPRINT("%s\n", __func__);
|
||||
if (usb_pipedevice(pipe) == r8a66597->rh_devnum)
|
||||
return r8a66597_submit_rh_msg(dev, pipe, buffer, transfer_len,
|
||||
setup);
|
||||
|
||||
R8A66597_DPRINT("%s: setup\n", __func__);
|
||||
set_devadd(r8a66597, r8a66597_address, dev, 0);
|
||||
|
||||
if (send_setup_packet(r8a66597, dev, setup) < 0) {
|
||||
printf("setup packet send error\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
dev->act_len = 0;
|
||||
if (usb_pipein(pipe))
|
||||
if (receive_control_packet(r8a66597, dev, buffer,
|
||||
transfer_len) < 0)
|
||||
return -1;
|
||||
|
||||
if (send_status_packet(r8a66597, pipe) < 0)
|
||||
return -1;
|
||||
|
||||
dev->status = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
|
||||
int transfer_len, int interval)
|
||||
{
|
||||
/* no implement */
|
||||
R8A66597_DPRINT("%s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void usb_event_poll(void)
|
||||
{
|
||||
/* no implement */
|
||||
R8A66597_DPRINT("%s\n", __func__);
|
||||
}
|
||||
|
||||
int usb_lowlevel_init(void)
|
||||
{
|
||||
struct r8a66597 *r8a66597 = &gr8a66597;
|
||||
|
||||
R8A66597_DPRINT("%s\n", __func__);
|
||||
|
||||
memset(r8a66597, 0, sizeof(r8a66597));
|
||||
r8a66597->reg = CONFIG_R8A66597_BASE_ADDR;
|
||||
|
||||
disable_controller(r8a66597);
|
||||
wait_ms(100);
|
||||
|
||||
enable_controller(r8a66597);
|
||||
r8a66597_port_power(r8a66597, 0 , 1);
|
||||
|
||||
/* check usb device */
|
||||
check_usb_device_connecting(r8a66597);
|
||||
|
||||
wait_ms(50);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_lowlevel_stop(void)
|
||||
{
|
||||
disable_controller(&gr8a66597);
|
||||
|
||||
return 0;
|
||||
}
|
||||
659
drivers/usb/host/r8a66597.h
Normal file
659
drivers/usb/host/r8a66597.h
Normal file
@@ -0,0 +1,659 @@
|
||||
/*
|
||||
* R8A66597 HCD (Host Controller Driver) for u-boot
|
||||
*
|
||||
* Copyright (C) 2008 Yoshihiro Shimoda <shimoda.yoshihiro@renesas.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; version 2 of the License.
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __R8A66597_H__
|
||||
#define __R8A66597_H__
|
||||
|
||||
#define SYSCFG0 0x00
|
||||
#define SYSCFG1 0x02
|
||||
#define SYSSTS0 0x04
|
||||
#define SYSSTS1 0x06
|
||||
#define DVSTCTR0 0x08
|
||||
#define DVSTCTR1 0x0A
|
||||
#define TESTMODE 0x0C
|
||||
#define PINCFG 0x0E
|
||||
#define DMA0CFG 0x10
|
||||
#define DMA1CFG 0x12
|
||||
#define CFIFO 0x14
|
||||
#define D0FIFO 0x18
|
||||
#define D1FIFO 0x1C
|
||||
#define CFIFOSEL 0x20
|
||||
#define CFIFOCTR 0x22
|
||||
#define CFIFOSIE 0x24
|
||||
#define D0FIFOSEL 0x28
|
||||
#define D0FIFOCTR 0x2A
|
||||
#define D1FIFOSEL 0x2C
|
||||
#define D1FIFOCTR 0x2E
|
||||
#define INTENB0 0x30
|
||||
#define INTENB1 0x32
|
||||
#define INTENB2 0x34
|
||||
#define BRDYENB 0x36
|
||||
#define NRDYENB 0x38
|
||||
#define BEMPENB 0x3A
|
||||
#define SOFCFG 0x3C
|
||||
#define INTSTS0 0x40
|
||||
#define INTSTS1 0x42
|
||||
#define INTSTS2 0x44
|
||||
#define BRDYSTS 0x46
|
||||
#define NRDYSTS 0x48
|
||||
#define BEMPSTS 0x4A
|
||||
#define FRMNUM 0x4C
|
||||
#define UFRMNUM 0x4E
|
||||
#define USBADDR 0x50
|
||||
#define USBREQ 0x54
|
||||
#define USBVAL 0x56
|
||||
#define USBINDX 0x58
|
||||
#define USBLENG 0x5A
|
||||
#define DCPCFG 0x5C
|
||||
#define DCPMAXP 0x5E
|
||||
#define DCPCTR 0x60
|
||||
#define PIPESEL 0x64
|
||||
#define PIPECFG 0x68
|
||||
#define PIPEBUF 0x6A
|
||||
#define PIPEMAXP 0x6C
|
||||
#define PIPEPERI 0x6E
|
||||
#define PIPE1CTR 0x70
|
||||
#define PIPE2CTR 0x72
|
||||
#define PIPE3CTR 0x74
|
||||
#define PIPE4CTR 0x76
|
||||
#define PIPE5CTR 0x78
|
||||
#define PIPE6CTR 0x7A
|
||||
#define PIPE7CTR 0x7C
|
||||
#define PIPE8CTR 0x7E
|
||||
#define PIPE9CTR 0x80
|
||||
#define PIPE1TRE 0x90
|
||||
#define PIPE1TRN 0x92
|
||||
#define PIPE2TRE 0x94
|
||||
#define PIPE2TRN 0x96
|
||||
#define PIPE3TRE 0x98
|
||||
#define PIPE3TRN 0x9A
|
||||
#define PIPE4TRE 0x9C
|
||||
#define PIPE4TRN 0x9E
|
||||
#define PIPE5TRE 0xA0
|
||||
#define PIPE5TRN 0xA2
|
||||
#define DEVADD0 0xD0
|
||||
#define DEVADD1 0xD2
|
||||
#define DEVADD2 0xD4
|
||||
#define DEVADD3 0xD6
|
||||
#define DEVADD4 0xD8
|
||||
#define DEVADD5 0xDA
|
||||
#define DEVADD6 0xDC
|
||||
#define DEVADD7 0xDE
|
||||
#define DEVADD8 0xE0
|
||||
#define DEVADD9 0xE2
|
||||
#define DEVADDA 0xE4
|
||||
|
||||
/* System Configuration Control Register */
|
||||
#define XTAL 0xC000 /* b15-14: Crystal selection */
|
||||
#define XTAL48 0x8000 /* 48MHz */
|
||||
#define XTAL24 0x4000 /* 24MHz */
|
||||
#define XTAL12 0x0000 /* 12MHz */
|
||||
#define XCKE 0x2000 /* b13: External clock enable */
|
||||
#define PLLC 0x0800 /* b11: PLL control */
|
||||
#define SCKE 0x0400 /* b10: USB clock enable */
|
||||
#define PCSDIS 0x0200 /* b9: not CS wakeup */
|
||||
#define LPSME 0x0100 /* b8: Low power sleep mode */
|
||||
#define HSE 0x0080 /* b7: Hi-speed enable */
|
||||
#define DCFM 0x0040 /* b6: Controller function select */
|
||||
#define DRPD 0x0020 /* b5: D+/- pull down control */
|
||||
#define DPRPU 0x0010 /* b4: D+ pull up control */
|
||||
#define USBE 0x0001 /* b0: USB module operation enable */
|
||||
|
||||
/* System Configuration Status Register */
|
||||
#define OVCBIT 0x8000 /* b15-14: Over-current bit */
|
||||
#define OVCMON 0xC000 /* b15-14: Over-current monitor */
|
||||
#define SOFEA 0x0020 /* b5: SOF monitor */
|
||||
#define IDMON 0x0004 /* b3: ID-pin monitor */
|
||||
#define LNST 0x0003 /* b1-0: D+, D- line status */
|
||||
#define SE1 0x0003 /* SE1 */
|
||||
#define FS_KSTS 0x0002 /* Full-Speed K State */
|
||||
#define FS_JSTS 0x0001 /* Full-Speed J State */
|
||||
#define LS_JSTS 0x0002 /* Low-Speed J State */
|
||||
#define LS_KSTS 0x0001 /* Low-Speed K State */
|
||||
#define SE0 0x0000 /* SE0 */
|
||||
|
||||
/* Device State Control Register */
|
||||
#define EXTLP0 0x0400 /* b10: External port */
|
||||
#define VBOUT 0x0200 /* b9: VBUS output */
|
||||
#define WKUP 0x0100 /* b8: Remote wakeup */
|
||||
#define RWUPE 0x0080 /* b7: Remote wakeup sense */
|
||||
#define USBRST 0x0040 /* b6: USB reset enable */
|
||||
#define RESUME 0x0020 /* b5: Resume enable */
|
||||
#define UACT 0x0010 /* b4: USB bus enable */
|
||||
#define RHST 0x0007 /* b1-0: Reset handshake status */
|
||||
#define HSPROC 0x0004 /* HS handshake is processing */
|
||||
#define HSMODE 0x0003 /* Hi-Speed mode */
|
||||
#define FSMODE 0x0002 /* Full-Speed mode */
|
||||
#define LSMODE 0x0001 /* Low-Speed mode */
|
||||
#define UNDECID 0x0000 /* Undecided */
|
||||
|
||||
/* Test Mode Register */
|
||||
#define UTST 0x000F /* b3-0: Test select */
|
||||
#define H_TST_PACKET 0x000C /* HOST TEST Packet */
|
||||
#define H_TST_SE0_NAK 0x000B /* HOST TEST SE0 NAK */
|
||||
#define H_TST_K 0x000A /* HOST TEST K */
|
||||
#define H_TST_J 0x0009 /* HOST TEST J */
|
||||
#define H_TST_NORMAL 0x0000 /* HOST Normal Mode */
|
||||
#define P_TST_PACKET 0x0004 /* PERI TEST Packet */
|
||||
#define P_TST_SE0_NAK 0x0003 /* PERI TEST SE0 NAK */
|
||||
#define P_TST_K 0x0002 /* PERI TEST K */
|
||||
#define P_TST_J 0x0001 /* PERI TEST J */
|
||||
#define P_TST_NORMAL 0x0000 /* PERI Normal Mode */
|
||||
|
||||
/* Data Pin Configuration Register */
|
||||
#define LDRV 0x8000 /* b15: Drive Current Adjust */
|
||||
#define VIF1 0x0000 /* VIF = 1.8V */
|
||||
#define VIF3 0x8000 /* VIF = 3.3V */
|
||||
#define INTA 0x0001 /* b1: USB INT-pin active */
|
||||
|
||||
/* DMAx Pin Configuration Register */
|
||||
#define DREQA 0x4000 /* b14: Dreq active select */
|
||||
#define BURST 0x2000 /* b13: Burst mode */
|
||||
#define DACKA 0x0400 /* b10: Dack active select */
|
||||
#define DFORM 0x0380 /* b9-7: DMA mode select */
|
||||
#define CPU_ADR_RD_WR 0x0000 /* Address + RD/WR mode (CPU bus) */
|
||||
#define CPU_DACK_RD_WR 0x0100 /* DACK + RD/WR mode (CPU bus) */
|
||||
#define CPU_DACK_ONLY 0x0180 /* DACK only mode (CPU bus) */
|
||||
#define SPLIT_DACK_ONLY 0x0200 /* DACK only mode (SPLIT bus) */
|
||||
#define DENDA 0x0040 /* b6: Dend active select */
|
||||
#define PKTM 0x0020 /* b5: Packet mode */
|
||||
#define DENDE 0x0010 /* b4: Dend enable */
|
||||
#define OBUS 0x0004 /* b2: OUTbus mode */
|
||||
|
||||
/* CFIFO/DxFIFO Port Select Register */
|
||||
#define RCNT 0x8000 /* b15: Read count mode */
|
||||
#define REW 0x4000 /* b14: Buffer rewind */
|
||||
#define DCLRM 0x2000 /* b13: DMA buffer clear mode */
|
||||
#define DREQE 0x1000 /* b12: DREQ output enable */
|
||||
#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
|
||||
#define MBW 0x0800
|
||||
#else
|
||||
#define MBW 0x0400 /* b10: Maximum bit width for FIFO access */
|
||||
#endif
|
||||
#define MBW_8 0x0000 /* 8bit */
|
||||
#define MBW_16 0x0400 /* 16bit */
|
||||
#define BIGEND 0x0100 /* b8: Big endian mode */
|
||||
#define BYTE_LITTLE 0x0000 /* little dendian */
|
||||
#define BYTE_BIG 0x0100 /* big endifan */
|
||||
#define ISEL 0x0020 /* b5: DCP FIFO port direction select */
|
||||
#define CURPIPE 0x000F /* b2-0: PIPE select */
|
||||
|
||||
/* CFIFO/DxFIFO Port Control Register */
|
||||
#define BVAL 0x8000 /* b15: Buffer valid flag */
|
||||
#define BCLR 0x4000 /* b14: Buffer clear */
|
||||
#define FRDY 0x2000 /* b13: FIFO ready */
|
||||
#define DTLN 0x0FFF /* b11-0: FIFO received data length */
|
||||
|
||||
/* Interrupt Enable Register 0 */
|
||||
#define VBSE 0x8000 /* b15: VBUS interrupt */
|
||||
#define RSME 0x4000 /* b14: Resume interrupt */
|
||||
#define SOFE 0x2000 /* b13: Frame update interrupt */
|
||||
#define DVSE 0x1000 /* b12: Device state transition interrupt */
|
||||
#define CTRE 0x0800 /* b11: Control transfer stage transition interrupt */
|
||||
#define BEMPE 0x0400 /* b10: Buffer empty interrupt */
|
||||
#define NRDYE 0x0200 /* b9: Buffer not ready interrupt */
|
||||
#define BRDYE 0x0100 /* b8: Buffer ready interrupt */
|
||||
|
||||
/* Interrupt Enable Register 1 */
|
||||
#define OVRCRE 0x8000 /* b15: Over-current interrupt */
|
||||
#define BCHGE 0x4000 /* b14: USB us chenge interrupt */
|
||||
#define DTCHE 0x1000 /* b12: Detach sense interrupt */
|
||||
#define ATTCHE 0x0800 /* b11: Attach sense interrupt */
|
||||
#define EOFERRE 0x0040 /* b6: EOF error interrupt */
|
||||
#define SIGNE 0x0020 /* b5: SETUP IGNORE interrupt */
|
||||
#define SACKE 0x0010 /* b4: SETUP ACK interrupt */
|
||||
|
||||
/* BRDY Interrupt Enable/Status Register */
|
||||
#define BRDY9 0x0200 /* b9: PIPE9 */
|
||||
#define BRDY8 0x0100 /* b8: PIPE8 */
|
||||
#define BRDY7 0x0080 /* b7: PIPE7 */
|
||||
#define BRDY6 0x0040 /* b6: PIPE6 */
|
||||
#define BRDY5 0x0020 /* b5: PIPE5 */
|
||||
#define BRDY4 0x0010 /* b4: PIPE4 */
|
||||
#define BRDY3 0x0008 /* b3: PIPE3 */
|
||||
#define BRDY2 0x0004 /* b2: PIPE2 */
|
||||
#define BRDY1 0x0002 /* b1: PIPE1 */
|
||||
#define BRDY0 0x0001 /* b1: PIPE0 */
|
||||
|
||||
/* NRDY Interrupt Enable/Status Register */
|
||||
#define NRDY9 0x0200 /* b9: PIPE9 */
|
||||
#define NRDY8 0x0100 /* b8: PIPE8 */
|
||||
#define NRDY7 0x0080 /* b7: PIPE7 */
|
||||
#define NRDY6 0x0040 /* b6: PIPE6 */
|
||||
#define NRDY5 0x0020 /* b5: PIPE5 */
|
||||
#define NRDY4 0x0010 /* b4: PIPE4 */
|
||||
#define NRDY3 0x0008 /* b3: PIPE3 */
|
||||
#define NRDY2 0x0004 /* b2: PIPE2 */
|
||||
#define NRDY1 0x0002 /* b1: PIPE1 */
|
||||
#define NRDY0 0x0001 /* b1: PIPE0 */
|
||||
|
||||
/* BEMP Interrupt Enable/Status Register */
|
||||
#define BEMP9 0x0200 /* b9: PIPE9 */
|
||||
#define BEMP8 0x0100 /* b8: PIPE8 */
|
||||
#define BEMP7 0x0080 /* b7: PIPE7 */
|
||||
#define BEMP6 0x0040 /* b6: PIPE6 */
|
||||
#define BEMP5 0x0020 /* b5: PIPE5 */
|
||||
#define BEMP4 0x0010 /* b4: PIPE4 */
|
||||
#define BEMP3 0x0008 /* b3: PIPE3 */
|
||||
#define BEMP2 0x0004 /* b2: PIPE2 */
|
||||
#define BEMP1 0x0002 /* b1: PIPE1 */
|
||||
#define BEMP0 0x0001 /* b0: PIPE0 */
|
||||
|
||||
/* SOF Pin Configuration Register */
|
||||
#define TRNENSEL 0x0100 /* b8: Select transaction enable period */
|
||||
#define BRDYM 0x0040 /* b6: BRDY clear timing */
|
||||
#define INTL 0x0020 /* b5: Interrupt sense select */
|
||||
#define EDGESTS 0x0010 /* b4: */
|
||||
#define SOFMODE 0x000C /* b3-2: SOF pin select */
|
||||
#define SOF_125US 0x0008 /* SOF OUT 125us Frame Signal */
|
||||
#define SOF_1MS 0x0004 /* SOF OUT 1ms Frame Signal */
|
||||
#define SOF_DISABLE 0x0000 /* SOF OUT Disable */
|
||||
|
||||
/* Interrupt Status Register 0 */
|
||||
#define VBINT 0x8000 /* b15: VBUS interrupt */
|
||||
#define RESM 0x4000 /* b14: Resume interrupt */
|
||||
#define SOFR 0x2000 /* b13: SOF frame update interrupt */
|
||||
#define DVST 0x1000 /* b12: Device state transition interrupt */
|
||||
#define CTRT 0x0800 /* b11: Control transfer stage transition interrupt */
|
||||
#define BEMP 0x0400 /* b10: Buffer empty interrupt */
|
||||
#define NRDY 0x0200 /* b9: Buffer not ready interrupt */
|
||||
#define BRDY 0x0100 /* b8: Buffer ready interrupt */
|
||||
#define VBSTS 0x0080 /* b7: VBUS input port */
|
||||
#define DVSQ 0x0070 /* b6-4: Device state */
|
||||
#define DS_SPD_CNFG 0x0070 /* Suspend Configured */
|
||||
#define DS_SPD_ADDR 0x0060 /* Suspend Address */
|
||||
#define DS_SPD_DFLT 0x0050 /* Suspend Default */
|
||||
#define DS_SPD_POWR 0x0040 /* Suspend Powered */
|
||||
#define DS_SUSP 0x0040 /* Suspend */
|
||||
#define DS_CNFG 0x0030 /* Configured */
|
||||
#define DS_ADDS 0x0020 /* Address */
|
||||
#define DS_DFLT 0x0010 /* Default */
|
||||
#define DS_POWR 0x0000 /* Powered */
|
||||
#define DVSQS 0x0030 /* b5-4: Device state */
|
||||
#define VALID 0x0008 /* b3: Setup packet detected flag */
|
||||
#define CTSQ 0x0007 /* b2-0: Control transfer stage */
|
||||
#define CS_SQER 0x0006 /* Sequence error */
|
||||
#define CS_WRND 0x0005 /* Control write nodata status stage */
|
||||
#define CS_WRSS 0x0004 /* Control write status stage */
|
||||
#define CS_WRDS 0x0003 /* Control write data stage */
|
||||
#define CS_RDSS 0x0002 /* Control read status stage */
|
||||
#define CS_RDDS 0x0001 /* Control read data stage */
|
||||
#define CS_IDST 0x0000 /* Idle or setup stage */
|
||||
|
||||
/* Interrupt Status Register 1 */
|
||||
#define OVRCR 0x8000 /* b15: Over-current interrupt */
|
||||
#define BCHG 0x4000 /* b14: USB bus chenge interrupt */
|
||||
#define DTCH 0x1000 /* b12: Detach sense interrupt */
|
||||
#define ATTCH 0x0800 /* b11: Attach sense interrupt */
|
||||
#define EOFERR 0x0040 /* b6: EOF-error interrupt */
|
||||
#define SIGN 0x0020 /* b5: Setup ignore interrupt */
|
||||
#define SACK 0x0010 /* b4: Setup acknowledge interrupt */
|
||||
|
||||
/* Frame Number Register */
|
||||
#define OVRN 0x8000 /* b15: Overrun error */
|
||||
#define CRCE 0x4000 /* b14: Received data error */
|
||||
#define FRNM 0x07FF /* b10-0: Frame number */
|
||||
|
||||
/* Micro Frame Number Register */
|
||||
#define UFRNM 0x0007 /* b2-0: Micro frame number */
|
||||
|
||||
/* Default Control Pipe Maxpacket Size Register */
|
||||
/* Pipe Maxpacket Size Register */
|
||||
#define DEVSEL 0xF000 /* b15-14: Device address select */
|
||||
#define MAXP 0x007F /* b6-0: Maxpacket size of default control pipe */
|
||||
|
||||
/* Default Control Pipe Control Register */
|
||||
#define BSTS 0x8000 /* b15: Buffer status */
|
||||
#define SUREQ 0x4000 /* b14: Send USB request */
|
||||
#define CSCLR 0x2000 /* b13: complete-split status clear */
|
||||
#define CSSTS 0x1000 /* b12: complete-split status */
|
||||
#define SUREQCLR 0x0800 /* b11: stop setup request */
|
||||
#define SQCLR 0x0100 /* b8: Sequence toggle bit clear */
|
||||
#define SQSET 0x0080 /* b7: Sequence toggle bit set */
|
||||
#define SQMON 0x0040 /* b6: Sequence toggle bit monitor */
|
||||
#define PBUSY 0x0020 /* b5: pipe busy */
|
||||
#define PINGE 0x0010 /* b4: ping enable */
|
||||
#define CCPL 0x0004 /* b2: Enable control transfer complete */
|
||||
#define PID 0x0003 /* b1-0: Response PID */
|
||||
#define PID_STALL11 0x0003 /* STALL */
|
||||
#define PID_STALL 0x0002 /* STALL */
|
||||
#define PID_BUF 0x0001 /* BUF */
|
||||
#define PID_NAK 0x0000 /* NAK */
|
||||
|
||||
/* Pipe Window Select Register */
|
||||
#define PIPENM 0x0007 /* b2-0: Pipe select */
|
||||
|
||||
/* Pipe Configuration Register */
|
||||
#define R8A66597_TYP 0xC000 /* b15-14: Transfer type */
|
||||
#define R8A66597_ISO 0xC000 /* Isochronous */
|
||||
#define R8A66597_INT 0x8000 /* Interrupt */
|
||||
#define R8A66597_BULK 0x4000 /* Bulk */
|
||||
#define R8A66597_BFRE 0x0400 /* b10: Buffer ready interrupt mode select */
|
||||
#define R8A66597_DBLB 0x0200 /* b9: Double buffer mode select */
|
||||
#define R8A66597_CNTMD 0x0100 /* b8: Continuous transfer mode select */
|
||||
#define R8A66597_SHTNAK 0x0080 /* b7: Transfer end NAK */
|
||||
#define R8A66597_DIR 0x0010 /* b4: Transfer direction select */
|
||||
#define R8A66597_EPNUM 0x000F /* b3-0: Eendpoint number select */
|
||||
|
||||
/* Pipe Buffer Configuration Register */
|
||||
#define BUFSIZE 0x7C00 /* b14-10: Pipe buffer size */
|
||||
#define BUFNMB 0x007F /* b6-0: Pipe buffer number */
|
||||
#define PIPE0BUF 256
|
||||
#define PIPExBUF 64
|
||||
|
||||
/* Pipe Maxpacket Size Register */
|
||||
#define MXPS 0x07FF /* b10-0: Maxpacket size */
|
||||
|
||||
/* Pipe Cycle Configuration Register */
|
||||
#define IFIS 0x1000 /* b12: Isochronous in-buffer flush mode select */
|
||||
#define IITV 0x0007 /* b2-0: Isochronous interval */
|
||||
|
||||
/* Pipex Control Register */
|
||||
#define BSTS 0x8000 /* b15: Buffer status */
|
||||
#define INBUFM 0x4000 /* b14: IN buffer monitor (Only for PIPE1 to 5) */
|
||||
#define CSCLR 0x2000 /* b13: complete-split status clear */
|
||||
#define CSSTS 0x1000 /* b12: complete-split status */
|
||||
#define ATREPM 0x0400 /* b10: Auto repeat mode */
|
||||
#define ACLRM 0x0200 /* b9: Out buffer auto clear mode */
|
||||
#define SQCLR 0x0100 /* b8: Sequence toggle bit clear */
|
||||
#define SQSET 0x0080 /* b7: Sequence toggle bit set */
|
||||
#define SQMON 0x0040 /* b6: Sequence toggle bit monitor */
|
||||
#define PBUSY 0x0020 /* b5: pipe busy */
|
||||
#define PID 0x0003 /* b1-0: Response PID */
|
||||
|
||||
/* PIPExTRE */
|
||||
#define TRENB 0x0200 /* b9: Transaction counter enable */
|
||||
#define TRCLR 0x0100 /* b8: Transaction counter clear */
|
||||
|
||||
/* PIPExTRN */
|
||||
#define TRNCNT 0xFFFF /* b15-0: Transaction counter */
|
||||
|
||||
/* DEVADDx */
|
||||
#define UPPHUB 0x7800
|
||||
#define HUBPORT 0x0700
|
||||
#define USBSPD 0x00C0
|
||||
#define RTPORT 0x0001
|
||||
|
||||
#define R8A66597_MAX_NUM_PIPE 10
|
||||
#define R8A66597_BUF_BSIZE 8
|
||||
#define R8A66597_MAX_DEVICE 10
|
||||
#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
|
||||
#define R8A66597_MAX_ROOT_HUB 1
|
||||
#else
|
||||
#define R8A66597_MAX_ROOT_HUB 2
|
||||
#endif
|
||||
#define R8A66597_MAX_SAMPLING 5
|
||||
#define R8A66597_RH_POLL_TIME 10
|
||||
|
||||
#define BULK_IN_PIPENUM 3
|
||||
#define BULK_IN_BUFNUM 8
|
||||
|
||||
#define BULK_OUT_PIPENUM 4
|
||||
#define BULK_OUT_BUFNUM 40
|
||||
|
||||
#define check_bulk_or_isoc(pipenum) ((pipenum >= 1 && pipenum <= 5))
|
||||
#define check_interrupt(pipenum) ((pipenum >= 6 && pipenum <= 9))
|
||||
#define make_devsel(addr) (addr << 12)
|
||||
|
||||
struct r8a66597 {
|
||||
unsigned long reg;
|
||||
unsigned short pipe_config; /* bit field */
|
||||
unsigned short port_status;
|
||||
unsigned short port_change;
|
||||
u16 speed; /* HSMODE or FSMODE or LSMODE */
|
||||
unsigned char rh_devnum;
|
||||
};
|
||||
|
||||
static inline u16 r8a66597_read(struct r8a66597 *r8a66597, unsigned long offset)
|
||||
{
|
||||
return inw(r8a66597->reg + offset);
|
||||
}
|
||||
|
||||
static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597,
|
||||
unsigned long offset, void *buf,
|
||||
int len)
|
||||
{
|
||||
int i;
|
||||
#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
|
||||
unsigned long fifoaddr = r8a66597->reg + offset;
|
||||
unsigned long count;
|
||||
unsigned long *p = buf;
|
||||
|
||||
count = len / 4;
|
||||
for (i = 0; i < count; i++)
|
||||
inl(p[i], r8a66597->reg + offset);
|
||||
|
||||
if (len & 0x00000003) {
|
||||
unsigned long tmp = inl(fifoaddr);
|
||||
memcpy((unsigned char *)buf + count * 4, &tmp, len & 0x03);
|
||||
}
|
||||
#else
|
||||
unsigned short *p = buf;
|
||||
|
||||
len = (len + 1) / 2;
|
||||
for (i = 0; i < len; i++)
|
||||
p[i] = inw(r8a66597->reg + offset);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void r8a66597_write(struct r8a66597 *r8a66597, u16 val,
|
||||
unsigned long offset)
|
||||
{
|
||||
outw(val, r8a66597->reg + offset);
|
||||
}
|
||||
|
||||
static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597,
|
||||
unsigned long offset, void *buf,
|
||||
int len)
|
||||
{
|
||||
int i;
|
||||
unsigned long fifoaddr = r8a66597->reg + offset;
|
||||
#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
|
||||
unsigned long count;
|
||||
unsigned char *pb;
|
||||
unsigned long *p = buf;
|
||||
|
||||
count = len / 4;
|
||||
for (i = 0; i < count; i++)
|
||||
outl(p[i], fifoaddr);
|
||||
|
||||
if (len & 0x00000003) {
|
||||
pb = (unsigned char *)buf + count * 4;
|
||||
for (i = 0; i < (len & 0x00000003); i++) {
|
||||
if (r8a66597_read(r8a66597, CFIFOSEL) & BIGEND)
|
||||
outb(pb[i], fifoaddr + i);
|
||||
else
|
||||
outb(pb[i], fifoaddr + 3 - i);
|
||||
}
|
||||
}
|
||||
#else
|
||||
int odd = len & 0x0001;
|
||||
unsigned short *p = buf;
|
||||
|
||||
len = len / 2;
|
||||
for (i = 0; i < len; i++)
|
||||
outw(p[i], fifoaddr);
|
||||
|
||||
if (odd) {
|
||||
unsigned char *pb = (unsigned char *)(buf + len);
|
||||
outb(*pb, fifoaddr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void r8a66597_mdfy(struct r8a66597 *r8a66597,
|
||||
u16 val, u16 pat, unsigned long offset)
|
||||
{
|
||||
u16 tmp;
|
||||
tmp = r8a66597_read(r8a66597, offset);
|
||||
tmp = tmp & (~pat);
|
||||
tmp = tmp | val;
|
||||
r8a66597_write(r8a66597, tmp, offset);
|
||||
}
|
||||
|
||||
#define r8a66597_bclr(r8a66597, val, offset) \
|
||||
r8a66597_mdfy(r8a66597, 0, val, offset)
|
||||
#define r8a66597_bset(r8a66597, val, offset) \
|
||||
r8a66597_mdfy(r8a66597, val, 0, offset)
|
||||
|
||||
static inline unsigned long get_syscfg_reg(int port)
|
||||
{
|
||||
return port == 0 ? SYSCFG0 : SYSCFG1;
|
||||
}
|
||||
|
||||
static inline unsigned long get_syssts_reg(int port)
|
||||
{
|
||||
return port == 0 ? SYSSTS0 : SYSSTS1;
|
||||
}
|
||||
|
||||
static inline unsigned long get_dvstctr_reg(int port)
|
||||
{
|
||||
return port == 0 ? DVSTCTR0 : DVSTCTR1;
|
||||
}
|
||||
|
||||
static inline unsigned long get_dmacfg_reg(int port)
|
||||
{
|
||||
return port == 0 ? DMA0CFG : DMA1CFG;
|
||||
}
|
||||
|
||||
static inline unsigned long get_intenb_reg(int port)
|
||||
{
|
||||
return port == 0 ? INTENB1 : INTENB2;
|
||||
}
|
||||
|
||||
static inline unsigned long get_intsts_reg(int port)
|
||||
{
|
||||
return port == 0 ? INTSTS1 : INTSTS2;
|
||||
}
|
||||
|
||||
static inline u16 get_rh_usb_speed(struct r8a66597 *r8a66597, int port)
|
||||
{
|
||||
unsigned long dvstctr_reg = get_dvstctr_reg(port);
|
||||
|
||||
return r8a66597_read(r8a66597, dvstctr_reg) & RHST;
|
||||
}
|
||||
|
||||
static inline void r8a66597_port_power(struct r8a66597 *r8a66597, int port,
|
||||
int power)
|
||||
{
|
||||
unsigned long dvstctr_reg = get_dvstctr_reg(port);
|
||||
|
||||
if (power)
|
||||
r8a66597_bset(r8a66597, VBOUT, dvstctr_reg);
|
||||
else
|
||||
r8a66597_bclr(r8a66597, VBOUT, dvstctr_reg);
|
||||
}
|
||||
|
||||
#define get_pipectr_addr(pipenum) (PIPE1CTR + (pipenum - 1) * 2)
|
||||
#define get_pipetre_addr(pipenum) (PIPE1TRE + (pipenum - 1) * 4)
|
||||
#define get_pipetrn_addr(pipenum) (PIPE1TRN + (pipenum - 1) * 4)
|
||||
#define get_devadd_addr(address) (DEVADD0 + address * 2)
|
||||
|
||||
|
||||
/* USB HUB CONSTANTS (not OHCI-specific; see hub.h, based on usb_ohci.h) */
|
||||
|
||||
/* destination of request */
|
||||
#define RH_INTERFACE 0x01
|
||||
#define RH_ENDPOINT 0x02
|
||||
#define RH_OTHER 0x03
|
||||
|
||||
#define RH_CLASS 0x20
|
||||
#define RH_VENDOR 0x40
|
||||
|
||||
/* Requests: bRequest << 8 | bmRequestType */
|
||||
#define RH_GET_STATUS 0x0080
|
||||
#define RH_CLEAR_FEATURE 0x0100
|
||||
#define RH_SET_FEATURE 0x0300
|
||||
#define RH_SET_ADDRESS 0x0500
|
||||
#define RH_GET_DESCRIPTOR 0x0680
|
||||
#define RH_SET_DESCRIPTOR 0x0700
|
||||
#define RH_GET_CONFIGURATION 0x0880
|
||||
#define RH_SET_CONFIGURATION 0x0900
|
||||
#define RH_GET_STATE 0x0280
|
||||
#define RH_GET_INTERFACE 0x0A80
|
||||
#define RH_SET_INTERFACE 0x0B00
|
||||
#define RH_SYNC_FRAME 0x0C80
|
||||
/* Our Vendor Specific Request */
|
||||
#define RH_SET_EP 0x2000
|
||||
|
||||
/* Hub port features */
|
||||
#define RH_PORT_CONNECTION 0x00
|
||||
#define RH_PORT_ENABLE 0x01
|
||||
#define RH_PORT_SUSPEND 0x02
|
||||
#define RH_PORT_OVER_CURRENT 0x03
|
||||
#define RH_PORT_RESET 0x04
|
||||
#define RH_PORT_POWER 0x08
|
||||
#define RH_PORT_LOW_SPEED 0x09
|
||||
|
||||
#define RH_C_PORT_CONNECTION 0x10
|
||||
#define RH_C_PORT_ENABLE 0x11
|
||||
#define RH_C_PORT_SUSPEND 0x12
|
||||
#define RH_C_PORT_OVER_CURRENT 0x13
|
||||
#define RH_C_PORT_RESET 0x14
|
||||
|
||||
/* Hub features */
|
||||
#define RH_C_HUB_LOCAL_POWER 0x00
|
||||
#define RH_C_HUB_OVER_CURRENT 0x01
|
||||
|
||||
#define RH_DEVICE_REMOTE_WAKEUP 0x00
|
||||
#define RH_ENDPOINT_STALL 0x01
|
||||
|
||||
#define RH_ACK 0x01
|
||||
#define RH_REQ_ERR -1
|
||||
#define RH_NACK 0x00
|
||||
|
||||
/* OHCI ROOT HUB REGISTER MASKS */
|
||||
|
||||
/* roothub.portstatus [i] bits */
|
||||
#define RH_PS_CCS 0x00000001 /* current connect status */
|
||||
#define RH_PS_PES 0x00000002 /* port enable status*/
|
||||
#define RH_PS_PSS 0x00000004 /* port suspend status */
|
||||
#define RH_PS_POCI 0x00000008 /* port over current indicator */
|
||||
#define RH_PS_PRS 0x00000010 /* port reset status */
|
||||
#define RH_PS_PPS 0x00000100 /* port power status */
|
||||
#define RH_PS_LSDA 0x00000200 /* low speed device attached */
|
||||
#define RH_PS_CSC 0x00010000 /* connect status change */
|
||||
#define RH_PS_PESC 0x00020000 /* port enable status change */
|
||||
#define RH_PS_PSSC 0x00040000 /* port suspend status change */
|
||||
#define RH_PS_OCIC 0x00080000 /* over current indicator change */
|
||||
#define RH_PS_PRSC 0x00100000 /* port reset status change */
|
||||
|
||||
/* roothub.status bits */
|
||||
#define RH_HS_LPS 0x00000001 /* local power status */
|
||||
#define RH_HS_OCI 0x00000002 /* over current indicator */
|
||||
#define RH_HS_DRWE 0x00008000 /* device remote wakeup enable */
|
||||
#define RH_HS_LPSC 0x00010000 /* local power status change */
|
||||
#define RH_HS_OCIC 0x00020000 /* over current indicator change */
|
||||
#define RH_HS_CRWE 0x80000000 /* clear remote wakeup enable */
|
||||
|
||||
/* roothub.b masks */
|
||||
#define RH_B_DR 0x0000ffff /* device removable flags */
|
||||
#define RH_B_PPCM 0xffff0000 /* port power control mask */
|
||||
|
||||
/* roothub.a masks */
|
||||
#define RH_A_NDP (0xff << 0) /* number of downstream ports */
|
||||
#define RH_A_PSM (1 << 8) /* power switching mode */
|
||||
#define RH_A_NPS (1 << 9) /* no power switching */
|
||||
#define RH_A_DT (1 << 10) /* device type (mbz) */
|
||||
#define RH_A_OCPM (1 << 11) /* over current protection mode */
|
||||
#define RH_A_NOCP (1 << 12) /* no over current protection */
|
||||
#define RH_A_POTPGT (0xff << 24) /* power on to power good time */
|
||||
|
||||
#endif /* __R8A66597_H__ */
|
||||
45
drivers/usb/host/s3c64xx-hcd.c
Normal file
45
drivers/usb/host/s3c64xx-hcd.c
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* URB OHCI HCD (Host Controller Driver) initialization for USB on the S3C64XX.
|
||||
*
|
||||
* Copyright (C) 2008,
|
||||
* Guennadi Liakhovetski, DENX Software Engineering <lg@denx.de>
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* 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 <s3c6400.h>
|
||||
|
||||
int usb_cpu_init(void)
|
||||
{
|
||||
OTHERS_REG |= 0x10000;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_cpu_stop(void)
|
||||
{
|
||||
OTHERS_REG &= ~0x10000;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void usb_cpu_init_fail(void)
|
||||
{
|
||||
OTHERS_REG &= ~0x10000;
|
||||
}
|
||||
734
drivers/usb/host/sl811-hcd.c
Normal file
734
drivers/usb/host/sl811-hcd.c
Normal file
@@ -0,0 +1,734 @@
|
||||
/*
|
||||
* (C) Copyright 2004
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*
|
||||
* This code is based on linux driver for sl811hs chip, source at
|
||||
* drivers/usb/host/sl811.c:
|
||||
*
|
||||
* SL811 Host Controller Interface driver for USB.
|
||||
*
|
||||
* Copyright (c) 2003/06, Courage Co., Ltd.
|
||||
*
|
||||
* Based on:
|
||||
* 1.uhci.c by Linus Torvalds, Johannes Erdfelt, Randy Dunlap,
|
||||
* Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber,
|
||||
* Adam Richter, Gregory P. Smith;
|
||||
* 2.Original SL811 driver (hc_sl811.o) by Pei Liu <pbl@cypress.com>
|
||||
* 3.Rewrited as sl811.o by Yin Aihua <yinah:couragetech.com.cn>
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* 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 <mpc8xx.h>
|
||||
#include <usb.h>
|
||||
#include "sl811.h"
|
||||
|
||||
#include "../../../board/kup/common/kup.h"
|
||||
|
||||
#ifdef __PPC__
|
||||
# define EIEIO __asm__ volatile ("eieio")
|
||||
#else
|
||||
# define EIEIO /* nothing */
|
||||
#endif
|
||||
|
||||
#define SL811_ADR (0x50000000)
|
||||
#define SL811_DAT (0x50000001)
|
||||
|
||||
#define mdelay(n) ({unsigned long msec=(n); while (msec--) udelay(1000);})
|
||||
|
||||
#ifdef SL811_DEBUG
|
||||
static int debug = 9;
|
||||
#endif
|
||||
|
||||
static int root_hub_devnum = 0;
|
||||
static struct usb_port_status rh_status = { 0 };/* root hub port status */
|
||||
|
||||
static int sl811_rh_submit_urb(struct usb_device *usb_dev, unsigned long pipe,
|
||||
void *data, int buf_len, struct devrequest *cmd);
|
||||
|
||||
static void sl811_write (__u8 index, __u8 data)
|
||||
{
|
||||
*(volatile unsigned char *) (SL811_ADR) = index;
|
||||
EIEIO;
|
||||
*(volatile unsigned char *) (SL811_DAT) = data;
|
||||
EIEIO;
|
||||
}
|
||||
|
||||
static __u8 sl811_read (__u8 index)
|
||||
{
|
||||
__u8 data;
|
||||
|
||||
*(volatile unsigned char *) (SL811_ADR) = index;
|
||||
EIEIO;
|
||||
data = *(volatile unsigned char *) (SL811_DAT);
|
||||
EIEIO;
|
||||
return (data);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read consecutive bytes of data from the SL811H/SL11H buffer
|
||||
*/
|
||||
static void inline sl811_read_buf(__u8 offset, __u8 *buf, __u8 size)
|
||||
{
|
||||
*(volatile unsigned char *) (SL811_ADR) = offset;
|
||||
EIEIO;
|
||||
while (size--) {
|
||||
*buf++ = *(volatile unsigned char *) (SL811_DAT);
|
||||
EIEIO;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Write consecutive bytes of data to the SL811H/SL11H buffer
|
||||
*/
|
||||
static void inline sl811_write_buf(__u8 offset, __u8 *buf, __u8 size)
|
||||
{
|
||||
*(volatile unsigned char *) (SL811_ADR) = offset;
|
||||
EIEIO;
|
||||
while (size--) {
|
||||
*(volatile unsigned char *) (SL811_DAT) = *buf++;
|
||||
EIEIO;
|
||||
}
|
||||
}
|
||||
|
||||
int usb_init_kup4x (void)
|
||||
{
|
||||
volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
|
||||
volatile memctl8xx_t *memctl = &immap->im_memctl;
|
||||
int i;
|
||||
unsigned char tmp;
|
||||
|
||||
memctl = &immap->im_memctl;
|
||||
memctl->memc_or7 = 0xFFFF8726;
|
||||
memctl->memc_br7 = 0x50000401; /* start at 0x50000000 */
|
||||
/* BP 14 low = USB ON */
|
||||
immap->im_cpm.cp_pbdat &= ~(BP_USB_VCC);
|
||||
/* PB 14 nomal port */
|
||||
immap->im_cpm.cp_pbpar &= ~(BP_USB_VCC);
|
||||
/* output */
|
||||
immap->im_cpm.cp_pbdir |= (BP_USB_VCC);
|
||||
|
||||
puts ("USB: ");
|
||||
|
||||
for (i = 0x10; i < 0xff; i++) {
|
||||
sl811_write(i, i);
|
||||
tmp = (sl811_read(i));
|
||||
if (tmp != i) {
|
||||
printf ("SL811 compare error index=0x%02x read=0x%02x\n", i, tmp);
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
printf ("SL811 ready\n");
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function resets SL811HS controller and detects the speed of
|
||||
* the connecting device
|
||||
*
|
||||
* Return: 0 = no device attached; 1 = USB device attached
|
||||
*/
|
||||
static int sl811_hc_reset(void)
|
||||
{
|
||||
int status ;
|
||||
|
||||
sl811_write(SL811_CTRL2, SL811_CTL2_HOST | SL811_12M_HI);
|
||||
sl811_write(SL811_CTRL1, SL811_CTRL1_RESET);
|
||||
|
||||
mdelay(20);
|
||||
|
||||
/* Disable hardware SOF generation, clear all irq status. */
|
||||
sl811_write(SL811_CTRL1, 0);
|
||||
mdelay(2);
|
||||
sl811_write(SL811_INTRSTS, 0xff);
|
||||
status = sl811_read(SL811_INTRSTS);
|
||||
|
||||
if (status & SL811_INTR_NOTPRESENT) {
|
||||
/* Device is not present */
|
||||
PDEBUG(0, "Device not present\n");
|
||||
rh_status.wPortStatus &= ~(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE);
|
||||
rh_status.wPortChange |= USB_PORT_STAT_C_CONNECTION;
|
||||
sl811_write(SL811_INTR, SL811_INTR_INSRMV);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Send SOF to address 0, endpoint 0. */
|
||||
sl811_write(SL811_LEN_B, 0);
|
||||
sl811_write(SL811_PIDEP_B, PIDEP(USB_PID_SOF, 0));
|
||||
sl811_write(SL811_DEV_B, 0x00);
|
||||
sl811_write(SL811_SOFLOW, SL811_12M_LOW);
|
||||
|
||||
if (status & SL811_INTR_SPEED_FULL) {
|
||||
/* full speed device connect directly to root hub */
|
||||
PDEBUG (0, "Full speed Device attached\n");
|
||||
|
||||
sl811_write(SL811_CTRL1, SL811_CTRL1_RESET);
|
||||
mdelay(20);
|
||||
sl811_write(SL811_CTRL2, SL811_CTL2_HOST | SL811_12M_HI);
|
||||
sl811_write(SL811_CTRL1, SL811_CTRL1_SOF);
|
||||
|
||||
/* start the SOF or EOP */
|
||||
sl811_write(SL811_CTRL_B, SL811_USB_CTRL_ARM);
|
||||
rh_status.wPortStatus |= USB_PORT_STAT_CONNECTION;
|
||||
rh_status.wPortStatus &= ~USB_PORT_STAT_LOW_SPEED;
|
||||
mdelay(2);
|
||||
sl811_write(SL811_INTRSTS, 0xff);
|
||||
} else {
|
||||
/* slow speed device connect directly to root-hub */
|
||||
PDEBUG(0, "Low speed Device attached\n");
|
||||
|
||||
sl811_write(SL811_CTRL1, SL811_CTRL1_RESET);
|
||||
mdelay(20);
|
||||
sl811_write(SL811_CTRL2, SL811_CTL2_HOST | SL811_CTL2_DSWAP | SL811_12M_HI);
|
||||
sl811_write(SL811_CTRL1, SL811_CTRL1_SPEED_LOW | SL811_CTRL1_SOF);
|
||||
|
||||
/* start the SOF or EOP */
|
||||
sl811_write(SL811_CTRL_B, SL811_USB_CTRL_ARM);
|
||||
rh_status.wPortStatus |= USB_PORT_STAT_CONNECTION | USB_PORT_STAT_LOW_SPEED;
|
||||
mdelay(2);
|
||||
sl811_write(SL811_INTRSTS, 0xff);
|
||||
}
|
||||
|
||||
rh_status.wPortChange |= USB_PORT_STAT_C_CONNECTION;
|
||||
sl811_write(SL811_INTR, /*SL811_INTR_INSRMV*/SL811_INTR_DONE_A);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int usb_lowlevel_init(void)
|
||||
{
|
||||
root_hub_devnum = 0;
|
||||
sl811_hc_reset();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_lowlevel_stop(void)
|
||||
{
|
||||
sl811_hc_reset();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int calc_needed_buswidth(int bytes, int need_preamble)
|
||||
{
|
||||
return !need_preamble ? bytes * 8 + 256 : 8 * 8 * bytes + 2048;
|
||||
}
|
||||
|
||||
static int sl811_send_packet(struct usb_device *dev, unsigned long pipe, __u8 *buffer, int len)
|
||||
{
|
||||
__u8 ctrl = SL811_USB_CTRL_ARM | SL811_USB_CTRL_ENABLE;
|
||||
__u16 status = 0;
|
||||
int err = 0, time_start = get_timer(0);
|
||||
int need_preamble = !(rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED) &&
|
||||
usb_pipeslow(pipe);
|
||||
|
||||
if (len > 239)
|
||||
return -1;
|
||||
|
||||
if (usb_pipeout(pipe))
|
||||
ctrl |= SL811_USB_CTRL_DIR_OUT;
|
||||
if (usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)))
|
||||
ctrl |= SL811_USB_CTRL_TOGGLE_1;
|
||||
if (need_preamble)
|
||||
ctrl |= SL811_USB_CTRL_PREAMBLE;
|
||||
|
||||
sl811_write(SL811_INTRSTS, 0xff);
|
||||
|
||||
while (err < 3) {
|
||||
sl811_write(SL811_ADDR_A, 0x10);
|
||||
sl811_write(SL811_LEN_A, len);
|
||||
if (usb_pipeout(pipe) && len)
|
||||
sl811_write_buf(0x10, buffer, len);
|
||||
|
||||
if (!(rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED) &&
|
||||
sl811_read(SL811_SOFCNTDIV)*64 < calc_needed_buswidth(len, need_preamble))
|
||||
ctrl |= SL811_USB_CTRL_SOF;
|
||||
else
|
||||
ctrl &= ~SL811_USB_CTRL_SOF;
|
||||
|
||||
sl811_write(SL811_CTRL_A, ctrl);
|
||||
while (!(sl811_read(SL811_INTRSTS) & SL811_INTR_DONE_A)) {
|
||||
if (5*CONFIG_SYS_HZ < get_timer(time_start)) {
|
||||
printf("USB transmit timed out\n");
|
||||
return -USB_ST_CRC_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
sl811_write(SL811_INTRSTS, 0xff);
|
||||
status = sl811_read(SL811_STS_A);
|
||||
|
||||
if (status & SL811_USB_STS_ACK) {
|
||||
int remainder = sl811_read(SL811_CNT_A);
|
||||
if (remainder) {
|
||||
PDEBUG(0, "usb transfer remainder = %d\n", remainder);
|
||||
len -= remainder;
|
||||
}
|
||||
if (usb_pipein(pipe) && len)
|
||||
sl811_read_buf(0x10, buffer, len);
|
||||
return len;
|
||||
}
|
||||
|
||||
if ((status & SL811_USB_STS_NAK) == SL811_USB_STS_NAK)
|
||||
continue;
|
||||
|
||||
PDEBUG(0, "usb transfer error %#x\n", (int)status);
|
||||
err++;
|
||||
}
|
||||
|
||||
err = 0;
|
||||
|
||||
if (status & SL811_USB_STS_ERROR)
|
||||
err |= USB_ST_BUF_ERR;
|
||||
if (status & SL811_USB_STS_TIMEOUT)
|
||||
err |= USB_ST_CRC_ERR;
|
||||
if (status & SL811_USB_STS_STALL)
|
||||
err |= USB_ST_STALLED;
|
||||
|
||||
return -err;
|
||||
}
|
||||
|
||||
int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
|
||||
int len)
|
||||
{
|
||||
int dir_out = usb_pipeout(pipe);
|
||||
int ep = usb_pipeendpoint(pipe);
|
||||
int max = usb_maxpacket(dev, pipe);
|
||||
int done = 0;
|
||||
|
||||
PDEBUG(7, "dev = %ld pipe = %ld buf = %p size = %d dir_out = %d\n",
|
||||
usb_pipedevice(pipe), usb_pipeendpoint(pipe), buffer, len, dir_out);
|
||||
|
||||
dev->status = 0;
|
||||
|
||||
sl811_write(SL811_DEV_A, usb_pipedevice(pipe));
|
||||
sl811_write(SL811_PIDEP_A, PIDEP(!dir_out ? USB_PID_IN : USB_PID_OUT, ep));
|
||||
while (done < len) {
|
||||
int res = sl811_send_packet(dev, pipe, (__u8*)buffer+done,
|
||||
max > len - done ? len - done : max);
|
||||
if (res < 0) {
|
||||
dev->status = -res;
|
||||
return res;
|
||||
}
|
||||
|
||||
if (!dir_out && res < max) /* short packet */
|
||||
break;
|
||||
|
||||
done += res;
|
||||
usb_dotoggle(dev, ep, dir_out);
|
||||
}
|
||||
|
||||
dev->act_len = done;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
|
||||
int len,struct devrequest *setup)
|
||||
{
|
||||
int done = 0;
|
||||
int devnum = usb_pipedevice(pipe);
|
||||
int ep = usb_pipeendpoint(pipe);
|
||||
|
||||
dev->status = 0;
|
||||
|
||||
if (devnum == root_hub_devnum)
|
||||
return sl811_rh_submit_urb(dev, pipe, buffer, len, setup);
|
||||
|
||||
PDEBUG(7, "dev = %d pipe = %ld buf = %p size = %d rt = %#x req = %#x bus = %i\n",
|
||||
devnum, ep, buffer, len, (int)setup->requesttype,
|
||||
(int)setup->request, sl811_read(SL811_SOFCNTDIV)*64);
|
||||
|
||||
sl811_write(SL811_DEV_A, devnum);
|
||||
sl811_write(SL811_PIDEP_A, PIDEP(USB_PID_SETUP, ep));
|
||||
/* setup phase */
|
||||
usb_settoggle(dev, ep, 1, 0);
|
||||
if (sl811_send_packet(dev, usb_sndctrlpipe(dev, ep),
|
||||
(__u8*)setup, sizeof(*setup)) == sizeof(*setup)) {
|
||||
int dir_in = usb_pipein(pipe);
|
||||
int max = usb_maxpacket(dev, pipe);
|
||||
|
||||
/* data phase */
|
||||
sl811_write(SL811_PIDEP_A,
|
||||
PIDEP(dir_in ? USB_PID_IN : USB_PID_OUT, ep));
|
||||
usb_settoggle(dev, ep, usb_pipeout(pipe), 1);
|
||||
while (done < len) {
|
||||
int res = sl811_send_packet(dev, pipe, (__u8*)buffer+done,
|
||||
max > len - done ? len - done : max);
|
||||
if (res < 0) {
|
||||
PDEBUG(0, "status data failed!\n");
|
||||
dev->status = -res;
|
||||
return 0;
|
||||
}
|
||||
done += res;
|
||||
usb_dotoggle(dev, ep, usb_pipeout(pipe));
|
||||
if (dir_in && res < max) /* short packet */
|
||||
break;
|
||||
}
|
||||
|
||||
/* status phase */
|
||||
sl811_write(SL811_PIDEP_A,
|
||||
PIDEP(!dir_in ? USB_PID_IN : USB_PID_OUT, ep));
|
||||
usb_settoggle(dev, ep, !usb_pipeout(pipe), 1);
|
||||
if (sl811_send_packet(dev,
|
||||
!dir_in ? usb_rcvctrlpipe(dev, ep) :
|
||||
usb_sndctrlpipe(dev, ep),
|
||||
0, 0) < 0) {
|
||||
PDEBUG(0, "status phase failed!\n");
|
||||
dev->status = -1;
|
||||
}
|
||||
} else {
|
||||
PDEBUG(0, "setup phase failed!\n");
|
||||
dev->status = -1;
|
||||
}
|
||||
|
||||
dev->act_len = done;
|
||||
|
||||
return done;
|
||||
}
|
||||
|
||||
int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
|
||||
int len, int interval)
|
||||
{
|
||||
PDEBUG(0, "dev = %p pipe = %#lx buf = %p size = %d int = %d\n", dev, pipe,
|
||||
buffer, len, interval);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* SL811 Virtual Root Hub
|
||||
*/
|
||||
|
||||
/* Device descriptor */
|
||||
static __u8 sl811_rh_dev_des[] =
|
||||
{
|
||||
0x12, /* __u8 bLength; */
|
||||
0x01, /* __u8 bDescriptorType; Device */
|
||||
0x10, /* __u16 bcdUSB; v1.1 */
|
||||
0x01,
|
||||
0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
|
||||
0x00, /* __u8 bDeviceSubClass; */
|
||||
0x00, /* __u8 bDeviceProtocol; */
|
||||
0x08, /* __u8 bMaxPacketSize0; 8 Bytes */
|
||||
0x00, /* __u16 idVendor; */
|
||||
0x00,
|
||||
0x00, /* __u16 idProduct; */
|
||||
0x00,
|
||||
0x00, /* __u16 bcdDevice; */
|
||||
0x00,
|
||||
0x00, /* __u8 iManufacturer; */
|
||||
0x02, /* __u8 iProduct; */
|
||||
0x01, /* __u8 iSerialNumber; */
|
||||
0x01 /* __u8 bNumConfigurations; */
|
||||
};
|
||||
|
||||
/* Configuration descriptor */
|
||||
static __u8 sl811_rh_config_des[] =
|
||||
{
|
||||
0x09, /* __u8 bLength; */
|
||||
0x02, /* __u8 bDescriptorType; Configuration */
|
||||
0x19, /* __u16 wTotalLength; */
|
||||
0x00,
|
||||
0x01, /* __u8 bNumInterfaces; */
|
||||
0x01, /* __u8 bConfigurationValue; */
|
||||
0x00, /* __u8 iConfiguration; */
|
||||
0x40, /* __u8 bmAttributes;
|
||||
Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup,
|
||||
4..0: resvd */
|
||||
0x00, /* __u8 MaxPower; */
|
||||
|
||||
/* interface */
|
||||
0x09, /* __u8 if_bLength; */
|
||||
0x04, /* __u8 if_bDescriptorType; Interface */
|
||||
0x00, /* __u8 if_bInterfaceNumber; */
|
||||
0x00, /* __u8 if_bAlternateSetting; */
|
||||
0x01, /* __u8 if_bNumEndpoints; */
|
||||
0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */
|
||||
0x00, /* __u8 if_bInterfaceSubClass; */
|
||||
0x00, /* __u8 if_bInterfaceProtocol; */
|
||||
0x00, /* __u8 if_iInterface; */
|
||||
|
||||
/* endpoint */
|
||||
0x07, /* __u8 ep_bLength; */
|
||||
0x05, /* __u8 ep_bDescriptorType; Endpoint */
|
||||
0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
|
||||
0x03, /* __u8 ep_bmAttributes; Interrupt */
|
||||
0x08, /* __u16 ep_wMaxPacketSize; */
|
||||
0x00,
|
||||
0xff /* __u8 ep_bInterval; 255 ms */
|
||||
};
|
||||
|
||||
/* root hub class descriptor*/
|
||||
static __u8 sl811_rh_hub_des[] =
|
||||
{
|
||||
0x09, /* __u8 bLength; */
|
||||
0x29, /* __u8 bDescriptorType; Hub-descriptor */
|
||||
0x01, /* __u8 bNbrPorts; */
|
||||
0x00, /* __u16 wHubCharacteristics; */
|
||||
0x00,
|
||||
0x50, /* __u8 bPwrOn2pwrGood; 2ms */
|
||||
0x00, /* __u8 bHubContrCurrent; 0 mA */
|
||||
0xfc, /* __u8 DeviceRemovable; *** 7 Ports max *** */
|
||||
0xff /* __u8 PortPwrCtrlMask; *** 7 ports max *** */
|
||||
};
|
||||
|
||||
/*
|
||||
* helper routine for returning string descriptors in UTF-16LE
|
||||
* input can actually be ISO-8859-1; ASCII is its 7-bit subset
|
||||
*/
|
||||
static int ascii2utf (char *s, u8 *utf, int utfmax)
|
||||
{
|
||||
int retval;
|
||||
|
||||
for (retval = 0; *s && utfmax > 1; utfmax -= 2, retval += 2) {
|
||||
*utf++ = *s++;
|
||||
*utf++ = 0;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* root_hub_string is used by each host controller's root hub code,
|
||||
* so that they're identified consistently throughout the system.
|
||||
*/
|
||||
static int usb_root_hub_string (int id, int serial, char *type, __u8 *data, int len)
|
||||
{
|
||||
char buf [30];
|
||||
|
||||
/* assert (len > (2 * (sizeof (buf) + 1)));
|
||||
assert (strlen (type) <= 8);*/
|
||||
|
||||
/* language ids */
|
||||
if (id == 0) {
|
||||
*data++ = 4; *data++ = 3; /* 4 bytes data */
|
||||
*data++ = 0; *data++ = 0; /* some language id */
|
||||
return 4;
|
||||
|
||||
/* serial number */
|
||||
} else if (id == 1) {
|
||||
sprintf (buf, "%#x", serial);
|
||||
|
||||
/* product description */
|
||||
} else if (id == 2) {
|
||||
sprintf (buf, "USB %s Root Hub", type);
|
||||
|
||||
/* id 3 == vendor description */
|
||||
|
||||
/* unsupported IDs --> "stall" */
|
||||
} else
|
||||
return 0;
|
||||
|
||||
ascii2utf (buf, data + 2, len - 2);
|
||||
data [0] = 2 + strlen(buf) * 2;
|
||||
data [1] = 3;
|
||||
return data [0];
|
||||
}
|
||||
|
||||
/* helper macro */
|
||||
#define OK(x) len = (x); break
|
||||
|
||||
/*
|
||||
* This function handles all USB request to the the virtual root hub
|
||||
*/
|
||||
static int sl811_rh_submit_urb(struct usb_device *usb_dev, unsigned long pipe,
|
||||
void *data, int buf_len, struct devrequest *cmd)
|
||||
{
|
||||
__u8 data_buf[16];
|
||||
__u8 *bufp = data_buf;
|
||||
int len = 0;
|
||||
int status = 0;
|
||||
|
||||
__u16 bmRType_bReq;
|
||||
__u16 wValue;
|
||||
__u16 wIndex;
|
||||
__u16 wLength;
|
||||
|
||||
if (usb_pipeint(pipe)) {
|
||||
PDEBUG(0, "interrupt transfer unimplemented!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
bmRType_bReq = cmd->requesttype | (cmd->request << 8);
|
||||
wValue = le16_to_cpu (cmd->value);
|
||||
wIndex = le16_to_cpu (cmd->index);
|
||||
wLength = le16_to_cpu (cmd->length);
|
||||
|
||||
PDEBUG(5, "submit rh urb, req = %d(%x) val = %#x index = %#x len=%d\n",
|
||||
bmRType_bReq, bmRType_bReq, wValue, wIndex, wLength);
|
||||
|
||||
/* Request Destination:
|
||||
without flags: Device,
|
||||
USB_RECIP_INTERFACE: interface,
|
||||
USB_RECIP_ENDPOINT: endpoint,
|
||||
USB_TYPE_CLASS means HUB here,
|
||||
USB_RECIP_OTHER | USB_TYPE_CLASS almost ever means HUB_PORT here
|
||||
*/
|
||||
switch (bmRType_bReq) {
|
||||
case RH_GET_STATUS:
|
||||
*(__u16 *)bufp = cpu_to_le16(1);
|
||||
OK(2);
|
||||
|
||||
case RH_GET_STATUS | USB_RECIP_INTERFACE:
|
||||
*(__u16 *)bufp = cpu_to_le16(0);
|
||||
OK(2);
|
||||
|
||||
case RH_GET_STATUS | USB_RECIP_ENDPOINT:
|
||||
*(__u16 *)bufp = cpu_to_le16(0);
|
||||
OK(2);
|
||||
|
||||
case RH_GET_STATUS | USB_TYPE_CLASS:
|
||||
*(__u32 *)bufp = cpu_to_le32(0);
|
||||
OK(4);
|
||||
|
||||
case RH_GET_STATUS | USB_RECIP_OTHER | USB_TYPE_CLASS:
|
||||
*(__u32 *)bufp = cpu_to_le32(rh_status.wPortChange<<16 | rh_status.wPortStatus);
|
||||
OK(4);
|
||||
|
||||
case RH_CLEAR_FEATURE | USB_RECIP_ENDPOINT:
|
||||
switch (wValue) {
|
||||
case 1:
|
||||
OK(0);
|
||||
}
|
||||
break;
|
||||
|
||||
case RH_CLEAR_FEATURE | USB_TYPE_CLASS:
|
||||
switch (wValue) {
|
||||
case C_HUB_LOCAL_POWER:
|
||||
OK(0);
|
||||
|
||||
case C_HUB_OVER_CURRENT:
|
||||
OK(0);
|
||||
}
|
||||
break;
|
||||
|
||||
case RH_CLEAR_FEATURE | USB_RECIP_OTHER | USB_TYPE_CLASS:
|
||||
switch (wValue) {
|
||||
case USB_PORT_FEAT_ENABLE:
|
||||
rh_status.wPortStatus &= ~USB_PORT_STAT_ENABLE;
|
||||
OK(0);
|
||||
|
||||
case USB_PORT_FEAT_SUSPEND:
|
||||
rh_status.wPortStatus &= ~USB_PORT_STAT_SUSPEND;
|
||||
OK(0);
|
||||
|
||||
case USB_PORT_FEAT_POWER:
|
||||
rh_status.wPortStatus &= ~USB_PORT_STAT_POWER;
|
||||
OK(0);
|
||||
|
||||
case USB_PORT_FEAT_C_CONNECTION:
|
||||
rh_status.wPortChange &= ~USB_PORT_STAT_C_CONNECTION;
|
||||
OK(0);
|
||||
|
||||
case USB_PORT_FEAT_C_ENABLE:
|
||||
rh_status.wPortChange &= ~USB_PORT_STAT_C_ENABLE;
|
||||
OK(0);
|
||||
|
||||
case USB_PORT_FEAT_C_SUSPEND:
|
||||
rh_status.wPortChange &= ~USB_PORT_STAT_C_SUSPEND;
|
||||
OK(0);
|
||||
|
||||
case USB_PORT_FEAT_C_OVER_CURRENT:
|
||||
rh_status.wPortChange &= ~USB_PORT_STAT_C_OVERCURRENT;
|
||||
OK(0);
|
||||
|
||||
case USB_PORT_FEAT_C_RESET:
|
||||
rh_status.wPortChange &= ~USB_PORT_STAT_C_RESET;
|
||||
OK(0);
|
||||
}
|
||||
break;
|
||||
|
||||
case RH_SET_FEATURE | USB_RECIP_OTHER | USB_TYPE_CLASS:
|
||||
switch (wValue) {
|
||||
case USB_PORT_FEAT_SUSPEND:
|
||||
rh_status.wPortStatus |= USB_PORT_STAT_SUSPEND;
|
||||
OK(0);
|
||||
|
||||
case USB_PORT_FEAT_RESET:
|
||||
rh_status.wPortStatus |= USB_PORT_STAT_RESET;
|
||||
rh_status.wPortChange = 0;
|
||||
rh_status.wPortChange |= USB_PORT_STAT_C_RESET;
|
||||
rh_status.wPortStatus &= ~USB_PORT_STAT_RESET;
|
||||
rh_status.wPortStatus |= USB_PORT_STAT_ENABLE;
|
||||
OK(0);
|
||||
|
||||
case USB_PORT_FEAT_POWER:
|
||||
rh_status.wPortStatus |= USB_PORT_STAT_POWER;
|
||||
OK(0);
|
||||
|
||||
case USB_PORT_FEAT_ENABLE:
|
||||
rh_status.wPortStatus |= USB_PORT_STAT_ENABLE;
|
||||
OK(0);
|
||||
}
|
||||
break;
|
||||
|
||||
case RH_SET_ADDRESS:
|
||||
root_hub_devnum = wValue;
|
||||
OK(0);
|
||||
|
||||
case RH_GET_DESCRIPTOR:
|
||||
switch ((wValue & 0xff00) >> 8) {
|
||||
case USB_DT_DEVICE:
|
||||
len = sizeof(sl811_rh_dev_des);
|
||||
bufp = sl811_rh_dev_des;
|
||||
OK(len);
|
||||
|
||||
case USB_DT_CONFIG:
|
||||
len = sizeof(sl811_rh_config_des);
|
||||
bufp = sl811_rh_config_des;
|
||||
OK(len);
|
||||
|
||||
case USB_DT_STRING:
|
||||
len = usb_root_hub_string(wValue & 0xff, (int)(long)0, "SL811HS", data, wLength);
|
||||
if (len > 0) {
|
||||
bufp = data;
|
||||
OK(len);
|
||||
}
|
||||
|
||||
default:
|
||||
status = -32;
|
||||
}
|
||||
break;
|
||||
|
||||
case RH_GET_DESCRIPTOR | USB_TYPE_CLASS:
|
||||
len = sizeof(sl811_rh_hub_des);
|
||||
bufp = sl811_rh_hub_des;
|
||||
OK(len);
|
||||
|
||||
case RH_GET_CONFIGURATION:
|
||||
bufp[0] = 0x01;
|
||||
OK(1);
|
||||
|
||||
case RH_SET_CONFIGURATION:
|
||||
OK(0);
|
||||
|
||||
default:
|
||||
PDEBUG(1, "unsupported root hub command\n");
|
||||
status = -32;
|
||||
}
|
||||
|
||||
len = min(len, buf_len);
|
||||
if (data != bufp)
|
||||
memcpy(data, bufp, len);
|
||||
|
||||
PDEBUG(5, "len = %d, status = %d\n", len, status);
|
||||
|
||||
usb_dev->status = status;
|
||||
usb_dev->act_len = len;
|
||||
|
||||
return status == 0 ? len : status;
|
||||
}
|
||||
104
drivers/usb/host/sl811.h
Normal file
104
drivers/usb/host/sl811.h
Normal file
@@ -0,0 +1,104 @@
|
||||
#ifndef __UBOOT_SL811_H
|
||||
#define __UBOOT_SL811_H
|
||||
|
||||
#undef SL811_DEBUG
|
||||
|
||||
#ifdef SL811_DEBUG
|
||||
#define PDEBUG(level, fmt, args...) \
|
||||
if (debug >= (level)) printf("[%s:%d] " fmt, \
|
||||
__PRETTY_FUNCTION__, __LINE__ , ## args)
|
||||
#else
|
||||
#define PDEBUG(level, fmt, args...) do {} while(0)
|
||||
#endif
|
||||
|
||||
/* Sl811 host control register */
|
||||
#define SL811_CTRL_A 0x00
|
||||
#define SL811_ADDR_A 0x01
|
||||
#define SL811_LEN_A 0x02
|
||||
#define SL811_STS_A 0x03 /* read */
|
||||
#define SL811_PIDEP_A 0x03 /* write */
|
||||
#define SL811_CNT_A 0x04 /* read */
|
||||
#define SL811_DEV_A 0x04 /* write */
|
||||
#define SL811_CTRL1 0x05
|
||||
#define SL811_INTR 0x06
|
||||
#define SL811_CTRL_B 0x08
|
||||
#define SL811_ADDR_B 0x09
|
||||
#define SL811_LEN_B 0x0A
|
||||
#define SL811_STS_B 0x0B /* read */
|
||||
#define SL811_PIDEP_B 0x0B /* write */
|
||||
#define SL811_CNT_B 0x0C /* read */
|
||||
#define SL811_DEV_B 0x0C /* write */
|
||||
#define SL811_INTRSTS 0x0D /* write clears bitwise */
|
||||
#define SL811_HWREV 0x0E /* read */
|
||||
#define SL811_SOFLOW 0x0E /* write */
|
||||
#define SL811_SOFCNTDIV 0x0F /* read */
|
||||
#define SL811_CTRL2 0x0F /* write */
|
||||
|
||||
/* USB control register bits (addr 0x00 and addr 0x08) */
|
||||
#define SL811_USB_CTRL_ARM 0x01
|
||||
#define SL811_USB_CTRL_ENABLE 0x02
|
||||
#define SL811_USB_CTRL_DIR_OUT 0x04
|
||||
#define SL811_USB_CTRL_ISO 0x10
|
||||
#define SL811_USB_CTRL_SOF 0x20
|
||||
#define SL811_USB_CTRL_TOGGLE_1 0x40
|
||||
#define SL811_USB_CTRL_PREAMBLE 0x80
|
||||
|
||||
/* USB status register bits (addr 0x03 and addr 0x0B) */
|
||||
#define SL811_USB_STS_ACK 0x01
|
||||
#define SL811_USB_STS_ERROR 0x02
|
||||
#define SL811_USB_STS_TIMEOUT 0x04
|
||||
#define SL811_USB_STS_TOGGLE_1 0x08
|
||||
#define SL811_USB_STS_SETUP 0x10
|
||||
#define SL811_USB_STS_OVERFLOW 0x20
|
||||
#define SL811_USB_STS_NAK 0x40
|
||||
#define SL811_USB_STS_STALL 0x80
|
||||
|
||||
/* Control register 1 bits (addr 0x05) */
|
||||
#define SL811_CTRL1_SOF 0x01
|
||||
#define SL811_CTRL1_RESET 0x08
|
||||
#define SL811_CTRL1_JKSTATE 0x10
|
||||
#define SL811_CTRL1_SPEED_LOW 0x20
|
||||
#define SL811_CTRL1_SUSPEND 0x40
|
||||
|
||||
/* Interrut enable (addr 0x06) and interrupt status register bits (addr 0x0D) */
|
||||
#define SL811_INTR_DONE_A 0x01
|
||||
#define SL811_INTR_DONE_B 0x02
|
||||
#define SL811_INTR_SOF 0x10
|
||||
#define SL811_INTR_INSRMV 0x20
|
||||
#define SL811_INTR_DETECT 0x40
|
||||
#define SL811_INTR_NOTPRESENT 0x40
|
||||
#define SL811_INTR_SPEED_FULL 0x80 /* only in status reg */
|
||||
|
||||
/* HW rev and SOF lo register bits (addr 0x0E) */
|
||||
#define SL811_HWR_HWREV 0xF0
|
||||
|
||||
/* SOF counter and control reg 2 (addr 0x0F) */
|
||||
#define SL811_CTL2_SOFHI 0x3F
|
||||
#define SL811_CTL2_DSWAP 0x40
|
||||
#define SL811_CTL2_HOST 0x80
|
||||
|
||||
/* Set up for 1-ms SOF time. */
|
||||
#define SL811_12M_LOW 0xE0
|
||||
#define SL811_12M_HI 0x2E
|
||||
|
||||
#define SL811_DATA_START 0x10
|
||||
#define SL811_DATA_LIMIT 240
|
||||
|
||||
/* Requests: bRequest << 8 | bmRequestType */
|
||||
#define RH_GET_STATUS 0x0080
|
||||
#define RH_CLEAR_FEATURE 0x0100
|
||||
#define RH_SET_FEATURE 0x0300
|
||||
#define RH_SET_ADDRESS 0x0500
|
||||
#define RH_GET_DESCRIPTOR 0x0680
|
||||
#define RH_SET_DESCRIPTOR 0x0700
|
||||
#define RH_GET_CONFIGURATION 0x0880
|
||||
#define RH_SET_CONFIGURATION 0x0900
|
||||
#define RH_GET_STATE 0x0280
|
||||
#define RH_GET_INTERFACE 0x0A80
|
||||
#define RH_SET_INTERFACE 0x0B00
|
||||
#define RH_SYNC_FRAME 0x0C80
|
||||
|
||||
|
||||
#define PIDEP(pid, ep) (((pid) & 0x0f) << 4 | (ep))
|
||||
|
||||
#endif /* __UBOOT_SL811_H */
|
||||
Reference in New Issue
Block a user