/* * Attach all the sub-devices we can find */ void obio_attach(device_t parent, device_t self, void *aux) { struct obio_softc *sc = device_private(self); struct pci_attach_args *pa = aux; struct confargs ca; bus_space_handle_t bsh; int node, child, namelen, error; u_int reg[20]; int intr[6], parent_intr = 0, parent_nintr = 0; int map_size = 0x1000; char name[32]; char compat[32]; sc->sc_dev = self; #ifdef OBIO_SPEED_CONTROL sc->sc_voltage = -1; sc->sc_busspeed = -1; sc->sc_spd_lo = 600; sc->sc_spd_hi = 800; #endif switch (PCI_PRODUCT(pa->pa_id)) { case PCI_PRODUCT_APPLE_GC: case PCI_PRODUCT_APPLE_OHARE: case PCI_PRODUCT_APPLE_HEATHROW: case PCI_PRODUCT_APPLE_PADDINGTON: case PCI_PRODUCT_APPLE_KEYLARGO: case PCI_PRODUCT_APPLE_PANGEA_MACIO: case PCI_PRODUCT_APPLE_INTREPID: node = pcidev_to_ofdev(pa->pa_pc, pa->pa_tag); if (node == -1) node = OF_finddevice("mac-io"); if (node == -1) node = OF_finddevice("/pci/mac-io"); break; case PCI_PRODUCT_APPLE_K2: case PCI_PRODUCT_APPLE_SHASTA: node = OF_finddevice("mac-io"); map_size = 0x10000; break; default: node = -1; break; } if (node == -1) panic("macio not found or unknown"); sc->sc_node = node; #if defined (PMAC_G5) if (OF_getprop(node, "assigned-addresses", reg, sizeof(reg)) < 20) { return; } #else if (OF_getprop(node, "assigned-addresses", reg, sizeof(reg)) < 12) return; #endif /* PMAC_G5 */ /* * XXX * This relies on the primary obio always attaching first which is * true on the PowerBook 3400c and similar machines but may or may * not work on others. We can't rely on the node name since Apple * didn't follow anything remotely resembling a consistent naming * scheme. */ if (obio0 == NULL) obio0 = sc; ca.ca_baseaddr = reg[2]; ca.ca_tag = pa->pa_memt; sc->sc_tag = pa->pa_memt; error = bus_space_map (pa->pa_memt, ca.ca_baseaddr, map_size, 0, &bsh); if (error) panic(": failed to map mac-io %#x", ca.ca_baseaddr); sc->sc_bh = bsh; printf(": addr 0x%x\n", ca.ca_baseaddr); /* Enable internal modem (KeyLargo) */ if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_KEYLARGO) { aprint_normal("%s: enabling KeyLargo internal modem\n", device_xname(self)); bus_space_write_4(ca.ca_tag, bsh, 0x40, bus_space_read_4(ca.ca_tag, bsh, 0x40) & ~(1<<25)); } /* Enable internal modem (Pangea) */ if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_PANGEA_MACIO) { /* set reset */ bus_space_write_1(ca.ca_tag, bsh, 0x006a + 0x03, 0x04); /* power modem on */ bus_space_write_1(ca.ca_tag, bsh, 0x006a + 0x02, 0x04); /* unset reset */ bus_space_write_1(ca.ca_tag, bsh, 0x006a + 0x03, 0x05); } /* Gatwick and Paddington use same product ID */ namelen = OF_getprop(node, "compatible", compat, sizeof(compat)); if (strcmp(compat, "gatwick") == 0) { parent_nintr = OF_getprop(node, "AAPL,interrupts", intr, sizeof(intr)); parent_intr = intr[0]; } else { /* Enable CD and microphone sound input. */ if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_PADDINGTON) bus_space_write_1(ca.ca_tag, bsh, 0x37, 0x03); } for (child = OF_child(node); child; child = OF_peer(child)) { namelen = OF_getprop(child, "name", name, sizeof(name)); if (namelen < 0) continue; if (namelen >= sizeof(name)) continue; #ifdef OBIO_SPEED_CONTROL if (strcmp(name, "gpio") == 0) { obio_setup_gpios(sc, child); continue; } #endif name[namelen] = 0; ca.ca_name = name; ca.ca_node = child; ca.ca_tag = pa->pa_memt; ca.ca_nreg = OF_getprop(child, "reg", reg, sizeof(reg)); if (strcmp(compat, "gatwick") != 0) { ca.ca_nintr = OF_getprop(child, "AAPL,interrupts", intr, sizeof(intr)); if (ca.ca_nintr == -1) ca.ca_nintr = OF_getprop(child, "interrupts", intr, sizeof(intr)); } else { intr[0] = parent_intr; ca.ca_nintr = parent_nintr; } ca.ca_reg = reg; ca.ca_intr = intr; config_found(self, &ca, obio_print); } }
static int dma_attach(device_t dev) { struct dma_softc *dsc; struct lsi64854_softc *lsc; struct dma_devinfo *ddi; device_t cdev; const char *name; char *cabletype; uint32_t csr; phandle_t child, node; int error, i; dsc = device_get_softc(dev); lsc = &dsc->sc_lsi64854; name = ofw_bus_get_name(dev); node = ofw_bus_get_node(dev); dsc->sc_ign = sbus_get_ign(dev); dsc->sc_slot = sbus_get_slot(dev); i = 0; lsc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &i, RF_ACTIVE); if (lsc->sc_res == NULL) { device_printf(dev, "cannot allocate resources\n"); return (ENXIO); } if (strcmp(name, "espdma") == 0 || strcmp(name, "dma") == 0) lsc->sc_channel = L64854_CHANNEL_SCSI; else if (strcmp(name, "ledma") == 0) { /* * Check to see which cable type is currently active and * set the appropriate bit in the ledma csr so that it * gets used. If we didn't netboot, the PROM won't have * the "cable-selection" property; default to TP and then * the user can change it via a "media" option to ifconfig. */ csr = L64854_GCSR(lsc); if ((OF_getprop_alloc(node, "cable-selection", 1, (void **)&cabletype)) == -1) { /* assume TP if nothing there */ csr |= E_TP_AUI; } else { if (strcmp(cabletype, "aui") == 0) csr &= ~E_TP_AUI; else csr |= E_TP_AUI; free(cabletype, M_OFWPROP); } L64854_SCSR(lsc, csr); DELAY(20000); /* manual says we need a 20ms delay */ lsc->sc_channel = L64854_CHANNEL_ENET; } else { device_printf(dev, "unsupported DMA channel\n"); error = ENXIO; goto fail_lres; } error = bus_dma_tag_create( bus_get_dma_tag(dev), /* parent */ 1, 0, /* alignment, boundary */ BUS_SPACE_MAXADDR, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ BUS_SPACE_MAXSIZE, /* maxsize */ BUS_SPACE_UNRESTRICTED, /* nsegments */ BUS_SPACE_MAXSIZE, /* maxsegsize */ 0, /* flags */ NULL, NULL, /* no locking */ &lsc->sc_parent_dmat); if (error != 0) { device_printf(dev, "cannot allocate parent DMA tag\n"); goto fail_lres; } i = sbus_get_burstsz(dev); lsc->sc_burst = (i & SBUS_BURST_32) ? 32 : (i & SBUS_BURST_16) ? 16 : 0; lsc->sc_dev = dev; /* Attach children. */ i = 0; for (child = OF_child(node); child != 0; child = OF_peer(child)) { if ((ddi = dma_setup_dinfo(dev, dsc, child)) == NULL) continue; if (i != 0) { device_printf(dev, "<%s>: only one child per DMA channel supported\n", ddi->ddi_obdinfo.obd_name); dma_destroy_dinfo(ddi); continue; } if ((cdev = device_add_child(dev, NULL, -1)) == NULL) { device_printf(dev, "<%s>: device_add_child failed\n", ddi->ddi_obdinfo.obd_name); dma_destroy_dinfo(ddi); continue; } device_set_ivars(cdev, ddi); i++; } return (bus_generic_attach(dev)); fail_lres: bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(lsc->sc_res), lsc->sc_res); return (error); }
/* * Walk the PCI bus hierarchy, starting with the root PCI bus and descending * through bridges, and initialize the interrupt line and latency timer * configuration registers of attached devices using firmware information, * as well as the the bus numbers and ranges of the bridges. */ void ofw_pci_init(device_t dev, phandle_t bushdl, u_int32_t ign, struct ofw_pci_bdesc *obd) { struct ofw_pci_register pcir; struct ofw_pci_bdesc subobd, *tobd; phandle_t node; char type[32]; int i, intr, freemap; u_int slot, busno, func, sub, lat; /* Initialize the quirk list. */ for (i = 0; i < OPQ_NENT; i++) { if (strcmp(sparc64_model, ofw_pci_quirks[i].opq_model) == 0) { pci_quirks = ofw_pci_quirks[i].opq_quirks; break; } } if ((node = OF_child(bushdl)) == 0) return; freemap = 0; busno = obd->obd_secbus; do { if (node == -1) panic("ofw_pci_init_intr: OF_child failed"); if (OF_getprop(node, "device_type", type, sizeof(type)) == -1) type[0] = '\0'; else type[sizeof(type) - 1] = '\0'; if (OF_getprop(node, "reg", &pcir, sizeof(pcir)) == -1) panic("ofw_pci_init: OF_getprop failed"); slot = OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi); func = OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi); if (strcmp(type, OFW_PCI_PCIBUS) == 0) { /* * This is a pci-pci bridge, initalize the bus number and * recurse to initialize the child bus. The hierarchy is * usually at most 2 levels deep, so recursion is * feasible. */ subobd.obd_bus = busno; subobd.obd_slot = slot; subobd.obd_func = func; sub = ofw_pci_alloc_busno(node); subobd.obd_secbus = subobd.obd_subbus = sub; /* Assume this bridge is mostly standard conforming. */ subobd.obd_init = ofw_pci_binit; subobd.obd_super = obd; /* * Need to change all subordinate bus registers of the * bridges above this one now so that configuration * transactions will get through. */ for (tobd = obd; tobd != NULL; tobd = tobd->obd_super) { tobd->obd_subbus = sub; tobd->obd_init(dev, tobd); } subobd.obd_init(dev, &subobd); #ifdef OFW_PCI_DEBUG device_printf(dev, "%s: descending to " "subordinate PCI bus\n", __func__); #endif /* OFW_PCI_DEBUG */ ofw_pci_init(dev, node, ign, &subobd); } else { /* * Initialize the latency timer register for * busmaster devices to work properly. This is another * task which the firmware does not always perform. * The Min_Gnt register can be used to compute it's * recommended value: it contains the desired latency * in units of 1/4 us. To calculate the correct latency * timer value, a bus clock of 33 and no wait states * should be assumed. */ lat = PCIB_READ_CONFIG(dev, busno, slot, func, PCIR_MINGNT, 1) * 33 / 4; if (lat != 0) { #ifdef OFW_PCI_DEBUG printf("device %d/%d/%d: latency timer %d -> " "%d\n", busno, slot, func, PCIB_READ_CONFIG(dev, busno, slot, func, PCIR_LATTIMER, 1), lat); #endif /* OFW_PCI_DEBUG */ PCIB_WRITE_CONFIG(dev, busno, slot, func, PCIR_LATTIMER, imin(lat, 255), 1); } /* Initialize the intline registers. */ if ((intr = ofw_pci_route_intr(node, ign)) != 255) { #ifdef OFW_PCI_DEBUG device_printf(dev, "%s: mapping intr for " "%d/%d/%d to %d (preset was %d)\n", __func__, busno, slot, func, intr, (int)PCIB_READ_CONFIG(dev, busno, slot, func, PCIR_INTLINE, 1)); #endif /* OFW_PCI_DEBUG */ PCIB_WRITE_CONFIG(dev, busno, slot, func, PCIR_INTLINE, intr, 1); } else { #ifdef OFW_PCI_DEBUG device_printf(dev, "%s: no interrupt " "mapping found for %d/%d/%d (preset %d)\n", __func__, busno, slot, func, (int)PCIB_READ_CONFIG(dev, busno, slot, func, PCIR_INTLINE, 1)); #endif /* OFW_PCI_DEBUG */ /* * The firmware initializes to 0 instead of * 255. */ PCIB_WRITE_CONFIG(dev, busno, slot, func, PCIR_INTLINE, 255, 1); } } } while ((node = OF_peer(node)) != 0); }
void xlights_attach(struct device *parent, struct device *self, void *aux) { struct xlights_softc *sc = (struct xlights_softc *)self; struct confargs *ca = aux; int nseg, error, intr[6]; u_int32_t reg[4]; int type; sc->sc_node = OF_child(ca->ca_node); OF_getprop(sc->sc_node, "reg", reg, sizeof(reg)); ca->ca_reg[0] += ca->ca_baseaddr; ca->ca_reg[2] += ca->ca_baseaddr; if ((sc->sc_reg = mapiodev(ca->ca_reg[0], ca->ca_reg[1])) == NULL) { printf(": cannot map registers\n"); return; } sc->sc_dmat = ca->ca_dmat; if ((sc->sc_dma = mapiodev(ca->ca_reg[2], ca->ca_reg[3])) == NULL) { printf(": cannot map DMA registers\n"); goto nodma; } if ((sc->sc_dbdma = dbdma_alloc(sc->sc_dmat, BL_DBDMA_CMDS)) == NULL) { printf(": cannot alloc DMA descriptors\n"); goto nodbdma; } sc->sc_dmacmd = sc->sc_dbdma->d_addr; if ((error = bus_dmamem_alloc(sc->sc_dmat, BL_BUFSZ, 0, 0, sc->sc_bufseg, 1, &nseg, BUS_DMA_NOWAIT))) { printf(": cannot allocate DMA mem (%d)\n", error); goto nodmamem; } if ((error = bus_dmamem_map(sc->sc_dmat, sc->sc_bufseg, nseg, BL_BUFSZ, (caddr_t *)&sc->sc_buf, BUS_DMA_NOWAIT))) { printf(": cannot map DMA mem (%d)\n", error); goto nodmamap; } sc->sc_bufpos = sc->sc_buf; if ((error = bus_dmamap_create(sc->sc_dmat, BL_BUFSZ, 1, BL_BUFSZ, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &sc->sc_bufmap))) { printf(": cannot create DMA map (%d)\n", error); goto nodmacreate; } if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_bufmap, sc->sc_buf, BL_BUFSZ, NULL, BUS_DMA_NOWAIT))) { printf(": cannot load DMA map (%d)\n", error); goto nodmaload; } /* XXX: Should probably extract this from the clock data * property of the soundchip node */ sc->sc_freq = 16384; OF_getprop(sc->sc_node, "interrupts", intr, sizeof(intr)); /* output interrupt */ sc->sc_intr = intr[2]; type = intr[3] ? IST_LEVEL : IST_EDGE; printf(": irq %d\n", sc->sc_intr); macobio_enable(I2SClockOffset, I2S0EN); out32rb(sc->sc_reg + I2S_INT, I2S_INT_CLKSTOPPEND); macobio_disable(I2SClockOffset, I2S0CLKEN); for (error = 0; error < 1000; error++) { if (in32rb(sc->sc_reg + I2S_INT) & I2S_INT_CLKSTOPPEND) { error = 0; break; } delay(1); } if (error) { printf("%s: i2s timeout\n", sc->sc_dev.dv_xname); goto nodmaload; } mac_intr_establish(parent, sc->sc_intr, intr[3] ? IST_LEVEL : type, IPL_AUDIO, xlights_intr, sc, sc->sc_dev.dv_xname); out32rb(sc->sc_reg + I2S_FORMAT, CLKSRC_VS); macobio_enable(I2SClockOffset, I2S0CLKEN); kthread_create_deferred(xlights_deferred, sc); timeout_set(&sc->sc_tmo, xlights_timeout, sc); return; nodmaload: bus_dmamap_destroy(sc->sc_dmat, sc->sc_bufmap); nodmacreate: bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_buf, BL_BUFSZ); nodmamap: bus_dmamem_free(sc->sc_dmat, sc->sc_bufseg, nseg); nodmamem: dbdma_free(sc->sc_dbdma); nodbdma: unmapiodev((void *)sc->sc_dma, ca->ca_reg[3]); nodma: unmapiodev(sc->sc_reg, ca->ca_reg[1]); }
static int ofw_iicbus_attach(device_t dev) { struct iicbus_softc *sc = IICBUS_SOFTC(dev); struct ofw_iicbus_devinfo *dinfo; phandle_t child, node, root; pcell_t freq, paddr; device_t childdev; ssize_t compatlen; char compat[255]; char *curstr; u_int iic_addr_8bit = 0; sc->dev = dev; mtx_init(&sc->lock, "iicbus", NULL, MTX_DEF); /* * If there is a clock-frequency property for the device node, use it as * the starting value for the bus frequency. Then call the common * routine that handles the tunable/sysctl which allows the FDT value to * be overridden by the user. */ node = ofw_bus_get_node(dev); freq = 0; OF_getencprop(node, "clock-frequency", &freq, sizeof(freq)); iicbus_init_frequency(dev, freq); iicbus_reset(dev, IIC_FASTEST, 0, NULL); bus_generic_probe(dev); bus_enumerate_hinted_children(dev); /* * Check if we're running on a PowerMac, needed for the I2C * address below. */ root = OF_peer(0); compatlen = OF_getprop(root, "compatible", compat, sizeof(compat)); if (compatlen != -1) { for (curstr = compat; curstr < compat + compatlen; curstr += strlen(curstr) + 1) { if (strncmp(curstr, "MacRISC", 7) == 0) iic_addr_8bit = 1; } } /* * Attach those children represented in the device tree. */ for (child = OF_child(node); child != 0; child = OF_peer(child)) { /* * Try to get the I2C address first from the i2c-address * property, then try the reg property. It moves around * on different systems. */ if (OF_getencprop(child, "i2c-address", &paddr, sizeof(paddr)) == -1) if (OF_getencprop(child, "reg", &paddr, sizeof(paddr)) == -1) continue; /* * Now set up the I2C and OFW bus layer devinfo and add it * to the bus. */ dinfo = malloc(sizeof(struct ofw_iicbus_devinfo), M_DEVBUF, M_NOWAIT | M_ZERO); if (dinfo == NULL) continue; /* * FreeBSD drivers expect I2C addresses to be expressed as * 8-bit values. Apple OFW data contains 8-bit values, but * Linux FDT data contains 7-bit values, so shift them up to * 8-bit format. */ if (iic_addr_8bit) dinfo->opd_dinfo.addr = paddr; else dinfo->opd_dinfo.addr = paddr << 1; if (ofw_bus_gen_setup_devinfo(&dinfo->opd_obdinfo, child) != 0) { free(dinfo, M_DEVBUF); continue; } childdev = device_add_child(dev, NULL, -1); resource_list_init(&dinfo->opd_dinfo.rl); ofw_bus_intr_to_rl(childdev, child, &dinfo->opd_dinfo.rl, NULL); device_set_ivars(childdev, dinfo); } /* Register bus */ OF_device_register_xref(OF_xref_from_node(node), dev); return (bus_generic_attach(dev)); }
static void isa_setup_children(device_t dev, phandle_t parent) { struct isa_regs *regs; struct resource_list *rl; device_t cdev; u_int64_t end, start; ofw_isa_intr_t *intrs, rintr; phandle_t node; uint32_t *drqs, *regidx; int i, ndrq, nintr, nreg, nregidx, rid, rtype; char *name; /* * Loop through children and fake up PnP devices for them. * Their resources are added as fully mapped and specified because * adjusting the resources and the resource list entries respectively * in isa_alloc_resource() causes trouble with drivers which use * rman_get_start(), pass-through or allocate and release resources * multiple times, etc. Adjusting the resources might be better off * in a bus_activate_resource method but the common ISA code doesn't * allow for an isa_activate_resource(). */ for (node = OF_child(parent); node != 0; node = OF_peer(node)) { if ((OF_getprop_alloc(node, "name", 1, (void **)&name)) == -1) continue; /* * Keyboard and mouse controllers hang off of the `8042' * node but we have no real use for the `8042' itself. */ if (strcmp(name, "8042") == 0) { isa_setup_children(dev, node); free(name, M_OFWPROP); continue; } for (i = 0; ofw_isa_pnp_map[i].name != NULL; i++) if (strcmp(ofw_isa_pnp_map[i].name, name) == 0) break; if (ofw_isa_pnp_map[i].name == NULL) { device_printf(dev, "no PnP map entry for node " "0x%lx: %s\n", (unsigned long)node, name); free(name, M_OFWPROP); continue; } if ((cdev = BUS_ADD_CHILD(dev, ISA_ORDER_PNPBIOS, NULL, -1)) == NULL) panic("isa_setup_children: BUS_ADD_CHILD failed"); isa_set_logicalid(cdev, ofw_isa_pnp_map[i].id); isa_set_vendorid(cdev, ofw_isa_pnp_map[i].id); rl = BUS_GET_RESOURCE_LIST(dev, cdev); nreg = OF_getprop_alloc(node, "reg", sizeof(*regs), (void **)®s); for (i = 0; i < nreg; i++) { start = ISA_REG_PHYS(®s[i]); end = start + regs[i].size - 1; rtype = ofw_isa_range_map(isab_ranges, isab_nrange, &start, &end, NULL); rid = 0; while (resource_list_find(rl, rtype, rid) != NULL) rid++; bus_set_resource(cdev, rtype, rid, start, end - start + 1); } if (nreg == -1 && parent != isab_node) { /* * The "reg" property still might be an index into * the set of registers of the parent device like * with the nodes hanging off of the `8042' node. */ nregidx = OF_getprop_alloc(node, "reg", sizeof(*regidx), (void **)®idx); if (nregidx > 2) panic("isa_setup_children: impossible number " "of register indices"); if (nregidx != -1 && (nreg = OF_getprop_alloc(parent, "reg", sizeof(*regs), (void **)®s)) >= nregidx) { for (i = 0; i < nregidx; i++) { start = ISA_REG_PHYS(®s[regidx[i]]); end = start + regs[regidx[i]].size - 1; rtype = ofw_isa_range_map(isab_ranges, isab_nrange, &start, &end, NULL); rid = 0; while (resource_list_find(rl, rtype, rid) != NULL) rid++; bus_set_resource(cdev, rtype, rid, start, end - start + 1); } } if (regidx != NULL) free(regidx, M_OFWPROP); } if (regs != NULL) free(regs, M_OFWPROP); nintr = OF_getprop_alloc(node, "interrupts", sizeof(*intrs), (void **)&intrs); for (i = 0; i < nintr; i++) { if (intrs[i] > 7) panic("isa_setup_children: intr too large"); rintr = ofw_isa_route_intr(device_get_parent(dev), node, &isa_iinfo, intrs[i]); if (rintr == PCI_INVALID_IRQ) { device_printf(dev, "could not map ISA " "interrupt %d for node 0x%lx: %s\n", intrs[i], (unsigned long)node, name); continue; } bus_set_resource(cdev, SYS_RES_IRQ, i, rintr, 1); } if (intrs != NULL) free(intrs, M_OFWPROP); ndrq = OF_getprop_alloc(node, "dma-channel", sizeof(*drqs), (void **)&drqs); for (i = 0; i < ndrq; i++) bus_set_resource(cdev, SYS_RES_DRQ, i, drqs[i], 1); if (drqs != NULL) free(drqs, M_OFWPROP); /* * Devices using DMA hang off of the `dma' node instead of * directly from the ISA bridge node. */ if (strcmp(name, "dma") == 0) isa_setup_children(dev, node); free(name, M_OFWPROP); } }
static int simplebus_attach(device_t dev) { device_t dev_child; struct simplebus_devinfo *di; struct simplebus_softc *sc; phandle_t dt_node, dt_child; sc = device_get_softc(dev); /* * Walk simple-bus and add direct subordinates as our children. */ dt_node = ofw_bus_get_node(dev); for (dt_child = OF_child(dt_node); dt_child != 0; dt_child = OF_peer(dt_child)) { /* Check and process 'status' property. */ if (!(fdt_is_enabled(dt_child))) continue; if (!(fdt_pm_is_enabled(dt_child))) continue; di = malloc(sizeof(*di), M_SIMPLEBUS, M_WAITOK | M_ZERO); if (ofw_bus_gen_setup_devinfo(&di->di_ofw, dt_child) != 0) { free(di, M_SIMPLEBUS); device_printf(dev, "could not set up devinfo\n"); continue; } resource_list_init(&di->di_res); if (fdt_reg_to_rl(dt_child, &di->di_res)) { device_printf(dev, "%s: could not process 'reg' " "property\n", di->di_ofw.obd_name); ofw_bus_gen_destroy_devinfo(&di->di_ofw); free(di, M_SIMPLEBUS); continue; } if (fdt_intr_to_rl(dt_child, &di->di_res, di->di_intr_sl)) { device_printf(dev, "%s: could not process " "'interrupts' property\n", di->di_ofw.obd_name); resource_list_free(&di->di_res); ofw_bus_gen_destroy_devinfo(&di->di_ofw); free(di, M_SIMPLEBUS); continue; } /* Add newbus device for this FDT node */ dev_child = device_add_child(dev, NULL, -1); if (dev_child == NULL) { device_printf(dev, "could not add child: %s\n", di->di_ofw.obd_name); resource_list_free(&di->di_res); ofw_bus_gen_destroy_devinfo(&di->di_ofw); free(di, M_SIMPLEBUS); continue; } #ifdef DEBUG device_printf(dev, "added child: %s\n\n", di->di_ofw.obd_name); #endif device_set_ivars(dev_child, di); } return (bus_generic_attach(dev)); }
static int kiic_attach(device_t self) { struct kiic_softc *sc = device_get_softc(self); int rid, rate; phandle_t node; char name[64]; bzero(sc, sizeof(*sc)); sc->sc_dev = self; node = ofw_bus_get_node(self); if (node == 0 || node == -1) { return (EINVAL); } rid = 0; sc->sc_reg = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->sc_reg == NULL) { return (ENOMEM); } if (OF_getencprop(node, "AAPL,i2c-rate", &rate, 4) != 4) { device_printf(self, "cannot get i2c-rate\n"); return (ENXIO); } if (OF_getencprop(node, "AAPL,address-step", &sc->sc_regstep, 4) != 4) { device_printf(self, "unable to find i2c address step\n"); return (ENXIO); } /* * Some Keywest I2C devices have their children attached directly * underneath them. Some have a single 'iicbus' child with the * devices underneath that. Sort this out, and make sure that the * OFW I2C layer has the correct node. * * Note: the I2C children of the Uninorth bridges have two ports. * In general, the port is designated in the 9th bit of the I2C * address. However, for kiic devices with children attached below * an i2c-bus node, the port is indicated in the 'reg' property * of the i2c-bus node. */ sc->sc_node = node; node = OF_child(node); if (OF_getprop(node, "name", name, sizeof(name)) > 0) { if (strcmp(name,"i2c-bus") == 0) { phandle_t reg; if (OF_getprop(node, "reg", ®, sizeof(reg)) > 0) sc->sc_i2c_base = reg << 8; sc->sc_node = node; } } mtx_init(&sc->sc_mutex, "kiic", NULL, MTX_DEF); sc->sc_irq = bus_alloc_resource_any(self, SYS_RES_IRQ, &sc->sc_irqrid, RF_ACTIVE); bus_setup_intr(self, sc->sc_irq, INTR_TYPE_MISC | INTR_MPSAFE, NULL, kiic_intr, sc, &sc->sc_ih); kiic_writereg(sc, ISR, kiic_readreg(sc, ISR)); kiic_writereg(sc, STATUS, 0); kiic_writereg(sc, IER, 0); kiic_setmode(sc, I2C_STDMODE); kiic_setspeed(sc, I2C_100kHz); /* XXX rate */ kiic_writereg(sc, IER, I2C_INT_DATA | I2C_INT_ADDR | I2C_INT_STOP); if (bootverbose) device_printf(self, "Revision: %02X\n", kiic_readreg(sc, REV)); /* Add the IIC bus layer */ sc->sc_iicbus = device_add_child(self, "iicbus", -1); return (bus_generic_attach(self)); }
/* * PCI attach: scan Open Firmware child nodes, and attach these as children * of the macio bus */ static int macio_attach(device_t dev) { struct macio_softc *sc; struct macio_devinfo *dinfo; phandle_t root; phandle_t child; phandle_t subchild; device_t cdev; u_int reg[3]; int error, quirks; sc = device_get_softc(dev); root = sc->sc_node = ofw_bus_get_node(dev); /* * Locate the device node and it's base address */ if (OF_getprop(root, "assigned-addresses", reg, sizeof(reg)) < sizeof(reg)) { return (ENXIO); } sc->sc_base = reg[2]; sc->sc_size = MACIO_REG_SIZE; sc->sc_mem_rman.rm_type = RMAN_ARRAY; sc->sc_mem_rman.rm_descr = "MacIO Device Memory"; error = rman_init(&sc->sc_mem_rman); if (error) { device_printf(dev, "rman_init() failed. error = %d\n", error); return (error); } error = rman_manage_region(&sc->sc_mem_rman, 0, sc->sc_size); if (error) { device_printf(dev, "rman_manage_region() failed. error = %d\n", error); return (error); } /* * Iterate through the sub-devices */ for (child = OF_child(root); child != 0; child = OF_peer(child)) { dinfo = malloc(sizeof(*dinfo), M_MACIO, M_WAITOK | M_ZERO); if (ofw_bus_gen_setup_devinfo(&dinfo->mdi_obdinfo, child) != 0) { free(dinfo, M_MACIO); continue; } quirks = macio_get_quirks(dinfo->mdi_obdinfo.obd_name); if ((quirks & MACIO_QUIRK_IGNORE) != 0) { ofw_bus_gen_destroy_devinfo(&dinfo->mdi_obdinfo); free(dinfo, M_MACIO); continue; } resource_list_init(&dinfo->mdi_resources); dinfo->mdi_ninterrupts = 0; macio_add_intr(child, dinfo); if ((quirks & MACIO_QUIRK_USE_CHILD_REG) != 0) macio_add_reg(OF_child(child), dinfo); else macio_add_reg(child, dinfo); if ((quirks & MACIO_QUIRK_CHILD_HAS_INTR) != 0) for (subchild = OF_child(child); subchild != 0; subchild = OF_peer(subchild)) macio_add_intr(subchild, dinfo); cdev = device_add_child(dev, NULL, -1); if (cdev == NULL) { device_printf(dev, "<%s>: device_add_child failed\n", dinfo->mdi_obdinfo.obd_name); resource_list_free(&dinfo->mdi_resources); ofw_bus_gen_destroy_devinfo(&dinfo->mdi_obdinfo); free(dinfo, M_MACIO); continue; } device_set_ivars(cdev, dinfo); } return (bus_generic_attach(dev)); }
int openfirmioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l) { struct ofiocdesc *of; int node, len, ok, error, s; char *name, *value; if (cmd == OFIOCGETOPTNODE) { s = splhigh(); *(int *) data = OF_finddevice("/options"); splx(s); return (0); } /* Verify node id */ of = (struct ofiocdesc *)data; node = of->of_nodeid; if (node != 0 && node != lastnode) { /* Not an easy one, must search for it */ s = splhigh(); ok = openfirmcheckid(OF_peer(0), node); splx(s); if (!ok) return (EINVAL); lastnode = node; } name = value = NULL; error = 0; switch (cmd) { case OFIOCGET: if ((flags & FREAD) == 0) return (EBADF); if (node == 0) return (EINVAL); error = openfirmgetstr(of->of_namelen, of->of_name, &name); if (error) break; s = splhigh(); len = OF_getproplen(node, name); splx(s); if (len > of->of_buflen) { error = ENOMEM; break; } of->of_buflen = len; /* -1 means no entry; 0 means no value */ if (len <= 0) break; value = malloc(len, M_TEMP, M_WAITOK); if (value == NULL) { error = ENOMEM; break; } s = splhigh(); len = OF_getprop(node, name, (void *)value, len); splx(s); error = copyout(value, of->of_buf, len); break; case OFIOCSET: if ((flags & FWRITE) == 0) return (EBADF); if (node == 0) return (EINVAL); error = openfirmgetstr(of->of_namelen, of->of_name, &name); if (error) break; error = openfirmgetstr(of->of_buflen, of->of_buf, &value); if (error) break; s = splhigh(); len = OF_setprop(node, name, value, of->of_buflen + 1); splx(s); /* * XXX * some OF implementations return the buffer length including * the trailing zero ( like macppc ) and some without ( like * FirmWorks OF used in Shark ) */ if ((len != (of->of_buflen + 1)) && (len != of->of_buflen)) error = EINVAL; break; case OFIOCNEXTPROP: { char newname[32]; if ((flags & FREAD) == 0) return (EBADF); if (node == 0) return (EINVAL); if (of->of_namelen != 0) { error = openfirmgetstr(of->of_namelen, of->of_name, &name); if (error) break; } s = splhigh(); ok = OF_nextprop(node, name, newname); splx(s); if (ok == 0) { error = ENOENT; break; } if (ok == -1) { error = EINVAL; break; } len = strlen(newname); if (len > of->of_buflen) len = of->of_buflen; else of->of_buflen = len; error = copyout(newname, of->of_buf, len); break; } case OFIOCGETNEXT: if ((flags & FREAD) == 0) return (EBADF); s = splhigh(); node = OF_peer(node); splx(s); *(int *)data = lastnode = node; break; case OFIOCGETCHILD: if ((flags & FREAD) == 0) return (EBADF); if (node == 0) return (EINVAL); s = splhigh(); node = OF_child(node); splx(s); *(int *)data = lastnode = node; break; case OFIOCFINDDEVICE: if ((flags & FREAD) == 0) return (EBADF); error = openfirmgetstr(of->of_namelen, of->of_name, &name); if (error) break; node = OF_finddevice(name); if (node == 0 || node == -1) { error = ENOENT; break; } of->of_nodeid = lastnode = node; break; default: return (ENOTTY); } if (name) free(name, M_TEMP); if (value) free(value, M_TEMP); return (error); }
static int sbus_attach(device_t dev) { struct sbus_softc *sc; struct sbus_devinfo *sdi; struct sbus_icarg *sica; struct sbus_ranges *range; struct resource *res; struct resource_list *rl; device_t cdev; bus_addr_t intrclr, intrmap, phys; bus_size_t size; u_long vec; phandle_t child, node; uint32_t prop; int i, j; sc = device_get_softc(dev); sc->sc_dev = dev; node = ofw_bus_get_node(dev); i = 0; sc->sc_sysio_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &i, RF_ACTIVE); if (sc->sc_sysio_res == NULL) panic("%s: cannot allocate device memory", __func__); if (OF_getprop(node, "interrupts", &prop, sizeof(prop)) == -1) panic("%s: cannot get IGN", __func__); sc->sc_ign = INTIGN(prop); sc->sc_cbustag = sbus_alloc_bustag(sc); /* * Record clock frequency for synchronous SCSI. * IS THIS THE CORRECT DEFAULT?? */ if (OF_getprop(node, "clock-frequency", &prop, sizeof(prop)) == -1) prop = 25000000; sc->sc_clockfreq = prop; prop /= 1000; device_printf(dev, "clock %d.%03d MHz\n", prop / 1000, prop % 1000); /* * Collect address translations from the OBP. */ if ((sc->sc_nrange = OF_getprop_alloc(node, "ranges", sizeof(*range), (void **)&range)) == -1) { panic("%s: error getting ranges property", __func__); } sc->sc_rd = (struct sbus_rd *)malloc(sizeof(*sc->sc_rd) * sc->sc_nrange, M_DEVBUF, M_NOWAIT); if (sc->sc_rd == NULL) panic("%s: cannot allocate rmans", __func__); /* * Preallocate all space that the SBus bridge decodes, so that nothing * else gets in the way; set up rmans etc. */ rl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev); for (i = 0; i < sc->sc_nrange; i++) { phys = range[i].poffset | ((bus_addr_t)range[i].pspace << 32); size = range[i].size; sc->sc_rd[i].rd_slot = range[i].cspace; sc->sc_rd[i].rd_coffset = range[i].coffset; sc->sc_rd[i].rd_cend = sc->sc_rd[i].rd_coffset + size; j = resource_list_add_next(rl, SYS_RES_MEMORY, phys, phys + size - 1, size); if ((res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &j, RF_ACTIVE)) == NULL) panic("%s: cannot allocate decoded range", __func__); sc->sc_rd[i].rd_bushandle = rman_get_bushandle(res); sc->sc_rd[i].rd_rman.rm_type = RMAN_ARRAY; sc->sc_rd[i].rd_rman.rm_descr = "SBus Device Memory"; if (rman_init(&sc->sc_rd[i].rd_rman) != 0 || rman_manage_region(&sc->sc_rd[i].rd_rman, 0, size) != 0) panic("%s: failed to set up memory rman", __func__); sc->sc_rd[i].rd_poffset = phys; sc->sc_rd[i].rd_pend = phys + size; sc->sc_rd[i].rd_res = res; } free(range, M_OFWPROP); /* * Get the SBus burst transfer size if burst transfers are supported. */ if (OF_getprop(node, "up-burst-sizes", &sc->sc_burst, sizeof(sc->sc_burst)) == -1 || sc->sc_burst == 0) sc->sc_burst = (SBUS_BURST64_DEF << SBUS_BURST64_SHIFT) | SBUS_BURST_DEF; /* initalise the IOMMU */ /* punch in our copies */ sc->sc_is.is_pmaxaddr = IOMMU_MAXADDR(SBUS_IOMMU_BITS); sc->sc_is.is_bustag = rman_get_bustag(sc->sc_sysio_res); sc->sc_is.is_bushandle = rman_get_bushandle(sc->sc_sysio_res); sc->sc_is.is_iommu = SBR_IOMMU; sc->sc_is.is_dtag = SBR_IOMMU_TLB_TAG_DIAG; sc->sc_is.is_ddram = SBR_IOMMU_TLB_DATA_DIAG; sc->sc_is.is_dqueue = SBR_IOMMU_QUEUE_DIAG; sc->sc_is.is_dva = SBR_IOMMU_SVADIAG; sc->sc_is.is_dtcmp = 0; sc->sc_is.is_sb[0] = SBR_STRBUF; sc->sc_is.is_sb[1] = 0; /* * Note: the SBus IOMMU ignores the high bits of an address, so a NULL * DMA pointer will be translated by the first page of the IOTSB. * To detect bugs we'll allocate and ignore the first entry. */ iommu_init(device_get_nameunit(dev), &sc->sc_is, 3, -1, 1); /* Create the DMA tag. */ if (bus_dma_tag_create(bus_get_dma_tag(dev), 8, 0, sc->sc_is.is_pmaxaddr, ~0, NULL, NULL, sc->sc_is.is_pmaxaddr, 0xff, 0xffffffff, 0, NULL, NULL, &sc->sc_cdmatag) != 0) panic("%s: bus_dma_tag_create failed", __func__); /* Customize the tag. */ sc->sc_cdmatag->dt_cookie = &sc->sc_is; sc->sc_cdmatag->dt_mt = &iommu_dma_methods; /* * Hunt through all the interrupt mapping regs and register our * interrupt controller for the corresponding interrupt vectors. * We do this early in order to be able to catch stray interrupts. */ for (i = 0; i <= SBUS_MAX_INO; i++) { if (sbus_find_intrmap(sc, i, &intrmap, &intrclr) == 0) continue; sica = malloc(sizeof(*sica), M_DEVBUF, M_NOWAIT); if (sica == NULL) panic("%s: could not allocate interrupt controller " "argument", __func__); sica->sica_sc = sc; sica->sica_map = intrmap; sica->sica_clr = intrclr; #ifdef SBUS_DEBUG device_printf(dev, "intr map (INO %d, %s) %#lx: %#lx, clr: %#lx\n", i, (i & INTMAP_OBIO_MASK) == 0 ? "SBus slot" : "OBIO", (u_long)intrmap, (u_long)SYSIO_READ8(sc, intrmap), (u_long)intrclr); #endif j = intr_controller_register(INTMAP_VEC(sc->sc_ign, i), &sbus_ic, sica); if (j != 0) device_printf(dev, "could not register interrupt " "controller for INO %d (%d)\n", i, j); } /* Enable the over-temperature and power-fail interrupts. */ i = 4; sc->sc_ot_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, &i, RF_ACTIVE); if (sc->sc_ot_ires == NULL || INTIGN(vec = rman_get_start(sc->sc_ot_ires)) != sc->sc_ign || INTVEC(SYSIO_READ8(sc, SBR_THERM_INT_MAP)) != vec || intr_vectors[vec].iv_ic != &sbus_ic || bus_setup_intr(dev, sc->sc_ot_ires, INTR_TYPE_MISC | INTR_FAST, NULL, sbus_overtemp, sc, &sc->sc_ot_ihand) != 0) panic("%s: failed to set up temperature interrupt", __func__); i = 3; sc->sc_pf_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, &i, RF_ACTIVE); if (sc->sc_pf_ires == NULL || INTIGN(vec = rman_get_start(sc->sc_pf_ires)) != sc->sc_ign || INTVEC(SYSIO_READ8(sc, SBR_POWER_INT_MAP)) != vec || intr_vectors[vec].iv_ic != &sbus_ic || bus_setup_intr(dev, sc->sc_pf_ires, INTR_TYPE_MISC | INTR_FAST, NULL, sbus_pwrfail, sc, &sc->sc_pf_ihand) != 0) panic("%s: failed to set up power fail interrupt", __func__); /* Initialize the counter-timer. */ sparc64_counter_init(device_get_nameunit(dev), rman_get_bustag(sc->sc_sysio_res), rman_get_bushandle(sc->sc_sysio_res), SBR_TC0); /* * Loop through ROM children, fixing any relative addresses * and then configuring each device. */ for (child = OF_child(node); child != 0; child = OF_peer(child)) { if ((sdi = sbus_setup_dinfo(dev, sc, child)) == NULL) continue; /* * For devices where there are variants that are actually * split into two SBus devices (as opposed to the first * half of the device being a SBus device and the second * half hanging off of the first one) like 'auxio' and * 'SUNW,fdtwo' or 'dma' and 'esp' probe the SBus device * which is a prerequisite to the driver attaching to the * second one with a lower order. Saves us from dealing * with different probe orders in the respective device * drivers which generally is more hackish. */ cdev = device_add_child_ordered(dev, (OF_child(child) == 0 && sbus_inlist(sdi->sdi_obdinfo.obd_name, sbus_order_first)) ? SBUS_ORDER_FIRST : SBUS_ORDER_NORMAL, NULL, -1); if (cdev == NULL) { device_printf(dev, "<%s>: device_add_child_ordered failed\n", sdi->sdi_obdinfo.obd_name); sbus_destroy_dinfo(sdi); continue; } device_set_ivars(cdev, sdi); } return (bus_generic_attach(dev)); }
void ht_attach(struct device *parent, struct device *self, void *aux) { struct ht_softc *sc = (struct ht_softc *)self; struct confargs *ca = aux; struct pcibus_attach_args pba; u_int32_t regs[6]; char compat[32]; int node, nn; int len; if (ca->ca_node == 0) { printf("invalid node on ht config\n"); return; } len = OF_getprop(ca->ca_node, "reg", regs, sizeof(regs)); if (len < sizeof(regs)) { printf(": regs lookup failed, node %x\n", ca->ca_node); return; } sc->sc_mem_bus_space.bus_base = 0x80000000; sc->sc_mem_bus_space.bus_size = 0; sc->sc_mem_bus_space.bus_io = 0; sc->sc_memt = &sc->sc_mem_bus_space; sc->sc_io_bus_space.bus_base = 0x80000000; sc->sc_io_bus_space.bus_size = 0; sc->sc_io_bus_space.bus_io = 1; sc->sc_iot = &sc->sc_io_bus_space; sc->sc_maxdevs = 1; for (node = OF_child(ca->ca_node); node; node = OF_peer(node)) sc->sc_maxdevs++; if (bus_space_map(sc->sc_memt, regs[1], (1 << DEVICE_SHIFT)*sc->sc_maxdevs, 0, &sc->sc_config0_memh)) { printf(": can't map PCI config0 memory\n"); return; } if (bus_space_map(sc->sc_memt, regs[1] + 0x01000000, 0x80000, 0, &sc->sc_config1_memh)) { printf(": can't map PCI config1 memory\n"); return; } if (bus_space_map(sc->sc_iot, regs[4], 0x1000, 0, &sc->sc_config0_ioh)) { printf(": can't map PCI config0 io\n"); return; } len = OF_getprop(ca->ca_node, "compatible", compat, sizeof(compat)); if (len <= 0) printf(": unknown"); else printf(": %s", compat); sc->sc_pc.pc_conf_v = sc; sc->sc_pc.pc_attach_hook = ht_attach_hook; sc->sc_pc.pc_bus_maxdevs = ht_bus_maxdevs; sc->sc_pc.pc_make_tag = ht_make_tag; sc->sc_pc.pc_decompose_tag = ht_decompose_tag; sc->sc_pc.pc_conf_read = ht_conf_read; sc->sc_pc.pc_conf_write = ht_conf_write; sc->sc_pc.pc_intr_v = sc; sc->sc_pc.pc_intr_map = ht_intr_map; sc->sc_pc.pc_intr_string = ht_intr_string; sc->sc_pc.pc_intr_line = ht_intr_line; sc->sc_pc.pc_intr_establish = ht_intr_establish; sc->sc_pc.pc_intr_disestablish = ht_intr_disestablish; sc->sc_pc.pc_ether_hw_addr = ht_ether_hw_addr; pba.pba_busname = "pci"; pba.pba_iot = sc->sc_iot; pba.pba_memt = sc->sc_memt; pba.pba_dmat = &pci_bus_dma_tag; pba.pba_pc = &sc->sc_pc; pba.pba_domain = pci_ndomains++; pba.pba_bus = 0; pba.pba_bridgetag = NULL; printf(": %d devices\n", sc->sc_maxdevs); extern void fix_node_irq(int, struct pcibus_attach_args *); for (node = OF_child(ca->ca_node); node; node = nn) { fix_node_irq(node, &pba); if ((nn = OF_child(node)) != 0) continue; while ((nn = OF_peer(node)) == 0) { node = OF_parent(node); if (node == ca->ca_node) { nn = 0; break; } } } config_found(self, &pba, ht_print); }
static int fdtbus_attach(device_t dev) { phandle_t root; phandle_t child; struct fdtbus_softc *sc; u_long start, end; int error; if ((root = OF_finddevice("/")) == -1) panic("fdtbus_attach: no root node."); sc = device_get_softc(dev); /* * IRQ rman. */ start = 0; end = FDT_INTR_MAX - 1; sc->sc_irq.rm_start = start; sc->sc_irq.rm_end = end; sc->sc_irq.rm_type = RMAN_ARRAY; sc->sc_irq.rm_descr = "Interrupt request lines"; if ((error = rman_init(&sc->sc_irq)) != 0) { device_printf(dev, "could not init IRQ rman, error = %d\n", error); return (error); } if ((error = rman_manage_region(&sc->sc_irq, start, end)) != 0) { device_printf(dev, "could not manage IRQ region, error = %d\n", error); return (error); } /* * Mem-mapped I/O space rman. */ start = 0; end = ~0ul; sc->sc_mem.rm_start = start; sc->sc_mem.rm_end = end; sc->sc_mem.rm_type = RMAN_ARRAY; sc->sc_mem.rm_descr = "I/O memory"; if ((error = rman_init(&sc->sc_mem)) != 0) { device_printf(dev, "could not init I/O mem rman, error = %d\n", error); return (error); } if ((error = rman_manage_region(&sc->sc_mem, start, end)) != 0) { device_printf(dev, "could not manage I/O mem region, " "error = %d\n", error); return (error); } /* * Walk the FDT root node and add top-level devices as our children. */ for (child = OF_child(root); child != 0; child = OF_peer(child)) { /* Check and process 'status' property. */ if (!(fdt_is_enabled(child))) continue; newbus_device_from_fdt_node(dev, child); } return (bus_generic_attach(dev)); }
/* * PCI attach: scan Open Firmware child nodes, and attach these as children * of the macio bus */ static int macio_attach(device_t dev) { struct macio_softc *sc; struct macio_devinfo *dinfo; phandle_t root; phandle_t child; phandle_t subchild; device_t cdev; u_int reg[3]; char compat[32]; int error, quirks; sc = device_get_softc(dev); root = sc->sc_node = ofw_bus_get_node(dev); /* * Locate the device node and it's base address */ if (OF_getprop(root, "assigned-addresses", reg, sizeof(reg)) < (ssize_t)sizeof(reg)) { return (ENXIO); } /* Used later to see if we have to enable the I2S part. */ OF_getprop(root, "compatible", compat, sizeof(compat)); sc->sc_base = reg[2]; sc->sc_size = MACIO_REG_SIZE; sc->sc_memrid = PCIR_BAR(0); sc->sc_memr = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_memrid, RF_ACTIVE); sc->sc_mem_rman.rm_type = RMAN_ARRAY; sc->sc_mem_rman.rm_descr = "MacIO Device Memory"; error = rman_init(&sc->sc_mem_rman); if (error) { device_printf(dev, "rman_init() failed. error = %d\n", error); return (error); } error = rman_manage_region(&sc->sc_mem_rman, 0, sc->sc_size); if (error) { device_printf(dev, "rman_manage_region() failed. error = %d\n", error); return (error); } /* * Iterate through the sub-devices */ for (child = OF_child(root); child != 0; child = OF_peer(child)) { dinfo = malloc(sizeof(*dinfo), M_MACIO, M_WAITOK | M_ZERO); if (ofw_bus_gen_setup_devinfo(&dinfo->mdi_obdinfo, child) != 0) { free(dinfo, M_MACIO); continue; } quirks = macio_get_quirks(dinfo->mdi_obdinfo.obd_name); if ((quirks & MACIO_QUIRK_IGNORE) != 0) { ofw_bus_gen_destroy_devinfo(&dinfo->mdi_obdinfo); free(dinfo, M_MACIO); continue; } resource_list_init(&dinfo->mdi_resources); dinfo->mdi_ninterrupts = 0; macio_add_intr(child, dinfo); if ((quirks & MACIO_QUIRK_USE_CHILD_REG) != 0) macio_add_reg(OF_child(child), dinfo); else macio_add_reg(child, dinfo); if ((quirks & MACIO_QUIRK_CHILD_HAS_INTR) != 0) for (subchild = OF_child(child); subchild != 0; subchild = OF_peer(subchild)) macio_add_intr(subchild, dinfo); cdev = device_add_child(dev, NULL, -1); if (cdev == NULL) { device_printf(dev, "<%s>: device_add_child failed\n", dinfo->mdi_obdinfo.obd_name); resource_list_free(&dinfo->mdi_resources); ofw_bus_gen_destroy_devinfo(&dinfo->mdi_obdinfo); free(dinfo, M_MACIO); continue; } device_set_ivars(cdev, dinfo); /* Set FCRs to enable some devices */ if (sc->sc_memr == NULL) continue; if (strcmp(ofw_bus_get_name(cdev), "bmac") == 0 || strcmp(ofw_bus_get_compat(cdev), "bmac+") == 0) { uint32_t fcr; fcr = bus_read_4(sc->sc_memr, HEATHROW_FCR); fcr |= FCR_ENET_ENABLE & ~FCR_ENET_RESET; bus_write_4(sc->sc_memr, HEATHROW_FCR, fcr); DELAY(50000); fcr |= FCR_ENET_RESET; bus_write_4(sc->sc_memr, HEATHROW_FCR, fcr); DELAY(50000); fcr &= ~FCR_ENET_RESET; bus_write_4(sc->sc_memr, HEATHROW_FCR, fcr); DELAY(50000); bus_write_4(sc->sc_memr, HEATHROW_FCR, fcr); } /* * Make sure the I2S0 and the I2S0_CLK are enabled. * On certain G5's they are not. */ if ((strcmp(ofw_bus_get_name(cdev), "i2s") == 0) && (strcmp(compat, "K2-Keylargo") == 0)) { uint32_t fcr1; fcr1 = bus_read_4(sc->sc_memr, KEYLARGO_FCR1); fcr1 |= FCR1_I2S0_CLK_ENABLE | FCR1_I2S0_ENABLE; bus_write_4(sc->sc_memr, KEYLARGO_FCR1, fcr1); } } return (bus_generic_attach(dev)); }
static void obio_setup_gpios(struct obio_softc *sc, int node) { uint32_t gpio_base, reg[6]; const struct sysctlnode *sysctl_node, *me, *freq; struct cpufreq *cf = &sc->sc_cf; char name[32]; int child, use_dfs, cpunode, hiclock; if (of_compatible(sc->sc_node, keylargo) == -1) return; if (OF_getprop(node, "reg", reg, sizeof(reg)) < 4) return; gpio_base = reg[0]; DPRINTF("gpio_base: %02x\n", gpio_base); /* now look for voltage and bus speed gpios */ use_dfs = 0; for (child = OF_child(node); child; child = OF_peer(child)) { if (OF_getprop(child, "name", name, sizeof(name)) < 1) continue; if (OF_getprop(child, "reg", reg, sizeof(reg)) < 4) continue; /* * These register offsets either have to be added to the obio * base address or to the gpio base address. This differs * even in the same OF-tree! So we guess the offset is * based on obio when it is larger than the gpio_base. */ if (reg[0] >= gpio_base) reg[0] -= gpio_base; if (strcmp(name, "frequency-gpio") == 0) { DPRINTF("found frequency_gpio at %02x\n", reg[0]); sc->sc_busspeed = gpio_base + reg[0]; } if (strcmp(name, "voltage-gpio") == 0) { DPRINTF("found voltage_gpio at %02x\n", reg[0]); sc->sc_voltage = gpio_base + reg[0]; } if (strcmp(name, "cpu-vcore-select") == 0) { DPRINTF("found cpu-vcore-select at %02x\n", reg[0]); sc->sc_voltage = gpio_base + reg[0]; /* frequency gpio is not needed, we use cpu's DFS */ use_dfs = 1; } } if ((sc->sc_voltage < 0) || (sc->sc_busspeed < 0 && !use_dfs)) return; printf("%s: enabling Intrepid CPU speed control\n", device_xname(sc->sc_dev)); sc->sc_spd_lo = curcpu()->ci_khz / 1000; hiclock = 0; cpunode = OF_finddevice("/cpus/@0"); OF_getprop(cpunode, "clock-frequency", &hiclock, 4); if (hiclock != 0) sc->sc_spd_hi = (hiclock + 500000) / 1000000; printf("hiclock: %d\n", sc->sc_spd_hi); sysctl_node = NULL; if (sysctl_createv(NULL, 0, NULL, &me, CTLFLAG_READWRITE, CTLTYPE_NODE, "intrepid", NULL, NULL, 0, NULL, 0, CTL_MACHDEP, CTL_CREATE, CTL_EOL) != 0) printf("couldn't create 'intrepid' node\n"); if (sysctl_createv(NULL, 0, NULL, &freq, CTLFLAG_READWRITE, CTLTYPE_NODE, "frequency", NULL, NULL, 0, NULL, 0, CTL_MACHDEP, me->sysctl_num, CTL_CREATE, CTL_EOL) != 0) printf("couldn't create 'frequency' node\n"); if (sysctl_createv(NULL, 0, NULL, &sysctl_node, CTLFLAG_READWRITE | CTLFLAG_OWNDESC, CTLTYPE_INT, "target", "CPU speed", sysctl_cpuspeed_temp, 0, (void *)sc, 0, CTL_MACHDEP, me->sysctl_num, freq->sysctl_num, CTL_CREATE, CTL_EOL) == 0) { } else printf("couldn't create 'target' node\n"); if (sysctl_createv(NULL, 0, NULL, &sysctl_node, CTLFLAG_READWRITE, CTLTYPE_INT, "current", NULL, sysctl_cpuspeed_cur, 1, (void *)sc, 0, CTL_MACHDEP, me->sysctl_num, freq->sysctl_num, CTL_CREATE, CTL_EOL) == 0) { } else printf("couldn't create 'current' node\n"); if (sysctl_createv(NULL, 0, NULL, &sysctl_node, CTLFLAG_READWRITE, CTLTYPE_STRING, "available", NULL, sysctl_cpuspeed_available, 2, (void *)sc, 0, CTL_MACHDEP, me->sysctl_num, freq->sysctl_num, CTL_CREATE, CTL_EOL) == 0) { } else printf("couldn't create 'available' node\n"); printf("speed: %d\n", curcpu()->ci_khz); /* support cpufreq */ snprintf(cf->cf_name, CPUFREQ_NAME_MAX, "Intrepid"); cf->cf_state[0].cfs_freq = sc->sc_spd_hi; cf->cf_state[1].cfs_freq = sc->sc_spd_lo; cf->cf_state_count = 2; cf->cf_mp = FALSE; cf->cf_cookie = sc; cf->cf_get_freq = obio_get_freq; cf->cf_set_freq = obio_set_freq; /* * XXX * cpufreq_register() calls xc_broadcast() which relies on kthreads * running so we need to postpone it */ config_interrupts(sc->sc_dev, obio_setup_cpufreq); }
static int lbc_attach(device_t dev) { struct lbc_softc *sc; struct lbc_devinfo *di; struct rman *rm; u_long offset, start, size; device_t cdev; phandle_t node, child; pcell_t *ranges, *rangesptr; int tuple_size, tuples; int par_addr_cells; int bank, error, i; sc = device_get_softc(dev); sc->sc_dev = dev; sc->sc_mrid = 0; sc->sc_mres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_mrid, RF_ACTIVE); if (sc->sc_mres == NULL) return (ENXIO); sc->sc_bst = rman_get_bustag(sc->sc_mres); sc->sc_bsh = rman_get_bushandle(sc->sc_mres); for (bank = 0; bank < LBC_DEV_MAX; bank++) { bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_BR(bank), 0); bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_OR(bank), 0); } /* * Initialize configuration register: * - enable Local Bus * - set data buffer control signal function * - disable parity byte select * - set ECC parity type * - set bus monitor timing and timer prescale */ bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LBCR, 0); /* * Initialize clock ratio register: * - disable PLL bypass mode * - configure LCLK delay cycles for the assertion of LALE * - set system clock divider */ bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LCRR, 0x00030008); bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LTEDR, 0); bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LTESR, ~0); bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LTEIR, 0x64080001); sc->sc_irid = 0; sc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irid, RF_ACTIVE | RF_SHAREABLE); if (sc->sc_ires != NULL) { error = bus_setup_intr(dev, sc->sc_ires, INTR_TYPE_MISC | INTR_MPSAFE, NULL, lbc_intr, sc, &sc->sc_icookie); if (error) { device_printf(dev, "could not activate interrupt\n"); bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid, sc->sc_ires); sc->sc_ires = NULL; } } sc->sc_ltesr = ~0; rangesptr = NULL; rm = &sc->sc_rman; rm->rm_type = RMAN_ARRAY; rm->rm_descr = "Local Bus Space"; rm->rm_start = 0UL; rm->rm_end = ~0UL; error = rman_init(rm); if (error) goto fail; error = rman_manage_region(rm, rm->rm_start, rm->rm_end); if (error) { rman_fini(rm); goto fail; } /* * Process 'ranges' property. */ node = ofw_bus_get_node(dev); if ((fdt_addrsize_cells(node, &sc->sc_addr_cells, &sc->sc_size_cells)) != 0) { error = ENXIO; goto fail; } par_addr_cells = fdt_parent_addr_cells(node); if (par_addr_cells > 2) { device_printf(dev, "unsupported parent #addr-cells\n"); error = ERANGE; goto fail; } tuple_size = sizeof(pcell_t) * (sc->sc_addr_cells + par_addr_cells + sc->sc_size_cells); tuples = OF_getprop_alloc(node, "ranges", tuple_size, (void **)&ranges); if (tuples < 0) { device_printf(dev, "could not retrieve 'ranges' property\n"); error = ENXIO; goto fail; } rangesptr = ranges; debugf("par addr_cells = %d, addr_cells = %d, size_cells = %d, " "tuple_size = %d, tuples = %d\n", par_addr_cells, sc->sc_addr_cells, sc->sc_size_cells, tuple_size, tuples); start = 0; size = 0; for (i = 0; i < tuples; i++) { /* The first cell is the bank (chip select) number. */ bank = fdt_data_get((void *)ranges, 1); if (bank < 0 || bank > LBC_DEV_MAX) { device_printf(dev, "bank out of range: %d\n", bank); error = ERANGE; goto fail; } ranges += 1; /* * Remaining cells of the child address define offset into * this CS. */ offset = fdt_data_get((void *)ranges, sc->sc_addr_cells - 1); ranges += sc->sc_addr_cells - 1; /* Parent bus start address of this bank. */ start = fdt_data_get((void *)ranges, par_addr_cells); ranges += par_addr_cells; size = fdt_data_get((void *)ranges, sc->sc_size_cells); ranges += sc->sc_size_cells; debugf("bank = %d, start = %lx, size = %lx\n", bank, start, size); sc->sc_banks[bank].addr = start + offset; sc->sc_banks[bank].size = size; /* * Attributes for the bank. * * XXX Note there are no DT bindings defined for them at the * moment, so we need to provide some defaults. */ sc->sc_banks[bank].width = 16; sc->sc_banks[bank].msel = LBCRES_MSEL_GPCM; sc->sc_banks[bank].decc = LBCRES_DECC_DISABLED; sc->sc_banks[bank].atom = LBCRES_ATOM_DISABLED; sc->sc_banks[bank].wp = 0; } /* * Initialize mem-mappings for the LBC banks (i.e. chip selects). */ error = lbc_banks_map(sc); if (error) goto fail; /* * Walk the localbus and add direct subordinates as our children. */ for (child = OF_child(node); child != 0; child = OF_peer(child)) { di = malloc(sizeof(*di), M_LBC, M_WAITOK | M_ZERO); if (ofw_bus_gen_setup_devinfo(&di->di_ofw, child) != 0) { free(di, M_LBC); device_printf(dev, "could not set up devinfo\n"); continue; } resource_list_init(&di->di_res); if (fdt_lbc_reg_decode(child, sc, di)) { device_printf(dev, "could not process 'reg' " "property\n"); ofw_bus_gen_destroy_devinfo(&di->di_ofw); free(di, M_LBC); continue; } fdt_lbc_fixup(child, sc, di); /* Add newbus device for this FDT node */ cdev = device_add_child(dev, NULL, -1); if (cdev == NULL) { device_printf(dev, "could not add child: %s\n", di->di_ofw.obd_name); resource_list_free(&di->di_res); ofw_bus_gen_destroy_devinfo(&di->di_ofw); free(di, M_LBC); continue; } debugf("added child name='%s', node=%p\n", di->di_ofw.obd_name, (void *)child); device_set_ivars(cdev, di); } /* * Enable the LBC. */ lbc_banks_enable(sc); free(rangesptr, M_OFWPROP); return (bus_generic_attach(dev)); fail: free(rangesptr, M_OFWPROP); bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_mrid, sc->sc_mres); return (error); }
static int davbus_attach(device_t self) { struct davbus_softc *sc; struct resource *dbdma_irq, *cintr; void *cookie; char compat[64]; int rid, oirq, err; sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO); sc->aoa.sc_dev = self; sc->node = ofw_bus_get_node(self); sc->soundnode = OF_child(sc->node); /* Map the controller register space. */ rid = 0; sc->reg = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->reg == NULL) return (ENXIO); /* Map the DBDMA channel register space. */ rid = 1; sc->aoa.sc_odma = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->aoa.sc_odma == NULL) return (ENXIO); /* Establish the DBDMA channel edge-triggered interrupt. */ rid = 1; dbdma_irq = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); if (dbdma_irq == NULL) return (ENXIO); oirq = rman_get_start(dbdma_irq); DPRINTF(("interrupting at irq %d\n", oirq)); err = powerpc_config_intr(oirq, INTR_TRIGGER_EDGE, INTR_POLARITY_LOW); if (err != 0) return (err); snd_setup_intr(self, dbdma_irq, INTR_MPSAFE, aoa_interrupt, sc, &cookie); /* Now initialize the controller. */ bzero(compat, sizeof(compat)); OF_getprop(sc->soundnode, "compatible", compat, sizeof(compat)); OF_getprop(sc->soundnode, "device-id", &sc->device_id, sizeof(u_int)); mtx_init(&sc->mutex, "DAVbus", NULL, MTX_DEF); device_printf(self, "codec: <%s>\n", compat); /* Setup the control interrupt. */ rid = 0; cintr = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); if (cintr != NULL) bus_setup_intr(self, cintr, INTR_TYPE_MISC | INTR_MPSAFE, NULL, davbus_cint, sc, &cookie); /* Initialize controller registers. */ bus_write_4(sc->reg, DAVBUS_SOUND_CTRL, DAVBUS_INPUT_SUBFRAME0 | DAVBUS_OUTPUT_SUBFRAME0 | DAVBUS_RATE_44100 | DAVBUS_INTR_PORTCHG); /* Attach DBDMA engine and PCM layer */ err = aoa_attach(sc); if (err) return (err); /* Install codec module */ if (strcmp(compat, "screamer") == 0) mixer_init(self, &screamer_mixer_class, sc); else if (strcmp(compat, "burgundy") == 0) mixer_init(self, &burgundy_mixer_class, sc); return (0); }
int openpromioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) { struct opiocdesc *op; int node, len, ok, error, s; char *name, *value, *nextprop; static char buf[32]; /* XXX */ if (optionsnode == 0) { s = splhigh(); optionsnode = OF_getnodebyname(0, "options"); splx(s); } /* All too easy... */ if (cmd == OPIOCGETOPTNODE) { *(int *)data = optionsnode; return (0); } /* Verify node id */ op = (struct opiocdesc *)data; node = op->op_nodeid; if (node != 0 && node != lastnode && node != optionsnode) { /* Not an easy one, must search for it */ s = splhigh(); ok = openpromcheckid(OF_peer(0), node); splx(s); if (!ok) return (EINVAL); lastnode = node; } name = value = NULL; error = 0; switch (cmd) { case OPIOCGET: if ((flags & FREAD) == 0) return (EBADF); if (node == 0) return (EINVAL); error = openpromgetstr(op->op_namelen, op->op_name, &name); if (error) break; s = splhigh(); strlcpy(buf, name, 32); /* XXX */ len = OF_getproplen(node, buf); splx(s); if (len > op->op_buflen) { error = ENOMEM; break; } op->op_buflen = len; /* -1 means no entry; 0 means no value */ if (len <= 0) break; value = malloc(len, M_TEMP, M_WAITOK); s = splhigh(); strlcpy(buf, name, 32); /* XXX */ OF_getprop(node, buf, value, len); splx(s); error = copyout(value, op->op_buf, len); break; case OPIOCSET: if ((flags & FWRITE) == 0) return (EBADF); if (node == 0) return (EINVAL); error = openpromgetstr(op->op_namelen, op->op_name, &name); if (error) break; error = openpromgetstr(op->op_buflen, op->op_buf, &value); if (error) break; s = splhigh(); strlcpy(buf, name, 32); /* XXX */ len = OF_setprop(node, buf, value, op->op_buflen + 1); splx(s); if (len != op->op_buflen) error = EINVAL; break; case OPIOCNEXTPROP: if ((flags & FREAD) == 0) return (EBADF); if (node == 0) return (EINVAL); error = openpromgetstr(op->op_namelen, op->op_name, &name); if (error) break; if (op->op_buflen <= 0) { error = ENAMETOOLONG; break; } value = nextprop = malloc(OPROMMAXPARAM, M_TEMP, M_WAITOK | M_CANFAIL); if (nextprop == NULL) { error = ENOMEM; break; } s = splhigh(); strlcpy(buf, name, 32); /* XXX */ error = OF_nextprop(node, buf, nextprop); splx(s); if (error == -1) { error = EINVAL; break; } if (error == 0) { char nul = '\0'; op->op_buflen = 0; error = copyout(&nul, op->op_buf, sizeof(char)); break; } len = strlen(nextprop); if (len > op->op_buflen) len = op->op_buflen; else op->op_buflen = len; error = copyout(nextprop, op->op_buf, len); break; case OPIOCGETNEXT: if ((flags & FREAD) == 0) return (EBADF); s = splhigh(); node = OF_peer(node); splx(s); *(int *)data = lastnode = node; break; case OPIOCGETCHILD: if ((flags & FREAD) == 0) return (EBADF); if (node == 0) return (EINVAL); s = splhigh(); node = OF_child(node); splx(s); *(int *)data = lastnode = node; break; default: return (ENOTTY); } if (name) free(name, M_TEMP, 0); if (value) free(value, M_TEMP, 0); return (error); }
static void cuda_attach(device_t parent, device_t self, void *aux) { struct confargs *ca = aux; struct cuda_softc *sc = device_private(self); struct i2cbus_attach_args iba; static struct cuda_attach_args caa; int irq = ca->ca_intr[0]; int node, i, child; char name[32]; sc->sc_dev = self; node = of_getnode_byname(OF_parent(ca->ca_node), "extint-gpio1"); if (node) OF_getprop(node, "interrupts", &irq, 4); aprint_normal(" irq %d", irq); sc->sc_node = ca->ca_node; sc->sc_memt = ca->ca_tag; sc->sc_sent = 0; sc->sc_received = 0; sc->sc_waiting = 0; sc->sc_polling = 0; sc->sc_state = CUDA_NOTREADY; sc->sc_error = 0; sc->sc_i2c_read_len = 0; if (bus_space_map(sc->sc_memt, ca->ca_reg[0] + ca->ca_baseaddr, ca->ca_reg[1], 0, &sc->sc_memh) != 0) { aprint_normal(": unable to map registers\n"); return; } sc->sc_ih = intr_establish(irq, IST_EDGE, IPL_TTY, cuda_intr, sc); printf("\n"); for (i = 0; i < 16; i++) { sc->sc_handlers[i].handler = NULL; sc->sc_handlers[i].cookie = NULL; } cuda_init(sc); /* now attach children */ config_interrupts(self, cuda_final); cuda_set_handler(sc, CUDA_ERROR, cuda_error_handler, sc); cuda_set_handler(sc, CUDA_PSEUDO, cuda_todr_handler, sc); child = OF_child(ca->ca_node); while (child != 0) { if (OF_getprop(child, "name", name, 32) == 0) continue; if (strncmp(name, "adb", 4) == 0) { cuda_set_handler(sc, CUDA_ADB, cuda_adb_handler, sc); sc->sc_adbops.cookie = sc; sc->sc_adbops.send = cuda_adb_send; sc->sc_adbops.poll = cuda_adb_poll; sc->sc_adbops.autopoll = cuda_autopoll; sc->sc_adbops.set_handler = cuda_adb_set_handler; config_found_ia(self, "adb_bus", &sc->sc_adbops, nadb_print); } else if (strncmp(name, "rtc", 4) == 0) { sc->sc_todr.todr_gettime = cuda_todr_get; sc->sc_todr.todr_settime = cuda_todr_set; sc->sc_todr.cookie = sc; todr_attach(&sc->sc_todr); } child = OF_peer(child); } caa.cookie = sc; caa.set_handler = cuda_set_handler; caa.send = cuda_send; caa.poll = cuda_poll; #if notyet config_found(self, &caa, cuda_print); #endif mutex_init(&sc->sc_buslock, MUTEX_DEFAULT, IPL_NONE); memset(&iba, 0, sizeof(iba)); iba.iba_tag = &sc->sc_i2c; sc->sc_i2c.ic_cookie = sc; sc->sc_i2c.ic_acquire_bus = cuda_i2c_acquire_bus; sc->sc_i2c.ic_release_bus = cuda_i2c_release_bus; sc->sc_i2c.ic_send_start = NULL; sc->sc_i2c.ic_send_stop = NULL; sc->sc_i2c.ic_initiate_xfer = NULL; sc->sc_i2c.ic_read_byte = NULL; sc->sc_i2c.ic_write_byte = NULL; sc->sc_i2c.ic_exec = cuda_i2c_exec; config_found_ia(self, "i2cbus", &iba, iicbus_print); if (cuda0 == NULL) cuda0 = &caa; }
static int mv_twsi_attach(device_t dev) { struct mv_twsi_softc *sc; phandle_t child, iicbusnode; device_t childdev; struct iicbus_ivar *devi; char dname[32]; /* 32 is taken from struct u_device */ uint32_t paddr; int len, error; sc = device_get_softc(dev); sc->dev = dev; bzero(baud_rate, sizeof(baud_rate)); mtx_init(&sc->mutex, device_get_nameunit(dev), MV_TWSI_NAME, MTX_DEF); /* Allocate IO resources */ if (bus_alloc_resources(dev, res_spec, sc->res)) { device_printf(dev, "could not allocate resources\n"); mv_twsi_detach(dev); return (ENXIO); } mv_twsi_cal_baud_rate(TWSI_BAUD_RATE_SLOW, &baud_rate[IIC_SLOW]); mv_twsi_cal_baud_rate(TWSI_BAUD_RATE_FAST, &baud_rate[IIC_FAST]); if (bootverbose) device_printf(dev, "calculated baud rates are:\n" " %" PRIu32 " kHz (M=%d, N=%d) for slow,\n" " %" PRIu32 " kHz (M=%d, N=%d) for fast.\n", baud_rate[IIC_SLOW].raw / 1000, baud_rate[IIC_SLOW].m, baud_rate[IIC_SLOW].n, baud_rate[IIC_FAST].raw / 1000, baud_rate[IIC_FAST].m, baud_rate[IIC_FAST].n); sc->iicbus = device_add_child(dev, IICBUS_DEVNAME, -1); if (sc->iicbus == NULL) { device_printf(dev, "could not add iicbus child\n"); mv_twsi_detach(dev); return (ENXIO); } /* Attach iicbus. */ bus_generic_attach(dev); iicbusnode = 0; /* Find iicbus as the child devices in the device tree. */ for (child = OF_child(ofw_bus_get_node(dev)); child != 0; child = OF_peer(child)) { len = OF_getproplen(child, "model"); if (len <= 0 || len > sizeof(dname) - 1) continue; error = OF_getprop(child, "model", &dname, len); dname[len + 1] = '\0'; if (error == -1) continue; len = strlen(dname); if (len == strlen(IICBUS_DEVNAME) && strncasecmp(dname, IICBUS_DEVNAME, len) == 0) { iicbusnode = child; break; } } if (iicbusnode == 0) goto attach_end; /* Attach child devices onto iicbus. */ for (child = OF_child(iicbusnode); child != 0; child = OF_peer(child)) { /* Get slave address. */ error = OF_getprop(child, "i2c-address", &paddr, sizeof(paddr)); if (error == -1) error = OF_getprop(child, "reg", &paddr, sizeof(paddr)); if (error == -1) continue; /* Get device driver name. */ len = OF_getproplen(child, "model"); if (len <= 0 || len > sizeof(dname) - 1) continue; OF_getprop(child, "model", &dname, len); dname[len + 1] = '\0'; if (bootverbose) device_printf(dev, "adding a device %s at %d.\n", dname, fdt32_to_cpu(paddr)); childdev = BUS_ADD_CHILD(sc->iicbus, 0, dname, -1); devi = IICBUS_IVAR(childdev); devi->addr = fdt32_to_cpu(paddr); } attach_end: bus_generic_attach(sc->iicbus); return (0); }