Skip to contentSkip to conversation

sunxi: musb otg controller support

PATCH New Hans de Goede 5 participants 31 messages Jan 11, 2015 – Feb 10, 2015

Subsystems (5)
lore
Share & tools
lore
#0 lore raw

cover sunxi: musb otg controller support

Hi Marek, Ian, et al,

I'm very happy to present this patch series, which is the last pieze of the puzzle to make it possible for people to use u-boot on sunxi devices without needing to resort to putting a soldering iron to their tablet :)

With this series sunxi tablet owners can simply plug in a usb keyboard into the otg port of their tablet (how boring).

Interestingly enough getting the musb code to work on sunxi was quite east, most of my time went into fixing generic usb / musb issues, which should help on other boards too :)

This entire series is based on u-boot-sunxi/next and for some of the sunxi specific patches there will likely be conflicts when applied directly to master, therefor I would like to suggest the following scheme for getting this upstream:

1) Add patches 1-5 to u-boot-sunxi/next (once reviewed)
2) Add patches 6-16 to u-boot-usb/next (once reviewed)
3) Get both trees pulled by Tom
4) Add patch 17 to u-boot-sunxi

As for reviewing, Marek can you review patches 3-16 please (so all those intended for u-boot-usb/next + patch 3-5), and Ian can you review patches 1-5 and 17 please ?

Thanks & Regards,

Hans

#1 lore raw

PATCH 1/17 sunxi: axp221: Protect axp221_init against multiple calls

The voltage setting code knows it needs to call axp221_init before calling the various voltage setting functions.

But users of axp utility functions like axp221_get_sid() do not know this, so the utility functions always call axp221_init() to ensure that the p2wi / rsb setup magic has been done.

Since doing this repeatedly is quite expensive, add a check to axp221_init so that it only does the initialization once.

---
 drivers/power/axp221.c | 6 ++++++
 1 file changed, 6 insertions(+)
drivers/power/axp221.c +6 -0
index 1fda19a..728727b 100644
@@ -304,9 +304,14 @@ int axp221_set_aldo3(unsigned int mvolt)
 
 int axp221_init(void)
 {
+	/* This cannot be 0 because it is used in SPL before BSS is ready */
+	static int needs_init = 1;
 	u8 axp_chip_id;
 	int ret;
 
+	if (!needs_init)
+		return 0;
+
 	ret = pmic_bus_init();
 	if (ret)
 		return ret;
@@ -318,6 +323,7 @@ int axp221_init(void)
 	if (!(axp_chip_id == 0x6 || axp_chip_id == 0x7 || axp_chip_id == 0x17))
 		return -ENODEV;
 
+	needs_init = 0;
 	return 0;
 }
 
Signature · 1 line
2.1.0
#2 lore raw

PATCH 1/17 sunxi: axp221: Protect axp221_init against multiple calls

Quoted 11 lines · Hans de Goede

The voltage setting code knows it needs to call axp221_init before calling the various voltage setting functions.

But users of axp utility functions like axp221_get_sid() do not know this, so the utility functions always call axp221_init() to ensure that the p2wi / rsb setup magic has been done.

Since doing this repeatedly is quite expensive, add a check to axp221_init so that it only does the initialization once.

Quoted 31 lines
---
 drivers/power/axp221.c | 6 ++++++
 1 file changed, 6 insertions(+)
drivers/power/axp221.c +6 -0
index 1fda19a..728727b 100644
@@ -304,9 +304,14 @@ int axp221_set_aldo3(unsigned int mvolt)
 
 int axp221_init(void)
 {
+	/* This cannot be 0 because it is used in SPL before BSS is ready */
+	static int needs_init = 1;
 	u8 axp_chip_id;
 	int ret;
 
+	if (!needs_init)
+		return 0;
+
 	ret = pmic_bus_init();
 	if (ret)
 		return ret;
@@ -318,6 +323,7 @@ int axp221_init(void)
 	if (!(axp_chip_id == 0x6 || axp_chip_id == 0x7 || axp_chip_id == 0x17))
 		return -ENODEV;
 
+	needs_init = 0;
 	return 0;
 }
 
#3 lore raw

PATCH 1/17 sunxi: axp221: Protect axp221_init against multiple calls

Hi,

Quoted 8 lines · Ian Campbell
Quoted 7 lines · Hans de Goede

The voltage setting code knows it needs to call axp221_init before calling the various voltage setting functions.

But users of axp utility functions like axp221_get_sid() do not know this, so the utility functions always call axp221_init() to ensure that the p2wi / rsb setup magic has been done.

Quoted 5 lines
Quoted 4 lines

Since doing this repeatedly is quite expensive, add a check to axp221_init so that it only does the initialization once.

Thanks for the reviews. I've queued up the first 5 patches of this series in u-boot-sunxi/next. I'll likely send a pull-req with everything we've in next later today.

Regards,

Hans

Quoted 34 lines
Quoted 32 lines
---
  drivers/power/axp221.c | 6 ++++++
  1 file changed, 6 insertions(+)
drivers/power/axp221.c +6 -0
index 1fda19a..728727b 100644
@@ -304,9 +304,14 @@ int axp221_set_aldo3(unsigned int mvolt)
 
  int axp221_init(void)
  {
+	/* This cannot be 0 because it is used in SPL before BSS is ready */
+	static int needs_init = 1;
  	u8 axp_chip_id;
  	int ret;
 
+	if (!needs_init)
+		return 0;
+
  	ret = pmic_bus_init();
  	if (ret)
  		return ret;
@@ -318,6 +323,7 @@ int axp221_init(void)
  	if (!(axp_chip_id == 0x6 || axp_chip_id == 0x7 || axp_chip_id == 0x17))
  		return -ENODEV;
 
+	needs_init = 0;
  	return 0;
  }
 
#4 lore raw

PATCH 2/17 sunxi: axp221: Add support for controlling the drivebus pin

In reply to Hans de Goede

The axp221 / axp223's N_VBUSEN pin can be configured as an output rather then an input, add axp_drivebus_enable() and _disable() functions to set the pin in output mode and control it.

---
 drivers/power/axp221.c | 36 ++++++++++++++++++++++++++++++++++++
 include/axp221.h       |  9 +++++++++
 2 files changed, 45 insertions(+)
drivers/power/axp221.c +36 -0
index 728727b..4c86f09 100644
@@ -353,3 +353,39 @@ int axp221_get_sid(unsigned int *sid)
 
 	return 0;
 }
+
+static int axp_drivebus_setup(void)
+{
+	int ret;
+
+	ret = axp221_init();
+	if (ret)
+		return ret;
+
+	/* Set N_VBUSEN pin to output / DRIVEBUS function */
+	return axp221_clrbits(AXP221_MISC_CTRL, AXP221_MISC_CTRL_N_VBUSEN_FUNC);
+}
+
+int axp_drivebus_enable(void)
+{
+	int ret;
+
+	ret = axp_drivebus_setup();
+	if (ret)
+		return ret;
+
+	/* Set DRIVEBUS high */
+	return axp221_setbits(AXP221_VBUS_IPSOUT, AXP221_VBUS_IPSOUT_DRIVEBUS);
+}
+
+int axp_drivebus_disable(void)
+{
+	int ret;
+
+	ret = axp_drivebus_setup();
+	if (ret)
+		return ret;
+
+	/* Set DRIVEBUS low */
+	return axp221_clrbits(AXP221_VBUS_IPSOUT, AXP221_VBUS_IPSOUT_DRIVEBUS);
+}
include/axp221.h +9 -0
index e9552f6..e6639f1 100644
@@ -45,11 +45,18 @@
 #define AXP221_ALDO1_CTRL	0x28
 #define AXP221_ALDO2_CTRL	0x29
 #define AXP221_ALDO3_CTRL	0x2a
+#define AXP221_VBUS_IPSOUT	0x30
+#define AXP221_VBUS_IPSOUT_DRIVEBUS	(1 << 2)
+#define AXP221_MISC_CTRL	0x8f
+#define AXP221_MISC_CTRL_N_VBUSEN_FUNC	(1 << 4)
 #define AXP221_PAGE		0xff
 
 /* Page 1 addresses */
 #define AXP221_SID		0x20
 
+/* We support drivebus control */
+#define AXP_DRIVEBUS
+
 int axp221_set_dcdc1(unsigned int mvolt);
 int axp221_set_dcdc2(unsigned int mvolt);
 int axp221_set_dcdc3(unsigned int mvolt);
@@ -64,3 +71,5 @@ int axp221_set_aldo2(unsigned int mvolt);
 int axp221_set_aldo3(unsigned int mvolt);
 int axp221_init(void);
 int axp221_get_sid(unsigned int *sid);
+int axp_drivebus_enable(void);
+int axp_drivebus_disable(void);
Signature · 1 line
2.1.0
#6 lore raw

PATCH 3/17 sunxi: Move usb-controller init code out of ehci-sunxi.c for reuse for otg

In reply to Hans de Goede

Most of the usb-controller init code found in ehci-sunxi.c also is necessary to init the otg usb controller, so move it to a common place.

While at it also update various #ifdefs / defines for sun8i support.

---
 arch/arm/cpu/armv7/sunxi/Makefile             |   1 +
 arch/arm/cpu/armv7/sunxi/usbc.c               | 229 ++++++++++++++++++++++++++
 arch/arm/include/asm/arch-sunxi/clock_sun4i.h |   2 +-
 arch/arm/include/asm/arch-sunxi/clock_sun6i.h |   1 +
 arch/arm/include/asm/arch-sunxi/cpu.h         |   4 +-
 arch/arm/include/asm/arch-sunxi/usbc.h        |  20 +++
 drivers/usb/host/ehci-sunxi.c                 | 213 ++----------------------
 include/configs/sun8i.h                       |   5 +
 8 files changed, 269 insertions(+), 206 deletions(-)
 create mode 100644 arch/arm/cpu/armv7/sunxi/usbc.c
 create mode 100644 arch/arm/include/asm/arch-sunxi/usbc.h
arch/arm/cpu/armv7/sunxi/Makefile +1 -0
index 1e89937..1720f7d 100644
@@ -12,6 +12,7 @@ obj-y	+= board.o
 obj-y	+= clock.o
 obj-y	+= cpu_info.o
 obj-y	+= pinmux.o
+obj-y	+= usbc.o
 obj-$(CONFIG_MACH_SUN6I)	+= prcm.o
 obj-$(CONFIG_MACH_SUN8I)	+= prcm.o
 obj-$(CONFIG_MACH_SUN6I)	+= p2wi.o
arch/arm/cpu/armv7/sunxi/usbc.c new file +229 -0

229 lines not on this page · raw message

arch/arm/include/asm/arch-sunxi/clock_sun4i.h +1 -1
index 70b789e..a6d129c 100644
@@ -182,7 +182,7 @@ struct sunxi_ccm_reg {
 #define AHB_GATE_OFFSET_USB_EHCI1	3
 #define AHB_GATE_OFFSET_USB_OHCI0	2
 #define AHB_GATE_OFFSET_USB_EHCI0	1
-#define AHB_GATE_OFFSET_USB		0
+#define AHB_GATE_OFFSET_USB0		0
 
 /* ahb clock gate bit offset (second register) */
 #define AHB_GATE_OFFSET_GMAC		17
arch/arm/include/asm/arch-sunxi/clock_sun6i.h +1 -0
index 653f63c..f85f94d 100644
@@ -204,6 +204,7 @@ struct sunxi_ccm_reg {
 #define AHB_GATE_OFFSET_USB_OHCI0	29
 #define AHB_GATE_OFFSET_USB_EHCI1	27
 #define AHB_GATE_OFFSET_USB_EHCI0	26
+#define AHB_GATE_OFFSET_USB0		24
 #define AHB_GATE_OFFSET_MCTL		14
 #define AHB_GATE_OFFSET_GMAC		17
 #define AHB_GATE_OFFSET_MMC3		11
arch/arm/include/asm/arch-sunxi/cpu.h +2 -2
index bcfa00d..82b3d46 100644
@@ -37,7 +37,7 @@
 #define SUNXI_MMC1_BASE			0x01c10000
 #define SUNXI_MMC2_BASE			0x01c11000
 #define SUNXI_MMC3_BASE			0x01c12000
-#ifndef CONFIG_MACH_SUN6I
+#if !defined CONFIG_MACH_SUN6I && !defined CONFIG_MACH_SUN8I
 #define SUNXI_USB0_BASE			0x01c13000
 #define SUNXI_USB1_BASE			0x01c14000
 #endif
@@ -45,7 +45,7 @@
 #define SUNXI_HDMI_BASE			0x01c16000
 #define SUNXI_SPI2_BASE			0x01c17000
 #define SUNXI_SATA_BASE			0x01c18000
-#ifndef CONFIG_MACH_SUN6I
+#if !defined CONFIG_MACH_SUN6I && !defined CONFIG_MACH_SUN8I
 #define SUNXI_PATA_BASE			0x01c19000
 #define SUNXI_ACE_BASE			0x01c1a000
 #define SUNXI_TVE1_BASE			0x01c1b000
arch/arm/include/asm/arch-sunxi/usbc.h new file +20 -0
new file mode 100644
index 0000000..8d20973
@@ -0,0 +1,20 @@
+/*
+ * Sunxi usb-controller code shared between the ehci and musb controllers
+ *
+ * Copyright (C) 2014 Roman Byshko
+ *
+ * Roman Byshko <[email protected]>
+ *
+ * Based on code from
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+void *sunxi_usbc_get_io_base(int index);
+int sunxi_usbc_request_resources(int index);
+int sunxi_usbc_free_resources(int index);
+void sunxi_usbc_enable(int index);
+void sunxi_usbc_disable(int index);
+void sunxi_usbc_vbus_enable(int index);
+void sunxi_usbc_vbus_disable(int index);
drivers/usb/host/ehci-sunxi.c +10 -203

239 lines not on this page · raw message

include/configs/sun8i.h +5 -0
index 792422d..f16e60b 100644
@@ -16,6 +16,11 @@
 
 #define CONFIG_SYS_PROMPT	"sun8i# "
 
+#ifdef CONFIG_USB_EHCI
+#define CONFIG_USB_EHCI_SUNXI
+#define CONFIG_USB_MAX_CONTROLLER_COUNT	1
+#endif
+
 /*
  * Include common sunxi configuration where most the settings are
  */
Signature · 1 line
2.1.0
#7 lore raw

PATCH 3/17 sunxi: Move usb-controller init code out of ehci-sunxi.c for reuse for otg

Quoted 6 lines · Hans de Goede

Most of the usb-controller init code found in ehci-sunxi.c also is necessary to init the otg usb controller, so move it to a common place.

While at it also update various #ifdefs / defines for sun8i support.

On the assumption that the code motion is really just that:

(I general prefer code motion patch to be just that, with precursor refactoring patch etc, but nevermind).

#8 lore raw

PATCH 4/17 sunxi: usbc: Add support for usb0 to the common usbc code

In reply to Hans de Goede
---
 arch/arm/cpu/armv7/sunxi/usbc.c               | 33 ++++++++++++++++++++-------
 arch/arm/include/asm/arch-sunxi/clock_sun4i.h |  4 +++-
 arch/arm/include/asm/arch-sunxi/clock_sun6i.h |  2 ++
 board/sunxi/Kconfig                           |  7 ++++++
 4 files changed, 37 insertions(+), 9 deletions(-)
arch/arm/cpu/armv7/sunxi/usbc.c +25 -8
index 621992c..4f11da5 100644
@@ -36,6 +36,16 @@ static struct sunxi_usbc_hcd {
 	int id;
 } sunxi_usbc_hcd[] = {
 	{
+		.usb_rst_mask = CCM_USB_CTRL_PHY0_RST | CCM_USB_CTRL_PHY0_CLK,
+		.ahb_clk_mask = 1 << AHB_GATE_OFFSET_USB0,
+#if defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I
+		.irq = 71,
+#else
+		.irq = 38,
+#endif
+		.id = 0,
+	},
+	{
 		.usb_rst_mask = CCM_USB_CTRL_PHY1_RST | CCM_USB_CTRL_PHY1_CLK,
 		.ahb_clk_mask = 1 << AHB_GATE_OFFSET_USB_EHCI0,
 #if defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I
@@ -78,6 +88,7 @@ void *sunxi_usbc_get_io_base(int index)
 static int get_vbus_gpio(int index)
 {
 	switch (index) {
+	case 0: return sunxi_name_to_gpio(CONFIG_USB0_VBUS_PIN);
 	case 1: return sunxi_name_to_gpio(CONFIG_USB1_VBUS_PIN);
 	case 2: return sunxi_name_to_gpio(CONFIG_USB2_VBUS_PIN);
 	}
@@ -117,6 +128,10 @@ static void sunxi_usb_phy_init(struct sunxi_usbc_hcd *sunxi_usbc)
 	 * translated from Chinese, you have been warned!
 	 */
 
+	/* Regulation 45 ohms */
+	if (sunxi_usbc->id == 0)
+		usb_phy_write(sunxi_usbc, 0x0c, 0x01, 1);
+
 	/* adjust PHY's magnitude and rate */
 	usb_phy_write(sunxi_usbc, 0x20, 0x14, 5);
 
@@ -151,7 +166,7 @@ static void sunxi_usb_passby(struct sunxi_usbc_hcd *sunxi_usbc, int enable)
 
 int sunxi_usbc_request_resources(int index)
 {
-	struct sunxi_usbc_hcd *sunxi_usbc = &sunxi_usbc_hcd[index - 1];
+	struct sunxi_usbc_hcd *sunxi_usbc = &sunxi_usbc_hcd[index];
 
 	sunxi_usbc->gpio_vbus = get_vbus_gpio(index);
 	if (sunxi_usbc->gpio_vbus != -1)
@@ -162,7 +177,7 @@ int sunxi_usbc_request_resources(int index)
 
 int sunxi_usbc_free_resources(int index)
 {
-	struct sunxi_usbc_hcd *sunxi_usbc = &sunxi_usbc_hcd[index - 1];
+	struct sunxi_usbc_hcd *sunxi_usbc = &sunxi_usbc_hcd[index];
 
 	if (sunxi_usbc->gpio_vbus != -1)
 		return gpio_free(sunxi_usbc->gpio_vbus);
@@ -172,7 +187,7 @@ int sunxi_usbc_free_resources(int index)
 
 void sunxi_usbc_enable(int index)
 {
-	struct sunxi_usbc_hcd *sunxi_usbc = &sunxi_usbc_hcd[index - 1];
+	struct sunxi_usbc_hcd *sunxi_usbc = &sunxi_usbc_hcd[index];
 	struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
 
 	/* enable common PHY only once */
@@ -187,17 +202,19 @@ void sunxi_usbc_enable(int index)
 
 	sunxi_usb_phy_init(sunxi_usbc);
 
-	sunxi_usb_passby(sunxi_usbc, SUNXI_USB_PASSBY_EN);
+	if (sunxi_usbc->id != 0)
+		sunxi_usb_passby(sunxi_usbc, SUNXI_USB_PASSBY_EN);
 
 	enabled_hcd_count++;
 }
 
 void sunxi_usbc_disable(int index)
 {
-	struct sunxi_usbc_hcd *sunxi_usbc = &sunxi_usbc_hcd[index - 1];
+	struct sunxi_usbc_hcd *sunxi_usbc = &sunxi_usbc_hcd[index];
 	struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
 
-	sunxi_usb_passby(sunxi_usbc, !SUNXI_USB_PASSBY_EN);
+	if (sunxi_usbc->id != 0)
+		sunxi_usb_passby(sunxi_usbc, !SUNXI_USB_PASSBY_EN);
 
 #if defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I
 	clrbits_le32(&ccm->ahb_reset0_cfg, sunxi_usbc->ahb_clk_mask);
@@ -214,7 +231,7 @@ void sunxi_usbc_disable(int index)
 
 void sunxi_usbc_vbus_enable(int index)
 {
-	struct sunxi_usbc_hcd *sunxi_usbc = &sunxi_usbc_hcd[index - 1];
+	struct sunxi_usbc_hcd *sunxi_usbc = &sunxi_usbc_hcd[index];
 
 	if (sunxi_usbc->gpio_vbus != -1)
 		gpio_direction_output(sunxi_usbc->gpio_vbus, 1);
@@ -222,7 +239,7 @@ void sunxi_usbc_vbus_enable(int index)
 
 void sunxi_usbc_vbus_disable(int index)
 {
-	struct sunxi_usbc_hcd *sunxi_usbc = &sunxi_usbc_hcd[index - 1];
+	struct sunxi_usbc_hcd *sunxi_usbc = &sunxi_usbc_hcd[index];
 
 	if (sunxi_usbc->gpio_vbus != -1)
 		gpio_direction_output(sunxi_usbc->gpio_vbus, 0);
arch/arm/include/asm/arch-sunxi/clock_sun4i.h +3 -1
index a6d129c..84a9a2b 100644
@@ -302,10 +302,12 @@ struct sunxi_ccm_reg {
 #define CCM_GMAC_CTRL_GPIT_MII (0x0 << 2)
 #define CCM_GMAC_CTRL_GPIT_RGMII (0x1 << 2)
 
+#define CCM_USB_CTRL_PHY0_RST (0x1 << 0)
 #define CCM_USB_CTRL_PHY1_RST (0x1 << 1)
 #define CCM_USB_CTRL_PHY2_RST (0x1 << 2)
 #define CCM_USB_CTRL_PHYGATE (0x1 << 8)
-/* These 2 are sun6i only, define them as 0 on sun4i */
+/* These 3 are sun6i only, define them as 0 on sun4i */
+#define CCM_USB_CTRL_PHY0_CLK 0
 #define CCM_USB_CTRL_PHY1_CLK 0
 #define CCM_USB_CTRL_PHY2_CLK 0
 
arch/arm/include/asm/arch-sunxi/clock_sun6i.h +2 -0
index f85f94d..4711260 100644
@@ -229,10 +229,12 @@ struct sunxi_ccm_reg {
 #define CCM_MMC_CTRL_PLL6		(0x1 << 24)
 #define CCM_MMC_CTRL_ENABLE		(0x1 << 31)
 
+#define CCM_USB_CTRL_PHY0_RST (0x1 << 0)
 #define CCM_USB_CTRL_PHY1_RST (0x1 << 1)
 #define CCM_USB_CTRL_PHY2_RST (0x1 << 2)
 /* There is no global phy clk gate on sun6i, define as 0 */
 #define CCM_USB_CTRL_PHYGATE 0
+#define CCM_USB_CTRL_PHY0_CLK (0x1 << 8)
 #define CCM_USB_CTRL_PHY1_CLK (0x1 << 9)
 #define CCM_USB_CTRL_PHY2_CLK (0x1 << 10)
 
board/sunxi/Kconfig +7 -0
index ca68065..bece6b7 100644
@@ -272,6 +272,13 @@ config MMC_SUNXI_SLOT_EXTRA
 	slot or emmc on mmc1 - mmc3. Setting this to 1, 2 or 3 will enable
 	support for this.
 
+config USB0_VBUS_PIN
+	string "Vbus enable pin for usb0 (otg)"
+	default ""
+	---help---
+	Set the Vbus enable pin for usb0 (otg). This takes a string in the
+	format understood by sunxi_name_to_gpio, e.g. PH1 for pin 1 of port H.
+
 config USB1_VBUS_PIN
 	string "Vbus enable pin for usb1 (ehci0)"
 	default "PH6" if MACH_SUN4I || MACH_SUN7I
Signature · 1 line
2.1.0
#10 lore raw

PATCH 5/17 sunxi: usbc: Add support for usb-vbus0 controller by axp drivebus pin

In reply to Hans de Goede

The axp221 / axp223's N_VBUSEN pin can be configured as an output rather then an input, and this is used on some boards to control usb-vbus0, add support for this.

---
 arch/arm/cpu/armv7/sunxi/usbc.c | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)
arch/arm/cpu/armv7/sunxi/usbc.c +26 -0
index 4f11da5..14de9f9 100644
@@ -17,6 +17,15 @@
 #include <asm/gpio.h>
 #include <asm/io.h>
 #include <common.h>
+#ifdef CONFIG_AXP152_POWER
+#include <axp152.h>
+#endif
+#ifdef CONFIG_AXP209_POWER
+#include <axp209.h>
+#endif
+#ifdef CONFIG_AXP221_POWER
+#include <axp221.h>
+#endif
 
 #define SUNXI_USB_PMU_IRQ_ENABLE	0x800
 #define SUNXI_USB_CSR			0x404
@@ -71,6 +80,12 @@ static struct sunxi_usbc_hcd {
 
 static int enabled_hcd_count;
 
+static bool use_axp_drivebus(int index)
+{
+	return index == 0 &&
+	       strcmp(CONFIG_USB0_VBUS_PIN, "axp_drivebus") == 0;
+}
+
 void *sunxi_usbc_get_io_base(int index)
 {
 	switch (index) {
@@ -87,6 +102,9 @@ void *sunxi_usbc_get_io_base(int index)
 
 static int get_vbus_gpio(int index)
 {
+	if (use_axp_drivebus(index))
+		return -1;
+
 	switch (index) {
 	case 0: return sunxi_name_to_gpio(CONFIG_USB0_VBUS_PIN);
 	case 1: return sunxi_name_to_gpio(CONFIG_USB1_VBUS_PIN);
@@ -233,6 +251,10 @@ void sunxi_usbc_vbus_enable(int index)
 {
 	struct sunxi_usbc_hcd *sunxi_usbc = &sunxi_usbc_hcd[index];
 
+#ifdef AXP_DRIVEBUS
+	if (use_axp_drivebus(index))
+		axp_drivebus_enable();
+#endif
 	if (sunxi_usbc->gpio_vbus != -1)
 		gpio_direction_output(sunxi_usbc->gpio_vbus, 1);
 }
@@ -241,6 +263,10 @@ void sunxi_usbc_vbus_disable(int index)
 {
 	struct sunxi_usbc_hcd *sunxi_usbc = &sunxi_usbc_hcd[index];
 
+#ifdef AXP_DRIVEBUS
+	if (use_axp_drivebus(index))
+		axp_drivebus_disable();
+#endif
 	if (sunxi_usbc->gpio_vbus != -1)
 		gpio_direction_output(sunxi_usbc->gpio_vbus, 0);
 }
Signature · 1 line
2.1.0
#11 lore raw

PATCH 5/17 sunxi: usbc: Add support for usb-vbus0 controller by axp drivebus pin

Quoted 5 lines · Hans de Goede

The axp221 / axp223's N_VBUSEN pin can be configured as an output rather then an input, and this is used on some boards to control usb-vbus0, add support for this.

I wonder if we should expose this as a pseudo-gpio? Anyway, this'll do for starters:

#12 lore raw

PATCH 6/17 usb: Fix usb_kbd_deregister when console-muxing is used

In reply to Hans de Goede

When iomuxing is used we must not only deregister the device with stdio.c, but also remove the reference to the device in the console_devices array used by console-muxing. Add a call to iomux_doenv to usb_kbd_deregister to update console_devices, which will drop the reference.

This fixes the console filling with "Failed to enqueue URB to controller" messages after a "usb stop force", or when the USB keyboard is gone after a "usb reset".

---
 common/usb_kbd.c | 4 ++++
 1 file changed, 4 insertions(+)
common/usb_kbd.c +4 -0
index bc7145e..732136e 100644
@@ -542,6 +542,10 @@ int usb_kbd_deregister(int force)
 		data = usb_kbd_dev->privptr;
 		if (stdio_deregister_dev(dev, force) != 0)
 			return 1;
+#ifdef CONFIG_CONSOLE_MUX
+		if (iomux_doenv(stdin, getenv("stdin")) != 0)
+			return 1;
+#endif
 #ifdef CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE
 		destroy_int_queue(usb_kbd_dev, data->intq);
 #endif
Signature · 1 line
2.1.0
#13 lore raw

PATCH 7/17 usb: Add an interval parameter to create_int_queue

In reply to Hans de Goede

Currently create_int_queue is only implemented by the ehci code, and that does not honor interrupt intervals, but other drivers which might also want to implement create_int_queue may honor intervals, so add an interval param.

---
 common/usb_kbd.c            | 6 ++++--
 drivers/usb/host/ehci-hcd.c | 2 +-
 include/usb.h               | 2 +-
 3 files changed, 6 insertions(+), 4 deletions(-)
common/usb_kbd.c +4 -2
index 732136e..ecc3085 100644
@@ -332,7 +332,8 @@ static inline void usb_kbd_poll_for_event(struct usb_device *dev)
 		/* We've consumed all queued int packets, create new */
 		destroy_int_queue(dev, data->intq);
 		data->intq = create_int_queue(dev, data->intpipe, 1,
-				      USB_KBD_BOOT_REPORT_SIZE, data->new);
+				      USB_KBD_BOOT_REPORT_SIZE, data->new,
+				      data->intinterval);
 	}
 #endif
 }
@@ -453,7 +454,8 @@ static int usb_kbd_probe(struct usb_device *dev, unsigned int ifnum)
 	debug("USB KBD: enable interrupt pipe...\n");
 #ifdef CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE
 	data->intq = create_int_queue(dev, data->intpipe, 1,
-				      USB_KBD_BOOT_REPORT_SIZE, data->new);
+				      USB_KBD_BOOT_REPORT_SIZE, data->new,
+				      data->intinterval);
 	if (!data->intq) {
 #else
 	if (usb_submit_int_msg(dev, data->intpipe, data->new, data->intpktsize,
drivers/usb/host/ehci-hcd.c +1 -1
index bc76066..e7a4729 100644
@@ -1148,7 +1148,7 @@ disable_periodic(struct ehci_ctrl *ctrl)
 
 struct int_queue *
 create_int_queue(struct usb_device *dev, unsigned long pipe, int queuesize,
-		 int elementsize, void *buffer)
+		 int elementsize, void *buffer, int interval)
 {
 	struct ehci_ctrl *ctrl = dev->controller;
 	struct int_queue *result = NULL;
include/usb.h +1 -1
index d3c7415..3d33b2d 100644
@@ -169,7 +169,7 @@ int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
 
 #ifdef CONFIG_USB_EHCI /* Only the ehci code has pollable int support */
 struct int_queue *create_int_queue(struct usb_device *dev, unsigned long pipe,
-	int queuesize, int elementsize, void *buffer);
+	int queuesize, int elementsize, void *buffer, int interval);
 int destroy_int_queue(struct usb_device *dev, struct int_queue *queue);
 void *poll_int_queue(struct usb_device *dev, struct int_queue *queue);
 #endif
Signature · 1 line
2.1.0
#14 lore raw

PATCH 8/17 usb: Do not log an error when no devices is plugged into a root-hub-less hcd

In reply to Hans de Goede

Before this commit u-boot would print the following on boot with musb and no usb device plugged in:

starting USB...
USB0: Port not available.
USB error: all controllers failed lowlevel init

This commit changes this to:

starting USB...
USB0: Port not available.

Which is the correct thing to do since the low-level init went fine.

---
 common/usb.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)
common/usb.c +5 -4
index 736cd9f..1eda099 100644
@@ -59,6 +59,7 @@ int usb_init(void)
 	void *ctrl;
 	struct usb_device *dev;
 	int i, start_index = 0;
+	int controllers_initialized = 0;
 	int ret;
 
 	dev_index = 0;
@@ -78,6 +79,7 @@ int usb_init(void)
 		ret = usb_lowlevel_init(i, USB_INIT_HOST, &ctrl);
 		if (ret == -ENODEV) {	/* No such device. */
 			puts("Port not available.\n");
+			controllers_initialized++;
 			continue;
 		}
 
@@ -89,6 +91,7 @@ int usb_init(void)
 		 * lowlevel init is OK, now scan the bus for devices
 		 * i.e. search HUBs and configure them
 		 */
+		controllers_initialized++;
 		start_index = dev_index;
 		printf("scanning bus %d for devices... ", i);
 		dev = usb_alloc_new_device(ctrl);
@@ -110,12 +113,10 @@ int usb_init(void)
 
 	debug("scan end\n");
 	/* if we were not able to find at least one working bus, bail out */
-	if (!usb_started) {
+	if (controllers_initialized == 0)
 		puts("USB error: all controllers failed lowlevel init\n");
-		return -1;
-	}
 
-	return 0;
+	return usb_started ? 0 : -1;
 }
 
 /******************************************************************************
Signature · 1 line
2.1.0
#15 lore raw

PATCH 9/17 musb-new: Add register defines for different reg layout on sunxi

In reply to Hans de Goede

The sunxi SoCs also have a musb controller, but with a different register layout.

---
 drivers/usb/musb-new/musb_regs.h | 92 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 92 insertions(+)
drivers/usb/musb-new/musb_regs.h +92 -0
index 03f2655..27e4ed4 100644
@@ -216,6 +216,9 @@
 
 #ifndef CONFIG_BLACKFIN
 
+/* SUNXI has different reg addresses, but identical r/w functions */
+#ifndef CONFIG_ARCH_SUNXI 
+
 /*
  * Common USB registers
  */
@@ -318,6 +321,85 @@
 #define MUSB_BUSCTL_OFFSET(_epnum, _offset) \
 	(0x80 + (8*(_epnum)) + (_offset))
 
+#else /* CONFIG_ARCH_SUNXI */
+
+/*
+ * Common USB registers
+ */
+
+#define MUSB_FADDR		0x0098
+#define MUSB_POWER		0x0040
+
+#define MUSB_INTRTX		0x0044
+#define MUSB_INTRRX		0x0046
+#define MUSB_INTRTXE		0x0048
+#define MUSB_INTRRXE		0x004A
+#define MUSB_INTRUSB		0x004C
+#define MUSB_INTRUSBE		0x0050
+#define MUSB_FRAME		0x0054
+#define MUSB_INDEX		0x0042
+#define MUSB_TESTMODE		0x007C
+
+/* Get offset for a given FIFO from musb->mregs */
+#define MUSB_FIFO_OFFSET(epnum)	(0x00 + ((epnum) * 4))
+
+/*
+ * Additional Control Registers
+ */
+
+#define MUSB_DEVCTL		0x0041
+
+/* These are always controlled through the INDEX register */
+#define MUSB_TXFIFOSZ		0x0090
+#define MUSB_RXFIFOSZ		0x0094
+#define MUSB_TXFIFOADD		0x0092
+#define MUSB_RXFIFOADD		0x0096
+
+#define MUSB_EPINFO		0x0078
+#define MUSB_RAMINFO		0x0079
+#define MUSB_LINKINFO		0x007A
+#define MUSB_VPLEN		0x007B
+#define MUSB_HS_EOF1		0x007C
+#define MUSB_FS_EOF1		0x007D
+#define MUSB_LS_EOF1		0x007E
+
+/* Offsets to endpoint registers */
+#define MUSB_TXMAXP		0x0080
+#define MUSB_TXCSR		0x0082
+#define MUSB_CSR0		0x0082
+#define MUSB_RXMAXP		0x0084
+#define MUSB_RXCSR		0x0086
+#define MUSB_RXCOUNT		0x0088
+#define MUSB_COUNT0		0x0088
+#define MUSB_TXTYPE		0x008C
+#define MUSB_TYPE0		0x008C
+#define MUSB_TXINTERVAL		0x008D
+#define MUSB_NAKLIMIT0		0x008D
+#define MUSB_RXTYPE		0x008E
+#define MUSB_RXINTERVAL		0x008F
+
+#define MUSB_CONFIGDATA		0x00b0 /* musb_read_configdata adds 0x10 ! */
+#define MUSB_FIFOSIZE		0x0090
+
+/* Offsets to endpoint registers in indexed model (using INDEX register) */
+#define MUSB_INDEXED_OFFSET(_epnum, _offset) (_offset)
+
+#define MUSB_TXCSR_MODE		0x2000
+
+/* "bus control"/target registers, for host side multipoint (external hubs) */
+#define MUSB_TXFUNCADDR		0x0098
+#define MUSB_TXHUBADDR		0x009A
+#define MUSB_TXHUBPORT		0x009B
+
+#define MUSB_RXFUNCADDR		0x009C
+#define MUSB_RXHUBADDR		0x009E
+#define MUSB_RXHUBPORT		0x009F
+
+/* Endpoint is selected with MUSB_INDEX. */
+#define MUSB_BUSCTL_OFFSET(_epnum, _offset) (_offset)
+
+#endif /* CONFIG_ARCH_SUNXI */
+
 static inline void musb_write_txfifosz(void __iomem *mbase, u8 c_size)
 {
 	musb_writeb(mbase, MUSB_TXFIFOSZ, c_size);
@@ -340,7 +422,9 @@ static inline void  musb_write_rxfifoadd(void __iomem *mbase, u16 c_off)
 
 static inline void musb_write_ulpi_buscontrol(void __iomem *mbase, u8 val)
 {
+#ifndef CONFIG_ARCH_SUNXI /* No ulpi on sunxi */
 	musb_writeb(mbase, MUSB_ULPI_BUSCONTROL, val);
+#endif
 }
 
 static inline u8 musb_read_txfifosz(void __iomem *mbase)
@@ -365,7 +449,11 @@ static inline u16  musb_read_rxfifoadd(void __iomem *mbase)
 
 static inline u8 musb_read_ulpi_buscontrol(void __iomem *mbase)
 {
+#ifdef CONFIG_ARCH_SUNXI /* No ulpi on sunxi */
+	return 0;
+#else
 	return musb_readb(mbase, MUSB_ULPI_BUSCONTROL);
+#endif
 }
 
 static inline u8 musb_read_configdata(void __iomem *mbase)
@@ -376,7 +464,11 @@ static inline u8 musb_read_configdata(void __iomem *mbase)
 
 static inline u16 musb_read_hwvers(void __iomem *mbase)
 {
+#ifdef CONFIG_ARCH_SUNXI
+	return 0; /* Unknown version */
+#else
 	return musb_readw(mbase, MUSB_HWVERS);
+#endif
 }
 
 static inline void __iomem *musb_read_target_reg_base(u8 i, void __iomem *mbase)
Signature · 1 line
2.1.0
#16 lore raw

PATCH 10/17 musb-new: Add sunxi musb controller support

In reply to Hans de Goede

This is based on Jussi Kivilinna's work for the linux-sunxi-3.4 kernel to use the kernels musb driver instead of Allwinners own custom driver.

---
 drivers/usb/musb-new/Makefile |   1 +
 drivers/usb/musb-new/sunxi.c  | 279 ++++++++++++++++++++++++++++++++++++++++++
 include/usb.h                 |   4 +-
 3 files changed, 282 insertions(+), 2 deletions(-)
 create mode 100644 drivers/usb/musb-new/sunxi.c
drivers/usb/musb-new/Makefile +1 -0
index 3facf0f..9edeece 100644
@@ -8,6 +8,7 @@ obj-$(CONFIG_MUSB_HOST) += musb_host.o musb_core.o musb_uboot.o
 obj-$(CONFIG_USB_MUSB_DSPS) += musb_dsps.o
 obj-$(CONFIG_USB_MUSB_AM35X) += am35x.o
 obj-$(CONFIG_USB_MUSB_OMAP2PLUS) += omap2430.o
+obj-$(CONFIG_USB_MUSB_SUNXI) += sunxi.o
 
 ccflags-y := $(call cc-option,-Wno-unused-variable) \
 		$(call cc-option,-Wno-unused-but-set-variable) \
drivers/usb/musb-new/sunxi.c new file +279 -0

279 lines not on this page · raw message

include/usb.h +2 -2
index 3d33b2d..b921a7f 100644
@@ -154,8 +154,8 @@ enum usb_init_type {
 	defined(CONFIG_USB_OMAP3) || defined(CONFIG_USB_DA8XX) || \
 	defined(CONFIG_USB_BLACKFIN) || defined(CONFIG_USB_AM35X) || \
 	defined(CONFIG_USB_MUSB_DSPS) || defined(CONFIG_USB_MUSB_AM35X) || \
-	defined(CONFIG_USB_MUSB_OMAP2PLUS) || defined(CONFIG_USB_XHCI) || \
-	defined(CONFIG_USB_DWC2)
+	defined(CONFIG_USB_MUSB_OMAP2PLUS) || defined(CONFIG_USB_MUSB_SUNXI) || \
+	defined(CONFIG_USB_XHCI) || defined(CONFIG_USB_DWC2)
 
 int usb_lowlevel_init(int index, enum usb_init_type init, void **controller);
 int usb_lowlevel_stop(int index);
Signature · 1 line
2.1.0
#17 lore raw

PATCH 11/17 musb-new: Use time based timeouts rather then cpu-cycles based timeouts

In reply to Hans de Goede

CPU cycle based timeouts are no good, because how long they use depends on CPU speed. Instead use time based timeouts, and wait one second for a device connection to show up (per the USB spec), and wait USB_TIMEOUT_MS for various urbs to complete.

This fixes "usb start" taking for ever when no device is plugged into the otg port.

---
 drivers/usb/musb-new/musb_uboot.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)
drivers/usb/musb-new/musb_uboot.c +8 -8
index 2676f09..f8a0346 100644
@@ -57,13 +57,11 @@ static struct urb *construct_urb(struct usb_device *dev, int endpoint_type,
 	return &urb;
 }
 
-#define MUSB_HOST_TIMEOUT	0x3ffffff
-
 static int submit_urb(struct usb_hcd *hcd, struct urb *urb)
 {
 	struct musb *host = hcd->hcd_priv;
 	int ret;
-	int timeout;
+	unsigned long timeout;
 
 	ret = musb_urb_enqueue(hcd, urb, 0);
 	if (ret < 0) {
@@ -71,12 +69,13 @@ static int submit_urb(struct usb_hcd *hcd, struct urb *urb)
 		return ret;
 	}
 
-	timeout = MUSB_HOST_TIMEOUT;
+	timeout = get_timer(0) + USB_TIMEOUT_MS(urb->pipe);
 	do {
 		if (ctrlc())
 			return -EIO;
 		host->isr(0, host);
-	} while ((urb->dev->status & USB_ST_NOT_PROC) && --timeout);
+	} while ((urb->dev->status & USB_ST_NOT_PROC) &&
+		 get_timer(0) < timeout);
 
 	return urb->status;
 }
@@ -115,7 +114,8 @@ int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
 {
 	u8 power;
 	void *mbase;
-	int timeout = MUSB_HOST_TIMEOUT;
+	/* USB spec says it may take up to 1 second for a device to connect */
+	unsigned long timeout = get_timer(0) + 1000;
 
 	if (!host) {
 		printf("MUSB host is not registered\n");
@@ -127,8 +127,8 @@ int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
 	do {
 		if (musb_readb(mbase, MUSB_DEVCTL) & MUSB_DEVCTL_HM)
 			break;
-	} while (--timeout);
-	if (!timeout)
+	} while (get_timer(0) < timeout);
+	if (get_timer(0) >= timeout)
 		return -ENODEV;
 
 	power = musb_readb(mbase, MUSB_POWER);
Signature · 1 line
2.1.0
#18 lore raw

PATCH 12/17 musb-new: Fix interrupt transfers not working

In reply to Hans de Goede

For bulk and ctrl transfers common/usb.c sets udev->status = USB_ST_NOT_PROC, but it does not do so for interrupt transfers.

musb_uboot.c: submit_urb() however was waiting for USB_ST_NOT_PROC to become 0, and thus without anyone setting USB_ST_NOT_PROC would exit immediately for interrupt urbs, returning the urb status of EINPROGRESS as error.

This commit fixes this, thereby also making usb_kbd.c work together with musb_new and CONFIG_SYS_USB_EVENT_POLL.

---
 drivers/usb/musb-new/musb_uboot.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/usb/musb-new/musb_uboot.c +1 -1
index f8a0346..28500bf 100644
@@ -74,7 +74,7 @@ static int submit_urb(struct usb_hcd *hcd, struct urb *urb)
 		if (ctrlc())
 			return -EIO;
 		host->isr(0, host);
-	} while ((urb->dev->status & USB_ST_NOT_PROC) &&
+	} while (urb->status == -EINPROGRESS &&
 		 get_timer(0) < timeout);
 
 	return urb->status;
Signature · 1 line
2.1.0
#19 lore raw

PATCH 13/17 musb-new: Fix reset sequence when in host mode

In reply to Hans de Goede

This commit fixes a number of issues with the reset sequence of musb-new in host mode:

1) Our usb device probe relies on a second device reset being done after the first descriptors read. Factor the musb reset code into a usb_reset_root_port function (and add this as an empty define for other controllers), and call this when a device has no parent.

2) Just like with normal usb controllers there needs to be a delay after reset, for normal usb controllers, this is handled in hub_port_reset, add a delay to usb_reset_root_port.

3) Sync the musb reset sequence with the upstream kernel, clear all bits of power except bits 4-7, and increase the time reset is asserted to 50 ms.

With these fixes an usb keyboard I have now always enumerates properly, where as earlier it would only enumerare properly once every 5 tries.

---
 common/usb.c                      |  2 ++
 drivers/usb/musb-new/musb_uboot.c | 31 ++++++++++++++++++++-----------
 include/usb.h                     |  5 +++++
 3 files changed, 27 insertions(+), 11 deletions(-)
common/usb.c +2 -0
index 1eda099..32e15cd 100644
@@ -970,6 +970,8 @@ int usb_new_device(struct usb_device *dev)
 			printf("\n     Couldn't reset port %i\n", dev->portnr);
 			return 1;
 		}
+	} else {
+		usb_reset_root_port();
 	}
 #endif
 
drivers/usb/musb-new/musb_uboot.c +20 -11
index 28500bf..dab6f9b 100644
@@ -110,9 +110,27 @@ int submit_int_msg(struct usb_device *dev, unsigned long pipe,
 	return submit_urb(&hcd, urb);
 }
 
-int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
+void usb_reset_root_port(void)
 {
+	void *mbase = host->mregs;
 	u8 power;
+
+	power = musb_readb(mbase, MUSB_POWER);
+	power &= 0xf0;
+	musb_writeb(mbase, MUSB_POWER, MUSB_POWER_RESET | power);
+	mdelay(50);
+	power = musb_readb(mbase, MUSB_POWER);
+	musb_writeb(mbase, MUSB_POWER, ~MUSB_POWER_RESET & power);
+	host->isr(0, host);
+	host_speed = (musb_readb(mbase, MUSB_POWER) & MUSB_POWER_HSMODE) ?
+			USB_SPEED_HIGH :
+			(musb_readb(mbase, MUSB_DEVCTL) & MUSB_DEVCTL_FSDEV) ?
+			USB_SPEED_FULL : USB_SPEED_LOW;
+	mdelay((host_speed == USB_SPEED_LOW) ? 200 : 50);
+}
+
+int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
+{
 	void *mbase;
 	/* USB spec says it may take up to 1 second for a device to connect */
 	unsigned long timeout = get_timer(0) + 1000;
@@ -131,16 +149,7 @@ int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
 	if (get_timer(0) >= timeout)
 		return -ENODEV;
 
-	power = musb_readb(mbase, MUSB_POWER);
-	musb_writeb(mbase, MUSB_POWER, MUSB_POWER_RESET | power);
-	udelay(30000);
-	power = musb_readb(mbase, MUSB_POWER);
-	musb_writeb(mbase, MUSB_POWER, ~MUSB_POWER_RESET & power);
-	host->isr(0, host);
-	host_speed = (musb_readb(mbase, MUSB_POWER) & MUSB_POWER_HSMODE) ?
-			USB_SPEED_HIGH :
-			(musb_readb(mbase, MUSB_DEVCTL) & MUSB_DEVCTL_FSDEV) ?
-			USB_SPEED_FULL : USB_SPEED_LOW;
+	usb_reset_root_port();
 	host->is_active = 1;
 	hcd.hcd_priv = host;
 
include/usb.h +5 -0
index b921a7f..a083591 100644
@@ -159,6 +159,11 @@ enum usb_init_type {
 
 int usb_lowlevel_init(int index, enum usb_init_type init, void **controller);
 int usb_lowlevel_stop(int index);
+#ifdef CONFIG_MUSB_HOST
+void usb_reset_root_port(void);
+#else
+#define usb_reset_root_port()
+#endif
 
 int submit_bulk_msg(struct usb_device *dev, unsigned long pipe,
 			void *buffer, int transfer_len);
Signature · 1 line
2.1.0
#20 lore raw

PATCH 14/17 musb-new: Properly remove a transfer from the schedule on timeout

In reply to Hans de Goede

If a transfer / urb times-out, properly remove it from the schedule, rather then letting it sit on the ep head. This stops the musb code from getting confused and refusing to queue further transfers after a timeout.

Tested by unplugging a usb-keyboard, replugging it and doing a usb-reset, before this commit the keyboard would not work after the usb-reset.

---
 drivers/usb/musb-new/musb_host.c  | 12 +++++++++---
 drivers/usb/musb-new/musb_host.h  |  1 +
 drivers/usb/musb-new/musb_uboot.c |  3 +++
 drivers/usb/musb-new/usb-compat.h |  1 +
 4 files changed, 14 insertions(+), 3 deletions(-)
drivers/usb/musb-new/musb_host.c +9 -3
index bbcee88..437309c 100644
@@ -2130,8 +2130,6 @@ done:
 	return ret;
 }
 
-
-#ifndef __UBOOT__
 /*
  * abort a transfer that's at the head of a hardware queue.
  * called with controller locked, irqs blocked
@@ -2195,7 +2193,14 @@ static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh)
 	return status;
 }
 
-static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
+#ifndef __UBOOT__
+static int musb_urb_dequeue(
+#else
+int musb_urb_dequeue(
+#endif
+	struct usb_hcd *hcd,
+	struct urb *urb,
+	int status)
 {
 	struct musb		*musb = hcd_to_musb(hcd);
 	struct musb_qh		*qh;
@@ -2253,6 +2258,7 @@ done:
 	return ret;
 }
 
+#ifndef __UBOOT__
 /* disable an endpoint */
 static void
 musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep)
drivers/usb/musb-new/musb_host.h +1 -0
index ebebe0c..546b4a2 100644
@@ -110,5 +110,6 @@ static inline struct urb *next_urb(struct musb_qh *qh)
 
 #ifdef __UBOOT__
 int musb_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags);
+int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status);
 #endif
 #endif				/* _MUSB_HOST_H */
drivers/usb/musb-new/musb_uboot.c +3 -0
index dab6f9b..e823ad1 100644
@@ -77,6 +77,9 @@ static int submit_urb(struct usb_hcd *hcd, struct urb *urb)
 	} while (urb->status == -EINPROGRESS &&
 		 get_timer(0) < timeout);
 
+	if (urb->status == -EINPROGRESS)
+		musb_urb_dequeue(hcd, urb, -ETIME);
+
 	return urb->status;
 }
 
drivers/usb/musb-new/usb-compat.h +1 -0
index 27f656f..50bad37 100644
@@ -48,6 +48,7 @@ struct urb {
 	list_add_tail(&urb->urb_list, &urb->ep->urb_list);	\
 	ret; })
 #define usb_hcd_unlink_urb_from_ep(hcd, urb)	list_del_init(&urb->urb_list)
+#define usb_hcd_check_unlink_urb(hdc, urb, status)	0
 
 static inline void usb_hcd_giveback_urb(struct usb_hcd *hcd,
 					struct urb *urb,
Signature · 1 line
2.1.0
#21 lore raw

PATCH 15/17 musb-new: Add urb and hep parameters to construct_urb

In reply to Hans de Goede

Make construct_urb take an urb and hep parameter, rather then having it always operate on the file global urb and hep structs. This is a preperation patch for adding interrupt queue support.

---
 drivers/usb/musb-new/musb_uboot.c | 63 +++++++++++++++++++--------------------
 1 file changed, 31 insertions(+), 32 deletions(-)
drivers/usb/musb-new/musb_uboot.c +31 -32
index e823ad1..3f9a98c 100644
@@ -25,36 +25,35 @@ static void musb_host_complete_urb(struct urb *urb)
 static struct usb_host_endpoint hep;
 static struct urb urb;
 
-static struct urb *construct_urb(struct usb_device *dev, int endpoint_type,
-				unsigned long pipe, void *buffer, int len,
-				struct devrequest *setup, int interval)
+static void construct_urb(struct urb *urb, struct usb_host_endpoint *hep,
+			  struct usb_device *dev, int endpoint_type,
+			  unsigned long pipe, void *buffer, int len,
+			  struct devrequest *setup, int interval)
 {
 	int epnum = usb_pipeendpoint(pipe);
 	int is_in = usb_pipein(pipe);
 
-	memset(&urb, 0, sizeof(struct urb));
-	memset(&hep, 0, sizeof(struct usb_host_endpoint));
-	INIT_LIST_HEAD(&hep.urb_list);
-	INIT_LIST_HEAD(&urb.urb_list);
-	urb.ep = &hep;
-	urb.complete = musb_host_complete_urb;
-	urb.status = -EINPROGRESS;
-	urb.dev = dev;
-	urb.pipe = pipe;
-	urb.transfer_buffer = buffer;
-	urb.transfer_dma = (unsigned long)buffer;
-	urb.transfer_buffer_length = len;
-	urb.setup_packet = (unsigned char *)setup;
-
-	urb.ep->desc.wMaxPacketSize =
+	memset(urb, 0, sizeof(struct urb));
+	memset(hep, 0, sizeof(struct usb_host_endpoint));
+	INIT_LIST_HEAD(&hep->urb_list);
+	INIT_LIST_HEAD(&urb->urb_list);
+	urb->ep = hep;
+	urb->complete = musb_host_complete_urb;
+	urb->status = -EINPROGRESS;
+	urb->dev = dev;
+	urb->pipe = pipe;
+	urb->transfer_buffer = buffer;
+	urb->transfer_dma = (unsigned long)buffer;
+	urb->transfer_buffer_length = len;
+	urb->setup_packet = (unsigned char *)setup;
+
+	urb->ep->desc.wMaxPacketSize =
 		__cpu_to_le16(is_in ? dev->epmaxpacketin[epnum] :
 				dev->epmaxpacketout[epnum]);
-	urb.ep->desc.bmAttributes = endpoint_type;
-	urb.ep->desc.bEndpointAddress =
+	urb->ep->desc.bmAttributes = endpoint_type;
+	urb->ep->desc.bEndpointAddress =
 		(is_in ? USB_DIR_IN : USB_DIR_OUT) | epnum;
-	urb.ep->desc.bInterval = interval;
-
-	return &urb;
+	urb->ep->desc.bInterval = interval;
 }
 
 static int submit_urb(struct usb_hcd *hcd, struct urb *urb)
@@ -86,31 +85,31 @@ static int submit_urb(struct usb_hcd *hcd, struct urb *urb)
 int submit_control_msg(struct usb_device *dev, unsigned long pipe,
 			void *buffer, int len, struct devrequest *setup)
 {
-	struct urb *urb = construct_urb(dev, USB_ENDPOINT_XFER_CONTROL, pipe,
-					buffer, len, setup, 0);
+	construct_urb(&urb, &hep, dev, USB_ENDPOINT_XFER_CONTROL, pipe,
+		      buffer, len, setup, 0);
 
 	/* Fix speed for non hub-attached devices */
 	if (!dev->parent)
 		dev->speed = host_speed;
 
-	return submit_urb(&hcd, urb);
+	return submit_urb(&hcd, &urb);
 }
 
 
 int submit_bulk_msg(struct usb_device *dev, unsigned long pipe,
 					void *buffer, int len)
 {
-	struct urb *urb = construct_urb(dev, USB_ENDPOINT_XFER_BULK, pipe,
-					buffer, len, NULL, 0);
-	return submit_urb(&hcd, urb);
+	construct_urb(&urb, &hep, dev, USB_ENDPOINT_XFER_BULK, pipe,
+		      buffer, len, NULL, 0);
+	return submit_urb(&hcd, &urb);
 }
 
 int submit_int_msg(struct usb_device *dev, unsigned long pipe,
 				void *buffer, int len, int interval)
 {
-	struct urb *urb = construct_urb(dev, USB_ENDPOINT_XFER_INT, pipe,
-					buffer, len, NULL, interval);
-	return submit_urb(&hcd, urb);
+	construct_urb(&urb, &hep, dev, USB_ENDPOINT_XFER_INT, pipe,
+		      buffer, len, NULL, interval);
+	return submit_urb(&hcd, &urb);
 }
 
 void usb_reset_root_port(void)
Signature · 1 line
2.1.0
#22 lore raw

PATCH 16/17 musb-new: Add interrupt queue support

In reply to Hans de Goede

Add interrupt queue support, so that a usb keyboard can be used without causing huge latencies.

---
 drivers/usb/musb-new/musb_uboot.c | 65 +++++++++++++++++++++++++++++++++++++++
 include/usb.h                     |  3 +-
 2 files changed, 67 insertions(+), 1 deletion(-)
drivers/usb/musb-new/musb_uboot.c +65 -0
index 3f9a98c..6e58ddf 100644
@@ -12,6 +12,11 @@
 #include "musb_gadget.h"
 
 #ifdef CONFIG_MUSB_HOST
+struct int_queue {
+	struct usb_host_endpoint hep;
+	struct urb urb;
+};
+
 static struct musb *host;
 static struct usb_hcd hcd;
 static enum usb_device_speed host_speed;
@@ -112,6 +117,66 @@ int submit_int_msg(struct usb_device *dev, unsigned long pipe,
 	return submit_urb(&hcd, &urb);
 }
 
+struct int_queue *create_int_queue(struct usb_device *dev, unsigned long pipe,
+	int queuesize, int elementsize, void *buffer, int interval)
+{
+	struct int_queue *queue;
+	int ret, index = usb_pipein(pipe) * 16 + usb_pipeendpoint(pipe);
+
+	if (queuesize != 1) {
+		printf("ERROR musb int-queues only support queuesize 1\n");
+		return NULL;
+	}
+
+	if (dev->int_pending & (1 << index)) {
+		printf("ERROR int-urb is already pending on pipe %lx\n", pipe);
+		return NULL;
+	}
+
+	queue = malloc(sizeof(*queue));
+	if (!queue)
+		return NULL;
+
+	construct_urb(&queue->urb, &queue->hep, dev, USB_ENDPOINT_XFER_INT,
+		      pipe, buffer, elementsize, NULL, interval);
+
+	ret = musb_urb_enqueue(&hcd, &queue->urb, 0);
+	if (ret < 0) {
+		printf("Failed to enqueue URB to controller\n");
+		free(queue);
+		return NULL;
+	}
+
+	dev->int_pending |= 1 << index;
+	return queue;
+}
+
+int destroy_int_queue(struct usb_device *dev, struct int_queue *queue)
+{
+	int index = usb_pipein(queue->urb.pipe) * 16 + 
+		    usb_pipeendpoint(queue->urb.pipe);
+
+	if (queue->urb.status == -EINPROGRESS)
+		musb_urb_dequeue(&hcd, &queue->urb, -ETIME);
+
+	dev->int_pending &= ~(1 << index);
+	free(queue);
+	return 0;
+}
+
+void *poll_int_queue(struct usb_device *dev, struct int_queue *queue)
+{
+	if (queue->urb.status != -EINPROGRESS)
+		return NULL; /* URB has already completed in a prev. poll */
+
+	host->isr(0, host);
+
+	if (queue->urb.status != -EINPROGRESS)
+		return queue->urb.transfer_buffer; /* Done */
+
+	return NULL; /* URB still pending */
+}
+
 void usb_reset_root_port(void)
 {
 	void *mbase = host->mregs;
include/usb.h +2 -1
index a083591..a8fee0b 100644
@@ -120,6 +120,7 @@ struct usb_device {
 	 * Each instance needs its own set of data structures.
 	 */
 	unsigned long status;
+	unsigned long int_pending;	/* 1 bit per ep, used by int_queue */
 	int act_len;			/* transfered bytes */
 	int maxchild;			/* Number of ports if hub */
 	int portnr;
@@ -172,7 +173,7 @@ int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
 int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
 			int transfer_len, int interval);
 
-#ifdef CONFIG_USB_EHCI /* Only the ehci code has pollable int support */
+#if defined CONFIG_USB_EHCI || defined CONFIG_MUSB_HOST
 struct int_queue *create_int_queue(struct usb_device *dev, unsigned long pipe,
 	int queuesize, int elementsize, void *buffer, int interval);
 int destroy_int_queue(struct usb_device *dev, struct int_queue *queue);
Signature · 1 line
2.1.0
#23 lore raw

PATCH 17/17 sunxi: Hookup OTG USB controller support

In reply to Hans de Goede

Hookup OTG USB controller support and enable the otg controller + USB-keyb on various tablets.

This allows tablet owners to interact with u-boot without needing to solder a serial console onto their tablet PCB.

---
 arch/arm/include/asm/arch-sunxi/usbc.h |  2 ++
 board/sunxi/Kconfig                    |  9 +++++++++
 board/sunxi/board.c                    | 25 +++++++++++++++++++++++++
 configs/Ippo_q8h_v1_2_defconfig        |  3 ++-
 configs/Ippo_q8h_v5_defconfig          |  3 ++-
 include/configs/sunxi-common.h         | 10 +++++++++-
 6 files changed, 49 insertions(+), 3 deletions(-)
arch/arm/include/asm/arch-sunxi/usbc.h +2 -0
index 8d20973..cb538cd 100644
@@ -11,6 +11,8 @@
  * SPDX-License-Identifier:	GPL-2.0+
  */
 
+extern const struct musb_platform_ops sunxi_musb_ops;
+
 void *sunxi_usbc_get_io_base(int index);
 int sunxi_usbc_request_resources(int index);
 int sunxi_usbc_free_resources(int index);
board/sunxi/Kconfig +9 -0
index bece6b7..89c51a2 100644
@@ -391,6 +391,15 @@ config VIDEO_LCD_PANEL_HITACHI_TX18D42VM
 endchoice
 
 
+config USB_MUSB_SUNXI
+	bool "Enable sunxi OTG / DRC USB controller in host mode"
+	default n
+	---help---
+	Say y here to enable support for the sunxi OTG / DRC USB controller
+	used on almost all sunxi boards. Note currently u-boot can only have
+	one usb host controller enabled at a time, so enabling this on boards
+	which also use the ehci host controller will result in build errors.
+
 config USB_KEYBOARD
 	boolean "Enable USB keyboard support"
 	default y
board/sunxi/board.c +25 -0
index 7d6d075..569ac84 100644
@@ -28,7 +28,9 @@
 #include <asm/arch/dram.h>
 #include <asm/arch/gpio.h>
 #include <asm/arch/mmc.h>
+#include <asm/arch/usbc.h>
 #include <asm/io.h>
+#include <linux/usb/musb.h>
 #include <net.h>
 
 DECLARE_GLOBAL_DATA_PTR;
@@ -208,6 +210,26 @@ void sunxi_board_init(void)
 }
 #endif
 
+#if defined(CONFIG_MUSB_HOST) || defined(CONFIG_MUSB_GADGET)
+static struct musb_hdrc_config musb_config = {
+	.multipoint     = 1,
+	.dyn_fifo       = 1,
+	.num_eps        = 6,
+	.ram_bits       = 11,
+};
+
+static struct musb_hdrc_platform_data musb_plat = {
+#if defined(CONFIG_MUSB_HOST)
+	.mode           = MUSB_HOST,
+#else
+	.mode		= MUSB_PERIPHERAL,
+#endif
+	.config         = &musb_config,
+	.power          = 250,
+	.platform_ops	= &sunxi_musb_ops,
+};
+#endif
+
 #ifdef CONFIG_MISC_INIT_R
 int misc_init_r(void)
 {
@@ -227,6 +249,9 @@ int misc_init_r(void)
 		eth_setenv_enetaddr("ethaddr", mac_addr);
 	}
 
+#if defined(CONFIG_MUSB_HOST) || defined(CONFIG_MUSB_GADGET)
+	musb_register(&musb_plat, NULL, (void *)SUNXI_USB0_BASE);
+#endif
 	return 0;
 }
 #endif
configs/Ippo_q8h_v1_2_defconfig +2 -1
index 0447b06..3e6d3cc 100644
@@ -1,11 +1,12 @@
 CONFIG_SPL=y
 CONFIG_SYS_EXTRA_OPTIONS="CONS_INDEX=5"
 CONFIG_FDTFILE="sun8i-a23-ippo-q8h-v1.2.dtb"
+CONFIG_USB_MUSB_SUNXI=y
+CONFIG_USB0_VBUS_PIN="axp_drivebus"
 CONFIG_VIDEO_LCD_MODE="x:800,y:480,depth:18,pclk_khz:33000,le:87,ri:167,up:31,lo:13,hs:1,vs:1,sync:3,vmode:0"
 CONFIG_VIDEO_LCD_POWER="PH7"
 CONFIG_VIDEO_LCD_BL_EN="PH6"
 CONFIG_VIDEO_LCD_BL_PWM="PH0"
-CONFIG_USB_KEYBOARD=n
 +S:CONFIG_ARM=y
 +S:CONFIG_ARCH_SUNXI=y
 +S:CONFIG_MACH_SUN8I=y
configs/Ippo_q8h_v5_defconfig +2 -1
index 4e82bf9..b96985e 100644
@@ -1,11 +1,12 @@
 CONFIG_SPL=y
 CONFIG_SYS_EXTRA_OPTIONS="CONS_INDEX=5"
 CONFIG_FDTFILE="sun8i-a23-ippo-q8h-v5.dtb"
+CONFIG_USB_MUSB_SUNXI=y
+CONFIG_USB0_VBUS_PIN="axp_drivebus"
 CONFIG_VIDEO_LCD_MODE="x:800,y:480,depth:18,pclk_khz:33000,le:87,ri:168,up:31,lo:13,hs:1,vs:1,sync:3,vmode:0"
 CONFIG_VIDEO_LCD_POWER="PH7"
 CONFIG_VIDEO_LCD_BL_EN="PH6"
 CONFIG_VIDEO_LCD_BL_PWM="PH0"
-CONFIG_USB_KEYBOARD=n
 +S:CONFIG_ARM=y
 +S:CONFIG_ARCH_SUNXI=y
 +S:CONFIG_MACH_SUN8I=y
include/configs/sunxi-common.h +9 -1
index 64d379a..121bcf4 100644
@@ -247,8 +247,16 @@
 #endif
 
 #ifdef CONFIG_USB_EHCI
-#define CONFIG_CMD_USB
 #define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 1
+#endif
+
+#ifdef CONFIG_USB_MUSB_SUNXI
+#define CONFIG_MUSB_HOST
+#define CONFIG_MUSB_PIO_ONLY
+#endif
+
+#if defined CONFIG_USB_EHCI || defined CONFIG_USB_MUSB_SUNXI
+#define CONFIG_CMD_USB
 #define CONFIG_USB_STORAGE
 #endif
 
Signature · 1 line
2.1.0
#24 lore raw

PATCH 17/17 sunxi: Hookup OTG USB controller support

Quoted 5 lines · Hans de Goede

Hookup OTG USB controller support and enable the otg controller + USB-keyb on various tablets.

This allows tablet owners to interact with u-boot without needing to solder a serial console onto their tablet PCB.

Looks good, except I can't for the life of me find where CONFIG_MUSB_GADGET is ever set for a sunxi platform.

I suspect it's just there in preparation for some future gadget mode work (what we care about here is host mode), is that right?

If so: Acked-by: Ian Campbell <[email protected]>

Quoted 1 line

+#if defined(CONFIG_MUSB_HOST) || defined(CONFIG_MUSB_GADGET)

Not just #ifdef CONFIG_USB_MUSB_SUNXI? (Ack either way)

Ian.

#25 lore raw

PATCH 17/17 sunxi: Hookup OTG USB controller support

Hi,

Quoted 4 lines · Ian Campbell
Quoted 3 lines · Hans de Goede

Hookup OTG USB controller support and enable the otg controller + USB-keyb on various tablets.

Quoted 8 lines
Quoted 2 lines

This allows tablet owners to interact with u-boot without needing to solder a serial console onto their tablet PCB.

Looks good, except I can't for the life of me find where CONFIG_MUSB_GADGET is ever set for a sunxi platform.

I suspect it's just there in preparation for some future gadget mode work (what we care about here is host mode), is that right?

Right, in theory we have everything in place for gadget mode when this patch-set lands and all someone needs to do is add a Kconfig option for it. Note I do not plan to work on that ATM, only so much hours in a day, etc. but I do invite others who are interested in this to take a look at the gadget stuff and patches are welcome :)

Quoted 6 lines

If so: Acked-by: Ian Campbell <[email protected]>

Quoted 1 line

+#if defined(CONFIG_MUSB_HOST) || defined(CONFIG_MUSB_GADGET)

Not just #ifdef CONFIG_USB_MUSB_SUNXI? (Ack either way)

This is the construct the other MUSB users use in their board code, but yes either would work.

Regards,

Hans

#26 lore raw

PATCH 17/17 sunxi: Hookup OTG USB controller support

In reply to Hans de Goede
Quoted 5 lines · On Sun, 11 Jan 2015 20:34:55 +0100 Hans de Goede <[email protected]> wrote:

Hookup OTG USB controller support and enable the otg controller + USB-keyb on various tablets.

This allows tablet owners to interact with u-boot without needing to solder a serial console onto their tablet PCB.

Thanks. Works great on my Primo73 and Primo81 tablets. However I have just one naive question before happily taking it into use by default.

Is the hardcoded otg host mode (without checking the id pin) always safe? For example, what happens if somebody connects a charger instead of a usb keyboard to the tablet?

Signature · 2 lines
Best regards,
Siarhei Siamashka
#27 lore raw

PATCH 17/17 sunxi: Hookup OTG USB controller support

Quoted 9 lines · On Sat, 31 Jan 2015 04:54:47 +0200 Siarhei Siamashka…
Quoted 5 lines · On Sun, 11 Jan 2015 20:34:55 +0100 Hans de Goede <[email protected]> wrote:

Hookup OTG USB controller support and enable the otg controller + USB-keyb on various tablets.

This allows tablet owners to interact with u-boot without needing to solder a serial console onto their tablet PCB.

Quoted 6 lines

Thanks. Works great on my Primo73 and Primo81 tablets. However I have just one naive question before happily taking it into use by default.

Is the hardcoded otg host mode (without checking the id pin) always safe? For example, what happens if somebody connects a charger instead of a usb keyboard to the tablet?

So, does anyone have any idea if it is theoretically safe to have two USB hosts connected to each other and both driving VBUS at +5V?

A somewhat realistic scenario is booting an Allwinner tablet over USB using the FEL mode. Is it a good idea for such tablet to have CONFIG_USB_MUSB_SUNXI=y and CONFIG_USB0_VBUS_PIN="axp_drivebus" in defconfig?

Signature · 2 lines
Best regards,
Siarhei Siamashka
#28 lore raw

PATCH 17/17 sunxi: Hookup OTG USB controller support

Quoted 19 lines · Siarhei Siamashka
Quoted 9 lines · On Sat, 31 Jan 2015 04:54:47 +0200 Siarhei Siamashka…
Quoted 5 lines · On Sun, 11 Jan 2015 20:34:55 +0100 Hans de Goede <[email protected]> wrote:

Hookup OTG USB controller support and enable the otg controller + USB-keyb on various tablets.

This allows tablet owners to interact with u-boot without needing to solder a serial console onto their tablet PCB.

Quoted 6 lines

Thanks. Works great on my Primo73 and Primo81 tablets. However I have just one naive question before happily taking it into use by default.

Is the hardcoded otg host mode (without checking the id pin) always safe? For example, what happens if somebody connects a charger instead of a usb keyboard to the tablet?

Quoted 8 lines

So, does anyone have any idea if it is theoretically safe to have two USB hosts connected to each other and both driving VBUS at +5V?

A somewhat realistic scenario is booting an Allwinner tablet over USB using the FEL mode. Is it a good idea for such tablet to have CONFIG_USB_MUSB_SUNXI=y and CONFIG_USB0_VBUS_PIN="axp_drivebus" in defconfig?

From my past experiments with some non-standard-compliant cables which allow connecting a tablet with a PC without telling the tablet to go OTG mode it seems the tablet battery is drained really quick in this case.

There is a protocol for telling the tablet not to power the bus (or telling the PC not to power it for that matter) but both sides have to support matching part of the protocol. Either way, ideal case is that tablet gets power form PC or powered hub even in host mode which is not standards-compliant and obviously does not work with stuff like keyboards.

However, it should be possible to detect that there is bus power at the moment a device is connected and not power the device in that case regardless of usb mode negotiated after the connection.

Thanks

Michal

#29 lore raw

PATCH 17/17 sunxi: Hookup OTG USB controller support

Hi,

Quoted 42 lines · Michal Suchanek
Quoted 19 lines · Siarhei Siamashka
Quoted 9 lines · On Sat, 31 Jan 2015 04:54:47 +0200 Siarhei Siamashka…
Quoted 5 lines · On Sun, 11 Jan 2015 20:34:55 +0100 Hans de Goede <[email protected]> wrote:

Hookup OTG USB controller support and enable the otg controller + USB-keyb on various tablets.

This allows tablet owners to interact with u-boot without needing to solder a serial console onto their tablet PCB.

Quoted 6 lines

Thanks. Works great on my Primo73 and Primo81 tablets. However I have just one naive question before happily taking it into use by default.

Is the hardcoded otg host mode (without checking the id pin) always safe? For example, what happens if somebody connects a charger instead of a usb keyboard to the tablet?

Quoted 8 lines

So, does anyone have any idea if it is theoretically safe to have two USB hosts connected to each other and both driving VBUS at +5V?

A somewhat realistic scenario is booting an Allwinner tablet over USB using the FEL mode. Is it a good idea for such tablet to have CONFIG_USB_MUSB_SUNXI=y and CONFIG_USB0_VBUS_PIN="axp_drivebus" in defconfig?

From my past experiments with some non-standard-compliant cables which
allow connecting a tablet with a PC without telling the tablet to go OTG mode it seems the tablet battery is drained really quick in this case.

There is a protocol for telling the tablet not to power the bus (or telling the PC not to power it for that matter) but both sides have to support matching part of the protocol. Either way, ideal case is that tablet gets power form PC or powered hub even in host mode which is not standards-compliant and obviously does not work with stuff like keyboards.

Quoted 3 lines

However, it should be possible to detect that there is bus power at the moment a device is connected and not power the device in that case regardless of usb mode negotiated after the connection.

Right, I've fixing this on my todo list, the plan is to add vbus_det support, and first check if there is an external vbus before enabling vbus.

Regards,

Hans

#30 lore raw

cover sunxi: musb otg controller support

In reply to Hans de Goede
Quoted 13 lines · Hans de Goede

Hi Marek, Ian, et al,

I'm very happy to present this patch series, which is the last pieze of the puzzle to make it possible for people to use u-boot on sunxi devices without needing to resort to putting a soldering iron to their tablet :)

With this series sunxi tablet owners can simply plug in a usb keyboard into the otg port of their tablet (how boring).

Interestingly enough getting the musb code to work on sunxi was quite east, most of my time went into fixing generic usb / musb issues, which should help on other boards too :)

Quoted 7 lines

This entire series is based on u-boot-sunxi/next and for some of the sunxi specific patches there will likely be conflicts when applied directly to master, therefor I would like to suggest the following scheme for getting this upstream:

1) Add patches 1-5 to u-boot-sunxi/next (once reviewed)
2) Add patches 6-16 to u-boot-usb/next (once reviewed)

Applied 6-16 to u-boot-usb/next (V2 of 07 is applied instead).

Thanks!

Best regards,
Marek Vasut