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 <stdio.h>
     37 #include <stdlib.h>
     38 #include <string.h>
     39 #include <sys/stat.h>
     40 #include <sys/types.h>
     41 #include <utils/constants.h>
     42 #include <utils/debug.h>
     43 #include <utils/sys.h>
     44 
     45 #include <algorithm>
     46 #include <fstream>
     47 #include <iostream>
     48 #include <map>
     49 #include <memory>
     50 #include <string>
     51 #include <utility>
     52 #include <vector>
     53 
     54 #include "hw_info_drm.h"
     55 
     56 #define __CLASS__ "HWInfoDRM"
     57 
     58 using drm_utils::DRMMaster;
     59 using drm_utils::DRMResMgr;
     60 using drm_utils::DRMLogger;
     61 using drm_utils::DRMLibLoader;
     62 using sde_drm::GetDRMManager;
     63 using sde_drm::DRMPlanesInfo;
     64 using sde_drm::DRMCrtcInfo;
     65 using sde_drm::DRMPlaneType;
     66 
     67 using std::vector;
     68 using std::map;
     69 using std::string;
     70 using std::fstream;
     71 using std::to_string;
     72 
     73 namespace sdm {
     74 
     75 class DRMLoggerImpl : public DRMLogger {
     76  public:
     77 #define PRINTLOG(method, format, buf)        \
     78   va_list list;                              \
     79   va_start(list, format);                    \
     80   vsnprintf(buf, sizeof(buf), format, list); \
     81   va_end(list);                              \
     82   Debug::Get()->method(kTagNone, "%s", buf);
     83 
     84   void Error(const char *format, ...) { PRINTLOG(Error, format, buf_); }
     85   void Warning(const char *format, ...) { PRINTLOG(Warning, format, buf_); }
     86   void Info(const char *format, ...) { PRINTLOG(Info, format, buf_); }
     87   void Debug(const char *format, ...) { PRINTLOG(Debug, format, buf_); }
     88 
     89  private:
     90   char buf_[1024] = {};
     91 };
     92 
     93 HWResourceInfo *HWInfoDRM::hw_resource_ = nullptr;
     94 
     95 HWInfoDRM::HWInfoDRM() {
     96   DRMLogger::Set(new DRMLoggerImpl());
     97   default_mode_ = (DRMLibLoader::GetInstance()->IsLoaded() == false);
     98   if (!default_mode_) {
     99     DRMMaster *drm_master = {};
    100     int dev_fd = -1;
    101     DRMMaster::GetInstance(&drm_master);
    102     if (!drm_master) {
    103       DLOGE("Failed to acquire DRMMaster instance");
    104       return;
    105     }
    106     drm_master->GetHandle(&dev_fd);
    107     DRMLibLoader::GetInstance()->FuncGetDRMManager()(dev_fd, &drm_mgr_intf_);
    108   }
    109 }
    110 
    111 HWInfoDRM::~HWInfoDRM() {
    112   delete hw_resource_;
    113   hw_resource_ = nullptr;
    114 
    115   if (drm_mgr_intf_) {
    116     DRMLibLoader::GetInstance()->FuncDestroyDRMManager()();
    117     drm_mgr_intf_ = nullptr;
    118   }
    119 }
    120 
    121 DisplayError HWInfoDRM::GetDynamicBWLimits(HWResourceInfo *hw_resource) {
    122   HWDynBwLimitInfo* bw_info = &hw_resource->dyn_bw_info;
    123   for (int index = 0; index < kBwModeMax; index++) {
    124     bw_info->total_bw_limit[index] = UINT32(hw_resource->max_bandwidth_low);
    125     bw_info->pipe_bw_limit[index] = hw_resource->max_pipe_bw;
    126   }
    127 
    128   return kErrorNone;
    129 }
    130 
    131 DisplayError HWInfoDRM::GetHWResourceInfo(HWResourceInfo *hw_resource) {
    132   if (hw_resource_) {
    133     *hw_resource = *hw_resource_;
    134     return kErrorNone;
    135   }
    136 
    137   hw_resource->num_blending_stages = 1;
    138   hw_resource->max_pipe_width = 2560;
    139   hw_resource->max_cursor_size = 128;
    140   hw_resource->max_scale_down = 1;
    141   hw_resource->max_scale_up = 1;
    142   hw_resource->has_decimation = false;
    143   hw_resource->max_bandwidth_low = 9600000;
    144   hw_resource->max_bandwidth_high = 9600000;
    145   hw_resource->max_pipe_bw = 4500000;
    146   hw_resource->max_sde_clk = 412500000;
    147   hw_resource->clk_fudge_factor = FLOAT(105) / FLOAT(100);
    148   hw_resource->macrotile_nv12_factor = 8;
    149   hw_resource->macrotile_factor = 4;
    150   hw_resource->linear_factor = 1;
    151   hw_resource->scale_factor = 1;
    152   hw_resource->extra_fudge_factor = 2;
    153   hw_resource->amortizable_threshold = 0;
    154   hw_resource->system_overhead_lines = 0;
    155   hw_resource->hw_dest_scalar_info.count = 0;
    156   hw_resource->hw_dest_scalar_info.max_scale_up = 0;
    157   hw_resource->hw_dest_scalar_info.max_input_width = 0;
    158   hw_resource->hw_dest_scalar_info.max_output_width = 0;
    159   hw_resource->is_src_split = true;
    160   hw_resource->perf_calc = false;
    161   hw_resource->has_dyn_bw_support = false;
    162   hw_resource->has_qseed3 = false;
    163   hw_resource->has_concurrent_writeback = false;
    164 
    165   // TODO(user): Deprecate
    166   hw_resource->hw_version = kHWMdssVersion5;
    167   hw_resource->hw_revision = 0;
    168   hw_resource->max_mixer_width = 0;
    169   hw_resource->writeback_index = 0;
    170   hw_resource->has_bwc = false;
    171   hw_resource->has_ubwc = true;
    172   hw_resource->has_macrotile = true;
    173   hw_resource->separate_rotator = true;
    174   hw_resource->has_non_scalar_rgb = false;
    175 
    176   GetSystemInfo(hw_resource);
    177   GetHWPlanesInfo(hw_resource);
    178   GetWBInfo(hw_resource);
    179 
    180   // Disable destination scalar count to 0 if extension library is not present
    181   DynLib extension_lib;
    182   if (!extension_lib.Open("libsdmextension.so")) {
    183     hw_resource->hw_dest_scalar_info.count = 0;
    184   }
    185 
    186   DLOGI("Max plane width = %d", hw_resource->max_pipe_width);
    187   DLOGI("Max cursor width = %d", hw_resource->max_cursor_size);
    188   DLOGI("Max plane upscale = %d", hw_resource->max_scale_up);
    189   DLOGI("Max plane downscale = %d", hw_resource->max_scale_down);
    190   DLOGI("Has Decimation = %d", hw_resource->has_decimation);
    191   DLOGI("Max Blending Stages = %d", hw_resource->num_blending_stages);
    192   DLOGI("Has Source Split = %d", hw_resource->is_src_split);
    193   DLOGI("Has QSEED3 = %d", hw_resource->has_qseed3);
    194   DLOGI("Has UBWC = %d", hw_resource->has_ubwc);
    195   DLOGI("Has Concurrent Writeback = %d", hw_resource->has_concurrent_writeback);
    196   DLOGI("Max Low Bw = %" PRIu64 "", hw_resource->max_bandwidth_low);
    197   DLOGI("Max High Bw = % " PRIu64 "", hw_resource->max_bandwidth_high);
    198   DLOGI("Max Pipe Bw = %" PRIu64 " KBps", hw_resource->max_pipe_bw);
    199   DLOGI("MaxSDEClock = % " PRIu64 " Hz", hw_resource->max_sde_clk);
    200   DLOGI("Clock Fudge Factor = %f", hw_resource->clk_fudge_factor);
    201   DLOGI("Prefill factors:");
    202   DLOGI("\tTiled_NV12 = %d", hw_resource->macrotile_nv12_factor);
    203   DLOGI("\tTiled = %d", hw_resource->macrotile_factor);
    204   DLOGI("\tLinear = %d", hw_resource->linear_factor);
    205   DLOGI("\tScale = %d", hw_resource->scale_factor);
    206   DLOGI("\tFudge_factor = %d", hw_resource->extra_fudge_factor);
    207 
    208   if (hw_resource->separate_rotator || hw_resource->num_dma_pipe) {
    209     GetHWRotatorInfo(hw_resource);
    210   }
    211 
    212   if (hw_resource->has_dyn_bw_support) {
    213     DisplayError ret = GetDynamicBWLimits(hw_resource);
    214     if (ret != kErrorNone) {
    215       DLOGE("Failed to read dynamic band width info");
    216       return ret;
    217     }
    218 
    219     DLOGI("Has Support for multiple bw limits shown below");
    220     for (int index = 0; index < kBwModeMax; index++) {
    221       DLOGI("Mode-index=%d  total_bw_limit=%d and pipe_bw_limit=%d", index,
    222             hw_resource->dyn_bw_info.total_bw_limit[index],
    223             hw_resource->dyn_bw_info.pipe_bw_limit[index]);
    224     }
    225   }
    226 
    227   if (!hw_resource_) {
    228     hw_resource_ = new HWResourceInfo();
    229     *hw_resource_ = *hw_resource;
    230   }
    231 
    232   return kErrorNone;
    233 }
    234 
    235 void HWInfoDRM::GetSystemInfo(HWResourceInfo *hw_resource) {
    236   DRMCrtcInfo info;
    237   drm_mgr_intf_->GetCrtcInfo(0 /* system_info */, &info);
    238   hw_resource->is_src_split = info.has_src_split;
    239   hw_resource->has_qseed3 = (info.qseed_version == sde_drm::QSEEDVersion::V3);
    240   hw_resource->num_blending_stages = info.max_blend_stages;
    241 }
    242 
    243 void HWInfoDRM::GetHWPlanesInfo(HWResourceInfo *hw_resource) {
    244   DRMPlanesInfo info;
    245   drm_mgr_intf_->GetPlanesInfo(&info);
    246   for (auto &pipe_obj : info.planes) {
    247     HWPipeCaps pipe_caps;
    248     string name = {};
    249     switch (pipe_obj.second) {
    250       case DRMPlaneType::RGB:
    251         pipe_caps.type = kPipeTypeRGB;
    252         hw_resource->num_rgb_pipe++;
    253         name = "RGB";
    254         break;
    255       case DRMPlaneType::VIG:
    256         pipe_caps.type = kPipeTypeVIG;
    257         hw_resource->num_vig_pipe++;
    258         name = "VIG";
    259         break;
    260       case DRMPlaneType::DMA:
    261         pipe_caps.type = kPipeTypeDMA;
    262         hw_resource->num_dma_pipe++;
    263         name = "DMA";
    264         break;
    265       case DRMPlaneType::CURSOR:
    266         pipe_caps.type = kPipeTypeCursor;
    267         hw_resource->num_cursor_pipe++;
    268         name = "CURSOR";
    269         break;
    270       default:
    271         break;
    272     }
    273     pipe_caps.id = pipe_obj.first;
    274     pipe_caps.max_rects = 1;
    275     DLOGI("%s Pipe : Id %d", name.c_str(), pipe_obj.first);
    276     hw_resource->hw_pipes.push_back(std::move(pipe_caps));
    277   }
    278 
    279   for (auto &pipe_type : info.types) {
    280     vector<LayerBufferFormat> supported_sdm_formats = {};
    281     for (auto &fmts : pipe_type.second.formats_supported) {
    282       GetSDMFormat(fmts.first, fmts.second, &supported_sdm_formats);
    283     }
    284 
    285     HWSubBlockType sub_blk_type = kHWSubBlockMax;
    286     switch (pipe_type.first) {
    287       case DRMPlaneType::RGB:
    288         sub_blk_type = kHWRGBPipe;
    289         // These properties are per plane but modeled in SDM as system-wide.
    290         hw_resource->max_pipe_width = pipe_type.second.max_linewidth;
    291         hw_resource->max_scale_down = pipe_type.second.max_downscale;
    292         hw_resource->max_scale_up = pipe_type.second.max_upscale;
    293         hw_resource->has_decimation =
    294             pipe_type.second.max_horizontal_deci > 1 && pipe_type.second.max_vertical_deci > 1;
    295         break;
    296       case DRMPlaneType::VIG:
    297         sub_blk_type = kHWVIGPipe;
    298         // These properties are per plane but modeled in SDM as system-wide.
    299         hw_resource->max_pipe_width = pipe_type.second.max_linewidth;
    300         hw_resource->max_scale_down = pipe_type.second.max_downscale;
    301         hw_resource->max_scale_up = pipe_type.second.max_upscale;
    302         hw_resource->has_decimation =
    303             pipe_type.second.max_horizontal_deci > 1 && pipe_type.second.max_vertical_deci > 1;
    304         break;
    305       case DRMPlaneType::DMA:
    306         sub_blk_type = kHWDMAPipe;
    307         break;
    308       case DRMPlaneType::CURSOR:
    309         sub_blk_type = kHWCursorPipe;
    310         hw_resource->max_cursor_size = pipe_type.second.max_linewidth;
    311         break;
    312       default:
    313         break;
    314     }
    315 
    316     if (sub_blk_type != kHWSubBlockMax) {
    317       hw_resource->supported_formats_map.erase(sub_blk_type);
    318       hw_resource->supported_formats_map.insert(make_pair(sub_blk_type, supported_sdm_formats));
    319     }
    320   }
    321 }
    322 
    323 void HWInfoDRM::GetWBInfo(HWResourceInfo *hw_resource) {
    324   HWSubBlockType sub_blk_type = kHWWBIntfOutput;
    325   vector<LayerBufferFormat> supported_sdm_formats = {};
    326   sde_drm::DRMDisplayToken token;
    327 
    328   // Fake register
    329   if (drm_mgr_intf_->RegisterDisplay(sde_drm::DRMDisplayType::VIRTUAL, &token)) {
    330     return;
    331   }
    332 
    333   sde_drm::DRMConnectorInfo connector_info;
    334   drm_mgr_intf_->GetConnectorInfo(token.conn_id, &connector_info);
    335   for (auto &fmts : connector_info.formats_supported) {
    336     GetSDMFormat(fmts.first, fmts.second, &supported_sdm_formats);
    337   }
    338 
    339   hw_resource->supported_formats_map.erase(sub_blk_type);
    340   hw_resource->supported_formats_map.insert(make_pair(sub_blk_type, supported_sdm_formats));
    341 
    342   drm_mgr_intf_->UnregisterDisplay(token);
    343 }
    344 
    345 DisplayError HWInfoDRM::GetHWRotatorInfo(HWResourceInfo *hw_resource) {
    346   const uint32_t kMaxV4L2Nodes = 64;
    347   bool found = false;
    348 
    349   for (uint32_t i = 0; (i < kMaxV4L2Nodes) && (false == found); i++) {
    350     string path = "/sys/class/video4linux/video" + to_string(i) + "/name";
    351     Sys::fstream fs(path, fstream::in);
    352     if (!fs.is_open()) {
    353       continue;
    354     }
    355 
    356     string line;
    357     if (Sys::getline_(fs, line) && (!strncmp(line.c_str(), "sde_rotator", strlen("sde_rotator")))) {
    358       hw_resource->hw_rot_info.device_path = string("/dev/video" + to_string(i));
    359       hw_resource->hw_rot_info.num_rotator++;
    360       hw_resource->hw_rot_info.type = HWRotatorInfo::ROT_TYPE_V4L2;
    361       hw_resource->hw_rot_info.has_downscale = true;
    362       // We support only 1 rotator
    363       found = true;
    364     }
    365   }
    366 
    367   DLOGI("V4L2 Rotator: Count = %d, Downscale = %d", hw_resource->hw_rot_info.num_rotator,
    368         hw_resource->hw_rot_info.has_downscale);
    369 
    370   return kErrorNone;
    371 }
    372 
    373 void HWInfoDRM::GetSDMFormat(uint32_t drm_format, uint64_t drm_format_modifier,
    374                              vector<LayerBufferFormat> *sdm_formats) {
    375   vector<LayerBufferFormat> &fmts(*sdm_formats);
    376   switch (drm_format) {
    377     case DRM_FORMAT_ARGB8888:
    378       fmts.push_back(kFormatARGB8888);
    379       break;
    380     case DRM_FORMAT_RGBA8888:
    381       fmts.push_back(drm_format_modifier ? kFormatRGBA8888Ubwc : kFormatRGBA8888);
    382       break;
    383     case DRM_FORMAT_BGRA8888:
    384       fmts.push_back(kFormatBGRA8888);
    385       break;
    386     case DRM_FORMAT_XRGB8888:
    387       fmts.push_back(kFormatXRGB8888);
    388       break;
    389     case DRM_FORMAT_RGBX8888:
    390       fmts.push_back(drm_format_modifier ? kFormatRGBX8888Ubwc : kFormatRGBX8888);
    391       break;
    392     case DRM_FORMAT_BGRX8888:
    393       fmts.push_back(kFormatBGRX8888);
    394       break;
    395     case DRM_FORMAT_RGBA5551:
    396       fmts.push_back(kFormatRGBA5551);
    397       break;
    398     case DRM_FORMAT_RGBA4444:
    399       fmts.push_back(kFormatRGBA4444);
    400       break;
    401     case DRM_FORMAT_RGB888:
    402       fmts.push_back(kFormatRGB888);
    403       break;
    404     case DRM_FORMAT_BGR888:
    405       fmts.push_back(kFormatBGR888);
    406       break;
    407     case DRM_FORMAT_RGB565:
    408       fmts.push_back(drm_format_modifier ? kFormatBGR565Ubwc : kFormatBGR565);
    409       break;
    410     case DRM_FORMAT_BGR565:
    411       fmts.push_back(kFormatBGR565);
    412       break;
    413     case DRM_FORMAT_RGBA1010102:
    414       fmts.push_back(drm_format_modifier ? kFormatRGBA1010102Ubwc : kFormatRGBA1010102);
    415       break;
    416     case DRM_FORMAT_ARGB2101010:
    417       fmts.push_back(kFormatARGB2101010);
    418       break;
    419     case DRM_FORMAT_RGBX1010102:
    420       fmts.push_back(drm_format_modifier ? kFormatRGBX1010102Ubwc : kFormatRGBX1010102);
    421       break;
    422     case DRM_FORMAT_XRGB2101010:
    423       fmts.push_back(kFormatXRGB2101010);
    424       break;
    425     case DRM_FORMAT_BGRA1010102:
    426       fmts.push_back(kFormatBGRA1010102);
    427       break;
    428     case DRM_FORMAT_ABGR2101010:
    429       fmts.push_back(kFormatABGR2101010);
    430       break;
    431     case DRM_FORMAT_BGRX1010102:
    432       fmts.push_back(kFormatBGRX1010102);
    433       break;
    434     case DRM_FORMAT_XBGR2101010:
    435       fmts.push_back(kFormatXBGR2101010);
    436       break;
    437     /* case DRM_FORMAT_P010:
    438          fmts.push_back(drm_format_modifier == (DRM_FORMAT_MOD_QCOM_COMPRESSED |
    439        DRM_FORMAT_MOD_QCOM_TIGHT) ?
    440          kFormatYCbCr420TP10Ubwc : kFormatYCbCr420P010; */
    441     case DRM_FORMAT_YVU420:
    442       fmts.push_back(kFormatYCrCb420PlanarStride16);
    443       break;
    444     case DRM_FORMAT_NV12:
    445       if (drm_format_modifier) {
    446         fmts.push_back(kFormatYCbCr420SPVenusUbwc);
    447       } else {
    448         fmts.push_back(kFormatYCbCr420SemiPlanarVenus);
    449         fmts.push_back(kFormatYCbCr420SemiPlanar);
    450       }
    451       break;
    452     case DRM_FORMAT_NV21:
    453       fmts.push_back(kFormatYCrCb420SemiPlanarVenus);
    454       fmts.push_back(kFormatYCrCb420SemiPlanar);
    455       break;
    456     case DRM_FORMAT_NV16:
    457       fmts.push_back(kFormatYCbCr422H2V1SemiPlanar);
    458       break;
    459     default:
    460       break;
    461   }
    462 }
    463 
    464 DisplayError HWInfoDRM::GetFirstDisplayInterfaceType(HWDisplayInterfaceInfo *hw_disp_info) {
    465   hw_disp_info->type = kPrimary;
    466   hw_disp_info->is_connected = true;
    467 
    468   return kErrorNone;
    469 }
    470 
    471 }  // namespace sdm
    472