1 /* $NetBSD: ehcivar.h,v 1.53 2024/09/23 10:07:26 skrll 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@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 #define EHCI_SITD_SIZE (roundup(sizeof(struct ehci_soft_sitd), EHCI_SITD_ALIGN)) 83 #define EHCI_SITD_CHUNK (EHCI_PAGE_SIZE / EHCI_SITD_SIZE) 84 85 struct ehci_xfer { 86 struct usbd_xfer ex_xfer; 87 TAILQ_ENTRY(ehci_xfer) ex_next; /* list of active xfers */ 88 enum { 89 EX_NONE, 90 EX_CTRL, 91 EX_BULK, 92 EX_INTR, 93 EX_ISOC, 94 EX_FS_ISOC 95 } ex_type; 96 /* ctrl/bulk/intr */ 97 struct { 98 ehci_soft_qtd_t **ex_sqtds; 99 size_t ex_nsqtd; 100 }; 101 union { 102 /* ctrl */ 103 struct { 104 ehci_soft_qtd_t *ex_setup; 105 ehci_soft_qtd_t *ex_data; 106 ehci_soft_qtd_t *ex_status; 107 }; 108 /* bulk/intr */ 109 struct { 110 ehci_soft_qtd_t *ex_sqtdstart; 111 ehci_soft_qtd_t *ex_sqtdend; 112 }; 113 /* isoc */ 114 struct { 115 ehci_soft_itd_t *ex_itdstart; 116 ehci_soft_itd_t *ex_itdend; 117 }; 118 /* split (aka fs) isoc */ 119 struct { 120 ehci_soft_sitd_t *ex_sitdstart; 121 ehci_soft_sitd_t *ex_sitdend; 122 }; 123 }; 124 bool ex_isdone; /* used only when DIAGNOSTIC is defined */ 125 }; 126 127 #define EHCI_BUS2SC(bus) ((bus)->ub_hcpriv) 128 #define EHCI_PIPE2SC(pipe) EHCI_BUS2SC((pipe)->up_dev->ud_bus) 129 #define EHCI_XFER2SC(xfer) EHCI_BUS2SC((xfer)->ux_bus) 130 #define EHCI_EPIPE2SC(epipe) EHCI_BUS2SC((epipe)->pipe.up_dev->ud_bus) 131 132 #define EHCI_XFER2EXFER(xfer) ((struct ehci_xfer *)(xfer)) 133 134 #define EHCI_XFER2EPIPE(xfer) ((struct ehci_pipe *)((xfer)->ux_pipe)) 135 #define EHCI_PIPE2EPIPE(pipe) ((struct ehci_pipe *)(pipe)) 136 137 /* Information about an entry in the interrupt list. */ 138 struct ehci_soft_islot { 139 ehci_soft_qh_t *sqh; /* Queue Head. */ 140 }; 141 142 #define EHCI_FRAMELIST_MAXCOUNT 1024 143 #define EHCI_IPOLLRATES 8 /* Poll rates (1ms, 2, 4, 8 .. 128) */ 144 #define EHCI_INTRQHS ((1 << EHCI_IPOLLRATES) - 1) 145 #define EHCI_MAX_POLLRATE (1 << (EHCI_IPOLLRATES - 1)) 146 #define EHCI_IQHIDX(lev, pos) \ 147 ((((pos) & ((1 << (lev)) - 1)) | (1 << (lev))) - 1) 148 #define EHCI_ILEV_IVAL(lev) (1 << (lev)) 149 150 151 #define EHCI_HASH_SIZE 128 152 #define EHCI_COMPANION_MAX 8 153 154 #define EHCI_FREE_LIST_INTERVAL 100 155 156 typedef struct ehci_softc { 157 device_t sc_dev; 158 kmutex_t sc_rhlock; 159 kmutex_t sc_lock; 160 kmutex_t sc_intr_lock; 161 kcondvar_t sc_doorbell; 162 void *sc_doorbell_si; 163 struct lwp *sc_doorbelllwp; 164 void *sc_pcd_si; 165 struct usbd_bus sc_bus; 166 bus_space_tag_t iot; 167 bus_space_handle_t ioh; 168 bus_size_t sc_size; 169 bus_dma_tag_t sc_dmatag; /* for control data structures */ 170 u_int sc_offs; /* offset to operational regs */ 171 int sc_flags; /* misc flags */ 172 #define EHCIF_DROPPED_INTR_WORKAROUND 0x01 173 #define EHCIF_ETTF 0x02 /* Emb. Transaction Translater func. */ 174 #define EHCIF_32BIT_ACCESS 0x04 /* 32-bit MMIO access req'd */ 175 176 uint32_t sc_cmd; /* shadow of cmd reg during suspend */ 177 178 u_int sc_ncomp; 179 u_int sc_npcomp; 180 device_t sc_comps[EHCI_COMPANION_MAX]; 181 182 /* This chunk to handle early RB_ASKNAME hand over. */ 183 callout_t sc_compcallout; 184 kmutex_t sc_complock; 185 kcondvar_t sc_compcv; 186 enum { 187 CO_EARLY, 188 CO_SCHED, 189 CO_DONE, 190 } sc_comp_state; 191 192 usb_dma_t sc_fldma; 193 ehci_link_t *sc_flist; 194 u_int sc_flsize; 195 u_int sc_rand; /* XXX need proper intr scheduling */ 196 197 struct ehci_soft_islot sc_islots[EHCI_INTRQHS]; 198 199 /* 200 * an array matching sc_flist, but with software pointers, 201 * not hardware address pointers 202 */ 203 struct ehci_soft_itd **sc_softitds; 204 205 TAILQ_HEAD(, ehci_xfer) sc_intrhead; 206 207 ehci_soft_qh_t *sc_freeqhs; 208 ehci_soft_qtd_t *sc_freeqtds; 209 LIST_HEAD(sc_freeitds, ehci_soft_itd) sc_freeitds; 210 LIST_HEAD(sc_freesitds, ehci_soft_sitd) sc_freesitds; 211 212 int sc_noport; 213 uint8_t sc_hasppc; /* has Port Power Control */ 214 uint8_t sc_istthreshold; /* ISOC Scheduling Threshold (uframes) */ 215 struct usbd_xfer *sc_intrxfer; 216 char sc_isreset[EHCI_MAX_PORTS]; 217 218 uint32_t sc_eintrs; 219 ehci_soft_qh_t *sc_async_head; 220 221 pool_cache_t sc_xferpool; /* free xfer pool */ 222 223 struct callout sc_tmo_intrlist; 224 225 device_t sc_child; /* /dev/usb# device */ 226 char sc_dying; 227 228 void (*sc_vendor_init)(struct ehci_softc *); 229 int (*sc_vendor_port_status)(struct ehci_softc *, uint32_t, int); 230 } ehci_softc_t; 231 232 static inline uint8_t 233 ehci_read_1(struct ehci_softc *sc, u_int offset) 234 { 235 if (ISSET(sc->sc_flags, EHCIF_32BIT_ACCESS)) { 236 uint32_t val; 237 238 val = bus_space_read_4(sc->iot, sc->ioh, offset & ~3); 239 return (val >> ((offset & 3) * NBBY)) & 0xff; 240 } else { 241 return bus_space_read_1(sc->iot, sc->ioh, offset); 242 } 243 } 244 245 static inline uint16_t 246 ehci_read_2(struct ehci_softc *sc, u_int offset) 247 { 248 if (ISSET(sc->sc_flags, EHCIF_32BIT_ACCESS)) { 249 uint32_t val; 250 251 val = bus_space_read_4(sc->iot, sc->ioh, offset & ~3); 252 return (val >> ((offset & 3) * NBBY)) & 0xffff; 253 } else { 254 return bus_space_read_2(sc->iot, sc->ioh, offset); 255 } 256 } 257 258 static inline void 259 ehci_write_1(struct ehci_softc *sc, u_int offset, uint8_t data) 260 { 261 if (ISSET(sc->sc_flags, EHCIF_32BIT_ACCESS)) { 262 const uint32_t mask = 0xffU << ((offset & 3) * NBBY); 263 uint32_t val; 264 265 val = bus_space_read_4(sc->iot, sc->ioh, offset & ~3); 266 val &= ~mask; 267 val |= __SHIFTIN(data, mask); 268 bus_space_write_4(sc->iot, sc->ioh, offset & ~3, val); 269 } else { 270 bus_space_write_1(sc->iot, sc->ioh, offset, data); 271 } 272 } 273 274 static inline void 275 ehci_write_2(struct ehci_softc *sc, u_int offset, uint16_t data) 276 { 277 if (ISSET(sc->sc_flags, EHCIF_32BIT_ACCESS)) { 278 const uint32_t mask = 0xffffU << ((offset & 3) * NBBY); 279 uint32_t val; 280 281 val = bus_space_read_4(sc->iot, sc->ioh, offset & ~3); 282 val &= ~mask; 283 val |= __SHIFTIN(data, mask); 284 bus_space_write_4(sc->iot, sc->ioh, offset & ~3, val); 285 } else { 286 bus_space_write_2(sc->iot, sc->ioh, offset, data); 287 } 288 } 289 290 #define EREAD1(sc, a) ehci_read_1((sc), (a)) 291 #define EREAD2(sc, a) ehci_read_2((sc), (a)) 292 #define EREAD4(sc, a) bus_space_read_4((sc)->iot, (sc)->ioh, (a)) 293 #define EWRITE1(sc, a, x) ehci_write_1((sc), (a), (x)) 294 #define EWRITE2(sc, a, x) ehci_write_2((sc), (a), (x)) 295 #define EWRITE4(sc, a, x) bus_space_write_4((sc)->iot, (sc)->ioh, (a), (x)) 296 #define EOREAD1(sc, a) ehci_read_1((sc), (sc)->sc_offs+(a)) 297 #define EOREAD2(sc, a) ehci_read_2((sc), (sc)->sc_offs+(a)) 298 #define EOREAD4(sc, a) bus_space_read_4((sc)->iot, (sc)->ioh, (sc)->sc_offs+(a)) 299 #define EOWRITE1(sc, a, x) ehci_write_1((sc), (sc)->sc_offs+(a), (x)) 300 #define EOWRITE2(sc, a, x) ehci_write_2((sc), (sc)->sc_offs+(a), (x)) 301 #define EOWRITE4(sc, a, x) bus_space_write_4((sc)->iot, (sc)->ioh, (sc)->sc_offs+(a), (x)) 302 303 int ehci_init(ehci_softc_t *); 304 int ehci_intr(void *); 305 int ehci_detach(ehci_softc_t *, int); 306 int ehci_activate(device_t, enum devact); 307 void ehci_childdet(device_t, device_t); 308 bool ehci_suspend(device_t, const pmf_qual_t *); 309 bool ehci_resume(device_t, const pmf_qual_t *); 310 bool ehci_shutdown(device_t, int); 311 312 #endif /* _EHCIVAR_H_ */ 313