Esempio n. 1
0
int
intr_fdt_map_irq(phandle_t iparent, pcell_t *intr, int icells)
{
	fdt_pic_decode_t intr_decode;
	phandle_t intr_parent;
	int i, rv, interrupt, trig, pol;

	intr_parent = OF_node_from_xref(iparent);
	for (i = 0; i < icells; i++)
		intr[i] = cpu_to_fdt32(intr[i]);

	for (i = 0; fdt_pic_table[i] != NULL; i++) {
		intr_decode = fdt_pic_table[i];
		rv = intr_decode(intr_parent, intr, &interrupt, &trig, &pol);

		if (rv == 0) {
			/* This was recognized as our PIC and decoded. */
			interrupt = FDT_MAP_IRQ(intr_parent, interrupt);
			return (interrupt);
		}
	}

	/* Not in table, so guess */
	interrupt = FDT_MAP_IRQ(intr_parent, fdt32_to_cpu(intr[0]));

	return (interrupt);
}
Esempio n. 2
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);
	}

	free(cfgtuples, M_OFWPROP);

	return (0);
}
Esempio n. 3
0
static int
aw_fdt_configure_pins(device_t dev, phandle_t cfgxref)
{
	struct a10_gpio_softc *sc;
	phandle_t node;
	const char **pinlist = NULL;
	char *pin_function = NULL;
	uint32_t pin_drive, pin_pull;
	int pins_nb, pin_num, pin_func, i, ret;

	sc = device_get_softc(dev);
	node = OF_node_from_xref(cfgxref);
	ret = 0;

	/* Getting all prop for configuring pins */
	pins_nb = ofw_bus_string_list_to_array(node, "allwinner,pins", &pinlist);
	if (pins_nb <= 0)
		return (ENOENT);
	if (OF_getprop_alloc(node, "allwinner,function",
			     sizeof(*pin_function),
			     (void **)&pin_function) == -1) {
		ret = ENOENT;
		goto out;
	}
	if (OF_getencprop(node, "allwinner,drive",
			  &pin_drive, sizeof(pin_drive)) == -1) {
		ret = ENOENT;
		goto out;
	}
	if (OF_getencprop(node, "allwinner,pull",
			  &pin_pull, sizeof(pin_pull)) == -1) {
		ret = ENOENT;
		goto out;
	}

	/* Configure each pin to the correct function, drive and pull */
	for (i = 0; i < pins_nb; i++) {
		pin_num = aw_find_pinnum_by_name(sc, pinlist[i]);
		if (pin_num == -1) {
			ret = ENOENT;
			goto out;
		}
		pin_func = aw_find_pin_func(sc, pin_num, pin_function);
		if (pin_func == -1) {
			ret = ENOENT;
			goto out;
		}

		A10_GPIO_LOCK(sc);
		a10_gpio_set_function(sc, pin_num, pin_func);
		a10_gpio_set_drv(sc, pin_num, pin_drive);
		a10_gpio_set_pud(sc, pin_num, pin_pull);
		A10_GPIO_UNLOCK(sc);
	}

 out:
	free(pinlist, M_OFWPROP);
	free(pin_function, M_OFWPROP);
	return (ret);
}
Esempio n. 4
0
/* Return the package handle that corresponds to an instance handle. */
static phandle_t
ofw_fdt_instance_to_package(ofw_t ofw, ihandle_t instance)
{

	/* Where real OF uses ihandles in the tree, FDT uses xref phandles */
	return (OF_node_from_xref(instance));
}
Esempio n. 5
0
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);
}
Esempio n. 6
0
static int
mtk_pinctrl_configure(device_t dev, phandle_t cfgxref)
{
	struct mtk_pin_group *pintable;
	phandle_t node, child;
	uint32_t socid;
	int ret;

	node = OF_node_from_xref(cfgxref);
	ret = 0;

	/* Now, get the system type, so we can get the proper GPIO mode array */
	socid = mtk_soc_get_socid();

	switch (socid) {
	case MTK_SOC_RT3050: /* fallthrough */
	case MTK_SOC_RT3052:
	case MTK_SOC_RT3350:
		pintable = rt3050_pintable;
		break;
	case MTK_SOC_RT3352:
		pintable = rt3352_pintable;
		break;
	case MTK_SOC_RT3662: /* fallthrough */
	case MTK_SOC_RT3883:
		pintable = rt3883_pintable;
		break;
	case MTK_SOC_RT5350:
		pintable = rt5350_pintable;
		break;
	case MTK_SOC_MT7620A: /* fallthrough */
	case MTK_SOC_MT7620N:
		pintable = mt7620_pintable;
		break;
	case MTK_SOC_MT7628: /* fallthrough */
	case MTK_SOC_MT7688:
		pintable = mt7628_pintable;
		break;
	case MTK_SOC_MT7621:
		pintable = mt7621_pintable;
		break;
	default:
		ret = ENOENT;
		goto out;
	}

	/*
	 * OpenWRT dts files have single child within the pinctrl nodes, which
	 * contains the 'ralink,group' and 'ralink,function' properties.
	 */ 
	for (child = OF_child(node); child != 0 && child != -1;
	    child = OF_peer(child)) {
		if ((ret = mtk_pinctrl_process_node(dev, pintable, child)) != 0)
			return (ret);
	}

out:
	return (ret);
}
Esempio n. 7
0
static int
rk30_gpio_init(void)
{
	phandle_t child, parent, root, ctrl;
	pcell_t gpios[MAX_PINS_PER_NODE * GPIOS_PROP_CELLS];
	struct gpio_ctrl_entry *e;
	int len, rv;

	root = OF_finddevice("/");
	len = 0;
	parent = root;

	/* Traverse through entire tree to find nodes with 'gpios' prop */
	for (child = OF_child(parent); child != 0; child = OF_peer(child)) {

		/* Find a 'leaf'. Start the search from this node. */
		while (OF_child(child)) {
			parent = child;
			child = OF_child(child);
		}
		if ((len = OF_getproplen(child, "gpios")) > 0) {

			if (len > sizeof(gpios))
				return (ENXIO);

			/* Get 'gpios' property. */
			OF_getprop(child, "gpios", &gpios, len);

			e = (struct gpio_ctrl_entry *)&gpio_controllers;

			/* Find and call a handler. */
			for (; e->compat; e++) {
				/*
				 * First cell of 'gpios' property should
				 * contain a ref. to a node defining GPIO
				 * controller.
				 */
				ctrl = OF_node_from_xref(fdt32_to_cpu(gpios[0]));

				if (fdt_is_compatible(ctrl, e->compat))
					/* Call a handler. */
					if ((rv = e->handler(ctrl,
					    (pcell_t *)&gpios, len)))
						return (rv);
			}
		}

		if (OF_peer(child) == 0) {
			/* No more siblings. */
			child = parent;
			parent = OF_parent(child);
		}
	}
	return (0);
}
Esempio n. 8
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);
}
Esempio n. 9
0
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);
}
Esempio n. 10
0
/*
 * Map an interrupt using the firmware reg, interrupt-map and
 * interrupt-map-mask properties.
 * The interrupt property to be mapped must be of size intrsz, and pointed to
 * by intr.  The regs property of the node for which the mapping is done must
 * be passed as regs. This property is an array of register specifications;
 * the size of the address part of such a specification must be passed as
 * physsz.  Only the first element of the property is used.
 * imap and imapsz hold the interrupt mask and it's size.
 * imapmsk is a pointer to the interrupt-map-mask property, which must have
 * a size of physsz + intrsz; it may be NULL, in which case a full mask is
 * assumed.
 * maskbuf must point to a buffer of length physsz + intrsz.
 * The interrupt is returned in result, which must point to a buffer of length
 * rintrsz (which gives the expected size of the mapped interrupt).
 * Returns number of cells in the interrupt if a mapping was found, 0 otherwise.
 */
int
ofw_bus_search_intrmap(void *intr, int intrsz, void *regs, int physsz,
    void *imap, int imapsz, void *imapmsk, void *maskbuf, void *result,
    int rintrsz, phandle_t *iparent)
{
	phandle_t parent;
	uint8_t *ref = maskbuf;
	uint8_t *uiintr = intr;
	uint8_t *uiregs = regs;
	uint8_t *uiimapmsk = imapmsk;
	uint8_t *mptr;
	pcell_t pintrsz;
	int i, rsz, tsz;

	rsz = -1;
	if (imapmsk != NULL) {
		for (i = 0; i < physsz; i++)
			ref[i] = uiregs[i] & uiimapmsk[i];
		for (i = 0; i < intrsz; i++)
			ref[physsz + i] = uiintr[i] & uiimapmsk[physsz + i];
	} else {
		bcopy(regs, ref, physsz);
		bcopy(intr, ref + physsz, intrsz);
	}

	mptr = imap;
	i = imapsz;
	while (i > 0) {
		bcopy(mptr + physsz + intrsz, &parent, sizeof(parent));
		if (OF_searchencprop(OF_node_from_xref(parent),
		    "#interrupt-cells", &pintrsz, sizeof(pintrsz)) == -1)
			pintrsz = 1;	/* default */
		pintrsz *= sizeof(pcell_t);

		/* Compute the map stride size. */
		tsz = physsz + intrsz + sizeof(phandle_t) + pintrsz;
		KASSERT(i >= tsz, ("ofw_bus_search_intrmap: truncated map"));

		if (bcmp(ref, mptr, physsz + intrsz) == 0) {
			bcopy(mptr + physsz + intrsz + sizeof(parent),
			    result, MIN(rintrsz, pintrsz));

			if (iparent != NULL)
				*iparent = parent;
			return (pintrsz/sizeof(pcell_t));
		}
		mptr += tsz;
		i -= tsz;
	}
	return (0);
}
Esempio n. 11
0
/*
 * 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);
}
Esempio n. 12
0
static phandle_t
mii_fdt_get_phynode(phandle_t macnode)
{
	static const char *props[] = {
	    "phy-handle", "phy", "phy-device"
	};
	pcell_t xref;
	u_int i;

	for (i = 0; i < nitems(props); ++i) {
		if (OF_getencprop(macnode, props[i], &xref, sizeof(xref)) > 0)
			return (OF_node_from_xref(xref));
	}
	return (-1);
}
Esempio n. 13
0
/*
 * 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);
}
Esempio n. 14
0
static int
jz4780_pinctrl_parse_pincfg(phandle_t pincfgxref, uint32_t *bias_value)
{
	phandle_t pincfg_node;
	int i;

	pincfg_node = OF_node_from_xref(pincfgxref);
	for (i = 0; i < nitems(jx4780_bias_table); i++) {
		if (OF_hasprop(pincfg_node, jx4780_bias_table[i].name)) {
			*bias_value = jx4780_bias_table[i].bias;
			return 0;
		}
	}

	return -1;
}
Esempio n. 15
0
static int pinmux_configure(device_t dev, phandle_t cfgxref)
{
	struct pinmux_softc *sc;
	phandle_t node, cfgnode;
	int rv;

	sc = device_get_softc(dev);
	cfgnode = OF_node_from_xref(cfgxref);


	for (node = OF_child(cfgnode); node != 0; node = OF_peer(node)) {
		if (!fdt_is_enabled(node))
			continue;
		rv = pinmux_process_node(sc, node);
	}
	return (0);
}
Esempio n. 16
0
/*
 * Add an interrupt to the dev's resource list if present
 */
static void
macio_add_intr(phandle_t devnode, struct macio_devinfo *dinfo)
{
	phandle_t iparent;
	int	*intr;
	int	i, nintr;
	int 	icells;

	if (dinfo->mdi_ninterrupts >= 6) {
		printf("macio: device has more than 6 interrupts\n");
		return;
	}

	nintr = OF_getprop_alloc(devnode, "interrupts", sizeof(*intr), 
		(void **)&intr);
	if (nintr == -1) {
		nintr = OF_getprop_alloc(devnode, "AAPL,interrupts", 
			sizeof(*intr), (void **)&intr);
		if (nintr == -1)
			return;
	}

	if (intr[0] == -1)
		return;

	if (OF_getprop(devnode, "interrupt-parent", &iparent, sizeof(iparent))
	    <= 0)
		panic("Interrupt but no interrupt parent!\n");

	if (OF_getprop(OF_node_from_xref(iparent), "#interrupt-cells", &icells,
	    sizeof(icells)) <= 0)
		icells = 1;

	for (i = 0; i < nintr; i+=icells) {
		u_int irq = MAP_IRQ(iparent, intr[i]);

		resource_list_add(&dinfo->mdi_resources, SYS_RES_IRQ,
		    dinfo->mdi_ninterrupts, irq, irq, 1);

		dinfo->mdi_interrupts[dinfo->mdi_ninterrupts] = irq;
		dinfo->mdi_ninterrupts++;
	}
}
Esempio n. 17
0
/*
 * Map an interrupt using the firmware reg, interrupt-map and
 * interrupt-map-mask properties.
 * The interrupt property to be mapped must be of size intrsz, and pointed to
 * by intr.  The regs property of the node for which the mapping is done must
 * be passed as regs. This property is an array of register specifications;
 * the size of the address part of such a specification must be passed as
 * physsz.  Only the first element of the property is used.
 * imap and imapsz hold the interrupt mask and it's size.
 * imapmsk is a pointer to the interrupt-map-mask property, which must have
 * a size of physsz + intrsz; it may be NULL, in which case a full mask is
 * assumed.
 * maskbuf must point to a buffer of length physsz + intrsz.
 * The interrupt is returned in result, which must point to a buffer of length
 * rintrsz (which gives the expected size of the mapped interrupt).
 * Returns number of cells in the interrupt if a mapping was found, 0 otherwise.
 */
int
ofw_bus_search_intrmap(void *intr, int intrsz, void *regs, int physsz,
    void *imap, int imapsz, void *imapmsk, void *maskbuf, void *result,
    int rintrsz, phandle_t *iparent)
{
	phandle_t parent;
	uint8_t *ref = maskbuf;
	uint8_t *uiintr = intr;
	uint8_t *uiregs = regs;
	uint8_t *uiimapmsk = imapmsk;
	uint8_t *mptr;
	pcell_t paddrsz;
	pcell_t pintrsz;
	int i, rsz, tsz;

	rsz = -1;
	if (imapmsk != NULL) {
		for (i = 0; i < physsz; i++)
			ref[i] = uiregs[i] & uiimapmsk[i];
		for (i = 0; i < intrsz; i++)
			ref[physsz + i] = uiintr[i] & uiimapmsk[physsz + i];
	} else {
		bcopy(regs, ref, physsz);
		bcopy(intr, ref + physsz, intrsz);
	}

	mptr = imap;
	i = imapsz;
	paddrsz = 0;
	while (i > 0) {
		bcopy(mptr + physsz + intrsz, &parent, sizeof(parent));
#ifndef OFW_IMAP_NO_IPARENT_ADDR_CELLS
		/*
		 * Find if we need to read the parent address data.
		 * CHRP-derived OF bindings, including ePAPR-compliant FDTs,
		 * use this as an optional part of the specifier.
		 */
		if (OF_getencprop(OF_node_from_xref(parent),
		    "#address-cells", &paddrsz, sizeof(paddrsz)) == -1)
			paddrsz = 0;	/* default */
		paddrsz *= sizeof(pcell_t);
#endif

		if (OF_searchencprop(OF_node_from_xref(parent),
		    "#interrupt-cells", &pintrsz, sizeof(pintrsz)) == -1)
			pintrsz = 1;	/* default */
		pintrsz *= sizeof(pcell_t);

		/* Compute the map stride size. */
		tsz = physsz + intrsz + sizeof(phandle_t) + paddrsz + pintrsz;
		KASSERT(i >= tsz, ("ofw_bus_search_intrmap: truncated map"));

		if (bcmp(ref, mptr, physsz + intrsz) == 0) {
			bcopy(mptr + physsz + intrsz + sizeof(parent) + paddrsz,
			    result, MIN(rintrsz, pintrsz));

			if (iparent != NULL)
				*iparent = parent;
			return (pintrsz/sizeof(pcell_t));
		}
		mptr += tsz;
		i -= tsz;
	}
	return (0);
}
Esempio n. 18
0
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);
}
Esempio n. 19
0
int
ofw_bus_intr_by_rid(device_t dev, phandle_t node, int wanted_rid,
    phandle_t *producer, int *ncells, pcell_t **cells)
{
	phandle_t iparent;
	uint32_t icells, *intr;
	int err, i, nintr, rid;
	boolean_t extended;

	nintr = OF_getencprop_alloc_multi(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_multi(node, "interrupts-extended",
		    sizeof(*intr), (void **)&intr);
		if (nintr <= 0)
			return (ESRCH);
		extended = true;
	}
	err = ESRCH;
	rid = 0;
	for (i = 0; i < nintr; i += icells, rid++) {
		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;
			}
		}
		if (rid == wanted_rid) {
			*cells = malloc(icells * sizeof(**cells), M_OFWPROP,
			    M_WAITOK);
			*producer = iparent;
			*ncells= icells;
			memcpy(*cells, intr + i, icells * sizeof(**cells));
			err = 0;
			break;
		}
	}
	free(intr, M_OFWPROP);
	return (err);
}
Esempio n. 20
0
static int
ofw_pcibus_assign_interrupt(device_t dev, device_t child)
{
	ofw_pci_intr_t intr[2];
	phandle_t node, iparent;
	int isz, icells;

	node = ofw_bus_get_node(child);

	if (node == -1) {
		/* Non-firmware enumerated child, use standard routing */
	
		intr[0] = pci_get_intpin(child);
		return (PCIB_ROUTE_INTERRUPT(device_get_parent(dev), child, 
		    intr[0]));
	}
	
	/*
	 * Try to determine the node's interrupt parent so we know which
	 * PIC to use.
	 */

	iparent = -1;
	if (OF_getprop(node, "interrupt-parent", &iparent, sizeof(iparent)) < 0)
		iparent = -1;
	icells = 1;
	if (iparent != -1)
		OF_getprop(OF_node_from_xref(iparent), "#interrupt-cells",
		    &icells, sizeof(icells));
	
	/*
	 * Any AAPL,interrupts property gets priority and is
	 * fully specified (i.e. does not need routing)
	 */

	isz = OF_getprop(node, "AAPL,interrupts", intr, sizeof(intr));
	if (isz == sizeof(intr[0])*icells)
		return ((iparent == -1) ? intr[0] : ofw_bus_map_intr(dev,
		    iparent, icells, intr));

	isz = OF_getprop(node, "interrupts", intr, sizeof(intr));
	if (isz == sizeof(intr[0])*icells) {
		if (iparent != -1)
			intr[0] = ofw_bus_map_intr(dev, iparent, icells, intr);
	} else {
		/* No property: our best guess is the intpin. */
		intr[0] = pci_get_intpin(child);
	}
	
	/*
	 * If we got intr from a property, it may or may not be an intpin.
	 * For on-board devices, it frequently is not, and is completely out
	 * of the valid intpin range.  For PCI slots, it hopefully is,
	 * otherwise we will have trouble interfacing with non-OFW buses
	 * such as cardbus.
	 * Since we cannot tell which it is without violating layering, we
	 * will always use the route_interrupt method, and treat exceptions
	 * on the level they become apparent.
	 */
	return (PCIB_ROUTE_INTERRUPT(device_get_parent(dev), child, intr[0]));
}
Esempio n. 21
0
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 **)&reg);
	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);
}
Esempio n. 22
0
static int
mv_gpio_setup_interrupts(struct mv_gpio_softc *sc, phandle_t node)
{
	phandle_t iparent;
	pcell_t irq_cells;
	int i, size;

	/* Find root interrupt controller */
	iparent = ofw_bus_find_iparent(node);
	if (iparent == 0) {
		device_printf(sc->dev, "No interrupt-parrent found. "
				"Error in DTB\n");
		return (ENXIO);
	} else {
		/* While at parent - store interrupt cells prop */
		if (OF_searchencprop(OF_node_from_xref(iparent),
		    "#interrupt-cells", &irq_cells, sizeof(irq_cells)) == -1) {
			device_printf(sc->dev, "DTB: Missing #interrupt-cells "
			    "property in interrupt parent node\n");
			return (ENXIO);
		}
	}

	size = OF_getproplen(node, "interrupts");
	if (size != -1) {
		size = size / sizeof(pcell_t);
		size = size / irq_cells;
		sc->irq_num = size;
		device_printf(sc->dev, "%d IRQs available\n", sc->irq_num);
	} else {
		device_printf(sc->dev, "ERROR: no interrupts entry found!\n");
		return (ENXIO);
	}

	for (i = 0; i < sc->irq_num; i++) {
		sc->irq_rid[i] = i;
		sc->irq_res[i] = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ,
			&sc->irq_rid[i], RF_ACTIVE);
		if (!sc->irq_res[i]) {
			mtx_destroy(&sc->mutex);
			device_printf(sc->dev,
			    "could not allocate gpio%d interrupt\n", i+1);
			return (ENXIO);
		}
	}

	device_printf(sc->dev, "Disable interrupts (offset = %x + EDGE(0x18)\n", sc->offset);
	/* Disable all interrupts */
	bus_space_write_4(sc->bst, sc->bsh, sc->offset + GPIO_INT_EDGE_MASK, 0);
	device_printf(sc->dev, "Disable interrupts (offset = %x + LEV(0x1C))\n", sc->offset);
	bus_space_write_4(sc->bst, sc->bsh, sc->offset + GPIO_INT_LEV_MASK, 0);

	for (i = 0; i < sc->irq_num; i++) {
		device_printf(sc->dev, "Setup intr %d\n", i);
		if (bus_setup_intr(sc->dev, sc->irq_res[i],
		    INTR_TYPE_MISC,
		    (driver_filter_t *)mv_gpio_intr, NULL,
		    sc, &sc->ih_cookie[i]) != 0) {
			mtx_destroy(&sc->mutex);
			bus_release_resource(sc->dev, SYS_RES_IRQ,
				sc->irq_rid[i], sc->irq_res[i]);
			device_printf(sc->dev, "could not set up intr %d\n", i);
			return (ENXIO);
		}
	}

	/* Clear interrupt status. */
	device_printf(sc->dev, "Clear int status (offset = %x)\n", sc->offset);
	bus_space_write_4(sc->bst, sc->bsh, sc->offset + GPIO_INT_CAUSE, 0);

	sc->debounce_callouts = (struct callout **)malloc(sc->pin_num *
	    sizeof(struct callout *), M_DEVBUF, M_WAITOK | M_ZERO);
	if (sc->debounce_callouts == NULL)
		return (ENOMEM);

	sc->debounce_counters = (int *)malloc(sc->pin_num * sizeof(int),
	    M_DEVBUF, M_WAITOK);
	if (sc->debounce_counters == NULL)
		return (ENOMEM);

	return (0);
}
Esempio n. 23
0
static int
tsec_fdt_attach(device_t dev)
{
	struct tsec_softc *sc;
	phandle_t phy;
	int error = 0;

	sc = device_get_softc(dev);
	sc->dev = dev;
	sc->node = ofw_bus_get_node(dev);

	/* Get phy address from fdt */
	if (OF_getencprop(sc->node, "phy-handle", &phy, sizeof(phy)) <= 0) {
		device_printf(dev, "PHY not found in device tree");
		return (ENXIO);
	}

	phy = OF_node_from_xref(phy);
	OF_decode_addr(OF_parent(phy), 0, &sc->phy_bst, &sc->phy_bsh);
	OF_getencprop(phy, "reg", &sc->phyaddr, sizeof(sc->phyaddr));

	/* Init timer */
	callout_init(&sc->tsec_callout, 1);

	/* Init locks */
	mtx_init(&sc->transmit_lock, device_get_nameunit(dev), "TSEC TX lock",
	    MTX_DEF);
	mtx_init(&sc->receive_lock, device_get_nameunit(dev), "TSEC RX lock",
	    MTX_DEF);
	mtx_init(&sc->ic_lock, device_get_nameunit(dev), "TSEC IC lock",
	    MTX_DEF);

	/* Allocate IO memory for TSEC registers */
	sc->sc_rrid = 0;
	sc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rrid,
	    RF_ACTIVE);
	if (sc->sc_rres == NULL) {
		device_printf(dev, "could not allocate IO memory range!\n");
		goto fail1;
	}
	sc->sc_bas.bsh = rman_get_bushandle(sc->sc_rres);
	sc->sc_bas.bst = rman_get_bustag(sc->sc_rres);

	/* TSEC attach */
	if (tsec_attach(sc) != 0) {
		device_printf(dev, "could not be configured\n");
		goto fail2;
	}

	/* Set up interrupts (TX/RX/ERR) */
	sc->sc_transmit_irid = TSEC_RID_TXIRQ;
	error = tsec_setup_intr(sc, &sc->sc_transmit_ires,
	    &sc->sc_transmit_ihand, &sc->sc_transmit_irid,
	    tsec_transmit_intr, "TX");
	if (error)
		goto fail2;

	sc->sc_receive_irid = TSEC_RID_RXIRQ;
	error = tsec_setup_intr(sc, &sc->sc_receive_ires,
	    &sc->sc_receive_ihand, &sc->sc_receive_irid,
	    tsec_receive_intr, "RX");
	if (error)
		goto fail3;

	sc->sc_error_irid = TSEC_RID_ERRIRQ;
	error = tsec_setup_intr(sc, &sc->sc_error_ires,
	    &sc->sc_error_ihand, &sc->sc_error_irid,
	    tsec_error_intr, "ERR");
	if (error)
		goto fail4;

	return (0);

fail4:
	tsec_release_intr(sc, sc->sc_receive_ires, sc->sc_receive_ihand,
	    sc->sc_receive_irid, "RX");
fail3:
	tsec_release_intr(sc, sc->sc_transmit_ires, sc->sc_transmit_ihand,
	    sc->sc_transmit_irid, "TX");
fail2:
	bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rrid, sc->sc_rres);
fail1:
	mtx_destroy(&sc->receive_lock);
	mtx_destroy(&sc->transmit_lock);
	return (ENXIO);
}
Esempio n. 24
0
static int
am335x_read_timing(device_t dev, phandle_t node, struct panel_info *panel)
{
	int error;
	phandle_t timings_node, timing_node, native;

	timings_node = ofw_bus_find_child(node, "display-timings");
	if (timings_node == 0) {
		device_printf(dev, "no \"display-timings\" node\n");
		return (-1);
	}

	if (OF_searchencprop(timings_node, "native-mode", &native,
	    sizeof(native)) == -1) {
		device_printf(dev, "no \"native-mode\" reference in \"timings\" node\n");
		return (-1);
	}

	timing_node = OF_node_from_xref(native);

	error = 0;
	if ((error = am335x_read_property(dev, timing_node,
	    "hactive", &panel->panel_width)))
		goto out;

	if ((error = am335x_read_property(dev, timing_node,
	    "vactive", &panel->panel_height)))
		goto out;

	if ((error = am335x_read_property(dev, timing_node,
	    "hfront-porch", &panel->panel_hfp)))
		goto out;

	if ((error = am335x_read_property(dev, timing_node,
	    "hback-porch", &panel->panel_hbp)))
		goto out;

	if ((error = am335x_read_property(dev, timing_node,
	    "hsync-len", &panel->panel_hsw)))
		goto out;

	if ((error = am335x_read_property(dev, timing_node,
	    "vfront-porch", &panel->panel_vfp)))
		goto out;

	if ((error = am335x_read_property(dev, timing_node,
	    "vback-porch", &panel->panel_vbp)))
		goto out;

	if ((error = am335x_read_property(dev, timing_node,
	    "vsync-len", &panel->panel_vsw)))
		goto out;

	if ((error = am335x_read_property(dev, timing_node,
	    "clock-frequency", &panel->panel_pxl_clk)))
		goto out;

	if ((error = am335x_read_property(dev, timing_node,
	    "pixelclk-active", &panel->pixelclk_active)))
		goto out;

	if ((error = am335x_read_property(dev, timing_node,
	    "hsync-active", &panel->hsync_active)))
		goto out;

	if ((error = am335x_read_property(dev, timing_node,
	    "vsync-active", &panel->vsync_active)))
		goto out;

out:
	return (error);
}
Esempio n. 25
0
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);
}
Esempio n. 26
0
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);
}
Esempio n. 27
0
int
fdt_get_phyaddr(phandle_t node, device_t dev, int *phy_addr, void **phy_sc)
{
	phandle_t phy_node;
	pcell_t phy_handle, phy_reg;
	uint32_t i;
	device_t parent, child;

	if (OF_getencprop(node, "phy-handle", (void *)&phy_handle,
	    sizeof(phy_handle)) <= 0)
		return (ENXIO);

	phy_node = OF_node_from_xref(phy_handle);

	if (OF_getprop(phy_node, "reg", (void *)&phy_reg,
	    sizeof(phy_reg)) <= 0)
		return (ENXIO);

	*phy_addr = fdt32_to_cpu(phy_reg);

	/*
	 * Search for softc used to communicate with phy.
	 */

	/*
	 * Step 1: Search for ancestor of the phy-node with a "phy-handle"
	 * property set.
	 */
	phy_node = OF_parent(phy_node);
	while (phy_node != 0) {
		if (OF_getprop(phy_node, "phy-handle", (void *)&phy_handle,
		    sizeof(phy_handle)) > 0)
			break;
		phy_node = OF_parent(phy_node);
	}
	if (phy_node == 0)
		return (ENXIO);

	/*
	 * Step 2: For each device with the same parent and name as ours
	 * compare its node with the one found in step 1, ancestor of phy
	 * node (stored in phy_node).
	 */
	parent = device_get_parent(dev);
	i = 0;
	child = device_find_child(parent, device_get_name(dev), i);
	while (child != NULL) {
		if (ofw_bus_get_node(child) == phy_node)
			break;
		i++;
		child = device_find_child(parent, device_get_name(dev), i);
	}
	if (child == NULL)
		return (ENXIO);

	/*
	 * Use softc of the device found.
	 */
	*phy_sc = (void *)device_get_softc(child);

	return (0);
}