ht.c revision 1.14
1/*	$OpenBSD: ht.c,v 1.14 2010/12/04 17:06:31 miod Exp $	*/
2
3/*
4 * Copyright (c) 2005 Mark Kettenis
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#include <sys/param.h>
20#include <sys/systm.h>
21#include <sys/device.h>
22
23#include <machine/autoconf.h>
24#include <machine/bus.h>
25
26#include <dev/pci/pcireg.h>
27#include <dev/pci/pcivar.h>
28#include <dev/pci/pcidevs.h>
29
30#include <macppc/pci/pcibrvar.h>
31
32#include <dev/ofw/openfirm.h>
33
34int	 ht_match(struct device *, void *, void *);
35void	 ht_attach(struct device *, struct device *, void *);
36
37void	 ht_attach_hook(struct device *, struct device *,
38	     struct pcibus_attach_args *);
39int	 ht_bus_maxdevs(void *, int);
40pcitag_t ht_make_tag(void *, int, int, int);
41void	 ht_decompose_tag(void *, pcitag_t, int *, int *, int *);
42int	 ht_conf_size(void *, pcitag_t);
43pcireg_t ht_conf_read(void *, pcitag_t, int);
44void	 ht_conf_write(void *, pcitag_t, int, pcireg_t);
45int	 ht_intr_map(void *, pcitag_t, int, int, pci_intr_handle_t *);
46const char *ht_intr_string(void *, pci_intr_handle_t);
47int	 ht_intr_line(void *, pci_intr_handle_t);
48void	*ht_intr_establish(void *, pci_intr_handle_t, int, int (*)(void *),
49	     void *, const char *);
50void	 ht_intr_disestablish(void *, void *);
51
52int	 ht_ether_hw_addr(struct ppc_pci_chipset *, u_int8_t *);
53
54int	 ht_print(void *, const char *);
55
56#define BUS_SHIFT 16
57#define DEVICE_SHIFT 11
58#define FNC_SHIFT 8
59
60struct ht_softc {
61	struct device	sc_dev;
62	int		sc_maxdevs;
63	struct ppc_bus_space sc_mem_bus_space;
64	struct ppc_bus_space sc_io_bus_space;
65	struct ppc_pci_chipset sc_pc;
66	bus_space_tag_t sc_memt;
67	bus_space_handle_t sc_config0_memh;
68	bus_space_handle_t sc_config1_memh;
69	bus_space_tag_t sc_iot;
70	bus_space_handle_t sc_config0_ioh;
71};
72
73struct cfattach ht_ca = {
74	sizeof(struct ht_softc), ht_match, ht_attach
75};
76
77struct cfdriver ht_cd = {
78	NULL, "ht", DV_DULL,
79};
80
81#if 0
82struct powerpc_bus_dma_tag pci_bus_dma_tag = {
83	NULL,
84	_dmamap_create,
85	_dmamap_destroy,
86	_dmamap_load,
87	_dmamap_load_mbuf,
88	_dmamap_load_uio,
89	_dmamap_load_raw,
90	_dmamap_unload,
91	_dmamap_sync,
92	_dmamem_alloc,
93	_dmamem_free,
94	_dmamem_map,
95	_dmamem_unmap,
96	_dmamem_mmap
97};
98#else
99extern struct powerpc_bus_dma_tag pci_bus_dma_tag;
100#endif
101
102int
103ht_match(struct device *parent, void *cf, void *aux)
104{
105	struct confargs *ca = aux;
106
107	if (strcmp(ca->ca_name, "ht") == 0)
108		return (1);
109	return (0);
110}
111
112void
113ht_attach(struct device *parent, struct device *self, void *aux)
114{
115	struct ht_softc *sc = (struct ht_softc *)self;
116	struct confargs *ca = aux;
117	struct pcibus_attach_args pba;
118	u_int32_t regs[6];
119	char compat[32];
120	int node, nn;
121	int len;
122
123	if (ca->ca_node == 0) {
124		printf(": invalid node on ht config\n");
125		return;
126	}
127
128	len = OF_getprop(ca->ca_node, "reg", regs, sizeof(regs));
129	if (len < sizeof(regs)) {
130		printf(": regs lookup failed, node %x\n", ca->ca_node);
131		return;
132	}
133
134	sc->sc_mem_bus_space.bus_base = 0x80000000;
135	sc->sc_mem_bus_space.bus_size = 0;
136	sc->sc_mem_bus_space.bus_io = 0;
137	sc->sc_memt = &sc->sc_mem_bus_space;
138
139	sc->sc_io_bus_space.bus_base = 0x80000000;
140	sc->sc_io_bus_space.bus_size = 0;
141	sc->sc_io_bus_space.bus_io = 1;
142	sc->sc_iot = &sc->sc_io_bus_space;
143
144	sc->sc_maxdevs = 1;
145	for (node = OF_child(ca->ca_node); node; node = OF_peer(node))
146		sc->sc_maxdevs++;
147
148	if (bus_space_map(sc->sc_memt, regs[1],
149	    (1 << DEVICE_SHIFT)*sc->sc_maxdevs, 0, &sc->sc_config0_memh)) {
150		printf(": can't map PCI config0 memory\n");
151		return;
152	}
153
154	if (bus_space_map(sc->sc_memt, regs[1] + 0x01000000, 0x80000, 0,
155	    &sc->sc_config1_memh)) {
156		printf(": can't map PCI config1 memory\n");
157		return;
158	}
159
160	if (bus_space_map(sc->sc_iot, regs[4], 0x1000, 0,
161	    &sc->sc_config0_ioh)) {
162		printf(": can't map PCI config0 io\n");
163		return;
164	}
165
166	len = OF_getprop(ca->ca_node, "compatible", compat, sizeof(compat));
167	if (len <= 0)
168		printf(": unknown");
169	else
170		printf(": %s", compat);
171
172	sc->sc_pc.pc_conf_v = sc;
173	sc->sc_pc.pc_attach_hook = ht_attach_hook;
174	sc->sc_pc.pc_bus_maxdevs = ht_bus_maxdevs;
175	sc->sc_pc.pc_make_tag = ht_make_tag;
176	sc->sc_pc.pc_decompose_tag = ht_decompose_tag;
177	sc->sc_pc.pc_conf_size = ht_conf_size;
178	sc->sc_pc.pc_conf_read = ht_conf_read;
179	sc->sc_pc.pc_conf_write = ht_conf_write;
180
181	sc->sc_pc.pc_intr_v = sc;
182	sc->sc_pc.pc_intr_map = ht_intr_map;
183	sc->sc_pc.pc_intr_string = ht_intr_string;
184	sc->sc_pc.pc_intr_line = ht_intr_line;
185	sc->sc_pc.pc_intr_establish = ht_intr_establish;
186	sc->sc_pc.pc_intr_disestablish = ht_intr_disestablish;
187	sc->sc_pc.pc_ether_hw_addr = ht_ether_hw_addr;
188
189	bzero(&pba, sizeof(pba));
190	pba.pba_busname = "pci";
191	pba.pba_iot = sc->sc_iot;
192	pba.pba_memt = sc->sc_memt;
193	pba.pba_dmat = &pci_bus_dma_tag;
194	pba.pba_pc = &sc->sc_pc;
195	pba.pba_domain = pci_ndomains++;
196	pba.pba_bus = 0;
197
198	printf(", %d devices\n", sc->sc_maxdevs);
199
200	extern void fix_node_irq(int, struct pcibus_attach_args *);
201
202	for (node = OF_child(ca->ca_node); node; node = nn) {
203		fix_node_irq(node, &pba);
204
205		if ((nn = OF_child(node)) != 0)
206			continue;
207
208		while ((nn = OF_peer(node)) == 0) {
209			node = OF_parent(node);
210			if (node == ca->ca_node) {
211				nn = 0;
212				break;
213			}
214		}
215	}
216
217	config_found(self, &pba, ht_print);
218}
219
220void
221ht_attach_hook(struct device *parent, struct device *self,
222    struct pcibus_attach_args *pba)
223{
224}
225
226int
227ht_bus_maxdevs(void *cpv, int bus)
228{
229	struct ht_softc *sc = cpv;
230
231	/* XXX Probing more busses doesn't work. */
232	if (bus == 0)
233		return sc->sc_maxdevs;
234	return 32;
235}
236
237pcitag_t
238ht_make_tag(void *cpv, int bus, int dev, int fnc)
239{
240	return (bus << BUS_SHIFT) | (dev << DEVICE_SHIFT) | (fnc << FNC_SHIFT);
241}
242
243void
244ht_decompose_tag(void *cpv, pcitag_t tag, int *busp, int *devp, int *fncp)
245{
246	if (busp != NULL)
247		*busp = (tag >> BUS_SHIFT) & 0xff;
248	if (devp != NULL)
249		*devp = (tag >> DEVICE_SHIFT) & 0x1f;
250	if (fncp != NULL)
251		*fncp = (tag >> FNC_SHIFT) & 0x7;
252}
253
254int
255ht_conf_size(void *cpv, pcitag_t tag)
256{
257	return PCI_CONFIG_SPACE_SIZE;
258}
259
260pcireg_t
261ht_conf_read(void *cpv, pcitag_t tag, int offset)
262{
263	struct ht_softc *sc = cpv;
264	int bus, dev, fcn;
265	pcireg_t reg;
266
267#ifdef DEBUG
268	printf("ht_conf_read: tag=%x, offset=%x\n", tag, offset);
269#endif
270	ht_decompose_tag(NULL, tag, &bus, &dev, &fcn);
271	if (bus == 0 && dev == 0) {
272		tag |= (offset << 2);
273		reg = bus_space_read_4(sc->sc_iot, sc->sc_config0_ioh, tag);
274		reg = letoh32(reg);
275	} else if (bus == 0) {
276		/* XXX Why can we only access function 0? */
277		if (fcn > 0)
278			return ~0;
279		tag |= offset;
280		reg = bus_space_read_4(sc->sc_memt, sc->sc_config0_memh, tag);
281	} else {
282		tag |= offset;
283		reg = bus_space_read_4(sc->sc_memt, sc->sc_config1_memh, tag);
284	}
285#ifdef DEBUG
286	printf("ht_conf_read: reg=%x\n", reg);
287#endif
288	return reg;
289}
290
291void
292ht_conf_write(void *cpv, pcitag_t tag, int offset, pcireg_t data)
293{
294	struct ht_softc *sc = cpv;
295	int bus, dev, fcn;
296
297#ifdef DEBUG
298	printf("ht_conf_write: tag=%x, offset=%x, data = %x\n",
299	       tag, offset, data);
300#endif
301	ht_decompose_tag(NULL, tag, &bus, &dev, &fcn);
302	if (bus == 0 && dev == 0) {
303		tag |= (offset << 2);
304		data = htole32(data);
305		bus_space_write_4(sc->sc_iot, sc->sc_config0_ioh, tag, data);
306		bus_space_read_4(sc->sc_iot, sc->sc_config0_ioh, tag);
307	} else if (bus == 0) {
308		/* XXX Why can we only access function 0? */
309		if (fcn > 0)
310			return;
311		tag |= offset;
312		bus_space_write_4(sc->sc_memt, sc->sc_config0_memh, tag, data);
313		bus_space_read_4(sc->sc_memt, sc->sc_config0_memh, tag);
314	} else {
315		tag |= offset;
316		bus_space_write_4(sc->sc_memt, sc->sc_config1_memh, tag, data);
317		bus_space_read_4(sc->sc_memt, sc->sc_config1_memh, tag);
318	}
319}
320
321/* XXX */
322#define PCI_INTERRUPT_NO_CONNECTION	0xff
323
324int
325ht_intr_map(void *cpv, pcitag_t tag, int pin, int line,
326    pci_intr_handle_t *ihp)
327{
328	int error = 0;
329
330#ifdef DEBUG
331	printf("ht_intr_map: tag=%x, pin=%d, line=%d\n", tag, pin, line);
332#endif
333
334	*ihp = -1;
335        if (line == PCI_INTERRUPT_NO_CONNECTION)
336                error = 1; /* No IRQ used. */
337        else if (pin > PCI_INTERRUPT_PIN_MAX) {
338                printf("ht_intr_map: bad interrupt pin %d\n", pin);
339                error = 1;
340        }
341
342	if (!error)
343		*ihp = line;
344	return error;
345}
346
347const char *
348ht_intr_string(void *cpv, pci_intr_handle_t ih)
349{
350	static char str[16];
351
352	snprintf(str, sizeof str, "irq %ld", ih);
353	return (str);
354}
355
356int
357ht_intr_line(void *cpv, pci_intr_handle_t ih)
358{
359	return (ih);
360}
361
362void *
363ht_intr_establish(void *cpv, pci_intr_handle_t ih, int level,
364    int (*func)(void *), void *arg, const char *name)
365{
366	return (*intr_establish_func)(cpv, ih, IST_LEVEL, level, func, arg,
367		name);
368}
369
370void
371ht_intr_disestablish(void *lcv, void *cookie)
372{
373}
374
375int
376ht_ether_hw_addr(struct ppc_pci_chipset *lcpc, u_int8_t *oaddr)
377{
378	u_int8_t laddr[6];
379	int node;
380	int len;
381
382	node = OF_finddevice("enet");
383	len = OF_getprop(node, "local-mac-address", laddr, sizeof(laddr));
384	if (sizeof(laddr) == len) {
385		memcpy(oaddr, laddr, sizeof(laddr));
386		return 1;
387	}
388
389	oaddr[0] = oaddr[1] = oaddr[2] = 0xff;
390	oaddr[3] = oaddr[4] = oaddr[5] = 0xff;
391	return 0;
392}
393
394int
395ht_print(void *aux, const char *pnp)
396{
397	struct pcibus_attach_args *pba = aux;
398
399	if (pnp)
400		printf("%s at %s", pba->pba_busname, pnp);
401	printf(" bus %d", pba->pba_bus);
402	return (UNCONF);
403}
404