Message ID | 1348612532-24419-3-git-send-email-dev@lynxeye.de |
---|---|
State | Accepted |
Delegated to: | Tom Warren |
Headers | show |
On 09/26/12 00:35, Lucas Stach wrote: > This adds the required code to set up a ULPI USB port. It is > mostly a port of the Linux ULPI setup code with some tweaks > added for more correctness, discovered along the way of > debugging this. > > To use this both CONFIG_USB_ULPI and CONFIG_USB_ULPI_VIEWPORT > have to be set in the board configuration file. > > v2: > - move all controller init stuff in the respective functions to > make them self contained > - let board define ULPI_REF_CLK to account for the possibility > that some ULPI phys need a other ref clk than 24MHz > - don't touch ULPI regs directly, use ULPI framework functions > - don't hide error messages under debug() > > v3: > - apply last comments from Igor, which make code still a bit cleaner > - add description of CONFIG_ULPI_REF_CLK to README I think the above (change history) belongs under the scissors line ('---'). > > Signed-off-by: Lucas Stach <dev@lynxeye.de> Apart from some (this time really) minor comments above and below: Acked-by: Igor Grinberg <grinberg@compulab.co.il> > --- > README | 3 + > arch/arm/cpu/armv7/tegra20/usb.c | 152 +++++++++++++++++++++++++++----- > arch/arm/include/asm/arch-tegra20/usb.h | 29 ++++-- > 3 Dateien geändert, 157 Zeilen hinzugefügt(+), 27 Zeilen entfernt(-) > > diff --git a/README b/README > index 4428205..3919143 100644 > --- a/README > +++ b/README > @@ -1239,6 +1239,9 @@ The following options need to be configured: > viewport is supported. > To enable the ULPI layer support, define CONFIG_USB_ULPI and > CONFIG_USB_ULPI_VIEWPORT in your board configuration file. > + If your ULPI phy needs a different reference clock than the > + standard 24 MHz then you have to define CONFIG_ULPI_REF_CLK to > + the appropiate value in Hz. s/appropiate/appropriate/ > > - MMC Support: > The MMC controller on the Intel PXA is supported. To > diff --git a/arch/arm/cpu/armv7/tegra20/usb.c b/arch/arm/cpu/armv7/tegra20/usb.c > index cac0918..86e52f6 100644 > --- a/arch/arm/cpu/armv7/tegra20/usb.c > +++ b/arch/arm/cpu/armv7/tegra20/usb.c > @@ -32,9 +32,17 @@ > #include <asm/arch/sys_proto.h> > #include <asm/arch/uart.h> > #include <asm/arch/usb.h> > +#include <usb/ulpi.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,11 +76,13 @@ 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 */ > @@ -188,8 +198,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 +308,114 @@ 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; > +} an empty line here would be nice. > +#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,24 +435,21 @@ 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; > @@ -412,6 +516,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 +526,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; > } > diff --git a/arch/arm/include/asm/arch-tegra20/usb.h b/arch/arm/include/asm/arch-tegra20/usb.h > index 638033b..bd89d66 100644 > --- a/arch/arm/include/asm/arch-tegra20/usb.h > +++ b/arch/arm/include/asm/arch-tegra20/usb.h > @@ -100,10 +100,12 @@ struct usb_ctlr { > > /* 0x410 */ > uint usb1_legacy_ctrl; > - uint reserved12[3]; > + uint reserved12[4]; > > - /* 0x420 */ > - uint reserved13[56]; > + /* 0x424 */ > + uint ulpi_timing_ctrl_0; > + uint ulpi_timing_ctrl_1; > + uint reserved13[53]; > > /* 0x500 */ > uint reserved14[64 * 3]; > @@ -144,10 +146,24 @@ struct usb_ctlr { > #define VBUS_SENSE_CTL_AB_SESS_VLD 2 > #define VBUS_SENSE_CTL_A_SESS_VLD 3 > > +/* USB2_IF_ULPI_TIMING_CTRL_0 */ > +#define ULPI_OUTPUT_PINMUX_BYP (1 << 10) > +#define ULPI_CLKOUT_PINMUX_BYP (1 << 11) > + > +/* USB2_IF_ULPI_TIMING_CTRL_1 */ > +#define ULPI_DATA_TRIMMER_LOAD (1 << 0) > +#define ULPI_DATA_TRIMMER_SEL(x) (((x) & 0x7) << 1) > +#define ULPI_STPDIRNXT_TRIMMER_LOAD (1 << 16) > +#define ULPI_STPDIRNXT_TRIMMER_SEL(x) (((x) & 0x7) << 17) > +#define ULPI_DIR_TRIMMER_LOAD (1 << 24) > +#define ULPI_DIR_TRIMMER_SEL(x) (((x) & 0x7) << 25) > + > /* USBx_IF_USB_SUSP_CTRL_0 */ > +#define ULPI_PHY_ENB (1 << 13) > #define UTMIP_PHY_ENB (1 << 12) > #define UTMIP_RESET (1 << 11) > #define USB_PHY_CLK_VALID (1 << 7) > +#define USB_SUSP_CLR (1 << 5) > > /* USBx_UTMIP_MISC_CFG1 */ > #define UTMIP_PLLU_STABLE_COUNT_SHIFT 6 > @@ -203,12 +219,15 @@ struct usb_ctlr { > /* SB2_CONTROLLER_2_USB2D_PORTSC1_0 */ > #define PTS_SHIFT 30 > #define PTS_MASK (3U << PTS_SHIFT) > -#define PTS_UTMI 0 > +#define PTS_UTMI 0 > #define PTS_RESERVED 1 > -#define PTS_ULP 2 > +#define PTS_ULPI 2 > #define PTS_ICUSB_SER 3 > > #define STS (1 << 29) > +#define WKOC (1 << 22) > +#define WKDS (1 << 21) > +#define WKCN (1 << 20) > > /* USBx_UTMIP_XCVR_CFG0_0 */ > #define UTMIP_FORCE_PD_POWERDOWN (1 << 14)
diff --git a/README b/README index 4428205..3919143 100644 --- a/README +++ b/README @@ -1239,6 +1239,9 @@ The following options need to be configured: viewport is supported. To enable the ULPI layer support, define CONFIG_USB_ULPI and CONFIG_USB_ULPI_VIEWPORT in your board configuration file. + If your ULPI phy needs a different reference clock than the + standard 24 MHz then you have to define CONFIG_ULPI_REF_CLK to + the appropiate value in Hz. - MMC Support: The MMC controller on the Intel PXA is supported. To diff --git a/arch/arm/cpu/armv7/tegra20/usb.c b/arch/arm/cpu/armv7/tegra20/usb.c index cac0918..86e52f6 100644 --- a/arch/arm/cpu/armv7/tegra20/usb.c +++ b/arch/arm/cpu/armv7/tegra20/usb.c @@ -32,9 +32,17 @@ #include <asm/arch/sys_proto.h> #include <asm/arch/uart.h> #include <asm/arch/usb.h> +#include <usb/ulpi.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,11 +76,13 @@ 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 */ @@ -188,8 +198,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 +308,114 @@ 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,24 +435,21 @@ 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; @@ -412,6 +516,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 +526,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; } diff --git a/arch/arm/include/asm/arch-tegra20/usb.h b/arch/arm/include/asm/arch-tegra20/usb.h index 638033b..bd89d66 100644 --- a/arch/arm/include/asm/arch-tegra20/usb.h +++ b/arch/arm/include/asm/arch-tegra20/usb.h @@ -100,10 +100,12 @@ struct usb_ctlr { /* 0x410 */ uint usb1_legacy_ctrl; - uint reserved12[3]; + uint reserved12[4]; - /* 0x420 */ - uint reserved13[56]; + /* 0x424 */ + uint ulpi_timing_ctrl_0; + uint ulpi_timing_ctrl_1; + uint reserved13[53]; /* 0x500 */ uint reserved14[64 * 3]; @@ -144,10 +146,24 @@ struct usb_ctlr { #define VBUS_SENSE_CTL_AB_SESS_VLD 2 #define VBUS_SENSE_CTL_A_SESS_VLD 3 +/* USB2_IF_ULPI_TIMING_CTRL_0 */ +#define ULPI_OUTPUT_PINMUX_BYP (1 << 10) +#define ULPI_CLKOUT_PINMUX_BYP (1 << 11) + +/* USB2_IF_ULPI_TIMING_CTRL_1 */ +#define ULPI_DATA_TRIMMER_LOAD (1 << 0) +#define ULPI_DATA_TRIMMER_SEL(x) (((x) & 0x7) << 1) +#define ULPI_STPDIRNXT_TRIMMER_LOAD (1 << 16) +#define ULPI_STPDIRNXT_TRIMMER_SEL(x) (((x) & 0x7) << 17) +#define ULPI_DIR_TRIMMER_LOAD (1 << 24) +#define ULPI_DIR_TRIMMER_SEL(x) (((x) & 0x7) << 25) + /* USBx_IF_USB_SUSP_CTRL_0 */ +#define ULPI_PHY_ENB (1 << 13) #define UTMIP_PHY_ENB (1 << 12) #define UTMIP_RESET (1 << 11) #define USB_PHY_CLK_VALID (1 << 7) +#define USB_SUSP_CLR (1 << 5) /* USBx_UTMIP_MISC_CFG1 */ #define UTMIP_PLLU_STABLE_COUNT_SHIFT 6 @@ -203,12 +219,15 @@ struct usb_ctlr { /* SB2_CONTROLLER_2_USB2D_PORTSC1_0 */ #define PTS_SHIFT 30 #define PTS_MASK (3U << PTS_SHIFT) -#define PTS_UTMI 0 +#define PTS_UTMI 0 #define PTS_RESERVED 1 -#define PTS_ULP 2 +#define PTS_ULPI 2 #define PTS_ICUSB_SER 3 #define STS (1 << 29) +#define WKOC (1 << 22) +#define WKDS (1 << 21) +#define WKCN (1 << 20) /* USBx_UTMIP_XCVR_CFG0_0 */ #define UTMIP_FORCE_PD_POWERDOWN (1 << 14)
This adds the required code to set up a ULPI USB port. It is mostly a port of the Linux ULPI setup code with some tweaks added for more correctness, discovered along the way of debugging this. To use this both CONFIG_USB_ULPI and CONFIG_USB_ULPI_VIEWPORT have to be set in the board configuration file. v2: - move all controller init stuff in the respective functions to make them self contained - let board define ULPI_REF_CLK to account for the possibility that some ULPI phys need a other ref clk than 24MHz - don't touch ULPI regs directly, use ULPI framework functions - don't hide error messages under debug() v3: - apply last comments from Igor, which make code still a bit cleaner - add description of CONFIG_ULPI_REF_CLK to README Signed-off-by: Lucas Stach <dev@lynxeye.de> --- README | 3 + arch/arm/cpu/armv7/tegra20/usb.c | 152 +++++++++++++++++++++++++++----- arch/arm/include/asm/arch-tegra20/usb.h | 29 ++++-- 3 Dateien geändert, 157 Zeilen hinzugefügt(+), 27 Zeilen entfernt(-)