MLK-18904-5: imx: hdp: Adding support for i.MX8M (MCU2) DP PHY to imx-dp.c
authorOliver Brown <oliver.brown@nxp.com>
Mon, 16 Jul 2018 13:55:00 +0000 (08:55 -0500)
committerLeonard Crestez <leonard.crestez@nxp.com>
Wed, 17 Apr 2019 23:51:34 +0000 (02:51 +0300)
Add support for MCU2 DisplayPort to imx-dp.c.

Signed-off-by: Oliver Brown <oliver.brown@nxp.com>
drivers/gpu/drm/imx/hdp/imx-dp.c
drivers/gpu/drm/imx/hdp/imx-dp.h

index 40b7959..276bd58 100644 (file)
@@ -11,8 +11,8 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  */
-
 #include <linux/clk.h>
+#include <linux/kernel.h>
 #ifdef DEBUG_FW_LOAD
 #include "mhdp_firmware.h"
 #endif
@@ -53,8 +53,9 @@ int dp_fw_init(state_struct *state)
        if (ret != 0) {
                DRM_ERROR("CDN_API_CheckAlive failed - check firmware!\n");
                return -ENXIO;
-       } else
-               DRM_INFO("CDN_API_CheckAlive returned ret = %d\n", ret);
+       }
+
+       DRM_INFO("CDN_API_CheckAlive returned ret = %d\n", ret);
 
        /* turn on IP activity */
        ret = CDN_API_MainControl_blocking(state, 1, &resp);
@@ -63,7 +64,7 @@ int dp_fw_init(state_struct *state)
 
        ret = CDN_API_General_Test_Echo_Ext_blocking(state, echo_msg, echo_resp,
                sizeof(echo_msg), CDN_BUS_TYPE_APB);
-       if (0 != strncmp(echo_msg, echo_resp, sizeof(echo_msg))) {
+       if (strncmp(echo_msg, echo_resp, sizeof(echo_msg)) != 0) {
                DRM_ERROR("CDN_API_General_Test_Echo_Ext_blocking - echo test failed, check firmware!");
                return -ENXIO;
        }
@@ -72,13 +73,16 @@ int dp_fw_init(state_struct *state)
 
        /* Line swaping */
        CDN_API_General_Write_Register_blocking(state,
-               ADDR_SOURCD_PHY + (LANES_CONFIG << 2), 0x0040001b);
+                                               ADDR_SOURCD_PHY +
+                                               (LANES_CONFIG << 2),
+                                               0x00400000 | hdp->lane_mapping);
        DRM_INFO("CDN_API_General_Write_Register_blockin ... setting LANES_CONFIG\n");
 
        return 0;
 }
 
-int dp_phy_init(state_struct *state, struct drm_display_mode *mode, int format, int color_depth)
+int dp_phy_init(state_struct *state, struct drm_display_mode *mode, int format,
+               int color_depth)
 {
        struct imx_hdp *hdp = state_to_imx_hdp(state);
        int max_link_rate = hdp->link_rate;
@@ -86,14 +90,14 @@ int dp_phy_init(state_struct *state, struct drm_display_mode *mode, int format,
        int ret;
 
        /* reset phy */
-       imx_hdp_call(hdp, phy_reset, hdp->ipcHndl, 0);
+       imx_hdp_call(hdp, phy_reset, hdp->ipcHndl, NULL, 0);
 
        /* PHY initialization while phy reset pin is active */
        AFE_init(state, num_lanes, (ENUM_AFE_LINK_RATE)max_link_rate);
        DRM_INFO("AFE_init\n");
 
        /* In this point the phy reset should be deactivated */
-       imx_hdp_call(hdp, phy_reset, hdp->ipcHndl, 1);
+       imx_hdp_call(hdp, phy_reset, hdp->ipcHndl, NULL, 1);
        DRM_INFO("deasserted reset\n");
 
        /* PHY power set */
@@ -107,11 +111,176 @@ int dp_phy_init(state_struct *state, struct drm_display_mode *mode, int format,
        return true;
 }
 
-/* Max Link Rate: 06h (1.62Gbps), 0Ah (2.7Gbps), 14h (5.4Gbps), 1Eh (8.1Gbps)--N/A */
-void dp_mode_set(state_struct *state, struct drm_display_mode *mode, int format, int color_depth, int max_link_rate)
+#ifdef DEBUG
+void print_header(void)
+{
+       /*       "0x00000000: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f"*/
+       DRM_INFO("          : 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n"
+                );
+       DRM_INFO("-----------------------------------------------------------\n"
+                );
+}
+
+void print_bytes(unsigned int addr, unsigned char *buf, unsigned int size)
+{
+       int i, index = 0;
+       char line[160];
+
+       if (((size + 11) * 3) > sizeof(line))
+               return;
+
+       index += sprintf(line, "0x%08x:", addr);
+       for (i = 0; i < size; i++)
+               index += sprintf(&line[index], " %02x", buf[i]);
+       DRM_INFO("%s\n", line);
+
+}
+
+int dump_dpcd(state_struct *state)
 {
        int ret;
 
+       DPTX_Read_DPCD_response resp_dpcd;
+
+       print_header();
+
+       ret = CDN_API_DPTX_Read_DPCD_blocking(state, 0x10, 0x0, &resp_dpcd,
+                                             CDN_BUS_TYPE_APB);
+       if (ret) {
+               DRM_INFO("_debug: function returned with status %d\n", ret);
+               return -1;
+       }
+       print_bytes(resp_dpcd.addr, resp_dpcd.buff, resp_dpcd.size);
+
+       ret = CDN_API_DPTX_Read_DPCD_blocking(state, 0x10, 0x100, &resp_dpcd,
+                                             CDN_BUS_TYPE_APB);
+       if (ret) {
+               DRM_INFO("_debug: function returned with status %d\n", ret);
+               return -1;
+       }
+       print_bytes(resp_dpcd.addr, resp_dpcd.buff, resp_dpcd.size);
+
+       ret = CDN_API_DPTX_Read_DPCD_blocking(state, 0x10, 0x200, &resp_dpcd,
+                                             CDN_BUS_TYPE_APB);
+       if (ret) {
+               DRM_INFO("_debug: function returned with status %d\n", ret);
+               return -1;
+       }
+       print_bytes(resp_dpcd.addr, resp_dpcd.buff, resp_dpcd.size);
+
+       ret = CDN_API_DPTX_Read_DPCD_blocking(state, 0x10, 0x210, &resp_dpcd,
+                                             CDN_BUS_TYPE_APB);
+       if (ret) {
+               DRM_INFO("_debug: function returned with status %d\n", ret);
+               return -1;
+       }
+       print_bytes(resp_dpcd.addr, resp_dpcd.buff, resp_dpcd.size);
+
+       ret = CDN_API_DPTX_Read_DPCD_blocking(state, 0x10, 0x220, &resp_dpcd,
+                                             CDN_BUS_TYPE_APB);
+       if (ret) {
+               DRM_INFO("_debug: function returned with status %d\n", ret);
+               return -1;
+       }
+       print_bytes(resp_dpcd.addr, resp_dpcd.buff, resp_dpcd.size);
+
+       ret = CDN_API_DPTX_Read_DPCD_blocking(state, 0x10, 0x700, &resp_dpcd,
+                                             CDN_BUS_TYPE_APB);
+       if (ret) {
+               DRM_INFO("_debug: function returned with status %d\n", ret);
+               return -1;
+       }
+       print_bytes(resp_dpcd.addr, resp_dpcd.buff, resp_dpcd.size);
+
+       ret = CDN_API_DPTX_Read_DPCD_blocking(state, 0x10, 0x710, &resp_dpcd,
+                                             CDN_BUS_TYPE_APB);
+       if (ret) {
+               DRM_INFO("_debug: function returned with status %d\n", ret);
+               return -1;
+       }
+       print_bytes(resp_dpcd.addr, resp_dpcd.buff, resp_dpcd.size);
+
+       ret = CDN_API_DPTX_Read_DPCD_blocking(state, 0x10, 0x720, &resp_dpcd,
+                                             CDN_BUS_TYPE_APB);
+       if (ret) {
+               DRM_INFO("_debug: function returned with status %d\n", ret);
+               return -1;
+       }
+       print_bytes(resp_dpcd.addr, resp_dpcd.buff, resp_dpcd.size);
+
+       ret = CDN_API_DPTX_Read_DPCD_blocking(state, 0x10, 0x730, &resp_dpcd,
+                                             CDN_BUS_TYPE_APB);
+       if (ret) {
+               DRM_INFO("_debug: function returned with status %d\n", ret);
+               return -1;
+       }
+
+       print_bytes(resp_dpcd.addr, resp_dpcd.buff, resp_dpcd.size);
+       return 0;
+}
+#endif
+
+int dp_get_training_status(state_struct *state)
+{
+       uint32_t evt;
+       uint8_t eventId;
+       uint8_t HPDevents;
+
+       do {
+               do {
+                       CDN_API_Get_Event(state, &evt);
+                       if (evt != 0)
+                               DRM_DEBUG("_Get_Event %d\n", evt);
+               } while ((evt & 2) == 0);
+               CDN_API_DPTX_ReadEvent_blocking(state, &eventId, &HPDevents);
+               DRM_DEBUG("ReadEvent  ID = %d HPD = %d\n", eventId, HPDevents);
+
+               switch (eventId) {
+               case 0x01:
+                       DRM_INFO("INFO: Full link training started\n");
+                       break;
+               case 0x02:
+                       DRM_INFO("INFO: Fast link training started\n");
+                       break;
+               case 0x04:
+                       DRM_INFO("INFO: Clock recovery phase finished\n");
+                       break;
+               case 0x08:
+                       DRM_INFO("INFO: Channel equalization phase finished (this is last part meaning training finished)\n");
+                       break;
+               case 0x10:
+                       DRM_INFO("INFO: Fast link training finished\n");
+                       break;
+               case 0x20:
+                       DRM_INFO("ERROR: Clock recovery phase failed\n");
+                       return -1;
+               case 0x40:
+                       DRM_INFO("ERROR: Channel equalization phase failed\n");
+                       return -1;
+               case 0x80:
+                       DRM_INFO("ERROR: Fast link training failed\n");
+                       return -1;
+               default:
+                       DRM_INFO("ERROR: Invalid ID:%x\n", eventId);
+                       return -1;
+               }
+       } while (eventId != 0x08 && eventId != 0x10);
+
+       return 0;
+}
+
+/* Max Link Rate: 06h (1.62Gbps), 0Ah (2.7Gbps), 14h (5.4Gbps),
+ * 1Eh (8.1Gbps)--N/A
+ */
+void dp_mode_set(state_struct *state,
+                       struct drm_display_mode *mode,
+                       int format,
+                       int color_depth,
+                       int max_link_rate)
+{
+       struct imx_hdp *hdp = state_to_imx_hdp(state);
+       int ret;
+       u8 training_retries = 10;
        /* Set Host capabilities */
        /* Number of lanes and SSC */
        u8 num_lanes = 4;
@@ -128,7 +297,8 @@ void dp_mode_set(state_struct *state, struct drm_display_mode *mode, int format,
        /* AUX training? */
        u8 no_aux_training = 0;
        /* Lane mapping */
-       u8 lane_mapping = 0x1B; /*  we have 4 lane, so it's OK */
+       u8 lane_mapping = hdp->lane_mapping; /*  we have 4 lane, so it's OK */
+
        /* Extended Host capabilities */
        u8 ext_host_cap = 1;
        /* Bits per sub-pixel */
@@ -140,29 +310,68 @@ void dp_mode_set(state_struct *state, struct drm_display_mode *mode, int format,
        /* Transfer Unit */
        u8 transfer_unit = 64;
        VIC_SYMBOL_RATE sym_rate;
+       u8 link_rate;
+       GENERAL_Read_Register_response regresp;
+
+       if (hdp->is_edp) {
+               /* eDP uses device tree link rate and number of lanes */
+               link_rate = hdp->edp_link_rate;
+               num_lanes = hdp->edp_num_lanes;
+
+               /* use the eDP supported rates */
+               switch (max_link_rate) {
+               case AFE_LINK_RATE_1_6:
+                       sym_rate = RATE_1_6;
+                       break;
+               case AFE_LINK_RATE_2_1:
+                       sym_rate = RATE_2_1;
+                       break;
+               case AFE_LINK_RATE_2_4:
+                       sym_rate = RATE_2_4;
+                       break;
+               case AFE_LINK_RATE_2_7:
+                       sym_rate = RATE_2_7;
+                       break;
+               case AFE_LINK_RATE_3_2:
+                       sym_rate = RATE_3_2;
+                       break;
+               case AFE_LINK_RATE_4_3:
+                       sym_rate = RATE_4_3;
+                       break;
+               case AFE_LINK_RATE_5_4:
+                       sym_rate = RATE_5_4;
+                       break;
+                       /*case AFE_LINK_RATE_8_1: sym_rate = RATE_8_1; break; */
+               default:
+                       sym_rate = RATE_1_6;
+               }
+       } else {
+               link_rate = max_link_rate;
+
+               switch (max_link_rate) {
+               case 0x0a:
+                       sym_rate = RATE_2_7;
+                       break;
+               case 0x14:
+                       sym_rate = RATE_5_4;
+                       break;
+               default:
+                       sym_rate = RATE_1_6;
+               }
+       }
 
        ret = CDN_API_DPTX_SetHostCap_blocking(state,
-               max_link_rate,
+               link_rate,
                (num_lanes & 0x7) | ((ssc & 1) << 3) | ((scrambler & 1) << 4),
                (max_vswing & 0x3) | ((force_max_vswing & 1) << 4),
                (max_preemph & 0x3) | ((force_max_preemph & 1) << 4),
                supp_test_patterns,
-               no_aux_training, //fast link training
+               no_aux_training, /* fast link training */
                lane_mapping,
                ext_host_cap
                );
        DRM_INFO("CDN_API_DPTX_SetHostCap_blocking (ret = %d)\n", ret);
 
-       switch (max_link_rate) {
-       case 0x0a:
-               sym_rate = RATE_2_7;
-               break;
-       case 0x14:
-               sym_rate = RATE_5_4;
-               break;
-       default:
-               sym_rate = RATE_1_6;
-       }
 
        ret = CDN_API_DPTX_Set_VIC_blocking(state,
                mode,
@@ -176,19 +385,52 @@ void dp_mode_set(state_struct *state, struct drm_display_mode *mode, int format,
                );
        DRM_INFO("CDN_API_DPTX_Set_VIC_blocking (ret = %d)\n", ret);
 
-       ret = CDN_API_DPTX_TrainingControl_blocking(state, 1);
-       DRM_INFO("CDN_API_DPTX_TrainingControl_blocking (ret = %d)\n", ret);
+       CDN_API_General_Read_Register_blocking(state, ADDR_DPTX_FRAMER +
+                                              (DP_FRAMER_SP << 2), &regresp);
+       DRM_INFO("Initial DP_FRAMER_SP: 0x%.2X\n", regresp.val);
+       regresp.val &= ~0x03; // clear HSP and VSP bits
+
+       DRM_INFO("Final DP_FRAMER_SP: 0x%.2X\n", regresp.val);
+       CDN_API_General_Write_Register_blocking(state, ADDR_DPTX_FRAMER +
+                                               (DP_FRAMER_SP << 2),
+                                               regresp.val);
+
+       do {
+               ret = CDN_API_DPTX_TrainingControl_blocking(state, 1);
+               DRM_DEBUG("CDN_API_DPTX_TrainingControl_blocking (ret = %d) start\n",
+                          ret);
+               if (dp_get_training_status(state) == 0)
+                       break;
+               training_retries--;
+
+               ret = CDN_API_DPTX_TrainingControl_blocking(state, 0);
+               DRM_DEBUG("CDN_API_DPTX_TrainingControl_blocking (ret = %d) stop\n",
+                          ret);
+               udelay(1000);
+
+       } while (training_retries > 0);
 
        /* Set video on */
        ret = CDN_API_DPTX_SetVideo_blocking(state, 1);
        DRM_INFO("CDN_API_DPTX_SetVideo_blocking (ret = %d)\n", ret);
 
        udelay(1000);
+
+#ifdef DEBUG
+       ret = CDN_API_DPTX_ReadLinkStat_blocking(state, &rls);
+       DRM_INFO("INFO: Get Read Link Status (ret = %d resp: rate: %d, lanes: %d, vswing 0..3: %d %d %d, preemp 0..3: %d %d %d\n",
+                ret, rls.rate, rls.lanes,
+                rls.swing[0], rls.swing[1], rls.swing[2],
+                rls.preemphasis[0], rls.preemphasis[1],
+                rls.preemphasis[2]);
+       dump_dpcd(state);
+#endif
+
 }
 
 int dp_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len)
 {
-    DPTX_Read_EDID_response edidResp;
+       DPTX_Read_EDID_response edidResp;
        state_struct *state = data;
        CDN_API_STATUS ret = 0;
 
@@ -222,3 +464,48 @@ int dp_get_hpd_state(state_struct *state, u8 *hpd)
        ret = CDN_API_DPTX_GetHpdStatus_blocking(state, hpd);
        return ret;
 }
+
+int dp_phy_init_t28hpc(state_struct *state,
+                      struct drm_display_mode *mode,
+                      int format,
+                      int color_depth)
+{
+       struct imx_hdp *hdp = state_to_imx_hdp(state);
+       int max_link_rate = hdp->link_rate;
+       int num_lanes = 4;
+       int ret;
+       u8 lane_mapping = hdp->lane_mapping;
+       /* reset phy */
+       imx_hdp_call(hdp, phy_reset, 0, &hdp->mem, 0);
+
+       if (hdp->is_edp) {
+               max_link_rate = hdp->edp_link_rate;
+               num_lanes = hdp->edp_num_lanes;
+       }
+
+       /* Line swaping */
+       CDN_API_General_Write_Register_blocking(state,
+                                               ADDR_SOURCD_PHY +
+                                               (LANES_CONFIG << 2),
+                                               0x00400000 | lane_mapping);
+       DRM_INFO("CDN_API_General_Write_Register_blocking ... setting LANES_CONFIG %x\n",
+                lane_mapping);
+
+       /* PHY initialization while phy reset pin is active */
+       afe_init_t28hpc(state, num_lanes, (ENUM_AFE_LINK_RATE)max_link_rate);
+       DRM_INFO("AFE_init\n");
+
+       /* In this point the phy reset should be deactivated */
+       imx_hdp_call(hdp, phy_reset, 0, &hdp->mem, 1);
+       DRM_INFO("deasserted reset\n");
+
+       /* PHY power set */
+       afe_power_t28hpc(state, num_lanes, (ENUM_AFE_LINK_RATE)max_link_rate);
+       DRM_INFO("AFE_power exit\n");
+
+       /* Video off */
+       ret = CDN_API_DPTX_SetVideo_blocking(state, 0);
+       DRM_INFO("CDN_API_DPTX_SetVideo_blocking (ret = %d)\n", ret);
+
+       return true;
+}
index db53aac..bc2bc9b 100644 (file)
 
 void dp_fw_load(state_struct *state);
 int dp_fw_init(state_struct *state);
-void dp_mode_set(state_struct *state, struct drm_display_mode *mode, int format, int color_depth, int max_link_rate);
-int dp_phy_init(state_struct *state, struct drm_display_mode *mode, int format, int color_depth);
+void dp_mode_set(state_struct *state,
+                struct drm_display_mode *mode,
+                int format, int color_depth,
+                int max_link_rate);
+int dp_phy_init(state_struct *state,
+               struct drm_display_mode *mode,
+               int format,
+               int color_depth);
+int dp_phy_init_t28hpc(state_struct *state,
+                      struct drm_display_mode *mode,
+                      int format,
+                      int color_depth);
 int dp_get_edid_block(void *data, u8 *buf, u32 block, size_t len);
 int dp_get_hpd_state(state_struct *state, u8 *hpd);