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 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 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 103 DisplayError HWInfoInterface::Destroy(HWInfoInterface *intf) { 104 HWInfo *hw_info = static_cast<HWInfo *>(intf); 105 delete hw_info; 106 107 return kErrorNone; 108 } 109 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 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 } else if (!strncmp(tokens[i], "avr", strlen("avr"))) { 253 hw_resource->has_avr = true; 254 } 255 } 256 } else if (!strncmp(tokens[0], "pipe_count", strlen("pipe_count"))) { 257 uint32_t pipe_count = UINT8(atoi(tokens[1])); 258 for (uint32_t i = 0; i < pipe_count; i++) { 259 Sys::getline_(fs, line); 260 if (!ParseString(line.c_str(), tokens, max_count, ": =\n", &token_count)) { 261 HWPipeCaps pipe_caps; 262 pipe_caps.type = kPipeTypeUnused; 263 for (uint32_t j = 0; j < token_count; j += 2) { 264 if (!strncmp(tokens[j], "pipe_type", strlen("pipe_type"))) { 265 if (!strncmp(tokens[j+1], "vig", strlen("vig"))) { 266 pipe_caps.type = kPipeTypeVIG; 267 hw_resource->num_vig_pipe++; 268 } else if (!strncmp(tokens[j+1], "rgb", strlen("rgb"))) { 269 pipe_caps.type = kPipeTypeRGB; 270 hw_resource->num_rgb_pipe++; 271 } else if (!strncmp(tokens[j+1], "dma", strlen("dma"))) { 272 pipe_caps.type = kPipeTypeDMA; 273 hw_resource->num_dma_pipe++; 274 } else if (!strncmp(tokens[j+1], "cursor", strlen("cursor"))) { 275 pipe_caps.type = kPipeTypeCursor; 276 hw_resource->num_cursor_pipe++; 277 } 278 } else if (!strncmp(tokens[j], "pipe_ndx", strlen("pipe_ndx"))) { 279 pipe_caps.id = UINT32(atoi(tokens[j+1])); 280 } else if (!strncmp(tokens[j], "rects", strlen("rects"))) { 281 pipe_caps.max_rects = UINT32(atoi(tokens[j+1])); 282 } else if (!strncmp(tokens[j], "fmts_supported", strlen("fmts_supported"))) { 283 char *tokens_fmt[max_count] = { NULL }; 284 uint32_t token_fmt_count = 0; 285 if (!ParseString(tokens[j+1], tokens_fmt, max_count, ",\n", &token_fmt_count)) { 286 if (pipe_caps.type == kPipeTypeVIG) { 287 ParseFormats(tokens_fmt, token_fmt_count, kHWVIGPipe, hw_resource); 288 } else if (pipe_caps.type == kPipeTypeRGB) { 289 ParseFormats(tokens_fmt, token_fmt_count, kHWRGBPipe, hw_resource); 290 } else if (pipe_caps.type == kPipeTypeDMA) { 291 ParseFormats(tokens_fmt, token_fmt_count, kHWDMAPipe, hw_resource); 292 } else if (pipe_caps.type == kPipeTypeCursor) { 293 ParseFormats(tokens_fmt, token_fmt_count, kHWCursorPipe, hw_resource); 294 } 295 } 296 } 297 } 298 hw_resource->hw_pipes.push_back(pipe_caps); 299 } 300 } 301 } 302 } 303 } 304 305 // Disable destination scalar count to 0 if extension library is not present 306 DynLib extension_lib; 307 if (!extension_lib.Open("libsdmextension.so")) { 308 hw_resource->hw_dest_scalar_info.count = 0; 309 } 310 311 DLOGI("SDE Version = %d, SDE Revision = %x, RGB = %d, VIG = %d, DMA = %d, Cursor = %d", 312 hw_resource->hw_version, hw_resource->hw_revision, hw_resource->num_rgb_pipe, 313 hw_resource->num_vig_pipe, hw_resource->num_dma_pipe, hw_resource->num_cursor_pipe); 314 DLOGI("Upscale Ratio = %d, Downscale Ratio = %d, Blending Stages = %d", hw_resource->max_scale_up, 315 hw_resource->max_scale_down, hw_resource->num_blending_stages); 316 DLOGI("SourceSplit = %d QSEED3 = %d", hw_resource->is_src_split, hw_resource->has_qseed3); 317 DLOGI("BWC = %d, UBWC = %d, Decimation = %d, Tile Format = %d Concurrent Writeback = %d", 318 hw_resource->has_bwc, hw_resource->has_ubwc, hw_resource->has_decimation, 319 hw_resource->has_macrotile, hw_resource->has_concurrent_writeback); 320 DLOGI("MaxLowBw = %" PRIu64 " , MaxHighBw = % " PRIu64 "", hw_resource->max_bandwidth_low, 321 hw_resource->max_bandwidth_high); 322 DLOGI("MaxPipeBw = %" PRIu64 " KBps, MaxSDEClock = % " PRIu64 " Hz, ClockFudgeFactor = %f", 323 hw_resource->max_pipe_bw, hw_resource->max_sde_clk, hw_resource->clk_fudge_factor); 324 DLOGI("Prefill factors: Tiled_NV12 = %d, Tiled = %d, Linear = %d, Scale = %d, Fudge_factor = %d", 325 hw_resource->macrotile_nv12_factor, hw_resource->macrotile_factor, 326 hw_resource->linear_factor, hw_resource->scale_factor, hw_resource->extra_fudge_factor); 327 328 if (hw_resource->separate_rotator || hw_resource->num_dma_pipe) { 329 GetHWRotatorInfo(hw_resource); 330 } 331 332 // If the driver doesn't spell out the wb index, assume it to be the number of rotators, 333 // based on legacy implementation. 334 if (hw_resource->writeback_index == kHWBlockMax) { 335 hw_resource->writeback_index = hw_resource->hw_rot_info.num_rotator; 336 } 337 338 if (hw_resource->has_dyn_bw_support) { 339 DisplayError ret = GetDynamicBWLimits(hw_resource); 340 if (ret != kErrorNone) { 341 DLOGE("Failed to read dynamic band width info"); 342 return ret; 343 } 344 345 DLOGI("Has Support for multiple bw limits shown below"); 346 for (int index = 0; index < kBwModeMax; index++) { 347 DLOGI("Mode-index=%d total_bw_limit=%d and pipe_bw_limit=%d", 348 index, hw_resource->dyn_bw_info.total_bw_limit[index], 349 hw_resource->dyn_bw_info.pipe_bw_limit[index]); 350 } 351 } 352 353 return kErrorNone; 354 } 355 356 DisplayError HWInfo::GetHWRotatorInfo(HWResourceInfo *hw_resource) { 357 if (GetMDSSRotatorInfo(hw_resource) != kErrorNone) 358 return GetV4L2RotatorInfo(hw_resource); 359 360 return kErrorNone; 361 } 362 363 DisplayError HWInfo::GetMDSSRotatorInfo(HWResourceInfo *hw_resource) { 364 Sys::fstream fs(kRotatorCapsPath, fstream::in); 365 if (!fs.is_open()) { 366 DLOGW("File '%s' not found", kRotatorCapsPath); 367 return kErrorNotSupported; 368 } 369 370 uint32_t token_count = 0; 371 const uint32_t max_count = 10; 372 char *tokens[max_count] = { NULL }; 373 string line; 374 375 hw_resource->hw_rot_info.type = HWRotatorInfo::ROT_TYPE_MDSS; 376 while (Sys::getline_(fs, line)) { 377 if (!ParseString(line.c_str(), tokens, max_count, ":, =\n", &token_count)) { 378 if (!strncmp(tokens[0], "wb_count", strlen("wb_count"))) { 379 hw_resource->hw_rot_info.num_rotator = UINT8(atoi(tokens[1])); 380 hw_resource->hw_rot_info.device_path = "/dev/mdss_rotator"; 381 } else if (!strncmp(tokens[0], "downscale", strlen("downscale"))) { 382 hw_resource->hw_rot_info.has_downscale = UINT8(atoi(tokens[1])); 383 } 384 } 385 } 386 387 DLOGI("MDSS Rotator: Count = %d, Downscale = %d", hw_resource->hw_rot_info.num_rotator, 388 hw_resource->hw_rot_info.has_downscale); 389 390 return kErrorNone; 391 } 392 393 DisplayError HWInfo::GetV4L2RotatorInfo(HWResourceInfo *hw_resource) { 394 const uint32_t kMaxV4L2Nodes = 64; 395 bool found = false; 396 397 for (uint32_t i = 0; (i < kMaxV4L2Nodes) && (false == found); i++) { 398 string path = "/sys/class/video4linux/video" + to_string(i) + "/name"; 399 Sys::fstream fs(path, fstream::in); 400 if (!fs.is_open()) { 401 continue; 402 } 403 404 string line; 405 if (Sys::getline_(fs, line) && 406 (!strncmp(line.c_str(), "sde_rotator", strlen("sde_rotator")))) { 407 hw_resource->hw_rot_info.device_path = string("/dev/video" + to_string(i)); 408 hw_resource->hw_rot_info.num_rotator++; 409 hw_resource->hw_rot_info.type = HWRotatorInfo::ROT_TYPE_V4L2; 410 hw_resource->hw_rot_info.has_downscale = true; 411 // We support only 1 rotator 412 found = true; 413 } 414 } 415 416 DLOGI("V4L2 Rotator: Count = %d, Downscale = %d", hw_resource->hw_rot_info.num_rotator, 417 hw_resource->hw_rot_info.has_downscale); 418 419 return kErrorNone; 420 } 421 422 LayerBufferFormat HWInfo::GetSDMFormat(int mdp_format) { 423 switch (mdp_format) { 424 case MDP_ARGB_8888: return kFormatARGB8888; 425 case MDP_RGBA_8888: return kFormatRGBA8888; 426 case MDP_BGRA_8888: return kFormatBGRA8888; 427 case MDP_XRGB_8888: return kFormatXRGB8888; 428 case MDP_RGBX_8888: return kFormatRGBX8888; 429 case MDP_BGRX_8888: return kFormatBGRX8888; 430 case MDP_RGBA_5551: return kFormatRGBA5551; 431 case MDP_RGBA_4444: return kFormatRGBA4444; 432 case MDP_RGB_888: return kFormatRGB888; 433 case MDP_BGR_888: return kFormatBGR888; 434 case MDP_RGB_565: return kFormatRGB565; 435 case MDP_BGR_565: return kFormatBGR565; 436 case MDP_RGBA_8888_UBWC: return kFormatRGBA8888Ubwc; 437 case MDP_RGBX_8888_UBWC: return kFormatRGBX8888Ubwc; 438 case MDP_RGB_565_UBWC: return kFormatBGR565Ubwc; 439 case MDP_Y_CB_CR_H2V2: return kFormatYCbCr420Planar; 440 case MDP_Y_CR_CB_H2V2: return kFormatYCrCb420Planar; 441 case MDP_Y_CR_CB_GH2V2: return kFormatYCrCb420PlanarStride16; 442 case MDP_Y_CBCR_H2V2: return kFormatYCbCr420SemiPlanar; 443 case MDP_Y_CRCB_H2V2: return kFormatYCrCb420SemiPlanar; 444 case MDP_Y_CBCR_H2V2_VENUS: return kFormatYCbCr420SemiPlanarVenus; 445 case MDP_Y_CBCR_H1V2: return kFormatYCbCr422H1V2SemiPlanar; 446 case MDP_Y_CRCB_H1V2: return kFormatYCrCb422H1V2SemiPlanar; 447 case MDP_Y_CBCR_H2V1: return kFormatYCbCr422H2V1SemiPlanar; 448 case MDP_Y_CRCB_H2V1: return kFormatYCrCb422H2V1SemiPlanar; 449 case MDP_Y_CBCR_H2V2_UBWC: return kFormatYCbCr420SPVenusUbwc; 450 case MDP_Y_CRCB_H2V2_VENUS: return kFormatYCrCb420SemiPlanarVenus; 451 case MDP_YCBYCR_H2V1: return kFormatYCbCr422H2V1Packed; 452 case MDP_RGBA_1010102: return kFormatRGBA1010102; 453 case MDP_ARGB_2101010: return kFormatARGB2101010; 454 case MDP_RGBX_1010102: return kFormatRGBX1010102; 455 case MDP_XRGB_2101010: return kFormatXRGB2101010; 456 case MDP_BGRA_1010102: return kFormatBGRA1010102; 457 case MDP_ABGR_2101010: return kFormatABGR2101010; 458 case MDP_BGRX_1010102: return kFormatBGRX1010102; 459 case MDP_XBGR_2101010: return kFormatXBGR2101010; 460 case MDP_RGBA_1010102_UBWC: return kFormatRGBA1010102Ubwc; 461 case MDP_RGBX_1010102_UBWC: return kFormatRGBX1010102Ubwc; 462 case MDP_Y_CBCR_H2V2_P010: return kFormatYCbCr420P010; 463 case MDP_Y_CBCR_H2V2_TP10_UBWC: return kFormatYCbCr420TP10Ubwc; 464 default: return kFormatInvalid; 465 } 466 } 467 468 void HWInfo::InitSupportedFormatMap(HWResourceInfo *hw_resource) { 469 hw_resource->supported_formats_map.clear(); 470 471 for (int sub_blk_type = INT(kHWVIGPipe); sub_blk_type < INT(kHWSubBlockMax); sub_blk_type++) { 472 PopulateSupportedFormatMap(kDefaultFormatSupport[sub_blk_type], MDP_IMGTYPE_LIMIT1, 473 (HWSubBlockType)sub_blk_type, hw_resource); 474 } 475 } 476 477 void HWInfo::ParseFormats(char *tokens[], uint32_t token_count, HWSubBlockType sub_blk_type, 478 HWResourceInfo *hw_resource) { 479 if (token_count > BITS_TO_BYTES(MDP_IMGTYPE_LIMIT1)) { 480 return; 481 } 482 483 std::unique_ptr<std::bitset<8>[]> format_supported(new std::bitset<8>[token_count]); 484 for (uint32_t i = 0; i < token_count; i++) { 485 format_supported[i] = UINT8(atoi(tokens[i])); 486 } 487 488 PopulateSupportedFormatMap(format_supported.get(), (token_count << 3), sub_blk_type, hw_resource); 489 } 490 491 void HWInfo::PopulateSupportedFormatMap(const std::bitset<8> *format_supported, 492 uint32_t format_count, HWSubBlockType sub_blk_type, 493 HWResourceInfo *hw_resource) { 494 vector <LayerBufferFormat> supported_sdm_formats; 495 for (uint32_t mdp_format = 0; mdp_format < format_count; mdp_format++) { 496 if (format_supported[mdp_format >> 3][mdp_format & 7]) { 497 LayerBufferFormat sdm_format = GetSDMFormat(INT(mdp_format)); 498 if (sdm_format != kFormatInvalid) { 499 supported_sdm_formats.push_back(sdm_format); 500 } 501 } 502 } 503 504 hw_resource->supported_formats_map.erase(sub_blk_type); 505 hw_resource->supported_formats_map.insert(make_pair(sub_blk_type, supported_sdm_formats)); 506 } 507 508 DisplayError HWInfo::GetFirstDisplayInterfaceType(HWDisplayInterfaceInfo *hw_disp_info) { 509 Sys::fstream fs("/sys/devices/virtual/graphics/fb0/msm_fb_type", fstream::in); 510 if (!fs.is_open()) { 511 return kErrorHardware; 512 } 513 514 string line; 515 if (!Sys::getline_(fs, line)) { 516 return kErrorHardware; 517 } 518 519 if (!strncmp(line.c_str(), "dtv panel", strlen("dtv panel")) || 520 !strncmp(line.c_str(), "dp panel", strlen("dp panel"))) { 521 hw_disp_info->type = kHDMI; 522 DLOGI("First display is HDMI"); 523 } else { 524 hw_disp_info->type = kPrimary; 525 DLOGI("First display is internal display"); 526 } 527 528 fs.close(); 529 fs.open("/sys/devices/virtual/graphics/fb0/connected", fstream::in); 530 if (!fs.is_open()) { 531 // If fb0 is for a DSI/connected panel, then connected node will not exist. 532 hw_disp_info->is_connected = true; 533 } else { 534 if (!Sys::getline_(fs, line)) { 535 return kErrorHardware; 536 } 537 538 hw_disp_info->is_connected = (!strncmp(line.c_str(), "1", strlen("1"))); 539 } 540 541 return kErrorNone; 542 } 543 544 } // namespace sdm 545 546