From nobody Wed Jan 25 04:46:00 2023 X-Original-To: dev-commits-src-branches@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4P1rrT1M1yz3bZNr; Wed, 25 Jan 2023 04:46:01 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4P1rrS4vcLz4M2S; Wed, 25 Jan 2023 04:46:00 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1674621960; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=jejl2EA1uNkMHevFEM3VTx2b1DAl9FXHBCiKDv06maM=; b=U7JEC/yKrXEVdjdnePq4M70gYVbpPyczd4LQGPPJk8IgZo34IVijUULYD9Rj0ZCWwgeWEa 6FuWZX3sSdp463VFq1uwO2T/QwSFAJaP/z7ayvrYQLhnJPqL29G9kwrpg3b81t7w2GhWqT maXoGTEsZeHqOToWs+gQTNWaJTNpvMwztWnlBzhzKcbrvffRiaX81uNbfXjz6ALuh6rpUc 2c5j0/TlHZoTZu8/gp4enqnP4V/eSxwS4/gJstGZUg/OgGonIx8dihDrowwin3cC/QO6Nr 2pNoUCrqMKMrBiLi2QdCOwl5QQ8Yr2vHfaHhFKNxD4uJw+jdrNLE27pK5tTOBA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1674621960; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=jejl2EA1uNkMHevFEM3VTx2b1DAl9FXHBCiKDv06maM=; b=b6qJg9NlXoN2CiiTkHf/O+ZciSPU275blpOnCR6fucUTHHjzRFfelzy1RkA60NiRzhLJyx JSBOrs2cHIF4YTxZd2liLyOFnY93LhLgnn4vZniiVPxzWqlXsp0ZDJs9Sl2j+tlVViQHpT cbBxQAVzPzSELuM3St0oJ4vxFTnOlm2Y0kzFuOOCsgu56oatwTFfJNtyyX4M4I4Z18/kxH 8IHlupR1hd9kz0/duIUw+Xt4d96FF4sP++GTb5QJJczFy2m3w5uyzeo9Got2cjbhHpXFw9 kvI73UDIyvcF6MLIJTG+TizXkj4/GSNz8gQMXdCvBMNjIAU+CYdkb6AXt7SVzQ== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1674621960; a=rsa-sha256; cv=none; b=B9XdNJQvkzkWE3V+yfiChlgLJEvwrCH8WQt1QdN0BnYZ4ZGq57bgrGx5bpNKbVwoq5Zj6x gWfx3U9H4rxw16bpfwoGbMxDtWWNwYzcITM7SO/iYhjf3tCcPe6fEVGRJE9955xLQnE8I5 0u5yd6o0m3AXdLzZbXcOjidC5QcIctJBCK6Ym21FIqILM43HroDA/2aic364WfLhysL7AC rvDXsGLaHXRMNXdCDwDiOLg424UvO556mFAr3Kp3qoaefrUP7zxMNhEsfzJwSC0Gm7KkI6 hz4L9qeY1xS804ZJ0ZAbZhBJGhpqGutjmkaqYgXjC2YHVvMqBJJJdmxSDC34cQ== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4P1rrS3yCVzcLX; Wed, 25 Jan 2023 04:46:00 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 30P4k0Rn053408; Wed, 25 Jan 2023 04:46:00 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 30P4k0YH053407; Wed, 25 Jan 2023 04:46:00 GMT (envelope-from git) Date: Wed, 25 Jan 2023 04:46:00 GMT Message-Id: <202301250446.30P4k0YH053407@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Warner Losh Subject: git: b02419fc409c - stable/13 - Revert "mips: remove saf1761" List-Id: Commits to the stable branches of the FreeBSD src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-branches List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-branches@freebsd.org X-BeenThere: dev-commits-src-branches@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: imp X-Git-Repository: src X-Git-Refname: refs/heads/stable/13 X-Git-Reftype: branch X-Git-Commit: b02419fc409c4857ef263b30f823674c6f6d834e Auto-Submitted: auto-generated X-ThisMailContainsUnwantedMimeParts: N The branch stable/13 has been updated by imp: URL: https://cgit.FreeBSD.org/src/commit/?id=b02419fc409c4857ef263b30f823674c6f6d834e commit b02419fc409c4857ef263b30f823674c6f6d834e Author: Warner Losh AuthorDate: 2023-01-25 04:00:23 +0000 Commit: Warner Losh 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 + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define USB_DEBUG_VAR saf1761_otg_debug + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#endif /* USB_GLOBAL_INCLUDE_FILE */ + +#include +#include + +#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 ***