Loading drivers/gpu/drm/msm/dp/dp_audio.c +14 −86 Original line number Diff line number Diff line Loading @@ -23,13 +23,6 @@ #include "dp_audio.h" #include "dp_panel.h" #define HEADER_BYTE_2_BIT 0 #define PARITY_BYTE_2_BIT 8 #define HEADER_BYTE_1_BIT 16 #define PARITY_BYTE_1_BIT 24 #define HEADER_BYTE_3_BIT 16 #define PARITY_BYTE_3_BIT 24 struct dp_audio_private { struct platform_device *ext_pdev; struct platform_device *pdev; Loading @@ -50,71 +43,6 @@ struct dp_audio_private { struct dp_audio dp_audio; }; static u8 dp_audio_get_g0_value(u8 data) { u8 c[4]; u8 g[4]; u8 ret_data = 0; u8 i; for (i = 0; i < 4; i++) c[i] = (data >> i) & 0x01; g[0] = c[3]; g[1] = c[0] ^ c[3]; g[2] = c[1]; g[3] = c[2]; for (i = 0; i < 4; i++) ret_data = ((g[i] & 0x01) << i) | ret_data; return ret_data; } static u8 dp_audio_get_g1_value(u8 data) { u8 c[4]; u8 g[4]; u8 ret_data = 0; u8 i; for (i = 0; i < 4; i++) c[i] = (data >> i) & 0x01; g[0] = c[0] ^ c[3]; g[1] = c[0] ^ c[1] ^ c[3]; g[2] = c[1] ^ c[2]; g[3] = c[2] ^ c[3]; for (i = 0; i < 4; i++) ret_data = ((g[i] & 0x01) << i) | ret_data; return ret_data; } static u8 dp_audio_calculate_parity(u32 data) { u8 x0 = 0; u8 x1 = 0; u8 ci = 0; u8 iData = 0; u8 i = 0; u8 parity_byte; u8 num_byte = (data & 0xFF00) > 0 ? 8 : 2; for (i = 0; i < num_byte; i++) { iData = (data >> i*4) & 0xF; ci = iData ^ x1; x1 = x0 ^ dp_audio_get_g1_value(ci); x0 = dp_audio_get_g0_value(ci); } parity_byte = x1 | (x0 << 4); return parity_byte; } static u32 dp_audio_get_header(struct dp_catalog_audio *catalog, enum dp_catalog_audio_sdp_type sdp, enum dp_catalog_audio_header_type header) Loading Loading @@ -148,7 +76,7 @@ static void dp_audio_stream_sdp(struct dp_audio_private *audio) DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_1); new_value = 0x02; parity_byte = dp_audio_calculate_parity(new_value); parity_byte = dp_header_get_parity(new_value); value |= ((new_value << HEADER_BYTE_1_BIT) | (parity_byte << PARITY_BYTE_1_BIT)); pr_debug("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n", Loading @@ -160,7 +88,7 @@ static void dp_audio_stream_sdp(struct dp_audio_private *audio) value = dp_audio_get_header(catalog, DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_2); new_value = value; parity_byte = dp_audio_calculate_parity(new_value); parity_byte = dp_header_get_parity(new_value); value |= ((new_value << HEADER_BYTE_2_BIT) | (parity_byte << PARITY_BYTE_2_BIT)); pr_debug("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n", Loading @@ -174,7 +102,7 @@ static void dp_audio_stream_sdp(struct dp_audio_private *audio) DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_3); new_value = audio->channels - 1; parity_byte = dp_audio_calculate_parity(new_value); parity_byte = dp_header_get_parity(new_value); value |= ((new_value << HEADER_BYTE_3_BIT) | (parity_byte << PARITY_BYTE_3_BIT)); pr_debug("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n", Loading @@ -195,7 +123,7 @@ static void dp_audio_timestamp_sdp(struct dp_audio_private *audio) DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_1); new_value = 0x1; parity_byte = dp_audio_calculate_parity(new_value); parity_byte = dp_header_get_parity(new_value); value |= ((new_value << HEADER_BYTE_1_BIT) | (parity_byte << PARITY_BYTE_1_BIT)); pr_debug("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n", Loading @@ -208,7 +136,7 @@ static void dp_audio_timestamp_sdp(struct dp_audio_private *audio) DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_2); new_value = 0x17; parity_byte = dp_audio_calculate_parity(new_value); parity_byte = dp_header_get_parity(new_value); value |= ((new_value << HEADER_BYTE_2_BIT) | (parity_byte << PARITY_BYTE_2_BIT)); pr_debug("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n", Loading @@ -221,7 +149,7 @@ static void dp_audio_timestamp_sdp(struct dp_audio_private *audio) DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_3); new_value = (0x0 | (0x11 << 2)); parity_byte = dp_audio_calculate_parity(new_value); parity_byte = dp_header_get_parity(new_value); value |= ((new_value << HEADER_BYTE_3_BIT) | (parity_byte << PARITY_BYTE_3_BIT)); pr_debug("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n", Loading @@ -241,7 +169,7 @@ static void dp_audio_infoframe_sdp(struct dp_audio_private *audio) DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_1); new_value = 0x84; parity_byte = dp_audio_calculate_parity(new_value); parity_byte = dp_header_get_parity(new_value); value |= ((new_value << HEADER_BYTE_1_BIT) | (parity_byte << PARITY_BYTE_1_BIT)); pr_debug("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n", Loading @@ -254,7 +182,7 @@ static void dp_audio_infoframe_sdp(struct dp_audio_private *audio) DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_2); new_value = 0x1b; parity_byte = dp_audio_calculate_parity(new_value); parity_byte = dp_header_get_parity(new_value); value |= ((new_value << HEADER_BYTE_2_BIT) | (parity_byte << PARITY_BYTE_2_BIT)); pr_debug("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n", Loading @@ -267,7 +195,7 @@ static void dp_audio_infoframe_sdp(struct dp_audio_private *audio) DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_3); new_value = (0x0 | (0x11 << 2)); parity_byte = dp_audio_calculate_parity(new_value); parity_byte = dp_header_get_parity(new_value); value |= ((new_value << HEADER_BYTE_3_BIT) | (parity_byte << PARITY_BYTE_3_BIT)); pr_debug("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n", Loading @@ -287,7 +215,7 @@ static void dp_audio_copy_management_sdp(struct dp_audio_private *audio) DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_1); new_value = 0x05; parity_byte = dp_audio_calculate_parity(new_value); parity_byte = dp_header_get_parity(new_value); value |= ((new_value << HEADER_BYTE_1_BIT) | (parity_byte << PARITY_BYTE_1_BIT)); pr_debug("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n", Loading @@ -300,7 +228,7 @@ static void dp_audio_copy_management_sdp(struct dp_audio_private *audio) DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_2); new_value = 0x0F; parity_byte = dp_audio_calculate_parity(new_value); parity_byte = dp_header_get_parity(new_value); value |= ((new_value << HEADER_BYTE_2_BIT) | (parity_byte << PARITY_BYTE_2_BIT)); pr_debug("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n", Loading @@ -313,7 +241,7 @@ static void dp_audio_copy_management_sdp(struct dp_audio_private *audio) DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_3); new_value = 0x0; parity_byte = dp_audio_calculate_parity(new_value); parity_byte = dp_header_get_parity(new_value); value |= ((new_value << HEADER_BYTE_3_BIT) | (parity_byte << PARITY_BYTE_3_BIT)); pr_debug("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n", Loading @@ -333,7 +261,7 @@ static void dp_audio_isrc_sdp(struct dp_audio_private *audio) DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_1); new_value = 0x06; parity_byte = dp_audio_calculate_parity(new_value); parity_byte = dp_header_get_parity(new_value); value |= ((new_value << HEADER_BYTE_1_BIT) | (parity_byte << PARITY_BYTE_1_BIT)); pr_debug("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n", Loading @@ -346,7 +274,7 @@ static void dp_audio_isrc_sdp(struct dp_audio_private *audio) DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_2); new_value = 0x0F; parity_byte = dp_audio_calculate_parity(new_value); parity_byte = dp_header_get_parity(new_value); value |= ((new_value << HEADER_BYTE_2_BIT) | (parity_byte << PARITY_BYTE_2_BIT)); pr_debug("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n", Loading drivers/gpu/drm/msm/dp/dp_aux.c +24 −1 Original line number Diff line number Diff line Loading @@ -42,6 +42,7 @@ struct dp_aux_private { bool no_send_stop; u32 offset; u32 segment; atomic_t aborted; struct drm_dp_aux drm_aux; }; Loading Loading @@ -279,6 +280,20 @@ static void dp_aux_reconfig(struct dp_aux *dp_aux) aux->catalog->reset(aux->catalog); } static void dp_aux_abort_transaction(struct dp_aux *dp_aux) { struct dp_aux_private *aux; if (!dp_aux) { pr_err("invalid input\n"); return; } aux = container_of(dp_aux, struct dp_aux_private, dp_aux); atomic_set(&aux->aborted, 1); } static void dp_aux_update_offset_and_segment(struct dp_aux_private *aux, struct drm_dp_aux_msg *input_msg) { Loading Loading @@ -379,6 +394,11 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *drm_aux, mutex_lock(&aux->mutex); if (atomic_read(&aux->aborted)) { ret = -ETIMEDOUT; goto unlock_exit; } aux->native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ); /* Ignore address only message */ Loading Loading @@ -413,7 +433,7 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *drm_aux, } ret = dp_aux_cmd_fifo_tx(aux, msg); if ((ret < 0) && aux->native) { if ((ret < 0) && aux->native && !atomic_read(&aux->aborted)) { aux->retry_cnt++; if (!(aux->retry_cnt % retry_count)) aux->catalog->update_aux_cfg(aux->catalog, Loading Loading @@ -469,6 +489,7 @@ static void dp_aux_init(struct dp_aux *dp_aux, struct dp_aux_cfg *aux_cfg) aux->catalog->setup(aux->catalog, aux_cfg); aux->catalog->reset(aux->catalog); aux->catalog->enable(aux->catalog, true); atomic_set(&aux->aborted, 0); aux->retry_cnt = 0; } Loading @@ -483,6 +504,7 @@ static void dp_aux_deinit(struct dp_aux *dp_aux) aux = container_of(dp_aux, struct dp_aux_private, dp_aux); atomic_set(&aux->aborted, 1); aux->catalog->enable(aux->catalog, false); } Loading Loading @@ -560,6 +582,7 @@ struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog, dp_aux->drm_aux_register = dp_aux_register; dp_aux->drm_aux_deregister = dp_aux_deregister; dp_aux->reconfig = dp_aux_reconfig; dp_aux->abort = dp_aux_abort_transaction; return dp_aux; error: Loading drivers/gpu/drm/msm/dp/dp_aux.h +1 −0 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ struct dp_aux { void (*init)(struct dp_aux *aux, struct dp_aux_cfg *aux_cfg); void (*deinit)(struct dp_aux *aux); void (*reconfig)(struct dp_aux *aux); void (*abort)(struct dp_aux *aux); }; struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog, Loading drivers/gpu/drm/msm/dp/dp_catalog.c +273 −54 Original line number Diff line number Diff line Loading @@ -337,7 +337,7 @@ static void dp_catalog_panel_setup_infoframe_sdp(struct dp_catalog_panel *panel) struct dp_catalog_private *catalog; struct drm_msm_ext_hdr_metadata *hdr; void __iomem *base; u32 header, data; u32 header, parity, data; if (!panel) { pr_err("invalid input\n"); Loading @@ -348,67 +348,90 @@ static void dp_catalog_panel_setup_infoframe_sdp(struct dp_catalog_panel *panel) hdr = &panel->hdr_data.hdr_meta; base = catalog->io->dp_link.base; header = dp_read(base + MMSS_DP_VSCEXT_0); header |= panel->hdr_data.vscext_header_byte1; dp_write(base + MMSS_DP_VSCEXT_0, header); header = dp_read(base + MMSS_DP_VSCEXT_1); header |= panel->hdr_data.vscext_header_byte2; dp_write(base + MMSS_DP_VSCEXT_1, header); header = dp_read(base + MMSS_DP_VSCEXT_1); header |= panel->hdr_data.vscext_header_byte3; dp_write(base + MMSS_DP_VSCEXT_1, header); header = panel->hdr_data.version; header |= panel->hdr_data.length << 8; header |= hdr->eotf << 16; dp_write(base + MMSS_DP_VSCEXT_2, header); /* HEADER BYTE 1 */ header = panel->hdr_data.vscext_header_byte1; parity = dp_header_get_parity(header); data = ((header << HEADER_BYTE_1_BIT) | (parity << PARITY_BYTE_1_BIT)); dp_write(base + MMSS_DP_VSCEXT_0, data); pr_debug("Header#1: 0x%x, parity = 0x%x\n", header, parity); pr_debug("DP_VSCEXT_0: 0x%x\n", data); /* HEADER BYTE 2 */ header = panel->hdr_data.vscext_header_byte2; parity = dp_header_get_parity(header); data = ((header << HEADER_BYTE_2_BIT) | (parity << PARITY_BYTE_2_BIT)); dp_write(base + MMSS_DP_VSCEXT_1, data); pr_debug("Header#2: 0x%x, parity = 0x%x\n", header, parity); pr_debug("DP_VSCEXT_1: 0x%x\n", data); /* HEADER BYTE 3 */ header = panel->hdr_data.vscext_header_byte3; parity = dp_header_get_parity(header); data = ((header << HEADER_BYTE_3_BIT) | (parity << PARITY_BYTE_3_BIT)); data |= dp_read(base + MMSS_DP_VSCEXT_1); dp_write(base + MMSS_DP_VSCEXT_1, data); pr_debug("Header#3: 0x%x, parity = 0x%x\n", header, parity); pr_debug("DP_VSCEXT_1: 0x%x\n", data); data = panel->hdr_data.version; data |= panel->hdr_data.length << 8; data |= hdr->eotf << 16; pr_debug("DP_VSCEXT_2: 0x%x\n", data); dp_write(base + MMSS_DP_VSCEXT_2, data); data = (DP_GET_LSB(hdr->display_primaries_x[0]) | (DP_GET_MSB(hdr->display_primaries_x[0]) << 8) | (DP_GET_LSB(hdr->display_primaries_y[0]) << 16) | (DP_GET_MSB(hdr->display_primaries_y[0]) << 24)); pr_debug("DP_VSCEXT_3: 0x%x\n", data); dp_write(base + MMSS_DP_VSCEXT_3, data); data = (DP_GET_LSB(hdr->display_primaries_x[1]) | (DP_GET_MSB(hdr->display_primaries_x[1]) << 8) | (DP_GET_LSB(hdr->display_primaries_y[1]) << 16) | (DP_GET_MSB(hdr->display_primaries_y[1]) << 24)); pr_debug("DP_VSCEXT_4: 0x%x\n", data); dp_write(base + MMSS_DP_VSCEXT_4, data); data = (DP_GET_LSB(hdr->display_primaries_x[2]) | (DP_GET_MSB(hdr->display_primaries_x[2]) << 8) | (DP_GET_LSB(hdr->display_primaries_y[2]) << 16) | (DP_GET_MSB(hdr->display_primaries_y[2]) << 24)); pr_debug("DP_VSCEXT_5: 0x%x\n", data); dp_write(base + MMSS_DP_VSCEXT_5, data); data = (DP_GET_LSB(hdr->white_point_x) | (DP_GET_MSB(hdr->white_point_x) << 8) | (DP_GET_LSB(hdr->white_point_y) << 16) | (DP_GET_MSB(hdr->white_point_y) << 24)); pr_debug("DP_VSCEXT_6: 0x%x\n", data); dp_write(base + MMSS_DP_VSCEXT_6, data); data = (DP_GET_LSB(hdr->max_luminance) | (DP_GET_MSB(hdr->max_luminance) << 8) | (DP_GET_LSB(hdr->min_luminance) << 16) | (DP_GET_MSB(hdr->min_luminance) << 24)); pr_debug("DP_VSCEXT_7: 0x%x\n", data); dp_write(base + MMSS_DP_VSCEXT_7, data); data = (DP_GET_LSB(hdr->max_content_light_level) | (DP_GET_MSB(hdr->max_content_light_level) << 8) | (DP_GET_LSB(hdr->max_average_light_level) << 16) | (DP_GET_MSB(hdr->max_average_light_level) << 24)); pr_debug("DP_VSCEXT_8: 0x%x\n", data); dp_write(base + MMSS_DP_VSCEXT_8, data); dp_write(base + MMSS_DP_VSCEXT_9, 0x00); } static void dp_catalog_panel_setup_vsc_sdp(struct dp_catalog_panel *panel) static void dp_catalog_panel_setup_ext_sdp(struct dp_catalog_panel *panel) { struct dp_catalog_private *catalog; void __iomem *base; u32 value; u32 header, parity, data; if (!panel) { pr_err("invalid input\n"); Loading @@ -418,30 +441,105 @@ static void dp_catalog_panel_setup_vsc_sdp(struct dp_catalog_panel *panel) dp_catalog_get_priv(panel); base = catalog->io->dp_link.base; value = dp_read(base + MMSS_DP_GENERIC0_0); value |= panel->hdr_data.vsc_header_byte1; dp_write(base + MMSS_DP_GENERIC0_0, value); /* HEADER BYTE 1 */ header = panel->hdr_data.ext_header_byte1; parity = dp_header_get_parity(header); data = ((header << HEADER_BYTE_1_BIT) | (parity << PARITY_BYTE_1_BIT)); dp_write(base + MMSS_DP_EXTENSION_0, data); pr_debug("Header#1: 0x%x, parity = 0x%x\n", header, parity); pr_debug("DP_EXTENSION_0: 0x%x\n", data); /* HEADER BYTE 2 */ header = panel->hdr_data.ext_header_byte2; parity = dp_header_get_parity(header); data = ((header << HEADER_BYTE_2_BIT) | (parity << PARITY_BYTE_2_BIT)); dp_write(base + MMSS_DP_EXTENSION_1, data); pr_debug("Header#2: 0x%x, parity = 0x%x\n", header, parity); pr_debug("DP_EXTENSION_1: 0x%x\n", data); dp_write(base + MMSS_DP_EXTENSION_1, 0x5AA55AA5); dp_write(base + MMSS_DP_EXTENSION_2, 0x5AA55AA5); dp_write(base + MMSS_DP_EXTENSION_3, 0x5AA55AA5); dp_write(base + MMSS_DP_EXTENSION_4, 0x5AA55AA5); dp_write(base + MMSS_DP_EXTENSION_5, 0x5AA55AA5); dp_write(base + MMSS_DP_EXTENSION_6, 0x5AA55AA5); dp_write(base + MMSS_DP_EXTENSION_7, 0x5AA55AA5); dp_write(base + MMSS_DP_EXTENSION_8, 0x5AA55AA5); dp_write(base + MMSS_DP_EXTENSION_9, 0x5AA55AA5); } static void dp_catalog_panel_setup_vsc_sdp(struct dp_catalog_panel *panel) { struct dp_catalog_private *catalog; void __iomem *base; u32 header, parity, data; u8 bpc; value = dp_read(base + MMSS_DP_GENERIC0_1); value |= panel->hdr_data.vsc_header_byte2; dp_write(base + MMSS_DP_GENERIC0_1, value); if (!panel) { pr_err("invalid input\n"); return; } value = dp_read(base + MMSS_DP_GENERIC0_1); value |= panel->hdr_data.vsc_header_byte3; dp_write(base + MMSS_DP_GENERIC0_1, value); dp_catalog_get_priv(panel); base = catalog->io->ctrl_io.base; /* HEADER BYTE 1 */ header = panel->hdr_data.vsc_header_byte1; parity = dp_header_get_parity(header); data = ((header << HEADER_BYTE_1_BIT) | (parity << PARITY_BYTE_1_BIT)); dp_write(base + MMSS_DP_GENERIC0_0, data); pr_debug("Header#1: 0x%x, parity = 0x%x\n", header, parity); pr_debug("DP_GENERIC0_0: 0x%x\n", data); /* HEADER BYTE 2 */ header = panel->hdr_data.vsc_header_byte2; parity = dp_header_get_parity(header); data = ((header << HEADER_BYTE_2_BIT) | (parity << PARITY_BYTE_2_BIT)); dp_write(base + MMSS_DP_GENERIC0_1, data); pr_debug("Header#2: 0x%x, parity = 0x%x\n", header, parity); pr_debug("DP_GENERIC0_1: 0x%x\n", data); /* HEADER BYTE 3 */ header = panel->hdr_data.vsc_header_byte3; parity = dp_header_get_parity(header); data = ((header << HEADER_BYTE_3_BIT) | (parity << PARITY_BYTE_3_BIT)); data |= dp_read(base + MMSS_DP_GENERIC0_1); dp_write(base + MMSS_DP_GENERIC0_1, data); pr_debug("Header#3: 0x%x, parity = 0x%x\n", header, parity); pr_debug("DP_GENERIC0_1: 0x%x\n", data); dp_write(base + MMSS_DP_GENERIC0_2, 0x00); dp_write(base + MMSS_DP_GENERIC0_3, 0x00); dp_write(base + MMSS_DP_GENERIC0_4, 0x00); dp_write(base + MMSS_DP_GENERIC0_5, 0x00); value = (panel->hdr_data.colorimetry & 0xF) | switch (panel->hdr_data.bpc) { default: case 10: bpc = BIT(1); break; case 8: bpc = BIT(0); break; case 6: bpc = 0; break; } data = (panel->hdr_data.colorimetry & 0xF) | ((panel->hdr_data.pixel_encoding & 0xF) << 4) | ((panel->hdr_data.bpc & 0x7) << 8) | (bpc << 8) | ((panel->hdr_data.dynamic_range & 0x1) << 15) | ((panel->hdr_data.content_type & 0x7) << 16); dp_write(base + MMSS_DP_GENERIC0_6, value); pr_debug("DP_GENERIC0_6: 0x%x\n", data); dp_write(base + MMSS_DP_GENERIC0_6, data); dp_write(base + MMSS_DP_GENERIC0_7, 0x00); dp_write(base + MMSS_DP_GENERIC0_8, 0x00); dp_write(base + MMSS_DP_GENERIC0_9, 0x00); Loading @@ -462,19 +560,31 @@ static void dp_catalog_panel_config_hdr(struct dp_catalog_panel *panel) base = catalog->io->dp_link.base; cfg = dp_read(base + MMSS_DP_SDP_CFG); /* EXTENSION_SDP_EN */ cfg |= BIT(4); /* VSCEXT_SDP_EN */ cfg |= BIT(16); /* GEN0_SDP_EN */ cfg |= BIT(17); /* GEN1_SDP_EN */ cfg |= BIT(18); dp_write(base + MMSS_DP_SDP_CFG, cfg); cfg2 = dp_read(base + MMSS_DP_SDP_CFG2); /* Generic0 SDP Payload is 19 bytes which is > 16, so Bit16 is 1 */ cfg2 |= BIT(16); /* EXTN_SDPSIZE */ cfg2 |= BIT(15); /* GENERIC0_SDPSIZE */ cfg |= BIT(16); /* GENERIC1_SDPSIZE */ cfg |= BIT(17); dp_write(base + MMSS_DP_SDP_CFG2, cfg2); dp_catalog_panel_setup_ext_sdp(panel); dp_catalog_panel_setup_vsc_sdp(panel); dp_catalog_panel_setup_infoframe_sdp(panel); Loading @@ -484,27 +594,8 @@ static void dp_catalog_panel_config_hdr(struct dp_catalog_panel *panel) dp_write(base + DP_MISC1_MISC0, cfg); cfg = dp_read(base + DP_CONFIGURATION_CTRL); /* Send VSC */ cfg |= BIT(7); switch (panel->hdr_data.bpc) { default: case 10: cfg |= BIT(9); break; case 8: cfg |= BIT(8); break; } dp_write(base + DP_CONFIGURATION_CTRL, cfg); cfg = dp_read(base + DP_COMPRESSION_MODE_CTRL); /* Trigger SDP values in registers */ cfg |= BIT(8); dp_write(base + DP_COMPRESSION_MODE_CTRL, cfg); dp_write(base + MMSS_DP_SDP_CFG3, 0x01); dp_write(base + MMSS_DP_SDP_CFG3, 0x00); } static void dp_catalog_ctrl_update_transfer_unit(struct dp_catalog_ctrl *ctrl) Loading Loading @@ -1179,6 +1270,8 @@ static void dp_catalog_audio_config_sdp(struct dp_catalog_audio *audio) dp_catalog_get_priv(audio); base = catalog->io->dp_link.base; sdp_cfg = dp_read(base + MMSS_DP_SDP_CFG); /* AUDIO_TIMESTAMP_SDP_EN */ sdp_cfg |= BIT(1); /* AUDIO_STREAM_SDP_EN */ Loading Loading @@ -1312,6 +1405,131 @@ static void dp_catalog_audio_enable(struct dp_catalog_audio *audio) wmb(); } static void dp_catalog_config_spd_header(struct dp_catalog_panel *panel) { struct dp_catalog_private *catalog; void __iomem *base; u32 value, new_value; u8 parity_byte; if (!panel) return; dp_catalog_get_priv(panel); base = catalog->io->dp_link.base; /* Config header and parity byte 1 */ value = dp_read(base + MMSS_DP_GENERIC1_0); new_value = 0x83; parity_byte = dp_header_get_parity(new_value); value |= ((new_value << HEADER_BYTE_1_BIT) | (parity_byte << PARITY_BYTE_1_BIT)); pr_debug("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n", value, parity_byte); dp_write(base + MMSS_DP_GENERIC1_0, value); /* Config header and parity byte 2 */ value = dp_read(base + MMSS_DP_GENERIC1_1); new_value = 0x1b; parity_byte = dp_header_get_parity(new_value); value |= ((new_value << HEADER_BYTE_2_BIT) | (parity_byte << PARITY_BYTE_2_BIT)); pr_debug("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n", value, parity_byte); dp_write(base + MMSS_DP_GENERIC1_1, value); /* Config header and parity byte 3 */ value = dp_read(base + MMSS_DP_GENERIC1_1); new_value = (0x0 | (0x12 << 2)); parity_byte = dp_header_get_parity(new_value); value |= ((new_value << HEADER_BYTE_3_BIT) | (parity_byte << PARITY_BYTE_3_BIT)); pr_debug("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n", new_value, parity_byte); dp_write(base + MMSS_DP_GENERIC1_1, value); } static void dp_catalog_panel_config_spd(struct dp_catalog_panel *panel) { struct dp_catalog_private *catalog; void __iomem *base; u32 spd_cfg = 0, spd_cfg2 = 0; u8 *vendor = NULL, *product = NULL; /* * Source Device Information * 00h unknown * 01h Digital STB * 02h DVD * 03h D-VHS * 04h HDD Video * 05h DVC * 06h DSC * 07h Video CD * 08h Game * 09h PC general * 0ah Bluray-Disc * 0bh Super Audio CD * 0ch HD DVD * 0dh PMP * 0eh-ffh reserved */ u32 device_type = 0; if (!panel) return; dp_catalog_get_priv(panel); base = catalog->io->dp_link.base; dp_catalog_config_spd_header(panel); vendor = panel->spd_vendor_name; product = panel->spd_product_description; dp_write(base + MMSS_DP_GENERIC1_2, ((vendor[0] & 0x7f) | ((vendor[1] & 0x7f) << 8) | ((vendor[2] & 0x7f) << 16) | ((vendor[3] & 0x7f) << 24))); dp_write(base + MMSS_DP_GENERIC1_3, ((vendor[4] & 0x7f) | ((vendor[5] & 0x7f) << 8) | ((vendor[6] & 0x7f) << 16) | ((vendor[7] & 0x7f) << 24))); dp_write(base + MMSS_DP_GENERIC1_4, ((product[0] & 0x7f) | ((product[1] & 0x7f) << 8) | ((product[2] & 0x7f) << 16) | ((product[3] & 0x7f) << 24))); dp_write(base + MMSS_DP_GENERIC1_5, ((product[4] & 0x7f) | ((product[5] & 0x7f) << 8) | ((product[6] & 0x7f) << 16) | ((product[7] & 0x7f) << 24))); dp_write(base + MMSS_DP_GENERIC1_6, ((product[8] & 0x7f) | ((product[9] & 0x7f) << 8) | ((product[10] & 0x7f) << 16) | ((product[11] & 0x7f) << 24))); dp_write(base + MMSS_DP_GENERIC1_7, ((product[12] & 0x7f) | ((product[13] & 0x7f) << 8) | ((product[14] & 0x7f) << 16) | ((product[15] & 0x7f) << 24))); dp_write(base + MMSS_DP_GENERIC1_8, device_type); dp_write(base + MMSS_DP_GENERIC1_9, 0x00); spd_cfg = dp_read(base + MMSS_DP_SDP_CFG); /* GENERIC1_SDP for SPD Infoframe */ spd_cfg |= BIT(18); dp_write(base + MMSS_DP_SDP_CFG, spd_cfg); spd_cfg2 = dp_read(base + MMSS_DP_SDP_CFG2); /* 28 data bytes for SPD Infoframe with GENERIC1 set */ spd_cfg2 |= BIT(17); dp_write(base + MMSS_DP_SDP_CFG2, spd_cfg2); dp_write(base + MMSS_DP_SDP_CFG3, 0x1); dp_write(base + MMSS_DP_SDP_CFG3, 0x0); } struct dp_catalog *dp_catalog_get(struct device *dev, struct dp_io *io) { int rc = 0; Loading Loading @@ -1364,6 +1582,7 @@ struct dp_catalog *dp_catalog_get(struct device *dev, struct dp_io *io) .timing_cfg = dp_catalog_panel_timing_cfg, .config_hdr = dp_catalog_panel_config_hdr, .tpg_config = dp_catalog_panel_tpg_cfg, .config_spd = dp_catalog_panel_config_spd, }; if (!io) { Loading drivers/gpu/drm/msm/dp/dp_catalog.h +80 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,11 @@ #define DP_INTR_CRC_UPDATED BIT(9) struct dp_catalog_hdr_data { u32 ext_header_byte0; u32 ext_header_byte1; u32 ext_header_byte2; u32 ext_header_byte3; u32 vsc_header_byte0; u32 vsc_header_byte1; u32 vsc_header_byte2; Loading Loading @@ -109,6 +114,13 @@ struct dp_catalog_ctrl { u32 (*read_phy_pattern)(struct dp_catalog_ctrl *ctrl); }; #define HEADER_BYTE_2_BIT 0 #define PARITY_BYTE_2_BIT 8 #define HEADER_BYTE_1_BIT 16 #define PARITY_BYTE_1_BIT 24 #define HEADER_BYTE_3_BIT 16 #define PARITY_BYTE_3_BIT 24 enum dp_catalog_audio_sdp_type { DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_TIMESTAMP, Loading Loading @@ -144,6 +156,8 @@ struct dp_catalog_panel { u32 sync_start; u32 width_blanking; u32 dp_active; u8 *spd_vendor_name; u8 *spd_product_description; struct dp_catalog_hdr_data hdr_data; Loading @@ -159,6 +173,7 @@ struct dp_catalog_panel { int (*timing_cfg)(struct dp_catalog_panel *panel); void (*config_hdr)(struct dp_catalog_panel *panel); void (*tpg_config)(struct dp_catalog_panel *panel, bool enable); void (*config_spd)(struct dp_catalog_panel *panel); }; struct dp_catalog { Loading @@ -168,6 +183,71 @@ struct dp_catalog { struct dp_catalog_panel panel; }; static inline u8 dp_ecc_get_g0_value(u8 data) { u8 c[4]; u8 g[4]; u8 ret_data = 0; u8 i; for (i = 0; i < 4; i++) c[i] = (data >> i) & 0x01; g[0] = c[3]; g[1] = c[0] ^ c[3]; g[2] = c[1]; g[3] = c[2]; for (i = 0; i < 4; i++) ret_data = ((g[i] & 0x01) << i) | ret_data; return ret_data; } static inline u8 dp_ecc_get_g1_value(u8 data) { u8 c[4]; u8 g[4]; u8 ret_data = 0; u8 i; for (i = 0; i < 4; i++) c[i] = (data >> i) & 0x01; g[0] = c[0] ^ c[3]; g[1] = c[0] ^ c[1] ^ c[3]; g[2] = c[1] ^ c[2]; g[3] = c[2] ^ c[3]; for (i = 0; i < 4; i++) ret_data = ((g[i] & 0x01) << i) | ret_data; return ret_data; } static inline u8 dp_header_get_parity(u32 data) { u8 x0 = 0; u8 x1 = 0; u8 ci = 0; u8 iData = 0; u8 i = 0; u8 parity_byte; u8 num_byte = (data & 0xFF00) > 0 ? 8 : 2; for (i = 0; i < num_byte; i++) { iData = (data >> i*4) & 0xF; ci = iData ^ x1; x1 = x0 ^ dp_ecc_get_g1_value(ci); x0 = dp_ecc_get_g0_value(ci); } parity_byte = x1 | (x0 << 4); return parity_byte; } struct dp_catalog *dp_catalog_get(struct device *dev, struct dp_io *io); void dp_catalog_put(struct dp_catalog *catalog); Loading Loading
drivers/gpu/drm/msm/dp/dp_audio.c +14 −86 Original line number Diff line number Diff line Loading @@ -23,13 +23,6 @@ #include "dp_audio.h" #include "dp_panel.h" #define HEADER_BYTE_2_BIT 0 #define PARITY_BYTE_2_BIT 8 #define HEADER_BYTE_1_BIT 16 #define PARITY_BYTE_1_BIT 24 #define HEADER_BYTE_3_BIT 16 #define PARITY_BYTE_3_BIT 24 struct dp_audio_private { struct platform_device *ext_pdev; struct platform_device *pdev; Loading @@ -50,71 +43,6 @@ struct dp_audio_private { struct dp_audio dp_audio; }; static u8 dp_audio_get_g0_value(u8 data) { u8 c[4]; u8 g[4]; u8 ret_data = 0; u8 i; for (i = 0; i < 4; i++) c[i] = (data >> i) & 0x01; g[0] = c[3]; g[1] = c[0] ^ c[3]; g[2] = c[1]; g[3] = c[2]; for (i = 0; i < 4; i++) ret_data = ((g[i] & 0x01) << i) | ret_data; return ret_data; } static u8 dp_audio_get_g1_value(u8 data) { u8 c[4]; u8 g[4]; u8 ret_data = 0; u8 i; for (i = 0; i < 4; i++) c[i] = (data >> i) & 0x01; g[0] = c[0] ^ c[3]; g[1] = c[0] ^ c[1] ^ c[3]; g[2] = c[1] ^ c[2]; g[3] = c[2] ^ c[3]; for (i = 0; i < 4; i++) ret_data = ((g[i] & 0x01) << i) | ret_data; return ret_data; } static u8 dp_audio_calculate_parity(u32 data) { u8 x0 = 0; u8 x1 = 0; u8 ci = 0; u8 iData = 0; u8 i = 0; u8 parity_byte; u8 num_byte = (data & 0xFF00) > 0 ? 8 : 2; for (i = 0; i < num_byte; i++) { iData = (data >> i*4) & 0xF; ci = iData ^ x1; x1 = x0 ^ dp_audio_get_g1_value(ci); x0 = dp_audio_get_g0_value(ci); } parity_byte = x1 | (x0 << 4); return parity_byte; } static u32 dp_audio_get_header(struct dp_catalog_audio *catalog, enum dp_catalog_audio_sdp_type sdp, enum dp_catalog_audio_header_type header) Loading Loading @@ -148,7 +76,7 @@ static void dp_audio_stream_sdp(struct dp_audio_private *audio) DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_1); new_value = 0x02; parity_byte = dp_audio_calculate_parity(new_value); parity_byte = dp_header_get_parity(new_value); value |= ((new_value << HEADER_BYTE_1_BIT) | (parity_byte << PARITY_BYTE_1_BIT)); pr_debug("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n", Loading @@ -160,7 +88,7 @@ static void dp_audio_stream_sdp(struct dp_audio_private *audio) value = dp_audio_get_header(catalog, DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_2); new_value = value; parity_byte = dp_audio_calculate_parity(new_value); parity_byte = dp_header_get_parity(new_value); value |= ((new_value << HEADER_BYTE_2_BIT) | (parity_byte << PARITY_BYTE_2_BIT)); pr_debug("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n", Loading @@ -174,7 +102,7 @@ static void dp_audio_stream_sdp(struct dp_audio_private *audio) DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_3); new_value = audio->channels - 1; parity_byte = dp_audio_calculate_parity(new_value); parity_byte = dp_header_get_parity(new_value); value |= ((new_value << HEADER_BYTE_3_BIT) | (parity_byte << PARITY_BYTE_3_BIT)); pr_debug("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n", Loading @@ -195,7 +123,7 @@ static void dp_audio_timestamp_sdp(struct dp_audio_private *audio) DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_1); new_value = 0x1; parity_byte = dp_audio_calculate_parity(new_value); parity_byte = dp_header_get_parity(new_value); value |= ((new_value << HEADER_BYTE_1_BIT) | (parity_byte << PARITY_BYTE_1_BIT)); pr_debug("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n", Loading @@ -208,7 +136,7 @@ static void dp_audio_timestamp_sdp(struct dp_audio_private *audio) DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_2); new_value = 0x17; parity_byte = dp_audio_calculate_parity(new_value); parity_byte = dp_header_get_parity(new_value); value |= ((new_value << HEADER_BYTE_2_BIT) | (parity_byte << PARITY_BYTE_2_BIT)); pr_debug("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n", Loading @@ -221,7 +149,7 @@ static void dp_audio_timestamp_sdp(struct dp_audio_private *audio) DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_3); new_value = (0x0 | (0x11 << 2)); parity_byte = dp_audio_calculate_parity(new_value); parity_byte = dp_header_get_parity(new_value); value |= ((new_value << HEADER_BYTE_3_BIT) | (parity_byte << PARITY_BYTE_3_BIT)); pr_debug("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n", Loading @@ -241,7 +169,7 @@ static void dp_audio_infoframe_sdp(struct dp_audio_private *audio) DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_1); new_value = 0x84; parity_byte = dp_audio_calculate_parity(new_value); parity_byte = dp_header_get_parity(new_value); value |= ((new_value << HEADER_BYTE_1_BIT) | (parity_byte << PARITY_BYTE_1_BIT)); pr_debug("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n", Loading @@ -254,7 +182,7 @@ static void dp_audio_infoframe_sdp(struct dp_audio_private *audio) DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_2); new_value = 0x1b; parity_byte = dp_audio_calculate_parity(new_value); parity_byte = dp_header_get_parity(new_value); value |= ((new_value << HEADER_BYTE_2_BIT) | (parity_byte << PARITY_BYTE_2_BIT)); pr_debug("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n", Loading @@ -267,7 +195,7 @@ static void dp_audio_infoframe_sdp(struct dp_audio_private *audio) DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_3); new_value = (0x0 | (0x11 << 2)); parity_byte = dp_audio_calculate_parity(new_value); parity_byte = dp_header_get_parity(new_value); value |= ((new_value << HEADER_BYTE_3_BIT) | (parity_byte << PARITY_BYTE_3_BIT)); pr_debug("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n", Loading @@ -287,7 +215,7 @@ static void dp_audio_copy_management_sdp(struct dp_audio_private *audio) DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_1); new_value = 0x05; parity_byte = dp_audio_calculate_parity(new_value); parity_byte = dp_header_get_parity(new_value); value |= ((new_value << HEADER_BYTE_1_BIT) | (parity_byte << PARITY_BYTE_1_BIT)); pr_debug("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n", Loading @@ -300,7 +228,7 @@ static void dp_audio_copy_management_sdp(struct dp_audio_private *audio) DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_2); new_value = 0x0F; parity_byte = dp_audio_calculate_parity(new_value); parity_byte = dp_header_get_parity(new_value); value |= ((new_value << HEADER_BYTE_2_BIT) | (parity_byte << PARITY_BYTE_2_BIT)); pr_debug("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n", Loading @@ -313,7 +241,7 @@ static void dp_audio_copy_management_sdp(struct dp_audio_private *audio) DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_3); new_value = 0x0; parity_byte = dp_audio_calculate_parity(new_value); parity_byte = dp_header_get_parity(new_value); value |= ((new_value << HEADER_BYTE_3_BIT) | (parity_byte << PARITY_BYTE_3_BIT)); pr_debug("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n", Loading @@ -333,7 +261,7 @@ static void dp_audio_isrc_sdp(struct dp_audio_private *audio) DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_1); new_value = 0x06; parity_byte = dp_audio_calculate_parity(new_value); parity_byte = dp_header_get_parity(new_value); value |= ((new_value << HEADER_BYTE_1_BIT) | (parity_byte << PARITY_BYTE_1_BIT)); pr_debug("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n", Loading @@ -346,7 +274,7 @@ static void dp_audio_isrc_sdp(struct dp_audio_private *audio) DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_2); new_value = 0x0F; parity_byte = dp_audio_calculate_parity(new_value); parity_byte = dp_header_get_parity(new_value); value |= ((new_value << HEADER_BYTE_2_BIT) | (parity_byte << PARITY_BYTE_2_BIT)); pr_debug("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n", Loading
drivers/gpu/drm/msm/dp/dp_aux.c +24 −1 Original line number Diff line number Diff line Loading @@ -42,6 +42,7 @@ struct dp_aux_private { bool no_send_stop; u32 offset; u32 segment; atomic_t aborted; struct drm_dp_aux drm_aux; }; Loading Loading @@ -279,6 +280,20 @@ static void dp_aux_reconfig(struct dp_aux *dp_aux) aux->catalog->reset(aux->catalog); } static void dp_aux_abort_transaction(struct dp_aux *dp_aux) { struct dp_aux_private *aux; if (!dp_aux) { pr_err("invalid input\n"); return; } aux = container_of(dp_aux, struct dp_aux_private, dp_aux); atomic_set(&aux->aborted, 1); } static void dp_aux_update_offset_and_segment(struct dp_aux_private *aux, struct drm_dp_aux_msg *input_msg) { Loading Loading @@ -379,6 +394,11 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *drm_aux, mutex_lock(&aux->mutex); if (atomic_read(&aux->aborted)) { ret = -ETIMEDOUT; goto unlock_exit; } aux->native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ); /* Ignore address only message */ Loading Loading @@ -413,7 +433,7 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *drm_aux, } ret = dp_aux_cmd_fifo_tx(aux, msg); if ((ret < 0) && aux->native) { if ((ret < 0) && aux->native && !atomic_read(&aux->aborted)) { aux->retry_cnt++; if (!(aux->retry_cnt % retry_count)) aux->catalog->update_aux_cfg(aux->catalog, Loading Loading @@ -469,6 +489,7 @@ static void dp_aux_init(struct dp_aux *dp_aux, struct dp_aux_cfg *aux_cfg) aux->catalog->setup(aux->catalog, aux_cfg); aux->catalog->reset(aux->catalog); aux->catalog->enable(aux->catalog, true); atomic_set(&aux->aborted, 0); aux->retry_cnt = 0; } Loading @@ -483,6 +504,7 @@ static void dp_aux_deinit(struct dp_aux *dp_aux) aux = container_of(dp_aux, struct dp_aux_private, dp_aux); atomic_set(&aux->aborted, 1); aux->catalog->enable(aux->catalog, false); } Loading Loading @@ -560,6 +582,7 @@ struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog, dp_aux->drm_aux_register = dp_aux_register; dp_aux->drm_aux_deregister = dp_aux_deregister; dp_aux->reconfig = dp_aux_reconfig; dp_aux->abort = dp_aux_abort_transaction; return dp_aux; error: Loading
drivers/gpu/drm/msm/dp/dp_aux.h +1 −0 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ struct dp_aux { void (*init)(struct dp_aux *aux, struct dp_aux_cfg *aux_cfg); void (*deinit)(struct dp_aux *aux); void (*reconfig)(struct dp_aux *aux); void (*abort)(struct dp_aux *aux); }; struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog, Loading
drivers/gpu/drm/msm/dp/dp_catalog.c +273 −54 Original line number Diff line number Diff line Loading @@ -337,7 +337,7 @@ static void dp_catalog_panel_setup_infoframe_sdp(struct dp_catalog_panel *panel) struct dp_catalog_private *catalog; struct drm_msm_ext_hdr_metadata *hdr; void __iomem *base; u32 header, data; u32 header, parity, data; if (!panel) { pr_err("invalid input\n"); Loading @@ -348,67 +348,90 @@ static void dp_catalog_panel_setup_infoframe_sdp(struct dp_catalog_panel *panel) hdr = &panel->hdr_data.hdr_meta; base = catalog->io->dp_link.base; header = dp_read(base + MMSS_DP_VSCEXT_0); header |= panel->hdr_data.vscext_header_byte1; dp_write(base + MMSS_DP_VSCEXT_0, header); header = dp_read(base + MMSS_DP_VSCEXT_1); header |= panel->hdr_data.vscext_header_byte2; dp_write(base + MMSS_DP_VSCEXT_1, header); header = dp_read(base + MMSS_DP_VSCEXT_1); header |= panel->hdr_data.vscext_header_byte3; dp_write(base + MMSS_DP_VSCEXT_1, header); header = panel->hdr_data.version; header |= panel->hdr_data.length << 8; header |= hdr->eotf << 16; dp_write(base + MMSS_DP_VSCEXT_2, header); /* HEADER BYTE 1 */ header = panel->hdr_data.vscext_header_byte1; parity = dp_header_get_parity(header); data = ((header << HEADER_BYTE_1_BIT) | (parity << PARITY_BYTE_1_BIT)); dp_write(base + MMSS_DP_VSCEXT_0, data); pr_debug("Header#1: 0x%x, parity = 0x%x\n", header, parity); pr_debug("DP_VSCEXT_0: 0x%x\n", data); /* HEADER BYTE 2 */ header = panel->hdr_data.vscext_header_byte2; parity = dp_header_get_parity(header); data = ((header << HEADER_BYTE_2_BIT) | (parity << PARITY_BYTE_2_BIT)); dp_write(base + MMSS_DP_VSCEXT_1, data); pr_debug("Header#2: 0x%x, parity = 0x%x\n", header, parity); pr_debug("DP_VSCEXT_1: 0x%x\n", data); /* HEADER BYTE 3 */ header = panel->hdr_data.vscext_header_byte3; parity = dp_header_get_parity(header); data = ((header << HEADER_BYTE_3_BIT) | (parity << PARITY_BYTE_3_BIT)); data |= dp_read(base + MMSS_DP_VSCEXT_1); dp_write(base + MMSS_DP_VSCEXT_1, data); pr_debug("Header#3: 0x%x, parity = 0x%x\n", header, parity); pr_debug("DP_VSCEXT_1: 0x%x\n", data); data = panel->hdr_data.version; data |= panel->hdr_data.length << 8; data |= hdr->eotf << 16; pr_debug("DP_VSCEXT_2: 0x%x\n", data); dp_write(base + MMSS_DP_VSCEXT_2, data); data = (DP_GET_LSB(hdr->display_primaries_x[0]) | (DP_GET_MSB(hdr->display_primaries_x[0]) << 8) | (DP_GET_LSB(hdr->display_primaries_y[0]) << 16) | (DP_GET_MSB(hdr->display_primaries_y[0]) << 24)); pr_debug("DP_VSCEXT_3: 0x%x\n", data); dp_write(base + MMSS_DP_VSCEXT_3, data); data = (DP_GET_LSB(hdr->display_primaries_x[1]) | (DP_GET_MSB(hdr->display_primaries_x[1]) << 8) | (DP_GET_LSB(hdr->display_primaries_y[1]) << 16) | (DP_GET_MSB(hdr->display_primaries_y[1]) << 24)); pr_debug("DP_VSCEXT_4: 0x%x\n", data); dp_write(base + MMSS_DP_VSCEXT_4, data); data = (DP_GET_LSB(hdr->display_primaries_x[2]) | (DP_GET_MSB(hdr->display_primaries_x[2]) << 8) | (DP_GET_LSB(hdr->display_primaries_y[2]) << 16) | (DP_GET_MSB(hdr->display_primaries_y[2]) << 24)); pr_debug("DP_VSCEXT_5: 0x%x\n", data); dp_write(base + MMSS_DP_VSCEXT_5, data); data = (DP_GET_LSB(hdr->white_point_x) | (DP_GET_MSB(hdr->white_point_x) << 8) | (DP_GET_LSB(hdr->white_point_y) << 16) | (DP_GET_MSB(hdr->white_point_y) << 24)); pr_debug("DP_VSCEXT_6: 0x%x\n", data); dp_write(base + MMSS_DP_VSCEXT_6, data); data = (DP_GET_LSB(hdr->max_luminance) | (DP_GET_MSB(hdr->max_luminance) << 8) | (DP_GET_LSB(hdr->min_luminance) << 16) | (DP_GET_MSB(hdr->min_luminance) << 24)); pr_debug("DP_VSCEXT_7: 0x%x\n", data); dp_write(base + MMSS_DP_VSCEXT_7, data); data = (DP_GET_LSB(hdr->max_content_light_level) | (DP_GET_MSB(hdr->max_content_light_level) << 8) | (DP_GET_LSB(hdr->max_average_light_level) << 16) | (DP_GET_MSB(hdr->max_average_light_level) << 24)); pr_debug("DP_VSCEXT_8: 0x%x\n", data); dp_write(base + MMSS_DP_VSCEXT_8, data); dp_write(base + MMSS_DP_VSCEXT_9, 0x00); } static void dp_catalog_panel_setup_vsc_sdp(struct dp_catalog_panel *panel) static void dp_catalog_panel_setup_ext_sdp(struct dp_catalog_panel *panel) { struct dp_catalog_private *catalog; void __iomem *base; u32 value; u32 header, parity, data; if (!panel) { pr_err("invalid input\n"); Loading @@ -418,30 +441,105 @@ static void dp_catalog_panel_setup_vsc_sdp(struct dp_catalog_panel *panel) dp_catalog_get_priv(panel); base = catalog->io->dp_link.base; value = dp_read(base + MMSS_DP_GENERIC0_0); value |= panel->hdr_data.vsc_header_byte1; dp_write(base + MMSS_DP_GENERIC0_0, value); /* HEADER BYTE 1 */ header = panel->hdr_data.ext_header_byte1; parity = dp_header_get_parity(header); data = ((header << HEADER_BYTE_1_BIT) | (parity << PARITY_BYTE_1_BIT)); dp_write(base + MMSS_DP_EXTENSION_0, data); pr_debug("Header#1: 0x%x, parity = 0x%x\n", header, parity); pr_debug("DP_EXTENSION_0: 0x%x\n", data); /* HEADER BYTE 2 */ header = panel->hdr_data.ext_header_byte2; parity = dp_header_get_parity(header); data = ((header << HEADER_BYTE_2_BIT) | (parity << PARITY_BYTE_2_BIT)); dp_write(base + MMSS_DP_EXTENSION_1, data); pr_debug("Header#2: 0x%x, parity = 0x%x\n", header, parity); pr_debug("DP_EXTENSION_1: 0x%x\n", data); dp_write(base + MMSS_DP_EXTENSION_1, 0x5AA55AA5); dp_write(base + MMSS_DP_EXTENSION_2, 0x5AA55AA5); dp_write(base + MMSS_DP_EXTENSION_3, 0x5AA55AA5); dp_write(base + MMSS_DP_EXTENSION_4, 0x5AA55AA5); dp_write(base + MMSS_DP_EXTENSION_5, 0x5AA55AA5); dp_write(base + MMSS_DP_EXTENSION_6, 0x5AA55AA5); dp_write(base + MMSS_DP_EXTENSION_7, 0x5AA55AA5); dp_write(base + MMSS_DP_EXTENSION_8, 0x5AA55AA5); dp_write(base + MMSS_DP_EXTENSION_9, 0x5AA55AA5); } static void dp_catalog_panel_setup_vsc_sdp(struct dp_catalog_panel *panel) { struct dp_catalog_private *catalog; void __iomem *base; u32 header, parity, data; u8 bpc; value = dp_read(base + MMSS_DP_GENERIC0_1); value |= panel->hdr_data.vsc_header_byte2; dp_write(base + MMSS_DP_GENERIC0_1, value); if (!panel) { pr_err("invalid input\n"); return; } value = dp_read(base + MMSS_DP_GENERIC0_1); value |= panel->hdr_data.vsc_header_byte3; dp_write(base + MMSS_DP_GENERIC0_1, value); dp_catalog_get_priv(panel); base = catalog->io->ctrl_io.base; /* HEADER BYTE 1 */ header = panel->hdr_data.vsc_header_byte1; parity = dp_header_get_parity(header); data = ((header << HEADER_BYTE_1_BIT) | (parity << PARITY_BYTE_1_BIT)); dp_write(base + MMSS_DP_GENERIC0_0, data); pr_debug("Header#1: 0x%x, parity = 0x%x\n", header, parity); pr_debug("DP_GENERIC0_0: 0x%x\n", data); /* HEADER BYTE 2 */ header = panel->hdr_data.vsc_header_byte2; parity = dp_header_get_parity(header); data = ((header << HEADER_BYTE_2_BIT) | (parity << PARITY_BYTE_2_BIT)); dp_write(base + MMSS_DP_GENERIC0_1, data); pr_debug("Header#2: 0x%x, parity = 0x%x\n", header, parity); pr_debug("DP_GENERIC0_1: 0x%x\n", data); /* HEADER BYTE 3 */ header = panel->hdr_data.vsc_header_byte3; parity = dp_header_get_parity(header); data = ((header << HEADER_BYTE_3_BIT) | (parity << PARITY_BYTE_3_BIT)); data |= dp_read(base + MMSS_DP_GENERIC0_1); dp_write(base + MMSS_DP_GENERIC0_1, data); pr_debug("Header#3: 0x%x, parity = 0x%x\n", header, parity); pr_debug("DP_GENERIC0_1: 0x%x\n", data); dp_write(base + MMSS_DP_GENERIC0_2, 0x00); dp_write(base + MMSS_DP_GENERIC0_3, 0x00); dp_write(base + MMSS_DP_GENERIC0_4, 0x00); dp_write(base + MMSS_DP_GENERIC0_5, 0x00); value = (panel->hdr_data.colorimetry & 0xF) | switch (panel->hdr_data.bpc) { default: case 10: bpc = BIT(1); break; case 8: bpc = BIT(0); break; case 6: bpc = 0; break; } data = (panel->hdr_data.colorimetry & 0xF) | ((panel->hdr_data.pixel_encoding & 0xF) << 4) | ((panel->hdr_data.bpc & 0x7) << 8) | (bpc << 8) | ((panel->hdr_data.dynamic_range & 0x1) << 15) | ((panel->hdr_data.content_type & 0x7) << 16); dp_write(base + MMSS_DP_GENERIC0_6, value); pr_debug("DP_GENERIC0_6: 0x%x\n", data); dp_write(base + MMSS_DP_GENERIC0_6, data); dp_write(base + MMSS_DP_GENERIC0_7, 0x00); dp_write(base + MMSS_DP_GENERIC0_8, 0x00); dp_write(base + MMSS_DP_GENERIC0_9, 0x00); Loading @@ -462,19 +560,31 @@ static void dp_catalog_panel_config_hdr(struct dp_catalog_panel *panel) base = catalog->io->dp_link.base; cfg = dp_read(base + MMSS_DP_SDP_CFG); /* EXTENSION_SDP_EN */ cfg |= BIT(4); /* VSCEXT_SDP_EN */ cfg |= BIT(16); /* GEN0_SDP_EN */ cfg |= BIT(17); /* GEN1_SDP_EN */ cfg |= BIT(18); dp_write(base + MMSS_DP_SDP_CFG, cfg); cfg2 = dp_read(base + MMSS_DP_SDP_CFG2); /* Generic0 SDP Payload is 19 bytes which is > 16, so Bit16 is 1 */ cfg2 |= BIT(16); /* EXTN_SDPSIZE */ cfg2 |= BIT(15); /* GENERIC0_SDPSIZE */ cfg |= BIT(16); /* GENERIC1_SDPSIZE */ cfg |= BIT(17); dp_write(base + MMSS_DP_SDP_CFG2, cfg2); dp_catalog_panel_setup_ext_sdp(panel); dp_catalog_panel_setup_vsc_sdp(panel); dp_catalog_panel_setup_infoframe_sdp(panel); Loading @@ -484,27 +594,8 @@ static void dp_catalog_panel_config_hdr(struct dp_catalog_panel *panel) dp_write(base + DP_MISC1_MISC0, cfg); cfg = dp_read(base + DP_CONFIGURATION_CTRL); /* Send VSC */ cfg |= BIT(7); switch (panel->hdr_data.bpc) { default: case 10: cfg |= BIT(9); break; case 8: cfg |= BIT(8); break; } dp_write(base + DP_CONFIGURATION_CTRL, cfg); cfg = dp_read(base + DP_COMPRESSION_MODE_CTRL); /* Trigger SDP values in registers */ cfg |= BIT(8); dp_write(base + DP_COMPRESSION_MODE_CTRL, cfg); dp_write(base + MMSS_DP_SDP_CFG3, 0x01); dp_write(base + MMSS_DP_SDP_CFG3, 0x00); } static void dp_catalog_ctrl_update_transfer_unit(struct dp_catalog_ctrl *ctrl) Loading Loading @@ -1179,6 +1270,8 @@ static void dp_catalog_audio_config_sdp(struct dp_catalog_audio *audio) dp_catalog_get_priv(audio); base = catalog->io->dp_link.base; sdp_cfg = dp_read(base + MMSS_DP_SDP_CFG); /* AUDIO_TIMESTAMP_SDP_EN */ sdp_cfg |= BIT(1); /* AUDIO_STREAM_SDP_EN */ Loading Loading @@ -1312,6 +1405,131 @@ static void dp_catalog_audio_enable(struct dp_catalog_audio *audio) wmb(); } static void dp_catalog_config_spd_header(struct dp_catalog_panel *panel) { struct dp_catalog_private *catalog; void __iomem *base; u32 value, new_value; u8 parity_byte; if (!panel) return; dp_catalog_get_priv(panel); base = catalog->io->dp_link.base; /* Config header and parity byte 1 */ value = dp_read(base + MMSS_DP_GENERIC1_0); new_value = 0x83; parity_byte = dp_header_get_parity(new_value); value |= ((new_value << HEADER_BYTE_1_BIT) | (parity_byte << PARITY_BYTE_1_BIT)); pr_debug("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n", value, parity_byte); dp_write(base + MMSS_DP_GENERIC1_0, value); /* Config header and parity byte 2 */ value = dp_read(base + MMSS_DP_GENERIC1_1); new_value = 0x1b; parity_byte = dp_header_get_parity(new_value); value |= ((new_value << HEADER_BYTE_2_BIT) | (parity_byte << PARITY_BYTE_2_BIT)); pr_debug("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n", value, parity_byte); dp_write(base + MMSS_DP_GENERIC1_1, value); /* Config header and parity byte 3 */ value = dp_read(base + MMSS_DP_GENERIC1_1); new_value = (0x0 | (0x12 << 2)); parity_byte = dp_header_get_parity(new_value); value |= ((new_value << HEADER_BYTE_3_BIT) | (parity_byte << PARITY_BYTE_3_BIT)); pr_debug("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n", new_value, parity_byte); dp_write(base + MMSS_DP_GENERIC1_1, value); } static void dp_catalog_panel_config_spd(struct dp_catalog_panel *panel) { struct dp_catalog_private *catalog; void __iomem *base; u32 spd_cfg = 0, spd_cfg2 = 0; u8 *vendor = NULL, *product = NULL; /* * Source Device Information * 00h unknown * 01h Digital STB * 02h DVD * 03h D-VHS * 04h HDD Video * 05h DVC * 06h DSC * 07h Video CD * 08h Game * 09h PC general * 0ah Bluray-Disc * 0bh Super Audio CD * 0ch HD DVD * 0dh PMP * 0eh-ffh reserved */ u32 device_type = 0; if (!panel) return; dp_catalog_get_priv(panel); base = catalog->io->dp_link.base; dp_catalog_config_spd_header(panel); vendor = panel->spd_vendor_name; product = panel->spd_product_description; dp_write(base + MMSS_DP_GENERIC1_2, ((vendor[0] & 0x7f) | ((vendor[1] & 0x7f) << 8) | ((vendor[2] & 0x7f) << 16) | ((vendor[3] & 0x7f) << 24))); dp_write(base + MMSS_DP_GENERIC1_3, ((vendor[4] & 0x7f) | ((vendor[5] & 0x7f) << 8) | ((vendor[6] & 0x7f) << 16) | ((vendor[7] & 0x7f) << 24))); dp_write(base + MMSS_DP_GENERIC1_4, ((product[0] & 0x7f) | ((product[1] & 0x7f) << 8) | ((product[2] & 0x7f) << 16) | ((product[3] & 0x7f) << 24))); dp_write(base + MMSS_DP_GENERIC1_5, ((product[4] & 0x7f) | ((product[5] & 0x7f) << 8) | ((product[6] & 0x7f) << 16) | ((product[7] & 0x7f) << 24))); dp_write(base + MMSS_DP_GENERIC1_6, ((product[8] & 0x7f) | ((product[9] & 0x7f) << 8) | ((product[10] & 0x7f) << 16) | ((product[11] & 0x7f) << 24))); dp_write(base + MMSS_DP_GENERIC1_7, ((product[12] & 0x7f) | ((product[13] & 0x7f) << 8) | ((product[14] & 0x7f) << 16) | ((product[15] & 0x7f) << 24))); dp_write(base + MMSS_DP_GENERIC1_8, device_type); dp_write(base + MMSS_DP_GENERIC1_9, 0x00); spd_cfg = dp_read(base + MMSS_DP_SDP_CFG); /* GENERIC1_SDP for SPD Infoframe */ spd_cfg |= BIT(18); dp_write(base + MMSS_DP_SDP_CFG, spd_cfg); spd_cfg2 = dp_read(base + MMSS_DP_SDP_CFG2); /* 28 data bytes for SPD Infoframe with GENERIC1 set */ spd_cfg2 |= BIT(17); dp_write(base + MMSS_DP_SDP_CFG2, spd_cfg2); dp_write(base + MMSS_DP_SDP_CFG3, 0x1); dp_write(base + MMSS_DP_SDP_CFG3, 0x0); } struct dp_catalog *dp_catalog_get(struct device *dev, struct dp_io *io) { int rc = 0; Loading Loading @@ -1364,6 +1582,7 @@ struct dp_catalog *dp_catalog_get(struct device *dev, struct dp_io *io) .timing_cfg = dp_catalog_panel_timing_cfg, .config_hdr = dp_catalog_panel_config_hdr, .tpg_config = dp_catalog_panel_tpg_cfg, .config_spd = dp_catalog_panel_config_spd, }; if (!io) { Loading
drivers/gpu/drm/msm/dp/dp_catalog.h +80 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,11 @@ #define DP_INTR_CRC_UPDATED BIT(9) struct dp_catalog_hdr_data { u32 ext_header_byte0; u32 ext_header_byte1; u32 ext_header_byte2; u32 ext_header_byte3; u32 vsc_header_byte0; u32 vsc_header_byte1; u32 vsc_header_byte2; Loading Loading @@ -109,6 +114,13 @@ struct dp_catalog_ctrl { u32 (*read_phy_pattern)(struct dp_catalog_ctrl *ctrl); }; #define HEADER_BYTE_2_BIT 0 #define PARITY_BYTE_2_BIT 8 #define HEADER_BYTE_1_BIT 16 #define PARITY_BYTE_1_BIT 24 #define HEADER_BYTE_3_BIT 16 #define PARITY_BYTE_3_BIT 24 enum dp_catalog_audio_sdp_type { DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_TIMESTAMP, Loading Loading @@ -144,6 +156,8 @@ struct dp_catalog_panel { u32 sync_start; u32 width_blanking; u32 dp_active; u8 *spd_vendor_name; u8 *spd_product_description; struct dp_catalog_hdr_data hdr_data; Loading @@ -159,6 +173,7 @@ struct dp_catalog_panel { int (*timing_cfg)(struct dp_catalog_panel *panel); void (*config_hdr)(struct dp_catalog_panel *panel); void (*tpg_config)(struct dp_catalog_panel *panel, bool enable); void (*config_spd)(struct dp_catalog_panel *panel); }; struct dp_catalog { Loading @@ -168,6 +183,71 @@ struct dp_catalog { struct dp_catalog_panel panel; }; static inline u8 dp_ecc_get_g0_value(u8 data) { u8 c[4]; u8 g[4]; u8 ret_data = 0; u8 i; for (i = 0; i < 4; i++) c[i] = (data >> i) & 0x01; g[0] = c[3]; g[1] = c[0] ^ c[3]; g[2] = c[1]; g[3] = c[2]; for (i = 0; i < 4; i++) ret_data = ((g[i] & 0x01) << i) | ret_data; return ret_data; } static inline u8 dp_ecc_get_g1_value(u8 data) { u8 c[4]; u8 g[4]; u8 ret_data = 0; u8 i; for (i = 0; i < 4; i++) c[i] = (data >> i) & 0x01; g[0] = c[0] ^ c[3]; g[1] = c[0] ^ c[1] ^ c[3]; g[2] = c[1] ^ c[2]; g[3] = c[2] ^ c[3]; for (i = 0; i < 4; i++) ret_data = ((g[i] & 0x01) << i) | ret_data; return ret_data; } static inline u8 dp_header_get_parity(u32 data) { u8 x0 = 0; u8 x1 = 0; u8 ci = 0; u8 iData = 0; u8 i = 0; u8 parity_byte; u8 num_byte = (data & 0xFF00) > 0 ? 8 : 2; for (i = 0; i < num_byte; i++) { iData = (data >> i*4) & 0xF; ci = iData ^ x1; x1 = x0 ^ dp_ecc_get_g1_value(ci); x0 = dp_ecc_get_g0_value(ci); } parity_byte = x1 | (x0 << 4); return parity_byte; } struct dp_catalog *dp_catalog_get(struct device *dev, struct dp_io *io); void dp_catalog_put(struct dp_catalog *catalog); Loading