1 /*
2 * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without modification, are permitted
5 * provided that the following conditions are met:
6 * * Redistributions of source code must retain the above copyright notice, this list of
7 * conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above copyright notice, this list of
9 * conditions and the following disclaimer in the documentation and/or other materials provided
10 * with the distribution.
11 * * Neither the name of The Linux Foundation nor the names of its contributors may be used to
12 * endorse or promote products derived from this software without specific prior written
13 * permission.
14 *
15 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
19 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
20 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
21 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
22 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24
25 #include <string.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <fcntl.h>
29 #include <sys/stat.h>
30 #include <sys/types.h>
31 #include <utils/constants.h>
32 #include <utils/debug.h>
33 #include <utils/sys.h>
34 #include <dlfcn.h>
35
36 #include <algorithm>
37 #include <iostream>
38 #include <fstream>
39 #include <map>
40 #include <memory>
41 #include <string>
42 #include <utility>
43 #include <vector>
44
45 #include "hw_info.h"
46
47 #define __CLASS__ "HWInfo"
48
49 using std::vector;
50 using std::map;
51 using std::string;
52 using std::fstream;
53 using std::to_string;
54
55 namespace sdm {
56
57 // kDefaultFormatSupport contains the bit map of supported formats for each hw blocks.
58 // For eg: if Cursor supports MDP_RGBA_8888[bit-13] and MDP_RGB_565[bit-0], then cursor pipe array
59 // contains { 0x01[0-3], 0x00[4-7], 0x00[8-12], 0x01[13-16], 0x00[17-20], 0x00[21-24], 0x00[24-28] }
60 const std::bitset<8> HWInfo::kDefaultFormatSupport[kHWSubBlockMax][
61 BITS_TO_BYTES(MDP_IMGTYPE_LIMIT1)] = {
62 { 0xFF, 0xF5, 0x1C, 0x1E, 0x20, 0xFF, 0x01, 0x00, 0xFE, 0x1F }, // kHWVIGPipe
63 { 0x33, 0xE0, 0x00, 0x16, 0x00, 0xBF, 0x00, 0x00, 0xFE, 0x07 }, // kHWRGBPipe
64 { 0x33, 0xE0, 0x00, 0x16, 0x00, 0xBF, 0x00, 0x00, 0xFE, 0x07 }, // kHWDMAPipe
65 { 0x12, 0x60, 0x0C, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00 }, // kHWCursorPipe
66 { 0xFF, 0xF5, 0x1C, 0x1E, 0x20, 0xFF, 0x01, 0x00, 0xFE, 0x1F }, // kHWRotatorInput
67 { 0xFF, 0xF5, 0x1C, 0x1E, 0x20, 0xFF, 0x01, 0x00, 0xFE, 0x1F }, // kHWRotatorOutput
68 { 0x3F, 0xF4, 0x10, 0x1E, 0x20, 0xFF, 0x01, 0x00, 0xAA, 0x16 }, // kHWWBIntfOutput
69 };
70
ParseString(const char * input,char * tokens[],const uint32_t max_token,const char * delim,uint32_t * count)71 int HWInfo::ParseString(const char *input, char *tokens[], const uint32_t max_token,
72 const char *delim, uint32_t *count) {
73 char *tmp_token = NULL;
74 char *temp_ptr;
75 uint32_t index = 0;
76 if (!input) {
77 return -1;
78 }
79 tmp_token = strtok_r(const_cast<char *>(input), delim, &temp_ptr);
80 while (tmp_token && index < max_token) {
81 tokens[index++] = tmp_token;
82 tmp_token = strtok_r(NULL, delim, &temp_ptr);
83 }
84 *count = index;
85
86 return 0;
87 }
88
Create(HWInfoInterface ** intf)89 DisplayError HWInfoInterface::Create(HWInfoInterface **intf) {
90 DisplayError error = kErrorNone;
91 HWInfo *hw_info = NULL;
92
93 hw_info = new HWInfo();
94 if (!hw_info) {
95 error = kErrorMemory;
96 } else {
97 *intf = hw_info;
98 }
99
100 return error;
101 }
102
Destroy(HWInfoInterface * intf)103 DisplayError HWInfoInterface::Destroy(HWInfoInterface *intf) {
104 HWInfo *hw_info = static_cast<HWInfo *>(intf);
105 delete hw_info;
106
107 return kErrorNone;
108 }
109
GetDynamicBWLimits(HWResourceInfo * hw_resource)110 DisplayError HWInfo::GetDynamicBWLimits(HWResourceInfo *hw_resource) {
111 Sys::fstream fs(kBWModeBitmap, fstream::in);
112 if (!fs.is_open()) {
113 DLOGE("File '%s' not found", kBWModeBitmap);
114 return kErrorHardware;
115 }
116
117 HWDynBwLimitInfo* bw_info = &hw_resource->dyn_bw_info;
118 for (int index = 0; index < kBwModeMax; index++) {
119 bw_info->total_bw_limit[index] = UINT32(hw_resource->max_bandwidth_low);
120 bw_info->pipe_bw_limit[index] = hw_resource->max_pipe_bw;
121 }
122
123 uint32_t token_count = 0;
124 const uint32_t max_count = kBwModeMax;
125 char *tokens[max_count] = { NULL };
126 string line;
127 while (Sys::getline_(fs, line)) {
128 if (!ParseString(line.c_str(), tokens, max_count, ":, =\n", &token_count)) {
129 if (!strncmp(tokens[0], "default_pipe", strlen("default_pipe"))) {
130 bw_info->pipe_bw_limit[kBwDefault] = UINT32(atoi(tokens[1]));
131 } else if (!strncmp(tokens[0], "camera_pipe", strlen("camera_pipe"))) {
132 bw_info->pipe_bw_limit[kBwCamera] = UINT32(atoi(tokens[1]));
133 } else if (!strncmp(tokens[0], "vflip_pipe", strlen("vflip_pipe"))) {
134 bw_info->pipe_bw_limit[kBwVFlip] = UINT32(atoi(tokens[1]));
135 } else if (!strncmp(tokens[0], "hflip_pipe", strlen("hflip_pipe"))) {
136 bw_info->pipe_bw_limit[kBwHFlip] = UINT32(atoi(tokens[1]));
137 } else if (!strncmp(tokens[0], "default", strlen("default"))) {
138 bw_info->total_bw_limit[kBwDefault] = UINT32(atoi(tokens[1]));
139 } else if (!strncmp(tokens[0], "camera", strlen("camera"))) {
140 bw_info->total_bw_limit[kBwCamera] = UINT32(atoi(tokens[1]));
141 } else if (!strncmp(tokens[0], "vflip", strlen("vflip"))) {
142 bw_info->total_bw_limit[kBwVFlip] = UINT32(atoi(tokens[1]));
143 } else if (!strncmp(tokens[0], "hflip", strlen("hflip"))) {
144 bw_info->total_bw_limit[kBwHFlip] = UINT32(atoi(tokens[1]));
145 }
146 }
147 }
148
149 return kErrorNone;
150 }
151
GetHWResourceInfo(HWResourceInfo * hw_resource)152 DisplayError HWInfo::GetHWResourceInfo(HWResourceInfo *hw_resource) {
153 string fb_path = "/sys/devices/virtual/graphics/fb"
154 + to_string(kHWCapabilitiesNode) + "/mdp/caps";
155
156 Sys::fstream fs(fb_path, fstream::in);
157 if (!fs.is_open()) {
158 DLOGE("File '%s' not found", fb_path.c_str());
159 return kErrorHardware;
160 }
161
162 InitSupportedFormatMap(hw_resource);
163 hw_resource->hw_version = kHWMdssVersion5;
164
165 uint32_t token_count = 0;
166 const uint32_t max_count = 256;
167 char *tokens[max_count] = { NULL };
168 string line;
169 while (Sys::getline_(fs, line)) {
170 // parse the line and update information accordingly
171 if (!ParseString(line.c_str(), tokens, max_count, ":, =\n", &token_count)) {
172 if (!strncmp(tokens[0], "hw_rev", strlen("hw_rev"))) {
173 hw_resource->hw_revision = UINT32(atoi(tokens[1])); // HW Rev, v1/v2
174 } else if (!strncmp(tokens[0], "rot_input_fmts", strlen("rot_input_fmts"))) {
175 ParseFormats(&tokens[1], (token_count - 1), kHWRotatorInput, hw_resource);
176 } else if (!strncmp(tokens[0], "rot_output_fmts", strlen("rot_output_fmts"))) {
177 ParseFormats(&tokens[1], (token_count - 1), kHWRotatorOutput, hw_resource);
178 } else if (!strncmp(tokens[0], "wb_output_fmts", strlen("wb_output_fmts"))) {
179 ParseFormats(&tokens[1], (token_count - 1), kHWWBIntfOutput, hw_resource);
180 } else if (!strncmp(tokens[0], "blending_stages", strlen("blending_stages"))) {
181 hw_resource->num_blending_stages = UINT8(atoi(tokens[1]));
182 } else if (!strncmp(tokens[0], "max_downscale_ratio", strlen("max_downscale_ratio"))) {
183 hw_resource->max_scale_down = UINT32(atoi(tokens[1]));
184 } else if (!strncmp(tokens[0], "max_upscale_ratio", strlen("max_upscale_ratio"))) {
185 hw_resource->max_scale_up = UINT32(atoi(tokens[1]));
186 } else if (!strncmp(tokens[0], "max_bandwidth_low", strlen("max_bandwidth_low"))) {
187 hw_resource->max_bandwidth_low = UINT64(atol(tokens[1]));
188 } else if (!strncmp(tokens[0], "max_bandwidth_high", strlen("max_bandwidth_high"))) {
189 hw_resource->max_bandwidth_high = UINT64(atol(tokens[1]));
190 } else if (!strncmp(tokens[0], "max_mixer_width", strlen("max_mixer_width"))) {
191 hw_resource->max_mixer_width = UINT32(atoi(tokens[1]));
192 } else if (!strncmp(tokens[0], "max_pipe_width", strlen("max_pipe_width"))) {
193 hw_resource->max_pipe_width = UINT32(atoi(tokens[1]));
194 } else if (!strncmp(tokens[0], "max_cursor_size", strlen("max_cursor_size"))) {
195 hw_resource->max_cursor_size = UINT32(atoi(tokens[1]));
196 } else if (!strncmp(tokens[0], "max_pipe_bw", strlen("max_pipe_bw"))) {
197 hw_resource->max_pipe_bw = UINT32(atoi(tokens[1]));
198 } else if (!strncmp(tokens[0], "max_mdp_clk", strlen("max_mdp_clk"))) {
199 hw_resource->max_sde_clk = UINT32(atoi(tokens[1]));
200 } else if (!strncmp(tokens[0], "clk_fudge_factor", strlen("clk_fudge_factor"))) {
201 hw_resource->clk_fudge_factor = FLOAT(atoi(tokens[1])) / FLOAT(atoi(tokens[2]));
202 } else if (!strncmp(tokens[0], "fmt_mt_nv12_factor", strlen("fmt_mt_nv12_factor"))) {
203 hw_resource->macrotile_nv12_factor = UINT32(atoi(tokens[1]));
204 } else if (!strncmp(tokens[0], "fmt_mt_factor", strlen("fmt_mt_factor"))) {
205 hw_resource->macrotile_factor = UINT32(atoi(tokens[1]));
206 } else if (!strncmp(tokens[0], "fmt_linear_factor", strlen("fmt_linear_factor"))) {
207 hw_resource->linear_factor = UINT32(atoi(tokens[1]));
208 } else if (!strncmp(tokens[0], "scale_factor", strlen("scale_factor"))) {
209 hw_resource->scale_factor = UINT32(atoi(tokens[1]));
210 } else if (!strncmp(tokens[0], "xtra_ff_factor", strlen("xtra_ff_factor"))) {
211 hw_resource->extra_fudge_factor = UINT32(atoi(tokens[1]));
212 } else if (!strncmp(tokens[0], "amortizable_threshold", strlen("amortizable_threshold"))) {
213 hw_resource->amortizable_threshold = UINT32(atoi(tokens[1]));
214 } else if (!strncmp(tokens[0], "system_overhead_lines", strlen("system_overhead_lines"))) {
215 hw_resource->system_overhead_lines = UINT32(atoi(tokens[1]));
216 } else if (!strncmp(tokens[0], "wb_intf_index", strlen("wb_intf_index"))) {
217 hw_resource->writeback_index = UINT32(atoi(tokens[1]));
218 } else if (!strncmp(tokens[0], "dest_scaler_count", strlen("dest_scaler_count"))) {
219 hw_resource->hw_dest_scalar_info.count = UINT32(atoi(tokens[1]));
220 } else if (!strncmp(tokens[0], "max_dest_scale_up", strlen("max_dest_scale_up"))) {
221 hw_resource->hw_dest_scalar_info.max_scale_up = UINT32(atoi(tokens[1]));
222 } else if (!strncmp(tokens[0], "max_dest_scaler_input_width",
223 strlen("max_dest_scaler_input_width"))) {
224 hw_resource->hw_dest_scalar_info.max_input_width = UINT32(atoi(tokens[1]));
225 } else if (!strncmp(tokens[0], "max_dest_scaler_output_width",
226 strlen("max_dest_scaler_output_width"))) {
227 hw_resource->hw_dest_scalar_info.max_output_width = UINT32(atoi(tokens[1]));
228 } else if (!strncmp(tokens[0], "features", strlen("features"))) {
229 for (uint32_t i = 0; i < token_count; i++) {
230 if (!strncmp(tokens[i], "bwc", strlen("bwc"))) {
231 hw_resource->has_bwc = true;
232 } else if (!strncmp(tokens[i], "ubwc", strlen("ubwc"))) {
233 hw_resource->has_ubwc = true;
234 } else if (!strncmp(tokens[i], "decimation", strlen("decimation"))) {
235 hw_resource->has_decimation = true;
236 } else if (!strncmp(tokens[i], "tile_format", strlen("tile_format"))) {
237 hw_resource->has_macrotile = true;
238 } else if (!strncmp(tokens[i], "src_split", strlen("src_split"))) {
239 hw_resource->is_src_split = true;
240 } else if (!strncmp(tokens[i], "non_scalar_rgb", strlen("non_scalar_rgb"))) {
241 hw_resource->has_non_scalar_rgb = true;
242 } else if (!strncmp(tokens[i], "perf_calc", strlen("perf_calc"))) {
243 hw_resource->perf_calc = true;
244 } else if (!strncmp(tokens[i], "dynamic_bw_limit", strlen("dynamic_bw_limit"))) {
245 hw_resource->has_dyn_bw_support = true;
246 } else if (!strncmp(tokens[i], "separate_rotator", strlen("separate_rotator"))) {
247 hw_resource->separate_rotator = true;
248 } else if (!strncmp(tokens[i], "qseed3", strlen("qseed3"))) {
249 hw_resource->has_qseed3 = true;
250 } else if (!strncmp(tokens[i], "concurrent_writeback", strlen("concurrent_writeback"))) {
251 hw_resource->has_concurrent_writeback = true;
252 }
253 }
254 } else if (!strncmp(tokens[0], "pipe_count", strlen("pipe_count"))) {
255 uint32_t pipe_count = UINT8(atoi(tokens[1]));
256 for (uint32_t i = 0; i < pipe_count; i++) {
257 Sys::getline_(fs, line);
258 if (!ParseString(line.c_str(), tokens, max_count, ": =\n", &token_count)) {
259 HWPipeCaps pipe_caps;
260 pipe_caps.type = kPipeTypeUnused;
261 for (uint32_t j = 0; j < token_count; j += 2) {
262 if (!strncmp(tokens[j], "pipe_type", strlen("pipe_type"))) {
263 if (!strncmp(tokens[j+1], "vig", strlen("vig"))) {
264 pipe_caps.type = kPipeTypeVIG;
265 hw_resource->num_vig_pipe++;
266 } else if (!strncmp(tokens[j+1], "rgb", strlen("rgb"))) {
267 pipe_caps.type = kPipeTypeRGB;
268 hw_resource->num_rgb_pipe++;
269 } else if (!strncmp(tokens[j+1], "dma", strlen("dma"))) {
270 pipe_caps.type = kPipeTypeDMA;
271 hw_resource->num_dma_pipe++;
272 } else if (!strncmp(tokens[j+1], "cursor", strlen("cursor"))) {
273 pipe_caps.type = kPipeTypeCursor;
274 hw_resource->num_cursor_pipe++;
275 }
276 } else if (!strncmp(tokens[j], "pipe_ndx", strlen("pipe_ndx"))) {
277 pipe_caps.id = UINT32(atoi(tokens[j+1]));
278 } else if (!strncmp(tokens[j], "rects", strlen("rects"))) {
279 pipe_caps.max_rects = UINT32(atoi(tokens[j+1]));
280 } else if (!strncmp(tokens[j], "fmts_supported", strlen("fmts_supported"))) {
281 char *tokens_fmt[max_count] = { NULL };
282 uint32_t token_fmt_count = 0;
283 if (!ParseString(tokens[j+1], tokens_fmt, max_count, ",\n", &token_fmt_count)) {
284 if (pipe_caps.type == kPipeTypeVIG) {
285 ParseFormats(tokens_fmt, token_fmt_count, kHWVIGPipe, hw_resource);
286 } else if (pipe_caps.type == kPipeTypeRGB) {
287 ParseFormats(tokens_fmt, token_fmt_count, kHWRGBPipe, hw_resource);
288 } else if (pipe_caps.type == kPipeTypeDMA) {
289 ParseFormats(tokens_fmt, token_fmt_count, kHWDMAPipe, hw_resource);
290 } else if (pipe_caps.type == kPipeTypeCursor) {
291 ParseFormats(tokens_fmt, token_fmt_count, kHWCursorPipe, hw_resource);
292 }
293 }
294 }
295 }
296 hw_resource->hw_pipes.push_back(pipe_caps);
297 }
298 }
299 }
300 }
301 }
302
303 // Disable destination scalar count to 0 if extension library is not present
304 DynLib extension_lib;
305 if (!extension_lib.Open("libsdmextension.so")) {
306 hw_resource->hw_dest_scalar_info.count = 0;
307 }
308
309 DLOGI("SDE Version = %d, SDE Revision = %x, RGB = %d, VIG = %d, DMA = %d, Cursor = %d",
310 hw_resource->hw_version, hw_resource->hw_revision, hw_resource->num_rgb_pipe,
311 hw_resource->num_vig_pipe, hw_resource->num_dma_pipe, hw_resource->num_cursor_pipe);
312 DLOGI("Upscale Ratio = %d, Downscale Ratio = %d, Blending Stages = %d", hw_resource->max_scale_up,
313 hw_resource->max_scale_down, hw_resource->num_blending_stages);
314 DLOGI("SourceSplit = %d QSEED3 = %d", hw_resource->is_src_split, hw_resource->has_qseed3);
315 DLOGI("BWC = %d, UBWC = %d, Decimation = %d, Tile Format = %d Concurrent Writeback = %d",
316 hw_resource->has_bwc, hw_resource->has_ubwc, hw_resource->has_decimation,
317 hw_resource->has_macrotile, hw_resource->has_concurrent_writeback);
318 DLOGI("MaxLowBw = %" PRIu64 " , MaxHighBw = % " PRIu64 "", hw_resource->max_bandwidth_low,
319 hw_resource->max_bandwidth_high);
320 DLOGI("MaxPipeBw = %" PRIu64 " KBps, MaxSDEClock = % " PRIu64 " Hz, ClockFudgeFactor = %f",
321 hw_resource->max_pipe_bw, hw_resource->max_sde_clk, hw_resource->clk_fudge_factor);
322 DLOGI("Prefill factors: Tiled_NV12 = %d, Tiled = %d, Linear = %d, Scale = %d, Fudge_factor = %d",
323 hw_resource->macrotile_nv12_factor, hw_resource->macrotile_factor,
324 hw_resource->linear_factor, hw_resource->scale_factor, hw_resource->extra_fudge_factor);
325
326 if (hw_resource->separate_rotator || hw_resource->num_dma_pipe) {
327 GetHWRotatorInfo(hw_resource);
328 }
329
330 // If the driver doesn't spell out the wb index, assume it to be the number of rotators,
331 // based on legacy implementation.
332 if (hw_resource->writeback_index == kHWBlockMax) {
333 hw_resource->writeback_index = hw_resource->hw_rot_info.num_rotator;
334 }
335
336 if (hw_resource->has_dyn_bw_support) {
337 DisplayError ret = GetDynamicBWLimits(hw_resource);
338 if (ret != kErrorNone) {
339 DLOGE("Failed to read dynamic band width info");
340 return ret;
341 }
342
343 DLOGI("Has Support for multiple bw limits shown below");
344 for (int index = 0; index < kBwModeMax; index++) {
345 DLOGI("Mode-index=%d total_bw_limit=%d and pipe_bw_limit=%d",
346 index, hw_resource->dyn_bw_info.total_bw_limit[index],
347 hw_resource->dyn_bw_info.pipe_bw_limit[index]);
348 }
349 }
350
351 return kErrorNone;
352 }
353
GetHWRotatorInfo(HWResourceInfo * hw_resource)354 DisplayError HWInfo::GetHWRotatorInfo(HWResourceInfo *hw_resource) {
355 if (GetMDSSRotatorInfo(hw_resource) != kErrorNone)
356 return GetV4L2RotatorInfo(hw_resource);
357
358 return kErrorNone;
359 }
360
GetMDSSRotatorInfo(HWResourceInfo * hw_resource)361 DisplayError HWInfo::GetMDSSRotatorInfo(HWResourceInfo *hw_resource) {
362 Sys::fstream fs(kRotatorCapsPath, fstream::in);
363 if (!fs.is_open()) {
364 DLOGW("File '%s' not found", kRotatorCapsPath);
365 return kErrorNotSupported;
366 }
367
368 uint32_t token_count = 0;
369 const uint32_t max_count = 10;
370 char *tokens[max_count] = { NULL };
371 string line;
372
373 hw_resource->hw_rot_info.type = HWRotatorInfo::ROT_TYPE_MDSS;
374 while (Sys::getline_(fs, line)) {
375 if (!ParseString(line.c_str(), tokens, max_count, ":, =\n", &token_count)) {
376 if (!strncmp(tokens[0], "wb_count", strlen("wb_count"))) {
377 hw_resource->hw_rot_info.num_rotator = UINT8(atoi(tokens[1]));
378 hw_resource->hw_rot_info.device_path = "/dev/mdss_rotator";
379 } else if (!strncmp(tokens[0], "downscale", strlen("downscale"))) {
380 hw_resource->hw_rot_info.has_downscale = UINT8(atoi(tokens[1]));
381 }
382 }
383 }
384
385 DLOGI("MDSS Rotator: Count = %d, Downscale = %d", hw_resource->hw_rot_info.num_rotator,
386 hw_resource->hw_rot_info.has_downscale);
387
388 return kErrorNone;
389 }
390
GetV4L2RotatorInfo(HWResourceInfo * hw_resource)391 DisplayError HWInfo::GetV4L2RotatorInfo(HWResourceInfo *hw_resource) {
392 const uint32_t kMaxV4L2Nodes = 64;
393 bool found = false;
394
395 for (uint32_t i = 0; (i < kMaxV4L2Nodes) && (false == found); i++) {
396 string path = "/sys/class/video4linux/video" + to_string(i) + "/name";
397 Sys::fstream fs(path, fstream::in);
398 if (!fs.is_open()) {
399 continue;
400 }
401
402 string line;
403 if (Sys::getline_(fs, line) &&
404 (!strncmp(line.c_str(), "sde_rotator", strlen("sde_rotator")))) {
405 hw_resource->hw_rot_info.device_path = string("/dev/video" + to_string(i));
406 hw_resource->hw_rot_info.num_rotator++;
407 hw_resource->hw_rot_info.type = HWRotatorInfo::ROT_TYPE_V4L2;
408 hw_resource->hw_rot_info.has_downscale = true;
409 // We support only 1 rotator
410 found = true;
411 }
412 }
413
414 DLOGI("V4L2 Rotator: Count = %d, Downscale = %d", hw_resource->hw_rot_info.num_rotator,
415 hw_resource->hw_rot_info.has_downscale);
416
417 return kErrorNone;
418 }
419
GetSDMFormat(int mdp_format)420 LayerBufferFormat HWInfo::GetSDMFormat(int mdp_format) {
421 switch (mdp_format) {
422 case MDP_ARGB_8888: return kFormatARGB8888;
423 case MDP_RGBA_8888: return kFormatRGBA8888;
424 case MDP_BGRA_8888: return kFormatBGRA8888;
425 case MDP_XRGB_8888: return kFormatXRGB8888;
426 case MDP_RGBX_8888: return kFormatRGBX8888;
427 case MDP_BGRX_8888: return kFormatBGRX8888;
428 case MDP_RGBA_5551: return kFormatRGBA5551;
429 case MDP_RGBA_4444: return kFormatRGBA4444;
430 case MDP_RGB_888: return kFormatRGB888;
431 case MDP_BGR_888: return kFormatBGR888;
432 case MDP_RGB_565: return kFormatRGB565;
433 case MDP_BGR_565: return kFormatBGR565;
434 case MDP_RGBA_8888_UBWC: return kFormatRGBA8888Ubwc;
435 case MDP_RGBX_8888_UBWC: return kFormatRGBX8888Ubwc;
436 case MDP_RGB_565_UBWC: return kFormatBGR565Ubwc;
437 case MDP_Y_CB_CR_H2V2: return kFormatYCbCr420Planar;
438 case MDP_Y_CR_CB_H2V2: return kFormatYCrCb420Planar;
439 case MDP_Y_CR_CB_GH2V2: return kFormatYCrCb420PlanarStride16;
440 case MDP_Y_CBCR_H2V2: return kFormatYCbCr420SemiPlanar;
441 case MDP_Y_CRCB_H2V2: return kFormatYCrCb420SemiPlanar;
442 case MDP_Y_CBCR_H2V2_VENUS: return kFormatYCbCr420SemiPlanarVenus;
443 case MDP_Y_CBCR_H1V2: return kFormatYCbCr422H1V2SemiPlanar;
444 case MDP_Y_CRCB_H1V2: return kFormatYCrCb422H1V2SemiPlanar;
445 case MDP_Y_CBCR_H2V1: return kFormatYCbCr422H2V1SemiPlanar;
446 case MDP_Y_CRCB_H2V1: return kFormatYCrCb422H2V1SemiPlanar;
447 case MDP_Y_CBCR_H2V2_UBWC: return kFormatYCbCr420SPVenusUbwc;
448 case MDP_Y_CRCB_H2V2_VENUS: return kFormatYCrCb420SemiPlanarVenus;
449 case MDP_YCBYCR_H2V1: return kFormatYCbCr422H2V1Packed;
450 case MDP_RGBA_1010102: return kFormatRGBA1010102;
451 case MDP_ARGB_2101010: return kFormatARGB2101010;
452 case MDP_RGBX_1010102: return kFormatRGBX1010102;
453 case MDP_XRGB_2101010: return kFormatXRGB2101010;
454 case MDP_BGRA_1010102: return kFormatBGRA1010102;
455 case MDP_ABGR_2101010: return kFormatABGR2101010;
456 case MDP_BGRX_1010102: return kFormatBGRX1010102;
457 case MDP_XBGR_2101010: return kFormatXBGR2101010;
458 case MDP_RGBA_1010102_UBWC: return kFormatRGBA1010102Ubwc;
459 case MDP_RGBX_1010102_UBWC: return kFormatRGBX1010102Ubwc;
460 case MDP_Y_CBCR_H2V2_P010: return kFormatYCbCr420P010;
461 case MDP_Y_CBCR_H2V2_TP10_UBWC: return kFormatYCbCr420TP10Ubwc;
462 default: return kFormatInvalid;
463 }
464 }
465
InitSupportedFormatMap(HWResourceInfo * hw_resource)466 void HWInfo::InitSupportedFormatMap(HWResourceInfo *hw_resource) {
467 hw_resource->supported_formats_map.clear();
468
469 for (int sub_blk_type = INT(kHWVIGPipe); sub_blk_type < INT(kHWSubBlockMax); sub_blk_type++) {
470 PopulateSupportedFormatMap(kDefaultFormatSupport[sub_blk_type], MDP_IMGTYPE_LIMIT1,
471 (HWSubBlockType)sub_blk_type, hw_resource);
472 }
473 }
474
ParseFormats(char * tokens[],uint32_t token_count,HWSubBlockType sub_blk_type,HWResourceInfo * hw_resource)475 void HWInfo::ParseFormats(char *tokens[], uint32_t token_count, HWSubBlockType sub_blk_type,
476 HWResourceInfo *hw_resource) {
477 if (token_count > BITS_TO_BYTES(MDP_IMGTYPE_LIMIT1)) {
478 return;
479 }
480
481 std::unique_ptr<std::bitset<8>[]> format_supported(new std::bitset<8>[token_count]);
482 for (uint32_t i = 0; i < token_count; i++) {
483 format_supported[i] = UINT8(atoi(tokens[i]));
484 }
485
486 PopulateSupportedFormatMap(format_supported.get(), (token_count << 3), sub_blk_type, hw_resource);
487 }
488
PopulateSupportedFormatMap(const std::bitset<8> * format_supported,uint32_t format_count,HWSubBlockType sub_blk_type,HWResourceInfo * hw_resource)489 void HWInfo::PopulateSupportedFormatMap(const std::bitset<8> *format_supported,
490 uint32_t format_count, HWSubBlockType sub_blk_type,
491 HWResourceInfo *hw_resource) {
492 vector <LayerBufferFormat> supported_sdm_formats;
493 for (uint32_t mdp_format = 0; mdp_format < format_count; mdp_format++) {
494 if (format_supported[mdp_format >> 3][mdp_format & 7]) {
495 LayerBufferFormat sdm_format = GetSDMFormat(INT(mdp_format));
496 if (sdm_format != kFormatInvalid) {
497 supported_sdm_formats.push_back(sdm_format);
498 }
499 }
500 }
501
502 hw_resource->supported_formats_map.erase(sub_blk_type);
503 hw_resource->supported_formats_map.insert(make_pair(sub_blk_type, supported_sdm_formats));
504 }
505
GetFirstDisplayInterfaceType(HWDisplayInterfaceInfo * hw_disp_info)506 DisplayError HWInfo::GetFirstDisplayInterfaceType(HWDisplayInterfaceInfo *hw_disp_info) {
507 Sys::fstream fs("/sys/devices/virtual/graphics/fb0/msm_fb_type", fstream::in);
508 if (!fs.is_open()) {
509 return kErrorHardware;
510 }
511
512 string line;
513 if (!Sys::getline_(fs, line)) {
514 return kErrorHardware;
515 }
516
517 if (!strncmp(line.c_str(), "dtv panel", strlen("dtv panel"))) {
518 hw_disp_info->type = kHDMI;
519 DLOGI("First display is HDMI");
520 } else {
521 hw_disp_info->type = kPrimary;
522 DLOGI("First display is internal display");
523 }
524
525 fs.close();
526 fs.open("/sys/devices/virtual/graphics/fb0/connected", fstream::in);
527 if (!fs.is_open()) {
528 // If fb0 is for a DSI/connected panel, then connected node will not exist.
529 hw_disp_info->is_connected = true;
530 } else {
531 if (!Sys::getline_(fs, line)) {
532 return kErrorHardware;
533 }
534
535 hw_disp_info->is_connected = (!strncmp(line.c_str(), "1", strlen("1")));
536 }
537
538 return kErrorNone;
539 }
540
541 } // namespace sdm
542
543