xref: /openbsd-src/sys/arch/octeon/dev/octeon_iobus.c (revision 495249e2c91bcb25c6fc2f27dcf09b0215f7ab0b)
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