[U-Boot] [PATCH v2 6/7] Tegra2: Add USB support

Simon Glass sjg at chromium.org
Thu May 5 21:34:19 CEST 2011


This adds basic USB support for port 0. The other port is not supported by this CL.

Signed-off-by: Simon Glass <sjg at chromium.org>
---
 arch/arm/include/asm/arch-tegra2/tegra2.h |    2 +
 arch/arm/include/asm/arch-tegra2/usb.h    |  217 ++++++++++++++++++++
 board/nvidia/common/Makefile              |   53 +++++
 board/nvidia/common/board.c               |    5 +
 board/nvidia/common/usb.c                 |  313 +++++++++++++++++++++++++++++
 drivers/usb/host/Makefile                 |    1 +
 drivers/usb/host/ehci-hcd.c               |   39 ++++
 drivers/usb/host/ehci-tegra.c             |   73 +++++++
 drivers/usb/host/ehci.h                   |    6 +-
 include/configs/harmony.h                 |    7 +
 include/configs/seaboard.h                |   10 +
 include/configs/tegra2-common.h           |   30 +++
 12 files changed, 755 insertions(+), 1 deletions(-)
 create mode 100644 arch/arm/include/asm/arch-tegra2/usb.h
 create mode 100644 board/nvidia/common/Makefile
 create mode 100644 board/nvidia/common/usb.c
 create mode 100644 drivers/usb/host/ehci-tegra.c

diff --git a/arch/arm/include/asm/arch-tegra2/tegra2.h b/arch/arm/include/asm/arch-tegra2/tegra2.h
index 742a75a..3bf0051 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 0000000..c37f404
--- /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 0000000..9bd0bf2
--- /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 ac2e3f8..658bf1f 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 0000000..0f70306
--- /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 51b2494..a8e107b 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 70c02c9..1049612 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 0000000..04e43b8
--- /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 945ab64..29ec82f 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/harmony.h b/include/configs/harmony.h
index 34bd899..0f49d88 100644
--- a/include/configs/harmony.h
+++ b/include/configs/harmony.h
@@ -47,4 +47,11 @@
 #define CONFIG_SYS_BOARD_ODMDATA	0x300d8011 /* lp1, 1GB */

 #define CONFIG_BOARD_EARLY_INIT_F
+
+/* 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
+
 #endif /* __CONFIG_H */
diff --git a/include/configs/seaboard.h b/include/configs/seaboard.h
index 06ce3e2..9c062e8 100644
--- a/include/configs/seaboard.h
+++ b/include/configs/seaboard.h
@@ -41,4 +41,14 @@
 #define CONFIG_SYS_BOARD_ODMDATA	0x300d8011 /* lp1, 1GB */

 #define CONFIG_BOARD_EARLY_INIT_F
+
+/* 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 febce35..ae417ea 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>

--
1.7.3.1



More information about the U-Boot mailing list