1 /* $NetBSD: gio.c,v 1.22 2006/08/30 23:48:55 rumble Exp $ */ 2 3 /* 4 * Copyright (c) 2000 Soren S. Jorvang 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed for the 18 * NetBSD Project. See http://www.NetBSD.org/ for 19 * information about NetBSD. 20 * 4. The name of the author may not be used to endorse or promote products 21 * derived from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 #include <sys/cdefs.h> 36 __KERNEL_RCSID(0, "$NetBSD: gio.c,v 1.22 2006/08/30 23:48:55 rumble Exp $"); 37 38 #include "opt_ddb.h" 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/device.h> 43 44 #define _SGIMIPS_BUS_DMA_PRIVATE 45 #include <machine/bus.h> 46 #include <machine/machtype.h> 47 48 #include <sgimips/gio/gioreg.h> 49 #include <sgimips/gio/giovar.h> 50 #include <sgimips/gio/giodevs_data.h> 51 52 #include "locators.h" 53 #include "newport.h" 54 #include "grtwo.h" 55 #include "imc.h" 56 #include "pic.h" 57 58 #if (NNEWPORT > 0) 59 #include <sgimips/gio/newportvar.h> 60 #endif 61 62 #if (NGRTWO > 0) 63 #include <sgimips/gio/grtwovar.h> 64 #endif 65 66 #if (NIMC > 0) 67 extern int imc_gio64_arb_config(int, uint32_t); 68 #endif 69 70 #if (NPIC > 0) 71 extern int pic_gio32_arb_config(int, uint32_t); 72 #endif 73 74 75 struct gio_softc { 76 struct device sc_dev; 77 }; 78 79 static int gio_match(struct device *, struct cfdata *, void *); 80 static void gio_attach(struct device *, struct device *, void *); 81 static int gio_print(void *, const char *); 82 static int gio_search(struct device *, struct cfdata *, 83 const int *, void *); 84 static int gio_submatch(struct device *, struct cfdata *, 85 const int *, void *); 86 87 CFATTACH_DECL(gio, sizeof(struct gio_softc), 88 gio_match, gio_attach, NULL, NULL); 89 90 static uint32_t gio_slot_addr[] = { 91 0x1f400000, 92 0x1f600000, 93 0x1f000000, 94 0 95 }; 96 97 static int 98 gio_match(struct device *parent, struct cfdata *match, void *aux) 99 { 100 101 return 1; 102 } 103 104 static void 105 gio_attach(struct device *parent, struct device *self, void *aux) 106 { 107 struct gio_attach_args ga; 108 int i; 109 110 printf("\n"); 111 112 for (i=0; gio_slot_addr[i] != 0; i++) { 113 ga.ga_slot = (gio_slot_addr[i] == 0x1f000000) ? GIO_SLOT_GFX : 114 (gio_slot_addr[i] == 0x1f400000) ? GIO_SLOT_EXP0 : 115 GIO_SLOT_EXP1; 116 ga.ga_addr = gio_slot_addr[i]; 117 ga.ga_iot = 0; 118 ga.ga_ioh = MIPS_PHYS_TO_KSEG1(gio_slot_addr[i]); 119 ga.ga_dmat = &sgimips_default_bus_dma_tag; 120 121 #if 0 122 /* XXX */ 123 if (bus_space_peek_4(ga.ga_iot, ga.ga_ioh, 0, &ga.ga_product)) 124 continue; 125 #else 126 if (badaddr((void *)ga.ga_ioh,sizeof(uint32_t))) 127 continue; 128 129 ga.ga_product = bus_space_read_4(ga.ga_iot, ga.ga_ioh, 0); 130 #endif 131 132 config_found_sm_loc(self, "gio", NULL, &ga, gio_print, 133 gio_submatch); 134 } 135 136 config_search_ia(gio_search, self, "gio", &ga); 137 } 138 139 static int 140 gio_print(void *aux, const char *pnp) 141 { 142 struct gio_attach_args *ga = aux; 143 int i = 0; 144 145 if (pnp != NULL) { 146 int product, revision; 147 148 product = GIO_PRODUCT_PRODUCTID(ga->ga_product); 149 150 if (GIO_PRODUCT_32BIT_ID(ga->ga_product)) 151 revision = GIO_PRODUCT_REVISION(ga->ga_product); 152 else 153 revision = 0; 154 155 while (gio_knowndevs[i].productid != 0) { 156 if (gio_knowndevs[i].productid == product) { 157 aprint_normal("%s", gio_knowndevs[i].product); 158 break; 159 } 160 i++; 161 } 162 163 if (gio_knowndevs[i].productid == 0) 164 aprint_normal("unknown GIO card"); 165 166 aprint_normal(" (product 0x%02x revision 0x%02x) at %s", 167 product, revision, pnp); 168 } 169 170 if (ga->ga_slot != GIOCF_SLOT_DEFAULT) 171 aprint_normal(" slot %d", ga->ga_slot); 172 if (ga->ga_addr != (uint32_t) GIOCF_ADDR_DEFAULT) 173 aprint_normal(" addr 0x%x", ga->ga_addr); 174 175 return UNCONF; 176 } 177 178 static int 179 gio_search(struct device *parent, struct cfdata *cf, 180 const int *ldesc, void *aux) 181 { 182 struct gio_attach_args *ga = aux; 183 184 do { 185 /* Handled by direct configuration, so skip here */ 186 if (cf->cf_loc[GIOCF_ADDR] == GIOCF_ADDR_DEFAULT) 187 return 0; 188 189 ga->ga_slot = cf->cf_loc[GIOCF_SLOT]; 190 ga->ga_addr = cf->cf_loc[GIOCF_ADDR]; 191 ga->ga_iot = 0; 192 ga->ga_ioh = MIPS_PHYS_TO_KSEG1(ga->ga_addr); 193 194 if (config_match(parent, cf, ga) > 0) 195 config_attach(parent, cf, ga, gio_print); 196 } while (cf->cf_fstate == FSTATE_STAR); 197 198 return 0; 199 } 200 201 static int 202 gio_submatch(struct device *parent, struct cfdata *cf, 203 const int *ldesc, void *aux) 204 { 205 struct gio_attach_args *ga = aux; 206 207 if (cf->cf_loc[GIOCF_SLOT] != GIOCF_SLOT_DEFAULT && 208 cf->cf_loc[GIOCF_SLOT] != ga->ga_slot) 209 return 0; 210 211 if (cf->cf_loc[GIOCF_ADDR] != GIOCF_ADDR_DEFAULT && 212 cf->cf_loc[GIOCF_ADDR] != ga->ga_addr) 213 return 0; 214 215 return config_match(parent, cf, aux); 216 } 217 218 int 219 gio_cnattach() 220 { 221 struct gio_attach_args ga; 222 int i; 223 224 /* XXX Duplicate code XXX */ 225 for (i=0; gio_slot_addr[i] != 0; i++) { 226 ga.ga_slot = i; 227 ga.ga_addr = gio_slot_addr[i]; 228 ga.ga_iot = 0; 229 ga.ga_ioh = MIPS_PHYS_TO_KSEG1(gio_slot_addr[i]); 230 231 #if 0 232 /* XXX */ 233 if (bus_space_peek_4(ga.ga_iot, ga.ga_ioh, 0, &ga.ga_product)) 234 continue; 235 #else 236 237 if (badaddr((void *)ga.ga_ioh,sizeof(uint32_t))) 238 continue; 239 240 ga.ga_product = bus_space_read_4(ga.ga_iot, ga.ga_ioh, 0); 241 #endif 242 243 #if (NGRTWO > 0) 244 if (grtwo_cnattach(&ga) == 0) 245 return 0; 246 #endif 247 248 /* XXX This probably attaches console to the wrong newport on 249 * dualhead Indys, as GFX slot is tried last not first */ 250 #if (NNEWPORT > 0) 251 if (newport_cnattach(&ga) == 0) 252 return 0; 253 #endif 254 255 } 256 257 return ENXIO; 258 } 259 260 /* 261 * Devices living in the expansion slots must enable or disable some 262 * GIO arbiter settings. This is accomplished via imc(4) or pic(4) 263 * registers, depending on the machine in question. 264 */ 265 int 266 gio_arb_config(int slot, uint32_t flags) 267 { 268 269 if (flags == 0) 270 return (EINVAL); 271 272 if (flags & ~(GIO_ARB_RT | GIO_ARB_LB | GIO_ARB_MST | GIO_ARB_SLV | 273 GIO_ARB_PIPE | GIO_ARB_NOPIPE)) 274 return (EINVAL); 275 276 if (((flags & GIO_ARB_RT) && (flags & GIO_ARB_LB)) || 277 ((flags & GIO_ARB_MST) && (flags & GIO_ARB_SLV)) || 278 ((flags & GIO_ARB_PIPE) && (flags & GIO_ARB_NOPIPE))) 279 return (EINVAL); 280 281 #if (NPIC > 0) 282 if (mach_type == MACH_SGI_IP12) 283 return (pic_gio32_arb_config(slot, flags)); 284 #endif 285 286 #if (NIMC > 0) 287 if (mach_type == MACH_SGI_IP20 || mach_type == MACH_SGI_IP22) 288 return (imc_gio64_arb_config(slot, flags)); 289 #endif 290 291 return (EINVAL); 292 } 293 294 /* 295 * Establish an interrupt handler for the specified slot. 296 */ 297 void * 298 gio_intr_establish(int slot, int level, int (*func)(void *), void *arg) 299 { 300 int intr; 301 302 switch (mach_type) { 303 case MACH_SGI_IP12: 304 case MACH_SGI_IP20: 305 if (slot == GIO_SLOT_GFX) 306 panic("gio_intr_establish: slot %d", slot); 307 intr = (slot == GIO_SLOT_EXP0) ? 0 : 6; 308 break; 309 310 case MACH_SGI_IP22: 311 if (mach_subtype == MACH_SGI_IP22_FULLHOUSE) { 312 if (slot == GIO_SLOT_EXP1) 313 panic("gio_intr_establish: slot %d", slot); 314 intr = (slot == GIO_SLOT_EXP0) ? 0 : 6; 315 } else { 316 if (slot == GIO_SLOT_GFX) 317 panic("gio_intr_establish: slot %d", slot); 318 intr = (slot == GIO_SLOT_EXP0) ? 22 : 23; 319 } 320 break; 321 322 default: 323 panic("gio_intr_establish: mach_type"); 324 } 325 326 return (cpu_intr_establish(intr, level, func, arg)); 327 } 328 329 const char * 330 gio_product_string(int prid) 331 { 332 int i; 333 334 for (i = 0; gio_knowndevs[i].product != NULL; i++) 335 if (gio_knowndevs[i].productid == prid) 336 return (gio_knowndevs[i].product); 337 338 return (NULL); 339 } 340