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; }
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; } }
/** * 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; }
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; }
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; }
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; }
/** * 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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
/** * 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; }
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; }
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; }