1 /* $NetBSD: ehcivar.h,v 1.55 2026/05/02 07:23:00 tsutsui Exp $ */ 2 3 /* 4 * Copyright (c) 2001 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Lennart Augustsson (lennart (at) augustsson.net). 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #ifndef _EHCIVAR_H_ 33 #define _EHCIVAR_H_ 34 35 #include <sys/pool.h> 36 37 typedef struct ehci_soft_qtd { 38 ehci_qtd_t *qtd; 39 struct ehci_soft_qtd *nextqtd; /* mirrors nextqtd in TD */ 40 ehci_physaddr_t physaddr; /* qTD's physical address */ 41 usb_dma_t dma; /* qTD's DMA infos */ 42 int offs; /* qTD's offset in usb_dma_t */ 43 struct usbd_xfer *xfer; /* xfer back pointer */ 44 uint16_t len; 45 } ehci_soft_qtd_t; 46 47 typedef struct ehci_soft_qh { 48 ehci_qh_t *qh; 49 struct ehci_soft_qh *next; 50 struct ehci_soft_qtd *sqtd; 51 ehci_physaddr_t physaddr; 52 usb_dma_t dma; /* QH's DMA infos */ 53 int offs; /* QH's offset in usb_dma_t */ 54 int islot; 55 } ehci_soft_qh_t; 56 57 typedef struct ehci_soft_itd { 58 union { 59 ehci_itd_t *itd; 60 ehci_sitd_t *sitd; 61 }; 62 union { 63 struct { 64 /* soft_itds links in a periodic frame */ 65 struct ehci_soft_itd *next; 66 struct ehci_soft_itd *prev; 67 } frame_list; 68 /* circular list of free itds */ 69 LIST_ENTRY(ehci_soft_itd) free_list; 70 }; 71 struct ehci_soft_itd *xfer_next; /* Next soft_itd in xfer */ 72 ehci_physaddr_t physaddr; 73 usb_dma_t dma; 74 int offs; 75 int slot; 76 struct timeval t; /* store free time */ 77 } ehci_soft_itd_t; 78 79 #define ehci_soft_sitd_t ehci_soft_itd_t 80 #define ehci_soft_sitd ehci_soft_itd 81 #define sc_softsitds sc_softitds 82 83 struct ehci_xfer { 84 struct usbd_xfer ex_xfer; 85 TAILQ_ENTRY(ehci_xfer) ex_next; /* list of active xfers */ 86 enum { 87 EX_NONE, 88 EX_CTRL, 89 EX_BULK, 90 EX_INTR, 91 EX_ISOC, 92 EX_FS_ISOC 93 } ex_type; 94 /* ctrl/bulk/intr */ 95 struct { 96 ehci_soft_qtd_t **ex_sqtds; 97 size_t ex_nsqtd; 98 }; 99 union { 100 /* ctrl */ 101 struct { 102 ehci_soft_qtd_t *ex_setup; 103 ehci_soft_qtd_t *ex_data; 104 ehci_soft_qtd_t *ex_status; 105 }; 106 /* bulk/intr */ 107 struct { 108 ehci_soft_qtd_t *ex_sqtdstart; 109 ehci_soft_qtd_t *ex_sqtdend; 110 }; 111 /* isoc */ 112 struct { 113 ehci_soft_itd_t *ex_itdstart; 114 ehci_soft_itd_t *ex_itdend; 115 }; 116 /* split (aka fs) isoc */ 117 struct { 118 ehci_soft_sitd_t *ex_sitdstart; 119 ehci_soft_sitd_t *ex_sitdend; 120 }; 121 }; 122 bool ex_isdone; /* used only when DIAGNOSTIC is defined */ 123 }; 124 125 #define EHCI_BUS2SC(bus) ((bus)->ub_hcpriv) 126 #define EHCI_PIPE2SC(pipe) EHCI_BUS2SC((pipe)->up_dev->ud_bus) 127 #define EHCI_XFER2SC(xfer) EHCI_BUS2SC((xfer)->ux_bus) 128 #define EHCI_EPIPE2SC(epipe) EHCI_BUS2SC((epipe)->pipe.up_dev->ud_bus) 129 130 #define EHCI_XFER2EXFER(xfer) ((struct ehci_xfer *)(xfer)) 131 132 #define EHCI_XFER2EPIPE(xfer) ((struct ehci_pipe *)((xfer)->ux_pipe)) 133 #define EHCI_PIPE2EPIPE(pipe) ((struct ehci_pipe *)(pipe)) 134 135 /* Information about an entry in the interrupt list. */ 136 struct ehci_soft_islot { 137 ehci_soft_qh_t *sqh; /* Queue Head. */ 138 }; 139 140 #define EHCI_FRAMELIST_MAXCOUNT 1024 141 #define EHCI_IPOLLRATES 8 /* Poll rates (1ms, 2, 4, 8 .. 128) */ 142 #define EHCI_INTRQHS ((1 << EHCI_IPOLLRATES) - 1) 143 #define EHCI_MAX_POLLRATE (1 << (EHCI_IPOLLRATES - 1)) 144 #define EHCI_IQHIDX(lev, pos) \ 145 ((((pos) & ((1 << (lev)) - 1)) | (1 << (lev))) - 1) 146 #define EHCI_ILEV_IVAL(lev) (1 << (lev)) 147 148 149 #define EHCI_HASH_SIZE 128 150 #define EHCI_COMPANION_MAX 8 151 152 #define EHCI_FREE_LIST_INTERVAL 100 153 154 typedef struct ehci_softc { 155 device_t sc_dev; 156 kmutex_t sc_rhlock; 157 kmutex_t sc_lock; 158 kmutex_t sc_intr_lock; 159 kcondvar_t sc_doorbell; 160 void *sc_doorbell_si; 161 struct lwp *sc_doorbelllwp; 162 void *sc_pcd_si; 163 struct usbd_bus sc_bus; 164 bus_space_tag_t iot; 165 bus_space_handle_t ioh; 166 bus_size_t sc_size; 167 bus_dma_tag_t sc_dmatag; /* for control data structures */ 168 u_int sc_offs; /* offset to operational regs */ 169 int sc_flags; /* misc flags */ 170 #define EHCIF_DROPPED_INTR_WORKAROUND 0x01 171 #define EHCIF_ETTF 0x02 /* Emb. Transaction Translater func. */ 172 #define EHCIF_32BIT_ACCESS 0x04 /* 32-bit MMIO access req'd */ 173 #define EHCIF_SB600_ASYNCLIST_RELOAD 0x08 /* SB600 quirk (PR/57359) */ 174 175 uint32_t sc_cmd; /* shadow of cmd reg during suspend */ 176 177 u_int sc_ncomp; 178 u_int sc_npcomp; 179 device_t sc_comps[EHCI_COMPANION_MAX]; 180 181 /* This chunk to handle early RB_ASKNAME hand over. */ 182 callout_t sc_compcallout; 183 kmutex_t sc_complock; 184 kcondvar_t sc_compcv; 185 enum { 186 CO_EARLY, 187 CO_SCHED, 188 CO_DONE, 189 } sc_comp_state; 190 191 usb_dma_t sc_fldma; 192 ehci_link_t *sc_flist; 193 u_int sc_flsize; 194 u_int sc_rand; /* XXX need proper intr scheduling */ 195 196 struct ehci_soft_islot sc_islots[EHCI_INTRQHS]; 197 198 /* 199 * an array matching sc_flist, but with software pointers, 200 * not hardware address pointers 201 */ 202 struct ehci_soft_itd **sc_softitds; 203 204 TAILQ_HEAD(, ehci_xfer) sc_intrhead; 205 206 ehci_soft_qh_t *sc_freeqhs; 207 ehci_soft_qtd_t *sc_freeqtds; 208 LIST_HEAD(sc_freeitds, ehci_soft_itd) sc_freeitds; 209 LIST_HEAD(sc_freesitds, ehci_soft_sitd) sc_freesitds; 210 211 int sc_noport; 212 uint8_t sc_hasppc; /* has Port Power Control */ 213 uint8_t sc_istthreshold; /* ISOC Scheduling Threshold (uframes) */ 214 struct usbd_xfer *sc_intrxfer; 215 char sc_isreset[EHCI_MAX_PORTS]; 216 217 uint32_t sc_eintrs; 218 ehci_soft_qh_t *sc_async_head; 219 220 pool_cache_t sc_xferpool; /* free xfer pool */ 221 222 struct callout sc_tmo_intrlist; 223 224 device_t sc_child; /* /dev/usb# device */ 225 char sc_dying; 226 227 void (*sc_vendor_init)(struct ehci_softc *); 228 int (*sc_vendor_port_status)(struct ehci_softc *, uint32_t, int); 229 } ehci_softc_t; 230 231 static inline uint8_t 232 ehci_read_1(struct ehci_softc *sc, u_int offset) 233 { 234 if (ISSET(sc->sc_flags, EHCIF_32BIT_ACCESS)) { 235 uint32_t val; 236 237 val = bus_space_read_4(sc->iot, sc->ioh, offset & ~3); 238 return (val >> ((offset & 3) * NBBY)) & 0xff; 239 } else { 240 return bus_space_read_1(sc->iot, sc->ioh, offset); 241 } 242 } 243 244 static inline uint16_t 245 ehci_read_2(struct ehci_softc *sc, u_int offset) 246 { 247 if (ISSET(sc->sc_flags, EHCIF_32BIT_ACCESS)) { 248 uint32_t val; 249 250 val = bus_space_read_4(sc->iot, sc->ioh, offset & ~3); 251 return (val >> ((offset & 3) * NBBY)) & 0xffff; 252 } else { 253 return bus_space_read_2(sc->iot, sc->ioh, offset); 254 } 255 } 256 257 static inline void 258 ehci_write_1(struct ehci_softc *sc, u_int offset, uint8_t data) 259 { 260 if (ISSET(sc->sc_flags, EHCIF_32BIT_ACCESS)) { 261 const uint32_t mask = 0xffU << ((offset & 3) * NBBY); 262 uint32_t val; 263 264 val = bus_space_read_4(sc->iot, sc->ioh, offset & ~3); 265 val &= ~mask; 266 val |= __SHIFTIN(data, mask); 267 bus_space_write_4(sc->iot, sc->ioh, offset & ~3, val); 268 } else { 269 bus_space_write_1(sc->iot, sc->ioh, offset, data); 270 } 271 } 272 273 static inline void 274 ehci_write_2(struct ehci_softc *sc, u_int offset, uint16_t data) 275 { 276 if (ISSET(sc->sc_flags, EHCIF_32BIT_ACCESS)) { 277 const uint32_t mask = 0xffffU << ((offset & 3) * NBBY); 278 uint32_t val; 279 280 val = bus_space_read_4(sc->iot, sc->ioh, offset & ~3); 281 val &= ~mask; 282 val |= __SHIFTIN(data, mask); 283 bus_space_write_4(sc->iot, sc->ioh, offset & ~3, val); 284 } else { 285 bus_space_write_2(sc->iot, sc->ioh, offset, data); 286 } 287 } 288 289 #define EREAD1(sc, a) ehci_read_1((sc), (a)) 290 #define EREAD2(sc, a) ehci_read_2((sc), (a)) 291 #define EREAD4(sc, a) bus_space_read_4((sc)->iot, (sc)->ioh, (a)) 292 #define EWRITE1(sc, a, x) ehci_write_1((sc), (a), (x)) 293 #define EWRITE2(sc, a, x) ehci_write_2((sc), (a), (x)) 294 #define EWRITE4(sc, a, x) bus_space_write_4((sc)->iot, (sc)->ioh, (a), (x)) 295 #define EOREAD1(sc, a) ehci_read_1((sc), (sc)->sc_offs+(a)) 296 #define EOREAD2(sc, a) ehci_read_2((sc), (sc)->sc_offs+(a)) 297 #define EOREAD4(sc, a) bus_space_read_4((sc)->iot, (sc)->ioh, (sc)->sc_offs+(a)) 298 #define EOWRITE1(sc, a, x) ehci_write_1((sc), (sc)->sc_offs+(a), (x)) 299 #define EOWRITE2(sc, a, x) ehci_write_2((sc), (sc)->sc_offs+(a), (x)) 300 #define EOWRITE4(sc, a, x) bus_space_write_4((sc)->iot, (sc)->ioh, (sc)->sc_offs+(a), (x)) 301 302 int ehci_init(ehci_softc_t *); 303 int ehci_intr(void *); 304 int ehci_detach(ehci_softc_t *, int); 305 int ehci_activate(device_t, enum devact); 306 void ehci_childdet(device_t, device_t); 307 bool ehci_suspend(device_t, const pmf_qual_t *); 308 bool ehci_resume(device_t, const pmf_qual_t *); 309 bool ehci_shutdown(device_t, int); 310 311 #endif /* _EHCIVAR_H_ */ 312