1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright (C) 2019-2022 Bootlin
4 * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
5 */
6
7 #include <drm/drm_print.h>
8
9 #include "logicvc_drm.h"
10 #include "logicvc_layer.h"
11 #include "logicvc_of.h"
12
13 static struct logicvc_of_property_sv logicvc_of_display_interface_sv[] = {
14 { "lvds-4bits", LOGICVC_DISPLAY_INTERFACE_LVDS_4BITS },
15 { "lvds-3bits", LOGICVC_DISPLAY_INTERFACE_LVDS_3BITS },
16 { },
17 };
18
19 static struct logicvc_of_property_sv logicvc_of_display_colorspace_sv[] = {
20 { "rgb", LOGICVC_DISPLAY_COLORSPACE_RGB },
21 { "yuv422", LOGICVC_DISPLAY_COLORSPACE_YUV422 },
22 { "yuv444", LOGICVC_DISPLAY_COLORSPACE_YUV444 },
23 { },
24 };
25
26 static struct logicvc_of_property_sv logicvc_of_layer_colorspace_sv[] = {
27 { "rgb", LOGICVC_LAYER_COLORSPACE_RGB },
28 { "yuv", LOGICVC_LAYER_COLORSPACE_YUV },
29 { },
30 };
31
32 static struct logicvc_of_property_sv logicvc_of_layer_alpha_mode_sv[] = {
33 { "layer", LOGICVC_LAYER_ALPHA_LAYER },
34 { "pixel", LOGICVC_LAYER_ALPHA_PIXEL },
35 { },
36 };
37
38 static struct logicvc_of_property logicvc_of_properties[] = {
39 [LOGICVC_OF_PROPERTY_DISPLAY_INTERFACE] = {
40 .name = "xylon,display-interface",
41 .sv = logicvc_of_display_interface_sv,
42 .range = {
43 LOGICVC_DISPLAY_INTERFACE_LVDS_4BITS,
44 LOGICVC_DISPLAY_INTERFACE_LVDS_3BITS,
45 },
46 },
47 [LOGICVC_OF_PROPERTY_DISPLAY_COLORSPACE] = {
48 .name = "xylon,display-colorspace",
49 .sv = logicvc_of_display_colorspace_sv,
50 .range = {
51 LOGICVC_DISPLAY_COLORSPACE_RGB,
52 LOGICVC_DISPLAY_COLORSPACE_YUV444,
53 },
54 },
55 [LOGICVC_OF_PROPERTY_DISPLAY_DEPTH] = {
56 .name = "xylon,display-depth",
57 .range = { 8, 24 },
58 },
59 [LOGICVC_OF_PROPERTY_ROW_STRIDE] = {
60 .name = "xylon,row-stride",
61 },
62 [LOGICVC_OF_PROPERTY_DITHERING] = {
63 .name = "xylon,dithering",
64 .optional = true,
65 },
66 [LOGICVC_OF_PROPERTY_BACKGROUND_LAYER] = {
67 .name = "xylon,background-layer",
68 .optional = true,
69 },
70 [LOGICVC_OF_PROPERTY_LAYERS_CONFIGURABLE] = {
71 .name = "xylon,layers-configurable",
72 .optional = true,
73 },
74 [LOGICVC_OF_PROPERTY_LAYERS_COUNT] = {
75 .name = "xylon,layers-count",
76 },
77 [LOGICVC_OF_PROPERTY_LAYER_DEPTH] = {
78 .name = "xylon,layer-depth",
79 .range = { 8, 24 },
80 },
81 [LOGICVC_OF_PROPERTY_LAYER_COLORSPACE] = {
82 .name = "xylon,layer-colorspace",
83 .sv = logicvc_of_layer_colorspace_sv,
84 .range = {
85 LOGICVC_LAYER_COLORSPACE_RGB,
86 LOGICVC_LAYER_COLORSPACE_RGB,
87 },
88 },
89 [LOGICVC_OF_PROPERTY_LAYER_ALPHA_MODE] = {
90 .name = "xylon,layer-alpha-mode",
91 .sv = logicvc_of_layer_alpha_mode_sv,
92 .range = {
93 LOGICVC_LAYER_ALPHA_LAYER,
94 LOGICVC_LAYER_ALPHA_PIXEL,
95 },
96 },
97 [LOGICVC_OF_PROPERTY_LAYER_BASE_OFFSET] = {
98 .name = "xylon,layer-base-offset",
99 },
100 [LOGICVC_OF_PROPERTY_LAYER_BUFFER_OFFSET] = {
101 .name = "xylon,layer-buffer-offset",
102 },
103 [LOGICVC_OF_PROPERTY_LAYER_PRIMARY] = {
104 .name = "xylon,layer-primary",
105 .optional = true,
106 },
107 };
108
logicvc_of_property_sv_value(struct logicvc_of_property_sv * sv,const char * string,u32 * value)109 static int logicvc_of_property_sv_value(struct logicvc_of_property_sv *sv,
110 const char *string, u32 *value)
111 {
112 unsigned int i = 0;
113
114 while (sv[i].string) {
115 if (!strcmp(sv[i].string, string)) {
116 *value = sv[i].value;
117 return 0;
118 }
119
120 i++;
121 }
122
123 return -EINVAL;
124 }
125
logicvc_of_property_parse_u32(struct device_node * of_node,unsigned int index,u32 * target)126 int logicvc_of_property_parse_u32(struct device_node *of_node,
127 unsigned int index, u32 *target)
128 {
129 struct logicvc_of_property *property;
130 const char *string;
131 u32 value;
132 int ret;
133
134 if (index >= LOGICVC_OF_PROPERTY_MAXIMUM)
135 return -EINVAL;
136
137 property = &logicvc_of_properties[index];
138
139 if (!property->optional &&
140 !of_property_read_bool(of_node, property->name))
141 return -ENODEV;
142
143 if (property->sv) {
144 ret = of_property_read_string(of_node, property->name, &string);
145 if (ret)
146 return ret;
147
148 ret = logicvc_of_property_sv_value(property->sv, string,
149 &value);
150 if (ret)
151 return ret;
152 } else {
153 ret = of_property_read_u32(of_node, property->name, &value);
154 if (ret)
155 return ret;
156 }
157
158 if (property->range[0] || property->range[1])
159 if (value < property->range[0] || value > property->range[1])
160 return -ERANGE;
161
162 *target = value;
163
164 return 0;
165 }
166
logicvc_of_property_parse_bool(struct device_node * of_node,unsigned int index,bool * target)167 void logicvc_of_property_parse_bool(struct device_node *of_node,
168 unsigned int index, bool *target)
169 {
170 struct logicvc_of_property *property;
171
172 if (index >= LOGICVC_OF_PROPERTY_MAXIMUM) {
173 /* Fallback. */
174 *target = false;
175 return;
176 }
177
178 property = &logicvc_of_properties[index];
179 *target = of_property_read_bool(of_node, property->name);
180 }
181
logicvc_of_node_is_layer(struct device_node * of_node)182 bool logicvc_of_node_is_layer(struct device_node *of_node)
183 {
184 return !of_node_cmp(of_node->name, "layer");
185 }
186