1 /* $OpenBSD: octeon_iobus.c,v 1.28 2024/05/20 23:17:10 jsg Exp $ */
2
3 /*
4 * Copyright (c) 2000-2004 Opsycon AB (www.opsycon.se)
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 */
28
29 /*
30 * This is a iobus driver.
31 * It handles configuration of all devices on the processor bus except UART.
32 */
33
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/kernel.h>
37 #include <sys/conf.h>
38 #include <sys/malloc.h>
39 #include <sys/device.h>
40 #include <sys/proc.h>
41 #include <sys/atomic.h>
42
43 #include <dev/ofw/fdt.h>
44 #include <dev/ofw/openfirm.h>
45
46 #include <machine/autoconf.h>
47 #include <machine/fdt.h>
48 #include <machine/intr.h>
49 #include <machine/octeonvar.h>
50 #include <machine/octeonreg.h>
51 #include <machine/octeon_model.h>
52
53 #include <octeon/dev/iobusvar.h>
54 #include <octeon/dev/octhcireg.h> /* USBN_BASE */
55
56 int iobusmatch(struct device *, void *, void *);
57 void iobusattach(struct device *, struct device *, void *);
58 int iobusprint(void *, const char *);
59 int iobussubmatch(struct device *, void *, void *);
60 int iobussearch(struct device *, void *, void *);
61
62 bus_addr_t iobus_pa_to_device(paddr_t);
63 paddr_t iobus_device_to_pa(bus_addr_t);
64
65 const struct cfattach iobus_ca = {
66 sizeof(struct device), iobusmatch, iobusattach
67 };
68
69 struct cfdriver iobus_cd = {
70 NULL, "iobus", DV_DULL
71 };
72
73 bus_space_t iobus_tag = {
74 .bus_base = PHYS_TO_XKPHYS(0, CCA_NC),
75 .bus_private = NULL,
76 ._space_read_1 = generic_space_read_1,
77 ._space_write_1 = generic_space_write_1,
78 ._space_read_2 = generic_space_read_2,
79 ._space_write_2 = generic_space_write_2,
80 ._space_read_4 = generic_space_read_4,
81 ._space_write_4 = generic_space_write_4,
82 ._space_read_8 = generic_space_read_8,
83 ._space_write_8 = generic_space_write_8,
84 ._space_read_raw_2 = generic_space_read_raw_2,
85 ._space_write_raw_2 = generic_space_write_raw_2,
86 ._space_read_raw_4 = generic_space_read_raw_4,
87 ._space_write_raw_4 = generic_space_write_raw_4,
88 ._space_read_raw_8 = generic_space_read_raw_8,
89 ._space_write_raw_8 = generic_space_write_raw_8,
90 ._space_map = iobus_space_map,
91 ._space_unmap = iobus_space_unmap,
92 ._space_subregion = generic_space_region,
93 ._space_vaddr = generic_space_vaddr
94 };
95
96 struct machine_bus_dma_tag iobus_bus_dma_tag = {
97 NULL, /* _cookie */
98 _dmamap_create,
99 _dmamap_destroy,
100 _dmamap_load,
101 _dmamap_load_mbuf,
102 _dmamap_load_uio,
103 _dmamap_load_raw,
104 _dmamap_load_buffer,
105 _dmamap_unload,
106 _dmamap_sync,
107 _dmamem_alloc,
108 _dmamem_free,
109 _dmamem_map,
110 _dmamem_unmap,
111 _dmamem_mmap,
112 iobus_pa_to_device,
113 iobus_device_to_pa,
114 0
115 };
116
117 /*
118 * List of iobus child devices whose base addresses are too large to be
119 * recorded in the kernel configuration file. So look them up from here instead.
120 */
121
122 static const struct octeon_iobus_addrs iobus_addrs[] = {
123 { "octcf", OCTEON_CF_BASE },
124 { "octrng", OCTEON_RNG_BASE },
125 { "dwctwo", USBN_BASE },
126 { "amdcf", OCTEON_AMDCF_BASE},
127 };
128
129 /* There can only be one. */
130 int iobus_found;
131
132 /*
133 * Match bus only to targets which have this bus.
134 */
135 int
iobusmatch(struct device * parent,void * match,void * aux)136 iobusmatch(struct device *parent, void *match, void *aux)
137 {
138 if (iobus_found)
139 return (0);
140
141 return (1);
142 }
143
144 int
iobusprint(void * aux,const char * iobus)145 iobusprint(void *aux, const char *iobus)
146 {
147 struct iobus_attach_args *aa = aux;
148
149 if (iobus != NULL)
150 printf("%s at %s", aa->aa_name, iobus);
151
152 if (aa->aa_addr != 0)
153 printf(" base 0x%lx", aa->aa_addr);
154 if (aa->aa_irq >= 0)
155 printf(" irq %d", aa->aa_irq);
156
157 return (UNCONF);
158 }
159
160 int
iobussubmatch(struct device * parent,void * vcf,void * args)161 iobussubmatch(struct device *parent, void *vcf, void *args)
162 {
163 struct cfdata *cf = vcf;
164 struct iobus_attach_args *aa = args;
165
166 if (strcmp(cf->cf_driver->cd_name, aa->aa_name) != 0)
167 return 0;
168
169 if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != (int)aa->aa_addr)
170 return 0;
171
172 return (*cf->cf_attach->ca_match)(parent, cf, aa);
173 }
174
175 void
iobusattach(struct device * parent,struct device * self,void * aux)176 iobusattach(struct device *parent, struct device *self, void *aux)
177 {
178 struct iobus_attach_args aa;
179 struct fdt_attach_args fa;
180 struct octeon_config oc;
181 struct device *sc = self;
182 int soc;
183
184 iobus_found = 1;
185
186 printf("\n");
187
188 /* XXX */
189 oc.mc_iobus_bust = &iobus_tag;
190 oc.mc_iobus_dmat = &iobus_bus_dma_tag;
191 void cn30xxfpa_bootstrap(struct octeon_config *);
192 cn30xxfpa_bootstrap(&oc);
193 void cn30xxpow_bootstrap(struct octeon_config *);
194 cn30xxpow_bootstrap(&oc);
195
196 /*
197 * Attach all subdevices as described in the config file.
198 */
199
200 if ((soc = OF_finddevice("/soc")) != -1) {
201 memset(&fa, 0, sizeof(fa));
202 fa.fa_name = "";
203 fa.fa_node = soc;
204 fa.fa_iot = &iobus_tag;
205 fa.fa_dmat = &iobus_bus_dma_tag;
206 config_found(self, &fa, NULL);
207 }
208
209 config_search(iobussearch, self, sc);
210
211 if (octeon_ver == OCTEON_2 || octeon_ver == OCTEON_3) {
212 memset(&aa, 0, sizeof(aa));
213 aa.aa_name = "octpcie";
214 aa.aa_bust = &iobus_tag;
215 aa.aa_dmat = &iobus_bus_dma_tag;
216 aa.aa_irq = -1;
217 config_found_sm(self, &aa, iobusprint, iobussubmatch);
218 }
219 }
220
221 int
iobussearch(struct device * parent,void * v,void * aux)222 iobussearch(struct device *parent, void *v, void *aux)
223 {
224 struct iobus_attach_args aa;
225 struct cfdata *cf = v;
226 int i;
227
228 aa.aa_name = cf->cf_driver->cd_name;
229 aa.aa_bust = &iobus_tag;
230 aa.aa_dmat = &iobus_bus_dma_tag;
231 aa.aa_addr = cf->cf_loc[0];
232 aa.aa_irq = cf->cf_loc[1];
233 aa.aa_unitno = cf->cf_unit;
234
235 /* No address specified, try to look it up. */
236 if (aa.aa_addr == -1) {
237 for (i = 0; i < nitems(iobus_addrs); i++) {
238 if (strcmp(iobus_addrs[i].name, cf->cf_driver->cd_name) == 0)
239 aa.aa_addr = iobus_addrs[i].address;
240 }
241 if (aa.aa_addr == -1)
242 return 0;
243 }
244
245 if (cf->cf_attach->ca_match(parent, cf, &aa) == 0)
246 return 0;
247
248 config_attach(parent, cf, &aa, iobusprint);
249 return 1;
250 }
251
252 int
iobus_space_map(bus_space_tag_t t,bus_addr_t offs,bus_size_t size,int flags,bus_space_handle_t * bshp)253 iobus_space_map(bus_space_tag_t t, bus_addr_t offs, bus_size_t size,
254 int flags, bus_space_handle_t *bshp)
255 {
256 if (ISSET(flags, BUS_SPACE_MAP_KSEG0)) {
257 *bshp = PHYS_TO_CKSEG0(offs);
258 return 0;
259 }
260 if (ISSET(flags, BUS_SPACE_MAP_CACHEABLE))
261 offs +=
262 PHYS_TO_XKPHYS(0, CCA_CACHED) - PHYS_TO_XKPHYS(0, CCA_NC);
263 *bshp = t->bus_base + offs;
264 return 0;
265 }
266
267 void
iobus_space_unmap(bus_space_tag_t t,bus_space_handle_t bsh,bus_size_t size)268 iobus_space_unmap(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t size)
269 {
270 }
271
272 /*
273 * Iobus bus_dma helpers.
274 */
275
276 bus_addr_t
iobus_pa_to_device(paddr_t pa)277 iobus_pa_to_device(paddr_t pa)
278 {
279 return (bus_addr_t)pa;
280 }
281
282 paddr_t
iobus_device_to_pa(bus_addr_t addr)283 iobus_device_to_pa(bus_addr_t addr)
284 {
285 return (paddr_t)addr;
286 }
287