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