All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH v4 1/2] usb: ulpi: add indicator configuration function
@ 2012-09-30 22:44 Lucas Stach
  2012-09-30 22:44 ` [U-Boot] [PATCH v4 2/2] tegra20: add USB ULPI init code Lucas Stach
  0 siblings, 1 reply; 3+ messages in thread
From: Lucas Stach @ 2012-09-30 22:44 UTC (permalink / raw)
  To: u-boot

Allows for easy configuration of the VBUS indicator related ULPI
config bits.

Also move the external indicator setup from ulpi_set_vbus() to
the new function.

Signed-off-by: Lucas Stach <dev@lynxeye.de>
Acked-by: Igor Grinberg <grinberg@compulab.co.il>
---
v4:
- do r-m-w access on iface_ctrl register
- align with coding style of other ulpi functions
---
 drivers/usb/ulpi/ulpi.c | 32 ++++++++++++++++++++++++++++----
 include/usb/ulpi.h      | 13 +++++++++++--
 2 Dateien ge?ndert, 39 Zeilen hinzugef?gt(+), 6 Zeilen entfernt(-)

diff --git a/drivers/usb/ulpi/ulpi.c b/drivers/usb/ulpi/ulpi.c
index dde2585..23b59e7 100644
--- a/drivers/usb/ulpi/ulpi.c
+++ b/drivers/usb/ulpi/ulpi.c
@@ -106,20 +106,44 @@ int ulpi_select_transceiver(struct ulpi_viewport *ulpi_vp, unsigned speed)
 	return ulpi_write(ulpi_vp, &ulpi->function_ctrl, val);
 }
 
-int ulpi_set_vbus(struct ulpi_viewport *ulpi_vp, int on, int ext_power,
-			int ext_ind)
+int ulpi_set_vbus(struct ulpi_viewport *ulpi_vp, int on, int ext_power)
 {
 	u32 flags = ULPI_OTG_DRVVBUS;
 	u8 *reg = on ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear;
 
 	if (ext_power)
 		flags |= ULPI_OTG_DRVVBUS_EXT;
-	if (ext_ind)
-		flags |= ULPI_OTG_EXTVBUSIND;
 
 	return ulpi_write(ulpi_vp, reg, flags);
 }
 
+int ulpi_set_vbus_indicator(struct ulpi_viewport *ulpi_vp, int external,
+			int passthu, int complement)
+{
+	u32 flags, val;
+	u8 *reg;
+
+	reg = external ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear;
+	val = ulpi_write(ulpi_vp, reg, ULPI_OTG_EXTVBUSIND);
+	if (val)
+		return val;
+
+	flags = passthu ? ULPI_IFACE_PASSTHRU : 0;
+	flags |= complement ? ULPI_IFACE_EXTVBUS_COMPLEMENT : 0;
+
+	val = ulpi_read(ulpi_vp, &ulpi->iface_ctrl);
+	if (val == ULPI_ERROR)
+		return val;
+
+	val = val & ~(ULPI_IFACE_PASSTHRU & ULPI_IFACE_EXTVBUS_COMPLEMENT);
+	val |= flags;
+	val = ulpi_write(ulpi_vp, &ulpi->iface_ctrl, val);
+	if (val)
+		return val;
+
+	return 0;
+}
+
 int ulpi_set_pd(struct ulpi_viewport *ulpi_vp, int enable)
 {
 	u32 val = ULPI_OTG_DP_PULLDOWN | ULPI_OTG_DM_PULLDOWN;
diff --git a/include/usb/ulpi.h b/include/usb/ulpi.h
index 9a75c24..99166c4 100644
--- a/include/usb/ulpi.h
+++ b/include/usb/ulpi.h
@@ -61,8 +61,17 @@ int ulpi_select_transceiver(struct ulpi_viewport *ulpi_vp, unsigned speed);
  *
  * returns 0 on success, ULPI_ERROR on failure.
  */
-int ulpi_set_vbus(struct ulpi_viewport *ulpi_vp,
-			int on, int ext_power, int ext_ind);
+int ulpi_set_vbus(struct ulpi_viewport *ulpi_vp, int on, int ext_power);
+
+/*
+ * Configure VBUS indicator
+ * @external		- external VBUS over-current indicator is used
+ * @passthru		- disables ANDing of internal VBUS comparator
+ *                    with external VBUS input
+ * @complement		- inverts the external VBUS input
+ */
+int ulpi_set_vbus_indicator(struct ulpi_viewport *ulpi_vp, int external,
+			int passthru, int complement);
 
 /*
  * Enable/disable pull-down resistors on D+ and D- USB lines.
-- 
1.7.11.4

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [U-Boot] [PATCH v4 2/2] tegra20: add USB ULPI init code
  2012-09-30 22:44 [U-Boot] [PATCH v4 1/2] usb: ulpi: add indicator configuration function Lucas Stach
@ 2012-09-30 22:44 ` Lucas Stach
  2012-09-30 23:22   ` Marek Vasut
  0 siblings, 1 reply; 3+ messages in thread
From: Lucas Stach @ 2012-09-30 22:44 UTC (permalink / raw)
  To: u-boot

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.

Signed-off-by: Lucas Stach <dev@lynxeye.de>
Acked-by: Igor Grinberg <grinberg@compulab.co.il>
---
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

v4:
- fix typos spotted by Igor
---
 README                                  |   3 +
 arch/arm/cpu/armv7/tegra20/usb.c        | 153 +++++++++++++++++++++++++++-----
 arch/arm/include/asm/arch-tegra20/usb.h |  29 ++++--
 3 Dateien ge?ndert, 158 Zeilen hinzugef?gt(+), 27 Zeilen entfernt(-)

diff --git a/README b/README
index a745d0b..70fbf95 100644
--- a/README
+++ b/README
@@ -1264,6 +1264,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 appropriate 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 eda8e6f..1b52b16 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 */
@@ -187,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;
@@ -297,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[])
 {
@@ -327,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;
@@ -406,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");
@@ -415,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;
 }
diff --git a/arch/arm/include/asm/arch-tegra20/usb.h b/arch/arm/include/asm/arch-tegra20/usb.h
index 4bbd4aa..fdbd127 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)
-- 
1.7.11.4

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [U-Boot] [PATCH v4 2/2] tegra20: add USB ULPI init code
  2012-09-30 22:44 ` [U-Boot] [PATCH v4 2/2] tegra20: add USB ULPI init code Lucas Stach
@ 2012-09-30 23:22   ` Marek Vasut
  0 siblings, 0 replies; 3+ messages in thread
From: Marek Vasut @ 2012-09-30 23:22 UTC (permalink / raw)
  To: u-boot

Dear Lucas Stach,

> 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.
[...]

Applied both, waiting for build.

Best regards,
Marek Vasut

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2012-09-30 23:22 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-09-30 22:44 [U-Boot] [PATCH v4 1/2] usb: ulpi: add indicator configuration function Lucas Stach
2012-09-30 22:44 ` [U-Boot] [PATCH v4 2/2] tegra20: add USB ULPI init code Lucas Stach
2012-09-30 23:22   ` Marek Vasut

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.