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

* 'master' of git://git.denx.de/u-boot-usb:
  USB: efikamx: Enable USB on EfikaMX and EfikaSB
  USB: Add generic ULPI layer and a viewport
  USB: EHCI: Allow EHCI post-powerup configuration in board files
  USB: mx51evk: add end enable USB host support on port 1
  USB: mx53loco: add end enable USB host support on port 1
  USB: MX5: Add MX5 usb post-init callback
  USB: MX5: Abstract out mx51 USB pixmux configuration
  USB: MX5: add generic USB EHCI support for mx51 and mx53
  USB: MX5: add helper functions to enable USB clocks
  usb:gadget:s5p Enable the USB Gadget framework at GONI
  usb:gadget:s5p USB Device Controller (UDC) implementation
  ehci: speed up initialization
  usb: add help for missing start subcommand
  cosmetic: remove excess whitespace from usb command help
  usb: align usb_endpoint_descriptor to 16-bit boundary
  usbtty: init endpoints prior to startup events
  pxa: convert pxa27x_udc to use read and write functions
  pxa: activate the first usb host port on pxa27x by default
  pxa: fix usb host register mismatch
  ehci-fsl: correct size of ehci caplength
  USB: Add usb_event_poll() to get keyboards working with EHCI
  USB: gadaget: add Marvell controller support
  USB: Fix complaints about strict aliasing in OHCI-HCD
  USB: Drop dead code from usb_kbd.c
  USB: Rework usb_kbd.c
  USB: Add functionality to poll the USB keyboard via control EP
This commit is contained in:
Wolfgang Denk 2011-12-12 07:58:58 +01:00
commit b2eb7d9bc6
40 changed files with 5594 additions and 841 deletions

View File

@ -286,6 +286,7 @@ LIBS += drivers/usb/gadget/libusb_gadget.o
LIBS += drivers/usb/host/libusb_host.o
LIBS += drivers/usb/musb/libusb_musb.o
LIBS += drivers/usb/phy/libusb_phy.o
LIBS += drivers/usb/ulpi/libusb_ulpi.o
LIBS += drivers/video/libvideo.o
LIBS += drivers/watchdog/libwatchdog.o
LIBS += common/libcommon.o

View File

@ -50,6 +50,78 @@ struct mxc_pll_reg *mxc_plls[PLL_CLOCKS] = {
struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)MXC_CCM_BASE;
void set_usboh3_clk(void)
{
unsigned int reg;
reg = readl(&mxc_ccm->cscmr1) &
~MXC_CCM_CSCMR1_USBOH3_CLK_SEL_MASK;
reg |= 1 << MXC_CCM_CSCMR1_USBOH3_CLK_SEL_OFFSET;
writel(reg, &mxc_ccm->cscmr1);
reg = readl(&mxc_ccm->cscdr1);
reg &= ~MXC_CCM_CSCDR1_USBOH3_CLK_PODF_MASK;
reg &= ~MXC_CCM_CSCDR1_USBOH3_CLK_PRED_MASK;
reg |= 4 << MXC_CCM_CSCDR1_USBOH3_CLK_PRED_OFFSET;
reg |= 1 << MXC_CCM_CSCDR1_USBOH3_CLK_PODF_OFFSET;
writel(reg, &mxc_ccm->cscdr1);
}
void enable_usboh3_clk(unsigned char enable)
{
unsigned int reg;
reg = readl(&mxc_ccm->CCGR2);
if (enable)
reg |= 1 << MXC_CCM_CCGR2_CG14_OFFSET;
else
reg &= ~(1 << MXC_CCM_CCGR2_CG14_OFFSET);
writel(reg, &mxc_ccm->CCGR2);
}
void set_usb_phy1_clk(void)
{
unsigned int reg;
reg = readl(&mxc_ccm->cscmr1);
reg &= ~MXC_CCM_CSCMR1_USB_PHY_CLK_SEL;
writel(reg, &mxc_ccm->cscmr1);
}
void enable_usb_phy1_clk(unsigned char enable)
{
unsigned int reg;
reg = readl(&mxc_ccm->CCGR4);
if (enable)
reg |= 1 << MXC_CCM_CCGR4_CG5_OFFSET;
else
reg &= ~(1 << MXC_CCM_CCGR4_CG5_OFFSET);
writel(reg, &mxc_ccm->CCGR4);
}
void set_usb_phy2_clk(void)
{
unsigned int reg;
reg = readl(&mxc_ccm->cscmr1);
reg &= ~MXC_CCM_CSCMR1_USB_PHY_CLK_SEL;
writel(reg, &mxc_ccm->cscmr1);
}
void enable_usb_phy2_clk(unsigned char enable)
{
unsigned int reg;
reg = readl(&mxc_ccm->CCGR4);
if (enable)
reg |= 1 << MXC_CCM_CCGR4_CG6_OFFSET;
else
reg &= ~(1 << MXC_CCM_CCGR4_CG6_OFFSET);
writel(reg, &mxc_ccm->CCGR4);
}
/*
* Calculate the frequency of PLLn.
*/

View File

@ -55,7 +55,7 @@ int usb_cpu_init(void)
while (readl(UHCHR) & UHCHR_FSBIR)
udelay(1);
#if defined(CONFIG_CPU_MONAHANS)
#if defined(CONFIG_CPU_MONAHANS) || defined(CONFIG_PXA27X)
writel(readl(UHCHR) & ~UHCHR_SSEP0, UHCHR);
#endif
#if defined(CONFIG_CPU_PXA27X)
@ -72,10 +72,10 @@ int usb_cpu_stop(void)
udelay(11);
writel(readl(UHCHR) & ~UHCHR_FHR, UHCHR);
writel(readl(UHCCOMS) | UHCHR_FHR, UHCCOMS);
writel(readl(UHCCOMS) | UHCCOMS_HCR, UHCCOMS);
udelay(10);
#if defined(CONFIG_CPU_MONAHANS)
#if defined(CONFIG_CPU_MONAHANS) || defined(CONFIG_PXA27X)
writel(readl(UHCHR) | UHCHR_SSEP0, UHCHR);
#endif
#if defined(CONFIG_CPU_PXA27X)

View File

@ -40,4 +40,9 @@ u32 imx_get_uartclk(void);
u32 imx_get_fecclk(void);
unsigned int mxc_get_clock(enum mxc_clock clk);
void set_usb_phy2_clk(void);
void enable_usb_phy2_clk(unsigned char enable);
void set_usboh3_clk(void);
void enable_usboh3_clk(unsigned char enable);
#endif /* __ASM_ARCH_CLOCK_H */

View File

@ -195,7 +195,10 @@ struct mxc_ccm_reg {
/* Define the bits in register CCGRx */
#define MXC_CCM_CCGR_CG_MASK 0x3
#define MXC_CCM_CCGR4_CG5_OFFSET 10
#define MXC_CCM_CCGR4_CG6_OFFSET 12
#define MXC_CCM_CCGR5_CG5_OFFSET 10
#define MXC_CCM_CCGR2_CG14_OFFSET 28
/* Define the bits in register CLPCR */
#define MXC_CCM_CLPCR_BYPASS_IPU_LPM_HS (0x1 << 18)

View File

@ -645,7 +645,7 @@ typedef void (*ExcpHndlr) (void) ;
#define UDCOTGICR_IEIDR (1 << 1) /* OTG ID Change Rising Edge Interrupt Enable */
#define UDCOTGICR_IEIDF (1 << 0) /* OTG ID Change Falling Edge Interrupt Enable */
#define UDCCSN(x) __REG2(0x40600100, (x) << 2)
#define UDCCSN(x) (0x40600100 + ((x) << 2))
#define UDCCSR0 0x40600100 /* UDC Control/Status register - Endpoint 0 */
#define UDCCSR0_SA (1 << 7) /* Setup Active */
@ -693,7 +693,7 @@ typedef void (*ExcpHndlr) (void) ;
#define UDCCSR_PC (1 << 1) /* Packet Complete */
#define UDCCSR_FS (1 << 0) /* FIFO needs service */
#define UDCBCN(x) __REG2(0x40600200, (x)<<2)
#define UDCBCN(x) (0x40600200 + ((x) << 2))
#define UDCBCR0 0x40600200 /* Byte Count Register - EP0 */
#define UDCBCRA 0x40600204 /* Byte Count Register - EPA */
#define UDCBCRB 0x40600208 /* Byte Count Register - EPB */
@ -719,7 +719,7 @@ typedef void (*ExcpHndlr) (void) ;
#define UDCBCRW 0x40600258 /* Byte Count Register - EPW */
#define UDCBCRX 0x4060025C /* Byte Count Register - EPX */
#define UDCDN(x) __REG2(0x40600300, (x)<<2)
#define UDCDN(x) (0x40600300 + ((x) << 2))
#define UDCDR0 0x40600300 /* Data Register - EP0 */
#define UDCDRA 0x40600304 /* Data Register - EPA */
#define UDCDRB 0x40600308 /* Data Register - EPB */
@ -745,7 +745,7 @@ typedef void (*ExcpHndlr) (void) ;
#define UDCDRW 0x40600358 /* Data Register - EPW */
#define UDCDRX 0x4060035C /* Data Register - EPX */
#define UDCCN(x) __REG2(0x40600400, (x)<<2)
#define UDCCN(x) (0x40600400 + ((x) << 2))
#define UDCCRA 0x40600404 /* Configuration register EPA */
#define UDCCRB 0x40600408 /* Configuration register EPB */
#define UDCCRC 0x4060040C /* Configuration register EPC */
@ -835,6 +835,8 @@ typedef void (*ExcpHndlr) (void) ;
#define UHCHIE 0x4C000068
#define UHCHIT 0x4C00006C
#define UHCCOMS_HCR (1<<0)
#define UHCHR_FSBIR (1<<0)
#define UHCHR_FHR (1<<1)
#define UHCHR_CGR (1<<2)

View File

@ -55,6 +55,10 @@
#define S5PC110_VIC1_BASE 0xF2100000
#define S5PC110_VIC2_BASE 0xF2200000
#define S5PC110_VIC3_BASE 0xF2300000
#define S5PC110_OTG_BASE 0xEC000000
#define S5PC110_PHY_BASE 0xEC100000
#define S5PC110_USB_PHY_CONTROL 0xE010E80C
#ifndef __ASSEMBLY__
#include <asm/io.h>

View File

@ -29,6 +29,10 @@ LIB = $(obj)lib$(BOARD).o
COBJS := efikamx.o
ifdef CONFIG_CMD_USB
COBJS += efikamx-usb.o
endif
SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c)
OBJS := $(addprefix $(obj),$(COBJS))
SOBJS := $(addprefix $(obj),$(SOBJS))

210
board/efikamx/efikamx-usb.c Normal file
View File

@ -0,0 +1,210 @@
/*
* Copyright (C) 2010 Marek Vasut <marek.vasut@gmail.com>
*
* (C) Copyright 2009 Freescale Semiconductor, Inc.
*
* 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 <usb.h>
#include <asm/io.h>
#include <asm/arch/imx-regs.h>
#include <asm/arch/mx5x_pins.h>
#include <asm/arch/iomux.h>
#include <asm/gpio.h>
#include <usb/ehci-fsl.h>
#include <usb/ulpi.h>
#include <errno.h>
#include "../../drivers/usb/host/ehci.h"
/* USB pin configuration */
#define USB_PAD_CONFIG (PAD_CTL_PKE_ENABLE | PAD_CTL_SRE_FAST | \
PAD_CTL_DRV_HIGH | PAD_CTL_100K_PU | \
PAD_CTL_HYS_ENABLE | PAD_CTL_PUE_PULL)
/*
* Configure the USB H1 and USB H2 IOMUX
*/
void setup_iomux_usb(void)
{
setup_iomux_usb_h1();
if (machine_is_efikasb())
setup_iomux_usb_h2();
/* USB PHY reset */
mxc_request_iomux(MX51_PIN_EIM_D27, IOMUX_CONFIG_ALT1);
mxc_iomux_set_pad(MX51_PIN_EIM_D27, PAD_CTL_PKE_ENABLE |
PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH);
/* USB HUB reset */
mxc_request_iomux(MX51_PIN_GPIO1_5, IOMUX_CONFIG_ALT0);
mxc_iomux_set_pad(MX51_PIN_GPIO1_5, PAD_CTL_PKE_ENABLE |
PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH);
/* WIFI EN (act low) */
mxc_request_iomux(MX51_PIN_EIM_A22, IOMUX_CONFIG_GPIO);
mxc_iomux_set_pad(MX51_PIN_EIM_A22, 0);
/* WIFI RESET */
mxc_request_iomux(MX51_PIN_EIM_A16, IOMUX_CONFIG_GPIO);
mxc_iomux_set_pad(MX51_PIN_EIM_A16, 0);
/* BT EN (act low) */
mxc_request_iomux(MX51_PIN_EIM_A17, IOMUX_CONFIG_GPIO);
mxc_iomux_set_pad(MX51_PIN_EIM_A17, 0);
}
/*
* Enable devices connected to USB BUSes
*/
static void efika_usb_enable_devices(void)
{
/* Enable Bluetooth */
gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_EIM_A17), 0);
udelay(10000);
gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_EIM_A17), 1);
/* Enable WiFi */
gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_EIM_A22), 1);
udelay(10000);
/* Reset the WiFi chip */
gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_EIM_A16), 0);
udelay(10000);
gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_EIM_A16), 1);
}
/*
* Reset USB HUB (or HUBs on EfikaSB)
*/
static void efika_usb_hub_reset(void)
{
/* HUB reset */
gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_GPIO1_5), 1);
udelay(1000);
gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_GPIO1_5), 0);
udelay(1000);
gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_GPIO1_5), 1);
}
/*
* Reset USB PHY (or PHYs on EfikaSB)
*/
static void efika_usb_phy_reset(void)
{
/* SMSC 3317 PHY reset */
gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_EIM_D27), 0);
udelay(1000);
gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_EIM_D27), 1);
}
static void efika_ehci_init(struct usb_ehci *ehci, uint32_t stp_gpio,
uint32_t alt0, uint32_t alt1)
{
int ret;
struct ulpi_regs *ulpi = (struct ulpi_regs *)0;
mxc_request_iomux(stp_gpio, alt0);
mxc_iomux_set_pad(stp_gpio, PAD_CTL_DRV_HIGH |
PAD_CTL_PKE_ENABLE | PAD_CTL_SRE_FAST);
gpio_direction_output(IOMUX_TO_GPIO(stp_gpio), 0);
udelay(1000);
gpio_set_value(IOMUX_TO_GPIO(stp_gpio), 1);
udelay(1000);
mxc_request_iomux(stp_gpio, alt1);
mxc_iomux_set_pad(stp_gpio, USB_PAD_CONFIG);
udelay(10000);
ret = ulpi_init((u32)&ehci->ulpi_viewpoint);
if (ret) {
printf("Efika USB ULPI initialization failed\n");
return;
}
/* ULPI set flags */
ulpi_write((u32)&ehci->ulpi_viewpoint, &ulpi->otg_ctrl,
ULPI_OTG_DP_PULLDOWN | ULPI_OTG_DM_PULLDOWN |
ULPI_OTG_EXTVBUSIND);
ulpi_write((u32)&ehci->ulpi_viewpoint, &ulpi->function_ctrl,
ULPI_FC_FULL_SPEED | ULPI_FC_OPMODE_NORMAL |
ULPI_FC_SUSPENDM);
ulpi_write((u32)&ehci->ulpi_viewpoint, &ulpi->iface_ctrl, 0);
/* Set VBus */
ulpi_write((u32)&ehci->ulpi_viewpoint, &ulpi->otg_ctrl_set,
ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT);
/*
* Set VBusChrg
*
* NOTE: This violates USB specification, but otherwise, USB on Efika
* doesn't work.
*/
ulpi_write((u32)&ehci->ulpi_viewpoint, &ulpi->otg_ctrl_set,
ULPI_OTG_CHRGVBUS);
}
int board_ehci_hcd_init(int port)
{
/* Init iMX51 EHCI */
efika_usb_phy_reset();
efika_usb_hub_reset();
efika_usb_enable_devices();
return 0;
}
void ehci_powerup_fixup(uint32_t *status_reg, uint32_t *reg)
{
uint32_t port = OTG_BASE_ADDR + (0x200 * CONFIG_MXC_USB_PORT);
struct usb_ehci *ehci = (struct usb_ehci *)port;
struct ulpi_regs *ulpi = (struct ulpi_regs *)0;
ulpi_write((u32)&ehci->ulpi_viewpoint, &ulpi->otg_ctrl_set,
ULPI_OTG_CHRGVBUS);
wait_ms(50);
/* terminate the reset */
*reg = ehci_readl(status_reg);
*reg |= EHCI_PS_PE;
}
void board_ehci_hcd_postinit(struct usb_ehci *ehci, int port)
{
uint32_t tmp;
if (port == 0) {
/* Adjust UTMI PHY frequency to 24MHz */
tmp = readl(OTG_BASE_ADDR + 0x80c);
tmp = (tmp & ~0x3) | 0x01;
writel(tmp, OTG_BASE_ADDR + 0x80c);
} else if (port == 1) {
efika_ehci_init(ehci, MX51_PIN_USBH1_STP,
IOMUX_CONFIG_ALT2, IOMUX_CONFIG_ALT0);
} else if ((port == 2) && machine_is_efikasb()) {
efika_ehci_init(ehci, MX51_PIN_EIM_A26,
IOMUX_CONFIG_ALT1, IOMUX_CONFIG_ALT2);
}
if (port)
mdelay(10);
}

View File

@ -539,6 +539,15 @@ void setup_iomux_ata(void)
static inline void setup_iomux_ata(void) { }
#endif
/*
* EHCI USB
*/
#ifdef CONFIG_CMD_USB
extern void setup_iomux_usb(void);
#else
static inline void setup_iomux_usb(void) { }
#endif
/*
* LED configuration
*/
@ -688,6 +697,12 @@ int board_late_init(void)
setup_iomux_led();
setup_iomux_ata();
setup_iomux_usb();
if (machine_is_efikasb())
setenv("preboot", "usb reset ; setenv stdin usbkbd\0");
setup_iomux_led();
efikamx_toggle_led(EFIKAMX_LED_BLUE);

View File

@ -35,6 +35,7 @@
#include <pmic.h>
#include <fsl_pmic.h>
#include <mc13892.h>
#include <usb/ehci-fsl.h>
DECLARE_GLOBAL_DATA_PTR;
@ -172,6 +173,64 @@ static void setup_iomux_spi(void)
}
#endif
#ifdef CONFIG_USB_EHCI_MX5
#define MX51EVK_USBH1_HUB_RST IOMUX_TO_GPIO(MX51_PIN_GPIO1_7) /* GPIO1_7 */
#define MX51EVK_USBH1_STP IOMUX_TO_GPIO(MX51_PIN_USBH1_STP) /* GPIO1_27 */
#define MX51EVK_USB_CLK_EN_B IOMUX_TO_GPIO(MX51_PIN_EIM_D18) /* GPIO2_1 */
#define MX51EVK_USB_PHY_RESET IOMUX_TO_GPIO(MX51_PIN_EIM_D21) /* GPIO2_5 */
#define USBH1_PAD (PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH | \
PAD_CTL_100K_PU | PAD_CTL_PUE_PULL | \
PAD_CTL_PKE_ENABLE | PAD_CTL_HYS_ENABLE)
#define GPIO_PAD (PAD_CTL_DRV_HIGH | PAD_CTL_PKE_ENABLE | \
PAD_CTL_SRE_FAST)
#define NO_PAD (1 << 16)
static void setup_usb_h1(void)
{
setup_iomux_usb_h1();
/* GPIO_1_7 for USBH1 hub reset */
mxc_request_iomux(MX51_PIN_GPIO1_7, IOMUX_CONFIG_ALT0);
mxc_iomux_set_pad(MX51_PIN_GPIO1_7, NO_PAD);
/* GPIO_2_1 */
mxc_request_iomux(MX51_PIN_EIM_D17, IOMUX_CONFIG_ALT1);
mxc_iomux_set_pad(MX51_PIN_EIM_D17, GPIO_PAD);
/* GPIO_2_5 for USB PHY reset */
mxc_request_iomux(MX51_PIN_EIM_D21, IOMUX_CONFIG_ALT1);
mxc_iomux_set_pad(MX51_PIN_EIM_D21, GPIO_PAD);
}
void board_ehci_hcd_init(int port)
{
/* Set USBH1_STP to GPIO and toggle it */
mxc_request_iomux(MX51_PIN_USBH1_STP, IOMUX_CONFIG_GPIO);
mxc_iomux_set_pad(MX51_PIN_USBH1_STP, USBH1_PAD);
gpio_direction_output(MX51EVK_USBH1_STP, 0);
gpio_direction_output(MX51EVK_USB_PHY_RESET, 0);
mdelay(10);
gpio_set_value(MX51EVK_USBH1_STP, 1);
/* Set back USBH1_STP to be function */
mxc_request_iomux(MX51_PIN_USBH1_STP, IOMUX_CONFIG_ALT0);
mxc_iomux_set_pad(MX51_PIN_USBH1_STP, USBH1_PAD);
/* De-assert USB PHY RESETB */
gpio_set_value(MX51EVK_USB_PHY_RESET, 1);
/* Drive USB_CLK_EN_B line low */
gpio_direction_output(MX51EVK_USB_CLK_EN_B, 0);
/* Reset USB hub */
gpio_direction_output(MX51EVK_USBH1_HUB_RST, 0);
mdelay(2);
gpio_set_value(MX51EVK_USBH1_HUB_RST, 1);
}
#endif
static void power_init(void)
{
unsigned int val;
@ -394,6 +453,9 @@ int board_early_init_f(void)
{
setup_iomux_uart();
setup_iomux_fec();
#ifdef CONFIG_USB_EHCI_MX5
setup_usb_h1();
#endif
return 0;
}

View File

@ -78,6 +78,16 @@ static void setup_iomux_uart(void)
PAD_CTL_ODE_OPENDRAIN_ENABLE);
}
#ifdef CONFIG_USB_EHCI_MX5
void board_ehci_hcd_init(int port)
{
/* request VBUS power enable pin, GPIO[8}, gpio7 */
mxc_request_iomux(MX53_PIN_ATA_DA_2, IOMUX_CONFIG_ALT1);
gpio_direction_output(IOMUX_TO_GPIO(MX53_PIN_ATA_DA_2), 0);
gpio_set_value(IOMUX_TO_GPIO(MX53_PIN_ATA_DA_2), 1);
}
#endif
static void setup_iomux_fec(void)
{
/*FEC_MDIO*/

View File

@ -26,7 +26,9 @@
#include <asm/arch/gpio.h>
#include <asm/arch/mmc.h>
#include <pmic.h>
#include <usb/s3c_udc.h>
#include <asm/arch/cpu.h>
#include <max8998_pmic.h>
DECLARE_GLOBAL_DATA_PTR;
static struct s5pc110_gpio *s5pc110_gpio;
@ -100,3 +102,47 @@ int board_mmc_init(bd_t *bis)
return s5p_mmc_init(0, 4);
}
#endif
#ifdef CONFIG_USB_GADGET
static int s5pc1xx_phy_control(int on)
{
int ret;
static int status;
struct pmic *p = get_pmic();
if (pmic_probe(p))
return -1;
if (on && !status) {
ret = pmic_set_output(p, MAX8998_REG_ONOFF1,
MAX8998_LDO3, LDO_ON);
ret = pmic_set_output(p, MAX8998_REG_ONOFF2,
MAX8998_LDO8, LDO_ON);
if (ret) {
puts("MAX8998 LDO setting error!\n");
return -1;
}
status = 1;
} else if (!on && status) {
ret = pmic_set_output(p, MAX8998_REG_ONOFF1,
MAX8998_LDO3, LDO_OFF);
ret = pmic_set_output(p, MAX8998_REG_ONOFF2,
MAX8998_LDO8, LDO_OFF);
if (ret) {
puts("MAX8998 LDO setting error!\n");
return -1;
}
status = 0;
}
udelay(10000);
return 0;
}
struct s3c_plat_otg_data s5pc110_otg_data = {
.phy_control = s5pc1xx_phy_control,
.regs_phy = S5PC110_PHY_BASE,
.regs_otg = S5PC110_OTG_BASE,
.usb_phy_ctrl = S5PC110_USB_PHY_CONTROL,
};
#endif

View File

@ -700,11 +700,12 @@ int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
U_BOOT_CMD(
usb, 5, 1, do_usb,
"USB sub-system",
"reset - reset (rescan) USB controller\n"
"usb stop [f] - stop USB [f]=force stop\n"
"usb tree - show USB device tree\n"
"start - start (scan) USB controller\n"
"usb reset - reset (rescan) USB controller\n"
"usb stop [f] - stop USB [f]=force stop\n"
"usb tree - show USB device tree\n"
"usb info [dev] - show available USB devices\n"
"usb storage - show details of USB storage devices\n"
"usb storage - show details of USB storage devices\n"
"usb dev [dev] - show or set current USB storage device\n"
"usb part [dev] - print partition table of one or all USB storage"
" devices\n"
@ -725,8 +726,9 @@ U_BOOT_CMD(
U_BOOT_CMD(
usb, 5, 1, do_usb,
"USB sub-system",
"reset - reset (rescan) USB controller\n"
"usb tree - show USB device tree\n"
"usb info [dev] - show available USB devices"
"start - start (scan) USB controller\n"
"usb reset - reset (rescan) USB controller\n"
"usb tree - show USB device tree\n"
"usb info [dev] - show available USB devices"
);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -554,11 +554,11 @@ int drv_usbtty_init (void)
usbtty_init_strings ();
usbtty_init_instances ();
usbtty_init_endpoints ();
udc_startup_events (device_instance);/* Enable dev, init udc pointers */
udc_connect (); /* Enable pullup for host detection */
usbtty_init_endpoints ();
/* Device initialization */
memset (&usbttydev, 0, sizeof (usbttydev));

View File

@ -26,9 +26,14 @@ include $(TOPDIR)/config.mk
LIB := $(obj)libusb_gadget.o
# new USB gadget layer dependencies
ifdef CONFIG_USB_GADGET
COBJS-y += epautoconf.o config.o usbstring.o
COBJS-$(CONFIG_USB_GADGET_S3C_UDC_OTG) += s3c_udc_otg.o
endif
ifdef CONFIG_USB_ETHER
COBJS-y += ether.o epautoconf.o config.o usbstring.o
COBJS-$(CONFIG_USB_ETH_RNDIS) += rndis.o
COBJS-$(CONFIG_MV_UDC) += mv_udc.o
else
# Devices not related to the new gadget layer depend on CONFIG_USB_DEVICE
ifdef CONFIG_USB_DEVICE

View File

@ -150,6 +150,11 @@
#define gadget_is_m66592(g) 0
#endif
#ifdef CONFIG_USB_GADGET_MV
#define gadget_is_mv(g) (!strcmp("mv_udc", (g)->name))
#else
#define gadget_is_mv(g) 0
#endif
/*
* CONFIG_USB_GADGET_SX2
@ -216,5 +221,7 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
return 0x20;
else if (gadget_is_m66592(gadget))
return 0x21;
else if (gadget_is_mv(gadget))
return 0x22;
return -ENOENT;
}

499
drivers/usb/gadget/mv_udc.c Normal file
View File

@ -0,0 +1,499 @@
/*
* Copyright 2011, Marvell Semiconductor Inc.
* Lei Wen <leiwen@marvell.com>
*
* 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
*
* Back ported to the 8xx platform (from the 8260 platform) by
* Murray.Jensen@cmst.csiro.au, 27-Jan-01.
*/
#include <common.h>
#include <command.h>
#include <config.h>
#include <net.h>
#include <malloc.h>
#include <asm/io.h>
#include <linux/types.h>
#include <usb/mv_udc.h>
#ifndef DEBUG
#define DBG(x...) do {} while (0)
#else
#define DBG(x...) printf(x)
static const char *reqname(unsigned r)
{
switch (r) {
case USB_REQ_GET_STATUS: return "GET_STATUS";
case USB_REQ_CLEAR_FEATURE: return "CLEAR_FEATURE";
case USB_REQ_SET_FEATURE: return "SET_FEATURE";
case USB_REQ_SET_ADDRESS: return "SET_ADDRESS";
case USB_REQ_GET_DESCRIPTOR: return "GET_DESCRIPTOR";
case USB_REQ_SET_DESCRIPTOR: return "SET_DESCRIPTOR";
case USB_REQ_GET_CONFIGURATION: return "GET_CONFIGURATION";
case USB_REQ_SET_CONFIGURATION: return "SET_CONFIGURATION";
case USB_REQ_GET_INTERFACE: return "GET_INTERFACE";
case USB_REQ_SET_INTERFACE: return "SET_INTERFACE";
default: return "*UNKNOWN*";
}
}
#endif
#define PAGE_SIZE 4096
#define QH_MAXNUM 32
static struct usb_endpoint_descriptor ep0_out_desc = {
.bLength = sizeof(struct usb_endpoint_descriptor),
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = 0,
.bmAttributes = USB_ENDPOINT_XFER_CONTROL,
};
static struct usb_endpoint_descriptor ep0_in_desc = {
.bLength = sizeof(struct usb_endpoint_descriptor),
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_CONTROL,
};
struct ept_queue_head *epts;
struct ept_queue_item *items[2 * NUM_ENDPOINTS];
static int mv_pullup(struct usb_gadget *gadget, int is_on);
static int mv_ep_enable(struct usb_ep *ep,
const struct usb_endpoint_descriptor *desc);
static int mv_ep_disable(struct usb_ep *ep);
static int mv_ep_queue(struct usb_ep *ep,
struct usb_request *req, gfp_t gfp_flags);
static struct usb_request *
mv_ep_alloc_request(struct usb_ep *ep, unsigned int gfp_flags);
static void mv_ep_free_request(struct usb_ep *ep, struct usb_request *_req);
static struct usb_gadget_ops mv_udc_ops = {
.pullup = mv_pullup,
};
static struct usb_ep_ops mv_ep_ops = {
.enable = mv_ep_enable,
.disable = mv_ep_disable,
.queue = mv_ep_queue,
.alloc_request = mv_ep_alloc_request,
.free_request = mv_ep_free_request,
};
static struct mv_ep ep[2 * NUM_ENDPOINTS];
static struct mv_drv controller = {
.gadget = {
.ep0 = &ep[0].ep,
.name = "mv_udc",
},
};
static struct usb_request *
mv_ep_alloc_request(struct usb_ep *ep, unsigned int gfp_flags)
{
struct mv_ep *mv_ep = container_of(ep, struct mv_ep, ep);
return &mv_ep->req;
}
static void mv_ep_free_request(struct usb_ep *ep, struct usb_request *_req)
{
return;
}
static void ep_enable(int num, int in)
{
struct ept_queue_head *head;
struct mv_udc *udc = controller.udc;
unsigned n;
head = epts + 2*num + in;
n = readl(&udc->epctrl[num]);
if (in)
n |= (CTRL_TXE | CTRL_TXR | CTRL_TXT_BULK);
else
n |= (CTRL_RXE | CTRL_RXR | CTRL_RXT_BULK);
if (num != 0)
head->config = CONFIG_MAX_PKT(EP_MAX_PACKET_SIZE) | CONFIG_ZLT;
writel(n, &udc->epctrl[num]);
}
static int mv_ep_enable(struct usb_ep *ep,
const struct usb_endpoint_descriptor *desc)
{
struct mv_ep *mv_ep = container_of(ep, struct mv_ep, ep);
int num, in;
num = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
in = (desc->bEndpointAddress & USB_DIR_IN) != 0;
ep_enable(num, in);
mv_ep->desc = desc;
return 0;
}
static int mv_ep_disable(struct usb_ep *ep)
{
return 0;
}
static int mv_ep_queue(struct usb_ep *ep,
struct usb_request *req, gfp_t gfp_flags)
{
struct mv_ep *mv_ep = container_of(ep, struct mv_ep, ep);
struct mv_udc *udc = controller.udc;
struct ept_queue_item *item;
struct ept_queue_head *head;
unsigned phys;
int bit, num, len, in;
num = mv_ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
in = (mv_ep->desc->bEndpointAddress & USB_DIR_IN) != 0;
item = items[2 * num + in];
head = epts + 2 * num + in;
phys = (unsigned)req->buf;
len = req->length;
item->next = TERMINATE;
item->info = INFO_BYTES(len) | INFO_IOC | INFO_ACTIVE;
item->page0 = phys;
item->page1 = (phys & 0xfffff000) + 0x1000;
head->next = (unsigned) item;
head->info = 0;
DBG("ept%d %s queue len %x, buffer %x\n",
num, in ? "in" : "out", len, phys);
if (in)
bit = EPT_TX(num);
else
bit = EPT_RX(num);
flush_cache(phys, len);
flush_cache((unsigned long)item, sizeof(struct ept_queue_item));
writel(bit, &udc->epprime);
return 0;
}
static void handle_ep_complete(struct mv_ep *ep)
{
struct ept_queue_item *item;
int num, in, len;
num = ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
in = (ep->desc->bEndpointAddress & USB_DIR_IN) != 0;
if (num == 0)
ep->desc = &ep0_out_desc;
item = items[2 * num + in];
if (item->info & 0xff)
printf("EP%d/%s FAIL nfo=%x pg0=%x\n",
num, in ? "in" : "out", item->info, item->page0);
len = (item->info >> 16) & 0x7fff;
ep->req.length -= len;
DBG("ept%d %s complete %x\n",
num, in ? "in" : "out", len);
ep->req.complete(&ep->ep, &ep->req);
if (num == 0) {
ep->req.length = 0;
usb_ep_queue(&ep->ep, &ep->req, 0);
ep->desc = &ep0_in_desc;
}
}
#define SETUP(type, request) (((type) << 8) | (request))
static void handle_setup(void)
{
struct usb_request *req = &ep[0].req;
struct mv_udc *udc = controller.udc;
struct ept_queue_head *head;
struct usb_ctrlrequest r;
int status = 0;
int num, in, _num, _in, i;
char *buf;
head = epts;
flush_cache((unsigned long)head, sizeof(struct ept_queue_head));
memcpy(&r, head->setup_data, sizeof(struct usb_ctrlrequest));
writel(EPT_RX(0), &udc->epstat);
DBG("handle setup %s, %x, %x index %x value %x\n", reqname(r.bRequest),
r.bRequestType, r.bRequest, r.wIndex, r.wValue);
switch (SETUP(r.bRequestType, r.bRequest)) {
case SETUP(USB_RECIP_ENDPOINT, USB_REQ_CLEAR_FEATURE):
_num = r.wIndex & 15;
_in = !!(r.wIndex & 0x80);
if ((r.wValue == 0) && (r.wLength == 0)) {
req->length = 0;
for (i = 0; i < NUM_ENDPOINTS; i++) {
if (!ep[i].desc)
continue;
num = ep[i].desc->bEndpointAddress
& USB_ENDPOINT_NUMBER_MASK;
in = (ep[i].desc->bEndpointAddress
& USB_DIR_IN) != 0;
if ((num == _num) && (in == _in)) {
ep_enable(num, in);
usb_ep_queue(controller.gadget.ep0,
req, 0);
break;
}
}
}
return;
case SETUP(USB_RECIP_DEVICE, USB_REQ_SET_ADDRESS):
/*
* write address delayed (will take effect
* after the next IN txn)
*/
writel((r.wValue << 25) | (1 << 24), &udc->devaddr);
req->length = 0;
usb_ep_queue(controller.gadget.ep0, req, 0);
return;
case SETUP(USB_DIR_IN | USB_RECIP_DEVICE, USB_REQ_GET_STATUS):
req->length = 2;
buf = (char *)req->buf;
buf[0] = 1 << USB_DEVICE_SELF_POWERED;
buf[1] = 0;
usb_ep_queue(controller.gadget.ep0, req, 0);
return;
}
/* pass request up to the gadget driver */
if (controller.driver)
status = controller.driver->setup(&controller.gadget, &r);
else
status = -ENODEV;
if (!status)
return;
DBG("STALL reqname %s type %x value %x, index %x\n",
reqname(r.bRequest), r.bRequestType, r.wValue, r.wIndex);
writel((1<<16) | (1 << 0), &udc->epctrl[0]);
}
static void stop_activity(void)
{
int i, num, in;
struct ept_queue_head *head;
struct mv_udc *udc = controller.udc;
writel(readl(&udc->epcomp), &udc->epcomp);
writel(readl(&udc->epstat), &udc->epstat);
writel(0xffffffff, &udc->epflush);
/* error out any pending reqs */
for (i = 0; i < NUM_ENDPOINTS; i++) {
if (i != 0)
writel(0, &udc->epctrl[i]);
if (ep[i].desc) {
num = ep[i].desc->bEndpointAddress
& USB_ENDPOINT_NUMBER_MASK;
in = (ep[i].desc->bEndpointAddress & USB_DIR_IN) != 0;
head = epts + (num * 2) + (in);
head->info = INFO_ACTIVE;
}
}
}
void udc_irq(void)
{
struct mv_udc *udc = controller.udc;
unsigned n = readl(&udc->usbsts);
writel(n, &udc->usbsts);
int bit, i, num, in;
n &= (STS_SLI | STS_URI | STS_PCI | STS_UI | STS_UEI);
if (n == 0)
return;
if (n & STS_URI) {
DBG("-- reset --\n");
stop_activity();
}
if (n & STS_SLI)
DBG("-- suspend --\n");
if (n & STS_PCI) {
DBG("-- portchange --\n");
bit = (readl(&udc->portsc) >> 26) & 3;
if (bit == 2) {
controller.gadget.speed = USB_SPEED_HIGH;
for (i = 1; i < NUM_ENDPOINTS && n; i++)
if (ep[i].desc)
ep[i].ep.maxpacket = 512;
} else {
controller.gadget.speed = USB_SPEED_FULL;
}
}
if (n & STS_UEI)
printf("<UEI %x>\n", readl(&udc->epcomp));
if ((n & STS_UI) || (n & STS_UEI)) {
n = readl(&udc->epstat);
if (n & EPT_RX(0))
handle_setup();
n = readl(&udc->epcomp);
if (n != 0)
writel(n, &udc->epcomp);
for (i = 0; i < NUM_ENDPOINTS && n; i++) {
if (ep[i].desc) {
num = ep[i].desc->bEndpointAddress
& USB_ENDPOINT_NUMBER_MASK;
in = (ep[i].desc->bEndpointAddress
& USB_DIR_IN) != 0;
bit = (in) ? EPT_TX(num) : EPT_RX(num);
if (n & bit)
handle_ep_complete(&ep[i]);
}
}
}
}
int usb_gadget_handle_interrupts(void)
{
u32 value;
struct mv_udc *udc = controller.udc;
value = readl(&udc->usbsts);
if (value)
udc_irq();
return value;
}
static int mv_pullup(struct usb_gadget *gadget, int is_on)
{
struct mv_udc *udc = controller.udc;
if (is_on) {
/* RESET */
writel(USBCMD_ITC(MICRO_8FRAME) | USBCMD_RST, &udc->usbcmd);
udelay(200);
writel((unsigned) epts, &udc->epinitaddr);
/* select DEVICE mode */
writel(USBMODE_DEVICE, &udc->usbmode);
writel(0xffffffff, &udc->epflush);
/* Turn on the USB connection by enabling the pullup resistor */
writel(USBCMD_ITC(MICRO_8FRAME) | USBCMD_RUN, &udc->usbcmd);
} else {
stop_activity();
writel(USBCMD_FS2, &udc->usbcmd);
udelay(800);
if (controller.driver)
controller.driver->disconnect(gadget);
}
return 0;
}
void udc_disconnect(void)
{
struct mv_udc *udc = controller.udc;
/* disable pullup */
stop_activity();
writel(USBCMD_FS2, &udc->usbcmd);
udelay(800);
if (controller.driver)
controller.driver->disconnect(&controller.gadget);
}
static int mvudc_probe(void)
{
struct ept_queue_head *head;
int i;
controller.gadget.ops = &mv_udc_ops;
controller.udc = (struct mv_udc *)CONFIG_USB_REG_BASE;
epts = memalign(PAGE_SIZE, QH_MAXNUM * sizeof(struct ept_queue_head));
memset(epts, 0, QH_MAXNUM * sizeof(struct ept_queue_head));
for (i = 0; i < 2 * NUM_ENDPOINTS; i++) {
/*
* For item0 and item1, they are served as ep0
* out&in seperately
*/
head = epts + i;
if (i < 2)
head->config = CONFIG_MAX_PKT(EP0_MAX_PACKET_SIZE)
| CONFIG_ZLT | CONFIG_IOS;
else
head->config = CONFIG_MAX_PKT(EP_MAX_PACKET_SIZE)
| CONFIG_ZLT;
head->next = TERMINATE;
head->info = 0;
items[i] = memalign(PAGE_SIZE, sizeof(struct ept_queue_item));
}
INIT_LIST_HEAD(&controller.gadget.ep_list);
ep[0].ep.maxpacket = 64;
ep[0].ep.name = "ep0";
ep[0].desc = &ep0_in_desc;
INIT_LIST_HEAD(&controller.gadget.ep0->ep_list);
for (i = 0; i < 2 * NUM_ENDPOINTS; i++) {
if (i != 0) {
ep[i].ep.maxpacket = 512;
ep[i].ep.name = "ep-";
list_add_tail(&ep[i].ep.ep_list,
&controller.gadget.ep_list);
ep[i].desc = NULL;
}
ep[i].ep.ops = &mv_ep_ops;
}
return 0;
}
int usb_gadget_register_driver(struct usb_gadget_driver *driver)
{
struct mv_udc *udc = controller.udc;
int retval;
if (!driver
|| driver->speed < USB_SPEED_FULL
|| !driver->bind
|| !driver->setup) {
DBG("bad parameter.\n");
return -EINVAL;
}
if (!mvudc_probe()) {
usb_lowlevel_init();
/* select ULPI phy */
writel(PTS(PTS_ENABLE) | PFSC, &udc->portsc);
}
retval = driver->bind(&controller.gadget);
if (retval) {
DBG("driver->bind() returned %d\n", retval);
return retval;
}
controller.driver = driver;
return 0;
}
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
{
return 0;
}

View File

@ -26,11 +26,13 @@
#include <common.h>
#include <config.h>
#include <asm/byteorder.h>
#include <usbdcore.h>
#include <usbdcore_ep0.h>
#include <usbdevice.h>
#include <asm/arch/hardware.h>
#include <asm/io.h>
#include <usb/pxa27x_udc.h>
#include "ep0.h"
/* number of endpoints on this UDC */
#define UDC_MAX_ENDPOINTS 24
@ -50,7 +52,7 @@ static void udc_dump_buffer(char *name, u8 *buf, int len)
static inline void udc_ack_int_UDCCR(int mask)
{
USIR1 = mask | USIR1;
writel(readl(USIR1) | mask, USIR1);
}
/*
@ -68,9 +70,7 @@ static int udc_write_urb(struct usb_endpoint_instance *endpoint)
{
struct urb *urb = endpoint->tx_urb;
int ep_num = endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK;
u32 *addr32 = (u32 *) &UDCDN(ep_num);
u32 *data32 = (u32 *) urb->buffer;
u8 *addr8 = (u8 *) &UDCDN(ep_num);
u8 *data8 = (u8 *) urb->buffer;
unsigned int i, n, w, b, is_short;
int timeout = 2000; /* 2ms */
@ -98,26 +98,28 @@ static int udc_write_urb(struct usb_endpoint_instance *endpoint)
/* Prepare for data send */
if (ep_num)
UDCCSN(ep_num) = UDCCSR_PC;
writel(UDCCSR_PC ,UDCCSN(ep_num));
for (i = 0; i < w; i++)
*addr32 = data32[endpoint->sent/4 + i];
writel(data32[endpoint->sent / 4 + i], UDCDN(ep_num));
for (i = 0; i < b; i++)
*addr8 = data8[endpoint->sent + w*4 + i];
writeb(data8[endpoint->sent + w * 4 + i], UDCDN(ep_num));
/* Set "Packet Complete" if less data then tx_packetSize */
if (is_short)
UDCCSN(ep_num) = ep_num ? UDCCSR_SP : UDCCSR0_IPR;
writel(ep_num ? UDCCSR_SP : UDCCSR0_IPR, UDCCSN(ep_num));
/* Wait for data sent */
while (!(UDCCSN(ep_num) & (ep_num ? UDCCSR_PC : UDCCSR0_IPR))) {
if (ep_num) {
if (ep_num) {
while (!(readl(UDCCSN(ep_num)) & UDCCSR_PC)) {
if (timeout-- == 0)
return -1;
else
udelay(1);
};
}
}
endpoint->last = n;
if (ep_num) {
@ -127,7 +129,7 @@ static int udc_write_urb(struct usb_endpoint_instance *endpoint)
endpoint->last -= n;
}
if ((endpoint->tx_urb->actual_length - endpoint->sent) <= 0) {
if (endpoint->sent >= urb->actual_length) {
urb->actual_length = 0;
endpoint->sent = 0;
endpoint->last = 0;
@ -148,7 +150,6 @@ static int udc_read_urb(struct usb_endpoint_instance *endpoint)
{
struct urb *urb = endpoint->rcv_urb;
int ep_num = endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK;
u32 *addr32 = (u32 *) &UDCDN(ep_num);
u32 *data32 = (u32 *) urb->buffer;
unsigned int i, n, is_short ;
@ -160,15 +161,15 @@ static int udc_read_urb(struct usb_endpoint_instance *endpoint)
endpoint->rcv_packetSize);
#endif
if (UDCCSN(ep_num) & UDCCSR_BNE)
n = UDCBCN(ep_num) & 0x3ff;
if (readl(UDCCSN(ep_num)) & UDCCSR_BNE)
n = readl(UDCBCN(ep_num)) & 0x3ff;
else /* zlp */
n = 0;
is_short = n != endpoint->rcv_packetSize;
usbdbg("n %d%s", n, is_short ? "-s" : "");
for (i = 0; i < n; i += 4)
data32[urb->actual_length/4 + i/4] = *addr32;
data32[urb->actual_length / 4 + i / 4] = readl(UDCDN(ep_num));
udc_dump_buffer("urb read", (u8 *) data32, urb->actual_length + n);
usbd_rcv_complete(endpoint, n, 0);
@ -178,27 +179,35 @@ static int udc_read_urb(struct usb_endpoint_instance *endpoint)
static int udc_read_urb_ep0(void)
{
u32 *addr32 = (u32 *) &UDCDN(0);
u32 *data32 = (u32 *) ep0_urb->buffer;
u8 *addr8 = (u8 *) &UDCDN(0);
u8 *data8 = (u8 *) ep0_urb->buffer;
unsigned int i, n, w, b;
n = UDCBCR0;
usbdbg("read urb on ep 0");
#if defined(USBDDBG) && defined(USBDPARANOIA)
usbdbg("urb: buf %p, buf_len %d, actual_len %d",
ep0_urb->buffer, ep0_urb->buffer_length, ep0_urb->actual_length);
#endif
n = readl(UDCBCR0);
w = n / 4;
b = n % 4;
for (i = 0; i < w; i++) {
data32[ep0_urb->actual_length/4 + i] = *addr32;
ep0_urb->actual_length += 4;
data32[ep0_urb->actual_length / 4 + i] = readl(UDCDN(0));
// ep0_urb->actual_length += 4;
}
for (i = 0; i < b; i++) {
data8[ep0_urb->actual_length + w*4 + i] = *addr8;
ep0_urb->actual_length++;
data8[ep0_urb->actual_length + w * 4 + i] = readb(UDCDN(0));
// ep0_urb->actual_length++;
}
UDCCSR0 = UDCCSR0_OPC | UDCCSR0_IPR;
ep0_urb->actual_length += n;
udc_dump_buffer("urb read", (u8 *) data32, ep0_urb->actual_length);
writel(UDCCSR0_OPC | UDCCSR0_IPR, UDCCSR0);
if (ep0_urb->actual_length == ep0_urb->device_request.wLength)
return 1;
@ -207,7 +216,7 @@ static int udc_read_urb_ep0(void)
static void udc_handle_ep0(struct usb_endpoint_instance *endpoint)
{
u32 udccsr0 = UDCCSR0;
u32 udccsr0 = readl(UDCCSR0);
u32 *data = (u32 *) &ep0_urb->device_request;
int i;
@ -216,7 +225,7 @@ static void udc_handle_ep0(struct usb_endpoint_instance *endpoint)
/* Clear stall status */
if (udccsr0 & UDCCSR0_SST) {
usberr("clear stall status");
UDCCSR0 = UDCCSR0_SST;
writel(UDCCSR0_SST, UDCCSR0);
ep0state = EP0_IDLE;
}
@ -227,8 +236,7 @@ static void udc_handle_ep0(struct usb_endpoint_instance *endpoint)
switch (ep0state) {
case EP0_IDLE:
udccsr0 = UDCCSR0;
udccsr0 = readl(UDCCSR0);
/* Start control request? */
if ((udccsr0 & (UDCCSR0_OPC | UDCCSR0_SA | UDCCSR0_RNE))
== (UDCCSR0_OPC | UDCCSR0_SA | UDCCSR0_RNE)) {
@ -238,15 +246,15 @@ static void udc_handle_ep0(struct usb_endpoint_instance *endpoint)
*/
usbdbg("try reading SETUP packet");
for (i = 0; i < 2; i++) {
if ((UDCCSR0 & UDCCSR0_RNE) == 0) {
if ((readl(UDCCSR0) & UDCCSR0_RNE) == 0) {
usberr("setup packet too short:%d", i);
goto stall;
}
data[i] = UDCDR0;
data[i] = readl(UDCDR0);
}
UDCCSR0 |= (UDCCSR0_OPC | UDCCSR0_SA);
if ((UDCCSR0 & UDCCSR0_RNE) != 0) {
writel(readl(UDCCSR0) | UDCCSR0_OPC | UDCCSR0_SA, UDCCSR0);
if ((readl(UDCCSR0) & UDCCSR0_RNE) != 0) {
usberr("setup packet too long");
goto stall;
}
@ -261,7 +269,7 @@ static void udc_handle_ep0(struct usb_endpoint_instance *endpoint)
(u8 *)data, 8);
goto stall;
}
UDCCSR0 = UDCCSR0_IPR;
writel(UDCCSR0_IPR, UDCCSR0);
ep0state = EP0_IDLE;
} else {
/* Check direction */
@ -274,7 +282,7 @@ static void udc_handle_ep0(struct usb_endpoint_instance *endpoint)
ep0_urb->buffer_length =
sizeof(ep0_urb->buffer_data);
ep0_urb->actual_length = 0;
UDCCSR0 = UDCCSR0_IPR;
writel(UDCCSR0_IPR, UDCCSR0);
} else {
/* The ep0_recv_setup function has
* already placed our response packet
@ -289,9 +297,9 @@ stall:
, (u8 *) data, 8);
ep0state = EP0_IDLE;
UDCCSR0 = UDCCSR0_SA |
writel(UDCCSR0_SA |
UDCCSR0_OPC | UDCCSR0_FST |
UDCCS0_FTF;
UDCCS0_FTF, UDCCSR0);
return;
}
@ -317,7 +325,7 @@ stall:
* - IPR cleared
* - OPC got set, without SA (likely status stage)
*/
UDCCSR0 = udccsr0 & (UDCCSR0_SA | UDCCSR0_OPC);
writel(udccsr0 & (UDCCSR0_SA | UDCCSR0_OPC), UDCCSR0);
}
break;
@ -351,7 +359,7 @@ read_complete:
case EP0_IN_DATA:
/* GET_DESCRIPTOR etc */
if (udccsr0 & UDCCSR0_OPC) {
UDCCSR0 = UDCCSR0_OPC | UDCCSR0_FTF;
writel(UDCCSR0_OPC | UDCCSR0_FTF, UDCCSR0);
usberr("ep0in premature status");
ep0state = EP0_IDLE;
} else {
@ -364,14 +372,14 @@ read_complete:
break;
case EP0_XFER_COMPLETE:
UDCCSR0 = UDCCSR0_IPR;
writel(UDCCSR0_IPR, UDCCSR0);
ep0state = EP0_IDLE;
break;
default:
usbdbg("Default\n");
}
USIR0 = USIR0_IR0;
writel(USIR0_IR0, USIR0);
}
static void udc_handle_ep(struct usb_endpoint_instance *endpoint)
@ -380,33 +388,33 @@ static void udc_handle_ep(struct usb_endpoint_instance *endpoint)
int ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK;
int ep_isout = (ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT;
u32 flags = UDCCSN(ep_num) & (UDCCSR_SST | UDCCSR_TRN);
u32 flags = readl(UDCCSN(ep_num)) & (UDCCSR_SST | UDCCSR_TRN);
if (flags)
UDCCSN(ep_num) = flags;
writel(flags, UDCCSN(ep_num));
if (ep_isout)
udc_read_urb(endpoint);
else
udc_write_urb(endpoint);
UDCCSN(ep_num) = UDCCSR_PC;
writel(UDCCSR_PC, UDCCSN(ep_num));
}
static void udc_state_changed(void)
{
int config, interface, alternate;
UDCCR |= UDCCR_SMAC;
writel(readl(UDCCR) | UDCCR_SMAC, UDCCR);
config = (UDCCR & UDCCR_ACN) >> UDCCR_ACN_S;
interface = (UDCCR & UDCCR_AIN) >> UDCCR_AIN_S;
alternate = (UDCCR & UDCCR_AAISN) >> UDCCR_AAISN_S;
config = (readl(UDCCR) & UDCCR_ACN) >> UDCCR_ACN_S;
interface = (readl(UDCCR) & UDCCR_AIN) >> UDCCR_AIN_S;
alternate = (readl(UDCCR) & UDCCR_AAISN) >> UDCCR_AAISN_S;
usbdbg("New UDC settings are: conf %d - inter %d - alter %d",
config, interface, alternate);
usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0);
UDCISR1 = UDCISR1_IRCC;
writel(UDCISR1_IRCC, UDCISR1);
}
void udc_irq(void)
@ -419,7 +427,7 @@ void udc_irq(void)
do {
handled = 0;
/* Suspend Interrupt Request */
if (USIR1 & UDCCR_SUSIR) {
if (readl(USIR1) & UDCCR_SUSIR) {
usbdbg("Suspend\n");
udc_ack_int_UDCCR(UDCCR_SUSIR);
handled = 1;
@ -427,35 +435,35 @@ void udc_irq(void)
}
/* Resume Interrupt Request */
if (USIR1 & UDCCR_RESIR) {
if (readl(USIR1) & UDCCR_RESIR) {
udc_ack_int_UDCCR(UDCCR_RESIR);
handled = 1;
usbdbg("USB resume\n");
}
if (USIR1 & (1<<31)) {
if (readl(USIR1) & (1<<31)) {
handled = 1;
udc_state_changed();
}
/* Reset Interrupt Request */
if (USIR1 & UDCCR_RSTIR) {
if (readl(USIR1) & UDCCR_RSTIR) {
udc_ack_int_UDCCR(UDCCR_RSTIR);
handled = 1;
usbdbg("Reset\n");
usbd_device_event_irq(udc_device, DEVICE_RESET, 0);
} else {
if (USIR0)
usbdbg("UISR0: %x \n", USIR0);
if (readl(USIR0))
usbdbg("UISR0: %x \n", readl(USIR0));
if (USIR0 & 0x2)
USIR0 = 0x2;
if (readl(USIR0) & 0x2)
writel(0x2, USIR0);
/* Control traffic */
if (USIR0 & USIR0_IR0) {
if (readl(USIR0) & USIR0_IR0) {
handled = 1;
writel(USIR0_IR0, USIR0);
udc_handle_ep0(udc_device->bus->endpoint_array);
USIR0 = USIR0_IR0;
}
endpoint = udc_device->bus->endpoint_array;
@ -464,11 +472,11 @@ void udc_irq(void)
USB_ENDPOINT_NUMBER_MASK;
if (!ep_num)
continue;
udcisr0 = UDCISR0;
udcisr0 = readl(UDCISR0);
if (udcisr0 &
UDCISR_INT(ep_num, UDC_INT_PACKETCMP)) {
UDCISR0 = UDCISR_INT(ep_num,
UDC_INT_PACKETCMP);
writel(UDCISR_INT(ep_num, UDC_INT_PACKETCMP),
UDCISR0);
udc_handle_ep(&endpoint[i]);
}
}
@ -485,21 +493,21 @@ void udc_irq(void)
static inline void udc_set_mask_UDCCR(int mask)
{
UDCCR = (UDCCR & UDCCR_MASK_BITS) | (mask & UDCCR_MASK_BITS);
writel((readl(UDCCR) & UDCCR_MASK_BITS) | (mask & UDCCR_MASK_BITS), UDCCR);
}
static inline void udc_clear_mask_UDCCR(int mask)
{
UDCCR = (UDCCR & UDCCR_MASK_BITS) & ~(mask & UDCCR_MASK_BITS);
writel((readl(UDCCR) & UDCCR_MASK_BITS) & ~(mask & UDCCR_MASK_BITS), UDCCR);
}
static void pio_irq_enable(int ep_num)
{
if (ep_num < 16)
UDCICR0 |= 3 << (ep_num * 2);
writel(readl(UDCICR0) | 3 << (ep_num * 2), UDCICR0);
else {
ep_num -= 16;
UDCICR1 |= 3 << (ep_num * 2);
writel(readl(UDCICR1) | 3 << (ep_num * 2), UDCICR1);
}
}
@ -589,22 +597,26 @@ void udc_setup_ep(struct usb_device_instance *device, unsigned int id,
tmp |= (ep_size << UDCCONR_MPS_S) & UDCCONR_MPS;
tmp |= UDCCONR_EE;
UDCCN(ep_num) = tmp;
writel(tmp, UDCCN(ep_num));
usbdbg("UDCCR%c = %x", 'A' + ep_num-1, UDCCN(ep_num));
usbdbg("UDCCSR%c = %x", 'A' + ep_num-1, UDCCSN(ep_num));
//usbdbg
usbdbg("UDCCR%c = %x", 'A' + ep_num-1, readl(UDCCN(ep_num)));
usbdbg("UDCCSR%c = %x", 'A' + ep_num-1, readl(UDCCSN(ep_num)));
}
#define CONFIG_USB_DEV_PULLUP_GPIO 87
/* Connect the USB device to the bus */
void udc_connect(void)
{
usbdbg("UDC connect");
#ifdef CONFIG_USB_DEV_PULLUP_GPIO
/* Turn on the USB connection by enabling the pullup resistor */
set_GPIO_mode(CONFIG_USB_DEV_PULLUP_GPIO | GPIO_OUT);
GPSR(CONFIG_USB_DEV_PULLUP_GPIO) = GPIO_bit(CONFIG_USB_DEV_PULLUP_GPIO);
writel(GPIO_bit(CONFIG_USB_DEV_PULLUP_GPIO), GPSR(CONFIG_USB_DEV_PULLUP_GPIO));
#else
/* Host port 2 transceiver D+ pull up enable */
writel(readl(UP2OCR) | UP2OCR_DPPUE, UP2OCR);
#endif
}
/* Disconnect the USB device to the bus */
@ -612,8 +624,13 @@ void udc_disconnect(void)
{
usbdbg("UDC disconnect");
#ifdef CONFIG_USB_DEV_PULLUP_GPIO
/* Turn off the USB connection by disabling the pullup resistor */
GPCR(CONFIG_USB_DEV_PULLUP_GPIO) = GPIO_bit(CONFIG_USB_DEV_PULLUP_GPIO);
writel(GPIO_bit(CONFIG_USB_DEV_PULLUP_GPIO), GPCR(CONFIG_USB_DEV_PULLUP_GPIO));
#else
/* Host port 2 transceiver D+ pull up disable */
writel(readl(UP2OCR) & ~UP2OCR_DPPUE, UP2OCR);
#endif
}
/* Switch on the UDC */
@ -621,15 +638,14 @@ void udc_enable(struct usb_device_instance *device)
{
ep0state = EP0_IDLE;
CKEN |= CKEN11_USB;
/* enable endpoint 0, A, B's Packet Complete Interrupt. */
UDCICR0 = 0x0000003f;
UDCICR1 = 0xa8000000;
writel(0xffffffff, UDCICR0);
writel(0xa8000000, UDCICR1);
/* clear the interrupt status/control registers */
UDCISR0 = 0xffffffff;
UDCISR1 = 0xffffffff;
writel(0xffffffff, UDCISR0);
writel(0xffffffff, UDCISR1);
/* set UDC-enable */
udc_set_mask_UDCCR(UDCCR_UDE);
@ -652,7 +668,7 @@ void udc_disable(void)
udc_clear_mask_UDCCR(UDCCR_UDE);
/* Disable clock for USB device */
CKEN &= ~CKEN11_USB;
writel(readl(CKEN) & ~CKEN11_USB, CKEN);
/* Free ep0 URB */
if (ep0_urb) {
@ -689,14 +705,15 @@ int udc_init(void)
udc_device = NULL;
usbdbg("PXA27x usbd start");
/* Enable clock for USB device */
writel(readl(CKEN) | CKEN11_USB, CKEN);
/* Disable the UDC */
udc_clear_mask_UDCCR(UDCCR_UDE);
/* Disable clock for USB device */
CKEN &= ~CKEN11_USB;
/* Disable IRQs: we don't use them */
UDCICR0 = UDCICR1 = 0;
writel(0, UDCICR0);
writel(0, UDCICR1);
return 0;
}

View File

@ -0,0 +1,271 @@
/* linux/arch/arm/plat-s3c/include/plat/regs-otg.h
*
* Copyright (C) 2004 Herbert Poetzl <herbert@13thfloor.at>
*
* Registers remapping:
* Lukasz Majewski <l.majewski@samsumg.com>
*
* This include file 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.
*/
#ifndef __ASM_ARCH_REGS_USB_OTG_HS_H
#define __ASM_ARCH_REGS_USB_OTG_HS_H
/* USB2.0 OTG Controller register */
struct s3c_usbotg_phy {
u32 phypwr;
u32 phyclk;
u32 rstcon;
};
/* Device Logical IN Endpoint-Specific Registers */
struct s3c_dev_in_endp {
u32 diepctl;
u8 res1[4];
u32 diepint;
u8 res2[4];
u32 dieptsiz;
u32 diepdma;
u8 res3[4];
u32 diepdmab;
};
/* Device Logical OUT Endpoint-Specific Registers */
struct s3c_dev_out_endp {
u32 doepctl;
u8 res1[4];
u32 doepint;
u8 res2[4];
u32 doeptsiz;
u32 doepdma;
u8 res3[4];
u32 doepdmab;
};
struct ep_fifo {
u32 fifo;
u8 res[4092];
};
/* USB2.0 OTG Controller register */
struct s3c_usbotg_reg {
/* Core Global Registers */
u32 gotgctl; /* OTG Control & Status */
u32 gotgint; /* OTG Interrupt */
u32 gahbcfg; /* Core AHB Configuration */
u32 gusbcfg; /* Core USB Configuration */
u32 grstctl; /* Core Reset */
u32 gintsts; /* Core Interrupt */
u32 gintmsk; /* Core Interrupt Mask */
u32 grxstsr; /* Receive Status Debug Read/Status Read */
u32 grxstsp; /* Receive Status Debug Pop/Status Pop */
u32 grxfsiz; /* Receive FIFO Size */
u32 gnptxfsiz; /* Non-Periodic Transmit FIFO Size */
u8 res1[216];
u32 dieptxf[15]; /* Device Periodic Transmit FIFO size register */
u8 res2[1728];
/* Device Configuration */
u32 dcfg; /* Device Configuration Register */
u32 dctl; /* Device Control */
u32 dsts; /* Device Status */
u8 res3[4];
u32 diepmsk; /* Device IN Endpoint Common Interrupt Mask */
u32 doepmsk; /* Device OUT Endpoint Common Interrupt Mask */
u32 daint; /* Device All Endpoints Interrupt */
u32 daintmsk; /* Device All Endpoints Interrupt Mask */
u8 res4[224];
struct s3c_dev_in_endp in_endp[16];
struct s3c_dev_out_endp out_endp[16];
u8 res5[768];
struct ep_fifo ep[16];
};
/*===================================================================== */
/*definitions related to CSR setting */
/* S3C_UDC_OTG_GOTGCTL */
#define B_SESSION_VALID (0x1<<19)
#define A_SESSION_VALID (0x1<<18)
/* S3C_UDC_OTG_GAHBCFG */
#define PTXFE_HALF (0<<8)
#define PTXFE_ZERO (1<<8)
#define NPTXFE_HALF (0<<7)
#define NPTXFE_ZERO (1<<7)
#define MODE_SLAVE (0<<5)
#define MODE_DMA (1<<5)
#define BURST_SINGLE (0<<1)
#define BURST_INCR (1<<1)
#define BURST_INCR4 (3<<1)
#define BURST_INCR8 (5<<1)
#define BURST_INCR16 (7<<1)
#define GBL_INT_UNMASK (1<<0)
#define GBL_INT_MASK (0<<0)
/* S3C_UDC_OTG_GRSTCTL */
#define AHB_MASTER_IDLE (1u<<31)
#define CORE_SOFT_RESET (0x1<<0)
/* S3C_UDC_OTG_GINTSTS/S3C_UDC_OTG_GINTMSK core interrupt register */
#define INT_RESUME (1u<<31)
#define INT_DISCONN (0x1<<29)
#define INT_CONN_ID_STS_CNG (0x1<<28)
#define INT_OUT_EP (0x1<<19)
#define INT_IN_EP (0x1<<18)
#define INT_ENUMDONE (0x1<<13)
#define INT_RESET (0x1<<12)
#define INT_SUSPEND (0x1<<11)
#define INT_EARLY_SUSPEND (0x1<<10)
#define INT_NP_TX_FIFO_EMPTY (0x1<<5)
#define INT_RX_FIFO_NOT_EMPTY (0x1<<4)
#define INT_SOF (0x1<<3)
#define INT_DEV_MODE (0x0<<0)
#define INT_HOST_MODE (0x1<<1)
#define INT_GOUTNakEff (0x01<<7)
#define INT_GINNakEff (0x01<<6)
#define FULL_SPEED_CONTROL_PKT_SIZE 8
#define FULL_SPEED_BULK_PKT_SIZE 64
#define HIGH_SPEED_CONTROL_PKT_SIZE 64
#define HIGH_SPEED_BULK_PKT_SIZE 512
#define RX_FIFO_SIZE (1024*4)
#define NPTX_FIFO_SIZE (1024*4)
#define PTX_FIFO_SIZE (1536*1)
#define DEPCTL_TXFNUM_0 (0x0<<22)
#define DEPCTL_TXFNUM_1 (0x1<<22)
#define DEPCTL_TXFNUM_2 (0x2<<22)
#define DEPCTL_TXFNUM_3 (0x3<<22)
#define DEPCTL_TXFNUM_4 (0x4<<22)
/* Enumeration speed */
#define USB_HIGH_30_60MHZ (0x0<<1)
#define USB_FULL_30_60MHZ (0x1<<1)
#define USB_LOW_6MHZ (0x2<<1)
#define USB_FULL_48MHZ (0x3<<1)
/* S3C_UDC_OTG_GRXSTSP STATUS */
#define OUT_PKT_RECEIVED (0x2<<17)
#define OUT_TRANSFER_COMPLELTED (0x3<<17)
#define SETUP_TRANSACTION_COMPLETED (0x4<<17)
#define SETUP_PKT_RECEIVED (0x6<<17)
#define GLOBAL_OUT_NAK (0x1<<17)
/* S3C_UDC_OTG_DCTL device control register */
#define NORMAL_OPERATION (0x1<<0)
#define SOFT_DISCONNECT (0x1<<1)
/* S3C_UDC_OTG_DAINT device all endpoint interrupt register */
#define DAINT_OUT_BIT (16)
#define DAINT_MASK (0xFFFF)
/* S3C_UDC_OTG_DIEPCTL0/DOEPCTL0 device
control IN/OUT endpoint 0 control register */
#define DEPCTL_EPENA (0x1<<31)
#define DEPCTL_EPDIS (0x1<<30)
#define DEPCTL_SETD1PID (0x1<<29)
#define DEPCTL_SETD0PID (0x1<<28)
#define DEPCTL_SNAK (0x1<<27)
#define DEPCTL_CNAK (0x1<<26)
#define DEPCTL_STALL (0x1<<21)
#define DEPCTL_TYPE_BIT (18)
#define DEPCTL_TYPE_MASK (0x3<<18)
#define DEPCTL_CTRL_TYPE (0x0<<18)
#define DEPCTL_ISO_TYPE (0x1<<18)
#define DEPCTL_BULK_TYPE (0x2<<18)
#define DEPCTL_INTR_TYPE (0x3<<18)
#define DEPCTL_USBACTEP (0x1<<15)
#define DEPCTL_NEXT_EP_BIT (11)
#define DEPCTL_MPS_BIT (0)
#define DEPCTL_MPS_MASK (0x7FF)
#define DEPCTL0_MPS_64 (0x0<<0)
#define DEPCTL0_MPS_32 (0x1<<0)
#define DEPCTL0_MPS_16 (0x2<<0)
#define DEPCTL0_MPS_8 (0x3<<0)
#define DEPCTL_MPS_BULK_512 (512<<0)
#define DEPCTL_MPS_INT_MPS_16 (16<<0)
#define DIEPCTL0_NEXT_EP_BIT (11)
/* S3C_UDC_OTG_DIEPMSK/DOEPMSK device IN/OUT endpoint
common interrupt mask register */
/* S3C_UDC_OTG_DIEPINTn/DOEPINTn device IN/OUT endpoint interrupt register */
#define BACK2BACK_SETUP_RECEIVED (0x1<<6)
#define INTKNEPMIS (0x1<<5)
#define INTKN_TXFEMP (0x1<<4)
#define NON_ISO_IN_EP_TIMEOUT (0x1<<3)
#define CTRL_OUT_EP_SETUP_PHASE_DONE (0x1<<3)
#define AHB_ERROR (0x1<<2)
#define EPDISBLD (0x1<<1)
#define TRANSFER_DONE (0x1<<0)
#define USB_PHY_CTRL_EN0 (0x1 << 0)
/* OPHYPWR */
#define PHY_0_SLEEP (0x1 << 5)
#define OTG_DISABLE_0 (0x1 << 4)
#define ANALOG_PWRDOWN (0x1 << 3)
#define FORCE_SUSPEND_0 (0x1 << 0)
/* URSTCON */
#define HOST_SW_RST (0x1 << 4)
#define PHY_SW_RST1 (0x1 << 3)
#define PHYLNK_SW_RST (0x1 << 2)
#define LINK_SW_RST (0x1 << 1)
#define PHY_SW_RST0 (0x1 << 0)
/* OPHYCLK */
#define COMMON_ON_N1 (0x1 << 7)
#define COMMON_ON_N0 (0x1 << 4)
#define ID_PULLUP0 (0x1 << 2)
#define CLK_SEL_24MHZ (0x3 << 0)
#define CLK_SEL_12MHZ (0x2 << 0)
#define CLK_SEL_48MHZ (0x0 << 0)
/* Device Configuration Register DCFG */
#define DEV_SPEED_HIGH_SPEED_20 (0x0 << 0)
#define DEV_SPEED_FULL_SPEED_20 (0x1 << 0)
#define DEV_SPEED_LOW_SPEED_11 (0x2 << 0)
#define DEV_SPEED_FULL_SPEED_11 (0x3 << 0)
#define EP_MISS_CNT(x) (x << 18)
#define DEVICE_ADDRESS(x) (x << 4)
/* Core Reset Register (GRSTCTL) */
#define TX_FIFO_FLUSH (0x1 << 5)
#define RX_FIFO_FLUSH (0x1 << 4)
#define TX_FIFO_NUMBER(x) (x << 6)
#define TX_FIFO_FLUSH_ALL TX_FIFO_NUMBER(0x10)
/* Masks definitions */
#define GINTMSK_INIT (INT_OUT_EP | INT_IN_EP | INT_RESUME | INT_ENUMDONE\
| INT_RESET | INT_SUSPEND)
#define DOEPMSK_INIT (CTRL_OUT_EP_SETUP_PHASE_DONE | AHB_ERROR|TRANSFER_DONE)
#define DIEPMSK_INIT (NON_ISO_IN_EP_TIMEOUT|AHB_ERROR|TRANSFER_DONE)
#define GAHBCFG_INIT (PTXFE_HALF | NPTXFE_HALF | MODE_DMA | BURST_INCR4\
| GBL_INT_UNMASK)
/* Device Endpoint X Transfer Size Register (DIEPTSIZX) */
#define DIEPT_SIZ_PKT_CNT(x) (x << 19)
#define DIEPT_SIZ_XFER_SIZE(x) (x << 0)
/* Device OUT Endpoint X Transfer Size Register (DOEPTSIZX) */
#define DOEPT_SIZ_PKT_CNT(x) (x << 19)
#define DOEPT_SIZ_XFER_SIZE(x) (x << 0)
#define DOEPT_SIZ_XFER_SIZE_MAX_EP0 (0x7F << 0)
#define DOEPT_SIZ_XFER_SIZE_MAX_EP (0x7FFF << 0)
/* Device Endpoint-N Control Register (DIEPCTLn/DOEPCTLn) */
#define DIEPCTL_TX_FIFO_NUM(x) (x << 22)
#define DIEPCTL_TX_FIFO_NUM_MASK (~DIEPCTL_TX_FIFO_NUM(0xF))
/* Device ALL Endpoints Interrupt Register (DAINT) */
#define DAINT_IN_EP_INT(x) (x << 0)
#define DAINT_OUT_EP_INT(x) (x << 16)
#endif

View File

@ -0,0 +1,892 @@
/*
* drivers/usb/gadget/s3c_udc_otg.c
* Samsung S3C on-chip full/high speed USB OTG 2.0 device controllers
*
* Copyright (C) 2008 for Samsung Electronics
*
* BSP Support for Samsung's UDC driver
* available at:
* git://git.kernel.org/pub/scm/linux/kernel/git/kki_ap/linux-2.6-samsung.git
*
* State machine bugfixes:
* Marek Szyprowski <m.szyprowski@samsung.com>
*
* Ported to u-boot:
* Marek Szyprowski <m.szyprowski@samsung.com>
* Lukasz Majewski <l.majewski@samsumg.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <common.h>
#include <asm/errno.h>
#include <linux/list.h>
#include <malloc.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <asm/byteorder.h>
#include <asm/io.h>
#include <asm/mach-types.h>
#include <asm/arch/gpio.h>
#include "regs-otg.h"
#include <usb/s3c_udc.h>
#include <usb/lin_gadget_compat.h>
/***********************************************************/
#define OTG_DMA_MODE 1
#undef DEBUG_S3C_UDC_SETUP
#undef DEBUG_S3C_UDC_EP0
#undef DEBUG_S3C_UDC_ISR
#undef DEBUG_S3C_UDC_OUT_EP
#undef DEBUG_S3C_UDC_IN_EP
#undef DEBUG_S3C_UDC
/* #define DEBUG_S3C_UDC_SETUP */
/* #define DEBUG_S3C_UDC_EP0 */
/* #define DEBUG_S3C_UDC_ISR */
/* #define DEBUG_S3C_UDC_OUT_EP */
/* #define DEBUG_S3C_UDC_IN_EP */
/* #define DEBUG_S3C_UDC */
#include <usb/s3c_udc.h>
#define EP0_CON 0
#define EP_MASK 0xF
#if defined(DEBUG_S3C_UDC_SETUP) || defined(DEBUG_S3C_UDC_ISR) \
|| defined(DEBUG_S3C_UDC_OUT_EP)
static char *state_names[] = {
"WAIT_FOR_SETUP",
"DATA_STATE_XMIT",
"DATA_STATE_NEED_ZLP",
"WAIT_FOR_OUT_STATUS",
"DATA_STATE_RECV",
"WAIT_FOR_COMPLETE",
"WAIT_FOR_OUT_COMPLETE",
"WAIT_FOR_IN_COMPLETE",
"WAIT_FOR_NULL_COMPLETE",
};
#endif
#define DRIVER_DESC "S3C HS USB OTG Device Driver, (c) Samsung Electronics"
#define DRIVER_VERSION "15 March 2009"
struct s3c_udc *the_controller;
static const char driver_name[] = "s3c-udc";
static const char driver_desc[] = DRIVER_DESC;
static const char ep0name[] = "ep0-control";
/* Max packet size*/
static unsigned int ep0_fifo_size = 64;
static unsigned int ep_fifo_size = 512;
static unsigned int ep_fifo_size2 = 1024;
static int reset_available = 1;
static struct usb_ctrlrequest *usb_ctrl;
static dma_addr_t usb_ctrl_dma_addr;
/*
Local declarations.
*/
static int s3c_ep_enable(struct usb_ep *ep,
const struct usb_endpoint_descriptor *);
static int s3c_ep_disable(struct usb_ep *ep);
static struct usb_request *s3c_alloc_request(struct usb_ep *ep,
gfp_t gfp_flags);
static void s3c_free_request(struct usb_ep *ep, struct usb_request *);
static int s3c_queue(struct usb_ep *ep, struct usb_request *, gfp_t gfp_flags);
static int s3c_dequeue(struct usb_ep *ep, struct usb_request *);
static int s3c_fifo_status(struct usb_ep *ep);
static void s3c_fifo_flush(struct usb_ep *ep);
static void s3c_ep0_read(struct s3c_udc *dev);
static void s3c_ep0_kick(struct s3c_udc *dev, struct s3c_ep *ep);
static void s3c_handle_ep0(struct s3c_udc *dev);
static int s3c_ep0_write(struct s3c_udc *dev);
static int write_fifo_ep0(struct s3c_ep *ep, struct s3c_request *req);
static void done(struct s3c_ep *ep, struct s3c_request *req, int status);
static void stop_activity(struct s3c_udc *dev,
struct usb_gadget_driver *driver);
static int udc_enable(struct s3c_udc *dev);
static void udc_set_address(struct s3c_udc *dev, unsigned char address);
static void reconfig_usbd(void);
static void set_max_pktsize(struct s3c_udc *dev, enum usb_device_speed speed);
static void nuke(struct s3c_ep *ep, int status);
static int s3c_udc_set_halt(struct usb_ep *_ep, int value);
static void s3c_udc_set_nak(struct s3c_ep *ep);
static struct usb_ep_ops s3c_ep_ops = {
.enable = s3c_ep_enable,
.disable = s3c_ep_disable,
.alloc_request = s3c_alloc_request,
.free_request = s3c_free_request,
.queue = s3c_queue,
.dequeue = s3c_dequeue,
.set_halt = s3c_udc_set_halt,
.fifo_status = s3c_fifo_status,
.fifo_flush = s3c_fifo_flush,
};
#define create_proc_files() do {} while (0)
#define remove_proc_files() do {} while (0)
/***********************************************************/
void __iomem *regs_otg;
struct s3c_usbotg_reg *reg;
struct s3c_usbotg_phy *phy;
static unsigned int usb_phy_ctrl;
void otg_phy_init(struct s3c_udc *dev)
{
dev->pdata->phy_control(1);
/*USB PHY0 Enable */
printf("USB PHY0 Enable\n");
/* Enable PHY */
writel(readl(usb_phy_ctrl) | USB_PHY_CTRL_EN0, usb_phy_ctrl);
if (dev->pdata->usb_flags == PHY0_SLEEP) /* C210 Universal */
writel((readl(&phy->phypwr)
&~(PHY_0_SLEEP | OTG_DISABLE_0 | ANALOG_PWRDOWN)
&~FORCE_SUSPEND_0), &phy->phypwr);
else /* C110 GONI */
writel((readl(&phy->phypwr) &~(OTG_DISABLE_0 | ANALOG_PWRDOWN)
&~FORCE_SUSPEND_0), &phy->phypwr);
writel((readl(&phy->phyclk) &~(ID_PULLUP0 | COMMON_ON_N0)) |
CLK_SEL_24MHZ, &phy->phyclk); /* PLL 24Mhz */
writel((readl(&phy->rstcon) &~(LINK_SW_RST | PHYLNK_SW_RST))
| PHY_SW_RST0, &phy->rstcon);
udelay(10);
writel(readl(&phy->rstcon)
&~(PHY_SW_RST0 | LINK_SW_RST | PHYLNK_SW_RST), &phy->rstcon);
udelay(10);
}
void otg_phy_off(struct s3c_udc *dev)
{
/* reset controller just in case */
writel(PHY_SW_RST0, &phy->rstcon);
udelay(20);
writel(readl(&phy->phypwr) &~PHY_SW_RST0, &phy->rstcon);
udelay(20);
writel(readl(&phy->phypwr) | OTG_DISABLE_0 | ANALOG_PWRDOWN
| FORCE_SUSPEND_0, &phy->phypwr);
writel(readl(usb_phy_ctrl) &~USB_PHY_CTRL_EN0, usb_phy_ctrl);
writel((readl(&phy->phyclk) & ~(ID_PULLUP0 | COMMON_ON_N0)),
&phy->phyclk);
udelay(10000);
dev->pdata->phy_control(0);
}
/***********************************************************/
#include "s3c_udc_otg_xfer_dma.c"
/*
* udc_disable - disable USB device controller
*/
static void udc_disable(struct s3c_udc *dev)
{
DEBUG_SETUP("%s: %p\n", __func__, dev);
udc_set_address(dev, 0);
dev->ep0state = WAIT_FOR_SETUP;
dev->gadget.speed = USB_SPEED_UNKNOWN;
dev->usb_address = 0;
otg_phy_off(dev);
}
/*
* udc_reinit - initialize software state
*/
static void udc_reinit(struct s3c_udc *dev)
{
unsigned int i;
DEBUG_SETUP("%s: %p\n", __func__, dev);
/* device/ep0 records init */
INIT_LIST_HEAD(&dev->gadget.ep_list);
INIT_LIST_HEAD(&dev->gadget.ep0->ep_list);
dev->ep0state = WAIT_FOR_SETUP;
/* basic endpoint records init */
for (i = 0; i < S3C_MAX_ENDPOINTS; i++) {
struct s3c_ep *ep = &dev->ep[i];
if (i != 0)
list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list);
ep->desc = 0;
ep->stopped = 0;
INIT_LIST_HEAD(&ep->queue);
ep->pio_irqs = 0;
}
/* the rest was statically initialized, and is read-only */
}
#define BYTES2MAXP(x) (x / 8)
#define MAXP2BYTES(x) (x * 8)
/* until it's enabled, this UDC should be completely invisible
* to any USB host.
*/
static int udc_enable(struct s3c_udc *dev)
{
DEBUG_SETUP("%s: %p\n", __func__, dev);
otg_phy_init(dev);
reconfig_usbd();
DEBUG_SETUP("S3C USB 2.0 OTG Controller Core Initialized : 0x%x\n",
readl(&reg->gintmsk));
dev->gadget.speed = USB_SPEED_UNKNOWN;
return 0;
}
/*
Register entry point for the peripheral controller driver.
*/
int usb_gadget_register_driver(struct usb_gadget_driver *driver)
{
struct s3c_udc *dev = the_controller;
int retval = 0;
unsigned long flags;
DEBUG_SETUP("%s: %s\n", __func__, "no name");
if (!driver
|| (driver->speed != USB_SPEED_FULL
&& driver->speed != USB_SPEED_HIGH)
|| !driver->bind || !driver->disconnect || !driver->setup)
return -EINVAL;
if (!dev)
return -ENODEV;
if (dev->driver)
return -EBUSY;
spin_lock_irqsave(&dev->lock, flags);
/* first hook up the driver ... */
dev->driver = driver;
spin_unlock_irqrestore(&dev->lock, flags);
if (retval) { /* TODO */
printf("target device_add failed, error %d\n", retval);
return retval;
}
retval = driver->bind(&dev->gadget);
if (retval) {
DEBUG_SETUP("%s: bind to driver --> error %d\n",
dev->gadget.name, retval);
dev->driver = 0;
return retval;
}
enable_irq(IRQ_OTG);
DEBUG_SETUP("Registered gadget driver %s\n", dev->gadget.name);
udc_enable(dev);
return 0;
}
/*
* Unregister entry point for the peripheral controller driver.
*/
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
{
struct s3c_udc *dev = the_controller;
unsigned long flags;
if (!dev)
return -ENODEV;
if (!driver || driver != dev->driver)
return -EINVAL;
spin_lock_irqsave(&dev->lock, flags);
dev->driver = 0;
stop_activity(dev, driver);
spin_unlock_irqrestore(&dev->lock, flags);
driver->unbind(&dev->gadget);
disable_irq(IRQ_OTG);
udc_disable(dev);
return 0;
}
/*
* done - retire a request; caller blocked irqs
*/
static void done(struct s3c_ep *ep, struct s3c_request *req, int status)
{
unsigned int stopped = ep->stopped;
DEBUG("%s: %s %p, req = %p, stopped = %d\n",
__func__, ep->ep.name, ep, &req->req, stopped);
list_del_init(&req->queue);
if (likely(req->req.status == -EINPROGRESS))
req->req.status = status;
else
status = req->req.status;
if (status && status != -ESHUTDOWN) {
DEBUG("complete %s req %p stat %d len %u/%u\n",
ep->ep.name, &req->req, status,
req->req.actual, req->req.length);
}
/* don't modify queue heads during completion callback */
ep->stopped = 1;
#ifdef DEBUG_S3C_UDC
printf("calling complete callback\n");
{
int i, len = req->req.length;
printf("pkt[%d] = ", req->req.length);
if (len > 64)
len = 64;
for (i = 0; i < len; i++) {
printf("%02x", ((u8 *)req->req.buf)[i]);
if ((i & 7) == 7)
printf(" ");
}
printf("\n");
}
#endif
spin_unlock(&ep->dev->lock);
req->req.complete(&ep->ep, &req->req);
spin_lock(&ep->dev->lock);
DEBUG("callback completed\n");
ep->stopped = stopped;
}
/*
* nuke - dequeue ALL requests
*/
static void nuke(struct s3c_ep *ep, int status)
{
struct s3c_request *req;
DEBUG("%s: %s %p\n", __func__, ep->ep.name, ep);
/* called with irqs blocked */
while (!list_empty(&ep->queue)) {
req = list_entry(ep->queue.next, struct s3c_request, queue);
done(ep, req, status);
}
}
static void stop_activity(struct s3c_udc *dev,
struct usb_gadget_driver *driver)
{
int i;
/* don't disconnect drivers more than once */
if (dev->gadget.speed == USB_SPEED_UNKNOWN)
driver = 0;
dev->gadget.speed = USB_SPEED_UNKNOWN;
/* prevent new request submissions, kill any outstanding requests */
for (i = 0; i < S3C_MAX_ENDPOINTS; i++) {
struct s3c_ep *ep = &dev->ep[i];
ep->stopped = 1;
nuke(ep, -ESHUTDOWN);
}
/* report disconnect; the driver is already quiesced */
if (driver) {
spin_unlock(&dev->lock);
driver->disconnect(&dev->gadget);
spin_lock(&dev->lock);
}
/* re-init driver-visible data structures */
udc_reinit(dev);
}
static void reconfig_usbd(void)
{
/* 2. Soft-reset OTG Core and then unreset again. */
int i;
unsigned int uTemp = writel(CORE_SOFT_RESET, &reg->grstctl);
DEBUG(2, "Reseting OTG controller\n");
writel(0<<15 /* PHY Low Power Clock sel*/
|1<<14 /* Non-Periodic TxFIFO Rewind Enable*/
|0x5<<10 /* Turnaround time*/
|0<<9 | 0<<8 /* [0:HNP disable,1:HNP enable][ 0:SRP disable*/
/* 1:SRP enable] H1= 1,1*/
|0<<7 /* Ulpi DDR sel*/
|0<<6 /* 0: high speed utmi+, 1: full speed serial*/
|0<<4 /* 0: utmi+, 1:ulpi*/
|1<<3 /* phy i/f 0:8bit, 1:16bit*/
|0x7<<0, /* HS/FS Timeout**/
&reg->gusbcfg);
/* 3. Put the OTG device core in the disconnected state.*/
uTemp = readl(&reg->dctl);
uTemp |= SOFT_DISCONNECT;
writel(uTemp, &reg->dctl);
udelay(20);
/* 4. Make the OTG device core exit from the disconnected state.*/
uTemp = readl(&reg->dctl);
uTemp = uTemp & ~SOFT_DISCONNECT;
writel(uTemp, &reg->dctl);
/* 5. Configure OTG Core to initial settings of device mode.*/
/* [][1: full speed(30Mhz) 0:high speed]*/
writel(EP_MISS_CNT(1) | DEV_SPEED_HIGH_SPEED_20, &reg->dcfg);
mdelay(1);
/* 6. Unmask the core interrupts*/
writel(GINTMSK_INIT, &reg->gintmsk);
/* 7. Set NAK bit of EP0, EP1, EP2*/
writel(DEPCTL_EPDIS|DEPCTL_SNAK, &reg->out_endp[EP0_CON].doepctl);
writel(DEPCTL_EPDIS|DEPCTL_SNAK, &reg->in_endp[EP0_CON].diepctl);
for (i = 1; i < S3C_MAX_ENDPOINTS; i++) {
writel(DEPCTL_EPDIS|DEPCTL_SNAK, &reg->out_endp[i].doepctl);
writel(DEPCTL_EPDIS|DEPCTL_SNAK, &reg->in_endp[i].diepctl);
}
/* 8. Unmask EPO interrupts*/
writel(((1 << EP0_CON) << DAINT_OUT_BIT)
| (1 << EP0_CON), &reg->daintmsk);
/* 9. Unmask device OUT EP common interrupts*/
writel(DOEPMSK_INIT, &reg->doepmsk);
/* 10. Unmask device IN EP common interrupts*/
writel(DIEPMSK_INIT, &reg->diepmsk);
/* 11. Set Rx FIFO Size (in 32-bit words) */
writel(RX_FIFO_SIZE >> 2, &reg->grxfsiz);
/* 12. Set Non Periodic Tx FIFO Size */
writel((NPTX_FIFO_SIZE >> 2) << 16 | ((RX_FIFO_SIZE >> 2)) << 0,
&reg->gnptxfsiz);
for (i = 1; i < S3C_MAX_HW_ENDPOINTS; i++)
writel((PTX_FIFO_SIZE >> 2) << 16 |
((RX_FIFO_SIZE + NPTX_FIFO_SIZE +
PTX_FIFO_SIZE*(i-1)) >> 2) << 0,
&reg->dieptxf[i-1]);
/* Flush the RX FIFO */
writel(RX_FIFO_FLUSH, &reg->grstctl);
while (readl(&reg->grstctl) & RX_FIFO_FLUSH)
DEBUG("%s: waiting for S3C_UDC_OTG_GRSTCTL\n", __func__);
/* Flush all the Tx FIFO's */
writel(TX_FIFO_FLUSH_ALL, &reg->grstctl);
writel(TX_FIFO_FLUSH_ALL | TX_FIFO_FLUSH, &reg->grstctl);
while (readl(&reg->grstctl) & TX_FIFO_FLUSH)
DEBUG("%s: waiting for S3C_UDC_OTG_GRSTCTL\n", __func__);
/* 13. Clear NAK bit of EP0, EP1, EP2*/
/* For Slave mode*/
/* EP0: Control OUT */
writel(DEPCTL_EPDIS | DEPCTL_CNAK,
&reg->out_endp[EP0_CON].doepctl);
/* 14. Initialize OTG Link Core.*/
writel(GAHBCFG_INIT, &reg->gahbcfg);
}
static void set_max_pktsize(struct s3c_udc *dev, enum usb_device_speed speed)
{
unsigned int ep_ctrl;
int i;
if (speed == USB_SPEED_HIGH) {
ep0_fifo_size = 64;
ep_fifo_size = 512;
ep_fifo_size2 = 1024;
dev->gadget.speed = USB_SPEED_HIGH;
} else {
ep0_fifo_size = 64;
ep_fifo_size = 64;
ep_fifo_size2 = 64;
dev->gadget.speed = USB_SPEED_FULL;
}
dev->ep[0].ep.maxpacket = ep0_fifo_size;
for (i = 1; i < S3C_MAX_ENDPOINTS; i++)
dev->ep[i].ep.maxpacket = ep_fifo_size;
/* EP0 - Control IN (64 bytes)*/
ep_ctrl = readl(&reg->in_endp[EP0_CON].diepctl);
writel(ep_ctrl|(0<<0), &reg->in_endp[EP0_CON].diepctl);
/* EP0 - Control OUT (64 bytes)*/
ep_ctrl = readl(&reg->out_endp[EP0_CON].doepctl);
writel(ep_ctrl|(0<<0), &reg->out_endp[EP0_CON].doepctl);
}
static int s3c_ep_enable(struct usb_ep *_ep,
const struct usb_endpoint_descriptor *desc)
{
struct s3c_ep *ep;
struct s3c_udc *dev;
unsigned long flags;
DEBUG("%s: %p\n", __func__, _ep);
ep = container_of(_ep, struct s3c_ep, ep);
if (!_ep || !desc || ep->desc || _ep->name == ep0name
|| desc->bDescriptorType != USB_DT_ENDPOINT
|| ep->bEndpointAddress != desc->bEndpointAddress
|| ep_maxpacket(ep) < le16_to_cpu(desc->wMaxPacketSize)) {
DEBUG("%s: bad ep or descriptor\n", __func__);
return -EINVAL;
}
/* xfer types must match, except that interrupt ~= bulk */
if (ep->bmAttributes != desc->bmAttributes
&& ep->bmAttributes != USB_ENDPOINT_XFER_BULK
&& desc->bmAttributes != USB_ENDPOINT_XFER_INT) {
DEBUG("%s: %s type mismatch\n", __func__, _ep->name);
return -EINVAL;
}
/* hardware _could_ do smaller, but driver doesn't */
if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK
&& le16_to_cpu(desc->wMaxPacketSize) != ep_maxpacket(ep))
|| !desc->wMaxPacketSize) {
DEBUG("%s: bad %s maxpacket\n", __func__, _ep->name);
return -ERANGE;
}
dev = ep->dev;
if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) {
DEBUG("%s: bogus device state\n", __func__);
return -ESHUTDOWN;
}
ep->stopped = 0;
ep->desc = desc;
ep->pio_irqs = 0;
ep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
/* Reset halt state */
s3c_udc_set_nak(ep);
s3c_udc_set_halt(_ep, 0);
spin_lock_irqsave(&ep->dev->lock, flags);
s3c_udc_ep_activate(ep);
spin_unlock_irqrestore(&ep->dev->lock, flags);
DEBUG("%s: enabled %s, stopped = %d, maxpacket = %d\n",
__func__, _ep->name, ep->stopped, ep->ep.maxpacket);
return 0;
}
/*
* Disable EP
*/
static int s3c_ep_disable(struct usb_ep *_ep)
{
struct s3c_ep *ep;
unsigned long flags;
DEBUG("%s: %p\n", __func__, _ep);
ep = container_of(_ep, struct s3c_ep, ep);
if (!_ep || !ep->desc) {
DEBUG("%s: %s not enabled\n", __func__,
_ep ? ep->ep.name : NULL);
return -EINVAL;
}
spin_lock_irqsave(&ep->dev->lock, flags);
/* Nuke all pending requests */
nuke(ep, -ESHUTDOWN);
ep->desc = 0;
ep->stopped = 1;
spin_unlock_irqrestore(&ep->dev->lock, flags);
DEBUG("%s: disabled %s\n", __func__, _ep->name);
return 0;
}
static struct usb_request *s3c_alloc_request(struct usb_ep *ep,
gfp_t gfp_flags)
{
struct s3c_request *req;
DEBUG("%s: %s %p\n", __func__, ep->name, ep);
req = kmalloc(sizeof *req, gfp_flags);
if (!req)
return 0;
memset(req, 0, sizeof *req);
INIT_LIST_HEAD(&req->queue);
return &req->req;
}
static void s3c_free_request(struct usb_ep *ep, struct usb_request *_req)
{
struct s3c_request *req;
DEBUG("%s: %p\n", __func__, ep);
req = container_of(_req, struct s3c_request, req);
WARN_ON(!list_empty(&req->queue));
kfree(req);
}
/* dequeue JUST ONE request */
static int s3c_dequeue(struct usb_ep *_ep, struct usb_request *_req)
{
struct s3c_ep *ep;
struct s3c_request *req;
unsigned long flags;
DEBUG("%s: %p\n", __func__, _ep);
ep = container_of(_ep, struct s3c_ep, ep);
if (!_ep || ep->ep.name == ep0name)
return -EINVAL;
spin_lock_irqsave(&ep->dev->lock, flags);
/* make sure it's actually queued on this endpoint */
list_for_each_entry(req, &ep->queue, queue) {
if (&req->req == _req)
break;
}
if (&req->req != _req) {
spin_unlock_irqrestore(&ep->dev->lock, flags);
return -EINVAL;
}
done(ep, req, -ECONNRESET);
spin_unlock_irqrestore(&ep->dev->lock, flags);
return 0;
}
/*
* Return bytes in EP FIFO
*/
static int s3c_fifo_status(struct usb_ep *_ep)
{
int count = 0;
struct s3c_ep *ep;
ep = container_of(_ep, struct s3c_ep, ep);
if (!_ep) {
DEBUG("%s: bad ep\n", __func__);
return -ENODEV;
}
DEBUG("%s: %d\n", __func__, ep_index(ep));
/* LPD can't report unclaimed bytes from IN fifos */
if (ep_is_in(ep))
return -EOPNOTSUPP;
return count;
}
/*
* Flush EP FIFO
*/
static void s3c_fifo_flush(struct usb_ep *_ep)
{
struct s3c_ep *ep;
ep = container_of(_ep, struct s3c_ep, ep);
if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) {
DEBUG("%s: bad ep\n", __func__);
return;
}
DEBUG("%s: %d\n", __func__, ep_index(ep));
}
static const struct usb_gadget_ops s3c_udc_ops = {
/* current versions must always be self-powered */
};
static struct s3c_udc memory = {
.usb_address = 0,
.gadget = {
.ops = &s3c_udc_ops,
.ep0 = &memory.ep[0].ep,
.name = driver_name,
},
/* control endpoint */
.ep[0] = {
.ep = {
.name = ep0name,
.ops = &s3c_ep_ops,
.maxpacket = EP0_FIFO_SIZE,
},
.dev = &memory,
.bEndpointAddress = 0,
.bmAttributes = 0,
.ep_type = ep_control,
},
/* first group of endpoints */
.ep[1] = {
.ep = {
.name = "ep1in-bulk",
.ops = &s3c_ep_ops,
.maxpacket = EP_FIFO_SIZE,
},
.dev = &memory,
.bEndpointAddress = USB_DIR_IN | 1,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.ep_type = ep_bulk_out,
.fifo_num = 1,
},
.ep[2] = {
.ep = {
.name = "ep2out-bulk",
.ops = &s3c_ep_ops,
.maxpacket = EP_FIFO_SIZE,
},
.dev = &memory,
.bEndpointAddress = USB_DIR_OUT | 2,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.ep_type = ep_bulk_in,
.fifo_num = 2,
},
.ep[3] = {
.ep = {
.name = "ep3in-int",
.ops = &s3c_ep_ops,
.maxpacket = EP_FIFO_SIZE,
},
.dev = &memory,
.bEndpointAddress = USB_DIR_IN | 3,
.bmAttributes = USB_ENDPOINT_XFER_INT,
.ep_type = ep_interrupt,
.fifo_num = 3,
},
};
/*
* probe - binds to the platform device
*/
int s3c_udc_probe(struct s3c_plat_otg_data *pdata)
{
struct s3c_udc *dev = &memory;
int retval = 0, i;
DEBUG("%s: %p\n", __func__, pdata);
dev->pdata = pdata;
phy = (struct s3c_usbotg_phy *)pdata->regs_phy;
reg = (struct s3c_usbotg_reg *)pdata->regs_otg;
usb_phy_ctrl = pdata->usb_phy_ctrl;
/* regs_otg = (void *)pdata->regs_otg; */
dev->gadget.is_dualspeed = 1; /* Hack only*/
dev->gadget.is_otg = 0;
dev->gadget.is_a_peripheral = 0;
dev->gadget.b_hnp_enable = 0;
dev->gadget.a_hnp_support = 0;
dev->gadget.a_alt_hnp_support = 0;
the_controller = dev;
for (i = 0; i < S3C_MAX_ENDPOINTS+1; i++) {
dev->dma_buf[i] = kmalloc(DMA_BUFFER_SIZE, GFP_KERNEL);
dev->dma_addr[i] = (dma_addr_t) dev->dma_buf[i];
invalidate_dcache_range((unsigned long) dev->dma_buf[i],
(unsigned long) (dev->dma_buf[i]
+ DMA_BUFFER_SIZE));
}
usb_ctrl = dev->dma_buf[0];
usb_ctrl_dma_addr = dev->dma_addr[0];
udc_reinit(dev);
return retval;
}
int usb_gadget_handle_interrupts()
{
u32 intr_status = readl(&reg->gintsts);
u32 gintmsk = readl(&reg->gintmsk);
if (intr_status & gintmsk)
return s3c_udc_irq(1, (void *)the_controller);
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -42,6 +42,7 @@ COBJS-$(CONFIG_USB_EHCI_FSL) += ehci-fsl.o
endif
COBJS-$(CONFIG_USB_EHCI_MXC) += ehci-mxc.o
COBJS-$(CONFIG_USB_EHCI_MXS) += ehci-mxs.o
COBJS-$(CONFIG_USB_EHCI_MX5) += ehci-mx5.o
COBJS-$(CONFIG_USB_EHCI_PPC4XX) += ehci-ppc4xx.o
COBJS-$(CONFIG_USB_EHCI_IXP4XX) += ehci-ixp.o
COBJS-$(CONFIG_USB_EHCI_KIRKWOOD) += ehci-kirkwood.o

View File

@ -26,6 +26,10 @@
#include <asm/io.h>
#include <malloc.h>
#include <watchdog.h>
#ifdef CONFIG_USB_KEYBOARD
#include <stdio_dev.h>
extern unsigned char new[];
#endif
#include "ehci.h"
@ -48,7 +52,7 @@ static struct descriptor {
0x29, /* bDescriptorType: hub descriptor */
2, /* bNrPorts -- runtime modified */
0, /* wHubCharacteristics */
0xff, /* bPwrOn2PwrGood */
10, /* bPwrOn2PwrGood */
0, /* bHubCntrCurrent */
{}, /* Device removable */
{} /* at most 7 ports! XXX */
@ -201,6 +205,14 @@ static inline void ehci_invalidate_dcache(struct QH *qh)
}
#endif /* CONFIG_EHCI_DCACHE */
void __ehci_powerup_fixup(uint32_t *status_reg, uint32_t *reg)
{
mdelay(50);
}
void ehci_powerup_fixup(uint32_t *status_reg, uint32_t *reg)
__attribute__((weak, alias("__ehci_powerup_fixup")));
static int handshake(uint32_t *ptr, uint32_t mask, uint32_t done, int usec)
{
uint32_t result;
@ -709,8 +721,8 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
* usb 2.0 specification say 50 ms resets on
* root
*/
wait_ms(50);
/* terminate the reset */
ehci_powerup_fixup(status_reg, &reg);
ehci_writel(status_reg, reg & ~EHCI_PS_PR);
/*
* A host controller must terminate the reset
@ -895,5 +907,32 @@ submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
debug("dev=%p, pipe=%lu, buffer=%p, length=%d, interval=%d",
dev, pipe, buffer, length, interval);
return -1;
return ehci_submit_async(dev, pipe, buffer, length, NULL);
}
#ifdef CONFIG_SYS_USB_EVENT_POLL
/*
* This function polls for USB keyboard data.
*/
void usb_event_poll()
{
struct stdio_dev *dev;
struct usb_device *usb_kbd_dev;
struct usb_interface *iface;
struct usb_endpoint_descriptor *ep;
int pipe;
int maxp;
/* Get the pointer to USB Keyboard device pointer */
dev = stdio_get_by_name("usbkbd");
usb_kbd_dev = (struct usb_device *)dev->priv;
iface = &usb_kbd_dev->config.if_desc[0];
ep = &iface->ep_desc[0];
pipe = usb_rcvintpipe(usb_kbd_dev, ep->bEndpointAddress);
/* Submit a interrupt transfer request */
maxp = usb_maxpacket(usb_kbd_dev, pipe);
usb_submit_int_msg(usb_kbd_dev, pipe, &new[0],
maxp > 8 ? 8 : maxp, ep->bInterval);
}
#endif /* CONFIG_SYS_USB_EVENT_POLL */

255
drivers/usb/host/ehci-mx5.c Normal file
View File

@ -0,0 +1,255 @@
/*
* Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
* Copyright (C) 2010 Freescale Semiconductor, Inc.
*
* 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.
*/
#include <common.h>
#include <usb.h>
#include <errno.h>
#include <linux/compiler.h>
#include <usb/ehci-fsl.h>
#include <asm/io.h>
#include <asm/arch/imx-regs.h>
#include <asm/arch/clock.h>
#include <asm/arch/mx5x_pins.h>
#include <asm/arch/iomux.h>
#include "ehci.h"
#include "ehci-core.h"
#define MX5_USBOTHER_REGS_OFFSET 0x800
#define MXC_OTG_OFFSET 0
#define MXC_H1_OFFSET 0x200
#define MXC_H2_OFFSET 0x400
#define MXC_USBCTRL_OFFSET 0
#define MXC_USB_PHY_CTR_FUNC_OFFSET 0x8
#define MXC_USB_PHY_CTR_FUNC2_OFFSET 0xc
#define MXC_USB_CTRL_1_OFFSET 0x10
#define MXC_USBH2CTRL_OFFSET 0x14
/* USB_CTRL */
#define MXC_OTG_UCTRL_OWIE_BIT (1 << 27) /* OTG wakeup intr enable */
#define MXC_OTG_UCTRL_OPM_BIT (1 << 24) /* OTG power mask */
#define MXC_H1_UCTRL_H1UIE_BIT (1 << 12) /* Host1 ULPI interrupt enable */
#define MXC_H1_UCTRL_H1WIE_BIT (1 << 11) /* HOST1 wakeup intr enable */
#define MXC_H1_UCTRL_H1PM_BIT (1 << 8) /* HOST1 power mask */
/* USB_PHY_CTRL_FUNC */
#define MXC_OTG_PHYCTRL_OC_DIS_BIT (1 << 8) /* OTG Disable Overcurrent Event */
#define MXC_H1_OC_DIS_BIT (1 << 5) /* UH1 Disable Overcurrent Event */
/* USBH2CTRL */
#define MXC_H2_UCTRL_H2UIE_BIT (1 << 8)
#define MXC_H2_UCTRL_H2WIE_BIT (1 << 7)
#define MXC_H2_UCTRL_H2PM_BIT (1 << 4)
/* USB_CTRL_1 */
#define MXC_USB_CTRL_UH1_EXT_CLK_EN (1 << 25)
/* USB pin configuration */
#define USB_PAD_CONFIG (PAD_CTL_PKE_ENABLE | PAD_CTL_SRE_FAST | \
PAD_CTL_DRV_HIGH | PAD_CTL_100K_PU | \
PAD_CTL_HYS_ENABLE | PAD_CTL_PUE_PULL)
#ifdef CONFIG_MX51
/*
* Configure the MX51 USB H1 IOMUX
*/
void setup_iomux_usb_h1(void)
{
mxc_request_iomux(MX51_PIN_USBH1_STP, IOMUX_CONFIG_ALT0);
mxc_iomux_set_pad(MX51_PIN_USBH1_STP, USB_PAD_CONFIG);
mxc_request_iomux(MX51_PIN_USBH1_CLK, IOMUX_CONFIG_ALT0);
mxc_iomux_set_pad(MX51_PIN_USBH1_CLK, USB_PAD_CONFIG);
mxc_request_iomux(MX51_PIN_USBH1_DIR, IOMUX_CONFIG_ALT0);
mxc_iomux_set_pad(MX51_PIN_USBH1_DIR, USB_PAD_CONFIG);
mxc_request_iomux(MX51_PIN_USBH1_NXT, IOMUX_CONFIG_ALT0);
mxc_iomux_set_pad(MX51_PIN_USBH1_NXT, USB_PAD_CONFIG);
mxc_request_iomux(MX51_PIN_USBH1_DATA0, IOMUX_CONFIG_ALT0);
mxc_iomux_set_pad(MX51_PIN_USBH1_DATA0, USB_PAD_CONFIG);
mxc_request_iomux(MX51_PIN_USBH1_DATA1, IOMUX_CONFIG_ALT0);
mxc_iomux_set_pad(MX51_PIN_USBH1_DATA1, USB_PAD_CONFIG);
mxc_request_iomux(MX51_PIN_USBH1_DATA2, IOMUX_CONFIG_ALT0);
mxc_iomux_set_pad(MX51_PIN_USBH1_DATA2, USB_PAD_CONFIG);
mxc_request_iomux(MX51_PIN_USBH1_DATA3, IOMUX_CONFIG_ALT0);
mxc_iomux_set_pad(MX51_PIN_USBH1_DATA3, USB_PAD_CONFIG);
mxc_request_iomux(MX51_PIN_USBH1_DATA4, IOMUX_CONFIG_ALT0);
mxc_iomux_set_pad(MX51_PIN_USBH1_DATA4, USB_PAD_CONFIG);
mxc_request_iomux(MX51_PIN_USBH1_DATA5, IOMUX_CONFIG_ALT0);
mxc_iomux_set_pad(MX51_PIN_USBH1_DATA5, USB_PAD_CONFIG);
mxc_request_iomux(MX51_PIN_USBH1_DATA6, IOMUX_CONFIG_ALT0);
mxc_iomux_set_pad(MX51_PIN_USBH1_DATA6, USB_PAD_CONFIG);
mxc_request_iomux(MX51_PIN_USBH1_DATA7, IOMUX_CONFIG_ALT0);
mxc_iomux_set_pad(MX51_PIN_USBH1_DATA7, USB_PAD_CONFIG);
}
/*
* Configure the MX51 USB H2 IOMUX
*/
void setup_iomux_usb_h2(void)
{
mxc_request_iomux(MX51_PIN_EIM_A24, IOMUX_CONFIG_ALT2);
mxc_iomux_set_pad(MX51_PIN_EIM_A24, USB_PAD_CONFIG);
mxc_request_iomux(MX51_PIN_EIM_A25, IOMUX_CONFIG_ALT2);
mxc_iomux_set_pad(MX51_PIN_EIM_A25, USB_PAD_CONFIG);
mxc_request_iomux(MX51_PIN_EIM_A26, IOMUX_CONFIG_ALT2);
mxc_iomux_set_pad(MX51_PIN_EIM_A26, USB_PAD_CONFIG);
mxc_request_iomux(MX51_PIN_EIM_A27, IOMUX_CONFIG_ALT2);
mxc_iomux_set_pad(MX51_PIN_EIM_A27, USB_PAD_CONFIG);
mxc_request_iomux(MX51_PIN_EIM_D16, IOMUX_CONFIG_ALT2);
mxc_iomux_set_pad(MX51_PIN_EIM_D16, USB_PAD_CONFIG);
mxc_request_iomux(MX51_PIN_EIM_D17, IOMUX_CONFIG_ALT2);
mxc_iomux_set_pad(MX51_PIN_EIM_D17, USB_PAD_CONFIG);
mxc_request_iomux(MX51_PIN_EIM_D18, IOMUX_CONFIG_ALT2);
mxc_iomux_set_pad(MX51_PIN_EIM_D18, USB_PAD_CONFIG);
mxc_request_iomux(MX51_PIN_EIM_D19, IOMUX_CONFIG_ALT2);
mxc_iomux_set_pad(MX51_PIN_EIM_D19, USB_PAD_CONFIG);
mxc_request_iomux(MX51_PIN_EIM_D20, IOMUX_CONFIG_ALT2);
mxc_iomux_set_pad(MX51_PIN_EIM_D20, USB_PAD_CONFIG);
mxc_request_iomux(MX51_PIN_EIM_D21, IOMUX_CONFIG_ALT2);
mxc_iomux_set_pad(MX51_PIN_EIM_D21, USB_PAD_CONFIG);
mxc_request_iomux(MX51_PIN_EIM_D22, IOMUX_CONFIG_ALT2);
mxc_iomux_set_pad(MX51_PIN_EIM_D22, USB_PAD_CONFIG);
mxc_request_iomux(MX51_PIN_EIM_D23, IOMUX_CONFIG_ALT2);
mxc_iomux_set_pad(MX51_PIN_EIM_D23, USB_PAD_CONFIG);
}
#endif
int mxc_set_usbcontrol(int port, unsigned int flags)
{
unsigned int v;
void __iomem *usb_base = (void __iomem *)OTG_BASE_ADDR;
void __iomem *usbother_base;
int ret = 0;
usbother_base = usb_base + MX5_USBOTHER_REGS_OFFSET;
switch (port) {
case 0: /* OTG port */
if (flags & MXC_EHCI_INTERNAL_PHY) {
v = __raw_readl(usbother_base +
MXC_USB_PHY_CTR_FUNC_OFFSET);
if (flags & MXC_EHCI_POWER_PINS_ENABLED)
/* OC/USBPWR is not used */
v |= MXC_OTG_PHYCTRL_OC_DIS_BIT;
else
/* OC/USBPWR is used */
v &= ~MXC_OTG_PHYCTRL_OC_DIS_BIT;
__raw_writel(v, usbother_base +
MXC_USB_PHY_CTR_FUNC_OFFSET);
v = __raw_readl(usbother_base + MXC_USBCTRL_OFFSET);
if (flags & MXC_EHCI_POWER_PINS_ENABLED)
v |= MXC_OTG_UCTRL_OPM_BIT;
else
v &= ~MXC_OTG_UCTRL_OPM_BIT;
__raw_writel(v, usbother_base + MXC_USBCTRL_OFFSET);
}
break;
case 1: /* Host 1 Host ULPI */
#ifdef CONFIG_MX51
/* The clock for the USBH1 ULPI port will come externally
from the PHY. */
v = __raw_readl(usbother_base + MXC_USB_CTRL_1_OFFSET);
__raw_writel(v | MXC_USB_CTRL_UH1_EXT_CLK_EN, usbother_base +
MXC_USB_CTRL_1_OFFSET);
#endif
v = __raw_readl(usbother_base + MXC_USBCTRL_OFFSET);
if (flags & MXC_EHCI_POWER_PINS_ENABLED)
v &= ~MXC_H1_UCTRL_H1PM_BIT; /* HOST1 power mask used */
else
v |= MXC_H1_UCTRL_H1PM_BIT; /* HOST1 power mask used */
__raw_writel(v, usbother_base + MXC_USBCTRL_OFFSET);
v = __raw_readl(usbother_base + MXC_USB_PHY_CTR_FUNC_OFFSET);
if (flags & MXC_EHCI_POWER_PINS_ENABLED)
v &= ~MXC_H1_OC_DIS_BIT; /* OC is used */
else
v |= MXC_H1_OC_DIS_BIT; /* OC is not used */
__raw_writel(v, usbother_base + MXC_USB_PHY_CTR_FUNC_OFFSET);
break;
case 2: /* Host 2 ULPI */
v = __raw_readl(usbother_base + MXC_USBH2CTRL_OFFSET);
if (flags & MXC_EHCI_POWER_PINS_ENABLED)
v &= ~MXC_H2_UCTRL_H2PM_BIT; /* HOST2 power mask used */
else
v |= MXC_H2_UCTRL_H2PM_BIT; /* HOST2 power mask used */
__raw_writel(v, usbother_base + MXC_USBH2CTRL_OFFSET);
break;
}
return ret;
}
void __board_ehci_hcd_postinit(struct usb_ehci *ehci, int port)
{
}
void board_ehci_hcd_postinit(struct usb_ehci *ehci, int port)
__attribute((weak, alias("__board_ehci_hcd_postinit")));
int ehci_hcd_init(void)
{
struct usb_ehci *ehci;
#ifdef CONFIG_MX53
struct clkctl *sc_regs = (struct clkctl *)CCM_BASE_ADDR;
u32 reg;
reg = __raw_readl(&sc_regs->cscmr1) & ~(1 << 26);
/* derive USB PHY clock multiplexer from PLL3 */
reg |= 1 << 26;
__raw_writel(reg, &sc_regs->cscmr1);
#endif
set_usboh3_clk();
enable_usboh3_clk(1);
set_usb_phy2_clk();
enable_usb_phy2_clk(1);
mdelay(1);
/* Do board specific initialization */
board_ehci_hcd_init(CONFIG_MXC_USB_PORT);
ehci = (struct usb_ehci *)(OTG_BASE_ADDR +
(0x200 * CONFIG_MXC_USB_PORT));
hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength);
hcor = (struct ehci_hcor *)((uint32_t)hccr +
HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
setbits_le32(&ehci->usbmode, CM_HOST);
__raw_writel(CONFIG_MXC_USB_PORTSC, &ehci->portsc);
setbits_le32(&ehci->portsc, USB_EN);
mxc_set_usbcontrol(CONFIG_MXC_USB_PORT, CONFIG_MXC_USB_FLAGS);
mdelay(10);
/* Do board specific post-initialization */
board_ehci_hcd_postinit(ehci, CONFIG_MXC_USB_PORT);
return 0;
}
int ehci_hcd_stop(void)
{
return 0;
}

View File

@ -1262,12 +1262,19 @@ static int ohci_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
int len = 0;
int stat = 0;
__u32 datab[4];
__u8 *data_buf = (__u8 *)datab;
union {
void *ptr;
__u8 *u8;
__u16 *u16;
__u32 *u32;
} databuf;
__u16 bmRType_bReq;
__u16 wValue;
__u16 wIndex;
__u16 wLength;
databuf.u32 = (__u32 *)datab;
#ifdef DEBUG
pkt_print(NULL, dev, pipe, buffer, transfer_len,
cmd, "SUB(rh)", usb_pipein(pipe));
@ -1297,20 +1304,20 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len,
*/
case RH_GET_STATUS:
*(__u16 *) data_buf = cpu_to_le16(1);
databuf.u16[0] = cpu_to_le16(1);
OK(2);
case RH_GET_STATUS | RH_INTERFACE:
*(__u16 *) data_buf = cpu_to_le16(0);
databuf.u16[0] = cpu_to_le16(0);
OK(2);
case RH_GET_STATUS | RH_ENDPOINT:
*(__u16 *) data_buf = cpu_to_le16(0);
databuf.u16[0] = cpu_to_le16(0);
OK(2);
case RH_GET_STATUS | RH_CLASS:
*(__u32 *) data_buf = cpu_to_le32(
databuf.u32[0] = cpu_to_le32(
RD_RH_STAT & ~(RH_HS_CRWE | RH_HS_DRWE));
OK(4);
case RH_GET_STATUS | RH_OTHER | RH_CLASS:
*(__u32 *) data_buf = cpu_to_le32(RD_RH_PORTSTAT);
databuf.u32[0] = cpu_to_le32(RD_RH_PORTSTAT);
OK(4);
case RH_CLEAR_FEATURE | RH_ENDPOINT:
@ -1374,14 +1381,14 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len,
min_t(unsigned int,
sizeof(root_hub_dev_des),
wLength));
data_buf = root_hub_dev_des; OK(len);
databuf.ptr = root_hub_dev_des; OK(len);
case (0x02): /* configuration descriptor */
len = min_t(unsigned int,
leni,
min_t(unsigned int,
sizeof(root_hub_config_des),
wLength));
data_buf = root_hub_config_des; OK(len);
databuf.ptr = root_hub_config_des; OK(len);
case (0x03): /* string descriptors */
if (wValue == 0x0300) {
len = min_t(unsigned int,
@ -1389,7 +1396,7 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len,
min_t(unsigned int,
sizeof(root_hub_str_index0),
wLength));
data_buf = root_hub_str_index0;
databuf.ptr = root_hub_str_index0;
OK(len);
}
if (wValue == 0x0301) {
@ -1398,7 +1405,7 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len,
min_t(unsigned int,
sizeof(root_hub_str_index1),
wLength));
data_buf = root_hub_str_index1;
databuf.ptr = root_hub_str_index1;
OK(len);
}
default:
@ -1410,41 +1417,45 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len,
{
__u32 temp = roothub_a(&gohci);
data_buf [0] = 9; /* min length; */
data_buf [1] = 0x29;
data_buf [2] = temp & RH_A_NDP;
databuf.u8[0] = 9; /* min length; */
databuf.u8[1] = 0x29;
databuf.u8[2] = temp & RH_A_NDP;
#ifdef CONFIG_AT91C_PQFP_UHPBUG
data_buf [2] = (data_buf [2] == 2) ? 1:0;
databuf.u8[2] = (databuf.u8[2] == 2) ? 1 : 0;
#endif
data_buf [3] = 0;
databuf.u8[3] = 0;
if (temp & RH_A_PSM) /* per-port power switching? */
data_buf [3] |= 0x1;
databuf.u8[3] |= 0x1;
if (temp & RH_A_NOCP) /* no overcurrent reporting? */
data_buf [3] |= 0x10;
databuf.u8[3] |= 0x10;
else if (temp & RH_A_OCPM)/* per-port overcurrent reporting? */
data_buf [3] |= 0x8;
databuf.u8[3] |= 0x8;
/* corresponds to data_buf[4-7] */
datab [1] = 0;
data_buf [5] = (temp & RH_A_POTPGT) >> 24;
/* corresponds to databuf.u8[4-7] */
databuf.u8[1] = 0;
databuf.u8[5] = (temp & RH_A_POTPGT) >> 24;
temp = roothub_b(&gohci);
data_buf [7] = temp & RH_B_DR;
if (data_buf [2] < 7) {
data_buf [8] = 0xff;
databuf.u8[7] = temp & RH_B_DR;
if (databuf.u8[2] < 7) {
databuf.u8[8] = 0xff;
} else {
data_buf [0] += 2;
data_buf [8] = (temp & RH_B_DR) >> 8;
data_buf [10] = data_buf [9] = 0xff;
databuf.u8[0] += 2;
databuf.u8[8] = (temp & RH_B_DR) >> 8;
databuf.u8[10] = databuf.u8[9] = 0xff;
}
len = min_t(unsigned int, leni,
min_t(unsigned int, data_buf [0], wLength));
min_t(unsigned int, databuf.u8[0], wLength));
OK(len);
}
case RH_GET_CONFIGURATION: *(__u8 *) data_buf = 0x01; OK(1);
case RH_GET_CONFIGURATION:
databuf.u8[0] = 0x01;
OK(1);
case RH_SET_CONFIGURATION: WR_RH_STAT(0x10000); OK(0);
case RH_SET_CONFIGURATION:
WR_RH_STAT(0x10000);
OK(0);
default:
dbg("unsupported root hub command");
@ -1458,8 +1469,8 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len,
#endif
len = min_t(int, len, leni);
if (data != data_buf)
memcpy(data, data_buf, len);
if (data != databuf.ptr)
memcpy(data, databuf.ptr, len);
dev->act_len = len;
dev->status = stat;

44
drivers/usb/ulpi/Makefile Normal file
View File

@ -0,0 +1,44 @@
#
# Copyright (C) 2011 Jana Rapava <fermata7@gmail.com>
# 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.
#
include $(TOPDIR)/config.mk
LIB := $(obj)libusb_ulpi.o
COBJS-$(CONFIG_USB_ULPI) += ulpi.o
COBJS-$(CONFIG_USB_ULPI_VIEWPORT) += ulpi-viewport.o
COBJS := $(COBJS-y)
SRCS := $(COBJS:.o=.c)
OBJS := $(addprefix $(obj),$(COBJS))
all: $(LIB)
$(LIB): $(obj).depend $(OBJS)
$(call cmd_link_o_target, $(OBJS))
#########################################################################
# defines $(obj).depend target
include $(SRCTREE)/rules.mk
sinclude $(obj).depend
#########################################################################

View File

@ -0,0 +1,118 @@
/*
* Copyright (C) 2011 Jana Rapava <fermata7@gmail.com>
* Copyright (C) 2011 CompuLab, Ltd. <www.compulab.co.il>
*
* Authors: Jana Rapava <fermata7@gmail.com>
* Igor Grinberg <grinberg@compulab.co.il>
*
* Based on:
* linux/drivers/usb/otg/ulpi_viewport.c
*
* Original Copyright follow:
* Copyright (C) 2011 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*
*/
#include <common.h>
#include <asm/io.h>
#include <usb/ulpi.h>
/* ULPI viewport control bits */
#define ULPI_SS (1 << 27)
#define ULPI_RWCTRL (1 << 29)
#define ULPI_RWRUN (1 << 30)
#define ULPI_WU (1 << 31)
/*
* Wait for the ULPI request to complete
*
* @ulpi_viewport - the address of the viewport
* @mask - expected value to wait for
*
* returns 0 on mask match, ULPI_ERROR on time out.
*/
static int ulpi_wait(u32 ulpi_viewport, u32 mask)
{
int timeout = CONFIG_USB_ULPI_TIMEOUT;
/* Wait for the bits in mask to become zero. */
while (--timeout) {
if ((readl(ulpi_viewport) & mask) == 0)
return 0;
udelay(1);
}
return ULPI_ERROR;
}
/*
* Wake the ULPI PHY up for communication
*
* returns 0 on success.
*/
static int ulpi_wakeup(u32 ulpi_viewport)
{
int err;
if (readl(ulpi_viewport) & ULPI_SS)
return 0; /* already awake */
writel(ULPI_WU, ulpi_viewport);
err = ulpi_wait(ulpi_viewport, ULPI_WU);
if (err)
printf("ULPI wakeup timed out\n");
return err;
}
/*
* Issue a ULPI read/write request
*
* @value - the ULPI request
*/
static int ulpi_request(u32 ulpi_viewport, u32 value)
{
int err;
err = ulpi_wakeup(ulpi_viewport);
if (err)
return err;
writel(value, ulpi_viewport);
err = ulpi_wait(ulpi_viewport, ULPI_RWRUN);
if (err)
printf("ULPI request timed out\n");
return err;
}
u32 ulpi_write(u32 ulpi_viewport, u8 *reg, u32 value)
{
u32 val = ULPI_RWRUN | ULPI_RWCTRL | ((u32)reg << 16) | (value & 0xff);
return ulpi_request(ulpi_viewport, val);
}
u32 ulpi_read(u32 ulpi_viewport, u8 *reg)
{
u32 err;
u32 val = ULPI_RWRUN | ((u32)reg << 16);
err = ulpi_request(ulpi_viewport, val);
if (err)
return err;
return (readl(ulpi_viewport) >> 8) & 0xff;
}

227
drivers/usb/ulpi/ulpi.c Normal file
View File

@ -0,0 +1,227 @@
/*
* Copyright (C) 2011 Jana Rapava <fermata7@gmail.com>
* Copyright (C) 2011 CompuLab, Ltd. <www.compulab.co.il>
*
* Authors: Jana Rapava <fermata7@gmail.com>
* Igor Grinberg <grinberg@compulab.co.il>
*
* Based on:
* linux/drivers/usb/otg/ulpi.c
* Generic ULPI USB transceiver support
*
* Original Copyright follow:
* Copyright (C) 2009 Daniel Mack <daniel@caiaq.de>
*
* Based on sources from
*
* Sascha Hauer <s.hauer@pengutronix.de>
* Freescale Semiconductors
*
* 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.
*/
#include <common.h>
#include <exports.h>
#include <usb/ulpi.h>
#define ULPI_ID_REGS_COUNT 4
#define ULPI_TEST_VALUE 0x55 /* 0x55 == 0b01010101 */
static struct ulpi_regs *ulpi = (struct ulpi_regs *)0;
static int ulpi_integrity_check(u32 ulpi_viewport)
{
u32 err, val, tval = ULPI_TEST_VALUE;
int i;
/* Use the 'special' test value to check all bits */
for (i = 0; i < 2; i++, tval <<= 1) {
err = ulpi_write(ulpi_viewport, &ulpi->scratch, tval);
if (err)
return err;
val = ulpi_read(ulpi_viewport, &ulpi->scratch);
if (val != tval) {
printf("ULPI integrity check failed\n");
return val;
}
}
return 0;
}
int ulpi_init(u32 ulpi_viewport)
{
u32 val, id = 0;
u8 *reg = &ulpi->product_id_high;
int i;
/* Assemble ID from four ULPI ID registers (8 bits each). */
for (i = 0; i < ULPI_ID_REGS_COUNT; i++) {
val = ulpi_read(ulpi_viewport, reg - i);
if (val == ULPI_ERROR)
return val;
id = (id << 8) | val;
}
/* Split ID into vendor and product ID. */
debug("ULPI transceiver ID 0x%04x:0x%04x\n", id >> 16, id & 0xffff);
return ulpi_integrity_check(ulpi_viewport);
}
int ulpi_select_transceiver(u32 ulpi_viewport, u8 speed)
{
u8 tspeed = ULPI_FC_FULL_SPEED;
u32 val;
switch (speed) {
case ULPI_FC_HIGH_SPEED:
case ULPI_FC_FULL_SPEED:
case ULPI_FC_LOW_SPEED:
case ULPI_FC_FS4LS:
tspeed = speed;
break;
default:
printf("ULPI: %s: wrong transceiver speed specified, "
"falling back to full speed\n", __func__);
}
val = ulpi_read(ulpi_viewport, &ulpi->function_ctrl);
if (val == ULPI_ERROR)
return val;
/* clear the previous speed setting */
val = (val & ~ULPI_FC_XCVRSEL_MASK) | tspeed;
return ulpi_write(ulpi_viewport, &ulpi->function_ctrl, val);
}
int ulpi_set_vbus(u32 ulpi_viewport, int on, int ext_power, int ext_ind)
{
u32 flags = ULPI_OTG_DRVVBUS;
u8 *reg = on ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear;
if (ext_power)
flags |= ULPI_OTG_DRVVBUS_EXT;
if (ext_ind)
flags |= ULPI_OTG_EXTVBUSIND;
return ulpi_write(ulpi_viewport, reg, flags);
}
int ulpi_set_pd(u32 ulpi_viewport, int enable)
{
u32 val = ULPI_OTG_DP_PULLDOWN | ULPI_OTG_DM_PULLDOWN;
u8 *reg = enable ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear;
return ulpi_write(ulpi_viewport, reg, val);
}
int ulpi_opmode_sel(u32 ulpi_viewport, u8 opmode)
{
u8 topmode = ULPI_FC_OPMODE_NORMAL;
u32 val;
switch (opmode) {
case ULPI_FC_OPMODE_NORMAL:
case ULPI_FC_OPMODE_NONDRIVING:
case ULPI_FC_OPMODE_DISABLE_NRZI:
case ULPI_FC_OPMODE_NOSYNC_NOEOP:
topmode = opmode;
break;
default:
printf("ULPI: %s: wrong OpMode specified, "
"falling back to OpMode Normal\n", __func__);
}
val = ulpi_read(ulpi_viewport, &ulpi->function_ctrl);
if (val == ULPI_ERROR)
return val;
/* clear the previous opmode setting */
val = (val & ~ULPI_FC_OPMODE_MASK) | topmode;
return ulpi_write(ulpi_viewport, &ulpi->function_ctrl, val);
}
int ulpi_serial_mode_enable(u32 ulpi_viewport, u8 smode)
{
switch (smode) {
case ULPI_IFACE_6_PIN_SERIAL_MODE:
case ULPI_IFACE_3_PIN_SERIAL_MODE:
break;
default:
printf("ULPI: %s: unrecognized Serial Mode specified\n",
__func__);
return ULPI_ERROR;
}
return ulpi_write(ulpi_viewport, &ulpi->iface_ctrl_set, smode);
}
int ulpi_suspend(u32 ulpi_viewport)
{
u32 err;
err = ulpi_write(ulpi_viewport, &ulpi->function_ctrl_clear,
ULPI_FC_SUSPENDM);
if (err)
printf("ULPI: %s: failed writing the suspend bit\n", __func__);
return err;
}
/*
* Wait for ULPI PHY reset to complete.
* Actual wait for reset must be done in a view port specific way,
* because it involves checking the DIR line.
*/
static int __ulpi_reset_wait(u32 ulpi_viewport)
{
u32 val;
int timeout = CONFIG_USB_ULPI_TIMEOUT;
/* Wait for the RESET bit to become zero */
while (--timeout) {
/*
* This function is generic and suppose to work
* with any viewport, so we cheat here and don't check
* for the error of ulpi_read(), if there is one, then
* there will be a timeout.
*/
val = ulpi_read(ulpi_viewport, &ulpi->function_ctrl);
if (!(val & ULPI_FC_RESET))
return 0;
udelay(1);
}
printf("ULPI: %s: reset timed out\n", __func__);
return ULPI_ERROR;
}
int ulpi_reset_wait(u32) __attribute__((weak, alias("__ulpi_reset_wait")));
int ulpi_reset(u32 ulpi_viewport)
{
u32 err;
err = ulpi_write(ulpi_viewport,
&ulpi->function_ctrl_set, ULPI_FC_RESET);
if (err) {
printf("ULPI: %s: failed writing reset bit\n", __func__);
return err;
}
return ulpi_reset_wait(ulpi_viewport);
}

View File

@ -44,6 +44,10 @@
#define CONFIG_SYS_TEXT_BASE 0x97800000
#define CONFIG_L2_OFF
#define CONFIG_SYS_ICACHE_OFF
#define CONFIG_SYS_DCACHE_OFF
/*
* Bootloader Components Configuration
*/
@ -53,6 +57,8 @@
#define CONFIG_CMD_FAT
#define CONFIG_CMD_EXT2
#define CONFIG_CMD_IDE
#define CONFIG_CMD_NET
#define CONFIG_CMD_DATE
#undef CONFIG_CMD_IMLS
/*
@ -174,18 +180,47 @@
#define CONFIG_MXC_ATA_PIO_MODE 4
#endif
/*
* USB
*/
#define CONFIG_CMD_USB
#ifdef CONFIG_CMD_USB
#define CONFIG_USB_EHCI /* Enable EHCI USB support */
#define CONFIG_USB_EHCI_MX5
#define CONFIG_USB_ULPI
#define CONFIG_USB_ULPI_VIEWPORT
#define CONFIG_MXC_USB_PORT 1
#if (CONFIG_MXC_USB_PORT == 0)
#define CONFIG_MXC_USB_PORTSC (1 << 28)
#define CONFIG_MXC_USB_FLAGS MXC_EHCI_INTERNAL_PHY
#else
#define CONFIG_MXC_USB_PORTSC (2 << 30)
#define CONFIG_MXC_USB_FLAGS 0
#endif
#define CONFIG_EHCI_IS_TDI
#define CONFIG_USB_STORAGE
#define CONFIG_USB_HOST_ETHER
#define CONFIG_USB_KEYBOARD
#define CONFIG_SYS_USB_EVENT_POLL_VIA_CONTROL_EP
#define CONFIG_PREBOOT
/* USB NET */
#ifdef CONFIG_CMD_NET
#define CONFIG_USB_ETHER_ASIX
#define CONFIG_NET_MULTI
#define CONFIG_CMD_PING
#define CONFIG_CMD_DHCP
#endif
#endif /* CONFIG_CMD_USB */
/*
* Filesystems
*/
#ifdef CONFIG_CMD_FAT
#define CONFIG_DOS_PARTITION
#ifdef CONFIG_CMD_NET
#define CONFIG_CMD_NFS
#endif
#endif
#undef CONFIG_CMD_PING
#undef CONFIG_CMD_DHCP
#undef CONFIG_CMD_NET
#undef CONFIG_CMD_NFS
#define CONFIG_CMD_DATE
/*
* Miscellaneous configurable options

View File

@ -110,6 +110,19 @@
#define CONFIG_CMD_MII
#define CONFIG_CMD_NET
/* USB Configs */
#define CONFIG_CMD_USB
#define CONFIG_CMD_FAT
#define CONFIG_USB_EHCI
#define CONFIG_USB_EHCI_MX5
#define CONFIG_USB_STORAGE
#define CONFIG_USB_HOST_ETHER
#define CONFIG_USB_ETHER_ASIX
#define CONFIG_USB_ETHER_SMSC95XX
#define CONFIG_MXC_USB_PORT 1
#define CONFIG_MXC_USB_PORTSC PORT_PTS_ULPI
#define CONFIG_MXC_USB_FLAGS MXC_EHCI_POWER_PINS_ENABLED
/* allow to overwrite serial and ethaddr */
#define CONFIG_ENV_OVERWRITE
#define CONFIG_CONS_INDEX 1

View File

@ -72,6 +72,19 @@
#define CONFIG_CMD_MII
#define CONFIG_CMD_NET
/* USB Configs */
#define CONFIG_CMD_USB
#define CONFIG_CMD_FAT
#define CONFIG_USB_EHCI
#define CONFIG_USB_EHCI_MX5
#define CONFIG_USB_STORAGE
#define CONFIG_USB_HOST_ETHER
#define CONFIG_USB_ETHER_ASIX
#define CONFIG_USB_ETHER_SMSC95XX
#define CONFIG_MXC_USB_PORT 1
#define CONFIG_MXC_USB_PORTSC (PORT_PTS_UTMI | PORT_PTS_PTW)
#define CONFIG_MXC_USB_FLAGS 0
/* allow to overwrite serial and ethaddr */
#define CONFIG_ENV_OVERWRITE
#define CONFIG_CONS_INDEX 1

View File

@ -237,5 +237,8 @@
#define CONFIG_SYS_I2C_SPEED 50000
#define CONFIG_I2C_MULTI_BUS
#define CONFIG_SYS_MAX_I2C_BUS 7
#define CONFIG_USB_GADGET
#define CONFIG_USB_GADGET_S3C_UDC_OTG
#define CONFIG_USB_GADGET_DUALSPEED
#endif /* __CONFIG_H */

View File

@ -186,35 +186,36 @@ struct usb_ehci {
u32 gptimer1_ctrl; /* 0x08C - General Purpose Timer 1 control */
u32 sbuscfg; /* 0x090 - System Bus Interface Control */
u8 res2[0x6C];
u16 caplength; /* 0x100 - Capability Register Length */
u8 caplength; /* 0x100 - Capability Register Length */
u8 res3[0x1];
u16 hciversion; /* 0x102 - Host Interface Version */
u32 hcsparams; /* 0x104 - Host Structural Parameters */
u32 hccparams; /* 0x108 - Host Capability Parameters */
u8 res3[0x14];
u8 res4[0x14];
u32 dciversion; /* 0x120 - Device Interface Version */
u32 dciparams; /* 0x124 - Device Controller Params */
u8 res4[0x18];
u8 res5[0x18];
u32 usbcmd; /* 0x140 - USB Command */
u32 usbsts; /* 0x144 - USB Status */
u32 usbintr; /* 0x148 - USB Interrupt Enable */
u32 frindex; /* 0x14C - USB Frame Index */
u8 res5[0x4];
u8 res6[0x4];
u32 perlistbase; /* 0x154 - Periodic List Base
- USB Device Address */
u32 ep_list_addr; /* 0x158 - Next Asynchronous List
- End Point Address */
u8 res6[0x4];
u8 res7[0x4];
u32 burstsize; /* 0x160 - Programmable Burst Size */
#define FSL_EHCI_TXPBURST(X) ((X) << 8)
#define FSL_EHCI_RXPBURST(X) (X)
u32 txfilltuning; /* 0x164 - Host TT Transmit
pre-buffer packet tuning */
u8 res7[0x8];
u8 res8[0x8];
u32 ulpi_viewpoint; /* 0x170 - ULPI Reister Access */
u8 res8[0xc];
u8 res9[0xc];
u32 config_flag; /* 0x180 - Configured Flag Register */
u32 portsc; /* 0x184 - Port status/control */
u8 res9[0x1C];
u8 res10[0x1C];
u32 otgsc; /* 0x1a4 - Oo-The-Go status and control */
u32 usbmode; /* 0x1a8 - USB Device Mode */
u32 epsetupstat; /* 0x1ac - End Point Setup Status */
@ -228,18 +229,34 @@ struct usb_ehci {
u32 epctrl3; /* 0x1cc - End Point Control 3 */
u32 epctrl4; /* 0x1d0 - End Point Control 4 */
u32 epctrl5; /* 0x1d4 - End Point Control 5 */
u8 res10[0x28];
u8 res11[0x28];
u32 usbgenctrl; /* 0x200 - USB General Control */
u32 isiphyctrl; /* 0x204 - On-Chip PHY Control */
u8 res11[0x1F8];
u8 res12[0x1F8];
u32 snoop1; /* 0x400 - Snoop 1 */
u32 snoop2; /* 0x404 - Snoop 2 */
u32 age_cnt_limit; /* 0x408 - Age Count Threshold */
u32 prictrl; /* 0x40c - Priority Control */
u32 sictrl; /* 0x410 - System Interface Control */
u8 res12[0xEC];
u8 res13[0xEC];
u32 control; /* 0x500 - Control */
u8 res13[0xafc];
u8 res14[0xafc];
};
/*
* For MXC SOCs
*/
#define MXC_EHCI_POWER_PINS_ENABLED (1 << 5)
#define MXC_EHCI_TTL_ENABLED (1 << 6)
#define MXC_EHCI_INTERNAL_PHY (1 << 7)
/* Board-specific initialization */
int board_ehci_hcd_init(int port);
/* CPU-specific abstracted-out IOMUX init */
#ifdef CONFIG_MX51
void setup_iomux_usb_h1(void);
void setup_iomux_usb_h2(void);
#endif
#endif /* _EHCI_FSL_H */

View File

@ -0,0 +1,62 @@
/*
* Copyright (c) 2011 Samsung Electronics
* Lukasz Majewski <l.majewski@samsung.com>
*
* This is a Linux kernel compatibility layer for USB Gadget
*
* 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 __LIN_COMPAT_H__
#define __LIN_COMPAT_H__
/* common */
#define spin_lock_init(...)
#define spin_lock(...)
#define spin_lock_irqsave(lock, flags) do {flags = 1; } while (0)
#define spin_unlock(...)
#define spin_unlock_irqrestore(lock, flags) do {flags = 0; } while (0)
#define disable_irq(...)
#define enable_irq(...)
#define mutex_init(...)
#define mutex_lock(...)
#define mutex_unlock(...)
#define WARN_ON(x) if (x) {printf("WARNING in %s line %d\n" \
, __FILE__, __LINE__); }
#define KERN_WARNING
#define KERN_ERR
#define KERN_NOTICE
#define KERN_DEBUG
#define GFP_KERNEL 0
#define IRQ_HANDLED 1
#define ENOTSUPP 524 /* Operation is not supported */
#define kmalloc(size, type) memalign(CONFIG_SYS_CACHELINE_SIZE, size)
#define kfree(addr) free(addr)
#define mdelay(n) ({unsigned long msec = (n); while (msec--) udelay(1000); })
#define __iomem
#define min_t min
#define dma_cache_maint(addr, size, mode) cache_flush()
void cache_flush(void);
#endif /* __LIN_COMPAT_H__ */

151
include/usb/mv_udc.h Normal file
View File

@ -0,0 +1,151 @@
/*
* Copyright 2011, Marvell Semiconductor Inc.
* Lei Wen <leiwen@marvell.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#ifndef __MV_UDC_H__
#define __MV_UDC_H__
#include <asm/byteorder.h>
#include <asm/errno.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
/* Endpoint 0 states */
#define EP0_IDLE 0
#define EP0_IN_DATA 1
#define EP0_OUT_DATA 2
#define EP0_XFER_COMPLETE 3
/* Endpoint parameters */
#define MAX_ENDPOINTS 4
#define EP_MAX_PACKET_SIZE 0x200
#define EP0_MAX_PACKET_SIZE 64
#define UDC_OUT_ENDPOINT 0x02
#define UDC_OUT_PACKET_SIZE EP_MAX_PACKET_SIZE
#define UDC_IN_ENDPOINT 0x01
#define UDC_IN_PACKET_SIZE EP_MAX_PACKET_SIZE
#define UDC_INT_ENDPOINT 0x05
#define UDC_INT_PACKET_SIZE EP_MAX_PACKET_SIZE
#define UDC_BULK_PACKET_SIZE EP_MAX_PACKET_SIZE
#define NUM_ENDPOINTS 6
#define REQ_COUNT 12
struct mv_ep {
struct usb_ep ep;
struct usb_request req;
struct list_head queue;
const struct usb_endpoint_descriptor *desc;
};
struct mv_udc {
u32 pad0[80];
#define MICRO_8FRAME 0x8
#define USBCMD_ITC(x) (((x > 0xff) ? 0xff : x) << 16)
#define USBCMD_FS2 (1 << 15)
#define USBCMD_RST (1 << 1)
#define USBCMD_RUN (1)
u32 usbcmd; /* 0x140 */
#define STS_SLI (1 << 8)
#define STS_URI (1 << 6)
#define STS_PCI (1 << 2)
#define STS_UEI (1 << 1)
#define STS_UI (1 << 0)
u32 usbsts; /* 0x144 */
u32 pad1[3];
u32 devaddr; /* 0x154 */
u32 epinitaddr; /* 0x158 */
u32 pad2[10];
#define PTS_ENABLE 2
#define PTS(x) ((x & 0x3) << 30)
#define PFSC (1 << 24)
u32 portsc; /* 0x184 */
u32 pad3[8];
#define USBMODE_DEVICE 2
u32 usbmode; /* 0x1a8 */
u32 epstat; /* 0x1ac */
#define EPT_TX(x) (1 << ((x & 0xffff) + 16))
#define EPT_RX(x) (1 << (x & 0xffff))
u32 epprime; /* 0x1b0 */
u32 epflush; /* 0x1b4 */
u32 pad4;
u32 epcomp; /* 0x1bc */
#define CTRL_TXE (1 << 23)
#define CTRL_TXR (1 << 22)
#define CTRL_RXE (1 << 7)
#define CTRL_RXR (1 << 6)
#define CTRL_TXT_BULK (2 << 18)
#define CTRL_RXT_BULK (2 << 2)
u32 epctrl[16]; /* 0x1c0 */
};
struct mv_drv {
struct usb_gadget gadget;
struct usb_gadget_driver *driver;
struct mv_udc *udc;
};
struct ept_queue_head {
unsigned config;
unsigned current; /* read-only */
unsigned next;
unsigned info;
unsigned page0;
unsigned page1;
unsigned page2;
unsigned page3;
unsigned page4;
unsigned reserved_0;
unsigned char setup_data[8];
unsigned reserved_1;
unsigned reserved_2;
unsigned reserved_3;
unsigned reserved_4;
};
#define CONFIG_MAX_PKT(n) ((n) << 16)
#define CONFIG_ZLT (1 << 29) /* stop on zero-len xfer */
#define CONFIG_IOS (1 << 15) /* IRQ on setup */
struct ept_queue_item {
unsigned next;
unsigned info;
unsigned page0;
unsigned page1;
unsigned page2;
unsigned page3;
unsigned page4;
unsigned reserved;
};
#define TERMINATE 1
#define INFO_BYTES(n) ((n) << 16)
#define INFO_IOC (1 << 15)
#define INFO_ACTIVE (1 << 7)
#define INFO_HALTED (1 << 6)
#define INFO_BUFFER_ERROR (1 << 5)
#define INFO_TX_ERROR (1 << 3)
extern int usb_lowlevel_init(void);
#endif /* __MV_UDC_H__ */

175
include/usb/s3c_udc.h Normal file
View File

@ -0,0 +1,175 @@
/*
* drivers/usb/gadget/s3c_udc.h
* Samsung S3C on-chip full/high speed USB device controllers
* Copyright (C) 2005 for Samsung Electronics
*
* 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 __S3C_USB_GADGET
#define __S3C_USB_GADGET
#include <asm/errno.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/list.h>
#include <usb/lin_gadget_compat.h>
#define PHY0_SLEEP (1 << 5)
/*-------------------------------------------------------------------------*/
/* DMA bounce buffer size, 16K is enough even for mass storage */
#define DMA_BUFFER_SIZE (4096*4)
#define EP0_FIFO_SIZE 64
#define EP_FIFO_SIZE 512
#define EP_FIFO_SIZE2 1024
/* ep0-control, ep1in-bulk, ep2out-bulk, ep3in-int */
#define S3C_MAX_ENDPOINTS 4
#define S3C_MAX_HW_ENDPOINTS 16
#define WAIT_FOR_SETUP 0
#define DATA_STATE_XMIT 1
#define DATA_STATE_NEED_ZLP 2
#define WAIT_FOR_OUT_STATUS 3
#define DATA_STATE_RECV 4
#define WAIT_FOR_COMPLETE 5
#define WAIT_FOR_OUT_COMPLETE 6
#define WAIT_FOR_IN_COMPLETE 7
#define WAIT_FOR_NULL_COMPLETE 8
#define TEST_J_SEL 0x1
#define TEST_K_SEL 0x2
#define TEST_SE0_NAK_SEL 0x3
#define TEST_PACKET_SEL 0x4
#define TEST_FORCE_ENABLE_SEL 0x5
/* ************************************************************************* */
/* IO
*/
enum ep_type {
ep_control, ep_bulk_in, ep_bulk_out, ep_interrupt
};
struct s3c_ep {
struct usb_ep ep;
struct s3c_udc *dev;
const struct usb_endpoint_descriptor *desc;
struct list_head queue;
unsigned long pio_irqs;
int len;
void *dma_buf;
u8 stopped;
u8 bEndpointAddress;
u8 bmAttributes;
enum ep_type ep_type;
int fifo_num;
};
struct s3c_request {
struct usb_request req;
struct list_head queue;
};
struct s3c_udc {
struct usb_gadget gadget;
struct usb_gadget_driver *driver;
struct s3c_plat_otg_data *pdata;
void *dma_buf[S3C_MAX_ENDPOINTS+1];
dma_addr_t dma_addr[S3C_MAX_ENDPOINTS+1];
int ep0state;
struct s3c_ep ep[S3C_MAX_ENDPOINTS];
unsigned char usb_address;
unsigned req_pending:1, req_std:1, req_config:1;
};
extern struct s3c_udc *the_controller;
#define ep_is_in(EP) (((EP)->bEndpointAddress&USB_DIR_IN) == USB_DIR_IN)
#define ep_index(EP) ((EP)->bEndpointAddress&0xF)
#define ep_maxpacket(EP) ((EP)->ep.maxpacket)
/*-------------------------------------------------------------------------*/
/* #define DEBUG_UDC */
#ifdef DEBUG_UDC
#define DBG(stuff...) printf("udc: " stuff)
#else
#define DBG(stuff...) do {} while (0)
#endif
#ifdef DEBUG_S3C_UDC_SETUP
#define DEBUG_SETUP(fmt, args...) printk(fmt, ##args)
#else
#define DEBUG_SETUP(fmt, args...) do {} while (0)
#endif
#ifdef DEBUG_S3C_UDC_EP0
#define DEBUG_EP0(fmt, args...) printk(fmt, ##args)
#else
#define DEBUG_EP0(fmt, args...) do {} while (0)
#endif
#ifdef DEBUG_S3C_UDC
#define DEBUG(fmt, args...) printk(fmt, ##args)
#else
#define DEBUG(fmt, args...) do {} while (0)
#endif
#ifdef DEBUG_S3C_UDC_ISR
#define DEBUG_ISR(fmt, args...) printk(fmt, ##args)
#else
#define DEBUG_ISR(fmt, args...) do {} while (0)
#endif
#ifdef DEBUG_S3C_UDC_OUT_EP
#define DEBUG_OUT_EP(fmt, args...) printk(fmt, ##args)
#else
#define DEBUG_OUT_EP(fmt, args...) do {} while (0)
#endif
#ifdef DEBUG_S3C_UDC_IN_EP
#define DEBUG_IN_EP(fmt, args...) printk(fmt, ##args)
#else
#define DEBUG_IN_EP(fmt, args...) do {} while (0)
#endif
#define ERR(stuff...) printf("ERR udc: " stuff)
#define WARN(stuff...) printf("WARNING udc: " stuff)
#define INFO(stuff...) printf("INFO udc: " stuff)
extern void otg_phy_init(struct s3c_udc *dev);
extern void otg_phy_off(struct s3c_udc *dev);
extern void s3c_udc_ep_set_stall(struct s3c_ep *ep);
extern int s3c_udc_probe(struct s3c_plat_otg_data *pdata);
struct s3c_plat_otg_data {
int (*phy_control)(int on);
unsigned int regs_phy;
unsigned int regs_otg;
unsigned int usb_phy_ctrl;
unsigned int usb_flags;
};
#endif

298
include/usb/ulpi.h Normal file
View File

@ -0,0 +1,298 @@
/*
* Generic ULPI interface.
*
* Copyright (C) 2011 Jana Rapava <fermata7@gmail.com>
* Copyright (C) 2011 CompuLab, Ltd. <www.compulab.co.il>
*
* Authors: Jana Rapava <fermata7@gmail.com>
* Igor Grinberg <grinberg@compulab.co.il>
*
* Register offsets taken from:
* linux/include/linux/usb/ulpi.h
*
* Original Copyrights follow:
* Copyright (C) 2010 Nokia Corporation
*
* This software is distributed under the terms of the GNU General
* Public License ("GPL") as published by the Free Software Foundation,
* version 2 of that License.
*/
#ifndef __USB_ULPI_H__
#define __USB_ULPI_H__
#define ULPI_ERROR (1 << 8) /* overflow from any register value */
#ifndef CONFIG_USB_ULPI_TIMEOUT
#define CONFIG_USB_ULPI_TIMEOUT 1000 /* timeout in us */
#endif
/*
* Initialize the ULPI transciever and check the interface integrity.
* @ulpi_viewport - the address of the ULPI viewport register.
*
* returns 0 on success, ULPI_ERROR on failure.
*/
int ulpi_init(u32 ulpi_viewport);
/*
* Select transceiver speed.
* @speed - ULPI_FC_HIGH_SPEED, ULPI_FC_FULL_SPEED (default),
* ULPI_FC_LOW_SPEED, ULPI_FC_FS4LS
* returns 0 on success, ULPI_ERROR on failure.
*/
int ulpi_select_transceiver(u32 ulpi_viewport, u8 speed);
/*
* Enable/disable VBUS.
* @ext_power - external VBUS supply is used (default is false)
* @ext_indicator - external VBUS over-current indicator is used
*
* returns 0 on success, ULPI_ERROR on failure.
*/
int ulpi_enable_vbus(u32 ulpi_viewport, int on, int ext_power, int ext_ind);
/*
* Enable/disable pull-down resistors on D+ and D- USB lines.
*
* returns 0 on success, ULPI_ERROR on failure.
*/
int ulpi_set_pd(u32 ulpi_viewport, int enable);
/*
* Select OpMode.
* @opmode - ULPI_FC_OPMODE_NORMAL (default), ULPI_FC_OPMODE_NONDRIVING,
* ULPI_FC_OPMODE_DISABLE_NRZI, ULPI_FC_OPMODE_NOSYNC_NOEOP
*
* returns 0 on success, ULPI_ERROR on failure.
*/
int ulpi_opmode_sel(u32 ulpi_viewport, u8 opmode);
/*
* Switch to Serial Mode.
* @smode - ULPI_IFACE_6_PIN_SERIAL_MODE or ULPI_IFACE_3_PIN_SERIAL_MODE
*
* returns 0 on success, ULPI_ERROR on failure.
*
* Notes:
* Switches immediately to Serial Mode.
* To return from Serial Mode, STP line needs to be asserted.
*/
int ulpi_serial_mode_enable(u32 ulpi_viewport, u8 smode);
/*
* Put PHY into low power mode.
*
* returns 0 on success, ULPI_ERROR on failure.
*
* Notes:
* STP line must be driven low to keep the PHY in suspend.
* To resume the PHY, STP line needs to be asserted.
*/
int ulpi_suspend(u32 ulpi_viewport);
/*
* Reset the transceiver. ULPI interface and registers are not affected.
*
* returns 0 on success, ULPI_ERROR on failure.
*/
int ulpi_reset(u32 ulpi_viewport);
/* ULPI access methods below must be implemented for each ULPI viewport. */
/*
* Write to the ULPI PHY register via the viewport.
* @reg - the ULPI register (one of the fields in struct ulpi_regs).
* @value - the value - only 8 lower bits are used, others ignored.
*
* returns 0 on success, ULPI_ERROR on failure.
*/
u32 ulpi_write(u32 ulpi_viewport, u8 *reg, u32 value);
/*
* Read the ULPI PHY register content via the viewport.
* @reg - the ULPI register (one of the fields in struct ulpi_regs).
*
* returns register content on success, ULPI_ERROR on failure.
*/
u32 ulpi_read(u32 ulpi_viewport, u8 *reg);
/*
* Wait for the reset to complete.
* The Link must not attempt to access the PHY until the reset has
* completed and DIR line is de-asserted.
*/
int ulpi_reset_wait(u32 ulpi_viewport);
/* Access Extended Register Set (indicator) */
#define ACCESS_EXT_REGS_OFFSET 0x2f /* read-write */
/* Vendor-specific */
#define VENDOR_SPEC_OFFSET 0x30
/*
* Extended Register Set
*
* Addresses 0x00-0x3F map directly to Immediate Register Set.
* Addresses 0x40-0x7F are reserved.
* Addresses 0x80-0xff are vendor-specific.
*/
#define EXT_VENDOR_SPEC_OFFSET 0x80
/* ULPI registers, bits and offsets definitions */
struct ulpi_regs {
/* Vendor ID and Product ID: 0x00 - 0x03 Read-only */
u8 vendor_id_low;
u8 vendor_id_high;
u8 product_id_low;
u8 product_id_high;
/* Function Control: 0x04 - 0x06 Read */
u8 function_ctrl; /* 0x04 Write */
u8 function_ctrl_set; /* 0x05 Set */
u8 function_ctrl_clear; /* 0x06 Clear */
/* Interface Control: 0x07 - 0x09 Read */
u8 iface_ctrl; /* 0x07 Write */
u8 iface_ctrl_set; /* 0x08 Set */
u8 iface_ctrl_clear; /* 0x09 Clear */
/* OTG Control: 0x0A - 0x0C Read */
u8 otg_ctrl; /* 0x0A Write */
u8 otg_ctrl_set; /* 0x0B Set */
u8 otg_ctrl_clear; /* 0x0C Clear */
/* USB Interrupt Enable Rising: 0x0D - 0x0F Read */
u8 usb_ie_rising; /* 0x0D Write */
u8 usb_ie_rising_set; /* 0x0E Set */
u8 usb_ie_rising_clear; /* 0x0F Clear */
/* USB Interrupt Enable Falling: 0x10 - 0x12 Read */
u8 usb_ie_falling; /* 0x10 Write */
u8 usb_ie_falling_set; /* 0x11 Set */
u8 usb_ie_falling_clear; /* 0x12 Clear */
/* USB Interrupt Status: 0x13 Read-only */
u8 usb_int_status;
/* USB Interrupt Latch: 0x14 Read-only with auto-clear */
u8 usb_int_latch;
/* Debug: 0x15 Read-only */
u8 debug;
/* Scratch Register: 0x16 - 0x18 Read */
u8 scratch; /* 0x16 Write */
u8 scratch_set; /* 0x17 Set */
u8 scratch_clear; /* 0x18 Clear */
/*
* Optional Carkit registers:
* Carkit Control: 0x19 - 0x1B Read
*/
u8 carkit_ctrl; /* 0x19 Write */
u8 carkit_ctrl_set; /* 0x1A Set */
u8 carkit_ctrl_clear; /* 0x1B Clear */
/* Carkit Interrupt Delay: 0x1C Read, Write */
u8 carkit_int_delay;
/* Carkit Interrupt Enable: 0x1D - 0x1F Read */
u8 carkit_ie; /* 0x1D Write */
u8 carkit_ie_set; /* 0x1E Set */
u8 carkit_ie_clear; /* 0x1F Clear */
/* Carkit Interrupt Status: 0x20 Read-only */
u8 carkit_int_status;
/* Carkit Interrupt Latch: 0x21 Read-only with auto-clear */
u8 carkit_int_latch;
/* Carkit Pulse Control: 0x22 - 0x24 Read */
u8 carkit_pulse_ctrl; /* 0x22 Write */
u8 carkit_pulse_ctrl_set; /* 0x23 Set */
u8 carkit_pulse_ctrl_clear; /* 0x24 Clear */
/*
* Other optional registers:
* Transmit Positive Width: 0x25 Read, Write
*/
u8 transmit_pos_width;
/* Transmit Negative Width: 0x26 Read, Write */
u8 transmit_neg_width;
/* Receive Polarity Recovery: 0x27 Read, Write */
u8 recv_pol_recovery;
/*
* Addresses 0x28 - 0x2E are reserved, so we use offsets
* for immediate registers with higher addresses
*/
};
/*
* Register Bits
*/
/* Function Control */
#define ULPI_FC_XCVRSEL_MASK (3 << 0)
#define ULPI_FC_HIGH_SPEED (0 << 0)
#define ULPI_FC_FULL_SPEED (1 << 0)
#define ULPI_FC_LOW_SPEED (2 << 0)
#define ULPI_FC_FS4LS (3 << 0)
#define ULPI_FC_TERMSELECT (1 << 2)
#define ULPI_FC_OPMODE_MASK (3 << 3)
#define ULPI_FC_OPMODE_NORMAL (0 << 3)
#define ULPI_FC_OPMODE_NONDRIVING (1 << 3)
#define ULPI_FC_OPMODE_DISABLE_NRZI (2 << 3)
#define ULPI_FC_OPMODE_NOSYNC_NOEOP (3 << 3)
#define ULPI_FC_RESET (1 << 5)
#define ULPI_FC_SUSPENDM (1 << 6)
/* Interface Control */
#define ULPI_IFACE_6_PIN_SERIAL_MODE (1 << 0)
#define ULPI_IFACE_3_PIN_SERIAL_MODE (1 << 1)
#define ULPI_IFACE_CARKITMODE (1 << 2)
#define ULPI_IFACE_CLOCKSUSPENDM (1 << 3)
#define ULPI_IFACE_AUTORESUME (1 << 4)
#define ULPI_IFACE_EXTVBUS_COMPLEMENT (1 << 5)
#define ULPI_IFACE_PASSTHRU (1 << 6)
#define ULPI_IFACE_PROTECT_IFC_DISABLE (1 << 7)
/* OTG Control */
#define ULPI_OTG_ID_PULLUP (1 << 0)
#define ULPI_OTG_DP_PULLDOWN (1 << 1)
#define ULPI_OTG_DM_PULLDOWN (1 << 2)
#define ULPI_OTG_DISCHRGVBUS (1 << 3)
#define ULPI_OTG_CHRGVBUS (1 << 4)
#define ULPI_OTG_DRVVBUS (1 << 5)
#define ULPI_OTG_DRVVBUS_EXT (1 << 6)
#define ULPI_OTG_EXTVBUSIND (1 << 7)
/*
* USB Interrupt Enable Rising,
* USB Interrupt Enable Falling,
* USB Interrupt Status and
* USB Interrupt Latch
*/
#define ULPI_INT_HOST_DISCONNECT (1 << 0)
#define ULPI_INT_VBUS_VALID (1 << 1)
#define ULPI_INT_SESS_VALID (1 << 2)
#define ULPI_INT_SESS_END (1 << 3)
#define ULPI_INT_IDGRD (1 << 4)
/* Debug */
#define ULPI_DEBUG_LINESTATE0 (1 << 0)
#define ULPI_DEBUG_LINESTATE1 (1 << 1)
/* Carkit Control */
#define ULPI_CARKIT_CTRL_CARKITPWR (1 << 0)
#define ULPI_CARKIT_CTRL_IDGNDDRV (1 << 1)
#define ULPI_CARKIT_CTRL_TXDEN (1 << 2)
#define ULPI_CARKIT_CTRL_RXDEN (1 << 3)
#define ULPI_CARKIT_CTRL_SPKLEFTEN (1 << 4)
#define ULPI_CARKIT_CTRL_SPKRIGHTEN (1 << 5)
#define ULPI_CARKIT_CTRL_MICEN (1 << 6)
/* Carkit Interrupt Enable */
#define ULPI_CARKIT_INT_EN_IDFLOAT_RISE (1 << 0)
#define ULPI_CARKIT_INT_EN_IDFLOAT_FALL (1 << 1)
#define ULPI_CARKIT_INT_EN_CARINTDET (1 << 2)
#define ULPI_CARKIT_INT_EN_DP_RISE (1 << 3)
#define ULPI_CARKIT_INT_EN_DP_FALL (1 << 4)
/* Carkit Interrupt Status and Latch */
#define ULPI_CARKIT_INT_IDFLOAT (1 << 0)
#define ULPI_CARKIT_INT_CARINTDET (1 << 1)
#define ULPI_CARKIT_INT_DP (1 << 2)
/* Carkit Pulse Control*/
#define ULPI_CARKIT_PLS_CTRL_TXPLSEN (1 << 0)
#define ULPI_CARKIT_PLS_CTRL_RXPLSEN (1 << 1)
#define ULPI_CARKIT_PLS_CTRL_SPKRLEFT_BIASEN (1 << 2)
#define ULPI_CARKIT_PLS_CTRL_SPKRRIGHT_BIASEN (1 << 3)
#endif /* __USB_ULPI_H__ */

View File

@ -199,7 +199,7 @@ struct usb_endpoint_descriptor {
u8 bmAttributes;
u16 wMaxPacketSize;
u8 bInterval;
} __attribute__ ((packed));
} __attribute__ ((packed)) __attribute__ ((aligned(2)));
struct usb_interface_descriptor {
u8 bLength;