hdmitx: add auto low latency mode(ALLM) [1/1]
authorZongdong Jiao <zongdong.jiao@amlogic.com>
Mon, 18 Feb 2019 09:33:22 +0000 (04:33 -0500)
committerJianxin Pan <jianxin.pan@amlogic.com>
Thu, 21 Feb 2019 05:07:52 +0000 (21:07 -0800)
PD#SWPL-4705

Problem:
Lack ALLM function

Solution:
Add ALLM function

Verify:
GXL/P212
If Rx supports ALLM, then
echo 1 > /sys/class/amhdmitx/amhdmitx0/allm_mode
otherwise it will set failed, cat allm_mode and will get 0.

Change-Id: I00233e5a5aac133b405590e7df78c7c4805ed0ef
Signed-off-by: Zongdong Jiao <zongdong.jiao@amlogic.com>
drivers/amlogic/media/vout/hdmitx/hdmi_common/hdmi_parameters.c
drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hdmi_tx_edid.c
drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hdmi_tx_main.c
drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hdmi_tx_video.c
drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hw/hdmi_tx_hw.c
include/linux/amlogic/media/vout/hdmi_tx/hdmi_common.h
include/linux/amlogic/media/vout/hdmi_tx/hdmi_tx_module.h

index 286bd91..81bf931 100644 (file)
@@ -3428,3 +3428,22 @@ unsigned int hdmi_get_csc_coef(
        return 1;
 }
 
+bool is_hdmi14_4k(enum hdmi_vic vic)
+{
+       bool ret = 0;
+
+       switch (vic) {
+       case HDMI_3840x2160p24_16x9:
+       case HDMI_3840x2160p25_16x9:
+       case HDMI_3840x2160p30_16x9:
+       case HDMI_4096x2160p24_256x135:
+               ret = 1;
+               break;
+       default:
+               ret = 0;
+               break;
+       }
+
+       return ret;
+}
+
index d650bfc..8115b67 100644 (file)
@@ -397,9 +397,9 @@ int Edid_Parse_check_HDMI_VSDB(struct hdmitx_dev *hdev,
        if (temp_addr >= VSpecificBoundary)
                ret = -1;
        else {
-               if ((buff[BlockAddr + 1] != 0x03) ||
-                       (buff[BlockAddr + 2] != 0x0C) ||
-                       (buff[BlockAddr + 3] != 0x0))
+               if ((buff[BlockAddr + 1] != GET_OUI_BYTE0(HDMI_IEEE_OUI)) ||
+                       (buff[BlockAddr + 2] != GET_OUI_BYTE1(HDMI_IEEE_OUI)) ||
+                       (buff[BlockAddr + 3] != GET_OUI_BYTE2(HDMI_IEEE_OUI)))
                        ret = -1;
        }
        return ret;
@@ -1579,7 +1579,7 @@ static int hdmitx_edid_block_parse(struct hdmitx_dev *hdmitx_device,
                        if ((BlockBuf[offset] == 0x03) &&
                                (BlockBuf[offset+1] == 0x0c) &&
                                (BlockBuf[offset+2] == 0x00)) {
-                               pRXCap->IEEEOUI = 0x000c03;
+                               pRXCap->IEEEOUI = HDMI_IEEE_OUI;
                                pRXCap->ColorDeepSupport =
                                        (count > 5) ? BlockBuf[offset+5] : 0;
                                set_vsdb_dc_cap(pRXCap);
@@ -1626,7 +1626,7 @@ static int hdmitx_edid_block_parse(struct hdmitx_dev *hdmitx_device,
                        } else if ((BlockBuf[offset] == 0xd8) &&
                                (BlockBuf[offset+1] == 0x5d) &&
                                (BlockBuf[offset+2] == 0xc4)) {
-                               pRXCap->HF_IEEEOUI = 0xd85dc4;
+                               pRXCap->HF_IEEEOUI = HF_IEEE_OUI;
                                pRXCap->Max_TMDS_Clock2 = BlockBuf[offset+4];
                                pRXCap->scdc_present =
                                        !!(BlockBuf[offset+5] & (1 << 7));
@@ -1636,6 +1636,11 @@ static int hdmitx_edid_block_parse(struct hdmitx_dev *hdmitx_device,
                                        !!(BlockBuf[offset+5] & (1 << 3));
                                set_vsdb_dc_420_cap(&hdmitx_device->RXCap,
                                        &BlockBuf[offset]);
+                               if (count > 7) {
+                                       unsigned char b7 = BlockBuf[offset+7];
+
+                                       pRXCap->allm = !!(b7 & (1 << 1));
+                               }
                        }
 
                        offset += count; /* ignore the remaind. */
@@ -2257,9 +2262,9 @@ int hdmitx_edid_parse(struct hdmitx_dev *hdmitx_device)
                if ((CheckSum & 0xff) == 0)
                        hdmitx_device->RXCap.IEEEOUI = 0;
                else
-                       hdmitx_device->RXCap.IEEEOUI = 0x0c03;
+                       hdmitx_device->RXCap.IEEEOUI = HDMI_IEEE_OUI;
                if (zero_numbers > 120)
-                       hdmitx_device->RXCap.IEEEOUI = 0x0c03;
+                       hdmitx_device->RXCap.IEEEOUI = HDMI_IEEE_OUI;
 
                return 0; /* do nothing. */
        }
@@ -2363,14 +2368,14 @@ int hdmitx_edid_parse(struct hdmitx_dev *hdmitx_device)
        }
 
        if (hdmitx_edid_search_IEEEOUI(&EDID_buf[128])) {
-               pRXCap->IEEEOUI = 0x0c03;
+               pRXCap->IEEEOUI = HDMI_IEEE_OUI;
                pr_info(EDID "find IEEEOUT\n");
        } else {
                pRXCap->IEEEOUI = 0x0;
                pr_info(EDID "not find IEEEOUT\n");
        }
 
-       if ((pRXCap->IEEEOUI != 0x0c03) || (pRXCap->IEEEOUI == 0x0) ||
+       if ((pRXCap->IEEEOUI != HDMI_IEEE_OUI) || (pRXCap->IEEEOUI == 0x0) ||
                (pRXCap->VIC_count == 0))
                hdmitx_edid_set_default_vic(hdmitx_device);
 
@@ -2381,10 +2386,10 @@ int hdmitx_edid_parse(struct hdmitx_dev *hdmitx_device)
                pRXCap->IEEEOUI = 0x0;
                pr_info(EDID "sink is DVI device\n");
        } else
-               pRXCap->IEEEOUI = 0x0c03;
+               pRXCap->IEEEOUI = HDMI_IEEE_OUI;
 
        if (edid_zero_data(EDID_buf))
-               pRXCap->IEEEOUI = 0x0c03;
+               pRXCap->IEEEOUI = HDMI_IEEE_OUI;
 
        if ((!pRXCap->AUD_count) && (!pRXCap->IEEEOUI))
                hdmitx_edid_set_default_aud(hdmitx_device);
@@ -2396,7 +2401,7 @@ int hdmitx_edid_parse(struct hdmitx_dev *hdmitx_device)
        hdmitx_device->tmp_buf[i] = 0;
 
        if (!hdmitx_edid_check_valid_blocks(&EDID_buf[0])) {
-               pRXCap->IEEEOUI = 0x0c03;
+               pRXCap->IEEEOUI = HDMI_IEEE_OUI;
                pr_info(EDID "Invalid edid, consider RX as HDMI device\n");
        }
        /* update RX HDR information */
@@ -2582,7 +2587,7 @@ bool hdmitx_edid_check_valid_mode(struct hdmitx_dev *hdev,
        pRXCap = &(hdev->RXCap);
 
        /* DVI case, only 8bit */
-       if (pRXCap->IEEEOUI != 0x0c03) {
+       if (pRXCap->IEEEOUI != HDMI_IEEE_OUI) {
                if (para->cd != COLORDEPTH_24B)
                        return 0;
        }
@@ -2743,7 +2748,7 @@ void hdmitx_edid_clear(struct hdmitx_dev *hdmitx_device)
        /* Note: in most cases, we think that rx is tv and the default
         * IEEEOUI is HDMI Identifier
         */
-       pRXCap->IEEEOUI = 0x000c03;
+       pRXCap->IEEEOUI = HDMI_IEEE_OUI;
 
        hdmitx_device->vic_count = 0;
        hdmitx_device->hdmi_info.vsdb_phy_addr.a = 0;
@@ -2935,6 +2940,10 @@ int hdmitx_edid_dump(struct hdmitx_dev *hdmitx_device, char *buffer,
                        "MaxTMDSClock2 %d MHz\n", pRXCap->Max_TMDS_Clock2 * 5);
        }
 
+       if (pRXCap->allm)
+               pos += snprintf(buffer+pos, buffer_len-pos, "ALLM: %x\n",
+                       pRXCap->allm);
+
        pos += snprintf(buffer+pos, buffer_len-pos, "vLatency: ");
        if (pRXCap->vLatency == LATENCY_INVALID_UNKNOWN)
                pos += snprintf(buffer+pos, buffer_len-pos,
index d85302a..18a9b35 100644 (file)
@@ -2557,6 +2557,77 @@ static ssize_t store_valid_mode(struct device *dev,
        return count;
 }
 
+static ssize_t show_allm_mode(struct device *dev,
+       struct device_attribute *attr, char *buf)
+{
+       int pos = 0;
+       struct hdmitx_dev *hdev = &hdmitx_device;
+       struct rx_cap *pRXCap = &(hdmitx_device.RXCap);
+
+       if (!pRXCap->allm) { /* Rx not support ALLM */
+               pos += snprintf(buf + pos, PAGE_SIZE, "0\n\r");
+               return pos;
+       }
+
+       if (hdev->allm_mode == 1)
+               pos += snprintf(buf + pos, PAGE_SIZE, "game\n\r");
+       else if (hdev->allm_mode == 2)
+               pos += snprintf(buf + pos, PAGE_SIZE, "graphics\n\r");
+       else if (hdev->allm_mode == 3)
+               pos += snprintf(buf + pos, PAGE_SIZE, "photo\n\r");
+       else if (hdev->allm_mode == 4)
+               pos += snprintf(buf + pos, PAGE_SIZE, "cinema\n\r");
+       else
+               pos += snprintf(buf + pos, PAGE_SIZE, "0\n\r");
+
+       return pos;
+}
+
+static ssize_t store_allm_mode(struct device *dev,
+       struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct hdmitx_dev *hdev = &hdmitx_device;
+       struct rx_cap *pRXCap = &hdev->RXCap;
+
+       pr_info("hdmitx: store allm_mode as %s\n", buf);
+
+       if (!pRXCap->allm) /* Rx not support ALLM */
+               return count;
+
+#define CMP_STR(str)   (strncmp(buf, str, strlen(str)) == 0)
+       if (CMP_STR("0")) {
+               // disable ALLM
+               hdev->allm_mode = 0;
+               hdev->HWOp.CntlConfig(hdev, CONF_ALLM_MODE, CLEAR_ALLM_MODE);
+               hdmitx_construct_vsif(hdev, VT_ALLM, 0, NULL);
+               if (is_hdmi14_4k(hdev->cur_VIC))
+                       hdmitx_construct_vsif(hdev, VT_HDMI14_4K, 1, NULL);
+               return count;
+       }
+       if (CMP_STR("1") || CMP_STR("game") || CMP_STR("graphics")
+               || CMP_STR("photo") || CMP_STR("cinema")) {
+               hdmitx_construct_vsif(hdev, VT_ALLM, 1, NULL);
+       }
+       if (CMP_STR("1") || CMP_STR("game")) {
+               hdev->allm_mode = 1;
+               // enable the default GAME ALLM
+               hdev->HWOp.CntlConfig(hdev, CONF_ALLM_MODE, SET_ALLM_GAME);
+       }
+       if (CMP_STR("graphics")) {
+               hdev->allm_mode = 2;
+               hdev->HWOp.CntlConfig(hdev, CONF_ALLM_MODE, SET_ALLM_GRAPHICS);
+       }
+       if (CMP_STR("photo")) {
+               hdev->allm_mode = 3;
+               hdev->HWOp.CntlConfig(hdev, CONF_ALLM_MODE, SET_ALLM_PHOTO);
+       }
+       if (CMP_STR("cinema")) {
+               hdev->allm_mode = 4;
+               hdev->HWOp.CntlConfig(hdev, CONF_ALLM_MODE, SET_ALLM_CINEMA);
+       }
+
+       return count;
+}
 
 /**/
 static ssize_t show_hdr_cap(struct device *dev,
@@ -3444,6 +3515,7 @@ static DEVICE_ATTR(hdr_cap, 0444, show_hdr_cap, NULL);
 static DEVICE_ATTR(dv_cap, 0444, show_dv_cap, NULL);
 static DEVICE_ATTR(dc_cap, 0444, show_dc_cap, NULL);
 static DEVICE_ATTR(valid_mode, 0664, show_valid_mode, store_valid_mode);
+static DEVICE_ATTR(allm_mode, 0664, show_allm_mode, store_allm_mode);
 static DEVICE_ATTR(aud_ch, 0664, show_aud_ch, store_aud_ch);
 static DEVICE_ATTR(avmute, 0664, show_avmute, store_avmute);
 static DEVICE_ATTR(swap, 0644, show_swap, store_swap);
@@ -3821,7 +3893,7 @@ static void hdmitx_hpd_plugin_handler(struct work_struct *work)
                rx_repeat_hpd_state(1);
        hdmitx_get_edid(hdev);
        hdmi_physcial_size_update(hdev);
-       if (hdev->RXCap.IEEEOUI != 0x000c03)
+       if (hdev->RXCap.IEEEOUI != HDMI_IEEE_OUI)
                hdev->HWOp.CntlConfig(hdev,
                        CONF_HDMI_DVI_MODE, DVI_MODE);
        else
@@ -4591,6 +4663,7 @@ static int amhdmitx_probe(struct platform_device *pdev)
        ret = device_create_file(dev, &dev_attr_support_3d);
        ret = device_create_file(dev, &dev_attr_dc_cap);
        ret = device_create_file(dev, &dev_attr_valid_mode);
+       ret = device_create_file(dev, &dev_attr_allm_mode);
 
 #ifdef CONFIG_AMLOGIC_LEGACY_EARLY_SUSPEND
        register_early_suspend(&hdmitx_early_suspend_handler);
@@ -4662,6 +4735,7 @@ static int amhdmitx_remove(struct platform_device *pdev)
        device_remove_file(dev, &dev_attr_dv_cap);
        device_remove_file(dev, &dev_attr_dc_cap);
        device_remove_file(dev, &dev_attr_valid_mode);
+       device_remove_file(dev, &dev_attr_allm_mode);
        device_remove_file(dev, &dev_attr_hpd_state);
        device_remove_file(dev, &dev_attr_rhpd_state);
        device_remove_file(dev, &dev_attr_max_exceed);
index 2c5b2e3..181ea70 100644 (file)
@@ -871,12 +871,12 @@ static void hdmi_tx_construct_avi_packet(
  *************************************/
 
 /*
- * HDMI Identifier = 0x000c03
+ * HDMI Identifier = HDMI_IEEE_OUI 0x000c03
  * If not, treated as a DVI Device
  */
 static int is_dvi_device(struct rx_cap *pRXCap)
 {
-       if (pRXCap->IEEEOUI != 0x000c03)
+       if (pRXCap->IEEEOUI != HDMI_IEEE_OUI)
                return 1;
        else
                return 0;
@@ -970,6 +970,29 @@ int hdmitx_set_display(struct hdmitx_dev *hdev, enum hdmi_vic VideoCode)
                                hdmi_set_vend_spec_infofram(hdev, 0);
                        else
                                ;
+
+                       switch (hdev->RXCap.allm ? hdev->allm_mode : 0) {
+                       case 1: /* game */
+                               hdmitx_construct_vsif(hdev, VT_ALLM, 1, NULL);
+                               hdev->HWOp.CntlConfig(hdev, CONF_ALLM_MODE,
+                                       SET_ALLM_GAME);
+                               break;
+                       case 2: /* graphics */
+                               hdev->HWOp.CntlConfig(hdev, CONF_ALLM_MODE,
+                                       SET_ALLM_GRAPHICS);
+                               break;
+                       case 3: /* photo */
+                               hdev->HWOp.CntlConfig(hdev, CONF_ALLM_MODE,
+                                       SET_ALLM_PHOTO);
+                               break;
+                       case 4: /* cinema */
+                               hdev->HWOp.CntlConfig(hdev, CONF_ALLM_MODE,
+                                       SET_ALLM_CINEMA);
+                               break;
+                       default:
+                               break;
+                       }
+
                        ret = 0;
                }
        }
@@ -1001,9 +1024,9 @@ static void hdmi_set_vend_spec_infofram(struct hdmitx_dev *hdev,
 
        for (i = 0; i < 0x6; i++)
                VEN_DB[i] = 0;
-       VEN_DB[0] = 0x03;
-       VEN_DB[1] = 0x0c;
-       VEN_DB[2] = 0x00;
+       VEN_DB[0] = GET_OUI_BYTE0(HDMI_IEEE_OUI);
+       VEN_DB[1] = GET_OUI_BYTE1(HDMI_IEEE_OUI);
+       VEN_DB[2] = GET_OUI_BYTE2(HDMI_IEEE_OUI);
        VEN_DB[3] = 0x00;    /* 4k x 2k  Spec P156 */
 
        if (VideoCode == HDMI_4k2k_30) {
@@ -1037,9 +1060,9 @@ int hdmi_set_3d(struct hdmitx_dev *hdev, int type, unsigned int param)
        else {
                for (i = 0; i < 0x6; i++)
                        VEN_DB[i] = 0;
-               VEN_DB[0] = 0x03;
-               VEN_DB[1] = 0x0c;
-               VEN_DB[2] = 0x00;
+               VEN_DB[0] = GET_OUI_BYTE0(HDMI_IEEE_OUI);
+               VEN_DB[1] = GET_OUI_BYTE1(HDMI_IEEE_OUI);
+               VEN_DB[2] = GET_OUI_BYTE2(HDMI_IEEE_OUI);
                VEN_DB[3] = 0x40;
                VEN_DB[4] = type<<4;
                VEN_DB[5] = param<<4;
@@ -1077,3 +1100,74 @@ static void hdmitx_set_spd_info(struct hdmitx_dev *hdev)
        SPD_DB[24] = 0x1;
        hdev->HWOp.SetPacket(HDMI_SOURCE_DESCRIPTION, SPD_DB, SPD_HB);
 }
+
+static void fill_hdmi4k_vsif_data(enum hdmi_vic vic, unsigned char *DB,
+       unsigned char *HB)
+{
+       if (!DB || !HB)
+               return;
+
+       if (vic == HDMI_4k2k_30)
+               DB[4] = 0x1;
+       else if (vic == HDMI_4k2k_25)
+               DB[4] = 0x2;
+       else if (vic == HDMI_4k2k_24)
+               DB[4] = 0x3;
+       else if (vic == HDMI_4k2k_smpte_24)
+               DB[4] = 0x4;
+       else
+               return;
+       HB[0] = 0x81;
+       HB[1] = 0x01;
+       HB[2] = 0x5;
+       DB[3] = 0x20;
+}
+
+int hdmitx_construct_vsif(struct hdmitx_dev *hdev, enum vsif_type type,
+       int on, void *param)
+{
+       unsigned char HB[3] = {0x81, 0x1, 0};
+       unsigned char len = 0; /* HB[2] = len */
+       unsigned char DB[27]; /* to be fulfilled */
+       unsigned int ieeeoui = 0;
+
+       if (!hdev || type >= VT_MAX)
+               return 0;
+       memset(DB, 0, sizeof(DB));
+
+       switch (type) {
+       case VT_DEFAULT:
+               break;
+       case VT_HDMI14_4K:
+               ieeeoui = HDMI_IEEE_OUI;
+               len = 5;
+               if (is_hdmi14_4k(hdev->cur_VIC)) {
+                       fill_hdmi4k_vsif_data(hdev->cur_VIC, DB, HB);
+                       hdmitx_set_avi_vic(0);
+               }
+               break;
+       case VT_ALLM:
+               ieeeoui = HF_IEEE_OUI;
+               len = 5;
+               DB[3] = 0x1; /* Fixed value */
+               if (on) {
+                       DB[4] |= 1 << 1; /* set bit1, ALLM_MODE */
+                       if (is_hdmi14_4k(hdev->cur_VIC))
+                               hdmitx_set_avi_vic(hdev->cur_VIC);
+               } else {
+                       DB[4] &= ~(1 << 1); /* clear bit1, ALLM_MODE */
+                       /* still send out HS_VSIF, no set AVI.VIC = 0 */
+               }
+               break;
+       default:
+               break;
+       }
+
+       HB[2] = len;
+       DB[0] = GET_OUI_BYTE0(ieeeoui);
+       DB[1] = GET_OUI_BYTE1(ieeeoui);
+       DB[2] = GET_OUI_BYTE2(ieeeoui);
+
+       hdev->HWOp.SetDataPacket(HDMI_PACKET_VEND, DB, HB);
+       return 1;
+}
index 576cb87..8e42d76 100644 (file)
@@ -68,6 +68,8 @@ struct ksv_lists_ {
 static struct ksv_lists_ tmp_ksv_lists;
 
 static void hdmitx_set_packet(int type, unsigned char *DB, unsigned char *HB);
+static void hdmitx_set_datapacket(int type, unsigned char *DB,
+       unsigned char *HB);
 static void hdmitx_setaudioinfoframe(unsigned char *AUD_DB,
        unsigned char *CHAN_STAT_BUF);
 static int hdmitx_set_dispmode(struct hdmitx_dev *hdev);
@@ -242,6 +244,11 @@ static void config_avmute(unsigned int val)
        }
 }
 
+void hdmitx_set_avi_vic(enum hdmi_vic vic)
+{
+       hdmitx_wr_reg(HDMITX_DWC_FC_AVIVID, vic);
+}
+
 static int read_avmute(void)
 {
        int val;
@@ -600,6 +607,7 @@ static void hdmi_hwi_init(struct hdmitx_dev *hdev)
 void HDMITX_Meson_Init(struct hdmitx_dev *hdev)
 {
        hdev->HWOp.SetPacket = hdmitx_set_packet;
+       hdev->HWOp.SetDataPacket = hdmitx_set_datapacket;
        hdev->HWOp.SetAudioInfoFrame = hdmitx_setaudioinfoframe;
        hdev->HWOp.SetDispMode = hdmitx_set_dispmode;
        hdev->HWOp.SetAudMode = hdmitx_set_audmode;
@@ -2264,6 +2272,40 @@ static void hdmitx_set_packet(int type, unsigned char *DB, unsigned char *HB)
        }
 }
 
+static void hdmitx_set_datapacket(int type, unsigned char *DB,
+       unsigned char *HB)
+{
+       int i;
+#if 0
+       pr_info("HB: %02x %02x %02x\nDB:", HB[0], HB[1], HB[2]);
+       for (i = 0; (i < 24) && (i < HB[2]); i++)
+               pr_info(" %02x", DB[i]);
+       pr_info("\n");
+#endif
+       switch (type) {
+       case HDMI_PACKET_VEND:
+               if ((!DB) || (!HB)) {
+                       hdmitx_set_reg_bits(HDMITX_DWC_FC_DATAUTO0, 0, 3, 1);
+                       hdmitx_wr_reg(HDMITX_DWC_FC_VSDSIZE, 0x0);
+                       return;
+               }
+               hdmitx_wr_reg(HDMITX_DWC_FC_VSDSIZE, HB[2]);
+               hdmitx_wr_reg(HDMITX_DWC_FC_VSDIEEEID0, DB[0]);
+               hdmitx_wr_reg(HDMITX_DWC_FC_VSDIEEEID1, DB[1]);
+               hdmitx_wr_reg(HDMITX_DWC_FC_VSDIEEEID2, DB[2]);
+               for (i = 0; (i < 24) && (i < HB[2]); i++)
+                       hdmitx_wr_reg(HDMITX_DWC_FC_VSDPAYLOAD0 + i, DB[3 + i]);
+               /* Enable VSI packet */
+               hdmitx_set_reg_bits(HDMITX_DWC_FC_DATAUTO0, 1, 3, 1);
+               hdmitx_wr_reg(HDMITX_DWC_FC_DATAUTO1, 0);
+               hdmitx_wr_reg(HDMITX_DWC_FC_DATAUTO2, 0x10);
+               hdmitx_set_reg_bits(HDMITX_DWC_FC_PACKET_TX_EN, 1, 4, 1);
+               break;
+       default:
+               break;
+       }
+}
+
 
 static void hdmitx_setaudioinfoframe(unsigned char *AUD_DB,
        unsigned char *CHAN_STAT_BUF)
@@ -4866,6 +4908,28 @@ static int hdmitx_cntl_config(struct hdmitx_dev *hdev, unsigned int cmd,
        case CONF_AVI_YQ01:
                hdmitx_set_reg_bits(HDMITX_DWC_FC_AVICONF3, argv, 2, 2);
                break;
+       case CONF_ALLM_MODE:
+               if (argv == CLEAR_ALLM_MODE) {
+                       hdmitx_set_reg_bits(HDMITX_DWC_FC_AVICONF2, 0, 7, 1);
+                       hdmitx_set_reg_bits(HDMITX_DWC_FC_AVICONF3, 0, 0, 2);
+                       break;
+               }
+               if (argv == GET_ALLM_MODE) {
+                       if (hdmitx_rd_reg(HDMITX_DWC_FC_AVICONF2) & (1 << 7))
+                               ret = hdmitx_rd_reg(HDMITX_DWC_FC_AVICONF3) & 3;
+                       else
+                               ret = -1;
+                       break;
+               }
+               /* set ALLM mode */
+               hdmitx_set_reg_bits(HDMITX_DWC_FC_AVICONF2, 1, 7, 1);
+               hdmitx_set_reg_bits(HDMITX_DWC_FC_AVICONF3, argv & 3, 0, 2);
+               if (argv == SET_ALLM_PHOTO) {
+                       // TODO
+                       // Extended colorimetry field may be
+                       // sYcc601, AdobeYcc601 or AdobeRGB
+               }
+               break;
        case CONF_EMP_NUMBER:
                hdmitx_set_reg_bits(HDMITX_TOP_EMP_CNTL0, argv, 16, 16);
                break;
index d35fd9d..ba21dff 100644 (file)
 
 #define HDMITX_VIC_MASK                        0xff
 
+/* Refer to http://standards-oui.ieee.org/oui/oui.txt */
+#define HDMI_IEEE_OUI  0x000C03
+#define HF_IEEE_OUI            0xC45DD8
+#define GET_OUI_BYTE0(oui)     (oui & 0xff) /* Little Endian */
+#define GET_OUI_BYTE1(oui)     ((oui >> 8) & 0xff)
+#define GET_OUI_BYTE2(oui)     ((oui >> 16) & 0xff)
+
 enum hdmi_vic {
        /* Refer to CEA 861-D */
        HDMI_Unknown = 0,
index b35a836..3f58f55 100644 (file)
@@ -111,6 +111,11 @@ struct rx_cap {
        unsigned int dc_30bit_420:1;
        unsigned int dc_36bit_420:1;
        unsigned int dc_48bit_420:1;
+       unsigned int max_frl_rate:4;
+       unsigned int fpap_start_loc:1;
+       unsigned int allm:1;
+       unsigned int mdelta:1;
+       unsigned int fva:1;
        unsigned int hdr_sup_eotf_sdr:1;
        unsigned int hdr_sup_eotf_hdr:1;
        unsigned int hdr_sup_eotf_smpte_st_2084:1;
@@ -325,6 +330,12 @@ struct hdmitx_dev {
        struct {
                void (*SetPacket)(int type, unsigned char *DB,
                        unsigned char *HB);
+               /* In original SetPacket, there are many policys, like
+                *  if ((DB[4] >> 4) == T3D_FRAME_PACKING)
+                * Need a only pure data packet to call
+                */
+               void (*SetDataPacket)(int type, unsigned char *DB,
+                       unsigned char *HB);
                void (*SetAudioInfoFrame)(unsigned char *AUD_DB,
                        unsigned char *CHAN_STAT_BUF);
                int (*SetDispMode)(struct hdmitx_dev *hdmitx_device);
@@ -411,6 +422,8 @@ struct hdmitx_dev {
        /* 0.1% clock shift, 1080p60hz->59.94hz */
        unsigned int frac_rate_policy;
        unsigned int rxsense_policy;
+       /* allm_mode: 1/game, 2/graphcis, 3/photo, 4/cinema */
+       unsigned int allm_mode;
        unsigned int sspll;
        /* configure for I2S: 8ch in, 2ch out */
        /* 0: default setting  1:ch0/1  2:ch2/3  3:ch4/5  4:ch6/7 */
@@ -496,6 +509,13 @@ struct hdmitx_dev {
        #define YCC_RANGE_LIM           0
        #define YCC_RANGE_FUL           1
        #define YCC_RANGE_RSVD          2
+#define CONF_ALLM_MODE         (CMD_CONF_OFFSET + 0X2000 + 0x04)
+       #define SET_ALLM_GRAPHICS       0
+       #define SET_ALLM_PHOTO          1
+       #define SET_ALLM_CINEMA         2
+       #define SET_ALLM_GAME           3
+       #define CLEAR_ALLM_MODE         0xf
+       #define GET_ALLM_MODE           0x10
 #define CONF_VIDEO_MUTE_OP      (CMD_CONF_OFFSET + 0x1000 + 0x04)
 #define VIDEO_MUTE          0x1
 #define VIDEO_UNMUTE        0x2
@@ -598,6 +618,42 @@ extern void hdmitx_edid_buf_compare_print(struct hdmitx_dev *hdmitx_device);
 
 extern const char *hdmitx_edid_get_native_VIC(struct hdmitx_dev *hdmitx_device);
 
+/* VSIF: Vendor Specific InfoFrame
+ * It has multiple purposes:
+ * 1. HDMI1.4 4K, HDMI_VIC=1/2/3/4, 2160p30/25/24hz, smpte24hz, AVI.VIC=0
+ *    In CTA-861-G, matched with AVI.VIC=95/94/93/98
+ * 2. 3D application, TB/SS/FP
+ * 3. DolbyVision, with Len=0x18
+ * 4. HDR10plus
+ * 5. HDMI20 3D OSD disparity / 3D dual-view / 3D independent view / ALLM
+ * Some functions are exclusive, but some may compound.
+ * Consider various state transitions carefully, such as play 3D under HDMI14
+ * 4K, exit 3D under 4K, play DV under 4K, enable ALLM under 3D dual-view
+ */
+enum vsif_type {
+       /* Below 4 functions are exclusive */
+       VT_HDMI14_4K = 1,
+       VT_T3D_VIDEO,
+       VT_DOLBYVISION,
+       VT_HDR10PLUS,
+       /* Maybe compound 3D dualview + ALLM */
+       VT_T3D_OSD_DISPARITY = 0x10,
+       VT_T3D_DUALVIEW,
+       VT_T3D_INDEPENDVEW,
+       VT_ALLM,
+       /* default: if non-HDMI4K, no any vsif; if HDMI4k, = VT_HDMI14_4K */
+       VT_DEFAULT,
+       VT_MAX,
+};
+int hdmitx_construct_vsif(struct hdmitx_dev *hdev, enum vsif_type type, int on,
+       void *param);
+
+/* if vic is 93 ~ 95, or 98 (HDMI14 4K), return 1 */
+bool is_hdmi14_4k(enum hdmi_vic vic);
+
+/* set vic to AVI.VIC */
+void hdmitx_set_avi_vic(enum hdmi_vic vic);
+
 /*
  * HDMI Repeater TX I/F
  * RX downstream Information from rptx to rprx