0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016 #include <linux/kernel.h>
0017 #include <linux/of.h>
0018 #include <linux/of_graph.h>
0019 #include <linux/slab.h>
0020 #include <linux/list.h>
0021
0022 static struct list_head dss_conv_list __initdata;
0023
0024 static const char prefix[] __initconst = "omapdss,";
0025
0026 struct dss_conv_node {
0027 struct list_head list;
0028 struct device_node *node;
0029 bool root;
0030 };
0031
0032 static int __init omapdss_count_strings(const struct property *prop)
0033 {
0034 const char *p = prop->value;
0035 int l = 0, total = 0;
0036 int i;
0037
0038 for (i = 0; total < prop->length; total += l, p += l, i++)
0039 l = strlen(p) + 1;
0040
0041 return i;
0042 }
0043
0044 static void __init omapdss_update_prop(struct device_node *node, char *compat,
0045 int len)
0046 {
0047 struct property *prop;
0048
0049 prop = kzalloc(sizeof(*prop), GFP_KERNEL);
0050 if (!prop)
0051 return;
0052
0053 prop->name = "compatible";
0054 prop->value = compat;
0055 prop->length = len;
0056
0057 of_update_property(node, prop);
0058 }
0059
0060 static void __init omapdss_prefix_strcpy(char *dst, int dst_len,
0061 const char *src, int src_len)
0062 {
0063 size_t total = 0;
0064
0065 while (total < src_len) {
0066 size_t l = strlen(src) + 1;
0067
0068 strcpy(dst, prefix);
0069 dst += strlen(prefix);
0070
0071 strcpy(dst, src);
0072 dst += l;
0073
0074 src += l;
0075 total += l;
0076 }
0077 }
0078
0079
0080 static void __init omapdss_omapify_node(struct device_node *node)
0081 {
0082 struct property *prop;
0083 char *new_compat;
0084 int num_strs;
0085 int new_len;
0086
0087 prop = of_find_property(node, "compatible", NULL);
0088
0089 if (!prop || !prop->value)
0090 return;
0091
0092 if (strnlen(prop->value, prop->length) >= prop->length)
0093 return;
0094
0095
0096 if (strncmp(prefix, prop->value, strlen(prefix)) == 0)
0097 return;
0098
0099 num_strs = omapdss_count_strings(prop);
0100
0101 new_len = prop->length + strlen(prefix) * num_strs;
0102 new_compat = kmalloc(new_len, GFP_KERNEL);
0103 if (!new_compat)
0104 return;
0105
0106 omapdss_prefix_strcpy(new_compat, new_len, prop->value, prop->length);
0107
0108 omapdss_update_prop(node, new_compat, new_len);
0109 }
0110
0111 static void __init omapdss_add_to_list(struct device_node *node, bool root)
0112 {
0113 struct dss_conv_node *n = kmalloc(sizeof(struct dss_conv_node),
0114 GFP_KERNEL);
0115 if (n) {
0116 n->node = node;
0117 n->root = root;
0118 list_add(&n->list, &dss_conv_list);
0119 }
0120 }
0121
0122 static bool __init omapdss_list_contains(const struct device_node *node)
0123 {
0124 struct dss_conv_node *n;
0125
0126 list_for_each_entry(n, &dss_conv_list, list) {
0127 if (n->node == node)
0128 return true;
0129 }
0130
0131 return false;
0132 }
0133
0134 static void __init omapdss_walk_device(struct device_node *node, bool root)
0135 {
0136 struct device_node *n;
0137
0138 omapdss_add_to_list(node, root);
0139
0140
0141
0142
0143
0144 n = of_get_child_by_name(node, "ports");
0145 if (!n)
0146 n = of_get_child_by_name(node, "port");
0147 if (!n)
0148 return;
0149
0150 of_node_put(n);
0151
0152 n = NULL;
0153 while ((n = of_graph_get_next_endpoint(node, n)) != NULL) {
0154 struct device_node *pn;
0155
0156 pn = of_graph_get_remote_port_parent(n);
0157
0158 if (!pn)
0159 continue;
0160
0161 if (!of_device_is_available(pn) || omapdss_list_contains(pn)) {
0162 of_node_put(pn);
0163 continue;
0164 }
0165
0166 omapdss_walk_device(pn, false);
0167 }
0168 }
0169
0170 static const struct of_device_id omapdss_of_match[] __initconst = {
0171 { .compatible = "ti,omap2-dss", },
0172 { .compatible = "ti,omap3-dss", },
0173 { .compatible = "ti,omap4-dss", },
0174 { .compatible = "ti,omap5-dss", },
0175 { .compatible = "ti,dra7-dss", },
0176 {},
0177 };
0178
0179 static int __init omapdss_boot_init(void)
0180 {
0181 struct device_node *dss, *child;
0182
0183 INIT_LIST_HEAD(&dss_conv_list);
0184
0185 dss = of_find_matching_node(NULL, omapdss_of_match);
0186
0187 if (dss == NULL || !of_device_is_available(dss)) {
0188 of_node_put(dss);
0189 return 0;
0190 }
0191
0192 omapdss_walk_device(dss, true);
0193
0194 for_each_available_child_of_node(dss, child) {
0195 if (!of_find_property(child, "compatible", NULL))
0196 continue;
0197
0198 omapdss_walk_device(child, true);
0199 }
0200
0201 while (!list_empty(&dss_conv_list)) {
0202 struct dss_conv_node *n;
0203
0204 n = list_first_entry(&dss_conv_list, struct dss_conv_node,
0205 list);
0206
0207 if (!n->root)
0208 omapdss_omapify_node(n->node);
0209
0210 list_del(&n->list);
0211 of_node_put(n->node);
0212 kfree(n);
0213 }
0214
0215 return 0;
0216 }
0217
0218 subsys_initcall(omapdss_boot_init);