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(tag, 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(tag, "%s", buf);
     94 
     95   void Error(const char *format, ...) { PRINTLOG(kTagNone, Error, format, buf_); }
     96   void Warning(const char *format, ...) { PRINTLOG(kTagDriverConfig, Warning, format, buf_); }
     97   void Info(const char *format, ...) { PRINTLOG(kTagDriverConfig, Info, format, buf_); }
     98   void Debug(const char *format, ...) { PRINTLOG(kTagDriverConfig, Debug, format, buf_); }
     99   void Verbose(const char *format, ...) { PRINTLOG(kTagDriverConfig, Verbose, format, buf_); }
    100 
    101  private:
    102   char buf_[1024] = {};
    103 };
    104 
    105 HWResourceInfo *HWInfoDRM::hw_resource_ = nullptr;
    106 
    107 HWInfoDRM::HWInfoDRM() {
    108   DRMLogger::Set(new DRMLoggerImpl());
    109   drm_lib = DRMLibLoader::GetInstance();
    110   if (drm_lib == nullptr) {
    111     DLOGE("Failed to load DRM Library");
    112     return;
    113   }
    114   default_mode_ = (drm_lib->IsLoaded() == false);
    115   if (!default_mode_) {
    116     DRMMaster *drm_master = {};
    117     int dev_fd = -1;
    118     DRMMaster::GetInstance(&drm_master);
    119     if (!drm_master) {
    120       DLOGE("Failed to acquire DRMMaster instance");
    121       return;
    122     }
    123     drm_master->GetHandle(&dev_fd);
    124     drm_lib->FuncGetDRMManager()(dev_fd, &drm_mgr_intf_);
    125   }
    126 }
    127 
    128 HWInfoDRM::~HWInfoDRM() {
    129   if (hw_resource_ != nullptr) {
    130     delete hw_resource_;
    131     hw_resource_ = nullptr;
    132   }
    133 
    134   if (drm_mgr_intf_) {
    135     if (drm_lib != nullptr) {
    136       drm_lib->FuncDestroyDRMManager()();
    137     }
    138     drm_mgr_intf_ = nullptr;
    139   }
    140 
    141   drm_lib->Destroy();
    142   drm_lib = nullptr;
    143   DRMMaster::DestroyInstance();
    144 }
    145 
    146 DisplayError HWInfoDRM::GetDynamicBWLimits(HWResourceInfo *hw_resource) {
    147   HWDynBwLimitInfo* bw_info = &hw_resource->dyn_bw_info;
    148   for (int index = 0; index < kBwModeMax; index++) {
    149     bw_info->total_bw_limit[index] = UINT32(hw_resource->max_bandwidth_low);
    150     bw_info->pipe_bw_limit[index] = hw_resource->max_pipe_bw;
    151   }
    152 
    153   return kErrorNone;
    154 }
    155 
    156 DisplayError HWInfoDRM::GetHWResourceInfo(HWResourceInfo *hw_resource) {
    157   if (hw_resource_) {
    158     *hw_resource = *hw_resource_;
    159     return kErrorNone;
    160   }
    161 
    162   hw_resource->num_blending_stages = 1;
    163   hw_resource->max_pipe_width = 2560;
    164   hw_resource->max_cursor_size = 128;
    165   hw_resource->max_scale_down = 1;
    166   hw_resource->max_scale_up = 1;
    167   hw_resource->has_decimation = false;
    168   hw_resource->max_bandwidth_low = 9600000;
    169   hw_resource->max_bandwidth_high = 9600000;
    170   hw_resource->max_pipe_bw = 4500000;
    171   hw_resource->max_sde_clk = 412500000;
    172   hw_resource->clk_fudge_factor = FLOAT(105) / FLOAT(100);
    173   hw_resource->macrotile_nv12_factor = 8;
    174   hw_resource->macrotile_factor = 4;
    175   hw_resource->linear_factor = 1;
    176   hw_resource->scale_factor = 1;
    177   hw_resource->extra_fudge_factor = 2;
    178   hw_resource->amortizable_threshold = 0;
    179   hw_resource->system_overhead_lines = 0;
    180   hw_resource->hw_dest_scalar_info.count = 0;
    181   hw_resource->hw_dest_scalar_info.max_scale_up = 0;
    182   hw_resource->hw_dest_scalar_info.max_input_width = 0;
    183   hw_resource->hw_dest_scalar_info.max_output_width = 0;
    184   hw_resource->is_src_split = true;
    185   hw_resource->perf_calc = false;
    186   hw_resource->has_dyn_bw_support = false;
    187   hw_resource->has_qseed3 = false;
    188   hw_resource->has_concurrent_writeback = false;
    189 
    190   // TODO(user): Deprecate
    191   hw_resource->hw_version = kHWMdssVersion5;
    192   hw_resource->hw_revision = 0;
    193   hw_resource->max_mixer_width = 0;
    194   hw_resource->writeback_index = 0;
    195   hw_resource->has_bwc = false;
    196   hw_resource->has_ubwc = true;
    197   hw_resource->has_macrotile = true;
    198   hw_resource->separate_rotator = true;
    199   hw_resource->has_non_scalar_rgb = false;
    200 
    201   GetSystemInfo(hw_resource);
    202   GetHWPlanesInfo(hw_resource);
    203   GetWBInfo(hw_resource);
    204 
    205   // Disable destination scalar count to 0 if extension library is not present
    206   DynLib extension_lib;
    207   if (!extension_lib.Open("libsdmextension.so")) {
    208     hw_resource->hw_dest_scalar_info.count = 0;
    209   }
    210 
    211   DLOGI("Max plane width = %d", hw_resource->max_pipe_width);
    212   DLOGI("Max cursor width = %d", hw_resource->max_cursor_size);
    213   DLOGI("Max plane upscale = %d", hw_resource->max_scale_up);
    214   DLOGI("Max plane downscale = %d", hw_resource->max_scale_down);
    215   DLOGI("Has Decimation = %d", hw_resource->has_decimation);
    216   DLOGI("Max Blending Stages = %d", hw_resource->num_blending_stages);
    217   DLOGI("Has Source Split = %d", hw_resource->is_src_split);
    218   DLOGI("Has QSEED3 = %d", hw_resource->has_qseed3);
    219   DLOGI("Has UBWC = %d", hw_resource->has_ubwc);
    220   DLOGI("Has Concurrent Writeback = %d", hw_resource->has_concurrent_writeback);
    221   DLOGI("Max Low Bw = %" PRIu64 "", hw_resource->max_bandwidth_low);
    222   DLOGI("Max High Bw = % " PRIu64 "", hw_resource->max_bandwidth_high);
    223   DLOGI("Max Pipe Bw = %" PRIu64 " KBps", hw_resource->max_pipe_bw);
    224   DLOGI("MaxSDEClock = % " PRIu64 " Hz", hw_resource->max_sde_clk);
    225   DLOGI("Clock Fudge Factor = %f", hw_resource->clk_fudge_factor);
    226   DLOGI("Prefill factors:");
    227   DLOGI("\tTiled_NV12 = %d", hw_resource->macrotile_nv12_factor);
    228   DLOGI("\tTiled = %d", hw_resource->macrotile_factor);
    229   DLOGI("\tLinear = %d", hw_resource->linear_factor);
    230   DLOGI("\tScale = %d", hw_resource->scale_factor);
    231   DLOGI("\tFudge_factor = %d", hw_resource->extra_fudge_factor);
    232 
    233   if (hw_resource->separate_rotator || hw_resource->num_dma_pipe) {
    234     GetHWRotatorInfo(hw_resource);
    235   }
    236 
    237   if (hw_resource->has_dyn_bw_support) {
    238     DisplayError ret = GetDynamicBWLimits(hw_resource);
    239     if (ret != kErrorNone) {
    240       DLOGE("Failed to read dynamic band width info");
    241       return ret;
    242     }
    243 
    244     DLOGI("Has Support for multiple bw limits shown below");
    245     for (int index = 0; index < kBwModeMax; index++) {
    246       DLOGI("Mode-index=%d  total_bw_limit=%d and pipe_bw_limit=%d", index,
    247             hw_resource->dyn_bw_info.total_bw_limit[index],
    248             hw_resource->dyn_bw_info.pipe_bw_limit[index]);
    249     }
    250   }
    251 
    252   if (!hw_resource_) {
    253     hw_resource_ = new HWResourceInfo();
    254     *hw_resource_ = *hw_resource;
    255   }
    256 
    257   return kErrorNone;
    258 }
    259 
    260 void HWInfoDRM::GetSystemInfo(HWResourceInfo *hw_resource) {
    261   DRMCrtcInfo info;
    262   drm_mgr_intf_->GetCrtcInfo(0 /* system_info */, &info);
    263   hw_resource->is_src_split = info.has_src_split;
    264   hw_resource->has_qseed3 = (info.qseed_version == sde_drm::QSEEDVersion::V3);
    265   hw_resource->num_blending_stages = info.max_blend_stages;
    266   hw_resource->smart_dma_rev = (info.smart_dma_rev == sde_drm::SmartDMARevision::V2) ?
    267     SmartDMARevision::V2 : SmartDMARevision::V1;
    268 }
    269 
    270 void HWInfoDRM::GetHWPlanesInfo(HWResourceInfo *hw_resource) {
    271   DRMPlanesInfo planes;
    272   drm_mgr_intf_->GetPlanesInfo(&planes);
    273   for (auto &pipe_obj : planes) {
    274     HWPipeCaps pipe_caps;
    275     string name = {};
    276     switch (pipe_obj.second.type) {
    277       case DRMPlaneType::DMA:
    278         name = "DMA";
    279         pipe_caps.type = kPipeTypeDMA;
    280         if (!hw_resource->num_dma_pipe) {
    281           PopulateSupportedFmts(kHWDMAPipe, pipe_obj.second, hw_resource);
    282         }
    283         hw_resource->num_dma_pipe++;
    284         break;
    285       case DRMPlaneType::VIG:
    286         name = "VIG";
    287         pipe_caps.type = kPipeTypeVIG;
    288         if (!hw_resource->num_vig_pipe) {
    289           PopulatePipeCaps(pipe_obj.second, hw_resource);
    290           PopulateSupportedFmts(kHWVIGPipe, pipe_obj.second, hw_resource);
    291         }
    292         hw_resource->num_vig_pipe++;
    293         break;
    294       case DRMPlaneType::CURSOR:
    295         name = "CURSOR";
    296         pipe_caps.type = kPipeTypeCursor;
    297         if (!hw_resource->num_cursor_pipe) {
    298           PopulateSupportedFmts(kHWCursorPipe, pipe_obj.second, hw_resource);
    299           hw_resource->max_cursor_size = pipe_obj.second.max_linewidth;
    300         }
    301         hw_resource->num_cursor_pipe++;
    302         break;
    303       default:
    304         continue;  // Not adding any other pipe type
    305     }
    306     pipe_caps.id = pipe_obj.first;
    307     pipe_caps.master_pipe_id = pipe_obj.second.master_plane_id;
    308     DLOGI("Adding %s Pipe : Id %d", name.c_str(), pipe_obj.first);
    309     hw_resource->hw_pipes.push_back(std::move(pipe_caps));
    310   }
    311 }
    312 
    313 void HWInfoDRM::PopulatePipeCaps(const sde_drm::DRMPlaneTypeInfo &info,
    314                                     HWResourceInfo *hw_resource) {
    315   hw_resource->max_pipe_width = info.max_linewidth;
    316   hw_resource->max_scale_down = info.max_downscale;
    317   hw_resource->max_scale_up = info.max_upscale;
    318   hw_resource->has_decimation = info.max_horizontal_deci > 1 && info.max_vertical_deci > 1;
    319 }
    320 
    321 void HWInfoDRM::PopulateSupportedFmts(HWSubBlockType sub_blk_type,
    322                                       const sde_drm::DRMPlaneTypeInfo  &info,
    323                                       HWResourceInfo *hw_resource) {
    324   vector<LayerBufferFormat> sdm_formats;
    325   FormatsMap &fmts_map = hw_resource->supported_formats_map;
    326 
    327   if (fmts_map.find(sub_blk_type) == fmts_map.end()) {
    328     for (auto &fmts : info.formats_supported) {
    329       GetSDMFormat(fmts.first, fmts.second, &sdm_formats);
    330     }
    331 
    332     fmts_map.insert(make_pair(sub_blk_type, sdm_formats));
    333   }
    334 }
    335 
    336 void HWInfoDRM::GetWBInfo(HWResourceInfo *hw_resource) {
    337   HWSubBlockType sub_blk_type = kHWWBIntfOutput;
    338   vector<LayerBufferFormat> supported_sdm_formats;
    339   sde_drm::DRMDisplayToken token;
    340 
    341   // Fake register
    342   if (drm_mgr_intf_->RegisterDisplay(sde_drm::DRMDisplayType::VIRTUAL, &token)) {
    343     return;
    344   }
    345 
    346   sde_drm::DRMConnectorInfo connector_info;
    347   drm_mgr_intf_->GetConnectorInfo(token.conn_id, &connector_info);
    348   for (auto &fmts : connector_info.formats_supported) {
    349     GetSDMFormat(fmts.first, fmts.second, &supported_sdm_formats);
    350   }
    351 
    352   hw_resource->supported_formats_map.erase(sub_blk_type);
    353   hw_resource->supported_formats_map.insert(make_pair(sub_blk_type, supported_sdm_formats));
    354 
    355   drm_mgr_intf_->UnregisterDisplay(token);
    356 }
    357 
    358 void HWInfoDRM::GetSDMFormat(uint32_t v4l2_format, LayerBufferFormat *sdm_format) {
    359   switch (v4l2_format) {
    360     case SDE_PIX_FMT_ARGB_8888:         *sdm_format = kFormatARGB8888;                 break;
    361     case SDE_PIX_FMT_RGBA_8888:         *sdm_format = kFormatRGBA8888;                 break;
    362     case SDE_PIX_FMT_BGRA_8888:         *sdm_format = kFormatBGRA8888;                 break;
    363     case SDE_PIX_FMT_RGBX_8888:         *sdm_format = kFormatRGBX8888;                 break;
    364     case SDE_PIX_FMT_BGRX_8888:         *sdm_format = kFormatBGRX8888;                 break;
    365     case SDE_PIX_FMT_RGBA_5551:         *sdm_format = kFormatRGBA5551;                 break;
    366     case SDE_PIX_FMT_RGBA_4444:         *sdm_format = kFormatRGBA4444;                 break;
    367     case SDE_PIX_FMT_RGB_888:           *sdm_format = kFormatRGB888;                   break;
    368     case SDE_PIX_FMT_BGR_888:           *sdm_format = kFormatBGR888;                   break;
    369     case SDE_PIX_FMT_RGB_565:           *sdm_format = kFormatRGB565;                   break;
    370     case SDE_PIX_FMT_BGR_565:           *sdm_format = kFormatBGR565;                   break;
    371     case SDE_PIX_FMT_Y_CB_CR_H2V2:      *sdm_format = kFormatYCbCr420Planar;           break;
    372     case SDE_PIX_FMT_Y_CR_CB_H2V2:      *sdm_format = kFormatYCrCb420Planar;           break;
    373     case SDE_PIX_FMT_Y_CR_CB_GH2V2:     *sdm_format = kFormatYCrCb420PlanarStride16;   break;
    374     case SDE_PIX_FMT_Y_CBCR_H2V2:       *sdm_format = kFormatYCbCr420SemiPlanar;       break;
    375     case SDE_PIX_FMT_Y_CRCB_H2V2:       *sdm_format = kFormatYCrCb420SemiPlanar;       break;
    376     case SDE_PIX_FMT_Y_CBCR_H1V2:       *sdm_format = kFormatYCbCr422H1V2SemiPlanar;   break;
    377     case SDE_PIX_FMT_Y_CRCB_H1V2:       *sdm_format = kFormatYCrCb422H1V2SemiPlanar;   break;
    378     case SDE_PIX_FMT_Y_CBCR_H2V1:       *sdm_format = kFormatYCbCr422H2V1SemiPlanar;   break;
    379     case SDE_PIX_FMT_Y_CRCB_H2V1:       *sdm_format = kFormatYCrCb422H2V1SemiPlanar;   break;
    380     case SDE_PIX_FMT_YCBYCR_H2V1:       *sdm_format = kFormatYCbCr422H2V1Packed;       break;
    381     case SDE_PIX_FMT_Y_CBCR_H2V2_VENUS: *sdm_format = kFormatYCbCr420SemiPlanarVenus;  break;
    382     case SDE_PIX_FMT_Y_CRCB_H2V2_VENUS: *sdm_format = kFormatYCrCb420SemiPlanarVenus;  break;
    383     case SDE_PIX_FMT_RGBA_8888_UBWC:    *sdm_format = kFormatRGBA8888Ubwc;             break;
    384     case SDE_PIX_FMT_RGBX_8888_UBWC:    *sdm_format = kFormatRGBX8888Ubwc;             break;
    385     case SDE_PIX_FMT_RGB_565_UBWC:      *sdm_format = kFormatBGR565Ubwc;               break;
    386     case SDE_PIX_FMT_Y_CBCR_H2V2_UBWC:  *sdm_format = kFormatYCbCr420SPVenusUbwc;      break;
    387     case SDE_PIX_FMT_RGBA_1010102:      *sdm_format = kFormatRGBA1010102;              break;
    388     case SDE_PIX_FMT_ARGB_2101010:      *sdm_format = kFormatARGB2101010;              break;
    389     case SDE_PIX_FMT_RGBX_1010102:      *sdm_format = kFormatRGBX1010102;              break;
    390     case SDE_PIX_FMT_XRGB_2101010:      *sdm_format = kFormatXRGB2101010;              break;
    391     case SDE_PIX_FMT_BGRA_1010102:      *sdm_format = kFormatBGRA1010102;              break;
    392     case SDE_PIX_FMT_ABGR_2101010:      *sdm_format = kFormatABGR2101010;              break;
    393     case SDE_PIX_FMT_BGRX_1010102:      *sdm_format = kFormatBGRX1010102;              break;
    394     case SDE_PIX_FMT_XBGR_2101010:      *sdm_format = kFormatXBGR2101010;              break;
    395     case SDE_PIX_FMT_RGBA_1010102_UBWC: *sdm_format = kFormatRGBA1010102Ubwc;          break;
    396     case SDE_PIX_FMT_RGBX_1010102_UBWC: *sdm_format = kFormatRGBX1010102Ubwc;          break;
    397     case SDE_PIX_FMT_Y_CBCR_H2V2_P010:  *sdm_format = kFormatYCbCr420P010;             break;
    398     case SDE_PIX_FMT_Y_CBCR_H2V2_TP10_UBWC: *sdm_format = kFormatYCbCr420TP10Ubwc;     break;
    399     /* TODO(user) : enable when defined in uapi
    400       case SDE_PIX_FMT_Y_CBCR_H2V2_P010_UBWC: *sdm_format = kFormatYCbCr420P010Ubwc;     break; */
    401     default: *sdm_format = kFormatInvalid;
    402   }
    403 }
    404 
    405 void HWInfoDRM::GetRotatorFormatsForType(int fd, uint32_t type,
    406                                          vector<LayerBufferFormat> *supported_formats) {
    407   struct v4l2_fmtdesc fmtdesc = {};
    408   fmtdesc.type = type;
    409   while (!Sys::ioctl_(fd, static_cast<int>(VIDIOC_ENUM_FMT), &fmtdesc)) {
    410     LayerBufferFormat sdm_format = kFormatInvalid;
    411     GetSDMFormat(fmtdesc.pixelformat, &sdm_format);
    412     if (sdm_format != kFormatInvalid) {
    413       supported_formats->push_back(sdm_format);
    414     }
    415     fmtdesc.index++;
    416   }
    417 }
    418 
    419 DisplayError HWInfoDRM::GetRotatorSupportedFormats(uint32_t v4l2_index,
    420                                                    HWResourceInfo *hw_resource) {
    421   string path = "/dev/video" + to_string(v4l2_index);
    422   int fd = Sys::open_(path.c_str(), O_RDONLY);
    423   if (fd < 0) {
    424     DLOGE("Failed to open %s with error %d", path.c_str(), errno);
    425     return kErrorNotSupported;
    426   }
    427 
    428   vector<LayerBufferFormat> supported_formats = {};
    429   GetRotatorFormatsForType(fd, V4L2_BUF_TYPE_VIDEO_OUTPUT, &supported_formats);
    430   hw_resource->supported_formats_map.erase(kHWRotatorInput);
    431   hw_resource->supported_formats_map.insert(make_pair(kHWRotatorInput, supported_formats));
    432 
    433   supported_formats = {};
    434   GetRotatorFormatsForType(fd, V4L2_BUF_TYPE_VIDEO_CAPTURE, &supported_formats);
    435   hw_resource->supported_formats_map.erase(kHWRotatorOutput);
    436   hw_resource->supported_formats_map.insert(make_pair(kHWRotatorOutput, supported_formats));
    437 
    438   Sys::close_(fd);
    439 
    440   return kErrorNone;
    441 }
    442 
    443 DisplayError HWInfoDRM::GetHWRotatorInfo(HWResourceInfo *hw_resource) {
    444   string v4l2_path = "/sys/class/video4linux/video";
    445   const uint32_t kMaxV4L2Nodes = 64;
    446 
    447   for (uint32_t i = 0; i < kMaxV4L2Nodes; i++) {
    448     string path = v4l2_path + to_string(i) + "/name";
    449     Sys::fstream fs(path, fstream::in);
    450     if (!fs.is_open()) {
    451       continue;
    452     }
    453 
    454     string line;
    455     if (Sys::getline_(fs, line) && (!strncmp(line.c_str(), "sde_rotator", strlen("sde_rotator")))) {
    456       hw_resource->hw_rot_info.device_path = string("/dev/video" + to_string(i));
    457       hw_resource->hw_rot_info.num_rotator++;
    458       hw_resource->hw_rot_info.type = HWRotatorInfo::ROT_TYPE_V4L2;
    459       hw_resource->hw_rot_info.has_downscale = true;
    460       GetRotatorSupportedFormats(i, hw_resource);
    461 
    462       string caps_path = v4l2_path + to_string(i) + "/device/caps";
    463       Sys::fstream caps_fs(caps_path, fstream::in);
    464 
    465       if (caps_fs.is_open()) {
    466         string caps;
    467         while (Sys::getline_(caps_fs, caps)) {
    468           const string downscale_compression = "downscale_compression=";
    469           const string min_downscale = "min_downscale=";
    470           if (caps.find(downscale_compression) != string::npos) {
    471             hw_resource->hw_rot_info.downscale_compression =
    472               std::stoi(string(caps, downscale_compression.length()));
    473           } else if (caps.find(min_downscale) != string::npos) {
    474             hw_resource->hw_rot_info.min_downscale =
    475               std::stof(string(caps, min_downscale.length()));
    476           }
    477         }
    478       }
    479 
    480       // We support only 1 rotator
    481       break;
    482     }
    483   }
    484 
    485   DLOGI("V4L2 Rotator: Count = %d, Downscale = %d, Min_downscale = %f, Downscale_compression = %d",
    486         hw_resource->hw_rot_info.num_rotator, hw_resource->hw_rot_info.has_downscale,
    487         hw_resource->hw_rot_info.min_downscale, hw_resource->hw_rot_info.downscale_compression);
    488 
    489   return kErrorNone;
    490 }
    491 
    492 void HWInfoDRM::GetSDMFormat(uint32_t drm_format, uint64_t drm_format_modifier,
    493                              vector<LayerBufferFormat> *sdm_formats) {
    494   vector<LayerBufferFormat> &fmts(*sdm_formats);
    495   switch (drm_format) {
    496     case DRM_FORMAT_BGRA8888:
    497       fmts.push_back(kFormatARGB8888);
    498       break;
    499     case DRM_FORMAT_ABGR8888:
    500       fmts.push_back(drm_format_modifier ? kFormatRGBA8888Ubwc : kFormatRGBA8888);
    501       break;
    502     case DRM_FORMAT_ARGB8888:
    503       fmts.push_back(kFormatBGRA8888);
    504       break;
    505     case DRM_FORMAT_BGRX8888:
    506       fmts.push_back(kFormatXRGB8888);
    507       break;
    508     case DRM_FORMAT_XBGR8888:
    509       fmts.push_back(drm_format_modifier ? kFormatRGBX8888Ubwc : kFormatRGBX8888);
    510       break;
    511     case DRM_FORMAT_XRGB8888:
    512       fmts.push_back(kFormatBGRX8888);
    513       break;
    514     case DRM_FORMAT_ABGR1555:
    515       fmts.push_back(kFormatRGBA5551);
    516       break;
    517     case DRM_FORMAT_ABGR4444:
    518       fmts.push_back(kFormatRGBA4444);
    519       break;
    520     case DRM_FORMAT_BGR888:
    521       fmts.push_back(kFormatRGB888);
    522       break;
    523     case DRM_FORMAT_RGB888:
    524       fmts.push_back(kFormatBGR888);
    525       break;
    526     case DRM_FORMAT_BGR565:
    527       fmts.push_back(drm_format_modifier ? kFormatBGR565Ubwc : kFormatRGB565);
    528       break;
    529     case DRM_FORMAT_RGB565:
    530       fmts.push_back(kFormatBGR565);
    531       break;
    532     case DRM_FORMAT_ABGR2101010:
    533       fmts.push_back(drm_format_modifier ? kFormatRGBA1010102Ubwc : kFormatRGBA1010102);
    534       break;
    535     case DRM_FORMAT_BGRA1010102:
    536       fmts.push_back(kFormatARGB2101010);
    537       break;
    538     case DRM_FORMAT_XBGR2101010:
    539       fmts.push_back(drm_format_modifier ? kFormatRGBX1010102Ubwc : kFormatRGBX1010102);
    540       break;
    541     case DRM_FORMAT_BGRX1010102:
    542       fmts.push_back(kFormatXRGB2101010);
    543       break;
    544     case DRM_FORMAT_ARGB2101010:
    545       fmts.push_back(kFormatBGRA1010102);
    546       break;
    547     case DRM_FORMAT_RGBA1010102:
    548       fmts.push_back(kFormatABGR2101010);
    549       break;
    550     case DRM_FORMAT_XRGB2101010:
    551       fmts.push_back(kFormatBGRX1010102);
    552       break;
    553     case DRM_FORMAT_RGBX1010102:
    554       fmts.push_back(kFormatXBGR2101010);
    555       break;
    556     case DRM_FORMAT_YVU420:
    557       fmts.push_back(kFormatYCrCb420PlanarStride16);
    558       break;
    559     case DRM_FORMAT_NV12:
    560       if (drm_format_modifier == (DRM_FORMAT_MOD_QCOM_COMPRESSED |
    561           DRM_FORMAT_MOD_QCOM_DX | DRM_FORMAT_MOD_QCOM_TIGHT)) {
    562           fmts.push_back(kFormatYCbCr420TP10Ubwc);
    563       } else if (drm_format_modifier == (DRM_FORMAT_MOD_QCOM_COMPRESSED |
    564                                          DRM_FORMAT_MOD_QCOM_DX)) {
    565         fmts.push_back(kFormatYCbCr420P010Ubwc);
    566       } else if (drm_format_modifier == DRM_FORMAT_MOD_QCOM_COMPRESSED) {
    567          fmts.push_back(kFormatYCbCr420SPVenusUbwc);
    568       } else if (drm_format_modifier == DRM_FORMAT_MOD_QCOM_DX) {
    569          fmts.push_back(kFormatYCbCr420P010);
    570       } else {
    571          fmts.push_back(kFormatYCbCr420SemiPlanarVenus);
    572          fmts.push_back(kFormatYCbCr420SemiPlanar);
    573       }
    574       break;
    575     case DRM_FORMAT_NV21:
    576       fmts.push_back(kFormatYCrCb420SemiPlanarVenus);
    577       fmts.push_back(kFormatYCrCb420SemiPlanar);
    578       break;
    579     case DRM_FORMAT_NV16:
    580       fmts.push_back(kFormatYCbCr422H2V1SemiPlanar);
    581       break;
    582     default:
    583       break;
    584   }
    585 }
    586 
    587 DisplayError HWInfoDRM::GetFirstDisplayInterfaceType(HWDisplayInterfaceInfo *hw_disp_info) {
    588   hw_disp_info->type = kPrimary;
    589   hw_disp_info->is_connected = true;
    590 
    591   return kErrorNone;
    592 }
    593 
    594 }  // namespace sdm
    595