xref: /openbsd/sys/arch/macppc/pci/ht.c (revision 5dea098c)
1 /*	$OpenBSD: ht.c,v 1.19 2022/03/13 12:33:01 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 
32 int	 ht_match(struct device *, void *, void *);
33 void	 ht_attach(struct device *, struct device *, void *);
34 
35 pcireg_t ht_conf_read(void *, pcitag_t, int);
36 void	 ht_conf_write(void *, pcitag_t, int, pcireg_t);
37 
38 int	 ht_print(void *, const char *);
39 
40 struct 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 
53 const struct cfattach ht_ca = {
54 	sizeof(struct ht_softc), ht_match, ht_attach
55 };
56 
57 struct cfdriver ht_cd = {
58 	NULL, "ht", DV_DULL,
59 };
60 
61 int
62 ht_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 
71 void
72 ht_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 < 0 || 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,
113 	    regs[2] - 0x01000000, 0, &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 
149 pcireg_t
150 ht_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 
182 void
183 ht_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 
214 int
215 ht_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