git: b02419fc409c - stable/13 - Revert "mips: remove saf1761"
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Wed, 25 Jan 2023 04:46:00 UTC
The branch stable/13 has been updated by imp:
URL: https://cgit.FreeBSD.org/src/commit/?id=b02419fc409c4857ef263b30f823674c6f6d834e
commit b02419fc409c4857ef263b30f823674c6f6d834e
Author: Warner Losh <imp@FreeBSD.org>
AuthorDate: 2023-01-25 04:00:23 +0000
Commit: Warner Losh <imp@FreeBSD.org>
CommitDate: 2023-01-25 04:00:23 +0000
Revert "mips: remove saf1761"
Mips is still in stable/13, so this should not have been merged.
This reverts commit 622ab2c4834068312b6cd33fd7ac961f31240350.
Sponsored by: Netflix
---
stand/usb/usbcore.mk | 8 +
sys/dev/usb/controller/saf1761_otg.c | 3657 +++++++++++++++++++++++++++++
sys/dev/usb/controller/saf1761_otg.h | 175 ++
sys/dev/usb/controller/saf1761_otg_boot.c | 140 ++
sys/dev/usb/controller/saf1761_otg_fdt.c | 269 +++
sys/dev/usb/controller/saf1761_otg_reg.h | 274 +++
sys/modules/usb/Makefile | 9 +-
sys/modules/usb/saf1761otg/Makefile | 42 +
8 files changed, 4573 insertions(+), 1 deletion(-)
diff --git a/stand/usb/usbcore.mk b/stand/usb/usbcore.mk
index ae80d06a24e7..7e0cc989228b 100644
--- a/stand/usb/usbcore.mk
+++ b/stand/usb/usbcore.mk
@@ -126,6 +126,14 @@ CFLAGS += -DUSB_PCI_PROBE_LIST="\"uss820dci\""
KSRCS+= uss820dci.c
.endif
+.if defined(HAVE_SAF1761OTG)
+CFLAGS += -DUSB_PCI_PROBE_LIST="\"saf1761otg\""
+CFLAGS += -DUSB_PCI_MEMORY_ADDRESS=0x900000007f100000ULL
+CFLAGS += -DUSB_PCI_MEMORY_SIZE=0x40000U
+KSRCS+= saf1761_otg.c
+KSRCS+= saf1761_otg_boot.c
+.endif
+
#
# USB core and templates
#
diff --git a/sys/dev/usb/controller/saf1761_otg.c b/sys/dev/usb/controller/saf1761_otg.c
new file mode 100644
index 000000000000..f5725a3cb48a
--- /dev/null
+++ b/sys/dev/usb/controller/saf1761_otg.c
@@ -0,0 +1,3657 @@
+/* $FreeBSD$ */
+/*-
+ * Copyright (c) 2014 Hans Petter Selasky <hselasky@FreeBSD.org>
+ * All rights reserved.
+ *
+ * This software was developed by SRI International and the University of
+ * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
+ * ("CTSRD"), as part of the DARPA CRASH research programme.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+/*
+ * This file contains the driver for the SAF1761 series USB OTG
+ * controller.
+ *
+ * Datasheet is available from:
+ * http://www.nxp.com/products/automotive/multimedia/usb/SAF1761BE.html
+ */
+
+#ifdef USB_GLOBAL_INCLUDE_FILE
+#include USB_GLOBAL_INCLUDE_FILE
+#else
+#include <sys/stdint.h>
+#include <sys/stddef.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/module.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/condvar.h>
+#include <sys/sysctl.h>
+#include <sys/sx.h>
+#include <sys/unistd.h>
+#include <sys/callout.h>
+#include <sys/malloc.h>
+#include <sys/priv.h>
+#include <sys/libkern.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+
+#define USB_DEBUG_VAR saf1761_otg_debug
+
+#include <dev/usb/usb_core.h>
+#include <dev/usb/usb_debug.h>
+#include <dev/usb/usb_busdma.h>
+#include <dev/usb/usb_process.h>
+#include <dev/usb/usb_transfer.h>
+#include <dev/usb/usb_device.h>
+#include <dev/usb/usb_hub.h>
+#include <dev/usb/usb_util.h>
+
+#include <dev/usb/usb_controller.h>
+#include <dev/usb/usb_bus.h>
+#endif /* USB_GLOBAL_INCLUDE_FILE */
+
+#include <dev/usb/controller/saf1761_otg.h>
+#include <dev/usb/controller/saf1761_otg_reg.h>
+
+#define SAF1761_OTG_BUS2SC(bus) \
+ ((struct saf1761_otg_softc *)(((uint8_t *)(bus)) - \
+ ((uint8_t *)&(((struct saf1761_otg_softc *)0)->sc_bus))))
+
+#define SAF1761_OTG_PC2UDEV(pc) \
+ (USB_DMATAG_TO_XROOT((pc)->tag_parent)->udev)
+
+#define SAF1761_DCINTERRUPT_THREAD_IRQ \
+ (SOTG_DCINTERRUPT_IEVBUS | SOTG_DCINTERRUPT_IEBRST | \
+ SOTG_DCINTERRUPT_IERESM | SOTG_DCINTERRUPT_IESUSP)
+
+#ifdef USB_DEBUG
+static int saf1761_otg_debug = 0;
+static int saf1761_otg_forcefs = 0;
+
+static
+SYSCTL_NODE(_hw_usb, OID_AUTO, saf1761_otg, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
+ "USB SAF1761 DCI");
+
+SYSCTL_INT(_hw_usb_saf1761_otg, OID_AUTO, debug, CTLFLAG_RWTUN,
+ &saf1761_otg_debug, 0, "SAF1761 DCI debug level");
+SYSCTL_INT(_hw_usb_saf1761_otg, OID_AUTO, forcefs, CTLFLAG_RWTUN,
+ &saf1761_otg_forcefs, 0, "SAF1761 DCI force FULL speed");
+#endif
+
+#define SAF1761_OTG_INTR_ENDPT 1
+
+/* prototypes */
+
+static const struct usb_bus_methods saf1761_otg_bus_methods;
+static const struct usb_pipe_methods saf1761_otg_non_isoc_methods;
+static const struct usb_pipe_methods saf1761_otg_device_isoc_methods;
+static const struct usb_pipe_methods saf1761_otg_host_isoc_methods;
+
+static saf1761_otg_cmd_t saf1761_host_setup_tx;
+static saf1761_otg_cmd_t saf1761_host_bulk_data_rx;
+static saf1761_otg_cmd_t saf1761_host_bulk_data_tx;
+static saf1761_otg_cmd_t saf1761_host_intr_data_rx;
+static saf1761_otg_cmd_t saf1761_host_intr_data_tx;
+static saf1761_otg_cmd_t saf1761_host_isoc_data_rx;
+static saf1761_otg_cmd_t saf1761_host_isoc_data_tx;
+static saf1761_otg_cmd_t saf1761_device_setup_rx;
+static saf1761_otg_cmd_t saf1761_device_data_rx;
+static saf1761_otg_cmd_t saf1761_device_data_tx;
+static saf1761_otg_cmd_t saf1761_device_data_tx_sync;
+static void saf1761_otg_device_done(struct usb_xfer *, usb_error_t);
+static void saf1761_otg_do_poll(struct usb_bus *);
+static void saf1761_otg_standard_done(struct usb_xfer *);
+static void saf1761_otg_intr_set(struct usb_xfer *, uint8_t);
+static void saf1761_otg_root_intr(struct saf1761_otg_softc *);
+static void saf1761_otg_enable_psof(struct saf1761_otg_softc *, uint8_t);
+
+/*
+ * Here is a list of what the SAF1761 chip can support. The main
+ * limitation is that the sum of the buffer sizes must be less than
+ * 8192 bytes.
+ */
+static const struct usb_hw_ep_profile saf1761_otg_ep_profile[] = {
+ [0] = {
+ .max_in_frame_size = 64,
+ .max_out_frame_size = 64,
+ .is_simplex = 0,
+ .support_control = 1,
+ },
+ [1] = {
+ .max_in_frame_size = SOTG_HS_MAX_PACKET_SIZE,
+ .max_out_frame_size = SOTG_HS_MAX_PACKET_SIZE,
+ .is_simplex = 0,
+ .support_interrupt = 1,
+ .support_bulk = 1,
+ .support_isochronous = 1,
+ .support_in = 1,
+ .support_out = 1,
+ },
+};
+
+static void
+saf1761_otg_get_hw_ep_profile(struct usb_device *udev,
+ const struct usb_hw_ep_profile **ppf, uint8_t ep_addr)
+{
+ if (ep_addr == 0) {
+ *ppf = saf1761_otg_ep_profile + 0;
+ } else if (ep_addr < 8) {
+ *ppf = saf1761_otg_ep_profile + 1;
+ } else {
+ *ppf = NULL;
+ }
+}
+
+static void
+saf1761_otg_pull_up(struct saf1761_otg_softc *sc)
+{
+ /* activate pullup on D+, if possible */
+
+ if (!sc->sc_flags.d_pulled_up && sc->sc_flags.port_powered) {
+ DPRINTF("\n");
+
+ sc->sc_flags.d_pulled_up = 1;
+ }
+}
+
+static void
+saf1761_otg_pull_down(struct saf1761_otg_softc *sc)
+{
+ /* release pullup on D+, if possible */
+
+ if (sc->sc_flags.d_pulled_up) {
+ DPRINTF("\n");
+
+ sc->sc_flags.d_pulled_up = 0;
+ }
+}
+
+static void
+saf1761_otg_wakeup_peer(struct saf1761_otg_softc *sc)
+{
+ uint16_t temp;
+
+ if (!(sc->sc_flags.status_suspend))
+ return;
+
+ DPRINTFN(5, "\n");
+
+ temp = SAF1761_READ_LE_4(sc, SOTG_MODE);
+ SAF1761_WRITE_LE_4(sc, SOTG_MODE, temp | SOTG_MODE_SNDRSU);
+ SAF1761_WRITE_LE_4(sc, SOTG_MODE, temp & ~SOTG_MODE_SNDRSU);
+
+ /* Wait 8ms for remote wakeup to complete. */
+ usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 125);
+}
+
+static uint8_t
+saf1761_host_channel_alloc(struct saf1761_otg_softc *sc, struct saf1761_otg_td *td)
+{
+ uint32_t map;
+ int x;
+
+ if (td->channel < SOTG_HOST_CHANNEL_MAX)
+ return (0);
+
+ /* check if device is suspended */
+ if (SAF1761_OTG_PC2UDEV(td->pc)->flags.self_suspended != 0)
+ return (1); /* busy - cannot transfer data */
+
+ switch (td->ep_type) {
+ case UE_INTERRUPT:
+ map = ~(sc->sc_host_intr_map |
+ sc->sc_host_intr_busy_map[0] |
+ sc->sc_host_intr_busy_map[1]);
+ /* find first set bit */
+ x = ffs(map) - 1;
+ if (x < 0 || x > 31)
+ break;
+ sc->sc_host_intr_map |= (1U << x);
+ td->channel = 32 + x;
+ return (0);
+ case UE_ISOCHRONOUS:
+ map = ~(sc->sc_host_isoc_map |
+ sc->sc_host_isoc_busy_map[0] |
+ sc->sc_host_isoc_busy_map[1]);
+ /* find first set bit */
+ x = ffs(map) - 1;
+ if (x < 0 || x > 31)
+ break;
+ sc->sc_host_isoc_map |= (1U << x);
+ td->channel = x;
+ return (0);
+ default:
+ map = ~(sc->sc_host_async_map |
+ sc->sc_host_async_busy_map[0] |
+ sc->sc_host_async_busy_map[1]);
+ /* find first set bit */
+ x = ffs(map) - 1;
+ if (x < 0 || x > 31)
+ break;
+ sc->sc_host_async_map |= (1U << x);
+ td->channel = 64 + x;
+ return (0);
+ }
+ return (1);
+}
+
+static void
+saf1761_host_channel_free(struct saf1761_otg_softc *sc, struct saf1761_otg_td *td)
+{
+ uint32_t x;
+
+ if (td->channel >= SOTG_HOST_CHANNEL_MAX)
+ return;
+
+ switch (td->ep_type) {
+ case UE_INTERRUPT:
+ x = td->channel - 32;
+ td->channel = SOTG_HOST_CHANNEL_MAX;
+ sc->sc_host_intr_map &= ~(1U << x);
+ sc->sc_host_intr_suspend_map &= ~(1U << x);
+ sc->sc_host_intr_busy_map[0] |= (1U << x);
+ SAF1761_WRITE_LE_4(sc, SOTG_INT_PTD_SKIP_PTD,
+ (~sc->sc_host_intr_map) | sc->sc_host_intr_suspend_map);
+ break;
+ case UE_ISOCHRONOUS:
+ x = td->channel;
+ td->channel = SOTG_HOST_CHANNEL_MAX;
+ sc->sc_host_isoc_map &= ~(1U << x);
+ sc->sc_host_isoc_suspend_map &= ~(1U << x);
+ sc->sc_host_isoc_busy_map[0] |= (1U << x);
+ SAF1761_WRITE_LE_4(sc, SOTG_ISO_PTD_SKIP_PTD,
+ (~sc->sc_host_isoc_map) | sc->sc_host_isoc_suspend_map);
+ break;
+ default:
+ x = td->channel - 64;
+ td->channel = SOTG_HOST_CHANNEL_MAX;
+ sc->sc_host_async_map &= ~(1U << x);
+ sc->sc_host_async_suspend_map &= ~(1U << x);
+ sc->sc_host_async_busy_map[0] |= (1U << x);
+ SAF1761_WRITE_LE_4(sc, SOTG_ATL_PTD_SKIP_PTD,
+ (~sc->sc_host_async_map) | sc->sc_host_async_suspend_map);
+ break;
+ }
+ saf1761_otg_enable_psof(sc, 1);
+}
+
+static uint32_t
+saf1761_peek_host_status_le_4(struct saf1761_otg_softc *sc, uint32_t offset)
+{
+ uint32_t x = 0;
+ while (1) {
+ uint32_t retval;
+
+ SAF1761_WRITE_LE_4(sc, SOTG_MEMORY_REG, offset);
+ SAF1761_90NS_DELAY(sc); /* read prefetch time is 90ns */
+ retval = SAF1761_READ_LE_4(sc, offset);
+ if (retval != 0)
+ return (retval);
+ if (++x == 8) {
+ DPRINTF("STAUS is zero at offset 0x%x\n", offset);
+ break;
+ }
+ }
+ return (0);
+}
+
+static void
+saf1761_read_host_memory(struct saf1761_otg_softc *sc,
+ struct saf1761_otg_td *td, uint32_t len)
+{
+ struct usb_page_search buf_res;
+ uint32_t offset;
+ uint32_t count;
+
+ if (len == 0)
+ return;
+
+ offset = SOTG_DATA_ADDR(td->channel);
+ SAF1761_WRITE_LE_4(sc, SOTG_MEMORY_REG, offset);
+ SAF1761_90NS_DELAY(sc); /* read prefetch time is 90ns */
+
+ /* optimised read first */
+ while (len > 0) {
+ usbd_get_page(td->pc, td->offset, &buf_res);
+
+ /* get correct length */
+ if (buf_res.length > len)
+ buf_res.length = len;
+
+ /* check buffer alignment */
+ if (((uintptr_t)buf_res.buffer) & 3)
+ break;
+
+ count = buf_res.length & ~3;
+ if (count == 0)
+ break;
+
+ bus_space_read_region_4((sc)->sc_io_tag, (sc)->sc_io_hdl,
+ offset, buf_res.buffer, count / 4);
+
+ len -= count;
+ offset += count;
+
+ /* update remainder and offset */
+ td->remainder -= count;
+ td->offset += count;
+ }
+
+ if (len > 0) {
+ /* use bounce buffer */
+ bus_space_read_region_4((sc)->sc_io_tag, (sc)->sc_io_hdl,
+ offset, sc->sc_bounce_buffer, (len + 3) / 4);
+ usbd_copy_in(td->pc, td->offset,
+ sc->sc_bounce_buffer, len);
+
+ /* update remainder and offset */
+ td->remainder -= len;
+ td->offset += len;
+ }
+}
+
+static void
+saf1761_write_host_memory(struct saf1761_otg_softc *sc,
+ struct saf1761_otg_td *td, uint32_t len)
+{
+ struct usb_page_search buf_res;
+ uint32_t offset;
+ uint32_t count;
+
+ if (len == 0)
+ return;
+
+ offset = SOTG_DATA_ADDR(td->channel);
+
+ /* optimised write first */
+ while (len > 0) {
+ usbd_get_page(td->pc, td->offset, &buf_res);
+
+ /* get correct length */
+ if (buf_res.length > len)
+ buf_res.length = len;
+
+ /* check buffer alignment */
+ if (((uintptr_t)buf_res.buffer) & 3)
+ break;
+
+ count = buf_res.length & ~3;
+ if (count == 0)
+ break;
+
+ bus_space_write_region_4((sc)->sc_io_tag, (sc)->sc_io_hdl,
+ offset, buf_res.buffer, count / 4);
+
+ len -= count;
+ offset += count;
+
+ /* update remainder and offset */
+ td->remainder -= count;
+ td->offset += count;
+ }
+ if (len > 0) {
+ /* use bounce buffer */
+ usbd_copy_out(td->pc, td->offset, sc->sc_bounce_buffer, len);
+ bus_space_write_region_4((sc)->sc_io_tag, (sc)->sc_io_hdl,
+ offset, sc->sc_bounce_buffer, (len + 3) / 4);
+
+ /* update remainder and offset */
+ td->remainder -= len;
+ td->offset += len;
+ }
+}
+
+static uint8_t
+saf1761_host_setup_tx(struct saf1761_otg_softc *sc, struct saf1761_otg_td *td)
+{
+ uint32_t pdt_addr;
+ uint32_t status;
+ uint32_t count;
+ uint32_t temp;
+
+ if (td->channel < SOTG_HOST_CHANNEL_MAX) {
+ pdt_addr = SOTG_PTD(td->channel);
+
+ status = saf1761_peek_host_status_le_4(sc, pdt_addr + SOTG_PTD_DW3);
+
+ DPRINTFN(5, "STATUS=0x%08x\n", status);
+
+ if (status & SOTG_PTD_DW3_ACTIVE) {
+ goto busy;
+ } else if (status & SOTG_PTD_DW3_HALTED) {
+ td->error_any = 1;
+ }
+ goto complete;
+ }
+ if (saf1761_host_channel_alloc(sc, td))
+ goto busy;
+
+ count = 8;
+
+ if (count != td->remainder) {
+ td->error_any = 1;
+ goto complete;
+ }
+
+ saf1761_write_host_memory(sc, td, count);
+
+ pdt_addr = SOTG_PTD(td->channel);
+
+ SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW7, 0);
+ SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW6, 0);
+ SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW5, 0);
+ SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW4, 0);
+
+ temp = SOTG_PTD_DW3_ACTIVE | (td->toggle << 25) | 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;
+ SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW2, temp);
+
+ temp = td->dw1_value | (2 << 10) /* SETUP PID */ | (td->ep_index >> 1);
+ SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW1, temp);
+
+ temp = (td->ep_index << 31) | (1 << 29) /* pkt-multiplier */ |
+ (td->max_packet_size << 18) /* wMaxPacketSize */ |
+ (count << 3) /* transfer count */ |
+ SOTG_PTD_DW0_VALID;
+ SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW0, temp);
+
+ /* activate PTD */
+ SAF1761_WRITE_LE_4(sc, SOTG_ATL_PTD_SKIP_PTD,
+ (~sc->sc_host_async_map) | sc->sc_host_async_suspend_map);
+
+ td->toggle = 1;
+busy:
+ return (1); /* busy */
+complete:
+ saf1761_host_channel_free(sc, td);
+ return (0); /* complete */
+}
+
+static uint8_t
+saf1761_host_bulk_data_rx(struct saf1761_otg_softc *sc, struct saf1761_otg_td *td)
+{
+ uint32_t pdt_addr;
+ uint32_t temp;
+
+ if (td->channel < SOTG_HOST_CHANNEL_MAX) {
+ uint32_t status;
+ uint32_t count;
+ uint8_t got_short;
+
+ pdt_addr = SOTG_PTD(td->channel);
+
+ status = saf1761_peek_host_status_le_4(sc, pdt_addr + SOTG_PTD_DW3);
+
+ DPRINTFN(5, "STATUS=0x%08x\n", status);
+
+ if (status & SOTG_PTD_DW3_ACTIVE) {
+ temp = saf1761_peek_host_status_le_4(sc,
+ pdt_addr + SOTG_PTD_DW0);
+ if (temp & SOTG_PTD_DW0_VALID) {
+ goto busy;
+ } else {
+ status = saf1761_peek_host_status_le_4(sc,
+ pdt_addr + SOTG_PTD_DW3);
+
+ /* check if still active */
+ if (status & SOTG_PTD_DW3_ACTIVE) {
+ saf1761_host_channel_free(sc, td);
+ goto retry;
+ } else if (status & SOTG_PTD_DW3_HALTED) {
+ if (!(status & SOTG_PTD_DW3_ERRORS))
+ td->error_stall = 1;
+ td->error_any = 1;
+ goto complete;
+ }
+ }
+ } else if (status & SOTG_PTD_DW3_HALTED) {
+ if (!(status & SOTG_PTD_DW3_ERRORS))
+ td->error_stall = 1;
+ td->error_any = 1;
+ goto complete;
+ }
+ if (td->dw1_value & SOTG_PTD_DW1_ENABLE_SPLIT)
+ count = (status & SOTG_PTD_DW3_XFER_COUNT_SPLIT);
+ else
+ count = (status & SOTG_PTD_DW3_XFER_COUNT_HS);
+ got_short = 0;
+
+ /* verify the packet byte count */
+ if (count != td->max_packet_size) {
+ if (count < td->max_packet_size) {
+ /* we have a short packet */
+ td->short_pkt = 1;
+ got_short = 1;
+ } else {
+ /* invalid USB packet */
+ td->error_any = 1;
+ goto complete;
+ }
+ }
+ td->toggle ^= 1;
+
+ /* verify the packet byte count */
+ if (count > td->remainder) {
+ /* invalid USB packet */
+ td->error_any = 1;
+ goto complete;
+ }
+
+ saf1761_read_host_memory(sc, td, count);
+
+ /* check if we are complete */
+ if ((td->remainder == 0) || got_short) {
+ if (td->short_pkt)
+ goto complete;
+ /* else need to receive a zero length packet */
+ }
+ saf1761_host_channel_free(sc, td);
+ }
+retry:
+ if (saf1761_host_channel_alloc(sc, td))
+ goto busy;
+
+ /* set toggle, if any */
+ if (td->set_toggle) {
+ td->set_toggle = 0;
+ td->toggle = 1;
+ }
+
+ /* receive one more packet */
+
+ pdt_addr = SOTG_PTD(td->channel);
+
+ SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW7, 0);
+ SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW6, 0);
+ SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW5, 0);
+ SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW4, 0);
+
+ temp = SOTG_PTD_DW3_ACTIVE | (td->toggle << 25) |
+ SOTG_PTD_DW3_CERR_2;
+ SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW3, temp);
+
+ temp = (SOTG_HC_MEMORY_ADDR(SOTG_DATA_ADDR(td->channel)) << 8);
+ SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW2, temp);
+
+ temp = td->dw1_value | (1 << 10) /* IN-PID */ | (td->ep_index >> 1);
+ SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW1, temp);
+
+ temp = (td->ep_index << 31) | (1 << 29) /* pkt-multiplier */ |
+ (td->max_packet_size << 18) /* wMaxPacketSize */ |
+ (td->max_packet_size << 3) /* transfer count */ |
+ SOTG_PTD_DW0_VALID;
+ SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW0, temp);
+
+ /* activate PTD */
+ SAF1761_WRITE_LE_4(sc, SOTG_ATL_PTD_SKIP_PTD,
+ (~sc->sc_host_async_map) | sc->sc_host_async_suspend_map);
+busy:
+ return (1); /* busy */
+complete:
+ saf1761_host_channel_free(sc, td);
+ return (0); /* complete */
+}
+
+static uint8_t
+saf1761_host_bulk_data_tx(struct saf1761_otg_softc *sc, struct saf1761_otg_td *td)
+{
+ uint32_t pdt_addr;
+ uint32_t temp;
+ uint32_t count;
+
+ if (td->channel < SOTG_HOST_CHANNEL_MAX) {
+ uint32_t status;
+
+ pdt_addr = SOTG_PTD(td->channel);
+
+ status = saf1761_peek_host_status_le_4(sc, pdt_addr + SOTG_PTD_DW3);
+
+ DPRINTFN(5, "STATUS=0x%08x\n", status);
+
+ if (status & SOTG_PTD_DW3_ACTIVE) {
+ goto busy;
+ } else if (status & SOTG_PTD_DW3_HALTED) {
+ if (!(status & SOTG_PTD_DW3_ERRORS))
+ td->error_stall = 1;
+ td->error_any = 1;
+ goto complete;
+ }
+ /* check remainder */
+ if (td->remainder == 0) {
+ if (td->short_pkt)
+ goto complete;
+ /* else we need to transmit a short packet */
+ }
+ saf1761_host_channel_free(sc, td);
+ }
+ if (saf1761_host_channel_alloc(sc, td))
+ goto busy;
+
+ count = td->max_packet_size;
+ if (td->remainder < count) {
+ /* we have a short packet */
+ td->short_pkt = 1;
+ count = td->remainder;
+ }
+
+ saf1761_write_host_memory(sc, td, count);
+
+ /* set toggle, if any */
+ if (td->set_toggle) {
+ td->set_toggle = 0;
+ td->toggle = 1;
+ }
+
+ /* send one more packet */
+
+ pdt_addr = SOTG_PTD(td->channel);
+
+ SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW7, 0);
+ SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW6, 0);
+ SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW5, 0);
+ SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW4, 0);
+
+ temp = SOTG_PTD_DW3_ACTIVE | (td->toggle << 25) |
+ SOTG_PTD_DW3_CERR_2;
+ SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW3, temp);
+
+ temp = (SOTG_HC_MEMORY_ADDR(SOTG_DATA_ADDR(td->channel)) << 8);
+ SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW2, temp);
+
+ temp = td->dw1_value | (0 << 10) /* OUT-PID */ | (td->ep_index >> 1);
+ SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW1, temp);
+
+ temp = (td->ep_index << 31) | (1 << 29) /* pkt-multiplier */ |
+ (td->max_packet_size << 18) /* wMaxPacketSize */ |
+ (count << 3) /* transfer count */ |
+ SOTG_PTD_DW0_VALID;
+ SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW0, temp);
+
+ /* activate PTD */
+ SAF1761_WRITE_LE_4(sc, SOTG_ATL_PTD_SKIP_PTD,
+ (~sc->sc_host_async_map) | sc->sc_host_async_suspend_map);
+
+ td->toggle ^= 1;
+busy:
+ return (1); /* busy */
+complete:
+ saf1761_host_channel_free(sc, td);
+ return (0); /* complete */
+}
+
+static uint8_t
+saf1761_host_intr_data_rx(struct saf1761_otg_softc *sc, struct saf1761_otg_td *td)
+{
+ uint32_t pdt_addr;
+ uint32_t temp;
+
+ if (td->channel < SOTG_HOST_CHANNEL_MAX) {
+ uint32_t status;
+ uint32_t count;
+ uint8_t got_short;
+
+ pdt_addr = SOTG_PTD(td->channel);
+
+ status = saf1761_peek_host_status_le_4(sc, pdt_addr + SOTG_PTD_DW3);
+
+ DPRINTFN(5, "STATUS=0x%08x\n", status);
+
+ if (status & SOTG_PTD_DW3_ACTIVE) {
+ goto busy;
+ } else if (status & SOTG_PTD_DW3_HALTED) {
+ if (!(status & SOTG_PTD_DW3_ERRORS))
+ td->error_stall = 1;
+ td->error_any = 1;
+ goto complete;
+ }
+ if (td->dw1_value & SOTG_PTD_DW1_ENABLE_SPLIT)
+ count = (status & SOTG_PTD_DW3_XFER_COUNT_SPLIT);
+ else
+ count = (status & SOTG_PTD_DW3_XFER_COUNT_HS);
+ got_short = 0;
+
+ /* verify the packet byte count */
+ if (count != td->max_packet_size) {
+ if (count < td->max_packet_size) {
+ /* we have a short packet */
+ td->short_pkt = 1;
+ got_short = 1;
+ } else {
+ /* invalid USB packet */
+ td->error_any = 1;
+ goto complete;
+ }
+ }
+ td->toggle ^= 1;
+
+ /* verify the packet byte count */
+ if (count > td->remainder) {
+ /* invalid USB packet */
+ td->error_any = 1;
+ goto complete;
+ }
+
+ saf1761_read_host_memory(sc, td, count);
+
+ /* check if we are complete */
+ if ((td->remainder == 0) || got_short) {
+ if (td->short_pkt)
+ goto complete;
+ /* else need to receive a zero length packet */
+ }
+ saf1761_host_channel_free(sc, td);
+ }
+ if (saf1761_host_channel_alloc(sc, td))
+ goto busy;
+
+ /* set toggle, if any */
+ if (td->set_toggle) {
+ td->set_toggle = 0;
+ td->toggle = 1;
+ }
+
+ /* receive one more packet */
+
+ pdt_addr = SOTG_PTD(td->channel);
+
+ SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW7, 0);
+ SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW6, 0);
+
+ 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 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;
+ SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW3, temp);
+
+ temp = (SOTG_HC_MEMORY_ADDR(SOTG_DATA_ADDR(td->channel)) << 8) |
+ (td->interval & 0xF8);
+ SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW2, temp);
+
+ temp = td->dw1_value | (1 << 10) /* IN-PID */ | (td->ep_index >> 1);
+ SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW1, temp);
+
+ temp = (td->ep_index << 31) | (1 << 29) /* pkt-multiplier */ |
+ (td->max_packet_size << 18) /* wMaxPacketSize */ |
+ (td->max_packet_size << 3) /* transfer count */ |
+ SOTG_PTD_DW0_VALID;
+ SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW0, temp);
+
+ /* activate PTD */
+ SAF1761_WRITE_LE_4(sc, SOTG_INT_PTD_SKIP_PTD,
+ (~sc->sc_host_intr_map) | sc->sc_host_intr_suspend_map);
+busy:
+ return (1); /* busy */
+complete:
+ saf1761_host_channel_free(sc, td);
+ return (0); /* complete */
+}
+
+static uint8_t
+saf1761_host_intr_data_tx(struct saf1761_otg_softc *sc, struct saf1761_otg_td *td)
+{
+ uint32_t pdt_addr;
+ uint32_t temp;
+ uint32_t count;
+
+ if (td->channel < SOTG_HOST_CHANNEL_MAX) {
+ uint32_t status;
+
+ pdt_addr = SOTG_PTD(td->channel);
+
+ status = saf1761_peek_host_status_le_4(sc, pdt_addr + SOTG_PTD_DW3);
+
+ DPRINTFN(5, "STATUS=0x%08x\n", status);
+
+ if (status & SOTG_PTD_DW3_ACTIVE) {
+ goto busy;
+ } else if (status & SOTG_PTD_DW3_HALTED) {
+ if (!(status & SOTG_PTD_DW3_ERRORS))
+ td->error_stall = 1;
+ td->error_any = 1;
+ goto complete;
+ }
+
+ /* check remainder */
+ if (td->remainder == 0) {
+ if (td->short_pkt)
+ goto complete;
+ /* else we need to transmit a short packet */
+ }
+ saf1761_host_channel_free(sc, td);
+ }
+ if (saf1761_host_channel_alloc(sc, td))
+ goto busy;
+
+ count = td->max_packet_size;
+ if (td->remainder < count) {
+ /* we have a short packet */
+ td->short_pkt = 1;
+ count = td->remainder;
+ }
+
+ saf1761_write_host_memory(sc, td, count);
+
+ /* set toggle, if any */
+ if (td->set_toggle) {
+ td->set_toggle = 0;
+ td->toggle = 1;
+ }
+
+ /* send one more packet */
+
+ pdt_addr = SOTG_PTD(td->channel);
+
+ SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW7, 0);
+ SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW6, 0);
+
+ 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 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;
+ SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW3, temp);
+
+ temp = (SOTG_HC_MEMORY_ADDR(SOTG_DATA_ADDR(td->channel)) << 8) |
+ (td->interval & 0xF8);
+ SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW2, temp);
+
+ temp = td->dw1_value | (0 << 10) /* OUT-PID */ | (td->ep_index >> 1);
+ SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW1, temp);
+
+ temp = (td->ep_index << 31) | (1 << 29) /* pkt-multiplier */ |
+ (td->max_packet_size << 18) /* wMaxPacketSize */ |
+ (count << 3) /* transfer count */ |
+ SOTG_PTD_DW0_VALID;
+ SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW0, temp);
+
+ /* activate PTD */
+ SAF1761_WRITE_LE_4(sc, SOTG_INT_PTD_SKIP_PTD,
+ (~sc->sc_host_intr_map) | sc->sc_host_intr_suspend_map);
+
+ td->toggle ^= 1;
+busy:
+ return (1); /* busy */
+complete:
+ saf1761_host_channel_free(sc, td);
+ return (0); /* complete */
+}
+
+static uint8_t
+saf1761_host_isoc_data_rx(struct saf1761_otg_softc *sc, struct saf1761_otg_td *td)
+{
+ uint32_t pdt_addr;
+ uint32_t temp;
+
+ if (td->channel < SOTG_HOST_CHANNEL_MAX) {
+ uint32_t status;
+ uint32_t count;
+
+ pdt_addr = SOTG_PTD(td->channel);
+
+ status = saf1761_peek_host_status_le_4(sc, pdt_addr + SOTG_PTD_DW3);
*** 3690 LINES SKIPPED ***