This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

AM3352: USB hotplug not working

Part Number: AM3352

Dear E2E community,

I'm working on a custom board (BBB based) that is equipped with an USB OTG connected to USB0. We have a multi gadget configured on that port. The kernel comes from TI, version 4.14.79.  The USB works only if plugged before Linux starts, otherwise it's not seen by the OS. The module (g_multi) is probed correctly on boot, no matter if USB is plugged or not.

Once the USB is working we can unplug and plug without any problem.

udevadm does not show any event (even if the USB is working).

Any suggestion?

Best regards,

Gabriele

  • Hi Gabriele,

    What is the OS on the host?

    Please post the USB portion of your board schematics.

  • Hi,

    the OS on the host side is ubuntu 16.04.

    Garbiele

  • Please run the following sequence and post the log.

    - Boot your AM3352 board without connecting its USB0 to the USB host;

    - Run the script attached below on your board and capture its output log;

    - Connect AM3352 USB0 to the USB host, and run the same script and capture its output again.

    #!/bin/bash
    #
    # Util to check USB subsystem for Linux kernel 3.12+ on TI Sitara devices
    #
    # Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
    #
    #
    #  Redistribution and use in source and binary forms, with or without
    #  modification, are permitted provided that the following conditions
    #  are met:
    #
    #    Redistributions of source code must retain the above copyright
    #    notice, this list of conditions and the following disclaimer.
    #
    #    Redistributions in binary form must reproduce the above copyright
    #    notice, this list of conditions and the following disclaimer in the
    #    documentation and/or other materials provided with the
    #    distribution.
    #
    #    Neither the name of Texas Instruments Incorporated nor the names of
    #    its contributors may be used to endorse or promote products derived
    #    from this software without specific prior written permission.
    #
    #  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    #  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    #  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    #  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    #  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    #  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    #  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    #  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    #  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    #  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    #  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    
    VERSION=0.2.10
    DTPATH=/sys/firmware/devicetree/base
    DEVPATH=/sys/devices/platform
    
    ### functions ###
    
    # $1 command to be checked
    check_command() {
        local _cmd=$1
    
        which $_cmd > /dev/null || {
            echo "Error: $_cmd command not found"
            exit 1
        }
    }
    
    # check if the kernel is supported
    # this tool only runs on v3.12+ kernel
    # return 0 - if kernel version >= 3.12
    #        1 - if kernel version < 3.12
    has_supported_kernel() {
    	local _ver
    	local _t
    
        check_command uname
        uname -a
    	_ver=`uname -r`
        _t=${_ver%%.*}
        # 2.x.x, unsupported
        [ $_t -ge 3 ] || return 1
        # 4.x.x, supported
        [ $_t -lt 4 ] || return 0
    
        _ver=${_ver#*.}
        _t=${_ver%%.*}
        # < 3.12.x, unsupported
        [ $_t -ge 12 ] || return 1
        return 0
    }
    
    # check if the platform is supported
    #    $PLATFORM - global variable
    # return 0 - if platform is supported
    #        1 - if platform is not supported
    check_platform () {
    	local _hw
    
        check_command grep
        [ "$PLATFORM" != "" ] || {
    	    _hw=`cat ${DTPATH}/compatible | tr '\0' ' '`
    	    DBG_PRINT $_hw
    
            if [[ "$_hw" == *"ti,am33xx"* ]]; then
                PLATFORM="am335x"
            elif [[ "$_hw" == *"ti,am43"* ]]; then
                PLATFORM="am437x"
            elif [[ "$_hw" == *"ti,dra7"* ]]; then
                PLATFORM="am57x"
            elif [[ "$_hw" == *"ti,k2g"* ]]; then
                PLATFORM="keystone"
            elif [[ "$_hw" == *"ti,am654"* ]]; then
                PLATFORM="am65x"
            else
                PLATFORM=$_hw
            fi
        }
    
        DBG_PRINT $PLATFORM
        case $PLATFORM in
            "am335x")
                USB0DT="$(find $DTPATH -name 'usb@47401000')"
                USB1DT="$(find $DTPATH -name 'usb@47401800')"
                USB0DEV="$(find $DEVPATH -name '47401400.usb')/musb-hdrc.*"
                USB1DEV="$(find $DEVPATH -name '47401c00.usb')/musb-hdrc.*"
                return 0;;
            "am437x")
                USB0DT="$(find $DTPATH -name 'usb@48390000')"
                USB1DT="$(find $DTPATH -name 'usb@483d0000')"
                return 0;;
            "am57x" | "keystone")
                USB0DT="$(find $DTPATH -name 'usb@48890000')"
                USB1DT="$(find $DTPATH -name 'usb@488d0000')"
                return 0;;
            "am65x")
                USB0DT="$(find $DTPATH -name 'dwc3@4000000')/usb@10000"
                USB1DT="$(find $DTPATH -name 'dwc3@4020000')/usb@10000"
                return 0;;
            *)
                echo "Unsupported \"$PLATFORM\""
                return 1;;
        esac
    }
    
    # check a kernel CONFIG option
    # params $1 - the config option
    #        $2 = '-q', quiet output
    # return 0 - undefined
    #        1 - defined as 'm', kernel module
    #        2 - defined as 'y', kernel builtin
    check_kernel_config() {
        local _cfg
    
        [ -n "$1" ] || return 0
        check_command zcat
        _cfg=`zcat /proc/config.gz | grep "^$1\>"`
    
        case ${_cfg#*=} in
            "y") return 2;;
            "m") return 1;;
              *) [ "$2" = "-q" ] ||
                  echo "Error: $1 is undefined in kernel config"
              return 0;;
        esac
    }
    
    # check a kernel module
    # $1 - module name, relative path from drivers/, without .ko surfix
    # return 0 - found
    #        1 - error
    check_module() {
        local _modname
        local _moddep
    
        [ -n "$1" ] || return 1
    
        _modname="/lib/modules/`uname -r`/kernel/drivers/${1}.ko"
        _moddep="/lib/modules/`uname -r`/modules.dep"
    
        DBG_PRINT 1
        [ -f $_modname ] || {
            echo "Error: $_modname not found."
            echo "       Please ensure 'make module_install' is done properly."
            return 1
        }
    
        DBG_PRINT 2
        [ -f $_moddep ] || $moddep_checked || {
            echo "Error: $_moddep not found."
            echo "       Please ensure 'make module_install' is done properly."
            moddep_checked=true
        }
    
        DBG_PRINT 3
        check_command lsmod
        check_command basename
        check_command tr
    
        lsmod | grep `basename $1 | tr '-' '_'` > /dev/null || {
            DBG_PRINT ">>>> ${1}.ko:"
            if grep "${1}.ko:" $_moddep > /dev/null; then
                DBG_PRINT 5
                echo "Error: $_moddep seems to be valid,"
                echo "       but `basename $1`.ko is not loaded."
                echo "       Please provide /proc/config.gz and /lib/module/`uname -r`/*"
                echo "       for further investigation."
            else
                DBG_PRINT 6
                echo "Error: `basename $1`: $_moddep is invalid."
                echo "       Please run command 'depmod' on the target to re-generate it,"
                echo "       then reboot the target. If the issue still exists, please"
                echo "       ensure 'make module_install' is done properly."
            fi
    
            DBG_PRINT 7
            return 1
        }
        DBG_PRINT 8
        return 0
    }
    
    # check kernel config, and modules (if CONFIG_*=M) for musb
    check_musb_drivers() {
        check_kernel_config CONFIG_USB_MUSB_HDRC
        [ $? != 1 ] || check_module 'usb/musb/musb_hdrc'
    
        check_kernel_config CONFIG_USB_MUSB_DUAL_ROLE -q
        [ $? != 0 ] || echo "Warning: CONFIG_USB_MUSB_DUAL_ROLE undefined."
    
        check_kernel_config CONFIG_USB_OTG -q
        [ $? == 0 ] || echo "Warning: CONFIG_USB_OTG defined."
    
        check_kernel_config CONFIG_USB_MUSB_DSPS
        [ $? != 1 ] || {
            check_module 'usb/musb/musb_dsps'
            check_module 'usb/musb/musb_am335x'
        }
    
        check_kernel_config CONFIG_AM335X_PHY_USB
        [ $? != 1 ] || {
            check_module 'usb/phy/phy-am335x'
            check_module 'usb/phy/phy-am335x-control'
        }
    
        check_kernel_config CONFIG_MUSB_PIO_ONLY -q
        [ $? != 0 ] || {
           if check_kernel_config CONFIG_TI_CPPI41 -q; then
               echo "Error: MUSB CPPI DMA mode is enabled, but CPPI moudle is not enabled in DMA Engine."
               echo "       Please enable CONFIG_TI_CPPI41 under DMA Engine Support in kernel config."
           fi
        }
    }
    
    # check kernel config, and modules (if CONFIG_*=M) for dwc3
    check_dwc3_drivers() {
        check_kernel_config CONFIG_USB_DWC3
        [ $? != 1 ] || check_module 'usb/dwc3/dwc3'
    
        check_kernel_config CONFIG_USB_DWC3_DUAL_ROLE -q
        [ $? != 0 ] || echo "Warning: CONFIG_USB_DWC3_DUAL_ROLE undefined."
    
        check_kernel_config CONFIG_USB_OTG -q
        [ $? == 0 ] || echo "Warning: CONFIG_USB_OTG defined."
    
        check_kernel_config CONFIG_USB_DWC3_OMAP
        [ $? != 1 ] || check_module 'usb/dwc3/dwc3-omap'
    
        check_kernel_config CONFIG_USB_XHCI_HCD
        [ $? != 1 ] || {
            check_module 'usb/host/xhci-plat-hcd'
            check_module 'usb/host/xhci-hcd'
        }
    
        check_kernel_config CONFIG_OMAP_CONTROL_PHY
        [ $? != 1 ] || check_module 'phy/phy-omap-control'
    
        if [ $PLATFORM = am437x ]; then
            check_kernel_config CONFIG_OMAP_USB2
            [ $? != 1 ] || check_module 'phy/phy-omap-usb2'
        else
            check_kernel_config CONFIG_TI_PIPE3
            [ $? != 1 ] || check_module 'phy/phy-ti-pipe3'
        fi
    }
    
    check_musb_dt() {
        local _dt_dir
        local _ent
        local _sts
    
        _dt_dir='/proc/device-tree/ocp/usb@47400000'
        _ent='. control@44e10620 usb-phy@47401300 usb-phy@47401b00 dma-controller@47402000'
    
        for _t in $_ent; do
            _sts=$(tr -d '\0' <${_dt_dir}/${_t}/status)
            [ "$_sts" != "disabled" ] || echo $_t: disabled in devicetree
        done
    }
    
    ### debug ###
    
    g_log_file=/tmp/chkusb.log
    
    DBG_ENABLE() { g_dbg_enabled=true; }
    DBG_DISABLE() { g_dbg_enabled=false; }
    DBG_LOG_RESET() { ! $g_dbg_enabled || echo > $g_log_file; }
    DBG_PRINT() { ! $g_dbg_enabled || echo "$(date +%H:%M:%S) [$(basename $0)]: $*"; }
    DBG_LOG() { DBG_PRINT $* >> $g_log_file; }
    DBG_LOG_MARK() { DBG_PRINT "----------------" >> $g_log_file; }
    
    
    ### main ####
    
    moddep_checked=false
    
    echo "chkusb.sh Version $VERSION"
    
    [ "$V" = "1" ] && DBG_ENABLE && DBG_LOG_RESET || DBG_DISABLE
    
    has_supported_kernel ||
        { echo "Unsupported kernel version: `uname -r`"; exit 1; }
    check_platform || exit 2
    DBG_PRINT device: $PLATFORM
    
    check_command lsusb
    if lsusb > /dev/null 2>&1; then
        echo "USB is initialized"
    else
        echo "USB initialization failed"
    fi
    
    # check kernel configs
    
    if [ -f /proc/config.gz ]; then
        case $PLATFORM in
            am335x) check_musb_drivers;;
            am437x | am57x | keystone | am65x) check_dwc3_drivers;;
            *)
                echo "Error: unsupported platform $PLATFORM"
                exit 5;;
        esac
    else
        echo "Error: /proc/config.gz not found"
    fi
    
    case $PLATFORM in
        am335x)
            for _f in $USB0DEV $USB1DEV; do
                echo "$(basename $_f): mode $(cat ${_f}/mode), $(cat ${_f}/vbus)"
            done
    
            _debugfs=`sed -ne 's/^debugfs \(.*\) debugfs.*/\1/p' /proc/mounts`
            [ -z "$_debugfs" ] ||
                grep -i 'power\|devctl\|testmode' ${_debugfs}/musb-hdrc.?/regdump
            ;;
    esac
    
    # check dr_mode & gadget drivers
    
    [ -d ${DTPATH} ] || {
        echo "Warning: ${DTPATH} not found"
        if [ -d "/lib/modules/`uname -r`/" ]; then
            echo "The list of USB gadget drivers installed:"
            ls -1Rp "/lib/modules/`uname -r`/kernel/drivers/usb/gadget/"
        fi
        exit 0
    }
    
    check_command basename
    for _usb_dir in "${USB0DT}" "${USB1DT}"; do
        [ -n "$_usb_dir" ] || continue
    
        [ ! -d "$_usb_dir/status" ] &&
            _status='(null)' || _status=`tr -d '\0' <$_usb_dir/status`
        _dr_mode=`tr -d '\0'  <$_usb_dir/dr_mode`
        echo `basename $_usb_dir`: $_dr_mode, $_status
    
        [ "$_status" = "disabled" -o "$_dr_mode" = "host" ] || gadget_mode=true
    done
    
    case $PLATFORM in
        am335x) check_musb_dt;;
        *) ;;
    esac
    
    DBG_PRINT $gadget_mode
    $gadget_mode || exit 0
    
    echo
    
    check_kernel_config CONFIG_USB_LIBCOMPOSITE
    case $? in
        0) echo "Error: no any gadget driver enabled"
           exit 6;;
        1) is_gadget_builtin=false;;
        2) echo "The gadget driver is built-in"
           is_gadget_builtin=true;;
    esac
    
    check_kernel_config CONFIG_USB_ZERO -q ||
        echo "Gadget Kernel Config: g_zero is enabled"
    check_kernel_config CONFIG_USB_AUDIO -q ||
        echo "Gadget Kernel Config: g_audio is enabled"
    check_kernel_config CONFIG_USB_ETH -q ||
        echo "Gadget Kernel Config: g_ether is enabled"
    check_kernel_config CONFIG_USB_G_NCM -q ||
        echo "Gadget Kernel Config: g_ncm is enabled"
    check_kernel_config CONFIG_USB_MASS_STORAGE -q ||
        echo "Gadget Kernel Config: g_mass_storage is enabled"
    check_kernel_config CONFIG_USB_G_SERIAL -q ||
        echo "Gadget Kernel Config: g_serial is enabled"
    check_kernel_config CONFIG_USB_G_PRINTER -q ||
        echo "Gadget Kernel Config: g_printer is enabled"
    
    g_driver=`grep '^DRIVER=' /sys/class/udc/*/uevent 2>/dev/null`
    echo "gadget driver loaded: ${g_driver:-(none)}"
    
    echo
    
    if ! $is_gadget_builtin; then
        if [ -d "/lib/modules/`uname -r`/" ]; then
            echo "The list of USB gadget drivers installed:"
            ls -1Rp "/lib/modules/`uname -r`/kernel/drivers/usb/gadget/"
        else
            echo "Error: /lib/modules/`uname -r`/ not found"
            echo "       Please ensure 'make modules_install' is done properly."
            exit 7
        fi
    fi
    
    # vim: ft=sh:ts=4:sw=4:et
    

  • Please find the attached usb.log file.

    Gabriele

    root@am335x-evm:~# ./8473.chkusb-0.2.10.sh.txt
    chkusb.sh Version 0.2.10
    Linux am335x-evm 4.14.79custom+ #111 PREEMPT Fri Oct 4 12:06:25 CEST 2019 armv7l GNU/Linux
    USB initialization failed
    Warning: CONFIG_USB_MUSB_DUAL_ROLE undefined.
    musb-hdrc.0: mode b_idle, Vbus off, timeout 1100 msec
    cat: can't open '/musb-hdrc.*/mode': No such file or directory
    cat: can't open '/musb-hdrc.*/vbus': No such file or directory
    musb-hdrc.*: mode ,
    Power       : e0
    Testmode    : 00
    DevCtl      : 80
    usb@47401000: peripheral, (null)
    usb@47401800: host, (null)
    usb-phy@47401b00: disabled in devicetree
    
    Gadget Kernel Config: g_zero is enabled
    Gadget Kernel Config: g_audio is enabled
    Gadget Kernel Config: g_ether is enabled
    Gadget Kernel Config: g_ncm is enabled
    Gadget Kernel Config: g_mass_storage is enabled
    Gadget Kernel Config: g_serial is enabled
    Gadget Kernel Config: g_printer is enabled
    gadget driver loaded: DRIVER=g_multi
    
    The list of USB gadget drivers installed:
    /lib/modules/4.14.79custom+/kernel/drivers/usb/gadget/:
    function/
    legacy/
    libcomposite.ko
    udc/
    
    /lib/modules/4.14.79custom+/kernel/drivers/usb/gadget/function:
    u_audio.ko
    u_ether.ko
    u_serial.ko
    usb_f_acm.ko
    usb_f_ecm.ko
    usb_f_ecm_subset.ko
    usb_f_eem.ko
    usb_f_fs.ko
    usb_f_hid.ko
    usb_f_mass_storage.ko
    usb_f_midi.ko
    usb_f_ncm.ko
    usb_f_obex.ko
    usb_f_printer.ko
    usb_f_rndis.ko
    usb_f_serial.ko
    usb_f_ss_lb.ko
    usb_f_uac1.ko
    usb_f_uac2.ko
    
    /lib/modules/4.14.79custom+/kernel/drivers/usb/gadget/legacy:
    g_acm_ms.ko
    g_audio.ko
    g_cdc.ko
    g_dbgp.ko
    g_ether.ko
    g_ffs.ko
    g_hid.ko
    g_mass_storage.ko
    g_midi.ko
    g_multi.ko
    g_ncm.ko
    g_printer.ko
    g_serial.ko
    g_zero.ko
    gadgetfs.ko
    
    /lib/modules/4.14.79custom+/kernel/drivers/usb/gadget/udc:
    udc-core.ko
    

  • Please try use the default kernel config and beaglebone dts in the Processor SDK Linux kernel without change any USB related configuration to see if the issue still happen.

  • Hi, I haven’t heard back from you, I’m assuming you were able to resolve your issue. If not, just post a reply below (or create a new thread if the thread has locked due to time-out).  thanks.

  • Hi,

    sorry for the late reply. At the moment I have no spare time to work on this issue, I will come back as soon as I can.

    Thank you for your suggestion,

    Gabriele

  • Hi,

    it took me a while, but I figured out that the problem was located somewhere at gadget level (we were using g_multi): for some reason it won't works if the board is booted without USB plugged in. I did some test using libcompose and I was able to setup a composite gadget (ACM + RNDIS) that worked without any problem, no matter when the board is connected.

    Right now I have no time to investigate the g_multi issue, but probably doesn't matter since it's legacy software.

    In conclusion, if someone is facing the same problem as mine, I highly recommend to switch to libcompose + configfs (even if you are using a single gadget!).

    Here are some links:

    Best regards,

    Gabriele