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 } 186