1*fa003bdcSvisa /* $OpenBSD: octeon_iobus.c,v 1.19 2017/04/24 14:10:19 visa 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> 544a04f2fdSsyuu #include <octeon/dev/cn30xxgmxreg.h> 5524a77cf7Smiod #include <octeon/dev/octhcireg.h> /* USBN_BASE */ 56494889e9Sjmatthew #include <octeon/dev/octuctlreg.h> 5761e15267Ssyuu 5861e15267Ssyuu int iobusmatch(struct device *, void *, void *); 5961e15267Ssyuu void iobusattach(struct device *, struct device *, void *); 6061e15267Ssyuu int iobusprint(void *, const char *); 6161e15267Ssyuu int iobussubmatch(struct device *, void *, void *); 6273a9bee3Sjasper int iobussearch(struct device *, void *, void *); 6361e15267Ssyuu 6461e15267Ssyuu u_int8_t iobus_read_1(bus_space_tag_t, bus_space_handle_t, bus_size_t); 6561e15267Ssyuu u_int16_t iobus_read_2(bus_space_tag_t, bus_space_handle_t, bus_size_t); 6661e15267Ssyuu u_int32_t iobus_read_4(bus_space_tag_t, bus_space_handle_t, bus_size_t); 6761e15267Ssyuu u_int64_t iobus_read_8(bus_space_tag_t, bus_space_handle_t, bus_size_t); 6861e15267Ssyuu 6961e15267Ssyuu void iobus_write_1(bus_space_tag_t, bus_space_handle_t, bus_size_t, 7061e15267Ssyuu u_int8_t); 7161e15267Ssyuu void iobus_write_2(bus_space_tag_t, bus_space_handle_t, bus_size_t, 7261e15267Ssyuu u_int16_t); 7361e15267Ssyuu void iobus_write_4(bus_space_tag_t, bus_space_handle_t, bus_size_t, 7461e15267Ssyuu u_int32_t); 7561e15267Ssyuu void iobus_write_8(bus_space_tag_t, bus_space_handle_t, bus_size_t, 7661e15267Ssyuu u_int64_t); 7761e15267Ssyuu 7861e15267Ssyuu void iobus_read_raw_2(bus_space_tag_t, bus_space_handle_t, bus_addr_t, 7961e15267Ssyuu u_int8_t *, bus_size_t); 8061e15267Ssyuu void iobus_write_raw_2(bus_space_tag_t, bus_space_handle_t, bus_addr_t, 8161e15267Ssyuu const u_int8_t *, bus_size_t); 8261e15267Ssyuu void iobus_read_raw_4(bus_space_tag_t, bus_space_handle_t, bus_addr_t, 8361e15267Ssyuu u_int8_t *, bus_size_t); 8461e15267Ssyuu void iobus_write_raw_4(bus_space_tag_t, bus_space_handle_t, bus_addr_t, 8561e15267Ssyuu const u_int8_t *, bus_size_t); 8661e15267Ssyuu void iobus_read_raw_8(bus_space_tag_t, bus_space_handle_t, bus_addr_t, 8761e15267Ssyuu u_int8_t *, bus_size_t); 8861e15267Ssyuu void iobus_write_raw_8(bus_space_tag_t, bus_space_handle_t, bus_addr_t, 8961e15267Ssyuu const u_int8_t *, bus_size_t); 9061e15267Ssyuu 9161e15267Ssyuu bus_addr_t iobus_pa_to_device(paddr_t); 9261e15267Ssyuu paddr_t iobus_device_to_pa(bus_addr_t); 9361e15267Ssyuu 9461e15267Ssyuu struct cfattach iobus_ca = { 9561e15267Ssyuu sizeof(struct device), iobusmatch, iobusattach 9661e15267Ssyuu }; 9761e15267Ssyuu 9861e15267Ssyuu struct cfdriver iobus_cd = { 9961e15267Ssyuu NULL, "iobus", DV_DULL 10061e15267Ssyuu }; 10161e15267Ssyuu 10261e15267Ssyuu bus_space_t iobus_tag = { 10361e15267Ssyuu .bus_base = PHYS_TO_XKPHYS(0, CCA_NC), 10461e15267Ssyuu .bus_private = NULL, 10561e15267Ssyuu ._space_read_1 = generic_space_read_1, 10661e15267Ssyuu ._space_write_1 = generic_space_write_1, 10761e15267Ssyuu ._space_read_2 = generic_space_read_2, 10861e15267Ssyuu ._space_write_2 = generic_space_write_2, 10961e15267Ssyuu ._space_read_4 = generic_space_read_4, 11061e15267Ssyuu ._space_write_4 = generic_space_write_4, 11161e15267Ssyuu ._space_read_8 = generic_space_read_8, 11261e15267Ssyuu ._space_write_8 = generic_space_write_8, 11361e15267Ssyuu ._space_read_raw_2 = generic_space_read_raw_2, 11461e15267Ssyuu ._space_write_raw_2 = generic_space_write_raw_2, 11561e15267Ssyuu ._space_read_raw_4 = generic_space_read_raw_4, 11661e15267Ssyuu ._space_write_raw_4 = generic_space_write_raw_4, 11761e15267Ssyuu ._space_read_raw_8 = generic_space_read_raw_8, 11861e15267Ssyuu ._space_write_raw_8 = generic_space_write_raw_8, 11961e15267Ssyuu ._space_map = iobus_space_map, 12061e15267Ssyuu ._space_unmap = iobus_space_unmap, 12161e15267Ssyuu ._space_subregion = generic_space_region, 12261e15267Ssyuu ._space_vaddr = generic_space_vaddr 12361e15267Ssyuu }; 12461e15267Ssyuu 12561e15267Ssyuu bus_space_handle_t iobus_h; 12661e15267Ssyuu 12761e15267Ssyuu struct machine_bus_dma_tag iobus_bus_dma_tag = { 12861e15267Ssyuu NULL, /* _cookie */ 12961e15267Ssyuu _dmamap_create, 13061e15267Ssyuu _dmamap_destroy, 13161e15267Ssyuu _dmamap_load, 13261e15267Ssyuu _dmamap_load_mbuf, 13361e15267Ssyuu _dmamap_load_uio, 13461e15267Ssyuu _dmamap_load_raw, 13561e15267Ssyuu _dmamap_load_buffer, 13661e15267Ssyuu _dmamap_unload, 13761e15267Ssyuu _dmamap_sync, 13861e15267Ssyuu _dmamem_alloc, 13961e15267Ssyuu _dmamem_free, 14061e15267Ssyuu _dmamem_map, 14161e15267Ssyuu _dmamem_unmap, 14261e15267Ssyuu _dmamem_mmap, 14361e15267Ssyuu iobus_pa_to_device, 14461e15267Ssyuu iobus_device_to_pa, 14561e15267Ssyuu 0 14661e15267Ssyuu }; 14761e15267Ssyuu 14861e15267Ssyuu /* 14973a9bee3Sjasper * List of iobus child devices whose base addresses are too large to be 15073a9bee3Sjasper * recorded in the kernel configuration file. So look them up from here instead. 15161e15267Ssyuu */ 15261e15267Ssyuu 15373a9bee3Sjasper static const struct octeon_iobus_addrs iobus_addrs[] = { 15473a9bee3Sjasper { "octcf", OCTEON_CF_BASE }, 15573a9bee3Sjasper { "octrng", OCTEON_RNG_BASE }, 15673a9bee3Sjasper { "dwctwo", USBN_BASE }, 1576920b493Spirofti { "amdcf", OCTEON_AMDCF_BASE}, 158494889e9Sjmatthew { "octuctl", UCTL_BASE }, 15961e15267Ssyuu }; 16073a9bee3Sjasper 16173a9bee3Sjasper /* There can only be one. */ 16273a9bee3Sjasper int iobus_found; 16361e15267Ssyuu 16461e15267Ssyuu /* 16561e15267Ssyuu * Match bus only to targets which have this bus. 16661e15267Ssyuu */ 16761e15267Ssyuu int 16861e15267Ssyuu iobusmatch(struct device *parent, void *match, void *aux) 16961e15267Ssyuu { 17073a9bee3Sjasper if (iobus_found) 17173a9bee3Sjasper return (0); 17273a9bee3Sjasper 17361e15267Ssyuu return (1); 17461e15267Ssyuu } 17561e15267Ssyuu 17661e15267Ssyuu int 17761e15267Ssyuu iobusprint(void *aux, const char *iobus) 17861e15267Ssyuu { 17961e15267Ssyuu struct iobus_attach_args *aa = aux; 18061e15267Ssyuu 18161e15267Ssyuu if (iobus != NULL) 18261e15267Ssyuu printf("%s at %s", aa->aa_name, iobus); 18361e15267Ssyuu 18473a9bee3Sjasper if (aa->aa_addr != 0) 18573a9bee3Sjasper printf(" base 0x%lx", aa->aa_addr); 18673a9bee3Sjasper if (aa->aa_irq >= 0) 18773a9bee3Sjasper printf(" irq %d", aa->aa_irq); 18861e15267Ssyuu 18961e15267Ssyuu return (UNCONF); 19061e15267Ssyuu } 19161e15267Ssyuu 19261e15267Ssyuu int 19361e15267Ssyuu iobussubmatch(struct device *parent, void *vcf, void *args) 19461e15267Ssyuu { 19561e15267Ssyuu struct cfdata *cf = vcf; 19661e15267Ssyuu struct iobus_attach_args *aa = args; 19761e15267Ssyuu 19861e15267Ssyuu if (strcmp(cf->cf_driver->cd_name, aa->aa_name) != 0) 19961e15267Ssyuu return 0; 20061e15267Ssyuu 20173a9bee3Sjasper if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != (int)aa->aa_addr) 20261e15267Ssyuu return 0; 20361e15267Ssyuu 20461e15267Ssyuu return (*cf->cf_attach->ca_match)(parent, cf, aa); 20561e15267Ssyuu } 20661e15267Ssyuu 20761e15267Ssyuu void 20861e15267Ssyuu iobusattach(struct device *parent, struct device *self, void *aux) 20961e15267Ssyuu { 210959570ccSvisa struct iobus_attach_args aa; 211c441d705Svisa struct fdt_attach_args fa; 2124a04f2fdSsyuu struct octeon_config oc; 213959570ccSvisa struct device *sc = self; 214c441d705Svisa int chipid, i, ngmx, soc; 21561e15267Ssyuu 21661e15267Ssyuu /* 21753df9d47Sjasper * Map and setup CIU control registers. 21861e15267Ssyuu */ 21961e15267Ssyuu if (bus_space_map(&iobus_tag, OCTEON_CIU_BASE, OCTEON_CIU_SIZE, 0, 22061e15267Ssyuu &iobus_h)) { 22161e15267Ssyuu printf(": can't map CIU control registers\n"); 22261e15267Ssyuu return; 22361e15267Ssyuu } 22461e15267Ssyuu 22573a9bee3Sjasper iobus_found = 1; 22673a9bee3Sjasper 22761e15267Ssyuu printf("\n"); 22861e15267Ssyuu 22961e15267Ssyuu octeon_intr_init(); 23061e15267Ssyuu 2314a04f2fdSsyuu /* XXX */ 2324a04f2fdSsyuu oc.mc_iobus_bust = &iobus_tag; 2334a04f2fdSsyuu oc.mc_iobus_dmat = &iobus_bus_dma_tag; 2344a04f2fdSsyuu void cn30xxfpa_bootstrap(struct octeon_config *); 2354a04f2fdSsyuu cn30xxfpa_bootstrap(&oc); 2364a04f2fdSsyuu void cn30xxpow_bootstrap(struct octeon_config *); 2374a04f2fdSsyuu cn30xxpow_bootstrap(&oc); 2384a04f2fdSsyuu 23961e15267Ssyuu /* 24073a9bee3Sjasper * Attach all subdevices as described in the config file. 24161e15267Ssyuu */ 242*fa003bdcSvisa 243*fa003bdcSvisa if ((soc = OF_finddevice("/soc")) != -1) { 244*fa003bdcSvisa memset(&fa, 0, sizeof(fa)); 245*fa003bdcSvisa fa.fa_name = ""; 246*fa003bdcSvisa fa.fa_node = soc; 247*fa003bdcSvisa fa.fa_iot = &iobus_tag; 248*fa003bdcSvisa fa.fa_dmat = &iobus_bus_dma_tag; 249*fa003bdcSvisa config_found(self, &fa, NULL); 250*fa003bdcSvisa } 251*fa003bdcSvisa 25273a9bee3Sjasper config_search(iobussearch, self, sc); 253959570ccSvisa 254959570ccSvisa chipid = octeon_get_chipid(); 255959570ccSvisa switch (octeon_model_family(chipid)) { 256959570ccSvisa case OCTEON_MODEL_FAMILY_CN30XX: 257959570ccSvisa case OCTEON_MODEL_FAMILY_CN50XX: 258959570ccSvisa default: 259959570ccSvisa ngmx = 1; 260959570ccSvisa break; 261959570ccSvisa case OCTEON_MODEL_FAMILY_CN61XX: 262959570ccSvisa ngmx = 2; 263959570ccSvisa break; 264251f411dSvisa case OCTEON_MODEL_FAMILY_CN73XX: 265251f411dSvisa ngmx = 0; 266251f411dSvisa break; 267959570ccSvisa } 268959570ccSvisa for (i = 0; i < ngmx; i++) { 269959570ccSvisa aa.aa_name = "cn30xxgmx"; 270959570ccSvisa aa.aa_bust = &iobus_tag; 271959570ccSvisa aa.aa_dmat = &iobus_bus_dma_tag; 272959570ccSvisa aa.aa_addr = GMX0_BASE_PORT0 + GMX_BLOCK_SIZE * i; 273959570ccSvisa aa.aa_irq = -1; 274959570ccSvisa aa.aa_unitno = i; 275959570ccSvisa config_found_sm(self, &aa, iobusprint, iobussubmatch); 276959570ccSvisa } 27773a9bee3Sjasper } 27873a9bee3Sjasper 27973a9bee3Sjasper int 28073a9bee3Sjasper iobussearch(struct device *parent, void *v, void *aux) 28173a9bee3Sjasper { 28273a9bee3Sjasper struct iobus_attach_args aa; 28373a9bee3Sjasper struct cfdata *cf = v; 28473a9bee3Sjasper int i; 28573a9bee3Sjasper 28673a9bee3Sjasper aa.aa_name = cf->cf_driver->cd_name; 28773a9bee3Sjasper aa.aa_bust = &iobus_tag; 28873a9bee3Sjasper aa.aa_dmat = &iobus_bus_dma_tag; 28973a9bee3Sjasper aa.aa_addr = cf->cf_loc[0]; 29073a9bee3Sjasper aa.aa_irq = cf->cf_loc[1]; 29173a9bee3Sjasper aa.aa_unitno = cf->cf_unit; 29273a9bee3Sjasper 29373a9bee3Sjasper /* No address specified, try to look it up. */ 29473a9bee3Sjasper if (aa.aa_addr == -1) { 29573a9bee3Sjasper for (i = 0; i < nitems(iobus_addrs); i++) { 29673a9bee3Sjasper if (strcmp(iobus_addrs[i].name, cf->cf_driver->cd_name) == 0) 29773a9bee3Sjasper aa.aa_addr = iobus_addrs[i].address; 29873a9bee3Sjasper } 299959570ccSvisa if (aa.aa_addr == -1) 300959570ccSvisa return 0; 30173a9bee3Sjasper } 30273a9bee3Sjasper 30373a9bee3Sjasper if (cf->cf_attach->ca_match(parent, cf, &aa) == 0) 30473a9bee3Sjasper return 0; 30573a9bee3Sjasper 30673a9bee3Sjasper config_attach(parent, cf, &aa, iobusprint); 30773a9bee3Sjasper return 1; 30861e15267Ssyuu } 30961e15267Ssyuu 31061e15267Ssyuu int 31161e15267Ssyuu iobus_space_map(bus_space_tag_t t, bus_addr_t offs, bus_size_t size, 31261e15267Ssyuu int flags, bus_space_handle_t *bshp) 31361e15267Ssyuu { 31461e15267Ssyuu if (ISSET(flags, BUS_SPACE_MAP_KSEG0)) { 31561e15267Ssyuu *bshp = PHYS_TO_CKSEG0(offs); 31661e15267Ssyuu return 0; 31761e15267Ssyuu } 31861e15267Ssyuu if (ISSET(flags, BUS_SPACE_MAP_CACHEABLE)) 31961e15267Ssyuu offs += 32061e15267Ssyuu PHYS_TO_XKPHYS(0, CCA_CACHED) - PHYS_TO_XKPHYS(0, CCA_NC); 32161e15267Ssyuu *bshp = t->bus_base + offs; 32261e15267Ssyuu return 0; 32361e15267Ssyuu } 32461e15267Ssyuu 32561e15267Ssyuu void 32661e15267Ssyuu iobus_space_unmap(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t size) 32761e15267Ssyuu { 32861e15267Ssyuu } 32961e15267Ssyuu 33061e15267Ssyuu /* 33161e15267Ssyuu * Iobus bus_dma helpers. 33261e15267Ssyuu */ 33361e15267Ssyuu 33461e15267Ssyuu bus_addr_t 33561e15267Ssyuu iobus_pa_to_device(paddr_t pa) 33661e15267Ssyuu { 33761e15267Ssyuu return (bus_addr_t)pa; 33861e15267Ssyuu } 33961e15267Ssyuu 34061e15267Ssyuu paddr_t 34161e15267Ssyuu iobus_device_to_pa(bus_addr_t addr) 34261e15267Ssyuu { 34361e15267Ssyuu return (paddr_t)addr; 34461e15267Ssyuu } 345