sunxi: musb otg controller support
Subsystems (5)
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
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
@@ -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
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_initbefore 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 callaxp221_init()to ensure that the p2wi / rsb setup magic has been done.Since doing this repeatedly is quite expensive, add a check to
axp221_initso that it only does the initialization once.Signed-off-by Hans de Goede <[email protected]>
Quoted 31 lines
--- drivers/power/axp221.c | 6 ++++++ 1 file changed, 6 insertions(+)drivers/power/axp221.c +6
-0@@ -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 ; }
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_initbefore 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 callaxp221_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_initso that it only does the initialization once.Signed-off-by Hans de Goede <[email protected]>Acked-by Ian Campbell <[email protected]>
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@@ -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 ; }
PATCH 2/17 sunxi: axp221: Add support for controlling the drivebus pin
In reply to Hans de GoedeThe 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
@@ -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
@@ -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
PATCH 2/17 sunxi: axp221: Add support for controlling the drivebus pin
On Sun, 2015-01-11 at 20:34 +0100, Hans de Goede wrote:
PATCH 3/17 sunxi: Move usb-controller init code out of ehci-sunxi.c for reuse for otg
In reply to Hans de GoedeMost 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
@@ -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
@@ -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
@@ -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
@@ -37,7 +37,7 @@#define SUNXI_MMC1_BASE 0x01c10000#define SUNXI_MMC2_BASE 0x01c11000#define SUNXI_MMC3_BASE 0x01c12000 -#ifndef CONFIG_MACH_SUN6I +#if !definedCONFIG_MACH_SUN6I && !definedCONFIG_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 !definedCONFIG_MACH_SUN6I && !definedCONFIG_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
@@ -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
@@ -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
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.calso 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.
Signed-off-by Hans de Goede <[email protected]>
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).
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
@@ -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 definedCONFIG_MACH_SUN6I || definedCONFIG_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 definedCONFIG_MACH_SUN6I || definedCONFIG_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 definedCONFIG_MACH_SUN6I || definedCONFIG_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
@@ -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
@@ -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
@@ -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
PATCH 4/17 sunxi: usbc: Add support for usb0 to the common usbc code
Quoted 1 line · Hans de Goede
Signed-off-by Hans de Goede <[email protected]>
PATCH 5/17 sunxi: usbc: Add support for usb-vbus0 controller by axp drivebus pin
In reply to Hans de GoedeThe 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
@@ -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
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_VBUSENpin 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.Signed-off-by Hans de Goede <[email protected]>
I wonder if we should expose this as a pseudo-gpio? Anyway, this'll do for starters:
PATCH 6/17 usb: Fix usb_kbd_deregister when console-muxing is used
In reply to Hans de GoedeWhen 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
@@ -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
PATCH 7/17 usb: Add an interval parameter to create_int_queue
In reply to Hans de GoedeCurrently 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
@@ -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
@@ -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
@@ -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
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 GoedeBefore 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
@@ -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
PATCH 9/17 musb-new: Add register defines for different reg layout on sunxi
In reply to Hans de GoedeThe 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
@@ -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
PATCH 10/17 musb-new: Add sunxi musb controller support
In reply to Hans de GoedeThis 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
@@ -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
@@ -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
PATCH 11/17 musb-new: Use time based timeouts rather then cpu-cycles based timeouts
In reply to Hans de GoedeCPU 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
@@ -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
PATCH 12/17 musb-new: Fix interrupt transfers not working
In reply to Hans de GoedeFor 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
@@ -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
PATCH 13/17 musb-new: Fix reset sequence when in host mode
In reply to Hans de GoedeThis 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
@@ -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
@@ -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
@@ -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
PATCH 14/17 musb-new: Properly remove a transfer from the schedule on timeout
In reply to Hans de GoedeIf 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
@@ -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
@@ -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
@@ -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
@@ -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
PATCH 15/17 musb-new: Add urb and hep parameters to construct_urb
In reply to Hans de GoedeMake 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
@@ -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
PATCH 16/17 musb-new: Add interrupt queue support
In reply to Hans de GoedeAdd 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
@@ -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
@@ -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 definedCONFIG_USB_EHCI || definedCONFIG_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
PATCH 17/17 sunxi: Hookup OTG USB controller support
In reply to Hans de GoedeHookup 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 definedCONFIG_USB_EHCI || definedCONFIG_USB_MUSB_SUNXI +#define CONFIG_CMD_USB #define CONFIG_USB_STORAGE #endif
Signature · 1 line
2.1.0
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.
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_GADGETis 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
PATCH 17/17 sunxi: Hookup OTG USB controller support
In reply to Hans de GoedeQuoted 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
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
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=yandCONFIG_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
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=yandCONFIG_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
cover sunxi: musb otg controller support
In reply to Hans de GoedeQuoted 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