aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c
diff options
context:
space:
mode:
authorTomi Valkeinen <tomi.valkeinen@ti.com>2015-12-09 13:26:00 -0500
committerTomi Valkeinen <tomi.valkeinen@ti.com>2015-12-29 04:07:48 -0500
commit9960aa7cb58caadef8edf3a2582e30664a6b68dd (patch)
treeff7cfe2855cca84c59beccba9f2ca7cea36541c2 /drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c
parent5ca28914b8b4371cfa56b6ee2dec68debb99718f (diff)
drm/omap: move omapdss & displays under omapdrm
Now that omapfb has its own copy of omapdss and display drivers, we can move omapdss and display drivers which omapdrm uses to omapdrm's directory. We also need to change the main drm Makefile so that omapdrm directory is always entered, because omapdss has a file that can't be built as a module. Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com> Acked-by: Dave Airlie <airlied@gmail.com> Acked-by: Rob Clark <robdclark@gmail.com>
Diffstat (limited to 'drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c')
-rw-r--r--drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c225
1 files changed, 225 insertions, 0 deletions
diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c b/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c
new file mode 100644
index 000000000000..136d30484d02
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c
@@ -0,0 +1,225 @@
1/*
2 * Copyright (C) 2014 Texas Instruments
3 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
4 *
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.
8 *
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
12 * more details.
13 *
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/>.
16 */
17
18/*
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.
23 *
24 * When we get generic panel drivers to the kernel, this file will be removed.
25 */
26
27#include <linux/kernel.h>
28#include <linux/of.h>
29#include <linux/of_graph.h>
30#include <linux/slab.h>
31#include <linux/list.h>
32
33static struct list_head dss_conv_list __initdata;
34
35static const char prefix[] __initconst = "omapdss,";
36
37struct dss_conv_node {
38 struct list_head list;
39 struct device_node *node;
40 bool root;
41};
42
43static int __init omapdss_count_strings(const struct property *prop)
44{
45 const char *p = prop->value;
46 int l = 0, total = 0;
47 int i;
48
49 for (i = 0; total < prop->length; total += l, p += l, i++)
50 l = strlen(p) + 1;
51
52 return i;
53}
54
55static void __init omapdss_update_prop(struct device_node *node, char *compat,
56 int len)
57{
58 struct property *prop;
59
60 prop = kzalloc(sizeof(*prop), GFP_KERNEL);
61 if (!prop)
62 return;
63
64 prop->name = "compatible";
65 prop->value = compat;
66 prop->length = len;
67
68 of_update_property(node, prop);
69}
70
71static void __init omapdss_prefix_strcpy(char *dst, int dst_len,
72 const char *src, int src_len)
73{
74 size_t total = 0;
75
76 while (total < src_len) {
77 size_t l = strlen(src) + 1;
78
79 strcpy(dst, prefix);
80 dst += strlen(prefix);
81
82 strcpy(dst, src);
83 dst += l;
84
85 src += l;
86 total += l;
87 }
88}
89
90/* prepend compatible property strings with "omapdss," */
91static void __init omapdss_omapify_node(struct device_node *node)
92{
93 struct property *prop;
94 char *new_compat;
95 int num_strs;
96 int new_len;
97
98 prop = of_find_property(node, "compatible", NULL);
99
100 if (!prop || !prop->value)
101 return;
102
103 if (strnlen(prop->value, prop->length) >= prop->length)
104 return;
105
106 /* is it already prefixed? */
107 if (strncmp(prefix, prop->value, strlen(prefix)) == 0)
108 return;
109
110 num_strs = omapdss_count_strings(prop);
111
112 new_len = prop->length + strlen(prefix) * num_strs;
113 new_compat = kmalloc(new_len, GFP_KERNEL);
114
115 omapdss_prefix_strcpy(new_compat, new_len, prop->value, prop->length);
116
117 omapdss_update_prop(node, new_compat, new_len);
118}
119
120static void __init omapdss_add_to_list(struct device_node *node, bool root)
121{
122 struct dss_conv_node *n = kmalloc(sizeof(struct dss_conv_node),
123 GFP_KERNEL);
124 if (n) {
125 n->node = node;
126 n->root = root;
127 list_add(&n->list, &dss_conv_list);
128 }
129}
130
131static bool __init omapdss_list_contains(const struct device_node *node)
132{
133 struct dss_conv_node *n;
134
135 list_for_each_entry(n, &dss_conv_list, list) {
136 if (n->node == node)
137 return true;
138 }
139
140 return false;
141}
142
143static void __init omapdss_walk_device(struct device_node *node, bool root)
144{
145 struct device_node *n;
146
147 omapdss_add_to_list(node, root);
148
149 /*
150 * of_graph_get_remote_port_parent() prints an error if there is no
151 * port/ports node. To avoid that, check first that there's the node.
152 */
153 n = of_get_child_by_name(node, "ports");
154 if (!n)
155 n = of_get_child_by_name(node, "port");
156 if (!n)
157 return;
158
159 of_node_put(n);
160
161 n = NULL;
162 while ((n = of_graph_get_next_endpoint(node, n)) != NULL) {
163 struct device_node *pn;
164
165 pn = of_graph_get_remote_port_parent(n);
166
167 if (!pn)
168 continue;
169
170 if (!of_device_is_available(pn) || omapdss_list_contains(pn)) {
171 of_node_put(pn);
172 continue;
173 }
174
175 omapdss_walk_device(pn, false);
176 }
177}
178
179static const struct of_device_id omapdss_of_match[] __initconst = {
180 { .compatible = "ti,omap2-dss", },
181 { .compatible = "ti,omap3-dss", },
182 { .compatible = "ti,omap4-dss", },
183 { .compatible = "ti,omap5-dss", },
184 { .compatible = "ti,dra7-dss", },
185 {},
186};
187
188static int __init omapdss_boot_init(void)
189{
190 struct device_node *dss, *child;
191
192 INIT_LIST_HEAD(&dss_conv_list);
193
194 dss = of_find_matching_node(NULL, omapdss_of_match);
195
196 if (dss == NULL || !of_device_is_available(dss))
197 return 0;
198
199 omapdss_walk_device(dss, true);
200
201 for_each_available_child_of_node(dss, child) {
202 if (!of_find_property(child, "compatible", NULL))
203 continue;
204
205 omapdss_walk_device(child, true);
206 }
207
208 while (!list_empty(&dss_conv_list)) {
209 struct dss_conv_node *n;
210
211 n = list_first_entry(&dss_conv_list, struct dss_conv_node,
212 list);
213
214 if (!n->root)
215 omapdss_omapify_node(n->node);
216
217 list_del(&n->list);
218 of_node_put(n->node);
219 kfree(n);
220 }
221
222 return 0;
223}
224
225subsys_initcall(omapdss_boot_init);