Home | History | Annotate | Download | only in drm
      1 /*
      2 * Copyright (c) 2017, The Linux Foundation. All rights reserved.
      3 *
      4 * Redistribution and use in source and binary forms, with or without
      5 * modification, are permitted provided that the following conditions are
      6 * met:
      7 *     * Redistributions of source code must retain the above copyright
      8 *       notice, this list of conditions and the following disclaimer.
      9 *     * Redistributions in binary form must reproduce the above
     10 *       copyright notice, this list of conditions and the following
     11 *       disclaimer in the documentation and/or other materials provided
     12 *       with the distribution.
     13 *     * Neither the name of The Linux Foundation nor the names of its
     14 *       contributors may be used to endorse or promote products derived
     15 *       from this software without specific prior written permission.
     16 *
     17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
     18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
     20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
     21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
     24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
     26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
     27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28 */
     29 
     30 #include <dlfcn.h>
     31 #include <drm/drm_fourcc.h>
     32 #include <drm_lib_loader.h>
     33 #include <drm_master.h>
     34 #include <drm_res_mgr.h>
     35 #include <fcntl.h>
     36 #include <media/msm_sde_rotator.h>
     37 #include <stdio.h>
     38 #include <stdlib.h>
     39 #include <string.h>
     40 #include <sys/stat.h>
     41 #include <sys/types.h>
     42 #include <utils/constants.h>
     43 #include <utils/debug.h>
     44 #include <utils/sys.h>
     45 
     46 #include <algorithm>
     47 #include <fstream>
     48 #include <iostream>
     49 #include <map>
     50 #include <memory>
     51 #include <string>
     52 #include <utility>
     53 #include <vector>
     54 
     55 #include "hw_info_drm.h"
     56 
     57 #ifndef DRM_FORMAT_MOD_QCOM_COMPRESSED
     58 #define DRM_FORMAT_MOD_QCOM_COMPRESSED fourcc_mod_code(QCOM, 1)
     59 #endif
     60 #ifndef DRM_FORMAT_MOD_QCOM_DX
     61 #define DRM_FORMAT_MOD_QCOM_DX fourcc_mod_code(QCOM, 0x2)
     62 #endif
     63 #ifndef DRM_FORMAT_MOD_QCOM_TIGHT
     64 #define DRM_FORMAT_MOD_QCOM_TIGHT fourcc_mod_code(QCOM, 0x4)
     65 #endif
     66 
     67 #define __CLASS__ "HWInfoDRM"
     68 
     69 using drm_utils::DRMMaster;
     70 using drm_utils::DRMResMgr;
     71 using drm_utils::DRMLogger;
     72 using drm_utils::DRMLibLoader;
     73 using sde_drm::GetDRMManager;
     74 using sde_drm::DRMPlanesInfo;
     75 using sde_drm::DRMCrtcInfo;
     76 using sde_drm::DRMPlaneType;
     77 
     78 using std::vector;
     79 using std::map;
     80 using std::string;
     81 using std::fstream;
     82 using std::to_string;
     83 
     84 namespace sdm {
     85 
     86 class DRMLoggerImpl : public DRMLogger {
     87  public:
     88 #define PRINTLOG(method, format, buf)        \
     89   va_list list;                              \
     90   va_start(list, format);                    \
     91   vsnprintf(buf, sizeof(buf), format, list); \
     92   va_end(list);                              \
     93   Debug::Get()->method(kTagNone, "%s", buf);
     94 
     95   void Error(const char *format, ...) { PRINTLOG(Error, format, buf_); }
     96   void Warning(const char *format, ...) { PRINTLOG(Warning, format, buf_); }
     97   void Info(const char *format, ...) { PRINTLOG(Info, format, buf_); }
     98   void Debug(const char *format, ...) { PRINTLOG(Debug, format, buf_); }
     99 
    100  private:
    101   char buf_[1024] = {};
    102 };
    103 
    104 HWResourceInfo *HWInfoDRM::hw_resource_ = nullptr;
    105 
    106 HWInfoDRM::HWInfoDRM() {
    107   DRMLogger::Set(new DRMLoggerImpl());
    108   default_mode_ = (DRMLibLoader::GetInstance()->IsLoaded() == false);
    109   if (!default_mode_) {
    110     DRMMaster *drm_master = {};
    111     int dev_fd = -1;
    112     DRMMaster::GetInstance(&drm_master);
    113     if (!drm_master) {
    114       DLOGE("Failed to acquire DRMMaster instance");
    115       return;
    116     }
    117     drm_master->GetHandle(&dev_fd);
    118     DRMLibLoader::GetInstance()->FuncGetDRMManager()(dev_fd, &drm_mgr_intf_);
    119   }
    120 }
    121 
    122 HWInfoDRM::~HWInfoDRM() {
    123   delete hw_resource_;
    124   hw_resource_ = nullptr;
    125 
    126   if (drm_mgr_intf_) {
    127     DRMLibLoader::GetInstance()->FuncDestroyDRMManager()();
    128     drm_mgr_intf_ = nullptr;
    129   }
    130 
    131   DRMLibLoader::Destroy();
    132   DRMMaster::DestroyInstance();
    133 }
    134 
    135 DisplayError HWInfoDRM::GetDynamicBWLimits(HWResourceInfo *hw_resource) {
    136   HWDynBwLimitInfo* bw_info = &hw_resource->dyn_bw_info;
    137   for (int index = 0; index < kBwModeMax; index++) {
    138     bw_info->total_bw_limit[index] = UINT32(hw_resource->max_bandwidth_low);
    139     bw_info->pipe_bw_limit[index] = hw_resource->max_pipe_bw;
    140   }
    141 
    142   return kErrorNone;
    143 }
    144 
    145 DisplayError HWInfoDRM::GetHWResourceInfo(HWResourceInfo *hw_resource) {
    146   if (hw_resource_) {
    147     *hw_resource = *hw_resource_;
    148     return kErrorNone;
    149   }
    150 
    151   hw_resource->num_blending_stages = 1;
    152   hw_resource->max_pipe_width = 2560;
    153   hw_resource->max_cursor_size = 128;
    154   hw_resource->max_scale_down = 1;
    155   hw_resource->max_scale_up = 1;
    156   hw_resource->has_decimation = false;
    157   hw_resource->max_bandwidth_low = 9600000;
    158   hw_resource->max_bandwidth_high = 9600000;
    159   hw_resource->max_pipe_bw = 4500000;
    160   hw_resource->max_sde_clk = 412500000;
    161   hw_resource->clk_fudge_factor = FLOAT(105) / FLOAT(100);
    162   hw_resource->macrotile_nv12_factor = 8;
    163   hw_resource->macrotile_factor = 4;
    164   hw_resource->linear_factor = 1;
    165   hw_resource->scale_factor = 1;
    166   hw_resource->extra_fudge_factor = 2;
    167   hw_resource->amortizable_threshold = 0;
    168   hw_resource->system_overhead_lines = 0;
    169   hw_resource->hw_dest_scalar_info.count = 0;
    170   hw_resource->hw_dest_scalar_info.max_scale_up = 0;
    171   hw_resource->hw_dest_scalar_info.max_input_width = 0;
    172   hw_resource->hw_dest_scalar_info.max_output_width = 0;
    173   hw_resource->is_src_split = true;
    174   hw_resource->perf_calc = false;
    175   hw_resource->has_dyn_bw_support = false;
    176   hw_resource->has_qseed3 = false;
    177   hw_resource->has_concurrent_writeback = false;
    178 
    179   // TODO(user): Deprecate
    180   hw_resource->hw_version = kHWMdssVersion5;
    181   hw_resource->hw_revision = 0;
    182   hw_resource->max_mixer_width = 0;
    183   hw_resource->writeback_index = 0;
    184   hw_resource->has_bwc = false;
    185   hw_resource->has_ubwc = true;
    186   hw_resource->has_macrotile = true;
    187   hw_resource->separate_rotator = true;
    188   hw_resource->has_non_scalar_rgb = false;
    189 
    190   GetSystemInfo(hw_resource);
    191   GetHWPlanesInfo(hw_resource);
    192   GetWBInfo(hw_resource);
    193 
    194   // Disable destination scalar count to 0 if extension library is not present
    195   DynLib extension_lib;
    196   if (!extension_lib.Open("libsdmextension.so")) {
    197     hw_resource->hw_dest_scalar_info.count = 0;
    198   }
    199 
    200   DLOGI("Max plane width = %d", hw_resource->max_pipe_width);
    201   DLOGI("Max cursor width = %d", hw_resource->max_cursor_size);
    202   DLOGI("Max plane upscale = %d", hw_resource->max_scale_up);
    203   DLOGI("Max plane downscale = %d", hw_resource->max_scale_down);
    204   DLOGI("Has Decimation = %d", hw_resource->has_decimation);
    205   DLOGI("Max Blending Stages = %d", hw_resource->num_blending_stages);
    206   DLOGI("Has Source Split = %d", hw_resource->is_src_split);
    207   DLOGI("Has QSEED3 = %d", hw_resource->has_qseed3);
    208   DLOGI("Has UBWC = %d", hw_resource->has_ubwc);
    209   DLOGI("Has Concurrent Writeback = %d", hw_resource->has_concurrent_writeback);
    210   DLOGI("Max Low Bw = %" PRIu64 "", hw_resource->max_bandwidth_low);
    211   DLOGI("Max High Bw = % " PRIu64 "", hw_resource->max_bandwidth_high);
    212   DLOGI("Max Pipe Bw = %" PRIu64 " KBps", hw_resource->max_pipe_bw);
    213   DLOGI("MaxSDEClock = % " PRIu64 " Hz", hw_resource->max_sde_clk);
    214   DLOGI("Clock Fudge Factor = %f", hw_resource->clk_fudge_factor);
    215   DLOGI("Prefill factors:");
    216   DLOGI("\tTiled_NV12 = %d", hw_resource->macrotile_nv12_factor);
    217   DLOGI("\tTiled = %d", hw_resource->macrotile_factor);
    218   DLOGI("\tLinear = %d", hw_resource->linear_factor);
    219   DLOGI("\tScale = %d", hw_resource->scale_factor);
    220   DLOGI("\tFudge_factor = %d", hw_resource->extra_fudge_factor);
    221 
    222   if (hw_resource->separate_rotator || hw_resource->num_dma_pipe) {
    223     GetHWRotatorInfo(hw_resource);
    224   }
    225 
    226   if (hw_resource->has_dyn_bw_support) {
    227     DisplayError ret = GetDynamicBWLimits(hw_resource);
    228     if (ret != kErrorNone) {
    229       DLOGE("Failed to read dynamic band width info");
    230       return ret;
    231     }
    232 
    233     DLOGI("Has Support for multiple bw limits shown below");
    234     for (int index = 0; index < kBwModeMax; index++) {
    235       DLOGI("Mode-index=%d  total_bw_limit=%d and pipe_bw_limit=%d", index,
    236             hw_resource->dyn_bw_info.total_bw_limit[index],
    237             hw_resource->dyn_bw_info.pipe_bw_limit[index]);
    238     }
    239   }
    240 
    241   if (!hw_resource_) {
    242     hw_resource_ = new HWResourceInfo();
    243     *hw_resource_ = *hw_resource;
    244   }
    245 
    246   return kErrorNone;
    247 }
    248 
    249 void HWInfoDRM::GetSystemInfo(HWResourceInfo *hw_resource) {
    250   DRMCrtcInfo info;
    251   drm_mgr_intf_->GetCrtcInfo(0 /* system_info */, &info);
    252   hw_resource->is_src_split = info.has_src_split;
    253   hw_resource->has_qseed3 = (info.qseed_version == sde_drm::QSEEDVersion::V3);
    254   hw_resource->num_blending_stages = info.max_blend_stages;
    255   hw_resource->smart_dma_rev = (info.smart_dma_rev == sde_drm::SmartDMARevision::V2) ?
    256     SmartDMARevision::V2 : SmartDMARevision::V1;
    257 }
    258 
    259 void HWInfoDRM::GetHWPlanesInfo(HWResourceInfo *hw_resource) {
    260   DRMPlanesInfo planes;
    261   drm_mgr_intf_->GetPlanesInfo(&planes);
    262   for (auto &pipe_obj : planes) {
    263     HWPipeCaps pipe_caps;
    264     string name = {};
    265     switch (pipe_obj.second.type) {
    266       case DRMPlaneType::DMA:
    267         name = "DMA";
    268         pipe_caps.type = kPipeTypeDMA;
    269         if (!hw_resource->num_dma_pipe) {
    270           PopulateSupportedFmts(kHWDMAPipe, pipe_obj.second, hw_resource);
    271         }
    272         hw_resource->num_dma_pipe++;
    273         break;
    274       case DRMPlaneType::VIG:
    275         name = "VIG";
    276         pipe_caps.type = kPipeTypeVIG;
    277         if (!hw_resource->num_vig_pipe) {
    278           PopulatePipeCaps(pipe_obj.second, hw_resource);
    279           PopulateSupportedFmts(kHWVIGPipe, pipe_obj.second, hw_resource);
    280         }
    281         hw_resource->num_vig_pipe++;
    282         break;
    283       case DRMPlaneType::CURSOR:
    284         name = "CURSOR";
    285         pipe_caps.type = kPipeTypeCursor;
    286         if (!hw_resource->num_cursor_pipe) {
    287           PopulateSupportedFmts(kHWCursorPipe, pipe_obj.second, hw_resource);
    288           hw_resource->max_cursor_size = pipe_obj.second.max_linewidth;
    289         }
    290         hw_resource->num_cursor_pipe++;
    291         break;
    292       default:
    293         continue;  // Not adding any other pipe type
    294     }
    295     pipe_caps.id = pipe_obj.first;
    296     pipe_caps.master_pipe_id = pipe_obj.second.master_plane_id;
    297     DLOGI("Adding %s Pipe : Id %d", name.c_str(), pipe_obj.first);
    298     hw_resource->hw_pipes.push_back(std::move(pipe_caps));
    299   }
    300 }
    301 
    302 void HWInfoDRM::PopulatePipeCaps(const sde_drm::DRMPlaneTypeInfo &info,
    303                                     HWResourceInfo *hw_resource) {
    304   hw_resource->max_pipe_width = info.max_linewidth;
    305   hw_resource->max_scale_down = info.max_downscale;
    306   hw_resource->max_scale_up = info.max_upscale;
    307   hw_resource->has_decimation = info.max_horizontal_deci > 1 && info.max_vertical_deci > 1;
    308 }
    309 
    310 void HWInfoDRM::PopulateSupportedFmts(HWSubBlockType sub_blk_type,
    311                                       const sde_drm::DRMPlaneTypeInfo  &info,
    312                                       HWResourceInfo *hw_resource) {
    313   vector<LayerBufferFormat> sdm_formats;
    314   FormatsMap &fmts_map = hw_resource->supported_formats_map;
    315 
    316   if (fmts_map.find(sub_blk_type) == fmts_map.end()) {
    317     for (auto &fmts : info.formats_supported) {
    318       GetSDMFormat(fmts.first, fmts.second, &sdm_formats);
    319     }
    320 
    321     fmts_map.insert(make_pair(sub_blk_type, sdm_formats));
    322   }
    323 }
    324 
    325 void HWInfoDRM::GetWBInfo(HWResourceInfo *hw_resource) {
    326   HWSubBlockType sub_blk_type = kHWWBIntfOutput;
    327   vector<LayerBufferFormat> supported_sdm_formats;
    328   sde_drm::DRMDisplayToken token;
    329 
    330   // Fake register
    331   if (drm_mgr_intf_->RegisterDisplay(sde_drm::DRMDisplayType::VIRTUAL, &token)) {
    332     return;
    333   }
    334 
    335   sde_drm::DRMConnectorInfo connector_info;
    336   drm_mgr_intf_->GetConnectorInfo(token.conn_id, &connector_info);
    337   for (auto &fmts : connector_info.formats_supported) {
    338     GetSDMFormat(fmts.first, fmts.second, &supported_sdm_formats);
    339   }
    340 
    341   hw_resource->supported_formats_map.erase(sub_blk_type);
    342   hw_resource->supported_formats_map.insert(make_pair(sub_blk_type, supported_sdm_formats));
    343 
    344   drm_mgr_intf_->UnregisterDisplay(token);
    345 }
    346 
    347 void HWInfoDRM::GetSDMFormat(uint32_t v4l2_format, LayerBufferFormat *sdm_format) {
    348   switch (v4l2_format) {
    349     case SDE_PIX_FMT_ARGB_8888:         *sdm_format = kFormatARGB8888;                 break;
    350     case SDE_PIX_FMT_RGBA_8888:         *sdm_format = kFormatRGBA8888;                 break;
    351     case SDE_PIX_FMT_BGRA_8888:         *sdm_format = kFormatBGRA8888;                 break;
    352     case SDE_PIX_FMT_RGBX_8888:         *sdm_format = kFormatRGBX8888;                 break;
    353     case SDE_PIX_FMT_BGRX_8888:         *sdm_format = kFormatBGRX8888;                 break;
    354     case SDE_PIX_FMT_RGBA_5551:         *sdm_format = kFormatRGBA5551;                 break;
    355     case SDE_PIX_FMT_RGBA_4444:         *sdm_format = kFormatRGBA4444;                 break;
    356     case SDE_PIX_FMT_RGB_888:           *sdm_format = kFormatRGB888;                   break;
    357     case SDE_PIX_FMT_BGR_888:           *sdm_format = kFormatBGR888;                   break;
    358     case SDE_PIX_FMT_RGB_565:           *sdm_format = kFormatRGB565;                   break;
    359     case SDE_PIX_FMT_BGR_565:           *sdm_format = kFormatBGR565;                   break;
    360     case SDE_PIX_FMT_Y_CB_CR_H2V2:      *sdm_format = kFormatYCbCr420Planar;           break;
    361     case SDE_PIX_FMT_Y_CR_CB_H2V2:      *sdm_format = kFormatYCrCb420Planar;           break;
    362     case SDE_PIX_FMT_Y_CR_CB_GH2V2:     *sdm_format = kFormatYCrCb420PlanarStride16;   break;
    363     case SDE_PIX_FMT_Y_CBCR_H2V2:       *sdm_format = kFormatYCbCr420SemiPlanar;       break;
    364     case SDE_PIX_FMT_Y_CRCB_H2V2:       *sdm_format = kFormatYCrCb420SemiPlanar;       break;
    365     case SDE_PIX_FMT_Y_CBCR_H1V2:       *sdm_format = kFormatYCbCr422H1V2SemiPlanar;   break;
    366     case SDE_PIX_FMT_Y_CRCB_H1V2:       *sdm_format = kFormatYCrCb422H1V2SemiPlanar;   break;
    367     case SDE_PIX_FMT_Y_CBCR_H2V1:       *sdm_format = kFormatYCbCr422H2V1SemiPlanar;   break;
    368     case SDE_PIX_FMT_Y_CRCB_H2V1:       *sdm_format = kFormatYCrCb422H2V1SemiPlanar;   break;
    369     case SDE_PIX_FMT_YCBYCR_H2V1:       *sdm_format = kFormatYCbCr422H2V1Packed;       break;
    370     case SDE_PIX_FMT_Y_CBCR_H2V2_VENUS: *sdm_format = kFormatYCbCr420SemiPlanarVenus;  break;
    371     case SDE_PIX_FMT_Y_CRCB_H2V2_VENUS: *sdm_format = kFormatYCrCb420SemiPlanarVenus;  break;
    372     case SDE_PIX_FMT_RGBA_8888_UBWC:    *sdm_format = kFormatRGBA8888Ubwc;             break;
    373     case SDE_PIX_FMT_RGBX_8888_UBWC:    *sdm_format = kFormatRGBX8888Ubwc;             break;
    374     case SDE_PIX_FMT_RGB_565_UBWC:      *sdm_format = kFormatBGR565Ubwc;               break;
    375     case SDE_PIX_FMT_Y_CBCR_H2V2_UBWC:  *sdm_format = kFormatYCbCr420SPVenusUbwc;      break;
    376     case SDE_PIX_FMT_RGBA_1010102:      *sdm_format = kFormatRGBA1010102;              break;
    377     case SDE_PIX_FMT_ARGB_2101010:      *sdm_format = kFormatARGB2101010;              break;
    378     case SDE_PIX_FMT_RGBX_1010102:      *sdm_format = kFormatRGBX1010102;              break;
    379     case SDE_PIX_FMT_XRGB_2101010:      *sdm_format = kFormatXRGB2101010;              break;
    380     case SDE_PIX_FMT_BGRA_1010102:      *sdm_format = kFormatBGRA1010102;              break;
    381     case SDE_PIX_FMT_ABGR_2101010:      *sdm_format = kFormatABGR2101010;              break;
    382     case SDE_PIX_FMT_BGRX_1010102:      *sdm_format = kFormatBGRX1010102;              break;
    383     case SDE_PIX_FMT_XBGR_2101010:      *sdm_format = kFormatXBGR2101010;              break;
    384     case SDE_PIX_FMT_RGBA_1010102_UBWC: *sdm_format = kFormatRGBA1010102Ubwc;          break;
    385     case SDE_PIX_FMT_RGBX_1010102_UBWC: *sdm_format = kFormatRGBX1010102Ubwc;          break;
    386     case SDE_PIX_FMT_Y_CBCR_H2V2_P010:  *sdm_format = kFormatYCbCr420P010;             break;
    387     case SDE_PIX_FMT_Y_CBCR_H2V2_TP10_UBWC: *sdm_format = kFormatYCbCr420TP10Ubwc;     break;
    388     /* TODO(user) : enable when defined in uapi
    389       case SDE_PIX_FMT_Y_CBCR_H2V2_P010_UBWC: *sdm_format = kFormatYCbCr420P010Ubwc;     break; */
    390     default: *sdm_format = kFormatInvalid;
    391   }
    392 }
    393 
    394 void HWInfoDRM::GetRotatorFormatsForType(int fd, uint32_t type,
    395                                          vector<LayerBufferFormat> *supported_formats) {
    396   struct v4l2_fmtdesc fmtdesc = {};
    397   fmtdesc.type = type;
    398   while (!Sys::ioctl_(fd, static_cast<int>(VIDIOC_ENUM_FMT), &fmtdesc)) {
    399     LayerBufferFormat sdm_format = kFormatInvalid;
    400     GetSDMFormat(fmtdesc.pixelformat, &sdm_format);
    401     if (sdm_format != kFormatInvalid) {
    402       supported_formats->push_back(sdm_format);
    403     }
    404     fmtdesc.index++;
    405   }
    406 }
    407 
    408 DisplayError HWInfoDRM::GetRotatorSupportedFormats(uint32_t v4l2_index,
    409                                                    HWResourceInfo *hw_resource) {
    410   string path = "/dev/video" + to_string(v4l2_index);
    411   int fd = Sys::open_(path.c_str(), O_RDONLY);
    412   if (fd < 0) {
    413     DLOGE("Failed to open %s with error %d", path.c_str(), errno);
    414     return kErrorNotSupported;
    415   }
    416 
    417   vector<LayerBufferFormat> supported_formats = {};
    418   GetRotatorFormatsForType(fd, V4L2_BUF_TYPE_VIDEO_OUTPUT, &supported_formats);
    419   hw_resource->supported_formats_map.erase(kHWRotatorInput);
    420   hw_resource->supported_formats_map.insert(make_pair(kHWRotatorInput, supported_formats));
    421 
    422   supported_formats = {};
    423   GetRotatorFormatsForType(fd, V4L2_BUF_TYPE_VIDEO_CAPTURE, &supported_formats);
    424   hw_resource->supported_formats_map.erase(kHWRotatorOutput);
    425   hw_resource->supported_formats_map.insert(make_pair(kHWRotatorOutput, supported_formats));
    426 
    427   Sys::close_(fd);
    428 
    429   return kErrorNone;
    430 }
    431 
    432 DisplayError HWInfoDRM::GetHWRotatorInfo(HWResourceInfo *hw_resource) {
    433   string v4l2_path = "/sys/class/video4linux/video";
    434   const uint32_t kMaxV4L2Nodes = 64;
    435 
    436   for (uint32_t i = 0; i < kMaxV4L2Nodes; i++) {
    437     string path = v4l2_path + to_string(i) + "/name";
    438     Sys::fstream fs(path, fstream::in);
    439     if (!fs.is_open()) {
    440       continue;
    441     }
    442 
    443     string line;
    444     if (Sys::getline_(fs, line) && (!strncmp(line.c_str(), "sde_rotator", strlen("sde_rotator")))) {
    445       hw_resource->hw_rot_info.device_path = string("/dev/video" + to_string(i));
    446       hw_resource->hw_rot_info.num_rotator++;
    447       hw_resource->hw_rot_info.type = HWRotatorInfo::ROT_TYPE_V4L2;
    448       hw_resource->hw_rot_info.has_downscale = true;
    449       GetRotatorSupportedFormats(i, hw_resource);
    450 
    451       string caps_path = v4l2_path + to_string(i) + "/device/caps";
    452       Sys::fstream caps_fs(caps_path, fstream::in);
    453 
    454       if (caps_fs.is_open()) {
    455         string caps;
    456         while (Sys::getline_(caps_fs, caps)) {
    457           const string downscale_compression = "downscale_compression=";
    458           const string min_downscale = "min_downscale=";
    459           if (caps.find(downscale_compression) != string::npos) {
    460             hw_resource->hw_rot_info.downscale_compression =
    461               std::stoi(string(caps, downscale_compression.length()));
    462           } else if (caps.find(min_downscale) != string::npos) {
    463             hw_resource->hw_rot_info.min_downscale =
    464               std::stof(string(caps, min_downscale.length()));
    465           }
    466         }
    467       }
    468 
    469       // We support only 1 rotator
    470       break;
    471     }
    472   }
    473 
    474   DLOGI("V4L2 Rotator: Count = %d, Downscale = %d, Min_downscale = %f, Downscale_compression = %d",
    475         hw_resource->hw_rot_info.num_rotator, hw_resource->hw_rot_info.has_downscale,
    476         hw_resource->hw_rot_info.min_downscale, hw_resource->hw_rot_info.downscale_compression);
    477 
    478   return kErrorNone;
    479 }
    480 
    481 void HWInfoDRM::GetSDMFormat(uint32_t drm_format, uint64_t drm_format_modifier,
    482                              vector<LayerBufferFormat> *sdm_formats) {
    483   vector<LayerBufferFormat> &fmts(*sdm_formats);
    484   switch (drm_format) {
    485     case DRM_FORMAT_BGRA8888:
    486       fmts.push_back(kFormatARGB8888);
    487       break;
    488     case DRM_FORMAT_ABGR8888:
    489       fmts.push_back(drm_format_modifier ? kFormatRGBA8888Ubwc : kFormatRGBA8888);
    490       break;
    491     case DRM_FORMAT_ARGB8888:
    492       fmts.push_back(kFormatBGRA8888);
    493       break;
    494     case DRM_FORMAT_BGRX8888:
    495       fmts.push_back(kFormatXRGB8888);
    496       break;
    497     case DRM_FORMAT_XBGR8888:
    498       fmts.push_back(drm_format_modifier ? kFormatRGBX8888Ubwc : kFormatRGBX8888);
    499       break;
    500     case DRM_FORMAT_XRGB8888:
    501       fmts.push_back(kFormatBGRX8888);
    502       break;
    503     case DRM_FORMAT_ABGR1555:
    504       fmts.push_back(kFormatRGBA5551);
    505       break;
    506     case DRM_FORMAT_ABGR4444:
    507       fmts.push_back(kFormatRGBA4444);
    508       break;
    509     case DRM_FORMAT_BGR888:
    510       fmts.push_back(kFormatRGB888);
    511       break;
    512     case DRM_FORMAT_RGB888:
    513       fmts.push_back(kFormatBGR888);
    514       break;
    515     case DRM_FORMAT_BGR565:
    516       fmts.push_back(drm_format_modifier ? kFormatBGR565Ubwc : kFormatRGB565);
    517       break;
    518     case DRM_FORMAT_RGB565:
    519       fmts.push_back(kFormatBGR565);
    520       break;
    521     case DRM_FORMAT_ABGR2101010:
    522       fmts.push_back(drm_format_modifier ? kFormatRGBA1010102Ubwc : kFormatRGBA1010102);
    523       break;
    524     case DRM_FORMAT_BGRA1010102:
    525       fmts.push_back(kFormatARGB2101010);
    526       break;
    527     case DRM_FORMAT_XBGR2101010:
    528       fmts.push_back(drm_format_modifier ? kFormatRGBX1010102Ubwc : kFormatRGBX1010102);
    529       break;
    530     case DRM_FORMAT_BGRX1010102:
    531       fmts.push_back(kFormatXRGB2101010);
    532       break;
    533     case DRM_FORMAT_ARGB2101010:
    534       fmts.push_back(kFormatBGRA1010102);
    535       break;
    536     case DRM_FORMAT_RGBA1010102:
    537       fmts.push_back(kFormatABGR2101010);
    538       break;
    539     case DRM_FORMAT_XRGB2101010:
    540       fmts.push_back(kFormatBGRX1010102);
    541       break;
    542     case DRM_FORMAT_RGBX1010102:
    543       fmts.push_back(kFormatXBGR2101010);
    544       break;
    545     case DRM_FORMAT_YVU420:
    546       fmts.push_back(kFormatYCrCb420PlanarStride16);
    547       break;
    548     case DRM_FORMAT_NV12:
    549       if (drm_format_modifier == (DRM_FORMAT_MOD_QCOM_COMPRESSED |
    550           DRM_FORMAT_MOD_QCOM_DX | DRM_FORMAT_MOD_QCOM_TIGHT)) {
    551           fmts.push_back(kFormatYCbCr420TP10Ubwc);
    552       } else if (drm_format_modifier == (DRM_FORMAT_MOD_QCOM_COMPRESSED |
    553                                          DRM_FORMAT_MOD_QCOM_DX)) {
    554         fmts.push_back(kFormatYCbCr420P010Ubwc);
    555       } else if (drm_format_modifier == DRM_FORMAT_MOD_QCOM_COMPRESSED) {
    556          fmts.push_back(kFormatYCbCr420SPVenusUbwc);
    557       } else if (drm_format_modifier == DRM_FORMAT_MOD_QCOM_DX) {
    558          fmts.push_back(kFormatYCbCr420P010);
    559       } else {
    560          fmts.push_back(kFormatYCbCr420SemiPlanarVenus);
    561          fmts.push_back(kFormatYCbCr420SemiPlanar);
    562       }
    563       break;
    564     case DRM_FORMAT_NV21:
    565       fmts.push_back(kFormatYCrCb420SemiPlanarVenus);
    566       fmts.push_back(kFormatYCrCb420SemiPlanar);
    567       break;
    568     case DRM_FORMAT_NV16:
    569       fmts.push_back(kFormatYCbCr422H2V1SemiPlanar);
    570       break;
    571     default:
    572       break;
    573   }
    574 }
    575 
    576 DisplayError HWInfoDRM::GetFirstDisplayInterfaceType(HWDisplayInterfaceInfo *hw_disp_info) {
    577   hw_disp_info->type = kPrimary;
    578   hw_disp_info->is_connected = true;
    579 
    580   return kErrorNone;
    581 }
    582 
    583 }  // namespace sdm
    584