xref: /netbsd-src/sys/arch/hpcmips/dev/plumohci.c (revision c7fb772b85b2b5d4cfb282f868f454b4701534fd)
1*c7fb772bSthorpej /*	$NetBSD: plumohci.c,v 1.18 2021/08/07 16:18:54 thorpej Exp $ */
2f9204d0aSuch 
3f9204d0aSuch /*-
4f9204d0aSuch  * Copyright (c) 2000 UCHIYAMA Yasushi
5f9204d0aSuch  * Copyright (c) 1999 MAEKAWA Masahide <bishop@rr.iij4u.or.jp>
6f9204d0aSuch  * All rights reserved.
7f9204d0aSuch  *
8f9204d0aSuch  * Redistribution and use in source and binary forms, with or without
9f9204d0aSuch  * modification, are permitted provided that the following conditions
10f9204d0aSuch  * are met:
11f9204d0aSuch  * 1. Redistributions of source code must retain the above copyright
12f9204d0aSuch  *    notice, this list of conditions and the following disclaimer.
13f9204d0aSuch  * 2. Redistributions in binary form must reproduce the above copyright
14f9204d0aSuch  *    notice, this list of conditions and the following disclaimer in the
15f9204d0aSuch  *    documentation and/or other materials provided with the distribution.
16f9204d0aSuch  *
17f9204d0aSuch  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18f9204d0aSuch  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19f9204d0aSuch  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20f9204d0aSuch  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21f9204d0aSuch  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22f9204d0aSuch  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23f9204d0aSuch  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24f9204d0aSuch  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25f9204d0aSuch  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26f9204d0aSuch  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27f9204d0aSuch  * SUCH DAMAGE.
28f9204d0aSuch  */
29f9204d0aSuch 
30f9204d0aSuch /*
31f9204d0aSuch  * USB Open Host Controller driver.
32f9204d0aSuch  *
33f9204d0aSuch  * OHCI spec: ftp://ftp.compaq.com/pub/supportinformation/papers/hcir1_0a.exe
34f9204d0aSuch  * USB spec: http://www.usb.org/developers/data/usb11.pdf
35f9204d0aSuch  */
36f9204d0aSuch 
370c82163cSlukem #include <sys/cdefs.h>
38*c7fb772bSthorpej __KERNEL_RCSID(0, "$NetBSD: plumohci.c,v 1.18 2021/08/07 16:18:54 thorpej Exp $");
390c82163cSlukem 
40f9204d0aSuch #include <sys/param.h>
41f9204d0aSuch #include <sys/systm.h>
42f9204d0aSuch #include <sys/kernel.h>
43f9204d0aSuch #include <sys/device.h>
44f9204d0aSuch #include <sys/proc.h>
45f9204d0aSuch #include <sys/queue.h>
46b950ff9aSthorpej #include <sys/kmem.h>
47f9204d0aSuch 
48f9204d0aSuch /* busdma */
49f9204d0aSuch #include <sys/mbuf.h>
5028d89839Smrg #include <uvm/uvm_extern.h>
51f9204d0aSuch 
52f9204d0aSuch #include <machine/bus.h>
531d1d5c87Stakemura #include <machine/bus_dma_hpcmips.h>
54f9204d0aSuch 
55f9204d0aSuch #include <dev/usb/usb.h>
56f9204d0aSuch #include <dev/usb/usbdi.h>
57f9204d0aSuch #include <dev/usb/usbdivar.h>
58f9204d0aSuch #include <dev/usb/usb_mem.h>
59f9204d0aSuch 
60f9204d0aSuch #include <dev/usb/ohcireg.h>
61f9204d0aSuch #include <dev/usb/ohcivar.h>
62f9204d0aSuch 
63f9204d0aSuch #include <hpcmips/tx/tx39var.h>
64f9204d0aSuch #include <hpcmips/dev/plumvar.h>
65f9204d0aSuch #include <hpcmips/dev/plumicuvar.h>
66f9204d0aSuch #include <hpcmips/dev/plumpowervar.h>
67f9204d0aSuch #include <hpcmips/dev/plumohcireg.h>
68f9204d0aSuch 
69cbab9cadSchs int plumohci_match(device_t, cfdata_t, void *);
70cbab9cadSchs void plumohci_attach(device_t, device_t, void *);
7158f851eeSuch int plumohci_intr(void *);
72f9204d0aSuch 
7358f851eeSuch void __plumohci_dmamap_sync(bus_dma_tag_t, bus_dmamap_t,
7458f851eeSuch     bus_addr_t, bus_size_t, int);
7558f851eeSuch int __plumohci_dmamem_alloc(bus_dma_tag_t, bus_size_t, bus_size_t,
7658f851eeSuch     bus_size_t, bus_dma_segment_t *, int, int *, int);
7758f851eeSuch void __plumohci_dmamem_free(bus_dma_tag_t, bus_dma_segment_t *, int);
7858f851eeSuch int __plumohci_dmamem_map(bus_dma_tag_t, bus_dma_segment_t *,
7953524e44Schristos     int, size_t, void **, int);
8053524e44Schristos void __plumohci_dmamem_unmap(bus_dma_tag_t, void *, size_t);
81f9204d0aSuch 
821d1d5c87Stakemura struct bus_dma_tag_hpcmips plumohci_bus_dma_tag = {
831d1d5c87Stakemura 	{
841d1d5c87Stakemura 		NULL,
851d1d5c87Stakemura 		{
861d1d5c87Stakemura 			_hpcmips_bd_map_create,
871d1d5c87Stakemura 			_hpcmips_bd_map_destroy,
881d1d5c87Stakemura 			_hpcmips_bd_map_load,
891d1d5c87Stakemura 			_hpcmips_bd_map_load_mbuf,
901d1d5c87Stakemura 			_hpcmips_bd_map_load_uio,
911d1d5c87Stakemura 			_hpcmips_bd_map_load_raw,
921d1d5c87Stakemura 			_hpcmips_bd_map_unload,
93f9204d0aSuch 			__plumohci_dmamap_sync,
94f9204d0aSuch 			__plumohci_dmamem_alloc,
95f9204d0aSuch 			__plumohci_dmamem_free,
96f9204d0aSuch 			__plumohci_dmamem_map,
97f9204d0aSuch 			__plumohci_dmamem_unmap,
981d1d5c87Stakemura 			_hpcmips_bd_mem_mmap,
991d1d5c87Stakemura 		},
1001d1d5c87Stakemura 	},
1011d1d5c87Stakemura 	NULL,
102f9204d0aSuch };
103f9204d0aSuch 
104f9204d0aSuch struct plumohci_shm {
105f9204d0aSuch 	bus_space_handle_t ps_bsh;
106f9204d0aSuch 	paddr_t	ps_paddr;
10753524e44Schristos 	void *	ps_caddr;
108f9204d0aSuch 	size_t	ps_size;
109f9204d0aSuch 	LIST_ENTRY(plumohci_shm) ps_link;
110f9204d0aSuch };
111f9204d0aSuch 
112f9204d0aSuch struct plumohci_softc {
113f9204d0aSuch 	struct ohci_softc sc;
114f9204d0aSuch 	void *sc_ih;
115f9204d0aSuch 	void *sc_wakeih;
116f9204d0aSuch 
117f9204d0aSuch 	LIST_HEAD(, plumohci_shm) sc_shm_head;
118f9204d0aSuch };
119f9204d0aSuch 
120ed2b61deSdrochner CFATTACH_DECL_NEW(plumohci, sizeof(struct plumohci_softc),
121c5e91d44Sthorpej     plumohci_match, plumohci_attach, NULL, NULL);
122f9204d0aSuch 
123f9204d0aSuch int
plumohci_match(device_t parent,cfdata_t match,void * aux)124cbab9cadSchs plumohci_match(device_t parent, cfdata_t match, void *aux)
125f9204d0aSuch {
126f9204d0aSuch 	/* PLUM2 builtin OHCI module */
127f9204d0aSuch 
1284e8e6643Sskrll 	return 1;
129f9204d0aSuch }
130f9204d0aSuch 
131f9204d0aSuch void
plumohci_attach(device_t parent,device_t self,void * aux)132cbab9cadSchs plumohci_attach(device_t parent, device_t self, void *aux)
133f9204d0aSuch {
134ed2b61deSdrochner 	struct plumohci_softc *sc = device_private(self);
135f9204d0aSuch 	struct plum_attach_args *pa = aux;
136f9204d0aSuch 
137ed2b61deSdrochner 	sc->sc.sc_dev = self;
1384e8e6643Sskrll 	sc->sc.sc_bus.ub_hcpriv = sc;
139ed2b61deSdrochner 
140f9204d0aSuch 	sc->sc.iot = pa->pa_iot;
1414e8e6643Sskrll 	sc->sc.sc_bus.ub_dmatag = &plumohci_bus_dma_tag.bdt;
1421d1d5c87Stakemura 	plumohci_bus_dma_tag._dmamap_chipset_v = sc;
143f9204d0aSuch 
144f9204d0aSuch 	/* Map I/O space */
145f9204d0aSuch 	if (bus_space_map(sc->sc.iot, PLUM_OHCI_REGBASE, OHCI_PAGE_SIZE,
146f9204d0aSuch 	    0, &sc->sc.ioh)) {
147f9204d0aSuch 		printf(": cannot map mem space\n");
148f9204d0aSuch 		return;
149f9204d0aSuch 	}
150f9204d0aSuch 
151f9204d0aSuch 	/* power up */
152f9204d0aSuch 	/*
153f9204d0aSuch 	 * in the case of PLUM2, UHOSTC uses the VRAM as the shared RAM
154f9204d0aSuch 	 * so establish power/clock of Video contoroller
155f9204d0aSuch 	 */
156f9204d0aSuch 	plum_power_establish(pa->pa_pc, PLUM_PWR_EXTPW1);
157f9204d0aSuch 	plum_power_establish(pa->pa_pc, PLUM_PWR_USB);
158f9204d0aSuch 
159f9204d0aSuch 	/* Disable interrupts, so we don't can any spurious ones. */
160f9204d0aSuch 	bus_space_write_4(sc->sc.iot, sc->sc.ioh, OHCI_INTERRUPT_DISABLE,
161f9204d0aSuch 	    OHCI_ALL_INTRS);
162f9204d0aSuch 
163f9204d0aSuch 	/* master enable */
164f9204d0aSuch 	sc->sc_ih = plum_intr_establish(pa->pa_pc, PLUM_INT_USB, IST_EDGE,
165f9204d0aSuch 	    IPL_USB, ohci_intr, sc);
166f9204d0aSuch #if 0
167f9204d0aSuch 	/*
168f9204d0aSuch 	 *  enable the clock restart request interrupt
169f9204d0aSuch 	 *  (for USBSUSPEND state)
170f9204d0aSuch 	 */
171f9204d0aSuch 	sc->sc_wakeih = plum_intr_establish(pa->pa_pc, PLUM_INT_USBWAKE,
172f9204d0aSuch 	    IST_EDGE, IPL_USB,
173f9204d0aSuch 	    plumohci_intr, sc);
174f9204d0aSuch #endif
175f9204d0aSuch 	/*
176f9204d0aSuch 	 * Shared memory list.
177f9204d0aSuch 	 */
178f9204d0aSuch 	LIST_INIT(&sc->sc_shm_head);
179f9204d0aSuch 
180f9204d0aSuch 	printf("\n");
181f9204d0aSuch 
1824e8e6643Sskrll 	int err = ohci_init(&sc->sc);
183f9204d0aSuch 
1844e8e6643Sskrll 	if (err) {
1854e8e6643Sskrll 		printf(": init failed, error=%d\n", err);
186f9204d0aSuch 
187f9204d0aSuch 		plum_intr_disestablish(pa->pa_pc, sc->sc_ih);
188f9204d0aSuch 		plum_intr_disestablish(pa->pa_pc, sc->sc_wakeih);
189f9204d0aSuch 
190f9204d0aSuch 		return;
191f9204d0aSuch 	}
192f9204d0aSuch 
193f9204d0aSuch 	/* Attach usb device. */
1942685996bSthorpej 	sc->sc.sc_child = config_found(self, &sc->sc.sc_bus, usbctlprint,
195*c7fb772bSthorpej 	    CFARGS_NONE);
196f9204d0aSuch }
197f9204d0aSuch 
198f9204d0aSuch int
plumohci_intr(void * arg)19958f851eeSuch plumohci_intr(void *arg)
200f9204d0aSuch {
201f9204d0aSuch 	printf("Plum2 OHCI: wakeup intr\n");
202f9204d0aSuch 	return 0;
203f9204d0aSuch }
204f9204d0aSuch 
205f9204d0aSuch /*
206f9204d0aSuch  * Plum2 OHCI specific busdma routines.
207f9204d0aSuch  *	Plum2 OHCI shared buffer can't allocate on memory
208f9204d0aSuch  *	but V-RAM (busspace).
209f9204d0aSuch  */
210f9204d0aSuch 
211f9204d0aSuch void
__plumohci_dmamap_sync(bus_dma_tag_t tx,bus_dmamap_t map,bus_addr_t offset,bus_size_t len,int ops)2121d1d5c87Stakemura __plumohci_dmamap_sync(bus_dma_tag_t tx, bus_dmamap_t map, bus_addr_t offset,
21358f851eeSuch     bus_size_t len, int ops)
214f9204d0aSuch {
2151d1d5c87Stakemura 	struct bus_dma_tag_hpcmips *t = (struct bus_dma_tag_hpcmips *)tx;
216f9204d0aSuch 	struct plumohci_softc *sc = t->_dmamap_chipset_v;
21758f851eeSuch 
218f9204d0aSuch 	/*
219f9204d0aSuch 	 * Flush the write buffer allocated on the V-RAM.
220f9204d0aSuch 	 * Accessing any host controller register flushs write buffer
221f9204d0aSuch 	 */
222f9204d0aSuch 	(void)bus_space_read_4(sc->sc.iot, sc->sc.ioh, OHCI_REVISION);
223f9204d0aSuch }
224f9204d0aSuch 
225f9204d0aSuch int
__plumohci_dmamem_alloc(bus_dma_tag_t tx,bus_size_t size,bus_size_t alignment,bus_size_t boundary,bus_dma_segment_t * segs,int nsegs,int * rsegs,int flags)2261d1d5c87Stakemura __plumohci_dmamem_alloc(bus_dma_tag_t tx, bus_size_t size,
2271d1d5c87Stakemura     bus_size_t alignment, bus_size_t boundary, bus_dma_segment_t *segs,
2281d1d5c87Stakemura     int nsegs, int *rsegs, int flags)
229f9204d0aSuch {
2301d1d5c87Stakemura 	struct bus_dma_tag_hpcmips *t = (struct bus_dma_tag_hpcmips *)tx;
231f9204d0aSuch 	struct plumohci_softc *sc = t->_dmamap_chipset_v;
232f9204d0aSuch 	struct plumohci_shm *ps;
233f9204d0aSuch 	bus_space_handle_t bsh;
234f9204d0aSuch 	paddr_t paddr;
23553524e44Schristos 	void *caddr;
236f9204d0aSuch 	int error;
237f9204d0aSuch 
238f9204d0aSuch 	size = round_page(size);
239f9204d0aSuch 
240f9204d0aSuch 	/*
241f9204d0aSuch 	 * Allocate buffer from V-RAM area.
242f9204d0aSuch 	 */
243f9204d0aSuch 	error = bus_space_alloc(sc->sc.iot, PLUM_OHCI_SHMEMBASE,
244f9204d0aSuch 	    PLUM_OHCI_SHMEMBASE + PLUM_OHCI_SHMEMSIZE - 1,
2458ffd886bStsutsui 	    size, OHCI_PAGE_SIZE, 0, 0,
2465c54e293Ssimonb 	    (bus_addr_t *)(void *)&caddr, &bsh);
247f9204d0aSuch 	if (error)
2484e8e6643Sskrll 		return 1;
249f9204d0aSuch 
250f9204d0aSuch 	pmap_extract(pmap_kernel(), (vaddr_t)caddr, &paddr);
251f9204d0aSuch 
252b950ff9aSthorpej 	ps = kmem_intr_alloc(sizeof(struct plumohci_shm), KM_NOSLEEP);
253f9204d0aSuch 	if (ps == 0)
2544e8e6643Sskrll 		return 1;
255f9204d0aSuch 
256f9204d0aSuch 	ps->ps_bsh = bsh;
257f9204d0aSuch 	ps->ps_size = segs[0].ds_len = size;
258f9204d0aSuch 	ps->ps_paddr = segs[0].ds_addr = paddr;
259f9204d0aSuch 	ps->ps_caddr = caddr;
260f9204d0aSuch 
261f9204d0aSuch 	LIST_INSERT_HEAD(&sc->sc_shm_head, ps, ps_link);
262f9204d0aSuch 
263f9204d0aSuch 	*rsegs = 1;
264f9204d0aSuch 
2654e8e6643Sskrll 	return 0;
266f9204d0aSuch }
267f9204d0aSuch 
268f9204d0aSuch void
__plumohci_dmamem_free(bus_dma_tag_t tx,bus_dma_segment_t * segs,int nsegs)2691d1d5c87Stakemura __plumohci_dmamem_free(bus_dma_tag_t tx, bus_dma_segment_t *segs, int nsegs)
270f9204d0aSuch {
2711d1d5c87Stakemura 	struct bus_dma_tag_hpcmips *t = (struct bus_dma_tag_hpcmips *)tx;
272f9204d0aSuch 	struct plumohci_softc *sc = t->_dmamap_chipset_v;
273f9204d0aSuch 	struct plumohci_shm *ps;
274f9204d0aSuch 
275f9204d0aSuch 	for (ps = LIST_FIRST(&sc->sc_shm_head); ps;
276f9204d0aSuch 	    ps = LIST_NEXT(ps, ps_link)) {
277f9204d0aSuch 
278f9204d0aSuch 		if (ps->ps_paddr == segs[0].ds_addr) {
279f9204d0aSuch 			bus_space_free(sc->sc.iot, ps->ps_bsh, ps->ps_size);
280f9204d0aSuch 			LIST_REMOVE(ps, ps_link);
281b950ff9aSthorpej 			kmem_intr_free(ps, sizeof(*ps));
282f9204d0aSuch 
283f9204d0aSuch 			return;
284f9204d0aSuch 		}
285f9204d0aSuch 	}
286f9204d0aSuch 
287f9204d0aSuch 	panic("__plumohci_dmamem_free: can't find corresponding handle.");
288f9204d0aSuch 	/* NOTREACHED */
289f9204d0aSuch }
290f9204d0aSuch 
291f9204d0aSuch int
__plumohci_dmamem_map(bus_dma_tag_t tx,bus_dma_segment_t * segs,int nsegs,size_t size,void ** kvap,int flags)2921d1d5c87Stakemura __plumohci_dmamem_map(bus_dma_tag_t tx, bus_dma_segment_t *segs, int nsegs,
29353524e44Schristos     size_t size, void **kvap, int flags)
294f9204d0aSuch {
2951d1d5c87Stakemura 	struct bus_dma_tag_hpcmips *t = (struct bus_dma_tag_hpcmips *)tx;
296f9204d0aSuch 	struct plumohci_softc *sc = t->_dmamap_chipset_v;
297f9204d0aSuch 	struct plumohci_shm *ps;
298f9204d0aSuch 
299f9204d0aSuch 	for (ps = LIST_FIRST(&sc->sc_shm_head); ps;
300f9204d0aSuch 	    ps = LIST_NEXT(ps, ps_link)) {
301f9204d0aSuch 		if (ps->ps_paddr == segs[0].ds_addr) {
302f9204d0aSuch 
303f9204d0aSuch 			*kvap = ps->ps_caddr;
304f9204d0aSuch 
3054e8e6643Sskrll 			return 0;
306f9204d0aSuch 		}
307f9204d0aSuch 	}
308f9204d0aSuch 
3094e8e6643Sskrll 	return 1;
310f9204d0aSuch }
311f9204d0aSuch 
312f9204d0aSuch void
__plumohci_dmamem_unmap(bus_dma_tag_t t,void * kva,size_t size)31353524e44Schristos __plumohci_dmamem_unmap(bus_dma_tag_t t, void *kva, size_t size)
314f9204d0aSuch {
315f9204d0aSuch 	/* nothing to do */
316f9204d0aSuch }
317