hwc: Add support for HDMI as Primary display

We are adding support for HDMI as Primary to the display HAL.
The HAL must be able to support boot-up use cases and cable
connect/disconnect events as follows:

1. Boot up with HDMI cable connected

   For this scenario we read the best mode supported by the
   HDMI TV and set that as the current and default mode for
   subsequent boot up.

2. Boot up without HDMI cable connected

   We read a default resolution from the driver by reading vscreen
   and reporting this as the display resolution to SF.

3. Switch the display to active state when we receive first frame

   When HDMI is primary we should rely on the first valid
   draw call in order to activate the display

4. Update handling of uevents when HDMI is primary

   a) Do not send hot plug when the cable is connected/disconnected.
   b) Use the correct display ID in uevents when HDMI is primary

5. Handle display timeout when HDMI is Primary

   When HDMI is connected as primary we clean up resources
   and call commit to generate a black frame on the interface.
   However, we do not call blank since we need the timing
   generator and HDMI core to remain turned on.

6. Clear pipe resource when HDMI is disconnected

   When HDMI is primary, we need to make sure that SF/HWC does
   not have any open fd's when the cable is disconnected.

   We clear all pipe resources and call a display commit to ensure
   that all the fd's are closed. This will ensure that the HDMI
   core turns off and that we receive an event the next time the
   cable is connected.

Change-Id: Ice70add583a3859f99bfa2e384fbbb6df4df92e1
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index 288b2e0..b5ba073 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -249,7 +249,23 @@
     const int dpy = HWC_DISPLAY_PRIMARY;
     bool fbComp = false;
     if (LIKELY(list && list->numHwLayers > 1) &&
-            ctx->dpyAttr[dpy].isActive) {
+            (ctx->dpyAttr[dpy].isActive ||
+             ctx->mHDMIDisplay->isHDMIPrimaryDisplay())) {
+
+        // When HDMI is primary we should rely on the first valid
+        // draw call in order to activate the display
+        if (!ctx->dpyAttr[dpy].isActive) {
+            // If the cable is connected after HWC initialization and before
+            // the UEvent thread is initialized then we will miss the ONLINE
+            // event. We need to update the display appropriately when we get
+            // the first valid frame.
+            int cableConnected = ctx->mHDMIDisplay->getConnectedState();
+            if ((cableConnected == 1) && !ctx->dpyAttr[dpy].connected) {
+                qhwc::handle_online(ctx, dpy);
+            }
+            ctx->mHDMIDisplay->activateDisplay();
+            ctx->dpyAttr[dpy].isActive = true;
+        }
 
         if (ctx->dpyAttr[dpy].customFBSize &&
                 list->flags & HWC_GEOMETRY_CHANGED)
@@ -433,19 +449,33 @@
 
     switch(dpy) {
     case HWC_DISPLAY_PRIMARY:
-        if(ioctl(ctx->dpyAttr[dpy].fd, FBIOBLANK, value) < 0 ) {
-            ALOGE("%s: ioctl FBIOBLANK failed for Primary with error %s"
-                    " value %d", __FUNCTION__, strerror(errno), value);
-            return -errno;
-        }
+        if(ctx->mHDMIDisplay->isHDMIPrimaryDisplay()) {
+            if(ctx->dpyAttr[dpy].connected) {
+                // When HDMI is connected as primary we clean up resources
+                // and call commit to generate a black frame on the interface.
+                // However, we do not call blank since we need the timing
+                // generator and HDMI core to remain turned on.
+                if((mode == HWC_POWER_MODE_OFF) &&
+                        (!Overlay::displayCommit(ctx->dpyAttr[dpy].fd))) {
+                    ALOGE("%s: display commit fail for %d", __FUNCTION__, dpy);
+                    ret = -1;
+                }
+            }
+        } else {
+            if(ioctl(ctx->dpyAttr[dpy].fd, FBIOBLANK, value) < 0 ) {
+                ALOGE("%s: ioctl FBIOBLANK failed for Primary with error %s"
+                        " value %d", __FUNCTION__, strerror(errno), value);
+                return -errno;
+            }
 
-        if(mode == HWC_POWER_MODE_NORMAL) {
-            // Enable HPD here, as during bootup POWER_MODE_NORMAL is set
-            // when SF is completely initialized
-            ctx->mHDMIDisplay->setHPD(1);
-        }
+            if(mode == HWC_POWER_MODE_NORMAL) {
+                // Enable HPD here, as during bootup POWER_MODE_NORMAL is set
+                // when SF is completely initialized
+                ctx->mHDMIDisplay->setHPD(1);
+            }
 
-        ctx->dpyAttr[dpy].isActive = not(mode == HWC_POWER_MODE_OFF);
+            ctx->dpyAttr[dpy].isActive = not(mode == HWC_POWER_MODE_OFF);
+        }
         //Deliberate fall through since there is no explicit power mode for
         //virtual displays.
     case HWC_DISPLAY_VIRTUAL: