Esempio n. 1
0
static int add_dt_node(u32 parent_phandle, u32 drc_index)
{
	struct device_node *dn;
	struct device_node *parent_dn;
	int rc;

	parent_dn = of_find_node_by_phandle(parent_phandle);
	if (!parent_dn)
		return -ENOENT;

	dn = dlpar_configure_connector(drc_index, parent_dn);
	if (!dn)
		return -ENOENT;

	rc = dlpar_attach_node(dn);
	if (rc)
		dlpar_free_cc_nodes(dn);

	of_node_put(parent_dn);
	return rc;
}
Esempio n. 2
0
static void imx_ocotp_init_dt(struct device_d *dev, void __iomem *base)
{
	char mac[6];
	const __be32 *prop;
	struct device_node *node = dev->device_node;
	int len;

	if (!node)
		return;

	prop = of_get_property(node, "barebox,provide-mac-address", &len);
	if (!prop)
		return;

	while (len >= MAC_ADDRESS_PROPLEN) {
		struct device_node *rnode;
		uint32_t phandle, offset;

		phandle = be32_to_cpup(prop++);

		rnode = of_find_node_by_phandle(phandle);
		offset = be32_to_cpup(prop++);

		mac[5] = readb(base + offset);
		offset = inc_offset(offset);
		mac[4] = readb(base + offset);
		offset = inc_offset(offset);
		mac[3] = readb(base + offset);
		offset = inc_offset(offset);
		mac[2] = readb(base + offset);
		offset = inc_offset(offset);
		mac[1] = readb(base + offset);
		offset = inc_offset(offset);
		mac[0] = readb(base + offset);

		of_eth_register_ethaddr(rnode, mac);

		len -= MAC_ADDRESS_PROPLEN;
	}
}
Esempio n. 3
0
File: irq.c Progetto: Lyude/linux
/**
 * of_irq_find_parent - Given a device node, find its interrupt parent node
 * @child: pointer to device node
 *
 * Returns a pointer to the interrupt parent node, or NULL if the interrupt
 * parent could not be determined.
 */
struct device_node *of_irq_find_parent(struct device_node *child)
{
	struct device_node *p;
	phandle parent;

	if (!of_node_get(child))
		return NULL;

	do {
		if (of_property_read_u32(child, "interrupt-parent", &parent)) {
			p = of_get_parent(child);
		} else	{
			if (of_irq_workarounds & OF_IMAP_NO_PHANDLE)
				p = of_node_get(of_irq_dflt_pic);
			else
				p = of_find_node_by_phandle(parent);
		}
		of_node_put(child);
		child = p;
	} while (p && of_get_property(p, "#interrupt-cells", NULL) == NULL);

	return p;
}
Esempio n. 4
0
static struct device_node *of_irq_find_parent(struct device_node *child)
{
	struct device_node *p;
	const phandle *parp;

	if (!of_node_get(child))
		return NULL;

	do {
		parp = of_get_property(child, "interrupt-parent", NULL);
		if (parp == NULL)
			p = of_get_parent(child);
		else {
			if (of_irq_workarounds & OF_IMAP_NO_PHANDLE)
				p = of_node_get(of_irq_dflt_pic);
			else
				p = of_find_node_by_phandle(*parp);
		}
		of_node_put(child);
		child = p;
	} while (p && of_get_property(p, "#interrupt-cells", NULL) == NULL);

	return p;
}
Esempio n. 5
0
static int __init mv64x60_mpsc_device_setup(struct device_node *np, int id)
{
	struct resource r[5];
	struct mpsc_pdata pdata;
	struct platform_device *pdev;
	const unsigned int *prop;
	const phandle *ph;
	struct device_node *sdma, *brg;
	int err;
	int port_number;

	/* only register the shared platform device the first time through */
	if (id == 0 && (err = mv64x60_mpsc_register_shared_pdev(np)))
		return err;

	memset(r, 0, sizeof(r));

	err = of_address_to_resource(np, 0, &r[0]);
	if (err)
		return err;

	of_irq_to_resource(np, 0, &r[4]);

	ph = of_get_property(np, "sdma", NULL);
	sdma = of_find_node_by_phandle(*ph);
	if (!sdma)
		return -ENODEV;

	of_irq_to_resource(sdma, 0, &r[3]);
	err = of_address_to_resource(sdma, 0, &r[1]);
	of_node_put(sdma);
	if (err)
		return err;

	ph = of_get_property(np, "brg", NULL);
	brg = of_find_node_by_phandle(*ph);
	if (!brg)
		return -ENODEV;

	err = of_address_to_resource(brg, 0, &r[2]);
	of_node_put(brg);
	if (err)
		return err;

	prop = of_get_property(np, "block-index", NULL);
	if (!prop)
		return -ENODEV;
	port_number = *(int *)prop;

	memset(&pdata, 0, sizeof(pdata));

	pdata.cache_mgmt = 1; /* All current revs need this set */

	prop = of_get_property(np, "max_idle", NULL);
	if (prop)
		pdata.max_idle = *prop;

	prop = of_get_property(brg, "current-speed", NULL);
	if (prop)
		pdata.default_baud = *prop;

	/* Default is 8 bits, no parity, no flow control */
	pdata.default_bits = 8;
	pdata.default_parity = 'n';
	pdata.default_flow = 'n';

	prop = of_get_property(np, "chr_1", NULL);
	if (prop)
		pdata.chr_1_val = *prop;

	prop = of_get_property(np, "chr_2", NULL);
	if (prop)
		pdata.chr_2_val = *prop;

	prop = of_get_property(np, "chr_10", NULL);
	if (prop)
		pdata.chr_10_val = *prop;

	prop = of_get_property(np, "mpcr", NULL);
	if (prop)
		pdata.mpcr_val = *prop;

	prop = of_get_property(brg, "bcr", NULL);
	if (prop)
		pdata.bcr_val = *prop;

	pdata.brg_can_tune = 1; /* All current revs need this set */

	prop = of_get_property(brg, "clock-src", NULL);
	if (prop)
		pdata.brg_clk_src = *prop;

	prop = of_get_property(brg, "clock-frequency", NULL);
	if (prop)
		pdata.brg_clk_freq = *prop;

	pdev = platform_device_alloc(MPSC_CTLR_NAME, port_number);
	if (!pdev)
		return -ENOMEM;

	err = platform_device_add_resources(pdev, r, 5);
	if (err)
		goto error;

	err = platform_device_add_data(pdev, &pdata, sizeof(pdata));
	if (err)
		goto error;

	err = platform_device_add(pdev);
	if (err)
		goto error;

	return 0;

error:
	platform_device_put(pdev);
	return err;
}
Esempio n. 6
0
static int __init gfar_of_init(void)
{
	struct device_node *np;
	unsigned int i;
	struct platform_device *mdio_dev, *gfar_dev;
	struct resource res;
	int ret;

	for (np = NULL, i = 0; (np = of_find_compatible_node(np, "mdio", "gianfar")) != NULL; i++) {
		int k;
		struct device_node *child = NULL;
		struct gianfar_mdio_data mdio_data;

		memset(&res, 0, sizeof(res));
		memset(&mdio_data, 0, sizeof(mdio_data));

		ret = of_address_to_resource(np, 0, &res);
		if (ret)
			goto mdio_err;

		mdio_dev = platform_device_register_simple("fsl-gianfar_mdio", res.start, &res, 1);
		if (IS_ERR(mdio_dev)) {
			ret = PTR_ERR(mdio_dev);
			goto mdio_err;
		}

		for (k = 0; k < 32; k++)
			mdio_data.irq[k] = -1;

		while ((child = of_get_next_child(np, child)) != NULL) {
			if (child->n_intrs) {
				u32 *id = (u32 *) get_property(child, "reg", NULL);
				mdio_data.irq[*id] = child->intrs[0].line;
			}
		}

		ret = platform_device_add_data(mdio_dev, &mdio_data, sizeof(struct gianfar_mdio_data));
		if (ret)
			goto mdio_unreg;
	}

	for (np = NULL, i = 0; (np = of_find_compatible_node(np, "network", "gianfar")) != NULL; i++) {
		struct resource r[4];
		struct device_node *phy, *mdio;
		struct gianfar_platform_data gfar_data;
		unsigned int *id;
		char *model;
		void *mac_addr;
		phandle *ph;

		memset(r, 0, sizeof(r));
		memset(&gfar_data, 0, sizeof(gfar_data));

		ret = of_address_to_resource(np, 0, &r[0]);
		if (ret)
			goto gfar_err;

		r[1].start = np->intrs[0].line;
		r[1].end = np->intrs[0].line;
		r[1].flags = IORESOURCE_IRQ;

		model = get_property(np, "model", NULL);

		/* If we aren't the FEC we have multiple interrupts */
		if (model && strcasecmp(model, "FEC")) {
			r[1].name = gfar_tx_intr;

			r[2].name = gfar_rx_intr;
			r[2].start = np->intrs[1].line;
			r[2].end = np->intrs[1].line;
			r[2].flags = IORESOURCE_IRQ;

			r[3].name = gfar_err_intr;
			r[3].start = np->intrs[2].line;
			r[3].end = np->intrs[2].line;
			r[3].flags = IORESOURCE_IRQ;
		}

		gfar_dev = platform_device_register_simple("fsl-gianfar", i, &r[0], np->n_intrs + 1);

		if (IS_ERR(gfar_dev)) {
			ret = PTR_ERR(gfar_dev);
			goto gfar_err;
		}

		mac_addr = get_property(np, "address", NULL);
		memcpy(gfar_data.mac_addr, mac_addr, 6);

		if (model && !strcasecmp(model, "TSEC"))
			gfar_data.device_flags =
				FSL_GIANFAR_DEV_HAS_GIGABIT |
				FSL_GIANFAR_DEV_HAS_COALESCE |
				FSL_GIANFAR_DEV_HAS_RMON |
				FSL_GIANFAR_DEV_HAS_MULTI_INTR;
		if (model && !strcasecmp(model, "eTSEC"))
			gfar_data.device_flags =
				FSL_GIANFAR_DEV_HAS_GIGABIT |
				FSL_GIANFAR_DEV_HAS_COALESCE |
				FSL_GIANFAR_DEV_HAS_RMON |
				FSL_GIANFAR_DEV_HAS_MULTI_INTR |
				FSL_GIANFAR_DEV_HAS_CSUM |
				FSL_GIANFAR_DEV_HAS_VLAN |
				FSL_GIANFAR_DEV_HAS_EXTENDED_HASH;

		ph = (phandle *) get_property(np, "phy-handle", NULL);
		phy = of_find_node_by_phandle(*ph);

		if (phy == NULL) {
			ret = -ENODEV;
			goto gfar_unreg;
		}

		mdio = of_get_parent(phy);

		id = (u32 *) get_property(phy, "reg", NULL);
		ret = of_address_to_resource(mdio, 0, &res);
		if (ret) {
			of_node_put(phy);
			of_node_put(mdio);
			goto gfar_unreg;
		}

		gfar_data.phy_id = *id;
		gfar_data.bus_id = res.start;

		of_node_put(phy);
		of_node_put(mdio);

		ret = platform_device_add_data(gfar_dev, &gfar_data, sizeof(struct gianfar_platform_data));
		if (ret)
			goto gfar_unreg;
	}

	return 0;

mdio_unreg:
	platform_device_unregister(mdio_dev);
mdio_err:
	return ret;

gfar_unreg:
	platform_device_unregister(gfar_dev);
gfar_err:
	return ret;
}
Esempio n. 7
0
/**
 * of_parse_phandle_with_args() - Find a node pointed by phandle in a list
 * @np:		pointer to a device tree node containing a list
 * @list_name:	property name that contains a list
 * @cells_name:	property name that specifies phandles' arguments count
 * @index:	index of a phandle to parse out
 * @out_args:	optional pointer to output arguments structure (will be filled)
 *
 * This function is useful to parse lists of phandles and their arguments.
 * Returns 0 on success and fills out_args, on error returns appropriate
 * errno value.
 *
 * Caller is responsible to call of_node_put() on the returned out_args->node
 * pointer.
 *
 * Example:
 *
 * phandle1: node1 {
 * 	#list-cells = <2>;
 * }
 *
 * phandle2: node2 {
 * 	#list-cells = <1>;
 * }
 *
 * node3 {
 * 	list = <&phandle1 1 2 &phandle2 3>;
 * }
 *
 * To get a device_node of the `node2' node you may call this:
 * of_parse_phandle_with_args(node3, "list", "#list-cells", 1, &args);
 */
static int __of_parse_phandle_with_args(const struct device_node *np,
					const char *list_name,
					const char *cells_name, int index,
					struct of_phandle_args *out_args)
{
	const __be32 *list, *list_end;
	int rc = 0, size, cur_index = 0;
	uint32_t count = 0;
	struct device_node *node = NULL;
	phandle phandle;

	/* Retrieve the phandle list property */
	list = of_get_property(np, list_name, &size);
	if (!list)
		return -ENOENT;
	list_end = list + size / sizeof(*list);

	/* Loop over the phandles until all the requested entry is found */
	while (list < list_end) {
		rc = -EINVAL;
		count = 0;

		/*
		 * If phandle is 0, then it is an empty entry with no
		 * arguments.  Skip forward to the next entry.
		 */
		phandle = be32_to_cpup(list++);
		if (phandle) {
			/*
			 * Find the provider node and parse the #*-cells
			 * property to determine the argument length
			 */
			node = of_find_node_by_phandle(phandle);
			if (!node) {
				pr_err("%s: could not find phandle\n",
					 np->full_name);
				goto err;
			}
			if (of_property_read_u32(node, cells_name, &count)) {
				pr_err("%s: could not get %s for %s\n",
					 np->full_name, cells_name,
					 node->full_name);
				goto err;
			}

			/*
			 * Make sure that the arguments actually fit in the
			 * remaining property data length
			 */
			if (list + count > list_end) {
				pr_err("%s: arguments longer than property\n",
					 np->full_name);
				goto err;
			}
		}

		/*
		 * All of the error cases above bail out of the loop, so at
		 * this point, the parsing is successful. If the requested
		 * index matches, then fill the out_args structure and return,
		 * or return -ENOENT for an empty entry.
		 */
		rc = -ENOENT;
		if (cur_index == index) {
			if (!phandle)
				goto err;

			if (out_args) {
				int i;
				if (WARN_ON(count > MAX_PHANDLE_ARGS))
					count = MAX_PHANDLE_ARGS;
				out_args->np = node;
				out_args->args_count = count;
				for (i = 0; i < count; i++)
					out_args->args[i] = be32_to_cpup(list++);
			} else {
				of_node_put(node);
			}

			/* Found it! return success */
			return 0;
		}

		of_node_put(node);
		node = NULL;
		list += count;
		cur_index++;
	}

	/*
	 * Unlock node before returning result; will be one of:
	 * -ENOENT : index is for empty phandle
	 * -EINVAL : parsing error on data
	 * [1..n]  : Number of phandle (count mode; when index = -1)
	 */
	rc = index < 0 ? cur_index : -ENOENT;
 err:
	if (node)
		of_node_put(node);
	return rc;
}
Esempio n. 8
0
static int
oh_port_probe(struct platform_device *_of_dev)
{
	struct device		*dpa_oh_dev;
	struct device_node	*dpa_oh_node;
	int			 lenp, _errno = 0, fq_idx, n_size, i, ret;
	const phandle		*oh_port_handle, *bpool_handle;
	struct platform_device	*oh_of_dev;
	struct device_node	*oh_node, *bpool_node = NULL, *root_node;
	struct device		*oh_dev;
	struct dpa_oh_config_s	*oh_config = NULL;
	uint32_t		*oh_all_queues;
	uint32_t		*oh_tx_queues;
	uint32_t		 queues_count;
	uint32_t		 crt_fqid_base;
	uint32_t		 crt_fq_count;
	bool			frag_enabled = false;
	struct fm_port_params	oh_port_tx_params;
	struct fm_port_pcd_param	oh_port_pcd_params;
	struct dpa_buffer_layout_s buf_layout;
	/* True if the current partition owns the OH port. */
	bool init_oh_port;
	const struct of_device_id *match;
	uint32_t crt_ext_pools_count, ext_pool_size;
	const unsigned int *port_id;
	const unsigned int *channel_id;
	const uint32_t		*bpool_cfg;
	const uint32_t		*bpid;

	memset(&oh_port_tx_params, 0, sizeof(oh_port_tx_params));
	dpa_oh_dev = &_of_dev->dev;
	dpa_oh_node = dpa_oh_dev->of_node;
	BUG_ON(dpa_oh_node == NULL);

	match = of_match_device(oh_port_match_table, dpa_oh_dev);
	if (!match)
		return -EINVAL;

	dev_dbg(dpa_oh_dev, "Probing OH port...\n");

	/*
	 * Find the referenced OH node
	 */

	oh_port_handle = of_get_property(dpa_oh_node,
		"fsl,fman-oh-port", &lenp);
	if (oh_port_handle == NULL) {
		dev_err(dpa_oh_dev, "No OH port handle found in node %s\n",
			dpa_oh_node->full_name);
		return -EINVAL;
	}

	BUG_ON(lenp % sizeof(*oh_port_handle));
	if (lenp != sizeof(*oh_port_handle)) {
		dev_err(dpa_oh_dev, "Found %lu OH port bindings in node %s,"
			" only 1 phandle is allowed.\n",
			(unsigned long int)(lenp / sizeof(*oh_port_handle)),
			dpa_oh_node->full_name);
		return -EINVAL;
	}

	/* Read configuration for the OH port */
	oh_node = of_find_node_by_phandle(*oh_port_handle);
	if (oh_node == NULL) {
		dev_err(dpa_oh_dev, "Can't find OH node referenced from "
			"node %s\n", dpa_oh_node->full_name);
		return -EINVAL;
	}
	dev_info(dpa_oh_dev, "Found OH node handle compatible with %s.\n",
		match->compatible);

	port_id = of_get_property(oh_node, "cell-index", &lenp);

	if (port_id == NULL) {
		dev_err(dpa_oh_dev, "No port id found in node %s\n",
			dpa_oh_node->full_name);
		_errno = -EINVAL;
		goto return_kfree;
	}

	BUG_ON(lenp % sizeof(*port_id));

	oh_of_dev = of_find_device_by_node(oh_node);
	BUG_ON(oh_of_dev == NULL);
	oh_dev = &oh_of_dev->dev;

	/*
	 * The OH port must be initialized exactly once.
	 * The following scenarios are of interest:
	 *	- the node is Linux-private (will always initialize it);
	 *	- the node is shared between two Linux partitions
	 *	  (only one of them will initialize it);
	 *	- the node is shared between a Linux and a LWE partition
	 *	  (Linux will initialize it) - "fsl,dpa-oh-shared"
	 */

	/* Check if the current partition owns the OH port
	 * and ought to initialize it. It may be the case that we leave this
	 * to another (also Linux) partition. */
	init_oh_port = strcmp(match->compatible, "fsl,dpa-oh-shared");

	/* If we aren't the "owner" of the OH node, we're done here. */
	if (!init_oh_port) {
		dev_dbg(dpa_oh_dev, "Not owning the shared OH port %s, "
			"will not initialize it.\n", oh_node->full_name);
		of_node_put(oh_node);
		return 0;
	}

	/* Allocate OH dev private data */
	oh_config = devm_kzalloc(dpa_oh_dev, sizeof(*oh_config), GFP_KERNEL);
	if (oh_config == NULL) {
		dev_err(dpa_oh_dev, "Can't allocate private data for "
			"OH node %s referenced from node %s!\n",
			oh_node->full_name, dpa_oh_node->full_name);
		_errno = -ENOMEM;
		goto return_kfree;
	}

	/*
	 * Read FQ ids/nums for the DPA OH node
	 */
	oh_all_queues = (uint32_t *)of_get_property(dpa_oh_node,
		"fsl,qman-frame-queues-oh", &lenp);
	if (oh_all_queues == NULL) {
		dev_err(dpa_oh_dev, "No frame queues have been "
			"defined for OH node %s referenced from node %s\n",
			oh_node->full_name, dpa_oh_node->full_name);
		_errno = -EINVAL;
		goto return_kfree;
	}

	/* Check that the OH error and default FQs are there */
	BUG_ON(lenp % (2 * sizeof(*oh_all_queues)));
	queues_count = lenp / (2 * sizeof(*oh_all_queues));
	if (queues_count != 2) {
		dev_err(dpa_oh_dev, "Error and Default queues must be "
			"defined for OH node %s referenced from node %s\n",
			oh_node->full_name, dpa_oh_node->full_name);
		_errno = -EINVAL;
		goto return_kfree;
	}

	/* Read the FQIDs defined for this OH port */
	dev_dbg(dpa_oh_dev, "Reading %d queues...\n", queues_count);
	fq_idx = 0;

	/* Error FQID - must be present */
	crt_fqid_base = oh_all_queues[fq_idx++];
	crt_fq_count = oh_all_queues[fq_idx++];
	if (crt_fq_count != 1) {
		dev_err(dpa_oh_dev, "Only 1 Error FQ allowed in OH node %s "
			"referenced from node %s (read: %d FQIDs).\n",
			oh_node->full_name, dpa_oh_node->full_name,
			crt_fq_count);
		_errno = -EINVAL;
		goto return_kfree;
	}
	oh_config->error_fqid = crt_fqid_base;
	dev_dbg(dpa_oh_dev, "Read Error FQID 0x%x for OH port %s.\n",
		oh_config->error_fqid, oh_node->full_name);

	/* Default FQID - must be present */
	crt_fqid_base = oh_all_queues[fq_idx++];
	crt_fq_count = oh_all_queues[fq_idx++];
	if (crt_fq_count != 1) {
		dev_err(dpa_oh_dev, "Only 1 Default FQ allowed "
			"in OH node %s referenced from %s (read: %d FQIDs).\n",
			oh_node->full_name, dpa_oh_node->full_name,
			crt_fq_count);
		_errno = -EINVAL;
		goto return_kfree;
	}
	oh_config->default_fqid = crt_fqid_base;
	dev_dbg(dpa_oh_dev, "Read Default FQID 0x%x for OH port %s.\n",
		oh_config->default_fqid, oh_node->full_name);

	/* TX FQID - presence is optional */
	oh_tx_queues = (uint32_t *)of_get_property(dpa_oh_node,
		"fsl,qman-frame-queues-tx", &lenp);
	if (oh_tx_queues == NULL) {
		dev_dbg(dpa_oh_dev, "No tx queues have been "
		"defined for OH node %s referenced from node %s\n",
			oh_node->full_name, dpa_oh_node->full_name);
		goto config_port;
	}

	/* Check that queues-tx has only a base and a count defined */
	BUG_ON(lenp % (2 * sizeof(*oh_tx_queues)));
	queues_count = lenp / (2 * sizeof(*oh_tx_queues));
	if (queues_count != 1) {
		dev_err(dpa_oh_dev, "TX queues must be defined in"
			"only one <base count> tuple for OH node %s "
			"referenced from node %s\n",
			oh_node->full_name, dpa_oh_node->full_name);
		_errno = -EINVAL;
		goto return_kfree;
	}

	/* Read channel id for the queues */
	channel_id = of_get_property(oh_node, "fsl,qman-channel-id", &lenp);
	if (channel_id == NULL) {
		dev_err(dpa_oh_dev, "No channel id found in node %s\n",
			dpa_oh_node->full_name);
		_errno = -EINVAL;
		goto return_kfree;
	}
	BUG_ON(lenp % sizeof(*channel_id));

	fq_idx = 0;
	crt_fqid_base = oh_tx_queues[fq_idx++];
	crt_fq_count = oh_tx_queues[fq_idx++];
	oh_config->egress_cnt = crt_fq_count;

	/* Allocate TX queues */
	dev_dbg(dpa_oh_dev, "Allocating %d queues for TX...\n", crt_fq_count);
	oh_config->egress_fqs = devm_kzalloc(dpa_oh_dev,
		crt_fq_count * sizeof(struct qman_fq), GFP_KERNEL);
	if (oh_config->egress_fqs == NULL) {
		dev_err(dpa_oh_dev, "Can't allocate private data for "
			"TX queues for OH node %s referenced from node %s!\n",
			oh_node->full_name, dpa_oh_node->full_name);
		_errno = -ENOMEM;
		goto return_kfree;
	}

	/* Create TX queues */
	for (i = 0; i < crt_fq_count; i++) {
		ret = oh_fq_create(oh_config->egress_fqs + i,
			crt_fqid_base + i, *channel_id, 3);
		if (ret != 0) {
			dev_err(dpa_oh_dev, "Unable to create TX frame "
				"queue %d for OH node %s referenced "
				"from node %s!\n",
				crt_fqid_base + i, oh_node->full_name,
				dpa_oh_node->full_name);
			_errno = -EINVAL;
			goto return_kfree;
		}
	}

config_port:
	/* Get a handle to the fm_port so we can set
	 * its configuration params */
	oh_config->oh_port = fm_port_bind(oh_dev);
	if (oh_config->oh_port == NULL) {
		dev_err(dpa_oh_dev, "NULL drvdata from fm port dev %s!\n",
			oh_node->full_name);
		_errno = -EINVAL;
		goto return_kfree;
	}

	oh_set_buffer_layout(oh_config->oh_port, &buf_layout);
	bpool_handle = of_get_property(dpa_oh_node,
			"fsl,bman-buffer-pools", &lenp);

	if (bpool_handle == NULL) {
		dev_info(dpa_oh_dev, "OH port %s has no buffer pool. Fragmentation will not be enabled\n",
			oh_node->full_name);
		goto init_port;
	}

	/* used for reading ext_pool_size*/
	root_node = of_find_node_by_path("/");
	if (root_node == NULL) {
		dev_err(dpa_oh_dev, "of_find_node_by_path(/) failed\n");
		_errno = -EINVAL;
		goto return_kfree;
	}

	n_size = of_n_size_cells(root_node);
	of_node_put(root_node);

	crt_ext_pools_count = lenp / sizeof(phandle);
	dev_dbg(dpa_oh_dev, "OH port number of pools = %u\n",
					crt_ext_pools_count);

	oh_port_tx_params.num_pools = crt_ext_pools_count;

	for (i = 0; i < crt_ext_pools_count; i++) {
		bpool_node = of_find_node_by_phandle(bpool_handle[i]);
		if (bpool_node == NULL) {
			dev_err(dpa_oh_dev, "Invalid Buffer pool node\n");
			_errno = -EINVAL;
			goto return_kfree;
		}

		bpid = of_get_property(bpool_node, "fsl,bpid", &lenp);
		if ((bpid == NULL) || (lenp != sizeof(*bpid))) {
			dev_err(dpa_oh_dev, "Invalid Buffer pool Id\n");
			_errno = -EINVAL;
			goto return_kfree;
		}

		oh_port_tx_params.pool_param[i].id = *bpid;
		dev_dbg(dpa_oh_dev, "OH port bpool id = %u\n", *bpid);

		bpool_cfg = of_get_property(bpool_node,
				"fsl,bpool-ethernet-cfg", &lenp);
		if (bpool_cfg == NULL) {
			dev_err(dpa_oh_dev, "Invalid Buffer pool config params\n");
			_errno = -EINVAL;
			goto return_kfree;
		}

		of_read_number(bpool_cfg, n_size);
		ext_pool_size = of_read_number(bpool_cfg + n_size, n_size);
		oh_port_tx_params.pool_param[i].size = ext_pool_size;
		dev_dbg(dpa_oh_dev, "OH port bpool size = %u\n",
			ext_pool_size);
		of_node_put(bpool_node);

	}

	if (buf_layout.data_align != FRAG_DATA_ALIGN ||
	    buf_layout.manip_extra_space != FRAG_MANIP_SPACE)
		goto init_port;

	frag_enabled = true;
	dev_info(dpa_oh_dev, "IP Fragmentation enabled for OH port %d",
		     *port_id);

init_port:
	of_node_put(oh_node);
	/* Set Tx params */
	dpaa_eth_init_port(tx, oh_config->oh_port, oh_port_tx_params,
		oh_config->error_fqid, oh_config->default_fqid, (&buf_layout),
		frag_enabled);
	/* Set PCD params */
	oh_port_pcd_params.cba = oh_alloc_pcd_fqids;
	oh_port_pcd_params.cbf = oh_free_pcd_fqids;
	oh_port_pcd_params.dev = dpa_oh_dev;
	fm_port_pcd_bind(oh_config->oh_port, &oh_port_pcd_params);

	dev_set_drvdata(dpa_oh_dev, oh_config);

	/* Enable the OH port */
	_errno = fm_port_enable(oh_config->oh_port);
	if (_errno)
		goto return_kfree;

	dev_info(dpa_oh_dev, "OH port %s enabled.\n", oh_node->full_name);

	return 0;

return_kfree:
	if (bpool_node)
		of_node_put(bpool_node);
	if (oh_node)
		of_node_put(oh_node);
	if (oh_config && oh_config->egress_fqs)
		devm_kfree(dpa_oh_dev, oh_config->egress_fqs);
	devm_kfree(dpa_oh_dev, oh_config);
	return _errno;
}
Esempio n. 9
0
struct dpa_bp * __cold __must_check /* __attribute__((nonnull)) */
dpa_bp_probe(struct platform_device *_of_dev, size_t *count)
{
	int			 i, lenp, na, ns;
	struct device		*dev;
	struct device_node	*dev_node;
	const phandle		*phandle_prop;
	const uint32_t		*bpid;
	const uint32_t		*bpool_cfg;
	struct dpa_bp		*dpa_bp;

	dev = &_of_dev->dev;

	/* The default is one, if there's no property */
	*count = 1;

	/* Get the buffer pools to be used */
	phandle_prop = of_get_property(dev->of_node,
					"fsl,bman-buffer-pools", &lenp);

	if (phandle_prop)
		*count = lenp / sizeof(phandle);
	else {
		dev_err(dev,
			"missing fsl,bman-buffer-pools device tree entry\n");
		return ERR_PTR(-EINVAL);
	}

	dpa_bp = devm_kzalloc(dev, *count * sizeof(*dpa_bp), GFP_KERNEL);
	if (unlikely(dpa_bp == NULL)) {
		dev_err(dev, "devm_kzalloc() failed\n");
		return ERR_PTR(-ENOMEM);
	}

	dev_node = of_find_node_by_path("/");
	if (unlikely(dev_node == NULL)) {
		dev_err(dev, "of_find_node_by_path(/) failed\n");
		return ERR_PTR(-EINVAL);
	}

	na = of_n_addr_cells(dev_node);
	ns = of_n_size_cells(dev_node);

	for (i = 0; i < *count && phandle_prop; i++) {
		of_node_put(dev_node);
		dev_node = of_find_node_by_phandle(phandle_prop[i]);
		if (unlikely(dev_node == NULL)) {
			dev_err(dev, "of_find_node_by_phandle() failed\n");
			return ERR_PTR(-EFAULT);
		}

		if (unlikely(!of_device_is_compatible(dev_node, "fsl,bpool"))) {
			dev_err(dev,
				"!of_device_is_compatible(%s, fsl,bpool)\n",
				dev_node->full_name);
			dpa_bp = ERR_PTR(-EINVAL);
			goto _return_of_node_put;
		}

		bpid = of_get_property(dev_node, "fsl,bpid", &lenp);
		if ((bpid == NULL) || (lenp != sizeof(*bpid))) {
			dev_err(dev, "fsl,bpid property not found.\n");
			dpa_bp = ERR_PTR(-EINVAL);
			goto _return_of_node_put;
		}
		dpa_bp[i].bpid = *bpid;

		bpool_cfg = of_get_property(dev_node, "fsl,bpool-ethernet-cfg",
					&lenp);
		if (bpool_cfg && (lenp == (2 * ns + na) * sizeof(*bpool_cfg))) {
			const uint32_t *seed_pool;

			dpa_bp[i].config_count =
				(int)of_read_number(bpool_cfg, ns);
			dpa_bp[i].size	= of_read_number(bpool_cfg + ns, ns);
			dpa_bp[i].paddr	=
				of_read_number(bpool_cfg + 2 * ns, na);

			seed_pool = of_get_property(dev_node,
					"fsl,bpool-ethernet-seeds", &lenp);
			dpa_bp[i].seed_pool = !!seed_pool;

		} else {
			dev_err(dev,
				"Missing/invalid fsl,bpool-ethernet-cfg device tree entry for node %s\n",
				dev_node->full_name);
			dpa_bp = ERR_PTR(-EINVAL);
			goto _return_of_node_put;
		}
	}

	sort(dpa_bp, *count, sizeof(*dpa_bp), dpa_bp_cmp, NULL);

	return dpa_bp;

_return_of_node_put:
	if (dev_node)
		of_node_put(dev_node);

	return dpa_bp;
}
Esempio n. 10
0
static int update_dt_node(u32 phandle)
{
	struct update_props_workarea *upwa;
	struct device_node *dn;
	struct property *prop = NULL;
	int i, rc;
	char *prop_data;
	char *rtas_buf;
	int update_properties_token;

	update_properties_token = rtas_token("ibm,update-properties");
	if (update_properties_token == RTAS_UNKNOWN_SERVICE)
		return -EINVAL;

	rtas_buf = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL);
	if (!rtas_buf)
		return -ENOMEM;

	dn = of_find_node_by_phandle(phandle);
	if (!dn) {
		kfree(rtas_buf);
		return -ENOENT;
	}

	upwa = (struct update_props_workarea *)&rtas_buf[0];
	upwa->phandle = phandle;

	do {
		rc = mobility_rtas_call(update_properties_token, rtas_buf);
		if (rc < 0)
			break;

		prop_data = rtas_buf + sizeof(*upwa);

		for (i = 0; i < upwa->nprops; i++) {
			char *prop_name;
			u32 vd;

			prop_name = prop_data + 1;
			prop_data += strlen(prop_name) + 1;
			vd = *prop_data++;

			switch (vd) {
			case 0x00000000:
				/*                                   */
				break;

			case 0x80000000:
				prop = of_find_property(dn, prop_name, NULL);
				prom_remove_property(dn, prop);
				prop = NULL;
				break;

			default:
				rc = update_dt_property(dn, &prop, prop_name,
							vd, prop_data);
				if (rc) {
					printk(KERN_ERR "Could not update %s"
					       " property\n", prop_name);
				}

				prop_data += vd;
			}
		}
	} while (rc == 1);

	of_node_put(dn);
	kfree(rtas_buf);
	return 0;
}
struct esoc_desc *devm_register_esoc_client(struct device *dev,
							const char *name)
{
	int ret, index;
	const char *client_desc;
	char *esoc_prop;
	const __be32 *parp;
	struct device_node *esoc_node;
	struct device_node *np = dev->of_node;
	struct esoc_clink *esoc_clink;
	struct esoc_desc *desc;
	char *esoc_name, *esoc_link;

	for (index = 0;; index++) {
		esoc_prop = kasprintf(GFP_KERNEL, "esoc-%d", index);
		parp = of_get_property(np, esoc_prop, NULL);
		if (parp == NULL) {
			dev_err(dev, "esoc device not present\n");
			kfree(esoc_prop);
			return NULL;
		}
		ret = of_property_read_string_index(np, "esoc-names", index,
								&client_desc);
		if (ret) {
			dev_err(dev, "cannot find matching string\n");
			kfree(esoc_prop);
			return NULL;
		}
		if (strcmp(client_desc, name)) {
			kfree(esoc_prop);
			continue;
		}
		kfree(esoc_prop);
		esoc_node = of_find_node_by_phandle(be32_to_cpup(parp));
		esoc_clink = get_esoc_clink_by_node(esoc_node);
		if (IS_ERR_OR_NULL(esoc_clink)) {
			dev_err(dev, "matching esoc clink not present\n");
			return ERR_PTR(-EPROBE_DEFER);
		}
		esoc_name = kasprintf(GFP_KERNEL, "esoc%d",
							esoc_clink->id);
		if (IS_ERR_OR_NULL(esoc_name)) {
			dev_err(dev, "unable to allocate esoc name\n");
			return ERR_PTR(-ENOMEM);
		}
		esoc_link = kasprintf(GFP_KERNEL, "%s", esoc_clink->link_name);
		if (IS_ERR_OR_NULL(esoc_link)) {
			dev_err(dev, "unable to allocate esoc link name\n");
			kfree(esoc_name);
			return ERR_PTR(-ENOMEM);
		}
		desc = devres_alloc(devm_esoc_desc_release,
						sizeof(*desc), GFP_KERNEL);
		if (IS_ERR_OR_NULL(desc)) {
			kfree(esoc_name);
			kfree(esoc_link);
			dev_err(dev, "unable to allocate esoc descriptor\n");
			return ERR_PTR(-ENOMEM);
		}
		desc->name = esoc_name;
		desc->link = esoc_link;
		desc->priv = esoc_clink;
		devres_add(dev, desc);
		return desc;
	}
	return NULL;
}
Esempio n. 12
0
int of_irq_map_raw(struct device_node *parent, const __be32 *intspec,
		   u32 ointsize, const __be32 *addr, struct of_irq *out_irq)
{
	struct device_node *ipar, *tnode, *old = NULL, *newpar = NULL;
	const __be32 *tmp, *imap, *imask;
	u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0;
	int imaplen, match, i;

	pr_debug("of_irq_map_raw: par=%s,intspec=[0x%08x 0x%08x...],ointsize=%d\n",
		 parent->full_name, be32_to_cpup(intspec),
		 be32_to_cpup(intspec + 1), ointsize);

	ipar = of_node_get(parent);

	/*                                                              
                                                                  
                                                  
  */
	do {
		tmp = of_get_property(ipar, "#interrupt-cells", NULL);
		if (tmp != NULL) {
			intsize = be32_to_cpu(*tmp);
			break;
		}
		tnode = ipar;
		ipar = of_irq_find_parent(ipar);
		of_node_put(tnode);
	} while (ipar);
	if (ipar == NULL) {
		pr_debug(" -> no parent found !\n");
		goto fail;
	}

	pr_debug("of_irq_map_raw: ipar=%s, size=%d\n", ipar->full_name, intsize);

	if (ointsize != intsize)
		return -EINVAL;

	/*                                                                 
                                                                        
  */
	old = of_node_get(ipar);
	do {
		tmp = of_get_property(old, "#address-cells", NULL);
		tnode = of_get_parent(old);
		of_node_put(old);
		old = tnode;
	} while (old && tmp == NULL);
	of_node_put(old);
	old = NULL;
	addrsize = (tmp == NULL) ? 2 : be32_to_cpu(*tmp);

	pr_debug(" -> addrsize=%d\n", addrsize);

	/*                                                          */
	while (ipar != NULL) {
		/*                                                            
                     
   */
		if (of_get_property(ipar, "interrupt-controller", NULL) !=
				NULL) {
			pr_debug(" -> got it !\n");
			for (i = 0; i < intsize; i++)
				out_irq->specifier[i] =
						of_read_number(intspec +i, 1);
			out_irq->size = intsize;
			out_irq->controller = ipar;
			of_node_put(old);
			return 0;
		}

		/*                               */
		imap = of_get_property(ipar, "interrupt-map", &imaplen);
		/*                                                 */
		if (imap == NULL) {
			pr_debug(" -> no map, getting parent\n");
			newpar = of_irq_find_parent(ipar);
			goto skiplevel;
		}
		imaplen /= sizeof(u32);

		/*                 */
		imask = of_get_property(ipar, "interrupt-map-mask", NULL);

		/*                                                            
                                                     
                      
   */
		if (addr == NULL && addrsize != 0) {
			pr_debug(" -> no reg passed in when needed !\n");
			goto fail;
		}

		/*                     */
		match = 0;
		while (imaplen > (addrsize + intsize + 1) && !match) {
			/*                    */
			match = 1;
			for (i = 0; i < addrsize && match; ++i) {
				u32 mask = imask ? imask[i] : 0xffffffffu;
				match = ((addr[i] ^ imap[i]) & mask) == 0;
			}
			for (; i < (addrsize + intsize) && match; ++i) {
				u32 mask = imask ? imask[i] : 0xffffffffu;
				match =
				   ((intspec[i-addrsize] ^ imap[i]) & mask) == 0;
			}
			imap += addrsize + intsize;
			imaplen -= addrsize + intsize;

			pr_debug(" -> match=%d (imaplen=%d)\n", match, imaplen);

			/*                          */
			if (of_irq_workarounds & OF_IMAP_NO_PHANDLE)
				newpar = of_node_get(of_irq_dflt_pic);
			else
				newpar = of_find_node_by_phandle(be32_to_cpup(imap));
			imap++;
			--imaplen;

			/*                    */
			if (newpar == NULL) {
				pr_debug(" -> imap parent not found !\n");
				goto fail;
			}

			/*                                               
            
    */
			tmp = of_get_property(newpar, "#interrupt-cells", NULL);
			if (tmp == NULL) {
				pr_debug(" -> parent lacks #interrupt-cells!\n");
				goto fail;
			}
			newintsize = be32_to_cpu(*tmp);
			tmp = of_get_property(newpar, "#address-cells", NULL);
			newaddrsize = (tmp == NULL) ? 0 : be32_to_cpu(*tmp);

			pr_debug(" -> newintsize=%d, newaddrsize=%d\n",
			    newintsize, newaddrsize);

			/*                                */
			if (imaplen < (newaddrsize + newintsize))
				goto fail;

			imap += newaddrsize + newintsize;
			imaplen -= newaddrsize + newintsize;

			pr_debug(" -> imaplen=%d\n", imaplen);
		}
		if (!match)
			goto fail;

		of_node_put(old);
		old = of_node_get(newpar);
		addrsize = newaddrsize;
		intsize = newintsize;
		intspec = imap - intsize;
		addr = intspec - addrsize;

	skiplevel:
		/*                               */
		pr_debug(" -> new parent: %s\n", newpar ? newpar->full_name : "<>");
		of_node_put(ipar);
		ipar = newpar;
		newpar = NULL;
	}
 fail:
	of_node_put(ipar);
	of_node_put(old);
	of_node_put(newpar);

	return -EINVAL;
}
Esempio n. 13
0
static int __init mv64x60_eth_device_setup(struct device_node *np, int id)
{
	struct resource r[1];
	struct mv643xx_eth_platform_data pdata;
	struct platform_device *pdev;
	struct device_node *phy;
	const u8 *mac_addr;
	const int *prop;
	const phandle *ph;
	int err;

	/* only register the shared platform device the first time through */
	if (id == 0 && (err = eth_register_shared_pdev(np)))
		return err;;

	memset(r, 0, sizeof(r));
	of_irq_to_resource(np, 0, &r[0]);

	memset(&pdata, 0, sizeof(pdata));

	prop = of_get_property(np, "block-index", NULL);
	if (!prop)
		return -ENODEV;
	pdata.port_number = *prop;

	mac_addr = of_get_mac_address(np);
	if (mac_addr)
		memcpy(pdata.mac_addr, mac_addr, 6);

	prop = of_get_property(np, "speed", NULL);
	if (prop)
		pdata.speed = *prop;

	prop = of_get_property(np, "tx_queue_size", NULL);
	if (prop)
		pdata.tx_queue_size = *prop;

	prop = of_get_property(np, "rx_queue_size", NULL);
	if (prop)
		pdata.rx_queue_size = *prop;

	prop = of_get_property(np, "tx_sram_addr", NULL);
	if (prop)
		pdata.tx_sram_addr = *prop;

	prop = of_get_property(np, "tx_sram_size", NULL);
	if (prop)
		pdata.tx_sram_size = *prop;

	prop = of_get_property(np, "rx_sram_addr", NULL);
	if (prop)
		pdata.rx_sram_addr = *prop;

	prop = of_get_property(np, "rx_sram_size", NULL);
	if (prop)
		pdata.rx_sram_size = *prop;

	ph = of_get_property(np, "phy", NULL);
	if (!ph)
		return -ENODEV;

	phy = of_find_node_by_phandle(*ph);
	if (phy == NULL)
		return -ENODEV;

	prop = of_get_property(phy, "reg", NULL);
	if (prop) {
		pdata.force_phy_addr = 1;
		pdata.phy_addr = *prop;
	}

	of_node_put(phy);

	pdev = platform_device_alloc(MV643XX_ETH_NAME, pdata.port_number);
	if (!pdev)
		return -ENOMEM;

	err = platform_device_add_resources(pdev, r, 1);
	if (err)
		goto error;

	err = platform_device_add_data(pdev, &pdata, sizeof(pdata));
	if (err)
		goto error;

	err = platform_device_add(pdev);
	if (err)
		goto error;

	return 0;

error:
	platform_device_put(pdev);
	return err;
}
Esempio n. 14
0
int of_pinctrl_select_state(struct device_node *np, const char *name)
{
	int state, ret;
	char propname[sizeof("pinctrl-4294967295")];
	const __be32 *list;
	int size, config;
	phandle phandle;
	struct device_node *np_config;
	const char *statename;

	if (!of_find_property(np, "pinctrl-0", NULL))
		return 0;

	/* For each defined state ID */
	for (state = 0; ; state++) {
		/* Retrieve the pinctrl-* property */
		sprintf(propname, "pinctrl-%d", state);
		list = of_get_property(np, propname, &size);
		if (!list) {
			ret = -ENODEV;
			break;
		}

		size /= sizeof(*list);

		/* Determine whether pinctrl-names property names the state */
		ret = of_property_read_string_index(np, "pinctrl-names",
						    state, &statename);
		/*
		 * If not, statename is just the integer state ID. But rather
		 * than dynamically allocate it and have to free it later,
		 * just point part way into the property name for the string.
		 */
		if (ret < 0) {
			/* strlen("pinctrl-") == 8 */
			statename = &propname[8];
		}

		if (strcmp(name, statename))
			continue;

		/* For every referenced pin configuration node in it */
		for (config = 0; config < size; config++) {
			phandle = be32_to_cpup(list++);

			/* Look up the pin configuration node */
			np_config = of_find_node_by_phandle(phandle);
			if (!np_config) {
				pr_err("prop %s %s index %i invalid phandle\n",
					np->full_name, propname, config);
				ret = -EINVAL;
				goto err;
			}

			/* Parse the node */
			ret = pinctrl_config_one(np_config);
			if (ret < 0)
				goto err;
		}

		return 0;
	}
err:
	return ret;
}
Esempio n. 15
0
static int __init fs_enet_of_init(void)
{
	struct device_node *np;
	unsigned int i;
	struct platform_device *fs_enet_dev = NULL;
	struct resource res;
	int ret;

	for (np = NULL, i = 0;
	     (np = of_find_compatible_node(np, "network", "fs_enet")) != NULL;
	     i++) {
		struct resource r[4];
		struct device_node *phy = NULL, *mdio = NULL;
		struct fs_platform_info fs_enet_data;
		const unsigned int *id;
		const unsigned int *phy_addr;
		const void *mac_addr;
		const phandle *ph;
		const char *model;

		memset(r, 0, sizeof(r));
		memset(&fs_enet_data, 0, sizeof(fs_enet_data));

		model = of_get_property(np, "model", NULL);
		if (model == NULL) {
			ret = -ENODEV;
			goto unreg;
		}

		id = of_get_property(np, "device-id", NULL);
		fs_enet_data.fs_no = *id;

		if (platform_device_skip(model, *id))
			continue;

		ret = of_address_to_resource(np, 0, &r[0]);
		if (ret)
			goto err;
		r[0].name = enet_regs;

		mac_addr = of_get_mac_address(np);
		if (mac_addr)
			memcpy(fs_enet_data.macaddr, mac_addr, 6);

		ph = of_get_property(np, "phy-handle", NULL);
		if (ph != NULL)
			phy = of_find_node_by_phandle(*ph);

		if (phy != NULL) {
			phy_addr = of_get_property(phy, "reg", NULL);
			fs_enet_data.phy_addr = *phy_addr;
			fs_enet_data.has_phy = 1;

			mdio = of_get_parent(phy);
			ret = of_address_to_resource(mdio, 0, &res);
			if (ret) {
				of_node_put(phy);
				of_node_put(mdio);
                                goto unreg;
			}
		}

		model = of_get_property(np, "model", NULL);
		strcpy(fs_enet_data.fs_type, model);

		if (strstr(model, "FEC")) {
			r[1].start = r[1].end = irq_of_parse_and_map(np, 0);
			r[1].flags = IORESOURCE_IRQ;
			r[1].name = enet_irq;

			fs_enet_dev =
				    platform_device_register_simple("fsl-cpm-fec", i, &r[0], 2);

			if (IS_ERR(fs_enet_dev)) {
				ret = PTR_ERR(fs_enet_dev);
				goto err;
			}

			fs_enet_data.rx_ring = 128;
			fs_enet_data.tx_ring = 16;
			fs_enet_data.rx_copybreak = 240;
			fs_enet_data.use_napi = 1;
			fs_enet_data.napi_weight = 17;

			snprintf((char*)&bus_id[i], BUS_ID_SIZE, "%x:%02x",
							(u32)res.start, fs_enet_data.phy_addr);
			fs_enet_data.bus_id = (char*)&bus_id[i];
			fs_enet_data.init_ioports = init_fec_ioports;
		}
		if (strstr(model, "SCC")) {
			ret = of_address_to_resource(np, 1, &r[1]);
			if (ret)
				goto err;
			r[1].name = enet_pram;

			r[2].start = r[2].end = irq_of_parse_and_map(np, 0);
			r[2].flags = IORESOURCE_IRQ;
			r[2].name = enet_irq;

			fs_enet_dev =
				    platform_device_register_simple("fsl-cpm-scc", i, &r[0], 3);

			if (IS_ERR(fs_enet_dev)) {
				ret = PTR_ERR(fs_enet_dev);
				goto err;
			}

			fs_enet_data.rx_ring = 64;
			fs_enet_data.tx_ring = 8;
			fs_enet_data.rx_copybreak = 240;
			fs_enet_data.use_napi = 1;
			fs_enet_data.napi_weight = 17;

			snprintf((char*)&bus_id[i], BUS_ID_SIZE, "%s", "fixed@10:1");
                        fs_enet_data.bus_id = (char*)&bus_id[i];
			fs_enet_data.init_ioports = init_scc_ioports;
		}

		of_node_put(phy);
		of_node_put(mdio);

		ret = platform_device_add_data(fs_enet_dev, &fs_enet_data,
					     sizeof(struct
						    fs_platform_info));
		if (ret)
			goto unreg;
	}
	return 0;

unreg:
	platform_device_unregister(fs_enet_dev);
err:
	return ret;
}
Esempio n. 16
0
static int __init fs_enet_of_init(void)
{
	struct device_node *np;
	unsigned int i;
	struct platform_device *fs_enet_dev;
	struct resource res;
	int ret;

	for (np = NULL, i = 0;
	     (np = of_find_compatible_node(np, "network", "fs_enet")) != NULL;
	     i++) {
		struct resource r[4];
		struct device_node *phy, *mdio;
		struct fs_platform_info fs_enet_data;
		const unsigned int *id, *phy_addr, *phy_irq;
		const void *mac_addr;
		const phandle *ph;
		const char *model;

		memset(r, 0, sizeof(r));
		memset(&fs_enet_data, 0, sizeof(fs_enet_data));

		ret = of_address_to_resource(np, 0, &r[0]);
		if (ret)
			goto err;
		r[0].name = fcc_regs;

		ret = of_address_to_resource(np, 1, &r[1]);
		if (ret)
			goto err;
		r[1].name = fcc_pram;

		ret = of_address_to_resource(np, 2, &r[2]);
		if (ret)
			goto err;
		r[2].name = fcc_regs_c;
		fs_enet_data.fcc_regs_c = r[2].start;

		of_irq_to_resource(np, 0, &r[3]);

		fs_enet_dev =
		    platform_device_register_simple("fsl-cpm-fcc", i, &r[0], 4);

		if (IS_ERR(fs_enet_dev)) {
			ret = PTR_ERR(fs_enet_dev);
			goto err;
		}

		model = of_get_property(np, "model", NULL);
		if (model == NULL) {
			ret = -ENODEV;
			goto unreg;
		}

		mac_addr = of_get_mac_address(np);
		if (mac_addr)
			memcpy(fs_enet_data.macaddr, mac_addr, 6);

		ph = of_get_property(np, "phy-handle", NULL);
		phy = of_find_node_by_phandle(*ph);

		if (phy == NULL) {
			ret = -ENODEV;
			goto unreg;
		}

		phy_addr = of_get_property(phy, "reg", NULL);
		fs_enet_data.phy_addr = *phy_addr;

		phy_irq = of_get_property(phy, "interrupts", NULL);

		id = of_get_property(np, "device-id", NULL);
		fs_enet_data.fs_no = *id;
		strcpy(fs_enet_data.fs_type, model);

		mdio = of_get_parent(phy);
                ret = of_address_to_resource(mdio, 0, &res);
                if (ret) {
                        of_node_put(phy);
                        of_node_put(mdio);
                        goto unreg;
                }

		fs_enet_data.clk_rx = *((u32 *)of_get_property(np,
						"rx-clock", NULL));
		fs_enet_data.clk_tx = *((u32 *)of_get_property(np,
						"tx-clock", NULL));

		if (strstr(model, "FCC")) {
			int fcc_index = *id - 1;
			const unsigned char *mdio_bb_prop;

			fs_enet_data.dpram_offset = (u32)cpm_dpram_addr(0);
			fs_enet_data.rx_ring = 32;
			fs_enet_data.tx_ring = 32;
			fs_enet_data.rx_copybreak = 240;
			fs_enet_data.use_napi = 0;
			fs_enet_data.napi_weight = 17;
			fs_enet_data.mem_offset = FCC_MEM_OFFSET(fcc_index);
			fs_enet_data.cp_page = CPM_CR_FCC_PAGE(fcc_index);
			fs_enet_data.cp_block = CPM_CR_FCC_SBLOCK(fcc_index);

			snprintf((char*)&bus_id[(*id)], BUS_ID_SIZE, "%x:%02x",
							(u32)res.start, fs_enet_data.phy_addr);
			fs_enet_data.bus_id = (char*)&bus_id[(*id)];
			fs_enet_data.init_ioports = init_fcc_ioports;

			mdio_bb_prop = of_get_property(phy, "bitbang", NULL);
			if (mdio_bb_prop) {
				struct platform_device *fs_enet_mdio_bb_dev;
				struct fs_mii_bb_platform_info fs_enet_mdio_bb_data;

				fs_enet_mdio_bb_dev =
					platform_device_register_simple("fsl-bb-mdio",
							i, NULL, 0);
				memset(&fs_enet_mdio_bb_data, 0,
						sizeof(struct fs_mii_bb_platform_info));
				fs_enet_mdio_bb_data.mdio_dat.bit =
					mdio_bb_prop[0];
				fs_enet_mdio_bb_data.mdio_dir.bit =
					mdio_bb_prop[1];
				fs_enet_mdio_bb_data.mdc_dat.bit =
					mdio_bb_prop[2];
				fs_enet_mdio_bb_data.mdio_port =
					mdio_bb_prop[3];
				fs_enet_mdio_bb_data.mdc_port =
					mdio_bb_prop[4];
				fs_enet_mdio_bb_data.delay =
					mdio_bb_prop[5];

				fs_enet_mdio_bb_data.irq[0] = phy_irq[0];
				fs_enet_mdio_bb_data.irq[1] = -1;
				fs_enet_mdio_bb_data.irq[2] = -1;
				fs_enet_mdio_bb_data.irq[3] = phy_irq[0];
				fs_enet_mdio_bb_data.irq[31] = -1;

				fs_enet_mdio_bb_data.mdio_dat.offset =
					(u32)&cpm2_immr->im_ioport.iop_pdatc;
				fs_enet_mdio_bb_data.mdio_dir.offset =
					(u32)&cpm2_immr->im_ioport.iop_pdirc;
				fs_enet_mdio_bb_data.mdc_dat.offset =
					(u32)&cpm2_immr->im_ioport.iop_pdatc;

				ret = platform_device_add_data(
						fs_enet_mdio_bb_dev,
						&fs_enet_mdio_bb_data,
						sizeof(struct fs_mii_bb_platform_info));
				if (ret)
					goto unreg;
			}

			of_node_put(phy);
			of_node_put(mdio);

			ret = platform_device_add_data(fs_enet_dev, &fs_enet_data,
						     sizeof(struct
							    fs_platform_info));
			if (ret)
				goto unreg;
		}
	}
	return 0;

unreg:
	platform_device_unregister(fs_enet_dev);
err:
	return ret;
}
Esempio n. 17
0
static int __init gfar_of_init(void)
{
	struct device_node *np;
	unsigned int i;
	struct platform_device *gfar_dev;
	struct resource res;
	int ret;

	for (np = NULL, i = 0;
	     (np = of_find_compatible_node(np, "network", "gianfar")) != NULL;
	     i++) {
		struct resource r[4];
		struct device_node *phy, *mdio;
		struct gianfar_platform_data gfar_data;
		const unsigned int *id;
		const char *model;
		const void *mac_addr;
		const phandle *ph;
		int n_res = 2;

		memset(r, 0, sizeof(r));
		memset(&gfar_data, 0, sizeof(gfar_data));

		ret = of_address_to_resource(np, 0, &r[0]);
		if (ret)
			goto err;

		of_irq_to_resource(np, 0, &r[1]);

		model = of_get_property(np, "model", NULL);

		/* If we aren't the FEC we have multiple interrupts */
		if (model && strcasecmp(model, "FEC")) {
			r[1].name = gfar_tx_intr;

			r[2].name = gfar_rx_intr;
			of_irq_to_resource(np, 1, &r[2]);

			r[3].name = gfar_err_intr;
			of_irq_to_resource(np, 2, &r[3]);

			n_res += 2;
		}

		gfar_dev =
		    platform_device_register_simple("fsl-gianfar", i, &r[0],
						    n_res);

		if (IS_ERR(gfar_dev)) {
			ret = PTR_ERR(gfar_dev);
			goto err;
		}

		mac_addr = of_get_mac_address(np);
		if (mac_addr)
			memcpy(gfar_data.mac_addr, mac_addr, 6);

		if (model && !strcasecmp(model, "TSEC"))
			gfar_data.device_flags =
			    FSL_GIANFAR_DEV_HAS_GIGABIT |
			    FSL_GIANFAR_DEV_HAS_COALESCE |
			    FSL_GIANFAR_DEV_HAS_RMON |
			    FSL_GIANFAR_DEV_HAS_MULTI_INTR;
		if (model && !strcasecmp(model, "eTSEC"))
			gfar_data.device_flags =
			    FSL_GIANFAR_DEV_HAS_GIGABIT |
			    FSL_GIANFAR_DEV_HAS_COALESCE |
			    FSL_GIANFAR_DEV_HAS_RMON |
			    FSL_GIANFAR_DEV_HAS_MULTI_INTR |
			    FSL_GIANFAR_DEV_HAS_CSUM |
			    FSL_GIANFAR_DEV_HAS_VLAN |
			    FSL_GIANFAR_DEV_HAS_EXTENDED_HASH;

		ph = of_get_property(np, "phy-handle", NULL);
		phy = of_find_node_by_phandle(*ph);

		if (phy == NULL) {
			ret = -ENODEV;
			goto unreg;
		}

		mdio = of_get_parent(phy);

		id = of_get_property(phy, "reg", NULL);
		ret = of_address_to_resource(mdio, 0, &res);
		if (ret) {
			of_node_put(phy);
			of_node_put(mdio);
			goto unreg;
		}

		gfar_data.phy_id = *id;
		gfar_data.bus_id = res.start;

		of_node_put(phy);
		of_node_put(mdio);

		ret =
		    platform_device_add_data(gfar_dev, &gfar_data,
					     sizeof(struct
						    gianfar_platform_data));
		if (ret)
			goto unreg;
	}

	return 0;

unreg:
	platform_device_unregister(gfar_dev);
err:
	return ret;
}
Esempio n. 18
0
int of_get_gpio(struct device_node *np, int index)
{
	int ret = -EINVAL;
	struct device_node *gc;
	struct of_gpio_chip *of_gc = NULL;
	int size;
	const u32 *gpios;
	u32 nr_cells;
	int i;
	const void *gpio_spec;
	const u32 *gpio_cells;
	int gpio_index = 0;

	gpios = of_get_property(np, "gpios", &size);
	if (!gpios) {
		ret = -ENOENT;
		goto err0;
	}
	nr_cells = size / sizeof(u32);

	for (i = 0; i < nr_cells;) {
		const phandle *gpio_phandle;

		gpio_phandle = gpios + i;
		gpio_spec = gpio_phandle + 1;

		/* one cell hole in the gpios = <>; */
		if (!*gpio_phandle) {
			if (gpio_index == index)
				return -ENOENT;
			i++;
			gpio_index++;
			continue;
		}

		gc = of_find_node_by_phandle(*gpio_phandle);
		if (!gc) {
			pr_debug("%s: could not find phandle for gpios\n",
				 np->full_name);
			goto err0;
		}

		of_gc = gc->data;
		if (!of_gc) {
			pr_debug("%s: gpio controller %s isn't registered\n",
				 np->full_name, gc->full_name);
			goto err1;
		}

		gpio_cells = of_get_property(gc, "#gpio-cells", &size);
		if (!gpio_cells || size != sizeof(*gpio_cells) ||
				*gpio_cells != of_gc->gpio_cells) {
			pr_debug("%s: wrong #gpio-cells for %s\n",
				 np->full_name, gc->full_name);
			goto err1;
		}

		/* Next phandle is at phandle cells + #gpio-cells */
		i += sizeof(*gpio_phandle) / sizeof(u32) + *gpio_cells;
		if (i >= nr_cells + 1) {
			pr_debug("%s: insufficient gpio-spec length\n",
				 np->full_name);
			goto err1;
		}

		if (gpio_index == index)
			break;

		of_gc = NULL;
		of_node_put(gc);
		gpio_index++;
	}

	if (!of_gc) {
		ret = -ENOENT;
		goto err0;
	}

	ret = of_gc->xlate(of_gc, np, gpio_spec);
	if (ret < 0)
		goto err1;

	ret += of_gc->gc.base;
err1:
	of_node_put(gc);
err0:
	pr_debug("%s exited with status %d\n", __func__, ret);
	return ret;
}
Esempio n. 19
0
static int rbppc_nand_probe(struct platform_device *pdev)
{
	struct device_node *gpio;
	struct device_node *nnand;
	struct resource res;
	struct rbppc_info *info;
	void *baddr;
	const unsigned *rdy, *nce, *cle, *ale;

	printk("RB_PPC NAND\n");

	info = kmalloc(sizeof(*info), GFP_KERNEL);

	rdy = of_get_property(pdev->dev.of_node, "rdy", NULL);
	nce = of_get_property(pdev->dev.of_node, "nce", NULL);
	cle = of_get_property(pdev->dev.of_node, "cle", NULL);
	ale = of_get_property(pdev->dev.of_node, "ale", NULL);

	if (!rdy || !nce || !cle || !ale) {
		printk("rbppc nand error: gpios properties are missing\n");
		goto err;
	}
	if (rdy[0] != nce[0] || rdy[0] != cle[0] || rdy[0] != ale[0]) {
		printk("rbppc nand error: "
		       "different gpios are not supported\n");
		goto err;
	}

	gpio = of_find_node_by_phandle(rdy[0]);
	if (!gpio) {
		printk("rbppc nand error: no gpio<%x> node found\n", *rdy);
		goto err;
	}
	if (of_address_to_resource(gpio, 0, &res)) {
		printk("rbppc nand error: no reg property in gpio found\n");
		goto err;
	}
	info->gpo = ioremap_nocache(res.start, res.end - res.start + 1);

	if (!of_address_to_resource(gpio, 1, &res)) {
		info->gpi = ioremap_nocache(res.start, res.end - res.start + 1);
	} else {
		info->gpi = info->gpo;
	}
	of_node_put(gpio);

	info->gpio_rdy = 1 << (31 - rdy[1]);
	info->gpio_nce = 1 << (31 - nce[1]);
	info->gpio_cle = 1 << (31 - cle[1]);
	info->gpio_ale = 1 << (31 - ale[1]);
	info->gpio_ctrls = info->gpio_nce | info->gpio_cle | info->gpio_ale;

	nnand = of_find_node_by_name(NULL, "nnand");
	if (!nnand) {
		printk("rbppc nand error: no nnand found\n");
		goto err;
	}
	if (of_address_to_resource(nnand, 0, &res)) {
		printk("rbppc nand error: no reg property in nnand found\n");
		goto err;
	}
	of_node_put(nnand);
	info->localbus = ioremap_nocache(res.start, res.end - res.start + 1);
	
	if (of_address_to_resource(pdev->dev.of_node, 0, &res)) {
	    printk("rbppc nand error: no reg property found\n");
	    goto err;
	}
	baddr = ioremap_nocache(res.start, res.end - res.start + 1);

	memset(&rnand, 0, sizeof(rnand));
	rnand.cmd_ctrl = rbppc_nand_hwcontrol;
    	rnand.dev_ready = rbppc_nand_ready;
    	rnand.read_buf = rbppc_read_buf;
	rnand.IO_ADDR_W = baddr;
	rnand.IO_ADDR_R = baddr;
	rnand.priv = info;

	return rb_nand_probe(&rnand, 0);

  err:
	kfree(info);
	return -1;
}
/**
 * of_irq_parse_raw - Low level interrupt tree parsing
 * @parent:	the device interrupt parent
 * @addr:	address specifier (start of "reg" property of the device) in be32 format
 * @out_irq:	structure of_irq updated by this function
 *
 * Returns 0 on success and a negative number on error
 *
 * This function is a low-level interrupt tree walking function. It
 * can be used to do a partial walk with synthetized reg and interrupts
 * properties, for example when resolving PCI interrupts when no device
 * node exist for the parent. It takes an interrupt specifier structure as
 * input, walks the tree looking for any interrupt-map properties, translates
 * the specifier for each map, and then returns the translated map.
 */
int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
{
	struct device_node *ipar, *tnode, *old = NULL, *newpar = NULL;
	__be32 initial_match_array[MAX_PHANDLE_ARGS];
	const __be32 *match_array = initial_match_array;
	const __be32 *tmp, *imap, *imask, dummy_imask[] = { [0 ... MAX_PHANDLE_ARGS] = ~0 };
	u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0;
	int imaplen, match, i;

#ifdef DEBUG
	of_print_phandle_args("of_irq_parse_raw: ", out_irq);
#endif

	ipar = of_node_get(out_irq->np);

	/* First get the #interrupt-cells property of the current cursor
	 * that tells us how to interpret the passed-in intspec. If there
	 * is none, we are nice and just walk up the tree
	 */
	do {
		tmp = of_get_property(ipar, "#interrupt-cells", NULL);
		if (tmp != NULL) {
			intsize = be32_to_cpu(*tmp);
			break;
		}
		tnode = ipar;
		ipar = of_irq_find_parent(ipar);
		of_node_put(tnode);
	} while (ipar);
	if (ipar == NULL) {
		pr_debug(" -> no parent found !\n");
		goto fail;
	}

	pr_debug("of_irq_parse_raw: ipar=%s, size=%d\n", of_node_full_name(ipar), intsize);

	if (out_irq->args_count != intsize)
		return -EINVAL;

	/* Look for this #address-cells. We have to implement the old linux
	 * trick of looking for the parent here as some device-trees rely on it
	 */
	old = of_node_get(ipar);
	do {
		tmp = of_get_property(old, "#address-cells", NULL);
		tnode = of_get_parent(old);
		of_node_put(old);
		old = tnode;
	} while (old && tmp == NULL);
	of_node_put(old);
	old = NULL;
	addrsize = (tmp == NULL) ? 2 : be32_to_cpu(*tmp);

	pr_debug(" -> addrsize=%d\n", addrsize);

	/* Range check so that the temporary buffer doesn't overflow */
	if (WARN_ON(addrsize + intsize > MAX_PHANDLE_ARGS))
		goto fail;

	/* Precalculate the match array - this simplifies match loop */
	for (i = 0; i < addrsize; i++)
		initial_match_array[i] = addr ? addr[i] : 0;
	for (i = 0; i < intsize; i++)
		initial_match_array[addrsize + i] = cpu_to_be32(out_irq->args[i]);

	/* Now start the actual "proper" walk of the interrupt tree */
	while (ipar != NULL) {
		/* Now check if cursor is an interrupt-controller and if it is
		 * then we are done
		 */
		if (of_get_property(ipar, "interrupt-controller", NULL) !=
				NULL) {
			pr_debug(" -> got it !\n");
			return 0;
		}

		/*
		 * interrupt-map parsing does not work without a reg
		 * property when #address-cells != 0
		 */
		if (addrsize && !addr) {
			pr_debug(" -> no reg passed in when needed !\n");
			goto fail;
		}

		/* Now look for an interrupt-map */
		imap = of_get_property(ipar, "interrupt-map", &imaplen);
		/* No interrupt map, check for an interrupt parent */
		if (imap == NULL) {
			pr_debug(" -> no map, getting parent\n");
			newpar = of_irq_find_parent(ipar);
			goto skiplevel;
		}
		imaplen /= sizeof(u32);

		/* Look for a mask */
		imask = of_get_property(ipar, "interrupt-map-mask", NULL);
		if (!imask)
			imask = dummy_imask;

		/* Parse interrupt-map */
		match = 0;
		while (imaplen > (addrsize + intsize + 1) && !match) {
			/* Compare specifiers */
			match = 1;
			for (i = 0; i < (addrsize + intsize); i++, imaplen--)
				match &= !((match_array[i] ^ *imap++) & imask[i]);

			pr_debug(" -> match=%d (imaplen=%d)\n", match, imaplen);

			/* Get the interrupt parent */
			if (of_irq_workarounds & OF_IMAP_NO_PHANDLE)
				newpar = of_node_get(of_irq_dflt_pic);
			else
				newpar = of_find_node_by_phandle(be32_to_cpup(imap));
			imap++;
			--imaplen;

			/* Check if not found */
			if (newpar == NULL) {
				pr_debug(" -> imap parent not found !\n");
				goto fail;
			}

			/* Get #interrupt-cells and #address-cells of new
			 * parent
			 */
			tmp = of_get_property(newpar, "#interrupt-cells", NULL);
			if (tmp == NULL) {
				pr_debug(" -> parent lacks #interrupt-cells!\n");
				goto fail;
			}
			newintsize = be32_to_cpu(*tmp);
			tmp = of_get_property(newpar, "#address-cells", NULL);
			newaddrsize = (tmp == NULL) ? 0 : be32_to_cpu(*tmp);

			pr_debug(" -> newintsize=%d, newaddrsize=%d\n",
			    newintsize, newaddrsize);

			/* Check for malformed properties */
			if (WARN_ON(newaddrsize + newintsize > MAX_PHANDLE_ARGS))
				goto fail;
			if (imaplen < (newaddrsize + newintsize))
				goto fail;

			imap += newaddrsize + newintsize;
			imaplen -= newaddrsize + newintsize;

			pr_debug(" -> imaplen=%d\n", imaplen);
		}
		if (!match)
			goto fail;

		/*
		 * Successfully parsed an interrrupt-map translation; copy new
		 * interrupt specifier into the out_irq structure
		 */
		out_irq->np = newpar;

		match_array = imap - newaddrsize - newintsize;
		for (i = 0; i < newintsize; i++)
			out_irq->args[i] = be32_to_cpup(imap - newintsize + i);
		out_irq->args_count = intsize = newintsize;
		addrsize = newaddrsize;

	skiplevel:
		/* Iterate again with new parent */
		pr_debug(" -> new parent: %s\n", of_node_full_name(newpar));
		of_node_put(ipar);
		ipar = newpar;
		newpar = NULL;
	}
 fail:
	of_node_put(ipar);
	of_node_put(newpar);

	return -EINVAL;
}
Esempio n. 21
0
static int update_dt_node(u32 phandle, s32 scope)
{
	struct update_props_workarea *upwa;
	struct device_node *dn;
	struct property *prop = NULL;
	int i, rc, rtas_rc;
	char *prop_data;
	char *rtas_buf;
	int update_properties_token;
	u32 vd;

	update_properties_token = rtas_token("ibm,update-properties");
	if (update_properties_token == RTAS_UNKNOWN_SERVICE)
		return -EINVAL;

	rtas_buf = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL);
	if (!rtas_buf)
		return -ENOMEM;

	dn = of_find_node_by_phandle(phandle);
	if (!dn) {
		kfree(rtas_buf);
		return -ENOENT;
	}

	upwa = (struct update_props_workarea *)&rtas_buf[0];
	upwa->phandle = phandle;

	do {
		rtas_rc = mobility_rtas_call(update_properties_token, rtas_buf,
					scope);
		if (rtas_rc < 0)
			break;

		prop_data = rtas_buf + sizeof(*upwa);

		/* On the first call to ibm,update-properties for a node the
		 * the first property value descriptor contains an empty
		 * property name, the property value length encoded as u32,
		 * and the property value is the node path being updated.
		 */
		if (*prop_data == 0) {
			prop_data++;
			vd = *(u32 *)prop_data;
			prop_data += vd + sizeof(vd);
			upwa->nprops--;
		}

		for (i = 0; i < upwa->nprops; i++) {
			char *prop_name;

			prop_name = prop_data;
			prop_data += strlen(prop_name) + 1;
			vd = *(u32 *)prop_data;
			prop_data += sizeof(vd);

			switch (vd) {
			case 0x00000000:
				/* name only property, nothing to do */
				break;

			case 0x80000000:
				prop = of_find_property(dn, prop_name, NULL);
				of_remove_property(dn, prop);
				prop = NULL;
				break;

			default:
				rc = update_dt_property(dn, &prop, prop_name,
							vd, prop_data);
				if (rc) {
					printk(KERN_ERR "Could not update %s"
					       " property\n", prop_name);
				}

				prop_data += vd;
			}
		}
	} while (rtas_rc == 1);

	of_node_put(dn);
	kfree(rtas_buf);
	return 0;
}
Esempio n. 22
0
int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize,
		const u32 *addr, struct of_irq *out_irq)
{
	struct device_node *ipar, *tnode, *old = NULL, *newpar = NULL;
	const u32 *tmp, *imap, *imask;
	u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0;
	int imaplen, match, i;

	DBG("of_irq_map_raw: par=%s,intspec=[0x%08x 0x%08x...],ointsize=%d\n",
	    parent->full_name, intspec[0], intspec[1], ointsize);

	ipar = of_node_get(parent);

	/* First get the #interrupt-cells property of the current cursor
	 * that tells us how to interpret the passed-in intspec. If there
	 * is none, we are nice and just walk up the tree
	 */
	do {
		tmp = of_get_property(ipar, "#interrupt-cells", NULL);
		if (tmp != NULL) {
			intsize = *tmp;
			break;
		}
		tnode = ipar;
		ipar = of_irq_find_parent(ipar);
		of_node_put(tnode);
	} while (ipar);
	if (ipar == NULL) {
		DBG(" -> no parent found !\n");
		goto fail;
	}

	DBG("of_irq_map_raw: ipar=%s, size=%d\n", ipar->full_name, intsize);

	if (ointsize != intsize)
		return -EINVAL;

	/* Look for this #address-cells. We have to implement the old linux
	 * trick of looking for the parent here as some device-trees rely on it
	 */
	old = of_node_get(ipar);
	do {
		tmp = of_get_property(old, "#address-cells", NULL);
		tnode = of_get_parent(old);
		of_node_put(old);
		old = tnode;
	} while(old && tmp == NULL);
	of_node_put(old);
	old = NULL;
	addrsize = (tmp == NULL) ? 2 : *tmp;

	DBG(" -> addrsize=%d\n", addrsize);

	/* Now start the actual "proper" walk of the interrupt tree */
	while (ipar != NULL) {
		/* Now check if cursor is an interrupt-controller and if it is
		 * then we are done
		 */
		if (of_get_property(ipar, "interrupt-controller", NULL) !=
				NULL) {
			DBG(" -> got it !\n");
			memcpy(out_irq->specifier, intspec,
			       intsize * sizeof(u32));
			out_irq->size = intsize;
			out_irq->controller = ipar;
			of_node_put(old);
			return 0;
		}

		/* Now look for an interrupt-map */
		imap = of_get_property(ipar, "interrupt-map", &imaplen);
		/* No interrupt map, check for an interrupt parent */
		if (imap == NULL) {
			DBG(" -> no map, getting parent\n");
			newpar = of_irq_find_parent(ipar);
			goto skiplevel;
		}
		imaplen /= sizeof(u32);

		/* Look for a mask */
		imask = of_get_property(ipar, "interrupt-map-mask", NULL);

		/* If we were passed no "reg" property and we attempt to parse
		 * an interrupt-map, then #address-cells must be 0.
		 * Fail if it's not.
		 */
		if (addr == NULL && addrsize != 0) {
			DBG(" -> no reg passed in when needed !\n");
			goto fail;
		}

		/* Parse interrupt-map */
		match = 0;
		while (imaplen > (addrsize + intsize + 1) && !match) {
			/* Compare specifiers */
			match = 1;
			for (i = 0; i < addrsize && match; ++i) {
				u32 mask = imask ? imask[i] : 0xffffffffu;
				match = ((addr[i] ^ imap[i]) & mask) == 0;
			}
			for (; i < (addrsize + intsize) && match; ++i) {
				u32 mask = imask ? imask[i] : 0xffffffffu;
				match =
				   ((intspec[i-addrsize] ^ imap[i]) & mask) == 0;
			}
			imap += addrsize + intsize;
			imaplen -= addrsize + intsize;

			DBG(" -> match=%d (imaplen=%d)\n", match, imaplen);

			/* Get the interrupt parent */
			if (of_irq_workarounds & OF_IMAP_NO_PHANDLE)
				newpar = of_node_get(of_irq_dflt_pic);
			else
				newpar = of_find_node_by_phandle((phandle)*imap);
			imap++;
			--imaplen;

			/* Check if not found */
			if (newpar == NULL) {
				DBG(" -> imap parent not found !\n");
				goto fail;
			}

			/* Get #interrupt-cells and #address-cells of new
			 * parent
			 */
			tmp = of_get_property(newpar, "#interrupt-cells", NULL);
			if (tmp == NULL) {
				DBG(" -> parent lacks #interrupt-cells !\n");
				goto fail;
			}
			newintsize = *tmp;
			tmp = of_get_property(newpar, "#address-cells", NULL);
			newaddrsize = (tmp == NULL) ? 0 : *tmp;

			DBG(" -> newintsize=%d, newaddrsize=%d\n",
			    newintsize, newaddrsize);

			/* Check for malformed properties */
			if (imaplen < (newaddrsize + newintsize))
				goto fail;

			imap += newaddrsize + newintsize;
			imaplen -= newaddrsize + newintsize;

			DBG(" -> imaplen=%d\n", imaplen);
		}
		if (!match)
			goto fail;

		of_node_put(old);
		old = of_node_get(newpar);
		addrsize = newaddrsize;
		intsize = newintsize;
		intspec = imap - intsize;
		addr = intspec - addrsize;

	skiplevel:
		/* Iterate again with new parent */
		DBG(" -> new parent: %s\n", newpar ? newpar->full_name : "<>");
		of_node_put(ipar);
		ipar = newpar;
		newpar = NULL;
	}
 fail:
	of_node_put(ipar);
	of_node_put(old);
	of_node_put(newpar);

	return -EINVAL;
}
Esempio n. 23
0
/**
 * of_parse_phandles_with_args - Find a node pointed by phandle in a list
 * @np:		pointer to a device tree node containing a list
 * @list_name:	property name that contains a list
 * @cells_name:	property name that specifies phandles' arguments count
 * @index:	index of a phandle to parse out
 * @out_node:	optional pointer to device_node struct pointer (will be filled)
 * @out_args:	optional pointer to arguments pointer (will be filled)
 *
 * This function is useful to parse lists of phandles and their arguments.
 * Returns 0 on success and fills out_node and out_args, on error returns
 * appropriate errno value.
 *
 * Example:
 *
 * phandle1: node1 {
 * 	#list-cells = <2>;
 * }
 *
 * phandle2: node2 {
 * 	#list-cells = <1>;
 * }
 *
 * node3 {
 * 	list = <&phandle1 1 2 &phandle2 3>;
 * }
 *
 * To get a device_node of the `node2' node you may call this:
 * of_parse_phandles_with_args(node3, "list", "#list-cells", 2, &node2, &args);
 */
int of_parse_phandles_with_args(struct device_node *np, const char *list_name,
				const char *cells_name, int index,
				struct device_node **out_node,
				const void **out_args)
{
	int ret = -EINVAL;
	const __be32 *list;
	const __be32 *list_end;
	int size;
	int cur_index = 0;
	struct device_node *node = NULL;
	const void *args = NULL;

	list = of_get_property(np, list_name, &size);
	if (!list) {
		ret = -ENOENT;
		goto err0;
	}
	list_end = list + size / sizeof(*list);

	while (list < list_end) {
		const __be32 *cells;
		phandle phandle;

		phandle = be32_to_cpup(list++);
		args = list;

		/* one cell hole in the list = <>; */
		if (!phandle)
			goto next;

		node = of_find_node_by_phandle(phandle);
		if (!node) {
			pr_debug("%s: could not find phandle\n",
				 np->full_name);
			goto err0;
		}

		cells = of_get_property(node, cells_name, &size);
		if (!cells || size != sizeof(*cells)) {
			pr_debug("%s: could not get %s for %s\n",
				 np->full_name, cells_name, node->full_name);
			goto err1;
		}

		list += be32_to_cpup(cells);
		if (list > list_end) {
			pr_debug("%s: insufficient arguments length\n",
				 np->full_name);
			goto err1;
		}
next:
		if (cur_index == index)
			break;

		of_node_put(node);
		node = NULL;
		args = NULL;
		cur_index++;
	}

	if (!node) {
		/*
		 * args w/o node indicates that the loop above has stopped at
		 * the 'hole' cell. Report this differently.
		 */
		if (args)
			ret = -EEXIST;
		else
			ret = -ENOENT;
		goto err0;
	}

	if (out_node)
		*out_node = node;
	if (out_args)
		*out_args = args;

	return 0;
err1:
	of_node_put(node);
err0:
	pr_debug("%s failed with status %d\n", __func__, ret);
	return ret;
}
Esempio n. 24
0
static int __init tsi108_eth_of_init(void)
{
	struct device_node *np;
	unsigned int i;
	struct platform_device *tsi_eth_dev;
	struct resource res;
	int ret;

	for (np = NULL, i = 0;
	     (np = of_find_compatible_node(np, "network", "tsi-ethernet")) != NULL;
	     i++) {
		struct resource r[2];
		struct device_node *phy;
		hw_info tsi_eth_data;
		const unsigned int *id;
		const unsigned int *phy_id;
		const void *mac_addr;
		const phandle *ph;

		memset(r, 0, sizeof(r));
		memset(&tsi_eth_data, 0, sizeof(tsi_eth_data));

		ret = of_address_to_resource(np, 0, &r[0]);
		DBG("%s: name:start->end = %s:0x%lx-> 0x%lx\n",
			__FUNCTION__,r[0].name, r[0].start, r[0].end);
		if (ret)
			goto err;

		r[1].name = "tx";
		r[1].start = irq_of_parse_and_map(np, 0);
		r[1].end = irq_of_parse_and_map(np, 0);
		r[1].flags = IORESOURCE_IRQ;
		DBG("%s: name:start->end = %s:0x%lx-> 0x%lx\n",
			__FUNCTION__,r[1].name, r[1].start, r[1].end);

		tsi_eth_dev =
		    platform_device_register_simple("tsi-ethernet", i, &r[0],
						    1);

		if (IS_ERR(tsi_eth_dev)) {
			ret = PTR_ERR(tsi_eth_dev);
			goto err;
		}

		mac_addr = of_get_mac_address(np);
		if (mac_addr)
			memcpy(tsi_eth_data.mac_addr, mac_addr, 6);

		ph = of_get_property(np, "phy-handle", NULL);
		phy = of_find_node_by_phandle(*ph);

		if (phy == NULL) {
			ret = -ENODEV;
			goto unreg;
		}

		id = of_get_property(phy, "reg", NULL);
		phy_id = of_get_property(phy, "phy-id", NULL);
		ret = of_address_to_resource(phy, 0, &res);
		if (ret) {
			of_node_put(phy);
			goto unreg;
		}
		tsi_eth_data.regs = r[0].start;
		tsi_eth_data.phyregs = res.start;
		tsi_eth_data.phy = *phy_id;
		tsi_eth_data.irq_num = irq_of_parse_and_map(np, 0);
		if (of_device_is_compatible(phy, "bcm54xx"))
			tsi_eth_data.phy_type = TSI108_PHY_BCM54XX;
		of_node_put(phy);
		ret =
		    platform_device_add_data(tsi_eth_dev, &tsi_eth_data,
					     sizeof(hw_info));
		if (ret)
			goto unreg;
	}
	return 0;
unreg:
	platform_device_unregister(tsi_eth_dev);
err:
	return ret;
}
Esempio n. 25
0
static int __init setup_codecvga(void)
{
    int retval = 0;
    int i;
    struct resource *res=NULL;
    int res_num=0;
    int sprite_num=0, dma_chan=-1;
    struct platform_device *pdev=NULL;
    struct codecvga_platform_data *pdata = NULL;
#ifdef CONFIG_CODEC_VGA_OF
	struct device_node *np=NULL;
    const void *prop=NULL;
    struct device_node *fbnp=NULL, *spnp=NULL;
#endif  /* CONFIG_CODEC_VGA_OF */

#ifdef CONFIG_CODEC_VGA_OF

    /*  */
    pr_info("cpufpga: **** setup from device tree\n");

    /* get node */
	np=of_find_compatible_node(NULL, "display", "p2pf,codecvga");
    if(!np){
        pr_err("A node for \"p2pf,codecvga\" is NOT found.\n");
        return 0;
    }

    /* fb-handle */
    prop = of_get_property(np, "fb-handle", NULL);
    if (!prop){
        retval = -ENOENT;
        pr_err("%s: property \"fb-handle\" is NOT found.\n",np->full_name);
        goto err;
    }
    fbnp = of_find_node_by_phandle(*(const phandle*)prop);
    if(!fbnp){
        retval = -ENOENT;
        pr_err("%s: node by \"fb-handle\" is NOT found.\n",np->full_name);
        goto err;
    }
    prop = of_get_property(np, "dma-chan", NULL);
    if(prop)
        dma_chan = *(u32*)prop;

    /* sprite-handle */
    prop = of_get_property(np, "sprite-handle", NULL);
    if (prop){
        spnp = of_find_node_by_phandle(*(const phandle*)prop);
        if(spnp){
            prop = of_get_property(spnp, "sprite-num", NULL);
            if(prop)
                sprite_num = *(u32*)prop;
        } else {
            pr_warning("%s: node by \"sprite-handle\" is NOT found.\n",np->full_name);
        }
    } else {
        pr_warning("%s: property \"sprite-handle\" is NOT found.\n",np->full_name);
    }

#else  /* ! CONFIG_CODEC_VGA_OF */

    sprite_num = CONFIG_CODEC_VGA_SPRITE_NUM;
    dma_chan = CONFIG_CODEC_VGA_DMA_CH;

#endif  /* CONFIG_CODEC_VGA_OF */

    /* allocte resources */
    res_num = sprite_num + 2;
    res = (struct resource *)kzalloc(sizeof(struct resource)*res_num, GFP_KERNEL);
    if(!res){
        retval = -ENOMEM;
        pr_err("no memory for resources\n");
        goto err;
    }

    /* get address map for control register */
#ifdef CONFIG_CODEC_VGA_OF
    retval = of_address_to_resource(np, 0, &res[0]);
    if(retval){
        pr_err("%s: failed to get address map\n",np->full_name);
        goto err;
    }
#else  /* ! CONFIG_CODEC_VGA_OF */
    res[0].name = "codecvga";
    res[0].flags = IORESOURCE_MEM;
    res[0].start = CONFIG_CODEC_VGA_REG_ADDR;
    res[0].end = CONFIG_CODEC_VGA_REG_SIZE + CONFIG_CODEC_VGA_REG_ADDR - 1;
#endif  /* CONFIG_CODEC_VGA_OF */
    pr_info("cpufpga: resource reg = [ 0x%08x - 0x%08x ]\n", res[0].start,res[0].end);

    /* get address map for fram-buffer memory */
#ifdef CONFIG_CODEC_VGA_OF
    retval = of_address_to_resource(fbnp, 0, &res[1]);
    if(retval){
        pr_err("%s: failed to get address map\n",fbnp->full_name);
        goto err;
    }
#else  /* ! CONFIG_CODEC_VGA_OF */
    res[1].name = "fb-handle";
    res[1].flags = IORESOURCE_MEM;
    res[1].start = CONFIG_CODEC_VGA_FB_ADDR;
    res[1].end = CONFIG_CODEC_VGA_FB_SIZE + CONFIG_CODEC_VGA_FB_ADDR - 1;
#endif  /* CONFIG_CODEC_VGA_OF */
    pr_info("cpufpga: resource fb = [ 0x%08x - 0x%08x ]\n", res[1].start,res[1].end);

    /* get address map for sprite-buffer memory */
    for(i=0; i<sprite_num; i++){
#ifdef CONFIG_CODEC_VGA_OF
        retval = of_address_to_resource(spnp, i, &res[2+i]);
        if(retval){
            pr_err("%s,i=%d: failed to get address map\n",spnp->full_name,i);
            goto err;
        }
#else  /* ! CONFIG_CODEC_VGA_OF */
    res[2+i].name = "sprite-handle";
    res[2+i].flags = IORESOURCE_MEM;
    res[2+i].start = CONFIG_CODEC_VGA_SPRITE_START_ADDR + ( i * CONFIG_CODEC_VGA_SPRITE_SIZE);
    res[2+i].end = res[2+i].start + CONFIG_CODEC_VGA_SPRITE_SIZE  - 1;
#endif  /* CONFIG_CODEC_VGA_OF */
        pr_info("cpufpga: resource sprite#%d = [ 0x%08x - 0x%08x ]\n",
                 i,res[2+i].start,res[2+i].end);
    }

    /* allocte platform data for codecvga */
    pdata = (struct codecvga_platform_data *)kzalloc(sizeof(struct codecvga_platform_data),GFP_KERNEL);
    if(!pdata){
        retval = -ENOMEM;
        pr_err("no memory for platform data\n");
        goto err;
    }

    /* setting platform data */
    pdata->sprite_num = sprite_num;
    pdata->dma_chan = dma_chan;
    pr_info("cpufpga: sprite number=%d, dma cahnnel=%d\n",
             pdata->sprite_num, pdata->dma_chan);


    /* allocte private_device */
    pdev = platform_device_alloc("codec_vga", 0);
    if (!pdev){
        pr_err("can't allocate for platform device\n");
        retval=-ENOMEM;
        goto err;
    }

    /* add resources to platform device */
    retval = platform_device_add_resources(pdev, res, res_num);
    if(retval){
        pr_err("failed to add resources to platform device\n");
        platform_device_del(pdev);
        goto err;
    }

    /* add platform data to platform device */
    retval = platform_device_add_data(pdev, pdata, sizeof(struct codecvga_platform_data));
    if (retval){
        pr_err("failed to add platform data to platform device\n");
        platform_device_del(pdev);
        goto err;
    }

    /* regiter platform device */
    retval = platform_device_add(pdev);
    if (retval){
        pr_err("failed to register platform device\n");
        platform_device_del(pdev);
        goto err;
    }

 err:
    if(pdata)
        kfree(pdata);
    if(res)
        kfree(res);

    /* complete */
    return retval;
}