Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 27 Jun 2013 08:47:06 +0200
From:      Hans Petter Selasky <hps@bitfrost.no>
To:        Oleksandr Tymoshenko <gonzo@bluezbox.com>
Cc:        arm@freebsd.org, usb@freebsd.org
Subject:   Re: Beaglebone USB driver (Mentor Graphics OTG)
Message-ID:  <51CBDFEA.7050203@bitfrost.no>
In-Reply-To: <0927BB4C-6917-408D-B102-AB98F72314B6@bluezbox.com>
References:  <51608AA4.2020804@bluezbox.com> <51611A7B.2010105@bitfrost.no> <0927BB4C-6917-408D-B102-AB98F72314B6@bluezbox.com>

next in thread | previous in thread | raw e-mail | index | archive | help
On 06/27/13 02:53, Oleksandr Tymoshenko wrote:
>
> On 2013-04-07, at 12:04 AM, Hans Petter Selasky <hps@bitfrost.no> wrote:
>
>> On 04/06/13 22:50, Oleksandr Tymoshenko wrote:
>>> Hello,
>>>
>>> This is first iteration of Host Mode support for Mentor Graphics
>>> OTG USB controller. I tested it by building kernel with USB memory
>>> stick mounted as /usr/obj, resulting kernel was bootable and worked fine.
>>> I reused some ideas (mostly for channel-management) from
>>> DWT OTG driver.
>>>
>>> Some pieces are still missing:
>>> - Support for SPLIT transactions, I don not have high speed hub
>>>      right now to test it, but implementing it should be really
>>> straighforward.
>>> - Isochronous transfers. I do not have hardware to test this. Does
>>>      anybody have any suggestion about simple use case?
>>> - Control Data OUT transaction
>>> - Wrapper for atmel HW has not ben synced with new core logic requirements
>>>      yet
>>>
>>> Please review and test. I tested it only with gcc-built kernel/world.
>>> Now when
>>> first iteration is finished I'm going to update all my boards to new
>>> world order
>>> (clang/EABI) and re-test this stuff.
>>>
>>> Patch:
>>> http://people.freebsd.org/~gonzo/arm/patches/beaglebone-musb.diff
>>
>> Hi,
>>
>> Looks like you've got the grasp of the USB controller stuff :-)
>>
>> Some comments:
>>
>> 1) Use DPRINTFN(-1, ...) instead of printf() for all printf() that are not part of boot dmesg.
>>
>> +				break;
>> +			default:
>> +				td->transfer_type = 0;
>> +				printf("Invalid USB speed: %d\n", speed);
>> +				break;
>> +		}
>>
>>
>> 2) You should implement if HOST mode, support for SUSPEND and RESUME. See EHCI driver. Basically what you need is:
>>
>> a) USB transfers are stopped/paused. I know there is a hack you need if the host transfer cancel hangs, and that is to write a dummy device address and wait for the USB transfer to error out after 250 us max.
>>
>> b) switch on USB suspend signalling.
>>
>>
>> At resume:
>>
>> c) do resume signalling, similar to EHCI/UHCI I think.
>>
>> d) switch on channel tokens.
>>
>>   	case UHF_PORT_SUSPEND:
>> +		if (sc->sc_mode == MUSB2_HOST_MODE)
>> +			printf("TODO: Set UHF_PORT_SUSPEND\n");
>> +		break;
>>
>>
>>
>> 3) Make sure that channels are not generating tokens if they are aborted / cancelled / timedout. This can not be verified using a USB mass storage device. Verify this by connecting a USB serial adapter. Try to open/close /dev/cuaU0. Make sure it does not loose any bytes and that channel cancel does not hang forever.
>
>

Hi,

> Thanks for review. Took  me quite some time to get back
> to the driver but here is updated version that addresses some
> of the issues you've mentioned:
> http://people.freebsd.org/~gonzo/arm/patches/beaglebone-usb-20130626.diff
>
> It fixes several bugs, adds proper SPLIT transactions support and
> suspend/resume signalling.  I tested it with urtwn-based WiFi chip,
> mass storage device, USB keyboard connected directly and using
> high-speed hub.
>
> Suspend/resume is not 100% complete though. I can use USB serial
> port adapter if it's suspended/resumed unconnected. But it stuck if I do
> the test while connected. Is it the right way to test it?

Which suspend you mean system/resume suspend or USB suspend/resume?

You should implement a musb_set_hw_power_sleep() too. This handles 
system going into suspend. You should probably reset that adapter at 
this point.

static void
musb_set_hw_power_sleep(struct usb_bus *bus, uint32_t state)
{
         struct ehci_softc *sc = EHCI_BUS2SC(bus);

         switch (state) {
         case USB_HW_POWER_SUSPEND:
         case USB_HW_POWER_SHUTDOWN:
                 ehci_suspend(sc);
                 break;
         case USB_HW_POWER_RESUME:
                 ehci_resume(sc);
                 break;
         default:
                 break;
         }
}

If the musb requires that you stop tokens before going in and out of 
suspend, you need to add functions like this:


ehci_device_resume/ehci_device_suspend

>
> On the related note: can somebody suggest budget USB protocol analyzer
> with support for high-speed bus?
>

http://www.totalphase.com/products/beagle_usb480/

There are more, but I don't have the list right now.

You can probably just remove this check. We don't support LOW speed in 
device mode.

-
-		if ((udev->speed != USB_SPEED_FULL) &&
-		    (udev->speed != USB_SPEED_HIGH)) {
-			/* not supported */
-			return;
+		if (sc->sc_mode != MUSB2_HOST_MODE) {
+			if ((udev->speed != USB_SPEED_FULL) &&
+			    (udev->speed != USB_SPEED_HIGH)) {
+				/* not supported */
+				return;
+			}
  		}

The musbotg_channel_free function is not sufficient! You need to program 
a non-existing device address like 127 and wait for 2 ms I recommend. 
The ABORT bits don't work with this controller last time I tried them! 
You can verify this by loading and unloading the wireless driver. I 
guess that IN tokens don't stop when you unload the driver. You will see 
this using an USB analyzer.

+#define	MUSB2_MAX_DEVICES (USB_MAX_DEVICES - 1)

+static void	
+musbotg_channel_free(struct musbotg_softc *sc, struct musbotg_td *td)
+{
+
+	DPRINTFN(1, "ep_no=%d\n", td->channel);
+
+	if (sc->sc_mode == MUSB2_DEVICE_MODE)
+		return;
+
+	if (td == NULL)
+		return;
+	if (td->channel == -1)
+		return;
+
+	musbotg_ep_int_set(sc, td->channel, 0);
+	sc->sc_channel_mask &= ~(1 << td->channel);
+	td->channel = -1;

/* force transfer failure */
MUSB2_WRITE_1(sc, MUSB2_REG_RXFADDR(0), 127);
XXX channel should not be re-used until after 2*125us. Can probably use 
ticks for this!

+}

The 2ms can be done asynchronosly by implementing this function. See 
EHCI driver.

static void
musbotg_get_dma_delay(struct usb_device *udev, uint32_t *pus)
{

	if (host_mode)
	        *pus = 2000;                   /* microseconds */
	else
		*pus = 0;
}

--HPS



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?51CBDFEA.7050203>