1 /* $NetBSD: msiiep.c,v 1.53 2022/01/21 19:14:14 thorpej Exp $ */
2
3 /*
4 * Copyright (c) 2001 Valeriy E. Ushakov
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: msiiep.c,v 1.53 2022/01/21 19:14:14 thorpej Exp $");
31
32 #include <sys/param.h>
33 #include <sys/kmem.h>
34 #include <sys/kernel.h>
35 #include <sys/systm.h>
36 #include <sys/device.h>
37
38 #include <uvm/uvm.h>
39
40 #define _SPARC_BUS_DMA_PRIVATE
41 #include <sys/bus.h>
42 #include <machine/autoconf.h>
43 #include <machine/promlib.h>
44
45 #include <dev/pci/pcireg.h>
46 #include <dev/pci/pcidevs.h>
47 #include <dev/pci/pcivar.h>
48
49 #include <sparc/sparc/msiiepreg.h>
50 #include <sparc/sparc/msiiepvar.h>
51 #include <sparc/sparc/pci_fixup.h>
52
53 /*
54 * Autoconfiguration.
55 *
56 * Normally, sparc autoconfiguration is driven by PROM device tree,
57 * however PROMs in ms-IIep machines usually don't have nodes for
58 * various important registers that are part of ms-IIep PCI controller.
59 * We work around by inserting a dummy device that acts as a parent
60 * for device drivers that deal with various functions of PCIC. The
61 * other option is to hack mainbus_attach() to treat ms-IIep specially,
62 * but I'd rather insulate the rest of the source from ms-IIep quirks.
63 */
64
65 /*
66 * "Stub" ms-IIep parent that knows how to attach various functions.
67 */
68 static int msiiep_match(device_t, cfdata_t, void *);
69 static void msiiep_attach(device_t, device_t, void *);
70
71 CFATTACH_DECL_NEW(msiiep, 0, msiiep_match, msiiep_attach, NULL, NULL);
72
73
74 /* sleep in idle spin */
75 static void msiiep_cpu_sleep(void);
76 volatile uint32_t *msiiep_mid = NULL;
77
78
79 /*
80 * The real thing.
81 */
82 static int mspcic_match(device_t, cfdata_t, void *);
83 static void mspcic_attach(device_t, device_t, void *);
84 static int mspcic_print(void *, const char *);
85
86 CFATTACH_DECL_NEW(mspcic, sizeof(struct mspcic_softc),
87 mspcic_match, mspcic_attach, NULL, NULL);
88
89
90 /**
91 * Only one PCI controller per MS-IIep and only one MS-IIep per system
92 * so don't bother with malloc'ing our tags.
93 */
94
95 /*
96 * PCI chipset tag
97 */
98 static struct sparc_pci_chipset mspcic_pc_tag = { NULL };
99
100
101 /* fixed i/o and one set of i/o cycle translation registers */
102 struct mspcic_pci_map mspcic_pci_iomap[IOMAP_SIZE] = {
103 { 0x30000000, 0x0, 0x00010000 } /* fixed i/o (decoded bits) */
104 };
105
106 /* fixed mem and two sets of mem cycle translation registers */
107 struct mspcic_pci_map mspcic_pci_memmap[MEMMAP_SIZE] = {
108 { 0x30100000, 0x00100000, 0x00f00000 } /* fixed mem (pass through) */
109 };
110
111 struct mspcic_cookie {
112 struct mspcic_pci_map *map;
113 int nmaps;
114 };
115
116 static struct mspcic_cookie mspcic_io_cookie = { mspcic_pci_iomap, 0 };
117 static struct mspcic_cookie mspcic_mem_cookie = { mspcic_pci_memmap, 0 };
118
119
120 static void mspcic_init_maps(void);
121 static void mspcic_pci_map_from_reg(struct mspcic_pci_map *,
122 uint8_t, uint8_t, uint8_t);
123 static bus_addr_t mspcic_pci_map_find(struct mspcic_pci_map *, int,
124 bus_addr_t, bus_size_t);
125 #ifdef DEBUG
126 static void mspcic_pci_map_print(struct mspcic_pci_map *, const char *);
127 #endif
128
129
130 static int mspcic_bus_map(bus_space_tag_t, bus_addr_t, bus_size_t,
131 int, vaddr_t, bus_space_handle_t *);
132 static paddr_t mspcic_bus_mmap(bus_space_tag_t, bus_addr_t, off_t, int, int);
133 static void *mspcic_intr_establish(bus_space_tag_t, int, int,
134 int (*)(void *), void *, void (*)(void));
135
136 /* bus space methods that do byteswapping */
137 static uint16_t mspcic_bus_read_2(bus_space_tag_t, bus_space_handle_t,
138 bus_size_t);
139 static uint32_t mspcic_bus_read_4(bus_space_tag_t, bus_space_handle_t,
140 bus_size_t);
141 static uint64_t mspcic_bus_read_8(bus_space_tag_t, bus_space_handle_t,
142 bus_size_t);
143 static void mspcic_bus_write_2(bus_space_tag_t, bus_space_handle_t,
144 bus_size_t, uint16_t);
145 static void mspcic_bus_write_4(bus_space_tag_t, bus_space_handle_t,
146 bus_size_t, uint32_t);
147 static void mspcic_bus_write_8(bus_space_tag_t, bus_space_handle_t,
148 bus_size_t, uint64_t);
149
150 static struct sparc_bus_space_tag mspcic_io_tag;
151 static struct sparc_bus_space_tag mspcic_mem_tag;
152
153
154 /*
155 * DMA tag
156 */
157 static int mspcic_dmamap_load(bus_dma_tag_t, bus_dmamap_t,
158 void *, bus_size_t, struct proc *, int);
159 static void mspcic_dmamap_unload(bus_dma_tag_t, bus_dmamap_t);
160 static int mspcic_dmamem_map(bus_dma_tag_t, bus_dma_segment_t *,
161 int, size_t, void **, int);
162
163 static struct sparc_bus_dma_tag mspcic_dma_tag = {
164 NULL, /* _cookie */
165
166 _bus_dmamap_create,
167 _bus_dmamap_destroy,
168 mspcic_dmamap_load,
169 _bus_dmamap_load_mbuf,
170 _bus_dmamap_load_uio,
171 _bus_dmamap_load_raw,
172 mspcic_dmamap_unload,
173 _bus_dmamap_sync,
174
175 _bus_dmamem_alloc,
176 _bus_dmamem_free,
177 mspcic_dmamem_map,
178 _bus_dmamem_unmap,
179 _bus_dmamem_mmap
180 };
181
182
183 static int
msiiep_match(device_t parent,cfdata_t cf,void * aux)184 msiiep_match(device_t parent, cfdata_t cf, void *aux)
185 {
186 struct mainbus_attach_args *ma = aux;
187 pcireg_t id;
188
189 /* match by PROM name */
190 if (strcmp(ma->ma_name, "pci") != 0)
191 return (0);
192
193 /*
194 * Verify that PCIC was successfully mapped by bootstrap code.
195 * Since PCIC contains all the registers vital to the kernel,
196 * bootstrap code maps them at a fixed va, MSIIEP_PCIC_VA
197 */
198 id = mspcic_read_4(pcic_id);
199 if (PCI_VENDOR(id) != PCI_VENDOR_SUN
200 && PCI_PRODUCT(id) != PCI_PRODUCT_SUN_MS_IIep)
201 panic("msiiep_match: id %08x", id);
202
203 return (1);
204 }
205
206
207 static void
msiiep_attach(device_t parent,device_t self,void * aux)208 msiiep_attach(device_t parent, device_t self, void *aux)
209 {
210 struct mainbus_attach_args *ma = aux;
211 struct msiiep_attach_args msa;
212 bus_space_handle_t hmid;
213 struct cpu_info *cur;
214
215 aprint_normal("\n");
216
217 if (bus_space_map(ma->ma_bustag, MSIIEP_MID_PA, 4, 0, &hmid) == 0) {
218 #ifdef DIAGNOSTICS
219 uint32_t mid;
220
221 mid = bus_space_read_4(ma->ma_bustag, hmid, 0);
222 printf("MID: %08x\n", mid);
223 #endif
224 msiiep_mid = (volatile uint32_t *)bus_space_vaddr(ma->ma_bustag,
225 hmid);
226 cur = curcpu();
227 cur->idlespin = msiiep_cpu_sleep;
228 }
229
230 /* pass on real mainbus_attach_args */
231 msa.msa_ma = ma;
232
233 /* config timer/counter part of PCIC */
234 msa.msa_name = "timer";
235 config_found(self, &msa, NULL, CFARGS_NONE);
236
237 /* config PCI tree */
238 msa.msa_name = "pcic";
239 config_found(self, &msa, NULL, CFARGS_NONE);
240 }
241
242 /* ARGSUSED */
243 void
msiiep_cpu_sleep(void)244 msiiep_cpu_sleep(void)
245 {
246 uint32_t reg;
247
248 if (msiiep_mid == 0)
249 return;
250 reg = *msiiep_mid;
251 *msiiep_mid = (reg & MID_MASK) | MID_STANDBY;
252 }
253
254
255 /* ======================================================================
256 *
257 * Real ms-IIep PCIC driver.
258 */
259
260 static int
mspcic_match(device_t parent,cfdata_t cf,void * aux)261 mspcic_match(device_t parent, cfdata_t cf, void *aux)
262 {
263 struct msiiep_attach_args *msa = aux;
264
265 return (strcmp(msa->msa_name, "pcic") == 0);
266 }
267
268
269 static void
mspcic_attach(device_t parent,device_t self,void * aux)270 mspcic_attach(device_t parent, device_t self, void *aux)
271 {
272 struct mspcic_softc *sc = device_private(self);
273 struct msiiep_attach_args *msa = aux;
274 struct mainbus_attach_args *ma = msa->msa_ma;
275 int node = ma->ma_node;
276 char devinfo[256], buf[32], *model;
277
278 struct pcibus_attach_args pba;
279
280 sc->sc_node = node;
281
282 /* copy parent tags */
283 sc->sc_bustag = ma->ma_bustag;
284 sc->sc_dmatag = ma->ma_dmatag;
285
286 /* print our PCI device info and bus clock frequency */
287 pci_devinfo(mspcic_read_4(pcic_id), mspcic_read_4(pcic_class), 0,
288 devinfo, sizeof(devinfo));
289 printf(": %s: clock = %s MHz\n", devinfo,
290 clockfreq(prom_getpropint(node, "clock-frequency", 33333333)));
291
292 mspcic_init_maps();
293
294 /*
295 * On Espresso, we need to adjust the interrupt mapping on
296 * lines 4-7, as onboard devices and cards in the PCI slots use
297 * those lines. Note, that enabling line 5 (onboard ide) causes
298 * a continuous interrupt stream, so leave that unmapped (0).
299 * Any other device using line 5 can't be used.
300 * Interrupt line wiring for slots is set in pci_machdep.c.
301 * Set the PCI Trdy and Retry Counters to non-zero values, otherwise
302 * we'll lock up when using devices behind a PCI-PCI bridge.
303 */
304 model = prom_getpropstringA(prom_findroot(), "model", buf, sizeof(buf));
305 if (model != NULL && !strcmp(model, "SUNW,375-0059")) {
306 mspcic_write_2(pcic_intr_asgn_sel_hi, (uint16_t) 0x7502);
307 mspcic_write_4(pcic_cntrs, (uint32_t) 0x00808000);
308 }
309
310 /* init cookies/parents in our statically allocated tags */
311 mspcic_io_tag = *sc->sc_bustag;
312 mspcic_io_tag.cookie = &mspcic_io_cookie;
313 mspcic_io_tag.ranges = NULL;
314 mspcic_io_tag.nranges = 0;
315 mspcic_io_tag.sparc_bus_map = mspcic_bus_map;
316 mspcic_io_tag.sparc_bus_mmap = mspcic_bus_mmap;
317 mspcic_io_tag.sparc_intr_establish = mspcic_intr_establish;
318 mspcic_io_tag.parent = sc->sc_bustag;
319
320 mspcic_io_tag.sparc_read_2 = mspcic_bus_read_2;
321 mspcic_io_tag.sparc_read_4 = mspcic_bus_read_4;
322 mspcic_io_tag.sparc_read_8 = mspcic_bus_read_8;
323 mspcic_io_tag.sparc_write_2 = mspcic_bus_write_2;
324 mspcic_io_tag.sparc_write_4 = mspcic_bus_write_4;
325 mspcic_io_tag.sparc_write_8 = mspcic_bus_write_8;
326
327 mspcic_mem_tag = *sc->sc_bustag;
328 mspcic_mem_tag.cookie = &mspcic_mem_cookie;
329 mspcic_mem_tag.ranges = NULL;
330 mspcic_mem_tag.nranges = 0;
331 mspcic_mem_tag.sparc_bus_map = mspcic_bus_map;
332 mspcic_mem_tag.sparc_bus_mmap = mspcic_bus_mmap;
333 mspcic_mem_tag.sparc_intr_establish = mspcic_intr_establish;
334 mspcic_mem_tag.parent = sc->sc_bustag;
335
336 mspcic_mem_tag.sparc_read_2 = mspcic_bus_read_2;
337 mspcic_mem_tag.sparc_read_4 = mspcic_bus_read_4;
338 mspcic_mem_tag.sparc_read_8 = mspcic_bus_read_8;
339 mspcic_mem_tag.sparc_write_2 = mspcic_bus_write_2;
340 mspcic_mem_tag.sparc_write_4 = mspcic_bus_write_4;
341 mspcic_mem_tag.sparc_write_8 = mspcic_bus_write_8;
342
343 mspcic_dma_tag._cookie = sc;
344 mspcic_pc_tag.cookie = sc;
345
346 /* save bus tags in softc */
347 sc->sc_iot = &mspcic_io_tag;
348 sc->sc_memt = &mspcic_mem_tag;
349 sc->sc_dmat = &mspcic_dma_tag;
350
351 /*
352 * Attach the PCI bus.
353 */
354 pba.pba_bus = 0;
355 pba.pba_bridgetag = NULL;
356 pba.pba_iot = sc->sc_iot;
357 pba.pba_memt = sc->sc_memt;
358 pba.pba_dmat = sc->sc_dmat;
359 pba.pba_dmat64 = NULL;
360 pba.pba_pc = &mspcic_pc_tag;
361 pba.pba_flags = PCI_FLAGS_IO_OKAY | PCI_FLAGS_MEM_OKAY;
362
363 mspcic_pci_scan(sc->sc_node);
364
365 config_found(self, &pba, mspcic_print,
366 CFARGS(.devhandle = device_handle(self)));
367 }
368
369
370 static int
mspcic_print(void * args,const char * busname)371 mspcic_print(void *args, const char *busname)
372 {
373
374 if (busname == NULL)
375 return (UNCONF);
376 return (QUIET);
377 }
378
379
380 /*
381 * Get the PIL currently assigned for this interrupt input line.
382 */
383 int
mspcic_assigned_interrupt(int line)384 mspcic_assigned_interrupt(int line)
385 {
386 unsigned int intrmap;
387
388 if (line < 0 || line > 7)
389 return (-1);
390
391 if (line < 4) {
392 intrmap = mspcic_read_2(pcic_intr_asgn_sel);
393 } else {
394 intrmap = mspcic_read_2(pcic_intr_asgn_sel_hi);
395 line -= 4;
396 }
397 return ((intrmap >> (line * 4)) & 0xf);
398 }
399
400
401 /* ======================================================================
402 *
403 * BUS space methods
404 */
405
406 static inline void
mspcic_pci_map_from_reg(struct mspcic_pci_map * m,uint8_t sbar,uint8_t pbar,uint8_t sizemask)407 mspcic_pci_map_from_reg(struct mspcic_pci_map *m,
408 uint8_t sbar, uint8_t pbar, uint8_t sizemask)
409 {
410 m->sysbase = 0x30000000 | ((sbar & 0x0f) << 24);
411 m->pcibase = pbar << 24;
412 m->size = ~((0xf0 | sizemask) << 24) + 1;
413 }
414
415
416 /* does [al, ar) and [bl, br) overlap? */
417 #define OVERLAP(al, ar, bl, br) (((al) < (br)) && ((bl) < (ar)))
418
419 /* does map "m" overlap with fixed mapping region? */
420 #define OVERLAP_FIXED(m) OVERLAP((m)->sysbase, (m)->sysbase + (m)->size, \
421 0x30000000, 0x31000000)
422
423 /* does map "ma" overlap map "mb" (possibly NULL)? */
424 #define OVERLAP_MAP(ma, mb) \
425 ((mb != NULL) && OVERLAP((ma)->sysbase, (ma)->sysbase + (ma)->size, \
426 (mb)->sysbase, (mb)->sysbase + (mb)->size))
427
428 /*
429 * Init auxiliary paddr->pci maps.
430 */
431 static void
mspcic_init_maps(void)432 mspcic_init_maps(void)
433 {
434 struct mspcic_pci_map *m0, *m1, *io;
435 int nmem, nio;
436
437 #ifdef DEBUG
438 printf("mspcic0: SMBAR0 %02x PMBAR0 %02x MSIZE0 %02x\n",
439 mspcic_read_1(pcic_smbar0), mspcic_read_1(pcic_pmbar0),
440 mspcic_read_1(pcic_msize0));
441 printf("mspcic0: SMBAR1 %02x PMBAR1 %02x MSIZE1 %02x\n",
442 mspcic_read_1(pcic_smbar1), mspcic_read_1(pcic_pmbar1),
443 mspcic_read_1(pcic_msize1));
444 printf("mspcic0: SIBAR %02x PIBAR %02x IOSIZE %02x\n",
445 mspcic_read_1(pcic_sibar), mspcic_read_1(pcic_pibar),
446 mspcic_read_1(pcic_iosize));
447 #endif
448 nmem = nio = 1;
449
450 m0 = &mspcic_pci_memmap[nmem];
451 mspcic_pci_map_from_reg(m0,
452 mspcic_read_1(pcic_smbar0), mspcic_read_1(pcic_pmbar0),
453 mspcic_read_1(pcic_msize0));
454 if (OVERLAP_FIXED(m0))
455 m0 = NULL;
456 else
457 ++nmem;
458
459 m1 = &mspcic_pci_memmap[nmem];
460 mspcic_pci_map_from_reg(m1,
461 mspcic_read_1(pcic_smbar1), mspcic_read_1(pcic_pmbar1),
462 mspcic_read_1(pcic_msize1));
463 if (OVERLAP_FIXED(m1) || OVERLAP_MAP(m1, m0))
464 m1 = NULL;
465 else
466 ++nmem;
467
468 io = &mspcic_pci_iomap[nio];
469 mspcic_pci_map_from_reg(io,
470 mspcic_read_1(pcic_sibar), mspcic_read_1(pcic_pibar),
471 mspcic_read_1(pcic_iosize));
472 if (OVERLAP_FIXED(io) || OVERLAP_MAP(io, m0) || OVERLAP_MAP(io, m1))
473 io = NULL;
474 else
475 ++nio;
476
477 mspcic_io_cookie.nmaps = nio;
478 mspcic_mem_cookie.nmaps = nmem;
479
480 #ifdef DEBUG
481 mspcic_pci_map_print(&mspcic_pci_iomap[0], "i/o fixed");
482 mspcic_pci_map_print(&mspcic_pci_memmap[0], "mem fixed");
483 if (m0) mspcic_pci_map_print(m0, "mem map0");
484 if (m1) mspcic_pci_map_print(m1, "mem map1");
485 if (io) mspcic_pci_map_print(io, "i/0 map");
486 #endif
487 }
488
489
490 #ifdef DEBUG
491 static void
mspcic_pci_map_print(struct mspcic_pci_map * m,const char * msg)492 mspcic_pci_map_print(struct mspcic_pci_map *m, const char *msg)
493 {
494 printf("mspcic0: paddr [%08x..%08x] -> pci [%08x..%08x] %s\n",
495 m->sysbase, m->sysbase + m->size - 1,
496 m->pcibase, m->pcibase + m->size - 1,
497 msg);
498 }
499 #endif
500
501
502 static bus_addr_t
mspcic_pci_map_find(struct mspcic_pci_map * m,int nmaps,bus_addr_t pciaddr,bus_size_t size)503 mspcic_pci_map_find(struct mspcic_pci_map *m, int nmaps,
504 bus_addr_t pciaddr, bus_size_t size)
505 {
506 bus_size_t offset;
507 int i;
508
509 for (i = 0; i < nmaps; ++i, ++m) {
510 offset = pciaddr - m->pcibase;
511 if (offset + size <= m->size)
512 return (m->sysbase + offset);
513 }
514 return (0);
515 }
516
517
518 static int
mspcic_bus_map(bus_space_tag_t t,bus_addr_t ba,bus_size_t size,int flags,vaddr_t va,bus_space_handle_t * hp)519 mspcic_bus_map(bus_space_tag_t t, bus_addr_t ba, bus_size_t size,
520 int flags, vaddr_t va, bus_space_handle_t *hp)
521 {
522 struct mspcic_cookie *c = t->cookie;
523 bus_addr_t paddr;
524
525 paddr = mspcic_pci_map_find(c->map, c->nmaps, ba, size);
526 if (paddr == 0)
527 return (EINVAL);
528 return (bus_space_map2(t->parent, paddr, size, flags, va, hp));
529 }
530
531
532 static paddr_t
mspcic_bus_mmap(bus_space_tag_t t,bus_addr_t ba,off_t off,int prot,int flags)533 mspcic_bus_mmap(bus_space_tag_t t, bus_addr_t ba, off_t off,
534 int prot, int flags)
535 {
536 struct mspcic_cookie *c = t->cookie;
537 bus_addr_t paddr;
538
539 /* verify that phys to pci mapping for the target page exists */
540 paddr = mspcic_pci_map_find(c->map, c->nmaps, ba + off, PAGE_SIZE);
541 if (paddr == 0)
542 return (-1);
543
544 return (bus_space_mmap(t->parent, paddr - off, off, prot, flags));
545 }
546
547
548 /*
549 * Install an interrupt handler.
550 *
551 * Bus-specific interrupt argument is 'line', an interrupt input line
552 * for ms-IIep. The PIL for each line is programmable via pcic interrupt
553 * assignment select registers (but we use existing assignments).
554 */
555 static void *
mspcic_intr_establish(bus_space_tag_t t,int line,int ipl,int (* handler)(void *),void * arg,void (* fastvec)(void))556 mspcic_intr_establish(bus_space_tag_t t, int line, int ipl,
557 int (*handler)(void *), void *arg,
558 void (*fastvec)(void))
559 {
560 struct intrhand *ih;
561 int pil;
562
563 ih = kmem_alloc(sizeof(*ih), KM_SLEEP);
564
565 /* use pil set-up by prom */
566 pil = mspcic_assigned_interrupt(line);
567 if (pil == -1)
568 panic("mspcic_intr_establish: line %d", line);
569
570 ih->ih_fun = handler;
571 ih->ih_arg = arg;
572 intr_establish(pil, ipl, ih, fastvec, false);
573
574 return(ih);
575 }
576
577
578 static uint16_t
mspcic_bus_read_2(bus_space_tag_t space,bus_space_handle_t handle,bus_size_t offset)579 mspcic_bus_read_2(bus_space_tag_t space, bus_space_handle_t handle,
580 bus_size_t offset)
581 {
582 uint16_t val = *(volatile uint16_t *)(handle + offset);
583
584 return le16toh(val);
585 }
586
587
588 static uint32_t
mspcic_bus_read_4(bus_space_tag_t space,bus_space_handle_t handle,bus_size_t offset)589 mspcic_bus_read_4(bus_space_tag_t space, bus_space_handle_t handle,
590 bus_size_t offset)
591 {
592 uint32_t val = *(volatile uint32_t *)(handle + offset);
593
594 return le32toh(val);
595 }
596
597
598 static uint64_t
mspcic_bus_read_8(bus_space_tag_t space,bus_space_handle_t handle,bus_size_t offset)599 mspcic_bus_read_8(bus_space_tag_t space, bus_space_handle_t handle,
600 bus_size_t offset)
601 {
602 uint64_t val = *(volatile uint64_t *)(handle + offset);
603
604 return le64toh(val);
605 }
606
607
608 static void
mspcic_bus_write_2(bus_space_tag_t space,bus_space_handle_t handle,bus_size_t offset,uint16_t value)609 mspcic_bus_write_2(bus_space_tag_t space, bus_space_handle_t handle,
610 bus_size_t offset, uint16_t value)
611 {
612
613 (*(volatile uint16_t *)(handle + offset)) = htole16(value);
614 }
615
616
617 static void
mspcic_bus_write_4(bus_space_tag_t space,bus_space_handle_t handle,bus_size_t offset,uint32_t value)618 mspcic_bus_write_4(bus_space_tag_t space, bus_space_handle_t handle,
619 bus_size_t offset, uint32_t value)
620 {
621
622 (*(volatile uint32_t *)(handle + offset)) = htole32(value);
623 }
624
625
626 static void
mspcic_bus_write_8(bus_space_tag_t space,bus_space_handle_t handle,bus_size_t offset,uint64_t value)627 mspcic_bus_write_8(bus_space_tag_t space, bus_space_handle_t handle,
628 bus_size_t offset, uint64_t value)
629 {
630
631 (*(volatile uint64_t *)(handle + offset)) = htole64(value);
632 }
633
634
635 /* ======================================================================
636 *
637 * DMA methods
638 */
639
640 static int
mspcic_dmamap_load(bus_dma_tag_t t,bus_dmamap_t map,void * buf,bus_size_t buflen,struct proc * p,int flags)641 mspcic_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map,
642 void *buf, bus_size_t buflen,
643 struct proc *p, int flags)
644 {
645 pmap_t pmap;
646 paddr_t pa;
647
648 if (p != NULL)
649 pmap = p->p_vmspace->vm_map.pmap;
650 else
651 pmap = pmap_kernel();
652
653 if (!pmap_extract(pmap, (vaddr_t)buf, &pa))
654 panic("mspcic_dmamap_load: dma memory not mapped");
655
656 /* we always use just one segment */
657 map->dm_nsegs = 1;
658 map->dm_segs[0].ds_addr = pa;
659 map->dm_segs[0].ds_len = buflen;
660 map->dm_mapsize = buflen;
661
662 return (0);
663 }
664
665 static void
mspcic_dmamap_unload(bus_dma_tag_t t,bus_dmamap_t map)666 mspcic_dmamap_unload(bus_dma_tag_t t, bus_dmamap_t map)
667 {
668
669 /* Mark the mappings as invalid. */
670 map->dm_mapsize = 0;
671 map->dm_nsegs = 0;
672 }
673
674
675 static int
mspcic_dmamem_map(bus_dma_tag_t tag,bus_dma_segment_t * segs,int nsegs,size_t size,void ** kvap,int flags)676 mspcic_dmamem_map(bus_dma_tag_t tag, bus_dma_segment_t *segs, int nsegs,
677 size_t size, void **kvap, int flags)
678 {
679 struct pglist *mlist;
680 struct vm_page *m;
681 vaddr_t va;
682 int pagesz = PAGE_SIZE;
683 const uvm_flag_t kmflags =
684 (flags & BUS_DMA_NOWAIT) != 0 ? UVM_KMF_NOWAIT : 0;
685
686 if (nsegs != 1)
687 panic("mspcic_dmamem_map: nsegs = %d", nsegs);
688
689 size = round_page(size);
690
691 va = uvm_km_alloc(kernel_map, size, 0, UVM_KMF_VAONLY | kmflags);
692 if (va == 0)
693 return (ENOMEM);
694
695 segs[0]._ds_va = va;
696 *kvap = (void *)va;
697
698 /*
699 * Map the pages allocated in _bus_dmamem_alloc()
700 * to the kernel virtual address space.
701 */
702 mlist = segs[0]._ds_mlist;
703 TAILQ_FOREACH(m, mlist, pageq.queue) {
704 paddr_t pa;
705
706 if (size == 0)
707 panic("mspcic_dmamem_map: size botch");
708
709 pa = VM_PAGE_TO_PHYS(m);
710 pmap_kenter_pa(va,
711 pa | PMAP_NC, VM_PROT_READ | VM_PROT_WRITE, 0);
712 va += pagesz;
713 size -= pagesz;
714 }
715 pmap_update(pmap_kernel());
716
717 return (0);
718 }
719