xref: /openbsd/sys/arch/loongson/dev/htb.c (revision 565153a0)
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