2 * Copyright (c) 2015, NVIDIA CORPORATION. All rights reserved.
4 * Author: Laxman Dewangan<ldewangan@nvidia.com>
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 #include <linux/init.h>
17 #include <linux/spinlock.h>
18 #include <linux/slab.h>
19 #include <linux/string.h>
20 #include <linux/proc_fs.h>
22 #include <linux/of_fdt.h>
24 static struct property *__of_copy_property(const struct property *prop,
27 struct property *propn;
29 propn = kzalloc(sizeof(*prop), flags);
33 propn->name = kstrdup(prop->name, flags);
34 if (propn->name == NULL)
37 if (prop->length > 0) {
38 propn->value = kmalloc(prop->length, flags);
39 if (propn->value == NULL)
41 memcpy(propn->value, prop->value, prop->length);
42 propn->length = prop->length;
54 static int __init update_target_node_from_overlay(
55 struct device_node *target, struct device_node *overlay)
57 struct property *prop;
58 struct property *tprop;
59 struct property *new_prop;
64 for_each_property_of_node(overlay, prop) {
65 /* Skip those we do not want to proceed */
66 if (!strcmp(prop->name, "name") ||
67 !strcmp(prop->name, "phandle") ||
68 !strcmp(prop->name, "linux,phandle"))
70 if (!strcmp(prop->name, "delete-target-property")) {
71 if (prop->length <= 0)
73 pval = (const char *)prop->value;
74 pr_info("Removing Prop %s from target %s\n",
75 pval, target->full_name);
76 tprop = of_find_property(target, pval, &lenp);
78 of_remove_property(target, tprop);
82 new_prop = __of_copy_property(prop, GFP_KERNEL);
84 pr_err("Prop %s can not be duplicated\n",
89 tprop = of_find_property(target, prop->name, &lenp);
91 ret = of_add_property(target, new_prop);
93 pr_err("Prop %s can not be added on node %s\n",
94 new_prop->name, target->full_name);
98 ret = of_update_property(target, new_prop);
100 pr_err("Prop %s can not be updated on node %s\n",
101 new_prop->name, target->full_name);
109 static int __init update_target_node(struct device_node *target,
110 struct device_node *overlay)
112 struct device_node *tchild, *ochild;
115 ret = update_target_node_from_overlay(target, overlay);
117 pr_err("Target %s update with overlay %s failed: %d\n",
118 target->name, overlay->name, ret);
122 for_each_child_of_node(overlay, ochild) {
123 tchild = of_get_child_by_name(target, ochild->name);
125 pr_err("Overlay child %s not found on target %s\n",
126 ochild->full_name, tchild->full_name);
130 ret = update_target_node(tchild, ochild);
132 pr_err("Target %s update with overlay %s failed: %d\n",
133 tchild->name, ochild->name, ret);
140 static int __init parse_fragment(struct device_node *np)
142 struct device_node *board_np, *odm_np, *overlay, *target, *cnp;
144 struct property *prop;
151 board_count = of_property_count_strings(np, "ids");
152 odm_count = of_property_count_strings(np, "odm-data");
153 if ((board_count <= 0) && (odm_count <= 0)) {
154 pr_err("Node %s does not have property ids and odm data\n",
159 nchild = of_get_child_count(np);
161 pr_err("Node %s does not have Overlay child\n", np->name);
165 /* Match the IDs or odm data */
166 board_np = of_find_node_by_path("/chosen/plugin-manager/ids");
167 odm_np = of_find_node_by_path("/chosen/plugin-manager/odm-data");
168 if (!board_np && !odm_np) {
169 pr_err("chosen/plugin-manager does'nt have ids and odm-data\n");
173 if ((board_count > 0) && board_np) {
174 of_property_for_each_string(np, "ids", prop, bname) {
175 found = of_property_read_bool(board_np, bname);
177 pr_info("node %s match with board %s\n",
178 np->full_name, bname);
184 if (!found && (odm_count > 0) && odm_np) {
185 of_property_for_each_string(np, "odm-data", prop, bname) {
186 found = of_property_read_bool(odm_np, bname);
188 pr_info("node %s match with odm-data %s\n",
189 np->full_name, bname);
198 for_each_child_of_node(np, cnp) {
199 target = of_parse_phandle(cnp, "target", 0);
201 pr_err("Node %s does not have targer node\n",
206 overlay = of_get_child_by_name(cnp, "_overlay_");
208 pr_err("Node %s does not have Overlay\n", cnp->name);
212 ret = update_target_node(target, overlay);
214 pr_err("Target %s update with overlay %s failed: %d\n",
215 target->name, overlay->name, ret);
222 static int __init plugin_manager_init(void)
224 struct device_node *pm_node;
225 struct device_node *child;
228 pr_info("Initializing plugin-manager\n");
230 pm_node = of_find_node_by_path("/plugin-manager");
232 pr_info("Plugin-manager not available\n");
236 if (!of_device_is_available(pm_node)) {
237 pr_info("Plugin-manager status disabled\n");
241 for_each_child_of_node(pm_node, child) {
242 if (!of_device_is_available(child)) {
243 pr_info("Plugin-manager child %s status disabled\n",
247 ret = parse_fragment(child);
249 pr_err("Error in parsing node %s: %d\n",
250 child->full_name, ret);
254 core_initcall(plugin_manager_init);