1*495249e2Sjsg /* $OpenBSD: octeon_iobus.c,v 1.28 2024/05/20 23:17:10 jsg Exp $ */
261e15267Ssyuu
361e15267Ssyuu /*
461e15267Ssyuu * Copyright (c) 2000-2004 Opsycon AB (www.opsycon.se)
561e15267Ssyuu *
661e15267Ssyuu * Redistribution and use in source and binary forms, with or without
761e15267Ssyuu * modification, are permitted provided that the following conditions
861e15267Ssyuu * are met:
961e15267Ssyuu * 1. Redistributions of source code must retain the above copyright
1061e15267Ssyuu * notice, this list of conditions and the following disclaimer.
1161e15267Ssyuu * 2. Redistributions in binary form must reproduce the above copyright
1261e15267Ssyuu * notice, this list of conditions and the following disclaimer in the
1361e15267Ssyuu * documentation and/or other materials provided with the distribution.
1461e15267Ssyuu *
1561e15267Ssyuu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
1661e15267Ssyuu * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1761e15267Ssyuu * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1861e15267Ssyuu * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
1961e15267Ssyuu * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2061e15267Ssyuu * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2161e15267Ssyuu * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2261e15267Ssyuu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2361e15267Ssyuu * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2461e15267Ssyuu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2561e15267Ssyuu * SUCH DAMAGE.
2661e15267Ssyuu *
2761e15267Ssyuu */
2861e15267Ssyuu
2961e15267Ssyuu /*
3061e15267Ssyuu * This is a iobus driver.
3161e15267Ssyuu * It handles configuration of all devices on the processor bus except UART.
3261e15267Ssyuu */
3361e15267Ssyuu
3461e15267Ssyuu #include <sys/param.h>
3561e15267Ssyuu #include <sys/systm.h>
3661e15267Ssyuu #include <sys/kernel.h>
3761e15267Ssyuu #include <sys/conf.h>
3861e15267Ssyuu #include <sys/malloc.h>
3961e15267Ssyuu #include <sys/device.h>
4061e15267Ssyuu #include <sys/proc.h>
411b2dfb44Sjmatthew #include <sys/atomic.h>
4261e15267Ssyuu
43c441d705Svisa #include <dev/ofw/fdt.h>
44c441d705Svisa #include <dev/ofw/openfirm.h>
45c441d705Svisa
4661e15267Ssyuu #include <machine/autoconf.h>
47c441d705Svisa #include <machine/fdt.h>
4861e15267Ssyuu #include <machine/intr.h>
494a04f2fdSsyuu #include <machine/octeonvar.h>
50a81120d9Sjasper #include <machine/octeonreg.h>
51959570ccSvisa #include <machine/octeon_model.h>
5261e15267Ssyuu
5361e15267Ssyuu #include <octeon/dev/iobusvar.h>
5424a77cf7Smiod #include <octeon/dev/octhcireg.h> /* USBN_BASE */
5561e15267Ssyuu
5661e15267Ssyuu int iobusmatch(struct device *, void *, void *);
5761e15267Ssyuu void iobusattach(struct device *, struct device *, void *);
5861e15267Ssyuu int iobusprint(void *, const char *);
5961e15267Ssyuu int iobussubmatch(struct device *, void *, void *);
6073a9bee3Sjasper int iobussearch(struct device *, void *, void *);
6161e15267Ssyuu
6261e15267Ssyuu bus_addr_t iobus_pa_to_device(paddr_t);
6361e15267Ssyuu paddr_t iobus_device_to_pa(bus_addr_t);
6461e15267Ssyuu
65471aeecfSnaddy const struct cfattach iobus_ca = {
6661e15267Ssyuu sizeof(struct device), iobusmatch, iobusattach
6761e15267Ssyuu };
6861e15267Ssyuu
6961e15267Ssyuu struct cfdriver iobus_cd = {
7061e15267Ssyuu NULL, "iobus", DV_DULL
7161e15267Ssyuu };
7261e15267Ssyuu
7361e15267Ssyuu bus_space_t iobus_tag = {
7461e15267Ssyuu .bus_base = PHYS_TO_XKPHYS(0, CCA_NC),
7561e15267Ssyuu .bus_private = NULL,
7661e15267Ssyuu ._space_read_1 = generic_space_read_1,
7761e15267Ssyuu ._space_write_1 = generic_space_write_1,
7861e15267Ssyuu ._space_read_2 = generic_space_read_2,
7961e15267Ssyuu ._space_write_2 = generic_space_write_2,
8061e15267Ssyuu ._space_read_4 = generic_space_read_4,
8161e15267Ssyuu ._space_write_4 = generic_space_write_4,
8261e15267Ssyuu ._space_read_8 = generic_space_read_8,
8361e15267Ssyuu ._space_write_8 = generic_space_write_8,
8461e15267Ssyuu ._space_read_raw_2 = generic_space_read_raw_2,
8561e15267Ssyuu ._space_write_raw_2 = generic_space_write_raw_2,
8661e15267Ssyuu ._space_read_raw_4 = generic_space_read_raw_4,
8761e15267Ssyuu ._space_write_raw_4 = generic_space_write_raw_4,
8861e15267Ssyuu ._space_read_raw_8 = generic_space_read_raw_8,
8961e15267Ssyuu ._space_write_raw_8 = generic_space_write_raw_8,
9061e15267Ssyuu ._space_map = iobus_space_map,
9161e15267Ssyuu ._space_unmap = iobus_space_unmap,
9261e15267Ssyuu ._space_subregion = generic_space_region,
9361e15267Ssyuu ._space_vaddr = generic_space_vaddr
9461e15267Ssyuu };
9561e15267Ssyuu
9661e15267Ssyuu struct machine_bus_dma_tag iobus_bus_dma_tag = {
9761e15267Ssyuu NULL, /* _cookie */
9861e15267Ssyuu _dmamap_create,
9961e15267Ssyuu _dmamap_destroy,
10061e15267Ssyuu _dmamap_load,
10161e15267Ssyuu _dmamap_load_mbuf,
10261e15267Ssyuu _dmamap_load_uio,
10361e15267Ssyuu _dmamap_load_raw,
10461e15267Ssyuu _dmamap_load_buffer,
10561e15267Ssyuu _dmamap_unload,
10661e15267Ssyuu _dmamap_sync,
10761e15267Ssyuu _dmamem_alloc,
10861e15267Ssyuu _dmamem_free,
10961e15267Ssyuu _dmamem_map,
11061e15267Ssyuu _dmamem_unmap,
11161e15267Ssyuu _dmamem_mmap,
11261e15267Ssyuu iobus_pa_to_device,
11361e15267Ssyuu iobus_device_to_pa,
11461e15267Ssyuu 0
11561e15267Ssyuu };
11661e15267Ssyuu
11761e15267Ssyuu /*
11873a9bee3Sjasper * List of iobus child devices whose base addresses are too large to be
11973a9bee3Sjasper * recorded in the kernel configuration file. So look them up from here instead.
12061e15267Ssyuu */
12161e15267Ssyuu
12273a9bee3Sjasper static const struct octeon_iobus_addrs iobus_addrs[] = {
12373a9bee3Sjasper { "octcf", OCTEON_CF_BASE },
12473a9bee3Sjasper { "octrng", OCTEON_RNG_BASE },
12573a9bee3Sjasper { "dwctwo", USBN_BASE },
1266920b493Spirofti { "amdcf", OCTEON_AMDCF_BASE},
12761e15267Ssyuu };
12873a9bee3Sjasper
12973a9bee3Sjasper /* There can only be one. */
13073a9bee3Sjasper int iobus_found;
13161e15267Ssyuu
13261e15267Ssyuu /*
13361e15267Ssyuu * Match bus only to targets which have this bus.
13461e15267Ssyuu */
13561e15267Ssyuu int
iobusmatch(struct device * parent,void * match,void * aux)13661e15267Ssyuu iobusmatch(struct device *parent, void *match, void *aux)
13761e15267Ssyuu {
13873a9bee3Sjasper if (iobus_found)
13973a9bee3Sjasper return (0);
14073a9bee3Sjasper
14161e15267Ssyuu return (1);
14261e15267Ssyuu }
14361e15267Ssyuu
14461e15267Ssyuu int
iobusprint(void * aux,const char * iobus)14561e15267Ssyuu iobusprint(void *aux, const char *iobus)
14661e15267Ssyuu {
14761e15267Ssyuu struct iobus_attach_args *aa = aux;
14861e15267Ssyuu
14961e15267Ssyuu if (iobus != NULL)
15061e15267Ssyuu printf("%s at %s", aa->aa_name, iobus);
15161e15267Ssyuu
15273a9bee3Sjasper if (aa->aa_addr != 0)
15373a9bee3Sjasper printf(" base 0x%lx", aa->aa_addr);
15473a9bee3Sjasper if (aa->aa_irq >= 0)
15573a9bee3Sjasper printf(" irq %d", aa->aa_irq);
15661e15267Ssyuu
15761e15267Ssyuu return (UNCONF);
15861e15267Ssyuu }
15961e15267Ssyuu
16061e15267Ssyuu int
iobussubmatch(struct device * parent,void * vcf,void * args)16161e15267Ssyuu iobussubmatch(struct device *parent, void *vcf, void *args)
16261e15267Ssyuu {
16361e15267Ssyuu struct cfdata *cf = vcf;
16461e15267Ssyuu struct iobus_attach_args *aa = args;
16561e15267Ssyuu
16661e15267Ssyuu if (strcmp(cf->cf_driver->cd_name, aa->aa_name) != 0)
16761e15267Ssyuu return 0;
16861e15267Ssyuu
16973a9bee3Sjasper if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != (int)aa->aa_addr)
17061e15267Ssyuu return 0;
17161e15267Ssyuu
17261e15267Ssyuu return (*cf->cf_attach->ca_match)(parent, cf, aa);
17361e15267Ssyuu }
17461e15267Ssyuu
17561e15267Ssyuu void
iobusattach(struct device * parent,struct device * self,void * aux)17661e15267Ssyuu iobusattach(struct device *parent, struct device *self, void *aux)
17761e15267Ssyuu {
178959570ccSvisa struct iobus_attach_args aa;
179c441d705Svisa struct fdt_attach_args fa;
1804a04f2fdSsyuu struct octeon_config oc;
181959570ccSvisa struct device *sc = self;
18289585224Svisa int soc;
18361e15267Ssyuu
18473a9bee3Sjasper iobus_found = 1;
18573a9bee3Sjasper
18661e15267Ssyuu printf("\n");
18761e15267Ssyuu
1884a04f2fdSsyuu /* XXX */
1894a04f2fdSsyuu oc.mc_iobus_bust = &iobus_tag;
1904a04f2fdSsyuu oc.mc_iobus_dmat = &iobus_bus_dma_tag;
1914a04f2fdSsyuu void cn30xxfpa_bootstrap(struct octeon_config *);
1924a04f2fdSsyuu cn30xxfpa_bootstrap(&oc);
1934a04f2fdSsyuu void cn30xxpow_bootstrap(struct octeon_config *);
1944a04f2fdSsyuu cn30xxpow_bootstrap(&oc);
1954a04f2fdSsyuu
19661e15267Ssyuu /*
19773a9bee3Sjasper * Attach all subdevices as described in the config file.
19861e15267Ssyuu */
199fa003bdcSvisa
200fa003bdcSvisa if ((soc = OF_finddevice("/soc")) != -1) {
201fa003bdcSvisa memset(&fa, 0, sizeof(fa));
202fa003bdcSvisa fa.fa_name = "";
203fa003bdcSvisa fa.fa_node = soc;
204fa003bdcSvisa fa.fa_iot = &iobus_tag;
205fa003bdcSvisa fa.fa_dmat = &iobus_bus_dma_tag;
206fa003bdcSvisa config_found(self, &fa, NULL);
207fa003bdcSvisa }
208fa003bdcSvisa
20973a9bee3Sjasper config_search(iobussearch, self, sc);
210959570ccSvisa
211750f12e5Svisa if (octeon_ver == OCTEON_2 || octeon_ver == OCTEON_3) {
212750f12e5Svisa memset(&aa, 0, sizeof(aa));
213750f12e5Svisa aa.aa_name = "octpcie";
214750f12e5Svisa aa.aa_bust = &iobus_tag;
215750f12e5Svisa aa.aa_dmat = &iobus_bus_dma_tag;
216750f12e5Svisa aa.aa_irq = -1;
217750f12e5Svisa config_found_sm(self, &aa, iobusprint, iobussubmatch);
218750f12e5Svisa }
21973a9bee3Sjasper }
22073a9bee3Sjasper
22173a9bee3Sjasper int
iobussearch(struct device * parent,void * v,void * aux)22273a9bee3Sjasper iobussearch(struct device *parent, void *v, void *aux)
22373a9bee3Sjasper {
22473a9bee3Sjasper struct iobus_attach_args aa;
22573a9bee3Sjasper struct cfdata *cf = v;
22673a9bee3Sjasper int i;
22773a9bee3Sjasper
22873a9bee3Sjasper aa.aa_name = cf->cf_driver->cd_name;
22973a9bee3Sjasper aa.aa_bust = &iobus_tag;
23073a9bee3Sjasper aa.aa_dmat = &iobus_bus_dma_tag;
23173a9bee3Sjasper aa.aa_addr = cf->cf_loc[0];
23273a9bee3Sjasper aa.aa_irq = cf->cf_loc[1];
23373a9bee3Sjasper aa.aa_unitno = cf->cf_unit;
23473a9bee3Sjasper
23573a9bee3Sjasper /* No address specified, try to look it up. */
23673a9bee3Sjasper if (aa.aa_addr == -1) {
23773a9bee3Sjasper for (i = 0; i < nitems(iobus_addrs); i++) {
23873a9bee3Sjasper if (strcmp(iobus_addrs[i].name, cf->cf_driver->cd_name) == 0)
23973a9bee3Sjasper aa.aa_addr = iobus_addrs[i].address;
24073a9bee3Sjasper }
241959570ccSvisa if (aa.aa_addr == -1)
242959570ccSvisa return 0;
24373a9bee3Sjasper }
24473a9bee3Sjasper
24573a9bee3Sjasper if (cf->cf_attach->ca_match(parent, cf, &aa) == 0)
24673a9bee3Sjasper return 0;
24773a9bee3Sjasper
24873a9bee3Sjasper config_attach(parent, cf, &aa, iobusprint);
24973a9bee3Sjasper return 1;
25061e15267Ssyuu }
25161e15267Ssyuu
25261e15267Ssyuu int
iobus_space_map(bus_space_tag_t t,bus_addr_t offs,bus_size_t size,int flags,bus_space_handle_t * bshp)25361e15267Ssyuu iobus_space_map(bus_space_tag_t t, bus_addr_t offs, bus_size_t size,
25461e15267Ssyuu int flags, bus_space_handle_t *bshp)
25561e15267Ssyuu {
25661e15267Ssyuu if (ISSET(flags, BUS_SPACE_MAP_KSEG0)) {
25761e15267Ssyuu *bshp = PHYS_TO_CKSEG0(offs);
25861e15267Ssyuu return 0;
25961e15267Ssyuu }
26061e15267Ssyuu if (ISSET(flags, BUS_SPACE_MAP_CACHEABLE))
26161e15267Ssyuu offs +=
26261e15267Ssyuu PHYS_TO_XKPHYS(0, CCA_CACHED) - PHYS_TO_XKPHYS(0, CCA_NC);
26361e15267Ssyuu *bshp = t->bus_base + offs;
26461e15267Ssyuu return 0;
26561e15267Ssyuu }
26661e15267Ssyuu
26761e15267Ssyuu void
iobus_space_unmap(bus_space_tag_t t,bus_space_handle_t bsh,bus_size_t size)26861e15267Ssyuu iobus_space_unmap(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t size)
26961e15267Ssyuu {
27061e15267Ssyuu }
27161e15267Ssyuu
27261e15267Ssyuu /*
27361e15267Ssyuu * Iobus bus_dma helpers.
27461e15267Ssyuu */
27561e15267Ssyuu
27661e15267Ssyuu bus_addr_t
iobus_pa_to_device(paddr_t pa)27761e15267Ssyuu iobus_pa_to_device(paddr_t pa)
27861e15267Ssyuu {
27961e15267Ssyuu return (bus_addr_t)pa;
28061e15267Ssyuu }
28161e15267Ssyuu
28261e15267Ssyuu paddr_t
iobus_device_to_pa(bus_addr_t addr)28361e15267Ssyuu iobus_device_to_pa(bus_addr_t addr)
28461e15267Ssyuu {
28561e15267Ssyuu return (paddr_t)addr;
28661e15267Ssyuu }
287