diff options
Diffstat (limited to 'roms/u-boot/drivers/usb/musb')
| -rw-r--r-- | roms/u-boot/drivers/usb/musb/Makefile | 14 | ||||
| -rw-r--r-- | roms/u-boot/drivers/usb/musb/am35x.c | 139 | ||||
| -rw-r--r-- | roms/u-boot/drivers/usb/musb/am35x.h | 82 | ||||
| -rw-r--r-- | roms/u-boot/drivers/usb/musb/blackfin_usb.c | 172 | ||||
| -rw-r--r-- | roms/u-boot/drivers/usb/musb/blackfin_usb.h | 99 | ||||
| -rw-r--r-- | roms/u-boot/drivers/usb/musb/da8xx.c | 128 | ||||
| -rw-r--r-- | roms/u-boot/drivers/usb/musb/davinci.c | 124 | ||||
| -rw-r--r-- | roms/u-boot/drivers/usb/musb/davinci.h | 74 | ||||
| -rw-r--r-- | roms/u-boot/drivers/usb/musb/musb_core.c | 155 | ||||
| -rw-r--r-- | roms/u-boot/drivers/usb/musb/musb_core.h | 395 | ||||
| -rw-r--r-- | roms/u-boot/drivers/usb/musb/musb_debug.h | 192 | ||||
| -rw-r--r-- | roms/u-boot/drivers/usb/musb/musb_hcd.c | 1172 | ||||
| -rw-r--r-- | roms/u-boot/drivers/usb/musb/musb_hcd.h | 99 | ||||
| -rw-r--r-- | roms/u-boot/drivers/usb/musb/musb_udc.c | 959 | ||||
| -rw-r--r-- | roms/u-boot/drivers/usb/musb/omap3.c | 145 | ||||
| -rw-r--r-- | roms/u-boot/drivers/usb/musb/omap3.h | 39 | 
16 files changed, 3988 insertions, 0 deletions
| diff --git a/roms/u-boot/drivers/usb/musb/Makefile b/roms/u-boot/drivers/usb/musb/Makefile new file mode 100644 index 00000000..3c9ed98b --- /dev/null +++ b/roms/u-boot/drivers/usb/musb/Makefile @@ -0,0 +1,14 @@ +# +# (C) Copyright 2000-2007 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier:	GPL-2.0+ +# + +obj-$(CONFIG_MUSB_HCD) += musb_hcd.o musb_core.o +obj-$(CONFIG_MUSB_UDC) += musb_udc.o musb_core.o +obj-$(CONFIG_USB_BLACKFIN) += blackfin_usb.o +obj-$(CONFIG_USB_DAVINCI) += davinci.o +obj-$(CONFIG_USB_OMAP3) += omap3.o +obj-$(CONFIG_USB_DA8XX) += da8xx.o +obj-$(CONFIG_USB_AM35X) += am35x.o diff --git a/roms/u-boot/drivers/usb/musb/am35x.c b/roms/u-boot/drivers/usb/musb/am35x.c new file mode 100644 index 00000000..62c3a6f6 --- /dev/null +++ b/roms/u-boot/drivers/usb/musb/am35x.c @@ -0,0 +1,139 @@ +/* + * am35x.c - TI's AM35x platform specific usb wrapper functions. + * + * Author: Ajay Kumar Gupta <ajay.gupta@ti.com> + * + * Based on drivers/usb/musb/da8xx.c + * + * Copyright (c) 2010 Texas Instruments Incorporated + * + * SPDX-License-Identifier:	GPL-2.0+ + */ + +#include <common.h> + +#include "am35x.h" + +/* MUSB platform configuration */ +struct musb_config musb_cfg = { +	.regs		= (struct musb_regs *)AM35X_USB_OTG_CORE_BASE, +	.timeout	= AM35X_USB_OTG_TIMEOUT, +	.musb_speed	= 0, +}; + +/* + * Enable the USB phy + */ +static u8 phy_on(void) +{ +	u32 devconf2; +	u32 timeout; + +	devconf2 = readl(&am35x_scm_general_regs->devconf2); + +	devconf2 &= ~(DEVCONF2_RESET | DEVCONF2_PHYPWRDN | DEVCONF2_OTGPWRDN | +		      DEVCONF2_OTGMODE | DEVCONF2_REFFREQ | +		      DEVCONF2_PHY_GPIOMODE); +	devconf2 |= DEVCONF2_SESENDEN | DEVCONF2_VBDTCTEN | DEVCONF2_PHY_PLLON | +		    DEVCONF2_REFFREQ_13MHZ | DEVCONF2_DATPOL; + +	writel(devconf2, &am35x_scm_general_regs->devconf2); + +	/* wait until the USB phy is turned on */ +	timeout = musb_cfg.timeout; +	while (timeout--) +		if (readl(&am35x_scm_general_regs->devconf2) & DEVCONF2_PHYCKGD) +			return 1; + +	/* USB phy was not turned on */ +	return 0; +} + +/* + * Disable the USB phy + */ +static void phy_off(void) +{ +	u32 devconf2; + +	/* +	 * Power down the on-chip PHY. +	 */ +	devconf2 = readl(&am35x_scm_general_regs->devconf2); + +	devconf2 &= ~DEVCONF2_PHY_PLLON; +	devconf2 |= DEVCONF2_PHYPWRDN | DEVCONF2_OTGPWRDN; +	writel(devconf2, &am35x_scm_general_regs->devconf2); +} + +/* + * This function performs platform specific initialization for usb0. + */ +int musb_platform_init(void) +{ +	u32 revision; +	u32 sw_reset; + +	/* global usb reset */ +	sw_reset = readl(&am35x_scm_general_regs->ip_sw_reset); +	sw_reset |= (1 << 0); +	writel(sw_reset, &am35x_scm_general_regs->ip_sw_reset); +	sw_reset &= ~(1 << 0); +	writel(sw_reset, &am35x_scm_general_regs->ip_sw_reset); + +	/* reset the controller */ +	writel(0x1, &am35x_usb_regs->control); +	udelay(5000); + +	/* start the on-chip usb phy and its pll */ +	if (phy_on() == 0) +		return -1; + +	/* Returns zero if e.g. not clocked */ +	revision = readl(&am35x_usb_regs->revision); +	if (revision == 0) +		return -1; + +	return 0; +} + +/* + * This function performs platform specific deinitialization for usb0. + */ +void musb_platform_deinit(void) +{ +	/* Turn off the phy */ +	phy_off(); +} + +/* + * This function reads data from endpoint fifo for AM35x + * which supports only 32bit read operation. + * + * ep           - endpoint number + * length       - number of bytes to read from FIFO + * fifo_data    - pointer to data buffer into which data is read + */ +__attribute__((weak)) +void read_fifo(u8 ep, u32 length, void *fifo_data) +{ +	u8  *data = (u8 *)fifo_data; +	u32 val; +	int i; + +	/* select the endpoint index */ +	writeb(ep, &musbr->index); + +	if (length > 4) { +		for (i = 0; i < (length >> 2); i++) { +			val = readl(&musbr->fifox[ep]); +			memcpy(data, &val, 4); +			data += 4; +		} +		length %= 4; +	} +	if (length > 0) { +		val = readl(&musbr->fifox[ep]); +		memcpy(data, &val, length); +	} +} diff --git a/roms/u-boot/drivers/usb/musb/am35x.h b/roms/u-boot/drivers/usb/musb/am35x.h new file mode 100644 index 00000000..bebe38d2 --- /dev/null +++ b/roms/u-boot/drivers/usb/musb/am35x.h @@ -0,0 +1,82 @@ +/* + * am35x.h - TI's AM35x platform specific usb wrapper definitions. + * + * Author: Ajay Kumar Gupta <ajay.gupta@ti.com> + * + * Based on drivers/usb/musb/da8xx.h + * + * Copyright (c) 2010 Texas Instruments Incorporated + * + * SPDX-License-Identifier:	GPL-2.0+ + */ + +#ifndef __AM35X_USB_H__ +#define __AM35X_USB_H__ + +#include <asm/arch/am35x_def.h> +#include "musb_core.h" + +/* Base address of musb wrapper */ +#define AM35X_USB_OTG_BASE	0x5C040000 + +/* Base address of musb core */ +#define AM35X_USB_OTG_CORE_BASE	(AM35X_USB_OTG_BASE + 0x400) + +/* Timeout for AM35x usb module */ +#define AM35X_USB_OTG_TIMEOUT	0x3FFFFFF + +/* + * AM35x platform USB wrapper register overlay. + */ +struct am35x_usb_regs { +	u32	revision; +	u32	control; +	u32	status; +	u32	emulation; +	u32	reserved0[1]; +	u32	autoreq; +	u32	srpfixtime; +	u32	ep_intsrc; +	u32	ep_intsrcset; +	u32	ep_intsrcclr; +	u32	ep_intmsk; +	u32	ep_intmskset; +	u32	ep_intmskclr; +	u32	ep_intsrcmsked; +	u32	reserved1[1]; +	u32	core_intsrc; +	u32	core_intsrcset; +	u32	core_intsrcclr; +	u32	core_intmsk; +	u32	core_intmskset; +	u32	core_intmskclr; +	u32	core_intsrcmsked; +	u32	reserved2[1]; +	u32	eoi; +	u32	mop_sop_en; +	u32	reserved3[2]; +	u32	txmode; +	u32	rxmode; +	u32	epcount_mode; +}; + +#define am35x_usb_regs ((struct am35x_usb_regs *)AM35X_USB_OTG_BASE) + +/* USB 2.0 PHY Control */ +#define DEVCONF2_PHY_GPIOMODE	(1 << 23) +#define DEVCONF2_OTGMODE	(3 << 14) +#define DEVCONF2_SESENDEN	(1 << 13)       /* Vsess_end comparator */ +#define DEVCONF2_VBDTCTEN	(1 << 12)       /* Vbus comparator */ +#define DEVCONF2_REFFREQ_24MHZ	(2 << 8) +#define DEVCONF2_REFFREQ_26MHZ	(7 << 8) +#define DEVCONF2_REFFREQ_13MHZ	(6 << 8) +#define DEVCONF2_REFFREQ	(0xf << 8) +#define DEVCONF2_PHYCKGD	(1 << 7) +#define DEVCONF2_VBUSSENSE	(1 << 6) +#define DEVCONF2_PHY_PLLON	(1 << 5)        /* override PLL suspend */ +#define DEVCONF2_RESET		(1 << 4) +#define DEVCONF2_PHYPWRDN	(1 << 3) +#define DEVCONF2_OTGPWRDN	(1 << 2) +#define DEVCONF2_DATPOL		(1 << 1) + +#endif	/* __AM35X_USB_H__ */ diff --git a/roms/u-boot/drivers/usb/musb/blackfin_usb.c b/roms/u-boot/drivers/usb/musb/blackfin_usb.c new file mode 100644 index 00000000..65fff887 --- /dev/null +++ b/roms/u-boot/drivers/usb/musb/blackfin_usb.c @@ -0,0 +1,172 @@ +/* + * Blackfin MUSB HCD (Host Controller Driver) for u-boot + * + * Copyright (c) 2008-2009 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include <common.h> + +#include <usb.h> + +#include <asm/blackfin.h> +#include <asm/clock.h> +#include <asm/mach-common/bits/usb.h> + +#include "musb_core.h" + +#ifndef CONFIG_USB_BLACKFIN_CLKIN +#define CONFIG_USB_BLACKFIN_CLKIN 24 +#endif + +/* MUSB platform configuration */ +struct musb_config musb_cfg = { +	.regs       = (struct musb_regs *)USB_FADDR, +	.timeout    = 0x3FFFFFF, +	.musb_speed = 0, +}; + +/* + * This function read or write data to endpoint fifo + * Blackfin use DMA polling method to avoid buffer alignment issues + * + * ep		- Endpoint number + * length	- Number of bytes to write to FIFO + * fifo_data	- Pointer to data buffer to be read/write + * is_write	- Flag for read or write + */ +void rw_fifo(u8 ep, u32 length, void *fifo_data, int is_write) +{ +	struct bfin_musb_dma_regs *regs; +	u32 val = (u32)fifo_data; + +	blackfin_dcache_flush_invalidate_range(fifo_data, fifo_data + length); + +	regs = (void *)USB_DMA_INTERRUPT; +	regs += ep; + +	/* Setup DMA address register */ +	bfin_write16(®s->addr_low, val); +	SSYNC(); + +	bfin_write16(®s->addr_high, val >> 16); +	SSYNC(); + +	/* Setup DMA count register */ +	bfin_write16(®s->count_low, length); +	bfin_write16(®s->count_high, 0); +	SSYNC(); + +	/* Enable the DMA */ +	val = (ep << 4) | DMA_ENA | INT_ENA; +	if (is_write) +		val |= DIRECTION; +	bfin_write16(®s->control, val); +	SSYNC(); + +	/* Wait for compelete */ +	while (!(bfin_read_USB_DMA_INTERRUPT() & (1 << ep))) +		continue; + +	/* acknowledge dma interrupt */ +	bfin_write_USB_DMA_INTERRUPT(1 << ep); +	SSYNC(); + +	/* Reset DMA */ +	bfin_write16(®s->control, 0); +	SSYNC(); +} + +void write_fifo(u8 ep, u32 length, void *fifo_data) +{ +	rw_fifo(ep, length, fifo_data, 1); +} + +void read_fifo(u8 ep, u32 length, void *fifo_data) +{ +	rw_fifo(ep, length, fifo_data, 0); +} + + +/* + * CPU and board-specific MUSB initializations.  Aliased function + * signals caller to move on. + */ +static void __def_musb_init(void) +{ +} +void board_musb_init(void) __attribute__((weak, alias("__def_musb_init"))); + +static void bfin_anomaly_init(void) +{ +	u32 revid; + +	if (!ANOMALY_05000346 && !ANOMALY_05000347) +		return; + +	revid = bfin_revid(); + +#ifdef __ADSPBF54x__ +	if (revid > 0) +		return; +#endif +#ifdef __ADSPBF52x__ +	if (ANOMALY_BF526 && revid > 0) +		return; +	if (ANOMALY_BF527 && revid > 1) +		return; +#endif + +	if (ANOMALY_05000346) { +		bfin_write_USB_APHY_CALIB(ANOMALY_05000346_value); +		SSYNC(); +	} + +	if (ANOMALY_05000347) { +		bfin_write_USB_APHY_CNTRL(0x0); +		SSYNC(); +	} +} + +int musb_platform_init(void) +{ +	/* board specific initialization */ +	board_musb_init(); + +	bfin_anomaly_init(); + +	/* Configure PLL oscillator register */ +	bfin_write_USB_PLLOSC_CTRL(0x3080 | +		((480 / CONFIG_USB_BLACKFIN_CLKIN) << 1)); +	SSYNC(); + +	bfin_write_USB_SRP_CLKDIV((get_sclk()/1000) / 32 - 1); +	SSYNC(); + +	bfin_write_USB_EP_NI0_RXMAXP(64); +	SSYNC(); + +	bfin_write_USB_EP_NI0_TXMAXP(64); +	SSYNC(); + +	/* Route INTRUSB/INTR_RX/INTR_TX to USB_INT0*/ +	bfin_write_USB_GLOBINTR(0x7); +	SSYNC(); + +	bfin_write_USB_GLOBAL_CTL(GLOBAL_ENA | EP1_TX_ENA | EP2_TX_ENA | +				EP3_TX_ENA | EP4_TX_ENA | EP5_TX_ENA | +				EP6_TX_ENA | EP7_TX_ENA | EP1_RX_ENA | +				EP2_RX_ENA | EP3_RX_ENA | EP4_RX_ENA | +				EP5_RX_ENA | EP6_RX_ENA | EP7_RX_ENA); +	SSYNC(); + +	return 0; +} + +/* + * This function performs Blackfin platform specific deinitialization for usb. +*/ +void musb_platform_deinit(void) +{ +} diff --git a/roms/u-boot/drivers/usb/musb/blackfin_usb.h b/roms/u-boot/drivers/usb/musb/blackfin_usb.h new file mode 100644 index 00000000..de994bf3 --- /dev/null +++ b/roms/u-boot/drivers/usb/musb/blackfin_usb.h @@ -0,0 +1,99 @@ +/* + * Blackfin MUSB HCD (Host Controller Driver) for u-boot + * + * Copyright (c) 2008-2009 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#ifndef __BLACKFIN_USB_H__ +#define __BLACKFIN_USB_H__ + +#include <linux/types.h> + +/* Every register is 32bit aligned, but only 16bits in size */ +#define ureg(name) u16 name; u16 __pad_##name; + +#define musb_regs musb_regs +struct musb_regs { +	/* common registers */ +	ureg(faddr) +	ureg(power) +	ureg(intrtx) +	ureg(intrrx) +	ureg(intrtxe) +	ureg(intrrxe) +	ureg(intrusb) +	ureg(intrusbe) +	ureg(frame) +	ureg(index) +	ureg(testmode) +	ureg(globintr) +	ureg(global_ctl) +	u32	reserved0[3]; +	/* indexed registers */ +	ureg(txmaxp) +	ureg(txcsr) +	ureg(rxmaxp) +	ureg(rxcsr) +	ureg(rxcount) +	ureg(txtype) +	ureg(txinterval) +	ureg(rxtype) +	ureg(rxinterval) +	u32	reserved1; +	ureg(txcount) +	u32	reserved2[5]; +	/* fifo */ +	u16	fifox[32]; +	/* OTG, dynamic FIFO, version & vendor registers */ +	u32	reserved3[16]; +	ureg(devctl) +	ureg(vbus_irq) +	ureg(vbus_mask) +	u32 reserved4[15]; +	ureg(linkinfo) +	ureg(vplen) +	ureg(hseof1) +	ureg(fseof1) +	ureg(lseof1) +	u32 reserved5[41]; +	/* target address registers */ +	struct musb_tar_regs { +		ureg(txmaxp) +		ureg(txcsr) +		ureg(rxmaxp) +		ureg(rxcsr) +		ureg(rxcount) +		ureg(txtype) +		ureg(txinternal) +		ureg(rxtype) +		ureg(rxinternal) +		u32	reserved6; +		ureg(txcount) +		u32 reserved7[5]; +	} tar[8]; +} __attribute__((packed)); + +struct bfin_musb_dma_regs { +	ureg(interrupt); +	ureg(control); +	ureg(addr_low); +	ureg(addr_high); +	ureg(count_low); +	ureg(count_high); +	u32 reserved0[2]; +}; + +#undef ureg + +/* EP5-EP7 are the only ones with 1024 byte FIFOs which BULK really needs */ +#define MUSB_BULK_EP 5 + +/* Blackfin FIFO's are static */ +#define MUSB_NO_DYNAMIC_FIFO + +/* No HUB support :( */ +#define MUSB_NO_MULTIPOINT + +#endif diff --git a/roms/u-boot/drivers/usb/musb/da8xx.c b/roms/u-boot/drivers/usb/musb/da8xx.c new file mode 100644 index 00000000..97d4ddb5 --- /dev/null +++ b/roms/u-boot/drivers/usb/musb/da8xx.c @@ -0,0 +1,128 @@ +/* + * da8xx.c - TI's DA8xx platform specific usb wrapper functions. + * + * Author: Ajay Kumar Gupta <ajay.gupta@ti.com> + * + * Based on drivers/usb/musb/davinci.c + * + * Copyright (C) 2009 Texas Instruments Incorporated + * + * SPDX-License-Identifier:	GPL-2.0+ + */ +#include <common.h> + +#include "musb_core.h" +#include <asm/arch/da8xx-usb.h> + +/* MUSB platform configuration */ +struct musb_config musb_cfg = { +	.regs		= (struct musb_regs *)DA8XX_USB_OTG_CORE_BASE, +	.timeout	= DA8XX_USB_OTG_TIMEOUT, +	.musb_speed	= 0, +}; + +/* + * This function enables VBUS by driving the GPIO Bank4 Pin 15 high. + */ +static void enable_vbus(void) +{ +	u32 value; + +	/* configure GPIO bank4 pin 15 in output direction */ +	value = readl(&davinci_gpio_bank45->dir); +	writel((value & (~DA8XX_USB_VBUS_GPIO)), &davinci_gpio_bank45->dir); + +	/* set GPIO bank4 pin 15 high to drive VBUS */ +	value = readl(&davinci_gpio_bank45->set_data); +	writel((value | DA8XX_USB_VBUS_GPIO), &davinci_gpio_bank45->set_data); +} + +/* + * Enable the usb0 phy. This initialization procedure is explained in + * the DA8xx USB user guide document. + */ +static u8 phy_on(void) +{ +	u32 timeout; +	u32 cfgchip2; + +	cfgchip2 = readl(&davinci_syscfg_regs->cfgchip2); + +	cfgchip2 &= ~(CFGCHIP2_RESET | CFGCHIP2_PHYPWRDN | CFGCHIP2_OTGPWRDN | +		      CFGCHIP2_OTGMODE | CFGCHIP2_REFFREQ); +	cfgchip2 |= CFGCHIP2_SESENDEN | CFGCHIP2_VBDTCTEN | CFGCHIP2_PHY_PLLON | +		    CFGCHIP2_REFFREQ_24MHZ; + +	writel(cfgchip2, &davinci_syscfg_regs->cfgchip2); + +	/* wait until the usb phy pll locks */ +	timeout = musb_cfg.timeout; +	while (timeout--) +		if (readl(&davinci_syscfg_regs->cfgchip2) & CFGCHIP2_PHYCLKGD) +			return 1; + +	/* USB phy was not turned on */ +	return 0; +} + +/* + * Disable the usb phy + */ +static void phy_off(void) +{ +	u32 cfgchip2; + +	/* +	 * Power down the on-chip PHY. +	 */ +	cfgchip2 = readl(&davinci_syscfg_regs->cfgchip2); +	cfgchip2 &= ~CFGCHIP2_PHY_PLLON; +	cfgchip2 |= CFGCHIP2_PHYPWRDN | CFGCHIP2_OTGPWRDN; +	writel(cfgchip2, &davinci_syscfg_regs->cfgchip2); +} + +/* + * This function performs DA8xx platform specific initialization for usb0. + */ +int musb_platform_init(void) +{ +	u32  revision; + +	/* enable psc for usb2.0 */ +	lpsc_on(33); + +	/* enable usb vbus */ +	enable_vbus(); + +	/* reset the controller */ +	writel(0x1, &da8xx_usb_regs->control); +	udelay(5000); + +	/* start the on-chip usb phy and its pll */ +	if (phy_on() == 0) +		return -1; + +	/* Returns zero if e.g. not clocked */ +	revision = readl(&da8xx_usb_regs->revision); +	if (revision == 0) +		return -1; + +	/* Disable all interrupts */ +	writel((DA8XX_USB_USBINT_MASK | DA8XX_USB_TXINT_MASK | +		DA8XX_USB_RXINT_MASK), &da8xx_usb_regs->intmsk_set); +	return 0; +} + +/* + * This function performs DA8xx platform specific deinitialization for usb0. + */ +void musb_platform_deinit(void) +{ +	/* Turn of the phy */ +	phy_off(); + +	/* flush any interrupts */ +	writel((DA8XX_USB_USBINT_MASK | DA8XX_USB_TXINT_MASK | +		DA8XX_USB_RXINT_MASK), &da8xx_usb_regs->intmsk_clr); +	writel(0, &da8xx_usb_regs->eoi); +} diff --git a/roms/u-boot/drivers/usb/musb/davinci.c b/roms/u-boot/drivers/usb/musb/davinci.c new file mode 100644 index 00000000..a9707a89 --- /dev/null +++ b/roms/u-boot/drivers/usb/musb/davinci.c @@ -0,0 +1,124 @@ +/* + * TI's Davinci platform specific USB wrapper functions. + * + * Copyright (c) 2008 Texas Instruments + * + * SPDX-License-Identifier:	GPL-2.0+ + * + * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments + */ + +#include <common.h> +#include <asm/io.h> +#include "davinci.h" +#include <asm/arch/hardware.h> + +#if !defined(CONFIG_DV_USBPHY_CTL) +#define CONFIG_DV_USBPHY_CTL (USBPHY_SESNDEN | USBPHY_VBDTCTEN) +#endif + +/* MUSB platform configuration */ +struct musb_config musb_cfg = { +	.regs		= (struct musb_regs *)MENTOR_USB0_BASE, +	.timeout	= DAVINCI_USB_TIMEOUT, +	.musb_speed	= 0, +}; + +/* MUSB module register overlay */ +struct davinci_usb_regs *dregs; + +/* + * Enable the USB phy + */ +static u8 phy_on(void) +{ +	u32 timeout; +#ifdef DAVINCI_DM365EVM +	u32 val; +#endif +	/* Wait until the USB phy is turned on */ +#ifdef DAVINCI_DM365EVM +	writel(USBPHY_PHY24MHZ | USBPHY_SESNDEN | +			USBPHY_VBDTCTEN, USBPHY_CTL_PADDR); +#else +	writel(CONFIG_DV_USBPHY_CTL, USBPHY_CTL_PADDR); +#endif +	timeout = musb_cfg.timeout; + +#ifdef DAVINCI_DM365EVM +	/* Set the ownership of GIO33 to USB */ +	val = readl(PINMUX4); +	val &= ~(PINMUX4_USBDRVBUS_BITCLEAR); +	val |= PINMUX4_USBDRVBUS_BITSET; +	writel(val, PINMUX4); +#endif +	while (timeout--) +		if (readl(USBPHY_CTL_PADDR) & USBPHY_PHYCLKGD) +			return 1; + +	/* USB phy was not turned on */ +	return 0; +} + +/* + * Disable the USB phy + */ +static void phy_off(void) +{ +	/* powerdown the on-chip PHY and its oscillator */ +	writel(USBPHY_OSCPDWN | USBPHY_PHYPDWN, USBPHY_CTL_PADDR); +} + +void __enable_vbus(void) +{ +	/* +	 *  nothing to do, vbus is handled through the cpu. +	 *  Define this function in board code, if it is +	 *  different on your board. +	 */ +} +void  enable_vbus(void) +	__attribute__((weak, alias("__enable_vbus"))); + +/* + * This function performs Davinci platform specific initialization for usb0. + */ +int musb_platform_init(void) +{ +	u32  revision; + +	/* enable USB VBUS */ +	enable_vbus(); + +	/* start the on-chip USB phy and its pll */ +	if (!phy_on()) +		return -1; + +	/* reset the controller */ +	dregs = (struct davinci_usb_regs *)DAVINCI_USB0_BASE; +	writel(1, &dregs->ctrlr); +	udelay(5000); + +	/* Returns zero if e.g. not clocked */ +	revision = readl(&dregs->version); +	if (!revision) +		return -1; + +	/* Disable all interrupts */ +	writel(DAVINCI_USB_USBINT_MASK | DAVINCI_USB_RXINT_MASK | +			DAVINCI_USB_TXINT_MASK , &dregs->intmsksetr); +	return 0; +} + +/* + * This function performs Davinci platform specific deinitialization for usb0. + */ +void musb_platform_deinit(void) +{ +	/* Turn of the phy */ +	phy_off(); + +	/* flush any interrupts */ +	writel(DAVINCI_USB_USBINT_MASK | DAVINCI_USB_TXINT_MASK | +			DAVINCI_USB_RXINT_MASK , &dregs->intclrr); +} diff --git a/roms/u-boot/drivers/usb/musb/davinci.h b/roms/u-boot/drivers/usb/musb/davinci.h new file mode 100644 index 00000000..9efefe81 --- /dev/null +++ b/roms/u-boot/drivers/usb/musb/davinci.h @@ -0,0 +1,74 @@ +/* + * TI's Davinci platform specific USB wrapper functions. + * + * Copyright (c) 2008 Texas Instruments + * + * SPDX-License-Identifier:	GPL-2.0+ + * + * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments + */ + +#ifndef __DAVINCI_USB_H__ +#define __DAVINCI_USB_H__ + +#include <asm/arch/hardware.h> +#include "musb_core.h" + +/* Base address of DAVINCI usb0 wrapper */ +#define DAVINCI_USB0_BASE 0x01C64000 + +/* Base address of DAVINCI musb core */ +#define MENTOR_USB0_BASE (DAVINCI_USB0_BASE+0x400) + +/* + * Davinci platform USB wrapper register overlay. Note: Only the required + * registers are included in this structure. It can be expanded as required. + */ +struct davinci_usb_regs { +	u32	version; +	u32	ctrlr; +	u32	reserved[0x20]; +	u32	intclrr; +	u32 	intmskr; +	u32 	intmsksetr; +}; + +#define DAVINCI_USB_TX_ENDPTS_MASK	0x1f /* ep0 + 4 tx */ +#define DAVINCI_USB_RX_ENDPTS_MASK	0x1e /* 4 rx */ +#define DAVINCI_USB_USBINT_SHIFT	16 +#define DAVINCI_USB_TXINT_SHIFT 	0 +#define DAVINCI_USB_RXINT_SHIFT 	8 +#define DAVINCI_INTR_DRVVBUS		0x0100 + +#define DAVINCI_USB_USBINT_MASK 	0x01ff0000	/* 8 Mentor, DRVVBUS */ +#define DAVINCI_USB_TXINT_MASK \ +		(DAVINCI_USB_TX_ENDPTS_MASK << DAVINCI_USB_TXINT_SHIFT) +#define DAVINCI_USB_RXINT_MASK \ +		(DAVINCI_USB_RX_ENDPTS_MASK << DAVINCI_USB_RXINT_SHIFT) +#define MGC_BUSCTL_OFFSET(_bEnd, _bOffset) \ +		(0x80 + (8*(_bEnd)) + (_bOffset)) + +/* Integrated highspeed/otg PHY */ +#define USBPHY_CTL_PADDR	(DAVINCI_SYSTEM_MODULE_BASE + 0x34) +#define USBPHY_PHY24MHZ 	(1 << 13) +#define USBPHY_PHYCLKGD 	(1 << 8) +#define USBPHY_SESNDEN		(1 << 7)	/* v(sess_end) comparator */ +#define USBPHY_VBDTCTEN 	(1 << 6)	/* v(bus) comparator */ +#define USBPHY_PHYPLLON 	(1 << 4)	/* override pll suspend */ +#define USBPHY_CLKO1SEL 	(1 << 3) +#define USBPHY_OSCPDWN		(1 << 2) +#define USBPHY_PHYPDWN		(1 << 0) + +/* Timeout for Davinci USB module */ +#define DAVINCI_USB_TIMEOUT 0x3FFFFFF + +/* IO Expander I2C address and VBUS enable mask */ +#define IOEXP_I2C_ADDR 0x3A +#define IOEXP_VBUSEN_MASK 1 + +/* extern functions */ +extern void lpsc_on(unsigned int id); +extern int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len); +extern int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len); +extern void enable_vbus(void); +#endif	/* __DAVINCI_USB_H__ */ diff --git a/roms/u-boot/drivers/usb/musb/musb_core.c b/roms/u-boot/drivers/usb/musb/musb_core.c new file mode 100644 index 00000000..786909fb --- /dev/null +++ b/roms/u-boot/drivers/usb/musb/musb_core.c @@ -0,0 +1,155 @@ +/* + * Mentor USB OTG Core functionality common for both Host and Device + * functionality. + * + * Copyright (c) 2008 Texas Instruments + * + * SPDX-License-Identifier:	GPL-2.0+ + * + * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments + */ + +#include <common.h> + +#include "musb_core.h" +struct musb_regs *musbr; + +/* + * program the mentor core to start (enable interrupts, dma, etc.) + */ +void musb_start(void) +{ +#if defined(CONFIG_MUSB_HCD) +	u8 devctl; +	u8 busctl; +#endif + +	/* disable all interrupts */ +	writew(0, &musbr->intrtxe); +	writew(0, &musbr->intrrxe); +	writeb(0, &musbr->intrusbe); +	writeb(0, &musbr->testmode); + +	/* put into basic highspeed mode and start session */ +	writeb(MUSB_POWER_HSENAB, &musbr->power); +#if defined(CONFIG_MUSB_HCD) +	/* Program PHY to use EXT VBUS if required */ +	if (musb_cfg.extvbus == 1) { +		busctl = musb_read_ulpi_buscontrol(musbr); +		musb_write_ulpi_buscontrol(musbr, busctl | ULPI_USE_EXTVBUS); +	} + +	devctl = readb(&musbr->devctl); +	writeb(devctl | MUSB_DEVCTL_SESSION, &musbr->devctl); +#endif +} + +#ifdef MUSB_NO_DYNAMIC_FIFO +# define config_fifo(dir, idx, addr) +#else +# define config_fifo(dir, idx, addr) \ +	do { \ +		writeb(idx, &musbr->dir##fifosz); \ +		writew(fifoaddr >> 3, &musbr->dir##fifoadd); \ +	} while (0) +#endif + +/* + * This function configures the endpoint configuration. The musb hcd or musb + * device implementation can use this function to configure the endpoints + * and set the FIFO sizes. Note: The summation of FIFO sizes of all endpoints + * should not be more than the available FIFO size. + * + * epinfo	- Pointer to EP configuration table + * cnt		- Number of entries in the EP conf table. + */ +void musb_configure_ep(const struct musb_epinfo *epinfo, u8 cnt) +{ +	u16 csr; +	u16 fifoaddr = 64; /* First 64 bytes of FIFO reserved for EP0 */ +	u32 fifosize; +	u8  idx; + +	while (cnt--) { +		/* prepare fifosize to write to register */ +		fifosize = epinfo->epsize >> 3; +		idx = ffs(fifosize) - 1; + +		writeb(epinfo->epnum, &musbr->index); +		if (epinfo->epdir) { +			/* Configure fifo size and fifo base address */ +			config_fifo(tx, idx, fifoaddr); + +			csr = readw(&musbr->txcsr); +#if defined(CONFIG_MUSB_HCD) +			/* clear the data toggle bit */ +			writew(csr | MUSB_TXCSR_CLRDATATOG, &musbr->txcsr); +#endif +			/* Flush fifo if required */ +			if (csr & MUSB_TXCSR_TXPKTRDY) +				writew(csr | MUSB_TXCSR_FLUSHFIFO, +					&musbr->txcsr); +		} else { +			/* Configure fifo size and fifo base address */ +			config_fifo(rx, idx, fifoaddr); + +			csr = readw(&musbr->rxcsr); +#if defined(CONFIG_MUSB_HCD) +			/* clear the data toggle bit */ +			writew(csr | MUSB_RXCSR_CLRDATATOG, &musbr->rxcsr); +#endif +			/* Flush fifo if required */ +			if (csr & MUSB_RXCSR_RXPKTRDY) +				writew(csr | MUSB_RXCSR_FLUSHFIFO, +					&musbr->rxcsr); +		} +		fifoaddr += epinfo->epsize; +		epinfo++; +	} +} + +/* + * This function writes data to endpoint fifo + * + * ep		- endpoint number + * length	- number of bytes to write to FIFO + * fifo_data	- Pointer to data buffer that contains the data to write + */ +__attribute__((weak)) +void write_fifo(u8 ep, u32 length, void *fifo_data) +{ +	u8  *data = (u8 *)fifo_data; + +	/* select the endpoint index */ +	writeb(ep, &musbr->index); + +	/* write the data to the fifo */ +	while (length--) +		writeb(*data++, &musbr->fifox[ep]); +} + +/* + * AM35x supports only 32bit read operations so + * use seperate read_fifo() function for it. + */ +#ifndef CONFIG_USB_AM35X +/* + * This function reads data from endpoint fifo + * + * ep           - endpoint number + * length       - number of bytes to read from FIFO + * fifo_data    - pointer to data buffer into which data is read + */ +__attribute__((weak)) +void read_fifo(u8 ep, u32 length, void *fifo_data) +{ +	u8  *data = (u8 *)fifo_data; + +	/* select the endpoint index */ +	writeb(ep, &musbr->index); + +	/* read the data to the fifo */ +	while (length--) +		*data++ = readb(&musbr->fifox[ep]); +} +#endif /* CONFIG_USB_AM35X */ diff --git a/roms/u-boot/drivers/usb/musb/musb_core.h b/roms/u-boot/drivers/usb/musb/musb_core.h new file mode 100644 index 00000000..ec8a038c --- /dev/null +++ b/roms/u-boot/drivers/usb/musb/musb_core.h @@ -0,0 +1,395 @@ +/****************************************************************** + * Copyright 2008 Mentor Graphics Corporation + * Copyright (C) 2008 by Texas Instruments + * + * This file is part of the Inventra Controller Driver for Linux. + * + * The Inventra Controller Driver for Linux is free software; you + * can redistribute it and/or modify it under the terms of the GNU + * General Public License version 2 as published by the Free Software + * Foundation. + * + * The Inventra Controller Driver for Linux 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 The Inventra Controller Driver for Linux ; if not, + * write to the Free Software Foundation, Inc., 59 Temple Place, + * Suite 330, Boston, MA  02111-1307  USA + * + * ANY DOWNLOAD, USE, REPRODUCTION, MODIFICATION OR DISTRIBUTION + * OF THIS DRIVER INDICATES YOUR COMPLETE AND UNCONDITIONAL ACCEPTANCE + * OF THOSE TERMS.THIS DRIVER IS PROVIDED "AS IS" AND MENTOR GRAPHICS + * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, RELATED TO THIS DRIVER. + * MENTOR GRAPHICS SPECIFICALLY DISCLAIMS ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY; FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT.  MENTOR GRAPHICS DOES NOT PROVIDE SUPPORT + * SERVICES OR UPDATES FOR THIS DRIVER, EVEN IF YOU ARE A MENTOR + * GRAPHICS SUPPORT CUSTOMER. + ******************************************************************/ + +#ifndef __MUSB_HDRC_DEFS_H__ +#define __MUSB_HDRC_DEFS_H__ + +#include <usb_defs.h> +#include <asm/io.h> + +#ifdef CONFIG_USB_BLACKFIN +# include "blackfin_usb.h" +#endif + +#define MUSB_EP0_FIFOSIZE	64	/* This is non-configurable */ + +/* EP0 */ +struct musb_ep0_regs { +	u16	reserved4; +	u16	csr0; +	u16	reserved5; +	u16	reserved6; +	u16	count0; +	u8	host_type0; +	u8	host_naklimit0; +	u8	reserved7; +	u8	reserved8; +	u8	reserved9; +	u8	configdata; +}; + +/* EP 1-15 */ +struct musb_epN_regs { +	u16	txmaxp; +	u16	txcsr; +	u16	rxmaxp; +	u16	rxcsr; +	u16	rxcount; +	u8	txtype; +	u8	txinterval; +	u8	rxtype; +	u8	rxinterval; +	u8	reserved0; +	u8	fifosize; +}; + +/* Mentor USB core register overlay structure */ +#ifndef musb_regs +struct musb_regs { +	/* common registers */ +	u8	faddr; +	u8	power; +	u16	intrtx; +	u16	intrrx; +	u16	intrtxe; +	u16	intrrxe; +	u8	intrusb; +	u8	intrusbe; +	u16	frame; +	u8	index; +	u8	testmode; +	/* indexed registers */ +	u16	txmaxp; +	u16	txcsr; +	u16	rxmaxp; +	u16	rxcsr; +	u16	rxcount; +	u8	txtype; +	u8	txinterval; +	u8	rxtype; +	u8	rxinterval; +	u8	reserved0; +	u8	fifosize; +	/* fifo */ +	u32	fifox[16]; +	/* OTG, dynamic FIFO, version & vendor registers */ +	u8	devctl; +	u8	reserved1; +	u8	txfifosz; +	u8	rxfifosz; +	u16	txfifoadd; +	u16	rxfifoadd; +	u32	vcontrol; +	u16	hwvers; +	u16	reserved2a[1]; +	u8	ulpi_busctl; +	u8	reserved2b[1]; +	u16	reserved2[3]; +	u8	epinfo; +	u8	raminfo; +	u8	linkinfo; +	u8	vplen; +	u8	hseof1; +	u8	fseof1; +	u8	lseof1; +	u8	reserved3; +	/* target address registers */ +	struct musb_tar_regs { +		u8	txfuncaddr; +		u8	reserved0; +		u8	txhubaddr; +		u8	txhubport; +		u8	rxfuncaddr; +		u8	reserved1; +		u8	rxhubaddr; +		u8	rxhubport; +	} tar[16]; +	/* +	 * endpoint registers +	 * ep0 elements are valid when array index is 0 +	 * otherwise epN is valid +	 */ +	union musb_ep_regs { +		struct musb_ep0_regs ep0; +		struct musb_epN_regs epN; +	} ep[16]; + +} __attribute__((packed)); +#endif + +/* + * MUSB Register bits + */ + +/* POWER */ +#define MUSB_POWER_ISOUPDATE	0x80 +#define MUSB_POWER_SOFTCONN	0x40 +#define MUSB_POWER_HSENAB	0x20 +#define MUSB_POWER_HSMODE	0x10 +#define MUSB_POWER_RESET	0x08 +#define MUSB_POWER_RESUME	0x04 +#define MUSB_POWER_SUSPENDM	0x02 +#define MUSB_POWER_ENSUSPEND	0x01 +#define MUSB_POWER_HSMODE_SHIFT	4 + +/* INTRUSB */ +#define MUSB_INTR_SUSPEND	0x01 +#define MUSB_INTR_RESUME	0x02 +#define MUSB_INTR_RESET		0x04 +#define MUSB_INTR_BABBLE	0x04 +#define MUSB_INTR_SOF		0x08 +#define MUSB_INTR_CONNECT	0x10 +#define MUSB_INTR_DISCONNECT	0x20 +#define MUSB_INTR_SESSREQ	0x40 +#define MUSB_INTR_VBUSERROR	0x80	/* For SESSION end */ + +/* DEVCTL */ +#define MUSB_DEVCTL_BDEVICE	0x80 +#define MUSB_DEVCTL_FSDEV	0x40 +#define MUSB_DEVCTL_LSDEV	0x20 +#define MUSB_DEVCTL_VBUS	0x18 +#define MUSB_DEVCTL_VBUS_SHIFT	3 +#define MUSB_DEVCTL_HM		0x04 +#define MUSB_DEVCTL_HR		0x02 +#define MUSB_DEVCTL_SESSION	0x01 + +/* ULPI VBUSCONTROL */ +#define ULPI_USE_EXTVBUS	0x01 +#define ULPI_USE_EXTVBUSIND	0x02 + +/* TESTMODE */ +#define MUSB_TEST_FORCE_HOST	0x80 +#define MUSB_TEST_FIFO_ACCESS	0x40 +#define MUSB_TEST_FORCE_FS	0x20 +#define MUSB_TEST_FORCE_HS	0x10 +#define MUSB_TEST_PACKET	0x08 +#define MUSB_TEST_K		0x04 +#define MUSB_TEST_J		0x02 +#define MUSB_TEST_SE0_NAK	0x01 + +/* Allocate for double-packet buffering (effectively doubles assigned _SIZE) */ +#define MUSB_FIFOSZ_DPB		0x10 +/* Allocation size (8, 16, 32, ... 4096) */ +#define MUSB_FIFOSZ_SIZE	0x0f + +/* CSR0 */ +#define MUSB_CSR0_FLUSHFIFO	0x0100 +#define MUSB_CSR0_TXPKTRDY	0x0002 +#define MUSB_CSR0_RXPKTRDY	0x0001 + +/* CSR0 in Peripheral mode */ +#define MUSB_CSR0_P_SVDSETUPEND	0x0080 +#define MUSB_CSR0_P_SVDRXPKTRDY	0x0040 +#define MUSB_CSR0_P_SENDSTALL	0x0020 +#define MUSB_CSR0_P_SETUPEND	0x0010 +#define MUSB_CSR0_P_DATAEND	0x0008 +#define MUSB_CSR0_P_SENTSTALL	0x0004 + +/* CSR0 in Host mode */ +#define MUSB_CSR0_H_DIS_PING		0x0800 +#define MUSB_CSR0_H_WR_DATATOGGLE	0x0400	/* Set to allow setting: */ +#define MUSB_CSR0_H_DATATOGGLE		0x0200	/* Data toggle control */ +#define MUSB_CSR0_H_NAKTIMEOUT		0x0080 +#define MUSB_CSR0_H_STATUSPKT		0x0040 +#define MUSB_CSR0_H_REQPKT		0x0020 +#define MUSB_CSR0_H_ERROR		0x0010 +#define MUSB_CSR0_H_SETUPPKT		0x0008 +#define MUSB_CSR0_H_RXSTALL		0x0004 + +/* CSR0 bits to avoid zeroing (write zero clears, write 1 ignored) */ +#define MUSB_CSR0_P_WZC_BITS	\ +	(MUSB_CSR0_P_SENTSTALL) +#define MUSB_CSR0_H_WZC_BITS	\ +	(MUSB_CSR0_H_NAKTIMEOUT | MUSB_CSR0_H_RXSTALL \ +	| MUSB_CSR0_RXPKTRDY) + +/* TxType/RxType */ +#define MUSB_TYPE_SPEED		0xc0 +#define MUSB_TYPE_SPEED_SHIFT	6 +#define MUSB_TYPE_SPEED_HIGH 	1 +#define MUSB_TYPE_SPEED_FULL 	2 +#define MUSB_TYPE_SPEED_LOW	3 +#define MUSB_TYPE_PROTO		0x30	/* Implicitly zero for ep0 */ +#define MUSB_TYPE_PROTO_SHIFT	4 +#define MUSB_TYPE_REMOTE_END	0xf	/* Implicitly zero for ep0 */ +#define MUSB_TYPE_PROTO_BULK 	2 +#define MUSB_TYPE_PROTO_INTR 	3 + +/* CONFIGDATA */ +#define MUSB_CONFIGDATA_MPRXE		0x80	/* Auto bulk pkt combining */ +#define MUSB_CONFIGDATA_MPTXE		0x40	/* Auto bulk pkt splitting */ +#define MUSB_CONFIGDATA_BIGENDIAN	0x20 +#define MUSB_CONFIGDATA_HBRXE		0x10	/* HB-ISO for RX */ +#define MUSB_CONFIGDATA_HBTXE		0x08	/* HB-ISO for TX */ +#define MUSB_CONFIGDATA_DYNFIFO		0x04	/* Dynamic FIFO sizing */ +#define MUSB_CONFIGDATA_SOFTCONE	0x02	/* SoftConnect */ +#define MUSB_CONFIGDATA_UTMIDW		0x01	/* Data width 0/1 => 8/16bits */ + +/* TXCSR in Peripheral and Host mode */ +#define MUSB_TXCSR_AUTOSET		0x8000 +#define MUSB_TXCSR_MODE			0x2000 +#define MUSB_TXCSR_DMAENAB		0x1000 +#define MUSB_TXCSR_FRCDATATOG		0x0800 +#define MUSB_TXCSR_DMAMODE		0x0400 +#define MUSB_TXCSR_CLRDATATOG		0x0040 +#define MUSB_TXCSR_FLUSHFIFO		0x0008 +#define MUSB_TXCSR_FIFONOTEMPTY		0x0002 +#define MUSB_TXCSR_TXPKTRDY		0x0001 + +/* TXCSR in Peripheral mode */ +#define MUSB_TXCSR_P_ISO		0x4000 +#define MUSB_TXCSR_P_INCOMPTX		0x0080 +#define MUSB_TXCSR_P_SENTSTALL		0x0020 +#define MUSB_TXCSR_P_SENDSTALL		0x0010 +#define MUSB_TXCSR_P_UNDERRUN		0x0004 + +/* TXCSR in Host mode */ +#define MUSB_TXCSR_H_WR_DATATOGGLE	0x0200 +#define MUSB_TXCSR_H_DATATOGGLE		0x0100 +#define MUSB_TXCSR_H_NAKTIMEOUT		0x0080 +#define MUSB_TXCSR_H_RXSTALL		0x0020 +#define MUSB_TXCSR_H_ERROR		0x0004 +#define MUSB_TXCSR_H_DATATOGGLE_SHIFT	8 + +/* TXCSR bits to avoid zeroing (write zero clears, write 1 ignored) */ +#define MUSB_TXCSR_P_WZC_BITS	\ +	(MUSB_TXCSR_P_INCOMPTX | MUSB_TXCSR_P_SENTSTALL \ +	| MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_FIFONOTEMPTY) +#define MUSB_TXCSR_H_WZC_BITS	\ +	(MUSB_TXCSR_H_NAKTIMEOUT | MUSB_TXCSR_H_RXSTALL \ +	| MUSB_TXCSR_H_ERROR | MUSB_TXCSR_FIFONOTEMPTY) + +/* RXCSR in Peripheral and Host mode */ +#define MUSB_RXCSR_AUTOCLEAR		0x8000 +#define MUSB_RXCSR_DMAENAB		0x2000 +#define MUSB_RXCSR_DISNYET		0x1000 +#define MUSB_RXCSR_PID_ERR		0x1000 +#define MUSB_RXCSR_DMAMODE		0x0800 +#define MUSB_RXCSR_INCOMPRX		0x0100 +#define MUSB_RXCSR_CLRDATATOG		0x0080 +#define MUSB_RXCSR_FLUSHFIFO		0x0010 +#define MUSB_RXCSR_DATAERROR		0x0008 +#define MUSB_RXCSR_FIFOFULL		0x0002 +#define MUSB_RXCSR_RXPKTRDY		0x0001 + +/* RXCSR in Peripheral mode */ +#define MUSB_RXCSR_P_ISO		0x4000 +#define MUSB_RXCSR_P_SENTSTALL		0x0040 +#define MUSB_RXCSR_P_SENDSTALL		0x0020 +#define MUSB_RXCSR_P_OVERRUN		0x0004 + +/* RXCSR in Host mode */ +#define MUSB_RXCSR_H_AUTOREQ		0x4000 +#define MUSB_RXCSR_H_WR_DATATOGGLE	0x0400 +#define MUSB_RXCSR_H_DATATOGGLE		0x0200 +#define MUSB_RXCSR_H_RXSTALL		0x0040 +#define MUSB_RXCSR_H_REQPKT		0x0020 +#define MUSB_RXCSR_H_ERROR		0x0004 +#define MUSB_S_RXCSR_H_DATATOGGLE	9 + +/* RXCSR bits to avoid zeroing (write zero clears, write 1 ignored) */ +#define MUSB_RXCSR_P_WZC_BITS	\ +	(MUSB_RXCSR_P_SENTSTALL | MUSB_RXCSR_P_OVERRUN \ +	| MUSB_RXCSR_RXPKTRDY) +#define MUSB_RXCSR_H_WZC_BITS	\ +	(MUSB_RXCSR_H_RXSTALL | MUSB_RXCSR_H_ERROR \ +	| MUSB_RXCSR_DATAERROR | MUSB_RXCSR_RXPKTRDY) + +/* HUBADDR */ +#define MUSB_HUBADDR_MULTI_TT		0x80 + +/* Endpoint configuration information. Note: The value of endpoint fifo size + * element should be either 8,16,32,64,128,256,512,1024,2048 or 4096. Other + * values are not supported + */ +struct musb_epinfo { +	u8	epnum;	/* endpoint number 	*/ +	u8	epdir;	/* endpoint direction	*/ +	u16	epsize;	/* endpoint FIFO size	*/ +}; + +/* + * Platform specific MUSB configuration. Any platform using the musb + * functionality should create one instance of this structure in the + * platform specific file. + */ +struct musb_config { +	struct	musb_regs	*regs; +	u32			timeout; +	u8			musb_speed; +	u8			extvbus; +}; + +/* externally defined data */ +extern struct musb_config	musb_cfg; +extern struct musb_regs		*musbr; + +/* exported functions */ +extern void musb_start(void); +extern void musb_configure_ep(const struct musb_epinfo *epinfo, u8 cnt); +extern void write_fifo(u8 ep, u32 length, void *fifo_data); +extern void read_fifo(u8 ep, u32 length, void *fifo_data); + +#if defined(CONFIG_USB_BLACKFIN) +/* Every USB register is accessed as a 16-bit even if the value itself + * is only 8-bits in size.  Fun stuff. + */ +# undef  readb +# define readb(addr)     (u8)bfin_read16(addr) +# undef  writeb +# define writeb(b, addr) bfin_write16(addr, b) +# undef MUSB_TXCSR_MODE /* not supported */ +# define MUSB_TXCSR_MODE 0 +/* + * The USB PHY on current Blackfin processors is a UTMI+ level 2 PHY. + * However, it has no ULPI support - so there are no registers at all. + * That means accesses to ULPI_BUSCONTROL have to be abstracted away. + */ +static inline u8 musb_read_ulpi_buscontrol(struct musb_regs *musbr) +{ +	return 0; +} +static inline void musb_write_ulpi_buscontrol(struct musb_regs *musbr, u8 val) +{} +#else +static inline u8 musb_read_ulpi_buscontrol(struct musb_regs *musbr) +{ +	return readb(&musbr->ulpi_busctl); +} +static inline void musb_write_ulpi_buscontrol(struct musb_regs *musbr, u8 val) +{ +	writeb(val, &musbr->ulpi_busctl); +} +#endif + +#endif	/* __MUSB_HDRC_DEFS_H__ */ diff --git a/roms/u-boot/drivers/usb/musb/musb_debug.h b/roms/u-boot/drivers/usb/musb/musb_debug.h new file mode 100644 index 00000000..b387fc36 --- /dev/null +++ b/roms/u-boot/drivers/usb/musb/musb_debug.h @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2009 Wind River Systems, Inc. + * Tom Rix <Tom.Rix@windriver.com> + * + * SPDX-License-Identifier:	GPL-2.0+ + */ + +/* Define MUSB_DEBUG before including this file to get debug macros */ +#ifdef MUSB_DEBUG + +#define MUSB_FLAGS_PRINT(v, x, y)		\ +  if (((v) & MUSB_##x##_##y))			\ +		serial_printf("\t\t"#y"\n") + +static inline void musb_print_pwr(u8 b) +{ +	serial_printf("\tpower   0x%2.2x\n", b); +	MUSB_FLAGS_PRINT(b, POWER, ISOUPDATE); +	MUSB_FLAGS_PRINT(b, POWER, SOFTCONN); +	MUSB_FLAGS_PRINT(b, POWER, HSENAB); +	MUSB_FLAGS_PRINT(b, POWER, HSMODE); +	MUSB_FLAGS_PRINT(b, POWER, RESET); +	MUSB_FLAGS_PRINT(b, POWER, RESUME); +	MUSB_FLAGS_PRINT(b, POWER, SUSPENDM); +	MUSB_FLAGS_PRINT(b, POWER, ENSUSPEND); +} + +static inline void musb_print_csr0(u16 w) +{ +	serial_printf("\tcsr0    0x%4.4x\n", w); +	MUSB_FLAGS_PRINT(w, CSR0, FLUSHFIFO); +	MUSB_FLAGS_PRINT(w, CSR0_P, SVDSETUPEND); +	MUSB_FLAGS_PRINT(w, CSR0_P, SVDRXPKTRDY); +	MUSB_FLAGS_PRINT(w, CSR0_P, SENDSTALL); +	MUSB_FLAGS_PRINT(w, CSR0_P, SETUPEND); +	MUSB_FLAGS_PRINT(w, CSR0_P, DATAEND); +	MUSB_FLAGS_PRINT(w, CSR0_P, SENTSTALL); +	MUSB_FLAGS_PRINT(w, CSR0, TXPKTRDY); +	MUSB_FLAGS_PRINT(w, CSR0, RXPKTRDY); +} + +static inline void musb_print_intrusb(u8 b) +{ +	serial_printf("\tintrusb 0x%2.2x\n", b); +	MUSB_FLAGS_PRINT(b, INTR, VBUSERROR); +	MUSB_FLAGS_PRINT(b, INTR, SESSREQ); +	MUSB_FLAGS_PRINT(b, INTR, DISCONNECT); +	MUSB_FLAGS_PRINT(b, INTR, CONNECT); +	MUSB_FLAGS_PRINT(b, INTR, SOF); +	MUSB_FLAGS_PRINT(b, INTR, RESUME); +	MUSB_FLAGS_PRINT(b, INTR, SUSPEND); + +	if (b & MUSB_INTR_BABBLE) +		serial_printf("\t\tMUSB_INTR_RESET or MUSB_INTR_BABBLE\n"); + +} + +static inline void musb_print_intrtx(u16 w) +{ +	serial_printf("\tintrtx 0x%4.4x\n", w); +} + +static inline void musb_print_intrrx(u16 w) +{ +	serial_printf("\tintrx 0x%4.4x\n", w); +} + +static inline void musb_print_devctl(u8 b) +{ +	serial_printf("\tdevctl  0x%2.2x\n", b); +	if (b & MUSB_DEVCTL_BDEVICE) +		serial_printf("\t\tB device\n"); +	else +		serial_printf("\t\tA device\n"); +	if (b & MUSB_DEVCTL_FSDEV) +		serial_printf("\t\tFast Device -(host mode)\n"); +	if (b & MUSB_DEVCTL_LSDEV) +		serial_printf("\t\tSlow Device -(host mode)\n"); +	if (b & MUSB_DEVCTL_HM) +		serial_printf("\t\tHost mode\n"); +	else +		serial_printf("\t\tPeripherial mode\n"); +	if (b & MUSB_DEVCTL_HR) +		serial_printf("\t\tHost request started(B device)\n"); +	else +		serial_printf("\t\tHost request finished(B device)\n"); +	if (b & MUSB_DEVCTL_BDEVICE) { +		if (b & MUSB_DEVCTL_SESSION) +			serial_printf("\t\tStart of session(B device)\n"); +		else +			serial_printf("\t\tEnd of session(B device)\n"); +	} else { +		if (b & MUSB_DEVCTL_SESSION) +			serial_printf("\t\tStart of session(A device)\n"); +		else +			serial_printf("\t\tEnd of session(A device)\n"); +	} +} + +static inline void musb_print_config(u8 b) +{ +	serial_printf("\tconfig 0x%2.2x\n", b); +	if (b & MUSB_CONFIGDATA_MPRXE) +		serial_printf("\t\tAuto combine rx bulk packets\n"); +	if (b & MUSB_CONFIGDATA_MPTXE) +		serial_printf("\t\tAuto split tx bulk packets\n"); +	if (b & MUSB_CONFIGDATA_BIGENDIAN) +		serial_printf("\t\tBig Endian ordering\n"); +	else +		serial_printf("\t\tLittle Endian ordering\n"); +	if (b & MUSB_CONFIGDATA_HBRXE) +		serial_printf("\t\tHigh speed rx iso endpoint\n"); +	if (b & MUSB_CONFIGDATA_HBTXE) +		serial_printf("\t\tHigh speed tx iso endpoint\n"); +	if (b & MUSB_CONFIGDATA_DYNFIFO) +		serial_printf("\t\tDynamic fifo sizing\n"); +	if (b & MUSB_CONFIGDATA_SOFTCONE) +		serial_printf("\t\tSoft Connect\n"); +	if (b & MUSB_CONFIGDATA_UTMIDW) +		serial_printf("\t\t16 bit data width\n"); +	else +		serial_printf("\t\t8 bit data width\n"); +} + +static inline void musb_print_rxmaxp(u16 w) +{ +	serial_printf("\trxmaxp  0x%4.4x\n", w); +} + +static inline void musb_print_rxcsr(u16 w) +{ +	serial_printf("\trxcsr   0x%4.4x\n", w); +	MUSB_FLAGS_PRINT(w, RXCSR, AUTOCLEAR); +	MUSB_FLAGS_PRINT(w, RXCSR, DMAENAB); +	MUSB_FLAGS_PRINT(w, RXCSR, DISNYET); +	MUSB_FLAGS_PRINT(w, RXCSR, PID_ERR); +	MUSB_FLAGS_PRINT(w, RXCSR, DMAMODE); +	MUSB_FLAGS_PRINT(w, RXCSR, CLRDATATOG); +	MUSB_FLAGS_PRINT(w, RXCSR, FLUSHFIFO); +	MUSB_FLAGS_PRINT(w, RXCSR, DATAERROR); +	MUSB_FLAGS_PRINT(w, RXCSR, FIFOFULL); +	MUSB_FLAGS_PRINT(w, RXCSR, RXPKTRDY); +	MUSB_FLAGS_PRINT(w, RXCSR_P, SENTSTALL); +	MUSB_FLAGS_PRINT(w, RXCSR_P, SENDSTALL); +	MUSB_FLAGS_PRINT(w, RXCSR_P, OVERRUN); + +	if (w & MUSB_RXCSR_P_ISO) +		serial_printf("\t\tiso mode\n"); +	else +		serial_printf("\t\tbulk mode\n"); + +} + +static inline void musb_print_txmaxp(u16 w) +{ +	serial_printf("\ttxmaxp  0x%4.4x\n", w); +} + +static inline void musb_print_txcsr(u16 w) +{ +	serial_printf("\ttxcsr   0x%4.4x\n", w); +	MUSB_FLAGS_PRINT(w, TXCSR, TXPKTRDY); +	MUSB_FLAGS_PRINT(w, TXCSR, FIFONOTEMPTY); +	MUSB_FLAGS_PRINT(w, TXCSR, FLUSHFIFO); +	MUSB_FLAGS_PRINT(w, TXCSR, CLRDATATOG); +	MUSB_FLAGS_PRINT(w, TXCSR_P, UNDERRUN); +	MUSB_FLAGS_PRINT(w, TXCSR_P, SENTSTALL); +	MUSB_FLAGS_PRINT(w, TXCSR_P, SENDSTALL); + +	if (w & MUSB_TXCSR_MODE) +		serial_printf("\t\tTX mode\n"); +	else +		serial_printf("\t\tRX mode\n"); +} + +#else + +/* stubs */ + +#define musb_print_pwr(b) +#define musb_print_csr0(w) +#define musb_print_intrusb(b) +#define musb_print_intrtx(w) +#define musb_print_intrrx(w) +#define musb_print_devctl(b) +#define musb_print_config(b) +#define musb_print_rxmaxp(w) +#define musb_print_rxcsr(w) +#define musb_print_txmaxp(w) +#define musb_print_txcsr(w) + +#endif /* MUSB_DEBUG */ diff --git a/roms/u-boot/drivers/usb/musb/musb_hcd.c b/roms/u-boot/drivers/usb/musb/musb_hcd.c new file mode 100644 index 00000000..f0ba8aaa --- /dev/null +++ b/roms/u-boot/drivers/usb/musb/musb_hcd.c @@ -0,0 +1,1172 @@ +/* + * Mentor USB OTG Core host controller driver. + * + * Copyright (c) 2008 Texas Instruments + * + * SPDX-License-Identifier:	GPL-2.0+ + * + * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments + */ + +#include <common.h> +#include <usb.h> +#include "musb_hcd.h" + +/* MSC control transfers */ +#define USB_MSC_BBB_RESET 	0xFF +#define USB_MSC_BBB_GET_MAX_LUN	0xFE + +/* Endpoint configuration information */ +static const struct musb_epinfo epinfo[3] = { +	{MUSB_BULK_EP, 1, 512}, /* EP1 - Bluk Out - 512 Bytes */ +	{MUSB_BULK_EP, 0, 512}, /* EP1 - Bluk In  - 512 Bytes */ +	{MUSB_INTR_EP, 0, 64}   /* EP2 - Interrupt IN - 64 Bytes */ +}; + +/* --- Virtual Root Hub ---------------------------------------------------- */ +#ifdef MUSB_NO_MULTIPOINT +static int rh_devnum; +static u32 port_status; + +#include <usbroothubdes.h> + +#endif + +/* + * This function writes the data toggle value. + */ +static void write_toggle(struct usb_device *dev, u8 ep, u8 dir_out) +{ +	u16 toggle = usb_gettoggle(dev, ep, dir_out); +	u16 csr; + +	if (dir_out) { +		csr = readw(&musbr->txcsr); +		if (!toggle) { +			if (csr & MUSB_TXCSR_MODE) +				csr = MUSB_TXCSR_CLRDATATOG; +			else +				csr = 0; +			writew(csr, &musbr->txcsr); +		} else { +			csr |= MUSB_TXCSR_H_WR_DATATOGGLE; +			writew(csr, &musbr->txcsr); +			csr |= (toggle << MUSB_TXCSR_H_DATATOGGLE_SHIFT); +			writew(csr, &musbr->txcsr); +		} +	} else { +		if (!toggle) { +			csr = readw(&musbr->txcsr); +			if (csr & MUSB_TXCSR_MODE) +				csr = MUSB_RXCSR_CLRDATATOG; +			else +				csr = 0; +			writew(csr, &musbr->rxcsr); +		} else { +			csr = readw(&musbr->rxcsr); +			csr |= MUSB_RXCSR_H_WR_DATATOGGLE; +			writew(csr, &musbr->rxcsr); +			csr |= (toggle << MUSB_S_RXCSR_H_DATATOGGLE); +			writew(csr, &musbr->rxcsr); +		} +	} +} + +/* + * This function checks if RxStall has occured on the endpoint. If a RxStall + * has occured, the RxStall is cleared and 1 is returned. If RxStall has + * not occured, 0 is returned. + */ +static u8 check_stall(u8 ep, u8 dir_out) +{ +	u16 csr; + +	/* For endpoint 0 */ +	if (!ep) { +		csr = readw(&musbr->txcsr); +		if (csr & MUSB_CSR0_H_RXSTALL) { +			csr &= ~MUSB_CSR0_H_RXSTALL; +			writew(csr, &musbr->txcsr); +			return 1; +		} +	} else { /* For non-ep0 */ +		if (dir_out) { /* is it tx ep */ +			csr = readw(&musbr->txcsr); +			if (csr & MUSB_TXCSR_H_RXSTALL) { +				csr &= ~MUSB_TXCSR_H_RXSTALL; +				writew(csr, &musbr->txcsr); +				return 1; +			} +		} else { /* is it rx ep */ +			csr = readw(&musbr->rxcsr); +			if (csr & MUSB_RXCSR_H_RXSTALL) { +				csr &= ~MUSB_RXCSR_H_RXSTALL; +				writew(csr, &musbr->rxcsr); +				return 1; +			} +		} +	} +	return 0; +} + +/* + * waits until ep0 is ready. Returns 0 if ep is ready, -1 for timeout + * error and -2 for stall. + */ +static int wait_until_ep0_ready(struct usb_device *dev, u32 bit_mask) +{ +	u16 csr; +	int result = 1; +	int timeout = CONFIG_MUSB_TIMEOUT; + +	while (result > 0) { +		csr = readw(&musbr->txcsr); +		if (csr & MUSB_CSR0_H_ERROR) { +			csr &= ~MUSB_CSR0_H_ERROR; +			writew(csr, &musbr->txcsr); +			dev->status = USB_ST_CRC_ERR; +			result = -1; +			break; +		} + +		switch (bit_mask) { +		case MUSB_CSR0_TXPKTRDY: +			if (!(csr & MUSB_CSR0_TXPKTRDY)) { +				if (check_stall(MUSB_CONTROL_EP, 0)) { +					dev->status = USB_ST_STALLED; +					result = -2; +				} else +					result = 0; +			} +			break; + +		case MUSB_CSR0_RXPKTRDY: +			if (check_stall(MUSB_CONTROL_EP, 0)) { +				dev->status = USB_ST_STALLED; +				result = -2; +			} else +				if (csr & MUSB_CSR0_RXPKTRDY) +					result = 0; +			break; + +		case MUSB_CSR0_H_REQPKT: +			if (!(csr & MUSB_CSR0_H_REQPKT)) { +				if (check_stall(MUSB_CONTROL_EP, 0)) { +					dev->status = USB_ST_STALLED; +					result = -2; +				} else +					result = 0; +			} +			break; +		} + +		/* Check the timeout */ +		if (--timeout) +			udelay(1); +		else { +			dev->status = USB_ST_CRC_ERR; +			result = -1; +			break; +		} +	} + +	return result; +} + +/* + * waits until tx ep is ready. Returns 1 when ep is ready and 0 on error. + */ +static int wait_until_txep_ready(struct usb_device *dev, u8 ep) +{ +	u16 csr; +	int timeout = CONFIG_MUSB_TIMEOUT; + +	do { +		if (check_stall(ep, 1)) { +			dev->status = USB_ST_STALLED; +			return 0; +		} + +		csr = readw(&musbr->txcsr); +		if (csr & MUSB_TXCSR_H_ERROR) { +			dev->status = USB_ST_CRC_ERR; +			return 0; +		} + +		/* Check the timeout */ +		if (--timeout) +			udelay(1); +		else { +			dev->status = USB_ST_CRC_ERR; +			return -1; +		} + +	} while (csr & MUSB_TXCSR_TXPKTRDY); +	return 1; +} + +/* + * waits until rx ep is ready. Returns 1 when ep is ready and 0 on error. + */ +static int wait_until_rxep_ready(struct usb_device *dev, u8 ep) +{ +	u16 csr; +	int timeout = CONFIG_MUSB_TIMEOUT; + +	do { +		if (check_stall(ep, 0)) { +			dev->status = USB_ST_STALLED; +			return 0; +		} + +		csr = readw(&musbr->rxcsr); +		if (csr & MUSB_RXCSR_H_ERROR) { +			dev->status = USB_ST_CRC_ERR; +			return 0; +		} + +		/* Check the timeout */ +		if (--timeout) +			udelay(1); +		else { +			dev->status = USB_ST_CRC_ERR; +			return -1; +		} + +	} while (!(csr & MUSB_RXCSR_RXPKTRDY)); +	return 1; +} + +/* + * This function performs the setup phase of the control transfer + */ +static int ctrlreq_setup_phase(struct usb_device *dev, struct devrequest *setup) +{ +	int result; +	u16 csr; + +	/* write the control request to ep0 fifo */ +	write_fifo(MUSB_CONTROL_EP, sizeof(struct devrequest), (void *)setup); + +	/* enable transfer of setup packet */ +	csr = readw(&musbr->txcsr); +	csr |= (MUSB_CSR0_TXPKTRDY|MUSB_CSR0_H_SETUPPKT); +	writew(csr, &musbr->txcsr); + +	/* wait until the setup packet is transmitted */ +	result = wait_until_ep0_ready(dev, MUSB_CSR0_TXPKTRDY); +	dev->act_len = 0; +	return result; +} + +/* + * This function handles the control transfer in data phase + */ +static int ctrlreq_in_data_phase(struct usb_device *dev, u32 len, void *buffer) +{ +	u16 csr; +	u32 rxlen = 0; +	u32 nextlen = 0; +	u8  maxpktsize = (1 << dev->maxpacketsize) * 8; +	u8  *rxbuff = (u8 *)buffer; +	u8  rxedlength; +	int result; + +	while (rxlen < len) { +		/* Determine the next read length */ +		nextlen = ((len-rxlen) > maxpktsize) ? maxpktsize : (len-rxlen); + +		/* Set the ReqPkt bit */ +		csr = readw(&musbr->txcsr); +		writew(csr | MUSB_CSR0_H_REQPKT, &musbr->txcsr); +		result = wait_until_ep0_ready(dev, MUSB_CSR0_RXPKTRDY); +		if (result < 0) +			return result; + +		/* Actual number of bytes received by usb */ +		rxedlength = readb(&musbr->rxcount); + +		/* Read the data from the RxFIFO */ +		read_fifo(MUSB_CONTROL_EP, rxedlength, &rxbuff[rxlen]); + +		/* Clear the RxPktRdy Bit */ +		csr = readw(&musbr->txcsr); +		csr &= ~MUSB_CSR0_RXPKTRDY; +		writew(csr, &musbr->txcsr); + +		/* short packet? */ +		if (rxedlength != nextlen) { +			dev->act_len += rxedlength; +			break; +		} +		rxlen += nextlen; +		dev->act_len = rxlen; +	} +	return 0; +} + +/* + * This function handles the control transfer out data phase + */ +static int ctrlreq_out_data_phase(struct usb_device *dev, u32 len, void *buffer) +{ +	u16 csr; +	u32 txlen = 0; +	u32 nextlen = 0; +	u8  maxpktsize = (1 << dev->maxpacketsize) * 8; +	u8  *txbuff = (u8 *)buffer; +	int result = 0; + +	while (txlen < len) { +		/* Determine the next write length */ +		nextlen = ((len-txlen) > maxpktsize) ? maxpktsize : (len-txlen); + +		/* Load the data to send in FIFO */ +		write_fifo(MUSB_CONTROL_EP, txlen, &txbuff[txlen]); + +		/* Set TXPKTRDY bit */ +		csr = readw(&musbr->txcsr); +			 +		csr |= MUSB_CSR0_TXPKTRDY; +#if !defined(CONFIG_SOC_DM365) +		csr |= MUSB_CSR0_H_DIS_PING; +#endif +		writew(csr, &musbr->txcsr); +		result = wait_until_ep0_ready(dev, MUSB_CSR0_TXPKTRDY); +		if (result < 0) +			break; + +		txlen += nextlen; +		dev->act_len = txlen; +	} +	return result; +} + +/* + * This function handles the control transfer out status phase + */ +static int ctrlreq_out_status_phase(struct usb_device *dev) +{ +	u16 csr; +	int result; + +	/* Set the StatusPkt bit */ +	csr = readw(&musbr->txcsr); +	csr |= (MUSB_CSR0_TXPKTRDY | MUSB_CSR0_H_STATUSPKT); +#if !defined(CONFIG_SOC_DM365) +	csr |= MUSB_CSR0_H_DIS_PING; +#endif +	writew(csr, &musbr->txcsr); + +	/* Wait until TXPKTRDY bit is cleared */ +	result = wait_until_ep0_ready(dev, MUSB_CSR0_TXPKTRDY); +	return result; +} + +/* + * This function handles the control transfer in status phase + */ +static int ctrlreq_in_status_phase(struct usb_device *dev) +{ +	u16 csr; +	int result; + +	/* Set the StatusPkt bit and ReqPkt bit */ +	csr = MUSB_CSR0_H_REQPKT | MUSB_CSR0_H_STATUSPKT; +#if !defined(CONFIG_SOC_DM365) +	csr |= MUSB_CSR0_H_DIS_PING; +#endif +	writew(csr, &musbr->txcsr); +	result = wait_until_ep0_ready(dev, MUSB_CSR0_H_REQPKT); + +	/* clear StatusPkt bit and RxPktRdy bit */ +	csr = readw(&musbr->txcsr); +	csr &= ~(MUSB_CSR0_RXPKTRDY | MUSB_CSR0_H_STATUSPKT); +	writew(csr, &musbr->txcsr); +	return result; +} + +/* + * determines the speed of the device (High/Full/Slow) + */ +static u8 get_dev_speed(struct usb_device *dev) +{ +	return (dev->speed == USB_SPEED_HIGH) ? MUSB_TYPE_SPEED_HIGH : +		((dev->speed == USB_SPEED_LOW) ? MUSB_TYPE_SPEED_LOW : +						MUSB_TYPE_SPEED_FULL); +} + +/* + * configure the hub address and the port address. + */ +static void config_hub_port(struct usb_device *dev, u8 ep) +{ +	u8 chid; +	u8 hub; + +	/* Find out the nearest parent which is high speed */ +	while (dev->parent->parent != NULL) +		if (get_dev_speed(dev->parent) !=  MUSB_TYPE_SPEED_HIGH) +			dev = dev->parent; +		else +			break; + +	/* determine the port address at that hub */ +	hub = dev->parent->devnum; +	for (chid = 0; chid < USB_MAXCHILDREN; chid++) +		if (dev->parent->children[chid] == dev) +			break; + +#ifndef MUSB_NO_MULTIPOINT +	/* configure the hub address and the port address */ +	writeb(hub, &musbr->tar[ep].txhubaddr); +	writeb((chid + 1), &musbr->tar[ep].txhubport); +	writeb(hub, &musbr->tar[ep].rxhubaddr); +	writeb((chid + 1), &musbr->tar[ep].rxhubport); +#endif +} + +#ifdef MUSB_NO_MULTIPOINT + +static void musb_port_reset(int do_reset) +{ +	u8 power = readb(&musbr->power); + +	if (do_reset) { +		power &= 0xf0; +		writeb(power | MUSB_POWER_RESET, &musbr->power); +		port_status |= USB_PORT_STAT_RESET; +		port_status &= ~USB_PORT_STAT_ENABLE; +		udelay(30000); +	} else { +		writeb(power & ~MUSB_POWER_RESET, &musbr->power); + +		power = readb(&musbr->power); +		if (power & MUSB_POWER_HSMODE) +			port_status |= USB_PORT_STAT_HIGH_SPEED; + +		port_status &= ~(USB_PORT_STAT_RESET | (USB_PORT_STAT_C_CONNECTION << 16)); +		port_status |= USB_PORT_STAT_ENABLE +			| (USB_PORT_STAT_C_RESET << 16) +			| (USB_PORT_STAT_C_ENABLE << 16); +	} +} + +/* + * root hub control + */ +static int musb_submit_rh_msg(struct usb_device *dev, unsigned long pipe, +			      void *buffer, int transfer_len, +			      struct devrequest *cmd) +{ +	int leni = transfer_len; +	int len = 0; +	int stat = 0; +	u32 datab[4]; +	const u8 *data_buf = (u8 *) datab; +	u16 bmRType_bReq; +	u16 wValue; +	u16 wIndex; +	u16 wLength; +	u16 int_usb; + +	if ((pipe & PIPE_INTERRUPT) == PIPE_INTERRUPT) { +		debug("Root-Hub submit IRQ: NOT implemented\n"); +		return 0; +	} + +	bmRType_bReq = cmd->requesttype | (cmd->request << 8); +	wValue = swap_16(cmd->value); +	wIndex = swap_16(cmd->index); +	wLength = swap_16(cmd->length); + +	debug("--- HUB ----------------------------------------\n"); +	debug("submit rh urb, req=%x val=%#x index=%#x len=%d\n", +	    bmRType_bReq, wValue, wIndex, wLength); +	debug("------------------------------------------------\n"); + +	switch (bmRType_bReq) { +	case RH_GET_STATUS: +		debug("RH_GET_STATUS\n"); + +		*(__u16 *) data_buf = swap_16(1); +		len = 2; +		break; + +	case RH_GET_STATUS | RH_INTERFACE: +		debug("RH_GET_STATUS | RH_INTERFACE\n"); + +		*(__u16 *) data_buf = swap_16(0); +		len = 2; +		break; + +	case RH_GET_STATUS | RH_ENDPOINT: +		debug("RH_GET_STATUS | RH_ENDPOINT\n"); + +		*(__u16 *) data_buf = swap_16(0); +		len = 2; +		break; + +	case RH_GET_STATUS | RH_CLASS: +		debug("RH_GET_STATUS | RH_CLASS\n"); + +		*(__u32 *) data_buf = swap_32(0); +		len = 4; +		break; + +	case RH_GET_STATUS | RH_OTHER | RH_CLASS: +		debug("RH_GET_STATUS | RH_OTHER | RH_CLASS\n"); + +		int_usb = readw(&musbr->intrusb); +		if (int_usb & MUSB_INTR_CONNECT) { +			port_status |= USB_PORT_STAT_CONNECTION +				| (USB_PORT_STAT_C_CONNECTION << 16); +			port_status |= USB_PORT_STAT_HIGH_SPEED +				| USB_PORT_STAT_ENABLE; +		} + +		if (port_status & USB_PORT_STAT_RESET) +			musb_port_reset(0); + +		*(__u32 *) data_buf = swap_32(port_status); +		len = 4; +		break; + +	case RH_CLEAR_FEATURE | RH_ENDPOINT: +		debug("RH_CLEAR_FEATURE | RH_ENDPOINT\n"); + +		switch (wValue) { +		case RH_ENDPOINT_STALL: +			debug("C_HUB_ENDPOINT_STALL\n"); +			len = 0; +			break; +		} +		port_status &= ~(1 << wValue); +		break; + +	case RH_CLEAR_FEATURE | RH_CLASS: +		debug("RH_CLEAR_FEATURE | RH_CLASS\n"); + +		switch (wValue) { +		case RH_C_HUB_LOCAL_POWER: +			debug("C_HUB_LOCAL_POWER\n"); +			len = 0; +			break; + +		case RH_C_HUB_OVER_CURRENT: +			debug("C_HUB_OVER_CURRENT\n"); +			len = 0; +			break; +		} +		port_status &= ~(1 << wValue); +		break; + +	case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS: +		debug("RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS\n"); + +		switch (wValue) { +		case RH_PORT_ENABLE: +			len = 0; +			break; + +		case RH_PORT_SUSPEND: +			len = 0; +			break; + +		case RH_PORT_POWER: +			len = 0; +			break; + +		case RH_C_PORT_CONNECTION: +			len = 0; +			break; + +		case RH_C_PORT_ENABLE: +			len = 0; +			break; + +		case RH_C_PORT_SUSPEND: +			len = 0; +			break; + +		case RH_C_PORT_OVER_CURRENT: +			len = 0; +			break; + +		case RH_C_PORT_RESET: +			len = 0; +			break; + +		default: +			debug("invalid wValue\n"); +			stat = USB_ST_STALLED; +		} + +		port_status &= ~(1 << wValue); +		break; + +	case RH_SET_FEATURE | RH_OTHER | RH_CLASS: +		debug("RH_SET_FEATURE | RH_OTHER | RH_CLASS\n"); + +		switch (wValue) { +		case RH_PORT_SUSPEND: +			len = 0; +			break; + +		case RH_PORT_RESET: +			musb_port_reset(1); +			len = 0; +			break; + +		case RH_PORT_POWER: +			len = 0; +			break; + +		case RH_PORT_ENABLE: +			len = 0; +			break; + +		default: +			debug("invalid wValue\n"); +			stat = USB_ST_STALLED; +		} + +		port_status |= 1 << wValue; +		break; + +	case RH_SET_ADDRESS: +		debug("RH_SET_ADDRESS\n"); + +		rh_devnum = wValue; +		len = 0; +		break; + +	case RH_GET_DESCRIPTOR: +		debug("RH_GET_DESCRIPTOR: %x, %d\n", wValue, wLength); + +		switch (wValue) { +		case (USB_DT_DEVICE << 8):	/* device descriptor */ +			len = min_t(unsigned int, +				    leni, min_t(unsigned int, +						sizeof(root_hub_dev_des), +						wLength)); +			data_buf = root_hub_dev_des; +			break; + +		case (USB_DT_CONFIG << 8):	/* configuration descriptor */ +			len = min_t(unsigned int, +				    leni, min_t(unsigned int, +						sizeof(root_hub_config_des), +						wLength)); +			data_buf = root_hub_config_des; +			break; + +		case ((USB_DT_STRING << 8) | 0x00):	/* string 0 descriptors */ +			len = min_t(unsigned int, +				    leni, min_t(unsigned int, +						sizeof(root_hub_str_index0), +						wLength)); +			data_buf = root_hub_str_index0; +			break; + +		case ((USB_DT_STRING << 8) | 0x01):	/* string 1 descriptors */ +			len = min_t(unsigned int, +				    leni, min_t(unsigned int, +						sizeof(root_hub_str_index1), +						wLength)); +			data_buf = root_hub_str_index1; +			break; + +		default: +			debug("invalid wValue\n"); +			stat = USB_ST_STALLED; +		} + +		break; + +	case RH_GET_DESCRIPTOR | RH_CLASS: { +		u8 *_data_buf = (u8 *) datab; +		debug("RH_GET_DESCRIPTOR | RH_CLASS\n"); + +		_data_buf[0] = 0x09;	/* min length; */ +		_data_buf[1] = 0x29; +		_data_buf[2] = 0x1;	/* 1 port */ +		_data_buf[3] = 0x01;	/* per-port power switching */ +		_data_buf[3] |= 0x10;	/* no overcurrent reporting */ + +		/* Corresponds to data_buf[4-7] */ +		_data_buf[4] = 0; +		_data_buf[5] = 5; +		_data_buf[6] = 0; +		_data_buf[7] = 0x02; +		_data_buf[8] = 0xff; + +		len = min_t(unsigned int, leni, +			    min_t(unsigned int, data_buf[0], wLength)); +		break; +	} + +	case RH_GET_CONFIGURATION: +		debug("RH_GET_CONFIGURATION\n"); + +		*(__u8 *) data_buf = 0x01; +		len = 1; +		break; + +	case RH_SET_CONFIGURATION: +		debug("RH_SET_CONFIGURATION\n"); + +		len = 0; +		break; + +	default: +		debug("*** *** *** unsupported root hub command *** *** ***\n"); +		stat = USB_ST_STALLED; +	} + +	len = min_t(int, len, leni); +	if (buffer != data_buf) +		memcpy(buffer, data_buf, len); + +	dev->act_len = len; +	dev->status = stat; +	debug("dev act_len %d, status %lu\n", dev->act_len, dev->status); + +	return stat; +} + +static void musb_rh_init(void) +{ +	rh_devnum = 0; +	port_status = 0; +} + +#else + +static void musb_rh_init(void) {} + +#endif + +/* + * do a control transfer + */ +int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, +			int len, struct devrequest *setup) +{ +	int devnum = usb_pipedevice(pipe); +	u8  devspeed; + +#ifdef MUSB_NO_MULTIPOINT +	/* Control message is for the HUB? */ +	if (devnum == rh_devnum) { +		int stat = musb_submit_rh_msg(dev, pipe, buffer, len, setup); +		if (stat) +			return stat; +	} +#endif + +	/* select control endpoint */ +	writeb(MUSB_CONTROL_EP, &musbr->index); +	readw(&musbr->txcsr); + +#ifndef MUSB_NO_MULTIPOINT +	/* target addr and (for multipoint) hub addr/port */ +	writeb(devnum, &musbr->tar[MUSB_CONTROL_EP].txfuncaddr); +	writeb(devnum, &musbr->tar[MUSB_CONTROL_EP].rxfuncaddr); +#endif + +	/* configure the hub address and the port number as required */ +	devspeed = get_dev_speed(dev); +	if ((musb_ishighspeed()) && (dev->parent != NULL) && +		(devspeed != MUSB_TYPE_SPEED_HIGH)) { +		config_hub_port(dev, MUSB_CONTROL_EP); +		writeb(devspeed << 6, &musbr->txtype); +	} else { +		writeb(musb_cfg.musb_speed << 6, &musbr->txtype); +#ifndef MUSB_NO_MULTIPOINT +		writeb(0, &musbr->tar[MUSB_CONTROL_EP].txhubaddr); +		writeb(0, &musbr->tar[MUSB_CONTROL_EP].txhubport); +		writeb(0, &musbr->tar[MUSB_CONTROL_EP].rxhubaddr); +		writeb(0, &musbr->tar[MUSB_CONTROL_EP].rxhubport); +#endif +	} + +	/* Control transfer setup phase */ +	if (ctrlreq_setup_phase(dev, setup) < 0) +		return 0; + +	switch (setup->request) { +	case USB_REQ_GET_DESCRIPTOR: +	case USB_REQ_GET_CONFIGURATION: +	case USB_REQ_GET_INTERFACE: +	case USB_REQ_GET_STATUS: +	case USB_MSC_BBB_GET_MAX_LUN: +		/* control transfer in-data-phase */ +		if (ctrlreq_in_data_phase(dev, len, buffer) < 0) +			return 0; +		/* control transfer out-status-phase */ +		if (ctrlreq_out_status_phase(dev) < 0) +			return 0; +		break; + +	case USB_REQ_SET_ADDRESS: +	case USB_REQ_SET_CONFIGURATION: +	case USB_REQ_SET_FEATURE: +	case USB_REQ_SET_INTERFACE: +	case USB_REQ_CLEAR_FEATURE: +	case USB_MSC_BBB_RESET: +		/* control transfer in status phase */ +		if (ctrlreq_in_status_phase(dev) < 0) +			return 0; +		break; + +	case USB_REQ_SET_DESCRIPTOR: +		/* control transfer out data phase */ +		if (ctrlreq_out_data_phase(dev, len, buffer) < 0) +			return 0; +		/* control transfer in status phase */ +		if (ctrlreq_in_status_phase(dev) < 0) +			return 0; +		break; + +	default: +		/* unhandled control transfer */ +		return -1; +	} + +	dev->status = 0; +	dev->act_len = len; + +#ifdef MUSB_NO_MULTIPOINT +	/* Set device address to USB_FADDR register */ +	if (setup->request == USB_REQ_SET_ADDRESS) +		writeb(dev->devnum, &musbr->faddr); +#endif + +	return len; +} + +/* + * do a bulk transfer + */ +int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, +					void *buffer, int len) +{ +	int dir_out = usb_pipeout(pipe); +	int ep = usb_pipeendpoint(pipe); +#ifndef MUSB_NO_MULTIPOINT +	int devnum = usb_pipedevice(pipe); +#endif +	u8  type; +	u16 csr; +	u32 txlen = 0; +	u32 nextlen = 0; +	u8  devspeed; + +	/* select bulk endpoint */ +	writeb(MUSB_BULK_EP, &musbr->index); + +#ifndef MUSB_NO_MULTIPOINT +	/* write the address of the device */ +	if (dir_out) +		writeb(devnum, &musbr->tar[MUSB_BULK_EP].txfuncaddr); +	else +		writeb(devnum, &musbr->tar[MUSB_BULK_EP].rxfuncaddr); +#endif + +	/* configure the hub address and the port number as required */ +	devspeed = get_dev_speed(dev); +	if ((musb_ishighspeed()) && (dev->parent != NULL) && +		(devspeed != MUSB_TYPE_SPEED_HIGH)) { +		/* +		 * MUSB is in high speed and the destination device is full +		 * speed device. So configure the hub address and port +		 * address registers. +		 */ +		config_hub_port(dev, MUSB_BULK_EP); +	} else { +#ifndef MUSB_NO_MULTIPOINT +		if (dir_out) { +			writeb(0, &musbr->tar[MUSB_BULK_EP].txhubaddr); +			writeb(0, &musbr->tar[MUSB_BULK_EP].txhubport); +		} else { +			writeb(0, &musbr->tar[MUSB_BULK_EP].rxhubaddr); +			writeb(0, &musbr->tar[MUSB_BULK_EP].rxhubport); +		} +#endif +		devspeed = musb_cfg.musb_speed; +	} + +	/* Write the saved toggle bit value */ +	write_toggle(dev, ep, dir_out); + +	if (dir_out) { /* bulk-out transfer */ +		/* Program the TxType register */ +		type = (devspeed << MUSB_TYPE_SPEED_SHIFT) | +			   (MUSB_TYPE_PROTO_BULK << MUSB_TYPE_PROTO_SHIFT) | +			   (ep & MUSB_TYPE_REMOTE_END); +		writeb(type, &musbr->txtype); + +		/* Write maximum packet size to the TxMaxp register */ +		writew(dev->epmaxpacketout[ep], &musbr->txmaxp); +		while (txlen < len) { +			nextlen = ((len-txlen) < dev->epmaxpacketout[ep]) ? +					(len-txlen) : dev->epmaxpacketout[ep]; + +#ifdef CONFIG_USB_BLACKFIN +			/* Set the transfer data size */ +			writew(nextlen, &musbr->txcount); +#endif + +			/* Write the data to the FIFO */ +			write_fifo(MUSB_BULK_EP, nextlen, +					(void *)(((u8 *)buffer) + txlen)); + +			/* Set the TxPktRdy bit */ +			csr = readw(&musbr->txcsr); +			writew(csr | MUSB_TXCSR_TXPKTRDY, &musbr->txcsr); + +			/* Wait until the TxPktRdy bit is cleared */ +			if (wait_until_txep_ready(dev, MUSB_BULK_EP) != 1) { +				readw(&musbr->txcsr); +				usb_settoggle(dev, ep, dir_out, +				(csr >> MUSB_TXCSR_H_DATATOGGLE_SHIFT) & 1); +				dev->act_len = txlen; +				return 0; +			} +			txlen += nextlen; +		} + +		/* Keep a copy of the data toggle bit */ +		csr = readw(&musbr->txcsr); +		usb_settoggle(dev, ep, dir_out, +				(csr >> MUSB_TXCSR_H_DATATOGGLE_SHIFT) & 1); +	} else { /* bulk-in transfer */ +		/* Write the saved toggle bit value */ +		write_toggle(dev, ep, dir_out); + +		/* Program the RxType register */ +		type = (devspeed << MUSB_TYPE_SPEED_SHIFT) | +			   (MUSB_TYPE_PROTO_BULK << MUSB_TYPE_PROTO_SHIFT) | +			   (ep & MUSB_TYPE_REMOTE_END); +		writeb(type, &musbr->rxtype); + +		/* Write the maximum packet size to the RxMaxp register */ +		writew(dev->epmaxpacketin[ep], &musbr->rxmaxp); +		while (txlen < len) { +			nextlen = ((len-txlen) < dev->epmaxpacketin[ep]) ? +					(len-txlen) : dev->epmaxpacketin[ep]; + +			/* Set the ReqPkt bit */ +			csr = readw(&musbr->rxcsr); +			writew(csr | MUSB_RXCSR_H_REQPKT, &musbr->rxcsr); + +			/* Wait until the RxPktRdy bit is set */ +			if (wait_until_rxep_ready(dev, MUSB_BULK_EP) != 1) { +				csr = readw(&musbr->rxcsr); +				usb_settoggle(dev, ep, dir_out, +				(csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1); +				csr &= ~MUSB_RXCSR_RXPKTRDY; +				writew(csr, &musbr->rxcsr); +				dev->act_len = txlen; +				return 0; +			} + +			/* Read the data from the FIFO */ +			read_fifo(MUSB_BULK_EP, nextlen, +					(void *)(((u8 *)buffer) + txlen)); + +			/* Clear the RxPktRdy bit */ +			csr =  readw(&musbr->rxcsr); +			csr &= ~MUSB_RXCSR_RXPKTRDY; +			writew(csr, &musbr->rxcsr); +			txlen += nextlen; +		} + +		/* Keep a copy of the data toggle bit */ +		csr = readw(&musbr->rxcsr); +		usb_settoggle(dev, ep, dir_out, +				(csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1); +	} + +	/* bulk transfer is complete */ +	dev->status = 0; +	dev->act_len = len; +	return 0; +} + +/* + * This function initializes the usb controller module. + */ +int usb_lowlevel_init(int index, enum usb_init_type init, void **controller) +{ +	u8  power; +	u32 timeout; + +	musb_rh_init(); + +	if (musb_platform_init() == -1) +		return -1; + +	/* Configure all the endpoint FIFO's and start usb controller */ +	musbr = musb_cfg.regs; +	musb_configure_ep(&epinfo[0], ARRAY_SIZE(epinfo)); +	musb_start(); + +	/* +	 * Wait until musb is enabled in host mode with a timeout. There +	 * should be a usb device connected. +	 */ +	timeout = musb_cfg.timeout; +	while (--timeout) +		if (readb(&musbr->devctl) & MUSB_DEVCTL_HM) +			break; + +	/* if musb core is not in host mode, then return */ +	if (!timeout) +		return -1; + +	/* start usb bus reset */ +	power = readb(&musbr->power); +	writeb(power | MUSB_POWER_RESET, &musbr->power); + +	/* After initiating a usb reset, wait for about 20ms to 30ms */ +	udelay(30000); + +	/* stop usb bus reset */ +	power = readb(&musbr->power); +	power &= ~MUSB_POWER_RESET; +	writeb(power, &musbr->power); + +	/* Determine if the connected device is a high/full/low speed device */ +	musb_cfg.musb_speed = (readb(&musbr->power) & MUSB_POWER_HSMODE) ? +			MUSB_TYPE_SPEED_HIGH : +			((readb(&musbr->devctl) & MUSB_DEVCTL_FSDEV) ? +			MUSB_TYPE_SPEED_FULL : MUSB_TYPE_SPEED_LOW); +	return 0; +} + +/* + * This function stops the operation of the davinci usb module. + */ +int usb_lowlevel_stop(int index) +{ +	/* Reset the USB module */ +	musb_platform_deinit(); +	writeb(0, &musbr->devctl); +	return 0; +} + +/* + * This function supports usb interrupt transfers. Currently, usb interrupt + * transfers are not supported. + */ +int submit_int_msg(struct usb_device *dev, unsigned long pipe, +				void *buffer, int len, int interval) +{ +	int dir_out = usb_pipeout(pipe); +	int ep = usb_pipeendpoint(pipe); +#ifndef MUSB_NO_MULTIPOINT +	int devnum = usb_pipedevice(pipe); +#endif +	u8  type; +	u16 csr; +	u32 txlen = 0; +	u32 nextlen = 0; +	u8  devspeed; + +	/* select interrupt endpoint */ +	writeb(MUSB_INTR_EP, &musbr->index); + +#ifndef MUSB_NO_MULTIPOINT +	/* write the address of the device */ +	if (dir_out) +		writeb(devnum, &musbr->tar[MUSB_INTR_EP].txfuncaddr); +	else +		writeb(devnum, &musbr->tar[MUSB_INTR_EP].rxfuncaddr); +#endif + +	/* configure the hub address and the port number as required */ +	devspeed = get_dev_speed(dev); +	if ((musb_ishighspeed()) && (dev->parent != NULL) && +		(devspeed != MUSB_TYPE_SPEED_HIGH)) { +		/* +		 * MUSB is in high speed and the destination device is full +		 * speed device. So configure the hub address and port +		 * address registers. +		 */ +		config_hub_port(dev, MUSB_INTR_EP); +	} else { +#ifndef MUSB_NO_MULTIPOINT +		if (dir_out) { +			writeb(0, &musbr->tar[MUSB_INTR_EP].txhubaddr); +			writeb(0, &musbr->tar[MUSB_INTR_EP].txhubport); +		} else { +			writeb(0, &musbr->tar[MUSB_INTR_EP].rxhubaddr); +			writeb(0, &musbr->tar[MUSB_INTR_EP].rxhubport); +		} +#endif +		devspeed = musb_cfg.musb_speed; +	} + +	/* Write the saved toggle bit value */ +	write_toggle(dev, ep, dir_out); + +	if (!dir_out) { /* intrrupt-in transfer */ +		/* Write the saved toggle bit value */ +		write_toggle(dev, ep, dir_out); +		writeb(interval, &musbr->rxinterval); + +		/* Program the RxType register */ +		type = (devspeed << MUSB_TYPE_SPEED_SHIFT) | +			   (MUSB_TYPE_PROTO_INTR << MUSB_TYPE_PROTO_SHIFT) | +			   (ep & MUSB_TYPE_REMOTE_END); +		writeb(type, &musbr->rxtype); + +		/* Write the maximum packet size to the RxMaxp register */ +		writew(dev->epmaxpacketin[ep], &musbr->rxmaxp); + +		while (txlen < len) { +			nextlen = ((len-txlen) < dev->epmaxpacketin[ep]) ? +					(len-txlen) : dev->epmaxpacketin[ep]; + +			/* Set the ReqPkt bit */ +			csr = readw(&musbr->rxcsr); +			writew(csr | MUSB_RXCSR_H_REQPKT, &musbr->rxcsr); + +			/* Wait until the RxPktRdy bit is set */ +			if (wait_until_rxep_ready(dev, MUSB_INTR_EP) != 1) { +				csr = readw(&musbr->rxcsr); +				usb_settoggle(dev, ep, dir_out, +				(csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1); +				csr &= ~MUSB_RXCSR_RXPKTRDY; +				writew(csr, &musbr->rxcsr); +				dev->act_len = txlen; +				return 0; +			} + +			/* Read the data from the FIFO */ +			read_fifo(MUSB_INTR_EP, nextlen, +					(void *)(((u8 *)buffer) + txlen)); + +			/* Clear the RxPktRdy bit */ +			csr =  readw(&musbr->rxcsr); +			csr &= ~MUSB_RXCSR_RXPKTRDY; +			writew(csr, &musbr->rxcsr); +			txlen += nextlen; +		} + +		/* Keep a copy of the data toggle bit */ +		csr = readw(&musbr->rxcsr); +		usb_settoggle(dev, ep, dir_out, +				(csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1); +	} + +	/* interrupt transfer is complete */ +	dev->irq_status = 0; +	dev->irq_act_len = len; +	dev->irq_handle(dev); +	dev->status = 0; +	dev->act_len = len; +	return 0; +} diff --git a/roms/u-boot/drivers/usb/musb/musb_hcd.h b/roms/u-boot/drivers/usb/musb/musb_hcd.h new file mode 100644 index 00000000..02b9adcb --- /dev/null +++ b/roms/u-boot/drivers/usb/musb/musb_hcd.h @@ -0,0 +1,99 @@ +/* + * Mentor USB OTG Core host controller driver. + * + * Copyright (c) 2008 Texas Instruments + * + * SPDX-License-Identifier:	GPL-2.0+ + * + * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments + */ + +#ifndef __MUSB_HCD_H__ +#define __MUSB_HCD_H__ + +#include "musb_core.h" +#ifdef CONFIG_USB_KEYBOARD +#include <stdio_dev.h> +extern unsigned char new[]; +#endif + +#ifndef CONFIG_MUSB_TIMEOUT +# define CONFIG_MUSB_TIMEOUT 100000 +#endif + +/* This defines the endpoint number used for control transfers */ +#define MUSB_CONTROL_EP 0 + +/* This defines the endpoint number used for bulk transfer */ +#ifndef MUSB_BULK_EP +# define MUSB_BULK_EP 1 +#endif + +/* This defines the endpoint number used for interrupt transfer */ +#define MUSB_INTR_EP 2 + +/* Determine the operating speed of MUSB core */ +#define musb_ishighspeed() \ +	((readb(&musbr->power) & MUSB_POWER_HSMODE) \ +		>> MUSB_POWER_HSMODE_SHIFT) + +#define min_t(type, x, y)	\ +	({ type __x = (x); type __y = (y); __x < __y ? __x : __y; }) + +/* USB HUB CONSTANTS (not OHCI-specific; see hub.h) */ + +/* destination of request */ +#define RH_INTERFACE		   0x01 +#define RH_ENDPOINT		   0x02 +#define RH_OTHER		   0x03 + +#define RH_CLASS		   0x20 +#define RH_VENDOR		   0x40 + +/* Requests: bRequest << 8 | bmRequestType */ +#define RH_GET_STATUS		0x0080 +#define RH_CLEAR_FEATURE	0x0100 +#define RH_SET_FEATURE		0x0300 +#define RH_SET_ADDRESS		0x0500 +#define RH_GET_DESCRIPTOR	0x0680 +#define RH_SET_DESCRIPTOR	0x0700 +#define RH_GET_CONFIGURATION	0x0880 +#define RH_SET_CONFIGURATION	0x0900 +#define RH_GET_STATE		0x0280 +#define RH_GET_INTERFACE	0x0A80 +#define RH_SET_INTERFACE	0x0B00 +#define RH_SYNC_FRAME		0x0C80 +/* Our Vendor Specific Request */ +#define RH_SET_EP		0x2000 + +/* Hub port features */ +#define RH_PORT_CONNECTION	   0x00 +#define RH_PORT_ENABLE		   0x01 +#define RH_PORT_SUSPEND		   0x02 +#define RH_PORT_OVER_CURRENT	   0x03 +#define RH_PORT_RESET		   0x04 +#define RH_PORT_POWER		   0x08 +#define RH_PORT_LOW_SPEED	   0x09 + +#define RH_C_PORT_CONNECTION	   0x10 +#define RH_C_PORT_ENABLE	   0x11 +#define RH_C_PORT_SUSPEND	   0x12 +#define RH_C_PORT_OVER_CURRENT	   0x13 +#define RH_C_PORT_RESET		   0x14 + +/* Hub features */ +#define RH_C_HUB_LOCAL_POWER	   0x00 +#define RH_C_HUB_OVER_CURRENT	   0x01 + +#define RH_DEVICE_REMOTE_WAKEUP	   0x00 +#define RH_ENDPOINT_STALL	   0x01 + +#define RH_ACK			   0x01 +#define RH_REQ_ERR		   -1 +#define RH_NACK			   0x00 + +/* extern functions */ +extern int musb_platform_init(void); +extern void musb_platform_deinit(void); + +#endif	/* __MUSB_HCD_H__ */ diff --git a/roms/u-boot/drivers/usb/musb/musb_udc.c b/roms/u-boot/drivers/usb/musb/musb_udc.c new file mode 100644 index 00000000..87640f4e --- /dev/null +++ b/roms/u-boot/drivers/usb/musb/musb_udc.c @@ -0,0 +1,959 @@ +/* + * Copyright (c) 2009 Wind River Systems, Inc. + * Tom Rix <Tom.Rix@windriver.com> + * + * This file is a rewrite of the usb device part of + * repository git.omapzoom.org/repo/u-boot.git, branch master, + * file cpu/omap3/fastboot.c + * + * This is the unique part of its copyright : + * + * ------------------------------------------------------------------------- + * + * (C) Copyright 2008 - 2009 + * Windriver, <www.windriver.com> + * Tom Rix <Tom.Rix@windriver.com> + * + * ------------------------------------------------------------------------- + * + * The details of connecting the device to the uboot usb device subsystem + * came from the old omap3 repository www.sakoman.net/u-boot-omap3.git, + * branch omap3-dev-usb, file drivers/usb/usbdcore_musb.c + * + * This is the unique part of its copyright : + * + * ------------------------------------------------------------------------- + * + * (C) Copyright 2008 Texas Instruments Incorporated. + * + * Based on + * u-boot OMAP1510 USB drivers (drivers/usbdcore_omap1510.c) + * twl4030 init based on linux (drivers/i2c/chips/twl4030_usb.c) + * + * Author: Diego Dompe (diego.dompe@ridgerun.com) + *         Atin Malaviya (atin.malaviya@gmail.com) + * + * ------------------------------------------------------------------------- + * + * SPDX-License-Identifier:	GPL-2.0+ + */ + +#include <common.h> +#include <usbdevice.h> +#include <usb/udc.h> +#include "../gadget/ep0.h" +#include "musb_core.h" +#if defined(CONFIG_USB_OMAP3) +#include "omap3.h" +#elif defined(CONFIG_USB_AM35X) +#include "am35x.h" +#elif defined(CONFIG_USB_DAVINCI) +#include "davinci.h" +#endif + +/* Define MUSB_DEBUG for debugging */ +/* #define MUSB_DEBUG */ +#include "musb_debug.h" + +#define MAX_ENDPOINT 15 + +#define GET_ENDPOINT(dev,ep)						\ +(((struct usb_device_instance *)(dev))->bus->endpoint_array + ep) + +#define SET_EP0_STATE(s)						\ +do {									\ +	if ((0 <= (s)) && (SET_ADDRESS >= (s))) {			\ +		if ((s) != ep0_state) {					\ +			if ((debug_setup) && (debug_level > 1))		\ +				serial_printf("INFO : Changing state "  \ +					      "from %s to %s in %s at " \ +					      "line %d\n",		\ +					      ep0_state_strings[ep0_state],\ +					      ep0_state_strings[s],	\ +					      __PRETTY_FUNCTION__,	\ +					      __LINE__);		\ +			ep0_state = s;					\ +		}							\ +	} else {							\ +		if (debug_level > 0)					\ +			serial_printf("Error at %s %d with setting "	\ +				      "state %d is invalid\n",		\ +				      __PRETTY_FUNCTION__, __LINE__, s); \ +	}								\ +} while (0) + +/* static implies these initialized to 0 or NULL */ +static int debug_setup; +static int debug_level; +static struct musb_epinfo epinfo[MAX_ENDPOINT * 2]; +static enum ep0_state_enum { +	IDLE = 0, +	TX, +	RX, +	SET_ADDRESS +} ep0_state = IDLE; +static char *ep0_state_strings[4] = { +	"IDLE", +	"TX", +	"RX", +	"SET_ADDRESS", +}; + +static struct urb *ep0_urb; +struct usb_endpoint_instance *ep0_endpoint; +static struct usb_device_instance *udc_device; +static int enabled; + +#ifdef MUSB_DEBUG +static void musb_db_regs(void) +{ +	u8 b; +	u16 w; + +	b = readb(&musbr->faddr); +	serial_printf("\tfaddr   0x%2.2x\n", b); + +	b = readb(&musbr->power); +	musb_print_pwr(b); + +	w = readw(&musbr->ep[0].ep0.csr0); +	musb_print_csr0(w); + +	b = readb(&musbr->devctl); +	musb_print_devctl(b); + +	b = readb(&musbr->ep[0].ep0.configdata); +	musb_print_config(b); + +	w = readw(&musbr->frame); +	serial_printf("\tframe   0x%4.4x\n", w); + +	b = readb(&musbr->index); +	serial_printf("\tindex   0x%2.2x\n", b); + +	w = readw(&musbr->ep[1].epN.rxmaxp); +	musb_print_rxmaxp(w); + +	w = readw(&musbr->ep[1].epN.rxcsr); +	musb_print_rxcsr(w); + +	w = readw(&musbr->ep[1].epN.txmaxp); +	musb_print_txmaxp(w); + +	w = readw(&musbr->ep[1].epN.txcsr); +	musb_print_txcsr(w); +} +#else +#define musb_db_regs() +#endif /* DEBUG_MUSB */ + +static void musb_peri_softconnect(void) +{ +	u8 power, devctl; + +	/* Power off MUSB */ +	power = readb(&musbr->power); +	power &= ~MUSB_POWER_SOFTCONN; +	writeb(power, &musbr->power); + +	/* Read intr to clear */ +	readb(&musbr->intrusb); +	readw(&musbr->intrrx); +	readw(&musbr->intrtx); + +	udelay(1000 * 1000); /* 1 sec */ + +	/* Power on MUSB */ +	power = readb(&musbr->power); +	power |= MUSB_POWER_SOFTCONN; +	/* +	 * The usb device interface is usb 1.1 +	 * Disable 2.0 high speed by clearring the hsenable bit. +	 */ +	power &= ~MUSB_POWER_HSENAB; +	writeb(power, &musbr->power); + +	/* Check if device is in b-peripheral mode */ +	devctl = readb(&musbr->devctl); +	if (!(devctl & MUSB_DEVCTL_BDEVICE) || +	    (devctl & MUSB_DEVCTL_HM)) { +		serial_printf("ERROR : Unsupport USB mode\n"); +		serial_printf("Check that mini-B USB cable is attached " +			      "to the device\n"); +	} + +	if (debug_setup && (debug_level > 1)) +		musb_db_regs(); +} + +static void musb_peri_reset(void) +{ +	if ((debug_setup) && (debug_level > 1)) +		serial_printf("INFO : %s reset\n", __PRETTY_FUNCTION__); + +	if (ep0_endpoint) +		ep0_endpoint->endpoint_address = 0xff; + +	/* Sync sw and hw addresses */ +	writeb(udc_device->address, &musbr->faddr); + +	SET_EP0_STATE(IDLE); +} + +static void musb_peri_resume(void) +{ +	/* noop */ +} + +static void musb_peri_ep0_stall(void) +{ +	u16 csr0; + +	csr0 = readw(&musbr->ep[0].ep0.csr0); +	csr0 |= MUSB_CSR0_P_SENDSTALL; +	writew(csr0, &musbr->ep[0].ep0.csr0); +	if ((debug_setup) && (debug_level > 1)) +		serial_printf("INFO : %s stall\n", __PRETTY_FUNCTION__); +} + +static void musb_peri_ep0_ack_req(void) +{ +	u16 csr0; + +	csr0 = readw(&musbr->ep[0].ep0.csr0); +	csr0 |= MUSB_CSR0_P_SVDRXPKTRDY; +	writew(csr0, &musbr->ep[0].ep0.csr0); +} + +static void musb_ep0_tx_ready(void) +{ +	u16 csr0; + +	csr0 = readw(&musbr->ep[0].ep0.csr0); +	csr0 |= MUSB_CSR0_TXPKTRDY; +	writew(csr0, &musbr->ep[0].ep0.csr0); +} + +static void musb_ep0_tx_ready_and_last(void) +{ +	u16 csr0; + +	csr0 = readw(&musbr->ep[0].ep0.csr0); +	csr0 |= (MUSB_CSR0_TXPKTRDY | MUSB_CSR0_P_DATAEND); +	writew(csr0, &musbr->ep[0].ep0.csr0); +} + +static void musb_peri_ep0_last(void) +{ +	u16 csr0; + +	csr0 = readw(&musbr->ep[0].ep0.csr0); +	csr0 |= MUSB_CSR0_P_DATAEND; +	writew(csr0, &musbr->ep[0].ep0.csr0); +} + +static void musb_peri_ep0_set_address(void) +{ +	u8 faddr; +	writeb(udc_device->address, &musbr->faddr); + +	/* Verify */ +	faddr = readb(&musbr->faddr); +	if (udc_device->address == faddr) { +		SET_EP0_STATE(IDLE); +		usbd_device_event_irq(udc_device, DEVICE_ADDRESS_ASSIGNED, 0); +		if ((debug_setup) && (debug_level > 1)) +			serial_printf("INFO : %s Address set to %d\n", +				      __PRETTY_FUNCTION__, udc_device->address); +	} else { +		if (debug_level > 0) +			serial_printf("ERROR : %s Address missmatch " +				      "sw %d vs hw %d\n", +				      __PRETTY_FUNCTION__, +				      udc_device->address, faddr); +	} +} + +static void musb_peri_rx_ack(unsigned int ep) +{ +	u16 peri_rxcsr; + +	peri_rxcsr = readw(&musbr->ep[ep].epN.rxcsr); +	peri_rxcsr &= ~MUSB_RXCSR_RXPKTRDY; +	writew(peri_rxcsr, &musbr->ep[ep].epN.rxcsr); +} + +static void musb_peri_tx_ready(unsigned int ep) +{ +	u16 peri_txcsr; + +	peri_txcsr = readw(&musbr->ep[ep].epN.txcsr); +	peri_txcsr |= MUSB_TXCSR_TXPKTRDY; +	writew(peri_txcsr, &musbr->ep[ep].epN.txcsr); +} + +static void musb_peri_ep0_zero_data_request(int err) +{ +	musb_peri_ep0_ack_req(); + +	if (err) { +		musb_peri_ep0_stall(); +		SET_EP0_STATE(IDLE); +	} else { + +		musb_peri_ep0_last(); + +		/* USBD state */ +		switch (ep0_urb->device_request.bRequest) { +		case USB_REQ_SET_ADDRESS: +			if ((debug_setup) && (debug_level > 1)) +				serial_printf("INFO : %s received set " +					      "address\n", __PRETTY_FUNCTION__); +			break; + +		case USB_REQ_SET_CONFIGURATION: +			if ((debug_setup) && (debug_level > 1)) +				serial_printf("INFO : %s Configured\n", +					      __PRETTY_FUNCTION__); +			usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0); +			break; +		} + +		/* EP0 state */ +		if (USB_REQ_SET_ADDRESS == ep0_urb->device_request.bRequest) { +			SET_EP0_STATE(SET_ADDRESS); +		} else { +			SET_EP0_STATE(IDLE); +		} +	} +} + +static void musb_peri_ep0_rx_data_request(void) +{ +	/* +	 * This is the completion of the data OUT / RX +	 * +	 * Host is sending data to ep0 that is not +	 * part of setup.  This comes from the cdc_recv_setup +	 * op that is device specific. +	 * +	 */ +	musb_peri_ep0_ack_req(); + +	ep0_endpoint->rcv_urb = ep0_urb; +	ep0_urb->actual_length = 0; +	SET_EP0_STATE(RX); +} + +static void musb_peri_ep0_tx_data_request(int err) +{ +	if (err) { +		musb_peri_ep0_stall(); +		SET_EP0_STATE(IDLE); +	} else { +		musb_peri_ep0_ack_req(); + +		ep0_endpoint->tx_urb = ep0_urb; +		ep0_endpoint->sent = 0; +		SET_EP0_STATE(TX); +	} +} + +static void musb_peri_ep0_idle(void) +{ +	u16 count0; +	int err; +	u16 csr0; + +	/* +	 * Verify addresses +	 * A lot of confusion can be caused if the address +	 * in software, udc layer, does not agree with the +	 * hardware.  Since the setting of the hardware address +	 * must be set after the set address request, the +	 * usb state machine is out of sync for a few frame. +	 * It is a good idea to run this check when changes +	 * are made to the state machine. +	 */ +	if ((debug_level > 0) && +	    (ep0_state != SET_ADDRESS)) { +		u8 faddr; + +		faddr = readb(&musbr->faddr); +		if (udc_device->address != faddr) { +			serial_printf("ERROR : %s addresses do not" +				      "match sw %d vs hw %d\n", +				      __PRETTY_FUNCTION__, +				      udc_device->address, faddr); +			udelay(1000 * 1000); +			hang(); +		} +	} + +	csr0 = readw(&musbr->ep[0].ep0.csr0); + +	if (!(MUSB_CSR0_RXPKTRDY & csr0)) +		goto end; + +	count0 = readw(&musbr->ep[0].ep0.count0); +	if (count0 == 0) +		goto end; + +	if (count0 != 8) { +		if ((debug_setup) && (debug_level > 1)) +			serial_printf("WARN : %s SETUP incorrect size %d\n", +				      __PRETTY_FUNCTION__, count0); +		musb_peri_ep0_stall(); +		goto end; +	} + +	read_fifo(0, count0, &ep0_urb->device_request); + +	if (debug_level > 2) +		print_usb_device_request(&ep0_urb->device_request); + +	if (ep0_urb->device_request.wLength == 0) { +		err = ep0_recv_setup(ep0_urb); + +		/* Zero data request */ +		musb_peri_ep0_zero_data_request(err); +	} else { +		/* Is data coming or going ? */ +		u8 reqType = ep0_urb->device_request.bmRequestType; + +		if (USB_REQ_DEVICE2HOST == (reqType & USB_REQ_DIRECTION_MASK)) { +			err = ep0_recv_setup(ep0_urb); +			/* Device to host */ +			musb_peri_ep0_tx_data_request(err); +		} else { +			/* +			 * Host to device +			 * +			 * The RX routine will call ep0_recv_setup +			 * when the data packet has arrived. +			 */ +			musb_peri_ep0_rx_data_request(); +		} +	} + +end: +	return; +} + +static void musb_peri_ep0_rx(void) +{ +	/* +	 * This is the completion of the data OUT / RX +	 * +	 * Host is sending data to ep0 that is not +	 * part of setup.  This comes from the cdc_recv_setup +	 * op that is device specific. +	 * +	 * Pass the data back to driver ep0_recv_setup which +	 * should give the cdc_recv_setup the chance to handle +	 * the rx +	 */ +	u16 csr0; +	u16 count0; + +	if (debug_level > 3) { +		if (0 != ep0_urb->actual_length) { +			serial_printf("%s finished ? %d of %d\n", +				      __PRETTY_FUNCTION__, +				      ep0_urb->actual_length, +				      ep0_urb->device_request.wLength); +		} +	} + +	if (ep0_urb->device_request.wLength == ep0_urb->actual_length) { +		musb_peri_ep0_last(); +		SET_EP0_STATE(IDLE); +		ep0_recv_setup(ep0_urb); +		return; +	} + +	csr0 = readw(&musbr->ep[0].ep0.csr0); +	if (!(MUSB_CSR0_RXPKTRDY & csr0)) +		return; + +	count0 = readw(&musbr->ep[0].ep0.count0); + +	if (count0) { +		struct usb_endpoint_instance *endpoint; +		u32 length; +		u8 *data; + +		endpoint = ep0_endpoint; +		if (endpoint && endpoint->rcv_urb) { +			struct urb *urb = endpoint->rcv_urb; +			unsigned int remaining_space = urb->buffer_length - +				urb->actual_length; + +			if (remaining_space) { +				int urb_bad = 0; /* urb is good */ + +				if (count0 > remaining_space) +					length = remaining_space; +				else +					length = count0; + +				data = (u8 *) urb->buffer_data; +				data += urb->actual_length; + +				/* The common musb fifo reader */ +				read_fifo(0, length, data); + +				musb_peri_ep0_ack_req(); + +				/* +				 * urb's actual_length is updated in +				 * usbd_rcv_complete +				 */ +				usbd_rcv_complete(endpoint, length, urb_bad); + +			} else { +				if (debug_level > 0) +					serial_printf("ERROR : %s no space in " +						      "rcv buffer\n", +						      __PRETTY_FUNCTION__); +			} +		} else { +			if (debug_level > 0) +				serial_printf("ERROR : %s problem with " +					      "endpoint\n", +					      __PRETTY_FUNCTION__); +		} +	} else { +		if (debug_level > 0) +			serial_printf("ERROR : %s with nothing to do\n", +				      __PRETTY_FUNCTION__); +	} +} + +static void musb_peri_ep0_tx(void) +{ +	u16 csr0; +	int transfer_size = 0; +	unsigned int p, pm; + +	csr0 = readw(&musbr->ep[0].ep0.csr0); + +	/* Check for pending tx */ +	if (csr0 & MUSB_CSR0_TXPKTRDY) +		goto end; + +	/* Check if this is the last packet sent */ +	if (ep0_endpoint->sent >= ep0_urb->actual_length) { +		SET_EP0_STATE(IDLE); +		goto end; +	} + +	transfer_size = ep0_urb->actual_length - ep0_endpoint->sent; +	/* Is the transfer size negative ? */ +	if (transfer_size <= 0) { +		if (debug_level > 0) +			serial_printf("ERROR : %s problem with the" +				      " transfer size %d\n", +				      __PRETTY_FUNCTION__, +				      transfer_size); +		SET_EP0_STATE(IDLE); +		goto end; +	} + +	/* Truncate large transfers to the fifo size */ +	if (transfer_size > ep0_endpoint->tx_packetSize) +		transfer_size = ep0_endpoint->tx_packetSize; + +	write_fifo(0, transfer_size, &ep0_urb->buffer[ep0_endpoint->sent]); +	ep0_endpoint->sent += transfer_size; + +	/* Done or more to send ? */ +	if (ep0_endpoint->sent >= ep0_urb->actual_length) +		musb_ep0_tx_ready_and_last(); +	else +		musb_ep0_tx_ready(); + +	/* Wait a bit */ +	pm = 10; +	for (p = 0; p < pm; p++) { +		csr0 = readw(&musbr->ep[0].ep0.csr0); +		if (!(csr0 & MUSB_CSR0_TXPKTRDY)) +			break; + +		/* Double the delay. */ +		udelay(1 << pm); +	} + +	if ((ep0_endpoint->sent >= ep0_urb->actual_length) && (p < pm)) +		SET_EP0_STATE(IDLE); + +end: +	return; +} + +static void musb_peri_ep0(void) +{ +	u16 csr0; + +	if (SET_ADDRESS == ep0_state) +		return; + +	csr0 = readw(&musbr->ep[0].ep0.csr0); + +	/* Error conditions */ +	if (MUSB_CSR0_P_SENTSTALL & csr0) { +		csr0 &= ~MUSB_CSR0_P_SENTSTALL; +		writew(csr0, &musbr->ep[0].ep0.csr0); +		SET_EP0_STATE(IDLE); +	} +	if (MUSB_CSR0_P_SETUPEND & csr0) { +		csr0 |= MUSB_CSR0_P_SVDSETUPEND; +		writew(csr0, &musbr->ep[0].ep0.csr0); +		SET_EP0_STATE(IDLE); +		if ((debug_setup) && (debug_level > 1)) +			serial_printf("WARN: %s SETUPEND\n", +				      __PRETTY_FUNCTION__); +	} + +	/* Normal states */ +	if (IDLE == ep0_state) +		musb_peri_ep0_idle(); + +	if (TX == ep0_state) +		musb_peri_ep0_tx(); + +	if (RX == ep0_state) +		musb_peri_ep0_rx(); +} + +static void musb_peri_rx_ep(unsigned int ep) +{ +	u16 peri_rxcount; +	u8 peri_rxcsr = readw(&musbr->ep[ep].epN.rxcsr); + +	if (!(peri_rxcsr & MUSB_RXCSR_RXPKTRDY)) { +		if (debug_level > 0) +			serial_printf("ERROR : %s %d without MUSB_RXCSR_RXPKTRDY set\n", +				      __PRETTY_FUNCTION__, ep); +		return; +	} + +	peri_rxcount = readw(&musbr->ep[ep].epN.rxcount); +	if (peri_rxcount) { +		struct usb_endpoint_instance *endpoint; +		u32 length; +		u8 *data; + +		endpoint = GET_ENDPOINT(udc_device, ep); +		if (endpoint && endpoint->rcv_urb) { +			struct urb *urb = endpoint->rcv_urb; +			unsigned int remaining_space = urb->buffer_length - +				urb->actual_length; + +			if (remaining_space) { +				int urb_bad = 0; /* urb is good */ + +				if (peri_rxcount > remaining_space) +					length = remaining_space; +				else +					length = peri_rxcount; + +				data = (u8 *) urb->buffer_data; +				data += urb->actual_length; + +				/* The common musb fifo reader */ +				read_fifo(ep, length, data); + +				musb_peri_rx_ack(ep); + +				/* +				 * urb's actual_length is updated in +				 * usbd_rcv_complete +				 */ +				usbd_rcv_complete(endpoint, length, urb_bad); + +			} else { +				if (debug_level > 0) +					serial_printf("ERROR : %s %d no space " +						      "in rcv buffer\n", +						      __PRETTY_FUNCTION__, ep); +			} +		} else { +			if (debug_level > 0) +				serial_printf("ERROR : %s %d problem with " +					      "endpoint\n", +					      __PRETTY_FUNCTION__, ep); +		} + +	} else { +		if (debug_level > 0) +			serial_printf("ERROR : %s %d with nothing to do\n", +				      __PRETTY_FUNCTION__, ep); +	} +} + +static void musb_peri_rx(u16 intr) +{ +	unsigned int ep; + +	/* Check for EP0 */ +	if (0x01 & intr) +		musb_peri_ep0(); + +	for (ep = 1; ep < 16; ep++) { +		if ((1 << ep) & intr) +			musb_peri_rx_ep(ep); +	} +} + +static void musb_peri_tx(u16 intr) +{ +	/* Check for EP0 */ +	if (0x01 & intr) +		musb_peri_ep0_tx(); + +	/* +	 * Use this in the future when handling epN tx +	 * +	 * u8 ep; +	 * +	 * for (ep = 1; ep < 16; ep++) { +	 *	if ((1 << ep) & intr) { +	 *		/ * handle tx for this endpoint * / +	 *	} +	 * } +	 */ +} + +void udc_irq(void) +{ +	/* This is a high freq called function */ +	if (enabled) { +		u8 intrusb; + +		intrusb = readb(&musbr->intrusb); + +		/* +		 * See drivers/usb/gadget/mpc8xx_udc.c for +		 * state diagram going from detached through +		 * configuration. +		 */ +		if (MUSB_INTR_RESUME & intrusb) { +			usbd_device_event_irq(udc_device, +					      DEVICE_BUS_ACTIVITY, 0); +			musb_peri_resume(); +		} + +		musb_peri_ep0(); + +		if (MUSB_INTR_RESET & intrusb) { +			usbd_device_event_irq(udc_device, DEVICE_RESET, 0); +			musb_peri_reset(); +		} + +		if (MUSB_INTR_DISCONNECT & intrusb) { +			/* cable unplugged from hub/host */ +			usbd_device_event_irq(udc_device, DEVICE_RESET, 0); +			musb_peri_reset(); +			usbd_device_event_irq(udc_device, DEVICE_HUB_RESET, 0); +		} + +		if (MUSB_INTR_SOF & intrusb) { +			usbd_device_event_irq(udc_device, +					      DEVICE_BUS_ACTIVITY, 0); +			musb_peri_resume(); +		} + +		if (MUSB_INTR_SUSPEND & intrusb) { +			usbd_device_event_irq(udc_device, +					      DEVICE_BUS_INACTIVE, 0); +		} + +		if (ep0_state != SET_ADDRESS) { +			u16 intrrx, intrtx; + +			intrrx = readw(&musbr->intrrx); +			intrtx = readw(&musbr->intrtx); + +			if (intrrx) +				musb_peri_rx(intrrx); + +			if (intrtx) +				musb_peri_tx(intrtx); +		} else { +			if (MUSB_INTR_SOF & intrusb) { +				u8 faddr; +				faddr = readb(&musbr->faddr); +				/* +				 * Setting of the address can fail. +				 * Normally it succeeds the second time. +				 */ +				if (udc_device->address != faddr) +					musb_peri_ep0_set_address(); +			} +		} +	} +} + +void udc_set_nak(int ep_num) +{ +	/* noop */ +} + +void udc_unset_nak(int ep_num) +{ +	/* noop */ +} + +int udc_endpoint_write(struct usb_endpoint_instance *endpoint) +{ +	int ret = 0; + +	/* Transmit only if the hardware is available */ +	if (endpoint->tx_urb && endpoint->state == 0) { +		unsigned int ep = endpoint->endpoint_address & +			USB_ENDPOINT_NUMBER_MASK; + +		u16 peri_txcsr = readw(&musbr->ep[ep].epN.txcsr); + +		/* Error conditions */ +		if (peri_txcsr & MUSB_TXCSR_P_UNDERRUN) { +			peri_txcsr &= ~MUSB_TXCSR_P_UNDERRUN; +			writew(peri_txcsr, &musbr->ep[ep].epN.txcsr); +		} + +		if (debug_level > 1) +			musb_print_txcsr(peri_txcsr); + +		/* Check if a packet is waiting to be sent */ +		if (!(peri_txcsr & MUSB_TXCSR_TXPKTRDY)) { +			u32 length; +			u8 *data; +			struct urb *urb = endpoint->tx_urb; +			unsigned int remaining_packet = urb->actual_length - +				endpoint->sent; + +			if (endpoint->tx_packetSize < remaining_packet) +				length = endpoint->tx_packetSize; +			else +				length = remaining_packet; + +			data = (u8 *) urb->buffer; +			data += endpoint->sent; + +			/* common musb fifo function */ +			write_fifo(ep, length, data); + +			musb_peri_tx_ready(ep); + +			endpoint->last = length; +			/* usbd_tx_complete will take care of updating 'sent' */ +			usbd_tx_complete(endpoint); +		} +	} else { +		if (debug_level > 0) +			serial_printf("ERROR : %s Problem with urb %p " +				      "or ep state %d\n", +				      __PRETTY_FUNCTION__, +				      endpoint->tx_urb, endpoint->state); +	} + +	return ret; +} + +void udc_setup_ep(struct usb_device_instance *device, unsigned int id, +		  struct usb_endpoint_instance *endpoint) +{ +	if (0 == id) { +		/* EP0 */ +		ep0_endpoint = endpoint; +		ep0_endpoint->endpoint_address = 0xff; +		ep0_urb = usbd_alloc_urb(device, endpoint); +	} else if (MAX_ENDPOINT >= id) { +		int ep_addr; + +		/* Check the direction */ +		ep_addr = endpoint->endpoint_address; +		if (USB_DIR_IN == (ep_addr & USB_ENDPOINT_DIR_MASK)) { +			/* IN */ +			epinfo[(id * 2) + 1].epsize = endpoint->tx_packetSize; +		} else { +			/* OUT */ +			epinfo[id * 2].epsize = endpoint->rcv_packetSize; +		} + +		musb_configure_ep(&epinfo[0], ARRAY_SIZE(epinfo)); +	} else { +		if (debug_level > 0) +			serial_printf("ERROR : %s endpoint request %d " +				      "exceeds maximum %d\n", +				      __PRETTY_FUNCTION__, id, MAX_ENDPOINT); +	} +} + +void udc_connect(void) +{ +	/* noop */ +} + +void udc_disconnect(void) +{ +	/* noop */ +} + +void udc_enable(struct usb_device_instance *device) +{ +	/* Save the device structure pointer */ +	udc_device = device; + +	enabled = 1; +} + +void udc_disable(void) +{ +	enabled = 0; +} + +void udc_startup_events(struct usb_device_instance *device) +{ +	/* The DEVICE_INIT event puts the USB device in the state STATE_INIT. */ +	usbd_device_event_irq(device, DEVICE_INIT, 0); + +	/* +	 * The DEVICE_CREATE event puts the USB device in the state +	 * STATE_ATTACHED. +	 */ +	usbd_device_event_irq(device, DEVICE_CREATE, 0); + +	/* Resets the address to 0 */ +	usbd_device_event_irq(device, DEVICE_RESET, 0); + +	udc_enable(device); +} + +int udc_init(void) +{ +	int ret; +	int ep_loop; + +	ret = musb_platform_init(); +	if (ret < 0) +		goto end; + +	/* Configure all the endpoint FIFO's and start usb controller */ +	musbr = musb_cfg.regs; + +	/* Initialize the endpoints */ +	for (ep_loop = 0; ep_loop < MAX_ENDPOINT * 2; ep_loop++) { +		epinfo[ep_loop].epnum = (ep_loop / 2) + 1; +		epinfo[ep_loop].epdir = ep_loop % 2; /* OUT, IN */ +		epinfo[ep_loop].epsize = 0; +	} + +	musb_peri_softconnect(); + +	ret = 0; +end: + +	return ret; +} diff --git a/roms/u-boot/drivers/usb/musb/omap3.c b/roms/u-boot/drivers/usb/musb/omap3.c new file mode 100644 index 00000000..97da529b --- /dev/null +++ b/roms/u-boot/drivers/usb/musb/omap3.c @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2009 Wind River Systems, Inc. + * Tom Rix <Tom.Rix@windriver.com> + * + * This is file is based on + * repository git.gitorious.org/u-boot-omap3/mainline.git, + * branch omap3-dev-usb, file drivers/usb/host/omap3530_usb.c + * + * This is the unique part of its copyright : + * + * ------------------------------------------------------------------------ + * + * Copyright (c) 2009 Texas Instruments + * + * ------------------------------------------------------------------------ + * + * SPDX-License-Identifier:	GPL-2.0+ + */ + +#include <asm/omap_common.h> +#include <twl4030.h> +#include <twl6030.h> +#include "omap3.h" + +static int platform_needs_initialization = 1; + +struct musb_config musb_cfg = { +	.regs		= (struct musb_regs *)MENTOR_USB0_BASE, +	.timeout	= OMAP3_USB_TIMEOUT, +	.musb_speed	= 0, +}; + +/* + * OMAP3 USB OTG registers. + */ +struct omap3_otg_regs { +	u32	revision; +	u32	sysconfig; +	u32	sysstatus; +	u32	interfsel; +	u32	simenable; +	u32	forcestdby; +}; + +static struct omap3_otg_regs *otg; + +#define OMAP3_OTG_SYSCONFIG_SMART_STANDBY_MODE		0x2000 +#define OMAP3_OTG_SYSCONFIG_NO_STANDBY_MODE		0x1000 +#define OMAP3_OTG_SYSCONFIG_SMART_IDLE_MODE		0x0010 +#define OMAP3_OTG_SYSCONFIG_NO_IDLE_MODE		0x0008 +#define OMAP3_OTG_SYSCONFIG_ENABLEWAKEUP		0x0004 +#define OMAP3_OTG_SYSCONFIG_SOFTRESET			0x0002 +#define OMAP3_OTG_SYSCONFIG_AUTOIDLE			0x0001 + +#define OMAP3_OTG_SYSSTATUS_RESETDONE			0x0001 + +/* OMAP4430 has an internal PHY, use it */ +#ifdef CONFIG_OMAP4430 +#define OMAP3_OTG_INTERFSEL_OMAP			0x0000 +#else +#define OMAP3_OTG_INTERFSEL_OMAP			0x0001 +#endif + +#define OMAP3_OTG_FORCESTDBY_STANDBY			0x0001 + + +#ifdef DEBUG_MUSB_OMAP3 +static void musb_db_otg_regs(void) +{ +	u32 l; +	l = readl(&otg->revision); +	serial_printf("OTG_REVISION 0x%x\n", l); +	l = readl(&otg->sysconfig); +	serial_printf("OTG_SYSCONFIG 0x%x\n", l); +	l = readl(&otg->sysstatus); +	serial_printf("OTG_SYSSTATUS 0x%x\n", l); +	l = readl(&otg->interfsel); +	serial_printf("OTG_INTERFSEL 0x%x\n", l); +	l = readl(&otg->forcestdby); +	serial_printf("OTG_FORCESTDBY 0x%x\n", l); +} +#endif + +int musb_platform_init(void) +{ +	int ret = -1; + +	if (platform_needs_initialization) { +		u32 stdby; + +		/* +		 * OMAP3EVM uses ISP1504 phy and so +		 * twl4030 related init is not required. +		 */ +#ifdef CONFIG_TWL4030_USB +		if (twl4030_usb_ulpi_init()) { +			serial_printf("ERROR: %s Could not initialize PHY\n", +				__PRETTY_FUNCTION__); +			goto end; +		} +#endif + +#ifdef CONFIG_TWL6030_POWER +		twl6030_usb_device_settings(); +#endif + +		otg = (struct omap3_otg_regs *)OMAP3_OTG_BASE; + +		/* Set OTG to always be on */ +		writel(OMAP3_OTG_SYSCONFIG_NO_STANDBY_MODE | +		       OMAP3_OTG_SYSCONFIG_NO_IDLE_MODE, &otg->sysconfig); + +		/* Set the interface */ +		writel(OMAP3_OTG_INTERFSEL_OMAP, &otg->interfsel); + +		/* Clear force standby */ +		stdby = readl(&otg->forcestdby); +		stdby &= ~OMAP3_OTG_FORCESTDBY_STANDBY; +		writel(stdby, &otg->forcestdby); + +#ifdef CONFIG_OMAP3_EVM +		musb_cfg.extvbus = omap3_evm_need_extvbus(); +#endif + +#ifdef CONFIG_OMAP4430 +		u32 *usbotghs_control = +			(u32 *)((*ctrl)->control_usbotghs_ctrl); +		*usbotghs_control = 0x15; +#endif +		platform_needs_initialization = 0; +	} + +	ret = platform_needs_initialization; + +#ifdef CONFIG_TWL4030_USB +end: +#endif +	return ret; + +} + +void musb_platform_deinit(void) +{ +	/* noop */ +} diff --git a/roms/u-boot/drivers/usb/musb/omap3.h b/roms/u-boot/drivers/usb/musb/omap3.h new file mode 100644 index 00000000..ae645c72 --- /dev/null +++ b/roms/u-boot/drivers/usb/musb/omap3.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2009 Wind River Systems, Inc. + * Tom Rix <Tom.Rix@windriver.com> + * + * This file is based on the file drivers/usb/musb/davinci.h + * + * This is the unique part of its copyright: + * + * -------------------------------------------------------------------- + * + * Copyright (c) 2008 Texas Instruments + * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments + * + * -------------------------------------------------------------------- + * + * SPDX-License-Identifier:	GPL-2.0+ + */ +#ifndef _MUSB_OMAP3_H_ +#define _MUSB_OMAP3_H_ + +#include <asm/arch/cpu.h> +#include "musb_core.h" + +/* Base address of MUSB registers */ +#define MENTOR_USB0_BASE MUSB_BASE + +/* Base address of OTG registers */ +#define OMAP3_OTG_BASE (MENTOR_USB0_BASE + 0x400) + +/* Timeout for USB module */ +#define OMAP3_USB_TIMEOUT 0x3FFFFFF + +int musb_platform_init(void); + +#ifdef CONFIG_OMAP3_EVM +extern u8 omap3_evm_need_extvbus(void); +#endif + +#endif /* _MUSB_OMAP3_H */ | 
