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 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 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 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 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 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 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 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 277 iobus_pa_to_device(paddr_t pa) 278 { 279 return (bus_addr_t)pa; 280 } 281 282 paddr_t 283 iobus_device_to_pa(bus_addr_t addr) 284 { 285 return (paddr_t)addr; 286 } 287