ht.c revision 1.16
1/*	$OpenBSD: ht.c,v 1.16 2013/08/07 07:29:19 mpi 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 <dev/ofw/openfirm.h>
31
32int	 ht_match(struct device *, void *, void *);
33void	 ht_attach(struct device *, struct device *, void *);
34
35pcireg_t ht_conf_read(void *, pcitag_t, int);
36void	 ht_conf_write(void *, pcitag_t, int, pcireg_t);
37
38int	 ht_print(void *, const char *);
39
40struct ht_softc {
41	struct device	sc_dev;
42	int		sc_maxdevs;
43	struct ppc_bus_space sc_mem_bus_space;
44	struct ppc_bus_space sc_io_bus_space;
45	struct ppc_pci_chipset sc_pc;
46	bus_space_tag_t sc_memt;
47	bus_space_handle_t sc_config0_memh;
48	bus_space_handle_t sc_config1_memh;
49	bus_space_tag_t sc_iot;
50	bus_space_handle_t sc_config0_ioh;
51};
52
53struct cfattach ht_ca = {
54	sizeof(struct ht_softc), ht_match, ht_attach
55};
56
57struct cfdriver ht_cd = {
58	NULL, "ht", DV_DULL,
59};
60
61int
62ht_match(struct device *parent, void *cf, void *aux)
63{
64	struct confargs *ca = aux;
65
66	if (strcmp(ca->ca_name, "ht") == 0)
67		return (1);
68	return (0);
69}
70
71void
72ht_attach(struct device *parent, struct device *self, void *aux)
73{
74	struct ht_softc *sc = (struct ht_softc *)self;
75	struct confargs *ca = aux;
76	struct pcibus_attach_args pba;
77	u_int32_t regs[6];
78	char compat[32];
79	int node, len;
80
81	if (ca->ca_node == 0) {
82		printf(": invalid node on ht config\n");
83		return;
84	}
85
86	len = OF_getprop(ca->ca_node, "reg", regs, sizeof(regs));
87	if (len < sizeof(regs)) {
88		printf(": regs lookup failed, node %x\n", ca->ca_node);
89		return;
90	}
91
92	sc->sc_mem_bus_space.bus_base = 0x80000000;
93	sc->sc_mem_bus_space.bus_size = 0;
94	sc->sc_mem_bus_space.bus_io = 0;
95	sc->sc_memt = &sc->sc_mem_bus_space;
96
97	sc->sc_io_bus_space.bus_base = 0x80000000;
98	sc->sc_io_bus_space.bus_size = 0;
99	sc->sc_io_bus_space.bus_io = 1;
100	sc->sc_iot = &sc->sc_io_bus_space;
101
102	sc->sc_maxdevs = 1;
103	for (node = OF_child(ca->ca_node); node; node = OF_peer(node))
104		sc->sc_maxdevs++;
105
106	if (bus_space_map(sc->sc_memt, regs[1],
107	    (1 << 11)*sc->sc_maxdevs, 0, &sc->sc_config0_memh)) {
108		printf(": can't map PCI config0 memory\n");
109		return;
110	}
111
112	if (bus_space_map(sc->sc_memt, regs[1] + 0x01000000, 0x80000, 0,
113	    &sc->sc_config1_memh)) {
114		printf(": can't map PCI config1 memory\n");
115		return;
116	}
117
118	if (bus_space_map(sc->sc_iot, regs[4], 0x1000, 0,
119	    &sc->sc_config0_ioh)) {
120		printf(": can't map PCI config0 io\n");
121		return;
122	}
123
124	len = OF_getprop(ca->ca_node, "compatible", compat, sizeof(compat));
125	if (len <= 0)
126		printf(": unknown");
127	else
128		printf(": %s", compat);
129
130	sc->sc_pc.pc_conf_v = sc;
131	sc->sc_pc.pc_node = ca->ca_node;
132	sc->sc_pc.pc_conf_read = ht_conf_read;
133	sc->sc_pc.pc_conf_write = ht_conf_write;
134
135	bzero(&pba, sizeof(pba));
136	pba.pba_busname = "pci";
137	pba.pba_iot = sc->sc_iot;
138	pba.pba_memt = sc->sc_memt;
139	pba.pba_dmat = &pci_bus_dma_tag;
140	pba.pba_pc = &sc->sc_pc;
141	pba.pba_domain = pci_ndomains++;
142	pba.pba_bus = 0;
143
144	printf(", %d devices\n", sc->sc_maxdevs);
145
146	config_found(self, &pba, ht_print);
147}
148
149pcireg_t
150ht_conf_read(void *cpv, pcitag_t tag, int offset)
151{
152	struct ht_softc *sc = cpv;
153	int bus, dev, fcn;
154	pcireg_t reg;
155	uint32_t val;
156
157	val = PCITAG_OFFSET(tag);
158#ifdef DEBUG
159	printf("ht_conf_read: tag=%x, offset=%x\n", val, offset);
160#endif
161	pci_decompose_tag(NULL, tag, &bus, &dev, &fcn);
162	if (bus == 0 && dev == 0) {
163		val |= (offset << 2);
164		reg = bus_space_read_4(sc->sc_iot, sc->sc_config0_ioh, val);
165		reg = letoh32(reg);
166	} else if (bus == 0) {
167		/* XXX Why can we only access function 0? */
168		if (fcn > 0)
169			return ~0;
170		val |= offset;
171		reg = bus_space_read_4(sc->sc_memt, sc->sc_config0_memh, val);
172	} else {
173		val |= offset;
174		reg = bus_space_read_4(sc->sc_memt, sc->sc_config1_memh, val);
175	}
176#ifdef DEBUG
177	printf("ht_conf_read: reg=%x\n", reg);
178#endif
179	return reg;
180}
181
182void
183ht_conf_write(void *cpv, pcitag_t tag, int offset, pcireg_t data)
184{
185	struct ht_softc *sc = cpv;
186	int bus, dev, fcn;
187	uint32_t val;
188
189	val = PCITAG_OFFSET(tag);
190#ifdef DEBUG
191	printf("ht_conf_write: tag=%x, offset=%x, data = %x\n",
192	       val, offset, data);
193#endif
194	pci_decompose_tag(NULL, tag, &bus, &dev, &fcn);
195	if (bus == 0 && dev == 0) {
196		val |= (offset << 2);
197		data = htole32(data);
198		bus_space_write_4(sc->sc_iot, sc->sc_config0_ioh, val, data);
199		bus_space_read_4(sc->sc_iot, sc->sc_config0_ioh, val);
200	} else if (bus == 0) {
201		/* XXX Why can we only access function 0? */
202		if (fcn > 0)
203			return;
204		val |= offset;
205		bus_space_write_4(sc->sc_memt, sc->sc_config0_memh, val, data);
206		bus_space_read_4(sc->sc_memt, sc->sc_config0_memh, val);
207	} else {
208		val |= offset;
209		bus_space_write_4(sc->sc_memt, sc->sc_config1_memh, val, data);
210		bus_space_read_4(sc->sc_memt, sc->sc_config1_memh, val);
211	}
212}
213
214int
215ht_print(void *aux, const char *pnp)
216{
217	struct pcibus_attach_args *pba = aux;
218
219	if (pnp)
220		printf("%s at %s", pba->pba_busname, pnp);
221	printf(" bus %d", pba->pba_bus);
222	return (UNCONF);
223}
224