summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/include/asm/arch-tegra2/bitfield.h2
-rw-r--r--arch/arm/include/asm/arch-tegra2/tegra2.h2
-rw-r--r--arch/arm/include/asm/arch-tegra2/usb.h217
-rw-r--r--board/nvidia/common/Makefile53
-rw-r--r--board/nvidia/common/board.c5
-rw-r--r--board/nvidia/common/usb.c313
-rw-r--r--drivers/usb/host/Makefile1
-rw-r--r--drivers/usb/host/ehci-hcd.c39
-rw-r--r--drivers/usb/host/ehci-tegra.c73
-rw-r--r--drivers/usb/host/ehci.h6
-rw-r--r--include/configs/seaboard.h10
-rw-r--r--include/configs/tegra2-common.h30
12 files changed, 749 insertions, 2 deletions
diff --git a/arch/arm/include/asm/arch-tegra2/bitfield.h b/arch/arm/include/asm/arch-tegra2/bitfield.h
index 5c3d29c635b..a124c858074 100644
--- a/arch/arm/include/asm/arch-tegra2/bitfield.h
+++ b/arch/arm/include/asm/arch-tegra2/bitfield.h
@@ -124,7 +124,7 @@
* readl/writel
*/
#define bf_writel(field, value, reg) ({ \
- u32 __reg = (reg); \
+ u32 *__reg = (u32 *)(reg); \
u32 __oldval = readl(__reg); \
bf_update(field, __oldval, value); \
writel(__oldval, __reg); \
diff --git a/arch/arm/include/asm/arch-tegra2/tegra2.h b/arch/arm/include/asm/arch-tegra2/tegra2.h
index 742a75a0dac..3bf005161b1 100644
--- a/arch/arm/include/asm/arch-tegra2/tegra2.h
+++ b/arch/arm/include/asm/arch-tegra2/tegra2.h
@@ -40,6 +40,8 @@
#define NV_PA_APB_UARTE_BASE (NV_PA_APB_MISC_BASE + 0x6400)
#define NV_PA_PMC_BASE 0x7000E400
#define NV_PA_CSITE_BASE 0x70040000
+#define NV_PA_USB1_BASE 0xC5000000
+#define NV_PA_USB3_BASE 0xC5008000
#define TEGRA2_SDRC_CS0 NV_PA_SDRAM_BASE
#define LOW_LEVEL_SRAM_STACK 0x4000FFFC
diff --git a/arch/arm/include/asm/arch-tegra2/usb.h b/arch/arm/include/asm/arch-tegra2/usb.h
new file mode 100644
index 00000000000..54b1a656c26
--- /dev/null
+++ b/arch/arm/include/asm/arch-tegra2/usb.h
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef _TEGRA_USB_H_
+#define _TEGRA_USB_H_
+
+
+/* USB Controller (USBx_CONTROLLER_) regs */
+struct usb_ctlr {
+ /* 0x000 */
+ uint id;
+ uint reserved0;
+ uint host;
+ uint device;
+
+ /* 0x010 */
+ uint txbuf;
+ uint rxbuf;
+ uint reserved1[2];
+
+ /* 0x020 */
+ uint reserved2[56];
+
+ /* 0x100 */
+ u16 cap_length;
+ u16 hci_version;
+ uint hcs_params;
+ uint hcc_params;
+ uint reserved3[5];
+
+ /* 0x120 */
+ uint dci_version;
+ uint dcc_params;
+ uint reserved4[6];
+
+ /* 0x140 */
+ uint usb_cmd;
+ uint usb_sts;
+ uint usb_intr;
+ uint frindex;
+
+ /* 0x150 */
+ uint reserved5;
+ uint periodic_list_base;
+ uint async_list_addr;
+ uint async_tt_sts;
+
+ /* 0x160 */
+ uint burst_size;
+ uint tx_fill_tuning;
+ uint reserved6; //; is this port_sc1 on some controllers?
+ uint icusb_ctrl;
+
+ /* 0x170 */
+ uint ulpi_viewport;
+ uint reserved7;
+ uint endpt_nak;
+ uint endpt_nak_enable;
+
+ /* 0x180 */
+ uint reserved;
+ uint port_sc1;
+ uint reserved8[6];
+
+ /* 0x1a0 */
+ uint reserved9;
+ uint otgsc;
+ uint usb_mode;
+ uint endpt_setup_stat;
+
+ /* 0x1b0 */
+ uint reserved10[20];
+
+ /* 0x200 */
+ uint reserved11[0x80];
+
+ /* 0x400 */
+ uint susp_ctrl;
+ uint phy_vbus_sensors;
+ uint phy_vbus_wakeup_id;
+ uint phy_alt_vbus_sys;
+
+ /* 0x410 */
+ uint usb1_legacy_ctrl;
+ uint reserved12[3];
+
+ /* 0x420 */
+ uint reserved13[56];
+
+ /* 0x500 */
+ uint reserved14[64 * 3];
+
+ /* 0x800 */
+ uint utmip_pll_cfg0;
+ uint utmip_pll_cfg1;
+ uint utmip_xcvr_cfg0;
+ uint utmip_bias_cfg0;
+
+ /* 0x810 */
+ uint utmip_hsrx_cfg0;
+ uint utmip_hsrx_cfg1;
+ uint utmip_fslsrx_cfg0;
+ uint utmip_fslsrx_cfg1;
+
+ /* 0x820 */
+ uint utmip_tx_cfg0;
+ uint utmip_misc_cfg0;
+ uint utmip_misc_cfg1;
+ uint utmip_debounce_cfg0;
+
+ /* 0x830 */
+ uint utmip_bat_chrg_cfg0;
+ uint utmip_spare_cfg0;
+ uint utmip_xcvr_cfg1;
+ uint utmip_bias_cfg1;
+};
+
+
+/* USB1_LEGACY_CTRL */
+#define USB1_NO_LEGACY_MODE_RANGE 0:0
+#define NO_LEGACY_MODE 1
+
+#define VBUS_SENSE_CTL_RANGE 2:1
+#define VBUS_SENSE_CTL_VBUS_WAKEUP 0
+#define VBUS_SENSE_CTL_AB_SESS_VLD_OR_VBUS_WAKEUP 1
+#define VBUS_SENSE_CTL_AB_SESS_VLD 2
+#define VBUS_SENSE_CTL_A_SESS_VLD 3
+
+/* USBx_IF_USB_SUSP_CTRL_0 */
+#define UTMIP_PHY_ENB_RANGE 12:12
+#define UTMIP_RESET_RANGE 11:11
+#define USB_PHY_CLK_VALID_RANGE 7:7
+
+/* USBx_UTMIP_MISC_CFG1 */
+#define UTMIP_PLLU_STABLE_COUNT_RANGE 17:6
+#define UTMIP_PLL_ACTIVE_DLY_COUNT_RANGE 22:18
+#define UTMIP_PHY_XTAL_CLOCKEN_RANGE 30:30
+
+/* USBx_UTMIP_PLL_CFG1_0 */
+#define UTMIP_PLLU_ENABLE_DLY_COUNT_RANGE 30:27
+#define UTMIP_XTAL_FREQ_COUNT_RANGE 11:0
+
+/* USBx_UTMIP_BIAS_CFG1_0 */
+#define UTMIP_BIAS_PDTRK_COUNT_RANGE 7:3
+
+#define UTMIP_DEBOUNCE_CFG0_RANGE 15:0
+
+/* USBx_UTMIP_TX_CFG0_0 */
+#define UTMIP_FS_PREAMBLE_J_RANGE 19:19
+
+/* USBx_UTMIP_BAT_CHRG_CFG0_0 */
+#define UTMIP_PD_CHRG_RANGE 0:0
+
+/* USBx_UTMIP_XCVR_CFG0_0 */
+#define UTMIP_XCVR_LSBIAS_SE_RANGE 21:21
+
+/* USBx_UTMIP_SPARE_CFG0_0 */
+#define FUSE_SETUP_SEL_RANGE 3:3
+
+/* USBx_UTMIP_HSRX_CFG0_0 */
+#define UTMIP_IDLE_WAIT_RANGE 19:15
+#define UTMIP_ELASTIC_LIMIT_RANGE 14:10
+
+/* USBx_UTMIP_HSRX_CFG0_1 */
+#define UTMIP_HS_SYNC_START_DLY_RANGE 4:1
+
+/* USBx_CONTROLLER_2_USB2D_ICUSB_CTRL_0 */
+#define IC_ENB1_RANGE 3:3
+
+/* SB2_CONTROLLER_2_USB2D_PORTSC1_0 */
+#define PTS_RANGE 31:30
+#define PTS_UTMI 0
+#define PTS_RESERVED 1
+#define PTS_ULP 2
+#define PTS_ICUSB_SER 3
+
+#define STS_RANGE 29:29
+
+/* USBx_UTMIP_XCVR_CFG0_0 */
+#define UTMIP_FORCE_PD_POWERDOWN_RANGE 14:14
+#define UTMIP_FORCE_PD2_POWERDOWN_RANGE 16:16
+#define UTMIP_FORCE_PDZI_POWERDOWN_RANGE 18:18
+
+/* USBx_UTMIP_XCVR_CFG1_0 */
+#define UTMIP_FORCE_PDDISC_POWERDOWN_RANGE 0:0
+#define UTMIP_FORCE_PDCHRP_POWERDOWN_RANGE 2:2
+#define UTMIP_FORCE_PDDR_POWERDOWN_RANGE 4:4
+
+/* USB3_IF_USB_PHY_VBUS_SENSORS_0 */
+#define VBUS_VLD_STS_RANGE 26:26
+
+
+/* Change USB port 1 into host mode */
+void usb1_set_host_mode(void);
+
+/* Setup USB on the board */
+void board_usb_init(void);
+
+#endif /* _TEGRA_USB_H_ */
diff --git a/board/nvidia/common/Makefile b/board/nvidia/common/Makefile
new file mode 100644
index 00000000000..9bd0bf29bb8
--- /dev/null
+++ b/board/nvidia/common/Makefile
@@ -0,0 +1,53 @@
+# Copyright (c) 2011 The Chromium OS Authors.
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+
+include $(TOPDIR)/config.mk
+
+ifneq ($(OBJTREE),$(SRCTREE))
+$(shell mkdir -p $(obj)board/$(VENDOR)/common)
+endif
+
+LIB = $(obj)lib$(VENDOR).o
+
+COBJS-y += board.o
+COBJS-$(CONFIG_USB_EHCI_TEGRA) += usb.o
+
+COBJS := $(COBJS-y)
+SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS := $(addprefix $(obj),$(COBJS))
+SOBJS := $(addprefix $(obj),$(SOBJS))
+
+all: $(LIB)
+
+$(LIB): $(obj).depend $(OBJS) $(SOBJS)
+ $(call cmd_link_o_target, $(OBJS) $(SOBJS))
+
+clean:
+ rm -f $(SOBJS) $(OBJS)
+
+distclean: clean
+ rm -f $(LIB) core *.bak $(obj).depend
+
+#########################################################################
+# This is for $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/board/nvidia/common/board.c b/board/nvidia/common/board.c
index ac2e3f87dbb..658bf1f83f8 100644
--- a/board/nvidia/common/board.c
+++ b/board/nvidia/common/board.c
@@ -32,6 +32,7 @@
#include <asm/arch/clock.h>
#include <asm/arch/pinmux.h>
#include <asm/arch/uart.h>
+#include <asm/arch/usb.h>
#include "board.h"
DECLARE_GLOBAL_DATA_PTR;
@@ -191,5 +192,9 @@ int board_init(void)
/* board id for Linux */
gd->bd->bi_arch_number = CONFIG_MACH_TYPE;
+#ifdef CONFIG_USB_EHCI_TEGRA
+ board_usb_init();
+#endif
+
return 0;
}
diff --git a/board/nvidia/common/usb.c b/board/nvidia/common/usb.c
new file mode 100644
index 00000000000..323d98492fa
--- /dev/null
+++ b/board/nvidia/common/usb.c
@@ -0,0 +1,313 @@
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ * (C) Copyright 2010,2011 NVIDIA Corporation <www.nvidia.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/bitfield.h>
+#include <asm/arch/tegra2.h>
+#include <asm/arch/sys_proto.h>
+
+#include <asm/arch/clk_rst.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/pinmux.h>
+#include <asm/arch/uart.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/usb.h>
+
+
+/* The fields for USB PLLU configuration parameters */
+struct usb_pll_params {
+ unsigned divn; /* PLL feedback divider */
+ unsigned divm; /* PLL input divider */
+ unsigned divp; /* post divider (2^n) */
+ unsigned cpcon; /* Base PLLC charge pump setup control */
+ unsigned lfcon; /* Base PLLC loop filter setup control */
+ u8 enable_delay_count; /* Pll-U Enable Delay Count */
+ u8 stable_count; /* PLL-U Stable count */
+ u8 active_delay_count; /* Pll-U Active delay count */
+ u8 xtal_freq_count; /* PLL-U Xtal frequency count */
+ unsigned debounce_a_time; /* 10ms delay for BIAS_DEBOUNCE_A */
+ unsigned bias_time; /* 20us delay after bias cell op */
+};
+
+/*
+ * This table has USB timing parameters for each Oscillator frequency we
+ * support. There are four sets of values:
+ *
+ * 1. PLLU configuration information (reference clock is osc/clk_m and
+ * PLLU-FOs are fixed at 12MHz/60MHz/480MHz).
+ *
+ * Reference frequency 13.0MHz 19.2MHz 12.0MHz 26.0MHz
+ * ----------------------------------------------------------------------
+ * DIVN 960 (0x3c0) 200 (0c8) 960 (3c0h) 960 (3c0)
+ * DIVM 13 (0d) 4 (04) 12 (0c) 26 (1a)
+ * Filter frequency (MHz) 1 4.8 6 2
+ * CPCON 1100b 0011b 1100b 1100b
+ * LFCON0 0 0 0 0
+ *
+ * 2. PLL CONFIGURATION & PARAMETERS for different clock generators:
+ *
+ * Reference frequency 13.0MHz 19.2MHz 12.0MHz 26.0MHz
+ * ---------------------------------------------------------------------------
+ * PLLU_ENABLE_DLY_COUNT 02 (0x02) 03 (03) 02 (02) 04 (04)
+ * PLLU_STABLE_COUNT 51 (33) 75 (4B) 47 (2F) 102 (66)
+ * PLL_ACTIVE_DLY_COUNT 05 (05) 06 (06) 04 (04) 09 (09)
+ * XTAL_FREQ_COUNT 127 (7F) 187 (BB) 118 (76) 254 (FE)
+ *
+ * 3. Debounce values IdDig, Avalid, Bvalid, VbusValid, VbusWakeUp, and
+ * SessEnd. Each of these signals have their own debouncer and for each of
+ * those one out of two debouncing times can be chosen (BIAS_DEBOUNCE_A or
+ * BIAS_DEBOUNCE_B).
+ *
+ * The values of DEBOUNCE_A and DEBOUNCE_B are calculated as follows:
+ * 0xffff -> No debouncing at all
+ * <n> ms = <n> *1000 / (1/19.2MHz) / 4
+ *
+ * So to program a 1 ms debounce for BIAS_DEBOUNCE_A, we have:
+ * BIAS_DEBOUNCE_A[15:0] = 1000 * 19.2 / 4 = 4800 = 0x12c0
+ *
+ * We need to use only DebounceA for BOOTROM. We don’t need the DebounceB
+ * values, so we can keep those to default.
+ *
+ * 4. The 20 microsecond delay after bias cell operation.
+ */
+static const struct usb_pll_params usb_pll[CLOCK_OSC_FREQ_COUNT] = {
+ /* DivN, DivM, DivP, CPCON, LFCON, Delays Debounce, Bias */
+ { 0x3C0, 0x0D, 0x00, 0xC, 0, 0x02, 0x33, 0x05, 0x7F, 0x7EF4, 5 },
+ { 0x0C8, 0x04, 0x00, 0x3, 0, 0x03, 0x4B, 0x06, 0xBB, 0xBB80, 7 },
+ { 0x3C0, 0x0C, 0x00, 0xC, 0, 0x02, 0x2F, 0x04, 0x76, 0x7530, 5 },
+ { 0x3C0, 0x1A, 0x00, 0xC, 0, 0x04, 0x66, 0x09, 0xFE, 0xFDE8, 9 }
+};
+
+/* UTMIP Idle Wait Delay */
+static const u8 utmip_idle_wait_delay = 17;
+
+/* UTMIP Elastic limit */
+static const u8 utmip_elastic_limit = 16;
+
+/* UTMIP High Speed Sync Start Delay */
+static const u8 utmip_hs_sync_start_delay = 9;
+
+
+void usb1_set_host_mode(void)
+{
+ struct usb_ctlr *usbctlr = (struct usb_ctlr *)NV_PA_USB1_BASE;
+
+ /* Check whether remote host from USB1 is driving VBus */
+ if (bf_readl(VBUS_VLD_STS, &usbctlr->phy_vbus_sensors))
+ return;
+
+ /*
+ * If not driving, we set GPIO USB1_VBus_En. Seaboard platform uses
+ * PAD SLXK (GPIO D.00) as USB1_VBus_En Config as GPIO
+ */
+ gpio_direction_output(GPIO_PD0, 1);
+
+ /* Z_SLXK = 0, normal, not tristate */
+ pinmux_tristate_disable(PIN_SLXK);
+}
+
+void usbf_reset_controller(enum periph_id id, struct usb_ctlr *usbctlr)
+{
+ /* Reset the USB controller with 2us delay */
+ reset_periph(id, 2);
+
+ /*
+ * Set USB1_NO_LEGACY_MODE to 1, Registers are accessible under
+ * base address
+ */
+ if (id == PERIPH_ID_USBD)
+ bf_writel(USB1_NO_LEGACY_MODE, NO_LEGACY_MODE,
+ &usbctlr->usb1_legacy_ctrl);
+
+ /* Put UTMIP1/3 in reset */
+ bf_writel(UTMIP_RESET, 1, &usbctlr->susp_ctrl);
+
+ /* Set USB3 to use UTMIP PHY */
+ if (id == PERIPH_ID_USB3)
+ bf_writel(UTMIP_PHY_ENB, 1, &usbctlr->susp_ctrl);
+
+ /*
+ * TODO: where do we take the USB1 out of reset? The old code would
+ * take USB3 out of reset, but not USB1. This code doesn't do either.
+ */
+}
+
+/* set up the USB controller with the parameters provided */
+static void init_usb_controller(enum periph_id id, struct usb_ctlr *usbctlr,
+ const struct usb_pll_params *params)
+{
+ u32 val;
+ int loop_count;
+
+ clock_enable(id);
+
+ /* Reset the usb controller */
+ usbf_reset_controller(id, usbctlr);
+
+ /* Stop crystal clock by setting UTMIP_PHY_XTAL_CLOCKEN low */
+ bf_clearl(UTMIP_PHY_XTAL_CLOCKEN, &usbctlr->utmip_misc_cfg1);
+
+ /* Follow the crystal clock disable by >100ns delay */
+ udelay(1);
+
+ /*
+ * To Use the A Session Valid for cable detection logic, VBUS_WAKEUP
+ * mux must be switched to actually use a_sess_vld threshold.
+ */
+ if (id == PERIPH_ID_USBD)
+ bf_enum_writel(VBUS_SENSE_CTL, A_SESS_VLD,
+ &usbctlr->usb1_legacy_ctrl);
+
+ /*
+ * PLL Delay CONFIGURATION settings. The following parameters control
+ * the bring up of the plls.
+ */
+ val = readl(&usbctlr->utmip_misc_cfg1);
+ bf_update(UTMIP_PLLU_STABLE_COUNT, val, params->stable_count);
+ bf_update(UTMIP_PLL_ACTIVE_DLY_COUNT, val,
+ params->active_delay_count);
+ writel(val, &usbctlr->utmip_misc_cfg1);
+
+ /* Set PLL enable delay count and crystal frequency count */
+ val = readl(&usbctlr->utmip_pll_cfg1);
+ bf_update(UTMIP_PLLU_ENABLE_DLY_COUNT, val,
+ params->enable_delay_count);
+ bf_update(UTMIP_XTAL_FREQ_COUNT, val, params->xtal_freq_count);
+ writel(val, &usbctlr->utmip_pll_cfg1);
+
+ /* Setting the tracking length time */
+ bf_writel(UTMIP_BIAS_PDTRK_COUNT, params->bias_time,
+ &usbctlr->utmip_bias_cfg1);
+
+ /* Program debounce time for VBUS to become valid */
+ bf_writel(UTMIP_DEBOUNCE_CFG0, params->debounce_a_time,
+ &usbctlr->utmip_debounce_cfg0);
+
+ /* Set UTMIP_FS_PREAMBLE_J to 1 */
+ bf_writel(UTMIP_FS_PREAMBLE_J, 1, &usbctlr->utmip_tx_cfg0);
+
+ /* Disable battery charge enabling bit */
+ bf_writel(UTMIP_PD_CHRG, 1, &usbctlr->utmip_bat_chrg_cfg0);
+
+ /* Set UTMIP_XCVR_LSBIAS_SEL to 0 */
+ bf_writel(UTMIP_XCVR_LSBIAS_SE, 0, &usbctlr->utmip_xcvr_cfg0);
+
+ /* Set bit 3 of UTMIP_SPARE_CFG0 to 1 */
+ bf_writel(FUSE_SETUP_SEL, 1, &usbctlr->utmip_spare_cfg0);
+
+ /*
+ * Configure the UTMIP_IDLE_WAIT and UTMIP_ELASTIC_LIMIT
+ * Setting these fields, together with default values of the
+ * other fields, results in programming the registers below as
+ * follows:
+ * UTMIP_HSRX_CFG0 = 0x9168c000
+ * UTMIP_HSRX_CFG1 = 0x13
+ */
+
+ /* Set PLL enable delay count and Crystal frequency count */
+ val = readl(&usbctlr->utmip_hsrx_cfg0);
+ bf_update(UTMIP_IDLE_WAIT, val, utmip_idle_wait_delay);
+ bf_update(UTMIP_ELASTIC_LIMIT, val, utmip_elastic_limit);
+ writel(val, &usbctlr->utmip_hsrx_cfg0);
+
+ /* Configure the UTMIP_HS_SYNC_START_DLY */
+ bf_writel(UTMIP_HS_SYNC_START_DLY, utmip_hs_sync_start_delay,
+ &usbctlr->utmip_hsrx_cfg1);
+
+ /* Preceed the crystal clock disable by >100ns delay. */
+ udelay(1);
+
+ /* Resuscitate crystal clock by setting UTMIP_PHY_XTAL_CLOCKEN */
+ bf_writel(UTMIP_PHY_XTAL_CLOCKEN, 1, &usbctlr->utmip_misc_cfg1);
+
+ /* Finished the per-controller init. */
+
+ /* De-assert UTMIP_RESET to bring out of reset. */
+ bf_clearl(UTMIP_RESET, &usbctlr->susp_ctrl);
+
+ /* Wait for the phy clock to become valid in 100 ms */
+ for (loop_count = 100000; loop_count != 0; loop_count--) {
+ if (bf_readl(USB_PHY_CLK_VALID, &usbctlr->susp_ctrl))
+ break;
+ udelay(1);
+ }
+}
+
+static void power_up_port(struct usb_ctlr *usbctlr)
+{
+ u32 val;
+
+ /* Deassert power down state */
+ val = readl(&usbctlr->utmip_xcvr_cfg0);
+ bf_update(UTMIP_FORCE_PD_POWERDOWN, val, 0);
+ bf_update(UTMIP_FORCE_PD2_POWERDOWN, val, 0);
+ bf_update(UTMIP_FORCE_PDZI_POWERDOWN, val, 0);
+ writel(val, &usbctlr->utmip_xcvr_cfg0);
+
+ val = readl(&usbctlr->utmip_xcvr_cfg1);
+ bf_update(UTMIP_FORCE_PDDISC_POWERDOWN, val, 0);
+ bf_update(UTMIP_FORCE_PDCHRP_POWERDOWN, val, 0);
+ bf_update(UTMIP_FORCE_PDDR_POWERDOWN, val, 0);
+ writel(val, &usbctlr->utmip_xcvr_cfg1);
+}
+
+void board_usb_init(void)
+{
+ enum clock_osc_freq freq;
+ const struct usb_pll_params *params;
+ struct usb_ctlr *usbctlr;
+ u32 val;
+ unsigned stable_time;
+
+ /* Get the Oscillator frequency */
+ freq = clock_get_osc_freq();
+
+ /* Enable PLL U for USB */
+ params = &usb_pll[freq];
+ stable_time = clock_start_pll(CLOCK_PLL_ID_USB,
+ params->divm, params->divn, params->divp, params->cpcon,
+ params->lfcon);
+ /* TODO: what should we do with stable_time? */
+
+ /* Set up our two ports */
+ usbctlr = (struct usb_ctlr *)NV_PA_USB1_BASE;
+ init_usb_controller(PERIPH_ID_USBD, usbctlr, params);
+
+ usbctlr = (struct usb_ctlr *)NV_PA_USB3_BASE;
+ init_usb_controller(PERIPH_ID_USB3, usbctlr, params);
+
+ /* Disable ICUSB FS/LS transceiver */
+ bf_writel(IC_ENB1, 0, &usbctlr->icusb_ctrl);
+
+ /* Select UTMI parallel interface */
+ bf_writel(PTS, PTS_UTMI, &usbctlr->port_sc1);
+ bf_writel(STS, 0, &usbctlr->port_sc1);
+
+ power_up_port(usbctlr);
+
+#ifdef CONFIG_TEGRA2_USB1_HOST
+ usb1_set_host_mode();
+#endif
+}
+
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 51b24943282..a8e107be678 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -46,6 +46,7 @@ COBJS-$(CONFIG_USB_EHCI_IXP4XX) += ehci-ixp.o
COBJS-$(CONFIG_USB_EHCI_KIRKWOOD) += ehci-kirkwood.o
COBJS-$(CONFIG_USB_EHCI_PCI) += ehci-pci.o
COBJS-$(CONFIG_USB_EHCI_VCT) += ehci-vct.o
+COBJS-$(CONFIG_USB_EHCI_TEGRA) += ehci-tegra.o
COBJS := $(COBJS-y)
SRCS := $(COBJS:.o=.c)
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 70c02c9deba..9647ef48526 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -247,6 +247,13 @@ static int ehci_reset(void)
#endif
ehci_writel(reg_ptr, tmp);
}
+
+#ifdef CONFIG_USB_EHCI_TXFIFO_THRESH
+ cmd = ehci_readl(&hcor->or_txfilltuning);
+ cmd &= ~TXFIFO_THRESH(0x3f);
+ cmd |= TXFIFO_THRESH(CONFIG_USB_EHCI_TXFIFO_THRESH);
+ ehci_writel(&hcor->or_txfilltuning, cmd);
+#endif
out:
return ret;
}
@@ -322,6 +329,27 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
int timeout;
int ret = 0;
+#ifdef CONFIG_USB_EHCI_DATA_ALIGN
+ /* In case ehci host requires alignment for buffers */
+ void *align_buf = NULL;
+ void *orig_buf = buffer;
+ int unaligned = ((int)buffer & (CONFIG_USB_EHCI_DATA_ALIGN - 1)) != 0;
+
+ if (unaligned) {
+ align_buf = malloc(length + CONFIG_USB_EHCI_DATA_ALIGN);
+ if (!align_buf)
+ return -1;
+ if ((int)align_buf & (CONFIG_USB_EHCI_DATA_ALIGN - 1))
+ buffer = (void *)((int)align_buf +
+ CONFIG_USB_EHCI_DATA_ALIGN -
+ ((int)align_buf &
+ (CONFIG_USB_EHCI_DATA_ALIGN - 1)));
+ else
+ buffer = align_buf;
+ if (usb_pipeout(pipe))
+ memcpy(buffer, orig_buf, length);
+ }
+#endif
debug("dev=%p, pipe=%lx, buffer=%p, length=%d, req=%p\n", dev, pipe,
buffer, length, req);
if (req != NULL)
@@ -514,9 +542,20 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
ehci_readl(&hcor->or_portsc[1]));
}
+#ifdef CONFIG_USB_EHCI_DATA_ALIGN
+ if (unaligned) {
+ if (usb_pipein(pipe) && dev->act_len)
+ memcpy(orig_buf, buffer, length);
+ free(align_buf);
+ }
+#endif
return (dev->status != USB_ST_NOT_PROC) ? 0 : -1;
fail:
+#ifdef CONFIG_USB_EHCI_DATA_ALIGN
+ if (unaligned)
+ free(align_buf);
+#endif
td = (void *)hc32_to_cpu(qh->qh_overlay.qt_next);
while (td != (void *)QT_NEXT_TERMINATE) {
qh->qh_overlay.qt_next = td->qt_next;
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
new file mode 100644
index 00000000000..04e43b840e7
--- /dev/null
+++ b/drivers/usb/host/ehci-tegra.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2009 NVIDIA Corporation
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <usb.h>
+
+#include "ehci.h"
+#include "ehci-core.h"
+
+#include <asm/errno.h>
+#include <asm/arch/usb.h>
+
+
+/*
+ * This is a list of base addresses for each USB port. These CONFIG_TEGRA2_...
+ * values are defined in the board config files. Non-existent ports are zero.
+ */
+int USB_base_addr[5] = {
+ CONFIG_TEGRA2_USB0,
+ CONFIG_TEGRA2_USB1,
+ CONFIG_TEGRA2_USB2,
+ CONFIG_TEGRA2_USB3,
+ 0
+};
+
+/*
+ * Create the appropriate control structures to manage
+ * a new EHCI host controller.
+ */
+int ehci_hcd_init(void)
+{
+ /* EHCI registers start at offset 0x100. For now support only port 0*/
+ hccr = (struct ehci_hccr *)(CONFIG_TEGRA2_USB0 + 0x100);
+ hcor = (struct ehci_hcor *)((uint32_t) hccr
+ + HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
+
+ return 0;
+}
+
+/*
+ * Destroy the appropriate control structures corresponding
+ * the the EHCI host controller.
+ */
+int ehci_hcd_stop(void)
+{
+#ifdef CONFIG_TEGRA2_USB1_HOST
+ usb1_set_host_mode();
+#endif
+ ehci_writel(&hcor->or_usbcmd, 0);
+ udelay(1000);
+ ehci_writel(&hcor->or_usbcmd, 2);
+ udelay(1000);
+ return 0;
+}
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 945ab64f951..29ec82f3b1a 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -80,7 +80,11 @@ struct ehci_hcor {
uint32_t or_ctrldssegment;
uint32_t or_periodiclistbase;
uint32_t or_asynclistaddr;
- uint32_t _reserved_[9];
+ uint32_t _reserved_0_;
+ uint32_t or_burstsize;
+ uint32_t or_txfilltuning;
+#define TXFIFO_THRESH(p) ((p & 0x3f) << 16)
+ uint32_t _reserved_1_[6];
uint32_t or_configflag;
#define FLAG_CF (1 << 0) /* true: we'll support "high speed" */
uint32_t or_portsc[CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS];
diff --git a/include/configs/seaboard.h b/include/configs/seaboard.h
index 27c8ae1d37c..76ffd9578a8 100644
--- a/include/configs/seaboard.h
+++ b/include/configs/seaboard.h
@@ -43,4 +43,14 @@
#define CONFIG_BOARD_EARLY_INIT_F
#define CONFIG_TEGRA2_GPIO
#define CONFIG_CMD_TEGRA2_GPIO_INFO
+
+/* To select the order in which U-Boot sees USB ports */
+#define CONFIG_TEGRA2_USB0 NV_PA_USB3_BASE
+#define CONFIG_TEGRA2_USB1 NV_PA_USB1_BASE
+#define CONFIG_TEGRA2_USB2 0
+#define CONFIG_TEGRA2_USB3 0
+
+/* Put USB1 in host mode */
+#define CONFIG_TEGRA2_USB1_HOST
+
#endif /* __CONFIG_H */
diff --git a/include/configs/tegra2-common.h b/include/configs/tegra2-common.h
index febce35ac1e..ae417ea7c0e 100644
--- a/include/configs/tegra2-common.h
+++ b/include/configs/tegra2-common.h
@@ -84,6 +84,36 @@
#define CONFIG_SYS_BAUDRATE_TABLE {4800, 9600, 19200, 38400, 57600,\
115200}
+
+/*
+ * USB Host.
+ */
+#define CONFIG_USB_EHCI
+#define CONFIG_USB_EHCI_TEGRA
+#define CONFIG_USB_CONTROLLER_INSTANCES 2
+
+/* Tegra2 requires USB buffers to be aligned to a word boundary */
+#define CONFIG_USB_EHCI_DATA_ALIGN 4
+
+/*
+ * This parameter affects a TXFILLTUNING field that controls how much data is
+ * sent to the latency fifo before it is sent to the wire. Without this
+ * parameter, the default (2) causes occasional Data Buffer Errors in OUT
+ * packets depending on the buffer address and size.
+ */
+#define CONFIG_USB_EHCI_TXFIFO_THRESH 10
+
+#define CONFIG_EHCI_IS_TDI
+#define CONFIG_USB_STORAGE
+
+#define CONFIG_CMD_USB /* USB Host support */
+
+/* partition types and file systems we want */
+#define CONFIG_DOS_PARTITION
+#define CONFIG_EFI_PARTITION
+#define CONFIG_CMD_EXT2
+
+
/* include default commands */
#include <config_cmd_default.h>