Merge tag 'mips_6.5_1' of git://git.kernel.org/pub/scm/linux/kernel/git/mips/linux
[platform/kernel/linux-starfive.git] / drivers / gpu / drm / logicvc / logicvc_of.c
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(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
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
182 bool logicvc_of_node_is_layer(struct device_node *of_node)
183 {
184         return !of_node_cmp(of_node->name, "layer");
185 }