From owner-svn-src-head@FreeBSD.ORG Sat Nov 22 17:26:44 2014 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id AE871870; Sat, 22 Nov 2014 17:26:44 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 9A71DBB8; Sat, 22 Nov 2014 17:26:44 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id sAMHQiTp086314; Sat, 22 Nov 2014 17:26:44 GMT (envelope-from hselasky@FreeBSD.org) Received: (from hselasky@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id sAMHQibd086313; Sat, 22 Nov 2014 17:26:44 GMT (envelope-from hselasky@FreeBSD.org) Message-Id: <201411221726.sAMHQibd086313@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: hselasky set sender to hselasky@FreeBSD.org using -f From: Hans Petter Selasky Date: Sat, 22 Nov 2014 17:26:44 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r274863 - head/sys/dev/usb/controller X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 22 Nov 2014 17:26:44 -0000 Author: hselasky Date: Sat Nov 22 17:26:43 2014 New Revision: 274863 URL: https://svnweb.freebsd.org/changeset/base/274863 Log: Fix the host mode ISOCHRONOUS transfer interval programming in the SAF1761 OTG driver. Currently the driver logic is very simple and double buffering the USB transactions is not done. Also you need to use an external USB high speed USB HUB for reliable FULL speed outgoing ISOCHRONOUS traffic, because the internal one chokes on so-called split transfers above 188 bytes. Modified: head/sys/dev/usb/controller/saf1761_otg.c Modified: head/sys/dev/usb/controller/saf1761_otg.c ============================================================================== --- head/sys/dev/usb/controller/saf1761_otg.c Sat Nov 22 17:19:39 2014 (r274862) +++ head/sys/dev/usb/controller/saf1761_otg.c Sat Nov 22 17:26:43 2014 (r274863) @@ -756,10 +756,14 @@ saf1761_host_intr_data_rx(struct saf1761 SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW7, 0); SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW6, 0); - temp = (0xFC << td->uframe) & 0xFF; /* complete split */ + if (td->dw1_value & SOTG_PTD_DW1_ENABLE_SPLIT) { + temp = (0xFC << td->uframe) & 0xFF; /* complete split */ + } else { + temp = 0; + } SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW5, temp); - temp = (1U << td->uframe); /* start split */ + temp = (1U << td->uframe); /* start mask or start split */ SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW4, temp); temp = SOTG_PTD_DW3_ACTIVE | (td->toggle << 25) | SOTG_PTD_DW3_CERR_3; @@ -846,10 +850,14 @@ saf1761_host_intr_data_tx(struct saf1761 SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW7, 0); SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW6, 0); - temp = (0xFC << td->uframe) & 0xFF; /* complete split */ + if (td->dw1_value & SOTG_PTD_DW1_ENABLE_SPLIT) { + temp = (0xFC << td->uframe) & 0xFF; /* complete split */ + } else { + temp = 0; + } SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW5, temp); - temp = (1U << td->uframe); /* start split */ + temp = (1U << td->uframe); /* start mask or start split */ SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW4, temp); temp = SOTG_PTD_DW3_ACTIVE | (td->toggle << 25) | SOTG_PTD_DW3_CERR_3; @@ -939,16 +947,21 @@ saf1761_host_isoc_data_rx(struct saf1761 SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW7, 0); SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW6, 0); - temp = (0xFC << td->uframe) & 0xFF; /* complete split */ + if (td->dw1_value & SOTG_PTD_DW1_ENABLE_SPLIT) { + temp = (0xFC << (td->uframe & 7)) & 0xFF; /* complete split */ + } else { + temp = 0; + } SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW5, temp); - temp = (1U << td->uframe); /* start split */ + temp = (1U << (td->uframe & 7)); /* start mask or start split */ SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW4, temp); temp = SOTG_PTD_DW3_ACTIVE | SOTG_PTD_DW3_CERR_3; SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW3, temp); - temp = (SOTG_HC_MEMORY_ADDR(SOTG_DATA_ADDR(td->channel)) << 8); + temp = (SOTG_HC_MEMORY_ADDR(SOTG_DATA_ADDR(td->channel)) << 8) | + (td->uframe & 0xF8); SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW2, temp); temp = td->dw1_value | (1 << 10) /* IN-PID */ | (td->ep_index >> 1); @@ -991,7 +1004,6 @@ saf1761_host_isoc_data_tx(struct saf1761 } else if (status & SOTG_PTD_DW3_HALTED) { goto complete; } - goto complete; } if (saf1761_host_channel_alloc(sc, td)) @@ -1014,13 +1026,14 @@ saf1761_host_isoc_data_tx(struct saf1761 SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW6, 0); SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW5, 0); - temp = (1U << td->uframe); /* start split */ + temp = (1U << (td->uframe & 7)); /* start mask or start split */ SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW4, temp); temp = SOTG_PTD_DW3_ACTIVE | SOTG_PTD_DW3_CERR_3; SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW3, temp); - temp = (SOTG_HC_MEMORY_ADDR(SOTG_DATA_ADDR(td->channel)) << 8); + temp = (SOTG_HC_MEMORY_ADDR(SOTG_DATA_ADDR(td->channel)) << 8) | + (td->uframe & 0xF8); SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW2, temp); temp = td->dw1_value | (0 << 10) /* OUT-PID */ | (td->ep_index >> 1); @@ -1685,6 +1698,8 @@ saf1761_otg_setup_standard_chain(struct uint8_t ep_type; uint8_t need_sync; uint8_t is_host; + uint8_t uframe_start; + uint8_t uframe_interval; DPRINTFN(9, "addr=%d endpt=%d sumlen=%d speed=%d\n", xfer->address, UE_GET_ADDR(xfer->endpointno), @@ -1738,15 +1753,25 @@ saf1761_otg_setup_standard_chain(struct x = 0; } + uframe_start = 0; + uframe_interval = 0; + if (x != xfer->nframes) { if (xfer->endpointno & UE_DIR_IN) { if (is_host) { - if (ep_type == UE_INTERRUPT) + if (ep_type == UE_INTERRUPT) { temp.func = &saf1761_host_intr_data_rx; - else if (ep_type == UE_ISOCHRONOUS) + } else if (ep_type == UE_ISOCHRONOUS) { temp.func = &saf1761_host_isoc_data_rx; - else + uframe_start = (SAF1761_READ_LE_4(sc, SOTG_FRINDEX) + 8) & + (SOTG_FRINDEX_MASK & ~7); + if (xfer->xroot->udev->speed == USB_SPEED_HIGH) + uframe_interval = 1U << xfer->fps_shift; + else + uframe_interval = 8U; + } else { temp.func = &saf1761_host_bulk_data_rx; + } need_sync = 0; } else { temp.func = &saf1761_device_data_tx; @@ -1754,12 +1779,19 @@ saf1761_otg_setup_standard_chain(struct } } else { if (is_host) { - if (ep_type == UE_INTERRUPT) + if (ep_type == UE_INTERRUPT) { temp.func = &saf1761_host_intr_data_tx; - else if (ep_type == UE_ISOCHRONOUS) + } else if (ep_type == UE_ISOCHRONOUS) { temp.func = &saf1761_host_isoc_data_tx; - else + uframe_start = (SAF1761_READ_LE_4(sc, SOTG_FRINDEX) + 8) & + (SOTG_FRINDEX_MASK & ~7); + if (xfer->xroot->udev->speed == USB_SPEED_HIGH) + uframe_interval = 1U << xfer->fps_shift; + else + uframe_interval = 8U; + } else { temp.func = &saf1761_host_bulk_data_tx; + } need_sync = 0; } else { temp.func = &saf1761_device_data_rx; @@ -1807,6 +1839,12 @@ saf1761_otg_setup_standard_chain(struct if (xfer->flags_int.isochronous_xfr) { temp.offset += temp.len; + + /* stamp the starting point for this transaction */ + temp.td->uframe = uframe_start; + + /* advance to next */ + uframe_start += uframe_interval; } else { /* get next Page Cache pointer */ temp.pc = xfer->frbuffers + x; @@ -3404,17 +3442,8 @@ saf1761_otg_xfer_setup(struct usb_setup_ td->ep_index = ep_no; td->ep_type = ep_type; td->dw1_value = dw1; - if (ep_type == UE_ISOCHRONOUS) { - if (parm->udev->speed == USB_SPEED_HIGH) { - uint8_t uframe_index = (ntd - 1 - n); - uframe_index <<= usbd_xfer_get_fps_shift(xfer); - td->uframe = (uframe_index & 7); - } else { - td->uframe = 0; - } - } else { - td->uframe = 0; - } + td->uframe = 0; + if (ep_type == UE_INTERRUPT) { if (xfer->interval > 32) td->interval = (32 / 2) << 3;