2 * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/
3 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 as published by
7 * the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * You should have received a copy of the GNU General Public License along with
15 * this program. If not, see <http://www.gnu.org/licenses/>.
19 * As omapdss panel drivers are omapdss specific, but we want to define the
20 * DT-data in generic manner, we convert the compatible strings of the panel and
21 * encoder nodes from "panel-foo" to "omapdss,panel-foo". This way we can have
22 * both correct DT data and omapdss specific drivers.
24 * When we get generic panel drivers to the kernel, this file will be removed.
27 #include <linux/kernel.h>
29 #include <linux/of_graph.h>
30 #include <linux/slab.h>
31 #include <linux/list.h>
33 static struct list_head dss_conv_list __initdata
;
35 static const char prefix
[] __initconst
= "omapdss,";
37 struct dss_conv_node
{
38 struct list_head list
;
39 struct device_node
*node
;
43 static int __init
omapdss_count_strings(const struct property
*prop
)
45 const char *p
= prop
->value
;
49 for (i
= 0; total
< prop
->length
; total
+= l
, p
+= l
, i
++)
55 static void __init
omapdss_update_prop(struct device_node
*node
, char *compat
,
58 struct property
*prop
;
60 prop
= kzalloc(sizeof(*prop
), GFP_KERNEL
);
64 prop
->name
= "compatible";
68 of_update_property(node
, prop
);
71 static void __init
omapdss_prefix_strcpy(char *dst
, int dst_len
,
72 const char *src
, int src_len
)
76 while (total
< src_len
) {
77 size_t l
= strlen(src
) + 1;
80 dst
+= strlen(prefix
);
90 /* prepend compatible property strings with "omapdss," */
91 static void __init
omapdss_omapify_node(struct device_node
*node
)
93 struct property
*prop
;
98 prop
= of_find_property(node
, "compatible", NULL
);
100 if (!prop
|| !prop
->value
)
103 if (strnlen(prop
->value
, prop
->length
) >= prop
->length
)
106 /* is it already prefixed? */
107 if (strncmp(prefix
, prop
->value
, strlen(prefix
)) == 0)
110 num_strs
= omapdss_count_strings(prop
);
112 new_len
= prop
->length
+ strlen(prefix
) * num_strs
;
113 new_compat
= kmalloc(new_len
, GFP_KERNEL
);
115 omapdss_prefix_strcpy(new_compat
, new_len
, prop
->value
, prop
->length
);
117 omapdss_update_prop(node
, new_compat
, new_len
);
120 static void __init
omapdss_add_to_list(struct device_node
*node
, bool root
)
122 struct dss_conv_node
*n
= kmalloc(sizeof(*n
), GFP_KERNEL
);
126 list_add(&n
->list
, &dss_conv_list
);
130 static bool __init
omapdss_list_contains(const struct device_node
*node
)
132 struct dss_conv_node
*n
;
134 list_for_each_entry(n
, &dss_conv_list
, list
) {
142 static void __init
omapdss_walk_device(struct device_node
*node
, bool root
)
144 struct device_node
*n
;
146 omapdss_add_to_list(node
, root
);
149 * of_graph_get_remote_port_parent() prints an error if there is no
150 * port/ports node. To avoid that, check first that there's the node.
152 n
= of_get_child_by_name(node
, "ports");
154 n
= of_get_child_by_name(node
, "port");
161 while ((n
= of_graph_get_next_endpoint(node
, n
)) != NULL
) {
162 struct device_node
*pn
;
164 pn
= of_graph_get_remote_port_parent(n
);
169 if (!of_device_is_available(pn
) || omapdss_list_contains(pn
)) {
174 omapdss_walk_device(pn
, false);
178 static const struct of_device_id omapdss_of_match
[] __initconst
= {
179 { .compatible
= "ti,omap2-dss", },
180 { .compatible
= "ti,omap3-dss", },
181 { .compatible
= "ti,omap4-dss", },
182 { .compatible
= "ti,omap5-dss", },
183 { .compatible
= "ti,dra7-dss", },
187 static int __init
omapdss_boot_init(void)
189 struct device_node
*dss
, *child
;
191 INIT_LIST_HEAD(&dss_conv_list
);
193 dss
= of_find_matching_node(NULL
, omapdss_of_match
);
195 if (dss
== NULL
|| !of_device_is_available(dss
))
198 omapdss_walk_device(dss
, true);
200 for_each_available_child_of_node(dss
, child
) {
201 if (!of_find_property(child
, "compatible", NULL
))
204 omapdss_walk_device(child
, true);
207 while (!list_empty(&dss_conv_list
)) {
208 struct dss_conv_node
*n
;
210 n
= list_first_entry(&dss_conv_list
, struct dss_conv_node
,
214 omapdss_omapify_node(n
->node
);
217 of_node_put(n
->node
);
224 subsys_initcall(omapdss_boot_init
);