1f9f848faSopenharmony_ci/*- 2f9f848faSopenharmony_ci * SPDX-License-Identifier: BSD-2-Clause 3f9f848faSopenharmony_ci * 4f9f848faSopenharmony_ci * Copyright (c) 2010-2022 Hans Petter Selasky 5f9f848faSopenharmony_ci * 6f9f848faSopenharmony_ci * Redistribution and use in source and binary forms, with or without 7f9f848faSopenharmony_ci * modification, are permitted provided that the following conditions 8f9f848faSopenharmony_ci * are met: 9f9f848faSopenharmony_ci * 1. Redistributions of source code must retain the above copyright 10f9f848faSopenharmony_ci * notice, this list of conditions and the following disclaimer. 11f9f848faSopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright 12f9f848faSopenharmony_ci * notice, this list of conditions and the following disclaimer in the 13f9f848faSopenharmony_ci * documentation and/or other materials provided with the distribution. 14f9f848faSopenharmony_ci * 15f9f848faSopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16f9f848faSopenharmony_ci * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17f9f848faSopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18f9f848faSopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19f9f848faSopenharmony_ci * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20f9f848faSopenharmony_ci * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21f9f848faSopenharmony_ci * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22f9f848faSopenharmony_ci * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23f9f848faSopenharmony_ci * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24f9f848faSopenharmony_ci * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25f9f848faSopenharmony_ci * SUCH DAMAGE. 26f9f848faSopenharmony_ci */ 27f9f848faSopenharmony_ci 28f9f848faSopenharmony_ci/* 29f9f848faSopenharmony_ci * USB eXtensible Host Controller Interface, a.k.a. USB 3.0 controller. 30f9f848faSopenharmony_ci * 31f9f848faSopenharmony_ci * The XHCI 1.0 spec can be found at 32f9f848faSopenharmony_ci * http://www.intel.com/technology/usb/download/xHCI_Specification_for_USB.pdf 33f9f848faSopenharmony_ci * and the USB 3.0 spec at 34f9f848faSopenharmony_ci * http://www.usb.org/developers/docs/usb_30_spec_060910.zip 35f9f848faSopenharmony_ci */ 36f9f848faSopenharmony_ci 37f9f848faSopenharmony_ci/* 38f9f848faSopenharmony_ci * A few words about the design implementation: This driver emulates 39f9f848faSopenharmony_ci * the concept about TDs which is found in EHCI specification. This 40f9f848faSopenharmony_ci * way we achieve that the USB controller drivers look similar to 41f9f848faSopenharmony_ci * eachother which makes it easier to understand the code. 42f9f848faSopenharmony_ci */ 43f9f848faSopenharmony_ci 44f9f848faSopenharmony_ci#include "implementation/global_implementation.h" 45f9f848faSopenharmony_ci#include "controller/xhci.h" 46f9f848faSopenharmony_ci#include "controller/xhcireg.h" 47f9f848faSopenharmony_ci 48f9f848faSopenharmony_ci#define XHCI_BUS2SC(bus) \ 49f9f848faSopenharmony_ci ((struct xhci_softc *)(((uint8_t *)(bus)) - \ 50f9f848faSopenharmony_ci ((uint8_t *)&(((struct xhci_softc *)0)->sc_bus)))) 51f9f848faSopenharmony_ci 52f9f848faSopenharmony_cistatic int xhcistreams; 53f9f848faSopenharmony_ci 54f9f848faSopenharmony_ci#ifdef USB_DEBUG 55f9f848faSopenharmony_cistatic int xhcidebug = 20; 56f9f848faSopenharmony_cistatic int xhciroute = 0; 57f9f848faSopenharmony_cistatic int xhcipolling = 0; 58f9f848faSopenharmony_cistatic int xhcidma32 = 0; 59f9f848faSopenharmony_cistatic int xhcictlstep = 0; 60f9f848faSopenharmony_ci#else 61f9f848faSopenharmony_ci#define xhciroute 0 62f9f848faSopenharmony_ci#define xhcidma32 0 63f9f848faSopenharmony_ci#define xhcictlstep 0 64f9f848faSopenharmony_ci#endif 65f9f848faSopenharmony_ci 66f9f848faSopenharmony_ci#undef USB_DEBUG_VAR 67f9f848faSopenharmony_ci#define USB_DEBUG_VAR xhcidebug 68f9f848faSopenharmony_ci 69f9f848faSopenharmony_ci#ifdef LOSCFG_USB_DEBUG 70f9f848faSopenharmony_cistatic int xhcidebug = 0; 71f9f848faSopenharmony_ci#endif 72f9f848faSopenharmony_ci 73f9f848faSopenharmony_ci 74f9f848faSopenharmony_ci#define XHCI_INTR_ENDPT 1 75f9f848faSopenharmony_ci 76f9f848faSopenharmony_ci#define XHCI_DO_CMD_TIMEOUT 1000 77f9f848faSopenharmony_ci 78f9f848faSopenharmony_cistruct xhci_std_temp { 79f9f848faSopenharmony_ci struct xhci_softc *sc; 80f9f848faSopenharmony_ci struct usb_page_cache *pc; 81f9f848faSopenharmony_ci struct xhci_td *td; 82f9f848faSopenharmony_ci struct xhci_td *td_next; 83f9f848faSopenharmony_ci uint32_t len; 84f9f848faSopenharmony_ci uint32_t offset; 85f9f848faSopenharmony_ci uint32_t max_packet_size; 86f9f848faSopenharmony_ci uint32_t average; 87f9f848faSopenharmony_ci uint16_t isoc_delta; 88f9f848faSopenharmony_ci uint16_t isoc_frame; 89f9f848faSopenharmony_ci uint8_t shortpkt; 90f9f848faSopenharmony_ci uint8_t multishort; 91f9f848faSopenharmony_ci uint8_t last_frame; 92f9f848faSopenharmony_ci uint8_t trb_type; 93f9f848faSopenharmony_ci uint8_t direction; 94f9f848faSopenharmony_ci uint8_t tbc; 95f9f848faSopenharmony_ci uint8_t tlbpc; 96f9f848faSopenharmony_ci uint8_t step_td; 97f9f848faSopenharmony_ci uint8_t do_isoc_sync; 98f9f848faSopenharmony_ci}; 99f9f848faSopenharmony_ci 100f9f848faSopenharmony_cistatic void xhci_do_poll(struct usb_bus *); 101f9f848faSopenharmony_cistatic void xhci_device_done(struct usb_xfer *, usb_error_t); 102f9f848faSopenharmony_cistatic void xhci_root_intr(struct xhci_softc *); 103f9f848faSopenharmony_cistatic void xhci_free_device_ext(struct usb_device *); 104f9f848faSopenharmony_cistatic struct xhci_endpoint_ext *xhci_get_endpoint_ext(struct usb_device *, 105f9f848faSopenharmony_ci struct usb_endpoint_descriptor *); 106f9f848faSopenharmony_cistatic usb_proc_callback_t xhci_configure_msg; 107f9f848faSopenharmony_cistatic usb_error_t xhci_configure_device(struct usb_device *); 108f9f848faSopenharmony_cistatic usb_error_t xhci_configure_endpoint(struct usb_device *, 109f9f848faSopenharmony_ci struct usb_endpoint_descriptor *, struct xhci_endpoint_ext *, 110f9f848faSopenharmony_ci uint16_t, uint8_t, uint8_t, uint8_t, uint16_t, uint16_t, 111f9f848faSopenharmony_ci uint8_t); 112f9f848faSopenharmony_cistatic usb_error_t xhci_configure_mask(struct usb_device *, 113f9f848faSopenharmony_ci uint32_t, uint8_t); 114f9f848faSopenharmony_cistatic usb_error_t xhci_cmd_evaluate_ctx(struct xhci_softc *, 115f9f848faSopenharmony_ci uint64_t, uint8_t); 116f9f848faSopenharmony_cistatic void xhci_endpoint_doorbell(struct usb_xfer *); 117f9f848faSopenharmony_cistatic void xhci_ctx_set_le32(struct xhci_softc *sc, volatile uint32_t *ptr, uint32_t val); 118f9f848faSopenharmony_cistatic uint32_t xhci_ctx_get_le32(struct xhci_softc *sc, volatile uint32_t *ptr); 119f9f848faSopenharmony_cistatic void xhci_ctx_set_le64(struct xhci_softc *sc, volatile uint64_t *ptr, uint64_t val); 120f9f848faSopenharmony_ci#ifdef USB_DEBUG 121f9f848faSopenharmony_cistatic uint64_t xhci_ctx_get_le64(struct xhci_softc *sc, volatile uint64_t *ptr); 122f9f848faSopenharmony_ci#endif 123f9f848faSopenharmony_ci 124f9f848faSopenharmony_ciextern struct usb_bus_methods xhci_bus_methods; 125f9f848faSopenharmony_ci 126f9f848faSopenharmony_ci#ifdef USB_DEBUG 127f9f848faSopenharmony_cistatic void 128f9f848faSopenharmony_cixhci_dump_trb(struct xhci_trb *trb) 129f9f848faSopenharmony_ci{ 130f9f848faSopenharmony_ci DPRINTFN(5, "trb = %p\n", trb); 131f9f848faSopenharmony_ci DPRINTFN(5, "qwTrb0 = 0x%016llx\n", (long long)le64toh(trb->qwTrb0)); 132f9f848faSopenharmony_ci DPRINTFN(5, "dwTrb2 = 0x%08x\n", le32toh(trb->dwTrb2)); 133f9f848faSopenharmony_ci DPRINTFN(5, "dwTrb3 = 0x%08x\n", le32toh(trb->dwTrb3)); 134f9f848faSopenharmony_ci} 135f9f848faSopenharmony_ci 136f9f848faSopenharmony_cistatic void 137f9f848faSopenharmony_cixhci_dump_endpoint(struct xhci_softc *sc, struct xhci_endp_ctx *pep) 138f9f848faSopenharmony_ci{ 139f9f848faSopenharmony_ci DPRINTFN(5, "pep = %p\n", pep); 140f9f848faSopenharmony_ci DPRINTFN(5, "dwEpCtx0=0x%08x\n", xhci_ctx_get_le32(sc, &pep->dwEpCtx0)); 141f9f848faSopenharmony_ci DPRINTFN(5, "dwEpCtx1=0x%08x\n", xhci_ctx_get_le32(sc, &pep->dwEpCtx1)); 142f9f848faSopenharmony_ci DPRINTFN(5, "qwEpCtx2=0x%016llx\n", (long long)xhci_ctx_get_le64(sc, &pep->qwEpCtx2)); 143f9f848faSopenharmony_ci DPRINTFN(5, "dwEpCtx4=0x%08x\n", xhci_ctx_get_le32(sc, &pep->dwEpCtx4)); 144f9f848faSopenharmony_ci DPRINTFN(5, "dwEpCtx5=0x%08x\n", xhci_ctx_get_le32(sc, &pep->dwEpCtx5)); 145f9f848faSopenharmony_ci DPRINTFN(5, "dwEpCtx6=0x%08x\n", xhci_ctx_get_le32(sc, &pep->dwEpCtx6)); 146f9f848faSopenharmony_ci DPRINTFN(5, "dwEpCtx7=0x%08x\n", xhci_ctx_get_le32(sc, &pep->dwEpCtx7)); 147f9f848faSopenharmony_ci} 148f9f848faSopenharmony_ci 149f9f848faSopenharmony_cistatic void 150f9f848faSopenharmony_cixhci_dump_device(struct xhci_softc *sc, struct xhci_slot_ctx *psl) 151f9f848faSopenharmony_ci{ 152f9f848faSopenharmony_ci DPRINTFN(5, "psl = %p\n", psl); 153f9f848faSopenharmony_ci DPRINTFN(5, "dwSctx0=0x%08x\n", xhci_ctx_get_le32(sc, &psl->dwSctx0)); 154f9f848faSopenharmony_ci DPRINTFN(5, "dwSctx1=0x%08x\n", xhci_ctx_get_le32(sc, &psl->dwSctx1)); 155f9f848faSopenharmony_ci DPRINTFN(5, "dwSctx2=0x%08x\n", xhci_ctx_get_le32(sc, &psl->dwSctx2)); 156f9f848faSopenharmony_ci DPRINTFN(5, "dwSctx3=0x%08x\n", xhci_ctx_get_le32(sc, &psl->dwSctx3)); 157f9f848faSopenharmony_ci} 158f9f848faSopenharmony_ci#endif 159f9f848faSopenharmony_ci 160f9f848faSopenharmony_ciuint8_t 161f9f848faSopenharmony_cixhci_use_polling(void) 162f9f848faSopenharmony_ci{ 163f9f848faSopenharmony_ci#ifdef USB_DEBUG 164f9f848faSopenharmony_ci return (xhcipolling != 0); 165f9f848faSopenharmony_ci#else 166f9f848faSopenharmony_ci return (0); 167f9f848faSopenharmony_ci#endif 168f9f848faSopenharmony_ci} 169f9f848faSopenharmony_ci 170f9f848faSopenharmony_cistatic void 171f9f848faSopenharmony_cixhci_iterate_hw_softc(struct usb_bus *bus, usb_bus_mem_sub_cb_t *cb) 172f9f848faSopenharmony_ci{ 173f9f848faSopenharmony_ci struct xhci_softc *sc = XHCI_BUS2SC(bus); 174f9f848faSopenharmony_ci uint8_t i; 175f9f848faSopenharmony_ci 176f9f848faSopenharmony_ci cb(bus, &sc->sc_hw.root_pc, &sc->sc_hw.root_pg, 177f9f848faSopenharmony_ci sizeof(struct xhci_hw_root), XHCI_PAGE_SIZE); 178f9f848faSopenharmony_ci 179f9f848faSopenharmony_ci cb(bus, &sc->sc_hw.ctx_pc, &sc->sc_hw.ctx_pg, 180f9f848faSopenharmony_ci sizeof(struct xhci_dev_ctx_addr), XHCI_PAGE_SIZE); 181f9f848faSopenharmony_ci 182f9f848faSopenharmony_ci for (i = 0; i != sc->sc_noscratch; i++) { 183f9f848faSopenharmony_ci cb(bus, &sc->sc_hw.scratch_pc[i], &sc->sc_hw.scratch_pg[i], 184f9f848faSopenharmony_ci XHCI_PAGE_SIZE, XHCI_PAGE_SIZE); 185f9f848faSopenharmony_ci } 186f9f848faSopenharmony_ci} 187f9f848faSopenharmony_ci 188f9f848faSopenharmony_cistatic void 189f9f848faSopenharmony_cixhci_ctx_set_le32(struct xhci_softc *sc, volatile uint32_t *ptr, uint32_t val) 190f9f848faSopenharmony_ci{ 191f9f848faSopenharmony_ci uint32_t offset; 192f9f848faSopenharmony_ci if (sc->sc_ctx_is_64_byte) { 193f9f848faSopenharmony_ci /* exploit the fact that our structures are XHCI_PAGE_SIZE aligned */ 194f9f848faSopenharmony_ci /* all contexts are initially 32-bytes */ 195f9f848faSopenharmony_ci offset = ((uintptr_t)ptr) & ((XHCI_PAGE_SIZE - 1) & ~(31U)); 196f9f848faSopenharmony_ci ptr = (volatile uint32_t *)(((volatile uint8_t *)ptr) + offset); 197f9f848faSopenharmony_ci } 198f9f848faSopenharmony_ci *ptr = htole32(val); 199f9f848faSopenharmony_ci} 200f9f848faSopenharmony_ci 201f9f848faSopenharmony_cistatic uint32_t 202f9f848faSopenharmony_cixhci_ctx_get_le32(struct xhci_softc *sc, volatile uint32_t *ptr) 203f9f848faSopenharmony_ci{ 204f9f848faSopenharmony_ci uint32_t offset; 205f9f848faSopenharmony_ci if (sc->sc_ctx_is_64_byte) { 206f9f848faSopenharmony_ci /* exploit the fact that our structures are XHCI_PAGE_SIZE aligned */ 207f9f848faSopenharmony_ci /* all contexts are initially 32-bytes */ 208f9f848faSopenharmony_ci offset = ((uintptr_t)ptr) & ((XHCI_PAGE_SIZE - 1) & ~(31U)); 209f9f848faSopenharmony_ci ptr = (volatile uint32_t *)(((volatile uint8_t *)ptr) + offset); 210f9f848faSopenharmony_ci } 211f9f848faSopenharmony_ci return (le32toh(*ptr)); 212f9f848faSopenharmony_ci} 213f9f848faSopenharmony_ci 214f9f848faSopenharmony_cistatic void 215f9f848faSopenharmony_cixhci_ctx_set_le64(struct xhci_softc *sc, volatile uint64_t *ptr, uint64_t val) 216f9f848faSopenharmony_ci{ 217f9f848faSopenharmony_ci uint32_t offset; 218f9f848faSopenharmony_ci if (sc->sc_ctx_is_64_byte) { 219f9f848faSopenharmony_ci /* exploit the fact that our structures are XHCI_PAGE_SIZE aligned */ 220f9f848faSopenharmony_ci /* all contexts are initially 32-bytes */ 221f9f848faSopenharmony_ci offset = ((uintptr_t)ptr) & ((XHCI_PAGE_SIZE - 1) & ~(31U)); 222f9f848faSopenharmony_ci ptr = (volatile uint64_t *)(((volatile uint8_t *)ptr) + offset); 223f9f848faSopenharmony_ci } 224f9f848faSopenharmony_ci *ptr = htole64(val); 225f9f848faSopenharmony_ci} 226f9f848faSopenharmony_ci 227f9f848faSopenharmony_ci#ifdef USB_DEBUG 228f9f848faSopenharmony_cistatic uint64_t 229f9f848faSopenharmony_cixhci_ctx_get_le64(struct xhci_softc *sc, volatile uint64_t *ptr) 230f9f848faSopenharmony_ci{ 231f9f848faSopenharmony_ci uint32_t offset; 232f9f848faSopenharmony_ci if (sc->sc_ctx_is_64_byte) { 233f9f848faSopenharmony_ci /* exploit the fact that our structures are XHCI_PAGE_SIZE aligned */ 234f9f848faSopenharmony_ci /* all contexts are initially 32-bytes */ 235f9f848faSopenharmony_ci offset = ((uintptr_t)ptr) & ((XHCI_PAGE_SIZE - 1) & ~(31U)); 236f9f848faSopenharmony_ci ptr = (volatile uint64_t *)(((volatile uint8_t *)ptr) + offset); 237f9f848faSopenharmony_ci } 238f9f848faSopenharmony_ci return (le64toh(*ptr)); 239f9f848faSopenharmony_ci} 240f9f848faSopenharmony_ci#endif 241f9f848faSopenharmony_ci 242f9f848faSopenharmony_cistatic int 243f9f848faSopenharmony_cixhci_reset_command_queue_locked(struct xhci_softc *sc) 244f9f848faSopenharmony_ci{ 245f9f848faSopenharmony_ci struct usb_page_search buf_res; 246f9f848faSopenharmony_ci struct xhci_hw_root *phwr; 247f9f848faSopenharmony_ci uint64_t addr; 248f9f848faSopenharmony_ci uint32_t temp; 249f9f848faSopenharmony_ci 250f9f848faSopenharmony_ci DPRINTF("\n"); 251f9f848faSopenharmony_ci 252f9f848faSopenharmony_ci temp = XREAD4(sc, oper, XHCI_CRCR_LO); 253f9f848faSopenharmony_ci if (temp & XHCI_CRCR_LO_CRR) { 254f9f848faSopenharmony_ci DPRINTF("Command ring running\n"); 255f9f848faSopenharmony_ci temp &= ~(XHCI_CRCR_LO_CS | XHCI_CRCR_LO_CA); 256f9f848faSopenharmony_ci 257f9f848faSopenharmony_ci /* 258f9f848faSopenharmony_ci * Try to abort the last command as per section 259f9f848faSopenharmony_ci * 4.6.1.2 "Aborting a Command" of the XHCI 260f9f848faSopenharmony_ci * specification: 261f9f848faSopenharmony_ci */ 262f9f848faSopenharmony_ci 263f9f848faSopenharmony_ci /* stop and cancel */ 264f9f848faSopenharmony_ci XWRITE4(sc, oper, XHCI_CRCR_LO, temp | XHCI_CRCR_LO_CS); 265f9f848faSopenharmony_ci XWRITE4(sc, oper, XHCI_CRCR_HI, 0); 266f9f848faSopenharmony_ci 267f9f848faSopenharmony_ci XWRITE4(sc, oper, XHCI_CRCR_LO, temp | XHCI_CRCR_LO_CA); 268f9f848faSopenharmony_ci XWRITE4(sc, oper, XHCI_CRCR_HI, 0); 269f9f848faSopenharmony_ci 270f9f848faSopenharmony_ci /* wait 250ms */ 271f9f848faSopenharmony_ci usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 4); 272f9f848faSopenharmony_ci 273f9f848faSopenharmony_ci /* check if command ring is still running */ 274f9f848faSopenharmony_ci temp = XREAD4(sc, oper, XHCI_CRCR_LO); 275f9f848faSopenharmony_ci if (temp & XHCI_CRCR_LO_CRR) { 276f9f848faSopenharmony_ci DPRINTF("Comand ring still running\n"); 277f9f848faSopenharmony_ci return (USB_ERR_IOERROR); 278f9f848faSopenharmony_ci } 279f9f848faSopenharmony_ci } 280f9f848faSopenharmony_ci 281f9f848faSopenharmony_ci /* reset command ring */ 282f9f848faSopenharmony_ci sc->sc_command_ccs = 1; 283f9f848faSopenharmony_ci sc->sc_command_idx = 0; 284f9f848faSopenharmony_ci 285f9f848faSopenharmony_ci usbd_get_page(&sc->sc_hw.root_pc, 0, &buf_res); 286f9f848faSopenharmony_ci 287f9f848faSopenharmony_ci /* set up command ring control base address */ 288f9f848faSopenharmony_ci addr = buf_res.physaddr; 289f9f848faSopenharmony_ci phwr = buf_res.buffer; 290f9f848faSopenharmony_ci addr += __offsetof(struct xhci_hw_root, hwr_commands[0]); 291f9f848faSopenharmony_ci 292f9f848faSopenharmony_ci DPRINTF("CRCR=0x%016llx\n", (unsigned long long)addr); 293f9f848faSopenharmony_ci 294f9f848faSopenharmony_ci (void)memset_s(phwr->hwr_commands, sizeof(phwr->hwr_commands), 0, sizeof(phwr->hwr_commands)); 295f9f848faSopenharmony_ci phwr->hwr_commands[XHCI_MAX_COMMANDS - 1].qwTrb0 = htole64(addr); 296f9f848faSopenharmony_ci 297f9f848faSopenharmony_ci usb_pc_cpu_flush(&sc->sc_hw.root_pc); 298f9f848faSopenharmony_ci 299f9f848faSopenharmony_ci XWRITE4(sc, oper, XHCI_CRCR_LO, ((uint32_t)addr) | XHCI_CRCR_LO_RCS); 300f9f848faSopenharmony_ci XWRITE4(sc, oper, XHCI_CRCR_HI, (uint32_t)(addr >> 32)); 301f9f848faSopenharmony_ci 302f9f848faSopenharmony_ci return (0); 303f9f848faSopenharmony_ci} 304f9f848faSopenharmony_ci 305f9f848faSopenharmony_ciusb_error_t 306f9f848faSopenharmony_cixhci_start_controller(struct xhci_softc *sc) 307f9f848faSopenharmony_ci{ 308f9f848faSopenharmony_ci struct usb_page_search buf_res; 309f9f848faSopenharmony_ci struct xhci_hw_root *phwr; 310f9f848faSopenharmony_ci struct xhci_dev_ctx_addr *pdctxa; 311f9f848faSopenharmony_ci uint64_t addr; 312f9f848faSopenharmony_ci uint32_t temp; 313f9f848faSopenharmony_ci uint16_t i; 314f9f848faSopenharmony_ci int ret; 315f9f848faSopenharmony_ci 316f9f848faSopenharmony_ci DPRINTF("\n"); 317f9f848faSopenharmony_ci 318f9f848faSopenharmony_ci sc->sc_event_ccs = 1; 319f9f848faSopenharmony_ci sc->sc_event_idx = 0; 320f9f848faSopenharmony_ci sc->sc_command_ccs = 1; 321f9f848faSopenharmony_ci sc->sc_command_idx = 0; 322f9f848faSopenharmony_ci 323f9f848faSopenharmony_ci /* Reset controller */ 324f9f848faSopenharmony_ci XWRITE4(sc, oper, XHCI_USBCMD, XHCI_CMD_HCRST); 325f9f848faSopenharmony_ci 326f9f848faSopenharmony_ci for (i = 0; i != 100; i++) { 327f9f848faSopenharmony_ci usb_pause_mtx(NULL, hz / 100); 328f9f848faSopenharmony_ci temp = (XREAD4(sc, oper, XHCI_USBCMD) & XHCI_CMD_HCRST) | 329f9f848faSopenharmony_ci (XREAD4(sc, oper, XHCI_USBSTS) & XHCI_STS_CNR); 330f9f848faSopenharmony_ci if (!temp) 331f9f848faSopenharmony_ci break; 332f9f848faSopenharmony_ci } 333f9f848faSopenharmony_ci 334f9f848faSopenharmony_ci if (temp) { 335f9f848faSopenharmony_ci device_printf(sc->sc_bus.parent, "Controller " 336f9f848faSopenharmony_ci "reset timeout.\n"); 337f9f848faSopenharmony_ci return (USB_ERR_IOERROR); 338f9f848faSopenharmony_ci } 339f9f848faSopenharmony_ci 340f9f848faSopenharmony_ci /* set up number of device slots */ 341f9f848faSopenharmony_ci DPRINTF("CONFIG=0x%08x -> 0x%08x\n", 342f9f848faSopenharmony_ci XREAD4(sc, oper, XHCI_CONFIG), sc->sc_noslot); 343f9f848faSopenharmony_ci 344f9f848faSopenharmony_ci XWRITE4(sc, oper, XHCI_CONFIG, sc->sc_noslot); 345f9f848faSopenharmony_ci 346f9f848faSopenharmony_ci temp = XREAD4(sc, oper, XHCI_USBSTS); 347f9f848faSopenharmony_ci 348f9f848faSopenharmony_ci /* clear interrupts */ 349f9f848faSopenharmony_ci XWRITE4(sc, oper, XHCI_USBSTS, temp); 350f9f848faSopenharmony_ci /* disable all device notifications */ 351f9f848faSopenharmony_ci XWRITE4(sc, oper, XHCI_DNCTRL, 0); 352f9f848faSopenharmony_ci 353f9f848faSopenharmony_ci /* set up device context base address */ 354f9f848faSopenharmony_ci usbd_get_page(&sc->sc_hw.ctx_pc, 0, &buf_res); 355f9f848faSopenharmony_ci pdctxa = buf_res.buffer; 356f9f848faSopenharmony_ci ret = memset_s(pdctxa, USB_PAGE_SIZE, 0, sizeof(*pdctxa)); 357f9f848faSopenharmony_ci if (ret != EOK) { 358f9f848faSopenharmony_ci usb_err("memset_s failed, ret:%d\n", ret); 359f9f848faSopenharmony_ci return (USB_ERR_BAD_BUFSIZE); 360f9f848faSopenharmony_ci } 361f9f848faSopenharmony_ci 362f9f848faSopenharmony_ci addr = buf_res.physaddr; 363f9f848faSopenharmony_ci addr += __offsetof(struct xhci_dev_ctx_addr, qwSpBufPtr[0]); 364f9f848faSopenharmony_ci 365f9f848faSopenharmony_ci /* slot 0 points to the table of scratchpad pointers */ 366f9f848faSopenharmony_ci pdctxa->qwBaaDevCtxAddr[0] = htole64(addr); 367f9f848faSopenharmony_ci 368f9f848faSopenharmony_ci for (i = 0; i != sc->sc_noscratch; i++) { 369f9f848faSopenharmony_ci struct usb_page_search buf_scp; 370f9f848faSopenharmony_ci usbd_get_page(&sc->sc_hw.scratch_pc[i], 0, &buf_scp); 371f9f848faSopenharmony_ci pdctxa->qwSpBufPtr[i] = htole64((uint64_t)buf_scp.physaddr); 372f9f848faSopenharmony_ci } 373f9f848faSopenharmony_ci 374f9f848faSopenharmony_ci addr = buf_res.physaddr; 375f9f848faSopenharmony_ci 376f9f848faSopenharmony_ci XWRITE4(sc, oper, XHCI_DCBAAP_LO, (uint32_t)addr); 377f9f848faSopenharmony_ci XWRITE4(sc, oper, XHCI_DCBAAP_HI, (uint32_t)(addr >> 32)); 378f9f848faSopenharmony_ci XWRITE4(sc, oper, XHCI_DCBAAP_LO, (uint32_t)addr); 379f9f848faSopenharmony_ci XWRITE4(sc, oper, XHCI_DCBAAP_HI, (uint32_t)(addr >> 32)); 380f9f848faSopenharmony_ci 381f9f848faSopenharmony_ci /* set up event table size */ 382f9f848faSopenharmony_ci DPRINTF("ERSTSZ=0x%08x -> 0x%08x\n", 383f9f848faSopenharmony_ci XREAD4(sc, runt, XHCI_ERSTSZ(0)), sc->sc_erst_max); 384f9f848faSopenharmony_ci 385f9f848faSopenharmony_ci XWRITE4(sc, runt, XHCI_ERSTSZ(0), XHCI_ERSTS_SET(sc->sc_erst_max)); 386f9f848faSopenharmony_ci 387f9f848faSopenharmony_ci /* set up interrupt rate */ 388f9f848faSopenharmony_ci XWRITE4(sc, runt, XHCI_IMOD(0), sc->sc_imod_default); 389f9f848faSopenharmony_ci 390f9f848faSopenharmony_ci usbd_get_page(&sc->sc_hw.root_pc, 0, &buf_res); 391f9f848faSopenharmony_ci 392f9f848faSopenharmony_ci phwr = buf_res.buffer; 393f9f848faSopenharmony_ci addr = buf_res.physaddr; 394f9f848faSopenharmony_ci addr += __offsetof(struct xhci_hw_root, hwr_events[0]); 395f9f848faSopenharmony_ci 396f9f848faSopenharmony_ci /* reset hardware root structure */ 397f9f848faSopenharmony_ci ret = memset_s(phwr, USB_PAGE_SIZE, 0, sizeof(*phwr)); 398f9f848faSopenharmony_ci if (ret != EOK) { 399f9f848faSopenharmony_ci usb_err("memset_s failed, ret:%d\n", ret); 400f9f848faSopenharmony_ci return (USB_ERR_BAD_BUFSIZE); 401f9f848faSopenharmony_ci } 402f9f848faSopenharmony_ci 403f9f848faSopenharmony_ci phwr->hwr_ring_seg[0].qwEvrsTablePtr = htole64(addr); 404f9f848faSopenharmony_ci phwr->hwr_ring_seg[0].dwEvrsTableSize = htole32(XHCI_MAX_EVENTS); 405f9f848faSopenharmony_ci 406f9f848faSopenharmony_ci DPRINTF("ERDP(0)=0x%016llx\n", (unsigned long long)addr); 407f9f848faSopenharmony_ci 408f9f848faSopenharmony_ci XWRITE4(sc, runt, XHCI_ERDP_LO(0), (uint32_t)addr); 409f9f848faSopenharmony_ci XWRITE4(sc, runt, XHCI_ERDP_HI(0), (uint32_t)(addr >> 32)); 410f9f848faSopenharmony_ci 411f9f848faSopenharmony_ci addr = buf_res.physaddr; 412f9f848faSopenharmony_ci 413f9f848faSopenharmony_ci DPRINTF("ERSTBA(0)=0x%016llx\n", (unsigned long long)addr); 414f9f848faSopenharmony_ci 415f9f848faSopenharmony_ci XWRITE4(sc, runt, XHCI_ERSTBA_LO(0), (uint32_t)addr); 416f9f848faSopenharmony_ci XWRITE4(sc, runt, XHCI_ERSTBA_HI(0), (uint32_t)(addr >> 32)); 417f9f848faSopenharmony_ci 418f9f848faSopenharmony_ci /* set up interrupter registers */ 419f9f848faSopenharmony_ci temp = XREAD4(sc, runt, XHCI_IMAN(0)); 420f9f848faSopenharmony_ci temp |= XHCI_IMAN_INTR_ENA; 421f9f848faSopenharmony_ci XWRITE4(sc, runt, XHCI_IMAN(0), temp); 422f9f848faSopenharmony_ci 423f9f848faSopenharmony_ci /* set up command ring control base address */ 424f9f848faSopenharmony_ci addr = buf_res.physaddr; 425f9f848faSopenharmony_ci addr += __offsetof(struct xhci_hw_root, hwr_commands[0]); 426f9f848faSopenharmony_ci 427f9f848faSopenharmony_ci DPRINTF("CRCR=0x%016llx\n", (unsigned long long)addr); 428f9f848faSopenharmony_ci 429f9f848faSopenharmony_ci XWRITE4(sc, oper, XHCI_CRCR_LO, ((uint32_t)addr) | XHCI_CRCR_LO_RCS); 430f9f848faSopenharmony_ci XWRITE4(sc, oper, XHCI_CRCR_HI, (uint32_t)(addr >> 32)); 431f9f848faSopenharmony_ci 432f9f848faSopenharmony_ci phwr->hwr_commands[XHCI_MAX_COMMANDS - 1].qwTrb0 = htole64(addr); 433f9f848faSopenharmony_ci 434f9f848faSopenharmony_ci usb_bus_mem_flush_all(&sc->sc_bus, &xhci_iterate_hw_softc); 435f9f848faSopenharmony_ci 436f9f848faSopenharmony_ci /* Go! */ 437f9f848faSopenharmony_ci XWRITE4(sc, oper, XHCI_USBCMD, XHCI_CMD_RS | 438f9f848faSopenharmony_ci XHCI_CMD_INTE | XHCI_CMD_HSEE); 439f9f848faSopenharmony_ci 440f9f848faSopenharmony_ci for (i = 0; i != 100; i++) { 441f9f848faSopenharmony_ci usb_pause_mtx(NULL, hz / 100); 442f9f848faSopenharmony_ci temp = XREAD4(sc, oper, XHCI_USBSTS) & XHCI_STS_HCH; 443f9f848faSopenharmony_ci if (!temp) 444f9f848faSopenharmony_ci break; 445f9f848faSopenharmony_ci } 446f9f848faSopenharmony_ci if (temp) { 447f9f848faSopenharmony_ci XWRITE4(sc, oper, XHCI_USBCMD, 0); 448f9f848faSopenharmony_ci device_printf(sc->sc_bus.parent, "Run timeout.\n"); 449f9f848faSopenharmony_ci return (USB_ERR_IOERROR); 450f9f848faSopenharmony_ci } 451f9f848faSopenharmony_ci 452f9f848faSopenharmony_ci /* catch any lost interrupts */ 453f9f848faSopenharmony_ci xhci_do_poll(&sc->sc_bus); 454f9f848faSopenharmony_ci 455f9f848faSopenharmony_ci if (sc->sc_port_route != NULL) { 456f9f848faSopenharmony_ci /* Route all ports to the XHCI by default */ 457f9f848faSopenharmony_ci (void)sc->sc_port_route(sc->sc_bus.parent, 458f9f848faSopenharmony_ci ~xhciroute, xhciroute); 459f9f848faSopenharmony_ci } 460f9f848faSopenharmony_ci return (USB_ERR_NORMAL_COMPLETION); 461f9f848faSopenharmony_ci} 462f9f848faSopenharmony_ci 463f9f848faSopenharmony_ciusb_error_t 464f9f848faSopenharmony_cixhci_halt_controller(struct xhci_softc *sc) 465f9f848faSopenharmony_ci{ 466f9f848faSopenharmony_ci uint32_t temp; 467f9f848faSopenharmony_ci uint16_t i; 468f9f848faSopenharmony_ci 469f9f848faSopenharmony_ci DPRINTF("\n"); 470f9f848faSopenharmony_ci 471f9f848faSopenharmony_ci sc->sc_capa_off = 0; 472f9f848faSopenharmony_ci sc->sc_oper_off = XREAD1(sc, capa, XHCI_CAPLENGTH); 473f9f848faSopenharmony_ci sc->sc_runt_off = XREAD4(sc, capa, XHCI_RTSOFF) & ~0xF; 474f9f848faSopenharmony_ci sc->sc_door_off = XREAD4(sc, capa, XHCI_DBOFF) & ~0x3; 475f9f848faSopenharmony_ci 476f9f848faSopenharmony_ci /* Halt controller */ 477f9f848faSopenharmony_ci XWRITE4(sc, oper, XHCI_USBCMD, 0); 478f9f848faSopenharmony_ci 479f9f848faSopenharmony_ci for (i = 0; i != 100; i++) { 480f9f848faSopenharmony_ci usb_pause_mtx(NULL, hz / 100); 481f9f848faSopenharmony_ci temp = XREAD4(sc, oper, XHCI_USBSTS) & XHCI_STS_HCH; 482f9f848faSopenharmony_ci if (temp) 483f9f848faSopenharmony_ci break; 484f9f848faSopenharmony_ci } 485f9f848faSopenharmony_ci 486f9f848faSopenharmony_ci if (!temp) { 487f9f848faSopenharmony_ci device_printf(sc->sc_bus.parent, "Controller halt timeout.\n"); 488f9f848faSopenharmony_ci return (USB_ERR_IOERROR); 489f9f848faSopenharmony_ci } 490f9f848faSopenharmony_ci return (USB_ERR_NORMAL_COMPLETION); 491f9f848faSopenharmony_ci} 492f9f848faSopenharmony_ci 493f9f848faSopenharmony_ciusb_error_t 494f9f848faSopenharmony_cixhci_reset_controller(struct xhci_softc *sc) 495f9f848faSopenharmony_ci{ 496f9f848faSopenharmony_ci uint32_t temp = 0; 497f9f848faSopenharmony_ci uint16_t i; 498f9f848faSopenharmony_ci 499f9f848faSopenharmony_ci DPRINTF("\n"); 500f9f848faSopenharmony_ci 501f9f848faSopenharmony_ci /* Reset controller */ 502f9f848faSopenharmony_ci XWRITE4(sc, oper, XHCI_USBCMD, XHCI_CMD_HCRST); 503f9f848faSopenharmony_ci 504f9f848faSopenharmony_ci for (i = 0; i != 100; i++) { 505f9f848faSopenharmony_ci usb_pause_mtx(NULL, hz / 100); 506f9f848faSopenharmony_ci temp = (XREAD4(sc, oper, XHCI_USBCMD) & XHCI_CMD_HCRST) | 507f9f848faSopenharmony_ci (XREAD4(sc, oper, XHCI_USBSTS) & XHCI_STS_CNR); 508f9f848faSopenharmony_ci if (!temp) 509f9f848faSopenharmony_ci break; 510f9f848faSopenharmony_ci } 511f9f848faSopenharmony_ci 512f9f848faSopenharmony_ci if (temp) { 513f9f848faSopenharmony_ci device_printf(sc->sc_bus.parent, "Controller " 514f9f848faSopenharmony_ci "reset timeout.\n"); 515f9f848faSopenharmony_ci return (USB_ERR_IOERROR); 516f9f848faSopenharmony_ci } 517f9f848faSopenharmony_ci return (USB_ERR_NORMAL_COMPLETION); 518f9f848faSopenharmony_ci} 519f9f848faSopenharmony_ci 520f9f848faSopenharmony_ciusb_error_t 521f9f848faSopenharmony_cixhci_init(struct xhci_softc *sc, device_t self, uint8_t dma32) 522f9f848faSopenharmony_ci{ 523f9f848faSopenharmony_ci uint32_t temp; 524f9f848faSopenharmony_ci 525f9f848faSopenharmony_ci DPRINTF("\n"); 526f9f848faSopenharmony_ci 527f9f848faSopenharmony_ci /* initialize some bus fields */ 528f9f848faSopenharmony_ci sc->sc_bus.parent = self; 529f9f848faSopenharmony_ci 530f9f848faSopenharmony_ci /* set the bus revision */ 531f9f848faSopenharmony_ci sc->sc_bus.usbrev = USB_REV_3_0; 532f9f848faSopenharmony_ci 533f9f848faSopenharmony_ci /* set up the bus struct */ 534f9f848faSopenharmony_ci sc->sc_bus.methods = &xhci_bus_methods; 535f9f848faSopenharmony_ci 536f9f848faSopenharmony_ci /* set up devices array */ 537f9f848faSopenharmony_ci sc->sc_bus.devices = sc->sc_devices; 538f9f848faSopenharmony_ci sc->sc_bus.devices_max = XHCI_MAX_DEVICES; 539f9f848faSopenharmony_ci 540f9f848faSopenharmony_ci /* set default cycle state in case of early interrupts */ 541f9f848faSopenharmony_ci sc->sc_event_ccs = 1; 542f9f848faSopenharmony_ci sc->sc_command_ccs = 1; 543f9f848faSopenharmony_ci 544f9f848faSopenharmony_ci /* set up bus space offsets */ 545f9f848faSopenharmony_ci sc->sc_capa_off = 0; 546f9f848faSopenharmony_ci sc->sc_oper_off = XREAD1(sc, capa, XHCI_CAPLENGTH); 547f9f848faSopenharmony_ci sc->sc_runt_off = XREAD4(sc, capa, XHCI_RTSOFF) & ~0x1F; 548f9f848faSopenharmony_ci sc->sc_door_off = XREAD4(sc, capa, XHCI_DBOFF) & ~0x3; 549f9f848faSopenharmony_ci 550f9f848faSopenharmony_ci DPRINTF("CAPLENGTH=0x%x\n", sc->sc_oper_off); 551f9f848faSopenharmony_ci DPRINTF("RUNTIMEOFFSET=0x%x\n", sc->sc_runt_off); 552f9f848faSopenharmony_ci DPRINTF("DOOROFFSET=0x%x\n", sc->sc_door_off); 553f9f848faSopenharmony_ci 554f9f848faSopenharmony_ci DPRINTF("xHCI version = 0x%04x\n", XREAD2(sc, capa, XHCI_HCIVERSION)); 555f9f848faSopenharmony_ci 556f9f848faSopenharmony_ci if (!(XREAD4(sc, oper, XHCI_PAGESIZE) & XHCI_PAGESIZE_4K)) { 557f9f848faSopenharmony_ci device_printf(sc->sc_bus.parent, "Controller does " 558f9f848faSopenharmony_ci "not support 4K page size.\n"); 559f9f848faSopenharmony_ci return (usb_error_t)(ENXIO); 560f9f848faSopenharmony_ci } 561f9f848faSopenharmony_ci 562f9f848faSopenharmony_ci temp = XREAD4(sc, capa, XHCI_HCSPARAMS0); 563f9f848faSopenharmony_ci 564f9f848faSopenharmony_ci DPRINTF("HCS0 = 0x%08x\n", temp); 565f9f848faSopenharmony_ci 566f9f848faSopenharmony_ci /* set up context size */ 567f9f848faSopenharmony_ci if (XHCI_HCS0_CSZ(temp)) { 568f9f848faSopenharmony_ci sc->sc_ctx_is_64_byte = 1; 569f9f848faSopenharmony_ci } else { 570f9f848faSopenharmony_ci sc->sc_ctx_is_64_byte = 0; 571f9f848faSopenharmony_ci } 572f9f848faSopenharmony_ci 573f9f848faSopenharmony_ci /* get DMA bits */ 574f9f848faSopenharmony_ci sc->sc_bus.dma_bits = (XHCI_HCS0_AC64(temp) && 575f9f848faSopenharmony_ci xhcidma32 == 0 && dma32 == 0) ? 64 : 32; 576f9f848faSopenharmony_ci 577f9f848faSopenharmony_ci device_printf(self, "%d bytes context size, %d-bit DMA\n", 578f9f848faSopenharmony_ci sc->sc_ctx_is_64_byte ? 64 : 32, (int)sc->sc_bus.dma_bits); 579f9f848faSopenharmony_ci 580f9f848faSopenharmony_ci temp = XREAD4(sc, capa, XHCI_HCSPARAMS1); 581f9f848faSopenharmony_ci 582f9f848faSopenharmony_ci /* get number of device slots */ 583f9f848faSopenharmony_ci sc->sc_noport = XHCI_HCS1_N_PORTS(temp); 584f9f848faSopenharmony_ci 585f9f848faSopenharmony_ci if (sc->sc_noport == 0) { 586f9f848faSopenharmony_ci device_printf(sc->sc_bus.parent, "Invalid number " 587f9f848faSopenharmony_ci "of ports: %u\n", sc->sc_noport); 588f9f848faSopenharmony_ci return (usb_error_t)(ENXIO); 589f9f848faSopenharmony_ci } 590f9f848faSopenharmony_ci 591f9f848faSopenharmony_ci sc->sc_noslot = XHCI_HCS1_DEVSLOT_MAX(temp); 592f9f848faSopenharmony_ci 593f9f848faSopenharmony_ci DPRINTF("Max slots: %u\n", sc->sc_noslot); 594f9f848faSopenharmony_ci 595f9f848faSopenharmony_ci if (sc->sc_noslot > XHCI_MAX_DEVICES) 596f9f848faSopenharmony_ci sc->sc_noslot = XHCI_MAX_DEVICES; 597f9f848faSopenharmony_ci 598f9f848faSopenharmony_ci temp = XREAD4(sc, capa, XHCI_HCSPARAMS2); 599f9f848faSopenharmony_ci 600f9f848faSopenharmony_ci DPRINTF("HCS2=0x%08x\n", temp); 601f9f848faSopenharmony_ci 602f9f848faSopenharmony_ci /* get number of scratchpads */ 603f9f848faSopenharmony_ci sc->sc_noscratch = XHCI_HCS2_SPB_MAX(temp); 604f9f848faSopenharmony_ci 605f9f848faSopenharmony_ci if (sc->sc_noscratch > XHCI_MAX_SCRATCHPADS) { 606f9f848faSopenharmony_ci device_printf(sc->sc_bus.parent, "XHCI request " 607f9f848faSopenharmony_ci "too many scratchpads\n"); 608f9f848faSopenharmony_ci return (usb_error_t)(ENOMEM); 609f9f848faSopenharmony_ci } 610f9f848faSopenharmony_ci 611f9f848faSopenharmony_ci DPRINTF("Max scratch: %u\n", sc->sc_noscratch); 612f9f848faSopenharmony_ci 613f9f848faSopenharmony_ci /* get event table size */ 614f9f848faSopenharmony_ci sc->sc_erst_max = 1U << XHCI_HCS2_ERST_MAX(temp); 615f9f848faSopenharmony_ci if (sc->sc_erst_max > XHCI_MAX_RSEG) 616f9f848faSopenharmony_ci sc->sc_erst_max = XHCI_MAX_RSEG; 617f9f848faSopenharmony_ci 618f9f848faSopenharmony_ci temp = XREAD4(sc, capa, XHCI_HCSPARAMS3); 619f9f848faSopenharmony_ci 620f9f848faSopenharmony_ci /* get maximum exit latency */ 621f9f848faSopenharmony_ci sc->sc_exit_lat_max = XHCI_HCS3_U1_DEL(temp) + 622f9f848faSopenharmony_ci XHCI_HCS3_U2_DEL(temp) + 250 /* us */; 623f9f848faSopenharmony_ci 624f9f848faSopenharmony_ci /* Check if we should use the default IMOD value. */ 625f9f848faSopenharmony_ci if (sc->sc_imod_default == 0) 626f9f848faSopenharmony_ci sc->sc_imod_default = XHCI_IMOD_DEFAULT; 627f9f848faSopenharmony_ci 628f9f848faSopenharmony_ci /* get all DMA memory */ 629f9f848faSopenharmony_ci if (usb_bus_mem_alloc_all(&sc->sc_bus, 630f9f848faSopenharmony_ci USB_GET_DMA_TAG(self), &xhci_iterate_hw_softc)) { 631f9f848faSopenharmony_ci return (usb_error_t)(ENOMEM); 632f9f848faSopenharmony_ci } 633f9f848faSopenharmony_ci 634f9f848faSopenharmony_ci /* set up command queue mutex and condition varible */ 635f9f848faSopenharmony_ci cv_init(&sc->sc_cmd_cv, "CMDQ"); 636f9f848faSopenharmony_ci sx_init(&sc->sc_cmd_sx, "CMDQ lock"); 637f9f848faSopenharmony_ci 638f9f848faSopenharmony_ci sc->sc_config_msg[0].hdr.pm_callback = &xhci_configure_msg; 639f9f848faSopenharmony_ci sc->sc_config_msg[0].bus = &sc->sc_bus; 640f9f848faSopenharmony_ci sc->sc_config_msg[1].hdr.pm_callback = &xhci_configure_msg; 641f9f848faSopenharmony_ci sc->sc_config_msg[1].bus = &sc->sc_bus; 642f9f848faSopenharmony_ci 643f9f848faSopenharmony_ci return (USB_ERR_NORMAL_COMPLETION); 644f9f848faSopenharmony_ci} 645f9f848faSopenharmony_ci 646f9f848faSopenharmony_civoid 647f9f848faSopenharmony_cixhci_uninit(struct xhci_softc *sc) 648f9f848faSopenharmony_ci{ 649f9f848faSopenharmony_ci /* 650f9f848faSopenharmony_ci * NOTE: At this point the control transfer process is gone 651f9f848faSopenharmony_ci * and "xhci_configure_msg" is no longer called. Consequently 652f9f848faSopenharmony_ci * waiting for the configuration messages to complete is not 653f9f848faSopenharmony_ci * needed. 654f9f848faSopenharmony_ci */ 655f9f848faSopenharmony_ci usb_bus_mem_free_all(&sc->sc_bus, &xhci_iterate_hw_softc); 656f9f848faSopenharmony_ci 657f9f848faSopenharmony_ci cv_destroy(&sc->sc_cmd_cv); 658f9f848faSopenharmony_ci sx_destroy(&sc->sc_cmd_sx); 659f9f848faSopenharmony_ci} 660f9f848faSopenharmony_ci 661f9f848faSopenharmony_cistatic void 662f9f848faSopenharmony_cixhci_set_hw_power_sleep(struct usb_bus *bus, uint32_t state) 663f9f848faSopenharmony_ci{ 664f9f848faSopenharmony_ci struct xhci_softc *sc = XHCI_BUS2SC(bus); 665f9f848faSopenharmony_ci 666f9f848faSopenharmony_ci switch (state) { 667f9f848faSopenharmony_ci case USB_HW_POWER_SUSPEND: 668f9f848faSopenharmony_ci DPRINTF("Stopping the XHCI\n"); 669f9f848faSopenharmony_ci (void)xhci_halt_controller(sc); 670f9f848faSopenharmony_ci (void)xhci_reset_controller(sc); 671f9f848faSopenharmony_ci break; 672f9f848faSopenharmony_ci case USB_HW_POWER_SHUTDOWN: 673f9f848faSopenharmony_ci DPRINTF("Stopping the XHCI\n"); 674f9f848faSopenharmony_ci (void)xhci_halt_controller(sc); 675f9f848faSopenharmony_ci (void)xhci_reset_controller(sc); 676f9f848faSopenharmony_ci break; 677f9f848faSopenharmony_ci case USB_HW_POWER_RESUME: 678f9f848faSopenharmony_ci DPRINTF("Starting the XHCI\n"); 679f9f848faSopenharmony_ci (void)xhci_start_controller(sc); 680f9f848faSopenharmony_ci break; 681f9f848faSopenharmony_ci default: 682f9f848faSopenharmony_ci break; 683f9f848faSopenharmony_ci } 684f9f848faSopenharmony_ci} 685f9f848faSopenharmony_ci 686f9f848faSopenharmony_cistatic usb_error_t 687f9f848faSopenharmony_cixhci_generic_done_sub(struct usb_xfer *xfer) 688f9f848faSopenharmony_ci{ 689f9f848faSopenharmony_ci struct xhci_td *td; 690f9f848faSopenharmony_ci struct xhci_td *td_alt_next; 691f9f848faSopenharmony_ci uint32_t len; 692f9f848faSopenharmony_ci uint8_t status; 693f9f848faSopenharmony_ci 694f9f848faSopenharmony_ci td = xfer->td_transfer_cache; 695f9f848faSopenharmony_ci td_alt_next = td->alt_next; 696f9f848faSopenharmony_ci 697f9f848faSopenharmony_ci if (xfer->aframes != xfer->nframes) 698f9f848faSopenharmony_ci usbd_xfer_set_frame_len(xfer, xfer->aframes, 0); 699f9f848faSopenharmony_ci 700f9f848faSopenharmony_ci while (1) { 701f9f848faSopenharmony_ci usb_pc_cpu_invalidate(td->page_cache); 702f9f848faSopenharmony_ci 703f9f848faSopenharmony_ci status = td->status; 704f9f848faSopenharmony_ci len = td->remainder; 705f9f848faSopenharmony_ci 706f9f848faSopenharmony_ci DPRINTFN(4, "xfer=%p[%u/%u] rem=%u/%u status=%u\n", 707f9f848faSopenharmony_ci xfer, (unsigned int)xfer->aframes, 708f9f848faSopenharmony_ci (unsigned int)xfer->nframes, 709f9f848faSopenharmony_ci (unsigned int)len, (unsigned int)td->len, 710f9f848faSopenharmony_ci (unsigned int)status); 711f9f848faSopenharmony_ci 712f9f848faSopenharmony_ci /* 713f9f848faSopenharmony_ci * Verify the status length and 714f9f848faSopenharmony_ci * add the length to "frlengths[]": 715f9f848faSopenharmony_ci */ 716f9f848faSopenharmony_ci if (len > td->len) { 717f9f848faSopenharmony_ci /* should not happen */ 718f9f848faSopenharmony_ci DPRINTF("Invalid status length, " 719f9f848faSopenharmony_ci "0x%04x/0x%04x bytes\n", len, td->len); 720f9f848faSopenharmony_ci status = XHCI_TRB_ERROR_LENGTH; 721f9f848faSopenharmony_ci } else if (xfer->aframes != xfer->nframes) { 722f9f848faSopenharmony_ci xfer->frlengths[xfer->aframes] += td->len - len; 723f9f848faSopenharmony_ci } 724f9f848faSopenharmony_ci /* Check for last transfer */ 725f9f848faSopenharmony_ci if (((void *)td) == xfer->td_transfer_last) { 726f9f848faSopenharmony_ci td = NULL; 727f9f848faSopenharmony_ci break; 728f9f848faSopenharmony_ci } 729f9f848faSopenharmony_ci /* Check for transfer error */ 730f9f848faSopenharmony_ci if (status != XHCI_TRB_ERROR_SHORT_PKT && 731f9f848faSopenharmony_ci status != XHCI_TRB_ERROR_SUCCESS) { 732f9f848faSopenharmony_ci /* the transfer is finished */ 733f9f848faSopenharmony_ci td = NULL; 734f9f848faSopenharmony_ci break; 735f9f848faSopenharmony_ci } 736f9f848faSopenharmony_ci /* Check for short transfer */ 737f9f848faSopenharmony_ci if (len > 0) { 738f9f848faSopenharmony_ci if (xfer->flags_int.short_frames_ok || 739f9f848faSopenharmony_ci xfer->flags_int.isochronous_xfr || 740f9f848faSopenharmony_ci xfer->flags_int.control_xfr) { 741f9f848faSopenharmony_ci /* follow alt next */ 742f9f848faSopenharmony_ci td = td->alt_next; 743f9f848faSopenharmony_ci } else { 744f9f848faSopenharmony_ci /* the transfer is finished */ 745f9f848faSopenharmony_ci td = NULL; 746f9f848faSopenharmony_ci } 747f9f848faSopenharmony_ci break; 748f9f848faSopenharmony_ci } 749f9f848faSopenharmony_ci td = td->obj_next; 750f9f848faSopenharmony_ci 751f9f848faSopenharmony_ci if (td->alt_next != td_alt_next) { 752f9f848faSopenharmony_ci /* this USB frame is complete */ 753f9f848faSopenharmony_ci break; 754f9f848faSopenharmony_ci } 755f9f848faSopenharmony_ci } 756f9f848faSopenharmony_ci 757f9f848faSopenharmony_ci /* update transfer cache */ 758f9f848faSopenharmony_ci 759f9f848faSopenharmony_ci xfer->td_transfer_cache = td; 760f9f848faSopenharmony_ci 761f9f848faSopenharmony_ci return ((status == XHCI_TRB_ERROR_STALL) ? USB_ERR_STALLED : 762f9f848faSopenharmony_ci (status != XHCI_TRB_ERROR_SHORT_PKT && 763f9f848faSopenharmony_ci status != XHCI_TRB_ERROR_SUCCESS) ? USB_ERR_IOERROR : 764f9f848faSopenharmony_ci USB_ERR_NORMAL_COMPLETION); 765f9f848faSopenharmony_ci} 766f9f848faSopenharmony_ci 767f9f848faSopenharmony_cistatic void 768f9f848faSopenharmony_cixhci_generic_done(struct usb_xfer *xfer) 769f9f848faSopenharmony_ci{ 770f9f848faSopenharmony_ci usb_error_t err = USB_ERR_NORMAL_COMPLETION; 771f9f848faSopenharmony_ci 772f9f848faSopenharmony_ci DPRINTFN(13, "xfer=%p endpoint=%p transfer done\n", 773f9f848faSopenharmony_ci xfer, xfer->endpoint); 774f9f848faSopenharmony_ci 775f9f848faSopenharmony_ci /* reset scanner */ 776f9f848faSopenharmony_ci 777f9f848faSopenharmony_ci xfer->td_transfer_cache = xfer->td_transfer_first; 778f9f848faSopenharmony_ci 779f9f848faSopenharmony_ci if (xfer->flags_int.control_xfr) { 780f9f848faSopenharmony_ci if (xfer->flags_int.control_hdr) 781f9f848faSopenharmony_ci err = xhci_generic_done_sub(xfer); 782f9f848faSopenharmony_ci 783f9f848faSopenharmony_ci xfer->aframes = 1; 784f9f848faSopenharmony_ci 785f9f848faSopenharmony_ci if (xfer->td_transfer_cache == NULL) 786f9f848faSopenharmony_ci goto done; 787f9f848faSopenharmony_ci } 788f9f848faSopenharmony_ci 789f9f848faSopenharmony_ci while (xfer->aframes != xfer->nframes) { 790f9f848faSopenharmony_ci err = xhci_generic_done_sub(xfer); 791f9f848faSopenharmony_ci xfer->aframes++; 792f9f848faSopenharmony_ci 793f9f848faSopenharmony_ci if (xfer->td_transfer_cache == NULL) 794f9f848faSopenharmony_ci goto done; 795f9f848faSopenharmony_ci } 796f9f848faSopenharmony_ci 797f9f848faSopenharmony_ci if (xfer->flags_int.control_xfr && 798f9f848faSopenharmony_ci !xfer->flags_int.control_act) 799f9f848faSopenharmony_ci err = xhci_generic_done_sub(xfer); 800f9f848faSopenharmony_cidone: 801f9f848faSopenharmony_ci /* transfer is complete */ 802f9f848faSopenharmony_ci xhci_device_done(xfer, err); 803f9f848faSopenharmony_ci} 804f9f848faSopenharmony_ci 805f9f848faSopenharmony_cistatic void 806f9f848faSopenharmony_cixhci_activate_transfer(struct usb_xfer *xfer) 807f9f848faSopenharmony_ci{ 808f9f848faSopenharmony_ci struct xhci_td *td; 809f9f848faSopenharmony_ci 810f9f848faSopenharmony_ci td = xfer->td_transfer_cache; 811f9f848faSopenharmony_ci 812f9f848faSopenharmony_ci usb_pc_cpu_invalidate(td->page_cache); 813f9f848faSopenharmony_ci 814f9f848faSopenharmony_ci if (!(td->td_trb[0].dwTrb3 & htole32(XHCI_TRB_3_CYCLE_BIT))) { 815f9f848faSopenharmony_ci /* activate the transfer */ 816f9f848faSopenharmony_ci td->td_trb[0].dwTrb3 |= htole32(XHCI_TRB_3_CYCLE_BIT); 817f9f848faSopenharmony_ci usb_pc_cpu_flush(td->page_cache); 818f9f848faSopenharmony_ci 819f9f848faSopenharmony_ci xhci_endpoint_doorbell(xfer); 820f9f848faSopenharmony_ci } 821f9f848faSopenharmony_ci} 822f9f848faSopenharmony_ci 823f9f848faSopenharmony_cistatic void 824f9f848faSopenharmony_cixhci_skip_transfer(struct usb_xfer *xfer) 825f9f848faSopenharmony_ci{ 826f9f848faSopenharmony_ci struct xhci_td *td; 827f9f848faSopenharmony_ci struct xhci_td *td_last; 828f9f848faSopenharmony_ci 829f9f848faSopenharmony_ci td = xfer->td_transfer_cache; 830f9f848faSopenharmony_ci td_last = xfer->td_transfer_last; 831f9f848faSopenharmony_ci 832f9f848faSopenharmony_ci td = td->alt_next; 833f9f848faSopenharmony_ci 834f9f848faSopenharmony_ci usb_pc_cpu_invalidate(td->page_cache); 835f9f848faSopenharmony_ci 836f9f848faSopenharmony_ci if (!(td->td_trb[0].dwTrb3 & htole32(XHCI_TRB_3_CYCLE_BIT))) { 837f9f848faSopenharmony_ci usb_pc_cpu_invalidate(td_last->page_cache); 838f9f848faSopenharmony_ci 839f9f848faSopenharmony_ci /* copy LINK TRB to current waiting location */ 840f9f848faSopenharmony_ci 841f9f848faSopenharmony_ci td->td_trb[0].qwTrb0 = td_last->td_trb[td_last->ntrb].qwTrb0; 842f9f848faSopenharmony_ci td->td_trb[0].dwTrb2 = td_last->td_trb[td_last->ntrb].dwTrb2; 843f9f848faSopenharmony_ci usb_pc_cpu_flush(td->page_cache); 844f9f848faSopenharmony_ci 845f9f848faSopenharmony_ci td->td_trb[0].dwTrb3 = td_last->td_trb[td_last->ntrb].dwTrb3; 846f9f848faSopenharmony_ci usb_pc_cpu_flush(td->page_cache); 847f9f848faSopenharmony_ci 848f9f848faSopenharmony_ci xhci_endpoint_doorbell(xfer); 849f9f848faSopenharmony_ci } 850f9f848faSopenharmony_ci} 851f9f848faSopenharmony_ci 852f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 853f9f848faSopenharmony_ci * xhci_check_transfer 854f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 855f9f848faSopenharmony_cistatic void 856f9f848faSopenharmony_cixhci_check_transfer(struct xhci_softc *sc, struct xhci_trb *trb) 857f9f848faSopenharmony_ci{ 858f9f848faSopenharmony_ci struct xhci_endpoint_ext *pepext; 859f9f848faSopenharmony_ci int64_t offset; 860f9f848faSopenharmony_ci uint64_t td_event; 861f9f848faSopenharmony_ci uint32_t temp; 862f9f848faSopenharmony_ci uint32_t remainder; 863f9f848faSopenharmony_ci uint16_t stream_id = 0; 864f9f848faSopenharmony_ci uint16_t i; 865f9f848faSopenharmony_ci uint8_t status; 866f9f848faSopenharmony_ci uint8_t halted; 867f9f848faSopenharmony_ci uint8_t epno; 868f9f848faSopenharmony_ci uint8_t index; 869f9f848faSopenharmony_ci 870f9f848faSopenharmony_ci /* decode TRB */ 871f9f848faSopenharmony_ci td_event = le64toh(trb->qwTrb0); 872f9f848faSopenharmony_ci temp = le32toh(trb->dwTrb2); 873f9f848faSopenharmony_ci 874f9f848faSopenharmony_ci remainder = XHCI_TRB_2_REM_GET(temp); 875f9f848faSopenharmony_ci status = XHCI_TRB_2_ERROR_GET(temp); 876f9f848faSopenharmony_ci 877f9f848faSopenharmony_ci temp = le32toh(trb->dwTrb3); 878f9f848faSopenharmony_ci epno = XHCI_TRB_3_EP_GET(temp); 879f9f848faSopenharmony_ci index = XHCI_TRB_3_SLOT_GET(temp); 880f9f848faSopenharmony_ci 881f9f848faSopenharmony_ci /* check if error means halted */ 882f9f848faSopenharmony_ci halted = (status != XHCI_TRB_ERROR_SHORT_PKT && 883f9f848faSopenharmony_ci status != XHCI_TRB_ERROR_SUCCESS); 884f9f848faSopenharmony_ci 885f9f848faSopenharmony_ci DPRINTF("slot=%u epno=%u remainder=%u status=%u\n", 886f9f848faSopenharmony_ci index, epno, remainder, status); 887f9f848faSopenharmony_ci 888f9f848faSopenharmony_ci if (index > sc->sc_noslot) { 889f9f848faSopenharmony_ci DPRINTF("Invalid slot.\n"); 890f9f848faSopenharmony_ci return; 891f9f848faSopenharmony_ci } 892f9f848faSopenharmony_ci 893f9f848faSopenharmony_ci if ((epno == 0) || (epno >= XHCI_MAX_ENDPOINTS)) { 894f9f848faSopenharmony_ci DPRINTF("Invalid endpoint.\n"); 895f9f848faSopenharmony_ci return; 896f9f848faSopenharmony_ci } 897f9f848faSopenharmony_ci 898f9f848faSopenharmony_ci pepext = &sc->sc_hw.devs[index].endp[epno]; 899f9f848faSopenharmony_ci 900f9f848faSopenharmony_ci /* try to find the USB transfer that generated the event */ 901f9f848faSopenharmony_ci for (i = 0;; i++) { 902f9f848faSopenharmony_ci struct usb_xfer *xfer; 903f9f848faSopenharmony_ci struct xhci_td *td; 904f9f848faSopenharmony_ci 905f9f848faSopenharmony_ci if (i == (XHCI_MAX_TRANSFERS - 1)) { 906f9f848faSopenharmony_ci if (pepext->trb_ep_mode != USB_EP_MODE_STREAMS || 907f9f848faSopenharmony_ci stream_id == (XHCI_MAX_STREAMS - 1)) 908f9f848faSopenharmony_ci break; 909f9f848faSopenharmony_ci stream_id++; 910f9f848faSopenharmony_ci i = 0; 911f9f848faSopenharmony_ci DPRINTFN(5, "stream_id=%u\n", stream_id); 912f9f848faSopenharmony_ci } 913f9f848faSopenharmony_ci 914f9f848faSopenharmony_ci xfer = pepext->xfer[i + (XHCI_MAX_TRANSFERS * stream_id)]; 915f9f848faSopenharmony_ci if (xfer == NULL) 916f9f848faSopenharmony_ci continue; 917f9f848faSopenharmony_ci 918f9f848faSopenharmony_ci td = xfer->td_transfer_cache; 919f9f848faSopenharmony_ci if (td == NULL) { 920f9f848faSopenharmony_ci continue; 921f9f848faSopenharmony_ci } 922f9f848faSopenharmony_ci 923f9f848faSopenharmony_ci DPRINTFN(5, "Checking if 0x%016llx == (0x%016llx .. 0x%016llx)\n", 924f9f848faSopenharmony_ci (long long)td_event, 925f9f848faSopenharmony_ci (long long)td->td_self, 926f9f848faSopenharmony_ci (long long)td->td_self + sizeof(td->td_trb)); 927f9f848faSopenharmony_ci 928f9f848faSopenharmony_ci /* 929f9f848faSopenharmony_ci * NOTE: Some XHCI implementations might not trigger 930f9f848faSopenharmony_ci * an event on the last LINK TRB so we need to 931f9f848faSopenharmony_ci * consider both the last and second last event 932f9f848faSopenharmony_ci * address as conditions for a successful transfer. 933f9f848faSopenharmony_ci * 934f9f848faSopenharmony_ci * NOTE: We assume that the XHCI will only trigger one 935f9f848faSopenharmony_ci * event per chain of TRBs. 936f9f848faSopenharmony_ci */ 937f9f848faSopenharmony_ci 938f9f848faSopenharmony_ci offset = td_event - td->td_self; 939f9f848faSopenharmony_ci 940f9f848faSopenharmony_ci if ((offset >= 0) && 941f9f848faSopenharmony_ci (offset < (int64_t)sizeof(td->td_trb))) { 942f9f848faSopenharmony_ci usb_pc_cpu_invalidate(td->page_cache); 943f9f848faSopenharmony_ci 944f9f848faSopenharmony_ci /* compute rest of remainder, if any */ 945f9f848faSopenharmony_ci for (i = (offset / 16) + 1; i < td->ntrb; i++) { 946f9f848faSopenharmony_ci temp = le32toh(td->td_trb[i].dwTrb2); 947f9f848faSopenharmony_ci remainder += XHCI_TRB_2_BYTES_GET(temp); 948f9f848faSopenharmony_ci } 949f9f848faSopenharmony_ci 950f9f848faSopenharmony_ci DPRINTFN(5, "New remainder: %u\n", remainder); 951f9f848faSopenharmony_ci 952f9f848faSopenharmony_ci /* clear isochronous transfer errors */ 953f9f848faSopenharmony_ci if (xfer->flags_int.isochronous_xfr) { 954f9f848faSopenharmony_ci if (halted) { 955f9f848faSopenharmony_ci halted = 0; 956f9f848faSopenharmony_ci status = XHCI_TRB_ERROR_SUCCESS; 957f9f848faSopenharmony_ci remainder = td->len; 958f9f848faSopenharmony_ci } 959f9f848faSopenharmony_ci } 960f9f848faSopenharmony_ci 961f9f848faSopenharmony_ci /* "td->remainder" is verified later */ 962f9f848faSopenharmony_ci td->remainder = remainder; 963f9f848faSopenharmony_ci td->status = status; 964f9f848faSopenharmony_ci 965f9f848faSopenharmony_ci usb_pc_cpu_flush(td->page_cache); 966f9f848faSopenharmony_ci 967f9f848faSopenharmony_ci /* 968f9f848faSopenharmony_ci * 1) Last transfer descriptor makes the 969f9f848faSopenharmony_ci * transfer done 970f9f848faSopenharmony_ci */ 971f9f848faSopenharmony_ci if (((void *)td) == xfer->td_transfer_last) { 972f9f848faSopenharmony_ci DPRINTF("TD is last\n"); 973f9f848faSopenharmony_ci xhci_generic_done(xfer); 974f9f848faSopenharmony_ci break; 975f9f848faSopenharmony_ci } 976f9f848faSopenharmony_ci 977f9f848faSopenharmony_ci /* 978f9f848faSopenharmony_ci * 2) Any kind of error makes the transfer 979f9f848faSopenharmony_ci * done 980f9f848faSopenharmony_ci */ 981f9f848faSopenharmony_ci if (halted) { 982f9f848faSopenharmony_ci DPRINTF("TD has I/O error\n"); 983f9f848faSopenharmony_ci xhci_generic_done(xfer); 984f9f848faSopenharmony_ci break; 985f9f848faSopenharmony_ci } 986f9f848faSopenharmony_ci 987f9f848faSopenharmony_ci /* 988f9f848faSopenharmony_ci * 3) If there is no alternate next transfer, 989f9f848faSopenharmony_ci * a short packet also makes the transfer done 990f9f848faSopenharmony_ci */ 991f9f848faSopenharmony_ci if (td->remainder > 0) { 992f9f848faSopenharmony_ci if (td->alt_next == NULL) { 993f9f848faSopenharmony_ci DPRINTF( 994f9f848faSopenharmony_ci "short TD has no alternate next\n"); 995f9f848faSopenharmony_ci xhci_generic_done(xfer); 996f9f848faSopenharmony_ci break; 997f9f848faSopenharmony_ci } 998f9f848faSopenharmony_ci DPRINTF("TD has short pkt\n"); 999f9f848faSopenharmony_ci if (xfer->flags_int.short_frames_ok || 1000f9f848faSopenharmony_ci xfer->flags_int.isochronous_xfr || 1001f9f848faSopenharmony_ci xfer->flags_int.control_xfr) { 1002f9f848faSopenharmony_ci /* follow the alt next */ 1003f9f848faSopenharmony_ci xfer->td_transfer_cache = td->alt_next; 1004f9f848faSopenharmony_ci xhci_activate_transfer(xfer); 1005f9f848faSopenharmony_ci break; 1006f9f848faSopenharmony_ci } 1007f9f848faSopenharmony_ci xhci_skip_transfer(xfer); 1008f9f848faSopenharmony_ci xhci_generic_done(xfer); 1009f9f848faSopenharmony_ci break; 1010f9f848faSopenharmony_ci } 1011f9f848faSopenharmony_ci 1012f9f848faSopenharmony_ci /* 1013f9f848faSopenharmony_ci * 4) Transfer complete - go to next TD 1014f9f848faSopenharmony_ci */ 1015f9f848faSopenharmony_ci DPRINTF("Following next TD\n"); 1016f9f848faSopenharmony_ci xfer->td_transfer_cache = td->obj_next; 1017f9f848faSopenharmony_ci xhci_activate_transfer(xfer); 1018f9f848faSopenharmony_ci break; /* there should only be one match */ 1019f9f848faSopenharmony_ci } 1020f9f848faSopenharmony_ci } 1021f9f848faSopenharmony_ci} 1022f9f848faSopenharmony_ci 1023f9f848faSopenharmony_cistatic int 1024f9f848faSopenharmony_cixhci_check_command(struct xhci_softc *sc, struct xhci_trb *trb) 1025f9f848faSopenharmony_ci{ 1026f9f848faSopenharmony_ci if (sc->sc_cmd_addr == trb->qwTrb0) { 1027f9f848faSopenharmony_ci DPRINTF("Received command event\n"); 1028f9f848faSopenharmony_ci sc->sc_cmd_result[0] = trb->dwTrb2; 1029f9f848faSopenharmony_ci sc->sc_cmd_result[1] = trb->dwTrb3; 1030f9f848faSopenharmony_ci (void)cv_signal(&sc->sc_cmd_cv); 1031f9f848faSopenharmony_ci return (1); /* command match */ 1032f9f848faSopenharmony_ci } 1033f9f848faSopenharmony_ci return (0); 1034f9f848faSopenharmony_ci} 1035f9f848faSopenharmony_ci 1036f9f848faSopenharmony_cistatic int 1037f9f848faSopenharmony_cixhci_interrupt_poll(struct xhci_softc *sc) 1038f9f848faSopenharmony_ci{ 1039f9f848faSopenharmony_ci struct usb_page_search buf_res; 1040f9f848faSopenharmony_ci struct xhci_hw_root *phwr; 1041f9f848faSopenharmony_ci uint64_t addr; 1042f9f848faSopenharmony_ci uint32_t temp; 1043f9f848faSopenharmony_ci int retval = 0; 1044f9f848faSopenharmony_ci uint16_t i; 1045f9f848faSopenharmony_ci uint8_t event; 1046f9f848faSopenharmony_ci uint8_t j; 1047f9f848faSopenharmony_ci uint8_t k; 1048f9f848faSopenharmony_ci uint8_t t; 1049f9f848faSopenharmony_ci 1050f9f848faSopenharmony_ci usbd_get_page(&sc->sc_hw.root_pc, 0, &buf_res); 1051f9f848faSopenharmony_ci 1052f9f848faSopenharmony_ci phwr = buf_res.buffer; 1053f9f848faSopenharmony_ci 1054f9f848faSopenharmony_ci /* Receive any events */ 1055f9f848faSopenharmony_ci 1056f9f848faSopenharmony_ci usb_pc_cpu_invalidate(&sc->sc_hw.root_pc); 1057f9f848faSopenharmony_ci 1058f9f848faSopenharmony_ci i = sc->sc_event_idx; 1059f9f848faSopenharmony_ci j = sc->sc_event_ccs; 1060f9f848faSopenharmony_ci t = 2; 1061f9f848faSopenharmony_ci 1062f9f848faSopenharmony_ci while (1) { 1063f9f848faSopenharmony_ci temp = le32toh(phwr->hwr_events[i].dwTrb3); 1064f9f848faSopenharmony_ci 1065f9f848faSopenharmony_ci k = (temp & XHCI_TRB_3_CYCLE_BIT) ? 1 : 0; 1066f9f848faSopenharmony_ci 1067f9f848faSopenharmony_ci if (j != k) 1068f9f848faSopenharmony_ci break; 1069f9f848faSopenharmony_ci 1070f9f848faSopenharmony_ci event = XHCI_TRB_3_TYPE_GET(temp); 1071f9f848faSopenharmony_ci 1072f9f848faSopenharmony_ci DPRINTFN(10, "event[%u] = %u (0x%016llx 0x%08lx 0x%08lx)\n", 1073f9f848faSopenharmony_ci i, event, (long long)le64toh(phwr->hwr_events[i].qwTrb0), 1074f9f848faSopenharmony_ci (long)le32toh(phwr->hwr_events[i].dwTrb2), 1075f9f848faSopenharmony_ci (long)le32toh(phwr->hwr_events[i].dwTrb3)); 1076f9f848faSopenharmony_ci 1077f9f848faSopenharmony_ci switch (event) { 1078f9f848faSopenharmony_ci case XHCI_TRB_EVENT_TRANSFER: 1079f9f848faSopenharmony_ci xhci_check_transfer(sc, &phwr->hwr_events[i]); 1080f9f848faSopenharmony_ci break; 1081f9f848faSopenharmony_ci case XHCI_TRB_EVENT_CMD_COMPLETE: 1082f9f848faSopenharmony_ci retval |= xhci_check_command(sc, &phwr->hwr_events[i]); 1083f9f848faSopenharmony_ci break; 1084f9f848faSopenharmony_ci default: 1085f9f848faSopenharmony_ci DPRINTF("Unhandled event = %u\n", event); 1086f9f848faSopenharmony_ci break; 1087f9f848faSopenharmony_ci } 1088f9f848faSopenharmony_ci 1089f9f848faSopenharmony_ci i++; 1090f9f848faSopenharmony_ci 1091f9f848faSopenharmony_ci if (i == XHCI_MAX_EVENTS) { 1092f9f848faSopenharmony_ci i = 0; 1093f9f848faSopenharmony_ci j ^= 1; 1094f9f848faSopenharmony_ci 1095f9f848faSopenharmony_ci /* check for timeout */ 1096f9f848faSopenharmony_ci if (!--t) 1097f9f848faSopenharmony_ci break; 1098f9f848faSopenharmony_ci } 1099f9f848faSopenharmony_ci } 1100f9f848faSopenharmony_ci 1101f9f848faSopenharmony_ci sc->sc_event_idx = i; 1102f9f848faSopenharmony_ci sc->sc_event_ccs = j; 1103f9f848faSopenharmony_ci 1104f9f848faSopenharmony_ci /* 1105f9f848faSopenharmony_ci * NOTE: The Event Ring Dequeue Pointer Register is 64-bit 1106f9f848faSopenharmony_ci * latched. That means to activate the register we need to 1107f9f848faSopenharmony_ci * write both the low and high double word of the 64-bit 1108f9f848faSopenharmony_ci * register. 1109f9f848faSopenharmony_ci */ 1110f9f848faSopenharmony_ci 1111f9f848faSopenharmony_ci addr = buf_res.physaddr; 1112f9f848faSopenharmony_ci addr += __offsetof(struct xhci_hw_root, hwr_events[i]); 1113f9f848faSopenharmony_ci 1114f9f848faSopenharmony_ci /* try to clear busy bit */ 1115f9f848faSopenharmony_ci addr |= XHCI_ERDP_LO_BUSY; 1116f9f848faSopenharmony_ci 1117f9f848faSopenharmony_ci XWRITE4(sc, runt, XHCI_ERDP_LO(0), (uint32_t)addr); 1118f9f848faSopenharmony_ci XWRITE4(sc, runt, XHCI_ERDP_HI(0), (uint32_t)(addr >> 32)); 1119f9f848faSopenharmony_ci 1120f9f848faSopenharmony_ci return (retval); 1121f9f848faSopenharmony_ci} 1122f9f848faSopenharmony_ci 1123f9f848faSopenharmony_cistatic usb_error_t 1124f9f848faSopenharmony_cixhci_do_command(struct xhci_softc *sc, struct xhci_trb *trb, 1125f9f848faSopenharmony_ci uint16_t timeout_ms) 1126f9f848faSopenharmony_ci{ 1127f9f848faSopenharmony_ci struct usb_page_search buf_res; 1128f9f848faSopenharmony_ci struct xhci_hw_root *phwr; 1129f9f848faSopenharmony_ci uint64_t addr; 1130f9f848faSopenharmony_ci uint32_t temp; 1131f9f848faSopenharmony_ci uint8_t i; 1132f9f848faSopenharmony_ci uint8_t j; 1133f9f848faSopenharmony_ci uint8_t timeout = 0; 1134f9f848faSopenharmony_ci usb_error_t err; 1135f9f848faSopenharmony_ci 1136f9f848faSopenharmony_ci XHCI_CMD_ASSERT_LOCKED(sc); 1137f9f848faSopenharmony_ci 1138f9f848faSopenharmony_ci /* get hardware root structure */ 1139f9f848faSopenharmony_ci 1140f9f848faSopenharmony_ci usbd_get_page(&sc->sc_hw.root_pc, 0, &buf_res); 1141f9f848faSopenharmony_ci 1142f9f848faSopenharmony_ci phwr = buf_res.buffer; 1143f9f848faSopenharmony_ci 1144f9f848faSopenharmony_ci /* Queue command */ 1145f9f848faSopenharmony_ci 1146f9f848faSopenharmony_ci USB_BUS_LOCK(&sc->sc_bus); 1147f9f848faSopenharmony_ciretry: 1148f9f848faSopenharmony_ci i = sc->sc_command_idx; 1149f9f848faSopenharmony_ci j = sc->sc_command_ccs; 1150f9f848faSopenharmony_ci 1151f9f848faSopenharmony_ci DPRINTFN(10, "command[%u] = %u (0x%016llx, 0x%08lx, 0x%08lx)\n", 1152f9f848faSopenharmony_ci i, XHCI_TRB_3_TYPE_GET(le32toh(trb->dwTrb3)), 1153f9f848faSopenharmony_ci (long long)le64toh(trb->qwTrb0), 1154f9f848faSopenharmony_ci (long)le32toh(trb->dwTrb2), 1155f9f848faSopenharmony_ci (long)le32toh(trb->dwTrb3)); 1156f9f848faSopenharmony_ci 1157f9f848faSopenharmony_ci phwr->hwr_commands[i].qwTrb0 = trb->qwTrb0; 1158f9f848faSopenharmony_ci phwr->hwr_commands[i].dwTrb2 = trb->dwTrb2; 1159f9f848faSopenharmony_ci 1160f9f848faSopenharmony_ci usb_pc_cpu_flush(&sc->sc_hw.root_pc); 1161f9f848faSopenharmony_ci 1162f9f848faSopenharmony_ci temp = trb->dwTrb3; 1163f9f848faSopenharmony_ci 1164f9f848faSopenharmony_ci if (j) 1165f9f848faSopenharmony_ci temp |= htole32(XHCI_TRB_3_CYCLE_BIT); 1166f9f848faSopenharmony_ci else 1167f9f848faSopenharmony_ci temp &= ~htole32(XHCI_TRB_3_CYCLE_BIT); 1168f9f848faSopenharmony_ci 1169f9f848faSopenharmony_ci temp &= ~htole32(XHCI_TRB_3_TC_BIT); 1170f9f848faSopenharmony_ci 1171f9f848faSopenharmony_ci phwr->hwr_commands[i].dwTrb3 = temp; 1172f9f848faSopenharmony_ci 1173f9f848faSopenharmony_ci usb_pc_cpu_flush(&sc->sc_hw.root_pc); 1174f9f848faSopenharmony_ci 1175f9f848faSopenharmony_ci addr = buf_res.physaddr; 1176f9f848faSopenharmony_ci addr += __offsetof(struct xhci_hw_root, hwr_commands[i]); 1177f9f848faSopenharmony_ci 1178f9f848faSopenharmony_ci sc->sc_cmd_addr = htole64(addr); 1179f9f848faSopenharmony_ci 1180f9f848faSopenharmony_ci i++; 1181f9f848faSopenharmony_ci 1182f9f848faSopenharmony_ci if (i == (XHCI_MAX_COMMANDS - 1)) { 1183f9f848faSopenharmony_ci if (j) { 1184f9f848faSopenharmony_ci temp = htole32(XHCI_TRB_3_TC_BIT | 1185f9f848faSopenharmony_ci XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_LINK) | 1186f9f848faSopenharmony_ci XHCI_TRB_3_CYCLE_BIT); 1187f9f848faSopenharmony_ci } else { 1188f9f848faSopenharmony_ci temp = htole32(XHCI_TRB_3_TC_BIT | 1189f9f848faSopenharmony_ci XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_LINK)); 1190f9f848faSopenharmony_ci } 1191f9f848faSopenharmony_ci 1192f9f848faSopenharmony_ci phwr->hwr_commands[i].dwTrb3 = temp; 1193f9f848faSopenharmony_ci 1194f9f848faSopenharmony_ci usb_pc_cpu_flush(&sc->sc_hw.root_pc); 1195f9f848faSopenharmony_ci 1196f9f848faSopenharmony_ci i = 0; 1197f9f848faSopenharmony_ci j ^= 1; 1198f9f848faSopenharmony_ci } 1199f9f848faSopenharmony_ci 1200f9f848faSopenharmony_ci sc->sc_command_idx = i; 1201f9f848faSopenharmony_ci sc->sc_command_ccs = j; 1202f9f848faSopenharmony_ci 1203f9f848faSopenharmony_ci XWRITE4(sc, door, XHCI_DOORBELL(0), 0); 1204f9f848faSopenharmony_ci 1205f9f848faSopenharmony_ci err = (usb_error_t)cv_timedwait(&sc->sc_cmd_cv, &sc->sc_bus.bus_mtx, 1206f9f848faSopenharmony_ci USB_MS_TO_TICKS(timeout_ms)); 1207f9f848faSopenharmony_ci 1208f9f848faSopenharmony_ci /* 1209f9f848faSopenharmony_ci * In some error cases event interrupts are not generated. 1210f9f848faSopenharmony_ci * Poll one time to see if the command has completed. 1211f9f848faSopenharmony_ci */ 1212f9f848faSopenharmony_ci if ((err != 0) && (xhci_interrupt_poll(sc) != 0)) { 1213f9f848faSopenharmony_ci DPRINTF("Command was completed when polling\n"); 1214f9f848faSopenharmony_ci err = USB_ERR_NORMAL_COMPLETION; 1215f9f848faSopenharmony_ci } 1216f9f848faSopenharmony_ci if (err != 0) { 1217f9f848faSopenharmony_ci DPRINTF("Command timeout!\n"); 1218f9f848faSopenharmony_ci /* 1219f9f848faSopenharmony_ci * After some weeks of continuous operation, it has 1220f9f848faSopenharmony_ci * been observed that the ASMedia Technology, ASM1042 1221f9f848faSopenharmony_ci * SuperSpeed USB Host Controller can suddenly stop 1222f9f848faSopenharmony_ci * accepting commands via the command queue. Try to 1223f9f848faSopenharmony_ci * first reset the command queue. If that fails do a 1224f9f848faSopenharmony_ci * host controller reset. 1225f9f848faSopenharmony_ci */ 1226f9f848faSopenharmony_ci if ((timeout == 0) && 1227f9f848faSopenharmony_ci (xhci_reset_command_queue_locked(sc) == 0)) { 1228f9f848faSopenharmony_ci temp = le32toh(trb->dwTrb3); 1229f9f848faSopenharmony_ci 1230f9f848faSopenharmony_ci /* 1231f9f848faSopenharmony_ci * Avoid infinite XHCI reset loops if the set 1232f9f848faSopenharmony_ci * address command fails to respond due to a 1233f9f848faSopenharmony_ci * non-enumerating device: 1234f9f848faSopenharmony_ci */ 1235f9f848faSopenharmony_ci if ((XHCI_TRB_3_TYPE_GET(temp) == XHCI_TRB_TYPE_ADDRESS_DEVICE) && 1236f9f848faSopenharmony_ci ((temp & XHCI_TRB_3_BSR_BIT) == 0)) { 1237f9f848faSopenharmony_ci DPRINTF("Set address timeout\n"); 1238f9f848faSopenharmony_ci } else { 1239f9f848faSopenharmony_ci timeout = 1; 1240f9f848faSopenharmony_ci goto retry; 1241f9f848faSopenharmony_ci } 1242f9f848faSopenharmony_ci } else { 1243f9f848faSopenharmony_ci DPRINTF("Controller reset!\n"); 1244f9f848faSopenharmony_ci usb_bus_reset_async_locked(&sc->sc_bus); 1245f9f848faSopenharmony_ci } 1246f9f848faSopenharmony_ci err = USB_ERR_TIMEOUT; 1247f9f848faSopenharmony_ci trb->dwTrb2 = 0; 1248f9f848faSopenharmony_ci trb->dwTrb3 = 0; 1249f9f848faSopenharmony_ci } else { 1250f9f848faSopenharmony_ci temp = le32toh(sc->sc_cmd_result[0]); 1251f9f848faSopenharmony_ci if (XHCI_TRB_2_ERROR_GET(temp) != XHCI_TRB_ERROR_SUCCESS) { 1252f9f848faSopenharmony_ci if (!((XHCI_TRB_2_ERROR_GET(temp) == XHCI_TRB_ERROR_SLOT_NOT_ON) && 1253f9f848faSopenharmony_ci (XHCI_TRB_3_SLOT_GET(le32toh(sc->sc_cmd_result[1]))))) { 1254f9f848faSopenharmony_ci err = USB_ERR_IOERROR; 1255f9f848faSopenharmony_ci } 1256f9f848faSopenharmony_ci } 1257f9f848faSopenharmony_ci 1258f9f848faSopenharmony_ci trb->dwTrb2 = sc->sc_cmd_result[0]; 1259f9f848faSopenharmony_ci trb->dwTrb3 = sc->sc_cmd_result[1]; 1260f9f848faSopenharmony_ci } 1261f9f848faSopenharmony_ci 1262f9f848faSopenharmony_ci USB_BUS_UNLOCK(&sc->sc_bus); 1263f9f848faSopenharmony_ci 1264f9f848faSopenharmony_ci return (err); 1265f9f848faSopenharmony_ci} 1266f9f848faSopenharmony_ci 1267f9f848faSopenharmony_cistatic usb_error_t 1268f9f848faSopenharmony_cixhci_cmd_enable_slot(struct xhci_softc *sc, uint8_t *pslot) 1269f9f848faSopenharmony_ci{ 1270f9f848faSopenharmony_ci struct xhci_trb trb; 1271f9f848faSopenharmony_ci uint32_t temp; 1272f9f848faSopenharmony_ci usb_error_t err; 1273f9f848faSopenharmony_ci 1274f9f848faSopenharmony_ci DPRINTF("\n"); 1275f9f848faSopenharmony_ci 1276f9f848faSopenharmony_ci trb.qwTrb0 = 0; 1277f9f848faSopenharmony_ci trb.dwTrb2 = 0; 1278f9f848faSopenharmony_ci trb.dwTrb3 = htole32(XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_ENABLE_SLOT)); 1279f9f848faSopenharmony_ci 1280f9f848faSopenharmony_ci err = xhci_do_command(sc, &trb, XHCI_DO_CMD_TIMEOUT/* ms */); 1281f9f848faSopenharmony_ci if (err) 1282f9f848faSopenharmony_ci goto done; 1283f9f848faSopenharmony_ci 1284f9f848faSopenharmony_ci temp = le32toh(trb.dwTrb3); 1285f9f848faSopenharmony_ci 1286f9f848faSopenharmony_ci *pslot = XHCI_TRB_3_SLOT_GET(temp); 1287f9f848faSopenharmony_ci 1288f9f848faSopenharmony_cidone: 1289f9f848faSopenharmony_ci return (err); 1290f9f848faSopenharmony_ci} 1291f9f848faSopenharmony_ci 1292f9f848faSopenharmony_cistatic usb_error_t 1293f9f848faSopenharmony_cixhci_cmd_disable_slot(struct xhci_softc *sc, uint8_t slot_id) 1294f9f848faSopenharmony_ci{ 1295f9f848faSopenharmony_ci struct xhci_trb trb; 1296f9f848faSopenharmony_ci uint32_t temp; 1297f9f848faSopenharmony_ci 1298f9f848faSopenharmony_ci DPRINTF("\n"); 1299f9f848faSopenharmony_ci 1300f9f848faSopenharmony_ci trb.qwTrb0 = 0; 1301f9f848faSopenharmony_ci trb.dwTrb2 = 0; 1302f9f848faSopenharmony_ci temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_DISABLE_SLOT) | 1303f9f848faSopenharmony_ci XHCI_TRB_3_SLOT_SET(slot_id); 1304f9f848faSopenharmony_ci 1305f9f848faSopenharmony_ci trb.dwTrb3 = htole32(temp); 1306f9f848faSopenharmony_ci 1307f9f848faSopenharmony_ci return (xhci_do_command(sc, &trb, XHCI_DO_CMD_TIMEOUT/* ms */)); 1308f9f848faSopenharmony_ci} 1309f9f848faSopenharmony_ci 1310f9f848faSopenharmony_cistatic usb_error_t 1311f9f848faSopenharmony_cixhci_cmd_set_address(struct xhci_softc *sc, uint64_t input_ctx, 1312f9f848faSopenharmony_ci uint8_t bsr, uint8_t slot_id) 1313f9f848faSopenharmony_ci{ 1314f9f848faSopenharmony_ci struct xhci_trb trb; 1315f9f848faSopenharmony_ci uint32_t temp; 1316f9f848faSopenharmony_ci 1317f9f848faSopenharmony_ci DPRINTF("\n"); 1318f9f848faSopenharmony_ci 1319f9f848faSopenharmony_ci trb.qwTrb0 = htole64(input_ctx); 1320f9f848faSopenharmony_ci trb.dwTrb2 = 0; 1321f9f848faSopenharmony_ci temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_ADDRESS_DEVICE) | 1322f9f848faSopenharmony_ci XHCI_TRB_3_SLOT_SET(slot_id); 1323f9f848faSopenharmony_ci 1324f9f848faSopenharmony_ci if (bsr) 1325f9f848faSopenharmony_ci temp |= XHCI_TRB_3_BSR_BIT; 1326f9f848faSopenharmony_ci 1327f9f848faSopenharmony_ci trb.dwTrb3 = htole32(temp); 1328f9f848faSopenharmony_ci 1329f9f848faSopenharmony_ci return (xhci_do_command(sc, &trb, XHCI_DO_CMD_TIMEOUT/* ms */)); 1330f9f848faSopenharmony_ci} 1331f9f848faSopenharmony_ci 1332f9f848faSopenharmony_cistatic usb_error_t 1333f9f848faSopenharmony_cixhci_set_address(struct usb_device *udev, struct mtx *mtx, uint16_t address) 1334f9f848faSopenharmony_ci{ 1335f9f848faSopenharmony_ci struct usb_page_search buf_inp; 1336f9f848faSopenharmony_ci struct usb_page_search buf_dev; 1337f9f848faSopenharmony_ci struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); 1338f9f848faSopenharmony_ci struct xhci_hw_dev *hdev; 1339f9f848faSopenharmony_ci struct xhci_dev_ctx *pdev; 1340f9f848faSopenharmony_ci struct xhci_endpoint_ext *pepext; 1341f9f848faSopenharmony_ci uint32_t temp; 1342f9f848faSopenharmony_ci uint16_t mps; 1343f9f848faSopenharmony_ci usb_error_t err; 1344f9f848faSopenharmony_ci uint8_t index; 1345f9f848faSopenharmony_ci 1346f9f848faSopenharmony_ci /* the root HUB case is not handled here */ 1347f9f848faSopenharmony_ci if (udev->parent_hub == NULL) 1348f9f848faSopenharmony_ci return (USB_ERR_INVAL); 1349f9f848faSopenharmony_ci 1350f9f848faSopenharmony_ci index = udev->controller_slot_id; 1351f9f848faSopenharmony_ci 1352f9f848faSopenharmony_ci hdev = &sc->sc_hw.devs[index]; 1353f9f848faSopenharmony_ci 1354f9f848faSopenharmony_ci if (mtx != NULL) 1355f9f848faSopenharmony_ci mtx_unlock(mtx); 1356f9f848faSopenharmony_ci 1357f9f848faSopenharmony_ci XHCI_CMD_LOCK(sc); 1358f9f848faSopenharmony_ci 1359f9f848faSopenharmony_ci switch (hdev->state) { 1360f9f848faSopenharmony_ci case XHCI_ST_DEFAULT: 1361f9f848faSopenharmony_ci case XHCI_ST_ENABLED: 1362f9f848faSopenharmony_ci 1363f9f848faSopenharmony_ci hdev->state = XHCI_ST_ENABLED; 1364f9f848faSopenharmony_ci 1365f9f848faSopenharmony_ci /* set configure mask to slot and EP0 */ 1366f9f848faSopenharmony_ci (void)xhci_configure_mask(udev, 3, 0); 1367f9f848faSopenharmony_ci 1368f9f848faSopenharmony_ci /* configure input slot context structure */ 1369f9f848faSopenharmony_ci err = xhci_configure_device(udev); 1370f9f848faSopenharmony_ci 1371f9f848faSopenharmony_ci if (err != 0) { 1372f9f848faSopenharmony_ci DPRINTF("Could not configure device\n"); 1373f9f848faSopenharmony_ci break; 1374f9f848faSopenharmony_ci } 1375f9f848faSopenharmony_ci 1376f9f848faSopenharmony_ci /* configure input endpoint context structure */ 1377f9f848faSopenharmony_ci switch (udev->speed) { 1378f9f848faSopenharmony_ci case USB_SPEED_LOW: 1379f9f848faSopenharmony_ci case USB_SPEED_FULL: 1380f9f848faSopenharmony_ci mps = 8; 1381f9f848faSopenharmony_ci break; 1382f9f848faSopenharmony_ci case USB_SPEED_HIGH: 1383f9f848faSopenharmony_ci mps = 64; 1384f9f848faSopenharmony_ci break; 1385f9f848faSopenharmony_ci default: 1386f9f848faSopenharmony_ci mps = 512; 1387f9f848faSopenharmony_ci break; 1388f9f848faSopenharmony_ci } 1389f9f848faSopenharmony_ci 1390f9f848faSopenharmony_ci pepext = xhci_get_endpoint_ext(udev, 1391f9f848faSopenharmony_ci &udev->ctrl_ep_desc); 1392f9f848faSopenharmony_ci 1393f9f848faSopenharmony_ci /* ensure the control endpoint is setup again */ 1394f9f848faSopenharmony_ci USB_BUS_LOCK(udev->bus); 1395f9f848faSopenharmony_ci pepext->trb_halted = 1; 1396f9f848faSopenharmony_ci pepext->trb_running = 0; 1397f9f848faSopenharmony_ci USB_BUS_UNLOCK(udev->bus); 1398f9f848faSopenharmony_ci 1399f9f848faSopenharmony_ci err = xhci_configure_endpoint(udev, 1400f9f848faSopenharmony_ci &udev->ctrl_ep_desc, pepext, 1401f9f848faSopenharmony_ci 0, 1, 1, 0, mps, mps, USB_EP_MODE_DEFAULT); 1402f9f848faSopenharmony_ci 1403f9f848faSopenharmony_ci if (err != 0) { 1404f9f848faSopenharmony_ci DPRINTF("Could not configure default endpoint\n"); 1405f9f848faSopenharmony_ci break; 1406f9f848faSopenharmony_ci } 1407f9f848faSopenharmony_ci 1408f9f848faSopenharmony_ci /* execute set address command */ 1409f9f848faSopenharmony_ci usbd_get_page(&hdev->input_pc, 0, &buf_inp); 1410f9f848faSopenharmony_ci 1411f9f848faSopenharmony_ci err = xhci_cmd_set_address(sc, buf_inp.physaddr, 1412f9f848faSopenharmony_ci (address == 0), index); 1413f9f848faSopenharmony_ci 1414f9f848faSopenharmony_ci if (err != 0) { 1415f9f848faSopenharmony_ci temp = le32toh(sc->sc_cmd_result[0]); 1416f9f848faSopenharmony_ci if ((address == 0) && (sc->sc_port_route != NULL) && 1417f9f848faSopenharmony_ci (XHCI_TRB_2_ERROR_GET(temp) == 1418f9f848faSopenharmony_ci XHCI_TRB_ERROR_PARAMETER)) { 1419f9f848faSopenharmony_ci /* LynxPoint XHCI - ports are not switchable */ 1420f9f848faSopenharmony_ci /* Un-route all ports from the XHCI */ 1421f9f848faSopenharmony_ci (void)sc->sc_port_route(sc->sc_bus.parent, 0, ~0); 1422f9f848faSopenharmony_ci } 1423f9f848faSopenharmony_ci DPRINTF("Could not set address " 1424f9f848faSopenharmony_ci "for slot %u.\n", index); 1425f9f848faSopenharmony_ci if (address != 0) 1426f9f848faSopenharmony_ci break; 1427f9f848faSopenharmony_ci } 1428f9f848faSopenharmony_ci 1429f9f848faSopenharmony_ci /* update device address to new value */ 1430f9f848faSopenharmony_ci 1431f9f848faSopenharmony_ci usbd_get_page(&hdev->device_pc, 0, &buf_dev); 1432f9f848faSopenharmony_ci pdev = buf_dev.buffer; 1433f9f848faSopenharmony_ci usb_pc_cpu_invalidate(&hdev->device_pc); 1434f9f848faSopenharmony_ci 1435f9f848faSopenharmony_ci temp = xhci_ctx_get_le32(sc, &pdev->ctx_slot.dwSctx3); 1436f9f848faSopenharmony_ci udev->address = XHCI_SCTX_3_DEV_ADDR_GET(temp); 1437f9f848faSopenharmony_ci 1438f9f848faSopenharmony_ci /* update device state to new value */ 1439f9f848faSopenharmony_ci 1440f9f848faSopenharmony_ci if (address != 0) 1441f9f848faSopenharmony_ci hdev->state = XHCI_ST_ADDRESSED; 1442f9f848faSopenharmony_ci else 1443f9f848faSopenharmony_ci hdev->state = XHCI_ST_DEFAULT; 1444f9f848faSopenharmony_ci break; 1445f9f848faSopenharmony_ci 1446f9f848faSopenharmony_ci default: 1447f9f848faSopenharmony_ci DPRINTF("Wrong state for set address.\n"); 1448f9f848faSopenharmony_ci err = USB_ERR_IOERROR; 1449f9f848faSopenharmony_ci break; 1450f9f848faSopenharmony_ci } 1451f9f848faSopenharmony_ci XHCI_CMD_UNLOCK(sc); 1452f9f848faSopenharmony_ci 1453f9f848faSopenharmony_ci if (mtx != NULL) 1454f9f848faSopenharmony_ci mtx_lock(mtx); 1455f9f848faSopenharmony_ci 1456f9f848faSopenharmony_ci return (err); 1457f9f848faSopenharmony_ci} 1458f9f848faSopenharmony_ci 1459f9f848faSopenharmony_cistatic usb_error_t 1460f9f848faSopenharmony_cixhci_cmd_configure_ep(struct xhci_softc *sc, uint64_t input_ctx, 1461f9f848faSopenharmony_ci uint8_t deconfigure, uint8_t slot_id) 1462f9f848faSopenharmony_ci{ 1463f9f848faSopenharmony_ci struct xhci_trb trb; 1464f9f848faSopenharmony_ci uint32_t temp; 1465f9f848faSopenharmony_ci 1466f9f848faSopenharmony_ci DPRINTF("\n"); 1467f9f848faSopenharmony_ci 1468f9f848faSopenharmony_ci trb.qwTrb0 = htole64(input_ctx); 1469f9f848faSopenharmony_ci trb.dwTrb2 = 0; 1470f9f848faSopenharmony_ci temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_CONFIGURE_EP) | 1471f9f848faSopenharmony_ci XHCI_TRB_3_SLOT_SET(slot_id); 1472f9f848faSopenharmony_ci 1473f9f848faSopenharmony_ci if (deconfigure) 1474f9f848faSopenharmony_ci temp |= XHCI_TRB_3_DCEP_BIT; 1475f9f848faSopenharmony_ci 1476f9f848faSopenharmony_ci trb.dwTrb3 = htole32(temp); 1477f9f848faSopenharmony_ci 1478f9f848faSopenharmony_ci return (xhci_do_command(sc, &trb, XHCI_DO_CMD_TIMEOUT/* ms */)); 1479f9f848faSopenharmony_ci} 1480f9f848faSopenharmony_ci 1481f9f848faSopenharmony_cistatic usb_error_t 1482f9f848faSopenharmony_cixhci_cmd_evaluate_ctx(struct xhci_softc *sc, uint64_t input_ctx, 1483f9f848faSopenharmony_ci uint8_t slot_id) 1484f9f848faSopenharmony_ci{ 1485f9f848faSopenharmony_ci struct xhci_trb trb; 1486f9f848faSopenharmony_ci uint32_t temp; 1487f9f848faSopenharmony_ci 1488f9f848faSopenharmony_ci DPRINTF("\n"); 1489f9f848faSopenharmony_ci 1490f9f848faSopenharmony_ci trb.qwTrb0 = htole64(input_ctx); 1491f9f848faSopenharmony_ci trb.dwTrb2 = 0; 1492f9f848faSopenharmony_ci temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_EVALUATE_CTX) | 1493f9f848faSopenharmony_ci XHCI_TRB_3_SLOT_SET(slot_id); 1494f9f848faSopenharmony_ci trb.dwTrb3 = htole32(temp); 1495f9f848faSopenharmony_ci 1496f9f848faSopenharmony_ci return (xhci_do_command(sc, &trb, XHCI_DO_CMD_TIMEOUT/* ms */)); 1497f9f848faSopenharmony_ci} 1498f9f848faSopenharmony_ci 1499f9f848faSopenharmony_cistatic usb_error_t 1500f9f848faSopenharmony_cixhci_cmd_reset_ep(struct xhci_softc *sc, uint8_t preserve, 1501f9f848faSopenharmony_ci uint8_t ep_id, uint8_t slot_id) 1502f9f848faSopenharmony_ci{ 1503f9f848faSopenharmony_ci struct xhci_trb trb; 1504f9f848faSopenharmony_ci uint32_t temp; 1505f9f848faSopenharmony_ci 1506f9f848faSopenharmony_ci DPRINTF("\n"); 1507f9f848faSopenharmony_ci 1508f9f848faSopenharmony_ci trb.qwTrb0 = 0; 1509f9f848faSopenharmony_ci trb.dwTrb2 = 0; 1510f9f848faSopenharmony_ci temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_RESET_EP) | 1511f9f848faSopenharmony_ci XHCI_TRB_3_SLOT_SET(slot_id) | 1512f9f848faSopenharmony_ci XHCI_TRB_3_EP_SET(ep_id); 1513f9f848faSopenharmony_ci 1514f9f848faSopenharmony_ci if (preserve) 1515f9f848faSopenharmony_ci temp |= XHCI_TRB_3_PRSV_BIT; 1516f9f848faSopenharmony_ci 1517f9f848faSopenharmony_ci trb.dwTrb3 = htole32(temp); 1518f9f848faSopenharmony_ci 1519f9f848faSopenharmony_ci return (xhci_do_command(sc, &trb, XHCI_DO_CMD_TIMEOUT/* ms */)); 1520f9f848faSopenharmony_ci} 1521f9f848faSopenharmony_ci 1522f9f848faSopenharmony_cistatic usb_error_t 1523f9f848faSopenharmony_cixhci_cmd_set_tr_dequeue_ptr(struct xhci_softc *sc, uint64_t dequeue_ptr, 1524f9f848faSopenharmony_ci uint16_t stream_id, uint8_t ep_id, uint8_t slot_id) 1525f9f848faSopenharmony_ci{ 1526f9f848faSopenharmony_ci struct xhci_trb trb; 1527f9f848faSopenharmony_ci uint32_t temp; 1528f9f848faSopenharmony_ci 1529f9f848faSopenharmony_ci DPRINTF("\n"); 1530f9f848faSopenharmony_ci 1531f9f848faSopenharmony_ci trb.qwTrb0 = htole64(dequeue_ptr); 1532f9f848faSopenharmony_ci 1533f9f848faSopenharmony_ci temp = XHCI_TRB_2_STREAM_SET(stream_id); 1534f9f848faSopenharmony_ci trb.dwTrb2 = htole32(temp); 1535f9f848faSopenharmony_ci 1536f9f848faSopenharmony_ci temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_SET_TR_DEQUEUE) | 1537f9f848faSopenharmony_ci XHCI_TRB_3_SLOT_SET(slot_id) | 1538f9f848faSopenharmony_ci XHCI_TRB_3_EP_SET(ep_id); 1539f9f848faSopenharmony_ci trb.dwTrb3 = htole32(temp); 1540f9f848faSopenharmony_ci 1541f9f848faSopenharmony_ci return (xhci_do_command(sc, &trb, XHCI_DO_CMD_TIMEOUT/* ms */)); 1542f9f848faSopenharmony_ci} 1543f9f848faSopenharmony_ci 1544f9f848faSopenharmony_cistatic usb_error_t 1545f9f848faSopenharmony_cixhci_cmd_stop_ep(struct xhci_softc *sc, uint8_t suspend, 1546f9f848faSopenharmony_ci uint8_t ep_id, uint8_t slot_id) 1547f9f848faSopenharmony_ci{ 1548f9f848faSopenharmony_ci struct xhci_trb trb; 1549f9f848faSopenharmony_ci uint32_t temp; 1550f9f848faSopenharmony_ci 1551f9f848faSopenharmony_ci DPRINTF("\n"); 1552f9f848faSopenharmony_ci 1553f9f848faSopenharmony_ci trb.qwTrb0 = 0; 1554f9f848faSopenharmony_ci trb.dwTrb2 = 0; 1555f9f848faSopenharmony_ci temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_STOP_EP) | 1556f9f848faSopenharmony_ci XHCI_TRB_3_SLOT_SET(slot_id) | 1557f9f848faSopenharmony_ci XHCI_TRB_3_EP_SET(ep_id); 1558f9f848faSopenharmony_ci 1559f9f848faSopenharmony_ci if (suspend) 1560f9f848faSopenharmony_ci temp |= XHCI_TRB_3_SUSP_EP_BIT; 1561f9f848faSopenharmony_ci 1562f9f848faSopenharmony_ci trb.dwTrb3 = htole32(temp); 1563f9f848faSopenharmony_ci 1564f9f848faSopenharmony_ci return (xhci_do_command(sc, &trb, XHCI_DO_CMD_TIMEOUT/* ms */)); 1565f9f848faSopenharmony_ci} 1566f9f848faSopenharmony_ci 1567f9f848faSopenharmony_cistatic usb_error_t 1568f9f848faSopenharmony_cixhci_cmd_reset_dev(struct xhci_softc *sc, uint8_t slot_id) 1569f9f848faSopenharmony_ci{ 1570f9f848faSopenharmony_ci struct xhci_trb trb; 1571f9f848faSopenharmony_ci uint32_t temp; 1572f9f848faSopenharmony_ci 1573f9f848faSopenharmony_ci DPRINTF("\n"); 1574f9f848faSopenharmony_ci 1575f9f848faSopenharmony_ci trb.qwTrb0 = 0; 1576f9f848faSopenharmony_ci trb.dwTrb2 = 0; 1577f9f848faSopenharmony_ci temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_RESET_DEVICE) | 1578f9f848faSopenharmony_ci XHCI_TRB_3_SLOT_SET(slot_id); 1579f9f848faSopenharmony_ci 1580f9f848faSopenharmony_ci trb.dwTrb3 = htole32(temp); 1581f9f848faSopenharmony_ci 1582f9f848faSopenharmony_ci return (xhci_do_command(sc, &trb, XHCI_DO_CMD_TIMEOUT/* ms */)); 1583f9f848faSopenharmony_ci} 1584f9f848faSopenharmony_ci 1585f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 1586f9f848faSopenharmony_ci * xhci_interrupt - XHCI interrupt handler 1587f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 1588f9f848faSopenharmony_civoid 1589f9f848faSopenharmony_cixhci_interrupt(unsigned int irq, struct xhci_softc *sc) 1590f9f848faSopenharmony_ci{ 1591f9f848faSopenharmony_ci uint32_t status; 1592f9f848faSopenharmony_ci uint32_t temp; 1593f9f848faSopenharmony_ci 1594f9f848faSopenharmony_ci USB_BUS_LOCK(&sc->sc_bus); 1595f9f848faSopenharmony_ci 1596f9f848faSopenharmony_ci status = XREAD4(sc, oper, XHCI_USBSTS); 1597f9f848faSopenharmony_ci 1598f9f848faSopenharmony_ci /* acknowledge interrupts, if any */ 1599f9f848faSopenharmony_ci if (status != 0) { 1600f9f848faSopenharmony_ci XWRITE4(sc, oper, XHCI_USBSTS, status); 1601f9f848faSopenharmony_ci DPRINTFN(16, "real interrupt (status=0x%08x)\n", status); 1602f9f848faSopenharmony_ci } 1603f9f848faSopenharmony_ci 1604f9f848faSopenharmony_ci temp = XREAD4(sc, runt, XHCI_IMAN(0)); 1605f9f848faSopenharmony_ci 1606f9f848faSopenharmony_ci /* force clearing of pending interrupts */ 1607f9f848faSopenharmony_ci if (temp & XHCI_IMAN_INTR_PEND) 1608f9f848faSopenharmony_ci XWRITE4(sc, runt, XHCI_IMAN(0), temp); 1609f9f848faSopenharmony_ci 1610f9f848faSopenharmony_ci /* check for event(s) */ 1611f9f848faSopenharmony_ci (void)xhci_interrupt_poll(sc); 1612f9f848faSopenharmony_ci 1613f9f848faSopenharmony_ci if (status & (XHCI_STS_PCD | XHCI_STS_HCH | 1614f9f848faSopenharmony_ci XHCI_STS_HSE | XHCI_STS_HCE)) { 1615f9f848faSopenharmony_ci if (status & XHCI_STS_PCD) { 1616f9f848faSopenharmony_ci xhci_root_intr(sc); 1617f9f848faSopenharmony_ci } 1618f9f848faSopenharmony_ci 1619f9f848faSopenharmony_ci if (status & XHCI_STS_HCH) { 1620f9f848faSopenharmony_ci PRINTK("%s: host controller halted\n", 1621f9f848faSopenharmony_ci __FUNCTION__); 1622f9f848faSopenharmony_ci } 1623f9f848faSopenharmony_ci 1624f9f848faSopenharmony_ci if (status & XHCI_STS_HSE) { 1625f9f848faSopenharmony_ci PRINTK("%s: host system error\n", 1626f9f848faSopenharmony_ci __FUNCTION__); 1627f9f848faSopenharmony_ci } 1628f9f848faSopenharmony_ci 1629f9f848faSopenharmony_ci if (status & XHCI_STS_HCE) { 1630f9f848faSopenharmony_ci PRINTK("%s: host controller error\n", 1631f9f848faSopenharmony_ci __FUNCTION__); 1632f9f848faSopenharmony_ci } 1633f9f848faSopenharmony_ci } 1634f9f848faSopenharmony_ci USB_BUS_UNLOCK(&sc->sc_bus); 1635f9f848faSopenharmony_ci} 1636f9f848faSopenharmony_ci 1637f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 1638f9f848faSopenharmony_ci * xhci_timeout - XHCI timeout handler 1639f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 1640f9f848faSopenharmony_cistatic void 1641f9f848faSopenharmony_cixhci_timeout(void *arg) 1642f9f848faSopenharmony_ci{ 1643f9f848faSopenharmony_ci struct usb_xfer *xfer = arg; 1644f9f848faSopenharmony_ci 1645f9f848faSopenharmony_ci DPRINTF("xfer=%p\n", xfer); 1646f9f848faSopenharmony_ci 1647f9f848faSopenharmony_ci USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED); 1648f9f848faSopenharmony_ci 1649f9f848faSopenharmony_ci /* transfer is transferred */ 1650f9f848faSopenharmony_ci xhci_device_done(xfer, USB_ERR_TIMEOUT); 1651f9f848faSopenharmony_ci} 1652f9f848faSopenharmony_ci 1653f9f848faSopenharmony_cistatic void 1654f9f848faSopenharmony_cixhci_do_poll(struct usb_bus *bus) 1655f9f848faSopenharmony_ci{ 1656f9f848faSopenharmony_ci struct xhci_softc *sc = XHCI_BUS2SC(bus); 1657f9f848faSopenharmony_ci 1658f9f848faSopenharmony_ci USB_BUS_LOCK(&sc->sc_bus); 1659f9f848faSopenharmony_ci (void)xhci_interrupt_poll(sc); 1660f9f848faSopenharmony_ci USB_BUS_UNLOCK(&sc->sc_bus); 1661f9f848faSopenharmony_ci} 1662f9f848faSopenharmony_ci 1663f9f848faSopenharmony_cistatic void 1664f9f848faSopenharmony_cixhci_setup_generic_chain_sub(struct xhci_std_temp *temp) 1665f9f848faSopenharmony_ci{ 1666f9f848faSopenharmony_ci struct usb_page_search buf_res; 1667f9f848faSopenharmony_ci struct xhci_td *td; 1668f9f848faSopenharmony_ci struct xhci_td *td_next; 1669f9f848faSopenharmony_ci struct xhci_td *td_alt_next; 1670f9f848faSopenharmony_ci struct xhci_td *td_first; 1671f9f848faSopenharmony_ci uint32_t buf_offset; 1672f9f848faSopenharmony_ci uint32_t average; 1673f9f848faSopenharmony_ci uint32_t len_old; 1674f9f848faSopenharmony_ci uint32_t npkt_off; 1675f9f848faSopenharmony_ci uint32_t dword; 1676f9f848faSopenharmony_ci uint8_t shortpkt_old; 1677f9f848faSopenharmony_ci uint8_t precompute; 1678f9f848faSopenharmony_ci uint8_t x; 1679f9f848faSopenharmony_ci 1680f9f848faSopenharmony_ci td_alt_next = NULL; 1681f9f848faSopenharmony_ci buf_offset = 0; 1682f9f848faSopenharmony_ci shortpkt_old = temp->shortpkt; 1683f9f848faSopenharmony_ci len_old = temp->len; 1684f9f848faSopenharmony_ci npkt_off = 0; 1685f9f848faSopenharmony_ci precompute = 1; 1686f9f848faSopenharmony_ci 1687f9f848faSopenharmony_cirestart: 1688f9f848faSopenharmony_ci 1689f9f848faSopenharmony_ci td = temp->td; 1690f9f848faSopenharmony_ci td_next = td_first = temp->td_next; 1691f9f848faSopenharmony_ci 1692f9f848faSopenharmony_ci while (1) { 1693f9f848faSopenharmony_ci if (temp->len == 0) { 1694f9f848faSopenharmony_ci if (temp->shortpkt) 1695f9f848faSopenharmony_ci break; 1696f9f848faSopenharmony_ci 1697f9f848faSopenharmony_ci /* send a Zero Length Packet, ZLP, last */ 1698f9f848faSopenharmony_ci 1699f9f848faSopenharmony_ci temp->shortpkt = 1; 1700f9f848faSopenharmony_ci average = 0; 1701f9f848faSopenharmony_ci 1702f9f848faSopenharmony_ci } else { 1703f9f848faSopenharmony_ci average = temp->average; 1704f9f848faSopenharmony_ci 1705f9f848faSopenharmony_ci if (temp->len < average) { 1706f9f848faSopenharmony_ci if (temp->len % temp->max_packet_size) { 1707f9f848faSopenharmony_ci temp->shortpkt = 1; 1708f9f848faSopenharmony_ci } 1709f9f848faSopenharmony_ci average = temp->len; 1710f9f848faSopenharmony_ci } 1711f9f848faSopenharmony_ci } 1712f9f848faSopenharmony_ci 1713f9f848faSopenharmony_ci if (td_next == NULL) 1714f9f848faSopenharmony_ci panic("%s: out of XHCI transfer descriptors!", __FUNCTION__); 1715f9f848faSopenharmony_ci 1716f9f848faSopenharmony_ci /* get next TD */ 1717f9f848faSopenharmony_ci 1718f9f848faSopenharmony_ci td = td_next; 1719f9f848faSopenharmony_ci td_next = td->obj_next; 1720f9f848faSopenharmony_ci 1721f9f848faSopenharmony_ci /* check if we are pre-computing */ 1722f9f848faSopenharmony_ci 1723f9f848faSopenharmony_ci if (precompute) { 1724f9f848faSopenharmony_ci /* update remaining length */ 1725f9f848faSopenharmony_ci 1726f9f848faSopenharmony_ci temp->len -= average; 1727f9f848faSopenharmony_ci 1728f9f848faSopenharmony_ci continue; 1729f9f848faSopenharmony_ci } 1730f9f848faSopenharmony_ci /* fill out current TD */ 1731f9f848faSopenharmony_ci 1732f9f848faSopenharmony_ci td->len = average; 1733f9f848faSopenharmony_ci td->remainder = 0; 1734f9f848faSopenharmony_ci td->status = 0; 1735f9f848faSopenharmony_ci 1736f9f848faSopenharmony_ci /* update remaining length */ 1737f9f848faSopenharmony_ci 1738f9f848faSopenharmony_ci temp->len -= average; 1739f9f848faSopenharmony_ci 1740f9f848faSopenharmony_ci /* reset TRB index */ 1741f9f848faSopenharmony_ci 1742f9f848faSopenharmony_ci x = 0; 1743f9f848faSopenharmony_ci 1744f9f848faSopenharmony_ci if (temp->trb_type == XHCI_TRB_TYPE_SETUP_STAGE) { 1745f9f848faSopenharmony_ci /* immediate data */ 1746f9f848faSopenharmony_ci 1747f9f848faSopenharmony_ci if (average > 8) 1748f9f848faSopenharmony_ci average = 8; 1749f9f848faSopenharmony_ci 1750f9f848faSopenharmony_ci td->td_trb[0].qwTrb0 = 0; 1751f9f848faSopenharmony_ci 1752f9f848faSopenharmony_ci usbd_copy_out(temp->pc, temp->offset + buf_offset, 1753f9f848faSopenharmony_ci (uint8_t *)(uintptr_t)&td->td_trb[0].qwTrb0, 1754f9f848faSopenharmony_ci average); 1755f9f848faSopenharmony_ci 1756f9f848faSopenharmony_ci dword = XHCI_TRB_2_BYTES_SET(8) | 1757f9f848faSopenharmony_ci XHCI_TRB_2_TDSZ_SET(0) | 1758f9f848faSopenharmony_ci XHCI_TRB_2_IRQ_SET(0); 1759f9f848faSopenharmony_ci 1760f9f848faSopenharmony_ci td->td_trb[0].dwTrb2 = htole32(dword); 1761f9f848faSopenharmony_ci 1762f9f848faSopenharmony_ci dword = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_SETUP_STAGE) | 1763f9f848faSopenharmony_ci XHCI_TRB_3_IDT_BIT | XHCI_TRB_3_CYCLE_BIT; 1764f9f848faSopenharmony_ci 1765f9f848faSopenharmony_ci /* check wLength */ 1766f9f848faSopenharmony_ci if (td->td_trb[0].qwTrb0 & 1767f9f848faSopenharmony_ci htole64(XHCI_TRB_0_WLENGTH_MASK)) { 1768f9f848faSopenharmony_ci if (td->td_trb[0].qwTrb0 & 1769f9f848faSopenharmony_ci htole64(XHCI_TRB_0_DIR_IN_MASK)) 1770f9f848faSopenharmony_ci dword |= XHCI_TRB_3_TRT_IN; 1771f9f848faSopenharmony_ci else 1772f9f848faSopenharmony_ci dword |= XHCI_TRB_3_TRT_OUT; 1773f9f848faSopenharmony_ci } 1774f9f848faSopenharmony_ci 1775f9f848faSopenharmony_ci td->td_trb[0].dwTrb3 = htole32(dword); 1776f9f848faSopenharmony_ci#ifdef USB_DEBUG 1777f9f848faSopenharmony_ci xhci_dump_trb(&td->td_trb[x]); 1778f9f848faSopenharmony_ci#endif 1779f9f848faSopenharmony_ci x++; 1780f9f848faSopenharmony_ci 1781f9f848faSopenharmony_ci } else do { 1782f9f848faSopenharmony_ci uint32_t npkt; 1783f9f848faSopenharmony_ci 1784f9f848faSopenharmony_ci /* fill out buffer pointers */ 1785f9f848faSopenharmony_ci 1786f9f848faSopenharmony_ci if (average == 0) { 1787f9f848faSopenharmony_ci (void)memset_s(&buf_res, sizeof(buf_res), 0, sizeof(buf_res)); 1788f9f848faSopenharmony_ci } else { 1789f9f848faSopenharmony_ci usbd_get_page(temp->pc, temp->offset + 1790f9f848faSopenharmony_ci buf_offset, &buf_res); 1791f9f848faSopenharmony_ci 1792f9f848faSopenharmony_ci /* get length to end of page */ 1793f9f848faSopenharmony_ci if (buf_res.length > average) 1794f9f848faSopenharmony_ci buf_res.length = average; 1795f9f848faSopenharmony_ci 1796f9f848faSopenharmony_ci /* check for maximum length */ 1797f9f848faSopenharmony_ci if (buf_res.length > XHCI_TD_PAGE_SIZE) 1798f9f848faSopenharmony_ci buf_res.length = XHCI_TD_PAGE_SIZE; 1799f9f848faSopenharmony_ci 1800f9f848faSopenharmony_ci npkt_off += buf_res.length; 1801f9f848faSopenharmony_ci } 1802f9f848faSopenharmony_ci 1803f9f848faSopenharmony_ci /* set up npkt */ 1804f9f848faSopenharmony_ci npkt = (len_old - npkt_off + temp->max_packet_size - 1) / 1805f9f848faSopenharmony_ci temp->max_packet_size; 1806f9f848faSopenharmony_ci 1807f9f848faSopenharmony_ci if (npkt == 0) 1808f9f848faSopenharmony_ci npkt = 1; 1809f9f848faSopenharmony_ci else if (npkt > 31) 1810f9f848faSopenharmony_ci npkt = 31; 1811f9f848faSopenharmony_ci 1812f9f848faSopenharmony_ci /* fill out TRB's */ 1813f9f848faSopenharmony_ci td->td_trb[x].qwTrb0 = 1814f9f848faSopenharmony_ci htole64((uint64_t)buf_res.physaddr); 1815f9f848faSopenharmony_ci 1816f9f848faSopenharmony_ci dword = 1817f9f848faSopenharmony_ci XHCI_TRB_2_BYTES_SET(buf_res.length) | 1818f9f848faSopenharmony_ci XHCI_TRB_2_TDSZ_SET(npkt) | 1819f9f848faSopenharmony_ci XHCI_TRB_2_IRQ_SET(0); 1820f9f848faSopenharmony_ci 1821f9f848faSopenharmony_ci td->td_trb[x].dwTrb2 = htole32(dword); 1822f9f848faSopenharmony_ci 1823f9f848faSopenharmony_ci switch (temp->trb_type) { 1824f9f848faSopenharmony_ci case XHCI_TRB_TYPE_ISOCH: 1825f9f848faSopenharmony_ci dword = XHCI_TRB_3_CHAIN_BIT | XHCI_TRB_3_CYCLE_BIT | 1826f9f848faSopenharmony_ci XHCI_TRB_3_TBC_SET(temp->tbc) | 1827f9f848faSopenharmony_ci XHCI_TRB_3_TLBPC_SET(temp->tlbpc); 1828f9f848faSopenharmony_ci if (td != td_first) { 1829f9f848faSopenharmony_ci dword |= XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_NORMAL); 1830f9f848faSopenharmony_ci } else if (temp->do_isoc_sync != 0) { 1831f9f848faSopenharmony_ci temp->do_isoc_sync = 0; 1832f9f848faSopenharmony_ci /* wait until "isoc_frame" */ 1833f9f848faSopenharmony_ci dword |= XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_ISOCH) | 1834f9f848faSopenharmony_ci XHCI_TRB_3_FRID_SET(temp->isoc_frame / 8); 1835f9f848faSopenharmony_ci } else { 1836f9f848faSopenharmony_ci /* start data transfer at next interval */ 1837f9f848faSopenharmony_ci dword |= XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_ISOCH) | 1838f9f848faSopenharmony_ci XHCI_TRB_3_ISO_SIA_BIT; 1839f9f848faSopenharmony_ci } 1840f9f848faSopenharmony_ci if (temp->direction == UE_DIR_IN) 1841f9f848faSopenharmony_ci dword |= XHCI_TRB_3_ISP_BIT; 1842f9f848faSopenharmony_ci break; 1843f9f848faSopenharmony_ci case XHCI_TRB_TYPE_DATA_STAGE: 1844f9f848faSopenharmony_ci dword = XHCI_TRB_3_CHAIN_BIT | XHCI_TRB_3_CYCLE_BIT | 1845f9f848faSopenharmony_ci XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_DATA_STAGE); 1846f9f848faSopenharmony_ci if (temp->direction == UE_DIR_IN) 1847f9f848faSopenharmony_ci dword |= XHCI_TRB_3_DIR_IN | XHCI_TRB_3_ISP_BIT; 1848f9f848faSopenharmony_ci /* 1849f9f848faSopenharmony_ci * Section 3.2.9 in the XHCI 1850f9f848faSopenharmony_ci * specification about control 1851f9f848faSopenharmony_ci * transfers says that we should use a 1852f9f848faSopenharmony_ci * normal-TRB if there are more TRBs 1853f9f848faSopenharmony_ci * extending the data-stage 1854f9f848faSopenharmony_ci * TRB. Update the "trb_type". 1855f9f848faSopenharmony_ci */ 1856f9f848faSopenharmony_ci temp->trb_type = XHCI_TRB_TYPE_NORMAL; 1857f9f848faSopenharmony_ci break; 1858f9f848faSopenharmony_ci case XHCI_TRB_TYPE_STATUS_STAGE: 1859f9f848faSopenharmony_ci dword = XHCI_TRB_3_CHAIN_BIT | XHCI_TRB_3_CYCLE_BIT | 1860f9f848faSopenharmony_ci XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_STATUS_STAGE); 1861f9f848faSopenharmony_ci if (temp->direction == UE_DIR_IN) 1862f9f848faSopenharmony_ci dword |= XHCI_TRB_3_DIR_IN; 1863f9f848faSopenharmony_ci break; 1864f9f848faSopenharmony_ci default: /* XHCI_TRB_TYPE_NORMAL */ 1865f9f848faSopenharmony_ci dword = XHCI_TRB_3_CHAIN_BIT | XHCI_TRB_3_CYCLE_BIT | 1866f9f848faSopenharmony_ci XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_NORMAL); 1867f9f848faSopenharmony_ci if (temp->direction == UE_DIR_IN) 1868f9f848faSopenharmony_ci dword |= XHCI_TRB_3_ISP_BIT; 1869f9f848faSopenharmony_ci break; 1870f9f848faSopenharmony_ci } 1871f9f848faSopenharmony_ci td->td_trb[x].dwTrb3 = htole32(dword); 1872f9f848faSopenharmony_ci 1873f9f848faSopenharmony_ci average -= buf_res.length; 1874f9f848faSopenharmony_ci buf_offset += buf_res.length; 1875f9f848faSopenharmony_ci#ifdef USB_DEBUG 1876f9f848faSopenharmony_ci xhci_dump_trb(&td->td_trb[x]); 1877f9f848faSopenharmony_ci#endif 1878f9f848faSopenharmony_ci x++; 1879f9f848faSopenharmony_ci 1880f9f848faSopenharmony_ci } while (average != 0); 1881f9f848faSopenharmony_ci 1882f9f848faSopenharmony_ci td->td_trb[x-1].dwTrb3 |= htole32(XHCI_TRB_3_IOC_BIT); 1883f9f848faSopenharmony_ci 1884f9f848faSopenharmony_ci /* store number of data TRB's */ 1885f9f848faSopenharmony_ci 1886f9f848faSopenharmony_ci td->ntrb = x; 1887f9f848faSopenharmony_ci 1888f9f848faSopenharmony_ci DPRINTF("NTRB=%u\n", x); 1889f9f848faSopenharmony_ci 1890f9f848faSopenharmony_ci /* fill out link TRB */ 1891f9f848faSopenharmony_ci 1892f9f848faSopenharmony_ci if (td_next != NULL) { 1893f9f848faSopenharmony_ci /* link the current TD with the next one */ 1894f9f848faSopenharmony_ci td->td_trb[x].qwTrb0 = htole64((uint64_t)td_next->td_self); 1895f9f848faSopenharmony_ci DPRINTF("LINK=0x%08llx\n", (long long)td_next->td_self); 1896f9f848faSopenharmony_ci } else { 1897f9f848faSopenharmony_ci /* this field will get updated later */ 1898f9f848faSopenharmony_ci DPRINTF("NOLINK\n"); 1899f9f848faSopenharmony_ci } 1900f9f848faSopenharmony_ci 1901f9f848faSopenharmony_ci dword = XHCI_TRB_2_IRQ_SET(0); 1902f9f848faSopenharmony_ci 1903f9f848faSopenharmony_ci td->td_trb[x].dwTrb2 = htole32(dword); 1904f9f848faSopenharmony_ci 1905f9f848faSopenharmony_ci dword = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_LINK) | 1906f9f848faSopenharmony_ci XHCI_TRB_3_CYCLE_BIT | XHCI_TRB_3_IOC_BIT | 1907f9f848faSopenharmony_ci /* 1908f9f848faSopenharmony_ci * CHAIN-BIT: Ensure that a multi-TRB IN-endpoint 1909f9f848faSopenharmony_ci * frame only receives a single short packet event 1910f9f848faSopenharmony_ci * by setting the CHAIN bit in the LINK field. In 1911f9f848faSopenharmony_ci * addition some XHCI controllers have problems 1912f9f848faSopenharmony_ci * sending a ZLP unless the CHAIN-BIT is set in 1913f9f848faSopenharmony_ci * the LINK TRB. 1914f9f848faSopenharmony_ci */ 1915f9f848faSopenharmony_ci XHCI_TRB_3_CHAIN_BIT; 1916f9f848faSopenharmony_ci 1917f9f848faSopenharmony_ci td->td_trb[x].dwTrb3 = htole32(dword); 1918f9f848faSopenharmony_ci 1919f9f848faSopenharmony_ci td->alt_next = td_alt_next; 1920f9f848faSopenharmony_ci#ifdef USB_DEBUG 1921f9f848faSopenharmony_ci xhci_dump_trb(&td->td_trb[x]); 1922f9f848faSopenharmony_ci#endif 1923f9f848faSopenharmony_ci usb_pc_cpu_flush(td->page_cache); 1924f9f848faSopenharmony_ci } 1925f9f848faSopenharmony_ci 1926f9f848faSopenharmony_ci if (precompute) { 1927f9f848faSopenharmony_ci precompute = 0; 1928f9f848faSopenharmony_ci 1929f9f848faSopenharmony_ci /* set up alt next pointer, if any */ 1930f9f848faSopenharmony_ci if (temp->last_frame) { 1931f9f848faSopenharmony_ci td_alt_next = NULL; 1932f9f848faSopenharmony_ci } else { 1933f9f848faSopenharmony_ci /* we use this field internally */ 1934f9f848faSopenharmony_ci td_alt_next = td_next; 1935f9f848faSopenharmony_ci } 1936f9f848faSopenharmony_ci 1937f9f848faSopenharmony_ci /* restore */ 1938f9f848faSopenharmony_ci temp->shortpkt = shortpkt_old; 1939f9f848faSopenharmony_ci temp->len = len_old; 1940f9f848faSopenharmony_ci goto restart; 1941f9f848faSopenharmony_ci } 1942f9f848faSopenharmony_ci 1943f9f848faSopenharmony_ci /* 1944f9f848faSopenharmony_ci * Remove cycle bit from the first TRB if we are 1945f9f848faSopenharmony_ci * stepping them: 1946f9f848faSopenharmony_ci */ 1947f9f848faSopenharmony_ci if (temp->step_td != 0) { 1948f9f848faSopenharmony_ci td_first->td_trb[0].dwTrb3 &= ~htole32(XHCI_TRB_3_CYCLE_BIT); 1949f9f848faSopenharmony_ci usb_pc_cpu_flush(td_first->page_cache); 1950f9f848faSopenharmony_ci } 1951f9f848faSopenharmony_ci 1952f9f848faSopenharmony_ci /* clear TD SIZE to zero, hence this is the last TRB */ 1953f9f848faSopenharmony_ci /* remove chain bit because this is the last data TRB in the chain */ 1954f9f848faSopenharmony_ci td->td_trb[td->ntrb - 1].dwTrb2 &= ~htole32(XHCI_TRB_2_TDSZ_SET(15)); 1955f9f848faSopenharmony_ci td->td_trb[td->ntrb - 1].dwTrb3 &= ~htole32(XHCI_TRB_3_CHAIN_BIT); 1956f9f848faSopenharmony_ci /* remove CHAIN-BIT from last LINK TRB */ 1957f9f848faSopenharmony_ci td->td_trb[td->ntrb].dwTrb3 &= ~htole32(XHCI_TRB_3_CHAIN_BIT); 1958f9f848faSopenharmony_ci 1959f9f848faSopenharmony_ci usb_pc_cpu_flush(td->page_cache); 1960f9f848faSopenharmony_ci 1961f9f848faSopenharmony_ci temp->td = td; 1962f9f848faSopenharmony_ci temp->td_next = td_next; 1963f9f848faSopenharmony_ci} 1964f9f848faSopenharmony_ci 1965f9f848faSopenharmony_cistatic void 1966f9f848faSopenharmony_cixhci_setup_generic_chain(struct usb_xfer *xfer) 1967f9f848faSopenharmony_ci{ 1968f9f848faSopenharmony_ci struct xhci_std_temp temp; 1969f9f848faSopenharmony_ci struct xhci_td *td; 1970f9f848faSopenharmony_ci uint32_t x; 1971f9f848faSopenharmony_ci uint32_t y; 1972f9f848faSopenharmony_ci uint8_t mult; 1973f9f848faSopenharmony_ci 1974f9f848faSopenharmony_ci temp.do_isoc_sync = 0; 1975f9f848faSopenharmony_ci temp.step_td = 0; 1976f9f848faSopenharmony_ci temp.tbc = 0; 1977f9f848faSopenharmony_ci temp.tlbpc = 0; 1978f9f848faSopenharmony_ci temp.average = xfer->max_hc_frame_size; 1979f9f848faSopenharmony_ci temp.max_packet_size = xfer->max_packet_size; 1980f9f848faSopenharmony_ci temp.sc = XHCI_BUS2SC(xfer->xroot->bus); 1981f9f848faSopenharmony_ci temp.pc = NULL; 1982f9f848faSopenharmony_ci temp.last_frame = 0; 1983f9f848faSopenharmony_ci temp.offset = 0; 1984f9f848faSopenharmony_ci temp.multishort = xfer->flags_int.isochronous_xfr || 1985f9f848faSopenharmony_ci xfer->flags_int.control_xfr || 1986f9f848faSopenharmony_ci xfer->flags_int.short_frames_ok; 1987f9f848faSopenharmony_ci 1988f9f848faSopenharmony_ci /* toggle the DMA set we are using */ 1989f9f848faSopenharmony_ci xfer->flags_int.curr_dma_set ^= 1; 1990f9f848faSopenharmony_ci 1991f9f848faSopenharmony_ci /* get next DMA set */ 1992f9f848faSopenharmony_ci td = xfer->td_start[xfer->flags_int.curr_dma_set]; 1993f9f848faSopenharmony_ci 1994f9f848faSopenharmony_ci temp.td = NULL; 1995f9f848faSopenharmony_ci temp.td_next = td; 1996f9f848faSopenharmony_ci 1997f9f848faSopenharmony_ci xfer->td_transfer_first = td; 1998f9f848faSopenharmony_ci xfer->td_transfer_cache = td; 1999f9f848faSopenharmony_ci 2000f9f848faSopenharmony_ci if (xfer->flags_int.isochronous_xfr) { 2001f9f848faSopenharmony_ci uint8_t shift; 2002f9f848faSopenharmony_ci 2003f9f848faSopenharmony_ci /* compute multiplier for ISOCHRONOUS transfers */ 2004f9f848faSopenharmony_ci mult = xfer->endpoint->ecomp ? 2005f9f848faSopenharmony_ci UE_GET_SS_ISO_MULT(xfer->endpoint->ecomp->bmAttributes) 2006f9f848faSopenharmony_ci : 0; 2007f9f848faSopenharmony_ci /* check for USB 2.0 multiplier */ 2008f9f848faSopenharmony_ci if (mult == 0) { 2009f9f848faSopenharmony_ci mult = (xfer->endpoint->edesc-> 2010f9f848faSopenharmony_ci wMaxPacketSize[1] >> 3) & 3; 2011f9f848faSopenharmony_ci } 2012f9f848faSopenharmony_ci /* range check */ 2013f9f848faSopenharmony_ci if (mult > 2) 2014f9f848faSopenharmony_ci mult = 3; 2015f9f848faSopenharmony_ci else 2016f9f848faSopenharmony_ci mult++; 2017f9f848faSopenharmony_ci 2018f9f848faSopenharmony_ci x = XREAD4(temp.sc, runt, XHCI_MFINDEX); 2019f9f848faSopenharmony_ci 2020f9f848faSopenharmony_ci DPRINTF("MFINDEX=0x%08x\n", x); 2021f9f848faSopenharmony_ci 2022f9f848faSopenharmony_ci switch (usbd_get_speed(xfer->xroot->udev)) { 2023f9f848faSopenharmony_ci case USB_SPEED_FULL: 2024f9f848faSopenharmony_ci shift = 3; 2025f9f848faSopenharmony_ci temp.isoc_delta = 8; /* 1ms */ 2026f9f848faSopenharmony_ci x += temp.isoc_delta - 1; 2027f9f848faSopenharmony_ci x &= ~(temp.isoc_delta - 1); 2028f9f848faSopenharmony_ci break; 2029f9f848faSopenharmony_ci default: 2030f9f848faSopenharmony_ci shift = usbd_xfer_get_fps_shift(xfer); 2031f9f848faSopenharmony_ci temp.isoc_delta = 1U << shift; 2032f9f848faSopenharmony_ci x += temp.isoc_delta - 1; 2033f9f848faSopenharmony_ci x &= ~(temp.isoc_delta - 1); 2034f9f848faSopenharmony_ci /* simple frame load balancing */ 2035f9f848faSopenharmony_ci x += xfer->endpoint->usb_uframe; 2036f9f848faSopenharmony_ci break; 2037f9f848faSopenharmony_ci } 2038f9f848faSopenharmony_ci 2039f9f848faSopenharmony_ci y = XHCI_MFINDEX_GET(x - xfer->endpoint->isoc_next); 2040f9f848faSopenharmony_ci 2041f9f848faSopenharmony_ci if ((xfer->endpoint->is_synced == 0) || 2042f9f848faSopenharmony_ci (y < (xfer->nframes << shift)) || 2043f9f848faSopenharmony_ci (XHCI_MFINDEX_GET(-y) >= (128 * 8))) { 2044f9f848faSopenharmony_ci /* 2045f9f848faSopenharmony_ci * If there is data underflow or the pipe 2046f9f848faSopenharmony_ci * queue is empty we schedule the transfer a 2047f9f848faSopenharmony_ci * few frames ahead of the current frame 2048f9f848faSopenharmony_ci * position. Else two isochronous transfers 2049f9f848faSopenharmony_ci * might overlap. 2050f9f848faSopenharmony_ci */ 2051f9f848faSopenharmony_ci xfer->endpoint->isoc_next = XHCI_MFINDEX_GET(x + (3 * 8)); 2052f9f848faSopenharmony_ci xfer->endpoint->is_synced = 1; 2053f9f848faSopenharmony_ci temp.do_isoc_sync = 1; 2054f9f848faSopenharmony_ci 2055f9f848faSopenharmony_ci DPRINTFN(3, "start next=%d\n", xfer->endpoint->isoc_next); 2056f9f848faSopenharmony_ci } 2057f9f848faSopenharmony_ci 2058f9f848faSopenharmony_ci /* compute isochronous completion time */ 2059f9f848faSopenharmony_ci 2060f9f848faSopenharmony_ci y = XHCI_MFINDEX_GET(xfer->endpoint->isoc_next - (x & ~7)); 2061f9f848faSopenharmony_ci 2062f9f848faSopenharmony_ci xfer->isoc_time_complete = 2063f9f848faSopenharmony_ci usb_isoc_time_expand(&temp.sc->sc_bus, x / 8) + 2064f9f848faSopenharmony_ci (y / 8) + (((xfer->nframes << shift) + 7) / 8); 2065f9f848faSopenharmony_ci 2066f9f848faSopenharmony_ci x = 0; 2067f9f848faSopenharmony_ci temp.isoc_frame = xfer->endpoint->isoc_next; 2068f9f848faSopenharmony_ci temp.trb_type = XHCI_TRB_TYPE_ISOCH; 2069f9f848faSopenharmony_ci 2070f9f848faSopenharmony_ci xfer->endpoint->isoc_next += xfer->nframes << shift; 2071f9f848faSopenharmony_ci 2072f9f848faSopenharmony_ci } else if (xfer->flags_int.control_xfr) { 2073f9f848faSopenharmony_ci /* check if we should prepend a setup message */ 2074f9f848faSopenharmony_ci 2075f9f848faSopenharmony_ci if (xfer->flags_int.control_hdr) { 2076f9f848faSopenharmony_ci temp.len = xfer->frlengths[0]; 2077f9f848faSopenharmony_ci temp.pc = xfer->frbuffers + 0; 2078f9f848faSopenharmony_ci temp.shortpkt = temp.len ? 1 : 0; 2079f9f848faSopenharmony_ci temp.trb_type = XHCI_TRB_TYPE_SETUP_STAGE; 2080f9f848faSopenharmony_ci temp.direction = 0; 2081f9f848faSopenharmony_ci 2082f9f848faSopenharmony_ci /* check for last frame */ 2083f9f848faSopenharmony_ci if (xfer->nframes == 1) { 2084f9f848faSopenharmony_ci /* no STATUS stage yet, SETUP is last */ 2085f9f848faSopenharmony_ci if (xfer->flags_int.control_act) 2086f9f848faSopenharmony_ci temp.last_frame = 1; 2087f9f848faSopenharmony_ci } 2088f9f848faSopenharmony_ci 2089f9f848faSopenharmony_ci xhci_setup_generic_chain_sub(&temp); 2090f9f848faSopenharmony_ci } 2091f9f848faSopenharmony_ci x = 1; 2092f9f848faSopenharmony_ci mult = 1; 2093f9f848faSopenharmony_ci temp.isoc_delta = 0; 2094f9f848faSopenharmony_ci temp.isoc_frame = 0; 2095f9f848faSopenharmony_ci temp.trb_type = xfer->flags_int.control_did_data ? 2096f9f848faSopenharmony_ci XHCI_TRB_TYPE_NORMAL : XHCI_TRB_TYPE_DATA_STAGE; 2097f9f848faSopenharmony_ci } else { 2098f9f848faSopenharmony_ci x = 0; 2099f9f848faSopenharmony_ci mult = 1; 2100f9f848faSopenharmony_ci temp.isoc_delta = 0; 2101f9f848faSopenharmony_ci temp.isoc_frame = 0; 2102f9f848faSopenharmony_ci temp.trb_type = XHCI_TRB_TYPE_NORMAL; 2103f9f848faSopenharmony_ci } 2104f9f848faSopenharmony_ci 2105f9f848faSopenharmony_ci if (x != xfer->nframes) { 2106f9f848faSopenharmony_ci /* set up page_cache pointer */ 2107f9f848faSopenharmony_ci temp.pc = xfer->frbuffers + x; 2108f9f848faSopenharmony_ci /* set endpoint direction */ 2109f9f848faSopenharmony_ci temp.direction = UE_GET_DIR(xfer->endpointno); 2110f9f848faSopenharmony_ci } 2111f9f848faSopenharmony_ci 2112f9f848faSopenharmony_ci while (x != xfer->nframes) { 2113f9f848faSopenharmony_ci /* DATA0 / DATA1 message */ 2114f9f848faSopenharmony_ci 2115f9f848faSopenharmony_ci temp.len = xfer->frlengths[x]; 2116f9f848faSopenharmony_ci temp.step_td = ((xfer->endpointno & UE_DIR_IN) && 2117f9f848faSopenharmony_ci x != 0 && temp.multishort == 0); 2118f9f848faSopenharmony_ci 2119f9f848faSopenharmony_ci x++; 2120f9f848faSopenharmony_ci 2121f9f848faSopenharmony_ci if (x == xfer->nframes) { 2122f9f848faSopenharmony_ci if (xfer->flags_int.control_xfr) { 2123f9f848faSopenharmony_ci /* no STATUS stage yet, DATA is last */ 2124f9f848faSopenharmony_ci if (xfer->flags_int.control_act) 2125f9f848faSopenharmony_ci temp.last_frame = 1; 2126f9f848faSopenharmony_ci } else { 2127f9f848faSopenharmony_ci temp.last_frame = 1; 2128f9f848faSopenharmony_ci } 2129f9f848faSopenharmony_ci } 2130f9f848faSopenharmony_ci if (temp.len == 0) { 2131f9f848faSopenharmony_ci /* make sure that we send an USB packet */ 2132f9f848faSopenharmony_ci 2133f9f848faSopenharmony_ci temp.shortpkt = 0; 2134f9f848faSopenharmony_ci 2135f9f848faSopenharmony_ci temp.tbc = 0; 2136f9f848faSopenharmony_ci temp.tlbpc = mult - 1; 2137f9f848faSopenharmony_ci 2138f9f848faSopenharmony_ci } else if (xfer->flags_int.isochronous_xfr) { 2139f9f848faSopenharmony_ci uint8_t tdpc; 2140f9f848faSopenharmony_ci 2141f9f848faSopenharmony_ci /* 2142f9f848faSopenharmony_ci * Isochronous transfers don't have short 2143f9f848faSopenharmony_ci * packet termination: 2144f9f848faSopenharmony_ci */ 2145f9f848faSopenharmony_ci 2146f9f848faSopenharmony_ci temp.shortpkt = 1; 2147f9f848faSopenharmony_ci 2148f9f848faSopenharmony_ci /* isochronous transfers have a transfer limit */ 2149f9f848faSopenharmony_ci 2150f9f848faSopenharmony_ci if (temp.len > xfer->max_frame_size) 2151f9f848faSopenharmony_ci temp.len = xfer->max_frame_size; 2152f9f848faSopenharmony_ci 2153f9f848faSopenharmony_ci /* compute TD packet count */ 2154f9f848faSopenharmony_ci tdpc = (temp.len + xfer->max_packet_size - 1) / 2155f9f848faSopenharmony_ci xfer->max_packet_size; 2156f9f848faSopenharmony_ci 2157f9f848faSopenharmony_ci temp.tbc = ((tdpc + mult - 1) / mult) - 1; 2158f9f848faSopenharmony_ci temp.tlbpc = (tdpc % mult); 2159f9f848faSopenharmony_ci 2160f9f848faSopenharmony_ci if (temp.tlbpc == 0) 2161f9f848faSopenharmony_ci temp.tlbpc = mult - 1; 2162f9f848faSopenharmony_ci else 2163f9f848faSopenharmony_ci temp.tlbpc--; 2164f9f848faSopenharmony_ci } else { 2165f9f848faSopenharmony_ci /* regular data transfer */ 2166f9f848faSopenharmony_ci 2167f9f848faSopenharmony_ci temp.shortpkt = xfer->flags.force_short_xfer ? 0 : 1; 2168f9f848faSopenharmony_ci } 2169f9f848faSopenharmony_ci 2170f9f848faSopenharmony_ci xhci_setup_generic_chain_sub(&temp); 2171f9f848faSopenharmony_ci 2172f9f848faSopenharmony_ci if (xfer->flags_int.isochronous_xfr) { 2173f9f848faSopenharmony_ci temp.offset += xfer->frlengths[x - 1]; 2174f9f848faSopenharmony_ci temp.isoc_frame += temp.isoc_delta; 2175f9f848faSopenharmony_ci } else { 2176f9f848faSopenharmony_ci /* get next Page Cache pointer */ 2177f9f848faSopenharmony_ci temp.pc = xfer->frbuffers + x; 2178f9f848faSopenharmony_ci } 2179f9f848faSopenharmony_ci } 2180f9f848faSopenharmony_ci 2181f9f848faSopenharmony_ci /* check if we should append a status stage */ 2182f9f848faSopenharmony_ci 2183f9f848faSopenharmony_ci if (xfer->flags_int.control_xfr && 2184f9f848faSopenharmony_ci !xfer->flags_int.control_act) { 2185f9f848faSopenharmony_ci /* 2186f9f848faSopenharmony_ci * Send a DATA1 message and invert the current 2187f9f848faSopenharmony_ci * endpoint direction. 2188f9f848faSopenharmony_ci */ 2189f9f848faSopenharmony_ci if (xhcictlstep || temp.sc->sc_ctlstep) { 2190f9f848faSopenharmony_ci /* 2191f9f848faSopenharmony_ci * Some XHCI controllers will not delay the 2192f9f848faSopenharmony_ci * status stage until the next SOF. Force this 2193f9f848faSopenharmony_ci * behaviour to avoid failed control 2194f9f848faSopenharmony_ci * transfers. 2195f9f848faSopenharmony_ci */ 2196f9f848faSopenharmony_ci temp.step_td = (xfer->nframes != 0); 2197f9f848faSopenharmony_ci } else { 2198f9f848faSopenharmony_ci temp.step_td = 0; 2199f9f848faSopenharmony_ci } 2200f9f848faSopenharmony_ci temp.direction = UE_GET_DIR(xfer->endpointno) ^ UE_DIR_IN; 2201f9f848faSopenharmony_ci temp.len = 0; 2202f9f848faSopenharmony_ci temp.pc = NULL; 2203f9f848faSopenharmony_ci temp.shortpkt = 0; 2204f9f848faSopenharmony_ci temp.last_frame = 1; 2205f9f848faSopenharmony_ci temp.trb_type = XHCI_TRB_TYPE_STATUS_STAGE; 2206f9f848faSopenharmony_ci 2207f9f848faSopenharmony_ci xhci_setup_generic_chain_sub(&temp); 2208f9f848faSopenharmony_ci } 2209f9f848faSopenharmony_ci 2210f9f848faSopenharmony_ci td = temp.td; 2211f9f848faSopenharmony_ci 2212f9f848faSopenharmony_ci /* must have at least one frame! */ 2213f9f848faSopenharmony_ci 2214f9f848faSopenharmony_ci xfer->td_transfer_last = td; 2215f9f848faSopenharmony_ci 2216f9f848faSopenharmony_ci DPRINTF("first=%p last=%p\n", xfer->td_transfer_first, td); 2217f9f848faSopenharmony_ci} 2218f9f848faSopenharmony_ci 2219f9f848faSopenharmony_cistatic void 2220f9f848faSopenharmony_cixhci_set_slot_pointer(struct xhci_softc *sc, uint8_t index, uint64_t dev_addr) 2221f9f848faSopenharmony_ci{ 2222f9f848faSopenharmony_ci struct usb_page_search buf_res; 2223f9f848faSopenharmony_ci struct xhci_dev_ctx_addr *pdctxa; 2224f9f848faSopenharmony_ci 2225f9f848faSopenharmony_ci usbd_get_page(&sc->sc_hw.ctx_pc, 0, &buf_res); 2226f9f848faSopenharmony_ci 2227f9f848faSopenharmony_ci pdctxa = buf_res.buffer; 2228f9f848faSopenharmony_ci 2229f9f848faSopenharmony_ci DPRINTF("addr[%u]=0x%016llx\n", index, (long long)dev_addr); 2230f9f848faSopenharmony_ci 2231f9f848faSopenharmony_ci pdctxa->qwBaaDevCtxAddr[index] = htole64(dev_addr); 2232f9f848faSopenharmony_ci 2233f9f848faSopenharmony_ci usb_pc_cpu_flush(&sc->sc_hw.ctx_pc); 2234f9f848faSopenharmony_ci} 2235f9f848faSopenharmony_ci 2236f9f848faSopenharmony_cistatic usb_error_t 2237f9f848faSopenharmony_cixhci_configure_mask(struct usb_device *udev, uint32_t mask, uint8_t drop) 2238f9f848faSopenharmony_ci{ 2239f9f848faSopenharmony_ci struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); 2240f9f848faSopenharmony_ci struct usb_page_search buf_inp; 2241f9f848faSopenharmony_ci struct xhci_input_dev_ctx *pinp; 2242f9f848faSopenharmony_ci uint32_t temp; 2243f9f848faSopenharmony_ci uint8_t index; 2244f9f848faSopenharmony_ci uint8_t x; 2245f9f848faSopenharmony_ci 2246f9f848faSopenharmony_ci index = udev->controller_slot_id; 2247f9f848faSopenharmony_ci 2248f9f848faSopenharmony_ci usbd_get_page(&sc->sc_hw.devs[index].input_pc, 0, &buf_inp); 2249f9f848faSopenharmony_ci 2250f9f848faSopenharmony_ci pinp = buf_inp.buffer; 2251f9f848faSopenharmony_ci 2252f9f848faSopenharmony_ci if (drop) { 2253f9f848faSopenharmony_ci mask &= XHCI_INCTX_NON_CTRL_MASK; 2254f9f848faSopenharmony_ci xhci_ctx_set_le32(sc, &pinp->ctx_input.dwInCtx0, mask); 2255f9f848faSopenharmony_ci xhci_ctx_set_le32(sc, &pinp->ctx_input.dwInCtx1, 0); 2256f9f848faSopenharmony_ci } else { 2257f9f848faSopenharmony_ci /* 2258f9f848faSopenharmony_ci * Some hardware requires that we drop the endpoint 2259f9f848faSopenharmony_ci * context before adding it again: 2260f9f848faSopenharmony_ci */ 2261f9f848faSopenharmony_ci xhci_ctx_set_le32(sc, &pinp->ctx_input.dwInCtx0, 2262f9f848faSopenharmony_ci mask & XHCI_INCTX_NON_CTRL_MASK); 2263f9f848faSopenharmony_ci 2264f9f848faSopenharmony_ci /* Add new endpoint context */ 2265f9f848faSopenharmony_ci xhci_ctx_set_le32(sc, &pinp->ctx_input.dwInCtx1, mask); 2266f9f848faSopenharmony_ci 2267f9f848faSopenharmony_ci /* find most significant set bit */ 2268f9f848faSopenharmony_ci for (x = 31; x != 1; x--) { 2269f9f848faSopenharmony_ci if (mask & (1 << x)) 2270f9f848faSopenharmony_ci break; 2271f9f848faSopenharmony_ci } 2272f9f848faSopenharmony_ci 2273f9f848faSopenharmony_ci /* adjust */ 2274f9f848faSopenharmony_ci x--; 2275f9f848faSopenharmony_ci 2276f9f848faSopenharmony_ci /* figure out the maximum number of contexts */ 2277f9f848faSopenharmony_ci if (x > sc->sc_hw.devs[index].context_num) 2278f9f848faSopenharmony_ci sc->sc_hw.devs[index].context_num = x; 2279f9f848faSopenharmony_ci else 2280f9f848faSopenharmony_ci x = sc->sc_hw.devs[index].context_num; 2281f9f848faSopenharmony_ci 2282f9f848faSopenharmony_ci /* update number of contexts */ 2283f9f848faSopenharmony_ci temp = xhci_ctx_get_le32(sc, &pinp->ctx_slot.dwSctx0); 2284f9f848faSopenharmony_ci temp &= ~XHCI_SCTX_0_CTX_NUM_SET(31); 2285f9f848faSopenharmony_ci temp |= XHCI_SCTX_0_CTX_NUM_SET(x + 1); 2286f9f848faSopenharmony_ci xhci_ctx_set_le32(sc, &pinp->ctx_slot.dwSctx0, temp); 2287f9f848faSopenharmony_ci } 2288f9f848faSopenharmony_ci usb_pc_cpu_flush(&sc->sc_hw.devs[index].input_pc); 2289f9f848faSopenharmony_ci return (USB_ERR_NORMAL_COMPLETION); 2290f9f848faSopenharmony_ci} 2291f9f848faSopenharmony_ci 2292f9f848faSopenharmony_cistatic usb_error_t 2293f9f848faSopenharmony_cixhci_configure_endpoint(struct usb_device *udev, 2294f9f848faSopenharmony_ci struct usb_endpoint_descriptor *edesc, struct xhci_endpoint_ext *pepext, 2295f9f848faSopenharmony_ci uint16_t interval, uint8_t max_packet_count, 2296f9f848faSopenharmony_ci uint8_t mult, uint8_t fps_shift, uint16_t max_packet_size, 2297f9f848faSopenharmony_ci uint16_t max_frame_size, uint8_t ep_mode) 2298f9f848faSopenharmony_ci{ 2299f9f848faSopenharmony_ci struct usb_page_search buf_inp; 2300f9f848faSopenharmony_ci struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); 2301f9f848faSopenharmony_ci struct xhci_input_dev_ctx *pinp; 2302f9f848faSopenharmony_ci uint64_t ring_addr = pepext->physaddr; 2303f9f848faSopenharmony_ci uint32_t temp; 2304f9f848faSopenharmony_ci uint8_t index; 2305f9f848faSopenharmony_ci uint8_t epno; 2306f9f848faSopenharmony_ci uint8_t type; 2307f9f848faSopenharmony_ci 2308f9f848faSopenharmony_ci index = udev->controller_slot_id; 2309f9f848faSopenharmony_ci 2310f9f848faSopenharmony_ci usbd_get_page(&sc->sc_hw.devs[index].input_pc, 0, &buf_inp); 2311f9f848faSopenharmony_ci 2312f9f848faSopenharmony_ci pinp = buf_inp.buffer; 2313f9f848faSopenharmony_ci 2314f9f848faSopenharmony_ci epno = edesc->bEndpointAddress; 2315f9f848faSopenharmony_ci type = edesc->bmAttributes & UE_XFERTYPE; 2316f9f848faSopenharmony_ci 2317f9f848faSopenharmony_ci if (type == UE_CONTROL) 2318f9f848faSopenharmony_ci epno |= UE_DIR_IN; 2319f9f848faSopenharmony_ci 2320f9f848faSopenharmony_ci epno = XHCI_EPNO2EPID(epno); 2321f9f848faSopenharmony_ci 2322f9f848faSopenharmony_ci if (epno == 0) 2323f9f848faSopenharmony_ci return (USB_ERR_NO_PIPE); /* invalid */ 2324f9f848faSopenharmony_ci 2325f9f848faSopenharmony_ci if (max_packet_count == 0) 2326f9f848faSopenharmony_ci return (USB_ERR_BAD_BUFSIZE); 2327f9f848faSopenharmony_ci 2328f9f848faSopenharmony_ci max_packet_count--; 2329f9f848faSopenharmony_ci 2330f9f848faSopenharmony_ci if (mult == 0) 2331f9f848faSopenharmony_ci return (USB_ERR_BAD_BUFSIZE); 2332f9f848faSopenharmony_ci 2333f9f848faSopenharmony_ci /* store endpoint mode */ 2334f9f848faSopenharmony_ci pepext->trb_ep_mode = ep_mode; 2335f9f848faSopenharmony_ci /* store bMaxPacketSize for control endpoints */ 2336f9f848faSopenharmony_ci pepext->trb_ep_maxp = edesc->wMaxPacketSize[0]; 2337f9f848faSopenharmony_ci usb_pc_cpu_flush(pepext->page_cache); 2338f9f848faSopenharmony_ci 2339f9f848faSopenharmony_ci if (ep_mode == USB_EP_MODE_STREAMS) { 2340f9f848faSopenharmony_ci temp = XHCI_EPCTX_0_EPSTATE_SET(0) | 2341f9f848faSopenharmony_ci XHCI_EPCTX_0_MAXP_STREAMS_SET(XHCI_MAX_STREAMS_LOG - 1) | 2342f9f848faSopenharmony_ci XHCI_EPCTX_0_LSA_SET(1); 2343f9f848faSopenharmony_ci 2344f9f848faSopenharmony_ci ring_addr += sizeof(struct xhci_trb) * 2345f9f848faSopenharmony_ci XHCI_MAX_TRANSFERS * XHCI_MAX_STREAMS; 2346f9f848faSopenharmony_ci } else { 2347f9f848faSopenharmony_ci temp = XHCI_EPCTX_0_EPSTATE_SET(0) | 2348f9f848faSopenharmony_ci XHCI_EPCTX_0_MAXP_STREAMS_SET(0) | 2349f9f848faSopenharmony_ci XHCI_EPCTX_0_LSA_SET(0); 2350f9f848faSopenharmony_ci 2351f9f848faSopenharmony_ci ring_addr |= XHCI_EPCTX_2_DCS_SET(1); 2352f9f848faSopenharmony_ci } 2353f9f848faSopenharmony_ci 2354f9f848faSopenharmony_ci switch (udev->speed) { 2355f9f848faSopenharmony_ci case USB_SPEED_FULL: 2356f9f848faSopenharmony_ci case USB_SPEED_LOW: 2357f9f848faSopenharmony_ci /* 1ms -> 125us */ 2358f9f848faSopenharmony_ci fps_shift += 3; 2359f9f848faSopenharmony_ci break; 2360f9f848faSopenharmony_ci default: 2361f9f848faSopenharmony_ci break; 2362f9f848faSopenharmony_ci } 2363f9f848faSopenharmony_ci 2364f9f848faSopenharmony_ci switch (type) { 2365f9f848faSopenharmony_ci case UE_INTERRUPT: 2366f9f848faSopenharmony_ci if (fps_shift > 3) 2367f9f848faSopenharmony_ci fps_shift--; 2368f9f848faSopenharmony_ci temp |= XHCI_EPCTX_0_IVAL_SET(fps_shift); 2369f9f848faSopenharmony_ci break; 2370f9f848faSopenharmony_ci case UE_ISOCHRONOUS: 2371f9f848faSopenharmony_ci temp |= XHCI_EPCTX_0_IVAL_SET(fps_shift); 2372f9f848faSopenharmony_ci 2373f9f848faSopenharmony_ci switch (udev->speed) { 2374f9f848faSopenharmony_ci case USB_SPEED_SUPER: 2375f9f848faSopenharmony_ci if (mult > 3) 2376f9f848faSopenharmony_ci mult = 3; 2377f9f848faSopenharmony_ci temp |= XHCI_EPCTX_0_MULT_SET(mult - 1); 2378f9f848faSopenharmony_ci max_packet_count /= mult; 2379f9f848faSopenharmony_ci break; 2380f9f848faSopenharmony_ci default: 2381f9f848faSopenharmony_ci break; 2382f9f848faSopenharmony_ci } 2383f9f848faSopenharmony_ci break; 2384f9f848faSopenharmony_ci default: 2385f9f848faSopenharmony_ci break; 2386f9f848faSopenharmony_ci } 2387f9f848faSopenharmony_ci 2388f9f848faSopenharmony_ci xhci_ctx_set_le32(sc, &pinp->ctx_ep[epno - 1].dwEpCtx0, temp); 2389f9f848faSopenharmony_ci 2390f9f848faSopenharmony_ci temp = 2391f9f848faSopenharmony_ci XHCI_EPCTX_1_HID_SET(0) | 2392f9f848faSopenharmony_ci XHCI_EPCTX_1_MAXB_SET(max_packet_count) | 2393f9f848faSopenharmony_ci XHCI_EPCTX_1_MAXP_SIZE_SET(max_packet_size); 2394f9f848faSopenharmony_ci 2395f9f848faSopenharmony_ci /* 2396f9f848faSopenharmony_ci * Always enable the "three strikes and you are gone" feature 2397f9f848faSopenharmony_ci * except for ISOCHRONOUS endpoints. This is suggested by 2398f9f848faSopenharmony_ci * section 4.3.3 in the XHCI specification about device slot 2399f9f848faSopenharmony_ci * initialisation. 2400f9f848faSopenharmony_ci */ 2401f9f848faSopenharmony_ci if (type != UE_ISOCHRONOUS) 2402f9f848faSopenharmony_ci temp |= XHCI_EPCTX_1_CERR_SET(3); 2403f9f848faSopenharmony_ci 2404f9f848faSopenharmony_ci switch (type) { 2405f9f848faSopenharmony_ci case UE_CONTROL: 2406f9f848faSopenharmony_ci temp |= XHCI_EPCTX_1_EPTYPE_SET(4); 2407f9f848faSopenharmony_ci break; 2408f9f848faSopenharmony_ci case UE_ISOCHRONOUS: 2409f9f848faSopenharmony_ci temp |= XHCI_EPCTX_1_EPTYPE_SET(1); 2410f9f848faSopenharmony_ci break; 2411f9f848faSopenharmony_ci case UE_BULK: 2412f9f848faSopenharmony_ci temp |= XHCI_EPCTX_1_EPTYPE_SET(2); 2413f9f848faSopenharmony_ci break; 2414f9f848faSopenharmony_ci default: 2415f9f848faSopenharmony_ci temp |= XHCI_EPCTX_1_EPTYPE_SET(3); 2416f9f848faSopenharmony_ci break; 2417f9f848faSopenharmony_ci } 2418f9f848faSopenharmony_ci 2419f9f848faSopenharmony_ci /* check for IN direction */ 2420f9f848faSopenharmony_ci if (epno & 1) 2421f9f848faSopenharmony_ci temp |= XHCI_EPCTX_1_EPTYPE_SET(4); 2422f9f848faSopenharmony_ci 2423f9f848faSopenharmony_ci xhci_ctx_set_le32(sc, &pinp->ctx_ep[epno - 1].dwEpCtx1, temp); 2424f9f848faSopenharmony_ci xhci_ctx_set_le64(sc, &pinp->ctx_ep[epno - 1].qwEpCtx2, ring_addr); 2425f9f848faSopenharmony_ci 2426f9f848faSopenharmony_ci switch (edesc->bmAttributes & UE_XFERTYPE) { 2427f9f848faSopenharmony_ci case UE_INTERRUPT: 2428f9f848faSopenharmony_ci case UE_ISOCHRONOUS: 2429f9f848faSopenharmony_ci temp = XHCI_EPCTX_4_MAX_ESIT_PAYLOAD_SET(max_frame_size) | 2430f9f848faSopenharmony_ci XHCI_EPCTX_4_AVG_TRB_LEN_SET(MIN(XHCI_PAGE_SIZE, 2431f9f848faSopenharmony_ci max_frame_size)); 2432f9f848faSopenharmony_ci break; 2433f9f848faSopenharmony_ci case UE_CONTROL: 2434f9f848faSopenharmony_ci temp = XHCI_EPCTX_4_AVG_TRB_LEN_SET(8); 2435f9f848faSopenharmony_ci break; 2436f9f848faSopenharmony_ci default: 2437f9f848faSopenharmony_ci temp = XHCI_EPCTX_4_AVG_TRB_LEN_SET(XHCI_PAGE_SIZE); 2438f9f848faSopenharmony_ci break; 2439f9f848faSopenharmony_ci } 2440f9f848faSopenharmony_ci 2441f9f848faSopenharmony_ci xhci_ctx_set_le32(sc, &pinp->ctx_ep[epno - 1].dwEpCtx4, temp); 2442f9f848faSopenharmony_ci 2443f9f848faSopenharmony_ci#ifdef USB_DEBUG 2444f9f848faSopenharmony_ci xhci_dump_endpoint(sc, &pinp->ctx_ep[epno - 1]); 2445f9f848faSopenharmony_ci#endif 2446f9f848faSopenharmony_ci usb_pc_cpu_flush(&sc->sc_hw.devs[index].input_pc); 2447f9f848faSopenharmony_ci 2448f9f848faSopenharmony_ci return (USB_ERR_NORMAL_COMPLETION); /* success */ 2449f9f848faSopenharmony_ci} 2450f9f848faSopenharmony_ci 2451f9f848faSopenharmony_cistatic usb_error_t 2452f9f848faSopenharmony_cixhci_configure_endpoint_by_xfer(struct usb_xfer *xfer) 2453f9f848faSopenharmony_ci{ 2454f9f848faSopenharmony_ci struct xhci_endpoint_ext *pepext; 2455f9f848faSopenharmony_ci struct usb_endpoint_ss_comp_descriptor *ecomp; 2456f9f848faSopenharmony_ci usb_stream_t x; 2457f9f848faSopenharmony_ci 2458f9f848faSopenharmony_ci pepext = xhci_get_endpoint_ext(xfer->xroot->udev, 2459f9f848faSopenharmony_ci xfer->endpoint->edesc); 2460f9f848faSopenharmony_ci 2461f9f848faSopenharmony_ci ecomp = xfer->endpoint->ecomp; 2462f9f848faSopenharmony_ci 2463f9f848faSopenharmony_ci for (x = 0; x != XHCI_MAX_STREAMS; x++) { 2464f9f848faSopenharmony_ci uint64_t temp; 2465f9f848faSopenharmony_ci 2466f9f848faSopenharmony_ci /* halt any transfers */ 2467f9f848faSopenharmony_ci pepext->trb[x * XHCI_MAX_TRANSFERS].dwTrb3 = 0; 2468f9f848faSopenharmony_ci 2469f9f848faSopenharmony_ci /* compute start of TRB ring for stream "x" */ 2470f9f848faSopenharmony_ci temp = pepext->physaddr + 2471f9f848faSopenharmony_ci (x * XHCI_MAX_TRANSFERS * sizeof(struct xhci_trb)) + 2472f9f848faSopenharmony_ci XHCI_SCTX_0_SCT_SEC_TR_RING; 2473f9f848faSopenharmony_ci 2474f9f848faSopenharmony_ci /* make tree structure */ 2475f9f848faSopenharmony_ci pepext->trb[(XHCI_MAX_TRANSFERS * 2476f9f848faSopenharmony_ci XHCI_MAX_STREAMS) + x].qwTrb0 = htole64(temp); 2477f9f848faSopenharmony_ci 2478f9f848faSopenharmony_ci /* reserved fields */ 2479f9f848faSopenharmony_ci pepext->trb[(XHCI_MAX_TRANSFERS * 2480f9f848faSopenharmony_ci XHCI_MAX_STREAMS) + x].dwTrb2 = 0; 2481f9f848faSopenharmony_ci pepext->trb[(XHCI_MAX_TRANSFERS * 2482f9f848faSopenharmony_ci XHCI_MAX_STREAMS) + x].dwTrb3 = 0; 2483f9f848faSopenharmony_ci } 2484f9f848faSopenharmony_ci usb_pc_cpu_flush(pepext->page_cache); 2485f9f848faSopenharmony_ci 2486f9f848faSopenharmony_ci return (xhci_configure_endpoint(xfer->xroot->udev, 2487f9f848faSopenharmony_ci xfer->endpoint->edesc, pepext, 2488f9f848faSopenharmony_ci xfer->interval, xfer->max_packet_count, 2489f9f848faSopenharmony_ci (ecomp != NULL) ? UE_GET_SS_ISO_MULT(ecomp->bmAttributes) + 1 : 1, 2490f9f848faSopenharmony_ci usbd_xfer_get_fps_shift(xfer), xfer->max_packet_size, 2491f9f848faSopenharmony_ci xfer->max_frame_size, xfer->endpoint->ep_mode)); 2492f9f848faSopenharmony_ci} 2493f9f848faSopenharmony_ci 2494f9f848faSopenharmony_cistatic usb_error_t 2495f9f848faSopenharmony_cixhci_configure_device(struct usb_device *udev) 2496f9f848faSopenharmony_ci{ 2497f9f848faSopenharmony_ci struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); 2498f9f848faSopenharmony_ci struct usb_page_search buf_inp; 2499f9f848faSopenharmony_ci struct usb_page_cache *pcinp; 2500f9f848faSopenharmony_ci struct xhci_input_dev_ctx *pinp; 2501f9f848faSopenharmony_ci struct usb_device *hubdev; 2502f9f848faSopenharmony_ci uint32_t temp; 2503f9f848faSopenharmony_ci uint32_t route; 2504f9f848faSopenharmony_ci uint32_t rh_port; 2505f9f848faSopenharmony_ci uint8_t is_hub; 2506f9f848faSopenharmony_ci uint8_t index; 2507f9f848faSopenharmony_ci uint8_t depth; 2508f9f848faSopenharmony_ci 2509f9f848faSopenharmony_ci index = udev->controller_slot_id; 2510f9f848faSopenharmony_ci 2511f9f848faSopenharmony_ci DPRINTF("index=%u\n", index); 2512f9f848faSopenharmony_ci 2513f9f848faSopenharmony_ci pcinp = &sc->sc_hw.devs[index].input_pc; 2514f9f848faSopenharmony_ci 2515f9f848faSopenharmony_ci usbd_get_page(pcinp, 0, &buf_inp); 2516f9f848faSopenharmony_ci 2517f9f848faSopenharmony_ci pinp = buf_inp.buffer; 2518f9f848faSopenharmony_ci 2519f9f848faSopenharmony_ci rh_port = 0; 2520f9f848faSopenharmony_ci route = 0; 2521f9f848faSopenharmony_ci 2522f9f848faSopenharmony_ci /* figure out route string and root HUB port number */ 2523f9f848faSopenharmony_ci 2524f9f848faSopenharmony_ci for (hubdev = udev; hubdev != NULL; hubdev = hubdev->parent_hub) { 2525f9f848faSopenharmony_ci if (hubdev->parent_hub == NULL) 2526f9f848faSopenharmony_ci break; 2527f9f848faSopenharmony_ci 2528f9f848faSopenharmony_ci depth = hubdev->parent_hub->depth; 2529f9f848faSopenharmony_ci 2530f9f848faSopenharmony_ci /* 2531f9f848faSopenharmony_ci * NOTE: HS/FS/LS devices and the SS root HUB can have 2532f9f848faSopenharmony_ci * more than 15 ports 2533f9f848faSopenharmony_ci */ 2534f9f848faSopenharmony_ci 2535f9f848faSopenharmony_ci rh_port = hubdev->port_no; 2536f9f848faSopenharmony_ci 2537f9f848faSopenharmony_ci if (depth == 0) 2538f9f848faSopenharmony_ci break; 2539f9f848faSopenharmony_ci 2540f9f848faSopenharmony_ci if (rh_port > 15) 2541f9f848faSopenharmony_ci rh_port = 15; 2542f9f848faSopenharmony_ci 2543f9f848faSopenharmony_ci if (depth < 6) 2544f9f848faSopenharmony_ci route |= rh_port << (4 * (depth - 1)); 2545f9f848faSopenharmony_ci } 2546f9f848faSopenharmony_ci 2547f9f848faSopenharmony_ci DPRINTF("Route=0x%08x\n", route); 2548f9f848faSopenharmony_ci 2549f9f848faSopenharmony_ci temp = XHCI_SCTX_0_ROUTE_SET(route) | 2550f9f848faSopenharmony_ci XHCI_SCTX_0_CTX_NUM_SET( 2551f9f848faSopenharmony_ci sc->sc_hw.devs[index].context_num + 1); 2552f9f848faSopenharmony_ci 2553f9f848faSopenharmony_ci switch (udev->speed) { 2554f9f848faSopenharmony_ci case USB_SPEED_LOW: 2555f9f848faSopenharmony_ci temp |= XHCI_SCTX_0_SPEED_SET(2); 2556f9f848faSopenharmony_ci if ((udev->parent_hs_hub != NULL) && 2557f9f848faSopenharmony_ci (udev->parent_hs_hub->ddesc.bDeviceProtocol == 2558f9f848faSopenharmony_ci UDPROTO_HSHUBMTT)) { 2559f9f848faSopenharmony_ci DPRINTF("Device inherits MTT\n"); 2560f9f848faSopenharmony_ci temp |= XHCI_SCTX_0_MTT_SET(1); 2561f9f848faSopenharmony_ci } 2562f9f848faSopenharmony_ci break; 2563f9f848faSopenharmony_ci case USB_SPEED_HIGH: 2564f9f848faSopenharmony_ci temp |= XHCI_SCTX_0_SPEED_SET(3); 2565f9f848faSopenharmony_ci if ((sc->sc_hw.devs[index].nports != 0) && 2566f9f848faSopenharmony_ci (udev->ddesc.bDeviceProtocol == UDPROTO_HSHUBMTT)) { 2567f9f848faSopenharmony_ci DPRINTF("HUB supports MTT\n"); 2568f9f848faSopenharmony_ci temp |= XHCI_SCTX_0_MTT_SET(1); 2569f9f848faSopenharmony_ci } 2570f9f848faSopenharmony_ci break; 2571f9f848faSopenharmony_ci case USB_SPEED_FULL: 2572f9f848faSopenharmony_ci temp |= XHCI_SCTX_0_SPEED_SET(1); 2573f9f848faSopenharmony_ci if ((udev->parent_hs_hub != NULL) && 2574f9f848faSopenharmony_ci (udev->parent_hs_hub->ddesc.bDeviceProtocol == 2575f9f848faSopenharmony_ci UDPROTO_HSHUBMTT)) { 2576f9f848faSopenharmony_ci DPRINTF("Device inherits MTT\n"); 2577f9f848faSopenharmony_ci temp |= XHCI_SCTX_0_MTT_SET(1); 2578f9f848faSopenharmony_ci } 2579f9f848faSopenharmony_ci break; 2580f9f848faSopenharmony_ci default: 2581f9f848faSopenharmony_ci temp |= XHCI_SCTX_0_SPEED_SET(4); 2582f9f848faSopenharmony_ci break; 2583f9f848faSopenharmony_ci } 2584f9f848faSopenharmony_ci 2585f9f848faSopenharmony_ci is_hub = sc->sc_hw.devs[index].nports != 0 && 2586f9f848faSopenharmony_ci (udev->speed == USB_SPEED_SUPER || 2587f9f848faSopenharmony_ci udev->speed == USB_SPEED_HIGH); 2588f9f848faSopenharmony_ci 2589f9f848faSopenharmony_ci if (is_hub) 2590f9f848faSopenharmony_ci temp |= XHCI_SCTX_0_HUB_SET(1); 2591f9f848faSopenharmony_ci 2592f9f848faSopenharmony_ci xhci_ctx_set_le32(sc, &pinp->ctx_slot.dwSctx0, temp); 2593f9f848faSopenharmony_ci 2594f9f848faSopenharmony_ci temp = XHCI_SCTX_1_RH_PORT_SET(rh_port); 2595f9f848faSopenharmony_ci 2596f9f848faSopenharmony_ci if (is_hub) { 2597f9f848faSopenharmony_ci temp |= XHCI_SCTX_1_NUM_PORTS_SET( 2598f9f848faSopenharmony_ci sc->sc_hw.devs[index].nports); 2599f9f848faSopenharmony_ci } 2600f9f848faSopenharmony_ci 2601f9f848faSopenharmony_ci switch (udev->speed) { 2602f9f848faSopenharmony_ci case USB_SPEED_SUPER: 2603f9f848faSopenharmony_ci switch (sc->sc_hw.devs[index].state) { 2604f9f848faSopenharmony_ci case XHCI_ST_ADDRESSED: 2605f9f848faSopenharmony_ci case XHCI_ST_CONFIGURED: 2606f9f848faSopenharmony_ci /* enable power save */ 2607f9f848faSopenharmony_ci temp |= XHCI_SCTX_1_MAX_EL_SET(sc->sc_exit_lat_max); 2608f9f848faSopenharmony_ci break; 2609f9f848faSopenharmony_ci default: 2610f9f848faSopenharmony_ci /* disable power save */ 2611f9f848faSopenharmony_ci break; 2612f9f848faSopenharmony_ci } 2613f9f848faSopenharmony_ci break; 2614f9f848faSopenharmony_ci default: 2615f9f848faSopenharmony_ci break; 2616f9f848faSopenharmony_ci } 2617f9f848faSopenharmony_ci 2618f9f848faSopenharmony_ci xhci_ctx_set_le32(sc, &pinp->ctx_slot.dwSctx1, temp); 2619f9f848faSopenharmony_ci 2620f9f848faSopenharmony_ci temp = XHCI_SCTX_2_IRQ_TARGET_SET(0); 2621f9f848faSopenharmony_ci 2622f9f848faSopenharmony_ci if (is_hub) { 2623f9f848faSopenharmony_ci temp |= XHCI_SCTX_2_TT_THINK_TIME_SET( 2624f9f848faSopenharmony_ci sc->sc_hw.devs[index].tt); 2625f9f848faSopenharmony_ci } 2626f9f848faSopenharmony_ci 2627f9f848faSopenharmony_ci hubdev = udev->parent_hs_hub; 2628f9f848faSopenharmony_ci 2629f9f848faSopenharmony_ci /* check if we should activate the transaction translator */ 2630f9f848faSopenharmony_ci switch (udev->speed) { 2631f9f848faSopenharmony_ci case USB_SPEED_FULL: 2632f9f848faSopenharmony_ci case USB_SPEED_LOW: 2633f9f848faSopenharmony_ci if (hubdev != NULL) { 2634f9f848faSopenharmony_ci temp |= XHCI_SCTX_2_TT_HUB_SID_SET( 2635f9f848faSopenharmony_ci hubdev->controller_slot_id); 2636f9f848faSopenharmony_ci temp |= XHCI_SCTX_2_TT_PORT_NUM_SET( 2637f9f848faSopenharmony_ci udev->hs_port_no); 2638f9f848faSopenharmony_ci } 2639f9f848faSopenharmony_ci break; 2640f9f848faSopenharmony_ci default: 2641f9f848faSopenharmony_ci break; 2642f9f848faSopenharmony_ci } 2643f9f848faSopenharmony_ci 2644f9f848faSopenharmony_ci xhci_ctx_set_le32(sc, &pinp->ctx_slot.dwSctx2, temp); 2645f9f848faSopenharmony_ci 2646f9f848faSopenharmony_ci /* 2647f9f848faSopenharmony_ci * These fields should be initialized to zero, according to 2648f9f848faSopenharmony_ci * XHCI section 6.2.2 - slot context: 2649f9f848faSopenharmony_ci */ 2650f9f848faSopenharmony_ci temp = XHCI_SCTX_3_DEV_ADDR_SET(0) | 2651f9f848faSopenharmony_ci XHCI_SCTX_3_SLOT_STATE_SET(0); 2652f9f848faSopenharmony_ci 2653f9f848faSopenharmony_ci xhci_ctx_set_le32(sc, &pinp->ctx_slot.dwSctx3, temp); 2654f9f848faSopenharmony_ci 2655f9f848faSopenharmony_ci#ifdef USB_DEBUG 2656f9f848faSopenharmony_ci xhci_dump_device(sc, &pinp->ctx_slot); 2657f9f848faSopenharmony_ci#endif 2658f9f848faSopenharmony_ci usb_pc_cpu_flush(pcinp); 2659f9f848faSopenharmony_ci 2660f9f848faSopenharmony_ci return (USB_ERR_NORMAL_COMPLETION); /* success */ 2661f9f848faSopenharmony_ci} 2662f9f848faSopenharmony_ci 2663f9f848faSopenharmony_cistatic usb_error_t 2664f9f848faSopenharmony_cixhci_alloc_device_ext(struct usb_device *udev) 2665f9f848faSopenharmony_ci{ 2666f9f848faSopenharmony_ci struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); 2667f9f848faSopenharmony_ci struct usb_page_search buf_dev; 2668f9f848faSopenharmony_ci struct usb_page_search buf_ep; 2669f9f848faSopenharmony_ci struct xhci_trb *trb; 2670f9f848faSopenharmony_ci struct usb_page_cache *pc; 2671f9f848faSopenharmony_ci struct usb_page *pg; 2672f9f848faSopenharmony_ci uint64_t addr; 2673f9f848faSopenharmony_ci uint8_t index; 2674f9f848faSopenharmony_ci uint8_t i; 2675f9f848faSopenharmony_ci 2676f9f848faSopenharmony_ci index = udev->controller_slot_id; 2677f9f848faSopenharmony_ci 2678f9f848faSopenharmony_ci pc = &sc->sc_hw.devs[index].device_pc; 2679f9f848faSopenharmony_ci pg = &sc->sc_hw.devs[index].device_pg; 2680f9f848faSopenharmony_ci 2681f9f848faSopenharmony_ci /* need to initialize the page cache */ 2682f9f848faSopenharmony_ci pc->tag_parent = sc->sc_bus.dma_parent_tag; 2683f9f848faSopenharmony_ci 2684f9f848faSopenharmony_ci if (usb_pc_alloc_mem(pc, pg, sc->sc_ctx_is_64_byte ? 2685f9f848faSopenharmony_ci (2 * sizeof(struct xhci_dev_ctx)) : 2686f9f848faSopenharmony_ci sizeof(struct xhci_dev_ctx), XHCI_PAGE_SIZE)) 2687f9f848faSopenharmony_ci goto error; 2688f9f848faSopenharmony_ci 2689f9f848faSopenharmony_ci usbd_get_page(pc, 0, &buf_dev); 2690f9f848faSopenharmony_ci 2691f9f848faSopenharmony_ci pc = &sc->sc_hw.devs[index].input_pc; 2692f9f848faSopenharmony_ci pg = &sc->sc_hw.devs[index].input_pg; 2693f9f848faSopenharmony_ci 2694f9f848faSopenharmony_ci /* need to initialize the page cache */ 2695f9f848faSopenharmony_ci pc->tag_parent = sc->sc_bus.dma_parent_tag; 2696f9f848faSopenharmony_ci 2697f9f848faSopenharmony_ci if (usb_pc_alloc_mem(pc, pg, sc->sc_ctx_is_64_byte ? 2698f9f848faSopenharmony_ci (2 * sizeof(struct xhci_input_dev_ctx)) : 2699f9f848faSopenharmony_ci sizeof(struct xhci_input_dev_ctx), XHCI_PAGE_SIZE)) { 2700f9f848faSopenharmony_ci goto error; 2701f9f848faSopenharmony_ci } 2702f9f848faSopenharmony_ci 2703f9f848faSopenharmony_ci /* initialize all endpoint LINK TRBs */ 2704f9f848faSopenharmony_ci 2705f9f848faSopenharmony_ci for (i = 0; i != XHCI_MAX_ENDPOINTS; i++) { 2706f9f848faSopenharmony_ci pc = &sc->sc_hw.devs[index].endpoint_pc[i]; 2707f9f848faSopenharmony_ci pg = &sc->sc_hw.devs[index].endpoint_pg[i]; 2708f9f848faSopenharmony_ci 2709f9f848faSopenharmony_ci /* need to initialize the page cache */ 2710f9f848faSopenharmony_ci pc->tag_parent = sc->sc_bus.dma_parent_tag; 2711f9f848faSopenharmony_ci 2712f9f848faSopenharmony_ci if (usb_pc_alloc_mem(pc, pg, 2713f9f848faSopenharmony_ci sizeof(struct xhci_dev_endpoint_trbs), XHCI_TRB_ALIGN)) { 2714f9f848faSopenharmony_ci goto error; 2715f9f848faSopenharmony_ci } 2716f9f848faSopenharmony_ci 2717f9f848faSopenharmony_ci /* lookup endpoint TRB ring */ 2718f9f848faSopenharmony_ci usbd_get_page(pc, 0, &buf_ep); 2719f9f848faSopenharmony_ci 2720f9f848faSopenharmony_ci /* get TRB pointer */ 2721f9f848faSopenharmony_ci trb = buf_ep.buffer; 2722f9f848faSopenharmony_ci trb += XHCI_MAX_TRANSFERS - 1; 2723f9f848faSopenharmony_ci 2724f9f848faSopenharmony_ci /* get TRB start address */ 2725f9f848faSopenharmony_ci addr = buf_ep.physaddr; 2726f9f848faSopenharmony_ci 2727f9f848faSopenharmony_ci /* create LINK TRB */ 2728f9f848faSopenharmony_ci trb->qwTrb0 = htole64(addr); 2729f9f848faSopenharmony_ci trb->dwTrb2 = htole32(XHCI_TRB_2_IRQ_SET(0)); 2730f9f848faSopenharmony_ci trb->dwTrb3 = htole32(XHCI_TRB_3_CYCLE_BIT | 2731f9f848faSopenharmony_ci XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_LINK)); 2732f9f848faSopenharmony_ci 2733f9f848faSopenharmony_ci usb_pc_cpu_flush(pc); 2734f9f848faSopenharmony_ci } 2735f9f848faSopenharmony_ci 2736f9f848faSopenharmony_ci xhci_set_slot_pointer(sc, index, buf_dev.physaddr); 2737f9f848faSopenharmony_ci 2738f9f848faSopenharmony_ci return (USB_ERR_NORMAL_COMPLETION); 2739f9f848faSopenharmony_ci 2740f9f848faSopenharmony_cierror: 2741f9f848faSopenharmony_ci xhci_free_device_ext(udev); 2742f9f848faSopenharmony_ci 2743f9f848faSopenharmony_ci return (USB_ERR_NOMEM); 2744f9f848faSopenharmony_ci} 2745f9f848faSopenharmony_ci 2746f9f848faSopenharmony_cistatic void 2747f9f848faSopenharmony_cixhci_free_device_ext(struct usb_device *udev) 2748f9f848faSopenharmony_ci{ 2749f9f848faSopenharmony_ci struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); 2750f9f848faSopenharmony_ci uint8_t index; 2751f9f848faSopenharmony_ci uint8_t i; 2752f9f848faSopenharmony_ci 2753f9f848faSopenharmony_ci index = udev->controller_slot_id; 2754f9f848faSopenharmony_ci xhci_set_slot_pointer(sc, index, 0); 2755f9f848faSopenharmony_ci 2756f9f848faSopenharmony_ci usb_pc_free_mem(&sc->sc_hw.devs[index].device_pc); 2757f9f848faSopenharmony_ci usb_pc_free_mem(&sc->sc_hw.devs[index].input_pc); 2758f9f848faSopenharmony_ci for (i = 0; i != XHCI_MAX_ENDPOINTS; i++) 2759f9f848faSopenharmony_ci usb_pc_free_mem(&sc->sc_hw.devs[index].endpoint_pc[i]); 2760f9f848faSopenharmony_ci} 2761f9f848faSopenharmony_ci 2762f9f848faSopenharmony_cistatic struct xhci_endpoint_ext * 2763f9f848faSopenharmony_cixhci_get_endpoint_ext(struct usb_device *udev, struct usb_endpoint_descriptor *edesc) 2764f9f848faSopenharmony_ci{ 2765f9f848faSopenharmony_ci struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); 2766f9f848faSopenharmony_ci struct xhci_endpoint_ext *pepext; 2767f9f848faSopenharmony_ci struct usb_page_cache *pc; 2768f9f848faSopenharmony_ci struct usb_page_search buf_ep; 2769f9f848faSopenharmony_ci uint8_t epno; 2770f9f848faSopenharmony_ci uint8_t index; 2771f9f848faSopenharmony_ci 2772f9f848faSopenharmony_ci epno = edesc->bEndpointAddress; 2773f9f848faSopenharmony_ci if ((edesc->bmAttributes & UE_XFERTYPE) == UE_CONTROL) 2774f9f848faSopenharmony_ci epno |= UE_DIR_IN; 2775f9f848faSopenharmony_ci 2776f9f848faSopenharmony_ci epno = XHCI_EPNO2EPID(epno); 2777f9f848faSopenharmony_ci 2778f9f848faSopenharmony_ci index = udev->controller_slot_id; 2779f9f848faSopenharmony_ci 2780f9f848faSopenharmony_ci pc = &sc->sc_hw.devs[index].endpoint_pc[epno]; 2781f9f848faSopenharmony_ci 2782f9f848faSopenharmony_ci usbd_get_page(pc, 0, &buf_ep); 2783f9f848faSopenharmony_ci 2784f9f848faSopenharmony_ci pepext = &sc->sc_hw.devs[index].endp[epno]; 2785f9f848faSopenharmony_ci pepext->page_cache = pc; 2786f9f848faSopenharmony_ci pepext->trb = buf_ep.buffer; 2787f9f848faSopenharmony_ci pepext->physaddr = buf_ep.physaddr; 2788f9f848faSopenharmony_ci 2789f9f848faSopenharmony_ci return (pepext); 2790f9f848faSopenharmony_ci} 2791f9f848faSopenharmony_ci 2792f9f848faSopenharmony_cistatic void 2793f9f848faSopenharmony_cixhci_endpoint_doorbell(struct usb_xfer *xfer) 2794f9f848faSopenharmony_ci{ 2795f9f848faSopenharmony_ci struct xhci_softc *sc = XHCI_BUS2SC(xfer->xroot->bus); 2796f9f848faSopenharmony_ci uint8_t epno; 2797f9f848faSopenharmony_ci uint8_t index; 2798f9f848faSopenharmony_ci 2799f9f848faSopenharmony_ci epno = xfer->endpointno; 2800f9f848faSopenharmony_ci if (xfer->flags_int.control_xfr) 2801f9f848faSopenharmony_ci epno |= UE_DIR_IN; 2802f9f848faSopenharmony_ci 2803f9f848faSopenharmony_ci epno = XHCI_EPNO2EPID(epno); 2804f9f848faSopenharmony_ci index = xfer->xroot->udev->controller_slot_id; 2805f9f848faSopenharmony_ci 2806f9f848faSopenharmony_ci if (xfer->xroot->udev->flags.self_suspended == 0) { 2807f9f848faSopenharmony_ci XWRITE4(sc, door, XHCI_DOORBELL(index), 2808f9f848faSopenharmony_ci epno | XHCI_DB_SID_SET(xfer->stream_id)); 2809f9f848faSopenharmony_ci } 2810f9f848faSopenharmony_ci} 2811f9f848faSopenharmony_ci 2812f9f848faSopenharmony_cistatic void 2813f9f848faSopenharmony_cixhci_transfer_remove(struct usb_xfer *xfer, usb_error_t error) 2814f9f848faSopenharmony_ci{ 2815f9f848faSopenharmony_ci struct xhci_endpoint_ext *pepext; 2816f9f848faSopenharmony_ci 2817f9f848faSopenharmony_ci if (xfer->flags_int.bandwidth_reclaimed) { 2818f9f848faSopenharmony_ci xfer->flags_int.bandwidth_reclaimed = 0; 2819f9f848faSopenharmony_ci 2820f9f848faSopenharmony_ci pepext = xhci_get_endpoint_ext(xfer->xroot->udev, 2821f9f848faSopenharmony_ci xfer->endpoint->edesc); 2822f9f848faSopenharmony_ci 2823f9f848faSopenharmony_ci pepext->trb_used[xfer->stream_id]--; 2824f9f848faSopenharmony_ci 2825f9f848faSopenharmony_ci pepext->xfer[xfer->qh_pos] = NULL; 2826f9f848faSopenharmony_ci 2827f9f848faSopenharmony_ci if (error && (pepext->trb_running != 0)) { 2828f9f848faSopenharmony_ci pepext->trb_halted = 1; 2829f9f848faSopenharmony_ci pepext->trb_running = 0; 2830f9f848faSopenharmony_ci } 2831f9f848faSopenharmony_ci } 2832f9f848faSopenharmony_ci} 2833f9f848faSopenharmony_ci 2834f9f848faSopenharmony_cistatic usb_error_t 2835f9f848faSopenharmony_cixhci_transfer_insert(struct usb_xfer *xfer) 2836f9f848faSopenharmony_ci{ 2837f9f848faSopenharmony_ci struct xhci_td *td_first; 2838f9f848faSopenharmony_ci struct xhci_td *td_last; 2839f9f848faSopenharmony_ci struct xhci_trb *trb_link; 2840f9f848faSopenharmony_ci struct xhci_endpoint_ext *pepext; 2841f9f848faSopenharmony_ci uint64_t addr; 2842f9f848faSopenharmony_ci usb_stream_t id; 2843f9f848faSopenharmony_ci uint8_t i; 2844f9f848faSopenharmony_ci uint8_t inext; 2845f9f848faSopenharmony_ci uint8_t trb_limit; 2846f9f848faSopenharmony_ci 2847f9f848faSopenharmony_ci DPRINTFN(8, "\n"); 2848f9f848faSopenharmony_ci 2849f9f848faSopenharmony_ci id = xfer->stream_id; 2850f9f848faSopenharmony_ci 2851f9f848faSopenharmony_ci /* check if already inserted */ 2852f9f848faSopenharmony_ci if (xfer->flags_int.bandwidth_reclaimed) { 2853f9f848faSopenharmony_ci DPRINTFN(8, "Already in schedule\n"); 2854f9f848faSopenharmony_ci return (USB_ERR_NORMAL_COMPLETION); 2855f9f848faSopenharmony_ci } 2856f9f848faSopenharmony_ci 2857f9f848faSopenharmony_ci pepext = xhci_get_endpoint_ext(xfer->xroot->udev, 2858f9f848faSopenharmony_ci xfer->endpoint->edesc); 2859f9f848faSopenharmony_ci 2860f9f848faSopenharmony_ci td_first = xfer->td_transfer_first; 2861f9f848faSopenharmony_ci td_last = xfer->td_transfer_last; 2862f9f848faSopenharmony_ci addr = pepext->physaddr; 2863f9f848faSopenharmony_ci 2864f9f848faSopenharmony_ci switch (xfer->endpoint->edesc->bmAttributes & UE_XFERTYPE) { 2865f9f848faSopenharmony_ci case UE_CONTROL: 2866f9f848faSopenharmony_ci case UE_INTERRUPT: 2867f9f848faSopenharmony_ci /* single buffered */ 2868f9f848faSopenharmony_ci trb_limit = 1; 2869f9f848faSopenharmony_ci break; 2870f9f848faSopenharmony_ci default: 2871f9f848faSopenharmony_ci /* multi buffered */ 2872f9f848faSopenharmony_ci trb_limit = (XHCI_MAX_TRANSFERS - 2); 2873f9f848faSopenharmony_ci break; 2874f9f848faSopenharmony_ci } 2875f9f848faSopenharmony_ci 2876f9f848faSopenharmony_ci if (pepext->trb_used[id] >= trb_limit) { 2877f9f848faSopenharmony_ci DPRINTFN(8, "Too many TDs queued.\n"); 2878f9f848faSopenharmony_ci return (USB_ERR_NOMEM); 2879f9f848faSopenharmony_ci } 2880f9f848faSopenharmony_ci 2881f9f848faSopenharmony_ci /* check if bMaxPacketSize changed */ 2882f9f848faSopenharmony_ci if (xfer->flags_int.control_xfr != 0 && 2883f9f848faSopenharmony_ci pepext->trb_ep_maxp != xfer->endpoint->edesc->wMaxPacketSize[0]) { 2884f9f848faSopenharmony_ci DPRINTFN(8, "Reconfigure control endpoint\n"); 2885f9f848faSopenharmony_ci 2886f9f848faSopenharmony_ci /* force driver to reconfigure endpoint */ 2887f9f848faSopenharmony_ci pepext->trb_halted = 1; 2888f9f848faSopenharmony_ci pepext->trb_running = 0; 2889f9f848faSopenharmony_ci } 2890f9f848faSopenharmony_ci 2891f9f848faSopenharmony_ci /* check for stopped condition, after putting transfer on interrupt queue */ 2892f9f848faSopenharmony_ci if (pepext->trb_running == 0) { 2893f9f848faSopenharmony_ci struct xhci_softc *sc = XHCI_BUS2SC(xfer->xroot->bus); 2894f9f848faSopenharmony_ci 2895f9f848faSopenharmony_ci DPRINTFN(8, "Not running\n"); 2896f9f848faSopenharmony_ci 2897f9f848faSopenharmony_ci /* start configuration */ 2898f9f848faSopenharmony_ci (void)usb_proc_msignal(USB_BUS_CONTROL_XFER_PROC(&sc->sc_bus), 2899f9f848faSopenharmony_ci &sc->sc_config_msg[0], &sc->sc_config_msg[1]); 2900f9f848faSopenharmony_ci return (USB_ERR_NORMAL_COMPLETION); 2901f9f848faSopenharmony_ci } 2902f9f848faSopenharmony_ci 2903f9f848faSopenharmony_ci pepext->trb_used[id]++; 2904f9f848faSopenharmony_ci 2905f9f848faSopenharmony_ci /* get current TRB index */ 2906f9f848faSopenharmony_ci i = pepext->trb_index[id]; 2907f9f848faSopenharmony_ci 2908f9f848faSopenharmony_ci /* get next TRB index */ 2909f9f848faSopenharmony_ci inext = (i + 1); 2910f9f848faSopenharmony_ci 2911f9f848faSopenharmony_ci /* the last entry of the ring is a hardcoded link TRB */ 2912f9f848faSopenharmony_ci if (inext >= (XHCI_MAX_TRANSFERS - 1)) 2913f9f848faSopenharmony_ci inext = 0; 2914f9f848faSopenharmony_ci 2915f9f848faSopenharmony_ci /* store next TRB index, before stream ID offset is added */ 2916f9f848faSopenharmony_ci pepext->trb_index[id] = inext; 2917f9f848faSopenharmony_ci 2918f9f848faSopenharmony_ci /* offset for stream */ 2919f9f848faSopenharmony_ci i += id * XHCI_MAX_TRANSFERS; 2920f9f848faSopenharmony_ci inext += id * XHCI_MAX_TRANSFERS; 2921f9f848faSopenharmony_ci 2922f9f848faSopenharmony_ci /* compute terminating return address */ 2923f9f848faSopenharmony_ci addr += (inext * sizeof(struct xhci_trb)); 2924f9f848faSopenharmony_ci 2925f9f848faSopenharmony_ci /* compute link TRB pointer */ 2926f9f848faSopenharmony_ci trb_link = td_last->td_trb + td_last->ntrb; 2927f9f848faSopenharmony_ci 2928f9f848faSopenharmony_ci /* update next pointer of last link TRB */ 2929f9f848faSopenharmony_ci trb_link->qwTrb0 = htole64(addr); 2930f9f848faSopenharmony_ci trb_link->dwTrb2 = htole32(XHCI_TRB_2_IRQ_SET(0)); 2931f9f848faSopenharmony_ci trb_link->dwTrb3 = htole32(XHCI_TRB_3_IOC_BIT | 2932f9f848faSopenharmony_ci XHCI_TRB_3_CYCLE_BIT | 2933f9f848faSopenharmony_ci XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_LINK)); 2934f9f848faSopenharmony_ci 2935f9f848faSopenharmony_ci#ifdef USB_DEBUG 2936f9f848faSopenharmony_ci xhci_dump_trb(&td_last->td_trb[td_last->ntrb]); 2937f9f848faSopenharmony_ci#endif 2938f9f848faSopenharmony_ci usb_pc_cpu_flush(td_last->page_cache); 2939f9f848faSopenharmony_ci 2940f9f848faSopenharmony_ci /* write ahead chain end marker */ 2941f9f848faSopenharmony_ci 2942f9f848faSopenharmony_ci pepext->trb[inext].qwTrb0 = 0; 2943f9f848faSopenharmony_ci pepext->trb[inext].dwTrb2 = 0; 2944f9f848faSopenharmony_ci pepext->trb[inext].dwTrb3 = 0; 2945f9f848faSopenharmony_ci 2946f9f848faSopenharmony_ci /* update next pointer of link TRB */ 2947f9f848faSopenharmony_ci 2948f9f848faSopenharmony_ci pepext->trb[i].qwTrb0 = htole64((uint64_t)td_first->td_self); 2949f9f848faSopenharmony_ci pepext->trb[i].dwTrb2 = htole32(XHCI_TRB_2_IRQ_SET(0)); 2950f9f848faSopenharmony_ci 2951f9f848faSopenharmony_ci#ifdef USB_DEBUG 2952f9f848faSopenharmony_ci xhci_dump_trb(&pepext->trb[i]); 2953f9f848faSopenharmony_ci#endif 2954f9f848faSopenharmony_ci usb_pc_cpu_flush(pepext->page_cache); 2955f9f848faSopenharmony_ci 2956f9f848faSopenharmony_ci /* toggle cycle bit which activates the transfer chain */ 2957f9f848faSopenharmony_ci 2958f9f848faSopenharmony_ci pepext->trb[i].dwTrb3 = htole32(XHCI_TRB_3_CYCLE_BIT | 2959f9f848faSopenharmony_ci XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_LINK)); 2960f9f848faSopenharmony_ci 2961f9f848faSopenharmony_ci usb_pc_cpu_flush(pepext->page_cache); 2962f9f848faSopenharmony_ci 2963f9f848faSopenharmony_ci DPRINTF("qh_pos = %u\n", i); 2964f9f848faSopenharmony_ci 2965f9f848faSopenharmony_ci pepext->xfer[i] = xfer; 2966f9f848faSopenharmony_ci 2967f9f848faSopenharmony_ci xfer->qh_pos = i; 2968f9f848faSopenharmony_ci 2969f9f848faSopenharmony_ci xfer->flags_int.bandwidth_reclaimed = 1; 2970f9f848faSopenharmony_ci 2971f9f848faSopenharmony_ci xhci_endpoint_doorbell(xfer); 2972f9f848faSopenharmony_ci 2973f9f848faSopenharmony_ci return (USB_ERR_NORMAL_COMPLETION); 2974f9f848faSopenharmony_ci} 2975f9f848faSopenharmony_ci 2976f9f848faSopenharmony_cistatic void 2977f9f848faSopenharmony_cixhci_root_intr(struct xhci_softc *sc) 2978f9f848faSopenharmony_ci{ 2979f9f848faSopenharmony_ci uint16_t i; 2980f9f848faSopenharmony_ci 2981f9f848faSopenharmony_ci USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); 2982f9f848faSopenharmony_ci 2983f9f848faSopenharmony_ci /* clear any old interrupt data */ 2984f9f848faSopenharmony_ci (void)memset_s(sc->sc_hub_idata, sizeof(sc->sc_hub_idata), 0, sizeof(sc->sc_hub_idata)); 2985f9f848faSopenharmony_ci 2986f9f848faSopenharmony_ci for (i = 1; i <= sc->sc_noport; i++) { 2987f9f848faSopenharmony_ci /* pick out CHANGE bits from the status register */ 2988f9f848faSopenharmony_ci if (XREAD4(sc, oper, XHCI_PORTSC(i)) & ( 2989f9f848faSopenharmony_ci XHCI_PS_CSC | XHCI_PS_PEC | 2990f9f848faSopenharmony_ci XHCI_PS_OCC | XHCI_PS_WRC | 2991f9f848faSopenharmony_ci XHCI_PS_PRC | XHCI_PS_PLC | 2992f9f848faSopenharmony_ci XHCI_PS_CEC)) { 2993f9f848faSopenharmony_ci sc->sc_hub_idata[i / 8] |= 1 << (i % 8); 2994f9f848faSopenharmony_ci DPRINTF("port %d changed\n", i); 2995f9f848faSopenharmony_ci } 2996f9f848faSopenharmony_ci } 2997f9f848faSopenharmony_ci uhub_root_intr(&sc->sc_bus, sc->sc_hub_idata, 2998f9f848faSopenharmony_ci sizeof(sc->sc_hub_idata)); 2999f9f848faSopenharmony_ci} 3000f9f848faSopenharmony_ci 3001f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 3002f9f848faSopenharmony_ci * xhci_device_done - XHCI done handler 3003f9f848faSopenharmony_ci * 3004f9f848faSopenharmony_ci * NOTE: This function can be called two times in a row on 3005f9f848faSopenharmony_ci * the same USB transfer. From close and from interrupt. 3006f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 3007f9f848faSopenharmony_cistatic void 3008f9f848faSopenharmony_cixhci_device_done(struct usb_xfer *xfer, usb_error_t error) 3009f9f848faSopenharmony_ci{ 3010f9f848faSopenharmony_ci DPRINTFN(2, "xfer=%p, endpoint=%p, error=%d\n", 3011f9f848faSopenharmony_ci xfer, xfer->endpoint, error); 3012f9f848faSopenharmony_ci 3013f9f848faSopenharmony_ci /* remove transfer from HW queue */ 3014f9f848faSopenharmony_ci xhci_transfer_remove(xfer, error); 3015f9f848faSopenharmony_ci 3016f9f848faSopenharmony_ci /* dequeue transfer and start next transfer */ 3017f9f848faSopenharmony_ci usbd_transfer_done(xfer, error); 3018f9f848faSopenharmony_ci} 3019f9f848faSopenharmony_ci 3020f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 3021f9f848faSopenharmony_ci * XHCI data transfer support (generic type) 3022f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 3023f9f848faSopenharmony_cistatic void 3024f9f848faSopenharmony_cixhci_device_generic_open(struct usb_xfer *xfer) 3025f9f848faSopenharmony_ci{ 3026f9f848faSopenharmony_ci if (xfer->flags_int.isochronous_xfr) { 3027f9f848faSopenharmony_ci switch (xfer->xroot->udev->speed) { 3028f9f848faSopenharmony_ci case USB_SPEED_FULL: 3029f9f848faSopenharmony_ci break; 3030f9f848faSopenharmony_ci default: 3031f9f848faSopenharmony_ci usb_hs_bandwidth_alloc(xfer); 3032f9f848faSopenharmony_ci break; 3033f9f848faSopenharmony_ci } 3034f9f848faSopenharmony_ci } 3035f9f848faSopenharmony_ci} 3036f9f848faSopenharmony_ci 3037f9f848faSopenharmony_cistatic void 3038f9f848faSopenharmony_cixhci_device_generic_close(struct usb_xfer *xfer) 3039f9f848faSopenharmony_ci{ 3040f9f848faSopenharmony_ci DPRINTF("\n"); 3041f9f848faSopenharmony_ci 3042f9f848faSopenharmony_ci xhci_device_done(xfer, USB_ERR_CANCELLED); 3043f9f848faSopenharmony_ci if (xfer->flags_int.isochronous_xfr) { 3044f9f848faSopenharmony_ci switch (xfer->xroot->udev->speed) { 3045f9f848faSopenharmony_ci case USB_SPEED_FULL: 3046f9f848faSopenharmony_ci break; 3047f9f848faSopenharmony_ci default: 3048f9f848faSopenharmony_ci usb_hs_bandwidth_free(xfer); 3049f9f848faSopenharmony_ci break; 3050f9f848faSopenharmony_ci } 3051f9f848faSopenharmony_ci } 3052f9f848faSopenharmony_ci} 3053f9f848faSopenharmony_ci 3054f9f848faSopenharmony_cistatic void 3055f9f848faSopenharmony_cixhci_device_generic_multi_enter(struct usb_endpoint *ep, 3056f9f848faSopenharmony_ci usb_stream_t stream_id, struct usb_xfer *enter_xfer) 3057f9f848faSopenharmony_ci{ 3058f9f848faSopenharmony_ci struct usb_xfer *xfer; 3059f9f848faSopenharmony_ci 3060f9f848faSopenharmony_ci /* check if there is a current transfer */ 3061f9f848faSopenharmony_ci xfer = ep->endpoint_q[stream_id].curr; 3062f9f848faSopenharmony_ci if (xfer == NULL) 3063f9f848faSopenharmony_ci return; 3064f9f848faSopenharmony_ci 3065f9f848faSopenharmony_ci /* 3066f9f848faSopenharmony_ci * Check if the current transfer is started and then pickup 3067f9f848faSopenharmony_ci * the next one, if any. Else wait for next start event due to 3068f9f848faSopenharmony_ci * block on failure feature. 3069f9f848faSopenharmony_ci */ 3070f9f848faSopenharmony_ci if (!xfer->flags_int.bandwidth_reclaimed) 3071f9f848faSopenharmony_ci return; 3072f9f848faSopenharmony_ci 3073f9f848faSopenharmony_ci xfer = TAILQ_FIRST(&ep->endpoint_q[stream_id].head); 3074f9f848faSopenharmony_ci if (xfer == NULL) { 3075f9f848faSopenharmony_ci /* 3076f9f848faSopenharmony_ci * In case of enter we have to consider that the 3077f9f848faSopenharmony_ci * transfer is queued by the USB core after the enter 3078f9f848faSopenharmony_ci * method is called. 3079f9f848faSopenharmony_ci */ 3080f9f848faSopenharmony_ci xfer = enter_xfer; 3081f9f848faSopenharmony_ci 3082f9f848faSopenharmony_ci if (xfer == NULL) 3083f9f848faSopenharmony_ci return; 3084f9f848faSopenharmony_ci } 3085f9f848faSopenharmony_ci 3086f9f848faSopenharmony_ci /* try to multi buffer */ 3087f9f848faSopenharmony_ci (void)xhci_transfer_insert(xfer); 3088f9f848faSopenharmony_ci} 3089f9f848faSopenharmony_ci 3090f9f848faSopenharmony_cistatic void 3091f9f848faSopenharmony_cixhci_device_generic_enter(struct usb_xfer *xfer) 3092f9f848faSopenharmony_ci{ 3093f9f848faSopenharmony_ci DPRINTF("\n"); 3094f9f848faSopenharmony_ci 3095f9f848faSopenharmony_ci /* set up TD's and QH */ 3096f9f848faSopenharmony_ci xhci_setup_generic_chain(xfer); 3097f9f848faSopenharmony_ci 3098f9f848faSopenharmony_ci xhci_device_generic_multi_enter(xfer->endpoint, 3099f9f848faSopenharmony_ci xfer->stream_id, xfer); 3100f9f848faSopenharmony_ci} 3101f9f848faSopenharmony_ci 3102f9f848faSopenharmony_cistatic void 3103f9f848faSopenharmony_cixhci_device_generic_start(struct usb_xfer *xfer) 3104f9f848faSopenharmony_ci{ 3105f9f848faSopenharmony_ci DPRINTF("\n"); 3106f9f848faSopenharmony_ci 3107f9f848faSopenharmony_ci /* try to insert xfer on HW queue */ 3108f9f848faSopenharmony_ci (void)xhci_transfer_insert(xfer); 3109f9f848faSopenharmony_ci 3110f9f848faSopenharmony_ci /* try to multi buffer */ 3111f9f848faSopenharmony_ci xhci_device_generic_multi_enter(xfer->endpoint, 3112f9f848faSopenharmony_ci xfer->stream_id, NULL); 3113f9f848faSopenharmony_ci 3114f9f848faSopenharmony_ci /* add transfer last on interrupt queue */ 3115f9f848faSopenharmony_ci usbd_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer); 3116f9f848faSopenharmony_ci 3117f9f848faSopenharmony_ci /* start timeout, if any */ 3118f9f848faSopenharmony_ci if (xfer->timeout != 0) 3119f9f848faSopenharmony_ci usbd_transfer_timeout_ms(xfer, &xhci_timeout, xfer->timeout); 3120f9f848faSopenharmony_ci} 3121f9f848faSopenharmony_ci 3122f9f848faSopenharmony_cistruct usb_pipe_methods xhci_device_generic_methods = { 3123f9f848faSopenharmony_ci .open = xhci_device_generic_open, 3124f9f848faSopenharmony_ci .close = xhci_device_generic_close, 3125f9f848faSopenharmony_ci .enter = xhci_device_generic_enter, 3126f9f848faSopenharmony_ci .start = xhci_device_generic_start, 3127f9f848faSopenharmony_ci}; 3128f9f848faSopenharmony_ci 3129f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 3130f9f848faSopenharmony_ci * xhci root HUB support 3131f9f848faSopenharmony_ci *------------------------------------------------------------------------* 3132f9f848faSopenharmony_ci * Simulate a hardware HUB by handling all the necessary requests. 3133f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 3134f9f848faSopenharmony_ci#define HSETW(ptr, val) ptr = { (uint8_t)(val), (uint8_t)((val) >> 8) } 3135f9f848faSopenharmony_ci 3136f9f848faSopenharmony_cistatic const 3137f9f848faSopenharmony_cistruct usb_device_descriptor xhci_devd = { 3138f9f848faSopenharmony_ci .bLength = sizeof(xhci_devd), 3139f9f848faSopenharmony_ci .bDescriptorType = UDESC_DEVICE, /* type */ 3140f9f848faSopenharmony_ci HSETW(.bcdUSB, 0x0300), /* USB version */ 3141f9f848faSopenharmony_ci .bDeviceClass = UDCLASS_HUB, /* class */ 3142f9f848faSopenharmony_ci .bDeviceSubClass = UDSUBCLASS_HUB, /* subclass */ 3143f9f848faSopenharmony_ci .bDeviceProtocol = UDPROTO_SSHUB, /* protocol */ 3144f9f848faSopenharmony_ci .bMaxPacketSize = 9, /* max packet size */ 3145f9f848faSopenharmony_ci HSETW(.idVendor, 0x0000), /* vendor */ 3146f9f848faSopenharmony_ci HSETW(.idProduct, 0x0000), /* product */ 3147f9f848faSopenharmony_ci HSETW(.bcdDevice, 0x0100), /* device version */ 3148f9f848faSopenharmony_ci .iManufacturer = 1, 3149f9f848faSopenharmony_ci .iProduct = 2, 3150f9f848faSopenharmony_ci .iSerialNumber = 0, 3151f9f848faSopenharmony_ci .bNumConfigurations = 1, /* # of configurations */ 3152f9f848faSopenharmony_ci}; 3153f9f848faSopenharmony_ci 3154f9f848faSopenharmony_cistatic const 3155f9f848faSopenharmony_cistruct xhci_bos_desc xhci_bosd = { 3156f9f848faSopenharmony_ci .bosd = { 3157f9f848faSopenharmony_ci .bLength = sizeof(xhci_bosd.bosd), 3158f9f848faSopenharmony_ci .bDescriptorType = UDESC_BOS, 3159f9f848faSopenharmony_ci HSETW(.wTotalLength, sizeof(xhci_bosd)), 3160f9f848faSopenharmony_ci .bNumDeviceCaps = 3, 3161f9f848faSopenharmony_ci }, 3162f9f848faSopenharmony_ci .usb2extd = { 3163f9f848faSopenharmony_ci .bLength = sizeof(xhci_bosd.usb2extd), 3164f9f848faSopenharmony_ci .bDescriptorType = 1, 3165f9f848faSopenharmony_ci .bDevCapabilityType = 2, 3166f9f848faSopenharmony_ci .bmAttributes[0] = 2, 3167f9f848faSopenharmony_ci }, 3168f9f848faSopenharmony_ci .usbdcd = { 3169f9f848faSopenharmony_ci .bLength = sizeof(xhci_bosd.usbdcd), 3170f9f848faSopenharmony_ci .bDescriptorType = UDESC_DEVICE_CAPABILITY, 3171f9f848faSopenharmony_ci .bDevCapabilityType = 3, 3172f9f848faSopenharmony_ci .bmAttributes = 0, 3173f9f848faSopenharmony_ci HSETW(.wSpeedsSupported, 0x000C), 3174f9f848faSopenharmony_ci .bFunctionalitySupport = 8, 3175f9f848faSopenharmony_ci .bU1DevExitLat = 255, /* dummy - not used */ 3176f9f848faSopenharmony_ci .wU2DevExitLat = { 0x00, 0x08 }, 3177f9f848faSopenharmony_ci }, 3178f9f848faSopenharmony_ci .cidd = { 3179f9f848faSopenharmony_ci .bLength = sizeof(xhci_bosd.cidd), 3180f9f848faSopenharmony_ci .bDescriptorType = 1, 3181f9f848faSopenharmony_ci .bDevCapabilityType = 4, 3182f9f848faSopenharmony_ci .bReserved = 0, 3183f9f848faSopenharmony_ci .bContainerID = 0, 3184f9f848faSopenharmony_ci }, 3185f9f848faSopenharmony_ci}; 3186f9f848faSopenharmony_ci 3187f9f848faSopenharmony_cistatic const 3188f9f848faSopenharmony_cistruct xhci_config_desc xhci_confd = { 3189f9f848faSopenharmony_ci .confd = { 3190f9f848faSopenharmony_ci .bLength = sizeof(xhci_confd.confd), 3191f9f848faSopenharmony_ci .bDescriptorType = UDESC_CONFIG, 3192f9f848faSopenharmony_ci .wTotalLength[0] = sizeof(xhci_confd), 3193f9f848faSopenharmony_ci .bNumInterface = 1, 3194f9f848faSopenharmony_ci .bConfigurationValue = 1, 3195f9f848faSopenharmony_ci .iConfiguration = 0, 3196f9f848faSopenharmony_ci .bmAttributes = UC_SELF_POWERED, 3197f9f848faSopenharmony_ci .bMaxPower = 0 /* max power */ 3198f9f848faSopenharmony_ci }, 3199f9f848faSopenharmony_ci .ifcd = { 3200f9f848faSopenharmony_ci .bLength = sizeof(xhci_confd.ifcd), 3201f9f848faSopenharmony_ci .bDescriptorType = UDESC_INTERFACE, 3202f9f848faSopenharmony_ci .bNumEndpoints = 1, 3203f9f848faSopenharmony_ci .bInterfaceClass = UICLASS_HUB, 3204f9f848faSopenharmony_ci .bInterfaceSubClass = UISUBCLASS_HUB, 3205f9f848faSopenharmony_ci .bInterfaceProtocol = 0, 3206f9f848faSopenharmony_ci }, 3207f9f848faSopenharmony_ci .endpd = { 3208f9f848faSopenharmony_ci .bLength = sizeof(xhci_confd.endpd), 3209f9f848faSopenharmony_ci .bDescriptorType = UDESC_ENDPOINT, 3210f9f848faSopenharmony_ci .bEndpointAddress = UE_DIR_IN | XHCI_INTR_ENDPT, 3211f9f848faSopenharmony_ci .bmAttributes = UE_INTERRUPT, 3212f9f848faSopenharmony_ci .wMaxPacketSize[0] = 2, /* max 15 ports */ 3213f9f848faSopenharmony_ci .bInterval = 255, 3214f9f848faSopenharmony_ci }, 3215f9f848faSopenharmony_ci .endpcd = { 3216f9f848faSopenharmony_ci .bLength = sizeof(xhci_confd.endpcd), 3217f9f848faSopenharmony_ci .bDescriptorType = UDESC_ENDPOINT_SS_COMP, 3218f9f848faSopenharmony_ci .bMaxBurst = 0, 3219f9f848faSopenharmony_ci .bmAttributes = 0, 3220f9f848faSopenharmony_ci }, 3221f9f848faSopenharmony_ci}; 3222f9f848faSopenharmony_ci 3223f9f848faSopenharmony_cistatic const 3224f9f848faSopenharmony_cistruct usb_hub_ss_descriptor xhci_hubd = { 3225f9f848faSopenharmony_ci .bLength = sizeof(xhci_hubd), 3226f9f848faSopenharmony_ci .bDescriptorType = UDESC_SS_HUB, 3227f9f848faSopenharmony_ci}; 3228f9f848faSopenharmony_ci 3229f9f848faSopenharmony_cistatic usb_error_t 3230f9f848faSopenharmony_cixhci_roothub_exec(struct usb_device *udev, 3231f9f848faSopenharmony_ci struct usb_device_request *req, const void **pptr, uint16_t *plength) 3232f9f848faSopenharmony_ci{ 3233f9f848faSopenharmony_ci struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); 3234f9f848faSopenharmony_ci const char *str_ptr; 3235f9f848faSopenharmony_ci const void *ptr; 3236f9f848faSopenharmony_ci uint32_t port; 3237f9f848faSopenharmony_ci uint32_t v; 3238f9f848faSopenharmony_ci uint16_t len; 3239f9f848faSopenharmony_ci uint16_t i; 3240f9f848faSopenharmony_ci uint16_t value; 3241f9f848faSopenharmony_ci uint16_t index; 3242f9f848faSopenharmony_ci uint8_t j; 3243f9f848faSopenharmony_ci usb_error_t err; 3244f9f848faSopenharmony_ci 3245f9f848faSopenharmony_ci USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); 3246f9f848faSopenharmony_ci 3247f9f848faSopenharmony_ci /* buffer reset */ 3248f9f848faSopenharmony_ci ptr = (const void *)&sc->sc_hub_desc; 3249f9f848faSopenharmony_ci len = 0; 3250f9f848faSopenharmony_ci err = USB_ERR_NORMAL_COMPLETION; 3251f9f848faSopenharmony_ci 3252f9f848faSopenharmony_ci value = UGETW(req->wValue); 3253f9f848faSopenharmony_ci index = UGETW(req->wIndex); 3254f9f848faSopenharmony_ci 3255f9f848faSopenharmony_ci DPRINTFN(3, "type=0x%02x request=0x%02x wLen=0x%04x " 3256f9f848faSopenharmony_ci "wValue=0x%04x wIndex=0x%04x\n", 3257f9f848faSopenharmony_ci req->bmRequestType, req->bRequest, 3258f9f848faSopenharmony_ci UGETW(req->wLength), value, index); 3259f9f848faSopenharmony_ci 3260f9f848faSopenharmony_ci#define C(x,y) ((x) | ((y) << 8)) 3261f9f848faSopenharmony_ci switch (C(req->bRequest, req->bmRequestType)) { 3262f9f848faSopenharmony_ci case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE): 3263f9f848faSopenharmony_ci case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE): 3264f9f848faSopenharmony_ci case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT): 3265f9f848faSopenharmony_ci /* 3266f9f848faSopenharmony_ci * DEVICE_REMOTE_WAKEUP and ENDPOINT_HALT are no-ops 3267f9f848faSopenharmony_ci * for the integrated root hub. 3268f9f848faSopenharmony_ci */ 3269f9f848faSopenharmony_ci break; 3270f9f848faSopenharmony_ci case C(UR_GET_CONFIG, UT_READ_DEVICE): 3271f9f848faSopenharmony_ci len = 1; 3272f9f848faSopenharmony_ci sc->sc_hub_desc.temp[0] = sc->sc_conf; 3273f9f848faSopenharmony_ci break; 3274f9f848faSopenharmony_ci case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE): 3275f9f848faSopenharmony_ci switch (value >> 8) { 3276f9f848faSopenharmony_ci case UDESC_DEVICE: 3277f9f848faSopenharmony_ci if ((value & 0xff) != 0) { 3278f9f848faSopenharmony_ci err = USB_ERR_IOERROR; 3279f9f848faSopenharmony_ci goto done; 3280f9f848faSopenharmony_ci } 3281f9f848faSopenharmony_ci len = sizeof(xhci_devd); 3282f9f848faSopenharmony_ci ptr = (const void *)&xhci_devd; 3283f9f848faSopenharmony_ci break; 3284f9f848faSopenharmony_ci 3285f9f848faSopenharmony_ci case UDESC_BOS: 3286f9f848faSopenharmony_ci if ((value & 0xff) != 0) { 3287f9f848faSopenharmony_ci err = USB_ERR_IOERROR; 3288f9f848faSopenharmony_ci goto done; 3289f9f848faSopenharmony_ci } 3290f9f848faSopenharmony_ci len = sizeof(xhci_bosd); 3291f9f848faSopenharmony_ci ptr = (const void *)&xhci_bosd; 3292f9f848faSopenharmony_ci break; 3293f9f848faSopenharmony_ci 3294f9f848faSopenharmony_ci case UDESC_CONFIG: 3295f9f848faSopenharmony_ci if ((value & 0xff) != 0) { 3296f9f848faSopenharmony_ci err = USB_ERR_IOERROR; 3297f9f848faSopenharmony_ci goto done; 3298f9f848faSopenharmony_ci } 3299f9f848faSopenharmony_ci len = sizeof(xhci_confd); 3300f9f848faSopenharmony_ci ptr = (const void *)&xhci_confd; 3301f9f848faSopenharmony_ci break; 3302f9f848faSopenharmony_ci 3303f9f848faSopenharmony_ci case UDESC_STRING: 3304f9f848faSopenharmony_ci switch (value & 0xff) { 3305f9f848faSopenharmony_ci case 0: /* Language table */ 3306f9f848faSopenharmony_ci str_ptr = "\001"; 3307f9f848faSopenharmony_ci break; 3308f9f848faSopenharmony_ci 3309f9f848faSopenharmony_ci case 1: /* Vendor */ 3310f9f848faSopenharmony_ci str_ptr = sc->sc_vendor; 3311f9f848faSopenharmony_ci break; 3312f9f848faSopenharmony_ci 3313f9f848faSopenharmony_ci case 2: /* Product */ 3314f9f848faSopenharmony_ci str_ptr = "XHCI root HUB"; 3315f9f848faSopenharmony_ci break; 3316f9f848faSopenharmony_ci 3317f9f848faSopenharmony_ci default: 3318f9f848faSopenharmony_ci str_ptr = ""; 3319f9f848faSopenharmony_ci break; 3320f9f848faSopenharmony_ci } 3321f9f848faSopenharmony_ci 3322f9f848faSopenharmony_ci len = usb_make_str_desc( 3323f9f848faSopenharmony_ci sc->sc_hub_desc.temp, 3324f9f848faSopenharmony_ci sizeof(sc->sc_hub_desc.temp), 3325f9f848faSopenharmony_ci str_ptr); 3326f9f848faSopenharmony_ci break; 3327f9f848faSopenharmony_ci 3328f9f848faSopenharmony_ci default: 3329f9f848faSopenharmony_ci err = USB_ERR_IOERROR; 3330f9f848faSopenharmony_ci goto done; 3331f9f848faSopenharmony_ci } 3332f9f848faSopenharmony_ci break; 3333f9f848faSopenharmony_ci case C(UR_GET_INTERFACE, UT_READ_INTERFACE): 3334f9f848faSopenharmony_ci len = 1; 3335f9f848faSopenharmony_ci sc->sc_hub_desc.temp[0] = 0; 3336f9f848faSopenharmony_ci break; 3337f9f848faSopenharmony_ci case C(UR_GET_STATUS, UT_READ_DEVICE): 3338f9f848faSopenharmony_ci len = 2; 3339f9f848faSopenharmony_ci USETW(sc->sc_hub_desc.stat.wStatus, UDS_SELF_POWERED); 3340f9f848faSopenharmony_ci break; 3341f9f848faSopenharmony_ci case C(UR_GET_STATUS, UT_READ_INTERFACE): 3342f9f848faSopenharmony_ci case C(UR_GET_STATUS, UT_READ_ENDPOINT): 3343f9f848faSopenharmony_ci len = 2; 3344f9f848faSopenharmony_ci USETW(sc->sc_hub_desc.stat.wStatus, 0); 3345f9f848faSopenharmony_ci break; 3346f9f848faSopenharmony_ci case C(UR_SET_ADDRESS, UT_WRITE_DEVICE): 3347f9f848faSopenharmony_ci if (value >= XHCI_MAX_DEVICES) { 3348f9f848faSopenharmony_ci err = USB_ERR_IOERROR; 3349f9f848faSopenharmony_ci goto done; 3350f9f848faSopenharmony_ci } 3351f9f848faSopenharmony_ci break; 3352f9f848faSopenharmony_ci case C(UR_SET_CONFIG, UT_WRITE_DEVICE): 3353f9f848faSopenharmony_ci if ((value != 0) && (value != 1)) { 3354f9f848faSopenharmony_ci err = USB_ERR_IOERROR; 3355f9f848faSopenharmony_ci goto done; 3356f9f848faSopenharmony_ci } 3357f9f848faSopenharmony_ci sc->sc_conf = value; 3358f9f848faSopenharmony_ci break; 3359f9f848faSopenharmony_ci case C(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE): 3360f9f848faSopenharmony_ci break; 3361f9f848faSopenharmony_ci case C(UR_SET_FEATURE, UT_WRITE_DEVICE): 3362f9f848faSopenharmony_ci case C(UR_SET_FEATURE, UT_WRITE_INTERFACE): 3363f9f848faSopenharmony_ci case C(UR_SET_FEATURE, UT_WRITE_ENDPOINT): 3364f9f848faSopenharmony_ci err = USB_ERR_IOERROR; 3365f9f848faSopenharmony_ci goto done; 3366f9f848faSopenharmony_ci case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE): 3367f9f848faSopenharmony_ci break; 3368f9f848faSopenharmony_ci case C(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT): 3369f9f848faSopenharmony_ci break; 3370f9f848faSopenharmony_ci /* Hub requests */ 3371f9f848faSopenharmony_ci case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_DEVICE): 3372f9f848faSopenharmony_ci break; 3373f9f848faSopenharmony_ci case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER): 3374f9f848faSopenharmony_ci DPRINTFN(9, "UR_CLEAR_PORT_FEATURE\n"); 3375f9f848faSopenharmony_ci 3376f9f848faSopenharmony_ci if ((index < 1) || 3377f9f848faSopenharmony_ci (index > sc->sc_noport)) { 3378f9f848faSopenharmony_ci err = USB_ERR_IOERROR; 3379f9f848faSopenharmony_ci goto done; 3380f9f848faSopenharmony_ci } 3381f9f848faSopenharmony_ci port = XHCI_PORTSC(index); 3382f9f848faSopenharmony_ci 3383f9f848faSopenharmony_ci v = XREAD4(sc, oper, port); 3384f9f848faSopenharmony_ci i = XHCI_PS_PLS_GET(v); 3385f9f848faSopenharmony_ci v &= ~XHCI_PS_CLEAR; 3386f9f848faSopenharmony_ci 3387f9f848faSopenharmony_ci switch (value) { 3388f9f848faSopenharmony_ci case UHF_C_BH_PORT_RESET: 3389f9f848faSopenharmony_ci XWRITE4(sc, oper, port, v | XHCI_PS_WRC); 3390f9f848faSopenharmony_ci break; 3391f9f848faSopenharmony_ci case UHF_C_PORT_CONFIG_ERROR: 3392f9f848faSopenharmony_ci XWRITE4(sc, oper, port, v | XHCI_PS_CEC); 3393f9f848faSopenharmony_ci break; 3394f9f848faSopenharmony_ci case UHF_C_PORT_SUSPEND: 3395f9f848faSopenharmony_ci case UHF_C_PORT_LINK_STATE: 3396f9f848faSopenharmony_ci XWRITE4(sc, oper, port, v | XHCI_PS_PLC); 3397f9f848faSopenharmony_ci break; 3398f9f848faSopenharmony_ci case UHF_C_PORT_CONNECTION: 3399f9f848faSopenharmony_ci XWRITE4(sc, oper, port, v | XHCI_PS_CSC); 3400f9f848faSopenharmony_ci break; 3401f9f848faSopenharmony_ci case UHF_C_PORT_ENABLE: 3402f9f848faSopenharmony_ci XWRITE4(sc, oper, port, v | XHCI_PS_PEC); 3403f9f848faSopenharmony_ci break; 3404f9f848faSopenharmony_ci case UHF_C_PORT_OVER_CURRENT: 3405f9f848faSopenharmony_ci XWRITE4(sc, oper, port, v | XHCI_PS_OCC); 3406f9f848faSopenharmony_ci break; 3407f9f848faSopenharmony_ci case UHF_C_PORT_RESET: 3408f9f848faSopenharmony_ci XWRITE4(sc, oper, port, v | XHCI_PS_PRC); 3409f9f848faSopenharmony_ci break; 3410f9f848faSopenharmony_ci case UHF_PORT_ENABLE: 3411f9f848faSopenharmony_ci XWRITE4(sc, oper, port, v | XHCI_PS_PED); 3412f9f848faSopenharmony_ci break; 3413f9f848faSopenharmony_ci case UHF_PORT_POWER: 3414f9f848faSopenharmony_ci XWRITE4(sc, oper, port, v & ~XHCI_PS_PP); 3415f9f848faSopenharmony_ci break; 3416f9f848faSopenharmony_ci case UHF_PORT_INDICATOR: 3417f9f848faSopenharmony_ci XWRITE4(sc, oper, port, v & ~XHCI_PS_PIC_SET(3)); 3418f9f848faSopenharmony_ci break; 3419f9f848faSopenharmony_ci case UHF_PORT_SUSPEND: 3420f9f848faSopenharmony_ci 3421f9f848faSopenharmony_ci /* U3 -> U15 */ 3422f9f848faSopenharmony_ci if (i == 3) { 3423f9f848faSopenharmony_ci XWRITE4(sc, oper, port, v | 3424f9f848faSopenharmony_ci XHCI_PS_PLS_SET(0xF) | XHCI_PS_LWS); 3425f9f848faSopenharmony_ci } 3426f9f848faSopenharmony_ci 3427f9f848faSopenharmony_ci /* wait 20ms for resume sequence to complete */ 3428f9f848faSopenharmony_ci usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 50); 3429f9f848faSopenharmony_ci 3430f9f848faSopenharmony_ci /* U0 */ 3431f9f848faSopenharmony_ci XWRITE4(sc, oper, port, v | 3432f9f848faSopenharmony_ci XHCI_PS_PLS_SET(0) | XHCI_PS_LWS); 3433f9f848faSopenharmony_ci break; 3434f9f848faSopenharmony_ci default: 3435f9f848faSopenharmony_ci err = USB_ERR_IOERROR; 3436f9f848faSopenharmony_ci goto done; 3437f9f848faSopenharmony_ci } 3438f9f848faSopenharmony_ci break; 3439f9f848faSopenharmony_ci 3440f9f848faSopenharmony_ci case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE): 3441f9f848faSopenharmony_ci if ((value & 0xff) != 0) { 3442f9f848faSopenharmony_ci err = USB_ERR_IOERROR; 3443f9f848faSopenharmony_ci goto done; 3444f9f848faSopenharmony_ci } 3445f9f848faSopenharmony_ci 3446f9f848faSopenharmony_ci v = XREAD4(sc, capa, XHCI_HCSPARAMS0); 3447f9f848faSopenharmony_ci 3448f9f848faSopenharmony_ci sc->sc_hub_desc.hubd = xhci_hubd; 3449f9f848faSopenharmony_ci 3450f9f848faSopenharmony_ci sc->sc_hub_desc.hubd.bNbrPorts = sc->sc_noport; 3451f9f848faSopenharmony_ci 3452f9f848faSopenharmony_ci if (XHCI_HCS0_PPC(v)) 3453f9f848faSopenharmony_ci i = UHD_PWR_INDIVIDUAL; 3454f9f848faSopenharmony_ci else 3455f9f848faSopenharmony_ci i = UHD_PWR_GANGED; 3456f9f848faSopenharmony_ci 3457f9f848faSopenharmony_ci if (XHCI_HCS0_PIND(v)) 3458f9f848faSopenharmony_ci i |= UHD_PORT_IND; 3459f9f848faSopenharmony_ci 3460f9f848faSopenharmony_ci i |= UHD_OC_INDIVIDUAL; 3461f9f848faSopenharmony_ci 3462f9f848faSopenharmony_ci USETW(sc->sc_hub_desc.hubd.wHubCharacteristics, i); 3463f9f848faSopenharmony_ci 3464f9f848faSopenharmony_ci /* see XHCI section 5.4.9: */ 3465f9f848faSopenharmony_ci sc->sc_hub_desc.hubd.bPwrOn2PwrGood = 10; 3466f9f848faSopenharmony_ci 3467f9f848faSopenharmony_ci for (j = 1; j <= sc->sc_noport; j++) { 3468f9f848faSopenharmony_ci v = XREAD4(sc, oper, XHCI_PORTSC(j)); 3469f9f848faSopenharmony_ci if (v & XHCI_PS_DR) { 3470f9f848faSopenharmony_ci sc->sc_hub_desc.hubd. 3471f9f848faSopenharmony_ci DeviceRemovable[j / 8] |= 1U << (j % 8); 3472f9f848faSopenharmony_ci } 3473f9f848faSopenharmony_ci } 3474f9f848faSopenharmony_ci len = sc->sc_hub_desc.hubd.bLength; 3475f9f848faSopenharmony_ci break; 3476f9f848faSopenharmony_ci 3477f9f848faSopenharmony_ci case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE): 3478f9f848faSopenharmony_ci len = 16; 3479f9f848faSopenharmony_ci (void)memset_s(sc->sc_hub_desc.temp, sizeof(sc->sc_hub_desc.temp), 0, len); 3480f9f848faSopenharmony_ci break; 3481f9f848faSopenharmony_ci 3482f9f848faSopenharmony_ci case C(UR_GET_STATUS, UT_READ_CLASS_OTHER): 3483f9f848faSopenharmony_ci DPRINTFN(9, "UR_GET_STATUS i=%d\n", index); 3484f9f848faSopenharmony_ci 3485f9f848faSopenharmony_ci if ((index < 1) || 3486f9f848faSopenharmony_ci (index > sc->sc_noport)) { 3487f9f848faSopenharmony_ci err = USB_ERR_IOERROR; 3488f9f848faSopenharmony_ci goto done; 3489f9f848faSopenharmony_ci } 3490f9f848faSopenharmony_ci 3491f9f848faSopenharmony_ci v = XREAD4(sc, oper, XHCI_PORTSC(index)); 3492f9f848faSopenharmony_ci 3493f9f848faSopenharmony_ci DPRINTFN(9, "port status=0x%08x\n", v); 3494f9f848faSopenharmony_ci 3495f9f848faSopenharmony_ci i = UPS_PORT_LINK_STATE_SET(XHCI_PS_PLS_GET(v)); 3496f9f848faSopenharmony_ci 3497f9f848faSopenharmony_ci switch (XHCI_PS_SPEED_GET(v)) { 3498f9f848faSopenharmony_ci case 3: 3499f9f848faSopenharmony_ci i |= UPS_HIGH_SPEED; 3500f9f848faSopenharmony_ci break; 3501f9f848faSopenharmony_ci case 2: 3502f9f848faSopenharmony_ci i |= UPS_LOW_SPEED; 3503f9f848faSopenharmony_ci break; 3504f9f848faSopenharmony_ci case 1: 3505f9f848faSopenharmony_ci /* FULL speed */ 3506f9f848faSopenharmony_ci break; 3507f9f848faSopenharmony_ci default: 3508f9f848faSopenharmony_ci i |= UPS_OTHER_SPEED; 3509f9f848faSopenharmony_ci break; 3510f9f848faSopenharmony_ci } 3511f9f848faSopenharmony_ci 3512f9f848faSopenharmony_ci if (v & XHCI_PS_CCS) 3513f9f848faSopenharmony_ci i |= UPS_CURRENT_CONNECT_STATUS; 3514f9f848faSopenharmony_ci if (v & XHCI_PS_PED) 3515f9f848faSopenharmony_ci i |= UPS_PORT_ENABLED; 3516f9f848faSopenharmony_ci if (v & XHCI_PS_OCA) 3517f9f848faSopenharmony_ci i |= UPS_OVERCURRENT_INDICATOR; 3518f9f848faSopenharmony_ci if (v & XHCI_PS_PR) 3519f9f848faSopenharmony_ci i |= UPS_RESET; 3520f9f848faSopenharmony_ci if (v & XHCI_PS_PP) { 3521f9f848faSopenharmony_ci /* 3522f9f848faSopenharmony_ci * The USB 3.0 RH is using the 3523f9f848faSopenharmony_ci * USB 2.0's power bit 3524f9f848faSopenharmony_ci */ 3525f9f848faSopenharmony_ci i |= UPS_PORT_POWER; 3526f9f848faSopenharmony_ci } 3527f9f848faSopenharmony_ci USETW(sc->sc_hub_desc.ps.wPortStatus, i); 3528f9f848faSopenharmony_ci 3529f9f848faSopenharmony_ci i = 0; 3530f9f848faSopenharmony_ci if (v & XHCI_PS_CSC) 3531f9f848faSopenharmony_ci i |= UPS_C_CONNECT_STATUS; 3532f9f848faSopenharmony_ci if (v & XHCI_PS_PEC) 3533f9f848faSopenharmony_ci i |= UPS_C_PORT_ENABLED; 3534f9f848faSopenharmony_ci if (v & XHCI_PS_OCC) 3535f9f848faSopenharmony_ci i |= UPS_C_OVERCURRENT_INDICATOR; 3536f9f848faSopenharmony_ci if (v & XHCI_PS_WRC) 3537f9f848faSopenharmony_ci i |= UPS_C_BH_PORT_RESET; 3538f9f848faSopenharmony_ci if (v & XHCI_PS_PRC) 3539f9f848faSopenharmony_ci i |= UPS_C_PORT_RESET; 3540f9f848faSopenharmony_ci if (v & XHCI_PS_PLC) 3541f9f848faSopenharmony_ci i |= UPS_C_PORT_LINK_STATE; 3542f9f848faSopenharmony_ci if (v & XHCI_PS_CEC) 3543f9f848faSopenharmony_ci i |= UPS_C_PORT_CONFIG_ERROR; 3544f9f848faSopenharmony_ci 3545f9f848faSopenharmony_ci USETW(sc->sc_hub_desc.ps.wPortChange, i); 3546f9f848faSopenharmony_ci len = sizeof(sc->sc_hub_desc.ps); 3547f9f848faSopenharmony_ci break; 3548f9f848faSopenharmony_ci 3549f9f848faSopenharmony_ci case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE): 3550f9f848faSopenharmony_ci err = USB_ERR_IOERROR; 3551f9f848faSopenharmony_ci goto done; 3552f9f848faSopenharmony_ci 3553f9f848faSopenharmony_ci case C(UR_SET_FEATURE, UT_WRITE_CLASS_DEVICE): 3554f9f848faSopenharmony_ci break; 3555f9f848faSopenharmony_ci 3556f9f848faSopenharmony_ci case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER): 3557f9f848faSopenharmony_ci 3558f9f848faSopenharmony_ci i = index >> 8; 3559f9f848faSopenharmony_ci index &= 0x00FF; 3560f9f848faSopenharmony_ci 3561f9f848faSopenharmony_ci if ((index < 1) || 3562f9f848faSopenharmony_ci (index > sc->sc_noport)) { 3563f9f848faSopenharmony_ci err = USB_ERR_IOERROR; 3564f9f848faSopenharmony_ci goto done; 3565f9f848faSopenharmony_ci } 3566f9f848faSopenharmony_ci 3567f9f848faSopenharmony_ci port = XHCI_PORTSC(index); 3568f9f848faSopenharmony_ci v = XREAD4(sc, oper, port) & ~XHCI_PS_CLEAR; 3569f9f848faSopenharmony_ci 3570f9f848faSopenharmony_ci switch (value) { 3571f9f848faSopenharmony_ci case UHF_PORT_U1_TIMEOUT: 3572f9f848faSopenharmony_ci if (XHCI_PS_SPEED_GET(v) != 4) { 3573f9f848faSopenharmony_ci err = USB_ERR_IOERROR; 3574f9f848faSopenharmony_ci goto done; 3575f9f848faSopenharmony_ci } 3576f9f848faSopenharmony_ci port = XHCI_PORTPMSC(index); 3577f9f848faSopenharmony_ci v = XREAD4(sc, oper, port); 3578f9f848faSopenharmony_ci v &= ~XHCI_PM3_U1TO_SET(0xFF); 3579f9f848faSopenharmony_ci v |= XHCI_PM3_U1TO_SET(i); 3580f9f848faSopenharmony_ci XWRITE4(sc, oper, port, v); 3581f9f848faSopenharmony_ci break; 3582f9f848faSopenharmony_ci case UHF_PORT_U2_TIMEOUT: 3583f9f848faSopenharmony_ci if (XHCI_PS_SPEED_GET(v) != 4) { 3584f9f848faSopenharmony_ci err = USB_ERR_IOERROR; 3585f9f848faSopenharmony_ci goto done; 3586f9f848faSopenharmony_ci } 3587f9f848faSopenharmony_ci port = XHCI_PORTPMSC(index); 3588f9f848faSopenharmony_ci v = XREAD4(sc, oper, port); 3589f9f848faSopenharmony_ci v &= ~XHCI_PM3_U2TO_SET(0xFF); 3590f9f848faSopenharmony_ci v |= XHCI_PM3_U2TO_SET(i); 3591f9f848faSopenharmony_ci XWRITE4(sc, oper, port, v); 3592f9f848faSopenharmony_ci break; 3593f9f848faSopenharmony_ci case UHF_BH_PORT_RESET: 3594f9f848faSopenharmony_ci XWRITE4(sc, oper, port, v | XHCI_PS_WPR); 3595f9f848faSopenharmony_ci break; 3596f9f848faSopenharmony_ci case UHF_PORT_LINK_STATE: 3597f9f848faSopenharmony_ci XWRITE4(sc, oper, port, v | 3598f9f848faSopenharmony_ci XHCI_PS_PLS_SET(i) | XHCI_PS_LWS); 3599f9f848faSopenharmony_ci /* 4ms settle time */ 3600f9f848faSopenharmony_ci usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 250); 3601f9f848faSopenharmony_ci break; 3602f9f848faSopenharmony_ci case UHF_PORT_ENABLE: 3603f9f848faSopenharmony_ci DPRINTFN(3, "set port enable %d\n", index); 3604f9f848faSopenharmony_ci break; 3605f9f848faSopenharmony_ci case UHF_PORT_SUSPEND: 3606f9f848faSopenharmony_ci DPRINTFN(6, "suspend port %u (LPM=%u)\n", index, i); 3607f9f848faSopenharmony_ci j = XHCI_PS_SPEED_GET(v); 3608f9f848faSopenharmony_ci if ((j < 1) || (j > 3)) { 3609f9f848faSopenharmony_ci /* non-supported speed */ 3610f9f848faSopenharmony_ci err = USB_ERR_IOERROR; 3611f9f848faSopenharmony_ci goto done; 3612f9f848faSopenharmony_ci } 3613f9f848faSopenharmony_ci XWRITE4(sc, oper, port, v | 3614f9f848faSopenharmony_ci XHCI_PS_PLS_SET(i ? 2 /* LPM */ : 3) | XHCI_PS_LWS); 3615f9f848faSopenharmony_ci break; 3616f9f848faSopenharmony_ci case UHF_PORT_RESET: 3617f9f848faSopenharmony_ci DPRINTFN(6, "reset port %d\n", index); 3618f9f848faSopenharmony_ci XWRITE4(sc, oper, port, v | XHCI_PS_PR); 3619f9f848faSopenharmony_ci break; 3620f9f848faSopenharmony_ci case UHF_PORT_POWER: 3621f9f848faSopenharmony_ci DPRINTFN(3, "set port power %d\n", index); 3622f9f848faSopenharmony_ci XWRITE4(sc, oper, port, v | XHCI_PS_PP); 3623f9f848faSopenharmony_ci break; 3624f9f848faSopenharmony_ci case UHF_PORT_TEST: 3625f9f848faSopenharmony_ci DPRINTFN(3, "set port test %d\n", index); 3626f9f848faSopenharmony_ci break; 3627f9f848faSopenharmony_ci case UHF_PORT_INDICATOR: 3628f9f848faSopenharmony_ci DPRINTFN(3, "set port indicator %d\n", index); 3629f9f848faSopenharmony_ci 3630f9f848faSopenharmony_ci v &= ~XHCI_PS_PIC_SET(3); 3631f9f848faSopenharmony_ci v |= XHCI_PS_PIC_SET(1); 3632f9f848faSopenharmony_ci 3633f9f848faSopenharmony_ci XWRITE4(sc, oper, port, v); 3634f9f848faSopenharmony_ci break; 3635f9f848faSopenharmony_ci default: 3636f9f848faSopenharmony_ci err = USB_ERR_IOERROR; 3637f9f848faSopenharmony_ci goto done; 3638f9f848faSopenharmony_ci } 3639f9f848faSopenharmony_ci break; 3640f9f848faSopenharmony_ci 3641f9f848faSopenharmony_ci case C(UR_CLEAR_TT_BUFFER, UT_WRITE_CLASS_OTHER): 3642f9f848faSopenharmony_ci case C(UR_RESET_TT, UT_WRITE_CLASS_OTHER): 3643f9f848faSopenharmony_ci case C(UR_GET_TT_STATE, UT_READ_CLASS_OTHER): 3644f9f848faSopenharmony_ci case C(UR_STOP_TT, UT_WRITE_CLASS_OTHER): 3645f9f848faSopenharmony_ci break; 3646f9f848faSopenharmony_ci default: 3647f9f848faSopenharmony_ci err = USB_ERR_IOERROR; 3648f9f848faSopenharmony_ci goto done; 3649f9f848faSopenharmony_ci } 3650f9f848faSopenharmony_cidone: 3651f9f848faSopenharmony_ci *plength = len; 3652f9f848faSopenharmony_ci *pptr = ptr; 3653f9f848faSopenharmony_ci return (err); 3654f9f848faSopenharmony_ci} 3655f9f848faSopenharmony_ci 3656f9f848faSopenharmony_cistatic void 3657f9f848faSopenharmony_cixhci_xfer_setup(struct usb_setup_params *parm) 3658f9f848faSopenharmony_ci{ 3659f9f848faSopenharmony_ci struct usb_page_search page_info; 3660f9f848faSopenharmony_ci struct usb_page_cache *pc; 3661f9f848faSopenharmony_ci struct usb_xfer *xfer; 3662f9f848faSopenharmony_ci void *last_obj; 3663f9f848faSopenharmony_ci uint32_t ntd; 3664f9f848faSopenharmony_ci uint32_t n; 3665f9f848faSopenharmony_ci 3666f9f848faSopenharmony_ci xfer = parm->curr_xfer; 3667f9f848faSopenharmony_ci 3668f9f848faSopenharmony_ci /* 3669f9f848faSopenharmony_ci * The proof for the "ntd" formula is illustrated like this: 3670f9f848faSopenharmony_ci * 3671f9f848faSopenharmony_ci * +------------------------------------+ 3672f9f848faSopenharmony_ci * | | 3673f9f848faSopenharmony_ci * | |remainder -> | 3674f9f848faSopenharmony_ci * | +-----+---+ | 3675f9f848faSopenharmony_ci * | | xxx | x | frm 0 | 3676f9f848faSopenharmony_ci * | +-----+---++ | 3677f9f848faSopenharmony_ci * | | xxx | xx | frm 1 | 3678f9f848faSopenharmony_ci * | +-----+----+ | 3679f9f848faSopenharmony_ci * | ... | 3680f9f848faSopenharmony_ci * +------------------------------------+ 3681f9f848faSopenharmony_ci * 3682f9f848faSopenharmony_ci * "xxx" means a completely full USB transfer descriptor 3683f9f848faSopenharmony_ci * 3684f9f848faSopenharmony_ci * "x" and "xx" means a short USB packet 3685f9f848faSopenharmony_ci * 3686f9f848faSopenharmony_ci * For the remainder of an USB transfer modulo 3687f9f848faSopenharmony_ci * "max_data_length" we need two USB transfer descriptors. 3688f9f848faSopenharmony_ci * One to transfer the remaining data and one to finalise with 3689f9f848faSopenharmony_ci * a zero length packet in case the "force_short_xfer" flag is 3690f9f848faSopenharmony_ci * set. We only need two USB transfer descriptors in the case 3691f9f848faSopenharmony_ci * where the transfer length of the first one is a factor of 3692f9f848faSopenharmony_ci * "max_frame_size". The rest of the needed USB transfer 3693f9f848faSopenharmony_ci * descriptors is given by the buffer size divided by the 3694f9f848faSopenharmony_ci * maximum data payload. 3695f9f848faSopenharmony_ci */ 3696f9f848faSopenharmony_ci parm->hc_max_packet_size = 0x400; 3697f9f848faSopenharmony_ci parm->hc_max_packet_count = 16 * 3; 3698f9f848faSopenharmony_ci parm->hc_max_frame_size = XHCI_TD_PAYLOAD_MAX; 3699f9f848faSopenharmony_ci 3700f9f848faSopenharmony_ci xfer->flags_int.bdma_enable = 1; 3701f9f848faSopenharmony_ci 3702f9f848faSopenharmony_ci usbd_transfer_setup_sub(parm); 3703f9f848faSopenharmony_ci 3704f9f848faSopenharmony_ci if (xfer->flags_int.isochronous_xfr) { 3705f9f848faSopenharmony_ci ntd = ((1 * xfer->nframes) 3706f9f848faSopenharmony_ci + (xfer->max_data_length / xfer->max_hc_frame_size)); 3707f9f848faSopenharmony_ci } else if (xfer->flags_int.control_xfr) { 3708f9f848faSopenharmony_ci ntd = ((2 * xfer->nframes) + 1 /* STATUS */ 3709f9f848faSopenharmony_ci + (xfer->max_data_length / xfer->max_hc_frame_size)); 3710f9f848faSopenharmony_ci } else { 3711f9f848faSopenharmony_ci ntd = ((2 * xfer->nframes) 3712f9f848faSopenharmony_ci + (xfer->max_data_length / xfer->max_hc_frame_size)); 3713f9f848faSopenharmony_ci } 3714f9f848faSopenharmony_ci 3715f9f848faSopenharmony_cialloc_dma_set: 3716f9f848faSopenharmony_ci 3717f9f848faSopenharmony_ci if (parm->err) 3718f9f848faSopenharmony_ci return; 3719f9f848faSopenharmony_ci 3720f9f848faSopenharmony_ci /* 3721f9f848faSopenharmony_ci * Allocate queue heads and transfer descriptors 3722f9f848faSopenharmony_ci */ 3723f9f848faSopenharmony_ci last_obj = NULL; 3724f9f848faSopenharmony_ci 3725f9f848faSopenharmony_ci if (usbd_transfer_setup_sub_malloc( 3726f9f848faSopenharmony_ci parm, &pc, sizeof(struct xhci_td), 3727f9f848faSopenharmony_ci XHCI_TD_ALIGN, ntd)) { 3728f9f848faSopenharmony_ci parm->err = USB_ERR_NOMEM; 3729f9f848faSopenharmony_ci return; 3730f9f848faSopenharmony_ci } 3731f9f848faSopenharmony_ci if (parm->buf) { 3732f9f848faSopenharmony_ci for (n = 0; n != ntd; n++) { 3733f9f848faSopenharmony_ci struct xhci_td *td; 3734f9f848faSopenharmony_ci 3735f9f848faSopenharmony_ci usbd_get_page(pc + n, 0, &page_info); 3736f9f848faSopenharmony_ci 3737f9f848faSopenharmony_ci td = page_info.buffer; 3738f9f848faSopenharmony_ci 3739f9f848faSopenharmony_ci /* init TD */ 3740f9f848faSopenharmony_ci td->td_self = page_info.physaddr; 3741f9f848faSopenharmony_ci td->obj_next = last_obj; 3742f9f848faSopenharmony_ci td->page_cache = pc + n; 3743f9f848faSopenharmony_ci 3744f9f848faSopenharmony_ci last_obj = td; 3745f9f848faSopenharmony_ci 3746f9f848faSopenharmony_ci usb_pc_cpu_flush(pc + n); 3747f9f848faSopenharmony_ci } 3748f9f848faSopenharmony_ci } 3749f9f848faSopenharmony_ci xfer->td_start[xfer->flags_int.curr_dma_set] = last_obj; 3750f9f848faSopenharmony_ci 3751f9f848faSopenharmony_ci if (!xfer->flags_int.curr_dma_set) { 3752f9f848faSopenharmony_ci xfer->flags_int.curr_dma_set = 1; 3753f9f848faSopenharmony_ci goto alloc_dma_set; 3754f9f848faSopenharmony_ci } 3755f9f848faSopenharmony_ci} 3756f9f848faSopenharmony_ci 3757f9f848faSopenharmony_cistatic usb_error_t 3758f9f848faSopenharmony_cixhci_configure_reset_endpoint(struct usb_xfer *xfer) 3759f9f848faSopenharmony_ci{ 3760f9f848faSopenharmony_ci struct xhci_softc *sc = XHCI_BUS2SC(xfer->xroot->bus); 3761f9f848faSopenharmony_ci struct usb_page_search buf_inp; 3762f9f848faSopenharmony_ci struct usb_device *udev; 3763f9f848faSopenharmony_ci struct xhci_endpoint_ext *pepext; 3764f9f848faSopenharmony_ci struct usb_endpoint_descriptor *edesc; 3765f9f848faSopenharmony_ci struct usb_page_cache *pcinp; 3766f9f848faSopenharmony_ci usb_error_t err; 3767f9f848faSopenharmony_ci usb_stream_t stream_id; 3768f9f848faSopenharmony_ci uint8_t index; 3769f9f848faSopenharmony_ci uint8_t epno; 3770f9f848faSopenharmony_ci 3771f9f848faSopenharmony_ci pepext = xhci_get_endpoint_ext(xfer->xroot->udev, 3772f9f848faSopenharmony_ci xfer->endpoint->edesc); 3773f9f848faSopenharmony_ci 3774f9f848faSopenharmony_ci udev = xfer->xroot->udev; 3775f9f848faSopenharmony_ci index = udev->controller_slot_id; 3776f9f848faSopenharmony_ci 3777f9f848faSopenharmony_ci pcinp = &sc->sc_hw.devs[index].input_pc; 3778f9f848faSopenharmony_ci 3779f9f848faSopenharmony_ci usbd_get_page(pcinp, 0, &buf_inp); 3780f9f848faSopenharmony_ci 3781f9f848faSopenharmony_ci edesc = xfer->endpoint->edesc; 3782f9f848faSopenharmony_ci 3783f9f848faSopenharmony_ci epno = edesc->bEndpointAddress; 3784f9f848faSopenharmony_ci stream_id = xfer->stream_id; 3785f9f848faSopenharmony_ci 3786f9f848faSopenharmony_ci if ((edesc->bmAttributes & UE_XFERTYPE) == UE_CONTROL) 3787f9f848faSopenharmony_ci epno |= UE_DIR_IN; 3788f9f848faSopenharmony_ci 3789f9f848faSopenharmony_ci epno = XHCI_EPNO2EPID(epno); 3790f9f848faSopenharmony_ci 3791f9f848faSopenharmony_ci if (epno == 0) 3792f9f848faSopenharmony_ci return (USB_ERR_NO_PIPE); /* invalid */ 3793f9f848faSopenharmony_ci 3794f9f848faSopenharmony_ci XHCI_CMD_LOCK(sc); 3795f9f848faSopenharmony_ci 3796f9f848faSopenharmony_ci /* configure endpoint */ 3797f9f848faSopenharmony_ci 3798f9f848faSopenharmony_ci err = xhci_configure_endpoint_by_xfer(xfer); 3799f9f848faSopenharmony_ci 3800f9f848faSopenharmony_ci if (err != 0) { 3801f9f848faSopenharmony_ci XHCI_CMD_UNLOCK(sc); 3802f9f848faSopenharmony_ci return (err); 3803f9f848faSopenharmony_ci } 3804f9f848faSopenharmony_ci 3805f9f848faSopenharmony_ci /* 3806f9f848faSopenharmony_ci * Get the endpoint into the stopped state according to the 3807f9f848faSopenharmony_ci * endpoint context state diagram in the XHCI specification: 3808f9f848faSopenharmony_ci */ 3809f9f848faSopenharmony_ci 3810f9f848faSopenharmony_ci err = xhci_cmd_stop_ep(sc, 0, epno, index); 3811f9f848faSopenharmony_ci 3812f9f848faSopenharmony_ci if (err != 0) 3813f9f848faSopenharmony_ci DPRINTF("Could not stop endpoint %u\n", epno); 3814f9f848faSopenharmony_ci 3815f9f848faSopenharmony_ci err = xhci_cmd_reset_ep(sc, 0, epno, index); 3816f9f848faSopenharmony_ci 3817f9f848faSopenharmony_ci if (err != 0) 3818f9f848faSopenharmony_ci DPRINTF("Could not reset endpoint %u\n", epno); 3819f9f848faSopenharmony_ci 3820f9f848faSopenharmony_ci err = xhci_cmd_set_tr_dequeue_ptr(sc, 3821f9f848faSopenharmony_ci (pepext->physaddr + (stream_id * sizeof(struct xhci_trb) * 3822f9f848faSopenharmony_ci XHCI_MAX_TRANSFERS)) | XHCI_EPCTX_2_DCS_SET(1), 3823f9f848faSopenharmony_ci stream_id, epno, index); 3824f9f848faSopenharmony_ci 3825f9f848faSopenharmony_ci if (err != 0) 3826f9f848faSopenharmony_ci DPRINTF("Could not set dequeue ptr for endpoint %u\n", epno); 3827f9f848faSopenharmony_ci 3828f9f848faSopenharmony_ci /* 3829f9f848faSopenharmony_ci * Get the endpoint into the running state according to the 3830f9f848faSopenharmony_ci * endpoint context state diagram in the XHCI specification: 3831f9f848faSopenharmony_ci */ 3832f9f848faSopenharmony_ci 3833f9f848faSopenharmony_ci (void)xhci_configure_mask(udev, (1U << epno) | 1U, 0); 3834f9f848faSopenharmony_ci 3835f9f848faSopenharmony_ci if (epno > 1) 3836f9f848faSopenharmony_ci err = xhci_cmd_configure_ep(sc, buf_inp.physaddr, 0, index); 3837f9f848faSopenharmony_ci else 3838f9f848faSopenharmony_ci err = xhci_cmd_evaluate_ctx(sc, buf_inp.physaddr, index); 3839f9f848faSopenharmony_ci 3840f9f848faSopenharmony_ci if (err != 0) 3841f9f848faSopenharmony_ci DPRINTF("Could not configure endpoint %u\n", epno); 3842f9f848faSopenharmony_ci 3843f9f848faSopenharmony_ci XHCI_CMD_UNLOCK(sc); 3844f9f848faSopenharmony_ci 3845f9f848faSopenharmony_ci return (USB_ERR_NORMAL_COMPLETION); 3846f9f848faSopenharmony_ci} 3847f9f848faSopenharmony_ci 3848f9f848faSopenharmony_cistatic void 3849f9f848faSopenharmony_cixhci_xfer_unsetup(struct usb_xfer *xfer) 3850f9f848faSopenharmony_ci{ 3851f9f848faSopenharmony_ci return; 3852f9f848faSopenharmony_ci} 3853f9f848faSopenharmony_ci 3854f9f848faSopenharmony_cistatic void 3855f9f848faSopenharmony_cixhci_start_dma_delay(struct usb_xfer *xfer) 3856f9f848faSopenharmony_ci{ 3857f9f848faSopenharmony_ci struct xhci_softc *sc = XHCI_BUS2SC(xfer->xroot->bus); 3858f9f848faSopenharmony_ci 3859f9f848faSopenharmony_ci /* put transfer on interrupt queue (again) */ 3860f9f848faSopenharmony_ci usbd_transfer_enqueue(&sc->sc_bus.intr_q, xfer); 3861f9f848faSopenharmony_ci 3862f9f848faSopenharmony_ci (void)usb_proc_msignal(USB_BUS_CONTROL_XFER_PROC(&sc->sc_bus), 3863f9f848faSopenharmony_ci &sc->sc_config_msg[0], &sc->sc_config_msg[1]); 3864f9f848faSopenharmony_ci} 3865f9f848faSopenharmony_ci 3866f9f848faSopenharmony_cistatic void 3867f9f848faSopenharmony_cixhci_configure_msg(struct usb_proc_msg *pm) 3868f9f848faSopenharmony_ci{ 3869f9f848faSopenharmony_ci struct xhci_softc *sc; 3870f9f848faSopenharmony_ci struct xhci_endpoint_ext *pepext; 3871f9f848faSopenharmony_ci struct usb_xfer *xfer; 3872f9f848faSopenharmony_ci 3873f9f848faSopenharmony_ci sc = XHCI_BUS2SC(((struct usb_bus_msg *)pm)->bus); 3874f9f848faSopenharmony_ci 3875f9f848faSopenharmony_cirestart: 3876f9f848faSopenharmony_ci TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { 3877f9f848faSopenharmony_ci pepext = xhci_get_endpoint_ext(xfer->xroot->udev, 3878f9f848faSopenharmony_ci xfer->endpoint->edesc); 3879f9f848faSopenharmony_ci 3880f9f848faSopenharmony_ci if ((pepext->trb_halted != 0) || 3881f9f848faSopenharmony_ci (pepext->trb_running == 0)) { 3882f9f848faSopenharmony_ci uint16_t i; 3883f9f848faSopenharmony_ci 3884f9f848faSopenharmony_ci /* clear halted and running */ 3885f9f848faSopenharmony_ci pepext->trb_halted = 0; 3886f9f848faSopenharmony_ci pepext->trb_running = 0; 3887f9f848faSopenharmony_ci 3888f9f848faSopenharmony_ci /* nuke remaining buffered transfers */ 3889f9f848faSopenharmony_ci 3890f9f848faSopenharmony_ci for (i = 0; i != (XHCI_MAX_TRANSFERS * 3891f9f848faSopenharmony_ci XHCI_MAX_STREAMS); i++) { 3892f9f848faSopenharmony_ci /* 3893f9f848faSopenharmony_ci * NOTE: We need to use the timeout 3894f9f848faSopenharmony_ci * error code here else existing 3895f9f848faSopenharmony_ci * isochronous clients can get 3896f9f848faSopenharmony_ci * confused: 3897f9f848faSopenharmony_ci */ 3898f9f848faSopenharmony_ci if (pepext->xfer[i] != NULL) { 3899f9f848faSopenharmony_ci xhci_device_done(pepext->xfer[i], 3900f9f848faSopenharmony_ci USB_ERR_TIMEOUT); 3901f9f848faSopenharmony_ci } 3902f9f848faSopenharmony_ci } 3903f9f848faSopenharmony_ci 3904f9f848faSopenharmony_ci /* 3905f9f848faSopenharmony_ci * NOTE: The USB transfer cannot vanish in 3906f9f848faSopenharmony_ci * this state! 3907f9f848faSopenharmony_ci */ 3908f9f848faSopenharmony_ci 3909f9f848faSopenharmony_ci USB_BUS_UNLOCK(&sc->sc_bus); 3910f9f848faSopenharmony_ci 3911f9f848faSopenharmony_ci (void)xhci_configure_reset_endpoint(xfer); 3912f9f848faSopenharmony_ci 3913f9f848faSopenharmony_ci USB_BUS_LOCK(&sc->sc_bus); 3914f9f848faSopenharmony_ci 3915f9f848faSopenharmony_ci /* check if halted is still cleared */ 3916f9f848faSopenharmony_ci if (pepext->trb_halted == 0) { 3917f9f848faSopenharmony_ci pepext->trb_running = 1; 3918f9f848faSopenharmony_ci (void)memset_s(pepext->trb_index, sizeof(pepext->trb_index), 3919f9f848faSopenharmony_ci 0, sizeof(pepext->trb_index)); 3920f9f848faSopenharmony_ci } 3921f9f848faSopenharmony_ci goto restart; 3922f9f848faSopenharmony_ci } 3923f9f848faSopenharmony_ci 3924f9f848faSopenharmony_ci if (xfer->flags_int.did_dma_delay) { 3925f9f848faSopenharmony_ci /* remove transfer from interrupt queue (again) */ 3926f9f848faSopenharmony_ci usbd_transfer_dequeue(xfer); 3927f9f848faSopenharmony_ci 3928f9f848faSopenharmony_ci /* we are finally done */ 3929f9f848faSopenharmony_ci usb_dma_delay_done_cb(xfer); 3930f9f848faSopenharmony_ci 3931f9f848faSopenharmony_ci /* queue changed - restart */ 3932f9f848faSopenharmony_ci goto restart; 3933f9f848faSopenharmony_ci } 3934f9f848faSopenharmony_ci } 3935f9f848faSopenharmony_ci 3936f9f848faSopenharmony_ci TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { 3937f9f848faSopenharmony_ci /* try to insert xfer on HW queue */ 3938f9f848faSopenharmony_ci (void)xhci_transfer_insert(xfer); 3939f9f848faSopenharmony_ci 3940f9f848faSopenharmony_ci /* try to multi buffer */ 3941f9f848faSopenharmony_ci xhci_device_generic_multi_enter(xfer->endpoint, 3942f9f848faSopenharmony_ci xfer->stream_id, NULL); 3943f9f848faSopenharmony_ci } 3944f9f848faSopenharmony_ci} 3945f9f848faSopenharmony_ci 3946f9f848faSopenharmony_cistatic void 3947f9f848faSopenharmony_cixhci_ep_init(struct usb_device *udev, struct usb_endpoint_descriptor *edesc, 3948f9f848faSopenharmony_ci struct usb_endpoint *ep) 3949f9f848faSopenharmony_ci{ 3950f9f848faSopenharmony_ci struct xhci_endpoint_ext *pepext; 3951f9f848faSopenharmony_ci 3952f9f848faSopenharmony_ci DPRINTFN(2, "endpoint=%p, addr=%d, endpt=%d, mode=%d\n", 3953f9f848faSopenharmony_ci ep, udev->address, edesc->bEndpointAddress, udev->flags.usb_mode); 3954f9f848faSopenharmony_ci 3955f9f848faSopenharmony_ci if (udev->parent_hub == NULL) { 3956f9f848faSopenharmony_ci /* root HUB has special endpoint handling */ 3957f9f848faSopenharmony_ci return; 3958f9f848faSopenharmony_ci } 3959f9f848faSopenharmony_ci 3960f9f848faSopenharmony_ci ep->methods = &xhci_device_generic_methods; 3961f9f848faSopenharmony_ci 3962f9f848faSopenharmony_ci pepext = xhci_get_endpoint_ext(udev, edesc); 3963f9f848faSopenharmony_ci 3964f9f848faSopenharmony_ci USB_BUS_LOCK(udev->bus); 3965f9f848faSopenharmony_ci pepext->trb_halted = 1; 3966f9f848faSopenharmony_ci pepext->trb_running = 0; 3967f9f848faSopenharmony_ci USB_BUS_UNLOCK(udev->bus); 3968f9f848faSopenharmony_ci} 3969f9f848faSopenharmony_ci 3970f9f848faSopenharmony_cistatic void 3971f9f848faSopenharmony_cixhci_ep_uninit(struct usb_device *udev, struct usb_endpoint *ep) 3972f9f848faSopenharmony_ci{ 3973f9f848faSopenharmony_ci 3974f9f848faSopenharmony_ci} 3975f9f848faSopenharmony_ci 3976f9f848faSopenharmony_cistatic void 3977f9f848faSopenharmony_cixhci_ep_clear_stall(struct usb_device *udev, struct usb_endpoint *ep) 3978f9f848faSopenharmony_ci{ 3979f9f848faSopenharmony_ci struct xhci_endpoint_ext *pepext; 3980f9f848faSopenharmony_ci 3981f9f848faSopenharmony_ci DPRINTF("\n"); 3982f9f848faSopenharmony_ci 3983f9f848faSopenharmony_ci if (udev->flags.usb_mode != USB_MODE_HOST) { 3984f9f848faSopenharmony_ci /* not supported */ 3985f9f848faSopenharmony_ci return; 3986f9f848faSopenharmony_ci } 3987f9f848faSopenharmony_ci if (udev->parent_hub == NULL) { 3988f9f848faSopenharmony_ci /* root HUB has special endpoint handling */ 3989f9f848faSopenharmony_ci return; 3990f9f848faSopenharmony_ci } 3991f9f848faSopenharmony_ci 3992f9f848faSopenharmony_ci pepext = xhci_get_endpoint_ext(udev, ep->edesc); 3993f9f848faSopenharmony_ci 3994f9f848faSopenharmony_ci USB_BUS_LOCK(udev->bus); 3995f9f848faSopenharmony_ci pepext->trb_halted = 1; 3996f9f848faSopenharmony_ci pepext->trb_running = 0; 3997f9f848faSopenharmony_ci USB_BUS_UNLOCK(udev->bus); 3998f9f848faSopenharmony_ci} 3999f9f848faSopenharmony_ci 4000f9f848faSopenharmony_cistatic usb_error_t 4001f9f848faSopenharmony_cixhci_device_init(struct usb_device *udev) 4002f9f848faSopenharmony_ci{ 4003f9f848faSopenharmony_ci struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); 4004f9f848faSopenharmony_ci usb_error_t err; 4005f9f848faSopenharmony_ci uint8_t temp; 4006f9f848faSopenharmony_ci 4007f9f848faSopenharmony_ci /* no init for root HUB */ 4008f9f848faSopenharmony_ci if (udev->parent_hub == NULL) 4009f9f848faSopenharmony_ci return (USB_ERR_NORMAL_COMPLETION); 4010f9f848faSopenharmony_ci 4011f9f848faSopenharmony_ci XHCI_CMD_LOCK(sc); 4012f9f848faSopenharmony_ci 4013f9f848faSopenharmony_ci /* set invalid default */ 4014f9f848faSopenharmony_ci 4015f9f848faSopenharmony_ci udev->controller_slot_id = sc->sc_noslot + 1; 4016f9f848faSopenharmony_ci 4017f9f848faSopenharmony_ci /* try to get a new slot ID from the XHCI */ 4018f9f848faSopenharmony_ci 4019f9f848faSopenharmony_ci err = xhci_cmd_enable_slot(sc, &temp); 4020f9f848faSopenharmony_ci 4021f9f848faSopenharmony_ci if (err) { 4022f9f848faSopenharmony_ci XHCI_CMD_UNLOCK(sc); 4023f9f848faSopenharmony_ci return (err); 4024f9f848faSopenharmony_ci } 4025f9f848faSopenharmony_ci 4026f9f848faSopenharmony_ci if (temp > sc->sc_noslot) { 4027f9f848faSopenharmony_ci XHCI_CMD_UNLOCK(sc); 4028f9f848faSopenharmony_ci return (USB_ERR_BAD_ADDRESS); 4029f9f848faSopenharmony_ci } 4030f9f848faSopenharmony_ci 4031f9f848faSopenharmony_ci if (sc->sc_hw.devs[temp].state != XHCI_ST_DISABLED) { 4032f9f848faSopenharmony_ci DPRINTF("slot %u already allocated.\n", temp); 4033f9f848faSopenharmony_ci XHCI_CMD_UNLOCK(sc); 4034f9f848faSopenharmony_ci return (USB_ERR_BAD_ADDRESS); 4035f9f848faSopenharmony_ci } 4036f9f848faSopenharmony_ci 4037f9f848faSopenharmony_ci /* store slot ID for later reference */ 4038f9f848faSopenharmony_ci 4039f9f848faSopenharmony_ci udev->controller_slot_id = temp; 4040f9f848faSopenharmony_ci 4041f9f848faSopenharmony_ci /* reset data structure */ 4042f9f848faSopenharmony_ci 4043f9f848faSopenharmony_ci (void)memset_s(&sc->sc_hw.devs[temp], sizeof(sc->sc_hw.devs[0]), 0, sizeof(sc->sc_hw.devs[0])); 4044f9f848faSopenharmony_ci 4045f9f848faSopenharmony_ci /* set mark slot allocated */ 4046f9f848faSopenharmony_ci 4047f9f848faSopenharmony_ci sc->sc_hw.devs[temp].state = XHCI_ST_ENABLED; 4048f9f848faSopenharmony_ci 4049f9f848faSopenharmony_ci err = xhci_alloc_device_ext(udev); 4050f9f848faSopenharmony_ci 4051f9f848faSopenharmony_ci XHCI_CMD_UNLOCK(sc); 4052f9f848faSopenharmony_ci 4053f9f848faSopenharmony_ci /* get device into default state */ 4054f9f848faSopenharmony_ci 4055f9f848faSopenharmony_ci if (err == 0) 4056f9f848faSopenharmony_ci err = xhci_set_address(udev, NULL, 0); 4057f9f848faSopenharmony_ci 4058f9f848faSopenharmony_ci return (err); 4059f9f848faSopenharmony_ci} 4060f9f848faSopenharmony_ci 4061f9f848faSopenharmony_cistatic void 4062f9f848faSopenharmony_cixhci_device_uninit(struct usb_device *udev) 4063f9f848faSopenharmony_ci{ 4064f9f848faSopenharmony_ci struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); 4065f9f848faSopenharmony_ci uint8_t index; 4066f9f848faSopenharmony_ci 4067f9f848faSopenharmony_ci /* no init for root HUB */ 4068f9f848faSopenharmony_ci if (udev->parent_hub == NULL) 4069f9f848faSopenharmony_ci return; 4070f9f848faSopenharmony_ci 4071f9f848faSopenharmony_ci XHCI_CMD_LOCK(sc); 4072f9f848faSopenharmony_ci 4073f9f848faSopenharmony_ci index = udev->controller_slot_id; 4074f9f848faSopenharmony_ci 4075f9f848faSopenharmony_ci if (index <= sc->sc_noslot) { 4076f9f848faSopenharmony_ci (void)xhci_cmd_disable_slot(sc, index); 4077f9f848faSopenharmony_ci sc->sc_hw.devs[index].state = XHCI_ST_DISABLED; 4078f9f848faSopenharmony_ci 4079f9f848faSopenharmony_ci /* free device extension */ 4080f9f848faSopenharmony_ci xhci_free_device_ext(udev); 4081f9f848faSopenharmony_ci } 4082f9f848faSopenharmony_ci 4083f9f848faSopenharmony_ci XHCI_CMD_UNLOCK(sc); 4084f9f848faSopenharmony_ci} 4085f9f848faSopenharmony_ci 4086f9f848faSopenharmony_cistatic void 4087f9f848faSopenharmony_cixhci_get_dma_delay(struct usb_device *udev, uint32_t *pus) 4088f9f848faSopenharmony_ci{ 4089f9f848faSopenharmony_ci /* 4090f9f848faSopenharmony_ci * Wait until the hardware has finished any possible use of 4091f9f848faSopenharmony_ci * the transfer descriptor(s) 4092f9f848faSopenharmony_ci */ 4093f9f848faSopenharmony_ci *pus = 2048; /* microseconds */ 4094f9f848faSopenharmony_ci} 4095f9f848faSopenharmony_ci 4096f9f848faSopenharmony_cistatic void 4097f9f848faSopenharmony_cixhci_device_resume(struct usb_device *udev) 4098f9f848faSopenharmony_ci{ 4099f9f848faSopenharmony_ci struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); 4100f9f848faSopenharmony_ci uint8_t index; 4101f9f848faSopenharmony_ci uint8_t n; 4102f9f848faSopenharmony_ci uint8_t p; 4103f9f848faSopenharmony_ci 4104f9f848faSopenharmony_ci DPRINTF("\n"); 4105f9f848faSopenharmony_ci 4106f9f848faSopenharmony_ci /* check for root HUB */ 4107f9f848faSopenharmony_ci if (udev->parent_hub == NULL) 4108f9f848faSopenharmony_ci return; 4109f9f848faSopenharmony_ci 4110f9f848faSopenharmony_ci index = udev->controller_slot_id; 4111f9f848faSopenharmony_ci 4112f9f848faSopenharmony_ci XHCI_CMD_LOCK(sc); 4113f9f848faSopenharmony_ci 4114f9f848faSopenharmony_ci /* blindly resume all endpoints */ 4115f9f848faSopenharmony_ci 4116f9f848faSopenharmony_ci USB_BUS_LOCK(udev->bus); 4117f9f848faSopenharmony_ci 4118f9f848faSopenharmony_ci for (n = 1; n != XHCI_MAX_ENDPOINTS; n++) { 4119f9f848faSopenharmony_ci for (p = 0; p != XHCI_MAX_STREAMS; p++) { 4120f9f848faSopenharmony_ci XWRITE4(sc, door, XHCI_DOORBELL(index), 4121f9f848faSopenharmony_ci n | XHCI_DB_SID_SET(p)); 4122f9f848faSopenharmony_ci } 4123f9f848faSopenharmony_ci } 4124f9f848faSopenharmony_ci 4125f9f848faSopenharmony_ci USB_BUS_UNLOCK(udev->bus); 4126f9f848faSopenharmony_ci 4127f9f848faSopenharmony_ci XHCI_CMD_UNLOCK(sc); 4128f9f848faSopenharmony_ci} 4129f9f848faSopenharmony_ci 4130f9f848faSopenharmony_cistatic void 4131f9f848faSopenharmony_cixhci_device_suspend(struct usb_device *udev) 4132f9f848faSopenharmony_ci{ 4133f9f848faSopenharmony_ci struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); 4134f9f848faSopenharmony_ci uint8_t index; 4135f9f848faSopenharmony_ci uint8_t n; 4136f9f848faSopenharmony_ci usb_error_t err; 4137f9f848faSopenharmony_ci 4138f9f848faSopenharmony_ci DPRINTF("\n"); 4139f9f848faSopenharmony_ci 4140f9f848faSopenharmony_ci /* check for root HUB */ 4141f9f848faSopenharmony_ci if (udev->parent_hub == NULL) 4142f9f848faSopenharmony_ci return; 4143f9f848faSopenharmony_ci 4144f9f848faSopenharmony_ci index = udev->controller_slot_id; 4145f9f848faSopenharmony_ci 4146f9f848faSopenharmony_ci XHCI_CMD_LOCK(sc); 4147f9f848faSopenharmony_ci 4148f9f848faSopenharmony_ci /* blindly suspend all endpoints */ 4149f9f848faSopenharmony_ci 4150f9f848faSopenharmony_ci for (n = 1; n != XHCI_MAX_ENDPOINTS; n++) { 4151f9f848faSopenharmony_ci err = xhci_cmd_stop_ep(sc, 1, n, index); 4152f9f848faSopenharmony_ci if (err != 0) { 4153f9f848faSopenharmony_ci DPRINTF("Failed to suspend endpoint " 4154f9f848faSopenharmony_ci "%u on slot %u (ignored).\n", n, index); 4155f9f848faSopenharmony_ci } 4156f9f848faSopenharmony_ci } 4157f9f848faSopenharmony_ci 4158f9f848faSopenharmony_ci XHCI_CMD_UNLOCK(sc); 4159f9f848faSopenharmony_ci} 4160f9f848faSopenharmony_ci 4161f9f848faSopenharmony_cistatic void 4162f9f848faSopenharmony_cixhci_set_hw_power(struct usb_bus *bus) 4163f9f848faSopenharmony_ci{ 4164f9f848faSopenharmony_ci DPRINTF("\n"); 4165f9f848faSopenharmony_ci} 4166f9f848faSopenharmony_ci 4167f9f848faSopenharmony_cistatic void 4168f9f848faSopenharmony_cixhci_device_state_change(struct usb_device *udev) 4169f9f848faSopenharmony_ci{ 4170f9f848faSopenharmony_ci struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); 4171f9f848faSopenharmony_ci struct usb_page_search buf_inp; 4172f9f848faSopenharmony_ci usb_error_t err; 4173f9f848faSopenharmony_ci uint8_t index; 4174f9f848faSopenharmony_ci 4175f9f848faSopenharmony_ci /* check for root HUB */ 4176f9f848faSopenharmony_ci if (udev->parent_hub == NULL) 4177f9f848faSopenharmony_ci return; 4178f9f848faSopenharmony_ci 4179f9f848faSopenharmony_ci index = udev->controller_slot_id; 4180f9f848faSopenharmony_ci 4181f9f848faSopenharmony_ci DPRINTF("\n"); 4182f9f848faSopenharmony_ci 4183f9f848faSopenharmony_ci if (usb_get_device_state(udev) == USB_STATE_CONFIGURED) { 4184f9f848faSopenharmony_ci err = uhub_query_info(udev, &sc->sc_hw.devs[index].nports, 4185f9f848faSopenharmony_ci &sc->sc_hw.devs[index].tt); 4186f9f848faSopenharmony_ci if (err != 0) 4187f9f848faSopenharmony_ci sc->sc_hw.devs[index].nports = 0; 4188f9f848faSopenharmony_ci } 4189f9f848faSopenharmony_ci 4190f9f848faSopenharmony_ci XHCI_CMD_LOCK(sc); 4191f9f848faSopenharmony_ci 4192f9f848faSopenharmony_ci switch (usb_get_device_state(udev)) { 4193f9f848faSopenharmony_ci case USB_STATE_POWERED: 4194f9f848faSopenharmony_ci if (sc->sc_hw.devs[index].state == XHCI_ST_DEFAULT) 4195f9f848faSopenharmony_ci break; 4196f9f848faSopenharmony_ci 4197f9f848faSopenharmony_ci /* set default state */ 4198f9f848faSopenharmony_ci sc->sc_hw.devs[index].state = XHCI_ST_DEFAULT; 4199f9f848faSopenharmony_ci 4200f9f848faSopenharmony_ci /* reset number of contexts */ 4201f9f848faSopenharmony_ci sc->sc_hw.devs[index].context_num = 0; 4202f9f848faSopenharmony_ci 4203f9f848faSopenharmony_ci err = xhci_cmd_reset_dev(sc, index); 4204f9f848faSopenharmony_ci 4205f9f848faSopenharmony_ci if (err != 0) { 4206f9f848faSopenharmony_ci DPRINTF("Device reset failed " 4207f9f848faSopenharmony_ci "for slot %u.\n", index); 4208f9f848faSopenharmony_ci } 4209f9f848faSopenharmony_ci break; 4210f9f848faSopenharmony_ci 4211f9f848faSopenharmony_ci case USB_STATE_ADDRESSED: 4212f9f848faSopenharmony_ci if (sc->sc_hw.devs[index].state == XHCI_ST_ADDRESSED) 4213f9f848faSopenharmony_ci break; 4214f9f848faSopenharmony_ci 4215f9f848faSopenharmony_ci sc->sc_hw.devs[index].state = XHCI_ST_ADDRESSED; 4216f9f848faSopenharmony_ci 4217f9f848faSopenharmony_ci /* set configure mask to slot only */ 4218f9f848faSopenharmony_ci (void)xhci_configure_mask(udev, 1, 0); 4219f9f848faSopenharmony_ci 4220f9f848faSopenharmony_ci err = xhci_cmd_configure_ep(sc, 0, 1, index); 4221f9f848faSopenharmony_ci 4222f9f848faSopenharmony_ci if (err) { 4223f9f848faSopenharmony_ci DPRINTF("Failed to deconfigure " 4224f9f848faSopenharmony_ci "slot %u.\n", index); 4225f9f848faSopenharmony_ci } 4226f9f848faSopenharmony_ci break; 4227f9f848faSopenharmony_ci 4228f9f848faSopenharmony_ci case USB_STATE_CONFIGURED: 4229f9f848faSopenharmony_ci if (sc->sc_hw.devs[index].state == XHCI_ST_CONFIGURED) 4230f9f848faSopenharmony_ci break; 4231f9f848faSopenharmony_ci 4232f9f848faSopenharmony_ci /* set configured state */ 4233f9f848faSopenharmony_ci sc->sc_hw.devs[index].state = XHCI_ST_CONFIGURED; 4234f9f848faSopenharmony_ci 4235f9f848faSopenharmony_ci /* reset number of contexts */ 4236f9f848faSopenharmony_ci sc->sc_hw.devs[index].context_num = 0; 4237f9f848faSopenharmony_ci 4238f9f848faSopenharmony_ci usbd_get_page(&sc->sc_hw.devs[index].input_pc, 0, &buf_inp); 4239f9f848faSopenharmony_ci 4240f9f848faSopenharmony_ci (void)xhci_configure_mask(udev, 3, 0); 4241f9f848faSopenharmony_ci 4242f9f848faSopenharmony_ci err = xhci_configure_device(udev); 4243f9f848faSopenharmony_ci if (err != 0) { 4244f9f848faSopenharmony_ci DPRINTF("Could not configure device " 4245f9f848faSopenharmony_ci "at slot %u.\n", index); 4246f9f848faSopenharmony_ci } 4247f9f848faSopenharmony_ci 4248f9f848faSopenharmony_ci err = xhci_cmd_evaluate_ctx(sc, buf_inp.physaddr, index); 4249f9f848faSopenharmony_ci if (err != 0) { 4250f9f848faSopenharmony_ci DPRINTF("Could not evaluate device " 4251f9f848faSopenharmony_ci "context at slot %u.\n", index); 4252f9f848faSopenharmony_ci } 4253f9f848faSopenharmony_ci break; 4254f9f848faSopenharmony_ci 4255f9f848faSopenharmony_ci default: 4256f9f848faSopenharmony_ci break; 4257f9f848faSopenharmony_ci } 4258f9f848faSopenharmony_ci XHCI_CMD_UNLOCK(sc); 4259f9f848faSopenharmony_ci} 4260f9f848faSopenharmony_ci 4261f9f848faSopenharmony_cistatic usb_error_t 4262f9f848faSopenharmony_cixhci_set_endpoint_mode(struct usb_device *udev, struct usb_endpoint *ep, 4263f9f848faSopenharmony_ci uint8_t ep_mode) 4264f9f848faSopenharmony_ci{ 4265f9f848faSopenharmony_ci switch (ep_mode) { 4266f9f848faSopenharmony_ci case USB_EP_MODE_DEFAULT: 4267f9f848faSopenharmony_ci return (USB_ERR_NORMAL_COMPLETION); 4268f9f848faSopenharmony_ci case USB_EP_MODE_STREAMS: 4269f9f848faSopenharmony_ci if ((xhcistreams == 0) || 4270f9f848faSopenharmony_ci ((ep->edesc->bmAttributes & UE_XFERTYPE) != UE_BULK) || 4271f9f848faSopenharmony_ci (udev->speed != USB_SPEED_SUPER)) 4272f9f848faSopenharmony_ci return (USB_ERR_INVAL); 4273f9f848faSopenharmony_ci return (USB_ERR_NORMAL_COMPLETION); 4274f9f848faSopenharmony_ci default: 4275f9f848faSopenharmony_ci return (USB_ERR_INVAL); 4276f9f848faSopenharmony_ci } 4277f9f848faSopenharmony_ci} 4278f9f848faSopenharmony_ci 4279f9f848faSopenharmony_cistruct usb_bus_methods xhci_bus_methods = { 4280f9f848faSopenharmony_ci .endpoint_init = xhci_ep_init, 4281f9f848faSopenharmony_ci .endpoint_uninit = xhci_ep_uninit, 4282f9f848faSopenharmony_ci .xfer_setup = xhci_xfer_setup, 4283f9f848faSopenharmony_ci .xfer_unsetup = xhci_xfer_unsetup, 4284f9f848faSopenharmony_ci .get_dma_delay = xhci_get_dma_delay, 4285f9f848faSopenharmony_ci .device_init = xhci_device_init, 4286f9f848faSopenharmony_ci .device_uninit = xhci_device_uninit, 4287f9f848faSopenharmony_ci .device_resume = xhci_device_resume, 4288f9f848faSopenharmony_ci .device_suspend = xhci_device_suspend, 4289f9f848faSopenharmony_ci .set_hw_power = xhci_set_hw_power, 4290f9f848faSopenharmony_ci .roothub_exec = xhci_roothub_exec, 4291f9f848faSopenharmony_ci .xfer_poll = xhci_do_poll, 4292f9f848faSopenharmony_ci .start_dma_delay = xhci_start_dma_delay, 4293f9f848faSopenharmony_ci .set_address = xhci_set_address, 4294f9f848faSopenharmony_ci .clear_stall = xhci_ep_clear_stall, 4295f9f848faSopenharmony_ci .device_state_change = xhci_device_state_change, 4296f9f848faSopenharmony_ci .set_hw_power_sleep = xhci_set_hw_power_sleep, 4297f9f848faSopenharmony_ci .set_endpoint_mode = xhci_set_endpoint_mode, 4298f9f848faSopenharmony_ci}; 4299