admpci.c revision 330897
1/* $NetBSD: admpci.c,v 1.1 2007/03/20 08:52:02 dyoung Exp $ */
2
3/*-
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 * Copyright (c) 2007 David Young.  All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or
9 * without modification, are permitted provided that the following
10 * conditions are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above
14 *    copyright notice, this list of conditions and the following
15 *    disclaimer in the documentation and/or other materials provided
16 *    with the distribution.
17 * 3. The name of the author may not be used to endorse or promote
18 *    products derived from this software without specific prior
19 *    written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
22 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
23 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
24 * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
26 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
28 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
30 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
32 * OF SUCH DAMAGE.
33 */
34/*-
35 * Copyright (c) 2006 Itronix Inc.
36 * All rights reserved.
37 *
38 * Written by Garrett D'Amore for Itronix Inc.
39 *
40 * Redistribution and use in source and binary forms, with or without
41 * modification, are permitted provided that the following conditions
42 * are met:
43 * 1. Redistributions of source code must retain the above copyright
44 *    notice, this list of conditions and the following disclaimer.
45 * 2. Redistributions in binary form must reproduce the above copyright
46 *    notice, this list of conditions and the following disclaimer in the
47 *    documentation and/or other materials provided with the distribution.
48 * 3. The name of Itronix Inc. may not be used to endorse
49 *    or promote products derived from this software without specific
50 *    prior written permission.
51 *
52 * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
54 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
55 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
56 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
57 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
58 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
59 * ON ANY THEORY OF LIABILITY, WHETHER IN
60 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
61 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
62 * POSSIBILITY OF SUCH DAMAGE.
63 */
64
65#include <sys/cdefs.h>
66__FBSDID("$FreeBSD: stable/11/sys/mips/adm5120/admpci.c 330897 2018-03-14 03:19:51Z eadler $");
67
68#include <sys/param.h>
69#include <sys/systm.h>
70
71#include <sys/bus.h>
72#include <sys/interrupt.h>
73#include <sys/malloc.h>
74#include <sys/kernel.h>
75#include <sys/module.h>
76#include <sys/rman.h>
77
78#include <vm/vm.h>
79#include <vm/pmap.h>
80#include <vm/vm_extern.h>
81
82#include <machine/bus.h>
83#include <machine/cpu.h>
84
85#include <dev/pci/pcivar.h>
86#include <dev/pci/pcireg.h>
87
88#include <dev/pci/pcib_private.h>
89#include "pcib_if.h"
90
91#include <mips/adm5120/adm5120reg.h>
92
93#ifdef ADMPCI_DEBUG
94int admpci_debug = 1;
95#define	ADMPCI_DPRINTF(__fmt, ...)		\
96do {						\
97	if (admpci_debug)			\
98		printf((__fmt), __VA_ARGS__);	\
99} while (/*CONSTCOND*/0)
100#else /* !ADMPCI_DEBUG */
101#define	ADMPCI_DPRINTF(__fmt, ...)	do { } while (/*CONSTCOND*/0)
102#endif /* ADMPCI_DEBUG */
103
104#define	ADMPCI_TAG_BUS_MASK		__BITS(23, 16)
105/* Bit 11 is reserved.	It selects the AHB-PCI bridge.	Let device 0
106 * be the bridge.  For all other device numbers, let bit[11] == 0.
107 */
108#define	ADMPCI_TAG_DEVICE_MASK		__BITS(15, 11)
109#define	ADMPCI_TAG_DEVICE_SUBMASK	__BITS(15, 12)
110#define	ADMPCI_TAG_DEVICE_BRIDGE	__BIT(11)
111#define	ADMPCI_TAG_FUNCTION_MASK	__BITS(10, 8)
112#define	ADMPCI_TAG_REGISTER_MASK	__BITS(7, 0)
113
114#define	ADMPCI_MAX_DEVICE
115
116struct admpci_softc {
117	device_t		sc_dev;
118	bus_space_tag_t		sc_st;
119
120	/* Access to PCI config registers */
121	bus_space_handle_t	sc_addrh;
122	bus_space_handle_t	sc_datah;
123
124	int			sc_busno;
125	struct rman		sc_mem_rman;
126	struct rman		sc_io_rman;
127	struct rman		sc_irq_rman;
128	uint32_t		sc_mem;
129	uint32_t		sc_io;
130};
131
132static int
133admpci_probe(device_t dev)
134{
135
136	return (0);
137}
138
139static int
140admpci_attach(device_t dev)
141{
142	int busno = 0;
143	struct admpci_softc *sc = device_get_softc(dev);
144
145	sc->sc_dev = dev;
146	sc->sc_busno = busno;
147
148	/* Use KSEG1 to access IO ports for it is uncached */
149	sc->sc_io = MIPS_PHYS_TO_KSEG1(ADM5120_BASE_PCI_IO);
150	sc->sc_io_rman.rm_type = RMAN_ARRAY;
151	sc->sc_io_rman.rm_descr = "ADMPCI I/O Ports";
152	if (rman_init(&sc->sc_io_rman) != 0 ||
153		rman_manage_region(&sc->sc_io_rman, 0, 0xffff) != 0) {
154		panic("admpci_attach: failed to set up I/O rman");
155	}
156
157	/* Use KSEG1 to access PCI memory for it is uncached */
158	sc->sc_mem = MIPS_PHYS_TO_KSEG1(ADM5120_BASE_PCI_MEM);
159	sc->sc_mem_rman.rm_type = RMAN_ARRAY;
160	sc->sc_mem_rman.rm_descr = "ADMPCI PCI Memory";
161	if (rman_init(&sc->sc_mem_rman) != 0 ||
162	    rman_manage_region(&sc->sc_mem_rman,
163	    sc->sc_mem, sc->sc_mem + 0x100000) != 0) {
164		panic("admpci_attach: failed to set up memory rman");
165	}
166
167	sc->sc_irq_rman.rm_type = RMAN_ARRAY;
168	sc->sc_irq_rman.rm_descr = "ADMPCI PCI IRQs";
169	if (rman_init(&sc->sc_irq_rman) != 0 ||
170	    rman_manage_region(&sc->sc_irq_rman, 1, 31) != 0)
171		panic("admpci_attach: failed to set up IRQ rman");
172
173	if (bus_space_map(sc->sc_st, ADM5120_BASE_PCI_CONFADDR, 4, 0,
174	    &sc->sc_addrh) != 0) {
175		device_printf(sc->sc_dev, "unable to address space\n");
176		panic("bus_space_map failed");
177	}
178
179	if (bus_space_map(sc->sc_st, ADM5120_BASE_PCI_CONFDATA, 4, 0,
180	    &sc->sc_datah) != 0) {
181		device_printf(sc->sc_dev, "unable to address space\n");
182		panic("bus_space_map failed");
183	}
184
185	device_add_child(dev, "pci", -1);
186	return (bus_generic_attach(dev));
187}
188
189static int
190admpci_maxslots(device_t dev)
191{
192
193	return (PCI_SLOTMAX);
194}
195
196static uint32_t
197admpci_make_addr(int bus, int slot, int func, int reg)
198{
199
200	return (0x80000000 | (bus << 16) | (slot << 11) | (func << 8) | reg);
201}
202
203static uint32_t
204admpci_read_config(device_t dev, int bus, int slot, int func, int reg,
205    int bytes)
206{
207	struct admpci_softc *sc = device_get_softc(dev);
208	uint32_t data;
209	uint32_t shift, mask;
210	bus_addr_t addr;
211
212	ADMPCI_DPRINTF("%s: sc %p tag (%x, %x, %x) reg %d\n", __func__,
213			(void *)sc, bus, slot, func, reg);
214
215	addr = admpci_make_addr(bus, slot, func, reg);
216
217	ADMPCI_DPRINTF("%s: sc_addrh %p sc_datah %p addr %p\n", __func__,
218	    (void *)sc->sc_addrh, (void *)sc->sc_datah, (void *)addr);
219
220	bus_space_write_4(sc->sc_io, sc->sc_addrh, 0, addr);
221	data = bus_space_read_4(sc->sc_io, sc->sc_datah, 0);
222
223	switch (reg % 4) {
224	case 3:
225		shift = 24;
226		break;
227	case 2:
228		shift = 16;
229		break;
230	case 1:
231		shift = 8;
232		break;
233	default:
234		shift = 0;
235		break;
236	}
237
238	switch (bytes) {
239	case 1:
240		mask = 0xff;
241		data = (data >> shift) & mask;
242		break;
243	case 2:
244		mask = 0xffff;
245		if (reg % 4 == 0)
246			data = data & mask;
247		else
248			data = (data >> 16) & mask;
249		break;
250	case 4:
251		break;
252	default:
253		panic("%s: wrong bytes count", __func__);
254		break;
255	}
256
257	ADMPCI_DPRINTF("%s: read 0x%x\n", __func__, data);
258	return (data);
259}
260
261static void
262admpci_write_config(device_t dev, int bus, int slot, int func, int reg,
263    uint32_t data, int bytes)
264{
265	struct admpci_softc *sc = device_get_softc(dev);
266	bus_addr_t addr;
267	uint32_t reg_data;
268	uint32_t shift, mask;
269
270	ADMPCI_DPRINTF("%s: sc %p tag (%x, %x, %x) reg %d\n", __func__,
271			(void *)sc, bus, slot, func, reg);
272
273	if (bytes != 4) {
274		reg_data = admpci_read_config(dev, bus, slot, func, reg, 4);
275
276		switch (reg % 4) {
277		case 3:
278			shift = 24;
279			break;
280		case 2:
281			shift = 16;
282			break;
283		case 1:
284			shift = 8;
285			break;
286		default:
287			shift = 0;
288			break;
289		}
290
291		switch (bytes) {
292		case 1:
293			mask = 0xff;
294			data = (reg_data & ~ (mask << shift)) | (data << shift);
295			break;
296		case 2:
297			mask = 0xffff;
298			if (reg % 4 == 0)
299				data = (reg_data & ~mask) | data;
300			else
301				data = (reg_data & ~ (mask << shift)) |
302				    (data << shift);
303			break;
304		case 4:
305			break;
306		default:
307			panic("%s: wrong bytes count", __func__);
308			break;
309		}
310	}
311
312	addr = admpci_make_addr(bus, slot, func, reg);
313
314	ADMPCI_DPRINTF("%s: sc_addrh %p sc_datah %p addr %p\n", __func__,
315	    (void *)sc->sc_addrh, (void *)sc->sc_datah, (void *)addr);
316
317	bus_space_write_4(sc->sc_io, sc->sc_addrh, 0, addr);
318	bus_space_write_4(sc->sc_io, sc->sc_datah, 0, data);
319}
320
321static int
322admpci_route_interrupt(device_t pcib, device_t dev, int pin)
323{
324	/* TODO: implement */
325	return (0);
326}
327
328static int
329admpci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
330{
331	struct admpci_softc *sc = device_get_softc(dev);
332
333	switch (which) {
334	case PCIB_IVAR_DOMAIN:
335		*result = 0;
336		return (0);
337	case PCIB_IVAR_BUS:
338		*result = sc->sc_busno;
339		return (0);
340	}
341
342	return (ENOENT);
343}
344
345static int
346admpci_write_ivar(device_t dev, device_t child, int which, uintptr_t result)
347{
348	struct admpci_softc * sc = device_get_softc(dev);
349
350	switch (which) {
351	case PCIB_IVAR_BUS:
352		sc->sc_busno = result;
353		return (0);
354	}
355	return (ENOENT);
356}
357
358static struct resource *
359admpci_alloc_resource(device_t bus, device_t child, int type, int *rid,
360    rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
361{
362
363	return (NULL);
364#if 0
365	struct admpci_softc *sc = device_get_softc(bus);
366	struct resource *rv = NULL;
367	struct rman *rm;
368	bus_space_handle_t bh = 0;
369
370	switch (type) {
371	case SYS_RES_IRQ:
372		rm = &sc->sc_irq_rman;
373		break;
374	case SYS_RES_MEMORY:
375		rm = &sc->sc_mem_rman;
376		bh = sc->sc_mem;
377		break;
378	case SYS_RES_IOPORT:
379		rm = &sc->sc_io_rman;
380		bh = sc->sc_io;
381		break;
382	default:
383		return (NULL);
384	}
385
386	rv = rman_reserve_resource(rm, start, end, count, flags, child);
387	if (rv == NULL)
388		return (NULL);
389	rman_set_rid(rv, *rid);
390	if (type != SYS_RES_IRQ) {
391		bh += (rman_get_start(rv));
392
393		rman_set_bustag(rv, sc->sc_st);
394		rman_set_bushandle(rv, bh);
395		if (flags & RF_ACTIVE) {
396			if (bus_activate_resource(child, type, *rid, rv)) {
397				rman_release_resource(rv);
398				return (NULL);
399			}
400		}
401	}
402	return (rv);
403#endif
404}
405
406static int
407admpci_activate_resource(device_t bus, device_t child, int type, int rid,
408    struct resource *r)
409{
410	bus_space_handle_t p;
411	int error;
412
413	if ((type == SYS_RES_MEMORY) || (type == SYS_RES_IOPORT)) {
414		error = bus_space_map(rman_get_bustag(r),
415		    rman_get_bushandle(r), rman_get_size(r), 0, &p);
416		if (error)
417			return (error);
418		rman_set_bushandle(r, p);
419	}
420	return (rman_activate_resource(r));
421}
422
423static int
424admpci_setup_intr(device_t dev, device_t child, struct resource *ires,
425		int flags, driver_filter_t *filt, driver_intr_t *handler,
426		void *arg, void **cookiep)
427{
428
429#if 0
430	struct admpci_softc *sc = device_get_softc(dev);
431	struct intr_event *event;
432	int irq, error;
433
434	irq = rman_get_start(ires);
435	if (irq >= ICU_LEN || irq == 2)
436		panic("%s: bad irq or type", __func__);
437
438	event = sc->sc_eventstab[irq];
439	if (event == NULL) {
440		error = intr_event_create(&event, (void *)irq, 0,
441		    (void (*)(void *))NULL, "admpci intr%d:", irq);
442		if (error)
443			return 0;
444		sc->sc_eventstab[irq] = event;
445	}
446
447	intr_event_add_handler(event, device_get_nameunit(child), filt,
448	    handler, arg, intr_priority(flags), flags, cookiep);
449
450	/* Enable it, set trigger mode. */
451	sc->sc_imask &= ~(1 << irq);
452	sc->sc_elcr &= ~(1 << irq);
453
454	admpci_set_icus(sc);
455#endif
456
457	return (0);
458}
459
460static int
461admpci_teardown_intr(device_t dev, device_t child, struct resource *res,
462    void *cookie)
463{
464
465	return (intr_event_remove_handler(cookie));
466}
467
468static device_method_t admpci_methods[] = {
469	/* Device interface */
470	DEVMETHOD(device_probe,		admpci_probe),
471	DEVMETHOD(device_attach,	admpci_attach),
472	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
473	DEVMETHOD(device_suspend,	bus_generic_suspend),
474	DEVMETHOD(device_resume,	bus_generic_resume),
475
476	/* Bus interface */
477	DEVMETHOD(bus_read_ivar,	admpci_read_ivar),
478	DEVMETHOD(bus_write_ivar,	admpci_write_ivar),
479	DEVMETHOD(bus_alloc_resource,	admpci_alloc_resource),
480	DEVMETHOD(bus_release_resource,	bus_generic_release_resource),
481	DEVMETHOD(bus_activate_resource, admpci_activate_resource),
482	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
483	DEVMETHOD(bus_setup_intr,	admpci_setup_intr),
484	DEVMETHOD(bus_teardown_intr,	admpci_teardown_intr),
485
486	/* pcib interface */
487	DEVMETHOD(pcib_maxslots,	admpci_maxslots),
488	DEVMETHOD(pcib_read_config,	admpci_read_config),
489	DEVMETHOD(pcib_write_config,	admpci_write_config),
490	DEVMETHOD(pcib_route_interrupt,	admpci_route_interrupt),
491
492	DEVMETHOD_END
493};
494
495static driver_t admpci_driver = {
496	"pcib",
497	admpci_methods,
498	sizeof(struct admpci_softc),
499};
500
501static devclass_t admpci_devclass;
502
503DRIVER_MODULE(admpci, obio, admpci_driver, admpci_devclass, 0, 0);
504