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
ht_match(struct device * parent,void * cf,void * aux)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
ht_attach(struct device * parent,struct device * self,void * aux)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
ht_conf_read(void * cpv,pcitag_t tag,int offset)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
ht_conf_write(void * cpv,pcitag_t tag,int offset,pcireg_t data)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
ht_print(void * aux,const char * pnp)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