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 | |
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 | |
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(np: of_node, propname: property->name)) |
141 | return -ENODEV; |
142 | |
143 | if (property->sv) { |
144 | ret = of_property_read_string(np: of_node, propname: property->name, out_string: &string); |
145 | if (ret) |
146 | return ret; |
147 | |
148 | ret = logicvc_of_property_sv_value(sv: property->sv, string, |
149 | value: &value); |
150 | if (ret) |
151 | return ret; |
152 | } else { |
153 | ret = of_property_read_u32(np: of_node, propname: property->name, out_value: &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 | |
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(np: of_node, propname: property->name); |
180 | } |
181 | |
182 | bool logicvc_of_node_is_layer(struct device_node *of_node) |
183 | { |
184 | return !of_node_cmp(of_node->name, "layer" ); |
185 | } |
186 | |