fhc.c revision 111134
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 * $FreeBSD: head/sys/sparc64/fhc/fhc.c 111134 2003-02-19 17:25:58Z jake $ 27 */ 28 29#include <sys/param.h> 30#include <sys/systm.h> 31#include <sys/bus.h> 32#include <sys/kernel.h> 33#include <sys/malloc.h> 34#include <sys/pcpu.h> 35 36#include <dev/ofw/openfirm.h> 37 38#include <machine/bus.h> 39#include <machine/bus_common.h> 40#include <machine/resource.h> 41 42#include <sys/rman.h> 43 44#include <sparc64/fhc/fhcreg.h> 45#include <sparc64/fhc/fhcvar.h> 46#include <sparc64/sbus/ofw_sbus.h> 47 48#define INTIGN(map) (((map) & INTMAP_IGN_MASK) >> INTMAP_IGN_SHIFT) 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_name; 60 char *fdi_type; 61 phandle_t fdi_node; 62 struct resource_list fdi_rl; 63}; 64 65static void fhc_intr_stub(void *); 66 67int 68fhc_probe(device_t dev) 69{ 70 71 return (0); 72} 73 74int 75fhc_attach(device_t dev) 76{ 77 struct fhc_devinfo *fdi; 78 struct sbus_regs *reg; 79 struct fhc_softc *sc; 80 phandle_t child; 81 phandle_t node; 82 bus_addr_t size; 83 bus_addr_t off; 84 device_t cdev; 85 uint32_t ctrl; 86 char *name; 87 int nreg; 88 int i; 89 90 sc = device_get_softc(dev); 91 node = sc->sc_node; 92 93 for (i = FHC_FANFAIL; i <= FHC_TOD; i++) { 94 bus_space_write_4(sc->sc_bt[i], sc->sc_bh[i], FHC_ICLR, 0x0); 95 bus_space_read_4(sc->sc_bt[i], sc->sc_bh[i], FHC_ICLR); 96 } 97 98 sc->sc_ign = sc->sc_board << 1; 99 bus_space_write_4(sc->sc_bt[FHC_IGN], sc->sc_bh[FHC_IGN], 0x0, 100 sc->sc_ign); 101 sc->sc_ign = bus_space_read_4(sc->sc_bt[FHC_IGN], 102 sc->sc_bh[FHC_IGN], 0x0); 103 104 ctrl = bus_space_read_4(sc->sc_bt[FHC_INTERNAL], 105 sc->sc_bh[FHC_INTERNAL], FHC_CTRL); 106 if ((sc->sc_flags & FHC_CENTRAL) == 0) 107 ctrl |= FHC_CTRL_IXIST; 108 ctrl &= ~(FHC_CTRL_AOFF | FHC_CTRL_BOFF | FHC_CTRL_SLINE); 109 bus_space_write_4(sc->sc_bt[FHC_INTERNAL], sc->sc_bh[FHC_INTERNAL], 110 FHC_CTRL, ctrl); 111 ctrl = bus_space_read_4(sc->sc_bt[FHC_INTERNAL], 112 sc->sc_bh[FHC_INTERNAL], FHC_CTRL); 113 114 sc->sc_nrange = OF_getprop_alloc(node, "ranges", 115 sizeof(*sc->sc_ranges), (void **)&sc->sc_ranges); 116 if (sc->sc_nrange == -1) { 117 device_printf(dev, "can't get ranges"); 118 return (ENXIO); 119 } 120 121 for (child = OF_child(node); child != 0; child = OF_peer(child)) { 122 if ((OF_getprop_alloc(child, "name", 1, (void **)&name)) == -1) 123 continue; 124 cdev = device_add_child(dev, NULL, -1); 125 if (cdev != NULL) { 126 fdi = malloc(sizeof(*fdi), M_DEVBUF, 127 M_WAITOK | M_ZERO); 128 fdi->fdi_name = name; 129 fdi->fdi_node = child; 130 OF_getprop_alloc(child, "device_type", 1, 131 (void **)&fdi->fdi_type); 132 resource_list_init(&fdi->fdi_rl); 133 nreg = OF_getprop_alloc(child, "reg", sizeof(*reg), 134 (void **)®); 135 if (nreg != -1) { 136 for (i = 0; i < nreg; i++) { 137 off = reg[i].sbr_offset; 138 size = reg[i].sbr_size; 139 resource_list_add(&fdi->fdi_rl, 140 SYS_RES_MEMORY, i, off, off + size, 141 size); 142 } 143 free(reg, M_OFWPROP); 144 } 145 device_set_ivars(cdev, fdi); 146 } else 147 free(name, M_OFWPROP); 148 } 149 150 return (bus_generic_attach(dev)); 151} 152 153int 154fhc_print_child(device_t dev, device_t child) 155{ 156 struct fhc_devinfo *fdi; 157 int rv; 158 159 fdi = device_get_ivars(child); 160 rv = bus_print_child_header(dev, child); 161 rv += resource_list_print_type(&fdi->fdi_rl, "mem", 162 SYS_RES_MEMORY, "%#lx"); 163 rv += bus_print_child_footer(dev, child); 164 return (rv); 165} 166 167void 168fhc_probe_nomatch(device_t dev, device_t child) 169{ 170 struct fhc_devinfo *fdi; 171 172 fdi = device_get_ivars(child); 173 device_printf(dev, "<%s>", fdi->fdi_name); 174 resource_list_print_type(&fdi->fdi_rl, "mem", SYS_RES_MEMORY, "%#lx"); 175 printf(" type %s (no driver attached)\n", 176 fdi->fdi_type != NULL ? fdi->fdi_type : "unknown"); 177} 178 179int 180fhc_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 181{ 182 struct fhc_devinfo *fdi; 183 184 if ((fdi = device_get_ivars(child)) == 0) 185 return (ENOENT); 186 switch (which) { 187 case FHC_IVAR_NAME: 188 *result = (uintptr_t)fdi->fdi_name; 189 break; 190 case FHC_IVAR_NODE: 191 *result = fdi->fdi_node; 192 break; 193 case FHC_IVAR_TYPE: 194 *result = (uintptr_t)fdi->fdi_type; 195 break; 196 default: 197 return (ENOENT); 198 } 199 return (0); 200} 201 202int 203fhc_write_ivar(device_t dev, device_t child, int which, uintptr_t value) 204{ 205 struct fhc_devinfo *fdi; 206 207 if ((fdi = device_get_ivars(child)) == 0) 208 return (ENOENT); 209 switch (which) { 210 case FHC_IVAR_NAME: 211 case FHC_IVAR_NODE: 212 case FHC_IVAR_TYPE: 213 return (EINVAL); 214 default: 215 return (ENOENT); 216 } 217 return (0); 218} 219 220int 221fhc_setup_intr(device_t bus, device_t child, struct resource *r, int flags, 222 driver_intr_t *func, void *arg, void **cookiep) 223{ 224 struct fhc_softc *sc; 225 struct fhc_clr *fc; 226 int error; 227 int rid; 228 229 sc = device_get_softc(bus); 230 rid = rman_get_rid(r); 231 232 fc = malloc(sizeof(*fc), M_DEVBUF, M_ZERO); 233 fc->fc_func = func; 234 fc->fc_arg = arg; 235 fc->fc_bt = sc->sc_bt[rid]; 236 fc->fc_bh = sc->sc_bh[rid]; 237 238 bus_space_write_4(sc->sc_bt[rid], sc->sc_bh[rid], FHC_IMAP, 239 r->r_start); 240 bus_space_read_4(sc->sc_bt[rid], sc->sc_bh[rid], FHC_IMAP); 241 242 error = bus_generic_setup_intr(bus, child, r, flags, fhc_intr_stub, 243 fc, cookiep); 244 if (error != 0) { 245 free(fc, M_DEVBUF); 246 return (error); 247 } 248 fc->fc_cookie = *cookiep; 249 *cookiep = fc; 250 251 bus_space_write_4(sc->sc_bt[rid], sc->sc_bh[rid], FHC_ICLR, 0x0); 252 bus_space_write_4(sc->sc_bt[rid], sc->sc_bh[rid], FHC_IMAP, 253 INTMAP_ENABLE(r->r_start, PCPU_GET(mid))); 254 bus_space_read_4(sc->sc_bt[rid], sc->sc_bh[rid], FHC_IMAP); 255 256 return (error); 257} 258 259int 260fhc_teardown_intr(device_t bus, device_t child, struct resource *r, 261 void *cookie) 262{ 263 struct fhc_clr *fc; 264 int error; 265 266 fc = cookie; 267 error = bus_generic_teardown_intr(bus, child, r, fc->fc_cookie); 268 if (error != 0) 269 free(fc, M_DEVBUF); 270 return (error); 271} 272 273static void 274fhc_intr_stub(void *arg) 275{ 276 struct fhc_clr *fc = arg; 277 278 fc->fc_func(fc->fc_arg); 279 280 bus_space_write_4(fc->fc_bt, fc->fc_bh, FHC_ICLR, 0x0); 281 bus_space_read_4(fc->fc_bt, fc->fc_bh, FHC_ICLR); 282} 283 284struct resource * 285fhc_alloc_resource(device_t bus, device_t child, int type, int *rid, 286 u_long start, u_long end, u_long count, u_int flags) 287{ 288 struct resource_list_entry *rle; 289 struct fhc_devinfo *fdi; 290 struct fhc_softc *sc; 291 struct resource *res; 292 bus_addr_t coffset; 293 bus_addr_t cend; 294 bus_addr_t phys; 295 int isdefault; 296 uint32_t map; 297 uint32_t vec; 298 int i; 299 300 isdefault = (start == 0UL && end == ~0UL); 301 res = NULL; 302 sc = device_get_softc(bus); 303 switch (type) { 304 case SYS_RES_IRQ: 305 if (!isdefault || count != 1 || *rid < FHC_FANFAIL || 306 *rid > FHC_TOD) 307 break; 308 309 map = bus_space_read_4(sc->sc_bt[*rid], sc->sc_bh[*rid], 310 FHC_IMAP); 311 vec = INTINO(map) | (sc->sc_ign << INTMAP_IGN_SHIFT); 312 bus_space_write_4(sc->sc_bt[*rid], sc->sc_bh[*rid], 313 FHC_IMAP, vec); 314 bus_space_read_4(sc->sc_bt[*rid], sc->sc_bh[*rid], FHC_IMAP); 315 316 res = bus_generic_alloc_resource(bus, child, type, rid, 317 vec, vec, 1, flags); 318 if (res != NULL) 319 rman_set_rid(res, *rid); 320 break; 321 case SYS_RES_MEMORY: 322 fdi = device_get_ivars(child); 323 rle = resource_list_find(&fdi->fdi_rl, type, *rid); 324 if (rle == NULL) 325 return (NULL); 326 if (rle->res != NULL) 327 panic("fhc_alloc_resource: resource entry is busy"); 328 if (isdefault) { 329 start = rle->start; 330 count = ulmax(count, rle->count); 331 end = ulmax(rle->end, start + count - 1); 332 } 333 for (i = 0; i < sc->sc_nrange; i++) { 334 coffset = sc->sc_ranges[i].coffset; 335 cend = coffset + sc->sc_ranges[i].size - 1; 336 if (start >= coffset && end <= cend) { 337 start -= coffset; 338 end -= coffset; 339 phys = sc->sc_ranges[i].poffset | 340 ((bus_addr_t)sc->sc_ranges[i].pspace << 32); 341 res = bus_generic_alloc_resource(bus, child, 342 type, rid, phys + start, phys + end, 343 count, flags); 344 rle->res = res; 345 break; 346 } 347 } 348 break; 349 default: 350 break; 351 } 352 return (res); 353} 354 355int 356fhc_release_resource(device_t bus, device_t child, int type, int rid, 357 struct resource *r) 358{ 359 struct resource_list_entry *rle; 360 struct fhc_devinfo *fdi; 361 int error; 362 363 error = bus_generic_release_resource(bus, child, type, rid, r); 364 if (error != 0) 365 return (error); 366 fdi = device_get_ivars(child); 367 rle = resource_list_find(&fdi->fdi_rl, type, rid); 368 if (rle == NULL) 369 panic("fhc_release_resource: can't find resource"); 370 if (rle->res == NULL) 371 panic("fhc_release_resource: resource entry is not busy"); 372 rle->res = NULL; 373 return (error); 374} 375