mirror of
https://github.com/Fishwaldo/u-boot.git
synced 2025-03-18 21:21:37 +00:00
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:
commit
b2eb7d9bc6
40 changed files with 5594 additions and 841 deletions
1
Makefile
1
Makefile
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
210
board/efikamx/efikamx-usb.c
Normal 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);
|
||||
}
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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*/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
1092
common/usb_kbd.c
1092
common/usb_kbd.c
File diff suppressed because it is too large
Load diff
|
@ -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));
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
499
drivers/usb/gadget/mv_udc.c
Normal 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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
271
drivers/usb/gadget/regs-otg.h
Normal file
271
drivers/usb/gadget/regs-otg.h
Normal 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
|
892
drivers/usb/gadget/s3c_udc_otg.c
Normal file
892
drivers/usb/gadget/s3c_udc_otg.c
Normal 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(®->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, ®->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**/
|
||||
®->gusbcfg);
|
||||
|
||||
/* 3. Put the OTG device core in the disconnected state.*/
|
||||
uTemp = readl(®->dctl);
|
||||
uTemp |= SOFT_DISCONNECT;
|
||||
writel(uTemp, ®->dctl);
|
||||
|
||||
udelay(20);
|
||||
|
||||
/* 4. Make the OTG device core exit from the disconnected state.*/
|
||||
uTemp = readl(®->dctl);
|
||||
uTemp = uTemp & ~SOFT_DISCONNECT;
|
||||
writel(uTemp, ®->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, ®->dcfg);
|
||||
|
||||
mdelay(1);
|
||||
|
||||
/* 6. Unmask the core interrupts*/
|
||||
writel(GINTMSK_INIT, ®->gintmsk);
|
||||
|
||||
/* 7. Set NAK bit of EP0, EP1, EP2*/
|
||||
writel(DEPCTL_EPDIS|DEPCTL_SNAK, ®->out_endp[EP0_CON].doepctl);
|
||||
writel(DEPCTL_EPDIS|DEPCTL_SNAK, ®->in_endp[EP0_CON].diepctl);
|
||||
|
||||
for (i = 1; i < S3C_MAX_ENDPOINTS; i++) {
|
||||
writel(DEPCTL_EPDIS|DEPCTL_SNAK, ®->out_endp[i].doepctl);
|
||||
writel(DEPCTL_EPDIS|DEPCTL_SNAK, ®->in_endp[i].diepctl);
|
||||
}
|
||||
|
||||
/* 8. Unmask EPO interrupts*/
|
||||
writel(((1 << EP0_CON) << DAINT_OUT_BIT)
|
||||
| (1 << EP0_CON), ®->daintmsk);
|
||||
|
||||
/* 9. Unmask device OUT EP common interrupts*/
|
||||
writel(DOEPMSK_INIT, ®->doepmsk);
|
||||
|
||||
/* 10. Unmask device IN EP common interrupts*/
|
||||
writel(DIEPMSK_INIT, ®->diepmsk);
|
||||
|
||||
/* 11. Set Rx FIFO Size (in 32-bit words) */
|
||||
writel(RX_FIFO_SIZE >> 2, ®->grxfsiz);
|
||||
|
||||
/* 12. Set Non Periodic Tx FIFO Size */
|
||||
writel((NPTX_FIFO_SIZE >> 2) << 16 | ((RX_FIFO_SIZE >> 2)) << 0,
|
||||
®->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,
|
||||
®->dieptxf[i-1]);
|
||||
|
||||
/* Flush the RX FIFO */
|
||||
writel(RX_FIFO_FLUSH, ®->grstctl);
|
||||
while (readl(®->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, ®->grstctl);
|
||||
writel(TX_FIFO_FLUSH_ALL | TX_FIFO_FLUSH, ®->grstctl);
|
||||
while (readl(®->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,
|
||||
®->out_endp[EP0_CON].doepctl);
|
||||
|
||||
/* 14. Initialize OTG Link Core.*/
|
||||
writel(GAHBCFG_INIT, ®->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(®->in_endp[EP0_CON].diepctl);
|
||||
writel(ep_ctrl|(0<<0), ®->in_endp[EP0_CON].diepctl);
|
||||
|
||||
/* EP0 - Control OUT (64 bytes)*/
|
||||
ep_ctrl = readl(®->out_endp[EP0_CON].doepctl);
|
||||
writel(ep_ctrl|(0<<0), ®->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(®->gintsts);
|
||||
u32 gintmsk = readl(®->gintmsk);
|
||||
|
||||
if (intr_status & gintmsk)
|
||||
return s3c_udc_irq(1, (void *)the_controller);
|
||||
return 0;
|
||||
}
|
1444
drivers/usb/gadget/s3c_udc_otg_xfer_dma.c
Normal file
1444
drivers/usb/gadget/s3c_udc_otg_xfer_dma.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -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
|
||||
|
|
|
@ -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, ®);
|
||||
|
||||
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
255
drivers/usb/host/ehci-mx5.c
Normal 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;
|
||||
}
|
||||
|
||||
|
|
@ -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
44
drivers/usb/ulpi/Makefile
Normal 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
|
||||
|
||||
#########################################################################
|
118
drivers/usb/ulpi/ulpi-viewport.c
Normal file
118
drivers/usb/ulpi/ulpi-viewport.c
Normal 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
227
drivers/usb/ulpi/ulpi.c
Normal 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);
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
62
include/usb/lin_gadget_compat.h
Normal file
62
include/usb/lin_gadget_compat.h
Normal 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
151
include/usb/mv_udc.h
Normal 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
175
include/usb/s3c_udc.h
Normal 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
298
include/usb/ulpi.h
Normal 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__ */
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue