diff options
Diffstat (limited to 'arch/arm/cpu/armv7/tegra20/usb.c')
-rw-r--r-- | arch/arm/cpu/armv7/tegra20/usb.c | 176 |
1 files changed, 139 insertions, 37 deletions
diff --git a/arch/arm/cpu/armv7/tegra20/usb.c b/arch/arm/cpu/armv7/tegra20/usb.c index cac0918ff3..1bccf2b0b2 100644 --- a/arch/arm/cpu/armv7/tegra20/usb.c +++ b/arch/arm/cpu/armv7/tegra20/usb.c @@ -24,17 +24,25 @@ #include <common.h> #include <asm/io.h> #include <asm-generic/gpio.h> -#include <asm/arch/tegra20.h> -#include <asm/arch/clk_rst.h> #include <asm/arch/clock.h> #include <asm/arch/gpio.h> #include <asm/arch/pinmux.h> -#include <asm/arch/sys_proto.h> -#include <asm/arch/uart.h> +#include <asm/arch/tegra.h> #include <asm/arch/usb.h> +#include <usb/ulpi.h> +#include <asm/arch-tegra/clk_rst.h> +#include <asm/arch-tegra/sys_proto.h> +#include <asm/arch-tegra/uart.h> #include <libfdt.h> #include <fdtdec.h> +#ifdef CONFIG_USB_ULPI + #ifndef CONFIG_USB_ULPI_VIEWPORT + #error "To use CONFIG_USB_ULPI on Tegra Boards you have to also \ + define CONFIG_USB_ULPI_VIEWPORT" + #endif +#endif + enum { USB_PORTS_MAX = 4, /* Maximum ports we allow */ }; @@ -68,16 +76,17 @@ enum dr_mode { struct fdt_usb { struct usb_ctlr *reg; /* address of registers in physical memory */ unsigned utmi:1; /* 1 if port has external tranceiver, else 0 */ + unsigned ulpi:1; /* 1 if port has external ULPI transceiver */ unsigned enabled:1; /* 1 to enable, 0 to disable */ unsigned has_legacy_mode:1; /* 1 if this port has legacy mode */ enum dr_mode dr_mode; /* dual role mode */ enum periph_id periph_id;/* peripheral id */ struct fdt_gpio_state vbus_gpio; /* GPIO for vbus enable */ + struct fdt_gpio_state phy_reset_gpio; /* GPIO to reset ULPI phy */ }; static struct fdt_usb port[USB_PORTS_MAX]; /* List of valid USB ports */ static unsigned port_count; /* Number of available ports */ -static int port_current; /* Current port (-1 = none) */ /* * This table has USB timing parameters for each Oscillator frequency we @@ -188,8 +197,8 @@ void usbf_reset_controller(struct fdt_usb *config, struct usb_ctlr *usbctlr) */ } -/* set up the USB controller with the parameters provided */ -static int init_usb_controller(struct fdt_usb *config, +/* set up the UTMI USB controller with the parameters provided */ +static int init_utmi_usb_controller(struct fdt_usb *config, struct usb_ctlr *usbctlr, const u32 timing[]) { u32 val; @@ -298,17 +307,115 @@ static int init_usb_controller(struct fdt_usb *config, if (!loop_count) return -1; - return 0; -} + /* Disable ICUSB FS/LS transceiver */ + clrbits_le32(&usbctlr->icusb_ctrl, IC_ENB1); + + /* Select UTMI parallel interface */ + clrsetbits_le32(&usbctlr->port_sc1, PTS_MASK, + PTS_UTMI << PTS_SHIFT); + clrbits_le32(&usbctlr->port_sc1, STS); -static void power_up_port(struct usb_ctlr *usbctlr) -{ /* Deassert power down state */ clrbits_le32(&usbctlr->utmip_xcvr_cfg0, UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN | UTMIP_FORCE_PDZI_POWERDOWN); clrbits_le32(&usbctlr->utmip_xcvr_cfg1, UTMIP_FORCE_PDDISC_POWERDOWN | UTMIP_FORCE_PDCHRP_POWERDOWN | UTMIP_FORCE_PDDR_POWERDOWN); + + return 0; +} + +#ifdef CONFIG_USB_ULPI +/* if board file does not set a ULPI reference frequency we default to 24MHz */ +#ifndef CONFIG_ULPI_REF_CLK +#define CONFIG_ULPI_REF_CLK 24000000 +#endif + +/* set up the ULPI USB controller with the parameters provided */ +static int init_ulpi_usb_controller(struct fdt_usb *config, + struct usb_ctlr *usbctlr) +{ + u32 val; + int loop_count; + struct ulpi_viewport ulpi_vp; + + /* set up ULPI reference clock on pllp_out4 */ + clock_enable(PERIPH_ID_DEV2_OUT); + clock_set_pllout(CLOCK_ID_PERIPH, PLL_OUT4, CONFIG_ULPI_REF_CLK); + + /* reset ULPI phy */ + if (fdt_gpio_isvalid(&config->phy_reset_gpio)) { + fdtdec_setup_gpio(&config->phy_reset_gpio); + gpio_direction_output(config->phy_reset_gpio.gpio, 0); + mdelay(5); + gpio_set_value(config->phy_reset_gpio.gpio, 1); + } + + /* Reset the usb controller */ + clock_enable(config->periph_id); + usbf_reset_controller(config, usbctlr); + + /* enable pinmux bypass */ + setbits_le32(&usbctlr->ulpi_timing_ctrl_0, + ULPI_CLKOUT_PINMUX_BYP | ULPI_OUTPUT_PINMUX_BYP); + + /* Select ULPI parallel interface */ + clrsetbits_le32(&usbctlr->port_sc1, PTS_MASK, PTS_ULPI << PTS_SHIFT); + + /* enable ULPI transceiver */ + setbits_le32(&usbctlr->susp_ctrl, ULPI_PHY_ENB); + + /* configure ULPI transceiver timings */ + val = 0; + writel(val, &usbctlr->ulpi_timing_ctrl_1); + + val |= ULPI_DATA_TRIMMER_SEL(4); + val |= ULPI_STPDIRNXT_TRIMMER_SEL(4); + val |= ULPI_DIR_TRIMMER_SEL(4); + writel(val, &usbctlr->ulpi_timing_ctrl_1); + udelay(10); + + val |= ULPI_DATA_TRIMMER_LOAD; + val |= ULPI_STPDIRNXT_TRIMMER_LOAD; + val |= ULPI_DIR_TRIMMER_LOAD; + writel(val, &usbctlr->ulpi_timing_ctrl_1); + + /* set up phy for host operation with external vbus supply */ + ulpi_vp.port_num = 0; + ulpi_vp.viewport_addr = (u32)&usbctlr->ulpi_viewport; + + if (ulpi_init(&ulpi_vp)) { + printf("Tegra ULPI viewport init failed\n"); + return -1; + } + + ulpi_set_vbus(&ulpi_vp, 1, 1); + ulpi_set_vbus_indicator(&ulpi_vp, 1, 1, 0); + + /* enable wakeup events */ + setbits_le32(&usbctlr->port_sc1, WKCN | WKDS | WKOC); + + /* Enable and wait for the phy clock to become valid in 100 ms */ + setbits_le32(&usbctlr->susp_ctrl, USB_SUSP_CLR); + for (loop_count = 100000; loop_count != 0; loop_count--) { + if (readl(&usbctlr->susp_ctrl) & USB_PHY_CLK_VALID) + break; + udelay(1); + } + if (!loop_count) + return -1; + clrbits_le32(&usbctlr->susp_ctrl, USB_SUSP_CLR); + + return 0; +} +#else +static int init_ulpi_usb_controller(struct fdt_usb *config, + struct usb_ctlr *usbctlr) +{ + printf("No code to set up ULPI controller, please enable" + "CONFIG_USB_ULPI and CONFIG_USB_ULPI_VIEWPORT"); + return -1; } +#endif static void config_clock(const u32 timing[]) { @@ -328,53 +435,45 @@ static int add_port(struct fdt_usb *config, const u32 timing[]) struct usb_ctlr *usbctlr = config->reg; if (port_count == USB_PORTS_MAX) { - debug("tegrausb: Cannot register more than %d ports\n", + printf("tegrausb: Cannot register more than %d ports\n", USB_PORTS_MAX); return -1; } - if (init_usb_controller(config, usbctlr, timing)) { - debug("tegrausb: Cannot init port\n"); + + if (config->utmi && init_utmi_usb_controller(config, usbctlr, timing)) { + printf("tegrausb: Cannot init port\n"); return -1; } - if (config->utmi) { - /* Disable ICUSB FS/LS transceiver */ - clrbits_le32(&usbctlr->icusb_ctrl, IC_ENB1); - - /* Select UTMI parallel interface */ - clrsetbits_le32(&usbctlr->port_sc1, PTS_MASK, - PTS_UTMI << PTS_SHIFT); - clrbits_le32(&usbctlr->port_sc1, STS); - power_up_port(usbctlr); + + if (config->ulpi && init_ulpi_usb_controller(config, usbctlr)) { + printf("tegrausb: Cannot init port\n"); + return -1; } + port[port_count++] = *config; return 0; } -int tegrausb_start_port(unsigned portnum, u32 *hccr, u32 *hcor) +int tegrausb_start_port(int portnum, u32 *hccr, u32 *hcor) { struct usb_ctlr *usbctlr; if (portnum >= port_count) return -1; - tegrausb_stop_port(); set_host_mode(&port[portnum]); usbctlr = port[portnum].reg; *hccr = (u32)&usbctlr->cap_length; *hcor = (u32)&usbctlr->usb_cmd; - port_current = portnum; return 0; } -int tegrausb_stop_port(void) +int tegrausb_stop_port(int portnum) { struct usb_ctlr *usbctlr; - if (port_current == -1) - return -1; - - usbctlr = port[port_current].reg; + usbctlr = port[portnum].reg; /* Stop controller */ writel(0, &usbctlr->usb_cmd); @@ -383,7 +482,7 @@ int tegrausb_stop_port(void) /* Initiate controller reset */ writel(2, &usbctlr->usb_cmd); udelay(1000); - port_current = -1; + return 0; } @@ -412,6 +511,7 @@ int fdt_decode_usb(const void *blob, int node, unsigned osc_frequency_mhz, phy = fdt_getprop(blob, node, "phy_type", NULL); config->utmi = phy && 0 == strcmp("utmi", phy); + config->ulpi = phy && 0 == strcmp("ulpi", phy); config->enabled = fdtdec_get_is_enabled(blob, node); config->has_legacy_mode = fdtdec_get_bool(blob, node, "nvidia,has-legacy-mode"); @@ -421,10 +521,13 @@ int fdt_decode_usb(const void *blob, int node, unsigned osc_frequency_mhz, return -FDT_ERR_NOTFOUND; } fdtdec_decode_gpio(blob, node, "nvidia,vbus-gpio", &config->vbus_gpio); - debug("enabled=%d, legacy_mode=%d, utmi=%d, periph_id=%d, vbus=%d, " - "dr_mode=%d\n", config->enabled, config->has_legacy_mode, - config->utmi, config->periph_id, config->vbus_gpio.gpio, - config->dr_mode); + fdtdec_decode_gpio(blob, node, "nvidia,phy-reset-gpio", + &config->phy_reset_gpio); + debug("enabled=%d, legacy_mode=%d, utmi=%d, ulpi=%d, periph_id=%d, " + "vbus=%d, phy_reset=%d, dr_mode=%d\n", + config->enabled, config->has_legacy_mode, config->utmi, + config->ulpi, config->periph_id, config->vbus_gpio.gpio, + config->phy_reset_gpio.gpio, config->dr_mode); return 0; } @@ -459,7 +562,6 @@ int board_usb_init(const void *blob) return -1; set_host_mode(&config); } - port_current = -1; return 0; } |