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