static int nvmem_get_cell_node(phandle_t node, int idx, phandle_t *cell) { phandle_t *p_cell; phandle_t cell_node; int ncell; if (!OF_hasprop(node, "nvmem-cells") || !OF_hasprop(node, "nvmem-cell-names")) return (ENOENT); ncell = OF_getencprop_alloc_multi(node, "nvmem-cells", sizeof(*p_cell), (void **)&p_cell); if (ncell <= 0) return (ENOENT); cell_node = OF_node_from_xref(p_cell[idx]); if (cell_node == p_cell[idx]) { if (bootverbose) printf("nvmem_get_node: Cannot resolve phandle %x\n", p_cell[idx]); OF_prop_free(p_cell); return (ENOENT); } OF_prop_free(p_cell); *cell = cell_node; return (0); }
int phy_get_by_ofw_property(device_t consumer_dev, phandle_t cnode, char *name, phy_t *phy) { pcell_t *cells; device_t phydev; int ncells, rv; intptr_t id; if (cnode <= 0) cnode = ofw_bus_get_node(consumer_dev); if (cnode <= 0) { device_printf(consumer_dev, "%s called on not ofw based device\n", __func__); return (ENXIO); } ncells = OF_getencprop_alloc(cnode, name, sizeof(pcell_t), (void **)&cells); if (ncells < 1) return (ENXIO); /* Tranlate provider to device. */ phydev = OF_device_from_xref(cells[0]); if (phydev == NULL) { OF_prop_free(cells); return (ENODEV); } /* Map phy to number. */ rv = PHY_MAP(phydev, cells[0], ncells - 1 , cells + 1, &id); OF_prop_free(cells); if (rv != 0) return (rv); return (phy_get_by_id(consumer_dev, phydev, id, phy)); }
static int pinmux_process_node(struct pinmux_softc *sc, phandle_t node) { struct pincfg cfg; char *pins, *pname; int i, len, lpins, rv; rv = pinmux_read_node(sc, node, &cfg, &pins, &lpins); if (rv != 0) return (rv); len = 0; pname = pins; do { i = strlen(pname) + 1; rv = pinmux_config_node(sc, pname, &cfg); if (rv != 0) device_printf(sc->dev, "Cannot configure pin: %s: %d\n", pname, rv); len += i; pname += i; } while (len < lpins); if (pins != NULL) OF_prop_free(pins); if (cfg.function != NULL) OF_prop_free(cfg.function); return (rv); }
int phy_get_by_ofw_idx(device_t consumer_dev, phandle_t cnode, int idx, phy_t *phy) { phandle_t xnode; pcell_t *cells; device_t phydev; int ncells, rv; intptr_t id; if (cnode <= 0) cnode = ofw_bus_get_node(consumer_dev); if (cnode <= 0) { device_printf(consumer_dev, "%s called on not ofw based device\n", __func__); return (ENXIO); } rv = ofw_bus_parse_xref_list_alloc(cnode, "phys", "#phy-cells", idx, &xnode, &ncells, &cells); if (rv != 0) return (rv); /* Tranlate provider to device. */ phydev = OF_device_from_xref(xnode); if (phydev == NULL) { OF_prop_free(cells); return (ENODEV); } /* Map phy to number. */ rv = PHY_MAP(phydev, xnode, ncells, cells, &id); OF_prop_free(cells); if (rv != 0) return (rv); return (phy_get_by_id(consumer_dev, phydev, id, phy)); }
static int clk_fixed_attach(device_t dev) { struct clk_fixed_softc *sc; intptr_t clk_type; phandle_t node; struct clk_fixed_def def; int rv; sc = device_get_softc(dev); sc->dev = dev; node = ofw_bus_get_node(dev); clk_type = ofw_bus_search_compatible(dev, compat_data)->ocd_data; bzero(&def, sizeof(def)); if (clk_type == CLK_TYPE_FIXED) rv = clk_fixed_init_fixed(sc, node, &def); else if (clk_type == CLK_TYPE_FIXED_FACTOR) rv = clk_fixed_init_fixed_factor(sc, node, &def); else rv = ENXIO; if (rv != 0) { device_printf(sc->dev, "Cannot FDT parameters.\n"); goto fail; } rv = clk_parse_ofw_clk_name(dev, node, &def.clkdef.name); if (rv != 0) { device_printf(sc->dev, "Cannot parse clock name.\n"); goto fail; } sc->clkdom = clkdom_create(dev); KASSERT(sc->clkdom != NULL, ("Clock domain is NULL")); rv = clknode_fixed_register(sc->clkdom, &def); if (rv != 0) { device_printf(sc->dev, "Cannot register fixed clock.\n"); rv = ENXIO; goto fail; } rv = clkdom_finit(sc->clkdom); if (rv != 0) { device_printf(sc->dev, "Clk domain finit fails.\n"); rv = ENXIO; goto fail; } #ifdef CLK_DEBUG clkdom_dump(sc->clkdom); #endif OF_prop_free(__DECONST(char *, def.clkdef.name)); OF_prop_free(def.clkdef.parent_names); return (bus_generic_attach(dev)); fail: OF_prop_free(__DECONST(char *, def.clkdef.name)); OF_prop_free(def.clkdef.parent_names); return (rv); }
static void gpioleds_attach_led(struct gpioleds_softc *sc, phandle_t node, struct gpioled *led) { char *name; int state, err; char *default_state; led->parent_sc = sc; state = 0; if (OF_getprop_alloc(node, "default-state", sizeof(char), (void **)&default_state) != -1) { if (strcasecmp(default_state, "on") == 0) state = 1; else if (strcasecmp(default_state, "off") == 0) state = 0; else if (strcasecmp(default_state, "keep") == 0) state = -1; else { state = -1; device_printf(sc->sc_dev, "unknown value for default-state in FDT\n"); } OF_prop_free(default_state); } name = NULL; if (OF_getprop_alloc(node, "label", 1, (void **)&name) == -1) OF_getprop_alloc(node, "name", 1, (void **)&name); if (name == NULL) { device_printf(sc->sc_dev, "no name provided for gpio LED, skipping\n"); return; } err = gpio_pin_get_by_ofw_idx(sc->sc_dev, node, 0, &led->pin); if (err) { device_printf(sc->sc_dev, "<%s> failed to map pin\n", name); if (name) OF_prop_free(name); return; } gpio_pin_setflags(led->pin, GPIO_PIN_OUTPUT); led->leddev = led_create_state(gpioled_control, led, name, state); if (name != NULL) OF_prop_free(name); }
/* * Utility functions for easier handling of OFW GPIO pins. * * !!! BEWARE !!! * GPIOBUS uses children's IVARs, so we cannot use this interface for cross * tree consumers. * */ static int gpio_pin_get_by_ofw_impl(device_t consumer, phandle_t cnode, char *prop_name, int idx, gpio_pin_t *out_pin) { phandle_t xref; pcell_t *cells; device_t busdev; struct gpiobus_pin pin; int ncells, rv; KASSERT(consumer != NULL && cnode > 0, ("both consumer and cnode required")); rv = ofw_bus_parse_xref_list_alloc(cnode, prop_name, "#gpio-cells", idx, &xref, &ncells, &cells); if (rv != 0) return (rv); /* Translate provider to device. */ pin.dev = OF_device_from_xref(xref); if (pin.dev == NULL) { OF_prop_free(cells); return (ENODEV); } /* Test if GPIO bus already exist. */ busdev = GPIO_GET_BUS(pin.dev); if (busdev == NULL) { OF_prop_free(cells); return (ENODEV); } /* Map GPIO pin. */ rv = gpio_map_gpios(pin.dev, cnode, OF_node_from_xref(xref), ncells, cells, &pin.pin, &pin.flags); OF_prop_free(cells); if (rv != 0) return (ENXIO); /* Reserve GPIO pin. */ rv = gpiobus_acquire_pin(busdev, pin.pin); if (rv != 0) return (EBUSY); *out_pin = malloc(sizeof(struct gpiobus_pin), M_DEVBUF, M_WAITOK | M_ZERO); **out_pin = pin; return (0); }
static int ti_pinmux_configure_pins(device_t dev, phandle_t cfgxref) { struct pincfg *cfgtuples, *cfg; phandle_t cfgnode; int i, ntuples; static struct ti_pinmux_softc *sc; sc = device_get_softc(dev); cfgnode = OF_node_from_xref(cfgxref); ntuples = OF_getencprop_alloc(cfgnode, "pinctrl-single,pins", sizeof(*cfgtuples), (void **)&cfgtuples); if (ntuples < 0) return (ENOENT); if (ntuples == 0) return (0); /* Empty property is not an error. */ for (i = 0, cfg = cfgtuples; i < ntuples; i++, cfg++) { if (bootverbose) { char name[32]; OF_getprop(cfgnode, "name", &name, sizeof(name)); printf("%16s: muxreg 0x%04x muxval 0x%02x\n", name, cfg->reg, cfg->conf); } /* write the register value (16-bit writes) */ ti_pinmux_write_2(sc, cfg->reg, cfg->conf); } OF_prop_free(cfgtuples); return (0); }
static int fdt_lbc_reg_decode(phandle_t node, struct lbc_softc *sc, struct lbc_devinfo *di) { rman_res_t start, end, count; pcell_t *reg, *regptr; pcell_t addr_cells, size_cells; int tuple_size, tuples; int i, j, rv, bank; if (fdt_addrsize_cells(OF_parent(node), &addr_cells, &size_cells) != 0) return (ENXIO); tuple_size = sizeof(pcell_t) * (addr_cells + size_cells); tuples = OF_getencprop_alloc_multi(node, "reg", tuple_size, (void **)®); debugf("addr_cells = %d, size_cells = %d\n", addr_cells, size_cells); debugf("tuples = %d, tuple size = %d\n", tuples, tuple_size); if (tuples <= 0) /* No 'reg' property in this node. */ return (0); regptr = reg; for (i = 0; i < tuples; i++) { bank = fdt_data_get((void *)reg, 1); di->di_bank = bank; reg += 1; /* Get address/size. */ start = count = 0; for (j = 0; j < addr_cells; j++) { start <<= 32; start |= reg[j]; } for (j = 0; j < size_cells; j++) { count <<= 32; count |= reg[addr_cells + j - 1]; } reg += addr_cells - 1 + size_cells; /* Calculate address range relative to VA base. */ start = sc->sc_banks[bank].kva + start; end = start + count - 1; debugf("reg addr bank = %d, start = %jx, end = %jx, " "count = %jx\n", bank, start, end, count); /* Use bank (CS) cell as rid. */ resource_list_add(&di->di_res, SYS_RES_MEMORY, bank, start, end, count); } rv = 0; OF_prop_free(regptr); return (rv); }
int fdt_reg_to_rl(phandle_t node, struct resource_list *rl) { u_long end, count, start; pcell_t *reg, *regptr; pcell_t addr_cells, size_cells; int tuple_size, tuples; int i, rv; long busaddr, bussize; if (fdt_addrsize_cells(OF_parent(node), &addr_cells, &size_cells) != 0) return (ENXIO); if (fdt_get_range(OF_parent(node), 0, &busaddr, &bussize)) { busaddr = 0; bussize = 0; } tuple_size = sizeof(pcell_t) * (addr_cells + size_cells); tuples = OF_getprop_alloc(node, "reg", tuple_size, (void **)®); debugf("addr_cells = %d, size_cells = %d\n", addr_cells, size_cells); debugf("tuples = %d, tuple size = %d\n", tuples, tuple_size); if (tuples <= 0) /* No 'reg' property in this node. */ return (0); regptr = reg; for (i = 0; i < tuples; i++) { rv = fdt_data_to_res(reg, addr_cells, size_cells, &start, &count); if (rv != 0) { resource_list_free(rl); goto out; } reg += addr_cells + size_cells; /* Calculate address range relative to base. */ start += busaddr; end = start + count - 1; debugf("reg addr start = %lx, end = %lx, count = %lx\n", start, end, count); resource_list_add(rl, SYS_RES_MEMORY, i, start, end, count); } rv = 0; out: OF_prop_free(regptr); return (rv); }
static int pinctrl_configure_pins(device_t bus, phandle_t cfgxref) { struct pinctrl_softc *sc; struct pincfg *cfg, *cfgdata; char name[32]; phandle_t node; ssize_t npins; int i; sc = device_get_softc(bus); node = OF_node_from_xref(cfgxref); memset(name, 0, sizeof(name)); OF_getprop(node, "name", name, sizeof(name)); npins = OF_getencprop_alloc(node, "atmel,pins", sizeof(*cfgdata), (void **)&cfgdata); if (npins < 0) { printf("We're doing it wrong %s\n", name); return (ENXIO); } if (npins == 0) return (0); for (i = 0, cfg = cfgdata; i < npins; i++, cfg++) { uint32_t pio; pio = (0xfffffff & sc->ranges[0].bus) + 0x200 * cfg->unit; printf("P%c%d %s %#x\n", cfg->unit + 'A', cfg->pin, periphs[cfg->periph], cfg->flags); switch (cfg->periph) { case 0: at91_pio_use_gpio(pio, 1u << cfg->pin); at91_pio_gpio_pullup(pio, 1u << cfg->pin, !!(cfg->flags & 1)); at91_pio_gpio_high_z(pio, 1u << cfg->pin, !!(cfg->flags & 2)); at91_pio_gpio_set_deglitch(pio, 1u << cfg->pin, !!(cfg->flags & 4)); // at91_pio_gpio_pulldown(pio, 1u << cfg->pin, // !!(cfg->flags & 8)); // at91_pio_gpio_dis_schmidt(pio, // 1u << cfg->pin, !!(cfg->flags & 16)); break; case 1: at91_pio_use_periph_a(pio, 1u << cfg->pin, cfg->flags); break; case 2: at91_pio_use_periph_b(pio, 1u << cfg->pin, cfg->flags); break; } } OF_prop_free(cfgdata); return (0); }
int hwreset_get_by_ofw_idx(device_t consumer_dev, phandle_t cnode, int idx, hwreset_t *rst) { phandle_t xnode; pcell_t *cells; device_t rstdev; int ncells, rv; intptr_t id; if (cnode <= 0) cnode = ofw_bus_get_node(consumer_dev); if (cnode <= 0) { device_printf(consumer_dev, "%s called on not ofw based device\n", __func__); return (ENXIO); } rv = ofw_bus_parse_xref_list_alloc(cnode, "resets", "#reset-cells", idx, &xnode, &ncells, &cells); if (rv != 0) return (rv); /* Tranlate provider to device */ rstdev = OF_device_from_xref(xnode); if (rstdev == NULL) { OF_prop_free(cells); return (ENODEV); } /* Map reset to number */ rv = HWRESET_MAP(rstdev, xnode, ncells, cells, &id); OF_prop_free(cells); if (rv != 0) return (rv); return (hwreset_get_by_id(consumer_dev, rstdev, id, rst)); }
/* * Loop through all the tuples in the resets= property for a device, asserting * or deasserting each reset. * * Be liberal about errors for now: warn about a failure to (de)assert but keep * trying with any other resets in the list. Return ENXIO if any errors were * found, and let the caller decide whether the problem is fatal. */ static int assert_deassert_all(device_t consumer, boolean_t assert) { phandle_t rnode; device_t resetdev; int resetnum, err, i, ncells; uint32_t *resets; boolean_t anyerrors; rnode = ofw_bus_get_node(consumer); ncells = OF_getencprop_alloc(rnode, "resets", sizeof(*resets), (void **)&resets); if (!assert && ncells < 2) { device_printf(consumer, "Warning: No resets specified in fdt " "data; device may not function."); return (ENXIO); } anyerrors = false; for (i = 0; i < ncells; i += 2) { resetdev = OF_device_from_xref(resets[i]); resetnum = resets[i + 1]; if (resetdev == NULL) { if (!assert) device_printf(consumer, "Warning: can not find " "driver for reset number %u; device may " "not function\n", resetnum); anyerrors = true; continue; } if (assert) err = FDT_RESET_ASSERT(resetdev, resetnum); else err = FDT_RESET_DEASSERT(resetdev, resetnum); if (err != 0) { if (!assert) device_printf(consumer, "Warning: failed to " "deassert reset number %u; device may not " "function\n", resetnum); anyerrors = true; } } OF_prop_free(resets); return (anyerrors ? ENXIO : 0); }
static int tegra124_coretemp_ofw_parse(struct tegra124_coretemp_softc *sc) { int rv, ncells; phandle_t node, xnode; pcell_t *cells; node = OF_peer(0); node = ofw_bus_find_child(node, "thermal-zones"); if (node <= 0) { device_printf(sc->dev, "Cannot find 'thermal-zones'.\n"); return (ENXIO); } node = ofw_bus_find_child(node, "cpu"); if (node <= 0) { device_printf(sc->dev, "Cannot find 'cpu'\n"); return (ENXIO); } rv = ofw_bus_parse_xref_list_alloc(node, "thermal-sensors", "#thermal-sensor-cells", 0, &xnode, &ncells, &cells); if (rv != 0) { device_printf(sc->dev, "Cannot parse 'thermal-sensors' property.\n"); return (ENXIO); } if (ncells != 1) { device_printf(sc->dev, "Invalid format of 'thermal-sensors' property(%d).\n", ncells); return (ENXIO); } sc->tsens_id = 0x100 + sc->cpu_id; //cells[0]; OF_prop_free(cells); sc->tsens_dev = OF_device_from_xref(xnode); if (sc->tsens_dev == NULL) { device_printf(sc->dev, "Cannot find thermal sensors device."); return (ENXIO); } return (0); }
static enum usb_ifc_type usb_get_ifc_mode(device_t dev, phandle_t node, char *name) { char *tmpstr; int rv; enum usb_ifc_type ret; rv = OF_getprop_alloc(node, name, 1, (void **)&tmpstr); if (rv <= 0) return (USB_IFC_TYPE_UNKNOWN); ret = USB_IFC_TYPE_UNKNOWN; if (strcmp(tmpstr, "utmi") == 0) ret = USB_IFC_TYPE_UTMI; else if (strcmp(tmpstr, "ulpi") == 0) ret = USB_IFC_TYPE_ULPI; else device_printf(dev, "Unsupported phy type: %s\n", tmpstr); OF_prop_free(tmpstr); return (ret); }
int fdt_is_enabled(phandle_t node) { char *stat; int ena, len; len = OF_getprop_alloc(node, "status", sizeof(char), (void **)&stat); if (len <= 0) /* It is OK if no 'status' property. */ return (1); /* Anything other than 'okay' means disabled. */ ena = 0; if (strncmp((char *)stat, "okay", len) == 0) ena = 1; OF_prop_free(stat); return (ena); }
static enum usb_dr_mode usb_get_dr_mode(device_t dev, phandle_t node, char *name) { char *tmpstr; int rv; enum usb_dr_mode ret; rv = OF_getprop_alloc(node, name, 1, (void **)&tmpstr); if (rv <= 0) return (USB_DR_MODE_UNKNOWN); ret = USB_DR_MODE_UNKNOWN; if (strcmp(tmpstr, "device") == 0) ret = USB_DR_MODE_DEVICE; else if (strcmp(tmpstr, "host") == 0) ret = USB_DR_MODE_HOST; else if (strcmp(tmpstr, "otg") == 0) ret = USB_DR_MODE_OTG; else device_printf(dev, "Unknown dr mode: %s\n", tmpstr); OF_prop_free(tmpstr); return (ret); }
static int fdt_localbus_reg_decode(phandle_t node, struct localbus_softc *sc, struct localbus_devinfo *di) { u_long start, end, count; pcell_t *reg, *regptr; pcell_t addr_cells, size_cells; int tuple_size, tuples; int i, rv, bank; if (fdt_addrsize_cells(OF_parent(node), &addr_cells, &size_cells) != 0) return (ENXIO); tuple_size = sizeof(pcell_t) * (addr_cells + size_cells); tuples = OF_getprop_alloc_multi(node, "reg", tuple_size, (void **)®); debugf("addr_cells = %d, size_cells = %d\n", addr_cells, size_cells); debugf("tuples = %d, tuple size = %d\n", tuples, tuple_size); if (tuples <= 0) /* No 'reg' property in this node. */ return (0); regptr = reg; for (i = 0; i < tuples; i++) { bank = fdt_data_get((void *)regptr, 1); if (bank >= MV_LOCALBUS_MAX_BANKS) { device_printf(sc->sc_dev, "bank number [%d] out of " "range\n", bank); continue; } /* * If device doesn't have virtual to physical mapping don't add * resources */ if (!(sc->sc_banks[bank].mapped)) { device_printf(sc->sc_dev, "device [%d]: missing memory " "mapping\n", bank); continue; } di->di_bank = bank; regptr += 1; /* Get address/size. */ rv = fdt_data_to_res(regptr, addr_cells - 1, size_cells, &start, &count); if (rv != 0) { resource_list_free(&di->di_res); goto out; } /* Check if enough amount of memory is mapped */ if (sc->sc_banks[bank].size < count) { device_printf(sc->sc_dev, "device [%d]: not enough " "memory reserved\n", bank); continue; } regptr += addr_cells - 1 + size_cells; /* Calculate address range relative to VA base. */ start = sc->sc_banks[bank].va + start; end = start + count - 1; debugf("reg addr bank = %d, start = %lx, end = %lx, " "count = %lx\n", bank, start, end, count); /* Use bank (CS) cell as rid. */ resource_list_add(&di->di_res, SYS_RES_MEMORY, di->di_bank, start, end, count); } rv = 0; out: OF_prop_free(reg); return (rv); }
static struct pinctrl_devinfo * at91_pinctrl_setup_dinfo(device_t dev, phandle_t node) { struct pinctrl_softc *sc; struct pinctrl_devinfo *ndi; uint32_t *reg, *intr, icells; uint64_t phys, size; phandle_t iparent; int i, j, k; int nintr; int nreg; sc = device_get_softc(dev); ndi = malloc(sizeof(*ndi), M_DEVBUF, M_WAITOK | M_ZERO); if (ofw_bus_gen_setup_devinfo(&ndi->obdinfo, node) != 0) { free(ndi, M_DEVBUF); return (NULL); } resource_list_init(&ndi->rl); nreg = OF_getencprop_alloc(node, "reg", sizeof(*reg), (void **)®); if (nreg == -1) nreg = 0; if (nreg % (sc->acells + sc->scells) != 0) { // if (bootverbose) device_printf(dev, "Malformed reg property on <%s>\n", ndi->obdinfo.obd_name); nreg = 0; } for (i = 0, k = 0; i < nreg; i += sc->acells + sc->scells, k++) { phys = size = 0; for (j = 0; j < sc->acells; j++) { phys <<= 32; phys |= reg[i + j]; } for (j = 0; j < sc->scells; j++) { size <<= 32; size |= reg[i + sc->acells + j]; } resource_list_add(&ndi->rl, SYS_RES_MEMORY, k, phys, phys + size - 1, size); } OF_prop_free(reg); nintr = OF_getencprop_alloc(node, "interrupts", sizeof(*intr), (void **)&intr); if (nintr > 0) { if (OF_searchencprop(node, "interrupt-parent", &iparent, sizeof(iparent)) == -1) { device_printf(dev, "No interrupt-parent found, " "assuming direct parent\n"); iparent = OF_parent(node); } if (OF_searchencprop(OF_node_from_xref(iparent), "#interrupt-cells", &icells, sizeof(icells)) == -1) { device_printf(dev, "Missing #interrupt-cells property," " assuming <1>\n"); icells = 1; } if (icells < 1 || icells > nintr) { device_printf(dev, "Invalid #interrupt-cells property " "value <%d>, assuming <1>\n", icells); icells = 1; } for (i = 0, k = 0; i < nintr; i += icells, k++) { intr[i] = ofw_bus_map_intr(dev, iparent, icells, &intr[i]); resource_list_add(&ndi->rl, SYS_RES_IRQ, k, intr[i], intr[i], 1); } OF_prop_free(intr); } return (ndi); }
static int ofw_gpiobus_parse_gpios_impl(device_t consumer, phandle_t cnode, char *pname, struct gpiobus_softc *bussc, struct gpiobus_pin **pins) { int gpiocells, i, j, ncells, npins; pcell_t *gpios; phandle_t gpio; ncells = OF_getencprop_alloc(cnode, pname, sizeof(*gpios), (void **)&gpios); if (ncells == -1) { device_printf(consumer, "Warning: No %s specified in fdt data; " "device may not function.\n", pname); return (-1); } /* * The gpio-specifier is controller independent, the first pcell has * the reference to the GPIO controller phandler. * Count the number of encoded gpio-specifiers on the first pass. */ i = 0; npins = 0; while (i < ncells) { /* Allow NULL specifiers. */ if (gpios[i] == 0) { npins++; i++; continue; } gpio = OF_node_from_xref(gpios[i]); /* If we have bussc, ignore devices from other gpios. */ if (bussc != NULL) if (ofw_bus_get_node(bussc->sc_dev) != gpio) return (0); /* * Check for gpio-controller property and read the #gpio-cells * for this GPIO controller. */ if (!OF_hasprop(gpio, "gpio-controller") || OF_getencprop(gpio, "#gpio-cells", &gpiocells, sizeof(gpiocells)) < 0) { device_printf(consumer, "gpio reference is not a gpio-controller.\n"); OF_prop_free(gpios); return (-1); } if (ncells - i < gpiocells + 1) { device_printf(consumer, "%s cells doesn't match #gpio-cells.\n", pname); return (-1); } npins++; i += gpiocells + 1; } if (npins == 0 || pins == NULL) { if (npins == 0) device_printf(consumer, "no pin specified in %s.\n", pname); OF_prop_free(gpios); return (npins); } *pins = malloc(sizeof(struct gpiobus_pin) * npins, M_DEVBUF, M_NOWAIT | M_ZERO); if (*pins == NULL) { OF_prop_free(gpios); return (-1); } /* Decode the gpio specifier on the second pass. */ i = 0; j = 0; while (i < ncells) { /* Allow NULL specifiers. */ if (gpios[i] == 0) { j++; i++; continue; } gpio = OF_node_from_xref(gpios[i]); /* Read gpio-cells property for this GPIO controller. */ if (OF_getencprop(gpio, "#gpio-cells", &gpiocells, sizeof(gpiocells)) < 0) { device_printf(consumer, "gpio does not have the #gpio-cells property.\n"); goto fail; } /* Return the device reference for the GPIO controller. */ (*pins)[j].dev = OF_device_from_xref(gpios[i]); if ((*pins)[j].dev == NULL) { device_printf(consumer, "no device registered for the gpio controller.\n"); goto fail; } /* * If the gpiobus softc is NULL we use the GPIO_GET_BUS() to * retrieve it. The GPIO_GET_BUS() method is only valid after * the child is probed and attached. */ if (bussc == NULL) { if (GPIO_GET_BUS((*pins)[j].dev) == NULL) { device_printf(consumer, "no gpiobus reference for %s.\n", device_get_nameunit((*pins)[j].dev)); goto fail; } bussc = device_get_softc(GPIO_GET_BUS((*pins)[j].dev)); } /* Get the GPIO pin number and flags. */ if (gpio_map_gpios((*pins)[j].dev, cnode, gpio, gpiocells, &gpios[i + 1], &(*pins)[j].pin, &(*pins)[j].flags) != 0) { device_printf(consumer, "cannot map the gpios specifier.\n"); goto fail; } /* Reserve the GPIO pin. */ if (gpiobus_acquire_pin(bussc->sc_busdev, (*pins)[j].pin) != 0) goto fail; j++; i += gpiocells + 1; } OF_prop_free(gpios); return (npins); fail: OF_prop_free(gpios); free(*pins, M_DEVBUF); return (-1); }
static int lbc_attach(device_t dev) { struct lbc_softc *sc; struct lbc_devinfo *di; struct rman *rm; uintmax_t offset, size; vm_paddr_t start; device_t cdev; phandle_t node, child; pcell_t *ranges, *rangesptr; int tuple_size, tuples; int par_addr_cells; int bank, error, i, j; 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"; 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_getencprop_alloc_multi(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(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 = 0; for (j = 0; j < sc->sc_addr_cells - 1; j++) { offset <<= sizeof(pcell_t) * 8; offset |= *ranges; ranges++; } /* Parent bus start address of this bank. */ start = 0; for (j = 0; j < par_addr_cells; j++) { start <<= sizeof(pcell_t) * 8; start |= *ranges; ranges++; } size = fdt_data_get((void *)ranges, sc->sc_size_cells); ranges += sc->sc_size_cells; debugf("bank = %d, start = %jx, size = %jx\n", bank, (uintmax_t)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=%x\n", di->di_ofw.obd_name, child); device_set_ivars(cdev, di); } /* * Enable the LBC. */ lbc_banks_enable(sc); OF_prop_free(rangesptr); return (bus_generic_attach(dev)); fail: OF_prop_free(rangesptr); bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_mrid, sc->sc_mres); return (error); }
static int aml8726_pinctrl_configure_pins(device_t dev, phandle_t cfgxref) { struct aml8726_pinctrl_softc *sc = device_get_softc(dev); struct aml8726_pinctrl_function *cf; struct aml8726_pinctrl_function *f; struct aml8726_pinctrl_pkg_pin *pp; struct aml8726_pinctrl_pin *cp; struct aml8726_pinctrl_pin *p; enum aml8726_pinctrl_pull_mode pm; char *function_name; char *pins; char *pin_name; char *pull; phandle_t node; ssize_t len; uint32_t value; node = OF_node_from_xref(cfgxref); len = OF_getprop_alloc(node, "amlogic,function", sizeof(char), (void **)&function_name); if (len < 0) { device_printf(dev, "missing amlogic,function attribute in FDT\n"); return (ENXIO); } for (f = sc->soc.func; f->name != NULL; f++) if (strncmp(f->name, function_name, len) == 0) break; if (f->name == NULL) { device_printf(dev, "unknown function attribute %.*s in FDT\n", len, function_name); OF_prop_free(function_name); return (ENXIO); } OF_prop_free(function_name); len = OF_getprop_alloc(node, "amlogic,pull", sizeof(char), (void **)&pull); pm = aml8726_unknown_pm; if (len > 0) { if (strncmp(pull, "enable", len) == 0) pm = aml8726_enable_pm; else if (strncmp(pull, "disable", len) == 0) pm = aml8726_disable_pm; else if (strncmp(pull, "down", len) == 0) pm = aml8726_enable_down_pm; else if (strncmp(pull, "up", len) == 0) pm = aml8726_enable_up_pm; else { device_printf(dev, "unknown pull attribute %.*s in FDT\n", len, pull); OF_prop_free(pull); return (ENXIO); } } OF_prop_free(pull); /* * Setting the pull direction isn't supported on all SoC. */ switch (pm) { case aml8726_enable_down_pm: case aml8726_enable_up_pm: if (sc->soc.pud_ctrl == false) { device_printf(dev, "SoC doesn't support setting pull direction.\n"); return (ENXIO); } break; default: break; } len = OF_getprop_alloc(node, "amlogic,pins", sizeof(char), (void **)&pins); if (len < 0) { device_printf(dev, "missing amlogic,pins attribute in FDT\n"); return (ENXIO); } pin_name = pins; while (len) { for (p = f->pins; p->name != NULL; p++) if (strncmp(p->name, pin_name, len) == 0) break; if (p->name == NULL) { /* display message prior to queuing up next string */ device_printf(dev, "unknown pin attribute %.*s in FDT\n", len, pin_name); } /* queue up next string */ while (*pin_name && len) { pin_name++; len--; } if (len) { pin_name++; len--; } if (p->name == NULL) continue; for (pp = sc->soc.ppin; pp->pkg_name != NULL; pp++) if (strcmp(pp->pkg_name, p->pkg_name) == 0) break; if (pp->pkg_name == NULL) { device_printf(dev, "missing entry for package pin %s\n", p->pkg_name); continue; } if (pm != aml8726_unknown_pm && pp->pull_bits == 0x00000000) { device_printf(dev, "missing pull info for package pin %s\n", p->pkg_name); continue; } AML_PINCTRL_LOCK(sc); /* * First clear all other mux bits associated with this * package pin. This may briefly configure the pin as * GPIO ... however this should be fine since after * reset the default GPIO mode is input. */ for (cf = sc->soc.func; cf->name != NULL; cf++) for (cp = cf->pins; cp->name != NULL; cp++) { if (cp == p) continue; if (strcmp(cp->pkg_name, p->pkg_name) != 0) continue; if (cp->mux_bits == 0) continue; if (pp->aobus == false) { value = MUX_READ_4(sc, cp->mux_addr); value &= ~cp->mux_bits; MUX_WRITE_4(sc, cp->mux_addr, value); } else { value = AOMUX_READ_4(sc, cp->mux_addr); value &= ~cp->mux_bits; AOMUX_WRITE_4(sc, cp->mux_addr, value); } } /* * Now set the desired mux bits. * * In the case of GPIO there's no bits to set. */ if (p->mux_bits != 0) { if (pp->aobus == false) { value = MUX_READ_4(sc, p->mux_addr); value |= p->mux_bits; MUX_WRITE_4(sc, p->mux_addr, value); } else { value = AOMUX_READ_4(sc, p->mux_addr); value |= p->mux_bits; AOMUX_WRITE_4(sc, p->mux_addr, value); } } /* * Finally set the pull mode if it was specified. */ switch (pm) { case aml8726_enable_down_pm: case aml8726_enable_up_pm: if (pp->aobus == false) { value = PUD_READ_4(sc, pp->pull_addr); if (pm == aml8726_enable_down_pm) value &= ~pp->pull_bits; else value |= pp->pull_bits; PUD_WRITE_4(sc, pp->pull_addr, value); } else { value = AOPUD_READ_4(sc, pp->pull_addr); if (pm == aml8726_enable_down_pm) value &= ~(pp->pull_bits << 16); else value |= (pp->pull_bits << 16); AOPUD_WRITE_4(sc, pp->pull_addr, value); } /* FALLTHROUGH */ case aml8726_disable_pm: case aml8726_enable_pm: if (pp->aobus == false) { value = PEN_READ_4(sc, pp->pull_addr); if (pm == aml8726_disable_pm) value &= ~pp->pull_bits; else value |= pp->pull_bits; PEN_WRITE_4(sc, pp->pull_addr, value); } else { value = AOPEN_READ_4(sc, pp->pull_addr); if (pm == aml8726_disable_pm) value &= ~pp->pull_bits; else value |= pp->pull_bits; AOPEN_WRITE_4(sc, pp->pull_addr, value); } break; default: break; } AML_PINCTRL_UNLOCK(sc); } OF_prop_free(pins); return (0); }
static int qman_portals_fdt_attach(device_t dev) { struct dpaa_portals_softc *sc; phandle_t node, child, cpu_node; vm_paddr_t portal_pa, portal_par_pa; vm_size_t portal_size; uint32_t addr, paddr, size; ihandle_t cpu; int cpu_num, cpus, intr_rid; struct dpaa_portals_devinfo di; struct ofw_bus_devinfo ofw_di = {}; cell_t *range; int nrange; int i; cpus = 0; sc = device_get_softc(dev); sc->sc_dev = dev; node = ofw_bus_get_node(dev); /* Get this node's range */ get_addr_props(ofw_bus_get_node(device_get_parent(dev)), &paddr, &size); get_addr_props(node, &addr, &size); nrange = OF_getencprop_alloc(node, "ranges", sizeof(*range), (void **)&range); if (nrange < addr + paddr + size) return (ENXIO); portal_pa = portal_par_pa = 0; portal_size = 0; for (i = 0; i < addr; i++) { portal_pa <<= 32; portal_pa |= range[i]; } for (; i < paddr + addr; i++) { portal_par_pa <<= 32; portal_par_pa |= range[i]; } portal_pa += portal_par_pa; for (; i < size + paddr + addr; i++) { portal_size = (uintmax_t)portal_size << 32; portal_size |= range[i]; } OF_prop_free(range); sc->sc_dp_size = portal_size; sc->sc_dp_pa = portal_pa; /* Find portals tied to CPUs */ for (child = OF_child(node); child != 0; child = OF_peer(child)) { if (cpus >= mp_ncpus) break; if (!ofw_bus_node_is_compatible(child, "fsl,qman-portal")) { continue; } /* Checkout related cpu */ if (OF_getprop(child, "cpu-handle", (void *)&cpu, sizeof(cpu)) <= 0) { cpu = qman_portal_find_cpu(cpus); if (cpu <= 0) continue; } /* Acquire cpu number */ cpu_node = OF_instance_to_package(cpu); if (OF_getencprop(cpu_node, "reg", &cpu_num, sizeof(cpu_num)) <= 0) { device_printf(dev, "Could not retrieve CPU number.\n"); return (ENXIO); } cpus++; if (ofw_bus_gen_setup_devinfo(&ofw_di, child) != 0) { device_printf(dev, "could not set up devinfo\n"); continue; } resource_list_init(&di.di_res); if (ofw_bus_reg_to_rl(dev, child, addr, size, &di.di_res)) { device_printf(dev, "%s: could not process 'reg' " "property\n", ofw_di.obd_name); ofw_bus_gen_destroy_devinfo(&ofw_di); continue; } if (ofw_bus_intr_to_rl(dev, child, &di.di_res, &intr_rid)) { device_printf(dev, "%s: could not process " "'interrupts' property\n", ofw_di.obd_name); resource_list_free(&di.di_res); ofw_bus_gen_destroy_devinfo(&ofw_di); continue; } di.di_intr_rid = intr_rid; if (dpaa_portal_alloc_res(dev, &di, cpu_num)) goto err; } ofw_bus_gen_destroy_devinfo(&ofw_di); return (qman_portals_attach(dev)); err: resource_list_free(&di.di_res); ofw_bus_gen_destroy_devinfo(&ofw_di); qman_portals_detach(dev); return (ENXIO); }
static int aml8726_ccm_configure_gates(struct aml8726_ccm_softc *sc) { struct aml8726_ccm_function *f; struct aml8726_ccm_gate *g; char *function_name; char *functions; phandle_t node; ssize_t len; uint32_t value; node = ofw_bus_get_node(sc->dev); len = OF_getprop_alloc(node, "functions", sizeof(char), (void **)&functions); if (len < 0) { device_printf(sc->dev, "missing functions attribute in FDT\n"); return (ENXIO); } function_name = functions; while (len) { for (f = sc->soc; f->name != NULL; f++) if (strncmp(f->name, function_name, len) == 0) break; if (f->name == NULL) { /* display message prior to queuing up next string */ device_printf(sc->dev, "unknown function attribute %.*s in FDT\n", len, function_name); } /* queue up next string */ while (*function_name && len) { function_name++; len--; } if (len) { function_name++; len--; } if (f->name == NULL) continue; AML_CCM_LOCK(sc); /* * Enable the clock gates necessary for the function. * * In some cases a clock may be shared across functions * (meaning don't disable a clock without ensuring that * it's not required by someone else). */ for (g = f->gates; g->bits != 0x00000000; g++) { value = CSR_READ_4(sc, g->addr); value |= g->bits; CSR_WRITE_4(sc, g->addr, value); } AML_CCM_UNLOCK(sc); } OF_prop_free(functions); return (0); }
static int altera_avgen_fdt_attach(device_t dev) { struct altera_avgen_softc *sc; char *str_fileio, *str_geomio, *str_mmapio; char *str_devname; phandle_t node; pcell_t cell; int devunit, error; sc = device_get_softc(dev); sc->avg_dev = dev; sc->avg_unit = device_get_unit(dev); /* * Query driver-specific OpenFirmware properties to determine how to * expose the device via /dev. */ str_fileio = NULL; str_geomio = NULL; str_mmapio = NULL; str_devname = NULL; devunit = -1; sc->avg_width = 1; node = ofw_bus_get_node(dev); if (OF_getprop(node, "sri-cambridge,width", &cell, sizeof(cell)) > 0) sc->avg_width = cell; (void)OF_getprop_alloc(node, "sri-cambridge,fileio", sizeof(char), (void **)&str_fileio); (void)OF_getprop_alloc(node, "sri-cambridge,geomio", sizeof(char), (void **)&str_geomio); (void)OF_getprop_alloc(node, "sri-cambridge,mmapio", sizeof(char), (void **)&str_mmapio); (void)OF_getprop_alloc(node, "sri-cambridge,devname", sizeof(char), (void **)&str_devname); if (OF_getprop(node, "sri-cambridge,devunit", &cell, sizeof(cell)) > 0) devunit = cell; /* Memory allocation and checking. */ sc->avg_rid = 0; sc->avg_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->avg_rid, RF_ACTIVE); if (sc->avg_res == NULL) { device_printf(dev, "couldn't map memory\n"); return (ENXIO); } error = altera_avgen_attach(sc, str_fileio, str_geomio, str_mmapio, str_devname, devunit); if (error != 0) bus_release_resource(dev, SYS_RES_MEMORY, sc->avg_rid, sc->avg_res); if (str_fileio != NULL) OF_prop_free(str_fileio); if (str_geomio != NULL) OF_prop_free(str_geomio); if (str_mmapio != NULL) OF_prop_free(str_mmapio); if (str_devname != NULL) OF_prop_free(str_devname); return (error); }