Merge "drm : Add secondary/external display support"
diff --git a/sdm/libs/core/Android.mk b/sdm/libs/core/Android.mk
index c5002a9..991cfac 100644
--- a/sdm/libs/core/Android.mk
+++ b/sdm/libs/core/Android.mk
@@ -49,6 +49,7 @@
 ifneq ($(TARGET_IS_HEADLESS), true)
     LOCAL_SRC_FILES           += $(LOCAL_HW_INTF_PATH_2)/hw_info_drm.cpp \
                                  $(LOCAL_HW_INTF_PATH_2)/hw_device_drm.cpp \
+                                 $(LOCAL_HW_INTF_PATH_2)/hw_hdmi_drm.cpp \
                                  $(LOCAL_HW_INTF_PATH_2)/hw_events_drm.cpp \
                                  $(LOCAL_HW_INTF_PATH_2)/hw_scale_drm.cpp \
                                  $(LOCAL_HW_INTF_PATH_2)/hw_virtual_drm.cpp \
diff --git a/sdm/libs/core/drm/hw_device_drm.h b/sdm/libs/core/drm/hw_device_drm.h
index 2199426..1c4f517 100644
--- a/sdm/libs/core/drm/hw_device_drm.h
+++ b/sdm/libs/core/drm/hw_device_drm.h
@@ -151,6 +151,7 @@
  protected:
   const char *device_name_ = {};
   bool deferred_initialize_ = false;
+  bool default_mode_ = false;
   sde_drm::DRMDisplayType disp_type_ = {};
   HWInfoInterface *hw_info_intf_ = {};
   BufferSyncHandler *buffer_sync_handler_ = {};
@@ -169,7 +170,6 @@
  private:
   bool synchronous_commit_ = false;
   HWMixerAttributes mixer_attributes_ = {};
-  bool default_mode_ = false;
   std::string interface_str_ = "DSI";
   HWScaleDRM *hw_scale_ = {};
 };
diff --git a/sdm/libs/core/drm/hw_hdmi_drm.cpp b/sdm/libs/core/drm/hw_hdmi_drm.cpp
new file mode 100644
index 0000000..27419c7
--- /dev/null
+++ b/sdm/libs/core/drm/hw_hdmi_drm.cpp
@@ -0,0 +1,163 @@
+/*
+* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above
+*       copyright notice, this list of conditions and the following
+*       disclaimer in the documentation and/or other materials provided
+*       with the distribution.
+*     * Neither the name of The Linux Foundation nor the names of its
+*       contributors may be used to endorse or promote products derived
+*       from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <drm_lib_loader.h>
+#include <drm_master.h>
+#include <drm_res_mgr.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <utils/debug.h>
+#include <utils/sys.h>
+#include <utils/formats.h>
+
+#include <vector>
+#include <map>
+#include <utility>
+
+#include "hw_hdmi_drm.h"
+
+#define __CLASS__ "HWHDMIDRM"
+
+using drm_utils::DRMMaster;
+using drm_utils::DRMResMgr;
+using drm_utils::DRMLibLoader;
+using drm_utils::DRMBuffer;
+using sde_drm::GetDRMManager;
+using sde_drm::DestroyDRMManager;
+using sde_drm::DRMDisplayType;
+using sde_drm::DRMDisplayToken;
+using sde_drm::DRMConnectorInfo;
+using sde_drm::DRMPPFeatureInfo;
+using sde_drm::DRMOps;
+using sde_drm::DRMTopology;
+
+namespace sdm {
+
+HWHDMIDRM::HWHDMIDRM(BufferSyncHandler *buffer_sync_handler, BufferAllocator *buffer_allocator,
+                     HWInfoInterface *hw_info_intf)
+  : HWDeviceDRM(buffer_sync_handler, buffer_allocator, hw_info_intf),
+  active_config_index_(0) {
+  HWDeviceDRM::device_type_ = kDeviceHDMI;
+  HWDeviceDRM::device_name_ = "HDMI Display Device";
+}
+
+// TODO(user) : split function in base class and avoid code duplicacy
+// by using base implementation for this basic stuff
+DisplayError HWHDMIDRM::Init() {
+  DisplayError error = kErrorNone;
+
+  default_mode_ = (DRMLibLoader::GetInstance()->IsLoaded() == false);
+
+  if (!default_mode_) {
+    DRMMaster *drm_master = {};
+    int dev_fd = -1;
+    DRMMaster::GetInstance(&drm_master);
+    drm_master->GetHandle(&dev_fd);
+    DRMLibLoader::GetInstance()->FuncGetDRMManager()(dev_fd, &drm_mgr_intf_);
+    if (drm_mgr_intf_->RegisterDisplay(DRMDisplayType::TV, &token_)) {
+      DLOGE("RegisterDisplay failed");
+      return kErrorResources;
+    }
+
+    drm_mgr_intf_->CreateAtomicReq(token_, &drm_atomic_intf_);
+    drm_mgr_intf_->GetConnectorInfo(token_.conn_id, &connector_info_);
+    InitializeConfigs();
+    drm_atomic_intf_->Perform(DRMOps::CRTC_SET_MODE, token_.crtc_id, &current_mode_);
+    drm_atomic_intf_->Perform(DRMOps::CRTC_SET_ACTIVE, token_.crtc_id, 1);
+
+    if (drm_atomic_intf_->Commit(true /* synchronous */)) {
+      DLOGE("Setting up CRTC %d, Connector %d for %s failed", token_.crtc_id, token_.conn_id,
+            device_name_);
+      return kErrorResources;
+    }
+
+    // Reload connector info for updated info after 1st commit
+    drm_mgr_intf_->GetConnectorInfo(token_.conn_id, &connector_info_);
+    DLOGI("Setup CRTC %d, Connector %d for %s", token_.crtc_id, token_.conn_id, device_name_);
+  }
+
+  PopulateDisplayAttributes();
+  PopulateHWPanelInfo();
+  UpdateMixerAttributes();
+
+  return error;
+}
+
+DisplayError HWHDMIDRM::GetNumDisplayAttributes(uint32_t *count) {
+  *count = connector_info_.num_modes;
+  if (*count <= 0) {
+    return kErrorHardware;
+  }
+
+  return kErrorNone;
+}
+
+DisplayError HWHDMIDRM::GetActiveConfig(uint32_t *active_config_index) {
+  *active_config_index = active_config_index_;
+  return kErrorNone;
+}
+
+DisplayError HWHDMIDRM::SetDisplayAttributes(uint32_t index) {
+  DTRACE_SCOPED();
+
+  if (index >= connector_info_.num_modes) {
+    return kErrorNotSupported;
+  }
+
+  active_config_index_ = index;
+
+  // TODO(user): fix this hard coding
+  frame_rate_ = 60;
+
+  // Get the display attributes for current active config index
+  GetDisplayAttributes(active_config_index_, &display_attributes_);
+  UpdateMixerAttributes();
+
+  return kErrorNone;
+}
+
+DisplayError HWHDMIDRM::GetConfigIndex(uint32_t mode, uint32_t *index) {
+  *index = mode;
+
+  return kErrorNone;
+}
+
+DisplayError HWHDMIDRM::Validate(HWLayers *hw_layers) {
+  HWDeviceDRM::ResetDisplayParams();
+
+  return HWDeviceDRM::Validate(hw_layers);
+}
+
+DisplayError HWHDMIDRM::Commit(HWLayers *hw_layers) {
+  return HWDeviceDRM::Commit(hw_layers);
+}
+
+}  // namespace sdm
+
diff --git a/sdm/libs/core/drm/hw_hdmi_drm.h b/sdm/libs/core/drm/hw_hdmi_drm.h
new file mode 100644
index 0000000..7e11e5e
--- /dev/null
+++ b/sdm/libs/core/drm/hw_hdmi_drm.h
@@ -0,0 +1,60 @@
+/*
+* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without modification, are permitted
+* provided that the following conditions are met:
+*    * Redistributions of source code must retain the above copyright notice, this list of
+*      conditions and the following disclaimer.
+*    * Redistributions in binary form must reproduce the above copyright notice, this list of
+*      conditions and the following disclaimer in the documentation and/or other materials provided
+*      with the distribution.
+*    * Neither the name of The Linux Foundation nor the names of its contributors may be used to
+*      endorse or promote products derived from this software without specific prior written
+*      permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __HW_HDMI_DRM_H__
+#define __HW_HDMI_DRM_H__
+
+#include <map>
+#include <vector>
+
+#include "hw_device_drm.h"
+
+namespace sdm {
+
+using std::vector;
+
+class HWHDMIDRM : public HWDeviceDRM {
+ public:
+  explicit HWHDMIDRM(BufferSyncHandler *buffer_sync_handler, BufferAllocator *buffer_allocator,
+                     HWInfoInterface *hw_info_intf);
+
+ protected:
+  virtual DisplayError Init();
+  virtual DisplayError GetNumDisplayAttributes(uint32_t *count);
+  // Requirement to call this only after the first config has been explicitly set by client
+  virtual DisplayError GetActiveConfig(uint32_t *active_config);
+  virtual DisplayError SetDisplayAttributes(uint32_t index);
+  virtual DisplayError GetConfigIndex(uint32_t mode, uint32_t *index);
+  virtual DisplayError Validate(HWLayers *hw_layers);
+  virtual DisplayError Commit(HWLayers *hw_layers);
+
+ private:
+  uint32_t active_config_index_;
+  uint32_t frame_rate_ = 0;
+};
+
+}  // namespace sdm
+
+#endif  // __HW_HDMI_DRM_H__
+
diff --git a/sdm/libs/core/hw_interface.cpp b/sdm/libs/core/hw_interface.cpp
index a7bcabd..f05aa0c 100644
--- a/sdm/libs/core/hw_interface.cpp
+++ b/sdm/libs/core/hw_interface.cpp
@@ -38,6 +38,7 @@
 #ifdef COMPILE_DRM
 #include "drm/hw_device_drm.h"
 #include "drm/hw_virtual_drm.h"
+#include "drm/hw_hdmi_drm.h"
 #endif
 
 #define __CLASS__ "HWInterface"
@@ -65,7 +66,9 @@
       if (driver_type == DriverType::FB) {
         hw = new HWHDMI(buffer_sync_handler, hw_info_intf);
       } else {
-        return kErrorNotSupported;
+#ifdef COMPILE_DRM
+        hw = new HWHDMIDRM(buffer_sync_handler, buffer_allocator, hw_info_intf);
+#endif
       }
       break;
     case kVirtual:
diff --git a/sdm/libs/hwc2/hwc_session.cpp b/sdm/libs/hwc2/hwc_session.cpp
index 2bf7d4d..7b68eb8 100644
--- a/sdm/libs/hwc2/hwc_session.cpp
+++ b/sdm/libs/hwc2/hwc_session.cpp
@@ -47,6 +47,7 @@
 
 #define HWC_UEVENT_SWITCH_HDMI "change@/devices/virtual/switch/hdmi"
 #define HWC_UEVENT_GRAPHICS_FB0 "change@/devices/virtual/graphics/fb0"
+#define HWC_UEVENT_DRM_EXT_HOTPLUG "mdss_mdp/drm/card"
 
 static sdm::HWCSession::HWCModuleMethods g_hwc_module_methods;
 
@@ -1453,6 +1454,8 @@
         callbacks_.Refresh(0);
         reset_panel_ = true;
       }
+    } else if (strcasestr(uevent_data, HWC_UEVENT_DRM_EXT_HOTPLUG)) {
+      HandleExtHPD(uevent_data, length);
     }
   }
   pthread_exit(0);
@@ -1460,6 +1463,29 @@
   return NULL;
 }
 
+void HWCSession::HandleExtHPD(const char *uevent_data, int length) {
+  const char *iterator_str = uevent_data;
+  const char *event_info = "status=";
+  const char *pstr = NULL;
+  while (((iterator_str - uevent_data) <= length) && (*iterator_str)) {
+    pstr = strstr(iterator_str, event_info);
+    if (pstr != NULL) {
+      break;
+    }
+    iterator_str += strlen(iterator_str) + 1;
+  }
+
+  if (pstr) {
+    bool connected = false;
+    if (strcmp(pstr+strlen(event_info), "connected") == 0) {
+      connected = true;
+    }
+
+    DLOGI("Recived Ext HPD, connected:%d  status=%s", connected, pstr+strlen(event_info));
+    HotPlugHandler(connected);
+  }
+}
+
 int HWCSession::GetEventValue(const char *uevent_data, int length, const char *event_info) {
   const char *iterator_str = uevent_data;
   while (((iterator_str - uevent_data) <= length) && (*iterator_str)) {
diff --git a/sdm/libs/hwc2/hwc_session.h b/sdm/libs/hwc2/hwc_session.h
index 7d31a3a..c4c38a5 100644
--- a/sdm/libs/hwc2/hwc_session.h
+++ b/sdm/libs/hwc2/hwc_session.h
@@ -119,6 +119,7 @@
   static void *HWCUeventThread(void *context);
   void *HWCUeventThreadHandler();
   int GetEventValue(const char *uevent_data, int length, const char *event_info);
+  void HandleExtHPD(const char *uevent_data, int length);
   int HotPlugHandler(bool connected);
   void ResetPanel();
   int32_t ConnectDisplay(int disp);