1 1.30 skrll /* $NetBSD: footbridge.c,v 1.30 2022/09/27 06:36:41 skrll Exp $ */ 2 1.1 chris 3 1.1 chris /* 4 1.1 chris * Copyright (c) 1997,1998 Mark Brinicombe. 5 1.1 chris * Copyright (c) 1997,1998 Causality Limited 6 1.1 chris * All rights reserved. 7 1.1 chris * 8 1.1 chris * Redistribution and use in source and binary forms, with or without 9 1.1 chris * modification, are permitted provided that the following conditions 10 1.1 chris * are met: 11 1.1 chris * 1. Redistributions of source code must retain the above copyright 12 1.1 chris * notice, this list of conditions and the following disclaimer. 13 1.1 chris * 2. Redistributions in binary form must reproduce the above copyright 14 1.1 chris * notice, this list of conditions and the following disclaimer in the 15 1.1 chris * documentation and/or other materials provided with the distribution. 16 1.1 chris * 3. All advertising materials mentioning features or use of this software 17 1.1 chris * must display the following acknowledgement: 18 1.1 chris * This product includes software developed by Mark Brinicombe 19 1.1 chris * for the NetBSD Project. 20 1.1 chris * 4. The name of the company nor the name of the author may be used to 21 1.1 chris * endorse or promote products derived from this software without specific 22 1.1 chris * prior written permission. 23 1.1 chris * 24 1.1 chris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 25 1.1 chris * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 26 1.1 chris * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 27 1.1 chris * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 28 1.1 chris * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 29 1.1 chris * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 30 1.1 chris * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 1.1 chris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 1.1 chris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 1.1 chris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 1.1 chris * SUCH DAMAGE. 35 1.1 chris */ 36 1.13 chris 37 1.13 chris #include <sys/cdefs.h> 38 1.30 skrll __KERNEL_RCSID(0, "$NetBSD: footbridge.c,v 1.30 2022/09/27 06:36:41 skrll Exp $"); 39 1.1 chris 40 1.1 chris #include <sys/param.h> 41 1.1 chris #include <sys/systm.h> 42 1.1 chris #include <sys/kernel.h> 43 1.1 chris #include <sys/conf.h> 44 1.1 chris #include <sys/device.h> 45 1.18 chris #include <uvm/uvm_extern.h> 46 1.1 chris 47 1.1 chris #include <dev/pci/pcivar.h> 48 1.1 chris #define _ARM32_BUS_DMA_PRIVATE 49 1.25 dyoung #include <sys/bus.h> 50 1.2 matt #include <machine/intr.h> 51 1.18 chris #include <machine/bootconfig.h> 52 1.3 thorpej 53 1.5 thorpej #include <arm/cpuconf.h> 54 1.3 thorpej #include <arm/cpufunc.h> 55 1.3 thorpej 56 1.1 chris #include <arm/footbridge/footbridgevar.h> 57 1.1 chris #include <arm/footbridge/dc21285reg.h> 58 1.1 chris #include <arm/footbridge/dc21285mem.h> 59 1.4 chris #include <arm/footbridge/footbridge.h> 60 1.29 skrll 61 1.1 chris /* 62 1.1 chris * DC21285 'Footbridge' device 63 1.1 chris * 64 1.1 chris * This probes and attaches the footbridge device 65 1.1 chris * It then configures any children 66 1.1 chris */ 67 1.1 chris 68 1.1 chris /* Declare prototypes */ 69 1.1 chris 70 1.21 skrll static int footbridge_match(device_t parent, cfdata_t cf, void *aux); 71 1.21 skrll static void footbridge_attach(device_t parent, device_t self, void *aux); 72 1.19 dsl static int footbridge_print(void *aux, const char *pnp); 73 1.19 dsl static int footbridge_intr(void *arg); 74 1.1 chris 75 1.1 chris /* Driver and attach structures */ 76 1.21 skrll CFATTACH_DECL_NEW(footbridge, sizeof(struct footbridge_softc), 77 1.10 thorpej footbridge_match, footbridge_attach, NULL, NULL); 78 1.1 chris 79 1.1 chris /* Various bus space tags */ 80 1.1 chris extern struct bus_space footbridge_bs_tag; 81 1.1 chris extern void footbridge_create_io_bs_tag(bus_space_tag_t t, void *cookie); 82 1.1 chris extern void footbridge_create_mem_bs_tag(bus_space_tag_t t, void *cookie); 83 1.1 chris struct bus_space footbridge_csr_tag; 84 1.1 chris struct bus_space footbridge_pci_io_bs_tag; 85 1.1 chris struct bus_space footbridge_pci_mem_bs_tag; 86 1.1 chris extern struct arm32_pci_chipset footbridge_pci_chipset; 87 1.1 chris extern struct arm32_bus_dma_tag footbridge_pci_bus_dma_tag; 88 1.18 chris extern struct arm32_dma_range footbridge_dma_ranges[1]; 89 1.1 chris 90 1.1 chris /* Used in footbridge_clock.c */ 91 1.1 chris struct footbridge_softc *clock_sc; 92 1.1 chris 93 1.1 chris /* Set to non-zero to enable verbose reporting of footbridge system ints */ 94 1.1 chris int footbridge_intr_report = 0; 95 1.1 chris 96 1.1 chris int footbridge_found; 97 1.1 chris 98 1.1 chris void 99 1.1 chris footbridge_pci_bs_tag_init(void) 100 1.1 chris { 101 1.1 chris /* Set up the PCI bus tags */ 102 1.1 chris footbridge_create_io_bs_tag(&footbridge_pci_io_bs_tag, 103 1.1 chris (void *)DC21285_PCI_IO_VBASE); 104 1.1 chris footbridge_create_mem_bs_tag(&footbridge_pci_mem_bs_tag, 105 1.1 chris (void *)DC21285_PCI_MEM_BASE); 106 1.1 chris } 107 1.1 chris 108 1.1 chris /* 109 1.21 skrll * int footbridge_print(void *aux, const char *name) 110 1.1 chris * 111 1.1 chris * print configuration info for children 112 1.1 chris */ 113 1.1 chris 114 1.1 chris static int 115 1.20 dsl footbridge_print(void *aux, const char *pnp) 116 1.1 chris { 117 1.1 chris union footbridge_attach_args *fba = aux; 118 1.1 chris 119 1.1 chris if (pnp) 120 1.12 thorpej aprint_normal("%s at %s", fba->fba_name, pnp); 121 1.1 chris return(UNCONF); 122 1.1 chris } 123 1.1 chris 124 1.1 chris /* 125 1.26 skrll * int footbridge_match(device_t parent, cfdata_t cf, void *aux) 126 1.1 chris * 127 1.1 chris * Just return ok for this if it is device 0 128 1.29 skrll */ 129 1.29 skrll 130 1.1 chris static int 131 1.21 skrll footbridge_match(device_t parent, cfdata_t cf, void *aux) 132 1.1 chris { 133 1.1 chris if (footbridge_found) 134 1.1 chris return(0); 135 1.1 chris return(1); 136 1.1 chris } 137 1.1 chris 138 1.1 chris 139 1.1 chris /* 140 1.21 skrll * void footbridge_attach(device_t parent, device_t dev, void *aux) 141 1.1 chris * 142 1.1 chris */ 143 1.29 skrll 144 1.1 chris static void 145 1.21 skrll footbridge_attach(device_t parent, device_t self, void *aux) 146 1.1 chris { 147 1.21 skrll struct footbridge_softc *sc = device_private(self); 148 1.1 chris union footbridge_attach_args fba; 149 1.1 chris int vendor, device, rev; 150 1.1 chris 151 1.1 chris /* There can only be 1 footbridge. */ 152 1.1 chris footbridge_found = 1; 153 1.1 chris 154 1.1 chris clock_sc = sc; 155 1.1 chris 156 1.21 skrll sc->sc_dev = self; 157 1.1 chris sc->sc_iot = &footbridge_bs_tag; 158 1.1 chris 159 1.1 chris /* Map the Footbridge */ 160 1.1 chris if (bus_space_map(sc->sc_iot, DC21285_ARMCSR_VBASE, 161 1.1 chris DC21285_ARMCSR_VSIZE, 0, &sc->sc_ioh)) 162 1.21 skrll panic("%s: Cannot map registers", device_xname(self)); 163 1.1 chris 164 1.1 chris /* Read the ID to make sure it is what we think it is */ 165 1.1 chris vendor = bus_space_read_2(sc->sc_iot, sc->sc_ioh, VENDOR_ID); 166 1.1 chris device = bus_space_read_2(sc->sc_iot, sc->sc_ioh, DEVICE_ID); 167 1.1 chris rev = bus_space_read_1(sc->sc_iot, sc->sc_ioh, REVISION); 168 1.1 chris if (vendor != DC21285_VENDOR_ID && device != DC21285_DEVICE_ID) 169 1.21 skrll panic("%s: Unrecognised ID", device_xname(self)); 170 1.1 chris 171 1.21 skrll aprint_normal(": DC21285 rev %d\n", rev); 172 1.1 chris 173 1.1 chris /* Disable all interrupts from the footbridge */ 174 1.1 chris bus_space_write_4(sc->sc_iot, sc->sc_ioh, IRQ_ENABLE_CLEAR, 0xffffffff); 175 1.1 chris bus_space_write_4(sc->sc_iot, sc->sc_ioh, FIQ_ENABLE_CLEAR, 0xffffffff); 176 1.1 chris 177 1.1 chris /* Install a generic handler to catch a load of system interrupts */ 178 1.11 chris sc->sc_serr_ih = footbridge_intr_claim(IRQ_SERR, IPL_HIGH, 179 1.1 chris "serr", footbridge_intr, sc); 180 1.11 chris sc->sc_sdram_par_ih = footbridge_intr_claim(IRQ_SDRAM_PARITY, IPL_HIGH, 181 1.1 chris "sdram parity", footbridge_intr, sc); 182 1.11 chris sc->sc_data_par_ih = footbridge_intr_claim(IRQ_DATA_PARITY, IPL_HIGH, 183 1.1 chris "data parity", footbridge_intr, sc); 184 1.11 chris sc->sc_master_abt_ih = footbridge_intr_claim(IRQ_MASTER_ABORT, IPL_HIGH, 185 1.1 chris "mast abt", footbridge_intr, sc); 186 1.11 chris sc->sc_target_abt_ih = footbridge_intr_claim(IRQ_TARGET_ABORT, IPL_HIGH, 187 1.1 chris "targ abt", footbridge_intr, sc); 188 1.11 chris sc->sc_parity_ih = footbridge_intr_claim(IRQ_PARITY, IPL_HIGH, 189 1.1 chris "parity", footbridge_intr, sc); 190 1.29 skrll 191 1.1 chris /* Set up the PCI bus tags */ 192 1.1 chris footbridge_create_io_bs_tag(&footbridge_pci_io_bs_tag, 193 1.1 chris (void *)DC21285_PCI_IO_VBASE); 194 1.1 chris footbridge_create_mem_bs_tag(&footbridge_pci_mem_bs_tag, 195 1.1 chris (void *)DC21285_PCI_MEM_BASE); 196 1.1 chris 197 1.6 chris /* calibrate the delay loop */ 198 1.6 chris calibrate_delay(); 199 1.18 chris 200 1.23 skrll /* 201 1.23 skrll * It seems that the default of the memory being visible from 0 upwards 202 1.18 chris * on the PCI bus causes issues when DMAing from traditional PC VGA 203 1.18 chris * address. This breaks dumping core on cats, as DMAing pages in the 204 1.18 chris * range 0xb800-0xc000 cause the system to hang. This suggests that 205 1.18 chris * the VGA BIOS is taking over those addresses. 206 1.18 chris * (note that the range 0xb800-c000 is on an S3 card, others may vary 207 1.18 chris * 208 1.18 chris * To workaround this the SDRAM window on the PCI bus is shifted 209 1.18 chris * to 0x20000000, and the DMA range setup to match. 210 1.18 chris */ 211 1.18 chris { 212 1.18 chris /* first calculate the correct base address mask */ 213 1.18 chris int memory_size = bootconfig.dram[0].pages * PAGE_SIZE; 214 1.18 chris uint32_t mask; 215 1.18 chris 216 1.18 chris /* window has to be at least 256KB, and up to 256MB */ 217 1.18 chris for (mask = 0x00040000; mask < 0x10000000; mask <<= 1) 218 1.18 chris if (mask >= memory_size) 219 1.18 chris break; 220 1.18 chris mask--; 221 1.18 chris mask &= SDRAM_MASK_256MB; 222 1.29 skrll 223 1.18 chris /* 224 1.18 chris * configure the mask, the offset into SDRAM and the address 225 1.18 chris * SDRAM is exposed on the PCI bus. 226 1.18 chris */ 227 1.18 chris bus_space_write_4(sc->sc_iot, sc->sc_ioh, SDRAM_BA_MASK, mask); 228 1.18 chris bus_space_write_4(sc->sc_iot, sc->sc_ioh, SDRAM_BA_OFFSET, 0); 229 1.18 chris bus_space_write_4(sc->sc_iot, sc->sc_ioh, SDRAM_MEMORY_ADDR, 0x20000000); 230 1.18 chris 231 1.18 chris /* configure the dma range for the footbridge to match */ 232 1.18 chris footbridge_dma_ranges[0].dr_sysbase = bootconfig.dram[0].address; 233 1.18 chris footbridge_dma_ranges[0].dr_busbase = 0x20000000; 234 1.18 chris footbridge_dma_ranges[0].dr_len = memory_size; 235 1.18 chris } 236 1.18 chris 237 1.1 chris /* Attach the PCI bus */ 238 1.1 chris fba.fba_pba.pba_pc = &footbridge_pci_chipset; 239 1.1 chris fba.fba_pba.pba_iot = &footbridge_pci_io_bs_tag; 240 1.1 chris fba.fba_pba.pba_memt = &footbridge_pci_mem_bs_tag; 241 1.1 chris fba.fba_pba.pba_dmat = &footbridge_pci_bus_dma_tag; 242 1.14 fvdl fba.fba_pba.pba_dmat64 = NULL; 243 1.24 dyoung fba.fba_pba.pba_flags = PCI_FLAGS_IO_OKAY | PCI_FLAGS_MEM_OKAY; 244 1.1 chris fba.fba_pba.pba_bus = 0; 245 1.7 thorpej fba.fba_pba.pba_bridgetag = NULL; 246 1.27 thorpej config_found(self, &fba.fba_pba, pcibusprint, 247 1.28 thorpej CFARGS(.iattr = "pcibus")); 248 1.1 chris 249 1.1 chris /* Attach uart device */ 250 1.1 chris fba.fba_fca.fca_name = "fcom"; 251 1.1 chris fba.fba_fca.fca_iot = sc->sc_iot; 252 1.1 chris fba.fba_fca.fca_ioh = sc->sc_ioh; 253 1.1 chris fba.fba_fca.fca_rx_irq = IRQ_SERIAL_RX; 254 1.1 chris fba.fba_fca.fca_tx_irq = IRQ_SERIAL_TX; 255 1.27 thorpej config_found(self, &fba.fba_fca, footbridge_print, 256 1.28 thorpej CFARGS(.iattr = "footbridge")); 257 1.29 skrll 258 1.1 chris /* Setup fast SA110 cache clean area */ 259 1.1 chris #ifdef CPU_SA110 260 1.1 chris if (cputype == CPU_ID_SA110) 261 1.1 chris footbridge_sa110_cc_setup(); 262 1.1 chris #endif /* CPU_SA110 */ 263 1.1 chris 264 1.1 chris } 265 1.1 chris 266 1.1 chris /* Generic footbridge interrupt handler */ 267 1.1 chris 268 1.1 chris int 269 1.20 dsl footbridge_intr(void *arg) 270 1.1 chris { 271 1.1 chris struct footbridge_softc *sc = arg; 272 1.1 chris u_int ctrl, intr; 273 1.1 chris 274 1.1 chris /* 275 1.1 chris * Read the footbridge control register and check for 276 1.1 chris * SERR and parity errors 277 1.1 chris */ 278 1.1 chris ctrl = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SA_CONTROL); 279 1.1 chris intr = ctrl & (RECEIVED_SERR | SA_SDRAM_PARITY_ERROR | 280 1.1 chris PCI_SDRAM_PARITY_ERROR | DMA_SDRAM_PARITY_ERROR); 281 1.1 chris if (intr) { 282 1.1 chris /* Report the interrupt if reporting is enabled */ 283 1.1 chris if (footbridge_intr_report) 284 1.1 chris printf("footbridge_intr: ctrl=%08x\n", intr); 285 1.1 chris /* Clear the interrupt state */ 286 1.1 chris bus_space_write_4(sc->sc_iot, sc->sc_ioh, SA_CONTROL, 287 1.1 chris ctrl | intr); 288 1.1 chris } 289 1.1 chris /* 290 1.1 chris * Read the PCI status register and check for errors 291 1.1 chris */ 292 1.1 chris ctrl = bus_space_read_4(sc->sc_iot, sc->sc_ioh, PCI_COMMAND_STATUS_REG); 293 1.1 chris intr = ctrl & (PCI_STATUS_PARITY_ERROR | PCI_STATUS_MASTER_TARGET_ABORT 294 1.1 chris | PCI_STATUS_MASTER_ABORT | PCI_STATUS_SPECIAL_ERROR 295 1.1 chris | PCI_STATUS_PARITY_DETECT); 296 1.1 chris if (intr) { 297 1.1 chris /* Report the interrupt if reporting is enabled */ 298 1.1 chris if (footbridge_intr_report) 299 1.1 chris printf("footbridge_intr: pcistat=%08x\n", intr); 300 1.1 chris /* Clear the interrupt state */ 301 1.1 chris bus_space_write_4(sc->sc_iot, sc->sc_ioh, 302 1.1 chris PCI_COMMAND_STATUS_REG, ctrl | intr); 303 1.1 chris } 304 1.1 chris return(0); 305 1.1 chris } 306 1.1 chris 307 1.1 chris /* End of footbridge.c */ 308