1 /* $OpenBSD: htb.c,v 1.3 2017/05/10 15:21:02 visa Exp $ */
2
3 /*
4 * Copyright (c) 2016 Visa Hankala
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 /*
20 * PCI host bridge driver for Loongson 3A.
21 */
22
23 #include <sys/param.h>
24 #include <sys/systm.h>
25 #include <sys/device.h>
26
27 #include <machine/autoconf.h>
28 #include <machine/loongson3.h>
29
30 #include <dev/pci/pcidevs.h>
31 #include <dev/pci/pcireg.h>
32 #include <dev/pci/pcivar.h>
33 #include <dev/pci/ppbreg.h>
34
35 #include <loongson/dev/htbreg.h>
36 #include <loongson/dev/htbvar.h>
37
38 struct htb_softc {
39 struct device sc_dev;
40 struct mips_pci_chipset sc_pc;
41 const struct htb_config *sc_config;
42 };
43
44 int htb_match(struct device *, void *, void *);
45 void htb_attach(struct device *, struct device *, void *);
46 int htb_print(void *, const char *);
47
48 void htb_attach_hook(struct device *, struct device *,
49 struct pcibus_attach_args *pba);
50 int htb_bus_maxdevs(void *, int);
51 pcitag_t htb_make_tag(void *, int, int, int);
52 void htb_decompose_tag(void *, pcitag_t, int *, int *, int *);
53 int htb_conf_addr(const struct bonito_config *, pcitag_t, int,
54 u_int32_t *, u_int32_t *);
55 int htb_conf_size(void *, pcitag_t);
56 pcireg_t htb_conf_read(void *, pcitag_t, int);
57 void htb_conf_write(void *, pcitag_t, int, pcireg_t);
58 int htb_pci_intr_map(struct pci_attach_args *, pci_intr_handle_t *);
59 const char *
60 htb_pci_intr_string(void *, pci_intr_handle_t);
61 void *htb_pci_intr_establish(void *, pci_intr_handle_t, int,
62 int (*)(void *), void *, char *);
63 void htb_pci_intr_disestablish(void *, void *);
64
65 bus_addr_t htb_pa_to_device(paddr_t);
66 paddr_t htb_device_to_pa(bus_addr_t);
67
68 int htb_io_map(bus_space_tag_t, bus_addr_t, bus_size_t, int,
69 bus_space_handle_t *);
70 int htb_mem_map(bus_space_tag_t, bus_addr_t, bus_size_t, int,
71 bus_space_handle_t *);
72 paddr_t htb_mem_mmap(bus_space_tag_t, bus_addr_t, off_t, int, int);
73
74 paddr_t htb_cfg_space_addr(pcitag_t, int);
75
76 pcireg_t htb_conf_read_early(pcitag_t, int);
77 pcitag_t htb_make_tag_early(int, int, int);
78
79 const struct cfattach htb_ca = {
80 sizeof(struct htb_softc), htb_match, htb_attach
81 };
82
83 struct cfdriver htb_cd = {
84 NULL, "htb", DV_DULL
85 };
86
87 struct machine_bus_dma_tag htb_bus_dma_tag = {
88 ._dmamap_create = _dmamap_create,
89 ._dmamap_destroy = _dmamap_destroy,
90 ._dmamap_load = _dmamap_load,
91 ._dmamap_load_mbuf = _dmamap_load_mbuf,
92 ._dmamap_load_uio = _dmamap_load_uio,
93 ._dmamap_load_raw = _dmamap_load_raw,
94 ._dmamap_load_buffer = _dmamap_load_buffer,
95 ._dmamap_unload = _dmamap_unload,
96 ._dmamap_sync = _dmamap_sync,
97 ._dmamem_alloc = _dmamem_alloc,
98 ._dmamem_free = _dmamem_free,
99 ._dmamem_map = _dmamem_map,
100 ._dmamem_unmap = _dmamem_unmap,
101 ._dmamem_mmap = _dmamem_mmap,
102
103 ._pa_to_device = htb_pa_to_device,
104 ._device_to_pa = htb_device_to_pa
105 };
106
107 struct mips_bus_space htb_pci_io_space_tag = {
108 .bus_base = PHYS_TO_XKPHYS(HTB_IO_BASE, CCA_NC),
109 ._space_read_1 = generic_space_read_1,
110 ._space_write_1 = generic_space_write_1,
111 ._space_read_2 = generic_space_read_2,
112 ._space_write_2 = generic_space_write_2,
113 ._space_read_4 = generic_space_read_4,
114 ._space_write_4 = generic_space_write_4,
115 ._space_read_8 = generic_space_read_8,
116 ._space_write_8 = generic_space_write_8,
117 ._space_read_raw_2 = generic_space_read_raw_2,
118 ._space_write_raw_2 = generic_space_write_raw_2,
119 ._space_read_raw_4 = generic_space_read_raw_4,
120 ._space_write_raw_4 = generic_space_write_raw_4,
121 ._space_read_raw_8 = generic_space_read_raw_8,
122 ._space_write_raw_8 = generic_space_write_raw_8,
123 ._space_map = htb_io_map,
124 ._space_unmap = generic_space_unmap,
125 ._space_subregion = generic_space_region,
126 ._space_vaddr = generic_space_vaddr,
127 ._space_mmap = generic_space_mmap
128 };
129
130 struct mips_bus_space htb_pci_mem_space_tag = {
131 .bus_base = PHYS_TO_XKPHYS(0, CCA_NC),
132 ._space_read_1 = generic_space_read_1,
133 ._space_write_1 = generic_space_write_1,
134 ._space_read_2 = generic_space_read_2,
135 ._space_write_2 = generic_space_write_2,
136 ._space_read_4 = generic_space_read_4,
137 ._space_write_4 = generic_space_write_4,
138 ._space_read_8 = generic_space_read_8,
139 ._space_write_8 = generic_space_write_8,
140 ._space_read_raw_2 = generic_space_read_raw_2,
141 ._space_write_raw_2 = generic_space_write_raw_2,
142 ._space_read_raw_4 = generic_space_read_raw_4,
143 ._space_write_raw_4 = generic_space_write_raw_4,
144 ._space_read_raw_8 = generic_space_read_raw_8,
145 ._space_write_raw_8 = generic_space_write_raw_8,
146 ._space_map = htb_mem_map,
147 ._space_unmap = generic_space_unmap,
148 ._space_subregion = generic_space_region,
149 ._space_vaddr = generic_space_vaddr,
150 ._space_mmap = htb_mem_mmap
151 };
152
153 int
htb_match(struct device * parent,void * match,void * aux)154 htb_match(struct device *parent, void *match, void *aux)
155 {
156 struct mainbus_attach_args *maa = aux;
157
158 if (loongson_ver != 0x3a && loongson_ver != 0x3b)
159 return 0;
160
161 if (strcmp(maa->maa_name, htb_cd.cd_name) != 0)
162 return 0;
163
164 return 1;
165 }
166
167 void
htb_attach(struct device * parent,struct device * self,void * aux)168 htb_attach(struct device *parent, struct device *self, void *aux)
169 {
170 struct pcibus_attach_args pba;
171 struct htb_softc *sc = (struct htb_softc *)self;
172 pci_chipset_tag_t pc = &sc->sc_pc;
173
174 printf("\n");
175
176 sc->sc_config = sys_platform->htb_config;
177
178 pc->pc_conf_v = sc;
179 pc->pc_attach_hook = htb_attach_hook;
180 pc->pc_bus_maxdevs = htb_bus_maxdevs;
181 pc->pc_make_tag = htb_make_tag;
182 pc->pc_decompose_tag = htb_decompose_tag;
183 pc->pc_conf_size = htb_conf_size;
184 pc->pc_conf_read = htb_conf_read;
185 pc->pc_conf_write = htb_conf_write;
186
187 pc->pc_intr_v = sc;
188 pc->pc_intr_map = htb_pci_intr_map;
189 pc->pc_intr_string = htb_pci_intr_string;
190 pc->pc_intr_establish = htb_pci_intr_establish;
191 pc->pc_intr_disestablish = htb_pci_intr_disestablish;
192
193 memset(&pba, 0, sizeof(pba));
194 pba.pba_busname = "pci";
195 pba.pba_iot = &htb_pci_io_space_tag;
196 pba.pba_memt = &htb_pci_mem_space_tag;
197 pba.pba_dmat = &htb_bus_dma_tag;
198 pba.pba_pc = pc;
199 pba.pba_ioex = extent_create("htb_io", 0, 0xffffffff, M_DEVBUF,
200 NULL, 0, EX_NOWAIT | EX_FILLED);
201 if (pba.pba_ioex != NULL) {
202 extent_free(pba.pba_ioex, 0, HTB_IO_SIZE, EX_NOWAIT);
203 }
204 pba.pba_memex = extent_create("htb_mem", 0, 0xffffffff, M_DEVBUF,
205 NULL, 0, EX_NOWAIT | EX_FILLED);
206 if (pba.pba_memex != NULL) {
207 extent_free(pba.pba_memex, HTB_MEM_BASE, HTB_MEM_SIZE,
208 EX_NOWAIT);
209 }
210 pba.pba_domain = pci_ndomains++;
211 pba.pba_bus = 0;
212 config_found(&sc->sc_dev, &pba, htb_print);
213 }
214
215 int
htb_print(void * aux,const char * pnp)216 htb_print(void *aux, const char *pnp)
217 {
218 struct pcibus_attach_args *pba = aux;
219
220 if (pnp)
221 printf("%s at %s", pba->pba_busname, pnp);
222 printf(" bus %d", pba->pba_bus);
223
224 return UNCONF;
225 }
226
227 void
htb_attach_hook(struct device * parent,struct device * self,struct pcibus_attach_args * pba)228 htb_attach_hook(struct device *parent, struct device *self,
229 struct pcibus_attach_args *pba)
230 {
231 pci_chipset_tag_t pc = pba->pba_pc;
232 struct htb_softc *sc = pc->pc_conf_v;
233 const struct htb_config *hc = sc->sc_config;
234
235 if (pba->pba_bus == 0)
236 hc->hc_attach_hook(pc);
237 }
238
239 int
htb_bus_maxdevs(void * v,int busno)240 htb_bus_maxdevs(void *v, int busno)
241 {
242 return 32;
243 }
244
245 pcitag_t
htb_make_tag(void * unused,int b,int d,int f)246 htb_make_tag(void *unused, int b, int d, int f)
247 {
248 return (b << 16) | (d << 11) | (f << 8);
249 }
250
251 void
htb_decompose_tag(void * unused,pcitag_t tag,int * bp,int * dp,int * fp)252 htb_decompose_tag(void *unused, pcitag_t tag, int *bp, int *dp, int *fp)
253 {
254 if (bp != NULL)
255 *bp = (tag >> 16) & 0xff;
256 if (dp != NULL)
257 *dp = (tag >> 11) & 0x1f;
258 if (fp != NULL)
259 *fp = (tag >> 8) & 0x7;
260 }
261
262 int
htb_conf_addr(const struct bonito_config * bc,pcitag_t tag,int offset,u_int32_t * cfgoff,u_int32_t * pcimap_cfg)263 htb_conf_addr(const struct bonito_config *bc, pcitag_t tag, int offset,
264 u_int32_t *cfgoff, u_int32_t *pcimap_cfg)
265 {
266 return -1;
267 }
268
269 int
htb_conf_size(void * v,pcitag_t tag)270 htb_conf_size(void *v, pcitag_t tag)
271 {
272 return PCIE_CONFIG_SPACE_SIZE;
273 }
274
275 pcireg_t
htb_conf_read(void * v,pcitag_t tag,int offset)276 htb_conf_read(void *v, pcitag_t tag, int offset)
277 {
278 return REGVAL(htb_cfg_space_addr(tag, offset));
279 }
280
281 void
htb_conf_write(void * v,pcitag_t tag,int offset,pcireg_t data)282 htb_conf_write(void *v, pcitag_t tag, int offset, pcireg_t data)
283 {
284 REGVAL(htb_cfg_space_addr(tag, offset)) = data;
285 }
286
287 paddr_t
htb_cfg_space_addr(pcitag_t tag,int offset)288 htb_cfg_space_addr(pcitag_t tag, int offset)
289 {
290 paddr_t pa;
291 int bus;
292
293 htb_decompose_tag(NULL, tag, &bus, NULL, NULL);
294 if (bus == 0)
295 pa = HTB_CFG_TYPE0_BASE;
296 else
297 pa = HTB_CFG_TYPE1_BASE;
298 return pa + tag + (offset & 0xfffc);
299 }
300
301 /*
302 * PCI interrupt handling
303 */
304
305 int
htb_pci_intr_map(struct pci_attach_args * pa,pci_intr_handle_t * ihp)306 htb_pci_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
307 {
308 int dev, pin;
309
310 *ihp = (pci_intr_handle_t)-1;
311
312 if (pa->pa_intrpin == 0)
313 return 1;
314
315 if (pa->pa_intrpin > PCI_INTERRUPT_PIN_MAX) {
316 printf(": bad interrupt pin %d\n", pa->pa_intrpin);
317 return 1;
318 }
319
320 pci_decompose_tag(pa->pa_pc, pa->pa_tag, NULL, &dev, NULL);
321 if (pa->pa_bridgetag != NULL) {
322 pin = PPB_INTERRUPT_SWIZZLE(pa->pa_rawintrpin, dev);
323 if (pa->pa_bridgeih[pin - 1] != (pci_intr_handle_t)-1) {
324 *ihp = pa->pa_bridgeih[pin - 1];
325 return 0;
326 }
327 }
328
329 if (pa->pa_intrline != 0) {
330 *ihp = pa->pa_intrline;
331 return 0;
332 }
333
334 return 1;
335 }
336
337 const char *
htb_pci_intr_string(void * cookie,pci_intr_handle_t ih)338 htb_pci_intr_string(void *cookie, pci_intr_handle_t ih)
339 {
340 static char irqstr[16];
341
342 snprintf(irqstr, sizeof(irqstr), "irq %lu", ih);
343 return irqstr;
344 }
345
346 void *
htb_pci_intr_establish(void * cookie,pci_intr_handle_t ih,int level,int (* cb)(void *),void * cbarg,char * name)347 htb_pci_intr_establish(void *cookie, pci_intr_handle_t ih, int level,
348 int (*cb)(void *), void *cbarg, char *name)
349 {
350 return loongson3_ht_intr_establish(ih, level, cb, cbarg, name);
351 }
352
353 void
htb_pci_intr_disestablish(void * cookie,void * ihp)354 htb_pci_intr_disestablish(void *cookie, void *ihp)
355 {
356 loongson3_ht_intr_disestablish(ihp);
357 }
358
359 bus_addr_t
htb_pa_to_device(paddr_t pa)360 htb_pa_to_device(paddr_t pa)
361 {
362 return pa ^ loongson_dma_base;
363 }
364
365 paddr_t
htb_device_to_pa(bus_addr_t addr)366 htb_device_to_pa(bus_addr_t addr)
367 {
368 return addr ^ loongson_dma_base;
369 }
370
371 /*
372 * bus_space(9) mapping routines
373 */
374
375 int
htb_io_map(bus_space_tag_t t,bus_addr_t offs,bus_size_t size,int flags,bus_space_handle_t * bshp)376 htb_io_map(bus_space_tag_t t, bus_addr_t offs, bus_size_t size, int flags,
377 bus_space_handle_t *bshp)
378 {
379 const struct legacy_io_range *r;
380 bus_addr_t end;
381
382 if (offs >= HTB_IO_SIZE)
383 return EINVAL;
384
385 if (offs < HTB_IO_LEGACY) {
386 end = offs + size - 1;
387 if ((r = sys_platform->legacy_io_ranges) == NULL)
388 return ENXIO;
389 for ( ; r->start != 0; r++) {
390 if (offs >= r->start && end <= r->end)
391 break;
392 }
393 if (r->end == 0)
394 return ENXIO;
395 }
396
397 *bshp = t->bus_base + offs;
398 return 0;
399 }
400
401 int
htb_mem_map(bus_space_tag_t t,bus_addr_t offs,bus_size_t size,int flags,bus_space_handle_t * bshp)402 htb_mem_map(bus_space_tag_t t, bus_addr_t offs, bus_size_t size, int flags,
403 bus_space_handle_t *bshp)
404 {
405 if (offs < HTB_MEM_BASE || offs + size > HTB_MEM_BASE + HTB_MEM_SIZE)
406 return EINVAL;
407
408 *bshp = t->bus_base + offs;
409 return 0;
410 }
411
412 paddr_t
htb_mem_mmap(bus_space_tag_t t,bus_addr_t addr,off_t off,int prot,int flags)413 htb_mem_mmap(bus_space_tag_t t, bus_addr_t addr, off_t off, int prot,
414 int flags)
415 {
416 return addr + off;
417 }
418
419 /*
420 * Functions for system setup
421 */
422
423 void
htb_early_setup(void)424 htb_early_setup(void)
425 {
426 pci_make_tag_early = htb_make_tag_early;
427 pci_conf_read_early = htb_conf_read_early;
428
429 early_mem_t = &htb_pci_mem_space_tag;
430 early_io_t = &htb_pci_io_space_tag;
431 }
432
433 pcitag_t
htb_make_tag_early(int b,int d,int f)434 htb_make_tag_early(int b, int d, int f)
435 {
436 return htb_make_tag(NULL, b, d, f);
437 }
438
439 pcireg_t
htb_conf_read_early(pcitag_t tag,int reg)440 htb_conf_read_early(pcitag_t tag, int reg)
441 {
442 return htb_conf_read(NULL, tag, reg);
443 }
444