1 /* $NetBSD: p5pb.c,v 1.4 2011/10/07 23:08:33 rkujawa Exp $ */ 2 3 /*- 4 * Copyright (c) 2011 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Radoslaw Kujawa. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/types.h> 33 #include <sys/param.h> 34 #include <sys/time.h> 35 #include <sys/systm.h> 36 #include <sys/errno.h> 37 #include <sys/device.h> 38 #include <sys/malloc.h> 39 #include <sys/extent.h> 40 41 #include <uvm/uvm_extern.h> 42 43 #include <machine/bus.h> 44 #include <machine/cpu.h> 45 46 #include <m68k/bus_dma.h> 47 #include <amiga/dev/zbusvar.h> 48 #include <amiga/pci/p5pbreg.h> 49 #include <amiga/pci/p5pbvar.h> 50 51 #include <dev/pci/pcivar.h> 52 #include <dev/pci/pcireg.h> 53 #include <dev/pci/pcidevs.h> 54 #include <dev/pci/pciconf.h> 55 56 /* Zorro IDs */ 57 #define ZORRO_MANID_P5 8512 58 #define ZORRO_PRODID_BPPC 110 /* BlizzardPPC */ 59 #define ZORRO_PRODID_CSPPC 100 /* CyberStormPPC */ 60 #define ZORRO_PRODID_P5PB 101 /* CVPPC/BVPPC/G-REX */ 61 #define ZORRO_PRODID_CV643D_Z3 67 /* CV64/3D */ 62 63 /* Initial CVPPC/BVPPC resolution as configured by the firmware */ 64 #define P5GFX_WIDTH 640 65 #define P5GFX_HEIGHT 480 66 #define P5GFX_DEPTH 8 67 #define P5GFX_LINEBYTES 640 68 69 /* #define P5PB_MATCH_CV643D 1 */ 70 /* #define P5PB_DEBUG 1 */ 71 72 static struct p5pb_bridge_type p5pb_bridge_cvppc = { 73 "Phase5 CVPPC/BVPPC PCI bridge", 74 false, 75 true, 76 1, 77 }; 78 79 static struct p5pb_bridge_type p5pb_bridge_cv643d = { 80 "Phase5 CyberVision 64/3D PCI bridge", 81 false, 82 false, 83 1, 84 }; 85 86 /* const struct p5pb_bridge_type p5pb_bridge_grex { 87 "DCE Computer G-REX PCI bridge", 88 true, 89 false, 90 5 91 } 92 */ 93 94 static int p5pb_match(struct device *, struct cfdata *, void *); 95 static void p5pb_attach(struct device *, struct device *, void *); 96 void p5pb_set_props(struct p5pb_softc *sc); 97 pcireg_t p5pb_pci_conf_read(pci_chipset_tag_t, pcitag_t, int); 98 void p5pb_pci_conf_write(pci_chipset_tag_t, pcitag_t, int, pcireg_t); 99 int p5pb_pci_bus_maxdevs(pci_chipset_tag_t pc, int busno); 100 int p5pb_pci_conf_hook(pci_chipset_tag_t pct, int bus, int dev, 101 int func, pcireg_t id); 102 void p5pb_pci_attach_hook (struct device *parent, 103 struct device *self, struct pcibus_attach_args *pba); 104 pcitag_t p5pb_pci_make_tag(pci_chipset_tag_t pc, int bus, int device, 105 int function); 106 void p5pb_pci_decompose_tag(pci_chipset_tag_t pc, pcitag_t tag, 107 int *bp, int *dp, int *fp); 108 int p5pb_pci_intr_map(const struct pci_attach_args *pa, 109 pci_intr_handle_t *ihp); 110 bool p5pb_bus_map_cv643d(struct p5pb_softc *sc); 111 static bool p5pb_bus_map_cvppc(struct p5pb_softc *sc); 112 113 CFATTACH_DECL_NEW(p5pb, sizeof(struct p5pb_softc), 114 p5pb_match, p5pb_attach, NULL, NULL); 115 116 static int p5pb_present = 0; 117 118 static int 119 p5pb_match(device_t parent, cfdata_t cf, void *aux) 120 { 121 struct zbus_args *zap; 122 123 zap = aux; 124 125 if (zap->manid != ZORRO_MANID_P5) 126 return 0; 127 128 #ifdef I_HAVE_P5PB_REALLY 129 /* 130 * At least some firmware versions do not create AutoConfig entries for 131 * CyberVisionPPC/BlizzardVisionPPC (product ID 0101). There's no "nice" 132 * way to detect the PCI bus in this case. At least check for CSPPC/BPPC. 133 */ 134 if ((zap->prodid != ZORRO_PRODID_BPPC) && 135 (zap->prodid != ZORRO_PRODID_CSPPC)) { 136 if (!p5pb_present) { 137 p5pb_present = 1; 138 return 100; /* XXX: This will break SCSI! */ 139 } 140 } 141 #endif 142 143 if ((zap->prodid != ZORRO_PRODID_P5PB) 144 #ifdef P5PB_MATCH_CV643D 145 /* 146 * This should not be used now, because CV64/3D grf driver does 147 * attach directly to Zorro bus. Might get useful if we ever get 148 * virgefb.. 149 */ 150 && (zap->prodid != ZORRO_PRODID_CV643D_Z3) 151 152 #endif 153 ) 154 return 0; 155 156 #ifdef P5PB_DEBUG 157 aprint_normal("p5pb matched by Zorro ID %d, %d\n", zap->manid, 158 zap->prodid); 159 #endif 160 161 if (p5pb_present) 162 return 0; /* Allow only one. */ 163 164 165 p5pb_present = 1; 166 return 10; 167 } 168 169 170 static void 171 p5pb_attach(device_t parent, device_t self, void *aux) 172 { 173 struct p5pb_softc *sc; 174 struct pcibus_attach_args pba; 175 struct p5pb_bridge_type *bt; 176 struct zbus_args *zap; 177 178 sc = device_private(self); 179 pci_chipset_tag_t pc = &sc->apc; 180 sc->sc_dev = self; 181 zap = aux; 182 183 if(zap->prodid == ZORRO_PRODID_CV643D_Z3) { 184 bt = &p5pb_bridge_cv643d; 185 sc->p5pb_bus_map = &p5pb_bus_map_cv643d; 186 sc->ba = zap->va; 187 } else { 188 bt = &p5pb_bridge_cvppc; 189 sc->p5pb_bus_map = p5pb_bus_map_cvppc; 190 } 191 192 if(!(sc->p5pb_bus_map(sc))) { 193 aprint_error_dev(self, 194 "couldn't map PCI configuration registers\n"); 195 return; 196 } 197 198 aprint_normal(": %s\n", bt->name); 199 200 #ifdef P5PB_DEBUG 201 aprint_normal("p5pb: mapped %x -> %x, %x -> %x\n, %x -> %x\n", 202 P5BUS_PCI_CONF_BASE, sc->pci_conf_area.base, 203 P5BUS_PCI_IO_BASE, sc->pci_conf_area.base, 204 P5BUS_PCI_MEM_BASE, sc->pci_mem_area.base ); 205 #endif 206 207 /* Initialize the PCI chipset tag. */ 208 sc->apc.pc_conf_v = (void*) pc; 209 sc->apc.pc_bus_maxdevs = p5pb_pci_bus_maxdevs; 210 sc->apc.pc_make_tag = amiga_pci_make_tag; 211 sc->apc.pc_decompose_tag = amiga_pci_decompose_tag; 212 sc->apc.pc_conf_read = p5pb_pci_conf_read; 213 sc->apc.pc_conf_write = p5pb_pci_conf_write; 214 sc->apc.pc_attach_hook = p5pb_pci_attach_hook; 215 216 sc->apc.pc_intr_map = p5pb_pci_intr_map; 217 sc->apc.pc_intr_string = amiga_pci_intr_string; 218 sc->apc.pc_intr_establish = amiga_pci_intr_establish; 219 sc->apc.pc_intr_disestablish = amiga_pci_intr_disestablish; 220 221 pba.pba_iot = &(sc->pci_io_area); 222 pba.pba_memt = &(sc->pci_mem_area); 223 pba.pba_dmat = NULL; 224 pba.pba_dmat64 = NULL; 225 pba.pba_pc = pc; 226 pba.pba_flags = PCI_FLAGS_MEM_OKAY | PCI_FLAGS_IO_OKAY; 227 pba.pba_bus = 0; 228 pba.pba_bridgetag = NULL; 229 230 p5pb_set_props(sc); 231 232 config_found_ia(self, "pcibus", &pba, pcibusprint); 233 } 234 235 /* 236 * Set properties needed to support fb driver. These are read later during 237 * autoconfg in device_register(). 238 */ 239 void 240 p5pb_set_props(struct p5pb_softc *sc) 241 { 242 prop_dictionary_t dict; 243 device_t dev; 244 245 dev = sc->sc_dev; 246 dict = device_properties(dev); 247 248 prop_dictionary_set_uint32(dict, "width", P5GFX_WIDTH); 249 prop_dictionary_set_uint32(dict, "height", P5GFX_HEIGHT); 250 prop_dictionary_set_uint8(dict, "depth", P5GFX_DEPTH); 251 prop_dictionary_set_uint16(dict, "linebytes", P5GFX_LINEBYTES); 252 prop_dictionary_set_uint64(dict, "address", P5BUS_PCI_MEM_BASE); 253 #if (NGENFB > 0) 254 /* 255 * Framebuffer starts at P5BUS_PCI_MEM_BASE, but genfb needs virtual 256 * address. 257 */ 258 prop_dictionary_set_uint64(dict, "virtual_address", 259 sc->pci_mem_area.base); 260 #endif 261 } 262 263 pcireg_t 264 p5pb_pci_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg) 265 { 266 uint32_t data; 267 uint32_t bus, dev, func; 268 269 pci_decompose_tag(pc, tag, &bus, &dev, &func); 270 271 data = bus_space_read_4(pc->pci_conf_datat, pc->pci_conf_datah, 272 (func<<5) + reg); 273 #ifdef P5PB_DEBUG 274 aprint_normal("p5pb conf read va: %lx, bus: %d, dev: %d, " 275 "func: %d, reg: %d -r-> data %x\n", 276 pc->pci_conf_datah, bus, dev, func, reg, data); 277 #endif 278 return data; 279 } 280 281 void 282 p5pb_pci_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t val) 283 { 284 uint32_t bus, dev, func; 285 286 pci_decompose_tag(pc, tag, &bus, &dev, &func); 287 288 bus_space_write_4(pc->pci_conf_datat, pc->pci_conf_datah, 289 (func << 5) + reg, val); 290 #ifdef P5PB_DEBUG 291 aprint_normal("p5pb conf write va: %lx, bus: %d, dev: %d, " 292 "func: %d, reg: %d -w-> data %x\n", 293 pc->pci_conf_datah, bus, dev, func, reg, val); 294 #endif 295 296 } 297 298 int 299 p5pb_pci_bus_maxdevs(pci_chipset_tag_t pc, int busno) 300 { 301 /* G-Rex has max 5 slots. CVPPC/BVPPC has only 1. */ 302 return 1; 303 } 304 305 void 306 p5pb_pci_attach_hook(struct device *parent, struct device *self, 307 struct pcibus_attach_args *pba) 308 { 309 } 310 311 int 312 p5pb_pci_intr_map(const struct pci_attach_args *pa, pci_intr_handle_t *ihp) 313 { 314 /* TODO: add sanity checking */ 315 316 *ihp = 2; 317 return 0; 318 } 319 320 static bool 321 p5pb_bus_map_cvppc(struct p5pb_softc *sc) 322 { 323 #ifdef P5PB_DEBUG 324 aprint_normal("p5pb: p5pb_bus_map_cvppc called\n"); 325 #endif /* P5PB_DEBUG */ 326 /* Setup bus space mappings. */ 327 sc->pci_conf_area.base = (bus_addr_t) zbusmap( 328 (void *) P5BUS_PCI_CONF_BASE, P5BUS_PCI_CONF_SIZE); 329 sc->pci_conf_area.absm = &amiga_bus_stride_1; 330 331 sc->pci_io_area.base = (bus_addr_t) zbusmap( 332 (void *) P5BUS_PCI_IO_BASE, P5BUS_PCI_IO_SIZE); 333 sc->pci_io_area.absm = &amiga_bus_stride_1swap_abs; 334 335 sc->pci_mem_area.base = (bus_addr_t) zbusmap( 336 (void *) P5BUS_PCI_MEM_BASE, P5BUS_PCI_MEM_SIZE); 337 sc->pci_mem_area.absm = &amiga_bus_stride_1swap_abs; 338 339 sc->apc.pci_conf_datat = &(sc->pci_conf_area); 340 sc->apc.pci_conf_addresst = &(sc->pci_conf_area); 341 342 if (bus_space_map(sc->apc.pci_conf_addresst, OFF_PCI_CONF_ADDR, 343 256, 0, &sc->apc.pci_conf_addressh)) 344 return false; 345 346 if (bus_space_map(sc->apc.pci_conf_datat, OFF_PCI_CONF_DATA, 347 256, 0, &sc->apc.pci_conf_datah)) 348 return false; 349 350 return true; 351 } 352 353 bool 354 p5pb_bus_map_cv643d(struct p5pb_softc *sc) { 355 #ifdef P5PB_DEBUG 356 aprint_normal("p5pb: p5pb_bus_map_cv643d called, ba = %x\n", 357 (bus_addr_t) sc->ba); 358 #endif /* P5PB_DEBUG */ 359 360 sc->pci_conf_area.base = (bus_addr_t) sc->ba + CV643D_PCI_CONF_BASE; 361 sc->pci_conf_area.absm = &amiga_bus_stride_1; 362 363 sc->pci_mem_area.base = (bus_addr_t) sc->ba + CV643D_PCI_MEM_BASE; 364 sc->pci_mem_area.absm = &amiga_bus_stride_1; 365 366 sc->pci_io_area.base = (bus_addr_t) sc->ba + CV643D_PCI_IO_BASE; 367 sc->pci_io_area.absm = &amiga_bus_stride_1; 368 369 sc->apc.pci_conf_datat = &(sc->pci_conf_area); 370 371 if (bus_space_map(sc->apc.pci_conf_datat, 0, 372 CV643D_PCI_CONF_SIZE, 0, &sc->apc.pci_conf_datah)) 373 return false; 374 375 376 return true; 377 } 378 379