From patchwork Fri Apr 29 01:00:47 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 93366 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 7F91AB6F74 for ; Fri, 29 Apr 2011 11:01:29 +1000 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id D5937280A5; Fri, 29 Apr 2011 03:01:27 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id Yo9XzBit6Pu8; Fri, 29 Apr 2011 03:01:27 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id B2D672808A; Fri, 29 Apr 2011 03:01:24 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id B8A122808A for ; Fri, 29 Apr 2011 03:01:22 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id t6ix-A3QnUlh for ; Fri, 29 Apr 2011 03:01:20 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from smtp-out.google.com (smtp-out.google.com [74.125.121.67]) by theia.denx.de (Postfix) with ESMTPS id 05D0528086 for ; Fri, 29 Apr 2011 03:01:18 +0200 (CEST) Received: from wpaz24.hot.corp.google.com (wpaz24.hot.corp.google.com [172.24.198.88]) by smtp-out.google.com with ESMTP id p3T116QZ002174; Thu, 28 Apr 2011 18:01:06 -0700 Received: from sglass.mtv.corp.google.com (sglass.mtv.corp.google.com [172.22.72.144]) by wpaz24.hot.corp.google.com with ESMTP id p3T10r2g010675; Thu, 28 Apr 2011 18:00:53 -0700 Received: by sglass.mtv.corp.google.com (Postfix, from userid 121222) id 77665140A7B; Thu, 28 Apr 2011 18:00:53 -0700 (PDT) From: Simon Glass To: u-boot@lists.denx.de Date: Thu, 28 Apr 2011 18:00:47 -0700 Message-Id: <1304038847-23703-1-git-send-email-sjg@chromium.org> X-Mailer: git-send-email 1.7.3.1 X-System-Of-Record: true Subject: [U-Boot] [PATCH 6/7] Tegra2: Add USB support X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.9 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de This adds basic USB support for port 0. The other port is not supported by this CL. TEST=Put USB stick in side port. Then: Tegra2 (SeaBoard) # ext2load usb 0:3 10000000 /boot/vmlinuz Loading file "/boot/vmlinuz" from usb device 0:3 (gpt3) 2745808 bytes read Tegra2 (SeaBoard) # Signed-off-by: Simon Glass --- 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/seaboard.h | 12 + include/configs/tegra2-common.h | 30 +++ 11 files changed, 750 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 -- 1.7.3.1 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 #include #include +#include #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..cb11048 --- /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 + * + * 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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +/* 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 + * ms = *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 +#include + +#include "ehci.h" +#include "ehci-core.h" + +#include +#include + + +/* + * 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/seaboard.h b/include/configs/seaboard.h index 06ce3e2..76ffd95 100644 --- a/include/configs/seaboard.h +++ b/include/configs/seaboard.h @@ -41,4 +41,16 @@ #define CONFIG_SYS_BOARD_ODMDATA 0x300d8011 /* lp1, 1GB */ #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 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