drm/exynos/hdmi: improve infoframe configuration 71/93971/5
authorAndrzej Hajda <a.hajda@samsung.com>
Tue, 25 Oct 2016 08:56:27 +0000 (10:56 +0200)
committerInki Dae <inki.dae@samsung.com>
Wed, 16 Nov 2016 23:11:09 +0000 (15:11 -0800)
Use core helpers to generate infoframes and add VSI frame generation
for UHD modes.

Change-Id: Ibea33cff20c6c4fa6b07a8e206770708a36fe53f
Signed-off-by: Andrzej Hajda <a.hajda@samsung.com>
drivers/gpu/drm/exynos/exynos_hdmi.c
drivers/gpu/drm/exynos/regs-hdmi.h

index 205db5f78de2c7262ea20892ba9246b661dcd178..b2258359e7c824a7d6af5de644475ce4a81872e5 100644 (file)
 
 #define HOTPLUG_DEBOUNCE_MS            1100
 
-/* AVI header and aspect ratio */
-#define HDMI_AVI_VERSION               0x02
-#define HDMI_AVI_LENGTH                        0x0D
-#define AVI_PICTURE_AR_NO_DATA         (0 << 4)
-#define AVI_PICTURE_AR_4_3             (1 << 4)
-#define AVI_PICTURE_AR_16_9            (2 << 4)
-#define AVI_PICTURE_AR_FUTURE          (3 << 4)
-#define AVI_ACTIVE_AR_SAME_AS_PIC      0x8
-#define AVI_ACTIVE_AR_4_3_CENTER       0x9
-#define AVI_ACTIVE_AR_16_9_CENTER      0xa
-#define AVI_ACTIVE_AR_14_9_CENTER      0xb
-
-/* AUI header info */
-#define HDMI_AUI_VERSION               0x01
-#define HDMI_AUI_LENGTH                        0x0A
-#define HDMI_AUI_DATA_CC_2CH           (0x1 << 0)
-#define HDMI_AUI_DATA_CC_6CH           (0x5 << 0)
-#define HDMI_AUI_DATA_CC_8CH           (0x7 << 0)
-#define HDMI_AUI_DATA_CA_2CH           (0x0 << 0)
-#define HDMI_AUI_DATA_CA_6CH           (0xb << 0)
-#define HDMI_AUI_DATA_CA_8CH           (0x13 << 0)
-
-
 enum hdmi_type {
        HDMI_TYPE13,
        HDMI_TYPE14,
@@ -146,7 +123,6 @@ struct hdmi_context {
        bool                            applied;
        struct delayed_work             hotplug_work;
        struct drm_display_mode         current_mode;
-       u8                              cea_video_id;
        const struct hdmi_driver_data   *drv_data;
 
        void __iomem                    *regs;
@@ -733,6 +709,13 @@ static inline void hdmi_reg_writev(struct hdmi_context *hdata, u32 reg_id,
        }
 }
 
+static inline void hdmi_reg_write_buf(struct hdmi_context *hdata, u32 reg_id,
+                                     u8 *buf, int size)
+{
+       for (reg_id = hdmi_map_reg(hdata, reg_id); size; --size, reg_id += 4)
+               writel(*buf++, hdata->regs + reg_id);
+}
+
 static inline void hdmi_reg_writemask(struct hdmi_context *hdata,
                                 u32 reg_id, u32 value, u32 mask)
 {
@@ -834,97 +817,50 @@ static int hdmi_clk_set_parents(struct hdmi_context *hdata, bool to_phy)
        return ret;
 }
 
-static u8 hdmi_chksum(struct hdmi_context *hdata,
-                       u32 start, u8 len, u32 hdr_sum)
-{
-       int i;
-
-       /* hdr_sum : header0 + header1 + header2
-       * start : start address of packet byte1
-       * len : packet bytes - 1 */
-       for (i = 0; i < len; ++i)
-               hdr_sum += 0xff & hdmi_reg_read(hdata, start + i * 4);
-
-       /* return 2's complement of 8 bit hdr_sum */
-       return (u8)(~(hdr_sum & 0xff) + 1);
-}
-
-static void hdmi_reg_infoframe(struct hdmi_context *hdata,
-                       union hdmi_infoframe *infoframe)
+static void hdmi_reg_infoframes(struct hdmi_context *hdata)
 {
-       u32 hdr_sum;
-       u8 chksum;
-       u32 mod;
-       u8 ar;
+       union hdmi_infoframe frm;
+       u8 buf[25];
+       int ret;
 
-       mod = hdmi_reg_read(hdata, HDMI_MODE_SEL);
        if (hdata->dvi_mode) {
-               hdmi_reg_writeb(hdata, HDMI_VSI_CON,
-                               HDMI_VSI_CON_DO_NOT_TRANSMIT);
                hdmi_reg_writeb(hdata, HDMI_AVI_CON,
                                HDMI_AVI_CON_DO_NOT_TRANSMIT);
+               hdmi_reg_writeb(hdata, HDMI_VSI_CON,
+                               HDMI_VSI_CON_DO_NOT_TRANSMIT);
                hdmi_reg_writeb(hdata, HDMI_AUI_CON, HDMI_AUI_CON_NO_TRAN);
                return;
        }
 
-       switch (infoframe->any.type) {
-       case HDMI_INFOFRAME_TYPE_AVI:
+       ret = drm_hdmi_avi_infoframe_from_display_mode(&frm.avi,
+                       &hdata->current_mode);
+       if (ret >= 0)
+               ret = hdmi_avi_infoframe_pack(&frm.avi, buf, sizeof(buf));
+       if (ret > 0) {
                hdmi_reg_writeb(hdata, HDMI_AVI_CON, HDMI_AVI_CON_EVERY_VSYNC);
-               hdmi_reg_writeb(hdata, HDMI_AVI_HEADER0, infoframe->any.type);
-               hdmi_reg_writeb(hdata, HDMI_AVI_HEADER1,
-                               infoframe->any.version);
-               hdmi_reg_writeb(hdata, HDMI_AVI_HEADER2, infoframe->any.length);
-               hdr_sum = infoframe->any.type + infoframe->any.version +
-                         infoframe->any.length;
-
-               /* Output format zero hardcoded ,RGB YBCR selection */
-               hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(1), 0 << 5 |
-                       AVI_ACTIVE_FORMAT_VALID);
-
-               /*
-                * Set the aspect ratio as per the mode, mentioned in
-                * Table 9 AVI InfoFrame Data Byte 2 of CEA-861-D Standard
-                */
-               ar = AVI_ACTIVE_AR_SAME_AS_PIC;
-               switch (hdata->current_mode.picture_aspect_ratio) {
-               case HDMI_PICTURE_ASPECT_4_3:
-                       ar |= AVI_PICTURE_AR_4_3;
-                       break;
-               case HDMI_PICTURE_ASPECT_16_9:
-                       ar |= AVI_PICTURE_AR_16_9;
-                       break;
-               case HDMI_PICTURE_ASPECT_NONE:
-               default:
-                       ar |= AVI_PICTURE_AR_NO_DATA;
-                       break;
-               }
-               hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2), ar);
+               hdmi_reg_write_buf(hdata, HDMI_AVI_HEADER0, buf, ret);
+       } else {
+               DRM_INFO("%s: invalid AVI infoframe (%d)\n", __func__, ret);
+       }
 
-               hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), hdata->cea_video_id);
+       ret = drm_hdmi_vendor_infoframe_from_display_mode(&frm.vendor.hdmi,
+                       &hdata->current_mode);
+       if (ret >= 0)
+               ret = hdmi_vendor_infoframe_pack(&frm.vendor.hdmi, buf,
+                               sizeof(buf));
+       if (ret > 0) {
+               hdmi_reg_writeb(hdata, HDMI_VSI_CON, HDMI_VSI_CON_EVERY_VSYNC);
+               hdmi_reg_write_buf(hdata, HDMI_VSI_HEADER0, buf, ret);
+       }
 
-               chksum = hdmi_chksum(hdata, HDMI_AVI_BYTE(1),
-                                       infoframe->any.length, hdr_sum);
-               DRM_DEBUG_KMS("AVI checksum = 0x%x\n", chksum);
-               hdmi_reg_writeb(hdata, HDMI_AVI_CHECK_SUM, chksum);
-               break;
-       case HDMI_INFOFRAME_TYPE_AUDIO:
-               hdmi_reg_writeb(hdata, HDMI_AUI_CON, 0x02);
-               hdmi_reg_writeb(hdata, HDMI_AUI_HEADER0, infoframe->any.type);
-               hdmi_reg_writeb(hdata, HDMI_AUI_HEADER1,
-                               infoframe->any.version);
-               hdmi_reg_writeb(hdata, HDMI_AUI_HEADER2, infoframe->any.length);
-               hdr_sum = infoframe->any.type + infoframe->any.version +
-                         infoframe->any.length;
-               hdmi_reg_writeb(hdata, HDMI_AUI_BYTE(1), HDMI_AUI_DATA_CC_2CH);
-               hdmi_reg_writeb(hdata, HDMI_AUI_BYTE(4), HDMI_AUI_DATA_CA_2CH);
-
-               chksum = hdmi_chksum(hdata, HDMI_AUI_BYTE(1),
-                                       infoframe->any.length, hdr_sum);
-               DRM_DEBUG_KMS("AUI checksum = 0x%x\n", chksum);
-               hdmi_reg_writeb(hdata, HDMI_AUI_CHECK_SUM, chksum);
-               break;
-       default:
-               break;
+       ret = hdmi_audio_infoframe_init(&frm.audio);
+       if (ret >= 0) {
+               frm.audio.channels = 2;
+               ret = hdmi_audio_infoframe_pack(&frm.audio, buf, sizeof(buf));
+       }
+       if (ret > 0) {
+               hdmi_reg_writeb(hdata, HDMI_AUI_CON, HDMI_AUI_CON_EVERY_VSYNC);
+               hdmi_reg_write_buf(hdata, HDMI_AUI_HEADER0, buf, ret);
        }
 }
 
@@ -1220,8 +1156,6 @@ static void hdmi_start(struct hdmi_context *hdata, bool start)
 
 static void hdmi_conf_init(struct hdmi_context *hdata)
 {
-       union hdmi_infoframe infoframe;
-
        /* disable HPD interrupts from HDMI IP block, use GPIO instead */
        hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL |
                HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
@@ -1258,15 +1192,7 @@ static void hdmi_conf_init(struct hdmi_context *hdata)
                hdmi_reg_writeb(hdata, HDMI_V13_AUI_CON, 0x02);
                hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 0x04);
        } else {
-               infoframe.any.type = HDMI_INFOFRAME_TYPE_AVI;
-               infoframe.any.version = HDMI_AVI_VERSION;
-               infoframe.any.length = HDMI_AVI_LENGTH;
-               hdmi_reg_infoframe(hdata, &infoframe);
-
-               infoframe.any.type = HDMI_INFOFRAME_TYPE_AUDIO;
-               infoframe.any.version = HDMI_AUI_VERSION;
-               infoframe.any.length = HDMI_AUI_LENGTH;
-               hdmi_reg_infoframe(hdata, &infoframe);
+               hdmi_reg_infoframes(hdata);
 
                /* enable AVI packet every vsync, fixes purple line problem */
                hdmi_reg_writemask(hdata, HDMI_CON_1, 2, 3 << 5);
@@ -1663,8 +1589,6 @@ static void hdmi_mode_set(struct exynos_drm_display *display,
        /* preserve mode information for later use. */
        drm_mode_copy(&hdata->current_mode, mode);
 
-       hdata->cea_video_id = drm_match_cea_mode(mode);
-
        hdmiphy_enable(hdata);
        hdmiphy_conf_apply(hdata);
 }
index ba4f16d3678fdacd2ddd7efb58d5d28983e80278..04144e3d8f502ee1495558d0d09174ac3a57a233 100644 (file)
 
 /* AUI bit definition */
 #define HDMI_AUI_CON_NO_TRAN           (0 << 0)
+#define HDMI_AUI_CON_EVERY_VSYNC       (1 << 1)
 
 /* VSI bit definition */
 #define HDMI_VSI_CON_DO_NOT_TRANSMIT   (0 << 0)
+#define HDMI_VSI_CON_EVERY_VSYNC       (1 << 1)
 
 /* HDCP related registers */
 #define HDMI_HDCP_SHA1(n)              HDMI_CORE_BASE(0x7000 + 4 * (n))