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 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); } free(cfgtuples, M_OFWPROP); return (0); }
int ofw_bus_reg_to_rl(device_t dev, phandle_t node, pcell_t acells, pcell_t scells, struct resource_list *rl) { uint64_t phys, size; ssize_t i, j, rid, nreg, ret; uint32_t *reg; char *name; /* * This may be just redundant when having ofw_bus_devinfo * but makes this routine independent of it. */ ret = OF_getencprop_alloc(node, "name", sizeof(*name), (void **)&name); if (ret == -1) name = NULL; ret = OF_getencprop_alloc(node, "reg", sizeof(*reg), (void **)®); nreg = (ret == -1) ? 0 : ret; if (nreg % (acells + scells) != 0) { if (bootverbose) device_printf(dev, "Malformed reg property on <%s>\n", (name == NULL) ? "unknown" : name); nreg = 0; } for (i = 0, rid = 0; i < nreg; i += acells + scells, rid++) { phys = size = 0; for (j = 0; j < acells; j++) { phys <<= 32; phys |= reg[i + j]; } for (j = 0; j < scells; j++) { size <<= 32; size |= reg[i + acells + j]; } /* Skip the dummy reg property of glue devices like ssm(4). */ if (size != 0) resource_list_add(rl, SYS_RES_MEMORY, rid, phys, phys + size - 1, size); } free(name, M_OFWPROP); free(reg, M_OFWPROP); return (0); }
static int jz4780_pinctrl_configure_pins(device_t dev, phandle_t cfgxref) { struct jz4780_pinctrl_softc *sc = device_get_softc(dev); device_t chip; phandle_t node; ssize_t i, len; uint32_t *value, *pconf; int result; node = OF_node_from_xref(cfgxref); len = OF_getencprop_alloc(node, "ingenic,pins", sizeof(uint32_t) * 4, (void **)&value); if (len < 0) { device_printf(dev, "missing ingenic,pins attribute in FDT\n"); return (ENXIO); } pconf = value; result = EINVAL; for (i = 0; i < len; i++, pconf += 4) { uint32_t bias; /* Lookup the chip that handles this configuration */ chip = jz4780_pinctrl_chip_lookup(sc, pconf[0]); if (chip == NULL) { device_printf(dev, "invalid gpio controller reference in FDT\n"); goto done; } if (jz4780_pinctrl_parse_pincfg(pconf[3], &bias) != 0) { device_printf(dev, "invalid pin bias for pin %u on %s in FDT\n", pconf[1], ofw_bus_get_name(chip)); goto done; } result = JZ4780_GPIO_CONFIGURE_PIN(chip, pconf[1], pconf[2], bias); if (result != 0) { device_printf(dev, "failed to configure pin %u on %s\n", pconf[1], ofw_bus_get_name(chip)); goto done; } } result = 0; done: free(value, M_OFWPROP); return (result); }
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 ofw_bus_msimap(phandle_t node, uint16_t pci_rid, phandle_t *msi_parent, uint32_t *msi_rid) { pcell_t *map, mask, msi_base, rid_base, rid_length; ssize_t len; uint32_t masked_rid, rid; int err, i; /* TODO: This should be OF_searchprop_alloc if we had it */ len = OF_getencprop_alloc(node, "msi-map", sizeof(*map), (void **)&map); if (len < 0) { if (msi_parent != NULL) { *msi_parent = 0; OF_getencprop(node, "msi-parent", msi_parent, sizeof(*msi_parent)); } if (msi_rid != NULL) *msi_rid = pci_rid; return (0); } err = ENOENT; rid = 0; mask = 0xffffffff; OF_getencprop(node, "msi-map-mask", &mask, sizeof(mask)); masked_rid = pci_rid & mask; for (i = 0; i < len; i += 4) { rid_base = map[i + 0]; rid_length = map[i + 3]; if (masked_rid < rid_base || masked_rid >= (rid_base + rid_length)) continue; msi_base = map[i + 2]; if (msi_parent != NULL) *msi_parent = map[i + 1]; if (msi_rid != NULL) *msi_rid = masked_rid - rid_base + msi_base; err = 0; break; } free(map, M_OFWPROP); return (err); }
void ofw_bus_setup_iinfo(phandle_t node, struct ofw_bus_iinfo *ii, int intrsz) { pcell_t addrc; int msksz; if (OF_getencprop(node, "#address-cells", &addrc, sizeof(addrc)) == -1) addrc = 2; ii->opi_addrc = addrc * sizeof(pcell_t); ii->opi_imapsz = OF_getencprop_alloc(node, "interrupt-map", 1, (void **)&ii->opi_imap); if (ii->opi_imapsz > 0) { msksz = OF_getencprop_alloc(node, "interrupt-map-mask", 1, (void **)&ii->opi_imapmsk); /* * Failure to get the mask is ignored; a full mask is used * then. We barf on bad mask sizes, however. */ if (msksz != -1 && msksz != ii->opi_addrc + intrsz) panic("ofw_bus_setup_iinfo: bad interrupt-map-mask " "property!"); } }
/* * Parse property that contain list of xrefs and values * (like standard "clocks" and "resets" properties) * Input arguments: * node - consumers device node * list_name - name of parsed list - "clocks" * cells_name - name of size property - "#clock-cells" * idx - the index of the requested list entry, or, if -1, an indication * to return the number of entries in the parsed list. * Output arguments: * producer - handle of producer * ncells - number of cells in result or the number of items in the list when * idx == -1. * cells - array of decoded cells */ static int ofw_bus_parse_xref_list_internal(phandle_t node, const char *list_name, const char *cells_name, int idx, phandle_t *producer, int *ncells, pcell_t **cells) { phandle_t pnode; phandle_t *elems; uint32_t pcells; int rv, i, j, nelems, cnt; elems = NULL; nelems = OF_getencprop_alloc(node, list_name, sizeof(*elems), (void **)&elems); if (nelems <= 0) return (ENOENT); rv = (idx == -1) ? 0 : ENOENT; for (i = 0, cnt = 0; i < nelems; i += pcells, cnt++) { pnode = elems[i++]; if (OF_getencprop(OF_node_from_xref(pnode), cells_name, &pcells, sizeof(pcells)) == -1) { printf("Missing %s property\n", cells_name); rv = ENOENT; break; } if ((i + pcells) > nelems) { printf("Invalid %s property value <%d>\n", cells_name, pcells); rv = ERANGE; break; } if (cnt == idx) { *cells= malloc(pcells * sizeof(**cells), M_OFWPROP, M_WAITOK); *producer = pnode; *ncells = pcells; for (j = 0; j < pcells; j++) (*cells)[j] = elems[i + j]; rv = 0; break; } } if (elems != NULL) free(elems, M_OFWPROP); if (idx == -1 && rv == 0) *ncells = cnt; return (rv); }
/* * 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; } } free(resets, M_OFWPROP); return (anyerrors ? ENXIO : 0); }
/* * Loop through all the tuples in the clocks= property for a device, enabling or * disabling each clock. * * Be liberal about errors for now: warn about a failure to enable but keep * trying with any other clocks in the list. Return ENXIO if any errors were * found, and let the caller decide whether the problem is fatal. */ static int enable_disable_all(device_t consumer, boolean_t enable) { phandle_t cnode; device_t clockdev; int clocknum, err, i, ncells; uint32_t *clks; boolean_t anyerrors; cnode = ofw_bus_get_node(consumer); ncells = OF_getencprop_alloc(cnode, "clocks", sizeof(*clks), (void **)&clks); if (enable && ncells < 2) { device_printf(consumer, "Warning: No clocks specified in fdt " "data; device may not function."); return (ENXIO); } anyerrors = false; for (i = 0; i < ncells; i += 2) { clockdev = OF_device_from_xref(clks[i]); clocknum = clks[i + 1]; if (clockdev == NULL) { if (enable) device_printf(consumer, "Warning: can not find " "driver for clock number %u; device may not " "function\n", clocknum); anyerrors = true; continue; } if (enable) err = FDT_CLOCK_ENABLE(clockdev, clocknum); else err = FDT_CLOCK_DISABLE(clockdev, clocknum); if (err != 0) { if (enable) device_printf(consumer, "Warning: failed to " "enable clock number %u; device may not " "function\n", clocknum); anyerrors = true; } } free(clks, M_OFWPROP); return (anyerrors ? ENXIO : 0); }
int tegra_drm_encoder_attach(struct tegra_drm_encoder *output, phandle_t node) { int rv; phandle_t ddc; /* XXX parse output panel here */ rv = OF_getencprop_alloc(node, "nvidia,edid", (void **)&output->edid); /* EDID exist but have invalid size */ if ((rv >= 0) && (rv != sizeof(struct edid))) { device_printf(output->dev, "Malformed \"nvidia,edid\" property\n"); if (output->edid != NULL) free(output->edid, M_OFWPROP); return (ENXIO); } gpio_pin_get_by_ofw_property(output->dev, node, "nvidia,hpd-gpio", &output->gpio_hpd); ddc = 0; OF_getencprop(node, "nvidia,ddc-i2c-bus", &ddc, sizeof(ddc)); if (ddc > 0) output->ddc = OF_device_from_xref(ddc); if ((output->edid == NULL) && (output->ddc == NULL)) return (ENXIO); if (output->gpio_hpd != NULL) { output->connector.polled = // DRM_CONNECTOR_POLL_HPD; DRM_CONNECTOR_POLL_DISCONNECT | DRM_CONNECTOR_POLL_CONNECT; } return (0); }
int fdt_clock_get_info(device_t consumer, int n, struct fdt_clock_info *info) { phandle_t cnode; device_t clockdev; int clocknum, err, ncells; uint32_t *clks; cnode = ofw_bus_get_node(consumer); ncells = OF_getencprop_alloc(cnode, "clocks", sizeof(*clks), (void **)&clks); if (ncells <= 0) return (ENXIO); n *= 2; if (ncells <= n) err = ENXIO; else { clockdev = OF_device_from_xref(clks[n]); if (clockdev == NULL) err = ENXIO; else { /* * Make struct contents minimally valid, then call * provider to fill in what it knows (provider can * override anything it wants to). */ clocknum = clks[n + 1]; bzero(info, sizeof(*info)); info->provider = clockdev; info->index = clocknum; info->name = ""; err = FDT_CLOCK_GET_INFO(clockdev, clocknum, info); } } free(clks, M_OFWPROP); return (err); }
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 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 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 struct ofwbus_devinfo * ofwbus_setup_dinfo(device_t dev, phandle_t node) { struct ofwbus_softc *sc; struct ofwbus_devinfo *ndi; uint32_t *reg, *intr, icells; uint64_t phys, size; phandle_t iparent; int i, j; 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->ndi_obdinfo, node) != 0) { free(ndi, M_DEVBUF); return (NULL); } if (OFWBUS_EXCLUDED(ndi->ndi_obdinfo.obd_name, ndi->ndi_obdinfo.obd_type)) { ofw_bus_gen_destroy_devinfo(&ndi->ndi_obdinfo); free(ndi, M_DEVBUF); return (NULL); } resource_list_init(&ndi->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->ndi_obdinfo.obd_name); nreg = 0; } for (i = 0; i < nreg; i += sc->acells + sc->scells) { 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]; } /* Skip the dummy reg property of glue devices like ssm(4). */ if (size != 0) resource_list_add(&ndi->ndi_rl, SYS_RES_MEMORY, i, phys, phys + size - 1, size); } free(reg, M_OFWPROP); nintr = OF_getencprop_alloc(node, "interrupts", sizeof(*intr), (void **)&intr); if (nintr > 0) { iparent = 0; OF_searchencprop(node, "interrupt-parent", &iparent, sizeof(iparent)); OF_searchencprop(OF_xref_phandle(iparent), "#interrupt-cells", &icells, sizeof(icells)); for (i = 0; i < nintr; i+= icells) { intr[i] = ofw_bus_map_intr(dev, iparent, icells, &intr[i]); resource_list_add(&ndi->ndi_rl, SYS_RES_IRQ, i, intr[i], intr[i], 1); } free(intr, M_OFWPROP); } return (ndi); }
int ofw_bus_intr_to_rl(device_t dev, phandle_t node, struct resource_list *rl, int *rlen) { phandle_t iparent; uint32_t icells, *intr; int err, i, irqnum, nintr, rid; boolean_t extended; nintr = OF_getencprop_alloc(node, "interrupts", sizeof(*intr), (void **)&intr); if (nintr > 0) { iparent = ofw_bus_find_iparent(node); if (iparent == 0) { device_printf(dev, "No interrupt-parent found, " "assuming direct parent\n"); iparent = OF_parent(node); iparent = OF_xref_from_node(iparent); } 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; } extended = false; } else { nintr = OF_getencprop_alloc(node, "interrupts-extended", sizeof(*intr), (void **)&intr); if (nintr <= 0) return (0); extended = true; } err = 0; rid = 0; for (i = 0; i < nintr; i += icells) { if (extended) { iparent = intr[i++]; if (OF_searchencprop(OF_node_from_xref(iparent), "#interrupt-cells", &icells, sizeof(icells)) == -1) { device_printf(dev, "Missing #interrupt-cells " "property\n"); err = ENOENT; break; } if (icells < 1 || (i + icells) > nintr) { device_printf(dev, "Invalid #interrupt-cells " "property value <%d>\n", icells); err = ERANGE; break; } } irqnum = ofw_bus_map_intr(dev, iparent, icells, &intr[i]); resource_list_add(rl, SYS_RES_IRQ, rid++, irqnum, irqnum, 1); } if (rlen != NULL) *rlen = rid; free(intr, M_OFWPROP); return (err); }
static int aml8726_usb_phy_attach(device_t dev) { struct aml8726_usb_phy_softc *sc = device_get_softc(dev); int err; int npwr_en; pcell_t *prop; phandle_t node; ssize_t len; uint32_t div; uint32_t i; uint32_t mode_a; uint32_t mode_b; uint32_t value; sc->dev = dev; if (aml8726_usb_phy_mode("/soc/usb@c9040000", &mode_a) != 0) { device_printf(dev, "missing usb@c9040000 node in FDT\n"); return (ENXIO); } if (aml8726_usb_phy_mode("/soc/usb@c90c0000", &mode_b) != 0) { device_printf(dev, "missing usb@c90c0000 node in FDT\n"); return (ENXIO); } if (bus_alloc_resources(dev, aml8726_usb_phy_spec, sc->res)) { device_printf(dev, "can not allocate resources for device\n"); return (ENXIO); } node = ofw_bus_get_node(dev); err = 0; len = OF_getencprop_alloc(node, "usb-pwr-en", 3 * sizeof(pcell_t), (void **)&prop); npwr_en = (len > 0) ? len : 0; sc->npwr_en = 0; sc->pwr_en = (struct aml8726_usb_phy_gpio *) malloc(npwr_en * sizeof (*sc->pwr_en), M_DEVBUF, M_WAITOK); for (i = 0; i < npwr_en; i++) { sc->pwr_en[i].dev = OF_device_from_xref(prop[i * 3]); sc->pwr_en[i].pin = prop[i * 3 + 1]; sc->pwr_en[i].pol = prop[i * 3 + 2]; if (sc->pwr_en[i].dev == NULL) { err = 1; break; } } free(prop, M_OFWPROP); if (err) { device_printf(dev, "unable to parse gpio\n"); goto fail; } /* Turn on power by setting pin and then enabling output driver. */ for (i = 0; i < npwr_en; i++) { if (GPIO_PIN_SET(sc->pwr_en[i].dev, sc->pwr_en[i].pin, PIN_ON_FLAG(sc->pwr_en[i].pol)) != 0 || GPIO_PIN_SETFLAGS(sc->pwr_en[i].dev, sc->pwr_en[i].pin, GPIO_PIN_OUTPUT) != 0) { device_printf(dev, "could not use gpio to control power\n"); goto fail; } sc->npwr_en++; } /* * Configure the clock source and divider. */ div = 2; value = CSR_READ_4(sc, AML_USB_PHY_CFG_REG); value &= ~(AML_USB_PHY_CFG_CLK_DIV_MASK | AML_USB_PHY_CFG_CLK_SEL_MASK); value &= ~(AML_USB_PHY_CFG_A_RST | AML_USB_PHY_CFG_B_RST); value &= ~(AML_USB_PHY_CFG_A_PLL_RST | AML_USB_PHY_CFG_B_PLL_RST); value &= ~(AML_USB_PHY_CFG_A_PHYS_RST | AML_USB_PHY_CFG_B_PHYS_RST); value &= ~(AML_USB_PHY_CFG_A_POR | AML_USB_PHY_CFG_B_POR); value |= AML_USB_PHY_CFG_CLK_SEL_XTAL; value |= ((div - 1) << AML_USB_PHY_CFG_CLK_DIV_SHIFT) & AML_USB_PHY_CFG_CLK_DIV_MASK; value |= AML_USB_PHY_CFG_CLK_EN; CSR_WRITE_4(sc, AML_USB_PHY_CFG_REG, value); CSR_BARRIER(sc, AML_USB_PHY_CFG_REG); /* * Issue the reset sequence. */ value |= (AML_USB_PHY_CFG_A_RST | AML_USB_PHY_CFG_B_RST); CSR_WRITE_4(sc, AML_USB_PHY_CFG_REG, value); CSR_BARRIER(sc, AML_USB_PHY_CFG_REG); DELAY(200); value &= ~(AML_USB_PHY_CFG_A_RST | AML_USB_PHY_CFG_B_RST); CSR_WRITE_4(sc, AML_USB_PHY_CFG_REG, value); CSR_BARRIER(sc, AML_USB_PHY_CFG_REG); DELAY(200); value |= (AML_USB_PHY_CFG_A_PLL_RST | AML_USB_PHY_CFG_B_PLL_RST); CSR_WRITE_4(sc, AML_USB_PHY_CFG_REG, value); CSR_BARRIER(sc, AML_USB_PHY_CFG_REG); DELAY(200); value &= ~(AML_USB_PHY_CFG_A_PLL_RST | AML_USB_PHY_CFG_B_PLL_RST); CSR_WRITE_4(sc, AML_USB_PHY_CFG_REG, value); CSR_BARRIER(sc, AML_USB_PHY_CFG_REG); DELAY(200); value |= (AML_USB_PHY_CFG_A_PHYS_RST | AML_USB_PHY_CFG_B_PHYS_RST); CSR_WRITE_4(sc, AML_USB_PHY_CFG_REG, value); CSR_BARRIER(sc, AML_USB_PHY_CFG_REG); DELAY(200); value &= ~(AML_USB_PHY_CFG_A_PHYS_RST | AML_USB_PHY_CFG_B_PHYS_RST); CSR_WRITE_4(sc, AML_USB_PHY_CFG_REG, value); CSR_BARRIER(sc, AML_USB_PHY_CFG_REG); DELAY(200); value |= (AML_USB_PHY_CFG_A_POR | AML_USB_PHY_CFG_B_POR); CSR_WRITE_4(sc, AML_USB_PHY_CFG_REG, value); CSR_BARRIER(sc, AML_USB_PHY_CFG_REG); DELAY(200); /* * Enable by clearing the power on reset. */ value &= ~(AML_USB_PHY_CFG_A_POR | AML_USB_PHY_CFG_B_POR); CSR_WRITE_4(sc, AML_USB_PHY_CFG_REG, value); CSR_BARRIER(sc, AML_USB_PHY_CFG_REG); DELAY(200); /* * Check if the clock was detected. */ value = CSR_READ_4(sc, AML_USB_PHY_CFG_REG); if ((value & AML_USB_PHY_CFG_CLK_DETECTED) != AML_USB_PHY_CFG_CLK_DETECTED) device_printf(dev, "PHY Clock not detected\n"); /* * Configure the mode for each port. */ value = CSR_READ_4(sc, AML_USB_PHY_MISC_A_REG); value &= ~(AML_USB_PHY_MISC_ID_OVERIDE_EN | AML_USB_PHY_MISC_ID_OVERIDE_DEVICE | AML_USB_PHY_MISC_ID_OVERIDE_HOST); value |= mode_a; CSR_WRITE_4(sc, AML_USB_PHY_MISC_A_REG, value); value = CSR_READ_4(sc, AML_USB_PHY_MISC_B_REG); value &= ~(AML_USB_PHY_MISC_ID_OVERIDE_EN | AML_USB_PHY_MISC_ID_OVERIDE_DEVICE | AML_USB_PHY_MISC_ID_OVERIDE_HOST); value |= mode_b; CSR_WRITE_4(sc, AML_USB_PHY_MISC_B_REG, value); CSR_BARRIER(sc, AML_USB_PHY_MISC_B_REG); return (0); fail: /* In the event of problems attempt to turn things back off. */ i = sc->npwr_en; while (i-- != 0) { GPIO_PIN_SET(sc->pwr_en[i].dev, sc->pwr_en[i].pin, PIN_OFF_FLAG(sc->pwr_en[i].pol)); } free (sc->pwr_en, M_DEVBUF); sc->pwr_en = NULL; bus_release_resources(dev, aml8726_usb_phy_spec, sc->res); return (ENXIO); }