* 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
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);
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;
}
/* 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;
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 */
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;
/* 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 */
/* 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,
);
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), ®resp);
+ 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;
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;
+}