fhc.c revision 143129
1/*- 2 * Copyright (c) 2003 Jake Burkholder. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: head/sys/sparc64/fhc/fhc.c 143129 2005-03-04 16:01:57Z marius $"); 29 30#include <sys/param.h> 31#include <sys/systm.h> 32#include <sys/bus.h> 33#include <sys/kernel.h> 34#include <sys/malloc.h> 35#include <sys/pcpu.h> 36 37#include <dev/ofw/ofw_bus.h> 38#include <dev/ofw/openfirm.h> 39 40#include <machine/bus.h> 41#include <machine/bus_common.h> 42#include <machine/resource.h> 43 44#include <sys/rman.h> 45 46#include <sparc64/fhc/fhcreg.h> 47#include <sparc64/fhc/fhcvar.h> 48#include <sparc64/sbus/ofw_sbus.h> 49 50struct fhc_clr { 51 driver_intr_t *fc_func; 52 void *fc_arg; 53 void *fc_cookie; 54 bus_space_tag_t fc_bt; 55 bus_space_handle_t fc_bh; 56}; 57 58struct fhc_devinfo { 59 char *fdi_compat; 60 char *fdi_model; 61 char *fdi_name; 62 char *fdi_type; 63 phandle_t fdi_node; 64 struct resource_list fdi_rl; 65}; 66 67static void fhc_intr_stub(void *); 68 69int 70fhc_probe(device_t dev) 71{ 72 73 return (0); 74} 75 76int 77fhc_attach(device_t dev) 78{ 79 struct fhc_devinfo *fdi; 80 struct sbus_regs *reg; 81 struct fhc_softc *sc; 82 phandle_t child; 83 phandle_t node; 84 bus_addr_t size; 85 bus_addr_t off; 86 device_t cdev; 87 uint32_t ctrl; 88 char *name; 89 int nreg; 90 int i; 91 92 sc = device_get_softc(dev); 93 node = sc->sc_node; 94 95 if (OF_getprop_alloc(node, "board-model", 1, (void **)&name) != -1) { 96 device_printf(dev, "board %d, %s\n", sc->sc_board, name); 97 free(name, M_OFWPROP); 98 } 99 100 for (i = FHC_FANFAIL; i <= FHC_TOD; i++) { 101 bus_space_write_4(sc->sc_bt[i], sc->sc_bh[i], FHC_ICLR, 0x0); 102 bus_space_read_4(sc->sc_bt[i], sc->sc_bh[i], FHC_ICLR); 103 } 104 105 sc->sc_ign = sc->sc_board << 1; 106 bus_space_write_4(sc->sc_bt[FHC_IGN], sc->sc_bh[FHC_IGN], 0x0, 107 sc->sc_ign); 108 sc->sc_ign = bus_space_read_4(sc->sc_bt[FHC_IGN], 109 sc->sc_bh[FHC_IGN], 0x0); 110 111 ctrl = bus_space_read_4(sc->sc_bt[FHC_INTERNAL], 112 sc->sc_bh[FHC_INTERNAL], FHC_CTRL); 113 if ((sc->sc_flags & FHC_CENTRAL) == 0) 114 ctrl |= FHC_CTRL_IXIST; 115 ctrl &= ~(FHC_CTRL_AOFF | FHC_CTRL_BOFF | FHC_CTRL_SLINE); 116 bus_space_write_4(sc->sc_bt[FHC_INTERNAL], sc->sc_bh[FHC_INTERNAL], 117 FHC_CTRL, ctrl); 118 ctrl = bus_space_read_4(sc->sc_bt[FHC_INTERNAL], 119 sc->sc_bh[FHC_INTERNAL], FHC_CTRL); 120 121 sc->sc_nrange = OF_getprop_alloc(node, "ranges", 122 sizeof(*sc->sc_ranges), (void **)&sc->sc_ranges); 123 if (sc->sc_nrange == -1) { 124 device_printf(dev, "can't get ranges\n"); 125 return (ENXIO); 126 } 127 128 for (child = OF_child(node); child != 0; child = OF_peer(child)) { 129 if ((OF_getprop_alloc(child, "name", 1, (void **)&name)) == -1) 130 continue; 131 cdev = device_add_child(dev, NULL, -1); 132 if (cdev != NULL) { 133 fdi = malloc(sizeof(*fdi), M_DEVBUF, M_WAITOK | M_ZERO); 134 if (fdi == NULL) 135 continue; 136 fdi->fdi_name = name; 137 fdi->fdi_node = child; 138 OF_getprop_alloc(child, "compatible", 1, 139 (void **)&fdi->fdi_compat); 140 OF_getprop_alloc(child, "device_type", 1, 141 (void **)&fdi->fdi_type); 142 OF_getprop_alloc(child, "model", 1, 143 (void **)&fdi->fdi_model); 144 resource_list_init(&fdi->fdi_rl); 145 nreg = OF_getprop_alloc(child, "reg", sizeof(*reg), 146 (void **)®); 147 if (nreg != -1) { 148 for (i = 0; i < nreg; i++) { 149 off = reg[i].sbr_offset; 150 size = reg[i].sbr_size; 151 resource_list_add(&fdi->fdi_rl, 152 SYS_RES_MEMORY, i, off, off + size, 153 size); 154 } 155 free(reg, M_OFWPROP); 156 } 157 device_set_ivars(cdev, fdi); 158 } else 159 free(name, M_OFWPROP); 160 } 161 162 return (bus_generic_attach(dev)); 163} 164 165int 166fhc_print_child(device_t dev, device_t child) 167{ 168 struct fhc_devinfo *fdi; 169 int rv; 170 171 fdi = device_get_ivars(child); 172 rv = bus_print_child_header(dev, child); 173 rv += resource_list_print_type(&fdi->fdi_rl, "mem", 174 SYS_RES_MEMORY, "%#lx"); 175 rv += bus_print_child_footer(dev, child); 176 return (rv); 177} 178 179void 180fhc_probe_nomatch(device_t dev, device_t child) 181{ 182 struct fhc_devinfo *fdi; 183 184 fdi = device_get_ivars(child); 185 device_printf(dev, "<%s>", fdi->fdi_name); 186 resource_list_print_type(&fdi->fdi_rl, "mem", SYS_RES_MEMORY, "%#lx"); 187 printf(" type %s (no driver attached)\n", 188 fdi->fdi_type != NULL ? fdi->fdi_type : "unknown"); 189} 190 191int 192fhc_setup_intr(device_t bus, device_t child, struct resource *r, int flags, 193 driver_intr_t *func, void *arg, void **cookiep) 194{ 195 struct fhc_softc *sc; 196 struct fhc_clr *fc; 197 int error; 198 int rid; 199 200 sc = device_get_softc(bus); 201 rid = rman_get_rid(r); 202 203 fc = malloc(sizeof(*fc), M_DEVBUF, M_WAITOK | M_ZERO); 204 if (fc == NULL) 205 return (0); 206 fc->fc_func = func; 207 fc->fc_arg = arg; 208 fc->fc_bt = sc->sc_bt[rid]; 209 fc->fc_bh = sc->sc_bh[rid]; 210 211 bus_space_write_4(sc->sc_bt[rid], sc->sc_bh[rid], FHC_IMAP, 212 rman_get_start(r)); 213 bus_space_read_4(sc->sc_bt[rid], sc->sc_bh[rid], FHC_IMAP); 214 215 error = bus_generic_setup_intr(bus, child, r, flags, fhc_intr_stub, 216 fc, cookiep); 217 if (error != 0) { 218 free(fc, M_DEVBUF); 219 return (error); 220 } 221 fc->fc_cookie = *cookiep; 222 *cookiep = fc; 223 224 bus_space_write_4(sc->sc_bt[rid], sc->sc_bh[rid], FHC_ICLR, 0x0); 225 bus_space_write_4(sc->sc_bt[rid], sc->sc_bh[rid], FHC_IMAP, 226 INTMAP_ENABLE(rman_get_start(r), PCPU_GET(mid))); 227 bus_space_read_4(sc->sc_bt[rid], sc->sc_bh[rid], FHC_IMAP); 228 229 return (error); 230} 231 232int 233fhc_teardown_intr(device_t bus, device_t child, struct resource *r, 234 void *cookie) 235{ 236 struct fhc_clr *fc; 237 int error; 238 239 fc = cookie; 240 error = bus_generic_teardown_intr(bus, child, r, fc->fc_cookie); 241 if (error != 0) 242 free(fc, M_DEVBUF); 243 return (error); 244} 245 246static void 247fhc_intr_stub(void *arg) 248{ 249 struct fhc_clr *fc = arg; 250 251 fc->fc_func(fc->fc_arg); 252 253 bus_space_write_4(fc->fc_bt, fc->fc_bh, FHC_ICLR, 0x0); 254 bus_space_read_4(fc->fc_bt, fc->fc_bh, FHC_ICLR); 255} 256 257struct resource * 258fhc_alloc_resource(device_t bus, device_t child, int type, int *rid, 259 u_long start, u_long end, u_long count, u_int flags) 260{ 261 struct resource_list_entry *rle; 262 struct fhc_devinfo *fdi; 263 struct fhc_softc *sc; 264 struct resource *res; 265 bus_addr_t coffset; 266 bus_addr_t cend; 267 bus_addr_t phys; 268 int isdefault; 269 uint32_t map; 270 uint32_t vec; 271 int i; 272 273 isdefault = (start == 0UL && end == ~0UL); 274 res = NULL; 275 sc = device_get_softc(bus); 276 switch (type) { 277 case SYS_RES_IRQ: 278 if (!isdefault || count != 1 || *rid < FHC_FANFAIL || 279 *rid > FHC_TOD) 280 break; 281 282 map = bus_space_read_4(sc->sc_bt[*rid], sc->sc_bh[*rid], 283 FHC_IMAP); 284 vec = INTINO(map) | (sc->sc_ign << INTMAP_IGN_SHIFT); 285 bus_space_write_4(sc->sc_bt[*rid], sc->sc_bh[*rid], 286 FHC_IMAP, vec); 287 bus_space_read_4(sc->sc_bt[*rid], sc->sc_bh[*rid], FHC_IMAP); 288 289 res = bus_generic_alloc_resource(bus, child, type, rid, 290 vec, vec, 1, flags); 291 if (res != NULL) 292 rman_set_rid(res, *rid); 293 break; 294 case SYS_RES_MEMORY: 295 fdi = device_get_ivars(child); 296 rle = resource_list_find(&fdi->fdi_rl, type, *rid); 297 if (rle == NULL) 298 return (NULL); 299 if (rle->res != NULL) 300 panic("%s: resource entry is busy", __func__); 301 if (isdefault) { 302 start = rle->start; 303 count = ulmax(count, rle->count); 304 end = ulmax(rle->end, start + count - 1); 305 } 306 for (i = 0; i < sc->sc_nrange; i++) { 307 coffset = sc->sc_ranges[i].coffset; 308 cend = coffset + sc->sc_ranges[i].size - 1; 309 if (start >= coffset && end <= cend) { 310 start -= coffset; 311 end -= coffset; 312 phys = sc->sc_ranges[i].poffset | 313 ((bus_addr_t)sc->sc_ranges[i].pspace << 32); 314 res = bus_generic_alloc_resource(bus, child, 315 type, rid, phys + start, phys + end, 316 count, flags); 317 rle->res = res; 318 break; 319 } 320 } 321 break; 322 default: 323 break; 324 } 325 return (res); 326} 327 328int 329fhc_release_resource(device_t bus, device_t child, int type, int rid, 330 struct resource *r) 331{ 332 struct resource_list_entry *rle; 333 struct fhc_devinfo *fdi; 334 int error; 335 336 error = bus_generic_release_resource(bus, child, type, rid, r); 337 if (type != SYS_RES_MEMORY || error != 0) 338 return (error); 339 fdi = device_get_ivars(child); 340 rle = resource_list_find(&fdi->fdi_rl, type, rid); 341 if (rle == NULL) 342 panic("%s: can't find resource", __func__); 343 if (rle->res == NULL) 344 panic("%s: resource entry is not busy", __func__); 345 rle->res = NULL; 346 return (error); 347} 348 349const char * 350fhc_get_compat(device_t bus, device_t dev) 351{ 352 struct fhc_devinfo *dinfo; 353 354 dinfo = device_get_ivars(dev); 355 return (dinfo->fdi_compat); 356} 357 358const char * 359fhc_get_model(device_t bus, device_t dev) 360{ 361 struct fhc_devinfo *dinfo; 362 363 dinfo = device_get_ivars(dev); 364 return (dinfo->fdi_model); 365} 366 367const char * 368fhc_get_name(device_t bus, device_t dev) 369{ 370 struct fhc_devinfo *dinfo; 371 372 dinfo = device_get_ivars(dev); 373 return (dinfo->fdi_name); 374} 375 376phandle_t 377fhc_get_node(device_t bus, device_t dev) 378{ 379 struct fhc_devinfo *dinfo; 380 381 dinfo = device_get_ivars(dev); 382 return (dinfo->fdi_node); 383} 384 385const char * 386fhc_get_type(device_t bus, device_t dev) 387{ 388 struct fhc_devinfo *dinfo; 389 390 dinfo = device_get_ivars(dev); 391 return (dinfo->fdi_type); 392} 393