public inbox for u-boot@lists.denx.de
 help / color / mirror / Atom feed
From: Igor Grinberg <grinberg@compulab.co.il>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH 3/3] tegra20: add USB ULPI init code
Date: Mon, 20 Aug 2012 15:07:36 +0300	[thread overview]
Message-ID: <50322888.4080404@compulab.co.il> (raw)
In-Reply-To: <1345392496-28739-4-git-send-email-dev@lynxeye.de>

Hi Lucas,

On 08/19/12 19:08, 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.

Can you share which tweaks for correctness are there?

> 
> To use this both CONFIG_USB_ULPI and CONFIG_USB_ULPI_VIEWPORT
> have to be set in the board configuration file.
> 
> Signed-off-by: Lucas Stach <dev@lynxeye.de>
> ---
>  arch/arm/cpu/armv7/tegra20/usb.c        | 131 +++++++++++++++++++++++++++++---
>  arch/arm/include/asm/arch-tegra20/usb.h |  29 +++++--
>  2 Dateien ge?ndert, 145 Zeilen hinzugef?gt(+), 15 Zeilen entfernt(-)
> 
> diff --git a/arch/arm/cpu/armv7/tegra20/usb.c b/arch/arm/cpu/armv7/tegra20/usb.c
> index 77966e5..2ae1244 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"

there is a mix of tabs and spaces in the above line, please make it only tabs

> +	#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 */
> @@ -187,8 +197,8 @@ static void usbf_reset_controller(struct fdt_usb *config,
>  	 */
>  }
>  
> -/* 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;
> @@ -300,6 +310,83 @@ static int init_usb_controller(struct fdt_usb *config,
>  	return 0;
>  }
>  
> +#ifdef CONFIG_USB_ULPI
> +/* 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_regs *ulpi_reg = (struct ulpi_regs *)0;
> +	struct ulpi_viewport ulpi_vp;
> +
> +	/* 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)) {
> +		debug("Tegra ULPI viewport init failed\n");

This looks like an error, right?
So why hide it under debug?

> +		return -1;
> +	}
> +
> +	ulpi_write(&ulpi_vp, &ulpi_reg->iface_ctrl_set, ULPI_IFACE_PASSTHRU);

The implementation for the indicator setup is currently missing
from the generic framework.
Have you thought about adding it?

> +	ulpi_write(&ulpi_vp, &ulpi_reg->otg_ctrl_set, ULPI_OTG_EXTVBUSIND);

Can ulpi_set_vbus(&ulpi_vp, 1, 1, 1) be used here?

> +
> +	/* enable wakeup events */
> +	setbits_le32(&usbctlr->port_sc1, WKCN | WKDS | WKOC);
> +
> +	setbits_le32(&usbctlr->susp_ctrl, USB_SUSP_CLR);
> +	/* Wait for the phy clock to become valid in 100 ms */
> +	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;
> +}
> +#endif
> +
>  static void power_up_port(struct usb_ctlr *usbctlr)
>  {
>  	/* Deassert power down state */
> @@ -331,11 +418,13 @@ static int add_port(struct fdt_usb *config, const u32 timing[])
>  		      USB_PORTS_MAX);
>  		return -1;
>  	}
> -	if (init_usb_controller(config, usbctlr, timing)) {
> -		debug("tegrausb: Cannot init port\n");
> -		return -1;
> -	}
> +
>  	if (config->utmi) {
> +		if (init_utmi_usb_controller(config, usbctlr, timing)) {
> +			debug("tegrausb: Cannot init port\n");

This also looks like an error...
So why debug()?

> +			return -1;
> +		}
> +
>  		/* Disable ICUSB FS/LS transceiver */
>  		clrbits_le32(&usbctlr->icusb_ctrl, IC_ENB1);
>  
> @@ -345,6 +434,24 @@ static int add_port(struct fdt_usb *config, const u32 timing[])
>  		clrbits_le32(&usbctlr->port_sc1, STS);
>  		power_up_port(usbctlr);
>  	}
> +
> +	if (config->ulpi) {
> +#ifdef CONFIG_USB_ULPI
> +		/* set up 24MHz ULPI reference clock on pllp_out4 */
> +		clock_enable(PERIPH_ID_DEV2_OUT);
> +		clock_set_pllout(CLOCK_ID_PERIPH, PLL_OUT4, 24000000);

Wouldn't it be clearer if:
1) you put the above inside the init_ulpi_usb_controller() function
2) Provide a !CONFIG_USB_ULPI implementation of the same function
   technically having only the code under #else below inside.

So then here instead of the whole #ifdef, you will have something like:
if (config->ulpi) {
	if (init_ulpi_usb_controller(config, usbctlr)) {
		printf("tegrausb: Cannot init port\n");
		return -1;
	}
}

> +
> +		if (init_ulpi_usb_controller(config, usbctlr)) {
> +			debug("tegrausb: Cannot init port\n");
> +			return -1;
> +		}
> +#else
> +		debug("No code to set up ULPI controller, please enable"
> +		      "CONFIG_USB_ULPI and CONFIG_USB_ULPI_VIEWPORT");
> +		return -1;
> +#endif
> +	}
> +
>  	port[port_count++] = *config;
>  
>  	return 0;

[...]



-- 
Regards,
Igor.

  reply	other threads:[~2012-08-20 12:07 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-08-19 16:08 [U-Boot] [PATCH 0/3] Tegra 2 USB ULPI series Lucas Stach
2012-08-19 16:08 ` [U-Boot] [PATCH 1/3] tegra20: complete periph_id enum Lucas Stach
2012-08-20 18:12   ` Stephen Warren
2012-08-21 19:04   ` Simon Glass
2012-08-19 16:08 ` [U-Boot] [PATCH 2/3] tegra20: add clock_set_pllout function Lucas Stach
2012-08-20 18:19   ` Stephen Warren
2012-08-19 16:08 ` [U-Boot] [PATCH 3/3] tegra20: add USB ULPI init code Lucas Stach
2012-08-20 12:07   ` Igor Grinberg [this message]
2012-08-20 12:41     ` Lucas Stach
2012-08-20 18:27       ` Stephen Warren
2012-08-21  7:59         ` Igor Grinberg
2012-08-21  7:54       ` Igor Grinberg
2012-08-20 18:25   ` Stephen Warren
2012-08-20 12:27 ` [U-Boot] [PATCH 0/3] Tegra 2 USB ULPI series Igor Grinberg
2012-08-20 12:43   ` Lucas Stach
2012-08-20 18:09 ` Stephen Warren
2012-08-20 19:59   ` Lucas Stach
2012-08-22 16:06     ` Stephen Warren

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=50322888.4080404@compulab.co.il \
    --to=grinberg@compulab.co.il \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox